@newrelic/browser-agent 1.312.1-rc.5 → 1.312.1-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cjs/common/constants/env.cdn.js +1 -1
  2. package/dist/cjs/common/constants/env.npm.js +1 -1
  3. package/dist/cjs/common/v2/script-correlation.js +50 -0
  4. package/dist/cjs/common/v2/script-tracker.js +278 -0
  5. package/dist/cjs/common/wrap/wrap-fetch.js +2 -2
  6. package/dist/cjs/common/wrap/wrap-function.js +2 -2
  7. package/dist/cjs/common/wrap/wrap-xhr.js +2 -2
  8. package/dist/cjs/features/ajax/aggregate/index.js +4 -4
  9. package/dist/cjs/features/generic_events/aggregate/index.js +21 -2
  10. package/dist/cjs/features/generic_events/instrument/index.js +24 -21
  11. package/dist/cjs/features/jserrors/aggregate/index.js +2 -2
  12. package/dist/cjs/features/logging/aggregate/index.js +4 -4
  13. package/dist/cjs/features/metrics/instrument/index.js +1 -8
  14. package/dist/cjs/loaders/api/register-api-types.js +5 -3
  15. package/dist/cjs/loaders/api/register.js +30 -22
  16. package/dist/esm/common/constants/env.cdn.js +1 -1
  17. package/dist/esm/common/constants/env.npm.js +1 -1
  18. package/dist/esm/common/v2/script-correlation.js +43 -0
  19. package/dist/esm/common/v2/script-tracker.js +270 -0
  20. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  21. package/dist/esm/common/wrap/wrap-function.js +1 -1
  22. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  23. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  24. package/dist/esm/features/generic_events/aggregate/index.js +20 -1
  25. package/dist/esm/features/generic_events/instrument/index.js +24 -21
  26. package/dist/esm/features/jserrors/aggregate/index.js +1 -1
  27. package/dist/esm/features/logging/aggregate/index.js +1 -1
  28. package/dist/esm/features/metrics/instrument/index.js +2 -9
  29. package/dist/esm/loaders/api/register-api-types.js +5 -3
  30. package/dist/esm/loaders/api/register.js +28 -20
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/types/common/v2/script-correlation.d.ts +38 -0
  33. package/dist/types/common/v2/script-correlation.d.ts.map +1 -0
  34. package/dist/types/common/{util → v2}/script-tracker.d.ts +3 -0
  35. package/dist/types/common/v2/script-tracker.d.ts.map +1 -0
  36. package/dist/types/common/{util/v2.d.ts → v2/utils.d.ts} +1 -1
  37. package/dist/types/common/v2/utils.d.ts.map +1 -0
  38. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  39. package/dist/types/features/generic_events/instrument/index.d.ts +1 -1
  40. package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -1
  41. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  42. package/dist/types/loaders/api/register-api-types.d.ts +11 -3
  43. package/dist/types/loaders/api/register-api-types.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/src/common/v2/script-correlation.js +44 -0
  46. package/src/common/v2/script-tracker.js +260 -0
  47. package/src/common/wrap/wrap-fetch.js +1 -1
  48. package/src/common/wrap/wrap-function.js +1 -1
  49. package/src/common/wrap/wrap-xhr.js +1 -1
  50. package/src/features/ajax/aggregate/index.js +1 -1
  51. package/src/features/generic_events/aggregate/index.js +20 -1
  52. package/src/features/generic_events/instrument/index.js +25 -22
  53. package/src/features/jserrors/aggregate/index.js +1 -1
  54. package/src/features/logging/aggregate/index.js +1 -1
  55. package/src/features/metrics/instrument/index.js +2 -13
  56. package/src/loaders/api/register-api-types.js +5 -3
  57. package/src/loaders/api/register.js +24 -17
  58. package/dist/cjs/common/util/script-tracker.js +0 -204
  59. package/dist/esm/common/util/script-tracker.js +0 -196
  60. package/dist/types/common/util/script-tracker.d.ts.map +0 -1
  61. package/dist/types/common/util/v2.d.ts.map +0 -1
  62. package/src/common/util/script-tracker.js +0 -189
  63. /package/dist/cjs/common/{util/v2.js → v2/utils.js} +0 -0
  64. /package/dist/esm/common/{util/v2.js → v2/utils.js} +0 -0
  65. /package/src/common/{util/v2.js → v2/utils.js} +0 -0
