PageSourceSearch

https://thebalkantrail.com/wp-content/plugins/tbx-plugin/inc/sentry/sentry-hooks.js?ver=1791298948

js thebalkantrail.com collected 2026-10-06 17:53:16 UTC 7,688 bytes, 162 lines download raw bytes

1(function () {
2    // Limits retry attempts in case Sentry can't be found
3    let retryCount = 0;
4    const maxRetries = 20;
5
6    function scheduleRetry() {
7        retryCount++;
8        if (retryCount < maxRetries) {
9            setTimeout(setupSentryFilter, 500);
10        } else {
11            console.warn('Sentry not available after', maxRetries * 0.5, 'seconds, giving up');
12        }
13    }
14
15    function setupSentryFilter() {
16        if (!window.Sentry) {
17            scheduleRetry();
18            return;
19        }
20
21        const hub = window.Sentry && window.Sentry.getCurrentHub();
22        const client = hub && hub.getClient();
23        if (!client) {
24            scheduleRetry();
25            return;
26        }
27
28        client.getOptions().beforeSend = function (event, hint) {
29            // No optional chaining / object spread here: this file ships unbundled,
30            // and older browsers (Safari <13.1, Chrome <80, legacy Edge) must still
31            // parse it — a SyntaxError would disable the filter exactly where it's
32            // needed most and report itself to Sentry as extra noise.
33
34            const ua = navigator.userAgent || '';
35            const exception = hint && hint.originalException;
36            const exceptionValue = event.exception && event.exception.values && event.exception.values[0];
37            const message =
38                (exception && exception.message) ||
39                (exception && typeof exception.toString === 'function' && exception.toString()) ||
40                (exceptionValue && exceptionValue.value) ||
41                (event.logentry && event.logentry.message) ||
42                event.message ||
43                (event.extra && event.extra.__serialized__ && event.extra.__serialized__.message) ||
44                '';
45            const tags = event.tags || {};
46            const url = (event.request && event.request.url) || '';
47
48            // Relabel Network Error to info level
49            if (message === 'Network Error') {
50                event.level = 'info';
51                event.tags = Object.assign({}, tags, { ignored_error: 'Network Error' });
52            }
53
54            // Relabel iOS fetch Load failed errors to info level (https://travelbase.sentry.io/issues/6337043303/)
55            const isLoadFailed = /(?:^TypeError:\s*)?Load failed$/i.test(message);
56            if (isLoadFailed && /iP(hone|ad|od)/.test(ua)) {
57                event.level = 'info';
58                event.tags = Object.assign({}, tags, { ignored_error: 'iOS fetch Load failed' });
59            }
60
61            // Ignore Android WebView IAB bridge errors (Facebook/Instagram in-app browser):
62            //   "Error invoking postMessage" — https://travelbase.sentry.io/issues/6783868008/
63            //   "Error invoking ... Java object is gone" — Java bridge object destroyed mid-page
64            //   Both come from iabjs:// internal Facebook scripts, not our code
65            // (https://travelbase.sentry.io/issues/6810702496/)
66            if (message.includes('Error invoking') && (message.includes('postMessage') || message.includes('Java object is gone'))) {
67                return null;
68            }
69
70            // Ignore iOS in-app browser (WKWebView) bridge errors: apps like Instagram/
71            // Facebook/Google inject their own script (sendDataToNative, sendPageHideMessage)
72            // that calls window.webkit.messageHandlers after the bridge is torn down on
73            // pagehide — not our code
74            const iosBridgeFrames = (exceptionValue && exceptionValue.stacktrace && exceptionValue.stacktrace.frames) || [];
75            const hasWebkitBridgeError = /webkit\.messageHandlers/i.test(message) ||
76                iosBridgeFrames.some(f =>
77                    /webkit\.messageHandlers/i.test(
78                        [f.function, f.filename, f.module, f.context_line].filter(Boolean).join(' ')
79                    )
80            );
81            if (hasWebkitBridgeError) {
82                return null;
83            }
84            if (iosBridgeFrames.some(f => /sendDataToNative|sendPageHideMessage/.test(f.function || ''))) {
85                return null;
86            }
87
88            // Ignore benign ResizeObserver errors (browser quirk) (https://travelbase.sentry.io/issues/6260843811/)
89            if (message.includes('ResizeObserver loop limit exceeded')) {
90                return null;
91            }
92
93            // Ignore aborted analytics beacons (https://travelbase.sentry.io/issues/6260858508/)
94            const analyticsHosts = [
95                'google-analytics.com',
96                'googletagmanager.com',
97                'googlesyndication.com',
98            ];
99            const breadcrumbs = event.breadcrumbs || [];
100            const fromAnalytics = analyticsHosts.some(h => url.includes(h)) ||
101                breadcrumbs.some(b =>
102                    b.category === 'fetch' &&
103                    analyticsHosts.some(h => ((b.data && b.data.url) || '').includes(h))
104            );
105            if (((exception && exception.name === 'AbortError') || /AbortError/i.test(message)) && fromAnalytics) {
106                return null;
107            }
108
109            // Ignore third-party fetch failures (popupsmart, ads, tracking pixels, etc.) - not our code
110            const thirdPartyHosts = [
111                'popupsmart.com',
112                'googleadservices.com',
113                'doubleclick.net',
114                'pinterest.com',
115            ];
116            const fromThirdParty = breadcrumbs.some(b =>
117                b.category === 'fetch' &&
118                thirdPartyHosts.some(h => ((b.data && b.data.url) || '').includes(h))
119            );
120            if (message === 'Failed to fetch' && fromThirdParty) {
121                return null;
122            }
123
124            // Ignore Failed to fetch from gtag/js in in-app browsers:
125            //   wv    = Android Chrome WebView (https://developer.chrome.com/docs/multidevice/user-agent/)
126            //   IABMV = Meta in-app browser marker, present on both Android and iOS
127            //   iOS without Version/ = WKWebView (standalone Safari + all real iOS browsers always include Version/x.x)
128            // (https://travelbase.sentry.io/share/issue/b87ea9ae63604a81b5e5137cd9dd380d
128/)
129            if (message === 'Failed to fetch') {
130                const frames = (exceptionValue && exceptionValue.stacktrace && exceptionValue.stacktrace.frames) || [];
131                const fromGtag = frames.some(f => (f.filename || f.module || '').includes('gtag/js'));
132                const fromIab = /\bwv\b/.test(ua) ||
133                    /IABMV/.test(ua) ||
134                    (/iP(hone|ad|od)/.test(ua) && !/Version\/[\d.]/.test(ua));
135                if (fromGtag && fromIab) return null;
136            }
137
138            // Ignore headless browsers and known web crawlers/bots
139            // Headless: detected via browser name (e.g. HeadlessChrome)
140            // Bots: UA patterns for major crawlers that render JS (Googlebot, Baiduspider, etc.)
141            const browserName = (event.contexts && event.contexts.browser && event.contexts.browser.name) || '';
142            if (/headless/i.test(browserName)) {
143                return null;
144            }
145            if (/bot|crawler|spider|Baiduspider|Googlebot|bingbot|YandexBot|DuckDuckBot|Slurp/i.test(ua)) {
146                return null;
147            }
148
149            // sample only 5% of info level events to reduce Sentry quota usage
150            if (event.level === 'info') {
151                if (Math.random() > 0.05) {
152                    return null;
153                }
154            }
155
156            // Always return event!
157            return event;
158        };
159    }
160
161    setupSentryFilter();
162})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.