@newrelic/browser-agent 1.243.0 → 1.244.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/common/config/state/init.js +6 -0
  3. package/dist/cjs/common/constants/env.cdn.js +9 -3
  4. package/dist/cjs/common/constants/env.js +8 -2
  5. package/dist/cjs/common/constants/env.npm.js +9 -3
  6. package/dist/cjs/common/util/console.js +2 -2
  7. package/dist/cjs/features/session_replay/aggregate/index.js +41 -25
  8. package/dist/cjs/features/spa/aggregate/index.js +3 -2
  9. package/dist/cjs/loaders/agent-base.js +3 -3
  10. package/dist/cjs/loaders/agent.js +1 -1
  11. package/dist/esm/common/config/state/init.js +6 -0
  12. package/dist/esm/common/constants/env.cdn.js +7 -2
  13. package/dist/esm/common/constants/env.js +6 -1
  14. package/dist/esm/common/constants/env.npm.js +7 -2
  15. package/dist/esm/common/util/console.js +2 -2
  16. package/dist/esm/features/session_replay/aggregate/index.js +39 -23
  17. package/dist/esm/features/spa/aggregate/index.js +3 -2
  18. package/dist/esm/loaders/agent-base.js +3 -3
  19. package/dist/esm/loaders/agent.js +1 -1
  20. package/dist/types/common/config/state/init.d.ts.map +1 -1
  21. package/dist/types/common/constants/env.cdn.d.ts +4 -0
  22. package/dist/types/common/constants/env.cdn.d.ts.map +1 -1
  23. package/dist/types/common/constants/env.d.ts +4 -0
  24. package/dist/types/common/constants/env.d.ts.map +1 -1
  25. package/dist/types/common/constants/env.npm.d.ts +4 -0
  26. package/dist/types/common/constants/env.npm.d.ts.map +1 -1
  27. package/dist/types/common/util/console.d.ts +3 -3
  28. package/dist/types/common/util/console.d.ts.map +1 -1
  29. package/dist/types/features/session_replay/aggregate/index.d.ts +2 -1
  30. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  31. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  32. package/dist/types/loaders/agent-base.d.ts +2 -2
  33. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  34. package/package.json +2 -2
  35. package/src/common/config/state/init.js +3 -0
  36. package/src/common/constants/__mocks__/env.js +1 -0
  37. package/src/common/constants/env.cdn.js +5 -0
  38. package/src/common/constants/env.js +5 -0
  39. package/src/common/constants/env.npm.js +5 -0
  40. package/src/common/util/console.js +2 -2
  41. package/src/features/session_replay/aggregate/index.js +38 -24
  42. package/src/features/spa/aggregate/index.js +3 -2
  43. package/src/loaders/agent-base.js +3 -3
  44. package/src/loaders/agent.js +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.244.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.243.1...v1.244.0) (2023-10-10)
