@newrelic/browser-agent 1.250.0 → 1.251.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/cjs/common/config/state/init.js +0 -2
- 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 -3
- package/dist/cjs/common/harvest/harvest.js +2 -2
- package/dist/cjs/common/harvest/types.js +1 -2
- package/dist/cjs/common/ids/bundle-id.js +1 -2
- package/dist/cjs/common/session/constants.js +7 -13
- package/dist/cjs/common/timer/interaction-timer.js +0 -1
- package/dist/cjs/common/timing/nav-timing.js +1 -2
- 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 +1 -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 +40 -27
- package/dist/cjs/features/session_replay/constants.js +8 -16
- package/dist/cjs/features/session_replay/instrument/index.js +11 -11
- package/dist/cjs/features/session_replay/shared/recorder-events.js +2 -0
- package/dist/cjs/features/session_replay/shared/recorder.js +51 -5
- package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +99 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +0 -2
- 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 +0 -2
- 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 +2 -1
- package/dist/esm/common/timer/interaction-timer.js +0 -1
- 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 +1 -1
- package/dist/esm/features/session_replay/aggregate/index.js +29 -16
- package/dist/esm/features/session_replay/shared/recorder-events.js +2 -0
- package/dist/esm/features/session_replay/shared/recorder.js +51 -5
- package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +93 -0
- package/dist/esm/features/session_trace/aggregate/index.js +0 -2
- 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/features/session_replay/aggregate/index.d.ts +8 -3
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder-events.d.ts +2 -0
- package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts +14 -1
- package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
- 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/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/harvest/harvest-scheduler.js +1 -1
- package/src/common/ids/__mocks__/bundle-id.js +1 -1
- package/src/common/ids/__mocks__/unique-id.js +2 -2
- package/src/features/metrics/aggregate/index.js +1 -1
- package/src/features/session_replay/aggregate/index.js +29 -16
- package/src/features/session_replay/shared/recorder-events.js +2 -0
- package/src/features/session_replay/shared/recorder.js +51 -6
- package/src/features/session_replay/shared/stylesheet-evaluator.js +89 -0
- package/src/loaders/agent-base.js +59 -15
- package/src/loaders/agent.js +0 -38
|
@@ -17,8 +17,8 @@ var _aggregateBase = require("../../utils/aggregate-base");
|
|
|
17
17
|
var _firstContentfulPaint = require("../../../common/vitals/first-contentful-paint");
|
|
18
18
|
var _firstPaint = require("../../../common/vitals/first-paint");
|
|
19
19
|
var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
|
|
20
|
-
function _getRequireWildcardCache(
|
|
21
|
-
function _interopRequireWildcard(
|
|
20
|
+
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); }
|
|
21
|
+
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; }
|
|
22
22
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
23
23
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
24
24
|
constructor(agentIdentifier, aggregator) {
|
|
@@ -5,5 +5,4 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.FEATURE_NAME = void 0;
|
|
7
7
|
var _features = require("../../loaders/features/features");
|
|
8
|
-
const FEATURE_NAME = _features.FEATURE_NAMES.pageViewEvent;
|
|
9
|
-
exports.FEATURE_NAME = FEATURE_NAME;
|
|
8
|
+
const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.pageViewEvent;
|
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Instrument = void 0;
|
|
7
7
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
8
8
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
9
|
-
function _getRequireWildcardCache(
|
|
10
|
-
function _interopRequireWildcard(
|
|
9
|
+
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); }
|
|
10
|
+
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; }
|
|
11
11
|
class Instrument extends _instrumentBase.InstrumentBase {
|
|
12
12
|
static featureName = CONSTANTS.FEATURE_NAME;
|
|
13
13
|
constructor(agentIdentifier, aggregator) {
|
|
@@ -5,5 +5,4 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.FEATURE_NAME = void 0;
|
|
7
7
|
var _features = require("../../loaders/features/features");
|
|
8
|
-
const FEATURE_NAME = _features.FEATURE_NAMES.pageViewTiming;
|
|
9
|
-
exports.FEATURE_NAME = FEATURE_NAME;
|
|
8
|
+
const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.pageViewTiming;
|
|
@@ -20,18 +20,18 @@ var _env = require("../../../common/constants/env.npm");
|
|
|
20
20
|
var _now = require("../../../common/timing/now");
|
|
21
21
|
var _constants3 = require("../../../common/session/constants");
|
|
22
22
|
var _stringify = require("../../../common/util/stringify");
|
|
23
|
-
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
35
|
class Aggregate extends _aggregateBase.AggregateBase {
|
|
36
36
|
static featureName = _constants.FEATURE_NAME;
|
|
37
37
|
// pass the recorder into the aggregator
|
|
@@ -43,8 +43,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
43
43
|
this.initialized = false;
|
|
44
44
|
/** Set once the feature has been "aborted" to prevent other side-effects from continuing */
|
|
45
45
|
this.blocked = false;
|
|
46
|
-
/**
|
|
47
|
-
this.
|
|
46
|
+
/** populated with the gzipper lib async */
|
|
47
|
+
this.gzipper = undefined;
|
|
48
|
+
/** populated with the u8 string lib async */
|
|
49
|
+
this.u8 = undefined;
|
|
48
50
|
/** the mode to start in. Defaults to off */
|
|
49
51
|
const {
|
|
50
52
|
session
|
|
@@ -91,6 +93,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
91
93
|
getPayload: this.prepareHarvest.bind(this),
|
|
92
94
|
raw: true
|
|
93
95
|
}, this);
|
|
96
|
+
if (this.recorder?.getEvents().type === 'preloaded') {
|
|
97
|
+
this.prepUtils().then(() => {
|
|
98
|
+
this.scheduler.runHarvest();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
94
101
|
(0, _registerHandler.registerHandler)('recordReplay', () => {
|
|
95
102
|
// if it has aborted or BCS returned bad entitlements, do not allow
|
|
96
103
|
if (this.blocked || !this.entitled) return;
|
|
@@ -195,24 +202,29 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
195
202
|
// We only report (harvest) in FULL mode
|
|
196
203
|
this.scheduler.startTimer(this.harvestTimeSeconds);
|
|
197
204
|
}
|
|
205
|
+
await this.prepUtils();
|
|
206
|
+
if (!this.recorder.recording) this.recorder.startRecording();
|
|
207
|
+
this.syncWithSessionManager({
|
|
208
|
+
sessionReplayMode: this.mode
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async prepUtils() {
|
|
198
212
|
try {
|
|
199
213
|
// Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
|
|
200
214
|
const {
|
|
201
215
|
gzipSync,
|
|
202
216
|
strToU8
|
|
203
217
|
} = await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "compressor" */'fflate')));
|
|
204
|
-
gzipper = gzipSync;
|
|
205
|
-
u8 = strToU8;
|
|
218
|
+
this.gzipper = gzipSync;
|
|
219
|
+
this.u8 = strToU8;
|
|
206
220
|
} catch (err) {
|
|
207
221
|
// compressor failed to load, but we can still record without compression as a last ditch effort
|
|
208
|
-
this.shouldCompress = false;
|
|
209
222
|
}
|
|
210
|
-
if (!this.recorder.recording) this.recorder.startRecording();
|
|
211
|
-
this.syncWithSessionManager({
|
|
212
|
-
sessionReplayMode: this.mode
|
|
213
|
-
});
|
|
214
223
|
}
|
|
215
224
|
prepareHarvest() {
|
|
225
|
+
let {
|
|
226
|
+
opts
|
|
227
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
216
228
|
if (!this.recorder) return;
|
|
217
229
|
const recorderEvents = this.recorder.getEvents();
|
|
218
230
|
// get the event type and use that to trigger another harvest if needed
|
|
@@ -223,8 +235,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
223
235
|
return;
|
|
224
236
|
}
|
|
225
237
|
let len = 0;
|
|
226
|
-
if (this.
|
|
227
|
-
payload.body = gzipper(u8("[".concat(payload.body.map(e => e.__serialized).join(','), "]")));
|
|
238
|
+
if (!!this.gzipper && !!this.u8) {
|
|
239
|
+
payload.body = this.gzipper(this.u8("[".concat(payload.body.map(e => e.__serialized).join(','), "]")));
|
|
228
240
|
len = payload.body.length;
|
|
229
241
|
this.scheduler.opts.gzip = true;
|
|
230
242
|
} else {
|
|
@@ -250,7 +262,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
250
262
|
sessionReplaySentFirstChunk: true
|
|
251
263
|
});
|
|
252
264
|
this.recorder.clearBuffer();
|
|
253
|
-
if (recorderEvents.type === 'preloaded') this.scheduler.runHarvest();
|
|
265
|
+
if (recorderEvents.type === 'preloaded') this.scheduler.runHarvest(opts);
|
|
254
266
|
return [payload];
|
|
255
267
|
}
|
|
256
268
|
getHarvestContents(recorderEvents) {
|
|
@@ -281,7 +293,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
281
293
|
const relativeNow = (0, _now.now)();
|
|
282
294
|
const firstEventTimestamp = events[0]?.timestamp; // from rrweb node
|
|
283
295
|
const lastEventTimestamp = events[events.length - 1]?.timestamp; // from rrweb node
|
|
284
|
-
const firstTimestamp = firstEventTimestamp || recorderEvents.cycleTimestamp;
|
|
296
|
+
const firstTimestamp = firstEventTimestamp || recorderEvents.cycleTimestamp; // from rrweb node || from when the harvest cycle started
|
|
285
297
|
const lastTimestamp = lastEventTimestamp || agentOffset + relativeNow;
|
|
286
298
|
return {
|
|
287
299
|
qs: {
|
|
@@ -292,7 +304,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
292
304
|
attributes: (0, _encode.obj)({
|
|
293
305
|
// this section of attributes must be controllable and stay below the query param padding limit -- see QUERY_PARAM_PADDING
|
|
294
306
|
// if not, data could be lost to truncation at time of sending, potentially breaking parsing / API behavior in NR1
|
|
295
|
-
...(this.
|
|
307
|
+
...(!!this.gzipper && !!this.u8 && {
|
|
296
308
|
content_encoding: 'gzip'
|
|
297
309
|
}),
|
|
298
310
|
'replay.firstTimestamp': firstTimestamp,
|
|
@@ -309,6 +321,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
309
321
|
hasError: recorderEvents.hasError || false,
|
|
310
322
|
isFirstChunk: agentRuntime.session.state.sessionReplaySentFirstChunk === false,
|
|
311
323
|
decompressedBytes: recorderEvents.payloadBytesEstimation,
|
|
324
|
+
invalidStylesheetsDetected: _stylesheetEvaluator.stylesheetEvaluator.invalidStylesheetsDetected,
|
|
325
|
+
inlinedAllStylesheets: recorderEvents.inlinedAllStylesheets,
|
|
312
326
|
'rrweb.version': _env.RRWEB_VERSION,
|
|
313
327
|
// customer-defined data should go last so that if it exceeds the query param padding limit it will be truncated instead of important attrs
|
|
314
328
|
...(endUserId && {
|
|
@@ -317,7 +331,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
317
331
|
// The Query Param is being arbitrarily limited in length here. It is also applied when estimating the size of the payload in getPayloadSize()
|
|
318
332
|
}, _constants.QUERY_PARAM_PADDING).substring(1) // remove the leading '&'
|
|
319
333
|
},
|
|
320
|
-
|
|
321
334
|
body: events
|
|
322
335
|
};
|
|
323
336
|
}
|
|
@@ -6,11 +6,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.RRWEB_EVENT_TYPES = exports.QUERY_PARAM_PADDING = exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.FEATURE_NAME = exports.CHECKOUT_MS = exports.AVG_COMPRESSION = exports.ABORT_REASONS = void 0;
|
|
7
7
|
var _constants = require("../../common/session/constants");
|
|
8
8
|
var _features = require("../../loaders/features/features");
|
|
9
|
-
const FEATURE_NAME = _features.FEATURE_NAMES.sessionReplay;
|
|
10
|
-
exports.
|
|
11
|
-
const
|
|
12
|
-
exports.AVG_COMPRESSION = AVG_COMPRESSION;
|
|
13
|
-
const RRWEB_EVENT_TYPES = {
|
|
9
|
+
const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.sessionReplay;
|
|
10
|
+
const AVG_COMPRESSION = exports.AVG_COMPRESSION = 0.12;
|
|
11
|
+
const RRWEB_EVENT_TYPES = exports.RRWEB_EVENT_TYPES = {
|
|
14
12
|
DomContentLoaded: 0,
|
|
15
13
|
Load: 1,
|
|
16
14
|
FullSnapshot: 2,
|
|
@@ -19,20 +17,16 @@ const RRWEB_EVENT_TYPES = {
|
|
|
19
17
|
Custom: 5
|
|
20
18
|
};
|
|
21
19
|
/** Vortex caps payload sizes at 1MB */
|
|
22
|
-
exports.
|
|
23
|
-
const MAX_PAYLOAD_SIZE = 1000000;
|
|
20
|
+
const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
|
|
24
21
|
/** Unloading caps around 64kb */
|
|
25
|
-
exports.
|
|
26
|
-
const IDEAL_PAYLOAD_SIZE = 64000;
|
|
22
|
+
const IDEAL_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = 64000;
|
|
27
23
|
/** Interval between forcing new full snapshots -- 15 seconds in error mode (x2), 5 minutes in full mode */
|
|
28
|
-
exports.
|
|
29
|
-
const CHECKOUT_MS = {
|
|
24
|
+
const CHECKOUT_MS = exports.CHECKOUT_MS = {
|
|
30
25
|
[_constants.MODE.ERROR]: 15000,
|
|
31
26
|
[_constants.MODE.FULL]: 300000,
|
|
32
27
|
[_constants.MODE.OFF]: 0
|
|
33
28
|
};
|
|
34
|
-
exports.
|
|
35
|
-
const ABORT_REASONS = {
|
|
29
|
+
const ABORT_REASONS = exports.ABORT_REASONS = {
|
|
36
30
|
RESET: {
|
|
37
31
|
message: 'Session was reset',
|
|
38
32
|
sm: 'Reset'
|
|
@@ -59,6 +53,4 @@ const ABORT_REASONS = {
|
|
|
59
53
|
}
|
|
60
54
|
};
|
|
61
55
|
/** Reserved room for query param attrs */
|
|
62
|
-
exports.
|
|
63
|
-
const QUERY_PARAM_PADDING = 5000;
|
|
64
|
-
exports.QUERY_PARAM_PADDING = QUERY_PARAM_PADDING;
|
|
56
|
+
const QUERY_PARAM_PADDING = exports.QUERY_PARAM_PADDING = 5000;
|
|
@@ -7,17 +7,17 @@ exports.Instrument = void 0;
|
|
|
7
7
|
var _constants = require("../../../common/session/constants");
|
|
8
8
|
var _instrumentBase = require("../../utils/instrument-base");
|
|
9
9
|
var _constants2 = require("../constants");
|
|
10
|
-
function _getRequireWildcardCache(
|
|
11
|
-
function _interopRequireWildcard(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
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); }
|
|
11
|
+
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; } /*
|
|
12
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
14
|
+
*/ /**
|
|
15
|
+
* @file Primes the Session Replay feature for lazy loading.
|
|
16
|
+
*
|
|
17
|
+
* NOTE: This code is under development and dormant. It will not download to instrumented pages or record any data.
|
|
18
|
+
* It is not production ready, and is not intended to be imported or implemented in any build of the browser agent until
|
|
19
|
+
* functionality is validated and a full user experience is curated.
|
|
20
|
+
*/
|
|
21
21
|
class Instrument extends _instrumentBase.InstrumentBase {
|
|
22
22
|
static featureName = _constants2.FEATURE_NAME;
|
|
23
23
|
constructor(agentIdentifier, aggregator) {
|
|
@@ -23,6 +23,8 @@ class RecorderEvents {
|
|
|
23
23
|
this.hasMeta = false;
|
|
24
24
|
/** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
|
|
25
25
|
this.hasError = false;
|
|
26
|
+
/** Payload metadata -- Denotes whether all stylesheet elements were able to be inlined */
|
|
27
|
+
this.inlinedAllStylesheets = true;
|
|
26
28
|
}
|
|
27
29
|
add(event) {
|
|
28
30
|
this.events.push(event);
|
|
@@ -10,6 +10,10 @@ var _constants = require("../constants");
|
|
|
10
10
|
var _config = require("../../../common/config/config");
|
|
11
11
|
var _recorderEvents = require("./recorder-events");
|
|
12
12
|
var _constants2 = require("../../../common/session/constants");
|
|
13
|
+
var _stylesheetEvaluator = require("./stylesheet-evaluator");
|
|
14
|
+
var _handle = require("../../../common/event-emitter/handle");
|
|
15
|
+
var _constants3 = require("../../metrics/constants");
|
|
16
|
+
var _features = require("../../../loaders/features/features");
|
|
13
17
|
class Recorder {
|
|
14
18
|
/** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
|
|
15
19
|
#events = new _recorderEvents.RecorderEvents();
|
|
@@ -17,14 +21,21 @@ class Recorder {
|
|
|
17
21
|
#backloggedEvents = new _recorderEvents.RecorderEvents();
|
|
18
22
|
/** array of recorder events -- Will be filled only if forced harvest was triggered and harvester does not exist */
|
|
19
23
|
#preloaded = [new _recorderEvents.RecorderEvents()];
|
|
24
|
+
/** flag that if true, blocks events from being "stored". Only set to true when a full snapshot has incomplete nodes (only stylesheets ATM) */
|
|
25
|
+
#fixing = false;
|
|
20
26
|
constructor(parent) {
|
|
21
27
|
/** True when actively recording, false when paused or stopped */
|
|
22
28
|
this.recording = false;
|
|
29
|
+
/** The pointer to the current bucket holding rrweb events */
|
|
23
30
|
this.currentBufferTarget = this.#events;
|
|
24
31
|
/** 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 */
|
|
25
32
|
this.lastMeta = false;
|
|
33
|
+
/** The parent class that instantiated the recorder */
|
|
26
34
|
this.parent = parent;
|
|
27
|
-
|
|
35
|
+
/** Config to inform to inline stylesheet contents (true default) */
|
|
36
|
+
this.shouldInlineStylesheets = (0, _config.getConfigurationValue)(this.parent.agentIdentifier, 'session_replay.inline_stylesheet');
|
|
37
|
+
/** A flag that can be set to false by failing conversions to stop the fetching process */
|
|
38
|
+
this.shouldFix = this.shouldInlineStylesheets;
|
|
28
39
|
/** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
|
|
29
40
|
this.stopRecording = () => {/* no-op until set by rrweb initializer */};
|
|
30
41
|
}
|
|
@@ -40,7 +51,8 @@ class Recorder {
|
|
|
40
51
|
payloadBytesEstimation: this.#backloggedEvents.payloadBytesEstimation + this.#events.payloadBytesEstimation,
|
|
41
52
|
hasError: this.#backloggedEvents.hasError || this.#events.hasError,
|
|
42
53
|
hasMeta: this.#backloggedEvents.hasMeta || this.#events.hasMeta,
|
|
43
|
-
hasSnapshot: this.#backloggedEvents.hasSnapshot || this.#events.hasSnapshot
|
|
54
|
+
hasSnapshot: this.#backloggedEvents.hasSnapshot || this.#events.hasSnapshot,
|
|
55
|
+
inlinedAllStylesheets: !!this.#backloggedEvents.events.length && this.#backloggedEvents.inlinedAllStylesheets || this.#events.inlinedAllStylesheets
|
|
44
56
|
};
|
|
45
57
|
}
|
|
46
58
|
|
|
@@ -68,7 +80,7 @@ class Recorder {
|
|
|
68
80
|
// set up rrweb configurations for maximum privacy --
|
|
69
81
|
// https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
|
|
70
82
|
const stop = (0, _rrweb.record)({
|
|
71
|
-
emit: this.
|
|
83
|
+
emit: this.audit.bind(this),
|
|
72
84
|
blockClass: block_class,
|
|
73
85
|
ignoreClass: ignore_class,
|
|
74
86
|
maskTextClass: mask_text_class,
|
|
@@ -87,10 +99,44 @@ class Recorder {
|
|
|
87
99
|
};
|
|
88
100
|
}
|
|
89
101
|
|
|
102
|
+
/**
|
|
103
|
+
* audit - Checks if the event node payload is missing certain attributes
|
|
104
|
+
* will forward on to the "store" method if nothing needs async fixing
|
|
105
|
+
* @param {*} event - An RRWEB event node
|
|
106
|
+
* @param {*} isCheckout - Flag indicating if the payload was triggered as a checkout
|
|
107
|
+
*/
|
|
108
|
+
audit(event, isCheckout) {
|
|
109
|
+
/** only run the audit if inline_stylesheets is configured as on (default behavior) */
|
|
110
|
+
if (this.shouldInlineStylesheets === false || !this.shouldFix) {
|
|
111
|
+
this.currentBufferTarget.inlinedAllStylesheets = false;
|
|
112
|
+
return this.store(event, isCheckout);
|
|
113
|
+
}
|
|
114
|
+
/** An count of stylesheet objects that were blocked from accessing contents via JS */
|
|
115
|
+
const incompletes = _stylesheetEvaluator.stylesheetEvaluator.evaluate();
|
|
116
|
+
/** Only stop ignoring data if already ignoring and a new valid snapshap is taking place (0 incompletes and we get a meta node for the snap) */
|
|
117
|
+
if (!incompletes && this.#fixing && event.type === _constants.RRWEB_EVENT_TYPES.Meta) this.#fixing = false;
|
|
118
|
+
if (incompletes) {
|
|
119
|
+
(0, _handle.handle)(_constants3.SUPPORTABILITY_METRIC_CHANNEL, ['SessionReplay/Payload/Missing-Inline-Css', incompletes], undefined, _features.FEATURE_NAMES.metrics, this.parent.ee);
|
|
120
|
+
/** wait for the evaluator to download/replace the incompletes' src code and then take a new snap */
|
|
121
|
+
_stylesheetEvaluator.stylesheetEvaluator.fix().then(failedToFix => {
|
|
122
|
+
if (failedToFix) {
|
|
123
|
+
this.currentBufferTarget.inlinedAllStylesheets = false;
|
|
124
|
+
this.shouldFix = false;
|
|
125
|
+
}
|
|
126
|
+
this.takeFullSnapshot();
|
|
127
|
+
});
|
|
128
|
+
/** Only start ignoring data if got a faulty snapshot */
|
|
129
|
+
if (event.type === _constants.RRWEB_EVENT_TYPES.FullSnapshot || event.type === _constants.RRWEB_EVENT_TYPES.Meta) this.#fixing = true;
|
|
130
|
+
}
|
|
131
|
+
/** Only store the data if not being "fixed" (full snapshots that have broken css) */
|
|
132
|
+
if (!this.#fixing) this.store(event, isCheckout);
|
|
133
|
+
}
|
|
134
|
+
|
|
90
135
|
/** Store a payload in the buffer (this.#events). This should be the callback to the recording lib noticing a mutation */
|
|
91
136
|
store(event, isCheckout) {
|
|
137
|
+
if (!event) return;
|
|
92
138
|
event.__serialized = (0, _stringify.stringify)(event);
|
|
93
|
-
if (!this.parent.scheduler) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
|
|
139
|
+
if (!this.parent.scheduler && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
|
|
94
140
|
if (this.parent.blocked) return;
|
|
95
141
|
const eventBytes = event.__serialized.length;
|
|
96
142
|
/** The estimated size of the payload after compression */
|
|
@@ -148,7 +194,7 @@ class Recorder {
|
|
|
148
194
|
* https://staging.onenr.io/037jbJWxbjy
|
|
149
195
|
* */
|
|
150
196
|
estimateCompression(data) {
|
|
151
|
-
if (this.
|
|
197
|
+
if (!!this.parent.gzipper && !!this.parent.u8) return data * _constants.AVG_COMPRESSION;
|
|
152
198
|
return data;
|
|
153
199
|
}
|
|
154
200
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.stylesheetEvaluator = void 0;
|
|
7
|
+
var _config = require("../../../common/config/config");
|
|
8
|
+
var _runtime = require("../../../common/constants/runtime");
|
|
9
|
+
class StylesheetEvaluator {
|
|
10
|
+
#evaluated = new WeakSet();
|
|
11
|
+
#fetchProms = [];
|
|
12
|
+
/**
|
|
13
|
+
* Flipped to true if stylesheets that cannot be natively inlined are detected by the stylesheetEvaluator class
|
|
14
|
+
* Used at harvest time to denote that all subsequent payloads are subject to this and customers should be advised to handle crossorigin decoration
|
|
15
|
+
* */
|
|
16
|
+
invalidStylesheetsDetected = false;
|
|
17
|
+
failedToFix = false;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* this works by checking (only ever once) each cssRules obj in the style sheets array. The try/catch will catch an error if the cssRules obj blocks access, triggering the module to try to "fix" the asset`. Returns the count of incomplete assets discovered.
|
|
21
|
+
* @returns {Number}
|
|
22
|
+
*/
|
|
23
|
+
evaluate() {
|
|
24
|
+
let incompletes = 0;
|
|
25
|
+
if (_runtime.isBrowserScope) {
|
|
26
|
+
for (let i = 0; i < Object.keys(document.styleSheets).length; i++) {
|
|
27
|
+
const ss = document.styleSheets[i];
|
|
28
|
+
if (!this.#evaluated.has(ss)) {
|
|
29
|
+
this.#evaluated.add(ss);
|
|
30
|
+
try {
|
|
31
|
+
// eslint-disable-next-line
|
|
32
|
+
const temp = ss.cssRules;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
incompletes++;
|
|
35
|
+
this.#fetchProms.push(this.#fetchAndOverride(document.styleSheets[i], ss.href));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (incompletes) this.invalidStylesheetsDetected = true;
|
|
41
|
+
return incompletes;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolves promise once all stylesheets have been fetched and overridden
|
|
46
|
+
* @returns {Promise}
|
|
47
|
+
*/
|
|
48
|
+
async fix() {
|
|
49
|
+
await Promise.all(this.#fetchProms);
|
|
50
|
+
this.#fetchProms = [];
|
|
51
|
+
const failedToFix = this.failedToFix;
|
|
52
|
+
this.failedToFix = false;
|
|
53
|
+
return failedToFix;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Fetches stylesheet contents and overrides the target getters
|
|
58
|
+
* @param {*} target - The stylesheet object target - ex. document.styleSheets[0]
|
|
59
|
+
* @param {*} href - The asset href to fetch
|
|
60
|
+
* @returns {Promise}
|
|
61
|
+
*/
|
|
62
|
+
async #fetchAndOverride(target, href) {
|
|
63
|
+
try {
|
|
64
|
+
const stylesheetContents = await _config.originals.FETCH.bind(window)(href);
|
|
65
|
+
if (!stylesheetContents.ok) {
|
|
66
|
+
this.failedToFix = true;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const stylesheetText = await stylesheetContents.text();
|
|
70
|
+
try {
|
|
71
|
+
const cssSheet = new CSSStyleSheet();
|
|
72
|
+
await cssSheet.replace(stylesheetText);
|
|
73
|
+
Object.defineProperty(target, 'cssRules', {
|
|
74
|
+
get() {
|
|
75
|
+
return cssSheet.cssRules;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
Object.defineProperty(target, 'rules', {
|
|
79
|
+
get() {
|
|
80
|
+
return cssSheet.rules;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
} catch (err) {
|
|
84
|
+
// cant make new dynamic stylesheets, browser likely doesn't support `.replace()`...
|
|
85
|
+
// this is appended in prep of forking rrweb
|
|
86
|
+
Object.defineProperty(target, 'cssText', {
|
|
87
|
+
get() {
|
|
88
|
+
return stylesheetText;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
this.failedToFix = true;
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
// failed to fetch
|
|
95
|
+
this.failedToFix = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const stylesheetEvaluator = exports.stylesheetEvaluator = new StylesheetEvaluator();
|
|
@@ -251,7 +251,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
251
251
|
}); // sends first stn harvest immediately
|
|
252
252
|
startupBuffer.decide(true); // signal to ALLOW & process data in EE's buffer into internal nodes queued for next harvest
|
|
253
253
|
}
|
|
254
|
-
|
|
255
254
|
#onHarvestFinished(result) {
|
|
256
255
|
if (result.sent && result.responseText && !this.ptid) {
|
|
257
256
|
// continue interval harvest only if ptid was returned by server on the first
|
|
@@ -290,7 +289,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
290
289
|
if (currentMode === _constants2.MODE.OFF && Object.keys(this.trace).length === 0) return;
|
|
291
290
|
if (currentMode === _constants2.MODE.ERROR) return; // Trace in this mode should never be harvesting, even on unload
|
|
292
291
|
}
|
|
293
|
-
|
|
294
292
|
return this.takeSTNs(options.retry);
|
|
295
293
|
}
|
|
296
294
|
|
|
@@ -5,19 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.START = exports.RESOURCE = exports.PUSH_STATE = exports.FN_START = exports.FN_END = exports.FEATURE_NAME = exports.END = exports.BST_RESOURCE = void 0;
|
|
7
7
|
var _features = require("../../loaders/features/features");
|
|
8
|
-
const FEATURE_NAME = _features.FEATURE_NAMES.sessionTrace;
|
|
9
|
-
exports.
|
|
10
|
-
const
|
|
11
|
-
exports.
|
|
12
|
-
const
|
|
13
|
-
exports.
|
|
14
|
-
const
|
|
15
|
-
exports.
|
|
16
|
-
const END = '-end';
|
|
17
|
-
exports.END = END;
|
|
18
|
-
const FN_START = 'fn' + START;
|
|
19
|
-
exports.FN_START = FN_START;
|
|
20
|
-
const FN_END = 'fn' + END;
|
|
21
|
-
exports.FN_END = FN_END;
|
|
22
|
-
const PUSH_STATE = 'pushState';
|
|
23
|
-
exports.PUSH_STATE = PUSH_STATE;
|
|
8
|
+
const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.sessionTrace;
|
|
9
|
+
const BST_RESOURCE = exports.BST_RESOURCE = 'bstResource';
|
|
10
|
+
const RESOURCE = exports.RESOURCE = 'resource';
|
|
11
|
+
const START = exports.START = '-start';
|
|
12
|
+
const END = exports.END = '-end';
|
|
13
|
+
const FN_START = exports.FN_START = 'fn' + START;
|
|
14
|
+
const FN_END = exports.FN_END = 'fn' + END;
|
|
15
|
+
const PUSH_STATE = exports.PUSH_STATE = 'pushState';
|
|
@@ -11,8 +11,8 @@ var _instrumentBase = require("../../utils/instrument-base");
|
|
|
11
11
|
var CONSTANTS = _interopRequireWildcard(require("../constants"));
|
|
12
12
|
var _features = require("../../../loaders/features/features");
|
|
13
13
|
var _runtime = require("../../../common/constants/runtime");
|
|
14
|
-
function _getRequireWildcardCache(
|
|
15
|
-
function _interopRequireWildcard(
|
|
14
|
+
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); }
|
|
15
|
+
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; }
|
|
16
16
|
/*
|
|
17
17
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
18
18
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -25,8 +25,8 @@ var _bundleId = require("../../../common/ids/bundle-id");
|
|
|
25
25
|
var _runtime = require("../../../common/constants/runtime");
|
|
26
26
|
var _handle = require("../../../common/event-emitter/handle");
|
|
27
27
|
var _constants2 = require("../../metrics/constants");
|
|
28
|
-
function _getRequireWildcardCache(
|
|
29
|
-
function _interopRequireWildcard(
|
|
28
|
+
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); }
|
|
29
|
+
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; }
|
|
30
30
|
/*
|
|
31
31
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
32
32
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -16,7 +16,6 @@ function InteractionNode(interaction, parent, type, timestamp) {
|
|
|
16
16
|
value: interaction,
|
|
17
17
|
writable: true // enumerable: false -- by default, which hides this prop from obj (iterations)
|
|
18
18
|
});
|
|
19
|
-
|
|
20
19
|
this.parent = parent;
|
|
21
20
|
this.id = ++lastId;
|
|
22
21
|
this.type = type;
|