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.