@newrelic/browser-agent 1.288.0 → 1.288.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
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.288.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.288.0...v1.288.1) (2025-04-18)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Call handle directly for submitting SM from SR recorder ([#1453](https://github.com/newrelic/newrelic-browser-agent/issues/1453)) ([4920580](https://github.com/newrelic/newrelic-browser-agent/commit/49205807b6038afb32e3f04ebabedfe5fc11456b))
12
+ * Ensure event buffer always exists ([#1452](https://github.com/newrelic/newrelic-browser-agent/issues/1452)) ([56e75b2](https://github.com/newrelic/newrelic-browser-agent/commit/56e75b243b87d1d44e8014ac0ad5f408f0d145c5))
13
+
6
14
  ## [1.288.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.287.0...v1.288.0) (2025-04-16)
7
15
 
8
16
 
@@ -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.288.0";
20
+ const VERSION = exports.VERSION = "1.288.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.288.0";
20
+ const VERSION = exports.VERSION = "1.288.1";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -166,7 +166,7 @@ class Recorder {
166
166
  store(event, isCheckout) {
167
167
  if (!event) return;
168
168
  if (this.parent.agentRef.runtime?.session?.isAfterSessionExpiry(event.timestamp)) {
169
- this.parent.reportSupportabilityMetric('Session/Expired/SessionReplay/Seen');
169
+ (0, _handle.handle)(_constants3.SUPPORTABILITY_METRIC_CHANNEL, ['Session/Expired/SessionReplay/Seen'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
170
170
  return;
171
171
  }
172
172
  if (!(this.parent instanceof _aggregateBase.AggregateBase) && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
@@ -33,14 +33,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
33
33
  if (agentRef.runtime.session?.isNew) this.initialPageLoadInteraction.customAttributes.isFirstOfSession = true; // mark the hard page load as first of its session
34
34
  this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
35
35
  const ixn = this.initialPageLoadInteraction;
36
- /** this.events (ixns to harvest) has already been set up, use it immediately */
37
- if (this.interactionsToHarvest) this.interactionsToHarvest.add(ixn);else {
38
- /** this.events (ixns to harvest) hasnt been initialized yet... wait for it */
39
- this.ee.on('entity-added', () => {
40
- this.interactionsToHarvest = this.events;
41
- this.interactionsToHarvest.add(ixn);
42
- });
43
- }
36
+ this.interactionsToHarvest.add(ixn);
44
37
  this.initialPageLoadInteraction = null;
45
38
  });
46
39
  _timeToFirstByte.timeToFirstByte.subscribe(({
@@ -39,11 +39,13 @@ class AggregateBase extends _featureBase.FeatureBase {
39
39
  this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
40
40
 
41
41
  const agentEntityGuid = this.agentRef?.runtime?.appMetadata?.agents?.[0]?.entityGuid;
42
- if (agentEntityGuid) {
43
- this.#setupEventStore(agentEntityGuid); // if there's no entity guid, wont dont anything, and will wait for rum flags
44
- } else {
42
+ this.#setupEventStore(agentEntityGuid);
43
+ if (!agentEntityGuid) {
44
+ /** wait for the entity guid from the rum response and use to it to further configure things to set the default entity to share an indexed entity with entityGuid */
45
45
  this.ee.on('entity-added', entity => {
46
- this.#setupEventStore(entity.entityGuid);
46
+ // not all event managers have this fn, like ST and SR
47
+ // this allows the lookup to work for the default and an entityGuid without creating two separate buffers
48
+ this.events?.setEventStore?.(entity.entityGuid);
47
49
  });
48
50
  }
49
51
  }
@@ -54,7 +56,7 @@ class AggregateBase extends _featureBase.FeatureBase {
54
56
  * @returns {void}
55
57
  */
56
58
  #setupEventStore(entityGuid) {
57
- if (this.events || !entityGuid) return;
59
+ if (this.events) return;
58
60
  switch (this.featureName) {
59
61
  // SessionTrace + Replay have their own storage mechanisms.
60
62
  case _features.FEATURE_NAMES.sessionTrace:
@@ -6,11 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.EventStoreManager = void 0;
7
7
  var _globalEvent = require("../../common/dispatch/global-event");
8
8
  var _featureFlags = require("../../common/util/feature-flags");
9
+ var _target = require("../../common/util/target");
9
10
  /**
10
11
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
11
12
  * SPDX-License-Identifier: Apache-2.0
12
13
  */
13
14
 
15
+ const DEFAULT_KEY = 'NR_CONTAINER_AGENT'; // this is the default entity guid used for the default storage instance
14
16
  /**
15
17
  * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
16
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.
@@ -19,14 +21,16 @@ class EventStoreManager {
19
21
  /**
20
22
  * @param {object} agentRef - reference to base agent class
21
23
  * @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
24
+ * @param {string} [defaultEntityGuid] - the entity guid to use as the default storage instance; if not provided, a new one is created
25
+ * @param {string} featureName - the name of the feature this manager is for; used for event dispatching
22
26
  */
23
27
  constructor(agentRef, storageClass, defaultEntityGuid, featureName) {
24
28
  this.agentRef = agentRef;
25
29
  this.entityManager = agentRef.runtime.entityManager;
26
30
  this.StorageClass = storageClass;
27
- this.appStorageMap = new Map();
28
- this.defaultEntity = this.#getEventStore(defaultEntityGuid);
31
+ this.appStorageMap = new Map([[DEFAULT_KEY, new this.StorageClass()]]);
29
32
  this.featureName = featureName;
33
+ this.setEventStore(defaultEntityGuid);
30
34
  }
31
35
 
32
36
  /**
@@ -34,11 +38,17 @@ class EventStoreManager {
34
38
  * @param {string=} targetEntityGuid the lookup
35
39
  * @returns {*} ALWAYS returns a storage instance
36
40
  */
37
- #getEventStore(targetEntityGuid) {
38
- if (!targetEntityGuid) return this.defaultEntity;
39
- if (!this.appStorageMap.has(targetEntityGuid)) this.appStorageMap.set(targetEntityGuid, new this.StorageClass());
41
+ #getEventStore(targetEntityGuid = DEFAULT_KEY) {
42
+ if (!this.appStorageMap.has(targetEntityGuid)) this.setEventStore(targetEntityGuid);
40
43
  return this.appStorageMap.get(targetEntityGuid);
41
44
  }
45
+ setEventStore(targetEntityGuid) {
46
+ /** we should already have an event store for the default */
47
+ if (!targetEntityGuid) return;
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();
50
+ this.appStorageMap.set(targetEntityGuid, eventStorage);
51
+ }
42
52
 
43
53
  // This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
44
54
 
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.288.0";
14
+ export const VERSION = "1.288.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.288.0";
14
+ export const VERSION = "1.288.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -159,7 +159,7 @@ export class Recorder {
159
159
  store(event, isCheckout) {
160
160
  if (!event) return;
161
161
  if (this.parent.agentRef.runtime?.session?.isAfterSessionExpiry(event.timestamp)) {
162
- this.parent.reportSupportabilityMetric('Session/Expired/SessionReplay/Seen');
162
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['Session/Expired/SessionReplay/Seen'], undefined, FEATURE_NAMES.metrics, this.ee);
163
163
  return;
164
164
  }
165
165
  if (!(this.parent instanceof AggregateBase) && this.#preloaded.length) this.currentBufferTarget = this.#preloaded[this.#preloaded.length - 1];else this.currentBufferTarget = this.#events;
@@ -26,14 +26,7 @@ export class Aggregate extends AggregateBase {
26
26
  if (agentRef.runtime.session?.isNew) this.initialPageLoadInteraction.customAttributes.isFirstOfSession = true; // mark the hard page load as first of its session
27
27
  this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
28
28
  const ixn = this.initialPageLoadInteraction;
29
- /** this.events (ixns to harvest) has already been set up, use it immediately */
30
- if (this.interactionsToHarvest) this.interactionsToHarvest.add(ixn);else {
31
- /** this.events (ixns to harvest) hasnt been initialized yet... wait for it */
32
- this.ee.on('entity-added', () => {
33
- this.interactionsToHarvest = this.events;
34
- this.interactionsToHarvest.add(ixn);
35
- });
36
- }
29
+ this.interactionsToHarvest.add(ixn);
37
30
  this.initialPageLoadInteraction = null;
38
31
  });
39
32
  timeToFirstByte.subscribe(({
@@ -32,11 +32,13 @@ export class AggregateBase extends FeatureBase {
32
32
  this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
33
33
 
34
34
  const agentEntityGuid = this.agentRef?.runtime?.appMetadata?.agents?.[0]?.entityGuid;
35
- if (agentEntityGuid) {
36
- this.#setupEventStore(agentEntityGuid); // if there's no entity guid, wont dont anything, and will wait for rum flags
37
- } else {
35
+ this.#setupEventStore(agentEntityGuid);
36
+ if (!agentEntityGuid) {
37
+ /** wait for the entity guid from the rum response and use to it to further configure things to set the default entity to share an indexed entity with entityGuid */
38
38
  this.ee.on('entity-added', entity => {
39
- this.#setupEventStore(entity.entityGuid);
39
+ // not all event managers have this fn, like ST and SR
40
+ // this allows the lookup to work for the default and an entityGuid without creating two separate buffers
41
+ this.events?.setEventStore?.(entity.entityGuid);
40
42
  });
41
43
  }
42
44
  }
@@ -47,7 +49,7 @@ export class AggregateBase extends FeatureBase {
47
49
  * @returns {void}
48
50
  */
49
51
  #setupEventStore(entityGuid) {
50
- if (this.events || !entityGuid) return;
52
+ if (this.events) return;
51
53
  switch (this.featureName) {
52
54
  // SessionTrace + Replay have their own storage mechanisms.
53
55
  case FEATURE_NAMES.sessionTrace:
@@ -4,7 +4,8 @@
4
4
  */
5
5
  import { dispatchGlobalEvent } from '../../common/dispatch/global-event';
6
6
  import { activatedFeatures } from '../../common/util/feature-flags';
7
-
7
+ import { isContainerAgentTarget } from '../../common/util/target';
8
+ const DEFAULT_KEY = 'NR_CONTAINER_AGENT'; // this is the default entity guid used for the default storage instance
8
9
  /**
9
10
  * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
10
11
  * 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.
@@ -13,14 +14,16 @@ export class EventStoreManager {
13
14
  /**
14
15
  * @param {object} agentRef - reference to base agent class
15
16
  * @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
17
+ * @param {string} [defaultEntityGuid] - the entity guid to use as the default storage instance; if not provided, a new one is created
18
+ * @param {string} featureName - the name of the feature this manager is for; used for event dispatching
16
19
  */
17
20
  constructor(agentRef, storageClass, defaultEntityGuid, featureName) {
18
21
  this.agentRef = agentRef;
19
22
  this.entityManager = agentRef.runtime.entityManager;
20
23
  this.StorageClass = storageClass;
21
- this.appStorageMap = new Map();
22
- this.defaultEntity = this.#getEventStore(defaultEntityGuid);
24
+ this.appStorageMap = new Map([[DEFAULT_KEY, new this.StorageClass()]]);
23
25
  this.featureName = featureName;
26
+ this.setEventStore(defaultEntityGuid);
24
27
  }
25
28
 
26
29
  /**
@@ -28,11 +31,17 @@ export class EventStoreManager {
28
31
  * @param {string=} targetEntityGuid the lookup
29
32
  * @returns {*} ALWAYS returns a storage instance
30
33
  */
31
- #getEventStore(targetEntityGuid) {
32
- if (!targetEntityGuid) return this.defaultEntity;
33
- if (!this.appStorageMap.has(targetEntityGuid)) this.appStorageMap.set(targetEntityGuid, new this.StorageClass());
34
+ #getEventStore(targetEntityGuid = DEFAULT_KEY) {
35
+ if (!this.appStorageMap.has(targetEntityGuid)) this.setEventStore(targetEntityGuid);
34
36
  return this.appStorageMap.get(targetEntityGuid);
35
37
  }
38
+ setEventStore(targetEntityGuid) {
39
+ /** we should already have an event store for the default */
40
+ if (!targetEntityGuid) return;
41
+ /** if the target is the container agent, SHARE the default storage -- otherwise create a new event store */
42
+ const eventStorage = isContainerAgentTarget(this.entityManager.get(targetEntityGuid), this.agentRef) ? this.appStorageMap.get(DEFAULT_KEY) : new this.StorageClass();
43
+ this.appStorageMap.set(targetEntityGuid, eventStorage);
44
+ }
36
45
 
37
46
  // This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
38
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OA4DC;IAzDC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0F;IAuB1F,yBAA+B;IAC/B,0CAAiC;IACjC,sBAA4B;IA+B9B,qCAUC;IAED,0EAiBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAqB7B;;CA6FF;8BA/O6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OAoDC;IAjDC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0F;IAe1F,yBAA+B;IAC/B,0CAAiC;IACjC,sBAA4B;IA+B9B,qCAUC;IAED,0EAiBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAqB7B;;CA6FF;8BAvO6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAqBA;IACE;;;;OAIG;IACH,sBAHW,MAAM,eACN,MAAM,EAkBhB;IAdC,iBAAwB;IAIxB,gBAAqB;IA2BjB,YAAuI;IAW7I;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED;;OAEG;IACH,cAGC;IADC,6BAAmB;IAGrB,qCAEC;IAED;;;;;;OAMG;IACH,uDAJW,MAAM,GAAC,SAAS,SAyB1B;IAED;;;;;;;OAOG;IACH,4BALG;QAAwB,SAAS,GAAzB,MAAM,YAAC;KACf,QAQF;IAED;;;OAGG;IACH,6CAsBC;IAED;;;OAGG;IACH,2CAOC;IALC,gBAA6C;IAO/C;;;;OAIG;IACH,uCAHW,GAAC,UACD,GAAC,QAIX;;CACF;4BAxM2B,gBAAgB"}
1
+ {"version":3,"file":"aggregate-base.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/aggregate-base.js"],"names":[],"mappings":"AAqBA;IACE;;;;OAIG;IACH,sBAHW,MAAM,eACN,MAAM,EAoBhB;IAhBC,iBAAwB;IAIxB,gBAAqB;IA6BjB,YAAuI;IAW7I;;;;OAIG;IACH,yBAHW,MAAM,EAAE,gBAwBlB;IAED;;OAEG;IACH,cAGC;IADC,6BAAmB;IAGrB,qCAEC;IAED;;;;;;OAMG;IACH,uDAJW,MAAM,GAAC,SAAS,SAyB1B;IAED;;;;;;;OAOG;IACH,4BALG;QAAwB,SAAS,GAAzB,MAAM,YAAC;KACf,QAQF;IAED;;;OAGG;IACH,6CAsBC;IAED;;;OAGG;IACH,2CAOC;IALC,gBAA6C;IAO/C;;;;OAIG;IACH,uCAHW,GAAC,UACD,GAAC,QAIX;;CACF;4BA1M2B,gBAAgB"}
@@ -6,14 +6,16 @@ export class EventStoreManager {
6
6
  /**
7
7
  * @param {object} agentRef - reference to base agent class
8
8
  * @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
9
+ * @param {string} [defaultEntityGuid] - the entity guid to use as the default storage instance; if not provided, a new one is created
10
+ * @param {string} featureName - the name of the feature this manager is for; used for event dispatching
9
11
  */
10
- constructor(agentRef: object, storageClass: EventBuffer | EventAggregator, defaultEntityGuid: any, featureName: any);
12
+ constructor(agentRef: object, storageClass: EventBuffer | EventAggregator, defaultEntityGuid?: string, featureName: string);
11
13
  agentRef: object;
12
14
  entityManager: any;
13
15
  StorageClass: any;
14
- appStorageMap: Map<any, any>;
15
- defaultEntity: any;
16
- featureName: any;
16
+ appStorageMap: Map<string, any>;
17
+ featureName: string;
18
+ setEventStore(targetEntityGuid: any): void;
17
19
  /**
18
20
  * Calls the isEmpty method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
19
21
  * @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
@@ -1 +1 @@
1
- {"version":3,"file":"event-store-manager.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-store-manager.js"],"names":[],"mappings":"AAOA;;;GAGG;AACH;IACE;;;OAGG;IACH,sBAHW,MAAM,gBACN,WAAW,GAAC,eAAe,4CASrC;IANC,iBAAwB;IACxB,mBAAmD;IACnD,kBAAgC;IAChC,6BAA8B;IAC9B,mBAA2D;IAC3D,iBAA8B;IAgBhC;;;;;OAKG;IACH,uBAJW,MAAM,0BAEJ,OAAO,CASnB;IAED;;;;;OAKG;IACH,WAJW,MAAM,oBACN,MAAM,GACJ,OAAO,CAYnB;IAED,0GAA0G;IAC1G,8DAEC;IAED;;;;;OAKG;IACH,WAJW,MAAM,YAAC,gCAYjB;IAED;;;;OAIG;IACH,2BAHW,GAAC,OAKX;IAED;;;;;OAKG;IACH,iCAJW,GAAC,oBACD,GAAC,OAKX;IAED;;;;;OAKG;IACH,oBAJW,GAAC,oBACD,GAAC,OAMX;IAED;;;;;OAKG;IACH,qBAJW,GAAC,oBACD,GAAC,OAMX;IAGD,2DAEC;IAED,0DAEC;;CACF"}
1
+ {"version":3,"file":"event-store-manager.d.ts","sourceRoot":"","sources":["../../../../src/features/utils/event-store-manager.js"],"names":[],"mappings":"AASA;;;GAGG;AACH;IACE;;;;;OAKG;IACH,sBALW,MAAM,gBACN,WAAW,GAAC,eAAe,sBAC3B,MAAM,eACN,MAAM,EAShB;IANC,iBAAwB;IACxB,mBAAmD;IACnD,kBAAgC;IAChC,gCAAsE;IACtE,oBAA8B;IAchC,2CAQC;IAID;;;;;OAKG;IACH,uBAJW,MAAM,0BAEJ,OAAO,CASnB;IAED;;;;;OAKG;IACH,WAJW,MAAM,oBACN,MAAM,GACJ,OAAO,CAYnB;IAED,0GAA0G;IAC1G,8DAEC;IAED;;;;;OAKG;IACH,WAJW,MAAM,YAAC,gCAYjB;IAED;;;;OAIG;IACH,2BAHW,GAAC,OAKX;IAED;;;;;OAKG;IACH,iCAJW,GAAC,oBACD,GAAC,OAKX;IAED;;;;;OAKG;IACH,oBAJW,GAAC,oBACD,GAAC,OAMX;IAED;;;;;OAKG;IACH,qBAJW,GAAC,oBACD,GAAC,OAMX;IAGD,2DAEC;IAED,0DAEC;;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.288.0",
3
+ "version": "1.288.1",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -155,7 +155,7 @@ export class Recorder {
155
155
  store (event, isCheckout) {
156
156
  if (!event) return
157
157
  if (this.parent.agentRef.runtime?.session?.isAfterSessionExpiry(event.timestamp)) {
158
- this.parent.reportSupportabilityMetric('Session/Expired/SessionReplay/Seen')
158
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['Session/Expired/SessionReplay/Seen'], undefined, FEATURE_NAMES.metrics, this.ee)
159
159
  return
160
160
  }
161
161
 
@@ -26,15 +26,7 @@ export class Aggregate extends AggregateBase {
26
26
  if (agentRef.runtime.session?.isNew) this.initialPageLoadInteraction.customAttributes.isFirstOfSession = true // mark the hard page load as first of its session
27
27
  this.initialPageLoadInteraction.forceSave = true // unless forcibly ignored, iPL always finish by default
28
28
  const ixn = this.initialPageLoadInteraction
29
- /** this.events (ixns to harvest) has already been set up, use it immediately */
30
- if (this.interactionsToHarvest) this.interactionsToHarvest.add(ixn)
31
- else {
32
- /** this.events (ixns to harvest) hasnt been initialized yet... wait for it */
33
- this.ee.on('entity-added', () => {
34
- this.interactionsToHarvest = this.events
35
- this.interactionsToHarvest.add(ixn)
36
- })
37
- }
29
+ this.interactionsToHarvest.add(ixn)
38
30
  this.initialPageLoadInteraction = null
39
31
  })
40
32
  timeToFirstByte.subscribe(({ attrs }) => {
@@ -34,11 +34,13 @@ export class AggregateBase extends FeatureBase {
34
34
  this.harvestOpts = {} // features aggregate classes can define custom opts for when their harvest is called
35
35
 
36
36
  const agentEntityGuid = this.agentRef?.runtime?.appMetadata?.agents?.[0]?.entityGuid
37
- if (agentEntityGuid) {
38
- this.#setupEventStore(agentEntityGuid) // if there's no entity guid, wont dont anything, and will wait for rum flags
39
- } else {
37
+ this.#setupEventStore(agentEntityGuid)
38
+ if (!agentEntityGuid) {
39
+ /** wait for the entity guid from the rum response and use to it to further configure things to set the default entity to share an indexed entity with entityGuid */
40
40
  this.ee.on('entity-added', entity => {
41
- this.#setupEventStore(entity.entityGuid)
41
+ // not all event managers have this fn, like ST and SR
42
+ // this allows the lookup to work for the default and an entityGuid without creating two separate buffers
43
+ this.events?.setEventStore?.(entity.entityGuid)
42
44
  })
43
45
  }
44
46
  }
@@ -49,7 +51,7 @@ export class AggregateBase extends FeatureBase {
49
51
  * @returns {void}
50
52
  */
51
53
  #setupEventStore (entityGuid) {
52
- if (this.events || !entityGuid) return
54
+ if (this.events) return
53
55
  switch (this.featureName) {
54
56
  // SessionTrace + Replay have their own storage mechanisms.
55
57
  case FEATURE_NAMES.sessionTrace:
@@ -4,7 +4,9 @@
4
4
  */
5
5
  import { dispatchGlobalEvent } from '../../common/dispatch/global-event'
6
6
  import { activatedFeatures } from '../../common/util/feature-flags'
7
+ import { isContainerAgentTarget } from '../../common/util/target'
7
8
 
9
+ const DEFAULT_KEY = 'NR_CONTAINER_AGENT' // this is the default entity guid used for the default storage instance
8
10
  /**
9
11
  * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
10
12
  * 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.
@@ -13,14 +15,16 @@ export class EventStoreManager {
13
15
  /**
14
16
  * @param {object} agentRef - reference to base agent class
15
17
  * @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
18
+ * @param {string} [defaultEntityGuid] - the entity guid to use as the default storage instance; if not provided, a new one is created
19
+ * @param {string} featureName - the name of the feature this manager is for; used for event dispatching
16
20
  */
17
21
  constructor (agentRef, storageClass, defaultEntityGuid, featureName) {
18
22
  this.agentRef = agentRef
19
23
  this.entityManager = agentRef.runtime.entityManager
20
24
  this.StorageClass = storageClass
21
- this.appStorageMap = new Map()
22
- this.defaultEntity = this.#getEventStore(defaultEntityGuid)
25
+ this.appStorageMap = new Map([[DEFAULT_KEY, new this.StorageClass()]])
23
26
  this.featureName = featureName
27
+ this.setEventStore(defaultEntityGuid)
24
28
  }
25
29
 
26
30
  /**
@@ -28,12 +32,21 @@ export class EventStoreManager {
28
32
  * @param {string=} targetEntityGuid the lookup
29
33
  * @returns {*} ALWAYS returns a storage instance
30
34
  */
31
- #getEventStore (targetEntityGuid) {
32
- if (!targetEntityGuid) return this.defaultEntity
33
- if (!this.appStorageMap.has(targetEntityGuid)) this.appStorageMap.set(targetEntityGuid, new this.StorageClass())
35
+ #getEventStore (targetEntityGuid = DEFAULT_KEY) {
36
+ if (!this.appStorageMap.has(targetEntityGuid)) this.setEventStore(targetEntityGuid)
34
37
  return this.appStorageMap.get(targetEntityGuid)
35
38
  }
36
39
 
40
+ setEventStore (targetEntityGuid) {
41
+ /** we should already have an event store for the default */
42
+ if (!targetEntityGuid) return
43
+ /** if the target is the container agent, SHARE the default storage -- otherwise create a new event store */
44
+ const eventStorage = (isContainerAgentTarget(this.entityManager.get(targetEntityGuid), this.agentRef))
45
+ ? this.appStorageMap.get(DEFAULT_KEY)
46
+ : new this.StorageClass()
47
+ this.appStorageMap.set(targetEntityGuid, eventStorage)
48
+ }
49
+
37
50
  // This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
38
51
 
39
52
  /**