@newrelic/browser-agent 1.320.0 → 1.320.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/common/config/runtime.js +1 -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/event-listener/event-listener-opts.js +1 -1
  6. package/dist/cjs/common/harvest/connector.js +200 -0
  7. package/dist/cjs/common/harvest/harvester.js +5 -8
  8. package/dist/cjs/common/harvest/send.js +8 -7
  9. package/dist/cjs/common/payloads/payloads.js +3 -2
  10. package/dist/cjs/common/serialize/bel-serializer.js +17 -4
  11. package/dist/cjs/common/timer/interaction-timer.js +2 -2
  12. package/dist/cjs/common/unload/eol.js +3 -3
  13. package/dist/cjs/common/util/console.js +2 -1
  14. package/dist/cjs/common/util/feature-flags.js +2 -1
  15. package/dist/cjs/common/v2/mfe-vitals.js +34 -11
  16. package/dist/cjs/common/window/page-visibility.js +1 -1
  17. package/dist/cjs/features/ajax/aggregate/index.js +19 -8
  18. package/dist/cjs/features/page_view_event/aggregate/index.js +2 -6
  19. package/dist/cjs/features/page_view_event/aggregate_v2/index.js +109 -0
  20. package/dist/cjs/features/page_view_event/instrument/index.js +6 -1
  21. package/dist/cjs/features/page_view_timing/aggregate/index.js +33 -14
  22. package/dist/cjs/features/session_replay/instrument/index.js +9 -0
  23. package/dist/cjs/features/session_replay/shared/recorder.js +2 -1
  24. package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +16 -4
  25. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +10 -3
  26. package/dist/cjs/features/utils/aggregate-base.js +0 -12
  27. package/dist/cjs/features/utils/instrument-base.js +72 -29
  28. package/dist/cjs/loaders/agent.js +2 -1
  29. package/dist/cjs/loaders/api/consent.js +2 -2
  30. package/dist/cjs/loaders/features/features.js +2 -1
  31. package/dist/esm/common/config/runtime.js +1 -0
  32. package/dist/esm/common/constants/env.cdn.js +1 -1
  33. package/dist/esm/common/constants/env.npm.js +1 -1
  34. package/dist/esm/common/event-listener/event-listener-opts.js +1 -1
  35. package/dist/esm/common/harvest/connector.js +193 -0
  36. package/dist/esm/common/harvest/harvester.js +5 -8
  37. package/dist/esm/common/harvest/send.js +10 -9
  38. package/dist/esm/common/payloads/payloads.js +3 -2
  39. package/dist/esm/common/serialize/bel-serializer.js +17 -4
  40. package/dist/esm/common/timer/interaction-timer.js +2 -2
  41. package/dist/esm/common/unload/eol.js +3 -3
  42. package/dist/esm/common/util/console.js +2 -1
  43. package/dist/esm/common/util/feature-flags.js +2 -1
  44. package/dist/esm/common/v2/mfe-vitals.js +34 -11
  45. package/dist/esm/common/window/page-visibility.js +1 -1
  46. package/dist/esm/features/ajax/aggregate/index.js +19 -8
  47. package/dist/esm/features/page_view_event/aggregate/index.js +2 -6
  48. package/dist/esm/features/page_view_event/aggregate_v2/index.js +100 -0
  49. package/dist/esm/features/page_view_event/instrument/index.js +6 -1
  50. package/dist/esm/features/page_view_timing/aggregate/index.js +33 -14
  51. package/dist/esm/features/session_replay/instrument/index.js +9 -0
  52. package/dist/esm/features/session_replay/shared/recorder.js +2 -1
  53. package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +16 -4
  54. package/dist/esm/features/soft_navigations/aggregate/interaction.js +10 -3
  55. package/dist/esm/features/utils/aggregate-base.js +0 -12
  56. package/dist/esm/features/utils/instrument-base.js +71 -28
  57. package/dist/esm/loaders/agent.js +2 -1
  58. package/dist/esm/loaders/api/consent.js +2 -2
  59. package/dist/esm/loaders/features/features.js +1 -0
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/types/common/config/runtime.d.ts.map +1 -1
  62. package/dist/types/common/event-listener/event-listener-opts.d.ts +1 -1
  63. package/dist/types/common/harvest/connector.d.ts +6 -0
  64. package/dist/types/common/harvest/connector.d.ts.map +1 -0
  65. package/dist/types/common/harvest/harvester.d.ts.map +1 -1
  66. package/dist/types/common/harvest/send.d.ts.map +1 -1
  67. package/dist/types/common/payloads/payloads.d.ts +3 -2
  68. package/dist/types/common/payloads/payloads.d.ts.map +1 -1
  69. package/dist/types/common/serialize/bel-serializer.d.ts +9 -1
  70. package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
  71. package/dist/types/common/unload/eol.d.ts +1 -1
  72. package/dist/types/common/unload/eol.d.ts.map +1 -1
  73. package/dist/types/common/util/console.d.ts +2 -1
  74. package/dist/types/common/util/console.d.ts.map +1 -1
  75. package/dist/types/common/v2/mfe-vitals.d.ts.map +1 -1
  76. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  77. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  78. package/dist/types/features/page_view_event/aggregate_v2/index.d.ts +20 -0
  79. package/dist/types/features/page_view_event/aggregate_v2/index.d.ts.map +1 -0
  80. package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
  81. package/dist/types/features/page_view_timing/aggregate/index.d.ts +0 -1
  82. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  83. package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
  84. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  85. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  86. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
  87. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
  88. package/dist/types/features/utils/aggregate-base.d.ts +0 -5
  89. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  90. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  91. package/dist/types/loaders/agent.d.ts.map +1 -1
  92. package/dist/types/loaders/features/features.d.ts +1 -0
  93. package/dist/types/loaders/features/features.d.ts.map +1 -1
  94. package/package.json +2 -2
  95. package/src/common/config/runtime.js +1 -0
  96. package/src/common/event-listener/event-listener-opts.js +1 -1
  97. package/src/common/harvest/connector.js +168 -0
  98. package/src/common/harvest/harvester.js +7 -9
  99. package/src/common/harvest/send.js +9 -7
  100. package/src/common/payloads/payloads.js +3 -2
  101. package/src/common/serialize/bel-serializer.js +13 -4
  102. package/src/common/timer/interaction-timer.js +2 -2
  103. package/src/common/unload/eol.js +3 -3
  104. package/src/common/util/console.js +2 -1
  105. package/src/common/util/feature-flags.js +1 -1
  106. package/src/common/v2/mfe-vitals.js +39 -12
  107. package/src/common/window/page-visibility.js +1 -1
  108. package/src/features/ajax/aggregate/index.js +12 -9
  109. package/src/features/page_view_event/aggregate/index.js +2 -6
  110. package/src/features/page_view_event/aggregate_v2/index.js +97 -0
  111. package/src/features/page_view_event/instrument/index.js +6 -1
  112. package/src/features/page_view_timing/aggregate/index.js +24 -15
  113. package/src/features/session_replay/instrument/index.js +9 -0
  114. package/src/features/session_replay/shared/recorder.js +2 -1
  115. package/src/features/soft_navigations/aggregate/ajax-node.js +10 -7
  116. package/src/features/soft_navigations/aggregate/interaction.js +6 -5
  117. package/src/features/utils/aggregate-base.js +0 -12
  118. package/src/features/utils/instrument-base.js +71 -25
  119. package/src/loaders/agent.js +2 -1
  120. package/src/loaders/api/consent.js +2 -2
  121. package/src/loaders/features/features.js +1 -0
