@newrelic/browser-agent 1.314.0-rc.0 → 1.314.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 (38) hide show
  1. package/dist/cjs/common/constants/agent-constants.js +2 -1
  2. package/dist/cjs/common/constants/env.cdn.js +1 -1
  3. package/dist/cjs/common/constants/env.npm.js +1 -1
  4. package/dist/cjs/common/vitals/cumulative-layout-shift.js +3 -2
  5. package/dist/cjs/common/vitals/interaction-to-next-paint.js +3 -2
  6. package/dist/cjs/common/vitals/largest-contentful-paint.js +2 -1
  7. package/dist/cjs/common/vitals/vital-metric.js +7 -4
  8. package/dist/cjs/features/page_view_timing/aggregate/index.js +27 -6
  9. package/dist/cjs/features/soft_navigations/aggregate/index.js +17 -14
  10. package/dist/cjs/loaders/api-base.js +1 -0
  11. package/dist/esm/common/constants/agent-constants.js +2 -1
  12. package/dist/esm/common/constants/env.cdn.js +1 -1
  13. package/dist/esm/common/constants/env.npm.js +1 -1
  14. package/dist/esm/common/vitals/cumulative-layout-shift.js +3 -2
  15. package/dist/esm/common/vitals/interaction-to-next-paint.js +3 -2
  16. package/dist/esm/common/vitals/largest-contentful-paint.js +2 -1
  17. package/dist/esm/common/vitals/vital-metric.js +7 -4
  18. package/dist/esm/features/page_view_timing/aggregate/index.js +27 -6
  19. package/dist/esm/features/soft_navigations/aggregate/index.js +17 -14
  20. package/dist/esm/loaders/api-base.js +1 -0
  21. package/dist/types/common/constants/agent-constants.d.ts +1 -0
  22. package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
  23. package/dist/types/common/vitals/vital-metric.d.ts +3 -2
  24. package/dist/types/common/vitals/vital-metric.d.ts.map +1 -1
  25. package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -1
  26. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  27. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  28. package/dist/types/loaders/api-base.d.ts +2 -0
  29. package/dist/types/loaders/api-base.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/common/constants/agent-constants.js +2 -1
  32. package/src/common/vitals/cumulative-layout-shift.js +2 -2
  33. package/src/common/vitals/interaction-to-next-paint.js +2 -2
  34. package/src/common/vitals/largest-contentful-paint.js +1 -1
  35. package/src/common/vitals/vital-metric.js +6 -4
  36. package/src/features/page_view_timing/aggregate/index.js +14 -6
  37. package/src/features/soft_navigations/aggregate/index.js +10 -8
  38. package/src/loaders/api-base.js +1 -0
@@ -18,5 +18,6 @@ const SUPPORTS_REGISTERED_ENTITIES = exports.SUPPORTS_REGISTERED_ENTITIES = {
18
18
  [_features.FEATURE_NAMES.logging]: true,
19
19
  [_features.FEATURE_NAMES.genericEvents]: true,
20
20
  [_features.FEATURE_NAMES.jserrors]: true,
21
- [_features.FEATURE_NAMES.ajax]: true
21
+ [_features.FEATURE_NAMES.ajax]: true,
22
+ [_features.FEATURE_NAMES.pageViewTiming]: true
22
23
  };
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.314.0-rc.0";
20
+ const VERSION = exports.VERSION = "1.314.0-rc.2";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.314.0-rc.0";
20
+ const VERSION = exports.VERSION = "1.314.0-rc.2";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -9,7 +9,7 @@ var _constants = require("./constants");
9
9
  var _vitalMetric = require("./vital-metric");
10
10
  var _runtime = require("../constants/runtime");
11
11
  /**
12
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
12
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
13
13
  * SPDX-License-Identifier: Apache-2.0
14
14
  */
15
15
 
@@ -29,7 +29,8 @@ if (_runtime.isBrowserScope) {
29
29
  };
30
30
  cumulativeLayoutShift.update({
31
31
  value,
32
- attrs
32
+ attrs,
33
+ element: attribution.largestShiftSource?.node
33
34
  });
34
35
  }, {
35
36
  reportAllChanges: true
@@ -9,7 +9,7 @@ var _vitalMetric = require("./vital-metric");
9
9
  var _constants = require("./constants");
10
10
  var _runtime = require("../constants/runtime");
11
11
  /**
12
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
12
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
13
13
  * SPDX-License-Identifier: Apache-2.0
14
14
  */
15
15
 
@@ -38,7 +38,8 @@ if (_runtime.isBrowserScope) {
38
38
  };
39
39
  interactionToNextPaint.update({
40
40
  value,
41
- attrs
41
+ attrs,
42
+ element: attribution.interactionTargetElement
42
43
  });
43
44
  });
44
45
  }
@@ -40,7 +40,8 @@ if (_runtime.isBrowserScope) {
40
40
  if (attribution.url) attrs.elUrl = (0, _cleanUrl.cleanURL)(attribution.url);
41
41
  largestContentfulPaint.update({
42
42
  value,
43
- attrs
43
+ attrs,
44
+ element: lcpEntry?.element
44
45
  });
45
46
  });
46
47
  }
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.VitalMetric = void 0;
7
7
  /**
8
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
8
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
9
9
  * SPDX-License-Identifier: Apache-2.0
10
10
  */
