@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/components/CountDown.d.ts +2 -2
- package/dist/cjs/components/Counter.d.ts +2 -2
- package/dist/cjs/components/DeviceSelector.d.ts +1 -1
- package/dist/cjs/index.js +886 -2362
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/widgetInterface.d.ts +7 -2
- package/dist/cjs/services/event.service.d.ts +6 -1
- package/dist/cjs/utils/constants.utils.d.ts +1 -0
- package/dist/esm/components/CountDown.d.ts +2 -2
- package/dist/esm/components/Counter.d.ts +2 -2
- package/dist/esm/components/DeviceSelector.d.ts +1 -1
- package/dist/esm/index.js +872 -2348
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces/widgetInterface.d.ts +7 -2
- package/dist/esm/services/event.service.d.ts +6 -1
- package/dist/esm/utils/constants.utils.d.ts +1 -0
- package/package.json +64 -64
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
/**
|
|
400
|
-
|
|
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
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
510
|
+
return;
|
|
553
511
|
}
|
|
554
512
|
|
|
555
513
|
const { port, projectId, protocol } = dsn;
|
|
556
514
|
|
|
557
515
|
const requiredComponents = ['protocol', 'publicKey', 'host', 'projectId'];
|
|
558
|
-
|
|
516
|
+
requiredComponents.forEach(component => {
|
|
559
517
|
if (!dsn[component]) {
|
|
560
|
-
|
|
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
|
-
|
|
572
|
-
return false;
|
|
523
|
+
throw new SentryError(`Invalid Sentry Dsn: Invalid projectId ${projectId}`);
|
|
573
524
|
}
|
|
574
525
|
|
|
575
526
|
if (!isValidProtocol(protocol)) {
|
|
576
|
-
|
|
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
|
-
|
|
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
|
-
|
|
595
|
-
return undefined;
|
|
596
|
-
}
|
|
540
|
+
validateDsn(components);
|
|
597
541
|
return components;
|
|
598
542
|
}
|
|
599
543
|
|
|
600
|
-
/**
|
|
601
|
-
|
|
602
|
-
/** Display name of this error instance. */
|
|
544
|
+
/** Prefix for logging strings */
|
|
545
|
+
const PREFIX = 'Sentry Logger ';
|
|
603
546
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1446
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
//
|
|
2142
|
-
//
|
|
2143
|
-
//
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
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 (
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
...(
|
|
3038
|
-
|
|
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
|
|
3745
|
-
if (
|
|
3746
|
-
event.
|
|
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
|
-
|
|
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
|
|
4252
|
-
client.captureSession
|
|
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
|
-
|
|
4926
|
-
const
|
|
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.
|
|
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
|
-
//
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
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[
|
|
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
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
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 || !
|
|
6545
|
+
if (!startTimestamp || !endTimestamp || !handlerData.xhr.__sentry_xhr__) {
|
|
6690
6546
|
return;
|
|
6691
6547
|
}
|
|
6692
6548
|
|
|
6693
|
-
const { method, url, status_code, body } =
|
|
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 (?:(
|
|
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*(.*?)(?:\((.*?)\))?(?:^|@)?((?:
|
|
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 =
|
|
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
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
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
|
|
8323
|
-
const
|
|
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
|
|
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
|
|
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
|
|
8344
|
-
const NETWORK_BODY_MAX_SIZE =
|
|
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('
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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('
|
|
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
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
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 =
|
|
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:
|
|
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
|
|
11285
|
-
!(e.type === EventType
|
|
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
|
|
11063
|
+
if (e.type === EventType.FullSnapshot) {
|
|
11291
11064
|
lastFullSnapshotEvent = e;
|
|
11292
11065
|
incrementalSnapshotCount = 0;
|
|
11293
11066
|
}
|
|
11294
|
-
else if (e.type === EventType
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11227
|
+
type: EventType.IncrementalSnapshot,
|
|
11455
11228
|
data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
|
|
11456
11229
|
})),
|
|
11457
11230
|
inputCb: (v) => wrappedEmit(wrapEvent({
|
|
11458
|
-
type: EventType
|
|
11231
|
+
type: EventType.IncrementalSnapshot,
|
|
11459
11232
|
data: Object.assign({ source: IncrementalSource.Input }, v),
|
|
11460
11233
|
})),
|
|
11461
11234
|
mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
|
|
11462
|
-
type: EventType
|
|
11235
|
+
type: EventType.IncrementalSnapshot,
|
|
11463
11236
|
data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
|
|
11464
11237
|
})),
|
|
11465
11238
|
styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
|
|
11466
|
-
type: EventType
|
|
11239
|
+
type: EventType.IncrementalSnapshot,
|
|
11467
11240
|
data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
|
|
11468
11241
|
})),
|
|
11469
11242
|
styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
|
|
11470
|
-
type: EventType
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
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.
|
|
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 `
|
|
12633
|
-
isExpired(session.lastActivity, timeouts.
|
|
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,
|
|
12694
|
-
return isSampled(sessionSampleRate) ? 'session' :
|
|
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,
|
|
12703
|
-
const sampled = getSessionSampleType(sessionSampleRate,
|
|
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
|
-
|
|
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 (
|
|
12765
|
-
//
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
12097
|
+
// Trigger error recording
|
|
12843
12098
|
// Need to be very careful that this does not cause an infinite loop
|
|
12844
|
-
if (
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
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
|
-
//
|
|
12946
|
-
|
|
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
|
|
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
|
-
|
|
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 } =
|
|
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
|
-
/**
|
|
13674
|
-
function
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
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
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
12715
|
+
if (bodySize < NETWORK_BODY_MAX_SIZE) {
|
|
12716
|
+
info.body = body;
|
|
12717
|
+
} else {
|
|
13715
12718
|
info._meta = {
|
|
13716
|
-
|
|
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
|
|
12787
|
+
status_code: statusCode,
|
|
13874
12788
|
request_body_size: requestBodySize,
|
|
13875
12789
|
response_body_size: responseBodySize,
|
|
13876
12790
|
} = breadcrumb.data;
|
|
13877
12791
|
|
|
13878
|
-
const
|
|
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
|
-
{
|
|
12807
|
+
{ captureBodies },
|
|
13898
12808
|
input,
|
|
13899
12809
|
requestBodySize,
|
|
13900
12810
|
) {
|
|
13901
|
-
|
|
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
|
|
13910
|
-
return buildNetworkRequestOrResponse(
|
|
12817
|
+
const body = getNetworkBody(getBodyString(requestBody));
|
|
12818
|
+
return buildNetworkRequestOrResponse(requestBodySize, body);
|
|
13911
12819
|
}
|
|
13912
12820
|
|
|
13913
12821
|
async function _getResponseInfo(
|
|
13914
|
-
|
|
13915
|
-
{
|
|
13916
|
-
networkCaptureBodies,
|
|
13917
|
-
textEncoder,
|
|
13918
|
-
networkResponseHeaders,
|
|
13919
|
-
}
|
|
13920
|
-
|
|
13921
|
-
,
|
|
12822
|
+
{ captureBodies, textEncoder },
|
|
13922
12823
|
response,
|
|
13923
12824
|
responseBodySize,
|
|
13924
12825
|
) {
|
|
13925
|
-
if (!
|
|
13926
|
-
return
|
|
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 (
|
|
13947
|
-
return
|
|
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(
|
|
12845
|
+
return buildNetworkRequestOrResponse(size, undefined);
|
|
13955
12846
|
} catch (e) {
|
|
13956
12847
|
// fallback
|
|
13957
|
-
return buildNetworkRequestOrResponse(
|
|
12848
|
+
return buildNetworkRequestOrResponse(responseBodySize, undefined);
|
|
13958
12849
|
}
|
|
13959
12850
|
}
|
|
13960
12851
|
|
|
13961
|
-
async function _parseFetchBody(
|
|
12852
|
+
async function _parseFetchBody(
|
|
12853
|
+
response,
|
|
12854
|
+
) {
|
|
12855
|
+
let bodyText;
|
|
12856
|
+
|
|
13962
12857
|
try {
|
|
13963
|
-
|
|
12858
|
+
bodyText = await response.text();
|
|
13964
12859
|
} catch (e2) {
|
|
13965
|
-
return
|
|
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
|
|
12932
|
+
const { startTimestamp, endTimestamp, input } = hint;
|
|
14079
12933
|
|
|
14080
12934
|
const {
|
|
14081
12935
|
url,
|
|
14082
12936
|
method,
|
|
14083
|
-
status_code: statusCode
|
|
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.
|
|
12948
|
+
options.captureBodies ? getNetworkBody(getBodyString(input)) : undefined,
|
|
14116
12949
|
);
|
|
14117
12950
|
const response = buildNetworkRequestOrResponse(
|
|
14118
|
-
networkResponseHeaders,
|
|
14119
12951
|
responseBodySize,
|
|
14120
|
-
options.
|
|
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
|
-
|
|
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
|
-
|
|
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 === '
|
|
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
|
-
//
|
|
14703
|
-
//
|
|
14704
|
-
if (replay.recordingMode === '
|
|
14705
|
-
const earliestEvent = replay.
|
|
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
|
|
15104
|
-
*
|
|
15105
|
-
*
|
|
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
|
-
|
|
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);
|
|
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
|
|
15201
|
-
*
|
|
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
|
-
|
|
15204
|
-
|
|
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 (!
|
|
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
|
-
|
|
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
|
|
15229
|
-
// If not sampled
|
|
15230
|
-
|
|
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
|
-
|
|
15252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15258
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15292
|
-
this.
|
|
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.
|
|
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 === '
|
|
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
|
|
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
|
-
|
|
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 == '
|
|
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 === '
|
|
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
|
-
*
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
15984
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
//
|
|
16350
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
14901
|
+
this._replay.stop();
|
|
16412
14902
|
}
|
|
16413
14903
|
|
|
16414
14904
|
/**
|
|
16415
|
-
*
|
|
14905
|
+
* Immediately send all pending events.
|
|
16416
14906
|
*/
|
|
16417
|
-
|
|
14907
|
+
flush() {
|
|
16418
14908
|
if (!this._replay || !this._replay.isEnabled()) {
|
|
16419
14909
|
return;
|
|
16420
14910
|
}
|
|
16421
14911
|
|
|
16422
|
-
return this._replay.
|
|
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
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
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
|
-
}
|
|
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-
|
|
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
|
-
|
|
35126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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: [
|
|
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
|
-
|
|
45770
|
-
|
|
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.
|
|
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: [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|