@newrelic/browser-agent 1.312.1 → 1.313.0-rc.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 (104) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/common/config/init-types.js +3 -2
  3. package/dist/cjs/common/config/init.js +10 -8
  4. package/dist/cjs/common/constants/env.cdn.js +1 -1
  5. package/dist/cjs/common/constants/env.npm.js +1 -1
  6. package/dist/cjs/common/timing/time-keeper.js +28 -1
  7. package/dist/cjs/common/util/short-circuit.js +13 -0
  8. package/dist/cjs/common/util/submit-data.js +2 -9
  9. package/dist/cjs/common/v2/script-correlation.js +50 -0
  10. package/dist/cjs/common/v2/script-tracker.js +278 -0
  11. package/dist/cjs/common/{util/v2.js → v2/utils.js} +4 -4
  12. package/dist/cjs/common/wrap/wrap-fetch.js +2 -2
  13. package/dist/cjs/common/wrap/wrap-function.js +2 -2
  14. package/dist/cjs/common/wrap/wrap-xhr.js +2 -2
  15. package/dist/cjs/features/ajax/aggregate/index.js +4 -4
  16. package/dist/cjs/features/generic_events/aggregate/index.js +21 -2
  17. package/dist/cjs/features/generic_events/instrument/index.js +24 -21
  18. package/dist/cjs/features/jserrors/aggregate/index.js +206 -40
  19. package/dist/cjs/features/logging/aggregate/index.js +4 -4
  20. package/dist/cjs/features/metrics/instrument/index.js +1 -8
  21. package/dist/cjs/features/session_trace/aggregate/index.js +3 -4
  22. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +2 -2
  23. package/dist/cjs/interfaces/registered-entity.js +7 -20
  24. package/dist/cjs/loaders/api/register-api-types.js +8 -8
  25. package/dist/cjs/loaders/api/register.js +49 -43
  26. package/dist/esm/common/config/init-types.js +3 -2
  27. package/dist/esm/common/config/init.js +10 -8
  28. package/dist/esm/common/constants/env.cdn.js +1 -1
  29. package/dist/esm/common/constants/env.npm.js +1 -1
  30. package/dist/esm/common/timing/time-keeper.js +28 -1
  31. package/dist/esm/common/util/short-circuit.js +6 -0
  32. package/dist/esm/common/util/submit-data.js +2 -9
  33. package/dist/esm/common/v2/script-correlation.js +43 -0
  34. package/dist/esm/common/v2/script-tracker.js +270 -0
  35. package/dist/esm/common/{util/v2.js → v2/utils.js} +4 -4
  36. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  37. package/dist/esm/common/wrap/wrap-function.js +1 -1
  38. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  39. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  40. package/dist/esm/features/generic_events/aggregate/index.js +20 -1
  41. package/dist/esm/features/generic_events/instrument/index.js +24 -21
  42. package/dist/esm/features/jserrors/aggregate/index.js +205 -39
  43. package/dist/esm/features/logging/aggregate/index.js +1 -1
  44. package/dist/esm/features/metrics/instrument/index.js +2 -9
  45. package/dist/esm/features/session_trace/aggregate/index.js +4 -5
  46. package/dist/esm/features/session_trace/aggregate/trace/storage.js +2 -2
  47. package/dist/esm/interfaces/registered-entity.js +7 -20
  48. package/dist/esm/loaders/api/register-api-types.js +8 -8
  49. package/dist/esm/loaders/api/register.js +46 -41
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/dist/types/common/config/init-types.d.ts +10 -8
  52. package/dist/types/common/config/init-types.d.ts.map +1 -1
  53. package/dist/types/common/config/init.d.ts.map +1 -1
  54. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  55. package/dist/types/common/util/short-circuit.d.ts +8 -0
  56. package/dist/types/common/util/short-circuit.d.ts.map +1 -0
  57. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  58. package/dist/types/common/v2/script-correlation.d.ts +38 -0
  59. package/dist/types/common/v2/script-correlation.d.ts.map +1 -0
  60. package/dist/types/common/{util → v2}/script-tracker.d.ts +3 -0
  61. package/dist/types/common/v2/script-tracker.d.ts.map +1 -0
  62. package/dist/types/common/{util/v2.d.ts → v2/utils.d.ts} +1 -1
  63. package/dist/types/common/v2/utils.d.ts.map +1 -0
  64. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  65. package/dist/types/features/generic_events/instrument/index.d.ts +1 -1
  66. package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
  67. package/dist/types/features/jserrors/aggregate/index.d.ts +25 -16
  68. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  69. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  70. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  71. package/dist/types/interfaces/registered-entity.d.ts +0 -10
  72. package/dist/types/interfaces/registered-entity.d.ts.map +1 -1
  73. package/dist/types/loaders/api/register-api-types.d.ts +15 -15
  74. package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
  75. package/dist/types/loaders/api/register.d.ts +6 -0
  76. package/dist/types/loaders/api/register.d.ts.map +1 -1
  77. package/package.json +2 -2
  78. package/src/common/config/init-types.js +3 -2
  79. package/src/common/config/init.js +6 -4
  80. package/src/common/timing/time-keeper.js +30 -1
  81. package/src/common/util/short-circuit.js +6 -0
  82. package/src/common/util/submit-data.js +2 -8
  83. package/src/common/v2/script-correlation.js +44 -0
  84. package/src/common/v2/script-tracker.js +260 -0
  85. package/src/common/{util/v2.js → v2/utils.js} +4 -4
  86. package/src/common/wrap/wrap-fetch.js +1 -1
  87. package/src/common/wrap/wrap-function.js +1 -1
  88. package/src/common/wrap/wrap-xhr.js +1 -1
  89. package/src/features/ajax/aggregate/index.js +1 -1
  90. package/src/features/generic_events/aggregate/index.js +20 -1
  91. package/src/features/generic_events/instrument/index.js +25 -22
  92. package/src/features/jserrors/aggregate/index.js +200 -43
  93. package/src/features/logging/aggregate/index.js +1 -1
  94. package/src/features/metrics/instrument/index.js +2 -13
  95. package/src/features/session_trace/aggregate/index.js +4 -6
  96. package/src/features/session_trace/aggregate/trace/storage.js +2 -2
  97. package/src/interfaces/registered-entity.js +8 -20
  98. package/src/loaders/api/register-api-types.js +8 -8
  99. package/src/loaders/api/register.js +42 -34
  100. package/dist/cjs/common/util/script-tracker.js +0 -204
  101. package/dist/esm/common/util/script-tracker.js +0 -196
  102. package/dist/types/common/util/script-tracker.d.ts.map +0 -1
  103. package/dist/types/common/util/v2.d.ts.map +0 -1
  104. package/src/common/util/script-tracker.js +0 -189
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.313.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.312.1...v1.313.0) (2026-04-14)
7
+
8
+
9
+ ### Features
10
+
11
+ * Apply legal and compliance requirements to register API ([#1742](https://github.com/newrelic/newrelic-browser-agent/issues/1742)) ([24199ee](https://github.com/newrelic/newrelic-browser-agent/commit/24199ee75c0e8d1e74d7d882526fd868b87a93ae))
12
+ * Automatically Detect MFE Errors ([#1720](https://github.com/newrelic/newrelic-browser-agent/issues/1720)) ([281617a](https://github.com/newrelic/newrelic-browser-agent/commit/281617a351459afe82c52e0ce657d3f7b1b5f19c))
13
+ * Improve MicroFrontEndTiming heuristics ([#1735](https://github.com/newrelic/newrelic-browser-agent/issues/1735)) ([e59c60a](https://github.com/newrelic/newrelic-browser-agent/commit/e59c60af34e8f2408ffa4835dc6db4fdcbf756ba))
14
+ * remove "withCredentials" ([#1747](https://github.com/newrelic/newrelic-browser-agent/issues/1747)) ([e84c292](https://github.com/newrelic/newrelic-browser-agent/commit/e84c292b9d17918de0e8e1542fe363e28fa67d33))
15
+ * Report CSP violations as new events ([#1736](https://github.com/newrelic/newrelic-browser-agent/issues/1736)) ([65b5b98](https://github.com/newrelic/newrelic-browser-agent/commit/65b5b988c6cb8d852ad952a3eee94a54864afcd2))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * Bad `trace.lastTimestamp` in Safari + back nav edge case ([#1754](https://github.com/newrelic/newrelic-browser-agent/issues/1754)) ([a607ee1](https://github.com/newrelic/newrelic-browser-agent/commit/a607ee1b34bb57fb800f0220074cd27d1f86a32d))
21
+
6
22
  ## [1.312.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.312.0...v1.312.1) (2026-04-02)
7
23
 
8
24
 
@@ -17,8 +17,9 @@ exports.default = void 0;
17
17
  * @property {boolean} [ajax.enabled] - Turn on/off the ajax feature (on by default).
18
18
  * @property {boolean} [ajax.autoStart] - If true, the agent will automatically start the ajax feature. Otherwise, it will be in a deferred state until the `start` API method is called.
19
19
  * @property {Object} [api]
20
- * @property {boolean} [api.allow_registered_children] - If true, the agent will allow registered children to be sent to the server.
21
- * @property {boolean} [api.duplicate_registered_data] - If true, the agent will capture registered child data to the main agent as well as the registered child.
20
+ * @property {Object} [api.register]
21
+ * @property {boolean} [api.register.enabled] - If true, the agent will allow registered children to be sent to the server.
22
+ * @property {boolean} [api.register.duplicate_data_to_container] - If true, the agent will capture registered child data to the main agent as well as the registered child.
22
23
  * @property {Object} [distributed_tracing]
23
24
  * @property {boolean} [distributed_tracing.enabled] - If true, distributed tracing headers will be added to outgoing requests. Requires ajax feature to be running.
24
25
  * @property {boolean} [distributed_tracing.exclude_newrelic_header]
@@ -27,7 +27,7 @@ const InitModelFn = () => {
27
27
  const hiddenState = {
28
28
  feature_flags: [],
29
29
  experimental: {
30
- allow_registered_children: false,
30
+ register: false,
31
31
  resources: false
32
32
  },
33
33
  mask_selector: '*',
@@ -60,13 +60,15 @@ const InitModelFn = () => {
60
60
  autoStart: true
61
61
  },
62
62
  api: {
63
- get allow_registered_children() {
64
- return hiddenState.feature_flags.includes(_constants.FEATURE_FLAGS.REGISTER) || hiddenState.experimental.allow_registered_children;
65
- },
66
- set allow_registered_children(val) {
67
- hiddenState.experimental.allow_registered_children = val;
68
- },
69
- duplicate_registered_data: false
63
+ register: {
64
+ get enabled() {
65
+ return hiddenState.feature_flags.includes(_constants.FEATURE_FLAGS.REGISTER) || hiddenState.experimental.register;
66
+ },
67
+ set enabled(val) {
68
+ hiddenState.experimental.register = val;
69
+ },
70
+ duplicate_data_to_container: false
71
+ }
70
72
  },
71
73
  browser_consent_mode: {
72
74
  enabled: false
@@ -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.312.1";
20
+ const VERSION = exports.VERSION = "1.313.0-rc.0";
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.312.1";
20
+ const VERSION = exports.VERSION = "1.313.0-rc.0";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -4,10 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.TimeKeeper = void 0;
7
+ var _constants = require("../../features/metrics/constants");
7
8
  var _runtime = require("../constants/runtime");
8
9
  var _monkeyPatched = require("../util/monkey-patched");
10
+ var _handle = require("../event-emitter/handle");
11
+ var _features = require("../../loaders/features/features");
9
12
  /**
10
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
13
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
11
14
  * SPDX-License-Identifier: Apache-2.0
12
15
  */
13
16
 
@@ -42,11 +45,31 @@ class TimeKeeper {
42
45
  * @type {boolean}
43
46
  */
44
47
  #ready = false;
48
+ #reportedDrift = false;
45
49
  constructor(sessionObj) {
46
50
  this.#session = sessionObj;
47
51
  this.processStoredDiff();
48
52
  (0, _monkeyPatched.isNative)(performance.now, Date.now); // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
49
53
  }
54
+ #detectDrift() {
55
+ if (this.#reportedDrift) return;
56
+ try {
57
+ // Drift detection: measures if performance.now() and Date.now() have become desynchronized
58
+ // This can happen when a machine sleeps and the performance timer freezes while Date continues
59
+ // this can also happen when a user sets their clock forward during the page lifecycle,
60
+ // but we have no way of distinguishing that from actual clock drift so we will just treat it as drift.
61
+ // In either case, the performance timestamps would be inaccurate at that point so we want to detect and report a count of it.
62
+ // We only detect positive drift (performance clock falling behind Date clock)
63
+ // Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
64
+ const drift = Date.now() - _runtime.originTime - performance.now();
65
+ if (drift > 1000) {
66
+ this.#reportedDrift = true;
67
+ (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, _features.FEATURE_NAMES.metrics, this.#session.agentRef.ee);
68
+ }
69
+ } catch (err) {
70
+ // Silently ignore drift detection errors to avoid breaking normal operation
71
+ }
72
+ }
50
73
  get ready() {
51
74
  return this.#ready;
52
75
  }
@@ -91,6 +114,7 @@ class TimeKeeper {
91
114
  * @returns {number} Corrected unix/epoch timestamp
92
115
  */
93
116
  convertRelativeTimestamp(relativeTime) {
117
+ this.#detectDrift();
94
118
  return _runtime.originTime + relativeTime;
95
119
  }
96
120
 
@@ -101,6 +125,7 @@ class TimeKeeper {
101
125
  * @returns {number}
102
126
  */
103
127
  convertAbsoluteTimestamp(timestamp) {
128
+ this.#detectDrift();
104
129
  return timestamp - _runtime.originTime;
105
130
  }
106
131
 
@@ -110,6 +135,7 @@ class TimeKeeper {
110
135
  * @return {number} Corrected unix/epoch timestamp
111
136
  */
112
137
  correctAbsoluteTimestamp(timestamp) {
138
+ this.#detectDrift();
113
139
  return timestamp - this.#localTimeDiff;
114
140
  }
115
141
 
@@ -119,6 +145,7 @@ class TimeKeeper {
119
145
  * @returns {number}
120
146
  */
121
147
  correctRelativeTimestamp(relativeTime) {
148
+ this.#detectDrift();
122
149
  return this.correctAbsoluteTimestamp(this.convertRelativeTimestamp(relativeTime));
123
150
  }
124
151
 
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ShortCircuit = void 0;
7
+ /**
8
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
9
+ * SPDX-License-Identifier: Apache-2.0
10
+ */
11
+ /** A special error used to short-circuit the error processing pipeline */
12
+ class ShortCircuit extends Error {}
13
+ exports.ShortCircuit = ShortCircuit;
@@ -9,7 +9,7 @@ exports.xhr = xhr;
9
9
  exports.xhrFetch = xhrFetch;
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
 
@@ -70,8 +70,7 @@ function xhrFetch({
70
70
  return fetch(url, {
71
71
  headers: objHeaders,
72
72
  method,
73
- body,
74
- credentials: 'include'
73
+ body
75
74
  });
76
75
  }
77
76
 
@@ -97,12 +96,6 @@ function xhr({
97
96
  }) {
98
97
  const request = new XMLHttpRequest();
99
98
  request.open(method, url, !sync);
100
- try {
101
- // Set cookie
102
- if ('withCredentials' in request) request.withCredentials = true;
103
- } catch (e) {
104
- // do nothing
105
- }
106
99
  headers.forEach(header => {
107
100
  request.setRequestHeader(header.key, header.value);
108
101
  });
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ScriptCorrelation = void 0;
7
+ /**
8
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
9
+ * SPDX-License-Identifier: Apache-2.0
10
+ */
11
+ /**
12
+ * Represents script correlation data combining DOM and Performance API information
13
+ */
14
+ class ScriptCorrelation {
15
+ /** @type {CorrelationTiming} [dom] - DOM-related information */
16
+ dom = new CorrelationTiming();
17
+ /** @type {CorrelationTiming} [performance] - Performance-related information */
18
+ performance = new CorrelationTiming();
19
+
20
+ /**
21
+ * Creates a new ScriptCorrelation instance
22
+ * @param {string} url - The cleaned URL of the script
23
+ */
24
+ constructor(url) {
25
+ /** @type {string} The cleaned URL of the script */
26
+ this.url = url;
27
+ }
28
+
29
+ /**
30
+ * Gets the script timing, using DOM timings if available, otherwise falling back to performance timings or registeredAt as appropriate. This is used to provide the most accurate script timing possible for registered entities.
31
+ * @returns {{start: number, end: number}
32
+ */
33
+ get script() {
34
+ const start = Math.max(this.dom.start, this.performance.end);
35
+ const end = Math.max(this.dom.end, this.performance.end, start);
36
+ return {
37
+ start,
38
+ end
39
+ };
40
+ }
41
+ }
42
+ exports.ScriptCorrelation = ScriptCorrelation;
43
+ class CorrelationTiming {
44
+ /** @type {number} [start] - The startTime from the performance entry */
45
+ start = 0;
46
+ /** @type {number} [end] - The responseEnd from the performance entry */
47
+ end = 0;
48
+ /** @type {*} [value] - The entry value */
49
+ value = undefined;
50
+ }
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.extractUrlsFromStack = extractUrlsFromStack;
7
+ exports.findScriptTimings = findScriptTimings;
8
+ exports.getDeepStackTrace = getDeepStackTrace;
9
+ exports.thisFile = exports.scriptCorrelations = void 0;
10
+ var _runtime = require("../constants/runtime");
11
+ var _now = require("../timing/now");
12
+ var _cleanUrl = require("../url/clean-url");
13
+ var _browserStackMatchers = require("../util/browser-stack-matchers");
14
+ var _scriptCorrelation = require("./script-correlation");
15
+ /**
16
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
17
+ * SPDX-License-Identifier: Apache-2.0
18
+ */
19
+
20
+ /**
21
+ * @typedef {import('./register-api-types').RegisterAPITimings} RegisterAPITimings
22
+ */
23
+
24
+ /** export for testing purposes */
25
+ let thisFile = exports.thisFile = void 0;
26
+ try {
27
+ exports.thisFile = thisFile = extractUrlsFromStack(getDeepStackTrace())[0];
28
+ } catch (err) {
29
+ exports.thisFile = thisFile = extractUrlsFromStack(err)[0];
30
+ }
31
+
32
+ /** @type {(entry: PerformanceEntry) => boolean} - A shared function to determine if a performance entry is a valid script or link resource for evaluation */
33
+ const validEntryCriteria = entry => entry.initiatorType === 'script' || ['link', 'fetch'].includes(entry.initiatorType) && entry.name.endsWith('.js');
34
+
35
+ /** @type {Map<string, ScriptCorrelation>} - Central registry for script correlations containing both DOM and Performance data */
36
+ const scriptCorrelations = exports.scriptCorrelations = new Map();
37
+ /** @type {Array<{ test: (entry: PerformanceEntry) => boolean, addedAt: number }>} an array of PerformanceObserver subscribers to check for late emissions */
38
+ let poSubscribers = [];
39
+
40
+ /**
41
+ * Retrieves a script correlation by URL using exact matching
42
+ * @param {string} targetUrl - The URL to find
43
+ * @returns {ScriptCorrelation | undefined} - The correlation object if found
44
+ */
45
+ function findCorrelation(targetUrl) {
46
+ return scriptCorrelations.get(targetUrl);
47
+ }
48
+
49
+ /**
50
+ * Gets or creates a script correlation entry
51
+ * @param {string} url - The cleaned URL
52
+ * @returns {ScriptCorrelation} - The correlation object
53
+ */
54
+ function getOrCreateCorrelation(url) {
55
+ const existing = findCorrelation(url);
56
+ if (existing) return existing;
57
+ const correlation = new _scriptCorrelation.ScriptCorrelation(url);
58
+ scriptCorrelations.set(url, correlation);
59
+
60
+ // Keep size under control
61
+ if (scriptCorrelations.size > 1000) {
62
+ const firstKey = scriptCorrelations.keys().next().value;
63
+ scriptCorrelations.delete(firstKey);
64
+ }
65
+ return correlation;
66
+ }
67
+
68
+ /** Set up a MutationObserver to detect script elements being added to the DOM */
69
+ if (_runtime.globalScope.MutationObserver && _runtime.globalScope.document) {
70
+ const scriptMutationObserver = new MutationObserver(mutations => {
71
+ mutations.forEach(mutation => {
72
+ mutation.addedNodes.forEach(node => {
73
+ if (node.nodeName === 'SCRIPT' && node.src) {
74
+ const cleanedSrc = (0, _cleanUrl.cleanURL)(node.src);
75
+ const correlation = getOrCreateCorrelation(cleanedSrc);
76
+ correlation.dom.start = (0, _now.now)();
77
+ correlation.dom.value = node;
78
+ const setEnd = () => {
79
+ correlation.dom.end = (0, _now.now)();
80
+ };
81
+ ['load', 'error'].forEach(event => node.addEventListener(event, setEnd, {
82
+ once: true
83
+ }));
84
+ }
85
+ });
86
+ });
87
+ });
88
+ scriptMutationObserver.observe(_runtime.globalScope.document, {
89
+ childList: true,
90
+ subtree: true
91
+ });
92
+ }
93
+ if (_runtime.globalScope.PerformanceObserver?.supportedEntryTypes.includes('resource')) {
94
+ /** We must track the script assets this way, because the performance buffer can fill up and when it does that
95
+ * it stops accepting new entries (instead of dropping old entries), which means if the register API is called
96
+ * after the buffer fills up we won't be able to get the script timing information from the resource timing API
97
+ */
98
+ const scriptObserver = new PerformanceObserver(list => {
99
+ list.getEntries().filter(validEntryCriteria).forEach(entry => {
100
+ // Update correlation with performance data (creates entry if needed)
101
+ const entryUrl = (0, _cleanUrl.cleanURL)(entry.name);
102
+ const correlation = getOrCreateCorrelation(entryUrl);
103
+ correlation.performance.start = Math.floor(entry.startTime);
104
+ correlation.performance.end = Math.floor(entry.responseEnd);
105
+ correlation.performance.value = entry;
106
+
107
+ // Clear resolved or expired subscribers
108
+ const canClear = [];
109
+ poSubscribers.forEach(({
110
+ test,
111
+ addedAt
112
+ }, idx) => {
113
+ if (test(entry) || (0, _now.now)() - addedAt > 10000) canClear.push(idx);
114
+ });
115
+ poSubscribers = poSubscribers.filter((_, idx) => !canClear.includes(idx));
116
+ });
117
+ });
118
+ scriptObserver.observe({
119
+ type: 'resource',
120
+ buffered: true
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Extracts URLs from stack traces using the same logic as compute-stack-trace.js
126
+ * @param {string} stack The error stack trace
127
+ * @returns {string[]} Array of cleaned URLs found in the stack trace
128
+ */
129
+ function extractUrlsFromStack(stack) {
130
+ if (!stack || typeof stack !== 'string') return [];
131
+ const urls = new Set();
132
+ const lines = stack.split('\n');
133
+ for (const line of lines) {
134
+ // Try gecko format first, then chrome
135
+ const parts = line.match(_browserStackMatchers.gecko) || line.match(_browserStackMatchers.chrome) || line.match(_browserStackMatchers.chromeEval);
136
+ if (parts && parts[2]) {
137
+ urls.add((0, _cleanUrl.cleanURL)(parts[2]));
138
+ } else {
139
+ // Fallback: match URLs using a generic .js pattern (non-greedy to handle ports and query params)
140
+ const fallbackMatch = line.match(/\(([^)]+\.js):\d+:\d+\)/) || line.match(/^\s+at\s+([^\s(]+\.js):\d+:\d+/);
141
+ if (fallbackMatch && fallbackMatch[1]) {
142
+ urls.add((0, _cleanUrl.cleanURL)(fallbackMatch[1]));
143
+ }
144
+ }
145
+ }
146
+ return [...urls];
147
+ }
148
+
149
+ /**
150
+ * Returns a deep stack trace by temporarily increasing the stack trace limit.
151
+ * @returns {Error.stack | undefined}
152
+ */
153
+ function getDeepStackTrace() {
154
+ let stack;
155
+ try {
156
+ const originalStackLimit = Error.stackTraceLimit;
157
+ Error.stackTraceLimit = 50;
158
+ stack = new Error().stack;
159
+ Error.stackTraceLimit = originalStackLimit;
160
+ } catch (e) {
161
+ stack = new Error().stack;
162
+ }
163
+ return stack;
164
+ }
165
+
166
+ /**
167
+ * Indicates whether the provided URL matches any script preload link tags in the document.
168
+ * @param {string} targetUrl The URL to match against preload tags
169
+ * @returns {boolean} True if a matching preload link is found, false otherwise
170
+ */
171
+ function wasPreloaded(targetUrl) {
172
+ if (!targetUrl || !_runtime.globalScope.document) return false;
173
+ try {
174
+ const linkTags = _runtime.globalScope.document.querySelectorAll('link[rel="preload"][as="script"]');
175
+ for (const link of linkTags) {
176
+ // link.href is resolved to an absolute URL by the browser (even if supplied as relative), so we can match exactly against the cleaned target URL
177
+ if ((0, _cleanUrl.cleanURL)(link.href) === targetUrl) return true;
178
+ }
179
+ } catch (error) {
180
+ // Don't let DOM parsing errors break anything
181
+ }
182
+ return false;
183
+ }
184
+
185
+ /**
186
+ * Checks if a performance entry matches the target MFE script URL using exact matching
187
+ * @param {PerformanceResourceTiming} entry - The resource timing entry
188
+ * @param {string} targetUrl - The MFE script URL to match
189
+ * @returns {boolean} True if the entry matches
190
+ */
191
+ function entryMatchesUrl(entry, targetUrl) {
192
+ const entryUrl = (0, _cleanUrl.cleanURL)(entry.name);
193
+ return entryUrl === targetUrl;
194
+ }
195
+
196
+ /**
197
+ * Applies performance entry timing data to a timings object
198
+ * @param {RegisterAPITimings} timings - The timings object to update
199
+ * @param {PerformanceResourceTiming} entry - The performance entry
200
+ */
201
+ function applyPerformanceEntry(timings, entry) {
202
+ timings.fetchStart = Math.floor(entry.startTime);
203
+ timings.fetchEnd = Math.floor(entry.responseEnd);
204
+ timings.asset = entry.name;
205
+ timings.type = entry.initiatorType;
206
+ }
207
+
208
+ /**
209
+ * Uses the stack of the initiator function, returns script timing information if a script can be found with the resource timing API matching the URL found in the stack.
210
+ * @returns {RegisterAPITimings} Object containing script fetch start and end times, and the asset URL if found
211
+ */
212
+ function findScriptTimings() {
213
+ const timings = {
214
+ registeredAt: (0, _now.now)(),
215
+ reportedAt: undefined,
216
+ fetchStart: 0,
217
+ fetchEnd: 0,
218
+ scriptStart: 0,
219
+ scriptEnd: 0,
220
+ asset: undefined,
221
+ type: 'unknown'
222
+ };
223
+ const stack = getDeepStackTrace();
224
+ if (!stack) return timings;
225
+ const navUrl = _runtime.globalScope.performance?.getEntriesByType('navigation')?.[0]?.name || '';
226
+ try {
227
+ const urls = extractUrlsFromStack(stack);
228
+ // Filter out agent file from URLs (unless it's the only one)
229
+ const mfeScriptUrl = (urls.length > 1 ? urls.filter(line => thisFile !== line) : urls)[0];
230
+ if (!mfeScriptUrl) return timings;
231
+
232
+ // Check for inline script
233
+ if (navUrl.includes(mfeScriptUrl)) {
234
+ timings.asset = (0, _cleanUrl.cleanURL)(navUrl);
235
+ timings.type = 'inline';
236
+ return timings;
237
+ }
238
+
239
+ // Get correlation data
240
+ timings.correlation = findCorrelation(mfeScriptUrl);
241
+
242
+ // Use correlation's performance entry if available, otherwise check live performance API
243
+ const performanceEntry = timings.correlation?.performance.value || performance.getEntriesByType('resource').find(e => entryMatchesUrl(e, mfeScriptUrl));
244
+ if (performanceEntry) {
245
+ applyPerformanceEntry(timings, performanceEntry);
246
+ } else if (wasPreloaded(mfeScriptUrl)) {
247
+ // Handle preloaded scripts that may report late
248
+ timings.asset = mfeScriptUrl;
249
+ timings.type = 'preload';
250
+
251
+ // Subscribe to late performance observer callbacks
252
+ poSubscribers.push({
253
+ addedAt: (0, _now.now)(),
254
+ test: entry => {
255
+ if (entryMatchesUrl(entry, mfeScriptUrl)) {
256
+ applyPerformanceEntry(timings, entry);
257
+ return true;
258
+ }
259
+ return false;
260
+ }
261
+ });
262
+ }
263
+
264
+ /*
265
+ * Use getters here because the correlation data may arrive after this function returns the timing object, and we want to provide the most up-to-date timing information possible when the getters are accessed at harvest time.
266
+ * The getters will fall back to fetchEnd if correlation data isn't available yet, which is our best approximation for script execution start when actual script timings can not be determined.
267
+ */
268
+ Object.defineProperty(timings, 'scriptStart', {
269
+ get: () => timings.correlation?.script.start || timings.fetchEnd
270
+ });
271
+ Object.defineProperty(timings, 'scriptEnd', {
272
+ get: () => timings.correlation?.script.end || timings.registeredAt
273
+ });
274
+ } catch (error) {
275
+ // Don't let stack parsing errors break anything
276
+ }
277
+ return timings;
278
+ }
@@ -34,7 +34,7 @@ const V2_TYPES = exports.V2_TYPES = {
34
34
  * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
35
35
  */
36
36
  function getRegisteredTargetsFromId(id, agentRef) {
37
- if (!id || !agentRef?.init.api.allow_registered_children) return [];
37
+ if (!id || !agentRef?.init.api.register.enabled) return [];
38
38
  const registeredEntities = agentRef.runtime.registeredEntities;
39
39
  return registeredEntities?.filter(entity => String(entity.metadata.target.id) === String(id)).map(entity => entity.metadata.target) || [];
40
40
  }
@@ -46,7 +46,7 @@ function getRegisteredTargetsFromId(id, agentRef) {
46
46
  * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
47
47
  */
48
48
  function getRegisteredTargetsFromFilename(filename, agentRef) {
49
- if (!filename || !agentRef?.init.api.allow_registered_children) return [];
49
+ if (!filename || !agentRef?.init.api.register.enabled) return [];
50
50
  const registeredEntities = agentRef.runtime.registeredEntities;
51
51
  return registeredEntities?.filter(entity => entity.metadata.timings?.asset?.endsWith(filename)).map(entity => entity.metadata.target) || [];
52
52
  }
@@ -98,7 +98,7 @@ function getVersion2DuplicationAttributes(target, aggregateInstance) {
98
98
  * @returns {boolean} returns true if the event should be duplicated for the target, false otherwise
99
99
  */
100
100
  function shouldDuplicate(target, aggregateInstance) {
101
- return !!target && !!supportsV2(aggregateInstance) && aggregateInstance.agentRef.init.api.duplicate_registered_data;
101
+ return !!target && !!supportsV2(aggregateInstance) && aggregateInstance.agentRef.init.api.register.duplicate_data_to_container;
102
102
  }
103
103
 
104
104
  /**
@@ -107,7 +107,7 @@ function shouldDuplicate(target, aggregateInstance) {
107
107
  * @returns {Array} An array of targets found from the stack trace. If no targets are found or allowed, returns an array with undefined.
108
108
  */
109
109
  function findTargetsFromStackTrace(agentRef) {
110
- if (!agentRef?.init.api.allow_registered_children) return [undefined];
110
+ if (!agentRef?.init.api.register.enabled) return [undefined];
111
111
  const targets = [];
112
112
  try {
113
113
  var urls = (0, _scriptTracker.extractUrlsFromStack)((0, _scriptTracker.getDeepStackTrace)());
@@ -7,7 +7,7 @@ exports.scopedEE = scopedEE;
7
7
  exports.wrapFetch = wrapFetch;
8
8
  var _contextualEe = require("../event-emitter/contextual-ee");
9
9
  var _runtime = require("../constants/runtime");
10
- var _v = require("../util/v2");
10
+ var _utils = require("../v2/utils");
11
11
  /**
12
12
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
13
13
  * SPDX-License-Identifier: Apache-2.0
@@ -79,7 +79,7 @@ function wrapFetch(sharedEE, agentRef) {
79
79
  target[name] = function () {
80
80
  var args = [...arguments];
81
81
  const ctx = {};
82
- const targets = (0, _v.findTargetsFromStackTrace)(agentRef);
82
+ const targets = (0, _utils.findTargetsFromStackTrace)(agentRef);
83
83
 
84
84
  // we are wrapping args in an array so we can preserve the reference
85
85
  ee.emit(prefix + 'before-start', [args], ctx);
@@ -8,7 +8,7 @@ exports.createWrapperWithEmitter = createWrapperWithEmitter;
8
8
  exports.flag = exports.default = void 0;
9
9
  var _contextualEe = require("../event-emitter/contextual-ee");
10
10
  var _bundleId = require("../ids/bundle-id");
11
- var _v = require("../util/v2");
11
+ var _utils = require("../v2/utils");
12
12
  /**
13
13
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
14
14
  * SPDX-License-Identifier: Apache-2.0
@@ -89,7 +89,7 @@ function createWrapperWithEmitter(emitter, always, agentRef) {
89
89
 
90
90
  // certain wrappers can inform the function wrapper to evaluate the stack of the executed wrapped function to find targets of the execution
91
91
  // (e.g. wrap-logger can inform this method to find try to find the MFE source of a console.log)
92
- targets = evaluateStack ? (0, _v.findTargetsFromStackTrace)(agentRef) : [undefined]; // undefined target always maps to the container agent
92
+ targets = evaluateStack ? (0, _utils.findTargetsFromStackTrace)(agentRef) : [undefined]; // undefined target always maps to the container agent
93
93
 
94
94
  if (typeof getContext === 'function') {
95
95
  ctx = getContext(args, originalThis);
@@ -11,7 +11,7 @@ var _eventListenerOpts = require("../event-listener/event-listener-opts");
11
11
  var _wrapFunction = require("./wrap-function");
12
12
  var _runtime = require("../constants/runtime");
13
13
  var _console = require("../util/console");
14
- var _v = require("../util/v2");
14
+ var _utils = require("../v2/utils");
15
15
  /**
16
16
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
17
17
  * SPDX-License-Identifier: Apache-2.0
@@ -55,7 +55,7 @@ function wrapXhr(sharedEE, agentRef) {
55
55
  function newXHR(opts) {
56
56
  const xhr = new OrigXHR(opts);
57
57
  const context = ee.context(xhr);
58
- context.targets = (0, _v.findTargetsFromStackTrace)(agentRef);
58
+ context.targets = (0, _utils.findTargetsFromStackTrace)(agentRef);
59
59
  try {
60
60
  ee.emit('new-xhr', [xhr], context);
61
61
  xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), (0, _eventListenerOpts.eventListenerOpts)(false));
@@ -14,7 +14,7 @@ var _aggregateBase = require("../../utils/aggregate-base");
14
14
  var _gql = require("./gql");
15
15
  var _belSerializer = require("../../../common/serialize/bel-serializer");
16
16
  var _nreum = require("../../../common/window/nreum");
17
- var _v = require("../../../common/util/v2");
17
+ var _utils = require("../../../common/v2/utils");
18
18
  /**
19
19
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
20
20
  * SPDX-License-Identifier: Apache-2.0
@@ -106,11 +106,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
106
106
  if (target) {
107
107
  this.events.add({
108
108
  ...event,
109
- targetAttributes: (0, _v.getVersion2Attributes)(target, this)
109
+ targetAttributes: (0, _utils.getVersion2Attributes)(target, this)
110
110
  });
111
- if ((0, _v.shouldDuplicate)(target, this)) this.reportContainerEvent({
111
+ if ((0, _utils.shouldDuplicate)(target, this)) this.reportContainerEvent({
112
112
  ...event,
113
- targetAttributes: (0, _v.getVersion2DuplicationAttributes)(target, this)
113
+ targetAttributes: (0, _utils.getVersion2DuplicationAttributes)(target, this)
114
114
  }, ctx);
115
115
  } else {
116
116
  this.reportContainerEvent(event, ctx);