@newrelic/browser-agent 1.290.0 → 1.290.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/common/config/configurable.js +1 -1
  3. package/dist/cjs/common/config/runtime.js +4 -2
  4. package/dist/cjs/common/constants/agent-constants.js +3 -2
  5. package/dist/cjs/common/constants/env.cdn.js +1 -1
  6. package/dist/cjs/common/constants/env.npm.js +1 -1
  7. package/dist/cjs/features/jserrors/instrument/index.js +3 -8
  8. package/dist/cjs/features/session_replay/aggregate/index.js +4 -4
  9. package/dist/cjs/features/session_replay/constants.js +0 -1
  10. package/dist/cjs/features/session_replay/instrument/index.js +4 -8
  11. package/dist/cjs/features/session_replay/shared/recorder.js +29 -30
  12. package/dist/cjs/features/utils/entity-manager.js +5 -6
  13. package/dist/cjs/features/utils/event-store-manager.js +8 -4
  14. package/dist/cjs/loaders/api/constants.js +1 -2
  15. package/dist/cjs/loaders/api/noticeError.js +3 -9
  16. package/dist/cjs/loaders/api/sharedHandlers.js +1 -7
  17. package/dist/esm/common/config/configurable.js +1 -1
  18. package/dist/esm/common/config/runtime.js +4 -2
  19. package/dist/esm/common/constants/agent-constants.js +2 -1
  20. package/dist/esm/common/constants/env.cdn.js +1 -1
  21. package/dist/esm/common/constants/env.npm.js +1 -1
  22. package/dist/esm/features/jserrors/instrument/index.js +3 -8
  23. package/dist/esm/features/session_replay/aggregate/index.js +4 -4
  24. package/dist/esm/features/session_replay/constants.js +0 -1
  25. package/dist/esm/features/session_replay/instrument/index.js +4 -8
  26. package/dist/esm/features/session_replay/shared/recorder.js +30 -31
  27. package/dist/esm/features/utils/entity-manager.js +5 -6
  28. package/dist/esm/features/utils/event-store-manager.js +5 -1
  29. package/dist/esm/loaders/api/constants.js +0 -1
  30. package/dist/esm/loaders/api/noticeError.js +2 -8
  31. package/dist/esm/loaders/api/sharedHandlers.js +1 -7
  32. package/dist/types/common/config/runtime.d.ts.map +1 -1
  33. package/dist/types/common/constants/agent-constants.d.ts +1 -0
  34. package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
  35. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  36. package/dist/types/features/session_replay/constants.d.ts +0 -1
  37. package/dist/types/features/session_replay/constants.d.ts.map +1 -1
  38. package/dist/types/features/session_replay/instrument/index.d.ts +0 -1
  39. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  40. package/dist/types/features/session_replay/shared/recorder.d.ts +0 -3
  41. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  42. package/dist/types/features/utils/entity-manager.d.ts +1 -5
  43. package/dist/types/features/utils/entity-manager.d.ts.map +1 -1
  44. package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
  45. package/dist/types/loaders/api/constants.d.ts +0 -1
  46. package/dist/types/loaders/api/constants.d.ts.map +1 -1
  47. package/dist/types/loaders/api/noticeError.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/src/common/config/configurable.js +1 -1
  50. package/src/common/config/runtime.js +3 -2
  51. package/src/common/constants/agent-constants.js +1 -0
  52. package/src/features/jserrors/instrument/index.js +3 -9
  53. package/src/features/session_replay/aggregate/index.js +4 -4
  54. package/src/features/session_replay/constants.js +0 -1
  55. package/src/features/session_replay/instrument/index.js +4 -8
  56. package/src/features/session_replay/shared/recorder.js +28 -32
  57. package/src/features/utils/entity-manager.js +5 -5
  58. package/src/features/utils/event-store-manager.js +5 -2
  59. package/src/loaders/api/constants.js +0 -2
  60. package/src/loaders/api/noticeError.js +2 -10
  61. package/src/loaders/api/sharedHandlers.js +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
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.290.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.290.0...v1.290.1) (2025-05-21)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Silence setting getter only harvestCount message ([#1480](https://github.com/newrelic/newrelic-browser-agent/issues/1480)) ([98b1ab6](https://github.com/newrelic/newrelic-browser-agent/commit/98b1ab69c8a03a41f0cdccf27e410728f389bebb))
12
+
6
13
  ## [1.290.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.289.0...v1.290.0) (2025-05-02)
7
14
 
8
15
 
@@ -26,7 +26,7 @@ function getModeledObject(obj, model) {
26
26
  }
27
27
  if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (typeof obj[key] === 'object' && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
28
28
  } catch (e) {
29
- (0, _console.warn)(1, e);
29
+ if (!output[key]) (0, _console.warn)(1, e);
30
30
  }
31
31
  }
32
32
  return output;
@@ -16,7 +16,7 @@ var _env = require("../constants/env.npm");
16
16
  * Module level count of harvests. This property will auto-increment each time it is accessed.
17
17
  * @type {number}
18
18
  */
19
- let harvestCount = 0;
19
+ let _harvestCount = 0;
20
20
  const ReadOnly = {
21
21
  buildEnv: _env.BUILD_ENV,
22
22
  distMethod: _env.DIST_METHOD,
@@ -32,6 +32,8 @@ const RuntimeModel = {
32
32
  entityManager: undefined,
33
33
  harvester: undefined,
34
34
  isolatedBacklog: false,
35
+ isRecording: false,
36
+ // true when actively recording, false when paused or stopped
35
37
  loaderType: undefined,
36
38
  maxBytes: 30000,
37
39
  obfuscator: undefined,
@@ -41,7 +43,7 @@ const RuntimeModel = {
41
43
  session: undefined,
42
44
  timeKeeper: undefined,
43
45
  get harvestCount() {
44
- return ++harvestCount;
46
+ return ++_harvestCount;
45
47
  }
46
48
  };
47
49
  const mergeRuntime = runtime => {
@@ -3,10 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = void 0;
6
+ exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.DEFAULT_KEY = void 0;
7
7
  /**
8
8
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
9
  * SPDX-License-Identifier: Apache-2.0
10
10
  */
11
11
  const IDEAL_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = 64000;
12
- const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
12
+ const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
13
+ const DEFAULT_KEY = exports.DEFAULT_KEY = 'NR_CONTAINER_AGENT';
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.290.0";
20
+ const VERSION = exports.VERSION = "1.290.1";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.290.0";
20
+ const VERSION = exports.VERSION = "1.290.1";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -10,7 +10,6 @@ var _constants = require("../constants");
10
10
  var _runtime = require("../../../common/constants/runtime");
11
11
  var _eventListenerOpts = require("../../../common/event-listener/event-listener-opts");
12
12
  var _now = require("../../../common/timing/now");
13
- var _constants2 = require("../../session_replay/constants");
14
13
  var _castError = require("../shared/cast-error");
15
14
  var _noticeError = require("../../../loaders/api/noticeError");
16
15
  var _setErrorHandler = require("../../../loaders/api/setErrorHandler");
@@ -23,7 +22,6 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
23
22
  */
24
23
  class Instrument extends _instrumentBase.InstrumentBase {
25
24
  static featureName = _constants.FEATURE_NAME;
26
- #replayRunning = false;
27
25
  constructor(agentRef) {
28
26
  super(agentRef, _constants.FEATURE_NAME);
29
27
 
@@ -38,20 +36,17 @@ class Instrument extends _instrumentBase.InstrumentBase {
38
36
  } catch (e) {}
39
37
  this.ee.on('internal-error', (error, reason) => {
40
38
  if (!this.abortHandler) return;
41
- (0, _handle.handle)('ierr', [(0, _castError.castError)(error), (0, _now.now)(), true, {}, this.#replayRunning, reason], undefined, this.featureName, this.ee);
42
- });
43
- this.ee.on(_constants2.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, isRunning => {
44
- this.#replayRunning = isRunning;
39
+ (0, _handle.handle)('ierr', [(0, _castError.castError)(error), (0, _now.now)(), true, {}, agentRef.runtime.isRecording, reason], undefined, this.featureName, this.ee);
45
40
  });
46
41
  _runtime.globalScope.addEventListener('unhandledrejection', promiseRejectionEvent => {
47
42
  if (!this.abortHandler) return;
48
43
  (0, _handle.handle)('err', [(0, _castError.castPromiseRejectionEvent)(promiseRejectionEvent), (0, _now.now)(), false, {
49
44
  unhandledPromiseRejection: 1
50
- }, this.#replayRunning], undefined, this.featureName, this.ee);
45
+ }, agentRef.runtime.isRecording], undefined, this.featureName, this.ee);
51
46
  }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort?.signal));
52
47
  _runtime.globalScope.addEventListener('error', errorEvent => {
53
48
  if (!this.abortHandler) return;
54
- (0, _handle.handle)('err', [(0, _castError.castErrorEvent)(errorEvent), (0, _now.now)(), false, {}, this.#replayRunning], undefined, this.featureName, this.ee);
49
+ (0, _handle.handle)('err', [(0, _castError.castErrorEvent)(errorEvent), (0, _now.now)(), false, {}, agentRef.runtime.isRecording], undefined, this.featureName, this.ee);
55
50
  }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort?.signal));
56
51
  this.abortHandler = this.#abort; // we also use this as a flag to denote that the feature is active or on and handling errors
57
52
  this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "jserrors-aggregate" */'../aggregate'))));
@@ -95,7 +95,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
95
95
  this.entitled = !!entitled;
96
96
  if (!this.entitled) {
97
97
  this.deregisterDrain();
98
- if (this.recorder?.recording) {
98
+ if (this.agentRef.runtime.isRecording) {
99
99
  this.abort(_constants.ABORT_REASONS.ENTITLEMENTS);
100
100
  this.reportSupportabilityMetric('SessionReplay/EnabledNotEntitled/Detected');
101
101
  }
@@ -136,7 +136,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
136
136
  this.mode = _constants2.MODE.FULL;
137
137
  // if the error was noticed AFTER the recorder was already imported....
138
138
  if (this.recorder && this.initialized) {
139
- if (!this.recorder.recording) this.recorder.startRecording();
139
+ if (!this.agentRef.runtime.isRecording) this.recorder.startRecording();
140
140
  this.syncWithSessionManager({
141
141
  sessionReplayMode: this.mode
142
142
  });
@@ -166,7 +166,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
166
166
  timeKeeper
167
167
  } = this.agentRef.runtime;
168
168
  this.timeKeeper = timeKeeper;
169
- if (this.recorder?.parent.trigger === _constants.TRIGGERS.API && this.recorder?.recording) {
169
+ if (this.recorder?.parent.trigger === _constants.TRIGGERS.API && this.agentRef.runtime.isRecording) {
170
170
  this.mode = _constants2.MODE.FULL;
171
171
  } else if (!session.isNew && !ignoreSession) {
172
172
  // inherit the mode of the existing session
@@ -204,7 +204,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
204
204
  this.prepUtils().then(() => this.agentRef.runtime.harvester.triggerHarvestFor(this));
205
205
  }
206
206
  await this.prepUtils();
207
- if (!this.recorder.recording) this.recorder.startRecording();
207
+ if (!this.agentRef.runtime.isRecording) this.recorder.startRecording();
208
208
  this.syncWithSessionManager({
209
209
  sessionReplayMode: this.mode
210
210
  });
@@ -15,7 +15,6 @@ const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.sessionRepla
15
15
  const SR_EVENT_EMITTER_TYPES = exports.SR_EVENT_EMITTER_TYPES = {
16
16
  RECORD: 'recordReplay',
17
17
  PAUSE: 'pauseReplay',
18
- REPLAY_RUNNING: 'replayRunning',
19
18
  ERROR_DURING_REPLAY: 'errorDuringReplay'
20
19
  };
21
20
  const AVG_COMPRESSION = exports.AVG_COMPRESSION = 0.12;
@@ -29,7 +29,6 @@ class Instrument extends _instrumentBase.InstrumentBase {
29
29
  (0, _recordReplay.setupRecordReplayAPI)(agentRef);
30
30
  (0, _pauseReplay.setupPauseReplayAPI)(agentRef);
31
31
  let session;
32
- this.replayRunning = false;
33
32
  this.#agentRef = agentRef;
34
33
  try {
35
34
  session = JSON.parse(localStorage.getItem("".concat(_constants.PREFIX, "_").concat(_constants.DEFAULT_KEY)));
@@ -46,16 +45,11 @@ class Instrument extends _instrumentBase.InstrumentBase {
46
45
 
47
46
  /** If the recorder is running, we can pass error events on to the agg to help it switch to full mode later */
48
47
  this.ee.on('err', e => {
49
- if (this.replayRunning) {
48
+ if (this.#agentRef.runtime.isRecording) {
50
49
  this.errorNoticed = true;
51
50
  (0, _handle.handle)(_constants2.SR_EVENT_EMITTER_TYPES.ERROR_DURING_REPLAY, [e], undefined, this.featureName, this.ee);
52
51
  }
53
52
  });
54
-
55
- /** Emitted by the recorder when it starts capturing data, used to determine if we should pass errors on to the agg */
56
- this.ee.on(_constants2.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, isRunning => {
57
- this.replayRunning = isRunning;
58
- });
59
53
  }
60
54
 
61
55
  // At this point wherein session state exists already but we haven't init SessionEntity aka verify timers.
@@ -95,7 +89,9 @@ class Instrument extends _instrumentBase.InstrumentBase {
95
89
  });
96
90
  this.recorder.startRecording();
97
91
  this.abortHandler = this.recorder.stopRecording;
98
- } catch (e) {} // TODO add internal error handling
92
+ } catch (err) {
93
+ this.parent.ee.emit('internal-error', [err]);
94
+ }
99
95
  this.importAggregator(this.#agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "session_replay-aggregate" */'../aggregate'))), {
100
96
  recorder: this.recorder,
101
97
  errorNoticed: this.errorNoticed
@@ -43,8 +43,6 @@ class Recorder {
43
43
  this.#events = new _recorderEvents.RecorderEvents(this.shouldFix);
44
44
  this.#backloggedEvents = new _recorderEvents.RecorderEvents(this.shouldFix);
45
45
  this.#preloaded = [new _recorderEvents.RecorderEvents(this.shouldFix)];
46
- /** True when actively recording, false when paused or stopped */
47
- this.recording = false;
48
46
  /** The pointer to the current bucket holding rrweb events */
49
47
  this.currentBufferTarget = this.#events;
50
48
  /** Only set to true once a snapshot node has been processed. Used to block preload harvests from sending before we know we have a snapshot */
@@ -52,7 +50,9 @@ class Recorder {
52
50
  /** 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 */
53
51
  this.lastMeta = false;
54
52
  /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
55
- this.stopRecording = () => {/* no-op until set by rrweb initializer */};
53
+ this.stopRecording = () => {
54
+ this.parent.agentRef.runtime.isRecording = false;
55
+ };
56
56
  }
57
57
  getEvents() {
58
58
  if (this.#preloaded[0]?.events.length) {
@@ -83,7 +83,7 @@ class Recorder {
83
83
 
84
84
  /** Begin recording using configured recording lib */
85
85
  startRecording() {
86
- this.recording = true;
86
+ this.parent.agentRef.runtime.isRecording = true;
87
87
  const {
88
88
  block_class,
89
89
  ignore_class,
@@ -98,27 +98,30 @@ class Recorder {
98
98
 
99
99
  // set up rrweb configurations for maximum privacy --
100
100
  // https://newrelic.atlassian.net/wiki/spaces/O11Y/pages/2792293280/2023+02+28+Browser+-+Session+Replay#Configuration-options
101
- const stop = (0, _rrweb.record)({
102
- emit: this.audit.bind(this),
103
- blockClass: block_class,
104
- ignoreClass: ignore_class,
105
- maskTextClass: mask_text_class,
106
- blockSelector: block_selector,
107
- maskInputOptions: mask_input_options,
108
- maskTextSelector: mask_text_selector,
109
- maskTextFn: _utils.customMasker,
110
- maskAllInputs: mask_all_inputs,
111
- maskInputFn: _utils.customMasker,
112
- inlineStylesheet: true,
113
- inlineImages: inline_images,
114
- collectFonts: collect_fonts,
115
- checkoutEveryNms: _constants.CHECKOUT_MS[this.parent.mode],
116
- recordAfter: 'DOMContentLoaded'
117
- });
101
+ let stop;
102
+ try {
103
+ stop = (0, _rrweb.record)({
104
+ emit: this.audit.bind(this),
105
+ blockClass: block_class,
106
+ ignoreClass: ignore_class,
107
+ maskTextClass: mask_text_class,
108
+ blockSelector: block_selector,
109
+ maskInputOptions: mask_input_options,
110
+ maskTextSelector: mask_text_selector,
111
+ maskTextFn: _utils.customMasker,
112
+ maskAllInputs: mask_all_inputs,
113
+ maskInputFn: _utils.customMasker,
114
+ inlineStylesheet: true,
115
+ inlineImages: inline_images,
116
+ collectFonts: collect_fonts,
117
+ checkoutEveryNms: _constants.CHECKOUT_MS[this.parent.mode],
118
+ recordAfter: 'DOMContentLoaded'
119
+ });
120
+ } catch (err) {
121
+ this.parent.ee.emit('internal-error', [err]);
122
+ }
118
123
  this.stopRecording = () => {
119
- this.recording = false;
120
- this.notified = false;
121
- this.parent.ee.emit(_constants.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, [false, this.parent.mode]);
124
+ this.parent.agentRef.runtime.isRecording = false;
122
125
  stop?.();
123
126
  };
124
127
  }
@@ -165,16 +168,12 @@ class Recorder {
165
168
  /** Store a payload in the buffer (this.#events). This should be the callback to the recording lib noticing a mutation */
166
169
  store(event, isCheckout) {
167
170
  if (!event) return;
168
- if (this.parent.agentRef.runtime?.session?.isAfterSessionExpiry(event.timestamp)) {
171
+ if (this.parent.agentRef.runtime.session?.isAfterSessionExpiry(event.timestamp)) {
169
172
  (0, _handle.handle)(_constants3.SUPPORTABILITY_METRIC_CHANNEL, ['Session/Expired/SessionReplay/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
170
173
  return;
171
174
  }
172
175
  if (!(this.parent instanceof _aggregateBase.AggregateBase) && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
173
176
  if (this.parent.blocked) return;
174
- if (!this.notified) {
175
- this.parent.ee.emit(_constants.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, [true, this.parent.mode]);
176
- this.notified = true;
177
- }
178
177
  if (this.parent.timeKeeper?.ready && !event.__newrelic) {
179
178
  event.__newrelic = (0, _utils.buildNRMetaNode)(event.timestamp, this.parent.timeKeeper);
180
179
  event.timestamp = this.parent.timeKeeper.correctAbsoluteTimestamp(event.timestamp);
@@ -219,7 +218,7 @@ class Recorder {
219
218
  /** force the recording lib to take a full DOM snapshot. This needs to occur in certain cases, like visibility changes */
220
219
  takeFullSnapshot() {
221
220
  try {
222
- if (!this.recording) return;
221
+ if (!this.parent.agentRef.runtime.isRecording) return;
223
222
  _rrweb.record.takeFullSnapshot();
224
223
  } catch (err) {
225
224
  // in the off chance we think we are recording, but rrweb does not, rrweb's lib will throw an error. This catch is just a precaution
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.EntityManager = void 0;
7
+ var _agentConstants = require("../../common/constants/agent-constants");
7
8
  /**
8
9
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
10
  * SPDX-License-Identifier: Apache-2.0
@@ -12,16 +13,14 @@ exports.EntityManager = void 0;
12
13
  class EntityManager {
13
14
  #entities = new Map();
14
15
  #entityGuidLookup = {};
15
- #defaultEntity = null;
16
16
  constructor(agentRef) {
17
17
  this.agentRef = agentRef;
18
- this.#defaultEntity = {
18
+ this.#entities.set(_agentConstants.DEFAULT_KEY, {
19
19
  licenseKey: agentRef.info.licenseKey,
20
20
  applicationID: agentRef.info.applicationID
21
- };
21
+ });
22
22
  }
23
- get(entityGuid) {
24
- if (!entityGuid) return this.#defaultEntity;
23
+ get(entityGuid = _agentConstants.DEFAULT_KEY) {
25
24
  return this.#entities.get(entityGuid);
26
25
  }
27
26
  getEntityGuidFor(licenseKey, applicationID) {
@@ -41,7 +40,7 @@ class EntityManager {
41
40
  this.#entities.clear();
42
41
  }
43
42
  setDefaultEntity(entity) {
44
- this.#defaultEntity = entity;
43
+ this.#entities.set(_agentConstants.DEFAULT_KEY, entity);
45
44
  }
46
45
  }
47
46
  exports.EntityManager = EntityManager;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.EventStoreManager = void 0;
7
+ var _agentConstants = require("../../common/constants/agent-constants");
7
8
  var _globalEvent = require("../../common/dispatch/global-event");
8
9
  var _featureFlags = require("../../common/util/feature-flags");
9
10
  var _target = require("../../common/util/target");
@@ -12,7 +13,6 @@ var _target = require("../../common/util/target");
12
13
  * SPDX-License-Identifier: Apache-2.0
13
14
  */
14
15
 
15
- const DEFAULT_KEY = 'NR_CONTAINER_AGENT'; // this is the default entity guid used for the default storage instance
16
16
  /**
17
17
  * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
18
18
  * The purpose is so the harvester can send data to different apps within the same agent. Each feature should have a manager if it needs this capability.
@@ -28,7 +28,7 @@ class EventStoreManager {
28
28
  this.agentRef = agentRef;
29
29
  this.entityManager = agentRef.runtime.entityManager;
30
30
  this.StorageClass = storageClass;
31
- this.appStorageMap = new Map([[DEFAULT_KEY, new this.StorageClass()]]);
31
+ this.appStorageMap = new Map([[_agentConstants.DEFAULT_KEY, new this.StorageClass()]]);
32
32
  this.featureName = featureName;
33
33
  this.setEventStore(defaultEntityGuid);
34
34
  }
@@ -38,7 +38,7 @@ class EventStoreManager {
38
38
  * @param {string=} targetEntityGuid the lookup
39
39
  * @returns {*} ALWAYS returns a storage instance
40
40
  */
41
- #getEventStore(targetEntityGuid = DEFAULT_KEY) {
41
+ #getEventStore(targetEntityGuid = _agentConstants.DEFAULT_KEY) {
42
42
  if (!this.appStorageMap.has(targetEntityGuid)) this.setEventStore(targetEntityGuid);
43
43
  return this.appStorageMap.get(targetEntityGuid);
44
44
  }
@@ -46,7 +46,7 @@ class EventStoreManager {
46
46
  /** we should already have an event store for the default */
47
47
  if (!targetEntityGuid) return;
48
48
  /** if the target is the container agent, SHARE the default storage -- otherwise create a new event store */
49
- const eventStorage = (0, _target.isContainerAgentTarget)(this.entityManager.get(targetEntityGuid), this.agentRef) ? this.appStorageMap.get(DEFAULT_KEY) : new this.StorageClass();
49
+ const eventStorage = (0, _target.isContainerAgentTarget)(this.entityManager.get(targetEntityGuid), this.agentRef) ? this.appStorageMap.get(_agentConstants.DEFAULT_KEY) : new this.StorageClass();
50
50
  this.appStorageMap.set(targetEntityGuid, eventStorage);
51
51
  }
52
52
 
@@ -102,6 +102,10 @@ class EventStoreManager {
102
102
  }];
103
103
  const allPayloads = [];
104
104
  this.appStorageMap.forEach((eventStore, targetEntityGuid) => {
105
+ // We shouldnt harvest unless we have a valid entity guid. It was ONLY stored under the default key temporarily
106
+ // until a real key was returned in the RUM call. The real key SHARES the event store with the default key, and
107
+ // should be the key that is honored to get the event store to ensure a valid connection was made.
108
+ if (targetEntityGuid === _agentConstants.DEFAULT_KEY) return;
105
109
  const targetApp = this.entityManager.get(targetEntityGuid);
106
110
  if (targetApp) allPayloads.push({
107
111
  targetApp,
@@ -3,14 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.spaPrefix = exports.replayRunning = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
6
+ exports.spaPrefix = exports.prefix = exports.WRAP_LOGGER = exports.START = exports.SET_USER_ID = exports.SET_PAGE_VIEW_NAME = exports.SET_ERROR_HANDLER = exports.SET_CUSTOM_ATTRIBUTE = exports.SET_CURRENT_ROUTE_NAME = exports.SET_APPLICATION_VERSION = exports.REGISTER = exports.RECORD_REPLAY = exports.RECORD_CUSTOM_EVENT = exports.PAUSE_REPLAY = exports.NOTICE_ERROR = exports.LOG = exports.INTERACTION = exports.FINISHED = exports.ADD_TO_TRACE = exports.ADD_RELEASE = exports.ADD_PAGE_ACTION = void 0;
7
7
  /**
8
8
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
9
  * SPDX-License-Identifier: Apache-2.0
10
10
  */
11
11
  const prefix = exports.prefix = 'api-';
12
12
  const spaPrefix = exports.spaPrefix = prefix + 'ixn-';
13
- const replayRunning = exports.replayRunning = {};
14
13
  const ADD_PAGE_ACTION = exports.ADD_PAGE_ACTION = 'addPageAction';
15
14
  const ADD_TO_TRACE = exports.ADD_TO_TRACE = 'addToTrace';
16
15
  const ADD_RELEASE = exports.ADD_RELEASE = 'addRelease';
@@ -6,11 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.noticeError = noticeError;
7
7
  exports.setupNoticeErrorAPI = setupNoticeErrorAPI;
8
8
  var _handle = require("../../common/event-emitter/handle");
9
- var _constants = require("../../common/session/constants");
10
9
  var _now = require("../../common/timing/now");
11
- var _constants2 = require("../../features/session_replay/constants");
12
10
  var _features = require("../features/features");
13
- var _constants3 = require("./constants");
11
+ var _constants = require("./constants");
14
12
  var _sharedHandlers = require("./sharedHandlers");
15
13
  /**
16
14
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
@@ -18,13 +16,9 @@ var _sharedHandlers = require("./sharedHandlers");
18
16
  */
19
17
 
20
18
  function setupNoticeErrorAPI(agent) {
21
- (0, _sharedHandlers.setupAPI)(_constants3.NOTICE_ERROR, (err, customAttributes) => noticeError(err, customAttributes, agent), agent);
22
- _constants3.replayRunning[agent.agentIdentifier] ??= _constants.MODE.OFF;
23
- agent.ee.on(_constants2.SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, isRunning => {
24
- _constants3.replayRunning[agent.agentIdentifier] = isRunning;
25
- });
19
+ (0, _sharedHandlers.setupAPI)(_constants.NOTICE_ERROR, (err, customAttributes) => noticeError(err, customAttributes, agent), agent);
26
20
  }
27
21
  function noticeError(err, customAttributes, agentRef, targetEntityGuid, timestamp = (0, _now.now)()) {
28
22
  if (typeof err === 'string') err = new Error(err);
29
- (0, _handle.handle)('err', [err, timestamp, false, customAttributes, !!_constants3.replayRunning[agentRef.agentIdentifier], undefined, targetEntityGuid], undefined, _features.FEATURE_NAMES.jserrors, agentRef.ee);
23
+ (0, _handle.handle)('err', [err, timestamp, false, customAttributes, agentRef.runtime.isRecording, undefined, targetEntityGuid], undefined, _features.FEATURE_NAMES.jserrors, agentRef.ee);
30
24
  }
@@ -64,13 +64,7 @@ function appendJsAttribute(agent, key, value, apiName, addToBrowserStorage) {
64
64
  if (value === null) {
65
65
  delete currentInfo.jsAttributes[key];
66
66
  } else {
67
- agent.info = {
68
- ...agent.info,
69
- jsAttributes: {
70
- ...currentInfo.jsAttributes,
71
- [key]: value
72
- }
73
- };
67
+ currentInfo.jsAttributes[key] = value;
74
68
  }
75
69
  if (addToBrowserStorage || value === null) (0, _handle.handle)(_constants2.prefix + apiName, [(0, _now.now)(), key, value], undefined, 'session', agent.ee);
76
70
  }
@@ -19,7 +19,7 @@ export function getModeledObject(obj, model) {
19
19
  }
20
20
  if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (typeof obj[key] === 'object' && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
21
21
  } catch (e) {
22
- warn(1, e);
22
+ if (!output[key]) warn(1, e);
23
23
  }
24
24
  }
25
25
  return output;
@@ -10,7 +10,7 @@ import { BUILD_ENV, DIST_METHOD, VERSION } from "../constants/env.npm";
10
10
  * Module level count of harvests. This property will auto-increment each time it is accessed.
11
11
  * @type {number}
12
12
  */
13
- let harvestCount = 0;
13
+ let _harvestCount = 0;
14
14
  const ReadOnly = {
15
15
  buildEnv: BUILD_ENV,
16
16
  distMethod: DIST_METHOD,
@@ -26,6 +26,8 @@ const RuntimeModel = {
26
26
  entityManager: undefined,
27
27
  harvester: undefined,
28
28
  isolatedBacklog: false,
29
+ isRecording: false,
30
+ // true when actively recording, false when paused or stopped
29
31
  loaderType: undefined,
30
32
  maxBytes: 30000,
31
33
  obfuscator: undefined,
@@ -35,7 +37,7 @@ const RuntimeModel = {
35
37
  session: undefined,
36
38
  timeKeeper: undefined,
37
39
  get harvestCount() {
38
- return ++harvestCount;
40
+ return ++_harvestCount;
39
41
  }
40
42
  };
41
43
  export const mergeRuntime = runtime => {
@@ -3,4 +3,5 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  export const IDEAL_PAYLOAD_SIZE = 64000;
6
- export const MAX_PAYLOAD_SIZE = 1000000;
6
+ export const MAX_PAYLOAD_SIZE = 1000000;
7
+ export const DEFAULT_KEY = 'NR_CONTAINER_AGENT';
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.290.0";
14
+ export const VERSION = "1.290.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.290.0";
14
+ export const VERSION = "1.290.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -9,7 +9,6 @@ import { FEATURE_NAME } from '../constants';
9
9
  import { globalScope } from '../../../common/constants/runtime';
10
10
  import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
11
11
  import { now } from '../../../common/timing/now';
12
- import { SR_EVENT_EMITTER_TYPES } from '../../session_replay/constants';
13
12
  import { castError, castErrorEvent, castPromiseRejectionEvent } from '../shared/cast-error';
14
13
  import { setupNoticeErrorAPI } from '../../../loaders/api/noticeError';
15
14
  import { setupSetErrorHandlerAPI } from '../../../loaders/api/setErrorHandler';
@@ -17,7 +16,6 @@ import { setupAddReleaseAPI } from '../../../loaders/api/addRelease';
17
16
  import { setupRegisterAPI } from '../../../loaders/api/register';
18
17
  export class Instrument extends InstrumentBase {
19
18
  static featureName = FEATURE_NAME;
20
- #replayRunning = false;
21
19
  constructor(agentRef) {
22
20
  super(agentRef, FEATURE_NAME);
23
21
 
@@ -32,20 +30,17 @@ export class Instrument extends InstrumentBase {
32
30
  } catch (e) {}
33
31
  this.ee.on('internal-error', (error, reason) => {
34
32
  if (!this.abortHandler) return;
35
- handle('ierr', [castError(error), now(), true, {}, this.#replayRunning, reason], undefined, this.featureName, this.ee);
36
- });
37
- this.ee.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, isRunning => {
38
- this.#replayRunning = isRunning;
33
+ handle('ierr', [castError(error), now(), true, {}, agentRef.runtime.isRecording, reason], undefined, this.featureName, this.ee);
39
34
  });
40
35
  globalScope.addEventListener('unhandledrejection', promiseRejectionEvent => {
41
36
  if (!this.abortHandler) return;
42
37
  handle('err', [castPromiseRejectionEvent(promiseRejectionEvent), now(), false, {
43
38
  unhandledPromiseRejection: 1
44
- }, this.#replayRunning], undefined, this.featureName, this.ee);
39
+ }, agentRef.runtime.isRecording], undefined, this.featureName, this.ee);
45
40
  }, eventListenerOpts(false, this.removeOnAbort?.signal));
46
41
  globalScope.addEventListener('error', errorEvent => {
47
42
  if (!this.abortHandler) return;
48
- handle('err', [castErrorEvent(errorEvent), now(), false, {}, this.#replayRunning], undefined, this.featureName, this.ee);
43
+ handle('err', [castErrorEvent(errorEvent), now(), false, {}, agentRef.runtime.isRecording], undefined, this.featureName, this.ee);
49
44
  }, eventListenerOpts(false, this.removeOnAbort?.signal));
50
45
  this.abortHandler = this.#abort; // we also use this as a flag to denote that the feature is active or on and handling errors
51
46
  this.importAggregator(agentRef, () => import(/* webpackChunkName: "jserrors-aggregate" */'../aggregate'));
@@ -90,7 +90,7 @@ export class Aggregate extends AggregateBase {
90
90
  this.entitled = !!entitled;
91
91
  if (!this.entitled) {
92
92
  this.deregisterDrain();
93
- if (this.recorder?.recording) {
93
+ if (this.agentRef.runtime.isRecording) {
94
94
  this.abort(ABORT_REASONS.ENTITLEMENTS);
95
95
  this.reportSupportabilityMetric('SessionReplay/EnabledNotEntitled/Detected');
96
96
  }
@@ -131,7 +131,7 @@ export class Aggregate extends AggregateBase {
131
131
  this.mode = MODE.FULL;
132
132
  // if the error was noticed AFTER the recorder was already imported....
133
133
  if (this.recorder && this.initialized) {
134
- if (!this.recorder.recording) this.recorder.startRecording();
134
+ if (!this.agentRef.runtime.isRecording) this.recorder.startRecording();
135
135
  this.syncWithSessionManager({
136
136
  sessionReplayMode: this.mode
137
137
  });
@@ -161,7 +161,7 @@ export class Aggregate extends AggregateBase {
161
161
  timeKeeper
162
162
  } = this.agentRef.runtime;
163
163
  this.timeKeeper = timeKeeper;
164
- if (this.recorder?.parent.trigger === TRIGGERS.API && this.recorder?.recording) {
164
+ if (this.recorder?.parent.trigger === TRIGGERS.API && this.agentRef.runtime.isRecording) {
165
165
  this.mode = MODE.FULL;
166
166
  } else if (!session.isNew && !ignoreSession) {
167
167
  // inherit the mode of the existing session
@@ -199,7 +199,7 @@ export class Aggregate extends AggregateBase {
199
199
  this.prepUtils().then(() => this.agentRef.runtime.harvester.triggerHarvestFor(this));
200
200
  }
201
201
  await this.prepUtils();
202
- if (!this.recorder.recording) this.recorder.startRecording();
202
+ if (!this.agentRef.runtime.isRecording) this.recorder.startRecording();
203
203
  this.syncWithSessionManager({
204
204
  sessionReplayMode: this.mode
205
205
  });
@@ -8,7 +8,6 @@ export const FEATURE_NAME = FEATURE_NAMES.sessionReplay;
8
8
  export const SR_EVENT_EMITTER_TYPES = {
9
9
  RECORD: 'recordReplay',
10
10
  PAUSE: 'pauseReplay',
11
- REPLAY_RUNNING: 'replayRunning',
12
11
  ERROR_DURING_REPLAY: 'errorDuringReplay'
13
12
  };
14
13
  export const AVG_COMPRESSION = 0.12;