@newrelic/browser-agent 1.294.0-rc.2 → 1.294.0-rc.4

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 (28) 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/timing/time-keeper.js +2 -0
  4. package/dist/cjs/common/util/monkey-patched.js +30 -0
  5. package/dist/cjs/common/window/nreum.js +3 -1
  6. package/dist/cjs/features/logging/instrument/index.js +8 -17
  7. package/dist/cjs/features/session_replay/aggregate/index.js +24 -4
  8. package/dist/esm/common/constants/env.cdn.js +1 -1
  9. package/dist/esm/common/constants/env.npm.js +1 -1
  10. package/dist/esm/common/timing/time-keeper.js +2 -0
  11. package/dist/esm/common/util/monkey-patched.js +23 -0
  12. package/dist/esm/common/window/nreum.js +3 -1
  13. package/dist/esm/features/logging/instrument/index.js +8 -17
  14. package/dist/esm/features/session_replay/aggregate/index.js +24 -4
  15. package/dist/tsconfig.tsbuildinfo +1 -1
  16. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  17. package/dist/types/common/util/monkey-patched.d.ts +7 -0
  18. package/dist/types/common/util/monkey-patched.d.ts.map +1 -0
  19. package/dist/types/common/window/nreum.d.ts.map +1 -1
  20. package/dist/types/features/logging/instrument/index.d.ts.map +1 -1
  21. package/dist/types/features/session_replay/aggregate/index.d.ts +9 -0
  22. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/common/timing/time-keeper.js +2 -0
  25. package/src/common/util/monkey-patched.js +24 -0
  26. package/src/common/window/nreum.js +3 -1
  27. package/src/features/logging/instrument/index.js +8 -6
  28. package/src/features/session_replay/aggregate/index.js +18 -4
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.294.0-rc.2";
20
+ const VERSION = exports.VERSION = "1.294.0-rc.4";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.DIST_METHOD = exports.BUILD_EN
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.294.0-rc.2";
20
+ const VERSION = exports.VERSION = "1.294.0-rc.4";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.TimeKeeper = void 0;
7
7
  var _runtime = require("../constants/runtime");
8
+ var _monkeyPatched = require("../util/monkey-patched");
8
9
  /**
9
10
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
10
11
  * SPDX-License-Identifier: Apache-2.0
@@ -44,6 +45,7 @@ class TimeKeeper {
44
45
  constructor(sessionObj) {
45
46
  this.#session = sessionObj;
46
47
  this.processStoredDiff();
48
+ (0, _monkeyPatched.isNative)(performance.now, Date.now); // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
47
49
  }
48
50
  get ready() {
49
51
  return this.#ready;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isNative = isNative;
7
+ var _console = require("./console");
8
+ /**
9
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
10
+ * SPDX-License-Identifier: Apache-2.0
11
+ */
12
+
13
+ const checked = new Map();
14
+
15
+ /**
16
+ * Checks if the provided functions are native functions.
17
+ * @param {...Function} fns - An array of functions to check if they are native.
18
+ * @returns {boolean} true if all the expected globals are native, false otherwise
19
+ */
20
+ function isNative(...fns) {
21
+ return fns.every(fn => {
22
+ if (checked.has(fn)) return checked.get(fn);
23
+ const isNative = typeof fn === 'function' && fn.toString().includes('[native code]');
24
+ if (!isNative) {
25
+ (0, _console.warn)(64, fn?.name || fn?.toString());
26
+ }
27
+ checked.set(fn, isNative);
28
+ return isNative;
29
+ });
30
+ }
@@ -16,6 +16,7 @@ exports.gosNREUMOriginals = gosNREUMOriginals;
16
16
  exports.setNREUMInitializedAgent = setNREUMInitializedAgent;
17
17
  var _runtime = require("../constants/runtime");
18
18
  var _now = require("../timing/now");
