@myinterview/widget-react 1.1.21-development-5e391f9 → 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/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/cjs/index.js
CHANGED
|
@@ -2051,7 +2051,7 @@ function loadModule(moduleName) {
|
|
|
2051
2051
|
* @returns A normalized version of the object, or `"**non-serializable**"` if any errors are thrown during normalization.
|
|
2052
2052
|
*/
|
|
2053
2053
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2054
|
-
function normalize(input, depth =
|
|
2054
|
+
function normalize(input, depth = 100, maxProperties = +Infinity) {
|
|
2055
2055
|
try {
|
|
2056
2056
|
// since we're at the outermost level, we don't provide a key
|
|
2057
2057
|
return visit('', input, depth, maxProperties);
|
|
@@ -2118,17 +2118,16 @@ function visit(
|
|
|
2118
2118
|
return value ;
|
|
2119
2119
|
}
|
|
2120
2120
|
|
|
2121
|
-
//
|
|
2122
|
-
//
|
|
2123
|
-
//
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
}
|
|
2121
|
+
// We can set `__sentry_override_normalization_depth__` on an object to ensure that from there
|
|
2122
|
+
// We keep a certain amount of depth.
|
|
2123
|
+
// This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state.
|
|
2124
|
+
const remainingDepth =
|
|
2125
|
+
typeof (value )['__sentry_override_normalization_depth__'] === 'number'
|
|
2126
|
+
? ((value )['__sentry_override_normalization_depth__'] )
|
|
2127
|
+
: depth;
|
|
2129
2128
|
|
|
2130
2129
|
// We're also done if we've reached the max depth
|
|
2131
|
-
if (
|
|
2130
|
+
if (remainingDepth === 0) {
|
|
2132
2131
|
// At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.
|
|
2133
2132
|
return stringified.replace('object ', '');
|
|
2134
2133
|
}
|
|
@@ -2144,7 +2143,7 @@ function visit(
|
|
|
2144
2143
|
try {
|
|
2145
2144
|
const jsonValue = valueWithToJSON.toJSON();
|
|
2146
2145
|
// We need to normalize the return value of `.toJSON()` in case it has circular references
|
|
2147
|
-
return visit('', jsonValue,
|
|
2146
|
+
return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);
|
|
2148
2147
|
} catch (err) {
|
|
2149
2148
|
// pass (The built-in `toJSON` failed, but we can still try to do it ourselves)
|
|
2150
2149
|
}
|
|
@@ -2173,7 +2172,7 @@ function visit(
|
|
|
2173
2172
|
|
|
2174
2173
|
// Recursively visit all the child nodes
|
|
2175
2174
|
const visitValue = visitable[visitKey];
|
|
2176
|
-
normalized[visitKey] = visit(visitKey, visitValue,
|
|
2175
|
+
normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);
|
|
2177
2176
|
|
|
2178
2177
|
numAdded++;
|
|
2179
2178
|
}
|
|
@@ -5823,7 +5822,7 @@ function getEventForEnvelopeItem(item, type) {
|
|
|
5823
5822
|
return Array.isArray(item) ? (item )[1] : undefined;
|
|
5824
5823
|
}
|
|
5825
5824
|
|
|
5826
|
-
const SDK_VERSION = '7.
|
|
5825
|
+
const SDK_VERSION = '7.50.0';
|
|
5827
5826
|
|
|
5828
5827
|
let originalFunctionToString;
|
|
5829
5828
|
|
|
@@ -5846,11 +5845,17 @@ class FunctionToString {constructor() { FunctionToString.prototype.__init.call(
|
|
|
5846
5845
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
5847
5846
|
originalFunctionToString = Function.prototype.toString;
|
|
5848
5847
|
|
|
5849
|
-
//
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5848
|
+
// intrinsics (like Function.prototype) might be immutable in some environments
|
|
5849
|
+
// e.g. Node with --frozen-intrinsics, XS (an embedded JavaScript engine) or SES (a JavaScript proposal)
|
|
5850
|
+
try {
|
|
5851
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5852
|
+
Function.prototype.toString = function ( ...args) {
|
|
5853
|
+
const context = getOriginalFunction(this) || this;
|
|
5854
|
+
return originalFunctionToString.apply(context, args);
|
|
5855
|
+
};
|
|
5856
|
+
} catch (e) {
|
|
5857
|
+
// ignore errors here, just don't patch this
|
|
5858
|
+
}
|
|
5854
5859
|
}
|
|
5855
5860
|
} FunctionToString.__initStatic();
|
|
5856
5861
|
|
|
@@ -8294,11 +8299,14 @@ const REPLAY_SESSION_KEY = 'sentryReplaySession';
|
|
|
8294
8299
|
const REPLAY_EVENT_NAME = 'replay_event';
|
|
8295
8300
|
const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
|
|
8296
8301
|
|
|
8297
|
-
// The idle limit for a session
|
|
8298
|
-
const
|
|
8302
|
+
// The idle limit for a session after which recording is paused.
|
|
8303
|
+
const SESSION_IDLE_PAUSE_DURATION = 300000; // 5 minutes in ms
|
|
8304
|
+
|
|
8305
|
+
// The idle limit for a session after which the session expires.
|
|
8306
|
+
const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms
|
|
8299
8307
|
|
|
8300
8308
|
// The maximum length of a session
|
|
8301
|
-
const MAX_SESSION_LIFE = 3600000; // 60 minutes
|
|
8309
|
+
const MAX_SESSION_LIFE = 3600000; // 60 minutes in ms
|
|
8302
8310
|
|
|
8303
8311
|
/** Default flush delays */
|
|
8304
8312
|
const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
@@ -8307,7 +8315,7 @@ const DEFAULT_FLUSH_MIN_DELAY = 5000;
|
|
|
8307
8315
|
const DEFAULT_FLUSH_MAX_DELAY = 5500;
|
|
8308
8316
|
|
|
8309
8317
|
/* How long to wait for error checkouts */
|
|
8310
|
-
const
|
|
8318
|
+
const BUFFER_CHECKOUT_TIME = 60000;
|
|
8311
8319
|
|
|
8312
8320
|
const RETRY_BASE_INTERVAL = 5000;
|
|
8313
8321
|
const RETRY_MAX_COUNT = 3;
|
|
@@ -8315,6 +8323,9 @@ const RETRY_MAX_COUNT = 3;
|
|
|
8315
8323
|
/* The max (uncompressed) size in bytes of a network body. Any body larger than this will be truncated. */
|
|
8316
8324
|
const NETWORK_BODY_MAX_SIZE = 150000;
|
|
8317
8325
|
|
|
8326
|
+
/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
|
|
8327
|
+
const CONSOLE_ARG_MAX_SIZE = 5000;
|
|
8328
|
+
|
|
8318
8329
|
var NodeType$1;
|
|
8319
8330
|
(function (NodeType) {
|
|
8320
8331
|
NodeType[NodeType["Document"] = 0] = "Document";
|
|
@@ -11979,6 +11990,31 @@ function createEventBuffer({ useCompression }) {
|
|
|
11979
11990
|
return new EventBufferArray();
|
|
11980
11991
|
}
|
|
11981
11992
|
|
|
11993
|
+
/**
|
|
11994
|
+
* Removes the session from Session Storage and unsets session in replay instance
|
|
11995
|
+
*/
|
|
11996
|
+
function clearSession(replay) {
|
|
11997
|
+
deleteSession();
|
|
11998
|
+
replay.session = undefined;
|
|
11999
|
+
}
|
|
12000
|
+
|
|
12001
|
+
/**
|
|
12002
|
+
* Deletes a session from storage
|
|
12003
|
+
*/
|
|
12004
|
+
function deleteSession() {
|
|
12005
|
+
const hasSessionStorage = 'sessionStorage' in WINDOW;
|
|
12006
|
+
|
|
12007
|
+
if (!hasSessionStorage) {
|
|
12008
|
+
return;
|
|
12009
|
+
}
|
|
12010
|
+
|
|
12011
|
+
try {
|
|
12012
|
+
WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
|
|
12013
|
+
} catch (e) {
|
|
12014
|
+
// Ignore potential SecurityError exceptions
|
|
12015
|
+
}
|
|
12016
|
+
}
|
|
12017
|
+
|
|
11982
12018
|
/**
|
|
11983
12019
|
* Given an initial timestamp and an expiry duration, checks to see if current
|
|
11984
12020
|
* time should be considered as expired.
|
|
@@ -12009,11 +12045,26 @@ function isSessionExpired(session, timeouts, targetTime = +new Date()) {
|
|
|
12009
12045
|
// First, check that maximum session length has not been exceeded
|
|
12010
12046
|
isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
|
|
12011
12047
|
// check that the idle timeout has not been exceeded (i.e. user has
|
|
12012
|
-
// performed an action within the last `
|
|
12013
|
-
isExpired(session.lastActivity, timeouts.
|
|
12048
|
+
// performed an action within the last `sessionIdleExpire` ms)
|
|
12049
|
+
isExpired(session.lastActivity, timeouts.sessionIdleExpire, targetTime)
|
|
12014
12050
|
);
|
|
12015
12051
|
}
|
|
12016
12052
|
|
|
12053
|
+
/**
|
|
12054
|
+
* Given a sample rate, returns true if replay should be sampled.
|
|
12055
|
+
*
|
|
12056
|
+
* 1.0 = 100% sampling
|
|
12057
|
+
* 0.0 = 0% sampling
|
|
12058
|
+
*/
|
|
12059
|
+
function isSampled(sampleRate) {
|
|
12060
|
+
if (sampleRate === undefined) {
|
|
12061
|
+
return false;
|
|
12062
|
+
}
|
|
12063
|
+
|
|
12064
|
+
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12065
|
+
return Math.random() < sampleRate;
|
|
12066
|
+
}
|
|
12067
|
+
|
|
12017
12068
|
/**
|
|
12018
12069
|
* Save a session to session storage.
|
|
12019
12070
|
*/
|
|
@@ -12030,21 +12081,6 @@ function saveSession(session) {
|
|
|
12030
12081
|
}
|
|
12031
12082
|
}
|
|
12032
12083
|
|
|
12033
|
-
/**
|
|
12034
|
-
* Given a sample rate, returns true if replay should be sampled.
|
|
12035
|
-
*
|
|
12036
|
-
* 1.0 = 100% sampling
|
|
12037
|
-
* 0.0 = 0% sampling
|
|
12038
|
-
*/
|
|
12039
|
-
function isSampled(sampleRate) {
|
|
12040
|
-
if (sampleRate === undefined) {
|
|
12041
|
-
return false;
|
|
12042
|
-
}
|
|
12043
|
-
|
|
12044
|
-
// Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
|
|
12045
|
-
return Math.random() < sampleRate;
|
|
12046
|
-
}
|
|
12047
|
-
|
|
12048
12084
|
/**
|
|
12049
12085
|
* Get a session with defaults & applied sampling.
|
|
12050
12086
|
*/
|
|
@@ -12063,14 +12099,15 @@ function makeSession(session) {
|
|
|
12063
12099
|
lastActivity,
|
|
12064
12100
|
segmentId,
|
|
12065
12101
|
sampled,
|
|
12102
|
+
shouldRefresh: true,
|
|
12066
12103
|
};
|
|
12067
12104
|
}
|
|
12068
12105
|
|
|
12069
12106
|
/**
|
|
12070
12107
|
* Get the sampled status for a session based on sample rates & current sampled status.
|
|
12071
12108
|
*/
|
|
12072
|
-
function getSessionSampleType(sessionSampleRate,
|
|
12073
|
-
return isSampled(sessionSampleRate) ? 'session' :
|
|
12109
|
+
function getSessionSampleType(sessionSampleRate, allowBuffering) {
|
|
12110
|
+
return isSampled(sessionSampleRate) ? 'session' : allowBuffering ? 'buffer' : false;
|
|
12074
12111
|
}
|
|
12075
12112
|
|
|
12076
12113
|
/**
|
|
@@ -12078,8 +12115,8 @@ function getSessionSampleType(sessionSampleRate, errorSampleRate) {
|
|
|
12078
12115
|
* that all replays will be saved to as attachments. Currently, we only expect
|
|
12079
12116
|
* one of these Sentry events per "replay session".
|
|
12080
12117
|
*/
|
|
12081
|
-
function createSession({ sessionSampleRate,
|
|
12082
|
-
const sampled = getSessionSampleType(sessionSampleRate,
|
|
12118
|
+
function createSession({ sessionSampleRate, allowBuffering, stickySession = false }) {
|
|
12119
|
+
const sampled = getSessionSampleType(sessionSampleRate, allowBuffering);
|
|
12083
12120
|
const session = makeSession({
|
|
12084
12121
|
sampled,
|
|
12085
12122
|
});
|
|
@@ -12127,7 +12164,7 @@ function getSession({
|
|
|
12127
12164
|
currentSession,
|
|
12128
12165
|
stickySession,
|
|
12129
12166
|
sessionSampleRate,
|
|
12130
|
-
|
|
12167
|
+
allowBuffering,
|
|
12131
12168
|
}) {
|
|
12132
12169
|
// If session exists and is passed, use it instead of always hitting session storage
|
|
12133
12170
|
const session = currentSession || (stickySession && fetchSession());
|
|
@@ -12140,8 +12177,9 @@ function getSession({
|
|
|
12140
12177
|
|
|
12141
12178
|
if (!isExpired) {
|
|
12142
12179
|
return { type: 'saved', session };
|
|
12143
|
-
} else if (session.
|
|
12144
|
-
//
|
|
12180
|
+
} else if (!session.shouldRefresh) {
|
|
12181
|
+
// In this case, stop
|
|
12182
|
+
// This is the case if we have an error session that is completed (=triggered an error)
|
|
12145
12183
|
const discardedSession = makeSession({ sampled: false });
|
|
12146
12184
|
return { type: 'new', session: discardedSession };
|
|
12147
12185
|
} else {
|
|
@@ -12153,7 +12191,7 @@ function getSession({
|
|
|
12153
12191
|
const newSession = createSession({
|
|
12154
12192
|
stickySession,
|
|
12155
12193
|
sessionSampleRate,
|
|
12156
|
-
|
|
12194
|
+
allowBuffering,
|
|
12157
12195
|
});
|
|
12158
12196
|
|
|
12159
12197
|
return { type: 'new', session: newSession };
|
|
@@ -12187,7 +12225,7 @@ async function addEvent(
|
|
|
12187
12225
|
// page has been left open and idle for a long period of time and user
|
|
12188
12226
|
// comes back to trigger a new session. The performance entries rely on
|
|
12189
12227
|
// `performance.timeOrigin`, which is when the page first opened.
|
|
12190
|
-
if (timestampInMs + replay.timeouts.
|
|
12228
|
+
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
12191
12229
|
return null;
|
|
12192
12230
|
}
|
|
12193
12231
|
|
|
@@ -12202,7 +12240,7 @@ async function addEvent(
|
|
|
12202
12240
|
return await replay.eventBuffer.addEvent(event, isCheckout);
|
|
12203
12241
|
} catch (error) {
|
|
12204
12242
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
|
|
12205
|
-
replay.stop('addEvent');
|
|
12243
|
+
await replay.stop('addEvent');
|
|
12206
12244
|
|
|
12207
12245
|
const client = getCurrentHub().getClient();
|
|
12208
12246
|
|
|
@@ -12269,23 +12307,17 @@ function handleAfterSendEvent(replay) {
|
|
|
12269
12307
|
// Trigger error recording
|
|
12270
12308
|
// Need to be very careful that this does not cause an infinite loop
|
|
12271
12309
|
if (
|
|
12272
|
-
replay.recordingMode === '
|
|
12310
|
+
replay.recordingMode === 'buffer' &&
|
|
12273
12311
|
event.exception &&
|
|
12274
12312
|
event.message !== UNABLE_TO_SEND_REPLAY // ignore this error because otherwise we could loop indefinitely with trying to capture replay and failing
|
|
12275
12313
|
) {
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
if (replay.stopRecording()) {
|
|
12284
|
-
// Reset all "capture on error" configuration before
|
|
12285
|
-
// starting a new recording
|
|
12286
|
-
replay.recordingMode = 'session';
|
|
12287
|
-
replay.startRecording();
|
|
12288
|
-
}
|
|
12314
|
+
if (!isSampled(replay.getOptions().errorSampleRate)) {
|
|
12315
|
+
return;
|
|
12316
|
+
}
|
|
12317
|
+
|
|
12318
|
+
setTimeout(() => {
|
|
12319
|
+
// Capture current event buffer as new replay
|
|
12320
|
+
void replay.sendBufferedReplayOrFlush();
|
|
12289
12321
|
});
|
|
12290
12322
|
}
|
|
12291
12323
|
};
|
|
@@ -13240,6 +13272,17 @@ function makeNetworkReplayBreadcrumb(
|
|
|
13240
13272
|
return result;
|
|
13241
13273
|
}
|
|
13242
13274
|
|
|
13275
|
+
/** Build the request or response part of a replay network breadcrumb that was skipped. */
|
|
13276
|
+
function buildSkippedNetworkRequestOrResponse(bodySize) {
|
|
13277
|
+
return {
|
|
13278
|
+
headers: {},
|
|
13279
|
+
size: bodySize,
|
|
13280
|
+
_meta: {
|
|
13281
|
+
warnings: ['URL_SKIPPED'],
|
|
13282
|
+
},
|
|
13283
|
+
};
|
|
13284
|
+
}
|
|
13285
|
+
|
|
13243
13286
|
/** Build the request or response part of a replay network breadcrumb. */
|
|
13244
13287
|
function buildNetworkRequestOrResponse(
|
|
13245
13288
|
headers,
|
|
@@ -13320,8 +13363,8 @@ function normalizeNetworkBody(body)
|
|
|
13320
13363
|
};
|
|
13321
13364
|
} catch (e3) {
|
|
13322
13365
|
return {
|
|
13323
|
-
body,
|
|
13324
|
-
warnings: ['INVALID_JSON'],
|
|
13366
|
+
body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
|
|
13367
|
+
warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
|
|
13325
13368
|
};
|
|
13326
13369
|
}
|
|
13327
13370
|
}
|
|
@@ -13340,6 +13383,11 @@ function _strIsProbablyJson(str) {
|
|
|
13340
13383
|
return (first === '[' && last === ']') || (first === '{' && last === '}');
|
|
13341
13384
|
}
|
|
13342
13385
|
|
|
13386
|
+
/** Match an URL against a list of strings/Regex. */
|
|
13387
|
+
function urlMatches(url, urls) {
|
|
13388
|
+
return stringMatchesSomePattern(url, urls);
|
|
13389
|
+
}
|
|
13390
|
+
|
|
13343
13391
|
/**
|
|
13344
13392
|
* Capture a fetch breadcrumb to a replay.
|
|
13345
13393
|
* This adds additional data (where approriate).
|
|
@@ -13399,33 +13447,37 @@ async function _prepareFetchData(
|
|
|
13399
13447
|
const {
|
|
13400
13448
|
url,
|
|
13401
13449
|
method,
|
|
13402
|
-
status_code: statusCode,
|
|
13450
|
+
status_code: statusCode = 0,
|
|
13403
13451
|
request_body_size: requestBodySize,
|
|
13404
13452
|
response_body_size: responseBodySize,
|
|
13405
13453
|
} = breadcrumb.data;
|
|
13406
13454
|
|
|
13407
|
-
const
|
|
13408
|
-
|
|
13455
|
+
const captureDetails = urlMatches(url, options.networkDetailAllowUrls);
|
|
13456
|
+
|
|
13457
|
+
const request = captureDetails
|
|
13458
|
+
? _getRequestInfo(options, hint.input, requestBodySize)
|
|
13459
|
+
: buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13460
|
+
const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize);
|
|
13409
13461
|
|
|
13410
13462
|
return {
|
|
13411
13463
|
startTimestamp,
|
|
13412
13464
|
endTimestamp,
|
|
13413
13465
|
url,
|
|
13414
13466
|
method,
|
|
13415
|
-
statusCode
|
|
13467
|
+
statusCode,
|
|
13416
13468
|
request,
|
|
13417
13469
|
response,
|
|
13418
13470
|
};
|
|
13419
13471
|
}
|
|
13420
13472
|
|
|
13421
13473
|
function _getRequestInfo(
|
|
13422
|
-
{
|
|
13474
|
+
{ networkCaptureBodies, networkRequestHeaders },
|
|
13423
13475
|
input,
|
|
13424
13476
|
requestBodySize,
|
|
13425
13477
|
) {
|
|
13426
|
-
const headers = getRequestHeaders(input,
|
|
13478
|
+
const headers = getRequestHeaders(input, networkRequestHeaders);
|
|
13427
13479
|
|
|
13428
|
-
if (!
|
|
13480
|
+
if (!networkCaptureBodies) {
|
|
13429
13481
|
return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
|
|
13430
13482
|
}
|
|
13431
13483
|
|
|
@@ -13436,19 +13488,24 @@ function _getRequestInfo(
|
|
|
13436
13488
|
}
|
|
13437
13489
|
|
|
13438
13490
|
async function _getResponseInfo(
|
|
13491
|
+
captureDetails,
|
|
13439
13492
|
{
|
|
13440
|
-
|
|
13493
|
+
networkCaptureBodies,
|
|
13441
13494
|
textEncoder,
|
|
13442
|
-
|
|
13495
|
+
networkResponseHeaders,
|
|
13443
13496
|
}
|
|
13444
13497
|
|
|
13445
13498
|
,
|
|
13446
13499
|
response,
|
|
13447
13500
|
responseBodySize,
|
|
13448
13501
|
) {
|
|
13449
|
-
|
|
13502
|
+
if (!captureDetails && responseBodySize !== undefined) {
|
|
13503
|
+
return buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
13504
|
+
}
|
|
13450
13505
|
|
|
13451
|
-
|
|
13506
|
+
const headers = getAllHeaders(response.headers, networkResponseHeaders);
|
|
13507
|
+
|
|
13508
|
+
if (!networkCaptureBodies && responseBodySize !== undefined) {
|
|
13452
13509
|
return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
|
|
13453
13510
|
}
|
|
13454
13511
|
|
|
@@ -13463,7 +13520,11 @@ async function _getResponseInfo(
|
|
|
13463
13520
|
? getBodySize(bodyText, textEncoder)
|
|
13464
13521
|
: responseBodySize;
|
|
13465
13522
|
|
|
13466
|
-
if (
|
|
13523
|
+
if (!captureDetails) {
|
|
13524
|
+
return buildSkippedNetworkRequestOrResponse(size);
|
|
13525
|
+
}
|
|
13526
|
+
|
|
13527
|
+
if (networkCaptureBodies) {
|
|
13467
13528
|
return buildNetworkRequestOrResponse(headers, size, bodyText);
|
|
13468
13529
|
}
|
|
13469
13530
|
|
|
@@ -13596,28 +13657,44 @@ function _prepareXhrData(
|
|
|
13596
13657
|
const {
|
|
13597
13658
|
url,
|
|
13598
13659
|
method,
|
|
13599
|
-
status_code: statusCode,
|
|
13660
|
+
status_code: statusCode = 0,
|
|
13600
13661
|
request_body_size: requestBodySize,
|
|
13601
13662
|
response_body_size: responseBodySize,
|
|
13602
13663
|
} = breadcrumb.data;
|
|
13603
13664
|
|
|
13604
|
-
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
13605
|
-
const requestHeaders = xhrInfo ? getAllowedHeaders(xhrInfo.request_headers, options.requestHeaders) : {};
|
|
13606
|
-
const responseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.responseHeaders);
|
|
13607
|
-
|
|
13608
13665
|
if (!url) {
|
|
13609
13666
|
return null;
|
|
13610
13667
|
}
|
|
13611
13668
|
|
|
13669
|
+
if (!urlMatches(url, options.networkDetailAllowUrls)) {
|
|
13670
|
+
const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
|
|
13671
|
+
const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
|
|
13672
|
+
return {
|
|
13673
|
+
startTimestamp,
|
|
13674
|
+
endTimestamp,
|
|
13675
|
+
url,
|
|
13676
|
+
method,
|
|
13677
|
+
statusCode,
|
|
13678
|
+
request,
|
|
13679
|
+
response,
|
|
13680
|
+
};
|
|
13681
|
+
}
|
|
13682
|
+
|
|
13683
|
+
const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
|
|
13684
|
+
const networkRequestHeaders = xhrInfo
|
|
13685
|
+
? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
|
|
13686
|
+
: {};
|
|
13687
|
+
const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
|
|
13688
|
+
|
|
13612
13689
|
const request = buildNetworkRequestOrResponse(
|
|
13613
|
-
|
|
13690
|
+
networkRequestHeaders,
|
|
13614
13691
|
requestBodySize,
|
|
13615
|
-
options.
|
|
13692
|
+
options.networkCaptureBodies ? getBodyString(input) : undefined,
|
|
13616
13693
|
);
|
|
13617
13694
|
const response = buildNetworkRequestOrResponse(
|
|
13618
|
-
|
|
13695
|
+
networkResponseHeaders,
|
|
13619
13696
|
responseBodySize,
|
|
13620
|
-
options.
|
|
13697
|
+
options.networkCaptureBodies ? hint.xhr.responseText : undefined,
|
|
13621
13698
|
);
|
|
13622
13699
|
|
|
13623
13700
|
return {
|
|
@@ -13625,7 +13702,7 @@ function _prepareXhrData(
|
|
|
13625
13702
|
endTimestamp,
|
|
13626
13703
|
url,
|
|
13627
13704
|
method,
|
|
13628
|
-
statusCode
|
|
13705
|
+
statusCode,
|
|
13629
13706
|
request,
|
|
13630
13707
|
response,
|
|
13631
13708
|
};
|
|
@@ -13657,10 +13734,16 @@ function handleNetworkBreadcrumbs(replay) {
|
|
|
13657
13734
|
try {
|
|
13658
13735
|
const textEncoder = new TextEncoder();
|
|
13659
13736
|
|
|
13737
|
+
const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
|
|
13738
|
+
replay.getOptions();
|
|
13739
|
+
|
|
13660
13740
|
const options = {
|
|
13661
13741
|
replay,
|
|
13662
13742
|
textEncoder,
|
|
13663
|
-
|
|
13743
|
+
networkDetailAllowUrls,
|
|
13744
|
+
networkCaptureBodies,
|
|
13745
|
+
networkRequestHeaders,
|
|
13746
|
+
networkResponseHeaders,
|
|
13664
13747
|
};
|
|
13665
13748
|
|
|
13666
13749
|
if (client && client.on) {
|
|
@@ -13768,9 +13851,66 @@ function handleScope(scope) {
|
|
|
13768
13851
|
return null;
|
|
13769
13852
|
}
|
|
13770
13853
|
|
|
13854
|
+
if (newBreadcrumb.category === 'console') {
|
|
13855
|
+
return normalizeConsoleBreadcrumb(newBreadcrumb);
|
|
13856
|
+
}
|
|
13857
|
+
|
|
13771
13858
|
return createBreadcrumb(newBreadcrumb);
|
|
13772
13859
|
}
|
|
13773
13860
|
|
|
13861
|
+
/** exported for tests only */
|
|
13862
|
+
function normalizeConsoleBreadcrumb(breadcrumb) {
|
|
13863
|
+
const args = breadcrumb.data && breadcrumb.data.arguments;
|
|
13864
|
+
|
|
13865
|
+
if (!Array.isArray(args) || args.length === 0) {
|
|
13866
|
+
return createBreadcrumb(breadcrumb);
|
|
13867
|
+
}
|
|
13868
|
+
|
|
13869
|
+
let isTruncated = false;
|
|
13870
|
+
|
|
13871
|
+
// Avoid giant args captures
|
|
13872
|
+
const normalizedArgs = args.map(arg => {
|
|
13873
|
+
if (!arg) {
|
|
13874
|
+
return arg;
|
|
13875
|
+
}
|
|
13876
|
+
if (typeof arg === 'string') {
|
|
13877
|
+
if (arg.length > CONSOLE_ARG_MAX_SIZE) {
|
|
13878
|
+
isTruncated = true;
|
|
13879
|
+
return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
|
|
13880
|
+
}
|
|
13881
|
+
|
|
13882
|
+
return arg;
|
|
13883
|
+
}
|
|
13884
|
+
if (typeof arg === 'object') {
|
|
13885
|
+
try {
|
|
13886
|
+
const normalizedArg = normalize(arg, 7);
|
|
13887
|
+
const stringified = JSON.stringify(normalizedArg);
|
|
13888
|
+
if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
|
|
13889
|
+
const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
|
|
13890
|
+
const json = JSON.parse(fixedJson);
|
|
13891
|
+
// We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
|
|
13892
|
+
isTruncated = true;
|
|
13893
|
+
return json;
|
|
13894
|
+
}
|
|
13895
|
+
return normalizedArg;
|
|
13896
|
+
} catch (e) {
|
|
13897
|
+
// fall back to default
|
|
13898
|
+
}
|
|
13899
|
+
}
|
|
13900
|
+
|
|
13901
|
+
return arg;
|
|
13902
|
+
});
|
|
13903
|
+
|
|
13904
|
+
return createBreadcrumb({
|
|
13905
|
+
...breadcrumb,
|
|
13906
|
+
data: {
|
|
13907
|
+
...breadcrumb.data,
|
|
13908
|
+
arguments: normalizedArgs,
|
|
13909
|
+
...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
|
|
13910
|
+
},
|
|
13911
|
+
});
|
|
13912
|
+
}
|
|
13913
|
+
|
|
13774
13914
|
/**
|
|
13775
13915
|
* Add global listeners that cannot be removed.
|
|
13776
13916
|
*/
|
|
@@ -13795,7 +13935,7 @@ function addGlobalListeners(replay) {
|
|
|
13795
13935
|
client.on('afterSendEvent', handleAfterSendEvent(replay));
|
|
13796
13936
|
client.on('createDsc', (dsc) => {
|
|
13797
13937
|
const replayId = replay.getSessionId();
|
|
13798
|
-
if (replayId) {
|
|
13938
|
+
if (replayId && replay.isEnabled()) {
|
|
13799
13939
|
dsc.replay_id = replayId;
|
|
13800
13940
|
}
|
|
13801
13941
|
});
|
|
@@ -14103,7 +14243,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14103
14243
|
// when an error occurs. Clear any state that happens before this current
|
|
14104
14244
|
// checkout. This needs to happen before `addEvent()` which updates state
|
|
14105
14245
|
// dependent on this reset.
|
|
14106
|
-
if (replay.recordingMode === '
|
|
14246
|
+
if (replay.recordingMode === 'buffer' && isCheckout) {
|
|
14107
14247
|
replay.setInitialState();
|
|
14108
14248
|
}
|
|
14109
14249
|
|
|
@@ -14129,7 +14269,7 @@ function getHandleRecordingEmit(replay) {
|
|
|
14129
14269
|
|
|
14130
14270
|
// See note above re: session start needs to reflect the most recent
|
|
14131
14271
|
// checkout.
|
|
14132
|
-
if (replay.recordingMode === '
|
|
14272
|
+
if (replay.recordingMode === 'buffer' && replay.session) {
|
|
14133
14273
|
const { earliestEvent } = replay.getContext();
|
|
14134
14274
|
if (earliestEvent) {
|
|
14135
14275
|
replay.session.started = earliestEvent;
|
|
@@ -14478,9 +14618,11 @@ class ReplayContainer {
|
|
|
14478
14618
|
__init2() {this.performanceEvents = [];}
|
|
14479
14619
|
|
|
14480
14620
|
/**
|
|
14481
|
-
* Recording can happen in one of
|
|
14482
|
-
*
|
|
14483
|
-
*
|
|
14621
|
+
* Recording can happen in one of three modes:
|
|
14622
|
+
* - session: Record the whole session, sending it continuously
|
|
14623
|
+
* - buffer: Always keep the last 60s of recording, requires:
|
|
14624
|
+
* - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
|
|
14625
|
+
* - or calling `flush()` to send the replay
|
|
14484
14626
|
*/
|
|
14485
14627
|
__init3() {this.recordingMode = 'session';}
|
|
14486
14628
|
|
|
@@ -14489,7 +14631,8 @@ class ReplayContainer {
|
|
|
14489
14631
|
* @hidden
|
|
14490
14632
|
*/
|
|
14491
14633
|
__init4() {this.timeouts = {
|
|
14492
|
-
|
|
14634
|
+
sessionIdlePause: SESSION_IDLE_PAUSE_DURATION,
|
|
14635
|
+
sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
|
|
14493
14636
|
maxSessionLife: MAX_SESSION_LIFE,
|
|
14494
14637
|
}; }
|
|
14495
14638
|
|
|
@@ -14550,8 +14693,6 @@ class ReplayContainer {
|
|
|
14550
14693
|
this._debouncedFlush = debounce(() => this._flush(), this._options.flushMinDelay, {
|
|
14551
14694
|
maxWait: this._options.flushMaxDelay,
|
|
14552
14695
|
});
|
|
14553
|
-
|
|
14554
|
-
this._experimentalOptions = _getExperimentalOptions(options);
|
|
14555
14696
|
}
|
|
14556
14697
|
|
|
14557
14698
|
/** Get the event context. */
|
|
@@ -14575,58 +14716,102 @@ class ReplayContainer {
|
|
|
14575
14716
|
}
|
|
14576
14717
|
|
|
14577
14718
|
/**
|
|
14578
|
-
*
|
|
14579
|
-
*
|
|
14580
|
-
* @hidden
|
|
14719
|
+
* Initializes the plugin based on sampling configuration. Should not be
|
|
14720
|
+
* called outside of constructor.
|
|
14581
14721
|
*/
|
|
14582
|
-
|
|
14583
|
-
|
|
14722
|
+
initializeSampling() {
|
|
14723
|
+
const { errorSampleRate, sessionSampleRate } = this._options;
|
|
14724
|
+
|
|
14725
|
+
// If neither sample rate is > 0, then do nothing - user will need to call one of
|
|
14726
|
+
// `start()` or `startBuffering` themselves.
|
|
14727
|
+
if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
|
|
14728
|
+
return;
|
|
14729
|
+
}
|
|
14730
|
+
|
|
14731
|
+
// Otherwise if there is _any_ sample rate set, try to load an existing
|
|
14732
|
+
// session, or create a new one.
|
|
14733
|
+
const isSessionSampled = this._loadAndCheckSession();
|
|
14734
|
+
|
|
14735
|
+
if (!isSessionSampled) {
|
|
14736
|
+
// This should only occur if `errorSampleRate` is 0 and was unsampled for
|
|
14737
|
+
// session-based replay. In this case there is nothing to do.
|
|
14738
|
+
return;
|
|
14739
|
+
}
|
|
14740
|
+
|
|
14741
|
+
if (!this.session) {
|
|
14742
|
+
// This should not happen, something wrong has occurred
|
|
14743
|
+
this._handleException(new Error('Unable to initialize and create session'));
|
|
14744
|
+
return;
|
|
14745
|
+
}
|
|
14746
|
+
|
|
14747
|
+
if (this.session.sampled && this.session.sampled !== 'session') {
|
|
14748
|
+
// If not sampled as session-based, then recording mode will be `buffer`
|
|
14749
|
+
// Note that we don't explicitly check if `sampled === 'buffer'` because we
|
|
14750
|
+
// could have sessions from Session storage that are still `error` from
|
|
14751
|
+
// prior SDK version.
|
|
14752
|
+
this.recordingMode = 'buffer';
|
|
14753
|
+
}
|
|
14754
|
+
|
|
14755
|
+
this._initializeRecording();
|
|
14584
14756
|
}
|
|
14585
14757
|
|
|
14586
14758
|
/**
|
|
14587
|
-
*
|
|
14759
|
+
* Start a replay regardless of sampling rate. Calling this will always
|
|
14760
|
+
* create a new session. Will throw an error if replay is already in progress.
|
|
14588
14761
|
*
|
|
14589
14762
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
14590
14763
|
* _performanceObserver, Recording, Sentry SDK, etc)
|
|
14591
14764
|
*/
|
|
14592
14765
|
start() {
|
|
14593
|
-
this.
|
|
14594
|
-
|
|
14595
|
-
if (!this._loadAndCheckSession()) {
|
|
14596
|
-
return;
|
|
14766
|
+
if (this._isEnabled && this.recordingMode === 'session') {
|
|
14767
|
+
throw new Error('Replay recording is already in progress');
|
|
14597
14768
|
}
|
|
14598
14769
|
|
|
14599
|
-
|
|
14600
|
-
|
|
14601
|
-
this._handleException(new Error('No session found'));
|
|
14602
|
-
return;
|
|
14770
|
+
if (this._isEnabled && this.recordingMode === 'buffer') {
|
|
14771
|
+
throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
|
|
14603
14772
|
}
|
|
14604
14773
|
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14774
|
+
const previousSessionId = this.session && this.session.id;
|
|
14775
|
+
|
|
14776
|
+
const { session } = getSession({
|
|
14777
|
+
timeouts: this.timeouts,
|
|
14778
|
+
stickySession: Boolean(this._options.stickySession),
|
|
14779
|
+
currentSession: this.session,
|
|
14780
|
+
// This is intentional: create a new session-based replay when calling `start()`
|
|
14781
|
+
sessionSampleRate: 1,
|
|
14782
|
+
allowBuffering: false,
|
|
14783
|
+
});
|
|
14609
14784
|
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
|
|
14785
|
+
session.previousSessionId = previousSessionId;
|
|
14786
|
+
this.session = session;
|
|
14787
|
+
|
|
14788
|
+
this._initializeRecording();
|
|
14789
|
+
}
|
|
14790
|
+
|
|
14791
|
+
/**
|
|
14792
|
+
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
14793
|
+
* `replaysOnErrorSampleRate` > 0, an error occurs.
|
|
14794
|
+
*/
|
|
14795
|
+
startBuffering() {
|
|
14796
|
+
if (this._isEnabled) {
|
|
14797
|
+
throw new Error('Replay recording is already in progress');
|
|
14614
14798
|
}
|
|
14615
14799
|
|
|
14616
|
-
|
|
14617
|
-
// should treat it as an activity
|
|
14618
|
-
this._updateSessionActivity();
|
|
14800
|
+
const previousSessionId = this.session && this.session.id;
|
|
14619
14801
|
|
|
14620
|
-
|
|
14621
|
-
|
|
14802
|
+
const { session } = getSession({
|
|
14803
|
+
timeouts: this.timeouts,
|
|
14804
|
+
stickySession: Boolean(this._options.stickySession),
|
|
14805
|
+
currentSession: this.session,
|
|
14806
|
+
sessionSampleRate: 0,
|
|
14807
|
+
allowBuffering: true,
|
|
14622
14808
|
});
|
|
14623
14809
|
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
14627
|
-
this._isEnabled = true;
|
|
14810
|
+
session.previousSessionId = previousSessionId;
|
|
14811
|
+
this.session = session;
|
|
14628
14812
|
|
|
14629
|
-
this.
|
|
14813
|
+
this.recordingMode = 'buffer';
|
|
14814
|
+
this._initializeRecording();
|
|
14630
14815
|
}
|
|
14631
14816
|
|
|
14632
14817
|
/**
|
|
@@ -14641,7 +14826,7 @@ class ReplayContainer {
|
|
|
14641
14826
|
// When running in error sampling mode, we need to overwrite `checkoutEveryNms`
|
|
14642
14827
|
// Without this, it would record forever, until an error happens, which we don't want
|
|
14643
14828
|
// instead, we'll always keep the last 60 seconds of replay before an error happened
|
|
14644
|
-
...(this.recordingMode === '
|
|
14829
|
+
...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
|
|
14645
14830
|
emit: getHandleRecordingEmit(this),
|
|
14646
14831
|
onMutation: this._onMutationHandler,
|
|
14647
14832
|
});
|
|
@@ -14652,17 +14837,18 @@ class ReplayContainer {
|
|
|
14652
14837
|
|
|
14653
14838
|
/**
|
|
14654
14839
|
* Stops the recording, if it was running.
|
|
14655
|
-
*
|
|
14840
|
+
*
|
|
14841
|
+
* Returns true if it was previously stopped, or is now stopped,
|
|
14842
|
+
* otherwise false.
|
|
14656
14843
|
*/
|
|
14657
14844
|
stopRecording() {
|
|
14658
14845
|
try {
|
|
14659
14846
|
if (this._stopRecording) {
|
|
14660
14847
|
this._stopRecording();
|
|
14661
14848
|
this._stopRecording = undefined;
|
|
14662
|
-
return true;
|
|
14663
14849
|
}
|
|
14664
14850
|
|
|
14665
|
-
return
|
|
14851
|
+
return true;
|
|
14666
14852
|
} catch (err) {
|
|
14667
14853
|
this._handleException(err);
|
|
14668
14854
|
return false;
|
|
@@ -14673,7 +14859,7 @@ class ReplayContainer {
|
|
|
14673
14859
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
14674
14860
|
* does not support a teardown
|
|
14675
14861
|
*/
|
|
14676
|
-
stop(reason) {
|
|
14862
|
+
async stop(reason) {
|
|
14677
14863
|
if (!this._isEnabled) {
|
|
14678
14864
|
return;
|
|
14679
14865
|
}
|
|
@@ -14689,12 +14875,24 @@ class ReplayContainer {
|
|
|
14689
14875
|
log(msg);
|
|
14690
14876
|
}
|
|
14691
14877
|
|
|
14878
|
+
// We can't move `_isEnabled` after awaiting a flush, otherwise we can
|
|
14879
|
+
// enter into an infinite loop when `stop()` is called while flushing.
|
|
14692
14880
|
this._isEnabled = false;
|
|
14693
14881
|
this._removeListeners();
|
|
14694
14882
|
this.stopRecording();
|
|
14883
|
+
|
|
14884
|
+
this._debouncedFlush.cancel();
|
|
14885
|
+
// See comment above re: `_isEnabled`, we "force" a flush, ignoring the
|
|
14886
|
+
// `_isEnabled` state of the plugin since it was disabled above.
|
|
14887
|
+
await this._flush({ force: true });
|
|
14888
|
+
|
|
14889
|
+
// After flush, destroy event buffer
|
|
14695
14890
|
this.eventBuffer && this.eventBuffer.destroy();
|
|
14696
14891
|
this.eventBuffer = null;
|
|
14697
|
-
|
|
14892
|
+
|
|
14893
|
+
// Clear session from session storage, note this means if a new session
|
|
14894
|
+
// is started after, it will not have `previousSessionId`
|
|
14895
|
+
clearSession(this);
|
|
14698
14896
|
} catch (err) {
|
|
14699
14897
|
this._handleException(err);
|
|
14700
14898
|
}
|
|
@@ -14725,6 +14923,45 @@ class ReplayContainer {
|
|
|
14725
14923
|
this.startRecording();
|
|
14726
14924
|
}
|
|
14727
14925
|
|
|
14926
|
+
/**
|
|
14927
|
+
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
14928
|
+
* Unless `continueRecording` is false, the replay will continue to record and
|
|
14929
|
+
* behave as a "session"-based replay.
|
|
14930
|
+
*
|
|
14931
|
+
* Otherwise, queue up a flush.
|
|
14932
|
+
*/
|
|
14933
|
+
async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
|
|
14934
|
+
if (this.recordingMode === 'session') {
|
|
14935
|
+
return this.flushImmediate();
|
|
14936
|
+
}
|
|
14937
|
+
|
|
14938
|
+
// Allow flush to complete before resuming as a session recording, otherwise
|
|
14939
|
+
// the checkout from `startRecording` may be included in the payload.
|
|
14940
|
+
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
14941
|
+
// than the session replay.
|
|
14942
|
+
await this.flushImmediate();
|
|
14943
|
+
|
|
14944
|
+
const hasStoppedRecording = this.stopRecording();
|
|
14945
|
+
|
|
14946
|
+
if (!continueRecording || !hasStoppedRecording) {
|
|
14947
|
+
return;
|
|
14948
|
+
}
|
|
14949
|
+
|
|
14950
|
+
// Re-start recording, but in "session" recording mode
|
|
14951
|
+
|
|
14952
|
+
// Reset all "capture on error" configuration before
|
|
14953
|
+
// starting a new recording
|
|
14954
|
+
this.recordingMode = 'session';
|
|
14955
|
+
|
|
14956
|
+
// Once this session ends, we do not want to refresh it
|
|
14957
|
+
if (this.session) {
|
|
14958
|
+
this.session.shouldRefresh = false;
|
|
14959
|
+
this._maybeSaveSession();
|
|
14960
|
+
}
|
|
14961
|
+
|
|
14962
|
+
this.startRecording();
|
|
14963
|
+
}
|
|
14964
|
+
|
|
14728
14965
|
/**
|
|
14729
14966
|
* We want to batch uploads of replay events. Save events only if
|
|
14730
14967
|
* `<flushMinDelay>` milliseconds have elapsed since the last event
|
|
@@ -14734,12 +14971,12 @@ class ReplayContainer {
|
|
|
14734
14971
|
* processing and hand back control to caller.
|
|
14735
14972
|
*/
|
|
14736
14973
|
addUpdate(cb) {
|
|
14737
|
-
// We need to always run `cb` (e.g. in the case of `this.recordingMode == '
|
|
14974
|
+
// We need to always run `cb` (e.g. in the case of `this.recordingMode == 'buffer'`)
|
|
14738
14975
|
const cbResult = cb();
|
|
14739
14976
|
|
|
14740
14977
|
// If this option is turned on then we will only want to call `flush`
|
|
14741
14978
|
// explicitly
|
|
14742
|
-
if (this.recordingMode === '
|
|
14979
|
+
if (this.recordingMode === 'buffer') {
|
|
14743
14980
|
return;
|
|
14744
14981
|
}
|
|
14745
14982
|
|
|
@@ -14811,12 +15048,12 @@ class ReplayContainer {
|
|
|
14811
15048
|
const oldSessionId = this.getSessionId();
|
|
14812
15049
|
|
|
14813
15050
|
// Prevent starting a new session if the last user activity is older than
|
|
14814
|
-
//
|
|
15051
|
+
// SESSION_IDLE_PAUSE_DURATION. Otherwise non-user activity can trigger a new
|
|
14815
15052
|
// session+recording. This creates noisy replays that do not have much
|
|
14816
15053
|
// content in them.
|
|
14817
15054
|
if (
|
|
14818
15055
|
this._lastActivity &&
|
|
14819
|
-
isExpired(this._lastActivity, this.timeouts.
|
|
15056
|
+
isExpired(this._lastActivity, this.timeouts.sessionIdlePause) &&
|
|
14820
15057
|
this.session &&
|
|
14821
15058
|
this.session.sampled === 'session'
|
|
14822
15059
|
) {
|
|
@@ -14866,6 +15103,30 @@ class ReplayContainer {
|
|
|
14866
15103
|
this._context.urls.push(url);
|
|
14867
15104
|
}
|
|
14868
15105
|
|
|
15106
|
+
/**
|
|
15107
|
+
* Initialize and start all listeners to varying events (DOM,
|
|
15108
|
+
* Performance Observer, Recording, Sentry SDK, etc)
|
|
15109
|
+
*/
|
|
15110
|
+
_initializeRecording() {
|
|
15111
|
+
this.setInitialState();
|
|
15112
|
+
|
|
15113
|
+
// this method is generally called on page load or manually - in both cases
|
|
15114
|
+
// we should treat it as an activity
|
|
15115
|
+
this._updateSessionActivity();
|
|
15116
|
+
|
|
15117
|
+
this.eventBuffer = createEventBuffer({
|
|
15118
|
+
useCompression: this._options.useCompression,
|
|
15119
|
+
});
|
|
15120
|
+
|
|
15121
|
+
this._removeListeners();
|
|
15122
|
+
this._addListeners();
|
|
15123
|
+
|
|
15124
|
+
// Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
|
|
15125
|
+
this._isEnabled = true;
|
|
15126
|
+
|
|
15127
|
+
this.startRecording();
|
|
15128
|
+
}
|
|
15129
|
+
|
|
14869
15130
|
/** A wrapper to conditionally capture exceptions. */
|
|
14870
15131
|
_handleException(error) {
|
|
14871
15132
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
|
|
@@ -14885,7 +15146,7 @@ class ReplayContainer {
|
|
|
14885
15146
|
stickySession: Boolean(this._options.stickySession),
|
|
14886
15147
|
currentSession: this.session,
|
|
14887
15148
|
sessionSampleRate: this._options.sessionSampleRate,
|
|
14888
|
-
|
|
15149
|
+
allowBuffering: this._options.errorSampleRate > 0,
|
|
14889
15150
|
});
|
|
14890
15151
|
|
|
14891
15152
|
// If session was newly created (i.e. was not loaded from storage), then
|
|
@@ -14902,7 +15163,7 @@ class ReplayContainer {
|
|
|
14902
15163
|
this.session = session;
|
|
14903
15164
|
|
|
14904
15165
|
if (!this.session.sampled) {
|
|
14905
|
-
this.stop('session unsampled');
|
|
15166
|
+
void this.stop('session unsampled');
|
|
14906
15167
|
return false;
|
|
14907
15168
|
}
|
|
14908
15169
|
|
|
@@ -15026,7 +15287,7 @@ class ReplayContainer {
|
|
|
15026
15287
|
const isSessionActive = this.checkAndHandleExpiredSession();
|
|
15027
15288
|
|
|
15028
15289
|
if (!isSessionActive) {
|
|
15029
|
-
// If the user has come back to the page within
|
|
15290
|
+
// If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION
|
|
15030
15291
|
// ms, we will re-use the existing session, otherwise create a new
|
|
15031
15292
|
// session
|
|
15032
15293
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
|
|
@@ -15100,7 +15361,7 @@ class ReplayContainer {
|
|
|
15100
15361
|
* Only flush if `this.recordingMode === 'session'`
|
|
15101
15362
|
*/
|
|
15102
15363
|
_conditionalFlush() {
|
|
15103
|
-
if (this.recordingMode === '
|
|
15364
|
+
if (this.recordingMode === 'buffer') {
|
|
15104
15365
|
return;
|
|
15105
15366
|
}
|
|
15106
15367
|
|
|
@@ -15195,7 +15456,7 @@ class ReplayContainer {
|
|
|
15195
15456
|
// This means we retried 3 times and all of them failed,
|
|
15196
15457
|
// or we ran into a problem we don't want to retry, like rate limiting.
|
|
15197
15458
|
// In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
|
|
15198
|
-
this.stop('sendReplay');
|
|
15459
|
+
void this.stop('sendReplay');
|
|
15199
15460
|
|
|
15200
15461
|
const client = getCurrentHub().getClient();
|
|
15201
15462
|
|
|
@@ -15209,8 +15470,12 @@ class ReplayContainer {
|
|
|
15209
15470
|
* Flush recording data to Sentry. Creates a lock so that only a single flush
|
|
15210
15471
|
* can be active at a time. Do not call this directly.
|
|
15211
15472
|
*/
|
|
15212
|
-
__init16() {this._flush = async (
|
|
15213
|
-
|
|
15473
|
+
__init16() {this._flush = async ({
|
|
15474
|
+
force = false,
|
|
15475
|
+
}
|
|
15476
|
+
|
|
15477
|
+
= {}) => {
|
|
15478
|
+
if (!this._isEnabled && !force) {
|
|
15214
15479
|
// This can happen if e.g. the replay was stopped because of exceeding the retry limit
|
|
15215
15480
|
return;
|
|
15216
15481
|
}
|
|
@@ -15291,23 +15556,6 @@ class ReplayContainer {
|
|
|
15291
15556
|
};}
|
|
15292
15557
|
}
|
|
15293
15558
|
|
|
15294
|
-
function _getExperimentalOptions(options) {
|
|
15295
|
-
const requestHeaders = options._experiments.captureRequestHeaders || [];
|
|
15296
|
-
const responseHeaders = options._experiments.captureResponseHeaders || [];
|
|
15297
|
-
const captureBodies = options._experiments.captureNetworkBodies || false;
|
|
15298
|
-
|
|
15299
|
-
// Add defaults
|
|
15300
|
-
const defaultHeaders = ['content-length', 'content-type', 'accept'];
|
|
15301
|
-
|
|
15302
|
-
return {
|
|
15303
|
-
network: {
|
|
15304
|
-
captureBodies,
|
|
15305
|
-
requestHeaders: [...defaultHeaders, ...requestHeaders.map(header => header.toLowerCase())],
|
|
15306
|
-
responseHeaders: [...defaultHeaders, ...responseHeaders.map(header => header.toLowerCase())],
|
|
15307
|
-
},
|
|
15308
|
-
};
|
|
15309
|
-
}
|
|
15310
|
-
|
|
15311
15559
|
function getOption(
|
|
15312
15560
|
selectors,
|
|
15313
15561
|
defaultSelectors,
|
|
@@ -15411,6 +15659,8 @@ function isElectronNodeRenderer() {
|
|
|
15411
15659
|
const MEDIA_SELECTORS =
|
|
15412
15660
|
'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
|
|
15413
15661
|
|
|
15662
|
+
const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
|
|
15663
|
+
|
|
15414
15664
|
let _initialized = false;
|
|
15415
15665
|
|
|
15416
15666
|
/**
|
|
@@ -15451,6 +15701,11 @@ class Replay {
|
|
|
15451
15701
|
maskAllInputs = true,
|
|
15452
15702
|
blockAllMedia = true,
|
|
15453
15703
|
|
|
15704
|
+
networkDetailAllowUrls = [],
|
|
15705
|
+
networkCaptureBodies = true,
|
|
15706
|
+
networkRequestHeaders = [],
|
|
15707
|
+
networkResponseHeaders = [],
|
|
15708
|
+
|
|
15454
15709
|
mask = [],
|
|
15455
15710
|
unmask = [],
|
|
15456
15711
|
block = [],
|
|
@@ -15509,6 +15764,11 @@ class Replay {
|
|
|
15509
15764
|
errorSampleRate,
|
|
15510
15765
|
useCompression,
|
|
15511
15766
|
blockAllMedia,
|
|
15767
|
+
networkDetailAllowUrls,
|
|
15768
|
+
networkCaptureBodies,
|
|
15769
|
+
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|
|
15770
|
+
networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
|
|
15771
|
+
|
|
15512
15772
|
_experiments,
|
|
15513
15773
|
};
|
|
15514
15774
|
|
|
@@ -15562,14 +15822,7 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15562
15822
|
}
|
|
15563
15823
|
|
|
15564
15824
|
/**
|
|
15565
|
-
*
|
|
15566
|
-
* potentially create a transaction before some native SDK integrations have run
|
|
15567
|
-
* and applied their own global event processor. An example is:
|
|
15568
|
-
* https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
15569
|
-
*
|
|
15570
|
-
* So we call `replay.setup` in next event loop as a workaround to wait for other
|
|
15571
|
-
* global event processors to finish. This is no longer needed, but keeping it
|
|
15572
|
-
* here to avoid any future issues.
|
|
15825
|
+
* Setup and initialize replay container
|
|
15573
15826
|
*/
|
|
15574
15827
|
setupOnce() {
|
|
15575
15828
|
if (!isBrowser()) {
|
|
@@ -15578,12 +15831,20 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15578
15831
|
|
|
15579
15832
|
this._setup();
|
|
15580
15833
|
|
|
15581
|
-
//
|
|
15582
|
-
|
|
15834
|
+
// Once upon a time, we tried to create a transaction in `setupOnce` and it would
|
|
15835
|
+
// potentially create a transaction before some native SDK integrations have run
|
|
15836
|
+
// and applied their own global event processor. An example is:
|
|
15837
|
+
// https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
|
|
15838
|
+
//
|
|
15839
|
+
// So we call `this._initialize()` in next event loop as a workaround to wait for other
|
|
15840
|
+
// global event processors to finish. This is no longer needed, but keeping it
|
|
15841
|
+
// here to avoid any future issues.
|
|
15842
|
+
setTimeout(() => this._initialize());
|
|
15583
15843
|
}
|
|
15584
15844
|
|
|
15585
15845
|
/**
|
|
15586
|
-
*
|
|
15846
|
+
* Start a replay regardless of sampling rate. Calling this will always
|
|
15847
|
+
* create a new session. Will throw an error if replay is already in progress.
|
|
15587
15848
|
*
|
|
15588
15849
|
* Creates or loads a session, attaches listeners to varying events (DOM,
|
|
15589
15850
|
* PerformanceObserver, Recording, Sentry SDK, etc)
|
|
@@ -15596,27 +15857,43 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15596
15857
|
this._replay.start();
|
|
15597
15858
|
}
|
|
15598
15859
|
|
|
15860
|
+
/**
|
|
15861
|
+
* Start replay buffering. Buffers until `flush()` is called or, if
|
|
15862
|
+
* `replaysOnErrorSampleRate` > 0, until an error occurs.
|
|
15863
|
+
*/
|
|
15864
|
+
startBuffering() {
|
|
15865
|
+
if (!this._replay) {
|
|
15866
|
+
return;
|
|
15867
|
+
}
|
|
15868
|
+
|
|
15869
|
+
this._replay.startBuffering();
|
|
15870
|
+
}
|
|
15871
|
+
|
|
15599
15872
|
/**
|
|
15600
15873
|
* Currently, this needs to be manually called (e.g. for tests). Sentry SDK
|
|
15601
15874
|
* does not support a teardown
|
|
15602
15875
|
*/
|
|
15603
15876
|
stop() {
|
|
15604
15877
|
if (!this._replay) {
|
|
15605
|
-
return;
|
|
15878
|
+
return Promise.resolve();
|
|
15606
15879
|
}
|
|
15607
15880
|
|
|
15608
|
-
this._replay.stop();
|
|
15881
|
+
return this._replay.stop();
|
|
15609
15882
|
}
|
|
15610
15883
|
|
|
15611
15884
|
/**
|
|
15612
|
-
*
|
|
15885
|
+
* If not in "session" recording mode, flush event buffer which will create a new replay.
|
|
15886
|
+
* Unless `continueRecording` is false, the replay will continue to record and
|
|
15887
|
+
* behave as a "session"-based replay.
|
|
15888
|
+
*
|
|
15889
|
+
* Otherwise, queue up a flush.
|
|
15613
15890
|
*/
|
|
15614
|
-
flush() {
|
|
15891
|
+
flush(options) {
|
|
15615
15892
|
if (!this._replay || !this._replay.isEnabled()) {
|
|
15616
|
-
return;
|
|
15893
|
+
return Promise.resolve();
|
|
15617
15894
|
}
|
|
15618
15895
|
|
|
15619
|
-
return this._replay.
|
|
15896
|
+
return this._replay.sendBufferedReplayOrFlush(options);
|
|
15620
15897
|
}
|
|
15621
15898
|
|
|
15622
15899
|
/**
|
|
@@ -15629,6 +15906,16 @@ Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
|
|
|
15629
15906
|
|
|
15630
15907
|
return this._replay.getSessionId();
|
|
15631
15908
|
}
|
|
15909
|
+
/**
|
|
15910
|
+
* Initializes replay.
|
|
15911
|
+
*/
|
|
15912
|
+
_initialize() {
|
|
15913
|
+
if (!this._replay) {
|
|
15914
|
+
return;
|
|
15915
|
+
}
|
|
15916
|
+
|
|
15917
|
+
this._replay.initializeSampling();
|
|
15918
|
+
}
|
|
15632
15919
|
|
|
15633
15920
|
/** Setup the integration. */
|
|
15634
15921
|
_setup() {
|
|
@@ -15678,6 +15965,10 @@ function loadReplayOptionsFromClient(initialOptions) {
|
|
|
15678
15965
|
return finalOptions;
|
|
15679
15966
|
}
|
|
15680
15967
|
|
|
15968
|
+
function _getMergedNetworkHeaders(headers) {
|
|
15969
|
+
return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
|
|
15970
|
+
}
|
|
15971
|
+
|
|
15681
15972
|
/**
|
|
15682
15973
|
* Polyfill for the optional chain operator, `?.`, given previous conversion of the expression into an array of values,
|
|
15683
15974
|
* descriptors, and functions.
|
|
@@ -16115,6 +16406,9 @@ class Postgres {
|
|
|
16115
16406
|
const span = _optionalChain([parentSpan, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
|
|
16116
16407
|
description: typeof config === 'string' ? config : (config ).text,
|
|
16117
16408
|
op: 'db',
|
|
16409
|
+
data: {
|
|
16410
|
+
'db.system': 'postgresql',
|
|
16411
|
+
},
|
|
16118
16412
|
})]);
|
|
16119
16413
|
|
|
16120
16414
|
if (typeof callback === 'function') {
|
|
@@ -16191,6 +16485,9 @@ class Mysql {constructor() { Mysql.prototype.__init.call(this); }
|
|
|
16191
16485
|
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
|
16192
16486
|
description: typeof options === 'string' ? options : (options ).sql,
|
|
16193
16487
|
op: 'db',
|
|
16488
|
+
data: {
|
|
16489
|
+
'db.system': 'mysql',
|
|
16490
|
+
},
|
|
16194
16491
|
})]);
|
|
16195
16492
|
|
|
16196
16493
|
if (typeof callback === 'function') {
|
|
@@ -16412,6 +16709,7 @@ class Mongo {
|
|
|
16412
16709
|
collectionName: collection.collectionName,
|
|
16413
16710
|
dbName: collection.dbName,
|
|
16414
16711
|
namespace: collection.namespace,
|
|
16712
|
+
'db.system': 'mongodb',
|
|
16415
16713
|
};
|
|
16416
16714
|
const spanContext = {
|
|
16417
16715
|
op: 'db',
|
|
@@ -16500,7 +16798,10 @@ class Prisma {
|
|
|
16500
16798
|
this._client.$use((params, next) => {
|
|
16501
16799
|
const action = params.action;
|
|
16502
16800
|
const model = params.model;
|
|
16503
|
-
return trace(
|
|
16801
|
+
return trace(
|
|
16802
|
+
{ name: model ? `${model} ${action}` : action, op: 'db.sql.prisma', data: { 'db.system': 'prisma' } },
|
|
16803
|
+
() => next(params),
|
|
16804
|
+
);
|
|
16504
16805
|
});
|
|
16505
16806
|
}
|
|
16506
16807
|
} Prisma.__initStatic();
|
|
@@ -29664,7 +29965,7 @@ const configGenerator = () => {
|
|
|
29664
29965
|
let release;
|
|
29665
29966
|
try {
|
|
29666
29967
|
environment !== null && environment !== void 0 ? environment : (environment = "staging");
|
|
29667
|
-
release !== null && release !== void 0 ? release : (release = "1.1.
|
|
29968
|
+
release !== null && release !== void 0 ? release : (release = "1.1.22");
|
|
29668
29969
|
}
|
|
29669
29970
|
catch (_a) {
|
|
29670
29971
|
console.error('sentry configGenerator error');
|