You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
9.4 KiB
273 lines
9.4 KiB
/** |
|
* Suppress expected console errors that are not actionable |
|
* This helps reduce noise in the development console |
|
*/ |
|
|
|
// Track suppressed errors to avoid spam |
|
const suppressedErrors = new Set<string>() |
|
|
|
export function suppressExpectedErrors() { |
|
// Override console.error to filter out expected errors |
|
const originalConsoleError = console.error |
|
|
|
console.error = (...args: any[]) => { |
|
const message = args.join(' ') |
|
|
|
// Suppress favicon 404 errors |
|
if (message.includes('favicon.ico') && message.includes('404')) { |
|
return |
|
} |
|
|
|
// Suppress CORS errors for external websites |
|
if (message.includes('CORS policy') || |
|
message.includes('Access-Control-Allow-Origin') || |
|
message.includes('has been blocked by CORS policy') || |
|
message.includes('blocked by CORS policy') || |
|
(message.includes('Access to fetch at') && message.includes('has been blocked')) || |
|
(message.includes('from origin') && message.includes('has been blocked'))) { |
|
return |
|
} |
|
|
|
// Suppress network errors for external websites (including CORS-related failures) |
|
// Suppress all ERR_FAILED errors as they're often CORS-related or expected failures |
|
if (message.includes('net::ERR_FAILED')) { |
|
return |
|
} |
|
|
|
// Suppress postMessage origin errors |
|
if (message.includes('Failed to execute \'postMessage\' on \'DOMWindow\'')) { |
|
return |
|
} |
|
|
|
// Suppress YouTube API warnings |
|
if (message.includes('Unrecognized feature: \'web-share\'')) { |
|
return |
|
} |
|
|
|
// Suppress Canvas2D warnings |
|
if (message.includes('Canvas2D: Multiple readback operations')) { |
|
return |
|
} |
|
|
|
// Suppress React "Maximum update depth exceeded" warnings |
|
// These are often caused by third-party libraries (e.g., Radix UI Popper) |
|
// where we cannot modify the source code directly |
|
if (message.includes('Maximum update depth exceeded')) { |
|
return |
|
} |
|
|
|
// Suppress Radix UI Dialog accessibility warnings |
|
// These are informational warnings about DialogTitle/Description |
|
// All our dialogs have titles (some hidden with sr-only for accessibility) |
|
const isRadixDialogWarning = |
|
(message.includes('DialogContent') || message.includes('DialogTitle')) && |
|
(message.includes('requires') || |
|
message.includes('Missing') || |
|
message.includes('aria-describedby') || |
|
message.includes('DialogTitle')) |
|
if (isRadixDialogWarning) { |
|
return |
|
} |
|
|
|
// Suppress Workbox precaching errors for development modules |
|
if (message.includes('Precaching did not find a match') && ( |
|
message.includes('@vite/client') || |
|
message.includes('main.tsx') || |
|
message.includes('src/') || |
|
message.includes('node_modules/') |
|
)) { |
|
return |
|
} |
|
|
|
// Suppress "too many concurrent REQs" errors (handled by circuit breaker) |
|
if (message.includes('too many concurrent REQs')) { |
|
return |
|
} |
|
|
|
// Suppress relay overload errors (handled by throttling) |
|
if (message.includes('Relay overloaded - too many concurrent requests')) { |
|
return |
|
} |
|
|
|
// Suppress nostr-tools "too many concurrent REQs" errors |
|
if (message.includes('NOTICE from') && message.includes('ERROR: too many concurrent REQs')) { |
|
return |
|
} |
|
|
|
// Suppress nostr-tools connection errors |
|
if (message.includes('NOTICE from') && ( |
|
message.includes('ERROR:') || |
|
message.includes('connection closed') || |
|
message.includes('connection errored') |
|
)) { |
|
return |
|
} |
|
|
|
// Suppress WebSocket connection errors |
|
if (message.includes('WebSocket connection to') || message.includes('failed:') || message.includes('Close received after close')) { |
|
return |
|
} |
|
|
|
// Suppress Ping timeout errors |
|
if (message.includes('Ping timeout')) { |
|
return |
|
} |
|
|
|
// Suppress invalid URL errors (often from empty or malformed relay URLs) |
|
if (message.includes('Invalid URL') || |
|
message.includes('Failed to construct \'URL\'') || |
|
(message.includes('wss://') && message.includes('Invalid')) || |
|
(message.includes('ws://') && message.includes('Invalid'))) { |
|
return |
|
} |
|
|
|
// Suppress invalid URI / media resource errors (e.g. empty img src resolving to origin) |
|
if (message.includes('Ungültige URI') || |
|
message.includes('Invalid URI') || |
|
message.includes('Medienressource') || |
|
(message.includes('fehlgeschlagen') && message.includes('URI')) || |
|
message.includes('Laden der Medienressource') || |
|
message.includes('Failed to load media resource') || |
|
message.includes('OpaqueResponseBlocking')) { |
|
return |
|
} |
|
|
|
// Suppress "unrecognised filter item" errors from relays |
|
if (message.includes('unrecognised filter item') || message.includes('unrecognized filter item')) { |
|
return |
|
} |
|
|
|
// Call original console.error for unexpected errors |
|
originalConsoleError.apply(console, args) |
|
} |
|
|
|
// Override console.warn to filter out expected warnings |
|
const originalConsoleWarn = console.warn |
|
|
|
console.warn = (...args: any[]) => { |
|
const message = args.join(' ') |
|
|
|
// Suppress invalid URI / failed media resource (e.g. empty img src) |
|
if (message.includes('Ungültige URI') || |
|
message.includes('Invalid URI') || |
|
message.includes('Medienressource') || |
|
(message.includes('fehlgeschlagen') && message.includes('URI')) || |
|
message.includes('Laden der Medienressource') || |
|
message.includes('Failed to load media resource')) { |
|
return |
|
} |
|
|
|
// Suppress React DevTools suggestion (only show once) |
|
if (message.includes('Download the React DevTools')) { |
|
if (suppressedErrors.has('react-devtools')) { |
|
return |
|
} |
|
suppressedErrors.add('react-devtools') |
|
} |
|
|
|
// Suppress Workbox warnings |
|
if (message.includes('workbox') && ( |
|
message.includes('will not be cached') || |
|
message.includes('Network request for') || |
|
message.includes('returned a response with status') |
|
)) { |
|
return |
|
} |
|
|
|
// Suppress Canvas2D warnings (performance suggestions) |
|
if (message.includes('Canvas2D') || |
|
message.includes('Multiple readback operations') || |
|
message.includes('willReadFrequently') || |
|
message.includes('getImageData')) { |
|
return |
|
} |
|
|
|
// Suppress CORS policy warnings |
|
if (message.includes('CORS policy') || |
|
message.includes('Access-Control-Allow-Origin') || |
|
message.includes('has been blocked by CORS policy') || |
|
message.includes('blocked by CORS policy') || |
|
(message.includes('Access to fetch') && message.includes('blocked')) || |
|
(message.includes('from origin') && message.includes('blocked'))) { |
|
return |
|
} |
|
|
|
// Suppress network fetch errors that are expected (CORS, etc.) |
|
if (message.includes('Failed to fetch') || |
|
message.includes('net::ERR_FAILED') || |
|
(message.includes('GET ') && message.includes('blocked')) || |
|
(message.includes('fetch') && message.includes('blocked'))) { |
|
return |
|
} |
|
|
|
// Suppress Radix UI Dialog accessibility warnings |
|
// These are informational warnings about DialogTitle/Description |
|
// All our dialogs have titles (some hidden with sr-only for accessibility) |
|
const isRadixDialogWarn = |
|
(message.includes('DialogContent') || message.includes('DialogTitle')) && |
|
(message.includes('requires') || |
|
message.includes('Missing') || |
|
message.includes('aria-describedby') || |
|
message.includes('DialogTitle')) |
|
if (isRadixDialogWarn) { |
|
return |
|
} |
|
|
|
// Suppress Nostr relay NOTICE messages (too many subscriptions, too many REQs, etc.) |
|
if (message.includes('NOTICE from') || |
|
message.includes('Too many subscriptions') || |
|
message.includes('Subscription rejected') || |
|
message.includes('too many concurrent REQs')) { |
|
return |
|
} |
|
|
|
// Call original console.warn for unexpected warnings |
|
originalConsoleWarn.apply(console, args) |
|
} |
|
|
|
// Override console.log to filter out expected logs |
|
const originalConsoleLog = console.log |
|
|
|
console.log = (...args: any[]) => { |
|
const message = args.join(' ') |
|
|
|
// Suppress React DevTools suggestion (only show once) |
|
if (message.includes('Download the React DevTools')) { |
|
return |
|
} |
|
|
|
// Suppress Workbox logs |
|
if (message.includes('workbox') || message.includes('[NoteStats]')) { |
|
return |
|
} |
|
|
|
// Suppress nostr-tools / relay NOTICE messages (subscription limits, REQ limits, etc.) |
|
if (message.includes('NOTICE from') || |
|
message.includes('Too many subscriptions') || |
|
message.includes('Subscription rejected') || |
|
message.includes('too many concurrent REQs')) { |
|
return |
|
} |
|
|
|
// Call original console.log for unexpected logs |
|
originalConsoleLog.apply(console, args) |
|
} |
|
} |
|
|
|
// Suppress unhandled promise rejections that are expected (e.g. SW "operation is insecure" in dev) |
|
function suppressExpectedRejections() { |
|
if (typeof window === 'undefined') return |
|
window.addEventListener('unhandledrejection', (event) => { |
|
const msg = event.reason?.message ?? String(event.reason) |
|
if (msg.includes('The operation is insecure') || (event.reason?.name === 'SecurityError' && msg.includes('insecure'))) { |
|
event.preventDefault() |
|
event.stopPropagation() |
|
} |
|
}) |
|
} |
|
|
|
// Initialize error suppression |
|
if (typeof window !== 'undefined') { |
|
suppressExpectedErrors() |
|
suppressExpectedRejections() |
|
}
|
|
|