diff --git a/src/diagnostics.js b/src/diagnostics.js new file mode 100644 index 0000000..36694a0 --- /dev/null +++ b/src/diagnostics.js @@ -0,0 +1,89 @@ +const MAX_LOG_ENTRIES = 300; +const logBuffer = []; +let snapshotProvider = null; +let browserDiagnosticsInstalled = false; + +const safeError = (error) => { + if (!error) return null; + if (error instanceof Error) { + return { + name: error.name, + message: error.message, + stack: error.stack || null, + }; + } + return { message: String(error) }; +}; + +const trimLogs = () => { + if (logBuffer.length > MAX_LOG_ENTRIES) { + logBuffer.splice(0, logBuffer.length - MAX_LOG_ENTRIES); + } +}; + +export const airshipLog = (event, data = {}, level = 'info') => { + const entry = { + ts: new Date().toISOString(), + level, + event, + ...data, + }; + + logBuffer.push(entry); + trimLogs(); + + const method = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log'; + console[method]('[airship]', event, entry); + return entry; +}; + +export const registerDebugSnapshot = (provider) => { + snapshotProvider = typeof provider === 'function' ? provider : null; +}; + +export const getAirshipLogs = () => logBuffer.map((entry) => ({ ...entry })); + +export const clearAirshipLogs = () => { + logBuffer.length = 0; +}; + +export const installBrowserDiagnostics = () => { + if (typeof window === 'undefined' || browserDiagnosticsInstalled) return; + browserDiagnosticsInstalled = true; + + window.__AIRSHIP_LOGS__ = logBuffer; + window.airshipDebug = { + getLogs: getAirshipLogs, + clearLogs: clearAirshipLogs, + snapshot: () => { + try { + return snapshotProvider?.() ?? null; + } catch (error) { + airshipLog('debug:snapshot-error', { error: safeError(error) }, 'error'); + return null; + } + }, + }; + + window.addEventListener('error', (event) => { + airshipLog('runtime:error', { + message: event.message || 'Unknown window error', + source: event.filename || null, + line: event.lineno || null, + column: event.colno || null, + error: safeError(event.error), + }, 'error'); + }); + + window.addEventListener('unhandledrejection', (event) => { + airshipLog('runtime:unhandled-rejection', { + error: safeError(event.reason), + }, 'error'); + }); + + airshipLog('diagnostics:installed', { + userAgent: navigator?.userAgent || 'unknown', + }); +}; + +installBrowserDiagnostics();