@newrelic/browser-agent 1.237.0 → 1.238.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 (116) hide show
  1. package/dist/cjs/common/constants/env.cdn.js +1 -1
  2. package/dist/cjs/common/constants/env.npm.js +1 -1
  3. package/dist/cjs/common/deny-list/deny-list.js +1 -1
  4. package/dist/cjs/common/event-emitter/contextual-ee.js +18 -26
  5. package/dist/cjs/common/event-emitter/event-context.js +12 -0
  6. package/dist/cjs/common/harvest/harvest.js +4 -4
  7. package/dist/cjs/common/ids/bundle-id.js +19 -0
  8. package/dist/cjs/common/wrap/wrap-events.js +3 -2
  9. package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
  10. package/dist/cjs/common/wrap/wrap-function.js +15 -46
  11. package/dist/cjs/common/wrap/wrap-mutation.js +1 -2
  12. package/dist/cjs/common/wrap/wrap-promise.js +2 -3
  13. package/dist/cjs/common/wrap/wrap-xhr.js +23 -27
  14. package/dist/cjs/features/ajax/instrument/distributed-tracing.js +0 -4
  15. package/dist/cjs/features/ajax/instrument/index.js +19 -9
  16. package/dist/cjs/features/metrics/aggregate/index.js +8 -0
  17. package/dist/cjs/features/session_replay/aggregate/index.js +2 -0
  18. package/dist/cjs/features/session_trace/aggregate/index.js +14 -8
  19. package/dist/cjs/features/spa/aggregate/index.js +1 -1
  20. package/dist/cjs/loaders/agent-base.js +12 -0
  21. package/dist/cjs/loaders/api/api.js +14 -1
  22. package/dist/cjs/loaders/api/interaction-types.js +11 -4
  23. package/dist/cjs/loaders/configure/configure.js +2 -1
  24. package/dist/esm/common/constants/env.cdn.js +1 -1
  25. package/dist/esm/common/constants/env.npm.js +1 -1
  26. package/dist/esm/common/deny-list/deny-list.js +1 -1
  27. package/dist/esm/common/event-emitter/contextual-ee.js +16 -23
  28. package/dist/esm/common/event-emitter/event-context.js +5 -0
  29. package/dist/esm/common/harvest/harvest.js +4 -4
  30. package/dist/esm/common/ids/bundle-id.js +13 -0
  31. package/dist/esm/common/wrap/wrap-events.js +4 -3
  32. package/dist/esm/common/wrap/wrap-fetch.js +2 -4
  33. package/dist/esm/common/wrap/wrap-function.js +15 -44
  34. package/dist/esm/common/wrap/wrap-mutation.js +2 -3
  35. package/dist/esm/common/wrap/wrap-promise.js +3 -4
  36. package/dist/esm/common/wrap/wrap-xhr.js +23 -27
  37. package/dist/esm/features/ajax/instrument/distributed-tracing.js +0 -4
  38. package/dist/esm/features/ajax/instrument/index.js +20 -10
  39. package/dist/esm/features/metrics/aggregate/index.js +8 -0
  40. package/dist/esm/features/session_replay/aggregate/index.js +2 -0
  41. package/dist/esm/features/session_trace/aggregate/index.js +14 -8
  42. package/dist/esm/features/spa/aggregate/index.js +1 -1
  43. package/dist/esm/loaders/agent-base.js +12 -0
  44. package/dist/esm/loaders/api/api.js +14 -1
  45. package/dist/esm/loaders/api/interaction-types.js +11 -4
  46. package/dist/esm/loaders/configure/configure.js +3 -2
  47. package/dist/types/common/event-emitter/contextual-ee.d.ts +22 -2
  48. package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
  49. package/dist/types/common/event-emitter/event-context.d.ts +5 -0
  50. package/dist/types/common/event-emitter/event-context.d.ts.map +1 -0
  51. package/dist/types/common/event-emitter/register-handler.d.ts +1 -1
  52. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  53. package/dist/types/common/ids/bundle-id.d.ts +5 -0
  54. package/dist/types/common/ids/bundle-id.d.ts.map +1 -0
  55. package/dist/types/common/session/session-entity.d.ts +6 -6
  56. package/dist/types/common/window/nreum.d.ts +2 -2
  57. package/dist/types/common/wrap/wrap-events.d.ts.map +1 -1
  58. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  59. package/dist/types/common/wrap/wrap-function.d.ts +1 -19
  60. package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
  61. package/dist/types/common/wrap/wrap-mutation.d.ts.map +1 -1
  62. package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
  63. package/dist/types/common/wrap/wrap-xhr.d.ts.map +1 -1
  64. package/dist/types/features/ajax/instrument/distributed-tracing.d.ts +1 -1
  65. package/dist/types/features/ajax/instrument/distributed-tracing.d.ts.map +1 -1
  66. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +5 -5
  67. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  68. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  69. package/dist/types/features/session_trace/aggregate/index.d.ts +5 -0
  70. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  71. package/dist/types/loaders/agent-base.d.ts +9 -0
  72. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  73. package/dist/types/loaders/api/api.d.ts +6 -0
  74. package/dist/types/loaders/api/api.d.ts.map +1 -1
  75. package/dist/types/loaders/api/interaction-types.d.ts +18 -7
  76. package/dist/types/loaders/api/interaction-types.d.ts.map +1 -1
  77. package/dist/types/loaders/configure/configure.d.ts +1 -0
  78. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  79. package/dist/types/loaders/features/features.d.ts +9 -9
  80. package/dist/types/loaders/micro-agent.d.ts +1 -1
  81. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  82. package/package.json +22 -27
  83. package/src/common/deny-list/deny-list.js +1 -1
  84. package/src/common/deny-list/deny-list.test.js +103 -30
  85. package/src/common/event-emitter/{contextual-ee.test.js → contextual-ee.component-test.js} +15 -32
  86. package/src/common/event-emitter/contextual-ee.js +20 -31
  87. package/src/common/event-emitter/event-context.js +5 -0
  88. package/src/common/harvest/harvest.js +4 -4
  89. package/src/common/harvest/harvest.test.js +1 -1
  90. package/src/common/ids/__mocks__/bundle-id.js +2 -0
  91. package/src/common/ids/__mocks__/unique-id.js +17 -0
  92. package/src/common/ids/bundle-id.js +13 -0
  93. package/src/common/url/__mocks__/parse-url.js +15 -0
  94. package/src/common/util/__mocks__/get-or-set.js +5 -0
  95. package/src/common/window/__mocks__/nreum.js +10 -0
  96. package/src/common/wrap/wrap-events.js +4 -3
  97. package/src/common/wrap/wrap-fetch.js +2 -4
  98. package/src/common/wrap/wrap-function.js +16 -44
  99. package/src/common/wrap/wrap-mutation.js +2 -3
  100. package/src/common/wrap/{wrap-promise.test.js → wrap-promise.component-test.js} +2 -32
  101. package/src/common/wrap/wrap-promise.js +3 -4
  102. package/src/common/wrap/wrap-xhr.js +24 -28
  103. package/src/features/ajax/instrument/distributed-tracing.js +0 -4
  104. package/src/features/ajax/instrument/distributed-tracing.test.js +375 -0
  105. package/src/features/ajax/instrument/index.js +22 -10
  106. package/src/features/metrics/aggregate/index.js +8 -0
  107. package/src/features/session_replay/aggregate/index.js +2 -0
  108. package/src/features/session_trace/aggregate/index.js +16 -7
  109. package/src/features/spa/aggregate/index.js +1 -1
  110. package/src/loaders/agent-base.js +12 -0
  111. package/src/loaders/api/api.component-test.js +45 -0
  112. package/src/loaders/api/api.js +14 -1
  113. package/src/loaders/api/interaction-types.js +11 -4
  114. package/src/loaders/configure/configure.js +11 -2
  115. /package/src/common/url/{encode.component-test.js → encode.test.js} +0 -0
  116. /package/src/common/url/{protocol.component-test.js → protocol.test.js} +0 -0
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.237.0";
15
+ const VERSION = "1.238.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -12,7 +12,7 @@ exports.VERSION = exports.DIST_METHOD = exports.BUILD_ENV = void 0;
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = "1.237.0";
15
+ const VERSION = "1.238.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -64,7 +64,7 @@ function setDenyList(denyListConfig) {
64
64
  host = url;
