@newrelic/browser-agent 1.311.0-rc.1 → 1.311.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 (62) hide show
  1. package/dist/cjs/common/constants/agent-constants.js +4 -5
  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/util/script-tracker.js +2 -0
  5. package/dist/cjs/common/util/v2.js +61 -5
  6. package/dist/cjs/common/wrap/wrap-fetch.js +12 -5
  7. package/dist/cjs/common/wrap/wrap-function.js +1 -1
  8. package/dist/cjs/common/wrap/wrap-xhr.js +5 -1
  9. package/dist/cjs/features/ajax/aggregate/index.js +24 -6
  10. package/dist/cjs/features/ajax/instrument/index.js +12 -10
  11. package/dist/cjs/features/generic_events/instrument/index.js +3 -3
  12. package/dist/cjs/features/logging/instrument/index.js +1 -1
  13. package/dist/cjs/features/logging/shared/utils.js +1 -1
  14. package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +6 -3
  15. package/dist/cjs/loaders/api/register.js +21 -22
  16. package/dist/cjs/loaders/api/wrapLogger.js +1 -1
  17. package/dist/esm/common/constants/agent-constants.js +4 -5
  18. package/dist/esm/common/constants/env.cdn.js +1 -1
  19. package/dist/esm/common/constants/env.npm.js +1 -1
  20. package/dist/esm/common/util/script-tracker.js +2 -2
  21. package/dist/esm/common/util/v2.js +57 -5
  22. package/dist/esm/common/wrap/wrap-fetch.js +12 -5
  23. package/dist/esm/common/wrap/wrap-function.js +1 -1
  24. package/dist/esm/common/wrap/wrap-xhr.js +5 -1
  25. package/dist/esm/features/ajax/aggregate/index.js +24 -6
  26. package/dist/esm/features/ajax/instrument/index.js +12 -10
  27. package/dist/esm/features/generic_events/instrument/index.js +3 -3
  28. package/dist/esm/features/logging/instrument/index.js +1 -1
  29. package/dist/esm/features/logging/shared/utils.js +1 -1
  30. package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +6 -3
  31. package/dist/esm/loaders/api/register.js +21 -22
  32. package/dist/esm/loaders/api/wrapLogger.js +1 -1
  33. package/dist/types/common/constants/agent-constants.d.ts.map +1 -1
  34. package/dist/types/common/util/script-tracker.d.ts +11 -0
  35. package/dist/types/common/util/script-tracker.d.ts.map +1 -1
  36. package/dist/types/common/util/v2.d.ts +23 -0
  37. package/dist/types/common/util/v2.d.ts.map +1 -1
  38. package/dist/types/common/wrap/wrap-fetch.d.ts +1 -1
  39. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  40. package/dist/types/common/wrap/wrap-xhr.d.ts +1 -1
  41. package/dist/types/common/wrap/wrap-xhr.d.ts.map +1 -1
  42. package/dist/types/features/ajax/aggregate/index.d.ts +2 -1
  43. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  44. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  45. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +1 -0
  46. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
  47. package/dist/types/loaders/api/register.d.ts.map +1 -1
  48. package/package.json +1 -1
  49. package/src/common/constants/agent-constants.js +4 -5
  50. package/src/common/util/script-tracker.js +2 -2
  51. package/src/common/util/v2.js +57 -6
  52. package/src/common/wrap/wrap-fetch.js +14 -5
  53. package/src/common/wrap/wrap-function.js +1 -1
  54. package/src/common/wrap/wrap-xhr.js +5 -1
  55. package/src/features/ajax/aggregate/index.js +22 -6
  56. package/src/features/ajax/instrument/index.js +13 -10
  57. package/src/features/generic_events/instrument/index.js +3 -3
  58. package/src/features/logging/instrument/index.js +1 -1
  59. package/src/features/logging/shared/utils.js +1 -1
  60. package/src/features/soft_navigations/aggregate/ajax-node.js +6 -3
  61. package/src/loaders/api/register.js +18 -11
  62. package/src/loaders/api/wrapLogger.js +1 -1
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.SUPPORTS_REGISTERED_ENTITIES = exports.SESSION_ERROR = exports.MAX_PAYLOAD_SIZE = exports.IDEAL_PAYLOAD_SIZE = exports.DEFAULT_KEY = void 0;
7
7
  var _features = require("../../loaders/features/features");
8
8
  /**
9
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
9
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
10
10
  * SPDX-License-Identifier: Apache-2.0
11
11
  */
12
12
 
