PageSourceSearch

https://www.clubic.com/assets-react/early-client-errors.js?v7

js clubic.com collected 2026-10-01 08:40:31 UTC 19,489 bytes, 683 lines download raw bytes

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.