@newrelic/browser-agent 1.286.0 → 1.287.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 (154) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/common/config/init-types.js +96 -0
  3. package/dist/cjs/common/config/init.js +9 -79
  4. package/dist/cjs/common/config/runtime.js +7 -6
  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/common/harvest/harvester.js +2 -2
  8. package/dist/cjs/common/util/feature-flags.js +4 -5
  9. package/dist/cjs/common/util/target.js +34 -0
  10. package/dist/cjs/features/ajax/aggregate/index.js +2 -1
  11. package/dist/cjs/features/generic_events/aggregate/index.js +10 -6
  12. package/dist/cjs/features/jserrors/aggregate/index.js +44 -22
  13. package/dist/cjs/features/logging/aggregate/index.js +17 -11
  14. package/dist/cjs/features/logging/shared/utils.js +3 -2
  15. package/dist/cjs/features/metrics/aggregate/index.js +6 -4
  16. package/dist/cjs/features/page_view_event/aggregate/index.js +60 -11
  17. package/dist/cjs/features/page_view_event/instrument/index.js +4 -0
  18. package/dist/cjs/features/session_replay/aggregate/index.js +8 -6
  19. package/dist/cjs/features/session_replay/instrument/index.js +1 -1
  20. package/dist/cjs/features/session_replay/shared/recorder-events.js +4 -2
  21. package/dist/cjs/features/session_replay/shared/recorder.js +12 -11
  22. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +1 -1
  23. package/dist/cjs/features/soft_navigations/aggregate/index.js +12 -2
  24. package/dist/cjs/features/spa/aggregate/index.js +3 -3
  25. package/dist/cjs/features/spa/aggregate/interaction.js +6 -9
  26. package/dist/cjs/features/utils/aggregate-base.js +49 -20
  27. package/dist/cjs/features/utils/entity-manager.js +47 -0
  28. package/dist/cjs/features/utils/event-store-manager.js +79 -54
  29. package/dist/cjs/interfaces/registered-entity.js +114 -0
  30. package/dist/cjs/loaders/api/api-methods.js +1 -1
  31. package/dist/cjs/loaders/api/api.js +50 -18
  32. package/dist/cjs/loaders/api/register-api-types.js +35 -0
  33. package/dist/cjs/loaders/api/register-api.js +165 -0
  34. package/dist/cjs/loaders/micro-agent-base.js +16 -0
  35. package/dist/cjs/loaders/micro-agent.js +1 -0
  36. package/dist/esm/common/config/init-types.js +92 -0
  37. package/dist/esm/common/config/init.js +9 -79
  38. package/dist/esm/common/config/runtime.js +7 -6
  39. package/dist/esm/common/constants/env.cdn.js +1 -1
  40. package/dist/esm/common/constants/env.npm.js +1 -1
  41. package/dist/esm/common/harvest/harvester.js +2 -2
  42. package/dist/esm/common/util/feature-flags.js +4 -5
  43. package/dist/esm/common/util/target.js +27 -0
  44. package/dist/esm/features/ajax/aggregate/index.js +2 -1
  45. package/dist/esm/features/generic_events/aggregate/index.js +10 -6
  46. package/dist/esm/features/jserrors/aggregate/index.js +44 -22
  47. package/dist/esm/features/logging/aggregate/index.js +17 -11
  48. package/dist/esm/features/logging/shared/utils.js +3 -2
  49. package/dist/esm/features/metrics/aggregate/index.js +6 -4
  50. package/dist/esm/features/page_view_event/aggregate/index.js +60 -11
  51. package/dist/esm/features/page_view_event/instrument/index.js +4 -0
  52. package/dist/esm/features/session_replay/aggregate/index.js +8 -6
  53. package/dist/esm/features/session_replay/instrument/index.js +1 -1
  54. package/dist/esm/features/session_replay/shared/recorder-events.js +4 -2
  55. package/dist/esm/features/session_replay/shared/recorder.js +12 -11
  56. package/dist/esm/features/session_trace/aggregate/trace/storage.js +1 -1
  57. package/dist/esm/features/soft_navigations/aggregate/index.js +12 -2
  58. package/dist/esm/features/spa/aggregate/index.js +3 -3
  59. package/dist/esm/features/spa/aggregate/interaction.js +6 -9
  60. package/dist/esm/features/utils/aggregate-base.js +49 -20
  61. package/dist/esm/features/utils/entity-manager.js +40 -0
  62. package/dist/esm/features/utils/event-store-manager.js +79 -54
  63. package/dist/esm/interfaces/registered-entity.js +107 -0
  64. package/dist/esm/loaders/api/api-methods.js +1 -1
  65. package/dist/esm/loaders/api/api.js +50 -18
  66. package/dist/esm/loaders/api/register-api-types.js +33 -0
  67. package/dist/esm/loaders/api/register-api.js +159 -0
  68. package/dist/esm/loaders/micro-agent-base.js +16 -0
  69. package/dist/esm/loaders/micro-agent.js +1 -0
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/dist/types/common/config/init-types.d.ts +275 -0
  72. package/dist/types/common/config/init-types.d.ts.map +1 -0
  73. package/dist/types/common/config/init.d.ts +1 -262
  74. package/dist/types/common/config/init.d.ts.map +1 -1
  75. package/dist/types/common/config/runtime.d.ts.map +1 -1
  76. package/dist/types/common/util/feature-flags.d.ts +1 -1
  77. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  78. package/dist/types/common/util/target.d.ts +18 -0
  79. package/dist/types/common/util/target.d.ts.map +1 -0
  80. package/dist/types/features/ajax/aggregate/index.d.ts +1 -1
  81. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  82. package/dist/types/features/generic_events/aggregate/index.d.ts +2 -1
  83. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  84. package/dist/types/features/jserrors/aggregate/index.d.ts +9 -1
  85. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  86. package/dist/types/features/logging/aggregate/index.d.ts +3 -3
  87. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  88. package/dist/types/features/logging/shared/utils.d.ts +2 -1
  89. package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
  90. package/dist/types/features/metrics/aggregate/index.d.ts +1 -0
  91. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  92. package/dist/types/features/page_view_event/aggregate/index.d.ts +10 -2
  93. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  94. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  95. package/dist/types/features/session_replay/aggregate/index.d.ts +2 -11
  96. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  97. package/dist/types/features/session_replay/shared/recorder-events.d.ts +1 -0
  98. package/dist/types/features/session_replay/shared/recorder-events.d.ts.map +1 -1
  99. package/dist/types/features/session_replay/shared/recorder.d.ts +4 -4
  100. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  101. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  102. package/dist/types/features/spa/aggregate/interaction.d.ts +3 -4
  103. package/dist/types/features/spa/aggregate/interaction.d.ts.map +1 -1
  104. package/dist/types/features/utils/aggregate-base.d.ts +22 -5
  105. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  106. package/dist/types/features/utils/entity-manager.d.ts +15 -0
  107. package/dist/types/features/utils/entity-manager.d.ts.map +1 -0
  108. package/dist/types/features/utils/event-store-manager.d.ts +48 -24
  109. package/dist/types/features/utils/event-store-manager.d.ts.map +1 -1
  110. package/dist/types/interfaces/registered-entity.d.ts +72 -0
  111. package/dist/types/interfaces/registered-entity.d.ts.map +1 -0
  112. package/dist/types/loaders/agent.d.ts +1 -1
  113. package/dist/types/loaders/api/api.d.ts.map +1 -1
  114. package/dist/types/loaders/api/register-api-types.d.ts +56 -0
  115. package/dist/types/loaders/api/register-api-types.d.ts.map +1 -0
  116. package/dist/types/loaders/api/register-api.d.ts +14 -0
  117. package/dist/types/loaders/api/register-api.d.ts.map +1 -0
  118. package/dist/types/loaders/micro-agent-base.d.ts +17 -0
  119. package/dist/types/loaders/micro-agent-base.d.ts.map +1 -1
  120. package/dist/types/loaders/micro-agent.d.ts +1 -0
  121. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  122. package/package.json +10 -1
  123. package/src/common/config/init-types.js +92 -0
  124. package/src/common/config/init.js +9 -79
  125. package/src/common/config/runtime.js +7 -6
  126. package/src/common/harvest/harvester.js +2 -2
  127. package/src/common/util/feature-flags.js +4 -5
  128. package/src/common/util/target.js +27 -0
  129. package/src/features/ajax/aggregate/index.js +2 -1
  130. package/src/features/generic_events/aggregate/index.js +8 -6
  131. package/src/features/jserrors/aggregate/index.js +42 -20
  132. package/src/features/logging/aggregate/index.js +14 -10
  133. package/src/features/logging/shared/utils.js +3 -2
  134. package/src/features/metrics/aggregate/index.js +7 -5
  135. package/src/features/page_view_event/aggregate/index.js +50 -8
  136. package/src/features/page_view_event/instrument/index.js +4 -0
  137. package/src/features/session_replay/aggregate/index.js +6 -3
  138. package/src/features/session_replay/instrument/index.js +1 -1
  139. package/src/features/session_replay/shared/recorder-events.js +5 -2
  140. package/src/features/session_replay/shared/recorder.js +12 -11
  141. package/src/features/session_trace/aggregate/trace/storage.js +1 -1
  142. package/src/features/soft_navigations/aggregate/index.js +11 -2
  143. package/src/features/spa/aggregate/index.js +3 -3
  144. package/src/features/spa/aggregate/interaction.js +6 -9
  145. package/src/features/utils/aggregate-base.js +54 -22
  146. package/src/features/utils/entity-manager.js +45 -0
  147. package/src/features/utils/event-store-manager.js +72 -49
  148. package/src/interfaces/registered-entity.js +107 -0
  149. package/src/loaders/api/api-methods.js +1 -1
  150. package/src/loaders/api/api.js +49 -13
  151. package/src/loaders/api/register-api-types.js +33 -0
  152. package/src/loaders/api/register-api.js +152 -0
  153. package/src/loaders/micro-agent-base.js +16 -0
  154. package/src/loaders/micro-agent.js +1 -0
