@newrelic/browser-agent 1.261.2 → 1.263.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 (103) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/cjs/common/config/state/configurable.js +4 -4
  3. package/dist/cjs/common/config/state/init.js +5 -3
  4. package/dist/cjs/common/constants/env.cdn.js +1 -1
  5. package/dist/cjs/common/constants/env.npm.js +1 -1
  6. package/dist/cjs/common/context/shared-context.js +2 -2
  7. package/dist/cjs/common/drain/drain.js +22 -16
  8. package/dist/cjs/common/harvest/harvest.js +1 -1
  9. package/dist/cjs/common/session/session-entity.js +2 -2
  10. package/dist/cjs/common/timing/time-keeper.js +13 -2
  11. package/dist/cjs/common/util/console.js +3 -4
  12. package/dist/cjs/common/util/obfuscate.js +3 -3
  13. package/dist/cjs/common/wrap/wrap-logger.js +2 -0
  14. package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
  15. package/dist/cjs/features/logging/aggregate/index.js +27 -2
  16. package/dist/cjs/features/logging/constants.js +2 -5
  17. package/dist/cjs/features/logging/shared/utils.js +2 -18
  18. package/dist/cjs/features/metrics/aggregate/index.js +16 -0
  19. package/dist/cjs/features/page_view_event/aggregate/index.js +20 -4
  20. package/dist/cjs/features/session_replay/aggregate/index.js +1 -1
  21. package/dist/cjs/features/session_replay/shared/recorder.js +1 -1
  22. package/dist/cjs/features/session_trace/aggregate/index.js +1 -1
  23. package/dist/cjs/features/spa/aggregate/index.js +1 -1
  24. package/dist/cjs/features/utils/aggregate-base.js +4 -3
  25. package/dist/cjs/features/utils/instrument-base.js +2 -2
  26. package/dist/cjs/loaders/agent-base.js +1 -1
  27. package/dist/cjs/loaders/agent.js +3 -4
  28. package/dist/cjs/loaders/api/api.js +13 -16
  29. package/dist/cjs/loaders/micro-agent.js +5 -5
  30. package/dist/esm/common/config/state/configurable.js +4 -4
  31. package/dist/esm/common/config/state/init.js +5 -3
  32. package/dist/esm/common/constants/env.cdn.js +1 -1
  33. package/dist/esm/common/constants/env.npm.js +1 -1
  34. package/dist/esm/common/context/shared-context.js +2 -2
  35. package/dist/esm/common/drain/drain.js +22 -16
  36. package/dist/esm/common/harvest/harvest.js +1 -1
  37. package/dist/esm/common/session/session-entity.js +2 -2
  38. package/dist/esm/common/timing/time-keeper.js +12 -2
  39. package/dist/esm/common/util/console.js +3 -4
  40. package/dist/esm/common/util/obfuscate.js +3 -3
  41. package/dist/esm/common/wrap/wrap-logger.js +2 -0
  42. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  43. package/dist/esm/features/logging/aggregate/index.js +28 -3
  44. package/dist/esm/features/logging/constants.js +1 -4
  45. package/dist/esm/features/logging/shared/utils.js +2 -18
  46. package/dist/esm/features/metrics/aggregate/index.js +16 -0
  47. package/dist/esm/features/page_view_event/aggregate/index.js +21 -5
  48. package/dist/esm/features/session_replay/aggregate/index.js +1 -1
  49. package/dist/esm/features/session_replay/shared/recorder.js +1 -1
  50. package/dist/esm/features/session_trace/aggregate/index.js +1 -1
  51. package/dist/esm/features/spa/aggregate/index.js +1 -1
  52. package/dist/esm/features/utils/aggregate-base.js +4 -3
  53. package/dist/esm/features/utils/instrument-base.js +2 -2
  54. package/dist/esm/loaders/agent-base.js +1 -1
  55. package/dist/esm/loaders/agent.js +3 -4
  56. package/dist/esm/loaders/api/api.js +15 -18
  57. package/dist/esm/loaders/micro-agent.js +5 -5
  58. package/dist/types/common/config/state/init.d.ts.map +1 -1
  59. package/dist/types/common/drain/drain.d.ts.map +1 -1
  60. package/dist/types/common/timing/time-keeper.d.ts +2 -1
  61. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  62. package/dist/types/common/util/console.d.ts +1 -1
  63. package/dist/types/common/util/console.d.ts.map +1 -1
  64. package/dist/types/common/wrap/wrap-logger.d.ts.map +1 -1
  65. package/dist/types/features/logging/aggregate/index.d.ts +1 -1
  66. package/dist/types/features/logging/aggregate/index.d.ts.map +1 -1
  67. package/dist/types/features/logging/constants.d.ts +0 -3
  68. package/dist/types/features/logging/constants.d.ts.map +1 -1
  69. package/dist/types/features/logging/shared/utils.d.ts +1 -1
  70. package/dist/types/features/logging/shared/utils.d.ts.map +1 -1
  71. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  72. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  73. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  74. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  75. package/dist/types/loaders/agent.d.ts.map +1 -1
  76. package/dist/types/loaders/api/api.d.ts.map +1 -1
  77. package/package.json +1 -1
  78. package/src/common/config/state/configurable.js +4 -4
  79. package/src/common/config/state/init.js +4 -3
  80. package/src/common/context/shared-context.js +2 -2
  81. package/src/common/drain/drain.js +21 -16
  82. package/src/common/harvest/harvest.js +1 -1
  83. package/src/common/session/session-entity.js +2 -2
  84. package/src/common/timing/time-keeper.js +14 -2
  85. package/src/common/util/console.js +3 -4
  86. package/src/common/util/obfuscate.js +3 -3
  87. package/src/common/wrap/wrap-logger.js +2 -0
  88. package/src/common/wrap/wrap-xhr.js +1 -1
  89. package/src/features/logging/aggregate/index.js +30 -3
  90. package/src/features/logging/constants.js +0 -4
  91. package/src/features/logging/shared/utils.js +2 -19
  92. package/src/features/metrics/aggregate/index.js +12 -0
  93. package/src/features/page_view_event/aggregate/index.js +22 -5
  94. package/src/features/session_replay/aggregate/index.js +1 -1
  95. package/src/features/session_replay/shared/recorder.js +1 -1
  96. package/src/features/session_trace/aggregate/index.js +1 -1
  97. package/src/features/spa/aggregate/index.js +1 -1
  98. package/src/features/utils/aggregate-base.js +4 -3
  99. package/src/features/utils/instrument-base.js +2 -2
  100. package/src/loaders/agent-base.js +1 -1
  101. package/src/loaders/agent.js +3 -4
  102. package/src/loaders/api/api.js +15 -18
  103. package/src/loaders/micro-agent.js +5 -5
