@newrelic/browser-agent 1.316.0 → 1.317.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 (140) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/common/config/init-types.js +1 -0
  3. package/dist/cjs/common/config/init.js +6 -4
  4. package/dist/cjs/common/constants/env.cdn.js +2 -2
  5. package/dist/cjs/common/constants/env.npm.js +2 -2
  6. package/dist/cjs/common/constants/events.js +26 -0
  7. package/dist/cjs/common/harvest/harvester.js +12 -4
  8. package/dist/cjs/common/payloads/payloads.js +127 -0
  9. package/dist/cjs/common/serialize/bel-serializer.js +4 -3
  10. package/dist/cjs/common/util/data-size.js +2 -2
  11. package/dist/cjs/common/util/obfuscate.js +147 -3
  12. package/dist/cjs/common/wrap/wrap-websocket.js +2 -1
  13. package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
  14. package/dist/cjs/features/ajax/aggregate/gql.js +40 -1
  15. package/dist/cjs/features/ajax/aggregate/index.js +51 -13
  16. package/dist/cjs/features/ajax/constants.js +6 -1
  17. package/dist/cjs/features/ajax/instrument/index.js +105 -17
  18. package/dist/cjs/features/generic_events/aggregate/index.js +15 -10
  19. package/dist/cjs/features/generic_events/constants.js +3 -2
  20. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.js +2 -2
  21. package/dist/cjs/features/jserrors/aggregate/index.js +12 -3
  22. package/dist/cjs/features/logging/aggregate/index.js +7 -3
  23. package/dist/cjs/features/metrics/aggregate/index.js +5 -1
  24. package/dist/cjs/features/page_view_event/aggregate/index.js +7 -3
  25. package/dist/cjs/features/page_view_timing/aggregate/index.js +6 -1
  26. package/dist/cjs/features/session_replay/aggregate/index.js +7 -1
  27. package/dist/cjs/features/session_trace/aggregate/index.js +6 -2
  28. package/dist/cjs/features/soft_navigations/aggregate/ajax-node.js +36 -5
  29. package/dist/cjs/features/soft_navigations/aggregate/index.js +7 -1
  30. package/dist/cjs/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  31. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +6 -4
  32. package/dist/cjs/features/utils/aggregate-base.js +2 -3
  33. package/dist/esm/common/config/init-types.js +1 -0
  34. package/dist/esm/common/config/init.js +3 -1
  35. package/dist/esm/common/constants/env.cdn.js +2 -2
  36. package/dist/esm/common/constants/env.npm.js +2 -2
  37. package/dist/esm/common/constants/events.js +20 -0
  38. package/dist/esm/common/harvest/harvester.js +12 -4
  39. package/dist/esm/common/payloads/payloads.js +118 -0
  40. package/dist/esm/common/serialize/bel-serializer.js +4 -3
  41. package/dist/esm/common/util/data-size.js +2 -2
  42. package/dist/esm/common/util/obfuscate.js +147 -3
  43. package/dist/esm/common/wrap/wrap-websocket.js +2 -1
  44. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  45. package/dist/esm/features/ajax/aggregate/gql.js +39 -1
  46. package/dist/esm/features/ajax/aggregate/index.js +52 -14
  47. package/dist/esm/features/ajax/constants.js +5 -0
  48. package/dist/esm/features/ajax/instrument/index.js +106 -18
  49. package/dist/esm/features/generic_events/aggregate/index.js +15 -10
  50. package/dist/esm/features/generic_events/constants.js +3 -2
  51. package/dist/esm/features/jserrors/aggregate/format-stack-trace.js +2 -2
  52. package/dist/esm/features/jserrors/aggregate/index.js +12 -3
  53. package/dist/esm/features/logging/aggregate/index.js +7 -3
  54. package/dist/esm/features/metrics/aggregate/index.js +5 -1
  55. package/dist/esm/features/page_view_event/aggregate/index.js +7 -3
  56. package/dist/esm/features/page_view_timing/aggregate/index.js +6 -1
  57. package/dist/esm/features/session_replay/aggregate/index.js +7 -1
  58. package/dist/esm/features/session_trace/aggregate/index.js +6 -2
  59. package/dist/esm/features/soft_navigations/aggregate/ajax-node.js +36 -5
  60. package/dist/esm/features/soft_navigations/aggregate/index.js +7 -1
  61. package/dist/esm/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  62. package/dist/esm/features/soft_navigations/aggregate/interaction.js +6 -4
  63. package/dist/esm/features/utils/aggregate-base.js +2 -3
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/dist/types/common/config/init-types.d.ts +4 -0
  66. package/dist/types/common/config/init-types.d.ts.map +1 -1
  67. package/dist/types/common/config/init.d.ts.map +1 -1
  68. package/dist/types/common/constants/events.d.ts +16 -0
  69. package/dist/types/common/constants/events.d.ts.map +1 -0
  70. package/dist/types/common/harvest/harvester.d.ts +4 -1
  71. package/dist/types/common/harvest/harvester.d.ts.map +1 -1
  72. package/dist/types/common/payloads/payloads.d.ts +42 -0
  73. package/dist/types/common/payloads/payloads.d.ts.map +1 -0
  74. package/dist/types/common/serialize/bel-serializer.d.ts +1 -1
  75. package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
  76. package/dist/types/common/util/obfuscate.d.ts +23 -2
  77. package/dist/types/common/util/obfuscate.d.ts.map +1 -1
  78. package/dist/types/common/wrap/wrap-websocket.d.ts.map +1 -1
  79. package/dist/types/features/ajax/aggregate/gql.d.ts +8 -0
  80. package/dist/types/features/ajax/aggregate/gql.d.ts.map +1 -1
  81. package/dist/types/features/ajax/aggregate/index.d.ts +2 -0
  82. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  83. package/dist/types/features/ajax/constants.d.ts +5 -0
  84. package/dist/types/features/ajax/constants.d.ts.map +1 -1
  85. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  86. package/dist/types/features/generic_events/aggregate/index.d.ts +3 -1
  87. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -1
  88. package/dist/types/features/generic_events/constants.d.ts.map +1 -1
  89. package/dist/types/features/jserrors/aggregate/index.d.ts +8 -1
  90. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  91. package/dist/types/features/logging/aggregate/index.d.ts +3 -1
  92. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  93. package/dist/types/features/metrics/aggregate/index.d.ts +2 -0
  94. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  95. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -0
  96. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  97. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -0
  98. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  99. package/dist/types/features/session_replay/aggregate/index.d.ts +2 -0
  100. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  101. package/dist/types/features/session_trace/aggregate/index.d.ts +2 -0
  102. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  103. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts +6 -1
  104. package/dist/types/features/soft_navigations/aggregate/ajax-node.d.ts.map +1 -1
  105. package/dist/types/features/soft_navigations/aggregate/index.d.ts +3 -0
  106. package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
  107. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts +3 -1
  108. package/dist/types/features/soft_navigations/aggregate/interaction.d.ts.map +1 -1
  109. package/dist/types/features/utils/aggregate-base.d.ts +0 -1
  110. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  111. package/package.json +2 -2
  112. package/src/common/config/init-types.js +1 -0
  113. package/src/common/config/init.js +2 -1
  114. package/src/common/constants/events.js +20 -0
  115. package/src/common/harvest/harvester.js +11 -4
  116. package/src/common/payloads/payloads.js +135 -0
  117. package/src/common/serialize/bel-serializer.js +4 -3
  118. package/src/common/util/data-size.js +2 -2
  119. package/src/common/util/obfuscate.js +154 -3
  120. package/src/common/wrap/wrap-websocket.js +2 -1
  121. package/src/common/wrap/wrap-xhr.js +1 -1
  122. package/src/features/ajax/aggregate/gql.js +42 -1
  123. package/src/features/ajax/aggregate/index.js +43 -13
  124. package/src/features/ajax/constants.js +5 -1
  125. package/src/features/ajax/instrument/index.js +114 -18
  126. package/src/features/generic_events/aggregate/index.js +14 -9
  127. package/src/features/generic_events/constants.js +3 -2
  128. package/src/features/jserrors/aggregate/format-stack-trace.js +3 -3
  129. package/src/features/jserrors/aggregate/index.js +12 -3
  130. package/src/features/logging/aggregate/index.js +7 -6
  131. package/src/features/metrics/aggregate/index.js +5 -1
  132. package/src/features/page_view_event/aggregate/index.js +6 -2
  133. package/src/features/page_view_timing/aggregate/index.js +6 -1
  134. package/src/features/session_replay/aggregate/index.js +7 -1
  135. package/src/features/session_trace/aggregate/index.js +6 -2
  136. package/src/features/soft_navigations/aggregate/ajax-node.js +26 -5
  137. package/src/features/soft_navigations/aggregate/index.js +7 -1
  138. package/src/features/soft_navigations/aggregate/initial-page-load-interaction.js +1 -1
  139. package/src/features/soft_navigations/aggregate/interaction.js +6 -4
  140. package/src/features/utils/aggregate-base.js +1 -3
