@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/esm/index.js
CHANGED
|
@@ -947,12 +947,6 @@ function createStackParser(...parsers) {
|
|
|
947
947
|
// Remove webpack (error: *) wrappers
|
|
948
948
|
const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, '$1') : line;
|
|
949
949
|
|
|
950
|
-
// https://github.com/getsentry/sentry-javascript/issues/7813
|
|
951
|
-
// Skip Error: lines
|
|
952
|
-
if (cleanedLine.match(/\S*Error: /)) {
|
|
953
|
-
continue;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
950
|
for (const parser of sortedParsers) {
|
|
957
951
|
const frame = parser(cleanedLine);
|
|
958
952
|
|
|
@@ -1137,8 +1131,6 @@ function supportsHistory() {
|
|
|
1137
1131
|
// eslint-disable-next-line deprecation/deprecation
|
|
1138
1132
|
const WINDOW$3 = getGlobalObject();
|
|
1139
1133
|
|
|
1140
|
-
const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v2__';
|
|
1141
|
-
|
|
1142
1134
|
/**
|
|
1143
1135
|
* Instrument native APIs to call handlers that can be used to create breadcrumbs, APM spans etc.
|
|
1144
1136
|
* - Console API
|
|
@@ -1251,13 +1243,11 @@ function instrumentFetch() {
|
|
|
1251
1243
|
|
|
1252
1244
|
fill(WINDOW$3, 'fetch', function (originalFetch) {
|
|
1253
1245
|
return function (...args) {
|
|
1254
|
-
const { method, url } = parseFetchArgs(args);
|
|
1255
|
-
|
|
1256
1246
|
const handlerData = {
|
|
1257
1247
|
args,
|
|
1258
1248
|
fetchData: {
|
|
1259
|
-
method,
|
|
1260
|
-
url,
|
|
1249
|
+
method: getFetchMethod(args),
|
|
1250
|
+
url: getFetchUrl(args),
|
|
1261
1251
|
},
|
|
1262
1252
|
startTimestamp: Date.now(),
|
|
1263
1253
|
};
|
|
@@ -1292,53 +1282,29 @@ function instrumentFetch() {
|
|
|
1292
1282
|
});
|
|
1293
1283
|
}
|
|
1294
1284
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
if (typeof resource === 'string') {
|
|
1301
|
-
return resource;
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
if (!resource) {
|
|
1305
|
-
return '';
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
if (hasProp(resource, 'url')) {
|
|
1309
|
-
return resource.url;
|
|
1285
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
1286
|
+
/** Extract `method` from fetch call arguments */
|
|
1287
|
+
function getFetchMethod(fetchArgs = []) {
|
|
1288
|
+
if ('Request' in WINDOW$3 && isInstanceOf(fetchArgs[0], Request) && fetchArgs[0].method) {
|
|
1289
|
+
return String(fetchArgs[0].method).toUpperCase();
|
|
1310
1290
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
return resource.toString();
|
|
1291
|
+
if (fetchArgs[1] && fetchArgs[1].method) {
|
|
1292
|
+
return String(fetchArgs[1].method).toUpperCase();
|
|
1314
1293
|
}
|
|
1315
|
-
|
|
1316
|
-
return '';
|
|
1294
|
+
return 'GET';
|
|
1317
1295
|
}
|
|
1318
1296
|
|
|
1319
|
-
/**
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
if (fetchArgs.length === 0) {
|
|
1324
|
-
return { method: 'GET', url: '' };
|
|
1297
|
+
/** Extract `url` from fetch call arguments */
|
|
1298
|
+
function getFetchUrl(fetchArgs = []) {
|
|
1299
|
+
if (typeof fetchArgs[0] === 'string') {
|
|
1300
|
+
return fetchArgs[0];
|
|
1325
1301
|
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
const [url, options] = fetchArgs ;
|
|
1329
|
-
|
|
1330
|
-
return {
|
|
1331
|
-
url: getUrlFromResource(url),
|
|
1332
|
-
method: hasProp(options, 'method') ? String(options.method).toUpperCase() : 'GET',
|
|
1333
|
-
};
|
|
1302
|
+
if ('Request' in WINDOW$3 && isInstanceOf(fetchArgs[0], Request)) {
|
|
1303
|
+
return fetchArgs[0].url;
|
|
1334
1304
|
}
|
|
1335
|
-
|
|
1336
|
-
const arg = fetchArgs[0];
|
|
1337
|
-
return {
|
|
1338
|
-
url: getUrlFromResource(arg ),
|
|
1339
|
-
method: hasProp(arg, 'method') ? String(arg.method).toUpperCase() : 'GET',
|
|
1340
|
-
};
|
|
1305
|
+
return String(fetchArgs[0]);
|
|
1341
1306
|
}
|
|
1307
|
+
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
|
1342
1308
|
|
|
1343
1309
|
/** JSDoc */
|
|
1344
1310
|
function instrumentXHR() {
|
|
@@ -1351,11 +1317,10 @@ function instrumentXHR() {
|
|
|
1351
1317
|
fill(xhrproto, 'open', function (originalOpen) {
|
|
1352
1318
|
return function ( ...args) {
|
|
1353
1319
|
const url = args[1];
|
|
1354
|
-
const xhrInfo = (this
|
|
1320
|
+
const xhrInfo = (this.__sentry_xhr__ = {
|
|
1355
1321
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
1356
1322
|
method: isString$2(args[0]) ? args[0].toUpperCase() : args[0],
|
|
1357
1323
|
url: args[1],
|
|
1358
|
-
request_headers: {},
|
|
1359
1324
|
});
|
|
1360
1325
|
|
|
1361
1326
|
// if Sentry key appears in URL, don't capture it as a request
|
|
@@ -1366,7 +1331,7 @@ function instrumentXHR() {
|
|
|
1366
1331
|
|
|
1367
1332
|
const onreadystatechangeHandler = () => {
|
|
1368
1333
|
// For whatever reason, this is not the same instance here as from the outer method
|
|
1369
|
-
const xhrInfo = this
|
|
1334
|
+
const xhrInfo = this.__sentry_xhr__;
|
|
1370
1335
|
|
|
1371
1336
|
if (!xhrInfo) {
|
|
1372
1337
|
return;
|
|
@@ -1401,32 +1366,14 @@ function instrumentXHR() {
|
|
|
1401
1366
|
this.addEventListener('readystatechange', onreadystatechangeHandler);
|
|
1402
1367
|
}
|
|
1403
1368
|
|
|
1404
|
-
// Intercepting `setRequestHeader` to access the request headers of XHR instance.
|
|
1405
|
-
// This will only work for user/library defined headers, not for the default/browser-assigned headers.
|
|
1406
|
-
// Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.
|
|
1407
|
-
fill(this, 'setRequestHeader', function (original) {
|
|
1408
|
-
return function ( ...setRequestHeaderArgs) {
|
|
1409
|
-
const [header, value] = setRequestHeaderArgs ;
|
|
1410
|
-
|
|
1411
|
-
const xhrInfo = this[SENTRY_XHR_DATA_KEY];
|
|
1412
|
-
|
|
1413
|
-
if (xhrInfo) {
|
|
1414
|
-
xhrInfo.request_headers[header.toLowerCase()] = value;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
return original.apply(this, setRequestHeaderArgs);
|
|
1418
|
-
};
|
|
1419
|
-
});
|
|
1420
|
-
|
|
1421
1369
|
return originalOpen.apply(this, args);
|
|
1422
1370
|
};
|
|
1423
1371
|
});
|
|
1424
1372
|
|
|
1425
1373
|
fill(xhrproto, 'send', function (originalSend) {
|
|
1426
1374
|
return function ( ...args) {
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
sentryXhrData.body = args[0];
|
|
1375
|
+
if (this.__sentry_xhr__ && args[0] !== undefined) {
|
|
1376
|
+
this.__sentry_xhr__.body = args[0];
|
|
1430
1377
|
}
|
|
1431
1378
|
|
|
1432
1379
|
triggerHandlers('xhr', {
|
|
@@ -1725,15 +1672,13 @@ function instrumentError() {
|
|
|
1725
1672
|
url,
|
|
1726
1673
|
});
|
|
1727
1674
|
|
|
1728
|
-
if (_oldOnErrorHandler
|
|
1675
|
+
if (_oldOnErrorHandler) {
|
|
1729
1676
|
// eslint-disable-next-line prefer-rest-params
|
|
1730
1677
|
return _oldOnErrorHandler.apply(this, arguments);
|
|
1731
1678
|
}
|
|
1732
1679
|
|
|
1733
1680
|
return false;
|
|
1734
1681
|
};
|
|
1735
|
-
|
|
1736
|
-
WINDOW$3.onerror.__SENTRY_INSTRUMENTED__ = true;
|
|
1737
1682
|
}
|
|
1738
1683
|
|
|
1739
1684
|
let _oldOnUnhandledRejectionHandler = null;
|
|
@@ -1744,15 +1689,13 @@ function instrumentUnhandledRejection() {
|
|
|
1744
1689
|
WINDOW$3.onunhandledrejection = function (e) {
|
|
1745
1690
|
triggerHandlers('unhandledrejection', e);
|
|
1746
1691
|
|
|
1747
|
-
if (_oldOnUnhandledRejectionHandler
|
|
1692
|
+
if (_oldOnUnhandledRejectionHandler) {
|
|
1748
1693
|
// eslint-disable-next-line prefer-rest-params
|
|
1749
1694
|
return _oldOnUnhandledRejectionHandler.apply(this, arguments);
|
|
1750
1695
|
}
|
|
1751
1696
|
|
|
1752
1697
|
return true;
|
|
1753
1698
|
};
|
|
1754
|
-
|
|
1755
|
-
WINDOW$3.onunhandledrejection.__SENTRY_INSTRUMENTED__ = true;
|
|
1756
1699
|
}
|
|
1757
1700
|
|
|
1758
1701
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
@@ -2050,7 +1993,7 @@ function loadModule(moduleName) {
|
|
|
2050
1993
|
* @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization.
|
|
2051
1994
|
*/
|
|
2052
1995
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2053
|
-
function normalize(input, depth =
|
|
1996
|
+
function normalize(input, depth = +Infinity, maxProperties = +Infinity) {
|
|
2054
1997
|
try {
|
|
2055
1998
|
// since we're at the outermost level, we don't provide a key
|
|
2056
1999
|
return visit('', input, depth, maxProperties);
|
|
@@ -2096,10 +2039,7 @@ function visit(
|
|
|
2096
2039
|
const [memoize, unmemoize] = memo;
|
|
2097
2040
|
|
|
2098
2041
|
// Get the simple cases out of the way first
|
|
2099
|
-
if (
|
|
2100
|
-
value == null || // this matches null and undefined -> eqeq not eqeqeq
|
|
2101
|
-
(['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))
|
|
2102
|
-
) {
|
|
2042
|
+
if (value === null || (['number', 'boolean', 'string'].includes(typeof value) && !isNaN$1(value))) {
|
|
2103
2043
|
return value ;
|
|
2104
2044
|
}
|
|
2105
2045
|
|
|
@@ -2120,16 +2060,17 @@ function visit(
|
|
|
2120
2060
|
return value ;
|
|
2121
2061
|
}
|
|
2122
2062
|
|
|
2123
|
-
//
|
|
2124
|
-
//
|
|
2125
|
-
//
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2063
|
+
// Do not normalize objects that we know have already been normalized. As a general rule, the
|
|
2064
|
+
// "__sentry_skip_normalization__" property should only be used sparingly and only should only be set on objects that
|
|
2065
|
+
// have already been normalized.
|
|
2066
|
+
let overriddenDepth = depth;
|
|
2067
|
+
|
|
2068
|
+
if (typeof (value )['__sentry_override_normalization_depth__'] === 'number') {
|
|
2069
|
+
overriddenDepth = (value )['__sentry_override_normalization_depth__'] ;
|
|
2070
|
+
}
|
|
2130
2071
|
|
|
2131
2072
|
// We're also done if we've reached the max depth
|
|
2132
|
-
if (
|
|
2073
|
+
if (overriddenDepth === 0) {
|
|
2133
2074
|
// At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.
|
|
2134
2075
|
return stringified.replace('object ', '');
|
|
2135
2076
|
}
|
|
@@ -2145,7 +2086,7 @@ function visit(
|
|
|
2145
2086
|
try {
|
|
2146
2087
|
const jsonValue = valueWithToJSON.toJSON();
|
|
2147
2088
|
// We need to normalize the return value of `.toJSON()` in case it has circular references
|
|
2148
|
-
return visit('', jsonValue,
|
|
2089
|
+
return visit('', jsonValue, overriddenDepth - 1, maxProperties, memo);
|
|
2149
2090
|
} catch (err) {
|
|
2150
2091
|
// pass (The built-in `toJSON` failed, but we can still try to do it ourselves)
|
|
2151
2092
|
}
|
|
@@ -2174,7 +2115,7 @@ function visit(
|
|
|
2174
2115
|
|
|
2175
2116
|
// Recursively visit all the child nodes
|
|
2176
2117
|
const visitValue = visitable[visitKey];
|
|
2177
|
-
normalized[visitKey] = visit(visitKey, visitValue,
|
|
2118
|
+
normalized[visitKey] = visit(visitKey, visitValue, overriddenDepth - 1, maxProperties, memo);
|
|
2178
2119
|
|
|
2179
2120
|
numAdded++;
|
|
2180
2121
|
}
|
|
@@ -2186,7 +2127,6 @@ function visit(
|
|
|
2186
2127
|
return normalized;
|
|
2187
2128
|
}
|
|
2188
2129
|
|
|
2189
|
-
/* eslint-disable complexity */
|
|
2190
2130
|
/**
|
|
2191
2131
|
* Stringify the given value. Handles various known special values and types.
|
|
2192
2132
|
*
|
|
@@ -2237,6 +2177,11 @@ function stringifyValue(
|
|
|
2237
2177
|
return '[NaN]';
|
|
2238
2178
|
}
|
|
2239
2179
|
|
|
2180
|
+
// this catches `undefined` (but not `null`, which is a primitive and can be serialized on its own)
|
|
2181
|
+
if (value === void 0) {
|
|
2182
|
+
return '[undefined]';
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2240
2185
|
if (typeof value === 'function') {
|
|
2241
2186
|
return `[Function: ${getFunctionName(value)}]`;
|
|
2242
2187
|
}
|
|
@@ -2254,19 +2199,11 @@ function stringifyValue(
|
|
|
2254
2199
|
// them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as
|
|
2255
2200
|
// `"[object Object]"`. If we instead look at the constructor's name (which is the same as the name of the class),
|
|
2256
2201
|
// we can make sure that only plain objects come out that way.
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
// Handle HTML Elements
|
|
2260
|
-
if (/^HTML(\w*)Element$/.test(objName)) {
|
|
2261
|
-
return `[HTMLElement: ${objName}]`;
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2264
|
-
return `[object ${objName}]`;
|
|
2202
|
+
return `[object ${getConstructorName(value)}]`;
|
|
2265
2203
|
} catch (err) {
|
|
2266
2204
|
return `**non-serializable** (${err})`;
|
|
2267
2205
|
}
|
|
2268
2206
|
}
|
|
2269
|
-
/* eslint-enable complexity */
|
|
2270
2207
|
|
|
2271
2208
|
function getConstructorName(value) {
|
|
2272
2209
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -2577,7 +2514,9 @@ function makePromiseBuffer(limit) {
|
|
|
2577
2514
|
* // environments where DOM might not be available
|
|
2578
2515
|
* @returns parsed URL object
|
|
2579
2516
|
*/
|
|
2580
|
-
function parseUrl(url)
|
|
2517
|
+
function parseUrl(url)
|
|
2518
|
+
|
|
2519
|
+
{
|
|
2581
2520
|
if (!url) {
|
|
2582
2521
|
return {};
|
|
2583
2522
|
}
|
|
@@ -2595,8 +2534,6 @@ function parseUrl(url) {
|
|
|
2595
2534
|
host: match[4],
|
|
2596
2535
|
path: match[5],
|
|
2597
2536
|
protocol: match[2],
|
|
2598
|
-
search: query,
|
|
2599
|
-
hash: fragment,
|
|
2600
2537
|
relative: match[5] + query + fragment, // everything minus origin
|
|
2601
2538
|
};
|
|
2602
2539
|
}
|
|
@@ -2981,7 +2918,6 @@ const ITEM_TYPE_TO_DATA_CATEGORY_MAP = {
|
|
|
2981
2918
|
profile: 'profile',
|
|
2982
2919
|
replay_event: 'replay',
|
|
2983
2920
|
replay_recording: 'replay',
|
|
2984
|
-
check_in: 'monitor',
|
|
2985
2921
|
};
|
|
2986
2922
|
|
|
2987
2923
|
/**
|
|
@@ -3011,14 +2947,16 @@ function createEventEnvelopeHeaders(
|
|
|
3011
2947
|
dsn,
|
|
3012
2948
|
) {
|
|
3013
2949
|
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;
|
|
2950
|
+
|
|
3014
2951
|
return {
|
|
3015
2952
|
event_id: event.event_id ,
|
|
3016
2953
|
sent_at: new Date().toISOString(),
|
|
3017
2954
|
...(sdkInfo && { sdk: sdkInfo }),
|
|
3018
2955
|
...(!!tunnel && { dsn: dsnToString(dsn) }),
|
|
3019
|
-
...(
|
|
3020
|
-
|
|
3021
|
-
|
|
2956
|
+
...(event.type === 'transaction' &&
|
|
2957
|
+
dynamicSamplingContext && {
|
|
2958
|
+
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
|
|
2959
|
+
}),
|
|
3022
2960
|
};
|
|
3023
2961
|
}
|
|
3024
2962
|
|
|
@@ -3723,16 +3661,9 @@ class Scope {
|
|
|
3723
3661
|
// errors with transaction and it relies on that.
|
|
3724
3662
|
if (this._span) {
|
|
3725
3663
|
event.contexts = { trace: this._span.getTraceContext(), ...event.contexts };
|
|
3726
|
-
const
|
|
3727
|
-
if (
|
|
3728
|
-
event.
|
|
3729
|
-
dynamicSamplingContext: transaction.getDynamicSamplingContext(),
|
|
3730
|
-
...event.sdkProcessingMetadata,
|
|
3731
|
-
};
|
|
3732
|
-
const transactionName = transaction.name;
|
|
3733
|
-
if (transactionName) {
|
|
3734
|
-
event.tags = { transaction: transactionName, ...event.tags };
|
|
3735
|
-
}
|
|
3664
|
+
const transactionName = this._span.transaction && this._span.transaction.name;
|
|
3665
|
+
if (transactionName) {
|
|
3666
|
+
event.tags = { transaction: transactionName, ...event.tags };
|
|
3736
3667
|
}
|
|
3737
3668
|
}
|
|
3738
3669
|
|
|
@@ -3856,6 +3787,11 @@ const API_VERSION = 4;
|
|
|
3856
3787
|
*/
|
|
3857
3788
|
const DEFAULT_BREADCRUMBS = 100;
|
|
3858
3789
|
|
|
3790
|
+
/**
|
|
3791
|
+
* A layer in the process stack.
|
|
3792
|
+
* @hidden
|
|
3793
|
+
*/
|
|
3794
|
+
|
|
3859
3795
|
/**
|
|
3860
3796
|
* @inheritDoc
|
|
3861
3797
|
*/
|
|
@@ -4133,17 +4069,7 @@ class Hub {
|
|
|
4133
4069
|
* @inheritDoc
|
|
4134
4070
|
*/
|
|
4135
4071
|
startTransaction(context, customSamplingContext) {
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && !result) {
|
|
4139
|
-
// eslint-disable-next-line no-console
|
|
4140
|
-
console.warn(`Tracing extension 'startTransaction' has not been added. Call 'addTracingExtensions' before calling 'init':
|
|
4141
|
-
Sentry.addTracingExtensions();
|
|
4142
|
-
Sentry.init({...});
|
|
4143
|
-
`);
|
|
4144
|
-
}
|
|
4145
|
-
|
|
4146
|
-
return result;
|
|
4072
|
+
return this._callExtensionMethod('startTransaction', context, customSamplingContext);
|
|
4147
4073
|
}
|
|
4148
4074
|
|
|
4149
4075
|
/**
|
|
@@ -4228,10 +4154,13 @@ Sentry.init({...});
|
|
|
4228
4154
|
*/
|
|
4229
4155
|
_sendSessionUpdate() {
|
|
4230
4156
|
const { scope, client } = this.getStackTop();
|
|
4157
|
+
if (!scope) return;
|
|
4231
4158
|
|
|
4232
4159
|
const session = scope.getSession();
|
|
4233
|
-
if (session
|
|
4234
|
-
client.captureSession
|
|
4160
|
+
if (session) {
|
|
4161
|
+
if (client && client.captureSession) {
|
|
4162
|
+
client.captureSession(session);
|
|
4163
|
+
}
|
|
4235
4164
|
}
|
|
4236
4165
|
}
|
|
4237
4166
|
|
|
@@ -4301,28 +4230,47 @@ function getCurrentHub() {
|
|
|
4301
4230
|
// Get main carrier (global for every environment)
|
|
4302
4231
|
const registry = getMainCarrier();
|
|
4303
4232
|
|
|
4304
|
-
if (registry.__SENTRY__ && registry.__SENTRY__.acs) {
|
|
4305
|
-
const hub = registry.__SENTRY__.acs.getCurrentHub();
|
|
4306
|
-
|
|
4307
|
-
if (hub) {
|
|
4308
|
-
return hub;
|
|
4309
|
-
}
|
|
4310
|
-
}
|
|
4311
|
-
|
|
4312
|
-
// Return hub that lives on a global object
|
|
4313
|
-
return getGlobalHub(registry);
|
|
4314
|
-
}
|
|
4315
|
-
|
|
4316
|
-
function getGlobalHub(registry = getMainCarrier()) {
|
|
4317
4233
|
// If there's no hub, or its an old API, assign a new one
|
|
4318
4234
|
if (!hasHubOnCarrier(registry) || getHubFromCarrier(registry).isOlderThan(API_VERSION)) {
|
|
4319
4235
|
setHubOnCarrier(registry, new Hub());
|
|
4320
4236
|
}
|
|
4321
4237
|
|
|
4238
|
+
// Prefer domains over global if they are there (applicable only to Node environment)
|
|
4239
|
+
if (isNodeEnv()) {
|
|
4240
|
+
return getHubFromActiveDomain(registry);
|
|
4241
|
+
}
|
|
4322
4242
|
// Return hub that lives on a global object
|
|
4323
4243
|
return getHubFromCarrier(registry);
|
|
4324
4244
|
}
|
|
4325
4245
|
|
|
4246
|
+
/**
|
|
4247
|
+
* Try to read the hub from an active domain, and fallback to the registry if one doesn't exist
|
|
4248
|
+
* @returns discovered hub
|
|
4249
|
+
*/
|
|
4250
|
+
function getHubFromActiveDomain(registry) {
|
|
4251
|
+
try {
|
|
4252
|
+
const sentry = getMainCarrier().__SENTRY__;
|
|
4253
|
+
const activeDomain = sentry && sentry.extensions && sentry.extensions.domain && sentry.extensions.domain.active;
|
|
4254
|
+
|
|
4255
|
+
// If there's no active domain, just return global hub
|
|
4256
|
+
if (!activeDomain) {
|
|
4257
|
+
return getHubFromCarrier(registry);
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
// If there's no hub on current domain, or it's an old API, assign a new one
|
|
4261
|
+
if (!hasHubOnCarrier(activeDomain) || getHubFromCarrier(activeDomain).isOlderThan(API_VERSION)) {
|
|
4262
|
+
const registryHubTopStack = getHubFromCarrier(registry).getStackTop();
|
|
4263
|
+
setHubOnCarrier(activeDomain, new Hub(registryHubTopStack.client, Scope.clone(registryHubTopStack.scope)));
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
// Return hub that lives on a domain
|
|
4267
|
+
return getHubFromCarrier(activeDomain);
|
|
4268
|
+
} catch (_Oo) {
|
|
4269
|
+
// Return hub that lives on a global object
|
|
4270
|
+
return getHubFromCarrier(registry);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4326
4274
|
/**
|
|
4327
4275
|
* This will tell whether a carrier has a hub on it or not
|
|
4328
4276
|
* @param carrier object
|
|
@@ -4396,69 +4344,6 @@ var SpanStatus; (function (SpanStatus) {
|
|
|
4396
4344
|
const DataLoss = 'data_loss'; SpanStatus["DataLoss"] = DataLoss;
|
|
4397
4345
|
})(SpanStatus || (SpanStatus = {}));
|
|
4398
4346
|
|
|
4399
|
-
/**
|
|
4400
|
-
* Wraps a function with a transaction/span and finishes the span after the function is done.
|
|
4401
|
-
*
|
|
4402
|
-
* Note that if you have not enabled tracing extensions via `addTracingExtensions`, this function
|
|
4403
|
-
* will not generate spans, and the `span` returned from the callback may be undefined.
|
|
4404
|
-
*
|
|
4405
|
-
* This function is meant to be used internally and may break at any time. Use at your own risk.
|
|
4406
|
-
*
|
|
4407
|
-
* @internal
|
|
4408
|
-
* @private
|
|
4409
|
-
*/
|
|
4410
|
-
function trace(
|
|
4411
|
-
context,
|
|
4412
|
-
callback,
|
|
4413
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
4414
|
-
onError = () => {},
|
|
4415
|
-
) {
|
|
4416
|
-
const ctx = { ...context };
|
|
4417
|
-
// If a name is set and a description is not, set the description to the name.
|
|
4418
|
-
if (ctx.name !== undefined && ctx.description === undefined) {
|
|
4419
|
-
ctx.description = ctx.name;
|
|
4420
|
-
}
|
|
4421
|
-
|
|
4422
|
-
const hub = getCurrentHub();
|
|
4423
|
-
const scope = hub.getScope();
|
|
4424
|
-
|
|
4425
|
-
const parentSpan = scope.getSpan();
|
|
4426
|
-
const activeSpan = parentSpan ? parentSpan.startChild(ctx) : hub.startTransaction(ctx);
|
|
4427
|
-
scope.setSpan(activeSpan);
|
|
4428
|
-
|
|
4429
|
-
function finishAndSetSpan() {
|
|
4430
|
-
activeSpan && activeSpan.finish();
|
|
4431
|
-
hub.getScope().setSpan(parentSpan);
|
|
4432
|
-
}
|
|
4433
|
-
|
|
4434
|
-
let maybePromiseResult;
|
|
4435
|
-
try {
|
|
4436
|
-
maybePromiseResult = callback(activeSpan);
|
|
4437
|
-
} catch (e) {
|
|
4438
|
-
activeSpan && activeSpan.setStatus('internal_error');
|
|
4439
|
-
onError(e);
|
|
4440
|
-
finishAndSetSpan();
|
|
4441
|
-
throw e;
|
|
4442
|
-
}
|
|
4443
|
-
|
|
4444
|
-
if (isThenable(maybePromiseResult)) {
|
|
4445
|
-
Promise.resolve(maybePromiseResult).then(
|
|
4446
|
-
() => {
|
|
4447
|
-
finishAndSetSpan();
|
|
4448
|
-
},
|
|
4449
|
-
e => {
|
|
4450
|
-
activeSpan && activeSpan.setStatus('internal_error');
|
|
4451
|
-
onError(e);
|
|
4452
|
-
finishAndSetSpan();
|
|
4453
|
-
},
|
|
4454
|
-
);
|
|
4455
|
-
} else {
|
|
4456
|
-
finishAndSetSpan();
|
|
4457
|
-
}
|
|
4458
|
-
|
|
4459
|
-
return maybePromiseResult;
|
|
4460
|
-
}
|
|
4461
|
-
|
|
4462
4347
|
// Note: All functions in this file are typed with a return value of `ReturnType<Hub[HUB_FUNCTION]>`,
|
|
4463
4348
|
// where HUB_FUNCTION is some method on the Hub class.
|
|
4464
4349
|
//
|
|
@@ -4800,11 +4685,7 @@ function prepareEvent(
|
|
|
4800
4685
|
|
|
4801
4686
|
applyClientOptions(prepared, options);
|
|
4802
4687
|
applyIntegrationsMetadata(prepared, integrations);
|
|
4803
|
-
|
|
4804
|
-
// Only apply debug metadata to error events.
|
|
4805
|
-
if (event.type === undefined) {
|
|
4806
|
-
applyDebugMetadata(prepared, options.stackParser);
|
|
4807
|
-
}
|
|
4688
|
+
applyDebugMetadata(prepared, options.stackParser);
|
|
4808
4689
|
|
|
4809
4690
|
// If we have scope given to us, use it as the base for further modifications.
|
|
4810
4691
|
// This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
|
|
@@ -4881,8 +4762,6 @@ function applyClientOptions(event, options) {
|
|
|
4881
4762
|
}
|
|
4882
4763
|
}
|
|
4883
4764
|
|
|
4884
|
-
const debugIdStackParserCache = new WeakMap();
|
|
4885
|
-
|
|
4886
4765
|
/**
|
|
4887
4766
|
* Applies debug metadata images to the event in order to apply source maps by looking up their debug ID.
|
|
4888
4767
|
*/
|
|
@@ -4893,28 +4772,10 @@ function applyDebugMetadata(event, stackParser) {
|
|
|
4893
4772
|
return;
|
|
4894
4773
|
}
|
|
4895
4774
|
|
|
4896
|
-
let debugIdStackFramesCache;
|
|
4897
|
-
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
|
|
4898
|
-
if (cachedDebugIdStackFrameCache) {
|
|
4899
|
-
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
|
|
4900
|
-
} else {
|
|
4901
|
-
debugIdStackFramesCache = new Map();
|
|
4902
|
-
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
|
|
4903
|
-
}
|
|
4904
|
-
|
|
4905
4775
|
// Build a map of filename -> debug_id
|
|
4906
4776
|
const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => {
|
|
4907
|
-
|
|
4908
|
-
const
|
|
4909
|
-
if (cachedParsedStack) {
|
|
4910
|
-
parsedStack = cachedParsedStack;
|
|
4911
|
-
} else {
|
|
4912
|
-
parsedStack = stackParser(debugIdStackTrace);
|
|
4913
|
-
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
|
|
4914
|
-
}
|
|
4915
|
-
|
|
4916
|
-
for (let i = parsedStack.length - 1; i >= 0; i--) {
|
|
4917
|
-
const stackFrame = parsedStack[i];
|
|
4777
|
+
const parsedStack = stackParser(debugIdStackTrace);
|
|
4778
|
+
for (const stackFrame of parsedStack) {
|
|
4918
4779
|
if (stackFrame.filename) {
|
|
4919
4780
|
acc[stackFrame.filename] = debugIdMap[debugIdStackTrace];
|
|
4920
4781
|
break;
|
|
@@ -5819,7 +5680,7 @@ function getEventForEnvelopeItem(item, type) {
|
|
|
5819
5680
|
return Array.isArray(item) ? (item )[1] : undefined;
|
|
5820
5681
|
}
|
|
5821
5682
|
|
|
5822
|
-
const SDK_VERSION = '7.
|
|
5683
|
+
const SDK_VERSION = '7.46.0';
|
|
5823
5684
|
|
|
5824
5685
|
let originalFunctionToString;
|
|
5825
5686
|
|
|
@@ -5842,17 +5703,11 @@ class FunctionToString {constructor() { FunctionToString.prototype.__init.call(
|
|
|
5842
5703
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
5843
5704
|
originalFunctionToString = Function.prototype.toString;
|
|
5844
5705
|
|
|
5845
|
-
//
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
const context = getOriginalFunction(this) || this;
|
|
5851
|
-
return originalFunctionToString.apply(context, args);
|
|
5852
|
-
};
|
|
5853
|
-
} catch (e) {
|
|
5854
|
-
// ignore errors here, just don't patch this
|
|
5855
|
-
}
|
|
5706
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5707
|
+
Function.prototype.toString = function ( ...args) {
|
|
5708
|
+
const context = getOriginalFunction(this) || this;
|
|
5709
|
+
return originalFunctionToString.apply(context, args);
|
|
5710
|
+
};
|
|
5856
5711
|
}
|
|
5857
5712
|
} FunctionToString.__initStatic();
|
|
5858
5713
|
|
|
@@ -6000,9 +5855,8 @@ function _getPossibleEventMessages(event) {
|
|
|
6000
5855
|
return [event.message];
|
|
6001
5856
|
}
|
|
6002
5857
|
if (event.exception) {
|
|
6003
|
-
const { values } = event.exception;
|
|
6004
5858
|
try {
|
|
6005
|
-
const { type = '', value = '' } = (values && values[
|
|
5859
|
+
const { type = '', value = '' } = (event.exception.values && event.exception.values[0]) || {};
|
|
6006
5860
|
return [`${value}`, `${type}: ${value}`];
|
|
6007
5861
|
} catch (oO) {
|
|
6008
5862
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(`Cannot extract message for event ${getEventDescription(event)}`);
|
|
@@ -6661,14 +6515,12 @@ function _consoleBreadcrumb(handlerData) {
|
|
|
6661
6515
|
function _xhrBreadcrumb(handlerData) {
|
|
6662
6516
|
const { startTimestamp, endTimestamp } = handlerData;
|
|
6663
6517
|
|
|
6664
|
-
const sentryXhrData = handlerData.xhr[SENTRY_XHR_DATA_KEY];
|
|
6665
|
-
|
|
6666
6518
|
// We only capture complete, non-sentry requests
|
|
6667
|
-
if (!startTimestamp || !endTimestamp || !
|
|
6519
|
+
if (!startTimestamp || !endTimestamp || !handlerData.xhr.__sentry_xhr__) {
|
|
6668
6520
|
return;
|
|
6669
6521
|
}
|
|
6670
6522
|
|
|
6671
|
-
const { method, url, status_code, body } =
|
|
6523
|
+
const { method, url, status_code, body } = handlerData.xhr.__sentry_xhr__;
|
|
6672
6524
|
|
|
6673
6525
|
const data = {
|
|
6674
6526
|
method,
|
|
@@ -6786,43 +6638,6 @@ function _isEvent(event) {
|
|
|
6786
6638
|
return event && !!(event ).target;
|
|
6787
6639
|
}
|
|
6788
6640
|
|
|
6789
|
-
/**
|
|
6790
|
-
* Creates an envelope from a user feedback.
|
|
6791
|
-
*/
|
|
6792
|
-
function createUserFeedbackEnvelope(
|
|
6793
|
-
feedback,
|
|
6794
|
-
{
|
|
6795
|
-
metadata,
|
|
6796
|
-
tunnel,
|
|
6797
|
-
dsn,
|
|
6798
|
-
}
|
|
6799
|
-
|
|
6800
|
-
,
|
|
6801
|
-
) {
|
|
6802
|
-
const headers = {
|
|
6803
|
-
event_id: feedback.event_id,
|
|
6804
|
-
sent_at: new Date().toISOString(),
|
|
6805
|
-
...(metadata &&
|
|
6806
|
-
metadata.sdk && {
|
|
6807
|
-
sdk: {
|
|
6808
|
-
name: metadata.sdk.name,
|
|
6809
|
-
version: metadata.sdk.version,
|
|
6810
|
-
},
|
|
6811
|
-
}),
|
|
6812
|
-
...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }),
|
|
6813
|
-
};
|
|
6814
|
-
const item = createUserFeedbackEnvelopeItem(feedback);
|
|
6815
|
-
|
|
6816
|
-
return createEnvelope(headers, [item]);
|
|
6817
|
-
}
|
|
6818
|
-
|
|
6819
|
-
function createUserFeedbackEnvelopeItem(feedback) {
|
|
6820
|
-
const feedbackHeaders = {
|
|
6821
|
-
type: 'user_report',
|
|
6822
|
-
};
|
|
6823
|
-
return [feedbackHeaders, feedback];
|
|
6824
|
-
}
|
|
6825
|
-
|
|
6826
6641
|
/**
|
|
6827
6642
|
* Configuration options for the Sentry Browser SDK.
|
|
6828
6643
|
* @see @sentry/types Options for more information.
|
|
@@ -6905,23 +6720,6 @@ class BrowserClient extends BaseClient {
|
|
|
6905
6720
|
super.sendEvent(event, hint);
|
|
6906
6721
|
}
|
|
6907
6722
|
|
|
6908
|
-
/**
|
|
6909
|
-
* Sends user feedback to Sentry.
|
|
6910
|
-
*/
|
|
6911
|
-
captureUserFeedback(feedback) {
|
|
6912
|
-
if (!this._isEnabled()) {
|
|
6913
|
-
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('SDK not enabled, will not capture user feedback.');
|
|
6914
|
-
return;
|
|
6915
|
-
}
|
|
6916
|
-
|
|
6917
|
-
const envelope = createUserFeedbackEnvelope(feedback, {
|
|
6918
|
-
metadata: this.getSdkMetadata(),
|
|
6919
|
-
dsn: this.getDsn(),
|
|
6920
|
-
tunnel: this.getOptions().tunnel,
|
|
6921
|
-
});
|
|
6922
|
-
void this._sendEnvelope(envelope);
|
|
6923
|
-
}
|
|
6924
|
-
|
|
6925
6723
|
/**
|
|
6926
6724
|
* @inheritDoc
|
|
6927
6725
|
*/
|
|
@@ -7164,7 +6962,7 @@ function createFrame(filename, func, lineno, colno) {
|
|
|
7164
6962
|
|
|
7165
6963
|
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
|
|
7166
6964
|
const chromeRegex =
|
|
7167
|
-
/^\s*at (?:(
|
|
6965
|
+
/^\s*at (?:(.*\).*?|.*?) ?\((?:address at )?)?(?:async )?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
|
|
7168
6966
|
const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
|
|
7169
6967
|
|
|
7170
6968
|
const chrome = line => {
|
|
@@ -7200,7 +6998,7 @@ const chromeStackLineParser = [CHROME_PRIORITY, chrome];
|
|
|
7200
6998
|
// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
|
|
7201
6999
|
// We need this specific case for now because we want no other regex to match.
|
|
7202
7000
|
const geckoREgex =
|
|
7203
|
-
/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:
|
|
7001
|
+
/^\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;
|
|
7204
7002
|
const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
|
|
7205
7003
|
|
|
7206
7004
|
const gecko = line => {
|
|
@@ -7232,7 +7030,8 @@ const gecko = line => {
|
|
|
7232
7030
|
|
|
7233
7031
|
const geckoStackLineParser = [GECKO_PRIORITY, gecko];
|
|
7234
7032
|
|
|
7235
|
-
const winjsRegex =
|
|
7033
|
+
const winjsRegex =
|
|
7034
|
+
/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
|
7236
7035
|
|
|
7237
7036
|
const winjs = line => {
|
|
7238
7037
|
const parts = winjsRegex.exec(line);
|
|
@@ -8297,14 +8096,11 @@ const REPLAY_SESSION_KEY = 'sentryReplaySession';
|
|
|
8297
8096
|
const REPLAY_EVENT_NAME = 'replay_event';
|
|
8298
8097
|
const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
|
|
8299
8098
|
|
|
8300
|
-
// The idle limit for a session
|
|
8301
|
-
const
|
|
8302
|
-
|
|
8303
|
-
// The idle limit for a session after which the session expires.
|
|
8304
|
-
const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms
|
|
8099
|
+
// The idle limit for a session
|
|
8100
|
+
const SESSION_IDLE_DURATION = 300000; // 5 minutes in ms
|
|
8305
8101
|
|
|
8306
8102
|
// The maximum length of a session
|
|
8307
|
-
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8103
|
+
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8308
8104
|
|
|
8309
8105
|
/** Default flush delays */
|
|
8310
8106
|
const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
@@ -8313,16 +8109,13 @@ const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
|
8313
8109
|
const DEFAULT_FLUSH_MAX_DELAY = 5500;
|
|
8314
8110
|
|
|
8315
8111
|
/* How long to wait for error checkouts */
|
|
8316
|
-
const
|
|
8112
|
+
const ERROR_CHECKOUT_TIME = 60000;
|
|
8317
8113
|
|
|
8318
8114
|
const RETRY_BASE_INTERVAL = 5000;
|
|
8319
8115
|
const RETRY_MAX_COUNT = 3;
|
|
8320
8116
|
|
|
8321
|
-
/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be
|
|
8322
|
-
const NETWORK_BODY_MAX_SIZE =
|
|
8323
|
-
|
|
8324
|
-
/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
|
|
8325
|
-
const CONSOLE_ARG_MAX_SIZE = 5000;
|
|
8117
|
+
/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be dropped. */
|
|
8118
|
+
const NETWORK_BODY_MAX_SIZE = 300000;
|
|
8326
8119
|
|
|
8327
8120
|
var NodeType$1;
|
|
8328
8121
|
(function (NodeType) {
|
|
@@ -8359,7 +8152,7 @@ function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInp
|
|
|
8359
8152
|
if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
|
|
8360
8153
|
return text;
|
|
8361
8154
|
}
|
|
8362
|
-
if (input.hasAttribute('
|
|
8155
|
+
if (input.hasAttribute('rr_is_password')) {
|
|
8363
8156
|
type = 'password';
|
|
8364
8157
|
}
|
|
8365
8158
|
if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
|
|
@@ -8392,21 +8185,6 @@ function is2DCanvasBlank(canvas) {
|
|
|
8392
8185
|
}
|
|
8393
8186
|
return true;
|
|
8394
8187
|
}
|
|
8395
|
-
function getInputType(element) {
|
|
8396
|
-
const type = element.type;
|
|
8397
|
-
return element.hasAttribute('data-rr-is-password')
|
|
8398
|
-
? 'password'
|
|
8399
|
-
: type
|
|
8400
|
-
? type.toLowerCase()
|
|
8401
|
-
: null;
|
|
8402
|
-
}
|
|
8403
|
-
function getInputValue(el, tagName, type) {
|
|
8404
|
-
typeof type === 'string' ? type.toLowerCase() : '';
|
|
8405
|
-
if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
|
|
8406
|
-
return el.getAttribute('value') || '';
|
|
8407
|
-
}
|
|
8408
|
-
return el.value;
|
|
8409
|
-
}
|
|
8410
8188
|
|
|
8411
8189
|
let _id = 1;
|
|
8412
8190
|
const tagNameRegex = new RegExp('[^a-z0-9-_:]');
|
|
@@ -8445,13 +8223,6 @@ function getCssRuleString(rule) {
|
|
|
8445
8223
|
catch (_a) {
|
|
8446
8224
|
}
|
|
8447
8225
|
}
|
|
8448
|
-
return validateStringifiedCssRule(cssStringified);
|
|
8449
|
-
}
|
|
8450
|
-
function validateStringifiedCssRule(cssStringified) {
|
|
8451
|
-
if (cssStringified.indexOf(':') > -1) {
|
|
8452
|
-
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
|
|
8453
|
-
return cssStringified.replace(regex, '$1\\$2');
|
|
8454
|
-
}
|
|
8455
8226
|
return cssStringified;
|
|
8456
8227
|
}
|
|
8457
8228
|
function isCSSImportRule(rule) {
|
|
@@ -8460,7 +8231,7 @@ function isCSSImportRule(rule) {
|
|
|
8460
8231
|
function stringifyStyleSheet(sheet) {
|
|
8461
8232
|
return sheet.cssRules
|
|
8462
8233
|
? Array.from(sheet.cssRules)
|
|
8463
|
-
.map((rule) => rule.cssText
|
|
8234
|
+
.map((rule) => rule.cssText || '')
|
|
8464
8235
|
.join('')
|
|
8465
8236
|
: '';
|
|
8466
8237
|
}
|
|
@@ -8795,15 +8566,14 @@ function serializeNode(n, options) {
|
|
|
8795
8566
|
tagName === 'select' ||
|
|
8796
8567
|
tagName === 'option') {
|
|
8797
8568
|
const el = n;
|
|
8798
|
-
const
|
|
8799
|
-
const value = getInputValue(el, tagName.toUpperCase(), type);
|
|
8569
|
+
const value = getInputValue(tagName, el, attributes);
|
|
8800
8570
|
const checked = n.checked;
|
|
8801
|
-
if (type !== 'submit' &&
|
|
8802
|
-
type !== 'button' &&
|
|
8571
|
+
if (attributes.type !== 'submit' &&
|
|
8572
|
+
attributes.type !== 'button' &&
|
|
8803
8573
|
value) {
|
|
8804
8574
|
attributes.value = maskInputValue({
|
|
8805
8575
|
input: el,
|
|
8806
|
-
type,
|
|
8576
|
+
type: attributes.type,
|
|
8807
8577
|
tagName,
|
|
8808
8578
|
value,
|
|
8809
8579
|
maskInputSelector,
|
|
@@ -9276,8 +9046,15 @@ function snapshot(n, options) {
|
|
|
9276
9046
|
function skipAttribute(tagName, attributeName, value) {
|
|
9277
9047
|
return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
|
|
9278
9048
|
}
|
|
9049
|
+
function getInputValue(tagName, el, attributes) {
|
|
9050
|
+
if (tagName === 'input' &&
|
|
9051
|
+
(attributes.type === 'radio' || attributes.type === 'checkbox')) {
|
|
9052
|
+
return el.getAttribute('value') || '';
|
|
9053
|
+
}
|
|
9054
|
+
return el.value;
|
|
9055
|
+
}
|
|
9279
9056
|
|
|
9280
|
-
var EventType
|
|
9057
|
+
var EventType;
|
|
9281
9058
|
(function (EventType) {
|
|
9282
9059
|
EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
|
|
9283
9060
|
EventType[EventType["Load"] = 1] = "Load";
|
|
@@ -9286,7 +9063,7 @@ var EventType$1;
|
|
|
9286
9063
|
EventType[EventType["Meta"] = 4] = "Meta";
|
|
9287
9064
|
EventType[EventType["Custom"] = 5] = "Custom";
|
|
9288
9065
|
EventType[EventType["Plugin"] = 6] = "Plugin";
|
|
9289
|
-
})(EventType
|
|
9066
|
+
})(EventType || (EventType = {}));
|
|
9290
9067
|
var IncrementalSource;
|
|
9291
9068
|
(function (IncrementalSource) {
|
|
9292
9069
|
IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
|
|
@@ -9901,9 +9678,9 @@ class MutationBuffer {
|
|
|
9901
9678
|
this.attributes.push(item);
|
|
9902
9679
|
}
|
|
9903
9680
|
if (m.attributeName === 'type' &&
|
|
9904
|
-
target.tagName === 'INPUT' &&
|
|
9681
|
+
m.target.tagName === 'INPUT' &&
|
|
9905
9682
|
(m.oldValue || '').toLowerCase() === 'password') {
|
|
9906
|
-
target.setAttribute('
|
|
9683
|
+
m.target.setAttribute('rr_is_password', 'true');
|
|
9907
9684
|
}
|
|
9908
9685
|
if (m.attributeName === 'style') {
|
|
9909
9686
|
const old = this.doc.createElement('span');
|
|
@@ -10300,25 +10077,27 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
|
|
|
10300
10077
|
isBlocked(target, blockClass, blockSelector, unblockSelector)) {
|
|
10301
10078
|
return;
|
|
10302
10079
|
}
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
(ignoreSelector && el.matches(ignoreSelector))) {
|
|
10080
|
+
let type = target.type;
|
|
10081
|
+
if (target.classList.contains(ignoreClass) ||
|
|
10082
|
+
(ignoreSelector && target.matches(ignoreSelector))) {
|
|
10307
10083
|
return;
|
|
10308
10084
|
}
|
|
10309
|
-
let text =
|
|
10085
|
+
let text = target.value;
|
|
10310
10086
|
let isChecked = false;
|
|
10087
|
+
if (target.hasAttribute('rr_is_password')) {
|
|
10088
|
+
type = 'password';
|
|
10089
|
+
}
|
|
10311
10090
|
if (type === 'radio' || type === 'checkbox') {
|
|
10312
10091
|
isChecked = target.checked;
|
|
10313
10092
|
}
|
|
10314
|
-
if (hasInputMaskOptions({
|
|
10093
|
+
else if (hasInputMaskOptions({
|
|
10315
10094
|
maskInputOptions,
|
|
10316
10095
|
maskInputSelector,
|
|
10317
10096
|
tagName,
|
|
10318
10097
|
type,
|
|
10319
10098
|
})) {
|
|
10320
10099
|
text = maskInputValue({
|
|
10321
|
-
input:
|
|
10100
|
+
input: target,
|
|
10322
10101
|
maskInputOptions,
|
|
10323
10102
|
maskInputSelector,
|
|
10324
10103
|
unmaskInputSelector,
|
|
@@ -10335,18 +10114,8 @@ function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, un
|
|
|
10335
10114
|
.querySelectorAll(`input[type="radio"][name="${name}"]`)
|
|
10336
10115
|
.forEach((el) => {
|
|
10337
10116
|
if (el !== target) {
|
|
10338
|
-
const text = maskInputValue({
|
|
10339
|
-
input: el,
|
|
10340
|
-
maskInputOptions,
|
|
10341
|
-
maskInputSelector,
|
|
10342
|
-
unmaskInputSelector,
|
|
10343
|
-
tagName,
|
|
10344
|
-
type,
|
|
10345
|
-
value: getInputValue(el, tagName, type),
|
|
10346
|
-
maskInputFn,
|
|
10347
|
-
});
|
|
10348
10117
|
cbWithDedup(el, callbackWrapper(wrapEventWithUserTriggeredFlag)({
|
|
10349
|
-
text,
|
|
10118
|
+
text: el.value,
|
|
10350
10119
|
isChecked: !isChecked,
|
|
10351
10120
|
userTriggered: false,
|
|
10352
10121
|
}, userTriggeredOnInput));
|
|
@@ -11259,17 +11028,17 @@ function record(options = {}) {
|
|
|
11259
11028
|
wrappedEmit = (e, isCheckout) => {
|
|
11260
11029
|
var _a;
|
|
11261
11030
|
if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
|
|
11262
|
-
e.type !== EventType
|
|
11263
|
-
!(e.type === EventType
|
|
11031
|
+
e.type !== EventType.FullSnapshot &&
|
|
11032
|
+
!(e.type === EventType.IncrementalSnapshot &&
|
|
11264
11033
|
e.data.source === IncrementalSource.Mutation)) {
|
|
11265
11034
|
mutationBuffers.forEach((buf) => buf.unfreeze());
|
|
11266
11035
|
}
|
|
11267
11036
|
emit(eventProcessor(e), isCheckout);
|
|
11268
|
-
if (e.type === EventType
|
|
11037
|
+
if (e.type === EventType.FullSnapshot) {
|
|
11269
11038
|
lastFullSnapshotEvent = e;
|
|
11270
11039
|
incrementalSnapshotCount = 0;
|
|
11271
11040
|
}
|
|
11272
|
-
else if (e.type === EventType
|
|
11041
|
+
else if (e.type === EventType.IncrementalSnapshot) {
|
|
11273
11042
|
if (e.data.source === IncrementalSource.Mutation &&
|
|
11274
11043
|
e.data.isAttachIframe) {
|
|
11275
11044
|
return;
|
|
@@ -11285,16 +11054,16 @@ function record(options = {}) {
|
|
|
11285
11054
|
};
|
|
11286
11055
|
const wrappedMutationEmit = (m) => {
|
|
11287
11056
|
wrappedEmit(wrapEvent({
|
|
11288
|
-
type: EventType
|
|
11057
|
+
type: EventType.IncrementalSnapshot,
|
|
11289
11058
|
data: Object.assign({ source: IncrementalSource.Mutation }, m),
|
|
11290
11059
|
}));
|
|
11291
11060
|
};
|
|
11292
11061
|
const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
|
|
11293
|
-
type: EventType
|
|
11062
|
+
type: EventType.IncrementalSnapshot,
|
|
11294
11063
|
data: Object.assign({ source: IncrementalSource.Scroll }, p),
|
|
11295
11064
|
}));
|
|
11296
11065
|
const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
|
|
11297
|
-
type: EventType
|
|
11066
|
+
type: EventType.IncrementalSnapshot,
|
|
11298
11067
|
data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
|
|
11299
11068
|
}));
|
|
11300
11069
|
const iframeManager = new IframeManager({
|
|
@@ -11339,7 +11108,7 @@ function record(options = {}) {
|
|
|
11339
11108
|
takeFullSnapshot = (isCheckout = false) => {
|
|
11340
11109
|
var _a, _b, _c, _d;
|
|
11341
11110
|
wrappedEmit(wrapEvent({
|
|
11342
|
-
type: EventType
|
|
11111
|
+
type: EventType.Meta,
|
|
11343
11112
|
data: {
|
|
11344
11113
|
href: window.location.href,
|
|
11345
11114
|
width: getWindowWidth(),
|
|
@@ -11382,7 +11151,7 @@ function record(options = {}) {
|
|
|
11382
11151
|
}
|
|
11383
11152
|
mirror.map = idNodeMap;
|
|
11384
11153
|
wrappedEmit(wrapEvent({
|
|
11385
|
-
type: EventType
|
|
11154
|
+
type: EventType.FullSnapshot,
|
|
11386
11155
|
data: {
|
|
11387
11156
|
node,
|
|
11388
11157
|
initialOffset: {
|
|
@@ -11407,7 +11176,7 @@ function record(options = {}) {
|
|
|
11407
11176
|
const handlers = [];
|
|
11408
11177
|
handlers.push(on$1('DOMContentLoaded', () => {
|
|
11409
11178
|
wrappedEmit(wrapEvent({
|
|
11410
|
-
type: EventType
|
|
11179
|
+
type: EventType.DomContentLoaded,
|
|
11411
11180
|
data: {},
|
|
11412
11181
|
}));
|
|
11413
11182
|
}));
|
|
@@ -11417,40 +11186,40 @@ function record(options = {}) {
|
|
|
11417
11186
|
onMutation,
|
|
11418
11187
|
mutationCb: wrappedMutationEmit,
|
|
11419
11188
|
mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
|
|
11420
|
-
type: EventType
|
|
11189
|
+
type: EventType.IncrementalSnapshot,
|
|
11421
11190
|
data: {
|
|
11422
11191
|
source,
|
|
11423
11192
|
positions,
|
|
11424
11193
|
},
|
|
11425
11194
|
})),
|
|
11426
11195
|
mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
|
|
11427
|
-
type: EventType
|
|
11196
|
+
type: EventType.IncrementalSnapshot,
|
|
11428
11197
|
data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
|
|
11429
11198
|
})),
|
|
11430
11199
|
scrollCb: wrappedScrollEmit,
|
|
11431
11200
|
viewportResizeCb: (d) => wrappedEmit(wrapEvent({
|
|
11432
|
-
type: EventType
|
|
11201
|
+
type: EventType.IncrementalSnapshot,
|
|
11433
11202
|
data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
|
|
11434
11203
|
})),
|
|
11435
11204
|
inputCb: (v) => wrappedEmit(wrapEvent({
|
|
11436
|
-
type: EventType
|
|
11205
|
+
type: EventType.IncrementalSnapshot,
|
|
11437
11206
|
data: Object.assign({ source: IncrementalSource.Input }, v),
|
|
11438
11207
|
})),
|
|
11439
11208
|
mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
|
|
11440
|
-
type: EventType
|
|
11209
|
+
type: EventType.IncrementalSnapshot,
|
|
11441
11210
|
data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
|
|
11442
11211
|
})),
|
|
11443
11212
|
styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
|
|
11444
|
-
type: EventType
|
|
11213
|
+
type: EventType.IncrementalSnapshot,
|
|
11445
11214
|
data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
|
|
11446
11215
|
})),
|
|
11447
11216
|
styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
|
|
11448
|
-
type: EventType
|
|
11217
|
+
type: EventType.IncrementalSnapshot,
|
|
11449
11218
|
data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
|
|
11450
11219
|
})),
|
|
11451
11220
|
canvasMutationCb: wrappedCanvasMutationEmit,
|
|
11452
11221
|
fontCb: (p) => wrappedEmit(wrapEvent({
|
|
11453
|
-
type: EventType
|
|
11222
|
+
type: EventType.IncrementalSnapshot,
|
|
11454
11223
|
data: Object.assign({ source: IncrementalSource.Font }, p),
|
|
11455
11224
|
})),
|
|
11456
11225
|
blockClass,
|
|
@@ -11483,7 +11252,7 @@ function record(options = {}) {
|
|
|
11483
11252
|
observer: p.observer,
|
|
11484
11253
|
options: p.options,
|
|
11485
11254
|
callback: (payload) => wrappedEmit(wrapEvent({
|
|
11486
|
-
type: EventType
|
|
11255
|
+
type: EventType.Plugin,
|
|
11487
11256
|
data: {
|
|
11488
11257
|
plugin: p.name,
|
|
11489
11258
|
payload,
|
|
@@ -11511,7 +11280,7 @@ function record(options = {}) {
|
|
|
11511
11280
|
else {
|
|
11512
11281
|
handlers.push(on$1('load', () => {
|
|
11513
11282
|
wrappedEmit(wrapEvent({
|
|
11514
|
-
type: EventType
|
|
11283
|
+
type: EventType.Load,
|
|
11515
11284
|
data: {},
|
|
11516
11285
|
}));
|
|
11517
11286
|
init();
|
|
@@ -11530,7 +11299,7 @@ record.addCustomEvent = (tag, payload) => {
|
|
|
11530
11299
|
throw new Error('please add custom event after start recording');
|
|
11531
11300
|
}
|
|
11532
11301
|
wrappedEmit(wrapEvent({
|
|
11533
|
-
type: EventType
|
|
11302
|
+
type: EventType.Custom,
|
|
11534
11303
|
data: {
|
|
11535
11304
|
tag,
|
|
11536
11305
|
payload,
|
|
@@ -11548,475 +11317,6 @@ record.takeFullSnapshot = (isCheckout) => {
|
|
|
11548
11317
|
};
|
|
11549
11318
|
record.mirror = mirror;
|
|
11550
11319
|
|
|
11551
|
-
/**
|
|
11552
|
-
* Create a breadcrumb for a replay.
|
|
11553
|
-
*/
|
|
11554
|
-
function createBreadcrumb(
|
|
11555
|
-
breadcrumb,
|
|
11556
|
-
) {
|
|
11557
|
-
return {
|
|
11558
|
-
timestamp: Date.now() / 1000,
|
|
11559
|
-
type: 'default',
|
|
11560
|
-
...breadcrumb,
|
|
11561
|
-
};
|
|
11562
|
-
}
|
|
11563
|
-
|
|
11564
|
-
var NodeType;
|
|
11565
|
-
(function (NodeType) {
|
|
11566
|
-
NodeType[NodeType["Document"] = 0] = "Document";
|
|
11567
|
-
NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
|
|
11568
|
-
NodeType[NodeType["Element"] = 2] = "Element";
|
|
11569
|
-
NodeType[NodeType["Text"] = 3] = "Text";
|
|
11570
|
-
NodeType[NodeType["CDATA"] = 4] = "CDATA";
|
|
11571
|
-
NodeType[NodeType["Comment"] = 5] = "Comment";
|
|
11572
|
-
})(NodeType || (NodeType = {}));
|
|
11573
|
-
|
|
11574
|
-
/**
|
|
11575
|
-
* Converts a timestamp to ms, if it was in s, or keeps it as ms.
|
|
11576
|
-
*/
|
|
11577
|
-
function timestampToMs(timestamp) {
|
|
11578
|
-
const isMs = timestamp > 9999999999;
|
|
11579
|
-
return isMs ? timestamp : timestamp * 1000;
|
|
11580
|
-
}
|
|
11581
|
-
|
|
11582
|
-
/**
|
|
11583
|
-
* Add an event to the event buffer.
|
|
11584
|
-
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
|
|
11585
|
-
*/
|
|
11586
|
-
async function addEvent(
|
|
11587
|
-
replay,
|
|
11588
|
-
event,
|
|
11589
|
-
isCheckout,
|
|
11590
|
-
) {
|
|
11591
|
-
if (!replay.eventBuffer) {
|
|
11592
|
-
// This implies that `_isEnabled` is false
|
|
11593
|
-
return null;
|
|
11594
|
-
}
|
|
11595
|
-
|
|
11596
|
-
if (replay.isPaused()) {
|
|
11597
|
-
// Do not add to event buffer when recording is paused
|
|
11598
|
-
return null;
|
|
11599
|
-
}
|
|
11600
|
-
|
|
11601
|
-
const timestampInMs = timestampToMs(event.timestamp);
|
|
11602
|
-
|
|
11603
|
-
// Throw out events that happen more than 5 minutes ago. This can happen if
|
|
11604
|
-
// page has been left open and idle for a long period of time and user
|
|
11605
|
-
// comes back to trigger a new session. The performance entries rely on
|
|
11606
|
-
// `performance.timeOrigin`, which is when the page first opened.
|
|
11607
|
-
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
11608
|
-
return null;
|
|
11609
|
-
}
|
|
11610
|
-
|
|
11611
|
-
try {
|
|
11612
|
-
if (isCheckout) {
|
|
11613
|
-
replay.eventBuffer.clear();
|
|
11614
|
-
}
|
|
11615
|
-
|
|
11616
|
-
return await replay.eventBuffer.addEvent(event);
|
|
11617
|
-
} catch (error) {
|
|
11618
|
-
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
|
|
11619
|
-
await replay.stop('addEvent');
|
|
11620
|
-
|
|
11621
|
-
const client = getCurrentHub().getClient();
|
|
11622
|
-
|
|
11623
|
-
if (client) {
|
|
11624
|
-
client.recordDroppedEvent('internal_sdk_error', 'replay');
|
|
11625
|
-
}
|
|
11626
|
-
}
|
|
11627
|
-
}
|
|
11628
|
-
|
|
11629
|
-
/**
|
|
11630
|
-
* Add a breadcrumb event to replay.
|
|
11631
|
-
*/
|
|
11632
|
-
function addBreadcrumbEvent(replay, breadcrumb) {
|
|
11633
|
-
if (breadcrumb.category === 'sentry.transaction') {
|
|
11634
|
-
return;
|
|
11635
|
-
}
|
|
11636
|
-
|
|
11637
|
-
if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
|
|
11638
|
-
replay.triggerUserActivity();
|
|
11639
|
-
} else {
|
|
11640
|
-
replay.checkAndHandleExpiredSession();
|
|
11641
|
-
}
|
|
11642
|
-
|
|
11643
|
-
replay.addUpdate(() => {
|
|
11644
|
-
void addEvent(replay, {
|
|
11645
|
-
type: EventType$1.Custom,
|
|
11646
|
-
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
|
|
11647
|
-
// but maybe we should just keep them as milliseconds
|
|
11648
|
-
timestamp: (breadcrumb.timestamp || 0) * 1000,
|
|
11649
|
-
data: {
|
|
11650
|
-
tag: 'breadcrumb',
|
|
11651
|
-
// normalize to max. 10 depth and 1_000 properties per object
|
|
11652
|
-
payload: normalize(breadcrumb, 10, 1000),
|
|
11653
|
-
},
|
|
11654
|
-
});
|
|
11655
|
-
|
|
11656
|
-
// Do not flush after console log messages
|
|
11657
|
-
return breadcrumb.category === 'console';
|
|
11658
|
-
});
|
|
11659
|
-
}
|
|
11660
|
-
|
|
11661
|
-
/**
|
|
11662
|
-
* Detect a slow click on a button/a tag,
|
|
11663
|
-
* and potentially create a corresponding breadcrumb.
|
|
11664
|
-
*/
|
|
11665
|
-
function detectSlowClick(
|
|
11666
|
-
replay,
|
|
11667
|
-
config,
|
|
11668
|
-
clickBreadcrumb,
|
|
11669
|
-
node,
|
|
11670
|
-
) {
|
|
11671
|
-
if (ignoreElement(node, config)) {
|
|
11672
|
-
return;
|
|
11673
|
-
}
|
|
11674
|
-
|
|
11675
|
-
/*
|
|
11676
|
-
We consider a slow click a click on a button/a, which does not trigger one of:
|
|
11677
|
-
- DOM mutation
|
|
11678
|
-
- Scroll (within 100ms)
|
|
11679
|
-
Within the given threshold time.
|
|
11680
|
-
After time timeout time, we stop listening and mark it as a slow click anyhow.
|
|
11681
|
-
*/
|
|
11682
|
-
|
|
11683
|
-
let cleanup = () => {
|
|
11684
|
-
// replaced further down
|
|
11685
|
-
};
|
|
11686
|
-
|
|
11687
|
-
// After timeout time, def. consider this a slow click, and stop watching for mutations
|
|
11688
|
-
const timeout = setTimeout(() => {
|
|
11689
|
-
handleSlowClick(replay, clickBreadcrumb, config.timeout, 'timeout');
|
|
11690
|
-
cleanup();
|
|
11691
|
-
}, config.timeout);
|
|
11692
|
-
|
|
11693
|
-
const mutationHandler = () => {
|
|
11694
|
-
maybeHandleSlowClick(replay, clickBreadcrumb, config.threshold, config.timeout, 'mutation');
|
|
11695
|
-
cleanup();
|
|
11696
|
-
};
|
|
11697
|
-
|
|
11698
|
-
const scrollHandler = () => {
|
|
11699
|
-
maybeHandleSlowClick(replay, clickBreadcrumb, config.scrollTimeout, config.timeout, 'scroll');
|
|
11700
|
-
cleanup();
|
|
11701
|
-
};
|
|
11702
|
-
|
|
11703
|
-
const obs = new MutationObserver(mutationHandler);
|
|
11704
|
-
|
|
11705
|
-
obs.observe(WINDOW.document.documentElement, {
|
|
11706
|
-
attributes: true,
|
|
11707
|
-
characterData: true,
|
|
11708
|
-
childList: true,
|
|
11709
|
-
subtree: true,
|
|
11710
|
-
});
|
|
11711
|
-
|
|
11712
|
-
WINDOW.addEventListener('scroll', scrollHandler);
|
|
11713
|
-
|
|
11714
|
-
// Stop listening to scroll timeouts early
|
|
11715
|
-
const scrollTimeout = setTimeout(() => {
|
|
11716
|
-
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
11717
|
-
}, config.scrollTimeout);
|
|
11718
|
-
|
|
11719
|
-
cleanup = () => {
|
|
11720
|
-
clearTimeout(timeout);
|
|
11721
|
-
clearTimeout(scrollTimeout);
|
|
11722
|
-
obs.disconnect();
|
|
11723
|
-
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
11724
|
-
};
|
|
11725
|
-
}
|
|
11726
|
-
|
|
11727
|
-
function maybeHandleSlowClick(
|
|
11728
|
-
replay,
|
|
11729
|
-
clickBreadcrumb,
|
|
11730
|
-
threshold,
|
|
11731
|
-
timeout,
|
|
11732
|
-
endReason,
|
|
11733
|
-
) {
|
|
11734
|
-
const now = Date.now();
|
|
11735
|
-
const timeAfterClickMs = now - clickBreadcrumb.timestamp * 1000;
|
|
11736
|
-
|
|
11737
|
-
if (timeAfterClickMs > threshold) {
|
|
11738
|
-
handleSlowClick(replay, clickBreadcrumb, Math.min(timeAfterClickMs, timeout), endReason);
|
|
11739
|
-
return true;
|
|
11740
|
-
}
|
|
11741
|
-
|
|
11742
|
-
return false;
|
|
11743
|
-
}
|
|
11744
|
-
|
|
11745
|
-
function handleSlowClick(
|
|
11746
|
-
replay,
|
|
11747
|
-
clickBreadcrumb,
|
|
11748
|
-
timeAfterClickMs,
|
|
11749
|
-
endReason,
|
|
11750
|
-
) {
|
|
11751
|
-
const breadcrumb = {
|
|
11752
|
-
message: clickBreadcrumb.message,
|
|
11753
|
-
timestamp: clickBreadcrumb.timestamp,
|
|
11754
|
-
category: 'ui.slowClickDetected',
|
|
11755
|
-
data: {
|
|
11756
|
-
...clickBreadcrumb.data,
|
|
11757
|
-
url: WINDOW.location.href,
|
|
11758
|
-
// TODO FN: add parametrized route, when possible
|
|
11759
|
-
timeAfterClickMs,
|
|
11760
|
-
endReason,
|
|
11761
|
-
},
|
|
11762
|
-
};
|
|
11763
|
-
|
|
11764
|
-
addBreadcrumbEvent(replay, breadcrumb);
|
|
11765
|
-
}
|
|
11766
|
-
|
|
11767
|
-
const SLOW_CLICK_IGNORE_TAGS = ['SELECT', 'OPTION'];
|
|
11768
|
-
|
|
11769
|
-
function ignoreElement(node, config) {
|
|
11770
|
-
// If <input> tag, we only want to consider input[type='submit'] & input[type='button']
|
|
11771
|
-
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
|
|
11772
|
-
return true;
|
|
11773
|
-
}
|
|
11774
|
-
|
|
11775
|
-
if (SLOW_CLICK_IGNORE_TAGS.includes(node.tagName)) {
|
|
11776
|
-
return true;
|
|
11777
|
-
}
|
|
11778
|
-
|
|
11779
|
-
// If <a> tag, detect special variants that may not lead to an action
|
|
11780
|
-
// If target !== _self, we may open the link somewhere else, which would lead to no action
|
|
11781
|
-
// Also, when downloading a file, we may not leave the page, but still not trigger an action
|
|
11782
|
-
if (
|
|
11783
|
-
node.tagName === 'A' &&
|
|
11784
|
-
(node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
|
|
11785
|
-
) {
|
|
11786
|
-
return true;
|
|
11787
|
-
}
|
|
11788
|
-
|
|
11789
|
-
if (config.ignoreSelector && node.matches(config.ignoreSelector)) {
|
|
11790
|
-
return true;
|
|
11791
|
-
}
|
|
11792
|
-
|
|
11793
|
-
return false;
|
|
11794
|
-
}
|
|
11795
|
-
|
|
11796
|
-
// Note that these are the serialized attributes and not attributes directly on
|
|
11797
|
-
// the DOM Node. Attributes we are interested in:
|
|
11798
|
-
const ATTRIBUTES_TO_RECORD = new Set([
|
|
11799
|
-
'id',
|
|
11800
|
-
'class',
|
|
11801
|
-
'aria-label',
|
|
11802
|
-
'role',
|
|
11803
|
-
'name',
|
|
11804
|
-
'alt',
|
|
11805
|
-
'title',
|
|
11806
|
-
'data-test-id',
|
|
11807
|
-
'data-testid',
|
|
11808
|
-
]);
|
|
11809
|
-
|
|
11810
|
-
/**
|
|
11811
|
-
* Inclusion list of attributes that we want to record from the DOM element
|
|
11812
|
-
*/
|
|
11813
|
-
function getAttributesToRecord(attributes) {
|
|
11814
|
-
const obj = {};
|
|
11815
|
-
for (const key in attributes) {
|
|
11816
|
-
if (ATTRIBUTES_TO_RECORD.has(key)) {
|
|
11817
|
-
let normalizedKey = key;
|
|
11818
|
-
|
|
11819
|
-
if (key === 'data-testid' || key === 'data-test-id') {
|
|
11820
|
-
normalizedKey = 'testId';
|
|
11821
|
-
}
|
|
11822
|
-
|
|
11823
|
-
obj[normalizedKey] = attributes[key];
|
|
11824
|
-
}
|
|
11825
|
-
}
|
|
11826
|
-
|
|
11827
|
-
return obj;
|
|
11828
|
-
}
|
|
11829
|
-
|
|
11830
|
-
const handleDomListener = (
|
|
11831
|
-
replay,
|
|
11832
|
-
) => {
|
|
11833
|
-
const slowClickExperiment = replay.getOptions()._experiments.slowClicks;
|
|
11834
|
-
|
|
11835
|
-
const slowClickConfig = slowClickExperiment
|
|
11836
|
-
? {
|
|
11837
|
-
threshold: slowClickExperiment.threshold,
|
|
11838
|
-
timeout: slowClickExperiment.timeout,
|
|
11839
|
-
scrollTimeout: slowClickExperiment.scrollTimeout,
|
|
11840
|
-
ignoreSelector: slowClickExperiment.ignoreSelectors ? slowClickExperiment.ignoreSelectors.join(',') : '',
|
|
11841
|
-
}
|
|
11842
|
-
: undefined;
|
|
11843
|
-
|
|
11844
|
-
return (handlerData) => {
|
|
11845
|
-
if (!replay.isEnabled()) {
|
|
11846
|
-
return;
|
|
11847
|
-
}
|
|
11848
|
-
|
|
11849
|
-
const result = handleDom(handlerData);
|
|
11850
|
-
|
|
11851
|
-
if (!result) {
|
|
11852
|
-
return;
|
|
11853
|
-
}
|
|
11854
|
-
|
|
11855
|
-
const isClick = handlerData.name === 'click';
|
|
11856
|
-
const event = isClick && (handlerData.event );
|
|
11857
|
-
// Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
|
|
11858
|
-
if (isClick && slowClickConfig && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
|
|
11859
|
-
detectSlowClick(
|
|
11860
|
-
replay,
|
|
11861
|
-
slowClickConfig,
|
|
11862
|
-
result ,
|
|
11863
|
-
getClickTargetNode(handlerData.event) ,
|
|
11864
|
-
);
|
|
11865
|
-
}
|
|
11866
|
-
|
|
11867
|
-
addBreadcrumbEvent(replay, result);
|
|
11868
|
-
};
|
|
11869
|
-
};
|
|
11870
|
-
|
|
11871
|
-
/** Get the base DOM breadcrumb. */
|
|
11872
|
-
function getBaseDomBreadcrumb(target, message) {
|
|
11873
|
-
// `__sn` property is the serialized node created by rrweb
|
|
11874
|
-
const serializedNode = target && isRrwebNode(target) && target.__sn.type === NodeType.Element ? target.__sn : null;
|
|
11875
|
-
|
|
11876
|
-
return {
|
|
11877
|
-
message,
|
|
11878
|
-
data: serializedNode
|
|
11879
|
-
? {
|
|
11880
|
-
nodeId: serializedNode.id,
|
|
11881
|
-
node: {
|
|
11882
|
-
id: serializedNode.id,
|
|
11883
|
-
tagName: serializedNode.tagName,
|
|
11884
|
-
textContent: target
|
|
11885
|
-
? Array.from(target.childNodes)
|
|
11886
|
-
.map(
|
|
11887
|
-
(node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
|
|
11888
|
-
)
|
|
11889
|
-
.filter(Boolean) // filter out empty values
|
|
11890
|
-
.map(text => (text ).trim())
|
|
11891
|
-
.join('')
|
|
11892
|
-
: '',
|
|
11893
|
-
attributes: getAttributesToRecord(serializedNode.attributes),
|
|
11894
|
-
},
|
|
11895
|
-
}
|
|
11896
|
-
: {},
|
|
11897
|
-
};
|
|
11898
|
-
}
|
|
11899
|
-
|
|
11900
|
-
/**
|
|
11901
|
-
* An event handler to react to DOM events.
|
|
11902
|
-
* Exported for tests.
|
|
11903
|
-
*/
|
|
11904
|
-
function handleDom(handlerData) {
|
|
11905
|
-
const { target, message } = getDomTarget(handlerData);
|
|
11906
|
-
|
|
11907
|
-
return createBreadcrumb({
|
|
11908
|
-
category: `ui.${handlerData.name}`,
|
|
11909
|
-
...getBaseDomBreadcrumb(target, message),
|
|
11910
|
-
});
|
|
11911
|
-
}
|
|
11912
|
-
|
|
11913
|
-
function getDomTarget(handlerData) {
|
|
11914
|
-
const isClick = handlerData.name === 'click';
|
|
11915
|
-
|
|
11916
|
-
let message;
|
|
11917
|
-
let target = null;
|
|
11918
|
-
|
|
11919
|
-
// Accessing event.target can throw (see getsentry/raven-js#838, #768)
|
|
11920
|
-
try {
|
|
11921
|
-
target = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
|
|
11922
|
-
message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
|
|
11923
|
-
} catch (e) {
|
|
11924
|
-
message = '<unknown>';
|
|
11925
|
-
}
|
|
11926
|
-
|
|
11927
|
-
return { target, message };
|
|
11928
|
-
}
|
|
11929
|
-
|
|
11930
|
-
function isRrwebNode(node) {
|
|
11931
|
-
return '__sn' in node;
|
|
11932
|
-
}
|
|
11933
|
-
|
|
11934
|
-
function getTargetNode(event) {
|
|
11935
|
-
if (isEventWithTarget(event)) {
|
|
11936
|
-
return event.target ;
|
|
11937
|
-
}
|
|
11938
|
-
|
|
11939
|
-
return event;
|
|
11940
|
-
}
|
|
11941
|
-
|
|
11942
|
-
const INTERACTIVE_SELECTOR = 'button,a';
|
|
11943
|
-
|
|
11944
|
-
// For clicks, we check if the target is inside of a button or link
|
|
11945
|
-
// If so, we use this as the target instead
|
|
11946
|
-
// This is useful because if you click on the image in <button><img></button>,
|
|
11947
|
-
// The target will be the image, not the button, which we don't want here
|
|
11948
|
-
function getClickTargetNode(event) {
|
|
11949
|
-
const target = getTargetNode(event);
|
|
11950
|
-
|
|
11951
|
-
if (!target || !(target instanceof Element)) {
|
|
11952
|
-
return target;
|
|
11953
|
-
}
|
|
11954
|
-
|
|
11955
|
-
const closestInteractive = target.closest(INTERACTIVE_SELECTOR);
|
|
11956
|
-
return closestInteractive || target;
|
|
11957
|
-
}
|
|
11958
|
-
|
|
11959
|
-
function isEventWithTarget(event) {
|
|
11960
|
-
return typeof event === 'object' && !!event && 'target' in event;
|
|
11961
|
-
}
|
|
11962
|
-
|
|
11963
|
-
/** Handle keyboard events & create breadcrumbs. */
|
|
11964
|
-
function handleKeyboardEvent(replay, event) {
|
|
11965
|
-
if (!replay.isEnabled()) {
|
|
11966
|
-
return;
|
|
11967
|
-
}
|
|
11968
|
-
|
|
11969
|
-
replay.triggerUserActivity();
|
|
11970
|
-
|
|
11971
|
-
const breadcrumb = getKeyboardBreadcrumb(event);
|
|
11972
|
-
|
|
11973
|
-
if (!breadcrumb) {
|
|
11974
|
-
return;
|
|
11975
|
-
}
|
|
11976
|
-
|
|
11977
|
-
addBreadcrumbEvent(replay, breadcrumb);
|
|
11978
|
-
}
|
|
11979
|
-
|
|
11980
|
-
/** exported only for tests */
|
|
11981
|
-
function getKeyboardBreadcrumb(event) {
|
|
11982
|
-
const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event;
|
|
11983
|
-
|
|
11984
|
-
// never capture for input fields
|
|
11985
|
-
if (!target || isInputElement(target )) {
|
|
11986
|
-
return null;
|
|
11987
|
-
}
|
|
11988
|
-
|
|
11989
|
-
// Note: We do not consider shift here, as that means "uppercase"
|
|
11990
|
-
const hasModifierKey = metaKey || ctrlKey || altKey;
|
|
11991
|
-
const isCharacterKey = key.length === 1; // other keys like Escape, Tab, etc have a longer length
|
|
11992
|
-
|
|
11993
|
-
// Do not capture breadcrumb if only a word key is pressed
|
|
11994
|
-
// This could leak e.g. user input
|
|
11995
|
-
if (!hasModifierKey && isCharacterKey) {
|
|
11996
|
-
return null;
|
|
11997
|
-
}
|
|
11998
|
-
|
|
11999
|
-
const message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
|
|
12000
|
-
const baseBreadcrumb = getBaseDomBreadcrumb(target , message);
|
|
12001
|
-
|
|
12002
|
-
return createBreadcrumb({
|
|
12003
|
-
category: 'ui.keyDown',
|
|
12004
|
-
message,
|
|
12005
|
-
data: {
|
|
12006
|
-
...baseBreadcrumb.data,
|
|
12007
|
-
metaKey,
|
|
12008
|
-
shiftKey,
|
|
12009
|
-
ctrlKey,
|
|
12010
|
-
altKey,
|
|
12011
|
-
key,
|
|
12012
|
-
},
|
|
12013
|
-
});
|
|
12014
|
-
}
|
|
12015
|
-
|
|
12016
|
-
function isInputElement(target) {
|
|
12017
|
-
return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
|
|
12018
|
-
}
|
|
12019
|
-
|
|
12020
11320
|
const NAVIGATION_ENTRY_KEYS = [
|
|
12021
11321
|
'name',
|
|
12022
11322
|
'type',
|
|
@@ -12170,19 +11470,20 @@ class EventBufferArray {
|
|
|
12170
11470
|
return this.events.length > 0;
|
|
12171
11471
|
}
|
|
12172
11472
|
|
|
12173
|
-
/** @inheritdoc */
|
|
12174
|
-
get type() {
|
|
12175
|
-
return 'sync';
|
|
12176
|
-
}
|
|
12177
|
-
|
|
12178
11473
|
/** @inheritdoc */
|
|
12179
11474
|
destroy() {
|
|
12180
11475
|
this.events = [];
|
|
12181
11476
|
}
|
|
12182
11477
|
|
|
12183
11478
|
/** @inheritdoc */
|
|
12184
|
-
async addEvent(event) {
|
|
11479
|
+
async addEvent(event, isCheckout) {
|
|
11480
|
+
if (isCheckout) {
|
|
11481
|
+
this.events = [event];
|
|
11482
|
+
return;
|
|
11483
|
+
}
|
|
11484
|
+
|
|
12185
11485
|
this.events.push(event);
|
|
11486
|
+
return;
|
|
12186
11487
|
}
|
|
12187
11488
|
|
|
12188
11489
|
/** @inheritdoc */
|
|
@@ -12196,22 +11497,6 @@ class EventBufferArray {
|
|
|
12196
11497
|
resolve(JSON.stringify(eventsRet));
|
|
12197
11498
|
});
|
|
12198
11499
|
}
|
|
12199
|
-
|
|
12200
|
-
/** @inheritdoc */
|
|
12201
|
-
clear() {
|
|
12202
|
-
this.events = [];
|
|
12203
|
-
}
|
|
12204
|
-
|
|
12205
|
-
/** @inheritdoc */
|
|
12206
|
-
getEarliestTimestamp() {
|
|
12207
|
-
const timestamp = this.events.map(event => event.timestamp).sort()[0];
|
|
12208
|
-
|
|
12209
|
-
if (!timestamp) {
|
|
12210
|
-
return null;
|
|
12211
|
-
}
|
|
12212
|
-
|
|
12213
|
-
return timestampToMs(timestamp);
|
|
12214
|
-
}
|
|
12215
11500
|
}
|
|
12216
11501
|
|
|
12217
11502
|
/**
|
|
@@ -12319,20 +11604,11 @@ class WorkerHandler {
|
|
|
12319
11604
|
* Exported only for testing.
|
|
12320
11605
|
*/
|
|
12321
11606
|
class EventBufferCompressionWorker {
|
|
11607
|
+
/** @inheritdoc */
|
|
12322
11608
|
|
|
12323
11609
|
constructor(worker) {
|
|
12324
11610
|
this._worker = new WorkerHandler(worker);
|
|
12325
|
-
this.
|
|
12326
|
-
}
|
|
12327
|
-
|
|
12328
|
-
/** @inheritdoc */
|
|
12329
|
-
get hasEvents() {
|
|
12330
|
-
return !!this._earliestTimestamp;
|
|
12331
|
-
}
|
|
12332
|
-
|
|
12333
|
-
/** @inheritdoc */
|
|
12334
|
-
get type() {
|
|
12335
|
-
return 'worker';
|
|
11611
|
+
this.hasEvents = false;
|
|
12336
11612
|
}
|
|
12337
11613
|
|
|
12338
11614
|
/**
|
|
@@ -12355,10 +11631,13 @@ class EventBufferCompressionWorker {
|
|
|
12355
11631
|
*
|
|
12356
11632
|
* Returns true if event was successfuly received and processed by worker.
|
|
12357
11633
|
*/
|
|
12358
|
-
addEvent(event) {
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
11634
|
+
async addEvent(event, isCheckout) {
|
|
11635
|
+
this.hasEvents = true;
|
|
11636
|
+
|
|
11637
|
+
if (isCheckout) {
|
|
11638
|
+
// This event is a checkout, make sure worker buffer is cleared before
|
|
11639
|
+
// proceeding.
|
|
11640
|
+
await this._clear();
|
|
12362
11641
|
}
|
|
12363
11642
|
|
|
12364
11643
|
return this._sendEventToWorker(event);
|
|
@@ -12371,18 +11650,6 @@ class EventBufferCompressionWorker {
|
|
|
12371
11650
|
return this._finishRequest();
|
|
12372
11651
|
}
|
|
12373
11652
|
|
|
12374
|
-
/** @inheritdoc */
|
|
12375
|
-
clear() {
|
|
12376
|
-
this._earliestTimestamp = null;
|
|
12377
|
-
// We do not wait on this, as we assume the order of messages is consistent for the worker
|
|
12378
|
-
void this._worker.postMessage('clear');
|
|
12379
|
-
}
|
|
12380
|
-
|
|
12381
|
-
/** @inheritdoc */
|
|
12382
|
-
getEarliestTimestamp() {
|
|
12383
|
-
return this._earliestTimestamp;
|
|
12384
|
-
}
|
|
12385
|
-
|
|
12386
11653
|
/**
|
|
12387
11654
|
* Send the event to the worker.
|
|
12388
11655
|
*/
|
|
@@ -12396,10 +11663,15 @@ class EventBufferCompressionWorker {
|
|
|
12396
11663
|
async _finishRequest() {
|
|
12397
11664
|
const response = await this._worker.postMessage('finish');
|
|
12398
11665
|
|
|
12399
|
-
this.
|
|
11666
|
+
this.hasEvents = false;
|
|
12400
11667
|
|
|
12401
11668
|
return response;
|
|
12402
11669
|
}
|
|
11670
|
+
|
|
11671
|
+
/** Clear any pending events from the worker. */
|
|
11672
|
+
_clear() {
|
|
11673
|
+
return this._worker.postMessage('clear');
|
|
11674
|
+
}
|
|
12403
11675
|
}
|
|
12404
11676
|
|
|
12405
11677
|
/**
|
|
@@ -12417,11 +11689,6 @@ class EventBufferProxy {
|
|
|
12417
11689
|
this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded();
|
|
12418
11690
|
}
|
|
12419
11691
|
|
|
12420
|
-
/** @inheritdoc */
|
|
12421
|
-
get type() {
|
|
12422
|
-
return this._used.type;
|
|
12423
|
-
}
|
|
12424
|
-
|
|
12425
11692
|
/** @inheritDoc */
|
|
12426
11693
|
get hasEvents() {
|
|
12427
11694
|
return this._used.hasEvents;
|
|
@@ -12433,23 +11700,13 @@ class EventBufferProxy {
|
|
|
12433
11700
|
this._compression.destroy();
|
|
12434
11701
|
}
|
|
12435
11702
|
|
|
12436
|
-
/** @inheritdoc */
|
|
12437
|
-
clear() {
|
|
12438
|
-
return this._used.clear();
|
|
12439
|
-
}
|
|
12440
|
-
|
|
12441
|
-
/** @inheritdoc */
|
|
12442
|
-
getEarliestTimestamp() {
|
|
12443
|
-
return this._used.getEarliestTimestamp();
|
|
12444
|
-
}
|
|
12445
|
-
|
|
12446
11703
|
/**
|
|
12447
11704
|
* Add an event to the event buffer.
|
|
12448
11705
|
*
|
|
12449
11706
|
* Returns true if event was successfully added.
|
|
12450
11707
|
*/
|
|
12451
|
-
addEvent(event) {
|
|
12452
|
-
return this._used.addEvent(event);
|
|
11708
|
+
addEvent(event, isCheckout) {
|
|
11709
|
+
return this._used.addEvent(event, isCheckout);
|
|
12453
11710
|
}
|
|
12454
11711
|
|
|
12455
11712
|
/** @inheritDoc */
|
|
@@ -12524,31 +11781,6 @@ function createEventBuffer({ useCompression }) {
|
|
|
12524
11781
|
return new EventBufferArray();
|
|
12525
11782
|
}
|
|
12526
11783
|
|
|
12527
|
-
/**
|
|
12528
|
-
* Removes the session from Session Storage and unsets session in replay instance
|
|
12529
|
-
*/
|
|
12530
|
-
function clearSession(replay) {
|
|
12531
|
-
deleteSession();
|
|
12532
|
-
replay.session = undefined;
|
|
12533
|
-
}
|
|
12534
|
-
|
|
12535
|
-
/**
|
|
12536
|
-
* Deletes a session from storage
|
|
12537
|
-
*/
|
|
12538
|
-
function deleteSession() {
|
|
12539
|
-
const hasSessionStorage = 'sessionStorage' in WINDOW;
|
|
12540
|
-
|
|
12541
|
-
if (!hasSessionStorage) {
|
|
12542
|
-
return;
|
|
12543
|
-
}
|
|
12544
|
-
|
|
12545
|
-
try {
|
|
12546
|
-
WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
|
|
12547
|
-
} catch (e) {
|
|
12548
|
-
// Ignore potential SecurityError exceptions
|
|
12549
|
-
}
|
|
12550
|
-
}
|
|
12551
|
-
|
|
12552
11784
|
/**
|
|
12553
11785
|
* Given an initial timestamp and an expiry duration, checks to see if current
|
|
12554
11786
|
* time should be considered as expired.
|
|
@@ -12579,26 +11811,11 @@ function isSessionExpired(session, timeouts, targetTime = +new Date()) {
|
|
|
12579
11811
|
// First, check that maximum session length has not been exceeded
|
|
12580
11812
|
isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
|
|
12581
11813
|
// check that the idle timeout has not been exceeded (i.e. user has
|
|
12582
|
-
// performed an action within the last `
|
|
12583
|
-
isExpired(session.lastActivity, timeouts.
|
|
11814
|
+
// performed an action within the last `idleTimeout` ms)
|
|
11815
|
+
isExpired(session.lastActivity, timeouts.sessionIdle, targetTime)
|
|
12584
11816
|
);
|
|
12585
11817
|
}
|
|
12586
11818
|
|
|
12587
|
-
/**
|
|
12588
|
-
* Given a sample rate, returns true if replay should be sampled.
|
|
12589
|
-
*
|
|
12590
|
-
* 1.0 = 100% sampling
|
|
12591
|
-
* 0.0 = 0% sampling
|
|
12592
|
-
*/
|
|
12593
|
-
function isSampled(sampleRate) {
|
|
12594
|
-
if (sampleRate === undefined) {
|
|
12595
|
-
return false;
|
|
12596
|
-
}
|
|
12597
|
-
|
|
12598
|
-
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12599
|
-
return Math.random() < sampleRate;
|
|
12600
|
-
}
|
|
12601
|
-
|
|
12602
11819
|
/**
|
|
12603
11820
|
* Save a session to session storage.
|
|
12604
11821
|
*/
|
|
@@ -12615,6 +11832,21 @@ function saveSession(session) {
|
|
|
12615
11832
|
}
|
|
12616
11833
|
}
|
|
12617
11834
|
|
|
11835
|
+
/**
|
|
11836
|
+
* Given a sample rate, returns true if replay should be sampled.
|
|
11837
|
+
*
|
|
11838
|
+
* 1.0 = 100% sampling
|
|
11839
|
+
* 0.0 = 0% sampling
|
|
11840
|
+
*/
|
|
11841
|
+
function isSampled(sampleRate) {
|
|
11842
|
+
if (sampleRate === undefined) {
|
|
11843
|
+
return false;
|
|
11844
|
+
}
|
|
11845
|
+
|
|
11846
|
+
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
11847
|
+
return Math.random() < sampleRate;
|
|
11848
|
+
}
|
|
11849
|
+
|
|
12618
11850
|
/**
|
|
12619
11851
|
* Get a session with defaults & applied sampling.
|
|
12620
11852
|
*/
|
|
@@ -12633,15 +11865,14 @@ function makeSession(session) {
|
|
|
12633
11865
|
lastActivity,
|
|
12634
11866
|
segmentId,
|
|
12635
11867
|
sampled,
|
|
12636
|
-
shouldRefresh: true,
|
|
12637
11868
|
};
|
|
12638
11869
|
}
|
|
12639
11870
|
|
|
12640
11871
|
/**
|
|
12641
11872
|
* Get the sampled status for a session based on sample rates & current sampled status.
|
|
12642
11873
|
*/
|
|
12643
|
-
function getSessionSampleType(sessionSampleRate,
|
|
12644
|
-
return isSampled(sessionSampleRate) ? 'session' :
|
|
11874
|
+
function getSessionSampleType(sessionSampleRate, errorSampleRate) {
|
|
11875
|
+
return isSampled(sessionSampleRate) ? 'session' : isSampled(errorSampleRate) ? 'error' : false;
|
|
12645
11876
|
}
|
|
12646
11877
|
|
|
12647
11878
|
/**
|
|
@@ -12649,8 +11880,8 @@ function getSessionSampleType(sessionSampleRate, allowBuffering) {
|
|
|
12649
11880
|
* that all replays will be saved to as attachments. Currently, we only expect
|
|
12650
11881
|
* one of these Sentry events per "replay session".
|
|
12651
11882
|
*/
|
|
12652
|
-
function createSession({ sessionSampleRate,
|
|
12653
|
-
const sampled = getSessionSampleType(sessionSampleRate,
|
|
11883
|
+
function createSession({ sessionSampleRate, errorSampleRate, stickySession = false }) {
|
|
11884
|
+
const sampled = getSessionSampleType(sessionSampleRate, errorSampleRate);
|
|
12654
11885
|
const session = makeSession({
|
|
12655
11886
|
sampled,
|
|
12656
11887
|
});
|
|
@@ -12698,7 +11929,7 @@ function getSession({
|
|
|
12698
11929
|
currentSession,
|
|
12699
11930
|
stickySession,
|
|
12700
11931
|
sessionSampleRate,
|
|
12701
|
-
|
|
11932
|
+
errorSampleRate,
|
|
12702
11933
|
}) {
|
|
12703
11934
|
// If session exists and is passed, use it instead of always hitting session storage
|
|
12704
11935
|
const session = currentSession || (stickySession && fetchSession());
|
|
@@ -12711,9 +11942,8 @@ function getSession({
|
|
|
12711
11942
|
|
|
12712
11943
|
if (!isExpired) {
|
|
12713
11944
|
return { type: 'saved', session };
|
|
12714
|
-
} else if (
|
|
12715
|
-
//
|
|
12716
|
-
// This is the case if we have an error session that is completed (=triggered an error)
|
|
11945
|
+
} else if (session.sampled === 'error') {
|
|
11946
|
+
// Error samples should not be re-created when expired, but instead we stop when the replay is done
|
|
12717
11947
|
const discardedSession = makeSession({ sampled: false });
|
|
12718
11948
|
return { type: 'new', session: discardedSession };
|
|
12719
11949
|
} else {
|
|
@@ -12725,12 +11955,65 @@ function getSession({
|
|
|
12725
11955
|
const newSession = createSession({
|
|
12726
11956
|
stickySession,
|
|
12727
11957
|
sessionSampleRate,
|
|
12728
|
-
|
|
11958
|
+
errorSampleRate,
|
|
12729
11959
|
});
|
|
12730
11960
|
|
|
12731
11961
|
return { type: 'new', session: newSession };
|
|
12732
11962
|
}
|
|
12733
11963
|
|
|
11964
|
+
/**
|
|
11965
|
+
* Add an event to the event buffer.
|
|
11966
|
+
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
|
|
11967
|
+
*/
|
|
11968
|
+
async function addEvent(
|
|
11969
|
+
replay,
|
|
11970
|
+
event,
|
|
11971
|
+
isCheckout,
|
|
11972
|
+
) {
|
|
11973
|
+
if (!replay.eventBuffer) {
|
|
11974
|
+
// This implies that `_isEnabled` is false
|
|
11975
|
+
return null;
|
|
11976
|
+
}
|
|
11977
|
+
|
|
11978
|
+
if (replay.isPaused()) {
|
|
11979
|
+
// Do not add to event buffer when recording is paused
|
|
11980
|
+
return null;
|
|
11981
|
+
}
|
|
11982
|
+
|
|
11983
|
+
// TODO: sadness -- we will want to normalize timestamps to be in ms -
|
|
11984
|
+
// requires coordination with frontend
|
|
11985
|
+
const isMs = event.timestamp > 9999999999;
|
|
11986
|
+
const timestampInMs = isMs ? event.timestamp : event.timestamp * 1000;
|
|
11987
|
+
|
|
11988
|
+
// Throw out events that happen more than 5 minutes ago. This can happen if
|
|
11989
|
+
// page has been left open and idle for a long period of time and user
|
|
11990
|
+
// comes back to trigger a new session. The performance entries rely on
|
|
11991
|
+
// `performance.timeOrigin`, which is when the page first opened.
|
|
11992
|
+
if (timestampInMs + replay.timeouts.sessionIdle < Date.now()) {
|
|
11993
|
+
return null;
|
|
11994
|
+
}
|
|
11995
|
+
|
|
11996
|
+
// Only record earliest event if a new session was created, otherwise it
|
|
11997
|
+
// shouldn't be relevant
|
|
11998
|
+
const earliestEvent = replay.getContext().earliestEvent;
|
|
11999
|
+
if (replay.session && replay.session.segmentId === 0 && (!earliestEvent || timestampInMs < earliestEvent)) {
|
|
12000
|
+
replay.getContext().earliestEvent = timestampInMs;
|
|
12001
|
+
}
|
|
12002
|
+
|
|
12003
|
+
try {
|
|
12004
|
+
return await replay.eventBuffer.addEvent(event, isCheckout);
|
|
12005
|
+
} catch (error) {
|
|
12006
|
+
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
|
|
12007
|
+
replay.stop('addEvent');
|
|
12008
|
+
|
|
12009
|
+
const client = getCurrentHub().getClient();
|
|
12010
|
+
|
|
12011
|
+
if (client) {
|
|
12012
|
+
client.recordDroppedEvent('internal_sdk_error', 'replay');
|
|
12013
|
+
}
|
|
12014
|
+
}
|
|
12015
|
+
}
|
|
12016
|
+
|
|
12734
12017
|
/** If the event is an error event */
|
|
12735
12018
|
function isErrorEvent(event) {
|
|
12736
12019
|
return !event.type;
|
|
@@ -12780,21 +12063,31 @@ function handleAfterSendEvent(replay) {
|
|
|
12780
12063
|
return;
|
|
12781
12064
|
}
|
|
12782
12065
|
|
|
12783
|
-
// Add error to list of errorIds of replay
|
|
12784
|
-
// sampled because context will get reset at next checkout.
|
|
12785
|
-
// XXX: There is also a race condition where it's possible to capture an
|
|
12786
|
-
// error to Sentry before Replay SDK has loaded, but response returns after
|
|
12787
|
-
// it was loaded, and this gets called.
|
|
12066
|
+
// Add error to list of errorIds of replay
|
|
12788
12067
|
if (event.event_id) {
|
|
12789
12068
|
replay.getContext().errorIds.add(event.event_id);
|
|
12790
12069
|
}
|
|
12791
12070
|
|
|
12792
|
-
//
|
|
12071
|
+
// Trigger error recording
|
|
12793
12072
|
// Need to be very careful that this does not cause an infinite loop
|
|
12794
|
-
if (
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12073
|
+
if (
|
|
12074
|
+
replay.recordingMode === 'error' &&
|
|
12075
|
+
event.exception &&
|
|
12076
|
+
event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing
|
|
12077
|
+
) {
|
|
12078
|
+
setTimeout(async () => {
|
|
12079
|
+
// Allow flush to complete before resuming as a session recording, otherwise
|
|
12080
|
+
// the checkout from `startRecording` may be included in the payload.
|
|
12081
|
+
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
12082
|
+
// than the session replay.
|
|
12083
|
+
await replay.flushImmediate();
|
|
12084
|
+
|
|
12085
|
+
if (replay.stopRecording()) {
|
|
12086
|
+
// Reset all "capture on error" configuration before
|
|
12087
|
+
// starting a new recording
|
|
12088
|
+
replay.recordingMode = 'session';
|
|
12089
|
+
replay.startRecording();
|
|
12090
|
+
}
|
|
12798
12091
|
});
|
|
12799
12092
|
}
|
|
12800
12093
|
};
|
|
@@ -12816,6 +12109,166 @@ function isBaseTransportSend() {
|
|
|
12816
12109
|
);
|
|
12817
12110
|
}
|
|
12818
12111
|
|
|
12112
|
+
var NodeType;
|
|
12113
|
+
(function (NodeType) {
|
|
12114
|
+
NodeType[NodeType["Document"] = 0] = "Document";
|
|
12115
|
+
NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
|
|
12116
|
+
NodeType[NodeType["Element"] = 2] = "Element";
|
|
12117
|
+
NodeType[NodeType["Text"] = 3] = "Text";
|
|
12118
|
+
NodeType[NodeType["CDATA"] = 4] = "CDATA";
|
|
12119
|
+
NodeType[NodeType["Comment"] = 5] = "Comment";
|
|
12120
|
+
})(NodeType || (NodeType = {}));
|
|
12121
|
+
|
|
12122
|
+
/**
|
|
12123
|
+
* Create a breadcrumb for a replay.
|
|
12124
|
+
*/
|
|
12125
|
+
function createBreadcrumb(
|
|
12126
|
+
breadcrumb,
|
|
12127
|
+
) {
|
|
12128
|
+
return {
|
|
12129
|
+
timestamp: Date.now() / 1000,
|
|
12130
|
+
type: 'default',
|
|
12131
|
+
...breadcrumb,
|
|
12132
|
+
};
|
|
12133
|
+
}
|
|
12134
|
+
|
|
12135
|
+
/**
|
|
12136
|
+
* Add a breadcrumb event to replay.
|
|
12137
|
+
*/
|
|
12138
|
+
function addBreadcrumbEvent(replay, breadcrumb) {
|
|
12139
|
+
if (breadcrumb.category === 'sentry.transaction') {
|
|
12140
|
+
return;
|
|
12141
|
+
}
|
|
12142
|
+
|
|
12143
|
+
if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
|
|
12144
|
+
replay.triggerUserActivity();
|
|
12145
|
+
} else {
|
|
12146
|
+
replay.checkAndHandleExpiredSession();
|
|
12147
|
+
}
|
|
12148
|
+
|
|
12149
|
+
replay.addUpdate(() => {
|
|
12150
|
+
void addEvent(replay, {
|
|
12151
|
+
type: EventType.Custom,
|
|
12152
|
+
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
|
|
12153
|
+
// but maybe we should just keep them as milliseconds
|
|
12154
|
+
timestamp: (breadcrumb.timestamp || 0) * 1000,
|
|
12155
|
+
data: {
|
|
12156
|
+
tag: 'breadcrumb',
|
|
12157
|
+
payload: breadcrumb,
|
|
12158
|
+
},
|
|
12159
|
+
});
|
|
12160
|
+
|
|
12161
|
+
// Do not flush after console log messages
|
|
12162
|
+
return breadcrumb.category === 'console';
|
|
12163
|
+
});
|
|
12164
|
+
}
|
|
12165
|
+
|
|
12166
|
+
// Note that these are the serialized attributes and not attributes directly on
|
|
12167
|
+
// the DOM Node. Attributes we are interested in:
|
|
12168
|
+
const ATTRIBUTES_TO_RECORD = new Set([
|
|
12169
|
+
'id',
|
|
12170
|
+
'class',
|
|
12171
|
+
'aria-label',
|
|
12172
|
+
'role',
|
|
12173
|
+
'name',
|
|
12174
|
+
'alt',
|
|
12175
|
+
'title',
|
|
12176
|
+
'data-test-id',
|
|
12177
|
+
'data-testid',
|
|
12178
|
+
]);
|
|
12179
|
+
|
|
12180
|
+
/**
|
|
12181
|
+
* Inclusion list of attributes that we want to record from the DOM element
|
|
12182
|
+
*/
|
|
12183
|
+
function getAttributesToRecord(attributes) {
|
|
12184
|
+
const obj = {};
|
|
12185
|
+
for (const key in attributes) {
|
|
12186
|
+
if (ATTRIBUTES_TO_RECORD.has(key)) {
|
|
12187
|
+
let normalizedKey = key;
|
|
12188
|
+
|
|
12189
|
+
if (key === 'data-testid' || key === 'data-test-id') {
|
|
12190
|
+
normalizedKey = 'testId';
|
|
12191
|
+
}
|
|
12192
|
+
|
|
12193
|
+
obj[normalizedKey] = attributes[key];
|
|
12194
|
+
}
|
|
12195
|
+
}
|
|
12196
|
+
|
|
12197
|
+
return obj;
|
|
12198
|
+
}
|
|
12199
|
+
|
|
12200
|
+
const handleDomListener =
|
|
12201
|
+
(replay) =>
|
|
12202
|
+
(handlerData) => {
|
|
12203
|
+
if (!replay.isEnabled()) {
|
|
12204
|
+
return;
|
|
12205
|
+
}
|
|
12206
|
+
|
|
12207
|
+
const result = handleDom(handlerData);
|
|
12208
|
+
|
|
12209
|
+
if (!result) {
|
|
12210
|
+
return;
|
|
12211
|
+
}
|
|
12212
|
+
|
|
12213
|
+
addBreadcrumbEvent(replay, result);
|
|
12214
|
+
};
|
|
12215
|
+
|
|
12216
|
+
/**
|
|
12217
|
+
* An event handler to react to DOM events.
|
|
12218
|
+
*/
|
|
12219
|
+
function handleDom(handlerData) {
|
|
12220
|
+
let target;
|
|
12221
|
+
let targetNode;
|
|
12222
|
+
|
|
12223
|
+
// Accessing event.target can throw (see getsentry/raven-js#838, #768)
|
|
12224
|
+
try {
|
|
12225
|
+
targetNode = getTargetNode(handlerData);
|
|
12226
|
+
target = htmlTreeAsString(targetNode);
|
|
12227
|
+
} catch (e) {
|
|
12228
|
+
target = '<unknown>';
|
|
12229
|
+
}
|
|
12230
|
+
|
|
12231
|
+
// `__sn` property is the serialized node created by rrweb
|
|
12232
|
+
const serializedNode =
|
|
12233
|
+
targetNode && '__sn' in targetNode && targetNode.__sn.type === NodeType.Element ? targetNode.__sn : null;
|
|
12234
|
+
|
|
12235
|
+
return createBreadcrumb({
|
|
12236
|
+
category: `ui.${handlerData.name}`,
|
|
12237
|
+
message: target,
|
|
12238
|
+
data: serializedNode
|
|
12239
|
+
? {
|
|
12240
|
+
nodeId: serializedNode.id,
|
|
12241
|
+
node: {
|
|
12242
|
+
id: serializedNode.id,
|
|
12243
|
+
tagName: serializedNode.tagName,
|
|
12244
|
+
textContent: targetNode
|
|
12245
|
+
? Array.from(targetNode.childNodes)
|
|
12246
|
+
.map(
|
|
12247
|
+
(node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
|
|
12248
|
+
)
|
|
12249
|
+
.filter(Boolean) // filter out empty values
|
|
12250
|
+
.map(text => (text ).trim())
|
|
12251
|
+
.join('')
|
|
12252
|
+
: '',
|
|
12253
|
+
attributes: getAttributesToRecord(serializedNode.attributes),
|
|
12254
|
+
},
|
|
12255
|
+
}
|
|
12256
|
+
: {},
|
|
12257
|
+
});
|
|
12258
|
+
}
|
|
12259
|
+
|
|
12260
|
+
function getTargetNode(handlerData) {
|
|
12261
|
+
if (isEventWithTarget(handlerData.event)) {
|
|
12262
|
+
return handlerData.event.target;
|
|
12263
|
+
}
|
|
12264
|
+
|
|
12265
|
+
return handlerData.event;
|
|
12266
|
+
}
|
|
12267
|
+
|
|
12268
|
+
function isEventWithTarget(event) {
|
|
12269
|
+
return !!(event ).target;
|
|
12270
|
+
}
|
|
12271
|
+
|
|
12819
12272
|
/**
|
|
12820
12273
|
* Returns true if we think the given event is an error originating inside of rrweb.
|
|
12821
12274
|
*/
|
|
@@ -12839,30 +12292,6 @@ function isRrwebError(event, hint) {
|
|
|
12839
12292
|
});
|
|
12840
12293
|
}
|
|
12841
12294
|
|
|
12842
|
-
/**
|
|
12843
|
-
* Determine if event should be sampled (only applies in buffer mode).
|
|
12844
|
-
* When an event is captured by `hanldleGlobalEvent`, when in buffer mode
|
|
12845
|
-
* we determine if we want to sample the error or not.
|
|
12846
|
-
*/
|
|
12847
|
-
function shouldSampleForBufferEvent(replay, event) {
|
|
12848
|
-
if (replay.recordingMode !== 'buffer') {
|
|
12849
|
-
return false;
|
|
12850
|
-
}
|
|
12851
|
-
|
|
12852
|
-
// ignore this error because otherwise we could loop indefinitely with
|
|
12853
|
-
// trying to capture replay and failing
|
|
12854
|
-
if (event.message === UNABLE_TO_SEND_REPLAY) {
|
|
12855
|
-
return false;
|
|
12856
|
-
}
|
|
12857
|
-
|
|
12858
|
-
// Require the event to be an error event & to have an exception
|
|
12859
|
-
if (!event.exception || event.type) {
|
|
12860
|
-
return false;
|
|
12861
|
-
}
|
|
12862
|
-
|
|
12863
|
-
return isSampled(replay.getOptions().errorSampleRate);
|
|
12864
|
-
}
|
|
12865
|
-
|
|
12866
12295
|
/**
|
|
12867
12296
|
* Returns a listener to be added to `addGlobalEventProcessor(listener)`.
|
|
12868
12297
|
*/
|
|
@@ -12892,16 +12321,8 @@ function handleGlobalEventListener(
|
|
|
12892
12321
|
return null;
|
|
12893
12322
|
}
|
|
12894
12323
|
|
|
12895
|
-
//
|
|
12896
|
-
|
|
12897
|
-
// And convert the buffer session to a full session
|
|
12898
|
-
const isErrorEventSampled = shouldSampleForBufferEvent(replay, event);
|
|
12899
|
-
|
|
12900
|
-
// Tag errors if it has been sampled in buffer mode, or if it is session mode
|
|
12901
|
-
// Only tag transactions if in session mode
|
|
12902
|
-
const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session';
|
|
12903
|
-
|
|
12904
|
-
if (shouldTagReplayId) {
|
|
12324
|
+
// Only tag transactions with replayId if not waiting for an error
|
|
12325
|
+
if (isErrorEvent(event) || (isTransactionEvent(event) && replay.recordingMode === 'session')) {
|
|
12905
12326
|
event.tags = { ...event.tags, replayId: replay.getSessionId() };
|
|
12906
12327
|
}
|
|
12907
12328
|
|
|
@@ -12951,7 +12372,7 @@ function createPerformanceSpans(
|
|
|
12951
12372
|
) {
|
|
12952
12373
|
return entries.map(({ type, start, end, name, data }) =>
|
|
12953
12374
|
addEvent(replay, {
|
|
12954
|
-
type: EventType
|
|
12375
|
+
type: EventType.Custom,
|
|
12955
12376
|
timestamp: start,
|
|
12956
12377
|
data: {
|
|
12957
12378
|
tag: 'performanceSpan',
|
|
@@ -13100,14 +12521,12 @@ function handleFetchSpanListener(replay) {
|
|
|
13100
12521
|
function handleXhr(handlerData) {
|
|
13101
12522
|
const { startTimestamp, endTimestamp, xhr } = handlerData;
|
|
13102
12523
|
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
if (!startTimestamp || !endTimestamp || !sentryXhrData) {
|
|
12524
|
+
if (!startTimestamp || !endTimestamp || !xhr.__sentry_xhr__) {
|
|
13106
12525
|
return null;
|
|
13107
12526
|
}
|
|
13108
12527
|
|
|
13109
12528
|
// This is only used as a fallback, so we know the body sizes are never set here
|
|
13110
|
-
const { method, url, status_code: statusCode } =
|
|
12529
|
+
const { method, url, status_code: statusCode } = xhr.__sentry_xhr__;
|
|
13111
12530
|
|
|
13112
12531
|
if (url === undefined) {
|
|
13113
12532
|
return null;
|
|
@@ -13140,393 +12559,6 @@ function handleXhrSpanListener(replay) {
|
|
|
13140
12559
|
};
|
|
13141
12560
|
}
|
|
13142
12561
|
|
|
13143
|
-
const OBJ = 10;
|
|
13144
|
-
const OBJ_KEY = 11;
|
|
13145
|
-
const OBJ_KEY_STR = 12;
|
|
13146
|
-
const OBJ_VAL = 13;
|
|
13147
|
-
const OBJ_VAL_STR = 14;
|
|
13148
|
-
const OBJ_VAL_COMPLETED = 15;
|
|
13149
|
-
|
|
13150
|
-
const ARR = 20;
|
|
13151
|
-
const ARR_VAL = 21;
|
|
13152
|
-
const ARR_VAL_STR = 22;
|
|
13153
|
-
const ARR_VAL_COMPLETED = 23;
|
|
13154
|
-
|
|
13155
|
-
const ALLOWED_PRIMITIVES = ['true', 'false', 'null'];
|
|
13156
|
-
|
|
13157
|
-
/**
|
|
13158
|
-
* Complete an incomplete JSON string.
|
|
13159
|
-
* This will ensure that the last element always has a `"~~"` to indicate it was truncated.
|
|
13160
|
-
* For example, `[1,2,` will be completed to `[1,2,"~~"]`
|
|
13161
|
-
* and `{"aa":"b` will be completed to `{"aa":"b~~"}`
|
|
13162
|
-
*/
|
|
13163
|
-
function completeJson(incompleteJson, stack) {
|
|
13164
|
-
if (!stack.length) {
|
|
13165
|
-
return incompleteJson;
|
|
13166
|
-
}
|
|
13167
|
-
|
|
13168
|
-
let json = incompleteJson;
|
|
13169
|
-
|
|
13170
|
-
// Most checks are only needed for the last step in the stack
|
|
13171
|
-
const lastPos = stack.length - 1;
|
|
13172
|
-
const lastStep = stack[lastPos];
|
|
13173
|
-
|
|
13174
|
-
json = _fixLastStep(json, lastStep);
|
|
13175
|
-
|
|
13176
|
-
// Complete remaining steps - just add closing brackets
|
|
13177
|
-
for (let i = lastPos; i >= 0; i--) {
|
|
13178
|
-
const step = stack[i];
|
|
13179
|
-
|
|
13180
|
-
switch (step) {
|
|
13181
|
-
case OBJ:
|
|
13182
|
-
json = `${json}}`;
|
|
13183
|
-
break;
|
|
13184
|
-
case ARR:
|
|
13185
|
-
json = `${json}]`;
|
|
13186
|
-
break;
|
|
13187
|
-
}
|
|
13188
|
-
}
|
|
13189
|
-
|
|
13190
|
-
return json;
|
|
13191
|
-
}
|
|
13192
|
-
|
|
13193
|
-
function _fixLastStep(json, lastStep) {
|
|
13194
|
-
switch (lastStep) {
|
|
13195
|
-
// Object cases
|
|
13196
|
-
case OBJ:
|
|
13197
|
-
return `${json}"~~":"~~"`;
|
|
13198
|
-
case OBJ_KEY:
|
|
13199
|
-
return `${json}:"~~"`;
|
|
13200
|
-
case OBJ_KEY_STR:
|
|
13201
|
-
return `${json}~~":"~~"`;
|
|
13202
|
-
case OBJ_VAL:
|
|
13203
|
-
return _maybeFixIncompleteObjValue(json);
|
|
13204
|
-
case OBJ_VAL_STR:
|
|
13205
|
-
return `${json}~~"`;
|
|
13206
|
-
case OBJ_VAL_COMPLETED:
|
|
13207
|
-
return `${json},"~~":"~~"`;
|
|
13208
|
-
|
|
13209
|
-
// Array cases
|
|
13210
|
-
case ARR:
|
|
13211
|
-
return `${json}"~~"`;
|
|
13212
|
-
case ARR_VAL:
|
|
13213
|
-
return _maybeFixIncompleteArrValue(json);
|
|
13214
|
-
case ARR_VAL_STR:
|
|
13215
|
-
return `${json}~~"`;
|
|
13216
|
-
case ARR_VAL_COMPLETED:
|
|
13217
|
-
return `${json},"~~"`;
|
|
13218
|
-
}
|
|
13219
|
-
|
|
13220
|
-
return json;
|
|
13221
|
-
}
|
|
13222
|
-
|
|
13223
|
-
function _maybeFixIncompleteArrValue(json) {
|
|
13224
|
-
const pos = _findLastArrayDelimiter(json);
|
|
13225
|
-
|
|
13226
|
-
if (pos > -1) {
|
|
13227
|
-
const part = json.slice(pos + 1);
|
|
13228
|
-
|
|
13229
|
-
if (ALLOWED_PRIMITIVES.includes(part.trim())) {
|
|
13230
|
-
return `${json},"~~"`;
|
|
13231
|
-
}
|
|
13232
|
-
|
|
13233
|
-
// Everything else is replaced with `"~~"`
|
|
13234
|
-
return `${json.slice(0, pos + 1)}"~~"`;
|
|
13235
|
-
}
|
|
13236
|
-
|
|
13237
|
-
// fallback, this shouldn't happen, to be save
|
|
13238
|
-
return json;
|
|
13239
|
-
}
|
|
13240
|
-
|
|
13241
|
-
function _findLastArrayDelimiter(json) {
|
|
13242
|
-
for (let i = json.length - 1; i >= 0; i--) {
|
|
13243
|
-
const char = json[i];
|
|
13244
|
-
|
|
13245
|
-
if (char === ',' || char === '[') {
|
|
13246
|
-
return i;
|
|
13247
|
-
}
|
|
13248
|
-
}
|
|
13249
|
-
|
|
13250
|
-
return -1;
|
|
13251
|
-
}
|
|
13252
|
-
|
|
13253
|
-
function _maybeFixIncompleteObjValue(json) {
|
|
13254
|
-
const startPos = json.lastIndexOf(':');
|
|
13255
|
-
|
|
13256
|
-
const part = json.slice(startPos + 1);
|
|
13257
|
-
|
|
13258
|
-
if (ALLOWED_PRIMITIVES.includes(part.trim())) {
|
|
13259
|
-
return `${json},"~~":"~~"`;
|
|
13260
|
-
}
|
|
13261
|
-
|
|
13262
|
-
// Everything else is replaced with `"~~"`
|
|
13263
|
-
// This also means we do not have incomplete numbers, e.g `[1` is replaced with `["~~"]`
|
|
13264
|
-
return `${json.slice(0, startPos + 1)}"~~"`;
|
|
13265
|
-
}
|
|
13266
|
-
|
|
13267
|
-
/**
|
|
13268
|
-
* Evaluate an (incomplete) JSON string.
|
|
13269
|
-
*/
|
|
13270
|
-
function evaluateJson(json) {
|
|
13271
|
-
const stack = [];
|
|
13272
|
-
|
|
13273
|
-
for (let pos = 0; pos < json.length; pos++) {
|
|
13274
|
-
_evaluateJsonPos(stack, json, pos);
|
|
13275
|
-
}
|
|
13276
|
-
|
|
13277
|
-
return stack;
|
|
13278
|
-
}
|
|
13279
|
-
|
|
13280
|
-
function _evaluateJsonPos(stack, json, pos) {
|
|
13281
|
-
const curStep = stack[stack.length - 1];
|
|
13282
|
-
|
|
13283
|
-
const char = json[pos];
|
|
13284
|
-
|
|
13285
|
-
const whitespaceRegex = /\s/;
|
|
13286
|
-
|
|
13287
|
-
if (whitespaceRegex.test(char)) {
|
|
13288
|
-
return;
|
|
13289
|
-
}
|
|
13290
|
-
|
|
13291
|
-
if (char === '"' && !_isEscaped(json, pos)) {
|
|
13292
|
-
_handleQuote(stack, curStep);
|
|
13293
|
-
return;
|
|
13294
|
-
}
|
|
13295
|
-
|
|
13296
|
-
switch (char) {
|
|
13297
|
-
case '{':
|
|
13298
|
-
_handleObj(stack, curStep);
|
|
13299
|
-
break;
|
|
13300
|
-
case '[':
|
|
13301
|
-
_handleArr(stack, curStep);
|
|
13302
|
-
break;
|
|
13303
|
-
case ':':
|
|
13304
|
-
_handleColon(stack, curStep);
|
|
13305
|
-
break;
|
|
13306
|
-
case ',':
|
|
13307
|
-
_handleComma(stack, curStep);
|
|
13308
|
-
break;
|
|
13309
|
-
case '}':
|
|
13310
|
-
_handleObjClose(stack, curStep);
|
|
13311
|
-
break;
|
|
13312
|
-
case ']':
|
|
13313
|
-
_handleArrClose(stack, curStep);
|
|
13314
|
-
break;
|
|
13315
|
-
}
|
|
13316
|
-
}
|
|
13317
|
-
|
|
13318
|
-
function _handleQuote(stack, curStep) {
|
|
13319
|
-
// End of obj value
|
|
13320
|
-
if (curStep === OBJ_VAL_STR) {
|
|
13321
|
-
stack.pop();
|
|
13322
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13323
|
-
return;
|
|
13324
|
-
}
|
|
13325
|
-
|
|
13326
|
-
// End of arr value
|
|
13327
|
-
if (curStep === ARR_VAL_STR) {
|
|
13328
|
-
stack.pop();
|
|
13329
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13330
|
-
return;
|
|
13331
|
-
}
|
|
13332
|
-
|
|
13333
|
-
// Start of obj value
|
|
13334
|
-
if (curStep === OBJ_VAL) {
|
|
13335
|
-
stack.push(OBJ_VAL_STR);
|
|
13336
|
-
return;
|
|
13337
|
-
}
|
|
13338
|
-
|
|
13339
|
-
// Start of arr value
|
|
13340
|
-
if (curStep === ARR_VAL) {
|
|
13341
|
-
stack.push(ARR_VAL_STR);
|
|
13342
|
-
return;
|
|
13343
|
-
}
|
|
13344
|
-
|
|
13345
|
-
// Start of obj key
|
|
13346
|
-
if (curStep === OBJ) {
|
|
13347
|
-
stack.push(OBJ_KEY_STR);
|
|
13348
|
-
return;
|
|
13349
|
-
}
|
|
13350
|
-
|
|
13351
|
-
// End of obj key
|
|
13352
|
-
if (curStep === OBJ_KEY_STR) {
|
|
13353
|
-
stack.pop();
|
|
13354
|
-
stack.push(OBJ_KEY);
|
|
13355
|
-
return;
|
|
13356
|
-
}
|
|
13357
|
-
}
|
|
13358
|
-
|
|
13359
|
-
function _handleObj(stack, curStep) {
|
|
13360
|
-
// Initial object
|
|
13361
|
-
if (!curStep) {
|
|
13362
|
-
stack.push(OBJ);
|
|
13363
|
-
return;
|
|
13364
|
-
}
|
|
13365
|
-
|
|
13366
|
-
// New object as obj value
|
|
13367
|
-
if (curStep === OBJ_VAL) {
|
|
13368
|
-
stack.push(OBJ);
|
|
13369
|
-
return;
|
|
13370
|
-
}
|
|
13371
|
-
|
|
13372
|
-
// New object as array element
|
|
13373
|
-
if (curStep === ARR_VAL) {
|
|
13374
|
-
stack.push(OBJ);
|
|
13375
|
-
}
|
|
13376
|
-
|
|
13377
|
-
// New object as first array element
|
|
13378
|
-
if (curStep === ARR) {
|
|
13379
|
-
stack.push(OBJ);
|
|
13380
|
-
return;
|
|
13381
|
-
}
|
|
13382
|
-
}
|
|
13383
|
-
|
|
13384
|
-
function _handleArr(stack, curStep) {
|
|
13385
|
-
// Initial array
|
|
13386
|
-
if (!curStep) {
|
|
13387
|
-
stack.push(ARR);
|
|
13388
|
-
stack.push(ARR_VAL);
|
|
13389
|
-
return;
|
|
13390
|
-
}
|
|
13391
|
-
|
|
13392
|
-
// New array as obj value
|
|
13393
|
-
if (curStep === OBJ_VAL) {
|
|
13394
|
-
stack.push(ARR);
|
|
13395
|
-
stack.push(ARR_VAL);
|
|
13396
|
-
return;
|
|
13397
|
-
}
|
|
13398
|
-
|
|
13399
|
-
// New array as array element
|
|
13400
|
-
if (curStep === ARR_VAL) {
|
|
13401
|
-
stack.push(ARR);
|
|
13402
|
-
stack.push(ARR_VAL);
|
|
13403
|
-
}
|
|
13404
|
-
|
|
13405
|
-
// New array as first array element
|
|
13406
|
-
if (curStep === ARR) {
|
|
13407
|
-
stack.push(ARR);
|
|
13408
|
-
stack.push(ARR_VAL);
|
|
13409
|
-
return;
|
|
13410
|
-
}
|
|
13411
|
-
}
|
|
13412
|
-
|
|
13413
|
-
function _handleColon(stack, curStep) {
|
|
13414
|
-
if (curStep === OBJ_KEY) {
|
|
13415
|
-
stack.pop();
|
|
13416
|
-
stack.push(OBJ_VAL);
|
|
13417
|
-
}
|
|
13418
|
-
}
|
|
13419
|
-
|
|
13420
|
-
function _handleComma(stack, curStep) {
|
|
13421
|
-
// Comma after obj value
|
|
13422
|
-
if (curStep === OBJ_VAL) {
|
|
13423
|
-
stack.pop();
|
|
13424
|
-
return;
|
|
13425
|
-
}
|
|
13426
|
-
if (curStep === OBJ_VAL_COMPLETED) {
|
|
13427
|
-
// Pop OBJ_VAL_COMPLETED & OBJ_VAL
|
|
13428
|
-
stack.pop();
|
|
13429
|
-
stack.pop();
|
|
13430
|
-
return;
|
|
13431
|
-
}
|
|
13432
|
-
|
|
13433
|
-
// Comma after arr value
|
|
13434
|
-
if (curStep === ARR_VAL) {
|
|
13435
|
-
// do nothing - basically we'd pop ARR_VAL but add it right back
|
|
13436
|
-
return;
|
|
13437
|
-
}
|
|
13438
|
-
|
|
13439
|
-
if (curStep === ARR_VAL_COMPLETED) {
|
|
13440
|
-
// Pop ARR_VAL_COMPLETED
|
|
13441
|
-
stack.pop();
|
|
13442
|
-
|
|
13443
|
-
// basically we'd pop ARR_VAL but add it right back
|
|
13444
|
-
return;
|
|
13445
|
-
}
|
|
13446
|
-
}
|
|
13447
|
-
|
|
13448
|
-
function _handleObjClose(stack, curStep) {
|
|
13449
|
-
// Empty object {}
|
|
13450
|
-
if (curStep === OBJ) {
|
|
13451
|
-
stack.pop();
|
|
13452
|
-
}
|
|
13453
|
-
|
|
13454
|
-
// Object with element
|
|
13455
|
-
if (curStep === OBJ_VAL) {
|
|
13456
|
-
// Pop OBJ_VAL, OBJ
|
|
13457
|
-
stack.pop();
|
|
13458
|
-
stack.pop();
|
|
13459
|
-
}
|
|
13460
|
-
|
|
13461
|
-
// Obj with element
|
|
13462
|
-
if (curStep === OBJ_VAL_COMPLETED) {
|
|
13463
|
-
// Pop OBJ_VAL_COMPLETED, OBJ_VAL, OBJ
|
|
13464
|
-
stack.pop();
|
|
13465
|
-
stack.pop();
|
|
13466
|
-
stack.pop();
|
|
13467
|
-
}
|
|
13468
|
-
|
|
13469
|
-
// if was obj value, complete it
|
|
13470
|
-
if (stack[stack.length - 1] === OBJ_VAL) {
|
|
13471
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13472
|
-
}
|
|
13473
|
-
|
|
13474
|
-
// if was arr value, complete it
|
|
13475
|
-
if (stack[stack.length - 1] === ARR_VAL) {
|
|
13476
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13477
|
-
}
|
|
13478
|
-
}
|
|
13479
|
-
|
|
13480
|
-
function _handleArrClose(stack, curStep) {
|
|
13481
|
-
// Empty array []
|
|
13482
|
-
if (curStep === ARR) {
|
|
13483
|
-
stack.pop();
|
|
13484
|
-
}
|
|
13485
|
-
|
|
13486
|
-
// Array with element
|
|
13487
|
-
if (curStep === ARR_VAL) {
|
|
13488
|
-
// Pop ARR_VAL, ARR
|
|
13489
|
-
stack.pop();
|
|
13490
|
-
stack.pop();
|
|
13491
|
-
}
|
|
13492
|
-
|
|
13493
|
-
// Array with element
|
|
13494
|
-
if (curStep === ARR_VAL_COMPLETED) {
|
|
13495
|
-
// Pop ARR_VAL_COMPLETED, ARR_VAL, ARR
|
|
13496
|
-
stack.pop();
|
|
13497
|
-
stack.pop();
|
|
13498
|
-
stack.pop();
|
|
13499
|
-
}
|
|
13500
|
-
|
|
13501
|
-
// if was obj value, complete it
|
|
13502
|
-
if (stack[stack.length - 1] === OBJ_VAL) {
|
|
13503
|
-
stack.push(OBJ_VAL_COMPLETED);
|
|
13504
|
-
}
|
|
13505
|
-
|
|
13506
|
-
// if was arr value, complete it
|
|
13507
|
-
if (stack[stack.length - 1] === ARR_VAL) {
|
|
13508
|
-
stack.push(ARR_VAL_COMPLETED);
|
|
13509
|
-
}
|
|
13510
|
-
}
|
|
13511
|
-
|
|
13512
|
-
function _isEscaped(str, pos) {
|
|
13513
|
-
const previousChar = str[pos - 1];
|
|
13514
|
-
|
|
13515
|
-
return previousChar === '\\' && !_isEscaped(str, pos - 1);
|
|
13516
|
-
}
|
|
13517
|
-
|
|
13518
|
-
/* eslint-disable max-lines */
|
|
13519
|
-
|
|
13520
|
-
/**
|
|
13521
|
-
* Takes an incomplete JSON string, and returns a hopefully valid JSON string.
|
|
13522
|
-
* Note that this _can_ fail, so you should check the return value is valid JSON.
|
|
13523
|
-
*/
|
|
13524
|
-
function fixJson(incompleteJson) {
|
|
13525
|
-
const stack = evaluateJson(incompleteJson);
|
|
13526
|
-
|
|
13527
|
-
return completeJson(incompleteJson, stack);
|
|
13528
|
-
}
|
|
13529
|
-
|
|
13530
12562
|
/** Get the size of a body. */
|
|
13531
12563
|
function getBodySize(
|
|
13532
12564
|
body,
|
|
@@ -13620,68 +12652,51 @@ function makeNetworkReplayBreadcrumb(
|
|
|
13620
12652
|
return result;
|
|
13621
12653
|
}
|
|
13622
12654
|
|
|
13623
|
-
/**
|
|
13624
|
-
function
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
}
|
|
12655
|
+
/** Get either a JSON network body, or a text representation. */
|
|
12656
|
+
function getNetworkBody(bodyText) {
|
|
12657
|
+
if (!bodyText) {
|
|
12658
|
+
return;
|
|
12659
|
+
}
|
|
12660
|
+
|
|
12661
|
+
try {
|
|
12662
|
+
return JSON.parse(bodyText);
|
|
12663
|
+
} catch (e2) {
|
|
12664
|
+
// return text
|
|
12665
|
+
}
|
|
12666
|
+
|
|
12667
|
+
return bodyText;
|
|
13632
12668
|
}
|
|
13633
12669
|
|
|
13634
12670
|
/** Build the request or response part of a replay network breadcrumb. */
|
|
13635
12671
|
function buildNetworkRequestOrResponse(
|
|
13636
|
-
headers,
|
|
13637
12672
|
bodySize,
|
|
13638
12673
|
body,
|
|
13639
12674
|
) {
|
|
13640
|
-
if (!bodySize && Object.keys(headers).length === 0) {
|
|
13641
|
-
return undefined;
|
|
13642
|
-
}
|
|
13643
|
-
|
|
13644
12675
|
if (!bodySize) {
|
|
13645
|
-
return
|
|
13646
|
-
headers,
|
|
13647
|
-
};
|
|
12676
|
+
return undefined;
|
|
13648
12677
|
}
|
|
13649
12678
|
|
|
13650
12679
|
if (!body) {
|
|
13651
12680
|
return {
|
|
13652
|
-
headers,
|
|
13653
12681
|
size: bodySize,
|
|
13654
12682
|
};
|
|
13655
12683
|
}
|
|
13656
12684
|
|
|
13657
12685
|
const info = {
|
|
13658
|
-
headers,
|
|
13659
12686
|
size: bodySize,
|
|
13660
12687
|
};
|
|
13661
12688
|
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
12689
|
+
if (bodySize < NETWORK_BODY_MAX_SIZE) {
|
|
12690
|
+
info.body = body;
|
|
12691
|
+
} else {
|
|
13665
12692
|
info._meta = {
|
|
13666
|
-
|
|
12693
|
+
errors: ['MAX_BODY_SIZE_EXCEEDED'],
|
|
13667
12694
|
};
|
|
13668
12695
|
}
|
|
13669
12696
|
|
|
13670
12697
|
return info;
|
|
13671
12698
|
}
|
|
13672
12699
|
|
|
13673
|
-
/** Filter a set of headers */
|
|
13674
|
-
function getAllowedHeaders(headers, allowedHeaders) {
|
|
13675
|
-
return Object.keys(headers).reduce((filteredHeaders, key) => {
|
|
13676
|
-
const normalizedKey = key.toLowerCase();
|
|
13677
|
-
// Avoid putting empty strings into the headers
|
|
13678
|
-
if (allowedHeaders.includes(normalizedKey) && headers[key]) {
|
|
13679
|
-
filteredHeaders[normalizedKey] = headers[key];
|
|
13680
|
-
}
|
|
13681
|
-
return filteredHeaders;
|
|
13682
|
-
}, {});
|
|
13683
|
-
}
|
|
13684
|
-
|
|
13685
12700
|
function _serializeFormData(formData) {
|
|
13686
12701
|
// This is a bit simplified, but gives us a decent estimate
|
|
13687
12702
|
// This converts e.g. { name: 'Anne Smith', age: 13 } to 'name=Anne+Smith&age=13'
|
|
@@ -13689,78 +12704,6 @@ function _serializeFormData(formData) {
|
|
|
13689
12704
|
return new URLSearchParams(formData).toString();
|
|
13690
12705
|
}
|
|
13691
12706
|
|
|
13692
|
-
function normalizeNetworkBody(body)
|
|
13693
|
-
|
|
13694
|
-
{
|
|
13695
|
-
if (!body || typeof body !== 'string') {
|
|
13696
|
-
return {
|
|
13697
|
-
body,
|
|
13698
|
-
warnings: [],
|
|
13699
|
-
};
|
|
13700
|
-
}
|
|
13701
|
-
|
|
13702
|
-
const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE;
|
|
13703
|
-
|
|
13704
|
-
if (_strIsProbablyJson(body)) {
|
|
13705
|
-
try {
|
|
13706
|
-
const json = exceedsSizeLimit ? fixJson(body.slice(0, NETWORK_BODY_MAX_SIZE)) : body;
|
|
13707
|
-
const normalizedBody = JSON.parse(json);
|
|
13708
|
-
return {
|
|
13709
|
-
body: normalizedBody,
|
|
13710
|
-
warnings: exceedsSizeLimit ? ['JSON_TRUNCATED'] : [],
|
|
13711
|
-
};
|
|
13712
|
-
} catch (e3) {
|
|
13713
|
-
return {
|
|
13714
|
-
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13715
|
-
warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
|
|
13716
|
-
};
|
|
13717
|
-
}
|
|
13718
|
-
}
|
|
13719
|
-
|
|
13720
|
-
return {
|
|
13721
|
-
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13722
|
-
warnings: exceedsSizeLimit ? ['TEXT_TRUNCATED'] : [],
|
|
13723
|
-
};
|
|
13724
|
-
}
|
|
13725
|
-
|
|
13726
|
-
function _strIsProbablyJson(str) {
|
|
13727
|
-
const first = str[0];
|
|
13728
|
-
const last = str[str.length - 1];
|
|
13729
|
-
|
|
13730
|
-
// Simple check: If this does not start & end with {} or [], it's not JSON
|
|
13731
|
-
return (first === '[' && last === ']') || (first === '{' && last === '}');
|
|
13732
|
-
}
|
|
13733
|
-
|
|
13734
|
-
/** Match an URL against a list of strings/Regex. */
|
|
13735
|
-
function urlMatches(url, urls) {
|
|
13736
|
-
const fullUrl = getFullUrl(url);
|
|
13737
|
-
|
|
13738
|
-
return stringMatchesSomePattern(fullUrl, urls);
|
|
13739
|
-
}
|
|
13740
|
-
|
|
13741
|
-
/** exported for tests */
|
|
13742
|
-
function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
|
|
13743
|
-
// Short circuit for common cases:
|
|
13744
|
-
if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith(WINDOW.location.origin)) {
|
|
13745
|
-
return url;
|
|
13746
|
-
}
|
|
13747
|
-
const fixedUrl = new URL(url, baseURI);
|
|
13748
|
-
|
|
13749
|
-
// If these do not match, we are not dealing with a relative URL, so just return it
|
|
13750
|
-
if (fixedUrl.origin !== new URL(baseURI).origin) {
|
|
13751
|
-
return url;
|
|
13752
|
-
}
|
|
13753
|
-
|
|
13754
|
-
const fullUrl = fixedUrl.href;
|
|
13755
|
-
|
|
13756
|
-
// Remove trailing slashes, if they don't match the original URL
|
|
13757
|
-
if (!url.endsWith('/') && fullUrl.endsWith('/')) {
|
|
13758
|
-
return fullUrl.slice(0, -1);
|
|
13759
|
-
}
|
|
13760
|
-
|
|
13761
|
-
return fullUrl;
|
|
13762
|
-
}
|
|
13763
|
-
|
|
13764
12707
|
/**
|
|
13765
12708
|
* Capture a fetch breadcrumb to a replay.
|
|
13766
12709
|
* This adds additional data (where approriate).
|
|
@@ -13768,9 +12711,7 @@ function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
|
|
|
13768
12711
|
async function captureFetchBreadcrumbToReplay(
|
|
13769
12712
|
breadcrumb,
|
|
13770
12713
|
hint,
|
|
13771
|
-
options
|
|
13772
|
-
|
|
13773
|
-
,
|
|
12714
|
+
options,
|
|
13774
12715
|
) {
|
|
13775
12716
|
try {
|
|
13776
12717
|
const data = await _prepareFetchData(breadcrumb, hint, options);
|
|
@@ -13797,7 +12738,6 @@ function enrichFetchBreadcrumb(
|
|
|
13797
12738
|
|
|
13798
12739
|
const body = _getFetchRequestArgBody(input);
|
|
13799
12740
|
const reqSize = getBodySize(body, options.textEncoder);
|
|
13800
|
-
|
|
13801
12741
|
const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined;
|
|
13802
12742
|
|
|
13803
12743
|
if (reqSize !== undefined) {
|
|
@@ -13811,109 +12751,97 @@ function enrichFetchBreadcrumb(
|
|
|
13811
12751
|
async function _prepareFetchData(
|
|
13812
12752
|
breadcrumb,
|
|
13813
12753
|
hint,
|
|
13814
|
-
options
|
|
13815
|
-
|
|
13816
|
-
,
|
|
12754
|
+
options,
|
|
13817
12755
|
) {
|
|
13818
12756
|
const { startTimestamp, endTimestamp } = hint;
|
|
13819
12757
|
|
|
13820
12758
|
const {
|
|
13821
12759
|
url,
|
|
13822
12760
|
method,
|
|
13823
|
-
status_code: statusCode
|
|
12761
|
+
status_code: statusCode,
|
|
13824
12762
|
request_body_size: requestBodySize,
|
|
13825
12763
|
response_body_size: responseBodySize,
|
|
13826
12764
|
} = breadcrumb.data;
|
|
13827
12765
|
|
|
13828
|
-
const
|
|
13829
|
-
|
|
13830
|
-
const request = captureDetails
|
|
13831
|
-
? _getRequestInfo(options, hint.input, requestBodySize)
|
|
13832
|
-
: buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13833
|
-
const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize);
|
|
12766
|
+
const request = _getRequestInfo(options, hint.input, requestBodySize);
|
|
12767
|
+
const response = await _getResponseInfo(options, hint.response, responseBodySize);
|
|
13834
12768
|
|
|
13835
12769
|
return {
|
|
13836
12770
|
startTimestamp,
|
|
13837
12771
|
endTimestamp,
|
|
13838
12772
|
url,
|
|
13839
12773
|
method,
|
|
13840
|
-
statusCode,
|
|
12774
|
+
statusCode: statusCode || 0,
|
|
13841
12775
|
request,
|
|
13842
12776
|
response,
|
|
13843
12777
|
};
|
|
13844
12778
|
}
|
|
13845
12779
|
|
|
13846
12780
|
function _getRequestInfo(
|
|
13847
|
-
{
|
|
12781
|
+
{ captureBodies },
|
|
13848
12782
|
input,
|
|
13849
12783
|
requestBodySize,
|
|
13850
12784
|
) {
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
if (!networkCaptureBodies) {
|
|
13854
|
-
return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
|
|
12785
|
+
if (!captureBodies) {
|
|
12786
|
+
return buildNetworkRequestOrResponse(requestBodySize, undefined);
|
|
13855
12787
|
}
|
|
13856
12788
|
|
|
13857
12789
|
// We only want to transmit string or string-like bodies
|
|
13858
12790
|
const requestBody = _getFetchRequestArgBody(input);
|
|
13859
|
-
const
|
|
13860
|
-
return buildNetworkRequestOrResponse(
|
|
12791
|
+
const body = getNetworkBody(getBodyString(requestBody));
|
|
12792
|
+
return buildNetworkRequestOrResponse(requestBodySize, body);
|
|
13861
12793
|
}
|
|
13862
12794
|
|
|
13863
12795
|
async function _getResponseInfo(
|
|
13864
|
-
|
|
13865
|
-
{
|
|
13866
|
-
networkCaptureBodies,
|
|
13867
|
-
textEncoder,
|
|
13868
|
-
networkResponseHeaders,
|
|
13869
|
-
}
|
|
13870
|
-
|
|
13871
|
-
,
|
|
12796
|
+
{ captureBodies, textEncoder },
|
|
13872
12797
|
response,
|
|
13873
12798
|
responseBodySize,
|
|
13874
12799
|
) {
|
|
13875
|
-
if (!
|
|
13876
|
-
return
|
|
13877
|
-
}
|
|
13878
|
-
|
|
13879
|
-
const headers = getAllHeaders(response.headers, networkResponseHeaders);
|
|
13880
|
-
|
|
13881
|
-
if (!networkCaptureBodies && responseBodySize !== undefined) {
|
|
13882
|
-
return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
|
|
12800
|
+
if (!captureBodies && responseBodySize !== undefined) {
|
|
12801
|
+
return buildNetworkRequestOrResponse(responseBodySize, undefined);
|
|
13883
12802
|
}
|
|
13884
12803
|
|
|
13885
12804
|
// Only clone the response if we need to
|
|
13886
12805
|
try {
|
|
13887
12806
|
// We have to clone this, as the body can only be read once
|
|
13888
12807
|
const res = response.clone();
|
|
13889
|
-
const bodyText = await _parseFetchBody(res);
|
|
12808
|
+
const { body, bodyText } = await _parseFetchBody(res);
|
|
13890
12809
|
|
|
13891
12810
|
const size =
|
|
13892
12811
|
bodyText && bodyText.length && responseBodySize === undefined
|
|
13893
12812
|
? getBodySize(bodyText, textEncoder)
|
|
13894
12813
|
: responseBodySize;
|
|
13895
12814
|
|
|
13896
|
-
if (
|
|
13897
|
-
return
|
|
12815
|
+
if (captureBodies) {
|
|
12816
|
+
return buildNetworkRequestOrResponse(size, body);
|
|
13898
12817
|
}
|
|
13899
12818
|
|
|
13900
|
-
|
|
13901
|
-
return buildNetworkRequestOrResponse(headers, size, bodyText);
|
|
13902
|
-
}
|
|
13903
|
-
|
|
13904
|
-
return buildNetworkRequestOrResponse(headers, size, undefined);
|
|
12819
|
+
return buildNetworkRequestOrResponse(size, undefined);
|
|
13905
12820
|
} catch (e) {
|
|
13906
12821
|
// fallback
|
|
13907
|
-
return buildNetworkRequestOrResponse(
|
|
12822
|
+
return buildNetworkRequestOrResponse(responseBodySize, undefined);
|
|
13908
12823
|
}
|
|
13909
12824
|
}
|
|
13910
12825
|
|
|
13911
|
-
async function _parseFetchBody(
|
|
12826
|
+
async function _parseFetchBody(
|
|
12827
|
+
response,
|
|
12828
|
+
) {
|
|
12829
|
+
let bodyText;
|
|
12830
|
+
|
|
13912
12831
|
try {
|
|
13913
|
-
|
|
12832
|
+
bodyText = await response.text();
|
|
13914
12833
|
} catch (e2) {
|
|
13915
|
-
return
|
|
12834
|
+
return {};
|
|
13916
12835
|
}
|
|
12836
|
+
|
|
12837
|
+
try {
|
|
12838
|
+
const body = JSON.parse(bodyText);
|
|
12839
|
+
return { body, bodyText };
|
|
12840
|
+
} catch (e3) {
|
|
12841
|
+
// just send bodyText
|
|
12842
|
+
}
|
|
12843
|
+
|
|
12844
|
+
return { bodyText, body: bodyText };
|
|
13917
12845
|
}
|
|
13918
12846
|
|
|
13919
12847
|
function _getFetchRequestArgBody(fetchArgs = []) {
|
|
@@ -13925,56 +12853,6 @@ function _getFetchRequestArgBody(fetchArgs = []) {
|
|
|
13925
12853
|
return (fetchArgs[1] ).body;
|
|
13926
12854
|
}
|
|
13927
12855
|
|
|
13928
|
-
function getAllHeaders(headers, allowedHeaders) {
|
|
13929
|
-
const allHeaders = {};
|
|
13930
|
-
|
|
13931
|
-
allowedHeaders.forEach(header => {
|
|
13932
|
-
if (headers.get(header)) {
|
|
13933
|
-
allHeaders[header] = headers.get(header) ;
|
|
13934
|
-
}
|
|
13935
|
-
});
|
|
13936
|
-
|
|
13937
|
-
return allHeaders;
|
|
13938
|
-
}
|
|
13939
|
-
|
|
13940
|
-
function getRequestHeaders(fetchArgs, allowedHeaders) {
|
|
13941
|
-
if (fetchArgs.length === 1 && typeof fetchArgs[0] !== 'string') {
|
|
13942
|
-
return getHeadersFromOptions(fetchArgs[0] , allowedHeaders);
|
|
13943
|
-
}
|
|
13944
|
-
|
|
13945
|
-
if (fetchArgs.length === 2) {
|
|
13946
|
-
return getHeadersFromOptions(fetchArgs[1] , allowedHeaders);
|
|
13947
|
-
}
|
|
13948
|
-
|
|
13949
|
-
return {};
|
|
13950
|
-
}
|
|
13951
|
-
|
|
13952
|
-
function getHeadersFromOptions(
|
|
13953
|
-
input,
|
|
13954
|
-
allowedHeaders,
|
|
13955
|
-
) {
|
|
13956
|
-
if (!input) {
|
|
13957
|
-
return {};
|
|
13958
|
-
}
|
|
13959
|
-
|
|
13960
|
-
const headers = input.headers;
|
|
13961
|
-
|
|
13962
|
-
if (!headers) {
|
|
13963
|
-
return {};
|
|
13964
|
-
}
|
|
13965
|
-
|
|
13966
|
-
if (headers instanceof Headers) {
|
|
13967
|
-
return getAllHeaders(headers, allowedHeaders);
|
|
13968
|
-
}
|
|
13969
|
-
|
|
13970
|
-
// We do not support this, as it is not really documented (anymore?)
|
|
13971
|
-
if (Array.isArray(headers)) {
|
|
13972
|
-
return {};
|
|
13973
|
-
}
|
|
13974
|
-
|
|
13975
|
-
return getAllowedHeaders(headers, allowedHeaders);
|
|
13976
|
-
}
|
|
13977
|
-
|
|
13978
12856
|
/**
|
|
13979
12857
|
* Capture an XHR breadcrumb to a replay.
|
|
13980
12858
|
* This adds additional data (where approriate).
|
|
@@ -14025,12 +12903,12 @@ function _prepareXhrData(
|
|
|
14025
12903
|
hint,
|
|
14026
12904
|
options,
|
|
14027
12905
|
) {
|
|
14028
|
-
const { startTimestamp, endTimestamp, input
|
|
12906
|
+
const { startTimestamp, endTimestamp, input } = hint;
|
|
14029
12907
|
|
|
14030
12908
|
const {
|
|
14031
12909
|
url,
|
|
14032
12910
|
method,
|
|
14033
|
-
status_code: statusCode
|
|
12911
|
+
status_code: statusCode,
|
|
14034
12912
|
request_body_size: requestBodySize,
|
|
14035
12913
|
response_body_size: responseBodySize,
|
|
14036
12914
|
} = breadcrumb.data;
|
|
@@ -14039,35 +12917,13 @@ function _prepareXhrData(
|
|
|
14039
12917
|
return null;
|
|
14040
12918
|
}
|
|
14041
12919
|
|
|
14042
|
-
if (!urlMatches(url, options.networkDetailAllowUrls)) {
|
|
14043
|
-
const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
14044
|
-
const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
14045
|
-
return {
|
|
14046
|
-
startTimestamp,
|
|
14047
|
-
endTimestamp,
|
|
14048
|
-
url,
|
|
14049
|
-
method,
|
|
14050
|
-
statusCode,
|
|
14051
|
-
request,
|
|
14052
|
-
response,
|
|
14053
|
-
};
|
|
14054
|
-
}
|
|
14055
|
-
|
|
14056
|
-
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
14057
|
-
const networkRequestHeaders = xhrInfo
|
|
14058
|
-
? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
|
|
14059
|
-
: {};
|
|
14060
|
-
const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
|
|
14061
|
-
|
|
14062
12920
|
const request = buildNetworkRequestOrResponse(
|
|
14063
|
-
networkRequestHeaders,
|
|
14064
12921
|
requestBodySize,
|
|
14065
|
-
options.
|
|
12922
|
+
options.captureBodies ? getNetworkBody(getBodyString(input)) : undefined,
|
|
14066
12923
|
);
|
|
14067
12924
|
const response = buildNetworkRequestOrResponse(
|
|
14068
|
-
networkResponseHeaders,
|
|
14069
12925
|
responseBodySize,
|
|
14070
|
-
options.
|
|
12926
|
+
options.captureBodies ? getNetworkBody(hint.xhr.responseText) : undefined,
|
|
14071
12927
|
);
|
|
14072
12928
|
|
|
14073
12929
|
return {
|
|
@@ -14075,26 +12931,12 @@ function _prepareXhrData(
|
|
|
14075
12931
|
endTimestamp,
|
|
14076
12932
|
url,
|
|
14077
12933
|
method,
|
|
14078
|
-
statusCode,
|
|
12934
|
+
statusCode: statusCode || 0,
|
|
14079
12935
|
request,
|
|
14080
12936
|
response,
|
|
14081
12937
|
};
|
|
14082
12938
|
}
|
|
14083
12939
|
|
|
14084
|
-
function getResponseHeaders(xhr) {
|
|
14085
|
-
const headers = xhr.getAllResponseHeaders();
|
|
14086
|
-
|
|
14087
|
-
if (!headers) {
|
|
14088
|
-
return {};
|
|
14089
|
-
}
|
|
14090
|
-
|
|
14091
|
-
return headers.split('\r\n').reduce((acc, line) => {
|
|
14092
|
-
const [key, value] = line.split(': ');
|
|
14093
|
-
acc[key.toLowerCase()] = value;
|
|
14094
|
-
return acc;
|
|
14095
|
-
}, {});
|
|
14096
|
-
}
|
|
14097
|
-
|
|
14098
12940
|
/**
|
|
14099
12941
|
* This method does two things:
|
|
14100
12942
|
* - It enriches the regular XHR/fetch breadcrumbs with request/response size data
|
|
@@ -14107,16 +12949,10 @@ function handleNetworkBreadcrumbs(replay) {
|
|
|
14107
12949
|
try {
|
|
14108
12950
|
const textEncoder = new TextEncoder();
|
|
14109
12951
|
|
|
14110
|
-
const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
|
|
14111
|
-
replay.getOptions();
|
|
14112
|
-
|
|
14113
12952
|
const options = {
|
|
14114
12953
|
replay,
|
|
14115
12954
|
textEncoder,
|
|
14116
|
-
|
|
14117
|
-
networkCaptureBodies,
|
|
14118
|
-
networkRequestHeaders,
|
|
14119
|
-
networkResponseHeaders,
|
|
12955
|
+
captureBodies: replay.getOptions()._experiments.captureNetworkBodies || false,
|
|
14120
12956
|
};
|
|
14121
12957
|
|
|
14122
12958
|
if (client && client.on) {
|
|
@@ -14224,66 +13060,9 @@ function handleScope(scope) {
|
|
|
14224
13060
|
return null;
|
|
14225
13061
|
}
|
|
14226
13062
|
|
|
14227
|
-
if (newBreadcrumb.category === 'console') {
|
|
14228
|
-
return normalizeConsoleBreadcrumb(newBreadcrumb);
|
|
14229
|
-
}
|
|
14230
|
-
|
|
14231
13063
|
return createBreadcrumb(newBreadcrumb);
|
|
14232
13064
|
}
|
|
14233
13065
|
|
|
14234
|
-
/** exported for tests only */
|
|
14235
|
-
function normalizeConsoleBreadcrumb(breadcrumb) {
|
|
14236
|
-
const args = breadcrumb.data && breadcrumb.data.arguments;
|
|
14237
|
-
|
|
14238
|
-
if (!Array.isArray(args) || args.length === 0) {
|
|
14239
|
-
return createBreadcrumb(breadcrumb);
|
|
14240
|
-
}
|
|
14241
|
-
|
|
14242
|
-
let isTruncated = false;
|
|
14243
|
-
|
|
14244
|
-
// Avoid giant args captures
|
|
14245
|
-
const normalizedArgs = args.map(arg => {
|
|
14246
|
-
if (!arg) {
|
|
14247
|
-
return arg;
|
|
14248
|
-
}
|
|
14249
|
-
if (typeof arg === 'string') {
|
|
14250
|
-
if (arg.length > CONSOLE_ARG_MAX_SIZE) {
|
|
14251
|
-
isTruncated = true;
|
|
14252
|
-
return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
|
|
14253
|
-
}
|
|
14254
|
-
|
|
14255
|
-
return arg;
|
|
14256
|
-
}
|
|
14257
|
-
if (typeof arg === 'object') {
|
|
14258
|
-
try {
|
|
14259
|
-
const normalizedArg = normalize(arg, 7);
|
|
14260
|
-
const stringified = JSON.stringify(normalizedArg);
|
|
14261
|
-
if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
|
|
14262
|
-
const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
|
|
14263
|
-
const json = JSON.parse(fixedJson);
|
|
14264
|
-
// We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
|
|
14265
|
-
isTruncated = true;
|
|
14266
|
-
return json;
|
|
14267
|
-
}
|
|
14268
|
-
return normalizedArg;
|
|
14269
|
-
} catch (e) {
|
|
14270
|
-
// fall back to default
|
|
14271
|
-
}
|
|
14272
|
-
}
|
|
14273
|
-
|
|
14274
|
-
return arg;
|
|
14275
|
-
});
|
|
14276
|
-
|
|
14277
|
-
return createBreadcrumb({
|
|
14278
|
-
...breadcrumb,
|
|
14279
|
-
data: {
|
|
14280
|
-
...breadcrumb.data,
|
|
14281
|
-
arguments: normalizedArgs,
|
|
14282
|
-
...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
|
|
14283
|
-
},
|
|
14284
|
-
});
|
|
14285
|
-
}
|
|
14286
|
-
|
|
14287
13066
|
/**
|
|
14288
13067
|
* Add global listeners that cannot be removed.
|
|
14289
13068
|
*/
|
|
@@ -14308,8 +13087,7 @@ function addGlobalListeners(replay) {
|
|
|
14308
13087
|
client.on('afterSendEvent', handleAfterSendEvent(replay));
|
|
14309
13088
|
client.on('createDsc', (dsc) => {
|
|
14310
13089
|
const replayId = replay.getSessionId();
|
|
14311
|
-
|
|
14312
|
-
if (replayId && replay.isEnabled() && replay.recordingMode === 'session') {
|
|
13090
|
+
if (replayId) {
|
|
14313
13091
|
dsc.replay_id = replayId;
|
|
14314
13092
|
}
|
|
14315
13093
|
});
|
|
@@ -14589,23 +13367,6 @@ function debounce(func, wait, options) {
|
|
|
14589
13367
|
return debounced;
|
|
14590
13368
|
}
|
|
14591
13369
|
|
|
14592
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
14593
|
-
|
|
14594
|
-
var EventType; (function (EventType) {
|
|
14595
|
-
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
14596
|
-
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
14597
|
-
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
14598
|
-
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
14599
|
-
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
14600
|
-
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
14601
|
-
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
14602
|
-
})(EventType || (EventType = {}));
|
|
14603
|
-
|
|
14604
|
-
/**
|
|
14605
|
-
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
14606
|
-
* we specifcally need in the SDK.
|
|
14607
|
-
*/
|
|
14608
|
-
|
|
14609
13370
|
/**
|
|
14610
13371
|
* Handler for recording events.
|
|
14611
13372
|
*
|
|
@@ -14634,7 +13395,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14634
13395
|
// when an error occurs. Clear any state that happens before this current
|
|
14635
13396
|
// checkout. This needs to happen before `addEvent()` which updates state
|
|
14636
13397
|
// dependent on this reset.
|
|
14637
|
-
if (replay.recordingMode === '
|
|
13398
|
+
if (replay.recordingMode === 'error' && isCheckout) {
|
|
14638
13399
|
replay.setInitialState();
|
|
14639
13400
|
}
|
|
14640
13401
|
|
|
@@ -14648,14 +13409,6 @@ function getHandleRecordingEmit(replay) {
|
|
|
14648
13409
|
return false;
|
|
14649
13410
|
}
|
|
14650
13411
|
|
|
14651
|
-
// Additionally, create a meta event that will capture certain SDK settings.
|
|
14652
|
-
// In order to handle buffer mode, this needs to either be done when we
|
|
14653
|
-
// receive checkout events or at flush time.
|
|
14654
|
-
//
|
|
14655
|
-
// `isCheckout` is always true, but want to be explicit that it should
|
|
14656
|
-
// only be added for checkouts
|
|
14657
|
-
void addSettingsEvent(replay, isCheckout);
|
|
14658
|
-
|
|
14659
13412
|
// If there is a previousSessionId after a full snapshot occurs, then
|
|
14660
13413
|
// the replay session was started due to session expiration. The new session
|
|
14661
13414
|
// is started before triggering a new checkout and contains the id
|
|
@@ -14666,10 +13419,10 @@ function getHandleRecordingEmit(replay) {
|
|
|
14666
13419
|
return true;
|
|
14667
13420
|
}
|
|
14668
13421
|
|
|
14669
|
-
//
|
|
14670
|
-
//
|
|
14671
|
-
if (replay.recordingMode === '
|
|
14672
|
-
const earliestEvent = replay.
|
|
13422
|
+
// See note above re: session start needs to reflect the most recent
|
|
13423
|
+
// checkout.
|
|
13424
|
+
if (replay.recordingMode === 'error' && replay.session) {
|
|
13425
|
+
const { earliestEvent } = replay.getContext();
|
|
14673
13426
|
if (earliestEvent) {
|
|
14674
13427
|
replay.session.started = earliestEvent;
|
|
14675
13428
|
|
|
@@ -14693,46 +13446,6 @@ function getHandleRecordingEmit(replay) {
|
|
|
14693
13446
|
};
|
|
14694
13447
|
}
|
|
14695
13448
|
|
|
14696
|
-
/**
|
|
14697
|
-
* Exported for tests
|
|
14698
|
-
*/
|
|
14699
|
-
function createOptionsEvent(replay) {
|
|
14700
|
-
const options = replay.getOptions();
|
|
14701
|
-
return {
|
|
14702
|
-
type: EventType.Custom,
|
|
14703
|
-
timestamp: Date.now(),
|
|
14704
|
-
data: {
|
|
14705
|
-
tag: 'options',
|
|
14706
|
-
payload: {
|
|
14707
|
-
sessionSampleRate: options.sessionSampleRate,
|
|
14708
|
-
errorSampleRate: options.errorSampleRate,
|
|
14709
|
-
useCompressionOption: options.useCompression,
|
|
14710
|
-
blockAllMedia: options.blockAllMedia,
|
|
14711
|
-
maskAllText: options.maskAllText,
|
|
14712
|
-
maskAllInputs: options.maskAllInputs,
|
|
14713
|
-
useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false,
|
|
14714
|
-
networkDetailHasUrls: options.networkDetailAllowUrls.length > 0,
|
|
14715
|
-
networkCaptureBodies: options.networkCaptureBodies,
|
|
14716
|
-
networkRequestHasHeaders: options.networkRequestHeaders.length > 0,
|
|
14717
|
-
networkResponseHasHeaders: options.networkResponseHeaders.length > 0,
|
|
14718
|
-
},
|
|
14719
|
-
},
|
|
14720
|
-
};
|
|
14721
|
-
}
|
|
14722
|
-
|
|
14723
|
-
/**
|
|
14724
|
-
* Add a "meta" event that contains a simplified view on current configuration
|
|
14725
|
-
* options. This should only be included on the first segment of a recording.
|
|
14726
|
-
*/
|
|
14727
|
-
function addSettingsEvent(replay, isCheckout) {
|
|
14728
|
-
// Only need to add this event when sending the first segment
|
|
14729
|
-
if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
|
|
14730
|
-
return Promise.resolve(null);
|
|
14731
|
-
}
|
|
14732
|
-
|
|
14733
|
-
return addEvent(replay, createOptionsEvent(replay), false);
|
|
14734
|
-
}
|
|
14735
|
-
|
|
14736
13449
|
/**
|
|
14737
13450
|
* Create a replay envelope ready to be sent.
|
|
14738
13451
|
* This includes both the replay event, as well as the recording data.
|
|
@@ -14844,9 +13557,11 @@ async function sendReplayRequest({
|
|
|
14844
13557
|
recordingData,
|
|
14845
13558
|
replayId,
|
|
14846
13559
|
segmentId: segment_id,
|
|
13560
|
+
includeReplayStartTimestamp,
|
|
14847
13561
|
eventContext,
|
|
14848
13562
|
timestamp,
|
|
14849
13563
|
session,
|
|
13564
|
+
options,
|
|
14850
13565
|
}) {
|
|
14851
13566
|
const preparedRecordingData = prepareRecordingData({
|
|
14852
13567
|
recordingData,
|
|
@@ -14868,8 +13583,9 @@ async function sendReplayRequest({
|
|
|
14868
13583
|
}
|
|
14869
13584
|
|
|
14870
13585
|
const baseEvent = {
|
|
13586
|
+
// @ts-ignore private api
|
|
14871
13587
|
type: REPLAY_EVENT_NAME,
|
|
14872
|
-
replay_start_timestamp: initialTimestamp / 1000,
|
|
13588
|
+
...(includeReplayStartTimestamp ? { replay_start_timestamp: initialTimestamp / 1000 } : {}),
|
|
14873
13589
|
timestamp: timestamp / 1000,
|
|
14874
13590
|
error_ids: errorIds,
|
|
14875
13591
|
trace_ids: traceIds,
|
|
@@ -14888,6 +13604,15 @@ async function sendReplayRequest({
|
|
|
14888
13604
|
return;
|
|
14889
13605
|
}
|
|
14890
13606
|
|
|
13607
|
+
replayEvent.contexts = {
|
|
13608
|
+
...replayEvent.contexts,
|
|
13609
|
+
replay: {
|
|
13610
|
+
...(replayEvent.contexts && replayEvent.contexts.replay),
|
|
13611
|
+
session_sample_rate: options.sessionSampleRate,
|
|
13612
|
+
error_sample_rate: options.errorSampleRate,
|
|
13613
|
+
},
|
|
13614
|
+
};
|
|
13615
|
+
|
|
14891
13616
|
/*
|
|
14892
13617
|
For reference, the fully built event looks something like this:
|
|
14893
13618
|
{
|
|
@@ -14918,6 +13643,10 @@ async function sendReplayRequest({
|
|
|
14918
13643
|
},
|
|
14919
13644
|
"sdkProcessingMetadata": {},
|
|
14920
13645
|
"contexts": {
|
|
13646
|
+
"replay": {
|
|
13647
|
+
"session_sample_rate": 1,
|
|
13648
|
+
"error_sample_rate": 0,
|
|
13649
|
+
},
|
|
14921
13650
|
},
|
|
14922
13651
|
}
|
|
14923
13652
|
*/
|
|
@@ -15043,11 +13772,9 @@ class ReplayContainer {
|
|
|
15043
13772
|
__init2() {this.performanceEvents = [];}
|
|
15044
13773
|
|
|
15045
13774
|
/**
|
|
15046
|
-
* Recording can happen in one of
|
|
15047
|
-
*
|
|
15048
|
-
*
|
|
15049
|
-
* - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
|
|
15050
|
-
* - or calling `flush()` to send the replay
|
|
13775
|
+
* Recording can happen in one of two modes:
|
|
13776
|
+
* * session: Record the whole session, sending it continuously
|
|
13777
|
+
* * error: Always keep the last 60s of recording, and when an error occurs, send it immediately
|
|
15051
13778
|
*/
|
|
15052
13779
|
__init3() {this.recordingMode = 'session';}
|
|
15053
13780
|
|
|
@@ -15056,8 +13783,7 @@ class ReplayContainer {
|
|
|
15056
13783
|
* @hidden
|
|
15057
13784
|
*/
|
|
15058
13785
|
__init4() {this.timeouts = {
|
|
15059
|
-
|
|
15060
|
-
sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
|
|
13786
|
+
sessionIdle: SESSION_IDLE_DURATION,
|
|
15061
13787
|
maxSessionLife: MAX_SESSION_LIFE,
|
|
15062
13788
|
}; }
|
|
15063
13789
|
|
|
@@ -15101,6 +13827,7 @@ class ReplayContainer {
|
|
|
15101
13827
|
errorIds: new Set(),
|
|
15102
13828
|
traceIds: new Set(),
|
|
15103
13829
|
urls: [],
|
|
13830
|
+
earliestEvent: null,
|
|
15104
13831
|
initialTimestamp: Date.now(),
|
|
15105
13832
|
initialUrl: '',
|
|
15106
13833
|
};}
|
|
@@ -15110,7 +13837,7 @@ class ReplayContainer {
|
|
|
15110
13837
|
recordingOptions,
|
|
15111
13838
|
}
|
|
15112
13839
|
|
|
15113
|
-
) {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);
|
|
13840
|
+
) {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);
|
|
15114
13841
|
this._recordingOptions = recordingOptions;
|
|
15115
13842
|
this._options = options;
|
|
15116
13843
|
|
|
@@ -15140,102 +13867,49 @@ class ReplayContainer {
|
|
|
15140
13867
|
}
|
|
15141
13868
|
|
|
15142
13869
|
/**
|
|
15143
|
-
* Initializes the plugin
|
|
15144
|
-
*
|
|
13870
|
+
* Initializes the plugin.
|
|
13871
|
+
*
|
|
13872
|
+
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
13873
|
+
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
15145
13874
|
*/
|
|
15146
|
-
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
// If neither sample rate is > 0, then do nothing - user will need to call one of
|
|
15150
|
-
// `start()` or `startBuffering` themselves.
|
|
15151
|
-
if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
|
|
15152
|
-
return;
|
|
15153
|
-
}
|
|
15154
|
-
|
|
15155
|
-
// Otherwise if there is _any_ sample rate set, try to load an existing
|
|
15156
|
-
// session, or create a new one.
|
|
15157
|
-
const isSessionSampled = this._loadAndCheckSession();
|
|
13875
|
+
start() {
|
|
13876
|
+
this.setInitialState();
|
|
15158
13877
|
|
|
15159
|
-
if (!
|
|
15160
|
-
// This should only occur if `errorSampleRate` is 0 and was unsampled for
|
|
15161
|
-
// session-based replay. In this case there is nothing to do.
|
|
13878
|
+
if (!this._loadAndCheckSession()) {
|
|
15162
13879
|
return;
|
|
15163
13880
|
}
|
|
15164
13881
|
|
|
13882
|
+
// If there is no session, then something bad has happened - can't continue
|
|
15165
13883
|
if (!this.session) {
|
|
15166
|
-
|
|
15167
|
-
this._handleException(new Error('Unable to initialize and create session'));
|
|
13884
|
+
this._handleException(new Error('No session found'));
|
|
15168
13885
|
return;
|
|
15169
13886
|
}
|
|
15170
13887
|
|
|
15171
|
-
if (this.session.sampled
|
|
15172
|
-
// If not sampled
|
|
15173
|
-
|
|
15174
|
-
// could have sessions from Session storage that are still `error` from
|
|
15175
|
-
// prior SDK version.
|
|
15176
|
-
this.recordingMode = 'buffer';
|
|
15177
|
-
}
|
|
15178
|
-
|
|
15179
|
-
this._initializeRecording();
|
|
15180
|
-
}
|
|
15181
|
-
|
|
15182
|
-
/**
|
|
15183
|
-
* Start a replay regardless of sampling rate. Calling this will always
|
|
15184
|
-
* create a new session. Will throw an error if replay is already in progress.
|
|
15185
|
-
*
|
|
15186
|
-
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
15187
|
-
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
15188
|
-
*/
|
|
15189
|
-
start() {
|
|
15190
|
-
if (this._isEnabled && this.recordingMode === 'session') {
|
|
15191
|
-
throw new Error('Replay recording is already in progress');
|
|
13888
|
+
if (!this.session.sampled) {
|
|
13889
|
+
// If session was not sampled, then we do not initialize the integration at all.
|
|
13890
|
+
return;
|
|
15192
13891
|
}
|
|
15193
13892
|
|
|
15194
|
-
|
|
15195
|
-
|
|
13893
|
+
// If session is sampled for errors, then we need to set the recordingMode
|
|
13894
|
+
// to 'error', which will configure recording with different options.
|
|
13895
|
+
if (this.session.sampled === 'error') {
|
|
13896
|
+
this.recordingMode = 'error';
|
|
15196
13897
|
}
|
|
15197
13898
|
|
|
15198
|
-
|
|
13899
|
+
// setup() is generally called on page load or manually - in both cases we
|
|
13900
|
+
// should treat it as an activity
|
|
13901
|
+
this._updateSessionActivity();
|
|
15199
13902
|
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
stickySession: Boolean(this._options.stickySession),
|
|
15203
|
-
currentSession: this.session,
|
|
15204
|
-
// This is intentional: create a new session-based replay when calling `start()`
|
|
15205
|
-
sessionSampleRate: 1,
|
|
15206
|
-
allowBuffering: false,
|
|
13903
|
+
this.eventBuffer = createEventBuffer({
|
|
13904
|
+
useCompression: this._options.useCompression,
|
|
15207
13905
|
});
|
|
15208
13906
|
|
|
15209
|
-
|
|
15210
|
-
this.session = session;
|
|
15211
|
-
|
|
15212
|
-
this._initializeRecording();
|
|
15213
|
-
}
|
|
15214
|
-
|
|
15215
|
-
/**
|
|
15216
|
-
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
15217
|
-
* `replaysOnErrorSampleRate` > 0, an error occurs.
|
|
15218
|
-
*/
|
|
15219
|
-
startBuffering() {
|
|
15220
|
-
if (this._isEnabled) {
|
|
15221
|
-
throw new Error('Replay recording is already in progress');
|
|
15222
|
-
}
|
|
15223
|
-
|
|
15224
|
-
const previousSessionId = this.session && this.session.id;
|
|
15225
|
-
|
|
15226
|
-
const { session } = getSession({
|
|
15227
|
-
timeouts: this.timeouts,
|
|
15228
|
-
stickySession: Boolean(this._options.stickySession),
|
|
15229
|
-
currentSession: this.session,
|
|
15230
|
-
sessionSampleRate: 0,
|
|
15231
|
-
allowBuffering: true,
|
|
15232
|
-
});
|
|
13907
|
+
this._addListeners();
|
|
15233
13908
|
|
|
15234
|
-
|
|
15235
|
-
this.
|
|
13909
|
+
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
13910
|
+
this._isEnabled = true;
|
|
15236
13911
|
|
|
15237
|
-
this.
|
|
15238
|
-
this._initializeRecording();
|
|
13912
|
+
this.startRecording();
|
|
15239
13913
|
}
|
|
15240
13914
|
|
|
15241
13915
|
/**
|
|
@@ -15250,7 +13924,7 @@ class ReplayContainer {
|
|
|
15250
13924
|
// When running in error sampling mode, we need to overwrite `checkoutEveryNms`
|
|
15251
13925
|
// Without this, it would record forever, until an error happens, which we don't want
|
|
15252
13926
|
// instead, we'll always keep the last 60 seconds of replay before an error happened
|
|
15253
|
-
...(this.recordingMode === '
|
|
13927
|
+
...(this.recordingMode === 'error' && { checkoutEveryNms: ERROR_CHECKOUT_TIME }),
|
|
15254
13928
|
emit: getHandleRecordingEmit(this),
|
|
15255
13929
|
onMutation: this._onMutationHandler,
|
|
15256
13930
|
});
|
|
@@ -15261,18 +13935,17 @@ class ReplayContainer {
|
|
|
15261
13935
|
|
|
15262
13936
|
/**
|
|
15263
13937
|
* Stops the recording, if it was running.
|
|
15264
|
-
*
|
|
15265
|
-
* Returns true if it was previously stopped, or is now stopped,
|
|
15266
|
-
* otherwise false.
|
|
13938
|
+
* Returns true if it was stopped, else false.
|
|
15267
13939
|
*/
|
|
15268
13940
|
stopRecording() {
|
|
15269
13941
|
try {
|
|
15270
13942
|
if (this._stopRecording) {
|
|
15271
13943
|
this._stopRecording();
|
|
15272
13944
|
this._stopRecording = undefined;
|
|
13945
|
+
return true;
|
|
15273
13946
|
}
|
|
15274
13947
|
|
|
15275
|
-
return
|
|
13948
|
+
return false;
|
|
15276
13949
|
} catch (err) {
|
|
15277
13950
|
this._handleException(err);
|
|
15278
13951
|
return false;
|
|
@@ -15283,7 +13956,7 @@ class ReplayContainer {
|
|
|
15283
13956
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
15284
13957
|
* does not support a teardown
|
|
15285
13958
|
*/
|
|
15286
|
-
|
|
13959
|
+
stop(reason) {
|
|
15287
13960
|
if (!this._isEnabled) {
|
|
15288
13961
|
return;
|
|
15289
13962
|
}
|
|
@@ -15299,24 +13972,12 @@ class ReplayContainer {
|
|
|
15299
13972
|
log(msg);
|
|
15300
13973
|
}
|
|
15301
13974
|
|
|
15302
|
-
// We can't move `_isEnabled` after awaiting a flush, otherwise we can
|
|
15303
|
-
// enter into an infinite loop when `stop()` is called while flushing.
|
|
15304
13975
|
this._isEnabled = false;
|
|
15305
13976
|
this._removeListeners();
|
|
15306
13977
|
this.stopRecording();
|
|
15307
|
-
|
|
15308
|
-
this._debouncedFlush.cancel();
|
|
15309
|
-
// See comment above re: `_isEnabled`, we "force" a flush, ignoring the
|
|
15310
|
-
// `_isEnabled` state of the plugin since it was disabled above.
|
|
15311
|
-
await this._flush({ force: true });
|
|
15312
|
-
|
|
15313
|
-
// After flush, destroy event buffer
|
|
15314
13978
|
this.eventBuffer && this.eventBuffer.destroy();
|
|
15315
13979
|
this.eventBuffer = null;
|
|
15316
|
-
|
|
15317
|
-
// Clear session from session storage, note this means if a new session
|
|
15318
|
-
// is started after, it will not have `previousSessionId`
|
|
15319
|
-
clearSession(this);
|
|
13980
|
+
this._debouncedFlush.cancel();
|
|
15320
13981
|
} catch (err) {
|
|
15321
13982
|
this._handleException(err);
|
|
15322
13983
|
}
|
|
@@ -15347,45 +14008,6 @@ class ReplayContainer {
|
|
|
15347
14008
|
this.startRecording();
|
|
15348
14009
|
}
|
|
15349
14010
|
|
|
15350
|
-
/**
|
|
15351
|
-
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
15352
|
-
* Unless `continueRecording` is false, the replay will continue to record and
|
|
15353
|
-
* behave as a "session"-based replay.
|
|
15354
|
-
*
|
|
15355
|
-
* Otherwise, queue up a flush.
|
|
15356
|
-
*/
|
|
15357
|
-
async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
|
|
15358
|
-
if (this.recordingMode === 'session') {
|
|
15359
|
-
return this.flushImmediate();
|
|
15360
|
-
}
|
|
15361
|
-
|
|
15362
|
-
// Allow flush to complete before resuming as a session recording, otherwise
|
|
15363
|
-
// the checkout from `startRecording` may be included in the payload.
|
|
15364
|
-
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
15365
|
-
// than the session replay.
|
|
15366
|
-
await this.flushImmediate();
|
|
15367
|
-
|
|
15368
|
-
const hasStoppedRecording = this.stopRecording();
|
|
15369
|
-
|
|
15370
|
-
if (!continueRecording || !hasStoppedRecording) {
|
|
15371
|
-
return;
|
|
15372
|
-
}
|
|
15373
|
-
|
|
15374
|
-
// Re-start recording, but in "session" recording mode
|
|
15375
|
-
|
|
15376
|
-
// Reset all "capture on error" configuration before
|
|
15377
|
-
// starting a new recording
|
|
15378
|
-
this.recordingMode = 'session';
|
|
15379
|
-
|
|
15380
|
-
// Once this session ends, we do not want to refresh it
|
|
15381
|
-
if (this.session) {
|
|
15382
|
-
this.session.shouldRefresh = false;
|
|
15383
|
-
this._maybeSaveSession();
|
|
15384
|
-
}
|
|
15385
|
-
|
|
15386
|
-
this.startRecording();
|
|
15387
|
-
}
|
|
15388
|
-
|
|
15389
14011
|
/**
|
|
15390
14012
|
* We want to batch uploads of replay events. Save events only if
|
|
15391
14013
|
* `<flushMinDelay>` milliseconds have elapsed since the last event
|
|
@@ -15395,12 +14017,12 @@ class ReplayContainer {
|
|
|
15395
14017
|
* processing and hand back control to caller.
|
|
15396
14018
|
*/
|
|
15397
14019
|
addUpdate(cb) {
|
|
15398
|
-
// We need to always run `cb` (e.g. in the case of `this.recordingMode == '
|
|
14020
|
+
// We need to always run `cb` (e.g. in the case of `this.recordingMode == 'error'`)
|
|
15399
14021
|
const cbResult = cb();
|
|
15400
14022
|
|
|
15401
14023
|
// If this option is turned on then we will only want to call `flush`
|
|
15402
14024
|
// explicitly
|
|
15403
|
-
if (this.recordingMode === '
|
|
14025
|
+
if (this.recordingMode === 'error') {
|
|
15404
14026
|
return;
|
|
15405
14027
|
}
|
|
15406
14028
|
|
|
@@ -15472,12 +14094,12 @@ class ReplayContainer {
|
|
|
15472
14094
|
const oldSessionId = this.getSessionId();
|
|
15473
14095
|
|
|
15474
14096
|
// Prevent starting a new session if the last user activity is older than
|
|
15475
|
-
//
|
|
14097
|
+
// SESSION_IDLE_DURATION. Otherwise non-user activity can trigger a new
|
|
15476
14098
|
// session+recording. This creates noisy replays that do not have much
|
|
15477
14099
|
// content in them.
|
|
15478
14100
|
if (
|
|
15479
14101
|
this._lastActivity &&
|
|
15480
|
-
isExpired(this._lastActivity, this.timeouts.
|
|
14102
|
+
isExpired(this._lastActivity, this.timeouts.sessionIdle) &&
|
|
15481
14103
|
this.session &&
|
|
15482
14104
|
this.session.sampled === 'session'
|
|
15483
14105
|
) {
|
|
@@ -15527,30 +14149,6 @@ class ReplayContainer {
|
|
|
15527
14149
|
this._context.urls.push(url);
|
|
15528
14150
|
}
|
|
15529
14151
|
|
|
15530
|
-
/**
|
|
15531
|
-
* Initialize and start all listeners to varying events (DOM,
|
|
15532
|
-
* Performance Observer, Recording, Sentry SDK, etc)
|
|
15533
|
-
*/
|
|
15534
|
-
_initializeRecording() {
|
|
15535
|
-
this.setInitialState();
|
|
15536
|
-
|
|
15537
|
-
// this method is generally called on page load or manually - in both cases
|
|
15538
|
-
// we should treat it as an activity
|
|
15539
|
-
this._updateSessionActivity();
|
|
15540
|
-
|
|
15541
|
-
this.eventBuffer = createEventBuffer({
|
|
15542
|
-
useCompression: this._options.useCompression,
|
|
15543
|
-
});
|
|
15544
|
-
|
|
15545
|
-
this._removeListeners();
|
|
15546
|
-
this._addListeners();
|
|
15547
|
-
|
|
15548
|
-
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
15549
|
-
this._isEnabled = true;
|
|
15550
|
-
|
|
15551
|
-
this.startRecording();
|
|
15552
|
-
}
|
|
15553
|
-
|
|
15554
14152
|
/** A wrapper to conditionally capture exceptions. */
|
|
15555
14153
|
_handleException(error) {
|
|
15556
14154
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
|
|
@@ -15570,7 +14168,7 @@ class ReplayContainer {
|
|
|
15570
14168
|
stickySession: Boolean(this._options.stickySession),
|
|
15571
14169
|
currentSession: this.session,
|
|
15572
14170
|
sessionSampleRate: this._options.sessionSampleRate,
|
|
15573
|
-
|
|
14171
|
+
errorSampleRate: this._options.errorSampleRate,
|
|
15574
14172
|
});
|
|
15575
14173
|
|
|
15576
14174
|
// If session was newly created (i.e. was not loaded from storage), then
|
|
@@ -15587,7 +14185,7 @@ class ReplayContainer {
|
|
|
15587
14185
|
this.session = session;
|
|
15588
14186
|
|
|
15589
14187
|
if (!this.session.sampled) {
|
|
15590
|
-
|
|
14188
|
+
this.stop('session unsampled');
|
|
15591
14189
|
return false;
|
|
15592
14190
|
}
|
|
15593
14191
|
|
|
@@ -15602,7 +14200,6 @@ class ReplayContainer {
|
|
|
15602
14200
|
WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange);
|
|
15603
14201
|
WINDOW.addEventListener('blur', this._handleWindowBlur);
|
|
15604
14202
|
WINDOW.addEventListener('focus', this._handleWindowFocus);
|
|
15605
|
-
WINDOW.addEventListener('keydown', this._handleKeyboardEvent);
|
|
15606
14203
|
|
|
15607
14204
|
// There is no way to remove these listeners, so ensure they are only added once
|
|
15608
14205
|
if (!this._hasInitializedCoreListeners) {
|
|
@@ -15631,7 +14228,6 @@ class ReplayContainer {
|
|
|
15631
14228
|
|
|
15632
14229
|
WINDOW.removeEventListener('blur', this._handleWindowBlur);
|
|
15633
14230
|
WINDOW.removeEventListener('focus', this._handleWindowFocus);
|
|
15634
|
-
WINDOW.removeEventListener('keydown', this._handleKeyboardEvent);
|
|
15635
14231
|
|
|
15636
14232
|
if (this._performanceObserver) {
|
|
15637
14233
|
this._performanceObserver.disconnect();
|
|
@@ -15682,11 +14278,6 @@ class ReplayContainer {
|
|
|
15682
14278
|
this._doChangeToForegroundTasks(breadcrumb);
|
|
15683
14279
|
};}
|
|
15684
14280
|
|
|
15685
|
-
/** Ensure page remains active when a key is pressed. */
|
|
15686
|
-
__init16() {this._handleKeyboardEvent = (event) => {
|
|
15687
|
-
handleKeyboardEvent(this, event);
|
|
15688
|
-
};}
|
|
15689
|
-
|
|
15690
14281
|
/**
|
|
15691
14282
|
* Tasks to run when we consider a page to be hidden (via blurring and/or visibility)
|
|
15692
14283
|
*/
|
|
@@ -15718,7 +14309,7 @@ class ReplayContainer {
|
|
|
15718
14309
|
const isSessionActive = this.checkAndHandleExpiredSession();
|
|
15719
14310
|
|
|
15720
14311
|
if (!isSessionActive) {
|
|
15721
|
-
// If the user has come back to the page within
|
|
14312
|
+
// If the user has come back to the page within SESSION_IDLE_DURATION
|
|
15722
14313
|
// ms, we will re-use the existing session, otherwise create a new
|
|
15723
14314
|
// session
|
|
15724
14315
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
|
|
@@ -15766,7 +14357,7 @@ class ReplayContainer {
|
|
|
15766
14357
|
_createCustomBreadcrumb(breadcrumb) {
|
|
15767
14358
|
this.addUpdate(() => {
|
|
15768
14359
|
void addEvent(this, {
|
|
15769
|
-
type: EventType
|
|
14360
|
+
type: EventType.Custom,
|
|
15770
14361
|
timestamp: breadcrumb.timestamp || 0,
|
|
15771
14362
|
data: {
|
|
15772
14363
|
tag: 'breadcrumb',
|
|
@@ -15792,7 +14383,7 @@ class ReplayContainer {
|
|
|
15792
14383
|
* Only flush if `this.recordingMode === 'session'`
|
|
15793
14384
|
*/
|
|
15794
14385
|
_conditionalFlush() {
|
|
15795
|
-
if (this.recordingMode === '
|
|
14386
|
+
if (this.recordingMode === 'error') {
|
|
15796
14387
|
return;
|
|
15797
14388
|
}
|
|
15798
14389
|
|
|
@@ -15807,35 +14398,22 @@ class ReplayContainer {
|
|
|
15807
14398
|
this._context.errorIds.clear();
|
|
15808
14399
|
this._context.traceIds.clear();
|
|
15809
14400
|
this._context.urls = [];
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
/** Update the initial timestamp based on the buffer content. */
|
|
15813
|
-
_updateInitialTimestampFromEventBuffer() {
|
|
15814
|
-
const { session, eventBuffer } = this;
|
|
15815
|
-
if (!session || !eventBuffer) {
|
|
15816
|
-
return;
|
|
15817
|
-
}
|
|
15818
|
-
|
|
15819
|
-
// we only ever update this on the initial segment
|
|
15820
|
-
if (session.segmentId) {
|
|
15821
|
-
return;
|
|
15822
|
-
}
|
|
15823
|
-
|
|
15824
|
-
const earliestEvent = eventBuffer.getEarliestTimestamp();
|
|
15825
|
-
if (earliestEvent && earliestEvent < this._context.initialTimestamp) {
|
|
15826
|
-
this._context.initialTimestamp = earliestEvent;
|
|
15827
|
-
}
|
|
14401
|
+
this._context.earliestEvent = null;
|
|
15828
14402
|
}
|
|
15829
14403
|
|
|
15830
14404
|
/**
|
|
15831
14405
|
* Return and clear _context
|
|
15832
14406
|
*/
|
|
15833
14407
|
_popEventContext() {
|
|
14408
|
+
if (this._context.earliestEvent && this._context.earliestEvent < this._context.initialTimestamp) {
|
|
14409
|
+
this._context.initialTimestamp = this._context.earliestEvent;
|
|
14410
|
+
}
|
|
14411
|
+
|
|
15834
14412
|
const _context = {
|
|
15835
14413
|
initialTimestamp: this._context.initialTimestamp,
|
|
15836
14414
|
initialUrl: this._context.initialUrl,
|
|
15837
|
-
errorIds: Array.from(this._context.errorIds),
|
|
15838
|
-
traceIds: Array.from(this._context.traceIds),
|
|
14415
|
+
errorIds: Array.from(this._context.errorIds).filter(Boolean),
|
|
14416
|
+
traceIds: Array.from(this._context.traceIds).filter(Boolean),
|
|
15839
14417
|
urls: this._context.urls,
|
|
15840
14418
|
};
|
|
15841
14419
|
|
|
@@ -15874,9 +14452,6 @@ class ReplayContainer {
|
|
|
15874
14452
|
}
|
|
15875
14453
|
|
|
15876
14454
|
try {
|
|
15877
|
-
// This uses the data from the eventBuffer, so we need to call this before `finish()
|
|
15878
|
-
this._updateInitialTimestampFromEventBuffer();
|
|
15879
|
-
|
|
15880
14455
|
// Note this empties the event buffer regardless of outcome of sending replay
|
|
15881
14456
|
const recordingData = await this.eventBuffer.finish();
|
|
15882
14457
|
|
|
@@ -15892,6 +14467,7 @@ class ReplayContainer {
|
|
|
15892
14467
|
replayId,
|
|
15893
14468
|
recordingData,
|
|
15894
14469
|
segmentId,
|
|
14470
|
+
includeReplayStartTimestamp: segmentId === 0,
|
|
15895
14471
|
eventContext,
|
|
15896
14472
|
session: this.session,
|
|
15897
14473
|
options: this.getOptions(),
|
|
@@ -15903,7 +14479,7 @@ class ReplayContainer {
|
|
|
15903
14479
|
// This means we retried 3 times and all of them failed,
|
|
15904
14480
|
// or we ran into a problem we don't want to retry, like rate limiting.
|
|
15905
14481
|
// In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
|
|
15906
|
-
|
|
14482
|
+
this.stop('sendReplay');
|
|
15907
14483
|
|
|
15908
14484
|
const client = getCurrentHub().getClient();
|
|
15909
14485
|
|
|
@@ -15917,12 +14493,8 @@ class ReplayContainer {
|
|
|
15917
14493
|
* Flush recording data to Sentry. Creates a lock so that only a single flush
|
|
15918
14494
|
* can be active at a time. Do not call this directly.
|
|
15919
14495
|
*/
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
}
|
|
15923
|
-
|
|
15924
|
-
= {}) => {
|
|
15925
|
-
if (!this._isEnabled && !force) {
|
|
14496
|
+
__init16() {this._flush = async () => {
|
|
14497
|
+
if (!this._isEnabled) {
|
|
15926
14498
|
// This can happen if e.g. the replay was stopped because of exceeding the retry limit
|
|
15927
14499
|
return;
|
|
15928
14500
|
}
|
|
@@ -15972,7 +14544,7 @@ class ReplayContainer {
|
|
|
15972
14544
|
}
|
|
15973
14545
|
|
|
15974
14546
|
/** Handler for rrweb.record.onMutation */
|
|
15975
|
-
|
|
14547
|
+
__init17() {this._onMutationHandler = (mutations) => {
|
|
15976
14548
|
const count = mutations.length;
|
|
15977
14549
|
|
|
15978
14550
|
const mutationLimit = this._options._experiments.mutationLimit || 0;
|
|
@@ -16106,8 +14678,6 @@ function isElectronNodeRenderer() {
|
|
|
16106
14678
|
const MEDIA_SELECTORS =
|
|
16107
14679
|
'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
|
|
16108
14680
|
|
|
16109
|
-
const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
|
|
16110
|
-
|
|
16111
14681
|
let _initialized = false;
|
|
16112
14682
|
|
|
16113
14683
|
/**
|
|
@@ -16148,11 +14718,6 @@ class Replay {
|
|
|
16148
14718
|
maskAllInputs = true,
|
|
16149
14719
|
blockAllMedia = true,
|
|
16150
14720
|
|
|
16151
|
-
networkDetailAllowUrls = [],
|
|
16152
|
-
networkCaptureBodies = true,
|
|
16153
|
-
networkRequestHeaders = [],
|
|
16154
|
-
networkResponseHeaders = [],
|
|
16155
|
-
|
|
16156
14721
|
mask = [],
|
|
16157
14722
|
unmask = [],
|
|
16158
14723
|
block = [],
|
|
@@ -16211,13 +14776,6 @@ class Replay {
|
|
|
16211
14776
|
errorSampleRate,
|
|
16212
14777
|
useCompression,
|
|
16213
14778
|
blockAllMedia,
|
|
16214
|
-
maskAllInputs,
|
|
16215
|
-
maskAllText,
|
|
16216
|
-
networkDetailAllowUrls,
|
|
16217
|
-
networkCaptureBodies,
|
|
16218
|
-
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|
|
16219
|
-
networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
|
|
16220
|
-
|
|
16221
14779
|
_experiments,
|
|
16222
14780
|
};
|
|
16223
14781
|
|
|
@@ -16271,7 +14829,14 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16271
14829
|
}
|
|
16272
14830
|
|
|
16273
14831
|
/**
|
|
16274
|
-
*
|
|
14832
|
+
* We previously used to create a transaction in `setupOnce` and it would
|
|
14833
|
+
* potentially create a transaction before some native SDK integrations have run
|
|
14834
|
+
* and applied their own global event processor. An example is:
|
|
14835
|
+
* https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
14836
|
+
*
|
|
14837
|
+
* So we call `replay.setup` in next event loop as a workaround to wait for other
|
|
14838
|
+
* global event processors to finish. This is no longer needed, but keeping it
|
|
14839
|
+
* here to avoid any future issues.
|
|
16275
14840
|
*/
|
|
16276
14841
|
setupOnce() {
|
|
16277
14842
|
if (!isBrowser()) {
|
|
@@ -16280,20 +14845,12 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16280
14845
|
|
|
16281
14846
|
this._setup();
|
|
16282
14847
|
|
|
16283
|
-
//
|
|
16284
|
-
|
|
16285
|
-
// and applied their own global event processor. An example is:
|
|
16286
|
-
// https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
16287
|
-
//
|
|
16288
|
-
// So we call `this._initialize()` in next event loop as a workaround to wait for other
|
|
16289
|
-
// global event processors to finish. This is no longer needed, but keeping it
|
|
16290
|
-
// here to avoid any future issues.
|
|
16291
|
-
setTimeout(() => this._initialize());
|
|
14848
|
+
// XXX: See method comments above
|
|
14849
|
+
setTimeout(() => this.start());
|
|
16292
14850
|
}
|
|
16293
14851
|
|
|
16294
14852
|
/**
|
|
16295
|
-
*
|
|
16296
|
-
* create a new session. Will throw an error if replay is already in progress.
|
|
14853
|
+
* Initializes the plugin.
|
|
16297
14854
|
*
|
|
16298
14855
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
16299
14856
|
* PerformanceObserver, Recording, Sentry SDK, etc)
|
|
@@ -16306,64 +14863,27 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
16306
14863
|
this._replay.start();
|
|
16307
14864
|
}
|
|
16308
14865
|
|
|
16309
|
-
/**
|
|
16310
|
-
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
16311
|
-
* `replaysOnErrorSampleRate` > 0, until an error occurs.
|
|
16312
|
-
*/
|
|
16313
|
-
startBuffering() {
|
|
16314
|
-
if (!this._replay) {
|
|
16315
|
-
return;
|
|
16316
|
-
}
|
|
16317
|
-
|
|
16318
|
-
this._replay.startBuffering();
|
|
16319
|
-
}
|
|
16320
|
-
|
|
16321
14866
|
/**
|
|
16322
14867
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
16323
14868
|
* does not support a teardown
|
|
16324
14869
|
*/
|
|
16325
14870
|
stop() {
|
|
16326
14871
|
if (!this._replay) {
|
|
16327
|
-
return
|
|
16328
|
-
}
|
|
16329
|
-
|
|
16330
|
-
return this._replay.stop();
|
|
16331
|
-
}
|
|
16332
|
-
|
|
16333
|
-
/**
|
|
16334
|
-
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
16335
|
-
* Unless `continueRecording` is false, the replay will continue to record and
|
|
16336
|
-
* behave as a "session"-based replay.
|
|
16337
|
-
*
|
|
16338
|
-
* Otherwise, queue up a flush.
|
|
16339
|
-
*/
|
|
16340
|
-
flush(options) {
|
|
16341
|
-
if (!this._replay || !this._replay.isEnabled()) {
|
|
16342
|
-
return Promise.resolve();
|
|
14872
|
+
return;
|
|
16343
14873
|
}
|
|
16344
14874
|
|
|
16345
|
-
|
|
14875
|
+
this._replay.stop();
|
|
16346
14876
|
}
|
|
16347
14877
|
|
|
16348
14878
|
/**
|
|
16349
|
-
*
|
|
14879
|
+
* Immediately send all pending events.
|
|
16350
14880
|
*/
|
|
16351
|
-
|
|
14881
|
+
flush() {
|
|
16352
14882
|
if (!this._replay || !this._replay.isEnabled()) {
|
|
16353
14883
|
return;
|
|
16354
14884
|
}
|
|
16355
14885
|
|
|
16356
|
-
return this._replay.
|
|
16357
|
-
}
|
|
16358
|
-
/**
|
|
16359
|
-
* Initializes replay.
|
|
16360
|
-
*/
|
|
16361
|
-
_initialize() {
|
|
16362
|
-
if (!this._replay) {
|
|
16363
|
-
return;
|
|
16364
|
-
}
|
|
16365
|
-
|
|
16366
|
-
this._replay.initializeSampling();
|
|
14886
|
+
return this._replay.flushImmediate();
|
|
16367
14887
|
}
|
|
16368
14888
|
|
|
16369
14889
|
/** Setup the integration. */
|
|
@@ -16414,10 +14934,6 @@ function loadReplayOptionsFromClient(initialOptions) {
|
|
|
16414
14934
|
return finalOptions;
|
|
16415
14935
|
}
|
|
16416
14936
|
|
|
16417
|
-
function _getMergedNetworkHeaders(headers) {
|
|
16418
|
-
return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
|
|
16419
|
-
}
|
|
16420
|
-
|
|
16421
14937
|
/**
|
|
16422
14938
|
* Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values,
|
|
16423
14939
|
* descriptors, and functions.
|
|
@@ -16855,9 +15371,6 @@ class Postgres {
|
|
|
16855
15371
|
const span = _optionalChain([parentSpan, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
|
|
16856
15372
|
description: typeof config === 'string' ? config : (config ).text,
|
|
16857
15373
|
op: 'db',
|
|
16858
|
-
data: {
|
|
16859
|
-
'db.system': 'postgresql',
|
|
16860
|
-
},
|
|
16861
15374
|
})]);
|
|
16862
15375
|
|
|
16863
15376
|
if (typeof callback === 'function') {
|
|
@@ -16934,9 +15447,6 @@ class Mysql {constructor() { Mysql.prototype.__init.call(this); }
|
|
|
16934
15447
|
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
|
16935
15448
|
description: typeof options === 'string' ? options : (options ).sql,
|
|
16936
15449
|
op: 'db',
|
|
16937
|
-
data: {
|
|
16938
|
-
'db.system': 'mysql',
|
|
16939
|
-
},
|
|
16940
15450
|
})]);
|
|
16941
15451
|
|
|
16942
15452
|
if (typeof callback === 'function') {
|
|
@@ -17158,7 +15668,6 @@ class Mongo {
|
|
|
17158
15668
|
collectionName: collection.collectionName,
|
|
17159
15669
|
dbName: collection.dbName,
|
|
17160
15670
|
namespace: collection.namespace,
|
|
17161
|
-
'db.system': 'mongodb',
|
|
17162
15671
|
};
|
|
17163
15672
|
const spanContext = {
|
|
17164
15673
|
op: 'db',
|
|
@@ -17245,15 +15754,31 @@ class Prisma {
|
|
|
17245
15754
|
}
|
|
17246
15755
|
|
|
17247
15756
|
this._client.$use((params, next) => {
|
|
15757
|
+
const scope = getCurrentHub().getScope();
|
|
15758
|
+
const parentSpan = _optionalChain([scope, 'optionalAccess', _2 => _2.getSpan, 'call', _3 => _3()]);
|
|
15759
|
+
|
|
17248
15760
|
const action = params.action;
|
|
17249
15761
|
const model = params.model;
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
|
|
15762
|
+
|
|
15763
|
+
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
|
15764
|
+
description: model ? `${model} ${action}` : action,
|
|
15765
|
+
op: 'db.sql.prisma',
|
|
15766
|
+
})]);
|
|
15767
|
+
|
|
15768
|
+
const rv = next(params);
|
|
15769
|
+
|
|
15770
|
+
if (isThenable(rv)) {
|
|
15771
|
+
return rv.then((res) => {
|
|
15772
|
+
_optionalChain([span, 'optionalAccess', _6 => _6.finish, 'call', _7 => _7()]);
|
|
15773
|
+
return res;
|
|
15774
|
+
});
|
|
15775
|
+
}
|
|
15776
|
+
|
|
15777
|
+
_optionalChain([span, 'optionalAccess', _8 => _8.finish, 'call', _9 => _9()]);
|
|
15778
|
+
return rv;
|
|
17254
15779
|
});
|
|
17255
15780
|
}
|
|
17256
|
-
}
|
|
15781
|
+
}Prisma.__initStatic();
|
|
17257
15782
|
|
|
17258
15783
|
/** Tracing integration for graphql package */
|
|
17259
15784
|
class GraphQL {constructor() { GraphQL.prototype.__init.call(this); }
|
|
@@ -30427,7 +28952,7 @@ const configGenerator = () => {
|
|
|
30427
28952
|
let release;
|
|
30428
28953
|
try {
|
|
30429
28954
|
environment !== null && environment !== void 0 ? environment : (environment = "staging");
|
|
30430
|
-
release !== null && release !== void 0 ? release : (release = "1.1.23-binary-
|
|
28955
|
+
release !== null && release !== void 0 ? release : (release = "1.1.23-binary-006");
|
|
30431
28956
|
}
|
|
30432
28957
|
catch (_a) {
|
|
30433
28958
|
console.error('sentry configGenerator error');
|
|
@@ -43494,9 +42019,7 @@ var AsapAction = (function (_super) {
|
|
|
43494
42019
|
var actions = scheduler.actions;
|
|
43495
42020
|
if (id != null && ((_a = actions[actions.length - 1]) === null || _a === void 0 ? void 0 : _a.id) !== id) {
|
|
43496
42021
|
immediateProvider.clearImmediate(id);
|
|
43497
|
-
|
|
43498
|
-
scheduler._scheduled = undefined;
|
|
43499
|
-
}
|
|
42022
|
+
scheduler._scheduled = undefined;
|
|
43500
42023
|
}
|
|
43501
42024
|
return undefined;
|
|
43502
42025
|
};
|