package/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.263.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.262.0...v1.263.0) (2024-07-25)
7
+
8
+
9
+ ### Features
10
+
11
+ * Optimize bundle size with warning codes ([#1111](https://github.com/newrelic/newrelic-browser-agent/issues/1111)) ([6ab7d2b](https://github.com/newrelic/newrelic-browser-agent/commit/6ab7d2bee5053fc75c0d20c6257afea5cf16d76d))
12
+ * Shut down agent if improperly configured ([#1116](https://github.com/newrelic/newrelic-browser-agent/issues/1116)) ([edc20d4](https://github.com/newrelic/newrelic-browser-agent/commit/edc20d4f81d1c0662f3f244240cc968b1f3870c9))
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * Prevent agent using invalid date header ([#1122](https://github.com/newrelic/newrelic-browser-agent/issues/1122)) ([6851c1b](https://github.com/newrelic/newrelic-browser-agent/commit/6851c1b1733c513ab4de119e875593a418e51b93))
18
+
19
+ ## [1.262.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.261.2...v1.262.0) (2024-07-09)
20
+
21
+
22
+ ### Features
23
+
24
+ * logging bundle optimization ([#1089](https://github.com/newrelic/newrelic-browser-agent/issues/1089)) ([83d7d1e](https://github.com/newrelic/newrelic-browser-agent/commit/83d7d1ed1863772e5515d128d0710cb456dafafd))
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * address call to stopTimer on undefined scheduler ([#1104](https://github.com/newrelic/newrelic-browser-agent/issues/1104)) ([5022134](https://github.com/newrelic/newrelic-browser-agent/commit/5022134783152e7eebbd54608eda5a09e8fe0ebb))
30
+ * Release backlog memory when features are blocked by RUM ([#1102](https://github.com/newrelic/newrelic-browser-agent/issues/1102)) ([5eb9164](https://github.com/newrelic/newrelic-browser-agent/commit/5eb91646314b5a225a1a902ecb0b58b57b5ee74f))
31
+ * safeguard api calls ([#1103](https://github.com/newrelic/newrelic-browser-agent/issues/1103)) ([3d815a3](https://github.com/newrelic/newrelic-browser-agent/commit/3d815a3988583911322541007bd5e176a5bba4c1))
32
+
6
33
  ## [1.261.2](https://github.com/newrelic/newrelic-browser-agent/compare/v1.261.1...v1.261.2) (2024-07-01)
7
34
 
8
35
 
@@ -7,8 +7,8 @@ exports.getModeledObject = getModeledObject;
7
7
  var _console = require("../../util/console");
8
8
  function getModeledObject(obj, model) {
9
9
  try {
10
- if (!obj || typeof obj !== 'object') return (0, _console.warn)('Setting a Configurable requires an object as input');
11
- if (!model || typeof model !== 'object') return (0, _console.warn)('Setting a Configurable requires a model to set its initial properties');
10
+ if (!obj || typeof obj !== 'object') return (0, _console.warn)(3);
11
+ if (!model || typeof model !== 'object') return (0, _console.warn)(4);
12
12
  // allow getters and setters to pass from model to target
13
13
  const output = Object.create(Object.getPrototypeOf(model), Object.getOwnPropertyDescriptors(model));
14
14
  const target = Object.keys(output).length === 0 ? obj : output;
@@ -21,11 +21,11 @@ function getModeledObject(obj, model) {
21
21
  }
22
22
  if (Array.isArray(obj[key]) && Array.isArray(model[key])) output[key] = Array.from(new Set([...obj[key], ...model[key]]));else if (typeof obj[key] === 'object' && typeof model[key] === 'object') output[key] = getModeledObject(obj[key], model[key]);else output[key] = obj[key];
23
23
  } catch (e) {
24
- (0, _console.warn)('An error occurred while setting a property of a Configurable', e);
24
+ (0, _console.warn)(1, e);
25
25
  }
26
26
  }
27
27
  return output;
28
28
  } catch (err) {
29
- (0, _console.warn)('An error occured while setting a Configurable', err);
29
+ (0, _console.warn)(2, err);
30
30
  }
31
31
  }
@@ -117,6 +117,8 @@ const model = () => {
117
117
  // serialize images for collection without public asset url -- right now this is only useful for testing as it easily generates payloads too large to be harvested
118
118
  inline_stylesheet: true,
119
119
  // serialize css for collection without public asset url
120
+ fix_stylesheets: true,
121
+ // fetch missing stylesheet resources for inlining, only works if 'inline_stylesheet' is also true
120
122
  // recording config settings
121
123
  mask_all_inputs: true,
122
124
  // this has a getter/setter to facilitate validation of the selectors
@@ -124,7 +126,7 @@ const model = () => {
124
126
  return hiddenState.mask_selector;
125
127
  },
126
128
  set mask_text_selector(val) {
127
- if ((0, _querySelector.isValidSelector)(val)) hiddenState.mask_selector = "".concat(val, ",").concat(nrMask);else if (val === '' || val === null) hiddenState.mask_selector = nrMask;else (0, _console.warn)('An invalid session_replay.mask_selector was provided. \'*\' will be used.', val);
129
+ if ((0, _querySelector.isValidSelector)(val)) hiddenState.mask_selector = "".concat(val, ",").concat(nrMask);else if (val === '' || val === null) hiddenState.mask_selector = nrMask;else (0, _console.warn)(5, val);
128
130
  },
129
131
  // these properties only have getters because they are enforcable constants and should error if someone tries to override them
130
132
  get block_class() {
@@ -142,7 +144,7 @@ const model = () => {
142
144
  return hiddenState.block_selector;
143
145
  },
144
146
  set block_selector(val) {
145
- if ((0, _querySelector.isValidSelector)(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') (0, _console.warn)('An invalid session_replay.block_selector was provided and will not be used', val);
147
+ if ((0, _querySelector.isValidSelector)(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') (0, _console.warn)(6, val);
146
148
  },
147
149
  // password: must always be present and true no matter what customer sets
148
150
  get mask_input_options() {
@@ -152,7 +154,7 @@ const model = () => {
152
154
  if (val && typeof val === 'object') hiddenState.mask_input_options = {
153
155
  ...val,
154
156
  password: true
155
- };else (0, _console.warn)('An invalid session_replay.mask_input_option was provided and will not be used', val);
157
+ };else (0, _console.warn)(7, val);
156
158
  }
157
159
  },
158
160
  session_trace: {
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = exports.VERSION = "1.261.2";
15
+ const VERSION = exports.VERSION = "1.263.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -12,7 +12,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
12
12
  /**
13
13
  * Exposes the version of the agent
14
14
  */
15
- const VERSION = exports.VERSION = "1.261.2";
15
+ const VERSION = exports.VERSION = "1.263.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -12,7 +12,7 @@ const model = {
12
12
  class SharedContext {
13
13
  constructor(context) {
14
14
  try {
15
- if (typeof context !== 'object') return (0, _console.warn)('shared context requires an object as input');
15
+ if (typeof context !== 'object') return (0, _console.warn)(8);
16
16
  this.sharedContext = {};
17
17
  Object.assign(this.sharedContext, model);
18
18
  Object.entries(context).forEach(_ref => {
@@ -20,7 +20,7 @@ class SharedContext {
20
20
  if (Object.keys(model).includes(key)) this.sharedContext[key] = value;
21
21
  });
22
22
  } catch (err) {
23
- (0, _console.warn)('An error occurred while setting SharedContext', err);
23
+ (0, _console.warn)(9, err);
24
24
  }
25
25
  }
26
26
  }
@@ -42,8 +42,9 @@ function registerDrain(agentIdentifier, group) {
42
42
  * @param {*} group - The named "bucket" to be removed from the registry
43
43
  */
44
44
  function deregisterDrain(agentIdentifier, group) {
45
- curateRegistry(agentIdentifier);
45
+ if (!agentIdentifier || !registry[agentIdentifier]) return;
46
46
  if (registry[agentIdentifier].get(group)) registry[agentIdentifier].delete(group);
47
+ drainGroup(agentIdentifier, group, false);
47
48
  if (registry[agentIdentifier].size) checkCanDrainAll(agentIdentifier);
48
49
  }
49
50
 
@@ -103,27 +104,32 @@ function checkCanDrainAll(agentIdentifier) {
103
104
  * @param {*} group - The name of a particular feature's event "bucket".
104
105
  */
105
106
  function drainGroup(agentIdentifier, group) {
107
+ let activateGroup = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
106
108
  const baseEE = agentIdentifier ? _contextualEe.ee.get(agentIdentifier) : _contextualEe.ee;
107
109
  const handlers = _registerHandler.registerHandler.handlers; // other storage in registerHandler
108
- if (!baseEE.backlog || !handlers) return;
109
- var bufferedEventsInGroup = baseEE.backlog[group];
110
- var groupHandlers = handlers[group]; // each group in the registerHandler storage
111
- if (groupHandlers) {
112
- // We don't cache the length of the buffer while looping because events might still be added while processing.
113
- for (var i = 0; bufferedEventsInGroup && i < bufferedEventsInGroup.length; ++i) {
114
- // eslint-disable-line no-unmodified-loop-condition
115
- emitEvent(bufferedEventsInGroup[i], groupHandlers);
116
- }
117
- (0, _mapOwn.mapOwn)(groupHandlers, function (eventType, handlerRegistrationList) {
118
- (0, _mapOwn.mapOwn)(handlerRegistrationList, function (i, registration) {
119
- // registration is an array of: [targetEE, eventHandler]
120
- registration[0].on(eventType, registration[1]);
110
+ if (baseEE.aborted || !baseEE.backlog || !handlers) return;
111
+
112
+ // Only activated features being drained should run queued listeners on buffered events. Deactivated features only need to release memory.
113
+ if (activateGroup) {
114
+ const bufferedEventsInGroup = baseEE.backlog[group];
115
+ const groupHandlers = handlers[group]; // each group in the registerHandler storage
116
+ if (groupHandlers) {
117
+ // We don't cache the length of the buffer while looping because events might still be added while processing.
118
+ for (let i = 0; bufferedEventsInGroup && i < bufferedEventsInGroup.length; ++i) {
119
+ // eslint-disable-line no-unmodified-loop-condition
120
+ emitEvent(bufferedEventsInGroup[i], groupHandlers);
121
+ }
122
+ (0, _mapOwn.mapOwn)(groupHandlers, function (eventType, handlerRegistrationList) {
123
+ (0, _mapOwn.mapOwn)(handlerRegistrationList, function (i, registration) {
124
+ // registration is an array of: [targetEE, eventHandler]
125
+ registration[0].on(eventType, registration[1]);
126
+ });
121
127
  });
122
- });
128
+ }
123
129
  }
124
130
  if (!baseEE.isolatedBacklog) delete handlers[group];
125
131
  baseEE.backlog[group] = null;
126
- baseEE.emit('drain-' + group, []);
132
+ baseEE.emit('drain-' + group, []); // TODO: Code exists purely for a unit test and needs to be refined
127
133
  }
128
134
 
129
135
  /**
@@ -156,7 +156,7 @@ class Harvest extends _sharedContext.SharedContext {
156
156
  body = (0, _stringify.stringify)(body);
157
157
  }
158
158
  /** Warn --once per endpoint-- if the agent tries to send large payloads */
159
- if (body.length > 750000 && (warnings[endpoint] = (warnings?.[endpoint] || 0) + 1) === 1) (0, _console.warn)("The Browser Agent is attempting to send a very large payload to /".concat(endpoint, ". This is usually tied to large amounts of custom attributes. Please check your configurations."));
159
+ if (body.length > 750000 && (warnings[endpoint] = (warnings?.[endpoint] || 0) + 1) === 1) (0, _console.warn)(28, endpoint);
160
160
  }
161
161
  if (!body || body.length === 0 || body === '{}' || body === '[]') {
162
162
  // If body is null, undefined, or an empty object or array, send an empty string instead
@@ -195,7 +195,7 @@ class SessionEntity {
195
195
  }
196
196
  return obj;
197
197
  } catch (e) {
198
- (0, _console.warn)('Failed to read from storage API', e);
198
+ (0, _console.warn)(10, e);
199
199
  // storage is inaccessible
200
200
  return {};
201
201
  }
@@ -221,7 +221,7 @@ class SessionEntity {
221
221
  return data;
222
222
  } catch (e) {
223
223
  // storage is inaccessible
224
- (0, _console.warn)('Failed to write to the storage API', e);
224
+ (0, _console.warn)(11, e);
225
225
  return null;
226
226
  }
227
227
  }
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.TimeKeeper = void 0;
7
7
  var _runtime = require("../constants/runtime");
8
8
  var _config = require("../config/config");
9
+ const rfc2616Regex = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-3][0-9]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{4}) ([01][0-9]|2[0-3])(:[0-5][0-9]){2} GMT$/;
10
+
9
11
  /**
10
12
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
11
13
  * is done by tracking the performance timings of the RUM call and applying a calculation
@@ -34,7 +36,7 @@ class TimeKeeper {
34
36
  /**
35
37
  * Represents whether the timekeeper is in a state that it can accurately convert
36
38
  * timestamps.
37
- * @type {number}
39
+ * @type {boolean}
38
40
  */
39
41
  #ready = false;
40
42
  constructor(agentIdentifier) {
@@ -47,6 +49,9 @@ class TimeKeeper {
47
49
  get correctedOriginTime() {
48
50
  return this.#correctedOriginTime;
49
51
  }
52
+ get localTimeDiff() {
53
+ return this.#localTimeDiff;
54
+ }
50
55
 
51
56
  /**
52
57
  * Process a rum request to calculate NR server time.
@@ -55,12 +60,16 @@ class TimeKeeper {
55
60
  * @param endTime {number} The end time of the RUM request
56
61
  */
57
62
  processRumRequest(rumRequest, startTime, endTime) {
58
- this.processStoredDiff();
63
+ this.processStoredDiff(); // Check session entity for stored time diff
59
64
  if (this.#ready) return; // Server time calculated from session entity
65
+
60
66
  const responseDateHeader = rumRequest.getResponseHeader('Date');
61
67
  if (!responseDateHeader) {
62
68
  throw new Error('Missing date header on rum response.');
63
69
  }
70
+ if (!rfc2616Regex.test(responseDateHeader)) {
71
+ throw new Error('Date header invalid format.');
72
+ }
64
73
  const medianRumOffset = (endTime - startTime) / 2;
65
74
  const serverOffset = startTime + medianRumOffset;
66
75
 
@@ -97,6 +106,8 @@ class TimeKeeper {
97
106
 
98
107
  /** Process the session entity and use the info to set the main time calculations if present */
99
108
  processStoredDiff() {
109
+ if (this.#ready) return; // Time diff has already been calculated
110
+
100
111
  const storedServerTimeDiff = this.#session?.read()?.serverTimeDiff;
101
112
  if (typeof storedServerTimeDiff === 'number' && !isNaN(storedServerTimeDiff)) {
102
113
  this.#localTimeDiff = storedServerTimeDiff;
@@ -10,8 +10,7 @@ exports.warn = warn;
10
10
  * @param {*} [secondary] Secondary data to include, usually an error or object
11
11
  * @returns
12
12
  */
13
- function warn(message, secondary) {
14
- if (typeof console.warn !== 'function') return;
15
- console.warn("New Relic: ".concat(message));
16
- if (secondary) console.warn(secondary);
13
+ function warn(code, secondary) {
14
+ if (typeof console.debug !== 'function') return;
15
+ console.debug("New Relic Warning: https://github.com/newrelic/newrelic-browser-agent/blob/main/docs/warning-codes.md#".concat(code), secondary);
17
16
  }
@@ -54,15 +54,15 @@ function validateRules(rules) {
54
54
  var invalidRegexDetected = false;
55
55
  for (var i = 0; i < rules.length; i++) {
56
56
  if (!('regex' in rules[i])) {
57
- (0, _console.warn)('An obfuscation replacement rule was detected missing a "regex" value.');
57
+ (0, _console.warn)(12);
58
58
  invalidRegexDetected = true;
59
59
  } else if (typeof rules[i].regex !== 'string' && !(rules[i].regex instanceof RegExp)) {
60
- (0, _console.warn)('An obfuscation replacement rule contains a "regex" value with an invalid type (must be a string or RegExp)');
60
+ (0, _console.warn)(13);
61
61
  invalidRegexDetected = true;
62
62
  }
63
63
  var replacement = rules[i].replacement;
64
64
  if (replacement && typeof replacement !== 'string') {
65
- (0, _console.warn)('An obfuscation replacement rule contains a "replacement" value with an invalid type (must be a string)');
65
+ (0, _console.warn)(14);
66
66
  invalidReplacementDetected = true;
67
67
  }
68
68
  }
@@ -7,6 +7,7 @@ exports.scopedEE = scopedEE;
7
7
  exports.wrapLogger = wrapLogger;
8
8
  var _contextualEe = require("../event-emitter/contextual-ee");
9
9
  var _eventContext = require("../event-emitter/event-context");
10
+ var _console = require("../util/console");
10
11
  var _wrapFunction = require("./wrap-function");
11
12
  /*
12
13
  * Copyright 2020 New Relic Corporation. All rights reserved.
@@ -26,6 +27,7 @@ var _wrapFunction = require("./wrap-function");
26
27
  */
27
28
  // eslint-disable-next-line
28
29
  function wrapLogger(sharedEE, parent, loggerFn, context) {
30
+ if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return (0, _console.warn)(29);
29
31
  const ee = scopedEE(sharedEE);
30
32
  const wrapFn = (0, _wrapFunction.createWrapperWithEmitter)(ee);
31
33
 
@@ -56,7 +56,7 @@ function wrapXhr(sharedEE) {
56
56
  ee.emit('new-xhr', [xhr], context);
57
57
  xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), (0, _eventListenerOpts.eventListenerOpts)(false));
58
58
  } catch (e) {
59
- (0, _console.warn)('An error occurred while intercepting XHR', e);
59
+ (0, _console.warn)(15, e);
60
60
  try {
61
61
  ee.emit('internal-error', [e]);
62
62
  } catch (err) {
@@ -14,6 +14,7 @@ var _constants = require("../../metrics/constants");
14
14
  var _aggregateBase = require("../../utils/aggregate-base");
15
15
  var _constants2 = require("../constants");
16
16
  var _log = require("../shared/log");
17
+ var _utils = require("../shared/utils");
17
18
  class Aggregate extends _aggregateBase.AggregateBase {
18
19
  static featureName = _constants2.FEATURE_NAME;
19
20
  #agentRuntime;
@@ -44,13 +45,37 @@ class Aggregate extends _aggregateBase.AggregateBase {
44
45
  this.drain();
45
46
  });
46
47
  }
47
- handleLog(timestamp, message, attributes, level) {
48
+ handleLog(timestamp, message) {
49
+ let attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
50
+ let level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants2.LOG_LEVELS.INFO;
48
51
  if (this.blocked) return;
52
+ if (!attributes || typeof attributes !== 'object') attributes = {};
53
+ if (typeof level === 'string') level = level.toUpperCase();
54
+ if (!(0, _utils.isValidLogLevel)(level)) return (0, _console.warn)(30, level);
55
+ try {
56
+ if (typeof message !== 'string') {
57
+ const stringified = (0, _stringify.stringify)(message);
58
+ /**
59
+ * Error instances convert to `{}` when stringified
60
+ * Symbol converts to '' when stringified
61
+ * other cases tbd
62
+ * */
63
+ if (!!stringified && stringified !== '{}') message = stringified;else message = String(message);
64
+ }
65
+ } catch (err) {
66
+ (0, _console.warn)(16, message);
67
+ return;
68
+ }
69
+ if (typeof message !== 'string' || !message) return (0, _console.warn)(32);
70
+ if (message.length > _constants2.MAX_PAYLOAD_SIZE) {
71
+ (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', message.length]);
72
+ return (0, _console.warn)(31, message.slice(0, 25) + '...');
73
+ }
49
74
  const log = new _log.Log(this.#agentRuntime.timeKeeper.convertRelativeTimestamp(timestamp), message, attributes, level);
50
75
  const logBytes = log.message.length + (0, _stringify.stringify)(log.attributes).length + log.level.length + 10; // timestamp == 10 chars
51
76
  if (logBytes > _constants2.MAX_PAYLOAD_SIZE) {
52
77
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Failed/Seen', logBytes]);
53
- return (0, _console.warn)(_constants2.LOGGING_IGNORED + '> ' + _constants2.MAX_PAYLOAD_SIZE + ' bytes', log.message.slice(0, 25) + '...');
78
+ return (0, _console.warn)(31, log.message.slice(0, 25) + '...');
54
79
  }
55
80
  if (this.estimatedBytes + logBytes >= _constants2.MAX_PAYLOAD_SIZE) {
56
81
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Logging/Harvest/Early/Seen', this.estimatedBytes + logBytes]);
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.MAX_PAYLOAD_SIZE = exports.LOG_LEVELS = exports.LOGGING_LEVEL_FAILURE_MESSAGE = exports.LOGGING_IGNORED = exports.LOGGING_FAILURE_MESSAGE = exports.LOGGING_EVENT_EMITTER_CHANNEL = exports.FEATURE_NAME = void 0;
6
+ exports.MAX_PAYLOAD_SIZE = exports.LOG_LEVELS = exports.LOGGING_EVENT_EMITTER_CHANNEL = exports.FEATURE_NAME = void 0;
7
7
  var _features = require("../../loaders/features/features");
8
8
  const LOG_LEVELS = exports.LOG_LEVELS = {
9
9
  ERROR: 'ERROR',
@@ -14,7 +14,4 @@ const LOG_LEVELS = exports.LOG_LEVELS = {
14
14
  };
15
15
  const LOGGING_EVENT_EMITTER_CHANNEL = exports.LOGGING_EVENT_EMITTER_CHANNEL = 'log';
16
16
  const FEATURE_NAME = exports.FEATURE_NAME = _features.FEATURE_NAMES.logging;
17
- const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
18
- const LOGGING_FAILURE_MESSAGE = exports.LOGGING_FAILURE_MESSAGE = 'failed to wrap logger: ';
19
- const LOGGING_LEVEL_FAILURE_MESSAGE = exports.LOGGING_LEVEL_FAILURE_MESSAGE = 'invalid log level: ';
20
- const LOGGING_IGNORED = exports.LOGGING_IGNORED = 'ignored log: ';
17
+ const MAX_PAYLOAD_SIZE = exports.MAX_PAYLOAD_SIZE = 1000000;
@@ -7,8 +7,6 @@ exports.bufferLog = bufferLog;
7
7
  exports.isValidLogLevel = isValidLogLevel;
8
8
  var _handle = require("../../../common/event-emitter/handle");
9
9
  var _now = require("../../../common/timing/now");
10
- var _console = require("../../../common/util/console");
11
- var _stringify = require("../../../common/util/stringify");
12
10
  var _features = require("../../../loaders/features/features");
13
11
  var _constants = require("../../metrics/constants");
14
12
  var _constants2 = require("../constants");
@@ -21,30 +19,16 @@ var _constants2 = require("../constants");
21
19
  function bufferLog(ee, message) {
22
20
  let customAttributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
23
21
  let level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants2.LOG_LEVELS.INFO;
24
- try {
25
- if (typeof message !== 'string') {
26
- const stringified = (0, _stringify.stringify)(message);
27
- /**
28
- * Error instances convert to `{}` when stringified
29
- * Symbol converts to '' when stringified
30
- * other cases tbd
31
- * */
32
- if (!!stringified && stringified !== '{}') message = stringified;else message = String(message);
33
- }
34
- } catch (err) {
35
- (0, _console.warn)('could not cast log message to string', message);
36
- return;
37
- }
38
22
  (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ["API/logging/".concat(level.toLowerCase(), "/called")], undefined, _features.FEATURE_NAMES.metrics, ee);
39
23
  (0, _handle.handle)(_constants2.LOGGING_EVENT_EMITTER_CHANNEL, [(0, _now.now)(), message, customAttributes, level], undefined, _features.FEATURE_NAMES.logging, ee);
40
24
  }
41
25
 
42
26
  /**
43
27
  * Checks if a supplied log level is acceptable for use in generating a log event
44
- * @param {string} level
28
+ * @param {string} level -- must be cast to uppercase before running this test
45
29
  * @returns {boolean}
46
30
  */
47
31
  function isValidLogLevel(level) {
48
32
  if (typeof level !== 'string') return false;
49
- return Object.values(_constants2.LOG_LEVELS).some(logLevel => logLevel.toUpperCase() === level.toUpperCase());
33
+ return Object.values(_constants2.LOG_LEVELS).some(logLevel => logLevel === level);
50
34
  }
@@ -108,6 +108,22 @@ class Aggregate extends _aggregateBase.AggregateBase {
108
108
  // Check if proxy for either chunks or beacon is being used
109
109
  if (proxy.assets) this.storeSupportabilityMetrics('Config/AssetsUrl/Changed');
110
110
  if (proxy.beacon) this.storeSupportabilityMetrics('Config/BeaconUrl/Changed');
111
+ if (_runtime.isBrowserScope && window.MutationObserver) {
112
+ this.storeSupportabilityMetrics('Generic/VideoElement/Added', window.document.querySelectorAll('video').length);
113
+ const mo = new MutationObserver(records => {
114
+ records.forEach(record => {
115
+ record.addedNodes.forEach(addedNode => {
116
+ if (addedNode instanceof HTMLVideoElement) {
117
+ this.storeSupportabilityMetrics('Generic/VideoElement/Added', 1);
118
+ }
119
+ });
120
+ });
121
+ });
122
+ mo.observe(window.document.body, {
123
+ childList: true,
124
+ subtree: true
125
+ });
126
+ }
111
127
  }
112
128
  eachSessionChecks() {
113
129
  if (!_runtime.isBrowserScope) return;
@@ -33,6 +33,10 @@ class Aggregate extends _aggregateBase.AggregateBase {
33
33
  this.firstByteToWindowLoad = 0; // our "frontend" duration
34
34
  this.firstByteToDomContent = 0; // our "dom processing" duration
35
35
  this.timeKeeper = new _timeKeeper.TimeKeeper(this.agentIdentifier);
36
+ if (!(0, _config.isConfigured)(agentIdentifier)) {
37
+ this.ee.abort();
38
+ return (0, _console.warn)(43);
39
+ }
36
40
  if (_runtime.isBrowserScope) {
37
41
  _timeToFirstByte.timeToFirstByte.subscribe(_ref => {
38
42
  let {
@@ -55,7 +59,6 @@ class Aggregate extends _aggregateBase.AggregateBase {
55
59
  const info = (0, _config.getInfo)(this.agentIdentifier);
56
60
  const agentRuntime = (0, _config.getRuntime)(this.agentIdentifier);
57
61
  const harvester = new _harvest.Harvest(this);
58
- if (!info.beacon) return;
59
62
  if (info.queueTime) this.aggregator.store('measures', 'qt', {
60
63
  value: info.queueTime
61
64
  });
@@ -148,11 +151,24 @@ class Aggregate extends _aggregateBase.AggregateBase {
148
151
  this.timeKeeper.processRumRequest(xhr, rumStartTime, rumEndTime);
149
152
  if (!this.timeKeeper.ready) throw new Error('TimeKeeper not ready');
150
153
  agentRuntime.timeKeeper = this.timeKeeper;
154
+
155
+ // Check if the time diff is such that we need to capture a supportability metric
156
+ if (this.timeKeeper.localTimeDiff >= 12 * 60 * 60 * 1000) {
157
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed12Hrs'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
158
+ } else if (this.timeKeeper.localTimeDiff >= 6 * 60 * 60 * 1000) {
159
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed6Hrs'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
160
+ } else if (this.timeKeeper.localTimeDiff >= 60 * 60 * 1000) {
161
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/DiffExceed1Hrs'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
162
+ }
151
163
  } catch (error) {
152
- (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
164
+ if (error?.message?.indexOf('invalid format') > 0) {
165
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/InvalidFormat'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
166
+ } else {
167
+ (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, _features.FEATURE_NAMES.metrics, this.ee);
168
+ }
153
169
  (0, _drain.drain)(this.agentIdentifier, _features.FEATURE_NAMES.metrics, true);
154
170
  this.ee.abort();
155
- (0, _console.warn)('Could not calculate New Relic server time. Agent shutting down.', error);
171
+ (0, _console.warn)(17, error);
156
172
  return;
157
173
  }
158
174
  try {
@@ -165,7 +181,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
165
181
  this.drain();
166
182
  } catch (err) {
167
183
  this.ee.abort();
168
- (0, _console.warn)('RUM call failed. Agent shutting down.', err);
184
+ (0, _console.warn)(18, err);
169
185
  }
170
186
  }
171
187
  });
@@ -421,7 +421,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
421
421
  abort() {
422
422
  let reason = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
423
423
  let data = arguments.length > 1 ? arguments[1] : undefined;
424
- (0, _console.warn)("SR aborted -- ".concat(reason.message));
424
+ (0, _console.warn)(33, reason.message);
425
425
  (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ["SessionReplay/Abort/".concat(reason.sm), data], undefined, _features.FEATURE_NAMES.metrics, this.ee);
426
426
  this.blocked = true;
427
427
  this.mode = _constants3.MODE.OFF;
@@ -39,7 +39,7 @@ class Recorder {
39
39
  /** Config to inform to inline stylesheet contents (true default) */
40
40
  this.shouldInlineStylesheets = (0, _config.getConfigurationValue)(this.parent.agentIdentifier, 'session_replay.inline_stylesheet');
41
41
  /** A flag that can be set to false by failing conversions to stop the fetching process */
42
- this.shouldFix = this.shouldInlineStylesheets;
42
+ this.shouldFix = this.shouldInlineStylesheets && (0, _config.getConfigurationValue)(this.parent.agentIdentifier, 'session_replay.fix_stylesheets');
43
43
  /** The method to stop recording. This defaults to a noop, but is overwritten once the recording library is imported and initialized */
44
44
  this.stopRecording = () => {/* no-op until set by rrweb initializer */};
45
45
  }
@@ -242,7 +242,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
242
242
  this.agentRuntime.session.write({
243
243
  sessionTraceMode: this.mode
244
244
  });
245
- this.scheduler.stopTimer();
245
+ this.scheduler?.stopTimer();
246
246
  }
247
247
  }
248
248
  exports.Aggregate = Aggregate;
@@ -702,7 +702,7 @@ class Aggregate extends _aggregateBase.AggregateBase {
702
702
  if (interaction.root?.attrs?.trigger === 'initialPageLoad') smCategory = 'InitialPageLoad';else if (interaction.routeChange) smCategory = 'RouteChange';else smCategory = 'Custom';
703
703
  (0, _handle.handle)(_constants2.SUPPORTABILITY_METRIC_CHANNEL, ["Spa/Interaction/".concat(smCategory, "/Duration/Ms"), Math.max((interaction.root?.end || 0) - (interaction.root?.start || 0), 0)], undefined, _features.FEATURE_NAMES.metrics, baseEE);
704
704
  scheduler?.scheduleHarvest(0);
705
- if (!scheduler) (0, _console.warn)('SPA scheduler is not initialized. Saved interaction is not sent!');
705
+ if (!scheduler) (0, _console.warn)(19);
706
706
  }
707
707
  function isEnabled() {
708
708
  var enabled = (0, _config.getConfigurationValue)(agentIdentifier, 'spa.enabled');
@@ -55,8 +55,9 @@ class AggregateBase extends _featureBase.FeatureBase {
55
55
  checkConfiguration() {
56
56
  // NOTE: This check has to happen at aggregator load time
57
57
  if (!(0, _config.isConfigured)(this.agentIdentifier)) {
58
+ const cdn = (0, _nreum.gosCDN)();
58
59
  let jsAttributes = {
59
- ...(0, _nreum.gosCDN)().info?.jsAttributes
60
+ ...cdn.info?.jsAttributes
60
61
  };
61
62
  try {
62
63
  jsAttributes = {
@@ -69,9 +70,9 @@ class AggregateBase extends _featureBase.FeatureBase {
69
70
  (0, _configure.configure)({
70
71
  agentIdentifier: this.agentIdentifier
71
72
  }, {
72
- ...(0, _nreum.gosCDN)(),
73
+ ...cdn,
73
74
  info: {
74
- ...(0, _nreum.gosCDN)().info,
75
+ ...cdn.info,
75
76
  jsAttributes
76
77
  },
77
78
  runtime: (0, _config.getRuntime)(this.agentIdentifier)
@@ -92,7 +92,7 @@ class InstrumentBase extends _featureBase.FeatureBase {
92
92
  session = setupAgentSession(this.agentIdentifier);
93
93
  }
94
94
  } catch (e) {
95
- (0, _console.warn)('A problem occurred when starting up session manager. This page will not start or extend any session.', e);
95
+ (0, _console.warn)(20, e);
96
96
  this.ee.emit('internal-error', [e]);
97
97
  if (this.featureName === _features.FEATURE_NAMES.sessionReplay) this.abortHandler?.(); // SR should stop recording if session DNE
98
98
  }
@@ -116,7 +116,7 @@ class InstrumentBase extends _featureBase.FeatureBase {
116
116
  this.featAggregate = new Aggregate(this.agentIdentifier, this.aggregator, argsObjFromInstrument);
117
117
  loadedSuccessfully(true);
118
118
  } catch (e) {
119
- (0, _console.warn)("Downloading and initializing ".concat(this.featureName, " failed..."), e);
119
+ (0, _console.warn)(34, e);
120
120
  this.abortHandler?.(); // undo any important alterations made to the page
121
121
  // not supported yet but nice to do: "abort" this agent's EE for this feature specifically
122
122
  (0, _drain.drain)(this.agentIdentifier, this.featureName, true);
@@ -33,7 +33,7 @@ class AgentBase {
33
33
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
34
34
  args[_key - 1] = arguments[_key];
35
35
  }
36
- if (typeof this.api?.[methodName] !== 'function') (0, _console.warn)("Call to agent api ".concat(methodName, " failed. The API is not currently initialized."));else return this.api[methodName](...args);
36
+ if (typeof this.api?.[methodName] !== 'function') (0, _console.warn)(35, methodName);else return this.api[methodName](...args);
37
37
  }
38
38
 
39
39
  /**