@openreplay/tracker 3.5.13-beta.0 → 3.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/app/guards.d.ts +2 -1
- package/cjs/app/guards.js +1 -1
- package/cjs/app/index.d.ts +1 -1
- package/cjs/app/index.js +37 -18
- package/cjs/app/nodes.d.ts +2 -2
- package/cjs/app/nodes.js +2 -2
- package/cjs/app/observer/observer.d.ts +2 -3
- package/cjs/app/observer/observer.js +58 -35
- package/cjs/app/sanitizer.d.ts +3 -1
- package/cjs/app/sanitizer.js +12 -1
- package/cjs/app/session.d.ts +2 -7
- package/cjs/app/session.js +24 -37
- package/cjs/index.js +2 -2
- package/cjs/modules/img.js +35 -9
- package/cjs/modules/input.d.ts +1 -0
- package/cjs/modules/input.js +5 -8
- package/cjs/modules/scroll.js +6 -5
- package/cjs/utils.js +1 -1
- package/lib/app/guards.d.ts +2 -1
- package/lib/app/guards.js +1 -1
- package/lib/app/index.d.ts +1 -1
- package/lib/app/index.js +38 -19
- package/lib/app/nodes.d.ts +2 -2
- package/lib/app/nodes.js +2 -2
- package/lib/app/observer/observer.d.ts +2 -3
- package/lib/app/observer/observer.js +58 -35
- package/lib/app/sanitizer.d.ts +3 -1
- package/lib/app/sanitizer.js +12 -1
- package/lib/app/session.d.ts +2 -7
- package/lib/app/session.js +24 -37
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +2 -2
- package/lib/modules/img.js +35 -9
- package/lib/modules/input.d.ts +1 -0
- package/lib/modules/input.js +5 -8
- package/lib/modules/scroll.js +6 -5
- package/lib/utils.js +1 -1
- package/package.json +8 -8
package/cjs/app/guards.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ declare type TagTypeMap = {
|
|
|
10
10
|
SELECT: HTMLSelectElement;
|
|
11
11
|
LABEL: HTMLLabelElement;
|
|
12
12
|
IFRAME: HTMLIFrameElement;
|
|
13
|
-
STYLE: HTMLStyleElement
|
|
13
|
+
STYLE: HTMLStyleElement;
|
|
14
|
+
style: SVGStyleElement;
|
|
14
15
|
LINK: HTMLLinkElement;
|
|
15
16
|
};
|
|
16
17
|
export declare function hasTag<T extends keyof TagTypeMap>(el: Node, tagName: T): el is TagTypeMap[typeof tagName];
|
package/cjs/app/guards.js
CHANGED
package/cjs/app/index.d.ts
CHANGED
package/cjs/app/index.js
CHANGED
|
@@ -32,7 +32,7 @@ class App {
|
|
|
32
32
|
this.stopCallbacks = [];
|
|
33
33
|
this.commitCallbacks = [];
|
|
34
34
|
this.activityState = ActivityState.NotActive;
|
|
35
|
-
this.version = '3.5.
|
|
35
|
+
this.version = '3.5.15'; // TODO: version compatability check inside each plugin.
|
|
36
36
|
this.projectKey = projectKey;
|
|
37
37
|
this.options = Object.assign({
|
|
38
38
|
revID: '',
|
|
@@ -57,14 +57,22 @@ class App {
|
|
|
57
57
|
this.ticker.attach(() => this.commit());
|
|
58
58
|
this.debug = new logger_js_1.default(this.options.__debug__);
|
|
59
59
|
this.notify = new logger_js_1.default(this.options.verbose ? logger_js_1.LogLevel.Warnings : logger_js_1.LogLevel.Silent);
|
|
60
|
-
this.session = new session_js_1.default(
|
|
60
|
+
this.session = new session_js_1.default();
|
|
61
|
+
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
62
|
+
if (userID != null) { // TODO: nullable userID
|
|
63
|
+
this.send(new messages_js_1.UserID(userID));
|
|
64
|
+
}
|
|
65
|
+
if (metadata != null) {
|
|
66
|
+
Object.entries(metadata).forEach(([key, value]) => this.send(new messages_js_1.Metadata(key, value)));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
61
69
|
this.localStorage = this.options.localStorage;
|
|
62
70
|
this.sessionStorage = this.options.sessionStorage;
|
|
63
71
|
if (sessionToken != null) {
|
|
64
72
|
this.sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
65
73
|
}
|
|
66
74
|
try {
|
|
67
|
-
this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function i(...i){return new t(...i)}return i.prototype=t.prototype,i}const i=new Map;const s=t(class{constructor(t,i,s){this.pageNo=t,this.firstIndex=i,this.timestamp=s,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});i.set(80,s);const e=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});i.set(0,e);const n=t(class{constructor(t,i,s){this.url=t,this.referrer=i,this.navigationStart=s,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});i.set(4,n);const r=t(class{constructor(t,i){this.width=t,this.height=i,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});i.set(5,r);const h=t(class{constructor(t,i){this.x=t,this.y=i,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});i.set(6,h);const o=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});i.set(7,o);const c=t(class{constructor(t,i,s,e,n){this.id=t,this.parentID=i,this.index=s,this.tag=e,this.svg=n,this._id=8}encode(t){return t.uint(8)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)&&t.string(this.tag)&&t.boolean(this.svg)}});i.set(8,c);const a=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(9,a);const u=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(10,u);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});i.set(11,d);const l=t(class{constructor(t,i,s){this.id=t,this.name=i,this.value=s,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});i.set(12,l);const p=t(class{constructor(t,i){this.id=t,this.name=i,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});i.set(13,p);const m=t(class{constructor(t,i){this.id=t,this.data=i,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});i.set(14,m);const g=t(class{constructor(t,i,s){this.id=t,this.x=i,this.y=s,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});i.set(16,g);const f=t(class{constructor(t,i){this.id=t,this.label=i,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});i.set(17,f);const y=t(class{constructor(t,i,s){this.id=t,this.value=i,this.mask=s,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});i.set(18,y);const _=t(class{constructor(t,i){this.id=t,this.checked=i,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});i.set(19,_);const v=t(class{constructor(t,i){this.x=t,this.y=i,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});i.set(20,v);const b=t(class{constructor(t,i){this.level=t,this.value=i,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});i.set(22,b);const S=t(class{constructor(t,i,s,e,n,r,h,o,c){this.requestStart=t,this.responseStart=i,this.responseEnd=s,this.domContentLoadedEventStart=e,this.domContentLoadedEventEnd=n,this.loadEventStart=r,this.loadEventEnd=h,this.firstPaint=o,this.firstContentfulPaint=c,this._id=23}encode(t){return t.uint(23)&&t.uint(this.requestStart)&&t.uint(this.responseStart)&&t.uint(this.responseEnd)&&t.uint(this.domContentLoadedEventStart)&&t.uint(this.domContentLoadedEventEnd)&&t.uint(this.loadEventStart)&&t.uint(this.loadEventEnd)&&t.uint(this.firstPaint)&&t.uint(this.firstContentfulPaint)}});i.set(23,S);const w=t(class{constructor(t,i,s){this.speedIndex=t,this.visuallyComplete=i,this.timeToInteractive=s,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});i.set(24,w);const E=t(class{constructor(t,i,s){this.name=t,this.message=i,this.payload=s,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});i.set(25,E);const x=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});i.set(27,x);const T=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});i.set(28,T);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});i.set(29,z);const k=t(class{constructor(t,i){this.key=t,this.value=i,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});i.set(30,k);const I=t(class{constructor(t,i,s){this.id=t,this.rule=i,this.index=s,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});i.set(37,I);const M=t(class{constructor(t,i){this.id=t,this.index=i,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});i.set(38,M);const B=t(class{constructor(t,i,s,e,n,r,h){this.method=t,this.url=i,this.request=s,this.response=e,this.status=n,this.timestamp=r,this.duration=h,this._id=39}encode(t){return t.uint(39)&&t.string(this.method)&&t.string(this.url)&&t.string(this.request)&&t.string(this.response)&&t.uint(this.status)&&t.uint(this.timestamp)&&t.uint(this.duration)}});i.set(39,B);const L=t(class{constructor(t,i,s,e){this.name=t,this.duration=i,this.args=s,this.result=e,this._id=40}encode(t){return t.uint(40)&&t.string(this.name)&&t.uint(this.duration)&&t.string(this.args)&&t.string(this.result)}});i.set(40,L);const C=t(class{constructor(t,i){this.key=t,this.value=i,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});i.set(41,C);const A=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});i.set(42,A);const U=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(44,U);const N=t(class{constructor(t,i){this.mutation=t,this.state=i,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});i.set(45,N);const R=t(class{constructor(t,i){this.type=t,this.payload=i,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});i.set(46,R);const O=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(47,O);const P=t(class{constructor(t,i,s,e){this.operationKind=t,this.operationName=i,this.variables=s,this.response=e,this._id=48}encode(t){return t.uint(48)&&t.string(this.operationKind)&&t.string(this.operationName)&&t.string(this.variables)&&t.string(this.response)}});i.set(48,P);const q=t(class{constructor(t,i,s,e){this.frames=t,this.ticks=i,this.totalJSHeapSize=s,this.usedJSHeapSize=e,this._id=49}encode(t){return t.uint(49)&&t.int(this.frames)&&t.int(this.ticks)&&t.uint(this.totalJSHeapSize)&&t.uint(this.usedJSHeapSize)}});i.set(49,q);const D=t(class{constructor(t,i,s,e,n,r,h,o){this.timestamp=t,this.duration=i,this.ttfb=s,this.headerSize=e,this.encodedBodySize=n,this.decodedBodySize=r,this.url=h,this.initiator=o,this._id=53}encode(t){return t.uint(53)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.ttfb)&&t.uint(this.headerSize)&&t.uint(this.encodedBodySize)&&t.uint(this.decodedBodySize)&&t.string(this.url)&&t.string(this.initiator)}});i.set(53,D);const W=t(class{constructor(t,i){this.downlink=t,this.type=i,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});i.set(54,W);const H=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});i.set(55,H);const J=t(class{constructor(t,i,s,e,n,r,h){this.timestamp=t,this.duration=i,this.context=s,this.containerType=e,this.containerSrc=n,this.containerId=r,this.containerName=h,this._id=59}encode(t){return t.uint(59)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.context)&&t.uint(this.containerType)&&t.string(this.containerSrc)&&t.string(this.containerId)&&t.string(this.containerName)}});i.set(59,J);const F=t(class{constructor(t,i,s,e){this.id=t,this.name=i,this.value=s,this.baseURL=e,this._id=60}encode(t){return t.uint(60)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)&&t.string(this.baseURL)}});i.set(60,F);const X=t(class{constructor(t,i,s){this.id=t,this.data=i,this.baseURL=s,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});i.set(61,X);const G=t(class{constructor(t,i){this.type=t,this.value=i,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});i.set(63,G);const K=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});i.set(64,K);const j=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});i.set(65,j);const Q=t(class{constructor(t,i,s,e){this.id=t,this.rule=i,this.index=s,this.baseURL=e,this._id=67}encode(t){return t.uint(67)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)&&t.string(this.baseURL)}});i.set(67,Q);const V=t(class{constructor(t,i,s,e){this.id=t,this.hesitationTime=i,this.label=s,this.selector=e,this._id=69}encode(t){return t.uint(69)&&t.uint(this.id)&&t.uint(this.hesitationTime)&&t.string(this.label)&&t.string(this.selector)}});i.set(69,V);const Y=t(class{constructor(t,i){this.frameID=t,this.id=i,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});i.set(70,Y);class Z{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure():(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();if(i.status>=400)return void this.retry(t);this.attemptsCount=0;const s=this.queue.shift();s?this.sendBatch(s):this.busy=!1}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0}}const tt="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(var 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))>=56320&&r<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(h+=1,(n=1024*(n-55296)+r-56320+65536)>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 it{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}checkpoint(){this.checkpointOffset=this.offset}isEmpty(){return 0===this.offset}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=tt.encode(t),s=i.byteLength;return!(!this.uint(s)||this.offset+s>this.size)&&(this.data.set(i,this.offset),this.offset+=s,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class st{constructor(t,i,s){this.pageNo=t,this.timestamp=i,this.onBatch=s,this.nextIndex=0,this.beaconSize=2e5,this.writer=new it(this.beaconSize),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepareBatchMeta()}prepareBatchMeta(){return new s(this.pageNo,this.nextIndex,this.timestamp).encode(this.writer)}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(t instanceof e&&(this.timestamp=t.timestamp),!t.encode(this.writer))for(this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta());!t.encode(this.writer);){if(this.beaconSize===this.beaconSizeLimit)return console.warn("OpenReplay: beacon size overflow. Skipping large message."),this.writer.reset(),this.prepareBatchMeta(),void(this.isEmpty=!0);this.beaconSize=Math.min(2*this.beaconSize,this.beaconSizeLimit),this.writer=new it(this.beaconSize),this.prepareBatchMeta()}this.writer.checkpoint(),this.nextIndex++,this.isEmpty=!1}finaliseBatch(){this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta(),this.isEmpty=!0)}clean(){this.writer.reset()}}let et=null,nt=null;function rt(){nt&&nt.finaliseBatch()}function ht(){null!==ct&&(clearInterval(ct),ct=null),nt&&(nt.clean(),nt=null)}let ot,ct=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return rt(),void ht();if(Array.isArray(t)){if(!nt)throw new Error("WebWorker: writer not initialised.");const s=nt;t.forEach(t=>{const e=new(i.get(t._id));Object.assign(e,t),e instanceof H&&(e.hidden?ot=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ot)),s.writeMessage(e)})}else{if("start"===t.type)return et=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{et&&(et.clean(),et=null),ht(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),nt=new st(t.pageNo,t.timestamp,t=>et&&et.push(t)),void(null===ct&&(ct=setInterval(rt,1e4)));if("auth"===t.type){if(!et)throw new Error("WebWorker: sender not initialised. Recieved auth.");if(!nt)throw new Error("WebWorker: writer not initialised. Recieved auth.");return et.authorise(t.token),void(t.beaconSizeLimit&&nt.setBeaconSizeLimit(t.beaconSizeLimit))}}}else rt()};
|
|
75
|
+
this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function i(...i){return new t(...i)}return i.prototype=t.prototype,i}const i=new Map;const s=t(class{constructor(t,i,s){this.pageNo=t,this.firstIndex=i,this.timestamp=s,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});i.set(80,s);const e=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});i.set(0,e);const n=t(class{constructor(t,i,s){this.url=t,this.referrer=i,this.navigationStart=s,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});i.set(4,n);const r=t(class{constructor(t,i){this.width=t,this.height=i,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});i.set(5,r);const h=t(class{constructor(t,i){this.x=t,this.y=i,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});i.set(6,h);const o=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});i.set(7,o);const c=t(class{constructor(t,i,s,e,n){this.id=t,this.parentID=i,this.index=s,this.tag=e,this.svg=n,this._id=8}encode(t){return t.uint(8)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)&&t.string(this.tag)&&t.boolean(this.svg)}});i.set(8,c);const a=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(9,a);const u=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(10,u);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});i.set(11,d);const l=t(class{constructor(t,i,s){this.id=t,this.name=i,this.value=s,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});i.set(12,l);const p=t(class{constructor(t,i){this.id=t,this.name=i,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});i.set(13,p);const g=t(class{constructor(t,i){this.id=t,this.data=i,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});i.set(14,g);const m=t(class{constructor(t,i,s){this.id=t,this.x=i,this.y=s,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});i.set(16,m);const f=t(class{constructor(t,i){this.id=t,this.label=i,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});i.set(17,f);const y=t(class{constructor(t,i,s){this.id=t,this.value=i,this.mask=s,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});i.set(18,y);const _=t(class{constructor(t,i){this.id=t,this.checked=i,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});i.set(19,_);const v=t(class{constructor(t,i){this.x=t,this.y=i,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});i.set(20,v);const S=t(class{constructor(t,i){this.level=t,this.value=i,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});i.set(22,S);const b=t(class{constructor(t,i,s,e,n,r,h,o,c){this.requestStart=t,this.responseStart=i,this.responseEnd=s,this.domContentLoadedEventStart=e,this.domContentLoadedEventEnd=n,this.loadEventStart=r,this.loadEventEnd=h,this.firstPaint=o,this.firstContentfulPaint=c,this._id=23}encode(t){return t.uint(23)&&t.uint(this.requestStart)&&t.uint(this.responseStart)&&t.uint(this.responseEnd)&&t.uint(this.domContentLoadedEventStart)&&t.uint(this.domContentLoadedEventEnd)&&t.uint(this.loadEventStart)&&t.uint(this.loadEventEnd)&&t.uint(this.firstPaint)&&t.uint(this.firstContentfulPaint)}});i.set(23,b);const w=t(class{constructor(t,i,s){this.speedIndex=t,this.visuallyComplete=i,this.timeToInteractive=s,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});i.set(24,w);const E=t(class{constructor(t,i,s){this.name=t,this.message=i,this.payload=s,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});i.set(25,E);const x=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});i.set(27,x);const T=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});i.set(28,T);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});i.set(29,z);const k=t(class{constructor(t,i){this.key=t,this.value=i,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});i.set(30,k);const A=t(class{constructor(t,i,s){this.id=t,this.rule=i,this.index=s,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});i.set(37,A);const I=t(class{constructor(t,i){this.id=t,this.index=i,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});i.set(38,I);const L=t(class{constructor(t,i,s,e,n,r,h){this.method=t,this.url=i,this.request=s,this.response=e,this.status=n,this.timestamp=r,this.duration=h,this._id=39}encode(t){return t.uint(39)&&t.string(this.method)&&t.string(this.url)&&t.string(this.request)&&t.string(this.response)&&t.uint(this.status)&&t.uint(this.timestamp)&&t.uint(this.duration)}});i.set(39,L);const C=t(class{constructor(t,i,s,e){this.name=t,this.duration=i,this.args=s,this.result=e,this._id=40}encode(t){return t.uint(40)&&t.string(this.name)&&t.uint(this.duration)&&t.string(this.args)&&t.string(this.result)}});i.set(40,C);const M=t(class{constructor(t,i){this.key=t,this.value=i,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});i.set(41,M);const N=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});i.set(42,N);const B=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(44,B);const U=t(class{constructor(t,i){this.mutation=t,this.state=i,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});i.set(45,U);const R=t(class{constructor(t,i){this.type=t,this.payload=i,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});i.set(46,R);const O=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(47,O);const P=t(class{constructor(t,i,s,e){this.operationKind=t,this.operationName=i,this.variables=s,this.response=e,this._id=48}encode(t){return t.uint(48)&&t.string(this.operationKind)&&t.string(this.operationName)&&t.string(this.variables)&&t.string(this.response)}});i.set(48,P);const q=t(class{constructor(t,i,s,e){this.frames=t,this.ticks=i,this.totalJSHeapSize=s,this.usedJSHeapSize=e,this._id=49}encode(t){return t.uint(49)&&t.int(this.frames)&&t.int(this.ticks)&&t.uint(this.totalJSHeapSize)&&t.uint(this.usedJSHeapSize)}});i.set(49,q);const D=t(class{constructor(t,i,s,e,n,r,h,o){this.timestamp=t,this.duration=i,this.ttfb=s,this.headerSize=e,this.encodedBodySize=n,this.decodedBodySize=r,this.url=h,this.initiator=o,this._id=53}encode(t){return t.uint(53)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.ttfb)&&t.uint(this.headerSize)&&t.uint(this.encodedBodySize)&&t.uint(this.decodedBodySize)&&t.string(this.url)&&t.string(this.initiator)}});i.set(53,D);const W=t(class{constructor(t,i){this.downlink=t,this.type=i,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});i.set(54,W);const H=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});i.set(55,H);const J=t(class{constructor(t,i,s,e,n,r,h){this.timestamp=t,this.duration=i,this.context=s,this.containerType=e,this.containerSrc=n,this.containerId=r,this.containerName=h,this._id=59}encode(t){return t.uint(59)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.context)&&t.uint(this.containerType)&&t.string(this.containerSrc)&&t.string(this.containerId)&&t.string(this.containerName)}});i.set(59,J);const F=t(class{constructor(t,i,s,e){this.id=t,this.name=i,this.value=s,this.baseURL=e,this._id=60}encode(t){return t.uint(60)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)&&t.string(this.baseURL)}});i.set(60,F);const X=t(class{constructor(t,i,s){this.id=t,this.data=i,this.baseURL=s,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});i.set(61,X);const G=t(class{constructor(t,i){this.type=t,this.value=i,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});i.set(63,G);const K=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});i.set(64,K);const j=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});i.set(65,j);const Q=t(class{constructor(t,i,s,e){this.id=t,this.rule=i,this.index=s,this.baseURL=e,this._id=67}encode(t){return t.uint(67)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)&&t.string(this.baseURL)}});i.set(67,Q);const V=t(class{constructor(t,i,s,e){this.id=t,this.hesitationTime=i,this.label=s,this.selector=e,this._id=69}encode(t){return t.uint(69)&&t.uint(this.id)&&t.uint(this.hesitationTime)&&t.string(this.label)&&t.string(this.selector)}});i.set(69,V);const Y=t(class{constructor(t,i){this.frameID=t,this.id=i,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});i.set(70,Y);class Z{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure():(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();if(i.status>=400)return void this.retry(t);this.attemptsCount=0;const s=this.queue.shift();s?this.sendBatch(s):this.busy=!1}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0}}const tt="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(var 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))>=56320&&r<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(h+=1,(n=1024*(n-55296)+r-56320+65536)>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 it{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}checkpoint(){this.checkpointOffset=this.offset}isEmpty(){return 0===this.offset}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=tt.encode(t),s=i.byteLength;return!(!this.uint(s)||this.offset+s>this.size)&&(this.data.set(i,this.offset),this.offset+=s,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class st{constructor(t,i,s){this.pageNo=t,this.timestamp=i,this.onBatch=s,this.nextIndex=0,this.beaconSize=2e5,this.writer=new it(this.beaconSize),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}prepare(){this.writer.isEmpty()&&new s(this.pageNo,this.nextIndex,this.timestamp).encode(this.writer)}write(t){const i=t.encode(this.writer);return i&&(this.isEmpty=!1,this.writer.checkpoint(),this.nextIndex++),i}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){for(t instanceof e&&(this.timestamp=t.timestamp);!this.write(t);){if(this.finaliseBatch(),this.beaconSize===this.beaconSizeLimit)return console.warn("OpenReplay: beacon size overflow. Skipping large message."),this.writer.reset(),this.prepare(),void(this.isEmpty=!0);this.beaconSize=Math.min(2*this.beaconSize,this.beaconSizeLimit),this.writer=new it(this.beaconSize),this.prepare(),this.isEmpty=!0}}finaliseBatch(){this.isEmpty||(this.onBatch(this.writer.flush()),this.prepare(),this.isEmpty=!0)}clean(){this.writer.reset()}}var et;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(et||(et={}));let nt=null,rt=null,ht=et.NotActive;function ot(){rt&&rt.finaliseBatch()}function ct(){ht=et.Stopping,null!==ut&&(clearInterval(ut),ut=null),rt&&(rt.clean(),rt=null),ht=et.NotActive}let at,ut=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return ot(),void ct();if(Array.isArray(t)){if(!rt)throw new Error("WebWorker: writer not initialised. Service Should be Started.");const s=rt;t.forEach(t=>{const e=new(i.get(t._id));Object.assign(e,t),e instanceof H&&(e.hidden?at=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(at)),s.writeMessage(e)})}else{if("start"===t.type)return ht=et.Starting,nt=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{nt&&(nt.clean(),nt=null),ct(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),rt=new st(t.pageNo,t.timestamp,t=>nt&&nt.push(t)),null===ut&&(ut=setInterval(ot,1e4)),ht=et.Active;if("auth"===t.type){if(!nt)throw new Error("WebWorker: sender not initialised. Received auth.");if(!rt)throw new Error("WebWorker: writer not initialised. Received auth.");return nt.authorise(t.token),void(t.beaconSizeLimit&&rt.setBeaconSizeLimit(t.beaconSizeLimit))}}}else ot()};
|
|
68
76
|
`], { type: 'text/javascript' })));
|
|
69
77
|
this.worker.onerror = e => {
|
|
70
78
|
this._debug("webworker_error", e);
|
|
@@ -72,6 +80,7 @@ class App {
|
|
|
72
80
|
this.worker.onmessage = ({ data }) => {
|
|
73
81
|
if (data === "failed") {
|
|
74
82
|
this.stop();
|
|
83
|
+
this._debug("worker_failed", {}); // add context (from worker)
|
|
75
84
|
}
|
|
76
85
|
else if (data === "restart") {
|
|
77
86
|
this.stop();
|
|
@@ -83,9 +92,10 @@ class App {
|
|
|
83
92
|
this.worker.postMessage(null);
|
|
84
93
|
}
|
|
85
94
|
};
|
|
86
|
-
//
|
|
95
|
+
// keep better tactics, discard others?
|
|
87
96
|
this.attachEventListener(window, 'beforeunload', alertWorker, false);
|
|
88
|
-
this.attachEventListener(document, 'mouseleave', alertWorker, false, false);
|
|
97
|
+
this.attachEventListener(document.body, 'mouseleave', alertWorker, false, false);
|
|
98
|
+
// TODO: stop session after inactivity timeout (make configurable)
|
|
89
99
|
this.attachEventListener(document, 'visibilitychange', alertWorker, false);
|
|
90
100
|
}
|
|
91
101
|
catch (e) {
|
|
@@ -159,8 +169,8 @@ class App {
|
|
|
159
169
|
}
|
|
160
170
|
// TODO: full correct semantic
|
|
161
171
|
checkRequiredVersion(version) {
|
|
162
|
-
const reqVer = version.split(
|
|
163
|
-
const ver = this.version.split(
|
|
172
|
+
const reqVer = version.split(/[.-]/);
|
|
173
|
+
const ver = this.version.split(/[.-]/);
|
|
164
174
|
for (let i = 0; i < 3; i++) {
|
|
165
175
|
if (Number(ver[i]) < Number(reqVer[i]) || isNaN(Number(ver[i])) || isNaN(Number(reqVer[i]))) {
|
|
166
176
|
return false;
|
|
@@ -254,7 +264,13 @@ class App {
|
|
|
254
264
|
connAttemptCount: this.options.connAttemptCount,
|
|
255
265
|
connAttemptGap: this.options.connAttemptGap,
|
|
256
266
|
};
|
|
257
|
-
this.worker.postMessage(startWorkerMsg);
|
|
267
|
+
this.worker.postMessage(startWorkerMsg);
|
|
268
|
+
this.session.update({
|
|
269
|
+
// "updating" with old metadata in order to trigger session's UpdateCallbacks.
|
|
270
|
+
// (for the case of internal .start() calls, like on "restart" webworker signal or assistent connection in tracker-assist )
|
|
271
|
+
metadata: startOpts.metadata || this.session.getInfo().metadata,
|
|
272
|
+
userID: startOpts.userID,
|
|
273
|
+
});
|
|
258
274
|
const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
|
|
259
275
|
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
260
276
|
return window.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
@@ -262,7 +278,7 @@ class App {
|
|
|
262
278
|
headers: {
|
|
263
279
|
'Content-Type': 'application/json',
|
|
264
280
|
},
|
|
265
|
-
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID:
|
|
281
|
+
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: this.session.getInfo().userID, token: this.sessionStorage.getItem(this.options.session_token_key), deviceMemory: performance_js_1.deviceMemory,
|
|
266
282
|
jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
|
|
267
283
|
})
|
|
268
284
|
.then(r => {
|
|
@@ -271,7 +287,7 @@ class App {
|
|
|
271
287
|
}
|
|
272
288
|
else {
|
|
273
289
|
return r.text().then(text => text === CANCELED
|
|
274
|
-
? Promise.reject(CANCELED)
|
|
290
|
+
? Promise.reject(CANCELED)
|
|
275
291
|
: Promise.reject(`Server error: ${r.status}. ${text}`));
|
|
276
292
|
}
|
|
277
293
|
})
|
|
@@ -287,20 +303,20 @@ class App {
|
|
|
287
303
|
}
|
|
288
304
|
this.sessionStorage.setItem(this.options.session_token_key, token);
|
|
289
305
|
this.localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
290
|
-
this.session.update(
|
|
291
|
-
this.activityState = ActivityState.Active;
|
|
306
|
+
this.session.update({ sessionID }); // TODO: no no-explicit 'any'
|
|
292
307
|
const startWorkerMsg = {
|
|
293
308
|
type: "auth",
|
|
294
309
|
token,
|
|
295
310
|
beaconSizeLimit
|
|
296
311
|
};
|
|
297
312
|
this.worker.postMessage(startWorkerMsg);
|
|
313
|
+
this.activityState = ActivityState.Active;
|
|
298
314
|
const onStartInfo = { sessionToken: token, userUUID, sessionID };
|
|
299
|
-
this.startCallbacks.forEach((cb) => cb(onStartInfo));
|
|
315
|
+
this.startCallbacks.forEach((cb) => cb(onStartInfo)); // TODO: start as early as possible (before receiving the token)
|
|
300
316
|
this.observer.observe();
|
|
301
317
|
this.ticker.start();
|
|
302
318
|
this.notify.log("OpenReplay tracking started.");
|
|
303
|
-
//
|
|
319
|
+
// get rid of onStart ?
|
|
304
320
|
if (typeof this.options.onStart === 'function') {
|
|
305
321
|
this.options.onStart(onStartInfo);
|
|
306
322
|
}
|
|
@@ -333,18 +349,21 @@ class App {
|
|
|
333
349
|
});
|
|
334
350
|
}
|
|
335
351
|
}
|
|
336
|
-
stop() {
|
|
352
|
+
stop(calledFromAPI = false) {
|
|
337
353
|
if (this.activityState !== ActivityState.NotActive) {
|
|
338
354
|
try {
|
|
339
|
-
if (this.worker) {
|
|
340
|
-
this.worker.postMessage("stop");
|
|
341
|
-
}
|
|
342
355
|
this.sanitizer.clear();
|
|
343
356
|
this.observer.disconnect();
|
|
344
357
|
this.nodes.clear();
|
|
345
358
|
this.ticker.stop();
|
|
346
359
|
this.stopCallbacks.forEach((cb) => cb());
|
|
360
|
+
if (calledFromAPI) {
|
|
361
|
+
this.session.reset();
|
|
362
|
+
}
|
|
347
363
|
this.notify.log("OpenReplay tracking stopped.");
|
|
364
|
+
if (this.worker) {
|
|
365
|
+
this.worker.postMessage("stop");
|
|
366
|
+
}
|
|
348
367
|
}
|
|
349
368
|
finally {
|
|
350
369
|
this.activityState = ActivityState.NotActive;
|
package/cjs/app/nodes.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare type NodeCallback = (node: Node) => void;
|
|
1
|
+
declare type NodeCallback = (node: Node, isStart: boolean) => void;
|
|
2
2
|
export default class Nodes {
|
|
3
3
|
private readonly node_id;
|
|
4
4
|
private readonly nodes;
|
|
@@ -9,7 +9,7 @@ export default class Nodes {
|
|
|
9
9
|
attachElementListener(type: string, node: Element, elementListener: EventListener): void;
|
|
10
10
|
registerNode(node: Node): [id: number, isNew: boolean];
|
|
11
11
|
unregisterNode(node: Node): number | undefined;
|
|
12
|
-
callNodeCallbacks(node: Node): void;
|
|
12
|
+
callNodeCallbacks(node: Node, isStart: boolean): void;
|
|
13
13
|
getID(node: Node): number | undefined;
|
|
14
14
|
getNode(id: number): Node | undefined;
|
|
15
15
|
clear(): void;
|
package/cjs/app/nodes.js
CHANGED
|
@@ -47,8 +47,8 @@ class Nodes {
|
|
|
47
47
|
}
|
|
48
48
|
return id;
|
|
49
49
|
}
|
|
50
|
-
callNodeCallbacks(node) {
|
|
51
|
-
this.nodeCallbacks.forEach((cb) => cb(node));
|
|
50
|
+
callNodeCallbacks(node, isStart) {
|
|
51
|
+
this.nodeCallbacks.forEach((cb) => cb(node, isStart));
|
|
52
52
|
}
|
|
53
53
|
getID(node) {
|
|
54
54
|
return node[this.node_id];
|
|
@@ -4,11 +4,10 @@ export default abstract class Observer {
|
|
|
4
4
|
protected readonly isTopContext: boolean;
|
|
5
5
|
private readonly observer;
|
|
6
6
|
private readonly commited;
|
|
7
|
+
private readonly recents;
|
|
7
8
|
private readonly indexes;
|
|
8
|
-
private readonly
|
|
9
|
+
private readonly attributesMap;
|
|
9
10
|
private readonly textSet;
|
|
10
|
-
private readonly newSet;
|
|
11
|
-
private readonly affectedSet;
|
|
12
11
|
constructor(app: App, isTopContext?: boolean);
|
|
13
12
|
private clear;
|
|
14
13
|
private sendNodeAttribute;
|
|
@@ -27,28 +27,35 @@ function isObservable(node) {
|
|
|
27
27
|
}
|
|
28
28
|
return !isIgnored(node);
|
|
29
29
|
}
|
|
30
|
+
/*
|
|
31
|
+
TODO:
|
|
32
|
+
- fix unbinding logic + send all removals first (ensure sequence is correct)
|
|
33
|
+
- use document as a 0-node in the upper context (should be updated in player at first)
|
|
34
|
+
*/
|
|
35
|
+
var RecentsType;
|
|
36
|
+
(function (RecentsType) {
|
|
37
|
+
RecentsType[RecentsType["New"] = 0] = "New";
|
|
38
|
+
RecentsType[RecentsType["Removed"] = 1] = "Removed";
|
|
39
|
+
RecentsType[RecentsType["Changed"] = 2] = "Changed";
|
|
40
|
+
})(RecentsType || (RecentsType = {}));
|
|
30
41
|
class Observer {
|
|
31
42
|
constructor(app, isTopContext = false) {
|
|
32
43
|
this.app = app;
|
|
33
44
|
this.isTopContext = isTopContext;
|
|
34
45
|
this.commited = [];
|
|
46
|
+
this.recents = new Map();
|
|
35
47
|
this.indexes = [];
|
|
36
|
-
this.
|
|
48
|
+
this.attributesMap = new Map();
|
|
37
49
|
this.textSet = new Set();
|
|
38
|
-
this.newSet = new Set();
|
|
39
|
-
this.affectedSet = new Set();
|
|
40
50
|
this.observer = new MutationObserver(this.app.safe((mutations) => {
|
|
41
|
-
for (const mutation of mutations) {
|
|
51
|
+
for (const mutation of mutations) { // mutations order is sequential
|
|
42
52
|
const target = mutation.target;
|
|
43
53
|
const type = mutation.type;
|
|
44
|
-
if (!isObservable(target)
|
|
54
|
+
if (!isObservable(target)) {
|
|
45
55
|
continue;
|
|
46
56
|
}
|
|
47
57
|
if (type === 'childList') {
|
|
48
58
|
for (let i = 0; i < mutation.removedNodes.length; i++) {
|
|
49
|
-
// TODO: handle node removal separately from binding.
|
|
50
|
-
// Node removals should go first in the commit.
|
|
51
|
-
// To check: MoveNode and other possible unbinding behaviours
|
|
52
59
|
this.bindTree(mutation.removedNodes[i]);
|
|
53
60
|
}
|
|
54
61
|
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
@@ -60,22 +67,23 @@ class Observer {
|
|
|
60
67
|
if (id === undefined) {
|
|
61
68
|
continue;
|
|
62
69
|
}
|
|
70
|
+
if (!this.recents.has(id)) {
|
|
71
|
+
this.recents.set(id, RecentsType.Changed); // TODO only when altered
|
|
72
|
+
}
|
|
63
73
|
if (type === 'attributes') {
|
|
64
74
|
const name = mutation.attributeName;
|
|
65
75
|
if (name === null) {
|
|
66
76
|
continue;
|
|
67
77
|
}
|
|
68
|
-
let attr = this.
|
|
78
|
+
let attr = this.attributesMap.get(id);
|
|
69
79
|
if (attr === undefined) {
|
|
70
|
-
this.
|
|
80
|
+
this.attributesMap.set(id, attr = new Set());
|
|
71
81
|
}
|
|
72
82
|
attr.add(name);
|
|
73
|
-
this.affectedSet.add(id);
|
|
74
83
|
continue;
|
|
75
84
|
}
|
|
76
85
|
if (type === 'characterData') {
|
|
77
86
|
this.textSet.add(id);
|
|
78
|
-
this.affectedSet.add(id);
|
|
79
87
|
continue;
|
|
80
88
|
}
|
|
81
89
|
}
|
|
@@ -84,11 +92,10 @@ class Observer {
|
|
|
84
92
|
}
|
|
85
93
|
clear() {
|
|
86
94
|
this.commited.length = 0;
|
|
95
|
+
this.recents.clear();
|
|
87
96
|
this.indexes.length = 1;
|
|
88
|
-
this.
|
|
97
|
+
this.attributesMap.clear();
|
|
89
98
|
this.textSet.clear();
|
|
90
|
-
this.newSet.clear();
|
|
91
|
-
this.affectedSet.clear();
|
|
92
99
|
}
|
|
93
100
|
sendNodeAttribute(id, node, name, value) {
|
|
94
101
|
if ((0, guards_js_1.isSVGElement)(node)) {
|
|
@@ -138,7 +145,7 @@ class Observer {
|
|
|
138
145
|
this.app.send(new messages_js_1.SetNodeAttribute(id, name, value));
|
|
139
146
|
}
|
|
140
147
|
sendNodeData(id, parentElement, data) {
|
|
141
|
-
if ((0, guards_js_1.hasTag)(parentElement, "STYLE")) {
|
|
148
|
+
if ((0, guards_js_1.hasTag)(parentElement, "STYLE") || (0, guards_js_1.hasTag)(parentElement, "style")) {
|
|
142
149
|
this.app.send(new messages_js_1.SetCSSDataURLBased(id, data, this.app.getBaseHref()));
|
|
143
150
|
return;
|
|
144
151
|
}
|
|
@@ -148,9 +155,11 @@ class Observer {
|
|
|
148
155
|
bindNode(node) {
|
|
149
156
|
const [id, isNew] = this.app.nodes.registerNode(node);
|
|
150
157
|
if (isNew) {
|
|
151
|
-
this.
|
|
158
|
+
this.recents.set(id, RecentsType.New);
|
|
159
|
+
}
|
|
160
|
+
else if (this.recents.get(id) !== RecentsType.New) { // can we do just `else` here?
|
|
161
|
+
this.recents.set(id, RecentsType.Removed);
|
|
152
162
|
}
|
|
153
|
-
this.affectedSet.add(id);
|
|
154
163
|
}
|
|
155
164
|
bindTree(node) {
|
|
156
165
|
if (!isObservable(node)) {
|
|
@@ -170,11 +179,11 @@ class Observer {
|
|
|
170
179
|
}
|
|
171
180
|
unbindNode(node) {
|
|
172
181
|
const id = this.app.nodes.unregisterNode(node);
|
|
173
|
-
|
|
174
|
-
if (id !== undefined && !this.newSet.has(id) && this.affectedSet.has(id)) { // Unbinding logic should be simplified. Node removals should go first.
|
|
182
|
+
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
|
175
183
|
this.app.send(new messages_js_1.RemoveNode(id));
|
|
176
184
|
}
|
|
177
185
|
}
|
|
186
|
+
// A top-consumption function on the infinite lists test. (~1% of performance resources)
|
|
178
187
|
_commitNode(id, node) {
|
|
179
188
|
if ((0, guards_js_1.isRootNode)(node)) {
|
|
180
189
|
return true;
|
|
@@ -183,9 +192,11 @@ class Observer {
|
|
|
183
192
|
let parentID;
|
|
184
193
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
185
194
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
186
|
-
// TODO: Clean the logic (though now it workd fine)
|
|
195
|
+
// TODO: Clean the logic (though now it workd fine)
|
|
187
196
|
if (!(0, guards_js_1.hasTag)(node, "HTML") || !this.isTopContext) {
|
|
188
197
|
if (parent === null) {
|
|
198
|
+
// Sometimes one observation contains attribute mutations for the removimg node, which gets ignored here.
|
|
199
|
+
// That shouldn't affect the visual rendering ( should it? )
|
|
189
200
|
this.unbindNode(node);
|
|
190
201
|
return false;
|
|
191
202
|
}
|
|
@@ -199,7 +210,11 @@ class Observer {
|
|
|
199
210
|
return false;
|
|
200
211
|
}
|
|
201
212
|
this.app.sanitizer.handleNode(id, parentID, node);
|
|
213
|
+
if (this.app.sanitizer.isMaskedContainer(parentID)) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
202
216
|
}
|
|
217
|
+
// From here parentID === undefined if node is top context HTML node
|
|
203
218
|
let sibling = node.previousSibling;
|
|
204
219
|
while (sibling !== null) {
|
|
205
220
|
const siblingID = this.app.nodes.getID(sibling);
|
|
@@ -213,19 +228,28 @@ class Observer {
|
|
|
213
228
|
if (sibling === null) {
|
|
214
229
|
this.indexes[id] = 0;
|
|
215
230
|
}
|
|
216
|
-
const
|
|
231
|
+
const recentsType = this.recents.get(id);
|
|
232
|
+
const isNew = recentsType === RecentsType.New;
|
|
217
233
|
const index = this.indexes[id];
|
|
218
234
|
if (index === undefined) {
|
|
219
235
|
throw 'commitNode: missing node index';
|
|
220
236
|
}
|
|
221
|
-
if (isNew
|
|
237
|
+
if (isNew) {
|
|
222
238
|
if ((0, guards_js_1.isElementNode)(node)) {
|
|
239
|
+
let el = node;
|
|
223
240
|
if (parentID !== undefined) {
|
|
224
|
-
this.app.
|
|
241
|
+
if (this.app.sanitizer.isMaskedContainer(id)) {
|
|
242
|
+
const width = el.clientWidth;
|
|
243
|
+
const height = el.clientHeight;
|
|
244
|
+
el = node.cloneNode();
|
|
245
|
+
el.style.width = width + 'px';
|
|
246
|
+
el.style.height = height + 'px';
|
|
247
|
+
}
|
|
248
|
+
this.app.send(new messages_js_1.CreateElementNode(id, parentID, index, el.tagName, (0, guards_js_1.isSVGElement)(node)));
|
|
225
249
|
}
|
|
226
|
-
for (let i = 0; i <
|
|
227
|
-
const attr =
|
|
228
|
-
this.sendNodeAttribute(id,
|
|
250
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
251
|
+
const attr = el.attributes[i];
|
|
252
|
+
this.sendNodeAttribute(id, el, attr.nodeName, attr.value);
|
|
229
253
|
}
|
|
230
254
|
}
|
|
231
255
|
else if ((0, guards_js_1.isTextNode)(node)) {
|
|
@@ -235,11 +259,10 @@ class Observer {
|
|
|
235
259
|
}
|
|
236
260
|
return true;
|
|
237
261
|
}
|
|
238
|
-
if (
|
|
239
|
-
// does this happen a lot?
|
|
262
|
+
if (recentsType === RecentsType.Removed && parentID !== undefined) {
|
|
240
263
|
this.app.send(new messages_js_1.MoveNode(id, parentID, index));
|
|
241
264
|
}
|
|
242
|
-
const attr = this.
|
|
265
|
+
const attr = this.attributesMap.get(id);
|
|
243
266
|
if (attr !== undefined) {
|
|
244
267
|
if (!(0, guards_js_1.isElementNode)(node)) {
|
|
245
268
|
throw 'commitNode: node is not an element';
|
|
@@ -268,12 +291,12 @@ class Observer {
|
|
|
268
291
|
}
|
|
269
292
|
return (this.commited[id] = this._commitNode(id, node));
|
|
270
293
|
}
|
|
271
|
-
commitNodes() {
|
|
294
|
+
commitNodes(isStart = false) {
|
|
272
295
|
let node;
|
|
273
|
-
this.
|
|
296
|
+
this.recents.forEach((type, id) => {
|
|
274
297
|
this.commitNode(id);
|
|
275
|
-
if (
|
|
276
|
-
this.app.nodes.callNodeCallbacks(node);
|
|
298
|
+
if (type === RecentsType.New && (node = this.app.nodes.getNode(id))) {
|
|
299
|
+
this.app.nodes.callNodeCallbacks(node, isStart);
|
|
277
300
|
}
|
|
278
301
|
});
|
|
279
302
|
this.clear();
|
|
@@ -290,7 +313,7 @@ class Observer {
|
|
|
290
313
|
});
|
|
291
314
|
this.bindTree(nodeToBind);
|
|
292
315
|
beforeCommit(this.app.nodes.getID(node));
|
|
293
|
-
this.commitNodes();
|
|
316
|
+
this.commitNodes(true);
|
|
294
317
|
}
|
|
295
318
|
disconnect() {
|
|
296
319
|
this.observer.disconnect();
|
package/cjs/app/sanitizer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import App from "./index.js";
|
|
1
|
+
import type App from "./index.js";
|
|
2
2
|
export interface Options {
|
|
3
3
|
obscureTextEmails: boolean;
|
|
4
4
|
obscureTextNumbers: boolean;
|
|
@@ -6,11 +6,13 @@ export interface Options {
|
|
|
6
6
|
export default class Sanitizer {
|
|
7
7
|
private readonly app;
|
|
8
8
|
private readonly masked;
|
|
9
|
+
private readonly maskedContainers;
|
|
9
10
|
private readonly options;
|
|
10
11
|
constructor(app: App, options: Partial<Options>);
|
|
11
12
|
handleNode(id: number, parentID: number, node: Node): void;
|
|
12
13
|
sanitize(id: number, data: string): string;
|
|
13
14
|
isMasked(id: number): boolean;
|
|
15
|
+
isMaskedContainer(id: number): boolean;
|
|
14
16
|
getInnerTextSecure(el: HTMLElement): string;
|
|
15
17
|
clear(): void;
|
|
16
18
|
}
|
package/cjs/app/sanitizer.js
CHANGED
|
@@ -6,6 +6,7 @@ class Sanitizer {
|
|
|
6
6
|
constructor(app, options) {
|
|
7
7
|
this.app = app;
|
|
8
8
|
this.masked = new Set();
|
|
9
|
+
this.maskedContainers = new Set();
|
|
9
10
|
this.options = Object.assign({
|
|
10
11
|
obscureTextEmails: true,
|
|
11
12
|
obscureTextNumbers: false,
|
|
@@ -13,9 +14,15 @@ class Sanitizer {
|
|
|
13
14
|
}
|
|
14
15
|
handleNode(id, parentID, node) {
|
|
15
16
|
if (this.masked.has(parentID) ||
|
|
16
|
-
((0, guards_js_1.isElementNode)(node) &&
|
|
17
|
+
((0, guards_js_1.isElementNode)(node) &&
|
|
18
|
+
(0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
|
|
17
19
|
this.masked.add(id);
|
|
18
20
|
}
|
|
21
|
+
if (this.maskedContainers.has(parentID) ||
|
|
22
|
+
((0, guards_js_1.isElementNode)(node) &&
|
|
23
|
+
(0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
|
|
24
|
+
this.maskedContainers.add(id);
|
|
25
|
+
}
|
|
19
26
|
}
|
|
20
27
|
sanitize(id, data) {
|
|
21
28
|
if (this.masked.has(id)) {
|
|
@@ -33,6 +40,9 @@ class Sanitizer {
|
|
|
33
40
|
isMasked(id) {
|
|
34
41
|
return this.masked.has(id);
|
|
35
42
|
}
|
|
43
|
+
isMaskedContainer(id) {
|
|
44
|
+
return this.maskedContainers.has(id);
|
|
45
|
+
}
|
|
36
46
|
getInnerTextSecure(el) {
|
|
37
47
|
const id = this.app.nodes.getID(el);
|
|
38
48
|
if (!id) {
|
|
@@ -42,6 +52,7 @@ class Sanitizer {
|
|
|
42
52
|
}
|
|
43
53
|
clear() {
|
|
44
54
|
this.masked.clear();
|
|
55
|
+
this.maskedContainers.clear();
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
58
|
exports.default = Sanitizer;
|
package/cjs/app/session.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import App from "./index.js";
|
|
2
1
|
interface SessionInfo {
|
|
3
2
|
sessionID: string | null;
|
|
4
3
|
metadata: Record<string, string>;
|
|
@@ -6,20 +5,16 @@ interface SessionInfo {
|
|
|
6
5
|
}
|
|
7
6
|
declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
|
|
8
7
|
export default class Session {
|
|
9
|
-
private app;
|
|
10
8
|
private metadata;
|
|
11
9
|
private userID;
|
|
12
10
|
private sessionID;
|
|
13
|
-
private activityState;
|
|
14
11
|
private callbacks;
|
|
15
|
-
constructor(app: App);
|
|
16
12
|
attachUpdateCallback(cb: OnUpdateCallback): void;
|
|
17
13
|
private handleUpdate;
|
|
18
|
-
update(
|
|
19
|
-
private _setMetadata;
|
|
20
|
-
private _setUserID;
|
|
14
|
+
update(newInfo: Partial<SessionInfo>): void;
|
|
21
15
|
setMetadata(key: string, value: string): void;
|
|
22
16
|
setUserID(userID: string): void;
|
|
23
17
|
getInfo(): SessionInfo;
|
|
18
|
+
reset(): void;
|
|
24
19
|
}
|
|
25
20
|
export {};
|