@openreplay/tracker 12.0.11 → 12.1.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 -0
- package/cjs/app/index.d.ts +7 -6
- package/cjs/app/index.js +81 -92
- package/cjs/app/messages.gen.d.ts +2 -2
- package/cjs/app/messages.gen.js +8 -8
- package/cjs/app/workerManager/QueueSender.d.ts +25 -0
- package/cjs/app/workerManager/QueueSender.js +133 -0
- package/cjs/app/workerManager/index.d.ts +37 -0
- package/cjs/app/workerManager/index.js +166 -0
- package/cjs/common/interaction.d.ts +56 -21
- package/cjs/common/messages.gen.d.ts +7 -7
- package/cjs/index.js +1 -1
- package/lib/app/index.d.ts +7 -6
- package/lib/app/index.js +81 -92
- package/lib/app/messages.gen.d.ts +2 -2
- package/lib/app/messages.gen.js +4 -4
- package/lib/app/workerManager/QueueSender.d.ts +25 -0
- package/lib/app/workerManager/QueueSender.js +130 -0
- package/lib/app/workerManager/index.d.ts +37 -0
- package/lib/app/workerManager/index.js +161 -0
- package/lib/common/interaction.d.ts +56 -21
- package/lib/common/messages.gen.d.ts +7 -7
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/cjs/app/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ 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 } from '../common/interaction.js';
|
|
14
|
+
import type { Options as WebworkerOptions, FromWorkerData } from '../common/interaction.js';
|
|
15
15
|
export interface StartOptions {
|
|
16
16
|
userID?: string;
|
|
17
17
|
metadata?: Record<string, string>;
|
|
@@ -90,7 +90,7 @@ export default class App {
|
|
|
90
90
|
private readonly revID;
|
|
91
91
|
private activityState;
|
|
92
92
|
private readonly version;
|
|
93
|
-
private readonly
|
|
93
|
+
private readonly workerManager?;
|
|
94
94
|
private compressionThreshold;
|
|
95
95
|
private restartAttempts;
|
|
96
96
|
private readonly bc;
|
|
@@ -100,9 +100,10 @@ export default class App {
|
|
|
100
100
|
private uxtManager;
|
|
101
101
|
private conditionsManager;
|
|
102
102
|
featureFlags: FeatureFlags;
|
|
103
|
-
private tagWatcher;
|
|
103
|
+
private readonly tagWatcher;
|
|
104
104
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>, signalError: (error: string, apis: string[]) => void);
|
|
105
|
-
|
|
105
|
+
handleWorkerMsg(data: FromWorkerData): void;
|
|
106
|
+
private readonly _debug;
|
|
106
107
|
private _usingOldFetchPlugin;
|
|
107
108
|
send(message: Message, urgent?: boolean): void;
|
|
108
109
|
/**
|
|
@@ -160,7 +161,7 @@ export default class App {
|
|
|
160
161
|
private checkSessionToken;
|
|
161
162
|
/**
|
|
162
163
|
* start buffering messages without starting the actual session, which gives
|
|
163
|
-
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
164
|
+
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
|
|
164
165
|
* and we will then send buffered batch, so it won't get lost
|
|
165
166
|
* */
|
|
166
167
|
coldStart(startOpts?: StartOptions, conditional?: boolean): Promise<void>;
|
|
@@ -178,7 +179,7 @@ export default class App {
|
|
|
178
179
|
/**
|
|
179
180
|
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
180
181
|
*
|
|
181
|
-
* Then when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
182
|
+
* Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
182
183
|
*
|
|
183
184
|
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
184
185
|
* */
|
package/cjs/app/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const attributeSender_js_1 = __importDefault(require("../modules/attributeSender
|
|
|
44
44
|
const canvas_js_1 = __importDefault(require("./canvas.js"));
|
|
45
45
|
const index_js_1 = __importDefault(require("../modules/userTesting/index.js"));
|
|
46
46
|
const tagWatcher_js_1 = __importDefault(require("../modules/tagWatcher.js"));
|
|
47
|
+
const index_js_2 = __importDefault(require("./workerManager/index.js"));
|
|
47
48
|
const CANCELED = 'canceled';
|
|
48
49
|
const uxtStorageKey = 'or_uxt_active';
|
|
49
50
|
const bufferStorageKey = 'or_buffer_1';
|
|
@@ -80,12 +81,26 @@ class App {
|
|
|
80
81
|
this.stopCallbacks = [];
|
|
81
82
|
this.commitCallbacks = [];
|
|
82
83
|
this.activityState = ActivityState.NotActive;
|
|
83
|
-
this.version = '12.0.
|
|
84
|
+
this.version = '12.1.0-beta.99'; // TODO: version compatability check inside each plugin.
|
|
84
85
|
this.compressionThreshold = 24 * 1000;
|
|
85
86
|
this.restartAttempts = 0;
|
|
86
87
|
this.bc = null;
|
|
87
88
|
this.canvasRecorder = null;
|
|
88
89
|
this.conditionsManager = null;
|
|
90
|
+
this._debug = (context, e) => {
|
|
91
|
+
if (this.options.__debug_report_edp !== null) {
|
|
92
|
+
void fetch(this.options.__debug_report_edp, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: { 'Content-Type': 'application/json' },
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
context,
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
error: `${e}`,
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
this.debug.error('OpenReplay error: ', context, e);
|
|
103
|
+
};
|
|
89
104
|
this._usingOldFetchPlugin = false;
|
|
90
105
|
this.coldStartCommitN = 0;
|
|
91
106
|
this.delay = 0;
|
|
@@ -175,51 +190,11 @@ class App {
|
|
|
175
190
|
this.session.applySessionHash(sessionToken);
|
|
176
191
|
}
|
|
177
192
|
try {
|
|
178
|
-
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' })));
|
|
179
|
-
this.
|
|
180
|
-
this._debug('webworker_error', e);
|
|
181
|
-
};
|
|
182
|
-
this.worker.onmessage = ({ data }) => {
|
|
183
|
-
// handling 401 auth restart (new token assignment)
|
|
184
|
-
if (data === 'a_stop') {
|
|
185
|
-
this.stop(false);
|
|
186
|
-
}
|
|
187
|
-
else if (data === 'a_start') {
|
|
188
|
-
void this.start({}, true);
|
|
189
|
-
}
|
|
190
|
-
else if (data === 'not_init') {
|
|
191
|
-
this.debug.warn('OR WebWorker: writer not initialised. Restarting tracker');
|
|
192
|
-
}
|
|
193
|
-
else if (data.type === 'failure') {
|
|
194
|
-
this.stop(false);
|
|
195
|
-
this.debug.error('worker_failed', data.reason);
|
|
196
|
-
this._debug('worker_failed', data.reason);
|
|
197
|
-
}
|
|
198
|
-
else if (data.type === 'compress') {
|
|
199
|
-
const batch = data.batch;
|
|
200
|
-
const batchSize = batch.byteLength;
|
|
201
|
-
if (batchSize > this.compressionThreshold) {
|
|
202
|
-
(0, fflate_1.gzip)(data.batch, { mtime: 0 }, (err, result) => {
|
|
203
|
-
if (err) {
|
|
204
|
-
this.debug.error('Openreplay compression error:', err);
|
|
205
|
-
this.worker?.postMessage({ type: 'uncompressed', batch: batch });
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
this.worker?.postMessage({ type: 'compressed', batch: result });
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
this.worker?.postMessage({ type: 'uncompressed', batch: batch });
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
else if (data.type === 'queue_empty') {
|
|
217
|
-
this.onSessionSent();
|
|
218
|
-
}
|
|
219
|
-
};
|
|
193
|
+
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' })));
|
|
194
|
+
this.workerManager = new index_js_2.default(this, webworker, this._debug);
|
|
220
195
|
const alertWorker = () => {
|
|
221
|
-
if (this.
|
|
222
|
-
this.
|
|
196
|
+
if (this.workerManager) {
|
|
197
|
+
this.workerManager.processMessage(null);
|
|
223
198
|
}
|
|
224
199
|
};
|
|
225
200
|
// keep better tactics, discard others?
|
|
@@ -238,7 +213,7 @@ class App {
|
|
|
238
213
|
// yes, there are someone out there
|
|
239
214
|
resp: 'never-gonna-let-you-down',
|
|
240
215
|
// you stole someone's identity
|
|
241
|
-
|
|
216
|
+
regen: 'never-gonna-run-around-and-desert-you',
|
|
242
217
|
};
|
|
243
218
|
if (this.bc) {
|
|
244
219
|
this.bc.postMessage({
|
|
@@ -256,7 +231,7 @@ class App {
|
|
|
256
231
|
const sessionToken = ev.data.token;
|
|
257
232
|
this.session.setSessionToken(sessionToken);
|
|
258
233
|
}
|
|
259
|
-
if (ev.data.line === proto.
|
|
234
|
+
if (ev.data.line === proto.regen) {
|
|
260
235
|
const sessionToken = ev.data.token;
|
|
261
236
|
this.session.regenerateTabId();
|
|
262
237
|
this.session.setSessionToken(sessionToken);
|
|
@@ -265,7 +240,7 @@ class App {
|
|
|
265
240
|
const token = this.session.getSessionToken();
|
|
266
241
|
if (token && this.bc) {
|
|
267
242
|
this.bc.postMessage({
|
|
268
|
-
line: ev.data.source === thisTab ? proto.
|
|
243
|
+
line: ev.data.source === thisTab ? proto.regen : proto.resp,
|
|
269
244
|
token,
|
|
270
245
|
source: thisTab,
|
|
271
246
|
context: this.contextId,
|
|
@@ -275,19 +250,44 @@ class App {
|
|
|
275
250
|
};
|
|
276
251
|
}
|
|
277
252
|
}
|
|
278
|
-
|
|
279
|
-
if (
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
253
|
+
handleWorkerMsg(data) {
|
|
254
|
+
if (data.type === 'restart') {
|
|
255
|
+
this.stop(false);
|
|
256
|
+
void this.start({}, true);
|
|
257
|
+
}
|
|
258
|
+
else if (data.type === 'not_init') {
|
|
259
|
+
this.debug.warn('OR WebWorker: writer not initialised; restarting worker');
|
|
260
|
+
}
|
|
261
|
+
else if (data.type === 'failure') {
|
|
262
|
+
this.stop(false);
|
|
263
|
+
this.debug.error('worker_failed', data.reason);
|
|
264
|
+
this._debug('worker_failed', data.reason);
|
|
265
|
+
}
|
|
266
|
+
else if (data.type === 'compress') {
|
|
267
|
+
const batch = data.batch;
|
|
268
|
+
const batchSize = batch.byteLength;
|
|
269
|
+
if (batchSize > this.compressionThreshold) {
|
|
270
|
+
(0, fflate_1.gzip)(data.batch, { mtime: 0 }, (err, result) => {
|
|
271
|
+
if (err) {
|
|
272
|
+
this.debug.error('Openreplay compression error:', err);
|
|
273
|
+
this.stop(false);
|
|
274
|
+
if (this.restartAttempts < 3) {
|
|
275
|
+
this.restartAttempts += 1;
|
|
276
|
+
void this.start({}, true);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
this.workerManager?.sendCompressedBatch(result);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
this.workerManager?.sendUncompressedBatch(batch);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else if (data.type === 'queue_empty') {
|
|
289
|
+
this.onSessionSent();
|
|
289
290
|
}
|
|
290
|
-
this.debug.error('OpenReplay error: ', context, e);
|
|
291
291
|
}
|
|
292
292
|
send(message, urgent = false) {
|
|
293
293
|
if (this.activityState === ActivityState.NotActive) {
|
|
@@ -327,24 +327,15 @@ class App {
|
|
|
327
327
|
* every ~30ms
|
|
328
328
|
* */
|
|
329
329
|
_nCommit() {
|
|
330
|
-
if (this.
|
|
331
|
-
|
|
332
|
-
(0,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
catch (e) {
|
|
342
|
-
this._debug('worker_commit', e);
|
|
343
|
-
this.stop(true);
|
|
344
|
-
setTimeout(() => {
|
|
345
|
-
void this.start();
|
|
346
|
-
}, 500);
|
|
347
|
-
}
|
|
330
|
+
if (this.workerManager !== undefined && this.messages.length) {
|
|
331
|
+
(0, utils_js_1.requestIdleCb)(() => {
|
|
332
|
+
this.messages.unshift((0, messages_gen_js_2.TabData)(this.session.getTabId()));
|
|
333
|
+
this.messages.unshift((0, messages_gen_js_2.Timestamp)(this.timestamp()));
|
|
334
|
+
// why I need to add opt chaining?
|
|
335
|
+
this.workerManager?.processMessage({ type: 'batch', data: this.messages });
|
|
336
|
+
this.commitCallbacks.forEach((cb) => cb(this.messages));
|
|
337
|
+
this.messages.length = 0;
|
|
338
|
+
});
|
|
348
339
|
}
|
|
349
340
|
}
|
|
350
341
|
/**
|
|
@@ -372,7 +363,7 @@ class App {
|
|
|
372
363
|
}
|
|
373
364
|
}
|
|
374
365
|
postToWorker(messages) {
|
|
375
|
-
this.
|
|
366
|
+
this.workerManager?.processMessage({ type: 'batch', data: messages });
|
|
376
367
|
this.commitCallbacks.forEach((cb) => cb(messages));
|
|
377
368
|
messages.length = 0;
|
|
378
369
|
}
|
|
@@ -519,7 +510,7 @@ class App {
|
|
|
519
510
|
}
|
|
520
511
|
/**
|
|
521
512
|
* start buffering messages without starting the actual session, which gives
|
|
522
|
-
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger
|
|
513
|
+
* user 30 seconds to "activate" and record session by calling `start()` on conditional trigger,
|
|
523
514
|
* and we will then send buffered batch, so it won't get lost
|
|
524
515
|
* */
|
|
525
516
|
async coldStart(startOpts = {}, conditional) {
|
|
@@ -655,7 +646,7 @@ class App {
|
|
|
655
646
|
/**
|
|
656
647
|
* Saves the captured messages in localStorage (or whatever is used in its place)
|
|
657
648
|
*
|
|
658
|
-
* Then when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
649
|
+
* Then, when this.offlineRecording is called, it will preload this messages and clear the storage item
|
|
659
650
|
*
|
|
660
651
|
* Keeping the size of local storage reasonable is up to the end users of this library
|
|
661
652
|
* */
|
|
@@ -684,7 +675,7 @@ class App {
|
|
|
684
675
|
async uploadOfflineRecording() {
|
|
685
676
|
this.stop(false);
|
|
686
677
|
const timestamp = (0, utils_js_1.now)();
|
|
687
|
-
this.
|
|
678
|
+
this.workerManager?.processMessage({
|
|
688
679
|
type: 'start',
|
|
689
680
|
pageNo: this.session.incPageNo(),
|
|
690
681
|
ingestPoint: this.options.ingestPoint,
|
|
@@ -712,8 +703,7 @@ class App {
|
|
|
712
703
|
}),
|
|
713
704
|
});
|
|
714
705
|
const { token, userBrowser, userCity, userCountry, userDevice, userOS, userState, beaconSizeLimit, projectID, } = await r.json();
|
|
715
|
-
this.
|
|
716
|
-
type: 'auth',
|
|
706
|
+
this.workerManager?.authorizeWorker({
|
|
717
707
|
token,
|
|
718
708
|
beaconSizeLimit,
|
|
719
709
|
});
|
|
@@ -737,7 +727,7 @@ class App {
|
|
|
737
727
|
if (isColdStart && this.coldInterval) {
|
|
738
728
|
clearInterval(this.coldInterval);
|
|
739
729
|
}
|
|
740
|
-
if (!this.
|
|
730
|
+
if (!this.workerManager) {
|
|
741
731
|
const reason = 'No worker found: perhaps, CSP is not set.';
|
|
742
732
|
this.signalError(reason, []);
|
|
743
733
|
return Promise.resolve(UnsuccessfulStart(reason));
|
|
@@ -764,7 +754,7 @@ class App {
|
|
|
764
754
|
metadata: startOpts.metadata,
|
|
765
755
|
});
|
|
766
756
|
const timestamp = (0, utils_js_1.now)();
|
|
767
|
-
this.
|
|
757
|
+
this.workerManager?.startWorker({
|
|
768
758
|
type: 'start',
|
|
769
759
|
pageNo: this.session.incPageNo(),
|
|
770
760
|
ingestPoint: this.options.ingestPoint,
|
|
@@ -810,7 +800,7 @@ class App {
|
|
|
810
800
|
}
|
|
811
801
|
})
|
|
812
802
|
.then(async (r) => {
|
|
813
|
-
if (!this.
|
|
803
|
+
if (!this.workerManager) {
|
|
814
804
|
const reason = 'no worker found after start request (this might not happen)';
|
|
815
805
|
this.signalError(reason, []);
|
|
816
806
|
return Promise.reject(reason);
|
|
@@ -850,8 +840,7 @@ class App {
|
|
|
850
840
|
timestamp: startTimestamp || timestamp,
|
|
851
841
|
projectID,
|
|
852
842
|
});
|
|
853
|
-
this.
|
|
854
|
-
type: 'auth',
|
|
843
|
+
this.workerManager?.authorizeWorker({
|
|
855
844
|
token,
|
|
856
845
|
beaconSizeLimit,
|
|
857
846
|
});
|
|
@@ -986,7 +975,7 @@ class App {
|
|
|
986
975
|
}
|
|
987
976
|
}
|
|
988
977
|
forceFlushBatch() {
|
|
989
|
-
this.
|
|
978
|
+
this.workerManager?.processMessage({ type: 'forceFlushBatch' });
|
|
990
979
|
}
|
|
991
980
|
getTabId() {
|
|
992
981
|
return this.session.getTabId();
|
|
@@ -1023,8 +1012,8 @@ class App {
|
|
|
1023
1012
|
this.stopCallbacks.forEach((cb) => cb());
|
|
1024
1013
|
this.debug.log('OpenReplay tracking stopped.');
|
|
1025
1014
|
this.tagWatcher.clear();
|
|
1026
|
-
if (this.
|
|
1027
|
-
this.
|
|
1015
|
+
if (this.workerManager && stopWorker) {
|
|
1016
|
+
this.workerManager?.stopWorker();
|
|
1028
1017
|
}
|
|
1029
1018
|
this.canvasRecorder?.clear();
|
|
1030
1019
|
}
|
|
@@ -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 Redux(action: string, state: string, duration: number): Messages.Redux;
|
|
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 ReduxNew(action: string, state: string, duration: number, actionTime: number): Messages.ReduxNew;
|
package/cjs/app/messages.gen.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Auto-generated, do not edit
|
|
3
3
|
/* eslint-disable */
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.CSSInsertRuleURLBased = exports.CustomIssue = exports.TechnicalInfo = exports.SetCSSDataURLBased = exports.SetNodeAttributeURLBased = exports.LongTask = exports.SetNodeFocus = exports.LoadFontFace = exports.SetPageVisibility = exports.ConnectionInformation = exports.ResourceTimingDeprecated = exports.SetNodeAttributeDict = exports.StringDict = exports.PerformanceTrack = exports.GraphQL = exports.NgRx = exports.MobX = exports.Vuex = exports.
|
|
6
|
-
exports.
|
|
5
|
+
exports.CSSInsertRuleURLBased = exports.CustomIssue = exports.TechnicalInfo = exports.SetCSSDataURLBased = exports.SetNodeAttributeURLBased = exports.LongTask = exports.SetNodeFocus = exports.LoadFontFace = exports.SetPageVisibility = exports.ConnectionInformation = exports.ResourceTimingDeprecated = exports.SetNodeAttributeDict = exports.StringDict = exports.PerformanceTrack = exports.GraphQL = exports.NgRx = exports.MobX = exports.Vuex = exports.Redux = exports.StateAction = exports.OTable = exports.Profiler = exports.Fetch = exports.CSSDeleteRule = exports.CSSInsertRule = exports.Metadata = exports.UserAnonymousID = exports.UserID = exports.CustomEvent = exports.PageRenderTiming = exports.PageLoadTiming = exports.ConsoleLog = exports.NetworkRequestDeprecated = exports.MouseMove = exports.SetInputChecked = exports.SetInputValue = exports.SetInputTarget = exports.SetNodeScroll = exports.SetNodeData = exports.RemoveNodeAttribute = exports.SetNodeAttribute = exports.RemoveNode = exports.MoveNode = exports.CreateTextNode = exports.CreateElementNode = exports.CreateDocument = exports.SetViewportScroll = exports.SetViewportSize = exports.SetPageLocation = exports.Timestamp = void 0;
|
|
6
|
+
exports.ReduxNew = exports.TagTrigger = exports.CanvasNode = exports.TabData = exports.TabChange = exports.ResourceTiming = exports.UnbindNodes = exports.MouseThrashing = exports.SelectionChange = exports.InputChange = exports.WSChannel = exports.NetworkRequest = exports.PartitionedMessage = exports.BatchMetadata = exports.Zustand = exports.JSException = exports.AdoptedSSRemoveOwner = exports.AdoptedSSAddOwner = exports.AdoptedSSDeleteRule = exports.AdoptedSSInsertRuleURLBased = exports.AdoptedSSReplaceURLBased = exports.CreateIFrameDocument = exports.MouseClick = void 0;
|
|
7
7
|
function Timestamp(timestamp) {
|
|
8
8
|
return [
|
|
9
9
|
0 /* Messages.Type.Timestamp */,
|
|
@@ -276,15 +276,15 @@ function StateAction(type) {
|
|
|
276
276
|
];
|
|
277
277
|
}
|
|
278
278
|
exports.StateAction = StateAction;
|
|
279
|
-
function
|
|
279
|
+
function Redux(action, state, duration) {
|
|
280
280
|
return [
|
|
281
|
-
44 /* Messages.Type.
|
|
281
|
+
44 /* Messages.Type.Redux */,
|
|
282
282
|
action,
|
|
283
283
|
state,
|
|
284
284
|
duration,
|
|
285
285
|
];
|
|
286
286
|
}
|
|
287
|
-
exports.
|
|
287
|
+
exports.Redux = Redux;
|
|
288
288
|
function Vuex(mutation, state) {
|
|
289
289
|
return [
|
|
290
290
|
45 /* Messages.Type.Vuex */,
|
|
@@ -656,13 +656,13 @@ function TagTrigger(tagId) {
|
|
|
656
656
|
];
|
|
657
657
|
}
|
|
658
658
|
exports.TagTrigger = TagTrigger;
|
|
659
|
-
function
|
|
659
|
+
function ReduxNew(action, state, duration, actionTime) {
|
|
660
660
|
return [
|
|
661
|
-
121 /* Messages.Type.
|
|
661
|
+
121 /* Messages.Type.ReduxNew */,
|
|
662
662
|
action,
|
|
663
663
|
state,
|
|
664
664
|
duration,
|
|
665
665
|
actionTime,
|
|
666
666
|
];
|
|
667
667
|
}
|
|
668
|
-
exports.
|
|
668
|
+
exports.ReduxNew = ReduxNew;
|
|
@@ -0,0 +1,25 @@
|
|
|
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 readonly pageNo?;
|
|
8
|
+
private attemptsCount;
|
|
9
|
+
private busy;
|
|
10
|
+
private readonly queue;
|
|
11
|
+
private readonly ingestURL;
|
|
12
|
+
private token;
|
|
13
|
+
private readonly isCompressing;
|
|
14
|
+
private lastBatchNum;
|
|
15
|
+
constructor(ingestBaseURL: string, onUnauthorised: () => any, onFailure: (reason: string) => any, MAX_ATTEMPTS_COUNT?: number, ATTEMPT_TIMEOUT?: number, onCompress?: ((batch: Uint8Array) => any) | undefined, pageNo?: number | undefined);
|
|
16
|
+
getQueueStatus(): boolean;
|
|
17
|
+
authorise(token: string): void;
|
|
18
|
+
push(batch: Uint8Array): void;
|
|
19
|
+
private sendNext;
|
|
20
|
+
private retry;
|
|
21
|
+
private sendBatch;
|
|
22
|
+
sendCompressed(batch: Uint8Array): void;
|
|
23
|
+
sendUncompressed(batch: Uint8Array): void;
|
|
24
|
+
clean(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const INGEST_PATH = '/v1/web/i';
|
|
4
|
+
const KEEPALIVE_SIZE_LIMIT = 64 << 10; // 64 kB
|
|
5
|
+
class QueueSender {
|
|
6
|
+
constructor(ingestBaseURL, onUnauthorised, onFailure, MAX_ATTEMPTS_COUNT = 10, ATTEMPT_TIMEOUT = 250, onCompress, pageNo) {
|
|
7
|
+
this.onUnauthorised = onUnauthorised;
|
|
8
|
+
this.onFailure = onFailure;
|
|
9
|
+
this.MAX_ATTEMPTS_COUNT = MAX_ATTEMPTS_COUNT;
|
|
10
|
+
this.ATTEMPT_TIMEOUT = ATTEMPT_TIMEOUT;
|
|
11
|
+
this.onCompress = onCompress;
|
|
12
|
+
this.pageNo = pageNo;
|
|
13
|
+
this.attemptsCount = 0;
|
|
14
|
+
this.busy = false;
|
|
15
|
+
this.queue = [];
|
|
16
|
+
this.token = null;
|
|
17
|
+
this.lastBatchNum = 0;
|
|
18
|
+
this.ingestURL = ingestBaseURL + INGEST_PATH;
|
|
19
|
+
this.isCompressing = onCompress !== undefined;
|
|
20
|
+
}
|
|
21
|
+
getQueueStatus() {
|
|
22
|
+
return this.queue.length === 0 && !this.busy;
|
|
23
|
+
}
|
|
24
|
+
authorise(token) {
|
|
25
|
+
this.token = token;
|
|
26
|
+
if (!this.busy) {
|
|
27
|
+
// TODO: transparent busy/send logic
|
|
28
|
+
this.sendNext();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
push(batch) {
|
|
32
|
+
if (this.busy || !this.token) {
|
|
33
|
+
this.queue.push(batch);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.busy = true;
|
|
37
|
+
if (this.isCompressing && this.onCompress) {
|
|
38
|
+
this.onCompress(batch);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const batchNum = ++this.lastBatchNum;
|
|
42
|
+
this.sendBatch(batch, false, batchNum);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
sendNext() {
|
|
47
|
+
const nextBatch = this.queue.shift();
|
|
48
|
+
if (nextBatch) {
|
|
49
|
+
this.busy = true;
|
|
50
|
+
if (this.isCompressing && this.onCompress) {
|
|
51
|
+
this.onCompress(nextBatch);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const batchNum = ++this.lastBatchNum;
|
|
55
|
+
this.sendBatch(nextBatch, false, batchNum);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
this.busy = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
retry(batch, isCompressed, batchNum) {
|
|
63
|
+
if (this.attemptsCount >= this.MAX_ATTEMPTS_COUNT) {
|
|
64
|
+
this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`);
|
|
65
|
+
// remains this.busy === true
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.attemptsCount++;
|
|
69
|
+
setTimeout(() => this.sendBatch(batch, isCompressed, batchNum), this.ATTEMPT_TIMEOUT * this.attemptsCount);
|
|
70
|
+
}
|
|
71
|
+
// would be nice to use Beacon API, but it is not available in WebWorker
|
|
72
|
+
sendBatch(batch, isCompressed, batchNum) {
|
|
73
|
+
const batchNumStr = batchNum?.toString().replace(/^([^_]+)_([^_]+).*/, '$1_$2_$3');
|
|
74
|
+
this.busy = true;
|
|
75
|
+
const headers = {
|
|
76
|
+
Authorization: `Bearer ${this.token}`,
|
|
77
|
+
};
|
|
78
|
+
if (isCompressed) {
|
|
79
|
+
headers['Content-Encoding'] = 'gzip';
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* sometimes happen during assist connects for some reason
|
|
83
|
+
* */
|
|
84
|
+
if (this.token === null) {
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
this.sendBatch(batch, isCompressed, `${batchNum ?? 'noBatchNum'}_newToken`);
|
|
87
|
+
}, 500);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
fetch(`${this.ingestURL}?batch=${this.pageNo ?? 'noPageNum'}_${batchNumStr ?? 'noBatchNum'}`, {
|
|
91
|
+
body: batch,
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers,
|
|
94
|
+
keepalive: batch.length < KEEPALIVE_SIZE_LIMIT,
|
|
95
|
+
})
|
|
96
|
+
.then((r) => {
|
|
97
|
+
if (r.status === 401) {
|
|
98
|
+
// TODO: continuous session ?
|
|
99
|
+
this.busy = false;
|
|
100
|
+
this.onUnauthorised();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
else if (r.status >= 400) {
|
|
104
|
+
this.retry(batch, isCompressed, `${batchNum ?? 'noBatchNum'}_network:${r.status}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Success
|
|
108
|
+
this.attemptsCount = 0;
|
|
109
|
+
this.sendNext();
|
|
110
|
+
})
|
|
111
|
+
.catch((e) => {
|
|
112
|
+
console.warn('OpenReplay:', e);
|
|
113
|
+
this.retry(batch, isCompressed, `${batchNum ?? 'noBatchNum'}_reject:${e.message}`);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
sendCompressed(batch) {
|
|
117
|
+
const batchNum = ++this.lastBatchNum;
|
|
118
|
+
this.sendBatch(batch, true, batchNum);
|
|
119
|
+
}
|
|
120
|
+
sendUncompressed(batch) {
|
|
121
|
+
const batchNum = ++this.lastBatchNum;
|
|
122
|
+
this.sendBatch(batch, false, batchNum);
|
|
123
|
+
}
|
|
124
|
+
clean() {
|
|
125
|
+
// sending last batch and closing the shop
|
|
126
|
+
this.sendNext();
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
this.token = null;
|
|
129
|
+
this.queue.length = 0;
|
|
130
|
+
}, 10);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.default = QueueSender;
|