@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 CHANGED
@@ -1,6 +1,11 @@
1
1
  # 7.0.0
2
2
 
3
- - **[breaking]** added gzip compression for large messages
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
- - improve node counting for dom drop
16
+ - optimise node counting for dom drop
12
17
 
13
18
  # 6.0.0
14
19
 
@@ -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
- // import { gzip } from 'fflate'
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 = '6.0.1'; // TODO: version compatability check inside each plugin.
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
  }
@@ -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(/([^\s]+)@([^\s]+)\.([^\s]+)/g, (...f) => (0, utils_js_1.stars)(f[1]) + '@' + (0, utils_js_1.stars)(f[2]) + '.' + (0, utils_js_1.stars)(f[3]));
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: '6.0.1',
145
+ trackerVersion: '7.0.0',
146
146
  projectKey: options.projectKey,
147
147
  doNotTrack,
148
148
  // TODO: add precise reason (an exact API missing)
@@ -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;
@@ -177,6 +177,6 @@ function default_1(app, options) {
177
177
  }
178
178
  });
179
179
  patchDocument(document, true);
180
- app.ticker.attach(sendMouseMove, 10);
180
+ app.ticker.attach(sendMouseMove, (options === null || options === void 0 ? void 0 : options.trackingOffset) || 7);
181
181
  }
182
182
  exports.default = default_1;
@@ -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>, customEnv?: Record<string, any>): void;
27
+ export default function (app: App, opts?: Partial<Options>): void;
28
28
  export {};