@@ -20,10 +20,11 @@ var _constants2 = require("../constants");
20
20
  * @param {string} message - the log message string
21
21
  * @param {{[key: string]: *}} customAttributes - The log's custom attributes if any
22
22
  * @param {enum} level - the log level enum
23
+ * @param {object=} targetEntityGuid - the optional target entity guid provided by an api call
23
24
  */
24
- function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO) {
25
+ function bufferLog(ee, message, customAttributes = {}, level = _constants2.LOG_LEVELS.INFO, targetEntityGuid, timestamp = (0, _now.now)()) {
25
26
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/logging/".concat(level.toLowerCase(), "/called")], undefined, _features.FEATURE_NAMES.metrics, ee);
26
- (0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [(0, _now.now)(), message, customAttributes, level], undefined, _features.FEATURE_NAMES.logging, ee);
27
+ (0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [timestamp, message, customAttributes, level, targetEntityGuid], undefined, _features.FEATURE_NAMES.logging, ee);
27
28
  }
28
29
 
29
30
  /**
@@ -28,8 +28,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
28
28
  this.harvestOpts.aggregatorTypes = ['cm', 'sm']; // the types in EventAggregator this feature cares about
29
29
  // This feature only harvests once per potential EoL of the page, which is handled by the central harvester.
30
30
 
31
+ // this must be read/stored synchronously, as the currentScript is removed from the DOM after this script is executed and this lookup will be void
32
+ // its used to report a SM later in the lifecycle
33
+ this.agentNonce = _runtime.isBrowserScope && document.currentScript?.nonce;
31
34
  this.waitForFlags(['err']).then(([errFlag]) => {
32
35
  if (errFlag) {
36
+ this.singleChecks(); // checks that are run only one time, at script load
37
+ this.eachSessionChecks(); // the start of every time user engages with page
33
38
  this.drain();
34
39
  } else {
35
40
  this.blocked = true; // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
@@ -40,8 +45,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
40
45
  // Allow features external to the metrics feature to capture SMs and CMs through the event emitter
41
46
  (0, _registerHandler.registerHandler)(_constants.SUPPORTABILITY_METRIC_CHANNEL, this.storeSupportabilityMetrics.bind(this), this.featureName, this.ee);
42
47
  (0, _registerHandler.registerHandler)(_constants.CUSTOM_METRIC_CHANNEL, this.storeEventMetrics.bind(this), this.featureName, this.ee);
43
- this.singleChecks(); // checks that are run only one time, at script load
44
- this.eachSessionChecks(); // the start of every time user engages with page
45
48
  }
46
49
  preHarvestChecks(opts) {
47
50
  return this.drained && opts.isFinalHarvest;
@@ -77,8 +80,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
77
80
  if (distMethod) this.storeSupportabilityMetrics("Generic/DistMethod/".concat(distMethod, "/Detected"));
78
81
  if (_runtime.isBrowserScope) {
79
82
  this.storeSupportabilityMetrics('Generic/Runtime/Browser/Detected');
80
- const nonce = document?.currentScript?.nonce;
81
- if (nonce && nonce !== '') {
83
+ if (this.agentNonce && this.agentNonce !== '') {
82
84
  this.storeSupportabilityMetrics('Generic/Runtime/Nonce/Detected');
83
85
  }
84
86
 
@@ -19,6 +19,8 @@ var _timeToFirstByte = require("../../../common/vitals/time-to-first-byte");
19
19
  var _now = require("../../../common/timing/now");
20
20
  var _timeKeeper = require("../../../common/timing/time-keeper");
21
21
  var _traverse = require("../../../common/util/traverse");
22
+ var _registerHandler = require("../../../common/event-emitter/register-handler");
23
+ var _target = require("../../../common/util/target");
22
24
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
23
25
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
24
26
  /**
@@ -34,6 +36,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
34
36
  this.firstByteToWindowLoad = 0; // our "frontend" duration
35
37
  this.firstByteToDomContent = 0; // our "dom processing" duration
36
38
 
39
+ (0, _registerHandler.registerHandler)('send-rum', (customAttibutes, target) => {
40
+ this.sendRum(customAttibutes, target);
41
+ }, this.featureName, this.ee);
37
42
  if (!(0, _info.isValid)(agentRef.agentIdentifier)) {
38
43
  this.ee.abort();
39
44
  return (0, _console.warn)(43);
@@ -56,7 +61,17 @@ class Aggregate extends _aggregateBase.AggregateBase {
56
61
  this.sendRum();
57
62
  }
58
63
  }
59
- sendRum() {
64
+
65
+ /**
66
+ *
67
+ * @param {Function} cb A function to run once the RUM call has finished - Defaults to activateFeatures
68
+ * @param {*} customAttributes custom attributes to attach to the RUM call - Defaults to info.js
69
+ * @param {*} target The target to harvest to - Since we will not know the entityGuid before harvesting, this must be an object directly supplied from the info object or API, not an entityGuid string for lookup with the entityManager - Defaults to { licenseKey: this.agentRef.info.licenseKey, applicationID: this.agentRef.info.applicationID }
70
+ */
71
+ sendRum(customAttributes = this.agentRef.info.jsAttributes, target = {
72
+ licenseKey: this.agentRef.info.licenseKey,
73
+ applicationID: this.agentRef.info.applicationID
74
+ }) {
60
75
  const info = this.agentRef.info;
61
76
  const measures = {};
62
77
  if (info.queueTime) measures.qt = info.queueTime;
@@ -82,9 +97,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
82
97
  if (this.agentRef.runtime.session) queryParameters.fsh = Number(this.agentRef.runtime.session.isNew); // "first session harvest" aka RUM request or PageView event of a session
83
98
 
84
99
  let body;
85
- if (typeof info.jsAttributes === 'object' && Object.keys(info.jsAttributes).length > 0) {
100
+ if (typeof customAttributes === 'object' && Object.keys(customAttributes).length > 0) {
86
101
  body = (0, _traverse.applyFnToProps)({
87
- ja: info.jsAttributes
102
+ ja: customAttributes
88
103
  }, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
89
104
  }
90
105
  if (_runtime.globalScope.performance) {
@@ -114,7 +129,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
114
129
  this.rumStartTime = (0, _now.now)();
115
130
  this.agentRef.runtime.harvester.triggerHarvestFor(this, {
116
131
  directSend: {
117
- targetApp: this.agentRef.mainAppKey,
132
+ targetApp: target,
118
133
  payload: {
119
134
  qs: queryParameters,
120
135
  body
@@ -127,20 +142,32 @@ class Aggregate extends _aggregateBase.AggregateBase {
127
142
  postHarvestCleanup({
128
143
  status,
129
144
  responseText,
130
- xhr
145
+ xhr,
146
+ targetApp
131
147
  }) {
132
148
  const rumEndTime = (0, _now.now)();
149
+ let app, flags;
150
+ try {
151
+ ({
152
+ app,
153
+ ...flags
154
+ } = JSON.parse(responseText));
155
+ this.processEntities(app.agents, targetApp);
156
+ } catch (error) {
157
+ // wont set entity stuff here, if main agent will later abort, if registered agent, nothing will happen
158
+ (0, _console.warn)(53, error);
159
+ }
160
+
161
+ /** Only run agent-wide side-effects if the harvest was for the main agent */
162
+ if (!(0, _target.isContainerAgentTarget)(targetApp, this.agentRef)) return;
133
163
  if (status >= 400 || status === 0) {
134
164
  (0, _console.warn)(18, status);
135
165
  // Adding retry logic for the rum call will be a separate change; this.blocked will need to be changed since that prevents another triggerHarvestFor()
136
166
  this.ee.abort();
137
167
  return;
138
168
  }
139
- const {
140
- app,
141
- ...flags
142
- } = JSON.parse(responseText);
143
169
  try {
170
+ // will do nothing if already done
144
171
  this.agentRef.runtime.timeKeeper.processRumRequest(xhr, this.rumStartTime, rumEndTime, app.nrServerTime);
145
172
  if (!this.agentRef.runtime.timeKeeper.ready) throw new Error('TimeKeeper not ready');
146
173
  } catch (error) {
@@ -148,10 +175,32 @@ class Aggregate extends _aggregateBase.AggregateBase {
148
175
  (0, _console.warn)(17, error);
149
176
  return;
150
177
  }
151
- this.agentRef.runtime.appMetadata = app;
152
- (0, _featureFlags.activateFeatures)(flags, this.agentIdentifier);
178
+
179
+ // set the agent runtime objects that require the rum response or entity guid
180
+ if (!Object.keys(this.agentRef.runtime.appMetadata).length) this.agentRef.runtime.appMetadata = app;
153
181
  this.drain();
154
182
  this.agentRef.runtime.harvester.startTimer();
183
+ (0, _featureFlags.activateFeatures)(flags, this.agentRef);
184
+ }
185
+ processEntities(entities, targetApp) {
186
+ if (!entities || !targetApp) return;
187
+ entities.forEach(agent => {
188
+ const entityManager = this.agentRef.runtime.entityManager;
189
+ const entityGuid = agent.entityGuid;
190
+ const entity = entityManager.get(entityGuid);
191
+ if (entity) return; // already processed
192
+
193
+ if ((0, _target.isContainerAgentTarget)(targetApp, this.agentRef)) {
194
+ entityManager.setDefaultEntity({
195
+ ...targetApp,
196
+ entityGuid
197
+ });
198
+ }
199
+ entityManager.set(agent.entityGuid, {
200
+ ...targetApp,
201
+ entityGuid
202
+ });
203
+ });
155
204
  }
156
205
  }
157
206
  exports.Aggregate = Aggregate;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.PageViewEvent = exports.Instrument = void 0;
7
+ var _handle = require("../../../common/event-emitter/handle");
7
8
  var _instrumentBase = require("../../utils/instrument-base");
8
9
  var CONSTANTS = _interopRequireWildcard(require("../constants"));
9
10
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
@@ -17,6 +18,9 @@ class Instrument extends _instrumentBase.InstrumentBase {
17
18
  static featureName = CONSTANTS.FEATURE_NAME;
18
19
  constructor(agentRef, auto = true) {
19
20
  super(agentRef, CONSTANTS.FEATURE_NAME, auto);
21
+
22
+ /** messages from the register API that can trigger a new RUM call */
23
+ this.ee.on('api-send-rum', (attrs, target) => (0, _handle.handle)('send-rum', [attrs, target], undefined, this.featureName, this.ee));
20
24
  this.importAggregator(agentRef);
21
25
  }
22
26
  }
@@ -223,6 +223,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
223
223
  }
224
224
  }
225
225
  makeHarvestPayload(shouldRetryOnFail) {
226
+ const payloadOutput = {
227
+ targetApp: undefined,
228
+ payload: undefined
229
+ };
226
230
  if (this.mode !== _constants2.MODE.FULL || this.blocked) return;
227
231
  if (!this.recorder || !this.timeKeeper?.ready || !this.recorder.hasSeenSnapshot) return;
228
232
  const recorderEvents = this.recorder.getEvents();
@@ -231,7 +235,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
231
235
  const payload = this.getHarvestContents(recorderEvents);
232
236
  if (!payload.body.length) {
233
237
  this.recorder.clearBuffer();
234
- return;
238
+ return [payloadOutput];
235
239
  }
236
240
  this.reportSupportabilityMetric('SessionReplay/Harvest/Attempts');
237
241
  let len = 0;
@@ -268,7 +272,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
268
272
  }
269
273
  if (len > _agentConstants.MAX_PAYLOAD_SIZE) {
270
274
  this.abort(_constants.ABORT_REASONS.TOO_BIG, len);
271
- return;
275
+ return [payloadOutput];
272
276
  }
273
277
  // TODO -- Gracefully handle the buffer for retries.
274
278
  if (!this.agentRef.runtime.session.state.sessionReplaySentFirstChunk) this.syncWithSessionManager({
@@ -276,10 +280,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
276
280
  });
277
281
  this.recorder.clearBuffer();
278
282
  if (recorderEvents.type === 'preloaded') this.agentRef.runtime.harvester.triggerHarvestFor(this);
279
- return [{
280
- targetApp: undefined,
281
- payload
282
- }]; // SR doesn't need a targetApp as it only works for the main, but format needs to make AggregateBase
283
+ payloadOutput.payload = payload;
284
+ return [payloadOutput];
283
285
  }
284
286
  getCorrectedTimestamp(node) {
285
287
  if (!node?.timestamp) return;
@@ -89,7 +89,7 @@ class Instrument extends _instrumentBase.InstrumentBase {
89
89
  });
90
90
  this.recorder.startRecording();
91
91
  this.abortHandler = this.recorder.stopRecording;
92
- } catch (e) {}
92
+ } catch (e) {} // TODO add internal error handling
93
93
  this.importAggregator(this.#agentRef, {
94
94
  recorder: this.recorder,
95
95
  errorNoticed: this.errorNoticed
@@ -26,8 +26,10 @@ class RecorderEvents {
26
26
  hasMeta = false;
27
27
  /** Payload metadata -- Should indicate that the payload being sent contains an error. Used for query/filter purposes in UI */
28
28
  hasError = false;
29
- /** Payload metadata -- Denotes whether all stylesheet elements were able to be inlined */
30
- inlinedAllStylesheets = true;
29
+ constructor(shouldInlineStylesheets = true) {
30
+ /** Payload metadata -- Denotes whether all stylesheet elements were able to be inlined */
31
+ this.inlinedAllStylesheets = shouldInlineStylesheets;
32
+ }
31
33
  add(event) {
32
34
  this.#events.add(event);
33
35
  }
@@ -35,9 +35,14 @@ class Recorder {
35
35
  #warnCSSOnce = (0, _invoke.single)(() => (0, _console.warn)(47)); // notifies user of potential replayer issue if fix_stylesheets is off
36
36
 
37
37
  constructor(parent) {
38
- this.#events = new _recorderEvents.RecorderEvents();
39
- this.#backloggedEvents = new _recorderEvents.RecorderEvents();
40
- this.#preloaded = [new _recorderEvents.RecorderEvents()];
38
+ /** The parent class that instantiated the recorder */
39
+ this.parent = parent;
40
+ /** A flag that can be set to false by failing conversions to stop the fetching process */
41
+ this.shouldFix = this.parent.agentRef.init.session_replay.fix_stylesheets;
42
+ /** Event Buffers */
43
+ this.#events = new _recorderEvents.RecorderEvents(this.shouldFix);
44
+ this.#backloggedEvents = new _recorderEvents.RecorderEvents(this.shouldFix);
45
+ this.#preloaded = [new _recorderEvents.RecorderEvents(this.shouldFix)];
41
46
  /** True when actively recording, false when paused or stopped */
42
47
  this.recording = false;
43
48
  /** The pointer to the current bucket holding rrweb events */
@@ -46,10 +51,6 @@ class Recorder {
46
51
  this.hasSeenSnapshot = false;
47
52
  /** 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 */
48
53
  this.lastMeta = false;
49
- /** The parent class that instantiated the recorder */
50
- this.parent = parent;
51
- /** A flag that can be set to false by failing conversions to stop the fetching process */
52
- this.shouldFix = this.parent.agentRef.init.session_replay.fix_stylesheets;
53
54
  /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
54
55
  this.stopRecording = () => {/* no-op until set by rrweb initializer */};
55
56
  }
@@ -76,8 +77,8 @@ class Recorder {
76
77
 
77
78
  /** Clears the buffer (this.#events), and resets all payload metadata properties */
78
79
  clearBuffer() {
79
- if (this.#preloaded[0]?.events.length) this.#preloaded.shift();else if (this.parent.mode === _constants2.MODE.ERROR) this.#backloggedEvents = this.#events;else this.#backloggedEvents = new _recorderEvents.RecorderEvents();
80
- this.#events = new _recorderEvents.RecorderEvents();
80
+ if (this.#preloaded[0]?.events.length) this.#preloaded.shift();else if (this.parent.mode === _constants2.MODE.ERROR) this.#backloggedEvents = this.#events;else this.#backloggedEvents = new _recorderEvents.RecorderEvents(this.shouldFix);
81
+ this.#events = new _recorderEvents.RecorderEvents(this.shouldFix);
81
82
  }
82
83
 
83
84
  /** Begin recording using configured recording lib */
@@ -129,7 +130,7 @@ class Recorder {
129
130
  */
130
131
  audit(event, isCheckout) {
131
132
  /** An count of stylesheet objects that were blocked from accessing contents via JS */
132
- const incompletes = _stylesheetEvaluator.stylesheetEvaluator.evaluate();
133
+ const incompletes = this.parent.agentRef.init.session_replay.fix_stylesheets ? _stylesheetEvaluator.stylesheetEvaluator.evaluate() : 0;
133
134
  const missingInlineSMTag = 'SessionReplay/Payload/Missing-Inline-Css/';
134
135
  /** only run the full fixing behavior (more costly) if fix_stylesheets is configured as on (default behavior) */
135
136
  if (!this.shouldFix) {
@@ -205,7 +206,7 @@ class Recorder {
205
206
  this.parent.agentRef.runtime.harvester.triggerHarvestFor(this.parent);
206
207
  } else {
207
208
  // we are still in "preload" and it triggered a "stop point". Make a new set, which will get pointed at on next cycle
208
- this.#preloaded.push(new _recorderEvents.RecorderEvents());
209
+ this.#preloaded.push(new _recorderEvents.RecorderEvents(this.shouldFix));
209
210
  }
210
211
  }
211
212
  }
@@ -267,7 +267,7 @@ class TraceStorage {
267
267
  }
268
268
  get() {
269
269
  return [{
270
- targetApp: this.parent.agentRef.mainAppKey,
270
+ targetApp: this.parent.agentRef.runtime.entityManager.get(),
271
271
  data: this.takeSTNs()
272
272
  }];
273
273
  }
@@ -31,7 +31,15 @@ class Aggregate extends _aggregateBase.AggregateBase {
31
31
  this.initialPageLoadInteraction.onDone.push(() => {
32
32
  // this ensures the .end() method also works with iPL
33
33
  this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
34
- this.interactionsToHarvest.add(this.initialPageLoadInteraction);
34
+ const ixn = this.initialPageLoadInteraction;
35
+ /** this.events (ixns to harvest) has already been set up, use it immediately */
36
+ if (this.interactionsToHarvest) this.interactionsToHarvest.add(ixn);else {
37
+ /** this.events (ixns to harvest) hasnt been initialized yet... wait for it */
38
+ this.ee.on('entity-added', () => {
39
+ this.interactionsToHarvest = this.events;
40
+ this.interactionsToHarvest.add(ixn);
41
+ });
42
+ }
35
43
  this.initialPageLoadInteraction = null;
36
44
  });
37
45
  _timeToFirstByte.timeToFirstByte.subscribe(({
@@ -132,7 +140,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
132
140
  */
133
141
  if (this.interactionInProgress?.isActiveDuring(timestamp)) return this.interactionInProgress;
134
142
  let saveIxn;
135
- const interactionsBuffer = this.interactionsToHarvest.get(this.agentRef.mainAppKey)[0].data;
143
+ const [{
144
+ data: interactionsBuffer
145
+ }] = this.interactionsToHarvest.get();
136
146
  for (let idx = interactionsBuffer.length - 1; idx >= 0; idx--) {
137
147
  // reverse search for the latest completed interaction for efficiency
138
148
  const finishedInteraction = interactionsBuffer[idx];
@@ -125,7 +125,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
125
125
  }
126
126
  });
127
127
  if (agentRef.init.spa.enabled !== true) return;
128
- state.initialPageLoad = new _interaction.Interaction('initialPageLoad', 0, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef.agentIdentifier);
128
+ state.initialPageLoad = new _interaction.Interaction('initialPageLoad', 0, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
129
129
  state.initialPageLoad.save = true;
130
130
  state.prevInteraction = state.initialPageLoad;
131
131
  state.currentNode = state.initialPageLoad.root; // hint
@@ -206,7 +206,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
206
206
  // Otherwise, if no interaction is currently active, create a new node ID,
207
207
  // and let the aggregator know that we entered a new event handler callback
208
208
  // so that it has a chance to possibly start an interaction.
209
- var ixn = new _interaction.Interaction(evName, this[FN_START], state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef.agentIdentifier);
209
+ var ixn = new _interaction.Interaction(evName, this[FN_START], state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
210
210
 
211
211
  // Store the interaction as prevInteraction in case it is prematurely discarded
212
212
  state.prevInteraction = ixn;
@@ -504,7 +504,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
504
504
  }, this.featureName, promiseEE);
505
505
  (0, _registerHandler.registerHandler)(INTERACTION_API + 'get', function (t) {
506
506
  var interaction;
507
- if (state?.currentNode?.[INTERACTION]) interaction = this.ixn = state.currentNode[INTERACTION];else if (state?.prevNode?.end === null && state?.prevNode?.[INTERACTION]?.root?.[INTERACTION]?.eventName !== 'initialPageLoad') interaction = this.ixn = state.prevNode[INTERACTION];else interaction = this.ixn = new _interaction.Interaction('api', t, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef.agentIdentifier);
507
+ if (state?.currentNode?.[INTERACTION]) interaction = this.ixn = state.currentNode[INTERACTION];else if (state?.prevNode?.end === null && state?.prevNode?.[INTERACTION]?.root?.[INTERACTION]?.eventName !== 'initialPageLoad') interaction = this.ixn = state.prevNode[INTERACTION];else interaction = this.ixn = new _interaction.Interaction('api', t, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentRef);
508
508
  if (!state.currentNode) {
509
509
  interaction.checkFinish();
510
510
  if (state.depth) setCurrentNode(interaction.root);
@@ -4,10 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Interaction = Interaction;
7
- var _info = require("../../../common/config/info");
8
7
  var _runtime = require("../../../common/constants/runtime");
9
8
  var _nreum = require("../../../common/window/nreum");
10
- var _contextualEe = require("../../../common/event-emitter/contextual-ee");
11
9
  var _interactionNode = require("./interaction-node");
12
10
  /**
13
11
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
@@ -17,11 +15,10 @@ var _interactionNode = require("./interaction-node");
17
15
  var originalSetTimeout = (0, _nreum.gosNREUMOriginals)().o.ST;
18
16
  var originalClearTimeout = (0, _nreum.gosNREUMOriginals)().o.CT;
19
17
  var lastId = {};
20
- function Interaction(eventName, timestamp, url, routeName, onFinished, agentIdentifier) {
21
- this.agentIdentifier = agentIdentifier;
22
- this.ee = _contextualEe.ee.get(agentIdentifier);
23
- lastId[agentIdentifier] = 0;
24
- this.id = ++lastId[agentIdentifier];
18
+ function Interaction(eventName, timestamp, url, routeName, onFinished, agentRef) {
19
+ this.agentRef = agentRef;
20
+ lastId[agentRef.agentIdentifier] = 0;
21
+ this.id = ++lastId[agentRef.agentIdentifier];
25
22
  this.eventName = eventName;
26
23
  this.nodes = 0;
27
24
  this.remaining = 0;
@@ -89,9 +86,9 @@ InteractionPrototype.finish = function finishInteraction() {
89
86
  if (this.onFinished) {
90
87
  this.onFinished(this);
91
88
  }
92
- Object.entries((0, _info.getInfo)(interaction.agentIdentifier).jsAttributes || {}).forEach(([attr, value]) => {
89
+ Object.entries(interaction.agentRef.info?.jsAttributes || {}).forEach(([attr, value]) => {
93
90
  if (!(attr in customAttrs)) customAttrs[attr] = value;
94
91
  });
95
92
  root.end = endTimestamp;
96
- interaction.ee.emit('interaction', [this]);
93
+ interaction.agentRef.ee.emit('interaction', [this]);
97
94
  };
@@ -14,21 +14,47 @@ var _obfuscate = require("../../common/util/obfuscate");
14
14
  var _features = require("../../loaders/features/features");
15
15
  var _eventStoreManager = require("./event-store-manager");
16
16
  var _harvester = require("../../common/harvest/harvester");
17
+ var _console = require("../../common/util/console");
18
+ var _entityManager = require("./entity-manager");
19
+ var _eventBuffer = require("./event-buffer");
17
20
  var _handle = require("../../common/event-emitter/handle");
18
21
  var _constants = require("../metrics/constants");
22
+ var _eventAggregator = require("../../common/aggregate/event-aggregator");
19
23
  /**
20
24
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
21
25
  * SPDX-License-Identifier: Apache-2.0
22
26
  */
23
27
 
24
28
  class AggregateBase extends _featureBase.FeatureBase {
29
+ /**
30
+ * Create an AggregateBase instance.
31
+ * @param {Object} agentRef The reference to the agent instance.
32
+ * @param {string} featureName The name of the feature creating the instance.
33
+ */
25
34
  constructor(agentRef, featureName) {
26
35
  super(agentRef.agentIdentifier, featureName);
27
36
  this.agentRef = agentRef;
28
37
  this.checkConfiguration(agentRef);
29
38
  this.doOnceForAllAggregate(agentRef);
39
+ this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
40
+
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 {
45
+ this.ee.on('entity-added', entity => {
46
+ this.#setupEventStore(entity.entityGuid);
47
+ });
48
+ }
49
+ }
30
50
 
31
- // This switch needs to be after doOnceForAllAggregate which may new sharedAggregator and reset mainAppKey.
51
+ /**
52
+ * sets up the event store for the feature. It must wait for the entity guid to be available before setting up the event store. This is called once the rum response is received with an entityGuid.
53
+ * @param {string} entityGuid
54
+ * @returns {void}
55
+ */
56
+ #setupEventStore(entityGuid) {
57
+ if (this.events || !entityGuid) return;
32
58
  switch (this.featureName) {
33
59
  // SessionTrace + Replay have their own storage mechanisms.
34
60
  case _features.FEATURE_NAMES.sessionTrace:
@@ -37,16 +63,15 @@ class AggregateBase extends _featureBase.FeatureBase {
37
63
  // Jserror and Metric features uses a singleton EventAggregator instead of a regular EventBuffer.
38
64
  case _features.FEATURE_NAMES.jserrors:
39
65
  case _features.FEATURE_NAMES.metrics:
40
- this.events = agentRef.sharedAggregator;
66
+ this.events = this.agentRef.sharedAggregator ??= new _eventStoreManager.EventStoreManager(this.agentRef, _eventAggregator.EventAggregator, entityGuid, 'shared_aggregator');
41
67
  break;
42
68
  /** All other features get EventBuffer in the ESM by default. Note: PVE is included here, but event buffer will always be empty so future harvests will still not happen by interval or EOL.
43
69
  This was necessary to prevent race cond. issues where the event buffer was checked before the feature could "block" itself.
44
70
  Its easier to just keep an empty event buffer in place. */
45
71
  default:
46
- this.events = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 1, agentRef.agentIdentifier, this.featureName);
72
+ this.events = new _eventStoreManager.EventStoreManager(this.agentRef, _eventBuffer.EventBuffer, entityGuid, this.featureName);
47
73
  break;
48
74
  }
49
- this.harvestOpts = {}; // features aggregate classes can define custom opts for when their harvest is called
50
75
  }
51
76
 
52
77
  /**
@@ -76,6 +101,10 @@ class AggregateBase extends _featureBase.FeatureBase {
76
101
  this.deregisterDrain();
77
102
  });
78
103
  }
104
+
105
+ /**
106
+ * Stages the feature to be drained
107
+ */
79
108
  drain() {
80
109
  (0, _drain.drain)(this.agentIdentifier, this.featureName);
81
110
  this.drained = true;
@@ -87,28 +116,29 @@ class AggregateBase extends _featureBase.FeatureBase {
87
116
  /**
88
117
  * Return harvest payload. A "serializer" function can be defined on a derived class to format the payload.
89
118
  * @param {Boolean} shouldRetryOnFail - harvester flag to backup payload for retry later if harvest request fails; this should be moved to harvester logic
90
- * @param {object|undefined} opts.target - the target app passed onto the event store manager to determine which app's data to return; if none provided, all apps data will be returned
119
+ * @param {object|undefined} opts - opts passed from the harvester to help form the payload
120
+ * @param {string} opts.targetEntityGuid - the entity guid of the target app
91
121
  * @returns {Array} Final payload tagged with their targeting browser app. The value of `payload` can be undefined if there are no pending events for an app. This should be a minimum length of 1.
92
122
  */
93
123
  makeHarvestPayload(shouldRetryOnFail = false, opts = {}) {
94
- if (this.events.isEmpty(this.harvestOpts, opts.target)) return;
124
+ if (!this.events || this.events.isEmpty(this.harvestOpts, opts.targetEntityGuid)) return;
95
125
  // Other conditions and things to do when preparing harvest that is required.
96
126
  if (this.preHarvestChecks && !this.preHarvestChecks(opts)) return;
97
- if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.target);
98
- const returnedDataArr = this.events.get(this.harvestOpts, opts.target);
99
- if (!returnedDataArr.length) throw new Error('Unexpected problem encountered. There should be at least one app for harvest!');
100
- this.events.clear(this.harvestOpts, opts.target);
127
+ if (shouldRetryOnFail) this.events.save(this.harvestOpts, opts.targetEntityGuid);
128
+ const returnedDataArr = this.events.get(this.harvestOpts, opts.targetEntityGuid);
129
+ if (!returnedDataArr.length) return (0, _console.warn)(52);
130
+ this.events.clear(this.harvestOpts, opts.targetEntityGuid);
101
131
  return returnedDataArr.map(({
102
132
  targetApp,
103
133
  data
104
134
  }) => {
105
135
  // A serializer or formatter assists in creating the payload `body` from stored events on harvest when defined by derived feature class.
106
- const body = this.serializer ? this.serializer(data) : data;
136
+ const body = this.serializer ? this.serializer(data, targetApp?.entityGuid) : data;
107
137
  const payload = {
108
138
  body
109
139
  };
110
140
  // Constructs the payload `qs` for relevant features on harvest.
111
- if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data);
141
+ if (this.queryStringsBuilder) payload.qs = this.queryStringsBuilder(data, targetApp?.entityGuid);
112
142
  return {
113
143
  targetApp,
114
144
  payload
@@ -119,11 +149,15 @@ class AggregateBase extends _featureBase.FeatureBase {
119
149
  /**
120
150
  * Cleanup task after a harvest.
121
151
  * @param {object} result - the cbResult object from the harvester's send method
152
+ * @param {object=} result.targetApp - the target app object that was used to point the harvest to the correct app
153
+ * @param {string=} result.targetApp.entityGuid - the entity guid of the target app
154
+ * @param {boolean=} result.sent - whether the harvest was sent successfully
155
+ * @param {boolean=} result.retry - whether the harvest should be retried
122
156
  */
123
157
  postHarvestCleanup(result = {}) {
124
158
  const harvestFailed = result.sent && result.retry;
125
- if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp);
126
- this.events.clearSave(this.harvestOpts, result.targetApp);
159
+ if (harvestFailed) this.events.reloadSave(this.harvestOpts, result.targetApp?.entityGuid);
160
+ this.events.clearSave(this.harvestOpts, result.targetApp?.entityGuid);
127
161
  }
128
162
 
129
163
  /**
@@ -163,12 +197,7 @@ class AggregateBase extends _featureBase.FeatureBase {
163
197
  doOnceForAllAggregate(agentRef) {
164
198
  if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new _obfuscate.Obfuscator(agentRef);
165
199
  this.obfuscator = agentRef.runtime.obfuscator;
166
- if (!agentRef.mainAppKey) agentRef.mainAppKey = {
167
- licenseKey: agentRef.info.licenseKey,
168
- appId: agentRef.info.applicationID
169
- };
170
- // Create a single Aggregator for this agent if DNE yet; to be used by jserror endpoint features.
171
- if (!agentRef.sharedAggregator) agentRef.sharedAggregator = new _eventStoreManager.EventStoreManager(agentRef.mainAppKey, 2, agentRef.agentIdentifier, 'shared_aggregator');
200
+ if (!agentRef.runtime.entityManager) agentRef.runtime.entityManager = new _entityManager.EntityManager(this.agentRef);
172
201
  if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
173
202
  }
174
203
 
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.EntityManager = void 0;
7
+ /**
8
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
+ * SPDX-License-Identifier: Apache-2.0
10
+ */
11
+
12
+ class EntityManager {
13
+ #entities = new Map();
14
+ #entityGuidLookup = {};
15
+ #defaultEntity = null;
16
+ constructor(agentRef) {
17
+ this.agentRef = agentRef;
18
+ this.#defaultEntity = {
19
+ licenseKey: agentRef.info.licenseKey,
20
+ applicationID: agentRef.info.applicationID
21
+ };
22
+ }
23
+ get(entityGuid) {
24
+ if (!entityGuid) return this.#defaultEntity;
25
+ return this.#entities.get(entityGuid);
26
+ }
27
+ getEntityGuidFor(licenseKey, applicationID) {
28
+ if (!this.#entityGuidLookup[licenseKey] || !this.#entityGuidLookup[applicationID]) return;
29
+ return this.#entityGuidLookup[licenseKey].filter(x => this.#entityGuidLookup[applicationID].includes(x))[0];
30
+ }
31
+ set(entityGuid, entity) {
32
+ if (this.#entities.has(entityGuid)) return;
33
+ this.#entities.set(entityGuid, entity);
34
+ this.#entityGuidLookup[entity.licenseKey] ??= [];
35
+ this.#entityGuidLookup[entity.licenseKey].push(entityGuid);
36
+ this.#entityGuidLookup[entity.applicationID] ??= [];
37
+ this.#entityGuidLookup[entity.applicationID].push(entityGuid);
38
+ this.agentRef.ee.emit('entity-added', [entity]);
39
+ }
40
+ clear() {
41
+ this.#entities.clear();
42
+ }
43
+ setDefaultEntity(entity) {
44
+ this.#defaultEntity = entity;
45
+ }
46
+ }
47
+ exports.EntityManager = EntityManager;