1(function () { 2 var DEFAULT_ENDPOINT = '/monitoring/early-error'; 3 var READY_EVENT = 'clubic:sentry-ready'; 4 var DISABLED_FLAG = '__earlySentryDisabled'; 5 var MAX_EVENTS = 10; 6 var MAX_FORCED_EVENTS = 5; 7 var MAX_DOM_MUTATION_RECORDS = 5; 8 var MAX_STRING_LENGTH = 2000; 9 var MAX_STACK_LENGTH = 8000; 10 var HYDRATION_REPORT_DELAY_MS = 250; 11 var DOM_MUTATION_OBSERVER_TIMEOUT_MS = 8000; 12 var DOM_MUTATION_OBSERVER_VERSION = 'parent-v1'; 13 var REACT_HYDRATION_ERROR_CODE = '418'; 14 var _DOMAIN = 'clubic.com'; 15 var EXTENSION_SOURCE_PATTERN = 16 /^(chrome-extension|moz-extension|safari-web-extension|safari-extension|ms-browser-extension|edge-extension|extension):\/\//i; 17 var EXTENSION_MARKER_PATTERN = 18 /grammarly|lastpass|1password|bitwarden|dashlane|google.translate|google-translate|translated-ltr|translated-rtl|skiptranslate|goog-te/i; 19 var sentryReady = false; 20 var domMutationObserver = null; 21 var domMutationObserverTimeout = null; 22 var domMutationStats = { 23 extension: 0, 24 firstParty: 0, 25 records: [], 26 thirdParty: 0, 27 total: 0, 28 unknown: 0, 29 }; 30 var hydrationReportSent = false; 31 var hydrationReportTimer = null; 32 var pendingHydrationDuplicateCount = 0; 33 var pendingHydrationPayload = null; 34 var hydrationErrorCallbacksExecuted = false; 35 36 if (window[DISABLED_FLAG]) { 37 return; 38 } 39 40 if (window.__earlySentrySetup) { 41 return; 42 } 43 44 window.__earlySentrySetup = true; 45 window.__earlySentrySentCount = 0; 46 window.__earlySentryForcedSentCount = 0; 47 48 var originalConsoleError = 49 window.console && typeof window.console.error === 'function' ? window.console.error.bind(window.console) : null; 50 var env = window.nextEnv || {}; 51 var rate = Number(env.NEXT_PUBLIC_SENTRY_EARLY_CLIENT_SAMPLE_RATE || 0); 52 var endpoint = env.NEXT_PUBLIC_SENTRY_EARLY_CLIENT_ENDPOINT || DEFAULT_ENDPOINT; 53 var isSampled = rate > 0 && Math.random() < rate; 54 55 function readReactMinifiedErrorCode(value) { 56 if (typeof value !== 'string') { 57 return null; 58 } 59 60 var match = value.match(/\bMinified React error #(\d+)\b/); 61 62 return match ? match[1] : null; 63 } 64 65 function truncateString(value, maxLength) { 66 if (typeof value !== 'string' || !value) { 67 return null; 68 } 69 70 if (value.length <= maxLength) { 71 return value; 72 } 73 74 return value.slice(0, maxLength - 3) + '...'; 75 } 76 77 function readDocumentState() { 78 return typeof document !== 'undefined' && typeof document.readyState === 'string' ? document.readyState : null; 79 } 80 81 function readPagePath() { 82 return window.location && typeof window.location.pathname === 'string' ? window.location.pathname : null; 83 } 84 85 function getForcedReport(p) { 86 var reactErrorCode = 87 (p && readReactMinifiedErrorCode(p.message)) || 88 (p && readReactMinifiedErrorCode(p.name)) || 89 (p && readReactMinifiedErrorCode(p.stack)) || 90 null; 91 92 if (reactErrorCode === REACT_HYDRATION_ERROR_CODE) { 93 return { 94 errorCategory: 'react-hydration', 95 forceSend: true, 96 reactErrorCode: reactErrorCode, 97 }; 98 } 99 100 return { 101 errorCategory: null, 102 forceSend: false, 103 reactErrorCode: reactErrorCode, 104 }; 105 } 106 107 function shouldSendPayload(p) { 108 var val = p.source || p.filename || null; 109 110 if (typeof val !== 'string' || !val) { 111 return true; 112 } 113 114 if (val.indexOf('//') === 0) { 115 val = window.location.protocol + val; 116 } else if (val.indexOf('/') === 0) { 117 val = window.location.origin + val; 118 } else if (!/^[a-z][a-z\d+.-]*:\/\//i.test(val)) { 119 return true; 120 } 121 122 try { 123 var srcHost = new URL(val).hostname.toLowerCase(); 124 var currentHost = window.location.hostname.toLowerCase(); 125 126 if (srcHost === currentHost || srcHost === 'localhost' || srcHost === '127.0.0.1') { 127 return true; 128 } 129 130 return srcHost === _DOMAIN || srcHost.slice(-(_DOMAIN.length + 1)) === '.' + _DOMAIN; 131 } catch (error) { 132 return true; 133 } 134 } 135 136 function getHost(value) { 137 if (typeof value !== 'string' || !value || EXTENSION_SOURCE_PATTERN.test(value)) { 138 return null; 139 } 140 141 try { 142 return new URL(value, window.location.href).hostname.toLowerCase(); 143 } catch (error) { 144 return null; 145 } 146 } 147 148 function isClubicHost(host) { 149 return ( 150 host === window.location.hostname.toLowerCase() || 151 host === 'localhost' || 152 host === '127.0.0.1' || 153 host === _DOMAIN || 154 host.slice(-(_DOMAIN.length + 1)) === '.' + _DOMAIN 155 ); 156 } 157 158 function readNodeMarker(node) { 159 if (!node || node.nodeType !== 1) { 160 return ''; 161 } 162 163 return [ 164 typeof node.id === 'string' ? node.id : '', 165 typeof node.className === 'string' ? node.className : '', 166 typeof node.getAttribute === 'function' ? node.getAttribute('data-testid') || '' : '', 167 ].join(' '); 168 } 169 170 function classifyDomMutationNode(node) { 171 if (!node || node.nodeType !== 1) { 172 return 'unknown'; 173 } 174 175 var source = readResourceSource(node); 176 177 if (source && EXTENSION_SOURCE_PATTERN.test(source)) { 178 return 'extension'; 179 } 180 181 if (EXTENSION_MARKER_PATTERN.test(readNodeMarker(node))) { 182 return 'extension'; 183 } 184 185 if (source) { 186 var host = getHost(source); 187 188 if (!host) { 189 return 'unknown'; 190 } 191 192 return isClubicHost(host) ? 'firstParty' : 'thirdParty'; 193 } 194 195 return 'unknown'; 196 } 197 198 function describeDomMutationNode(node) { 199 if (!node || node.nodeType !== 1) { 200 return null; 201 } 202 203 return [ 204 typeof node.tagName === 'string' ? node.tagName.toLowerCase() : 'node', 205 typeof node.id === 'string' && node.id ? '#' + node.id.slice(0, 80) : null, 206 typeof node.className === 'string' && node.className 207 ? '.' + node.className.trim().split(/\s+/).slice(0, 3).join('.') 208 : null, 209 readResourceSource(node), 210 ] 211 .filter(Boolean) 212 .join(' '); 213 } 214 215 function describeDomMutationParent(node) { 216 if (!node) { 217 return null; 218 } 219 220 if (node.nodeType === 9) { 221 return 'document'; 222 } 223 224 if (node.nodeType === 11) { 225 return 'fragment'; 226 } 227 228 return describeDomMutationNode(node); 229 } 230 231 function recordDomMutation(node, action, parentNode) { 232 var kind = classifyDomMutationNode(node); 233 var description = describeDomMutationNode(node); 234 var parentDescription = describeDomMutationParent(parentNode || (node && node.parentNode)); 235 236 domMutationStats.total += 1; 237 238 if (kind === 'extension') { 239 domMutationStats.extension += 1; 240 } else if (kind === 'thirdParty') { 241 domMutationStats.thirdParty += 1; 242 } else if (kind === 'firstParty') { 243 domMutationStats.firstParty += 1; 244 } else { 245 domMutationStats.unknown += 1; 246 } 247 248 if (description && domMutationStats.records.length < MAX_DOM_MUTATION_RECORDS) { 249 domMutationStats.records.push( 250 [ 251 action, 252 kind, 253 truncateString( 254 [parentDescription ? 'parent=' + parentDescription : null, description].filter(
254Boolean).join(' > '), 255 300, 256 ), 257 ].join(':'), 258 ); 259 } 260 } 261 262 function stopDomMutationObserver() { 263 if (domMutationObserver) { 264 domMutationObserver.disconnect(); 265 domMutationObserver = null; 266 } 267 268 if (domMutationObserverTimeout) { 269 clearTimeout(domMutationObserverTimeout); 270 domMutationObserverTimeout = null; 271 } 272 } 273 274 window.__stopEarlyDomMutationObserver = stopDomMutationObserver; 275 276 function startDomMutationObserver() { 277 if (typeof MutationObserver !== 'function' || !document || !document.documentElement) { 278 return; 279 } 280 281 try { 282 domMutationObserver = new MutationObserver(function (mutations) { 283 for (var i = 0; i < mutations.length; i += 1) { 284 var mutation = mutations[i]; 285 286 if (mutation.type === 'attributes') { 287 recordDomMutation(mutation.target, 'attr', mutation.target && mutation.target.parentNode); 288 continue; 289 } 290 291 for (var j = 0; j < mutation.addedNodes.length; j += 1) { 292 recordDomMutation(mutation.addedNodes[j], 'add', mutation.target); 293 } 294 295 for (var k = 0; k < mutation.removedNodes.length; k += 1) { 296 recordDomMutation(mutation.removedNodes[k], 'remove', mutation.target); 297 } 298 } 299 }); 300 domMutationObserver.observe(document.documentElement, { 301 attributeFilter: ['class', 'id', 'style', 'translate'], 302 attributes: true, 303 childList: true, 304 subtree: true, 305 }); 306 domMutationObserverTimeout = setTimeout(stopDomMutationObserver, DOM_MUTATION_OBSERVER_TIMEOUT_MS); 307 } catch (error) {} 308 } 309 310 function readDomMutationSourceKind() { 311 if (domMutationStats.extension > 0) { 312 return 'extension'; 313 } 314 315 if (domMutationStats.thirdParty > 0) { 316 return 'third-party'; 317 } 318 319 if (domMutationStats.firstParty > 0) { 320 return 'first-party'; 321 } 322 323 if (domMutationStats.unknown > 0) { 324 return 'unknown'; 325 } 326 327 return 'none'; 328 } 329 330 function hydratePayloadDiagnostics(p) { 331 var sourceKind = readDomMutationSourceKind(); 332 333 p.domMutationCount = domMutationStats.total; 334 p.domMutationExtensionCount = domMutationStats.extension; 335 p.domMutationFirstPartyCount = domMutationStats.firstParty; 336 p.domMutationSourceKind = sourceKind; 337 p.domMutationSummary = domMutationStats.records.join(' | '); 338 p.domMutationSuspected = sourceKind === 'extension' || sourceKind === 'third-party'; 339 p.domMutationThirdPartyCount = domMutationStats.thirdParty; 340 p.domMutationUnknownCount = domMutationStats.unknown; 341 342 return p; 343 } 344 345 function sendNow(p, forcedReport) { 346 if (!p) { 347 return; 348 } 349 350 if ((sentryReady && !forcedReport.forceSend) || (!isSampled && !forcedReport.forceSend)) { 351 return; 352 } 353 354 if (!forcedReport.forceSend && !shouldSendPayload(p)) { 355 return; 356 } 357 358 if (forcedReport.forceSend) { 359 if (window.__earlySentryForcedSentCount >= MAX_FORCED_EVENTS) { 360 return; 361 } 362 363 window.__earlySentryForcedSentCount += 1; 364 } else { 365 if (window.__earlySentrySentCount >= MAX_EVENTS) { 366 return; 367 } 368 369 window.__earlySentrySentCount += 1; 370 } 371 372 hydratePayloadDiagnostics(p); 373 374 var body = JSON.stringify({ 375 colno: p.colno || null, 376 documentReadyState: truncateString(p.documentReadyState || readDocumentState(), MAX_STRING_LENGTH), 377 domMutationCount: p.domMutationCount || 0, 378 domMutationExtensionCount: p.domMutationExtensionCount || 0, 379 domMutationFirstPartyCount: p.domMutationFirstPartyCount || 0, 380 domMutationObserverVersion: DOM_MUTATION_OBSERVER_VERSION, 381 domMutationSourceKind: p.domMutationSourceKind || 'none', 382 domMutationSummary: truncateString(p.domMutationSummary, MAX_STRING_LENGTH), 383 domMutationSuspected: p.domMutationSuspected === true, 384 domMutationThirdPartyCount: p.domMutationThirdPartyCount || 0, 385 domMutationUnknownCount: p.domMutationUnknownCount || 0, 386 errorCategory: forcedReport.errorCategory, 387 forced: forcedReport.forceSend,
388 hydrationDuplicateCount: p.hydrationDuplicateCount || null, 389 hydrationReportDelayMs: p.hydrationReportDelayMs || null, 390 lineno: p.lineno || null, 391 message: truncateString(p.message, MAX_STRING_LENGTH), 392 name: truncateString(p.name, MAX_STRING_LENGTH), 393 pagePath: truncateString(p.pagePath || readPagePath(), MAX_STRING_LENGTH), 394 reactErrorCode: forcedReport.reactErrorCode, 395 release: env.NEXT_PUBLIC_VERSION, 396 resourceAs: truncateString(p.resourceAs, MAX_STRING_LENGTH), 397 resourceHref: truncateString(p.resourceHref, MAX_STRING_LENGTH), 398 resourceId: truncateString(p.resourceId, MAX_STRING_LENGTH), 399 resourceRel: truncateString(p.resourceRel, MAX_STRING_LENGTH), 400 sentryReady: sentryReady, 401 source: truncateString(p.source || p.filename, MAX_STRING_LENGTH), 402 stack: truncateString(p.stack, MAX_STACK_LENGTH), 403 tagName: truncateString(p.tagName, MAX_STRING_LENGTH), 404 timestamp: p.timestamp || Date.now(), 405 type: p.type, 406 }); 407 408 if (navigator.sendBeacon) { 409 try { 410 if (navigator.sendBeacon(endpoint, body)) { 411 return; 412 } 413 } catch (error) {} 414 } 415 416 fetch(endpoint, { 417 method: 'POST', 418 headers: { 419 'Content-Type': 'application/json', 420 }, 421 body: body, 422 keepalive: true, 423 credentials: 'same-origin', 424 }).catch(function () {}); 425 } 426 427 function mergeHydrationPayload(p) { 428 if (!pendingHydrationPayload) { 429 pendingHydrationPayload = p; 430 return; 431 } 432 433 if (!pendingHydrationPayload.stack && p.stack) { 434 pendingHydrationPayload.stack = p.stack; 435 } 436 437 if (!pendingHydrationPayload.source && (p.source || p.filename)) { 438 pendingHydrationPayload.source = p.source || p.filename; 439 } 440 441 if (!pendingHydrationPayload.lineno && p.lineno) { 442 pendingHydrationPayload.lineno = p.lineno; 443 } 444 445 if (!pendingHydrationPayload.colno && p.colno) { 446 pendingHydrationPayload.colno = p.colno; 447 } 448 } 449 450 function flushHydrationPayload() { 451 if (!pendingHydrationPayload || hydrationReportSent) { 452 return; 453 } 454 455 var payload = pendingHydrationPayload; 456 457 if (hydrationReportTimer) { 458 clearTimeout(hydrationReportTimer); 459 hydrationReportTimer = null; 460 } 461 462 pendingHydrationPayload = null; 463 payload.hydrationDuplicateCount = pendingHydrationDuplicateCount; 464 payload.hydrationReportDelayMs = HYDRATION_REPORT_DELAY_MS; 465 hydrationReportSent = true; 466 sendNow(payload, getForcedReport(payload)); 467 } 468 469 function queueHydrationPayload(p) { 470 if (hydrationReportSent) { 471 return; 472 } 473 474 pendingHydrationDuplicateCount += 1; 475 mergeHydrationPayload(p); 476 477 if (!hydrationReportTimer) { 478 hydrationReportTimer = setTimeout(flushHydrationPayload, HYDRATION_REPORT_DELAY_MS); 479 } 480 } 481 482 function runHydrationErrorCallbacks(p) { 483 if (hydrationErrorCallbacksExecuted) { 484 return; 485 } 486 487 hydrationErrorCallbacksExecuted = true; 488 489 var callbacks = window.__earlyHydrationErrorCallbacks; 490 491 if (!Array.isArray(callbacks)) { 492 return; 493 } 494 495 for (var i = 0; i < callbacks.length; i += 1) { 496 if (typeof callbacks[i] !== 'function') { 497 continue; 498 } 499 500 try { 501 callbacks[i](p); 502 } catch (error) {} 503 } 504 } 505 506 function send(p) { 507 if (!p) { 508 return; 509 } 510 511 var forcedReport = getForcedReport(p); 512 513 if (forcedReport.reactErrorCode === REACT_HYDRATION_ERROR_CODE) { 514 runHydrationErrorCallbacks(p); 515 queueHydrationPayload(p); 516 return; 517 } 518 519 sendNow(p, forcedReport); 520 } 521 522 function getBasePayload() { 523 return { timestamp: Date.now() }; 524 } 525 526 function normalizeSourceUrl(value) { 527 if (typeof value !== 'string' || !value) { 528 return null; 529 } 530 531 if (value.indexOf('//') === 0) { 532 return window.location.protocol + value; 533 } 534 535 if (value.indexOf('/') === 0) { 536 return window.location.origin + value; 537 } 538 539 return value; 540 } 541 542 function readResourceSource(target) { 543 if (!target) { 544 return null; 545 } 546 547 return normalizeSourceUrl( 548 target.src || 549 target.href || 550 (typeof target.getAttribute === 'function' && (target.getAttribute('src') || target.getAttribute('href'))) || 551 null, 552 ); 553 } 554 555 function toErrorPayload(error) { 556 if (!error) return { name: null, message: null, stack: null }; 557 return {
558 name: typeof error.name === 'string' ? error.name : null, 559 message: typeof error.message === 'string' ? error.message : String(error), 560 stack: typeof error.stack === 'string' ? error.stack : null, 561 }; 562 } 563 564 function toConsolePayload(args) { 565 var firstError = null; 566 var messageParts = []; 567 568 for (var i = 0; i < args.length; i += 1) { 569 var arg = args[i]; 570 var errorPayload = toErrorPayload(arg); 571 572 if (!firstError && (errorPayload.message || errorPayload.stack || errorPayload.name)) { 573 firstError = errorPayload; 574 } 575 576 if (errorPayload.message) { 577 messageParts.push(errorPayload.message); 578 } 579 } 580 581 return { 582 name: firstError ? firstError.name : null, 583 message: messageParts.join(' '), 584 stack: firstError ? firstError.stack : null, 585 }; 586 } 587 588 function onConsoleError() { 589 var base = getBasePayload(); 590 var consolePayload = toConsolePayload(arguments); 591 var forcedReport = getForcedReport(consolePayload); 592 593 if (!forcedReport.forceSend) { 594 return; 595 } 596 597 send({ 598 type: 'console-error', 599 message: consolePayload.message, 600 name: consolePayload.name, 601 stack: consolePayload.stack, 602 timestamp: base.timestamp, 603 }); 604 } 605 606 if (originalConsoleError) { 607 window.console.error = function () { 608 onConsoleError.apply(null, arguments); 609 originalConsoleError.apply(null, arguments); 610 }; 611 } 612 613 function onError(event) { 614 var target = event.target; 615 var base = getBasePayload(); 616 617 if (target && (target.tagName === 'SCRIPT' || target.tagName === 'LINK')) { 618 var resourceSource = readResourceSource(target); 619 620 send({ 621 type: 'resource', 622 message: 'Early resource load failure', 623 tagName: typeof target.tagName === 'string' ? target.tagName : null, 624 source: resourceSource, 625 resourceAs: typeof target.as === 'string' ? target.as : null, 626 resourceHref: 627 (typeof target.getAttribute === 'function' && target.getAttribute('href')) || 628 (typeof target.href === 'string' ? target.href : null), 629 resourceId: typeof target.id === 'string' ? target.id : null, 630 resourceRel: 631 (typeof target.rel === 'string' && target.rel) || 632 (typeof target.getAttribute === 'function' && target.getAttribute('rel')) || 633 null, 634 timestamp: base.timestamp, 635 }); 636 return; 637 } 638 639 var errorPayload = toErrorPayload(event.error); 640 send({ 641 type: 'error', 642 message: typeof event.message === 'string' ? event.message : errorPayload.message, 643 filename: typeof event.filename === 'string' ? event.filename : null, 644 lineno: typeof event.lineno === 'number' ? event.lineno : null, 645 colno: typeof event.colno === 'number' ? event.colno : null, 646 name: errorPayload.name, 647 source: normalizeSourceUrl(event.filename), 648 stack: errorPayload.stack, 649 timestamp: base.timestamp, 650 }); 651 } 652 653 function onUnhandledRejection(event) { 654 var errorPayload = toErrorPayload(event.reason); 655 var base = getBasePayload(); 656 657 send({ 658 type: 'unhandledrejection', 659 message: errorPayload.message, 660 name: errorPayload.name, 661 source: normalizeSourceUrl( 662 event.reason && typeof event.reason === 'object' && typeof event.reason.filename === 'string' 663 ? event.reason.filename 664 : null, 665 ), 666 stack: errorPayload.stack, 667 timestamp: base.timestamp, 668 }); 669 } 670 671 function stopEarlySentry() { 672 sentryReady = true; 673 window[DISABLED_FLAG] = true; 674 stopDomMutationObserver(); 675 window.removeEventListener(READY_EVENT, stopEarlySentry); 676 } 677 678 startDomMutationObserver(); 679 window.addEventListener('error', onError, true); 680 window.addEventListener('unhandledrejection', onUnhandledRejection); 681 window.addEventListener('pagehide', flushHydrationPayload); 682 window.addEventListener(READY_EVENT, stopEarlySentry); 683})();
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.