/** * In-memory log buffer (capped at MAX_LOGS entries) and batched broadcast to * open dashboard tabs. Provides log() and debugLog() used by all background modules. * Depends on: (none — loaded first) */ const logs = []; const MAX_LOGS = 500; // Track dashboard tabs const dashboardTabs = new Set(); /** * Append a log entry to the in-memory buffer and broadcast to dashboard tabs. * Automatically classifies the entry as 'error', 'warn', or 'info' based on keywords. * @param {...*} args - Values to log; objects are JSON-stringified. */ function log(...args) { console.log('[Holesail-bg]', ...args); const timestamp = Date.now(); const message = args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' '); const lower = message.toLowerCase(); const level = (lower.includes('error') || lower.includes('fail') || lower.includes('err:')) ? 'error' : (lower.includes('warn') || lower.includes('warning')) ? 'warn' : 'info'; logs.push({ timestamp, message, level }); if (logs.length > MAX_LOGS) logs.shift(); broadcastLogs(); } /** * Log a debug-level entry. No-op unless `DEBUG_VERBOSE` is true. * @param {...*} args - Values to log. */ function debugLog(...args) { if (!DEBUG_VERBOSE) return; log('[debug]', ...args); } let _broadcastPending = false; function broadcastLogs() { if (_broadcastPending) return; _broadcastPending = true; // Batch rapid log calls into a single IPC message to avoid sending a full // copy of the 500-entry array on every individual log() call. setTimeout(() => { _broadcastPending = false; const snapshot = logs.slice(0); for (const tabId of dashboardTabs) { browser.tabs.sendMessage(tabId, { type: 'holesail-logs', logs: snapshot }).catch(() => {}); } }, 100); }