11
11
  class VitalMetric {
@@ -18,13 +18,15 @@ class VitalMetric {
18
18
  }
19
19
  update({
20
20
  value,
21
- attrs = {}
21
+ attrs = {},
22
+ element
22
23
  }) {
23
24
  if (value === undefined || value === null || value < 0) return;
24
25
  const state = {
25
26
  value: this.roundingMethod(value),
26
27
  name: this.name,
27
- attrs
28
+ attrs,
29
+ element
28
30
  };
29
31
  this.history.push(state);
30
32
  this.#subscribers.forEach(cb => {
@@ -39,7 +41,8 @@ class VitalMetric {
39
41
  return this.history[this.history.length - 1] || {
40
42
  value: undefined,
41
43
  name: this.name,
42
- attrs: {}
44
+ attrs: {},
45
+ element: undefined
43
46
  };
44
47
  }
45
48
  get isValid() {
@@ -21,6 +21,8 @@ var _runtime = require("../../../common/constants/runtime");
21
21
  var _eventOrigin = require("../../../common/util/event-origin");
22
22
  var _loadTime = require("../../../common/vitals/load-time");
23
23
  var _webdriverDetection = require("../../../common/util/webdriver-detection");
24
+ var _selectorPath = require("../../../common/dom/selector-path");
25
+ var _utils = require("../../../common/v2/utils");
24
26
  var _cleanUrl = require("../../../common/url/clean-url");
25
27
  /**
26
28
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
@@ -32,9 +34,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
32
34
  #handleVitalMetric = ({
33
35
  name,
34
36
  value,
35
- attrs
37
+ attrs,
38
+ element
36
39
  }) => {
37
- this.addTiming(name, value, attrs);
40
+ this.addTiming(name, value, attrs, element);
38
41
  };
39
42
  constructor(agentRef) {
40
43
  super(agentRef, _constants.FEATURE_NAME);
@@ -62,10 +65,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
62
65
  const {
63
66
  name,
64
67
  value,
65
- attrs
68
+ attrs,
69
+ element
66
70
  } = _cumulativeLayoutShift.cumulativeLayoutShift.current;
67
71
  if (value === undefined) return;
68
- this.addTiming(name, value * 1000, attrs);
72
+ this.addTiming(name, value * 1000, attrs, element);
69
73
  }, true, true); // CLS node should only reports on vis change rather than on every change
70
74
 
71
75
  this.drain();
@@ -83,7 +87,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
83
87
  this.curSessEndRecorded = true;
84
88
  }
85
89
  }
86
- addTiming(name, value, attrs) {
90
+ addTiming(name, value, attrs, element) {
87
91
  attrs = attrs || {};
88
92
  attrs.pageUrl = (0, _cleanUrl.cleanURL)((0, _runtime.getNavigationEntry)()?.name || _runtime.initialLocation);
89
93
  addConnectionAttributes(attrs); // network conditions may differ from the actual for VitalMetrics when they were captured
@@ -104,7 +108,24 @@ class Aggregate extends _aggregateBase.AggregateBase {
104
108
  value,
105
109
  attrs
106
110
  };
107
- this.events.add(timing);
111
+ const targets = (0, _selectorPath.analyzeElemPath)(element, [], this.agentRef).targets;
112
+ if (!targets.length) targets.push(undefined);
113
+ targets.forEach(target => {
114
+ this.events.add({
115
+ ...timing,
116
+ attrs: {
117
+ ...attrs,
118
+ ...(0, _utils.getVersion2Attributes)(target, this)
119
+ }
120
+ });
121
+ if ((0, _utils.shouldDuplicate)(target, this.agentRef)) this.events.add({
122
+ ...timing,
123
+ attrs: {
124
+ ...attrs,
125
+ ...(0, _utils.getVersion2DuplicationAttributes)(target, this)
126
+ }
127
+ });
128
+ });
108
129
  (0, _handle.handle)('pvtAdded', [name, value, attrs], undefined, _features.FEATURE_NAMES.sessionTrace, this.ee);
109
130
  this.checkForFirstInteraction();
110
131
 
@@ -36,7 +36,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
36
36
  this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
37
37
  const ixn = this.initialPageLoadInteraction;
38
38
  this.events.add(ixn); // add the iPL ixn to the buffer for harvest
39
- this.initialPageLoadInteraction = null;
40
39
  });
41
40
  _loadTime.loadTime.subscribe(({
42
41
  value: loadEventTime
@@ -230,22 +229,26 @@ class Aggregate extends _aggregateBase.AggregateBase {
230
229
  const INTERACTION_API = 'api-ixn-';
231
230
  const thisClass = this;
232
231
  (0, _registerHandler.registerHandler)(INTERACTION_API + 'get', function (time, {
233
- waitForEnd
232
+ waitForEnd,
233
+ targetPageLoad
234
234
  } = {}) {
235
235
  // In here, 'this' refers to the EventContext specific to per InteractionHandle instance spawned by each .interaction() api call.
236
236
  // Each api call aka IH instance would therefore retain a reference to either the in-progress interaction *at the time of the call* OR a new api-started interaction.
237
- this.associatedInteraction = thisClass.getInteractionFor(time);
238
- if (this.associatedInteraction?.trigger === _constants.IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
239
- if (!this.associatedInteraction) {
240
- // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
241
- this.associatedInteraction = thisClass.interactionInProgress = new _interaction.Interaction(_constants.API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi);
242
- thisClass.domObserver.observe(document.body, {
243
- attributes: true,
244
- childList: true,
245
- subtree: true,
246
- characterData: true
247
- }); // start observing for DOM changes like a regular UI-driven interaction
248
- thisClass.setClosureHandlers();
237
+ if (targetPageLoad) this.associatedInteraction = thisClass.initialPageLoadInteraction; // this option only grabs the IPL, no frills
238
+ else {
239
+ this.associatedInteraction = thisClass.getInteractionFor(time);
240
+ if (this.associatedInteraction?.trigger === _constants.IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
241
+ if (!this.associatedInteraction) {
242
+ // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
243
+ this.associatedInteraction = thisClass.interactionInProgress = new _interaction.Interaction(_constants.API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi);
244
+ thisClass.domObserver.observe(document.body, {
245
+ attributes: true,
246
+ childList: true,
247
+ subtree: true,
248
+ characterData: true
249
+ }); // start observing for DOM changes like a regular UI-driven interaction
250
+ thisClass.setClosureHandlers();
251
+ }
249
252
  }
250
253
  if (waitForEnd === true) {
251
254
  this.associatedInteraction.keepOpenUntilEndApi = true;
@@ -202,6 +202,7 @@ class ApiBase {
202
202
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
203
203
  * @param {Object} [opts] Options to configure the new or existing interaction with
204
204
  * @param {boolean} [opts.waitForEnd=false] To forcibly keep the interaction open until the `.end` method is called on its handle, set to true. Defaults to false. After an interaction is earmarked with this, it cannot be undone.
205
+ * @param {boolean} [opts.targetPageLoad=false] If true, bind this API handle to the initial page load interaction forcibly instead of creating or targeting a soft navigation interaction.
205
206
  * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
206
207
  * - Note: Does not apply to MicroAgent
207
208
  * - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
@@ -11,5 +11,6 @@ export const SUPPORTS_REGISTERED_ENTITIES = {
11
11
  [FEATURE_NAMES.logging]: true,
12
12
  [FEATURE_NAMES.genericEvents]: true,
13
13
  [FEATURE_NAMES.jserrors]: true,
14
- [FEATURE_NAMES.ajax]: true
14
+ [FEATURE_NAMES.ajax]: true,
15
+ [FEATURE_NAMES.pageViewTiming]: true
15
16
  };
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.314.0-rc.0";
14
+ export const VERSION = "1.314.0-rc.2";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.314.0-rc.0";
14
+ export const VERSION = "1.314.0-rc.2";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -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 { onCLS } from 'web-vitals/attribution';
@@ -22,7 +22,8 @@ if (isBrowserScope) {
22
22
  };
23
23
  cumulativeLayoutShift.update({
24
24
  value,
25
- attrs
25
+ attrs,
26
+ element: attribution.largestShiftSource?.node
26
27
  });
27
28
  }, {
28
29
  reportAllChanges: true
@@ -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 { onINP } from 'web-vitals/attribution';
@@ -31,7 +31,8 @@ if (isBrowserScope) {
31
31
  };
32
32
  interactionToNextPaint.update({
33
33
  value,
34
- attrs
34
+ attrs,
35
+ element: attribution.interactionTargetElement
35
36
  });
36
37
  });
37
38
  }
@@ -33,7 +33,8 @@ if (isBrowserScope) {
33
33
  if (attribution.url) attrs.elUrl = cleanURL(attribution.url);
34
34
  largestContentfulPaint.update({
35
35
  value,
36
- attrs
36
+ attrs,
37
+ element: lcpEntry?.element
37
38
  });
38
39
  });
39
40
  }
@@ -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
  export class VitalMetric {
@@ -12,13 +12,15 @@ export class VitalMetric {
12
12
  }
13
13
  update({
14
14
  value,
15
- attrs = {}
15
+ attrs = {},
16
+ element
16
17
  }) {
17
18
  if (value === undefined || value === null || value < 0) return;
18
19
  const state = {
19
20
  value: this.roundingMethod(value),
20
21
  name: this.name,
21
- attrs
22
+ attrs,
23
+ element
22
24
  };
23
25
  this.history.push(state);
24
26
  this.#subscribers.forEach(cb => {
@@ -33,7 +35,8 @@ export class VitalMetric {
33
35
  return this.history[this.history.length - 1] || {
34
36
  value: undefined,
35
37
  name: this.name,
36
- attrs: {}
38
+ attrs: {},
39
+ element: undefined
37
40
  };
38
41
  }
39
42
  get isValid() {
@@ -20,15 +20,18 @@ import { initiallyHidden, getNavigationEntry, initialLocation } from '../../../c
20
20
  import { eventOrigin } from '../../../common/util/event-origin';
21
21
  import { loadTime } from '../../../common/vitals/load-time';
22
22
  import { webdriverDetected } from '../../../common/util/webdriver-detection';
23
+ import { analyzeElemPath } from '../../../common/dom/selector-path';
24
+ import { getVersion2Attributes, getVersion2DuplicationAttributes, shouldDuplicate } from '../../../common/v2/utils';
23
25
  import { cleanURL } from '../../../common/url/clean-url';
24
26
  export class Aggregate extends AggregateBase {
25
27
  static featureName = FEATURE_NAME;
26
28
  #handleVitalMetric = ({
27
29
  name,
28
30
  value,
29
- attrs
31
+ attrs,
32
+ element
30
33
  }) => {
31
- this.addTiming(name, value, attrs);
34
+ this.addTiming(name, value, attrs, element);
32
35
  };
33
36
  constructor(agentRef) {
34
37
  super(agentRef, FEATURE_NAME);
@@ -56,10 +59,11 @@ export class Aggregate extends AggregateBase {
56
59
  const {
57
60
  name,
58
61
  value,
59
- attrs
62
+ attrs,
63
+ element
60
64
  } = cumulativeLayoutShift.current;
61
65
  if (value === undefined) return;
62
- this.addTiming(name, value * 1000, attrs);
66
+ this.addTiming(name, value * 1000, attrs, element);
63
67
  }, true, true); // CLS node should only reports on vis change rather than on every change
64
68
 
65
69
  this.drain();
@@ -77,7 +81,7 @@ export class Aggregate extends AggregateBase {
77
81
  this.curSessEndRecorded = true;
78
82
  }
79
83
  }
80
- addTiming(name, value, attrs) {
84
+ addTiming(name, value, attrs, element) {
81
85
  attrs = attrs || {};
82
86
  attrs.pageUrl = cleanURL(getNavigationEntry()?.name || initialLocation);
83
87
  addConnectionAttributes(attrs); // network conditions may differ from the actual for VitalMetrics when they were captured
@@ -98,7 +102,24 @@ export class Aggregate extends AggregateBase {
98
102
  value,
99
103
  attrs
100
104
  };
101
- this.events.add(timing);
105
+ const targets = analyzeElemPath(element, [], this.agentRef).targets;
106
+ if (!targets.length) targets.push(undefined);
107
+ targets.forEach(target => {
108
+ this.events.add({
109
+ ...timing,
110
+ attrs: {
111
+ ...attrs,
112
+ ...getVersion2Attributes(target, this)
113
+ }
114
+ });
115
+ if (shouldDuplicate(target, this.agentRef)) this.events.add({
116
+ ...timing,
117
+ attrs: {
118
+ ...attrs,
119
+ ...getVersion2DuplicationAttributes(target, this)
120
+ }
121
+ });
122
+ });
102
123
  handle('pvtAdded', [name, value, attrs], undefined, FEATURE_NAMES.sessionTrace, this.ee);
103
124
  this.checkForFirstInteraction();
104
125
 
@@ -29,7 +29,6 @@ export class Aggregate extends AggregateBase {
29
29
  this.initialPageLoadInteraction.forceSave = true; // unless forcibly ignored, iPL always finish by default
30
30
  const ixn = this.initialPageLoadInteraction;
31
31
  this.events.add(ixn); // add the iPL ixn to the buffer for harvest
32
- this.initialPageLoadInteraction = null;
33
32
  });
34
33
  loadTime.subscribe(({
35
34
  value: loadEventTime
@@ -223,22 +222,26 @@ export class Aggregate extends AggregateBase {
223
222
  const INTERACTION_API = 'api-ixn-';
224
223
  const thisClass = this;
225
224
  registerHandler(INTERACTION_API + 'get', function (time, {
226
- waitForEnd
225
+ waitForEnd,
226
+ targetPageLoad
227
227
  } = {}) {
228
228
  // In here, 'this' refers to the EventContext specific to per InteractionHandle instance spawned by each .interaction() api call.
229
229
  // Each api call aka IH instance would therefore retain a reference to either the in-progress interaction *at the time of the call* OR a new api-started interaction.
230
- this.associatedInteraction = thisClass.getInteractionFor(time);
231
- if (this.associatedInteraction?.trigger === IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
232
- if (!this.associatedInteraction) {
233
- // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
234
- this.associatedInteraction = thisClass.interactionInProgress = new Interaction(API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi);
235
- thisClass.domObserver.observe(document.body, {
236
- attributes: true,
237
- childList: true,
238
- subtree: true,
239
- characterData: true
240
- }); // start observing for DOM changes like a regular UI-driven interaction
241
- thisClass.setClosureHandlers();
230
+ if (targetPageLoad) this.associatedInteraction = thisClass.initialPageLoadInteraction; // this option only grabs the IPL, no frills
231
+ else {
232
+ this.associatedInteraction = thisClass.getInteractionFor(time);
233
+ if (this.associatedInteraction?.trigger === IPL_TRIGGER_NAME) this.associatedInteraction = null; // the api get-interaction method cannot target IPL
234
+ if (!this.associatedInteraction) {
235
+ // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
236
+ this.associatedInteraction = thisClass.interactionInProgress = new Interaction(API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi);
237
+ thisClass.domObserver.observe(document.body, {
238
+ attributes: true,
239
+ childList: true,
240
+ subtree: true,
241
+ characterData: true
242
+ }); // start observing for DOM changes like a regular UI-driven interaction
243
+ thisClass.setClosureHandlers();
244
+ }
242
245
  }
243
246
  if (waitForEnd === true) {
244
247
  this.associatedInteraction.keepOpenUntilEndApi = true;
@@ -196,6 +196,7 @@ export class ApiBase {
196
196
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
197
197
  * @param {Object} [opts] Options to configure the new or existing interaction with
198
198
  * @param {boolean} [opts.waitForEnd=false] To forcibly keep the interaction open until the `.end` method is called on its handle, set to true. Defaults to false. After an interaction is earmarked with this, it cannot be undone.
199
+ * @param {boolean} [opts.targetPageLoad=false] If true, bind this API handle to the initial page load interaction forcibly instead of creating or targeting a soft navigation interaction.
199
200
  * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
200
201
  * - Note: Does not apply to MicroAgent
201
202
  * - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
@@ -7,6 +7,7 @@ export const SUPPORTS_REGISTERED_ENTITIES: {
7
7
  [FEATURE_NAMES.genericEvents]: boolean;
8
8
  [FEATURE_NAMES.jserrors]: boolean;
9
9
  [FEATURE_NAMES.ajax]: boolean;
10
+ [FEATURE_NAMES.pageViewTiming]: boolean;
10
11
  };
11
12
  import { FEATURE_NAMES } from '../../loaders/features/features';
12
13
  //# sourceMappingURL=agent-constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-constants.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/agent-constants.js"],"names":[],"mappings":"AAMA,iCAAkC,KAAK,CAAA;AACvC,+BAAgC,OAAO,CAAA;AACvC,0BAA2B,oBAAoB,CAAA;AAC/C,4BAA6B,eAAe,CAAA;AAE5C;IACE,CAAC,aAAa,CAAC,OAAO,CAAC,UAAM;IAC7B,CAAC,aAAa,CAAC,aAAa,CAAC,UAAM;IACnC,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAM;IAC9B,CAAC,aAAa,CAAC,IAAI,CAAC,UAAM;EAC3B;8BAZ6B,iCAAiC"}
1
+ {"version":3,"file":"agent-constants.d.ts","sourceRoot":"","sources":["../../../../src/common/constants/agent-constants.js"],"names":[],"mappings":"AAMA,iCAAkC,KAAK,CAAA;AACvC,+BAAgC,OAAO,CAAA;AACvC,0BAA2B,oBAAoB,CAAA;AAC/C,4BAA6B,eAAe,CAAA;AAE5C;IACE,CAAC,aAAa,CAAC,OAAO,CAAC,UAAM;IAC7B,CAAC,aAAa,CAAC,aAAa,CAAC,UAAM;IACnC,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAM;IAC9B,CAAC,aAAa,CAAC,IAAI,CAAC,UAAM;IAC1B,CAAC,aAAa,CAAC,cAAc,CAAC,UAAM;EACrC;8BAb6B,iCAAiC"}
@@ -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
  export class VitalMetric {
@@ -8,9 +8,10 @@ export class VitalMetric {
8
8
  name: any;
9
9
  attrs: {};
10
10
  roundingMethod: any;
11
- update({ value, attrs }: {
11
+ update({ value, attrs, element }: {
12
12
  value: any;
13
13
  attrs?: {} | undefined;
14
+ element: any;
14
15
  }): void;
15
16
  get current(): any;
16
17
  get isValid(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"vital-metric.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/vital-metric.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAIE,4CAIC;IAND,eAAY;IAGV,UAAgB;IAChB,UAAe;IACf,oBAAwF;IAG1F;;;aAgBC;IAED,mBAMC;IAED,uBAEC;IAED,uEAMC;;CACF"}
1
+ {"version":3,"file":"vital-metric.d.ts","sourceRoot":"","sources":["../../../../src/common/vitals/vital-metric.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IAIE,4CAIC;IAND,eAAY;IAGV,UAAgB;IAChB,UAAe;IACf,oBAAwF;IAG1F;;;;aAiBC;IAED,mBAOC;IAED,uBAEC;IAED,uEAMC;;CACF"}
@@ -8,7 +8,7 @@ export class Aggregate extends AggregateBase {
8
8
  * @param {number} timestamp
9
9
  */
10
10
  endCurrentSession(timestamp: number): void;
11
- addTiming(name: any, value: any, attrs: any): {
11
+ addTiming(name: any, value: any, attrs: any, element: any): {
12
12
  name: any;
13
13
  value: any;
14
14
  attrs: any;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"AAwBA;IACE,2BAAiC;IAMjC,2BA4BC;IA1BC,4BAA+B;IAC/B,0BAA6B;IA2B/B;;;OAGG;IACH,6BAFW,MAAM,QAOhB;IAED;;;;MA+BC;IAED;;;OAGG;IACH,4BAFa,IAAI,CAahB;IAED,gDAWC;IAED,4BAGC;IAGD,qCAwBC;;CACF;8BA5J6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/page_view_timing/aggregate/index.js"],"names":[],"mappings":"AA0BA;IACE,2BAAiC;IAMjC,2BA4BC;IA1BC,4BAA+B;IAC/B,0BAA6B;IA2B/B;;;OAGG;IACH,6BAFW,MAAM,QAOhB;IAED;;;;MAqCC;IAED;;;OAGG;IACH,4BAFa,IAAI,CAahB;IAED,gDAWC;IAED,4BAGC;IAGD,qCAwBC;;CACF;8BApK6B,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OAgEC;IA3DC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0E;IAe1E,yBAA+B;IAC/B,0CAAiC;IACjC,yBAA4C;IAyC9C,qCAUC;IAED,0EAmBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAsB7B;;CAiHF;8BA1Q6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/soft_navigations/aggregate/index.js"],"names":[],"mappings":"AAeA;IACE,2BAAiC;IACjC;;OA+DC;IA1DC,2BAAwC;IACxC,iBAA8B;IAE9B,uDAA0E;IAc1E,yBAA+B;IAC/B,0CAAiC;IACjC,yBAA4C;IAyC9C,qCAUC;IAED,0EAmBC;IAED,2BAiBC;IAED;;;;;;;OAOG;IACH,6BAHW,mBAAmB,OAsB7B;;CAoHF;8BA5Q6B,4BAA4B;2CAGf,iCAAiC;4BAChD,eAAe"}
@@ -143,12 +143,14 @@ export class ApiBase {
143
143
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
144
144
  * @param {Object} [opts] Options to configure the new or existing interaction with
145
145
  * @param {boolean} [opts.waitForEnd=false] To forcibly keep the interaction open until the `.end` method is called on its handle, set to true. Defaults to false. After an interaction is earmarked with this, it cannot be undone.
146
+ * @param {boolean} [opts.targetPageLoad=false] If true, bind this API handle to the initial page load interaction forcibly instead of creating or targeting a soft navigation interaction.
146
147
  * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
147
148
  * - Note: Does not apply to MicroAgent
148
149
  * - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.
149
150
  */
150
151
  interaction(opts?: {
151
152
  waitForEnd?: boolean | undefined;
153
+ targetPageLoad?: boolean | undefined;
152
154
  }): InteractionInstance;
153
155
  /**
154
156
  * Wrap a logger function to capture a log each time the function is invoked with the message and arguments passed
@@ -1 +1 @@
1
- {"version":3,"file":"api-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/api-base.js"],"names":[],"mappings":"AAOA;;GAEG;AACH;IAQE;;;;;OAKG;IACH,oBAHW,MAAM,eACN,MAAM,OAIhB;IAED;;;;;;;;OAQG;IACH,iBAHW,OAAO,0BAA0B,EAAE,sBAAsB,GAC1D,OAAO,0BAA0B,EAAE,WAAW,CAIvD;IAED;;;;;OAKG;IACH,6BAHW,MAAM,eACN,MAAM,OAIhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,SACN,MAAM,OAIhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,YAC1B,OAAO,OAIjB;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,qBACZ,MAAM,OAIhB;IAED;;;;;OAKG;IACH,iBAHW,MAAM,GAAC,IAAI,iBACX,OAAO,OAIjB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;;MAKE;IACF,aAHW,MAAM,YACN;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM,CAAA;KAAC,OAIpF;IAED;;;OAGG;IACH,aAEC;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAIhB;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED;;;;;;;;MAQE;IACF,mBALG;QAAuB,UAAU;KACjC,GAAU,mBAAmB,CAM/B;IAED;;;;;;MAME;IACF,mBAJW,MAAM,gBACN,MAAM,YACN;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM,CAAA;KAAC,OAIpF;IAED;;;;;;OAMG;IACH,cAJW,MAAM,YACN;QAAC,KAAK,CAAC,EAAE,MAAM,GAAC,eAAe,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,GAAC,eAAe,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAC,GACvF;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAIpF;IAED;;;;;OAKG;IACH,gBAFW,OAAO,OAAC,OAIlB;;CACF;kCAtOY,OAAO,yBAAyB,EAAE,mBAAmB"}
1
+ {"version":3,"file":"api-base.d.ts","sourceRoot":"","sources":["../../../src/loaders/api-base.js"],"names":[],"mappings":"AAOA;;GAEG;AACH;IAQE;;;;;OAKG;IACH,oBAHW,MAAM,eACN,MAAM,OAIhB;IAED;;;;;;;;OAQG;IACH,iBAHW,OAAO,0BAA0B,EAAE,sBAAsB,GAC1D,OAAO,0BAA0B,EAAE,WAAW,CAIvD;IAED;;;;;OAKG;IACH,6BAHW,MAAM,eACN,MAAM,OAIhB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,SACN,MAAM,OAIhB;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,SACN,MAAM,GAAC,MAAM,GAAC,OAAO,GAAC,IAAI,YAC1B,OAAO,OAIjB;IAED;;;;;OAKG;IACH,mBAHW,KAAK,GAAC,MAAM,qBACZ,MAAM,OAIhB;IAED;;;;;OAKG;IACH,iBAHW,MAAM,GAAC,IAAI,iBACX,OAAO,OAIjB;IAED;;;;;;;OAOG;IACH,6BAJW,MAAM,GAAC,IAAI,OAMrB;IAED;;;;OAIG;IACH,0BAFW,CAAC,KAAK,EAAE,KAAK,GAAC,MAAM,KAAK,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,OAI9D;IAED;;;;;OAKG;IACH,iBAHW,MAAM,MACN,MAAM,OAIhB;IAED;;;;;MAKE;IACF,aAHW,MAAM,YACN;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM,CAAA;KAAC,OAIpF;IAED;;;OAGG;IACH,aAEC;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAIhB;IAED;;;;OAIG;IACH,oBAEC;IAED;;;;;OAKG;IACH,mBAEC;IAED;;;;;;;;;;OAUG;IACH,6BARW;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,OAUrF;IAED;;;;;OAKG;IACH,0BAHW,MAAM,OAKhB;IAED;;;;;;;;;MASE;IACF,mBANG;QAAuB,UAAU;QACT,cAAc;KACtC,GAAU,mBAAmB,CAM/B;IAED;;;;;;MAME;IACF,mBAJW,MAAM,gBACN,MAAM,YACN;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,GAAC,OAAO,GAAC,OAAO,GAAC,MAAM,GAAC,MAAM,CAAA;KAAC,OAIpF;IAED;;;;;;OAMG;IACH,cAJW,MAAM,YACN;QAAC,KAAK,CAAC,EAAE,MAAM,GAAC,eAAe,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,GAAC,eAAe,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAC,GACvF;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAIpF;IAED;;;;;OAKG;IACH,gBAFW,OAAO,OAAC,OAIlB;;CACF;kCAvOY,OAAO,yBAAyB,EAAE,mBAAmB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.314.0-rc.0",
3
+ "version": "1.314.0-rc.2",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -13,5 +13,6 @@ export const SUPPORTS_REGISTERED_ENTITIES = {
13
13
  [FEATURE_NAMES.logging]: true,
14
14
  [FEATURE_NAMES.genericEvents]: true,
15
15
  [FEATURE_NAMES.jserrors]: true,
16
- [FEATURE_NAMES.ajax]: true
16
+ [FEATURE_NAMES.ajax]: true,
17
+ [FEATURE_NAMES.pageViewTiming]: true
17
18
  }
@@ -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 { onCLS } from 'web-vitals/attribution'
@@ -18,6 +18,6 @@ if (isBrowserScope) {
18
18
  largestShiftValue: attribution.largestShiftValue,
19
19
  loadState: attribution.loadState
20
20
  }
21
- cumulativeLayoutShift.update({ value, attrs })
21
+ cumulativeLayoutShift.update({ value, attrs, element: attribution.largestShiftSource?.node })
22
22
  }, { reportAllChanges: true })
23
23
  }
@@ -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 { onINP } from 'web-vitals/attribution'
@@ -25,6 +25,6 @@ if (isBrowserScope) {
25
25
  presentationDelay: attribution.presentationDelay,
26
26
  loadState: attribution.loadState
27
27
  }
28
- interactionToNextPaint.update({ value, attrs })
28
+ interactionToNextPaint.update({ value, attrs, element: attribution.interactionTargetElement })
29
29
  })
30
30
  }
@@ -31,6 +31,6 @@ if (isBrowserScope) {
31
31
  if (attribution.element) attrs.element = attribution.element
32
32
  if (attribution.url) attrs.elUrl = cleanURL(attribution.url)
33
33
 
34
- largestContentfulPaint.update({ value, attrs })
34
+ largestContentfulPaint.update({ value, attrs, element: lcpEntry?.element })
35
35
  })
36
36
  }
@@ -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
  export class VitalMetric {
@@ -12,12 +12,13 @@ export class VitalMetric {
12
12
  this.roundingMethod = typeof roundingMethod === 'function' ? roundingMethod : Math.floor
13
13
  }
14
14
 
15
- update ({ value, attrs = {} }) {
15
+ update ({ value, attrs = {}, element }) {
16
16
  if (value === undefined || value === null || value < 0) return
17
17
  const state = {
18
18
  value: this.roundingMethod(value),
19
19
  name: this.name,
20
- attrs
20
+ attrs,
21
+ element
21
22
  }
22
23
 
23
24
  this.history.push(state)
@@ -34,7 +35,8 @@ export class VitalMetric {
34
35
  return this.history[this.history.length - 1] || {
35
36
  value: undefined,
36
37
  name: this.name,
37
- attrs: {}
38
+ attrs: {},
39
+ element: undefined
38
40
  }
39
41
  }
40
42
 
@@ -20,13 +20,15 @@ import { initiallyHidden, getNavigationEntry, initialLocation } from '../../../c
20
20
  import { eventOrigin } from '../../../common/util/event-origin'
21
21
  import { loadTime } from '../../../common/vitals/load-time'
22
22
  import { webdriverDetected } from '../../../common/util/webdriver-detection'
23
+ import { analyzeElemPath } from '../../../common/dom/selector-path'
24
+ import { getVersion2Attributes, getVersion2DuplicationAttributes, shouldDuplicate } from '../../../common/v2/utils'
23
25
  import { cleanURL } from '../../../common/url/clean-url'
24
26
 
25
27
  export class Aggregate extends AggregateBase {
26
28
  static featureName = FEATURE_NAME
27
29
 
28
- #handleVitalMetric = ({ name, value, attrs }) => {
29
- this.addTiming(name, value, attrs)
30
+ #handleVitalMetric = ({ name, value, attrs, element }) => {
31
+ this.addTiming(name, value, attrs, element)
30
32
  }
31
33
 
32
34
  constructor (agentRef) {
@@ -50,9 +52,9 @@ export class Aggregate extends AggregateBase {
50
52
  /* Downstream, the event consumer interprets all timing node value as ms-unit and converts it to seconds via division by 1000. CLS is unitless so this normally is a problem.
51
53
  bel.6 schema also doesn't support decimal values, of which cls within [0,1). However, the two nicely cancels out, and we can multiply cls by 1000 to both negate the division
52
54
  and send an integer > 1. We effectively lose some precision down to 3 decimal places for this workaround. E.g. (real) 0.749132... -> 749.132...-> 749 -> 0.749 (final) */
53
- const { name, value, attrs } = cumulativeLayoutShift.current
55
+ const { name, value, attrs, element } = cumulativeLayoutShift.current
54
56
  if (value === undefined) return
55
- this.addTiming(name, value * 1000, attrs)
57
+ this.addTiming(name, value * 1000, attrs, element)
56
58
  }, true, true) // CLS node should only reports on vis change rather than on every change
57
59
 
58
60
  this.drain()
@@ -70,7 +72,7 @@ export class Aggregate extends AggregateBase {
70
72
  }
71
73
  }
