@newrelic/browser-agent 1.316.0 → 1.317.0-rc.1

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 (170) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/common/config/configurable.js +1 -1
  3. package/dist/cjs/common/config/init-types.js +1 -0
  4. package/dist/cjs/common/config/init.js +6 -4
  5. package/dist/cjs/common/constants/env.cdn.js +2 -2
  6. package/dist/cjs/common/constants/env.npm.js +2 -2
  7. package/dist/cjs/common/constants/events.js +26 -0
  8. package/dist/cjs/common/harvest/harvester.js +9 -217
  9. package/dist/cjs/common/harvest/send.js +232 -0
  10. package/dist/cjs/common/harvest/types.js +9 -5
  11. package/dist/cjs/common/payloads/payloads.js +127 -0
  12. package/dist/cjs/common/serialize/bel-serializer.js +4 -3
  13. package/dist/cjs/common/session/session-entity.js +8 -8
  14. package/dist/cjs/common/util/data-size.js +2 -2
  15. package/dist/cjs/common/util/obfuscate.js +147 -3
  16. package/dist/cjs/common/v2/mfe-vitals.js +286 -0
  17. package/dist/cjs/common/wrap/wrap-websocket.js +2 -1
  18. package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
  19. package/dist/cjs/features/ajax/aggregate/gql.js +40 -1
  20. package/dist/cjs/features/ajax/aggregate/index.js +51 -13
  21. package/dist/cjs/features/ajax/constants.js +6 -1
  22. package/dist/cjs/features/ajax/instrument/index.js +105 -17
  23. package/dist/cjs/features/generic_events/aggregate/index.js +15 -10
  24. package/dist/cjs/features/generic_events/constants.js +3 -2
  25. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.js +2 -2
  26. package/dist/cjs/features/jserrors/aggregate/index.js +12 -3
  27. package/dist/cjs/features/logging/aggregate/index.js +12 -8
  28. package/dist/cjs/features/metrics/aggregate/index.js +5 -1
  29. package/dist/cjs/features/page_view_event/aggregate/index.js +72 -33
  30. package/dist/cjs/features/page_view_timing/aggregate/index.js +6 -1
  31. package/dist/cjs/features/session_replay/aggregate/index.js +39 -29
  32. package/dist/cjs/features/session_trace/aggregate/index.js +35 -29
  33. package/dist/cjs/features/session_trace/constants.js +17 -3
  34. package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +36 -5
  35. package/dist/cjs/features/soft_navigations/aggregate/index.js +7 -1
  36. package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  37. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +6 -4
  38. package/dist/cjs/features/utils/aggregate-base.js +4 -3
  39. package/dist/cjs/loaders/api/register.js +26 -4
  40. package/dist/esm/common/config/configurable.js +1 -1
  41. package/dist/esm/common/config/init-types.js +1 -0
  42. package/dist/esm/common/config/init.js +3 -1
  43. package/dist/esm/common/constants/env.cdn.js +2 -2
  44. package/dist/esm/common/constants/env.npm.js +2 -2
  45. package/dist/esm/common/constants/events.js +20 -0
  46. package/dist/esm/common/harvest/harvester.js +9 -217
  47. package/dist/esm/common/harvest/send.js +226 -0
  48. package/dist/esm/common/harvest/types.js +9 -5
  49. package/dist/esm/common/payloads/payloads.js +118 -0
  50. package/dist/esm/common/serialize/bel-serializer.js +4 -3
  51. package/dist/esm/common/session/session-entity.js +9 -9
  52. package/dist/esm/common/util/data-size.js +2 -2
  53. package/dist/esm/common/util/obfuscate.js +147 -3
  54. package/dist/esm/common/v2/mfe-vitals.js +281 -0
  55. package/dist/esm/common/wrap/wrap-websocket.js +2 -1
  56. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  57. package/dist/esm/features/ajax/aggregate/gql.js +39 -1
  58. package/dist/esm/features/ajax/aggregate/index.js +52 -14
  59. package/dist/esm/features/ajax/constants.js +5 -0
  60. package/dist/esm/features/ajax/instrument/index.js +106 -18
  61. package/dist/esm/features/generic_events/aggregate/index.js +15 -10
  62. package/dist/esm/features/generic_events/constants.js +3 -2
  63. package/dist/esm/features/jserrors/aggregate/format-stack-trace.js +2 -2
  64. package/dist/esm/features/jserrors/aggregate/index.js +12 -3
  65. package/dist/esm/features/logging/aggregate/index.js +12 -8
  66. package/dist/esm/features/metrics/aggregate/index.js +5 -1
  67. package/dist/esm/features/page_view_event/aggregate/index.js +71 -32
  68. package/dist/esm/features/page_view_timing/aggregate/index.js +6 -1
  69. package/dist/esm/features/session_replay/aggregate/index.js +39 -29
  70. package/dist/esm/features/session_trace/aggregate/index.js +36 -30
  71. package/dist/esm/features/session_trace/constants.js +16 -2
  72. package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +36 -5
  73. package/dist/esm/features/soft_navigations/aggregate/index.js +7 -1
  74. package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  75. package/dist/esm/features/soft_navigations/aggregate/interaction.js +6 -4
  76. package/dist/esm/features/utils/aggregate-base.js +4 -3
  77. package/dist/esm/loaders/api/register.js +26 -4
  78. package/dist/tsconfig.tsbuildinfo +1 -1
  79. package/dist/types/common/config/init-types.d.ts +4 -0
  80. package/dist/types/common/config/init-types.d.ts.map +1 -1
  81. package/dist/types/common/config/init.d.ts.map +1 -1
  82. package/dist/types/common/constants/events.d.ts +16 -0
  83. package/dist/types/common/constants/events.d.ts.map +1 -0
  84. package/dist/types/common/harvest/harvester.d.ts +2 -16
  85. package/dist/types/common/harvest/harvester.d.ts.map +1 -1
  86. package/dist/types/common/harvest/send.d.ts +9 -0
  87. package/dist/types/common/harvest/send.d.ts.map +1 -0
  88. package/dist/types/common/harvest/types.d.ts +39 -10
  89. package/dist/types/common/harvest/types.d.ts.map +1 -1
  90. package/dist/types/common/payloads/payloads.d.ts +42 -0
  91. package/dist/types/common/payloads/payloads.d.ts.map +1 -0
  92. package/dist/types/common/serialize/bel-serializer.d.ts +1 -1
  93. package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
  94. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  95. package/dist/types/common/util/obfuscate.d.ts +23 -2
  96. package/dist/types/common/util/obfuscate.d.ts.map +1 -1
  97. package/dist/types/common/v2/mfe-vitals.d.ts +14 -0
  98. package/dist/types/common/v2/mfe-vitals.d.ts.map +1 -0
  99. package/dist/types/common/wrap/wrap-websocket.d.ts.map +1 -1
  100. package/dist/types/features/ajax/aggregate/gql.d.ts +8 -0
  101. package/dist/types/features/ajax/aggregate/gql.d.ts.map +1 -1
  102. package/dist/types/features/ajax/aggregate/index.d.ts +2 -0
  103. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  104. package/dist/types/features/ajax/constants.d.ts +5 -0
  105. package/dist/types/features/ajax/constants.d.ts.map +1 -1
  106. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  107. package/dist/types/features/generic_events/aggregate/index.d.ts +3 -1
  108. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  109. package/dist/types/features/generic_events/constants.d.ts.map +1 -1
  110. package/dist/types/features/jserrors/aggregate/index.d.ts +8 -1
  111. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  112. package/dist/types/features/logging/aggregate/index.d.ts +3 -1
  113. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  114. package/dist/types/features/metrics/aggregate/index.d.ts +2 -0
  115. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  116. package/dist/types/features/page_view_event/aggregate/index.d.ts +3 -0
  117. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  118. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -0
  119. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  120. package/dist/types/features/session_replay/aggregate/index.d.ts +4 -2
  121. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  122. package/dist/types/features/session_trace/aggregate/index.d.ts +3 -1
  123. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  124. package/dist/types/features/session_trace/constants.d.ts +17 -0
  125. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +6 -1
  126. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
  127. package/dist/types/features/soft_navigations/aggregate/index.d.ts +3 -0
  128. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  129. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +3 -1
  130. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
  131. package/dist/types/features/utils/aggregate-base.d.ts +0 -1
  132. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  133. package/dist/types/loaders/api/register.d.ts.map +1 -1
  134. package/package.json +3 -3
  135. package/src/common/config/configurable.js +1 -1
  136. package/src/common/config/init-types.js +1 -0
  137. package/src/common/config/init.js +2 -1
  138. package/src/common/constants/events.js +20 -0
  139. package/src/common/harvest/harvester.js +9 -201
  140. package/src/common/harvest/send.js +209 -0
  141. package/src/common/harvest/types.js +9 -5
  142. package/src/common/payloads/payloads.js +135 -0
  143. package/src/common/serialize/bel-serializer.js +4 -3
  144. package/src/common/session/session-entity.js +8 -9
  145. package/src/common/util/data-size.js +2 -2
  146. package/src/common/util/obfuscate.js +154 -3
  147. package/src/common/v2/mfe-vitals.js +260 -0
  148. package/src/common/wrap/wrap-websocket.js +2 -1
  149. package/src/common/wrap/wrap-xhr.js +1 -1
  150. package/src/features/ajax/aggregate/gql.js +42 -1
  151. package/src/features/ajax/aggregate/index.js +43 -13
  152. package/src/features/ajax/constants.js +5 -1
  153. package/src/features/ajax/instrument/index.js +114 -18
  154. package/src/features/generic_events/aggregate/index.js +14 -9
  155. package/src/features/generic_events/constants.js +3 -2
  156. package/src/features/jserrors/aggregate/format-stack-trace.js +3 -3
  157. package/src/features/jserrors/aggregate/index.js +12 -3
  158. package/src/features/logging/aggregate/index.js +12 -11
  159. package/src/features/metrics/aggregate/index.js +5 -1
  160. package/src/features/page_view_event/aggregate/index.js +58 -29
  161. package/src/features/page_view_timing/aggregate/index.js +6 -1
  162. package/src/features/session_replay/aggregate/index.js +37 -28
  163. package/src/features/session_trace/aggregate/index.js +37 -30
  164. package/src/features/session_trace/constants.js +7 -1
  165. package/src/features/soft_navigations/aggregate/ajax-node.js +26 -5
  166. package/src/features/soft_navigations/aggregate/index.js +7 -1
  167. package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  168. package/src/features/soft_navigations/aggregate/interaction.js +6 -4
  169. package/src/features/utils/aggregate-base.js +3 -3
  170. package/src/loaders/api/register.js +24 -4
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.AjaxNode = void 0;
7
7
  var _belSerializer = require("../../../common/serialize/bel-serializer");
