@openreplay/tracker 7.0.3 → 8.0.0
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 +10 -0
- package/cjs/app/index.js +56 -5
- package/cjs/app/messages.gen.d.ts +2 -0
- package/cjs/app/messages.gen.js +15 -1
- package/cjs/app/observer/observer.js +2 -2
- package/cjs/app/sanitizer.d.ts +1 -0
- package/cjs/app/sanitizer.js +6 -4
- package/cjs/app/session.d.ts +4 -0
- package/cjs/app/session.js +18 -0
- package/cjs/common/interaction.d.ts +1 -0
- package/cjs/common/messages.gen.d.ts +12 -2
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +9 -1
- package/cjs/modules/attributeSender.d.ts +14 -0
- package/cjs/modules/attributeSender.js +44 -0
- package/cjs/modules/img.js +4 -4
- package/cjs/modules/tabs.d.ts +2 -0
- package/cjs/modules/tabs.js +13 -0
- package/cjs/utils.d.ts +1 -1
- package/cjs/utils.js +13 -11
- package/coverage/clover.xml +683 -620
- package/coverage/coverage-final.json +13 -12
- package/coverage/lcov-report/index.html +47 -47
- package/coverage/lcov-report/main/app/guards.ts.html +42 -42
- package/coverage/lcov-report/main/app/index.html +34 -34
- package/coverage/lcov-report/main/app/index.ts.html +62 -8
- package/coverage/lcov-report/main/app/logger.ts.html +1 -1
- package/coverage/lcov-report/main/app/messages.gen.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/iframe_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/iframe_offsets.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/index.html +1 -1
- package/coverage/lcov-report/main/app/observer/shadow_root_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/observer/top_observer.ts.html +1 -1
- package/coverage/lcov-report/main/app/sanitizer.ts.html +98 -98
- package/coverage/lcov-report/main/app/session.ts.html +1 -1
- package/coverage/lcov-report/main/app/ticker.ts.html +1 -1
- package/coverage/lcov-report/main/index.html +24 -24
- package/coverage/lcov-report/main/index.ts.html +126 -6
- package/coverage/lcov-report/main/modules/attributeSender.ts.html +217 -0
- package/coverage/lcov-report/main/modules/axiosSpy.ts.html +1 -1
- package/coverage/lcov-report/main/modules/connection.ts.html +1 -1
- package/coverage/lcov-report/main/modules/console.ts.html +1 -1
- package/coverage/lcov-report/main/modules/constructedStyleSheets.ts.html +1 -1
- package/coverage/lcov-report/main/modules/cssrules.ts.html +1 -1
- package/coverage/lcov-report/main/modules/exception.ts.html +1 -1
- package/coverage/lcov-report/main/{app/nodes.ts.html → modules/featureFlags.ts.html} +124 -127
- 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 +6 -6
- package/coverage/lcov-report/main/modules/index.html +38 -8
- package/coverage/lcov-report/main/modules/input.ts.html +1 -1
- package/coverage/lcov-report/main/modules/mouse.ts.html +1 -1
- package/coverage/lcov-report/main/modules/network.ts.html +1 -1
- package/coverage/lcov-report/main/modules/performance.ts.html +1 -1
- package/coverage/lcov-report/main/modules/scroll.ts.html +1 -1
- package/coverage/lcov-report/main/modules/selection.ts.html +1 -1
- package/coverage/lcov-report/main/modules/tabs.ts.html +1 -1
- package/coverage/lcov-report/main/modules/timing.ts.html +1 -1
- package/coverage/lcov-report/main/modules/viewport.ts.html +1 -1
- package/coverage/lcov-report/main/utils.ts.html +112 -112
- package/coverage/lcov-report/webworker/BatchWriter.ts.html +125 -176
- package/coverage/lcov-report/webworker/MessageEncoder.gen.ts.html +88 -88
- package/coverage/lcov-report/webworker/PrimitiveEncoder.ts.html +110 -110
- package/coverage/lcov-report/webworker/QueueSender.ts.html +140 -110
- package/coverage/lcov-report/webworker/index.html +56 -71
- package/coverage/lcov-report/webworker/index.ts.html +34 -10
- package/coverage/lcov.info +1232 -1092
- package/lib/app/index.d.ts +10 -0
- package/lib/app/index.js +57 -6
- package/lib/app/messages.gen.d.ts +2 -0
- package/lib/app/messages.gen.js +12 -0
- package/lib/app/observer/observer.js +3 -3
- package/lib/app/sanitizer.d.ts +1 -0
- package/lib/app/sanitizer.js +4 -3
- package/lib/app/session.d.ts +4 -0
- package/lib/app/session.js +18 -0
- package/lib/common/interaction.d.ts +1 -0
- package/lib/common/messages.gen.d.ts +12 -2
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +9 -1
- package/lib/modules/attributeSender.d.ts +14 -0
- package/lib/modules/attributeSender.js +39 -0
- package/lib/modules/img.js +5 -5
- package/lib/modules/tabs.d.ts +2 -0
- package/lib/modules/tabs.js +10 -0
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +11 -9
- package/package.json +5 -2
- package/coverage/lcov-report/main/app/observer/observer.ts.html +0 -1282
- package/coverage/lcov-report/main/vendors/finder/finder.ts.html +0 -1381
- package/coverage/lcov-report/main/vendors/finder/index.html +0 -116
- package/coverage/lcov-report/webworker/StringDictionary.ts.html +0 -124
package/lib/app/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import Sanitizer from './sanitizer.js';
|
|
|
5
5
|
import Ticker from './ticker.js';
|
|
6
6
|
import Logger from './logger.js';
|
|
7
7
|
import Session from './session.js';
|
|
8
|
+
import AttributeSender from '../modules/attributeSender.js';
|
|
8
9
|
import type { Options as ObserverOptions } from './observer/top_observer.js';
|
|
9
10
|
import type { Options as SanitizerOptions } from './sanitizer.js';
|
|
10
11
|
import type { Options as LoggerOptions } from './logger.js';
|
|
@@ -41,6 +42,7 @@ type AppOptions = {
|
|
|
41
42
|
session_reset_key: string;
|
|
42
43
|
session_token_key: string;
|
|
43
44
|
session_pageno_key: string;
|
|
45
|
+
session_tabid_key: string;
|
|
44
46
|
local_uuid_key: string;
|
|
45
47
|
ingestPoint: string;
|
|
46
48
|
resourceBaseHref: string | null;
|
|
@@ -50,6 +52,7 @@ type AppOptions = {
|
|
|
50
52
|
__debug__?: LoggerOptions;
|
|
51
53
|
localStorage: Storage | null;
|
|
52
54
|
sessionStorage: Storage | null;
|
|
55
|
+
forceSingleTab?: boolean;
|
|
53
56
|
onStart?: StartCallback;
|
|
54
57
|
network?: NetworkOptions;
|
|
55
58
|
} & WebworkerOptions & SessOptions;
|
|
@@ -78,6 +81,8 @@ export default class App {
|
|
|
78
81
|
private readonly worker?;
|
|
79
82
|
private compressionThreshold;
|
|
80
83
|
private restartAttempts;
|
|
84
|
+
private readonly bc;
|
|
85
|
+
attributeSender: AttributeSender;
|
|
81
86
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>);
|
|
82
87
|
private _debug;
|
|
83
88
|
private _usingOldFetchPlugin;
|
|
@@ -117,7 +122,12 @@ export default class App {
|
|
|
117
122
|
active(): boolean;
|
|
118
123
|
resetNextPageSession(flag: boolean): void;
|
|
119
124
|
private _start;
|
|
125
|
+
/**
|
|
126
|
+
* basically we ask other tabs during constructor
|
|
127
|
+
* and here we just apply 10ms delay just in case
|
|
128
|
+
* */
|
|
120
129
|
start(...args: Parameters<App['_start']>): Promise<StartPromiseReturn>;
|
|
130
|
+
getTabId(): string;
|
|
121
131
|
stop(stopWorker?: boolean): void;
|
|
122
132
|
}
|
|
123
133
|
export {};
|
package/lib/app/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Timestamp, Metadata, UserID } from './messages.gen.js';
|
|
1
|
+
import { Timestamp, Metadata, UserID, TabChange, TabData } from './messages.gen.js';
|
|
2
2
|
import { now, adjustTimeOrigin, deprecationWarn } from '../utils.js';
|
|
3
3
|
import Nodes from './nodes.js';
|
|
4
4
|
import Observer from './observer/top_observer.js';
|
|
@@ -8,6 +8,7 @@ import Logger, { LogLevel } from './logger.js';
|
|
|
8
8
|
import Session from './session.js';
|
|
9
9
|
import { gzip } from 'fflate';
|
|
10
10
|
import { deviceMemory, jsHeapSizeLimit } from '../modules/performance.js';
|
|
11
|
+
import AttributeSender from '../modules/attributeSender.js';
|
|
11
12
|
const CANCELED = 'canceled';
|
|
12
13
|
const START_ERROR = ':(';
|
|
13
14
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
@@ -31,9 +32,10 @@ export default class App {
|
|
|
31
32
|
this.stopCallbacks = [];
|
|
32
33
|
this.commitCallbacks = [];
|
|
33
34
|
this.activityState = ActivityState.NotActive;
|
|
34
|
-
this.version = '
|
|
35
|
+
this.version = '8.0.0'; // TODO: version compatability check inside each plugin.
|
|
35
36
|
this.compressionThreshold = 24 * 1000;
|
|
36
37
|
this.restartAttempts = 0;
|
|
38
|
+
this.bc = new BroadcastChannel('rick');
|
|
37
39
|
this._usingOldFetchPlugin = false;
|
|
38
40
|
this.delay = 0;
|
|
39
41
|
this.projectKey = projectKey;
|
|
@@ -44,6 +46,7 @@ export default class App {
|
|
|
44
46
|
session_token_key: '__openreplay_token',
|
|
45
47
|
session_pageno_key: '__openreplay_pageno',
|
|
46
48
|
session_reset_key: '__openreplay_reset',
|
|
49
|
+
session_tabid_key: '__openreplay_tabid',
|
|
47
50
|
local_uuid_key: '__openreplay_uuid',
|
|
48
51
|
ingestPoint: DEFAULT_INGEST_POINT,
|
|
49
52
|
resourceBaseHref: null,
|
|
@@ -52,6 +55,7 @@ export default class App {
|
|
|
52
55
|
__debug_report_edp: null,
|
|
53
56
|
localStorage: null,
|
|
54
57
|
sessionStorage: null,
|
|
58
|
+
forceSingleTab: false,
|
|
55
59
|
}, options);
|
|
56
60
|
this.revID = this.options.revID;
|
|
57
61
|
this.localStorage = (_a = this.options.localStorage) !== null && _a !== void 0 ? _a : window.localStorage;
|
|
@@ -64,6 +68,7 @@ export default class App {
|
|
|
64
68
|
this.debug = new Logger(this.options.__debug__);
|
|
65
69
|
this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent);
|
|
66
70
|
this.session = new Session(this, this.options);
|
|
71
|
+
this.attributeSender = new AttributeSender(this);
|
|
67
72
|
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
68
73
|
if (userID != null) {
|
|
69
74
|
// TODO: nullable userID
|
|
@@ -78,7 +83,7 @@ export default class App {
|
|
|
78
83
|
this.session.applySessionHash(sessionToken);
|
|
79
84
|
}
|
|
80
85
|
try {
|
|
81
|
-
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3,r){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i",this.isCompressing=void 0!==r}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t))}sendNext(){const t=this.queue.shift();t?(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t)):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};i&&(s["Content-Encoding"]="gzip"),null!==this.token?fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)}):setTimeout(()=>{this.sendBatch(t,i)},500)}sendCompressed(t){this.sendBatch(t,!0)}sendUncompressed(t){this.sendBatch(t,!1)}clean(){this.sendNext(),setTimeout(()=>{this.token=null,this.queue.length=0},100)}}const i="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 s extends class{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(t){const s=i.encode(t),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}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5: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:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14: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 17:return this.uint(t[1])&&this.string(t[2]);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 20:return this.uint(t[1])&&this.uint(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: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 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);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 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48: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 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);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 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58: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 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67: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 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);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 114:case 115:return this.uint(t[1]);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])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,r){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=r,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,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];this.writeType(t),this.writeFields(t),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}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),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 r;!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"}(r||(r={}));let h=null,u=null,a=r.NotActive;function o(){u&&u.finaliseBatch()}function c(){a=r.Stopping,null!==l&&(clearInterval(l),l=null),u&&(u.clean(),u=null),h&&(h.clean(),setTimeout(()=>{h=null},500)),a=r.NotActive}function g(){a!==r.Stopped&&(postMessage("restart"),c())}let p,l=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return o(),c(),a=r.Stopped;if(!Array.isArray(i)){if("compressed"===i.type){if(!h)return console.debug("WebWorker: sender not initialised. Compressed batch."),void g();h.sendCompressed(i.batch)}if("uncompressed"===i.type){if(!h)return console.debug("WebWorker: sender not initialised. Uncompressed batch."),void g();h.sendUncompressed(i.batch)}return"start"===i.type?(a=r.Starting,h=new t(i.ingestPoint,()=>{g()},t=>{!function(t){postMessage({type:"failure",reason:t}),c()}(t)},i.connAttemptCount,i.connAttemptGap,t=>{postMessage({type:"compress",batch:t},[t.buffer])}),u=new n(i.pageNo,i.timestamp,i.url,t=>h&&h.push(t)),null===l&&(l=setInterval(o,1e4)),a=r.Active):"auth"===i.type?h?u?(h.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void g()):(console.debug("WebWorker: sender not initialised. Received auth."),void g()):void 0}if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?p=setTimeout(()=>g(),18e5):clearTimeout(p)),t.writeMessage(i)})}u||(postMessage("not_init"),g())}else o()};'], { type: 'text/javascript' })));
|
|
86
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3,r){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i",this.isCompressing=void 0!==r}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t))}sendNext(){const t=this.queue.shift();t?(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t)):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};i&&(s["Content-Encoding"]="gzip"),null!==this.token?fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)}):setTimeout(()=>{this.sendBatch(t,i)},500)}sendCompressed(t){this.sendBatch(t,!0)}sendUncompressed(t){this.sendBatch(t,!1)}clean(){this.sendNext(),setTimeout(()=>{this.token=null,this.queue.length=0},10)}}const i="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 s extends class{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(t){const s=i.encode(t),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}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5: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:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14: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 17:return this.uint(t[1])&&this.string(t[2]);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 20:return this.uint(t[1])&&this.uint(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: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 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);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 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48: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 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);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 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58: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 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67: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 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);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 114:case 115:return this.uint(t[1]);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 117:case 118:return this.string(t[1])}}}class e{constructor(t,i,e,n,r){this.pageNo=t,this.timestamp=i,this.url=e,this.onBatch=n,this.tabId=r,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){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=null,u=n.NotActive;function a(){h&&h.finaliseBatch()}function o(){u=n.Stopping,null!==p&&(clearInterval(p),p=null),h&&(h.clean(),h=null),r&&(r.clean(),setTimeout(()=>{r=null},20)),setTimeout(()=>{u=n.NotActive},100)}function c(){u!==n.Stopped&&(postMessage("restart"),o())}let g,p=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),o(),u=n.Stopped;if(!Array.isArray(i)){if("compressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Compressed batch."),void c();r.sendCompressed(i.batch)}if("uncompressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Uncompressed batch."),void c();r.sendUncompressed(i.batch)}return"start"===i.type?(u=n.Starting,r=new t(i.ingestPoint,()=>{c()},t=>{!function(t){postMessage({type:"failure",reason:t}),o()}(t)},i.connAttemptCount,i.connAttemptGap,t=>{postMessage({type:"compress",batch:t},[t.buffer])}),h=new e(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t),i.tabId),null===p&&(p=setInterval(a,1e4)),u=n.Active):"auth"===i.type?r?h?(r.authorise(i.token),void(i.beaconSizeLimit&&h.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void c()):(console.debug("WebWorker: sender not initialised. Received auth."),void c()):void 0}if(null!==h){const t=h;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>c(),18e5):clearTimeout(g)),t.writeMessage(i)})}h||(postMessage("not_init"),c())}else a()};'], { type: 'text/javascript' })));
|
|
82
87
|
this.worker.onerror = (e) => {
|
|
83
88
|
this._debug('webworker_error', e);
|
|
84
89
|
};
|
|
@@ -132,6 +137,28 @@ export default class App {
|
|
|
132
137
|
catch (e) {
|
|
133
138
|
this._debug('worker_start', e);
|
|
134
139
|
}
|
|
140
|
+
const thisTab = this.session.getTabId();
|
|
141
|
+
if (!this.session.getSessionToken() && !this.options.forceSingleTab) {
|
|
142
|
+
this.bc.postMessage({ line: 'never-gonna-give-you-up', source: thisTab });
|
|
143
|
+
}
|
|
144
|
+
this.bc.onmessage = (ev) => {
|
|
145
|
+
if (ev.data.source === thisTab)
|
|
146
|
+
return;
|
|
147
|
+
if (ev.data.line === 'never-gonna-let-you-down') {
|
|
148
|
+
const sessionToken = ev.data.token;
|
|
149
|
+
this.session.setSessionToken(sessionToken);
|
|
150
|
+
}
|
|
151
|
+
if (ev.data.line === 'never-gonna-give-you-up') {
|
|
152
|
+
const token = this.session.getSessionToken();
|
|
153
|
+
if (token) {
|
|
154
|
+
this.bc.postMessage({
|
|
155
|
+
line: 'never-gonna-let-you-down',
|
|
156
|
+
token,
|
|
157
|
+
source: thisTab,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
135
162
|
}
|
|
136
163
|
_debug(context, e) {
|
|
137
164
|
if (this.options.__debug_report_edp !== null) {
|
|
@@ -173,6 +200,7 @@ export default class App {
|
|
|
173
200
|
}
|
|
174
201
|
commit() {
|
|
175
202
|
if (this.worker && this.messages.length) {
|
|
203
|
+
this.messages.unshift(TabData(this.session.getTabId()));
|
|
176
204
|
this.messages.unshift(Timestamp(this.timestamp()));
|
|
177
205
|
this.worker.postMessage(this.messages);
|
|
178
206
|
this.commitCallbacks.forEach((cb) => cb(this.messages));
|
|
@@ -342,17 +370,21 @@ export default class App {
|
|
|
342
370
|
url: document.URL,
|
|
343
371
|
connAttemptCount: this.options.connAttemptCount,
|
|
344
372
|
connAttemptGap: this.options.connAttemptGap,
|
|
373
|
+
tabId: this.session.getTabId(),
|
|
345
374
|
});
|
|
346
375
|
const lsReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
|
|
347
376
|
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
348
377
|
const needNewSessionID = startOpts.forceNew || lsReset || resetByWorker;
|
|
378
|
+
const sessionToken = this.session.getSessionToken();
|
|
379
|
+
const isNewSession = needNewSessionID || !sessionToken;
|
|
380
|
+
console.log('OpenReplay: starting session', needNewSessionID, sessionToken);
|
|
349
381
|
return window
|
|
350
382
|
.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
351
383
|
method: 'POST',
|
|
352
384
|
headers: {
|
|
353
385
|
'Content-Type': 'application/json',
|
|
354
386
|
},
|
|
355
|
-
body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token:
|
|
387
|
+
body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: isNewSession ? undefined : sessionToken, deviceMemory,
|
|
356
388
|
jsHeapSizeLimit })),
|
|
357
389
|
})
|
|
358
390
|
.then((r) => {
|
|
@@ -394,6 +426,11 @@ export default class App {
|
|
|
394
426
|
timestamp: startTimestamp || timestamp,
|
|
395
427
|
projectID,
|
|
396
428
|
});
|
|
429
|
+
if (!isNewSession && token === sessionToken) {
|
|
430
|
+
console.log('continuing session on new tab', this.session.getTabId());
|
|
431
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
432
|
+
this.send(TabChange(this.session.getTabId()));
|
|
433
|
+
}
|
|
397
434
|
// (Re)send Metadata for the case of a new session
|
|
398
435
|
Object.entries(this.session.getInfo().metadata).forEach(([key, value]) => this.send(Metadata(key, value)));
|
|
399
436
|
this.localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
@@ -428,25 +465,39 @@ export default class App {
|
|
|
428
465
|
return UnsuccessfulStart(START_ERROR);
|
|
429
466
|
});
|
|
430
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* basically we ask other tabs during constructor
|
|
470
|
+
* and here we just apply 10ms delay just in case
|
|
471
|
+
* */
|
|
431
472
|
start(...args) {
|
|
432
473
|
if (!document.hidden) {
|
|
433
|
-
return
|
|
474
|
+
return new Promise((resolve) => {
|
|
475
|
+
setTimeout(() => {
|
|
476
|
+
resolve(this._start(...args));
|
|
477
|
+
}, 10);
|
|
478
|
+
});
|
|
434
479
|
}
|
|
435
480
|
else {
|
|
436
481
|
return new Promise((resolve) => {
|
|
437
482
|
const onVisibilityChange = () => {
|
|
438
483
|
if (!document.hidden) {
|
|
439
484
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
440
|
-
|
|
485
|
+
setTimeout(() => {
|
|
486
|
+
resolve(this._start(...args));
|
|
487
|
+
}, 10);
|
|
441
488
|
}
|
|
442
489
|
};
|
|
443
490
|
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
444
491
|
});
|
|
445
492
|
}
|
|
446
493
|
}
|
|
494
|
+
getTabId() {
|
|
495
|
+
return this.session.getTabId();
|
|
496
|
+
}
|
|
447
497
|
stop(stopWorker = true) {
|
|
448
498
|
if (this.activityState !== ActivityState.NotActive) {
|
|
449
499
|
try {
|
|
500
|
+
this.attributeSender.clear();
|
|
450
501
|
this.sanitizer.clear();
|
|
451
502
|
this.observer.disconnect();
|
|
452
503
|
this.nodes.clear();
|
|
@@ -66,3 +66,5 @@ export declare function SelectionChange(selectionStart: number, selectionEnd: nu
|
|
|
66
66
|
export declare function MouseThrashing(timestamp: number): Messages.MouseThrashing;
|
|
67
67
|
export declare function UnbindNodes(totalRemovedPercent: number): Messages.UnbindNodes;
|
|
68
68
|
export declare function ResourceTiming(timestamp: number, duration: number, ttfb: number, headerSize: number, encodedBodySize: number, decodedBodySize: number, url: string, initiator: string, transferredSize: number, cached: boolean): Messages.ResourceTiming;
|
|
69
|
+
export declare function TabChange(tabId: string): Messages.TabChange;
|
|
70
|
+
export declare function TabData(tabId: string): Messages.TabData;
|
package/lib/app/messages.gen.js
CHANGED
|
@@ -530,3 +530,15 @@ export function ResourceTiming(timestamp, duration, ttfb, headerSize, encodedBod
|
|
|
530
530
|
cached,
|
|
531
531
|
];
|
|
532
532
|
}
|
|
533
|
+
export function TabChange(tabId) {
|
|
534
|
+
return [
|
|
535
|
+
117 /* Messages.Type.TabChange */,
|
|
536
|
+
tabId,
|
|
537
|
+
];
|
|
538
|
+
}
|
|
539
|
+
export function TabData(tabId) {
|
|
540
|
+
return [
|
|
541
|
+
118 /* Messages.Type.TabData */,
|
|
542
|
+
tabId,
|
|
543
|
+
];
|
|
544
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RemoveNodeAttribute,
|
|
1
|
+
import { RemoveNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, UnbindNodes, } from '../messages.gen.js';
|
|
2
2
|
import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag, isCommentNode, } from '../guards.js';
|
|
3
3
|
function isIgnored(node) {
|
|
4
4
|
if (isCommentNode(node)) {
|
|
@@ -113,7 +113,7 @@ export default class Observer {
|
|
|
113
113
|
this.app.send(SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
|
-
this.app.
|
|
116
|
+
this.app.attributeSender.sendSetAttribute(id, name, value);
|
|
117
117
|
}
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
@@ -143,7 +143,7 @@ export default class Observer {
|
|
|
143
143
|
if (name === 'href' || value.length > 1e5) {
|
|
144
144
|
value = '';
|
|
145
145
|
}
|
|
146
|
-
this.app.
|
|
146
|
+
this.app.attributeSender.sendSetAttribute(id, name, value);
|
|
147
147
|
}
|
|
148
148
|
sendNodeData(id, parentElement, data) {
|
|
149
149
|
if (hasTag(parentElement, 'style')) {
|
package/lib/app/sanitizer.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface Options {
|
|
|
9
9
|
obscureTextNumbers: boolean;
|
|
10
10
|
domSanitizer?: (node: Element) => SanitizeLevel;
|
|
11
11
|
}
|
|
12
|
+
export declare const stringWiper: (input: string) => string;
|
|
12
13
|
export default class Sanitizer {
|
|
13
14
|
private readonly app;
|
|
14
15
|
private readonly obscured;
|
package/lib/app/sanitizer.js
CHANGED
|
@@ -6,6 +6,9 @@ export var SanitizeLevel;
|
|
|
6
6
|
SanitizeLevel[SanitizeLevel["Obscured"] = 1] = "Obscured";
|
|
7
7
|
SanitizeLevel[SanitizeLevel["Hidden"] = 2] = "Hidden";
|
|
8
8
|
})(SanitizeLevel || (SanitizeLevel = {}));
|
|
9
|
+
export const stringWiper = (input) => input
|
|
10
|
+
.trim()
|
|
11
|
+
.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g, '█');
|
|
9
12
|
export default class Sanitizer {
|
|
10
13
|
constructor(app, options) {
|
|
11
14
|
this.app = app;
|
|
@@ -40,9 +43,7 @@ export default class Sanitizer {
|
|
|
40
43
|
sanitize(id, data) {
|
|
41
44
|
if (this.obscured.has(id)) {
|
|
42
45
|
// TODO: is it the best place to put trim() ? Might trimmed spaces be considered in layout in certain cases?
|
|
43
|
-
return data
|
|
44
|
-
.trim()
|
|
45
|
-
.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g, '█');
|
|
46
|
+
return stringWiper(data);
|
|
46
47
|
}
|
|
47
48
|
if (this.options.obscureTextNumbers) {
|
|
48
49
|
data = data.replace(/\d/g, '0');
|
package/lib/app/session.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
|
|
|
10
10
|
export type Options = {
|
|
11
11
|
session_token_key: string;
|
|
12
12
|
session_pageno_key: string;
|
|
13
|
+
session_tabid_key: string;
|
|
13
14
|
};
|
|
14
15
|
export default class Session {
|
|
15
16
|
private readonly app;
|
|
@@ -20,6 +21,7 @@ export default class Session {
|
|
|
20
21
|
private readonly callbacks;
|
|
21
22
|
private timestamp;
|
|
22
23
|
private projectID;
|
|
24
|
+
private tabId;
|
|
23
25
|
constructor(app: App, options: Options);
|
|
24
26
|
attachUpdateCallback(cb: OnUpdateCallback): void;
|
|
25
27
|
private handleUpdate;
|
|
@@ -32,6 +34,8 @@ export default class Session {
|
|
|
32
34
|
setSessionToken(token: string): void;
|
|
33
35
|
applySessionHash(hash: string): void;
|
|
34
36
|
getSessionHash(): string | undefined;
|
|
37
|
+
getTabId(): string;
|
|
38
|
+
private createTabId;
|
|
35
39
|
getInfo(): SessionInfo;
|
|
36
40
|
reset(): void;
|
|
37
41
|
}
|
package/lib/app/session.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { generateRandomId } from '../utils.js';
|
|
1
2
|
export default class Session {
|
|
2
3
|
constructor(app, options) {
|
|
3
4
|
this.app = app;
|
|
@@ -6,6 +7,7 @@ export default class Session {
|
|
|
6
7
|
this.userID = null;
|
|
7
8
|
this.callbacks = [];
|
|
8
9
|
this.timestamp = 0;
|
|
10
|
+
this.createTabId();
|
|
9
11
|
}
|
|
10
12
|
attachUpdateCallback(cb) {
|
|
11
13
|
this.callbacks.push(cb);
|
|
@@ -92,6 +94,22 @@ export default class Session {
|
|
|
92
94
|
}
|
|
93
95
|
return encodeURI(String(pageNo) + '&' + token);
|
|
94
96
|
}
|
|
97
|
+
getTabId() {
|
|
98
|
+
if (!this.tabId)
|
|
99
|
+
this.createTabId();
|
|
100
|
+
return this.tabId;
|
|
101
|
+
}
|
|
102
|
+
createTabId() {
|
|
103
|
+
const localId = this.app.sessionStorage.getItem(this.options.session_tabid_key);
|
|
104
|
+
if (localId) {
|
|
105
|
+
this.tabId = localId;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const randomId = generateRandomId(12);
|
|
109
|
+
this.app.sessionStorage.setItem(this.options.session_tabid_key, randomId);
|
|
110
|
+
this.tabId = randomId;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
95
113
|
getInfo() {
|
|
96
114
|
return {
|
|
97
115
|
sessionID: this.sessionID,
|
|
@@ -64,7 +64,9 @@ export declare const enum Type {
|
|
|
64
64
|
SelectionChange = 113,
|
|
65
65
|
MouseThrashing = 114,
|
|
66
66
|
UnbindNodes = 115,
|
|
67
|
-
ResourceTiming = 116
|
|
67
|
+
ResourceTiming = 116,
|
|
68
|
+
TabChange = 117,
|
|
69
|
+
TabData = 118
|
|
68
70
|
}
|
|
69
71
|
export type Timestamp = [
|
|
70
72
|
Type.Timestamp,
|
|
@@ -464,5 +466,13 @@ export type ResourceTiming = [
|
|
|
464
466
|
number,
|
|
465
467
|
boolean
|
|
466
468
|
];
|
|
467
|
-
type
|
|
469
|
+
export type TabChange = [
|
|
470
|
+
Type.TabChange,
|
|
471
|
+
string
|
|
472
|
+
];
|
|
473
|
+
export type TabData = [
|
|
474
|
+
Type.TabData,
|
|
475
|
+
string
|
|
476
|
+
];
|
|
477
|
+
type Message = Timestamp | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequest | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | Redux | Vuex | MobX | NgRx | GraphQL | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTimingDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTiming | TabChange | TabData;
|
|
468
478
|
export default Message;
|