@openreplay/tracker 12.1.0-beta.99 → 13.0.1
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 +9 -0
- package/bun.lockb +0 -0
- package/cjs/app/canvas.d.ts +2 -1
- package/cjs/app/canvas.js +27 -13
- package/cjs/app/index.d.ts +15 -8
- package/cjs/app/index.js +134 -88
- package/cjs/app/messages.gen.d.ts +2 -2
- package/cjs/app/messages.gen.js +8 -8
- package/cjs/common/interaction.d.ts +21 -56
- package/cjs/common/messages.gen.d.ts +7 -7
- package/cjs/index.js +2 -2
- package/coverage/clover.xml +1054 -964
- package/coverage/coverage-final.json +21 -21
- package/coverage/lcov-report/index.html +43 -43
- package/coverage/lcov-report/main/app/canvas.ts.html +224 -47
- package/coverage/lcov-report/main/app/guards.ts.html +26 -26
- package/coverage/lcov-report/main/app/index.html +42 -42
- package/coverage/lcov-report/main/app/index.ts.html +157 -37
- package/coverage/lcov-report/main/app/logger.ts.html +1 -1
- package/coverage/lcov-report/main/app/messages.gen.ts.html +244 -154
- package/coverage/lcov-report/main/app/nodes.ts.html +7 -4
- 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 +5 -5
- 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 +7 -4
- package/coverage/lcov-report/main/app/sanitizer.ts.html +2 -2
- package/coverage/lcov-report/main/app/session.ts.html +2 -2
- package/coverage/lcov-report/main/app/ticker.ts.html +1 -1
- package/coverage/lcov-report/main/index.html +13 -13
- package/coverage/lcov-report/main/index.ts.html +32 -14
- package/coverage/lcov-report/main/modules/Network/beaconProxy.ts.html +17 -8
- package/coverage/lcov-report/main/modules/Network/fetchProxy.ts.html +40 -13
- package/coverage/lcov-report/main/modules/Network/index.html +21 -21
- package/coverage/lcov-report/main/modules/Network/index.ts.html +2 -2
- package/coverage/lcov-report/main/modules/Network/networkMessage.ts.html +12 -6
- package/coverage/lcov-report/main/modules/Network/utils.ts.html +17 -8
- package/coverage/lcov-report/main/modules/Network/xhrProxy.ts.html +39 -12
- 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 +4 -22
- 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 +3 -3
- 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 +4 -4
- package/coverage/lcov-report/main/modules/index.html +24 -24
- 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 +2 -2
- 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 +95 -92
- 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 +4 -4
- package/coverage/lcov-report/main/utils.ts.html +181 -31
- package/coverage/lcov-report/webworker/BatchWriter.ts.html +1 -1
- package/coverage/lcov-report/webworker/MessageEncoder.gen.ts.html +31 -7
- package/coverage/lcov-report/webworker/PrimitiveEncoder.ts.html +1 -1
- package/coverage/lcov-report/webworker/QueueSender.ts.html +48 -18
- package/coverage/lcov-report/webworker/index.html +14 -14
- package/coverage/lcov-report/webworker/index.ts.html +51 -21
- package/coverage/lcov.info +1882 -1653
- package/lib/app/canvas.d.ts +2 -1
- package/lib/app/canvas.js +27 -13
- package/lib/app/index.d.ts +15 -8
- package/lib/app/index.js +134 -88
- package/lib/app/messages.gen.d.ts +2 -2
- package/lib/app/messages.gen.js +4 -4
- package/lib/common/interaction.d.ts +21 -56
- package/lib/common/messages.gen.d.ts +7 -7
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +2 -2
- package/package.json +2 -2
- package/cjs/app/workerManager/QueueSender.d.ts +0 -25
- package/cjs/app/workerManager/QueueSender.js +0 -133
- package/cjs/app/workerManager/index.d.ts +0 -37
- package/cjs/app/workerManager/index.js +0 -166
- package/lib/app/workerManager/QueueSender.d.ts +0 -25
- package/lib/app/workerManager/QueueSender.js +0 -130
- package/lib/app/workerManager/index.d.ts +0 -37
- package/lib/app/workerManager/index.js +0 -161
package/lib/app/canvas.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ interface Options {
|
|
|
4
4
|
quality: 'low' | 'medium' | 'high';
|
|
5
5
|
isDebug?: boolean;
|
|
6
6
|
fixedScaling?: boolean;
|
|
7
|
+
useAnimationFrame?: boolean;
|
|
7
8
|
}
|
|
8
9
|
declare class CanvasRecorder {
|
|
9
10
|
private readonly app;
|
|
@@ -17,7 +18,7 @@ declare class CanvasRecorder {
|
|
|
17
18
|
captureCanvas: (node: Node) => void;
|
|
18
19
|
recordCanvas: (node: Node, id: number) => void;
|
|
19
20
|
sendSnaps(images: {
|
|
20
|
-
data:
|
|
21
|
+
data: Blob;
|
|
21
22
|
id: number;
|
|
22
23
|
}[], canvasId: number, createdAt: number): void;
|
|
23
24
|
clear(): void;
|
package/lib/app/canvas.js
CHANGED
|
@@ -56,6 +56,17 @@ class CanvasRecorder {
|
|
|
56
56
|
};
|
|
57
57
|
const canvasMsg = CanvasNode(id.toString(), ts);
|
|
58
58
|
this.app.send(canvasMsg);
|
|
59
|
+
const captureFn = (canvas) => {
|
|
60
|
+
captureSnapshot(canvas, this.options.quality, this.snapshots[id].dummy, this.options.fixedScaling, (blob) => {
|
|
61
|
+
if (!blob)
|
|
62
|
+
return;
|
|
63
|
+
this.snapshots[id].images.push({ id: this.app.timestamp(), data: blob });
|
|
64
|
+
if (this.snapshots[id].images.length > 9) {
|
|
65
|
+
this.sendSnaps(this.snapshots[id].images, id, this.snapshots[id].createdAt);
|
|
66
|
+
this.snapshots[id].images = [];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
};
|
|
59
70
|
const int = setInterval(() => {
|
|
60
71
|
const cid = this.app.nodes.getID(node);
|
|
61
72
|
const canvas = cid ? this.app.nodes.getNode(cid) : undefined;
|
|
@@ -65,11 +76,13 @@ class CanvasRecorder {
|
|
|
65
76
|
}
|
|
66
77
|
else {
|
|
67
78
|
if (!this.snapshots[id].paused) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
if (this.options.useAnimationFrame) {
|
|
80
|
+
requestAnimationFrame(() => {
|
|
81
|
+
captureFn(canvas);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
captureFn(canvas);
|
|
73
86
|
}
|
|
74
87
|
}
|
|
75
88
|
}
|
|
@@ -92,12 +105,12 @@ class CanvasRecorder {
|
|
|
92
105
|
}
|
|
93
106
|
const formData = new FormData();
|
|
94
107
|
images.forEach((snapshot) => {
|
|
95
|
-
const blob =
|
|
108
|
+
const blob = snapshot.data;
|
|
96
109
|
if (!blob)
|
|
97
110
|
return;
|
|
98
|
-
formData.append('snapshot', blob
|
|
111
|
+
formData.append('snapshot', blob, `${createdAt}_${canvasId}_${snapshot.id}.webp`);
|
|
99
112
|
if (this.options.isDebug) {
|
|
100
|
-
saveImageData(
|
|
113
|
+
saveImageData(blob, `${createdAt}_${canvasId}_${snapshot.id}.webp`);
|
|
101
114
|
}
|
|
102
115
|
});
|
|
103
116
|
fetch(this.app.options.ingestPoint + '/v1/web/images', {
|
|
@@ -124,8 +137,8 @@ const qualityInt = {
|
|
|
124
137
|
medium: 0.55,
|
|
125
138
|
high: 0.8,
|
|
126
139
|
};
|
|
127
|
-
function captureSnapshot(canvas, quality = 'medium', dummy, fixedScaling = false) {
|
|
128
|
-
const imageFormat = 'image/
|
|
140
|
+
function captureSnapshot(canvas, quality = 'medium', dummy, fixedScaling = false, onBlob) {
|
|
141
|
+
const imageFormat = 'image/webp';
|
|
129
142
|
if (fixedScaling) {
|
|
130
143
|
const canvasScaleRatio = window.devicePixelRatio || 1;
|
|
131
144
|
dummy.width = canvas.width / canvasScaleRatio;
|
|
@@ -135,10 +148,10 @@ function captureSnapshot(canvas, quality = 'medium', dummy, fixedScaling = false
|
|
|
135
148
|
return '';
|
|
136
149
|
}
|
|
137
150
|
ctx.drawImage(canvas, 0, 0, dummy.width, dummy.height);
|
|
138
|
-
|
|
151
|
+
dummy.toBlob(onBlob, imageFormat, qualityInt[quality]);
|
|
139
152
|
}
|
|
140
153
|
else {
|
|
141
|
-
|
|
154
|
+
canvas.toBlob(onBlob, imageFormat, qualityInt[quality]);
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
157
|
function dataUrlToBlob(dataUrl) {
|
|
@@ -157,7 +170,8 @@ function dataUrlToBlob(dataUrl) {
|
|
|
157
170
|
}
|
|
158
171
|
return [new Blob([u8arr], { type: mime }), u8arr];
|
|
159
172
|
}
|
|
160
|
-
function saveImageData(
|
|
173
|
+
function saveImageData(imageDataBlob, name) {
|
|
174
|
+
const imageDataUrl = URL.createObjectURL(imageDataBlob);
|
|
161
175
|
const link = document.createElement('a');
|
|
162
176
|
link.href = imageDataUrl;
|
|
163
177
|
link.download = name;
|
package/lib/app/index.d.ts
CHANGED
|
@@ -11,12 +11,13 @@ import type { Options as ObserverOptions } from './observer/top_observer.js';
|
|
|
11
11
|
import type { Options as SanitizerOptions } from './sanitizer.js';
|
|
12
12
|
import type { Options as SessOptions } from './session.js';
|
|
13
13
|
import type { Options as NetworkOptions } from '../modules/network.js';
|
|
14
|
-
import type { Options as WebworkerOptions
|
|
14
|
+
import type { Options as WebworkerOptions } from '../common/interaction.js';
|
|
15
15
|
export interface StartOptions {
|
|
16
16
|
userID?: string;
|
|
17
17
|
metadata?: Record<string, string>;
|
|
18
18
|
forceNew?: boolean;
|
|
19
19
|
sessionHash?: string;
|
|
20
|
+
assistOnly?: boolean;
|
|
20
21
|
}
|
|
21
22
|
interface OnStartInfo {
|
|
22
23
|
sessionID: string;
|
|
@@ -57,6 +58,12 @@ type AppOptions = {
|
|
|
57
58
|
disableStringDict?: boolean;
|
|
58
59
|
assistSocketHost?: string;
|
|
59
60
|
disableCanvas?: boolean;
|
|
61
|
+
canvas: {
|
|
62
|
+
disableCanvas?: boolean;
|
|
63
|
+
fixedCanvasScaling?: boolean;
|
|
64
|
+
__save_canvas_locally?: boolean;
|
|
65
|
+
useAnimationFrame?: boolean;
|
|
66
|
+
};
|
|
60
67
|
/** @deprecated */
|
|
61
68
|
onStart?: StartCallback;
|
|
62
69
|
network?: NetworkOptions;
|
|
@@ -90,20 +97,20 @@ export default class App {
|
|
|
90
97
|
private readonly revID;
|
|
91
98
|
private activityState;
|
|
92
99
|
private readonly version;
|
|
93
|
-
private readonly
|
|
100
|
+
private readonly worker?;
|
|
101
|
+
attributeSender: AttributeSender;
|
|
102
|
+
featureFlags: FeatureFlags;
|
|
103
|
+
socketMode: boolean;
|
|
94
104
|
private compressionThreshold;
|
|
95
105
|
private restartAttempts;
|
|
96
106
|
private readonly bc;
|
|
97
107
|
private readonly contextId;
|
|
98
|
-
attributeSender: AttributeSender;
|
|
99
108
|
private canvasRecorder;
|
|
100
109
|
private uxtManager;
|
|
101
110
|
private conditionsManager;
|
|
102
|
-
featureFlags: FeatureFlags;
|
|
103
111
|
private readonly tagWatcher;
|
|
104
112
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>, signalError: (error: string, apis: string[]) => void);
|
|
105
|
-
|
|
106
|
-
private readonly _debug;
|
|
113
|
+
private _debug;
|
|
107
114
|
private _usingOldFetchPlugin;
|
|
108
115
|
send(message: Message, urgent?: boolean): void;
|
|
109
116
|
/**
|
|
@@ -161,7 +168,7 @@ export default class App {
|
|
|
161
168
|
private checkSessionToken;
|
|
162
169
|
/**
|
|
163
170
|
* start buffering messages without starting the actual session, which gives
|
|
164
|
-
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
171
|
+
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
165
172
|
* and we will then send buffered batch, so it won't get lost
|
|
166
173
|
* */
|
|
167
174
|
coldStart(startOpts?: StartOptions, conditional?: boolean): Promise<void>;
|
|
@@ -179,7 +186,7 @@ export default class App {
|
|
|
179
186
|
/**
|
|
180
187
|
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
181
188
|
*
|
|
182
|
-
* Then
|
|
189
|
+
* Then when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
183
190
|
*
|
|
184
191
|
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
185
192
|
* */
|
package/lib/app/index.js
CHANGED
|
@@ -15,7 +15,6 @@ import AttributeSender from '../modules/attributeSender.js';
|
|
|
15
15
|
import CanvasRecorder from './canvas.js';
|
|
16
16
|
import UserTestManager from '../modules/userTesting/index.js';
|
|
17
17
|
import TagWatcher from '../modules/tagWatcher.js';
|
|
18
|
-
import WebWorkerManager from './workerManager/index.js';
|
|
19
18
|
const CANCELED = 'canceled';
|
|
20
19
|
const uxtStorageKey = 'or_uxt_active';
|
|
21
20
|
const bufferStorageKey = 'or_buffer_1';
|
|
@@ -52,26 +51,13 @@ export default class App {
|
|
|
52
51
|
this.stopCallbacks = [];
|
|
53
52
|
this.commitCallbacks = [];
|
|
54
53
|
this.activityState = ActivityState.NotActive;
|
|
55
|
-
this.version = '
|
|
54
|
+
this.version = '13.0.1'; // TODO: version compatability check inside each plugin.
|
|
55
|
+
this.socketMode = false;
|
|
56
56
|
this.compressionThreshold = 24 * 1000;
|
|
57
57
|
this.restartAttempts = 0;
|
|
58
58
|
this.bc = null;
|
|
59
59
|
this.canvasRecorder = null;
|
|
60
60
|
this.conditionsManager = null;
|
|
61
|
-
this._debug = (context, e) => {
|
|
62
|
-
if (this.options.__debug_report_edp !== null) {
|
|
63
|
-
void fetch(this.options.__debug_report_edp, {
|
|
64
|
-
method: 'POST',
|
|
65
|
-
headers: { 'Content-Type': 'application/json' },
|
|
66
|
-
body: JSON.stringify({
|
|
67
|
-
context,
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
error: `${e}`,
|
|
70
|
-
}),
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
this.debug.error('OpenReplay error: ', context, e);
|
|
74
|
-
};
|
|
75
61
|
this._usingOldFetchPlugin = false;
|
|
76
62
|
this.coldStartCommitN = 0;
|
|
77
63
|
this.delay = 0;
|
|
@@ -103,6 +89,18 @@ export default class App {
|
|
|
103
89
|
});
|
|
104
90
|
};
|
|
105
91
|
this.onUxtCb = [];
|
|
92
|
+
if (Object.keys(options).findIndex((k) => ['fixedCanvasScaling', 'disableCanvas'].includes(k)) !==
|
|
93
|
+
-1) {
|
|
94
|
+
console.warn('Openreplay: canvas options are moving to separate key "canvas" in next update. Please update your configuration.');
|
|
95
|
+
options = {
|
|
96
|
+
...options,
|
|
97
|
+
canvas: {
|
|
98
|
+
__save_canvas_locally: options.__save_canvas_locally,
|
|
99
|
+
fixedCanvasScaling: options.fixedCanvasScaling,
|
|
100
|
+
disableCanvas: options.disableCanvas,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
106
104
|
this.contextId = Math.random().toString(36).slice(2);
|
|
107
105
|
this.projectKey = projectKey;
|
|
108
106
|
this.networkOptions = options.network;
|
|
@@ -127,6 +125,13 @@ export default class App {
|
|
|
127
125
|
assistSocketHost: '',
|
|
128
126
|
fixedCanvasScaling: false,
|
|
129
127
|
disableCanvas: false,
|
|
128
|
+
assistOnly: false,
|
|
129
|
+
canvas: {
|
|
130
|
+
disableCanvas: false,
|
|
131
|
+
fixedCanvasScaling: false,
|
|
132
|
+
__save_canvas_locally: false,
|
|
133
|
+
useAnimationFrame: false,
|
|
134
|
+
},
|
|
130
135
|
}, options);
|
|
131
136
|
if (!this.options.forceSingleTab && globalThis && 'BroadcastChannel' in globalThis) {
|
|
132
137
|
const host = location.hostname.split('.').slice(-2).join('_');
|
|
@@ -161,11 +166,51 @@ export default class App {
|
|
|
161
166
|
this.session.applySessionHash(sessionToken);
|
|
162
167
|
}
|
|
163
168
|
try {
|
|
164
|
-
const webworker = new Worker(URL.createObjectURL(new Blob(['"use strict";const t="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,r=0,h=0;h!==i;){if(n=t.charCodeAt(h),h+=1,n>=55296&&n<=56319){if(h===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(r=t.charCodeAt(h),!(r>=56320&&r<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+r-56320+65536,h+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class i{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(i){const s=t.encode(i),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class s extends i{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 38:case 70:case 75:case 76:case 77:case 82:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:case 24:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 50:case 54:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:case 27:case 30:case 41:case 45:case 46:case 63:case 64:case 79:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 67:case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4])}}}class e{constructor(t,i,e,n,r,h){this.pageNo=t,this.timestamp=i,this.url=e,this.onBatch=n,this.tabId=r,this.onOfflineEnd=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url],i=[118,this.tabId];this.writeType(t),this.writeFields(t),this.writeWithSize(i),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if("q_end"===t[0])return this.finaliseBatch(),this.onOfflineEnd();0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){if(this.isEmpty)return;const t=this.encoder.flush();this.onBatch(t),this.prepare()}clean(){this.encoder.reset()}}var n;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active",t[t.Stopped=4]="Stopped"}(n||(n={}));let r=null,h=n.NotActive;function a(t){postMessage({type:"status",data:t}),h=t}function u(){r&&r.finaliseBatch()}function c(){a(n.Stopping),null!==f&&(clearInterval(f),f=null),r&&(r.clean(),r=null),setTimeout((()=>{a(n.NotActive)}),100)}function o(){h!==n.Stopped&&(postMessage({type:"restart"}),c())}let f=null;self.onmessage=({data:t})=>{if(null!=t){if("writer_finalize"===t.type)return u(),h=n.Stopped;if("reset_writer"!==t.type){if("forceFlushBatch"!==t.type){if("to_writer"===t.type){let i=!1;t.data.forEach((t=>{r?r.writeMessage(t):i||(i=!0,postMessage({type:"not_init"}),o())}))}return"start"===t.type?(h=n.Starting,r=new e(t.pageNo,t.timestamp,t.url,(t=>{postMessage({type:"batch_ready",data:t},[t.buffer])}),t.tabId,(()=>postMessage({type:"queue_empty"}))),null===f&&(f=setInterval(u,1e4)),h=n.Active):"beacon_size_limit"===t.type?r?void(t.beaconSizeLimit&&r.setBeaconSizeLimit(t.beaconSizeLimit)):(console.debug("OR WebWorker: writer not initialised. Received auth."),void o()):void("restart"===t.type&&o())}u()}else c()}else u()};'], { type: 'text/javascript' })));
|
|
165
|
-
this.
|
|
169
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,s,i,e=10,n=250,h,r){this.onUnauthorised=s,this.onFailure=i,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.pageNo=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.lastBatchNum=0,this.ingestURL=t+"/v1/web/i",this.isCompressing=void 0!==h}getQueueStatus(){return 0===this.queue.length&&!this.busy}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){if(this.busy||!this.token)this.queue.push(t);else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}else this.busy=!1}retry(t,s,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout((()=>this.sendBatch(t,s,i)),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,s,i){const e=i?.toString().replace(/^([^_]+)_([^_]+).*/,"$1_$2_$3");this.busy=!0;const n={Authorization:`Bearer ${this.token}`};s&&(n["Content-Encoding"]="gzip"),null!==this.token?fetch(`${this.ingestURL}?batch=${this.pageNo??"noPageNum"}_${e??"noBatchNum"}`,{body:t,method:"POST",headers:n,keepalive:t.length<65536}).then((e=>{if(401===e.status)return this.busy=!1,void this.onUnauthorised();e.status>=400?this.retry(t,s,`${i??"noBatchNum"}_network:${e.status}`):(this.attemptsCount=0,this.sendNext())})).catch((e=>{console.warn("OpenReplay:",e),this.retry(t,s,`${i??"noBatchNum"}_reject:${e.message}`)})):setTimeout((()=>{this.sendBatch(t,s,`${i??"noBatchNum"}_newToken`)}),500)}sendCompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!0,s)}sendUncompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}clean(){this.sendNext(),setTimeout((()=>{this.token=null,this.queue.length=0}),10)}}const s="function"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let e=-1;for(let n=0,h=0,r=0;r!==s;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===s){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){i[e+=1]=240|n>>>18,i[e+=1]=128|n>>>12&63,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n;continue}}n<=127?i[e+=1]=0|n:n<=2047?(i[e+=1]=192|n>>>6,i[e+=1]=128|63&n):(i[e+=1]=224|n>>>12,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n)}return i.subarray(0,e+1)}};class i{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,s){this.data.set(t,s)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const i=s.encode(t),e=i.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(i,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class e extends i{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 38:case 70:case 75:case 76:case 77:case 82:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:case 24:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 50:case 54:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:case 27:case 30:case 41:case 45:case 46:case 63:case 64:case 79:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 67:case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4])}}}class n{constructor(t,s,i,n,h,r){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=n,this.tabId=h,this.onOfflineEnd=r,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new e(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url],s=[118,this.tabId];this.writeType(t),this.writeFields(t),this.writeWithSize(s),this.isEmpty=!0}writeWithSize(t){const s=this.encoder;if(!this.writeType(t)||!s.skip(3))return!1;const i=s.getCurrentOffset(),e=this.writeFields(t);if(e){const e=s.getCurrentOffset()-i;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,i-3),s.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if("q_end"===t[0])return this.finaliseBatch(),this.onOfflineEnd();0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new e(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new e(this.beaconSize),this.prepare()))}finaliseBatch(){if(this.isEmpty)return;const t=this.encoder.flush();this.onBatch(t),this.prepare()}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active",t[t.Stopped=4]="Stopped"}(h||(h={}));let r=null,a=null,u=h.NotActive;function o(){a&&a.finaliseBatch()}function c(){return new Promise((t=>{u=h.Stopping,null!==l&&(clearInterval(l),l=null),a&&(a.clean(),a=null),r&&(r.clean(),setTimeout((()=>{r=null}),20)),setTimeout((()=>{u=h.NotActive,t(null)}),100)}))}function p(){u!==h.Stopped&&(postMessage("a_stop"),c().then((()=>{postMessage("a_start")})))}let g,l=null;self.onmessage=({data:s})=>{if(null!=s){if("stop"===s)return o(),void c().then((()=>{u=h.Stopped}));if("forceFlushBatch"!==s){if(!Array.isArray(s)){if("compressed"===s.type){if(!r)return console.debug("OR WebWorker: sender not initialised. Compressed batch."),void p();s.batch&&r.sendCompressed(s.batch)}if("uncompressed"===s.type){if(!r)return console.debug("OR WebWorker: sender not initialised. Uncompressed batch."),void p();s.batch&&r.sendUncompressed(s.batch)}return"start"===s.type?(u=h.Starting,r=new t(s.ingestPoint,(()=>{p()}),(t=>{!function(t){postMessage({type:"failure",reason:t}),c()}(t)}),s.connAttemptCount,s.connAttemptGap,(t=>{postMessage({type:"compress",batch:t},[t.buffer])}),s.pageNo),a=new n(s.pageNo,s.timestamp,s.url,(t=>{r&&r.push(t)}),s.tabId,(()=>postMessage({type:"queue_empty"}))),null===l&&(l=setInterval(o,1e4)),u=h.Active):"auth"===s.type?r?a?(r.authorise(s.token),void(s.beaconSizeLimit&&a.setBeaconSizeLimit(s.beaconSizeLimit))):(console.debug("OR WebWorker: writer not initialised. Received auth."),void p()):(console.debug("OR WebWorker: sender not initialised. Received auth."),void p()):void 0}if(a){const t=a;s.forEach((s=>{55===s[0]&&(s[1]?g=setTimeout((()=>p()),18e5):clearTimeout(g)),t.writeMessage(s)}))}else postMessage("not_init"),p()}else o()}else o()};'], { type: 'text/javascript' })));
|
|
170
|
+
this.worker.onerror = (e) => {
|
|
171
|
+
this._debug('webworker_error', e);
|
|
172
|
+
};
|
|
173
|
+
this.worker.onmessage = ({ data }) => {
|
|
174
|
+
// handling 401 auth restart (new token assignment)
|
|
175
|
+
if (data === 'a_stop') {
|
|
176
|
+
this.stop(false);
|
|
177
|
+
}
|
|
178
|
+
else if (data === 'a_start') {
|
|
179
|
+
void this.start({}, true);
|
|
180
|
+
}
|
|
181
|
+
else if (data === 'not_init') {
|
|
182
|
+
this.debug.warn('OR WebWorker: writer not initialised. Restarting tracker');
|
|
183
|
+
}
|
|
184
|
+
else if (data.type === 'failure') {
|
|
185
|
+
this.stop(false);
|
|
186
|
+
this.debug.error('worker_failed', data.reason);
|
|
187
|
+
this._debug('worker_failed', data.reason);
|
|
188
|
+
}
|
|
189
|
+
else if (data.type === 'compress') {
|
|
190
|
+
const batch = data.batch;
|
|
191
|
+
const batchSize = batch.byteLength;
|
|
192
|
+
if (batchSize > this.compressionThreshold) {
|
|
193
|
+
gzip(data.batch, { mtime: 0 }, (err, result) => {
|
|
194
|
+
if (err) {
|
|
195
|
+
this.debug.error('Openreplay compression error:', err);
|
|
196
|
+
this.worker?.postMessage({ type: 'uncompressed', batch: batch });
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
this.worker?.postMessage({ type: 'compressed', batch: result });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
this.worker?.postMessage({ type: 'uncompressed', batch: batch });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (data.type === 'queue_empty') {
|
|
208
|
+
this.onSessionSent();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
166
211
|
const alertWorker = () => {
|
|
167
|
-
if (this.
|
|
168
|
-
this.
|
|
212
|
+
if (this.worker) {
|
|
213
|
+
this.worker.postMessage(null);
|
|
169
214
|
}
|
|
170
215
|
};
|
|
171
216
|
// keep better tactics, discard others?
|
|
@@ -184,7 +229,7 @@ export default class App {
|
|
|
184
229
|
// yes, there are someone out there
|
|
185
230
|
resp: 'never-gonna-let-you-down',
|
|
186
231
|
// you stole someone's identity
|
|
187
|
-
|
|
232
|
+
reg: 'never-gonna-run-around-and-desert-you',
|
|
188
233
|
};
|
|
189
234
|
if (this.bc) {
|
|
190
235
|
this.bc.postMessage({
|
|
@@ -202,7 +247,7 @@ export default class App {
|
|
|
202
247
|
const sessionToken = ev.data.token;
|
|
203
248
|
this.session.setSessionToken(sessionToken);
|
|
204
249
|
}
|
|
205
|
-
if (ev.data.line === proto.
|
|
250
|
+
if (ev.data.line === proto.reg) {
|
|
206
251
|
const sessionToken = ev.data.token;
|
|
207
252
|
this.session.regenerateTabId();
|
|
208
253
|
this.session.setSessionToken(sessionToken);
|
|
@@ -211,7 +256,7 @@ export default class App {
|
|
|
211
256
|
const token = this.session.getSessionToken();
|
|
212
257
|
if (token && this.bc) {
|
|
213
258
|
this.bc.postMessage({
|
|
214
|
-
line: ev.data.source === thisTab ? proto.
|
|
259
|
+
line: ev.data.source === thisTab ? proto.reg : proto.resp,
|
|
215
260
|
token,
|
|
216
261
|
source: thisTab,
|
|
217
262
|
context: this.contextId,
|
|
@@ -221,44 +266,19 @@ export default class App {
|
|
|
221
266
|
};
|
|
222
267
|
}
|
|
223
268
|
}
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
this.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this._debug('worker_failed', data.reason);
|
|
236
|
-
}
|
|
237
|
-
else if (data.type === 'compress') {
|
|
238
|
-
const batch = data.batch;
|
|
239
|
-
const batchSize = batch.byteLength;
|
|
240
|
-
if (batchSize > this.compressionThreshold) {
|
|
241
|
-
gzip(data.batch, { mtime: 0 }, (err, result) => {
|
|
242
|
-
if (err) {
|
|
243
|
-
this.debug.error('Openreplay compression error:', err);
|
|
244
|
-
this.stop(false);
|
|
245
|
-
if (this.restartAttempts < 3) {
|
|
246
|
-
this.restartAttempts += 1;
|
|
247
|
-
void this.start({}, true);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
this.workerManager?.sendCompressedBatch(result);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
this.workerManager?.sendUncompressedBatch(batch);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
else if (data.type === 'queue_empty') {
|
|
260
|
-
this.onSessionSent();
|
|
269
|
+
_debug(context, e) {
|
|
270
|
+
if (this.options.__debug_report_edp !== null) {
|
|
271
|
+
void fetch(this.options.__debug_report_edp, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: { 'Content-Type': 'application/json' },
|
|
274
|
+
body: JSON.stringify({
|
|
275
|
+
context,
|
|
276
|
+
// @ts-ignore
|
|
277
|
+
error: `${e}`,
|
|
278
|
+
}),
|
|
279
|
+
});
|
|
261
280
|
}
|
|
281
|
+
this.debug.error('OpenReplay error: ', context, e);
|
|
262
282
|
}
|
|
263
283
|
send(message, urgent = false) {
|
|
264
284
|
if (this.activityState === ActivityState.NotActive) {
|
|
@@ -298,15 +318,31 @@ export default class App {
|
|
|
298
318
|
* every ~30ms
|
|
299
319
|
* */
|
|
300
320
|
_nCommit() {
|
|
301
|
-
if (this.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
321
|
+
if (this.socketMode) {
|
|
322
|
+
this.messages.unshift(TabData(this.session.getTabId()));
|
|
323
|
+
this.messages.unshift(Timestamp(this.timestamp()));
|
|
324
|
+
this.commitCallbacks.forEach((cb) => cb(this.messages));
|
|
325
|
+
this.messages.length = 0;
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (this.worker !== undefined && this.messages.length) {
|
|
329
|
+
try {
|
|
330
|
+
requestIdleCb(() => {
|
|
331
|
+
this.messages.unshift(TabData(this.session.getTabId()));
|
|
332
|
+
this.messages.unshift(Timestamp(this.timestamp()));
|
|
333
|
+
// why I need to add opt chaining?
|
|
334
|
+
this.worker?.postMessage(this.messages);
|
|
335
|
+
this.commitCallbacks.forEach((cb) => cb(this.messages));
|
|
336
|
+
this.messages.length = 0;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
this._debug('worker_commit', e);
|
|
341
|
+
this.stop(true);
|
|
342
|
+
setTimeout(() => {
|
|
343
|
+
void this.start();
|
|
344
|
+
}, 500);
|
|
345
|
+
}
|
|
310
346
|
}
|
|
311
347
|
}
|
|
312
348
|
/**
|
|
@@ -334,7 +370,7 @@ export default class App {
|
|
|
334
370
|
}
|
|
335
371
|
}
|
|
336
372
|
postToWorker(messages) {
|
|
337
|
-
this.
|
|
373
|
+
this.worker?.postMessage(messages);
|
|
338
374
|
this.commitCallbacks.forEach((cb) => cb(messages));
|
|
339
375
|
messages.length = 0;
|
|
340
376
|
}
|
|
@@ -481,7 +517,7 @@ export default class App {
|
|
|
481
517
|
}
|
|
482
518
|
/**
|
|
483
519
|
* start buffering messages without starting the actual session, which gives
|
|
484
|
-
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
520
|
+
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
485
521
|
* and we will then send buffered batch, so it won't get lost
|
|
486
522
|
* */
|
|
487
523
|
async coldStart(startOpts = {}, conditional) {
|
|
@@ -617,7 +653,7 @@ export default class App {
|
|
|
617
653
|
/**
|
|
618
654
|
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
619
655
|
*
|
|
620
|
-
* Then
|
|
656
|
+
* Then when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
621
657
|
*
|
|
622
658
|
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
623
659
|
* */
|
|
@@ -646,7 +682,7 @@ export default class App {
|
|
|
646
682
|
async uploadOfflineRecording() {
|
|
647
683
|
this.stop(false);
|
|
648
684
|
const timestamp = now();
|
|
649
|
-
this.
|
|
685
|
+
this.worker?.postMessage({
|
|
650
686
|
type: 'start',
|
|
651
687
|
pageNo: this.session.incPageNo(),
|
|
652
688
|
ingestPoint: this.options.ingestPoint,
|
|
@@ -674,7 +710,8 @@ export default class App {
|
|
|
674
710
|
}),
|
|
675
711
|
});
|
|
676
712
|
const { token, userBrowser, userCity, userCountry, userDevice, userOS, userState, beaconSizeLimit, projectID, } = await r.json();
|
|
677
|
-
this.
|
|
713
|
+
this.worker?.postMessage({
|
|
714
|
+
type: 'auth',
|
|
678
715
|
token,
|
|
679
716
|
beaconSizeLimit,
|
|
680
717
|
});
|
|
@@ -698,7 +735,7 @@ export default class App {
|
|
|
698
735
|
if (isColdStart && this.coldInterval) {
|
|
699
736
|
clearInterval(this.coldInterval);
|
|
700
737
|
}
|
|
701
|
-
if (!this.
|
|
738
|
+
if (!this.worker) {
|
|
702
739
|
const reason = 'No worker found: perhaps, CSP is not set.';
|
|
703
740
|
this.signalError(reason, []);
|
|
704
741
|
return Promise.resolve(UnsuccessfulStart(reason));
|
|
@@ -725,7 +762,7 @@ export default class App {
|
|
|
725
762
|
metadata: startOpts.metadata,
|
|
726
763
|
});
|
|
727
764
|
const timestamp = now();
|
|
728
|
-
this.
|
|
765
|
+
this.worker.postMessage({
|
|
729
766
|
type: 'start',
|
|
730
767
|
pageNo: this.session.incPageNo(),
|
|
731
768
|
ingestPoint: this.options.ingestPoint,
|
|
@@ -756,6 +793,7 @@ export default class App {
|
|
|
756
793
|
jsHeapSizeLimit,
|
|
757
794
|
timezone: getTimezone(),
|
|
758
795
|
condition: conditionName,
|
|
796
|
+
assistOnly: startOpts.assistOnly ?? this.socketMode,
|
|
759
797
|
}),
|
|
760
798
|
})
|
|
761
799
|
.then((r) => {
|
|
@@ -771,7 +809,7 @@ export default class App {
|
|
|
771
809
|
}
|
|
772
810
|
})
|
|
773
811
|
.then(async (r) => {
|
|
774
|
-
if (!this.
|
|
812
|
+
if (!this.worker) {
|
|
775
813
|
const reason = 'no worker found after start request (this might not happen)';
|
|
776
814
|
this.signalError(reason, []);
|
|
777
815
|
return Promise.reject(reason);
|
|
@@ -785,7 +823,7 @@ export default class App {
|
|
|
785
823
|
delay, // derived from token
|
|
786
824
|
sessionID, // derived from token
|
|
787
825
|
startTimestamp, // real startTS (server time), derived from sessionID
|
|
788
|
-
userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, } = r;
|
|
826
|
+
userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, assistOnly: socketOnly, } = r;
|
|
789
827
|
if (typeof token !== 'string' ||
|
|
790
828
|
typeof userUUID !== 'string' ||
|
|
791
829
|
(typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined') ||
|
|
@@ -811,10 +849,17 @@ export default class App {
|
|
|
811
849
|
timestamp: startTimestamp || timestamp,
|
|
812
850
|
projectID,
|
|
813
851
|
});
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
852
|
+
if (socketOnly) {
|
|
853
|
+
this.socketMode = true;
|
|
854
|
+
this.worker.postMessage('stop');
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
this.worker.postMessage({
|
|
858
|
+
type: 'auth',
|
|
859
|
+
token,
|
|
860
|
+
beaconSizeLimit,
|
|
861
|
+
});
|
|
862
|
+
}
|
|
818
863
|
if (!isNewSession && token === sessionToken) {
|
|
819
864
|
this.debug.log('continuing session on new tab', this.session.getTabId());
|
|
820
865
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
@@ -831,14 +876,15 @@ export default class App {
|
|
|
831
876
|
void this.featureFlags.reloadFlags();
|
|
832
877
|
await this.tagWatcher.fetchTags(this.options.ingestPoint, token);
|
|
833
878
|
this.activityState = ActivityState.Active;
|
|
834
|
-
if (canvasEnabled && !this.options.disableCanvas) {
|
|
879
|
+
if (canvasEnabled && !this.options.canvas.disableCanvas) {
|
|
835
880
|
this.canvasRecorder =
|
|
836
881
|
this.canvasRecorder ??
|
|
837
882
|
new CanvasRecorder(this, {
|
|
838
883
|
fps: canvasFPS,
|
|
839
884
|
quality: canvasQuality,
|
|
840
|
-
isDebug: this.options.__save_canvas_locally,
|
|
841
|
-
fixedScaling: this.options.fixedCanvasScaling,
|
|
885
|
+
isDebug: this.options.canvas.__save_canvas_locally,
|
|
886
|
+
fixedScaling: this.options.canvas.fixedCanvasScaling,
|
|
887
|
+
useAnimationFrame: this.options.canvas.useAnimationFrame,
|
|
842
888
|
});
|
|
843
889
|
this.canvasRecorder.startTracking();
|
|
844
890
|
}
|
|
@@ -946,7 +992,7 @@ export default class App {
|
|
|
946
992
|
}
|
|
947
993
|
}
|
|
948
994
|
forceFlushBatch() {
|
|
949
|
-
this.
|
|
995
|
+
this.worker?.postMessage('forceFlushBatch');
|
|
950
996
|
}
|
|
951
997
|
getTabId() {
|
|
952
998
|
return this.session.getTabId();
|
|
@@ -983,8 +1029,8 @@ export default class App {
|
|
|
983
1029
|
this.stopCallbacks.forEach((cb) => cb());
|
|
984
1030
|
this.debug.log('OpenReplay tracking stopped.');
|
|
985
1031
|
this.tagWatcher.clear();
|
|
986
|
-
if (this.
|
|
987
|
-
this.
|
|
1032
|
+
if (this.worker && stopWorker) {
|
|
1033
|
+
this.worker.postMessage('stop');
|
|
988
1034
|
}
|
|
989
1035
|
this.canvasRecorder?.clear();
|
|
990
1036
|
}
|
|
@@ -31,7 +31,7 @@ export declare function Fetch(method: string, url: string, request: string, resp
|
|
|
31
31
|
export declare function Profiler(name: string, duration: number, args: string, result: string): Messages.Profiler;
|
|
32
32
|
export declare function OTable(key: string, value: string): Messages.OTable;
|
|
33
33
|
export declare function StateAction(type: string): Messages.StateAction;
|
|
34
|
-
export declare function
|
|
34
|
+
export declare function ReduxDeprecated(action: string, state: string, duration: number): Messages.ReduxDeprecated;
|
|
35
35
|
export declare function Vuex(mutation: string, state: string): Messages.Vuex;
|
|
36
36
|
export declare function MobX(type: string, payload: string): Messages.MobX;
|
|
37
37
|
export declare function NgRx(action: string, state: string, duration: number): Messages.NgRx;
|
|
@@ -72,4 +72,4 @@ export declare function TabChange(tabId: string): Messages.TabChange;
|
|
|
72
72
|
export declare function TabData(tabId: string): Messages.TabData;
|
|
73
73
|
export declare function CanvasNode(nodeId: string, timestamp: number): Messages.CanvasNode;
|
|
74
74
|
export declare function TagTrigger(tagId: number): Messages.TagTrigger;
|
|
75
|
-
export declare function
|
|
75
|
+
export declare function Redux(action: string, state: string, duration: number, actionTime: number): Messages.Redux;
|
package/lib/app/messages.gen.js
CHANGED
|
@@ -241,9 +241,9 @@ export function StateAction(type) {
|
|
|
241
241
|
type,
|
|
242
242
|
];
|
|
243
243
|
}
|
|
244
|
-
export function
|
|
244
|
+
export function ReduxDeprecated(action, state, duration) {
|
|
245
245
|
return [
|
|
246
|
-
44 /* Messages.Type.
|
|
246
|
+
44 /* Messages.Type.ReduxDeprecated */,
|
|
247
247
|
action,
|
|
248
248
|
state,
|
|
249
249
|
duration,
|
|
@@ -580,9 +580,9 @@ export function TagTrigger(tagId) {
|
|
|
580
580
|
tagId,
|
|
581
581
|
];
|
|
582
582
|
}
|
|
583
|
-
export function
|
|
583
|
+
export function Redux(action, state, duration, actionTime) {
|
|
584
584
|
return [
|
|
585
|
-
121 /* Messages.Type.
|
|
585
|
+
121 /* Messages.Type.Redux */,
|
|
586
586
|
action,
|
|
587
587
|
state,
|
|
588
588
|
duration,
|