@newrelic/browser-agent 1.301.0-rc.0 → 1.301.0-rc.2

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 (133) hide show
  1. package/dist/cjs/common/config/init-types.js +1 -1
  2. package/dist/cjs/common/config/init.js +7 -1
  3. package/dist/cjs/common/config/runtime.js +1 -1
  4. package/dist/cjs/common/constants/agent-constants.js +11 -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/common/drain/drain.js +1 -1
  8. package/dist/cjs/common/harvest/harvester.js +30 -39
  9. package/dist/cjs/common/util/mfe.js +45 -0
  10. package/dist/cjs/features/generic_events/aggregate/index.js +9 -8
  11. package/dist/cjs/features/generic_events/constants.js +3 -1
  12. package/dist/cjs/features/jserrors/aggregate/index.js +18 -17
  13. package/dist/cjs/features/logging/aggregate/index.js +19 -15
  14. package/dist/cjs/features/logging/shared/utils.js +3 -3
  15. package/dist/cjs/features/page_view_event/aggregate/index.js +3 -33
  16. package/dist/cjs/features/session_replay/aggregate/index.js +13 -13
  17. package/dist/cjs/features/session_replay/shared/recorder.js +3 -2
  18. package/dist/cjs/features/session_trace/aggregate/index.js +0 -2
  19. package/dist/cjs/features/soft_navigations/aggregate/index.js +1 -2
  20. package/dist/cjs/features/utils/aggregate-base.js +45 -47
  21. package/dist/cjs/loaders/api/addPageAction.js +2 -2
  22. package/dist/cjs/loaders/api/log.js +2 -2
  23. package/dist/cjs/loaders/api/noticeError.js +2 -2
  24. package/dist/cjs/loaders/api/register-api-types.js +5 -5
  25. package/dist/cjs/loaders/api/register.js +80 -97
  26. package/dist/esm/common/config/init-types.js +1 -1
  27. package/dist/esm/common/config/init.js +7 -1
  28. package/dist/esm/common/config/runtime.js +1 -1
  29. package/dist/esm/common/constants/agent-constants.js +9 -1
  30. package/dist/esm/common/constants/env.cdn.js +1 -1
  31. package/dist/esm/common/constants/env.npm.js +1 -1
  32. package/dist/esm/common/drain/drain.js +1 -1
  33. package/dist/esm/common/harvest/harvester.js +30 -39
  34. package/dist/esm/common/util/mfe.js +38 -0
  35. package/dist/esm/features/generic_events/aggregate/index.js +9 -8
  36. package/dist/esm/features/generic_events/constants.js +3 -1
  37. package/dist/esm/features/jserrors/aggregate/index.js +18 -17
  38. package/dist/esm/features/logging/aggregate/index.js +19 -15
  39. package/dist/esm/features/logging/shared/utils.js +3 -3
  40. package/dist/esm/features/page_view_event/aggregate/index.js +3 -33
  41. package/dist/esm/features/session_replay/aggregate/index.js +13 -13
  42. package/dist/esm/features/session_replay/shared/recorder.js +3 -2
  43. package/dist/esm/features/session_trace/aggregate/index.js +0 -2
  44. package/dist/esm/features/soft_navigations/aggregate/index.js +1 -2
  45. package/dist/esm/features/utils/aggregate-base.js +46 -48
  46. package/dist/esm/loaders/api/addPageAction.js +2 -2
  47. package/dist/esm/loaders/api/log.js +2 -2
  48. package/dist/esm/loaders/api/noticeError.js +2 -2
  49. package/dist/esm/loaders/api/register-api-types.js +5 -5
  50. package/dist/esm/loaders/api/register.js +80 -97
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/dist/types/common/config/init-types.d.ts +4 -1
  53. package/dist/types/common/config/init-types.d.ts.map +1 -1
  54. package/dist/types/common/config/init.d.ts.map +1 -1
  55. package/dist/types/common/constants/agent-constants.d.ts +7 -4
  56. package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
  57. package/dist/types/common/harvest/harvester.d.ts +2 -2
  58. package/dist/types/common/harvest/harvester.d.ts.map +1 -1
  59. package/dist/types/common/util/mfe.d.ts +20 -0
  60. package/dist/types/common/util/mfe.d.ts.map +1 -0
  61. package/dist/types/features/generic_events/aggregate/index.d.ts +2 -2
  62. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  63. package/dist/types/features/generic_events/constants.d.ts +1 -0
  64. package/dist/types/features/jserrors/aggregate/index.d.ts +3 -3
  65. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  66. package/dist/types/features/logging/aggregate/index.d.ts +3 -3
  67. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  68. package/dist/types/features/logging/shared/utils.d.ts +2 -2
  69. package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
  70. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -4
  71. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  72. package/dist/types/features/session_replay/aggregate/index.d.ts +13 -4
  73. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  74. package/dist/types/features/session_replay/shared/recorder.d.ts +1 -0
  75. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  76. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  77. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  78. package/dist/types/features/utils/aggregate-base.d.ts +13 -5
  79. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  80. package/dist/types/loaders/api/addPageAction.d.ts +1 -1
  81. package/dist/types/loaders/api/addPageAction.d.ts.map +1 -1
  82. package/dist/types/loaders/api/log.d.ts +1 -1
  83. package/dist/types/loaders/api/log.d.ts.map +1 -1
  84. package/dist/types/loaders/api/noticeError.d.ts +1 -1
  85. package/dist/types/loaders/api/noticeError.d.ts.map +1 -1
  86. package/dist/types/loaders/api/register-api-types.d.ts +4 -4
  87. package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
  88. package/dist/types/loaders/api/register.d.ts +8 -1
  89. package/dist/types/loaders/api/register.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/common/config/init-types.js +1 -1
  92. package/src/common/config/init.js +3 -1
  93. package/src/common/config/runtime.js +1 -1
  94. package/src/common/constants/agent-constants.js +10 -0
  95. package/src/common/drain/drain.js +1 -1
  96. package/src/common/harvest/harvester.js +27 -32
  97. package/src/common/util/mfe.js +35 -0
  98. package/src/features/generic_events/aggregate/index.js +9 -8
  99. package/src/features/generic_events/constants.js +3 -1
  100. package/src/features/jserrors/aggregate/index.js +17 -17
  101. package/src/features/logging/aggregate/index.js +20 -13
  102. package/src/features/logging/shared/utils.js +3 -3
  103. package/src/features/page_view_event/aggregate/index.js +3 -28
  104. package/src/features/session_replay/aggregate/index.js +12 -10
  105. package/src/features/session_replay/shared/recorder.js +3 -2
  106. package/src/features/session_trace/aggregate/index.js +0 -2
  107. package/src/features/soft_navigations/aggregate/index.js +1 -2
  108. package/src/features/utils/aggregate-base.js +47 -42
  109. package/src/loaders/api/addPageAction.js +2 -2
  110. package/src/loaders/api/log.js +2 -2
  111. package/src/loaders/api/noticeError.js +2 -2
  112. package/src/loaders/api/register-api-types.js +5 -5
  113. package/src/loaders/api/register.js +62 -89
  114. package/dist/cjs/common/util/target.js +0 -34
  115. package/dist/cjs/features/utils/entity-manager.js +0 -46
  116. package/dist/cjs/features/utils/event-store-manager.js +0 -174
  117. package/dist/cjs/loaders/api/register-api.js +0 -165
  118. package/dist/esm/common/util/target.js +0 -27
  119. package/dist/esm/features/utils/entity-manager.js +0 -39
  120. package/dist/esm/features/utils/event-store-manager.js +0 -166
  121. package/dist/esm/loaders/api/register-api.js +0 -159
  122. package/dist/types/common/util/target.d.ts +0 -18
  123. package/dist/types/common/util/target.d.ts.map +0 -1
  124. package/dist/types/features/utils/entity-manager.d.ts +0 -11
  125. package/dist/types/features/utils/entity-manager.d.ts.map +0 -1
  126. package/dist/types/features/utils/event-store-manager.d.ts +0 -85
  127. package/dist/types/features/utils/event-store-manager.d.ts.map +0 -1
  128. package/dist/types/loaders/api/register-api.d.ts +0 -14
  129. package/dist/types/loaders/api/register-api.d.ts.map +0 -1
  130. package/src/common/util/target.js +0 -27
  131. package/src/features/utils/entity-manager.js +0 -45
  132. package/src/features/utils/event-store-manager.js +0 -165
  133. package/src/loaders/api/register-api.js +0 -152
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { handle } from '../../common/event-emitter/handle'
6
6
  import { warn } from '../../common/util/console'