65
65
  pathname = '';
66
66
  }
67
- let [hostname, port] = host.split(':');
67
+ let [hostname] = host.split(':');
68
68
  denyList.push({
69
69
  hostname,
70
70
  pathname
@@ -3,30 +3,29 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ee = void 0;
7
- exports.getOrSetContext = getOrSetContext;
6
+ exports.ee = exports.contextId = void 0;
8
7
  var _nreum = require("../window/nreum");
9
8
  var _getOrSet = require("../util/get-or-set");
10
- var _mapOwn = require("../util/map-own");
11
9
  var _config = require("../config/config");
10
+ var _eventContext = require("./event-context");
11
+ var _bundleId = require("../ids/bundle-id");
12
12
  /*
13
13
  * Copyright 2020 New Relic Corporation. All rights reserved.
14
14
  * SPDX-License-Identifier: Apache-2.0
15
15
  */
16
16
 
17
- var ctxId = 'nr@context';
18
-
17
+ // create a unique id to store event context data for the current agent bundle
18
+ const contextId = "nr@context:".concat(_bundleId.bundleId);
19
19
  // create global emitter instance that can be shared among bundles
20
- let nr = (0, _nreum.gosNREUM)();
21
- var globalInstance;
20
+ exports.contextId = contextId;
21
+ const globalInstance = ee(undefined, 'globalEE');
22
+
23
+ // Only override the exposed event emitter if one has not already been exposed
22
24
  exports.ee = globalInstance;
23
- if (nr.ee) {
24
- exports.ee = globalInstance = nr.ee;
25
- } else {
26
- exports.ee = globalInstance = ee(undefined, 'globalEE');
25
+ const nr = (0, _nreum.gosNREUM)();
26
+ if (!nr.ee) {
27
27
  nr.ee = globalInstance;
28
28
  }
29
- function EventContext() {}
30
29
  function ee(old, debugId) {
31
30
  var handlers = {};
32
31
  var bufferGroupMap = {};
@@ -60,12 +59,12 @@ function ee(old, debugId) {
60
59
  };
61
60
  return emitter;
62
61
  function context(contextOrStore) {
63
- if (contextOrStore && contextOrStore instanceof EventContext) {
62
+ if (contextOrStore && contextOrStore instanceof _eventContext.EventContext) {
64
63
  return contextOrStore;
65
64
  } else if (contextOrStore) {
66
- return (0, _getOrSet.getOrSet)(contextOrStore, ctxId, getNewContext);
65
+ return (0, _getOrSet.getOrSet)(contextOrStore, contextId, () => new _eventContext.EventContext(contextId));
67
66
  } else {
68
- return getNewContext();
67
+ return new _eventContext.EventContext(contextId);
69
68
  }
70
69
  }
71
70
  function emit(type, args, contextOrStore, force, bubble) {
@@ -112,12 +111,13 @@ function ee(old, debugId) {
112
111
  return emitters[name] = emitters[name] || ee(emitter, name);
113
112
  }
114
113
  function bufferEventsByGroup(types, group) {
115
- var eventBuffer = getBuffer();
114
+ const eventBuffer = getBuffer();
115
+ group = group || 'feature';
116
116
 
117
117
  // do not buffer events if agent has been aborted
118
118
  if (emitter.aborted) return;
119
- (0, _mapOwn.mapOwn)(types, function (i, type) {
120
- group = group || 'feature';
119
+ Object.entries(types || {}).forEach(_ref => {
120
+ let [_, type] = _ref;
121
121
  bufferGroupMap[type] = group;
122
122
  if (!(group in eventBuffer)) {
123
123
  eventBuffer[group] = [];
@@ -135,14 +135,6 @@ function ee(old, debugId) {
135
135
  return emitter.backlog;
136
136
  }
137
137
  }
138
-
139
- // get context object from store object, or create if does not exist
140
- function getOrSetContext(obj) {
141
- return (0, _getOrSet.getOrSet)(obj, ctxId, getNewContext);
142
- }
143
- function getNewContext() {
144
- return new EventContext();
145
- }
146
138
  function abort() {
147
139
  globalInstance.aborted = true;
148
140
  globalInstance.backlog = {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.EventContext = void 0;
7
+ class EventContext {
8
+ constructor(contextId) {
9
+ this.contextId = contextId;
10
+ }
11
+ }
12
+ exports.EventContext = EventContext;
@@ -56,7 +56,8 @@ class Harvest extends _sharedContext.SharedContext {
56
56
  isFinalHarvest: spec.opts?.unload
57
57
  });
58
58
  const options = {
59
- retry: !spec.opts?.unload && submitMethod === submitData.xhr
59
+ retry: !spec.opts?.unload && submitMethod === submitData.xhr,
60
+ isFinalHarvest: spec.opts?.unload === true
60
61
  };
61
62
  const payload = this.createPayload(spec.endpoint, options);
62
63
  const caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this);
@@ -258,9 +259,8 @@ class Harvest extends _sharedContext.SharedContext {
258
259
  cleanPayload() {
259
260
  let payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
260
261
  const clean = input => {
261
- if (typeof Uint8Array !== 'undefined' && input instanceof Uint8Array || typeof input === 'string') {
262
- return input.length > 0 ? input : null;
263
- }
262
+ if (typeof Uint8Array !== 'undefined' && input instanceof Uint8Array || Array.isArray(input)) return input;
263
+ if (typeof input === 'string') return input.length > 0 ? input : null;
264
264
  return Object.entries(input || {}).reduce((accumulator, _ref2) => {
265
265
  let [key, value] = _ref2;
266
266
  if (typeof value === 'number' || typeof value === 'string' && value.length > 0 || typeof value === 'object' && Object.keys(value || {}).length > 0) {
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.bundleId = void 0;
7
+ var _uniqueId = require("./unique-id");
8
+ /**
9
+ * @file Contains a unique identifier for the running agent bundle
10
+ * when loaded.
11
+ * @copyright 2023 New Relic Corporation. All rights reserved.
12
+ * @license Apache-2.0
13
+ */
14
+
15
+ /**
16
+ * Provides a unique id for the current agent bundle
17
+ */
18
+ const bundleId = (0, _uniqueId.generateUuid)();
19
+ exports.bundleId = bundleId;
@@ -20,9 +20,10 @@ var _runtime = require("../constants/runtime");
20
20
  */
21
21
 
22
22
  const wrapped = {};
23
- const XHR = XMLHttpRequest;
23
+ const XHR = _runtime.globalScope.XMLHttpRequest;
24
24
  const ADD_EVENT_LISTENER = 'addEventListener';
25
25
  const REMOVE_EVENT_LISTENER = 'removeEventListener';
26
+ const flag = "nr@wrapped:".concat(_contextualEe.contextId);
26
27
 
27
28
  /**
28
29
  * Wraps `addEventListener` and `removeEventListener` on: global scope; the prototype of `XMLHttpRequest`, and
@@ -51,7 +52,7 @@ function wrapEvents(sharedEE) {
51
52
  if (originalListener === null || typeof originalListener !== 'function' && typeof originalListener !== 'object') {
52
53
  return;
53
54
  }
54
- var wrapped = (0, _getOrSet.getOrSet)(originalListener, 'nr@wrapped', function () {
55
+ var wrapped = (0, _getOrSet.getOrSet)(originalListener, flag, function () {
55
56
  var listener = {
56
57
  object: wrapHandleEvent,
57
58
  function: originalListener
@@ -7,7 +7,6 @@ exports.scopedEE = scopedEE;
7
7
  exports.wrapFetch = wrapFetch;
8
8
  var _contextualEe = require("../event-emitter/contextual-ee");
9
9
  var _runtime = require("../constants/runtime");
10
- var _wrapFunction = require("./wrap-function");
11
10
  /*
12
11
  * Copyright 2020 New Relic Corporation. All rights reserved.
13
12
  * SPDX-License-Identifier: Apache-2.0
@@ -23,7 +22,6 @@ var bodyMethods = ['arrayBuffer', 'blob', 'json', 'text', 'formData'];
23
22
  var Req = _runtime.globalScope.Request;
24
23
  var Res = _runtime.globalScope.Response;
25
24
  var proto = 'prototype';
26
- var ctxId = 'nr@context';
27
25
  const wrapped = {};
28
26
 
29
27
  /**
@@ -80,7 +78,7 @@ function wrapFetch(sharedEE) {
80
78
  // we are wrapping args in an array so we can preserve the reference
81
79
  ee.emit(prefix + 'before-start', [args], ctx);
82
80
  var dtPayload;
83
- if (ctx[ctxId] && ctx[ctxId].dt) dtPayload = ctx[ctxId].dt;
81
+ if (ctx[_contextualEe.contextId] && ctx[_contextualEe.contextId].dt) dtPayload = ctx[_contextualEe.contextId].dt;
84
82
  var origPromiseFromFetch = fn.apply(this, args);
85
83
  ee.emit(prefix + 'start', [args, dtPayload], origPromiseFromFetch);
86
84
 
@@ -5,9 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.createWrapperWithEmitter = createWrapperWithEmitter;
7
7
  exports.flag = exports.default = void 0;
8
- exports.wrapFunction = wrapFunction;
9
- exports.wrapInPlace = wrapInPlace;
10
8
  var _contextualEe = require("../event-emitter/contextual-ee");
9
+ var _bundleId = require("../ids/bundle-id");
11
10
  /*
12
11
  * Copyright 2020 New Relic Corporation. All rights reserved.
13
12
  * SPDX-License-Identifier: Apache-2.0
@@ -16,7 +15,7 @@ var _contextualEe = require("../event-emitter/contextual-ee");
16
15
  * @file Provides helper functions for wrapping functions in various scenarios.
17
16
  */
18
17
 
19
- const flag = 'nr@original';
18
+ const flag = "nr@original:".concat(_bundleId.bundleId);
20
19
 
21
20
  /**
22
21
  * A convenience alias of `hasOwnProperty`.
@@ -110,25 +109,23 @@ function createWrapperWithEmitter(emitter, always) {
110
109
 
111
110
  /**
112
111
  * Creates wrapper functions around each of an array of methods on a specified object.
113
- * @param {Object} obj - The object to which the specified methods belong.
114
- * @param {string[]} methods - An array of method names to be wrapped.
115
- * @param {string} [prefix=''] - A prefix to add to the names of emitted events. If `-` is the first character, also
116
- * adds the method name before the prefix.
117
- * @param {function|object} [getContext] - The function or object that will serve as the 'this' context for handlers
118
- * of events emitted by this wrapper.
119
- * @param {boolean} [bubble=false] - If `true`, emitted events should also bubble up to the old emitter upon which
120
- * the `emitter` in the current scope was based (if it defines one).
112
+ * @param {Object} obj The object to which the specified methods belong.
113
+ * @param {string[]} methods An array of method names to be wrapped.
114
+ * @param {string} [prefix=''] A prefix to add to the names of emitted events. If `-` is the first character, also
115
+ * adds the method name before the prefix.
116
+ * @param {function|object} [getContext] The function or object that will serve as the 'this' context for handlers
117
+ * of events emitted by this wrapper.
118
+ * @param {boolean} [bubble=false] If `true`, emitted events should also bubble up to the old emitter upon which
119
+ * the `emitter` in the current scope was based (if it defines one).
121
120
  */
122
121
  function inPlace(obj, methods, prefix, getContext, bubble) {
123
122
  if (!prefix) prefix = '';
123
+
124
124
  // If prefix starts with '-' set this boolean to add the method name to the prefix before passing each one to wrap.
125
- var prependMethodPrefix = prefix.charAt(0) === '-';
126
- var fn;
127
- var method;
128
- var i;
129
- for (i = 0; i < methods.length; i++) {
130
- method = methods[i];
131
- fn = obj[method];
125
+ const prependMethodPrefix = prefix.charAt(0) === '-';
126
+ for (let i = 0; i < methods.length; i++) {
127
+ const method = methods[i];
128
+ const fn = obj[method];
132
129
 
133
130
  // Unless fn is both wrappable and unwrapped, bail so we don't add extra properties with undefined values.
134
131
  if (notWrappable(fn)) continue;
@@ -222,32 +219,4 @@ function copy(from, to, emitter) {
222
219
  */
223
220
  function notWrappable(fn) {
224
221
  return !(fn && fn instanceof Function && fn.apply && !fn[flag]);
225
- }
226
-
227
- /**
228
- * Creates a wrapped version of a function using a specified wrapper function. The new wrapped function references the
229
- * original function. Also copies the properties of the original function to the wrapped function.
230
- * @param {function} fn - A function to be wrapped.
231
- * @param {function} wrapper - A higher order function that returns a new function, which executes the function passed
232
- * to the higher order function as an argument.
233
- * @returns {function} A wrapped function with an internal reference to the original function.
234
- */
235
- function wrapFunction(fn, wrapper) {
236
- var wrapped = wrapper(fn);
237
- wrapped[flag] = fn;
238
- copy(fn, wrapped, _contextualEe.ee);
239
- return wrapped;
240
- }
241
-
242
- /**
243
- * Replaces a function with a wrapped version of itself. To preserve object references, rather than taking the function
244
- * itself as an argument, takes the object on which the particular named function is a property.
245
- * @param {Object} obj - The object on which the named function is a property.
246
- * @param {string} fnName - The name of the function to be wrapped.
247
- * @param {function} wrapper - A higher order function that returns a new function, which executes the function passed
248
- * to the higher order function as an argument.
249
- */
250
- function wrapInPlace(obj, fnName, wrapper) {
251
- var fn = obj[fnName];
252
- obj[fnName] = wrapFunction(fn, wrapper);
253
222
  }
@@ -7,7 +7,6 @@ exports.scopedEE = scopedEE;
7
7
  exports.wrapMutation = wrapMutation;
8
8
  var _contextualEe = require("../event-emitter/contextual-ee");
9
9
  var _wrapFunction = require("./wrap-function");
10
- var _config = require("../config/config");
11
10
  var _runtime = require("../constants/runtime");
12
11
  /*
13
12
  * Copyright 2020 New Relic Corporation. All rights reserved.
@@ -36,7 +35,7 @@ function wrapMutation(sharedEE) {
36
35
  wrapped[ee.debugId] = true; // otherwise, first feature to wrap mutations
37
36
 
38
37
  var wrapFn = (0, _wrapFunction.createWrapperWithEmitter)(ee);
39
- var OriginalObserver = _config.originals.MO;
38
+ var OriginalObserver = _runtime.globalScope.MutationObserver;
40
39
  if (OriginalObserver) {
41
40
  window.MutationObserver = function WrappedMutationObserver(cb) {
42
41
  if (this instanceof OriginalObserver) {
@@ -7,7 +7,6 @@ exports.scopedEE = scopedEE;
7
7
  exports.wrapPromise = wrapPromise;
8
8
  var _wrapFunction = require("./wrap-function");
9
9
  var _contextualEe = require("../event-emitter/contextual-ee");
10
- var _config = require("../config/config");
11
10
  var _runtime = require("../constants/runtime");
12
11
  /*
13
12
  * Copyright 2020 New Relic Corporation. All rights reserved.
@@ -35,9 +34,9 @@ function wrapPromise(sharedEE) {
35
34
  if (wrapped[promiseEE.debugId]) return promiseEE;
36
35
  wrapped[promiseEE.debugId] = true; // otherwise, first feature to wrap promise
37
36
 
38
- var getContext = _contextualEe.getOrSetContext;
37
+ var getContext = promiseEE.context;
39
38
  var promiseWrapper = (0, _wrapFunction.createWrapperWithEmitter)(promiseEE);
40
- var prevPromiseObj = _config.originals.PR;
39
+ var prevPromiseObj = _runtime.globalScope.Promise;
41
40
  if (prevPromiseObj) {
42
41
  // ensure there's a Promise API (native or otherwise) to even wrap
43
42
  wrap();
@@ -9,7 +9,6 @@ var _wrapEvents = require("./wrap-events");
9
9
  var _contextualEe = require("../event-emitter/contextual-ee");
10
10
  var _eventListenerOpts = require("../event-listener/event-listener-opts");
11
11
  var _wrapFunction = require("./wrap-function");
12
- var _config = require("../config/config");
13
12
  var _runtime = require("../constants/runtime");
14
13
  var _console = require("../util/console");
15
14
  /*
@@ -42,32 +41,28 @@ function wrapXhr(sharedEE) {
42
41
 
43
42
  (0, _wrapEvents.wrapEvents)(baseEE); // wrap-events patches XMLHttpRequest.prototype.addEventListener for us
44
43
  var wrapFn = (0, _wrapFunction.createWrapperWithEmitter)(ee);
45
- var OrigXHR = _config.originals.XHR;
46
- var MutationObserver = _config.originals.MO;
47
- var Promise = _config.originals.PR;
48
- var setImmediate = _config.originals.SI;
44
+ var OrigXHR = _runtime.globalScope.XMLHttpRequest;
45
+ var MutationObserver = _runtime.globalScope.MutationObserver;
46
+ var Promise = _runtime.globalScope.Promise;
47
+ var setImmediate = _runtime.globalScope.setInterval;
49
48
  var READY_STATE_CHANGE = 'readystatechange';
50
49
  var handlers = ['onload', 'onerror', 'onabort', 'onloadstart', 'onloadend', 'onprogress', 'ontimeout'];
51
50
  var pendingXhrs = [];
52
- var activeListeners = _runtime.globalScope.XMLHttpRequest.listeners;
53
51
  var XHR = _runtime.globalScope.XMLHttpRequest = newXHR;
54
52
  function newXHR(opts) {
55
- var xhr = new OrigXHR(opts);
56
- this.listeners = activeListeners ? [...activeListeners, intercept] : [intercept];
57
- function intercept() {
53
+ const xhr = new OrigXHR(opts);
54
+ const context = ee.context(xhr);
55
+ try {
56
+ ee.emit('new-xhr', [xhr], context);
57
+ xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), (0, _eventListenerOpts.eventListenerOpts)(false));
58
+ } catch (e) {
59
+ (0, _console.warn)('An error occurred while intercepting XHR', e);
58
60
  try {
59
- ee.emit('new-xhr', [xhr], xhr);
60
- xhr.addEventListener(READY_STATE_CHANGE, wrapXHR, (0, _eventListenerOpts.eventListenerOpts)(false));
61
- } catch (e) {
62
- (0, _console.warn)('An error occured while intercepting XHR', e);
63
- try {
64
- ee.emit('internal-error', [e]);
65
- } catch (err) {
66
- // do nothing
67
- }
61
+ ee.emit('internal-error', [e]);
62
+ } catch (err) {
63
+ // do nothing
68
64
  }
69
65
  }
70
- this.listeners.forEach(listener => listener());
71
66
  return xhr;
72
67
  }
73
68
  copy(OrigXHR, XHR);
@@ -81,14 +76,15 @@ function wrapXhr(sharedEE) {
81
76
  function wrapOnreadystatechange(args, xhr) {
82
77
  wrapFn.inPlace(xhr, ['onreadystatechange'], 'fn-', getObject);
83
78
  }
84
- function wrapXHR() {
85
- var xhr = this;
86
- var ctx = ee.context(xhr);
87
- if (xhr.readyState > 3 && !ctx.resolved) {
88
- ctx.resolved = true;
89
- ee.emit('xhr-resolved', [], xhr);
90
- }
91
- wrapFn.inPlace(xhr, handlers, 'fn-', getObject);
79
+ function wrapXHR(ctx) {
80
+ return function () {
81
+ var xhr = this;
82
+ if (xhr.readyState > 3 && !ctx.resolved) {
83
+ ctx.resolved = true;
84
+ ee.emit('xhr-resolved', [], xhr);
85
+ }
86
+ wrapFn.inPlace(xhr, handlers, 'fn-', getObject);
87
+ };
92
88
  }
93
89
 
94
90
  // Wrapping the onreadystatechange property of XHRs takes some special tricks.
@@ -17,10 +17,6 @@ var _stringify = require("../../../common/util/stringify");
17
17
  class DT {
18
18
  constructor(agentIdentifier) {
19
19
  this.agentIdentifier = agentIdentifier;
20
- // Binds this class instance context to the following fn used in an external module (exported);
21
- // Alternatively, can make them class field arrow functions, but requires experimental features/plugin for eslint.
22
- this.generateTracePayload = this.generateTracePayload.bind(this);
23
- this.shouldGenerateTrace = this.shouldGenerateTrace.bind(this);
24
20
  }
25
21
  generateTracePayload(parsedOrigin) {
26
22
  if (!this.shouldGenerateTrace(parsedOrigin)) {
@@ -26,7 +26,7 @@ var _features = require("../../../loaders/features/features");
26
26
  var handlers = ['load', 'error', 'abort', 'timeout'];
27
27
  var handlersLen = handlers.length;
28
28
  var origRequest = _config.originals.REQ;
29
- var origXHR = _runtime.globalScope.XMLHttpRequest;
29
+ var origXHR = _config.originals.XHR;
30
30
  class Instrument extends _instrumentBase.InstrumentBase {
31
31
  static featureName = _constants.FEATURE_NAME;
32
32
  constructor(agentIdentifier, aggregator) {
@@ -193,15 +193,25 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
193
193
  function onFetchBeforeStart(args) {
194
194
  var opts = args[1] || {};
195
195
  var url;
196
- // argument is USVString
197
196
  if (typeof args[0] === 'string') {
197
+ // argument is USVString
198
198
  url = args[0];
199
- // argument is Request object
199
+ if (url.length === 0 && _runtime.isBrowserScope) {
200
+ url = '' + _runtime.globalScope.location.href;
201
+ }
200
202
  } else if (args[0] && args[0].url) {
203
+ // argument is Request object
201
204
  url = args[0].url;
202
- // argument is URL object
203
205
  } else if (_runtime.globalScope?.URL && args[0] && args[0] instanceof URL) {
206
+ // argument is URL object
204
207
  url = args[0].href;
208
+ } else if (typeof args[0].toString === 'function') {
209
+ url = args[0].toString();
210
+ }
211
+ if (typeof url !== 'string' || url.length === 0) {
212
+ // Short-circuit DT since we could not determine the URL of the fetch call
213
+ // this is very unlikely to happen
214
+ return;
205
215
  }
206
216
  if (url) {
207
217
  this.parsedOrigin = (0, _parseUrl.parseUrl)(url);
@@ -211,7 +221,11 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
211
221
  if (!payload || !payload.newrelicHeader && !payload.traceContextParentHeader) {
212
222
  return;
213
223
  }
214
- if (typeof args[0] === 'string' || _runtime.globalScope?.URL && args[0] && args[0] instanceof URL) {
224
+ if (args[0] && args[0].headers) {
225
+ if (addHeaders(args[0].headers, payload)) {
226
+ this.dt = payload;
227
+ }
228
+ } else {
215
229
  var clone = {};
216
230
  for (var key in opts) {
217
231
  clone[key] = opts[key];
@@ -225,10 +239,6 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
225
239
  } else {
226
240
  args.push(clone);
227
241
  }
228
- } else if (args[0] && args[0].headers) {
229
- if (addHeaders(args[0].headers, payload)) {
230
- this.dt = payload;
231
- }
232
242
  }
233
243
  function addHeaders(headersObj, payload) {
234
244
  var added = false;
@@ -154,6 +154,14 @@ class Aggregate extends _aggregateBase.AggregateBase {
154
154
  // Capture metrics for size of custom attributes
155
155
  const jsAttributes = (0, _stringify.stringify)(info.jsAttributes);
156
156
  this.storeSupportabilityMetrics('PageSession/Feature/CustomData/Bytes', jsAttributes === '{}' ? 0 : jsAttributes.length);
157
+
158
+ // Capture metrics for performance markers and measures
159
+ if (typeof performance !== 'undefined') {
160
+ const markers = performance.getEntriesByType('mark');
161
+ const measures = performance.getEntriesByType('measure');
162
+ this.storeSupportabilityMetrics('Generic/Performance/Mark/Seen', markers.length);
163
+ this.storeSupportabilityMetrics('Generic/Performance/Measure/Seen', measures.length);
164
+ }
157
165
  } catch (e) {
158
166
  // do nothing
159
167
  }
@@ -182,11 +182,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
182
182
  this.scheduler.startTimer(this.harvestTimeSeconds);
183
183
  }
184
184
  try {
185
+ // Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
185
186
  recorder = (await Promise.resolve().then(() => _interopRequireWildcard(require( /* webpackChunkName: "recorder" */'rrweb')))).record;
186
187
  } catch (err) {
187
188
  return this.abort();
188
189
  }
189
190
  try {
191
+ // Do not change the webpackChunkName or it will break the webpack nrba-chunking plugin
190
192
  const {
191
193
  gzipSync,
192
194
  strToU8
@@ -64,9 +64,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
64
64
  this.sentTrace = null;
65
65
  this.harvestTimeSeconds = (0, _config.getConfigurationValue)(agentIdentifier, 'session_trace.harvestTimeSeconds') || 10;
66
66
  this.maxNodesPerHarvest = (0, _config.getConfigurationValue)(agentIdentifier, 'session_trace.maxNodesPerHarvest') || 1000;
67
+ /**
68
+ * Standalone (mode) refers to the legacy version of ST before the idea of 'session' or the Replay feature existed.
69
+ * It has some different behavior vs when used in tandem with replay. */
67
70
  this.isStandalone = false;
68
71
  const operationalGate = new _handlerCache.HandlerCache(); // acts as a controller-intermediary that can enable or disable this feature's collection dynamically
69
72
  const sessionEntity = this.agentRuntime.session;
73
+ this.operationalGate = operationalGate;
70
74
 
71
75
  /* --- The following section deals with user sessions concept & contains non-trivial control flow. --- */
72
76
  const controlTraceOp = traceMode => {
@@ -250,17 +254,16 @@ class Aggregate extends _aggregateBase.AggregateBase {
250
254
  }
251
255
  }
252
256
  #prepareHarvest(options) {
253
- /* Standalone refers to the legacy version of ST before the idea of 'session' or the Replay feature existed.
254
- It has a different behavior on returning a payload for harvest than when used in tandem with either of those concepts. */
255
257
  if (this.isStandalone) {
256
- if ((0, _now.now)() > MAX_TRACE_DURATION) {
257
- // been collecting for over the longest duration we should run for, empty trace object so ST has nothing to send
258
- this.#scheduler.stopTimer();
259
- this.trace = {};
258
+ if (this.ptid && (0, _now.now)() >= MAX_TRACE_DURATION) {
259
+ // Perform a final harvest once we hit or exceed the max session trace time
260
+ options.isFinalHarvest = true;
261
+ this.operationalGate.permanentlyDecide(false);
262
+ this.#scheduler.stopTimer(true);
263
+ } else if (this.ptid && this.nodeCount <= REQ_THRESHOLD_TO_SEND && !options.isFinalHarvest) {
264
+ // Only harvest when more than some threshold of nodes are pending, after the very first harvest, with the exception of the last outgoing harvest.
260
265
  return;
261
266
  }
262
- // Only harvest when more than some threshold of nodes are pending, after the very first harvest.
263
- if (this.ptid && this.nodeCount <= REQ_THRESHOLD_TO_SEND) return;
264
267
  } else {
265
268
  // -- *cli May '26 - Update: Not rate limiting backgrounded pages either for now.
266
269
  // if (this.ptid && document.visibilityState === 'hidden' && this.nodeCount <= REQ_THRESHOLD_TO_SEND) return
@@ -450,6 +453,9 @@ class Aggregate extends _aggregateBase.AggregateBase {
450
453
  const openedSpace = this.trimSTNs(ERROR_MODE_SECONDS_WINDOW); // but maybe we could make some space by discarding irrelevant nodes if we're in sessioned Error mode
451
454
  if (openedSpace == 0) return;
452
455
  }
456
+ if (this.isStandalone && (0, _now.now)() >= MAX_TRACE_DURATION) {
457
+ return;
458
+ }
453
459
  if (this.trace[stn.n]) this.trace[stn.n].push(stn);else this.trace[stn.n] = [stn];
454
460
  this.nodeCount++;
455
461
  }
@@ -407,7 +407,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
407
407
  (0, _registerHandler.registerHandler)(FETCH_DONE, function (err, res) {
408
408
  var node = this[SPA_NODE];
409
409
  if (node) {
410
- if (err) {
410
+ if (err || !(0, _denyList.shouldCollectEvent)(this.params)) {
411
411
  node.cancel();
412
412
  return;
413
413
  }
@@ -56,6 +56,18 @@ class AgentBase {
56
56
  (0, _console.warn)('Call to agent api setUserId failed. The js errors feature is not currently initialized.');
57
57
  }
58
58
 
59
+ /**
60
+ * Adds a user-defined application version string to subsequent events on the page.
61
+ * This decorates all payloads with an attribute of `application.version` which is queryable in NR1.
62
+ * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/setapplicationversion/}
63
+ * @param {string|null} value A string identifier for the application version, useful for
64
+ * tying all browser events to a specific release tag. The value parameter does not
65
+ * have to be unique. Passing a null value unsets any existing value.
66
+ */
67
+ setApplicationVersion(value) {
68
+ (0, _console.warn)('Call to agent api setApplicationVersion failed. The agent is not currently initialized.');
69
+ }
70
+
59
71
  /**
60
72
  * Allows selective ignoring and grouping of known errors that the browser agent captures.
61
73
  * {@link https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/seterrorhandler/}
@@ -26,7 +26,7 @@ const CUSTOM_ATTR_GROUP = 'CUSTOM/'; // the subgroup items should be stored unde
26
26
  exports.CUSTOM_ATTR_GROUP = CUSTOM_ATTR_GROUP;
27
27
  function setTopLevelCallers() {
28
28
  const nr = (0, _nreum.gosCDN)();
29
- const funcs = ['setErrorHandler', 'finished', 'addToTrace', 'inlineHit', 'addRelease', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId'];
29
+ const funcs = ['setErrorHandler', 'finished', 'addToTrace', 'inlineHit', 'addRelease', 'addPageAction', 'setCurrentRouteName', 'setPageViewName', 'setCustomAttribute', 'interaction', 'noticeError', 'setUserId', 'setApplicationVersion'];
30
30
  funcs.forEach(f => {
31
31
  nr[f] = function () {
32
32
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -115,6 +115,19 @@ function setAPI(agentIdentifier, forceDrain) {
115
115
  }
116
116
  return appendJsAttribute('enduser.id', value, 'setUserId', true);
117
117
  };
118
+
119
+ /**
120
+ * Attach the 'applcation.version' attribute onto agent payloads. This may be used in NR queries to group all browser events by a specific customer-defined release.
121
+ * @param {string|null} value - Application version -- if null, will "unset" the value
122
+ * @returns @see apiCall
123
+ */
124
+ apiInterface.setApplicationVersion = function (value) {
125
+ if (!(typeof value === 'string' || value === null)) {
126
+ (0, _console.warn)("Failed to execute setApplicationVersion. Expected <String | null>, but got <".concat(typeof value, ">."));
127
+ return;
128
+ }
129
+ return appendJsAttribute('application.version', value, 'setApplicationVersion', false);
130
+ };
118
131
  apiInterface.interaction = function () {
119
132
  return new InteractionHandle().get();
120
133
  };