@sentry/replay 7.53.1 → 7.54.0
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/cjs/index.js +235 -128
- package/cjs/index.js.map +1 -1
- package/esm/index.js +237 -130
- package/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/types/coreHandlers/handleGlobalEvent.d.ts.map +1 -1
- package/types/coreHandlers/util/addBreadcrumbEvent.d.ts.map +1 -1
- package/types/integration.d.ts +1 -1
- package/types/integration.d.ts.map +1 -1
- package/types/replay.d.ts +20 -2
- package/types/replay.d.ts.map +1 -1
- package/types/types.d.ts +17 -3
- package/types/types.d.ts.map +1 -1
- package/types/util/addGlobalListeners.d.ts.map +1 -1
- package/types/util/createPerformanceSpans.d.ts +1 -1
- package/types/util/createPerformanceSpans.d.ts.map +1 -1
- package/types/util/throttle.d.ts +12 -0
- package/types/util/throttle.d.ts.map +1 -0
package/cjs/index.js
CHANGED
|
@@ -1135,7 +1135,7 @@ if (typeof window !== 'undefined' && window.Proxy && window.Reflect) {
|
|
|
1135
1135
|
},
|
|
1136
1136
|
});
|
|
1137
1137
|
}
|
|
1138
|
-
function throttle(func, wait, options = {}) {
|
|
1138
|
+
function throttle$1(func, wait, options = {}) {
|
|
1139
1139
|
let timeout = null;
|
|
1140
1140
|
let previous = 0;
|
|
1141
1141
|
return function (arg) {
|
|
@@ -1870,7 +1870,7 @@ function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
|
|
|
1870
1870
|
: 500;
|
|
1871
1871
|
let positions = [];
|
|
1872
1872
|
let timeBaseline;
|
|
1873
|
-
const wrappedCb = throttle((source) => {
|
|
1873
|
+
const wrappedCb = throttle$1((source) => {
|
|
1874
1874
|
const totalOffset = Date.now() - timeBaseline;
|
|
1875
1875
|
callbackWrapper(mousemoveCb)(positions.map((p) => {
|
|
1876
1876
|
p.timeOffset -= totalOffset;
|
|
@@ -1879,7 +1879,7 @@ function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
|
|
|
1879
1879
|
positions = [];
|
|
1880
1880
|
timeBaseline = null;
|
|
1881
1881
|
}, callbackThreshold);
|
|
1882
|
-
const updatePosition = throttle((evt) => {
|
|
1882
|
+
const updatePosition = throttle$1((evt) => {
|
|
1883
1883
|
const target = getEventTarget(evt);
|
|
1884
1884
|
const { clientX, clientY } = isTouchEvent(evt)
|
|
1885
1885
|
? evt.changedTouches[0]
|
|
@@ -1953,7 +1953,7 @@ function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockCl
|
|
|
1953
1953
|
});
|
|
1954
1954
|
}
|
|
1955
1955
|
function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) {
|
|
1956
|
-
const updatePosition = throttle((evt) => {
|
|
1956
|
+
const updatePosition = throttle$1((evt) => {
|
|
1957
1957
|
const target = getEventTarget(evt);
|
|
1958
1958
|
if (!target ||
|
|
1959
1959
|
isBlocked(target, blockClass, blockSelector, unblockSelector)) {
|
|
@@ -1981,7 +1981,7 @@ function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector,
|
|
|
1981
1981
|
function initViewportResizeObserver({ viewportResizeCb, }) {
|
|
1982
1982
|
let lastH = -1;
|
|
1983
1983
|
let lastW = -1;
|
|
1984
|
-
const updateDimension = throttle(() => {
|
|
1984
|
+
const updateDimension = throttle$1(() => {
|
|
1985
1985
|
const height = getWindowHeight();
|
|
1986
1986
|
const width = getWindowWidth();
|
|
1987
1987
|
if (lastH !== height || lastW !== width) {
|
|
@@ -2270,7 +2270,7 @@ function initStyleDeclarationObserver({ styleDeclarationCb, mirror }, { win }) {
|
|
|
2270
2270
|
});
|
|
2271
2271
|
}
|
|
2272
2272
|
function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSelector, unblockSelector, mirror, sampling, }) {
|
|
2273
|
-
const handler = (type) => throttle(callbackWrapper((event) => {
|
|
2273
|
+
const handler = (type) => throttle$1(callbackWrapper((event) => {
|
|
2274
2274
|
const target = getEventTarget(event);
|
|
2275
2275
|
if (!target ||
|
|
2276
2276
|
isBlocked(target, blockClass, blockSelector, unblockSelector)) {
|
|
@@ -3287,89 +3287,6 @@ var NodeType;
|
|
|
3287
3287
|
NodeType[NodeType["Comment"] = 5] = "Comment";
|
|
3288
3288
|
})(NodeType || (NodeType = {}));
|
|
3289
3289
|
|
|
3290
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3291
|
-
|
|
3292
|
-
var EventType; (function (EventType) {
|
|
3293
|
-
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
3294
|
-
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
3295
|
-
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
3296
|
-
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
3297
|
-
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
3298
|
-
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
3299
|
-
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
3300
|
-
})(EventType || (EventType = {}));
|
|
3301
|
-
|
|
3302
|
-
/**
|
|
3303
|
-
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
3304
|
-
* we specifcally need in the SDK.
|
|
3305
|
-
*/
|
|
3306
|
-
|
|
3307
|
-
/**
|
|
3308
|
-
* Converts a timestamp to ms, if it was in s, or keeps it as ms.
|
|
3309
|
-
*/
|
|
3310
|
-
function timestampToMs(timestamp) {
|
|
3311
|
-
const isMs = timestamp > 9999999999;
|
|
3312
|
-
return isMs ? timestamp : timestamp * 1000;
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3315
|
-
/**
|
|
3316
|
-
* Add an event to the event buffer.
|
|
3317
|
-
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
|
|
3318
|
-
*/
|
|
3319
|
-
async function addEvent(
|
|
3320
|
-
replay,
|
|
3321
|
-
event,
|
|
3322
|
-
isCheckout,
|
|
3323
|
-
) {
|
|
3324
|
-
if (!replay.eventBuffer) {
|
|
3325
|
-
// This implies that `_isEnabled` is false
|
|
3326
|
-
return null;
|
|
3327
|
-
}
|
|
3328
|
-
|
|
3329
|
-
if (replay.isPaused()) {
|
|
3330
|
-
// Do not add to event buffer when recording is paused
|
|
3331
|
-
return null;
|
|
3332
|
-
}
|
|
3333
|
-
|
|
3334
|
-
const timestampInMs = timestampToMs(event.timestamp);
|
|
3335
|
-
|
|
3336
|
-
// Throw out events that happen more than 5 minutes ago. This can happen if
|
|
3337
|
-
// page has been left open and idle for a long period of time and user
|
|
3338
|
-
// comes back to trigger a new session. The performance entries rely on
|
|
3339
|
-
// `performance.timeOrigin`, which is when the page first opened.
|
|
3340
|
-
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
3341
|
-
return null;
|
|
3342
|
-
}
|
|
3343
|
-
|
|
3344
|
-
try {
|
|
3345
|
-
if (isCheckout) {
|
|
3346
|
-
replay.eventBuffer.clear();
|
|
3347
|
-
}
|
|
3348
|
-
|
|
3349
|
-
const replayOptions = replay.getOptions();
|
|
3350
|
-
|
|
3351
|
-
const eventAfterPossibleCallback =
|
|
3352
|
-
typeof replayOptions.beforeAddRecordingEvent === 'function' && event.type === EventType.Custom
|
|
3353
|
-
? replayOptions.beforeAddRecordingEvent(event)
|
|
3354
|
-
: event;
|
|
3355
|
-
|
|
3356
|
-
if (!eventAfterPossibleCallback) {
|
|
3357
|
-
return;
|
|
3358
|
-
}
|
|
3359
|
-
|
|
3360
|
-
return await replay.eventBuffer.addEvent(eventAfterPossibleCallback);
|
|
3361
|
-
} catch (error) {
|
|
3362
|
-
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(error);
|
|
3363
|
-
await replay.stop('addEvent');
|
|
3364
|
-
|
|
3365
|
-
const client = core.getCurrentHub().getClient();
|
|
3366
|
-
|
|
3367
|
-
if (client) {
|
|
3368
|
-
client.recordDroppedEvent('internal_sdk_error', 'replay');
|
|
3369
|
-
}
|
|
3370
|
-
}
|
|
3371
|
-
}
|
|
3372
|
-
|
|
3373
3290
|
/**
|
|
3374
3291
|
* Add a breadcrumb event to replay.
|
|
3375
3292
|
*/
|
|
@@ -3385,7 +3302,7 @@ function addBreadcrumbEvent(replay, breadcrumb) {
|
|
|
3385
3302
|
}
|
|
3386
3303
|
|
|
3387
3304
|
replay.addUpdate(() => {
|
|
3388
|
-
void
|
|
3305
|
+
void replay.throttledAddEvent({
|
|
3389
3306
|
type: EventType$1.Custom,
|
|
3390
3307
|
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
|
|
3391
3308
|
// but maybe we should just keep them as milliseconds
|
|
@@ -3726,7 +3643,7 @@ function getKeyboardBreadcrumb(event) {
|
|
|
3726
3643
|
const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event;
|
|
3727
3644
|
|
|
3728
3645
|
// never capture for input fields
|
|
3729
|
-
if (!target || isInputElement(target )) {
|
|
3646
|
+
if (!target || isInputElement(target ) || !key) {
|
|
3730
3647
|
return null;
|
|
3731
3648
|
}
|
|
3732
3649
|
|
|
@@ -3898,6 +3815,14 @@ function t(t){let e=t.length;for(;--e>=0;)t[e]=0}const e=new Uint8Array([0,0,0,0
|
|
|
3898
3815
|
|
|
3899
3816
|
function e(){const e=new Blob([r]);return URL.createObjectURL(e)}
|
|
3900
3817
|
|
|
3818
|
+
/**
|
|
3819
|
+
* Converts a timestamp to ms, if it was in s, or keeps it as ms.
|
|
3820
|
+
*/
|
|
3821
|
+
function timestampToMs(timestamp) {
|
|
3822
|
+
const isMs = timestamp > 9999999999;
|
|
3823
|
+
return isMs ? timestamp : timestamp * 1000;
|
|
3824
|
+
}
|
|
3825
|
+
|
|
3901
3826
|
/**
|
|
3902
3827
|
* A basic event buffer that does not do any compression.
|
|
3903
3828
|
* Used as fallback if the compression worker cannot be loaded or is disabled.
|
|
@@ -4475,6 +4400,81 @@ function getSession({
|
|
|
4475
4400
|
return { type: 'new', session: newSession };
|
|
4476
4401
|
}
|
|
4477
4402
|
|
|
4403
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
4404
|
+
|
|
4405
|
+
var EventType; (function (EventType) {
|
|
4406
|
+
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
4407
|
+
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
4408
|
+
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
4409
|
+
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
4410
|
+
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
4411
|
+
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
4412
|
+
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
4413
|
+
})(EventType || (EventType = {}));
|
|
4414
|
+
|
|
4415
|
+
/**
|
|
4416
|
+
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
4417
|
+
* we specifcally need in the SDK.
|
|
4418
|
+
*/
|
|
4419
|
+
|
|
4420
|
+
/**
|
|
4421
|
+
* Add an event to the event buffer.
|
|
4422
|
+
* `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
|
|
4423
|
+
*/
|
|
4424
|
+
async function addEvent(
|
|
4425
|
+
replay,
|
|
4426
|
+
event,
|
|
4427
|
+
isCheckout,
|
|
4428
|
+
) {
|
|
4429
|
+
if (!replay.eventBuffer) {
|
|
4430
|
+
// This implies that `_isEnabled` is false
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
if (replay.isPaused()) {
|
|
4435
|
+
// Do not add to event buffer when recording is paused
|
|
4436
|
+
return null;
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
const timestampInMs = timestampToMs(event.timestamp);
|
|
4440
|
+
|
|
4441
|
+
// Throw out events that happen more than 5 minutes ago. This can happen if
|
|
4442
|
+
// page has been left open and idle for a long period of time and user
|
|
4443
|
+
// comes back to trigger a new session. The performance entries rely on
|
|
4444
|
+
// `performance.timeOrigin`, which is when the page first opened.
|
|
4445
|
+
if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
|
|
4446
|
+
return null;
|
|
4447
|
+
}
|
|
4448
|
+
|
|
4449
|
+
try {
|
|
4450
|
+
if (isCheckout) {
|
|
4451
|
+
replay.eventBuffer.clear();
|
|
4452
|
+
}
|
|
4453
|
+
|
|
4454
|
+
const replayOptions = replay.getOptions();
|
|
4455
|
+
|
|
4456
|
+
const eventAfterPossibleCallback =
|
|
4457
|
+
typeof replayOptions.beforeAddRecordingEvent === 'function' && event.type === EventType.Custom
|
|
4458
|
+
? replayOptions.beforeAddRecordingEvent(event)
|
|
4459
|
+
: event;
|
|
4460
|
+
|
|
4461
|
+
if (!eventAfterPossibleCallback) {
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
return await replay.eventBuffer.addEvent(eventAfterPossibleCallback);
|
|
4466
|
+
} catch (error) {
|
|
4467
|
+
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(error);
|
|
4468
|
+
await replay.stop('addEvent');
|
|
4469
|
+
|
|
4470
|
+
const client = core.getCurrentHub().getClient();
|
|
4471
|
+
|
|
4472
|
+
if (client) {
|
|
4473
|
+
client.recordDroppedEvent('internal_sdk_error', 'replay');
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
|
|
4478
4478
|
/** If the event is an error event */
|
|
4479
4479
|
function isErrorEvent(event) {
|
|
4480
4480
|
return !event.type;
|
|
@@ -4649,13 +4649,6 @@ function handleGlobalEventListener(
|
|
|
4649
4649
|
event.tags = { ...event.tags, replayId: replay.getSessionId() };
|
|
4650
4650
|
}
|
|
4651
4651
|
|
|
4652
|
-
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && replay.getOptions()._experiments.traceInternals && isErrorEvent(event)) {
|
|
4653
|
-
const exc = getEventExceptionValues(event);
|
|
4654
|
-
addInternalBreadcrumb({
|
|
4655
|
-
message: `Tagging event (${event.event_id}) - ${event.message} - ${exc.type}: ${exc.value}`,
|
|
4656
|
-
});
|
|
4657
|
-
}
|
|
4658
|
-
|
|
4659
4652
|
// In cases where a custom client is used that does not support the new hooks (yet),
|
|
4660
4653
|
// we manually call this hook method here
|
|
4661
4654
|
if (afterSendHandler) {
|
|
@@ -4667,34 +4660,15 @@ function handleGlobalEventListener(
|
|
|
4667
4660
|
};
|
|
4668
4661
|
}
|
|
4669
4662
|
|
|
4670
|
-
function addInternalBreadcrumb(arg) {
|
|
4671
|
-
const { category, level, message, ...rest } = arg;
|
|
4672
|
-
|
|
4673
|
-
core.addBreadcrumb({
|
|
4674
|
-
category: category || 'console',
|
|
4675
|
-
level: level || 'debug',
|
|
4676
|
-
message: `[debug]: ${message}`,
|
|
4677
|
-
...rest,
|
|
4678
|
-
});
|
|
4679
|
-
}
|
|
4680
|
-
|
|
4681
|
-
function getEventExceptionValues(event) {
|
|
4682
|
-
return {
|
|
4683
|
-
type: 'Unknown',
|
|
4684
|
-
value: 'n/a',
|
|
4685
|
-
...(event.exception && event.exception.values && event.exception.values[0]),
|
|
4686
|
-
};
|
|
4687
|
-
}
|
|
4688
|
-
|
|
4689
4663
|
/**
|
|
4690
|
-
* Create a "span" for each performance entry.
|
|
4664
|
+
* Create a "span" for each performance entry.
|
|
4691
4665
|
*/
|
|
4692
4666
|
function createPerformanceSpans(
|
|
4693
4667
|
replay,
|
|
4694
4668
|
entries,
|
|
4695
4669
|
) {
|
|
4696
|
-
return entries.map(({ type, start, end, name, data }) =>
|
|
4697
|
-
|
|
4670
|
+
return entries.map(({ type, start, end, name, data }) => {
|
|
4671
|
+
const response = replay.throttledAddEvent({
|
|
4698
4672
|
type: EventType$1.Custom,
|
|
4699
4673
|
timestamp: start,
|
|
4700
4674
|
data: {
|
|
@@ -4707,8 +4681,11 @@ function createPerformanceSpans(
|
|
|
4707
4681
|
data,
|
|
4708
4682
|
},
|
|
4709
4683
|
},
|
|
4710
|
-
})
|
|
4711
|
-
|
|
4684
|
+
});
|
|
4685
|
+
|
|
4686
|
+
// If response is a string, it means its either THROTTLED or SKIPPED
|
|
4687
|
+
return typeof response === 'string' ? Promise.resolve(null) : response;
|
|
4688
|
+
});
|
|
4712
4689
|
}
|
|
4713
4690
|
|
|
4714
4691
|
function handleHistory(handlerData) {
|
|
@@ -6057,6 +6034,16 @@ function addGlobalListeners(replay) {
|
|
|
6057
6034
|
dsc.replay_id = replayId;
|
|
6058
6035
|
}
|
|
6059
6036
|
});
|
|
6037
|
+
|
|
6038
|
+
client.on('startTransaction', transaction => {
|
|
6039
|
+
replay.lastTransaction = transaction;
|
|
6040
|
+
});
|
|
6041
|
+
|
|
6042
|
+
// We may be missing the initial startTransaction due to timing issues,
|
|
6043
|
+
// so we capture it on finish again.
|
|
6044
|
+
client.on('finishTransaction', transaction => {
|
|
6045
|
+
replay.lastTransaction = transaction;
|
|
6046
|
+
});
|
|
6060
6047
|
}
|
|
6061
6048
|
}
|
|
6062
6049
|
|
|
@@ -6780,6 +6767,62 @@ async function sendReplay(
|
|
|
6780
6767
|
}
|
|
6781
6768
|
}
|
|
6782
6769
|
|
|
6770
|
+
const THROTTLED = '__THROTTLED';
|
|
6771
|
+
const SKIPPED = '__SKIPPED';
|
|
6772
|
+
|
|
6773
|
+
/**
|
|
6774
|
+
* Create a throttled function off a given function.
|
|
6775
|
+
* When calling the throttled function, it will call the original function only
|
|
6776
|
+
* if it hasn't been called more than `maxCount` times in the last `durationSeconds`.
|
|
6777
|
+
*
|
|
6778
|
+
* Returns `THROTTLED` if throttled for the first time, after that `SKIPPED`,
|
|
6779
|
+
* or else the return value of the original function.
|
|
6780
|
+
*/
|
|
6781
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6782
|
+
function throttle(
|
|
6783
|
+
fn,
|
|
6784
|
+
maxCount,
|
|
6785
|
+
durationSeconds,
|
|
6786
|
+
) {
|
|
6787
|
+
const counter = new Map();
|
|
6788
|
+
|
|
6789
|
+
const _cleanup = (now) => {
|
|
6790
|
+
const threshold = now - durationSeconds;
|
|
6791
|
+
counter.forEach((_value, key) => {
|
|
6792
|
+
if (key < threshold) {
|
|
6793
|
+
counter.delete(key);
|
|
6794
|
+
}
|
|
6795
|
+
});
|
|
6796
|
+
};
|
|
6797
|
+
|
|
6798
|
+
const _getTotalCount = () => {
|
|
6799
|
+
return [...counter.values()].reduce((a, b) => a + b, 0);
|
|
6800
|
+
};
|
|
6801
|
+
|
|
6802
|
+
let isThrottled = false;
|
|
6803
|
+
|
|
6804
|
+
return (...rest) => {
|
|
6805
|
+
// Date in second-precision, which we use as basis for the throttling
|
|
6806
|
+
const now = Math.floor(Date.now() / 1000);
|
|
6807
|
+
|
|
6808
|
+
// First, make sure to delete any old entries
|
|
6809
|
+
_cleanup(now);
|
|
6810
|
+
|
|
6811
|
+
// If already over limit, do nothing
|
|
6812
|
+
if (_getTotalCount() >= maxCount) {
|
|
6813
|
+
const wasThrottled = isThrottled;
|
|
6814
|
+
isThrottled = true;
|
|
6815
|
+
return wasThrottled ? SKIPPED : THROTTLED;
|
|
6816
|
+
}
|
|
6817
|
+
|
|
6818
|
+
isThrottled = false;
|
|
6819
|
+
const count = counter.get(now) || 0;
|
|
6820
|
+
counter.set(now, count + 1);
|
|
6821
|
+
|
|
6822
|
+
return fn(...rest);
|
|
6823
|
+
};
|
|
6824
|
+
}
|
|
6825
|
+
|
|
6783
6826
|
/* eslint-disable max-lines */ // TODO: We might want to split this file up
|
|
6784
6827
|
|
|
6785
6828
|
/**
|
|
@@ -6802,6 +6845,11 @@ class ReplayContainer {
|
|
|
6802
6845
|
*/
|
|
6803
6846
|
__init3() {this.recordingMode = 'session';}
|
|
6804
6847
|
|
|
6848
|
+
/**
|
|
6849
|
+
* The current or last active transcation.
|
|
6850
|
+
* This is only available when performance is enabled.
|
|
6851
|
+
*/
|
|
6852
|
+
|
|
6805
6853
|
/**
|
|
6806
6854
|
* These are here so we can overwrite them in tests etc.
|
|
6807
6855
|
* @hidden
|
|
@@ -6868,6 +6916,14 @@ class ReplayContainer {
|
|
|
6868
6916
|
this._debouncedFlush = debounce(() => this._flush(), this._options.flushMinDelay, {
|
|
6869
6917
|
maxWait: this._options.flushMaxDelay,
|
|
6870
6918
|
});
|
|
6919
|
+
|
|
6920
|
+
this._throttledAddEvent = throttle(
|
|
6921
|
+
(event, isCheckout) => addEvent(this, event, isCheckout),
|
|
6922
|
+
// Max 300 events...
|
|
6923
|
+
300,
|
|
6924
|
+
// ... per 5s
|
|
6925
|
+
5,
|
|
6926
|
+
);
|
|
6871
6927
|
}
|
|
6872
6928
|
|
|
6873
6929
|
/** Get the event context. */
|
|
@@ -7297,6 +7353,52 @@ class ReplayContainer {
|
|
|
7297
7353
|
this._context.urls.push(url);
|
|
7298
7354
|
}
|
|
7299
7355
|
|
|
7356
|
+
/**
|
|
7357
|
+
* Add a breadcrumb event, that may be throttled.
|
|
7358
|
+
* If it was throttled, we add a custom breadcrumb to indicate that.
|
|
7359
|
+
*/
|
|
7360
|
+
throttledAddEvent(
|
|
7361
|
+
event,
|
|
7362
|
+
isCheckout,
|
|
7363
|
+
) {
|
|
7364
|
+
const res = this._throttledAddEvent(event, isCheckout);
|
|
7365
|
+
|
|
7366
|
+
// If this is THROTTLED, it means we have throttled the event for the first time
|
|
7367
|
+
// In this case, we want to add a breadcrumb indicating that something was skipped
|
|
7368
|
+
if (res === THROTTLED) {
|
|
7369
|
+
const breadcrumb = createBreadcrumb({
|
|
7370
|
+
category: 'replay.throttled',
|
|
7371
|
+
});
|
|
7372
|
+
|
|
7373
|
+
this.addUpdate(() => {
|
|
7374
|
+
void addEvent(this, {
|
|
7375
|
+
type: EventType$1.Custom,
|
|
7376
|
+
timestamp: breadcrumb.timestamp || 0,
|
|
7377
|
+
data: {
|
|
7378
|
+
tag: 'breadcrumb',
|
|
7379
|
+
payload: breadcrumb,
|
|
7380
|
+
metric: true,
|
|
7381
|
+
},
|
|
7382
|
+
});
|
|
7383
|
+
});
|
|
7384
|
+
}
|
|
7385
|
+
|
|
7386
|
+
return res;
|
|
7387
|
+
}
|
|
7388
|
+
|
|
7389
|
+
/**
|
|
7390
|
+
* This will get the parametrized route name of the current page.
|
|
7391
|
+
* This is only available if performance is enabled, and if an instrumented router is used.
|
|
7392
|
+
*/
|
|
7393
|
+
getCurrentRoute() {
|
|
7394
|
+
const lastTransaction = this.lastTransaction || core.getCurrentHub().getScope().getTransaction();
|
|
7395
|
+
if (!lastTransaction || !['route', 'custom'].includes(lastTransaction.metadata.source)) {
|
|
7396
|
+
return undefined;
|
|
7397
|
+
}
|
|
7398
|
+
|
|
7399
|
+
return lastTransaction.name;
|
|
7400
|
+
}
|
|
7401
|
+
|
|
7300
7402
|
/**
|
|
7301
7403
|
* Initialize and start all listeners to varying events (DOM,
|
|
7302
7404
|
* Performance Observer, Recording, Sentry SDK, etc)
|
|
@@ -7535,7 +7637,7 @@ class ReplayContainer {
|
|
|
7535
7637
|
*/
|
|
7536
7638
|
_createCustomBreadcrumb(breadcrumb) {
|
|
7537
7639
|
this.addUpdate(() => {
|
|
7538
|
-
void
|
|
7640
|
+
void this.throttledAddEvent({
|
|
7539
7641
|
type: EventType$1.Custom,
|
|
7540
7642
|
timestamp: breadcrumb.timestamp || 0,
|
|
7541
7643
|
data: {
|
|
@@ -7734,8 +7836,8 @@ class ReplayContainer {
|
|
|
7734
7836
|
__init18() {this._onMutationHandler = (mutations) => {
|
|
7735
7837
|
const count = mutations.length;
|
|
7736
7838
|
|
|
7737
|
-
const mutationLimit = this._options.
|
|
7738
|
-
const mutationBreadcrumbLimit = this._options.
|
|
7839
|
+
const mutationLimit = this._options.mutationLimit;
|
|
7840
|
+
const mutationBreadcrumbLimit = this._options.mutationBreadcrumbLimit;
|
|
7739
7841
|
const overMutationLimit = mutationLimit && count > mutationLimit;
|
|
7740
7842
|
|
|
7741
7843
|
// Create a breadcrumb if a lot of mutations happen at the same time
|
|
@@ -7745,15 +7847,15 @@ class ReplayContainer {
|
|
|
7745
7847
|
category: 'replay.mutations',
|
|
7746
7848
|
data: {
|
|
7747
7849
|
count,
|
|
7850
|
+
limit: overMutationLimit,
|
|
7748
7851
|
},
|
|
7749
7852
|
});
|
|
7750
7853
|
this._createCustomBreadcrumb(breadcrumb);
|
|
7751
7854
|
}
|
|
7752
7855
|
|
|
7856
|
+
// Stop replay if over the mutation limit
|
|
7753
7857
|
if (overMutationLimit) {
|
|
7754
|
-
|
|
7755
|
-
// Instead, we do a full snapshot
|
|
7756
|
-
this._triggerFullSnapshot(false);
|
|
7858
|
+
void this.stop('mutationLimit');
|
|
7757
7859
|
return false;
|
|
7758
7860
|
}
|
|
7759
7861
|
|
|
@@ -7907,6 +8009,9 @@ class Replay {
|
|
|
7907
8009
|
maskAllInputs = true,
|
|
7908
8010
|
blockAllMedia = true,
|
|
7909
8011
|
|
|
8012
|
+
mutationBreadcrumbLimit = 750,
|
|
8013
|
+
mutationLimit = 10000,
|
|
8014
|
+
|
|
7910
8015
|
networkDetailAllowUrls = [],
|
|
7911
8016
|
networkCaptureBodies = true,
|
|
7912
8017
|
networkRequestHeaders = [],
|
|
@@ -7974,6 +8079,8 @@ class Replay {
|
|
|
7974
8079
|
blockAllMedia,
|
|
7975
8080
|
maskAllInputs,
|
|
7976
8081
|
maskAllText,
|
|
8082
|
+
mutationBreadcrumbLimit,
|
|
8083
|
+
mutationLimit,
|
|
7977
8084
|
networkDetailAllowUrls,
|
|
7978
8085
|
networkCaptureBodies,
|
|
7979
8086
|
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|