@newrelic/browser-agent 1.312.1 → 1.313.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 +1 -1
  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
@@ -13,7 +13,6 @@ exports.default = void 0;
13
13
  * @property {(name: string, attributes?: object) => void} addPageAction - Add a page action for the registered entity.
14
14
  * @property {(message: string, options?: { customAttributes?: object, level?: 'ERROR' | 'TRACE' | 'DEBUG' | 'INFO' | 'WARN'}) => void} log - Capture a log for the registered entity.
15
15
  * @property {(error: Error | string, customAttributes?: object) => void} noticeError - Notice an error for the registered entity.
16
- * @property {(target: RegisterAPIConstructor) => RegisterAPI} register - Record a custom event for the registered entity.
17
16
  * @property {() => void} deregister - Deregister the registered entity, which blocks its use and captures end of life timings.
18
17
  * @property {(eventType: string, attributes?: Object) => void} recordCustomEvent - Record a custom event for the registered entity.
19
18
  * @property {(eventType: string, options?: {start?: number|PerformanceMark, end?: number|PerformanceMark, customAttributes?: object}) => ({start: number, end: number, duration: number, customAttributes: object})} measure - Measures a task that is recorded as a BrowserPerformance event.
@@ -27,14 +26,14 @@ exports.default = void 0;
27
26
  * @property {string} id - The unique id for the registered entity. This will be assigned to any synthesized entities.
28
27
  * @property {string} name - The readable name for the registered entity. This will be assigned to any synthesized entities.
29
28
  * @property {{[key: string]: any}} [tags] - The tags for the registered entity as key-value pairs. This will be assigned to any synthesized entities. Tags are converted to source.* attributes (e.g., {environment: 'production'} becomes source.environment: 'production').
30
- * @property {boolean} [isolated] - When true, each registration creates an isolated instance. When false, multiple registrations with the same id and isolated: false will share a single instance, including all custom attributes, ids, names, and metadata. Calling deregister on a shared instance will deregister it for all entities using the instance. Defaults to true.
29
+ * @property {RegisterAPITarget} [parent] - The parent target for the registered entity. If none was supplied, it will assume the entity guid from the main agent.
31
30
  * @property {string} [parentId] - The parentId for the registered entity. If none was supplied, it will assume the entity guid from the main agent.
32
31
  */
33
32
  /**
34
33
  * @typedef {Object} RegisterAPIMetadata
35
34
  * @property {Object} customAttributes - The custom attributes for the registered entity.
36
- * @property {RegisterAPITimings} timings - The timing metrics for the registered entity.
37
- * @property {RegisterAPITarget} target - The options for the registered entity.
35
+ * @property {Partial<RegisterAPITimings>} timings - The timing metrics for the registered entity.
36
+ * @property {Partial<RegisterAPITarget>} target - The options for the registered entity.
38
37
  */
39
38
  /**
40
39
  * @typedef {Object} RegisterAPITarget
@@ -42,15 +41,16 @@ exports.default = void 0;
42
41
  * @property {string} name - The name returned for the registered entity.
43
42
  * @property {{[key: string]: any}} [tags] - The tags for the registered entity as key-value pairs.
44
43
  * @property {string} [parentId] - The parentId for the registered entity. If none was supplied, it will assume the entity guid from the main agent.
45
- * @property {boolean} [isolated] - When true, each registration creates an isolated instance. When false, multiple registrations with the same id and isolated: false will share a single instance, including all custom attributes, ids, names, and metadata. Calling deregister on a shared instance will deregister it for all entities using the instance. Defaults to true.
46
44
  */
47
45
  /**
48
46
  * @typedef {Object} RegisterAPITimings
49
47
  * @property {number} registeredAt - The timestamp when the registered entity was created.
50
48
  * @property {number} [reportedAt] - The timestamp when the registered entity was deregistered.
51
- * @property {number} fetchStart - The timestamp when the registered entity began fetching.
52
- * @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).
53
53
  * @property {Object} [asset] - The asset path (if found) for the registered entity.
54
- * @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.
55
55
  */
56
56
  var _default = exports.default = {};
@@ -4,9 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.setupRegisterAPI = setupRegisterAPI;
7
+ exports.warnings = void 0;
7
8
  var _handle = require("../../common/event-emitter/handle");
