@myinterview/widget-react 1.1.23-binary-check-one → 1.1.23-binary-002

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -8,26 +8,51 @@ var reactDom = require('react-dom');
8
8
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
9
 
10
10
  function _interopNamespace(e) {
11
- if (e && e.__esModule) return e;
12
- var n = Object.create(null);
13
- if (e) {
14
- Object.keys(e).forEach(function (k) {
15
- if (k !== 'default') {
16
- var d = Object.getOwnPropertyDescriptor(e, k);
17
- Object.defineProperty(n, k, d.get ? d : {
18
- enumerable: true,
19
- get: function () { return e[k]; }
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
20
22
  });
21
- }
22
- });
23
- }
24
- n["default"] = e;
25
- return Object.freeze(n);
23
+ }
24
+ n["default"] = e;
25
+ return Object.freeze(n);
26
26
  }
27
27
 
28
28
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
29
29
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
30
30
 
31
+ /*! *****************************************************************************
32
+ Copyright (c) Microsoft Corporation.
33
+
34
+ Permission to use, copy, modify, and/or distribute this software for any
35
+ purpose with or without fee is hereby granted.
36
+
37
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
38
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
40
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
42
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
43
+ PERFORMANCE OF THIS SOFTWARE.
44
+ ***************************************************************************** */
45
+
46
+ function __awaiter(thisArg, _arguments, P, generator) {
47
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
48
+ return new (P || (P = Promise))(function (resolve, reject) {
49
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
50
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
51
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
52
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
53
+ });
54
+ }
55
+
31
56
  // eslint-disable-next-line @typescript-eslint/unbound-method
32
57
  const objectToString = Object.prototype.toString;
33
58
 
@@ -396,83 +421,19 @@ function getLocationHref() {
396
421
  }
397
422
  }
398
423
 
399
- /** Prefix for logging strings */
400
- const PREFIX = 'Sentry Logger ';
401
-
402
- const CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert', 'trace'] ;
403
-
404
- /**
405
- * Temporarily disable sentry console instrumentations.
406
- *
407
- * @param callback The function to run against the original `console` messages
408
- * @returns The results of the callback
409
- */
410
- function consoleSandbox(callback) {
411
- if (!('console' in GLOBAL_OBJ)) {
412
- return callback();
413
- }
414
-
415
- const originalConsole = GLOBAL_OBJ.console ;
416
- const wrappedLevels = {};
417
-
418
- // Restore all wrapped console methods
419
- CONSOLE_LEVELS.forEach(level => {
420
- // TODO(v7): Remove this check as it's only needed for Node 6
421
- const originalWrappedFunc =
422
- originalConsole[level] && (originalConsole[level] ).__sentry_original__;
423
- if (level in originalConsole && originalWrappedFunc) {
424
- wrappedLevels[level] = originalConsole[level] ;
425
- originalConsole[level] = originalWrappedFunc ;
426
- }
427
- });
428
-
429
- try {
430
- return callback();
431
- } finally {
432
- // Revert restoration to wrapped state
433
- Object.keys(wrappedLevels).forEach(level => {
434
- originalConsole[level] = wrappedLevels[level ];
435
- });
436
- }
437
- }
438
-
439
- function makeLogger() {
440
- let enabled = false;
441
- const logger = {
442
- enable: () => {
443
- enabled = true;
444
- },
445
- disable: () => {
446
- enabled = false;
447
- },
448
- };
424
+ /** An error emitted by Sentry SDKs and related utilities. */
425
+ class SentryError extends Error {
426
+ /** Display name of this error instance. */
449
427
 
450
- if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
451
- CONSOLE_LEVELS.forEach(name => {
452
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
453
- logger[name] = (...args) => {
454
- if (enabled) {
455
- consoleSandbox(() => {
456
- GLOBAL_OBJ.console[name](`${PREFIX}[${name}]:`, ...args);
457
- });
458
- }
459
- };
460
- });
461
- } else {
462
- CONSOLE_LEVELS.forEach(name => {
463
- logger[name] = () => undefined;
464
- });
428
+ constructor( message, logLevel = 'warn') {
429
+ super(message);this.message = message;
430
+ this.name = new.target.prototype.constructor.name;
431
+ // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line
432
+ // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes
433
+ // instances of `SentryError` fail `obj instanceof SentryError` checks.
434
+ Object.setPrototypeOf(this, new.target.prototype);
435
+ this.logLevel = logLevel;
465
436
  }
466
-
467
- return logger ;
468
- }
469
-
470
- // Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
471
- let logger;
472
- if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
473
- logger = getGlobalSingleton('logger', makeLogger);
474
- } else {
475
- logger = makeLogger();
476
437
  }
477
438
 
478
439
  /** Regular expression used to parse a Dsn. */