@@ -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 = {}, customEnv) {
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
- /* ====== Fetch ====== */
105
- const origFetch = customEnv
106
- ? customEnv.fetch.bind(customEnv)
107
- : window.fetch.bind(window);
108
- const trackFetch = (input, init = {}) => {
109
- if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
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
- else {
123
- init.headers[name] = value;
124
- }
125
- });
126
- const startTime = performance.now();
127
- return origFetch(input, init).then((response) => {
128
- const duration = performance.now() - startTime;
129
- if (options.failuresOnly && response.status < 400) {
130
- return response;
131
- }
132
- const r = response.clone();
133
- r.text()
134
- .then((text) => {
135
- const reqHs = {};
136
- const resHs = {};
137
- if (ignoreHeaders !== true) {
138
- // request headers
139
- const writeReqHeader = ([n, v]) => {
140
- if (!isHIgnored(n)) {
141
- reqHs[n] = v;
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
- if (init.headers instanceof Headers) {
145
- init.headers.forEach((v, n) => writeReqHeader([n, v]));
146
- }
147
- else if (Array.isArray(init.headers)) {
148
- init.headers.forEach(writeReqHeader);
149
- }
150
- else if (typeof init.headers === 'object') {
151
- Object.entries(init.headers).forEach(writeReqHeader);
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
- // response headers
154
- r.headers.forEach((v, n) => {
155
- if (!isHIgnored(n))
156
- resHs[n] = v;
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
- const method = strMethod(init.method);
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(input),
168
+ url: String(url),
162
169
  method,
163
- status: r.status,
170
+ status: xhr.status,
164
171
  request: {
165
172
  headers: reqHs,
166
- body: init.body,
173
+ body: reqBody,
167
174
  },
168
175
  response: {
169
176
  headers: resHs,
170
- body: text,
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)('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
177
- })
178
- .catch((e) => app.debug.error('Could not process Fetch response:', e));
179
- return response;
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
- else {
260
- XMLHttpRequest.prototype.send = trackXHRSend;
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.headers[name] = value;
193
+ rdo.body = body;
194
+ // @ts-ignore ??? this -> XMLHttpRequest
195
+ return nativeSend.apply(this, arguments);
268
196
  }
269
- // @ts-ignore ??? this -> XMLHttpRequest
270
- return nativeSetRequestHeader.apply(this, arguments);
271
- }
272
- if (customEnv) {
273
- if ('XMLHttpRequest' in customEnv) {
274
- customEnv.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader.bind(customEnv);
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
- else {
278
- XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
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
@@ -79,6 +79,9 @@ function isIframeCrossdomain(e) {
79
79
  }
80
80
  }
81
81
  exports.isIframeCrossdomain = isIframeCrossdomain;
82
+ /**
83
+ * checks if iframe is accessible
84
+ **/
82
85
  function canAccessIframe(iframe) {
83
86
  try {
84
87
  return Boolean(iframe.contentDocument);
@@ -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
- // import { gzip } from 'fflate'
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 = '6.0.1'; // TODO: version compatability check inside each plugin.
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
  }
@@ -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(/([^\s]+)@([^\s]+)\.([^\s]+)/g, (...f) => stars(f[1]) + '@' + stars(f[2]) + '.' + stars(f[3]));
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: '6.0.1',
140
+ trackerVersion: '7.0.0',
141
141
  projectKey: options.projectKey,
142
142
  doNotTrack,
143
143
  // TODO: add precise reason (an exact API missing)
@@ -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;
@@ -175,5 +175,5 @@ export default function (app, options) {
175
175
  }
176
176
  });
177
177
  patchDocument(document, true);
178
- app.ticker.attach(sendMouseMove, 10);
178
+ app.ticker.attach(sendMouseMove, (options === null || options === void 0 ? void 0 : options.trackingOffset) || 7);
179
179
  }
@@ -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>, customEnv?: Record<string, any>): void;
27
+ export default function (app: App, opts?: Partial<Options>): void;
28
28
  export {};
@@ -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 = {}, customEnv) {
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
- /* ====== Fetch ====== */
103
- const origFetch = customEnv
104
- ? customEnv.fetch.bind(customEnv)
105
- : window.fetch.bind(window);
106
- const trackFetch = (input, init = {}) => {
107
- if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
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
- else {
121
- init.headers[name] = value;
122
- }
123
- });
124
- const startTime = performance.now();
125
- return origFetch(input, init).then((response) => {
126
- const duration = performance.now() - startTime;
127
- if (options.failuresOnly && response.status < 400) {
128
- return response;
129
- }
130
- const r = response.clone();
131
- r.text()
132
- .then((text) => {
133
- const reqHs = {};
134
- const resHs = {};
135
- if (ignoreHeaders !== true) {
136
- // request headers
137
- const writeReqHeader = ([n, v]) => {
138
- if (!isHIgnored(n)) {
139
- reqHs[n] = v;
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
- if (init.headers instanceof Headers) {
143
- init.headers.forEach((v, n) => writeReqHeader([n, v]));
144
- }
145
- else if (Array.isArray(init.headers)) {
146
- init.headers.forEach(writeReqHeader);
147
- }
148
- else if (typeof init.headers === 'object') {
149
- Object.entries(init.headers).forEach(writeReqHeader);
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
- // response headers
152
- r.headers.forEach((v, n) => {
153
- if (!isHIgnored(n))
154
- resHs[n] = v;
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
- const method = strMethod(init.method);
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(input),
166
+ url: String(url),
160
167
  method,
161
- status: r.status,
168
+ status: xhr.status,
162
169
  request: {
163
170
  headers: reqHs,
164
- body: init.body,
171
+ body: reqBody,
165
172
  },
166
173
  response: {
167
174
  headers: resHs,
168
- body: text,
175
+ body: xhr.response,
169
176
  },
170
177
  });
171
178
  if (!reqResInfo) {
172
179
  return;
173
180
  }
174
- app.send(NetworkRequest('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + getTimeOrigin(), duration));
175
- })
176
- .catch((e) => app.debug.error('Could not process Fetch response:', e));
177
- return response;
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
- else {
258
- XMLHttpRequest.prototype.send = trackXHRSend;
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.headers[name] = value;
191
+ rdo.body = body;
192
+ // @ts-ignore ??? this -> XMLHttpRequest
193
+ return nativeSend.apply(this, arguments);
266
194
  }
267
- // @ts-ignore ??? this -> XMLHttpRequest
268
- return nativeSetRequestHeader.apply(this, arguments);
269
- }
270
- if (customEnv) {
271
- if ('XMLHttpRequest' in customEnv) {
272
- customEnv.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader.bind(customEnv);
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
- else {
276
- XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
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
@@ -68,6 +68,9 @@ export function isIframeCrossdomain(e) {
68
68
  return true;
69
69
  }
70
70
  }
71
+ /**
72
+ * checks if iframe is accessible
73
+ **/
71
74
  export function canAccessIframe(iframe) {
72
75
  try {
73
76
  return Boolean(iframe.contentDocument);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "6.0.1",
4
+ "version": "7.0.0",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"