19
+ var _monkeyPatched = require("../util/monkey-patched");
19
20
  /**
20
21
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
21
22
  * SPDX-License-Identifier: Apache-2.0
@@ -63,7 +64,7 @@ function gosNREUMOriginals() {
63
64
  if (!nr.o) {
64
65
  nr.o = {
65
66
  ST: _runtime.globalScope.setTimeout,
66
- SI: _runtime.globalScope.setImmediate,
67
+ SI: _runtime.globalScope.setImmediate || _runtime.globalScope.setInterval,
67
68
  CT: _runtime.globalScope.clearTimeout,
68
69
  XHR: _runtime.globalScope.XMLHttpRequest,
69
70
  REQ: _runtime.globalScope.Request,
@@ -74,6 +75,7 @@ function gosNREUMOriginals() {
74
75
  FETCH: _runtime.globalScope.fetch,
75
76
  WS: _runtime.globalScope.WebSocket
76
77
  };
78
+ (0, _monkeyPatched.isNative)(...Object.values(nr.o)); // Warns if the originals are not native, which is typically required for the agent to work properly
77
79
  }
78
80
  return nr;
79
81
  }
@@ -12,6 +12,7 @@ var _runtime = require("../../../common/constants/runtime");
12
12
  var _log = require("../../../loaders/api/log");
13
13
  var _wrapLogger2 = require("../../../loaders/api/wrapLogger");
14
14
  var _register = require("../../../loaders/api/register");
15
+ var _monkeyPatched = require("../../../common/util/monkey-patched");
15
16
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
17
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /**
17
18
  * Copyright 2020-2025 New Relic, Inc. All rights reserved.
@@ -27,24 +28,14 @@ class Instrument extends _instrumentBase.InstrumentBase {
27
28
  (0, _wrapLogger2.setupWrapLoggerAPI)(agentRef);
28
29
  (0, _register.setupRegisterAPI)(agentRef);
29
30
  const instanceEE = this.ee;
30
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'log', {
31
- level: 'info'
32
- });
33
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'error', {
34
- level: 'error'
35
- });
36
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'warn', {
37
- level: 'warn'
38
- });
39
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'info', {
40
- level: 'info'
41
- });
42
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'debug', {
43
- level: 'debug'
44
- });
45
- (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, 'trace', {
46
- level: 'trace'
31
+ const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace'];
32
+ globals.forEach(method => {
33
+ (0, _monkeyPatched.isNative)(_runtime.globalScope.console[method]);
34
+ (0, _wrapLogger.wrapLogger)(instanceEE, _runtime.globalScope.console, method, {
35
+ level: method === 'log' ? 'info' : method
36
+ });
47
37
  });
38
+
48
39
  /** emitted by wrap-logger function */
