@openreplay/tracker 11.0.6 → 12.0.0-beta.99
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/CHANGELOG.md +4 -2
- package/cjs/app/index.d.ts +88 -9
- package/cjs/app/index.js +492 -125
- package/cjs/app/logger.d.ts +7 -17
- package/cjs/app/logger.js +11 -19
- package/cjs/app/messages.gen.d.ts +2 -0
- package/cjs/app/messages.gen.js +20 -1
- package/cjs/app/observer/iframe_observer.js +4 -1
- package/cjs/app/observer/shadow_root_observer.js +4 -1
- package/cjs/app/observer/top_observer.js +7 -4
- package/cjs/app/workerManager/QueueSender.d.ts +23 -0
- package/cjs/app/workerManager/QueueSender.js +126 -0
- package/cjs/app/workerManager/index.d.ts +37 -0
- package/cjs/app/workerManager/index.js +167 -0
- package/cjs/common/interaction.d.ts +56 -18
- package/cjs/common/messages.gen.d.ts +17 -2
- package/cjs/index.d.ts +45 -2
- package/cjs/index.js +237 -106
- package/cjs/modules/Network/beaconProxy.js +4 -1
- package/cjs/modules/Network/fetchProxy.js +24 -1
- package/cjs/modules/Network/index.js +6 -3
- package/cjs/modules/Network/xhrProxy.js +24 -1
- package/cjs/modules/conditionsManager.d.ts +84 -0
- package/cjs/modules/conditionsManager.js +343 -0
- package/cjs/modules/exception.js +4 -1
- package/cjs/modules/featureFlags.d.ts +1 -1
- package/cjs/modules/featureFlags.js +36 -46
- package/cjs/modules/network.js +5 -2
- package/cjs/modules/tagWatcher.d.ts +21 -0
- package/cjs/modules/tagWatcher.js +77 -0
- package/cjs/modules/userTesting/index.js +30 -4
- package/cjs/modules/userTesting/recorder.js +71 -88
- package/coverage/clover.xml +577 -544
- package/coverage/coverage-final.json +8 -8
- package/coverage/lcov-report/index.html +28 -28
- package/coverage/lcov-report/main/app/canvas.ts.html +97 -46
- package/coverage/lcov-report/main/app/guards.ts.html +1 -1
- package/coverage/lcov-report/main/app/index.html +19 -19
- package/coverage/lcov-report/main/app/index.ts.html +62 -35
- package/coverage/lcov-report/main/app/logger.ts.html +1 -1
- package/coverage/lcov-report/main/app/messages.gen.ts.html +32 -5
- package/coverage/lcov-report/main/app/nodes.ts.html +17 -5
- package/coverage/lcov-report/main/app/observer/iframe_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/iframe_offsets.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/index.html +1 -1
- package/coverage/lcov-report/main/app/observer/shadow_root_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/top_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/sanitizer.ts.html +1 -1
- package/coverage/lcov-report/main/app/session.ts.html +1 -1
- package/coverage/lcov-report/main/app/ticker.ts.html +1 -1
- package/coverage/lcov-report/main/index.html +9 -9
- package/coverage/lcov-report/main/index.ts.html +27 -6
- package/coverage/lcov-report/main/modules/Network/beaconProxy.ts.html +1 -1
- package/coverage/lcov-report/main/modules/Network/fetchProxy.ts.html +1 -1
- package/coverage/lcov-report/main/modules/Network/index.html +1 -1
- package/coverage/lcov-report/main/modules/Network/index.ts.html +1 -1
- package/coverage/lcov-report/main/modules/Network/networkMessage.ts.html +1 -1
- package/coverage/lcov-report/main/modules/Network/utils.ts.html +1 -1
- package/coverage/lcov-report/main/modules/Network/xhrProxy.ts.html +1 -1
- package/coverage/lcov-report/main/modules/attributeSender.ts.html +1 -1
- package/coverage/lcov-report/main/modules/axiosSpy.ts.html +1 -1
- package/coverage/lcov-report/main/modules/conditionsManager.ts.html +92 -38
- package/coverage/lcov-report/main/modules/connection.ts.html +1 -1
- package/coverage/lcov-report/main/modules/console.ts.html +1 -1
- package/coverage/lcov-report/main/modules/constructedStyleSheets.ts.html +1 -1
- package/coverage/lcov-report/main/modules/cssrules.ts.html +1 -1
- package/coverage/lcov-report/main/modules/exception.ts.html +1 -1
- package/coverage/lcov-report/main/modules/featureFlags.ts.html +1 -1
- package/coverage/lcov-report/main/modules/focus.ts.html +1 -1
- package/coverage/lcov-report/main/modules/fonts.ts.html +1 -1
- package/coverage/lcov-report/main/modules/img.ts.html +1 -1
- package/coverage/lcov-report/main/modules/index.html +21 -21
- package/coverage/lcov-report/main/modules/input.ts.html +1 -1
- package/coverage/lcov-report/main/modules/mouse.ts.html +1 -1
- package/coverage/lcov-report/main/modules/network.ts.html +1 -1
- package/coverage/lcov-report/main/modules/performance.ts.html +1 -1
- package/coverage/lcov-report/main/modules/scroll.ts.html +1 -1
- package/coverage/lcov-report/main/modules/selection.ts.html +1 -1
- package/coverage/lcov-report/main/modules/tabs.ts.html +1 -1
- package/coverage/lcov-report/main/modules/tagWatcher.ts.html +54 -27
- package/coverage/lcov-report/main/modules/timing.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/SignalManager.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/dnd.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/index.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/index.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/recorder.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/styles.ts.html +1 -1
- package/coverage/lcov-report/main/modules/userTesting/utils.ts.html +1 -1
- package/coverage/lcov-report/main/modules/viewport.ts.html +1 -1
- package/coverage/lcov-report/main/utils.ts.html +1 -1
- package/coverage/lcov-report/webworker/BatchWriter.ts.html +1 -1
- package/coverage/lcov-report/webworker/MessageEncoder.gen.ts.html +17 -5
- package/coverage/lcov-report/webworker/PrimitiveEncoder.ts.html +1 -1
- package/coverage/lcov-report/webworker/QueueSender.ts.html +1 -1
- package/coverage/lcov-report/webworker/index.html +7 -7
- package/coverage/lcov-report/webworker/index.ts.html +1 -1
- package/coverage/lcov.info +1100 -1033
- package/lib/app/index.d.ts +88 -9
- package/lib/app/index.js +452 -111
- package/lib/app/logger.d.ts +7 -17
- package/lib/app/logger.js +11 -19
- package/lib/app/messages.gen.d.ts +2 -0
- package/lib/app/messages.gen.js +17 -0
- package/lib/app/workerManager/QueueSender.d.ts +23 -0
- package/lib/app/workerManager/QueueSender.js +123 -0
- package/lib/app/workerManager/index.d.ts +37 -0
- package/lib/app/workerManager/index.js +162 -0
- package/lib/common/interaction.d.ts +56 -18
- package/lib/common/messages.gen.d.ts +17 -2
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +45 -2
- package/lib/index.js +191 -86
- package/lib/modules/conditionsManager.d.ts +84 -0
- package/lib/modules/conditionsManager.js +340 -0
- package/lib/modules/featureFlags.d.ts +1 -1
- package/lib/modules/featureFlags.js +36 -46
- package/lib/modules/tagWatcher.d.ts +21 -0
- package/lib/modules/tagWatcher.js +74 -0
- package/lib/modules/userTesting/recorder.js +71 -88
- package/package.json +1 -1
- package/tsconfig-base.json +3 -2
package/lib/app/logger.d.ts
CHANGED
|
@@ -5,22 +5,12 @@ export declare const LogLevel: {
|
|
|
5
5
|
readonly Errors: 2;
|
|
6
6
|
readonly Silent: 0;
|
|
7
7
|
};
|
|
8
|
-
type
|
|
9
|
-
type CustomLevel = {
|
|
10
|
-
error: boolean;
|
|
11
|
-
warn: boolean;
|
|
12
|
-
log: boolean;
|
|
13
|
-
};
|
|
14
|
-
interface _Options {
|
|
15
|
-
level: LogLevel | CustomLevel;
|
|
16
|
-
messages?: number[];
|
|
17
|
-
}
|
|
18
|
-
export type Options = true | _Options | LogLevel;
|
|
8
|
+
export type ILogLevel = (typeof LogLevel)[keyof typeof LogLevel];
|
|
19
9
|
export default class Logger {
|
|
20
|
-
private readonly
|
|
21
|
-
constructor(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
private readonly level;
|
|
11
|
+
constructor(debugLevel?: ILogLevel);
|
|
12
|
+
private shouldLog;
|
|
13
|
+
log(...args: any[]): void;
|
|
14
|
+
warn(...args: any[]): void;
|
|
15
|
+
error(...args: any[]): void;
|
|
25
16
|
}
|
|
26
|
-
export {};
|
package/lib/app/logger.js
CHANGED
|
@@ -5,36 +5,28 @@ export const LogLevel = {
|
|
|
5
5
|
Errors: 2,
|
|
6
6
|
Silent: 0,
|
|
7
7
|
};
|
|
8
|
-
function IsCustomLevel(l) {
|
|
9
|
-
return typeof l === 'object';
|
|
10
|
-
}
|
|
11
8
|
export default class Logger {
|
|
12
|
-
constructor(
|
|
13
|
-
this.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
? { level: options }
|
|
18
|
-
: options;
|
|
9
|
+
constructor(debugLevel = LogLevel.Silent) {
|
|
10
|
+
this.level = debugLevel;
|
|
11
|
+
}
|
|
12
|
+
shouldLog(level) {
|
|
13
|
+
return this.level >= level;
|
|
19
14
|
}
|
|
20
15
|
log(...args) {
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
: this.options.level >= LogLevel.Log) {
|
|
16
|
+
if (this.shouldLog(LogLevel.Log)) {
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
24
18
|
console.log(...args);
|
|
25
19
|
}
|
|
26
20
|
}
|
|
27
21
|
warn(...args) {
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
: this.options.level >= LogLevel.Warnings) {
|
|
22
|
+
if (this.shouldLog(LogLevel.Warnings)) {
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
31
24
|
console.warn(...args);
|
|
32
25
|
}
|
|
33
26
|
}
|
|
34
27
|
error(...args) {
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
: this.options.level >= LogLevel.Errors) {
|
|
28
|
+
if (this.shouldLog(LogLevel.Errors)) {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
38
30
|
console.error(...args);
|
|
39
31
|
}
|
|
40
32
|
}
|
|
@@ -62,6 +62,7 @@ export declare function Zustand(mutation: string, state: string): Messages.Zusta
|
|
|
62
62
|
export declare function BatchMetadata(version: number, pageNo: number, firstIndex: number, timestamp: number, location: string): Messages.BatchMetadata;
|
|
63
63
|
export declare function PartitionedMessage(partNo: number, partTotal: number): Messages.PartitionedMessage;
|
|
64
64
|
export declare function NetworkRequest(type: string, method: string, url: string, request: string, response: string, status: number, timestamp: number, duration: number, transferredBodySize: number): Messages.NetworkRequest;
|
|
65
|
+
export declare function WSChannel(chType: string, channelName: string, data: string, timestamp: number, dir: string, messageType: string): Messages.WSChannel;
|
|
65
66
|
export declare function InputChange(id: number, value: string, valueMasked: boolean, label: string, hesitationTime: number, inputDuration: number): Messages.InputChange;
|
|
66
67
|
export declare function SelectionChange(selectionStart: number, selectionEnd: number, selection: string): Messages.SelectionChange;
|
|
67
68
|
export declare function MouseThrashing(timestamp: number): Messages.MouseThrashing;
|
|
@@ -70,3 +71,4 @@ export declare function ResourceTiming(timestamp: number, duration: number, ttfb
|
|
|
70
71
|
export declare function TabChange(tabId: string): Messages.TabChange;
|
|
71
72
|
export declare function TabData(tabId: string): Messages.TabData;
|
|
72
73
|
export declare function CanvasNode(nodeId: string, timestamp: number): Messages.CanvasNode;
|
|
74
|
+
export declare function TagTrigger(tagId: number): Messages.TagTrigger;
|
package/lib/app/messages.gen.js
CHANGED
|
@@ -498,6 +498,17 @@ export function NetworkRequest(type, method, url, request, response, status, tim
|
|
|
498
498
|
transferredBodySize,
|
|
499
499
|
];
|
|
500
500
|
}
|
|
501
|
+
export function WSChannel(chType, channelName, data, timestamp, dir, messageType) {
|
|
502
|
+
return [
|
|
503
|
+
84 /* Messages.Type.WSChannel */,
|
|
504
|
+
chType,
|
|
505
|
+
channelName,
|
|
506
|
+
data,
|
|
507
|
+
timestamp,
|
|
508
|
+
dir,
|
|
509
|
+
messageType,
|
|
510
|
+
];
|
|
511
|
+
}
|
|
501
512
|
export function InputChange(id, value, valueMasked, label, hesitationTime, inputDuration) {
|
|
502
513
|
return [
|
|
503
514
|
112 /* Messages.Type.InputChange */,
|
|
@@ -563,3 +574,9 @@ export function CanvasNode(nodeId, timestamp) {
|
|
|
563
574
|
timestamp,
|
|
564
575
|
];
|
|
565
576
|
}
|
|
577
|
+
export function TagTrigger(tagId) {
|
|
578
|
+
return [
|
|
579
|
+
120 /* Messages.Type.TagTrigger */,
|
|
580
|
+
tagId,
|
|
581
|
+
];
|
|
582
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default class QueueSender {
|
|
2
|
+
private readonly onUnauthorised;
|
|
3
|
+
private readonly onFailure;
|
|
4
|
+
private readonly MAX_ATTEMPTS_COUNT;
|
|
5
|
+
private readonly ATTEMPT_TIMEOUT;
|
|
6
|
+
private readonly onCompress?;
|
|
7
|
+
private attemptsCount;
|
|
8
|
+
private busy;
|
|
9
|
+
private readonly queue;
|
|
10
|
+
private readonly ingestURL;
|
|
11
|
+
private token;
|
|
12
|
+
private readonly isCompressing;
|
|
13
|
+
constructor(ingestBaseURL: string, onUnauthorised: () => any, onFailure: (reason: string) => any, MAX_ATTEMPTS_COUNT?: number, ATTEMPT_TIMEOUT?: number, onCompress?: ((batch: Uint8Array) => any) | undefined);
|
|
14
|
+
getQueueStatus(): boolean;
|
|
15
|
+
authorise(token: string): void;
|
|
16
|
+
push(batch: Uint8Array): void;
|
|
17
|
+
private sendNext;
|
|
18
|
+
private retry;
|
|
19
|
+
private sendBatch;
|
|
20
|
+
sendCompressed(batch: Uint8Array): void;
|
|
21
|
+
sendUncompressed(batch: Uint8Array): void;
|
|
22
|
+
clean(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const INGEST_PATH = '/v1/web/i';
|
|
2
|
+
const KEEPALIVE_SIZE_LIMIT = 64 << 10; // 64 kB
|
|
3
|
+
export default class QueueSender {
|
|
4
|
+
constructor(ingestBaseURL, onUnauthorised, onFailure, MAX_ATTEMPTS_COUNT = 10, ATTEMPT_TIMEOUT = 1000, onCompress) {
|
|
5
|
+
this.onUnauthorised = onUnauthorised;
|
|
6
|
+
this.onFailure = onFailure;
|
|
7
|
+
this.MAX_ATTEMPTS_COUNT = MAX_ATTEMPTS_COUNT;
|
|
8
|
+
this.ATTEMPT_TIMEOUT = ATTEMPT_TIMEOUT;
|
|
9
|
+
this.onCompress = onCompress;
|
|
10
|
+
this.attemptsCount = 0;
|
|
11
|
+
this.busy = false;
|
|
12
|
+
this.queue = [];
|
|
13
|
+
this.token = null;
|
|
14
|
+
this.ingestURL = ingestBaseURL + INGEST_PATH;
|
|
15
|
+
this.isCompressing = onCompress !== undefined;
|
|
16
|
+
}
|
|
17
|
+
getQueueStatus() {
|
|
18
|
+
return this.queue.length === 0 && !this.busy;
|
|
19
|
+
}
|
|
20
|
+
authorise(token) {
|
|
21
|
+
this.token = token;
|
|
22
|
+
if (!this.busy) {
|
|
23
|
+
// TODO: transparent busy/send logic
|
|
24
|
+
this.sendNext();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
push(batch) {
|
|
28
|
+
if (this.busy || !this.token) {
|
|
29
|
+
this.queue.push(batch);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.busy = true;
|
|
33
|
+
if (this.isCompressing && this.onCompress) {
|
|
34
|
+
this.onCompress(batch);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.sendBatch(batch);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
sendNext() {
|
|
42
|
+
const nextBatch = this.queue.shift();
|
|
43
|
+
if (nextBatch) {
|
|
44
|
+
this.busy = true;
|
|
45
|
+
if (this.isCompressing && this.onCompress) {
|
|
46
|
+
this.onCompress(nextBatch);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.sendBatch(nextBatch);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.busy = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
retry(batch, isCompressed) {
|
|
57
|
+
if (this.attemptsCount >= this.MAX_ATTEMPTS_COUNT) {
|
|
58
|
+
this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`);
|
|
59
|
+
// remains this.busy === true
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.attemptsCount++;
|
|
63
|
+
setTimeout(() => this.sendBatch(batch, isCompressed), this.ATTEMPT_TIMEOUT * this.attemptsCount);
|
|
64
|
+
}
|
|
65
|
+
// would be nice to use Beacon API, but it is not available in WebWorker
|
|
66
|
+
sendBatch(batch, isCompressed) {
|
|
67
|
+
this.busy = true;
|
|
68
|
+
const headers = {
|
|
69
|
+
Authorization: `Bearer ${this.token}`,
|
|
70
|
+
};
|
|
71
|
+
if (isCompressed) {
|
|
72
|
+
headers['Content-Encoding'] = 'gzip';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* sometimes happen during assist connects for some reason
|
|
76
|
+
* */
|
|
77
|
+
if (this.token === null) {
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
this.sendBatch(batch, isCompressed);
|
|
80
|
+
}, 500);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
fetch(this.ingestURL, {
|
|
84
|
+
body: batch,
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers,
|
|
87
|
+
keepalive: batch.length < KEEPALIVE_SIZE_LIMIT,
|
|
88
|
+
})
|
|
89
|
+
.then((r) => {
|
|
90
|
+
if (r.status === 401) {
|
|
91
|
+
// TODO: continuous session ?
|
|
92
|
+
this.busy = false;
|
|
93
|
+
this.onUnauthorised();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
else if (r.status >= 400) {
|
|
97
|
+
this.retry(batch, isCompressed);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Success
|
|
101
|
+
this.attemptsCount = 0;
|
|
102
|
+
this.sendNext();
|
|
103
|
+
})
|
|
104
|
+
.catch((e) => {
|
|
105
|
+
console.warn('OpenReplay:', e);
|
|
106
|
+
this.retry(batch, isCompressed);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
sendCompressed(batch) {
|
|
110
|
+
this.sendBatch(batch, true);
|
|
111
|
+
}
|
|
112
|
+
sendUncompressed(batch) {
|
|
113
|
+
this.sendBatch(batch, false);
|
|
114
|
+
}
|
|
115
|
+
clean() {
|
|
116
|
+
// sending last batch and closing the shop
|
|
117
|
+
this.sendNext();
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
this.token = null;
|
|
120
|
+
this.queue.length = 0;
|
|
121
|
+
}, 10);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FromWorkerData, ToWorkerData, WorkerAuth, WorkerStart } from '../../common/interaction.js';
|
|
2
|
+
import App from '../index.js';
|
|
3
|
+
import QueueSender from './QueueSender.js';
|
|
4
|
+
declare enum WorkerStatus {
|
|
5
|
+
NotActive = 0,
|
|
6
|
+
Starting = 1,
|
|
7
|
+
Stopping = 2,
|
|
8
|
+
Active = 3,
|
|
9
|
+
Stopped = 4
|
|
10
|
+
}
|
|
11
|
+
interface TypedWorker extends Omit<Worker, 'postMessage'> {
|
|
12
|
+
postMessage(data: ToWorkerData): void;
|
|
13
|
+
}
|
|
14
|
+
declare class WebWorkerManager {
|
|
15
|
+
private readonly app;
|
|
16
|
+
private readonly worker;
|
|
17
|
+
private readonly onError;
|
|
18
|
+
sendIntervalID: ReturnType<typeof setInterval> | null;
|
|
19
|
+
restartTimeoutID: ReturnType<typeof setTimeout> | null;
|
|
20
|
+
workerStatus: WorkerStatus;
|
|
21
|
+
sender: QueueSender | null;
|
|
22
|
+
constructor(app: App, worker: TypedWorker, onError: (ctx: string, e: any) => any);
|
|
23
|
+
finalize: () => void;
|
|
24
|
+
resetWebWorker: () => void;
|
|
25
|
+
resetSender: () => void;
|
|
26
|
+
reset: () => void;
|
|
27
|
+
initiateRestart: () => void;
|
|
28
|
+
initiateFailure: (reason: string) => void;
|
|
29
|
+
processMessage: (data: ToWorkerData | null) => void;
|
|
30
|
+
startWorker: (data: WorkerStart) => void;
|
|
31
|
+
stopWorker: () => void;
|
|
32
|
+
authorizeWorker: (data: WorkerAuth) => void;
|
|
33
|
+
sendCompressedBatch: (data: Uint8Array) => void;
|
|
34
|
+
sendUncompressedBatch: (data: Uint8Array) => void;
|
|
35
|
+
postMessage: (data: FromWorkerData) => void;
|
|
36
|
+
}
|
|
37
|
+
export default WebWorkerManager;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import QueueSender from './QueueSender.js';
|
|
2
|
+
var WorkerStatus;
|
|
3
|
+
(function (WorkerStatus) {
|
|
4
|
+
WorkerStatus[WorkerStatus["NotActive"] = 0] = "NotActive";
|
|
5
|
+
WorkerStatus[WorkerStatus["Starting"] = 1] = "Starting";
|
|
6
|
+
WorkerStatus[WorkerStatus["Stopping"] = 2] = "Stopping";
|
|
7
|
+
WorkerStatus[WorkerStatus["Active"] = 3] = "Active";
|
|
8
|
+
WorkerStatus[WorkerStatus["Stopped"] = 4] = "Stopped";
|
|
9
|
+
})(WorkerStatus || (WorkerStatus = {}));
|
|
10
|
+
const AUTO_SEND_INTERVAL = 10 * 1000;
|
|
11
|
+
const rebroadcastEvents = ['queue_empty', 'not_init', 'restart'];
|
|
12
|
+
class WebWorkerManager {
|
|
13
|
+
constructor(app, worker, onError) {
|
|
14
|
+
this.app = app;
|
|
15
|
+
this.worker = worker;
|
|
16
|
+
this.onError = onError;
|
|
17
|
+
this.sendIntervalID = null;
|
|
18
|
+
this.restartTimeoutID = null;
|
|
19
|
+
this.workerStatus = WorkerStatus.NotActive;
|
|
20
|
+
this.sender = null;
|
|
21
|
+
this.finalize = () => {
|
|
22
|
+
this.worker.postMessage({ type: 'writer_finalize' });
|
|
23
|
+
};
|
|
24
|
+
this.resetWebWorker = () => {
|
|
25
|
+
this.worker.postMessage({ type: 'reset_writer' });
|
|
26
|
+
};
|
|
27
|
+
this.resetSender = () => {
|
|
28
|
+
if (!this.sender) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.sender.clean();
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
this.sender = null;
|
|
34
|
+
}, 20);
|
|
35
|
+
};
|
|
36
|
+
this.reset = () => {
|
|
37
|
+
this.workerStatus = WorkerStatus.Stopping;
|
|
38
|
+
if (this.sendIntervalID !== null) {
|
|
39
|
+
clearInterval(this.sendIntervalID);
|
|
40
|
+
this.sendIntervalID = null;
|
|
41
|
+
}
|
|
42
|
+
this.resetSender();
|
|
43
|
+
this.resetWebWorker();
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
this.workerStatus = WorkerStatus.NotActive;
|
|
46
|
+
}, 100);
|
|
47
|
+
};
|
|
48
|
+
this.initiateRestart = () => {
|
|
49
|
+
if (this.workerStatus === WorkerStatus.Stopped) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.postMessage({ type: 'restart' });
|
|
53
|
+
this.reset();
|
|
54
|
+
};
|
|
55
|
+
this.initiateFailure = (reason) => {
|
|
56
|
+
if ([WorkerStatus.Stopped, WorkerStatus.Stopping, WorkerStatus.NotActive].includes(this.workerStatus)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.postMessage({ type: 'failure', reason });
|
|
60
|
+
this.reset();
|
|
61
|
+
};
|
|
62
|
+
this.processMessage = (data) => {
|
|
63
|
+
if (data === null) {
|
|
64
|
+
this.finalize();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (data.type === 'batch' && Array.isArray(data.data)) {
|
|
68
|
+
data.data.forEach((message) => {
|
|
69
|
+
if (message[0] === 55 /* MType.SetPageVisibility */) {
|
|
70
|
+
// document is hidden
|
|
71
|
+
if (message[1]) {
|
|
72
|
+
this.restartTimeoutID = setTimeout(() => this.initiateRestart(), 30 * 60 * 1000);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (this.restartTimeoutID) {
|
|
76
|
+
clearTimeout(this.restartTimeoutID);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
this.worker.postMessage({ type: 'to_writer', data: data.data });
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
this.startWorker = (data) => {
|
|
85
|
+
this.sender = new QueueSender(data.ingestPoint, () => {
|
|
86
|
+
// onUnauthorised
|
|
87
|
+
this.initiateRestart();
|
|
88
|
+
}, (reason) => {
|
|
89
|
+
// onFailure
|
|
90
|
+
this.initiateFailure(reason);
|
|
91
|
+
}, data.connAttemptCount, data.connAttemptGap, (batch) => {
|
|
92
|
+
this.postMessage({ type: 'compress', batch });
|
|
93
|
+
});
|
|
94
|
+
if (this.sendIntervalID === null) {
|
|
95
|
+
this.sendIntervalID = setInterval(this.finalize, AUTO_SEND_INTERVAL);
|
|
96
|
+
}
|
|
97
|
+
this.worker.postMessage(data);
|
|
98
|
+
return;
|
|
99
|
+
};
|
|
100
|
+
this.stopWorker = () => {
|
|
101
|
+
this.finalize();
|
|
102
|
+
this.reset();
|
|
103
|
+
return;
|
|
104
|
+
};
|
|
105
|
+
this.authorizeWorker = (data) => {
|
|
106
|
+
if (!this.sender) {
|
|
107
|
+
console.debug('OR WebWorker: sender not initialised. Received auth.');
|
|
108
|
+
this.initiateRestart();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.sender.authorise(data.token);
|
|
112
|
+
if (data.beaconSizeLimit) {
|
|
113
|
+
this.worker.postMessage({ type: 'beacon_size_limit', data: data.beaconSizeLimit });
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
};
|
|
117
|
+
this.sendCompressedBatch = (data) => {
|
|
118
|
+
var _a;
|
|
119
|
+
if (!this.sender) {
|
|
120
|
+
console.debug('OR Worker: sender not init. Compressed batch');
|
|
121
|
+
this.initiateRestart();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
(_a = this.sender) === null || _a === void 0 ? void 0 : _a.sendCompressed(data);
|
|
125
|
+
return;
|
|
126
|
+
};
|
|
127
|
+
this.sendUncompressedBatch = (data) => {
|
|
128
|
+
if (!this.sender) {
|
|
129
|
+
console.debug('OR Worker: sender not init. Compressed batch.');
|
|
130
|
+
this.initiateRestart();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (data) {
|
|
134
|
+
this.sender.sendUncompressed(data);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
this.postMessage = (data) => {
|
|
139
|
+
this.app.handleWorkerMsg(data);
|
|
140
|
+
};
|
|
141
|
+
this.worker.onerror = (e) => {
|
|
142
|
+
this.onError('webworker_error', e);
|
|
143
|
+
};
|
|
144
|
+
this.worker.onmessage = ({ data }) => {
|
|
145
|
+
if (rebroadcastEvents.includes(data.type)) {
|
|
146
|
+
this.postMessage(data);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
switch (data.type) {
|
|
150
|
+
case 'status':
|
|
151
|
+
this.workerStatus = data.data;
|
|
152
|
+
return;
|
|
153
|
+
case 'batch_ready':
|
|
154
|
+
if (this.sender) {
|
|
155
|
+
this.app.debug.log('Openreplay: msg batch to sender: ', data.data);
|
|
156
|
+
this.sender.push(data.data);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export default WebWorkerManager;
|
|
@@ -3,7 +3,61 @@ export interface Options {
|
|
|
3
3
|
connAttemptCount?: number;
|
|
4
4
|
connAttemptGap?: number;
|
|
5
5
|
}
|
|
6
|
-
type
|
|
6
|
+
export type ToWorkerData = null | Stop | Batch | WorkerStart | BeaconSizeLimit | ToWriterData | ForceFlushBatch | CheckQueue | ResetWriter | WriterFinalize;
|
|
7
|
+
export type FromWorkerData = Restart | Failure | NotInit | Compress | QEmpty | Status | BatchReady;
|
|
8
|
+
type BatchReady = {
|
|
9
|
+
type: 'batch_ready';
|
|
10
|
+
data: Uint8Array;
|
|
11
|
+
};
|
|
12
|
+
type Status = {
|
|
13
|
+
type: 'status';
|
|
14
|
+
data: number;
|
|
15
|
+
};
|
|
16
|
+
type Compress = {
|
|
17
|
+
type: 'compress';
|
|
18
|
+
batch: Uint8Array;
|
|
19
|
+
};
|
|
20
|
+
type Restart = {
|
|
21
|
+
type: 'restart';
|
|
22
|
+
};
|
|
23
|
+
type NotInit = {
|
|
24
|
+
type: 'not_init';
|
|
25
|
+
};
|
|
26
|
+
type Stop = {
|
|
27
|
+
type: 'stop';
|
|
28
|
+
};
|
|
29
|
+
type Batch = {
|
|
30
|
+
type: 'batch';
|
|
31
|
+
data: Array<Message>;
|
|
32
|
+
};
|
|
33
|
+
type ForceFlushBatch = {
|
|
34
|
+
type: 'forceFlushBatch';
|
|
35
|
+
};
|
|
36
|
+
type CheckQueue = {
|
|
37
|
+
type: 'check_queue';
|
|
38
|
+
};
|
|
39
|
+
type WriterFinalize = {
|
|
40
|
+
type: 'writer_finalize';
|
|
41
|
+
};
|
|
42
|
+
type ResetWriter = {
|
|
43
|
+
type: 'reset_writer';
|
|
44
|
+
};
|
|
45
|
+
type BeaconSizeLimit = {
|
|
46
|
+
type: 'beacon_size_limit';
|
|
47
|
+
data: number;
|
|
48
|
+
};
|
|
49
|
+
type ToWriterData = {
|
|
50
|
+
type: 'to_writer';
|
|
51
|
+
data: Array<Message>;
|
|
52
|
+
};
|
|
53
|
+
type Failure = {
|
|
54
|
+
type: 'failure';
|
|
55
|
+
reason: string;
|
|
56
|
+
};
|
|
57
|
+
type QEmpty = {
|
|
58
|
+
type: 'queue_empty';
|
|
59
|
+
};
|
|
60
|
+
export type WorkerStart = {
|
|
7
61
|
type: 'start';
|
|
8
62
|
ingestPoint: string;
|
|
9
63
|
pageNo: number;
|
|
@@ -11,24 +65,8 @@ type Start = {
|
|
|
11
65
|
url: string;
|
|
12
66
|
tabId: string;
|
|
13
67
|
} & Options;
|
|
14
|
-
type
|
|
15
|
-
type: 'auth';
|
|
68
|
+
export type WorkerAuth = {
|
|
16
69
|
token: string;
|
|
17
70
|
beaconSizeLimit?: number;
|
|
18
71
|
};
|
|
19
|
-
export type ToWorkerData = null | 'stop' | Start | Auth | Array<Message> | {
|
|
20
|
-
type: 'compressed';
|
|
21
|
-
batch: Uint8Array;
|
|
22
|
-
} | {
|
|
23
|
-
type: 'uncompressed';
|
|
24
|
-
batch: Uint8Array;
|
|
25
|
-
} | 'forceFlushBatch';
|
|
26
|
-
type Failure = {
|
|
27
|
-
type: 'failure';
|
|
28
|
-
reason: string;
|
|
29
|
-
};
|
|
30
|
-
export type FromWorkerData = 'restart' | Failure | 'not_init' | {
|
|
31
|
-
type: 'compress';
|
|
32
|
-
batch: Uint8Array;
|
|
33
|
-
};
|
|
34
72
|
export {};
|
|
@@ -61,6 +61,7 @@ export declare const enum Type {
|
|
|
61
61
|
BatchMetadata = 81,
|
|
62
62
|
PartitionedMessage = 82,
|
|
63
63
|
NetworkRequest = 83,
|
|
64
|
+
WSChannel = 84,
|
|
64
65
|
InputChange = 112,
|
|
65
66
|
SelectionChange = 113,
|
|
66
67
|
MouseThrashing = 114,
|
|
@@ -68,7 +69,8 @@ export declare const enum Type {
|
|
|
68
69
|
ResourceTiming = 116,
|
|
69
70
|
TabChange = 117,
|
|
70
71
|
TabData = 118,
|
|
71
|
-
CanvasNode = 119
|
|
72
|
+
CanvasNode = 119,
|
|
73
|
+
TagTrigger = 120
|
|
72
74
|
}
|
|
73
75
|
export type Timestamp = [
|
|
74
76
|
Type.Timestamp,
|
|
@@ -444,6 +446,15 @@ export type NetworkRequest = [
|
|
|
444
446
|
number,
|
|
445
447
|
number
|
|
446
448
|
];
|
|
449
|
+
export type WSChannel = [
|
|
450
|
+
Type.WSChannel,
|
|
451
|
+
string,
|
|
452
|
+
string,
|
|
453
|
+
string,
|
|
454
|
+
number,
|
|
455
|
+
string,
|
|
456
|
+
string
|
|
457
|
+
];
|
|
447
458
|
export type InputChange = [
|
|
448
459
|
Type.InputChange,
|
|
449
460
|
number,
|
|
@@ -493,5 +504,9 @@ export type CanvasNode = [
|
|
|
493
504
|
string,
|
|
494
505
|
number
|
|
495
506
|
];
|
|
496
|
-
type
|
|
507
|
+
export type TagTrigger = [
|
|
508
|
+
Type.TagTrigger,
|
|
509
|
+
number
|
|
510
|
+
];
|
|
511
|
+
type Message = Timestamp | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | Redux | Vuex | MobX | NgRx | GraphQL | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData | CanvasNode | TagTrigger;
|
|
497
512
|
export default Message;
|