@newrelic/browser-agent 1.249.0 → 1.251.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/CHANGELOG.md +26 -0
- package/dist/cjs/common/config/state/init.js +1 -3
- package/dist/cjs/common/config/state/originals.js +1 -2
- package/dist/cjs/common/constants/env.cdn.js +4 -8
- package/dist/cjs/common/constants/env.js +4 -8
- package/dist/cjs/common/constants/env.npm.js +4 -8
- package/dist/cjs/common/constants/runtime.js +13 -24
- package/dist/cjs/common/constants/shared-channel.js +2 -3
- package/dist/cjs/common/event-emitter/contextual-ee.js +2 -4
- package/dist/cjs/common/event-emitter/handle.js +1 -2
- package/dist/cjs/common/harvest/harvest-scheduler.js +4 -4
- package/dist/cjs/common/harvest/harvest.js +6 -5
- package/dist/cjs/common/harvest/types.js +1 -2
- package/dist/cjs/common/ids/bundle-id.js +1 -2
- package/dist/cjs/common/ids/unique-id.js +1 -1
- package/dist/cjs/common/session/constants.js +19 -7
- package/dist/cjs/common/session/session-entity.js +8 -26
- package/dist/cjs/common/timer/interaction-timer.js +0 -1
- package/dist/cjs/common/timing/nav-timing.js +1 -2
- package/dist/cjs/common/url/encode.js +2 -0
- package/dist/cjs/common/util/feature-flags.js +1 -2
- package/dist/cjs/common/vitals/constants.js +2 -3
- package/dist/cjs/common/vitals/cumulative-layout-shift.js +1 -2
- package/dist/cjs/common/vitals/first-contentful-paint.js +1 -2
- package/dist/cjs/common/vitals/first-input-delay.js +1 -2
- package/dist/cjs/common/vitals/first-paint.js +1 -2
- package/dist/cjs/common/vitals/interaction-to-next-paint.js +1 -2
- package/dist/cjs/common/vitals/largest-contentful-paint.js +1 -2
- package/dist/cjs/common/vitals/long-task.js +1 -3
- package/dist/cjs/common/vitals/time-to-first-byte.js +1 -2
- package/dist/cjs/common/window/nreum.js +1 -2
- package/dist/cjs/common/wrap/wrap-function.js +2 -4
- package/dist/cjs/features/ajax/aggregate/index.js +0 -2
- package/dist/cjs/features/ajax/constants.js +1 -2
- package/dist/cjs/features/jserrors/aggregate/index.js +0 -1
- package/dist/cjs/features/jserrors/aggregate/string-hash-code.js +0 -1
- package/dist/cjs/features/jserrors/constants.js +1 -2
- package/dist/cjs/features/metrics/aggregate/index.js +3 -1
- package/dist/cjs/features/metrics/constants.js +5 -10
- package/dist/cjs/features/page_action/constants.js +1 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +2 -2
- package/dist/cjs/features/page_view_event/constants.js +1 -2
- package/dist/cjs/features/page_view_event/instrument/index.js +2 -2
- package/dist/cjs/features/page_view_timing/constants.js +1 -2
- package/dist/cjs/features/session_replay/aggregate/index.js +128 -289
- package/dist/cjs/features/session_replay/constants.js +50 -3
- package/dist/cjs/features/session_replay/instrument/index.js +30 -8
- package/dist/cjs/features/session_replay/shared/recorder-events.js +33 -0
- package/dist/cjs/features/session_replay/shared/recorder.js +201 -0
- package/dist/cjs/features/session_replay/{replay-mode.js → shared/replay-mode.js} +5 -5
- package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +94 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +25 -27
- package/dist/cjs/features/session_trace/constants.js +8 -16
- package/dist/cjs/features/session_trace/instrument/index.js +2 -2
- package/dist/cjs/features/spa/aggregate/index.js +2 -2
- package/dist/cjs/features/spa/aggregate/interaction-node.js +0 -1
- package/dist/cjs/features/spa/constants.js +22 -44
- package/dist/cjs/features/spa/instrument/index.js +2 -2
- package/dist/cjs/features/utils/instrument-base.js +6 -7
- package/dist/cjs/features/utils/lazy-feature-loader.js +2 -2
- package/dist/cjs/loaders/agent-base.js +61 -15
- package/dist/cjs/loaders/agent.js +0 -38
- package/dist/cjs/loaders/api/api.js +7 -7
- package/dist/cjs/loaders/api/interaction-types.js +1 -2
- package/dist/cjs/loaders/features/features.js +3 -5
- package/dist/cjs/loaders/micro-agent.js +2 -2
- package/dist/esm/common/config/state/init.js +1 -3
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/harvest/harvest-scheduler.js +1 -1
- package/dist/esm/common/harvest/harvest.js +4 -3
- package/dist/esm/common/ids/unique-id.js +1 -1
- package/dist/esm/common/session/constants.js +16 -1
- package/dist/esm/common/session/session-entity.js +2 -16
- package/dist/esm/common/timer/interaction-timer.js +0 -1
- package/dist/esm/common/url/encode.js +2 -0
- package/dist/esm/common/vitals/long-task.js +0 -1
- package/dist/esm/features/ajax/aggregate/index.js +0 -2
- package/dist/esm/features/jserrors/aggregate/index.js +0 -1
- package/dist/esm/features/jserrors/aggregate/string-hash-code.js +0 -1
- package/dist/esm/features/metrics/aggregate/index.js +3 -1
- package/dist/esm/features/session_replay/aggregate/index.js +98 -255
- package/dist/esm/features/session_replay/constants.js +49 -1
- package/dist/esm/features/session_replay/instrument/index.js +24 -1
- package/dist/esm/features/session_replay/shared/recorder-events.js +26 -0
- package/dist/esm/features/session_replay/shared/recorder.js +194 -0
- package/dist/esm/features/session_replay/{replay-mode.js → shared/replay-mode.js} +4 -4
- package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +88 -0
- package/dist/esm/features/session_trace/aggregate/index.js +2 -4
- package/dist/esm/features/spa/aggregate/interaction-node.js +0 -1
- package/dist/esm/features/utils/instrument-base.js +0 -1
- package/dist/esm/loaders/agent-base.js +62 -15
- package/dist/esm/loaders/agent.js +0 -38
- package/dist/types/common/harvest/harvest.d.ts +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/constants.d.ts +15 -0
- package/dist/types/common/session/session-entity.d.ts +0 -15
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/url/encode.d.ts +1 -1
- package/dist/types/common/url/encode.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +7 -63
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +55 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts +2 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +23 -0
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -0
- package/dist/types/features/session_replay/shared/recorder.d.ts +53 -0
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -0
- package/dist/types/features/session_replay/shared/replay-mode.d.ts.map +1 -0
- package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts +22 -0
- package/dist/types/features/session_replay/shared/stylesheet-evaluator.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +48 -12
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts +0 -33
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/package.json +49 -49
- package/src/common/config/state/init.js +1 -1
- package/src/common/harvest/harvest-scheduler.js +1 -1
- package/src/common/harvest/harvest.js +4 -3
- package/src/common/ids/__mocks__/bundle-id.js +1 -1
- package/src/common/ids/__mocks__/unique-id.js +2 -2
- package/src/common/ids/unique-id.js +1 -1
- package/src/common/session/__mocks__/session-entity.js +0 -6
- package/src/common/session/constants.js +18 -0
- package/src/common/session/session-entity.js +1 -17
- package/src/common/url/encode.js +2 -1
- package/src/features/metrics/aggregate/index.js +3 -1
- package/src/features/session_replay/aggregate/index.js +91 -246
- package/src/features/session_replay/constants.js +45 -0
- package/src/features/session_replay/instrument/index.js +18 -1
- package/src/features/session_replay/shared/recorder-events.js +27 -0
- package/src/features/session_replay/shared/recorder.js +190 -0
- package/src/features/session_replay/{replay-mode.js → shared/replay-mode.js} +4 -4
- package/src/features/session_replay/shared/stylesheet-evaluator.js +84 -0
- package/src/features/session_trace/aggregate/index.js +2 -2
- package/src/loaders/agent-base.js +59 -15
- package/src/loaders/agent.js +0 -38
- package/dist/types/features/session_replay/replay-mode.d.ts.map +0 -1
- /package/dist/types/features/session_replay/{replay-mode.d.ts → shared/replay-mode.d.ts} +0 -0
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.Aggregate = void 0;
|
|
7
7
|
var _registerHandler = require("../../../common/event-emitter/register-handler");
|
|
8
8
|
var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
|
|
9
9
|
var _constants = require("../constants");
|
|
10
|
-
var _stringify = require("../../../common/util/stringify");
|
|
11
10
|
var _config = require("../../../common/config/config");
|
|
12
|
-
var _sessionEntity = require("../../../common/session/session-entity");
|
|
13
11
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
14
12
|
var _sharedChannel = require("../../../common/constants/shared-channel");
|
|
15
13
|
var _encode = require("../../../common/url/encode");
|
|
@@ -20,143 +18,74 @@ var _handle = require("../../../common/event-emitter/handle");
|
|
|
20
18
|
var _features = require("../../../loaders/features/features");
|
|
21
19
|
var _env = require("../../../common/constants/env.npm");
|
|
22
20
|
var _now = require("../../../common/timing/now");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Load: 1,
|
|
39
|
-
FullSnapshot: 2,
|
|
40
|
-
IncrementalSnapshot: 3,
|
|
41
|
-
Meta: 4,
|
|
42
|
-
Custom: 5
|
|
43
|
-
};
|
|
44
|
-
exports.RRWEB_EVENT_TYPES = RRWEB_EVENT_TYPES;
|
|
45
|
-
const ABORT_REASONS = {
|
|
46
|
-
RESET: {
|
|
47
|
-
message: 'Session was reset',
|
|
48
|
-
sm: 'Reset'
|
|
49
|
-
},
|
|
50
|
-
IMPORT: {
|
|
51
|
-
message: 'Recorder failed to import',
|
|
52
|
-
sm: 'Import'
|
|
53
|
-
},
|
|
54
|
-
TOO_MANY: {
|
|
55
|
-
message: '429: Too Many Requests',
|
|
56
|
-
sm: 'Too-Many'
|
|
57
|
-
},
|
|
58
|
-
TOO_BIG: {
|
|
59
|
-
message: 'Payload was too large',
|
|
60
|
-
sm: 'Too-Big'
|
|
61
|
-
},
|
|
62
|
-
CROSS_TAB: {
|
|
63
|
-
message: 'Session Entity was set to OFF on another tab',
|
|
64
|
-
sm: 'Cross-Tab'
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
let recorder, gzipper, u8;
|
|
68
|
-
|
|
69
|
-
/** Vortex caps payload sizes at 1MB */
|
|
70
|
-
const MAX_PAYLOAD_SIZE = 1000000;
|
|
71
|
-
/** Unloading caps around 64kb */
|
|
72
|
-
exports.MAX_PAYLOAD_SIZE = MAX_PAYLOAD_SIZE;
|
|
73
|
-
const IDEAL_PAYLOAD_SIZE = 64000;
|
|
74
|
-
/** Reserved room for query param attrs */
|
|
75
|
-
exports.IDEAL_PAYLOAD_SIZE = IDEAL_PAYLOAD_SIZE;
|
|
76
|
-
const QUERY_PARAM_PADDING = 5000;
|
|
77
|
-
/** Interval between forcing new full snapshots -- 15 seconds in error mode (x2), 5 minutes in full mode */
|
|
78
|
-
const CHECKOUT_MS = {
|
|
79
|
-
[_sessionEntity.MODE.ERROR]: 15000,
|
|
80
|
-
[_sessionEntity.MODE.FULL]: 300000,
|
|
81
|
-
[_sessionEntity.MODE.OFF]: 0
|
|
82
|
-
};
|
|
21
|
+
var _constants3 = require("../../../common/session/constants");
|
|
22
|
+
var _stringify = require("../../../common/util/stringify");
|
|
23
|
+
var _stylesheetEvaluator = require("../shared/stylesheet-evaluator");
|
|
24
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
25
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /*
|
|
26
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
27
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
28
|
+
*/ /**
|
|
29
|
+
* @file Records, aggregates, and harvests session replay data.
|
|
30
|
+
*
|
|
31
|
+
* NOTE: This code is under development and dormant. It will not download to instrumented pages or record any data.
|
|
32
|
+
* It is not production ready, and is not intended to be imported or implemented in any build of the browser agent until
|
|
33
|
+
* functionality is validated and a full user experience is curated.
|
|
34
|
+
*/
|
|
35
|
+
let gzipper, u8;
|
|
83
36
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
84
37
|
static featureName = _constants.FEATURE_NAME;
|
|
85
|
-
|
|
38
|
+
// pass the recorder into the aggregator
|
|
39
|
+
constructor(agentIdentifier, aggregator, args) {
|
|
86
40
|
super(agentIdentifier, aggregator, _constants.FEATURE_NAME);
|
|
87
|
-
/** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
|
|
88
|
-
this.events = [];
|
|
89
|
-
/** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
|
|
90
|
-
this.backloggedEvents = [];
|
|
91
41
|
/** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
|
|
92
42
|
this.harvestTimeSeconds = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.harvestTimeSeconds') || 60;
|
|
93
43
|
/** Set once the recorder has fully initialized after flag checks and sampling */
|
|
94
44
|
this.initialized = false;
|
|
95
|
-
/** Set once an error has been detected on the page. Never unset */
|
|
96
|
-
this.errorNoticed = false;
|
|
97
|
-
/** The "mode" to record in. Defaults to "OFF" until flags and sampling are checked. See "MODE" constant. */
|
|
98
|
-
this.mode = _sessionEntity.MODE.OFF;
|
|
99
45
|
/** Set once the feature has been "aborted" to prevent other side-effects from continuing */
|
|
100
46
|
this.blocked = false;
|
|
101
|
-
/** True when actively recording, false when paused or stopped */
|
|
102
|
-
this.recording = false;
|
|
103
47
|
/** can shut off efforts to compress the data */
|
|
104
48
|
this.shouldCompress = true;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.hasSnapshot = false;
|
|
111
|
-
/** Payload metadata -- Should indicate that the payload being sent has a meta node. The meta node should always precede a snapshot node. */
|
|
112
|
-
this.hasMeta = false;
|
|
113
|
-
/** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
|
|
114
|
-
this.hasError = false;
|
|
115
|
-
|
|
116
|
-
/** Payload metadata -- Should indicate when a replay blob started recording. Resets each time a harvest occurs.
|
|
117
|
-
* cycle timestamps are used as fallbacks if event timestamps cannot be used
|
|
118
|
-
*/
|
|
119
|
-
this.cycleTimestamp = undefined;
|
|
120
|
-
|
|
121
|
-
/** A value which increments with every new mutation node reported. Resets after a harvest is sent */
|
|
122
|
-
this.payloadBytesEstimation = 0;
|
|
123
|
-
|
|
124
|
-
/** Hold on to the last meta node, so that it can be re-inserted if the meta and snapshot nodes are broken up due to harvesting */
|
|
125
|
-
this.lastMeta = undefined;
|
|
49
|
+
/** the mode to start in. Defaults to off */
|
|
50
|
+
const {
|
|
51
|
+
session
|
|
52
|
+
} = (0, _config.getRuntime)(this.agentIdentifier);
|
|
53
|
+
this.mode = session.state.sessionReplayMode || _constants3.MODE.OFF;
|
|
126
54
|
|
|
127
55
|
/** set by BCS response */
|
|
128
56
|
this.entitled = false;
|
|
57
|
+
this.recorder = args?.recorder;
|
|
58
|
+
if (this.recorder) this.recorder.parent = this;
|
|
129
59
|
const shouldSetup = (0, _config.getConfigurationValue)(agentIdentifier, 'privacy.cookies_enabled') === true && (0, _config.getConfigurationValue)(agentIdentifier, 'session_trace.enabled') === true;
|
|
130
|
-
|
|
131
|
-
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
132
|
-
this.stopRecording = () => {/* no-op until set by rrweb initializer */};
|
|
133
60
|
if (shouldSetup) {
|
|
134
61
|
// The SessionEntity class can emit a message indicating the session was cleared and reset (expiry, inactivity). This feature must abort and never resume if that occurs.
|
|
135
|
-
this.ee.on(
|
|
136
|
-
this.
|
|
62
|
+
this.ee.on(_constants3.SESSION_EVENTS.RESET, () => {
|
|
63
|
+
this.scheduler.runHarvest();
|
|
64
|
+
this.abort(_constants.ABORT_REASONS.RESET);
|
|
137
65
|
});
|
|
138
66
|
|
|
139
67
|
// The SessionEntity class can emit a message indicating the session was paused (visibility change). This feature must stop recording if that occurs.
|
|
140
|
-
this.ee.on(
|
|
141
|
-
this.stopRecording();
|
|
68
|
+
this.ee.on(_constants3.SESSION_EVENTS.PAUSE, () => {
|
|
69
|
+
this.recorder?.stopRecording();
|
|
142
70
|
});
|
|
143
71
|
// The SessionEntity class can emit a message indicating the session was resumed (visibility change). This feature must start running again (if already running) if that occurs.
|
|
144
|
-
this.ee.on(
|
|
72
|
+
this.ee.on(_constants3.SESSION_EVENTS.RESUME, () => {
|
|
73
|
+
if (!this.recorder) return;
|
|
145
74
|
// if the mode changed on a different tab, it needs to update this instance to match
|
|
146
75
|
const {
|
|
147
76
|
session
|
|
148
77
|
} = (0, _config.getRuntime)(this.agentIdentifier);
|
|
149
78
|
this.mode = session.state.sessionReplayMode;
|
|
150
|
-
if (!this.initialized || this.mode ===
|
|
151
|
-
this.startRecording();
|
|
79
|
+
if (!this.initialized || this.mode === _constants3.MODE.OFF) return;
|
|
80
|
+
this.recorder?.startRecording();
|
|
152
81
|
});
|
|
153
|
-
this.ee.on(
|
|
154
|
-
if (!this.initialized || this.blocked || type !==
|
|
155
|
-
if (this.mode !==
|
|
82
|
+
this.ee.on(_constants3.SESSION_EVENTS.UPDATE, (type, data) => {
|
|
83
|
+
if (!this.recorder || !this.initialized || this.blocked || type !== _constants3.SESSION_EVENT_TYPES.CROSS_TAB) return;
|
|
84
|
+
if (this.mode !== _constants3.MODE.OFF && data.sessionReplayMode === _constants3.MODE.OFF) this.abort(_constants.ABORT_REASONS.CROSS_TAB);
|
|
156
85
|
this.mode = data.sessionReplay;
|
|
157
86
|
});
|
|
158
87
|
|
|
159
|
-
// Bespoke logic for
|
|
88
|
+
// Bespoke logic for blobs endpoint.
|
|
160
89
|
this.scheduler = new _harvestScheduler.HarvestScheduler('browser/blobs', {
|
|
161
90
|
onFinished: this.onHarvestFinished.bind(this),
|
|
162
91
|
retryDelay: this.harvestTimeSeconds,
|
|
@@ -167,28 +96,29 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
167
96
|
// if it has aborted or BCS returned bad entitlements, do not allow
|
|
168
97
|
if (this.blocked || !this.entitled) return;
|
|
169
98
|
// if it isnt already (fully) initialized... initialize it
|
|
170
|
-
if (!recorder) this.initializeRecording(false, true, true);
|
|
99
|
+
if (!this.recorder) this.initializeRecording(false, true, true);
|
|
171
100
|
// its been initialized and imported the recorder but its not recording (mode === off || error)
|
|
172
|
-
else if (this.mode !==
|
|
101
|
+
else if (this.mode !== _constants3.MODE.FULL) this.switchToFull();
|
|
173
102
|
// if it gets all the way to here, that means a full session is already recording... do nothing
|
|
174
103
|
}, this.featureName, this.ee);
|
|
175
104
|
(0, _registerHandler.registerHandler)('pauseReplay', () => {
|
|
176
|
-
this.forceStop(this.mode !==
|
|
105
|
+
this.forceStop(this.mode !== _constants3.MODE.ERROR);
|
|
177
106
|
}, this.featureName, this.ee);
|
|
178
107
|
|
|
179
108
|
// Wait for an error to be reported. This currently is wrapped around the "Error" feature. This is a feature-feature dependency.
|
|
180
109
|
// This was to ensure that all errors, including those on the page before load and those handled with "noticeError" are accounted for. Needs evalulation
|
|
181
110
|
(0, _registerHandler.registerHandler)('errorAgg', e => {
|
|
182
|
-
this.hasError = true;
|
|
183
111
|
this.errorNoticed = true;
|
|
112
|
+
if (this.recorder) this.recorder.currentBufferTarget.hasError = true;
|
|
184
113
|
// run once
|
|
185
|
-
if (this.mode ===
|
|
114
|
+
if (this.mode === _constants3.MODE.ERROR && _runtime.globalScope?.document.visibilityState === 'visible') {
|
|
186
115
|
this.switchToFull();
|
|
187
116
|
}
|
|
188
117
|
}, this.featureName, this.ee);
|
|
189
118
|
this.waitForFlags(['sr']).then(_ref => {
|
|
190
119
|
let [flagOn] = _ref;
|
|
191
120
|
this.entitled = flagOn;
|
|
121
|
+
if (!this.entitled && this.recorder?.recording) this.recorder.abort(_constants.ABORT_REASONS.ENTITLEMENTS);
|
|
192
122
|
this.initializeRecording(Math.random() * 100 < (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.error_sampling_rate'), Math.random() * 100 < (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.sampling_rate'));
|
|
193
123
|
}).then(() => _sharedChannel.sharedChannel.onReplayReady(this.mode)); // notify watchers that replay started with the mode
|
|
194
124
|
|
|
@@ -196,11 +126,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
196
126
|
}
|
|
197
127
|
}
|
|
198
128
|
switchToFull() {
|
|
199
|
-
this.mode =
|
|
129
|
+
this.mode = _constants3.MODE.FULL;
|
|
200
130
|
// if the error was noticed AFTER the recorder was already imported....
|
|
201
|
-
if (recorder && this.initialized) {
|
|
202
|
-
this.stopRecording();
|
|
203
|
-
this.startRecording();
|
|
131
|
+
if (this.recorder && this.initialized) {
|
|
132
|
+
this.recorder.stopRecording();
|
|
133
|
+
this.recorder.startRecording();
|
|
204
134
|
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
205
135
|
this.syncWithSessionManager({
|
|
206
136
|
sessionReplayMode: this.mode
|
|
@@ -218,42 +148,51 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
218
148
|
*/
|
|
219
149
|
async initializeRecording(errorSample, fullSample, ignoreSession) {
|
|
220
150
|
this.initialized = true;
|
|
221
|
-
if (!this.entitled
|
|
222
|
-
|
|
223
|
-
session
|
|
224
|
-
} = (0, _config.getRuntime)(this.agentIdentifier);
|
|
151
|
+
if (!this.entitled) return;
|
|
152
|
+
|
|
225
153
|
// if theres an existing session replay in progress, there's no need to sample, just check the entitlements response
|
|
226
154
|
// if not, these sample flags need to be checked
|
|
227
155
|
// if this isnt the FIRST load of a session AND
|
|
228
156
|
// we are not actively recording SR... DO NOT import or run the recording library
|
|
229
157
|
// session replay samples can only be decided on the first load of a session
|
|
230
158
|
// session replays can continue if already in progress
|
|
159
|
+
const {
|
|
160
|
+
session
|
|
161
|
+
} = (0, _config.getRuntime)(this.agentIdentifier);
|
|
231
162
|
if (!session.isNew && !ignoreSession) {
|
|
232
163
|
// inherit the mode of the existing session
|
|
233
164
|
this.mode = session.state.sessionReplayMode;
|
|
234
165
|
} else {
|
|
235
166
|
// The session is new... determine the mode the new session should start in
|
|
236
|
-
if (fullSample) this.mode =
|
|
237
|
-
else if (errorSample) this.mode =
|
|
167
|
+
if (fullSample) this.mode = _constants3.MODE.FULL; // full mode has precedence over error mode
|
|
168
|
+
else if (errorSample) this.mode = _constants3.MODE.ERROR;
|
|
238
169
|
// If neither are selected, then don't record (early return)
|
|
239
|
-
else
|
|
170
|
+
else {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!this.recorder) {
|
|
175
|
+
try {
|
|
176
|
+
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
177
|
+
const {
|
|
178
|
+
Recorder
|
|
179
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "recorder" */'../shared/recorder')));
|
|
180
|
+
this.recorder = new Recorder(this);
|
|
181
|
+
this.recorder.currentBufferTarget.hasError = this.errorNoticed;
|
|
182
|
+
} catch (err) {
|
|
183
|
+
return this.abort(_constants.ABORT_REASONS.IMPORT);
|
|
184
|
+
}
|
|
240
185
|
}
|
|
241
186
|
|
|
242
187
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
243
|
-
if (this.mode ===
|
|
244
|
-
this.mode =
|
|
245
|
-
}
|
|
246
|
-
try {
|
|
247
|
-
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
248
|
-
recorder = (await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "recorder" */'rrweb')))).record;
|
|
249
|
-
} catch (err) {
|
|
250
|
-
return this.abort(ABORT_REASONS.IMPORT);
|
|
188
|
+
if (this.mode === _constants3.MODE.ERROR && this.errorNoticed) {
|
|
189
|
+
this.mode = _constants3.MODE.FULL;
|
|
251
190
|
}
|
|
252
191
|
|
|
253
192
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
254
193
|
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
255
194
|
// If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
|
|
256
|
-
if (this.mode ===
|
|
195
|
+
if (this.mode === _constants3.MODE.FULL && !this.scheduler.started) {
|
|
257
196
|
// We only report (harvest) in FULL mode
|
|
258
197
|
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
259
198
|
}
|
|
@@ -269,24 +208,41 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
269
208
|
// compressor failed to load, but we can still record without compression as a last ditch effort
|
|
270
209
|
this.shouldCompress = false;
|
|
271
210
|
}
|
|
272
|
-
this.startRecording();
|
|
211
|
+
if (!this.recorder.recording) this.recorder.startRecording();
|
|
273
212
|
this.syncWithSessionManager({
|
|
274
213
|
sessionReplayMode: this.mode
|
|
275
214
|
});
|
|
276
215
|
}
|
|
277
216
|
prepareHarvest() {
|
|
278
|
-
if (
|
|
279
|
-
const
|
|
217
|
+
if (!this.recorder) return;
|
|
218
|
+
const recorderEvents = this.recorder.getEvents();
|
|
219
|
+
// get the event type and use that to trigger another harvest if needed
|
|
220
|
+
if (!recorderEvents.events.length || this.mode !== _constants3.MODE.FULL || this.blocked) return;
|
|
221
|
+
const payload = this.getHarvestContents(recorderEvents);
|
|
280
222
|
if (!payload.body.length) {
|
|
281
|
-
this.clearBuffer();
|
|
223
|
+
this.recorder.clearBuffer();
|
|
282
224
|
return;
|
|
283
225
|
}
|
|
226
|
+
let len = 0;
|
|
284
227
|
if (this.shouldCompress) {
|
|
285
|
-
payload.body = gzipper(u8(
|
|
228
|
+
payload.body = gzipper(u8("[".concat(payload.body.map(e => e.__serialized).join(','), "]")));
|
|
229
|
+
len = payload.body.length;
|
|
286
230
|
this.scheduler.opts.gzip = true;
|
|
287
231
|
} else {
|
|
232
|
+
payload.body = payload.body.map(_ref2 => {
|
|
233
|
+
let {
|
|
234
|
+
__serialized,
|
|
235
|
+
...node
|
|
236
|
+
} = _ref2;
|
|
237
|
+
return node;
|
|
238
|
+
});
|
|
239
|
+
len = (0, _stringify.stringify)(payload.body).length;
|
|
288
240
|
this.scheduler.opts.gzip = false;
|
|
289
241
|
}
|
|
242
|
+
if (len > _constants.MAX_PAYLOAD_SIZE) {
|
|
243
|
+
this.abort(_constants.ABORT_REASONS.TOO_BIG);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
290
246
|
// TODO -- Gracefully handle the buffer for retries.
|
|
291
247
|
const {
|
|
292
248
|
session
|
|
@@ -294,37 +250,39 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
294
250
|
if (!session.state.sessionReplaySentFirstChunk) this.syncWithSessionManager({
|
|
295
251
|
sessionReplaySentFirstChunk: true
|
|
296
252
|
});
|
|
297
|
-
this.clearBuffer();
|
|
253
|
+
this.recorder.clearBuffer();
|
|
254
|
+
if (recorderEvents.type === 'preloaded') this.scheduler.runHarvest();
|
|
298
255
|
return [payload];
|
|
299
256
|
}
|
|
300
|
-
getHarvestContents() {
|
|
257
|
+
getHarvestContents(recorderEvents) {
|
|
258
|
+
recorderEvents ??= this.recorder.getEvents();
|
|
259
|
+
let events = recorderEvents.events;
|
|
301
260
|
const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
|
|
302
261
|
const info = (0, _config.getInfo)(this.agentIdentifier);
|
|
303
262
|
const endUserId = info.jsAttributes?.['enduser.id'];
|
|
304
|
-
if (this.backloggedEvents.length) this.events = [...this.backloggedEvents, ...this.events];
|
|
305
263
|
|
|
306
264
|
// do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
|
|
307
265
|
// we will manually inject it if this happens
|
|
308
|
-
const payloadStartsWithFullSnapshot =
|
|
309
|
-
if (payloadStartsWithFullSnapshot && !!this.lastMeta) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
this.lastMeta = undefined;
|
|
266
|
+
const payloadStartsWithFullSnapshot = events?.[0]?.type === _constants.RRWEB_EVENT_TYPES.FullSnapshot;
|
|
267
|
+
if (payloadStartsWithFullSnapshot && !!this.recorder.lastMeta) {
|
|
268
|
+
recorderEvents.hasMeta = true;
|
|
269
|
+
events.unshift(this.recorder.lastMeta); // --> pushed the meta from a previous payload into newer payload... but it still has old timestamps
|
|
270
|
+
this.recorder.lastMeta = undefined;
|
|
313
271
|
}
|
|
314
272
|
|
|
315
273
|
// do not let the last node be a meta node, since this NEEDS to precede a snapshot
|
|
316
274
|
// we will manually inject it later if we find a payload that is missing a meta node
|
|
317
|
-
const payloadEndsWithMeta =
|
|
275
|
+
const payloadEndsWithMeta = events[events.length - 1]?.type === _constants.RRWEB_EVENT_TYPES.Meta;
|
|
318
276
|
if (payloadEndsWithMeta) {
|
|
319
|
-
this.lastMeta =
|
|
320
|
-
|
|
321
|
-
|
|
277
|
+
this.recorder.lastMeta = events[events.length - 1];
|
|
278
|
+
events = events.slice(0, events.length - 1);
|
|
279
|
+
recorderEvents.hasMeta = !!events.find(x => x.type === _constants.RRWEB_EVENT_TYPES.Meta);
|
|
322
280
|
}
|
|
323
281
|
const agentOffset = (0, _config.getRuntime)(this.agentIdentifier).offset;
|
|
324
282
|
const relativeNow = (0, _now.now)();
|
|
325
|
-
const firstEventTimestamp =
|
|
326
|
-
const lastEventTimestamp =
|
|
327
|
-
const firstTimestamp = firstEventTimestamp ||
|
|
283
|
+
const firstEventTimestamp = events[0]?.timestamp; // from rrweb node
|
|
284
|
+
const lastEventTimestamp = events[events.length - 1]?.timestamp; // from rrweb node
|
|
285
|
+
const firstTimestamp = firstEventTimestamp || recorderEvents.cycleTimestamp;
|
|
328
286
|
const lastTimestamp = lastEventTimestamp || agentOffset + relativeNow;
|
|
329
287
|
return {
|
|
330
288
|
qs: {
|
|
@@ -342,148 +300,37 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
342
300
|
'replay.firstTimestampOffset': firstTimestamp - agentOffset,
|
|
343
301
|
'replay.lastTimestamp': lastTimestamp,
|
|
344
302
|
'replay.durationMs': lastTimestamp - firstTimestamp,
|
|
345
|
-
'replay.nodes':
|
|
303
|
+
'replay.nodes': events.length,
|
|
346
304
|
'session.durationMs': agentRuntime.session.getDuration(),
|
|
347
305
|
agentVersion: agentRuntime.version,
|
|
348
306
|
session: agentRuntime.session.state.value,
|
|
349
307
|
rst: relativeNow,
|
|
350
|
-
hasMeta:
|
|
351
|
-
hasSnapshot:
|
|
352
|
-
hasError:
|
|
308
|
+
hasMeta: recorderEvents.hasMeta || false,
|
|
309
|
+
hasSnapshot: recorderEvents.hasSnapshot || false,
|
|
310
|
+
hasError: recorderEvents.hasError || false,
|
|
353
311
|
isFirstChunk: agentRuntime.session.state.sessionReplaySentFirstChunk === false,
|
|
354
|
-
decompressedBytes:
|
|
312
|
+
decompressedBytes: recorderEvents.payloadBytesEstimation,
|
|
313
|
+
invalidStylesheetsDetected: _stylesheetEvaluator.stylesheetEvaluator.invalidStylesheetsDetected,
|
|
314
|
+
inlinedAllStylesheets: recorderEvents.inlinedAllStylesheets,
|
|
355
315
|
'rrweb.version': _env.RRWEB_VERSION,
|
|
356
316
|
// customer-defined data should go last so that if it exceeds the query param padding limit it will be truncated instead of important attrs
|
|
357
317
|
...(endUserId && {
|
|
358
318
|
'enduser.id': endUserId
|
|
359
319
|
})
|
|
360
320
|
// The Query Param is being arbitrarily limited in length here. It is also applied when estimating the size of the payload in getPayloadSize()
|
|
361
|
-
}, QUERY_PARAM_PADDING).substring(1) // remove the leading '&'
|
|
321
|
+
}, _constants.QUERY_PARAM_PADDING).substring(1) // remove the leading '&'
|
|
362
322
|
},
|
|
363
|
-
|
|
364
|
-
body: this.events
|
|
323
|
+
body: events
|
|
365
324
|
};
|
|
366
325
|
}
|
|
367
326
|
onHarvestFinished(result) {
|
|
368
327
|
// The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
|
|
369
328
|
if (result.status === 429) {
|
|
370
|
-
this.abort(ABORT_REASONS.TOO_MANY);
|
|
329
|
+
this.abort(_constants.ABORT_REASONS.TOO_MANY);
|
|
371
330
|
}
|
|
372
331
|
if (this.blocked) this.scheduler.stopTimer(true);
|
|
373
332
|
}
|
|
374
333
|
|
|
375
|
-
/** Clears the buffer (this.events), and resets all payload metadata properties */
|
|
376
|
-
clearBuffer() {
|
|
377
|
-
if (this.mode === _sessionEntity.MODE.ERROR) this.backloggedEvents = this.events;else this.backloggedEvents = [];
|
|
378
|
-
this.events = [];
|
|
379
|
-
this.hasSnapshot = false;
|
|
380
|
-
this.hasMeta = false;
|
|
381
|
-
this.hasError = false;
|
|
382
|
-
this.payloadBytesEstimation = 0;
|
|
383
|
-
this.clearTimestamps();
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/** Begin recording using configured recording lib */
|
|
387
|
-
startRecording() {
|
|
388
|
-
if (!recorder) {
|
|
389
|
-
(0, _console.warn)('Recording library was never imported');
|
|
390
|
-
return this.abort(ABORT_REASONS.IMPORT);
|
|
391
|
-
}
|
|
392
|
-
this.recording = true;
|
|
393
|
-
const {
|
|
394
|
-
block_class,
|
|
395
|
-
ignore_class,
|
|
396
|
-
mask_text_class,
|
|
397
|
-
block_selector,
|
|
398
|
-
mask_input_options,
|
|
399
|
-
mask_text_selector,
|
|
400
|
-
mask_all_inputs,
|
|
401
|
-
inline_images,
|
|
402
|
-
inline_stylesheet,
|
|
403
|
-
collect_fonts
|
|
404
|
-
} = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay');
|
|
405
|
-
// set up rrweb configurations for maximum privacy --
|
|
406
|
-
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
407
|
-
const stop = recorder({
|
|
408
|
-
emit: this.store.bind(this),
|
|
409
|
-
blockClass: block_class,
|
|
410
|
-
ignoreClass: ignore_class,
|
|
411
|
-
maskTextClass: mask_text_class,
|
|
412
|
-
blockSelector: block_selector,
|
|
413
|
-
maskInputOptions: mask_input_options,
|
|
414
|
-
maskTextSelector: mask_text_selector,
|
|
415
|
-
maskAllInputs: mask_all_inputs,
|
|
416
|
-
inlineImages: inline_images,
|
|
417
|
-
inlineStylesheet: inline_stylesheet,
|
|
418
|
-
collectFonts: collect_fonts,
|
|
419
|
-
checkoutEveryNms: CHECKOUT_MS[this.mode]
|
|
420
|
-
});
|
|
421
|
-
this.stopRecording = () => {
|
|
422
|
-
this.recording = false;
|
|
423
|
-
stop();
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/** Store a payload in the buffer (this.events). This should be the callback to the recording lib noticing a mutation */
|
|
428
|
-
store(event, isCheckout) {
|
|
429
|
-
this.setTimestamps();
|
|
430
|
-
if (this.blocked) return;
|
|
431
|
-
const eventBytes = (0, _stringify.stringify)(event).length;
|
|
432
|
-
/** The estimated size of the payload after compression */
|
|
433
|
-
const payloadSize = this.getPayloadSize(eventBytes);
|
|
434
|
-
// Vortex will block payloads at a certain size, we might as well not send.
|
|
435
|
-
if (payloadSize > MAX_PAYLOAD_SIZE) {
|
|
436
|
-
this.clearBuffer();
|
|
437
|
-
return this.abort(ABORT_REASONS.TOO_BIG);
|
|
438
|
-
}
|
|
439
|
-
// Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
|
|
440
|
-
// to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
|
|
441
|
-
// each time we see a new checkout, we can drop the old data.
|
|
442
|
-
// we need to check for meta because rrweb will flag it as checkout twice, once for meta, then once for snapshot
|
|
443
|
-
if (this.mode === _sessionEntity.MODE.ERROR && isCheckout && event.type === RRWEB_EVENT_TYPES.Meta) {
|
|
444
|
-
// we are still waiting for an error to throw, so keep wiping the buffer over time
|
|
445
|
-
this.clearBuffer();
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// meta event
|
|
449
|
-
if (event.type === RRWEB_EVENT_TYPES.Meta) {
|
|
450
|
-
this.hasMeta = true;
|
|
451
|
-
}
|
|
452
|
-
// snapshot event
|
|
453
|
-
if (event.type === RRWEB_EVENT_TYPES.FullSnapshot) {
|
|
454
|
-
this.hasSnapshot = true;
|
|
455
|
-
}
|
|
456
|
-
this.events.push(event);
|
|
457
|
-
this.payloadBytesEstimation += eventBytes;
|
|
458
|
-
|
|
459
|
-
// We are making an effort to try to keep payloads manageable for unloading. If they reach the unload limit before their interval,
|
|
460
|
-
// it will send immediately. This often happens on the first snapshot, which can be significantly larger than the other payloads.
|
|
461
|
-
if (payloadSize > IDEAL_PAYLOAD_SIZE && this.mode !== _sessionEntity.MODE.ERROR) {
|
|
462
|
-
// if we've made it to the ideal size of ~64kb before the interval timer, we should send early.
|
|
463
|
-
this.scheduler.runHarvest();
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/** force the recording lib to take a full DOM snapshot. This needs to occur in certain cases, like visibility changes */
|
|
468
|
-
takeFullSnapshot() {
|
|
469
|
-
if (!recorder) return;
|
|
470
|
-
recorder.takeFullSnapshot();
|
|
471
|
-
}
|
|
472
|
-
setTimestamps() {
|
|
473
|
-
// fallbacks if timestamps cannot be derived from rrweb events
|
|
474
|
-
if (!this.cycleTimestamp) this.cycleTimestamp = (0, _config.getRuntime)(this.agentIdentifier).offset + _runtime.globalScope.performance.now();
|
|
475
|
-
}
|
|
476
|
-
clearTimestamps() {
|
|
477
|
-
this.cycleTimestamp = undefined;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/** Estimate the payload size */
|
|
481
|
-
getPayloadSize() {
|
|
482
|
-
let newBytes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
483
|
-
// the query param padding constant gives us some padding for the other metadata to be safely injected
|
|
484
|
-
return this.estimateCompression(this.payloadBytesEstimation + newBytes) + QUERY_PARAM_PADDING;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
334
|
/**
|
|
488
335
|
* Forces the agent into OFF mode so that changing tabs or navigating
|
|
489
336
|
* does not restart the recording. This is used when the customer calls
|
|
@@ -491,8 +338,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
491
338
|
*/
|
|
492
339
|
forceStop(forceHarvest) {
|
|
493
340
|
if (forceHarvest) this.scheduler.runHarvest();
|
|
494
|
-
this.mode =
|
|
495
|
-
this.stopRecording();
|
|
341
|
+
this.mode = _constants3.MODE.OFF;
|
|
342
|
+
this.recorder?.stopRecording?.();
|
|
496
343
|
this.syncWithSessionManager({
|
|
497
344
|
sessionReplayMode: this.mode
|
|
498
345
|
});
|
|
@@ -504,22 +351,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
504
351
|
(0, _console.warn)("SR aborted -- ".concat(reason.message));
|
|
505
352
|
(0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(reason.sm)], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
506
353
|
this.blocked = true;
|
|
507
|
-
this.mode =
|
|
508
|
-
this.stopRecording();
|
|
354
|
+
this.mode = _constants3.MODE.OFF;
|
|
355
|
+
this.recorder?.stopRecording?.();
|
|
509
356
|
this.syncWithSessionManager({
|
|
510
357
|
sessionReplayMode: this.mode
|
|
511
358
|
});
|
|
512
|
-
this.clearTimestamps();
|
|
359
|
+
this.recorder?.clearTimestamps?.();
|
|
513
360
|
this.ee.emit('REPLAY_ABORTED');
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
/** Extensive research has yielded about an 88% compression factor on these payloads.
|
|
517
|
-
* This is an estimation using that factor as to not cause performance issues while evaluating
|
|
518
|
-
* https://staging.onenr.io/037jbJWxbjy
|
|
519
|
-
* */
|
|
520
|
-
estimateCompression(data) {
|
|
521
|
-
if (this.shouldCompress) return data * AVG_COMPRESSION;
|
|
522
|
-
return data;
|
|
361
|
+
this.recorder?.clearBuffer?.();
|
|
523
362
|
}
|
|
524
363
|
syncWithSessionManager() {
|
|
525
364
|
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|