8
9
  var _console = require("../../common/util/console");
9
- var _v = require("../../common/util/v2");
10
+ var _utils = require("../../common/v2/utils");
10
11
  var _features = require("../features/features");
11
12
  var _now = require("../../common/timing/now");
12
13
  var _constants = require("../../features/metrics/constants");
@@ -19,7 +20,7 @@ var _invoke = require("../../common/util/invoke");
19
20
  var _measure = require("./measure");
20
21
  var _recordCustomEvent = require("./recordCustomEvent");
21
22
  var _pageVisibility = require("../../common/window/page-visibility");
22
- var _scriptTracker = require("../../common/util/script-tracker");
23
+ var _scriptTracker = require("../../common/v2/script-tracker");
23
24
  var _uniqueId = require("../../common/ids/unique-id");
24
25
  /**
25
26
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
@@ -32,6 +33,17 @@ var _uniqueId = require("../../common/ids/unique-id");
32
33
 
33
34
  const PROTECTED_KEYS = ['name', 'id', 'type'];
34
35
 
36
+ /**
37
+ * Warning functions that only fire once - can be reset in tests
38
+ * @private
39
+ */
40
+ const warnings = exports.warnings = {
41
+ experimental: (0, _invoke.single)(() => (0, _console.warn)(54, 'newrelic.register')),
42
+ disabled: (0, _invoke.single)(() => (0, _console.warn)(55)),
43
+ invalidTarget: (0, _invoke.single)(target => (0, _console.warn)(48, target)),
44
+ deregistered: (0, _invoke.single)(() => (0, _console.warn)(68))
45
+ };
46
+
35
47
  /**
36
48
  * @experimental
37
49
  * IMPORTANT: This feature is being developed for use internally and is not in a public-facing production-ready state.
@@ -48,38 +60,41 @@ function setupRegisterAPI(agent) {
48
60
  * Also conducts certain side-effects, such as harvesting a PageView event when triggered and gathering metadata for the registered entity.
49
61
  * @param {Object} agentRef the reference to the base agent instance
50
62
  * @param {import('./register-api-types').RegisterAPIConstructor} target
51
- * @param {import('./register-api-types').RegisterAPIConstructor} [parent]
52
63
  * @returns {RegisterAPI} the api object to be returned from the register api method
53
64
  */