72
74
 
73
- addTiming (name, value, attrs) {
75
+ addTiming (name, value, attrs, element) {
74
76
  attrs = attrs || {}
75
77
  attrs.pageUrl = cleanURL(getNavigationEntry()?.name || initialLocation)
76
78
 
@@ -93,7 +95,13 @@ export class Aggregate extends AggregateBase {
93
95
  value,
94
96
  attrs
95
97
  }
96
- this.events.add(timing)
98
+
99
+ const targets = analyzeElemPath(element, [], this.agentRef).targets
100
+ if (!targets.length) targets.push(undefined)
101
+ targets.forEach(target => {
102
+ this.events.add({ ...timing, attrs: { ...attrs, ...getVersion2Attributes(target, this) } })
103
+ if (shouldDuplicate(target, this.agentRef)) this.events.add({ ...timing, attrs: { ...attrs, ...getVersion2DuplicationAttributes(target, this) } })
104
+ })
97
105
 
98
106
  handle('pvtAdded', [name, value, attrs], undefined, FEATURE_NAMES.sessionTrace, this.ee)
99
107
 
@@ -30,7 +30,6 @@ export class Aggregate extends AggregateBase {
30
30
  this.initialPageLoadInteraction.forceSave = true // unless forcibly ignored, iPL always finish by default
31
31
  const ixn = this.initialPageLoadInteraction
32
32
  this.events.add(ixn) // add the iPL ixn to the buffer for harvest
33
- this.initialPageLoadInteraction = null
34
33
  })
35
34
 
36
35
  loadTime.subscribe(({ value: loadEventTime }) => {
@@ -230,16 +229,19 @@ export class Aggregate extends AggregateBase {
230
229
  const INTERACTION_API = 'api-ixn-'
231
230
  const thisClass = this
232
231
 
233
- registerHandler(INTERACTION_API + 'get', function (time, { waitForEnd } = {}) {
232
+ registerHandler(INTERACTION_API + 'get', function (time, { waitForEnd, targetPageLoad } = {}) {
234
233
  // In here, 'this' refers to the EventContext specific to per InteractionHandle instance spawned by each .interaction() api call.
235
234
  // Each api call aka IH instance would therefore retain a reference to either the in-progress interaction *at the time of the call* OR a new api-started interaction.
236
- this.associatedInteraction = thisClass.getInteractionFor(time)
237
- if (this.associatedInteraction?.trigger === IPL_TRIGGER_NAME) this.associatedInteraction = null // the api get-interaction method cannot target IPL
238
- if (!this.associatedInteraction) {
235
+ if (targetPageLoad) this.associatedInteraction = thisClass.initialPageLoadInteraction // this option only grabs the IPL, no frills
236
+ else {
237
+ this.associatedInteraction = thisClass.getInteractionFor(time)
238
+ if (this.associatedInteraction?.trigger === IPL_TRIGGER_NAME) this.associatedInteraction = null // the api get-interaction method cannot target IPL
239
+ if (!this.associatedInteraction) {
239
240
  // This new api-driven interaction will be the target of any subsequent .interaction() call, until it is closed by EITHER .end() OR the regular url>dom change process.
240
- this.associatedInteraction = thisClass.interactionInProgress = new Interaction(API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi)
241
- thisClass.domObserver.observe(document.body, { attributes: true, childList: true, subtree: true, characterData: true }) // start observing for DOM changes like a regular UI-driven interaction
242
- thisClass.setClosureHandlers()
241
+ this.associatedInteraction = thisClass.interactionInProgress = new Interaction(API_TRIGGER_NAME, Math.floor(time), thisClass.latestRouteSetByApi)
242
+ thisClass.domObserver.observe(document.body, { attributes: true, childList: true, subtree: true, characterData: true }) // start observing for DOM changes like a regular UI-driven interaction
243
+ thisClass.setClosureHandlers()
244
+ }
243
245
  }
244
246
  if (waitForEnd === true) {
245
247
  this.associatedInteraction.keepOpenUntilEndApi = true
@@ -197,6 +197,7 @@ export class ApiBase {
197
197
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/interaction/}
198
198
  * @param {Object} [opts] Options to configure the new or existing interaction with
199
199
  * @param {boolean} [opts.waitForEnd=false] To forcibly keep the interaction open until the `.end` method is called on its handle, set to true. Defaults to false. After an interaction is earmarked with this, it cannot be undone.
200
+ * @param {boolean} [opts.targetPageLoad=false] If true, bind this API handle to the initial page load interaction forcibly instead of creating or targeting a soft navigation interaction.
200
201
  * @returns {InteractionInstance} An API object that is bound to a specific BrowserInteraction event. Each time this method is called for the same BrowserInteraction, a new object is created, but it still references the same interaction.
201
202
  * - Note: Does not apply to MicroAgent
202
203
  * - Deprecation Notice: interaction.createTracer is deprecated. See https://docs.newrelic.com/eol/2024/04/eol-04-24-24-createtracer/ for more information.