@newrelic/browser-agent 1.313.1-rc.3 → 1.313.1-rc.5

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.
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.313.1-rc.3";
20
+ const VERSION = exports.VERSION = "1.313.1-rc.5";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -17,7 +17,7 @@ exports.VERSION = exports.RRWEB_VERSION = exports.RRWEB_PACKAGE_NAME = exports.D
17
17
  /**
18
18
  * Exposes the version of the agent
19
19
  */
20
- const VERSION = exports.VERSION = "1.313.1-rc.3";
20
+ const VERSION = exports.VERSION = "1.313.1-rc.5";
21
21
 
22
22
  /**
23
23
  * Exposes the build type of the agent
@@ -45,14 +45,19 @@ class TimeKeeper {
45
45
  * @type {boolean}
46
46
  */
47
47
  #ready = false;
48
- #reportedDrift = false;
48
+
49
+ /**
50
+ * The total measured drift in milliseconds. Represents how much performance.now()
51
+ * has fallen behind Date.now(), which is used to correct timestamp conversions.
52
+ * @type {number}
53
+ */
54
+ #measuredDrift = 0;
49
55
  constructor(sessionObj) {
50
56
  this.#session = sessionObj;
51
57
  this.processStoredDiff();
52
58
  (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.
53
59
  }
54
60
  #detectDrift() {
55
- if (this.#reportedDrift) return;
56
61
  try {
57
62
  // Drift detection: measures if performance.now() and Date.now() have become desynchronized
58
63
  // This can happen when a machine sleeps and the performance timer freezes while Date continues
@@ -63,8 +68,13 @@ class TimeKeeper {
63
68
  // Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
64
69
  const drift = Date.now() - _runtime.originTime - performance.now();
65
70
  if (drift > 1000) {
66
- this.#reportedDrift = true;
67
- (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, _features.FEATURE_NAMES.metrics, this.#session.agentRef.ee);
71
+ // Check if this is new drift (increase of >1000ms from last measurement)
72
+ const newDrift = drift - this.#measuredDrift;
73
+ if (newDrift > 1000) {
74
+ // Update measured drift and report it
75
+ this.#measuredDrift = drift;
76
+ if (this.#session) (0, _handle.handle)(_constants.SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, _features.FEATURE_NAMES.metrics, this.#session.agentRef.ee);
77
+ }
68
78
  }
69
79
  } catch (err) {
70
80
  // Silently ignore drift detection errors to avoid breaking normal operation
@@ -115,7 +125,8 @@ class TimeKeeper {
115
125
  */
116
126
  convertRelativeTimestamp(relativeTime) {
117
127
  this.#detectDrift();
118
- return _runtime.originTime + relativeTime;
128
+ // Add measured drift to compensate for performance.now() falling behind
129
+ return _runtime.originTime + relativeTime + this.#measuredDrift;
119
130
  }
120
131
 
121
132
  /**
@@ -126,7 +137,8 @@ class TimeKeeper {
126
137
  */
127
138
  convertAbsoluteTimestamp(timestamp) {
128
139
  this.#detectDrift();
129
- return timestamp - _runtime.originTime;
140
+ // Subtract measured drift since we're converting from absolute to relative
141
+ return timestamp - _runtime.originTime - this.#measuredDrift;
130
142
  }
131
143
 
132
144
  /**
@@ -17,12 +17,15 @@ const loadTime = exports.loadTime = new _vitalMetric.VitalMetric(_constants.VITA
17
17
  if (_runtime.isBrowserScope) {
18
18
  const perf = _runtime.globalScope.performance;
19
19
  const handler = () => {
20
- if (!loadTime.isValid && perf) {
20
+ // setTimeout defers the read until after the load event handler returns,
21
+ // ensuring loadEventEnd is populated (non-zero) — matching the web-vitals onTTFB pattern
22
+ setTimeout(() => {
23
+ if (loadTime.isValid || !perf) return;
21
24
  const navEntry = (0, _runtime.getNavigationEntry)();
22
25
  loadTime.update({
23
26
  value: navEntry ? navEntry.loadEventEnd : perf.timing?.loadEventEnd - _runtime.originTime
24
27
  });
25
- }
28
+ }, 0);
26
29
  };
27
30
  (0, _load.onWindowLoad)(handler, true);
28
31
  }
@@ -11,7 +11,7 @@
11
11
  /**
12
12
  * Exposes the version of the agent
13
13
  */
14
- export const VERSION = "1.313.1-rc.3";
14
+ export const VERSION = "1.313.1-rc.5";
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.313.1-rc.3";
14
+ export const VERSION = "1.313.1-rc.5";
15
15
 
16
16
  /**
17
17
  * Exposes the build type of the agent
@@ -39,14 +39,19 @@ export class TimeKeeper {
39
39
  * @type {boolean}
40
40
  */
41
41
  #ready = false;
42
- #reportedDrift = false;
42
+
43
+ /**
44
+ * The total measured drift in milliseconds. Represents how much performance.now()
45
+ * has fallen behind Date.now(), which is used to correct timestamp conversions.
46
+ * @type {number}
47
+ */
48
+ #measuredDrift = 0;
43
49
  constructor(sessionObj) {
44
50
  this.#session = sessionObj;
45
51
  this.processStoredDiff();
46
52
  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
53
  }
48
54
  #detectDrift() {
49
- if (this.#reportedDrift) return;
50
55
  try {
51
56
  // Drift detection: measures if performance.now() and Date.now() have become desynchronized
52
57
  // This can happen when a machine sleeps and the performance timer freezes while Date continues
@@ -57,8 +62,13 @@ export class TimeKeeper {
57
62
  // Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
58
63
  const drift = Date.now() - originTime - performance.now();
59
64
  if (drift > 1000) {
60
- this.#reportedDrift = true;
61
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee);
65
+ // Check if this is new drift (increase of >1000ms from last measurement)
66
+ const newDrift = drift - this.#measuredDrift;
67
+ if (newDrift > 1000) {
68
+ // Update measured drift and report it
69
+ this.#measuredDrift = drift;
70
+ if (this.#session) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee);
71
+ }
62
72
  }
63
73
  } catch (err) {
64
74
  // Silently ignore drift detection errors to avoid breaking normal operation
@@ -109,7 +119,8 @@ export class TimeKeeper {
109
119
  */
110
120
  convertRelativeTimestamp(relativeTime) {
111
121
  this.#detectDrift();
112
- return originTime + relativeTime;
122
+ // Add measured drift to compensate for performance.now() falling behind
123
+ return originTime + relativeTime + this.#measuredDrift;
113
124
  }
114
125
 
115
126
  /**
@@ -120,7 +131,8 @@ export class TimeKeeper {
120
131
  */
121
132
  convertAbsoluteTimestamp(timestamp) {
122
133
  this.#detectDrift();
123
- return timestamp - originTime;
134
+ // Subtract measured drift since we're converting from absolute to relative
135
+ return timestamp - originTime - this.#measuredDrift;
124
136
  }
125
137
 
126
138
  /**
@@ -10,12 +10,15 @@ export const loadTime = new VitalMetric(VITAL_NAMES.LOAD_TIME);
10
10
  if (isBrowserScope) {
11
11
  const perf = globalScope.performance;
12
12
  const handler = () => {
13
- if (!loadTime.isValid && perf) {
13
+ // setTimeout defers the read until after the load event handler returns,
14
+ // ensuring loadEventEnd is populated (non-zero) — matching the web-vitals onTTFB pattern
15
+ setTimeout(() => {
16
+ if (loadTime.isValid || !perf) return;
14
17
  const navEntry = getNavigationEntry();
15
18
  loadTime.update({
16
19
  value: navEntry ? navEntry.loadEventEnd : perf.timing?.loadEventEnd - originTime
17
20
  });
18
- }
21
+ }, 0);
19
22
  };
20
23
  onWindowLoad(handler, true);
21
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"time-keeper.d.ts","sourceRoot":"","sources":["../../../../src/common/timing/time-keeper.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH;IA6BE,6BAIC;IAsBD,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAKlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAKlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAKjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAKlB;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":"AAUA;;;;GAIG;AACH;IAkCE,6BAIC;IA0BD,qBAEC;IAED,kCAEC;IAED,4BAEC;IAED;;;;;;OAMG;IACH,8BALsB,cAAc,aACf,MAAM,WACR,MAAM,gBACD,MAAM,QAqB7B;IAED;;;;;OAKG;IACH,uCAHwB,MAAM,GACjB,MAAM,CAMlB;IAED;;;;;OAKG;IACH,0CAFa,MAAM,CAMlB;IAED;;;;OAIG;IACH,oCAHqB,MAAM,GACf,MAAM,CAKjB;IAED;;;;OAIG;IACH,uCAHW,mBAAmB,GACjB,MAAM,CAKlB;IAED,+FAA+F;IAC/F,0BASC;;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newrelic/browser-agent",
3
- "version": "1.313.1-rc.3",
3
+ "version": "1.313.1-rc.5",
4
4
  "private": false,
5
5
  "author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
6
6
  "description": "New Relic Browser Agent",
@@ -40,7 +40,12 @@ export class TimeKeeper {
40
40
  */
41
41
  #ready = false
42
42
 
43
- #reportedDrift = false
43
+ /**
44
+ * The total measured drift in milliseconds. Represents how much performance.now()
45
+ * has fallen behind Date.now(), which is used to correct timestamp conversions.
46
+ * @type {number}
47
+ */
48
+ #measuredDrift = 0
44
49
 
45
50
  constructor (sessionObj) {
46
51
  this.#session = sessionObj
@@ -49,7 +54,6 @@ export class TimeKeeper {
49
54
  }
50
55
 
51
56
  #detectDrift () {
52
- if (this.#reportedDrift) return
53
57
  try {
54
58
  // Drift detection: measures if performance.now() and Date.now() have become desynchronized
55
59
  // This can happen when a machine sleeps and the performance timer freezes while Date continues
@@ -60,8 +64,13 @@ export class TimeKeeper {
60
64
  // Note: localTimeDiff (server time offset) is NOT part of drift - that's a legitimate offset
61
65
  const drift = (Date.now() - originTime) - performance.now()
62
66
  if (drift > 1000) {
63
- this.#reportedDrift = true
64
- handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee)
67
+ // Check if this is new drift (increase of >1000ms from last measurement)
68
+ const newDrift = drift - this.#measuredDrift
69
+ if (newDrift > 1000) {
70
+ // Update measured drift and report it
71
+ this.#measuredDrift = drift
72
+ if (this.#session) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Generic/TimeKeeper/ClockDrift/Detected', drift], undefined, FEATURE_NAMES.metrics, this.#session.agentRef.ee)
73
+ }
65
74
  }
66
75
  } catch (err) {
67
76
  // Silently ignore drift detection errors to avoid breaking normal operation
@@ -116,7 +125,8 @@ export class TimeKeeper {
116
125
  */
117
126
  convertRelativeTimestamp (relativeTime) {
118
127
  this.#detectDrift()
119
- return originTime + relativeTime
128
+ // Add measured drift to compensate for performance.now() falling behind
129
+ return originTime + relativeTime + this.#measuredDrift
120
130
  }
121
131
 
122
132
  /**
@@ -127,7 +137,8 @@ export class TimeKeeper {
127
137
  */
128
138
  convertAbsoluteTimestamp (timestamp) {
129
139
  this.#detectDrift()
130
- return timestamp - originTime
140
+ // Subtract measured drift since we're converting from absolute to relative
141
+ return timestamp - originTime - this.#measuredDrift
131
142
  }
132
143
 
133
144
  /**
@@ -12,12 +12,15 @@ export const loadTime = new VitalMetric(VITAL_NAMES.LOAD_TIME)
12
12
  if (isBrowserScope) {
13
13
  const perf = globalScope.performance
14
14
  const handler = () => {
15
- if (!loadTime.isValid && perf) {
15
+ // setTimeout defers the read until after the load event handler returns,
16
+ // ensuring loadEventEnd is populated (non-zero) — matching the web-vitals onTTFB pattern
17
+ setTimeout(() => {
18
+ if (loadTime.isValid || !perf) return
16
19
  const navEntry = getNavigationEntry()
17
20
  loadTime.update({
18
21
  value: navEntry ? navEntry.loadEventEnd : (perf.timing?.loadEventEnd - originTime)
19
22
  })
20
- }
23
+ }, 0)
21
24
  }
22
25
 
23
26
  onWindowLoad(handler, true)