@@ -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-rc.5";
20
+ const VERSION = exports.VERSION = "1.312.1-rc.7";
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-rc.5";
20
+ const VERSION = exports.VERSION = "1.312.1-rc.7";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -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
+ }
@@ -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);
@@ -16,7 +16,7 @@ var _traverse = require("../../../common/util/traverse");
16
16
  var _userActionsAggregator = require("./user-actions/user-actions-aggregator");
17
17
  var _iframe = require("../../../common/dom/iframe");
18
18
  var _typeCheck = require("../../../common/util/type-check");
19
- var _v = require("../../../common/util/v2");
19
+ var _utils = require("../../../common/v2/utils");
20
20
  /**
21
21
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
22
22
  * SPDX-License-Identifier: Apache-2.0
@@ -270,6 +270,25 @@ class Aggregate extends _aggregateBase.AggregateBase {
270
270
  this.addEvent(event);
271
271
  }, this.featureName, this.ee);
272
272
  }
273
+ if (!agentRef.init.feature_flags.includes('no_spv')) {
274
+ (0, _registerHandler.registerHandler)('spv', evt => {
275
+ this.addEvent({
276
+ eventType: 'SecurityPolicyViolation',
277
+ timestamp: this.#toEpoch(evt.timeStamp),
278
+ blockedUri: evt.blockedURI,
279
+ documentUri: evt.documentURI,
280
+ effectiveDirective: evt.effectiveDirective,
281
+ originalPolicy: evt.originalPolicy,
282
+ sourceFile: evt.sourceFile,
283
+ statusCode: evt.statusCode,
284
+ lineNumber: evt.lineNumber,
285
+ columnNumber: evt.columnNumber,
286
+ disposition: evt.disposition,
287
+ sample: evt.sample,
288
+ referrer: evt.referrer
289
+ });
290
+ }, this.featureName, this.ee);
291
+ }
273
292
  this.drain();
274
293
  });
275
294
  }
@@ -305,7 +324,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
305
324
  pageUrl: (0, _cleanUrl.cleanURL)('' + _runtime.initialLocation),
306
325
  currentUrl: (0, _cleanUrl.cleanURL)('' + location),
307
326
  /** Specific attributes only supplied if harvesting to endpoint version 2 */
308
- ...(0, _v.getVersion2Attributes)(target, this)
327
+ ...(0, _utils.getVersion2Attributes)(target, this)
309
328
  };
