/** * Enhanced Real-Time Error Monitoring * Captures ALL browser console output and forwards it to the server */ (function() { 'use strict'; const ERROR_ENDPOINT = '/claude/api/log-error'; // Queue to prevent error loops const errorQueue = []; let isReporting = false; // Send error to server with better error handling function reportError(errorData) { errorQueue.push(errorData); processQueue(); } function processQueue() { if (isReporting || errorQueue.length === 0) return; isReporting = true; const errorData = errorQueue.shift(); // Add timestamp if not present if (!errorData.timestamp) { errorData.timestamp = new Date().toISOString(); } // Add URL if not present if (!errorData.url) { errorData.url = window.location.href; } // Add page info errorData.pageInfo = { pathname: window.location.pathname, search: window.location.search, hash: window.location.hash }; fetch(ERROR_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(errorData) }) .catch(err => { // Silently fail - don't log to console to prevent infinite loop // Last resort: store in sessionStorage for later retrieval try { const stored = JSON.parse(sessionStorage.getItem('browser_errors') || '[]'); stored.push(errorData); sessionStorage.setItem('browser_errors', JSON.stringify(stored.slice(-50))); } catch(e) {} }) .finally(() => { isReporting = false; // Process next error after a short delay setTimeout(processQueue, 100); }); } // Create visual error indicator function createErrorIndicator() { if (document.getElementById('error-indicator')) return; const indicator = document.createElement('div'); indicator.id = 'error-indicator'; indicator.innerHTML = '⚠️ Errors - Check Server Logs'; indicator.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%); color: white; padding: 12px 20px; border-radius: 8px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; font-weight: 600; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 99999; cursor: pointer; animation: slideIn 0.3s ease-out; display: none; `; indicator.onclick = () => { indicator.remove(); }; const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateY(100px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } `; document.head.appendChild(style); document.body.appendChild(indicator); return indicator; } function showErrorIndicator() { const indicator = createErrorIndicator(); if (indicator) { indicator.style.display = 'block'; // Auto-hide after 30 seconds setTimeout(() => { if (indicator.parentElement) { indicator.style.animation = 'slideIn 0.3s ease-out reverse'; setTimeout(() => indicator.remove(), 300); } }, 30000); } } // Intercept ALL console methods const consoleMethods = ['log', 'warn', 'info', 'error', 'debug']; const originals = {}; consoleMethods.forEach(method => { originals[method] = console[method]; console[method] = function(...args) { // Call original console method originals[method].apply(console, args); // Format the message for server logging const message = args.map(arg => { if (typeof arg === 'string') return arg; if (typeof arg === 'object') { try { return JSON.stringify(arg); } catch(e) { return String(arg); } } return String(arg); }).join(' '); // Skip reporting our own error-monitor failures to prevent infinite loop if (message.includes('[ErrorMonitor] Failed to report error')) { return; } // Skip AUTO-FIX logs from server if (message.includes('AUTO_FIX')) { return; } // Report to server reportError({ type: `console-${method}`, method: method, message: message, args: args.map(arg => { if (typeof arg === 'object') { try { return JSON.stringify(arg); } catch(e) { return String(arg); } } return String(arg); }), timestamp: new Date().toISOString(), url: window.location.href }); // Show error indicator for errors if (method === 'error') { showErrorIndicator(); } }; }); // Global error handler window.addEventListener('error', (event) => { reportError({ type: 'javascript-error', message: event.message, filename: event.filename, line: event.lineno, column: event.colno, stack: event.error?.stack, timestamp: new Date().toISOString(), url: window.location.href }); showErrorIndicator(); }); // Unhandled promise rejection handler window.addEventListener('unhandledrejection', (event) => { reportError({ type: 'unhandled-rejection', message: event.reason?.message || String(event.reason), stack: event.reason?.stack, timestamp: new Date().toISOString(), url: window.location.href }); showErrorIndicator(); }); // Resource loading errors window.addEventListener('error', (event) => { if (event.target !== window) { const src = event.target.src || event.target.href || 'unknown'; reportError({ type: 'resource-error', message: 'Failed to load: ' + src, tagName: event.target.tagName, timestamp: new Date().toISOString(), url: window.location.href }); showErrorIndicator(); } }, true); // Log page load reportError({ type: 'page-load', message: 'Page loaded', url: window.location.href, timestamp: new Date().toISOString() }); // Log SSE client status after page loads setTimeout(() => { reportError({ type: 'sse-status-check', message: 'SSE Client Status', sseClientExists: typeof window.sseClient !== 'undefined', sseClientType: typeof window.sseClient, registerSSEEventHandlersExists: typeof window.registerSSEEventHandlers !== 'undefined', attachedSessionId: window.attachedSessionId || 'not-set', currentSessionId: window.chatSessionId || 'not-set', pathname: window.location.pathname, timestamp: new Date().toISOString() }); }, 2000); // Report any sessionStorage errors from previous page loads try { const stored = sessionStorage.getItem('browser_errors'); if (stored) { const errors = JSON.parse(stored); errors.forEach(err => reportError(err)); sessionStorage.removeItem('browser_errors'); } } catch(e) { // Ignore errors parsing stored errors } console.log('[ErrorMonitor] Enhanced error monitoring active - all console output being sent to server'); })();