@newrelic/browser-agent 1.256.1 → 1.258.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/cjs/common/config/state/configurable.js +8 -5
  3. package/dist/cjs/common/config/state/init.js +0 -2
  4. package/dist/cjs/common/config/state/runtime.js +10 -8
  5. package/dist/cjs/common/constants/env.cdn.js +1 -1
  6. package/dist/cjs/common/constants/env.npm.js +1 -1
  7. package/dist/cjs/common/constants/runtime.js +8 -2
  8. package/dist/cjs/common/harvest/harvest.js +7 -5
  9. package/dist/cjs/common/session/constants.js +1 -0
  10. package/dist/cjs/common/session/session-entity.js +3 -0
  11. package/dist/cjs/common/timing/time-keeper.js +45 -9
  12. package/dist/cjs/common/vitals/time-to-first-byte.js +1 -1
  13. package/dist/cjs/common/vitals/vital-metric.js +1 -1
  14. package/dist/cjs/features/ajax/aggregate/chunk.js +50 -0
  15. package/dist/cjs/features/ajax/aggregate/index.js +131 -191
  16. package/dist/cjs/features/ajax/instrument/index.js +0 -3
  17. package/dist/cjs/features/jserrors/aggregate/index.js +26 -13
  18. package/dist/cjs/features/page_view_event/aggregate/index.js +3 -3
  19. package/dist/cjs/features/session_replay/aggregate/index.js +12 -5
  20. package/dist/cjs/features/session_replay/constants.js +2 -1
  21. package/dist/cjs/features/session_replay/instrument/index.js +15 -5
  22. package/dist/cjs/features/session_replay/shared/recorder.js +6 -3
  23. package/dist/cjs/features/session_replay/shared/utils.js +9 -8
  24. package/dist/cjs/features/session_trace/aggregate/index.js +3 -5
  25. package/dist/cjs/features/soft_navigations/aggregate/index.js +2 -2
  26. package/dist/cjs/features/spa/instrument/index.js +0 -2
  27. package/dist/cjs/features/utils/agent-session.js +1 -5
  28. package/dist/cjs/features/utils/instrument-base.js +11 -14
  29. package/dist/cjs/features/utils/nr1-debugger.js +27 -0
  30. package/dist/cjs/loaders/agent.js +4 -0
  31. package/dist/cjs/loaders/api/apiAsync.js +5 -4
  32. package/dist/esm/common/config/state/configurable.js +8 -5
  33. package/dist/esm/common/config/state/init.js +0 -2
  34. package/dist/esm/common/config/state/runtime.js +11 -9
  35. package/dist/esm/common/constants/env.cdn.js +1 -1
  36. package/dist/esm/common/constants/env.npm.js +1 -1
  37. package/dist/esm/common/constants/runtime.js +7 -1
  38. package/dist/esm/common/harvest/harvest.js +7 -5
  39. package/dist/esm/common/session/constants.js +1 -0
  40. package/dist/esm/common/session/session-entity.js +3 -0
  41. package/dist/esm/common/timing/time-keeper.js +46 -9
  42. package/dist/esm/common/vitals/time-to-first-byte.js +2 -2
  43. package/dist/esm/common/vitals/vital-metric.js +1 -1
  44. package/dist/esm/features/ajax/aggregate/chunk.js +43 -0
  45. package/dist/esm/features/ajax/aggregate/index.js +130 -191
  46. package/dist/esm/features/ajax/instrument/index.js +1 -4
  47. package/dist/esm/features/jserrors/aggregate/index.js +26 -13
  48. package/dist/esm/features/page_view_event/aggregate/index.js +4 -4
  49. package/dist/esm/features/session_replay/aggregate/index.js +12 -5
  50. package/dist/esm/features/session_replay/constants.js +2 -1
  51. package/dist/esm/features/session_replay/instrument/index.js +16 -6
  52. package/dist/esm/features/session_replay/shared/recorder.js +6 -3
  53. package/dist/esm/features/session_replay/shared/utils.js +9 -7
  54. package/dist/esm/features/session_trace/aggregate/index.js +3 -5
  55. package/dist/esm/features/soft_navigations/aggregate/index.js +2 -2
  56. package/dist/esm/features/spa/instrument/index.js +0 -2
  57. package/dist/esm/features/utils/agent-session.js +1 -5
  58. package/dist/esm/features/utils/instrument-base.js +11 -14
  59. package/dist/esm/features/utils/nr1-debugger.js +21 -0
  60. package/dist/esm/loaders/agent.js +4 -0
  61. package/dist/esm/loaders/api/apiAsync.js +5 -4
  62. package/dist/types/common/config/state/configurable.d.ts.map +1 -1
  63. package/dist/types/common/config/state/init.d.ts.map +1 -1
  64. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  65. package/dist/types/common/constants/runtime.d.ts +6 -1
  66. package/dist/types/common/constants/runtime.d.ts.map +1 -1
  67. package/dist/types/common/harvest/harvest.d.ts +1 -1
  68. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  69. package/dist/types/common/session/constants.d.ts +1 -0
  70. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  71. package/dist/types/common/timing/time-keeper.d.ts +1 -1
  72. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  73. package/dist/types/features/ajax/aggregate/chunk.d.ts +8 -0
  74. package/dist/types/features/ajax/aggregate/chunk.d.ts.map +1 -0
  75. package/dist/types/features/ajax/aggregate/index.d.ts +8 -6
  76. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  77. package/dist/types/features/ajax/instrument/index.d.ts +2 -2
  78. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  79. package/dist/types/features/jserrors/aggregate/index.d.ts +0 -1
  80. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  81. package/dist/types/features/session_replay/aggregate/index.d.ts +0 -1
  82. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  83. package/dist/types/features/session_replay/constants.d.ts +1 -0
  84. package/dist/types/features/session_replay/constants.d.ts.map +1 -1
  85. package/dist/types/features/session_replay/instrument/index.d.ts +1 -0
  86. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
  87. package/dist/types/features/session_replay/shared/recorder.d.ts +1 -0
  88. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  89. package/dist/types/features/session_replay/shared/utils.d.ts +5 -5
  90. package/dist/types/features/session_replay/shared/utils.d.ts.map +1 -1
  91. package/dist/types/features/session_trace/aggregate/index.d.ts +8 -8
  92. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  93. package/dist/types/features/spa/instrument/index.d.ts.map +1 -1
  94. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  95. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  96. package/dist/types/features/utils/nr1-debugger.d.ts +2 -0
  97. package/dist/types/features/utils/nr1-debugger.d.ts.map +1 -0
  98. package/dist/types/loaders/agent.d.ts +5 -1
  99. package/dist/types/loaders/agent.d.ts.map +1 -1
  100. package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
  101. package/package.json +1 -1
  102. package/src/common/config/state/configurable.js +9 -8
  103. package/src/common/config/state/init.js +0 -1
  104. package/src/common/config/state/runtime.js +12 -9
  105. package/src/common/constants/__mocks__/runtime.js +2 -0
  106. package/src/common/constants/runtime.js +6 -1
  107. package/src/common/drain/__mocks__/drain.js +2 -0
  108. package/src/common/harvest/harvest.js +8 -6
  109. package/src/common/session/constants.js +1 -0
  110. package/src/common/session/session-entity.js +2 -0
  111. package/src/common/timing/time-keeper.js +44 -10
  112. package/src/common/vitals/time-to-first-byte.js +2 -2
  113. package/src/common/vitals/vital-metric.js +1 -1
  114. package/src/common/window/__mocks__/load.js +3 -0
  115. package/src/features/ajax/aggregate/chunk.js +51 -0
  116. package/src/features/ajax/aggregate/index.js +128 -200
  117. package/src/features/ajax/instrument/index.js +1 -4
  118. package/src/features/jserrors/aggregate/index.js +28 -11
  119. package/src/features/page_view_event/aggregate/index.js +4 -4
  120. package/src/features/session_replay/aggregate/index.js +19 -7
  121. package/src/features/session_replay/constants.js +2 -1
  122. package/src/features/session_replay/instrument/index.js +16 -6
  123. package/src/features/session_replay/shared/__mocks__/utils.js +2 -0
  124. package/src/features/session_replay/shared/recorder.js +7 -4
  125. package/src/features/session_replay/shared/utils.js +9 -7
  126. package/src/features/session_trace/aggregate/index.js +3 -6
  127. package/src/features/soft_navigations/aggregate/index.js +2 -2
  128. package/src/features/spa/instrument/index.js +0 -3
  129. package/src/features/utils/__mocks__/agent-session.js +1 -0
  130. package/src/features/utils/__mocks__/feature-base.js +11 -0
  131. package/src/features/utils/agent-session.js +1 -7
  132. package/src/features/utils/instrument-base.js +11 -14
  133. package/src/features/utils/nr1-debugger.js +22 -0
  134. package/src/loaders/agent.js +4 -0
  135. package/src/loaders/api/apiAsync.js +5 -4
  136. package/dist/cjs/common/storage/first-party-cookies.js +0 -36
  137. package/dist/esm/common/storage/first-party-cookies.js +0 -29
  138. package/dist/types/common/storage/first-party-cookies.d.ts +0 -8
  139. package/dist/types/common/storage/first-party-cookies.d.ts.map +0 -1
  140. package/src/common/storage/first-party-cookies.js +0 -32