310
329
  const eventAttributes = {
311
330
  /** Agent-level custom attributes */
@@ -31,9 +31,10 @@ class Instrument extends _instrumentBase.InstrumentBase {
31
31
  constructor(agentRef) {
32
32
  super(agentRef, _constants.FEATURE_NAME);
33
33
  const websocketsEnabled = agentRef.init.feature_flags.includes('websockets');
34
+ const securityPolicyViolationEnabled = !agentRef.init.feature_flags.includes('no_spv');
34
35
 
35
36
  /** config values that gate whether the generic events aggregator should be imported at all */
36
- const genericEventSourceConfigs = [agentRef.init.page_action.enabled, agentRef.init.performance.capture_marks, agentRef.init.performance.capture_measures, agentRef.init.performance.resources.enabled, agentRef.init.user_actions.enabled, websocketsEnabled];
37
+ const genericEventSourceConfigs = [agentRef.init.page_action.enabled, agentRef.init.performance.capture_marks, agentRef.init.performance.capture_measures, agentRef.init.performance.resources.enabled, agentRef.init.user_actions.enabled, websocketsEnabled, securityPolicyViolationEnabled];
37
38
 
38
39
  /** feature specific APIs */
39
40
  (0, _addPageAction.setupAddPageActionAPI)(agentRef);
@@ -41,8 +42,24 @@ class Instrument extends _instrumentBase.InstrumentBase {
41
42
  (0, _finished.setupFinishedAPI)(agentRef);
42
43
  (0, _register.setupRegisterAPI)(agentRef);
43
44
  (0, _measure.setupMeasureAPI)(agentRef);
44
- let historyEE, websocketsEE;
45
- if (websocketsEnabled) websocketsEE = (0, _wrapWebsocket.wrapWebSocket)(this.ee);
45
+ this.removeOnAbort = new AbortController();
46
+ this.abortHandler = () => {
47
+ this.removeOnAbort.abort();
48
+ this.abortHandler = undefined; // weakly allow this abort op to run only once
49
+ };
50
+ let historyEE;
51
+ if (websocketsEnabled) {
52
+ // this can apply outside browser scope such as in worker
53
+ const websocketsEE = (0, _wrapWebsocket.wrapWebSocket)(this.ee);
54
+ websocketsEE.on('ws', nrData => {
55
+ (0, _handle.handle)('ws-complete', [nrData], undefined, this.featureName, this.ee);
56
+ });
57
+ }
58
+ if (securityPolicyViolationEnabled) {
59
+ _runtime.globalScope.addEventListener('securitypolicyviolation', evt => {
60
+ (0, _handle.handle)('spv', [evt], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
61
+ }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort.signal));
62
+ }
46
63
  if (_runtime.isBrowserScope) {
47
64
  (0, _wrapFetch.wrapFetch)(this.ee, agentRef);
48
65
  (0, _wrapXhr.wrapXhr)(this.ee, agentRef);
@@ -61,7 +78,7 @@ class Instrument extends _instrumentBase.InstrumentBase {
61
78
  );
62
79
  _runtime.globalScope.addEventListener('error', () => {
63
80
  (0, _handle.handle)('uaErr', [], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
64
- }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort?.signal));
81
+ }, (0, _eventListenerOpts.eventListenerOpts)(false, this.removeOnAbort.signal));
65
82
  this.ee.on('open-xhr-start', (args, xhr) => {
66
83
  if (!isInternalTraffic(args[1])) {
67
84
  xhr.addEventListener('readystatechange', () => {
@@ -69,7 +86,7 @@ class Instrument extends _instrumentBase.InstrumentBase {
69
86
  // HEADERS_RECEIVED
70
87
  (0, _handle.handle)('uaXhr', [], undefined, _features.FEATURE_NAMES.genericEvents, this.ee);
71
88
  }
72
- });
89
+ }, (0, _eventListenerOpts.eventListenerOpts)(undefined, this.removeOnAbort.signal));
73
90
  }
74
91
  });
75
92
  this.ee.on('fetch-start', fetchArguments => {
@@ -83,8 +100,8 @@ class Instrument extends _instrumentBase.InstrumentBase {
83
100
  }
84
101
  historyEE.on('pushState-end', navigationChange);
85
102
  historyEE.on('replaceState-end', navigationChange);
86
- window.addEventListener('hashchange', navigationChange, (0, _eventListenerOpts.eventListenerOpts)(true, this.removeOnAbort?.signal));
87
- window.addEventListener('popstate', navigationChange, (0, _eventListenerOpts.eventListenerOpts)(true, this.removeOnAbort?.signal));
103
+ window.addEventListener('hashchange', navigationChange, (0, _eventListenerOpts.eventListenerOpts)(true, this.removeOnAbort.signal));
104
+ window.addEventListener('popstate', navigationChange, (0, _eventListenerOpts.eventListenerOpts)(true, this.removeOnAbort.signal));
88
105
  function navigationChange() {
89
106
  historyEE.emit('navChange');
90
107
  }
@@ -101,20 +118,6 @@ class Instrument extends _instrumentBase.InstrumentBase {
101
118
  });
102
119
  }
103
120
  }
104
- if (websocketsEnabled) {
105
- // this can apply outside browser scope such as in worker
106
- websocketsEE.on('ws', nrData => {
107
- (0, _handle.handle)('ws-complete', [nrData], undefined, this.featureName, this.ee);
108
- });
109
- }
110
- try {
111
- this.removeOnAbort = new AbortController();
112
- } catch (e) {}
113
- this.abortHandler = () => {
114
- this.removeOnAbort?.abort();
115
- this.abortHandler = undefined; // weakly allow this abort op to run only once
116
- };
117
-
118
121
  /** If any of the sources are active, import the aggregator. otherwise deregister */
119
122
  if (genericEventSourceConfigs.some(x => x)) this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "generic_events-aggregate" */'../aggregate'))));else this.deregisterDrain();
120
123
  }
@@ -18,7 +18,7 @@ var _aggregateBase = require("../../utils/aggregate-base");
18
18
  var _now = require("../../../common/timing/now");
19
19
  var _traverse = require("../../../common/util/traverse");
20
20
  var _internalErrors = require("./internal-errors");
21
- var _v = require("../../../common/util/v2");
21
+ var _utils = require("../../../common/v2/utils");
22
22
  var _causeString = require("./cause-string");