@@ -25,6 +25,7 @@ import { SESSION_ERROR } from '../../common/constants/agent-constants'
25
25
  import { handle } from '../../common/event-emitter/handle'
26
26
 
27
27
  const checkedAgents = new WeakSet()
28
+ const runtimeBootstrapPromises = new WeakMap()
28
29
 
29
30
  /**
30
31
  * Base class for instrumenting a feature.
@@ -103,28 +104,13 @@ export class InstrumentBase extends FeatureBase {
103
104
  return
104
105
  }
105
106
 
106
- let session
107
- try {
108
- if (canEnableSessionTracking(agentRef.init)) { // would require some setup before certain features start
109
- const { setupAgentSession } = await import(/* webpackChunkName: "session-manager" */ './agent-session')
110
- session = setupAgentSession(agentRef)
111
- }
107
+ try { // in the interest of keeping loader file size small, some modules are lazy-loaded as part of the larger async chunk
108
+ await ensureRuntimeBootstrap(agentRef, this.ee, this.featureName)
112
109
  } catch (e) {
113
- warn(20, e)
114
- this.ee.emit('internal-error', [e])
115
- handle(SESSION_ERROR, [e], undefined, this.featureName, this.ee)
116
- }
117
-
118
- if (agentRef.init.api.register.allow_iframe_bridge) {
119
- try {
120
- // This chunk doesn't exist in the lite build (see webpack IgnorePlugin config) since none
121
- // of lite's features wire up agent.register -- guard against that rather than letting an
122
- // unhandled rejection surface if this flag is ever set on a lite page.
123
- const { setupIframeMFEMessageListener } = await import(/* webpackChunkName: "iframe-message-handler" */ '../../loaders/configure/iframe-message-handler')
124
- setupIframeMFEMessageListener(agentRef)
125
- } catch (e) {
126
- warn(23, e)
127
- }
110
+ warn(79, e)
111
+ this.ee.abort() // failed Connector or Harvester will cause entire agent to shutdown
112
+ this.loadedSuccessfully(false)
113
+ return
128
114
  }
