@openreplay/tracker 3.6.3 → 3.6.5
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/.eslintignore +8 -0
- package/cjs/app/guards.js +1 -2
- package/cjs/app/index.d.ts +15 -13
- package/cjs/app/index.js +56 -40
- package/cjs/app/logger.js +6 -3
- package/cjs/app/observer/iframe_observer.d.ts +1 -1
- package/cjs/app/observer/iframe_observer.js +1 -1
- package/cjs/app/observer/observer.d.ts +2 -3
- package/cjs/app/observer/observer.js +38 -40
- package/cjs/app/observer/shadow_root_observer.d.ts +1 -1
- package/cjs/app/observer/shadow_root_observer.js +1 -1
- package/cjs/app/observer/top_observer.d.ts +2 -2
- package/cjs/app/observer/top_observer.js +12 -11
- package/cjs/app/sanitizer.d.ts +1 -1
- package/cjs/app/sanitizer.js +5 -5
- package/cjs/app/session.d.ts +14 -2
- package/cjs/app/session.js +19 -6
- package/cjs/app/ticker.d.ts +1 -1
- package/cjs/common/messages.d.ts +1 -1
- package/cjs/common/messages.js +69 -120
- package/cjs/common/webworker.d.ts +3 -3
- package/cjs/index.d.ts +9 -8
- package/cjs/index.js +34 -28
- package/cjs/modules/connection.d.ts +1 -1
- package/cjs/modules/console.d.ts +1 -1
- package/cjs/modules/console.js +5 -5
- package/cjs/modules/cssrules.d.ts +1 -1
- package/cjs/modules/cssrules.js +3 -3
- package/cjs/modules/exception.d.ts +2 -2
- package/cjs/modules/exception.js +7 -6
- package/cjs/modules/img.d.ts +1 -1
- package/cjs/modules/img.js +15 -12
- package/cjs/modules/input.d.ts +1 -1
- package/cjs/modules/input.js +15 -15
- package/cjs/modules/longtasks.d.ts +1 -1
- package/cjs/modules/longtasks.js +13 -5
- package/cjs/modules/mouse.d.ts +1 -1
- package/cjs/modules/mouse.js +10 -12
- package/cjs/modules/performance.d.ts +1 -1
- package/cjs/modules/scroll.d.ts +1 -1
- package/cjs/modules/timing.d.ts +1 -1
- package/cjs/modules/timing.js +12 -24
- package/cjs/modules/viewport.d.ts +1 -1
- package/cjs/utils.js +7 -7
- package/cjs/vendors/finder/finder.js +53 -48
- package/lib/app/guards.js +1 -2
- package/lib/app/index.d.ts +15 -13
- package/lib/app/index.js +65 -49
- package/lib/app/logger.js +6 -3
- package/lib/app/observer/iframe_observer.d.ts +1 -1
- package/lib/app/observer/iframe_observer.js +3 -3
- package/lib/app/observer/observer.d.ts +2 -3
- package/lib/app/observer/observer.js +40 -42
- package/lib/app/observer/shadow_root_observer.d.ts +1 -1
- package/lib/app/observer/shadow_root_observer.js +3 -3
- package/lib/app/observer/top_observer.d.ts +2 -2
- package/lib/app/observer/top_observer.js +17 -16
- package/lib/app/sanitizer.d.ts +1 -1
- package/lib/app/sanitizer.js +7 -7
- package/lib/app/session.d.ts +14 -2
- package/lib/app/session.js +19 -6
- package/lib/app/ticker.d.ts +1 -1
- package/lib/common/messages.d.ts +1 -1
- package/lib/common/messages.js +69 -120
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/common/webworker.d.ts +3 -3
- package/lib/index.d.ts +9 -8
- package/lib/index.js +49 -43
- package/lib/modules/connection.d.ts +1 -1
- package/lib/modules/connection.js +1 -1
- package/lib/modules/console.d.ts +1 -1
- package/lib/modules/console.js +8 -8
- package/lib/modules/cssrules.d.ts +1 -1
- package/lib/modules/cssrules.js +5 -5
- package/lib/modules/exception.d.ts +2 -2
- package/lib/modules/exception.js +8 -7
- package/lib/modules/img.d.ts +1 -1
- package/lib/modules/img.js +18 -15
- package/lib/modules/input.d.ts +1 -1
- package/lib/modules/input.js +18 -18
- package/lib/modules/longtasks.d.ts +1 -1
- package/lib/modules/longtasks.js +14 -6
- package/lib/modules/mouse.d.ts +1 -1
- package/lib/modules/mouse.js +14 -16
- package/lib/modules/performance.d.ts +1 -1
- package/lib/modules/performance.js +2 -2
- package/lib/modules/scroll.d.ts +1 -1
- package/lib/modules/scroll.js +2 -2
- package/lib/modules/timing.d.ts +1 -1
- package/lib/modules/timing.js +15 -27
- package/lib/modules/viewport.d.ts +1 -1
- package/lib/modules/viewport.js +1 -1
- package/lib/utils.js +7 -7
- package/lib/vendors/finder/finder.js +53 -48
- package/package.json +28 -10
package/lib/app/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Timestamp, Metadata, UserID } from
|
|
2
|
-
import { timestamp } from
|
|
3
|
-
import Nodes from
|
|
4
|
-
import Observer from
|
|
5
|
-
import Sanitizer from
|
|
6
|
-
import Ticker from
|
|
7
|
-
import Logger, { LogLevel } from
|
|
8
|
-
import Session from
|
|
9
|
-
import { deviceMemory, jsHeapSizeLimit } from
|
|
10
|
-
const CANCELED =
|
|
11
|
-
const START_ERROR =
|
|
1
|
+
import { Timestamp, Metadata, UserID } from '../common/messages.js';
|
|
2
|
+
import { timestamp } from '../utils.js';
|
|
3
|
+
import Nodes from './nodes.js';
|
|
4
|
+
import Observer from './observer/top_observer.js';
|
|
5
|
+
import Sanitizer from './sanitizer.js';
|
|
6
|
+
import Ticker from './ticker.js';
|
|
7
|
+
import Logger, { LogLevel } from './logger.js';
|
|
8
|
+
import Session from './session.js';
|
|
9
|
+
import { deviceMemory, jsHeapSizeLimit } from '../modules/performance.js';
|
|
10
|
+
const CANCELED = 'canceled';
|
|
11
|
+
const START_ERROR = ':(';
|
|
12
12
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
13
13
|
const SuccessfulStart = (body) => (Object.assign(Object.assign({}, body), { success: true }));
|
|
14
14
|
var ActivityState;
|
|
@@ -29,7 +29,7 @@ export default class App {
|
|
|
29
29
|
this.stopCallbacks = [];
|
|
30
30
|
this.commitCallbacks = [];
|
|
31
31
|
this.activityState = ActivityState.NotActive;
|
|
32
|
-
this.version = '3.6.
|
|
32
|
+
this.version = '3.6.4'; // TODO: version compatability check inside each plugin.
|
|
33
33
|
this.projectKey = projectKey;
|
|
34
34
|
this.options = Object.assign({
|
|
35
35
|
revID: '',
|
|
@@ -54,9 +54,10 @@ export default class App {
|
|
|
54
54
|
this.ticker.attach(() => this.commit());
|
|
55
55
|
this.debug = new Logger(this.options.__debug__);
|
|
56
56
|
this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent);
|
|
57
|
-
this.session = new Session();
|
|
57
|
+
this.session = new Session(this, this.options);
|
|
58
58
|
this.session.attachUpdateCallback(({ userID, metadata }) => {
|
|
59
|
-
if (userID != null) {
|
|
59
|
+
if (userID != null) {
|
|
60
|
+
// TODO: nullable userID
|
|
60
61
|
this.send(new UserID(userID));
|
|
61
62
|
}
|
|
62
63
|
if (metadata != null) {
|
|
@@ -69,17 +70,16 @@ export default class App {
|
|
|
69
70
|
this.sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
70
71
|
}
|
|
71
72
|
try {
|
|
72
|
-
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;function ht(){rt&&rt.finaliseBatch()}function ot(){et.Stopping,null!==at&&(clearInterval(at),at=null),rt&&(rt.clean(),rt=null),et.NotActive}et.NotActive;let ct,at=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return ht(),void ot();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?ct=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ct)),s.writeMessage(e)})}else{if("start"===t.type)return et.Starting,nt=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{nt&&(nt.clean(),nt=null),ot(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),rt=new st(t.pageNo,t.timestamp,t=>nt&&nt.push(t)),null===at&&(at=setInterval(ht,1e4)),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 ht()};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this._debug("webworker_error", e);
|
|
73
|
+
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(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 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;function ht(){rt&&rt.finaliseBatch()}function ot(){et.Stopping,null!==at&&(clearInterval(at),at=null),rt&&(rt.clean(),rt=null),et.NotActive}et.NotActive;let ct,at=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return ht(),void ot();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?ct=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ct)),s.writeMessage(e)})}else{if("start"===t.type)return et.Starting,nt=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{nt&&(nt.clean(),nt=null),ot(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),rt=new st(t.pageNo,t.timestamp,t=>nt&&nt.push(t)),null===at&&(at=setInterval(ht,1e4)),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 ht()};'], { type: 'text/javascript' })));
|
|
74
|
+
this.worker.onerror = (e) => {
|
|
75
|
+
this._debug('webworker_error', e);
|
|
76
76
|
};
|
|
77
77
|
this.worker.onmessage = ({ data }) => {
|
|
78
|
-
if (data ===
|
|
78
|
+
if (data === 'failed') {
|
|
79
79
|
this.stop();
|
|
80
|
-
this._debug(
|
|
80
|
+
this._debug('worker_failed', {}); // add context (from worker)
|
|
81
81
|
}
|
|
82
|
-
else if (data ===
|
|
82
|
+
else if (data === 'restart') {
|
|
83
83
|
this.stop();
|
|
84
84
|
this.start({ forceNew: true });
|
|
85
85
|
}
|
|
@@ -96,7 +96,7 @@ export default class App {
|
|
|
96
96
|
this.attachEventListener(document, 'visibilitychange', alertWorker, false);
|
|
97
97
|
}
|
|
98
98
|
catch (e) {
|
|
99
|
-
this._debug(
|
|
99
|
+
this._debug('worker_start', e);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
_debug(context, e) {
|
|
@@ -106,11 +106,11 @@ export default class App {
|
|
|
106
106
|
headers: { 'Content-Type': 'application/json' },
|
|
107
107
|
body: JSON.stringify({
|
|
108
108
|
context,
|
|
109
|
-
error: `${e}
|
|
110
|
-
})
|
|
109
|
+
error: `${e}`,
|
|
110
|
+
}),
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
|
-
this.debug.error(
|
|
113
|
+
this.debug.error('OpenReplay error: ', context, e);
|
|
114
114
|
}
|
|
115
115
|
send(message, urgent = false) {
|
|
116
116
|
if (this.activityState === ActivityState.NotActive) {
|
|
@@ -129,7 +129,7 @@ export default class App {
|
|
|
129
129
|
if (this.worker && this.messages.length) {
|
|
130
130
|
this.messages.unshift(new Timestamp(timestamp()));
|
|
131
131
|
this.worker.postMessage(this.messages);
|
|
132
|
-
this.commitCallbacks.forEach(cb => cb(this.messages));
|
|
132
|
+
this.commitCallbacks.forEach((cb) => cb(this.messages));
|
|
133
133
|
this.messages.length = 0;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -140,7 +140,7 @@ export default class App {
|
|
|
140
140
|
fn.apply(this, args);
|
|
141
141
|
}
|
|
142
142
|
catch (e) {
|
|
143
|
-
app._debug(
|
|
143
|
+
app._debug('safe_fn_call', e);
|
|
144
144
|
// time: timestamp(),
|
|
145
145
|
// name: e.name,
|
|
146
146
|
// message: e.message,
|
|
@@ -169,10 +169,13 @@ export default class App {
|
|
|
169
169
|
const reqVer = version.split(/[.-]/);
|
|
170
170
|
const ver = this.version.split(/[.-]/);
|
|
171
171
|
for (let i = 0; i < 3; i++) {
|
|
172
|
+
if (isNaN(Number(ver[i])) || isNaN(Number(reqVer[i]))) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
172
175
|
if (Number(ver[i]) > Number(reqVer[i])) {
|
|
173
176
|
return true;
|
|
174
177
|
}
|
|
175
|
-
if (Number(ver[i]) < Number(reqVer[i])
|
|
178
|
+
if (Number(ver[i]) < Number(reqVer[i])) {
|
|
176
179
|
return false;
|
|
177
180
|
}
|
|
178
181
|
}
|
|
@@ -200,6 +203,14 @@ export default class App {
|
|
|
200
203
|
getSessionID() {
|
|
201
204
|
return this.session.getInfo().sessionID || undefined;
|
|
202
205
|
}
|
|
206
|
+
getSessionURL() {
|
|
207
|
+
const { projectID, sessionID } = this.session.getInfo();
|
|
208
|
+
if (!projectID || !sessionID) {
|
|
209
|
+
this.debug.error('OpenReplay error: Unable to build session URL');
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
return this.options.ingestPoint.replace(/ingest$/, `${projectID}/session/${sessionID}`);
|
|
213
|
+
}
|
|
203
214
|
getHost() {
|
|
204
215
|
return new URL(this.options.ingestPoint).hostname;
|
|
205
216
|
}
|
|
@@ -218,12 +229,13 @@ export default class App {
|
|
|
218
229
|
return document.baseURI;
|
|
219
230
|
}
|
|
220
231
|
// IE only
|
|
221
|
-
return ((_b = (_a = document.head) === null || _a === void 0 ? void 0 : _a.getElementsByTagName(
|
|
232
|
+
return (((_b = (_a = document.head) === null || _a === void 0 ? void 0 : _a.getElementsByTagName('base')[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('href')) ||
|
|
233
|
+
location.origin + location.pathname);
|
|
222
234
|
}
|
|
223
235
|
resolveResourceURL(resourceURL) {
|
|
224
236
|
const base = new URL(this.getBaseHref());
|
|
225
|
-
base.pathname +=
|
|
226
|
-
base.pathname.replace(/\/+/g,
|
|
237
|
+
base.pathname += '/' + new URL(resourceURL).pathname;
|
|
238
|
+
base.pathname.replace(/\/+/g, '/');
|
|
227
239
|
return base.toString();
|
|
228
240
|
}
|
|
229
241
|
isServiceURL(url) {
|
|
@@ -242,10 +254,10 @@ export default class App {
|
|
|
242
254
|
}
|
|
243
255
|
_start(startOpts) {
|
|
244
256
|
if (!this.worker) {
|
|
245
|
-
return Promise.resolve(UnsuccessfulStart(
|
|
257
|
+
return Promise.resolve(UnsuccessfulStart('No worker found: perhaps, CSP is not set.'));
|
|
246
258
|
}
|
|
247
259
|
if (this.activityState !== ActivityState.NotActive) {
|
|
248
|
-
return Promise.resolve(UnsuccessfulStart(
|
|
260
|
+
return Promise.resolve(UnsuccessfulStart('OpenReplay: trying to call `start()` on the instance that has been started already.'));
|
|
249
261
|
}
|
|
250
262
|
this.activityState = ActivityState.Starting;
|
|
251
263
|
let pageNo = 0;
|
|
@@ -257,7 +269,7 @@ export default class App {
|
|
|
257
269
|
this.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
258
270
|
const startInfo = this.getStartInfo();
|
|
259
271
|
const startWorkerMsg = {
|
|
260
|
-
type:
|
|
272
|
+
type: 'start',
|
|
261
273
|
pageNo,
|
|
262
274
|
ingestPoint: this.options.ingestPoint,
|
|
263
275
|
timestamp: startInfo.timestamp,
|
|
@@ -266,6 +278,7 @@ export default class App {
|
|
|
266
278
|
};
|
|
267
279
|
this.worker.postMessage(startWorkerMsg);
|
|
268
280
|
this.session.update({
|
|
281
|
+
// TODO: transparent "session" module logic AND explicit internal api for plugins.
|
|
269
282
|
// "updating" with old metadata in order to trigger session's UpdateCallbacks.
|
|
270
283
|
// (for the case of internal .start() calls, like on "restart" webworker signal or assistent connection in tracker-assist )
|
|
271
284
|
metadata: startOpts.metadata || this.session.getInfo().metadata,
|
|
@@ -273,7 +286,8 @@ export default class App {
|
|
|
273
286
|
});
|
|
274
287
|
const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
|
|
275
288
|
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
276
|
-
return window
|
|
289
|
+
return window
|
|
290
|
+
.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
277
291
|
method: 'POST',
|
|
278
292
|
headers: {
|
|
279
293
|
'Content-Type': 'application/json',
|
|
@@ -281,19 +295,21 @@ export default class App {
|
|
|
281
295
|
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: this.session.getInfo().userID, token: this.sessionStorage.getItem(this.options.session_token_key), deviceMemory,
|
|
282
296
|
jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
|
|
283
297
|
})
|
|
284
|
-
.then(r => {
|
|
298
|
+
.then((r) => {
|
|
285
299
|
if (r.status === 200) {
|
|
286
300
|
return r.json();
|
|
287
301
|
}
|
|
288
302
|
else {
|
|
289
|
-
return r
|
|
303
|
+
return r
|
|
304
|
+
.text()
|
|
305
|
+
.then((text) => text === CANCELED
|
|
290
306
|
? Promise.reject(CANCELED)
|
|
291
307
|
: Promise.reject(`Server error: ${r.status}. ${text}`));
|
|
292
308
|
}
|
|
293
309
|
})
|
|
294
|
-
.then(r => {
|
|
310
|
+
.then((r) => {
|
|
295
311
|
if (!this.worker) {
|
|
296
|
-
return Promise.reject(
|
|
312
|
+
return Promise.reject('no worker found after start request (this might not happen)');
|
|
297
313
|
}
|
|
298
314
|
const { token, userUUID, sessionID, beaconSizeLimit } = r;
|
|
299
315
|
if (typeof token !== 'string' ||
|
|
@@ -305,9 +321,9 @@ export default class App {
|
|
|
305
321
|
this.localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
306
322
|
this.session.update({ sessionID }); // TODO: no no-explicit 'any'
|
|
307
323
|
const startWorkerMsg = {
|
|
308
|
-
type:
|
|
324
|
+
type: 'auth',
|
|
309
325
|
token,
|
|
310
|
-
beaconSizeLimit
|
|
326
|
+
beaconSizeLimit,
|
|
311
327
|
};
|
|
312
328
|
this.worker.postMessage(startWorkerMsg);
|
|
313
329
|
this.activityState = ActivityState.Active;
|
|
@@ -315,21 +331,21 @@ export default class App {
|
|
|
315
331
|
this.startCallbacks.forEach((cb) => cb(onStartInfo)); // TODO: start as early as possible (before receiving the token)
|
|
316
332
|
this.observer.observe();
|
|
317
333
|
this.ticker.start();
|
|
318
|
-
this.notify.log(
|
|
334
|
+
this.notify.log('OpenReplay tracking started.');
|
|
319
335
|
// get rid of onStart ?
|
|
320
336
|
if (typeof this.options.onStart === 'function') {
|
|
321
337
|
this.options.onStart(onStartInfo);
|
|
322
338
|
}
|
|
323
339
|
return SuccessfulStart(onStartInfo);
|
|
324
340
|
})
|
|
325
|
-
.catch(reason => {
|
|
341
|
+
.catch((reason) => {
|
|
326
342
|
this.sessionStorage.removeItem(this.options.session_token_key);
|
|
327
343
|
this.stop();
|
|
328
344
|
if (reason === CANCELED) {
|
|
329
345
|
return UnsuccessfulStart(CANCELED);
|
|
330
346
|
}
|
|
331
|
-
this.notify.log(
|
|
332
|
-
this._debug(
|
|
347
|
+
this.notify.log('OpenReplay was unable to start. ', reason);
|
|
348
|
+
this._debug('session_start', reason);
|
|
333
349
|
return UnsuccessfulStart(START_ERROR);
|
|
334
350
|
});
|
|
335
351
|
}
|
|
@@ -341,11 +357,11 @@ export default class App {
|
|
|
341
357
|
return new Promise((resolve) => {
|
|
342
358
|
const onVisibilityChange = () => {
|
|
343
359
|
if (!document.hidden) {
|
|
344
|
-
document.removeEventListener(
|
|
360
|
+
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
345
361
|
resolve(this._start(options));
|
|
346
362
|
}
|
|
347
363
|
};
|
|
348
|
-
document.addEventListener(
|
|
364
|
+
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
349
365
|
});
|
|
350
366
|
}
|
|
351
367
|
}
|
|
@@ -360,9 +376,9 @@ export default class App {
|
|
|
360
376
|
if (calledFromAPI) {
|
|
361
377
|
this.session.reset();
|
|
362
378
|
}
|
|
363
|
-
this.notify.log(
|
|
379
|
+
this.notify.log('OpenReplay tracking stopped.');
|
|
364
380
|
if (this.worker && !restarting) {
|
|
365
|
-
this.worker.postMessage(
|
|
381
|
+
this.worker.postMessage('stop');
|
|
366
382
|
}
|
|
367
383
|
}
|
|
368
384
|
finally {
|
package/lib/app/logger.js
CHANGED
|
@@ -10,9 +10,12 @@ function IsCustomLevel(l) {
|
|
|
10
10
|
}
|
|
11
11
|
export default class Logger {
|
|
12
12
|
constructor(options = LogLevel.Silent) {
|
|
13
|
-
this.options =
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
this.options =
|
|
14
|
+
options === true
|
|
15
|
+
? { level: LogLevel.Verbose }
|
|
16
|
+
: typeof options === 'number'
|
|
17
|
+
? { level: options }
|
|
18
|
+
: options;
|
|
16
19
|
}
|
|
17
20
|
log(...args) {
|
|
18
21
|
if (IsCustomLevel(this.options.level)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Observer from
|
|
2
|
-
import { CreateIFrameDocument } from
|
|
1
|
+
import Observer from './observer.js';
|
|
2
|
+
import { CreateIFrameDocument } from '../../common/messages.js';
|
|
3
3
|
export default class IFrameObserver extends Observer {
|
|
4
4
|
observe(iframe) {
|
|
5
5
|
const doc = iframe.contentDocument;
|
|
@@ -10,7 +10,7 @@ export default class IFrameObserver extends Observer {
|
|
|
10
10
|
// Have to observe document, because the inner <html> might be changed
|
|
11
11
|
this.observeRoot(doc, (docID) => {
|
|
12
12
|
if (docID === undefined) {
|
|
13
|
-
console.log(
|
|
13
|
+
console.log('OpenReplay: Iframe document not bound');
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
this.app.send(CreateIFrameDocument(hostID, docID));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import App from
|
|
1
|
+
import App from '../index.js';
|
|
2
2
|
export default abstract class Observer {
|
|
3
3
|
protected readonly app: App;
|
|
4
4
|
protected readonly isTopContext: boolean;
|
|
@@ -13,9 +13,8 @@ export default abstract class Observer {
|
|
|
13
13
|
private sendNodeAttribute;
|
|
14
14
|
private sendNodeData;
|
|
15
15
|
private bindNode;
|
|
16
|
-
private unbindChildNode;
|
|
17
16
|
private bindTree;
|
|
18
|
-
private
|
|
17
|
+
private unbindTree;
|
|
19
18
|
private _commitNode;
|
|
20
19
|
private commitNode;
|
|
21
20
|
private commitNodes;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, } from
|
|
2
|
-
import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag
|
|
1
|
+
import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, } from '../../common/messages.js';
|
|
2
|
+
import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag } from '../guards.js';
|
|
3
3
|
function isIgnored(node) {
|
|
4
4
|
if (isTextNode(node)) {
|
|
5
5
|
return false;
|
|
@@ -11,13 +11,9 @@ function isIgnored(node) {
|
|
|
11
11
|
if (tag === 'LINK') {
|
|
12
12
|
const rel = node.getAttribute('rel');
|
|
13
13
|
const as = node.getAttribute('as');
|
|
14
|
-
return !((rel === null || rel === void 0 ? void 0 : rel.includes('stylesheet')) || as ===
|
|
14
|
+
return !((rel === null || rel === void 0 ? void 0 : rel.includes('stylesheet')) || as === 'style' || as === 'font');
|
|
15
15
|
}
|
|
16
|
-
return (tag === 'SCRIPT' ||
|
|
17
|
-
tag === 'NOSCRIPT' ||
|
|
18
|
-
tag === 'META' ||
|
|
19
|
-
tag === 'TITLE' ||
|
|
20
|
-
tag === 'BASE');
|
|
16
|
+
return (tag === 'SCRIPT' || tag === 'NOSCRIPT' || tag === 'META' || tag === 'TITLE' || tag === 'BASE');
|
|
21
17
|
}
|
|
22
18
|
function isObservable(node) {
|
|
23
19
|
if (isRootNode(node)) {
|
|
@@ -30,17 +26,11 @@ function isObservable(node) {
|
|
|
30
26
|
- fix unbinding logic + send all removals first (ensure sequence is correct)
|
|
31
27
|
- use document as a 0-node in the upper context (should be updated in player at first)
|
|
32
28
|
*/
|
|
33
|
-
/*
|
|
34
|
-
Nikita:
|
|
35
|
-
- rn we only send unbind event for parent (all child nodes will be cut in the live replay anyways)
|
|
36
|
-
to prevent sending 1k+ unbinds for child nodes and making replay file bigger than it should be
|
|
37
|
-
*/
|
|
38
29
|
var RecentsType;
|
|
39
30
|
(function (RecentsType) {
|
|
40
31
|
RecentsType[RecentsType["New"] = 0] = "New";
|
|
41
32
|
RecentsType[RecentsType["Removed"] = 1] = "Removed";
|
|
42
33
|
RecentsType[RecentsType["Changed"] = 2] = "Changed";
|
|
43
|
-
RecentsType[RecentsType["RemovedChild"] = 3] = "RemovedChild";
|
|
44
34
|
})(RecentsType || (RecentsType = {}));
|
|
45
35
|
export default class Observer {
|
|
46
36
|
constructor(app, isTopContext = false) {
|
|
@@ -52,7 +42,8 @@ export default class Observer {
|
|
|
52
42
|
this.attributesMap = new Map();
|
|
53
43
|
this.textSet = new Set();
|
|
54
44
|
this.observer = new MutationObserver(this.app.safe((mutations) => {
|
|
55
|
-
for (const mutation of mutations) {
|
|
45
|
+
for (const mutation of mutations) {
|
|
46
|
+
// mutations order is sequential
|
|
56
47
|
const target = mutation.target;
|
|
57
48
|
const type = mutation.type;
|
|
58
49
|
if (!isObservable(target)) {
|
|
@@ -60,7 +51,10 @@ export default class Observer {
|
|
|
60
51
|
}
|
|
61
52
|
if (type === 'childList') {
|
|
62
53
|
for (let i = 0; i < mutation.removedNodes.length; i++) {
|
|
63
|
-
|
|
54
|
+
// Should be the same as bindTree(mutation.removedNodes[i]), but logic needs to be be untied
|
|
55
|
+
if (isObservable(mutation.removedNodes[i])) {
|
|
56
|
+
this.bindNode(mutation.removedNodes[i]);
|
|
57
|
+
}
|
|
64
58
|
}
|
|
65
59
|
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
66
60
|
this.bindTree(mutation.addedNodes[i]);
|
|
@@ -81,7 +75,7 @@ export default class Observer {
|
|
|
81
75
|
}
|
|
82
76
|
let attr = this.attributesMap.get(id);
|
|
83
77
|
if (attr === undefined) {
|
|
84
|
-
this.attributesMap.set(id, attr = new Set());
|
|
78
|
+
this.attributesMap.set(id, (attr = new Set()));
|
|
85
79
|
}
|
|
86
80
|
attr.add(name);
|
|
87
81
|
continue;
|
|
@@ -129,7 +123,7 @@ export default class Observer {
|
|
|
129
123
|
return;
|
|
130
124
|
}
|
|
131
125
|
if (name === 'value' &&
|
|
132
|
-
hasTag(node,
|
|
126
|
+
hasTag(node, 'INPUT') &&
|
|
133
127
|
node.type !== 'button' &&
|
|
134
128
|
node.type !== 'reset' &&
|
|
135
129
|
node.type !== 'submit') {
|
|
@@ -139,7 +133,7 @@ export default class Observer {
|
|
|
139
133
|
this.app.send(new RemoveNodeAttribute(id, name));
|
|
140
134
|
return;
|
|
141
135
|
}
|
|
142
|
-
if (name === 'style' || name === 'href' && hasTag(node,
|
|
136
|
+
if (name === 'style' || (name === 'href' && hasTag(node, 'LINK'))) {
|
|
143
137
|
this.app.send(new SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
|
|
144
138
|
return;
|
|
145
139
|
}
|
|
@@ -149,7 +143,7 @@ export default class Observer {
|
|
|
149
143
|
this.app.send(new SetNodeAttribute(id, name, value));
|
|
150
144
|
}
|
|
151
145
|
sendNodeData(id, parentElement, data) {
|
|
152
|
-
if (hasTag(parentElement,
|
|
146
|
+
if (hasTag(parentElement, 'STYLE') || hasTag(parentElement, 'style')) {
|
|
153
147
|
this.app.send(new SetCSSDataURLBased(id, data, this.app.getBaseHref()));
|
|
154
148
|
return;
|
|
155
149
|
}
|
|
@@ -161,40 +155,43 @@ export default class Observer {
|
|
|
161
155
|
if (isNew) {
|
|
162
156
|
this.recents.set(id, RecentsType.New);
|
|
163
157
|
}
|
|
164
|
-
else if (this.recents.get(id) !== RecentsType.New) {
|
|
158
|
+
else if (this.recents.get(id) !== RecentsType.New) {
|
|
165
159
|
this.recents.set(id, RecentsType.Removed);
|
|
166
160
|
}
|
|
167
161
|
}
|
|
168
|
-
|
|
169
|
-
const [id] = this.app.nodes.registerNode(node);
|
|
170
|
-
this.recents.set(id, RecentsType.RemovedChild);
|
|
171
|
-
}
|
|
172
|
-
bindTree(node, isChildUnbinding = false) {
|
|
162
|
+
bindTree(node) {
|
|
173
163
|
if (!isObservable(node)) {
|
|
174
164
|
return;
|
|
175
165
|
}
|
|
176
166
|
this.bindNode(node);
|
|
177
167
|
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
|
|
178
|
-
acceptNode: (node) => isIgnored(node)
|
|
179
|
-
|| (this.app.nodes.getID(node) !== undefined && !isChildUnbinding)
|
|
168
|
+
acceptNode: (node) => isIgnored(node) || this.app.nodes.getID(node) !== undefined
|
|
180
169
|
? NodeFilter.FILTER_REJECT
|
|
181
170
|
: NodeFilter.FILTER_ACCEPT,
|
|
182
171
|
},
|
|
183
172
|
// @ts-ignore
|
|
184
173
|
false);
|
|
185
174
|
while (walker.nextNode()) {
|
|
186
|
-
|
|
187
|
-
this.unbindChildNode(walker.currentNode);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
this.bindNode(walker.currentNode);
|
|
191
|
-
}
|
|
175
|
+
this.bindNode(walker.currentNode);
|
|
192
176
|
}
|
|
193
177
|
}
|
|
194
|
-
|
|
178
|
+
unbindTree(node) {
|
|
195
179
|
const id = this.app.nodes.unregisterNode(node);
|
|
196
180
|
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
|
197
|
-
|
|
181
|
+
// Sending RemoveNode only for parent to maintain
|
|
182
|
+
this.app.send(RemoveNode(id));
|
|
183
|
+
// Unregistering all the children in order to clear the memory
|
|
184
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
|
|
185
|
+
acceptNode: (node) => isIgnored(node) || this.app.nodes.getID(node) === undefined
|
|
186
|
+
? NodeFilter.FILTER_REJECT
|
|
187
|
+
: NodeFilter.FILTER_ACCEPT,
|
|
188
|
+
},
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
false);
|
|
191
|
+
while (walker.nextNode()) {
|
|
192
|
+
this.app.nodes.unregisterNode(walker.currentNode);
|
|
193
|
+
}
|
|
194
|
+
// MBTODO: count and send RemovedNodesCount (for the page crash detection in heuristics)
|
|
198
195
|
}
|
|
199
196
|
}
|
|
200
197
|
// A top-consumption function on the infinite lists test. (~1% of performance resources)
|
|
@@ -207,20 +204,20 @@ export default class Observer {
|
|
|
207
204
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
208
205
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
209
206
|
// TODO: Clean the logic (though now it workd fine)
|
|
210
|
-
if (!hasTag(node,
|
|
207
|
+
if (!hasTag(node, 'HTML') || !this.isTopContext) {
|
|
211
208
|
if (parent === null) {
|
|
212
209
|
// Sometimes one observation contains attribute mutations for the removimg node, which gets ignored here.
|
|
213
|
-
// That shouldn't affect the visual rendering ( should it? )
|
|
214
|
-
this.
|
|
210
|
+
// That shouldn't affect the visual rendering ( should it? maybe when transition applied? )
|
|
211
|
+
this.unbindTree(node);
|
|
215
212
|
return false;
|
|
216
213
|
}
|
|
217
214
|
parentID = this.app.nodes.getID(parent);
|
|
218
215
|
if (parentID === undefined) {
|
|
219
|
-
this.
|
|
216
|
+
this.unbindTree(node);
|
|
220
217
|
return false;
|
|
221
218
|
}
|
|
222
219
|
if (!this.commitNode(parentID)) {
|
|
223
|
-
this.
|
|
220
|
+
this.unbindTree(node);
|
|
224
221
|
return false;
|
|
225
222
|
}
|
|
226
223
|
this.app.sanitizer.handleNode(id, parentID, node);
|
|
@@ -315,7 +312,8 @@ export default class Observer {
|
|
|
315
312
|
});
|
|
316
313
|
this.clear();
|
|
317
314
|
}
|
|
318
|
-
// ISSSUE
|
|
315
|
+
// ISSSUE (nodeToBinde should be the same as node. Look at the comment about 0-node at the beginning of the file.)
|
|
316
|
+
// TODO: use one observer instance for all iframes/shadowRoots (composition instiad of inheritance)
|
|
319
317
|
observeRoot(node, beforeCommit, nodeToBind = node) {
|
|
320
318
|
this.observer.observe(node, {
|
|
321
319
|
childList: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Observer from
|
|
2
|
-
import { CreateIFrameDocument } from
|
|
1
|
+
import Observer from './observer.js';
|
|
2
|
+
import { CreateIFrameDocument } from '../../common/messages.js';
|
|
3
3
|
export default class ShadowRootObserver extends Observer {
|
|
4
4
|
observe(el) {
|
|
5
5
|
const shRoot = el.shadowRoot;
|
|
@@ -9,7 +9,7 @@ export default class ShadowRootObserver extends Observer {
|
|
|
9
9
|
} // log
|
|
10
10
|
this.observeRoot(shRoot, (rootID) => {
|
|
11
11
|
if (rootID === undefined) {
|
|
12
|
-
console.log(
|
|
12
|
+
console.log('OpenReplay: Shadow Root was not bound');
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
this.app.send(CreateIFrameDocument(hostID, rootID));
|