23
23
  /**
24
24
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
@@ -200,7 +200,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
200
200
  let [type, bucketHash, params, newMetrics, localAttrs, target] = errorInfoArr;
201
201
  const allCustomAttrs = {
202
202
  /** MFE specific attributes if in "multiple" mode (ie consumer version 2) */
203
- ...(0, _v.getVersion2Attributes)(target, this)
203
+ ...(0, _utils.getVersion2Attributes)(target, this)
204
204
  };
205
205
  Object.entries(this.agentRef.info.jsAttributes).forEach(([k, v]) => setCustom(k, v));
206
206
  Object.entries(softNavCustomAttrs).forEach(([k, v]) => setCustom(k, v)); // when an ixn finishes, it'll pass attrs specific to the ixn; if no associated ixn, this defaults to empty
@@ -15,7 +15,7 @@ var _traverse = require("../../../common/util/traverse");
15
15
  var _constants2 = require("../../../common/session/constants");
16
16
  var _constants3 = require("../../session_replay/constants");
17
17
  var _featureGates = require("../../utils/feature-gates");
18
- var _v = require("../../../common/util/v2");
18
+ var _utils2 = require("../../../common/v2/utils");
19
19
  /**
20
20
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
21
21
  * SPDX-License-Identifier: Apache-2.0
@@ -106,11 +106,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
106
106
  };
107
107
  addEvent({
108
108
  ...attributes,
109
- ...(0, _v.getVersion2Attributes)(target, this)
109
+ ...(0, _utils2.getVersion2Attributes)(target, this)
110
110
  });
111
- if ((0, _v.shouldDuplicate)(target, this)) addEvent({
111
+ if ((0, _utils2.shouldDuplicate)(target, this)) addEvent({
112
112
  ...attributes,
113
- ...(0, _v.getVersion2DuplicationAttributes)(target, this)
113
+ ...(0, _utils2.getVersion2DuplicationAttributes)(target, this)
114
114
  });
115
115
  }
116
116
  serializer(eventBuffer) {
@@ -4,23 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Metrics = exports.Instrument = void 0;
7
- var _runtime = require("../../../common/constants/runtime");
8
- var _handle = require("../../../common/event-emitter/handle");
9
7
  var _instrumentBase = require("../../utils/instrument-base");
10
8
  var _constants = require("../constants");
11
9
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
12
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
10
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
13
11
  * SPDX-License-Identifier: Apache-2.0
14
12
  */
15
13
  class Instrument extends _instrumentBase.InstrumentBase {
16
14
  static featureName = _constants.FEATURE_NAME;
17
15
  constructor(agentRef) {
18
16
  super(agentRef, _constants.FEATURE_NAME);
19
- if (_runtime.isBrowserScope) {
20
- document.addEventListener('securitypolicyviolation', e => {
21
- (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/CSPViolation/Detected'], undefined, this.featureName, this.ee);
22
- });
23
- }
24
17
  this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "metrics-aggregate" */'../aggregate'))));
25
18
  }
26
19
  }
@@ -46,9 +46,11 @@ exports.default = void 0;
46
46
  * @typedef {Object} RegisterAPITimings
47
47
  * @property {number} registeredAt - The timestamp when the registered entity was created.
48
48
  * @property {number} [reportedAt] - The timestamp when the registered entity was deregistered.
49
- * @property {number} fetchStart - The timestamp when the registered entity began fetching.
50
- * @property {number} fetchEnd - The timestamp when the registered entity finished fetching.
49
+ * @property {number} fetchStart - The timestamp when the registered entity began fetching (performance.start).
50
+ * @property {number} fetchEnd - The timestamp when the registered entity finished fetching (performance.end).
51
+ * @property {number} scriptStart - The timestamp when script initialization began (max of dom.start or performance.end, or performance.end if no dom.start).
52
+ * @property {number} scriptEnd - The timestamp when script loading completed (dom.end or registeredAt if no dom.end).
51
53
  * @property {Object} [asset] - The asset path (if found) for the registered entity.
52
- * @property {string} type - The type of timing associated with the registered entity, 'script' or 'link' if found with the performance resource API, 'inline' if found to be associated with the root document URL, or 'unknown' if no associated resource could be found.
54
+ * @property {string} type - The type of timing associated with the registered entity, 'script' or 'link' if found with the performance resource API, 'fetch' for dynamic imports, 'inline' if found to be associated with the root document URL, or 'unknown' if no associated resource could be found.
53
55
  */
54
56
  var _default = exports.default = {};