7
- import { isContainerAgentTarget, isValidTarget } from '../../common/util/target'
7
+ import { isValidMFETarget } from '../../common/util/mfe'
8
8
  import { FEATURE_NAMES } from '../features/features'
9
9
  import { now } from '../../common/timing/now'
10
10
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
@@ -13,6 +13,7 @@ import { REGISTER } from './constants'
13
13
  import { log } from './log'
14
14
  import { addPageAction } from './addPageAction'
15
15
  import { noticeError } from './noticeError'
16
+ import { single } from '../../common/util/invoke'
16
17
 
17
18
  /**
18
19
  * @typedef {import('./register-api-types').RegisterAPI} RegisterAPI
@@ -35,106 +36,80 @@ export function setupRegisterAPI (agent) {
35
36
  * @param {Object} agentRef the reference to the base agent instance
36
37
  * @param {Object} handlers the shared handlers to be used by both the base agent's API and the external target's API
37
38
  * @param {Object} target the target information to be used by the external target's API to send data to the correct location
39
+ * @param {string} [target.licenseKey] the license key of the target to report data to
40
+ * @param {string} target.id the entity ID of the target to report data to
41
+ * @param {string} target.name the entity name of the target to report data to
38
42
  * @returns {RegisterAPI} the api object to be returned from the register api method
39
43
  */