7
+
8
+
9
+ ### Features
10
+
11
+ * Add Session Replay configurations to collect inline assets ([#763](https://github.com/newrelic/newrelic-browser-agent/issues/763)) ([cef08dd](https://github.com/newrelic/newrelic-browser-agent/commit/cef08dd3f0cd99735dbc719e3c075fe83bbc6219))
12
+ * Bump rrweb to 2.0.0.11 and make constant dynamic at build time ([#770](https://github.com/newrelic/newrelic-browser-agent/issues/770)) ([9ea84cf](https://github.com/newrelic/newrelic-browser-agent/commit/9ea84cf247b31af544e2ea7ed0873241ff82eebc))
13
+ * Ensure 15 second minimum error buffer when possible ([#759](https://github.com/newrelic/newrelic-browser-agent/issues/759)) ([8506803](https://github.com/newrelic/newrelic-browser-agent/commit/8506803eaba27b7c603432f8ba0c909b677d3c3b))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * Fix invalid timestamps ([#771](https://github.com/newrelic/newrelic-browser-agent/issues/771)) ([bc5a57c](https://github.com/newrelic/newrelic-browser-agent/commit/bc5a57c8c42c62c311e24b77f00dc1225a3b5873))
19
+ * Isolate browser interaction node ([#758](https://github.com/newrelic/newrelic-browser-agent/issues/758)) ([b9e8277](https://github.com/newrelic/newrelic-browser-agent/commit/b9e82773c67d710e0f6dc1f892908afc8be004cd))
20
+
21
+ ## [1.243.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.243.0...v1.243.1) (2023-10-04)
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * Improve Session Replay abort metric reliability ([#754](https://github.com/newrelic/newrelic-browser-agent/issues/754)) ([14f08ac](https://github.com/newrelic/newrelic-browser-agent/commit/14f08aca8bf1a610984fc2303604a04910f07db6))
27
+
6
28
  ## [1.243.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.242.0...v1.243.0) (2023-10-04)
7
29
 
8
30
 
@@ -110,6 +110,12 @@ const model = () => {
110
110
  // float from 0 - 100
111
111
  error_sampling_rate: 50,
112
112
  // float from 0 - 100
113
+ collect_fonts: false,
114
+ // serialize fonts for collection without public asset url, this is currently broken in RRWeb -- https://github.com/rrweb-io/rrweb/issues/1304. When fixed, revisit with test cases
115
+ inline_images: false,
116
+ // serialize images for collection without public asset url
117
+ inline_stylesheet: true,
118
+ // serialize css for collection without public asset url
113
119
  // recording config settings
114
120
  mask_all_inputs: true,
115
121
  // this has a getter/setter to facilitate validation of the selectors
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
6
+ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
7
7
  /**
8
8
  * @file This file exposes CDN build environment variables. These variables will
9
9
  * be overridden with babel.
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.243.0";
15
+ const VERSION = "1.244.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -26,4 +26,10 @@ const BUILD_ENV = "CDN";
26
26
  */
27
27
  exports.BUILD_ENV = BUILD_ENV;
28
28
  const DIST_METHOD = 'CDN';
29
- exports.DIST_METHOD = DIST_METHOD;
29
+
30
+ /**
31
+ * Exposes the lib version of rrweb
32
+ */
33
+ exports.DIST_METHOD = DIST_METHOD;
34
+ const RRWEB_VERSION = "2.0.0-alpha.11";
35
+ exports.RRWEB_VERSION = RRWEB_VERSION;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
6
+ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
7
7
  var _package = _interopRequireDefault(require("../../../package.json"));
8
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
9
  /**
@@ -29,4 +29,10 @@ const BUILD_ENV = 'NPM';
29
29
  */
30
30
  exports.BUILD_ENV = BUILD_ENV;
31
31
  const DIST_METHOD = 'NPM';
32
- exports.DIST_METHOD = DIST_METHOD;
32
+
33
+ /**
34
+ * Exposes the lib version of rrweb
35
+ */
36
+ exports.DIST_METHOD = DIST_METHOD;
37
+ const RRWEB_VERSION = _package.default.dependencies.rrweb;
38
+ exports.RRWEB_VERSION = RRWEB_VERSION;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
6
+ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
7
7
  /**
8
8
  * @file This file exposes NPM build environment variables. These variables will
9
9
  * be overridden with babel.
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.243.0";
15
+ const VERSION = "1.244.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -27,4 +27,10 @@ const BUILD_ENV = 'NPM';
27
27
  */
28
28
  exports.BUILD_ENV = BUILD_ENV;
29
29
  const DIST_METHOD = 'NPM';
30
- exports.DIST_METHOD = DIST_METHOD;
30
+
31
+ /**
32
+ * Exposes the lib version of rrweb
33
+ */
34
+ exports.DIST_METHOD = DIST_METHOD;
35
+ const RRWEB_VERSION = "2.0.0-alpha.11";
36
+ exports.RRWEB_VERSION = RRWEB_VERSION;
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.warn = warn;
7
7
  /**
8
8
  * A helper method to warn to the console with New Relic: decoration
9
- * @param {string} message - The primary message to warn
10
- * @param {*} secondary - Secondary data to include, usually an error or object
9
+ * @param {string} message The primary message to warn
10
+ * @param {*} [secondary] Secondary data to include, usually an error or object
11
11
  * @returns
12
12
  */
13
13
  function warn(message, secondary) {
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.RRWEB_VERSION = exports.RRWEB_EVENT_TYPES = exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.Aggregate = exports.AVG_COMPRESSION = void 0;
6
+ exports.RRWEB_EVENT_TYPES = exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.Aggregate = exports.AVG_COMPRESSION = void 0;
7
7
  var _registerHandler = require("../../../common/event-emitter/register-handler");
8
8
  var _harvestScheduler = require("../../../common/harvest/harvest-scheduler");
9
9
  var _constants = require("../constants");
@@ -16,6 +16,9 @@ var _encode = require("../../../common/url/encode");
16
16
  var _console = require("../../../common/util/console");
17
17
  var _runtime = require("../../../common/constants/runtime");
18
18
  var _constants2 = require("../../metrics/constants");
19
+ var _handle = require("../../../common/event-emitter/handle");
20
+ var _features = require("../../../loaders/features/features");
21
+ var _env = require("../../../common/constants/env.npm");
19
22
  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); }
20
23
  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; } /*
21
24
  * Copyright 2023 New Relic Corporation. All rights reserved.
@@ -27,9 +30,6 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
27
30
  * It is not production ready, and is not intended to be imported or implemented in any build of the browser agent until
28
31
  * functionality is validated and a full user experience is curated.
29
32
  */
30
- // would be better to get this dynamically in some way
31
- const RRWEB_VERSION = '2.0.0-alpha.8';
32
- exports.RRWEB_VERSION = RRWEB_VERSION;
33
33
  const AVG_COMPRESSION = 0.12;
34
34
  exports.AVG_COMPRESSION = AVG_COMPRESSION;
35
35
  const RRWEB_EVENT_TYPES = {
@@ -57,6 +57,10 @@ const ABORT_REASONS = {
57
57
  TOO_BIG: {
58
58
  message: 'Payload was too large',
59
59
  sm: 'Too-Big'
60
+ },
61
+ CROSS_TAB: {
62
+ message: 'Session Entity was set to OFF on another tab',
63
+ sm: 'Cross-Tab'
60
64
  }
61
65
  };
62
66
  let recorder, gzipper, u8;
@@ -66,10 +70,10 @@ const MAX_PAYLOAD_SIZE = 1000000;
66
70
  /** Unloading caps around 64kb */
67
71
  exports.MAX_PAYLOAD_SIZE = MAX_PAYLOAD_SIZE;
68
72
  const IDEAL_PAYLOAD_SIZE = 64000;
69
- /** Interval between forcing new full snapshots -- 30 seconds in error mode, 5 minutes in full mode */
73
+ /** Interval between forcing new full snapshots -- 15 seconds in error mode (x2), 5 minutes in full mode */
70
74
  exports.IDEAL_PAYLOAD_SIZE = IDEAL_PAYLOAD_SIZE;
71
75
  const CHECKOUT_MS = {
72
- [_sessionEntity.MODE.ERROR]: 30000,
76
+ [_sessionEntity.MODE.ERROR]: 15000,
73
77
  [_sessionEntity.MODE.FULL]: 300000,
74
78
  [_sessionEntity.MODE.OFF]: 0
75
79
  };
@@ -79,6 +83,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
79
83
  super(agentIdentifier, aggregator, _constants.FEATURE_NAME);
80
84
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
81
85
  this.events = [];
86
+ /** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
87
+ this.backloggedEvents = [];
82
88
  /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
83
89
  this.harvestTimeSeconds = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay.harvestTimeSeconds') || 60;
84
90
  /** Set once the recorder has fully initialized after flag checks and sampling */
@@ -140,7 +146,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
140
146
  });
141
147
  this.ee.on(_sessionEntity.SESSION_EVENTS.UPDATE, (type, data) => {
142
148
  if (!this.initialized || this.blocked || type !== _sessionEntity.SESSION_EVENT_TYPES.CROSS_TAB) return;
143
- if (this.mode !== _sessionEntity.MODE.OFF && data.sessionReplay === _sessionEntity.MODE.OFF) this.abort('Session Entity was set to OFF on another tab');
149
+ if (this.mode !== _sessionEntity.MODE.OFF && data.sessionReplay === _sessionEntity.MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB);
144
150
  this.mode = data.sessionReplay;
145
151
  });
146
152
 
@@ -248,6 +254,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
248
254
  prepareHarvest() {
249
255
  if (this.events.length === 0 || this.mode !== _sessionEntity.MODE.FULL && !this.blocked) return;
250
256
  const payload = this.getHarvestContents();
257
+ if (!payload.body.length) {
258
+ this.clearBuffer();
259
+ return;
260
+ }
251
261
  if (this.shouldCompress) {
252
262
  payload.body = gzipper(u8((0, _stringify.stringify)(payload.body)));
253
263
  this.scheduler.opts.gzip = true;
@@ -267,6 +277,16 @@ class Aggregate extends _aggregateBase.AggregateBase {
267
277
  getHarvestContents() {
268
278
  const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
269
279
  const info = (0, _config.getInfo)(this.agentIdentifier);
280
+ if (this.backloggedEvents.length) this.events = [...this.backloggedEvents, ...this.events];
281
+
282
+ // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
283
+ // we will manually inject it if this happens
284
+ const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot;
285
+ if (payloadStartsWithFullSnapshot && !!this.lastMeta) {
286
+ this.hasMeta = true;
287
+ this.events.unshift(this.lastMeta); // --> pushed the meta from a previous payload into newer payload... but it still has old timestamps
288
+ this.lastMeta = undefined;
289
+ }
270
290
 
271
291
  // do not let the last node be a meta node, since this NEEDS to precede a snapshot
272
292
  // we will manually inject it later if we find a payload that is missing a meta node
@@ -276,16 +296,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
276
296
  this.events = this.events.slice(0, this.events.length - 1);
277
297
  this.hasMeta = !!this.events.find(x => x.type === RRWEB_EVENT_TYPES.Meta);
278
298
  }
279
-
280
- // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
281
- // we will manually inject it if this happens
282
- const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot;
283
- if (payloadStartsWithFullSnapshot) {
284
- this.hasMeta = true;
285
- this.events.unshift(this.lastMeta);
286
- }
287
- const firstEventTimestamp = this.events[0]?.timestamp;
288
- const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp;
299
+ const firstEventTimestamp = this.events[0]?.timestamp; // from rrweb node
300
+ const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp; // from rrweb node
289
301
  const firstTimestamp = firstEventTimestamp || this.cycleTimestamp;
290
302
  const lastTimestamp = lastEventTimestamp || (0, _config.getRuntime)(this.agentIdentifier).offset + _runtime.globalScope.performance.now();
291
303
  return {
@@ -309,7 +321,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
309
321
  hasError: this.hasError,
310
322
  isFirstChunk: agentRuntime.session.state.sessionReplaySentFirstChunk === false,
311
323
  decompressedBytes: this.payloadBytesEstimation,
312
- 'nr.rrweb.version': RRWEB_VERSION
324
+ 'nr.rrweb.version': _env.RRWEB_VERSION
313
325
  }, MAX_PAYLOAD_SIZE - this.payloadBytesEstimation).substring(1) // remove the leading '&'
314
326
  },
315
327
 
@@ -326,6 +338,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
326
338
 
327
339
  /** Clears the buffer (this.events), and resets all payload metadata properties */
328
340
  clearBuffer() {
341
+ if (this.mode === _sessionEntity.MODE.ERROR) this.backloggedEvents = this.events;else this.backloggedEvents = [];
329
342
  this.events = [];
330
343
  this.hasSnapshot = false;
331
344
  this.hasMeta = false;
@@ -340,9 +353,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
340
353
  (0, _console.warn)('Recording library was never imported');
341
354
  return this.abort(ABORT_REASONS.IMPORT);
342
355
  }
343
- this.clearTimestamps();
344
- // set the fallbacks as early as possible
345
- this.setTimestamps();
346
356
  this.recording = true;
347
357
  const {
348
358
  block_class,
@@ -351,7 +361,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
351
361
  block_selector,
352
362
  mask_input_options,
353
363
  mask_text_selector,
354
- mask_all_inputs
364
+ mask_all_inputs,
365
+ inline_images,
366
+ inline_stylesheet,
367
+ collect_fonts
355
368
  } = (0, _config.getConfigurationValue)(this.agentIdentifier, 'session_replay');
356
369
  // set up rrweb configurations for maximum privacy --
357
370
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
@@ -364,6 +377,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
364
377
  maskInputOptions: mask_input_options,
365
378
  maskTextSelector: mask_text_selector,
366
379
  maskAllInputs: mask_all_inputs,
380
+ inlineImages: inline_images,
381
+ inlineStylesheet: inline_stylesheet,
382
+ collectFonts: collect_fonts,
367
383
  checkoutEveryNms: CHECKOUT_MS[this.mode]
368
384
  });
369
385
  this.stopRecording = () => {
@@ -387,7 +403,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
387
403
  // Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
388
404
  // to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
389
405
  // each time we see a new checkout, we can drop the old data.
390
- if (this.mode === _sessionEntity.MODE.ERROR && isCheckout) {
406
+ // we need to check for meta because rrweb will flag it as checkout twice, once for meta, then once for snapshot
407
+ if (this.mode === _sessionEntity.MODE.ERROR && isCheckout && event.type === RRWEB_EVENT_TYPES.Meta) {
391
408
  // we are still waiting for an error to throw, so keep wiping the buffer over time
392
409
  this.clearBuffer();
393
410
  }
@@ -395,7 +412,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
395
412
  // meta event
396
413
  if (event.type === RRWEB_EVENT_TYPES.Meta) {
397
414
  this.hasMeta = true;
398
- this.lastMeta = event;
399
415
  }
400
416
  // snapshot event
401
417
  if (event.type === RRWEB_EVENT_TYPES.FullSnapshot) {
@@ -436,7 +452,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
436
452
  abort() {
437
453
  let reason = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
438
454
  (0, _console.warn)("SR aborted -- ".concat(reason.message));
439
- this.ee.emit(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(ABORT_REASONS[reason.sm])]);
455
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(reason.sm)], undefined, _features.FEATURE_NAMES.metrics, this.ee);
440
456
  this.blocked = true;
441
457
  this.mode = _sessionEntity.MODE.OFF;
442
458
  this.stopRecording();
@@ -21,6 +21,7 @@ var _features = require("../../../loaders/features/features");
21
21
  var _aggregateBase = require("../../utils/aggregate-base");
22
22
  var _firstContentfulPaint = require("../../../common/vitals/first-contentful-paint");
23
23
  var _firstPaint = require("../../../common/vitals/first-paint");
24
+ var _bundleId = require("../../../common/ids/bundle-id");
24
25
  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); }
25
26
  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; }
26
27
  /*
@@ -182,7 +183,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
182
183
  (0, _registerHandler.registerHandler)(FN_START, function (args, eventSource) {
183
184
  var ev = args[0];
184
185
  var evName = ev.type;
185
- var eventNode = ev.__nrNode;
186
+ var eventNode = ev["__nrNode:".concat(_bundleId.bundleId)];
186
187
  if (!state.pageLoaded && evName === 'load' && eventSource === window) {
187
188
  state.pageLoaded = true;
188
189
  // set to null so prevNode is set correctly
@@ -226,7 +227,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
226
227
  }
227
228
  }
228
229
  }
229
- ev.__nrNode = state.currentNode;
230
+ ev["__nrNode:".concat(_bundleId.bundleId)] = state.currentNode;
230
231
  }, this.featureName, eventsEE);
231
232
 
232
233
  /**
@@ -15,7 +15,7 @@ class AgentBase {
15
15
  * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
16
16
  */
17
17
  addPageAction(name, attributes) {
18
- (0, _console.warn)('Call to agent api addPageAction failed. The session trace feature is not currently initialized.');
18
+ (0, _console.warn)('Call to agent api addPageAction failed. The page action feature is not currently initialized.');
19
19
  }
20
20
 
21
21
  /**
@@ -95,13 +95,13 @@ class AgentBase {
95
95
  * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
96
96
  */
97
97
  addRelease(name, id) {
98
- (0, _console.warn)('Call to agent api addRelease failed. The agent is not currently initialized.');
98
+ (0, _console.warn)('Call to agent api addRelease failed. The js errors feature is not currently initialized.');
99
99
  }
100
100
 
101
101
  /**
102
102
  * Starts a set of agent features if not running in "autoStart" mode
103
103
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
104
- * @param {string|string[]|undefined} name The feature name(s) to start. If no name(s) are passed, all features will be started
104
+ * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
105
105
  */
106
106
  start(featureNames) {
107
107
  (0, _console.warn)('Call to agent api addRelease failed. The agent is not currently initialized.');
@@ -112,7 +112,7 @@ class Agent extends _agentBase.AgentBase {
112
112
  * If you are sending the same event object to New Relic as a PageAction, omit the TYPE attribute. (type is a string to describe what type of event you are marking inside of a session trace.) If included, it will override the event type and cause the PageAction event to be sent incorrectly. Instead, use the name attribute for event information.
113
113
  */
114
114
  addToTrace(customAttributes) {
115
- (0, _console.warn)('Call to agent api addToTrace failed. The page action feature is not currently initialized.');
115
+ (0, _console.warn)('Call to agent api addToTrace failed. The session trace feature is not currently initialized.');
116
116
  }
117
117
 
118
118
  /**
@@ -102,6 +102,12 @@ const model = () => {
102
102
  // float from 0 - 100
103
103
  error_sampling_rate: 50,
104
104
  // float from 0 - 100
105
+ collect_fonts: false,
106
+ // serialize fonts for collection without public asset url, this is currently broken in RRWeb -- https://github.com/rrweb-io/rrweb/issues/1304. When fixed, revisit with test cases
107
+ inline_images: false,
108
+ // serialize images for collection without public asset url
109
+ inline_stylesheet: true,
110
+ // serialize css for collection without public asset url
105
111
  // recording config settings
106
112
  mask_all_inputs: true,
107
113
  // this has a getter/setter to facilitate validation of the selectors
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.243.0";
9
+ export const VERSION = "1.244.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -17,4 +17,9 @@ export const BUILD_ENV = "CDN";
17
17
  /**
18
18
  * Exposes the distribution method of the agent
19
19
  */
20
- export const DIST_METHOD = 'CDN';
20
+ export const DIST_METHOD = 'CDN';
21
+
22
+ /**
23
+ * Exposes the lib version of rrweb
24
+ */
25
+ export const RRWEB_VERSION = "2.0.0-alpha.11";
@@ -20,4 +20,9 @@ export const BUILD_ENV = 'NPM';
20
20
  /**
21
21
  * Exposes the distribution method of the agent
22
22
  */
23
- export const DIST_METHOD = 'NPM';
23
+ export const DIST_METHOD = 'NPM';
24
+
25
+ /**
26
+ * Exposes the lib version of rrweb
27
+ */
28
+ export const RRWEB_VERSION = pkgJSON.dependencies.rrweb;
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.243.0";
9
+ export const VERSION = "1.244.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -18,4 +18,9 @@ export const BUILD_ENV = 'NPM';
18
18
  * Exposes the distribution method of the agent
19
19
  * Valid valuse are CDN, NPM
20
20
  */
21
- export const DIST_METHOD = 'NPM';
21
+ export const DIST_METHOD = 'NPM';
22
+
23
+ /**
24
+ * Exposes the lib version of rrweb
25
+ */
26
+ export const RRWEB_VERSION = "2.0.0-alpha.11";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * A helper method to warn to the console with New Relic: decoration
3
- * @param {string} message - The primary message to warn
4
- * @param {*} secondary - Secondary data to include, usually an error or object
3
+ * @param {string} message The primary message to warn
4
+ * @param {*} [secondary] Secondary data to include, usually an error or object
5
5
  * @returns
6
6
  */
7
7
  export function warn(message, secondary) {
@@ -22,9 +22,9 @@ 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
24
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
25
-
26
- // would be better to get this dynamically in some way
27
- export const RRWEB_VERSION = '2.0.0-alpha.8';
25
+ import { handle } from '../../../common/event-emitter/handle';
26
+ import { FEATURE_NAMES } from '../../../loaders/features/features';
27
+ import { RRWEB_VERSION } from "../../../common/constants/env.npm";
28
28
  export const AVG_COMPRESSION = 0.12;
29
29
  export const RRWEB_EVENT_TYPES = {
30
30
  DomContentLoaded: 0,
@@ -50,6 +50,10 @@ const ABORT_REASONS = {
50
50
  TOO_BIG: {
51
51
  message: 'Payload was too large',
52
52
  sm: 'Too-Big'
53
+ },
54
+ CROSS_TAB: {
55
+ message: 'Session Entity was set to OFF on another tab',
56
+ sm: 'Cross-Tab'
53
57
  }
54
58
  };
55
59
  let recorder, gzipper, u8;
@@ -58,9 +62,9 @@ let recorder, gzipper, u8;
58
62
  export const MAX_PAYLOAD_SIZE = 1000000;
59
63
  /** Unloading caps around 64kb */
60
64
  export const IDEAL_PAYLOAD_SIZE = 64000;
61
- /** Interval between forcing new full snapshots -- 30 seconds in error mode, 5 minutes in full mode */
65
+ /** Interval between forcing new full snapshots -- 15 seconds in error mode (x2), 5 minutes in full mode */
62
66
  const CHECKOUT_MS = {
63
- [MODE.ERROR]: 30000,
67
+ [MODE.ERROR]: 15000,
64
68
  [MODE.FULL]: 300000,
65
69
  [MODE.OFF]: 0
66
70
  };
@@ -70,6 +74,8 @@ export class Aggregate extends AggregateBase {
70
74
  super(agentIdentifier, aggregator, FEATURE_NAME);
71
75
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
72
76
  this.events = [];
77
+ /** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
78
+ this.backloggedEvents = [];
73
79
  /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
74
80
  this.harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'session_replay.harvestTimeSeconds') || 60;
75
81
  /** Set once the recorder has fully initialized after flag checks and sampling */
@@ -131,7 +137,7 @@ export class Aggregate extends AggregateBase {
131
137
  });
132
138
  this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
133
139
  if (!this.initialized || this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return;
134
- if (this.mode !== MODE.OFF && data.sessionReplay === MODE.OFF) this.abort('Session Entity was set to OFF on another tab');
140
+ if (this.mode !== MODE.OFF && data.sessionReplay === MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB);
135
141
  this.mode = data.sessionReplay;
136
142
  });
137
143
 
@@ -239,6 +245,10 @@ export class Aggregate extends AggregateBase {
239
245
  prepareHarvest() {
240
246
  if (this.events.length === 0 || this.mode !== MODE.FULL && !this.blocked) return;
241
247
  const payload = this.getHarvestContents();
248
+ if (!payload.body.length) {
249
+ this.clearBuffer();
250
+ return;
251
+ }
242
252
  if (this.shouldCompress) {
243
253
  payload.body = gzipper(u8(stringify(payload.body)));
244
254
  this.scheduler.opts.gzip = true;
@@ -258,6 +268,16 @@ export class Aggregate extends AggregateBase {
258
268
  getHarvestContents() {
259
269
  const agentRuntime = getRuntime(this.agentIdentifier);
260
270
  const info = getInfo(this.agentIdentifier);
271
+ if (this.backloggedEvents.length) this.events = [...this.backloggedEvents, ...this.events];
272
+
273
+ // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
274
+ // we will manually inject it if this happens
275
+ const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot;
276
+ if (payloadStartsWithFullSnapshot && !!this.lastMeta) {
277
+ this.hasMeta = true;
278
+ this.events.unshift(this.lastMeta); // --> pushed the meta from a previous payload into newer payload... but it still has old timestamps
279
+ this.lastMeta = undefined;
280
+ }
261
281
 
262
282
  // do not let the last node be a meta node, since this NEEDS to precede a snapshot
263
283
  // we will manually inject it later if we find a payload that is missing a meta node
@@ -267,16 +287,8 @@ export class Aggregate extends AggregateBase {
267
287
  this.events = this.events.slice(0, this.events.length - 1);
268
288
  this.hasMeta = !!this.events.find(x => x.type === RRWEB_EVENT_TYPES.Meta);
269
289
  }
270
-
271
- // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
272
- // we will manually inject it if this happens
273
- const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot;
274
- if (payloadStartsWithFullSnapshot) {
275
- this.hasMeta = true;
276
- this.events.unshift(this.lastMeta);
277
- }
278
- const firstEventTimestamp = this.events[0]?.timestamp;
279
- const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp;
290
+ const firstEventTimestamp = this.events[0]?.timestamp; // from rrweb node
291
+ const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp; // from rrweb node
280
292
  const firstTimestamp = firstEventTimestamp || this.cycleTimestamp;
281
293
  const lastTimestamp = lastEventTimestamp || getRuntime(this.agentIdentifier).offset + globalScope.performance.now();
282
294
  return {
@@ -317,6 +329,7 @@ export class Aggregate extends AggregateBase {
317
329
 
318
330
  /** Clears the buffer (this.events), and resets all payload metadata properties */
319
331
  clearBuffer() {
332
+ if (this.mode === MODE.ERROR) this.backloggedEvents = this.events;else this.backloggedEvents = [];
320
333
  this.events = [];
321
334
  this.hasSnapshot = false;
322
335
  this.hasMeta = false;
@@ -331,9 +344,6 @@ export class Aggregate extends AggregateBase {
331
344
  warn('Recording library was never imported');
332
345
  return this.abort(ABORT_REASONS.IMPORT);
333
346
  }
334
- this.clearTimestamps();
335
- // set the fallbacks as early as possible
336
- this.setTimestamps();
337
347
  this.recording = true;
338
348
  const {
339
349
  block_class,
@@ -342,7 +352,10 @@ export class Aggregate extends AggregateBase {
342
352
  block_selector,
343
353
  mask_input_options,
344
354
  mask_text_selector,
345
- mask_all_inputs
355
+ mask_all_inputs,
356
+ inline_images,
357
+ inline_stylesheet,
358
+ collect_fonts
346
359
  } = getConfigurationValue(this.agentIdentifier, 'session_replay');
347
360
  // set up rrweb configurations for maximum privacy --
348
361
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
@@ -355,6 +368,9 @@ export class Aggregate extends AggregateBase {
355
368
  maskInputOptions: mask_input_options,
356
369
  maskTextSelector: mask_text_selector,
357
370
  maskAllInputs: mask_all_inputs,
371
+ inlineImages: inline_images,
372
+ inlineStylesheet: inline_stylesheet,
373
+ collectFonts: collect_fonts,
358
374
  checkoutEveryNms: CHECKOUT_MS[this.mode]
359
375
  });
360
376
  this.stopRecording = () => {
@@ -378,7 +394,8 @@ export class Aggregate extends AggregateBase {
378
394
  // Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
379
395
  // to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
380
396
  // each time we see a new checkout, we can drop the old data.
381
- if (this.mode === MODE.ERROR && isCheckout) {
397
+ // we need to check for meta because rrweb will flag it as checkout twice, once for meta, then once for snapshot
398
+ if (this.mode === MODE.ERROR && isCheckout && event.type === RRWEB_EVENT_TYPES.Meta) {
382
399
  // we are still waiting for an error to throw, so keep wiping the buffer over time
383
400
  this.clearBuffer();
384
401
  }
@@ -386,7 +403,6 @@ export class Aggregate extends AggregateBase {
386
403
  // meta event
387
404
  if (event.type === RRWEB_EVENT_TYPES.Meta) {
388
405
  this.hasMeta = true;
389
- this.lastMeta = event;
390
406
  }
391
407
  // snapshot event
392
408
  if (event.type === RRWEB_EVENT_TYPES.FullSnapshot) {
@@ -427,7 +443,7 @@ export class Aggregate extends AggregateBase {
427
443
  abort() {
428
444
  let reason = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
429
445
  warn("SR aborted -- ".concat(reason.message));
430
- this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(ABORT_REASONS[reason.sm])]);
446
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(reason.sm)], undefined, FEATURE_NAMES.metrics, this.ee);
431
447
  this.blocked = true;
432
448
  this.mode = MODE.OFF;
433
449
  this.stopRecording();
@@ -20,6 +20,7 @@ import { FEATURE_NAMES } from '../../../loaders/features/features';
20
20
  import { AggregateBase } from '../../utils/aggregate-base';
21
21
  import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint';
22
22
  import { firstPaint } from '../../../common/vitals/first-paint';
23
+ import { bundleId } from '../../../common/ids/bundle-id';
23
24
  const {
24
25
  FEATURE_NAME,
25
26
  INTERACTION_EVENTS,
@@ -173,7 +174,7 @@ export class Aggregate extends AggregateBase {
173
174
  register(FN_START, function (args, eventSource) {
174
175
  var ev = args[0];
175
176
  var evName = ev.type;
176
- var eventNode = ev.__nrNode;
177
+ var eventNode = ev["__nrNode:".concat(bundleId)];
177
178
  if (!state.pageLoaded && evName === 'load' && eventSource === window) {
178
179
  state.pageLoaded = true;
179
180
  // set to null so prevNode is set correctly
@@ -217,7 +218,7 @@ export class Aggregate extends AggregateBase {
217
218
  }
218
219
  }
219
220
  }
220
- ev.__nrNode = state.currentNode;
221
+ ev["__nrNode:".concat(bundleId)] = state.currentNode;
221
222
  }, this.featureName, eventsEE);
222
223
 
223
224
  /**
@@ -9,7 +9,7 @@ export class AgentBase {
9
9
  * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
10
10
  */
11
11
  addPageAction(name, attributes) {
12
- warn('Call to agent api addPageAction failed. The session trace feature is not currently initialized.');
12
+ warn('Call to agent api addPageAction failed. The page action feature is not currently initialized.');
13
13
  }
14
14
 
15
15
  /**
@@ -89,13 +89,13 @@ export class AgentBase {
89
89
  * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
90
90
  */
91
91
  addRelease(name, id) {
92
- warn('Call to agent api addRelease failed. The agent is not currently initialized.');
92
+ warn('Call to agent api addRelease failed. The js errors feature is not currently initialized.');
93
93
  }
94
94
 
95
95
  /**
96
96
  * Starts a set of agent features if not running in "autoStart" mode
97
97
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
98
- * @param {string|string[]|undefined} name The feature name(s) to start. If no name(s) are passed, all features will be started
98
+ * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
99
99
  */
100
100
  start(featureNames) {
101
101
  warn('Call to agent api addRelease failed. The agent is not currently initialized.');
@@ -103,7 +103,7 @@ export class Agent extends AgentBase {
103
103
  * If you are sending the same event object to New Relic as a PageAction, omit the TYPE attribute. (type is a string to describe what type of event you are marking inside of a session trace.) If included, it will override the event type and cause the PageAction event to be sent incorrectly. Instead, use the name attribute for event information.
104
104
  */
105
105
  addToTrace(customAttributes) {
106
- warn('Call to agent api addToTrace failed. The page action feature is not currently initialized.');
106
+ warn('Call to agent api addToTrace failed. The session trace feature is not currently initialized.');
107
107
  }
108
108
 
109
109
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"AAuGA,+CAIC;AAED,0DAIC;AAED,+DAYC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../../src/common/config/state/init.js"],"names":[],"mappings":"AA0GA,+CAIC;AAED,0DAIC;AAED,+DAYC"}
@@ -15,4 +15,8 @@ export const BUILD_ENV: string | undefined;
15
15
  * Exposes the distribution method of the agent
16
16
  */
17
17
  export const DIST_METHOD: "CDN";
18
+ /**
19
+ * Exposes the lib version of rrweb
20
+ */
21
+ export const RRWEB_VERSION: string | undefined;
18
22
  //# sourceMappingURL=env.cdn.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.cdn.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.cdn.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,yCAAgD;AAEhD;;;GAGG;AACH,2CAA8C;AAE9C;;GAEG;AACH,gCAAgC"}
1
+ {"version":3,"file":"env.cdn.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.cdn.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,yCAAgD;AAEhD;;;GAGG;AACH,2CAA8C;AAE9C;;GAEG;AACH,gCAAgC;AAEhC;;GAEG;AACH,+CAAsD"}
@@ -10,4 +10,8 @@ export const BUILD_ENV: "NPM";
10
10
  * Exposes the distribution method of the agent
11
11
  */
12
12
  export const DIST_METHOD: "NPM";
13
+ /**
14
+ * Exposes the lib version of rrweb
15
+ */
16
+ export const RRWEB_VERSION: any;
13
17
  //# sourceMappingURL=env.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.js"],"names":[],"mappings":"AASA;;GAEG;AACH,0BAAsC;AAEtC;;GAEG;AACH,8BAA8B;AAE9B;;GAEG;AACH,gCAAgC"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.js"],"names":[],"mappings":"AASA;;GAEG;AACH,0BAAsC;AAEtC;;GAEG;AACH,8BAA8B;AAE9B;;GAEG;AACH,gCAAgC;AAEhC;;GAEG;AACH,gCAAuD"}
@@ -16,4 +16,8 @@ export const BUILD_ENV: "NPM";
16
16
  * Valid valuse are CDN, NPM
17
17
  */
18
18
  export const DIST_METHOD: "NPM";
19
+ /**
20
+ * Exposes the lib version of rrweb
21
+ */
22
+ export const RRWEB_VERSION: string | undefined;
19
23
  //# sourceMappingURL=env.npm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.npm.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.npm.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,yCAAgD;AAEhD;;;GAGG;AACH,8BAA8B;AAE9B;;;GAGG;AACH,gCAAgC"}
1
+ {"version":3,"file":"env.npm.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/env.npm.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,yCAAgD;AAEhD;;;GAGG;AACH,8BAA8B;AAE9B;;;GAGG;AACH,gCAAgC;AAEhC;;GAEG;AACH,+CAAsD"}
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * A helper method to warn to the console with New Relic: decoration
3
- * @param {string} message - The primary message to warn
4
- * @param {*} secondary - Secondary data to include, usually an error or object
3
+ * @param {string} message The primary message to warn
4
+ * @param {*} [secondary] Secondary data to include, usually an error or object
5
5
  * @returns
6
6
  */
7
- export function warn(message: string, secondary: any): void;
7
+ export function warn(message: string, secondary?: any): void;
8
8
  //# sourceMappingURL=console.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../../../src/common/util/console.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,8BAJW,MAAM,wBAQhB"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../../../src/common/util/console.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,8BAJW,MAAM,yBAQhB"}
@@ -1,4 +1,3 @@
1
- export const RRWEB_VERSION: "2.0.0-alpha.8";
2
1
  export const AVG_COMPRESSION: 0.12;
3
2
  export namespace RRWEB_EVENT_TYPES {
4
3
  const DomContentLoaded: number;
@@ -17,6 +16,8 @@ export class Aggregate extends AggregateBase {
17
16
  constructor(agentIdentifier: any, aggregator: any);
18
17
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
19
18
  events: any[];
19
+ /** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
20
+ backloggedEvents: any[];
20
21
  /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
21
22
  harvestTimeSeconds: any;
22
23
  /** Set once the recorder has fully initialized after flag checks and sampling */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA0BA,4CAA4C;AAE5C,mCAAmC;;;;;;;;;AAgCnC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AAIvC;IACE,2BAAiC;IACjC,mDA2GC;IAzGC,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;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IAErB;;OAEG;IACH,oBAA+B;IAE/B,qGAAqG;IACrG,+BAA+B;IAE/B,kIAAkI;IAClI,cAAyB;IAOzB,uIAAuI;IACvI,0BAAyE;IA0BvE,wCAKQ;IAgCZ;;;;;;OAMG;IACH,kCALW,OAAO,eACP,OAAO,cACP,OAAO,GACL,IAAI,CAuDhB;IAED;;;;;;;;;oBAeC;IAED;;;;;;;;;MAiDC;IAED,qCAOC;IAED,kFAAkF;IAClF,oBAOC;IAED,qDAAqD;IACrD,uBA4BC;IAED,yHAAyH;IACzH,yCAsCC;IAED,0HAA0H;IAC1H,yBAGC;IAED,sBAGC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED,yDAAyD;IACzD,yBASC;IAED;;;SAGK;IACL,oCAGC;IAED,yCAGC;CACF;8BA3a6B,4BAA4B;iCALzB,2CAA2C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AA4BA,mCAAmC;;;;;;;;;AAoCnC,uCAAuC;AACvC,uCAAuC;AACvC,iCAAiC;AACjC,uCAAuC;AAIvC;IACE,2BAAiC;IACjC,mDA6GC;IA3GC,iHAAiH;IACjH,cAAgB;IAChB,mFAAmF;IACnF,wBAA0B;IAC1B,8GAA8G;IAC9G,wBAAgH;IAChH,iFAAiF;IACjF,qBAAwB;IACxB,mEAAmE;IACnE,sBAAyB;IACzB,6GAA6G;IAC7G,aAAoB;IAGpB,iEAAiE;IACjE,mBAAsB;IACtB,gDAAgD;IAChD,wBAA0B;IAE1B;;;MAGE;IACF,qBAAwB;IACxB,4IAA4I;IAC5I,iBAAoB;IACpB,+HAA+H;IAC/H,kBAAqB;IAErB;;OAEG;IACH,oBAA+B;IAE/B,qGAAqG;IACrG,+BAA+B;IAE/B,kIAAkI;IAClI,cAAyB;IAOzB,uIAAuI;IACvI,0BAAyE;IA0BvE,wCAKQ;IAgCZ;;;;;;OAMG;IACH,kCALW,OAAO,eACP,OAAO,cACP,OAAO,GACL,IAAI,CAuDhB;IAED;;;;;;;;;oBAkBC;IAED;;;;;;;;;MAoDC;IAED,qCAOC;IAED,kFAAkF;IAClF,oBASC;IAED,qDAAqD;IACrD,uBA4BC;IAED,yHAAyH;IACzH,yCAsCC;IAED,0HAA0H;IAC1H,yBAGC;IAED,sBAGC;IAED,wBAEC;IAED,gCAAgC;IAChC,uCAGC;IAED,yDAAyD;IACzD,yBASC;IAED;;;SAGK;IACL,oCAGC;IAED,yCAGC;CACF;8BAzb6B,4BAA4B;iCALzB,2CAA2C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/index.js"],"names":[],"mappings":"AA2BA;IACE,2BAAiC;IACjC,mDA8rBC;IA3rBC;;;;;;;;;;;;;;;;MAgBC;IAED,uBAAsC;CA0qBzC;8BAzsB6B,4BAA4B;2BAJ/B,cAAc"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/index.js"],"names":[],"mappings":"AA4BA;IACE,2BAAiC;IACjC,mDA8rBC;IA3rBC;;;;;;;;;;;;;;;;MAgBC;IAED,uBAAsC;CA0qBzC;8BA1sB6B,4BAA4B;2BAJ/B,cAAc"}
@@ -67,8 +67,8 @@ export class AgentBase {
67
67
  /**
68
68
  * Starts a set of agent features if not running in "autoStart" mode
69
69
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
70
- * @param {string|string[]|undefined} name The feature name(s) to start. If no name(s) are passed, all features will be started
70
+ * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
71
71
  */
72
- start(featureNames: any): void;
72
+ start(featureNames?: string | string[] | undefined): void;
73
73
  }
74
74
  //# sourceMappingURL=agent-base.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAIA;IACE;;;;;OAKG;IACH,oBAHW,MAAM,yCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,mCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,IAAI,uCAK5B;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,+CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,QAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,QAMrB;IAED;;;;OAIG;IACH,kCAFmB,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,QAI9D;IAED;;;;OAIG;IACH,+CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,QAIhB;IAED;;;;OAIG;IACH,+BAEC;CACF"}
1
+ {"version":3,"file":"agent-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/agent-base.js"],"names":[],"mappings":"AAIA;IACE;;;;;OAKG;IACH,oBAHW,MAAM,yCAKhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,mCAKhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,IAAI,uCAK5B;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,+CAKtB;IAED;;;;OAIG;IACH,iBAFW,MAAM,GAAC,IAAI,QAIrB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,QAMrB;IAED;;;;OAIG;IACH,kCAFmB,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,QAI9D;IAED;;;;OAIG;IACH,+CAEC;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,QAIhB;IAED;;;;OAIG;IACH,0DAEC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.243.0",
3
+ "version": "1.244.0",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -176,7 +176,7 @@
176
176
  "dependencies": {
177
177
  "core-js": "^3.26.0",
178
178
  "fflate": "^0.7.4",
179
- "rrweb": "2.0.0-alpha.8",
179
+ "rrweb": "2.0.0-alpha.11",
180
180
  "web-vitals": "^3.1.0"
181
181
  },
182
182
  "devDependencies": {
@@ -63,6 +63,9 @@ const model = () => {
63
63
  harvestTimeSeconds: 60,
64
64
  sampling_rate: 50, // float from 0 - 100
65
65
  error_sampling_rate: 50, // float from 0 - 100
66
+ collect_fonts: false, // serialize fonts for collection without public asset url, this is currently broken in RRWeb -- https://github.com/rrweb-io/rrweb/issues/1304. When fixed, revisit with test cases
67
+ inline_images: false, // serialize images for collection without public asset url
68
+ inline_stylesheet: true, // serialize css for collection without public asset url
66
69
  // recording config settings
67
70
  mask_all_inputs: true,
68
71
  // this has a getter/setter to facilitate validation of the selectors
@@ -1,3 +1,4 @@
1
1
  export const VERSION = '0.0.0'
2
2
  export const BUILD_ENV = 'TEST'
3
3
  export const DIST_METHOD = 'TEST'
4
+ export const RRWEB_VERSION = '0.0.0'
@@ -18,3 +18,8 @@ export const BUILD_ENV = process.env.BUILD_ENV
18
18
  * Exposes the distribution method of the agent
19
19
  */
20
20
  export const DIST_METHOD = 'CDN'
21
+
22
+ /**
23
+ * Exposes the lib version of rrweb
24
+ */
25
+ export const RRWEB_VERSION = process.env.RRWEB_VERSION
@@ -21,3 +21,8 @@ export const BUILD_ENV = 'NPM'
21
21
  * Exposes the distribution method of the agent
22
22
  */
23
23
  export const DIST_METHOD = 'NPM'
24
+
25
+ /**
26
+ * Exposes the lib version of rrweb
27
+ */
28
+ export const RRWEB_VERSION = pkgJSON.dependencies.rrweb
@@ -19,3 +19,8 @@ export const BUILD_ENV = 'NPM'
19
19
  * Valid valuse are CDN, NPM
20
20
  */
21
21
  export const DIST_METHOD = 'NPM'
22
+
23
+ /**
24
+ * Exposes the lib version of rrweb
25
+ */
26
+ export const RRWEB_VERSION = process.env.RRWEB_VERSION
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * A helper method to warn to the console with New Relic: decoration
3
- * @param {string} message - The primary message to warn
4
- * @param {*} secondary - Secondary data to include, usually an error or object
3
+ * @param {string} message The primary message to warn
4
+ * @param {*} [secondary] Secondary data to include, usually an error or object
5
5
  * @returns
6
6
  */
7
7
  export function warn (message, secondary) {
@@ -22,9 +22,9 @@ 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
24
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
25
-
26
- // would be better to get this dynamically in some way
27
- export const RRWEB_VERSION = '2.0.0-alpha.8'
25
+ import { handle } from '../../../common/event-emitter/handle'
26
+ import { FEATURE_NAMES } from '../../../loaders/features/features'
27
+ import { RRWEB_VERSION } from '../../../common/constants/env'
28
28
 
29
29
  export const AVG_COMPRESSION = 0.12
30
30
 
@@ -53,6 +53,10 @@ const ABORT_REASONS = {
53
53
  TOO_BIG: {
54
54
  message: 'Payload was too large',
55
55
  sm: 'Too-Big'
56
+ },
57
+ CROSS_TAB: {
58
+ message: 'Session Entity was set to OFF on another tab',
59
+ sm: 'Cross-Tab'
56
60
  }
57
61
  }
58
62
 
@@ -62,8 +66,8 @@ let recorder, gzipper, u8
62
66
  export const MAX_PAYLOAD_SIZE = 1000000
63
67
  /** Unloading caps around 64kb */
64
68
  export const IDEAL_PAYLOAD_SIZE = 64000
65
- /** Interval between forcing new full snapshots -- 30 seconds in error mode, 5 minutes in full mode */
66
- const CHECKOUT_MS = { [MODE.ERROR]: 30000, [MODE.FULL]: 300000, [MODE.OFF]: 0 }
69
+ /** Interval between forcing new full snapshots -- 15 seconds in error mode (x2), 5 minutes in full mode */
70
+ const CHECKOUT_MS = { [MODE.ERROR]: 15000, [MODE.FULL]: 300000, [MODE.OFF]: 0 }
67
71
 
68
72
  export class Aggregate extends AggregateBase {
69
73
  static featureName = FEATURE_NAME
@@ -71,6 +75,8 @@ export class Aggregate extends AggregateBase {
71
75
  super(agentIdentifier, aggregator, FEATURE_NAME)
72
76
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
73
77
  this.events = []
78
+ /** Backlog used for a 2-part sliding window to guarantee a 15-30s buffer window */
79
+ this.backloggedEvents = []
74
80
  /** The interval to harvest at. This gets overridden if the size of the payload exceeds certain thresholds */
75
81
  this.harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'session_replay.harvestTimeSeconds') || 60
76
82
  /** Set once the recorder has fully initialized after flag checks and sampling */
@@ -134,7 +140,7 @@ export class Aggregate extends AggregateBase {
134
140
 
135
141
  this.ee.on(SESSION_EVENTS.UPDATE, (type, data) => {
136
142
  if (!this.initialized || this.blocked || type !== SESSION_EVENT_TYPES.CROSS_TAB) return
137
- if (this.mode !== MODE.OFF && data.sessionReplay === MODE.OFF) this.abort('Session Entity was set to OFF on another tab')
143
+ if (this.mode !== MODE.OFF && data.sessionReplay === MODE.OFF) this.abort(ABORT_REASONS.CROSS_TAB)
138
144
  this.mode = data.sessionReplay
139
145
  })
140
146
 
@@ -241,7 +247,10 @@ export class Aggregate extends AggregateBase {
241
247
  prepareHarvest () {
242
248
  if (this.events.length === 0 || (this.mode !== MODE.FULL && !this.blocked)) return
243
249
  const payload = this.getHarvestContents()
244
-
250
+ if (!payload.body.length) {
251
+ this.clearBuffer()
252
+ return
253
+ }
245
254
  if (this.shouldCompress) {
246
255
  payload.body = gzipper(u8(stringify(payload.body)))
247
256
  this.scheduler.opts.gzip = true
@@ -259,6 +268,17 @@ export class Aggregate extends AggregateBase {
259
268
  const agentRuntime = getRuntime(this.agentIdentifier)
260
269
  const info = getInfo(this.agentIdentifier)
261
270
 
271
+ if (this.backloggedEvents.length) this.events = [...this.backloggedEvents, ...this.events]
272
+
273
+ // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
274
+ // we will manually inject it if this happens
275
+ const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot
276
+ if (payloadStartsWithFullSnapshot && !!this.lastMeta) {
277
+ this.hasMeta = true
278
+ this.events.unshift(this.lastMeta) // --> pushed the meta from a previous payload into newer payload... but it still has old timestamps
279
+ this.lastMeta = undefined
280
+ }
281
+
262
282
  // do not let the last node be a meta node, since this NEEDS to precede a snapshot
263
283
  // we will manually inject it later if we find a payload that is missing a meta node
264
284
  const payloadEndsWithMeta = this.events[this.events.length - 1]?.type === RRWEB_EVENT_TYPES.Meta
@@ -268,16 +288,8 @@ export class Aggregate extends AggregateBase {
268
288
  this.hasMeta = !!this.events.find(x => x.type === RRWEB_EVENT_TYPES.Meta)
269
289
  }
270
290
 
271
- // do not let the first node be a full snapshot node, since this NEEDS to be preceded by a meta node
272
- // we will manually inject it if this happens
273
- const payloadStartsWithFullSnapshot = this.events[0]?.type === RRWEB_EVENT_TYPES.FullSnapshot
274
- if (payloadStartsWithFullSnapshot) {
275
- this.hasMeta = true
276
- this.events.unshift(this.lastMeta)
277
- }
278
-
279
- const firstEventTimestamp = this.events[0]?.timestamp
280
- const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp
291
+ const firstEventTimestamp = this.events[0]?.timestamp // from rrweb node
292
+ const lastEventTimestamp = this.events[this.events.length - 1]?.timestamp // from rrweb node
281
293
  const firstTimestamp = firstEventTimestamp || this.cycleTimestamp
282
294
  const lastTimestamp = lastEventTimestamp || getRuntime(this.agentIdentifier).offset + globalScope.performance.now()
283
295
  return {
@@ -317,6 +329,8 @@ export class Aggregate extends AggregateBase {
317
329
 
318
330
  /** Clears the buffer (this.events), and resets all payload metadata properties */
319
331
  clearBuffer () {
332
+ if (this.mode === MODE.ERROR) this.backloggedEvents = this.events
333
+ else this.backloggedEvents = []
320
334
  this.events = []
321
335
  this.hasSnapshot = false
322
336
  this.hasMeta = false
@@ -331,11 +345,8 @@ export class Aggregate extends AggregateBase {
331
345
  warn('Recording library was never imported')
332
346
  return this.abort(ABORT_REASONS.IMPORT)
333
347
  }
334
- this.clearTimestamps()
335
- // set the fallbacks as early as possible
336
- this.setTimestamps()
337
348
  this.recording = true
338
- const { block_class, ignore_class, mask_text_class, block_selector, mask_input_options, mask_text_selector, mask_all_inputs } = getConfigurationValue(this.agentIdentifier, 'session_replay')
349
+ const { block_class, ignore_class, mask_text_class, block_selector, mask_input_options, mask_text_selector, mask_all_inputs, inline_images, inline_stylesheet, collect_fonts } = getConfigurationValue(this.agentIdentifier, 'session_replay')
339
350
  // set up rrweb configurations for maximum privacy --
340
351
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
341
352
  const stop = recorder({
@@ -347,6 +358,9 @@ export class Aggregate extends AggregateBase {
347
358
  maskInputOptions: mask_input_options,
348
359
  maskTextSelector: mask_text_selector,
349
360
  maskAllInputs: mask_all_inputs,
361
+ inlineImages: inline_images,
362
+ inlineStylesheet: inline_stylesheet,
363
+ collectFonts: collect_fonts,
350
364
  checkoutEveryNms: CHECKOUT_MS[this.mode]
351
365
  })
352
366
 
@@ -371,7 +385,8 @@ export class Aggregate extends AggregateBase {
371
385
  // Checkout events are flags by the recording lib that indicate a fullsnapshot was taken every n ms. These are important
372
386
  // to help reconstruct the replay later and must be included. While waiting and buffering for errors to come through,
373
387
  // each time we see a new checkout, we can drop the old data.
374
- if (this.mode === MODE.ERROR && isCheckout) {
388
+ // we need to check for meta because rrweb will flag it as checkout twice, once for meta, then once for snapshot
389
+ if (this.mode === MODE.ERROR && isCheckout && event.type === RRWEB_EVENT_TYPES.Meta) {
375
390
  // we are still waiting for an error to throw, so keep wiping the buffer over time
376
391
  this.clearBuffer()
377
392
  }
@@ -379,7 +394,6 @@ export class Aggregate extends AggregateBase {
379
394
  // meta event
380
395
  if (event.type === RRWEB_EVENT_TYPES.Meta) {
381
396
  this.hasMeta = true
382
- this.lastMeta = event
383
397
  }
384
398
  // snapshot event
385
399
  if (event.type === RRWEB_EVENT_TYPES.FullSnapshot) {
@@ -421,7 +435,7 @@ export class Aggregate extends AggregateBase {
421
435
  /** Abort the feature, once aborted it will not resume */
422
436
  abort (reason = {}) {
423
437
  warn(`SR aborted -- ${reason.message}`)
424
- this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, [`SessionReplay/Abort/${ABORT_REASONS[reason.sm]}`])
438
+ handle(SUPPORTABILITY_METRIC_CHANNEL, [`SessionReplay/Abort/${reason.sm}`], undefined, FEATURE_NAMES.metrics, this.ee)
425
439
  this.blocked = true
426
440
  this.mode = MODE.OFF
427
441
  this.stopRecording()
@@ -20,6 +20,7 @@ import { FEATURE_NAMES } from '../../../loaders/features/features'
20
20
  import { AggregateBase } from '../../utils/aggregate-base'
21
21
  import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint'
22
22
  import { firstPaint } from '../../../common/vitals/first-paint'
23
+ import { bundleId } from '../../../common/ids/bundle-id'
23
24
 
24
25
  const {
25
26
  FEATURE_NAME, INTERACTION_EVENTS, MAX_TIMER_BUDGET, FN_START, FN_END, CB_START, INTERACTION_API, REMAINING,
@@ -166,7 +167,7 @@ export class Aggregate extends AggregateBase {
166
167
  register(FN_START, function (args, eventSource) {
167
168
  var ev = args[0]
168
169
  var evName = ev.type
169
- var eventNode = ev.__nrNode
170
+ var eventNode = ev[`__nrNode:${bundleId}`]
170
171
 
171
172
  if (!state.pageLoaded && evName === 'load' && eventSource === window) {
172
173
  state.pageLoaded = true
@@ -216,7 +217,7 @@ export class Aggregate extends AggregateBase {
216
217
  }
217
218
  }
218
219
 
219
- ev.__nrNode = state.currentNode
220
+ ev[`__nrNode:${bundleId}`] = state.currentNode
220
221
  }, this.featureName, eventsEE)
221
222
 
222
223
  /**
@@ -10,7 +10,7 @@ export class AgentBase {
10
10
  * @param {object} [attributes] JSON object with one or more key/value pairs. For example: {key:"value"}. The key is reported as its own PageAction attribute with the specified values.
11
11
  */
12
12
  addPageAction (name, attributes) {
13
- warn('Call to agent api addPageAction failed. The session trace feature is not currently initialized.')
13
+ warn('Call to agent api addPageAction failed. The page action feature is not currently initialized.')
14
14
  }
15
15
 
16
16
  /**
@@ -90,13 +90,13 @@ export class AgentBase {
90
90
  * @param {string} id The ID or version of this release; for example, a version number, build number from your CI environment, GitHub SHA, GUID, or a hash of the contents.
91
91
  */
92
92
  addRelease (name, id) {
93
- warn('Call to agent api addRelease failed. The agent is not currently initialized.')
93
+ warn('Call to agent api addRelease failed. The js errors feature is not currently initialized.')
94
94
  }
95
95
 
96
96
  /**
97
97
  * Starts a set of agent features if not running in "autoStart" mode
98
98
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/start/}
99
- * @param {string|string[]|undefined} name The feature name(s) to start. If no name(s) are passed, all features will be started
99
+ * @param {string|string[]} [featureNames] The name(s) of the features to start. If no name(s) are passed, all features will be started
100
100
  */
101
101
  start (featureNames) {
102
102
  warn('Call to agent api addRelease failed. The agent is not currently initialized.')
@@ -107,7 +107,7 @@ export class Agent extends AgentBase {
107
107
  * If you are sending the same event object to New Relic as a PageAction, omit the TYPE attribute. (type is a string to describe what type of event you are marking inside of a session trace.) If included, it will override the event type and cause the PageAction event to be sent incorrectly. Instead, use the name attribute for event information.
108
108
  */
109
109
  addToTrace (customAttributes) {
110
- warn('Call to agent api addToTrace failed. The page action feature is not currently initialized.')
110
+ warn('Call to agent api addToTrace failed. The session trace feature is not currently initialized.')
111
111
  }
112
112
 
113
113
  /**