@myinterview/widget-react 1.1.23-binary-004 → 1.1.23-binary-006
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 +633 -2110
- package/dist/cjs/index.js.map +1 -1
- 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 +633 -2110
- package/dist/esm/index.js.map +1 -1
- package/package.json +23 -23
package/dist/cjs/index.js
CHANGED
|
@@ -973,12 +973,6 @@ function createStackParser(...parsers) {
|
|
|
973
973
|
// Remove webpack (error: *) wrappers
|
|
974
974
|
const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, '$1') : line;
|
|
975
975
|
|
|
976
|
-
// https://github.com/getsentry/sentry-javascript/issues/7813
|
|
977
|
-
// Skip Error: lines
|
|
978
|
-
if (cleanedLine.match(/\S*Error: /)) {
|
|
979
|
-
continue;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
976
|
for (const parser of sortedParsers) {
|
|
983
977
|
const frame = parser(cleanedLine);
|
|
984
978
|
|
|
@@ -1163,8 +1157,6 @@ function supportsHistory() {
|
|
|
1163
1157
|
// eslint-disable-next-line deprecation/deprecation
|
|
1164
1158
|
const WINDOW$3 = getGlobalObject();
|
|
1165
1159
|
|
|
1166
|
-
const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v2__';
|
|
1167
|
-
|
|
1168
1160
|
/**
|
|
1169
1161
|
* Instrument native APIs to call handlers that can be used to create breadcrumbs, APM spans etc.
|
|
1170
1162
|
* - Console API
|
|
@@ -1277,13 +1269,11 @@ function instrumentFetch() {
|
|
|
1277
1269
|
|
|
1278
1270
|
fill(WINDOW$3, 'fetch', function (originalFetch) {
|
|
1279
1271
|
return function (...args) {
|
|
1280
|
-
const { method, url } = parseFetchArgs(args);
|
|
1281
|
-
|
|
1282
1272
|
const handlerData = {
|
|
1283
1273
|
args,
|
|
1284
1274
|
fetchData: {
|
|
1285
|
-
method,
|
|
1286
|
-
url,
|
|
1275
|
+
method: getFetchMethod(args),
|
|
1276
|
+
url: getFetchUrl(args),
|
|
1287
1277
|
},
|
|
1288
1278
|
startTimestamp: Date.now(),
|
|
1289
1279
|
};
|
|
@@ -1318,53 +1308,29 @@ function instrumentFetch() {
|
|
|
1318
1308
|
});
|
|
1319
1309
|
}
|
|
1320
1310
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
if (typeof resource === 'string') {
|
|
1327
|
-
return resource;
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
if (!resource) {
|
|
1331
|
-
return '';
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
if (hasProp(resource, 'url')) {
|
|
1335
|
-
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();
|
|
1336
1316
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
return resource.toString();
|
|
1317
|
+
if (fetchArgs[1] && fetchArgs[1].method) {
|
|
1318
|
+
return String(fetchArgs[1].method).toUpperCase();
|
|
1340
1319
|
}
|
|
1341
|
-
|
|
1342
|
-
return '';
|
|
1320
|
+
return 'GET';
|
|
1343
1321
|
}
|
|
1344
1322
|
|
|
1345
|
-
/**
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
if (fetchArgs.length === 0) {
|
|
1350
|
-
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];
|
|
1351
1327
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
const [url, options] = fetchArgs ;
|
|
1355
|
-
|
|
1356
|
-
return {
|
|
1357
|
-
url: getUrlFromResource(url),
|
|
1358
|
-
method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET',
|
|
1359
|
-
};
|
|
1328
|
+
if ('Request' in WINDOW$3 && isInstanceOf(fetchArgs[0], Request)) {
|
|
1329
|
+
return fetchArgs[0].url;
|
|
1360
1330
|
}
|
|
1361
|
-
|
|
1362
|
-
const arg = fetchArgs[0];
|
|
1363
|
-
return {
|
|
1364
|
-
url: getUrlFromResource(arg ),
|
|
1365
|
-
method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',
|
|
1366
|
-
};
|
|
1331
|
+
return String(fetchArgs[0]);
|
|
1367
1332
|
}
|
|
1333
|
+
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
|
1368
1334
|
|
|
1369
1335
|
/** JSDoc */
|
|
1370
1336
|
function instrumentXHR() {
|
|
@@ -1377,11 +1343,10 @@ function instrumentXHR() {
|
|
|
1377
1343
|
fill(xhrproto, 'open', function (originalOpen) {
|
|
1378
1344
|
return function ( ...args) {
|
|
1379
1345
|
const url = args[1];
|
|
1380
|
-
const xhrInfo = (this
|
|
1346
|
+
const xhrInfo = (this.__sentry_xhr__ = {
|
|
1381
1347
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1382
1348
|
method: isString$2(args[0]) ? args[0].toUpperCase() : args[0],
|
|
1383
1349
|
url: args[1],
|
|
1384
|
-
request_headers: {},
|
|
1385
1350
|
});
|
|
1386
1351
|
|
|
1387
1352
|
// if Sentry key appears in URL, don't capture it as a request
|
|
@@ -1392,7 +1357,7 @@ function instrumentXHR() {
|
|
|
1392
1357
|
|
|
1393
1358
|
const onreadystatechangeHandler = () => {
|
|
1394
1359
|
// For whatever reason, this is not the same instance here as from the outer method
|
|
1395
|
-
const xhrInfo = this
|
|
1360
|
+
const xhrInfo = this.__sentry_xhr__;
|
|
1396
1361
|
|
|
1397
1362
|
if (!xhrInfo) {
|
|
1398
1363
|
return;
|
|
@@ -1427,32 +1392,14 @@ function instrumentXHR() {
|
|
|
1427
1392
|
this.addEventListener('readystatechange', onreadystatechangeHandler);
|
|
1428
1393
|
}
|
|
1429
1394
|
|
|
1430
|
-
// Intercepting `setRequestHeader` to access the request headers of XHR instance.
|
|
1431
|
-
// This will only work for user/library defined headers, not for the default/browser-assigned headers.
|
|
1432
|
-
// Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.
|
|
1433
|
-
fill(this, 'setRequestHeader', function (original) {
|
|
1434
|
-
return function ( ...setRequestHeaderArgs) {
|
|
1435
|
-
const [header, value] = setRequestHeaderArgs ;
|
|
1436
|
-
|
|
1437
|
-
const xhrInfo = this[SENTRY_XHR_DATA_KEY];
|
|
1438
|
-
|
|
1439
|
-
if (xhrInfo) {
|
|
1440
|
-
xhrInfo.request_headers[header.toLowerCase()] = value;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
return original.apply(this, setRequestHeaderArgs);
|
|
1444
|
-
};
|
|
1445
|
-
});
|
|
1446
|
-
|
|
1447
1395
|
return originalOpen.apply(this, args);
|
|
1448
1396
|
};
|
|
1449
1397
|
});
|
|
1450
1398
|
|
|
1451
1399
|
fill(xhrproto, 'send', function (originalSend) {
|
|
1452
1400
|
return function ( ...args) {
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
sentryXhrData.body = args[0];
|
|
1401
|
+
if (this.__sentry_xhr__ && args[0] !== undefined) {
|
|
1402
|
+
this.__sentry_xhr__.body = args[0];
|
|
1456
1403
|
}
|
|
1457
1404
|
|
|
1458
1405
|
triggerHandlers('xhr', {
|
|
@@ -1751,15 +1698,13 @@ function instrumentError() {
|
|
|
1751
1698
|
url,
|
|
1752
1699
|
});
|
|
1753
1700
|
|
|
1754
|
-
if (_oldOnErrorHandler
|
|
1701
|
+
if (_oldOnErrorHandler) {
|
|
1755
1702
|
// eslint-disable-next-line prefer-rest-params
|
|
1756
1703
|
return _oldOnErrorHandler.apply(this, arguments);
|
|
1757
1704
|
}
|
|
1758
1705
|
|
|
1759
1706
|
return false;
|
|
1760
1707
|
};
|
|
1761
|
-
|
|
1762
|
-
WINDOW$3.onerror.__SENTRY_INSTRUMENTED__ = true;
|
|
1763
1708
|
}
|
|
1764
1709
|
|
|
1765
1710
|
let _oldOnUnhandledRejectionHandler = null;
|
|
@@ -1770,15 +1715,13 @@ function instrumentUnhandledRejection() {
|
|
|
1770
1715
|
WINDOW$3.onunhandledrejection = function (e) {
|
|
1771
1716
|
triggerHandlers('unhandledrejection', e);
|
|
1772
1717
|
|
|
1773
|
-
if (_oldOnUnhandledRejectionHandler
|
|
1718
|
+
if (_oldOnUnhandledRejectionHandler) {
|
|
1774
1719
|
// eslint-disable-next-line prefer-rest-params
|
|
1775
1720
|
return _oldOnUnhandledRejectionHandler.apply(this, arguments);
|
|
1776
1721
|
}
|
|
1777
1722
|
|
|
1778
1723
|
return true;
|
|
1779
1724
|
};
|
|
1780
|
-
|
|
1781
|
-
WINDOW$3.onunhandledrejection.__SENTRY_INSTRUMENTED__ = true;
|
|
1782
1725
|
}
|
|
1783
1726
|
|
|
1784
1727
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
@@ -2076,7 +2019,7 @@ function loadModule(moduleName) {
|
|
|
2076
2019
|
* @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization.
|
|
2077
2020
|
*/
|
|
2078
2021
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2079
|
-
function normalize(input, depth =
|
|
2022
|
+
function normalize(input, depth = +Infinity, maxProperties = +Infinity) {
|
|
2080
2023
|
try {
|
|
2081
2024
|
// since we're at the outermost level, we don't provide a key
|
|
2082
2025
|
return visit('', input, depth, maxProperties);
|
|
@@ -2122,10 +2065,7 @@ function visit(
|
|
|
2122
2065
|
const [memoize, unmemoize] = memo;
|
|
2123
2066
|
|
|
2124
2067
|
// Get the simple cases out of the way first
|
|
2125
|
-
if (
|
|
2126
|
-
value == null || // this matches null and undefined -> eqeq not eqeqeq
|
|
2127
|
-
(['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))
|
|
2128
|
-
) {
|
|
2068
|
+
if (value === null || (['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))) {
|
|
2129
2069
|
return value ;
|
|
2130
2070
|
}
|
|
2131
2071
|
|
|
@@ -2146,16 +2086,17 @@ function visit(
|
|
|
2146
2086
|
return value ;
|
|
2147
2087
|
}
|
|
2148
2088
|
|
|
2149
|
-
//
|
|
2150
|
-
//
|
|
2151
|
-
//
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
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
|
+
}
|
|
2156
2097
|
|
|
2157
2098
|
// We're also done if we've reached the max depth
|
|
2158
|
-
if (
|
|
2099
|
+
if (overriddenDepth === 0) {
|
|
2159
2100
|
// At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.
|
|
2160
2101
|
return stringified.replace('object ', '');
|
|
2161
2102
|
}
|
|
@@ -2171,7 +2112,7 @@ function visit(
|
|
|
2171
2112
|
try {
|
|
2172
2113
|
const jsonValue = valueWithToJSON.toJSON();
|
|
2173
2114
|
// We need to normalize the return value of `.toJSON()` in case it has circular references
|
|
2174
|
-
return visit('', jsonValue,
|
|
2115
|
+
return visit('', jsonValue, overriddenDepth - 1, maxProperties, memo);
|
|
2175
2116
|
} catch (err) {
|
|
2176
2117
|
// pass (The built-in `toJSON` failed, but we can still try to do it ourselves)
|
|
2177
2118
|
}
|
|
@@ -2200,7 +2141,7 @@ function visit(
|
|
|
2200
2141
|
|
|
2201
2142
|
// Recursively visit all the child nodes
|
|
2202
2143
|
const visitValue = visitable[visitKey];
|
|
2203
|
-
normalized[visitKey] = visit(visitKey, visitValue,
|
|
2144
|
+
normalized[visitKey] = visit(visitKey, visitValue, overriddenDepth - 1, maxProperties, memo);
|
|
2204
2145
|
|
|
2205
2146
|
numAdded++;
|
|
2206
2147
|
}
|
|
@@ -2212,7 +2153,6 @@ function visit(
|
|
|
2212
2153
|
return normalized;
|
|
2213
2154
|
}
|
|
2214
2155
|
|
|
2215
|
-
/* eslint-disable complexity */
|
|
2216
2156
|
/**
|
|
2217
2157
|
* Stringify the given value. Handles various known special values and types.
|
|
2218
2158
|
*
|
|
@@ -2263,6 +2203,11 @@ function stringifyValue(
|
|
|
2263
2203
|
return '[NaN]';
|
|
2264
2204
|
}
|
|
2265
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
|
+
|
|
2266
2211
|
if (typeof value === 'function') {
|
|
2267
2212
|
return `[Function: ${getFunctionName(value)}]`;
|
|
2268
2213
|
}
|
|
@@ -2280,19 +2225,11 @@ function stringifyValue(
|
|
|
2280
2225
|
// them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as
|
|
2281
2226
|
// `"[object Object]"`. If we instead look at the constructor's name (which is the same as the name of the class),
|
|
2282
2227
|
// we can make sure that only plain objects come out that way.
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
// Handle HTML Elements
|
|
2286
|
-
if (/^HTML(\w*)Element$/.test(objName)) {
|
|
2287
|
-
return `[HTMLElement: ${objName}]`;
|
|
2288
|
-
}
|
|
2289
|
-
|
|
2290
|
-
return `[object ${objName}]`;
|
|
2228
|
+
return `[object ${getConstructorName(value)}]`;
|
|
2291
2229
|
} catch (err) {
|
|
2292
2230
|
return `**non-serializable** (${err})`;
|
|
2293
2231
|
}
|
|
2294
2232
|
}
|
|
2295
|
-
/* eslint-enable complexity */
|
|
2296
2233
|
|
|
2297
2234
|
function getConstructorName(value) {
|
|
2298
2235
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -2603,7 +2540,9 @@ function makePromiseBuffer(limit) {
|
|
|
2603
2540
|
* // environments where DOM might not be available
|
|
2604
2541
|
* @returns parsed URL object
|
|
2605
2542
|
*/
|
|
2606
|
-
function parseUrl(url)
|
|
2543
|
+
function parseUrl(url)
|
|
2544
|
+
|
|
2545
|
+
{
|
|
2607
2546
|
if (!url) {
|
|
2608
2547
|
return {};
|
|
2609
2548
|
}
|
|
@@ -2621,8 +2560,6 @@ function parseUrl(url) {
|
|
|
2621
2560
|
host: match[4],
|
|
2622
2561
|
path: match[5],
|
|
2623
2562
|
protocol: match[2],
|
|
2624
|
-
search: query,
|
|
2625
|
-
hash: fragment,
|
|
2626
2563
|
relative: match[5] + query + fragment, // everything minus origin
|
|
2627
2564
|
};
|
|
2628
2565
|
}
|
|
@@ -3007,7 +2944,6 @@ const ITEM_TYPE_TO_DATA_CATEGORY_MAP = {
|
|
|
3007
2944
|
profile: 'profile',
|
|
3008
2945
|
replay_event: 'replay',
|
|
3009
2946
|
replay_recording: 'replay',
|
|
3010
|
-
check_in: 'monitor',
|
|
3011
2947
|
};
|
|
3012
2948
|
|
|
3013
2949
|
/**
|
|
@@ -3037,14 +2973,16 @@ function createEventEnvelopeHeaders(
|
|
|
3037
2973
|
dsn,
|
|
3038
2974
|
) {
|
|
3039
2975
|
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;
|
|
2976
|
+
|
|
3040
2977
|
return {
|
|
3041
2978
|
event_id: event.event_id ,
|
|
3042
2979
|
sent_at: new Date().toISOString(),
|
|
3043
2980
|
...(sdkInfo && { sdk: sdkInfo }),
|
|
3044
2981
|
...(!!tunnel && { dsn: dsnToString(dsn) }),
|
|
3045
|
-
...(
|
|
3046
|
-
|
|
3047
|
-
|
|
2982
|
+
...(event.type === 'transaction' &&
|
|
2983
|
+
dynamicSamplingContext && {
|
|
2984
|
+
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
|
|
2985
|
+
}),
|
|
3048
2986
|
};
|
|
3049
2987
|
}
|
|
3050
2988
|
|
|
@@ -3749,16 +3687,9 @@ class Scope {
|
|
|
3749
3687
|
// errors with transaction and it relies on that.
|
|
3750
3688
|
if (this._span) {
|
|
3751
3689
|
event.contexts = { trace: this._span.getTraceContext(), ...event.contexts };
|
|
3752
|
-
const
|
|
3753
|
-
if (
|
|
3754
|
-
event.
|
|
3755
|
-
dynamicSamplingContext: transaction.getDynamicSamplingContext(),
|
|
3756
|
-
...event.sdkProcessingMetadata,
|
|
3757
|
-
};
|
|
3758
|
-
const transactionName = transaction.name;
|
|
3759
|
-
if (transactionName) {
|
|
3760
|
-
event.tags = { transaction: transactionName, ...event.tags };
|
|
3761
|
-
}
|
|
3690
|
+
const transactionName = this._span.transaction && this._span.transaction.name;
|
|
3691
|
+
if (transactionName) {
|
|
3692
|
+
event.tags = { transaction: transactionName, ...event.tags };
|
|
3762
3693
|
}
|
|
3763
3694
|
}
|
|
3764
3695
|
|
|
@@ -3882,6 +3813,11 @@ const API_VERSION = 4;
|
|
|
3882
3813
|
*/
|
|
3883
3814
|
const DEFAULT_BREADCRUMBS = 100;
|
|
3884
3815
|
|
|
3816
|
+
/**
|
|
3817
|
+
* A layer in the process stack.
|
|
3818
|
+
* @hidden
|
|
3819
|
+
*/
|
|
3820
|
+
|
|
3885
3821
|
/**
|
|
3886
3822
|
* @inheritDoc
|
|
3887
3823
|
*/
|
|
@@ -4159,17 +4095,7 @@ class Hub {
|
|
|
4159
4095
|
* @inheritDoc
|
|
4160
4096
|
*/
|
|
4161
4097
|
startTransaction(context, customSamplingContext) {
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && !result) {
|
|
4165
|
-
// eslint-disable-next-line no-console
|
|
4166
|
-
console.warn(`Tracing extension 'startTransaction' has not been added. Call 'addTracingExtensions' before calling 'init':
|
|
4167
|
-
Sentry.addTracingExtensions();
|
|
4168
|
-
Sentry.init({...});
|
|
4169
|
-
`);
|
|
4170
|
-
}
|
|
4171
|
-
|
|
4172
|
-
return result;
|
|
4098
|
+
return this._callExtensionMethod('startTransaction', context, customSamplingContext);
|
|
4173
4099
|
}
|
|
4174
4100
|
|
|
4175
4101
|
/**
|
|
@@ -4254,10 +4180,13 @@ Sentry.init({...});
|
|
|
4254
4180
|
*/
|
|
4255
4181
|
_sendSessionUpdate() {
|
|
4256
4182
|
const { scope, client } = this.getStackTop();
|
|
4183
|
+
if (!scope) return;
|
|
4257
4184
|
|
|
4258
4185
|
const session = scope.getSession();
|
|
4259
|
-
if (session
|
|
4260
|
-
client.captureSession
|
|
4186
|
+
if (session) {
|
|
4187
|
+
if (client && client.captureSession) {
|
|
4188
|
+
client.captureSession(session);
|
|
4189
|
+
}
|
|
4261
4190
|
}
|
|
4262
4191
|
}
|
|
4263
4192
|
|
|
@@ -4327,28 +4256,47 @@ function getCurrentHub() {
|
|
|
4327
4256
|
// Get main carrier (global for every environment)
|
|
4328
4257
|
const registry = getMainCarrier();
|
|
4329
4258
|
|
|
4330
|
-
if (registry.__SENTRY__ && registry.__SENTRY__.acs) {
|
|
4331
|
-
const hub = registry.__SENTRY__.acs.getCurrentHub();
|
|
4332
|
-
|
|
4333
|
-
if (hub) {
|
|
4334
|
-
return hub;
|
|
4335
|
-
}
|
|
4336
|
-
}
|
|
4337
|
-
|
|
4338
|
-
// Return hub that lives on a global object
|
|
4339
|
-
return getGlobalHub(registry);
|
|
4340
|
-
}
|
|
4341
|
-
|
|
4342
|
-
function getGlobalHub(registry = getMainCarrier()) {
|
|
4343
4259
|
// If there's no hub, or its an old API, assign a new one
|
|
4344
4260
|
if (!hasHubOnCarrier(registry) || getHubFromCarrier(registry).isOlderThan(API_VERSION)) {
|
|
4345
4261
|
setHubOnCarrier(registry, new Hub());
|
|
4346
4262
|
}
|
|
4347
4263
|
|
|
4264
|
+
// Prefer domains over global if they are there (applicable only to Node environment)
|
|
4265
|
+
if (isNodeEnv()) {
|
|
4266
|
+
return getHubFromActiveDomain(registry);
|
|
4267
|
+
}
|
|
4348
4268
|
// Return hub that lives on a global object
|
|
4349
4269
|
return getHubFromCarrier(registry);
|
|
4350
4270
|
}
|
|
4351
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
|
+
|
|
4352
4300
|
/**
|
|
4353
4301
|
* This will tell whether a carrier has a hub on it or not
|
|
4354
4302
|
* @param carrier object
|
|
@@ -4422,69 +4370,6 @@ var SpanStatus; (function (SpanStatus) {
|
|
|
4422
4370
|
const DataLoss = 'data_loss'; SpanStatus["DataLoss"] = DataLoss;
|
|
4423
4371
|
})(SpanStatus || (SpanStatus = {}));
|
|
4424
4372
|
|
|
4425
|
-
/**
|
|
4426
|
-
* Wraps a function with a transaction/span and finishes the span after the function is done.
|
|
4427
|
-
*
|
|
4428
|
-
* Note that if you have not enabled tracing extensions via `addTracingExtensions`, this function
|
|
4429
|
-
* will not generate spans, and the `span` returned from the callback may be undefined.
|
|
4430
|
-
*
|
|
4431
|
-
* This function is meant to be used internally and may break at any time. Use at your own risk.
|
|
4432
|
-
*
|
|
4433
|
-
* @internal
|
|
4434
|
-
* @private
|
|
4435
|
-
*/
|
|
4436
|
-
function trace(
|
|
4437
|
-
context,
|
|
4438
|
-
callback,
|
|
4439
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
4440
|
-
onError = () => {},
|
|
4441
|
-
) {
|
|
4442
|
-
const ctx = { ...context };
|
|
4443
|
-
// If a name is set and a description is not, set the description to the name.
|
|
4444
|
-
if (ctx.name !== undefined && ctx.description === undefined) {
|
|
4445
|
-
ctx.description = ctx.name;
|
|
4446
|
-
}
|
|
4447
|
-
|
|
4448
|
-
const hub = getCurrentHub();
|
|
4449
|
-
const scope = hub.getScope();
|
|
4450
|
-
|
|
4451
|
-
const parentSpan = scope.getSpan();
|
|
4452
|
-
const activeSpan = parentSpan ? parentSpan.startChild(ctx) : hub.startTransaction(ctx);
|
|
4453
|
-
scope.setSpan(activeSpan);
|
|
4454
|
-
|
|
4455
|
-
function finishAndSetSpan() {
|
|
4456
|
-
activeSpan && activeSpan.finish();
|
|
4457
|
-
hub.getScope().setSpan(parentSpan);
|
|
4458
|
-
}
|
|
4459
|
-
|
|
4460
|
-
let maybePromiseResult;
|
|
4461
|
-
try {
|
|
4462
|
-
maybePromiseResult = callback(activeSpan);
|
|
4463
|
-
} catch (e) {
|
|
4464
|
-
activeSpan && activeSpan.setStatus('internal_error');
|
|
4465
|
-
onError(e);
|
|
4466
|
-
finishAndSetSpan();
|
|
4467
|
-
throw e;
|
|
4468
|
-
}
|
|
4469
|
-
|
|
4470
|
-
if (isThenable(maybePromiseResult)) {
|
|
4471
|
-
Promise.resolve(maybePromiseResult).then(
|
|
4472
|
-
() => {
|
|
4473
|
-
finishAndSetSpan();
|
|
4474
|
-
},
|
|
4475
|
-
e => {
|
|
4476
|
-
activeSpan && activeSpan.setStatus('internal_error');
|
|
4477
|
-
onError(e);
|
|
4478
|
-
finishAndSetSpan();
|
|
4479
|
-
},
|
|
4480
|
-
);
|
|
4481
|
-
} else {
|
|
4482
|
-
finishAndSetSpan();
|
|
4483
|
-
}
|
|
4484
|
-
|
|
4485
|
-
return maybePromiseResult;
|
|
4486
|
-
}
|
|
4487
|
-
|
|
4488
4373
|
// Note: All functions in this file are typed with a return value of `ReturnType<Hub[HUB_FUNCTION]>`,
|
|
4489
4374
|
// where HUB_FUNCTION is some method on the Hub class.
|
|
4490
4375
|
//
|
|
@@ -4826,11 +4711,7 @@ function prepareEvent(
|
|
|
4826
4711
|
|
|
4827
4712
|
applyClientOptions(prepared, options);
|
|
4828
4713
|
applyIntegrationsMetadata(prepared, integrations);
|
|
4829
|
-
|
|
4830
|
-
// Only apply debug metadata to error events.
|
|
4831
|
-
if (event.type === undefined) {
|
|
4832
|
-
applyDebugMetadata(prepared, options.stackParser);
|
|
4833
|
-
}
|
|
4714
|
+
applyDebugMetadata(prepared, options.stackParser);
|
|
4834
4715
|
|
|
4835
4716
|
// If we have scope given to us, use it as the base for further modifications.
|
|
4836
4717
|
// This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
|
|
@@ -4907,8 +4788,6 @@ function applyClientOptions(event, options) {
|
|
|
4907
4788
|
}
|
|
4908
4789
|
}
|
|
4909
4790
|
|
|
4910
|
-
const debugIdStackParserCache = new WeakMap();
|
|
4911
|
-
|
|
4912
4791
|
/**
|
|
4913
4792
|
* Applies debug metadata images to the event in order to apply source maps by looking up their debug ID.
|
|
4914
4793
|
*/
|
|
@@ -4919,28 +4798,10 @@ function applyDebugMetadata(event, stackParser) {
|
|
|
4919
4798
|
return;
|
|
4920
4799
|
}
|
|
4921
4800
|
|
|
4922
|
-
let debugIdStackFramesCache;
|
|
4923
|
-
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
|
|
4924
|
-
if (cachedDebugIdStackFrameCache) {
|
|
4925
|
-
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
|
|
4926
|
-
} else {
|
|
4927
|
-
debugIdStackFramesCache = new Map();
|
|
4928
|
-
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
|
|
4929
|
-
}
|
|
4930
|
-
|
|
4931
4801
|
// Build a map of filename -> debug_id
|
|
4932
4802
|
const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => {
|
|
4933
|
-
|
|
4934
|
-
const
|
|
4935
|
-
if (cachedParsedStack) {
|
|
4936
|
-
parsedStack = cachedParsedStack;
|
|
4937
|
-
} else {
|
|
4938
|
-
parsedStack = stackParser(debugIdStackTrace);
|
|
4939
|
-
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
|
|
4940
|
-
}
|
|
4941
|
-
|
|
4942
|
-
for (let i = parsedStack.length - 1; i >= 0; i--) {
|
|
4943
|
-
const stackFrame = parsedStack[i];
|
|
4803
|
+
const parsedStack = stackParser(debugIdStackTrace);
|
|
4804
|
+
for (const stackFrame of parsedStack) {
|
|
4944
4805
|
if (stackFrame.filename) {
|
|
4945
4806
|
acc[stackFrame.filename] = debugIdMap[debugIdStackTrace];
|
|
4946
4807
|
break;
|
|
@@ -5845,7 +5706,7 @@ function getEventForEnvelopeItem(item, type) {
|
|
|
5845
5706
|
return Array.isArray(item) ? (item )[1] : undefined;
|
|
5846
5707
|
}
|
|
5847
5708
|
|
|
5848
|
-
const SDK_VERSION = '7.
|
|
5709
|
+
const SDK_VERSION = '7.46.0';
|
|
5849
5710
|
|
|
5850
5711
|
let originalFunctionToString;
|
|
5851
5712
|
|
|
@@ -5868,17 +5729,11 @@ class FunctionToString {constructor() { FunctionToString.prototype.__init.call(
|
|
|
5868
5729
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
5869
5730
|
originalFunctionToString = Function.prototype.toString;
|
|
5870
5731
|
|
|
5871
|
-
//
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
const context = getOriginalFunction(this) || this;
|
|
5877
|
-
return originalFunctionToString.apply(context, args);
|
|
5878
|
-
};
|
|
5879
|
-
} catch (e) {
|
|
5880
|
-
// ignore errors here, just don't patch this
|
|
5881
|
-
}
|
|
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
|
+
};
|
|
5882
5737
|
}
|
|
5883
5738
|
} FunctionToString.__initStatic();
|
|
5884
5739
|
|
|
@@ -6026,9 +5881,8 @@ function _getPossibleEventMessages(event) {
|
|
|
6026
5881
|
return [event.message];
|
|
6027
5882
|
}
|
|
6028
5883
|
if (event.exception) {
|
|
6029
|
-
const { values } = event.exception;
|
|
6030
5884
|
try {
|
|
6031
|
-
const { type = '', value = '' } = (values && values[
|
|
5885
|
+
const { type = '', value = '' } = (event.exception.values && event.exception.values[0]) || {};
|
|
6032
5886
|
return [`${value}`, `${type}: ${value}`];
|
|
6033
5887
|
} catch (oO) {
|
|
6034
5888
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(`Cannot extract message for event ${getEventDescription(event)}`);
|
|
@@ -6687,14 +6541,12 @@ function _consoleBreadcrumb(handlerData) {
|
|
|
6687
6541
|
function _xhrBreadcrumb(handlerData) {
|
|
6688
6542
|
const { startTimestamp, endTimestamp } = handlerData;
|
|
6689
6543
|
|
|
6690
|
-
const sentryXhrData = handlerData.xhr[SENTRY_XHR_DATA_KEY];
|
|
6691
|
-
|
|
6692
6544
|
// We only capture complete, non-sentry requests
|
|
6693
|
-
if (!startTimestamp || !endTimestamp || !
|
|
6545
|
+
if (!startTimestamp || !endTimestamp || !handlerData.xhr.__sentry_xhr__) {
|
|
6694
6546
|
return;
|
|
6695
6547
|
}
|
|
6696
6548
|
|
|
6697
|
-
const { method, url, status_code, body } =
|
|
6549
|
+
const { method, url, status_code, body } = handlerData.xhr.__sentry_xhr__;
|
|
6698
6550
|
|
|
6699
6551
|
const data = {
|
|
6700
6552
|
method,
|
|
@@ -6812,43 +6664,6 @@ function _isEvent(event) {
|
|
|
6812
6664
|
return event && !!(event ).target;
|
|
6813
6665
|
}
|
|
6814
6666
|
|
|
6815
|
-
/**
|
|
6816
|
-
* Creates an envelope from a user feedback.
|
|
6817
|
-
*/
|
|
6818
|
-
function createUserFeedbackEnvelope(
|
|
6819
|
-
feedback,
|
|
6820
|
-
{
|
|
6821
|
-
metadata,
|
|
6822
|
-
tunnel,
|
|
6823
|
-
dsn,
|
|
6824
|
-
}
|
|
6825
|
-
|
|
6826
|
-
,
|
|
6827
|
-
) {
|
|
6828
|
-
const headers = {
|
|
6829
|
-
event_id: feedback.event_id,
|
|
6830
|
-
sent_at: new Date().toISOString(),
|
|
6831
|
-
...(metadata &&
|
|
6832
|
-
metadata.sdk && {
|
|
6833
|
-
sdk: {
|
|
6834
|
-
name: metadata.sdk.name,
|
|
6835
|
-
version: metadata.sdk.version,
|
|
6836
|
-
},
|
|
6837
|
-
}),
|
|
6838
|
-
...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }),
|
|
6839
|
-
};
|
|
6840
|
-
const item = createUserFeedbackEnvelopeItem(feedback);
|
|
6841
|
-
|
|
6842
|
-
return createEnvelope(headers, [item]);
|
|
6843
|
-
}
|
|
6844
|
-
|
|
6845
|
-
function createUserFeedbackEnvelopeItem(feedback) {
|
|
6846
|
-
const feedbackHeaders = {
|
|
6847
|
-
type: 'user_report',
|
|
6848
|
-
};
|
|
6849
|
-
return [feedbackHeaders, feedback];
|
|
6850
|
-
}
|
|
6851
|
-
|
|
6852
6667
|
/**
|
|
6853
6668
|
* Configuration options for the Sentry Browser SDK.
|
|
6854
6669
|
* @see @sentry/types Options for more information.
|
|
@@ -6931,23 +6746,6 @@ class BrowserClient extends BaseClient {
|
|
|
6931
6746
|
super.sendEvent(event, hint);
|
|
6932
6747
|
}
|
|
6933
6748
|
|
|
6934
|
-
/**
|
|
6935
|
-
* Sends user feedback to Sentry.
|
|
6936
|
-
*/
|
|
6937
|
-
captureUserFeedback(feedback) {
|
|
6938
|
-
if (!this._isEnabled()) {
|
|
6939
|
-
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('SDK not enabled, will not capture user feedback.');
|
|
6940
|
-
return;
|
|
6941
|
-
}
|
|
6942
|
-
|
|
6943
|
-
const envelope = createUserFeedbackEnvelope(feedback, {
|
|
6944
|
-
metadata: this.getSdkMetadata(),
|
|
6945
|
-
dsn: this.getDsn(),
|
|
6946
|
-
tunnel: this.getOptions().tunnel,
|
|
6947
|
-
});
|
|
6948
|
-
void this._sendEnvelope(envelope);
|
|
6949
|
-
}
|
|
6950
|
-
|
|
6951
6749
|
/**
|
|
6952
6750
|
* @inheritDoc
|
|
6953
6751
|
*/
|
|
@@ -7190,7 +6988,7 @@ function createFrame(filename, func, lineno, colno) {
|
|
|
7190
6988
|
|
|
7191
6989
|
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
|
|
7192
6990
|
const chromeRegex =
|
|
7193
|
-
/^\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;
|
|
7194
6992
|
const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
|
|
7195
6993
|
|
|
7196
6994
|
const chrome = line => {
|
|
@@ -7226,7 +7024,7 @@ const chromeStackLineParser = [CHROME_PRIORITY, chrome];
|
|
|
7226
7024
|
// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
|
|
7227
7025
|
// We need this specific case for now because we want no other regex to match.
|
|
7228
7026
|
const geckoREgex =
|
|
7229
|
-
/^\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;
|
|
7230
7028
|
const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
|
|
7231
7029
|
|
|
7232
7030
|
const gecko = line => {
|
|
@@ -7258,7 +7056,8 @@ const gecko = line => {
|
|
|
7258
7056
|
|
|
7259
7057
|
const geckoStackLineParser = [GECKO_PRIORITY, gecko];
|
|
7260
7058
|
|
|
7261
|
-
const winjsRegex =
|
|
7059
|
+
const winjsRegex =
|
|
7060
|
+
/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
|
7262
7061
|
|
|
7263
7062
|
const winjs = line => {
|
|
7264
7063
|
const parts = winjsRegex.exec(line);
|
|
@@ -8323,14 +8122,11 @@ const REPLAY_SESSION_KEY = 'sentryReplaySession';
|
|
|
8323
8122
|
const REPLAY_EVENT_NAME = 'replay_event';
|
|
8324
8123
|
const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
|
|
8325
8124
|
|
|
8326
|
-
// The idle limit for a session
|
|
8327
|
-
const
|
|
8328
|
-
|
|
8329
|
-
// The idle limit for a session after which the session expires.
|
|
8330
|
-
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
|
|
8331
8127
|
|
|
8332
8128
|
// The maximum length of a session
|
|
8333
|
-
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8129
|
+
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8334
8130
|
|
|
8335
8131
|
/** Default flush delays */
|
|
8336
8132
|
const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
@@ -8339,16 +8135,13 @@ const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
|
8339
8135
|
const DEFAULT_FLUSH_MAX_DELAY = 5500;
|
|
8340
8136
|
|
|
8341
8137
|
/* How long to wait for error checkouts */
|
|
8342
|
-
const
|
|
8138
|
+
const ERROR_CHECKOUT_TIME = 60000;
|
|
8343
8139
|
|
|
8344
8140
|
const RETRY_BASE_INTERVAL = 5000;
|
|
8345
8141
|
const RETRY_MAX_COUNT = 3;
|
|
8346
8142
|
|
|
8347
|
-
/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be
|
|
8348
|
-
const NETWORK_BODY_MAX_SIZE =
|
|
8349
|
-
|
|
8350
|
-
/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
|
|
8351
|
-
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;
|
|
8352
8145
|
|
|
8353
8146
|
var NodeType$1;
|
|
8354
8147
|
(function (NodeType) {
|
|
@@ -8385,7 +8178,7 @@ function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInp
|
|
|
8385
8178
|
if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
|
|
8386
8179
|
return text;
|
|
8387
8180
|
}
|
|
8388
|
-
if (input.hasAttribute('
|
|
8181
|
+
if (input.hasAttribute('rr_is_password')) {
|
|
8389
8182
|
type = 'password';
|
|
8390
8183
|
}
|
|
8391
8184
|
if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
|
|
@@ -8418,21 +8211,6 @@ function is2DCanvasBlank(canvas) {
|
|
|
8418
8211
|
}
|
|
8419
8212
|
return true;
|
|
8420
8213
|
}
|
|
8421
|
-
function getInputType(element) {
|
|
8422
|
-
const type = element.type;
|
|
8423
|
-
return element.hasAttribute('data-rr-is-password')
|
|
8424
|
-
? 'password'
|
|
8425
|
-
: type
|
|
8426
|
-
? type.toLowerCase()
|
|
8427
|
-
: null;
|
|
8428
|
-
}
|
|
8429
|
-
function getInputValue(el, tagName, type) {
|
|
8430
|
-
typeof type === 'string' ? type.toLowerCase() : '';
|
|
8431
|
-
if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
|
|
8432
|
-
return el.getAttribute('value') || '';
|
|
8433
|
-
}
|
|
8434
|
-
return el.value;
|
|
8435
|
-
}
|
|
8436
8214
|
|
|
8437
8215
|
let _id = 1;
|
|
8438
8216
|
const tagNameRegex = new RegExp('[^a-z0-9-_:]');
|
|
@@ -8471,13 +8249,6 @@ function getCssRuleString(rule) {
|
|
|
8471
8249
|
catch (_a) {
|
|
8472
8250
|
}
|
|
8473
8251
|
}
|
|
8474
|
-
return validateStringifiedCssRule(cssStringified);
|
|
8475
|
-
}
|
|
8476
|
-
function validateStringifiedCssRule(cssStringified) {
|
|
8477
|
-
if (cssStringified.indexOf(':') > -1) {
|
|
8478
|
-
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
|
|
8479
|
-
return cssStringified.replace(regex, '$1\\$2');
|
|
8480
|
-
}
|
|
8481
8252
|
return cssStringified;
|
|
8482
8253
|
}
|
|
8483
8254
|
function isCSSImportRule(rule) {
|
|
@@ -8486,7 +8257,7 @@ function isCSSImportRule(rule) {
|
|
|
8486
8257
|
function stringifyStyleSheet(sheet) {
|
|
8487
8258
|
return sheet.cssRules
|
|
8488
8259
|
? Array.from(sheet.cssRules)
|
|
8489
|
-
.map((rule) => rule.cssText
|
|
8260
|
+
.map((rule) => rule.cssText || '')
|
|
8490
8261
|
.join('')
|
|
8491
8262
|
: '';
|
|
8492
8263
|
}
|
|
@@ -8821,15 +8592,14 @@ function serializeNode(n, options) {
|
|
|
8821
8592
|
tagName === 'select' ||
|
|
8822
8593
|
tagName === 'option') {
|
|
8823
8594
|
const el = n;
|
|
8824
|
-
const
|
|
8825
|
-
const value = getInputValue(el, tagName.toUpperCase(), type);
|
|
8595
|
+
const value = getInputValue(tagName, el, attributes);
|
|
8826
8596
|
const checked = n.checked;
|
|
8827
|
-
if (type !== 'submit' &&
|
|
8828
|
-
type !== 'button' &&
|
|
8597
|
+
if (attributes.type !== 'submit' &&
|
|
8598
|
+
attributes.type !== 'button' &&
|
|
8829
8599
|
value) {
|
|
8830
8600
|
attributes.value = maskInputValue({
|
|
8831
8601
|
input: el,
|
|
8832
|
-
type,
|
|
8602
|
+
type: attributes.type,
|
|
8833
8603
|
tagName,
|
|
8834
8604
|
value,
|
|
8835
8605
|
maskInputSelector,
|
|
@@ -9302,8 +9072,15 @@ function snapshot(n, options) {
|
|
|
9302
9072
|
function skipAttribute(tagName, attributeName, value) {
|
|
9303
9073
|
return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
|
|
9304
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
|
+
}
|
|
9305
9082
|
|
|
9306
|
-
var EventType
|
|
9083
|
+
var EventType;
|
|
9307
9084
|
(function (EventType) {
|
|
9308
9085
|
EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
|
|
9309
9086
|
EventType[EventType["Load"] = 1] = "Load";
|
|
@@ -9312,7 +9089,7 @@ var EventType$1;
|
|
|
9312
9089
|
EventType[EventType["Meta"] = 4] = "Meta";
|
|
9313
9090
|
EventType[EventType["Custom"] = 5] = "Custom";
|
|
9314
9091
|
EventType[EventType["Plugin"] = 6] = "Plugin";
|
|
9315
|
-
})(EventType
|
|
9092
|
+
})(EventType || (EventType = {}));
|
|
9316
9093
|
var IncrementalSource;
|
|
9317
9094
|
(function (IncrementalSource) {
|
|
9318
9095
|
IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
|
|
@@ -9927,9 +9704,9 @@ class MutationBuffer {
|
|
|
9927
9704
|
this.attributes.push(item);
|
|
9928
9705
|
}
|
|
9929
9706
|
if (m.attributeName === 'type' &&
|
|
9930
|
-
target.tagName === 'INPUT' &&
|
|
9707
|
+
m.target.tagName === 'INPUT' &&
|
|
9931
9708
|
(m.oldValue || '').toLowerCase() === 'password') {
|
|
9932
|
-
target.setAttribute('
|
|
9709
|
+
m.target.setAttribute('rr_is_password', 'true');
|
|
9933
9710
|
}
|
|
9934
9711
|
if (m.attributeName === 'style') {
|
|
9935
9712
|
const old = this.doc.createElement('span');
|
|
@@ -10326,25 +10103,27 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
|
|
|
10326
10103
|
isBlocked(target, blockClass, blockSelector, unblockSelector)) {
|
|
10327
10104
|
return;
|
|
10328
10105
|
}
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
(ignoreSelector && el.matches(ignoreSelector))) {
|
|
10106
|
+
let type = target.type;
|
|
10107
|
+
if (target.classList.contains(ignoreClass) ||
|
|
10108
|
+
(ignoreSelector && target.matches(ignoreSelector))) {
|
|
10333
10109
|
return;
|
|
10334
10110
|
}
|
|
10335
|
-
let text =
|
|
10111
|
+
let text = target.value;
|
|
10336
10112
|
let isChecked = false;
|
|
10113
|
+
if (target.hasAttribute('rr_is_password')) {
|
|
10114
|
+
type = 'password';
|
|
10115
|
+
}
|
|
10337
10116
|
if (type === 'radio' || type === 'checkbox') {
|
|
10338
10117
|
isChecked = target.checked;
|
|
10339
10118
|
}
|
|
10340
|
-
if (hasInputMaskOptions({
|
|
10119
|
+
else if (hasInputMaskOptions({
|
|
10341
10120
|
maskInputOptions,
|
|
10342
10121
|
maskInputSelector,
|
|
10343
10122
|
tagName,
|
|
10344
10123
|
type,
|
|
10345
10124
|
})) {
|
|
10346
10125
|
text = maskInputValue({
|
|
10347
|
-
input:
|
|
10126
|
+
input: target,
|
|
10348
10127
|
maskInputOptions,
|
|
10349
10128
|
maskInputSelector,
|
|
10350
10129
|
unmaskInputSelector,
|
|
@@ -10361,18 +10140,8 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
|
|
|
10361
10140
|
.querySelectorAll(`input[type="radio"][name="${name}"]`)
|
|
10362
10141
|
.forEach((el) => {
|
|
10363
10142
|
if (el !== target) {
|
|
10364
|
-
const text = maskInputValue({
|
|
10365
|
-
input: el,
|
|
10366
|
-
maskInputOptions,
|
|
10367
|
-
maskInputSelector,
|
|
10368
|
-
unmaskInputSelector,
|
|
10369
|
-
tagName,
|
|
10370
|
-
type,
|
|
10371
|
-
value: getInputValue(el, tagName, type),
|
|
10372
|
-
maskInputFn,
|
|
10373
|
-
});
|
|
10374
10143
|
cbWithDedup(el, callbackWrapper(wrapEventWithUserTriggeredFlag)({
|
|
10375
|
-
text,
|
|
10144
|
+
text: el.value,
|
|
10376
10145
|
isChecked: !isChecked,
|
|
10377
10146
|
userTriggered: false,
|
|
10378
10147
|
}, userTriggeredOnInput));
|
|
@@ -11285,17 +11054,17 @@ function record(options = {}) {
|
|
|
11285
11054
|
wrappedEmit = (e, isCheckout) => {
|
|
11286
11055
|
var _a;
|
|
11287
11056
|
if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
|
|
11288
|
-
e.type !== EventType
|
|
11289
|
-
!(e.type === EventType
|
|
11057
|
+
e.type !== EventType.FullSnapshot &&
|
|
11058
|
+
!(e.type === EventType.IncrementalSnapshot &&
|
|
11290
11059
|
e.data.source === IncrementalSource.Mutation)) {
|
|
11291
11060
|
mutationBuffers.forEach((buf) => buf.unfreeze());
|
|
11292
11061
|
}
|
|
11293
11062
|
emit(eventProcessor(e), isCheckout);
|
|
11294
|
-
if (e.type === EventType
|
|
11063
|
+
if (e.type === EventType.FullSnapshot) {
|
|
11295
11064
|
lastFullSnapshotEvent = e;
|
|
11296
11065
|
incrementalSnapshotCount = 0;
|
|
11297
11066
|
}
|
|
11298
|
-
else if (e.type === EventType
|
|
11067
|
+
else if (e.type === EventType.IncrementalSnapshot) {
|
|
11299
11068
|
if (e.data.source === IncrementalSource.Mutation &&
|
|
11300
11069
|
e.data.isAttachIframe) {
|
|
11301
11070
|
return;
|
|
@@ -11311,16 +11080,16 @@ function record(options = {}) {
|
|
|
11311
11080
|
};
|
|
11312
11081
|
const wrappedMutationEmit = (m) => {
|
|
11313
11082
|
wrappedEmit(wrapEvent({
|
|
11314
|
-
type: EventType
|
|
11083
|
+
type: EventType.IncrementalSnapshot,
|
|
11315
11084
|
data: Object.assign({ source: IncrementalSource.Mutation }, m),
|
|
11316
11085
|
}));
|
|
11317
11086
|
};
|
|
11318
11087
|
const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
|
|
11319
|
-
type: EventType
|
|
11088
|
+
type: EventType.IncrementalSnapshot,
|
|
11320
11089
|
data: Object.assign({ source: IncrementalSource.Scroll }, p),
|
|
11321
11090
|
}));
|
|
11322
11091
|
const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
|
|
11323
|
-
type: EventType
|
|
11092
|
+
type: EventType.IncrementalSnapshot,
|
|
11324
11093
|
data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
|
|
11325
11094
|
}));
|
|
11326
11095
|
const iframeManager = new IframeManager({
|
|
@@ -11365,7 +11134,7 @@ function record(options = {}) {
|
|
|
11365
11134
|
takeFullSnapshot = (isCheckout = false) => {
|
|
11366
11135
|
var _a, _b, _c, _d;
|
|
11367
11136
|
wrappedEmit(wrapEvent({
|
|
11368
|
-
type: EventType
|
|
11137
|
+
type: EventType.Meta,
|
|
11369
11138
|
data: {
|
|
11370
11139
|
href: window.location.href,
|
|
11371
11140
|
width: getWindowWidth(),
|
|
@@ -11408,7 +11177,7 @@ function record(options = {}) {
|
|
|
11408
11177
|
}
|
|
11409
11178
|
mirror.map = idNodeMap;
|
|
11410
11179
|
wrappedEmit(wrapEvent({
|
|
11411
|
-
type: EventType
|
|
11180
|
+
type: EventType.FullSnapshot,
|
|
11412
11181
|
data: {
|
|
11413
11182
|
node,
|
|
11414
11183
|
initialOffset: {
|
|
@@ -11433,7 +11202,7 @@ function record(options = {}) {
|
|
|
11433
11202
|
const handlers = [];
|
|
11434
11203
|
handlers.push(on$1('DOMContentLoaded', () => {
|
|
11435
11204
|
wrappedEmit(wrapEvent({
|
|
11436
|
-
type: EventType
|
|
11205
|
+
type: EventType.DomContentLoaded,
|
|
11437
11206
|
data: {},
|
|
11438
11207
|
}));
|
|
11439
11208
|
}));
|
|
@@ -11443,40 +11212,40 @@ function record(options = {}) {
|
|
|
11443
11212
|
onMutation,
|
|
11444
11213
|
mutationCb: wrappedMutationEmit,
|
|
11445
11214
|
mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
|
|
11446
|
-
type: EventType
|
|
11215
|
+
type: EventType.IncrementalSnapshot,
|
|
11447
11216
|
data: {
|
|
11448
11217
|
source,
|
|
11449
11218
|
positions,
|
|
11450
11219
|
},
|
|
11451
11220
|
})),
|
|
11452
11221
|
mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
|
|
11453
|
-
type: EventType
|
|
11222
|
+
type: EventType.IncrementalSnapshot,
|
|
11454
11223
|
data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
|
|
11455
11224
|
})),
|
|
11456
11225
|
scrollCb: wrappedScrollEmit,
|
|
11457
11226
|
viewportResizeCb: (d) => wrappedEmit(wrapEvent({
|
|
11458
|
-
type: EventType
|
|
11227
|
+
type: EventType.IncrementalSnapshot,
|
|
11459
11228
|
data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
|
|
11460
11229
|
})),
|
|
11461
11230
|
inputCb: (v) => wrappedEmit(wrapEvent({
|
|
11462
|
-
type: EventType
|
|
11231
|
+
type: EventType.IncrementalSnapshot,
|
|
11463
11232
|
data: Object.assign({ source: IncrementalSource.Input }, v),
|
|
11464
11233
|
})),
|
|
11465
11234
|
mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
|
|
11466
|
-
type: EventType
|
|
11235
|
+
type: EventType.IncrementalSnapshot,
|
|
11467
11236
|
data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
|
|
11468
11237
|
})),
|
|
11469
11238
|
styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
|
|
11470
|
-
type: EventType
|
|
11239
|
+
type: EventType.IncrementalSnapshot,
|
|
11471
11240
|
data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
|
|
11472
11241
|
})),
|
|
11473
11242
|
styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
|
|
11474
|
-
type: EventType
|
|
11243
|
+
type: EventType.IncrementalSnapshot,
|
|
11475
11244
|
data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
|
|
11476
11245
|
})),
|
|
11477
11246
|
canvasMutationCb: wrappedCanvasMutationEmit,
|
|
11478
11247
|
fontCb: (p) => wrappedEmit(wrapEvent({
|
|
11479
|
-
type: EventType
|
|
11248
|
+
type: EventType.IncrementalSnapshot,
|
|
11480
11249
|
data: Object.assign({ source: IncrementalSource.Font }, p),
|
|
11481
11250
|
})),
|
|
11482
11251
|
blockClass,
|
|
@@ -11509,7 +11278,7 @@ function record(options = {}) {
|
|
|
11509
11278
|
observer: p.observer,
|
|
11510
11279
|
options: p.options,
|
|
11511
11280
|
callback: (payload) => wrappedEmit(wrapEvent({
|
|
11512
|
-
type: EventType
|
|
11281
|
+
type: EventType.Plugin,
|
|
11513
11282
|
data: {
|
|
11514
11283
|
plugin: p.name,
|
|
11515
11284
|
payload,
|
|
@@ -11537,7 +11306,7 @@ function record(options = {}) {
|
|
|
11537
11306
|
else {
|
|
11538
11307
|
handlers.push(on$1('load', () => {
|
|
11539
11308
|
wrappedEmit(wrapEvent({
|
|
11540
|
-
type: EventType
|
|
11309
|
+
type: EventType.Load,
|
|
11541
11310
|
data: {},
|
|
11542
11311
|
}));
|
|
11543
11312
|
init();
|
|
@@ -11556,7 +11325,7 @@ record.addCustomEvent = (tag, payload) => {
|
|
|
11556
11325
|
throw new Error('please add custom event after start recording');
|
|
11557
11326
|
}
|
|
11558
11327
|
wrappedEmit(wrapEvent({
|
|
11559
|
-
type: EventType
|
|
11328
|
+
type: EventType.Custom,
|
|
11560
11329
|
data: {
|
|
11561
11330
|
tag,
|
|
11562
11331
|
payload,
|
|
@@ -11574,475 +11343,6 @@ record.takeFullSnapshot = (isCheckout) => {
|
|
|
11574
11343
|
};
|
|
11575
11344
|
record.mirror = mirror;
|
|
11576
11345
|
|
|
11577
|
-
/**
|
|
11578
|
-
* Create a breadcrumb for a replay.
|
|
11579
|
-
*/
|
|
11580
|
-
function createBreadcrumb(
|
|
11581
|
-
breadcrumb,
|
|
11582
|
-
) {
|
|
11583
|
-
return {
|
|
11584
|
-
timestamp: Date.now() / 1000,
|
|
11585
|
-
type: 'default',
|
|
11586
|
-
...breadcrumb,
|
|
11587
|
-
};
|
|
11588
|
-
}
|
|
11589
|
-
|
|
11590
|
-
var NodeType;
|
|
11591
|
-
(function (NodeType) {
|
|
11592
|
-
NodeType[NodeType["Document"] = 0] = "Document";
|
|
11593
|
-
NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
|
|
11594
|
-
NodeType[NodeType["Element"] = 2] = "Element";
|
|
11595
|
-
NodeType[NodeType["Text"] = 3] = "Text";
|
|
11596
|
-
NodeType[NodeType["CDATA"] = 4] = "CDATA";
|
|
11597
|
-
NodeType[NodeType["Comment"] = 5] = "Comment";
|
|
11598
|
-
})(NodeType || (NodeType = {}));
|
|
11599
|
-
|
|
11600
|
-
/**
|
|
11601
|
-
* Converts a timestamp to ms, if it was in s, or keeps it as ms.
|
|
11602
|
-
*/
|
|
11603
|
-
function timestampToMs(timestamp) {
|
|
11604
|
-
const isMs = timestamp > 9999999999;
|
|
11605
|
-
return isMs ? timestamp : timestamp * 1000;
|
|
11606
|
-
}
|
|
11607
|
-
|
|
11608
|
-
/**
|
|
11609
|
-
* Add an event to the event buffer.
|
|
11610
|
-
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
|
|
11611
|
-
*/
|
|
11612
|
-
async function addEvent(
|
|
11613
|
-
replay,
|
|
11614
|
-
event,
|
|
11615
|
-
isCheckout,
|
|
11616
|
-
) {
|
|
11617
|
-
if (!replay.eventBuffer) {
|
|
11618
|
-
// This implies that `_isEnabled` is false
|
|
11619
|
-
return null;
|
|
11620
|
-
}
|
|
11621
|
-
|
|
11622
|
-
if (replay.isPaused()) {
|
|
11623
|
-
// Do not add to event buffer when recording is paused
|
|
11624
|
-
return null;
|
|
11625
|
-
}
|
|
11626
|
-
|
|
11627
|
-
const timestampInMs = timestampToMs(event.timestamp);
|
|
11628
|
-
|
|
11629
|
-
// Throw out events that happen more than 5 minutes ago. This can happen if
|
|
11630
|
-
// page has been left open and idle for a long period of time and user
|
|
11631
|
-
// comes back to trigger a new session. The performance entries rely on
|
|
11632
|
-
// `performance.timeOrigin`, which is when the page first opened.
|
|
11633
|
-
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
11634
|
-
return null;
|
|
11635
|
-
}
|
|
11636
|
-
|
|
11637
|
-
try {
|
|
11638
|
-
if (isCheckout) {
|
|
11639
|
-
replay.eventBuffer.clear();
|
|
11640
|
-
}
|
|
11641
|
-
|
|
11642
|
-
return await replay.eventBuffer.addEvent(event);
|
|
11643
|
-
} catch (error) {
|
|
11644
|
-
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
|
|
11645
|
-
await replay.stop('addEvent');
|
|
11646
|
-
|
|
11647
|
-
const client = getCurrentHub().getClient();
|
|
11648
|
-
|
|
11649
|
-
if (client) {
|
|
11650
|
-
client.recordDroppedEvent('internal_sdk_error', 'replay');
|
|
11651
|
-
}
|
|
11652
|
-
}
|
|
11653
|
-
}
|
|
11654
|
-
|
|
11655
|
-
/**
|
|
11656
|
-
* Add a breadcrumb event to replay.
|
|
11657
|
-
*/
|
|
11658
|
-
function addBreadcrumbEvent(replay, breadcrumb) {
|
|
11659
|
-
if (breadcrumb.category === 'sentry.transaction') {
|
|
11660
|
-
return;
|
|
11661
|
-
}
|
|
11662
|
-
|
|
11663
|
-
if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
|
|
11664
|
-
replay.triggerUserActivity();
|
|
11665
|
-
} else {
|
|
11666
|
-
replay.checkAndHandleExpiredSession();
|
|
11667
|
-
}
|
|
11668
|
-
|
|
11669
|
-
replay.addUpdate(() => {
|
|
11670
|
-
void addEvent(replay, {
|
|
11671
|
-
type: EventType$1.Custom,
|
|
11672
|
-
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
|
|
11673
|
-
// but maybe we should just keep them as milliseconds
|
|
11674
|
-
timestamp: (breadcrumb.timestamp || 0) * 1000,
|
|
11675
|
-
data: {
|
|
11676
|
-
tag: 'breadcrumb',
|
|
11677
|
-
// normalize to max. 10 depth and 1_000 properties per object
|
|
11678
|
-
payload: normalize(breadcrumb, 10, 1000),
|
|
11679
|
-
},
|
|
11680
|
-
});
|
|
11681
|
-
|
|
11682
|
-
// Do not flush after console log messages
|
|
11683
|
-
return breadcrumb.category === 'console';
|
|
11684
|
-
});
|
|
11685
|
-
}
|
|
11686
|
-
|
|
11687
|
-
/**
|
|
11688
|
-
* Detect a slow click on a button/a tag,
|
|
11689
|
-
* and potentially create a corresponding breadcrumb.
|
|
11690
|
-
*/
|
|
11691
|
-
function detectSlowClick(
|
|
11692
|
-
replay,
|
|
11693
|
-
config,
|
|
11694
|
-
clickBreadcrumb,
|
|
11695
|
-
node,
|
|
11696
|
-
) {
|
|
11697
|
-
if (ignoreElement(node, config)) {
|
|
11698
|
-
return;
|
|
11699
|
-
}
|
|
11700
|
-
|
|
11701
|
-
/*
|
|
11702
|
-
We consider a slow click a click on a button/a, which does not trigger one of:
|
|
11703
|
-
- DOM mutation
|
|
11704
|
-
- Scroll (within 100ms)
|
|
11705
|
-
Within the given threshold time.
|
|
11706
|
-
After time timeout time, we stop listening and mark it as a slow click anyhow.
|
|
11707
|
-
*/
|
|
11708
|
-
|
|
11709
|
-
let cleanup = () => {
|
|
11710
|
-
// replaced further down
|
|
11711
|
-
};
|
|
11712
|
-
|
|
11713
|
-
// After timeout time, def. consider this a slow click, and stop watching for mutations
|
|
11714
|
-
const timeout = setTimeout(() => {
|
|
11715
|
-
handleSlowClick(replay, clickBreadcrumb, config.timeout, 'timeout');
|
|
11716
|
-
cleanup();
|
|
11717
|
-
}, config.timeout);
|
|
11718
|
-
|
|
11719
|
-
const mutationHandler = () => {
|
|
11720
|
-
maybeHandleSlowClick(replay, clickBreadcrumb, config.threshold, config.timeout, 'mutation');
|
|
11721
|
-
cleanup();
|
|
11722
|
-
};
|
|
11723
|
-
|
|
11724
|
-
const scrollHandler = () => {
|
|
11725
|
-
maybeHandleSlowClick(replay, clickBreadcrumb, config.scrollTimeout, config.timeout, 'scroll');
|
|
11726
|
-
cleanup();
|
|
11727
|
-
};
|
|
11728
|
-
|
|
11729
|
-
const obs = new MutationObserver(mutationHandler);
|
|
11730
|
-
|
|
11731
|
-
obs.observe(WINDOW.document.documentElement, {
|
|
11732
|
-
attributes: true,
|
|
11733
|
-
characterData: true,
|
|
11734
|
-
childList: true,
|
|
11735
|
-
subtree: true,
|
|
11736
|
-
});
|
|
11737
|
-
|
|
11738
|
-
WINDOW.addEventListener('scroll', scrollHandler);
|
|
11739
|
-
|
|
11740
|
-
// Stop listening to scroll timeouts early
|
|
11741
|
-
const scrollTimeout = setTimeout(() => {
|
|
11742
|
-
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
11743
|
-
}, config.scrollTimeout);
|
|
11744
|
-
|
|
11745
|
-
cleanup = () => {
|
|
11746
|
-
clearTimeout(timeout);
|
|
11747
|
-
clearTimeout(scrollTimeout);
|
|
11748
|
-
obs.disconnect();
|
|
11749
|
-
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
11750
|
-
};
|
|
11751
|
-
}
|
|
11752
|
-
|
|
11753
|
-
function maybeHandleSlowClick(
|
|
11754
|
-
replay,
|
|
11755
|
-
clickBreadcrumb,
|
|
11756
|
-
threshold,
|
|
11757
|
-
timeout,
|
|
11758
|
-
endReason,
|
|
11759
|
-
) {
|
|
11760
|
-
const now = Date.now();
|
|
11761
|
-
const timeAfterClickMs = now - clickBreadcrumb.timestamp * 1000;
|
|
11762
|
-
|
|
11763
|
-
if (timeAfterClickMs > threshold) {
|
|
11764
|
-
handleSlowClick(replay, clickBreadcrumb, Math.min(timeAfterClickMs, timeout), endReason);
|
|
11765
|
-
return true;
|
|
11766
|
-
}
|
|
11767
|
-
|
|
11768
|
-
return false;
|
|
11769
|
-
}
|
|
11770
|
-
|
|
11771
|
-
function handleSlowClick(
|
|
11772
|
-
replay,
|
|
11773
|
-
clickBreadcrumb,
|
|
11774
|
-
timeAfterClickMs,
|
|
11775
|
-
endReason,
|
|
11776
|
-
) {
|
|
11777
|
-
const breadcrumb = {
|
|
11778
|
-
message: clickBreadcrumb.message,
|
|
11779
|
-
timestamp: clickBreadcrumb.timestamp,
|
|
11780
|
-
category: 'ui.slowClickDetected',
|
|
11781
|
-
data: {
|
|
11782
|
-
...clickBreadcrumb.data,
|
|
11783
|
-
url: WINDOW.location.href,
|
|
11784
|
-
// TODO FN: add parametrized route, when possible
|
|
11785
|
-
timeAfterClickMs,
|
|
11786
|
-
endReason,
|
|
11787
|
-
},
|
|
11788
|
-
};
|
|
11789
|
-
|
|
11790
|
-
addBreadcrumbEvent(replay, breadcrumb);
|
|
11791
|
-
}
|
|
11792
|
-
|
|
11793
|
-
const SLOW_CLICK_IGNORE_TAGS = ['SELECT', 'OPTION'];
|
|
11794
|
-
|
|
11795
|
-
function ignoreElement(node, config) {
|
|
11796
|
-
// If <input> tag, we only want to consider input[type='submit'] & input[type='button']
|
|
11797
|
-
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
|
|
11798
|
-
return true;
|
|
11799
|
-
}
|
|
11800
|
-
|
|
11801
|
-
if (SLOW_CLICK_IGNORE_TAGS.includes(node.tagName)) {
|
|
11802
|
-
return true;
|
|
11803
|
-
}
|
|
11804
|
-
|
|
11805
|
-
// If <a> tag, detect special variants that may not lead to an action
|
|
11806
|
-
// If target !== _self, we may open the link somewhere else, which would lead to no action
|
|
11807
|
-
// Also, when downloading a file, we may not leave the page, but still not trigger an action
|
|
11808
|
-
if (
|
|
11809
|
-
node.tagName === 'A' &&
|
|
11810
|
-
(node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
|
|
11811
|
-
) {
|
|
11812
|
-
return true;
|
|
11813
|
-
}
|
|
11814
|
-
|
|
11815
|
-
if (config.ignoreSelector && node.matches(config.ignoreSelector)) {
|
|
11816
|
-
return true;
|
|
11817
|
-
}
|
|
11818
|
-
|
|
11819
|
-
return false;
|
|
11820
|
-
}
|
|
11821
|
-
|
|
11822
|
-
// Note that these are the serialized attributes and not attributes directly on
|
|
11823
|
-
// the DOM Node. Attributes we are interested in:
|
|
11824
|
-
const ATTRIBUTES_TO_RECORD = new Set([
|
|
11825
|
-
'id',
|
|
11826
|
-
'class',
|
|
11827
|
-
'aria-label',
|
|
11828
|
-
'role',
|
|
11829
|
-
'name',
|
|
11830
|
-
'alt',
|
|
11831
|
-
'title',
|
|
11832
|
-
'data-test-id',
|
|
11833
|
-
'data-testid',
|
|
11834
|
-
]);
|
|
11835
|
-
|
|
11836
|
-
/**
|
|
11837
|
-
* Inclusion list of attributes that we want to record from the DOM element
|
|
11838
|
-
*/
|
|
11839
|
-
function getAttributesToRecord(attributes) {
|
|
11840
|
-
const obj = {};
|
|
11841
|
-
for (const key in attributes) {
|
|
11842
|
-
if (ATTRIBUTES_TO_RECORD.has(key)) {
|
|
11843
|
-
let normalizedKey = key;
|
|
11844
|
-
|
|
11845
|
-
if (key === 'data-testid' || key === 'data-test-id') {
|
|
11846
|
-
normalizedKey = 'testId';
|
|
11847
|
-
}
|
|
11848
|
-
|
|
11849
|
-
obj[normalizedKey] = attributes[key];
|
|
11850
|
-
}
|
|
11851
|
-
}
|
|
11852
|
-
|
|
11853
|
-
return obj;
|
|
11854
|
-
}
|
|
11855
|
-
|
|
11856
|
-
const handleDomListener = (
|
|
11857
|
-
replay,
|
|
11858
|
-
) => {
|
|
11859
|
-
const slowClickExperiment = replay.getOptions()._experiments.slowClicks;
|
|
11860
|
-
|
|
11861
|
-
const slowClickConfig = slowClickExperiment
|
|
11862
|
-
? {
|
|
11863
|
-
threshold: slowClickExperiment.threshold,
|
|
11864
|
-
timeout: slowClickExperiment.timeout,
|
|
11865
|
-
scrollTimeout: slowClickExperiment.scrollTimeout,
|
|
11866
|
-
ignoreSelector: slowClickExperiment.ignoreSelectors ? slowClickExperiment.ignoreSelectors.join(',') : '',
|
|
11867
|
-
}
|
|
11868
|
-
: undefined;
|
|
11869
|
-
|
|
11870
|
-
return (handlerData) => {
|
|
11871
|
-
if (!replay.isEnabled()) {
|
|
11872
|
-
return;
|
|
11873
|
-
}
|
|
11874
|
-
|
|
11875
|
-
const result = handleDom(handlerData);
|
|
11876
|
-
|
|
11877
|
-
if (!result) {
|
|
11878
|
-
return;
|
|
11879
|
-
}
|
|
11880
|
-
|
|
11881
|
-
const isClick = handlerData.name === 'click';
|
|
11882
|
-
const event = isClick && (handlerData.event );
|
|
11883
|
-
// Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
|
|
11884
|
-
if (isClick && slowClickConfig && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
|
|
11885
|
-
detectSlowClick(
|
|
11886
|
-
replay,
|
|
11887
|
-
slowClickConfig,
|
|
11888
|
-
result ,
|
|
11889
|
-
getClickTargetNode(handlerData.event) ,
|
|
11890
|
-
);
|
|
11891
|
-
}
|
|
11892
|
-
|
|
11893
|
-
addBreadcrumbEvent(replay, result);
|
|
11894
|
-
};
|
|
11895
|
-
};
|
|
11896
|
-
|
|
11897
|
-
/** Get the base DOM breadcrumb. */
|
|
11898
|
-
function getBaseDomBreadcrumb(target, message) {
|
|
11899
|
-
// `__sn` property is the serialized node created by rrweb
|
|
11900
|
-
const serializedNode = target && isRrwebNode(target) && target.__sn.type === NodeType.Element ? target.__sn : null;
|
|
11901
|
-
|
|
11902
|
-
return {
|
|
11903
|
-
message,
|
|
11904
|
-
data: serializedNode
|
|
11905
|
-
? {
|
|
11906
|
-
nodeId: serializedNode.id,
|
|
11907
|
-
node: {
|
|
11908
|
-
id: serializedNode.id,
|
|
11909
|
-
tagName: serializedNode.tagName,
|
|
11910
|
-
textContent: target
|
|
11911
|
-
? Array.from(target.childNodes)
|
|
11912
|
-
.map(
|
|
11913
|
-
(node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
|
|
11914
|
-
)
|
|
11915
|
-
.filter(Boolean) // filter out empty values
|
|
11916
|
-
.map(text => (text ).trim())
|
|
11917
|
-
.join('')
|
|
11918
|
-
: '',
|
|
11919
|
-
attributes: getAttributesToRecord(serializedNode.attributes),
|
|
11920
|
-
},
|
|
11921
|
-
}
|
|
11922
|
-
: {},
|
|
11923
|
-
};
|
|
11924
|
-
}
|
|
11925
|
-
|
|
11926
|
-
/**
|
|
11927
|
-
* An event handler to react to DOM events.
|
|
11928
|
-
* Exported for tests.
|
|
11929
|
-
*/
|
|
11930
|
-
function handleDom(handlerData) {
|
|
11931
|
-
const { target, message } = getDomTarget(handlerData);
|
|
11932
|
-
|
|
11933
|
-
return createBreadcrumb({
|
|
11934
|
-
category: `ui.${handlerData.name}`,
|
|
11935
|
-
...getBaseDomBreadcrumb(target, message),
|
|
11936
|
-
});
|
|
11937
|
-
}
|
|
11938
|
-
|
|
11939
|
-
function getDomTarget(handlerData) {
|
|
11940
|
-
const isClick = handlerData.name === 'click';
|
|
11941
|
-
|
|
11942
|
-
let message;
|
|
11943
|
-
let target = null;
|
|
11944
|
-
|
|
11945
|
-
// Accessing event.target can throw (see getsentry/raven-js#838, #768)
|
|
11946
|
-
try {
|
|
11947
|
-
target = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
|
|
11948
|
-
message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
|
|
11949
|
-
} catch (e) {
|
|
11950
|
-
message = '<unknown>';
|
|
11951
|
-
}
|
|
11952
|
-
|
|
11953
|
-
return { target, message };
|
|
11954
|
-
}
|
|
11955
|
-
|
|
11956
|
-
function isRrwebNode(node) {
|
|
11957
|
-
return '__sn' in node;
|
|
11958
|
-
}
|
|
11959
|
-
|
|
11960
|
-
function getTargetNode(event) {
|
|
11961
|
-
if (isEventWithTarget(event)) {
|
|
11962
|
-
return event.target ;
|
|
11963
|
-
}
|
|
11964
|
-
|
|
11965
|
-
return event;
|
|
11966
|
-
}
|
|
11967
|
-
|
|
11968
|
-
const INTERACTIVE_SELECTOR = 'button,a';
|
|
11969
|
-
|
|
11970
|
-
// For clicks, we check if the target is inside of a button or link
|
|
11971
|
-
// If so, we use this as the target instead
|
|
11972
|
-
// This is useful because if you click on the image in <button><img></button>,
|
|
11973
|
-
// The target will be the image, not the button, which we don't want here
|
|
11974
|
-
function getClickTargetNode(event) {
|
|
11975
|
-
const target = getTargetNode(event);
|
|
11976
|
-
|
|
11977
|
-
if (!target || !(target instanceof Element)) {
|
|
11978
|
-
return target;
|
|
11979
|
-
}
|
|
11980
|
-
|
|
11981
|
-
const closestInteractive = target.closest(INTERACTIVE_SELECTOR);
|
|
11982
|
-
return closestInteractive || target;
|
|
11983
|
-
}
|
|
11984
|
-
|
|
11985
|
-
function isEventWithTarget(event) {
|
|
11986
|
-
return typeof event === 'object' && !!event && 'target' in event;
|
|
11987
|
-
}
|
|
11988
|
-
|
|
11989
|
-
/** Handle keyboard events & create breadcrumbs. */
|
|
11990
|
-
function handleKeyboardEvent(replay, event) {
|
|
11991
|
-
if (!replay.isEnabled()) {
|
|
11992
|
-
return;
|
|
11993
|
-
}
|
|
11994
|
-
|
|
11995
|
-
replay.triggerUserActivity();
|
|
11996
|
-
|
|
11997
|
-
const breadcrumb = getKeyboardBreadcrumb(event);
|
|
11998
|
-
|
|
11999
|
-
if (!breadcrumb) {
|
|
12000
|
-
return;
|
|
12001
|
-
}
|
|
12002
|
-
|
|
12003
|
-
addBreadcrumbEvent(replay, breadcrumb);
|
|
12004
|
-
}
|
|
12005
|
-
|
|
12006
|
-
/** exported only for tests */
|
|
12007
|
-
function getKeyboardBreadcrumb(event) {
|
|
12008
|
-
const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event;
|
|
12009
|
-
|
|
12010
|
-
// never capture for input fields
|
|
12011
|
-
if (!target || isInputElement(target )) {
|
|
12012
|
-
return null;
|
|
12013
|
-
}
|
|
12014
|
-
|
|
12015
|
-
// Note: We do not consider shift here, as that means "uppercase"
|
|
12016
|
-
const hasModifierKey = metaKey || ctrlKey || altKey;
|
|
12017
|
-
const isCharacterKey = key.length === 1; // other keys like Escape, Tab, etc have a longer length
|
|
12018
|
-
|
|
12019
|
-
// Do not capture breadcrumb if only a word key is pressed
|
|
12020
|
-
// This could leak e.g. user input
|
|
12021
|
-
if (!hasModifierKey && isCharacterKey) {
|
|
12022
|
-
return null;
|
|
12023
|
-
}
|
|
12024
|
-
|
|
12025
|
-
const message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
|
|
12026
|
-
const baseBreadcrumb = getBaseDomBreadcrumb(target , message);
|
|
12027
|
-
|
|
12028
|
-
return createBreadcrumb({
|
|
12029
|
-
category: 'ui.keyDown',
|
|
12030
|
-
message,
|
|
12031
|
-
data: {
|
|
12032
|
-
...baseBreadcrumb.data,
|
|
12033
|
-
metaKey,
|
|
12034
|
-
shiftKey,
|
|
12035
|
-
ctrlKey,
|
|
12036
|
-
altKey,
|
|
12037
|
-
key,
|
|
12038
|
-
},
|
|
12039
|
-
});
|
|
12040
|
-
}
|
|
12041
|
-
|
|
12042
|
-
function isInputElement(target) {
|
|
12043
|
-
return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
|
|
12044
|
-
}
|
|
12045
|
-
|
|
12046
11346
|
const NAVIGATION_ENTRY_KEYS = [
|
|
12047
11347
|
'name',
|
|
12048
11348
|
'type',
|
|
@@ -12196,19 +11496,20 @@ class EventBufferArray {
|
|
|
12196
11496
|
return this.events.length > 0;
|
|
12197
11497
|
}
|
|
12198
11498
|
|
|
12199
|
-
/** @inheritdoc */
|
|
12200
|
-
get type() {
|
|
12201
|
-
return 'sync';
|
|
12202
|
-
}
|
|
12203
|
-
|
|
12204
11499
|
/** @inheritdoc */
|
|
12205
11500
|
destroy() {
|
|
12206
11501
|
this.events = [];
|
|
12207
11502
|
}
|
|
12208
11503
|
|
|
12209
11504
|
/** @inheritdoc */
|
|
12210
|
-
async addEvent(event) {
|
|
11505
|
+
async addEvent(event, isCheckout) {
|
|
11506
|
+
if (isCheckout) {
|
|
11507
|
+
this.events = [event];
|
|
11508
|
+
return;
|
|
11509
|
+
}
|
|
11510
|
+
|
|
12211
11511
|
this.events.push(event);
|
|
11512
|
+
return;
|
|
12212
11513
|
}
|
|
12213
11514
|
|
|
12214
11515
|
/** @inheritdoc */
|
|
@@ -12222,22 +11523,6 @@ class EventBufferArray {
|
|
|
12222
11523
|
resolve(JSON.stringify(eventsRet));
|
|
12223
11524
|
});
|
|
12224
11525
|
}
|
|
12225
|
-
|
|
12226
|
-
/** @inheritdoc */
|
|
12227
|
-
clear() {
|
|
12228
|
-
this.events = [];
|
|
12229
|
-
}
|
|
12230
|
-
|
|
12231
|
-
/** @inheritdoc */
|
|
12232
|
-
getEarliestTimestamp() {
|
|
12233
|
-
const timestamp = this.events.map(event => event.timestamp).sort()[0];
|
|
12234
|
-
|
|
12235
|
-
if (!timestamp) {
|
|
12236
|
-
return null;
|
|
12237
|
-
}
|
|
12238
|
-
|
|
12239
|
-
return timestampToMs(timestamp);
|
|
12240
|
-
}
|
|
12241
11526
|
}
|
|
12242
11527
|
|
|
12243
11528
|
/**
|
|
@@ -12345,20 +11630,11 @@ class WorkerHandler {
|
|
|
12345
11630
|
* Exported only for testing.
|
|
12346
11631
|
*/
|
|
12347
11632
|
class EventBufferCompressionWorker {
|
|
11633
|
+
/** @inheritdoc */
|
|
12348
11634
|
|
|
12349
11635
|
constructor(worker) {
|
|
12350
11636
|
this._worker = new WorkerHandler(worker);
|
|
12351
|
-
this.
|
|
12352
|
-
}
|
|
12353
|
-
|
|
12354
|
-
/** @inheritdoc */
|
|
12355
|
-
get hasEvents() {
|
|
12356
|
-
return !!this._earliestTimestamp;
|
|
12357
|
-
}
|
|
12358
|
-
|
|
12359
|
-
/** @inheritdoc */
|
|
12360
|
-
get type() {
|
|
12361
|
-
return 'worker';
|
|
11637
|
+
this.hasEvents = false;
|
|
12362
11638
|
}
|
|
12363
11639
|
|
|
12364
11640
|
/**
|
|
@@ -12381,10 +11657,13 @@ class EventBufferCompressionWorker {
|
|
|
12381
11657
|
*
|
|
12382
11658
|
* Returns true if event was successfuly received and processed by worker.
|
|
12383
11659
|
*/
|
|
12384
|
-
addEvent(event) {
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
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();
|
|
12388
11667
|
}
|
|
12389
11668
|
|
|
12390
11669
|
return this._sendEventToWorker(event);
|
|
@@ -12397,18 +11676,6 @@ class EventBufferCompressionWorker {
|
|
|
12397
11676
|
return this._finishRequest();
|
|
12398
11677
|
}
|
|
12399
11678
|
|
|
12400
|
-
/** @inheritdoc */
|
|
12401
|
-
clear() {
|
|
12402
|
-
this._earliestTimestamp = null;
|
|
12403
|
-
// We do not wait on this, as we assume the order of messages is consistent for the worker
|
|
12404
|
-
void this._worker.postMessage('clear');
|
|
12405
|
-
}
|
|
12406
|
-
|
|
12407
|
-
/** @inheritdoc */
|
|
12408
|
-
getEarliestTimestamp() {
|
|
12409
|
-
return this._earliestTimestamp;
|
|
12410
|
-
}
|
|
12411
|
-
|
|
12412
11679
|
/**
|
|
12413
11680
|
* Send the event to the worker.
|
|
12414
11681
|
*/
|
|
@@ -12422,10 +11689,15 @@ class EventBufferCompressionWorker {
|
|
|
12422
11689
|
async _finishRequest() {
|
|
12423
11690
|
const response = await this._worker.postMessage('finish');
|
|
12424
11691
|
|
|
12425
|
-
this.
|
|
11692
|
+
this.hasEvents = false;
|
|
12426
11693
|
|
|
12427
11694
|
return response;
|
|
12428
11695
|
}
|
|
11696
|
+
|
|
11697
|
+
/** Clear any pending events from the worker. */
|
|
11698
|
+
_clear() {
|
|
11699
|
+
return this._worker.postMessage('clear');
|
|
11700
|
+
}
|
|
12429
11701
|
}
|
|
12430
11702
|
|
|
12431
11703
|
/**
|
|
@@ -12443,11 +11715,6 @@ class EventBufferProxy {
|
|
|
12443
11715
|
this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded();
|
|
12444
11716
|
}
|
|
12445
11717
|
|
|
12446
|
-
/** @inheritdoc */
|
|
12447
|
-
get type() {
|
|
12448
|
-
return this._used.type;
|
|
12449
|
-
}
|
|
12450
|
-
|
|
12451
11718
|
/** @inheritDoc */
|
|
12452
11719
|
get hasEvents() {
|
|
12453
11720
|
return this._used.hasEvents;
|
|
@@ -12459,23 +11726,13 @@ class EventBufferProxy {
|
|
|
12459
11726
|
this._compression.destroy();
|
|
12460
11727
|
}
|
|
12461
11728
|
|
|
12462
|
-
/** @inheritdoc */
|
|
12463
|
-
clear() {
|
|
12464
|
-
return this._used.clear();
|
|
12465
|
-
}
|
|
12466
|
-
|
|
12467
|
-
/** @inheritdoc */
|
|
12468
|
-
getEarliestTimestamp() {
|
|
12469
|
-
return this._used.getEarliestTimestamp();
|
|
12470
|
-
}
|
|
12471
|
-
|
|
12472
11729
|
/**
|
|
12473
11730
|
* Add an event to the event buffer.
|
|
12474
11731
|
*
|
|
12475
11732
|
* Returns true if event was successfully added.
|
|
12476
11733
|
*/
|
|
12477
|
-
addEvent(event) {
|
|
12478
|
-
return this._used.addEvent(event);
|
|
11734
|
+
addEvent(event, isCheckout) {
|
|
11735
|
+
return this._used.addEvent(event, isCheckout);
|
|
12479
11736
|
}
|
|
12480
11737
|
|
|
12481
11738
|
/** @inheritDoc */
|
|
@@ -12550,31 +11807,6 @@ function createEventBuffer({ useCompression }) {
|
|
|
12550
11807
|
return new EventBufferArray();
|
|
12551
11808
|
}
|
|
12552
11809
|
|
|
12553
|
-
/**
|
|
12554
|
-
* Removes the session from Session Storage and unsets session in replay instance
|
|
12555
|
-
*/
|
|
12556
|
-
function clearSession(replay) {
|
|
12557
|
-
deleteSession();
|
|
12558
|
-
replay.session = undefined;
|
|
12559
|
-
}
|
|
12560
|
-
|
|
12561
|
-
/**
|
|
12562
|
-
* Deletes a session from storage
|
|
12563
|
-
*/
|
|
12564
|
-
function deleteSession() {
|
|
12565
|
-
const hasSessionStorage = 'sessionStorage' in WINDOW;
|
|
12566
|
-
|
|
12567
|
-
if (!hasSessionStorage) {
|
|
12568
|
-
return;
|
|
12569
|
-
}
|
|
12570
|
-
|
|
12571
|
-
try {
|
|
12572
|
-
WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
|
|
12573
|
-
} catch (e) {
|
|
12574
|
-
// Ignore potential SecurityError exceptions
|
|
12575
|
-
}
|
|
12576
|
-
}
|
|
12577
|
-
|
|
12578
11810
|
/**
|
|
12579
11811
|
* Given an initial timestamp and an expiry duration, checks to see if current
|
|
12580
11812
|
* time should be considered as expired.
|
|
@@ -12605,26 +11837,11 @@ function isSessionExpired(session, timeouts, targetTime = +new Date()) {
|
|
|
12605
11837
|
// First, check that maximum session length has not been exceeded
|
|
12606
11838
|
isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
|
|
12607
11839
|
// check that the idle timeout has not been exceeded (i.e. user has
|
|
12608
|
-
// performed an action within the last `
|
|
12609
|
-
isExpired(session.lastActivity, timeouts.
|
|
11840
|
+
// performed an action within the last `idleTimeout` ms)
|
|
11841
|
+
isExpired(session.lastActivity, timeouts.sessionIdle, targetTime)
|
|
12610
11842
|
);
|
|
12611
11843
|
}
|
|
12612
11844
|
|
|
12613
|
-
/**
|
|
12614
|
-
* Given a sample rate, returns true if replay should be sampled.
|
|
12615
|
-
*
|
|
12616
|
-
* 1.0 = 100% sampling
|
|
12617
|
-
* 0.0 = 0% sampling
|
|
12618
|
-
*/
|
|
12619
|
-
function isSampled(sampleRate) {
|
|
12620
|
-
if (sampleRate === undefined) {
|
|
12621
|
-
return false;
|
|
12622
|
-
}
|
|
12623
|
-
|
|
12624
|
-
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12625
|
-
return Math.random() < sampleRate;
|
|
12626
|
-
}
|
|
12627
|
-
|
|
12628
11845
|
/**
|
|
12629
11846
|
* Save a session to session storage.
|
|
12630
11847
|
*/
|
|
@@ -12641,6 +11858,21 @@ function saveSession(session) {
|
|
|
12641
11858
|
}
|
|
12642
11859
|
}
|
|
12643
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
|
+
|
|
12644
11876
|
/**
|
|
12645
11877
|
* Get a session with defaults & applied sampling.
|
|
12646
11878
|
*/
|
|
@@ -12659,15 +11891,14 @@ function makeSession(session) {
|
|
|
12659
11891
|
lastActivity,
|
|
12660
11892
|
segmentId,
|
|
12661
11893
|
sampled,
|
|
12662
|
-
shouldRefresh: true,
|
|
12663
11894
|
};
|
|
12664
11895
|
}
|
|
12665
11896
|
|
|
12666
11897
|
/**
|
|
12667
11898
|
* Get the sampled status for a session based on sample rates & current sampled status.
|
|
12668
11899
|
*/
|
|
12669
|
-
function getSessionSampleType(sessionSampleRate,
|
|
12670
|
-
return isSampled(sessionSampleRate) ? 'session' :
|
|
11900
|
+
function getSessionSampleType(sessionSampleRate, errorSampleRate) {
|
|
11901
|
+
return isSampled(sessionSampleRate) ? 'session' : isSampled(errorSampleRate) ? 'error' : false;
|
|
12671
11902
|
}
|
|
12672
11903
|
|
|
12673
11904
|
/**
|
|
@@ -12675,8 +11906,8 @@ function getSessionSampleType(sessionSampleRate, allowBuffering) {
|
|
|
12675
11906
|
* that all replays will be saved to as attachments. Currently, we only expect
|
|
12676
11907
|
* one of these Sentry events per "replay session".
|
|
12677
11908
|
*/
|
|
12678
|
-
function createSession({ sessionSampleRate,
|
|
12679
|
-
const sampled = getSessionSampleType(sessionSampleRate,
|
|
11909
|
+
function createSession({ sessionSampleRate, errorSampleRate, stickySession = false }) {
|
|
11910
|
+
const sampled = getSessionSampleType(sessionSampleRate, errorSampleRate);
|
|
12680
11911
|
const session = makeSession({
|
|
12681
11912
|
sampled,
|
|
12682
11913
|
});
|
|
@@ -12724,7 +11955,7 @@ function getSession({
|
|
|
12724
11955
|
currentSession,
|
|
12725
11956
|
stickySession,
|
|
12726
11957
|
sessionSampleRate,
|
|
12727
|
-
|
|
11958
|
+
errorSampleRate,
|
|
12728
11959
|
}) {
|
|
12729
11960
|
// If session exists and is passed, use it instead of always hitting session storage
|
|
12730
11961
|
const session = currentSession || (stickySession && fetchSession());
|
|
@@ -12737,9 +11968,8 @@ function getSession({
|
|
|
12737
11968
|
|
|
12738
11969
|
if (!isExpired) {
|
|
12739
11970
|
return { type: 'saved', session };
|
|
12740
|
-
} else if (
|
|
12741
|
-
//
|
|
12742
|
-
// 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
|
|
12743
11973
|
const discardedSession = makeSession({ sampled: false });
|
|
12744
11974
|
return { type: 'new', session: discardedSession };
|
|
12745
11975
|
} else {
|
|
@@ -12751,12 +11981,65 @@ function getSession({
|
|
|
12751
11981
|
const newSession = createSession({
|
|
12752
11982
|
stickySession,
|
|
12753
11983
|
sessionSampleRate,
|
|
12754
|
-
|
|
11984
|
+
errorSampleRate,
|
|
12755
11985
|
});
|
|
12756
11986
|
|
|
12757
11987
|
return { type: 'new', session: newSession };
|
|
12758
11988
|
}
|
|
12759
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
|
+
|
|
12760
12043
|
/** If the event is an error event */
|
|
12761
12044
|
function isErrorEvent(event) {
|
|
12762
12045
|
return !event.type;
|
|
@@ -12806,21 +12089,31 @@ function handleAfterSendEvent(replay) {
|
|
|
12806
12089
|
return;
|
|
12807
12090
|
}
|
|
12808
12091
|
|
|
12809
|
-
// Add error to list of errorIds of replay
|
|
12810
|
-
// sampled because context will get reset at next checkout.
|
|
12811
|
-
// XXX: There is also a race condition where it's possible to capture an
|
|
12812
|
-
// error to Sentry before Replay SDK has loaded, but response returns after
|
|
12813
|
-
// it was loaded, and this gets called.
|
|
12092
|
+
// Add error to list of errorIds of replay
|
|
12814
12093
|
if (event.event_id) {
|
|
12815
12094
|
replay.getContext().errorIds.add(event.event_id);
|
|
12816
12095
|
}
|
|
12817
12096
|
|
|
12818
|
-
//
|
|
12097
|
+
// Trigger error recording
|
|
12819
12098
|
// Need to be very careful that this does not cause an infinite loop
|
|
12820
|
-
if (
|
|
12821
|
-
|
|
12822
|
-
|
|
12823
|
-
|
|
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
|
+
}
|
|
12824
12117
|
});
|
|
12825
12118
|
}
|
|
12826
12119
|
};
|
|
@@ -12842,6 +12135,166 @@ function isBaseTransportSend() {
|
|
|
12842
12135
|
);
|
|
12843
12136
|
}
|
|
12844
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
|
+
|
|
12845
12298
|
/**
|
|
12846
12299
|
* Returns true if we think the given event is an error originating inside of rrweb.
|
|
12847
12300
|
*/
|
|
@@ -12865,30 +12318,6 @@ function isRrwebError(event, hint) {
|
|
|
12865
12318
|
});
|
|
12866
12319
|
}
|
|
12867
12320
|
|
|
12868
|
-
/**
|
|
12869
|
-
* Determine if event should be sampled (only applies in buffer mode).
|
|
12870
|
-
* When an event is captured by `hanldleGlobalEvent`, when in buffer mode
|
|
12871
|
-
* we determine if we want to sample the error or not.
|
|
12872
|
-
*/
|
|
12873
|
-
function shouldSampleForBufferEvent(replay, event) {
|
|
12874
|
-
if (replay.recordingMode !== 'buffer') {
|
|
12875
|
-
return false;
|
|
12876
|
-
}
|
|
12877
|
-
|
|
12878
|
-
// ignore this error because otherwise we could loop indefinitely with
|
|
12879
|
-
// trying to capture replay and failing
|
|
12880
|
-
if (event.message === UNABLE_TO_SEND_REPLAY) {
|
|
12881
|
-
return false;
|
|
12882
|
-
}
|
|
12883
|
-
|
|
12884
|
-
// Require the event to be an error event & to have an exception
|
|
12885
|
-
if (!event.exception || event.type) {
|
|
12886
|
-
return false;
|
|
12887
|
-
}
|
|
12888
|
-
|
|
12889
|
-
return isSampled(replay.getOptions().errorSampleRate);
|
|
12890
|
-
}
|
|
12891
|
-
|
|
12892
12321
|
/**
|
|
12893
12322
|
* Returns a listener to be added to `addGlobalEventProcessor(listener)`.
|
|
12894
12323
|
*/
|
|
@@ -12918,16 +12347,8 @@ function handleGlobalEventListener(
|
|
|
12918
12347
|
return null;
|
|
12919
12348
|
}
|
|
12920
12349
|
|
|
12921
|
-
//
|
|
12922
|
-
|
|
12923
|
-
// And convert the buffer session to a full session
|
|
12924
|
-
const isErrorEventSampled = shouldSampleForBufferEvent(replay, event);
|
|
12925
|
-
|
|
12926
|
-
// Tag errors if it has been sampled in buffer mode, or if it is session mode
|
|
12927
|
-
// Only tag transactions if in session mode
|
|
12928
|
-
const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session';
|
|
12929
|
-
|
|
12930
|
-
if (shouldTagReplayId) {
|
|
12350
|
+
// Only tag transactions with replayId if not waiting for an error
|
|
12351
|
+
if (isErrorEvent(event) || (isTransactionEvent(event) && replay.recordingMode === 'session')) {
|
|
12931
12352
|
event.tags = { ...event.tags, replayId: replay.getSessionId() };
|
|
12932
12353
|
}
|
|
12933
12354
|
|
|
@@ -12977,7 +12398,7 @@ function createPerformanceSpans(
|
|
|
12977
12398
|
) {
|
|
12978
12399
|
return entries.map(({ type, start, end, name, data }) =>
|
|
12979
12400
|
addEvent(replay, {
|
|
12980
|
-
type: EventType
|
|
12401
|
+
type: EventType.Custom,
|
|
12981
12402
|
timestamp: start,
|
|
12982
12403
|
data: {
|
|
12983
12404
|
tag: 'performanceSpan',
|
|
@@ -13126,14 +12547,12 @@ function handleFetchSpanListener(replay) {
|
|
|
13126
12547
|
function handleXhr(handlerData) {
|
|
13127
12548
|
const { startTimestamp, endTimestamp, xhr } = handlerData;
|
|
13128
12549
|
|
|
13129
|
-
|
|
13130
|
-
|
|
13131
|
-
if (!startTimestamp || !endTimestamp || !sentryXhrData) {
|
|
12550
|
+
if (!startTimestamp || !endTimestamp || !xhr.__sentry_xhr__) {
|
|
13132
12551
|
return null;
|
|
13133
12552
|
}
|
|
13134
12553
|
|
|
13135
12554
|
// This is only used as a fallback, so we know the body sizes are never set here
|
|
13136
|
-
const { method, url, status_code: statusCode } =
|
|
12555
|
+
const { method, url, status_code: statusCode } = xhr.__sentry_xhr__;
|
|
13137
12556
|
|
|
13138
12557
|
if (url === undefined) {
|
|
13139
12558
|
return null;
|
|
@@ -13166,393 +12585,6 @@ function handleXhrSpanListener(replay) {
|
|
|
13166
12585
|
};
|
|
13167
12586
|
}
|
|
13168
12587
|
|
|
13169
|
-
const OBJ = 10;
|
|
13170
|
-
const OBJ_KEY = 11;
|
|
13171
|
-
const OBJ_KEY_STR = 12;
|
|
13172
|
-
const OBJ_VAL = 13;
|
|
13173
|
-
const OBJ_VAL_STR = 14;
|
|
13174
|
-
const OBJ_VAL_COMPLETED = 15;
|
|
13175
|
-
|
|
13176
|
-
const ARR = 20;
|
|
13177
|
-
const ARR_VAL = 21;
|
|
13178
|
-
const ARR_VAL_STR = 22;
|
|
13179
|
-
const ARR_VAL_COMPLETED = 23;
|
|
13180
|
-
|
|
13181
|
-
const ALLOWED_PRIMITIVES = ['true', 'false', 'null'];
|
|
13182
|
-
|
|
13183
|
-
/**
|
|
13184
|
-
* Complete an incomplete JSON string.
|
|
13185
|
-
* This will ensure that the last element always has a `"~~"` to indicate it was truncated.
|
|
13186
|
-
* For example, `[1,2,` will be completed to `[1,2,"~~"]`
|
|
13187
|
-
* and `{"aa":"b` will be completed to `{"aa":"b~~"}`
|
|
13188
|
-
*/
|
|
13189
|
-
function completeJson(incompleteJson, stack) {
|
|
13190
|
-
if (!stack.length) {
|
|
13191
|
-
return incompleteJson;
|
|
13192
|
-
}
|
|
13193
|
-
|
|
13194
|
-
let json = incompleteJson;
|
|
13195
|
-
|
|
13196
|
-
// Most checks are only needed for the last step in the stack
|
|
13197
|
-
const lastPos = stack.length - 1;
|
|
13198
|
-
const lastStep = stack[lastPos];
|
|
13199
|
-
|
|
13200
|
-
json = _fixLastStep(json, lastStep);
|
|
13201
|
-
|
|
13202
|
-
// Complete remaining steps - just add closing brackets
|
|
13203
|
-
for (let i = lastPos; i >= 0; i--) {
|
|
13204
|
-
const step = stack[i];
|
|
13205
|
-
|
|
13206
|
-
switch (step) {
|
|
13207
|
-
case OBJ:
|
|
13208
|
-
json = `${json}}`;
|
|
13209
|
-
break;
|
|
13210
|
-
case ARR:
|
|
13211
|
-
json = `${json}]`;
|
|
13212
|
-
break;
|
|
13213
|
-
}
|
|
13214
|
-
}
|
|
13215
|
-
|
|
13216
|
-
return json;
|
|
13217
|
-
}
|
|
13218
|
-
|
|
13219
|
-
function _fixLastStep(json, lastStep) {
|
|
13220
|
-
switch (lastStep) {
|
|
13221
|
-
// Object cases
|
|
13222
|
-
case OBJ:
|
|
13223
|
-
return `${json}"~~":"~~"`;
|
|
13224
|
-
case OBJ_KEY:
|
|
13225
|
-
return `${json}:"~~"`;
|
|
13226
|
-
case OBJ_KEY_STR:
|
|
13227
|
-
return `${json}~~":"~~"`;
|
|
13228
|
-
case OBJ_VAL:
|
|
13229
|
-
return _maybeFixIncompleteObjValue(json);
|
|
13230
|
-
case OBJ_VAL_STR:
|
|
13231
|
-
return `${json}~~"`;
|
|
13232
|
-
case OBJ_VAL_COMPLETED:
|
|
13233
|
-
return `${json},"~~":"~~"`;
|
|
13234
|
-
|
|
13235
|
-
// Array cases
|
|
13236
|
-
case ARR:
|
|
13237
|
-
return `${json}"~~"`;
|
|
13238
|
-
case ARR_VAL:
|
|
13239
|
-
return _maybeFixIncompleteArrValue(json);
|
|
13240
|
-
case ARR_VAL_STR:
|
|
13241
|
-
return `${json}~~"`;
|
|
13242
|
-
case ARR_VAL_COMPLETED:
|
|
13243
|
-
return `${json},"~~"`;
|
|
13244
|
-
}
|
|
13245
|
-
|
|
13246
|
-
return json;
|
|
13247
|
-
}
|
|
13248
|
-
|
|
13249
|
-
function _maybeFixIncompleteArrValue(json) {
|
|
13250
|
-
const pos = _findLastArrayDelimiter(json);
|
|
13251
|
-
|
|
13252
|
-
if (pos > -1) {
|
|
13253
|
-
const part = json.slice(pos + 1);
|
|
13254
|
-
|
|
13255
|
-
if (ALLOWED_PRIMITIVES.includes(part.trim())) {
|
|
13256
|
-
return `${json},"~~"`;
|
|
13257
|
-
}
|
|
13258
|
-
|
|
13259
|
-
// Everything else is replaced with `"~~"`
|
|
13260
|
-
return `${json.slice(0, pos + 1)}"~~"`;
|
|
13261
|
-
}
|
|
13262
|
-
|
|
13263
|
-
// fallback, this shouldn't happen, to be save
|
|
13264
|
-
return json;
|
|
13265
|
-
}
|
|
13266
|
-
|
|
13267
|
-
function _findLastArrayDelimiter(json) {
|
|
13268
|
-
for (let i = json.length - 1; i >= 0; i--) {
|
|
13269
|
-
const char = json[i];
|
|
13270
|
-
|
|
13271
|
-
if (char === ',' || char === '[') {
|
|
13272
|
-
return i;
|
|
13273
|
-
}
|
|
13274
|
-
}
|
|
13275
|
-
|
|
13276
|
-
return -1;
|
|
13277
|
-
}
|
|
13278
|
-
|
|
13279
|
-
function _maybeFixIncompleteObjValue(json) {
|
|
13280
|
-
const startPos = json.lastIndexOf(':');
|
|
13281
|
-
|
|
13282
|
-
const part = json.slice(startPos + 1);
|
|
13283
|
-
|
|
13284
|
-
if (ALLOWED_PRIMITIVES.includes(part.trim())) {
|
|
13285
|
-
return `${json},"~~":"~~"`;
|
|
13286
|
-
}
|
|
13287
|
-
|
|
13288
|
-
// Everything else is replaced with `"~~"`
|
|
13289
|
-
// This also means we do not have incomplete numbers, e.g `[1` is replaced with `["~~"]`
|
|
13290
|
-
return `${json.slice(0, startPos + 1)}"~~"`;
|
|
13291
|
-
}
|
|
13292
|
-
|
|
13293
|
-
/**
|
|
13294
|
-
* Evaluate an (incomplete) JSON string.
|
|
13295
|
-
*/
|
|
13296
|
-
function evaluateJson(json) {
|
|
13297
|
-
const stack = [];
|
|
13298
|
-
|
|
13299
|
-
for (let pos = 0; pos < json.length; pos++) {
|
|
13300
|
-
_evaluateJsonPos(stack, json, pos);
|
|
13301
|
-
}
|
|
13302
|
-
|
|
13303
|
-
return stack;
|
|
13304
|
-
}
|
|
13305
|
-
|
|
13306
|
-
function _evaluateJsonPos(stack, json, pos) {
|
|
13307
|
-
const curStep = stack[stack.length - 1];
|
|
13308
|
-
|
|
13309
|
-
const char = json[pos];
|
|
13310
|
-
|
|
13311
|
-
const whitespaceRegex = /\s/;
|
|
13312
|
-
|
|
13313
|
-
if (whitespaceRegex.test(char)) {
|
|
13314
|
-
return;
|
|
13315
|
-
}
|
|
13316
|
-
|
|
13317
|
-
if (char === '"' && !_isEscaped(json, pos)) {
|
|
13318
|
-
_handleQuote(stack, curStep);
|
|
13319
|
-
return;
|
|
13320
|
-
}
|
|
13321
|
-
|
|
13322
|
-
switch (char) {
|
|
13323
|
-
case '{':
|
|
13324
|
-
_handleObj(stack, curStep);
|
|
13325
|
-
break;
|
|
13326
|
-
case '[':
|
|
13327
|
-
_handleArr(stack, curStep);
|
|
13328
|
-
break;
|
|
13329
|
-
case ':':
|
|
13330
|
-
_handleColon(stack, curStep);
|
|
13331
|
-
break;
|
|
13332
|
-
case ',':
|
|
13333
|
-
_handleComma(stack, curStep);
|
|
13334
|
-
break;
|
|
13335
|
-
case '}':
|
|
13336
|
-
_handleObjClose(stack, curStep);
|
|
13337
|
-
break;
|
|
13338
|
-
case ']':
|
|
13339
|
-
_handleArrClose(stack, curStep);
|
|
13340
|
-
break;
|
|
13341
|
-
}
|
|
13342
|
-
}
|
|
13343
|
-
|
|
13344
|
-
function _handleQuote(stack, curStep) {
|
|
13345
|
-
// End of obj value
|
|
13346
|
-
if (curStep === OBJ_VAL_STR) {
|
|
13347
|
-
stack.pop();
|
|
13348
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13349
|
-
return;
|
|
13350
|
-
}
|
|
13351
|
-
|
|
13352
|
-
// End of arr value
|
|
13353
|
-
if (curStep === ARR_VAL_STR) {
|
|
13354
|
-
stack.pop();
|
|
13355
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13356
|
-
return;
|
|
13357
|
-
}
|
|
13358
|
-
|
|
13359
|
-
// Start of obj value
|
|
13360
|
-
if (curStep === OBJ_VAL) {
|
|
13361
|
-
stack.push(OBJ_VAL_STR);
|
|
13362
|
-
return;
|
|
13363
|
-
}
|
|
13364
|
-
|
|
13365
|
-
// Start of arr value
|
|
13366
|
-
if (curStep === ARR_VAL) {
|
|
13367
|
-
stack.push(ARR_VAL_STR);
|
|
13368
|
-
return;
|
|
13369
|
-
}
|
|
13370
|
-
|
|
13371
|
-
// Start of obj key
|
|
13372
|
-
if (curStep === OBJ) {
|
|
13373
|
-
stack.push(OBJ_KEY_STR);
|
|
13374
|
-
return;
|
|
13375
|
-
}
|
|
13376
|
-
|
|
13377
|
-
// End of obj key
|
|
13378
|
-
if (curStep === OBJ_KEY_STR) {
|
|
13379
|
-
stack.pop();
|
|
13380
|
-
stack.push(OBJ_KEY);
|
|
13381
|
-
return;
|
|
13382
|
-
}
|
|
13383
|
-
}
|
|
13384
|
-
|
|
13385
|
-
function _handleObj(stack, curStep) {
|
|
13386
|
-
// Initial object
|
|
13387
|
-
if (!curStep) {
|
|
13388
|
-
stack.push(OBJ);
|
|
13389
|
-
return;
|
|
13390
|
-
}
|
|
13391
|
-
|
|
13392
|
-
// New object as obj value
|
|
13393
|
-
if (curStep === OBJ_VAL) {
|
|
13394
|
-
stack.push(OBJ);
|
|
13395
|
-
return;
|
|
13396
|
-
}
|
|
13397
|
-
|
|
13398
|
-
// New object as array element
|
|
13399
|
-
if (curStep === ARR_VAL) {
|
|
13400
|
-
stack.push(OBJ);
|
|
13401
|
-
}
|
|
13402
|
-
|
|
13403
|
-
// New object as first array element
|
|
13404
|
-
if (curStep === ARR) {
|
|
13405
|
-
stack.push(OBJ);
|
|
13406
|
-
return;
|
|
13407
|
-
}
|
|
13408
|
-
}
|
|
13409
|
-
|
|
13410
|
-
function _handleArr(stack, curStep) {
|
|
13411
|
-
// Initial array
|
|
13412
|
-
if (!curStep) {
|
|
13413
|
-
stack.push(ARR);
|
|
13414
|
-
stack.push(ARR_VAL);
|
|
13415
|
-
return;
|
|
13416
|
-
}
|
|
13417
|
-
|
|
13418
|
-
// New array as obj value
|
|
13419
|
-
if (curStep === OBJ_VAL) {
|
|
13420
|
-
stack.push(ARR);
|
|
13421
|
-
stack.push(ARR_VAL);
|
|
13422
|
-
return;
|
|
13423
|
-
}
|
|
13424
|
-
|
|
13425
|
-
// New array as array element
|
|
13426
|
-
if (curStep === ARR_VAL) {
|
|
13427
|
-
stack.push(ARR);
|
|
13428
|
-
stack.push(ARR_VAL);
|
|
13429
|
-
}
|
|
13430
|
-
|
|
13431
|
-
// New array as first array element
|
|
13432
|
-
if (curStep === ARR) {
|
|
13433
|
-
stack.push(ARR);
|
|
13434
|
-
stack.push(ARR_VAL);
|
|
13435
|
-
return;
|
|
13436
|
-
}
|
|
13437
|
-
}
|
|
13438
|
-
|
|
13439
|
-
function _handleColon(stack, curStep) {
|
|
13440
|
-
if (curStep === OBJ_KEY) {
|
|
13441
|
-
stack.pop();
|
|
13442
|
-
stack.push(OBJ_VAL);
|
|
13443
|
-
}
|
|
13444
|
-
}
|
|
13445
|
-
|
|
13446
|
-
function _handleComma(stack, curStep) {
|
|
13447
|
-
// Comma after obj value
|
|
13448
|
-
if (curStep === OBJ_VAL) {
|
|
13449
|
-
stack.pop();
|
|
13450
|
-
return;
|
|
13451
|
-
}
|
|
13452
|
-
if (curStep === OBJ_VAL_COMPLETED) {
|
|
13453
|
-
// Pop OBJ_VAL_COMPLETED & OBJ_VAL
|
|
13454
|
-
stack.pop();
|
|
13455
|
-
stack.pop();
|
|
13456
|
-
return;
|
|
13457
|
-
}
|
|
13458
|
-
|
|
13459
|
-
// Comma after arr value
|
|
13460
|
-
if (curStep === ARR_VAL) {
|
|
13461
|
-
// do nothing - basically we'd pop ARR_VAL but add it right back
|
|
13462
|
-
return;
|
|
13463
|
-
}
|
|
13464
|
-
|
|
13465
|
-
if (curStep === ARR_VAL_COMPLETED) {
|
|
13466
|
-
// Pop ARR_VAL_COMPLETED
|
|
13467
|
-
stack.pop();
|
|
13468
|
-
|
|
13469
|
-
// basically we'd pop ARR_VAL but add it right back
|
|
13470
|
-
return;
|
|
13471
|
-
}
|
|
13472
|
-
}
|
|
13473
|
-
|
|
13474
|
-
function _handleObjClose(stack, curStep) {
|
|
13475
|
-
// Empty object {}
|
|
13476
|
-
if (curStep === OBJ) {
|
|
13477
|
-
stack.pop();
|
|
13478
|
-
}
|
|
13479
|
-
|
|
13480
|
-
// Object with element
|
|
13481
|
-
if (curStep === OBJ_VAL) {
|
|
13482
|
-
// Pop OBJ_VAL, OBJ
|
|
13483
|
-
stack.pop();
|
|
13484
|
-
stack.pop();
|
|
13485
|
-
}
|
|
13486
|
-
|
|
13487
|
-
// Obj with element
|
|
13488
|
-
if (curStep === OBJ_VAL_COMPLETED) {
|
|
13489
|
-
// Pop OBJ_VAL_COMPLETED, OBJ_VAL, OBJ
|
|
13490
|
-
stack.pop();
|
|
13491
|
-
stack.pop();
|
|
13492
|
-
stack.pop();
|
|
13493
|
-
}
|
|
13494
|
-
|
|
13495
|
-
// if was obj value, complete it
|
|
13496
|
-
if (stack[stack.length - 1] === OBJ_VAL) {
|
|
13497
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13498
|
-
}
|
|
13499
|
-
|
|
13500
|
-
// if was arr value, complete it
|
|
13501
|
-
if (stack[stack.length - 1] === ARR_VAL) {
|
|
13502
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13503
|
-
}
|
|
13504
|
-
}
|
|
13505
|
-
|
|
13506
|
-
function _handleArrClose(stack, curStep) {
|
|
13507
|
-
// Empty array []
|
|
13508
|
-
if (curStep === ARR) {
|
|
13509
|
-
stack.pop();
|
|
13510
|
-
}
|
|
13511
|
-
|
|
13512
|
-
// Array with element
|
|
13513
|
-
if (curStep === ARR_VAL) {
|
|
13514
|
-
// Pop ARR_VAL, ARR
|
|
13515
|
-
stack.pop();
|
|
13516
|
-
stack.pop();
|
|
13517
|
-
}
|
|
13518
|
-
|
|
13519
|
-
// Array with element
|
|
13520
|
-
if (curStep === ARR_VAL_COMPLETED) {
|
|
13521
|
-
// Pop ARR_VAL_COMPLETED, ARR_VAL, ARR
|
|
13522
|
-
stack.pop();
|
|
13523
|
-
stack.pop();
|
|
13524
|
-
stack.pop();
|
|
13525
|
-
}
|
|
13526
|
-
|
|
13527
|
-
// if was obj value, complete it
|
|
13528
|
-
if (stack[stack.length - 1] === OBJ_VAL) {
|
|
13529
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13530
|
-
}
|
|
13531
|
-
|
|
13532
|
-
// if was arr value, complete it
|
|
13533
|
-
if (stack[stack.length - 1] === ARR_VAL) {
|
|
13534
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13535
|
-
}
|
|
13536
|
-
}
|
|
13537
|
-
|
|
13538
|
-
function _isEscaped(str, pos) {
|
|
13539
|
-
const previousChar = str[pos - 1];
|
|
13540
|
-
|
|
13541
|
-
return previousChar === '\\' && !_isEscaped(str, pos - 1);
|
|
13542
|
-
}
|
|
13543
|
-
|
|
13544
|
-
/* eslint-disable max-lines */
|
|
13545
|
-
|
|
13546
|
-
/**
|
|
13547
|
-
* Takes an incomplete JSON string, and returns a hopefully valid JSON string.
|
|
13548
|
-
* Note that this _can_ fail, so you should check the return value is valid JSON.
|
|
13549
|
-
*/
|
|
13550
|
-
function fixJson(incompleteJson) {
|
|
13551
|
-
const stack = evaluateJson(incompleteJson);
|
|
13552
|
-
|
|
13553
|
-
return completeJson(incompleteJson, stack);
|
|
13554
|
-
}
|
|
13555
|
-
|
|
13556
12588
|
/** Get the size of a body. */
|
|
13557
12589
|
function getBodySize(
|
|
13558
12590
|
body,
|
|
@@ -13646,68 +12678,51 @@ function makeNetworkReplayBreadcrumb(
|
|
|
13646
12678
|
return result;
|
|
13647
12679
|
}
|
|
13648
12680
|
|
|
13649
|
-
/**
|
|
13650
|
-
function
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
}
|
|
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;
|
|
13658
12694
|
}
|
|
13659
12695
|
|
|
13660
12696
|
/** Build the request or response part of a replay network breadcrumb. */
|
|
13661
12697
|
function buildNetworkRequestOrResponse(
|
|
13662
|
-
headers,
|
|
13663
12698
|
bodySize,
|
|
13664
12699
|
body,
|
|
13665
12700
|
) {
|
|
13666
|
-
if (!bodySize && Object.keys(headers).length === 0) {
|
|
13667
|
-
return undefined;
|
|
13668
|
-
}
|
|
13669
|
-
|
|
13670
12701
|
if (!bodySize) {
|
|
13671
|
-
return
|
|
13672
|
-
headers,
|
|
13673
|
-
};
|
|
12702
|
+
return undefined;
|
|
13674
12703
|
}
|
|
13675
12704
|
|
|
13676
12705
|
if (!body) {
|
|
13677
12706
|
return {
|
|
13678
|
-
headers,
|
|
13679
12707
|
size: bodySize,
|
|
13680
12708
|
};
|
|
13681
12709
|
}
|
|
13682
12710
|
|
|
13683
12711
|
const info = {
|
|
13684
|
-
headers,
|
|
13685
12712
|
size: bodySize,
|
|
13686
12713
|
};
|
|
13687
12714
|
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
12715
|
+
if (bodySize < NETWORK_BODY_MAX_SIZE) {
|
|
12716
|
+
info.body = body;
|
|
12717
|
+
} else {
|
|
13691
12718
|
info._meta = {
|
|
13692
|
-
|
|
12719
|
+
errors: ['MAX_BODY_SIZE_EXCEEDED'],
|
|
13693
12720
|
};
|
|
13694
12721
|
}
|
|
13695
12722
|
|
|
13696
12723
|
return info;
|
|
13697
12724
|
}
|
|
13698
12725
|
|
|
13699
|
-
/** Filter a set of headers */
|
|
13700
|
-
function getAllowedHeaders(headers, allowedHeaders) {
|
|
13701
|
-
return Object.keys(headers).reduce((filteredHeaders, key) => {
|
|
13702
|
-
const normalizedKey = key.toLowerCase();
|
|
13703
|
-
// Avoid putting empty strings into the headers
|
|
13704
|
-
if (allowedHeaders.includes(normalizedKey) && headers[key]) {
|
|
13705
|
-
filteredHeaders[normalizedKey] = headers[key];
|
|
13706
|
-
}
|
|
13707
|
-
return filteredHeaders;
|
|
13708
|
-
}, {});
|
|
13709
|
-
}
|
|
13710
|
-
|
|
13711
12726
|
function _serializeFormData(formData) {
|
|
13712
12727
|
// This is a bit simplified, but gives us a decent estimate
|
|
13713
12728
|
// This converts e.g. { name: 'Anne Smith', age: 13 } to 'name=Anne+Smith&age=13'
|
|
@@ -13715,78 +12730,6 @@ function _serializeFormData(formData) {
|
|
|
13715
12730
|
return new URLSearchParams(formData).toString();
|
|
13716
12731
|
}
|
|
13717
12732
|
|
|
13718
|
-
function normalizeNetworkBody(body)
|
|
13719
|
-
|
|
13720
|
-
{
|
|
13721
|
-
if (!body || typeof body !== 'string') {
|
|
13722
|
-
return {
|
|
13723
|
-
body,
|
|
13724
|
-
warnings: [],
|
|
13725
|
-
};
|
|
13726
|
-
}
|
|
13727
|
-
|
|
13728
|
-
const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE;
|
|
13729
|
-
|
|
13730
|
-
if (_strIsProbablyJson(body)) {
|
|
13731
|
-
try {
|
|
13732
|
-
const json = exceedsSizeLimit ? fixJson(body.slice(0, NETWORK_BODY_MAX_SIZE)) : body;
|
|
13733
|
-
const normalizedBody = JSON.parse(json);
|
|
13734
|
-
return {
|
|
13735
|
-
body: normalizedBody,
|
|
13736
|
-
warnings: exceedsSizeLimit ? ['JSON_TRUNCATED'] : [],
|
|
13737
|
-
};
|
|
13738
|
-
} catch (e3) {
|
|
13739
|
-
return {
|
|
13740
|
-
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13741
|
-
warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
|
|
13742
|
-
};
|
|
13743
|
-
}
|
|
13744
|
-
}
|
|
13745
|
-
|
|
13746
|
-
return {
|
|
13747
|
-
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13748
|
-
warnings: exceedsSizeLimit ? ['TEXT_TRUNCATED'] : [],
|
|
13749
|
-
};
|
|
13750
|
-
}
|
|
13751
|
-
|
|
13752
|
-
function _strIsProbablyJson(str) {
|
|
13753
|
-
const first = str[0];
|
|
13754
|
-
const last = str[str.length - 1];
|
|
13755
|
-
|
|
13756
|
-
// Simple check: If this does not start & end with {} or [], it's not JSON
|
|
13757
|
-
return (first === '[' && last === ']') || (first === '{' && last === '}');
|
|
13758
|
-
}
|
|
13759
|
-
|
|
13760
|
-
/** Match an URL against a list of strings/Regex. */
|
|
13761
|
-
function urlMatches(url, urls) {
|
|
13762
|
-
const fullUrl = getFullUrl(url);
|
|
13763
|
-
|
|
13764
|
-
return stringMatchesSomePattern(fullUrl, urls);
|
|
13765
|
-
}
|
|
13766
|
-
|
|
13767
|
-
/** exported for tests */
|
|
13768
|
-
function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
|
|
13769
|
-
// Short circuit for common cases:
|
|
13770
|
-
if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith(WINDOW.location.origin)) {
|
|
13771
|
-
return url;
|
|
13772
|
-
}
|
|
13773
|
-
const fixedUrl = new URL(url, baseURI);
|
|
13774
|
-
|
|
13775
|
-
// If these do not match, we are not dealing with a relative URL, so just return it
|
|
13776
|
-
if (fixedUrl.origin !== new URL(baseURI).origin) {
|
|
13777
|
-
return url;
|
|
13778
|
-
}
|
|
13779
|
-
|
|
13780
|
-
const fullUrl = fixedUrl.href;
|
|
13781
|
-
|
|
13782
|
-
// Remove trailing slashes, if they don't match the original URL
|
|
13783
|
-
if (!url.endsWith('/') && fullUrl.endsWith('/')) {
|
|
13784
|
-
return fullUrl.slice(0, -1);
|
|
13785
|
-
}
|
|
13786
|
-
|
|
13787
|
-
return fullUrl;
|
|
13788
|
-
}
|
|
13789
|
-
|
|
13790
12733
|
/**
|
|
13791
12734
|
* Capture a fetch breadcrumb to a replay.
|
|
13792
12735
|
* This adds additional data (where approriate).
|
|
@@ -13794,9 +12737,7 @@ function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
|
|
|
13794
12737
|
async function captureFetchBreadcrumbToReplay(
|
|
13795
12738
|
breadcrumb,
|
|
13796
12739
|
hint,
|
|
13797
|
-
options
|
|
13798
|
-
|
|
13799
|
-
,
|
|
12740
|
+
options,
|
|
13800
12741
|
) {
|
|
13801
12742
|
try {
|
|
13802
12743
|
const data = await _prepareFetchData(breadcrumb, hint, options);
|
|
@@ -13823,7 +12764,6 @@ function enrichFetchBreadcrumb(
|
|
|
13823
12764
|
|
|
13824
12765
|
const body = _getFetchRequestArgBody(input);
|
|
13825
12766
|
const reqSize = getBodySize(body, options.textEncoder);
|
|
13826
|
-
|
|
13827
12767
|
const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined;
|
|
13828
12768
|
|
|
13829
12769
|
if (reqSize !== undefined) {
|
|
@@ -13837,109 +12777,97 @@ function enrichFetchBreadcrumb(
|
|
|
13837
12777
|
async function _prepareFetchData(
|
|
13838
12778
|
breadcrumb,
|
|
13839
12779
|
hint,
|
|
13840
|
-
options
|
|
13841
|
-
|
|
13842
|
-
,
|
|
12780
|
+
options,
|
|
13843
12781
|
) {
|
|
13844
12782
|
const { startTimestamp, endTimestamp } = hint;
|
|
13845
12783
|
|
|
13846
12784
|
const {
|
|
13847
12785
|
url,
|
|
13848
12786
|
method,
|
|
13849
|
-
status_code: statusCode
|
|
12787
|
+
status_code: statusCode,
|
|
13850
12788
|
request_body_size: requestBodySize,
|
|
13851
12789
|
response_body_size: responseBodySize,
|
|
13852
12790
|
} = breadcrumb.data;
|
|
13853
12791
|
|
|
13854
|
-
const
|
|
13855
|
-
|
|
13856
|
-
const request = captureDetails
|
|
13857
|
-
? _getRequestInfo(options, hint.input, requestBodySize)
|
|
13858
|
-
: buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13859
|
-
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);
|
|
13860
12794
|
|
|
13861
12795
|
return {
|
|
13862
12796
|
startTimestamp,
|
|
13863
12797
|
endTimestamp,
|
|
13864
12798
|
url,
|
|
13865
12799
|
method,
|
|
13866
|
-
statusCode,
|
|
12800
|
+
statusCode: statusCode || 0,
|
|
13867
12801
|
request,
|
|
13868
12802
|
response,
|
|
13869
12803
|
};
|
|
13870
12804
|
}
|
|
13871
12805
|
|
|
13872
12806
|
function _getRequestInfo(
|
|
13873
|
-
{
|
|
12807
|
+
{ captureBodies },
|
|
13874
12808
|
input,
|
|
13875
12809
|
requestBodySize,
|
|
13876
12810
|
) {
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
if (!networkCaptureBodies) {
|
|
13880
|
-
return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
|
|
12811
|
+
if (!captureBodies) {
|
|
12812
|
+
return buildNetworkRequestOrResponse(requestBodySize, undefined);
|
|
13881
12813
|
}
|
|
13882
12814
|
|
|
13883
12815
|
// We only want to transmit string or string-like bodies
|
|
13884
12816
|
const requestBody = _getFetchRequestArgBody(input);
|
|
13885
|
-
const
|
|
13886
|
-
return buildNetworkRequestOrResponse(
|
|
12817
|
+
const body = getNetworkBody(getBodyString(requestBody));
|
|
12818
|
+
return buildNetworkRequestOrResponse(requestBodySize, body);
|
|
13887
12819
|
}
|
|
13888
12820
|
|
|
13889
12821
|
async function _getResponseInfo(
|
|
13890
|
-
|
|
13891
|
-
{
|
|
13892
|
-
networkCaptureBodies,
|
|
13893
|
-
textEncoder,
|
|
13894
|
-
networkResponseHeaders,
|
|
13895
|
-
}
|
|
13896
|
-
|
|
13897
|
-
,
|
|
12822
|
+
{ captureBodies, textEncoder },
|
|
13898
12823
|
response,
|
|
13899
12824
|
responseBodySize,
|
|
13900
12825
|
) {
|
|
13901
|
-
if (!
|
|
13902
|
-
return
|
|
13903
|
-
}
|
|
13904
|
-
|
|
13905
|
-
const headers = getAllHeaders(response.headers, networkResponseHeaders);
|
|
13906
|
-
|
|
13907
|
-
if (!networkCaptureBodies && responseBodySize !== undefined) {
|
|
13908
|
-
return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
|
|
12826
|
+
if (!captureBodies && responseBodySize !== undefined) {
|
|
12827
|
+
return buildNetworkRequestOrResponse(responseBodySize, undefined);
|
|
13909
12828
|
}
|
|
13910
12829
|
|
|
13911
12830
|
// Only clone the response if we need to
|
|
13912
12831
|
try {
|
|
13913
12832
|
// We have to clone this, as the body can only be read once
|
|
13914
12833
|
const res = response.clone();
|
|
13915
|
-
const bodyText = await _parseFetchBody(res);
|
|
12834
|
+
const { body, bodyText } = await _parseFetchBody(res);
|
|
13916
12835
|
|
|
13917
12836
|
const size =
|
|
13918
12837
|
bodyText && bodyText.length && responseBodySize === undefined
|
|
13919
12838
|
? getBodySize(bodyText, textEncoder)
|
|
13920
12839
|
: responseBodySize;
|
|
13921
12840
|
|
|
13922
|
-
if (
|
|
13923
|
-
return
|
|
12841
|
+
if (captureBodies) {
|
|
12842
|
+
return buildNetworkRequestOrResponse(size, body);
|
|
13924
12843
|
}
|
|
13925
12844
|
|
|
13926
|
-
|
|
13927
|
-
return buildNetworkRequestOrResponse(headers, size, bodyText);
|
|
13928
|
-
}
|
|
13929
|
-
|
|
13930
|
-
return buildNetworkRequestOrResponse(headers, size, undefined);
|
|
12845
|
+
return buildNetworkRequestOrResponse(size, undefined);
|
|
13931
12846
|
} catch (e) {
|
|
13932
12847
|
// fallback
|
|
13933
|
-
return buildNetworkRequestOrResponse(
|
|
12848
|
+
return buildNetworkRequestOrResponse(responseBodySize, undefined);
|
|
13934
12849
|
}
|
|
13935
12850
|
}
|
|
13936
12851
|
|
|
13937
|
-
async function _parseFetchBody(
|
|
12852
|
+
async function _parseFetchBody(
|
|
12853
|
+
response,
|
|
12854
|
+
) {
|
|
12855
|
+
let bodyText;
|
|
12856
|
+
|
|
13938
12857
|
try {
|
|
13939
|
-
|
|
12858
|
+
bodyText = await response.text();
|
|
13940
12859
|
} catch (e2) {
|
|
13941
|
-
return
|
|
12860
|
+
return {};
|
|
13942
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 };
|
|
13943
12871
|
}
|
|
13944
12872
|
|
|
13945
12873
|
function _getFetchRequestArgBody(fetchArgs = []) {
|
|
@@ -13951,56 +12879,6 @@ function _getFetchRequestArgBody(fetchArgs = []) {
|
|
|
13951
12879
|
return (fetchArgs[1] ).body;
|
|
13952
12880
|
}
|
|
13953
12881
|
|
|
13954
|
-
function getAllHeaders(headers, allowedHeaders) {
|
|
13955
|
-
const allHeaders = {};
|
|
13956
|
-
|
|
13957
|
-
allowedHeaders.forEach(header => {
|
|
13958
|
-
if (headers.get(header)) {
|
|
13959
|
-
allHeaders[header] = headers.get(header) ;
|
|
13960
|
-
}
|
|
13961
|
-
});
|
|
13962
|
-
|
|
13963
|
-
return allHeaders;
|
|
13964
|
-
}
|
|
13965
|
-
|
|
13966
|
-
function getRequestHeaders(fetchArgs, allowedHeaders) {
|
|
13967
|
-
if (fetchArgs.length === 1 && typeof fetchArgs[0] !== 'string') {
|
|
13968
|
-
return getHeadersFromOptions(fetchArgs[0] , allowedHeaders);
|
|
13969
|
-
}
|
|
13970
|
-
|
|
13971
|
-
if (fetchArgs.length === 2) {
|
|
13972
|
-
return getHeadersFromOptions(fetchArgs[1] , allowedHeaders);
|
|
13973
|
-
}
|
|
13974
|
-
|
|
13975
|
-
return {};
|
|
13976
|
-
}
|
|
13977
|
-
|
|
13978
|
-
function getHeadersFromOptions(
|
|
13979
|
-
input,
|
|
13980
|
-
allowedHeaders,
|
|
13981
|
-
) {
|
|
13982
|
-
if (!input) {
|
|
13983
|
-
return {};
|
|
13984
|
-
}
|
|
13985
|
-
|
|
13986
|
-
const headers = input.headers;
|
|
13987
|
-
|
|
13988
|
-
if (!headers) {
|
|
13989
|
-
return {};
|
|
13990
|
-
}
|
|
13991
|
-
|
|
13992
|
-
if (headers instanceof Headers) {
|
|
13993
|
-
return getAllHeaders(headers, allowedHeaders);
|
|
13994
|
-
}
|
|
13995
|
-
|
|
13996
|
-
// We do not support this, as it is not really documented (anymore?)
|
|
13997
|
-
if (Array.isArray(headers)) {
|
|
13998
|
-
return {};
|
|
13999
|
-
}
|
|
14000
|
-
|
|
14001
|
-
return getAllowedHeaders(headers, allowedHeaders);
|
|
14002
|
-
}
|
|
14003
|
-
|
|
14004
12882
|
/**
|
|
14005
12883
|
* Capture an XHR breadcrumb to a replay.
|
|
14006
12884
|
* This adds additional data (where approriate).
|
|
@@ -14051,12 +12929,12 @@ function _prepareXhrData(
|
|
|
14051
12929
|
hint,
|
|
14052
12930
|
options,
|
|
14053
12931
|
) {
|
|
14054
|
-
const { startTimestamp, endTimestamp, input
|
|
12932
|
+
const { startTimestamp, endTimestamp, input } = hint;
|
|
14055
12933
|
|
|
14056
12934
|
const {
|
|
14057
12935
|
url,
|
|
14058
12936
|
method,
|
|
14059
|
-
status_code: statusCode
|
|
12937
|
+
status_code: statusCode,
|
|
14060
12938
|
request_body_size: requestBodySize,
|
|
14061
12939
|
response_body_size: responseBodySize,
|
|
14062
12940
|
} = breadcrumb.data;
|
|
@@ -14065,35 +12943,13 @@ function _prepareXhrData(
|
|
|
14065
12943
|
return null;
|
|
14066
12944
|
}
|
|
14067
12945
|
|
|
14068
|
-
if (!urlMatches(url, options.networkDetailAllowUrls)) {
|
|
14069
|
-
const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
14070
|
-
const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
14071
|
-
return {
|
|
14072
|
-
startTimestamp,
|
|
14073
|
-
endTimestamp,
|
|
14074
|
-
url,
|
|
14075
|
-
method,
|
|
14076
|
-
statusCode,
|
|
14077
|
-
request,
|
|
14078
|
-
response,
|
|
14079
|
-
};
|
|
14080
|
-
}
|
|
14081
|
-
|
|
14082
|
-
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
14083
|
-
const networkRequestHeaders = xhrInfo
|
|
14084
|
-
? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
|
|
14085
|
-
: {};
|
|
14086
|
-
const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
|
|
14087
|
-
|
|
14088
12946
|
const request = buildNetworkRequestOrResponse(
|
|
14089
|
-
networkRequestHeaders,
|
|
14090
12947
|
requestBodySize,
|
|
14091
|
-
options.
|
|
12948
|
+
options.captureBodies ? getNetworkBody(getBodyString(input)) : undefined,
|
|
14092
12949
|
);
|
|
14093
12950
|
const response = buildNetworkRequestOrResponse(
|
|
14094
|
-
networkResponseHeaders,
|
|
14095
12951
|
responseBodySize,
|
|
14096
|
-
options.
|
|
12952
|
+
options.captureBodies ? getNetworkBody(hint.xhr.responseText) : undefined,
|
|
14097
12953
|
);
|
|
14098
12954
|
|
|
14099
12955
|
return {
|
|
@@ -14101,26 +12957,12 @@ function _prepareXhrData(
|
|
|
14101
12957
|
endTimestamp,
|
|
14102
12958
|
url,
|
|
14103
12959
|
method,
|
|
14104
|
-
statusCode,
|
|
12960
|
+
statusCode: statusCode || 0,
|
|
14105
12961
|
request,
|
|
14106
12962
|
response,
|
|
14107
12963
|
};
|
|
14108
12964
|
}
|
|
14109
12965
|
|
|
14110
|
-
function getResponseHeaders(xhr) {
|
|
14111
|
-
const headers = xhr.getAllResponseHeaders();
|
|
14112
|
-
|
|
14113
|
-
if (!headers) {
|
|
14114
|
-
return {};
|
|
14115
|
-
}
|
|
14116
|
-
|
|
14117
|
-
return headers.split('\r\n').reduce((acc, line) => {
|
|
14118
|
-
const [key, value] = line.split(': ');
|
|
14119
|
-
acc[key.toLowerCase()] = value;
|
|
14120
|
-
return acc;
|
|
14121
|
-
}, {});
|
|
14122
|
-
}
|
|
14123
|
-
|
|
14124
12966
|
/**
|
|
14125
12967
|
* This method does two things:
|
|
14126
12968
|
* - It enriches the regular XHR/fetch breadcrumbs with request/response size data
|
|
@@ -14133,16 +12975,10 @@ function handleNetworkBreadcrumbs(replay) {
|
|
|
14133
12975
|
try {
|
|
14134
12976
|
const textEncoder = new TextEncoder();
|
|
14135
12977
|
|
|
14136
|
-
const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
|
|
14137
|
-
replay.getOptions();
|
|
14138
|
-
|
|
14139
12978
|
const options = {
|
|
14140
12979
|
replay,
|
|
14141
12980
|
textEncoder,
|
|
14142
|
-
|
|
14143
|
-
networkCaptureBodies,
|
|
14144
|
-
networkRequestHeaders,
|
|
14145
|
-
networkResponseHeaders,
|
|
12981
|
+
captureBodies: replay.getOptions()._experiments.captureNetworkBodies || false,
|
|
14146
12982
|
};
|
|
14147
12983
|
|
|
14148
12984
|
if (client && client.on) {
|
|
@@ -14250,66 +13086,9 @@ function handleScope(scope) {
|
|
|
14250
13086
|
return null;
|
|
14251
13087
|
}
|
|
14252
13088
|
|
|
14253
|
-
if (newBreadcrumb.category === 'console') {
|
|
14254
|
-
return normalizeConsoleBreadcrumb(newBreadcrumb);
|
|
14255
|
-
}
|
|
14256
|
-
|
|
14257
13089
|
return createBreadcrumb(newBreadcrumb);
|
|
14258
13090
|
}
|
|
14259
13091
|
|
|
14260
|
-
/** exported for tests only */
|
|
14261
|
-
function normalizeConsoleBreadcrumb(breadcrumb) {
|
|
14262
|
-
const args = breadcrumb.data && breadcrumb.data.arguments;
|
|
14263
|
-
|
|
14264
|
-
if (!Array.isArray(args) || args.length === 0) {
|
|
14265
|
-
return createBreadcrumb(breadcrumb);
|
|
14266
|
-
}
|
|
14267
|
-
|
|
14268
|
-
let isTruncated = false;
|
|
14269
|
-
|
|
14270
|
-
// Avoid giant args captures
|
|
14271
|
-
const normalizedArgs = args.map(arg => {
|
|
14272
|
-
if (!arg) {
|
|
14273
|
-
return arg;
|
|
14274
|
-
}
|
|
14275
|
-
if (typeof arg === 'string') {
|
|
14276
|
-
if (arg.length > CONSOLE_ARG_MAX_SIZE) {
|
|
14277
|
-
isTruncated = true;
|
|
14278
|
-
return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
|
|
14279
|
-
}
|
|
14280
|
-
|
|
14281
|
-
return arg;
|
|
14282
|
-
}
|
|
14283
|
-
if (typeof arg === 'object') {
|
|
14284
|
-
try {
|
|
14285
|
-
const normalizedArg = normalize(arg, 7);
|
|
14286
|
-
const stringified = JSON.stringify(normalizedArg);
|
|
14287
|
-
if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
|
|
14288
|
-
const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
|
|
14289
|
-
const json = JSON.parse(fixedJson);
|
|
14290
|
-
// We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
|
|
14291
|
-
isTruncated = true;
|
|
14292
|
-
return json;
|
|
14293
|
-
}
|
|
14294
|
-
return normalizedArg;
|
|
14295
|
-
} catch (e) {
|
|
14296
|
-
// fall back to default
|
|
14297
|
-
}
|
|
14298
|
-
}
|
|
14299
|
-
|
|
14300
|
-
return arg;
|
|
14301
|
-
});
|
|
14302
|
-
|
|
14303
|
-
return createBreadcrumb({
|
|
14304
|
-
...breadcrumb,
|
|
14305
|
-
data: {
|
|
14306
|
-
...breadcrumb.data,
|
|
14307
|
-
arguments: normalizedArgs,
|
|
14308
|
-
...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
|
|
14309
|
-
},
|
|
14310
|
-
});
|
|
14311
|
-
}
|
|
14312
|
-
|
|
14313
13092
|
/**
|
|
14314
13093
|
* Add global listeners that cannot be removed.
|
|
14315
13094
|
*/
|
|
@@ -14334,8 +13113,7 @@ function addGlobalListeners(replay) {
|
|
|
14334
13113
|
client.on('afterSendEvent', handleAfterSendEvent(replay));
|
|
14335
13114
|
client.on('createDsc', (dsc) => {
|
|
14336
13115
|
const replayId = replay.getSessionId();
|
|
14337
|
-
|
|
14338
|
-
if (replayId && replay.isEnabled() && replay.recordingMode === 'session') {
|
|
13116
|
+
if (replayId) {
|
|
14339
13117
|
dsc.replay_id = replayId;
|
|
14340
13118
|
}
|
|
14341
13119
|
});
|
|
@@ -14615,23 +13393,6 @@ function debounce(func, wait, options) {
|
|
|
14615
13393
|
return debounced;
|
|
14616
13394
|
}
|
|
14617
13395
|
|
|
14618
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
14619
|
-
|
|
14620
|
-
var EventType; (function (EventType) {
|
|
14621
|
-
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
14622
|
-
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
14623
|
-
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
14624
|
-
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
14625
|
-
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
14626
|
-
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
14627
|
-
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
14628
|
-
})(EventType || (EventType = {}));
|
|
14629
|
-
|
|
14630
|
-
/**
|
|
14631
|
-
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
14632
|
-
* we specifcally need in the SDK.
|
|
14633
|
-
*/
|
|
14634
|
-
|
|
14635
13396
|
/**
|
|
14636
13397
|
* Handler for recording events.
|
|
14637
13398
|
*
|
|
@@ -14660,7 +13421,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14660
13421
|
// when an error occurs. Clear any state that happens before this current
|
|
14661
13422
|
// checkout. This needs to happen before `addEvent()` which updates state
|
|
14662
13423
|
// dependent on this reset.
|
|
14663
|
-
if (replay.recordingMode === '
|
|
13424
|
+
if (replay.recordingMode === 'error' && isCheckout) {
|
|
14664
13425
|
replay.setInitialState();
|
|
14665
13426
|
}
|
|
14666
13427
|
|
|
@@ -14674,14 +13435,6 @@ function getHandleRecordingEmit(replay) {
|
|
|
14674
13435
|
return false;
|
|
14675
13436
|
}
|
|
14676
13437
|
|
|
14677
|
-
// Additionally, create a meta event that will capture certain SDK settings.
|
|
14678
|
-
// In order to handle buffer mode, this needs to either be done when we
|
|
14679
|
-
// receive checkout events or at flush time.
|
|
14680
|
-
//
|
|
14681
|
-
// `isCheckout` is always true, but want to be explicit that it should
|
|
14682
|
-
// only be added for checkouts
|
|
14683
|
-
void addSettingsEvent(replay, isCheckout);
|
|
14684
|
-
|
|
14685
13438
|
// If there is a previousSessionId after a full snapshot occurs, then
|
|
14686
13439
|
// the replay session was started due to session expiration. The new session
|
|
14687
13440
|
// is started before triggering a new checkout and contains the id
|
|
@@ -14692,10 +13445,10 @@ function getHandleRecordingEmit(replay) {
|
|
|
14692
13445
|
return true;
|
|
14693
13446
|
}
|
|
14694
13447
|
|
|
14695
|
-
//
|
|
14696
|
-
//
|
|
14697
|
-
if (replay.recordingMode === '
|
|
14698
|
-
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();
|
|
14699
13452
|
if (earliestEvent) {
|
|
14700
13453
|
replay.session.started = earliestEvent;
|
|
14701
13454
|
|
|
@@ -14719,46 +13472,6 @@ function getHandleRecordingEmit(replay) {
|
|
|
14719
13472
|
};
|
|
14720
13473
|
}
|
|
14721
13474
|
|
|
14722
|
-
/**
|
|
14723
|
-
* Exported for tests
|
|
14724
|
-
*/
|
|
14725
|
-
function createOptionsEvent(replay) {
|
|
14726
|
-
const options = replay.getOptions();
|
|
14727
|
-
return {
|
|
14728
|
-
type: EventType.Custom,
|
|
14729
|
-
timestamp: Date.now(),
|
|
14730
|
-
data: {
|
|
14731
|
-
tag: 'options',
|
|
14732
|
-
payload: {
|
|
14733
|
-
sessionSampleRate: options.sessionSampleRate,
|
|
14734
|
-
errorSampleRate: options.errorSampleRate,
|
|
14735
|
-
useCompressionOption: options.useCompression,
|
|
14736
|
-
blockAllMedia: options.blockAllMedia,
|
|
14737
|
-
maskAllText: options.maskAllText,
|
|
14738
|
-
maskAllInputs: options.maskAllInputs,
|
|
14739
|
-
useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false,
|
|
14740
|
-
networkDetailHasUrls: options.networkDetailAllowUrls.length > 0,
|
|
14741
|
-
networkCaptureBodies: options.networkCaptureBodies,
|
|
14742
|
-
networkRequestHasHeaders: options.networkRequestHeaders.length > 0,
|
|
14743
|
-
networkResponseHasHeaders: options.networkResponseHeaders.length > 0,
|
|
14744
|
-
},
|
|
14745
|
-
},
|
|
14746
|
-
};
|
|
14747
|
-
}
|
|
14748
|
-
|
|
14749
|
-
/**
|
|
14750
|
-
* Add a "meta" event that contains a simplified view on current configuration
|
|
14751
|
-
* options. This should only be included on the first segment of a recording.
|
|
14752
|
-
*/
|
|
14753
|
-
function addSettingsEvent(replay, isCheckout) {
|
|
14754
|
-
// Only need to add this event when sending the first segment
|
|
14755
|
-
if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
|
|
14756
|
-
return Promise.resolve(null);
|
|
14757
|
-
}
|
|
14758
|
-
|
|
14759
|
-
return addEvent(replay, createOptionsEvent(replay), false);
|
|
14760
|
-
}
|
|
14761
|
-
|
|
14762
13475
|
/**
|
|
14763
13476
|
* Create a replay envelope ready to be sent.
|
|
14764
13477
|
* This includes both the replay event, as well as the recording data.
|
|
@@ -14870,9 +13583,11 @@ async function sendReplayRequest({
|
|
|
14870
13583
|
recordingData,
|
|
14871
13584
|
replayId,
|
|
14872
13585
|
segmentId: segment_id,
|
|
13586
|
+
includeReplayStartTimestamp,
|
|
14873
13587
|
eventContext,
|
|
14874
13588
|
timestamp,
|
|
14875
13589
|
session,
|
|
13590
|
+
options,
|
|
14876
13591
|
}) {
|
|
14877
13592
|
const preparedRecordingData = prepareRecordingData({
|
|
14878
13593
|
recordingData,
|
|
@@ -14894,8 +13609,9 @@ async function sendReplayRequest({
|
|
|
14894
13609
|
}
|
|
14895
13610
|
|
|
14896
13611
|
const baseEvent = {
|
|
13612
|
+
// @ts-ignore private api
|
|
14897
13613
|
type: REPLAY_EVENT_NAME,
|
|
14898
|
-
replay_start_timestamp: initialTimestamp / 1000,
|
|
13614
|
+
...(includeReplayStartTimestamp ? { replay_start_timestamp: initialTimestamp / 1000 } : {}),
|
|
14899
13615
|
timestamp: timestamp / 1000,
|
|
14900
13616
|
error_ids: errorIds,
|
|
14901
13617
|
trace_ids: traceIds,
|
|
@@ -14914,6 +13630,15 @@ async function sendReplayRequest({
|
|
|
14914
13630
|
return;
|
|
14915
13631
|
}
|
|
14916
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
|
+
|
|
14917
13642
|
/*
|
|
14918
13643
|
For reference, the fully built event looks something like this:
|
|
14919
13644
|
{
|
|
@@ -14944,6 +13669,10 @@ async function sendReplayRequest({
|
|
|
14944
13669
|
},
|
|
14945
13670
|
"sdkProcessingMetadata": {},
|
|
14946
13671
|
"contexts": {
|
|
13672
|
+
"replay": {
|
|
13673
|
+
"session_sample_rate": 1,
|
|
13674
|
+
"error_sample_rate": 0,
|
|
13675
|
+
},
|
|
14947
13676
|
},
|
|
14948
13677
|
}
|
|
14949
13678
|
*/
|
|
@@ -15069,11 +13798,9 @@ class ReplayContainer {
|
|
|
15069
13798
|
__init2() {this.performanceEvents = [];}
|
|
15070
13799
|
|
|
15071
13800
|
/**
|
|
15072
|
-
* Recording can happen in one of
|
|
15073
|
-
*
|
|
15074
|
-
*
|
|
15075
|
-
* - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
|
|
15076
|
-
* - 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
|
|
15077
13804
|
*/
|
|
15078
13805
|
__init3() {this.recordingMode = 'session';}
|
|
15079
13806
|
|
|
@@ -15082,8 +13809,7 @@ class ReplayContainer {
|
|
|
15082
13809
|
* @hidden
|
|
15083
13810
|
*/
|
|
15084
13811
|
__init4() {this.timeouts = {
|
|
15085
|
-
|
|
15086
|
-
sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
|
|
13812
|
+
sessionIdle: SESSION_IDLE_DURATION,
|
|
15087
13813
|
maxSessionLife: MAX_SESSION_LIFE,
|
|
15088
13814
|
}; }
|
|
15089
13815
|
|
|
@@ -15127,6 +13853,7 @@ class ReplayContainer {
|
|
|
15127
13853
|
errorIds: new Set(),
|
|
15128
13854
|
traceIds: new Set(),
|
|
15129
13855
|
urls: [],
|
|
13856
|
+
earliestEvent: null,
|
|
15130
13857
|
initialTimestamp: Date.now(),
|
|
15131
13858
|
initialUrl: '',
|
|
15132
13859
|
};}
|
|
@@ -15136,7 +13863,7 @@ class ReplayContainer {
|
|
|
15136
13863
|
recordingOptions,
|
|
15137
13864
|
}
|
|
15138
13865
|
|
|
15139
|
-
) {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);
|
|
15140
13867
|
this._recordingOptions = recordingOptions;
|
|
15141
13868
|
this._options = options;
|
|
15142
13869
|
|
|
@@ -15166,102 +13893,49 @@ class ReplayContainer {
|
|
|
15166
13893
|
}
|
|
15167
13894
|
|
|
15168
13895
|
/**
|
|
15169
|
-
* Initializes the plugin
|
|
15170
|
-
*
|
|
13896
|
+
* Initializes the plugin.
|
|
13897
|
+
*
|
|
13898
|
+
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
13899
|
+
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
15171
13900
|
*/
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
// If neither sample rate is > 0, then do nothing - user will need to call one of
|
|
15176
|
-
// `start()` or `startBuffering` themselves.
|
|
15177
|
-
if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
|
|
15178
|
-
return;
|
|
15179
|
-
}
|
|
15180
|
-
|
|
15181
|
-
// Otherwise if there is _any_ sample rate set, try to load an existing
|
|
15182
|
-
// session, or create a new one.
|
|
15183
|
-
const isSessionSampled = this._loadAndCheckSession();
|
|
13901
|
+
start() {
|
|
13902
|
+
this.setInitialState();
|
|
15184
13903
|
|
|
15185
|
-
if (!
|
|
15186
|
-
// This should only occur if `errorSampleRate` is 0 and was unsampled for
|
|
15187
|
-
// session-based replay. In this case there is nothing to do.
|
|
13904
|
+
if (!this._loadAndCheckSession()) {
|
|
15188
13905
|
return;
|
|
15189
13906
|
}
|
|
15190
13907
|
|
|
13908
|
+
// If there is no session, then something bad has happened - can't continue
|
|
15191
13909
|
if (!this.session) {
|
|
15192
|
-
|
|
15193
|
-
this._handleException(new Error('Unable to initialize and create session'));
|
|
13910
|
+
this._handleException(new Error('No session found'));
|
|
15194
13911
|
return;
|
|
15195
13912
|
}
|
|
15196
13913
|
|
|
15197
|
-
if (this.session.sampled
|
|
15198
|
-
// If not sampled
|
|
15199
|
-
|
|
15200
|
-
// could have sessions from Session storage that are still `error` from
|
|
15201
|
-
// prior SDK version.
|
|
15202
|
-
this.recordingMode = 'buffer';
|
|
15203
|
-
}
|
|
15204
|
-
|
|
15205
|
-
this._initializeRecording();
|
|
15206
|
-
}
|
|
15207
|
-
|
|
15208
|
-
/**
|
|
15209
|
-
* Start a replay regardless of sampling rate. Calling this will always
|
|
15210
|
-
* create a new session. Will throw an error if replay is already in progress.
|
|
15211
|
-
*
|
|
15212
|
-
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
15213
|
-
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
15214
|
-
*/
|
|
15215
|
-
start() {
|
|
15216
|
-
if (this._isEnabled && this.recordingMode === 'session') {
|
|
15217
|
-
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;
|
|
15218
13917
|
}
|
|
15219
13918
|
|
|
15220
|
-
|
|
15221
|
-
|
|
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';
|
|
15222
13923
|
}
|
|
15223
13924
|
|
|
15224
|
-
|
|
13925
|
+
// setup() is generally called on page load or manually - in both cases we
|
|
13926
|
+
// should treat it as an activity
|
|
13927
|
+
this._updateSessionActivity();
|
|
15225
13928
|
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
stickySession: Boolean(this._options.stickySession),
|
|
15229
|
-
currentSession: this.session,
|
|
15230
|
-
// This is intentional: create a new session-based replay when calling `start()`
|
|
15231
|
-
sessionSampleRate: 1,
|
|
15232
|
-
allowBuffering: false,
|
|
13929
|
+
this.eventBuffer = createEventBuffer({
|
|
13930
|
+
useCompression: this._options.useCompression,
|
|
15233
13931
|
});
|
|
15234
13932
|
|
|
15235
|
-
|
|
15236
|
-
this.session = session;
|
|
15237
|
-
|
|
15238
|
-
this._initializeRecording();
|
|
15239
|
-
}
|
|
15240
|
-
|
|
15241
|
-
/**
|
|
15242
|
-
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
15243
|
-
* `replaysOnErrorSampleRate` > 0, an error occurs.
|
|
15244
|
-
*/
|
|
15245
|
-
startBuffering() {
|
|
15246
|
-
if (this._isEnabled) {
|
|
15247
|
-
throw new Error('Replay recording is already in progress');
|
|
15248
|
-
}
|
|
15249
|
-
|
|
15250
|
-
const previousSessionId = this.session && this.session.id;
|
|
15251
|
-
|
|
15252
|
-
const { session } = getSession({
|
|
15253
|
-
timeouts: this.timeouts,
|
|
15254
|
-
stickySession: Boolean(this._options.stickySession),
|
|
15255
|
-
currentSession: this.session,
|
|
15256
|
-
sessionSampleRate: 0,
|
|
15257
|
-
allowBuffering: true,
|
|
15258
|
-
});
|
|
13933
|
+
this._addListeners();
|
|
15259
13934
|
|
|
15260
|
-
|
|
15261
|
-
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;
|
|
15262
13937
|
|
|
15263
|
-
this.
|
|
15264
|
-
this._initializeRecording();
|
|
13938
|
+
this.startRecording();
|
|
15265
13939
|
}
|
|
15266
13940
|
|
|
15267
13941
|
/**
|
|
@@ -15276,7 +13950,7 @@ class ReplayContainer {
|
|
|
15276
13950
|
// When running in error sampling mode, we need to overwrite `checkoutEveryNms`
|
|
15277
13951
|
// Without this, it would record forever, until an error happens, which we don't want
|
|
15278
13952
|
// instead, we'll always keep the last 60 seconds of replay before an error happened
|
|
15279
|
-
...(this.recordingMode === '
|
|
13953
|
+
...(this.recordingMode === 'error' && { checkoutEveryNms: ERROR_CHECKOUT_TIME }),
|
|
15280
13954
|
emit: getHandleRecordingEmit(this),
|
|
15281
13955
|
onMutation: this._onMutationHandler,
|
|
15282
13956
|
});
|
|
@@ -15287,18 +13961,17 @@ class ReplayContainer {
|
|
|
15287
13961
|
|
|
15288
13962
|
/**
|
|
15289
13963
|
* Stops the recording, if it was running.
|
|
15290
|
-
*
|
|
15291
|
-
* Returns true if it was previously stopped, or is now stopped,
|
|
15292
|
-
* otherwise false.
|
|
13964
|
+
* Returns true if it was stopped, else false.
|
|
15293
13965
|
*/
|
|
15294
13966
|
stopRecording() {
|
|
15295
13967
|
try {
|
|
15296
13968
|
if (this._stopRecording) {
|
|
15297
13969
|
this._stopRecording();
|
|
15298
13970
|
this._stopRecording = undefined;
|
|
13971
|
+
return true;
|
|
15299
13972
|
}
|
|
15300
13973
|
|
|
15301
|
-
return
|
|
13974
|
+
return false;
|
|
15302
13975
|
} catch (err) {
|
|
15303
13976
|
this._handleException(err);
|
|
15304
13977
|
return false;
|
|
@@ -15309,7 +13982,7 @@ class ReplayContainer {
|
|
|
15309
13982
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
15310
13983
|
* does not support a teardown
|
|
15311
13984
|
*/
|
|
15312
|
-
|
|
13985
|
+
stop(reason) {
|
|
15313
13986
|
if (!this._isEnabled) {
|
|
15314
13987
|
return;
|
|
15315
13988
|
}
|
|
@@ -15325,24 +13998,12 @@ class ReplayContainer {
|
|
|
15325
13998
|
log(msg);
|
|
15326
13999
|
}
|
|
15327
14000
|
|
|
15328
|
-
// We can't move `_isEnabled` after awaiting a flush, otherwise we can
|
|
15329
|
-
// enter into an infinite loop when `stop()` is called while flushing.
|
|
15330
14001
|
this._isEnabled = false;
|
|
15331
14002
|
this._removeListeners();
|
|
15332
14003
|
this.stopRecording();
|
|
15333
|
-
|
|
15334
|
-
this._debouncedFlush.cancel();
|
|
15335
|
-
// See comment above re: `_isEnabled`, we "force" a flush, ignoring the
|
|
15336
|
-
// `_isEnabled` state of the plugin since it was disabled above.
|
|
15337
|
-
await this._flush({ force: true });
|
|
15338
|
-
|
|
15339
|
-
// After flush, destroy event buffer
|
|
15340
14004
|
this.eventBuffer && this.eventBuffer.destroy();
|
|
15341
14005
|
this.eventBuffer = null;
|
|
15342
|
-
|
|
15343
|
-
// Clear session from session storage, note this means if a new session
|
|
15344
|
-
// is started after, it will not have `previousSessionId`
|
|
15345
|
-
clearSession(this);
|
|
14006
|
+
this._debouncedFlush.cancel();
|
|
15346
14007
|
} catch (err) {
|
|
15347
14008
|
this._handleException(err);
|
|
15348
14009
|
}
|
|
@@ -15373,45 +14034,6 @@ class ReplayContainer {
|
|
|
15373
14034
|
this.startRecording();
|
|
15374
14035
|
}
|
|
15375
14036
|
|
|
15376
|
-
/**
|
|
15377
|
-
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
15378
|
-
* Unless `continueRecording` is false, the replay will continue to record and
|
|
15379
|
-
* behave as a "session"-based replay.
|
|
15380
|
-
*
|
|
15381
|
-
* Otherwise, queue up a flush.
|
|
15382
|
-
*/
|
|
15383
|
-
async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
|
|
15384
|
-
if (this.recordingMode === 'session') {
|
|
15385
|
-
return this.flushImmediate();
|
|
15386
|
-
}
|
|
15387
|
-
|
|
15388
|
-
// Allow flush to complete before resuming as a session recording, otherwise
|
|
15389
|
-
// the checkout from `startRecording` may be included in the payload.
|
|
15390
|
-
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
15391
|
-
// than the session replay.
|
|
15392
|
-
await this.flushImmediate();
|
|
15393
|
-
|
|
15394
|
-
const hasStoppedRecording = this.stopRecording();
|
|
15395
|
-
|
|
15396
|
-
if (!continueRecording || !hasStoppedRecording) {
|
|
15397
|
-
return;
|
|
15398
|
-
}
|
|
15399
|
-
|
|
15400
|
-
// Re-start recording, but in "session" recording mode
|
|
15401
|
-
|
|
15402
|
-
// Reset all "capture on error" configuration before
|
|
15403
|
-
// starting a new recording
|
|
15404
|
-
this.recordingMode = 'session';
|
|
15405
|
-
|
|
15406
|
-
// Once this session ends, we do not want to refresh it
|
|
15407
|
-
if (this.session) {
|
|
15408
|
-
this.session.shouldRefresh = false;
|
|
15409
|
-
this._maybeSaveSession();
|
|
15410
|
-
}
|
|
15411
|
-
|
|
15412
|
-
this.startRecording();
|
|
15413
|
-
}
|
|
15414
|
-
|
|
15415
14037
|
/**
|
|
15416
14038
|
* We want to batch uploads of replay events. Save events only if
|
|
15417
14039
|
* `<flushMinDelay>` milliseconds have elapsed since the last event
|
|
@@ -15421,12 +14043,12 @@ class ReplayContainer {
|
|
|
15421
14043
|
* processing and hand back control to caller.
|
|
15422
14044
|
*/
|
|
15423
14045
|
addUpdate(cb) {
|
|
15424
|
-
// 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'`)
|
|
15425
14047
|
const cbResult = cb();
|
|
15426
14048
|
|
|
15427
14049
|
// If this option is turned on then we will only want to call `flush`
|
|
15428
14050
|
// explicitly
|
|
15429
|
-
if (this.recordingMode === '
|
|
14051
|
+
if (this.recordingMode === 'error') {
|
|
15430
14052
|
return;
|
|
15431
14053
|
}
|
|
15432
14054
|
|
|
@@ -15498,12 +14120,12 @@ class ReplayContainer {
|
|
|
15498
14120
|
const oldSessionId = this.getSessionId();
|
|
15499
14121
|
|
|
15500
14122
|
// Prevent starting a new session if the last user activity is older than
|
|
15501
|
-
//
|
|
14123
|
+
// SESSION_IDLE_DURATION. Otherwise non-user activity can trigger a new
|
|
15502
14124
|
// session+recording. This creates noisy replays that do not have much
|
|
15503
14125
|
// content in them.
|
|
15504
14126
|
if (
|
|
15505
14127
|
this._lastActivity &&
|
|
15506
|
-
isExpired(this._lastActivity, this.timeouts.
|
|
14128
|
+
isExpired(this._lastActivity, this.timeouts.sessionIdle) &&
|
|
15507
14129
|
this.session &&
|
|
15508
14130
|
this.session.sampled === 'session'
|
|
15509
14131
|
) {
|
|
@@ -15553,30 +14175,6 @@ class ReplayContainer {
|
|
|
15553
14175
|
this._context.urls.push(url);
|
|
15554
14176
|
}
|
|
15555
14177
|
|
|
15556
|
-
/**
|
|
15557
|
-
* Initialize and start all listeners to varying events (DOM,
|
|
15558
|
-
* Performance Observer, Recording, Sentry SDK, etc)
|
|
15559
|
-
*/
|
|
15560
|
-
_initializeRecording() {
|
|
15561
|
-
this.setInitialState();
|
|
15562
|
-
|
|
15563
|
-
// this method is generally called on page load or manually - in both cases
|
|
15564
|
-
// we should treat it as an activity
|
|
15565
|
-
this._updateSessionActivity();
|
|
15566
|
-
|
|
15567
|
-
this.eventBuffer = createEventBuffer({
|
|
15568
|
-
useCompression: this._options.useCompression,
|
|
15569
|
-
});
|
|
15570
|
-
|
|
15571
|
-
this._removeListeners();
|
|
15572
|
-
this._addListeners();
|
|
15573
|
-
|
|
15574
|
-
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
15575
|
-
this._isEnabled = true;
|
|
15576
|
-
|
|
15577
|
-
this.startRecording();
|
|
15578
|
-
}
|
|
15579
|
-
|
|
15580
14178
|
/** A wrapper to conditionally capture exceptions. */
|
|
15581
14179
|
_handleException(error) {
|
|
15582
14180
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
|
|
@@ -15596,7 +14194,7 @@ class ReplayContainer {
|
|
|
15596
14194
|
stickySession: Boolean(this._options.stickySession),
|
|
15597
14195
|
currentSession: this.session,
|
|
15598
14196
|
sessionSampleRate: this._options.sessionSampleRate,
|
|
15599
|
-
|
|
14197
|
+
errorSampleRate: this._options.errorSampleRate,
|
|
15600
14198
|
});
|
|
15601
14199
|
|
|
15602
14200
|
// If session was newly created (i.e. was not loaded from storage), then
|
|
@@ -15613,7 +14211,7 @@ class ReplayContainer {
|
|
|
15613
14211
|
this.session = session;
|
|
15614
14212
|
|
|
15615
14213
|
if (!this.session.sampled) {
|
|
15616
|
-
|
|
14214
|
+
this.stop('session unsampled');
|
|
15617
14215
|
return false;
|
|
15618
14216
|
}
|
|
15619
14217
|
|
|
@@ -15628,7 +14226,6 @@ class ReplayContainer {
|
|
|
15628
14226
|
WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange);
|
|
15629
14227
|
WINDOW.addEventListener('blur', this._handleWindowBlur);
|
|
15630
14228
|
WINDOW.addEventListener('focus', this._handleWindowFocus);
|
|
15631
|
-
WINDOW.addEventListener('keydown', this._handleKeyboardEvent);
|
|
15632
14229
|
|
|
15633
14230
|
// There is no way to remove these listeners, so ensure they are only added once
|
|
15634
14231
|
if (!this._hasInitializedCoreListeners) {
|
|
@@ -15657,7 +14254,6 @@ class ReplayContainer {
|
|
|
15657
14254
|
|
|
15658
14255
|
WINDOW.removeEventListener('blur', this._handleWindowBlur);
|
|
15659
14256
|
WINDOW.removeEventListener('focus', this._handleWindowFocus);
|
|
15660
|
-
WINDOW.removeEventListener('keydown', this._handleKeyboardEvent);
|
|
15661
14257
|
|
|
15662
14258
|
if (this._performanceObserver) {
|
|
15663
14259
|
this._performanceObserver.disconnect();
|
|
@@ -15708,11 +14304,6 @@ class ReplayContainer {
|
|
|
15708
14304
|
this._doChangeToForegroundTasks(breadcrumb);
|
|
15709
14305
|
};}
|
|
15710
14306
|
|
|
15711
|
-
/** Ensure page remains active when a key is pressed. */
|
|
15712
|
-
__init16() {this._handleKeyboardEvent = (event) => {
|
|
15713
|
-
handleKeyboardEvent(this, event);
|
|
15714
|
-
};}
|
|
15715
|
-
|
|
15716
14307
|
/**
|
|
15717
14308
|
* Tasks to run when we consider a page to be hidden (via blurring and/or visibility)
|
|
15718
14309
|
*/
|
|
@@ -15744,7 +14335,7 @@ class ReplayContainer {
|
|
|
15744
14335
|
const isSessionActive = this.checkAndHandleExpiredSession();
|
|
15745
14336
|
|
|
15746
14337
|
if (!isSessionActive) {
|
|
15747
|
-
// If the user has come back to the page within
|
|
14338
|
+
// If the user has come back to the page within SESSION_IDLE_DURATION
|
|
15748
14339
|
// ms, we will re-use the existing session, otherwise create a new
|
|
15749
14340
|
// session
|
|
15750
14341
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
|
|
@@ -15792,7 +14383,7 @@ class ReplayContainer {
|
|
|
15792
14383
|
_createCustomBreadcrumb(breadcrumb) {
|
|
15793
14384
|
this.addUpdate(() => {
|
|
15794
14385
|
void addEvent(this, {
|
|
15795
|
-
type: EventType
|
|
14386
|
+
type: EventType.Custom,
|
|
15796
14387
|
timestamp: breadcrumb.timestamp || 0,
|
|
15797
14388
|
data: {
|
|
15798
14389
|
tag: 'breadcrumb',
|
|
@@ -15818,7 +14409,7 @@ class ReplayContainer {
|
|
|
15818
14409
|
* Only flush if `this.recordingMode === 'session'`
|
|
15819
14410
|
*/
|
|
15820
14411
|
_conditionalFlush() {
|
|
15821
|
-
if (this.recordingMode === '
|
|
14412
|
+
if (this.recordingMode === 'error') {
|
|
15822
14413
|
return;
|
|
15823
14414
|
}
|
|
15824
14415
|
|
|
@@ -15833,35 +14424,22 @@ class ReplayContainer {
|
|
|
15833
14424
|
this._context.errorIds.clear();
|
|
15834
14425
|
this._context.traceIds.clear();
|
|
15835
14426
|
this._context.urls = [];
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
/** Update the initial timestamp based on the buffer content. */
|
|
15839
|
-
_updateInitialTimestampFromEventBuffer() {
|
|
15840
|
-
const { session, eventBuffer } = this;
|
|
15841
|
-
if (!session || !eventBuffer) {
|
|
15842
|
-
return;
|
|
15843
|
-
}
|
|
15844
|
-
|
|
15845
|
-
// we only ever update this on the initial segment
|
|
15846
|
-
if (session.segmentId) {
|
|
15847
|
-
return;
|
|
15848
|
-
}
|
|
15849
|
-
|
|
15850
|
-
const earliestEvent = eventBuffer.getEarliestTimestamp();
|
|
15851
|
-
if (earliestEvent && earliestEvent < this._context.initialTimestamp) {
|
|
15852
|
-
this._context.initialTimestamp = earliestEvent;
|
|
15853
|
-
}
|
|
14427
|
+
this._context.earliestEvent = null;
|
|
15854
14428
|
}
|
|
15855
14429
|
|
|
15856
14430
|
/**
|
|
15857
14431
|
* Return and clear _context
|
|
15858
14432
|
*/
|
|
15859
14433
|
_popEventContext() {
|
|
14434
|
+
if (this._context.earliestEvent && this._context.earliestEvent < this._context.initialTimestamp) {
|
|
14435
|
+
this._context.initialTimestamp = this._context.earliestEvent;
|
|
14436
|
+
}
|
|
14437
|
+
|
|
15860
14438
|
const _context = {
|
|
15861
14439
|
initialTimestamp: this._context.initialTimestamp,
|
|
15862
14440
|
initialUrl: this._context.initialUrl,
|
|
15863
|
-
errorIds: Array.from(this._context.errorIds),
|
|
15864
|
-
traceIds: Array.from(this._context.traceIds),
|
|
14441
|
+
errorIds: Array.from(this._context.errorIds).filter(Boolean),
|
|
14442
|
+
traceIds: Array.from(this._context.traceIds).filter(Boolean),
|
|
15865
14443
|
urls: this._context.urls,
|
|
15866
14444
|
};
|
|
15867
14445
|
|
|
@@ -15900,9 +14478,6 @@ class ReplayContainer {
|
|
|
15900
14478
|
}
|
|
15901
14479
|
|
|
15902
14480
|
try {
|
|
15903
|
-
// This uses the data from the eventBuffer, so we need to call this before `finish()
|
|
15904
|
-
this._updateInitialTimestampFromEventBuffer();
|
|
15905
|
-
|
|
15906
14481
|
// Note this empties the event buffer regardless of outcome of sending replay
|
|
15907
14482
|
const recordingData = await this.eventBuffer.finish();
|
|
15908
14483
|
|
|
@@ -15918,6 +14493,7 @@ class ReplayContainer {
|
|
|
15918
14493
|
replayId,
|
|
15919
14494
|
recordingData,
|
|
15920
14495
|
segmentId,
|
|
14496
|
+
includeReplayStartTimestamp: segmentId === 0,
|
|
15921
14497
|
eventContext,
|
|
15922
14498
|
session: this.session,
|
|
15923
14499
|
options: this.getOptions(),
|
|
@@ -15929,7 +14505,7 @@ class ReplayContainer {
|
|
|
15929
14505
|
// This means we retried 3 times and all of them failed,
|
|
15930
14506
|
// or we ran into a problem we don't want to retry, like rate limiting.
|
|
15931
14507
|
// In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
|
|
15932
|
-
|
|
14508
|
+
this.stop('sendReplay');
|
|
15933
14509
|
|
|
15934
14510
|
const client = getCurrentHub().getClient();
|
|
15935
14511
|
|
|
@@ -15943,12 +14519,8 @@ class ReplayContainer {
|
|
|
15943
14519
|
* Flush recording data to Sentry. Creates a lock so that only a single flush
|
|
15944
14520
|
* can be active at a time. Do not call this directly.
|
|
15945
14521
|
*/
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
}
|
|
15949
|
-
|
|
15950
|
-
= {}) => {
|
|
15951
|
-
if (!this._isEnabled && !force) {
|
|
14522
|
+
__init16() {this._flush = async () => {
|
|
14523
|
+
if (!this._isEnabled) {
|
|
15952
14524
|
// This can happen if e.g. the replay was stopped because of exceeding the retry limit
|
|
15953
14525
|
return;
|
|
15954
14526
|
}
|
|
@@ -15998,7 +14570,7 @@ class ReplayContainer {
|
|
|
15998
14570
|
}
|
|
15999
14571
|
|
|
16000
14572
|
/** Handler for rrweb.record.onMutation */
|
|
16001
|
-
|
|
14573
|
+
__init17() {this._onMutationHandler = (mutations) => {
|
|
16002
14574
|
const count = mutations.length;
|
|
16003
14575
|
|
|
16004
14576
|
const mutationLimit = this._options._experiments.mutationLimit || 0;
|
|
@@ -16132,8 +14704,6 @@ function isElectronNodeRenderer() {
|
|
|
16132
14704
|
const MEDIA_SELECTORS =
|
|
16133
14705
|
'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
|
|
16134
14706
|
|
|
16135
|
-
const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
|
|
16136
|
-
|
|
16137
14707
|
let _initialized = false;
|
|
16138
14708
|
|
|
16139
14709
|
/**
|
|
@@ -16174,11 +14744,6 @@ class Replay {
|
|
|
16174
14744
|
maskAllInputs = true,
|
|
16175
14745
|
blockAllMedia = true,
|
|
16176
14746
|
|
|
16177
|
-
networkDetailAllowUrls = [],
|
|
16178
|
-
networkCaptureBodies = true,
|
|
16179
|
-
networkRequestHeaders = [],
|
|
16180
|
-
networkResponseHeaders = [],
|
|
16181
|
-
|
|
16182
14747
|
mask = [],
|
|
16183
14748
|
unmask = [],
|
|
16184
14749
|
block = [],
|
|
@@ -16237,13 +14802,6 @@ class Replay {
|
|
|
16237
14802
|
errorSampleRate,
|
|
16238
14803
|
useCompression,
|
|
16239
14804
|
blockAllMedia,
|
|
16240
|
-
maskAllInputs,
|
|
16241
|
-
maskAllText,
|
|
16242
|
-
networkDetailAllowUrls,
|
|
16243
|
-
networkCaptureBodies,
|
|
16244
|
-
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|
|
16245
|
-
networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
|
|
16246
|
-
|
|
16247
14805
|
_experiments,
|
|
16248
14806
|
};
|
|
16249
14807
|
|
|
@@ -16297,7 +14855,14 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16297
14855
|
}
|
|
16298
14856
|
|
|
16299
14857
|
/**
|
|
16300
|
-
*
|
|
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.
|
|
16301
14866
|
*/
|
|
16302
14867
|
setupOnce() {
|
|
16303
14868
|
if (!isBrowser()) {
|
|
@@ -16306,20 +14871,12 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16306
14871
|
|
|
16307
14872
|
this._setup();
|
|
16308
14873
|
|
|
16309
|
-
//
|
|
16310
|
-
|
|
16311
|
-
// and applied their own global event processor. An example is:
|
|
16312
|
-
// https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
16313
|
-
//
|
|
16314
|
-
// So we call `this._initialize()` in next event loop as a workaround to wait for other
|
|
16315
|
-
// global event processors to finish. This is no longer needed, but keeping it
|
|
16316
|
-
// here to avoid any future issues.
|
|
16317
|
-
setTimeout(() => this._initialize());
|
|
14874
|
+
// XXX: See method comments above
|
|
14875
|
+
setTimeout(() => this.start());
|
|
16318
14876
|
}
|
|
16319
14877
|
|
|
16320
14878
|
/**
|
|
16321
|
-
*
|
|
16322
|
-
* create a new session. Will throw an error if replay is already in progress.
|
|
14879
|
+
* Initializes the plugin.
|
|
16323
14880
|
*
|
|
16324
14881
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
16325
14882
|
* PerformanceObserver, Recording, Sentry SDK, etc)
|
|
@@ -16332,64 +14889,27 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16332
14889
|
this._replay.start();
|
|
16333
14890
|
}
|
|
16334
14891
|
|
|
16335
|
-
/**
|
|
16336
|
-
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
16337
|
-
* `replaysOnErrorSampleRate` > 0, until an error occurs.
|
|
16338
|
-
*/
|
|
16339
|
-
startBuffering() {
|
|
16340
|
-
if (!this._replay) {
|
|
16341
|
-
return;
|
|
16342
|
-
}
|
|
16343
|
-
|
|
16344
|
-
this._replay.startBuffering();
|
|
16345
|
-
}
|
|
16346
|
-
|
|
16347
14892
|
/**
|
|
16348
14893
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
16349
14894
|
* does not support a teardown
|
|
16350
14895
|
*/
|
|
16351
14896
|
stop() {
|
|
16352
14897
|
if (!this._replay) {
|
|
16353
|
-
return
|
|
16354
|
-
}
|
|
16355
|
-
|
|
16356
|
-
return this._replay.stop();
|
|
16357
|
-
}
|
|
16358
|
-
|
|
16359
|
-
/**
|
|
16360
|
-
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
16361
|
-
* Unless `continueRecording` is false, the replay will continue to record and
|
|
16362
|
-
* behave as a "session"-based replay.
|
|
16363
|
-
*
|
|
16364
|
-
* Otherwise, queue up a flush.
|
|
16365
|
-
*/
|
|
16366
|
-
flush(options) {
|
|
16367
|
-
if (!this._replay || !this._replay.isEnabled()) {
|
|
16368
|
-
return Promise.resolve();
|
|
14898
|
+
return;
|
|
16369
14899
|
}
|
|
16370
14900
|
|
|
16371
|
-
|
|
14901
|
+
this._replay.stop();
|
|
16372
14902
|
}
|
|
16373
14903
|
|
|
16374
14904
|
/**
|
|
16375
|
-
*
|
|
14905
|
+
* Immediately send all pending events.
|
|
16376
14906
|
*/
|
|
16377
|
-
|
|
14907
|
+
flush() {
|
|
16378
14908
|
if (!this._replay || !this._replay.isEnabled()) {
|
|
16379
14909
|
return;
|
|
16380
14910
|
}
|
|
16381
14911
|
|
|
16382
|
-
return this._replay.
|
|
16383
|
-
}
|
|
16384
|
-
/**
|
|
16385
|
-
* Initializes replay.
|
|
16386
|
-
*/
|
|
16387
|
-
_initialize() {
|
|
16388
|
-
if (!this._replay) {
|
|
16389
|
-
return;
|
|
16390
|
-
}
|
|
16391
|
-
|
|
16392
|
-
this._replay.initializeSampling();
|
|
14912
|
+
return this._replay.flushImmediate();
|
|
16393
14913
|
}
|
|
16394
14914
|
|
|
16395
14915
|
/** Setup the integration. */
|
|
@@ -16440,10 +14960,6 @@ function loadReplayOptionsFromClient(initialOptions) {
|
|
|
16440
14960
|
return finalOptions;
|
|
16441
14961
|
}
|
|
16442
14962
|
|
|
16443
|
-
function _getMergedNetworkHeaders(headers) {
|
|
16444
|
-
return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
|
|
16445
|
-
}
|
|
16446
|
-
|
|
16447
14963
|
/**
|
|
16448
14964
|
* Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values,
|
|
16449
14965
|
* descriptors, and functions.
|
|
@@ -16881,9 +15397,6 @@ class Postgres {
|
|
|
16881
15397
|
const span = _optionalChain([parentSpan, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
|
|
16882
15398
|
description: typeof config === 'string' ? config : (config ).text,
|
|
16883
15399
|
op: 'db',
|
|
16884
|
-
data: {
|
|
16885
|
-
'db.system': 'postgresql',
|
|
16886
|
-
},
|
|
16887
15400
|
})]);
|
|
16888
15401
|
|
|
16889
15402
|
if (typeof callback === 'function') {
|
|
@@ -16960,9 +15473,6 @@ class Mysql {constructor() { Mysql.prototype.__init.call(this); }
|
|
|
16960
15473
|
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
|
16961
15474
|
description: typeof options === 'string' ? options : (options ).sql,
|
|
16962
15475
|
op: 'db',
|
|
16963
|
-
data: {
|
|
16964
|
-
'db.system': 'mysql',
|
|
16965
|
-
},
|
|
16966
15476
|
})]);
|
|
16967
15477
|
|
|
16968
15478
|
if (typeof callback === 'function') {
|
|
@@ -17184,7 +15694,6 @@ class Mongo {
|
|
|
17184
15694
|
collectionName: collection.collectionName,
|
|
17185
15695
|
dbName: collection.dbName,
|
|
17186
15696
|
namespace: collection.namespace,
|
|
17187
|
-
'db.system': 'mongodb',
|
|
17188
15697
|
};
|
|
17189
15698
|
const spanContext = {
|
|
17190
15699
|
op: 'db',
|
|
@@ -17271,15 +15780,31 @@ class Prisma {
|
|
|
17271
15780
|
}
|
|
17272
15781
|
|
|
17273
15782
|
this._client.$use((params, next) => {
|
|
15783
|
+
const scope = getCurrentHub().getScope();
|
|
15784
|
+
const parentSpan = _optionalChain([scope, 'optionalAccess', _2 => _2.getSpan, 'call', _3 => _3()]);
|
|
15785
|
+
|
|
17274
15786
|
const action = params.action;
|
|
17275
15787
|
const model = params.model;
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
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;
|
|
17280
15805
|
});
|
|
17281
15806
|
}
|
|
17282
|
-
}
|
|
15807
|
+
}Prisma.__initStatic();
|
|
17283
15808
|
|
|
17284
15809
|
/** Tracing integration for graphql package */
|
|
17285
15810
|
class GraphQL {constructor() { GraphQL.prototype.__init.call(this); }
|
|
@@ -30453,7 +28978,7 @@ const configGenerator = () => {
|
|
|
30453
28978
|
let release;
|
|
30454
28979
|
try {
|
|
30455
28980
|
environment !== null && environment !== void 0 ? environment : (environment = "staging");
|
|
30456
|
-
release !== null && release !== void 0 ? release : (release = "1.1.23-binary-
|
|
28981
|
+
release !== null && release !== void 0 ? release : (release = "1.1.23-binary-006");
|
|
30457
28982
|
}
|
|
30458
28983
|
catch (_a) {
|
|
30459
28984
|
console.error('sentry configGenerator error');
|
|
@@ -43520,9 +42045,7 @@ var AsapAction = (function (_super) {
|
|
|
43520
42045
|
var actions = scheduler.actions;
|
|
43521
42046
|
if (id != null && ((_a = actions[actions.length - 1]) === null || _a === void 0 ? void 0 : _a.id) !== id) {
|
|
43522
42047
|
immediateProvider.clearImmediate(id);
|
|
43523
|
-
|
|
43524
|
-
scheduler._scheduled = undefined;
|
|
43525
|
-
}
|
|
42048
|
+
scheduler._scheduled = undefined;
|
|
43526
42049
|
}
|
|
43527
42050
|
return undefined;
|
|
43528
42051
|
};
|