@@ -16,8 +16,7 @@ const DEFAULT_KEY = exports.DEFAULT_KEY = 'NR_CONTAINER_AGENT';
16
16
  const SESSION_ERROR = exports.SESSION_ERROR = 'SESSION_ERROR';
17
17
  const SUPPORTS_REGISTERED_ENTITIES = exports.SUPPORTS_REGISTERED_ENTITIES = {
18
18
  [_features.FEATURE_NAMES.logging]: true,
19
- // flip other features here when they are supported by DEM consumers
20
- [_features.FEATURE_NAMES.genericEvents]: false,
21
- [_features.FEATURE_NAMES.jserrors]: false,
22
- [_features.FEATURE_NAMES.ajax]: false
19
+ [_features.FEATURE_NAMES.genericEvents]: true,
20
+ [_features.FEATURE_NAMES.jserrors]: true,
21
+ [_features.FEATURE_NAMES.ajax]: true
23
22
  };
@@ -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.311.0-rc.1";
20
+ const VERSION = exports.VERSION = "1.311.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.311.0-rc.1";
20
+ const VERSION = exports.VERSION = "1.311.0-rc.2";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -3,7 +3,9 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.extractUrlsFromStack = extractUrlsFromStack;
6
7
  exports.findScriptTimings = findScriptTimings;
8
+ exports.getDeepStackTrace = getDeepStackTrace;
7
9
  exports.thisFile = void 0;
8
10
  var _runtime = require("../constants/runtime");
9
11
  var _now = require("../timing/now");
@@ -4,7 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.V2_TYPES = void 0;
7
+ exports.findTargetsFromStackTrace = findTargetsFromStackTrace;
8
+ exports.getRegisteredTargetsFromFilename = getRegisteredTargetsFromFilename;
9
+ exports.getRegisteredTargetsFromId = getRegisteredTargetsFromId;
7
10
  exports.getVersion2Attributes = getVersion2Attributes;
11
+ exports.getVersion2DuplicationAttributes = getVersion2DuplicationAttributes;
12
+ exports.shouldDuplicate = shouldDuplicate;
13
+ var _scriptTracker = require("./script-tracker");
8
14
  /**
9
15
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
10
16
  * SPDX-License-Identifier: Apache-2.0
@@ -21,6 +27,30 @@ const V2_TYPES = exports.V2_TYPES = {
21
27
  BA: 'BA'
22
28
  };
23
29
 
30
+ /**
31
+ * Returns the registered target associated with a given ID. Returns undefined if not found.
32
+ * @param {string|number} id
33
+ * @param {*} agentRef the agent reference
34
+ * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
35
+ */
36
+ function getRegisteredTargetsFromId(id, agentRef) {
37
+ if (!id || !agentRef?.init.api.allow_registered_children) return [];
38
+ const registeredEntities = agentRef.runtime.registeredEntities;
39
+ return registeredEntities?.filter(entity => String(entity.metadata.target.id) === String(id)).map(entity => entity.metadata.target) || [];
40
+ }
41
+
42
+ /**
43
+ * Returns the registered target(s) associated with a given filename if found in the resource timing API during registration. Returns an empty array if not found.
44
+ * @param {string} filename
45
+ * @param {*} agentRef
46
+ * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
47
+ */
48
+ function getRegisteredTargetsFromFilename(filename, agentRef) {
49
+ if (!filename || !agentRef?.init.api.allow_registered_children) return [];
50
+ const registeredEntities = agentRef.runtime.registeredEntities;
51
+ return registeredEntities?.filter(entity => entity.metadata.timings?.asset?.endsWith(filename)).map(entity => entity.metadata.target) || [];
52
+ }
53
+
24
54
  /**
25
55
  * When given a valid target, returns an object with the V2 payload attributes. Returns an empty object otherwise.
26
56
  * @note Field names may change as the schema is finalized
@@ -40,11 +70,37 @@ function getVersion2Attributes(target, aggregateInstance) {
40
70
  };
41
71
  }
42
72
  /** otherwise, the data belongs to the target (MFE) and should be attributed as such */
