@newrelic/browser-agent 1.258.2 → 1.259.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 +7 -0
- package/dist/cjs/cdn/polyfills.js +3 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +1 -1
- package/dist/cjs/common/harvest/harvest-scheduler.js +4 -2
- package/dist/cjs/features/ajax/constants.js +3 -2
- package/dist/cjs/features/jserrors/aggregate/index.js +2 -1
- package/dist/cjs/features/metrics/aggregate/index.js +0 -8
- package/dist/cjs/features/page_view_event/aggregate/index.js +1 -1
- package/dist/cjs/features/session_replay/aggregate/index.js +31 -36
- package/dist/cjs/features/session_replay/constants.js +5 -2
- package/dist/cjs/features/session_replay/instrument/index.js +53 -13
- package/dist/cjs/features/session_replay/shared/utils.js +3 -5
- package/dist/cjs/features/session_trace/aggregate/index.js +181 -527
- package/dist/cjs/features/session_trace/aggregate/trace/node.js +19 -0
- package/dist/cjs/features/session_trace/aggregate/trace/storage.js +289 -0
- package/dist/cjs/features/session_trace/constants.js +3 -2
- package/dist/cjs/features/session_trace/instrument/index.js +7 -3
- package/dist/cjs/features/utils/aggregate-base.js +1 -0
- package/dist/cjs/features/utils/feature-gates.js +17 -0
- package/dist/cjs/features/utils/instrument-base.js +2 -1
- package/dist/cjs/loaders/agent-base.js +4 -0
- package/dist/cjs/loaders/api/api-methods.js +1 -1
- package/dist/cjs/loaders/api/api.js +2 -2
- package/dist/cjs/loaders/configure/configure.js +1 -0
- package/dist/esm/cdn/polyfills.js +3 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvest-scheduler.js +4 -2
- package/dist/esm/features/ajax/constants.js +2 -1
- package/dist/esm/features/jserrors/aggregate/index.js +2 -1
- package/dist/esm/features/metrics/aggregate/index.js +0 -8
- package/dist/esm/features/page_view_event/aggregate/index.js +1 -1
- package/dist/esm/features/session_replay/aggregate/index.js +32 -37
- package/dist/esm/features/session_replay/constants.js +4 -1
- package/dist/esm/features/session_replay/instrument/index.js +54 -14
- package/dist/esm/features/session_replay/shared/utils.js +4 -6
- package/dist/esm/features/session_trace/aggregate/index.js +182 -527
- package/dist/esm/features/session_trace/aggregate/trace/node.js +12 -0
- package/dist/esm/features/session_trace/aggregate/trace/storage.js +282 -0
- package/dist/esm/features/session_trace/constants.js +2 -1
- package/dist/esm/features/session_trace/instrument/index.js +7 -3
- package/dist/esm/features/utils/aggregate-base.js +1 -0
- package/dist/esm/features/utils/feature-gates.js +11 -0
- package/dist/esm/features/utils/instrument-base.js +3 -2
- package/dist/esm/loaders/agent-base.js +4 -0
- package/dist/esm/loaders/api/api-methods.js +1 -1
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/esm/loaders/configure/configure.js +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/features/ajax/constants.d.ts +1 -0
- package/dist/types/features/ajax/constants.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.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 +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/constants.d.ts +3 -0
- package/dist/types/features/session_replay/instrument/index.d.ts +0 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts +1 -1
- package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +39 -52
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/trace/node.d.ts +12 -0
- package/dist/types/features/session_trace/aggregate/trace/node.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts +43 -0
- package/dist/types/features/session_trace/aggregate/trace/storage.d.ts.map +1 -0
- package/dist/types/features/session_trace/constants.d.ts +1 -0
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +1 -0
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/feature-gates.d.ts +2 -0
- package/dist/types/features/utils/feature-gates.d.ts.map +1 -0
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +1 -0
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/polyfills.js +2 -0
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvest-scheduler.js +4 -2
- package/src/features/ajax/constants.js +2 -0
- package/src/features/jserrors/aggregate/index.js +2 -1
- package/src/features/metrics/aggregate/index.js +0 -8
- package/src/features/page_view_event/aggregate/index.js +1 -1
- package/src/features/session_replay/aggregate/index.js +30 -39
- package/src/features/session_replay/constants.js +4 -0
- package/src/features/session_replay/instrument/index.js +48 -8
- package/src/features/session_replay/shared/__mocks__/utils.js +0 -1
- package/src/features/session_replay/shared/utils.js +4 -7
- package/src/features/session_trace/aggregate/index.js +157 -493
- package/src/features/session_trace/aggregate/trace/node.js +12 -0
- package/src/features/session_trace/aggregate/trace/storage.js +287 -0
- package/src/features/session_trace/constants.js +1 -0
- package/src/features/session_trace/instrument/index.js +7 -2
- package/src/features/utils/__mocks__/feature-gates.js +1 -0
- package/src/features/utils/aggregate-base.js +1 -0
- package/src/features/utils/feature-gates.js +11 -0
- package/src/features/utils/instrument-base.js +3 -2
- package/src/loaders/agent-base.js +4 -0
- package/src/loaders/api/api-methods.js +1 -1
- package/src/loaders/api/api.js +2 -2
- package/src/loaders/configure/configure.js +1 -0
- package/dist/cjs/features/session_replay/shared/replay-mode.js +0 -28
- package/dist/cjs/features/utils/handler-cache.js +0 -70
- package/dist/esm/features/session_replay/shared/replay-mode.js +0 -23
- package/dist/esm/features/utils/handler-cache.js +0 -63
- package/dist/types/features/session_replay/shared/replay-mode.d.ts +0 -9
- package/dist/types/features/session_replay/shared/replay-mode.d.ts.map +0 -1
- package/dist/types/features/utils/handler-cache.d.ts +0 -23
- package/dist/types/features/utils/handler-cache.d.ts.map +0 -1
- package/src/features/session_replay/shared/replay-mode.js +0 -23
- package/src/features/utils/handler-cache.js +0 -65
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { registerHandler } from '../../../common/event-emitter/register-handler';
|
|
14
14
|
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
15
|
-
import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES } from '../constants';
|
|
15
|
+
import { ABORT_REASONS, FEATURE_NAME, MAX_PAYLOAD_SIZE, QUERY_PARAM_PADDING, RRWEB_EVENT_TYPES, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants';
|
|
16
16
|
import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
|
|
17
17
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
18
18
|
import { sharedChannel } from '../../../common/constants/shared-channel';
|
|
@@ -91,15 +91,6 @@ export class Aggregate extends AggregateBase {
|
|
|
91
91
|
getPayload: this.prepareHarvest.bind(this),
|
|
92
92
|
raw: true
|
|
93
93
|
}, this);
|
|
94
|
-
registerHandler(SR_EVENT_EMITTER_TYPES.RECORD, () => {
|
|
95
|
-
// if it has aborted or BCS returned bad entitlements, do not allow
|
|
96
|
-
if (this.blocked || !this.entitled) return;
|
|
97
|
-
// if it isnt already (fully) initialized... initialize it
|
|
98
|
-
if (!this.recorder) this.initializeRecording(false, true, true);
|
|
99
|
-
// its been initialized and imported the recorder but its not recording (mode === off || error)
|
|
100
|
-
else if (this.mode !== MODE.FULL) this.switchToFull();
|
|
101
|
-
// if it gets all the way to here, that means a full session is already recording... do nothing
|
|
102
|
-
}, this.featureName, this.ee);
|
|
103
94
|
registerHandler(SR_EVENT_EMITTER_TYPES.PAUSE, () => {
|
|
104
95
|
this.forceStop(this.mode !== MODE.ERROR);
|
|
105
96
|
}, this.featureName, this.ee);
|
|
@@ -117,9 +108,9 @@ export class Aggregate extends AggregateBase {
|
|
|
117
108
|
inline_images,
|
|
118
109
|
collect_fonts
|
|
119
110
|
} = getConfigurationValue(this.agentIdentifier, 'session_replay');
|
|
120
|
-
this.waitForFlags(['sr']).then(_ref => {
|
|
121
|
-
let [
|
|
122
|
-
this.entitled =
|
|
111
|
+
this.waitForFlags(['srs', 'sr']).then(_ref => {
|
|
112
|
+
let [srMode, entitled] = _ref;
|
|
113
|
+
this.entitled = !!entitled;
|
|
123
114
|
if (!this.entitled) {
|
|
124
115
|
deregisterDrain(this.agentIdentifier, this.featureName);
|
|
125
116
|
if (this.recorder?.recording) {
|
|
@@ -129,11 +120,14 @@ export class Aggregate extends AggregateBase {
|
|
|
129
120
|
return;
|
|
130
121
|
}
|
|
131
122
|
this.drain();
|
|
132
|
-
this.initializeRecording(
|
|
123
|
+
this.initializeRecording(srMode);
|
|
133
124
|
}).then(() => {
|
|
134
|
-
if (this.mode === MODE.OFF)
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
if (this.mode === MODE.OFF) {
|
|
126
|
+
this.recorder?.stopRecording(); // stop any conservative preload recording launched by instrument
|
|
127
|
+
while (this.recorder?.getEvents().events.length) this.recorder?.clearBuffer?.();
|
|
128
|
+
}
|
|
129
|
+
sharedChannel.onReplayReady(this.mode);
|
|
130
|
+
}); // notify watchers that replay started with the mode
|
|
137
131
|
|
|
138
132
|
/** Detect if the default configs have been altered and report a SM. This is useful to evaluate what the reasonable defaults are across a customer base over time */
|
|
139
133
|
if (!autoStart) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Config/SessionReplay/AutoStart/Modified'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
@@ -176,7 +170,7 @@ export class Aggregate extends AggregateBase {
|
|
|
176
170
|
* @param {boolean} ignoreSession - whether to force the method to ignore the session state and use just the sample flags
|
|
177
171
|
* @returns {void}
|
|
178
172
|
*/
|
|
179
|
-
async initializeRecording(
|
|
173
|
+
async initializeRecording(srMode, ignoreSession) {
|
|
180
174
|
this.initialized = true;
|
|
181
175
|
if (!this.entitled) return;
|
|
182
176
|
|
|
@@ -191,23 +185,17 @@ export class Aggregate extends AggregateBase {
|
|
|
191
185
|
timeKeeper
|
|
192
186
|
} = getRuntime(this.agentIdentifier);
|
|
193
187
|
this.timeKeeper = timeKeeper;
|
|
194
|
-
if (
|
|
188
|
+
if (this.recorder?.parent.trigger === TRIGGERS.API && this.recorder?.recording) {
|
|
189
|
+
this.mode = MODE.FULL;
|
|
190
|
+
} else if (!session.isNew && !ignoreSession) {
|
|
195
191
|
// inherit the mode of the existing session
|
|
196
192
|
this.mode = session.state.sessionReplayMode;
|
|
197
193
|
} else {
|
|
198
194
|
// The session is new... determine the mode the new session should start in
|
|
199
|
-
|
|
200
|
-
else if (errorSample) this.mode = MODE.ERROR;
|
|
201
|
-
// If neither are selected, then don't record (early return)
|
|
202
|
-
else {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (this.recorder?.getEvents().type === 'preloaded') {
|
|
207
|
-
this.prepUtils().then(() => {
|
|
208
|
-
this.scheduler.runHarvest();
|
|
209
|
-
});
|
|
195
|
+
this.mode = srMode;
|
|
210
196
|
}
|
|
197
|
+
// If off, then don't record (early return)
|
|
198
|
+
if (this.mode === MODE.OFF) return;
|
|
211
199
|
if (!this.recorder) {
|
|
212
200
|
try {
|
|
213
201
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
@@ -225,13 +213,20 @@ export class Aggregate extends AggregateBase {
|
|
|
225
213
|
|
|
226
214
|
// If an error was noticed before the mode could be set (like in the early lifecycle of the page), immediately set to FULL mode
|
|
227
215
|
if (this.mode === MODE.ERROR && this.errorNoticed) this.mode = MODE.FULL;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
216
|
+
if (this.mode === MODE.FULL) {
|
|
217
|
+
// If theres preloaded events and we are in full mode, just harvest immediately to clear up space and for consistency
|
|
218
|
+
if (this.recorder?.getEvents().type === 'preloaded') {
|
|
219
|
+
this.prepUtils().then(() => {
|
|
220
|
+
this.scheduler.runHarvest();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
224
|
+
// ERROR mode will do this until an error is thrown, and then switch into FULL mode.
|
|
225
|
+
// If an error happened in ERROR mode before we've gotten to this stage, it will have already set the mode to FULL
|
|
226
|
+
if (!this.scheduler.started) {
|
|
227
|
+
// We only report (harvest) in FULL mode
|
|
228
|
+
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
229
|
+
}
|
|
235
230
|
}
|
|
236
231
|
await this.prepUtils();
|
|
237
232
|
if (!this.recorder.recording) this.recorder.startRecording();
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
import { handle } from '../../../common/event-emitter/handle';
|
|
13
13
|
import { DEFAULT_KEY, MODE, PREFIX } from '../../../common/session/constants';
|
|
14
14
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { hasReplayPrerequisite, isPreloadAllowed } from '../shared/utils';
|
|
16
|
+
import { FEATURE_NAME, SR_EVENT_EMITTER_TYPES, TRIGGERS } from '../constants';
|
|
17
17
|
export class Instrument extends InstrumentBase {
|
|
18
18
|
static featureName = FEATURE_NAME;
|
|
19
|
+
#mode;
|
|
19
20
|
constructor(agentIdentifier, aggregator) {
|
|
20
21
|
let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
21
22
|
super(agentIdentifier, aggregator, FEATURE_NAME, auto);
|
|
@@ -24,8 +25,12 @@ export class Instrument extends InstrumentBase {
|
|
|
24
25
|
try {
|
|
25
26
|
session = JSON.parse(localStorage.getItem("".concat(PREFIX, "_").concat(DEFAULT_KEY)));
|
|
26
27
|
} catch (err) {}
|
|
28
|
+
if (hasReplayPrerequisite(agentIdentifier)) {
|
|
29
|
+
this.ee.on('recordReplay', () => this.#apiStartOrRestartReplay());
|
|
30
|
+
}
|
|
27
31
|
if (this.#canPreloadRecorder(session)) {
|
|
28
|
-
this.#
|
|
32
|
+
this.#mode = session?.sessionReplayMode;
|
|
33
|
+
this.#preloadStartRecording();
|
|
29
34
|
} else {
|
|
30
35
|
this.importAggregator();
|
|
31
36
|
}
|
|
@@ -58,20 +63,55 @@ export class Instrument extends InstrumentBase {
|
|
|
58
63
|
return isPreloadAllowed(this.agentIdentifier);
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
#alreadyStarted = false;
|
|
67
|
+
/**
|
|
68
|
+
* This func is use for early pre-load recording prior to replay feature (agg) being loaded onto the page. It should only setup once, including if already called and in-progress.
|
|
69
|
+
*/
|
|
70
|
+
async #preloadStartRecording(trigger) {
|
|
71
|
+
if (this.#alreadyStarted) return;
|
|
72
|
+
this.#alreadyStarted = true;
|
|
73
|
+
try {
|
|
74
|
+
const {
|
|
75
|
+
Recorder
|
|
76
|
+
} = await import( /* webpackChunkName: "recorder" */'../shared/recorder');
|
|
77
|
+
|
|
78
|
+
// If startReplay() has been used by this point, we must record in full mode regardless of session preload:
|
|
79
|
+
// Note: recorder starts here with w/e the mode is at this time, but this may be changed later (see #apiStartOrRestartReplay else-case)
|
|
80
|
+
this.recorder ??= new Recorder({
|
|
81
|
+
mode: this.#mode,
|
|
82
|
+
agentIdentifier: this.agentIdentifier,
|
|
83
|
+
trigger,
|
|
84
|
+
ee: this.ee
|
|
85
|
+
});
|
|
86
|
+
this.recorder.startRecording();
|
|
87
|
+
this.abortHandler = this.recorder.stopRecording;
|
|
88
|
+
} catch (e) {}
|
|
72
89
|
this.importAggregator({
|
|
73
90
|
recorder: this.recorder,
|
|
74
91
|
errorNoticed: this.errorNoticed
|
|
75
92
|
});
|
|
76
93
|
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Called whenever startReplay API is used. That could occur any time, pre or post load.
|
|
97
|
+
*/
|
|
98
|
+
#apiStartOrRestartReplay() {
|
|
99
|
+
if (this.featAggregate) {
|
|
100
|
+
// post-load; there's possibly already an ongoing recording
|
|
101
|
+
if (this.featAggregate.mode !== MODE.FULL) this.featAggregate.initializeRecording(MODE.FULL, true);
|
|
102
|
+
} else {
|
|
103
|
+
// pre-load
|
|
104
|
+
this.#mode = MODE.FULL;
|
|
105
|
+
this.#preloadStartRecording(TRIGGERS.API);
|
|
106
|
+
// There's a race here wherein either:
|
|
107
|
+
// a. Recorder has not been initialized, and we've set the enforced mode, so we're good, or;
|
|
108
|
+
// b. Record has been initialized, possibly with the "wrong" mode, so we have to correct that + restart.
|
|
109
|
+
if (this.recorder && this.recorder.parent.mode !== MODE.FULL) {
|
|
110
|
+
this.recorder.parent.mode = MODE.FULL;
|
|
111
|
+
this.recorder.stopRecording();
|
|
112
|
+
this.recorder.startRecording();
|
|
113
|
+
this.abortHandler = this.recorder.stopRecording;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
77
117
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { getConfigurationValue, originals } from '../../../common/config/config';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
function hasReplayPrerequisite(agentId) {
|
|
2
|
+
import { canEnableSessionTracking } from '../../utils/feature-gates';
|
|
3
|
+
import { originTime } from '../../../common/constants/runtime';
|
|
4
|
+
export function hasReplayPrerequisite(agentId) {
|
|
7
5
|
return !!originals.MO &&
|
|
8
6
|
// Session Replay cannot work without Mutation Observer
|
|
9
|
-
|
|
7
|
+
canEnableSessionTracking(agentId) &&
|
|
10
8
|
// requires session tracking to be running (hence "session" replay...)
|
|
11
9
|
getConfigurationValue(agentId, 'session_trace.enabled') === true; // Session Replay as of now is tightly coupled with Session Trace in the UI
|
|
12
10
|
}
|