react-query-external-sync
Version:
A tool for syncing React Query state to an external Dev Tools
289 lines • 10.3 kB
JavaScript
/**
* Helper function for controlled logging
* Only shows logs when enableLogs is true
* Always shows warnings and errors regardless of enableLogs setting
*/
export function log(message, enableLogs, type = "log") {
if (!enableLogs)
return;
switch (type) {
case "warn":
console.warn(message);
break;
case "error":
console.error(message);
break;
default:
console.log(message);
}
}
/**
* Sync logger for external sync operations
* Provides clean, grouped logging similar to API route logging
*/
class ExternalSyncLogger {
constructor() {
this.operations = new Map();
}
/**
* Start a new sync operation
*/
startOperation(type, context, enableLogs = false) {
const requestId = this.generateRequestId();
const fullContext = {
deviceName: context.deviceName || "unknown",
deviceId: context.deviceId || "unknown",
platform: context.platform || "unknown",
requestId,
timestamp: Date.now(),
};
this.operations.set(requestId, {
context: fullContext,
startTime: Date.now(),
stats: {
storageUpdates: { mmkv: 0, asyncStorage: 0, secureStore: 0 },
queryActions: {
dataUpdates: 0,
refetches: 0,
invalidations: 0,
resets: 0,
removes: 0,
errors: 0,
},
connectionEvents: { connects: 0, disconnects: 0, reconnects: 0 },
errors: [],
},
enableLogs,
});
if (enableLogs) {
const icon = this.getOperationIcon(type);
const readableTime = new Date(fullContext.timestamp).toLocaleString("en-US", {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: true,
});
log(`┌─ 🌴 ${this.getOperationTitle(type)} • ${fullContext.deviceName} (${fullContext.platform}) • ${readableTime}`, enableLogs);
}
return requestId;
}
/**
* Log a storage update
*/
logStorageUpdate(requestId, storageType, key, currentValue, newValue) {
const operation = this.operations.get(requestId);
if (!operation)
return;
operation.stats.storageUpdates[storageType]++;
if (operation.enableLogs) {
const icon = this.getStorageIcon(storageType);
const typeDisplay = storageType === "asyncStorage"
? "AsyncStorage"
: storageType === "secureStore"
? "SecureStore"
: "MMKV";
log(`├─ ${icon} ${typeDisplay}: ${key} | ${JSON.stringify(currentValue)} → ${JSON.stringify(newValue)}`, operation.enableLogs);
}
}
/**
* Log a query action
*/
logQueryAction(requestId, action, queryHash, success = true) {
const operation = this.operations.get(requestId);
if (!operation)
return;
// Update stats based on action type
switch (action) {
case "ACTION-DATA-UPDATE":
operation.stats.queryActions.dataUpdates++;
break;
case "ACTION-REFETCH":
operation.stats.queryActions.refetches++;
break;
case "ACTION-INVALIDATE":
operation.stats.queryActions.invalidations++;
break;
case "ACTION-RESET":
operation.stats.queryActions.resets++;
break;
case "ACTION-REMOVE":
operation.stats.queryActions.removes++;
break;
default:
if (!success)
operation.stats.queryActions.errors++;
break;
}
if (operation.enableLogs) {
const icon = this.getActionIcon(action, success);
const actionName = this.getActionDisplayName(action);
log(`├─ ${icon} ${actionName}: ${queryHash}`, operation.enableLogs);
}
}
/**
* Log a connection event
*/
logConnectionEvent(requestId, event, details) {
const operation = this.operations.get(requestId);
if (!operation)
return;
operation.stats.connectionEvents[`${event}s`]++;
if (operation.enableLogs) {
const icon = event === "connect" ? "🔗" : event === "disconnect" ? "🔌" : "🔄";
const message = details
? `${event.toUpperCase()}: ${details}`
: event.toUpperCase();
console.log(`├ ${icon} ${message}`);
}
}
/**
* Log an error
*/
logError(requestId, type, message, error) {
var _a;
const operation = this.operations.get(requestId);
if (!operation)
return;
operation.stats.errors.push({
type,
message,
timestamp: Date.now(),
});
if (operation.enableLogs) {
console.log(`├ ❌ ${type}: ${message}`);
if (error === null || error === void 0 ? void 0 : error.stack) {
console.log(`├ Stack: ${(_a = error.stack.split("\n")[1]) === null || _a === void 0 ? void 0 : _a.trim()}`);
}
}
}
/**
* Complete and log the operation summary
*/
completeOperation(requestId, success = true) {
const operation = this.operations.get(requestId);
if (!operation)
return;
// Only show completion log if there was an error
if (operation.enableLogs && !success) {
log(`└─ ❌ Error`, operation.enableLogs);
log("", operation.enableLogs); // Add empty line for spacing
}
else if (operation.enableLogs) {
// Just add spacing for successful operations without the "Complete" message
log("", operation.enableLogs);
}
// Clean up without logging summary
this.operations.delete(requestId);
}
generateRequestId() {
return Math.random().toString(36).substring(2, 15);
}
getOperationIcon(type) {
switch (type) {
case "connection":
return "🔗";
case "query-action":
return "🔄";
case "storage-update":
return "💾";
case "sync-session":
return "🔄";
default:
return "📋";
}
}
getOperationTitle(type) {
switch (type) {
case "connection":
return "Connection";
case "query-action":
return "Query Action";
case "storage-update":
return "Storage Update";
case "sync-session":
return "Sync Session";
default:
return "Operation";
}
}
getStorageIcon(storageType) {
switch (storageType) {
case "mmkv":
return "💾";
case "asyncStorage":
return "📱";
case "secureStore":
return "🔐";
default:
return "📦";
}
}
getActionIcon(action, success) {
if (!success)
return "🔴"; // Red for failures (#EF4444)
switch (action) {
case "ACTION-DATA-UPDATE":
return "🟢"; // Green for fresh/success (#039855)
case "ACTION-REFETCH":
return "🔵"; // Blue for refetch (#1570EF)
case "ACTION-INVALIDATE":
return "🟠"; // Orange for invalidate (#DC6803)
case "ACTION-RESET":
return "⚫"; // Dark gray for reset (#475467)
case "ACTION-REMOVE":
return "🟣"; // Pink/purple for remove (#DB2777)
case "ACTION-TRIGGER-ERROR":
return "🔴"; // Red for error (#EF4444)
case "ACTION-RESTORE-ERROR":
return "🟢"; // Green for restore (success variant)
case "ACTION-TRIGGER-LOADING":
return "🔷"; // Light blue diamond for loading (#0891B2)
case "ACTION-RESTORE-LOADING":
return "🔶"; // Orange diamond for restore loading (loading variant)
case "ACTION-CLEAR-MUTATION-CACHE":
return "⚪"; // White for clear cache (neutral)
case "ACTION-CLEAR-QUERY-CACHE":
return "⬜"; // White square for clear cache (neutral)
case "ACTION-ONLINE-MANAGER-ONLINE":
return "🟢"; // Green for online (fresh)
case "ACTION-ONLINE-MANAGER-OFFLINE":
return "🔴"; // Red for offline (error)
default:
return "⚪"; // White for generic (inactive #667085)
}
}
getActionDisplayName(action) {
switch (action) {
case "ACTION-DATA-UPDATE":
return "Data Update";
case "ACTION-REFETCH":
return "Refetch";
case "ACTION-INVALIDATE":
return "Invalidate";
case "ACTION-RESET":
return "Reset";
case "ACTION-REMOVE":
return "Remove";
case "ACTION-TRIGGER-ERROR":
return "Trigger Error";
case "ACTION-RESTORE-ERROR":
return "Restore Error";
case "ACTION-TRIGGER-LOADING":
return "Trigger Loading";
case "ACTION-RESTORE-LOADING":
return "Restore Loading";
default:
return action.replace("ACTION-", "").replace(/-/g, " ");
}
}
formatDuration(ms) {
if (ms < 1000)
return `${ms}ms`;
const seconds = (ms / 1000).toFixed(1);
return `${seconds}s`;
}
}
export const syncLogger = new ExternalSyncLogger();
//# sourceMappingURL=logger.js.map