File size: 58,115 Bytes
fa9c65f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
/**
 * Deferred Sentry SDK init and filtering policy.
 *
 * This module is dynamically imported by `sentry-defer.ts` so the large
 * `beforeSend` policy and Sentry SDK import stay out of the eager dashboard
 * entry chunk. Keep pre-init queuing in `sentry-defer.ts`; keep SDK setup here.
 */

import { isDebugBearRumScriptFrame } from './debugbear-rum';
import { getSentryBuildMetadata } from './sentry-build-metadata';

type SentryNs = typeof import('@sentry/browser');

// Known third-party hosts fetched by MapLibre (tiles, styles, glyphs, sprites).
// Hosts whose `Failed to fetch (<host>)` errors are suppressed in beforeSend.
// Originally maplibre-only (transient tile/style failures), expanded to cover
// first-party callers that hit the same hosts directly (e.g.
// `MapContainer.fetchAndApplyRadar` β†’ `api.rainviewer.com`). The set IS the
// safety: only known third-party hosts are suppressed; first-party fetches
// to `api.worldmonitor.app` and the self-hosted R2 PMTiles bucket are NOT
// in the set, so genuine basemap / API regressions still surface.
const THIRD_PARTY_FETCH_HOST_ALLOWLIST = new Set([
  'tilecache.rainviewer.com',
  'api.rainviewer.com', // weather radar API used by MapContainer.fetchAndApplyRadar β€” WORLDMONITOR-QG
  'basemaps.cartocdn.com',
  'tiles.openfreemap.org',
  'protomaps.github.io',
  // Clerk Frontend API (CNAME β†’ Clerk's auth infra). The bundled Clerk SDK
  // fetches it for session/token refresh and retries transient failures
  // itself (`retryImmediately`); a `Failed to fetch (clerk.worldmonitor.app)`
  // that leaks to onunhandledrejection is a Clerk-SDK-internal network blip,
  // not our code β€” same disposition as the existing `/ClerkJS: Network error/`
  // ignoreError. NOT our `api.worldmonitor.app`, which stays off the list so
  // genuine API regressions still surface (WORLDMONITOR-SA/SB).
  'clerk.worldmonitor.app',
  // DebugBear RUM beacon collector. We embed the DebugBear RUM script
  // (`src/bootstrap/debugbear-rum.ts` β†’ cdn.debugbear.com) whose collector
  // POSTs field metrics to `data.debugbear.com`; a leaked
  // `NetworkError ... (data.debugbear.com)` / `Failed to fetch (data.debugbear.com)`
  // is a dropped monitoring beacon (adblock / network blip) β€” invisible to the
  // user and unactionable, same disposition as the Clerk-SDK-internal fetch
  // above. NOT `api.worldmonitor.app` (stays off so real API regressions
  // surface). WORLDMONITOR-RP.
  'data.debugbear.com',
  // Self-hosted Umami analytics collector (`src/services/analytics.ts` loads
  // `abacus.worldmonitor.app/script.js`, whose tracker POSTs events to
  // `/api/send`). Same disposition as the DebugBear beacon above: a dropped
  // analytics beacon is invisible to the user and unactionable β€” typically an
  // ad-blocker or a fetch-wrapping extension killing the POST. It reaches
  // Sentry despite the extension gate because the leaked rejection carries our
  // Vite `window.fetch` trampolines, which make hasFirstParty true. Serves no
  // product data, so an abacus outage belongs to uptime monitoring, not a
  // per-user Sentry error. NOT `api.worldmonitor.app` (stays off so real API
  // regressions surface). WORLDMONITOR-WH/WJ.
  'abacus.worldmonitor.app',
]);

