@openreplay/tracker 6.0.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -2
- package/cjs/app/index.d.ts +1 -0
- package/cjs/app/index.js +28 -3
- package/cjs/app/observer/top_observer.js +0 -2
- package/cjs/app/sanitizer.js +5 -1
- package/cjs/index.js +1 -1
- package/cjs/modules/mouse.d.ts +7 -0
- package/cjs/modules/mouse.js +1 -1
- package/cjs/modules/network.d.ts +1 -1
- package/cjs/modules/network.js +125 -195
- package/cjs/utils.d.ts +3 -0
- package/cjs/utils.js +3 -0
- package/lib/app/index.d.ts +1 -0
- package/lib/app/index.js +28 -3
- package/lib/app/observer/top_observer.js +0 -2
- package/lib/app/sanitizer.js +5 -1
- package/lib/index.js +1 -1
- package/lib/modules/mouse.d.ts +7 -0
- package/lib/modules/mouse.js +1 -1
- package/lib/modules/network.d.ts +1 -1
- package/lib/modules/network.js +125 -195
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# 7.0.0
|
|
2
2
|
|
|
3
|
-
- **[breaking]** added gzip compression
|
|
3
|
+
- **[breaking]** added gzip compression to large messages
|
|
4
|
+
- fix email regexp to significantly improve performance
|
|
5
|
+
|
|
6
|
+
# 6.0.2
|
|
7
|
+
|
|
8
|
+
- fix network tracking for same domain iframes created by js code
|
|
4
9
|
|
|
5
10
|
# 6.0.1
|
|
6
11
|
|
|
@@ -8,7 +13,7 @@
|
|
|
8
13
|
- remove useless logs
|
|
9
14
|
- tune mouse thrashing detection
|
|
10
15
|
- fix iframe handling
|
|
11
|
-
-
|
|
16
|
+
- optimise node counting for dom drop
|
|
12
17
|
|
|
13
18
|
# 6.0.0
|
|
14
19
|
|
package/cjs/app/index.d.ts
CHANGED
|
@@ -77,6 +77,7 @@ export default class App {
|
|
|
77
77
|
private readonly version;
|
|
78
78
|
private readonly worker?;
|
|
79
79
|
private compressionThreshold;
|
|
80
|
+
private restartAttempts;
|
|
80
81
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>);
|
|
81
82
|
private _debug;
|
|
82
83
|
private _usingOldFetchPlugin;
|
package/cjs/app/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const sanitizer_js_1 = require("./sanitizer.js");
|
|
|
9
9
|
const ticker_js_1 = require("./ticker.js");
|
|
10
10
|
const logger_js_1 = require("./logger.js");
|
|
11
11
|
const session_js_1 = require("./session.js");
|
|
12
|
-
|
|
12
|
+
const fflate_1 = require("fflate");
|
|
13
13
|
const performance_js_1 = require("../modules/performance.js");
|
|
14
14
|
const CANCELED = 'canceled';
|
|
15
15
|
const START_ERROR = ':(';
|
|
@@ -34,8 +34,9 @@ class App {
|
|
|
34
34
|
this.stopCallbacks = [];
|
|
35
35
|
this.commitCallbacks = [];
|
|
36
36
|
this.activityState = ActivityState.NotActive;
|
|
37
|
-
this.version = '
|
|
37
|
+
this.version = '7.0.0'; // TODO: version compatability check inside each plugin.
|
|
38
38
|
this.compressionThreshold = 24 * 1000;
|
|
39
|
+
this.restartAttempts = 0;
|
|
39
40
|
this._usingOldFetchPlugin = false;
|
|
40
41
|
this.delay = 0;
|
|
41
42
|
this.projectKey = projectKey;
|
|
@@ -80,11 +81,12 @@ class App {
|
|
|
80
81
|
this.session.applySessionHash(sessionToken);
|
|
81
82
|
}
|
|
82
83
|
try {
|
|
83
|
-
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{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,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}sendNext(){const t=this.queue.shift();t?this.sendBatch(t):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)})}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,h=0,r=0;r!==i;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class s extends class{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const s=i.encode(t),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 17:return this.uint(t[1])&&this.string(t[2]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 20:return this.uint(t[1])&&this.uint(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 114:case 115:return this.uint(t[1]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,h){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){this.isEmpty||(this.onBatch(this.encoder.flush()),this.prepare())}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(h||(h={}));let r=null,u=null;function a(){u&&u.finaliseBatch()}function c(){h.Stopping,null!==l&&(clearInterval(l),l=null),u&&(u.clean(),u=null),r&&(r.clean(),r=null),h.NotActive}function o(){postMessage("restart"),c()}h.NotActive;let g,l=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),void c();if(!Array.isArray(i))return"start"===i.type?(h.Starting,r=new t(i.ingestPoint,()=>{o()},t=>{!function(t){postMessage({type:"failure",reason:t}),c()}(t)},i.connAttemptCount,i.connAttemptGap),u=new n(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t)),null===l&&(l=setInterval(a,1e4)),h.Active):"auth"===i.type?r?u?(r.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void o()):(console.debug("WebWorker: sender not initialised. Received auth."),void o()):void 0;if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>o(),18e5):clearTimeout(g)),t.writeMessage(i)})}u||(postMessage("not_init"),o())}else a()};'], { type: 'text/javascript' })));
|
|
84
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3,h){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.isCompressing=!1,this.ingestURL=t+"/v1/web/i",void 0!==h&&(this.isCompressing=!0)}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t))}sendNext(){const t=this.queue.shift();t?(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t)):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};i&&(s["Content-Encoding"]="gzip"),null!==this.token?fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)}):setTimeout(()=>{this.sendBatch(t,i)},500)}sendCompressed(t){this.sendBatch(t,!0)}sendUncompressed(t){this.sendBatch(t,!1)}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,h=0,r=0;r!==i;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class s extends class{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const s=i.encode(t),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 17:return this.uint(t[1])&&this.string(t[2]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 20:return this.uint(t[1])&&this.uint(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 114:case 115:return this.uint(t[1]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,h){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){this.isEmpty||(this.onBatch(this.encoder.flush()),this.prepare())}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(h||(h={}));let r=null,u=null;function a(){u&&u.finaliseBatch()}function o(){h.Stopping,null!==p&&(clearInterval(p),p=null),u&&(u.clean(),u=null),r&&(r.clean(),r=null),h.NotActive}function c(){postMessage("restart"),o()}h.NotActive;let g,p=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),void o();if(!Array.isArray(i)){if("compressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Compressed batch."),void c();r.sendCompressed(i.batch)}if("uncompressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Uncompressed batch."),void c();r.sendUncompressed(i.batch)}return"start"===i.type?(h.Starting,r=new t(i.ingestPoint,()=>{c()},t=>{!function(t){postMessage({type:"failure",reason:t}),o()}(t)},i.connAttemptCount,i.connAttemptGap,t=>{postMessage({type:"compress",batch:t},[t.buffer])}),u=new n(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t)),null===p&&(p=setInterval(a,1e4)),h.Active):"auth"===i.type?r?u?(r.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void c()):(console.debug("WebWorker: sender not initialised. Received auth."),void c()):void 0}if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>c(),18e5):clearTimeout(g)),t.writeMessage(i)})}u||(postMessage("not_init"),c())}else a()};'], { type: 'text/javascript' })));
|
|
84
85
|
this.worker.onerror = (e) => {
|
|
85
86
|
this._debug('webworker_error', e);
|
|
86
87
|
};
|
|
87
88
|
this.worker.onmessage = ({ data }) => {
|
|
89
|
+
var _a;
|
|
88
90
|
if (data === 'restart') {
|
|
89
91
|
this.stop(false);
|
|
90
92
|
void this.start({}, true);
|
|
@@ -96,6 +98,28 @@ class App {
|
|
|
96
98
|
this.stop(false);
|
|
97
99
|
this._debug('worker_failed', data.reason);
|
|
98
100
|
}
|
|
101
|
+
else if (data.type === 'compress') {
|
|
102
|
+
const batch = data.batch;
|
|
103
|
+
const batchSize = batch.byteLength;
|
|
104
|
+
if (batchSize > this.compressionThreshold) {
|
|
105
|
+
(0, fflate_1.gzip)(data.batch, { mtime: 0 }, (err, result) => {
|
|
106
|
+
var _a;
|
|
107
|
+
if (err) {
|
|
108
|
+
console.error('Openreplay compression error:', err);
|
|
109
|
+
this.stop(false);
|
|
110
|
+
if (this.restartAttempts < 3) {
|
|
111
|
+
this.restartAttempts += 1;
|
|
112
|
+
void this.start({}, true);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'compressed', batch: result });
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'uncompressed', batch: batch });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
99
123
|
};
|
|
100
124
|
const alertWorker = () => {
|
|
101
125
|
if (this.worker) {
|
|
@@ -393,6 +417,7 @@ class App {
|
|
|
393
417
|
if (typeof this.options.onStart === 'function') {
|
|
394
418
|
this.options.onStart(onStartInfo);
|
|
395
419
|
}
|
|
420
|
+
this.restartAttempts = 0;
|
|
396
421
|
return SuccessfulStart(onStartInfo);
|
|
397
422
|
})
|
|
398
423
|
.catch((reason) => {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const observer_js_1 = require("./observer.js");
|
|
4
4
|
const guards_js_1 = require("../guards.js");
|
|
5
|
-
const network_js_1 = require("../../modules/network.js");
|
|
6
5
|
const iframe_observer_js_1 = require("./iframe_observer.js");
|
|
7
6
|
const shadow_root_observer_js_1 = require("./shadow_root_observer.js");
|
|
8
7
|
const iframe_offsets_js_1 = require("./iframe_offsets.js");
|
|
@@ -70,7 +69,6 @@ class TopObserver extends observer_js_1.default {
|
|
|
70
69
|
//TODO: more explicit logic
|
|
71
70
|
) {
|
|
72
71
|
this.contextsSet.add(currentWin);
|
|
73
|
-
(0, network_js_1.default)(this.app, this.app.networkOptions, currentWin);
|
|
74
72
|
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
|
75
73
|
this.contextCallbacks.forEach((cb) => cb(currentWin));
|
|
76
74
|
}
|
package/cjs/app/sanitizer.js
CHANGED
|
@@ -51,7 +51,11 @@ class Sanitizer {
|
|
|
51
51
|
data = data.replace(/\d/g, '0');
|
|
52
52
|
}
|
|
53
53
|
if (this.options.obscureTextEmails) {
|
|
54
|
-
data = data.replace(
|
|
54
|
+
data = data.replace(/^\w+([.-]\w+)*@\w+([.-]\w+)*\.\w{2,3}$/g, (email) => {
|
|
55
|
+
const [name, domain] = email.split('@');
|
|
56
|
+
const [domainName, host] = domain.split('.');
|
|
57
|
+
return `${(0, utils_js_1.stars)(name)}@${(0, utils_js_1.stars)(domainName)}.${(0, utils_js_1.stars)(host)}`;
|
|
58
|
+
});
|
|
55
59
|
}
|
|
56
60
|
return data;
|
|
57
61
|
}
|
package/cjs/index.js
CHANGED
|
@@ -142,7 +142,7 @@ class API {
|
|
|
142
142
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
143
143
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
144
144
|
req.send(JSON.stringify({
|
|
145
|
-
trackerVersion: '
|
|
145
|
+
trackerVersion: '7.0.0',
|
|
146
146
|
projectKey: options.projectKey,
|
|
147
147
|
doNotTrack,
|
|
148
148
|
// TODO: add precise reason (an exact API missing)
|
package/cjs/modules/mouse.d.ts
CHANGED
|
@@ -20,5 +20,12 @@ export interface MouseHandlerOptions {
|
|
|
20
20
|
* default 10_000
|
|
21
21
|
* */
|
|
22
22
|
maxOptimiseTries?: number;
|
|
23
|
+
/**
|
|
24
|
+
* how many ticks to wait before capturing mouse position
|
|
25
|
+
* (can affect performance)
|
|
26
|
+
* 1 tick = 30ms
|
|
27
|
+
* default 7
|
|
28
|
+
* */
|
|
29
|
+
trackingOffset?: number;
|
|
23
30
|
}
|
|
24
31
|
export default function (app: App, options?: MouseHandlerOptions): void;
|
package/cjs/modules/mouse.js
CHANGED
|
@@ -177,6 +177,6 @@ function default_1(app, options) {
|
|
|
177
177
|
}
|
|
178
178
|
});
|
|
179
179
|
patchDocument(document, true);
|
|
180
|
-
app.ticker.attach(sendMouseMove,
|
|
180
|
+
app.ticker.attach(sendMouseMove, (options === null || options === void 0 ? void 0 : options.trackingOffset) || 7);
|
|
181
181
|
}
|
|
182
182
|
exports.default = default_1;
|
package/cjs/modules/network.d.ts
CHANGED
|
@@ -24,5 +24,5 @@ export interface Options {
|
|
|
24
24
|
capturePayload: boolean;
|
|
25
25
|
sanitizer?: Sanitizer;
|
|
26
26
|
}
|
|
27
|
-
export default function (app: App, opts?: Partial<Options
|
|
27
|
+
export default function (app: App, opts?: Partial<Options>): void;
|
|
28
28
|
export {};
|
package/cjs/modules/network.js
CHANGED
|
@@ -2,43 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
4
4
|
const utils_js_1 = require("../utils.js");
|
|
5
|
-
// Request:
|
|
6
|
-
// declare const enum BodyType {
|
|
7
|
-
// Blob = "Blob",
|
|
8
|
-
// ArrayBuffer = "ArrayBuffer",
|
|
9
|
-
// TypedArray = "TypedArray",
|
|
10
|
-
// DataView = "DataView",
|
|
11
|
-
// FormData = "FormData",
|
|
12
|
-
// URLSearchParams = "URLSearchParams",
|
|
13
|
-
// Document = "Document", // XHR only
|
|
14
|
-
// ReadableStream = "ReadableStream", // Fetch only
|
|
15
|
-
// Literal = "literal",
|
|
16
|
-
// Unknown = "unk",
|
|
17
|
-
// }
|
|
18
|
-
// XHRResponse body: ArrayBuffer, a Blob, a Document, a JavaScript Object, or a string
|
|
19
|
-
// TODO: extract maximum of useful information from any type of Request/Responce bodies
|
|
20
|
-
// function objectifyBody(body: any): RequestBody {
|
|
21
|
-
// if (body instanceof Blob) {
|
|
22
|
-
// return {
|
|
23
|
-
// body: `<Blob type: ${body.type}>; size: ${body.size}`,
|
|
24
|
-
// bodyType: BodyType.Blob,
|
|
25
|
-
// }
|
|
26
|
-
// }
|
|
27
|
-
// return {
|
|
28
|
-
// body,
|
|
29
|
-
// bodyType: BodyType.Literal,
|
|
30
|
-
// }
|
|
31
|
-
// }
|
|
32
|
-
function checkCacheByPerformanceTimings(requestUrl) {
|
|
33
|
-
if (performance) {
|
|
34
|
-
const timings = performance.getEntriesByName(requestUrl)[0];
|
|
35
|
-
if (timings) {
|
|
36
|
-
// @ts-ignore - weird ts typings, please refer to https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
|
|
37
|
-
return timings.transferSize === 0 || timings.responseStart - timings.requestStart < 10;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
5
|
function getXHRRequestDataObject(xhr) {
|
|
43
6
|
// @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
|
|
44
7
|
if (!xhr.__or_req_data__) {
|
|
@@ -51,7 +14,7 @@ function getXHRRequestDataObject(xhr) {
|
|
|
51
14
|
function strMethod(method) {
|
|
52
15
|
return typeof method === 'string' ? method.toUpperCase() : 'GET';
|
|
53
16
|
}
|
|
54
|
-
function default_1(app, opts = {}
|
|
17
|
+
function default_1(app, opts = {}) {
|
|
55
18
|
const options = Object.assign({
|
|
56
19
|
failuresOnly: false,
|
|
57
20
|
ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
|
|
@@ -101,182 +64,149 @@ function default_1(app, opts = {}, customEnv) {
|
|
|
101
64
|
}
|
|
102
65
|
return JSON.stringify(r);
|
|
103
66
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return origFetch(input, init);
|
|
111
|
-
}
|
|
112
|
-
setSessionTokenHeader(function (name, value) {
|
|
113
|
-
if (init.headers === undefined) {
|
|
114
|
-
init.headers = {};
|
|
115
|
-
}
|
|
116
|
-
if (init.headers instanceof Headers) {
|
|
117
|
-
init.headers.append(name, value);
|
|
118
|
-
}
|
|
119
|
-
else if (Array.isArray(init.headers)) {
|
|
120
|
-
init.headers.push([name, value]);
|
|
67
|
+
const patchWindow = (context) => {
|
|
68
|
+
/* ====== Fetch ====== */
|
|
69
|
+
const origFetch = context.fetch.bind(context);
|
|
70
|
+
const trackFetch = (input, init = {}) => {
|
|
71
|
+
if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
|
|
72
|
+
return origFetch(input, init);
|
|
121
73
|
}
|
|
122
|
-
|
|
123
|
-
init.headers
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
74
|
+
setSessionTokenHeader(function (name, value) {
|
|
75
|
+
if (init.headers === undefined) {
|
|
76
|
+
init.headers = {};
|
|
77
|
+
}
|
|
78
|
+
if (init.headers instanceof Headers) {
|
|
79
|
+
init.headers.append(name, value);
|
|
80
|
+
}
|
|
81
|
+
else if (Array.isArray(init.headers)) {
|
|
82
|
+
init.headers.push([name, value]);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
init.headers[name] = value;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const startTime = performance.now();
|
|
89
|
+
return origFetch(input, init).then((response) => {
|
|
90
|
+
const duration = performance.now() - startTime;
|
|
91
|
+
if (options.failuresOnly && response.status < 400) {
|
|
92
|
+
return response;
|
|
93
|
+
}
|
|
94
|
+
const r = response.clone();
|
|
95
|
+
r.text()
|
|
96
|
+
.then((text) => {
|
|
97
|
+
const reqHs = {};
|
|
98
|
+
const resHs = {};
|
|
99
|
+
if (ignoreHeaders !== true) {
|
|
100
|
+
// request headers
|
|
101
|
+
const writeReqHeader = ([n, v]) => {
|
|
102
|
+
if (!isHIgnored(n)) {
|
|
103
|
+
reqHs[n] = v;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
if (init.headers instanceof Headers) {
|
|
107
|
+
init.headers.forEach((v, n) => writeReqHeader([n, v]));
|
|
142
108
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
109
|
+
else if (Array.isArray(init.headers)) {
|
|
110
|
+
init.headers.forEach(writeReqHeader);
|
|
111
|
+
}
|
|
112
|
+
else if (typeof init.headers === 'object') {
|
|
113
|
+
Object.entries(init.headers).forEach(writeReqHeader);
|
|
114
|
+
}
|
|
115
|
+
// response headers
|
|
116
|
+
r.headers.forEach((v, n) => {
|
|
117
|
+
if (!isHIgnored(n))
|
|
118
|
+
resHs[n] = v;
|
|
119
|
+
});
|
|
152
120
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
121
|
+
const method = strMethod(init.method);
|
|
122
|
+
const reqResInfo = sanitize({
|
|
123
|
+
url: String(input),
|
|
124
|
+
method,
|
|
125
|
+
status: r.status,
|
|
126
|
+
request: {
|
|
127
|
+
headers: reqHs,
|
|
128
|
+
body: init.body,
|
|
129
|
+
},
|
|
130
|
+
response: {
|
|
131
|
+
headers: resHs,
|
|
132
|
+
body: text,
|
|
133
|
+
},
|
|
157
134
|
});
|
|
158
|
-
|
|
159
|
-
|
|
135
|
+
if (!reqResInfo) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
app.send((0, messages_gen_js_1.NetworkRequest)('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
139
|
+
})
|
|
140
|
+
.catch((e) => app.debug.error('Could not process Fetch response:', e));
|
|
141
|
+
return response;
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
context.fetch = trackFetch;
|
|
145
|
+
/* ====== <> ====== */
|
|
146
|
+
/* ====== XHR ====== */
|
|
147
|
+
const nativeOpen = context.XMLHttpRequest.prototype.open;
|
|
148
|
+
function trackXMLHttpReqOpen(initMethod, url) {
|
|
149
|
+
const xhr = this;
|
|
150
|
+
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
151
|
+
let startTime = 0;
|
|
152
|
+
xhr.addEventListener('loadstart', (e) => {
|
|
153
|
+
startTime = e.timeStamp;
|
|
154
|
+
});
|
|
155
|
+
xhr.addEventListener('load', app.safe((e) => {
|
|
156
|
+
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
157
|
+
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
158
|
+
const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
|
|
159
|
+
const resHs = hString
|
|
160
|
+
? hString
|
|
161
|
+
.split('\r\n')
|
|
162
|
+
.map((h) => h.split(':'))
|
|
163
|
+
.filter((entry) => !isHIgnored(entry[0]))
|
|
164
|
+
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
165
|
+
: {};
|
|
166
|
+
const method = strMethod(initMethod);
|
|
160
167
|
const reqResInfo = sanitize({
|
|
161
|
-
url: String(
|
|
168
|
+
url: String(url),
|
|
162
169
|
method,
|
|
163
|
-
status:
|
|
170
|
+
status: xhr.status,
|
|
164
171
|
request: {
|
|
165
172
|
headers: reqHs,
|
|
166
|
-
body:
|
|
173
|
+
body: reqBody,
|
|
167
174
|
},
|
|
168
175
|
response: {
|
|
169
176
|
headers: resHs,
|
|
170
|
-
body:
|
|
177
|
+
body: xhr.response,
|
|
171
178
|
},
|
|
172
179
|
});
|
|
173
180
|
if (!reqResInfo) {
|
|
174
181
|
return;
|
|
175
182
|
}
|
|
176
|
-
app.send((0, messages_gen_js_1.NetworkRequest)('
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
};
|
|
182
|
-
if (customEnv) {
|
|
183
|
-
if ('fetch' in customEnv) {
|
|
184
|
-
customEnv.fetch = trackFetch;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
window.fetch = trackFetch;
|
|
189
|
-
}
|
|
190
|
-
/* ====== <> ====== */
|
|
191
|
-
/* ====== XHR ====== */
|
|
192
|
-
const nativeOpen = customEnv
|
|
193
|
-
? customEnv.XMLHttpRequest.prototype.open
|
|
194
|
-
: XMLHttpRequest.prototype.open;
|
|
195
|
-
function trackXMLHttpReqOpen(initMethod, url) {
|
|
196
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
197
|
-
const xhr = this;
|
|
198
|
-
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
199
|
-
let startTime = 0;
|
|
200
|
-
xhr.addEventListener('loadstart', (e) => {
|
|
201
|
-
startTime = e.timeStamp;
|
|
202
|
-
});
|
|
203
|
-
xhr.addEventListener('load', app.safe((e) => {
|
|
204
|
-
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
205
|
-
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
206
|
-
const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
|
|
207
|
-
const resHs = hString
|
|
208
|
-
? hString
|
|
209
|
-
.split('\r\n')
|
|
210
|
-
.map((h) => h.split(':'))
|
|
211
|
-
.filter((entry) => !isHIgnored(entry[0]))
|
|
212
|
-
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
213
|
-
: {};
|
|
214
|
-
const method = strMethod(initMethod);
|
|
215
|
-
const reqResInfo = sanitize({
|
|
216
|
-
url: String(url),
|
|
217
|
-
method,
|
|
218
|
-
status: xhr.status,
|
|
219
|
-
request: {
|
|
220
|
-
headers: reqHs,
|
|
221
|
-
body: reqBody,
|
|
222
|
-
},
|
|
223
|
-
response: {
|
|
224
|
-
headers: resHs,
|
|
225
|
-
body: xhr.response,
|
|
226
|
-
},
|
|
227
|
-
});
|
|
228
|
-
if (!reqResInfo) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
app.send((0, messages_gen_js_1.NetworkRequest)('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
232
|
-
}));
|
|
233
|
-
//TODO: handle error (though it has no Error API nor any useful information)
|
|
234
|
-
//xhr.addEventListener('error', (e) => {})
|
|
235
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
236
|
-
return nativeOpen.apply(this, arguments);
|
|
237
|
-
}
|
|
238
|
-
if (customEnv) {
|
|
239
|
-
if ('XMLHttpRequest' in customEnv) {
|
|
240
|
-
customEnv.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen.bind(customEnv);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
245
|
-
}
|
|
246
|
-
const nativeSend = XMLHttpRequest.prototype.send;
|
|
247
|
-
function trackXHRSend(body) {
|
|
248
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
249
|
-
const rdo = getXHRRequestDataObject(this);
|
|
250
|
-
rdo.body = body;
|
|
251
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
252
|
-
return nativeSend.apply(this, arguments);
|
|
253
|
-
}
|
|
254
|
-
if (customEnv) {
|
|
255
|
-
if ('XMLHttpRequest' in customEnv) {
|
|
256
|
-
customEnv.XMLHttpRequest.prototype.send = trackXHRSend.bind(customEnv);
|
|
183
|
+
app.send((0, messages_gen_js_1.NetworkRequest)('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
184
|
+
}));
|
|
185
|
+
//TODO: handle error (though it has no Error API nor any useful information)
|
|
186
|
+
//xhr.addEventListener('error', (e) => {})
|
|
187
|
+
return nativeOpen.apply(this, arguments);
|
|
257
188
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
const nativeSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
263
|
-
function trackSetReqHeader(name, value) {
|
|
264
|
-
if (!isHIgnored(name)) {
|
|
265
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
189
|
+
context.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
190
|
+
const nativeSend = context.XMLHttpRequest.prototype.send;
|
|
191
|
+
function trackXHRSend(body) {
|
|
266
192
|
const rdo = getXHRRequestDataObject(this);
|
|
267
|
-
rdo.
|
|
193
|
+
rdo.body = body;
|
|
194
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
195
|
+
return nativeSend.apply(this, arguments);
|
|
268
196
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
197
|
+
context.XMLHttpRequest.prototype.send = trackXHRSend;
|
|
198
|
+
const nativeSetRequestHeader = context.XMLHttpRequest.prototype.setRequestHeader;
|
|
199
|
+
function trackSetReqHeader(name, value) {
|
|
200
|
+
if (!isHIgnored(name)) {
|
|
201
|
+
const rdo = getXHRRequestDataObject(this);
|
|
202
|
+
rdo.headers[name] = value;
|
|
203
|
+
}
|
|
204
|
+
return nativeSetRequestHeader.apply(this, arguments);
|
|
275
205
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
206
|
+
context.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
|
|
207
|
+
/* ====== <> ====== */
|
|
208
|
+
};
|
|
209
|
+
patchWindow(window);
|
|
210
|
+
app.observer.attachContextCallback(app.safe(patchWindow));
|
|
281
211
|
}
|
|
282
212
|
exports.default = default_1;
|
package/cjs/utils.d.ts
CHANGED
|
@@ -12,4 +12,7 @@ export declare function deprecationWarn(nameOfFeature: string, useInstead: strin
|
|
|
12
12
|
export declare function getLabelAttribute(e: Element): string | null;
|
|
13
13
|
export declare function hasOpenreplayAttribute(e: Element, attr: string): boolean;
|
|
14
14
|
export declare function isIframeCrossdomain(e: HTMLIFrameElement): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* checks if iframe is accessible
|
|
17
|
+
**/
|
|
15
18
|
export declare function canAccessIframe(iframe: HTMLIFrameElement): boolean;
|
package/cjs/utils.js
CHANGED
package/lib/app/index.d.ts
CHANGED
|
@@ -77,6 +77,7 @@ export default class App {
|
|
|
77
77
|
private readonly version;
|
|
78
78
|
private readonly worker?;
|
|
79
79
|
private compressionThreshold;
|
|
80
|
+
private restartAttempts;
|
|
80
81
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>);
|
|
81
82
|
private _debug;
|
|
82
83
|
private _usingOldFetchPlugin;
|
package/lib/app/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import Sanitizer from './sanitizer.js';
|
|
|
6
6
|
import Ticker from './ticker.js';
|
|
7
7
|
import Logger, { LogLevel } from './logger.js';
|
|
8
8
|
import Session from './session.js';
|
|
9
|
-
|
|
9
|
+
import { gzip } from 'fflate';
|
|
10
10
|
import { deviceMemory, jsHeapSizeLimit } from '../modules/performance.js';
|
|
11
11
|
const CANCELED = 'canceled';
|
|
12
12
|
const START_ERROR = ':(';
|
|
@@ -31,8 +31,9 @@ export default class App {
|
|
|
31
31
|
this.stopCallbacks = [];
|
|
32
32
|
this.commitCallbacks = [];
|
|
33
33
|
this.activityState = ActivityState.NotActive;
|
|
34
|
-
this.version = '
|
|
34
|
+
this.version = '7.0.0'; // TODO: version compatability check inside each plugin.
|
|
35
35
|
this.compressionThreshold = 24 * 1000;
|
|
36
|
+
this.restartAttempts = 0;
|
|
36
37
|
this._usingOldFetchPlugin = false;
|
|
37
38
|
this.delay = 0;
|
|
38
39
|
this.projectKey = projectKey;
|
|
@@ -77,11 +78,12 @@ export default class App {
|
|
|
77
78
|
this.session.applySessionHash(sessionToken);
|
|
78
79
|
}
|
|
79
80
|
try {
|
|
80
|
-
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{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,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}sendNext(){const t=this.queue.shift();t?this.sendBatch(t):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)})}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,h=0,r=0;r!==i;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class s extends class{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const s=i.encode(t),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 17:return this.uint(t[1])&&this.string(t[2]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 20:return this.uint(t[1])&&this.uint(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 114:case 115:return this.uint(t[1]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,h){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){this.isEmpty||(this.onBatch(this.encoder.flush()),this.prepare())}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(h||(h={}));let r=null,u=null;function a(){u&&u.finaliseBatch()}function c(){h.Stopping,null!==l&&(clearInterval(l),l=null),u&&(u.clean(),u=null),r&&(r.clean(),r=null),h.NotActive}function o(){postMessage("restart"),c()}h.NotActive;let g,l=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),void c();if(!Array.isArray(i))return"start"===i.type?(h.Starting,r=new t(i.ingestPoint,()=>{o()},t=>{!function(t){postMessage({type:"failure",reason:t}),c()}(t)},i.connAttemptCount,i.connAttemptGap),u=new n(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t)),null===l&&(l=setInterval(a,1e4)),h.Active):"auth"===i.type?r?u?(r.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void o()):(console.debug("WebWorker: sender not initialised. Received auth."),void o()):void 0;if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>o(),18e5):clearTimeout(g)),t.writeMessage(i)})}u||(postMessage("not_init"),o())}else a()};'], { type: 'text/javascript' })));
|
|
81
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3,h){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.isCompressing=!1,this.ingestURL=t+"/v1/web/i",void 0!==h&&(this.isCompressing=!0)}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t))}sendNext(){const t=this.queue.shift();t?(this.busy=!0,this.isCompressing&&this.onCompress?this.onCompress(t):this.sendBatch(t)):this.busy=!1}retry(t,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t,i),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,i){this.busy=!0;const s={Authorization:"Bearer "+this.token};i&&(s["Content-Encoding"]="gzip"),null!==this.token?fetch(this.ingestURL,{body:t,method:"POST",headers:s,keepalive:t.length<65536}).then(s=>{if(401===s.status)return this.busy=!1,void this.onUnauthorised();s.status>=400?this.retry(t,i):(this.attemptsCount=0,this.sendNext())}).catch(s=>{console.warn("OpenReplay:",s),this.retry(t,i)}):setTimeout(()=>{this.sendBatch(t,i)},500)}sendCompressed(t){this.sendBatch(t,!0)}sendUncompressed(t){this.sendBatch(t,!1)}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,h=0,r=0;r!==i;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class s extends class{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const s=i.encode(t),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 17:return this.uint(t[1])&&this.string(t[2]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 20:return this.uint(t[1])&&this.uint(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 114:case 115:return this.uint(t[1]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,h){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){this.isEmpty||(this.onBatch(this.encoder.flush()),this.prepare())}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(h||(h={}));let r=null,u=null;function a(){u&&u.finaliseBatch()}function o(){h.Stopping,null!==p&&(clearInterval(p),p=null),u&&(u.clean(),u=null),r&&(r.clean(),r=null),h.NotActive}function c(){postMessage("restart"),o()}h.NotActive;let g,p=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),void o();if(!Array.isArray(i)){if("compressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Compressed batch."),void c();r.sendCompressed(i.batch)}if("uncompressed"===i.type){if(!r)return console.debug("WebWorker: sender not initialised. Uncompressed batch."),void c();r.sendUncompressed(i.batch)}return"start"===i.type?(h.Starting,r=new t(i.ingestPoint,()=>{c()},t=>{!function(t){postMessage({type:"failure",reason:t}),o()}(t)},i.connAttemptCount,i.connAttemptGap,t=>{postMessage({type:"compress",batch:t},[t.buffer])}),u=new n(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t)),null===p&&(p=setInterval(a,1e4)),h.Active):"auth"===i.type?r?u?(r.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void c()):(console.debug("WebWorker: sender not initialised. Received auth."),void c()):void 0}if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>c(),18e5):clearTimeout(g)),t.writeMessage(i)})}u||(postMessage("not_init"),c())}else a()};'], { type: 'text/javascript' })));
|
|
81
82
|
this.worker.onerror = (e) => {
|
|
82
83
|
this._debug('webworker_error', e);
|
|
83
84
|
};
|
|
84
85
|
this.worker.onmessage = ({ data }) => {
|
|
86
|
+
var _a;
|
|
85
87
|
if (data === 'restart') {
|
|
86
88
|
this.stop(false);
|
|
87
89
|
void this.start({}, true);
|
|
@@ -93,6 +95,28 @@ export default class App {
|
|
|
93
95
|
this.stop(false);
|
|
94
96
|
this._debug('worker_failed', data.reason);
|
|
95
97
|
}
|
|
98
|
+
else if (data.type === 'compress') {
|
|
99
|
+
const batch = data.batch;
|
|
100
|
+
const batchSize = batch.byteLength;
|
|
101
|
+
if (batchSize > this.compressionThreshold) {
|
|
102
|
+
gzip(data.batch, { mtime: 0 }, (err, result) => {
|
|
103
|
+
var _a;
|
|
104
|
+
if (err) {
|
|
105
|
+
console.error('Openreplay compression error:', err);
|
|
106
|
+
this.stop(false);
|
|
107
|
+
if (this.restartAttempts < 3) {
|
|
108
|
+
this.restartAttempts += 1;
|
|
109
|
+
void this.start({}, true);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// @ts-ignore
|
|
113
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'compressed', batch: result });
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'uncompressed', batch: batch });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
96
120
|
};
|
|
97
121
|
const alertWorker = () => {
|
|
98
122
|
if (this.worker) {
|
|
@@ -390,6 +414,7 @@ export default class App {
|
|
|
390
414
|
if (typeof this.options.onStart === 'function') {
|
|
391
415
|
this.options.onStart(onStartInfo);
|
|
392
416
|
}
|
|
417
|
+
this.restartAttempts = 0;
|
|
393
418
|
return SuccessfulStart(onStartInfo);
|
|
394
419
|
})
|
|
395
420
|
.catch((reason) => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Observer from './observer.js';
|
|
2
2
|
import { isElementNode, hasTag } from '../guards.js';
|
|
3
|
-
import Network from '../../modules/network.js';
|
|
4
3
|
import IFrameObserver from './iframe_observer.js';
|
|
5
4
|
import ShadowRootObserver from './shadow_root_observer.js';
|
|
6
5
|
import IFrameOffsets from './iframe_offsets.js';
|
|
@@ -68,7 +67,6 @@ export default class TopObserver extends Observer {
|
|
|
68
67
|
//TODO: more explicit logic
|
|
69
68
|
) {
|
|
70
69
|
this.contextsSet.add(currentWin);
|
|
71
|
-
Network(this.app, this.app.networkOptions, currentWin);
|
|
72
70
|
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
|
73
71
|
this.contextCallbacks.forEach((cb) => cb(currentWin));
|
|
74
72
|
}
|
package/lib/app/sanitizer.js
CHANGED
|
@@ -48,7 +48,11 @@ export default class Sanitizer {
|
|
|
48
48
|
data = data.replace(/\d/g, '0');
|
|
49
49
|
}
|
|
50
50
|
if (this.options.obscureTextEmails) {
|
|
51
|
-
data = data.replace(
|
|
51
|
+
data = data.replace(/^\w+([.-]\w+)*@\w+([.-]\w+)*\.\w{2,3}$/g, (email) => {
|
|
52
|
+
const [name, domain] = email.split('@');
|
|
53
|
+
const [domainName, host] = domain.split('.');
|
|
54
|
+
return `${stars(name)}@${stars(domainName)}.${stars(host)}`;
|
|
55
|
+
});
|
|
52
56
|
}
|
|
53
57
|
return data;
|
|
54
58
|
}
|
package/lib/index.js
CHANGED
|
@@ -137,7 +137,7 @@ export default class API {
|
|
|
137
137
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
138
138
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
139
139
|
req.send(JSON.stringify({
|
|
140
|
-
trackerVersion: '
|
|
140
|
+
trackerVersion: '7.0.0',
|
|
141
141
|
projectKey: options.projectKey,
|
|
142
142
|
doNotTrack,
|
|
143
143
|
// TODO: add precise reason (an exact API missing)
|
package/lib/modules/mouse.d.ts
CHANGED
|
@@ -20,5 +20,12 @@ export interface MouseHandlerOptions {
|
|
|
20
20
|
* default 10_000
|
|
21
21
|
* */
|
|
22
22
|
maxOptimiseTries?: number;
|
|
23
|
+
/**
|
|
24
|
+
* how many ticks to wait before capturing mouse position
|
|
25
|
+
* (can affect performance)
|
|
26
|
+
* 1 tick = 30ms
|
|
27
|
+
* default 7
|
|
28
|
+
* */
|
|
29
|
+
trackingOffset?: number;
|
|
23
30
|
}
|
|
24
31
|
export default function (app: App, options?: MouseHandlerOptions): void;
|
package/lib/modules/mouse.js
CHANGED
package/lib/modules/network.d.ts
CHANGED
|
@@ -24,5 +24,5 @@ export interface Options {
|
|
|
24
24
|
capturePayload: boolean;
|
|
25
25
|
sanitizer?: Sanitizer;
|
|
26
26
|
}
|
|
27
|
-
export default function (app: App, opts?: Partial<Options
|
|
27
|
+
export default function (app: App, opts?: Partial<Options>): void;
|
|
28
28
|
export {};
|
package/lib/modules/network.js
CHANGED
|
@@ -1,42 +1,5 @@
|
|
|
1
1
|
import { NetworkRequest } from '../app/messages.gen.js';
|
|
2
2
|
import { getTimeOrigin } from '../utils.js';
|
|
3
|
-
// Request:
|
|
4
|
-
// declare const enum BodyType {
|
|
5
|
-
// Blob = "Blob",
|
|
6
|
-
// ArrayBuffer = "ArrayBuffer",
|
|
7
|
-
// TypedArray = "TypedArray",
|
|
8
|
-
// DataView = "DataView",
|
|
9
|
-
// FormData = "FormData",
|
|
10
|
-
// URLSearchParams = "URLSearchParams",
|
|
11
|
-
// Document = "Document", // XHR only
|
|
12
|
-
// ReadableStream = "ReadableStream", // Fetch only
|
|
13
|
-
// Literal = "literal",
|
|
14
|
-
// Unknown = "unk",
|
|
15
|
-
// }
|
|
16
|
-
// XHRResponse body: ArrayBuffer, a Blob, a Document, a JavaScript Object, or a string
|
|
17
|
-
// TODO: extract maximum of useful information from any type of Request/Responce bodies
|
|
18
|
-
// function objectifyBody(body: any): RequestBody {
|
|
19
|
-
// if (body instanceof Blob) {
|
|
20
|
-
// return {
|
|
21
|
-
// body: `<Blob type: ${body.type}>; size: ${body.size}`,
|
|
22
|
-
// bodyType: BodyType.Blob,
|
|
23
|
-
// }
|
|
24
|
-
// }
|
|
25
|
-
// return {
|
|
26
|
-
// body,
|
|
27
|
-
// bodyType: BodyType.Literal,
|
|
28
|
-
// }
|
|
29
|
-
// }
|
|
30
|
-
function checkCacheByPerformanceTimings(requestUrl) {
|
|
31
|
-
if (performance) {
|
|
32
|
-
const timings = performance.getEntriesByName(requestUrl)[0];
|
|
33
|
-
if (timings) {
|
|
34
|
-
// @ts-ignore - weird ts typings, please refer to https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
|
|
35
|
-
return timings.transferSize === 0 || timings.responseStart - timings.requestStart < 10;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
3
|
function getXHRRequestDataObject(xhr) {
|
|
41
4
|
// @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
|
|
42
5
|
if (!xhr.__or_req_data__) {
|
|
@@ -49,7 +12,7 @@ function getXHRRequestDataObject(xhr) {
|
|
|
49
12
|
function strMethod(method) {
|
|
50
13
|
return typeof method === 'string' ? method.toUpperCase() : 'GET';
|
|
51
14
|
}
|
|
52
|
-
export default function (app, opts = {}
|
|
15
|
+
export default function (app, opts = {}) {
|
|
53
16
|
const options = Object.assign({
|
|
54
17
|
failuresOnly: false,
|
|
55
18
|
ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
|
|
@@ -99,181 +62,148 @@ export default function (app, opts = {}, customEnv) {
|
|
|
99
62
|
}
|
|
100
63
|
return JSON.stringify(r);
|
|
101
64
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return origFetch(input, init);
|
|
109
|
-
}
|
|
110
|
-
setSessionTokenHeader(function (name, value) {
|
|
111
|
-
if (init.headers === undefined) {
|
|
112
|
-
init.headers = {};
|
|
113
|
-
}
|
|
114
|
-
if (init.headers instanceof Headers) {
|
|
115
|
-
init.headers.append(name, value);
|
|
116
|
-
}
|
|
117
|
-
else if (Array.isArray(init.headers)) {
|
|
118
|
-
init.headers.push([name, value]);
|
|
65
|
+
const patchWindow = (context) => {
|
|
66
|
+
/* ====== Fetch ====== */
|
|
67
|
+
const origFetch = context.fetch.bind(context);
|
|
68
|
+
const trackFetch = (input, init = {}) => {
|
|
69
|
+
if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
|
|
70
|
+
return origFetch(input, init);
|
|
119
71
|
}
|
|
120
|
-
|
|
121
|
-
init.headers
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
72
|
+
setSessionTokenHeader(function (name, value) {
|
|
73
|
+
if (init.headers === undefined) {
|
|
74
|
+
init.headers = {};
|
|
75
|
+
}
|
|
76
|
+
if (init.headers instanceof Headers) {
|
|
77
|
+
init.headers.append(name, value);
|
|
78
|
+
}
|
|
79
|
+
else if (Array.isArray(init.headers)) {
|
|
80
|
+
init.headers.push([name, value]);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
init.headers[name] = value;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
const startTime = performance.now();
|
|
87
|
+
return origFetch(input, init).then((response) => {
|
|
88
|
+
const duration = performance.now() - startTime;
|
|
89
|
+
if (options.failuresOnly && response.status < 400) {
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
const r = response.clone();
|
|
93
|
+
r.text()
|
|
94
|
+
.then((text) => {
|
|
95
|
+
const reqHs = {};
|
|
96
|
+
const resHs = {};
|
|
97
|
+
if (ignoreHeaders !== true) {
|
|
98
|
+
// request headers
|
|
99
|
+
const writeReqHeader = ([n, v]) => {
|
|
100
|
+
if (!isHIgnored(n)) {
|
|
101
|
+
reqHs[n] = v;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
if (init.headers instanceof Headers) {
|
|
105
|
+
init.headers.forEach((v, n) => writeReqHeader([n, v]));
|
|
140
106
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
107
|
+
else if (Array.isArray(init.headers)) {
|
|
108
|
+
init.headers.forEach(writeReqHeader);
|
|
109
|
+
}
|
|
110
|
+
else if (typeof init.headers === 'object') {
|
|
111
|
+
Object.entries(init.headers).forEach(writeReqHeader);
|
|
112
|
+
}
|
|
113
|
+
// response headers
|
|
114
|
+
r.headers.forEach((v, n) => {
|
|
115
|
+
if (!isHIgnored(n))
|
|
116
|
+
resHs[n] = v;
|
|
117
|
+
});
|
|
150
118
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
119
|
+
const method = strMethod(init.method);
|
|
120
|
+
const reqResInfo = sanitize({
|
|
121
|
+
url: String(input),
|
|
122
|
+
method,
|
|
123
|
+
status: r.status,
|
|
124
|
+
request: {
|
|
125
|
+
headers: reqHs,
|
|
126
|
+
body: init.body,
|
|
127
|
+
},
|
|
128
|
+
response: {
|
|
129
|
+
headers: resHs,
|
|
130
|
+
body: text,
|
|
131
|
+
},
|
|
155
132
|
});
|
|
156
|
-
|
|
157
|
-
|
|
133
|
+
if (!reqResInfo) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
app.send(NetworkRequest('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + getTimeOrigin(), duration));
|
|
137
|
+
})
|
|
138
|
+
.catch((e) => app.debug.error('Could not process Fetch response:', e));
|
|
139
|
+
return response;
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
context.fetch = trackFetch;
|
|
143
|
+
/* ====== <> ====== */
|
|
144
|
+
/* ====== XHR ====== */
|
|
145
|
+
const nativeOpen = context.XMLHttpRequest.prototype.open;
|
|
146
|
+
function trackXMLHttpReqOpen(initMethod, url) {
|
|
147
|
+
const xhr = this;
|
|
148
|
+
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
149
|
+
let startTime = 0;
|
|
150
|
+
xhr.addEventListener('loadstart', (e) => {
|
|
151
|
+
startTime = e.timeStamp;
|
|
152
|
+
});
|
|
153
|
+
xhr.addEventListener('load', app.safe((e) => {
|
|
154
|
+
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
155
|
+
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
156
|
+
const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
|
|
157
|
+
const resHs = hString
|
|
158
|
+
? hString
|
|
159
|
+
.split('\r\n')
|
|
160
|
+
.map((h) => h.split(':'))
|
|
161
|
+
.filter((entry) => !isHIgnored(entry[0]))
|
|
162
|
+
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
163
|
+
: {};
|
|
164
|
+
const method = strMethod(initMethod);
|
|
158
165
|
const reqResInfo = sanitize({
|
|
159
|
-
url: String(
|
|
166
|
+
url: String(url),
|
|
160
167
|
method,
|
|
161
|
-
status:
|
|
168
|
+
status: xhr.status,
|
|
162
169
|
request: {
|
|
163
170
|
headers: reqHs,
|
|
164
|
-
body:
|
|
171
|
+
body: reqBody,
|
|
165
172
|
},
|
|
166
173
|
response: {
|
|
167
174
|
headers: resHs,
|
|
168
|
-
body:
|
|
175
|
+
body: xhr.response,
|
|
169
176
|
},
|
|
170
177
|
});
|
|
171
178
|
if (!reqResInfo) {
|
|
172
179
|
return;
|
|
173
180
|
}
|
|
174
|
-
app.send(NetworkRequest('
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
};
|
|
180
|
-
if (customEnv) {
|
|
181
|
-
if ('fetch' in customEnv) {
|
|
182
|
-
customEnv.fetch = trackFetch;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
window.fetch = trackFetch;
|
|
187
|
-
}
|
|
188
|
-
/* ====== <> ====== */
|
|
189
|
-
/* ====== XHR ====== */
|
|
190
|
-
const nativeOpen = customEnv
|
|
191
|
-
? customEnv.XMLHttpRequest.prototype.open
|
|
192
|
-
: XMLHttpRequest.prototype.open;
|
|
193
|
-
function trackXMLHttpReqOpen(initMethod, url) {
|
|
194
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
195
|
-
const xhr = this;
|
|
196
|
-
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
197
|
-
let startTime = 0;
|
|
198
|
-
xhr.addEventListener('loadstart', (e) => {
|
|
199
|
-
startTime = e.timeStamp;
|
|
200
|
-
});
|
|
201
|
-
xhr.addEventListener('load', app.safe((e) => {
|
|
202
|
-
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
203
|
-
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
204
|
-
const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
|
|
205
|
-
const resHs = hString
|
|
206
|
-
? hString
|
|
207
|
-
.split('\r\n')
|
|
208
|
-
.map((h) => h.split(':'))
|
|
209
|
-
.filter((entry) => !isHIgnored(entry[0]))
|
|
210
|
-
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
211
|
-
: {};
|
|
212
|
-
const method = strMethod(initMethod);
|
|
213
|
-
const reqResInfo = sanitize({
|
|
214
|
-
url: String(url),
|
|
215
|
-
method,
|
|
216
|
-
status: xhr.status,
|
|
217
|
-
request: {
|
|
218
|
-
headers: reqHs,
|
|
219
|
-
body: reqBody,
|
|
220
|
-
},
|
|
221
|
-
response: {
|
|
222
|
-
headers: resHs,
|
|
223
|
-
body: xhr.response,
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
if (!reqResInfo) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
app.send(NetworkRequest('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + getTimeOrigin(), duration));
|
|
230
|
-
}));
|
|
231
|
-
//TODO: handle error (though it has no Error API nor any useful information)
|
|
232
|
-
//xhr.addEventListener('error', (e) => {})
|
|
233
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
234
|
-
return nativeOpen.apply(this, arguments);
|
|
235
|
-
}
|
|
236
|
-
if (customEnv) {
|
|
237
|
-
if ('XMLHttpRequest' in customEnv) {
|
|
238
|
-
customEnv.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen.bind(customEnv);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
243
|
-
}
|
|
244
|
-
const nativeSend = XMLHttpRequest.prototype.send;
|
|
245
|
-
function trackXHRSend(body) {
|
|
246
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
247
|
-
const rdo = getXHRRequestDataObject(this);
|
|
248
|
-
rdo.body = body;
|
|
249
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
250
|
-
return nativeSend.apply(this, arguments);
|
|
251
|
-
}
|
|
252
|
-
if (customEnv) {
|
|
253
|
-
if ('XMLHttpRequest' in customEnv) {
|
|
254
|
-
customEnv.XMLHttpRequest.prototype.send = trackXHRSend.bind(customEnv);
|
|
181
|
+
app.send(NetworkRequest('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + getTimeOrigin(), duration));
|
|
182
|
+
}));
|
|
183
|
+
//TODO: handle error (though it has no Error API nor any useful information)
|
|
184
|
+
//xhr.addEventListener('error', (e) => {})
|
|
185
|
+
return nativeOpen.apply(this, arguments);
|
|
255
186
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
const nativeSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
261
|
-
function trackSetReqHeader(name, value) {
|
|
262
|
-
if (!isHIgnored(name)) {
|
|
263
|
-
// @ts-ignore ??? this -> XMLHttpRequest
|
|
187
|
+
context.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
188
|
+
const nativeSend = context.XMLHttpRequest.prototype.send;
|
|
189
|
+
function trackXHRSend(body) {
|
|
264
190
|
const rdo = getXHRRequestDataObject(this);
|
|
265
|
-
rdo.
|
|
191
|
+
rdo.body = body;
|
|
192
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
193
|
+
return nativeSend.apply(this, arguments);
|
|
266
194
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
195
|
+
context.XMLHttpRequest.prototype.send = trackXHRSend;
|
|
196
|
+
const nativeSetRequestHeader = context.XMLHttpRequest.prototype.setRequestHeader;
|
|
197
|
+
function trackSetReqHeader(name, value) {
|
|
198
|
+
if (!isHIgnored(name)) {
|
|
199
|
+
const rdo = getXHRRequestDataObject(this);
|
|
200
|
+
rdo.headers[name] = value;
|
|
201
|
+
}
|
|
202
|
+
return nativeSetRequestHeader.apply(this, arguments);
|
|
273
203
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
204
|
+
context.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
|
|
205
|
+
/* ====== <> ====== */
|
|
206
|
+
};
|
|
207
|
+
patchWindow(window);
|
|
208
|
+
app.observer.attachContextCallback(app.safe(patchWindow));
|
|
279
209
|
}
|
package/lib/utils.d.ts
CHANGED
|
@@ -12,4 +12,7 @@ export declare function deprecationWarn(nameOfFeature: string, useInstead: strin
|
|
|
12
12
|
export declare function getLabelAttribute(e: Element): string | null;
|
|
13
13
|
export declare function hasOpenreplayAttribute(e: Element, attr: string): boolean;
|
|
14
14
|
export declare function isIframeCrossdomain(e: HTMLIFrameElement): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* checks if iframe is accessible
|
|
17
|
+
**/
|
|
15
18
|
export declare function canAccessIframe(iframe: HTMLIFrameElement): boolean;
|
package/lib/utils.js
CHANGED