@@ -17,9 +17,11 @@ var _stringify = require("../../../common/util/stringify");
17
17
  var _stylesheetEvaluator = require("../shared/stylesheet-evaluator");
18
18
  var _now = require("../../../common/timing/now");
19
19
  var _agentConstants = require("../../../common/constants/agent-constants");
20
+ var _events = require("../../../common/constants/events");
20
21
  var _cleanUrl = require("../../../common/url/clean-url");
21
22
  var _featureGates = require("../../utils/feature-gates");
22
23
  var _constants3 = require("../../../loaders/api/constants");
24
+ var _obfuscate = require("../../../common/util/obfuscate");
23
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); } /**
24
26
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
25
27
  * SPDX-License-Identifier: Apache-2.0
@@ -33,6 +35,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
33
35
  // pass the recorder into the aggregator
34
36
  constructor(agentRef, args) {
35
37
  super(agentRef, _constants.FEATURE_NAME);
38
+
39
+ // Create obfuscator for session replay query params
40
+ this.obfuscator = new _obfuscate.Obfuscator(agentRef, _events.EVENT_TYPES.SR);
41
+
36
42
  /** Set once the recorder has fully initialized after flag checks and sampling */
37
43
  this.initialized = false;
38
44
  /** Set once the feature has been "aborted" to prevent other side-effects from continuing */