49
40
  this.ee.on('wrap-logger-end', function handleLog([message]) {
50
41
  const {
@@ -291,6 +291,24 @@ class Aggregate extends _aggregateBase.AggregateBase {
291
291
  if (node.__newrelic) return node.timestamp;
292
292
  return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp);
293
293
  }
294
+
295
+ /**
296
+ * returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
297
+ * @param {Object[]} [nodes] - the nodes to evaluate
298
+ * @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
299
+ */
300
+ getFirstAndLastNodes(nodes = []) {
301
+ const output = {
302
+ firstEvent: nodes[0],
303
+ lastEvent: nodes[nodes.length - 1]
304
+ };
305
+ nodes.forEach(node => {
306
+ const timestamp = node?.timestamp;
307
+ if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node;
308
+ if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node;
309
+ });
310
+ return output;
311
+ }
294
312
  getHarvestContents(recorderEvents) {
295
313
  recorderEvents ??= this.recorder.getEvents();
296
314
  let events = recorderEvents.events;
@@ -315,11 +333,13 @@ class Aggregate extends _aggregateBase.AggregateBase {
315
333
  recorderEvents.hasMeta = !!events.find(x => x.type === _constants.RRWEB_EVENT_TYPES.Meta);
316
334
  }
317
335
  const relativeNow = (0, _now.now)();
318
- const firstEventTimestamp = this.getCorrectedTimestamp(events[0]); // from rrweb node
319
- const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]); // from rrweb node
336
+ const {
337
+ firstEvent,
338
+ lastEvent
339
+ } = this.getFirstAndLastNodes(events);
320
340
  // from rrweb node || from when the harvest cycle started
321
- const firstTimestamp = firstEventTimestamp || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
322
- const lastTimestamp = lastEventTimestamp || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
341
+ const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
342
+ const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
323
343
  const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {};
324
344
  return {
325
345
  qs: {
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.294.0-rc.2";
14
+ export const VERSION = "1.294.0-rc.4";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.294.0-rc.2";
14
+ export const VERSION = "1.294.0-rc.4";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -3,6 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { originTime } from '../constants/runtime';
6
+ import { isNative } from '../util/monkey-patched';
6
7
 
7
8
  /**
8
9
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
@@ -38,6 +39,7 @@ export class TimeKeeper {
38
39
  constructor(sessionObj) {
39
40
  this.#session = sessionObj;
40
41
  this.processStoredDiff();
42
+ isNative(performance.now, Date.now); // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
41
43
  }
42
44
  get ready() {
43
45
  return this.#ready;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { warn } from './console';
6
+ const checked = new Map();
7
+
8
+ /**
9
+ * Checks if the provided functions are native functions.
10
+ * @param {...Function} fns - An array of functions to check if they are native.
11
+ * @returns {boolean} true if all the expected globals are native, false otherwise
12
+ */
13
+ export function isNative(...fns) {
14
+ return fns.every(fn => {
15
+ if (checked.has(fn)) return checked.get(fn);
16
+ const isNative = typeof fn === 'function' && fn.toString().includes('[native code]');
17
+ if (!isNative) {
18
+ warn(64, fn?.name || fn?.toString());
19
+ }
20
+ checked.set(fn, isNative);
21
+ return isNative;
22
+ });
23
+ }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { globalScope } from '../constants/runtime';
6
6
  import { now } from '../timing/now';
7
+ import { isNative } from '../util/monkey-patched';
7
8
  export const defaults = {
8
9
  beacon: 'bam.nr-data.net',
9
10
  errorBeacon: 'bam.nr-data.net'
@@ -46,7 +47,7 @@ export function gosNREUMOriginals() {
46
47
  if (!nr.o) {
47
48
  nr.o = {
48
49
  ST: globalScope.setTimeout,
49
- SI: globalScope.setImmediate,
50
+ SI: globalScope.setImmediate || globalScope.setInterval,
50
51
  CT: globalScope.clearTimeout,
51
52
  XHR: globalScope.XMLHttpRequest,
52
53
  REQ: globalScope.Request,
@@ -57,6 +58,7 @@ export function gosNREUMOriginals() {
57
58
  FETCH: globalScope.fetch,
58
59
  WS: globalScope.WebSocket
59
60
  };
61
+ isNative(...Object.values(nr.o)); // Warns if the originals are not native, which is typically required for the agent to work properly
60
62
  }
61
63
  return nr;
62
64
  }
@@ -10,6 +10,7 @@ import { globalScope } from '../../../common/constants/runtime';
10
10
  import { setupLogAPI } from '../../../loaders/api/log';
11
11
  import { setupWrapLoggerAPI } from '../../../loaders/api/wrapLogger';
12
12
  import { setupRegisterAPI } from '../../../loaders/api/register';
13
+ import { isNative } from '../../../common/util/monkey-patched';
13
14
  export class Instrument extends InstrumentBase {
14
15
  static featureName = FEATURE_NAME;
15
16
  constructor(agentRef) {
@@ -20,24 +21,14 @@ export class Instrument extends InstrumentBase {
20
21
  setupWrapLoggerAPI(agentRef);
21
22
  setupRegisterAPI(agentRef);
22
23
  const instanceEE = this.ee;
23
- wrapLogger(instanceEE, globalScope.console, 'log', {
24
- level: 'info'
25
- });
26
- wrapLogger(instanceEE, globalScope.console, 'error', {
27
- level: 'error'
28
- });
29
- wrapLogger(instanceEE, globalScope.console, 'warn', {
30
- level: 'warn'
31
- });
32
- wrapLogger(instanceEE, globalScope.console, 'info', {
33
- level: 'info'
34
- });
35
- wrapLogger(instanceEE, globalScope.console, 'debug', {
36
- level: 'debug'
37
- });
38
- wrapLogger(instanceEE, globalScope.console, 'trace', {
39
- level: 'trace'
24
+ const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace'];
25
+ globals.forEach(method => {
26
+ isNative(globalScope.console[method]);
27
+ wrapLogger(instanceEE, globalScope.console, method, {
28
+ level: method === 'log' ? 'info' : method
29
+ });
40
30
  });
31
+
41
32
  /** emitted by wrap-logger function */
42
33
  this.ee.on('wrap-logger-end', function handleLog([message]) {
43
34
  const {
@@ -286,6 +286,24 @@ export class Aggregate extends AggregateBase {
286
286
  if (node.__newrelic) return node.timestamp;
287
287
  return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp);
288
288
  }
289
+
290
+ /**
291
+ * returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
292
+ * @param {Object[]} [nodes] - the nodes to evaluate
293
+ * @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
294
+ */
295
+ getFirstAndLastNodes(nodes = []) {
296
+ const output = {
297
+ firstEvent: nodes[0],
298
+ lastEvent: nodes[nodes.length - 1]
299
+ };
300
+ nodes.forEach(node => {
301
+ const timestamp = node?.timestamp;
302
+ if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node;
303
+ if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node;
304
+ });
305
+ return output;
306
+ }
289
307
  getHarvestContents(recorderEvents) {
290
308
  recorderEvents ??= this.recorder.getEvents();
291
309
  let events = recorderEvents.events;
@@ -310,11 +328,13 @@ export class Aggregate extends AggregateBase {
310
328
  recorderEvents.hasMeta = !!events.find(x => x.type === RRWEB_EVENT_TYPES.Meta);
311
329
  }
312
330
  const relativeNow = now();
313
- const firstEventTimestamp = this.getCorrectedTimestamp(events[0]); // from rrweb node
314
- const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]); // from rrweb node
331
+ const {
332
+ firstEvent,
333
+ lastEvent
334
+ } = this.getFirstAndLastNodes(events);
315
335
  // from rrweb node || from when the harvest cycle started
316
- const firstTimestamp = firstEventTimestamp || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
317
- const lastTimestamp = lastEventTimestamp || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
336
+ const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp));
337
+ const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow));
318
338
  const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {};
319
339
  return {
320
340
  qs: {
@@ -1 +1 @@
1
- {"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
1
+ {"root":["../src/index.js","../src/cdn/experimental.js","../src/cdn/lite.js","../src/cdn/pro.js","../src/cdn/spa.js","../src/common/aggregate/aggregator.js","../src/common/aggregate/event-aggregator.js","../src/common/config/configurable.js","../src/common/config/info.js","../src/common/config/init-types.js","../src/common/config/init.js","../src/common/config/loader-config.js","../src/common/config/runtime.js","../src/common/constants/agent-constants.js","../src/common/constants/env.cdn.js","../src/common/constants/env.js","../src/common/constants/env.npm.js","../src/common/constants/runtime.js","../src/common/constants/shared-channel.js","../src/common/deny-list/deny-list.js","../src/common/dispatch/global-event.js","../src/common/dom/iframe.js","../src/common/dom/query-selector.js","../src/common/dom/selector-path.js","../src/common/drain/drain.js","../src/common/event-emitter/contextual-ee.js","../src/common/event-emitter/event-context.js","../src/common/event-emitter/handle.js","../src/common/event-emitter/register-handler.js","../src/common/event-listener/event-listener-opts.js","../src/common/harvest/harvester.js","../src/common/harvest/types.js","../src/common/ids/bundle-id.js","../src/common/ids/id.js","../src/common/ids/unique-id.js","../src/common/serialize/bel-serializer.js","../src/common/session/constants.js","../src/common/session/session-entity.js","../src/common/storage/local-storage.js","../src/common/timer/interaction-timer.js","../src/common/timer/timer.js","../src/common/timing/nav-timing.js","../src/common/timing/now.js","../src/common/timing/time-keeper.js","../src/common/unload/eol.js","../src/common/url/canonicalize-url.js","../src/common/url/clean-url.js","../src/common/url/encode.js","../src/common/url/location.js","../src/common/url/parse-url.js","../src/common/url/protocol.js","../src/common/util/attribute-size.js","../src/common/util/console.js","../src/common/util/data-size.js","../src/common/util/event-origin.js","../src/common/util/feature-flags.js","../src/common/util/get-or-set.js","../src/common/util/invoke.js","../src/common/util/monkey-patched.js","../src/common/util/obfuscate.js","../src/common/util/stringify.js","../src/common/util/submit-data.js","../src/common/util/target.js","../src/common/util/text.js","../src/common/util/traverse.js","../src/common/util/type-check.js","../src/common/vitals/constants.js","../src/common/vitals/cumulative-layout-shift.js","../src/common/vitals/first-contentful-paint.js","../src/common/vitals/first-paint.js","../src/common/vitals/interaction-to-next-paint.js","../src/common/vitals/largest-contentful-paint.js","../src/common/vitals/time-to-first-byte.js","../src/common/vitals/vital-metric.js","../src/common/window/load.js","../src/common/window/nreum.js","../src/common/window/page-visibility.js","../src/common/wrap/wrap-events.js","../src/common/wrap/wrap-fetch.js","../src/common/wrap/wrap-function.js","../src/common/wrap/wrap-history.js","../src/common/wrap/wrap-jsonp.js","../src/common/wrap/wrap-logger.js","../src/common/wrap/wrap-mutation.js","../src/common/wrap/wrap-promise.js","../src/common/wrap/wrap-timer.js","../src/common/wrap/wrap-websocket.js","../src/common/wrap/wrap-xhr.js","../src/features/ajax/constants.js","../src/features/ajax/index.js","../src/features/ajax/aggregate/gql.js","../src/features/ajax/aggregate/index.js","../src/features/ajax/instrument/distributed-tracing.js","../src/features/ajax/instrument/index.js","../src/features/ajax/instrument/response-size.js","../src/features/generic_events/constants.js","../src/features/generic_events/index.js","../src/features/generic_events/aggregate/index.js","../src/features/generic_events/aggregate/user-actions/aggregated-user-action.js","../src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js","../src/features/generic_events/instrument/index.js","../src/features/jserrors/constants.js","../src/features/jserrors/index.js","../src/features/jserrors/aggregate/canonical-function-name.js","../src/features/jserrors/aggregate/cause-string.js","../src/features/jserrors/aggregate/compute-stack-trace.js","../src/features/jserrors/aggregate/format-stack-trace.js","../src/features/jserrors/aggregate/index.js","../src/features/jserrors/aggregate/internal-errors.js","../src/features/jserrors/aggregate/string-hash-code.js","../src/features/jserrors/instrument/index.js","../src/features/jserrors/shared/cast-error.js","../src/features/jserrors/shared/uncaught-error.js","../src/features/logging/constants.js","../src/features/logging/index.js","../src/features/logging/aggregate/index.js","../src/features/logging/instrument/index.js","../src/features/logging/shared/log.js","../src/features/logging/shared/utils.js","../src/features/metrics/constants.js","../src/features/metrics/index.js","../src/features/metrics/aggregate/framework-detection.js","../src/features/metrics/aggregate/index.js","../src/features/metrics/aggregate/websocket-detection.js","../src/features/metrics/instrument/index.js","../src/features/page_action/constants.js","../src/features/page_action/index.js","../src/features/page_action/instrument/index.js","../src/features/page_view_event/constants.js","../src/features/page_view_event/index.js","../src/features/page_view_event/aggregate/index.js","../src/features/page_view_event/aggregate/initialized-features.js","../src/features/page_view_event/instrument/index.js","../src/features/page_view_timing/constants.js","../src/features/page_view_timing/index.js","../src/features/page_view_timing/aggregate/index.js","../src/features/page_view_timing/instrument/index.js","../src/features/session_replay/constants.js","../src/features/session_replay/index.js","../src/features/session_replay/aggregate/index.js","../src/features/session_replay/instrument/index.js","../src/features/session_replay/shared/recorder-events.js","../src/features/session_replay/shared/recorder.js","../src/features/session_replay/shared/stylesheet-evaluator.js","../src/features/session_replay/shared/utils.js","../src/features/session_trace/constants.js","../src/features/session_trace/index.js","../src/features/session_trace/aggregate/index.js","../src/features/session_trace/aggregate/trace/node.js","../src/features/session_trace/aggregate/trace/storage.js","../src/features/session_trace/instrument/index.js","../src/features/soft_navigations/constants.js","../src/features/soft_navigations/index.js","../src/features/soft_navigations/aggregate/ajax-node.js","../src/features/soft_navigations/aggregate/bel-node.js","../src/features/soft_navigations/aggregate/index.js","../src/features/soft_navigations/aggregate/initial-page-load-interaction.js","../src/features/soft_navigations/aggregate/interaction.js","../src/features/soft_navigations/instrument/index.js","../src/features/spa/constants.js","../src/features/spa/index.js","../src/features/spa/aggregate/index.js","../src/features/spa/aggregate/interaction-node.js","../src/features/spa/aggregate/interaction.js","../src/features/spa/aggregate/serializer.js","../src/features/spa/instrument/index.js","../src/features/utils/agent-session.js","../src/features/utils/aggregate-base.js","../src/features/utils/entity-manager.js","../src/features/utils/event-buffer.js","../src/features/utils/event-store-manager.js","../src/features/utils/feature-base.js","../src/features/utils/feature-gates.js","../src/features/utils/instrument-base.js","../src/features/utils/nr1-debugger.js","../src/interfaces/registered-entity.js","../src/loaders/agent-base.js","../src/loaders/agent.js","../src/loaders/api-base.js","../src/loaders/browser-agent.js","../src/loaders/micro-agent-base.js","../src/loaders/micro-agent.js","../src/loaders/api/addPageAction.js","../src/loaders/api/addRelease.js","../src/loaders/api/addToTrace.js","../src/loaders/api/constants.js","../src/loaders/api/finished.js","../src/loaders/api/interaction-types.js","../src/loaders/api/interaction.js","../src/loaders/api/log.js","../src/loaders/api/measure.js","../src/loaders/api/noticeError.js","../src/loaders/api/pauseReplay.js","../src/loaders/api/recordCustomEvent.js","../src/loaders/api/recordReplay.js","../src/loaders/api/register-api-types.js","../src/loaders/api/register-api.js","../src/loaders/api/register.js","../src/loaders/api/setApplicationVersion.js","../src/loaders/api/setCustomAttribute.js","../src/loaders/api/setErrorHandler.js","../src/loaders/api/setPageViewName.js","../src/loaders/api/setUserId.js","../src/loaders/api/sharedHandlers.js","../src/loaders/api/start.js","../src/loaders/api/topLevelCallers.js","../src/loaders/api/wrapLogger.js","../src/loaders/configure/configure.js","../src/loaders/configure/nonce.js","../src/loaders/configure/public-path.js","../src/loaders/features/enabled-features.js","../src/loaders/features/featureDependencies.js","../src/loaders/features/features.js"],"version":"5.7.3"}
@@ -1 +1 @@
1
- {"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAMA;;;;GAIG;AACH;IA2BE,6BAGC;IAED,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAIlB;IAED,+FAA+F;IAC/F,0BASC;;CACF"}
1
+ {"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH;IA2BE,6BAIC;IAED,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAIlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAIjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAIlB;IAED,+FAA+F;IAC/F,0BASC;;CACF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Checks if the provided functions are native functions.
3
+ * @param {...Function} fns - An array of functions to check if they are native.
4
+ * @returns {boolean} true if all the expected globals are native, false otherwise
5
+ */
6
+ export function isNative(...fns: Function[]): boolean;
7
+ //# sourceMappingURL=monkey-patched.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monkey-patched.d.ts","sourceRoot":"","sources":["../../../../src/common/util/monkey-patched.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,iCAHW,UAAW,GACT,OAAO,CAYnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"nreum.d.ts","sourceRoot":"","sources":["../../../../src/common/window/nreum.js"],"names":[],"mappings":"AAYA,gCAMC;AAED,oCAWC;AAED,4CASC;AAED,oCASC;AAED,yCAiBC;AAED,+EAQC;AAED;;;;GAIG;AACH,uDAGC;AAED,uDAGC;AAED,yCAGC;AAED,8BAMC"}
1
+ {"version":3,"file":"nreum.d.ts","sourceRoot":"","sources":["../../../../src/common/window/nreum.js"],"names":[],"mappings":"AAaA,gCAMC;AAED,oCAWC;AAED,4CASC;AAED,oCASC;AAED,yCAkBC;AAED,+EAQC;AAED;;;;GAIG;AACH,uDAGC;AAED,uDAGC;AAED,yCAGC;AAED,8BAMC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/instrument/index.js"],"names":[],"mappings":"AAaA;IACE,2BAAiC;IACjC,2BAqBC;CACF;AAED,wCAAiC;+BAnCF,6BAA6B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/logging/instrument/index.js"],"names":[],"mappings":"AAcA;IACE,2BAAiC;IACjC,2BAsBC;CACF;AAED,wCAAiC;+BArCF,6BAA6B"}
@@ -31,6 +31,15 @@ export class Aggregate extends AggregateBase {
31
31
  payload: undefined;
32
32
  }[] | undefined;
33
33
  getCorrectedTimestamp(node: any): any;
34
+ /**
35
+ * returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
36
+ * @param {Object[]} [nodes] - the nodes to evaluate
37
+ * @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
38
+ */
39
+ getFirstAndLastNodes(nodes?: Object[]): {
40
+ firstEvent: Object | undefined;
41
+ lastEvent: Object | undefined;
42
+ };
34
43
  getHarvestContents(recorderEvents: any): {
35
44
  qs: {
36
45
  browser_monitoring_key: any;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAsFC;IAzFD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,kBAA+C;IAG/C,kCAAqG;IAoEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;OAKG;IACH,4BAJW,OAAO,iBACP,OAAO,GACL,IAAI,CAuDhB;IAED,2BASC;IAED;;;oBAuDC;IAED,sCAIC;IAED;;;;;;;;;;MAuEC;IAED,sCAKC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,+CASC;IAED,yCAIC;CACF;8BAxX6B,4BAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/session_replay/aggregate/index.js"],"names":[],"mappings":"AAyBA;IACE,2BAAiC;IAIjC,sCAsFC;IAzFD,aAAe;IAKb,iFAAiF;IACjF,qBAAwB;IAGxB,2CAA2C;IAC3C,sDAAwB;IACxB,6CAA6C;IAC7C,gDAAmB;IAEnB,0BAA0B;IAC1B,kBAAqB;IACrB,6CAA6C;IAC7C,gBAA2B;IAE3B,cAA8B;IAC9B,kBAA+C;IAG/C,kCAAqG;IAoEvG,0BAEC;IAED,0BAMC;IAED,qBAUC;IAED;;;;;OAKG;IACH,4BAJW,OAAO,iBACP,OAAO,GACL,IAAI,CAuDhB;IAED,2BASC;IAED;;;oBAuDC;IAED,sCAIC;IAED;;;;OAIG;IACH,6BAHW,MAAM,EAAE,GACN;QAAE,UAAU,EAAE,MAAM,GAAC,SAAS,CAAC;QAAC,SAAS,EAAE,MAAM,GAAC,SAAS,CAAA;KAAE,CAUzE;IAED;;;;;;;;;;MAsEC;IAED,sCAKC;IAED;;;;OAIG;IACH,mCAKC;IAED,yDAAyD;IACzD,+CASC;IAED,yCAIC;CACF;8BAtY6B,4BAA4B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.294.0-rc.2",
3
+ "version": "1.294.0-rc.4",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -3,6 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { originTime } from '../constants/runtime'
6
+ import { isNative } from '../util/monkey-patched'
6
7
 
7
8
  /**
8
9
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
@@ -39,6 +40,7 @@ export class TimeKeeper {
39
40
  constructor (sessionObj) {
40
41
  this.#session = sessionObj
41
42
  this.processStoredDiff()
43
+ isNative(performance.now, Date.now) // will warn the user if these are not native functions. We need these to be native for time in the agent to be accurate in general.
42
44
  }
43
45
 
44
46
  get ready () {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Copyright 2020-2025 New Relic, Inc. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { warn } from './console'
6
+
7
+ const checked = new Map()
8
+
9
+ /**
10
+ * Checks if the provided functions are native functions.
11
+ * @param {...Function} fns - An array of functions to check if they are native.
12
+ * @returns {boolean} true if all the expected globals are native, false otherwise
13
+ */
14
+ export function isNative (...fns) {
15
+ return fns.every(fn => {
16
+ if (checked.has(fn)) return checked.get(fn)
17
+ const isNative = typeof fn === 'function' && fn.toString().includes('[native code]')
18
+ if (!isNative) {
19
+ warn(64, fn?.name || fn?.toString())
20
+ }
21
+ checked.set(fn, isNative)
22
+ return isNative
23
+ })
24
+ }
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { globalScope } from '../constants/runtime'
6
6
  import { now } from '../timing/now'
7
+ import { isNative } from '../util/monkey-patched'
7
8
 
8
9
  export const defaults = {
9
10
  beacon: 'bam.nr-data.net',
@@ -58,7 +59,7 @@ export function gosNREUMOriginals () {
58
59
  if (!nr.o) {
59
60
  nr.o = {
60
61
  ST: globalScope.setTimeout,
61
- SI: globalScope.setImmediate,
62
+ SI: globalScope.setImmediate || globalScope.setInterval,
62
63
  CT: globalScope.clearTimeout,
63
64
  XHR: globalScope.XMLHttpRequest,
64
65
  REQ: globalScope.Request,
@@ -68,6 +69,7 @@ export function gosNREUMOriginals () {
68
69
  FETCH: globalScope.fetch,
69
70
  WS: globalScope.WebSocket
70
71
  }
72
+ isNative(...Object.values(nr.o)) // Warns if the originals are not native, which is typically required for the agent to work properly
71
73
  }
72
74
  return nr
73
75
  }
@@ -10,6 +10,7 @@ import { globalScope } from '../../../common/constants/runtime'
10
10
  import { setupLogAPI } from '../../../loaders/api/log'
11
11
  import { setupWrapLoggerAPI } from '../../../loaders/api/wrapLogger'
12
12
  import { setupRegisterAPI } from '../../../loaders/api/register'
13
+ import { isNative } from '../../../common/util/monkey-patched'
13
14
 
14
15
  export class Instrument extends InstrumentBase {
15
16
  static featureName = FEATURE_NAME
@@ -22,12 +23,13 @@ export class Instrument extends InstrumentBase {
22
23
  setupRegisterAPI(agentRef)
23
24
 
24
25
  const instanceEE = this.ee
25
- wrapLogger(instanceEE, globalScope.console, 'log', { level: 'info' })
26
- wrapLogger(instanceEE, globalScope.console, 'error', { level: 'error' })
27
- wrapLogger(instanceEE, globalScope.console, 'warn', { level: 'warn' })
28
- wrapLogger(instanceEE, globalScope.console, 'info', { level: 'info' })
29
- wrapLogger(instanceEE, globalScope.console, 'debug', { level: 'debug' })
30
- wrapLogger(instanceEE, globalScope.console, 'trace', { level: 'trace' })
26
+ const globals = ['log', 'error', 'warn', 'info', 'debug', 'trace']
27
+
28
+ globals.forEach((method) => {
29
+ isNative(globalScope.console[method])
30
+ wrapLogger(instanceEE, globalScope.console, method, { level: method === 'log' ? 'info' : method })
31
+ })
32
+
31
33
  /** emitted by wrap-logger function */
32
34
  this.ee.on('wrap-logger-end', function handleLog ([message]) {
33
35
  const { level, customAttributes } = this
@@ -275,6 +275,21 @@ export class Aggregate extends AggregateBase {
275
275
  return this.timeKeeper.correctAbsoluteTimestamp(node.timestamp)
276
276
  }
277
277
 
278
+ /**
279
+ * returns the timestamps for the earliest and latest nodes in the provided array, even if out of order
280
+ * @param {Object[]} [nodes] - the nodes to evaluate
281
+ * @returns {{ firstEvent: Object|undefined, lastEvent: Object|undefined }} - the earliest and latest nodes. Defaults to undefined if no nodes are provided or if no timestamps are found in the nodes.
282
+ */
283
+ getFirstAndLastNodes (nodes = []) {
284
+ const output = { firstEvent: nodes[0], lastEvent: nodes[nodes.length - 1] }
285
+ nodes.forEach(node => {
286
+ const timestamp = node?.timestamp
287
+ if (!output.firstEvent?.timestamp || (timestamp || Infinity) < output.firstEvent.timestamp) output.firstEvent = node
288
+ if (!output.lastEvent?.timestamp || (timestamp || -Infinity) > output.lastEvent.timestamp) output.lastEvent = node
289
+ })
290
+ return output
291
+ }
292
+
278
293
  getHarvestContents (recorderEvents) {
279
294
  recorderEvents ??= this.recorder.getEvents()
280
295
  let events = recorderEvents.events
@@ -301,11 +316,10 @@ export class Aggregate extends AggregateBase {
301
316
 
302
317
  const relativeNow = now()
303
318
 
304
- const firstEventTimestamp = this.getCorrectedTimestamp(events[0]) // from rrweb node
305
- const lastEventTimestamp = this.getCorrectedTimestamp(events[events.length - 1]) // from rrweb node
319
+ const { firstEvent, lastEvent } = this.getFirstAndLastNodes(events)
306
320
  // from rrweb node || from when the harvest cycle started
307
- const firstTimestamp = firstEventTimestamp || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp))
308
- const lastTimestamp = lastEventTimestamp || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow))
321
+ const firstTimestamp = this.getCorrectedTimestamp(firstEvent) || Math.floor(this.timeKeeper.correctAbsoluteTimestamp(recorderEvents.cycleTimestamp))
322
+ const lastTimestamp = this.getCorrectedTimestamp(lastEvent) || Math.floor(this.timeKeeper.correctRelativeTimestamp(relativeNow))
309
323
 
310
324
  const agentMetadata = agentRuntime.appMetadata?.agents?.[0] || {}
311
325