73
+ return target.attributes;
74
+ }
75
+
76
+ /**
77
+ * Returns the attributes used for duplicating data in version 2 of the harvest endpoint. If not valid for duplication, returns an empty object.
78
+ * @param {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget} target
79
+ * @param {*} aggregateInstance the aggregate instance calling the method
80
+ * @returns {Object}
81
+ */
82
+ function getVersion2DuplicationAttributes(target, aggregateInstance) {
83
+ if (aggregateInstance?.harvestEndpointVersion !== 2 || !shouldDuplicate(target, aggregateInstance?.agentRef)) return {};
43
84
  return {
44
- 'source.id': target.id,
45
- 'source.name': target.name,
46
- 'source.type': target.type,
47
- 'parent.id': target.parent?.id || containerAgentEntityGuid,
48
- 'parent.type': target.parent?.type || V2_TYPES.BA
85
+ 'child.id': target.id,
86
+ 'child.type': target.type,
87
+ ...getVersion2Attributes(undefined, aggregateInstance)
49
88
  };
89
+ }
90
+ function shouldDuplicate(target, agentRef) {
91
+ return !!target && agentRef.init.api.duplicate_registered_data;
92
+ }
93
+ function findTargetsFromStackTrace(agentRef) {
94
+ if (!agentRef?.init.api.allow_registered_children) return [];
95
+ const targets = [];
96
+ try {
97
+ var urls = (0, _scriptTracker.extractUrlsFromStack)((0, _scriptTracker.getDeepStackTrace)());
98
+ let iterator = urls.length - 1;
99
+ while (urls[iterator]) {
100
+ targets.push(...getRegisteredTargetsFromFilename(urls[iterator--], agentRef));
101
+ }
102
+ } catch (err) {
103
+ // Silent catch to prevent errors from propagating
104
+ }
105
+ return targets;
50
106
  }
@@ -7,6 +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
11
  /**
11
12
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
12
13
  * SPDX-License-Identifier: Apache-2.0
@@ -33,7 +34,7 @@ const wrapped = {};
33
34
  * event emitter will be based.
34
35
  * @returns {Object} Scoped event emitter with a debug ID of `fetch`.
35
36
  */