129
115
 
130
116
  /**
@@ -132,23 +118,24 @@ export class InstrumentBase extends FeatureBase {
132
118
  * it's only responsible for aborting its one specific feature, rather than all.
133
119
  */
134
120
  try {
135
- if (!this.#shouldImportAgg(this.featureName, session, agentRef.init)) {
121
+ if (!this.#shouldImportAgg(this.featureName, agentRef.runtime.session, agentRef.init)) {
122
+ this.abortHandler?.()
136
123
  drain(this.agentRef, this.featureName)
137
124
  this.loadedSuccessfully(false) // aggregate module isn't loaded at all
138
125
  return
139
126
  }
140
127
  const { Aggregate } = await fetchAggregator()
128
+
141
129
  this.featAggregate = new Aggregate(agentRef, argsObjFromInstrument)
142
130
 
143
- agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate) // "subscribe" the feature to future harvest intervals (PVE will start the timer)
131
+ agentRef.runtime.harvester.initializedAggregates.push(this.featAggregate) // "subscribe" the feature to future harvest intervals
144
132
  this.loadedSuccessfully(true)
145
133
  } catch (e) {
146
134
  warn(34, e)
147
- this.abortHandler?.() // undo any important alterations made to the page
135
+ this.abortHandler?.()
148
136
  // not supported yet but nice to do: "abort" this agent's EE for this feature specifically
149
137
  drain(this.agentRef, this.featureName, true)
150
138
  this.loadedSuccessfully(false)
151
- if (this.ee) this.ee.abort()
152
139
  }
153
140
  }
154
141
 
@@ -206,3 +193,62 @@ export class InstrumentBase extends FeatureBase {
206
193
  }
207
194
  }
208
195
  }
