@myinterview/widget-react 1.1.21-development-eca8c5c → 1.1.22-development-2bfa0c3
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/README.md +2 -6
- package/dist/cjs/index.js +483 -182
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/videoInterface.d.ts +1 -0
- package/dist/esm/index.js +483 -182
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces/videoInterface.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -2025,7 +2025,7 @@ function loadModule(moduleName) {
|
|
|
2025
2025
|
* @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization.
|
|
2026
2026
|
*/
|
|
2027
2027
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2028
|
-
function normalize(input, depth =
|
|
2028
|
+
function normalize(input, depth = 100, maxProperties = +Infinity) {
|
|
2029
2029
|
try {
|
|
2030
2030
|
// since we're at the outermost level, we don't provide a key
|
|
2031
2031
|
return visit('', input, depth, maxProperties);
|
|
@@ -2092,17 +2092,16 @@ function visit(
|
|
|
2092
2092
|
return value ;
|
|
2093
2093
|
}
|
|
2094
2094
|
|
|
2095
|
-
//
|
|
2096
|
-
//
|
|
2097
|
-
//
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
}
|
|
2095
|
+
// We can set `__sentry_override_normalization_depth__` on an object to ensure that from there
|
|
2096
|
+
// We keep a certain amount of depth.
|
|
2097
|
+
// This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state.
|
|
2098
|
+
const remainingDepth =
|
|
2099
|
+
typeof (value )['__sentry_override_normalization_depth__'] === 'number'
|
|
2100
|
+
? ((value )['__sentry_override_normalization_depth__'] )
|
|
2101
|
+
: depth;
|
|
2103
2102
|
|
|
2104
2103
|
// We're also done if we've reached the max depth
|
|
2105
|
-
if (
|
|
2104
|
+
if (remainingDepth === 0) {
|
|
2106
2105
|
// At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.
|
|
2107
2106
|
return stringified.replace('object ', '');
|
|
2108
2107
|
}
|
|
@@ -2118,7 +2117,7 @@ function visit(
|
|
|
2118
2117
|
try {
|
|
2119
2118
|
const jsonValue = valueWithToJSON.toJSON();
|
|
2120
2119
|
// We need to normalize the return value of `.toJSON()` in case it has circular references
|
|
2121
|
-
return visit('', jsonValue,
|
|
2120
|
+
return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);
|
|
2122
2121
|
} catch (err) {
|
|
2123
2122
|
// pass (The built-in `toJSON` failed, but we can still try to do it ourselves)
|
|
2124
2123
|
}
|
|
@@ -2147,7 +2146,7 @@ function visit(
|
|
|
2147
2146
|
|
|
2148
2147
|
// Recursively visit all the child nodes
|
|
2149
2148
|
const visitValue = visitable[visitKey];
|
|
2150
|
-
normalized[visitKey] = visit(visitKey, visitValue,
|
|
2149
|
+
normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);
|
|
2151
2150
|
|
|
2152
2151
|
numAdded++;
|
|
2153
2152
|
}
|
|
@@ -5797,7 +5796,7 @@ function getEventForEnvelopeItem(item, type) {
|
|
|
5797
5796
|
return Array.isArray(item) ? (item )[1] : undefined;
|
|
5798
5797
|
}
|
|
5799
5798
|
|
|
5800
|
-
const SDK_VERSION = '7.
|
|
5799
|
+
const SDK_VERSION = '7.50.0';
|
|
5801
5800
|
|
|
5802
5801
|
let originalFunctionToString;
|
|
5803
5802
|
|
|
@@ -5820,11 +5819,17 @@ class FunctionToString {constructor() { FunctionToString.prototype.__init.call(
|
|
|
5820
5819
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
5821
5820
|
originalFunctionToString = Function.prototype.toString;
|
|
5822
5821
|
|
|
5823
|
-
//
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5822
|
+
// intrinsics (like Function.prototype) might be immutable in some environments
|
|
5823
|
+
// e.g. Node with --frozen-intrinsics, XS (an embedded JavaScript engine) or SES (a JavaScript proposal)
|
|
5824
|
+
try {
|
|
5825
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5826
|
+
Function.prototype.toString = function ( ...args) {
|
|
5827
|
+
const context = getOriginalFunction(this) || this;
|
|
5828
|
+
return originalFunctionToString.apply(context, args);
|
|
5829
|
+
};
|
|
5830
|
+
} catch (e) {
|
|
5831
|
+
// ignore errors here, just don't patch this
|
|
5832
|
+
}
|
|
5828
5833
|
}
|
|
5829
5834
|
} FunctionToString.__initStatic();
|
|
5830
5835
|
|
|
@@ -8268,11 +8273,14 @@ const REPLAY_SESSION_KEY = 'sentryReplaySession';
|
|
|
8268
8273
|
const REPLAY_EVENT_NAME = 'replay_event';
|
|
8269
8274
|
const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
|
|
8270
8275
|
|
|
8271
|
-
// The idle limit for a session
|
|
8272
|
-
const
|
|
8276
|
+
// The idle limit for a session after which recording is paused.
|
|
8277
|
+
const SESSION_IDLE_PAUSE_DURATION = 300000; // 5 minutes in ms
|
|
8278
|
+
|
|
8279
|
+
// The idle limit for a session after which the session expires.
|
|
8280
|
+
const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms
|
|
8273
8281
|
|
|
8274
8282
|
// The maximum length of a session
|
|
8275
|
-
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8283
|
+
const MAX_SESSION_LIFE = 3600000; // 60 minutes in ms
|
|
8276
8284
|
|
|
8277
8285
|
/** Default flush delays */
|
|
8278
8286
|
const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
@@ -8281,7 +8289,7 @@ const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
|
8281
8289
|
const DEFAULT_FLUSH_MAX_DELAY = 5500;
|
|
8282
8290
|
|
|
8283
8291
|
/* How long to wait for error checkouts */
|
|
8284
|
-
const
|
|
8292
|
+
const BUFFER_CHECKOUT_TIME = 60000;
|
|
8285
8293
|
|
|
8286
8294
|
const RETRY_BASE_INTERVAL = 5000;
|
|
8287
8295
|
const RETRY_MAX_COUNT = 3;
|
|
@@ -8289,6 +8297,9 @@ const RETRY_MAX_COUNT = 3;
|
|
|
8289
8297
|
/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be truncated. */
|
|
8290
8298
|
const NETWORK_BODY_MAX_SIZE = 150000;
|
|
8291
8299
|
|
|
8300
|
+
/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
|
|
8301
|
+
const CONSOLE_ARG_MAX_SIZE = 5000;
|
|
8302
|
+
|
|
8292
8303
|
var NodeType$1;
|
|
8293
8304
|
(function (NodeType) {
|
|
8294
8305
|
NodeType[NodeType["Document"] = 0] = "Document";
|
|
@@ -11953,6 +11964,31 @@ function createEventBuffer({ useCompression }) {
|
|
|
11953
11964
|
return new EventBufferArray();
|
|
11954
11965
|
}
|
|
11955
11966
|
|
|
11967
|
+
/**
|
|
11968
|
+
* Removes the session from Session Storage and unsets session in replay instance
|
|
11969
|
+
*/
|
|
11970
|
+
function clearSession(replay) {
|
|
11971
|
+
deleteSession();
|
|
11972
|
+
replay.session = undefined;
|
|
11973
|
+
}
|
|
11974
|
+
|
|
11975
|
+
/**
|
|
11976
|
+
* Deletes a session from storage
|
|
11977
|
+
*/
|
|
11978
|
+
function deleteSession() {
|
|
11979
|
+
const hasSessionStorage = 'sessionStorage' in WINDOW;
|
|
11980
|
+
|
|
11981
|
+
if (!hasSessionStorage) {
|
|
11982
|
+
return;
|
|
11983
|
+
}
|
|
11984
|
+
|
|
11985
|
+
try {
|
|
11986
|
+
WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
|
|
11987
|
+
} catch (e) {
|
|
11988
|
+
// Ignore potential SecurityError exceptions
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
|
|
11956
11992
|
/**
|
|
11957
11993
|
* Given an initial timestamp and an expiry duration, checks to see if current
|
|
11958
11994
|
* time should be considered as expired.
|
|
@@ -11983,11 +12019,26 @@ function isSessionExpired(session, timeouts, targetTime = +new Date()) {
|
|
|
11983
12019
|
// First, check that maximum session length has not been exceeded
|
|
11984
12020
|
isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
|
|
11985
12021
|
// check that the idle timeout has not been exceeded (i.e. user has
|
|
11986
|
-
// performed an action within the last `
|
|
11987
|
-
isExpired(session.lastActivity, timeouts.
|
|
12022
|
+
// performed an action within the last `sessionIdleExpire` ms)
|
|
12023
|
+
isExpired(session.lastActivity, timeouts.sessionIdleExpire, targetTime)
|
|
11988
12024
|
);
|
|
11989
12025
|
}
|
|
11990
12026
|
|
|
12027
|
+
/**
|
|
12028
|
+
* Given a sample rate, returns true if replay should be sampled.
|
|
12029
|
+
*
|
|
12030
|
+
* 1.0 = 100% sampling
|
|
12031
|
+
* 0.0 = 0% sampling
|
|
12032
|
+
*/
|
|
12033
|
+
function isSampled(sampleRate) {
|
|
12034
|
+
if (sampleRate === undefined) {
|
|
12035
|
+
return false;
|
|
12036
|
+
}
|
|
12037
|
+
|
|
12038
|
+
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12039
|
+
return Math.random() < sampleRate;
|
|
12040
|
+
}
|
|
12041
|
+
|
|
11991
12042
|
/**
|
|
11992
12043
|
* Save a session to session storage.
|
|
11993
12044
|
*/
|
|
@@ -12004,21 +12055,6 @@ function saveSession(session) {
|
|
|
12004
12055
|
}
|
|
12005
12056
|
}
|
|
12006
12057
|
|
|
12007
|
-
/**
|
|
12008
|
-
* Given a sample rate, returns true if replay should be sampled.
|
|
12009
|
-
*
|
|
12010
|
-
* 1.0 = 100% sampling
|
|
12011
|
-
* 0.0 = 0% sampling
|
|
12012
|
-
*/
|
|
12013
|
-
function isSampled(sampleRate) {
|
|
12014
|
-
if (sampleRate === undefined) {
|
|
12015
|
-
return false;
|
|
12016
|
-
}
|
|
12017
|
-
|
|
12018
|
-
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12019
|
-
return Math.random() < sampleRate;
|
|
12020
|
-
}
|
|
12021
|
-
|
|
12022
12058
|
/**
|
|
12023
12059
|
* Get a session with defaults & applied sampling.
|
|
12024
12060
|
*/
|
|
@@ -12037,14 +12073,15 @@ function makeSession(session) {
|
|
|
12037
12073
|
lastActivity,
|
|
12038
12074
|
segmentId,
|
|
12039
12075
|
sampled,
|
|
12076
|
+
shouldRefresh: true,
|
|
12040
12077
|
};
|
|
12041
12078
|
}
|
|
12042
12079
|
|
|
12043
12080
|
/**
|
|
12044
12081
|
* Get the sampled status for a session based on sample rates & current sampled status.
|
|
12045
12082
|
*/
|
|
12046
|
-
function getSessionSampleType(sessionSampleRate,
|
|
12047
|
-
return isSampled(sessionSampleRate) ? 'session' :
|
|
12083
|
+
function getSessionSampleType(sessionSampleRate, allowBuffering) {
|
|
12084
|
+
return isSampled(sessionSampleRate) ? 'session' : allowBuffering ? 'buffer' : false;
|
|
12048
12085
|
}
|
|
12049
12086
|
|
|
12050
12087
|
/**
|
|
@@ -12052,8 +12089,8 @@ function getSessionSampleType(sessionSampleRate, errorSampleRate) {
|
|
|
12052
12089
|
* that all replays will be saved to as attachments. Currently, we only expect
|
|
12053
12090
|
* one of these Sentry events per "replay session".
|
|
12054
12091
|
*/
|
|
12055
|
-
function createSession({ sessionSampleRate,
|
|
12056
|
-
const sampled = getSessionSampleType(sessionSampleRate,
|
|
12092
|
+
function createSession({ sessionSampleRate, allowBuffering, stickySession = false }) {
|
|
12093
|
+
const sampled = getSessionSampleType(sessionSampleRate, allowBuffering);
|
|
12057
12094
|
const session = makeSession({
|
|
12058
12095
|
sampled,
|
|
12059
12096
|
});
|
|
@@ -12101,7 +12138,7 @@ function getSession({
|
|
|
12101
12138
|
currentSession,
|
|
12102
12139
|
stickySession,
|
|
12103
12140
|
sessionSampleRate,
|
|
12104
|
-
|
|
12141
|
+
allowBuffering,
|
|
12105
12142
|
}) {
|
|
12106
12143
|
// If session exists and is passed, use it instead of always hitting session storage
|
|
12107
12144
|
const session = currentSession || (stickySession && fetchSession());
|
|
@@ -12114,8 +12151,9 @@ function getSession({
|
|
|
12114
12151
|
|
|
12115
12152
|
if (!isExpired) {
|
|
12116
12153
|
return { type: 'saved', session };
|
|
12117
|
-
} else if (session.
|
|
12118
|
-
//
|
|
12154
|
+
} else if (!session.shouldRefresh) {
|
|
12155
|
+
// In this case, stop
|
|
12156
|
+
// This is the case if we have an error session that is completed (=triggered an error)
|
|
12119
12157
|
const discardedSession = makeSession({ sampled: false });
|
|
12120
12158
|
return { type: 'new', session: discardedSession };
|
|
12121
12159
|
} else {
|
|
@@ -12127,7 +12165,7 @@ function getSession({
|
|
|
12127
12165
|
const newSession = createSession({
|
|
12128
12166
|
stickySession,
|
|
12129
12167
|
sessionSampleRate,
|
|
12130
|
-
|
|
12168
|
+
allowBuffering,
|
|
12131
12169
|
});
|
|
12132
12170
|
|
|
12133
12171
|
return { type: 'new', session: newSession };
|
|
@@ -12161,7 +12199,7 @@ async function addEvent(
|
|
|
12161
12199
|
// page has been left open and idle for a long period of time and user
|
|
12162
12200
|
// comes back to trigger a new session. The performance entries rely on
|
|
12163
12201
|
// `performance.timeOrigin`, which is when the page first opened.
|
|
12164
|
-
if (timestampInMs + replay.timeouts.
|
|
12202
|
+
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
12165
12203
|
return null;
|
|
12166
12204
|
}
|
|
12167
12205
|
|
|
@@ -12176,7 +12214,7 @@ async function addEvent(
|
|
|
12176
12214
|
return await replay.eventBuffer.addEvent(event, isCheckout);
|
|
12177
12215
|
} catch (error) {
|
|
12178
12216
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
|
|
12179
|
-
replay.stop('addEvent');
|
|
12217
|
+
await replay.stop('addEvent');
|
|
12180
12218
|
|
|
12181
12219
|
const client = getCurrentHub().getClient();
|
|
12182
12220
|
|
|
@@ -12243,23 +12281,17 @@ function handleAfterSendEvent(replay) {
|
|
|
12243
12281
|
// Trigger error recording
|
|
12244
12282
|
// Need to be very careful that this does not cause an infinite loop
|
|
12245
12283
|
if (
|
|
12246
|
-
replay.recordingMode === '
|
|
12284
|
+
replay.recordingMode === 'buffer' &&
|
|
12247
12285
|
event.exception &&
|
|
12248
12286
|
event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing
|
|
12249
12287
|
) {
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
if (replay.stopRecording()) {
|
|
12258
|
-
// Reset all "capture on error" configuration before
|
|
12259
|
-
// starting a new recording
|
|
12260
|
-
replay.recordingMode = 'session';
|
|
12261
|
-
replay.startRecording();
|
|
12262
|
-
}
|
|
12288
|
+
if (!isSampled(replay.getOptions().errorSampleRate)) {
|
|
12289
|
+
return;
|
|
12290
|
+
}
|
|
12291
|
+
|
|
12292
|
+
setTimeout(() => {
|
|
12293
|
+
// Capture current event buffer as new replay
|
|
12294
|
+
void replay.sendBufferedReplayOrFlush();
|
|
12263
12295
|
});
|
|
12264
12296
|
}
|
|
12265
12297
|
};
|
|
@@ -13214,6 +13246,17 @@ function makeNetworkReplayBreadcrumb(
|
|
|
13214
13246
|
return result;
|
|
13215
13247
|
}
|
|
13216
13248
|
|
|
13249
|
+
/** Build the request or response part of a replay network breadcrumb that was skipped. */
|
|
13250
|
+
function buildSkippedNetworkRequestOrResponse(bodySize) {
|
|
13251
|
+
return {
|
|
13252
|
+
headers: {},
|
|
13253
|
+
size: bodySize,
|
|
13254
|
+
_meta: {
|
|
13255
|
+
warnings: ['URL_SKIPPED'],
|
|
13256
|
+
},
|
|
13257
|
+
};
|
|
13258
|
+
}
|
|
13259
|
+
|
|
13217
13260
|
/** Build the request or response part of a replay network breadcrumb. */
|
|
13218
13261
|
function buildNetworkRequestOrResponse(
|
|
13219
13262
|
headers,
|
|
@@ -13294,8 +13337,8 @@ function normalizeNetworkBody(body)
|
|
|
13294
13337
|
};
|
|
13295
13338
|
} catch (e3) {
|
|
13296
13339
|
return {
|
|
13297
|
-
body,
|
|
13298
|
-
warnings: ['INVALID_JSON'],
|
|
13340
|
+
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13341
|
+
warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
|
|
13299
13342
|
};
|
|
13300
13343
|
}
|
|
13301
13344
|
}
|
|
@@ -13314,6 +13357,11 @@ function _strIsProbablyJson(str) {
|
|
|
13314
13357
|
return (first === '[' && last === ']') || (first === '{' && last === '}');
|
|
13315
13358
|
}
|
|
13316
13359
|
|
|
13360
|
+
/** Match an URL against a list of strings/Regex. */
|
|
13361
|
+
function urlMatches(url, urls) {
|
|
13362
|
+
return stringMatchesSomePattern(url, urls);
|
|
13363
|
+
}
|
|
13364
|
+
|
|
13317
13365
|
/**
|
|
13318
13366
|
* Capture a fetch breadcrumb to a replay.
|
|
13319
13367
|
* This adds additional data (where approriate).
|
|
@@ -13373,33 +13421,37 @@ async function _prepareFetchData(
|
|
|
13373
13421
|
const {
|
|
13374
13422
|
url,
|
|
13375
13423
|
method,
|
|
13376
|
-
status_code: statusCode,
|
|
13424
|
+
status_code: statusCode = 0,
|
|
13377
13425
|
request_body_size: requestBodySize,
|
|
13378
13426
|
response_body_size: responseBodySize,
|
|
13379
13427
|
} = breadcrumb.data;
|
|
13380
13428
|
|
|
13381
|
-
const
|
|
13382
|
-
|
|
13429
|
+
const captureDetails = urlMatches(url, options.networkDetailAllowUrls);
|
|
13430
|
+
|
|
13431
|
+
const request = captureDetails
|
|
13432
|
+
? _getRequestInfo(options, hint.input, requestBodySize)
|
|
13433
|
+
: buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13434
|
+
const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize);
|
|
13383
13435
|
|
|
13384
13436
|
return {
|
|
13385
13437
|
startTimestamp,
|
|
13386
13438
|
endTimestamp,
|
|
13387
13439
|
url,
|
|
13388
13440
|
method,
|
|
13389
|
-
statusCode
|
|
13441
|
+
statusCode,
|
|
13390
13442
|
request,
|
|
13391
13443
|
response,
|
|
13392
13444
|
};
|
|
13393
13445
|
}
|
|
13394
13446
|
|
|
13395
13447
|
function _getRequestInfo(
|
|
13396
|
-
{
|
|
13448
|
+
{ networkCaptureBodies, networkRequestHeaders },
|
|
13397
13449
|
input,
|
|
13398
13450
|
requestBodySize,
|
|
13399
13451
|
) {
|
|
13400
|
-
const headers = getRequestHeaders(input,
|
|
13452
|
+
const headers = getRequestHeaders(input, networkRequestHeaders);
|
|
13401
13453
|
|
|
13402
|
-
if (!
|
|
13454
|
+
if (!networkCaptureBodies) {
|
|
13403
13455
|
return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
|
|
13404
13456
|
}
|
|
13405
13457
|
|
|
@@ -13410,19 +13462,24 @@ function _getRequestInfo(
|
|
|
13410
13462
|
}
|
|
13411
13463
|
|
|
13412
13464
|
async function _getResponseInfo(
|
|
13465
|
+
captureDetails,
|
|
13413
13466
|
{
|
|
13414
|
-
|
|
13467
|
+
networkCaptureBodies,
|
|
13415
13468
|
textEncoder,
|
|
13416
|
-
|
|
13469
|
+
networkResponseHeaders,
|
|
13417
13470
|
}
|
|
13418
13471
|
|
|
13419
13472
|
,
|
|
13420
13473
|
response,
|
|
13421
13474
|
responseBodySize,
|
|
13422
13475
|
) {
|
|
13423
|
-
|
|
13476
|
+
if (!captureDetails && responseBodySize !== undefined) {
|
|
13477
|
+
return buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
13478
|
+
}
|
|
13424
13479
|
|
|
13425
|
-
|
|
13480
|
+
const headers = getAllHeaders(response.headers, networkResponseHeaders);
|
|
13481
|
+
|
|
13482
|
+
if (!networkCaptureBodies && responseBodySize !== undefined) {
|
|
13426
13483
|
return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
|
|
13427
13484
|
}
|
|
13428
13485
|
|
|
@@ -13437,7 +13494,11 @@ async function _getResponseInfo(
|
|
|
13437
13494
|
? getBodySize(bodyText, textEncoder)
|
|
13438
13495
|
: responseBodySize;
|
|
13439
13496
|
|
|
13440
|
-
if (
|
|
13497
|
+
if (!captureDetails) {
|
|
13498
|
+
return buildSkippedNetworkRequestOrResponse(size);
|
|
13499
|
+
}
|
|
13500
|
+
|
|
13501
|
+
if (networkCaptureBodies) {
|
|
13441
13502
|
return buildNetworkRequestOrResponse(headers, size, bodyText);
|
|
13442
13503
|
}
|
|
13443
13504
|
|
|
@@ -13570,28 +13631,44 @@ function _prepareXhrData(
|
|
|
13570
13631
|
const {
|
|
13571
13632
|
url,
|
|
13572
13633
|
method,
|
|
13573
|
-
status_code: statusCode,
|
|
13634
|
+
status_code: statusCode = 0,
|
|
13574
13635
|
request_body_size: requestBodySize,
|
|
13575
13636
|
response_body_size: responseBodySize,
|
|
13576
13637
|
} = breadcrumb.data;
|
|
13577
13638
|
|
|
13578
|
-
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
13579
|
-
const requestHeaders = xhrInfo ? getAllowedHeaders(xhrInfo.request_headers, options.requestHeaders) : {};
|
|
13580
|
-
const responseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.responseHeaders);
|
|
13581
|
-
|
|
13582
13639
|
if (!url) {
|
|
13583
13640
|
return null;
|
|
13584
13641
|
}
|
|
13585
13642
|
|
|
13643
|
+
if (!urlMatches(url, options.networkDetailAllowUrls)) {
|
|
13644
|
+
const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13645
|
+
const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
13646
|
+
return {
|
|
13647
|
+
startTimestamp,
|
|
13648
|
+
endTimestamp,
|
|
13649
|
+
url,
|
|
13650
|
+
method,
|
|
13651
|
+
statusCode,
|
|
13652
|
+
request,
|
|
13653
|
+
response,
|
|
13654
|
+
};
|
|
13655
|
+
}
|
|
13656
|
+
|
|
13657
|
+
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
13658
|
+
const networkRequestHeaders = xhrInfo
|
|
13659
|
+
? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
|
|
13660
|
+
: {};
|
|
13661
|
+
const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
|
|
13662
|
+
|
|
13586
13663
|
const request = buildNetworkRequestOrResponse(
|
|
13587
|
-
|
|
13664
|
+
networkRequestHeaders,
|
|
13588
13665
|
requestBodySize,
|
|
13589
|
-
options.
|
|
13666
|
+
options.networkCaptureBodies ? getBodyString(input) : undefined,
|
|
13590
13667
|
);
|
|
13591
13668
|
const response = buildNetworkRequestOrResponse(
|
|
13592
|
-
|
|
13669
|
+
networkResponseHeaders,
|
|
13593
13670
|
responseBodySize,
|
|
13594
|
-
options.
|
|
13671
|
+
options.networkCaptureBodies ? hint.xhr.responseText : undefined,
|
|
13595
13672
|
);
|
|
13596
13673
|
|
|
13597
13674
|
return {
|
|
@@ -13599,7 +13676,7 @@ function _prepareXhrData(
|
|
|
13599
13676
|
endTimestamp,
|
|
13600
13677
|
url,
|
|
13601
13678
|
method,
|
|
13602
|
-
statusCode
|
|
13679
|
+
statusCode,
|
|
13603
13680
|
request,
|
|
13604
13681
|
response,
|
|
13605
13682
|
};
|
|
@@ -13631,10 +13708,16 @@ function handleNetworkBreadcrumbs(replay) {
|
|
|
13631
13708
|
try {
|
|
13632
13709
|
const textEncoder = new TextEncoder();
|
|
13633
13710
|
|
|
13711
|
+
const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
|
|
13712
|
+
replay.getOptions();
|
|
13713
|
+
|
|
13634
13714
|
const options = {
|
|
13635
13715
|
replay,
|
|
13636
13716
|
textEncoder,
|
|
13637
|
-
|
|
13717
|
+
networkDetailAllowUrls,
|
|
13718
|
+
networkCaptureBodies,
|
|
13719
|
+
networkRequestHeaders,
|
|
13720
|
+
networkResponseHeaders,
|
|
13638
13721
|
};
|
|
13639
13722
|
|
|
13640
13723
|
if (client && client.on) {
|
|
@@ -13742,9 +13825,66 @@ function handleScope(scope) {
|
|
|
13742
13825
|
return null;
|
|
13743
13826
|
}
|
|
13744
13827
|
|
|
13828
|
+
if (newBreadcrumb.category === 'console') {
|
|
13829
|
+
return normalizeConsoleBreadcrumb(newBreadcrumb);
|
|
13830
|
+
}
|
|
13831
|
+
|
|
13745
13832
|
return createBreadcrumb(newBreadcrumb);
|
|
13746
13833
|
}
|
|
13747
13834
|
|
|
13835
|
+
/** exported for tests only */
|
|
13836
|
+
function normalizeConsoleBreadcrumb(breadcrumb) {
|
|
13837
|
+
const args = breadcrumb.data && breadcrumb.data.arguments;
|
|
13838
|
+
|
|
13839
|
+
if (!Array.isArray(args) || args.length === 0) {
|
|
13840
|
+
return createBreadcrumb(breadcrumb);
|
|
13841
|
+
}
|
|
13842
|
+
|
|
13843
|
+
let isTruncated = false;
|
|
13844
|
+
|
|
13845
|
+
// Avoid giant args captures
|
|
13846
|
+
const normalizedArgs = args.map(arg => {
|
|
13847
|
+
if (!arg) {
|
|
13848
|
+
return arg;
|
|
13849
|
+
}
|
|
13850
|
+
if (typeof arg === 'string') {
|
|
13851
|
+
if (arg.length > CONSOLE_ARG_MAX_SIZE) {
|
|
13852
|
+
isTruncated = true;
|
|
13853
|
+
return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
|
|
13854
|
+
}
|
|
13855
|
+
|
|
13856
|
+
return arg;
|
|
13857
|
+
}
|
|
13858
|
+
if (typeof arg === 'object') {
|
|
13859
|
+
try {
|
|
13860
|
+
const normalizedArg = normalize(arg, 7);
|
|
13861
|
+
const stringified = JSON.stringify(normalizedArg);
|
|
13862
|
+
if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
|
|
13863
|
+
const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
|
|
13864
|
+
const json = JSON.parse(fixedJson);
|
|
13865
|
+
// We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
|
|
13866
|
+
isTruncated = true;
|
|
13867
|
+
return json;
|
|
13868
|
+
}
|
|
13869
|
+
return normalizedArg;
|
|
13870
|
+
} catch (e) {
|
|
13871
|
+
// fall back to default
|
|
13872
|
+
}
|
|
13873
|
+
}
|
|
13874
|
+
|
|
13875
|
+
return arg;
|
|
13876
|
+
});
|
|
13877
|
+
|
|
13878
|
+
return createBreadcrumb({
|
|
13879
|
+
...breadcrumb,
|
|
13880
|
+
data: {
|
|
13881
|
+
...breadcrumb.data,
|
|
13882
|
+
arguments: normalizedArgs,
|
|
13883
|
+
...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
|
|
13884
|
+
},
|
|
13885
|
+
});
|
|
13886
|
+
}
|
|
13887
|
+
|
|
13748
13888
|
/**
|
|
13749
13889
|
* Add global listeners that cannot be removed.
|
|
13750
13890
|
*/
|
|
@@ -13769,7 +13909,7 @@ function addGlobalListeners(replay) {
|
|
|
13769
13909
|
client.on('afterSendEvent', handleAfterSendEvent(replay));
|
|
13770
13910
|
client.on('createDsc', (dsc) => {
|
|
13771
13911
|
const replayId = replay.getSessionId();
|
|
13772
|
-
if (replayId) {
|
|
13912
|
+
if (replayId && replay.isEnabled()) {
|
|
13773
13913
|
dsc.replay_id = replayId;
|
|
13774
13914
|
}
|
|
13775
13915
|
});
|
|
@@ -14077,7 +14217,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14077
14217
|
// when an error occurs. Clear any state that happens before this current
|
|
14078
14218
|
// checkout. This needs to happen before `addEvent()` which updates state
|
|
14079
14219
|
// dependent on this reset.
|
|
14080
|
-
if (replay.recordingMode === '
|
|
14220
|
+
if (replay.recordingMode === 'buffer' && isCheckout) {
|
|
14081
14221
|
replay.setInitialState();
|
|
14082
14222
|
}
|
|
14083
14223
|
|
|
@@ -14103,7 +14243,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14103
14243
|
|
|
14104
14244
|
// See note above re: session start needs to reflect the most recent
|
|
14105
14245
|
// checkout.
|
|
14106
|
-
if (replay.recordingMode === '
|
|
14246
|
+
if (replay.recordingMode === 'buffer' && replay.session) {
|
|
14107
14247
|
const { earliestEvent } = replay.getContext();
|
|
14108
14248
|
if (earliestEvent) {
|
|
14109
14249
|
replay.session.started = earliestEvent;
|
|
@@ -14452,9 +14592,11 @@ class ReplayContainer {
|
|
|
14452
14592
|
__init2() {this.performanceEvents = [];}
|
|
14453
14593
|
|
|
14454
14594
|
/**
|
|
14455
|
-
* Recording can happen in one of
|
|
14456
|
-
*
|
|
14457
|
-
*
|
|
14595
|
+
* Recording can happen in one of three modes:
|
|
14596
|
+
* - session: Record the whole session, sending it continuously
|
|
14597
|
+
* - buffer: Always keep the last 60s of recording, requires:
|
|
14598
|
+
* - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
|
|
14599
|
+
* - or calling `flush()` to send the replay
|
|
14458
14600
|
*/
|
|
14459
14601
|
__init3() {this.recordingMode = 'session';}
|
|
14460
14602
|
|
|
@@ -14463,7 +14605,8 @@ class ReplayContainer {
|
|
|
14463
14605
|
* @hidden
|
|
14464
14606
|
*/
|
|
14465
14607
|
__init4() {this.timeouts = {
|
|
14466
|
-
|
|
14608
|
+
sessionIdlePause: SESSION_IDLE_PAUSE_DURATION,
|
|
14609
|
+
sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
|
|
14467
14610
|
maxSessionLife: MAX_SESSION_LIFE,
|
|
14468
14611
|
}; }
|
|
14469
14612
|
|
|
@@ -14524,8 +14667,6 @@ class ReplayContainer {
|
|
|
14524
14667
|
this._debouncedFlush = debounce(() => this._flush(), this._options.flushMinDelay, {
|
|
14525
14668
|
maxWait: this._options.flushMaxDelay,
|
|
14526
14669
|
});
|
|
14527
|
-
|
|
14528
|
-
this._experimentalOptions = _getExperimentalOptions(options);
|
|
14529
14670
|
}
|
|
14530
14671
|
|
|
14531
14672
|
/** Get the event context. */
|
|
@@ -14549,58 +14690,102 @@ class ReplayContainer {
|
|
|
14549
14690
|
}
|
|
14550
14691
|
|
|
14551
14692
|
/**
|
|
14552
|
-
*
|
|
14553
|
-
*
|
|
14554
|
-
* @hidden
|
|
14693
|
+
* Initializes the plugin based on sampling configuration. Should not be
|
|
14694
|
+
* called outside of constructor.
|
|
14555
14695
|
*/
|
|
14556
|
-
|
|
14557
|
-
|
|
14696
|
+
initializeSampling() {
|
|
14697
|
+
const { errorSampleRate, sessionSampleRate } = this._options;
|
|
14698
|
+
|
|
14699
|
+
// If neither sample rate is > 0, then do nothing - user will need to call one of
|
|
14700
|
+
// `start()` or `startBuffering` themselves.
|
|
14701
|
+
if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
|
|
14702
|
+
return;
|
|
14703
|
+
}
|
|
14704
|
+
|
|
14705
|
+
// Otherwise if there is _any_ sample rate set, try to load an existing
|
|
14706
|
+
// session, or create a new one.
|
|
14707
|
+
const isSessionSampled = this._loadAndCheckSession();
|
|
14708
|
+
|
|
14709
|
+
if (!isSessionSampled) {
|
|
14710
|
+
// This should only occur if `errorSampleRate` is 0 and was unsampled for
|
|
14711
|
+
// session-based replay. In this case there is nothing to do.
|
|
14712
|
+
return;
|
|
14713
|
+
}
|
|
14714
|
+
|
|
14715
|
+
if (!this.session) {
|
|
14716
|
+
// This should not happen, something wrong has occurred
|
|
14717
|
+
this._handleException(new Error('Unable to initialize and create session'));
|
|
14718
|
+
return;
|
|
14719
|
+
}
|
|
14720
|
+
|
|
14721
|
+
if (this.session.sampled && this.session.sampled !== 'session') {
|
|
14722
|
+
// If not sampled as session-based, then recording mode will be `buffer`
|
|
14723
|
+
// Note that we don't explicitly check if `sampled === 'buffer'` because we
|
|
14724
|
+
// could have sessions from Session storage that are still `error` from
|
|
14725
|
+
// prior SDK version.
|
|
14726
|
+
this.recordingMode = 'buffer';
|
|
14727
|
+
}
|
|
14728
|
+
|
|
14729
|
+
this._initializeRecording();
|
|
14558
14730
|
}
|
|
14559
14731
|
|
|
14560
14732
|
/**
|
|
14561
|
-
*
|
|
14733
|
+
* Start a replay regardless of sampling rate. Calling this will always
|
|
14734
|
+
* create a new session. Will throw an error if replay is already in progress.
|
|
14562
14735
|
*
|
|
14563
14736
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
14564
14737
|
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
14565
14738
|
*/
|
|
14566
14739
|
start() {
|
|
14567
|
-
this.
|
|
14568
|
-
|
|
14569
|
-
if (!this._loadAndCheckSession()) {
|
|
14570
|
-
return;
|
|
14740
|
+
if (this._isEnabled && this.recordingMode === 'session') {
|
|
14741
|
+
throw new Error('Replay recording is already in progress');
|
|
14571
14742
|
}
|
|
14572
14743
|
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
this._handleException(new Error('No session found'));
|
|
14576
|
-
return;
|
|
14744
|
+
if (this._isEnabled && this.recordingMode === 'buffer') {
|
|
14745
|
+
throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
|
|
14577
14746
|
}
|
|
14578
14747
|
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14748
|
+
const previousSessionId = this.session && this.session.id;
|
|
14749
|
+
|
|
14750
|
+
const { session } = getSession({
|
|
14751
|
+
timeouts: this.timeouts,
|
|
14752
|
+
stickySession: Boolean(this._options.stickySession),
|
|
14753
|
+
currentSession: this.session,
|
|
14754
|
+
// This is intentional: create a new session-based replay when calling `start()`
|
|
14755
|
+
sessionSampleRate: 1,
|
|
14756
|
+
allowBuffering: false,
|
|
14757
|
+
});
|
|
14583
14758
|
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
14759
|
+
session.previousSessionId = previousSessionId;
|
|
14760
|
+
this.session = session;
|
|
14761
|
+
|
|
14762
|
+
this._initializeRecording();
|
|
14763
|
+
}
|
|
14764
|
+
|
|
14765
|
+
/**
|
|
14766
|
+
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
14767
|
+
* `replaysOnErrorSampleRate` > 0, an error occurs.
|
|
14768
|
+
*/
|
|
14769
|
+
startBuffering() {
|
|
14770
|
+
if (this._isEnabled) {
|
|
14771
|
+
throw new Error('Replay recording is already in progress');
|
|
14588
14772
|
}
|
|
14589
14773
|
|
|
14590
|
-
|
|
14591
|
-
// should treat it as an activity
|
|
14592
|
-
this._updateSessionActivity();
|
|
14774
|
+
const previousSessionId = this.session && this.session.id;
|
|
14593
14775
|
|
|
14594
|
-
|
|
14595
|
-
|
|
14776
|
+
const { session } = getSession({
|
|
14777
|
+
timeouts: this.timeouts,
|
|
14778
|
+
stickySession: Boolean(this._options.stickySession),
|
|
14779
|
+
currentSession: this.session,
|
|
14780
|
+
sessionSampleRate: 0,
|
|
14781
|
+
allowBuffering: true,
|
|
14596
14782
|
});
|
|
14597
14783
|
|
|
14598
|
-
|
|
14599
|
-
|
|
14600
|
-
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
14601
|
-
this._isEnabled = true;
|
|
14784
|
+
session.previousSessionId = previousSessionId;
|
|
14785
|
+
this.session = session;
|
|
14602
14786
|
|
|
14603
|
-
this.
|
|
14787
|
+
this.recordingMode = 'buffer';
|
|
14788
|
+
this._initializeRecording();
|
|
14604
14789
|
}
|
|
14605
14790
|
|
|
14606
14791
|
/**
|
|
@@ -14615,7 +14800,7 @@ class ReplayContainer {
|
|
|
14615
14800
|
// When running in error sampling mode, we need to overwrite `checkoutEveryNms`
|
|
14616
14801
|
// Without this, it would record forever, until an error happens, which we don't want
|
|
14617
14802
|
// instead, we'll always keep the last 60 seconds of replay before an error happened
|
|
14618
|
-
...(this.recordingMode === '
|
|
14803
|
+
...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
|
|
14619
14804
|
emit: getHandleRecordingEmit(this),
|
|
14620
14805
|
onMutation: this._onMutationHandler,
|
|
14621
14806
|
});
|
|
@@ -14626,17 +14811,18 @@ class ReplayContainer {
|
|
|
14626
14811
|
|
|
14627
14812
|
/**
|
|
14628
14813
|
* Stops the recording, if it was running.
|
|
14629
|
-
*
|
|
14814
|
+
*
|
|
14815
|
+
* Returns true if it was previously stopped, or is now stopped,
|
|
14816
|
+
* otherwise false.
|
|
14630
14817
|
*/
|
|
14631
14818
|
stopRecording() {
|
|
14632
14819
|
try {
|
|
14633
14820
|
if (this._stopRecording) {
|
|
14634
14821
|
this._stopRecording();
|
|
14635
14822
|
this._stopRecording = undefined;
|
|
14636
|
-
return true;
|
|
14637
14823
|
}
|
|
14638
14824
|
|
|
14639
|
-
return
|
|
14825
|
+
return true;
|
|
14640
14826
|
} catch (err) {
|
|
14641
14827
|
this._handleException(err);
|
|
14642
14828
|
return false;
|
|
@@ -14647,7 +14833,7 @@ class ReplayContainer {
|
|
|
14647
14833
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
14648
14834
|
* does not support a teardown
|
|
14649
14835
|
*/
|
|
14650
|
-
stop(reason) {
|
|
14836
|
+
async stop(reason) {
|
|
14651
14837
|
if (!this._isEnabled) {
|
|
14652
14838
|
return;
|
|
14653
14839
|
}
|
|
@@ -14663,12 +14849,24 @@ class ReplayContainer {
|
|
|
14663
14849
|
log(msg);
|
|
14664
14850
|
}
|
|
14665
14851
|
|
|
14852
|
+
// We can't move `_isEnabled` after awaiting a flush, otherwise we can
|
|
14853
|
+
// enter into an infinite loop when `stop()` is called while flushing.
|
|
14666
14854
|
this._isEnabled = false;
|
|
14667
14855
|
this._removeListeners();
|
|
14668
14856
|
this.stopRecording();
|
|
14857
|
+
|
|
14858
|
+
this._debouncedFlush.cancel();
|
|
14859
|
+
// See comment above re: `_isEnabled`, we "force" a flush, ignoring the
|
|
14860
|
+
// `_isEnabled` state of the plugin since it was disabled above.
|
|
14861
|
+
await this._flush({ force: true });
|
|
14862
|
+
|
|
14863
|
+
// After flush, destroy event buffer
|
|
14669
14864
|
this.eventBuffer && this.eventBuffer.destroy();
|
|
14670
14865
|
this.eventBuffer = null;
|
|
14671
|
-
|
|
14866
|
+
|
|
14867
|
+
// Clear session from session storage, note this means if a new session
|
|
14868
|
+
// is started after, it will not have `previousSessionId`
|
|
14869
|
+
clearSession(this);
|
|
14672
14870
|
} catch (err) {
|
|
14673
14871
|
this._handleException(err);
|
|
14674
14872
|
}
|
|
@@ -14699,6 +14897,45 @@ class ReplayContainer {
|
|
|
14699
14897
|
this.startRecording();
|
|
14700
14898
|
}
|
|
14701
14899
|
|
|
14900
|
+
/**
|
|
14901
|
+
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
14902
|
+
* Unless `continueRecording` is false, the replay will continue to record and
|
|
14903
|
+
* behave as a "session"-based replay.
|
|
14904
|
+
*
|
|
14905
|
+
* Otherwise, queue up a flush.
|
|
14906
|
+
*/
|
|
14907
|
+
async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
|
|
14908
|
+
if (this.recordingMode === 'session') {
|
|
14909
|
+
return this.flushImmediate();
|
|
14910
|
+
}
|
|
14911
|
+
|
|
14912
|
+
// Allow flush to complete before resuming as a session recording, otherwise
|
|
14913
|
+
// the checkout from `startRecording` may be included in the payload.
|
|
14914
|
+
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
14915
|
+
// than the session replay.
|
|
14916
|
+
await this.flushImmediate();
|
|
14917
|
+
|
|
14918
|
+
const hasStoppedRecording = this.stopRecording();
|
|
14919
|
+
|
|
14920
|
+
if (!continueRecording || !hasStoppedRecording) {
|
|
14921
|
+
return;
|
|
14922
|
+
}
|
|
14923
|
+
|
|
14924
|
+
// Re-start recording, but in "session" recording mode
|
|
14925
|
+
|
|
14926
|
+
// Reset all "capture on error" configuration before
|
|
14927
|
+
// starting a new recording
|
|
14928
|
+
this.recordingMode = 'session';
|
|
14929
|
+
|
|
14930
|
+
// Once this session ends, we do not want to refresh it
|
|
14931
|
+
if (this.session) {
|
|
14932
|
+
this.session.shouldRefresh = false;
|
|
14933
|
+
this._maybeSaveSession();
|
|
14934
|
+
}
|
|
14935
|
+
|
|
14936
|
+
this.startRecording();
|
|
14937
|
+
}
|
|
14938
|
+
|
|
14702
14939
|
/**
|
|
14703
14940
|
* We want to batch uploads of replay events. Save events only if
|
|
14704
14941
|
* `<flushMinDelay>` milliseconds have elapsed since the last event
|
|
@@ -14708,12 +14945,12 @@ class ReplayContainer {
|
|
|
14708
14945
|
* processing and hand back control to caller.
|
|
14709
14946
|
*/
|
|
14710
14947
|
addUpdate(cb) {
|
|
14711
|
-
// We need to always run `cb` (e.g. in the case of `this.recordingMode == '
|
|
14948
|
+
// We need to always run `cb` (e.g. in the case of `this.recordingMode == 'buffer'`)
|
|
14712
14949
|
const cbResult = cb();
|
|
14713
14950
|
|
|
14714
14951
|
// If this option is turned on then we will only want to call `flush`
|
|
14715
14952
|
// explicitly
|
|
14716
|
-
if (this.recordingMode === '
|
|
14953
|
+
if (this.recordingMode === 'buffer') {
|
|
14717
14954
|
return;
|
|
14718
14955
|
}
|
|
14719
14956
|
|
|
@@ -14785,12 +15022,12 @@ class ReplayContainer {
|
|
|
14785
15022
|
const oldSessionId = this.getSessionId();
|
|
14786
15023
|
|
|
14787
15024
|
// Prevent starting a new session if the last user activity is older than
|
|
14788
|
-
//
|
|
15025
|
+
// SESSION_IDLE_PAUSE_DURATION. Otherwise non-user activity can trigger a new
|
|
14789
15026
|
// session+recording. This creates noisy replays that do not have much
|
|
14790
15027
|
// content in them.
|
|
14791
15028
|
if (
|
|
14792
15029
|
this._lastActivity &&
|
|
14793
|
-
isExpired(this._lastActivity, this.timeouts.
|
|
15030
|
+
isExpired(this._lastActivity, this.timeouts.sessionIdlePause) &&
|
|
14794
15031
|
this.session &&
|
|
14795
15032
|
this.session.sampled === 'session'
|
|
14796
15033
|
) {
|
|
@@ -14840,6 +15077,30 @@ class ReplayContainer {
|
|
|
14840
15077
|
this._context.urls.push(url);
|
|
14841
15078
|
}
|
|
14842
15079
|
|
|
15080
|
+
/**
|
|
15081
|
+
* Initialize and start all listeners to varying events (DOM,
|
|
15082
|
+
* Performance Observer, Recording, Sentry SDK, etc)
|
|
15083
|
+
*/
|
|
15084
|
+
_initializeRecording() {
|
|
15085
|
+
this.setInitialState();
|
|
15086
|
+
|
|
15087
|
+
// this method is generally called on page load or manually - in both cases
|
|
15088
|
+
// we should treat it as an activity
|
|
15089
|
+
this._updateSessionActivity();
|
|
15090
|
+
|
|
15091
|
+
this.eventBuffer = createEventBuffer({
|
|
15092
|
+
useCompression: this._options.useCompression,
|
|
15093
|
+
});
|
|
15094
|
+
|
|
15095
|
+
this._removeListeners();
|
|
15096
|
+
this._addListeners();
|
|
15097
|
+
|
|
15098
|
+
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
15099
|
+
this._isEnabled = true;
|
|
15100
|
+
|
|
15101
|
+
this.startRecording();
|
|
15102
|
+
}
|
|
15103
|
+
|
|
14843
15104
|
/** A wrapper to conditionally capture exceptions. */
|
|
14844
15105
|
_handleException(error) {
|
|
14845
15106
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
|
|
@@ -14859,7 +15120,7 @@ class ReplayContainer {
|
|
|
14859
15120
|
stickySession: Boolean(this._options.stickySession),
|
|
14860
15121
|
currentSession: this.session,
|
|
14861
15122
|
sessionSampleRate: this._options.sessionSampleRate,
|
|
14862
|
-
|
|
15123
|
+
allowBuffering: this._options.errorSampleRate > 0,
|
|
14863
15124
|
});
|
|
14864
15125
|
|
|
14865
15126
|
// If session was newly created (i.e. was not loaded from storage), then
|
|
@@ -14876,7 +15137,7 @@ class ReplayContainer {
|
|
|
14876
15137
|
this.session = session;
|
|
14877
15138
|
|
|
14878
15139
|
if (!this.session.sampled) {
|
|
14879
|
-
this.stop('session unsampled');
|
|
15140
|
+
void this.stop('session unsampled');
|
|
14880
15141
|
return false;
|
|
14881
15142
|
}
|
|
14882
15143
|
|
|
@@ -15000,7 +15261,7 @@ class ReplayContainer {
|
|
|
15000
15261
|
const isSessionActive = this.checkAndHandleExpiredSession();
|
|
15001
15262
|
|
|
15002
15263
|
if (!isSessionActive) {
|
|
15003
|
-
// If the user has come back to the page within
|
|
15264
|
+
// If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION
|
|
15004
15265
|
// ms, we will re-use the existing session, otherwise create a new
|
|
15005
15266
|
// session
|
|
15006
15267
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
|
|
@@ -15074,7 +15335,7 @@ class ReplayContainer {
|
|
|
15074
15335
|
* Only flush if `this.recordingMode === 'session'`
|
|
15075
15336
|
*/
|
|
15076
15337
|
_conditionalFlush() {
|
|
15077
|
-
if (this.recordingMode === '
|
|
15338
|
+
if (this.recordingMode === 'buffer') {
|
|
15078
15339
|
return;
|
|
15079
15340
|
}
|
|
15080
15341
|
|
|
@@ -15169,7 +15430,7 @@ class ReplayContainer {
|
|
|
15169
15430
|
// This means we retried 3 times and all of them failed,
|
|
15170
15431
|
// or we ran into a problem we don't want to retry, like rate limiting.
|
|
15171
15432
|
// In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
|
|
15172
|
-
this.stop('sendReplay');
|
|
15433
|
+
void this.stop('sendReplay');
|
|
15173
15434
|
|
|
15174
15435
|
const client = getCurrentHub().getClient();
|
|
15175
15436
|
|
|
@@ -15183,8 +15444,12 @@ class ReplayContainer {
|
|
|
15183
15444
|
* Flush recording data to Sentry. Creates a lock so that only a single flush
|
|
15184
15445
|
* can be active at a time. Do not call this directly.
|
|
15185
15446
|
*/
|
|
15186
|
-
__init16() {this._flush = async (
|
|
15187
|
-
|
|
15447
|
+
__init16() {this._flush = async ({
|
|
15448
|
+
force = false,
|
|
15449
|
+
}
|
|
15450
|
+
|
|
15451
|
+
= {}) => {
|
|
15452
|
+
if (!this._isEnabled && !force) {
|
|
15188
15453
|
// This can happen if e.g. the replay was stopped because of exceeding the retry limit
|
|
15189
15454
|
return;
|
|
15190
15455
|
}
|
|
@@ -15265,23 +15530,6 @@ class ReplayContainer {
|
|
|
15265
15530
|
};}
|
|
15266
15531
|
}
|
|
15267
15532
|
|
|
15268
|
-
function _getExperimentalOptions(options) {
|
|
15269
|
-
const requestHeaders = options._experiments.captureRequestHeaders || [];
|
|
15270
|
-
const responseHeaders = options._experiments.captureResponseHeaders || [];
|
|
15271
|
-
const captureBodies = options._experiments.captureNetworkBodies || false;
|
|
15272
|
-
|
|
15273
|
-
// Add defaults
|
|
15274
|
-
const defaultHeaders = ['content-length', 'content-type', 'accept'];
|
|
15275
|
-
|
|
15276
|
-
return {
|
|
15277
|
-
network: {
|
|
15278
|
-
captureBodies,
|
|
15279
|
-
requestHeaders: [...defaultHeaders, ...requestHeaders.map(header => header.toLowerCase())],
|
|
15280
|
-
responseHeaders: [...defaultHeaders, ...responseHeaders.map(header => header.toLowerCase())],
|
|
15281
|
-
},
|
|
15282
|
-
};
|
|
15283
|
-
}
|
|
15284
|
-
|
|
15285
15533
|
function getOption(
|
|
15286
15534
|
selectors,
|
|
15287
15535
|
defaultSelectors,
|
|
@@ -15385,6 +15633,8 @@ function isElectronNodeRenderer() {
|
|
|
15385
15633
|
const MEDIA_SELECTORS =
|
|
15386
15634
|
'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
|
|
15387
15635
|
|
|
15636
|
+
const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
|
|
15637
|
+
|
|
15388
15638
|
let _initialized = false;
|
|
15389
15639
|
|
|
15390
15640
|
/**
|
|
@@ -15425,6 +15675,11 @@ class Replay {
|
|
|
15425
15675
|
maskAllInputs = true,
|
|
15426
15676
|
blockAllMedia = true,
|
|
15427
15677
|
|
|
15678
|
+
networkDetailAllowUrls = [],
|
|
15679
|
+
networkCaptureBodies = true,
|
|
15680
|
+
networkRequestHeaders = [],
|
|
15681
|
+
networkResponseHeaders = [],
|
|
15682
|
+
|
|
15428
15683
|
mask = [],
|
|
15429
15684
|
unmask = [],
|
|
15430
15685
|
block = [],
|
|
@@ -15483,6 +15738,11 @@ class Replay {
|
|
|
15483
15738
|
errorSampleRate,
|
|
15484
15739
|
useCompression,
|
|
15485
15740
|
blockAllMedia,
|
|
15741
|
+
networkDetailAllowUrls,
|
|
15742
|
+
networkCaptureBodies,
|
|
15743
|
+
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|
|
15744
|
+
networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
|
|
15745
|
+
|
|
15486
15746
|
_experiments,
|
|
15487
15747
|
};
|
|
15488
15748
|
|
|
@@ -15536,14 +15796,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15536
15796
|
}
|
|
15537
15797
|
|
|
15538
15798
|
/**
|
|
15539
|
-
*
|
|
15540
|
-
* potentially create a transaction before some native SDK integrations have run
|
|
15541
|
-
* and applied their own global event processor. An example is:
|
|
15542
|
-
* https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
15543
|
-
*
|
|
15544
|
-
* So we call `replay.setup` in next event loop as a workaround to wait for other
|
|
15545
|
-
* global event processors to finish. This is no longer needed, but keeping it
|
|
15546
|
-
* here to avoid any future issues.
|
|
15799
|
+
* Setup and initialize replay container
|
|
15547
15800
|
*/
|
|
15548
15801
|
setupOnce() {
|
|
15549
15802
|
if (!isBrowser()) {
|
|
@@ -15552,12 +15805,20 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15552
15805
|
|
|
15553
15806
|
this._setup();
|
|
15554
15807
|
|
|
15555
|
-
//
|
|
15556
|
-
|
|
15808
|
+
// Once upon a time, we tried to create a transaction in `setupOnce` and it would
|
|
15809
|
+
// potentially create a transaction before some native SDK integrations have run
|
|
15810
|
+
// and applied their own global event processor. An example is:
|
|
15811
|
+
// https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
15812
|
+
//
|
|
15813
|
+
// So we call `this._initialize()` in next event loop as a workaround to wait for other
|
|
15814
|
+
// global event processors to finish. This is no longer needed, but keeping it
|
|
15815
|
+
// here to avoid any future issues.
|
|
15816
|
+
setTimeout(() => this._initialize());
|
|
15557
15817
|
}
|
|
15558
15818
|
|
|
15559
15819
|
/**
|
|
15560
|
-
*
|
|
15820
|
+
* Start a replay regardless of sampling rate. Calling this will always
|
|
15821
|
+
* create a new session. Will throw an error if replay is already in progress.
|
|
15561
15822
|
*
|
|
15562
15823
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
15563
15824
|
* PerformanceObserver, Recording, Sentry SDK, etc)
|
|
@@ -15570,27 +15831,43 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15570
15831
|
this._replay.start();
|
|
15571
15832
|
}
|
|
15572
15833
|
|
|
15834
|
+
/**
|
|
15835
|
+
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
15836
|
+
* `replaysOnErrorSampleRate` > 0, until an error occurs.
|
|
15837
|
+
*/
|
|
15838
|
+
startBuffering() {
|
|
15839
|
+
if (!this._replay) {
|
|
15840
|
+
return;
|
|
15841
|
+
}
|
|
15842
|
+
|
|
15843
|
+
this._replay.startBuffering();
|
|
15844
|
+
}
|
|
15845
|
+
|
|
15573
15846
|
/**
|
|
15574
15847
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
15575
15848
|
* does not support a teardown
|
|
15576
15849
|
*/
|
|
15577
15850
|
stop() {
|
|
15578
15851
|
if (!this._replay) {
|
|
15579
|
-
return;
|
|
15852
|
+
return Promise.resolve();
|
|
15580
15853
|
}
|
|
15581
15854
|
|
|
15582
|
-
this._replay.stop();
|
|
15855
|
+
return this._replay.stop();
|
|
15583
15856
|
}
|
|
15584
15857
|
|
|
15585
15858
|
/**
|
|
15586
|
-
*
|
|
15859
|
+
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
15860
|
+
* Unless `continueRecording` is false, the replay will continue to record and
|
|
15861
|
+
* behave as a "session"-based replay.
|
|
15862
|
+
*
|
|
15863
|
+
* Otherwise, queue up a flush.
|
|
15587
15864
|
*/
|
|
15588
|
-
flush() {
|
|
15865
|
+
flush(options) {
|
|
15589
15866
|
if (!this._replay || !this._replay.isEnabled()) {
|
|
15590
|
-
return;
|
|
15867
|
+
return Promise.resolve();
|
|
15591
15868
|
}
|
|
15592
15869
|
|
|
15593
|
-
return this._replay.
|
|
15870
|
+
return this._replay.sendBufferedReplayOrFlush(options);
|
|
15594
15871
|
}
|
|
15595
15872
|
|
|
15596
15873
|
/**
|
|
@@ -15603,6 +15880,16 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15603
15880
|
|
|
15604
15881
|
return this._replay.getSessionId();
|
|
15605
15882
|
}
|
|
15883
|
+
/**
|
|
15884
|
+
* Initializes replay.
|
|
15885
|
+
*/
|
|
15886
|
+
_initialize() {
|
|
15887
|
+
if (!this._replay) {
|
|
15888
|
+
return;
|
|
15889
|
+
}
|
|
15890
|
+
|
|
15891
|
+
this._replay.initializeSampling();
|
|
15892
|
+
}
|
|
15606
15893
|
|
|
15607
15894
|
/** Setup the integration. */
|
|
15608
15895
|
_setup() {
|
|
@@ -15652,6 +15939,10 @@ function loadReplayOptionsFromClient(initialOptions) {
|
|
|
15652
15939
|
return finalOptions;
|
|
15653
15940
|
}
|
|
15654
15941
|
|
|
15942
|
+
function _getMergedNetworkHeaders(headers) {
|
|
15943
|
+
return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
|
|
15944
|
+
}
|
|
15945
|
+
|
|
15655
15946
|
/**
|
|
15656
15947
|
* Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values,
|
|
15657
15948
|
* descriptors, and functions.
|
|
@@ -16089,6 +16380,9 @@ class Postgres {
|
|
|
16089
16380
|
const span = _optionalChain([parentSpan, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
|
|
16090
16381
|
description: typeof config === 'string' ? config : (config ).text,
|
|
16091
16382
|
op: 'db',
|
|
16383
|
+
data: {
|
|
16384
|
+
'db.system': 'postgresql',
|
|
16385
|
+
},
|
|
16092
16386
|
})]);
|
|
16093
16387
|
|
|
16094
16388
|
if (typeof callback === 'function') {
|
|
@@ -16165,6 +16459,9 @@ class Mysql {constructor() { Mysql.prototype.__init.call(this); }
|
|
|
16165
16459
|
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
|
16166
16460
|
description: typeof options === 'string' ? options : (options ).sql,
|
|
16167
16461
|
op: 'db',
|
|
16462
|
+
data: {
|
|
16463
|
+
'db.system': 'mysql',
|
|
16464
|
+
},
|
|
16168
16465
|
})]);
|
|
16169
16466
|
|
|
16170
16467
|
if (typeof callback === 'function') {
|
|
@@ -16386,6 +16683,7 @@ class Mongo {
|
|
|
16386
16683
|
collectionName: collection.collectionName,
|
|
16387
16684
|
dbName: collection.dbName,
|
|
16388
16685
|
namespace: collection.namespace,
|
|
16686
|
+
'db.system': 'mongodb',
|
|
16389
16687
|
};
|
|
16390
16688
|
const spanContext = {
|
|
16391
16689
|
op: 'db',
|
|
@@ -16474,7 +16772,10 @@ class Prisma {
|
|
|
16474
16772
|
this._client.$use((params, next) => {
|
|
16475
16773
|
const action = params.action;
|
|
16476
16774
|
const model = params.model;
|
|
16477
|
-
return trace(
|
|
16775
|
+
return trace(
|
|
16776
|
+
{ name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
|
|
16777
|
+
() => next(params),
|
|
16778
|
+
);
|
|
16478
16779
|
});
|
|
16479
16780
|
}
|
|
16480
16781
|
} Prisma.__initStatic();
|
|
@@ -29638,7 +29939,7 @@ const configGenerator = () => {
|
|
|
29638
29939
|
let release;
|
|
29639
29940
|
try {
|
|
29640
29941
|
environment !== null && environment !== void 0 ? environment : (environment = "staging");
|
|
29641
|
-
release !== null && release !== void 0 ? release : (release = "1.1.
|
|
29942
|
+
release !== null && release !== void 0 ? release : (release = "1.1.22");
|
|
29642
29943
|
}
|
|
29643
29944
|
catch (_a) {
|
|
29644
29945
|
console.error('sentry configGenerator error');
|