36
- function wrapFetch(sharedEE) {
37
+ function wrapFetch(sharedEE, agentRef) {
37
38
  const ee = scopedEE(sharedEE);
38
39
  if (!(Req && Res && _runtime.globalScope.fetch)) {
39
40
  return ee;
@@ -49,8 +50,10 @@ function wrapFetch(sharedEE) {
49
50
  wrapPromiseMethod(Res[proto], method, bodyPrefix);
50
51
  });
51
52
  wrapPromiseMethod(_runtime.globalScope, 'fetch', prefix);
52
- ee.on(prefix + 'end', function (err, res) {
53
+ ee.on(prefix + 'end', function (err, res, targets) {
53
54
  var ctx = this;
55
+ // undefined target reports to container
56
+ ctx.targets = targets || [undefined];
54
57
  if (res) {
55
58
  var size = res.headers.get('content-length');
56
59
  if (size !== null) {
@@ -75,7 +78,11 @@ function wrapFetch(sharedEE) {
75
78
  if (typeof fn === 'function') {
76
79
  target[name] = function () {
77
80
  var args = [...arguments];
78
- var ctx = {};
81
+ const ctx = {};
82
+ const targets = (0, _v.findTargetsFromStackTrace)(agentRef);
83
+ // undefined target reports to container
84
+ if (!targets.length) targets.push(undefined);
85
+
79
86
  // we are wrapping args in an array so we can preserve the reference
80
87
  ee.emit(prefix + 'before-start', [args], ctx);
81
88
  var dtPayload;
@@ -85,10 +92,10 @@ function wrapFetch(sharedEE) {
85
92
 
86
93
  // Note we need to cast the returned (orig) Promise from native APIs into the current global Promise, which may or may not be our WrappedPromise.
87
94
  return origPromiseFromFetch.then(function (val) {
88
- ee.emit(prefix + 'end', [null, val], origPromiseFromFetch);
95
+ ee.emit(prefix + 'end', [null, val, targets], origPromiseFromFetch);
89
96
  return val;
90
97
  }, function (err) {
91
- ee.emit(prefix + 'end', [err], origPromiseFromFetch);
98
+ ee.emit(prefix + 'end', [err, undefined, targets], origPromiseFromFetch);
92
99
  throw err;
93
100
  });
94
101
  };
@@ -9,7 +9,7 @@ exports.flag = exports.default = void 0;
9
9
  var _contextualEe = require("../event-emitter/contextual-ee");
10
10
  var _bundleId = require("../ids/bundle-id");
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
 
@@ -11,6 +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
15
  /**
15
16
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
16
17
  * SPDX-License-Identifier: Apache-2.0
@@ -31,7 +32,7 @@ const XHR_PROPS = ['open', 'send']; // these are the specific funcs being wrappe
31
32
  * @returns {Object} Scoped event emitter with a debug ID of `xhr`.
32
33
  */
33
34
  // eslint-disable-next-line
34
- function wrapXhr(sharedEE) {
35
+ function wrapXhr(sharedEE, agentRef) {
35
36
  var baseEE = sharedEE || _contextualEe.ee;
36
37
  const ee = scopedEE(baseEE);
37
38
  if (typeof _runtime.globalScope.XMLHttpRequest === 'undefined') return ee;
@@ -54,6 +55,9 @@ function wrapXhr(sharedEE) {
54
55
  function newXHR(opts) {
55
56
  const xhr = new OrigXHR(opts);
56
57
  const context = ee.context(xhr);
58
+ context.targets = (0, _v.findTargetsFromStackTrace)(agentRef);
59
+ // undefined target reports to container
60
+ if (!context.targets.length) context.targets.push(undefined);
57
61
  try {
58
62
  ee.emit('new-xhr', [xhr], context);
59
63
  xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), (0, _eventListenerOpts.eventListenerOpts)(false));
@@ -14,6 +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
18
  /**
18
19
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
19
20
  * SPDX-License-Identifier: Apache-2.0
@@ -32,9 +33,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
32
33
  super.customAttributesAreSeparate = true;
33
34
  }
34
35
  (0, _registerHandler.registerHandler)('returnAjax', event => this.events.add(event), this.featureName, this.ee);
35
- (0, _registerHandler.registerHandler)('xhr', function () {
36
+ (0, _registerHandler.registerHandler)('xhr', function (params, metrics, startTime, endTime, type, target) {
36
37
  // the EE-drain system not only switches "this" but also passes a new EventContext with info. Should consider platform refactor to another system which passes a mutable context around separately and predictably to avoid problems like this.
37
- classThis.storeXhr(...arguments, this); // this switches the context back to the class instance while passing the NR context as an argument -- see "ctx" in storeXhr
38
+ classThis.storeXhr(params, metrics, startTime, endTime, type, target, this); // this switches the context back to the class instance while passing the NR context as an argument -- see "ctx" in storeXhr
38
39
  }, this.featureName, this.ee);
39
40
  this.ee.on('long-task', (task, originator) => {
40
41
  if (originator instanceof (0, _nreum.gosNREUMOriginals)().o.XHR) {
@@ -45,7 +46,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
45
46
  });
46
47
  this.waitForFlags([]).then(() => this.drain());
47
48
  }
48
- storeXhr(params, metrics, startTime, endTime, type, ctx) {
49
+ storeXhr(params, metrics, startTime, endTime, type, target, ctx) {
49
50
  metrics.time = startTime;
50
51
 
51
52
  // send to session traces
@@ -100,12 +101,28 @@ class Aggregate extends _aggregateBase.AggregateBase {
100
101
  query: ctx.parsedOrigin?.search
101
102
  });
102
103
  if (event.gql) this.reportSupportabilityMetric('Ajax/Events/GraphQL/Bytes-Added', (0, _stringify.stringify)(event.gql).length);
104
+
105
+ /** make a copy of the event for the MFE target if it exists */
106
+ if (target) {
107
+ this.events.add({
108
+ ...event,
109
+ targetAttributes: (0, _v.getVersion2Attributes)(target, this)
110
+ });
111
+ if ((0, _v.shouldDuplicate)(target, this.agentRef)) this.reportContainerEvent({
112
+ ...event,
113
+ targetAttributes: (0, _v.getVersion2DuplicationAttributes)(target, this)
114
+ }, ctx);
115
+ } else {
116
+ this.reportContainerEvent(event, ctx);
117
+ }
118
+ }
119
+ reportContainerEvent(evt, ctx) {
103
120
  const softNavInUse = Boolean(this.agentRef.features?.[_features.FEATURE_NAMES.softNav]);
104
121
  if (softNavInUse) {
105
122
  // when SN is running, pass the event w/ info to it for evaluation -- either part of an interaction or is given back
106
- (0, _handle.handle)('ajax', [event, ctx], undefined, _features.FEATURE_NAMES.softNav, this.ee);
123
+ (0, _handle.handle)('ajax', [evt, ctx], undefined, _features.FEATURE_NAMES.softNav, this.ee);
107
124
  } else {
108
- this.events.add(event);
125
+ this.events.add(evt);
109
126
  }
110
127
  }
111
128
  serializer(eventBuffer) {
@@ -139,7 +156,8 @@ class Aggregate extends _aggregateBase.AggregateBase {
139
156
  // gql decorators are added as custom attributes to alleviate need for new BEL schema
140
157
  const attrParts = (0, _belSerializer.addCustomAttributes)({
141
158
  ...(jsAttributes || {}),
142
- ...(event.gql || {})
159
+ ...(event.gql || {}),
160
+ ...(event.targetAttributes || {}) // used to supply the version 2 attributes, either MFE target or duplication attributes for the main agent app
143
161
  }, addString);
144
162
  fields.unshift((0, _belSerializer.numeric)(attrParts.length));
145
163
  insert += fields.join(',');
@@ -23,7 +23,7 @@ var _now = require("../../../common/timing/now");
23
23
  var _denyList = require("../../../common/deny-list/deny-list");
24
24
  var _extractUrl = require("../../../common/url/extract-url");
25
25
  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); } /**
26
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
26
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
27
27
  * SPDX-License-Identifier: Apache-2.0
28
28
  */
29
29
  var handlers = ['load', 'error', 'abort', 'timeout'];
@@ -69,8 +69,8 @@ class Instrument extends _instrumentBase.InstrumentBase {
69
69
  } catch (err) {
70
70
  // do nothing
71
71
  }
72
- (0, _wrapFetch.wrapFetch)(this.ee);
73
- (0, _wrapXhr.wrapXhr)(this.ee);
72
+ (0, _wrapFetch.wrapFetch)(this.ee, agentRef);
73
+ (0, _wrapXhr.wrapXhr)(this.ee, agentRef);
74
74
  subscribeToEvents(agentRef, this.ee, this.handler, this.dt);
75
75
  this.importAggregator(agentRef, () => Promise.resolve().then(() => _interopRequireWildcard(require(/* webpackChunkName: "ajax-aggregate" */'../aggregate/index.js'))));
76
76
  }
@@ -294,12 +294,9 @@ function subscribeToEvents(agentRef, ee, handler, dt) {
294
294
  this.metrics = {};
295
295
  this.startTime = (0, _now.now)();
296
296
  this.dt = dtPayload;
297
- if (fetchArguments.length >= 1) this.target = fetchArguments[0];
298
- if (fetchArguments.length >= 2) this.opts = fetchArguments[1];
299
- var opts = this.opts || {};
300
- var target = this.target;
297
+ let [target, opts = {}] = fetchArguments;
301
298
  addUrl(this, (0, _extractUrl.extractUrl)(target));
302
- var method = ('' + (target && target instanceof origRequest && target.method || opts.method || 'GET')).toUpperCase();
299
+ const method = ('' + (target && target instanceof origRequest && target.method || opts.method || 'GET')).toUpperCase();
303
300
  this.params.method = method;
304
301
  this.body = opts.body;
305
302
  this.txSize = (0, _dataSize.dataSize)(opts.body) || 0;
@@ -324,7 +321,8 @@ function subscribeToEvents(agentRef, ee, handler, dt) {
324
321
  rxSize: responseSize,
325
322
  duration: (0, _now.now)() - this.startTime
326
323
  };
327
- handler('xhr', [this.params, metrics, this.startTime, this.endTime, 'fetch'], this, _features.FEATURE_NAMES.ajax);
324
+ const payload = [this.params, metrics, this.startTime, this.endTime, 'fetch'];
325
+ this.targets.forEach(target => reportToAgg(payload, this, target));
328
326
  }
329
327
 
330
328
  // Create report for XHR request that has finished
@@ -348,7 +346,11 @@ function subscribeToEvents(agentRef, ee, handler, dt) {
348
346
 
349
347
  // Always send cbTime, even if no noticeable time was taken.
350
348
  metrics.cbTime = this.cbTime;
351
- handler('xhr', [params, metrics, this.startTime, this.endTime, 'xhr'], this, _features.FEATURE_NAMES.ajax);
349
+ const payload = [params, metrics, this.startTime, this.endTime, 'xhr'];
350
+ this.targets.forEach(target => reportToAgg(payload, this, target));
351
+ }
352
+ function reportToAgg(payload, context, target) {
353
+ handler('xhr', [...payload, target], context, _features.FEATURE_NAMES.ajax);
352
354
  }
353
355
  function captureXhrData(ctx, xhr) {
354
356
  ctx.params.status = xhr.status;
@@ -23,7 +23,7 @@ var _parseUrl = require("../../../common/url/parse-url");
23
23
  var _extractUrl = require("../../../common/url/extract-url");
24
24
  var _wrapWebsocket = require("../../../common/wrap/wrap-websocket");
25
25
  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); } /**
26
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
26
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
27
27
  * SPDX-License-Identifier: Apache-2.0
28
28
  */
29
29
  class Instrument extends _instrumentBase.InstrumentBase {
@@ -44,8 +44,8 @@ class Instrument extends _instrumentBase.InstrumentBase {
44
44
  let historyEE, websocketsEE;
45
45
  if (websocketsEnabled) websocketsEE = (0, _wrapWebsocket.wrapWebSocket)(this.ee);
46
46
  if (_runtime.isBrowserScope) {
47
- (0, _wrapFetch.wrapFetch)(this.ee);
48
- (0, _wrapXhr.wrapXhr)(this.ee);
47
+ (0, _wrapFetch.wrapFetch)(this.ee, agentRef);
48
+ (0, _wrapXhr.wrapXhr)(this.ee, agentRef);
49
49
  historyEE = (0, _wrapHistory.wrapHistory)(this.ee);
50
50
  if (agentRef.init.user_actions.enabled) {
51
51
  _constants.OBSERVED_EVENTS.forEach(eventType => (0, _eventListenerOpts.windowAddEventListener)(eventType, evt => (0, _handle.handle)('ua', [evt], undefined, this.featureName, this.ee), true));
@@ -14,7 +14,7 @@ var _wrapLogger2 = require("../../../loaders/api/wrapLogger");
14
14
  var _register = require("../../../loaders/api/register");
15
15
  var _monkeyPatched = require("../../../common/util/monkey-patched");
16
16
  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); } /**
17
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
17
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
18
18
  * SPDX-License-Identifier: Apache-2.0
19
19
  */
20
20
  class Instrument extends _instrumentBase.InstrumentBase {
@@ -11,7 +11,7 @@ var _features = require("../../../loaders/features/features");
11
11
  var _constants = require("../../metrics/constants");
12
12
  var _constants2 = require("../constants");
13
13
  /**
14
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
14
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
@@ -8,7 +8,7 @@ var _belSerializer = require("../../../common/serialize/bel-serializer");
8
8
  var _constants = require("../constants");
9
9
  var _belNode = require("./bel-node");
10
10
  /**
11
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
11
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
12
12
  * SPDX-License-Identifier: Apache-2.0
13
13
  */
14
14
 
@@ -27,6 +27,7 @@ class AjaxNode extends _belNode.BelNode {
27
27
  this.traceId = ajaxEvent.traceId;
28
28
  this.spanTimestamp = ajaxEvent.spanTimestamp;
29
29
  this.gql = ajaxEvent.gql;
30
+ this.targetAttributes = ajaxEvent.targetAttributes;
30
31
  this.start = ajaxEvent.startTime;
31
32
  this.end = ajaxEvent.endTime;
32
33
  if (ajaxContext?.latestLongtaskEnd) {
@@ -50,8 +51,10 @@ class AjaxNode extends _belNode.BelNode {
50
51
  (0, _belSerializer.numeric)(this.callbackDuration),
51
52
  // not relative
52
53
  addString(this.method), (0, _belSerializer.numeric)(this.status), addString(this.domain), addString(this.path), (0, _belSerializer.numeric)(this.txSize), (0, _belSerializer.numeric)(this.rxSize), this.requestedWith, addString(this.nodeId), (0, _belSerializer.nullable)(this.spanId, addString, true) + (0, _belSerializer.nullable)(this.traceId, addString, true) + (0, _belSerializer.nullable)(this.spanTimestamp, _belSerializer.numeric)];
53
- let allAttachedNodes = [];
54
- if (typeof this.gql === 'object') allAttachedNodes = (0, _belSerializer.addCustomAttributes)(this.gql, addString);
54
+ let allAttachedNodes = (0, _belSerializer.addCustomAttributes)({
55
+ ...(this.gql || {}),
56
+ ...(this.targetAttributes || {})
57
+ }, addString);
55
58
  this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
56
59
 
57
60
  fields[1] = (0, _belSerializer.numeric)(allAttachedNodes.length);
@@ -20,6 +20,7 @@ var _measure = require("./measure");
20
20
  var _recordCustomEvent = require("./recordCustomEvent");
21
21
  var _pageVisibility = require("../../common/window/page-visibility");
22
22
  var _scriptTracker = require("../../common/util/script-tracker");
23
+ var _uniqueId = require("../../common/ids/unique-id");
23
24
  /**
24
25
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
25
26
  * SPDX-License-Identifier: Apache-2.0
@@ -53,13 +54,32 @@ function setupRegisterAPI(agent) {
53
54
  function register(agentRef, target, parent) {
54
55
  (0, _console.warn)(54, 'newrelic.register');
55
56
  target ||= {};
57
+ target.instance = (0, _uniqueId.generateRandomHexString)(8);
56
58
  target.type = _v.V2_TYPES.MFE;
57
59
  target.licenseKey ||= agentRef.info.licenseKey; // will inherit the license key from the container agent if not provided for brevity. A future state may dictate that we need different license keys to do different things.
58
60
  target.blocked = false;
59
- target.parent = parent || {};
60
61
  if (typeof target.tags !== 'object' || target.tags === null || Array.isArray(target.tags)) target.tags = {};
62
+ target.parent = parent || {
63
+ get id() {
64
+ return agentRef.runtime.appMetadata.agents[0].entityGuid;
65
+ },
66
+ // getter because this is asyncronously set
67
+ type: _v.V2_TYPES.BA
68
+ };
61
69
  const timings = (0, _scriptTracker.findScriptTimings)();
62
70
  const attrs = {};
71
+ Object.defineProperty(target, 'attributes', {
72
+ get() {
73
+ return {
74
+ ...attrs,
75
+ 'source.id': target.id,
76
+ 'source.name': target.name,
77
+ 'source.type': target.type,
78
+ 'parent.type': target.parent?.type || _v.V2_TYPES.BA,
79
+ 'parent.id': target.parent?.id
80
+ };
81
+ }
82
+ });
63
83
 
64
84
  // Process tags object and add to attrs, excluding protected keys
65
85
  Object.entries(target.tags).forEach(([key, value]) => {
@@ -213,27 +233,6 @@ function register(agentRef, target, parent) {
213
233
  const timestamp = (0, _now.now)();
214
234
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/register/".concat(methodToCall.name, "/called")], undefined, _features.FEATURE_NAMES.metrics, agentRef.ee);
215
235
  try {
216
- const shouldDuplicate = agentRef.init.api.duplicate_registered_data && methodToCall !== register;
217
- if (shouldDuplicate) {
218
- let duplicatedArgs = args;
219
- if (args[1] instanceof Object) {
220
- const childAttrs = {
221
- 'child.id': target.id,
222
- 'child.type': target.type
223
- };
224
- if ('customAttributes' in args[1]) duplicatedArgs = [args[0], {
225
- ...args[1],
226
- customAttributes: {
227
- ...args[1].customAttributes,
228
- ...childAttrs
229
- }
230
- }, ...args.slice(2)];else duplicatedArgs = [args[0], {
231
- ...args[1],
232
- ...childAttrs
233
- }, ...args.slice(2)];
234
- }
235
- methodToCall(...duplicatedArgs, undefined, timestamp);
236
- }
237
236
  return methodToCall(...args, target, timestamp); // always report to target
238
237
  } catch (err) {
239
238
  (0, _console.warn)(50, err);
@@ -9,7 +9,7 @@ var _constants = require("../../features/logging/constants");
9
9
  var _constants2 = require("./constants");
10
10
  var _sharedHandlers = require("./sharedHandlers");
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
 
@@ -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 { FEATURE_NAMES } from '../../loaders/features/features';
@@ -9,8 +9,7 @@ export const DEFAULT_KEY = 'NR_CONTAINER_AGENT';
9
9
  export const SESSION_ERROR = 'SESSION_ERROR';
10
10
  export const SUPPORTS_REGISTERED_ENTITIES = {
11
11
  [FEATURE_NAMES.logging]: true,
12
- // flip other features here when they are supported by DEM consumers
13
- [FEATURE_NAMES.genericEvents]: false,
14
- [FEATURE_NAMES.jserrors]: false,
15
- [FEATURE_NAMES.ajax]: false
12
+ [FEATURE_NAMES.genericEvents]: true,
13
+ [FEATURE_NAMES.jserrors]: true,
14
+ [FEATURE_NAMES.ajax]: true
16
15
  };
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.311.0-rc.1";
14
+ export const VERSION = "1.311.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.311.0-rc.1";
14
+ export const VERSION = "1.311.0-rc.2";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -59,7 +59,7 @@ if (globalScope.PerformanceObserver?.supportedEntryTypes.includes('resource')) {
59
59
  * @param {string} stack The error stack trace
60
60
  * @returns {string[]} Array of cleaned URLs found in the stack trace
61
61
  */
62
- function extractUrlsFromStack(stack) {
62
+ export function extractUrlsFromStack(stack) {
63
63
  if (!stack || typeof stack !== 'string') return [];
64
64
  const urls = new Set();
65
65
  const lines = stack.split('\n');
@@ -83,7 +83,7 @@ function extractUrlsFromStack(stack) {
83
83
  * Returns a deep stack trace by temporarily increasing the stack trace limit.
84
84
  * @returns {Error.stack | undefined}
85
85
  */
86
- function getDeepStackTrace() {
86
+ export function getDeepStackTrace() {
87
87
  let stack;
88
88
  try {
89
89
  const originalStackLimit = Error.stackTraceLimit;
@@ -3,6 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
+ import { extractUrlsFromStack, getDeepStackTrace } from './script-tracker';
7
+
6
8
  /**
7
9
  * @enum {string}
8
10
  * @readonly
@@ -14,6 +16,30 @@ export const V2_TYPES = {
14
16
  BA: 'BA'
15
17
  };
16
18
 
19
+ /**
20
+ * Returns the registered target associated with a given ID. Returns undefined if not found.
21
+ * @param {string|number} id
22
+ * @param {*} agentRef the agent reference
23
+ * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
24
+ */
25
+ export function getRegisteredTargetsFromId(id, agentRef) {
26
+ if (!id || !agentRef?.init.api.allow_registered_children) return [];
27
+ const registeredEntities = agentRef.runtime.registeredEntities;
28
+ return registeredEntities?.filter(entity => String(entity.metadata.target.id) === String(id)).map(entity => entity.metadata.target) || [];
29
+ }
30
+
31
+ /**
32
+ * Returns the registered target(s) associated with a given filename if found in the resource timing API during registration. Returns an empty array if not found.
33
+ * @param {string} filename
34
+ * @param {*} agentRef
35
+ * @returns {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget[]}
36
+ */
37
+ export function getRegisteredTargetsFromFilename(filename, agentRef) {
38
+ if (!filename || !agentRef?.init.api.allow_registered_children) return [];
39
+ const registeredEntities = agentRef.runtime.registeredEntities;
40
+ return registeredEntities?.filter(entity => entity.metadata.timings?.asset?.endsWith(filename)).map(entity => entity.metadata.target) || [];
41
+ }
42
+
17
43
  /**
18
44
  * When given a valid target, returns an object with the V2 payload attributes. Returns an empty object otherwise.
19
45
  * @note Field names may change as the schema is finalized
@@ -33,11 +59,37 @@ export function getVersion2Attributes(target, aggregateInstance) {
33
59
  };
34
60
  }
35
61
  /** otherwise, the data belongs to the target (MFE) and should be attributed as such */
62
+ return target.attributes;
63
+ }
64
+
65
+ /**
66
+ * Returns the attributes used for duplicating data in version 2 of the harvest endpoint. If not valid for duplication, returns an empty object.
67
+ * @param {import("../../interfaces/registered-entity").RegisterAPIMetadataTarget} target
68
+ * @param {*} aggregateInstance the aggregate instance calling the method
69
+ * @returns {Object}
70
+ */
71
+ export function getVersion2DuplicationAttributes(target, aggregateInstance) {
72
+ if (aggregateInstance?.harvestEndpointVersion !== 2 || !shouldDuplicate(target, aggregateInstance?.agentRef)) return {};
36
73
  return {
37
- 'source.id': target.id,
38
- 'source.name': target.name,
39
- 'source.type': target.type,
40
- 'parent.id': target.parent?.id || containerAgentEntityGuid,
41
- 'parent.type': target.parent?.type || V2_TYPES.BA
74
+ 'child.id': target.id,
75
+ 'child.type': target.type,
76
+ ...getVersion2Attributes(undefined, aggregateInstance)
42
77
  };
78
+ }
79
+ export function shouldDuplicate(target, agentRef) {
80
+ return !!target && agentRef.init.api.duplicate_registered_data;
81
+ }
82
+ export function findTargetsFromStackTrace(agentRef) {
83
+ if (!agentRef?.init.api.allow_registered_children) return [];
84
+ const targets = [];
85
+ try {
86
+ var urls = extractUrlsFromStack(getDeepStackTrace());
87
+ let iterator = urls.length - 1;
88
+ while (urls[iterator]) {
89
+ targets.push(...getRegisteredTargetsFromFilename(urls[iterator--], agentRef));
90
+ }
91
+ } catch (err) {
92
+ // Silent catch to prevent errors from propagating
93
+ }
94
+ return targets;
43
95
  }