@newrelic/browser-agent 1.285.0 → 1.286.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 (65) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +6 -0
  3. package/dist/cjs/common/constants/env.cdn.js +1 -1
  4. package/dist/cjs/common/constants/env.npm.js +1 -1
  5. package/dist/cjs/common/dom/selector-path.js +1 -1
  6. package/dist/cjs/common/harvest/harvester.js +1 -1
  7. package/dist/cjs/common/util/feature-flags.js +2 -1
  8. package/dist/cjs/features/session_replay/shared/recorder.js +5 -0
  9. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +3 -2
  10. package/dist/cjs/features/utils/aggregate-base.js +2 -4
  11. package/dist/cjs/features/utils/event-store-manager.js +1 -1
  12. package/dist/cjs/features/utils/nr1-debugger.js +1 -1
  13. package/dist/cjs/loaders/agent-base.js +1 -1
  14. package/dist/cjs/loaders/agent.js +3 -1
  15. package/dist/cjs/loaders/api/api.js +57 -61
  16. package/dist/cjs/loaders/api/apiAsync.js +19 -22
  17. package/dist/cjs/loaders/configure/configure.js +12 -15
  18. package/dist/cjs/loaders/micro-agent-base.js +1 -1
  19. package/dist/cjs/loaders/micro-agent.js +3 -1
  20. package/dist/esm/common/constants/env.cdn.js +1 -1
  21. package/dist/esm/common/constants/env.npm.js +1 -1
  22. package/dist/esm/common/dom/selector-path.js +1 -1
  23. package/dist/esm/common/harvest/harvester.js +1 -1
  24. package/dist/esm/common/util/feature-flags.js +2 -1
  25. package/dist/esm/features/session_replay/shared/recorder.js +5 -0
  26. package/dist/esm/features/session_trace/aggregate/trace/storage.js +3 -2
  27. package/dist/esm/features/utils/aggregate-base.js +2 -4
  28. package/dist/esm/features/utils/event-store-manager.js +1 -1
  29. package/dist/esm/features/utils/nr1-debugger.js +1 -1
  30. package/dist/esm/loaders/agent-base.js +1 -1
  31. package/dist/esm/loaders/agent.js +3 -1
  32. package/dist/esm/loaders/api/api.js +56 -60
  33. package/dist/esm/loaders/api/apiAsync.js +14 -17
  34. package/dist/esm/loaders/configure/configure.js +13 -16
  35. package/dist/esm/loaders/micro-agent-base.js +1 -1
  36. package/dist/esm/loaders/micro-agent.js +3 -1
  37. package/dist/types/common/dom/selector-path.d.ts.map +1 -1
  38. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  39. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  40. package/dist/types/loaders/agent.d.ts +1 -0
  41. package/dist/types/loaders/agent.d.ts.map +1 -1
  42. package/dist/types/loaders/api/api.d.ts +1 -20
  43. package/dist/types/loaders/api/api.d.ts.map +1 -1
  44. package/dist/types/loaders/api/apiAsync.d.ts +1 -1
  45. package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
  46. package/dist/types/loaders/configure/configure.d.ts +1 -0
  47. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  48. package/dist/types/loaders/micro-agent.d.ts +1 -0
  49. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/common/dom/selector-path.js +1 -3
  52. package/src/common/harvest/harvester.js +1 -1
  53. package/src/common/util/feature-flags.js +2 -1
  54. package/src/features/session_replay/shared/recorder.js +5 -0
  55. package/src/features/session_trace/aggregate/trace/storage.js +2 -2
  56. package/src/features/utils/aggregate-base.js +2 -2
  57. package/src/features/utils/event-store-manager.js +1 -1
  58. package/src/features/utils/nr1-debugger.js +1 -1
  59. package/src/loaders/agent-base.js +2 -2
  60. package/src/loaders/agent.js +4 -1
  61. package/src/loaders/api/api.js +56 -60
  62. package/src/loaders/api/apiAsync.js +14 -18
  63. package/src/loaders/configure/configure.js +12 -12
  64. package/src/loaders/micro-agent-base.js +2 -2
  65. package/src/loaders/micro-agent.js +4 -1
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Sets or re-sets the agent's configuration values from global settings. This also attach those as properties to the agent instance.
3
+ * IMPORTANT: setNREUMInitializedAgent must be called on the agent prior to calling this function.
3
4
  */
4
5
  export function configure(agent: any, opts: {} | undefined, loaderType: any, forceDrain: any): void;
5
6
  //# sourceMappingURL=configure.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"AAkBA;;GAEG;AACH,oGA+DC"}
