@openreplay/tracker 4.1.8 → 4.1.9

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.
@@ -109,8 +109,7 @@ export default class App {
109
109
  active(): boolean;
110
110
  resetNextPageSession(flag: boolean): void;
111
111
  private _start;
112
- start(options?: StartOptions): Promise<StartPromiseReturn>;
112
+ start(...args: Parameters<App['_start']>): Promise<StartPromiseReturn>;
113
113
  stop(stopWorker?: boolean): void;
114
- restart(): void;
115
114
  }
116
115
  export {};
package/cjs/app/index.js CHANGED
@@ -33,7 +33,7 @@ class App {
33
33
  this.stopCallbacks = [];
34
34
  this.commitCallbacks = [];
35
35
  this.activityState = ActivityState.NotActive;
36
- this.version = '4.1.7'; // TODO: version compatability check inside each plugin.
36
+ this.version = '4.1.8'; // TODO: version compatability check inside each plugin.
37
37
  this.delay = 0;
38
38
  this.projectKey = projectKey;
39
39
  this.options = Object.assign({
@@ -83,7 +83,7 @@ class App {
83
83
  this.worker.onmessage = ({ data }) => {
84
84
  if (data === 'restart') {
85
85
  this.stop(false);
86
- this.start({ forceNew: true }); // TODO: keep userID & metadata (draw scenarios)
86
+ this.start({}, true);
87
87
  }
88
88
  else if (data.type === 'failure') {
89
89
  this.stop(false);
@@ -120,7 +120,6 @@ class App {
120
120
  }
121
121
  send(message, urgent = false) {
122
122
  if (this.activityState === ActivityState.NotActive) {
123
- // this.debug.log('SendiTrying to send when not active', message) <- crashing the app
124
123
  return;
125
124
  }
126
125
  this.messages.push(message);
@@ -269,8 +268,7 @@ class App {
269
268
  this.sessionStorage.removeItem(this.options.session_reset_key);
270
269
  }
271
270
  }
272
- _start(startOpts) {
273
- (0, utils_js_1.adjustTimeOrigin)();
271
+ _start(startOpts = {}, resetByWorker = false) {
274
272
  if (!this.worker) {
275
273
  return Promise.resolve(UnsuccessfulStart('No worker found: perhaps, CSP is not set.'));
276
274
  }
@@ -278,9 +276,19 @@ class App {
278
276
  return Promise.resolve(UnsuccessfulStart('OpenReplay: trying to call `start()` on the instance that has been started already.'));
279
277
  }
280
278
  this.activityState = ActivityState.Starting;
279
+ (0, utils_js_1.adjustTimeOrigin)();
281
280
  if (startOpts.sessionHash) {
282
281
  this.session.applySessionHash(startOpts.sessionHash);
283
282
  }
283
+ if (startOpts.forceNew) {
284
+ // Reset session metadata only if requested directly
285
+ this.session.reset();
286
+ }
287
+ this.session.assign({
288
+ // MBTODO: maybe it would make sense to `forceNew` if the `userID` was changed
289
+ userID: startOpts.userID,
290
+ metadata: startOpts.metadata,
291
+ });
284
292
  const timestamp = (0, utils_js_1.now)();
285
293
  this.worker.postMessage({
286
294
  type: 'start',
@@ -291,23 +299,16 @@ class App {
291
299
  connAttemptCount: this.options.connAttemptCount,
292
300
  connAttemptGap: this.options.connAttemptGap,
293
301
  });
294
- this.session.update({
295
- // TODO: transparent "session" module logic AND explicit internal api for plugins.
296
- // "updating" with old metadata in order to trigger session's UpdateCallbacks.
297
- // (for the case of internal .start() calls, like on "restart" webworker signal or assistent connection in tracker-assist )
298
- metadata: startOpts.metadata || this.session.getInfo().metadata,
299
- userID: startOpts.userID,
300
- });
301
- const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
302
+ const lsReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
302
303
  this.sessionStorage.removeItem(this.options.session_reset_key);
303
- const shouldReset = startOpts.forceNew || sReset !== null;
304
+ const needNewSessionID = startOpts.forceNew || lsReset || resetByWorker;
304
305
  return window
305
306
  .fetch(this.options.ingestPoint + '/v1/web/start', {
306
307
  method: 'POST',
307
308
  headers: {
308
309
  'Content-Type': 'application/json',
309
310
  },
310
- body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: shouldReset ? undefined : this.session.getSessionToken(), deviceMemory: performance_js_1.deviceMemory,
311
+ body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: needNewSessionID ? undefined : this.session.getSessionToken(), deviceMemory: performance_js_1.deviceMemory,
311
312
  jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit })),
312
313
  })
313
314
  .then((r) => {
@@ -329,23 +330,27 @@ class App {
329
330
  if (this.activityState === ActivityState.NotActive) {
330
331
  return Promise.reject('Tracker stopped during authorisation');
331
332
  }
332
- const { token, userUUID, sessionID, projectID, beaconSizeLimit, startTimestamp, // real startTS, derived from sessionID
333
- delay, } = r;
333
+ const { token, userUUID, projectID, beaconSizeLimit, delay, // derived from token
334
+ sessionID, // derived from token
335
+ startTimestamp, // real startTS (server time), derived from sessionID
336
+ } = r;
334
337
  if (typeof token !== 'string' ||
335
338
  typeof userUUID !== 'string' ||
336
- //typeof startTimestamp !== 'number' ||
337
- //typeof sessionID !== 'string' ||
339
+ (typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined') ||
340
+ typeof sessionID !== 'string' ||
338
341
  typeof delay !== 'number' ||
339
342
  (typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
340
343
  return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
341
344
  }
342
345
  this.delay = delay;
343
- const prevSessionID = this.session.getInfo().sessionID;
344
- if (prevSessionID && prevSessionID !== sessionID) {
345
- this.session.reset();
346
- }
347
346
  this.session.setSessionToken(token);
348
- this.session.update({ sessionID, timestamp: startTimestamp || timestamp, projectID }); // TODO: no no-explicit 'any'
347
+ this.session.assign({
348
+ sessionID,
349
+ timestamp: startTimestamp || timestamp,
350
+ projectID,
351
+ });
352
+ // (Re)send Metadata for the case of a new session
353
+ Object.entries(this.session.getInfo().metadata).forEach(([key, value]) => this.send((0, messages_gen_js_1.Metadata)(key, value)));
349
354
  this.localStorage.setItem(this.options.local_uuid_key, userUUID);
350
355
  this.worker.postMessage({
351
356
  type: 'auth',
@@ -376,16 +381,16 @@ class App {
376
381
  return UnsuccessfulStart(START_ERROR);
377
382
  });
378
383
  }
379
- start(options = {}) {
384
+ start(...args) {
380
385
  if (!document.hidden) {
381
- return this._start(options);
386
+ return this._start(...args);
382
387
  }
383
388
  else {
384
389
  return new Promise((resolve) => {
385
390
  const onVisibilityChange = () => {
386
391
  if (!document.hidden) {
387
392
  document.removeEventListener('visibilitychange', onVisibilityChange);
388
- resolve(this._start(options));
393
+ resolve(this._start(...args));
389
394
  }
390
395
  };
391
396
  document.addEventListener('visibilitychange', onVisibilityChange);
@@ -410,9 +415,5 @@ class App {
410
415
  }
411
416
  }
412
417
  }
413
- restart() {
414
- this.stop(false);
415
- this.start({ forceNew: false });
416
- }
417
418
  }
418
419
  exports.default = App;
@@ -23,7 +23,7 @@ export default class Session {
23
23
  constructor(app: App, options: Options);
24
24
  attachUpdateCallback(cb: OnUpdateCallback): void;
25
25
  private handleUpdate;
26
- update(newInfo: Partial<SessionInfo>): void;
26
+ assign(newInfo: Partial<SessionInfo>): void;
27
27
  setMetadata(key: string, value: string): void;
28
28
  setUserID(userID: string): void;
29
29
  private getPageNumber;
@@ -21,7 +21,7 @@ class Session {
21
21
  }
22
22
  this.callbacks.forEach((cb) => cb(newInfo));
23
23
  }
24
- update(newInfo) {
24
+ assign(newInfo) {
25
25
  if (newInfo.userID !== undefined) {
26
26
  // TODO clear nullable/undefinable types
27
27
  this.userID = newInfo.userID;
package/cjs/index.js CHANGED
@@ -138,7 +138,7 @@ class API {
138
138
  // no-cors issue only with text/plain or not-set Content-Type
139
139
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
140
140
  req.send(JSON.stringify({
141
- trackerVersion: '4.1.7',
141
+ trackerVersion: '4.1.8',
142
142
  projectKey: options.projectKey,
143
143
  doNotTrack,
144
144
  // TODO: add precise reason (an exact API missing)
@@ -70,13 +70,12 @@ function default_1(app, opts) {
70
70
  } // Resources are necessary for all timings
71
71
  let resources = {};
72
72
  function resourceTiming(entry) {
73
- var _a;
74
73
  if (entry.duration < 0 || !(0, utils_js_1.isURL)(entry.name) || app.isServiceURL(entry.name))
75
74
  return;
76
75
  if (resources !== null) {
77
76
  resources[entry.name] = entry.startTime + entry.duration;
78
77
  }
79
- app.send((0, messages_gen_js_1.ResourceTiming)(entry.startTime + ((_a = performance === null || performance === void 0 ? void 0 : performance.timing) === null || _a === void 0 ? void 0 : _a.navigationStart), entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
78
+ app.send((0, messages_gen_js_1.ResourceTiming)(entry.startTime + performance.timing.navigationStart, entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
80
79
  }
81
80
  const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
82
81
  let prevSessionID;
@@ -145,9 +144,9 @@ function default_1(app, opts) {
145
144
  const speedIndex = paintBlocks === null
146
145
  ? 0
147
146
  : calculateSpeedIndex(firstContentfulPaint || firstPaint, paintBlocks);
147
+ const { domContentLoadedEventEnd, navigationStart } = performance.timing;
148
148
  const timeToInteractive = interactiveWindowTickTime === null
149
- ? Math.max(interactiveWindowStartTime, firstContentfulPaint, performance.timing.domContentLoadedEventEnd - performance.timing.navigationStart ||
150
- 0)
149
+ ? Math.max(interactiveWindowStartTime, firstContentfulPaint, domContentLoadedEventEnd - navigationStart || 0)
151
150
  : 0;
152
151
  app.send((0, messages_gen_js_1.PageRenderTiming)(speedIndex, firstContentfulPaint > visuallyComplete ? firstContentfulPaint : visuallyComplete, timeToInteractive));
153
152
  }
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_js_1 = require("../utils.js");
3
4
  const messages_gen_js_1 = require("../app/messages.gen.js");
4
5
  function default_1(app) {
5
6
  let url, width, height;
6
- let navigationStart = performance.timing.navigationStart;
7
+ let navigationStart;
7
8
  const sendSetPageLocation = app.safe(() => {
8
9
  const { URL } = document;
9
10
  if (URL !== url) {
@@ -25,6 +26,7 @@ function default_1(app) {
25
26
  : app.safe(() => app.send((0, messages_gen_js_1.SetPageVisibility)(document.hidden)));
26
27
  app.attachStartCallback(() => {
27
28
  url = '';
29
+ navigationStart = (0, utils_js_1.getTimeOrigin)();
28
30
  width = height = -1;
29
31
  sendSetPageLocation();
30
32
  sendSetViewportSize();
package/cjs/utils.d.ts CHANGED
@@ -2,6 +2,7 @@ export declare const IN_BROWSER: boolean;
2
2
  export declare const IS_FIREFOX: false | RegExpMatchArray | null;
3
3
  export declare const MAX_STR_LEN = 100000;
4
4
  export declare function adjustTimeOrigin(): void;
5
+ export declare function getTimeOrigin(): number;
5
6
  export declare const now: () => number;
6
7
  export declare const stars: (str: string) => string;
7
8
  export declare function normSpaces(str: string): string;
package/cjs/utils.js CHANGED
@@ -1,19 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.isURL = exports.normSpaces = exports.stars = exports.now = exports.adjustTimeOrigin = exports.MAX_STR_LEN = exports.IS_FIREFOX = exports.IN_BROWSER = void 0;
3
+ exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.isURL = exports.normSpaces = exports.stars = exports.now = exports.getTimeOrigin = exports.adjustTimeOrigin = exports.MAX_STR_LEN = exports.IS_FIREFOX = exports.IN_BROWSER = void 0;
4
4
  const DEPRECATED_ATTRS = { htmlmasked: 'hidden', masked: 'obscured' };
5
5
  exports.IN_BROWSER = !(typeof window === 'undefined');
6
6
  exports.IS_FIREFOX = exports.IN_BROWSER && navigator.userAgent.match(/firefox|fxios/i);
7
7
  exports.MAX_STR_LEN = 1e5;
8
8
  // Buggy to use `performance.timeOrigin || performance.timing.navigationStart`
9
9
  // https://github.com/mdn/content/issues/4713
10
- let timeOrigin = exports.IN_BROWSER
11
- ? Date.now() - performance.now()
12
- : 0;
10
+ // Maybe move to timer/ticker
11
+ let timeOrigin = exports.IN_BROWSER ? Date.now() - performance.now() : 0;
13
12
  function adjustTimeOrigin() {
14
13
  timeOrigin = Date.now() - performance.now();
15
14
  }
16
15
  exports.adjustTimeOrigin = adjustTimeOrigin;
16
+ function getTimeOrigin() {
17
+ return timeOrigin;
18
+ }
19
+ exports.getTimeOrigin = getTimeOrigin;
17
20
  exports.now = exports.IN_BROWSER && !!performance.now
18
21
  ? () => Math.round(performance.now() + timeOrigin)
19
22
  : () => Date.now();
@@ -109,8 +109,7 @@ export default class App {
109
109
  active(): boolean;
110
110
  resetNextPageSession(flag: boolean): void;
111
111
  private _start;
112
- start(options?: StartOptions): Promise<StartPromiseReturn>;
112
+ start(...args: Parameters<App['_start']>): Promise<StartPromiseReturn>;
113
113
  stop(stopWorker?: boolean): void;
114
- restart(): void;
115
114
  }
116
115
  export {};
package/lib/app/index.js CHANGED
@@ -30,7 +30,7 @@ export default class App {
30
30
  this.stopCallbacks = [];
31
31
  this.commitCallbacks = [];
32
32
  this.activityState = ActivityState.NotActive;
33
- this.version = '4.1.7'; // TODO: version compatability check inside each plugin.
33
+ this.version = '4.1.8'; // TODO: version compatability check inside each plugin.
34
34
  this.delay = 0;
35
35
  this.projectKey = projectKey;
36
36
  this.options = Object.assign({
@@ -80,7 +80,7 @@ export default class App {
80
80
  this.worker.onmessage = ({ data }) => {
81
81
  if (data === 'restart') {
82
82
  this.stop(false);
83
- this.start({ forceNew: true }); // TODO: keep userID & metadata (draw scenarios)
83
+ this.start({}, true);
84
84
  }
85
85
  else if (data.type === 'failure') {
86
86
  this.stop(false);
@@ -117,7 +117,6 @@ export default class App {
117
117
  }
118
118
  send(message, urgent = false) {
119
119
  if (this.activityState === ActivityState.NotActive) {
120
- // this.debug.log('SendiTrying to send when not active', message) <- crashing the app
121
120
  return;
122
121
  }
123
122
  this.messages.push(message);
@@ -266,8 +265,7 @@ export default class App {
266
265
  this.sessionStorage.removeItem(this.options.session_reset_key);
267
266
  }
268
267
  }
269
- _start(startOpts) {
270
- adjustTimeOrigin();
268
+ _start(startOpts = {}, resetByWorker = false) {
271
269
  if (!this.worker) {
272
270
  return Promise.resolve(UnsuccessfulStart('No worker found: perhaps, CSP is not set.'));
273
271
  }
@@ -275,9 +273,19 @@ export default class App {
275
273
  return Promise.resolve(UnsuccessfulStart('OpenReplay: trying to call `start()` on the instance that has been started already.'));
276
274
  }
277
275
  this.activityState = ActivityState.Starting;
276
+ adjustTimeOrigin();
278
277
  if (startOpts.sessionHash) {
279
278
  this.session.applySessionHash(startOpts.sessionHash);
280
279
  }
280
+ if (startOpts.forceNew) {
281
+ // Reset session metadata only if requested directly
282
+ this.session.reset();
283
+ }
284
+ this.session.assign({
285
+ // MBTODO: maybe it would make sense to `forceNew` if the `userID` was changed
286
+ userID: startOpts.userID,
287
+ metadata: startOpts.metadata,
288
+ });
281
289
  const timestamp = now();
282
290
  this.worker.postMessage({
283
291
  type: 'start',
@@ -288,23 +296,16 @@ export default class App {
288
296
  connAttemptCount: this.options.connAttemptCount,
289
297
  connAttemptGap: this.options.connAttemptGap,
290
298
  });
291
- this.session.update({
292
- // TODO: transparent "session" module logic AND explicit internal api for plugins.
293
- // "updating" with old metadata in order to trigger session's UpdateCallbacks.
294
- // (for the case of internal .start() calls, like on "restart" webworker signal or assistent connection in tracker-assist )
295
- metadata: startOpts.metadata || this.session.getInfo().metadata,
296
- userID: startOpts.userID,
297
- });
298
- const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
299
+ const lsReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
299
300
  this.sessionStorage.removeItem(this.options.session_reset_key);
300
- const shouldReset = startOpts.forceNew || sReset !== null;
301
+ const needNewSessionID = startOpts.forceNew || lsReset || resetByWorker;
301
302
  return window
302
303
  .fetch(this.options.ingestPoint + '/v1/web/start', {
303
304
  method: 'POST',
304
305
  headers: {
305
306
  'Content-Type': 'application/json',
306
307
  },
307
- body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: shouldReset ? undefined : this.session.getSessionToken(), deviceMemory,
308
+ body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: needNewSessionID ? undefined : this.session.getSessionToken(), deviceMemory,
308
309
  jsHeapSizeLimit })),
309
310
  })
310
311
  .then((r) => {
@@ -326,23 +327,27 @@ export default class App {
326
327
  if (this.activityState === ActivityState.NotActive) {
327
328
  return Promise.reject('Tracker stopped during authorisation');
328
329
  }
329
- const { token, userUUID, sessionID, projectID, beaconSizeLimit, startTimestamp, // real startTS, derived from sessionID
330
- delay, } = r;
330
+ const { token, userUUID, projectID, beaconSizeLimit, delay, // derived from token
331
+ sessionID, // derived from token
332
+ startTimestamp, // real startTS (server time), derived from sessionID
333
+ } = r;
331
334
  if (typeof token !== 'string' ||
332
335
  typeof userUUID !== 'string' ||
333
- //typeof startTimestamp !== 'number' ||
334
- //typeof sessionID !== 'string' ||
336
+ (typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined') ||
337
+ typeof sessionID !== 'string' ||
335
338
  typeof delay !== 'number' ||
336
339
  (typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
337
340
  return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
338
341
  }
339
342
  this.delay = delay;
340
- const prevSessionID = this.session.getInfo().sessionID;
341
- if (prevSessionID && prevSessionID !== sessionID) {
342
- this.session.reset();
343
- }
344
343
  this.session.setSessionToken(token);
345
- this.session.update({ sessionID, timestamp: startTimestamp || timestamp, projectID }); // TODO: no no-explicit 'any'
344
+ this.session.assign({
345
+ sessionID,
346
+ timestamp: startTimestamp || timestamp,
347
+ projectID,
348
+ });
349
+ // (Re)send Metadata for the case of a new session
350
+ Object.entries(this.session.getInfo().metadata).forEach(([key, value]) => this.send(Metadata(key, value)));
346
351
  this.localStorage.setItem(this.options.local_uuid_key, userUUID);
347
352
  this.worker.postMessage({
348
353
  type: 'auth',
@@ -373,16 +378,16 @@ export default class App {
373
378
  return UnsuccessfulStart(START_ERROR);
374
379
  });
375
380
  }
376
- start(options = {}) {
381
+ start(...args) {
377
382
  if (!document.hidden) {
378
- return this._start(options);
383
+ return this._start(...args);
379
384
  }
380
385
  else {
381
386
  return new Promise((resolve) => {
382
387
  const onVisibilityChange = () => {
383
388
  if (!document.hidden) {
384
389
  document.removeEventListener('visibilitychange', onVisibilityChange);
385
- resolve(this._start(options));
390
+ resolve(this._start(...args));
386
391
  }
387
392
  };
388
393
  document.addEventListener('visibilitychange', onVisibilityChange);
@@ -407,8 +412,4 @@ export default class App {
407
412
  }
408
413
  }
409
414
  }
410
- restart() {
411
- this.stop(false);
412
- this.start({ forceNew: false });
413
- }
414
415
  }
@@ -23,7 +23,7 @@ export default class Session {
23
23
  constructor(app: App, options: Options);
24
24
  attachUpdateCallback(cb: OnUpdateCallback): void;
25
25
  private handleUpdate;
26
- update(newInfo: Partial<SessionInfo>): void;
26
+ assign(newInfo: Partial<SessionInfo>): void;
27
27
  setMetadata(key: string, value: string): void;
28
28
  setUserID(userID: string): void;
29
29
  private getPageNumber;
@@ -19,7 +19,7 @@ export default class Session {
19
19
  }
20
20
  this.callbacks.forEach((cb) => cb(newInfo));
21
21
  }
22
- update(newInfo) {
22
+ assign(newInfo) {
23
23
  if (newInfo.userID !== undefined) {
24
24
  // TODO clear nullable/undefinable types
25
25
  this.userID = newInfo.userID;
package/lib/index.js CHANGED
@@ -133,7 +133,7 @@ export default class API {
133
133
  // no-cors issue only with text/plain or not-set Content-Type
134
134
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
135
135
  req.send(JSON.stringify({
136
- trackerVersion: '4.1.7',
136
+ trackerVersion: '4.1.8',
137
137
  projectKey: options.projectKey,
138
138
  doNotTrack,
139
139
  // TODO: add precise reason (an exact API missing)
@@ -68,13 +68,12 @@ export default function (app, opts) {
68
68
  } // Resources are necessary for all timings
69
69
  let resources = {};
70
70
  function resourceTiming(entry) {
71
- var _a;
72
71
  if (entry.duration < 0 || !isURL(entry.name) || app.isServiceURL(entry.name))
73
72
  return;
74
73
  if (resources !== null) {
75
74
  resources[entry.name] = entry.startTime + entry.duration;
76
75
  }
77
- app.send(ResourceTiming(entry.startTime + ((_a = performance === null || performance === void 0 ? void 0 : performance.timing) === null || _a === void 0 ? void 0 : _a.navigationStart), entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
76
+ app.send(ResourceTiming(entry.startTime + performance.timing.navigationStart, entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
78
77
  }
79
78
  const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
80
79
  let prevSessionID;
@@ -143,9 +142,9 @@ export default function (app, opts) {
143
142
  const speedIndex = paintBlocks === null
144
143
  ? 0
145
144
  : calculateSpeedIndex(firstContentfulPaint || firstPaint, paintBlocks);
145
+ const { domContentLoadedEventEnd, navigationStart } = performance.timing;
146
146
  const timeToInteractive = interactiveWindowTickTime === null
147
- ? Math.max(interactiveWindowStartTime, firstContentfulPaint, performance.timing.domContentLoadedEventEnd - performance.timing.navigationStart ||
148
- 0)
147
+ ? Math.max(interactiveWindowStartTime, firstContentfulPaint, domContentLoadedEventEnd - navigationStart || 0)
149
148
  : 0;
150
149
  app.send(PageRenderTiming(speedIndex, firstContentfulPaint > visuallyComplete ? firstContentfulPaint : visuallyComplete, timeToInteractive));
151
150
  }
@@ -1,7 +1,8 @@
1
+ import { getTimeOrigin } from '../utils.js';
1
2
  import { SetPageLocation, SetViewportSize, SetPageVisibility } from '../app/messages.gen.js';
2
3
  export default function (app) {
3
4
  let url, width, height;
4
- let navigationStart = performance.timing.navigationStart;
5
+ let navigationStart;
5
6
  const sendSetPageLocation = app.safe(() => {
6
7
  const { URL } = document;
7
8
  if (URL !== url) {
@@ -23,6 +24,7 @@ export default function (app) {
23
24
  : app.safe(() => app.send(SetPageVisibility(document.hidden)));
24
25
  app.attachStartCallback(() => {
25
26
  url = '';
27
+ navigationStart = getTimeOrigin();
26
28
  width = height = -1;
27
29
  sendSetPageLocation();
28
30
  sendSetViewportSize();
package/lib/utils.d.ts CHANGED
@@ -2,6 +2,7 @@ export declare const IN_BROWSER: boolean;
2
2
  export declare const IS_FIREFOX: false | RegExpMatchArray | null;
3
3
  export declare const MAX_STR_LEN = 100000;
4
4
  export declare function adjustTimeOrigin(): void;
5
+ export declare function getTimeOrigin(): number;
5
6
  export declare const now: () => number;
6
7
  export declare const stars: (str: string) => string;
7
8
  export declare function normSpaces(str: string): string;
package/lib/utils.js CHANGED
@@ -4,12 +4,14 @@ export const IS_FIREFOX = IN_BROWSER && navigator.userAgent.match(/firefox|fxios
4
4
  export const MAX_STR_LEN = 1e5;
5
5
  // Buggy to use `performance.timeOrigin || performance.timing.navigationStart`
6
6
  // https://github.com/mdn/content/issues/4713
7
- let timeOrigin = IN_BROWSER
8
- ? Date.now() - performance.now()
9
- : 0;
7
+ // Maybe move to timer/ticker
8
+ let timeOrigin = IN_BROWSER ? Date.now() - performance.now() : 0;
10
9
  export function adjustTimeOrigin() {
11
10
  timeOrigin = Date.now() - performance.now();
12
11
  }
12
+ export function getTimeOrigin() {
13
+ return timeOrigin;
14
+ }
13
15
  export const now = IN_BROWSER && !!performance.now
14
16
  ? () => Math.round(performance.now() + timeOrigin)
15
17
  : () => Date.now();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "4.1.8",
4
+ "version": "4.1.9",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"