8
+ var _payloads = require("../../../common/payloads/payloads");
8
9
  var _constants = require("../../ajax/constants");
9
10
  var _constants2 = require("../constants");
10
11
  var _belNode = require("./bel-node");
@@ -31,6 +32,12 @@ class AjaxNode extends _belNode.BelNode {
31
32
  this.targetAttributes = ajaxEvent.targetAttributes;
32
33
  this[_constants.AJAX_ID] = ajaxEvent[_constants.AJAX_ID]; // all AjaxRequest events should have a unique identifier to allow for easier grouping and analysis in the UI
33
34
 
35
+ // optional payload metadata attributes
36
+ this.requestBody = ajaxEvent.requestBody;
37
+ this.requestHeaders = ajaxEvent.requestHeaders;
38
+ this.requestQuery = ajaxEvent.requestQuery;
39
+ this.responseBody = ajaxEvent.responseBody;
40
+ this.responseHeaders = ajaxEvent.responseHeaders;
34
41
  this.start = ajaxEvent.startTime;
35
42
  this.end = ajaxEvent.endTime;
36
43
  if (ajaxContext?.latestLongtaskEnd) {
@@ -38,8 +45,11 @@ class AjaxNode extends _belNode.BelNode {
38
45
  this.callbackDuration = this.callbackEnd - this.end; // callbackDuration is the time from ajax loaded to last long task observed from it
39
46
  } else this.callbackEnd = this.end; // if no long task was observed, callbackEnd is the same as end
40
47
  }
41
- serialize(parentStartTimestamp, agentRef) {
42
- const addString = (0, _belSerializer.getAddStringContext)(agentRef.runtime.obfuscator);
48
+ serialize(parentStartTimestamp, agentRef, ajaxObfuscator) {
49
+ const {
50
+ addString,
51
+ addStringWithTruncation
52
+ } = (0, _payloads.createStringAdders)(_belSerializer.getAddStringContext, ajaxObfuscator);
43
53
  const nodeList = [];
44
54
 
45
55
  // IMPORTANT: The order in which addString is called matters and correlates to the order in which string shows up in the harvest payload. Do not re-order the following code.
@@ -54,11 +64,32 @@ class AjaxNode extends _belNode.BelNode {
54
64
  (0, _belSerializer.numeric)(this.callbackDuration),
55
65
  // not relative
56
66
  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)];
57
- let allAttachedNodes = (0, _belSerializer.addCustomAttributes)({
58
- ...(this.gql || {}),
67
+ // Regular attributes: obfuscate only
68
+ const regularAttrs = (0, _belSerializer.addCustomAttributes)({
69
+ [_constants.AJAX_ID]: this[_constants.AJAX_ID],
59
70
  ...(this.targetAttributes || {}),
60
- [_constants.AJAX_ID]: this[_constants.AJAX_ID]
71
+ ...(this.gql || {})
61
72
  }, addString);
73
+
74
+ // Payload attributes: obfuscate then truncate
75
+ const payloadAttrs = (0, _belSerializer.addCustomAttributes)({
76
+ ...(this.requestBody ? {
77
+ requestBody: this.requestBody
78
+ } : {}),
79
+ ...(this.requestHeaders ? {
80
+ requestHeaders: this.requestHeaders
81
+ } : {}),
82
+ ...(this.requestQuery ? {
83
+ requestQuery: this.requestQuery
84
+ } : {}),
85
+ ...(this.responseBody ? {
86
+ responseBody: this.responseBody
87
+ } : {}),
88
+ ...(this.responseHeaders ? {
89
+ responseHeaders: this.responseHeaders
90
+ } : {})
91
+ }, addStringWithTruncation);
92
+ let allAttachedNodes = [...regularAttrs, ...payloadAttrs];
62
93
  this.children.forEach(node => allAttachedNodes.push(node.serialize())); // no children is expected under ajax nodes at this time
63
94
 
64
95
  fields[1] = (0, _belSerializer.numeric)(allAttachedNodes.length);
@@ -10,10 +10,12 @@ var _webdriverDetection = require("../../../common/util/webdriver-detection");
10
10
  var _loadTime = require("../../../common/vitals/load-time");
11
11
  var _features = require("../../../loaders/features/features");
12
12
  var _aggregateBase = require("../../utils/aggregate-base");
13
+ var _obfuscate = require("../../../common/util/obfuscate");
13
14
  var _constants = require("../constants");
14
15
  var _ajaxNode = require("./ajax-node");
15
16
  var _initialPageLoadInteraction = require("./initial-page-load-interaction");
16
17
  var _interaction = require("./interaction");
18
+ var _events = require("../../../common/constants/events");
17
19
  /**
18
20
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
19
21
  * SPDX-License-Identifier: Apache-2.0
@@ -26,6 +28,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
26
28
  }) {
27
29
  super(agentRef, _constants.FEATURE_NAME);
28
30
  super.customAttributesAreSeparate = true;
31
+
32
+ // Create obfuscators for browser interactions and nested AJAX requests
33
+ this.interactionObfuscator = new _obfuscate.Obfuscator(agentRef, _events.EVENT_TYPES.BI);
34
+ this.ajaxObfuscator = new _obfuscate.Obfuscator(agentRef, _events.EVENT_TYPES.AJAX);
29
35
  this.interactionsToHarvest = this.events;
30
36
  this.domObserver = domObserver;
31
37
  this.initialPageLoadInteraction = new _initialPageLoadInteraction.InitialPageLoadInteraction(agentRef);
@@ -89,7 +95,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
89
95
  let firstIxnStartTime;
90
96
  const serializedIxnList = [];
91
97
  for (const interaction of eventBuffer) {
92
- serializedIxnList.push(interaction.serialize(firstIxnStartTime, this.agentRef));
98
+ serializedIxnList.push(interaction.serialize(firstIxnStartTime, this.agentRef, this.interactionObfuscator, this.ajaxObfuscator));
93
99
  if (firstIxnStartTime === undefined) firstIxnStartTime = Math.floor(interaction.start); // careful not to match or overwrite on 0 value!
94
100
  }
95
101
  return "bel.7;".concat(serializedIxnList.join(';'));
@@ -11,7 +11,7 @@ var _firstPaint = require("../../../common/vitals/first-paint");
11
11
  var _firstContentfulPaint = require("../../../common/vitals/first-contentful-paint");
12
12
  var _constants = 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
 
@@ -12,7 +12,7 @@ var _cleanUrl = require("../../../common/url/clean-url");
12
12
  var _constants = require("../constants");
13
13
  var _belNode = require("./bel-node");
14
14
  /**
15
- * Copyright 2020-2025 New Relic, Inc. All rights reserved.
15
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
16
16
  * SPDX-License-Identifier: Apache-2.0
17
17
  */
18
18
 
@@ -127,11 +127,13 @@ class Interaction extends _belNode.BelNode {
127
127
  * Serializes (BEL) the interaction data for transmission.
128
128
  * @param {Number} firstStartTimeOfPayload timestamp
129
129
  * @param {Agent} agentRef Pass in the agent reference directly so that the event itself doesnt need to store the pointers and ruin the evaluation of the event size by including unused object references.
130
+ * @param {Obfuscator} interactionObfuscator Obfuscator for BrowserInteraction event type
131
+ * @param {Obfuscator} ajaxObfuscator Obfuscator for AjaxRequest event type (passed to child AjaxNodes)
130
132
  * @returns {String} A string that is the serialized representation of this interaction.
131
133
  */
132
- serialize(firstStartTimeOfPayload, agentRef) {
134
+ serialize(firstStartTimeOfPayload, agentRef, interactionObfuscator, ajaxObfuscator) {
133
135
  const isFirstIxnOfPayload = firstStartTimeOfPayload === undefined;
134
- const addString = (0, _belSerializer.getAddStringContext)(agentRef.runtime.obfuscator);
136
+ const addString = (0, _belSerializer.getAddStringContext)(interactionObfuscator);
135
137
  const nodeList = [];
136
138
  let ixnType;
137
139
  if (this.trigger === _constants.IPL_TRIGGER_NAME) ixnType = _constants.INTERACTION_TYPE.INITIAL_PAGE_LOAD;else if (this.newURL !== this.oldURL) ixnType = _constants.INTERACTION_TYPE.ROUTE_CHANGE;else ixnType = _constants.INTERACTION_TYPE.UNSPECIFIED;
@@ -157,7 +159,7 @@ class Interaction extends _belNode.BelNode {
157
159
  /* Querypack encoder+decoder quirkiness:
158
160
  - If first ixn node of payload is being processed, its children's start time must be offset by this node's start. (firstStartTime should be undefined.)
159
161
  - Else for subsequent ixns in the same payload, we go back to using that first ixn node's start to offset their children's start. */
160
- this.children.forEach(node => allAttachedNodes.push(node.serialize(isFirstIxnOfPayload ? this.start : firstStartTimeOfPayload, agentRef))); // recursively add the serialized string of every child of this (ixn) bel node
162
+ this.children.forEach(node => allAttachedNodes.push(node.serialize(isFirstIxnOfPayload ? this.start : firstStartTimeOfPayload, agentRef, ajaxObfuscator))); // recursively add the serialized string of every child of this (ixn) bel node
161
163
 
162
164
  fields[1] = (0, _belSerializer.numeric)(allAttachedNodes.length);
163
165
  nodeList.push(fields);
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.AggregateBase = void 0;
7
7
  var _featureBase = require("./feature-base");
8
8
  var _drain = require("../../common/drain/drain");
9
- var _obfuscate = require("../../common/util/obfuscate");
10
9
  var _features = require("../../loaders/features/features");
11
10
  var _harvester = require("../../common/harvest/harvester");
12
11
  var _eventBuffer = require("./event-buffer");
@@ -14,6 +13,7 @@ var _handle = require("../../common/event-emitter/handle");
14
13
  var _constants = require("../metrics/constants");
15
14
  var _eventAggregator = require("../../common/aggregate/event-aggregator");
16
15
  var _agentConstants = require("../../common/constants/agent-constants");
16
+ var _console = require("../../common/util/console");
17
17
  /**
18
18
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
19
19
  * SPDX-License-Identifier: Apache-2.0
@@ -118,6 +118,7 @@ class AggregateBase extends _featureBase.FeatureBase {
118
118
  }
119
119
  function buildOutput(ref) {
120
120
  return flagNames.map(flag => {
121
+ if (ref[flag] === undefined || ref[flag] === null) (0, _console.warn)(71, flag);
121
122
  if (!ref[flag]) return 0;
122
123
  return ref[flag];
123
124
  });
@@ -183,8 +184,8 @@ class AggregateBase extends _featureBase.FeatureBase {
183
184
  * This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
184
185
  */
185
186
  doOnceForAllAggregate(agentRef) {
186
- if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new _obfuscate.Obfuscator(agentRef);
187
- this.obfuscator = agentRef.runtime.obfuscator;
187
+ // Note: obfuscator is now created per-feature for their specific event types
188
+
188
189
  if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
189
190
  }
190
191
 
@@ -21,6 +21,7 @@ var _measure = require("./measure");
21
21
  var _recordCustomEvent = require("./recordCustomEvent");
22
22
  var _pageVisibility = require("../../common/window/page-visibility");
23
23
  var _scriptTracker = require("../../common/v2/script-tracker");
24
+ var _mfeVitals = require("../../common/v2/mfe-vitals");
24
25
  var _uniqueId = require("../../common/ids/unique-id");
25
26
  /**
26
27
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
@@ -84,6 +85,9 @@ function register(agentRef, target) {
84
85
  type: _utils.V2_TYPES.BA
85
86
  };
86
87
  const timings = (0, _scriptTracker.findScriptTimings)();
88
+
89
+ // Track MFE vitals for this entity
90
+ const vitals = (0, _mfeVitals.trackMFEVitals)(target.id);
87
91
  const attrs = {};
88
92
 
89
93
  // Only define attributes getter if it doesn't already exist
@@ -172,7 +176,8 @@ function register(agentRef, target) {
172
176
  return attrs;
173
177
  },
174
178
  target,
175
- timings
179
+ timings,
180
+ vitals
176
181
  }
177
182
  };
178
183
 
@@ -200,9 +205,17 @@ function register(agentRef, target) {
200
205
  // only ever report the timings the first time this is called
201
206
  if (timings.reportedAt) return;
202
207
  timings.reportedAt = (0, _now.now)();
208
+
209
+ // Disconnect observers and capture current values, store in timings obj for visibility
210
+ vitals.disconnect();
211
+ timings.fcp = vitals.fcp;
212
+ timings.lcp = vitals.lcp;
213
+ timings.cls = vitals.cls;
214
+ timings.inp = vitals.inp;
203
215
  const timeToFetch = timings.fetchEnd - timings.fetchStart; // fetchStart to fetchEnd
204
216
  const timeToExecute = timings.scriptEnd - timings.scriptStart; // scriptStart to scriptEnd
205
- api.recordCustomEvent('MicroFrontEndTiming', {
217
+
218
+ const eventData = {
206
219
  assetUrl: timings.asset,
207
220
  // the url of the script that was registered, or undefined if it could not be determined (inline or no match)
208
221
  assetType: timings.type,
@@ -217,8 +230,17 @@ function register(agentRef, target) {
217
230
  // fetchStart to fetchEnd
218
231
  timeToLoad: timeToFetch + timeToExecute,
219
232
  // fetch time and script time together
220
- timeToRegister: timings.registeredAt // timestamp when register() was called
221
- });
233
+ timeToRegister: timings.registeredAt,
234
+ // timestamp when register() was called
235
+ 'nr.vitals.fcp': vitals.fcp || null,
236
+ // FCP vital object with value and metadata
237
+ 'nr.vitals.lcp': vitals.lcp || null,
238
+ // LCP vital object with value and metadata
239
+ 'nr.vitals.cls': vitals.cls || null,
240
+ // CLS vital object with value and metadata
241
+ 'nr.vitals.inp': vitals.inp || null // INP vital object with value and metadata
242
+ };
243
+ api.recordCustomEvent('MicroFrontEndTiming', eventData);
222
244
  }
223
245
 
224
246
  /**
@@ -17,7 +17,7 @@ export function getModeledObject(obj, model) {
17
17
  output[key] = null;
18
18
  continue;
19
19
  }
20
- if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (obj[key] instanceof Map || obj[key] instanceof Set || obj[key] instanceof Date || obj[key] instanceof RegExp) output[key] = obj[key];else if (typeof obj[key] === 'object' && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
20
+ if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (obj[key] instanceof Map || obj[key] instanceof Set || obj[key] instanceof Date || obj[key] instanceof RegExp) output[key] = obj[key];else if (typeof obj[key] === 'object' && model[key] !== null && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
21
21
  } catch (e) {
22
22
  if (!output[key]) warn(1, e);
23
23
  }
@@ -11,6 +11,7 @@
11
11
  * @property {boolean} [ajax.block_internal] - If true, agent requests going to harvest endpoint are treated as on deny list. In other words, agent will not self-report AJAX.
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
+ * @property {('none'|'failures'|'all')} [ajax.capture_payloads] - Controls when AJAX request/response payloads are captured. 'none' = never capture, 'failures' = capture only on errors (4xx, 5xx, network errors, GraphQL errors), 'all' = always capture.
14
15
  * @property {Object} [api]
15
16
  * @property {Object} [api.register]
16
17
  * @property {boolean} [api.register.enabled] - If true, the agent will allow registered children to be sent to the server.
@@ -3,6 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { FEATURE_FLAGS } from '../../features/generic_events/constants';
6
+ import { CAPTURE_PAYLOAD_SETTINGS } from '../../features/ajax/constants';
6
7
  import { isValidSelector } from '../dom/query-selector';
7
8
  import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS } from '../session/constants';
8
9
  import { warn } from '../util/console';
@@ -51,7 +52,8 @@ const InitModelFn = () => {
51
52
  deny_list: undefined,
52
53
  block_internal: true,
53
54
  enabled: true,
54
- autoStart: true
55
+ autoStart: true,
56
+ capture_payloads: CAPTURE_PAYLOAD_SETTINGS.NONE
55
57
  },
56
58
  api: {
57
59
  register: {
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.316.0";
14
+ export const VERSION = "1.317.0-rc.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -25,4 +25,4 @@ export const BUILD_ENV = "CDN";
25
25
  export const DIST_METHOD = 'CDN';
26
26
  export const RRWEB_PACKAGE_NAME = '@newrelic/rrweb';
27
27
  // Babel will inline this with the rrweb (fork) version on CDN builds.
28
- export const RRWEB_VERSION = "1.1.0";
28
+ export const RRWEB_VERSION = "^1.1.2";
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.316.0";
14
+ export const VERSION = "1.317.0-rc.1";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -26,4 +26,4 @@ export const BUILD_ENV = 'NPM';
26
26
  export const DIST_METHOD = 'NPM';
27
27
  export const RRWEB_PACKAGE_NAME = '@newrelic/rrweb';
28
28
  // Babel will inline this with the rrweb (fork) version on NPM dist esm/cjs builds.
29
- export const RRWEB_VERSION = "1.1.0";
29
+ export const RRWEB_VERSION = "^1.1.2";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ export const EVENT_TYPES = {
7
+ AJAX: 'AjaxRequest',
8
+ PA: 'PageAction',
9
+ UA: 'UserAction',
10
+ BP: 'BrowserPerformance',
11
+ WS: 'WebSocket',
12
+ SPV: 'SecurityPolicyViolation',
13
+ JSE: 'JavaScriptError',
14
+ LOG: 'Log',
15
+ PVE: 'PageView',
16
+ PVT: 'PageViewTiming',
17
+ SR: 'SessionReplay',
18
+ ST: 'SessionTrace',
19
+ BI: 'BrowserInteraction'
20
+ };
@@ -3,19 +3,12 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants';
6
- import { FEATURE_TO_ENDPOINT, JSERRORS, RUM, EVENTS, FEATURE_NAMES, BLOBS, LOGS } from '../../loaders/features/features';
7
- import { VERSION } from "../constants/env.npm";
8
- import { globalScope, isWorkerScope } from '../constants/runtime';
6
+ import { FEATURE_TO_ENDPOINT, FEATURE_NAMES } from '../../loaders/features/features';
9
7
  import { handle } from '../event-emitter/handle';
10
- import { eventListenerOpts } from '../event-listener/event-listener-opts';
11
- import { now } from '../timing/now';
12
8
  import { subscribeToEOL } from '../unload/eol';
13
- import { cleanURL } from '../url/clean-url';
14
- import { obj, param } from '../url/encode';
15
- import { warn } from '../util/console';
16
- import { stringify } from '../util/stringify';
17
- import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
18
- import { dispatchGlobalEvent } from '../dispatch/global-event';
9
+ import { getSubmitMethod, xhr as xhrMethod } from '../util/submit-data';
10
+ import { send } from './send';
11
+ import { Obfuscator } from '../util/obfuscate';
19
12
  const RETRY = 'Harvester/Retry/';
20
13
  const RETRY_ATTEMPTED = RETRY + 'Attempted/';
21
14
  const RETRY_FAILED = RETRY + 'Failed/';
@@ -25,6 +18,10 @@ export class Harvester {
25
18
  initializedAggregates = [];
26
19
  constructor(agentRef) {
27
20
  this.agentRef = agentRef;
21
+
22
+ // Create obfuscator for harvest metadata (referrer URL, etc.)
23
+ // No event type specified - applies to all harvests regardless of feature
24
+ this.obfuscator = new Obfuscator(agentRef);
28
25
  subscribeToEOL(() => {
29
26
  // do one last harvest round or check
30
27
  this.initializedAggregates.forEach(aggregateInst => {
@@ -71,6 +68,7 @@ export class Harvester {
71
68
  payload: output.payload,
72
69
  localOpts,
73
70
  submitMethod,
71
+ harvesterObfuscator: this.obfuscator,
74
72
  cbFinished,
75
73
  raw: aggregateInst.harvestOpts.raw,
76
74
  featureName: aggregateInst.featureName,
@@ -99,210 +97,4 @@ export class Harvester {
99
97
  aggregateInst.postHarvestCleanup(result);
100
98
  }
101
99
  }
102
- }
103
-
104
- /**
105
- * @typedef {import('./types.js').NetworkSendSpec} NetworkSendSpec
106
- */
107
-
108
- const warnings = {};
109
- /**
110
- * Initiate a harvest call.
111
- * @param {NetworkSendSpec} param0 Specification for sending data
112
- * @returns {boolean} True if a network call was made. Note that this does not mean or guarantee that it was successful.
113
- */
114
- export function send(agentRef, {
115
- endpoint,
116
- payload,
117
- localOpts = {},
118
- submitMethod,
119
- cbFinished,
120
- raw,
121
- featureName,
122
- endpointVersion = 1
123
- }) {
124
- if (!agentRef.info.errorBeacon) return false;
125
- let {
126
- body,
127
- qs
128
- } = cleanPayload(payload);
129
- if (Object.keys(body).length === 0 && !localOpts.sendEmptyBody) {
130
- // if there's no body to send, just run onfinish stuff and return
131
- if (cbFinished) cbFinished({
132
- sent: false
133
- });
134
- return false;
135
- }
136
- const protocol = agentRef.init.ssl === false ? 'http' : 'https';
137
- const perceivedBeacon = agentRef.init.proxy.beacon || agentRef.info.errorBeacon;
138
- const url = raw ? "".concat(protocol, "://").concat(perceivedBeacon, "/").concat(endpoint) : "".concat(protocol, "://").concat(perceivedBeacon).concat(endpoint !== RUM ? '/' + endpoint : '', "/").concat(endpointVersion, "/").concat(agentRef.info.licenseKey);
139
- const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint) : '';
140
- let payloadParams = obj(qs, agentRef.runtime.maxBytes);
141
- if (baseParams === '' && payloadParams.startsWith('&')) {
142
- payloadParams = payloadParams.substring(1);
143
- }
144
- const fullUrl = "".concat(url, "?").concat(baseParams).concat(payloadParams);
145
- const gzip = !!qs?.attributes?.includes('gzip');
146
-
147
- // all gzipped data is already in the correct format and needs no transformation
148
- // all features going to 'events' endpoint should already be serialized & stringified
149
- let stringBody = gzip || endpoint === EVENTS ? body : stringify(body);
150
-
151
- // If body is null, undefined, or an empty object or array after stringifying, send an empty string instead.
152
- if (!stringBody || stringBody.length === 0 || stringBody === '{}' || stringBody === '[]') stringBody = '';
153
-
154
- // Warn--once per endpoint--if the agent tries to send large payloads
155
- if (endpoint !== BLOBS && stringBody.length > 750000 && (warnings[endpoint] = (warnings[endpoint] || 0) + 1) === 1) warn(28, endpoint);
156
- const headers = [{
157
- key: 'content-type',
158
- value: 'text/plain'
159
- }];
160
-
161
- /* Since workers don't support sendBeacon right now, they can only use XHR method.
162
- Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
163
- we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
164
- Following the removal of img-element method. */
165
- let result = submitMethod({
166
- url: fullUrl,
167
- body: stringBody,
168
- sync: localOpts.isFinalHarvest && isWorkerScope,
169
- headers
170
- });
171
- if (!localOpts.isFinalHarvest && cbFinished) {
172
- // final harvests don't hold onto buffer data (shouldRetryOnFail is false), so cleanup isn't needed
173
- if (submitMethod === xhrMethod) {
174
- result.addEventListener('loadend', function () {
175
- // `this` here in block refers to the XHR object in this scope, do not change the anon function to an arrow function
176
- // status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
177
- const cbResult = {
178
- sent: this.status !== 0,
179
- status: this.status,
180
- retry: shouldRetry(this.status),
181
- fullUrl,
182
- xhr: this,
183
- responseText: this.responseText
184
- };
185
- cbFinished(cbResult);
186
-
187
- /** temporary audit of consistency of harvest metadata flags */
188
- if (!shouldRetry(this.status)) trackHarvestMetadata();
189
- }, eventListenerOpts(false));
190
- } else if (submitMethod === fetchMethod) {
191
- result.then(async function (response) {
192
- const status = response.status;
193
- const cbResult = {
194
- sent: true,
195
- status,
196
- retry: shouldRetry(status),
197
- fullUrl,
198
- fetchResponse: response,
199
- responseText: await response.text()
200
- };
201
- cbFinished(cbResult);
202
- /** temporary audit of consistency of harvest metadata flags */
203
- if (!shouldRetry(status)) trackHarvestMetadata();
204
- });
205
- }
206
- function trackHarvestMetadata() {
207
- try {
208
- if (featureName === FEATURE_NAMES.jserrors && !body?.err) return;
209
- const hasReplay = baseParams.includes('hr=1');
210
- const hasTrace = baseParams.includes('ht=1');
211
- const hasError = qs?.attributes?.includes('hasError=true');
212
- handle('harvest-metadata', [{
213
- [featureName]: {
214
- ...(hasReplay && {
215
- hasReplay
216
- }),
217
- ...(hasTrace && {
218
- hasTrace
219
- }),
220
- ...(hasError && {
221
- hasError
222
- })
223
- }
224
- }], undefined, FEATURE_NAMES.metrics, agentRef.ee);
225
- } catch (err) {
226
- // do nothing
227
- }
228
- }
229
- }
230
- dispatchGlobalEvent({
231
- drained: !!agentRef.runtime?.activatedFeatures,
232
- type: 'data',
233
- name: 'harvest',
234
- feature: featureName,
235
- data: {
236
- endpoint,
237
- headers,
238
- payload,
239
- submitMethod: getSubmitMethodName(),
240
- raw,
241
- synchronousXhr: !!(localOpts.isFinalHarvest && isWorkerScope)
242
- }
243
- });
244
- return true;
245
- function shouldRetry(status) {
246
- switch (status) {
247
- case 408:
248
- case 429:
249
- case 500:
250
- return true;
251
- }
252
- return status >= 502 && status <= 504 || status >= 512 && status <= 530;
253
- }
254
- function getSubmitMethodName() {
255
- if (submitMethod === xhrMethod) return 'xhr';
256
- if (submitMethod === fetchMethod) return 'fetch';
257
- return 'beacon';
258
- }
259
- }
260
-
261
- /**
262
- * Cleans and returns a payload object containing a body and qs
263
- * object with key/value pairs. KV pairs where the value is null,
264
- * undefined, or an empty string are removed to save on transmission
265
- * size.
266
- * @param {HarvestPayload} payload Payload to be sent to the endpoint.
267
- * @returns {HarvestPayload} Cleaned payload payload to be sent to the endpoint.
268
- */
269
- function cleanPayload(payload = {}) {
270
- const clean = input => {
271
- if (typeof Uint8Array !== 'undefined' && input instanceof Uint8Array || Array.isArray(input)) return input;
272
- if (typeof input === 'string') return input;
273
- return Object.entries(input || {}).reduce((accumulator, [key, value]) => {
274
- if (typeof value === 'number' || typeof value === 'string' && value.length > 0 || typeof value === 'object' && Object.keys(value || {}).length > 0) {
275
- accumulator[key] = value;
276
- }
277
- return accumulator;
278
- }, {});
279
- };
280
- return {
281
- body: clean(payload.body),
282
- qs: clean(payload.qs)
283
- };
284
- }
285
-
286
- // The stuff that gets sent every time.
287
- function baseQueryString(agentRef, qs, endpoint) {
288
- const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location));
289
- const session = agentRef.runtime.session;
290
- const hr = !!session?.state.sessionReplaySentFirstChunk && session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS;
291
- const ht = !!session?.state.traceHarvestStarted && session?.state.sessionTraceMode === 1 && ![LOGS, BLOBS].includes(endpoint);
292
- const qps = ['a=' + agentRef.info.applicationID, param('sa', agentRef.info.sa ? '' + agentRef.info.sa : ''), param('v', VERSION), transactionNameParam(), param('ct', agentRef.runtime.customTransaction), '&rst=' + now(), '&ck=0',
293
- // ck param DEPRECATED - still expected by backend
294
- '&s=' + (session?.state.value || '0'),
295
- // the 0 id encaps all untrackable and default traffic
296
- param('ref', ref), param('ptid', agentRef.runtime.ptid ? '' + agentRef.runtime.ptid : '')];
297
- if (hr) qps.push(param('hr', '1', qs));
298
- if (ht) qps.push(param('ht', '1', qs));
299
- return qps.join('');
300
-
301
- // Constructs the transaction name param for the beacon URL.
302
- // Prefers the obfuscated transaction name over the plain text.
303
- // Falls back to making up a name.
304
- function transactionNameParam() {
305
- if (agentRef.info.transactionName) return param('to', agentRef.info.transactionName);
306
- return param('t', agentRef.info.tNamePlain || 'Unnamed Transaction');
307
- }
308
100
  }