1
+ {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../../../src/loaders/configure/configure.js"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,oGA8DC"}
@@ -21,6 +21,7 @@ export class MicroAgent extends MicroAgentBase {
21
21
  loader_config: any;
22
22
  runtime: any;
23
23
  };
24
+ get api(): this;
24
25
  }
25
26
  import { MicroAgentBase } from './micro-agent-base';
26
27
  //# sourceMappingURL=micro-agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAsBA;;;;GAIG;AACH;IACE;;OAEG;IACH,qBAFW,OAAO,SAAS,EAAE,YAAY,EAsDxC;IAjDC,aAAkB;IAMlB;;;;OAIG;IACH,uBAFW,MAAM,GAAC,MAAM,EAAE,aAqCzB;IAKH;;;;;MAOC;CACF;+BAhF8B,oBAAoB"}
1
+ {"version":3,"file":"micro-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/micro-agent.js"],"names":[],"mappings":"AAsBA;;;;GAIG;AACH;IACE;;OAEG;IACH,qBAFW,OAAO,SAAS,EAAE,YAAY,EAqDxC;IAhDC,aAAkB;IAKlB;;;;OAIG;IACH,uBAFW,MAAM,GAAC,MAAM,EAAE,aAqCzB;IAKH;;;;;MAOC;IAED,gBAEC;CACF;+BAnF8B,oBAAoB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.285.0",
3
+ "version": "1.286.0",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -34,9 +34,7 @@ export const generateSelectorPath = (elem, targetFields = []) => {
34
34
  try {
35
35
  while (elem?.tagName) {
36
36
  const { id, localName } = elem
37
- targetFields.forEach(field => {
38
- nearestFields[nearestAttrName(field)] ||= elem[field]
39
- })
37
+ targetFields.forEach(field => { nearestFields[nearestAttrName(field)] ||= (elem[field]?.baseVal || elem[field]) })
40
38
  const selector = [
41
39
  localName,
42
40
  id ? `#${id}` : '',
@@ -178,7 +178,7 @@ function send (agentRef, { endpoint, targetApp, payload, localOpts = {}, submitM
178
178
 
179
179
  dispatchGlobalEvent({
180
180
  agentIdentifier: agentRef.agentIdentifier,
181
- loaded: !!activatedFeatures?.[agentRef.agentIdentifier],
181
+ drained: !!activatedFeatures?.[agentRef.agentIdentifier],
182
182
  type: 'data',
183
183
  name: 'harvest',
184
184
  feature: featureName,
@@ -28,10 +28,11 @@ export function activateFeatures (flags, agentIdentifier) {
28
28
 
29
29
  sentIds.add(agentIdentifier)
30
30
 
31
- // let any window level subscribers know that the agent is running
31
+ // let any window level subscribers know that the agent is running, per install docs
32
32
  dispatchGlobalEvent({
33
33
  agentIdentifier,
34
34
  loaded: true,
35
+ drained: true,
35
36
  type: 'lifecycle',
36
37
  name: 'load',
37
38
  feature: undefined,
@@ -14,6 +14,8 @@ import { FEATURE_NAMES } from '../../../loaders/features/features'
14
14
  import { buildNRMetaNode, customMasker } from './utils'
15
15
  import { IDEAL_PAYLOAD_SIZE } from '../../../common/constants/agent-constants'
16
16
  import { AggregateBase } from '../../utils/aggregate-base'
17
+ import { warn } from '../../../common/util/console'
18
+ import { single } from '../../../common/util/invoke'
17
19
 
18
20
  export class Recorder {
19
21
  /** Each page mutation or event will be stored (raw) in this array. This array will be cleared on each harvest */
@@ -25,6 +27,8 @@ export class Recorder {
25
27
  /** flag that if true, blocks events from being "stored". Only set to true when a full snapshot has incomplete nodes (only stylesheets ATM) */
26
28
  #fixing = false
27
29
 
30
+ #warnCSSOnce = single(() => warn(47)) // notifies user of potential replayer issue if fix_stylesheets is off
31
+
28
32
  constructor (parent) {
29
33
  this.#events = new RecorderEvents()
30
34
  this.#backloggedEvents = new RecorderEvents()
@@ -120,6 +124,7 @@ export class Recorder {
120
124
  if (!this.shouldFix) {
121
125
  if (incompletes > 0) {
122
126
  this.currentBufferTarget.inlinedAllStylesheets = false
127
+ this.#warnCSSOnce()
123
128
  handle(SUPPORTABILITY_METRIC_CHANNEL, [missingInlineSMTag + 'Skipped', incompletes], undefined, FEATURE_NAMES.metrics, this.parent.ee)
124
129
  }
125
130
  return this.store(event, isCheckout)
@@ -15,7 +15,7 @@ const SUPPORTS_PERFORMANCE_OBSERVER = typeof globalScope.PerformanceObserver ===
15
15
 
16
16
  const ignoredEvents = {
17
17
  // we find that certain events make the data too noisy to be useful
18
- global: { mouseup: true, mousedown: true },
18
+ global: { mouseup: true, mousedown: true, mousemove: true },
19
19
  // certain events are present both in the window and in PVT metrics. PVT metrics are prefered so the window events should be ignored
20
20
  window: { load: true, pagehide: true },
21
21
  // when ajax instrumentation is disabled, all XMLHttpRequest events will return with origin = xhrOriginMissing and should be ignored
@@ -182,8 +182,8 @@ export class TraceStorage {
182
182
  }
183
183
 
184
184
  shouldIgnoreEvent (event, target) {
185
- const origin = eventOrigin(event.target, target, this.parent.ee)
186
185
  if (event.type in ignoredEvents.global) return true
186
+ const origin = eventOrigin(event.target, target, this.parent.ee)
187
187
  if (!!ignoredEvents[origin] && ignoredEvents[origin].ignoreAll) return true
188
188
  return !!(!!ignoredEvents[origin] && event.type in ignoredEvents[origin])
189
189
  }
@@ -136,14 +136,14 @@ export class AggregateBase extends FeatureBase {
136
136
  } catch (err) {
137
137
  // do nothing
138
138
  }
139
- configure({ agentIdentifier: this.agentIdentifier }, {
139
+ configure(existingAgent, {
140
140
  ...cdn,
141
141
  info: {
142
142
  ...cdn.info,
143
143
  jsAttributes
144
144
  },
145
145
  runtime: existingAgent.runtime
146
- })
146
+ }, existingAgent.runtime.loaderType)
147
147
  }
148
148
  }
149
149
 
@@ -53,7 +53,7 @@ export class EventStoreManager {
53
53
  add (event, target) {
54
54
  dispatchGlobalEvent({
55
55
  agentIdentifier: this.agentIdentifier,
56
- loaded: !!activatedFeatures?.[this.agentIdentifier],
56
+ drained: !!activatedFeatures?.[this.agentIdentifier],
57
57
  type: 'data',
58
58
  name: 'buffer',
59
59
  feature: this.featureName,
@@ -7,7 +7,7 @@ import { gosCDN } from '../../common/window/nreum'
7
7
  const debugId = 1
8
8
  const newrelic = gosCDN()
9
9
  export function debugNR1 (agentIdentifier, location, event, otherprops = {}, debugName = 'SR') {
10
- const api = agentIdentifier ? newrelic.initializedAgents[agentIdentifier].api.addPageAction : newrelic.addPageAction
10
+ const api = agentIdentifier ? newrelic.initializedAgents[agentIdentifier].addPageAction : newrelic.addPageAction
11
11
  let url
12
12
  try {
13
13
  const locURL = new URL(window.location)
@@ -20,8 +20,8 @@ export class AgentBase extends MicroAgentBase {
20
20
  * @param {...any} args
21
21
  */
22
22
  #callMethod (methodName, ...args) {
23
- if (typeof this.api?.[methodName] !== 'function') warn(35, methodName)
24
- else return this.api[methodName](...args)
23
+ if (this[methodName] === AgentBase.prototype[methodName] || this[methodName] === MicroAgentBase.prototype[methodName]) warn(35, methodName)
24
+ else return this[methodName](...args)
25
25
  }
26
26
 
27
27
  /**
@@ -72,6 +72,10 @@ export class Agent extends AgentBase {
72
72
  }
73
73
  }
74
74
 
75
+ get api () {
76
+ return this
77
+ }
78
+
75
79
  run () {
76
80
  // Attempt to initialize all the requested features (sequentially in prio order & synchronously), with any failure aborting the whole process.
77
81
  try {
@@ -102,7 +106,6 @@ export class Agent extends AgentBase {
102
106
  }
103
107
 
104
108
  const newrelic = gosNREUM()
105
- delete newrelic.initializedAgents[this.agentIdentifier]?.api // prevent further calls to agent-specific APIs (see "configure.js")
106
109
  delete newrelic.initializedAgents[this.agentIdentifier]?.features // GC mem used internally by features
107
110
  delete this.sharedAggregator
108
111
  // Keep the initialized agent object with its configs for troubleshooting purposes.
@@ -3,10 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { FEATURE_NAMES } from '../features/features'
6
- import { getInfo, setInfo } from '../../common/config/info'
7
- import { getRuntime } from '../../common/config/runtime'
6
+ import { setInfo } from '../../common/config/info'
8
7
  import { handle } from '../../common/event-emitter/handle'
9
- import { ee } from '../../common/event-emitter/contextual-ee'
10
8
  import { drain, registerDrain } from '../../common/drain/drain'
11
9
  import { onWindowLoad } from '../../common/window/load'
12
10
  import { isBrowserScope } from '../../common/constants/runtime'
@@ -31,55 +29,53 @@ export function setTopLevelCallers () {
31
29
 
32
30
  function caller (fnName, ...args) {
33
31
  let returnVals = []
34
- Object.values(nr.initializedAgents).forEach(val => {
35
- if (!val || !val.api) {
32
+ Object.values(nr.initializedAgents).forEach(agt => {
33
+ if (!agt || !agt.runtime) {
36
34
  warn(38, fnName)
37
- } else if (val.exposed && val.api[fnName]) {
38
- returnVals.push(val.api[fnName](...args))
35
+ } else if (agt.exposed && agt[fnName] && agt.runtime.loaderType !== 'micro-agent') {
36
+ returnVals.push(agt[fnName](...args))
39
37
  }
40
38
  })
41
- return returnVals.length > 1 ? returnVals : returnVals[0]
39
+ return returnVals[0]
42
40
  }
43
41
  }
44
42
 
45
43
  const replayRunning = {}
46
44
 
47
- export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false) {
48
- if (!forceDrain) registerDrain(agentIdentifier, 'api')
49
- const apiInterface = {}
50
- var instanceEE = ee.get(agentIdentifier)
51
- var tracerEE = instanceEE.get('tracer')
45
+ export function setAPI (agent, forceDrain) {
46
+ if (!forceDrain) registerDrain(agent.agentIdentifier, 'api')
47
+ const tracerEE = agent.ee.get('tracer')
52
48
 
53
- replayRunning[agentIdentifier] = MODE.OFF
49
+ replayRunning[agent.agentIdentifier] = MODE.OFF
54
50
 
55
- instanceEE.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, (isRunning) => {
56
- replayRunning[agentIdentifier] = isRunning
51
+ agent.ee.on(SR_EVENT_EMITTER_TYPES.REPLAY_RUNNING, (isRunning) => {
52
+ replayRunning[agent.agentIdentifier] = isRunning
57
53
  })
58
54
 
59
- var prefix = 'api-'
60
- var spaPrefix = prefix + 'ixn-'
55
+ const prefix = 'api-'
56
+ const spaPrefix = prefix + 'ixn-'
61
57
 
62
- apiInterface.log = function (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) {
63
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/log/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
64
- bufferLog(instanceEE, message, customAttributes, level)
58
+ agent.log = function (message, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) {
59
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/log/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
60
+ bufferLog(agent.ee, message, customAttributes, level)
65
61
  }
66
62
 
67
- apiInterface.wrapLogger = (parent, functionName, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) => {
68
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/wrapLogger/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
69
- wrapLogger(instanceEE, parent, functionName, { customAttributes, level })
63
+ agent.wrapLogger = (parent, functionName, { customAttributes = {}, level = LOG_LEVELS.INFO } = {}) => {
64
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/wrapLogger/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
65
+ wrapLogger(agent.ee, parent, functionName, { customAttributes, level })
70
66
  }
71
67
 
72
68
  // Setup stub functions that queue calls for later processing.
73
- asyncApiMethods.forEach(fnName => { apiInterface[fnName] = apiCall(prefix, fnName, true, 'api') })
69
+ asyncApiMethods.forEach(fnName => { agent[fnName] = apiCall(prefix, fnName, true, 'api') })
74
70
 
75
- apiInterface.addPageAction = apiCall(prefix, 'addPageAction', true, FEATURE_NAMES.genericEvents)
71
+ agent.addPageAction = apiCall(prefix, 'addPageAction', true, FEATURE_NAMES.genericEvents)
76
72
 
77
- apiInterface.recordCustomEvent = apiCall(prefix, 'recordCustomEvent', true, FEATURE_NAMES.genericEvents)
73
+ agent.recordCustomEvent = apiCall(prefix, 'recordCustomEvent', true, FEATURE_NAMES.genericEvents)
78
74
 
79
- apiInterface.setPageViewName = function (name, host) {
75
+ agent.setPageViewName = function (name, host) {
80
76
  if (typeof name !== 'string') return
81
77
  if (name.charAt(0) !== '/') name = '/' + name
82
- getRuntime(agentIdentifier).customTransaction = (host || 'http://custom.transaction') + name
78
+ agent.runtime.customTransaction = (host || 'http://custom.transaction') + name
83
79
  return apiCall(prefix, 'setPageViewName', true)()
84
80
  }
85
81
 
@@ -92,15 +88,15 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
92
88
  * @returns @see apiCall
93
89
  */
94
90
  function appendJsAttribute (key, value, apiName, addToBrowserStorage) {
95
- const currentInfo = getInfo(agentIdentifier)
91
+ const currentInfo = agent.info
96
92
  if (value === null) {
97
93
  delete currentInfo.jsAttributes[key]
98
94
  } else {
99
- setInfo(agentIdentifier, { ...currentInfo, jsAttributes: { ...currentInfo.jsAttributes, [key]: value } })
95
+ setInfo(agent.agentIdentifier, { ...currentInfo, jsAttributes: { ...currentInfo.jsAttributes, [key]: value } })
100
96
  }
101
97
  return apiCall(prefix, apiName, true, (!!addToBrowserStorage || value === null) ? 'session' : undefined)(key, value)
102
98
  }
103
- apiInterface.setCustomAttribute = function (name, value, persistAttribute = false) {
99
+ agent.setCustomAttribute = function (name, value, persistAttribute = false) {
104
100
  if (typeof name !== 'string') {
105
101
  warn(39, typeof name)
106
102
  return
@@ -116,7 +112,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
116
112
  * @param {string} value - unique user identifier; a null user id suggests none should exist
117
113
  * @returns @see apiCall
118
114
  */
119
- apiInterface.setUserId = function (value) {
115
+ agent.setUserId = function (value) {
120
116
  if (!(typeof value === 'string' || value === null)) {
121
117
  warn(41, typeof value)
122
118
  return
@@ -129,7 +125,7 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
129
125
  * @param {string|null} value - Application version -- if null, will "unset" the value
130
126
  * @returns @see apiCall
131
127
  */
132
- apiInterface.setApplicationVersion = function (value) {
128
+ agent.setApplicationVersion = function (value) {
133
129
  if (!(typeof value === 'string' || value === null)) {
134
130
  warn(42, typeof value)
135
131
  return
@@ -137,26 +133,26 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
137
133
  return appendJsAttribute('application.version', value, 'setApplicationVersion', false)
138
134
  }
139
135
 
140
- apiInterface.start = () => {
136
+ agent.start = () => {
141
137
  try {
142
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/start/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
143
- instanceEE.emit('manual-start-all')
138
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/start/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
139
+ agent.ee.emit('manual-start-all')
144
140
  } catch (err) {
145
141
  warn(23, err)
146
142
  }
147
143
  }
148
144
 
149
- apiInterface[SR_EVENT_EMITTER_TYPES.RECORD] = function () {
150
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/recordReplay/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
151
- handle(SR_EVENT_EMITTER_TYPES.RECORD, [], undefined, FEATURE_NAMES.sessionReplay, instanceEE)
145
+ agent[SR_EVENT_EMITTER_TYPES.RECORD] = function () {
146
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/recordReplay/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
147
+ handle(SR_EVENT_EMITTER_TYPES.RECORD, [], undefined, FEATURE_NAMES.sessionReplay, agent.ee)
152
148
  }
153
149
 
154
- apiInterface[SR_EVENT_EMITTER_TYPES.PAUSE] = function () {
155
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/pauseReplay/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
156
- handle(SR_EVENT_EMITTER_TYPES.PAUSE, [], undefined, FEATURE_NAMES.sessionReplay, instanceEE)
150
+ agent[SR_EVENT_EMITTER_TYPES.PAUSE] = function () {
151
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/pauseReplay/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
152
+ handle(SR_EVENT_EMITTER_TYPES.PAUSE, [], undefined, FEATURE_NAMES.sessionReplay, agent.ee)
157
153
  }
158
154
 
159
- apiInterface.interaction = function (options) {
155
+ agent.interaction = function (options) {
160
156
  return new InteractionHandle().get(typeof options === 'object' ? options : {})
161
157
  }
162
158
 
@@ -167,9 +163,9 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
167
163
  var contextStore = {}
168
164
  var ixn = this
169
165
  var hasCb = typeof cb === 'function'
170
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/createTracer/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
166
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/createTracer/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
171
167
  // Soft navigations won't support Tracer nodes, but this fn should still work the same otherwise (e.g., run the orig cb).
172
- if (!runSoftNavOverSpa) handle(spaPrefix + 'tracer', [now(), name, contextStore], ixn, FEATURE_NAMES.spa, instanceEE)
168
+ if (!agent.runSoftNavOverSpa) handle(spaPrefix + 'tracer', [now(), name, contextStore], ixn, FEATURE_NAMES.spa, agent.ee)
173
169
  return function () {
174
170
  tracerEE.emit((hasCb ? '' : 'no-') + 'fn-start', [now(), ixn, hasCb], contextStore)
175
171
  if (hasCb) {
@@ -189,30 +185,30 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
189
185
  }
190
186
 
191
187
  ;['actionText', 'setName', 'setAttribute', 'save', 'ignore', 'onEnd', 'getContext', 'end', 'get'].forEach(name => {
192
- InteractionApiProto[name] = apiCall(spaPrefix, name, undefined, runSoftNavOverSpa ? FEATURE_NAMES.softNav : FEATURE_NAMES.spa)
188
+ InteractionApiProto[name] = apiCall(spaPrefix, name, undefined, agent.runSoftNavOverSpa ? FEATURE_NAMES.softNav : FEATURE_NAMES.spa)
193
189
  })
194
- apiInterface.setCurrentRouteName = runSoftNavOverSpa ? apiCall(spaPrefix, 'routeName', undefined, FEATURE_NAMES.softNav) : apiCall(prefix, 'routeName', true, FEATURE_NAMES.spa)
190
+ agent.setCurrentRouteName = agent.runSoftNavOverSpa ? apiCall(spaPrefix, 'routeName', undefined, FEATURE_NAMES.softNav) : apiCall(prefix, 'routeName', true, FEATURE_NAMES.spa)
195
191
 
196
192
  function apiCall (prefix, name, notSpa, bufferGroup) {
197
193
  return function () {
198
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/' + name + '/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
194
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/' + name + '/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
199
195
  dispatchGlobalEvent({
200
- agentIdentifier,
201
- loaded: !!activatedFeatures?.[agentIdentifier],
196
+ agentIdentifier: agent.agentIdentifier,
197
+ drained: !!activatedFeatures?.[agent.agentIdentifier],
202
198
  type: 'data',
203
199
  name: 'api',
204
200
  feature: prefix + name,
205
201
  data: { notSpa, bufferGroup }
206
202
  })
207
- if (bufferGroup) handle(prefix + name, [notSpa ? now() : performance.now(), ...arguments], notSpa ? null : this, bufferGroup, instanceEE) // no bufferGroup means only the SM is emitted
203
+ if (bufferGroup) handle(prefix + name, [notSpa ? now() : performance.now(), ...arguments], notSpa ? null : this, bufferGroup, agent.ee) // no bufferGroup means only the SM is emitted
208
204
  return notSpa ? undefined : this // returns the InteractionHandle which allows these methods to be chained
209
205
  }
210
206
  }
211
207
 
212
- apiInterface.noticeError = function (err, customAttributes) {
208
+ agent.noticeError = function (err, customAttributes) {
213
209
  if (typeof err === 'string') err = new Error(err)
214
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/noticeError/called'], undefined, FEATURE_NAMES.metrics, instanceEE)
215
- handle('err', [err, now(), false, customAttributes, !!replayRunning[agentIdentifier]], undefined, FEATURE_NAMES.jserrors, instanceEE)
210
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['API/noticeError/called'], undefined, FEATURE_NAMES.metrics, agent.ee)
211
+ handle('err', [err, now(), false, customAttributes, !!replayRunning[agent.agentIdentifier]], undefined, FEATURE_NAMES.jserrors, agent.ee)
216
212
  }
217
213
 
218
214
  // theres no window.load event on non-browser scopes, lazy load immediately
@@ -221,14 +217,14 @@ export function setAPI (agentIdentifier, forceDrain, runSoftNavOverSpa = false)
221
217
  else onWindowLoad(() => lazyLoad(), true)
222
218
 
223
219
  function lazyLoad () {
224
- import(/* webpackChunkName: "async-api" */'./apiAsync').then(({ setAPI }) => {
225
- setAPI(agentIdentifier)
226
- drain(agentIdentifier, 'api')
220
+ import(/* webpackChunkName: "async-api" */'./apiAsync').then(({ setAsyncAPI }) => {
221
+ setAsyncAPI(agent)
222
+ drain(agent.agentIdentifier, 'api')
227
223
  }).catch((err) => {
228
224
  warn(27, err)
229
- instanceEE.abort()
225
+ agent.ee.abort()
230
226
  })
231
227
  }
232
228
 
233
- return apiInterface
229
+ return true
234
230
  }
@@ -3,18 +3,14 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { FEATURE_NAMES } from '../features/features'
6
- import { getRuntime } from '../../common/config/runtime'
7
- import { ee } from '../../common/event-emitter/contextual-ee'
8
6
  import { handle } from '../../common/event-emitter/handle'
9
7
  import { registerHandler } from '../../common/event-emitter/register-handler'
10
8
  import { single } from '../../common/util/invoke'
11
9
  import { CUSTOM_METRIC_CHANNEL } from '../../features/metrics/constants'
12
10
  import { originTime } from '../../common/constants/runtime'
13
11
 
14
- export function setAPI (agentIdentifier) {
15
- var instanceEE = ee.get(agentIdentifier)
16
-
17
- var api = {
12
+ export function setAsyncAPI (agent) {
13
+ const api = {
18
14
  finished: single(finished),
19
15
  setErrorHandler,
20
16
  addToTrace,
@@ -22,22 +18,22 @@ export function setAPI (agentIdentifier) {
22
18
  }
23
19
 
24
20
  // Hook all of the api functions up to the queues/stubs created in loader/api.js
25
- Object.entries(api).forEach(([fnName, fnCall]) => registerHandler('api-' + fnName, fnCall, 'api', instanceEE))
21
+ Object.entries(api).forEach(([fnName, fnCall]) => registerHandler('api-' + fnName, fnCall, 'api', agent.ee))
26
22
 
27
23
  // All API functions get passed the time they were called as their
28
24
  // first parameter. These functions can be called asynchronously.
29
25
 
30
26
  function finished (t, providedTime) {
31
- var time = providedTime ? providedTime - originTime : t
32
- handle(CUSTOM_METRIC_CHANNEL, ['finished', { time }], undefined, FEATURE_NAMES.metrics, instanceEE)
27
+ const time = providedTime ? providedTime - originTime : t
28
+ handle(CUSTOM_METRIC_CHANNEL, ['finished', { time }], undefined, FEATURE_NAMES.metrics, agent.ee)
33
29
  addToTrace(t, { name: 'finished', start: time + originTime, origin: 'nr' })
34
- handle('api-addPageAction', [time, 'finished'], undefined, FEATURE_NAMES.genericEvents, instanceEE)
30
+ handle('api-addPageAction', [time, 'finished'], undefined, FEATURE_NAMES.genericEvents, agent.ee)
35
31
  }
36
32
 
37
- function addToTrace (t, evt) {
33
+ function addToTrace (_, evt) {
38
34
  if (!(evt && typeof evt === 'object' && evt.name && evt.start)) return
39
35
 
40
- var report = {
36
+ const report = {
41
37
  n: evt.name,
42
38
  s: evt.start - originTime,
43
39
  e: (evt.end || evt.start) - originTime,
@@ -45,16 +41,16 @@ export function setAPI (agentIdentifier) {
45
41
  t: 'api'
46
42
  }
47
43
 
48
- handle('bstApi', [report], undefined, FEATURE_NAMES.sessionTrace, instanceEE)
44
+ handle('bstApi', [report], undefined, FEATURE_NAMES.sessionTrace, agent.ee)
49
45
  }
50
46
 
51
- function setErrorHandler (t, handler) {
52
- getRuntime(agentIdentifier).onerror = handler
47
+ function setErrorHandler (_, handler) {
48
+ agent.runtime.onerror = handler
53
49
  }
54
50
 
55
- var releaseCount = 0
56
- function addRelease (t, name, id) {
51
+ let releaseCount = 0
52
+ function addRelease (_, name, id) {
57
53
  if (++releaseCount > 10) return
58
- getRuntime(agentIdentifier).releaseIds[name.slice(-200)] = ('' + id).slice(-200)
54
+ agent.runtime.releaseIds[name.slice(-200)] = ('' + id).slice(-200)
59
55
  }
60
56
  }
@@ -5,7 +5,7 @@
5
5
  import { setAPI, setTopLevelCallers } from '../api/api'
6
6
  import { addToNREUM, gosCDN } from '../../common/window/nreum'
7
7
  import { setInfo } from '../../common/config/info'
8
- import { getConfiguration, setConfiguration } from '../../common/config/init'
8
+ import { setConfiguration } from '../../common/config/init'
9
9
  import { setLoaderConfig } from '../../common/config/loader-config'
10
10
  import { setRuntime } from '../../common/config/runtime'
11
11
  import { activatedFeatures } from '../../common/util/feature-flags'
@@ -14,10 +14,11 @@ import { redefinePublicPath } from './public-path'
14
14
  import { ee } from '../../common/event-emitter/contextual-ee'
15
15
  import { dispatchGlobalEvent } from '../../common/dispatch/global-event'
16
16
 
17
- let alreadySetOnce = false // the configure() function can run multiple times in agent lifecycle
17
+ const alreadySetOnce = new Set() // the configure() function can run multiple times in agent lifecycle for different agents
18
18
 
19
19
  /**
20
20
  * Sets or re-sets the agent's configuration values from global settings. This also attach those as properties to the agent instance.
21
+ * IMPORTANT: setNREUMInitializedAgent must be called on the agent prior to calling this function.
21
22
  */
22
23
  export function configure (agent, opts = {}, loaderType, forceDrain) {
23
24
  // eslint-disable-next-line camelcase
@@ -41,10 +42,10 @@ export function configure (agent, opts = {}, loaderType, forceDrain) {
41
42
  }
42
43
  setInfo(agent.agentIdentifier, info)
43
44
 
44
- const updatedInit = getConfiguration(agent.agentIdentifier)
45
+ const updatedInit = agent.init
45
46
  const internalTrafficList = [info.beacon, info.errorBeacon]
46
47
 
47
- if (!alreadySetOnce) {
48
+ if (!alreadySetOnce.has(agent.agentIdentifier)) {
48
49
  if (updatedInit.proxy.assets) {
49
50
  redefinePublicPath(updatedInit.proxy.assets)
50
51
  internalTrafficList.push(updatedInit.proxy.assets)
@@ -65,21 +66,20 @@ export function configure (agent, opts = {}, loaderType, forceDrain) {
65
66
  runtime.ptid = agent.agentIdentifier
66
67
  setRuntime(agent.agentIdentifier, runtime)
67
68
 
68
- agent.ee = ee.get(agent.agentIdentifier)
69
+ if (!alreadySetOnce.has(agent.agentIdentifier)) {
70
+ agent.ee = ee.get(agent.agentIdentifier)
71
+ agent.exposed = exposed
72
+ setAPI(agent, forceDrain) // assign our API functions to the agent instance
69
73
 
70
- if (agent.api === undefined) agent.api = setAPI(agent.agentIdentifier, forceDrain, agent.runSoftNavOverSpa)
71
- if (agent.exposed === undefined) agent.exposed = exposed
72
-
73
- if (!alreadySetOnce) {
74
74
  dispatchGlobalEvent({
75
75
  agentIdentifier: agent.agentIdentifier,
76
- loaded: !!activatedFeatures?.[agent.agentIdentifier],
76
+ drained: !!activatedFeatures?.[agent.agentIdentifier],
77
77
  type: 'lifecycle',
78
78
  name: 'initialize',
79
79
  feature: undefined,
80
- data: { init: updatedInit, info, loader_config, runtime }
80
+ data: agent.config
81
81
  })
82
82
  }
83
83
 
84
- alreadySetOnce = true
84
+ alreadySetOnce.add(agent.agentIdentifier)
85
85
  }
@@ -18,8 +18,8 @@ export class MicroAgentBase {
18
18
  * @param {...any} args
19
19
  */
20
20
  #callMethod (methodName, ...args) {
21
- if (typeof this.api?.[methodName] !== 'function') warn(35, methodName)
22
- else return this.api[methodName](...args)
21
+ if (this[methodName] === MicroAgentBase.prototype[methodName]) warn(35, methodName)
22
+ else return this[methodName](...args)
23
23
  }
24
24
 
25
25
  // MicroAgent class custom defines its own start
@@ -36,7 +36,6 @@ export class MicroAgent extends MicroAgentBase {
36
36
  setNREUMInitializedAgent(this.agentIdentifier, this)
37
37
 
38
38
  configure(this, { ...options, runtime: { isolatedBacklog: true } }, options.loaderType || 'micro-agent')
39
- Object.assign(this, this.api) // the APIs should be available at the class level for micro-agent
40
39
 
41
40
  /**
42
41
  * Starts a set of agent features if not running in "autoStart" mode
@@ -91,4 +90,8 @@ export class MicroAgent extends MicroAgentBase {
91
90
  runtime: this.runtime
92
91
  }
93
92
  }
93
+
94
+ get api () {
95
+ return this
96
+ }
94
97
  }