@@ -503,16 +464,13 @@ function dsnToString(dsn, withPassword = false) {
503
464
  * Parses a Dsn from a given string.
504
465
  *
505
466
  * @param str A Dsn as string
506
- * @returns Dsn as DsnComponents or undefined if @param str is not a valid DSN string
467
+ * @returns Dsn as DsnComponents
507
468
  */
508
469
  function dsnFromString(str) {
509
470
  const match = DSN_REGEX.exec(str);
510
471
 
511
472
  if (!match) {
512
- // This should be logged to the console
513
- // eslint-disable-next-line no-console
514
- console.error(`Invalid Sentry Dsn: ${str}`);
515
- return undefined;
473
+ throw new SentryError(`Invalid Sentry Dsn: ${str}`);
516
474
  }
517
475
 
518
476
  const [protocol, publicKey, pass = '', host, port = '', lastPath] = match.slice(1);
@@ -549,67 +507,117 @@ function dsnFromComponents(components) {
549
507
 
550
508
  function validateDsn(dsn) {
551
509
  if (!(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
552
- return true;
510
+ return;
553
511
  }
554
512
 
555
513
  const { port, projectId, protocol } = dsn;
556
514
 
557
515
  const requiredComponents = ['protocol', 'publicKey', 'host', 'projectId'];
558
- const hasMissingRequiredComponent = requiredComponents.find(component => {
516
+ requiredComponents.forEach(component => {
559
517
  if (!dsn[component]) {
560
- logger.error(`Invalid Sentry Dsn: ${component} missing`);
561
- return true;
518
+ throw new SentryError(`Invalid Sentry Dsn: ${component} missing`);
562
519
  }
563
- return false;
564
520
  });
565
521
 
566
- if (hasMissingRequiredComponent) {
567
- return false;
568
- }
569
-
570
522
  if (!projectId.match(/^\d+$/)) {
571
- logger.error(`Invalid Sentry Dsn: Invalid projectId ${projectId}`);
572
- return false;
523
+ throw new SentryError(`Invalid Sentry Dsn: Invalid projectId ${projectId}`);
573
524
  }
574
525
 
575
526
  if (!isValidProtocol(protocol)) {
576
- logger.error(`Invalid Sentry Dsn: Invalid protocol ${protocol}`);
577
- return false;
527
+ throw new SentryError(`Invalid Sentry Dsn: Invalid protocol ${protocol}`);
578
528
  }
579
529
 
580
530
  if (port && isNaN(parseInt(port, 10))) {
581
- logger.error(`Invalid Sentry Dsn: Invalid port ${port}`);
582
- return false;
531
+ throw new SentryError(`Invalid Sentry Dsn: Invalid port ${port}`);
583
532
  }
584
533
 
585
534
  return true;
586
535
  }
587
536
 
588
- /**
589
- * Creates a valid Sentry Dsn object, identifying a Sentry instance and project.
590
- * @returns a valid DsnComponents object or `undefined` if @param from is an invalid DSN source
591
- */
537
+ /** The Sentry Dsn, identifying a Sentry instance and project. */
592
538
  function makeDsn(from) {
593
539
  const components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from);
594
- if (!components || !validateDsn(components)) {
595
- return undefined;
596
- }
540
+ validateDsn(components);
597
541
  return components;
598
542
  }
599
543
 
600
- /** An error emitted by Sentry SDKs and related utilities. */
601
- class SentryError extends Error {
602
- /** Display name of this error instance. */
544
+ /** Prefix for logging strings */
545
+ const PREFIX = 'Sentry Logger ';
603
546
 
604
- constructor( message, logLevel = 'warn') {
605
- super(message);this.message = message;
606
- this.name = new.target.prototype.constructor.name;
607
- // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line
608
- // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes
609
- // instances of `SentryError` fail `obj instanceof SentryError` checks.
610
- Object.setPrototypeOf(this, new.target.prototype);
611
- this.logLevel = logLevel;
547
+ const CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert', 'trace'] ;
548
+
549
+ /**
550
+ * Temporarily disable sentry console instrumentations.
551
+ *
552
+ * @param callback The function to run against the original `console` messages
553
+ * @returns The results of the callback
554
+ */
555
+ function consoleSandbox(callback) {
556
+ if (!('console' in GLOBAL_OBJ)) {
557
+ return callback();
558
+ }
559
+
560
+ const originalConsole = GLOBAL_OBJ.console ;
561
+ const wrappedLevels = {};
562
+
563
+ // Restore all wrapped console methods
564
+ CONSOLE_LEVELS.forEach(level => {
565
+ // TODO(v7): Remove this check as it's only needed for Node 6
566
+ const originalWrappedFunc =
567
+ originalConsole[level] && (originalConsole[level] ).__sentry_original__;
568
+ if (level in originalConsole && originalWrappedFunc) {
569
+ wrappedLevels[level] = originalConsole[level] ;
570
+ originalConsole[level] = originalWrappedFunc ;
571
+ }
572
+ });
573
+
574
+ try {
575
+ return callback();
576
+ } finally {
577
+ // Revert restoration to wrapped state
578
+ Object.keys(wrappedLevels).forEach(level => {
579
+ originalConsole[level] = wrappedLevels[level ];
580
+ });
581
+ }
582
+ }
583
+
584
+ function makeLogger() {
585
+ let enabled = false;
586
+ const logger = {
587
+ enable: () => {
588
+ enabled = true;
589
+ },
590
+ disable: () => {
591
+ enabled = false;
592
+ },
593
+ };
594
+
595
+ if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
596
+ CONSOLE_LEVELS.forEach(name => {
597
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
598
+ logger[name] = (...args) => {
599
+ if (enabled) {
600
+ consoleSandbox(() => {
601
+ GLOBAL_OBJ.console[name](`${PREFIX}[${name}]:`, ...args);
602
+ });
603
+ }
604
+ };
605
+ });
606
+ } else {
607
+ CONSOLE_LEVELS.forEach(name => {
608
+ logger[name] = () => undefined;
609
+ });
612
610
  }
611
+
612
+ return logger ;
613
+ }
614
+
615
+ // Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
616
+ let logger;
617
+ if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
618
+ logger = getGlobalSingleton('logger', makeLogger);
619
+ } else {
620
+ logger = makeLogger();
613
621
  }
614
622
 
615
623
  /**
@@ -965,12 +973,6 @@ function createStackParser(...parsers) {
965
973
  // Remove webpack (error: *) wrappers
966
974
  const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, '$1') : line;
967
975
 
968
- // https://github.com/getsentry/sentry-javascript/issues/7813
969
- // Skip Error: lines
970
- if (cleanedLine.match(/\S*Error: /)) {
971
- continue;
972
- }
973
-
974
976
  for (const parser of sortedParsers) {
975
977
  const frame = parser(cleanedLine);
976
978
 
@@ -1155,8 +1157,6 @@ function supportsHistory() {
1155
1157
  // eslint-disable-next-line deprecation/deprecation
1156
1158
  const WINDOW$3 = getGlobalObject();
1157
1159
 
1158
- const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v2__';
1159
-
1160
1160
  /**
1161
1161
  * Instrument native APIs to call handlers that can be used to create breadcrumbs, APM spans etc.
1162
1162
  * - Console API
@@ -1269,13 +1269,11 @@ function instrumentFetch() {
1269
1269
 
1270
1270
  fill(WINDOW$3, 'fetch', function (originalFetch) {
1271
1271
  return function (...args) {
1272
- const { method, url } = parseFetchArgs(args);
1273
-
1274
1272
  const handlerData = {
1275
1273
  args,
1276
1274
  fetchData: {
1277
- method,
1278
- url,
1275
+ method: getFetchMethod(args),
1276
+ url: getFetchUrl(args),
1279
1277
  },
1280
1278
  startTimestamp: Date.now(),
1281
1279
  };
@@ -1310,53 +1308,29 @@ function instrumentFetch() {
1310
1308
  });
1311
1309
  }
1312
1310
 
1313
- function hasProp(obj, prop) {
1314
- return !!obj && typeof obj === 'object' && !!(obj )[prop];
1315
- }
1316
-
1317
- function getUrlFromResource(resource) {
1318
- if (typeof resource === 'string') {
1319
- return resource;
1320
- }
1321
-
1322
- if (!resource) {
1323
- return '';
1324
- }
1325
-
1326
- if (hasProp(resource, 'url')) {
1327
- return resource.url;
1311
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
1312
+ /** Extract `method` from fetch call arguments */
1313
+ function getFetchMethod(fetchArgs = []) {
1314
+ if ('Request' in WINDOW$3 && isInstanceOf(fetchArgs[0], Request) && fetchArgs[0].method) {
1315
+ return String(fetchArgs[0].method).toUpperCase();
1328
1316
  }
1329
-
1330
- if (resource.toString) {
1331
- return resource.toString();
1317
+ if (fetchArgs[1] && fetchArgs[1].method) {
1318
+ return String(fetchArgs[1].method).toUpperCase();
1332
1319
  }
1333
-
1334
- return '';
1320
+ return 'GET';
1335
1321
  }
1336
1322
 
1337
- /**
1338
- * Parses the fetch arguments to find the used Http method and the url of the request
1339
- */
1340
- function parseFetchArgs(fetchArgs) {
1341
- if (fetchArgs.length === 0) {
1342
- return { method: 'GET', url: '' };
1323
+ /** Extract `url` from fetch call arguments */
1324
+ function getFetchUrl(fetchArgs = []) {
1325
+ if (typeof fetchArgs[0] === 'string') {
1326
+ return fetchArgs[0];
1343
1327
  }
1344
-
1345
- if (fetchArgs.length === 2) {
1346
- const [url, options] = fetchArgs ;
1347
-
1348
- return {
1349
- url: getUrlFromResource(url),
1350
- method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET',
1351
- };
1328
+ if ('Request' in WINDOW$3 && isInstanceOf(fetchArgs[0], Request)) {
1329
+ return fetchArgs[0].url;
1352
1330
  }
1353
-
1354
- const arg = fetchArgs[0];
1355
- return {
1356
- url: getUrlFromResource(arg ),
1357
- method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',
1358
- };
1331
+ return String(fetchArgs[0]);
1359
1332
  }
1333
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access */
1360
1334
 
1361
1335
  /** JSDoc */
1362
1336
  function instrumentXHR() {
@@ -1369,11 +1343,10 @@ function instrumentXHR() {
1369
1343
  fill(xhrproto, 'open', function (originalOpen) {
1370
1344
  return function ( ...args) {
1371
1345
  const url = args[1];
1372
- const xhrInfo = (this[SENTRY_XHR_DATA_KEY] = {
1346
+ const xhrInfo = (this.__sentry_xhr__ = {
1373
1347
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1374
1348
  method: isString$2(args[0]) ? args[0].toUpperCase() : args[0],
1375
1349
  url: args[1],
1376
- request_headers: {},
1377
1350
  });
1378
1351
 
1379
1352
  // if Sentry key appears in URL, don't capture it as a request
@@ -1384,7 +1357,7 @@ function instrumentXHR() {
1384
1357
 
1385
1358
  const onreadystatechangeHandler = () => {
1386
1359
  // For whatever reason, this is not the same instance here as from the outer method
1387
- const xhrInfo = this[SENTRY_XHR_DATA_KEY];
1360
+ const xhrInfo = this.__sentry_xhr__;
1388
1361
 
1389
1362
  if (!xhrInfo) {
1390
1363
  return;
@@ -1419,32 +1392,14 @@ function instrumentXHR() {
1419
1392
  this.addEventListener('readystatechange', onreadystatechangeHandler);
1420
1393
  }
1421
1394
 
1422
- // Intercepting `setRequestHeader` to access the request headers of XHR instance.
1423
- // This will only work for user/library defined headers, not for the default/browser-assigned headers.
1424
- // Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.
1425
- fill(this, 'setRequestHeader', function (original) {
1426
- return function ( ...setRequestHeaderArgs) {
1427
- const [header, value] = setRequestHeaderArgs ;
1428
-
1429
- const xhrInfo = this[SENTRY_XHR_DATA_KEY];
1430
-
1431
- if (xhrInfo) {
1432
- xhrInfo.request_headers[header.toLowerCase()] = value;
1433
- }
1434
-
1435
- return original.apply(this, setRequestHeaderArgs);
1436
- };
1437
- });
1438
-
1439
1395
  return originalOpen.apply(this, args);
1440
1396
  };
1441
1397
  });
1442
1398
 
1443
1399
  fill(xhrproto, 'send', function (originalSend) {
1444
1400
  return function ( ...args) {
1445
- const sentryXhrData = this[SENTRY_XHR_DATA_KEY];
1446
- if (sentryXhrData && args[0] !== undefined) {
1447
- sentryXhrData.body = args[0];
1401
+ if (this.__sentry_xhr__ && args[0] !== undefined) {
1402
+ this.__sentry_xhr__.body = args[0];
1448
1403
  }
1449
1404
 
1450
1405
  triggerHandlers('xhr', {
@@ -1743,15 +1698,13 @@ function instrumentError() {
1743
1698
  url,
1744
1699
  });
1745
1700
 
1746
- if (_oldOnErrorHandler && !_oldOnErrorHandler.__SENTRY_LOADER__) {
1701
+ if (_oldOnErrorHandler) {
1747
1702
  // eslint-disable-next-line prefer-rest-params
1748
1703
  return _oldOnErrorHandler.apply(this, arguments);
1749
1704
  }
1750
1705
 
1751
1706
  return false;
1752
1707
  };
1753
-
1754
- WINDOW$3.onerror.__SENTRY_INSTRUMENTED__ = true;
1755
1708
  }
1756
1709
 
1757
1710
  let _oldOnUnhandledRejectionHandler = null;
@@ -1762,15 +1715,13 @@ function instrumentUnhandledRejection() {
1762
1715
  WINDOW$3.onunhandledrejection = function (e) {
1763
1716
  triggerHandlers('unhandledrejection', e);
1764
1717
 
1765
- if (_oldOnUnhandledRejectionHandler && !_oldOnUnhandledRejectionHandler.__SENTRY_LOADER__) {
1718
+ if (_oldOnUnhandledRejectionHandler) {
1766
1719
  // eslint-disable-next-line prefer-rest-params
1767
1720
  return _oldOnUnhandledRejectionHandler.apply(this, arguments);
1768
1721
  }
1769
1722
 
1770
1723
  return true;
1771
1724
  };
1772
-
1773
- WINDOW$3.onunhandledrejection.__SENTRY_INSTRUMENTED__ = true;
1774
1725
  }
1775
1726
 
1776
1727
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -2068,7 +2019,7 @@ function loadModule(moduleName) {
2068
2019
  * @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization.
2069
2020
  */
2070
2021
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2071
- function normalize(input, depth = 100, maxProperties = +Infinity) {
2022
+ function normalize(input, depth = +Infinity, maxProperties = +Infinity) {
2072
2023
  try {
2073
2024
  // since we're at the outermost level, we don't provide a key
2074
2025
  return visit('', input, depth, maxProperties);
@@ -2114,10 +2065,7 @@ function visit(
2114
2065
  const [memoize, unmemoize] = memo;
2115
2066
 
2116
2067
  // Get the simple cases out of the way first
2117
- if (
2118
- value == null || // this matches null and undefined -> eqeq not eqeqeq
2119
- (['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))
2120
- ) {
2068
+ if (value === null || (['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))) {
2121
2069
  return value ;
2122
2070
  }
2123
2071
 
@@ -2138,16 +2086,17 @@ function visit(
2138
2086
  return value ;
2139
2087
  }
2140
2088
 
2141
- // We can set `__sentry_override_normalization_depth__` on an object to ensure that from there
2142
- // We keep a certain amount of depth.
2143
- // This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state.
2144
- const remainingDepth =
2145
- typeof (value )['__sentry_override_normalization_depth__'] === 'number'
2146
- ? ((value )['__sentry_override_normalization_depth__'] )
2147
- : depth;
2089
+ // Do not normalize objects that we know have already been normalized. As a general rule, the
2090
+ // "__sentry_skip_normalization__" property should only be used sparingly and only should only be set on objects that
2091
+ // have already been normalized.
2092
+ let overriddenDepth = depth;
2093
+
2094
+ if (typeof (value )['__sentry_override_normalization_depth__'] === 'number') {
2095
+ overriddenDepth = (value )['__sentry_override_normalization_depth__'] ;
2096
+ }
2148
2097
 
2149
2098
  // We're also done if we've reached the max depth
2150
- if (remainingDepth === 0) {
2099
+ if (overriddenDepth === 0) {
2151
2100
  // At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.
2152
2101
  return stringified.replace('object ', '');
2153
2102
  }
@@ -2163,7 +2112,7 @@ function visit(
2163
2112
  try {
2164
2113
  const jsonValue = valueWithToJSON.toJSON();
2165
2114
  // We need to normalize the return value of `.toJSON()` in case it has circular references
2166
- return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);
2115
+ return visit('', jsonValue, overriddenDepth - 1, maxProperties, memo);
2167
2116
  } catch (err) {
2168
2117
  // pass (The built-in `toJSON` failed, but we can still try to do it ourselves)
2169
2118
  }
@@ -2192,7 +2141,7 @@ function visit(
2192
2141
 
2193
2142
  // Recursively visit all the child nodes
2194
2143
  const visitValue = visitable[visitKey];
2195
- normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);
2144
+ normalized[visitKey] = visit(visitKey, visitValue, overriddenDepth - 1, maxProperties, memo);
2196
2145
 
2197
2146
  numAdded++;
2198
2147
  }
@@ -2204,7 +2153,6 @@ function visit(
2204
2153
  return normalized;
2205
2154
  }
2206
2155
 
2207
- /* eslint-disable complexity */
2208
2156
  /**
2209
2157
  * Stringify the given value. Handles various known special values and types.
2210
2158
  *
@@ -2255,6 +2203,11 @@ function stringifyValue(
2255
2203
  return '[NaN]';
2256
2204
  }
2257
2205
 
2206
+ // this catches `undefined` (but not `null`, which is a primitive and can be serialized on its own)
2207
+ if (value === void 0) {
2208
+ return '[undefined]';
2209
+ }
2210
+
2258
2211
  if (typeof value === 'function') {
2259
2212
  return `[Function: ${getFunctionName(value)}]`;
2260
2213
  }
@@ -2272,19 +2225,11 @@ function stringifyValue(
2272
2225
  // them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as
2273
2226
  // `"[object Object]"`. If we instead look at the constructor's name (which is the same as the name of the class),
2274
2227
  // we can make sure that only plain objects come out that way.
2275
- const objName = getConstructorName(value);
2276
-
2277
- // Handle HTML Elements
2278
- if (/^HTML(\w*)Element$/.test(objName)) {
2279
- return `[HTMLElement: ${objName}]`;
2280
- }
2281
-
2282
- return `[object ${objName}]`;
2228
+ return `[object ${getConstructorName(value)}]`;
2283
2229
  } catch (err) {
2284
2230
  return `**non-serializable** (${err})`;
2285
2231
  }
2286
2232
  }
2287
- /* eslint-enable complexity */
2288
2233
 
2289
2234
  function getConstructorName(value) {
2290
2235
  const prototype = Object.getPrototypeOf(value);
@@ -2595,7 +2540,9 @@ function makePromiseBuffer(limit) {
2595
2540
  * // environments where DOM might not be available
2596
2541
  * @returns parsed URL object
2597
2542
  */
2598
- function parseUrl(url) {
2543
+ function parseUrl(url)
2544
+
2545
+ {
2599
2546
  if (!url) {
2600
2547
  return {};
2601
2548
  }
@@ -2613,8 +2560,6 @@ function parseUrl(url) {
2613
2560
  host: match[4],
2614
2561
  path: match[5],
2615
2562
  protocol: match[2],
2616
- search: query,
2617
- hash: fragment,
2618
2563
  relative: match[5] + query + fragment, // everything minus origin
2619
2564
  };
2620
2565
  }
@@ -2999,7 +2944,6 @@ const ITEM_TYPE_TO_DATA_CATEGORY_MAP = {
2999
2944
  profile: 'profile',
3000
2945
  replay_event: 'replay',
3001
2946
  replay_recording: 'replay',
3002
- check_in: 'monitor',
3003
2947
  };
3004
2948
 
3005
2949
  /**
@@ -3029,14 +2973,16 @@ function createEventEnvelopeHeaders(
3029
2973
  dsn,
3030
2974
  ) {
3031
2975
  const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;
2976
+
3032
2977
  return {
3033
2978
  event_id: event.event_id ,
3034
2979
  sent_at: new Date().toISOString(),
3035
2980
  ...(sdkInfo && { sdk: sdkInfo }),
3036
2981
  ...(!!tunnel && { dsn: dsnToString(dsn) }),
3037
- ...(dynamicSamplingContext && {
3038
- trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
3039
- }),
2982
+ ...(event.type === 'transaction' &&
2983
+ dynamicSamplingContext && {
2984
+ trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
2985
+ }),
3040
2986
  };
3041
2987
  }
3042
2988
 
@@ -3741,16 +3687,9 @@ class Scope {
3741
3687
  // errors with transaction and it relies on that.
3742
3688
  if (this._span) {
3743
3689
  event.contexts = { trace: this._span.getTraceContext(), ...event.contexts };
3744
- const transaction = this._span.transaction;
3745
- if (transaction) {
3746
- event.sdkProcessingMetadata = {
3747
- dynamicSamplingContext: transaction.getDynamicSamplingContext(),
3748
- ...event.sdkProcessingMetadata,
3749
- };
3750
- const transactionName = transaction.name;
3751
- if (transactionName) {
3752
- event.tags = { transaction: transactionName, ...event.tags };
3753
- }
3690
+ const transactionName = this._span.transaction && this._span.transaction.name;
3691
+ if (transactionName) {
3692
+ event.tags = { transaction: transactionName, ...event.tags };
3754
3693
  }
3755
3694
  }
3756
3695
 
@@ -3874,6 +3813,11 @@ const API_VERSION = 4;
3874
3813
  */
3875
3814
  const DEFAULT_BREADCRUMBS = 100;
3876
3815
 
3816
+ /**
3817
+ * A layer in the process stack.
3818
+ * @hidden
3819
+ */
3820
+
3877
3821
  /**
3878
3822
  * @inheritDoc
3879
3823
  */
@@ -4151,17 +4095,7 @@ class Hub {
4151
4095
  * @inheritDoc
4152
4096
  */
4153
4097
  startTransaction(context, customSamplingContext) {
4154
- const result = this._callExtensionMethod('startTransaction', context, customSamplingContext);
4155
-
4156
- if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && !result) {
4157
- // eslint-disable-next-line no-console
4158
- console.warn(`Tracing extension 'startTransaction' has not been added. Call 'addTracingExtensions' before calling 'init':
4159
- Sentry.addTracingExtensions();
4160
- Sentry.init({...});
4161
- `);
4162
- }
4163
-
4164
- return result;
4098
+ return this._callExtensionMethod('startTransaction', context, customSamplingContext);
4165
4099
  }
4166
4100
 
4167
4101
  /**
@@ -4246,10 +4180,13 @@ Sentry.init({...});
4246
4180
  */
4247
4181
  _sendSessionUpdate() {
4248
4182
  const { scope, client } = this.getStackTop();
4183
+ if (!scope) return;
4249
4184
 
4250
4185
  const session = scope.getSession();
4251
- if (session && client && client.captureSession) {
4252
- client.captureSession(session);
4186
+ if (session) {
4187
+ if (client && client.captureSession) {
4188
+ client.captureSession(session);
4189
+ }
4253
4190
  }
4254
4191
  }
4255
4192
 
@@ -4319,28 +4256,47 @@ function getCurrentHub() {
4319
4256
  // Get main carrier (global for every environment)
4320
4257
  const registry = getMainCarrier();
4321
4258
 
4322
- if (registry.__SENTRY__ && registry.__SENTRY__.acs) {
4323
- const hub = registry.__SENTRY__.acs.getCurrentHub();
4324
-
4325
- if (hub) {
4326
- return hub;
4327
- }
4328
- }
4329
-
4330
- // Return hub that lives on a global object
4331
- return getGlobalHub(registry);
4332
- }
4333
-
4334
- function getGlobalHub(registry = getMainCarrier()) {
4335
4259
  // If there's no hub, or its an old API, assign a new one
4336
4260
  if (!hasHubOnCarrier(registry) || getHubFromCarrier(registry).isOlderThan(API_VERSION)) {
4337
4261
  setHubOnCarrier(registry, new Hub());
4338
4262
  }
4339
4263
 
4264
+ // Prefer domains over global if they are there (applicable only to Node environment)
4265
+ if (isNodeEnv()) {
4266
+ return getHubFromActiveDomain(registry);
4267
+ }
4340
4268
  // Return hub that lives on a global object
4341
4269
  return getHubFromCarrier(registry);
4342
4270
  }
4343
4271
 
4272
+ /**
4273
+ * Try to read the hub from an active domain, and fallback to the registry if one doesn't exist
4274
+ * @returns discovered hub
4275
+ */
4276
+ function getHubFromActiveDomain(registry) {
4277
+ try {
4278
+ const sentry = getMainCarrier().__SENTRY__;
4279
+ const activeDomain = sentry && sentry.extensions && sentry.extensions.domain && sentry.extensions.domain.active;
4280
+
4281
+ // If there's no active domain, just return global hub
4282
+ if (!activeDomain) {
4283
+ return getHubFromCarrier(registry);
4284
+ }
4285
+
4286
+ // If there's no hub on current domain, or it's an old API, assign a new one
4287
+ if (!hasHubOnCarrier(activeDomain) || getHubFromCarrier(activeDomain).isOlderThan(API_VERSION)) {
4288
+ const registryHubTopStack = getHubFromCarrier(registry).getStackTop();
4289
+ setHubOnCarrier(activeDomain, new Hub(registryHubTopStack.client, Scope.clone(registryHubTopStack.scope)));
4290
+ }
4291
+
4292
+ // Return hub that lives on a domain
4293
+ return getHubFromCarrier(activeDomain);
4294
+ } catch (_Oo) {
4295
+ // Return hub that lives on a global object
4296
+ return getHubFromCarrier(registry);
4297
+ }
4298
+ }
4299
+
4344
4300
  /**
4345
4301
  * This will tell whether a carrier has a hub on it or not
4346
4302
  * @param carrier object
@@ -4414,69 +4370,6 @@ var SpanStatus; (function (SpanStatus) {
4414
4370
  const DataLoss = 'data_loss'; SpanStatus["DataLoss"] = DataLoss;
4415
4371
  })(SpanStatus || (SpanStatus = {}));
4416
4372
 
4417
- /**
4418
- * Wraps a function with a transaction/span and finishes the span after the function is done.
4419
- *
4420
- * Note that if you have not enabled tracing extensions via `addTracingExtensions`, this function
4421
- * will not generate spans, and the `span` returned from the callback may be undefined.
4422
- *
4423
- * This function is meant to be used internally and may break at any time. Use at your own risk.
4424
- *
4425
- * @internal
4426
- * @private
4427
- */
4428
- function trace(
4429
- context,
4430
- callback,
4431
- // eslint-disable-next-line @typescript-eslint/no-empty-function
4432
- onError = () => {},
4433
- ) {
4434
- const ctx = { ...context };
4435
- // If a name is set and a description is not, set the description to the name.
4436
- if (ctx.name !== undefined && ctx.description === undefined) {
4437
- ctx.description = ctx.name;
4438
- }
4439
-
4440
- const hub = getCurrentHub();
4441
- const scope = hub.getScope();
4442
-
4443
- const parentSpan = scope.getSpan();
4444
- const activeSpan = parentSpan ? parentSpan.startChild(ctx) : hub.startTransaction(ctx);
4445
- scope.setSpan(activeSpan);
4446
-
4447
- function finishAndSetSpan() {
4448
- activeSpan && activeSpan.finish();
4449
- hub.getScope().setSpan(parentSpan);
4450
- }
4451
-
4452
- let maybePromiseResult;
4453
- try {
4454
- maybePromiseResult = callback(activeSpan);
4455
- } catch (e) {
4456
- activeSpan && activeSpan.setStatus('internal_error');
4457
- onError(e);
4458
- finishAndSetSpan();
4459
- throw e;
4460
- }
4461
-
4462
- if (isThenable(maybePromiseResult)) {
4463
- Promise.resolve(maybePromiseResult).then(
4464
- () => {
4465
- finishAndSetSpan();
4466
- },
4467
- e => {
4468
- activeSpan && activeSpan.setStatus('internal_error');
4469
- onError(e);
4470
- finishAndSetSpan();
4471
- },
4472
- );
4473
- } else {
4474
- finishAndSetSpan();
4475
- }
4476
-
4477
- return maybePromiseResult;
4478
- }
4479
-
4480
4373
  // Note: All functions in this file are typed with a return value of `ReturnType<Hub[HUB_FUNCTION]>`,
4481
4374
  // where HUB_FUNCTION is some method on the Hub class.
4482
4375
  //
@@ -4818,11 +4711,7 @@ function prepareEvent(
4818
4711
 
4819
4712
  applyClientOptions(prepared, options);
4820
4713
  applyIntegrationsMetadata(prepared, integrations);
4821
-
4822
- // Only apply debug metadata to error events.
4823
- if (event.type === undefined) {
4824
- applyDebugMetadata(prepared, options.stackParser);
4825
- }
4714
+ applyDebugMetadata(prepared, options.stackParser);
4826
4715
 
4827
4716
  // If we have scope given to us, use it as the base for further modifications.
4828
4717
  // This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
@@ -4899,8 +4788,6 @@ function applyClientOptions(event, options) {
4899
4788
  }
4900
4789
  }
4901
4790
 
4902
- const debugIdStackParserCache = new WeakMap();
4903
-
4904
4791
  /**
4905
4792
  * Applies debug metadata images to the event in order to apply source maps by looking up their debug ID.
4906
4793
  */
@@ -4911,28 +4798,10 @@ function applyDebugMetadata(event, stackParser) {
4911
4798
  return;
4912
4799
  }
4913
4800
 
4914
- let debugIdStackFramesCache;
4915
- const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
4916
- if (cachedDebugIdStackFrameCache) {
4917
- debugIdStackFramesCache = cachedDebugIdStackFrameCache;
4918
- } else {
4919
- debugIdStackFramesCache = new Map();
4920
- debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
4921
- }
4922
-
4923
4801
  // Build a map of filename -> debug_id
4924
4802
  const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => {
4925
- let parsedStack;
4926
- const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
4927
- if (cachedParsedStack) {
4928
- parsedStack = cachedParsedStack;
4929
- } else {
4930
- parsedStack = stackParser(debugIdStackTrace);
4931
- debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
4932
- }
4933
-
4934
- for (let i = parsedStack.length - 1; i >= 0; i--) {
4935
- const stackFrame = parsedStack[i];
4803
+ const parsedStack = stackParser(debugIdStackTrace);
4804
+ for (const stackFrame of parsedStack) {
4936
4805
  if (stackFrame.filename) {
4937
4806
  acc[stackFrame.filename] = debugIdMap[debugIdStackTrace];
4938
4807
  break;
@@ -5109,20 +4978,16 @@ class BaseClient {
5109
4978
  */
5110
4979
  constructor(options) {BaseClient.prototype.__init.call(this);BaseClient.prototype.__init2.call(this);BaseClient.prototype.__init3.call(this);BaseClient.prototype.__init4.call(this);BaseClient.prototype.__init5.call(this);
5111
4980
  this._options = options;
5112
-
5113
4981
  if (options.dsn) {
5114
4982
  this._dsn = makeDsn(options.dsn);
5115
- } else {
5116
- (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('No DSN provided, client will not do anything.');
5117
- }
5118
-
5119
- if (this._dsn) {
5120
4983
  const url = getEnvelopeEndpointWithUrlEncodedAuth(this._dsn, options);
5121
4984
  this._transport = options.transport({
5122
4985
  recordDroppedEvent: this.recordDroppedEvent.bind(this),
5123
4986
  ...options.transportOptions,
5124
4987
  url,
5125
4988
  });
4989
+ } else {
4990
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('No DSN provided, client will not do anything.');
5126
4991
  }
5127
4992
  }
5128
4993
 
@@ -5841,7 +5706,7 @@ function getEventForEnvelopeItem(item, type) {
5841
5706
  return Array.isArray(item) ? (item )[1] : undefined;
5842
5707
  }
5843
5708
 
5844
- const SDK_VERSION = '7.53.0';
5709
+ const SDK_VERSION = '7.46.0';
5845
5710
 
5846
5711
  let originalFunctionToString;
5847
5712
 
@@ -5864,17 +5729,11 @@ class FunctionToString {constructor() { FunctionToString.prototype.__init.call(
5864
5729
  // eslint-disable-next-line @typescript-eslint/unbound-method
5865
5730
  originalFunctionToString = Function.prototype.toString;
5866
5731
 
5867
- // intrinsics (like Function.prototype) might be immutable in some environments
5868
- // e.g. Node with --frozen-intrinsics, XS (an embedded JavaScript engine) or SES (a JavaScript proposal)
5869
- try {
5870
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5871
- Function.prototype.toString = function ( ...args) {
5872
- const context = getOriginalFunction(this) || this;
5873
- return originalFunctionToString.apply(context, args);
5874
- };
5875
- } catch (e) {
5876
- // ignore errors here, just don't patch this
5877
- }
5732
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5733
+ Function.prototype.toString = function ( ...args) {
5734
+ const context = getOriginalFunction(this) || this;
5735
+ return originalFunctionToString.apply(context, args);
5736
+ };
5878
5737
  }
5879
5738
  } FunctionToString.__initStatic();
5880
5739
 
@@ -6022,9 +5881,8 @@ function _getPossibleEventMessages(event) {
6022
5881
  return [event.message];
6023
5882
  }
6024
5883
  if (event.exception) {
6025
- const { values } = event.exception;
6026
5884
  try {
6027
- const { type = '', value = '' } = (values && values[values.length - 1]) || {};
5885
+ const { type = '', value = '' } = (event.exception.values && event.exception.values[0]) || {};
6028
5886
  return [`${value}`, `${type}: ${value}`];
6029
5887
  } catch (oO) {
6030
5888
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(`Cannot extract message for event ${getEventDescription(event)}`);
@@ -6074,9 +5932,9 @@ function _getEventFilterUrl(event) {
6074
5932
  }
6075
5933
 
6076
5934
  var Integrations = /*#__PURE__*/Object.freeze({
6077
- __proto__: null,
6078
- FunctionToString: FunctionToString,
6079
- InboundFilters: InboundFilters
5935
+ __proto__: null,
5936
+ FunctionToString: FunctionToString,
5937
+ InboundFilters: InboundFilters
6080
5938
  });
6081
5939
 
6082
5940
  const WINDOW$1 = GLOBAL_OBJ ;
@@ -6683,14 +6541,12 @@ function _consoleBreadcrumb(handlerData) {
6683
6541
  function _xhrBreadcrumb(handlerData) {
6684
6542
  const { startTimestamp, endTimestamp } = handlerData;
6685
6543
 
6686
- const sentryXhrData = handlerData.xhr[SENTRY_XHR_DATA_KEY];
6687
-
6688
6544
  // We only capture complete, non-sentry requests
6689
- if (!startTimestamp || !endTimestamp || !sentryXhrData) {
6545
+ if (!startTimestamp || !endTimestamp || !handlerData.xhr.__sentry_xhr__) {
6690
6546
  return;
6691
6547
  }
6692
6548
 
6693
- const { method, url, status_code, body } = sentryXhrData;
6549
+ const { method, url, status_code, body } = handlerData.xhr.__sentry_xhr__;
6694
6550
 
6695
6551
  const data = {
6696
6552
  method,
@@ -6808,43 +6664,6 @@ function _isEvent(event) {
6808
6664
  return event && !!(event ).target;
6809
6665
  }
6810
6666
 
6811
- /**
6812
- * Creates an envelope from a user feedback.
6813
- */
6814
- function createUserFeedbackEnvelope(
6815
- feedback,
6816
- {
6817
- metadata,
6818
- tunnel,
6819
- dsn,
6820
- }
6821
-
6822
- ,
6823
- ) {
6824
- const headers = {
6825
- event_id: feedback.event_id,
6826
- sent_at: new Date().toISOString(),
6827
- ...(metadata &&
6828
- metadata.sdk && {
6829
- sdk: {
6830
- name: metadata.sdk.name,
6831
- version: metadata.sdk.version,
6832
- },
6833
- }),
6834
- ...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }),
6835
- };
6836
- const item = createUserFeedbackEnvelopeItem(feedback);
6837
-
6838
- return createEnvelope(headers, [item]);
6839
- }
6840
-
6841
- function createUserFeedbackEnvelopeItem(feedback) {
6842
- const feedbackHeaders = {
6843
- type: 'user_report',
6844
- };
6845
- return [feedbackHeaders, feedback];
6846
- }
6847
-
6848
6667
  /**
6849
6668
  * Configuration options for the Sentry Browser SDK.
6850
6669
  * @see @sentry/types Options for more information.
@@ -6927,23 +6746,6 @@ class BrowserClient extends BaseClient {
6927
6746
  super.sendEvent(event, hint);
6928
6747
  }
6929
6748
 
6930
- /**
6931
- * Sends user feedback to Sentry.
6932
- */
6933
- captureUserFeedback(feedback) {
6934
- if (!this._isEnabled()) {
6935
- (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('SDK not enabled, will not capture user feedback.');
6936
- return;
6937
- }
6938
-
6939
- const envelope = createUserFeedbackEnvelope(feedback, {
6940
- metadata: this.getSdkMetadata(),
6941
- dsn: this.getDsn(),
6942
- tunnel: this.getOptions().tunnel,
6943
- });
6944
- void this._sendEnvelope(envelope);
6945
- }
6946
-
6947
6749
  /**
6948
6750
  * @inheritDoc
6949
6751
  */
@@ -7186,7 +6988,7 @@ function createFrame(filename, func, lineno, colno) {
7186
6988
 
7187
6989
  // Chromium based browsers: Chrome, Brave, new Opera, new Edge
7188
6990
  const chromeRegex =
7189
- /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
6991
+ /^\s*at (?:(.*\).*?|.*?) ?\((?:address at )?)?(?:async )?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
7190
6992
  const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
7191
6993
 
7192
6994
  const chrome = line => {
@@ -7222,7 +7024,7 @@ const chromeStackLineParser = [CHROME_PRIORITY, chrome];
7222
7024
  // generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
7223
7025
  // We need this specific case for now because we want no other regex to match.
7224
7026
  const geckoREgex =
7225
- /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
7027
+ /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
7226
7028
  const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
7227
7029
 
7228
7030
  const gecko = line => {
@@ -7254,7 +7056,8 @@ const gecko = line => {
7254
7056
 
7255
7057
  const geckoStackLineParser = [GECKO_PRIORITY, gecko];
7256
7058
 
7257
- const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
7059
+ const winjsRegex =
7060
+ /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
7258
7061
 
7259
7062
  const winjs = line => {
7260
7063
  const parts = winjsRegex.exec(line);
@@ -8300,13 +8103,13 @@ function startSessionTracking() {
8300
8103
  }
8301
8104
 
8302
8105
  var index$1 = /*#__PURE__*/Object.freeze({
8303
- __proto__: null,
8304
- GlobalHandlers: GlobalHandlers,
8305
- TryCatch: TryCatch,
8306
- Breadcrumbs: Breadcrumbs,
8307
- LinkedErrors: LinkedErrors,
8308
- HttpContext: HttpContext,
8309
- Dedupe: Dedupe
8106
+ __proto__: null,
8107
+ GlobalHandlers: GlobalHandlers,
8108
+ TryCatch: TryCatch,
8109
+ Breadcrumbs: Breadcrumbs,
8110
+ LinkedErrors: LinkedErrors,
8111
+ HttpContext: HttpContext,
8112
+ Dedupe: Dedupe
8310
8113
  });
8311
8114
 
8312
8115
  // exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser`
@@ -8319,14 +8122,11 @@ const REPLAY_SESSION_KEY = 'sentryReplaySession';
8319
8122
  const REPLAY_EVENT_NAME = 'replay_event';
8320
8123
  const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
8321
8124
 
8322
- // The idle limit for a session after which recording is paused.
8323
- const SESSION_IDLE_PAUSE_DURATION = 300000; // 5 minutes in ms
8324
-
8325
- // The idle limit for a session after which the session expires.
8326
- const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms
8125
+ // The idle limit for a session
8126
+ const SESSION_IDLE_DURATION = 300000; // 5 minutes in ms
8327
8127
 
8328
8128
  // The maximum length of a session
8329
- const MAX_SESSION_LIFE = 3600000; // 60 minutes in ms
8129
+ const MAX_SESSION_LIFE = 3600000; // 60 minutes
8330
8130
 
8331
8131
  /** Default flush delays */
8332
8132
  const DEFAULT_FLUSH_MIN_DELAY = 5000;
@@ -8335,16 +8135,13 @@ const DEFAULT_FLUSH_MIN_DELAY = 5000;
8335
8135
  const DEFAULT_FLUSH_MAX_DELAY = 5500;
8336
8136
 
8337
8137
  /* How long to wait for error checkouts */
8338
- const BUFFER_CHECKOUT_TIME = 60000;
8138
+ const ERROR_CHECKOUT_TIME = 60000;
8339
8139
 
8340
8140
  const RETRY_BASE_INTERVAL = 5000;
8341
8141
  const RETRY_MAX_COUNT = 3;
8342
8142
 
8343
- /* The max (uncompressed) size in bytes of a network body. Any body larger than this will be truncated. */
8344
- const NETWORK_BODY_MAX_SIZE = 150000;
8345
-
8346
- /* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
8347
- const CONSOLE_ARG_MAX_SIZE = 5000;
8143
+ /* The max (uncompressed) size in bytes of a network body. Any body larger than this will be dropped. */
8144
+ const NETWORK_BODY_MAX_SIZE = 300000;
8348
8145
 
8349
8146
  var NodeType$1;
8350
8147
  (function (NodeType) {
@@ -8381,7 +8178,7 @@ function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInp
8381
8178
  if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
8382
8179
  return text;
8383
8180
  }
8384
- if (input.hasAttribute('data-rr-is-password')) {
8181
+ if (input.hasAttribute('rr_is_password')) {
8385
8182
  type = 'password';
8386
8183
  }
8387
8184
  if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
@@ -8414,21 +8211,6 @@ function is2DCanvasBlank(canvas) {
8414
8211
  }
8415
8212
  return true;
8416
8213
  }
8417
- function getInputType(element) {
8418
- const type = element.type;
8419
- return element.hasAttribute('data-rr-is-password')
8420
- ? 'password'
8421
- : type
8422
- ? type.toLowerCase()
8423
- : null;
8424
- }
8425
- function getInputValue(el, tagName, type) {
8426
- typeof type === 'string' ? type.toLowerCase() : '';
8427
- if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
8428
- return el.getAttribute('value') || '';
8429
- }
8430
- return el.value;
8431
- }
8432
8214
 
8433
8215
  let _id = 1;
8434
8216
  const tagNameRegex = new RegExp('[^a-z0-9-_:]');
@@ -8467,13 +8249,6 @@ function getCssRuleString(rule) {
8467
8249
  catch (_a) {
8468
8250
  }
8469
8251
  }
8470
- return validateStringifiedCssRule(cssStringified);
8471
- }
8472
- function validateStringifiedCssRule(cssStringified) {
8473
- if (cssStringified.indexOf(':') > -1) {
8474
- const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
8475
- return cssStringified.replace(regex, '$1\\$2');
8476
- }
8477
8252
  return cssStringified;
8478
8253
  }
8479
8254
  function isCSSImportRule(rule) {
@@ -8482,7 +8257,7 @@ function isCSSImportRule(rule) {
8482
8257
  function stringifyStyleSheet(sheet) {
8483
8258
  return sheet.cssRules
8484
8259
  ? Array.from(sheet.cssRules)
8485
- .map((rule) => rule.cssText ? validateStringifiedCssRule(rule.cssText) : '')
8260
+ .map((rule) => rule.cssText || '')
8486
8261
  .join('')
8487
8262
  : '';
8488
8263
  }
@@ -8817,15 +8592,14 @@ function serializeNode(n, options) {
8817
8592
  tagName === 'select' ||
8818
8593
  tagName === 'option') {
8819
8594
  const el = n;
8820
- const type = getInputType(el);
8821
- const value = getInputValue(el, tagName.toUpperCase(), type);
8595
+ const value = getInputValue(tagName, el, attributes);
8822
8596
  const checked = n.checked;
8823
- if (type !== 'submit' &&
8824
- type !== 'button' &&
8597
+ if (attributes.type !== 'submit' &&
8598
+ attributes.type !== 'button' &&
8825
8599
  value) {
8826
8600
  attributes.value = maskInputValue({
8827
8601
  input: el,
8828
- type,
8602
+ type: attributes.type,
8829
8603
  tagName,
8830
8604
  value,
8831
8605
  maskInputSelector,
@@ -9298,8 +9072,15 @@ function snapshot(n, options) {
9298
9072
  function skipAttribute(tagName, attributeName, value) {
9299
9073
  return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
9300
9074
  }
9075
+ function getInputValue(tagName, el, attributes) {
9076
+ if (tagName === 'input' &&
9077
+ (attributes.type === 'radio' || attributes.type === 'checkbox')) {
9078
+ return el.getAttribute('value') || '';
9079
+ }
9080
+ return el.value;
9081
+ }
9301
9082
 
9302
- var EventType$1;
9083
+ var EventType;
9303
9084
  (function (EventType) {
9304
9085
  EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
9305
9086
  EventType[EventType["Load"] = 1] = "Load";
@@ -9308,7 +9089,7 @@ var EventType$1;
9308
9089
  EventType[EventType["Meta"] = 4] = "Meta";
9309
9090
  EventType[EventType["Custom"] = 5] = "Custom";
9310
9091
  EventType[EventType["Plugin"] = 6] = "Plugin";
9311
- })(EventType$1 || (EventType$1 = {}));
9092
+ })(EventType || (EventType = {}));
9312
9093
  var IncrementalSource;
9313
9094
  (function (IncrementalSource) {
9314
9095
  IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
@@ -9923,9 +9704,9 @@ class MutationBuffer {
9923
9704
  this.attributes.push(item);
9924
9705
  }
9925
9706
  if (m.attributeName === 'type' &&
9926
- target.tagName === 'INPUT' &&
9707
+ m.target.tagName === 'INPUT' &&
9927
9708
  (m.oldValue || '').toLowerCase() === 'password') {
9928
- target.setAttribute('data-rr-is-password', 'true');
9709
+ m.target.setAttribute('rr_is_password', 'true');
9929
9710
  }
9930
9711
  if (m.attributeName === 'style') {
9931
9712
  const old = this.doc.createElement('span');
@@ -10322,25 +10103,27 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
10322
10103
  isBlocked(target, blockClass, blockSelector, unblockSelector)) {
10323
10104
  return;
10324
10105
  }
10325
- const el = target;
10326
- const type = getInputType(el);
10327
- if (el.classList.contains(ignoreClass) ||
10328
- (ignoreSelector && el.matches(ignoreSelector))) {
10106
+ let type = target.type;
10107
+ if (target.classList.contains(ignoreClass) ||
10108
+ (ignoreSelector && target.matches(ignoreSelector))) {
10329
10109
  return;
10330
10110
  }
10331
- let text = getInputValue(el, tagName, type);
10111
+ let text = target.value;
10332
10112
  let isChecked = false;
10113
+ if (target.hasAttribute('rr_is_password')) {
10114
+ type = 'password';
10115
+ }
10333
10116
  if (type === 'radio' || type === 'checkbox') {
10334
10117
  isChecked = target.checked;
10335
10118
  }
10336
- if (hasInputMaskOptions({
10119
+ else if (hasInputMaskOptions({
10337
10120
  maskInputOptions,
10338
10121
  maskInputSelector,
10339
10122
  tagName,
10340
10123
  type,
10341
10124
  })) {
10342
10125
  text = maskInputValue({
10343
- input: el,
10126
+ input: target,
10344
10127
  maskInputOptions,
10345
10128
  maskInputSelector,
10346
10129
  unmaskInputSelector,
@@ -10357,18 +10140,8 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
10357
10140
  .querySelectorAll(`input[type="radio"][name="${name}"]`)
10358
10141
  .forEach((el) => {
10359
10142
  if (el !== target) {
10360
- const text = maskInputValue({
10361
- input: el,
10362
- maskInputOptions,
10363
- maskInputSelector,
10364
- unmaskInputSelector,
10365
- tagName,
10366
- type,
10367
- value: getInputValue(el, tagName, type),
10368
- maskInputFn,
10369
- });
10370
10143
  cbWithDedup(el, callbackWrapper(wrapEventWithUserTriggeredFlag)({
10371
- text,
10144
+ text: el.value,
10372
10145
  isChecked: !isChecked,
10373
10146
  userTriggered: false,
10374
10147
  }, userTriggeredOnInput));
@@ -11281,17 +11054,17 @@ function record(options = {}) {
11281
11054
  wrappedEmit = (e, isCheckout) => {
11282
11055
  var _a;
11283
11056
  if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
11284
- e.type !== EventType$1.FullSnapshot &&
11285
- !(e.type === EventType$1.IncrementalSnapshot &&
11057
+ e.type !== EventType.FullSnapshot &&
11058
+ !(e.type === EventType.IncrementalSnapshot &&
11286
11059
  e.data.source === IncrementalSource.Mutation)) {
11287
11060
  mutationBuffers.forEach((buf) => buf.unfreeze());
11288
11061
  }
11289
11062
  emit(eventProcessor(e), isCheckout);
11290
- if (e.type === EventType$1.FullSnapshot) {
11063
+ if (e.type === EventType.FullSnapshot) {
11291
11064
  lastFullSnapshotEvent = e;
11292
11065
  incrementalSnapshotCount = 0;
11293
11066
  }
11294
- else if (e.type === EventType$1.IncrementalSnapshot) {
11067
+ else if (e.type === EventType.IncrementalSnapshot) {
11295
11068
  if (e.data.source === IncrementalSource.Mutation &&
11296
11069
  e.data.isAttachIframe) {
11297
11070
  return;
@@ -11307,16 +11080,16 @@ function record(options = {}) {
11307
11080
  };
11308
11081
  const wrappedMutationEmit = (m) => {
11309
11082
  wrappedEmit(wrapEvent({
11310
- type: EventType$1.IncrementalSnapshot,
11083
+ type: EventType.IncrementalSnapshot,
11311
11084
  data: Object.assign({ source: IncrementalSource.Mutation }, m),
11312
11085
  }));
11313
11086
  };
11314
11087
  const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
11315
- type: EventType$1.IncrementalSnapshot,
11088
+ type: EventType.IncrementalSnapshot,
11316
11089
  data: Object.assign({ source: IncrementalSource.Scroll }, p),
11317
11090
  }));
11318
11091
  const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
11319
- type: EventType$1.IncrementalSnapshot,
11092
+ type: EventType.IncrementalSnapshot,
11320
11093
  data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
11321
11094
  }));
11322
11095
  const iframeManager = new IframeManager({
@@ -11361,7 +11134,7 @@ function record(options = {}) {
11361
11134
  takeFullSnapshot = (isCheckout = false) => {
11362
11135
  var _a, _b, _c, _d;
11363
11136
  wrappedEmit(wrapEvent({
11364
- type: EventType$1.Meta,
11137
+ type: EventType.Meta,
11365
11138
  data: {
11366
11139
  href: window.location.href,
11367
11140
  width: getWindowWidth(),
@@ -11404,7 +11177,7 @@ function record(options = {}) {
11404
11177
  }
11405
11178
  mirror.map = idNodeMap;
11406
11179
  wrappedEmit(wrapEvent({
11407
- type: EventType$1.FullSnapshot,
11180
+ type: EventType.FullSnapshot,
11408
11181
  data: {
11409
11182
  node,
11410
11183
  initialOffset: {
@@ -11429,7 +11202,7 @@ function record(options = {}) {
11429
11202
  const handlers = [];
11430
11203
  handlers.push(on$1('DOMContentLoaded', () => {
11431
11204
  wrappedEmit(wrapEvent({
11432
- type: EventType$1.DomContentLoaded,
11205
+ type: EventType.DomContentLoaded,
11433
11206
  data: {},
11434
11207
  }));
11435
11208
  }));
@@ -11439,40 +11212,40 @@ function record(options = {}) {
11439
11212
  onMutation,
11440
11213
  mutationCb: wrappedMutationEmit,
11441
11214
  mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
11442
- type: EventType$1.IncrementalSnapshot,
11215
+ type: EventType.IncrementalSnapshot,
11443
11216
  data: {
11444
11217
  source,
11445
11218
  positions,
11446
11219
  },
11447
11220
  })),
11448
11221
  mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
11449
- type: EventType$1.IncrementalSnapshot,
11222
+ type: EventType.IncrementalSnapshot,
11450
11223
  data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
11451
11224
  })),
11452
11225
  scrollCb: wrappedScrollEmit,
11453
11226
  viewportResizeCb: (d) => wrappedEmit(wrapEvent({
11454
- type: EventType$1.IncrementalSnapshot,
11227
+ type: EventType.IncrementalSnapshot,
11455
11228
  data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
11456
11229
  })),
11457
11230
  inputCb: (v) => wrappedEmit(wrapEvent({
11458
- type: EventType$1.IncrementalSnapshot,
11231
+ type: EventType.IncrementalSnapshot,
11459
11232
  data: Object.assign({ source: IncrementalSource.Input }, v),
11460
11233
  })),
11461
11234
  mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
11462
- type: EventType$1.IncrementalSnapshot,
11235
+ type: EventType.IncrementalSnapshot,
11463
11236
  data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
11464
11237
  })),
11465
11238
  styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
11466
- type: EventType$1.IncrementalSnapshot,
11239
+ type: EventType.IncrementalSnapshot,
11467
11240
  data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
11468
11241
  })),
11469
11242
  styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
11470
- type: EventType$1.IncrementalSnapshot,
11243
+ type: EventType.IncrementalSnapshot,
11471
11244
  data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
11472
11245
  })),
11473
11246
  canvasMutationCb: wrappedCanvasMutationEmit,
11474
11247
  fontCb: (p) => wrappedEmit(wrapEvent({
11475
- type: EventType$1.IncrementalSnapshot,
11248
+ type: EventType.IncrementalSnapshot,
11476
11249
  data: Object.assign({ source: IncrementalSource.Font }, p),
11477
11250
  })),
11478
11251
  blockClass,
@@ -11505,7 +11278,7 @@ function record(options = {}) {
11505
11278
  observer: p.observer,
11506
11279
  options: p.options,
11507
11280
  callback: (payload) => wrappedEmit(wrapEvent({
11508
- type: EventType$1.Plugin,
11281
+ type: EventType.Plugin,
11509
11282
  data: {
11510
11283
  plugin: p.name,
11511
11284
  payload,
@@ -11533,7 +11306,7 @@ function record(options = {}) {
11533
11306
  else {
11534
11307
  handlers.push(on$1('load', () => {
11535
11308
  wrappedEmit(wrapEvent({
11536
- type: EventType$1.Load,
11309
+ type: EventType.Load,
11537
11310
  data: {},
11538
11311
  }));
11539
11312
  init();
@@ -11552,7 +11325,7 @@ record.addCustomEvent = (tag, payload) => {
11552
11325
  throw new Error('please add custom event after start recording');
11553
11326
  }
11554
11327
  wrappedEmit(wrapEvent({
11555
- type: EventType$1.Custom,
11328
+ type: EventType.Custom,
11556
11329
  data: {
11557
11330
  tag,
11558
11331
  payload,
@@ -11570,503 +11343,6 @@ record.takeFullSnapshot = (isCheckout) => {
11570
11343
  };
11571
11344
  record.mirror = mirror;
11572
11345
 
11573
- /**
11574
- * Create a breadcrumb for a replay.
11575
- */
11576
- function createBreadcrumb(
11577
- breadcrumb,
11578
- ) {
11579
- return {
11580
- timestamp: Date.now() / 1000,
11581
- type: 'default',
11582
- ...breadcrumb,
11583
- };
11584
- }
11585
-
11586
- var NodeType;
11587
- (function (NodeType) {
11588
- NodeType[NodeType["Document"] = 0] = "Document";
11589
- NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
11590
- NodeType[NodeType["Element"] = 2] = "Element";
11591
- NodeType[NodeType["Text"] = 3] = "Text";
11592
- NodeType[NodeType["CDATA"] = 4] = "CDATA";
11593
- NodeType[NodeType["Comment"] = 5] = "Comment";
11594
- })(NodeType || (NodeType = {}));
11595
-
11596
- /* eslint-disable @typescript-eslint/naming-convention */
11597
-
11598
- var EventType; (function (EventType) {
11599
- const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
11600
- const Load = 1; EventType[EventType["Load"] = Load] = "Load";
11601
- const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
11602
- const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
11603
- const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
11604
- const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
11605
- const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
11606
- })(EventType || (EventType = {}));
11607
-
11608
- /**
11609
- * This is a partial copy of rrweb's eventWithTime type which only contains the properties
11610
- * we specifcally need in the SDK.
11611
- */
11612
-
11613
- /**
11614
- * Converts a timestamp to ms, if it was in s, or keeps it as ms.
11615
- */
11616
- function timestampToMs(timestamp) {
11617
- const isMs = timestamp > 9999999999;
11618
- return isMs ? timestamp : timestamp * 1000;
11619
- }
11620
-
11621
- /**
11622
- * Add an event to the event buffer.
11623
- * `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
11624
- */
11625
- async function addEvent(
11626
- replay,
11627
- event,
11628
- isCheckout,
11629
- ) {
11630
- if (!replay.eventBuffer) {
11631
- // This implies that `_isEnabled` is false
11632
- return null;
11633
- }
11634
-
11635
- if (replay.isPaused()) {
11636
- // Do not add to event buffer when recording is paused
11637
- return null;
11638
- }
11639
-
11640
- const timestampInMs = timestampToMs(event.timestamp);
11641
-
11642
- // Throw out events that happen more than 5 minutes ago. This can happen if
11643
- // page has been left open and idle for a long period of time and user
11644
- // comes back to trigger a new session. The performance entries rely on
11645
- // `performance.timeOrigin`, which is when the page first opened.
11646
- if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
11647
- return null;
11648
- }
11649
-
11650
- try {
11651
- if (isCheckout) {
11652
- replay.eventBuffer.clear();
11653
- }
11654
-
11655
- const replayOptions = replay.getOptions();
11656
-
11657
- const eventAfterPossibleCallback =
11658
- typeof replayOptions.beforeAddRecordingEvent === 'function' && event.type === EventType.Custom
11659
- ? replayOptions.beforeAddRecordingEvent(event)
11660
- : event;
11661
-
11662
- if (!eventAfterPossibleCallback) {
11663
- return;
11664
- }
11665
-
11666
- return await replay.eventBuffer.addEvent(eventAfterPossibleCallback);
11667
- } catch (error) {
11668
- (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
11669
- await replay.stop('addEvent');
11670
-
11671
- const client = getCurrentHub().getClient();
11672
-
11673
- if (client) {
11674
- client.recordDroppedEvent('internal_sdk_error', 'replay');
11675
- }
11676
- }
11677
- }
11678
-
11679
- /**
11680
- * Add a breadcrumb event to replay.
11681
- */
11682
- function addBreadcrumbEvent(replay, breadcrumb) {
11683
- if (breadcrumb.category === 'sentry.transaction') {
11684
- return;
11685
- }
11686
-
11687
- if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
11688
- replay.triggerUserActivity();
11689
- } else {
11690
- replay.checkAndHandleExpiredSession();
11691
- }
11692
-
11693
- replay.addUpdate(() => {
11694
- void addEvent(replay, {
11695
- type: EventType$1.Custom,
11696
- // TODO: We were converting from ms to seconds for breadcrumbs, spans,
11697
- // but maybe we should just keep them as milliseconds
11698
- timestamp: (breadcrumb.timestamp || 0) * 1000,
11699
- data: {
11700
- tag: 'breadcrumb',
11701
- // normalize to max. 10 depth and 1_000 properties per object
11702
- payload: normalize(breadcrumb, 10, 1000),
11703
- },
11704
- });
11705
-
11706
- // Do not flush after console log messages
11707
- return breadcrumb.category === 'console';
11708
- });
11709
- }
11710
-
11711
- /**
11712
- * Detect a slow click on a button/a tag,
11713
- * and potentially create a corresponding breadcrumb.
11714
- */
11715
- function detectSlowClick(
11716
- replay,
11717
- config,
11718
- clickBreadcrumb,
11719
- node,
11720
- ) {
11721
- if (ignoreElement(node, config)) {
11722
- return;
11723
- }
11724
-
11725
- /*
11726
- We consider a slow click a click on a button/a, which does not trigger one of:
11727
- - DOM mutation
11728
- - Scroll (within 100ms)
11729
- Within the given threshold time.
11730
- After time timeout time, we stop listening and mark it as a slow click anyhow.
11731
- */
11732
-
11733
- let cleanup = () => {
11734
- // replaced further down
11735
- };
11736
-
11737
- // After timeout time, def. consider this a slow click, and stop watching for mutations
11738
- const timeout = setTimeout(() => {
11739
- handleSlowClick(replay, clickBreadcrumb, config.timeout, 'timeout');
11740
- cleanup();
11741
- }, config.timeout);
11742
-
11743
- const mutationHandler = () => {
11744
- maybeHandleSlowClick(replay, clickBreadcrumb, config.threshold, config.timeout, 'mutation');
11745
- cleanup();
11746
- };
11747
-
11748
- const scrollHandler = () => {
11749
- maybeHandleSlowClick(replay, clickBreadcrumb, config.scrollTimeout, config.timeout, 'scroll');
11750
- cleanup();
11751
- };
11752
-
11753
- const obs = new MutationObserver(mutationHandler);
11754
-
11755
- obs.observe(WINDOW.document.documentElement, {
11756
- attributes: true,
11757
- characterData: true,
11758
- childList: true,
11759
- subtree: true,
11760
- });
11761
-
11762
- WINDOW.addEventListener('scroll', scrollHandler);
11763
-
11764
- // Stop listening to scroll timeouts early
11765
- const scrollTimeout = setTimeout(() => {
11766
- WINDOW.removeEventListener('scroll', scrollHandler);
11767
- }, config.scrollTimeout);
11768
-
11769
- cleanup = () => {
11770
- clearTimeout(timeout);
11771
- clearTimeout(scrollTimeout);
11772
- obs.disconnect();
11773
- WINDOW.removeEventListener('scroll', scrollHandler);
11774
- };
11775
- }
11776
-
11777
- function maybeHandleSlowClick(
11778
- replay,
11779
- clickBreadcrumb,
11780
- threshold,
11781
- timeout,
11782
- endReason,
11783
- ) {
11784
- const now = Date.now();
11785
- const timeAfterClickMs = now - clickBreadcrumb.timestamp * 1000;
11786
-
11787
- if (timeAfterClickMs > threshold) {
11788
- handleSlowClick(replay, clickBreadcrumb, Math.min(timeAfterClickMs, timeout), endReason);
11789
- return true;
11790
- }
11791
-
11792
- return false;
11793
- }
11794
-
11795
- function handleSlowClick(
11796
- replay,
11797
- clickBreadcrumb,
11798
- timeAfterClickMs,
11799
- endReason,
11800
- ) {
11801
- const breadcrumb = {
11802
- message: clickBreadcrumb.message,
11803
- timestamp: clickBreadcrumb.timestamp,
11804
- category: 'ui.slowClickDetected',
11805
- data: {
11806
- ...clickBreadcrumb.data,
11807
- url: WINDOW.location.href,
11808
- // TODO FN: add parametrized route, when possible
11809
- timeAfterClickMs,
11810
- endReason,
11811
- },
11812
- };
11813
-
11814
- addBreadcrumbEvent(replay, breadcrumb);
11815
- }
11816
-
11817
- const SLOW_CLICK_IGNORE_TAGS = ['SELECT', 'OPTION'];
11818
-
11819
- function ignoreElement(node, config) {
11820
- // If <input> tag, we only want to consider input[type='submit'] & input[type='button']
11821
- if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
11822
- return true;
11823
- }
11824
-
11825
- if (SLOW_CLICK_IGNORE_TAGS.includes(node.tagName)) {
11826
- return true;
11827
- }
11828
-
11829
- // If <a> tag, detect special variants that may not lead to an action
11830
- // If target !== _self, we may open the link somewhere else, which would lead to no action
11831
- // Also, when downloading a file, we may not leave the page, but still not trigger an action
11832
- if (
11833
- node.tagName === 'A' &&
11834
- (node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
11835
- ) {
11836
- return true;
11837
- }
11838
-
11839
- if (config.ignoreSelector && node.matches(config.ignoreSelector)) {
11840
- return true;
11841
- }
11842
-
11843
- return false;
11844
- }
11845
-
11846
- // Note that these are the serialized attributes and not attributes directly on
11847
- // the DOM Node. Attributes we are interested in:
11848
- const ATTRIBUTES_TO_RECORD = new Set([
11849
- 'id',
11850
- 'class',
11851
- 'aria-label',
11852
- 'role',
11853
- 'name',
11854
- 'alt',
11855
- 'title',
11856
- 'data-test-id',
11857
- 'data-testid',
11858
- ]);
11859
-
11860
- /**
11861
- * Inclusion list of attributes that we want to record from the DOM element
11862
- */
11863
- function getAttributesToRecord(attributes) {
11864
- const obj = {};
11865
- for (const key in attributes) {
11866
- if (ATTRIBUTES_TO_RECORD.has(key)) {
11867
- let normalizedKey = key;
11868
-
11869
- if (key === 'data-testid' || key === 'data-test-id') {
11870
- normalizedKey = 'testId';
11871
- }
11872
-
11873
- obj[normalizedKey] = attributes[key];
11874
- }
11875
- }
11876
-
11877
- return obj;
11878
- }
11879
-
11880
- const handleDomListener = (
11881
- replay,
11882
- ) => {
11883
- const slowClickExperiment = replay.getOptions()._experiments.slowClicks;
11884
-
11885
- const slowClickConfig = slowClickExperiment
11886
- ? {
11887
- threshold: slowClickExperiment.threshold,
11888
- timeout: slowClickExperiment.timeout,
11889
- scrollTimeout: slowClickExperiment.scrollTimeout,
11890
- ignoreSelector: slowClickExperiment.ignoreSelectors ? slowClickExperiment.ignoreSelectors.join(',') : '',
11891
- }
11892
- : undefined;
11893
-
11894
- return (handlerData) => {
11895
- if (!replay.isEnabled()) {
11896
- return;
11897
- }
11898
-
11899
- const result = handleDom(handlerData);
11900
-
11901
- if (!result) {
11902
- return;
11903
- }
11904
-
11905
- const isClick = handlerData.name === 'click';
11906
- const event = isClick && (handlerData.event );
11907
- // Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
11908
- if (isClick && slowClickConfig && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
11909
- detectSlowClick(
11910
- replay,
11911
- slowClickConfig,
11912
- result ,
11913
- getClickTargetNode(handlerData.event) ,
11914
- );
11915
- }
11916
-
11917
- addBreadcrumbEvent(replay, result);
11918
- };
11919
- };
11920
-
11921
- /** Get the base DOM breadcrumb. */
11922
- function getBaseDomBreadcrumb(target, message) {
11923
- // `__sn` property is the serialized node created by rrweb
11924
- const serializedNode = target && isRrwebNode(target) && target.__sn.type === NodeType.Element ? target.__sn : null;
11925
-
11926
- return {
11927
- message,
11928
- data: serializedNode
11929
- ? {
11930
- nodeId: serializedNode.id,
11931
- node: {
11932
- id: serializedNode.id,
11933
- tagName: serializedNode.tagName,
11934
- textContent: target
11935
- ? Array.from(target.childNodes)
11936
- .map(
11937
- (node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
11938
- )
11939
- .filter(Boolean) // filter out empty values
11940
- .map(text => (text ).trim())
11941
- .join('')
11942
- : '',
11943
- attributes: getAttributesToRecord(serializedNode.attributes),
11944
- },
11945
- }
11946
- : {},
11947
- };
11948
- }
11949
-
11950
- /**
11951
- * An event handler to react to DOM events.
11952
- * Exported for tests.
11953
- */
11954
- function handleDom(handlerData) {
11955
- const { target, message } = getDomTarget(handlerData);
11956
-
11957
- return createBreadcrumb({
11958
- category: `ui.${handlerData.name}`,
11959
- ...getBaseDomBreadcrumb(target, message),
11960
- });
11961
- }
11962
-
11963
- function getDomTarget(handlerData) {
11964
- const isClick = handlerData.name === 'click';
11965
-
11966
- let message;
11967
- let target = null;
11968
-
11969
- // Accessing event.target can throw (see getsentry/raven-js#838, #768)
11970
- try {
11971
- target = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
11972
- message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
11973
- } catch (e) {
11974
- message = '<unknown>';
11975
- }
11976
-
11977
- return { target, message };
11978
- }
11979
-
11980
- function isRrwebNode(node) {
11981
- return '__sn' in node;
11982
- }
11983
-
11984
- function getTargetNode(event) {
11985
- if (isEventWithTarget(event)) {
11986
- return event.target ;
11987
- }
11988
-
11989
- return event;
11990
- }
11991
-
11992
- const INTERACTIVE_SELECTOR = 'button,a';
11993
-
11994
- // For clicks, we check if the target is inside of a button or link
11995
- // If so, we use this as the target instead
11996
- // This is useful because if you click on the image in <button><img></button>,
11997
- // The target will be the image, not the button, which we don't want here
11998
- function getClickTargetNode(event) {
11999
- const target = getTargetNode(event);
12000
-
12001
- if (!target || !(target instanceof Element)) {
12002
- return target;
12003
- }
12004
-
12005
- const closestInteractive = target.closest(INTERACTIVE_SELECTOR);
12006
- return closestInteractive || target;
12007
- }
12008
-
12009
- function isEventWithTarget(event) {
12010
- return typeof event === 'object' && !!event && 'target' in event;
12011
- }
12012
-
12013
- /** Handle keyboard events & create breadcrumbs. */
12014
- function handleKeyboardEvent(replay, event) {
12015
- if (!replay.isEnabled()) {
12016
- return;
12017
- }
12018
-
12019
- replay.triggerUserActivity();
12020
-
12021
- const breadcrumb = getKeyboardBreadcrumb(event);
12022
-
12023
- if (!breadcrumb) {
12024
- return;
12025
- }
12026
-
12027
- addBreadcrumbEvent(replay, breadcrumb);
12028
- }
12029
-
12030
- /** exported only for tests */
12031
- function getKeyboardBreadcrumb(event) {
12032
- const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event;
12033
-
12034
- // never capture for input fields
12035
- if (!target || isInputElement(target )) {
12036
- return null;
12037
- }
12038
-
12039
- // Note: We do not consider shift here, as that means "uppercase"
12040
- const hasModifierKey = metaKey || ctrlKey || altKey;
12041
- const isCharacterKey = key.length === 1; // other keys like Escape, Tab, etc have a longer length
12042
-
12043
- // Do not capture breadcrumb if only a word key is pressed
12044
- // This could leak e.g. user input
12045
- if (!hasModifierKey && isCharacterKey) {
12046
- return null;
12047
- }
12048
-
12049
- const message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
12050
- const baseBreadcrumb = getBaseDomBreadcrumb(target , message);
12051
-
12052
- return createBreadcrumb({
12053
- category: 'ui.keyDown',
12054
- message,
12055
- data: {
12056
- ...baseBreadcrumb.data,
12057
- metaKey,
12058
- shiftKey,
12059
- ctrlKey,
12060
- altKey,
12061
- key,
12062
- },
12063
- });
12064
- }
12065
-
12066
- function isInputElement(target) {
12067
- return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
12068
- }
12069
-
12070
11346
  const NAVIGATION_ENTRY_KEYS = [
12071
11347
  'name',
12072
11348
  'type',
@@ -12220,19 +11496,20 @@ class EventBufferArray {
12220
11496
  return this.events.length > 0;
12221
11497
  }
12222
11498
 
12223
- /** @inheritdoc */
12224
- get type() {
12225
- return 'sync';
12226
- }
12227
-
12228
11499
  /** @inheritdoc */
12229
11500
  destroy() {
12230
11501
  this.events = [];
12231
11502
  }
12232
11503
 
12233
11504
  /** @inheritdoc */
12234
- async addEvent(event) {
11505
+ async addEvent(event, isCheckout) {
11506
+ if (isCheckout) {
11507
+ this.events = [event];
11508
+ return;
11509
+ }
11510
+
12235
11511
  this.events.push(event);
11512
+ return;
12236
11513
  }
12237
11514
 
12238
11515
  /** @inheritdoc */
@@ -12246,22 +11523,6 @@ class EventBufferArray {
12246
11523
  resolve(JSON.stringify(eventsRet));
12247
11524
  });
12248
11525
  }
12249
-
12250
- /** @inheritdoc */
12251
- clear() {
12252
- this.events = [];
12253
- }
12254
-
12255
- /** @inheritdoc */
12256
- getEarliestTimestamp() {
12257
- const timestamp = this.events.map(event => event.timestamp).sort()[0];
12258
-
12259
- if (!timestamp) {
12260
- return null;
12261
- }
12262
-
12263
- return timestampToMs(timestamp);
12264
- }
12265
11526
  }
12266
11527
 
12267
11528
  /**
@@ -12369,20 +11630,11 @@ class WorkerHandler {
12369
11630
  * Exported only for testing.
12370
11631
  */
12371
11632
  class EventBufferCompressionWorker {
11633
+ /** @inheritdoc */
12372
11634
 
12373
11635
  constructor(worker) {
12374
11636
  this._worker = new WorkerHandler(worker);
12375
- this._earliestTimestamp = null;
12376
- }
12377
-
12378
- /** @inheritdoc */
12379
- get hasEvents() {
12380
- return !!this._earliestTimestamp;
12381
- }
12382
-
12383
- /** @inheritdoc */
12384
- get type() {
12385
- return 'worker';
11637
+ this.hasEvents = false;
12386
11638
  }
12387
11639
 
12388
11640
  /**
@@ -12405,10 +11657,13 @@ class EventBufferCompressionWorker {
12405
11657
  *
12406
11658
  * Returns true if event was successfuly received and processed by worker.
12407
11659
  */
12408
- addEvent(event) {
12409
- const timestamp = timestampToMs(event.timestamp);
12410
- if (!this._earliestTimestamp || timestamp < this._earliestTimestamp) {
12411
- this._earliestTimestamp = timestamp;
11660
+ async addEvent(event, isCheckout) {
11661
+ this.hasEvents = true;
11662
+
11663
+ if (isCheckout) {
11664
+ // This event is a checkout, make sure worker buffer is cleared before
11665
+ // proceeding.
11666
+ await this._clear();
12412
11667
  }
12413
11668
 
12414
11669
  return this._sendEventToWorker(event);
@@ -12421,18 +11676,6 @@ class EventBufferCompressionWorker {
12421
11676
  return this._finishRequest();
12422
11677
  }
12423
11678
 
12424
- /** @inheritdoc */
12425
- clear() {
12426
- this._earliestTimestamp = null;
12427
- // We do not wait on this, as we assume the order of messages is consistent for the worker
12428
- void this._worker.postMessage('clear');
12429
- }
12430
-
12431
- /** @inheritdoc */
12432
- getEarliestTimestamp() {
12433
- return this._earliestTimestamp;
12434
- }
12435
-
12436
11679
  /**
12437
11680
  * Send the event to the worker.
12438
11681
  */
@@ -12446,10 +11689,15 @@ class EventBufferCompressionWorker {
12446
11689
  async _finishRequest() {
12447
11690
  const response = await this._worker.postMessage('finish');
12448
11691
 
12449
- this._earliestTimestamp = null;
11692
+ this.hasEvents = false;
12450
11693
 
12451
11694
  return response;
12452
11695
  }
11696
+
11697
+ /** Clear any pending events from the worker. */
11698
+ _clear() {
11699
+ return this._worker.postMessage('clear');
11700
+ }
12453
11701
  }
12454
11702
 
12455
11703
  /**
@@ -12467,11 +11715,6 @@ class EventBufferProxy {
12467
11715
  this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded();
12468
11716
  }
12469
11717
 
12470
- /** @inheritdoc */
12471
- get type() {
12472
- return this._used.type;
12473
- }
12474
-
12475
11718
  /** @inheritDoc */
12476
11719
  get hasEvents() {
12477
11720
  return this._used.hasEvents;
@@ -12483,23 +11726,13 @@ class EventBufferProxy {
12483
11726
  this._compression.destroy();
12484
11727
  }
12485
11728
 
12486
- /** @inheritdoc */
12487
- clear() {
12488
- return this._used.clear();
12489
- }
12490
-
12491
- /** @inheritdoc */
12492
- getEarliestTimestamp() {
12493
- return this._used.getEarliestTimestamp();
12494
- }
12495
-
12496
11729
  /**
12497
11730
  * Add an event to the event buffer.
12498
11731
  *
12499
11732
  * Returns true if event was successfully added.
12500
11733
  */
12501
- addEvent(event) {
12502
- return this._used.addEvent(event);
11734
+ addEvent(event, isCheckout) {
11735
+ return this._used.addEvent(event, isCheckout);
12503
11736
  }
12504
11737
 
12505
11738
  /** @inheritDoc */
@@ -12574,31 +11807,6 @@ function createEventBuffer({ useCompression }) {
12574
11807
  return new EventBufferArray();
12575
11808
  }
12576
11809
 
12577
- /**
12578
- * Removes the session from Session Storage and unsets session in replay instance
12579
- */
12580
- function clearSession(replay) {
12581
- deleteSession();
12582
- replay.session = undefined;
12583
- }
12584
-
12585
- /**
12586
- * Deletes a session from storage
12587
- */
12588
- function deleteSession() {
12589
- const hasSessionStorage = 'sessionStorage' in WINDOW;
12590
-
12591
- if (!hasSessionStorage) {
12592
- return;
12593
- }
12594
-
12595
- try {
12596
- WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
12597
- } catch (e) {
12598
- // Ignore potential SecurityError exceptions
12599
- }
12600
- }
12601
-
12602
11810
  /**
12603
11811
  * Given an initial timestamp and an expiry duration, checks to see if current
12604
11812
  * time should be considered as expired.
@@ -12629,26 +11837,11 @@ function isSessionExpired(session, timeouts, targetTime = +new Date()) {
12629
11837
  // First, check that maximum session length has not been exceeded
12630
11838
  isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
12631
11839
  // check that the idle timeout has not been exceeded (i.e. user has
12632
- // performed an action within the last `sessionIdleExpire` ms)
12633
- isExpired(session.lastActivity, timeouts.sessionIdleExpire, targetTime)
11840
+ // performed an action within the last `idleTimeout` ms)
11841
+ isExpired(session.lastActivity, timeouts.sessionIdle, targetTime)
12634
11842
  );
12635
11843
  }
12636
11844
 
12637
- /**
12638
- * Given a sample rate, returns true if replay should be sampled.
12639
- *
12640
- * 1.0 = 100% sampling
12641
- * 0.0 = 0% sampling
12642
- */
12643
- function isSampled(sampleRate) {
12644
- if (sampleRate === undefined) {
12645
- return false;
12646
- }
12647
-
12648
- // Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
12649
- return Math.random() < sampleRate;
12650
- }
12651
-
12652
11845
  /**
12653
11846
  * Save a session to session storage.
12654
11847
  */
@@ -12665,6 +11858,21 @@ function saveSession(session) {
12665
11858
  }
12666
11859
  }
12667
11860
 
11861
+ /**
11862
+ * Given a sample rate, returns true if replay should be sampled.
11863
+ *
11864
+ * 1.0 = 100% sampling
11865
+ * 0.0 = 0% sampling
11866
+ */
11867
+ function isSampled(sampleRate) {
11868
+ if (sampleRate === undefined) {
11869
+ return false;
11870
+ }
11871
+
11872
+ // Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
11873
+ return Math.random() < sampleRate;
11874
+ }
11875
+
12668
11876
  /**
12669
11877
  * Get a session with defaults & applied sampling.
12670
11878
  */
@@ -12683,15 +11891,14 @@ function makeSession(session) {
12683
11891
  lastActivity,
12684
11892
  segmentId,
12685
11893
  sampled,
12686
- shouldRefresh: true,
12687
11894
  };
12688
11895
  }
12689
11896
 
12690
11897
  /**
12691
11898
  * Get the sampled status for a session based on sample rates & current sampled status.
12692
11899
  */
12693
- function getSessionSampleType(sessionSampleRate, allowBuffering) {
12694
- return isSampled(sessionSampleRate) ? 'session' : allowBuffering ? 'buffer' : false;
11900
+ function getSessionSampleType(sessionSampleRate, errorSampleRate) {
11901
+ return isSampled(sessionSampleRate) ? 'session' : isSampled(errorSampleRate) ? 'error' : false;
12695
11902
  }
12696
11903
 
12697
11904
  /**
@@ -12699,8 +11906,8 @@ function getSessionSampleType(sessionSampleRate, allowBuffering) {
12699
11906
  * that all replays will be saved to as attachments. Currently, we only expect
12700
11907
  * one of these Sentry events per "replay session".
12701
11908
  */
12702
- function createSession({ sessionSampleRate, allowBuffering, stickySession = false }) {
12703
- const sampled = getSessionSampleType(sessionSampleRate, allowBuffering);
11909
+ function createSession({ sessionSampleRate, errorSampleRate, stickySession = false }) {
11910
+ const sampled = getSessionSampleType(sessionSampleRate, errorSampleRate);
12704
11911
  const session = makeSession({
12705
11912
  sampled,
12706
11913
  });
@@ -12748,7 +11955,7 @@ function getSession({
12748
11955
  currentSession,
12749
11956
  stickySession,
12750
11957
  sessionSampleRate,
12751
- allowBuffering,
11958
+ errorSampleRate,
12752
11959
  }) {
12753
11960
  // If session exists and is passed, use it instead of always hitting session storage
12754
11961
  const session = currentSession || (stickySession && fetchSession());
@@ -12761,9 +11968,8 @@ function getSession({
12761
11968
 
12762
11969
  if (!isExpired) {
12763
11970
  return { type: 'saved', session };
12764
- } else if (!session.shouldRefresh) {
12765
- // In this case, stop
12766
- // This is the case if we have an error session that is completed (=triggered an error)
11971
+ } else if (session.sampled === 'error') {
11972
+ // Error samples should not be re-created when expired, but instead we stop when the replay is done
12767
11973
  const discardedSession = makeSession({ sampled: false });
12768
11974
  return { type: 'new', session: discardedSession };
12769
11975
  } else {
@@ -12775,12 +11981,65 @@ function getSession({
12775
11981
  const newSession = createSession({
12776
11982
  stickySession,
12777
11983
  sessionSampleRate,
12778
- allowBuffering,
11984
+ errorSampleRate,
12779
11985
  });
12780
11986
 
12781
11987
  return { type: 'new', session: newSession };
12782
11988
  }
12783
11989
 
11990
+ /**
11991
+ * Add an event to the event buffer.
11992
+ * `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
11993
+ */
11994
+ async function addEvent(
11995
+ replay,
11996
+ event,
11997
+ isCheckout,
11998
+ ) {
11999
+ if (!replay.eventBuffer) {
12000
+ // This implies that `_isEnabled` is false
12001
+ return null;
12002
+ }
12003
+
12004
+ if (replay.isPaused()) {
12005
+ // Do not add to event buffer when recording is paused
12006
+ return null;
12007
+ }
12008
+
12009
+ // TODO: sadness -- we will want to normalize timestamps to be in ms -
12010
+ // requires coordination with frontend
12011
+ const isMs = event.timestamp > 9999999999;
12012
+ const timestampInMs = isMs ? event.timestamp : event.timestamp * 1000;
12013
+
12014
+ // Throw out events that happen more than 5 minutes ago. This can happen if
12015
+ // page has been left open and idle for a long period of time and user
12016
+ // comes back to trigger a new session. The performance entries rely on
12017
+ // `performance.timeOrigin`, which is when the page first opened.
12018
+ if (timestampInMs + replay.timeouts.sessionIdle < Date.now()) {
12019
+ return null;
12020
+ }
12021
+
12022
+ // Only record earliest event if a new session was created, otherwise it
12023
+ // shouldn't be relevant
12024
+ const earliestEvent = replay.getContext().earliestEvent;
12025
+ if (replay.session && replay.session.segmentId === 0 && (!earliestEvent || timestampInMs < earliestEvent)) {
12026
+ replay.getContext().earliestEvent = timestampInMs;
12027
+ }
12028
+
12029
+ try {
12030
+ return await replay.eventBuffer.addEvent(event, isCheckout);
12031
+ } catch (error) {
12032
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
12033
+ replay.stop('addEvent');
12034
+
12035
+ const client = getCurrentHub().getClient();
12036
+
12037
+ if (client) {
12038
+ client.recordDroppedEvent('internal_sdk_error', 'replay');
12039
+ }
12040
+ }
12041
+ }
12042
+
12784
12043
  /** If the event is an error event */
12785
12044
  function isErrorEvent(event) {
12786
12045
  return !event.type;
@@ -12830,21 +12089,31 @@ function handleAfterSendEvent(replay) {
12830
12089
  return;
12831
12090
  }
12832
12091
 
12833
- // Add error to list of errorIds of replay. This is ok to do even if not
12834
- // sampled because context will get reset at next checkout.
12835
- // XXX: There is also a race condition where it's possible to capture an
12836
- // error to Sentry before Replay SDK has loaded, but response returns after
12837
- // it was loaded, and this gets called.
12092
+ // Add error to list of errorIds of replay
12838
12093
  if (event.event_id) {
12839
12094
  replay.getContext().errorIds.add(event.event_id);
12840
12095
  }
12841
12096
 
12842
- // If error event is tagged with replay id it means it was sampled (when in buffer mode)
12097
+ // Trigger error recording
12843
12098
  // Need to be very careful that this does not cause an infinite loop
12844
- if (replay.recordingMode === 'buffer' && event.tags && event.tags.replayId) {
12845
- setTimeout(() => {
12846
- // Capture current event buffer as new replay
12847
- void replay.sendBufferedReplayOrFlush();
12099
+ if (
12100
+ replay.recordingMode === 'error' &&
12101
+ event.exception &&
12102
+ event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing
12103
+ ) {
12104
+ setTimeout(async () => {
12105
+ // Allow flush to complete before resuming as a session recording, otherwise
12106
+ // the checkout from `startRecording` may be included in the payload.
12107
+ // Prefer to keep the error replay as a separate (and smaller) segment
12108
+ // than the session replay.
12109
+ await replay.flushImmediate();
12110
+
12111
+ if (replay.stopRecording()) {
12112
+ // Reset all "capture on error" configuration before
12113
+ // starting a new recording
12114
+ replay.recordingMode = 'session';
12115
+ replay.startRecording();
12116
+ }
12848
12117
  });
12849
12118
  }
12850
12119
  };
@@ -12866,6 +12135,166 @@ function isBaseTransportSend() {
12866
12135
  );
12867
12136
  }
12868
12137
 
12138
+ var NodeType;
12139
+ (function (NodeType) {
12140
+ NodeType[NodeType["Document"] = 0] = "Document";
12141
+ NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
12142
+ NodeType[NodeType["Element"] = 2] = "Element";
12143
+ NodeType[NodeType["Text"] = 3] = "Text";
12144
+ NodeType[NodeType["CDATA"] = 4] = "CDATA";
12145
+ NodeType[NodeType["Comment"] = 5] = "Comment";
12146
+ })(NodeType || (NodeType = {}));
12147
+
12148
+ /**
12149
+ * Create a breadcrumb for a replay.
12150
+ */
12151
+ function createBreadcrumb(
12152
+ breadcrumb,
12153
+ ) {
12154
+ return {
12155
+ timestamp: Date.now() / 1000,
12156
+ type: 'default',
12157
+ ...breadcrumb,
12158
+ };
12159
+ }
12160
+
12161
+ /**
12162
+ * Add a breadcrumb event to replay.
12163
+ */
12164
+ function addBreadcrumbEvent(replay, breadcrumb) {
12165
+ if (breadcrumb.category === 'sentry.transaction') {
12166
+ return;
12167
+ }
12168
+
12169
+ if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
12170
+ replay.triggerUserActivity();
12171
+ } else {
12172
+ replay.checkAndHandleExpiredSession();
12173
+ }
12174
+
12175
+ replay.addUpdate(() => {
12176
+ void addEvent(replay, {
12177
+ type: EventType.Custom,
12178
+ // TODO: We were converting from ms to seconds for breadcrumbs, spans,
12179
+ // but maybe we should just keep them as milliseconds
12180
+ timestamp: (breadcrumb.timestamp || 0) * 1000,
12181
+ data: {
12182
+ tag: 'breadcrumb',
12183
+ payload: breadcrumb,
12184
+ },
12185
+ });
12186
+
12187
+ // Do not flush after console log messages
12188
+ return breadcrumb.category === 'console';
12189
+ });
12190
+ }
12191
+
12192
+ // Note that these are the serialized attributes and not attributes directly on
12193
+ // the DOM Node. Attributes we are interested in:
12194
+ const ATTRIBUTES_TO_RECORD = new Set([
12195
+ 'id',
12196
+ 'class',
12197
+ 'aria-label',
12198
+ 'role',
12199
+ 'name',
12200
+ 'alt',
12201
+ 'title',
12202
+ 'data-test-id',
12203
+ 'data-testid',
12204
+ ]);
12205
+
12206
+ /**
12207
+ * Inclusion list of attributes that we want to record from the DOM element
12208
+ */
12209
+ function getAttributesToRecord(attributes) {
12210
+ const obj = {};
12211
+ for (const key in attributes) {
12212
+ if (ATTRIBUTES_TO_RECORD.has(key)) {
12213
+ let normalizedKey = key;
12214
+
12215
+ if (key === 'data-testid' || key === 'data-test-id') {
12216
+ normalizedKey = 'testId';
12217
+ }
12218
+
12219
+ obj[normalizedKey] = attributes[key];
12220
+ }
12221
+ }
12222
+
12223
+ return obj;
12224
+ }
12225
+
12226
+ const handleDomListener =
12227
+ (replay) =>
12228
+ (handlerData) => {
12229
+ if (!replay.isEnabled()) {
12230
+ return;
12231
+ }
12232
+
12233
+ const result = handleDom(handlerData);
12234
+
12235
+ if (!result) {
12236
+ return;
12237
+ }
12238
+
12239
+ addBreadcrumbEvent(replay, result);
12240
+ };
12241
+
12242
+ /**
12243
+ * An event handler to react to DOM events.
12244
+ */
12245
+ function handleDom(handlerData) {
12246
+ let target;
12247
+ let targetNode;
12248
+
12249
+ // Accessing event.target can throw (see getsentry/raven-js#838, #768)
12250
+ try {
12251
+ targetNode = getTargetNode(handlerData);
12252
+ target = htmlTreeAsString(targetNode);
12253
+ } catch (e) {
12254
+ target = '<unknown>';
12255
+ }
12256
+
12257
+ // `__sn` property is the serialized node created by rrweb
12258
+ const serializedNode =
12259
+ targetNode && '__sn' in targetNode && targetNode.__sn.type === NodeType.Element ? targetNode.__sn : null;
12260
+
12261
+ return createBreadcrumb({
12262
+ category: `ui.${handlerData.name}`,
12263
+ message: target,
12264
+ data: serializedNode
12265
+ ? {
12266
+ nodeId: serializedNode.id,
12267
+ node: {
12268
+ id: serializedNode.id,
12269
+ tagName: serializedNode.tagName,
12270
+ textContent: targetNode
12271
+ ? Array.from(targetNode.childNodes)
12272
+ .map(
12273
+ (node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
12274
+ )
12275
+ .filter(Boolean) // filter out empty values
12276
+ .map(text => (text ).trim())
12277
+ .join('')
12278
+ : '',
12279
+ attributes: getAttributesToRecord(serializedNode.attributes),
12280
+ },
12281
+ }
12282
+ : {},
12283
+ });
12284
+ }
12285
+
12286
+ function getTargetNode(handlerData) {
12287
+ if (isEventWithTarget(handlerData.event)) {
12288
+ return handlerData.event.target;
12289
+ }
12290
+
12291
+ return handlerData.event;
12292
+ }
12293
+
12294
+ function isEventWithTarget(event) {
12295
+ return !!(event ).target;
12296
+ }
12297
+
12869
12298
  /**
12870
12299
  * Returns true if we think the given event is an error originating inside of rrweb.
12871
12300
  */
@@ -12889,30 +12318,6 @@ function isRrwebError(event, hint) {
12889
12318
  });
12890
12319
  }
12891
12320
 
12892
- /**
12893
- * Determine if event should be sampled (only applies in buffer mode).
12894
- * When an event is captured by `hanldleGlobalEvent`, when in buffer mode
12895
- * we determine if we want to sample the error or not.
12896
- */
12897
- function shouldSampleForBufferEvent(replay, event) {
12898
- if (replay.recordingMode !== 'buffer') {
12899
- return false;
12900
- }
12901
-
12902
- // ignore this error because otherwise we could loop indefinitely with
12903
- // trying to capture replay and failing
12904
- if (event.message === UNABLE_TO_SEND_REPLAY) {
12905
- return false;
12906
- }
12907
-
12908
- // Require the event to be an error event & to have an exception
12909
- if (!event.exception || event.type) {
12910
- return false;
12911
- }
12912
-
12913
- return isSampled(replay.getOptions().errorSampleRate);
12914
- }
12915
-
12916
12321
  /**
12917
12322
  * Returns a listener to be added to `addGlobalEventProcessor(listener)`.
12918
12323
  */
@@ -12942,16 +12347,8 @@ function handleGlobalEventListener(
12942
12347
  return null;
12943
12348
  }
12944
12349
 
12945
- // When in buffer mode, we decide to sample here.
12946
- // Later, in `handleAfterSendEvent`, if the replayId is set, we know that we sampled
12947
- // And convert the buffer session to a full session
12948
- const isErrorEventSampled = shouldSampleForBufferEvent(replay, event);
12949
-
12950
- // Tag errors if it has been sampled in buffer mode, or if it is session mode
12951
- // Only tag transactions if in session mode
12952
- const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session';
12953
-
12954
- if (shouldTagReplayId) {
12350
+ // Only tag transactions with replayId if not waiting for an error
12351
+ if (isErrorEvent(event) || (isTransactionEvent(event) && replay.recordingMode === 'session')) {
12955
12352
  event.tags = { ...event.tags, replayId: replay.getSessionId() };
12956
12353
  }
12957
12354
 
@@ -13001,7 +12398,7 @@ function createPerformanceSpans(
13001
12398
  ) {
13002
12399
  return entries.map(({ type, start, end, name, data }) =>
13003
12400
  addEvent(replay, {
13004
- type: EventType$1.Custom,
12401
+ type: EventType.Custom,
13005
12402
  timestamp: start,
13006
12403
  data: {
13007
12404
  tag: 'performanceSpan',
@@ -13150,14 +12547,12 @@ function handleFetchSpanListener(replay) {
13150
12547
  function handleXhr(handlerData) {
13151
12548
  const { startTimestamp, endTimestamp, xhr } = handlerData;
13152
12549
 
13153
- const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];
13154
-
13155
- if (!startTimestamp || !endTimestamp || !sentryXhrData) {
12550
+ if (!startTimestamp || !endTimestamp || !xhr.__sentry_xhr__) {
13156
12551
  return null;
13157
12552
  }
13158
12553
 
13159
12554
  // This is only used as a fallback, so we know the body sizes are never set here
13160
- const { method, url, status_code: statusCode } = sentryXhrData;
12555
+ const { method, url, status_code: statusCode } = xhr.__sentry_xhr__;
13161
12556
 
13162
12557
  if (url === undefined) {
13163
12558
  return null;
@@ -13190,393 +12585,6 @@ function handleXhrSpanListener(replay) {
13190
12585
  };
13191
12586
  }
13192
12587
 
13193
- const OBJ = 10;
13194
- const OBJ_KEY = 11;
13195
- const OBJ_KEY_STR = 12;
13196
- const OBJ_VAL = 13;
13197
- const OBJ_VAL_STR = 14;
13198
- const OBJ_VAL_COMPLETED = 15;
13199
-
13200
- const ARR = 20;
13201
- const ARR_VAL = 21;
13202
- const ARR_VAL_STR = 22;
13203
- const ARR_VAL_COMPLETED = 23;
13204
-
13205
- const ALLOWED_PRIMITIVES = ['true', 'false', 'null'];
13206
-
13207
- /**
13208
- * Complete an incomplete JSON string.
13209
- * This will ensure that the last element always has a `"~~"` to indicate it was truncated.
13210
- * For example, `[1,2,` will be completed to `[1,2,"~~"]`
13211
- * and `{"aa":"b` will be completed to `{"aa":"b~~"}`
13212
- */
13213
- function completeJson(incompleteJson, stack) {
13214
- if (!stack.length) {
13215
- return incompleteJson;
13216
- }
13217
-
13218
- let json = incompleteJson;
13219
-
13220
- // Most checks are only needed for the last step in the stack
13221
- const lastPos = stack.length - 1;
13222
- const lastStep = stack[lastPos];
13223
-
13224
- json = _fixLastStep(json, lastStep);
13225
-
13226
- // Complete remaining steps - just add closing brackets
13227
- for (let i = lastPos; i >= 0; i--) {
13228
- const step = stack[i];
13229
-
13230
- switch (step) {
13231
- case OBJ:
13232
- json = `${json}}`;
13233
- break;
13234
- case ARR:
13235
- json = `${json}]`;
13236
- break;
13237
- }
13238
- }
13239
-
13240
- return json;
13241
- }
13242
-
13243
- function _fixLastStep(json, lastStep) {
13244
- switch (lastStep) {
13245
- // Object cases
13246
- case OBJ:
13247
- return `${json}"~~":"~~"`;
13248
- case OBJ_KEY:
13249
- return `${json}:"~~"`;
13250
- case OBJ_KEY_STR:
13251
- return `${json}~~":"~~"`;
13252
- case OBJ_VAL:
13253
- return _maybeFixIncompleteObjValue(json);
13254
- case OBJ_VAL_STR:
13255
- return `${json}~~"`;
13256
- case OBJ_VAL_COMPLETED:
13257
- return `${json},"~~":"~~"`;
13258
-
13259
- // Array cases
13260
- case ARR:
13261
- return `${json}"~~"`;
13262
- case ARR_VAL:
13263
- return _maybeFixIncompleteArrValue(json);
13264
- case ARR_VAL_STR:
13265
- return `${json}~~"`;
13266
- case ARR_VAL_COMPLETED:
13267
- return `${json},"~~"`;
13268
- }
13269
-
13270
- return json;
13271
- }
13272
-
13273
- function _maybeFixIncompleteArrValue(json) {
13274
- const pos = _findLastArrayDelimiter(json);
13275
-
13276
- if (pos > -1) {
13277
- const part = json.slice(pos + 1);
13278
-
13279
- if (ALLOWED_PRIMITIVES.includes(part.trim())) {
13280
- return `${json},"~~"`;
13281
- }
13282
-
13283
- // Everything else is replaced with `"~~"`
13284
- return `${json.slice(0, pos + 1)}"~~"`;
13285
- }
13286
-
13287
- // fallback, this shouldn't happen, to be save
13288
- return json;
13289
- }
13290
-
13291
- function _findLastArrayDelimiter(json) {
13292
- for (let i = json.length - 1; i >= 0; i--) {
13293
- const char = json[i];
13294
-
13295
- if (char === ',' || char === '[') {
13296
- return i;
13297
- }
13298
- }
13299
-
13300
- return -1;
13301
- }
13302
-
13303
- function _maybeFixIncompleteObjValue(json) {
13304
- const startPos = json.lastIndexOf(':');
13305
-
13306
- const part = json.slice(startPos + 1);
13307
-
13308
- if (ALLOWED_PRIMITIVES.includes(part.trim())) {
13309
- return `${json},"~~":"~~"`;
13310
- }
13311
-
13312
- // Everything else is replaced with `"~~"`
13313
- // This also means we do not have incomplete numbers, e.g `[1` is replaced with `["~~"]`
13314
- return `${json.slice(0, startPos + 1)}"~~"`;
13315
- }
13316
-
13317
- /**
13318
- * Evaluate an (incomplete) JSON string.
13319
- */
13320
- function evaluateJson(json) {
13321
- const stack = [];
13322
-
13323
- for (let pos = 0; pos < json.length; pos++) {
13324
- _evaluateJsonPos(stack, json, pos);
13325
- }
13326
-
13327
- return stack;
13328
- }
13329
-
13330
- function _evaluateJsonPos(stack, json, pos) {
13331
- const curStep = stack[stack.length - 1];
13332
-
13333
- const char = json[pos];
13334
-
13335
- const whitespaceRegex = /\s/;
13336
-
13337
- if (whitespaceRegex.test(char)) {
13338
- return;
13339
- }
13340
-
13341
- if (char === '"' && !_isEscaped(json, pos)) {
13342
- _handleQuote(stack, curStep);
13343
- return;
13344
- }
13345
-
13346
- switch (char) {
13347
- case '{':
13348
- _handleObj(stack, curStep);
13349
- break;
13350
- case '[':
13351
- _handleArr(stack, curStep);
13352
- break;
13353
- case ':':
13354
- _handleColon(stack, curStep);
13355
- break;
13356
- case ',':
13357
- _handleComma(stack, curStep);
13358
- break;
13359
- case '}':
13360
- _handleObjClose(stack, curStep);
13361
- break;
13362
- case ']':
13363
- _handleArrClose(stack, curStep);
13364
- break;
13365
- }
13366
- }
13367
-
13368
- function _handleQuote(stack, curStep) {
13369
- // End of obj value
13370
- if (curStep === OBJ_VAL_STR) {
13371
- stack.pop();
13372
- stack.push(OBJ_VAL_COMPLETED);
13373
- return;
13374
- }
13375
-
13376
- // End of arr value
13377
- if (curStep === ARR_VAL_STR) {
13378
- stack.pop();
13379
- stack.push(ARR_VAL_COMPLETED);
13380
- return;
13381
- }
13382
-
13383
- // Start of obj value
13384
- if (curStep === OBJ_VAL) {
13385
- stack.push(OBJ_VAL_STR);
13386
- return;
13387
- }
13388
-
13389
- // Start of arr value
13390
- if (curStep === ARR_VAL) {
13391
- stack.push(ARR_VAL_STR);
13392
- return;
13393
- }
13394
-
13395
- // Start of obj key
13396
- if (curStep === OBJ) {
13397
- stack.push(OBJ_KEY_STR);
13398
- return;
13399
- }
13400
-
13401
- // End of obj key
13402
- if (curStep === OBJ_KEY_STR) {
13403
- stack.pop();
13404
- stack.push(OBJ_KEY);
13405
- return;
13406
- }
13407
- }
13408
-
13409
- function _handleObj(stack, curStep) {
13410
- // Initial object
13411
- if (!curStep) {
13412
- stack.push(OBJ);
13413
- return;
13414
- }
13415
-
13416
- // New object as obj value
13417
- if (curStep === OBJ_VAL) {
13418
- stack.push(OBJ);
13419
- return;
13420
- }
13421
-
13422
- // New object as array element
13423
- if (curStep === ARR_VAL) {
13424
- stack.push(OBJ);
13425
- }
13426
-
13427
- // New object as first array element
13428
- if (curStep === ARR) {
13429
- stack.push(OBJ);
13430
- return;
13431
- }
13432
- }
13433
-
13434
- function _handleArr(stack, curStep) {
13435
- // Initial array
13436
- if (!curStep) {
13437
- stack.push(ARR);
13438
- stack.push(ARR_VAL);
13439
- return;
13440
- }
13441
-
13442
- // New array as obj value
13443
- if (curStep === OBJ_VAL) {
13444
- stack.push(ARR);
13445
- stack.push(ARR_VAL);
13446
- return;
13447
- }
13448
-
13449
- // New array as array element
13450
- if (curStep === ARR_VAL) {
13451
- stack.push(ARR);
13452
- stack.push(ARR_VAL);
13453
- }
13454
-
13455
- // New array as first array element
13456
- if (curStep === ARR) {
13457
- stack.push(ARR);
13458
- stack.push(ARR_VAL);
13459
- return;
13460
- }
13461
- }
13462
-
13463
- function _handleColon(stack, curStep) {
13464
- if (curStep === OBJ_KEY) {
13465
- stack.pop();
13466
- stack.push(OBJ_VAL);
13467
- }
13468
- }
13469
-
13470
- function _handleComma(stack, curStep) {
13471
- // Comma after obj value
13472
- if (curStep === OBJ_VAL) {
13473
- stack.pop();
13474
- return;
13475
- }
13476
- if (curStep === OBJ_VAL_COMPLETED) {
13477
- // Pop OBJ_VAL_COMPLETED & OBJ_VAL
13478
- stack.pop();
13479
- stack.pop();
13480
- return;
13481
- }
13482
-
13483
- // Comma after arr value
13484
- if (curStep === ARR_VAL) {
13485
- // do nothing - basically we'd pop ARR_VAL but add it right back
13486
- return;
13487
- }
13488
-
13489
- if (curStep === ARR_VAL_COMPLETED) {
13490
- // Pop ARR_VAL_COMPLETED
13491
- stack.pop();
13492
-
13493
- // basically we'd pop ARR_VAL but add it right back
13494
- return;
13495
- }
13496
- }
13497
-
13498
- function _handleObjClose(stack, curStep) {
13499
- // Empty object {}
13500
- if (curStep === OBJ) {
13501
- stack.pop();
13502
- }
13503
-
13504
- // Object with element
13505
- if (curStep === OBJ_VAL) {
13506
- // Pop OBJ_VAL, OBJ
13507
- stack.pop();
13508
- stack.pop();
13509
- }
13510
-
13511
- // Obj with element
13512
- if (curStep === OBJ_VAL_COMPLETED) {
13513
- // Pop OBJ_VAL_COMPLETED, OBJ_VAL, OBJ
13514
- stack.pop();
13515
- stack.pop();
13516
- stack.pop();
13517
- }
13518
-
13519
- // if was obj value, complete it
13520
- if (stack[stack.length - 1] === OBJ_VAL) {
13521
- stack.push(OBJ_VAL_COMPLETED);
13522
- }
13523
-
13524
- // if was arr value, complete it
13525
- if (stack[stack.length - 1] === ARR_VAL) {
13526
- stack.push(ARR_VAL_COMPLETED);
13527
- }
13528
- }
13529
-
13530
- function _handleArrClose(stack, curStep) {
13531
- // Empty array []
13532
- if (curStep === ARR) {
13533
- stack.pop();
13534
- }
13535
-
13536
- // Array with element
13537
- if (curStep === ARR_VAL) {
13538
- // Pop ARR_VAL, ARR
13539
- stack.pop();
13540
- stack.pop();
13541
- }
13542
-
13543
- // Array with element
13544
- if (curStep === ARR_VAL_COMPLETED) {
13545
- // Pop ARR_VAL_COMPLETED, ARR_VAL, ARR
13546
- stack.pop();
13547
- stack.pop();
13548
- stack.pop();
13549
- }
13550
-
13551
- // if was obj value, complete it
13552
- if (stack[stack.length - 1] === OBJ_VAL) {
13553
- stack.push(OBJ_VAL_COMPLETED);
13554
- }
13555
-
13556
- // if was arr value, complete it
13557
- if (stack[stack.length - 1] === ARR_VAL) {
13558
- stack.push(ARR_VAL_COMPLETED);
13559
- }
13560
- }
13561
-
13562
- function _isEscaped(str, pos) {
13563
- const previousChar = str[pos - 1];
13564
-
13565
- return previousChar === '\\' && !_isEscaped(str, pos - 1);
13566
- }
13567
-
13568
- /* eslint-disable max-lines */
13569
-
13570
- /**
13571
- * Takes an incomplete JSON string, and returns a hopefully valid JSON string.
13572
- * Note that this _can_ fail, so you should check the return value is valid JSON.
13573
- */
13574
- function fixJson(incompleteJson) {
13575
- const stack = evaluateJson(incompleteJson);
13576
-
13577
- return completeJson(incompleteJson, stack);
13578
- }
13579
-
13580
12588
  /** Get the size of a body. */
13581
12589
  function getBodySize(
13582
12590
  body,
@@ -13670,68 +12678,51 @@ function makeNetworkReplayBreadcrumb(
13670
12678
  return result;
13671
12679
  }
13672
12680
 
13673
- /** Build the request or response part of a replay network breadcrumb that was skipped. */
13674
- function buildSkippedNetworkRequestOrResponse(bodySize) {
13675
- return {
13676
- headers: {},
13677
- size: bodySize,
13678
- _meta: {
13679
- warnings: ['URL_SKIPPED'],
13680
- },
13681
- };
12681
+ /** Get either a JSON network body, or a text representation. */
12682
+ function getNetworkBody(bodyText) {
12683
+ if (!bodyText) {
12684
+ return;
12685
+ }
12686
+
12687
+ try {
12688
+ return JSON.parse(bodyText);
12689
+ } catch (e2) {
12690
+ // return text
12691
+ }
12692
+
12693
+ return bodyText;
13682
12694
  }
13683
12695
 
13684
12696
  /** Build the request or response part of a replay network breadcrumb. */
13685
12697
  function buildNetworkRequestOrResponse(
13686
- headers,
13687
12698
  bodySize,
13688
12699
  body,
13689
12700
  ) {
13690
- if (!bodySize && Object.keys(headers).length === 0) {
13691
- return undefined;
13692
- }
13693
-
13694
12701
  if (!bodySize) {
13695
- return {
13696
- headers,
13697
- };
12702
+ return undefined;
13698
12703
  }
13699
12704
 
13700
12705
  if (!body) {
13701
12706
  return {
13702
- headers,
13703
12707
  size: bodySize,
13704
12708
  };
13705
12709
  }
13706
12710
 
13707
12711
  const info = {
13708
- headers,
13709
12712
  size: bodySize,
13710
12713
  };
13711
12714
 
13712
- const { body: normalizedBody, warnings } = normalizeNetworkBody(body);
13713
- info.body = normalizedBody;
13714
- if (warnings.length > 0) {
12715
+ if (bodySize < NETWORK_BODY_MAX_SIZE) {
12716
+ info.body = body;
12717
+ } else {
13715
12718
  info._meta = {
13716
- warnings,
12719
+ errors: ['MAX_BODY_SIZE_EXCEEDED'],
13717
12720
  };
13718
12721
  }
13719
12722
 
13720
12723
  return info;
13721
12724
  }
13722
12725
 
13723
- /** Filter a set of headers */
13724
- function getAllowedHeaders(headers, allowedHeaders) {
13725
- return Object.keys(headers).reduce((filteredHeaders, key) => {
13726
- const normalizedKey = key.toLowerCase();
13727
- // Avoid putting empty strings into the headers
13728
- if (allowedHeaders.includes(normalizedKey) && headers[key]) {
13729
- filteredHeaders[normalizedKey] = headers[key];
13730
- }
13731
- return filteredHeaders;
13732
- }, {});
13733
- }
13734
-
13735
12726
  function _serializeFormData(formData) {
13736
12727
  // This is a bit simplified, but gives us a decent estimate
13737
12728
  // This converts e.g. { name: 'Anne Smith', age: 13 } to 'name=Anne+Smith&age=13'
@@ -13739,78 +12730,6 @@ function _serializeFormData(formData) {
13739
12730
  return new URLSearchParams(formData).toString();
13740
12731
  }
13741
12732
 
13742
- function normalizeNetworkBody(body)
13743
-
13744
- {
13745
- if (!body || typeof body !== 'string') {
13746
- return {
13747
- body,
13748
- warnings: [],
13749
- };
13750
- }
13751
-
13752
- const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE;
13753
-
13754
- if (_strIsProbablyJson(body)) {
13755
- try {
13756
- const json = exceedsSizeLimit ? fixJson(body.slice(0, NETWORK_BODY_MAX_SIZE)) : body;
13757
- const normalizedBody = JSON.parse(json);
13758
- return {
13759
- body: normalizedBody,
13760
- warnings: exceedsSizeLimit ? ['JSON_TRUNCATED'] : [],
13761
- };
13762
- } catch (e3) {
13763
- return {
13764
- body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
13765
- warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
13766
- };
13767
- }
13768
- }
13769
-
13770
- return {
13771
- body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
13772
- warnings: exceedsSizeLimit ? ['TEXT_TRUNCATED'] : [],
13773
- };
13774
- }
13775
-
13776
- function _strIsProbablyJson(str) {
13777
- const first = str[0];
13778
- const last = str[str.length - 1];
13779
-
13780
- // Simple check: If this does not start & end with {} or [], it's not JSON
13781
- return (first === '[' && last === ']') || (first === '{' && last === '}');
13782
- }
13783
-
13784
- /** Match an URL against a list of strings/Regex. */
13785
- function urlMatches(url, urls) {
13786
- const fullUrl = getFullUrl(url);
13787
-
13788
- return stringMatchesSomePattern(fullUrl, urls);
13789
- }
13790
-
13791
- /** exported for tests */
13792
- function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
13793
- // Short circuit for common cases:
13794
- if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith(WINDOW.location.origin)) {
13795
- return url;
13796
- }
13797
- const fixedUrl = new URL(url, baseURI);
13798
-
13799
- // If these do not match, we are not dealing with a relative URL, so just return it
13800
- if (fixedUrl.origin !== new URL(baseURI).origin) {
13801
- return url;
13802
- }
13803
-
13804
- const fullUrl = fixedUrl.href;
13805
-
13806
- // Remove trailing slashes, if they don't match the original URL
13807
- if (!url.endsWith('/') && fullUrl.endsWith('/')) {
13808
- return fullUrl.slice(0, -1);
13809
- }
13810
-
13811
- return fullUrl;
13812
- }
13813
-
13814
12733
  /**
13815
12734
  * Capture a fetch breadcrumb to a replay.
13816
12735
  * This adds additional data (where approriate).
@@ -13818,9 +12737,7 @@ function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
13818
12737
  async function captureFetchBreadcrumbToReplay(
13819
12738
  breadcrumb,
13820
12739
  hint,
13821
- options
13822
-
13823
- ,
12740
+ options,
13824
12741
  ) {
13825
12742
  try {
13826
12743
  const data = await _prepareFetchData(breadcrumb, hint, options);
@@ -13847,7 +12764,6 @@ function enrichFetchBreadcrumb(
13847
12764
 
13848
12765
  const body = _getFetchRequestArgBody(input);
13849
12766
  const reqSize = getBodySize(body, options.textEncoder);
13850
-
13851
12767
  const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined;
13852
12768
 
13853
12769
  if (reqSize !== undefined) {
@@ -13861,109 +12777,97 @@ function enrichFetchBreadcrumb(
13861
12777
  async function _prepareFetchData(
13862
12778
  breadcrumb,
13863
12779
  hint,
13864
- options
13865
-
13866
- ,
12780
+ options,
13867
12781
  ) {
13868
12782
  const { startTimestamp, endTimestamp } = hint;
13869
12783
 
13870
12784
  const {
13871
12785
  url,
13872
12786
  method,
13873
- status_code: statusCode = 0,
12787
+ status_code: statusCode,
13874
12788
  request_body_size: requestBodySize,
13875
12789
  response_body_size: responseBodySize,
13876
12790
  } = breadcrumb.data;
13877
12791
 
13878
- const captureDetails = urlMatches(url, options.networkDetailAllowUrls);
13879
-
13880
- const request = captureDetails
13881
- ? _getRequestInfo(options, hint.input, requestBodySize)
13882
- : buildSkippedNetworkRequestOrResponse(requestBodySize);
13883
- const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize);
12792
+ const request = _getRequestInfo(options, hint.input, requestBodySize);
12793
+ const response = await _getResponseInfo(options, hint.response, responseBodySize);
13884
12794
 
13885
12795
  return {
13886
12796
  startTimestamp,
13887
12797
  endTimestamp,
13888
12798
  url,
13889
12799
  method,
13890
- statusCode,
12800
+ statusCode: statusCode || 0,
13891
12801
  request,
13892
12802
  response,
13893
12803
  };
13894
12804
  }
13895
12805
 
13896
12806
  function _getRequestInfo(
13897
- { networkCaptureBodies, networkRequestHeaders },
12807
+ { captureBodies },
13898
12808
  input,
13899
12809
  requestBodySize,
13900
12810
  ) {
13901
- const headers = getRequestHeaders(input, networkRequestHeaders);
13902
-
13903
- if (!networkCaptureBodies) {
13904
- return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
12811
+ if (!captureBodies) {
12812
+ return buildNetworkRequestOrResponse(requestBodySize, undefined);
13905
12813
  }
13906
12814
 
13907
12815
  // We only want to transmit string or string-like bodies
13908
12816
  const requestBody = _getFetchRequestArgBody(input);
13909
- const bodyStr = getBodyString(requestBody);
13910
- return buildNetworkRequestOrResponse(headers, requestBodySize, bodyStr);
12817
+ const body = getNetworkBody(getBodyString(requestBody));
12818
+ return buildNetworkRequestOrResponse(requestBodySize, body);
13911
12819
  }
13912
12820
 
13913
12821
  async function _getResponseInfo(
13914
- captureDetails,
13915
- {
13916
- networkCaptureBodies,
13917
- textEncoder,
13918
- networkResponseHeaders,
13919
- }
13920
-
13921
- ,
12822
+ { captureBodies, textEncoder },
13922
12823
  response,
13923
12824
  responseBodySize,
13924
12825
  ) {
13925
- if (!captureDetails && responseBodySize !== undefined) {
13926
- return buildSkippedNetworkRequestOrResponse(responseBodySize);
13927
- }
13928
-
13929
- const headers = getAllHeaders(response.headers, networkResponseHeaders);
13930
-
13931
- if (!networkCaptureBodies && responseBodySize !== undefined) {
13932
- return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
12826
+ if (!captureBodies && responseBodySize !== undefined) {
12827
+ return buildNetworkRequestOrResponse(responseBodySize, undefined);
13933
12828
  }
13934
12829
 
13935
12830
  // Only clone the response if we need to
13936
12831
  try {
13937
12832
  // We have to clone this, as the body can only be read once
13938
12833
  const res = response.clone();
13939
- const bodyText = await _parseFetchBody(res);
12834
+ const { body, bodyText } = await _parseFetchBody(res);
13940
12835
 
13941
12836
  const size =
13942
12837
  bodyText && bodyText.length && responseBodySize === undefined
13943
12838
  ? getBodySize(bodyText, textEncoder)
13944
12839
  : responseBodySize;
13945
12840
 
13946
- if (!captureDetails) {
13947
- return buildSkippedNetworkRequestOrResponse(size);
13948
- }
13949
-
13950
- if (networkCaptureBodies) {
13951
- return buildNetworkRequestOrResponse(headers, size, bodyText);
12841
+ if (captureBodies) {
12842
+ return buildNetworkRequestOrResponse(size, body);
13952
12843
  }
13953
12844
 
13954
- return buildNetworkRequestOrResponse(headers, size, undefined);
12845
+ return buildNetworkRequestOrResponse(size, undefined);
13955
12846
  } catch (e) {
13956
12847
  // fallback
13957
- return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
12848
+ return buildNetworkRequestOrResponse(responseBodySize, undefined);
13958
12849
  }
13959
12850
  }
13960
12851
 
13961
- async function _parseFetchBody(response) {
12852
+ async function _parseFetchBody(
12853
+ response,
12854
+ ) {
12855
+ let bodyText;
12856
+
13962
12857
  try {
13963
- return await response.text();
12858
+ bodyText = await response.text();
13964
12859
  } catch (e2) {
13965
- return undefined;
12860
+ return {};
13966
12861
  }
12862
+
12863
+ try {
12864
+ const body = JSON.parse(bodyText);
12865
+ return { body, bodyText };
12866
+ } catch (e3) {
12867
+ // just send bodyText
12868
+ }
12869
+
12870
+ return { bodyText, body: bodyText };
13967
12871
  }
13968
12872
 
13969
12873
  function _getFetchRequestArgBody(fetchArgs = []) {
@@ -13975,56 +12879,6 @@ function _getFetchRequestArgBody(fetchArgs = []) {
13975
12879
  return (fetchArgs[1] ).body;
13976
12880
  }
13977
12881
 
13978
- function getAllHeaders(headers, allowedHeaders) {
13979
- const allHeaders = {};
13980
-
13981
- allowedHeaders.forEach(header => {
13982
- if (headers.get(header)) {
13983
- allHeaders[header] = headers.get(header) ;
13984
- }
13985
- });
13986
-
13987
- return allHeaders;
13988
- }
13989
-
13990
- function getRequestHeaders(fetchArgs, allowedHeaders) {
13991
- if (fetchArgs.length === 1 && typeof fetchArgs[0] !== 'string') {
13992
- return getHeadersFromOptions(fetchArgs[0] , allowedHeaders);
13993
- }
13994
-
13995
- if (fetchArgs.length === 2) {
13996
- return getHeadersFromOptions(fetchArgs[1] , allowedHeaders);
13997
- }
13998
-
13999
- return {};
14000
- }
14001
-
14002
- function getHeadersFromOptions(
14003
- input,
14004
- allowedHeaders,
14005
- ) {
14006
- if (!input) {
14007
- return {};
14008
- }
14009
-
14010
- const headers = input.headers;
14011
-
14012
- if (!headers) {
14013
- return {};
14014
- }
14015
-
14016
- if (headers instanceof Headers) {
14017
- return getAllHeaders(headers, allowedHeaders);
14018
- }
14019
-
14020
- // We do not support this, as it is not really documented (anymore?)
14021
- if (Array.isArray(headers)) {
14022
- return {};
14023
- }
14024
-
14025
- return getAllowedHeaders(headers, allowedHeaders);
14026
- }
14027
-
14028
12882
  /**
14029
12883
  * Capture an XHR breadcrumb to a replay.
14030
12884
  * This adds additional data (where approriate).
@@ -14075,12 +12929,12 @@ function _prepareXhrData(
14075
12929
  hint,
14076
12930
  options,
14077
12931
  ) {
14078
- const { startTimestamp, endTimestamp, input, xhr } = hint;
12932
+ const { startTimestamp, endTimestamp, input } = hint;
14079
12933
 
14080
12934
  const {
14081
12935
  url,
14082
12936
  method,
14083
- status_code: statusCode = 0,
12937
+ status_code: statusCode,
14084
12938
  request_body_size: requestBodySize,
14085
12939
  response_body_size: responseBodySize,
14086
12940
  } = breadcrumb.data;
@@ -14089,35 +12943,13 @@ function _prepareXhrData(
14089
12943
  return null;
14090
12944
  }
14091
12945
 
14092
- if (!urlMatches(url, options.networkDetailAllowUrls)) {
14093
- const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
14094
- const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
14095
- return {
14096
- startTimestamp,
14097
- endTimestamp,
14098
- url,
14099
- method,
14100
- statusCode,
14101
- request,
14102
- response,
14103
- };
14104
- }
14105
-
14106
- const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
14107
- const networkRequestHeaders = xhrInfo
14108
- ? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
14109
- : {};
14110
- const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
14111
-
14112
12946
  const request = buildNetworkRequestOrResponse(
14113
- networkRequestHeaders,
14114
12947
  requestBodySize,
14115
- options.networkCaptureBodies ? getBodyString(input) : undefined,
12948
+ options.captureBodies ? getNetworkBody(getBodyString(input)) : undefined,
14116
12949
  );
14117
12950
  const response = buildNetworkRequestOrResponse(
14118
- networkResponseHeaders,
14119
12951
  responseBodySize,
14120
- options.networkCaptureBodies ? hint.xhr.responseText : undefined,
12952
+ options.captureBodies ? getNetworkBody(hint.xhr.responseText) : undefined,
14121
12953
  );
14122
12954
 
14123
12955
  return {
@@ -14125,26 +12957,12 @@ function _prepareXhrData(
14125
12957
  endTimestamp,
14126
12958
  url,
14127
12959
  method,
14128
- statusCode,
12960
+ statusCode: statusCode || 0,
14129
12961
  request,
14130
12962
  response,
14131
12963
  };
14132
12964
  }
14133
12965
 
14134
- function getResponseHeaders(xhr) {
14135
- const headers = xhr.getAllResponseHeaders();
14136
-
14137
- if (!headers) {
14138
- return {};
14139
- }
14140
-
14141
- return headers.split('\r\n').reduce((acc, line) => {
14142
- const [key, value] = line.split(': ');
14143
- acc[key.toLowerCase()] = value;
14144
- return acc;
14145
- }, {});
14146
- }
14147
-
14148
12966
  /**
14149
12967
  * This method does two things:
14150
12968
  * - It enriches the regular XHR/fetch breadcrumbs with request/response size data
@@ -14157,16 +12975,10 @@ function handleNetworkBreadcrumbs(replay) {
14157
12975
  try {
14158
12976
  const textEncoder = new TextEncoder();
14159
12977
 
14160
- const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
14161
- replay.getOptions();
14162
-
14163
12978
  const options = {
14164
12979
  replay,
14165
12980
  textEncoder,
14166
- networkDetailAllowUrls,
14167
- networkCaptureBodies,
14168
- networkRequestHeaders,
14169
- networkResponseHeaders,
12981
+ captureBodies: replay.getOptions()._experiments.captureNetworkBodies || false,
14170
12982
  };
14171
12983
 
14172
12984
  if (client && client.on) {
@@ -14274,66 +13086,9 @@ function handleScope(scope) {
14274
13086
  return null;
14275
13087
  }
14276
13088
 
14277
- if (newBreadcrumb.category === 'console') {
14278
- return normalizeConsoleBreadcrumb(newBreadcrumb);
14279
- }
14280
-
14281
13089
  return createBreadcrumb(newBreadcrumb);
14282
13090
  }
14283
13091
 
14284
- /** exported for tests only */
14285
- function normalizeConsoleBreadcrumb(breadcrumb) {
14286
- const args = breadcrumb.data && breadcrumb.data.arguments;
14287
-
14288
- if (!Array.isArray(args) || args.length === 0) {
14289
- return createBreadcrumb(breadcrumb);
14290
- }
14291
-
14292
- let isTruncated = false;
14293
-
14294
- // Avoid giant args captures
14295
- const normalizedArgs = args.map(arg => {
14296
- if (!arg) {
14297
- return arg;
14298
- }
14299
- if (typeof arg === 'string') {
14300
- if (arg.length > CONSOLE_ARG_MAX_SIZE) {
14301
- isTruncated = true;
14302
- return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
14303
- }
14304
-
14305
- return arg;
14306
- }
14307
- if (typeof arg === 'object') {
14308
- try {
14309
- const normalizedArg = normalize(arg, 7);
14310
- const stringified = JSON.stringify(normalizedArg);
14311
- if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
14312
- const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
14313
- const json = JSON.parse(fixedJson);
14314
- // We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
14315
- isTruncated = true;
14316
- return json;
14317
- }
14318
- return normalizedArg;
14319
- } catch (e) {
14320
- // fall back to default
14321
- }
14322
- }
14323
-
14324
- return arg;
14325
- });
14326
-
14327
- return createBreadcrumb({
14328
- ...breadcrumb,
14329
- data: {
14330
- ...breadcrumb.data,
14331
- arguments: normalizedArgs,
14332
- ...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
14333
- },
14334
- });
14335
- }
14336
-
14337
13092
  /**
14338
13093
  * Add global listeners that cannot be removed.
14339
13094
  */
@@ -14358,8 +13113,7 @@ function addGlobalListeners(replay) {
14358
13113
  client.on('afterSendEvent', handleAfterSendEvent(replay));
14359
13114
  client.on('createDsc', (dsc) => {
14360
13115
  const replayId = replay.getSessionId();
14361
- // We do not want to set the DSC when in buffer mode, as that means the replay has not been sent (yet)
14362
- if (replayId && replay.isEnabled() && replay.recordingMode === 'session') {
13116
+ if (replayId) {
14363
13117
  dsc.replay_id = replayId;
14364
13118
  }
14365
13119
  });
@@ -14667,7 +13421,7 @@ function getHandleRecordingEmit(replay) {
14667
13421
  // when an error occurs. Clear any state that happens before this current
14668
13422
  // checkout. This needs to happen before `addEvent()` which updates state
14669
13423
  // dependent on this reset.
14670
- if (replay.recordingMode === 'buffer' && isCheckout) {
13424
+ if (replay.recordingMode === 'error' && isCheckout) {
14671
13425
  replay.setInitialState();
14672
13426
  }
14673
13427
 
@@ -14681,14 +13435,6 @@ function getHandleRecordingEmit(replay) {
14681
13435
  return false;
14682
13436
  }
14683
13437
 
14684
- // Additionally, create a meta event that will capture certain SDK settings.
14685
- // In order to handle buffer mode, this needs to either be done when we
14686
- // receive checkout events or at flush time.
14687
- //
14688
- // `isCheckout` is always true, but want to be explicit that it should
14689
- // only be added for checkouts
14690
- void addSettingsEvent(replay, isCheckout);
14691
-
14692
13438
  // If there is a previousSessionId after a full snapshot occurs, then
14693
13439
  // the replay session was started due to session expiration. The new session
14694
13440
  // is started before triggering a new checkout and contains the id
@@ -14699,10 +13445,10 @@ function getHandleRecordingEmit(replay) {
14699
13445
  return true;
14700
13446
  }
14701
13447
 
14702
- // When in buffer mode, make sure we adjust the session started date to the current earliest event of the buffer
14703
- // this should usually be the timestamp of the checkout event, but to be safe...
14704
- if (replay.recordingMode === 'buffer' && replay.session && replay.eventBuffer) {
14705
- const earliestEvent = replay.eventBuffer.getEarliestTimestamp();
13448
+ // See note above re: session start needs to reflect the most recent
13449
+ // checkout.
13450
+ if (replay.recordingMode === 'error' && replay.session) {
13451
+ const { earliestEvent } = replay.getContext();
14706
13452
  if (earliestEvent) {
14707
13453
  replay.session.started = earliestEvent;
14708
13454
 
@@ -14712,30 +13458,6 @@ function getHandleRecordingEmit(replay) {
14712
13458
  }
14713
13459
  }
14714
13460
 
14715
- const options = replay.getOptions();
14716
-
14717
- // TODO: We want this as an experiment so that we can test
14718
- // internally and create metrics before making this the default
14719
- if (options._experiments.delayFlushOnCheckout) {
14720
- // If the full snapshot is due to an initial load, we will not have
14721
- // a previous session ID. In this case, we want to buffer events
14722
- // for a set amount of time before flushing. This can help avoid
14723
- // capturing replays of users that immediately close the window.
14724
- setTimeout(() => replay.conditionalFlush(), options._experiments.delayFlushOnCheckout);
14725
-
14726
- // Cancel any previously debounced flushes to ensure there are no [near]
14727
- // simultaneous flushes happening. The latter request should be
14728
- // insignificant in this case, so wait for additional user interaction to
14729
- // trigger a new flush.
14730
- //
14731
- // This can happen because there's no guarantee that a recording event
14732
- // happens first. e.g. a mouse click can happen and trigger a debounced
14733
- // flush before the checkout.
14734
- replay.cancelFlush();
14735
-
14736
- return true;
14737
- }
14738
-
14739
13461
  // Flush immediately so that we do not miss the first segment, otherwise
14740
13462
  // it can prevent loading on the UI. This will cause an increase in short
14741
13463
  // replays (e.g. opening and closing a tab quickly), but these can be
@@ -14750,46 +13472,6 @@ function getHandleRecordingEmit(replay) {
14750
13472
  };
14751
13473
  }
14752
13474
 
14753
- /**
14754
- * Exported for tests
14755
- */
14756
- function createOptionsEvent(replay) {
14757
- const options = replay.getOptions();
14758
- return {
14759
- type: EventType.Custom,
14760
- timestamp: Date.now(),
14761
- data: {
14762
- tag: 'options',
14763
- payload: {
14764
- sessionSampleRate: options.sessionSampleRate,
14765
- errorSampleRate: options.errorSampleRate,
14766
- useCompressionOption: options.useCompression,
14767
- blockAllMedia: options.blockAllMedia,
14768
- maskAllText: options.maskAllText,
14769
- maskAllInputs: options.maskAllInputs,
14770
- useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false,
14771
- networkDetailHasUrls: options.networkDetailAllowUrls.length > 0,
14772
- networkCaptureBodies: options.networkCaptureBodies,
14773
- networkRequestHasHeaders: options.networkRequestHeaders.length > 0,
14774
- networkResponseHasHeaders: options.networkResponseHeaders.length > 0,
14775
- },
14776
- },
14777
- };
14778
- }
14779
-
14780
- /**
14781
- * Add a "meta" event that contains a simplified view on current configuration
14782
- * options. This should only be included on the first segment of a recording.
14783
- */
14784
- function addSettingsEvent(replay, isCheckout) {
14785
- // Only need to add this event when sending the first segment
14786
- if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
14787
- return Promise.resolve(null);
14788
- }
14789
-
14790
- return addEvent(replay, createOptionsEvent(replay), false);
14791
- }
14792
-
14793
13475
  /**
14794
13476
  * Create a replay envelope ready to be sent.
14795
13477
  * This includes both the replay event, as well as the recording data.
@@ -14901,9 +13583,11 @@ async function sendReplayRequest({
14901
13583
  recordingData,
14902
13584
  replayId,
14903
13585
  segmentId: segment_id,
13586
+ includeReplayStartTimestamp,
14904
13587
  eventContext,
14905
13588
  timestamp,
14906
13589
  session,
13590
+ options,
14907
13591
  }) {
14908
13592
  const preparedRecordingData = prepareRecordingData({
14909
13593
  recordingData,
@@ -14925,8 +13609,9 @@ async function sendReplayRequest({
14925
13609
  }
14926
13610
 
14927
13611
  const baseEvent = {
13612
+ // @ts-ignore private api
14928
13613
  type: REPLAY_EVENT_NAME,
14929
- replay_start_timestamp: initialTimestamp / 1000,
13614
+ ...(includeReplayStartTimestamp ? { replay_start_timestamp: initialTimestamp / 1000 } : {}),
14930
13615
  timestamp: timestamp / 1000,
14931
13616
  error_ids: errorIds,
14932
13617
  trace_ids: traceIds,
@@ -14945,6 +13630,15 @@ async function sendReplayRequest({
14945
13630
  return;
14946
13631
  }
14947
13632
 
13633
+ replayEvent.contexts = {
13634
+ ...replayEvent.contexts,
13635
+ replay: {
13636
+ ...(replayEvent.contexts && replayEvent.contexts.replay),
13637
+ session_sample_rate: options.sessionSampleRate,
13638
+ error_sample_rate: options.errorSampleRate,
13639
+ },
13640
+ };
13641
+
14948
13642
  /*
14949
13643
  For reference, the fully built event looks something like this:
14950
13644
  {
@@ -14975,6 +13669,10 @@ async function sendReplayRequest({
14975
13669
  },
14976
13670
  "sdkProcessingMetadata": {},
14977
13671
  "contexts": {
13672
+ "replay": {
13673
+ "session_sample_rate": 1,
13674
+ "error_sample_rate": 0,
13675
+ },
14978
13676
  },
14979
13677
  }
14980
13678
  */
@@ -15100,11 +13798,9 @@ class ReplayContainer {
15100
13798
  __init2() {this.performanceEvents = [];}
15101
13799
 
15102
13800
  /**
15103
- * Recording can happen in one of three modes:
15104
- * - session: Record the whole session, sending it continuously
15105
- * - buffer: Always keep the last 60s of recording, requires:
15106
- * - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
15107
- * - or calling `flush()` to send the replay
13801
+ * Recording can happen in one of two modes:
13802
+ * * session: Record the whole session, sending it continuously
13803
+ * * error: Always keep the last 60s of recording, and when an error occurs, send it immediately
15108
13804
  */
15109
13805
  __init3() {this.recordingMode = 'session';}
15110
13806
 
@@ -15113,8 +13809,7 @@ class ReplayContainer {
15113
13809
  * @hidden
15114
13810
  */
15115
13811
  __init4() {this.timeouts = {
15116
- sessionIdlePause: SESSION_IDLE_PAUSE_DURATION,
15117
- sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
13812
+ sessionIdle: SESSION_IDLE_DURATION,
15118
13813
  maxSessionLife: MAX_SESSION_LIFE,
15119
13814
  }; }
15120
13815
 
@@ -15158,6 +13853,7 @@ class ReplayContainer {
15158
13853
  errorIds: new Set(),
15159
13854
  traceIds: new Set(),
15160
13855
  urls: [],
13856
+ earliestEvent: null,
15161
13857
  initialTimestamp: Date.now(),
15162
13858
  initialUrl: '',
15163
13859
  };}
@@ -15167,7 +13863,7 @@ class ReplayContainer {
15167
13863
  recordingOptions,
15168
13864
  }
15169
13865
 
15170
- ) {ReplayContainer.prototype.__init.call(this);ReplayContainer.prototype.__init2.call(this);ReplayContainer.prototype.__init3.call(this);ReplayContainer.prototype.__init4.call(this);ReplayContainer.prototype.__init5.call(this);ReplayContainer.prototype.__init6.call(this);ReplayContainer.prototype.__init7.call(this);ReplayContainer.prototype.__init8.call(this);ReplayContainer.prototype.__init9.call(this);ReplayContainer.prototype.__init10.call(this);ReplayContainer.prototype.__init11.call(this);ReplayContainer.prototype.__init12.call(this);ReplayContainer.prototype.__init13.call(this);ReplayContainer.prototype.__init14.call(this);ReplayContainer.prototype.__init15.call(this);ReplayContainer.prototype.__init16.call(this);ReplayContainer.prototype.__init17.call(this);ReplayContainer.prototype.__init18.call(this);
13866
+ ) {ReplayContainer.prototype.__init.call(this);ReplayContainer.prototype.__init2.call(this);ReplayContainer.prototype.__init3.call(this);ReplayContainer.prototype.__init4.call(this);ReplayContainer.prototype.__init5.call(this);ReplayContainer.prototype.__init6.call(this);ReplayContainer.prototype.__init7.call(this);ReplayContainer.prototype.__init8.call(this);ReplayContainer.prototype.__init9.call(this);ReplayContainer.prototype.__init10.call(this);ReplayContainer.prototype.__init11.call(this);ReplayContainer.prototype.__init12.call(this);ReplayContainer.prototype.__init13.call(this);ReplayContainer.prototype.__init14.call(this);ReplayContainer.prototype.__init15.call(this);ReplayContainer.prototype.__init16.call(this);ReplayContainer.prototype.__init17.call(this);
15171
13867
  this._recordingOptions = recordingOptions;
15172
13868
  this._options = options;
15173
13869
 
@@ -15197,102 +13893,49 @@ class ReplayContainer {
15197
13893
  }
15198
13894
 
15199
13895
  /**
15200
- * Initializes the plugin based on sampling configuration. Should not be
15201
- * called outside of constructor.
13896
+ * Initializes the plugin.
13897
+ *
13898
+ * Creates or loads a session, attaches listeners to varying events (DOM,
13899
+ * _performanceObserver, Recording, Sentry SDK, etc)
15202
13900
  */
15203
- initializeSampling() {
15204
- const { errorSampleRate, sessionSampleRate } = this._options;
15205
-
15206
- // If neither sample rate is > 0, then do nothing - user will need to call one of
15207
- // `start()` or `startBuffering` themselves.
15208
- if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
15209
- return;
15210
- }
15211
-
15212
- // Otherwise if there is _any_ sample rate set, try to load an existing
15213
- // session, or create a new one.
15214
- const isSessionSampled = this._loadAndCheckSession();
13901
+ start() {
13902
+ this.setInitialState();
15215
13903
 
15216
- if (!isSessionSampled) {
15217
- // This should only occur if `errorSampleRate` is 0 and was unsampled for
15218
- // session-based replay. In this case there is nothing to do.
13904
+ if (!this._loadAndCheckSession()) {
15219
13905
  return;
15220
13906
  }
15221
13907
 
13908
+ // If there is no session, then something bad has happened - can't continue
15222
13909
  if (!this.session) {
15223
- // This should not happen, something wrong has occurred
15224
- this._handleException(new Error('Unable to initialize and create session'));
13910
+ this._handleException(new Error('No session found'));
15225
13911
  return;
15226
13912
  }
15227
13913
 
15228
- if (this.session.sampled && this.session.sampled !== 'session') {
15229
- // If not sampled as session-based, then recording mode will be `buffer`
15230
- // Note that we don't explicitly check if `sampled === 'buffer'` because we
15231
- // could have sessions from Session storage that are still `error` from
15232
- // prior SDK version.
15233
- this.recordingMode = 'buffer';
15234
- }
15235
-
15236
- this._initializeRecording();
15237
- }
15238
-
15239
- /**
15240
- * Start a replay regardless of sampling rate. Calling this will always
15241
- * create a new session. Will throw an error if replay is already in progress.
15242
- *
15243
- * Creates or loads a session, attaches listeners to varying events (DOM,
15244
- * _performanceObserver, Recording, Sentry SDK, etc)
15245
- */
15246
- start() {
15247
- if (this._isEnabled && this.recordingMode === 'session') {
15248
- throw new Error('Replay recording is already in progress');
13914
+ if (!this.session.sampled) {
13915
+ // If session was not sampled, then we do not initialize the integration at all.
13916
+ return;
15249
13917
  }
15250
13918
 
15251
- if (this._isEnabled && this.recordingMode === 'buffer') {
15252
- throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
13919
+ // If session is sampled for errors, then we need to set the recordingMode
13920
+ // to 'error', which will configure recording with different options.
13921
+ if (this.session.sampled === 'error') {
13922
+ this.recordingMode = 'error';
15253
13923
  }
15254
13924
 
15255
- const previousSessionId = this.session && this.session.id;
13925
+ // setup() is generally called on page load or manually - in both cases we
13926
+ // should treat it as an activity
13927
+ this._updateSessionActivity();
15256
13928
 
15257
- const { session } = getSession({
15258
- timeouts: this.timeouts,
15259
- stickySession: Boolean(this._options.stickySession),
15260
- currentSession: this.session,
15261
- // This is intentional: create a new session-based replay when calling `start()`
15262
- sessionSampleRate: 1,
15263
- allowBuffering: false,
13929
+ this.eventBuffer = createEventBuffer({
13930
+ useCompression: this._options.useCompression,
15264
13931
  });
15265
13932
 
15266
- session.previousSessionId = previousSessionId;
15267
- this.session = session;
15268
-
15269
- this._initializeRecording();
15270
- }
15271
-
15272
- /**
15273
- * Start replay buffering. Buffers until `flush()` is called or, if
15274
- * `replaysOnErrorSampleRate` > 0, an error occurs.
15275
- */
15276
- startBuffering() {
15277
- if (this._isEnabled) {
15278
- throw new Error('Replay recording is already in progress');
15279
- }
15280
-
15281
- const previousSessionId = this.session && this.session.id;
15282
-
15283
- const { session } = getSession({
15284
- timeouts: this.timeouts,
15285
- stickySession: Boolean(this._options.stickySession),
15286
- currentSession: this.session,
15287
- sessionSampleRate: 0,
15288
- allowBuffering: true,
15289
- });
13933
+ this._addListeners();
15290
13934
 
15291
- session.previousSessionId = previousSessionId;
15292
- this.session = session;
13935
+ // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
13936
+ this._isEnabled = true;
15293
13937
 
15294
- this.recordingMode = 'buffer';
15295
- this._initializeRecording();
13938
+ this.startRecording();
15296
13939
  }
15297
13940
 
15298
13941
  /**
@@ -15307,7 +13950,7 @@ class ReplayContainer {
15307
13950
  // When running in error sampling mode, we need to overwrite `checkoutEveryNms`
15308
13951
  // Without this, it would record forever, until an error happens, which we don't want
15309
13952
  // instead, we'll always keep the last 60 seconds of replay before an error happened
15310
- ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
13953
+ ...(this.recordingMode === 'error' && { checkoutEveryNms: ERROR_CHECKOUT_TIME }),
15311
13954
  emit: getHandleRecordingEmit(this),
15312
13955
  onMutation: this._onMutationHandler,
15313
13956
  });
@@ -15318,18 +13961,17 @@ class ReplayContainer {
15318
13961
 
15319
13962
  /**
15320
13963
  * Stops the recording, if it was running.
15321
- *
15322
- * Returns true if it was previously stopped, or is now stopped,
15323
- * otherwise false.
13964
+ * Returns true if it was stopped, else false.
15324
13965
  */
15325
13966
  stopRecording() {
15326
13967
  try {
15327
13968
  if (this._stopRecording) {
15328
13969
  this._stopRecording();
15329
13970
  this._stopRecording = undefined;
13971
+ return true;
15330
13972
  }
15331
13973
 
15332
- return true;
13974
+ return false;
15333
13975
  } catch (err) {
15334
13976
  this._handleException(err);
15335
13977
  return false;
@@ -15340,7 +13982,7 @@ class ReplayContainer {
15340
13982
  * Currently, this needs to be manually called (e.g. for tests). Sentry SDK
15341
13983
  * does not support a teardown
15342
13984
  */
15343
- async stop(reason) {
13985
+ stop(reason) {
15344
13986
  if (!this._isEnabled) {
15345
13987
  return;
15346
13988
  }
@@ -15356,24 +13998,12 @@ class ReplayContainer {
15356
13998
  log(msg);
15357
13999
  }
15358
14000
 
15359
- // We can't move `_isEnabled` after awaiting a flush, otherwise we can
15360
- // enter into an infinite loop when `stop()` is called while flushing.
15361
14001
  this._isEnabled = false;
15362
14002
  this._removeListeners();
15363
14003
  this.stopRecording();
15364
-
15365
- this._debouncedFlush.cancel();
15366
- // See comment above re: `_isEnabled`, we "force" a flush, ignoring the
15367
- // `_isEnabled` state of the plugin since it was disabled above.
15368
- await this._flush({ force: true });
15369
-
15370
- // After flush, destroy event buffer
15371
14004
  this.eventBuffer && this.eventBuffer.destroy();
15372
14005
  this.eventBuffer = null;
15373
-
15374
- // Clear session from session storage, note this means if a new session
15375
- // is started after, it will not have `previousSessionId`
15376
- clearSession(this);
14006
+ this._debouncedFlush.cancel();
15377
14007
  } catch (err) {
15378
14008
  this._handleException(err);
15379
14009
  }
@@ -15404,45 +14034,6 @@ class ReplayContainer {
15404
14034
  this.startRecording();
15405
14035
  }
15406
14036
 
15407
- /**
15408
- * If not in "session" recording mode, flush event buffer which will create a new replay.
15409
- * Unless `continueRecording` is false, the replay will continue to record and
15410
- * behave as a "session"-based replay.
15411
- *
15412
- * Otherwise, queue up a flush.
15413
- */
15414
- async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
15415
- if (this.recordingMode === 'session') {
15416
- return this.flushImmediate();
15417
- }
15418
-
15419
- // Allow flush to complete before resuming as a session recording, otherwise
15420
- // the checkout from `startRecording` may be included in the payload.
15421
- // Prefer to keep the error replay as a separate (and smaller) segment
15422
- // than the session replay.
15423
- await this.flushImmediate();
15424
-
15425
- const hasStoppedRecording = this.stopRecording();
15426
-
15427
- if (!continueRecording || !hasStoppedRecording) {
15428
- return;
15429
- }
15430
-
15431
- // Re-start recording, but in "session" recording mode
15432
-
15433
- // Reset all "capture on error" configuration before
15434
- // starting a new recording
15435
- this.recordingMode = 'session';
15436
-
15437
- // Once this session ends, we do not want to refresh it
15438
- if (this.session) {
15439
- this.session.shouldRefresh = false;
15440
- this._maybeSaveSession();
15441
- }
15442
-
15443
- this.startRecording();
15444
- }
15445
-
15446
14037
  /**
15447
14038
  * We want to batch uploads of replay events. Save events only if
15448
14039
  * `<flushMinDelay>` milliseconds have elapsed since the last event
@@ -15452,12 +14043,12 @@ class ReplayContainer {
15452
14043
  * processing and hand back control to caller.
15453
14044
  */
15454
14045
  addUpdate(cb) {
15455
- // We need to always run `cb` (e.g. in the case of `this.recordingMode == 'buffer'`)
14046
+ // We need to always run `cb` (e.g. in the case of `this.recordingMode == 'error'`)
15456
14047
  const cbResult = cb();
15457
14048
 
15458
14049
  // If this option is turned on then we will only want to call `flush`
15459
14050
  // explicitly
15460
- if (this.recordingMode === 'buffer') {
14051
+ if (this.recordingMode === 'error') {
15461
14052
  return;
15462
14053
  }
15463
14054
 
@@ -15501,17 +14092,7 @@ class ReplayContainer {
15501
14092
  }
15502
14093
 
15503
14094
  /**
15504
- * Only flush if `this.recordingMode === 'session'`
15505
- */
15506
- conditionalFlush() {
15507
- if (this.recordingMode === 'buffer') {
15508
- return Promise.resolve();
15509
- }
15510
-
15511
- return this.flushImmediate();
15512
- }
15513
-
15514
- /**
14095
+ *
15515
14096
  * Always flush via `_debouncedFlush` so that we do not have flushes triggered
15516
14097
  * from calling both `flush` and `_debouncedFlush`. Otherwise, there could be
15517
14098
  * cases of mulitple flushes happening closely together.
@@ -15522,13 +14103,6 @@ class ReplayContainer {
15522
14103
  return this._debouncedFlush.flush() ;
15523
14104
  }
15524
14105
 
15525
- /**
15526
- * Cancels queued up flushes.
15527
- */
15528
- cancelFlush() {
15529
- this._debouncedFlush.cancel();
15530
- }
15531
-
15532
14106
  /** Get the current sesion (=replay) ID */
15533
14107
  getSessionId() {
15534
14108
  return this.session && this.session.id;
@@ -15546,12 +14120,12 @@ class ReplayContainer {
15546
14120
  const oldSessionId = this.getSessionId();
15547
14121
 
15548
14122
  // Prevent starting a new session if the last user activity is older than
15549
- // SESSION_IDLE_PAUSE_DURATION. Otherwise non-user activity can trigger a new
14123
+ // SESSION_IDLE_DURATION. Otherwise non-user activity can trigger a new
15550
14124
  // session+recording. This creates noisy replays that do not have much
15551
14125
  // content in them.
15552
14126
  if (
15553
14127
  this._lastActivity &&
15554
- isExpired(this._lastActivity, this.timeouts.sessionIdlePause) &&
14128
+ isExpired(this._lastActivity, this.timeouts.sessionIdle) &&
15555
14129
  this.session &&
15556
14130
  this.session.sampled === 'session'
15557
14131
  ) {
@@ -15601,30 +14175,6 @@ class ReplayContainer {
15601
14175
  this._context.urls.push(url);
15602
14176
  }
15603
14177
 
15604
- /**
15605
- * Initialize and start all listeners to varying events (DOM,
15606
- * Performance Observer, Recording, Sentry SDK, etc)
15607
- */
15608
- _initializeRecording() {
15609
- this.setInitialState();
15610
-
15611
- // this method is generally called on page load or manually - in both cases
15612
- // we should treat it as an activity
15613
- this._updateSessionActivity();
15614
-
15615
- this.eventBuffer = createEventBuffer({
15616
- useCompression: this._options.useCompression,
15617
- });
15618
-
15619
- this._removeListeners();
15620
- this._addListeners();
15621
-
15622
- // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
15623
- this._isEnabled = true;
15624
-
15625
- this.startRecording();
15626
- }
15627
-
15628
14178
  /** A wrapper to conditionally capture exceptions. */
15629
14179
  _handleException(error) {
15630
14180
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
@@ -15644,7 +14194,7 @@ class ReplayContainer {
15644
14194
  stickySession: Boolean(this._options.stickySession),
15645
14195
  currentSession: this.session,
15646
14196
  sessionSampleRate: this._options.sessionSampleRate,
15647
- allowBuffering: this._options.errorSampleRate > 0,
14197
+ errorSampleRate: this._options.errorSampleRate,
15648
14198
  });
15649
14199
 
15650
14200
  // If session was newly created (i.e. was not loaded from storage), then
@@ -15661,7 +14211,7 @@ class ReplayContainer {
15661
14211
  this.session = session;
15662
14212
 
15663
14213
  if (!this.session.sampled) {
15664
- void this.stop('session unsampled');
14214
+ this.stop('session unsampled');
15665
14215
  return false;
15666
14216
  }
15667
14217
 
@@ -15676,7 +14226,6 @@ class ReplayContainer {
15676
14226
  WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange);
15677
14227
  WINDOW.addEventListener('blur', this._handleWindowBlur);
15678
14228
  WINDOW.addEventListener('focus', this._handleWindowFocus);
15679
- WINDOW.addEventListener('keydown', this._handleKeyboardEvent);
15680
14229
 
15681
14230
  // There is no way to remove these listeners, so ensure they are only added once
15682
14231
  if (!this._hasInitializedCoreListeners) {
@@ -15705,7 +14254,6 @@ class ReplayContainer {
15705
14254
 
15706
14255
  WINDOW.removeEventListener('blur', this._handleWindowBlur);
15707
14256
  WINDOW.removeEventListener('focus', this._handleWindowFocus);
15708
- WINDOW.removeEventListener('keydown', this._handleKeyboardEvent);
15709
14257
 
15710
14258
  if (this._performanceObserver) {
15711
14259
  this._performanceObserver.disconnect();
@@ -15756,11 +14304,6 @@ class ReplayContainer {
15756
14304
  this._doChangeToForegroundTasks(breadcrumb);
15757
14305
  };}
15758
14306
 
15759
- /** Ensure page remains active when a key is pressed. */
15760
- __init16() {this._handleKeyboardEvent = (event) => {
15761
- handleKeyboardEvent(this, event);
15762
- };}
15763
-
15764
14307
  /**
15765
14308
  * Tasks to run when we consider a page to be hidden (via blurring and/or visibility)
15766
14309
  */
@@ -15778,7 +14321,7 @@ class ReplayContainer {
15778
14321
  // Send replay when the page/tab becomes hidden. There is no reason to send
15779
14322
  // replay if it becomes visible, since no actions we care about were done
15780
14323
  // while it was hidden
15781
- void this.conditionalFlush();
14324
+ this._conditionalFlush();
15782
14325
  }
15783
14326
 
15784
14327
  /**
@@ -15792,7 +14335,7 @@ class ReplayContainer {
15792
14335
  const isSessionActive = this.checkAndHandleExpiredSession();
15793
14336
 
15794
14337
  if (!isSessionActive) {
15795
- // If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION
14338
+ // If the user has come back to the page within SESSION_IDLE_DURATION
15796
14339
  // ms, we will re-use the existing session, otherwise create a new
15797
14340
  // session
15798
14341
  (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
@@ -15840,7 +14383,7 @@ class ReplayContainer {
15840
14383
  _createCustomBreadcrumb(breadcrumb) {
15841
14384
  this.addUpdate(() => {
15842
14385
  void addEvent(this, {
15843
- type: EventType$1.Custom,
14386
+ type: EventType.Custom,
15844
14387
  timestamp: breadcrumb.timestamp || 0,
15845
14388
  data: {
15846
14389
  tag: 'breadcrumb',
@@ -15862,6 +14405,17 @@ class ReplayContainer {
15862
14405
  return Promise.all(createPerformanceSpans(this, createPerformanceEntries(entries)));
15863
14406
  }
15864
14407
 
14408
+ /**
14409
+ * Only flush if `this.recordingMode === 'session'`
14410
+ */
14411
+ _conditionalFlush() {
14412
+ if (this.recordingMode === 'error') {
14413
+ return;
14414
+ }
14415
+
14416
+ void this.flushImmediate();
14417
+ }
14418
+
15865
14419
  /**
15866
14420
  * Clear _context
15867
14421
  */
@@ -15870,35 +14424,22 @@ class ReplayContainer {
15870
14424
  this._context.errorIds.clear();
15871
14425
  this._context.traceIds.clear();
15872
14426
  this._context.urls = [];
15873
- }
15874
-
15875
- /** Update the initial timestamp based on the buffer content. */
15876
- _updateInitialTimestampFromEventBuffer() {
15877
- const { session, eventBuffer } = this;
15878
- if (!session || !eventBuffer) {
15879
- return;
15880
- }
15881
-
15882
- // we only ever update this on the initial segment
15883
- if (session.segmentId) {
15884
- return;
15885
- }
15886
-
15887
- const earliestEvent = eventBuffer.getEarliestTimestamp();
15888
- if (earliestEvent && earliestEvent < this._context.initialTimestamp) {
15889
- this._context.initialTimestamp = earliestEvent;
15890
- }
14427
+ this._context.earliestEvent = null;
15891
14428
  }
15892
14429
 
15893
14430
  /**
15894
14431
  * Return and clear _context
15895
14432
  */
15896
14433
  _popEventContext() {
14434
+ if (this._context.earliestEvent && this._context.earliestEvent < this._context.initialTimestamp) {
14435
+ this._context.initialTimestamp = this._context.earliestEvent;
14436
+ }
14437
+
15897
14438
  const _context = {
15898
14439
  initialTimestamp: this._context.initialTimestamp,
15899
14440
  initialUrl: this._context.initialUrl,
15900
- errorIds: Array.from(this._context.errorIds),
15901
- traceIds: Array.from(this._context.traceIds),
14441
+ errorIds: Array.from(this._context.errorIds).filter(Boolean),
14442
+ traceIds: Array.from(this._context.traceIds).filter(Boolean),
15902
14443
  urls: this._context.urls,
15903
14444
  };
15904
14445
 
@@ -15937,9 +14478,6 @@ class ReplayContainer {
15937
14478
  }
15938
14479
 
15939
14480
  try {
15940
- // This uses the data from the eventBuffer, so we need to call this before `finish()
15941
- this._updateInitialTimestampFromEventBuffer();
15942
-
15943
14481
  // Note this empties the event buffer regardless of outcome of sending replay
15944
14482
  const recordingData = await this.eventBuffer.finish();
15945
14483
 
@@ -15955,6 +14493,7 @@ class ReplayContainer {
15955
14493
  replayId,
15956
14494
  recordingData,
15957
14495
  segmentId,
14496
+ includeReplayStartTimestamp: segmentId === 0,
15958
14497
  eventContext,
15959
14498
  session: this.session,
15960
14499
  options: this.getOptions(),
@@ -15966,7 +14505,7 @@ class ReplayContainer {
15966
14505
  // This means we retried 3 times and all of them failed,
15967
14506
  // or we ran into a problem we don't want to retry, like rate limiting.
15968
14507
  // In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
15969
- void this.stop('sendReplay');
14508
+ this.stop('sendReplay');
15970
14509
 
15971
14510
  const client = getCurrentHub().getClient();
15972
14511
 
@@ -15980,12 +14519,8 @@ class ReplayContainer {
15980
14519
  * Flush recording data to Sentry. Creates a lock so that only a single flush
15981
14520
  * can be active at a time. Do not call this directly.
15982
14521
  */
15983
- __init17() {this._flush = async ({
15984
- force = false,
15985
- }
15986
-
15987
- = {}) => {
15988
- if (!this._isEnabled && !force) {
14522
+ __init16() {this._flush = async () => {
14523
+ if (!this._isEnabled) {
15989
14524
  // This can happen if e.g. the replay was stopped because of exceeding the retry limit
15990
14525
  return;
15991
14526
  }
@@ -16035,7 +14570,7 @@ class ReplayContainer {
16035
14570
  }
16036
14571
 
16037
14572
  /** Handler for rrweb.record.onMutation */
16038
- __init18() {this._onMutationHandler = (mutations) => {
14573
+ __init17() {this._onMutationHandler = (mutations) => {
16039
14574
  const count = mutations.length;
16040
14575
 
16041
14576
  const mutationLimit = this._options._experiments.mutationLimit || 0;
@@ -16169,8 +14704,6 @@ function isElectronNodeRenderer() {
16169
14704
  const MEDIA_SELECTORS =
16170
14705
  'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
16171
14706
 
16172
- const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
16173
-
16174
14707
  let _initialized = false;
16175
14708
 
16176
14709
  /**
@@ -16211,11 +14744,6 @@ class Replay {
16211
14744
  maskAllInputs = true,
16212
14745
  blockAllMedia = true,
16213
14746
 
16214
- networkDetailAllowUrls = [],
16215
- networkCaptureBodies = true,
16216
- networkRequestHeaders = [],
16217
- networkResponseHeaders = [],
16218
-
16219
14747
  mask = [],
16220
14748
  unmask = [],
16221
14749
  block = [],
@@ -16223,8 +14751,6 @@ class Replay {
16223
14751
  ignore = [],
16224
14752
  maskFn,
16225
14753
 
16226
- beforeAddRecordingEvent,
16227
-
16228
14754
  // eslint-disable-next-line deprecation/deprecation
16229
14755
  blockClass,
16230
14756
  // eslint-disable-next-line deprecation/deprecation
@@ -16276,14 +14802,6 @@ class Replay {
16276
14802
  errorSampleRate,
16277
14803
  useCompression,
16278
14804
  blockAllMedia,
16279
- maskAllInputs,
16280
- maskAllText,
16281
- networkDetailAllowUrls,
16282
- networkCaptureBodies,
16283
- networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
16284
- networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
16285
- beforeAddRecordingEvent,
16286
-
16287
14805
  _experiments,
16288
14806
  };
16289
14807
 
@@ -16337,7 +14855,14 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
16337
14855
  }
16338
14856
 
16339
14857
  /**
16340
- * Setup and initialize replay container
14858
+ * We previously used to create a transaction in `setupOnce` and it would
14859
+ * potentially create a transaction before some native SDK integrations have run
14860
+ * and applied their own global event processor. An example is:
14861
+ * https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
14862
+ *
14863
+ * So we call `replay.setup` in next event loop as a workaround to wait for other
14864
+ * global event processors to finish. This is no longer needed, but keeping it
14865
+ * here to avoid any future issues.
16341
14866
  */
16342
14867
  setupOnce() {
16343
14868
  if (!isBrowser()) {
@@ -16346,20 +14871,12 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
16346
14871
 
16347
14872
  this._setup();
16348
14873
 
16349
- // Once upon a time, we tried to create a transaction in `setupOnce` and it would
16350
- // potentially create a transaction before some native SDK integrations have run
16351
- // and applied their own global event processor. An example is:
16352
- // https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
16353
- //
16354
- // So we call `this._initialize()` in next event loop as a workaround to wait for other
16355
- // global event processors to finish. This is no longer needed, but keeping it
16356
- // here to avoid any future issues.
16357
- setTimeout(() => this._initialize());
14874
+ // XXX: See method comments above
14875
+ setTimeout(() => this.start());
16358
14876
  }
16359
14877
 
16360
14878
  /**
16361
- * Start a replay regardless of sampling rate. Calling this will always
16362
- * create a new session. Will throw an error if replay is already in progress.
14879
+ * Initializes the plugin.
16363
14880
  *
16364
14881
  * Creates or loads a session, attaches listeners to varying events (DOM,
16365
14882
  * PerformanceObserver, Recording, Sentry SDK, etc)
@@ -16372,64 +14889,27 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
16372
14889
  this._replay.start();
16373
14890
  }
16374
14891
 
16375
- /**
16376
- * Start replay buffering. Buffers until `flush()` is called or, if
16377
- * `replaysOnErrorSampleRate` > 0, until an error occurs.
16378
- */
16379
- startBuffering() {
16380
- if (!this._replay) {
16381
- return;
16382
- }
16383
-
16384
- this._replay.startBuffering();
16385
- }
16386
-
16387
14892
  /**
16388
14893
  * Currently, this needs to be manually called (e.g. for tests). Sentry SDK
16389
14894
  * does not support a teardown
16390
14895
  */
16391
14896
  stop() {
16392
14897
  if (!this._replay) {
16393
- return Promise.resolve();
16394
- }
16395
-
16396
- return this._replay.stop();
16397
- }
16398
-
16399
- /**
16400
- * If not in "session" recording mode, flush event buffer which will create a new replay.
16401
- * Unless `continueRecording` is false, the replay will continue to record and
16402
- * behave as a "session"-based replay.
16403
- *
16404
- * Otherwise, queue up a flush.
16405
- */
16406
- flush(options) {
16407
- if (!this._replay || !this._replay.isEnabled()) {
16408
- return Promise.resolve();
14898
+ return;
16409
14899
  }
16410
14900
 
16411
- return this._replay.sendBufferedReplayOrFlush(options);
14901
+ this._replay.stop();
16412
14902
  }
16413
14903
 
16414
14904
  /**
16415
- * Get the current session ID.
14905
+ * Immediately send all pending events.
16416
14906
  */
16417
- getReplayId() {
14907
+ flush() {
16418
14908
  if (!this._replay || !this._replay.isEnabled()) {
16419
14909
  return;
16420
14910
  }
16421
14911
 
16422
- return this._replay.getSessionId();
16423
- }
16424
- /**
16425
- * Initializes replay.
16426
- */
16427
- _initialize() {
16428
- if (!this._replay) {
16429
- return;
16430
- }
16431
-
16432
- this._replay.initializeSampling();
14912
+ return this._replay.flushImmediate();
16433
14913
  }
16434
14914
 
16435
14915
  /** Setup the integration. */
@@ -16480,10 +14960,6 @@ function loadReplayOptionsFromClient(initialOptions) {
16480
14960
  return finalOptions;
16481
14961
  }
16482
14962
 
16483
- function _getMergedNetworkHeaders(headers) {
16484
- return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
16485
- }
16486
-
16487
14963
  /**
16488
14964
  * Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values,
16489
14965
  * descriptors, and functions.
@@ -16921,9 +15397,6 @@ class Postgres {
16921
15397
  const span = _optionalChain([parentSpan, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
16922
15398
  description: typeof config === 'string' ? config : (config ).text,
16923
15399
  op: 'db',
16924
- data: {
16925
- 'db.system': 'postgresql',
16926
- },
16927
15400
  })]);
16928
15401
 
16929
15402
  if (typeof callback === 'function') {
@@ -17000,9 +15473,6 @@ class Mysql {constructor() { Mysql.prototype.__init.call(this); }
17000
15473
  const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
17001
15474
  description: typeof options === 'string' ? options : (options ).sql,
17002
15475
  op: 'db',
17003
- data: {
17004
- 'db.system': 'mysql',
17005
- },
17006
15476
  })]);
17007
15477
 
17008
15478
  if (typeof callback === 'function') {
@@ -17224,7 +15694,6 @@ class Mongo {
17224
15694
  collectionName: collection.collectionName,
17225
15695
  dbName: collection.dbName,
17226
15696
  namespace: collection.namespace,
17227
- 'db.system': 'mongodb',
17228
15697
  };
17229
15698
  const spanContext = {
17230
15699
  op: 'db',
@@ -17311,15 +15780,31 @@ class Prisma {
17311
15780
  }
17312
15781
 
17313
15782
  this._client.$use((params, next) => {
15783
+ const scope = getCurrentHub().getScope();
15784
+ const parentSpan = _optionalChain([scope, 'optionalAccess', _2 => _2.getSpan, 'call', _3 => _3()]);
15785
+
17314
15786
  const action = params.action;
17315
15787
  const model = params.model;
17316
- return trace(
17317
- { name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
17318
- () => next(params),
17319
- );
15788
+
15789
+ const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
15790
+ description: model ? `${model} ${action}` : action,
15791
+ op: 'db.sql.prisma',
15792
+ })]);
15793
+
15794
+ const rv = next(params);
15795
+
15796
+ if (isThenable(rv)) {
15797
+ return rv.then((res) => {
15798
+ _optionalChain([span, 'optionalAccess', _6 => _6.finish, 'call', _7 => _7()]);
15799
+ return res;
15800
+ });
15801
+ }
15802
+
15803
+ _optionalChain([span, 'optionalAccess', _8 => _8.finish, 'call', _9 => _9()]);
15804
+ return rv;
17320
15805
  });
17321
15806
  }
17322
- } Prisma.__initStatic();
15807
+ }Prisma.__initStatic();
17323
15808
 
17324
15809
  /** Tracing integration for graphql package */
17325
15810
  class GraphQL {constructor() { GraphQL.prototype.__init.call(this); }
@@ -25651,6 +24136,7 @@ var STATES$5;
25651
24136
  STATES["RE_INIT_RECORDER__NEXT_QUESTION"] = "reInitRecorderNextQuestion";
25652
24137
  STATES["UPLOADING"] = "uploading";
25653
24138
  STATES["CONFIRM"] = "confirm";
24139
+ STATES["CONFIRM_WATING"] = "confirmWaiting";
25654
24140
  STATES["FINISHED"] = "finished";
25655
24141
  STATES["ERROR"] = "error";
25656
24142
  })(STATES$5 || (STATES$5 = {}));
@@ -25704,6 +24190,7 @@ var ACTIONS$6;
25704
24190
  ACTIONS["RESET_FAILED_RECORDING_ATTEMPTS"] = "resetFailedRecordingAttempts";
25705
24191
  ACTIONS["CLEAR_VIDEO_ERROR"] = "clearVideoError";
25706
24192
  ACTIONS["UPDATE_VIDEO_DIMENSIONS"] = "updateVideoDimensions";
24193
+ ACTIONS["UPDATE_UPLOADED_FALSE_COUNT"] = "updateUploadedFalseCount";
25707
24194
  })(ACTIONS$6 || (ACTIONS$6 = {}));
25708
24195
  var EVENTS$5;
25709
24196
  (function (EVENTS) {
@@ -25759,6 +24246,7 @@ var GUARDS$3;
25759
24246
  GUARDS["IS_RECORDER_READY"] = "isRecorderReady";
25760
24247
  GUARDS["IS_ASSESSMENT_QUESTION"] = "isAssessmentQuestion";
25761
24248
  GUARDS["IS_TIMES_UP"] = "isTimesUp";
24249
+ GUARDS["SHOULD_TRY_TO_CONFIRM"] = "shouldTryToConfirm";
25762
24250
  })(GUARDS$3 || (GUARDS$3 = {}));
25763
24251
  var TAGS;
25764
24252
  (function (TAGS) {
@@ -25768,6 +24256,7 @@ var TAGS;
25768
24256
  TAGS["DISPLAY_OUTER_VIEW"] = "displayOuterView";
25769
24257
  TAGS["DISPLAY_QUESTION"] = "displayQuestion";
25770
24258
  TAGS["DISPLAY_QUESTIONS_LIST"] = "displayQuestionsList";
24259
+ TAGS["DISPLAY_UPLOAD"] = "displayUpload";
25771
24260
  TAGS["LOADING"] = "loading";
25772
24261
  })(TAGS || (TAGS = {}));
25773
24262
 
@@ -30489,7 +28978,7 @@ const configGenerator = () => {
30489
28978
  let release;
30490
28979
  try {
30491
28980
  environment !== null && environment !== void 0 ? environment : (environment = "staging");
30492
- release !== null && release !== void 0 ? release : (release = "1.1.23-binary-check-one");
28981
+ release !== null && release !== void 0 ? release : (release = "1.1.23-binary-002");
30493
28982
  }
30494
28983
  catch (_a) {
30495
28984
  console.error('sentry configGenerator error');
@@ -30962,6 +29451,7 @@ const SECONDS_LEFT_HIGHLIGHT = 10;
30962
29451
  const DEFAULT_ASSESSMENT_MAX_CHARS = 300;
30963
29452
  const DEFAULT_ASSESSMENT_DURATION = 0;
30964
29453
  const DEFAULT_VIDEO_DIMENSIONS = { width: 1280, height: 720 }; // Transcoder default dimensions (720p)
29454
+ const MAX_CONFIRM_ATTEMPTS = 5;
30965
29455
  // Font
30966
29456
  const FONT_URL = 'https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600;700&display=swap';
30967
29457
  var RETAKE_SPEED;
@@ -35122,8 +33612,8 @@ function memoizeOne(resultFn, isEqual) {
35122
33612
  }
35123
33613
 
35124
33614
  var memoizeOne_esm = /*#__PURE__*/Object.freeze({
35125
- __proto__: null,
35126
- 'default': memoizeOne
33615
+ __proto__: null,
33616
+ 'default': memoizeOne
35127
33617
  });
35128
33618
 
35129
33619
  var require$$2 = /*@__PURE__*/getAugmentedNamespace(memoizeOne_esm);
@@ -39083,6 +37573,11 @@ var EVENT_TYPES;
39083
37573
  EVENT_TYPES["SOUND_RESTORED"] = "soundRestored";
39084
37574
  EVENT_TYPES["TIMES_UP"] = "timesUp";
39085
37575
  EVENT_TYPES["COMPLETED_INTERVIEW"] = "completedInterview";
37576
+ EVENT_TYPES["RECONNECTED"] = "reconnected";
37577
+ EVENT_TYPES["CONFIRM_UPLOADED_FAILED"] = "confirmUploadedFailed";
37578
+ EVENT_TYPES["FINISHED"] = "finished";
37579
+ EVENT_TYPES["ON_FINISH_SUCCEED"] = "onFinishSucceed";
37580
+ EVENT_TYPES["ON_FINISH_FAILED"] = "onFinishFailed";
39086
37581
  })(EVENT_TYPES || (EVENT_TYPES = {}));
39087
37582
  let event_id;
39088
37583
  const updateEventId = (eventId) => { event_id = eventId; };
@@ -39632,31 +38127,6 @@ const Setup = ({ widgetMachine, sendToWidget, isPracticeDisabled, recordWithoutV
39632
38127
  React__default["default"].createElement(C, { className: startButtonClassNames, color: "special", backgroundColor: "white", onClick: () => sendToWidget(EVENTS$5.QUESTION_MODE), disabled: !canStartInterview }, t(isResumed ? 'welcome.resumeInterview' : 'buttons.btn_start').toUpperCase()))));
39633
38128
  };
39634
38129
 
39635
- /*! *****************************************************************************
39636
- Copyright (c) Microsoft Corporation.
39637
-
39638
- Permission to use, copy, modify, and/or distribute this software for any
39639
- purpose with or without fee is hereby granted.
39640
-
39641
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
39642
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39643
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
39644
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39645
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
39646
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
39647
- PERFORMANCE OF THIS SOFTWARE.
39648
- ***************************************************************************** */
39649
-
39650
- function __awaiter(thisArg, _arguments, P, generator) {
39651
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
39652
- return new (P || (P = Promise))(function (resolve, reject) {
39653
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39654
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
39655
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
39656
- step((generator = generator.apply(thisArg, _arguments || [])).next());
39657
- });
39658
- }
39659
-
39660
38130
  const uploadToS3 = (url, data, onProgress, timeout = 0) => s3AxiosInstance.put(url, data, {
39661
38131
  headers: { 'Content-Type': 'video/webm' }, onUploadProgress: onProgress, timeout,
39662
38132
  });
@@ -39727,8 +38197,8 @@ const OuterView = ({ widgetMachine, sendToWidget, recorderRef }) => {
39727
38197
  const isQuestionDisplayed = widgetMachine.hasTag(TAGS.DISPLAY_QUESTION) || (isVideoQuestionState && !currentQuestionObj.thinkingTime);
39728
38198
  const isPreviewState = widgetMachine.matches(STATES$5.PREVIEW);
39729
38199
  const isUploadingState = widgetMachine.matches(STATES$5.UPLOADING);
39730
- const isConfirmState = widgetMachine.matches(STATES$5.CONFIRM);
39731
38200
  const isQuestionsListDisplayed = widgetMachine.hasTag(TAGS.DISPLAY_QUESTIONS_LIST);
38201
+ const isUploadDisplayed = widgetMachine.hasTag(TAGS.DISPLAY_UPLOAD);
39732
38202
  const isRecording = recorderMachine.matches({ [STATES$6.RECORDING]: STATES$6.COLLECTING_BLOBS });
39733
38203
  const isCountDown = recorderMachine.matches({ [STATES$6.RECORDING]: STATES$6.COUNT_DOWN });
39734
38204
  const isPracticeMode = recordingType === TAKE_TYPES.PRACTICE;
@@ -39746,7 +38216,7 @@ const OuterView = ({ widgetMachine, sendToWidget, recorderRef }) => {
39746
38216
  isSetupState && React__default["default"].createElement(Setup, { recordWithoutVideo: recordWithoutVideo, widgetMachine: widgetMachine, sendToWidget: sendToWidget, isPracticeDisabled: !!config.disablePractice }),
39747
38217
  isQuestionsListDisplayed && React__default["default"].createElement(QuestionsList, { questions: questions, currentQuestion: currentQuestion, isPracticeMode: isPracticeMode, questionsStatus: questionsStatus }),
39748
38218
  isQuestionDisplayed && React__default["default"].createElement(Question, { questionObj: currentQuestionObj }),
39749
- (isUploadingState || isConfirmState) && (React__default["default"].createElement(Upload, { isConnected: isConnected, totalFileSize: totalFileSize, totalUploadedFilesSize: totalUploadedFilesSize, totalUploadSpeed: totalUploadSpeed }))));
38219
+ isUploadDisplayed && (React__default["default"].createElement(Upload, { isConnected: isConnected, totalFileSize: totalFileSize, totalUploadedFilesSize: totalUploadedFilesSize, totalUploadSpeed: totalUploadSpeed }))));
39750
38220
  };
39751
38221
 
39752
38222
  var actions = {};
@@ -43575,9 +42045,7 @@ var AsapAction = (function (_super) {
43575
42045
  var actions = scheduler.actions;
43576
42046
  if (id != null && ((_a = actions[actions.length - 1]) === null || _a === void 0 ? void 0 : _a.id) !== id) {
43577
42047
  immediateProvider.clearImmediate(id);
43578
- if (scheduler._scheduled === id) {
43579
- scheduler._scheduled = undefined;
43580
- }
42048
+ scheduler._scheduled = undefined;
43581
42049
  }
43582
42050
  return undefined;
43583
42051
  };
@@ -44843,7 +43311,7 @@ const accUploaderMachine = createMachine({
44843
43311
  actions: [ACTIONS$2.SENTRY],
44844
43312
  },
44845
43313
  {
44846
- actions: [ACTIONS$2.SET_UPLOADED, ACTIONS$2.SENTRY],
43314
+ actions: [ACTIONS$2.SENTRY],
44847
43315
  target: `#uploader.${STATES$2.UPLOADED}`, // In case the video already uploaded
44848
43316
  },
44849
43317
  ],
@@ -44860,7 +43328,6 @@ const accUploaderMachine = createMachine({
44860
43328
  id: 'uploadToS3',
44861
43329
  src: ({ signedUrl, file }) => (callback) => uploadToS3(signedUrl, file, callback),
44862
43330
  onDone: {
44863
- // actions: [ACTIONS.SET_UPLOADED],
44864
43331
  target: `#uploader.${STATES$2.UPLOADED}`,
44865
43332
  },
44866
43333
  onError: {
@@ -45216,10 +43683,14 @@ const accWidgetMachine = createMachine({
45216
43683
  failedRecordingMessage: VIDEO_CORRUPTED_STATES.NO_ERROR,
45217
43684
  isResumed: false,
45218
43685
  videoDimensions: DEFAULT_VIDEO_DIMENSIONS,
43686
+ confirmUploadedFalseCount: 0,
45219
43687
  },
45220
43688
  on: {
45221
43689
  [EVENTS$1.CONNECTION_CHANGED]: {
45222
- actions: [ACTIONS$6.SET_CONNECTION],
43690
+ actions: [
43691
+ ACTIONS$6.SET_CONNECTION,
43692
+ { type: ACTIONS$6.EMIT_TRACKING_EVENT, data: { eventType: EVENT_TYPES.RECONNECTED } },
43693
+ ],
45223
43694
  },
45224
43695
  [EVENTS$5.UPLOADER_PROGRESS]: {
45225
43696
  actions: [ACTIONS$6.UPDATE_TOTAL_UPLOADED_FILES_SIZE],
@@ -45746,7 +44217,7 @@ const accWidgetMachine = createMachine({
45746
44217
  },
45747
44218
  },
45748
44219
  [STATES$5.UPLOADING]: {
45749
- tags: [TAGS.DISPLAY_OUTER_VIEW],
44220
+ tags: [TAGS.DISPLAY_OUTER_VIEW, TAGS.DISPLAY_UPLOAD],
45750
44221
  entry: [
45751
44222
  { type: ACTIONS$6.SESSION_EVENT, data: { event: 'widget_completed', type: 'date' } },
45752
44223
  { type: ACTIONS$6.CONSOLE_DEBUG, data: { message: DEBUG.UPLOADING_STATE } },
@@ -45760,30 +44231,57 @@ const accWidgetMachine = createMachine({
45760
44231
  },
45761
44232
  },
45762
44233
  },
44234
+ [STATES$5.CONFIRM_WATING]: {
44235
+ tags: [TAGS.DISPLAY_OUTER_VIEW, TAGS.DISPLAY_UPLOAD],
44236
+ always: {
44237
+ target: STATES$5.CONFIRM,
44238
+ cond: GUARDS$3.IS_CONNECTED,
44239
+ },
44240
+ },
45763
44241
  [STATES$5.CONFIRM]: {
45764
- tags: [TAGS.DISPLAY_OUTER_VIEW],
44242
+ tags: [TAGS.DISPLAY_OUTER_VIEW, TAGS.DISPLAY_UPLOAD],
45765
44243
  invoke: {
45766
44244
  id: 'getVideo',
45767
44245
  src: (context) => { var _a; return getVideo(((_a = context.widgetConfig.video) === null || _a === void 0 ? void 0 : _a.video_id) || ''); },
45768
- onDone: {
45769
- target: STATES$5.FINISHED,
45770
- cond: (_, event) => !!event.data.data.data.video.uploaded,
45771
- },
44246
+ onDone: [
44247
+ {
44248
+ target: STATES$5.FINISHED,
44249
+ cond: (_, event) => !!event.data.data.data.video.uploaded,
44250
+ },
44251
+ {
44252
+ actions: [
44253
+ ACTIONS$6.UPDATE_UPLOADED_FALSE_COUNT,
44254
+ { type: ACTIONS$6.SENTRY, data: { eventName: 'CONFIRM::UPLOADED_FALSE' } },
44255
+ ],
44256
+ target: STATES$5.CONFIRM_WATING,
44257
+ cond: GUARDS$3.SHOULD_TRY_TO_CONFIRM,
44258
+ },
44259
+ {
44260
+ actions: [
44261
+ { type: ACTIONS$6.SET_VIDEO_ERROR, data: { errorMessage: 'Error, Please contact support' } },
44262
+ { type: ACTIONS$6.EMIT_TRACKING_EVENT, data: { eventType: EVENT_TYPES.CONFIRM_UPLOADED_FAILED } },
44263
+ ],
44264
+ target: STATES$5.ERROR,
44265
+ },
44266
+ ],
45772
44267
  onError: [
45773
44268
  {
45774
- actions: [() => console.error('UPDATE_VIDEO_UPLADED_ERROR:'), console.error, ACTIONS$6.SENTRY],
44269
+ actions: [() => console.error('UPDATE_VIDEO_UPLADED_ERROR:'), console.error, { type: ACTIONS$6.SENTRY, data: { eventName: 'CONFIRM::ERROR__NOT_FOUND' } }],
45775
44270
  target: STATES$5.FINISHED,
45776
44271
  cond: (_, event) => event.data.response.status === STATUS_CODES.NOT_FOUND,
45777
44272
  },
45778
44273
  {
45779
- actions: [ACTIONS$6.SENTRY],
45780
- target: STATES$5.CONFIRM,
44274
+ actions: [() => console.error('UPDATE_VIDEO_UPLADED_ERROR:'), console.error, { type: ACTIONS$6.SENTRY, data: { eventName: 'CONFIRM::ERROR' } }],
44275
+ target: STATES$5.CONFIRM_WATING,
45781
44276
  },
45782
44277
  ],
45783
44278
  },
45784
44279
  },
45785
44280
  [STATES$5.FINISHED]: {
45786
- entry: [{ type: ACTIONS$6.CONSOLE_DEBUG, data: { message: DEBUG.INTERVIEW_SUBMITTED } }],
44281
+ entry: [
44282
+ { type: ACTIONS$6.CONSOLE_DEBUG, data: { message: DEBUG.INTERVIEW_SUBMITTED } },
44283
+ { type: ACTIONS$6.EMIT_TRACKING_EVENT, data: { eventType: EVENT_TYPES.FINISHED } },
44284
+ ],
45787
44285
  type: 'final',
45788
44286
  },
45789
44287
  [STATES$5.ERROR]: {
@@ -45979,9 +44477,12 @@ const accWidgetMachine = createMachine({
45979
44477
  widgetConfig: Object.assign(Object.assign({}, widgetConfig), { video: Object.assign(Object.assign({}, widgetConfig.video), { videos: (_b = (_a = widgetConfig.video) === null || _a === void 0 ? void 0 : _a.videos) === null || _b === void 0 ? void 0 : _b.map((video, idx) => ((idx !== questionNumber - 1) ? video : videoFile)) }) }),
45980
44478
  });
45981
44479
  }),
45982
- [ACTIONS$6.SET_VIDEO_ERROR]: assign$2((_, event) => ({
45983
- error: event.data.response.data || { errorMessage: event.data.message },
45984
- })),
44480
+ [ACTIONS$6.SET_VIDEO_ERROR]: assign$2((_, event, meta) => {
44481
+ var _a, _b, _c, _d;
44482
+ return ({
44483
+ error: ((_b = (_a = event.data) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.data) || { errorMessage: ((_c = event.data) === null || _c === void 0 ? void 0 : _c.message) || ((_d = meta.action.data) === null || _d === void 0 ? void 0 : _d.errorMessage) },
44484
+ });
44485
+ }),
45985
44486
  [ACTIONS$6.REVOKE_MEMORY]: send$2((_, event) => ({ type: EVENTS$4.REMOVE_TAKES, data: { questionToRemove: event.data.questionNumber } }), { to: ({ storageRef }) => storageRef }),
45986
44487
  [ACTIONS$6.UPDATE_VIDEO_OBJECT]: assign$2(({ widgetConfig, recordingType }) => {
45987
44488
  var _a, _b;
@@ -46015,6 +44516,9 @@ const accWidgetMachine = createMachine({
46015
44516
  height: event.data.height,
46016
44517
  },
46017
44518
  })),
44519
+ [ACTIONS$6.UPDATE_UPLOADED_FALSE_COUNT]: assign$2(({ confirmUploadedFalseCount }) => ({
44520
+ confirmUploadedFalseCount: confirmUploadedFalseCount + 1,
44521
+ })),
46018
44522
  },
46019
44523
  services: {
46020
44524
  [SERVICES$1.UPDATE_VIDEO_OBJECT_CALL]: ({ widgetConfig: { video }, recordingType, speedTestResult }, event, meta) => (callback, onReceive) => {
@@ -46058,6 +44562,7 @@ const accWidgetMachine = createMachine({
46058
44562
  [GUARDS$3.IS_RECORDER_READY]: ({ recorderRef }) => (recorderRef === null || recorderRef === void 0 ? void 0 : recorderRef.getSnapshot().value) === STATES$6.IDLE,
46059
44563
  [GUARDS$3.IS_ASSESSMENT_QUESTION]: ({ questions, currentQuestion }) => !!questions[currentQuestion - 1].answerType && questions[currentQuestion - 1].answerType !== ANSWER_TYPES.VIDEO,
46060
44564
  [GUARDS$3.IS_TIMES_UP]: (_, event) => !!event.data.isTimesUp,
44565
+ [GUARDS$3.SHOULD_TRY_TO_CONFIRM]: ({ confirmUploadedFalseCount }) => confirmUploadedFalseCount <= MAX_CONFIRM_ATTEMPTS,
46061
44566
  },
46062
44567
  });
46063
44568
 
@@ -48580,10 +47085,25 @@ const Main = ({ widgetConfig, setShouldShowWaterMark, myinterviewRef, isWidgetMi
48580
47085
  React.useEffect(() => {
48581
47086
  setShouldShowWaterMark(!!(company === null || company === void 0 ? void 0 : company.shouldShowWaterMark));
48582
47087
  }, [company === null || company === void 0 ? void 0 : company.shouldShowWaterMark]);
47088
+ const _onFinish = () => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; return (_b = (_a = widgetConfig.config).onFinish) === null || _b === void 0 ? void 0 : _b.call(_a, { redirectUrl: candidate.redirectUrl, video_id: (video === null || video === void 0 ? void 0 : video.video_id) || '' }); });
48583
47089
  React.useEffect(() => {
48584
- var _a, _b;
48585
47090
  if (machine.done) {
48586
- (_b = (_a = widgetConfig.config).onFinish) === null || _b === void 0 ? void 0 : _b.call(_a, { redirectUrl: candidate.redirectUrl, video_id: (video === null || video === void 0 ? void 0 : video.video_id) || '' });
47091
+ if (widgetConfig.config.onFinish) {
47092
+ _onFinish().then(() => {
47093
+ emitTrackEvent({ eventType: EVENT_TYPES.ON_FINISH_SUCCEED });
47094
+ }).catch((err) => {
47095
+ var _a;
47096
+ let errorMessage = '';
47097
+ try {
47098
+ errorMessage = (err === null || err === void 0 ? void 0 : err.message) || (err === null || err === void 0 ? void 0 : err.msg) || ((_a = err === null || err === void 0 ? void 0 : err.data) === null || _a === void 0 ? void 0 : _a.message);
47099
+ }
47100
+ catch (_b) {
47101
+ //
47102
+ }
47103
+ emitTrackEvent({ eventType: EVENT_TYPES.ON_FINISH_FAILED, extraData: { errorMessage } });
47104
+ throw err;
47105
+ });
47106
+ }
48587
47107
  }
48588
47108
  }, [machine.done]);
48589
47109
  React.useEffect(() => {
@@ -48599,11 +47119,16 @@ const Main = ({ widgetConfig, setShouldShowWaterMark, myinterviewRef, isWidgetMi
48599
47119
  });
48600
47120
  }
48601
47121
  }, [candidate, job === null || job === void 0 ? void 0 : job.language]);
47122
+ const setBackgroundOpacity = () => {
47123
+ var _a;
47124
+ (_a = myinterviewRef === null || myinterviewRef === void 0 ? void 0 : myinterviewRef.current) === null || _a === void 0 ? void 0 : _a.style.setProperty('--myinterview-background-opacity', isLoading || isErrorState ? '0' : '1');
47125
+ };
48602
47126
  React.useEffect(() => {
48603
47127
  var _a, _b;
48604
47128
  if (isErrorState && (error === null || error === void 0 ? void 0 : error.statusCode) === 400) {
48605
47129
  (_b = (_a = widgetConfig.config).onError) === null || _b === void 0 ? void 0 : _b.call(_a, { messageType: 'applied' });
48606
47130
  }
47131
+ setBackgroundOpacity();
48607
47132
  }, [isErrorState]);
48608
47133
  const isResumed = React.useMemo(() => { var _a, _b; return !!((_b = (_a = widgetConfig.video) === null || _a === void 0 ? void 0 : _a.videos) === null || _b === void 0 ? void 0 : _b.some((v) => v.uploaded)); }, [widgetConfig.video]);
48609
47134
  const handleScroll = (e) => {
@@ -48613,8 +47138,7 @@ const Main = ({ widgetConfig, setShouldShowWaterMark, myinterviewRef, isWidgetMi
48613
47138
  (_b = viewsRef === null || viewsRef === void 0 ? void 0 : viewsRef.current) === null || _b === void 0 ? void 0 : _b.style.setProperty('--myinterview-widget-practice-opacity', scrollTop > 10 ? '0' : '1');
48614
47139
  };
48615
47140
  React.useEffect(() => {
48616
- var _a;
48617
- (_a = myinterviewRef === null || myinterviewRef === void 0 ? void 0 : myinterviewRef.current) === null || _a === void 0 ? void 0 : _a.style.setProperty('--myinterview-background-opacity', isLoading || isErrorState ? '0' : '1');
47141
+ setBackgroundOpacity();
48618
47142
  }, [isLoading]);
48619
47143
  const onRetry = () => {
48620
47144
  send(EVENTS$5.RETRY);
@@ -48812,15 +47336,15 @@ const Widget = ({ candidate, job, video, config, disabled = false, buttonText =
48812
47336
  revertBodyStyling();
48813
47337
  setIsWidgetOpen(false);
48814
47338
  };
48815
- const onInterviewCompleted = (data) => {
47339
+ const onInterviewCompleted = (data) => __awaiter(void 0, void 0, void 0, function* () {
48816
47340
  var _a;
48817
- (_a = config.onFinish) === null || _a === void 0 ? void 0 : _a.call(config, data);
48818
47341
  onCloseWidget();
48819
- };
47342
+ yield ((_a = config.onFinish) === null || _a === void 0 ? void 0 : _a.call(config, data));
47343
+ });
48820
47344
  const onError = (data) => {
48821
47345
  var _a;
48822
- (_a = config.onError) === null || _a === void 0 ? void 0 : _a.call(config, data);
48823
47346
  onCloseWidget();
47347
+ (_a = config.onError) === null || _a === void 0 ? void 0 : _a.call(config, data);
48824
47348
  };
48825
47349
  const openWidget = () => {
48826
47350
  var _a;