196
+
197
+ /**
198
+ * Lazily initializes the shared runtime bootstrap for a given agent exactly once. This loads session setup, Connector, and
199
+ * Harvester through shared async chunks and returns the same in-flight Promise to any concurrent callers.
200
+ *
201
+ * Session setup failures are reported but do not stop bootstrap. Connector or Harvester failures are allowed to bubble so the caller can abort the agent.
202
+ *
203
+ * @param {Object} agentRef - The agent reference object.
204
+ * @param {Object} ee - The feature event emitter used for error reporting.
205
+ * @param {string} featureName - The feature name used when reporting session setup errors.
206
+ * @returns {Promise<void>} Resolves when the shared bootstrap completes.
207
+ */
208
+ async function ensureRuntimeBootstrap (agentRef, ee, featureName) {
209
+ if (runtimeBootstrapPromises.has(agentRef)) return runtimeBootstrapPromises.get(agentRef)
210
+
211
+ const bootstrapPromise = (async () => {
212
+ if (canEnableSessionTracking(agentRef.init)) {
213
+ try {
214
+ const { setupAgentSession } = await import(/* webpackChunkName: "session-manager" */ './agent-session')
215
+ setupAgentSession(agentRef) // sets agentRef.runtime.session, if successful
216
+ } catch (e) {
217
+ warn(20, e)
218
+ ee.emit('internal-error', [e])
219
+ handle(SESSION_ERROR, [e], undefined, featureName, ee)
220
+ }
221
+ }
222
+ if (agentRef.init.api.register.allow_iframe_bridge) {
223
+ try {
224
+ // This chunk doesn't exist in the lite build (see webpack IgnorePlugin config) since none
225
+ // of lite's features wire up agent.register -- guard against that rather than letting an
226
+ // unhandled rejection surface if this flag is ever set on a lite page.
227
+ const { setupIframeMFEMessageListener } = await import(/* webpackChunkName: "iframe-message-handler" */ '../../loaders/configure/iframe-message-handler')
228
+ setupIframeMFEMessageListener(agentRef)
229
+ } catch (e) {
230
+ warn(23, e)
231
+ }
232
+ }
233
+
234
+ const [{ Connector }, { Harvester }] = await Promise.all([
235
+ import(/* webpackChunkName: "connector" */ '../../common/harvest/connector'),
236
+ import(/* webpackChunkName: "harvester" */ '../../common/harvest/harvester')
237
+ ])
238
+ agentRef.runtime.connector = new Connector(agentRef)
239
+ agentRef.runtime.harvester = new Harvester(agentRef)
240
+
241
+ /* Wait for auto-started features' aggregates to load before starting the harvest timer, so Harvester's EOL
242
+ listener registers after aggregate-level listeners like web-vitals' CWV APIs. Not awaited here to avoid
243
+ deadlock, since every feature awaits this same bootstrap promise before its own aggregate load.
244
+ Only auto-started features are waited on: an autoStart:false feature only registers in drainRegistry once
245
+ `start` is called, so filtering on that registry excludes any feature that's never started instead of
246
+ blocking startTimer() forever. */
247
+ const autoStartedFeatures = Object.values(agentRef.features).filter(feature => agentRef.runtime.drainRegistry.has(feature.featureName))
248
+ Promise.all(autoStartedFeatures.map(feature => feature.onAggregateImported))
249
+ .then(() => agentRef.runtime.harvester.startTimer())
250
+ })()
251
+
252
+ runtimeBootstrapPromises.set(agentRef, bootstrapPromise)
253
+ await bootstrapPromise
254
+ }
@@ -93,10 +93,11 @@ export class Agent extends AgentBase {
93
93
  try {
94
94
  const enabledFeatures = getEnabledFeatures(this.init)
95
95
  const featuresToStart = [...this.desiredFeatures]
96
+ const isRumV2Enabled = this.init.feature_flags.includes('rum_v2')
96
97
 
97
98
  featuresToStart.sort((a, b) => featurePriority[a.featureName] - featurePriority[b.featureName])
98
99
  featuresToStart.forEach(InstrumentCtor => {
99
- if (!enabledFeatures[InstrumentCtor.featureName] && InstrumentCtor.featureName !== FEATURE_NAMES.pageViewEvent) return // PVE is required to run even if it's marked disabled
100
+ if (!enabledFeatures[InstrumentCtor.featureName] && (isRumV2Enabled || InstrumentCtor.featureName !== FEATURE_NAMES.pageViewEvent)) return // PVE is required to run even if it's marked disabled unless rum_v2 is enabled
100
101
 
101
102
  const dependencies = getFeatureDependencyNames(InstrumentCtor.featureName)
102
103
  const missingDependencies = dependencies.filter(featName => !(featName in this.features)) // any other feature(s) this depends on should've been initialized on prior iterations by priority order
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
2
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { prefix, CONSENT } from './constants'
@@ -23,7 +23,7 @@ export function setupConsentAPI (agent) {
23
23
  pveInst.onAggregateImported.then((loaded) => {
24
24
  const pveAgg = pveInst.featAggregate
25
25
  if (loaded && !pveAgg.sentRum) {
26
- pveAgg.sendRum()
26
+ pveAgg.sendRum?.() // only the old v1 aggregate has a sendRum method that acts as a blocker for the rest of the agent; v2 aggregate will auto report when harvester becomes unblocked
27
27
  }
28
28
  })
29
29
  }
@@ -8,6 +8,7 @@ export const EVENTS = 'events'
8
8
  export const JSERRORS = 'jserrors'
9
9
  export const BLOBS = 'browser/blobs'
10
10
  export const RUM = 'rum'
11
+ export const CONNECT = 'connect'
11
12
  export const LOGS = 'browser/logs'
12
13
 
13
14
  export const FEATURE_NAMES = {