@newrelic/browser-agent 1.241.0 → 1.242.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/dist/cjs/cdn/polyfills/lite.js +13 -1
- package/dist/cjs/cdn/polyfills/pro.js +17 -1
- package/dist/cjs/cdn/polyfills/spa.js +18 -1
- package/dist/cjs/common/config/state/init.js +32 -5
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/dom/query-selector.js +16 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +10 -6
- package/dist/cjs/features/utils/instrument-base.js +1 -0
- package/dist/esm/cdn/polyfills/lite.js +8 -1
- package/dist/esm/cdn/polyfills/pro.js +13 -2
- package/dist/esm/cdn/polyfills/spa.js +13 -1
- package/dist/esm/common/config/state/init.js +32 -5
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/dom/query-selector.js +9 -0
- package/dist/esm/features/session_replay/aggregate/index.js +10 -6
- package/dist/esm/features/utils/instrument-base.js +1 -0
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/dom/query-selector.d.ts +2 -0
- package/dist/types/common/dom/query-selector.d.ts.map +1 -0
- 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/utils/instrument-base.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/polyfills/lite.js +14 -1
- package/src/cdn/polyfills/pro.js +23 -2
- package/src/cdn/polyfills/spa.js +24 -1
- package/src/common/config/state/init.js +33 -4
- package/src/common/config/state/init.test.js +40 -0
- package/src/common/dom/query-selector.js +9 -0
- package/src/common/dom/query-selector.test.js +24 -0
- package/src/features/session_replay/aggregate/index.js +10 -6
- package/src/features/utils/instrument-base.js +1 -0
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
require("../polyfills.js");
|
|
4
|
-
require("
|
|
4
|
+
var _agent = require("../../loaders/agent");
|
|
5
|
+
var _instrument = require("../../features/page_view_event/instrument");
|
|
6
|
+
var _instrument2 = require("../../features/page_view_timing/instrument");
|
|
7
|
+
var _instrument3 = require("../../features/metrics/instrument");
|
|
8
|
+
/**
|
|
9
|
+
* @file Creates a version of the "Lite" agent loader with [core-js]{@link https://github.com/zloirock/core-js}
|
|
10
|
+
* polyfills for pre-ES6 browsers and IE 11.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
new _agent.Agent({
|
|
14
|
+
features: [_instrument.Instrument, _instrument2.Instrument, _instrument3.Instrument],
|
|
15
|
+
loaderType: 'lite-polyfills'
|
|
16
|
+
});
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
require("../polyfills.js");
|
|
4
|
-
require("
|
|
4
|
+
var _agent = require("../../loaders/agent");
|
|
5
|
+
var _instrument = require("../../features/page_view_event/instrument");
|
|
6
|
+
var _instrument2 = require("../../features/page_view_timing/instrument");
|
|
7
|
+
var _instrument3 = require("../../features/metrics/instrument");
|
|
8
|
+
var _instrument4 = require("../../features/jserrors/instrument");
|
|
9
|
+
var _instrument5 = require("../../features/ajax/instrument");
|
|
10
|
+
var _instrument6 = require("../../features/session_trace/instrument");
|
|
11
|
+
var _instrument7 = require("../../features/page_action/instrument");
|
|
12
|
+
/**
|
|
13
|
+
* @file Creates a version of the "PRO" agent loader with [core-js]{@link https://github.com/zloirock/core-js}
|
|
14
|
+
* polyfills for pre-ES6 browsers and IE 11.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
new _agent.Agent({
|
|
18
|
+
features: [_instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument5.Instrument, _instrument3.Instrument, _instrument7.Instrument, _instrument4.Instrument],
|
|
19
|
+
loaderType: 'pro-polyfills'
|
|
20
|
+
});
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
require("../polyfills.js");
|
|
4
|
-
require("
|
|
4
|
+
var _agent = require("../../loaders/agent");
|
|
5
|
+
var _instrument = require("../../features/page_view_event/instrument");
|
|
6
|
+
var _instrument2 = require("../../features/page_view_timing/instrument");
|
|
7
|
+
var _instrument3 = require("../../features/metrics/instrument");
|
|
8
|
+
var _instrument4 = require("../../features/jserrors/instrument");
|
|
9
|
+
var _instrument5 = require("../../features/ajax/instrument");
|
|
10
|
+
var _instrument6 = require("../../features/session_trace/instrument");
|
|
11
|
+
var _instrument7 = require("../../features/spa/instrument");
|
|
12
|
+
var _instrument8 = require("../../features/page_action/instrument");
|
|
13
|
+
/**
|
|
14
|
+
* @file Creates a version of the "SPA" agent loader with [core-js]{@link https://github.com/zloirock/core-js}
|
|
15
|
+
* polyfills for pre-ES6 browsers and IE 11.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
new _agent.Agent({
|
|
19
|
+
features: [_instrument5.Instrument, _instrument.Instrument, _instrument2.Instrument, _instrument6.Instrument, _instrument3.Instrument, _instrument8.Instrument, _instrument4.Instrument, _instrument7.Instrument],
|
|
20
|
+
loaderType: 'spa-polyfills'
|
|
21
|
+
});
|
|
@@ -6,16 +6,36 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.getConfiguration = getConfiguration;
|
|
7
7
|
exports.getConfigurationValue = getConfigurationValue;
|
|
8
8
|
exports.setConfiguration = setConfiguration;
|
|
9
|
+
var _querySelector = require("../../dom/query-selector");
|
|
9
10
|
var _constants = require("../../session/constants");
|
|
11
|
+
var _console = require("../../util/console");
|
|
10
12
|
var _nreum = require("../../window/nreum");
|
|
11
13
|
var _configurable = require("./configurable");
|
|
12
14
|
const model = () => {
|
|
13
15
|
const hiddenState = {
|
|
16
|
+
mask_selector: '*',
|
|
14
17
|
block_selector: '[data-nr-block]',
|
|
15
18
|
mask_input_options: {
|
|
16
|
-
|
|
19
|
+
color: false,
|
|
20
|
+
date: false,
|
|
21
|
+
'datetime-local': false,
|
|
22
|
+
email: false,
|
|
23
|
+
month: false,
|
|
24
|
+
number: false,
|
|
25
|
+
range: false,
|
|
26
|
+
search: false,
|
|
27
|
+
tel: false,
|
|
28
|
+
text: false,
|
|
29
|
+
time: false,
|
|
30
|
+
url: false,
|
|
31
|
+
week: false,
|
|
32
|
+
// unify textarea and select element with text input
|
|
33
|
+
textarea: false,
|
|
34
|
+
select: false,
|
|
35
|
+
password: true // This will be enforced to always be true in the setter
|
|
17
36
|
}
|
|
18
37
|
};
|
|
38
|
+
|
|
19
39
|
return {
|
|
20
40
|
proxy: {
|
|
21
41
|
assets: undefined,
|
|
@@ -91,8 +111,15 @@ const model = () => {
|
|
|
91
111
|
error_sampling_rate: 50,
|
|
92
112
|
// float from 0 - 100
|
|
93
113
|
// recording config settings
|
|
94
|
-
mask_text_selector: '*',
|
|
95
114
|
mask_all_inputs: true,
|
|
115
|
+
// this has a getter/setter to facilitate validation of the selectors
|
|
116
|
+
get mask_text_selector() {
|
|
117
|
+
return hiddenState.mask_selector;
|
|
118
|
+
},
|
|
119
|
+
set mask_text_selector(val) {
|
|
120
|
+
if ((0, _querySelector.isValidSelector)(val)) hiddenState.mask_selector = val + ',[data-nr-mask]';else if (val === null) hiddenState.mask_selector = val; // null is acceptable, which completely disables the behavior
|
|
121
|
+
else (0, _console.warn)('An invalid session_replay.mask_selector was provided and will not be used', val);
|
|
122
|
+
},
|
|
96
123
|
// these properties only have getters because they are enforcable constants and should error if someone tries to override them
|
|
97
124
|
get block_class() {
|
|
98
125
|
return 'nr-block';
|
|
@@ -109,17 +136,17 @@ const model = () => {
|
|
|
109
136
|
return hiddenState.block_selector;
|
|
110
137
|
},
|
|
111
138
|
set block_selector(val) {
|
|
112
|
-
hiddenState.block_selector += ",".concat(val);
|
|
139
|
+
if ((0, _querySelector.isValidSelector)(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') (0, _console.warn)('An invalid session_replay.block_selector was provided and will not be used', val);
|
|
113
140
|
},
|
|
114
141
|
// password: must always be present and true no matter what customer sets
|
|
115
142
|
get mask_input_options() {
|
|
116
143
|
return hiddenState.mask_input_options;
|
|
117
144
|
},
|
|
118
145
|
set mask_input_options(val) {
|
|
119
|
-
hiddenState.mask_input_options = {
|
|
146
|
+
if (val && typeof val === 'object') hiddenState.mask_input_options = {
|
|
120
147
|
...val,
|
|
121
148
|
password: true
|
|
122
|
-
};
|
|
149
|
+
};else (0, _console.warn)('An invalid session_replay.mask_input_option was provided and will not be used', val);
|
|
123
150
|
}
|
|
124
151
|
},
|
|
125
152
|
spa: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isValidSelector = void 0;
|
|
7
|
+
const isValidSelector = selector => {
|
|
8
|
+
if (!selector || typeof selector !== 'string') return false;
|
|
9
|
+
try {
|
|
10
|
+
document.createDocumentFragment().querySelector(selector);
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
};
|
|
16
|
+
exports.isValidSelector = isValidSelector;
|
|
@@ -15,6 +15,8 @@ var _sharedChannel = require("../../../common/constants/shared-channel");
|
|
|
15
15
|
var _encode = require("../../../common/url/encode");
|
|
16
16
|
var _console = require("../../../common/util/console");
|
|
17
17
|
var _runtime = require("../../../common/constants/runtime");
|
|
18
|
+
var _constants2 = require("../../metrics/constants");
|
|
19
|
+
var _features = require("../../../loaders/features/features");
|
|
18
20
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
21
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /*
|
|
20
22
|
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
@@ -104,7 +106,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
104
106
|
if (shouldSetup) {
|
|
105
107
|
// 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.
|
|
106
108
|
this.ee.on(_sessionEntity.SESSION_EVENTS.RESET, () => {
|
|
107
|
-
this.abort();
|
|
109
|
+
this.abort('Session Reset');
|
|
108
110
|
});
|
|
109
111
|
|
|
110
112
|
// The SessionEntity class can emit a message indicating the session was paused (visibility change). This feature must stop recording if that occurs.
|
|
@@ -191,7 +193,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
191
193
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
192
194
|
recorder = (await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "recorder" */'rrweb')))).record;
|
|
193
195
|
} catch (err) {
|
|
194
|
-
return this.abort();
|
|
196
|
+
return this.abort('Recorder failed to import');
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
@@ -267,7 +269,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
267
269
|
onHarvestFinished(result) {
|
|
268
270
|
// The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
|
|
269
271
|
if (result.status === 429) {
|
|
270
|
-
this.abort();
|
|
272
|
+
this.abort('429: Too many requests');
|
|
271
273
|
}
|
|
272
274
|
if (this.blocked) this.scheduler.stopTimer(true);
|
|
273
275
|
}
|
|
@@ -287,7 +289,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
287
289
|
startRecording() {
|
|
288
290
|
if (!recorder) {
|
|
289
291
|
(0, _console.warn)('Recording library was never imported');
|
|
290
|
-
return this.abort();
|
|
292
|
+
return this.abort('Recorder was never imported');
|
|
291
293
|
}
|
|
292
294
|
this.clearTimestamps();
|
|
293
295
|
// set the fallbacks as early as possible
|
|
@@ -331,7 +333,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
331
333
|
// Vortex will block payloads at a certain size, we might as well not send.
|
|
332
334
|
if (payloadSize > MAX_PAYLOAD_SIZE) {
|
|
333
335
|
this.clearBuffer();
|
|
334
|
-
|
|
336
|
+
this.ee.emit(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Too-Big/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
|
|
337
|
+
return this.abort('Payload too big');
|
|
335
338
|
}
|
|
336
339
|
// Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
|
|
337
340
|
// to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
|
|
@@ -402,7 +405,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
402
405
|
}
|
|
403
406
|
|
|
404
407
|
/** Abort the feature, once aborted it will not resume */
|
|
405
|
-
abort() {
|
|
408
|
+
abort(reason) {
|
|
409
|
+
(0, _console.warn)("SR aborted -- ".concat(reason));
|
|
406
410
|
this.blocked = true;
|
|
407
411
|
this.mode = _sessionEntity.MODE.OFF;
|
|
408
412
|
this.stopRecording();
|
|
@@ -119,6 +119,7 @@ class InstrumentBase extends _featureBase.FeatureBase {
|
|
|
119
119
|
(0, _console.warn)("Downloading and initializing ".concat(this.featureName, " failed..."), e);
|
|
120
120
|
this.abortHandler?.(); // undo any important alterations made to the page
|
|
121
121
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
122
|
+
(0, _drain.drain)(this.agentIdentifier, this.featureName);
|
|
122
123
|
loadedSuccessfully(false);
|
|
123
124
|
}
|
|
124
125
|
};
|
|
@@ -4,4 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js';
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent';
|
|
8
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument';
|
|
9
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument';
|
|
10
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument';
|
|
11
|
+
new Agent({
|
|
12
|
+
features: [InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentMetrics],
|
|
13
|
+
loaderType: 'lite-polyfills'
|
|
14
|
+
});
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Creates a version of the "
|
|
2
|
+
* @file Creates a version of the "PRO" agent loader with [core-js]{@link https://github.com/zloirock/core-js}
|
|
3
3
|
* polyfills for pre-ES6 browsers and IE 11.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js';
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent';
|
|
8
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument';
|
|
9
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument';
|
|
10
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument';
|
|
11
|
+
import { Instrument as InstrumentErrors } from '../../features/jserrors/instrument';
|
|
12
|
+
import { Instrument as InstrumentXhr } from '../../features/ajax/instrument';
|
|
13
|
+
import { Instrument as InstrumentSessionTrace } from '../../features/session_trace/instrument';
|
|
14
|
+
import { Instrument as InstrumentPageAction } from '../../features/page_action/instrument';
|
|
15
|
+
new Agent({
|
|
16
|
+
features: [InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentXhr, InstrumentMetrics, InstrumentPageAction, InstrumentErrors],
|
|
17
|
+
loaderType: 'pro-polyfills'
|
|
18
|
+
});
|
|
@@ -4,4 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js';
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent';
|
|
8
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument';
|
|
9
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument';
|
|
10
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument';
|
|
11
|
+
import { Instrument as InstrumentErrors } from '../../features/jserrors/instrument';
|
|
12
|
+
import { Instrument as InstrumentXhr } from '../../features/ajax/instrument';
|
|
13
|
+
import { Instrument as InstrumentSessionTrace } from '../../features/session_trace/instrument';
|
|
14
|
+
import { Instrument as InstrumentSpa } from '../../features/spa/instrument';
|
|
15
|
+
import { Instrument as InstrumentPageAction } from '../../features/page_action/instrument';
|
|
16
|
+
new Agent({
|
|
17
|
+
features: [InstrumentXhr, InstrumentPageViewEvent, InstrumentPageViewTiming, InstrumentSessionTrace, InstrumentMetrics, InstrumentPageAction, InstrumentErrors, InstrumentSpa],
|
|
18
|
+
loaderType: 'spa-polyfills'
|
|
19
|
+
});
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
+
import { isValidSelector } from '../../dom/query-selector';
|
|
1
2
|
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS } from '../../session/constants';
|
|
3
|
+
import { warn } from '../../util/console';
|
|
2
4
|
import { gosNREUMInitializedAgents } from '../../window/nreum';
|
|
3
5
|
import { getModeledObject } from './configurable';
|
|
4
6
|
const model = () => {
|
|
5
7
|
const hiddenState = {
|
|
8
|
+
mask_selector: '*',
|
|
6
9
|
block_selector: '[data-nr-block]',
|
|
7
10
|
mask_input_options: {
|
|
8
|
-
|
|
11
|
+
color: false,
|
|
12
|
+
date: false,
|
|
13
|
+
'datetime-local': false,
|
|
14
|
+
email: false,
|
|
15
|
+
month: false,
|
|
16
|
+
number: false,
|
|
17
|
+
range: false,
|
|
18
|
+
search: false,
|
|
19
|
+
tel: false,
|
|
20
|
+
text: false,
|
|
21
|
+
time: false,
|
|
22
|
+
url: false,
|
|
23
|
+
week: false,
|
|
24
|
+
// unify textarea and select element with text input
|
|
25
|
+
textarea: false,
|
|
26
|
+
select: false,
|
|
27
|
+
password: true // This will be enforced to always be true in the setter
|
|
9
28
|
}
|
|
10
29
|
};
|
|
30
|
+
|
|
11
31
|
return {
|
|
12
32
|
proxy: {
|
|
13
33
|
assets: undefined,
|
|
@@ -83,8 +103,15 @@ const model = () => {
|
|
|
83
103
|
error_sampling_rate: 50,
|
|
84
104
|
// float from 0 - 100
|
|
85
105
|
// recording config settings
|
|
86
|
-
mask_text_selector: '*',
|
|
87
106
|
mask_all_inputs: true,
|
|
107
|
+
// this has a getter/setter to facilitate validation of the selectors
|
|
108
|
+
get mask_text_selector() {
|
|
109
|
+
return hiddenState.mask_selector;
|
|
110
|
+
},
|
|
111
|
+
set mask_text_selector(val) {
|
|
112
|
+
if (isValidSelector(val)) hiddenState.mask_selector = val + ',[data-nr-mask]';else if (val === null) hiddenState.mask_selector = val; // null is acceptable, which completely disables the behavior
|
|
113
|
+
else warn('An invalid session_replay.mask_selector was provided and will not be used', val);
|
|
114
|
+
},
|
|
88
115
|
// these properties only have getters because they are enforcable constants and should error if someone tries to override them
|
|
89
116
|
get block_class() {
|
|
90
117
|
return 'nr-block';
|
|
@@ -101,17 +128,17 @@ const model = () => {
|
|
|
101
128
|
return hiddenState.block_selector;
|
|
102
129
|
},
|
|
103
130
|
set block_selector(val) {
|
|
104
|
-
hiddenState.block_selector += ",".concat(val);
|
|
131
|
+
if (isValidSelector(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') warn('An invalid session_replay.block_selector was provided and will not be used', val);
|
|
105
132
|
},
|
|
106
133
|
// password: must always be present and true no matter what customer sets
|
|
107
134
|
get mask_input_options() {
|
|
108
135
|
return hiddenState.mask_input_options;
|
|
109
136
|
},
|
|
110
137
|
set mask_input_options(val) {
|
|
111
|
-
hiddenState.mask_input_options = {
|
|
138
|
+
if (val && typeof val === 'object') hiddenState.mask_input_options = {
|
|
112
139
|
...val,
|
|
113
140
|
password: true
|
|
114
|
-
};
|
|
141
|
+
};else warn('An invalid session_replay.mask_input_option was provided and will not be used', val);
|
|
115
142
|
}
|
|
116
143
|
},
|
|
117
144
|
spa: {
|
|
@@ -21,6 +21,8 @@ import { sharedChannel } from '../../../common/constants/shared-channel';
|
|
|
21
21
|
import { obj as encodeObj } from '../../../common/url/encode';
|
|
22
22
|
import { warn } from '../../../common/util/console';
|
|
23
23
|
import { globalScope } from '../../../common/constants/runtime';
|
|
24
|
+
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
25
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
24
26
|
|
|
25
27
|
// would be better to get this dynamically in some way
|
|
26
28
|
export const RRWEB_VERSION = '2.0.0-alpha.8';
|
|
@@ -96,7 +98,7 @@ export class Aggregate extends AggregateBase {
|
|
|
96
98
|
if (shouldSetup) {
|
|
97
99
|
// 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.
|
|
98
100
|
this.ee.on(SESSION_EVENTS.RESET, () => {
|
|
99
|
-
this.abort();
|
|
101
|
+
this.abort('Session Reset');
|
|
100
102
|
});
|
|
101
103
|
|
|
102
104
|
// The SessionEntity class can emit a message indicating the session was paused (visibility change). This feature must stop recording if that occurs.
|
|
@@ -183,7 +185,7 @@ export class Aggregate extends AggregateBase {
|
|
|
183
185
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
184
186
|
recorder = (await import( /* webpackChunkName: "recorder" */'rrweb')).record;
|
|
185
187
|
} catch (err) {
|
|
186
|
-
return this.abort();
|
|
188
|
+
return this.abort('Recorder failed to import');
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
@@ -259,7 +261,7 @@ export class Aggregate extends AggregateBase {
|
|
|
259
261
|
onHarvestFinished(result) {
|
|
260
262
|
// The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
|
|
261
263
|
if (result.status === 429) {
|
|
262
|
-
this.abort();
|
|
264
|
+
this.abort('429: Too many requests');
|
|
263
265
|
}
|
|
264
266
|
if (this.blocked) this.scheduler.stopTimer(true);
|
|
265
267
|
}
|
|
@@ -279,7 +281,7 @@ export class Aggregate extends AggregateBase {
|
|
|
279
281
|
startRecording() {
|
|
280
282
|
if (!recorder) {
|
|
281
283
|
warn('Recording library was never imported');
|
|
282
|
-
return this.abort();
|
|
284
|
+
return this.abort('Recorder was never imported');
|
|
283
285
|
}
|
|
284
286
|
this.clearTimestamps();
|
|
285
287
|
// set the fallbacks as early as possible
|
|
@@ -323,7 +325,8 @@ export class Aggregate extends AggregateBase {
|
|
|
323
325
|
// Vortex will block payloads at a certain size, we might as well not send.
|
|
324
326
|
if (payloadSize > MAX_PAYLOAD_SIZE) {
|
|
325
327
|
this.clearBuffer();
|
|
326
|
-
|
|
328
|
+
this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Too-Big/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
|
|
329
|
+
return this.abort('Payload too big');
|
|
327
330
|
}
|
|
328
331
|
// Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
|
|
329
332
|
// to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
|
|
@@ -394,7 +397,8 @@ export class Aggregate extends AggregateBase {
|
|
|
394
397
|
}
|
|
395
398
|
|
|
396
399
|
/** Abort the feature, once aborted it will not resume */
|
|
397
|
-
abort() {
|
|
400
|
+
abort(reason) {
|
|
401
|
+
warn("SR aborted -- ".concat(reason));
|
|
398
402
|
this.blocked = true;
|
|
399
403
|
this.mode = MODE.OFF;
|
|
400
404
|
this.stopRecording();
|
|
@@ -114,6 +114,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
114
114
|
warn("Downloading and initializing ".concat(this.featureName, " failed..."), e);
|
|
115
115
|
this.abortHandler?.(); // undo any important alterations made to the page
|
|
116
116
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
117
|
+
drain(this.agentIdentifier, this.featureName);
|
|
117
118
|
loadedSuccessfully(false);
|
|
118
119
|
}
|
|
119
120
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"AAuGA,+CAIC;AAED,0DAIC;AAED,+DAYC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-selector.d.ts","sourceRoot":"","sources":["../../../../src/common/dom/query-selector.js"],"names":[],"mappings":"AAAO,wDAQN"}
|
|
@@ -94,7 +94,7 @@ export class Aggregate extends AggregateBase {
|
|
|
94
94
|
/** Estimate the payload size */
|
|
95
95
|
getPayloadSize(newBytes?: number): any;
|
|
96
96
|
/** Abort the feature, once aborted it will not resume */
|
|
97
|
-
abort(): void;
|
|
97
|
+
abort(reason: any): void;
|
|
98
98
|
/** Extensive research has yielded about an 88% compression factor on these payloads.
|
|
99
99
|
* This is an estimation using that factor as to not cause performance issues while evaluating
|
|
100
100
|
* https://staging.onenr.io/037jbJWxbjy
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA2BA,4CAA4C;AAE5C,mCAAmC;AAInC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AAIvC;IACE,2BAAiC;IACjC,mDAmGC;IAjGC,iHAAiH;IACjH,cAAgB;IAChB,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IACxB,mEAAmE;IACnE,sBAAyB;IACzB,6GAA6G;IAC7G,aAAoB;IAGpB,iEAAiE;IACjE,mBAAsB;IACtB,gDAAgD;IAChD,wBAA0B;IAE1B,gGAAgG;IAChG,sBAAyB;IACzB;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IAErB;;OAEG;IACH;;;;;;;;;MAA+G;IAE/G,qGAAqG;IACrG,+BAA+B;IAE/B,kIAAkI;IAClI,cAAyB;IAOzB,uIAAuI;IACvI,0BAAyE;IAiBvE,wCAKQ;IA+BZ;;;;;;OAMG;IACH,kCALW,OAAO,eACP,OAAO,cACP,OAAO,GACL,IAAI,CAyDhB;IAED;;;;;;;;;oBAaC;IAED;;;;;;;;;MA4BC;IAED,qCAOC;IAED,kFAAkF;IAClF,oBAQC;IAED,qDAAqD;IACrD,uBA4BC;IAED,yHAAyH;IACzH,yCA6CC;IAED,0HAA0H;IAC1H,yBAGC;IAED,gCAQC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED,yDAAyD;IACzD,yBAQC;IAED;;;SAGK;IACL,oCAGC;IAED,yCAGC;CACF;8BA/X6B,4BAA4B;iCALzB,2CAA2C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAcA;;;GAGG;AACH;IACE;;;;;;;;OAQG;IACH,6BAPW,MAAM,uCAEN,MAAM,8BA4BhB;IArBC,cAAgB;IAEhB,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,qBAA8B;IAE9B;;;MAGE;IACF,kCAAoC;IAQtC;;;;;OAKG;IACH,
|
|
1
|
+
{"version":3,"file":"instrument-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/instrument-base.js"],"names":[],"mappings":"AAcA;;;GAGG;AACH;IACE;;;;;;;;OAQG;IACH,6BAPW,MAAM,uCAEN,MAAM,8BA4BhB;IArBC,cAAgB;IAEhB,8IAA8I;IAC9I,cADW,WAAW,SAAS,CACF;IAE7B;;;MAGE;IACF,qBAA8B;IAE9B;;;MAGE;IACF,kCAAoC;IAQtC;;;;;OAKG;IACH,mEA4DC;IAED;;;;;KAKC;IACD,6BAJS,MAAM,mCAWd;CACF;4BAhI2B,gBAAgB"}
|
package/package.json
CHANGED
|
@@ -4,4 +4,17 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js'
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent'
|
|
8
|
+
|
|
9
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument'
|
|
10
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument'
|
|
11
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument'
|
|
12
|
+
|
|
13
|
+
new Agent({
|
|
14
|
+
features: [
|
|
15
|
+
InstrumentPageViewEvent,
|
|
16
|
+
InstrumentPageViewTiming,
|
|
17
|
+
InstrumentMetrics
|
|
18
|
+
],
|
|
19
|
+
loaderType: 'lite-polyfills'
|
|
20
|
+
})
|
package/src/cdn/polyfills/pro.js
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Creates a version of the "
|
|
2
|
+
* @file Creates a version of the "PRO" agent loader with [core-js]{@link https://github.com/zloirock/core-js}
|
|
3
3
|
* polyfills for pre-ES6 browsers and IE 11.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js'
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent'
|
|
8
|
+
|
|
9
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument'
|
|
10
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument'
|
|
11
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument'
|
|
12
|
+
import { Instrument as InstrumentErrors } from '../../features/jserrors/instrument'
|
|
13
|
+
import { Instrument as InstrumentXhr } from '../../features/ajax/instrument'
|
|
14
|
+
import { Instrument as InstrumentSessionTrace } from '../../features/session_trace/instrument'
|
|
15
|
+
import { Instrument as InstrumentPageAction } from '../../features/page_action/instrument'
|
|
16
|
+
|
|
17
|
+
new Agent({
|
|
18
|
+
features: [
|
|
19
|
+
InstrumentPageViewEvent,
|
|
20
|
+
InstrumentPageViewTiming,
|
|
21
|
+
InstrumentSessionTrace,
|
|
22
|
+
InstrumentXhr,
|
|
23
|
+
InstrumentMetrics,
|
|
24
|
+
InstrumentPageAction,
|
|
25
|
+
InstrumentErrors
|
|
26
|
+
],
|
|
27
|
+
loaderType: 'pro-polyfills'
|
|
28
|
+
})
|
package/src/cdn/polyfills/spa.js
CHANGED
|
@@ -4,4 +4,27 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import '../polyfills.js'
|
|
7
|
-
import '
|
|
7
|
+
import { Agent } from '../../loaders/agent'
|
|
8
|
+
|
|
9
|
+
import { Instrument as InstrumentPageViewEvent } from '../../features/page_view_event/instrument'
|
|
10
|
+
import { Instrument as InstrumentPageViewTiming } from '../../features/page_view_timing/instrument'
|
|
11
|
+
import { Instrument as InstrumentMetrics } from '../../features/metrics/instrument'
|
|
12
|
+
import { Instrument as InstrumentErrors } from '../../features/jserrors/instrument'
|
|
13
|
+
import { Instrument as InstrumentXhr } from '../../features/ajax/instrument'
|
|
14
|
+
import { Instrument as InstrumentSessionTrace } from '../../features/session_trace/instrument'
|
|
15
|
+
import { Instrument as InstrumentSpa } from '../../features/spa/instrument'
|
|
16
|
+
import { Instrument as InstrumentPageAction } from '../../features/page_action/instrument'
|
|
17
|
+
|
|
18
|
+
new Agent({
|
|
19
|
+
features: [
|
|
20
|
+
InstrumentXhr,
|
|
21
|
+
InstrumentPageViewEvent,
|
|
22
|
+
InstrumentPageViewTiming,
|
|
23
|
+
InstrumentSessionTrace,
|
|
24
|
+
InstrumentMetrics,
|
|
25
|
+
InstrumentPageAction,
|
|
26
|
+
InstrumentErrors,
|
|
27
|
+
InstrumentSpa
|
|
28
|
+
],
|
|
29
|
+
loaderType: 'spa-polyfills'
|
|
30
|
+
})
|
|
@@ -1,11 +1,32 @@
|
|
|
1
|
+
import { isValidSelector } from '../../dom/query-selector'
|
|
1
2
|
import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS } from '../../session/constants'
|
|
3
|
+
import { warn } from '../../util/console'
|
|
2
4
|
import { gosNREUMInitializedAgents } from '../../window/nreum'
|
|
3
5
|
import { getModeledObject } from './configurable'
|
|
4
6
|
|
|
5
7
|
const model = () => {
|
|
6
8
|
const hiddenState = {
|
|
9
|
+
mask_selector: '*',
|
|
7
10
|
block_selector: '[data-nr-block]',
|
|
8
|
-
mask_input_options: {
|
|
11
|
+
mask_input_options: {
|
|
12
|
+
color: false,
|
|
13
|
+
date: false,
|
|
14
|
+
'datetime-local': false,
|
|
15
|
+
email: false,
|
|
16
|
+
month: false,
|
|
17
|
+
number: false,
|
|
18
|
+
range: false,
|
|
19
|
+
search: false,
|
|
20
|
+
tel: false,
|
|
21
|
+
text: false,
|
|
22
|
+
time: false,
|
|
23
|
+
url: false,
|
|
24
|
+
week: false,
|
|
25
|
+
// unify textarea and select element with text input
|
|
26
|
+
textarea: false,
|
|
27
|
+
select: false,
|
|
28
|
+
password: true // This will be enforced to always be true in the setter
|
|
29
|
+
}
|
|
9
30
|
}
|
|
10
31
|
return {
|
|
11
32
|
proxy: {
|
|
@@ -43,8 +64,14 @@ const model = () => {
|
|
|
43
64
|
sampling_rate: 50, // float from 0 - 100
|
|
44
65
|
error_sampling_rate: 50, // float from 0 - 100
|
|
45
66
|
// recording config settings
|
|
46
|
-
mask_text_selector: '*',
|
|
47
67
|
mask_all_inputs: true,
|
|
68
|
+
// this has a getter/setter to facilitate validation of the selectors
|
|
69
|
+
get mask_text_selector () { return hiddenState.mask_selector },
|
|
70
|
+
set mask_text_selector (val) {
|
|
71
|
+
if (isValidSelector(val)) hiddenState.mask_selector = val + ',[data-nr-mask]'
|
|
72
|
+
else if (val === null) hiddenState.mask_selector = val // null is acceptable, which completely disables the behavior
|
|
73
|
+
else warn('An invalid session_replay.mask_selector was provided and will not be used', val)
|
|
74
|
+
},
|
|
48
75
|
// these properties only have getters because they are enforcable constants and should error if someone tries to override them
|
|
49
76
|
get block_class () { return 'nr-block' },
|
|
50
77
|
get ignore_class () { return 'nr-ignore' },
|
|
@@ -55,14 +82,16 @@ const model = () => {
|
|
|
55
82
|
return hiddenState.block_selector
|
|
56
83
|
},
|
|
57
84
|
set block_selector (val) {
|
|
58
|
-
hiddenState.block_selector += `,${val}`
|
|
85
|
+
if (isValidSelector(val)) hiddenState.block_selector += `,${val}`
|
|
86
|
+
else if (val !== '') warn('An invalid session_replay.block_selector was provided and will not be used', val)
|
|
59
87
|
},
|
|
60
88
|
// password: must always be present and true no matter what customer sets
|
|
61
89
|
get mask_input_options () {
|
|
62
90
|
return hiddenState.mask_input_options
|
|
63
91
|
},
|
|
64
92
|
set mask_input_options (val) {
|
|
65
|
-
hiddenState.mask_input_options = { ...val, password: true }
|
|
93
|
+
if (val && typeof val === 'object') hiddenState.mask_input_options = { ...val, password: true }
|
|
94
|
+
else warn('An invalid session_replay.mask_input_option was provided and will not be used', val)
|
|
66
95
|
}
|
|
67
96
|
},
|
|
68
97
|
spa: { enabled: true, harvestTimeSeconds: 10, autoStart: true }
|
|
@@ -26,3 +26,43 @@ test('getConfigurationValue parses path correctly', () => {
|
|
|
26
26
|
expect(getConfigurationValue('ab', 'page_action')).toEqual({ enabled: true, harvestTimeSeconds: 1000, autoStart: true })
|
|
27
27
|
expect(getConfigurationValue('ab', 'page_action.harvestTimeSeconds')).toEqual(1000)
|
|
28
28
|
})
|
|
29
|
+
|
|
30
|
+
describe('property getters/setters used for validation', () => {
|
|
31
|
+
test('invalid values do not pass through', () => {
|
|
32
|
+
setConfiguration('12345', {
|
|
33
|
+
session_replay: {
|
|
34
|
+
block_selector: '[invalid selector]',
|
|
35
|
+
mask_text_selector: '[invalid selector]',
|
|
36
|
+
mask_input_options: 'select:true'
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
expect(getConfigurationValue('12345', 'session_replay.block_selector')).toEqual('[data-nr-block]')
|
|
41
|
+
expect(getConfigurationValue('12345', 'session_replay.mask_text_selector')).toEqual('*')
|
|
42
|
+
expect(getConfigurationValue('12345', 'session_replay.mask_input_options')).toMatchObject({ password: true, select: false })
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('valid values do pass through', () => {
|
|
46
|
+
setConfiguration('23456', {
|
|
47
|
+
session_replay: {
|
|
48
|
+
block_selector: '[block-text-test]',
|
|
49
|
+
mask_text_selector: '[mask-text-test]',
|
|
50
|
+
mask_input_options: { select: true }
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(getConfigurationValue('23456', 'session_replay.block_selector')).toEqual('[data-nr-block],[block-text-test]')
|
|
55
|
+
expect(getConfigurationValue('23456', 'session_replay.mask_text_selector')).toEqual('[mask-text-test],[data-nr-mask]')
|
|
56
|
+
expect(getConfigurationValue('23456', 'session_replay.mask_input_options')).toMatchObject({ password: true, select: true })
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('null accepted for mask_text', () => {
|
|
60
|
+
setConfiguration('34567', {
|
|
61
|
+
session_replay: {
|
|
62
|
+
mask_text_selector: null
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
expect(getConfigurationValue('34567', 'session_replay.mask_text_selector')).toEqual(null)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isValidSelector } from './query-selector'
|
|
2
|
+
describe('query selector tests', () => {
|
|
3
|
+
test('handles nullish values', () => {
|
|
4
|
+
expect(isValidSelector(null)).toEqual(false)
|
|
5
|
+
expect(isValidSelector('')).toEqual(false)
|
|
6
|
+
expect(isValidSelector(0)).toEqual(false)
|
|
7
|
+
expect(isValidSelector(false)).toEqual(false)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('handles truthy but invalid values', () => {
|
|
11
|
+
expect(isValidSelector({ test: 1 })).toEqual(false)
|
|
12
|
+
expect(isValidSelector([1, 2, 3])).toEqual(false)
|
|
13
|
+
expect(isValidSelector(1)).toEqual(false)
|
|
14
|
+
expect(isValidSelector(',')).toEqual(false)
|
|
15
|
+
expect(isValidSelector('[invalid space]')).toEqual(false)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('handles valid selectors', () => {
|
|
19
|
+
expect(isValidSelector('#id')).toEqual(true)
|
|
20
|
+
expect(isValidSelector('.class')).toEqual(true)
|
|
21
|
+
expect(isValidSelector('.multiple,#selectors')).toEqual(true)
|
|
22
|
+
expect(isValidSelector('[attr-selector]')).toEqual(true)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
@@ -21,6 +21,8 @@ import { sharedChannel } from '../../../common/constants/shared-channel'
|
|
|
21
21
|
import { obj as encodeObj } from '../../../common/url/encode'
|
|
22
22
|
import { warn } from '../../../common/util/console'
|
|
23
23
|
import { globalScope } from '../../../common/constants/runtime'
|
|
24
|
+
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
25
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
24
26
|
|
|
25
27
|
// would be better to get this dynamically in some way
|
|
26
28
|
export const RRWEB_VERSION = '2.0.0-alpha.8'
|
|
@@ -91,7 +93,7 @@ export class Aggregate extends AggregateBase {
|
|
|
91
93
|
if (shouldSetup) {
|
|
92
94
|
// 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.
|
|
93
95
|
this.ee.on(SESSION_EVENTS.RESET, () => {
|
|
94
|
-
this.abort()
|
|
96
|
+
this.abort('Session Reset')
|
|
95
97
|
})
|
|
96
98
|
|
|
97
99
|
// The SessionEntity class can emit a message indicating the session was paused (visibility change). This feature must stop recording if that occurs.
|
|
@@ -176,7 +178,7 @@ export class Aggregate extends AggregateBase {
|
|
|
176
178
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
177
179
|
recorder = (await import(/* webpackChunkName: "recorder" */'rrweb')).record
|
|
178
180
|
} catch (err) {
|
|
179
|
-
return this.abort()
|
|
181
|
+
return this.abort('Recorder failed to import')
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
// FULL mode records AND reports from the beginning, while ERROR mode only records (but does not report).
|
|
@@ -251,7 +253,7 @@ export class Aggregate extends AggregateBase {
|
|
|
251
253
|
onHarvestFinished (result) {
|
|
252
254
|
// The mutual decision for now is to stop recording and clear buffers if ingest is experiencing 429 rate limiting
|
|
253
255
|
if (result.status === 429) {
|
|
254
|
-
this.abort()
|
|
256
|
+
this.abort('429: Too many requests')
|
|
255
257
|
}
|
|
256
258
|
|
|
257
259
|
if (this.blocked) this.scheduler.stopTimer(true)
|
|
@@ -272,7 +274,7 @@ export class Aggregate extends AggregateBase {
|
|
|
272
274
|
startRecording () {
|
|
273
275
|
if (!recorder) {
|
|
274
276
|
warn('Recording library was never imported')
|
|
275
|
-
return this.abort()
|
|
277
|
+
return this.abort('Recorder was never imported')
|
|
276
278
|
}
|
|
277
279
|
this.clearTimestamps()
|
|
278
280
|
// set the fallbacks as early as possible
|
|
@@ -309,7 +311,8 @@ export class Aggregate extends AggregateBase {
|
|
|
309
311
|
// Vortex will block payloads at a certain size, we might as well not send.
|
|
310
312
|
if (payloadSize > MAX_PAYLOAD_SIZE) {
|
|
311
313
|
this.clearBuffer()
|
|
312
|
-
|
|
314
|
+
this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Too-Big/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
315
|
+
return this.abort('Payload too big')
|
|
313
316
|
}
|
|
314
317
|
// Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
|
|
315
318
|
// to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
|
|
@@ -373,7 +376,8 @@ export class Aggregate extends AggregateBase {
|
|
|
373
376
|
}
|
|
374
377
|
|
|
375
378
|
/** Abort the feature, once aborted it will not resume */
|
|
376
|
-
abort () {
|
|
379
|
+
abort (reason) {
|
|
380
|
+
warn(`SR aborted -- ${reason}`)
|
|
377
381
|
this.blocked = true
|
|
378
382
|
this.mode = MODE.OFF
|
|
379
383
|
this.stopRecording()
|
|
@@ -108,6 +108,7 @@ export class InstrumentBase extends FeatureBase {
|
|
|
108
108
|
warn(`Downloading and initializing ${this.featureName} failed...`, e)
|
|
109
109
|
this.abortHandler?.() // undo any important alterations made to the page
|
|
110
110
|
// not supported yet but nice to do: "abort" this agent's EE for this feature specifically
|
|
111
|
+
drain(this.agentIdentifier, this.featureName)
|
|
111
112
|
loadedSuccessfully(false)
|
|
112
113
|
}
|
|
113
114
|
}
|