40
44
  export function buildRegisterApi (agentRef, target) {
41
45
  const attrs = {}
42
46
  warn(54, 'newrelic.register')
43
47
 
44
- /** @type {Function|undefined} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
45
- let invalidApiResponse
48
+ target ||= {}
49
+ target.licenseKey ||= agentRef.info.licenseKey // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
50
+ target.blocked = false
51
+
52
+ /** @type {Function} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
53
+ let invalidApiResponse = () => {}
54
+ /** @type {Array} the array of registered target APIs */
55
+ const registeredEntities = agentRef.runtime.registeredEntities
56
+
57
+ /** if we have already registered this target, go ahead and re-use it */
58
+ const preregisteredEntity = registeredEntities.find(({ metadata: { target: { id, name } } }) => id === target.id)
59
+ if (preregisteredEntity) {
60
+ if (preregisteredEntity.metadata.target.name !== target.name) preregisteredEntity.metadata.target.name = target.name
61
+ return preregisteredEntity
62
+ }
46
63
 
47
64
  /**
48
- * A promise that indicates when all needed connections for the registered child to be ready to report data
49
- * 1. The main agent to be ready (made a RUM call and got its entity guid)
50
- * 2. The child to be registered with the main agent (made its own RUM call and got its entity guid)
51
- * @type {Promise<RegisterAPI>}
52
- */
53
- let _connected
54
- if (!agentRef.init.api.allow_registered_children) invalidApiResponse = () => warn(55)
55
- if (!target || !isValidTarget(target)) invalidApiResponse = () => warn(48, target)
65
+ * Block the API, and supply a warning function to display a message to end users
66
+ * @param {Function} warning
67
+ */
68
+ const block = (warning) => {
69
+ target.blocked = true
70
+ invalidApiResponse = warning
71
+ }
72
+
73
+ /** primary cases that can block the register API from working at init time */
74
+ if (!agentRef.init.api.allow_registered_children) block(single(() => warn(55)))
75
+ if (!isValidMFETarget(target)) block(single(() => warn(48, target)))
56
76
 
57
77
  /** @type {RegisterAPI} */
58
78
  const api = {
59
- addPageAction: (name, attributes = {}) => {
60
- report(addPageAction, [name, { ...attrs, ...attributes }, agentRef], target)
61
- },
62
- log: (message, options = {}) => {
63
- report(log, [message, { ...options, customAttributes: { ...attrs, ...(options.customAttributes || {}) } }, agentRef], target)
64
- },
65
- noticeError: (error, attributes = {}) => {
66
- report(noticeError, [error, { ...attrs, ...attributes }, agentRef], target)
67
- },
68
- setApplicationVersion: (value) => {
69
- attrs['application.version'] = value
70
- },
71
- setCustomAttribute: (key, value) => {
72
- attrs[key] = value
73
- },
74
- setUserId: (value) => {
75
- attrs['enduser.id'] = value
76
- },
79
+ addPageAction: (name, attributes = {}) => report(addPageAction, [name, { ...attrs, ...attributes }, agentRef], target),
80
+ log: (message, options = {}) => report(log, [message, { ...options, customAttributes: { ...attrs, ...(options.customAttributes || {}) } }, agentRef], target),
81
+ noticeError: (error, attributes = {}) => report(noticeError, [error, { ...attrs, ...attributes }, agentRef], target),
82
+ setApplicationVersion: (value) => setLocalValue('application.version', value),
83
+ setCustomAttribute: (key, value) => setLocalValue(key, value),
84
+ setUserId: (value) => setLocalValue('enduser.id', value),
77
85
  /** metadata */
78
86
  metadata: {
79
87
  customAttributes: attrs,
80
- target,
81
- /** set in a getter so that later access of the Promise is not polluted before customer is allowed to set a catch block */
82
- get connected () {
83
- return _connected || Promise.reject(new Error('Failed to connect'))
84
- }
88
+ target
85
89
  }
86
90
  }
87
91
 
88
- if (invalidApiResponse) {
89
- invalidApiResponse()
90
- } else {
91
- _connected = new Promise((resolve, reject) => {
92
- try {
93
- const entityManager = agentRef.runtime?.entityManager
94
- /** check if main agent already has main agent entity guid */
95
- let mainAgentReady = !!entityManager?.get().entityGuid
96
- /** check if registered target already has entity guid */
97
- let registeredEntityGuid = entityManager?.getEntityGuidFor(target.licenseKey, target.applicationID)
98
- let registrationReady = !!registeredEntityGuid
99
-
100
- /** check if we can just resolve immediately without making another connect call */
101
- if (mainAgentReady && registrationReady) {
102
- target.entityGuid = registeredEntityGuid
103
- resolve(api)
104
- } else {
105
- /** we need to make a new connection call since we dont already have a registered entity for this call */
106
-
107
- /** if the connect callback doesnt resolve in 15 seconds... reject */
108
- const timeout = setTimeout(() => reject(new Error('Failed to connect - Timeout')), 15000)
109
-
110
- // tell the main agent to send a rum call for this target
111
- // when the rum call resolves, it will emit an "entity-added" event, see below
112
- agentRef.ee.emit('api-send-rum', [attrs, target])
113
-
114
- // wait for entity events to emit to see when main agent and/or API registration is ready
115
- agentRef.ee.on('entity-added', entityEventHandler)
92
+ /**
93
+ * Check if the API is blocked and emit a warning message describing the blockage
94
+ * @returns {boolean}
95
+ */
96
+ const isBlocked = () => {
97
+ if (target.blocked) invalidApiResponse()
98
+ return target.blocked
99
+ }
116
100
 
117
- function entityEventHandler (entity) {
118
- if (isContainerAgentTarget(entity, agentRef)) mainAgentReady ||= true
119
- else {
120
- if (target.licenseKey === entity.licenseKey && target.applicationID === entity.applicationID) {
121
- registrationReady = true
122
- target.entityGuid = entity.entityGuid
123
- }
124
- }
101
+ /** only allow registered APIs to be tracked in the agent runtime */
102
+ if (!isBlocked()) registeredEntities.push(api)
125
103
 
126
- if (mainAgentReady && registrationReady) {
127
- clearTimeout(timeout)
128
- // unsubscribe from the event emitter
129
- agentRef.ee.removeEventListener('entity-added', entityEventHandler)
130
- resolve(api)
131
- }
132
- }
133
- }
134
- } catch (err) {
135
- reject(err)
136
- }
137
- })
104
+ /**
105
+ * Sets a value local to the registered API attrs. Will do nothing if APIs are deregistered.
106
+ * @param {string} key The attribute key
107
+ * @param {*} value the attribute value
108
+ * @returns {void}
109
+ */
110
+ const setLocalValue = (key, value) => {
111
+ if (isBlocked()) return
112
+ attrs[key] = value
138
113
  }
139
114
 
140
115
  /**
@@ -142,23 +117,21 @@ export function buildRegisterApi (agentRef, target) {
142
117
  * If the api.duplicate_registered_data configuration value is set to true, the data will be reported to BOTH the container and the external target
143
118
  * @param {*} methodToCall the container agent's API method to call
144
119
  * @param {*} args the arguments to supply to the container agent's API method
145
- * @param {string} targetEntityGuid the target entity guid, which looks up the target to report the data to from the entity manager. If undefined, will report to the container agent's target.
120
+ * @param {string} target the target to report the data to. If undefined, will report to the container agent's target.
146
121
  * @returns
147
122
  */
148
- const report = async (methodToCall, args, target) => {
149
- if (invalidApiResponse) return invalidApiResponse()
123
+ const report = (methodToCall, args, target) => {
124
+ if (isBlocked()) return
150
125
  /** set the timestamp before the async part of waiting for the rum response for better accuracy */
151
126
  const timestamp = now()
152
127
  handle(SUPPORTABILITY_METRIC_CHANNEL, [`API/register/${methodToCall.name}/called`], undefined, FEATURE_NAMES.metrics, agentRef.ee)
153
128
  try {
154
- await _connected
155
- // target should be decorated with entityGuid by the rum resp at this point
156
129
  const shouldDuplicate = agentRef.init.api.duplicate_registered_data
157
- if (shouldDuplicate === true || (Array.isArray(shouldDuplicate) && shouldDuplicate.includes(target.entityGuid))) {
130
+ if (shouldDuplicate === true || Array.isArray(shouldDuplicate)) {
158
131
  // also report to container by providing undefined target
159
132
  methodToCall(...args, undefined, timestamp)
160
133
  }
161
- methodToCall(...args, target.entityGuid, timestamp) // always report to target
134
+ return methodToCall(...args, target, timestamp) // always report to target
162
135
  } catch (err) {
163
136
  warn(50, err)
164
137
  }
@@ -1,34 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isContainerAgentTarget = isContainerAgentTarget;
7
- exports.isValidTarget = isValidTarget;
8
- /**
9
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
10
- * SPDX-License-Identifier: Apache-2.0
11
- */
12
-
13
- /**
14
- * @param {Object} [target] - the target to be validated
15
- * @param {boolean} [allowUndefined=true]
16
- * @returns {boolean}
17
- */
18
- function isValidTarget(target) {
19
- /** target can be undefined to support legacy/default behaviors - main agent does not supply a target */
20
- if (!target) return true;
21
- /** if not undefined, we require specific values */
22
- return !!(target.licenseKey && target.applicationID);
23
- }
24
-
25
- /**
26
- * Checks if the target matches the container agent target
27
- * @param {*} target the target to be validated
28
- * @param {*} agentRef the agent reference to be validated
29
- * @returns {boolean}
30
- */
31
- function isContainerAgentTarget(target, agentRef) {
32
- if (!target) return true;
33
- return target.licenseKey === agentRef.info.licenseKey && target.applicationID === agentRef.info.applicationID;
34
- }
@@ -1,46 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.EntityManager = void 0;
7
- var _agentConstants = require("../../common/constants/agent-constants");
8
- /**
9
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
10
- * SPDX-License-Identifier: Apache-2.0
11
- */
12
-
13
- class EntityManager {
14
- #entities = new Map();
15
- #entityGuidLookup = {};
16
- constructor(agentRef) {
17
- this.agentRef = agentRef;
18
- this.#entities.set(_agentConstants.DEFAULT_KEY, {
19
- licenseKey: agentRef.info.licenseKey,
20
- applicationID: agentRef.info.applicationID
21
- });
22
- }
23
- get(entityGuid = _agentConstants.DEFAULT_KEY) {
24
- return this.#entities.get(entityGuid);
25
- }
26
- getEntityGuidFor(licenseKey, applicationID) {
27
- if (!this.#entityGuidLookup[licenseKey] || !this.#entityGuidLookup[applicationID]) return;
28
- return this.#entityGuidLookup[licenseKey].filter(x => this.#entityGuidLookup[applicationID].includes(x))[0];
29
- }
30
- set(entityGuid, entity) {
31
- if (this.#entities.has(entityGuid)) return;
32
- this.#entities.set(entityGuid, entity);
33
- this.#entityGuidLookup[entity.licenseKey] ??= [];
34
- this.#entityGuidLookup[entity.licenseKey].push(entityGuid);
35
- this.#entityGuidLookup[entity.applicationID] ??= [];
36
- this.#entityGuidLookup[entity.applicationID].push(entityGuid);
37
- this.agentRef.ee.emit('entity-added', [entity]);
38
- }
39
- clear() {
40
- this.#entities.clear();
41
- }
42
- setDefaultEntity(entity) {
43
- this.#entities.set(_agentConstants.DEFAULT_KEY, entity);
44
- }
45
- }
46
- exports.EntityManager = EntityManager;
@@ -1,174 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.EventStoreManager = void 0;
7
- var _agentConstants = require("../../common/constants/agent-constants");
8
- var _target = require("../../common/util/target");
9
- /**
10
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
11
- * SPDX-License-Identifier: Apache-2.0
12
- */
13
-
14
- /**
15
- * This layer allows multiple browser entity apps, or "target", to each have their own segregated storage instance.
16
- * 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.
17
- */
18
- class EventStoreManager {
19
- /**
20
- * @param {object} agentRef - reference to base agent class
21
- * @param {EventBuffer|EventAggregator} storageClass - the type of storage to use in this manager; 'EventBuffer' (1), 'EventAggregator' (2)
22
- * @param {string} [defaultEntityGuid] - the entity guid to use as the default storage instance; if not provided, a new one is created
23
- * @param {Object} featureAgg - the feature aggregate instance that initialized this manager
24
- */
25
- constructor(agentRef, storageClass, defaultEntityGuid, featureAgg) {
26
- this.agentRef = agentRef;
27
- this.entityManager = agentRef.runtime.entityManager;
28
- this.StorageClass = storageClass;
29
- this.appStorageMap = new Map([[_agentConstants.DEFAULT_KEY, new this.StorageClass(_agentConstants.MAX_PAYLOAD_SIZE, featureAgg)]]);
30
- this.featureAgg = featureAgg;
31
- this.setEventStore(defaultEntityGuid);
32
- }
33
-
34
- /**
35
- * Always returns a storage instance. Creates one if one does not exist. If a lookup is not provided, uses the DEFAULT namespace
36
- * @param {string=} targetEntityGuid the lookup
37
- * @returns {*} ALWAYS returns a storage instance
38
- */
39
- #getEventStore(targetEntityGuid = _agentConstants.DEFAULT_KEY) {
40
- if (!this.appStorageMap.has(targetEntityGuid)) this.setEventStore(targetEntityGuid);
41
- return this.appStorageMap.get(targetEntityGuid);
42
- }
43
- setEventStore(targetEntityGuid) {
44
- /** we should already have an event store for the default */
45
- if (!targetEntityGuid) return;
46
- /** if the target is the container agent, SHARE the default storage -- otherwise create a new event store */
47
- const eventStorage = (0, _target.isContainerAgentTarget)(this.entityManager.get(targetEntityGuid), this.agentRef) ? this.appStorageMap.get(_agentConstants.DEFAULT_KEY) : new this.StorageClass(_agentConstants.MAX_PAYLOAD_SIZE, this.featureAgg);
48
- this.appStorageMap.set(targetEntityGuid, eventStorage);
49
- }
50
-
51
- /** IMPORTANT
52
- * This class must contain an union of all methods from all supported storage classes and conceptualize away the target app argument.
53
- */
54
-
55
- get length() {
56
- return this.#getEventStore().length;
57
- }
58
-
59
- /**
60
- * Calls the merge method on the underlying storage class.
61
- * @param {*} matcher
62
- * @param {*} data
63
- * @param {*} targetEntityGuid
64
- * @returns {boolean} True if the merge was successful
65
- */
66
- merge(matcher, data, targetEntityGuid) {
67
- return this.#getEventStore(targetEntityGuid).merge(matcher, data);
68
- }
69
-
70
- /**
71
- * Calls the isEmpty method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
72
- * @param {object} optsIfPresent - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
73
- * @param {object} target - specific app's storage to check; if not provided, this method takes into account all apps recorded by this manager
74
- * @returns {boolean} True if the target's storage is empty, or target does not exist in map (defaults to all storages)
75
- */
76
- isEmpty(optsIfPresent, targetEntityGuid) {
77
- if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).isEmpty(optsIfPresent);
78
- for (const eventStore of this.appStorageMap.values()) {
79
- if (!eventStore.isEmpty(optsIfPresent)) return false;
80
- }
81
- return true;
82
- }
83
-
84
- /**
85
- * Calls the add method on the underlying storage class.
86
- * @param {string} event - the event element to store
87
- * @param {object} targetEntityGuid - the entity guid lookup to store event under; if not provided, this method adds to the default
88
- * @returns {boolean} True if the event was successfully added
89
- */
90
- add(event, targetEntityGuid) {
91
- return this.#getEventStore(targetEntityGuid).add(event);
92
- }
93
-
94
- /** This is only used by the Metrics feature which has no need to add metric under a different app atm. */
95
- addMetric(type, name, params, value) {
96
- return this.#getEventStore().addMetric(type, name, params, value);
97
- }
98
-
99
- /**
100
- * Calls the get method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
101
- * @param {object=} opts - exists if called during harvest interval, @see AggregateBase.makeHarvestPayload
102
- * @param {object=} target - specific app to fetch; if not provided, this method fetches from all apps
103
- * @returns {Array} Objects of `data` labeled with their respective `target` app to be sent to
104
- */
105
- get(opts, targetEntityGuid) {
106
- if (targetEntityGuid) return [{
107
- targetApp: this.entityManager.get(targetEntityGuid),
108
- data: this.#getEventStore(targetEntityGuid).get(opts)
109
- }];
110
- const allPayloads = [];
111
- this.appStorageMap.forEach((eventStore, targetEntityGuid) => {
112
- // We shouldnt harvest unless we have a valid entity guid. It was ONLY stored under the default key temporarily
113
- // until a real key was returned in the RUM call. The real key SHARES the event store with the default key, and
114
- // should be the key that is honored to get the event store to ensure a valid connection was made.
115
- if (targetEntityGuid === _agentConstants.DEFAULT_KEY) return;
116
- const targetApp = this.entityManager.get(targetEntityGuid);
117
- if (targetApp) allPayloads.push({
118
- targetApp,
119
- data: eventStore.get(opts)
120
- });
121
- });
122
- return allPayloads;
123
- }
124
-
125
- /**
126
- * Calls the byteSize method on the underlying storage class
127
- * @param {*} targetEntityGuid
128
- * @returns
129
- */
130
- byteSize(targetEntityGuid) {
131
- return this.#getEventStore(targetEntityGuid).byteSize();
132
- }
133
-
134
- /**
135
- * Calls the wouldExceedMaxSize method on the underlying storage class
136
- * @param {*} incomingSize
137
- * @param {*} targetEntityGuid
138
- * @returns
139
- */
140
- wouldExceedMaxSize(incomingSize, targetEntityGuid) {
141
- return this.#getEventStore(targetEntityGuid).wouldExceedMaxSize(incomingSize);
142
- }
143
-
144
- /**
145
- * Calls the save method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
146
- * @param {*} optsIfPresent
147
- * @param {*} targetEntityGuid
148
- * @returns
149
- */
150
- save(optsIfPresent, targetEntityGuid) {
151
- if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).save(optsIfPresent);
152
- this.appStorageMap.forEach(eventStore => eventStore.save(optsIfPresent));
153
- }
154
-
155
- /**
156
- * Calls the clear method on the underlying storage class. If target is provided, runs just for the target, otherwise runs for all apps.
157
- * @param {*} optsIfPresent
158
- * @param {*} targetEntityGuid
159
- * @returns
160
- */
161
- clear(optsIfPresent, targetEntityGuid) {
162
- if (targetEntityGuid) return this.#getEventStore(targetEntityGuid).clear(optsIfPresent);
163
- this.appStorageMap.forEach(eventStore => eventStore.clear(optsIfPresent));
164
- }
165
-
166
- // Unlike the methods above, the following will have a target as they are called by AggregateBase.postHarvestCleanup callback on harvest finish after getting & sending the data.
167
- reloadSave(optsIfPresent, targetEntityGuid) {
168
- return this.#getEventStore(targetEntityGuid).reloadSave(optsIfPresent);
169
- }
170
- clearSave(optsIfPresent, targetEntityGuid) {
171
- return this.#getEventStore(targetEntityGuid).clearSave(optsIfPresent);
172
- }
173
- }
174
- exports.EventStoreManager = EventStoreManager;
@@ -1,165 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.buildRegisterApi = buildRegisterApi;
7
- var _handle = require("../../common/event-emitter/handle");
8
- var _console = require("../../common/util/console");
9
- var _target = require("../../common/util/target");
10
- var _features = require("../features/features");
11
- var _now = require("../../common/timing/now");
12
- var _constants = require("../../features/metrics/constants");
13
- /**
14
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
15
- * SPDX-License-Identifier: Apache-2.0
16
- */
17
-
18
- /**
19
- * @typedef {import('./register-api-types').RegisterAPI} RegisterAPI
20
- */
21
-
22
- /**
23
- * Builds the api object that will be returned from the register api method.
24
- * Also conducts certain side-effects, such as harvesting a PageView event when triggered and gathering metadata for the registered entity.
25
- * @param {Object} agentRef the reference to the base agent instance
26
- * @param {Object} handlers the shared handlers to be used by both the base agent's API and the external target's API
27
- * @param {Object} target the target information to be used by the external target's API to send data to the correct location
28
- * @returns {RegisterAPI} the api object to be returned from the register api method
29
- */
30
- function buildRegisterApi(agentRef, handlers, target) {
31
- const attrs = {};
32
- (0, _console.warn)(54, 'newrelic.register');
33
-
34
- /** @type {Function|undefined} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
35
- let invalidApiResponse;
36
-
37
- /**
38
- * A promise that indicates when all needed connections for the registered child to be ready to report data
39
- * 1. The main agent to be ready (made a RUM call and got its entity guid)
40
- * 2. The child to be registered with the main agent (made its own RUM call and got its entity guid)
41
- * @type {Promise<RegisterAPI>}
42
- */
43
- let _connected;
44
- if (!agentRef.init.api.allow_registered_children) invalidApiResponse = () => (0, _console.warn)(55);
45
- if (!target || !(0, _target.isValidTarget)(target)) invalidApiResponse = () => (0, _console.warn)(48, target);
46
-
47
- /** @type {RegisterAPI} */
48
- const api = {
49
- addPageAction: (name, attributes = {}) => {
50
- report(handlers.addPageAction, [name, {
51
- ...attrs,
52
- ...attributes
53
- }], target);
54
- },
55
- log: (message, options = {}) => {
56
- report(handlers.log, [message, {
57
- ...options,
58
- customAttributes: {
59
- ...attrs,
60
- ...(options.customAttributes || {})
61
- }
62
- }], target);
63
- },
64
- noticeError: (error, attributes = {}) => {
65
- report(handlers.noticeError, [error, {
66
- ...attrs,
67
- ...attributes
68
- }], target);
69
- },
70
- setApplicationVersion: value => {
71
- attrs['application.version'] = value;
72
- },
73
- setCustomAttribute: (key, value) => {
74
- attrs[key] = value;
75
- },
76
- setUserId: value => {
77
- attrs['enduser.id'] = value;
78
- },
79
- /** metadata */
80
- metadata: {
81
- customAttributes: attrs,
82
- target,
83
- /** set in a getter so that later access of the Promise is not polluted before customer is allowed to set a catch block */
84
- get connected() {
85
- return _connected || Promise.reject(new Error('Failed to connect'));
86
- }
87
- }
88
- };
89
- if (invalidApiResponse) {
90
- invalidApiResponse();
91
- } else {
92
- _connected = new Promise((resolve, reject) => {
93
- try {
94
- const entityManager = agentRef.runtime?.entityManager;
95
- /** check if main agent already has main agent entity guid */
96
- let mainAgentReady = !!entityManager?.get().entityGuid;
97
- /** check if registered target already has entity guid */
98
- let registeredEntityGuid = entityManager?.getEntityGuidFor(target.licenseKey, target.applicationID);
99
- let registrationReady = !!registeredEntityGuid;
100
-
101
- /** check if we can just resolve immediately without making another connect call */
102
- if (mainAgentReady && registrationReady) {
103
- target.entityGuid = registeredEntityGuid;
104
- resolve(api);
105
- } else {
106
- /** we need to make a new connection call since we dont already have a registered entity for this call */
107
-
108
- /** if the connect callback doesnt resolve in 15 seconds... reject */
109
- const timeout = setTimeout(() => reject(new Error('Failed to connect - Timeout')), 15000);
110
-
111
- // tell the main agent to send a rum call for this target
112
- // when the rum call resolves, it will emit an "entity-added" event, see below
113
- agentRef.ee.emit('api-send-rum', [attrs, target]);
114
-
115
- // wait for entity events to emit to see when main agent and/or API registration is ready
116
- agentRef.ee.on('entity-added', entityEventHandler);
117
- function entityEventHandler(entity) {
118
- if ((0, _target.isContainerAgentTarget)(entity, agentRef)) mainAgentReady ||= true;else {
119
- if (target.licenseKey === entity.licenseKey && target.applicationID === entity.applicationID) {
120
- registrationReady = true;
121
- target.entityGuid = entity.entityGuid;
122
- }
123
- }
124
- if (mainAgentReady && registrationReady) {
125
- clearTimeout(timeout);
126
- // unsubscribe from the event emitter
127
- agentRef.ee.removeEventListener('entity-added', entityEventHandler);
128
- resolve(api);
129
- }
130
- }
131
- }
132
- } catch (err) {
133
- reject(err);
134
- }
135
- });
136
- }
137
-
138
- /**
139
- * The reporter method that will be used to report the data to the container agent's API method. If invalid, will log a warning and not execute.
140
- * If the api.duplicate_registered_data configuration value is set to true, the data will be reported to BOTH the container and the external target
141
- * @param {*} methodToCall the container agent's API method to call
142
- * @param {*} args the arguments to supply to the container agent's API method
143
- * @param {string} targetEntityGuid the target entity guid, which looks up the target to report the data to from the entity manager. If undefined, will report to the container agent's target.
144
- * @returns
145
- */
146
- const report = async (methodToCall, args, target) => {
147
- if (invalidApiResponse) return invalidApiResponse();
148
- /** set the timestamp before the async part of waiting for the rum response for better accuracy */
149
- const timestamp = (0, _now.now)();
150
- (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/register/".concat(methodToCall.name, "/called")], undefined, _features.FEATURE_NAMES.metrics, agentRef.ee);
151
- try {
152
- await _connected;
153
- // target should be decorated with entityGuid by the rum resp at this point
154
- const shouldDuplicate = agentRef.init.api.duplicate_registered_data;
155
- if (shouldDuplicate === true || Array.isArray(shouldDuplicate) && shouldDuplicate.includes(target.entityGuid)) {
156
- // also report to container by providing undefined target
157
- methodToCall(...args, undefined, timestamp);
158
- }
159
- methodToCall(...args, target.entityGuid, timestamp); // always report to target
160
- } catch (err) {
161
- (0, _console.warn)(50, err);
162
- }
163
- };
164
- return api;
165
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- /**
7
- * @param {Object} [target] - the target to be validated
8
- * @param {boolean} [allowUndefined=true]
9
- * @returns {boolean}
10
- */
11
- export function isValidTarget(target) {
12
- /** target can be undefined to support legacy/default behaviors - main agent does not supply a target */
13
- if (!target) return true;
14
- /** if not undefined, we require specific values */
15
- return !!(target.licenseKey && target.applicationID);
16
- }
17
-
18
- /**
19
- * Checks if the target matches the container agent target
20
- * @param {*} target the target to be validated
21
- * @param {*} agentRef the agent reference to be validated
22
- * @returns {boolean}
23
- */
24
- export function isContainerAgentTarget(target, agentRef) {
25
- if (!target) return true;
26
- return target.licenseKey === agentRef.info.licenseKey && target.applicationID === agentRef.info.applicationID;
27
- }