@sentry/replay 7.52.0 → 7.53.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/README.md +11 -11
- package/cjs/index.js +238 -34
- package/cjs/index.js.map +1 -1
- package/esm/index.js +238 -34
- package/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/types/coreHandlers/handleDom.d.ts.map +1 -1
- package/types/coreHandlers/handleSlowClick.d.ts +12 -0
- package/types/coreHandlers/handleSlowClick.d.ts.map +1 -0
- package/types/integration.d.ts +1 -1
- package/types/integration.d.ts.map +1 -1
- package/types/replay.d.ts +8 -5
- package/types/replay.d.ts.map +1 -1
- package/types/types.d.ts +31 -1
- package/types/types.d.ts.map +1 -1
- package/types/util/addEvent.d.ts.map +1 -1
- package/types/util/handleRecordingEmit.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -195,17 +195,17 @@ The following options can be configured as options to the integration, in `new R
|
|
|
195
195
|
|
|
196
196
|
The following options can be configured as options to the integration, in `new Replay({})`:
|
|
197
197
|
|
|
198
|
-
| key | type | default | description
|
|
199
|
-
| ---------------- | ------------------------ |
|
|
200
|
-
| maskAllText | boolean | `true` | Mask _all_ text content. Will pass text content through `
|
|
201
|
-
| maskAllInputs | boolean | `true` | Mask values of `<input>` elements. Passes input values through `maskInputFn` before sending to server.
|
|
202
|
-
| blockAllMedia | boolean | `true` | Block _all_ media elements (`img, svg, video, object, picture, embed, map, audio`)
|
|
203
|
-
|
|
|
204
|
-
| block | Array<string> | `.sentry-block, [data-sentry-block]` | Redact any elements that match the DOM selectors. See [privacy](#blocking) section for an example.
|
|
205
|
-
| unblock | Array<string> | `.sentry-unblock, [data-sentry-unblock]`| Do not redact any elements that match the DOM selectors. Useful when using `blockAllMedia`. See [privacy](#blocking) section for an example.
|
|
206
|
-
| mask | Array<string> | `.sentry-mask, [data-sentry-mask]` | Mask all elements that match the given DOM selectors. See [privacy](#masking) section for an example.
|
|
207
|
-
| unmask | Array<string> | `.sentry-unmask, [data-sentry-unmask]` | Unmask all elements that match the given DOM selectors. Useful when using `maskAllText`. See [privacy](#masking) section for an example.
|
|
208
|
-
| ignore | Array<string> | `.sentry-ignore, [data-sentry-ignore]` | Ignores all events on the matching input fields. See [privacy](#ignoring) section for an example.
|
|
198
|
+
| key | type | default | description |
|
|
199
|
+
| ---------------- | ------------------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
200
|
+
| maskAllText | boolean | `true` | Mask _all_ text content. Will pass text content through `maskFn` before sending to server. |
|
|
201
|
+
| maskAllInputs | boolean | `true` | Mask values of `<input>` elements. Passes input values through `maskInputFn` before sending to server. |
|
|
202
|
+
| blockAllMedia | boolean | `true` | Block _all_ media elements (`img, svg, video, object, picture, embed, map, audio`) |
|
|
203
|
+
| maskFn | (text: string) => string | `(text) => '*'.repeat(text.length)` | Function to customize how text content is masked before sending to server. By default, masks text with `*`. |
|
|
204
|
+
| block | Array<string> | `.sentry-block, [data-sentry-block]` | Redact any elements that match the DOM selectors. See [privacy](#blocking) section for an example. |
|
|
205
|
+
| unblock | Array<string> | `.sentry-unblock, [data-sentry-unblock]`| Do not redact any elements that match the DOM selectors. Useful when using `blockAllMedia`. See [privacy](#blocking) section for an example. |
|
|
206
|
+
| mask | Array<string> | `.sentry-mask, [data-sentry-mask]` | Mask all elements that match the given DOM selectors. See [privacy](#masking) section for an example. |
|
|
207
|
+
| unmask | Array<string> | `.sentry-unmask, [data-sentry-unmask]` | Unmask all elements that match the given DOM selectors. Useful when using `maskAllText`. See [privacy](#masking) section for an example. |
|
|
208
|
+
| ignore | Array<string> | `.sentry-ignore, [data-sentry-ignore]` | Ignores all events on the matching input fields. See [privacy](#ignoring) section for an example. |
|
|
209
209
|
|
|
210
210
|
#### Deprecated options
|
|
211
211
|
In order to streamline our privacy options, the following have been deprecated in favor for the respective options above.
|
package/cjs/index.js
CHANGED
|
@@ -3287,6 +3287,23 @@ 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
|
+
|
|
3290
3307
|
/**
|
|
3291
3308
|
* Converts a timestamp to ms, if it was in s, or keeps it as ms.
|
|
3292
3309
|
*/
|
|
@@ -3329,7 +3346,18 @@ async function addEvent(
|
|
|
3329
3346
|
replay.eventBuffer.clear();
|
|
3330
3347
|
}
|
|
3331
3348
|
|
|
3332
|
-
|
|
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);
|
|
3333
3361
|
} catch (error) {
|
|
3334
3362
|
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(error);
|
|
3335
3363
|
await replay.stop('addEvent');
|
|
@@ -3374,6 +3402,141 @@ function addBreadcrumbEvent(replay, breadcrumb) {
|
|
|
3374
3402
|
});
|
|
3375
3403
|
}
|
|
3376
3404
|
|
|
3405
|
+
/**
|
|
3406
|
+
* Detect a slow click on a button/a tag,
|
|
3407
|
+
* and potentially create a corresponding breadcrumb.
|
|
3408
|
+
*/
|
|
3409
|
+
function detectSlowClick(
|
|
3410
|
+
replay,
|
|
3411
|
+
config,
|
|
3412
|
+
clickBreadcrumb,
|
|
3413
|
+
node,
|
|
3414
|
+
) {
|
|
3415
|
+
if (ignoreElement(node, config)) {
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
/*
|
|
3420
|
+
We consider a slow click a click on a button/a, which does not trigger one of:
|
|
3421
|
+
- DOM mutation
|
|
3422
|
+
- Scroll (within 100ms)
|
|
3423
|
+
Within the given threshold time.
|
|
3424
|
+
After time timeout time, we stop listening and mark it as a slow click anyhow.
|
|
3425
|
+
*/
|
|
3426
|
+
|
|
3427
|
+
let cleanup = () => {
|
|
3428
|
+
// replaced further down
|
|
3429
|
+
};
|
|
3430
|
+
|
|
3431
|
+
// After timeout time, def. consider this a slow click, and stop watching for mutations
|
|
3432
|
+
const timeout = setTimeout(() => {
|
|
3433
|
+
handleSlowClick(replay, clickBreadcrumb, config.timeout, 'timeout');
|
|
3434
|
+
cleanup();
|
|
3435
|
+
}, config.timeout);
|
|
3436
|
+
|
|
3437
|
+
const mutationHandler = () => {
|
|
3438
|
+
maybeHandleSlowClick(replay, clickBreadcrumb, config.threshold, config.timeout, 'mutation');
|
|
3439
|
+
cleanup();
|
|
3440
|
+
};
|
|
3441
|
+
|
|
3442
|
+
const scrollHandler = () => {
|
|
3443
|
+
maybeHandleSlowClick(replay, clickBreadcrumb, config.scrollTimeout, config.timeout, 'scroll');
|
|
3444
|
+
cleanup();
|
|
3445
|
+
};
|
|
3446
|
+
|
|
3447
|
+
const obs = new MutationObserver(mutationHandler);
|
|
3448
|
+
|
|
3449
|
+
obs.observe(WINDOW.document.documentElement, {
|
|
3450
|
+
attributes: true,
|
|
3451
|
+
characterData: true,
|
|
3452
|
+
childList: true,
|
|
3453
|
+
subtree: true,
|
|
3454
|
+
});
|
|
3455
|
+
|
|
3456
|
+
WINDOW.addEventListener('scroll', scrollHandler);
|
|
3457
|
+
|
|
3458
|
+
// Stop listening to scroll timeouts early
|
|
3459
|
+
const scrollTimeout = setTimeout(() => {
|
|
3460
|
+
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
3461
|
+
}, config.scrollTimeout);
|
|
3462
|
+
|
|
3463
|
+
cleanup = () => {
|
|
3464
|
+
clearTimeout(timeout);
|
|
3465
|
+
clearTimeout(scrollTimeout);
|
|
3466
|
+
obs.disconnect();
|
|
3467
|
+
WINDOW.removeEventListener('scroll', scrollHandler);
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
function maybeHandleSlowClick(
|
|
3472
|
+
replay,
|
|
3473
|
+
clickBreadcrumb,
|
|
3474
|
+
threshold,
|
|
3475
|
+
timeout,
|
|
3476
|
+
endReason,
|
|
3477
|
+
) {
|
|
3478
|
+
const now = Date.now();
|
|
3479
|
+
const timeAfterClickMs = now - clickBreadcrumb.timestamp * 1000;
|
|
3480
|
+
|
|
3481
|
+
if (timeAfterClickMs > threshold) {
|
|
3482
|
+
handleSlowClick(replay, clickBreadcrumb, Math.min(timeAfterClickMs, timeout), endReason);
|
|
3483
|
+
return true;
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3486
|
+
return false;
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
function handleSlowClick(
|
|
3490
|
+
replay,
|
|
3491
|
+
clickBreadcrumb,
|
|
3492
|
+
timeAfterClickMs,
|
|
3493
|
+
endReason,
|
|
3494
|
+
) {
|
|
3495
|
+
const breadcrumb = {
|
|
3496
|
+
message: clickBreadcrumb.message,
|
|
3497
|
+
timestamp: clickBreadcrumb.timestamp,
|
|
3498
|
+
category: 'ui.slowClickDetected',
|
|
3499
|
+
data: {
|
|
3500
|
+
...clickBreadcrumb.data,
|
|
3501
|
+
url: WINDOW.location.href,
|
|
3502
|
+
// TODO FN: add parametrized route, when possible
|
|
3503
|
+
timeAfterClickMs,
|
|
3504
|
+
endReason,
|
|
3505
|
+
},
|
|
3506
|
+
};
|
|
3507
|
+
|
|
3508
|
+
addBreadcrumbEvent(replay, breadcrumb);
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
const SLOW_CLICK_IGNORE_TAGS = ['SELECT', 'OPTION'];
|
|
3512
|
+
|
|
3513
|
+
function ignoreElement(node, config) {
|
|
3514
|
+
// If <input> tag, we only want to consider input[type='submit'] & input[type='button']
|
|
3515
|
+
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
|
|
3516
|
+
return true;
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
if (SLOW_CLICK_IGNORE_TAGS.includes(node.tagName)) {
|
|
3520
|
+
return true;
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
// If <a> tag, detect special variants that may not lead to an action
|
|
3524
|
+
// If target !== _self, we may open the link somewhere else, which would lead to no action
|
|
3525
|
+
// Also, when downloading a file, we may not leave the page, but still not trigger an action
|
|
3526
|
+
if (
|
|
3527
|
+
node.tagName === 'A' &&
|
|
3528
|
+
(node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
|
|
3529
|
+
) {
|
|
3530
|
+
return true;
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
if (config.ignoreSelector && node.matches(config.ignoreSelector)) {
|
|
3534
|
+
return true;
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
return false;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3377
3540
|
// Note that these are the serialized attributes and not attributes directly on
|
|
3378
3541
|
// the DOM Node. Attributes we are interested in:
|
|
3379
3542
|
const ATTRIBUTES_TO_RECORD = new Set([
|
|
@@ -3408,9 +3571,21 @@ function getAttributesToRecord(attributes) {
|
|
|
3408
3571
|
return obj;
|
|
3409
3572
|
}
|
|
3410
3573
|
|
|
3411
|
-
const handleDomListener =
|
|
3412
|
-
|
|
3413
|
-
|
|
3574
|
+
const handleDomListener = (
|
|
3575
|
+
replay,
|
|
3576
|
+
) => {
|
|
3577
|
+
const slowClickExperiment = replay.getOptions()._experiments.slowClicks;
|
|
3578
|
+
|
|
3579
|
+
const slowClickConfig = slowClickExperiment
|
|
3580
|
+
? {
|
|
3581
|
+
threshold: slowClickExperiment.threshold,
|
|
3582
|
+
timeout: slowClickExperiment.timeout,
|
|
3583
|
+
scrollTimeout: slowClickExperiment.scrollTimeout,
|
|
3584
|
+
ignoreSelector: slowClickExperiment.ignoreSelectors ? slowClickExperiment.ignoreSelectors.join(',') : '',
|
|
3585
|
+
}
|
|
3586
|
+
: undefined;
|
|
3587
|
+
|
|
3588
|
+
return (handlerData) => {
|
|
3414
3589
|
if (!replay.isEnabled()) {
|
|
3415
3590
|
return;
|
|
3416
3591
|
}
|
|
@@ -3421,8 +3596,21 @@ const handleDomListener =
|
|
|
3421
3596
|
return;
|
|
3422
3597
|
}
|
|
3423
3598
|
|
|
3599
|
+
const isClick = handlerData.name === 'click';
|
|
3600
|
+
const event = isClick && (handlerData.event );
|
|
3601
|
+
// Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
|
|
3602
|
+
if (isClick && slowClickConfig && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
|
|
3603
|
+
detectSlowClick(
|
|
3604
|
+
replay,
|
|
3605
|
+
slowClickConfig,
|
|
3606
|
+
result ,
|
|
3607
|
+
getClickTargetNode(handlerData.event) ,
|
|
3608
|
+
);
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3424
3611
|
addBreadcrumbEvent(replay, result);
|
|
3425
3612
|
};
|
|
3613
|
+
};
|
|
3426
3614
|
|
|
3427
3615
|
/** Get the base DOM breadcrumb. */
|
|
3428
3616
|
function getBaseDomBreadcrumb(target, message) {
|
|
@@ -6145,23 +6333,6 @@ function debounce(func, wait, options) {
|
|
|
6145
6333
|
return debounced;
|
|
6146
6334
|
}
|
|
6147
6335
|
|
|
6148
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
6149
|
-
|
|
6150
|
-
var EventType; (function (EventType) {
|
|
6151
|
-
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
6152
|
-
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
6153
|
-
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
6154
|
-
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
6155
|
-
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
6156
|
-
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
6157
|
-
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
6158
|
-
})(EventType || (EventType = {}));
|
|
6159
|
-
|
|
6160
|
-
/**
|
|
6161
|
-
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
6162
|
-
* we specifcally need in the SDK.
|
|
6163
|
-
*/
|
|
6164
|
-
|
|
6165
6336
|
/**
|
|
6166
6337
|
* Handler for recording events.
|
|
6167
6338
|
*
|
|
@@ -6235,6 +6406,30 @@ function getHandleRecordingEmit(replay) {
|
|
|
6235
6406
|
}
|
|
6236
6407
|
}
|
|
6237
6408
|
|
|
6409
|
+
const options = replay.getOptions();
|
|
6410
|
+
|
|
6411
|
+
// TODO: We want this as an experiment so that we can test
|
|
6412
|
+
// internally and create metrics before making this the default
|
|
6413
|
+
if (options._experiments.delayFlushOnCheckout) {
|
|
6414
|
+
// If the full snapshot is due to an initial load, we will not have
|
|
6415
|
+
// a previous session ID. In this case, we want to buffer events
|
|
6416
|
+
// for a set amount of time before flushing. This can help avoid
|
|
6417
|
+
// capturing replays of users that immediately close the window.
|
|
6418
|
+
setTimeout(() => replay.conditionalFlush(), options._experiments.delayFlushOnCheckout);
|
|
6419
|
+
|
|
6420
|
+
// Cancel any previously debounced flushes to ensure there are no [near]
|
|
6421
|
+
// simultaneous flushes happening. The latter request should be
|
|
6422
|
+
// insignificant in this case, so wait for additional user interaction to
|
|
6423
|
+
// trigger a new flush.
|
|
6424
|
+
//
|
|
6425
|
+
// This can happen because there's no guarantee that a recording event
|
|
6426
|
+
// happens first. e.g. a mouse click can happen and trigger a debounced
|
|
6427
|
+
// flush before the checkout.
|
|
6428
|
+
replay.cancelFlush();
|
|
6429
|
+
|
|
6430
|
+
return true;
|
|
6431
|
+
}
|
|
6432
|
+
|
|
6238
6433
|
// Flush immediately so that we do not miss the first segment, otherwise
|
|
6239
6434
|
// it can prevent loading on the UI. This will cause an increase in short
|
|
6240
6435
|
// replays (e.g. opening and closing a tab quickly), but these can be
|
|
@@ -7000,7 +7195,17 @@ class ReplayContainer {
|
|
|
7000
7195
|
}
|
|
7001
7196
|
|
|
7002
7197
|
/**
|
|
7003
|
-
*
|
|
7198
|
+
* Only flush if `this.recordingMode === 'session'`
|
|
7199
|
+
*/
|
|
7200
|
+
conditionalFlush() {
|
|
7201
|
+
if (this.recordingMode === 'buffer') {
|
|
7202
|
+
return Promise.resolve();
|
|
7203
|
+
}
|
|
7204
|
+
|
|
7205
|
+
return this.flushImmediate();
|
|
7206
|
+
}
|
|
7207
|
+
|
|
7208
|
+
/**
|
|
7004
7209
|
* Always flush via `_debouncedFlush` so that we do not have flushes triggered
|
|
7005
7210
|
* from calling both `flush` and `_debouncedFlush`. Otherwise, there could be
|
|
7006
7211
|
* cases of mulitple flushes happening closely together.
|
|
@@ -7011,6 +7216,13 @@ class ReplayContainer {
|
|
|
7011
7216
|
return this._debouncedFlush.flush() ;
|
|
7012
7217
|
}
|
|
7013
7218
|
|
|
7219
|
+
/**
|
|
7220
|
+
* Cancels queued up flushes.
|
|
7221
|
+
*/
|
|
7222
|
+
cancelFlush() {
|
|
7223
|
+
this._debouncedFlush.cancel();
|
|
7224
|
+
}
|
|
7225
|
+
|
|
7014
7226
|
/** Get the current sesion (=replay) ID */
|
|
7015
7227
|
getSessionId() {
|
|
7016
7228
|
return this.session && this.session.id;
|
|
@@ -7260,7 +7472,7 @@ class ReplayContainer {
|
|
|
7260
7472
|
// Send replay when the page/tab becomes hidden. There is no reason to send
|
|
7261
7473
|
// replay if it becomes visible, since no actions we care about were done
|
|
7262
7474
|
// while it was hidden
|
|
7263
|
-
this.
|
|
7475
|
+
void this.conditionalFlush();
|
|
7264
7476
|
}
|
|
7265
7477
|
|
|
7266
7478
|
/**
|
|
@@ -7344,17 +7556,6 @@ class ReplayContainer {
|
|
|
7344
7556
|
return Promise.all(createPerformanceSpans(this, createPerformanceEntries(entries)));
|
|
7345
7557
|
}
|
|
7346
7558
|
|
|
7347
|
-
/**
|
|
7348
|
-
* Only flush if `this.recordingMode === 'session'`
|
|
7349
|
-
*/
|
|
7350
|
-
_conditionalFlush() {
|
|
7351
|
-
if (this.recordingMode === 'buffer') {
|
|
7352
|
-
return;
|
|
7353
|
-
}
|
|
7354
|
-
|
|
7355
|
-
void this.flushImmediate();
|
|
7356
|
-
}
|
|
7357
|
-
|
|
7358
7559
|
/**
|
|
7359
7560
|
* Clear _context
|
|
7360
7561
|
*/
|
|
@@ -7716,6 +7917,8 @@ class Replay {
|
|
|
7716
7917
|
ignore = [],
|
|
7717
7918
|
maskFn,
|
|
7718
7919
|
|
|
7920
|
+
beforeAddRecordingEvent,
|
|
7921
|
+
|
|
7719
7922
|
// eslint-disable-next-line deprecation/deprecation
|
|
7720
7923
|
blockClass,
|
|
7721
7924
|
// eslint-disable-next-line deprecation/deprecation
|
|
@@ -7773,6 +7976,7 @@ class Replay {
|
|
|
7773
7976
|
networkCaptureBodies,
|
|
7774
7977
|
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|
|
7775
7978
|
networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
|
|
7979
|
+
beforeAddRecordingEvent,
|
|
7776
7980
|
|
|
7777
7981
|
_experiments,
|
|
7778
7982
|
};
|