@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.
- package/cjs/app/index.d.ts +1 -2
- package/cjs/app/index.js +32 -31
- package/cjs/app/session.d.ts +1 -1
- package/cjs/app/session.js +1 -1
- package/cjs/index.js +1 -1
- package/cjs/modules/timing.js +3 -4
- package/cjs/modules/viewport.js +3 -1
- package/cjs/utils.d.ts +1 -0
- package/cjs/utils.js +7 -4
- package/lib/app/index.d.ts +1 -2
- package/lib/app/index.js +32 -31
- package/lib/app/session.d.ts +1 -1
- package/lib/app/session.js +1 -1
- package/lib/index.js +1 -1
- package/lib/modules/timing.js +3 -4
- package/lib/modules/viewport.js +3 -1
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +5 -3
- package/package.json +1 -1
package/cjs/app/index.d.ts
CHANGED
|
@@ -109,8 +109,7 @@ export default class App {
|
|
|
109
109
|
active(): boolean;
|
|
110
110
|
resetNextPageSession(flag: boolean): void;
|
|
111
111
|
private _start;
|
|
112
|
-
start(
|
|
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.
|
|
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({
|
|
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.
|
|
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
|
|
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:
|
|
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,
|
|
333
|
-
|
|
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
|
-
|
|
337
|
-
|
|
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.
|
|
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(
|
|
384
|
+
start(...args) {
|
|
380
385
|
if (!document.hidden) {
|
|
381
|
-
return this._start(
|
|
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(
|
|
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;
|
package/cjs/app/session.d.ts
CHANGED
|
@@ -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
|
-
|
|
26
|
+
assign(newInfo: Partial<SessionInfo>): void;
|
|
27
27
|
setMetadata(key: string, value: string): void;
|
|
28
28
|
setUserID(userID: string): void;
|
|
29
29
|
private getPageNumber;
|
package/cjs/app/session.js
CHANGED
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.
|
|
141
|
+
trackerVersion: '4.1.8',
|
|
142
142
|
projectKey: options.projectKey,
|
|
143
143
|
doNotTrack,
|
|
144
144
|
// TODO: add precise reason (an exact API missing)
|
package/cjs/modules/timing.js
CHANGED
|
@@ -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 +
|
|
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,
|
|
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
|
}
|
package/cjs/modules/viewport.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
11
|
-
|
|
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();
|
package/lib/app/index.d.ts
CHANGED
|
@@ -109,8 +109,7 @@ export default class App {
|
|
|
109
109
|
active(): boolean;
|
|
110
110
|
resetNextPageSession(flag: boolean): void;
|
|
111
111
|
private _start;
|
|
112
|
-
start(
|
|
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.
|
|
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({
|
|
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.
|
|
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
|
|
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:
|
|
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,
|
|
330
|
-
|
|
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
|
-
|
|
334
|
-
|
|
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.
|
|
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(
|
|
381
|
+
start(...args) {
|
|
377
382
|
if (!document.hidden) {
|
|
378
|
-
return this._start(
|
|
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(
|
|
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
|
}
|
package/lib/app/session.d.ts
CHANGED
|
@@ -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
|
-
|
|
26
|
+
assign(newInfo: Partial<SessionInfo>): void;
|
|
27
27
|
setMetadata(key: string, value: string): void;
|
|
28
28
|
setUserID(userID: string): void;
|
|
29
29
|
private getPageNumber;
|
package/lib/app/session.js
CHANGED
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.
|
|
136
|
+
trackerVersion: '4.1.8',
|
|
137
137
|
projectKey: options.projectKey,
|
|
138
138
|
doNotTrack,
|
|
139
139
|
// TODO: add precise reason (an exact API missing)
|
package/lib/modules/timing.js
CHANGED
|
@@ -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 +
|
|
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,
|
|
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
|
}
|
package/lib/modules/viewport.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
8
|
-
|
|
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();
|