54
- function register(agentRef, target, parent) {
55
- (0, _console.warn)(54, 'newrelic.register');
65
+ function register(agentRef, target) {
66
+ warnings.experimental();
56
67
  target ||= {};
57
68
  target.instance = (0, _uniqueId.generateRandomHexString)(8);
58
- target.type = _v.V2_TYPES.MFE;
69
+ target.type = _utils.V2_TYPES.MFE;
59
70
  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.
60
71
  target.blocked = false;
61
72
  if (typeof target.tags !== 'object' || target.tags === null || Array.isArray(target.tags)) target.tags = {};
62
- target.parent = parent || {
73
+ target.parent ??= {
63
74
  get id() {
64
75
  return agentRef.runtime.appMetadata.agents[0].entityGuid;
65
76
  },
66
77
  // getter because this is asyncronously set
67
- type: _v.V2_TYPES.BA
78
+ type: _utils.V2_TYPES.BA
68
79
  };
69
80
  const timings = (0, _scriptTracker.findScriptTimings)();
70
81
  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
- });
82
+
83
+ // Only define attributes getter if it doesn't already exist
84
+ if (!Object.prototype.hasOwnProperty.call(target, 'attributes')) {
85
+ Object.defineProperty(target, 'attributes', {
86
+ get() {
87
+ return {
88
+ ...attrs,
89
+ 'source.id': target.id,
90
+ 'source.name': target.name,
91
+ 'source.type': target.type,
92
+ 'parent.type': target.parent?.type || _utils.V2_TYPES.BA,
93
+ 'parent.id': target.parent?.id
94
+ };
95
+ }
96
+ });
97
+ }
83
98
 
84
99
  // Process tags object and add to attrs, excluding protected keys
85
100
  Object.entries(target.tags).forEach(([key, value]) => {
@@ -87,23 +102,11 @@ function register(agentRef, target, parent) {
87
102
  attrs["source.".concat(key)] = value;
88
103
  }
89
104
  });
90
- target.isolated ??= true;
91
105
 
92
106
  /** @type {Function} a function that is set and reports when APIs are triggered -- warns the customer of the invalid state */
93
107
  let invalidApiResponse = () => {};
94
108
  /** @type {Array} the array of registered target APIs */
95
109
  const registeredEntities = agentRef.runtime.registeredEntities;
96
- if (!target.isolated) {
97
- /** if we have already registered this non-isolated target, go ahead and re-use it */
98
- const sharedEntity = registeredEntities.find(({
99
- metadata: {
100
- target: {
101
- id
102
- }
103
- }
104
- }) => id === target.id && !target.isolated);
105
- if (sharedEntity) return sharedEntity;
106
- }
107
110
 
108
111
  /**
109
112
  * Block the API, and supply a warning function to display a message to end users
@@ -118,8 +121,8 @@ function register(agentRef, target, parent) {
118
121
  }
119
122
 
120
123
  /** primary cases that can block the register API from working at init time */
121
- if (!agentRef.init.api.allow_registered_children) block((0, _invoke.single)(() => (0, _console.warn)(55)));
122
- if (!hasValidValue(target.id) || !hasValidValue(target.name)) block((0, _invoke.single)(() => (0, _console.warn)(48, target)));
124
+ if (!agentRef.init.api.register.enabled) block(warnings.disabled);
125
+ if (!hasValidValue(target.id) || !hasValidValue(target.name)) block(() => warnings.invalidTarget(target));
123
126
 
124
127
  /** @type {RegisterAPI} */
125
128
  const api = {
@@ -130,7 +133,7 @@ function register(agentRef, target, parent) {
130
133
  deregister: () => {
131
134
  /** note: blocking this instance will disable access for all entities sharing the instance, and will invalidate it from the v2 checks */
132
135
  reportTimings();
133
- block((0, _invoke.single)(() => (0, _console.warn)(68)));
136
+ block(warnings.deregistered);
134
137
  },
135
138
  log: (message, options = {}) => report(_log.log, [message, {
136
139
  ...options,
@@ -150,7 +153,6 @@ function register(agentRef, target, parent) {
150
153
  ...attrs,
151
154
  ...attributes
152
155
  }, agentRef], target),
153
- register: (target = {}) => report(register, [agentRef, target], api.metadata.target),
154
156
  recordCustomEvent: (eventType, attributes = {}) => report(_recordCustomEvent.recordCustomEvent, [eventType, {
155
157
  ...attrs,
156
158
  ...attributes
@@ -192,20 +194,24 @@ function register(agentRef, target, parent) {
192
194
  // only ever report the timings the first time this is called
193
195
  if (timings.reportedAt) return;
194
196
  timings.reportedAt = (0, _now.now)();
197
+ const timeToFetch = timings.fetchEnd - timings.fetchStart; // fetchStart to fetchEnd
198
+ const timeToExecute = timings.scriptEnd - timings.scriptStart; // scriptStart to scriptEnd
195
199
  api.recordCustomEvent('MicroFrontEndTiming', {
196
200
  assetUrl: timings.asset,
197
201
  // the url of the script that was registered, or undefined if it could not be determined (inline or no match)
198
202
  assetType: timings.type,
199
203
  // the type of asset that was associated with the timings, one of 'script', 'link' (if preloaded and found in the resource timing buffer), 'preload' (if preloaded but not found in the resource timing buffer), or "unknown" if it could not be determined
200
- timeToLoad: timings.registeredAt - timings.fetchStart,
201
- // fetchStart to registeredAt
204
+ timeAlive: timings.reportedAt - timings.registeredAt,
205
+ // registeredAt to reportedAt
202
206
  timeToBeRequested: timings.fetchStart,
203
207
  // origin to fetchStart
204
- timeToFetch: timings.fetchEnd - timings.fetchStart,
208
+ timeToExecute,
209
+ // scriptStart to scriptEnd
210
+ timeToFetch,
205
211
  // fetchStart to fetchEnd
206
- timeToRegister: timings.registeredAt - timings.fetchEnd,
207
- // fetchEnd to registeredAt
208
- timeAlive: timings.reportedAt - timings.registeredAt // registeredAt to reportedAt
212
+ timeToLoad: timeToFetch + timeToExecute,
213
+ // fetch time and script time together
214
+ timeToRegister: timings.registeredAt // timestamp when register() was called
209
215
  });
210
216
  }
211
217
 
@@ -222,7 +228,7 @@ function register(agentRef, target, parent) {
222
228
 
223
229
  /**
224
230
  * The reporter method that will be used to report the data to the container agent's API method. If invalid, will log a warning and not execute.
225
- * If the api.duplicate_registered_data configuration value is set to true, the data will be reported to BOTH the container and the external target
231
+ * If the api.register.duplicate_data_to_container configuration value is set to true, the data will be reported to BOTH the container and the external target
226
232
  * @param {*} methodToCall the container agent's API method to call
227
233
  * @param {*} args the arguments to supply to the container agent's API method
228
234
  * @param {string} target the target to report the data to. If undefined, will report to the container agent's target.
@@ -12,8 +12,9 @@
12
12
  * @property {boolean} [ajax.enabled] - Turn on/off the ajax feature (on by default).
13
13
  * @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.
14
14
  * @property {Object} [api]
15
- * @property {boolean} [api.allow_registered_children] - If true, the agent will allow registered children to be sent to the server.
16
- * @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.
15
+ * @property {Object} [api.register]
16
+ * @property {boolean} [api.register.enabled] - If true, the agent will allow registered children to be sent to the server.
17
+ * @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.
17
18
  * @property {Object} [distributed_tracing]
18
19
  * @property {boolean} [distributed_tracing.enabled] - If true, distributed tracing headers will be added to outgoing requests. Requires ajax feature to be running.
19
20
  * @property {boolean} [distributed_tracing.exclude_newrelic_header]
@@ -21,7 +21,7 @@ const InitModelFn = () => {
21
21
  const hiddenState = {
22
22
  feature_flags: [],
23
23
  experimental: {
24
- allow_registered_children: false,
24
+ register: false,
25
25
  resources: false
26
26
  },
27
27
  mask_selector: '*',
@@ -54,13 +54,15 @@ const InitModelFn = () => {
54
54
  autoStart: true
55
55
  },
56
56
  api: {
57
- get allow_registered_children() {
58
- return hiddenState.feature_flags.includes(FEATURE_FLAGS.REGISTER) || hiddenState.experimental.allow_registered_children;
59
- },
60
- set allow_registered_children(val) {
61
- hiddenState.experimental.allow_registered_children = val;
62
- },
63
- duplicate_registered_data: false
57
+ register: {
58
+ get enabled() {
59
+ return hiddenState.feature_flags.includes(FEATURE_FLAGS.REGISTER) || hiddenState.experimental.register;
60
+ },
61
+ set enabled(val) {
62
+ hiddenState.experimental.register = val;
63
+ },
64
+ duplicate_data_to_container: false
65
+ }
64
66
  },
65
67
  browser_consent_mode: {
66
68
  enabled: false
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.312.1";
14
+ export const VERSION = "1.313.0";
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.312.1";
14
+ export const VERSION = "1.313.0";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -1,9 +1,12 @@
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
+ import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';
5
6
  import { originTime } from '../constants/runtime';
6
7
  import { isNative } from '../util/monkey-patched';
8
+ import { handle } from '../event-emitter/handle';
9
+ import { FEATURE_NAMES } from '../../loaders/features/features';
7
10
 
8
11
  /**
9
12
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
@@ -36,11 +39,31 @@ export class TimeKeeper {
36
39
  * @type {boolean}
37
40
  */
38
41
  #ready = false;
42
+ #reportedDrift = false;
39
43
  constructor(sessionObj) {
40
44
  this.#session = sessionObj;
41
45
  this.processStoredDiff();
42
46
  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.
43
47
  }
48
+ #detectDrift() {
49
+ if (this.#reportedDrift) return;
50
+ try {
51
+ // Drift detection: measures if performance.now() and Date.now() have become desynchronized
52
+ // This can happen when a machine sleeps and the performance timer freezes while Date continues
53
+ // this can also happen when a user sets their clock forward during the page lifecycle,
54
+ // but we have no way of distinguishing that from actual clock drift so we will just treat it as drift.
55
+ // In either case, the performance timestamps would be inaccurate at that point so we want to detect and report a count of it.
56
+ // We only detect positive drift (performance clock falling behind Date clock)
57
+ // Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
58
+ const drift = Date.now() - originTime - performance.now();
59
+ if (drift > 1000) {
60
+ this.#reportedDrift = true;
61
+ handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee);
62
+ }
63
+ } catch (err) {
64
+ // Silently ignore drift detection errors to avoid breaking normal operation
65
+ }
66
+ }
44
67
  get ready() {
45
68
  return this.#ready;
46
69
  }
@@ -85,6 +108,7 @@ export class TimeKeeper {
85
108
  * @returns {number} Corrected unix/epoch timestamp
86
109
  */
87
110
  convertRelativeTimestamp(relativeTime) {
111
+ this.#detectDrift();
88
112
  return originTime + relativeTime;
89
113
  }
90
114
 
@@ -95,6 +119,7 @@ export class TimeKeeper {
95
119
  * @returns {number}
96
120
  */
97
121
  convertAbsoluteTimestamp(timestamp) {
122
+ this.#detectDrift();
98
123
  return timestamp - originTime;
99
124
  }
100
125
 
@@ -104,6 +129,7 @@ export class TimeKeeper {
104
129
  * @return {number} Corrected unix/epoch timestamp
105
130
  */
106
131
  correctAbsoluteTimestamp(timestamp) {
132
+ this.#detectDrift();
107
133
  return timestamp - this.#localTimeDiff;
108
134
  }
109
135
 
@@ -113,6 +139,7 @@ export class TimeKeeper {
113
139
  * @returns {number}
114
140
  */
115
141
  correctRelativeTimestamp(relativeTime) {
142
+ this.#detectDrift();
116
143
  return this.correctAbsoluteTimestamp(this.convertRelativeTimestamp(relativeTime));
117
144
  }
118
145
 
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /** A special error used to short-circuit the error processing pipeline */
6
+ export class ShortCircuit extends Error {}
@@ -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
 
@@ -62,8 +62,7 @@ export function xhrFetch({
62
62
  return fetch(url, {
63
63
  headers: objHeaders,
64
64
  method,
65
- body,
66
- credentials: 'include'
65
+ body
67
66
  });
68
67
  }
69
68
 
@@ -89,12 +88,6 @@ export function xhr({
89
88
  }) {
90
89
  const request = new XMLHttpRequest();
91
90
  request.open(method, url, !sync);
92
- try {
93
- // Set cookie
94
- if ('withCredentials' in request) request.withCredentials = true;
95
- } catch (e) {
96
- // do nothing
97
- }
98
91
  headers.forEach(header => {
99
92
  request.setRequestHeader(header.key, header.value);
100
93
  });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /**
6
+ * Represents script correlation data combining DOM and Performance API information
7
+ */
8
+ export class ScriptCorrelation {
9
+ /** @type {CorrelationTiming} [dom] - DOM-related information */
10
+ dom = new CorrelationTiming();
11
+ /** @type {CorrelationTiming} [performance] - Performance-related information */
12
+ performance = new CorrelationTiming();
13
+
14
+ /**
15
+ * Creates a new ScriptCorrelation instance
16
+ * @param {string} url - The cleaned URL of the script
17
+ */
18
+ constructor(url) {
19
+ /** @type {string} The cleaned URL of the script */
20
+ this.url = url;
21
+ }
22
+
23
+ /**
24
+ * 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.
25
+ * @returns {{start: number, end: number}
26
+ */
27
+ get script() {
28
+ const start = Math.max(this.dom.start, this.performance.end);
29
+ const end = Math.max(this.dom.end, this.performance.end, start);
30
+ return {
31
+ start,
32
+ end
33
+ };
34
+ }
35
+ }
36
+ class CorrelationTiming {
37
+ /** @type {number} [start] - The startTime from the performance entry */
38
+ start = 0;
39
+ /** @type {number} [end] - The responseEnd from the performance entry */
40
+ end = 0;
41
+ /** @type {*} [value] - The entry value */
42
+ value = undefined;
43
+ }