function buildSentryInitOptions(): Parameters<SentryNs['init']>[0] {
  const sentryDsn = import.meta.env.VITE_SENTRY_DSN?.trim();
  return {
    dsn: sentryDsn || undefined,
    ...getSentryBuildMetadata(__APP_VERSION__, __BUILD_HASH__),
    environment: (location.hostname === 'worldmonitor.app' || location.hostname.endsWith('.worldmonitor.app')) ? 'production'
      : location.hostname.includes('vercel.app') ? 'preview'
      : 'development',
    enabled: Boolean(sentryDsn) && !location.hostname.startsWith('localhost') && !('__TAURI_INTERNALS__' in window),
    allowUrls: [
      /https?:\/\/(www\.|tech\.|finance\.|commodity\.|happy\.)?worldmonitor\.app/,
      /https?:\/\/.*\.vercel\.app/,
    ],
    sendDefaultPii: true,
    tracesSampleRate: 0.1,
    ignoreErrors: [
      'Invalid WebGL2RenderingContext',
      'WebGL context lost',
      /imageManager/,
      /ResizeObserver loop/,
      /NotAllowedError/,
      /InvalidAccessError/,
      /importScripts/,
      /^TypeError: Load failed( \(.*\))?$/,
      /^TypeError: (?:cancelled|avbruten)$/,
      /runtime\.sendMessage\(\)/,
      /Java object is gone/,
      /^Object captured as promise rejection with keys:/,
      /Unable to load image/,
      /Non-Error promise rejection captured with value:/,
      /Connection to Indexed Database server lost/,
      // Library-thrown (Convex client / Clerk persistent cache) when the user's
      // browser has IndexedDB disabled (Safari Private Browsing, hardened
      // Firefox, some WebView contexts). Our code only initializes the
      // library; the throw is environmental and unavoidable from our side.
      // Same disposition as the existing "Connection to Indexed Database
      // server lost" entry above. WORLDMONITOR-RC.
      /^IndexedDBUnavailableError|IndexedDB is not available in this environment/,
      /webkit\.messageHandlers/,
      /(?:unsafe-eval.*Content Security Policy|Content Security Policy.*unsafe-eval)/,
      /Fullscreen request denied/,
      /requestFullscreen/,
      /webkitEnterFullscreen/,
      /vc_text_indicators_context/,
      /Program failed to link/,
      /too much recursion/,
      /zaloJSV2/,
      /Java bridge method invocation error/,
      /Could not compile fragment shader/,
      /can't redefine non-configurable property/,
      /Can.t find variable: (CONFIG|currentInset|NP|webkit|EmptyRanges|logMutedMessage|UTItemActionController|DarkReader|Readability|onPageLoaded|Game|frappe|getPercent|ucConfig|\$a)/,
      /invalid origin/,
      /\.data\.split is not a function/,
      /signal is aborted without reason/,
      /contentWindow\.postMessage/,
      /Could not compile vertex shader/,
      /objectStoreNames/,
      /Unexpected identifier 'https'/,
      /Can't find variable: _0x/,
      /Can't find variable: video/,
      /hackLocationFailed is not defined/,
      /userScripts is not defined/,
      /NS_ERROR_ABORT/,
      /NS_ERROR_OUT_OF_MEMORY/,
      /NS_ERROR_UNEXPECTED/, // Firefox XPCOM: Worker init failure on privacy-hardened Firefox/Ubuntu β€” WORLDMONITOR-N6/N7/N8/N9
      /NS_ERROR_FILE_NO_DEVICE_SPACE/, // Firefox XPCOM: disk-full on IndexedDB/cache/SW write β€” WORLDMONITOR-Q0
      /DataCloneError.*could not be cloned/,
      /cannot decode message/,
      /WKWebView was deallocated/,
      // WKWebView host-app JS bridge timeout β€” Apple WebKit emits this exact phrase
      // when a JS-to-native `postMessage` (e.g. WKScriptMessageHandler) gets no
      // reply within the host's expected window. Common in in-app browsers like
      // DuckDuckGo / Yelp / Reddit-mobile / Instagram. We never postMessage to a
      // WKScriptMessageHandler ourselves; this is browser-native and unactionable
      // (WORLDMONITOR-KJ β€” 15 events / 14 users in DuckDuckGo 26.3 on macOS).
      /WKWebView API client did not respond to this postMessage/,
      /Unexpected end of(?: JSON)? input/,
      /window\.android\.\w+ is not a function/,
      /Attempted to assign to readonly property/,
      /Cannot assign to read only property/,
      /FetchEvent\.respondWith/,
      /QuotaExceededError/,
      /^TypeError: ε·²ε–ζΆˆ$/,
      /^fetchError: Network request failed$/,
      /window\.ethereum/,
      /setting 'luma'/,
      /ML request .* timed out/,
      /(?:AbortError: )?The operation was aborted\.?\s*$/,
      // Bare `Uncaught Error: AbortError` (no message body) from Convex
      // server-side action timeouts auto-captured by Convex's Sentry
      // integration. Zero-frame, environment 'prod', no actionable context
      // β€” the action retries cleanly. WORLDMONITOR-QH.
      /^Uncaught Error: AbortError$/,
      /Unexpected end of script/,
      /Style is not done loading/,
      /Event `CustomEvent`.*captured as promise rejection/,
      /Event `ProgressEvent`.*captured as promise rejection/, // resource/XHR `error` ProgressEvent leaking via onunhandledrejection (img/script/audio/EventSource load failure). Our IDB/worker/FileReader onerror handlers all reject with wrapped Errors (never a raw ProgressEvent); the only XHR caller is fire-and-forget + Tauri-desktop-only where Sentry is disabled β€” so a raw ProgressEvent rejection can never originate from our bundle. Sibling of the CustomEvent entry above β€” WORLDMONITOR-SQ
      /getProgramInfoLog/,
      /__firefox__/,
      /ifameElement\.contentDocument/,
      /Invalid video id/,
      /Fetch is aborted/,
      /Stylesheet append timeout/,
      /Worker is not a constructor/,
      /_pcmBridgeCallbackHandler/,
      /UCShellJava/,
      /Cannot define multiple custom elements/,
      /maxTextureDimension2D/,
      /Container app not found/,
      /this\.St\.unref/,
      /evaluating 'elemFound\.value'/,
      /[Cc]an(?:'t|not) access (?:'\w+'|lexical declaration '\w+') before initialization/,
      /^Uint8Array$/,
      /createObjectStore/,
      /The database connection is closing/,
      /shortcut icon/,
      /Attempting to change value of a readonly property/,
      /reading 'nodeType'/,
      /The node to be removed is not a child of this node/,
      /The object can not be found here/, // Safari variant of above (Clerk SDK removeChild on detached DOM)
      /feature named .\w+. was not found/,
      /a2z\.onStatusUpdate/,
      /Attempting to run\(\), but is already running/,
      /this\.player\.destroy is not a function/,
      /isReCreate is not defined/,
      /reading 'style'.*HTMLImageElement/,
      /can't access property "write", \w+ is undefined/,
      /(?:AbortError: )?The user aborted a request/,
      /\w+ is not a function.*\/uv\/service\//,
      /__isInQueue__/,
      /^(?:LIDNotify(?:Id)?|onWebViewAppeared|onGetWiFiBSSID|onHide|onShow|onReady|tapAt|removeHighlight|UTItemActionController) is not defined$/,
      /Se requiere plan premium/,
      /hybridExecute is not defined/,
      /reading 'postMessage'/,
      /appendChild.*Unexpected token/,
      /\bmag is not defined\b/,
      /evaluating '[^']*\.luma/,
      /translateNotifyError/,
      /GM_getValue/,
      /gm_menus/, // WORLDMONITOR-TJ β€” Greasemonkey/Violentmonkey internal (GUID-keyed window['<uuid>'].gm_menus userscript-menu registry); never in our bundle, sibling of GM_getValue
      /^InvalidStateError:|The object is in an invalid state/,
      /Could not establish connection\. Receiving end does not exist/,
      /webkitCurrentPlaybackTargetIsWireless/,
      /webkit(?:Supports)?PresentationMode/,
      /Cannot redefine property: webdriver/,
      /null is not an object \(evaluating '\w+\.theme'\)/,
      /this\.player\.\w+ is not a function/,
      /videoTrack\.configuration/,
      /evaluating 'v\.setProps'/,
      /button\[aria-label/,
      /The fetching process for the media resource was aborted/,
      /Invalid regular expression: missing/,
      /WeixinJSBridge/,
      /evaluating '\w+\.type'/,
      /Policy with name .* already exists/,
      /[sx]wbrowser is not defined/,
      /browser\.storage\.local/,
      /The play\(\) request was interrupted/,
      /MutationEvent is not defined/,
      /Cannot redefine property: userAgent/,
      /st_framedeep|ucbrowser_script/,
      /iabjs_unified_bridge/,
      /DarkReader/,
      /window\.receiveMessage/,
      /Cross-origin script load denied/,
      /orgSetInterval is not a function/,
      /Blocked a frame with origin.*accessing a cross-origin frame/,
      /SnapTube/,
      /sortedTrackListForMenu/,
      /isWhiteToBlack/,
      /window\.videoSniffer/,
      /closeTabMediaModal/,
      /missing \) after argument list/,
      /Error invoking postMessage: Java exception/,
      /IndexSizeError/,
      /Failed to construct 'Worker'.*cannot be accessed from origin/,
      /undefined is not an object \(evaluating '(?:this\.)?media(?:Controller)?\.(?:duration|videoTracks|readyState|audioTracks|media)/,
      /\$ is not defined/,
      /Qt\([^)]*\) is not a function/,
      /shaderSource must be an instance of WebGLShader/,
      /WebGL2RenderingContext\.shaderSource: Argument 1 is not an object/,
      // Chrome wording for the same condition (gl.createShader returned null,
      // typically after WebGL context loss or on degraded GPU drivers). WORLDMONITOR-RM.
      /Failed to execute 'shaderSource' on 'WebGL2?RenderingContext': parameter 1 is not of type 'WebGLShader'/,
      /Failed to initialize WebGL/,
      /opacityVertexArray\.length/,
      /Length of new data is \d+, which doesn't match current length of/,
      /^AJAXError:.*(?:Load failed|Unauthorized|\(401\))/,
      /^NetworkError: Load failed$/,
      /^A network error occurred\.?$/,
      /nmhCrx is not defined/,
      /\bcrusoe is not defined\b/, // WORLDMONITOR-R3 β€” injected userscript reference, anonymous-frames-only stack
      /\bvc_request_action is not defined\b/, // WORLDMONITOR-RB β€” Samsung Internet / Tizen smart-view-cast global injection
      /\bmainWorldSdk is not defined\b/, // WORLDMONITOR-TG β€” browser extension SDK injected into the page main world references its global before define; not in our bundle (Edge 148/Windows, anonymous-frames-only stack)
      /navigationPerformanceLoggerJavascriptInterface/,
      /jQuery is not defined/,
      /illegal UTF-16 sequence/,
      /detectIncognito/,
      /Cannot read properties of null \(reading '__uv'\)/,
      /Can't find variable: p\d+/,
      /^timeout$/,
      /Can't find variable: caches/,
      /crypto\.randomUUID is not a function/,
      /ucapi is not defined/,
      /Identifier '(?:script|reportPage|element|Shop|change_ua|originalPrompt)' has already been declared/, // change_ua: User-Agent-changer browser extension injecting same script twice β€” WORLDMONITOR-2D (88 events / 26 users). originalPrompt: extension hooking window.prompt double-injected β€” WORLDMONITOR-TE (not in our bundle; build would fail on a duplicate top-level const)
      /getAttribute is not a function.*getAttribute\("role"\)/,
      /SCDynimacBridge/,
      /errTimes is not defined/,
      /Failed to get ServiceWorkerRegistration/,
      /^ReferenceError: Cannot access uninitialized variable\.?$/,
      /Failed writing data to the file system/,
      /Error invoking initializeCallbackHandler/,
      /releasePointerCapture.*Invalid pointer/,
      /Array buffer allocation failed/,
      /Client can't handle this message/,
      /Invalid LngLat object/,
      /autoReset/,
      /webkitExitFullScreen/,
      /downProgCallback/,
      /syncDownloadState/,
      /^ReferenceError: HTMLOUT is not defined$/,
      /^ReferenceError: xbrowser is not defined$/,
      /LibraryDetectorTests_detect/,
      /contentBoxSize\[0\] is undefined/,
      /Attempting to run\(\), but is already running/,
      /Out of range source coordinates for DEM data/,
      /Invalid character: '\\0'/,
      /Failed to execute 'unobserve' on 'IntersectionObserver'/,
      /WKErrorDomain/,
      /Content-Length header of network response exceeds response Body/,
      /^Uncaught \[object ErrorEvent\]$/,
      /^\[object Event\]$/,
      /trsMethod\w+ is not defined/,
      /checkLogin is not a function/,
      /VConsole is not defined/,
      /exitFullscreen.*Document not active/,
      /Force close delete origin/,
      /zp_token is not defined/,
      /literal not terminated before end of script/,
      /'' is not a valid selector/,
      /frappe is not defined/,
      /Unexpected identifier 'does'/,
      /Failed reading data from the file system/,
      /^UnavailableError(:.*)?$/,
      /null is not an object \(evaluating '\w{1,3}\.indexOf'\)/,
      /export declarations may only appear at top level/,
      /ucConfig is not defined/,
      /getShaderPrecisionFormat/,
      /Cannot read properties of null \(reading 'touches'\)/,
      /Failed to execute 'querySelectorAll' on '[^']*': ':[a-z]+\(/,
      /args\.site\.enabledFeatures/,
      /can't access property "\w+", FONTS\[/,
      /null is not an object \(evaluating '\w+\.magnitude\.toFixed'\)/,
      /start offset of Int16Array should be a multiple of 2/,
      /Cannot read properties of undefined \(reading 'then'\)/,
      /^(?:Error: )?uncaught exception: undefined$/,
      /ss_bootstrap_config/, // Surfly proxy β€” "Can't find variable: ss_bootstrap_config" (Safari) or "ss_bootstrap_config is not defined" (Chrome)
      /undefined is not an object \(evaluating '[a-z]\.includes'\)/,
      /^"use strict" is not a function$/,
      /Can only call Window\.setTimeout on instances of Window/, // iOS Safari cross-frame setTimeout from 3rd-party injected script
      /^Can't find variable: _G$/, // browser extension/userscript injecting _G global
      /onAppPageCallback is not defined/, // Android Chrome WebView injection (Huawei/Samsung browsers)
      /\.at is not a function/, // Instagram/older Android in-app browsers missing Array.at()
      /Response cannot have a body with the given status/, // Safari: Response constructor with 204/304 + body
      /ClerkJS: Network error/, // Clerk SDK transient network failures on user devices
      /^ClerkJS: Response: needs_(?:first|second)_factor\b/, // Clerk SDK auth-flow branch not yet supported; SDK-internal limitation, not our code β€” WORLDMONITOR-Q1. Narrow to the observed `needs_*_factor` family so future actionable `ClerkJS: Response: <something>` errors (e.g. misconfigured redirect URI) still surface.
      /\[clerk\] failed to load/, // Clerk SDK failed to load its own UI chunk from clerk.worldmonitor.app β€” SDK-internal load failure, not our code (WORLDMONITOR-??: Yandex Browser 26.4).
      /doesn't provide an export named/, // stale cached chunk after deploy references removed export
      /Possible side-effect in debug-evaluate/, // Chrome DevTools internal EvalError
      /ConvexError: CONFLICT/, // Expected OCC rejection on concurrent preference saves
      /ConvexError: API_ACCESS_REQUIRED/, // Expected business error: free user opens API Keys tab; client handles gracefully (UnifiedSettings.ts:731-738) β€” WORLDMONITOR-NA
      /\[CONVEX [AQM]\(.+?\)\] Connection lost while action was in flight/, // Convex SDK transient WS disconnect
      /^Invalid start version: \d+:\d+:\d+, transitioning from \d+:\d+:\d+$/, // Convex SDK internal sync protocol error from `remote_query_set.js` (server republished query mid-transition or WS reconnect race) β€” WORLDMONITOR-Q5
      /Response did not contain `success` or `data`/, // DuckDuckGo browser internal tracker/content-block response β€” never emitted by our code
      /Cannot set properties of undefined \(setting 'bodyTouched'\)/, // Quark browser (Alibaba mobile) touch-tracking script injection (WORLDMONITOR-N1)
      /Cannot read properties of \w+ \(reading '[^']*[^\x00-\x7F][^']*'\)/, // Non-ASCII property name in message = mojibake/corrupted identifier from injected extension; our bundle emits ASCII-only identifiers (WORLDMONITOR-NS)
      /Octal literals are not allowed in strict mode/, // Runtime SyntaxError from injected extension script; our TS bundle never emits octal literals and doesn't eval (WORLDMONITOR-NV)
      /Unexpected identifier 'm'/, // Foreign script injection on Opera; pre-compiled bundle can't parse-fail at runtime (WORLDMONITOR-NT)
      /PlayerControlsInterface\.\w+ is not a function/, // Android Chrome WebView native bridge injection (Bilibili/UC/QQ-style host) β€” never emitted by our code (WORLDMONITOR-P2)
      /github\.com\/styled-components\/styled-components\/blob/, // styled-components runtime error (errors.md#N URL); we don't depend on styled-components, so it can only be a browser extension (Grammarly et al.) injecting its own bundle β€” WORLDMONITOR-SE
    ],
    beforeSend(event) {
      const msg = event.exception?.values?.[0]?.value ?? '';
      if (msg.length <= 3 && /^[a-zA-Z_$]+$/.test(msg)) return null;
      const frames = event.exception?.values?.[0]?.stacktrace?.frames ?? [];
      const vendorChunk = /\/(maplibre|deck-stack|d3|topojson|i18n|sentry|transformers|onnxruntime)-[A-Za-z0-9_-]+\.js/;
      const firstPartyFile = (filename: string) => {
        if (/\.(ts|tsx)$/.test(filename) || /^src\//.test(filename)) return true;
        if (/\/assets\/[A-Za-z0-9_-]+(-[A-Za-z0-9_-]+)*\.js/.test(filename)) return !vendorChunk.test(filename);
        return false;
      };
      const nonInfraFrames = frames.filter(f => f.filename && f.filename !== '<anonymous>' && f.filename !== '[native code]' && !/\/sentry-[A-Za-z0-9_-]+\.js/.test(f.filename));
      const hasFirstParty = nonInfraFrames.some(f => firstPartyFile(f.filename ?? ''));
      const hasAnyStack = nonInfraFrames.length > 0;
      // Suppress maplibre internal null-access crashes (light, placement) only when stack is in map chunk
      if (/this\.style\._layers|reading '_layers'|this\.(light|sky) is null|can't access property "(id|type|setFilter|bind)"[,] ?[\w.]+ is (null|undefined)|can't access property "(id|type)" of null|Cannot read properties of null \(reading '(id|type|setFilter|_layers)'\)|null is not an object \(evaluating '\w{1,3}\.(id|style)|^\w{1,2} is null$/.test(msg)) {
        if (frames.some(f => /\/(map|maplibre|deck-stack)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      }
      // Suppress any TypeError / RangeError that happens entirely within maplibre or deck.gl internals.
      // RangeError: "Invalid array length" during deck.gl bindVertexArray / _updateCache on large
      // GL layer updates (vertex-buffer allocation failure in vendor code β€” WORLDMONITOR-N4).
      // EXCEPTION: `Failed to fetch (<host>)` is routed through the host-allowlist block below
      // so a self-hosted R2 PMTiles / first-party basemap regression isn't silently dropped just
      // because its stack happens to be all-vendor frames (WORLDMONITOR-NE/NF follow-up).
      const excType = event.exception?.values?.[0]?.type ?? '';
      // Host-suffixed fetch-failure shapes β€” Chrome/Edge `Failed to fetch (<host>)`
      // (maplibre's AJAX wrapper AND first-party fetch callers) and Firefox
      // `NetworkError when attempting to fetch resource. (<host>)` (the
      // engine-equivalent phrasing, e.g. an embedded SDK's beacon fetch β€”
      // WORLDMONITOR-RP). Both route through the host allowlist below, which is
      // the load-bearing safety; this match is just the shape detector.
      const isHostScopedFetchFailure = excType === 'TypeError'
        && /^(?:Failed to fetch|NetworkError when attempting to fetch resource\.) \([^)]+\)$/.test(msg);
      if (!isHostScopedFetchFailure
          && (excType === 'TypeError' || excType === 'RangeError' || /^(?:TypeError|RangeError):/.test(msg))
          && frames.length > 0) {
        if (nonInfraFrames.length > 0 && nonInfraFrames.every(f => /\/(map|maplibre|deck-stack)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      }
      // Suppress `Failed to fetch (<host>)` for known third-party hosts. Originally
      // scoped to maplibre's tile/style/glyph fetches (which wrap transient network
      // errors and rethrow in a Generator-backed Promise that leaks to
      // onunhandledrejection even though DeckGLMap's map-error handler already
      // logs the warning). Expanded (WORLDMONITOR-QG) to also cover first-party
      // call sites that fetch the same allowlisted hosts directly β€” e.g.
      // `MapContainer.fetchAndApplyRadar` hitting `api.rainviewer.com`. The
      // host-allowlist set is the load-bearing safety: only known third-party
      // hosts get suppressed; first-party fetch failures (self-hosted R2 PMTiles
      // bucket, `api.worldmonitor.app`) are intentionally NOT in the set so a
      // real basemap / API regression is never silently dropped
      // (WORLDMONITOR-NE/NF, WORLDMONITOR-QG).
      if (isHostScopedFetchFailure) {
        const hostMatch = msg.match(/^(?:Failed to fetch|NetworkError when attempting to fetch resource\.) \(([^)]+)\)$/);
        const host = hostMatch?.[1];
        if (host && THIRD_PARTY_FETCH_HOST_ALLOWLIST.has(host)) return null;
      }
      // Suppress Three.js/globe.gl TypeError crashes in main bundle (reading 'type'/'pathType'/'count'/'__globeObjType' on undefined during WebGL traversal/raycast).
      // __globeObjType is exclusively set by three-globe on its own objects and we have no user onClick/onHover handler, so it is always globe.gl internal even when the stack shows the bundled main chunk (WORLDMONITOR-ME).
      if (/reading '__globeObjType'|__globeObjType/.test(msg)) return null;
      if (/reading '(?:type|pathType|count)'|can't access property "(?:type|pathType|count|__globeObjType)",? \w+ is (?:undefined|null)|undefined is not an object \(evaluating '\w+\.(?:pathType|count)'\)/.test(msg)) {
        if (!hasFirstParty) return null;
      }
      // deck.gl/maplibre internal null-access on Layer.isHidden during render (Safari 26.4 beta,
      // empty stacks, preceded by DeckGLMap map-error breadcrumbs). Our first-party `isHidden`
      // lives on SmartPollContext in runtime.ts β€” any access there would produce frames, so gate
      // on !hasFirstParty to preserve signal on a real poller regression (WORLDMONITOR-NR).
      if (/undefined is not an object \(evaluating '\w{1,3}\.isHidden'\)|Cannot read properties of undefined \(reading 'isHidden'\)/.test(msg)) {
        if (!hasFirstParty) return null;
      }
      // Short minified ReferenceError from Safari ("Can't find variable: ss"). With an empty stack
      // and no first-party frames, this is userscript/extension injection. Our own minified bundle
      // would keep frames via the source-mapped assets/*.js chunks; if the SDK strips them, the
      // stack is non-empty. Bound var length to 1–2 to avoid masking a real "foo is not defined"
      // that happens to hit the unhandledrejection path (WORLDMONITOR-NQ).
      if (!hasFirstParty && frames.length === 0 && /^Can't find variable: \w{1,2}$/.test(msg)) return null;
      // Suppress minified Three.js/globe.gl crashes (e.g. "l is undefined" in raycast, "b is undefined" in update/initGlobe)
      if (/^\w{1,2} is (?:undefined|not an object)$/.test(msg) && frames.length > 0) {
        if (frames.some(f => /\/(main|index)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? '') && /(raycast|update|initGlobe|traverse|render)/.test(f.function ?? ''))) return null;
      }
      // Suppress Three.js OrbitControls touch crashes (finger lifted during pinch-zoom).
      // OrbitControls is bundled into the main chunk, so hasFirstParty is true.
      // Match by function name pattern (_handleTouch*Dolly*) or suppress when no first-party frames.
      //
      // Symbolicated case: function name regex hits (_handleTouchDolly*, OrbitControls).
      // Unsymbolicated case (Sentry WORLDMONITOR-P7): single minified frame in the main
      // bundle (e.g. `Yge`) on iOS/iPadOS Safari. iOS is the only platform where a
      // touch-driven `t.x` crash is plausible AND the production build can lose source
      // maps for OrbitControls' touch handlers. Gate on:
      //   - exactly one main-bundle frame in the trace (no other first-party functions)
      //   - device.family/os indicates iOS/iPadOS
      // so a real `t.x` regression elsewhere on desktop still surfaces.
      if (/undefined is not an object \(evaluating 't\.x'\)|Cannot read properties of undefined \(reading 'x'\)/.test(msg)) {
        if (!hasFirstParty || frames.some(f => /\b_handleTouch\w*Dolly|OrbitControls/.test(f.function ?? ''))) return null;
        const osName = ((event.contexts as any)?.os?.name as string) ?? '';
        const isTouchOs = /^(iOS|iPadOS)$/.test(osName);
        const mainBundleFrames = nonInfraFrames.filter(f => /\/(main|index)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''));
        if (isTouchOs && mainBundleFrames.length === 1 && nonInfraFrames.length === mainBundleFrames.length) return null;
      }
      // Suppress Three.js OrbitControls pointer-capture race: pointerdown handler calls
      // setPointerCapture but the browser has already released the pointer (focus change,
      // rapid re-tap). OrbitControls is bundled into main-*.js, so hasFirstParty=true and
      // production stacks are often unsymbolicated β€” require a positive three.js signature
      // in the frame context (the literal `this._pointers … setPointerCapture` code slice)
      // so an unrelated first-party setPointerCapture regression still surfaces (WORLDMONITOR-NC).
      if (excType === 'NotFoundError' && /setPointerCapture.*No active pointer with the given id/.test(msg)) {
        // Sentry wire format includes `context: [[lineno, text], ...]` per frame, but the
        // SDK's StackFrame type omits it β€” cast to any to read it.
        const hasOrbitControlsContext = frames.some(f => {
          const ctx = (f as any).context;
          if (!Array.isArray(ctx)) return false;
          return ctx.some(row =>
            Array.isArray(row) && typeof row[1] === 'string'
            && /_pointers[^\n]*setPointerCapture|setPointerCapture[^\n]*_pointers/.test(row[1]),
          );
        });
        if (hasOrbitControlsContext) return null;
      }
      // Suppress deck.gl/maplibre null-access crashes with no usable stack trace (requestAnimationFrame wrapping)
      if (/null is not an object \(evaluating '\w{1,3}\.(id|type|style)'\)/.test(msg) && frames.length === 0) return null;
      // Suppress Safari sortedTrackListForMenu native crash (value is generic "Type error", function name in stack)
      if (excType === 'TypeError' && frames.some(f => /sortedTrackListForMenu/.test(f.function ?? ''))) return null;
      // Suppress TypeErrors from anonymous/injected scripts (no real source files or only inline page URL)
      if ((excType === 'TypeError' || /^TypeError:/.test(msg)) && frames.length > 0 && frames.every(f => !f.filename || f.filename === '<anonymous>' || /^blob:/.test(f.filename) || /^https?:\/\/[^/]+\/?$/.test(f.filename))) return null;
      // Suppress errors thrown by an injected browser-automation harness driving
      // the page (e.g. Floot's agent). Its selector-resolution helpers throw
      // `Element not found: <sel>`, `No element found: <sel>`, and
      // `$pressKey(...) was called with no selector` from an injected
      // `<anonymous>` script (helperGetStyle et al.), and reference Floot's own
      // `data-floot-id` attribute. These are generic `Error` (not TypeError, so
      // the anonymous-script gate above misses them) whose only frames are
      // `<anonymous>` β†’ hasFirstParty=false. Our bundle never emits these
      // phrasings (grep-verified across src/ + api/). Gated on !hasFirstParty so
      // a same-worded first-party error would still surface. The `... found:`
      // matches REQUIRE the trailing colon+selector, leaving the colon-less
      // ambiguous `Element not found` (handled by the !hasFirstParty ambiguous
      // gate below, which additionally demands a confirmed third-party stack)
      // untouched. WORLDMONITOR-VR/VV/VW/VX/VY/VS/VT/VZ (2026-07-09 Floot agent).
      // NB: the `called with no selector` regex deliberately omits the leading
      // "was " β€” the beforeSend unit-test harness strips TypeScript `as <T>`
      // assertions with a crude `/as\s+\w+/` that also mangles the English
      // "was called". Matching from "called" keeps the test's eval'd copy intact.
      if (!hasFirstParty && (
        /^(?:Element not found|No element found):/.test(msg)
        || /\bcalled with no selector\b/.test(msg)
        || /data-floot-id/.test(msg)
      )) return null;
      // Suppress parentNode.insertBefore from injected/inline scripts (iOS WKWebView, Apple Mail)
      // Also covers [native code] frames (no filename) produced by WKWebView's forEach wrapper
      if (/parentNode\.insertBefore/.test(msg) && frames.every(f => !f.filename || f.filename === '<anonymous>' || f.filename === '[native code]' || /^blob:/.test(f.filename) || /^https?:\/\/[^/]+\/?$/.test(f.filename))) return null;
      // Suppress TypeErrors whose ONLY source frames are non-script URLs β€” the
      // page document URL itself (a relative path like `/dashboard` or the full
      // `https://<host>/dashboard`) or any external resource served without a
      // recognized script extension. Scripts injected into the page's MAIN world
      // β€” WKUserScript content scripts on Firefox iOS / other in-app WebViews,
      // bookmarklets β€” are attributed by WebKit to the document URL (line 1,
      // minified fns `o`/`s`/`Or`, with native `insertBefore`/`forEach` frames),
      // not to a distinct `.js` script URL. Our own shipped code never runs from
      // such a URL: the app entry is a hashed `/assets/*.js` module chunk (flagged
      // first-party by firstPartyFile), so a TypeError with zero first-party
      // frames whose non-infra frames are all non-script URLs cannot originate in
      // our bundle. The `frames.every(...)` injected-script gate above misses this
      // because the `[native code]` insertBefore/forEach frames break its
      // predicate and its page-URL matcher only accepts bare origins, not document
      // paths (WORLDMONITOR-V8: Firefox iOS 152, `undefined is not an object
      // (evaluating 's[e]')`, insertBefore in a promiseReactionJob β€” 6 events / 1
      // user).
      //
      // `isNonScriptUrlFrame` is intentionally broader than "page document": the
      // `https?://` branch also matches extensionless third-party script URLs
      // (e.g. `https://js.stripe.com/v3/`). That is still correct to suppress here
      // β€” the `!hasFirstParty` guard already proves zero first-party involvement,
      // so a same-shaped error from a third-party host is equally unactionable.
      const isNonScriptUrlFrame = (filename: string) =>
        !/\.(?:m|c)?[jt]sx?(?:[?#]|$)/.test(filename)
        && (/^\/(?!\/)/.test(filename) || /^https?:\/\//.test(filename));
      if ((excType === 'TypeError' || /^TypeError:/.test(msg))
          && !hasFirstParty
          && nonInfraFrames.length > 0
          && nonInfraFrames.every(f => isNonScriptUrlFrame(f.filename ?? ''))) return null;
      // Suppress NotFoundError: insertBefore with no usable stack (Chrome 146+ extension DOM interference β€” stack shows minified bundle but no line/function)
      if (excType === 'NotFoundError' && /insertBefore/.test(msg) && frames.every(f => !f.lineno && !f.function)) return null;
      // Suppress Sentry breadcrumb DOM-measuring crashes (element.offsetWidth on detached DOM)
      if (/evaluating '(?:element|e)\.offset(?:Width|Height)'/.test(msg) && frames.some(f => /\/sentry-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      // Suppress errors originating entirely from blob: URLs (browser extensions)
      if (frames.length > 0 && frames.every(f => /^blob:/.test(f.filename ?? ''))) return null;
      // Suppress errors where any frame is a chrome/moz/safari extension, ONLY when stack has no first-party frames.
      // A first-party frame elsewhere in the stack means the error likely originated in our code; surface it even if
      // an extension wrapped the call.
      if (!hasFirstParty && frames.some(f => /^(?:chrome|moz|safari(?:-web)?)-extension:\/\//.test(f.filename ?? ''))) return null;
      // Bare `Failed to fetch` leaking via onunhandledrejection when a browser
      // extension has monkeypatched `window.fetch` (e.g. Adjust SDK's
      // injectScriptAdjust.js, page-inspector extensions) and chained an uncaught
      // `.then()` on the result. A transient network blip rejects the underlying
      // fetch and the extension's orphan promise surfaces as an unhandled rejection.
      // Our first-party frames (the runtime fetch interceptor + country-geometry
      // loader) appear ONLY because our wrapper sits in the call chain β€” our own
      // fetch callers already wrap rejections in try/catch (country-geometry's
      // ensureLoaded logs a warning and resolves), so this is NOT a first-party
      // leak. Unlike the generic `!hasFirstParty` `Failed to fetch` gate below,
      // this fires WITH first-party frames present, but only when an extension has
      // a monkeypatched-`window.fetch` frame on the stack β€” a genuine API outage
      // (host-suffixed `Failed to fetch (<host>)`, handled above) and any
      // non-extension user are unaffected. The function match is anchored to
      // exactly `window.fetch` / `fetch` or the `Function.prototype.apply`
      // trampoline (`Object.apply` / `apply`) an extension's hook.js uses to
      // re-invoke the original fetch β€” NOT a loose `/fetch/` β€” so an extension
      // frame named `fetchContent` / `prefetch` does NOT swallow a real bare
      // `Failed to fetch` from our own code (WORLDMONITOR-SG). The `apply`
      // trampoline variant is WORLDMONITOR-TZ: a wallet extension's
      // `injected/hook.js` wraps `window.fetch` and the leaked rejection frame
      // surfaces as `Object.apply`, not `window.fetch`.
      if (/^(?:TypeError: )?Failed to fetch$/.test(msg)
          && frames.some(f => /^(?:chrome|moz|safari(?:-web)?)-extension:\/\//.test(f.filename ?? '') && /^(?:(?:.*\.)?window\.|(?:window|Object)\.)?(?:fetch|apply)$/i.test(f.function ?? ''))) {
        return null;
      }
      // Bare `Failed to fetch` surfacing through the DebugBear RUM collector's
      // window.fetch monkeypatch. DebugBear (src/bootstrap/debugbear-rum.ts β†’
      // cdn.debugbear.com/<id>.js; Sentry attributes its frames to the script
      // configured script path) wraps window.fetch to time it, so a
      // transient network blip on ANY app fetch rejects and its wrapper
      // re-surfaces the rejection as an unhandled rejection, injecting its own
      // frames. Without DebugBear the identical failure is zero-frame and already
      // suppressed above β€” the collector's frames are the ONLY reason it reaches
      // here. The `/assets/*.js` frames it carries are `window.fetch` TRAMPOLINES
      // (Vite code-split chunk names, e.g. panel-storage/widget-store, which do
      // not themselves fetch β€” grep-verified), NOT real callers. Suppress only
      // when a DebugBear collector frame is present AND every non-infra frame is
      // either that collector or the observed caller-free `window.fetch`/`fetch`
      // trampolines from panel-storage/widget-store. Other first-party fetch
      // wrappers (notably runtime.ts) must surface. Mirrors the SG
      // extension-wrapper gate above; collector identity comes from
      // DEBUGBEAR_RUM_SCRIPT_SRC via the shared predicate.
      // WORLDMONITOR-VC (93ev/69u, 2026-07-04+).
      // The optional `\w{1,3}.` receiver prefix is WORLDMONITOR-VQ: a later Vite
      // build emits the same trampoline as `Rt.window.fetch` rather than a bare
      // `window.fetch`, and the anchored match rejected it, so the identical
      // wrapper class re-surfaced as a new issue. The prefix is bounded to a
      // minified identifier (≀3 chars) so a real named receiver β€” e.g.
      // `apiClient.fetch` β€” is still read as a genuine caller and surfaces.
      if (/^(?:TypeError: )?Failed to fetch$/.test(msg)
          && frames.some(f => isDebugBearRumScriptFrame(f.filename ?? ''))
          && nonInfraFrames.every(f =>
            isDebugBearRumScriptFrame(f.filename ?? '')
            || (/\/assets\/(?:panel-storage|widget-store)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? '')
              && /^(?:\w{1,3}\.)?(?:window\.)?fetch$/.test(f.function ?? '')))) {
        return null;
      }
      // Suppress Sentry SDK DOM breadcrumb null-access on document.activeElement/contains.
      // Gated on !hasFirstParty because Sentry wraps first-party handlers, so a genuine app `el.contains(...)` bug
      // can produce a stack containing both main-*.js and sentry-*.js frames.
      if (!hasFirstParty && /Cannot read properties of null \(reading 'contains'\)|null is not an object \(evaluating '\w+\.contains'\)/.test(msg) && frames.some(f => /\/sentry-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      // Suppress Convex WS onmessage JSON.parse truncation (intermittent WS frame splits on Ping/Updated control messages)
      if (excType === 'SyntaxError' && /is not valid JSON/.test(msg) && !hasFirstParty && frames.some(f => /onmessage/.test(f.function ?? ''))) return null;
      // Suppress errors originating from UV proxy (Ultraviolet service worker)
      if (frames.some(f => /\/uv\/service\//.test(f.filename ?? '') || /uv\.handler/.test(f.filename ?? ''))) return null;
      // Suppress Greasemonkey/Tampermonkey userscript errors (x-plugin-script, stay-userscript.html)
      if (frames.length > 0 && frames.every(f => !f.filename || /\/x-plugin-script\/|\/stay-userscript\.html$/.test(f.filename))) return null;
      // Suppress YouTube IFrame widget API internal errors
      if (frames.some(f => /www-widgetapi\.js/.test(f.filename ?? ''))) return null;
      // Suppress Sentry beacon XHR transport errors (readyState on aborted XHR β€” not our code)
      if (frames.some(f => /beacon\.min\.js/.test(f.filename ?? ''))) return null;
      // Suppress Fireglass (Symantec/Broadcom CloudSOC) console-hook recursion.
      // Fireglass wraps console.log and recurses on its own debug output, producing
      // "Maximum call stack size exceeded". Stack frames are <anonymous> so the
      // generic hasFirstParty gate below can't see it β€” match by function name.
      // Gated on excType === 'RangeError' (mirrors the sortedTrackListForMenu
      // pattern above) so an unrelated exception with a FireglassUtils frame
      // isn't silently dropped (WORLDMONITOR-MK).
      if (excType === 'RangeError' && frames.some(f => /FireglassUtils/.test(f.function ?? ''))) return null;
      // Suppress Chrome Mobile WebView 105+ Request constructor quirk ONLY when
      // the Dodo checkout lazy chunk is in the stack (WORLDMONITOR-MH). The
      // exact message is unique to the Fetch Β§ Request() duplex requirement, but
      // src/services/runtime.ts (runtime fetch patch) also constructs `new
      // Request(init)` at lines 861/869/902 β€” without this provenance guard the
      // same filter would hide a real first-party streaming-fetch regression.
      // Guard on the vendored chunk name (checkout-*.js = Dodo SDK, lazy-loaded
      // only when startCheckout runs) so a runtime.ts failure still surfaces.
      if (/Failed to construct 'Request': The `duplex` member must be specified/.test(msg)
          && frames.some(f => /\/assets\/checkout-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      // Suppress "options is not defined" from browser extension overriding Navigator getter (WORLDMONITOR-JN).
      // Only suppress when stack has no first-party frames (filename=<anonymous> is the extension getter).
      if (/^options is not defined$/.test(msg) && frames.every(f => !f.filename || f.filename === '<anonymous>' || f.filename === '[native code]')) return null;
      // Suppress TransactionInactiveError only when no first-party frames are present
      // (Safari kills open IDB transactions in background tabs β€” not actionable noise)
      // First-party paths in storage.ts / persistent-cache.ts / vector-db.ts must still surface.
      if ((/TransactionInactiveError/.test(msg) || excType === 'TransactionInactiveError') && !hasFirstParty) return null;
      // Suppress ambiguous runtime errors ONLY when stack positively identifies third-party
      // origin. Empty stacks are NOT suppressed because we cannot confirm the error didn't
      // come from our own code (OOM, stack overflow, network failures all commonly arrive
      // without frames even when our code triggered them).
      // iOS Safari WKWebView throws `UnknownError: Cannot inject key into script value`
      // at the native bridge when a non-structurally-cloneable value is passed to a
      // bridge API (history.pushState, IndexedDB, etc.). The throw is native; a first-
      // party caller is always on the stack, so the generic `!hasFirstParty` gate below
      // misses it. Scope to excType==='UnknownError' β€” that type name is WebKit-only and
      // cannot originate from our TypeScript (WORLDMONITOR-NM).
      if (excType === 'UnknownError' && /Cannot inject key into script value/.test(msg)) return null;
      // Convex SDK re-auth race: during a WebSocket reconnect, `BaseConvexClient.
      // tryToReauthenticate` can read `this.authState.config.fetchToken` while
      // authState is transitioning out of `authenticated` state. Known Convex
      // internal; we use the SDK as-is. Gate by the exact function name so we
      // don't mask a genuine first-party `fetchToken` regression
      // (WORLDMONITOR-NJ).
      if (/Cannot read properties of undefined \(reading 'fetchToken'\)/.test(msg)
          && frames.some(f => /tryToReauthenticate/.test(f.function ?? ''))) return null;
      // Dynamic-import chunk-load failures whose browser-emitted message names one of
      // our own hashed `/assets/*.js` chunks. These FETCH-failure phrasings (Chrome
      // `Failed to fetch dynamically imported module: <url>`, Firefox `error loading
      // dynamically imported module: <url>`) are deploy-skew (a stale hashed filename
      // 404s after a deploy) or a transient network blip β€” never a first-party logic
      // bug: our compiled code can't synthesize the string, the URL is one of our
      // owned hashed chunks, and the load itself failed (a chunk that fetches
      // then throws during evaluation rejects with the underlying error, not
      // this wrapper). Unlike the
      // zero-frame variant below, the `import()` call site here is first-party
      // (MapContainer.initDeck, lazy panel/video loaders), so the rejection rides a
      // first-party frame and the `!hasFirstParty` gate misses it (WORLDMONITOR-TN: Map
      // chunk, WORLDMONITOR-S1: hls chunk). Match the owned, hashed asset URL in
      // the message instead of the stack.
      const dynamicImportAssetUrlMatch = msg.match(
        /(?:https?:\/\/[^\s'")]+)?\/assets\/[A-Za-z0-9_-]+-[A-Za-z0-9_-]+\.js/i,
      );
      let isOwnedDynamicImportAssetUrl = false;
      if (dynamicImportAssetUrlMatch) {
        const assetUrl = dynamicImportAssetUrlMatch[0];
        if (assetUrl.startsWith('/')) {
          isOwnedDynamicImportAssetUrl = true;
        } else {
          try {
            const host = new URL(assetUrl).hostname;
            const currentHost = typeof location !== 'undefined' ? location.hostname : '';
            isOwnedDynamicImportAssetUrl = host === 'worldmonitor.app'
              || host.endsWith('.worldmonitor.app')
              || (currentHost.endsWith('.vercel.app') && host === currentHost);
          } catch {
            isOwnedDynamicImportAssetUrl = false;
          }
        }
      }
      if (/(?:Failed to fetch|error loading) dynamically imported module/i.test(msg)
          && isOwnedDynamicImportAssetUrl) return null;
      // Stale-chunk-after-deploy: modulepreload / dynamic import failures arrive with no
      // stack trace because the browser fires them as synthetic TypeErrors at fetch time,
      // not at any first-party call site. The chunk-reload guard auto-reloads the page,
      // so the user is unaffected β€” but the Sentry event is still captured. Drop these
      // even when frames.length === 0 (WORLDMONITOR-Q / WORLDMONITOR-15). The phrases
      // are runtime-emitted only β€” our shipped code cannot synthesize them. Browser
      // variants: Chrome/Edge `Failed to fetch dynamically imported module` (no URL /
      // modulepreload), Safari `Importing a module script failed.`, Firefox `error
      // loading dynamically imported module`. `Importing binding name '<x>' is not
      // found.` (Safari) is the module-LINK counterpart: a chunk imports a named export
      // a sibling chunk no longer provides after a deploy β€” a built bundle always links
      // consistently, so at runtime this is version skew, never a code defect, and it
      // throws at link time with zero first-party frames (WORLDMONITOR-TM).
      if (
        !hasFirstParty
        && /(?:Failed to fetch|error loading) dynamically imported module|Importing a module script failed|Importing binding name '[^']*' is not found/i.test(msg)
      ) return null;
      // Zero-frame async-rejection patterns: AbortSignal.timeout() rejections
      // and DOMException(NotSupportedError) bubble up via
      // onunhandledrejection without any first-party frames captured (the
      // browser fires them from internal infra at the timer boundary). Both
      // phrases are runtime-emitted only β€” our shipped code cannot synthesize
      // the literal "signal timed out" or DOMException name. Same `!hasFirstParty`
      // safety as the dynamic-import block (WORLDMONITOR-66 / WORLDMONITOR-62).
      //
      // Extensions to the same gate:
      //   β€’ `out of memory` β€” Firefox via setInterval mechanism, zero frames
      //     (WORLDMONITOR-KE). Browser-engine signal, not synthesizable by
      //     our code.
      //   β€’ `\.(toLowerCase|trim|indexOf|findIndex) is not a function` β€”
      //     Apple Mail privacy proxy walks DOM with forEach and assumes
      //     `el.className` is a string, but on SVG elements it's a
      //     `SVGAnimatedString` (WORLDMONITOR-P2). Frame stack is
      //     [sentry-chunk, [native code]] which gets fully filtered out of
      //     `nonInfraFrames` β†’ hasAnyStack=false. The literal " is not a
      //     function" suffix anchored to those four mutator names is
      //     unambiguously a third-party prototype-mismatch (our code never
      //     calls those methods on objects of unknown shape).
      //   β€’ `Request timeout: /...` β€” third-party Electron wrappers
      //     (WORLDMONITOR-PW: Electron 39.2.7 polling /api/setIsSelect, an
      //     endpoint we don't serve). Our own `Request timeout` strings
      //     don't include a colon-and-path suffix; the format is unique to
      //     wrapper-injected code.
      if (
        !hasFirstParty
        && (
          /signal timed out/.test(msg)
          || /NotSupportedError/.test(msg)
          || /out of memory/i.test(msg)
          || /\.(?:toLowerCase|trim|indexOf|findIndex) is not a function/.test(msg)
          || /^(?:Error: )?Request timeout: \//.test(msg)
          // `^Failed to fetch$` (no host suffix) with zero captured frames =
          // background fetch from a service worker / browser extension /
          // in-app webview / stale pre-deploy bundle. A first-party fetch
          // failing in our shipped code surfaces with at least one
          // source-mapped .ts frame on the rejection (the awaiting site).
          // The hostname-suffixed variant `Failed to fetch (<host>)` is
          // handled above by `isHostScopedFetchFailure` which does its own
          // first-party-host allowlist (WORLDMONITOR-KM).
          || /^(?:TypeError: )?Failed to fetch$/.test(msg)
          // Safari module-loader abort / streaming-fetch interruption: iOS
          // Safari emits `SyntaxError: Unexpected EOF` with zero captured
          // frames via `onunhandledrejection` when a dynamic `import()` or
          // service-worker-mediated fetch is truncated mid-stream (PWA
          // lifecycle transitions, background-tab termination, network blip
          // during app boot). Our own `JSON.parse` calls produce
          // engine-specific phrasings β€” V8: `Unexpected end of JSON input`;
          // Safari: `JSON Parse error: Unexpected EOF` (with prefix) β€” so
          // bare `Unexpected EOF` is engine-emitted only. Same `!hasFirstParty`
          // safety as the `Failed to fetch` / `signal timed out` blocks above
          // (WORLDMONITOR-RF).
          || /^(?:SyntaxError: )?Unexpected EOF$/.test(msg)
          // `Unexpected token '<'` with zero captured frames = HTML served
          // where JS was expected: a stale hashed chunk after a deploy (the
          // SPA index.html fallback starts with `<!DOCTYPE html>`), or a
          // captive-portal / proxy / ISP HTML interstitial intercepting a
          // `<script>` / dynamic-import fetch. The `<` is dispositive β€” our
          // already-parsed, build-time-validated first-party bundle cannot
          // emit a parse error on its own source, and a genuine first-party
          // SyntaxError carries a source-mapped .ts frame (hasFirstParty β†’
          // preserved). The `hasAnyStack`-gated `Unexpected token/keyword`
          // gate below misses this zero-frame variant. `(?:SyntaxError: )?`
          // mirrors the EOF gate above: some engines embed the type in the
          // `value` field (WORLDMONITOR-TY).
          || /^(?:SyntaxError: )?Unexpected token '<'/.test(msg)
          // Bare `Unexpected token '<keyword>'` with zero captured frames on ancient
          // Android WebView (Chrome 98) β€” injected bridge/extension script or a
          // browser-internal parse failure, not our already-parsed bundle. A genuine
          // first-party SyntaxError carries a source-mapped .ts frame or an owned
          // hashed-chunk URL in the message (handled above). The `hasAnyStack`-gated
          // token gate below misses this zero-frame variant (WORLDMONITOR-??:
          // Unexpected token 'else' / 'for', 2026-07-18).
          || /^(?:SyntaxError: )?Unexpected token '(?:else|for)'$/.test(msg)
          // Firefox's wording for a failed `fetch()` β€” the engine-emitted
          // equivalent of Chrome's bare `Failed to fetch` (above) and Safari's
          // `Load failed`. Surfaces via `onunhandledrejection` with zero captured
          // frames. Same provenance reasoning as the `Failed to fetch` gate
          // (WORLDMONITOR-KM): a genuine first-party fetch failure keeps a
          // source-mapped .ts frame on the awaiting site (hasFirstParty β†’ NOT
          // suppressed, preserved by the first-party-stack test), so a zero-frame
          // rejection is a background / service-worker / extension / stale-pre-
          // deploy-bundle fetch. The literal phrase is engine-emitted only β€” our
          // shipped code never synthesizes it. This aligns the Firefox phrasing
          // with the bare `Failed to fetch` handling; the earlier blanket
          // "let NetworkError through" caution predated the KM provenance
          // refinement (WORLDMONITOR-RK).
          || /^(?:TypeError: )?NetworkError when attempting to fetch resource\.?$/.test(msg)
          // `.postMessage` on null with no first-party frame = an in-app webview
          // JS bridge / injected extension script posting to a null message
          // target (observed on ancient Mobile Safari 13 in-app browsers β€”
          // WORLDMONITOR-TE/TF). A genuine first-party `worker.postMessage` /
          // iframe-bridge bug keeps a source-mapped .ts frame (hasFirstParty β†’
          // preserved), so a no-first-party occurrence is bridge/extension noise.
          // This is the WebKit phrasing; the V8 `reading 'postMessage'` variant is
          // already suppressed via the ignoreErrors entry above.
          || /null is not an object \(evaluating '[^']*\.postMessage'\)/.test(msg)
        )
      ) return null;
      if (hasAnyStack && !hasFirstParty && (
        /Maximum call stack size exceeded/.test(msg)
        || /^\w{1,2} is not a (?:function|constructor)/.test(msg)
        || /Cannot add property \w+, object is not extensible/.test(msg)
        || /^TypeError: Internal error$/.test(msg)
        || /^Key not found$/.test(msg)
        || /^Element not found$/.test(msg)
        || /^TypeError: NetworkError/.test(msg)
        || /Could not connect to the server/.test(msg)
        || (excType === 'SyntaxError' && /^Unexpected (?:token|keyword)/.test(msg))
        || /^SyntaxError: Unexpected (?:token|keyword)/.test(msg)
        || /Invalid or unexpected token/.test(msg)
        || /^Operation timed out/.test(msg)
        || /Cannot inject key into script value/.test(msg)
        || /Connection lost while action was in flight/.test(msg)
        || /WEBGLRenderPipeline.*Link error/.test(msg)
      )) return null;
      // `SyntaxError: Invalid or unexpected token` (and the Unexpected token/keyword/EOF
      // family) surfacing THROUGH the deck.gl/maplibre WebGL init path. Our compiled,
      // already-parsed bundle cannot emit a JS parse error at the first-party
      // `MapContainer.initDeck` call site β€” a runtime SyntaxError here means deck.gl /
      // maplibre parsed external content (a Worker script, a `new Function` shader
      // builder, or a stale/corrupt lazily-loaded chunk after a deploy). The
      // `!hasFirstParty` token-parse gate above misses this because `initDeck` rides the
      // stack as the CALLER, not the source. Gate on the presence of a deck-stack /
      // maplibre vendor frame so a genuine first-party SyntaxError elsewhere still
      // surfaces (WORLDMONITOR-SP).
      // `(?:SyntaxError: )?` mirrors the EOF/token gates above (lines 588, 601):
      // some engines embed the exception type in the `value` field, so `msg` can be
      // either `Invalid or unexpected token` or `SyntaxError: Invalid or unexpected
      // token`. Anchoring without the optional prefix would let the prefixed variant
      // slip through here despite the first-party `MapContainer` frame (Greptile P2).
      if (excType === 'SyntaxError'
          && /^(?:SyntaxError: )?(?:Invalid or unexpected token|Unexpected (?:token|keyword|identifier|EOF|end of script))/.test(msg)
          && frames.some(f => /\/(?:maplibre|deck-stack)-[A-Za-z0-9_-]+\.js/.test(f.filename ?? ''))) return null;
      return event;
    },
  };
}

export async function loadAndInitSentry(): Promise<SentryNs> {
  const ns = await import('@sentry/browser');
  ns.init(buildSentryInitOptions());
  return ns;
}