@sentry/replay 7.54.0 → 7.55.1
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 +104 -63
- package/cjs/index.js.map +1 -1
- package/esm/index.js +104 -63
- package/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/types/constants.d.ts +2 -0
- package/types/constants.d.ts.map +1 -1
- package/types/coreHandlers/handleDom.d.ts.map +1 -1
- package/types/coreHandlers/handleKeyboardEvent.d.ts.map +1 -1
- package/types/coreHandlers/handleScope.d.ts +4 -1
- package/types/coreHandlers/handleScope.d.ts.map +1 -1
- package/types/coreHandlers/handleSlowClick.d.ts +2 -0
- package/types/coreHandlers/handleSlowClick.d.ts.map +1 -1
- package/types/coreHandlers/util/getAttributesToRecord.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.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 +8 -0
- package/types/replay.d.ts.map +1 -1
- package/types/session/getSession.d.ts.map +1 -1
- package/types/types/index.d.ts +6 -0
- package/types/types/index.d.ts.map +1 -0
- package/types/types/performance.d.ts +124 -0
- package/types/types/performance.d.ts.map +1 -0
- package/types/{types.d.ts → types/replay.d.ts} +21 -144
- package/types/types/replay.d.ts.map +1 -0
- package/types/types/replayFrame.d.ts +160 -0
- package/types/types/replayFrame.d.ts.map +1 -0
- package/types/types/request.d.ts +15 -0
- package/types/types/request.d.ts.map +1 -0
- package/types/types/rrweb.d.ts +1 -9
- package/types/types/rrweb.d.ts.map +1 -1
- package/types/util/addEvent.d.ts.map +1 -1
- package/types/util/createBreadcrumb.d.ts +2 -4
- package/types/util/createBreadcrumb.d.ts.map +1 -1
- package/types/util/handleRecordingEmit.d.ts +2 -2
- package/types/util/handleRecordingEmit.d.ts.map +1 -1
- package/types/types.d.ts.map +0 -1
package/esm/index.js
CHANGED
|
@@ -38,6 +38,11 @@ const NETWORK_BODY_MAX_SIZE = 150000;
|
|
|
38
38
|
/* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
|
|
39
39
|
const CONSOLE_ARG_MAX_SIZE = 5000;
|
|
40
40
|
|
|
41
|
+
/* Min. time to wait before we consider something a slow click. */
|
|
42
|
+
const SLOW_CLICK_THRESHOLD = 3000;
|
|
43
|
+
/* For scroll actions after a click, we only look for a very short time period to detect programmatic scrolling. */
|
|
44
|
+
const SLOW_CLICK_SCROLL_TIMEOUT = 300;
|
|
45
|
+
|
|
41
46
|
var NodeType$1;
|
|
42
47
|
(function (NodeType) {
|
|
43
48
|
NodeType[NodeType["Document"] = 0] = "Document";
|
|
@@ -991,7 +996,7 @@ function skipAttribute(tagName, attributeName, value) {
|
|
|
991
996
|
return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
|
|
992
997
|
}
|
|
993
998
|
|
|
994
|
-
var EventType
|
|
999
|
+
var EventType;
|
|
995
1000
|
(function (EventType) {
|
|
996
1001
|
EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
|
|
997
1002
|
EventType[EventType["Load"] = 1] = "Load";
|
|
@@ -1000,7 +1005,7 @@ var EventType$1;
|
|
|
1000
1005
|
EventType[EventType["Meta"] = 4] = "Meta";
|
|
1001
1006
|
EventType[EventType["Custom"] = 5] = "Custom";
|
|
1002
1007
|
EventType[EventType["Plugin"] = 6] = "Plugin";
|
|
1003
|
-
})(EventType
|
|
1008
|
+
})(EventType || (EventType = {}));
|
|
1004
1009
|
var IncrementalSource;
|
|
1005
1010
|
(function (IncrementalSource) {
|
|
1006
1011
|
IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
|
|
@@ -2973,17 +2978,17 @@ function record(options = {}) {
|
|
|
2973
2978
|
wrappedEmit = (e, isCheckout) => {
|
|
2974
2979
|
var _a;
|
|
2975
2980
|
if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
|
|
2976
|
-
e.type !== EventType
|
|
2977
|
-
!(e.type === EventType
|
|
2981
|
+
e.type !== EventType.FullSnapshot &&
|
|
2982
|
+
!(e.type === EventType.IncrementalSnapshot &&
|
|
2978
2983
|
e.data.source === IncrementalSource.Mutation)) {
|
|
2979
2984
|
mutationBuffers.forEach((buf) => buf.unfreeze());
|
|
2980
2985
|
}
|
|
2981
2986
|
emit(eventProcessor(e), isCheckout);
|
|
2982
|
-
if (e.type === EventType
|
|
2987
|
+
if (e.type === EventType.FullSnapshot) {
|
|
2983
2988
|
lastFullSnapshotEvent = e;
|
|
2984
2989
|
incrementalSnapshotCount = 0;
|
|
2985
2990
|
}
|
|
2986
|
-
else if (e.type === EventType
|
|
2991
|
+
else if (e.type === EventType.IncrementalSnapshot) {
|
|
2987
2992
|
if (e.data.source === IncrementalSource.Mutation &&
|
|
2988
2993
|
e.data.isAttachIframe) {
|
|
2989
2994
|
return;
|
|
@@ -2999,16 +3004,16 @@ function record(options = {}) {
|
|
|
2999
3004
|
};
|
|
3000
3005
|
const wrappedMutationEmit = (m) => {
|
|
3001
3006
|
wrappedEmit(wrapEvent({
|
|
3002
|
-
type: EventType
|
|
3007
|
+
type: EventType.IncrementalSnapshot,
|
|
3003
3008
|
data: Object.assign({ source: IncrementalSource.Mutation }, m),
|
|
3004
3009
|
}));
|
|
3005
3010
|
};
|
|
3006
3011
|
const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
|
|
3007
|
-
type: EventType
|
|
3012
|
+
type: EventType.IncrementalSnapshot,
|
|
3008
3013
|
data: Object.assign({ source: IncrementalSource.Scroll }, p),
|
|
3009
3014
|
}));
|
|
3010
3015
|
const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
|
|
3011
|
-
type: EventType
|
|
3016
|
+
type: EventType.IncrementalSnapshot,
|
|
3012
3017
|
data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
|
|
3013
3018
|
}));
|
|
3014
3019
|
const iframeManager = new IframeManager({
|
|
@@ -3053,7 +3058,7 @@ function record(options = {}) {
|
|
|
3053
3058
|
takeFullSnapshot = (isCheckout = false) => {
|
|
3054
3059
|
var _a, _b, _c, _d;
|
|
3055
3060
|
wrappedEmit(wrapEvent({
|
|
3056
|
-
type: EventType
|
|
3061
|
+
type: EventType.Meta,
|
|
3057
3062
|
data: {
|
|
3058
3063
|
href: window.location.href,
|
|
3059
3064
|
width: getWindowWidth(),
|
|
@@ -3096,7 +3101,7 @@ function record(options = {}) {
|
|
|
3096
3101
|
}
|
|
3097
3102
|
mirror.map = idNodeMap;
|
|
3098
3103
|
wrappedEmit(wrapEvent({
|
|
3099
|
-
type: EventType
|
|
3104
|
+
type: EventType.FullSnapshot,
|
|
3100
3105
|
data: {
|
|
3101
3106
|
node,
|
|
3102
3107
|
initialOffset: {
|
|
@@ -3121,7 +3126,7 @@ function record(options = {}) {
|
|
|
3121
3126
|
const handlers = [];
|
|
3122
3127
|
handlers.push(on('DOMContentLoaded', () => {
|
|
3123
3128
|
wrappedEmit(wrapEvent({
|
|
3124
|
-
type: EventType
|
|
3129
|
+
type: EventType.DomContentLoaded,
|
|
3125
3130
|
data: {},
|
|
3126
3131
|
}));
|
|
3127
3132
|
}));
|
|
@@ -3131,40 +3136,40 @@ function record(options = {}) {
|
|
|
3131
3136
|
onMutation,
|
|
3132
3137
|
mutationCb: wrappedMutationEmit,
|
|
3133
3138
|
mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
|
|
3134
|
-
type: EventType
|
|
3139
|
+
type: EventType.IncrementalSnapshot,
|
|
3135
3140
|
data: {
|
|
3136
3141
|
source,
|
|
3137
3142
|
positions,
|
|
3138
3143
|
},
|
|
3139
3144
|
})),
|
|
3140
3145
|
mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
|
|
3141
|
-
type: EventType
|
|
3146
|
+
type: EventType.IncrementalSnapshot,
|
|
3142
3147
|
data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
|
|
3143
3148
|
})),
|
|
3144
3149
|
scrollCb: wrappedScrollEmit,
|
|
3145
3150
|
viewportResizeCb: (d) => wrappedEmit(wrapEvent({
|
|
3146
|
-
type: EventType
|
|
3151
|
+
type: EventType.IncrementalSnapshot,
|
|
3147
3152
|
data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
|
|
3148
3153
|
})),
|
|
3149
3154
|
inputCb: (v) => wrappedEmit(wrapEvent({
|
|
3150
|
-
type: EventType
|
|
3155
|
+
type: EventType.IncrementalSnapshot,
|
|
3151
3156
|
data: Object.assign({ source: IncrementalSource.Input }, v),
|
|
3152
3157
|
})),
|
|
3153
3158
|
mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
|
|
3154
|
-
type: EventType
|
|
3159
|
+
type: EventType.IncrementalSnapshot,
|
|
3155
3160
|
data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
|
|
3156
3161
|
})),
|
|
3157
3162
|
styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
|
|
3158
|
-
type: EventType
|
|
3163
|
+
type: EventType.IncrementalSnapshot,
|
|
3159
3164
|
data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
|
|
3160
3165
|
})),
|
|
3161
3166
|
styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
|
|
3162
|
-
type: EventType
|
|
3167
|
+
type: EventType.IncrementalSnapshot,
|
|
3163
3168
|
data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
|
|
3164
3169
|
})),
|
|
3165
3170
|
canvasMutationCb: wrappedCanvasMutationEmit,
|
|
3166
3171
|
fontCb: (p) => wrappedEmit(wrapEvent({
|
|
3167
|
-
type: EventType
|
|
3172
|
+
type: EventType.IncrementalSnapshot,
|
|
3168
3173
|
data: Object.assign({ source: IncrementalSource.Font }, p),
|
|
3169
3174
|
})),
|
|
3170
3175
|
blockClass,
|
|
@@ -3197,7 +3202,7 @@ function record(options = {}) {
|
|
|
3197
3202
|
observer: p.observer,
|
|
3198
3203
|
options: p.options,
|
|
3199
3204
|
callback: (payload) => wrappedEmit(wrapEvent({
|
|
3200
|
-
type: EventType
|
|
3205
|
+
type: EventType.Plugin,
|
|
3201
3206
|
data: {
|
|
3202
3207
|
plugin: p.name,
|
|
3203
3208
|
payload,
|
|
@@ -3225,7 +3230,7 @@ function record(options = {}) {
|
|
|
3225
3230
|
else {
|
|
3226
3231
|
handlers.push(on('load', () => {
|
|
3227
3232
|
wrappedEmit(wrapEvent({
|
|
3228
|
-
type: EventType
|
|
3233
|
+
type: EventType.Load,
|
|
3229
3234
|
data: {},
|
|
3230
3235
|
}));
|
|
3231
3236
|
init();
|
|
@@ -3244,7 +3249,7 @@ record.addCustomEvent = (tag, payload) => {
|
|
|
3244
3249
|
throw new Error('please add custom event after start recording');
|
|
3245
3250
|
}
|
|
3246
3251
|
wrappedEmit(wrapEvent({
|
|
3247
|
-
type: EventType
|
|
3252
|
+
type: EventType.Custom,
|
|
3248
3253
|
data: {
|
|
3249
3254
|
tag,
|
|
3250
3255
|
payload,
|
|
@@ -3301,7 +3306,7 @@ function addBreadcrumbEvent(replay, breadcrumb) {
|
|
|
3301
3306
|
|
|
3302
3307
|
replay.addUpdate(() => {
|
|
3303
3308
|
void replay.throttledAddEvent({
|
|
3304
|
-
type: EventType
|
|
3309
|
+
type: EventType.Custom,
|
|
3305
3310
|
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
|
|
3306
3311
|
// but maybe we should just keep them as milliseconds
|
|
3307
3312
|
timestamp: (breadcrumb.timestamp || 0) * 1000,
|
|
@@ -3423,15 +3428,16 @@ function handleSlowClick(
|
|
|
3423
3428
|
addBreadcrumbEvent(replay, breadcrumb);
|
|
3424
3429
|
}
|
|
3425
3430
|
|
|
3426
|
-
const
|
|
3431
|
+
const SLOW_CLICK_TAGS = ['A', 'BUTTON', 'INPUT'];
|
|
3427
3432
|
|
|
3433
|
+
/** exported for tests only */
|
|
3428
3434
|
function ignoreElement(node, config) {
|
|
3429
|
-
|
|
3430
|
-
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
|
|
3435
|
+
if (!SLOW_CLICK_TAGS.includes(node.tagName)) {
|
|
3431
3436
|
return true;
|
|
3432
3437
|
}
|
|
3433
3438
|
|
|
3434
|
-
|
|
3439
|
+
// If <input> tag, we only want to consider input[type='submit'] & input[type='button']
|
|
3440
|
+
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
|
|
3435
3441
|
return true;
|
|
3436
3442
|
}
|
|
3437
3443
|
|
|
@@ -3464,6 +3470,8 @@ const ATTRIBUTES_TO_RECORD = new Set([
|
|
|
3464
3470
|
'title',
|
|
3465
3471
|
'data-test-id',
|
|
3466
3472
|
'data-testid',
|
|
3473
|
+
'disabled',
|
|
3474
|
+
'aria-disabled',
|
|
3467
3475
|
]);
|
|
3468
3476
|
|
|
3469
3477
|
/**
|
|
@@ -3489,14 +3497,14 @@ function getAttributesToRecord(attributes) {
|
|
|
3489
3497
|
const handleDomListener = (
|
|
3490
3498
|
replay,
|
|
3491
3499
|
) => {
|
|
3492
|
-
const
|
|
3500
|
+
const { slowClickTimeout, slowClickIgnoreSelectors } = replay.getOptions();
|
|
3493
3501
|
|
|
3494
|
-
const slowClickConfig =
|
|
3502
|
+
const slowClickConfig = slowClickTimeout
|
|
3495
3503
|
? {
|
|
3496
|
-
threshold:
|
|
3497
|
-
timeout:
|
|
3498
|
-
scrollTimeout:
|
|
3499
|
-
ignoreSelector:
|
|
3504
|
+
threshold: Math.min(SLOW_CLICK_THRESHOLD, slowClickTimeout),
|
|
3505
|
+
timeout: slowClickTimeout,
|
|
3506
|
+
scrollTimeout: SLOW_CLICK_SCROLL_TIMEOUT,
|
|
3507
|
+
ignoreSelector: slowClickIgnoreSelectors ? slowClickIgnoreSelectors.join(',') : '',
|
|
3500
3508
|
}
|
|
3501
3509
|
: undefined;
|
|
3502
3510
|
|
|
@@ -3625,7 +3633,10 @@ function handleKeyboardEvent(replay, event) {
|
|
|
3625
3633
|
return;
|
|
3626
3634
|
}
|
|
3627
3635
|
|
|
3628
|
-
|
|
3636
|
+
// Update user activity, but do not restart recording as it can create
|
|
3637
|
+
// noisy/low-value replays (e.g. user comes back from idle, hits alt-tab, new
|
|
3638
|
+
// session with a single "keydown" breadcrumb is created)
|
|
3639
|
+
replay.updateUserActivity();
|
|
3629
3640
|
|
|
3630
3641
|
const breadcrumb = getKeyboardBreadcrumb(event);
|
|
3631
3642
|
|
|
@@ -4376,11 +4387,13 @@ function getSession({
|
|
|
4376
4387
|
// within "max session time").
|
|
4377
4388
|
const isExpired = isSessionExpired(session, timeouts);
|
|
4378
4389
|
|
|
4379
|
-
if (!isExpired) {
|
|
4390
|
+
if (!isExpired || (allowBuffering && session.shouldRefresh)) {
|
|
4380
4391
|
return { type: 'saved', session };
|
|
4381
4392
|
} else if (!session.shouldRefresh) {
|
|
4382
|
-
//
|
|
4383
|
-
//
|
|
4393
|
+
// This is the case if we have an error session that is completed
|
|
4394
|
+
// (=triggered an error). Session will continue as session-based replay,
|
|
4395
|
+
// and when this session is expired, it will not be renewed until user
|
|
4396
|
+
// reloads.
|
|
4384
4397
|
const discardedSession = makeSession({ sampled: false });
|
|
4385
4398
|
return { type: 'new', session: discardedSession };
|
|
4386
4399
|
} else {
|
|
@@ -4398,22 +4411,9 @@ function getSession({
|
|
|
4398
4411
|
return { type: 'new', session: newSession };
|
|
4399
4412
|
}
|
|
4400
4413
|
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
const DomContentLoaded = 0; EventType[EventType["DomContentLoaded"] = DomContentLoaded] = "DomContentLoaded";
|
|
4405
|
-
const Load = 1; EventType[EventType["Load"] = Load] = "Load";
|
|
4406
|
-
const FullSnapshot = 2; EventType[EventType["FullSnapshot"] = FullSnapshot] = "FullSnapshot";
|
|
4407
|
-
const IncrementalSnapshot = 3; EventType[EventType["IncrementalSnapshot"] = IncrementalSnapshot] = "IncrementalSnapshot";
|
|
4408
|
-
const Meta = 4; EventType[EventType["Meta"] = Meta] = "Meta";
|
|
4409
|
-
const Custom = 5; EventType[EventType["Custom"] = Custom] = "Custom";
|
|
4410
|
-
const Plugin = 6; EventType[EventType["Plugin"] = Plugin] = "Plugin";
|
|
4411
|
-
})(EventType || (EventType = {}));
|
|
4412
|
-
|
|
4413
|
-
/**
|
|
4414
|
-
* This is a partial copy of rrweb's eventWithTime type which only contains the properties
|
|
4415
|
-
* we specifcally need in the SDK.
|
|
4416
|
-
*/
|
|
4414
|
+
function isCustomEvent(event) {
|
|
4415
|
+
return event.type === EventType.Custom;
|
|
4416
|
+
}
|
|
4417
4417
|
|
|
4418
4418
|
/**
|
|
4419
4419
|
* Add an event to the event buffer.
|
|
@@ -4452,7 +4452,7 @@ async function addEvent(
|
|
|
4452
4452
|
const replayOptions = replay.getOptions();
|
|
4453
4453
|
|
|
4454
4454
|
const eventAfterPossibleCallback =
|
|
4455
|
-
typeof replayOptions.beforeAddRecordingEvent === 'function' && event
|
|
4455
|
+
typeof replayOptions.beforeAddRecordingEvent === 'function' && isCustomEvent(event)
|
|
4456
4456
|
? replayOptions.beforeAddRecordingEvent(event)
|
|
4457
4457
|
: event;
|
|
4458
4458
|
|
|
@@ -4667,7 +4667,7 @@ function createPerformanceSpans(
|
|
|
4667
4667
|
) {
|
|
4668
4668
|
return entries.map(({ type, start, end, name, data }) => {
|
|
4669
4669
|
const response = replay.throttledAddEvent({
|
|
4670
|
-
type: EventType
|
|
4670
|
+
type: EventType.Custom,
|
|
4671
4671
|
timestamp: start,
|
|
4672
4672
|
data: {
|
|
4673
4673
|
tag: 'performanceSpan',
|
|
@@ -5901,6 +5901,10 @@ function _isFetchHint(hint) {
|
|
|
5901
5901
|
|
|
5902
5902
|
let _LAST_BREADCRUMB = null;
|
|
5903
5903
|
|
|
5904
|
+
function isBreadcrumbWithCategory(breadcrumb) {
|
|
5905
|
+
return !!breadcrumb.category;
|
|
5906
|
+
}
|
|
5907
|
+
|
|
5904
5908
|
const handleScopeListener =
|
|
5905
5909
|
(replay) =>
|
|
5906
5910
|
(scope) => {
|
|
@@ -5936,9 +5940,9 @@ function handleScope(scope) {
|
|
|
5936
5940
|
_LAST_BREADCRUMB = newBreadcrumb;
|
|
5937
5941
|
|
|
5938
5942
|
if (
|
|
5939
|
-
newBreadcrumb
|
|
5940
|
-
|
|
5941
|
-
|
|
5943
|
+
!isBreadcrumbWithCategory(newBreadcrumb) ||
|
|
5944
|
+
['fetch', 'xhr', 'sentry.event', 'sentry.transaction'].includes(newBreadcrumb.category) ||
|
|
5945
|
+
newBreadcrumb.category.startsWith('ui.')
|
|
5942
5946
|
) {
|
|
5943
5947
|
return null;
|
|
5944
5948
|
}
|
|
@@ -5951,7 +5955,9 @@ function handleScope(scope) {
|
|
|
5951
5955
|
}
|
|
5952
5956
|
|
|
5953
5957
|
/** exported for tests only */
|
|
5954
|
-
function normalizeConsoleBreadcrumb(
|
|
5958
|
+
function normalizeConsoleBreadcrumb(
|
|
5959
|
+
breadcrumb,
|
|
5960
|
+
) {
|
|
5955
5961
|
const args = breadcrumb.data && breadcrumb.data.arguments;
|
|
5956
5962
|
|
|
5957
5963
|
if (!Array.isArray(args) || args.length === 0) {
|
|
@@ -6400,6 +6406,10 @@ function getHandleRecordingEmit(replay) {
|
|
|
6400
6406
|
// a previous session ID. In this case, we want to buffer events
|
|
6401
6407
|
// for a set amount of time before flushing. This can help avoid
|
|
6402
6408
|
// capturing replays of users that immediately close the window.
|
|
6409
|
+
// TODO: We should check `recordingMode` here and do nothing if it's
|
|
6410
|
+
// buffer, instead of checking inside of timeout, this will make our
|
|
6411
|
+
// tests a bit cleaner as we will need to wait on the delay in order to
|
|
6412
|
+
// do nothing.
|
|
6403
6413
|
setTimeout(() => replay.conditionalFlush(), options._experiments.delayFlushOnCheckout);
|
|
6404
6414
|
|
|
6405
6415
|
// Cancel any previously debounced flushes to ensure there are no [near]
|
|
@@ -7166,6 +7176,8 @@ class ReplayContainer {
|
|
|
7166
7176
|
return this.flushImmediate();
|
|
7167
7177
|
}
|
|
7168
7178
|
|
|
7179
|
+
const activityTime = Date.now();
|
|
7180
|
+
|
|
7169
7181
|
// Allow flush to complete before resuming as a session recording, otherwise
|
|
7170
7182
|
// the checkout from `startRecording` may be included in the payload.
|
|
7171
7183
|
// Prefer to keep the error replay as a separate (and smaller) segment
|
|
@@ -7187,6 +7199,18 @@ class ReplayContainer {
|
|
|
7187
7199
|
// Once this session ends, we do not want to refresh it
|
|
7188
7200
|
if (this.session) {
|
|
7189
7201
|
this.session.shouldRefresh = false;
|
|
7202
|
+
|
|
7203
|
+
// It's possible that the session lifespan is > max session lifespan
|
|
7204
|
+
// because we have been buffering beyond max session lifespan (we ignore
|
|
7205
|
+
// expiration given that `shouldRefresh` is true). Since we flip
|
|
7206
|
+
// `shouldRefresh`, the session could be considered expired due to
|
|
7207
|
+
// lifespan, which is not what we want. Update session start date to be
|
|
7208
|
+
// the current timestamp, so that session is not considered to be
|
|
7209
|
+
// expired. This means that max replay duration can be MAX_SESSION_LIFE +
|
|
7210
|
+
// (length of buffer), which we are ok with.
|
|
7211
|
+
this._updateUserActivity(activityTime);
|
|
7212
|
+
this._updateSessionActivity(activityTime);
|
|
7213
|
+
this.session.started = activityTime;
|
|
7190
7214
|
this._maybeSaveSession();
|
|
7191
7215
|
}
|
|
7192
7216
|
|
|
@@ -7250,6 +7274,18 @@ class ReplayContainer {
|
|
|
7250
7274
|
this._updateSessionActivity();
|
|
7251
7275
|
}
|
|
7252
7276
|
|
|
7277
|
+
/**
|
|
7278
|
+
* Updates the user activity timestamp *without* resuming
|
|
7279
|
+
* recording. Some user events (e.g. keydown) can be create
|
|
7280
|
+
* low-value replays that only contain the keypress as a
|
|
7281
|
+
* breadcrumb. Instead this would require other events to
|
|
7282
|
+
* create a new replay after a session has expired.
|
|
7283
|
+
*/
|
|
7284
|
+
updateUserActivity() {
|
|
7285
|
+
this._updateUserActivity();
|
|
7286
|
+
this._updateSessionActivity();
|
|
7287
|
+
}
|
|
7288
|
+
|
|
7253
7289
|
/**
|
|
7254
7290
|
* Only flush if `this.recordingMode === 'session'`
|
|
7255
7291
|
*/
|
|
@@ -7370,7 +7406,7 @@ class ReplayContainer {
|
|
|
7370
7406
|
|
|
7371
7407
|
this.addUpdate(() => {
|
|
7372
7408
|
void addEvent(this, {
|
|
7373
|
-
type: EventType
|
|
7409
|
+
type: EventType.Custom,
|
|
7374
7410
|
timestamp: breadcrumb.timestamp || 0,
|
|
7375
7411
|
data: {
|
|
7376
7412
|
tag: 'breadcrumb',
|
|
@@ -7440,7 +7476,7 @@ class ReplayContainer {
|
|
|
7440
7476
|
stickySession: Boolean(this._options.stickySession),
|
|
7441
7477
|
currentSession: this.session,
|
|
7442
7478
|
sessionSampleRate: this._options.sessionSampleRate,
|
|
7443
|
-
allowBuffering: this._options.errorSampleRate > 0,
|
|
7479
|
+
allowBuffering: this._options.errorSampleRate > 0 || this.recordingMode === 'buffer',
|
|
7444
7480
|
});
|
|
7445
7481
|
|
|
7446
7482
|
// If session was newly created (i.e. was not loaded from storage), then
|
|
@@ -7636,7 +7672,7 @@ class ReplayContainer {
|
|
|
7636
7672
|
_createCustomBreadcrumb(breadcrumb) {
|
|
7637
7673
|
this.addUpdate(() => {
|
|
7638
7674
|
void this.throttledAddEvent({
|
|
7639
|
-
type: EventType
|
|
7675
|
+
type: EventType.Custom,
|
|
7640
7676
|
timestamp: breadcrumb.timestamp || 0,
|
|
7641
7677
|
data: {
|
|
7642
7678
|
tag: 'breadcrumb',
|
|
@@ -8010,6 +8046,9 @@ class Replay {
|
|
|
8010
8046
|
mutationBreadcrumbLimit = 750,
|
|
8011
8047
|
mutationLimit = 10000,
|
|
8012
8048
|
|
|
8049
|
+
slowClickTimeout = 7000,
|
|
8050
|
+
slowClickIgnoreSelectors = [],
|
|
8051
|
+
|
|
8013
8052
|
networkDetailAllowUrls = [],
|
|
8014
8053
|
networkCaptureBodies = true,
|
|
8015
8054
|
networkRequestHeaders = [],
|
|
@@ -8079,6 +8118,8 @@ class Replay {
|
|
|
8079
8118
|
maskAllText,
|
|
8080
8119
|
mutationBreadcrumbLimit,
|
|
8081
8120
|
mutationLimit,
|
|
8121
|
+
slowClickTimeout,
|
|
8122
|
+
slowClickIgnoreSelectors,
|
|
8082
8123
|
networkDetailAllowUrls,
|
|
8083
8124
|
networkCaptureBodies,
|
|
8084
8125
|
networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
|