@@ -310,7 +316,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
310
316
  return {
311
317
  qs: {
312
318
  browser_monitoring_key: this.agentRef.info.licenseKey,
313
- type: 'SessionReplay',
319
+ type: _events.EVENT_TYPES.SR,
314
320
  app_id: this.agentRef.info.applicationID,
315
321
  protocol_version: '0',
316
322
  timestamp: firstTimestamp,
@@ -11,9 +11,10 @@ var _storage = require("./trace/storage");
11
11
  var _encode = require("../../../common/url/encode");
12
12
  var _runtime = require("../../../common/constants/runtime");
13
13
  var _constants2 = require("../../../common/session/constants");
14
- var _traverse = require("../../../common/util/traverse");
14
+ var _obfuscate = require("../../../common/util/obfuscate");
15
15
  var _cleanUrl = require("../../../common/url/clean-url");
16
16
  var _console = require("../../../common/util/console");
17
+ var _events = require("../../../common/constants/events");
17
18
  /**
18
19
  * Copyright 2020-2026 New Relic, Inc. All rights reserved.
19
20
  * SPDX-License-Identifier: Apache-2.0
@@ -27,6 +28,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
27
28
  super(agentRef, _constants.FEATURE_NAME);
28
29
  this.harvestOpts.raw = true;
29
30
 
31
+ // Create obfuscator for session trace nodes
32
+ this.obfuscator = new _obfuscate.Obfuscator(agentRef, _events.EVENT_TYPES.ST);
33
+
30
34
  /** Tied to the entitlement flag response from BCS. Will short circuit operations of the agg if false */
31
35
  this.entitled = undefined;
32
36
  /** A flag used to decide if the 30 node threshold should be ignored on the first harvest to ensure sending on the first payload */
@@ -113,7 +117,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
113
117
  serializer(stns) {
114
118
  if (!stns.length) return; // there are no processed nodes
115
119
  this.everHarvested = true;
116
- return (0, _traverse.applyFnToProps)(stns, this.obfuscator.obfuscateString.bind(this.obfuscator), 'string');
120
+ return this.obfuscator.traverseAndObfuscateEvents(stns);
117
121
  }
118
122
  queryStringsBuilder(stns) {
119
123
  const firstSessionHarvest = !this.agentRef.runtime.session.state.traceHarvestStarted;
@@ -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");
@@ -183,8 +182,8 @@ class AggregateBase extends _featureBase.FeatureBase {
183
182
  * This method should run after checkConfiguration, which may reset the agent's info/runtime object that is used here.
184
183
  */
185
184
  doOnceForAllAggregate(agentRef) {
186
- if (!agentRef.runtime.obfuscator) agentRef.runtime.obfuscator = new _obfuscate.Obfuscator(agentRef);
187
- this.obfuscator = agentRef.runtime.obfuscator;
185
+ // Note: obfuscator is now created per-feature for their specific event types
186
+
188
187
  if (!agentRef.runtime.harvester) agentRef.runtime.harvester = new _harvester.Harvester(agentRef);
189
188
  }
190
189
 
@@ -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";
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";
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
+ };
@@ -16,6 +16,7 @@ import { warn } from '../util/console';
16
16
  import { stringify } from '../util/stringify';
17
17
  import { getSubmitMethod, xhr as xhrMethod, xhrFetch as fetchMethod } from '../util/submit-data';
18
18
  import { dispatchGlobalEvent } from '../dispatch/global-event';
19
+ import { Obfuscator } from '../util/obfuscate';
19
20
  const RETRY = 'Harvester/Retry/';
20
21
  const RETRY_ATTEMPTED = RETRY + 'Attempted/';
21
22
  const RETRY_FAILED = RETRY + 'Failed/';
@@ -25,6 +26,10 @@ export class Harvester {
25
26
  initializedAggregates = [];
26
27
  constructor(agentRef) {
27
28
  this.agentRef = agentRef;
29
+
30
+ // Create obfuscator for harvest metadata (referrer URL, etc.)
31
+ // No event type specified - applies to all harvests regardless of feature
32
+ this.obfuscator = new Obfuscator(agentRef);
28
33
  subscribeToEOL(() => {
29
34
  // do one last harvest round or check
30
35
  this.initializedAggregates.forEach(aggregateInst => {
@@ -71,6 +76,7 @@ export class Harvester {
71
76
  payload: output.payload,
72
77
  localOpts,
73
78
  submitMethod,
79
+ harvesterObfuscator: this.obfuscator,
74
80
  cbFinished,
75
81
  raw: aggregateInst.harvestOpts.raw,
76
82
  featureName: aggregateInst.featureName,
@@ -119,7 +125,8 @@ export function send(agentRef, {
119
125
  cbFinished,
120
126
  raw,
121
127
  featureName,
122
- endpointVersion = 1
128
+ endpointVersion = 1,
129
+ harvesterObfuscator
123
130
  }) {
124
131
  if (!agentRef.info.errorBeacon) return false;
125
132
  let {
@@ -136,7 +143,7 @@ export function send(agentRef, {
136
143
  const protocol = agentRef.init.ssl === false ? 'http' : 'https';
137
144
  const perceivedBeacon = agentRef.init.proxy.beacon || agentRef.info.errorBeacon;
138
145
  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) : '';
146
+ const baseParams = !raw ? baseQueryString(agentRef, qs, endpoint, harvesterObfuscator) : '';
140
147
  let payloadParams = obj(qs, agentRef.runtime.maxBytes);
141
148
  if (baseParams === '' && payloadParams.startsWith('&')) {
142
149
  payloadParams = payloadParams.substring(1);
@@ -284,8 +291,9 @@ function cleanPayload(payload = {}) {
284
291
  }
285
292
 
286
293
  // The stuff that gets sent every time.
287
- function baseQueryString(agentRef, qs, endpoint) {
288
- const ref = agentRef.runtime.obfuscator.obfuscateString(cleanURL('' + globalScope.location));
294
+ function baseQueryString(agentRef, qs, endpoint, harvesterObfuscator) {
295
+ const cleanedURL = cleanURL('' + globalScope.location);
296
+ const ref = harvesterObfuscator?.obfuscateString(cleanedURL) ?? cleanedURL;
289
297
  const session = agentRef.runtime.session;
290
298
  const hr = !!session?.state.sessionReplaySentFirstChunk && session?.state.sessionReplayMode === 1 && endpoint !== JSERRORS;
291
299
  const ht = !!session?.state.traceHarvestStarted && session?.state.sessionTraceMode === 1 && ![LOGS, BLOBS].includes(endpoint);
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Copyright 2020-2026 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { stringify } from '../util/stringify';
7
+ import { CAPTURE_PAYLOAD_SETTINGS } from '../../features/ajax/constants';
8
+
9
+ /**
10
+ * Determines whether payload data should be captured based on the capture mode setting,
11
+ * HTTP status code, and GraphQL error status.
12
+ * @param {string} captureMode - The capture mode setting ('none', 'all', or 'failures')
13
+ * @param {number} statusCode - The HTTP status code
14
+ * @param {boolean} hasGQLErrors - Whether the response contains GraphQL errors
15
+ * @returns {boolean} True if payload should be captured
16
+ */
17
+ export function canCapturePayload(captureMode, statusCode, hasGQLErrors) {
18
+ if (captureMode === CAPTURE_PAYLOAD_SETTINGS.ALL) return true;
19
+ if (!captureMode || captureMode === CAPTURE_PAYLOAD_SETTINGS.NONE) return false;
20
+
21
+ // Default "failures" mode
22
+ return statusCode === 0 || statusCode >= 400 || hasGQLErrors === true;
23
+ }
24
+
25
+ /**
26
+ * Parses a query string into an object of key-value pairs.
27
+ * @param {string} search a query string starting with "?" or without (ex. new URL(...).search)
28
+ * @returns {Object|undefined} Parsed query parameters as key-value pairs. Returns undefined if no valid parameters are found.
29
+ */
30
+ export function parseQueryString(search) {
31
+ if (!search || search.length === 0) return;
32
+ const queryParams = {};
33
+ try {
34
+ const searchParams = new URLSearchParams(search);
35
+ searchParams.forEach(function (value, key) {
36
+ queryParams[key] = value;
37
+ });
38
+ } catch (e) {
39
+ // Fallback for environments without URLSearchParams
40
+ }
41
+ return queryParams;
42
+ }
43
+
44
+ /**
45
+ * Determines if the given content type is likely to be human-readable (text-based).
46
+ * @param {Object} headers - The headers object containing content-type
47
+ * @param {*} data - The data to check
48
+ * @returns {boolean} True if the content type is human-readable (text-based)
49
+ */
50
+ export function isLikelyHumanReadable(headers, data) {
51
+ if (!headers) return typeof data === 'string';
52
+ var contentType = headers['content-type'];
53
+ if (!contentType) return typeof data === 'string';
54
+ // Normalize to lowercase and extract the mime type (ignore charset, etc.)
55
+ var mimeType = contentType.toLowerCase().split(';')[0].trim();
56
+
57
+ // Check for text/* types
58
+ if (mimeType.indexOf('text/') === 0) return true;
59
+
60
+ // Check for specific application/* types
61
+ var readableAppTypes = ['/json', '/xml', '/xhtml+xml', '/ld+json', '/yaml', '/x-www-form-urlencoded'];
62
+ for (var i = 0; i < readableAppTypes.length; i++) {
63
+ if (mimeType === 'application' + readableAppTypes[i]) return true;
64
+ }
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * Truncates a string to ensure its UTF-8 byte length does not exceed 4092 bytes. If truncation is necessary,
70
+ * the string is cut off at a character boundary to avoid breaking multi-byte characters and " ..." is appended to indicate truncation.
71
+ * If not a string, it is first converted to a string using JSON.stringify.
72
+ * @param {*} data The data to truncate.
73
+ * @returns {string}
74
+ */
75
+ export function truncateAsString(data) {
76
+ if (!data) return data;
77
+ try {
78
+ if (typeof data !== 'string') data = stringify(data);
79
+ let bytes = 0;
80
+ let i = 0;
81
+ let needsEllipsis = false;
82
+ while (i < data.length) {
83
+ const c = data.charCodeAt(i);
84
+ const charBytes = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0xD800 || c >= 0xE000 ? 3 : 4;
85
+ if (bytes + charBytes > 4092) {
86
+ needsEllipsis = true;
87
+ break;
88
+ }
89
+ bytes += charBytes;
90
+ i += charBytes === 4 ? 2 : 1;
91
+ }
92
+ return data.slice(0, i) + (needsEllipsis ? ' ...' : '');
93
+ } catch (e) {
94
+ return data;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Creates string adder functions for BEL serialization with obfuscation and optional truncation.
100
+ * This ensures a single string table is used while providing separate handling for regular vs payload attributes.
101
+ * @param {Function} getAddStringContext - Function that creates a new string table context
102
+ * @param {Object} obfuscator - Optional obfuscator instance for string obfuscation
103
+ * @returns {{addString: Function, addStringWithTruncation: Function}} Object containing both string adder functions
104
+ */
105
+ export function createStringAdders(getAddStringContext, obfuscator) {
106
+ const addStringRaw = getAddStringContext();
107
+ const processString = (str, shouldTruncate) => {
108
+ if (typeof str === 'undefined' || str === '') return addStringRaw(str);
109
+ if (typeof str !== 'string') str = stringify(str);
110
+ const obfuscated = obfuscator?.obfuscateString(str) ?? str;
111
+ const processed = shouldTruncate ? truncateAsString(obfuscated) : obfuscated;
112
+ return addStringRaw(processed);
113
+ };
114
+ return {
115
+ addString: str => processString(str, false),
116
+ addStringWithTruncation: str => processString(str, true)
117
+ };
118
+ }
@@ -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
 
@@ -15,13 +15,14 @@ export function numeric(n, noDefault) {
15
15
  }
16
16
  return n === undefined || n === 0 ? '' : Math.floor(n).toString(36);
17
17
  }
18
- export function getAddStringContext(obfuscator) {
18
+ export function getAddStringContext(obfuscator, truncator) {
19
19
  let stringTableIdx = 0;
20
20
  const stringTable = Object.prototype.hasOwnProperty.call(Object, 'create') ? Object.create(null) : {};
21
21
  return addString;
22
22
  function addString(str) {
23
23
  if (typeof str === 'undefined' || str === '') return '';
24
- str = obfuscator.obfuscateString(String(str));
24
+ str = obfuscator?.obfuscateString(String(str)) ?? String(str);
25
+ str = truncator?.(str) ?? str;
25
26
  if (hasOwnProp.call(stringTable, str)) {
26
27
  return numeric(stringTable[str], true);
27
28
  } else {
@@ -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
 
@@ -12,7 +12,7 @@ import { stringify } from './stringify';
12
12
  * @returns {(number|undefined)} - The size of the data or undefined if size cannot be determined.
13
13
  */
14
14
  export function dataSize(data) {
15
- if (typeof data === 'string' && data.length) return data.length;
15
+ if (typeof data === 'string') return data.length;
16
16
  if (typeof data !== 'object') return undefined;
17
17
  // eslint-disable-next-line
18
18
  if (typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer && data.byteLength) return data.byteLength;