package/CHANGELOG.md CHANGED
@@ -3,6 +3,38 @@
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.258.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.257.0...v1.258.0) (2024-04-29)
7
+
8
+
9
+ ### Features
10
+
11
+ * Add harvestId to Session Replay payloads ([#1002](https://github.com/newrelic/newrelic-browser-agent/issues/1002)) ([aea9ac4](https://github.com/newrelic/newrelic-browser-agent/commit/aea9ac4dc791c58badc6d2efe7bdbb3c0f51a8bb))
12
+ * JSErrors timestamped per harvest ([#997](https://github.com/newrelic/newrelic-browser-agent/issues/997)) ([97ae128](https://github.com/newrelic/newrelic-browser-agent/commit/97ae128934df7a74701eef001e49b0065ffe8216))
13
+ * Maintain calculated NR server time for session ([#980](https://github.com/newrelic/newrelic-browser-agent/issues/980)) ([c487e04](https://github.com/newrelic/newrelic-browser-agent/commit/c487e04f46a606545c8172b6ed1c022b4dc1cac1))
14
+ * Restructure AJAX Aggregate ([#1003](https://github.com/newrelic/newrelic-browser-agent/issues/1003)) ([1c3a6b9](https://github.com/newrelic/newrelic-browser-agent/commit/1c3a6b963c1eb7e0792225c3a4c15b6fd8d64505))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * Clean up xhrWrappable ([#1000](https://github.com/newrelic/newrelic-browser-agent/issues/1000)) ([5e28fb7](https://github.com/newrelic/newrelic-browser-agent/commit/5e28fb722aa2bf08acc89066d5814e5bef862741))
20
+ * Prevent null CLS ([#993](https://github.com/newrelic/newrelic-browser-agent/issues/993)) ([a518039](https://github.com/newrelic/newrelic-browser-agent/commit/a518039aa61862553d546cf0e675b733a9f9bed7))
21
+
22
+ ## [1.257.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.256.1...v1.257.0) (2024-04-18)
23
+
24
+
25
+ ### Features
26
+
27
+ * Decorate errors with hasReplay individually ([#983](https://github.com/newrelic/newrelic-browser-agent/issues/983)) ([b6a7a3e](https://github.com/newrelic/newrelic-browser-agent/commit/b6a7a3ebcf2a69b9cbe9888208bb62330918cdf7))
28
+ * Session Replay preload optimizations ([#982](https://github.com/newrelic/newrelic-browser-agent/issues/982)) ([fa20693](https://github.com/newrelic/newrelic-browser-agent/commit/fa20693d746bed2fa0b8ff972e4b9bee4bbe6956))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * Agent class type declarations ([#987](https://github.com/newrelic/newrelic-browser-agent/issues/987)) ([b682c88](https://github.com/newrelic/newrelic-browser-agent/commit/b682c880bfb149b61f6c00bf821459ea55a37ae8))
34
+ * JSEerrors harvest hasReplay decoration ([#986](https://github.com/newrelic/newrelic-browser-agent/issues/986)) ([6dd09c5](https://github.com/newrelic/newrelic-browser-agent/commit/6dd09c505af87b3a1b08330362eca46951ea22ed))
35
+ * Session replay preload without autoStart ([#985](https://github.com/newrelic/newrelic-browser-agent/issues/985)) ([f50351a](https://github.com/newrelic/newrelic-browser-agent/commit/f50351acb08b65b03e7f4b5530a001a80fc04ece))
36
+ * Soft navigations memory leak on harvest ([#979](https://github.com/newrelic/newrelic-browser-agent/issues/979)) ([53bb120](https://github.com/newrelic/newrelic-browser-agent/commit/53bb1209cb66fe1a52385b2863e35a93fb29afae))
37
+
6
38
  ## [1.256.1](https://github.com/newrelic/newrelic-browser-agent/compare/v1.256.0...v1.256.1) (2024-04-15)
7
39
 
8
40
 
@@ -13,12 +13,15 @@ function getModeledObject(obj, model) {
13
13
  const output = Object.create(Object.getPrototypeOf(model), Object.getOwnPropertyDescriptors(model));
14
14
  const target = Object.keys(output).length === 0 ? obj : output;
15
15
  for (let key in target) {
16
- if (obj[key] !== undefined) {
17
- try {
18
- 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];
19
- } catch (e) {
20
- (0, _console.warn)('An error occurred while setting a property of a Configurable', e);
16
+ if (obj[key] === undefined) continue;
17
+ try {
18
+ if (obj[key] === null) {
19
+ output[key] = null;
20
+ continue;
21
21
  }
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
+ } catch (e) {
24
+ (0, _console.warn)('An error occurred while setting a property of a Configurable', e);
22
25
  }
23
26
  }
24
27
  return output;
@@ -62,8 +62,6 @@ const model = () => {
62
62
  allowed_origins: undefined
63
63
  },
64
64
  session: {
65
- domain: undefined,
66
- // used by first party cookies to set the top-level domain
67
65
  expiresMs: _constants.DEFAULT_EXPIRES_MS,
68
66
  inactiveMs: _constants.DEFAULT_INACTIVE_MS
69
67
  },
@@ -9,17 +9,18 @@ var _configurable = require("./configurable");
9
9
  var _nreum = require("../../window/nreum");
10
10
  var _runtime = require("../../constants/runtime");
11
11
  var _env = require("../../constants/env.npm");
12
- const model = {
12
+ const readonly = {
13
13
  buildEnv: _env.BUILD_ENV,
14
+ distMethod: _env.DIST_METHOD,
15
+ version: _env.VERSION,
16
+ originTime: _runtime.originTime
17
+ };
18
+ const model = {
14
19
  customTransaction: undefined,
15
20
  disabled: false,
16
- distMethod: _env.DIST_METHOD,
17
21
  isolatedBacklog: false,
18
22
  loaderType: undefined,
19
23
  maxBytes: 30000,
20
- // The "timeOrigin" property is the new standard timestamp property shared across main frame and workers, but is not supported in some early Safari browsers (safari<15) + IE
21
- // ingest expects an integer value, and timeOrigin can return a float.
22
- offset: Math.floor(_runtime.globalScope?.performance?.timeOrigin || _runtime.globalScope?.performance?.timing?.navigationStart || Date.now()),
23
24
  onerror: undefined,
24
25
  origin: '' + _runtime.globalScope.location,
25
26
  ptid: undefined,
@@ -27,8 +28,6 @@ const model = {
27
28
  /** Agent-specific metadata found in the RUM call response. ex. entityGuid */
28
29
  appMetadata: {},
29
30
  session: undefined,
30
- xhrWrappable: typeof _runtime.globalScope.XMLHttpRequest?.prototype?.addEventListener === 'function',
31
- version: _env.VERSION,
32
31
  denyList: undefined,
33
32
  harvestCount: 0,
34
33
  timeKeeper: undefined
@@ -41,7 +40,10 @@ function getRuntime(id) {
41
40
  }
42
41
  function setRuntime(id, obj) {
43
42
  if (!id) throw new Error('All runtime objects require an agent identifier!');
44
- _cache[id] = (0, _configurable.getModeledObject)(obj, model);
43
+ _cache[id] = {
44
+ ...(0, _configurable.getModeledObject)(obj, model),
45
+ ...readonly
46
+ };
45
47
  const agentInst = (0, _nreum.getNREUMInitializedAgent)(id);
46
48
  if (agentInst) agentInst.runtime = _cache[id];
47
49
  }
@@ -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.256.1";
15
+ const VERSION = exports.VERSION = "1.258.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.256.1";
15
+ const VERSION = exports.VERSION = "1.258.0";
16
16
 
17
17
  /**
18
18
  * Exposes the build type of the agent
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.supportsSendBeacon = exports.offset = exports.loadedAsDeferredBrowserScript = exports.isiOS = exports.isWorkerScope = exports.isIE = exports.isBrowserScope = exports.initiallyHidden = exports.initialLocation = exports.iOSBelow16 = exports.globalScope = exports.ffVersion = void 0;
6
+ exports.supportsSendBeacon = exports.originTime = exports.loadedAsDeferredBrowserScript = exports.isiOS = exports.isWorkerScope = exports.isIE = exports.isBrowserScope = exports.initiallyHidden = exports.initialLocation = exports.iOSBelow16 = exports.globalScope = exports.ffVersion = void 0;
7
7
  /**
8
8
  * @file Contains constants about the environment the agent is running
9
9
  * within. These values are derived at the time the agent is first loaded.
@@ -44,4 +44,10 @@ const ffVersion = exports.ffVersion = (() => {
44
44
  const isIE = exports.isIE = Boolean(isBrowserScope && window.document.documentMode); // deprecated property that only works in IE
45
45
 
46
46
  const supportsSendBeacon = exports.supportsSendBeacon = !!globalScope.navigator?.sendBeacon;
47
- const offset = exports.offset = Math.floor(Date.now() - performance.now());
47
+
48
+ /**
49
+ * Represents the absolute timestamp in milliseconds that the page was loaded
50
+ * according to the browser's local clock.
51
+ * @type {number}
52
+ */
53
+ const originTime = exports.originTime = Math.floor(Date.now() - performance.now());
@@ -137,7 +137,7 @@ class Harvest extends _sharedContext.SharedContext {
137
137
  let url = "".concat(protocol, "://").concat(perceviedBeacon).concat(endpointURLPart, "/1/").concat(info.licenseKey);
138
138
  if (customUrl) url = customUrl;
139
139
  if (raw) url = "".concat(protocol, "://").concat(perceviedBeacon, "/").concat(endpoint);
140
- const baseParams = !raw && includeBaseParams ? this.baseQueryString(qs) : '';
140
+ const baseParams = !raw && includeBaseParams ? this.baseQueryString(qs, endpoint) : '';
141
141
  let payloadParams = (0, _encode.obj)(qs, agentRuntime.maxBytes);
142
142
  if (!submitMethod) {
143
143
  submitMethod = submitData.getSubmitMethod({
@@ -207,17 +207,19 @@ class Harvest extends _sharedContext.SharedContext {
207
207
  }
208
208
 
209
209
  // The stuff that gets sent every time.
210
- baseQueryString(qs) {
210
+ baseQueryString(qs, endpoint) {
211
211
  const runtime = (0, _config.getRuntime)(this.sharedContext.agentIdentifier);
212
212
  const info = (0, _config.getInfo)(this.sharedContext.agentIdentifier);
213
213
  const location = (0, _cleanUrl.cleanURL)((0, _location.getLocation)());
214
214
  const ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location;
215
- return ['a=' + info.applicationID, (0, _encode.param)('sa', info.sa ? '' + info.sa : ''), (0, _encode.param)('v', _env.VERSION), transactionNameParam(info), (0, _encode.param)('ct', runtime.customTransaction), '&rst=' + (0, _now.now)(), '&ck=0',
215
+ const hr = runtime?.session?.state.sessionReplayMode === 1 && endpoint !== 'jserrors';
216
+ const qps = ['a=' + info.applicationID, (0, _encode.param)('sa', info.sa ? '' + info.sa : ''), (0, _encode.param)('v', _env.VERSION), transactionNameParam(info), (0, _encode.param)('ct', runtime.customTransaction), '&rst=' + (0, _now.now)(), '&ck=0',
216
217
  // ck param DEPRECATED - still expected by backend
217
218
  '&s=' + (runtime.session?.state.value || '0'),
218
219
  // the 0 id encaps all untrackable and default traffic
219
- (0, _encode.param)('ref', ref), (0, _encode.param)('ptid', runtime.ptid ? '' + runtime.ptid : ''), (0, _encode.param)('hr', runtime?.session?.state.sessionReplayMode === 1 ? '1' : '0', qs) // hasReplay
220
- ].join('');
220
+ (0, _encode.param)('ref', ref), (0, _encode.param)('ptid', runtime.ptid ? '' + runtime.ptid : '')];
221
+ if (hr) qps.push((0, _encode.param)('hr', '1', qs));
222
+ return qps.join('');
221
223
  }
222
224
 
223
225
  /**
@@ -9,6 +9,7 @@ const DEFAULT_KEY = exports.DEFAULT_KEY = 'SESSION';
9
9
  const DEFAULT_EXPIRES_MS = exports.DEFAULT_EXPIRES_MS = 14400000;
10
10
  const DEFAULT_INACTIVE_MS = exports.DEFAULT_INACTIVE_MS = 1800000;
11
11
  const SESSION_EVENTS = exports.SESSION_EVENTS = {
12
+ STARTED: 'session-started',
12
13
  PAUSE: 'session-pause',
13
14
  RESET: 'session-reset',
14
15
  RESUME: 'session-resume',
@@ -29,6 +29,8 @@ const model = {
29
29
  sessionReplaySentFirstChunk: false,
30
30
  sessionTraceMode: _constants.MODE.OFF,
31
31
  traceHarvestStarted: false,
32
+ serverTimeDiff: null,
33
+ // set by TimeKeeper; "undefined" value will not be stringified and stored but "null" will
32
34
  custom: {}
33
35
  };
34
36
  class SessionEntity {
@@ -143,6 +145,7 @@ class SessionEntity {
143
145
  // we can use a modeled object here to help us know and manage what values are being used. -- see "model" above
144
146
  if (this.isNew) this.write((0, _configurable.getModeledObject)(this.state, model), true);else this.sync(initialRead);
145
147
  this.initialized = true;
148
+ this.ee.emit(_constants.SESSION_EVENTS.STARTED, [this.isNew]);
146
149
  }
147
150
 
148
151
  // This is the actual key appended to the storage API
@@ -4,6 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.TimeKeeper = void 0;
7
+ var _runtime = require("../constants/runtime");
8
+ var _contextualEe = require("../event-emitter/contextual-ee");
9
+ var _config = require("../config/config");
10
+ var _constants = require("../session/constants");
7
11
  /**
8
12
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
9
13
  * is done by tracking the performance timings of the RUM call and applying a calculation
@@ -11,10 +15,10 @@ exports.TimeKeeper = void 0;
11
15
  */
12
16
  class TimeKeeper {
13
17
  /**
14
- * Represents the browser origin time.
15
- * @type {number}
18
+ * Pointer to the current agent session if it exists.
19
+ * @type {import('../session/session-entity').SessionEntity}
16
20
  */
17
- #originTime;
21
+ #session;
18
22
 
19
23
  /**
20
24
  * Represents the browser origin time corrected to NR server time.
@@ -35,15 +39,24 @@ class TimeKeeper {
35
39
  * @type {number}
36
40
  */
37
41
  #ready = false;
38
- constructor() {
39
- this.#originTime = Date.now() - performance.now();
42
+ constructor(agentIdentifier) {
43
+ this.#session = (0, _config.getRuntime)(agentIdentifier)?.session;
44
+ if (this.#session) {
45
+ const ee = _contextualEe.ee.get(agentIdentifier);
46
+ ee.on(_constants.SESSION_EVENTS.UPDATE, this.#processSessionUpdate.bind(this));
47
+ ee.on(_constants.SESSION_EVENTS.STARTED, () => {
48
+ if (this.#ready) {
49
+ this.#session.write({
50
+ serverTimeDiff: this.#localTimeDiff
51
+ });
52
+ }
53
+ });
54
+ this.#processSessionUpdate(null, this.#session.read());
55
+ }
40
56
  }
41
57
  get ready() {
42
58
  return this.#ready;
43
59
  }
44
- get originTime() {
45
- return this.#originTime;
46
- }
47
60
  get correctedOriginTime() {
48
61
  return this.#correctedOriginTime;
49
62
  }
@@ -55,6 +68,8 @@ class TimeKeeper {
55
68
  * @param endTime {number} The end time of the RUM request
56
69
  */
57
70
  processRumRequest(rumRequest, startTime, endTime) {
71
+ if (this.#ready) return; // Server time calculated from session entity
72
+
58
73
  const responseDateHeader = rumRequest.getResponseHeader('Date');
59
74
  if (!responseDateHeader) {
60
75
  throw new Error('Missing date header on rum response.');
@@ -64,10 +79,13 @@ class TimeKeeper {
64
79
 
65
80
  // Corrected page origin time
66
81
  this.#correctedOriginTime = Math.floor(Date.parse(responseDateHeader) - serverOffset);
67
- this.#localTimeDiff = this.#originTime - this.#correctedOriginTime;
82
+ this.#localTimeDiff = _runtime.originTime - this.#correctedOriginTime;
68
83
  if (Number.isNaN(this.#correctedOriginTime)) {
69
84
  throw new Error('Date header invalid format.');
70
85
  }
86
+ if (this.#session) this.#session.write({
87
+ serverTimeDiff: this.#localTimeDiff
88
+ });
71
89
  this.#ready = true;
72
90
  }
73
91
 
@@ -89,5 +107,23 @@ class TimeKeeper {
89
107
  correctAbsoluteTimestamp(timestamp) {
90
108
  return Math.floor(timestamp - this.#localTimeDiff);
91
109
  }
110
+
111
+ /**
112
+ * Processes a session entity update payload to extract the server time calculated.
113
+ * @param {import('../session/constants').SESSION_EVENT_TYPES | null} type
114
+ * @param {Object} data
115
+ */
116
+ #processSessionUpdate(type, data) {
117
+ if (typeof data?.serverTimeDiff !== 'number') return;
118
+ if (!type && !this.#ready ||
119
+ // This captures the initial read from the session entity when the timekeeper first initializes
120
+ type === _constants.SESSION_EVENT_TYPES.CROSS_TAB // This captures any cross-tab write of the session entity
121
+ ) {
122
+ // This captures the initial read from the session entity when the timekeeper first initializes
123
+ this.#localTimeDiff = data.serverTimeDiff;
124
+ this.#correctedOriginTime = _runtime.originTime - this.#localTimeDiff;
125
+ this.#ready = true;
126
+ }
127
+ }
92
128
  }
93
129
  exports.TimeKeeper = TimeKeeper;
@@ -27,7 +27,7 @@ if (_runtime.isBrowserScope && typeof PerformanceNavigationTiming !== 'undefined
27
27
  if (!timeToFirstByte.isValid) {
28
28
  const entry = {};
29
29
  // convert real timestamps to relative timestamps to match web-vitals behavior
30
- for (let key in _runtime.globalScope?.performance?.timing || {}) entry[key] = Math.max(_runtime.globalScope?.performance?.timing[key] - _runtime.offset, 0);
30
+ for (let key in _runtime.globalScope?.performance?.timing || {}) entry[key] = Math.max(_runtime.globalScope?.performance?.timing[key] - _runtime.originTime, 0);
31
31
 
32
32
  // ttfb is equiv to document's responseStart property in timing API --> https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming/responseStart
33
33
  timeToFirstByte.update({
@@ -17,7 +17,7 @@ class VitalMetric {
17
17
  value,
18
18
  attrs = {}
19
19
  } = _ref;
20
- if (value < 0) return;
20
+ if (value === undefined || value === null || value < 0) return;
21
21
  const state = {
22
22
  value: this.roundingMethod(value),
23
23
  name: this.name,
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _belSerializer = require("../../../common/serialize/bel-serializer");
8
+ var _config = require("../../../common/config/config");
9
+ class Chunk {
10
+ constructor(events, aggregateInstance) {
11
+ this.addString = (0, _belSerializer.getAddStringContext)(aggregateInstance.agentIdentifier); // pass agentIdentifier here
12
+ this.events = events;
13
+ this.payload = 'bel.7;';
14
+ for (let i = 0; i < events.length; i++) {
15
+ const event = events[i];
16
+ const fields = [(0, _belSerializer.numeric)(event.startTime), (0, _belSerializer.numeric)(event.endTime - event.startTime), (0, _belSerializer.numeric)(0),
17
+ // callbackEnd
18
+ (0, _belSerializer.numeric)(0),
19
+ // no callbackDuration for non-SPA events
20
+ this.addString(event.method), (0, _belSerializer.numeric)(event.status), this.addString(event.domain), this.addString(event.path), (0, _belSerializer.numeric)(event.requestSize), (0, _belSerializer.numeric)(event.responseSize), event.type === 'fetch' ? 1 : '', this.addString(0),
21
+ // nodeId
22
+ (0, _belSerializer.nullable)(event.spanId, this.addString, true) +
23
+ // guid
24
+ (0, _belSerializer.nullable)(event.traceId, this.addString, true) +
25
+ // traceId
26
+ (0, _belSerializer.nullable)(event.spanTimestamp, _belSerializer.numeric, false) // timestamp
27
+ ];
28
+ let insert = '2,';
29
+
30
+ // Since configuration objects (like info) are created new each time they are set, we have to grab the current pointer to the attr object here.
31
+ const jsAttributes = (0, _config.getInfo)(aggregateInstance.agentIdentifier).jsAttributes;
32
+
33
+ // add custom attributes
34
+ // gql decorators are added as custom attributes to alleviate need for new BEL schema
35
+ const attrParts = (0, _belSerializer.addCustomAttributes)({
36
+ ...(jsAttributes || {}),
37
+ ...(event.gql || {})
38
+ }, this.addString);
39
+ fields.unshift((0, _belSerializer.numeric)(attrParts.length));
40
+ insert += fields.join(',');
41
+ if (attrParts && attrParts.length > 0) {
42
+ insert += ';' + attrParts.join(';');
43
+ }
44
+ if (i + 1 < events.length) insert += ';';
45
+ this.payload += insert;
46
+ }
47
+ this.tooBig = this.payload.length * 2 > aggregateInstance.MAX_PAYLOAD_SIZE;
48
+ }
49
+ }
50
+ exports.default = Chunk;