@openreplay/tracker 18.1.3 → 18.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -163,7 +163,6 @@ export default class App {
163
163
  private worker?;
164
164
  attributeSender: AttributeSender;
165
165
  socketMode: boolean;
166
- private compressionThreshold;
167
166
  private readonly bc;
168
167
  private readonly contextId;
169
168
  private canvasRecorder;
@@ -1,4 +1,10 @@
1
1
  import type App from '../app/index.js';
2
+ export declare function isDeepClickable(element: Element): boolean;
3
+ /**
4
+ * cursor is inherited, so every child of a clickable div reports a pointer too;
5
+ * climb to the outermost element that still owns the pointer
6
+ * */
7
+ export declare function resolvePointerRoot(element: Element): Element;
2
8
  export interface MouseHandlerOptions {
3
9
  disableClickmaps?: boolean;
4
10
  /**
@@ -11,4 +17,4 @@ export interface MouseHandlerOptions {
11
17
  customAttributes?: string[];
12
18
  }
13
19
  export default function (app: App, options?: MouseHandlerOptions): void;
14
- export declare function getCSSPath(el: any): string | false;
20
+ export declare function getCSSPath(el: any, customAttributes?: string[]): string | false;
@@ -11,6 +11,15 @@ export declare const DOCS_HOST = "https://docs.openreplay.com";
11
11
  export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
12
12
  export declare function getCustomAttributeLabel(e: Element, customAttributes?: string[]): string;
13
13
  export declare function getClassSelector(e: Element): string;
14
+ export declare const cssEscape: (str: string) => string;
15
+ /** escape a value that goes inside a quoted css attribute selector */
16
+ export declare function cssAttrValue(value: string): string;
17
+ export declare function getCustomAttributeSelector(e: Element, customAttributes?: string[]): string;
18
+ /**
19
+ * human readable label of a clicked element: its own text/description,
20
+ * then the same for a few ancestors (a click on an icon inside a card)
21
+ * */
22
+ export declare function getTextualLabel(e: Element, getInnerText: (el: HTMLElement) => string, maxAncestors?: number): string;
14
23
  export declare function getLabelAttribute(e: Element): string | null;
15
24
  export declare function hasOpenreplayAttribute(e: Element, attr: string): boolean;
16
25
  /**
@@ -12,24 +12,16 @@ type Start = {
12
12
  url: string;
13
13
  tabId: string;
14
14
  localDebug?: boolean;
15
+ compressionThreshold?: number;
15
16
  } & Options;
16
17
  type Auth = {
17
18
  type: 'auth';
18
19
  token: string;
19
20
  beaconSizeLimit?: number;
20
21
  protocolVersion?: number;
22
+ compressionThreshold?: number;
21
23
  };
22
- export type ToWorkerData = null | 'stop' | Start | Auth | Array<Message> | {
23
- type: 'compressed';
24
- batch: Uint8Array;
25
- dataType: DataType;
26
- split?: number;
27
- } | {
28
- type: 'uncompressed';
29
- batch: Uint8Array;
30
- dataType: DataType;
31
- split?: number;
32
- } | 'forceFlushBatch' | 'closing' | 'check_queue';
24
+ export type ToWorkerData = null | 'stop' | Start | Auth | Array<Message> | 'forceFlushBatch' | 'closing' | 'check_queue';
33
25
  type Failure = {
34
26
  type: 'failure';
35
27
  reason: string;
@@ -42,10 +34,5 @@ type LocalSave = {
42
34
  name: string;
43
35
  batch: Uint8Array;
44
36
  };
45
- export type FromWorkerData = 'a_stop' | 'a_start' | Failure | 'not_init' | {
46
- type: 'compress';
47
- batch: Uint8Array;
48
- dataType: DataType;
49
- split?: number;
50
- } | QEmpty | LocalSave;
37
+ export type FromWorkerData = 'a_stop' | 'a_start' | Failure | 'not_init' | QEmpty | LocalSave;
51
38
  export {};
package/dist/lib/entry.js CHANGED
@@ -455,6 +455,80 @@ function getClassSelector(e) {
455
455
  return '';
456
456
  return '.' + Array.from(e.classList).join('.');
457
457
  }
458
+ const cssEscape = (typeof CSS !== 'undefined' && CSS.escape) || ((str) => str);
459
+ /** escape a value that goes inside a quoted css attribute selector */
460
+ function cssAttrValue(value) {
461
+ return value.replace(/(["\\])/g, '\\$1');
462
+ }
463
+ function getCustomAttributeSelector(e, customAttributes) {
464
+ if (!customAttributes || customAttributes.length === 0)
465
+ return '';
466
+ for (const attr of customAttributes) {
467
+ const value = e.getAttribute(attr);
468
+ if (value !== null) {
469
+ return `[${attr}="${cssAttrValue(value)}"]`;
470
+ }
471
+ }
472
+ return '';
473
+ }
474
+ const TEXT_LABEL_ATTRIBUTES = ['aria-label', 'title', 'alt', 'placeholder'];
475
+ const VALUE_INPUT_TYPES = ['button', 'submit', 'reset'];
476
+ function cleanLabel(str) {
477
+ const label = normSpaces(str);
478
+ return /[a-z0-9]/i.test(label) ? label.slice(0, 100) : '';
479
+ }
480
+ function getOwnTextLabel(e, getInnerText, isAncestor) {
481
+ const tag = e.tagName.toUpperCase();
482
+ if (tag !== 'SELECT') {
483
+ const rawText = getInnerText(e) || '';
484
+ // truncated or multiline text belongs to a container, not to this element
485
+ if (rawText.length <= 100 && !(isAncestor && /[\r\n]/.test(rawText))) {
486
+ const text = cleanLabel(rawText);
487
+ if (text)
488
+ return text;
489
+ }
490
+ }
491
+ for (const attr of TEXT_LABEL_ATTRIBUTES) {
492
+ const value = e.getAttribute(attr);
493
+ if (value) {
494
+ const label = cleanLabel(value);
495
+ if (label)
496
+ return label;
497
+ }
498
+ }
499
+ if (tag === 'INPUT' && VALUE_INPUT_TYPES.includes(e.type)) {
500
+ const label = cleanLabel(e.value);
501
+ if (label)
502
+ return label;
503
+ }
504
+ // icon-only elements carry their meaning on a child
505
+ const describedChild = e.querySelector('[aria-label], img[alt], [title]');
506
+ if (describedChild) {
507
+ for (const attr of TEXT_LABEL_ATTRIBUTES) {
508
+ const value = describedChild.getAttribute(attr);
509
+ if (value) {
510
+ const label = cleanLabel(value);
511
+ if (label)
512
+ return label;
513
+ }
514
+ }
515
+ }
516
+ return '';
517
+ }
518
+ /**
519
+ * human readable label of a clicked element: its own text/description,
520
+ * then the same for a few ancestors (a click on an icon inside a card)
521
+ * */
522
+ function getTextualLabel(e, getInnerText, maxAncestors = 2) {
523
+ let el = e;
524
+ for (let depth = 0; el !== null && depth <= maxAncestors; depth++) {
525
+ const label = getOwnTextLabel(el, getInnerText, depth > 0);
526
+ if (label)
527
+ return label;
528
+ el = el.parentElement;
529
+ }
530
+ return '';
531
+ }
458
532
  function getLabelAttribute(e) {
459
533
  let value = e.getAttribute('data-openreplay-label');
460
534
  if (value !== null) {
@@ -631,11 +705,21 @@ class FIFOTaskScheduler {
631
705
  this.isRunning = false;
632
706
  return;
633
707
  }
634
- // Get the next task and execute it
708
+ // Get the next task and execute it. A task that throws (or rejects) must
709
+ // still schedule the next one: leaving `isRunning` true strands the queue
710
+ // for the lifetime of the page, and since commits run through here that
711
+ // silently ends the recording. See #4836.
635
712
  const nextTask = this.taskQueue.shift();
636
- Promise.resolve(nextTask()).then(() => {
637
- requestAnimationFrame(() => executeNextTask());
638
- });
713
+ const scheduleNext = () => requestAnimationFrame(() => executeNextTask());
714
+ let result;
715
+ try {
716
+ result = nextTask();
717
+ }
718
+ catch (e) {
719
+ scheduleNext();
720
+ throw e;
721
+ }
722
+ Promise.resolve(result).then(scheduleNext, scheduleNext);
639
723
  };
640
724
  executeNextTask();
641
725
  }
@@ -4295,7 +4379,7 @@ class Ticker {
4295
4379
  * this value is injected during build time via rollup
4296
4380
  * */
4297
4381
  // @ts-ignore
4298
- const workerBodyFn = "!function(){\"use strict\";class t{constructor(t,s,i,e=10,n=250,h,r){this.onUnauthorised=s,this.onFailure=i,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.onCompress=h,this.pageNo=r,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.lastBatchNum=0,this.inflightKeepaliveBytes=0,this.ingestURL=t+\"/v1/web/i\",this.isCompressing=void 0!==h}getQueueStatus(){return 0===this.queue.length&&!this.busy}authorise(t){this.token=t,this.busy||this.sendNext()}push(t,s=\"player\",i){if(this.busy||!this.token)this.queue.push({batch:t,dataType:s,split:i});else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t,s,i);else{const e=++this.lastBatchNum;this.sendBatch(t,!1,e,s,i)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t.batch,t.dataType,t.split);else{const s=++this.lastBatchNum;this.sendBatch(t.batch,!1,s,t.dataType,t.split)}else this.busy=!1}retry(t,s,i,e=\"player\",n){if(this.attemptsCount>=this.MAX_ATTEMPTS_COUNT)return void this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`);this.attemptsCount++;const h=new Uint8Array(t);setTimeout((()=>this.sendBatch(h,s,i,e,n)),this.ATTEMPT_TIMEOUT*this.attemptsCount)}sendBatch(t,s,i,e=\"player\",n){var h,r,a;if(0===t.length)return console.error(\"OpenReplay: refusing to send 0-byte batch.\",{batchNum:i,dataType:e,isCompressed:s,batch:t}),this.attemptsCount=0,void this.sendNext();const u=(null!==(h=null==i?void 0:i.toString())&&void 0!==h?h:\"0\").match(/^([^_]+)(?:_([^_]+))?/),o=null!==(r=null==u?void 0:u[1])&&void 0!==r?r:\"0\",l=(null==u?void 0:u[2])?u[2]:\"\";this.busy=!0;const c={Authorization:`Bearer ${this.token}`,DataType:e};if(s&&(c[\"Content-Encoding\"]=\"gzip\"),null===this.token)return void setTimeout((()=>{this.sendBatch(t,s,`${null!=i?i:\"noBatchNum\"}_newToken`,e,n)}),500);const d=t.length<65536&&this.inflightKeepaliveBytes+t.length<=65536;d&&(this.inflightKeepaliveBytes+=t.length);const p=()=>{d&&(this.inflightKeepaliveBytes-=t.length)},f=t.byteLength;let g=this.ingestURL;g+=`?batch=${null!==(a=this.pageNo)&&void 0!==a?a:0}`,g+=`_${o}`,g+=`_${f}`,g+=\"_\"+(d?\"kyes\":\"kno\"),l&&(g+=`_${l}`),void 0!==n&&(g+=`&split=${n}`),fetch(g,{body:t,method:\"POST\",headers:c,keepalive:d}).then((h=>{var r;if(p(),null===(r=h.body)||void 0===r||r.cancel().catch((()=>{})),401===h.status)return this.busy=!1,void this.onUnauthorised();h.status>=400?this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_network:${h.status}`,e,n):(this.attemptsCount=0,this.sendNext())})).catch((h=>{p(),console.warn(\"OpenReplay:\",h),this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_reject:${h.message}`,e,n)}))}sendCompressed(t,s=\"player\",i){const e=++this.lastBatchNum;this.sendBatch(t,!0,e,s,i)}sendUncompressed(t,s=\"player\",i){const e=++this.lastBatchNum;this.sendBatch(t,!1,e,s,i)}clean(){this.sendNext(),setTimeout((()=>{this.token=null,this.queue.length=0}),10)}}const s=new Set([60,61,71,73]),i=new Set([21,22,40,41,44,45,46,47,48,79,83,84,85,87,89,116,120,121,123]),e=new Set([17,23,24,27,28,29,30,42,63,64,78,112,115,124]),n=\"function\"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let e=-1;for(let n=0,h=0,r=0;r!==s;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===s){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){i[e+=1]=239,i[e+=1]=191,i[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){i[e+=1]=240|n>>>18,i[e+=1]=128|n>>>12&63,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n;continue}}n<=127?i[e+=1]=0|n:n<=2047?(i[e+=1]=192|n>>>6,i[e+=1]=128|63&n):(i[e+=1]=224|n>>>12,i[e+=1]=128|n>>>6&63,i[e+=1]=128|63&n)}return i.subarray(0,e+1)}};class h{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}getCurrentCheckpoint(){return this.checkpointOffset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,s){this.data.set(t,s)}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=n.encode(t),i=s.byteLength;return!(!this.uint(i)||this.offset+i>this.size)&&(this.data.set(s,this.offset),this.offset+=i,!0)}reset(){this.offset=0,this.checkpointOffset=0}rewind(t,s){t>this.offset||s>this.checkpointOffset||(this.offset=t,this.checkpointOffset=s)}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class r extends h{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 65:case 70:case 75:case 76:case 77: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:case 24:case 35:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 52:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 34:case 36:case 50:case 54: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 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 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:case 27:case 30:case 41:case 45:case 46:case 43:case 63:case 64:case 79:case 124: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 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.int(t[5]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);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 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 68:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83: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])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 85: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])&&this.uint(t[11])&&this.uint(t[12])&&this.uint(t[13])&&this.uint(t[14])&&this.uint(t[15])&&this.uint(t[16])&&this.uint(t[17]);case 87:return this.string(t[1])&&this.int(t[2])&&this.int(t[3]);case 89:return this.string(t[1])&&this.int(t[2])&&this.int(t[3])&&this.int(t[4])&&this.int(t[5])&&this.string(t[6]);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 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 122:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 123:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])}}}class a{constructor(t,s,i){this.bufferSize=t,this.version=s,this.dataType=i,this.sizeBuffer=new Uint8Array(3),this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0,this.encoder=new r(t)}push(t,s){const i=this.encoder,e=null===this.snap,n=i.getCurrentOffset(),h=i.getCurrentCheckpoint();if(e){const t={pageNo:s.pageNo,firstIndex:s.index,timestamp:s.timestamp,url:s.url,tabId:s.tabId};if(!this.writeHeader(t))return i.rewind(n,h),!1;this.snap=t,this.lastPushedTs=s.timestamp}return 0===t[0]||s.timestamp===this.lastPushedTs||this.writeMessageWithSize([0,s.timestamp])?this.writeMessageWithSize(t)?(this.lastPushedTs=s.timestamp,0!==t[0]&&(this.hasNonTimestamp=!0),!0):(i.rewind(n,h),e&&(this.snap=null),!1):(i.rewind(n,h),!1)}hasContent(){return null!==this.snap&&this.hasNonTimestamp}size(){return null===this.snap?0:this.encoder.getCurrentOffset()}flush(){if(!this.hasContent())return this.reset(),null;const t=this.encoder.flush();return this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0,t}reset(){this.encoder.reset(),this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0}writeHeader(t){const s=this.encoder,i=[81,this.version,t.pageNo,t.firstIndex,t.timestamp,t.url];return!!s.uint(i[0])&&(!!s.encode(i)&&(!(s.getCurrentOffset()>this.bufferSize)&&(s.checkpoint(),!!this.writeMessageWithSize([0,t.timestamp])&&!!this.writeMessageWithSize([118,t.tabId]))))}writeMessageWithSize(t){const s=this.encoder;if(!s.uint(t[0])||!s.skip(3))return!1;const i=s.getCurrentOffset();if(!s.encode(t))return!1;const e=s.getCurrentOffset(),n=e-i;return n>16777215?(console.warn(\"OpenReplay: max message size overflow.\"),!1):!(e>this.bufferSize)&&(this.writeSizeAt(n,i-3),s.checkpoint(),!0)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}}class u{constructor(t,s,i,e,n,h,r=!1,u){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=e,this.tabId=n,this.onOfflineEnd=h,this.localDebug=r,this.onLocalSave=u,this.nextIndex=0,this.beaconSize=2e5,this.beaconSizeLimit=1e6,this.protocolVersion=1,this.visualSent=!1,this.signalSeen=!1,this.heldOther=[],this.playerBuilder=new a(this.beaconSize,this.playerVersion(),\"player\"),this.assetBuilder=new a(this.beaconSize,3,\"assets\"),this.devtoolsBuilder=new a(this.beaconSize,4,\"devtools\"),this.analyticsBuilder=new a(this.beaconSize,5,\"analytics\")}initActive(){return 2===this.protocolVersion&&!this.visualSent}playerVersion(){return 2===this.protocolVersion?2:1}currentCtx(){return{pageNo:this.pageNo,index:this.nextIndex,timestamp:this.timestamp,url:this.url,tabId:this.tabId}}setBeaconSizeLimit(t){this.beaconSizeLimit=t}setProtocolVersion(t){if(this.protocolVersion!==t){if(this.protocolVersion=t,2===t&&!this.signalSeen)return this.playerBuilder.reset(),this.assetBuilder.reset(),this.playerBuilder=new a(this.beaconSizeLimit,this.playerVersion(),\"player\"),void(this.assetBuilder=new a(this.beaconSizeLimit,3,\"assets\"));2===t&&(this.visualSent=!0),this.playerBuilder.reset(),this.playerBuilder=new a(this.beaconSize,this.playerVersion(),\"player\")}}writeMessage(t){if(-1===t[0])return this.finaliseBatch(),this.onOfflineEnd();if(12===t[0]&&\"orloaded\"===t[2])return void(this.initActive()?this.finalizeVisual():this.signalSeen=!0);0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]);const s=this.routeMessage(t);this.pushTo(s,t)}routeMessage(t){if(2===this.protocolVersion){const n=t[0];if(s.has(n))return this.assetBuilder;if(i.has(n))return this.devtoolsBuilder;if(e.has(n))return this.analyticsBuilder}return this.playerBuilder}pushTo(t,s){const i=this.currentCtx();if(this.initActive())return void this.pushDuringInit(t,s,i);if(t.push(s,i))return void this.nextIndex++;if(t===this.assetBuilder&&this.flushBuilder(this.playerBuilder),this.flushBuilder(t),t.push(s,i))return void this.nextIndex++;const e=new a(this.beaconSizeLimit,t.version,t.dataType);if(!e.push(s,i))return void console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",s);this.nextIndex++;const n=e.flush();n&&(t===this.assetBuilder&&this.flushBuilder(this.playerBuilder),this.emitBatch(n,t.dataType,!1))}pushDuringInit(t,s,i){const e=t===this.playerBuilder||t===this.assetBuilder;if(t.push(s,i))return this.nextIndex++,void(e&&this.playerBuilder.size()+this.assetBuilder.size()>=this.beaconSizeLimit&&this.finalizeVisual());if(e)return this.finalizeVisual(),void this.pushTo(this.routeMessage(s),s);if(this.flushBuilderToHeld(t),t.push(s,i))return void this.nextIndex++;const n=new a(this.beaconSizeLimit,t.version,t.dataType);if(!n.push(s,i))return void console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",s);this.nextIndex++;const h=n.flush();h&&this.heldOther.push({batch:h,dataType:t.dataType})}flushBuilderToHeld(t){const s=t.flush();s&&this.heldOther.push({batch:s,dataType:t.dataType})}finalizeVisual(t=!1){const s=this.playerBuilder.flush(),i=this.assetBuilder.flush();if(this.visualSent=!0,this.playerBuilder=new a(this.beaconSize,this.playerVersion(),\"player\"),this.assetBuilder=new a(this.beaconSize,3,\"assets\"),s&&i){const e=new Uint8Array(s.length+i.length);e.set(s,0),e.set(i,s.length),this.emitBatch(e,\"visual\",t,s.length)}else s?this.emitBatch(s,\"player\",t):i&&this.emitBatch(i,\"assets\",t);for(const s of this.heldOther)this.emitBatch(s.batch,s.dataType,t);this.heldOther.length=0,this.flushBuilder(this.devtoolsBuilder,t),this.flushBuilder(this.analyticsBuilder,t)}flushBuilder(t,s=!1){const i=t.flush();return!!i&&(this.emitBatch(i,t.dataType,s),!0)}emitBatch(t,s,i,e){this.localDebug&&this.onLocalSave&&this.onLocalSave(`${s}-${Date.now()}`,t.slice()),this.onBatch(t,i,s,e)}finaliseBatch(t=!1){this.initActive()?this.finalizeVisual(t):(this.flushBuilder(this.playerBuilder,t),this.flushBuilder(this.assetBuilder,t),this.flushBuilder(this.devtoolsBuilder,t),this.flushBuilder(this.analyticsBuilder,t))}clean(){this.playerBuilder.reset(),this.assetBuilder.reset(),this.devtoolsBuilder.reset(),this.analyticsBuilder.reset(),this.heldOther.length=0,this.visualSent=!1,this.signalSeen=!1}}var o;!function(t){t[t.NotActive=0]=\"NotActive\",t[t.Starting=1]=\"Starting\",t[t.Stopping=2]=\"Stopping\",t[t.Active=3]=\"Active\",t[t.Stopped=4]=\"Stopped\"}(o||(o={}));let l=null,c=null,d=o.NotActive;function p(t){c&&c.finaliseBatch(t)}function f(){return new Promise((t=>{d=o.Stopping,null!==y&&(clearInterval(y),y=null),c&&(c.clean(),c=null),l&&(l.clean(),setTimeout((()=>{l=null}),20)),setTimeout((()=>{d=o.NotActive,t(null)}),100)}))}function g(){[o.Stopped,o.Stopping].includes(d)||(postMessage(\"a_stop\"),f().then((()=>{postMessage(\"a_start\")})))}let m,y=null;self.onmessage=({data:s})=>{var i;if(\"stop\"===s)return p(),void f().then((()=>{d=o.Stopped}));if(\"forceFlushBatch\"!==s)if(\"closing\"!==s){if(!Array.isArray(s)){if(\"compressed\"===s.type){if(!l)return console.debug(\"OR WebWorker: sender not initialised. Compressed batch.\"),void g();s.batch&&l.sendCompressed(s.batch,s.dataType,s.split)}if(\"uncompressed\"===s.type){if(!l)return console.debug(\"OR WebWorker: sender not initialised. Uncompressed batch.\"),void g();s.batch&&l.sendUncompressed(s.batch,s.dataType,s.split)}return\"start\"===s.type?(d=o.Starting,l=new t(s.ingestPoint,(()=>{g()}),(t=>{!function(t){postMessage({type:\"failure\",reason:t}),f()}(t)}),s.connAttemptCount,s.connAttemptGap,((t,s,i)=>{postMessage({type:\"compress\",batch:t,dataType:s,split:i},[t.buffer])}),s.pageNo),c=new u(s.pageNo,s.timestamp,s.url,((t,s,i=\"player\",e)=>{l&&(s?l.sendUncompressed(t,i,e):l.push(t,i,e))}),s.tabId,(()=>postMessage({type:\"queue_empty\"})),null!==(i=s.localDebug)&&void 0!==i&&i,((t,s)=>{postMessage({type:\"local_save\",name:t,batch:s},[s.buffer])})),null===y&&(y=setInterval(p,3e4)),d=o.Active):\"auth\"===s.type?l?c?(l.authorise(s.token),s.beaconSizeLimit&&c.setBeaconSizeLimit(s.beaconSizeLimit),void(s.protocolVersion&&c.setProtocolVersion(s.protocolVersion))):(console.debug(\"OR WebWorker: writer not initialised. Received auth.\"),void g()):(console.debug(\"OR WebWorker: sender not initialised. Received auth.\"),void g()):void 0}if(c){const t=c;s.forEach((s=>{55===s[0]&&(s[1]?m=setTimeout((()=>g()),18e5):clearTimeout(m)),t.writeMessage(s)}))}else postMessage(\"not_init\"),g()}else p(!0);else p()}}();\n";
4382
+ const workerBodyFn = "!function(){\"use strict\";function t(t,i,s,e){return new(s||(s=Promise))(function(n,h){function r(t){try{u(e.next(t))}catch(t){h(t)}}function a(t){try{u(e.throw(t))}catch(t){h(t)}}function u(t){var i;t.done?n(t.value):(i=t.value,i instanceof s?i:new s(function(t){t(i)})).then(r,a)}u((e=e.apply(t,i||[])).next())})}\"function\"==typeof SuppressedError&&SuppressedError;const i=\"undefined\"!=typeof CompressionStream;class s{constructor(t,i,s,e=10,n=250,h,r){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.pageNo=h,this.attemptsCount=0,this.queue=[],this.inFlight=null,this.inFlightDispatched=!1,this.compressionEpoch=0,this.token=null,this.stopped=!1,this.lastSeq=0,this.compressionThreshold=24e3,this.inflightKeepaliveBytes=0,this.ingestURL=t+\"/v1/web/i\",\"number\"==typeof r&&(this.compressionThreshold=r)}getQueueStatus(){return 0===this.queue.length&&null===this.inFlight}setCompressionThreshold(t){this.compressionThreshold=t}authorise(t){this.token=t,this.pump()}push(t,i=\"player\",s,e=!1){this.stopped||(this.queue.push({seq:++this.lastSeq,batch:t,dataType:i,split:s,raw:e}),this.pump())}pump(){if(this.stopped||null!==this.inFlight||null===this.token||0===this.queue.length)return;const t=this.queue.shift();if(this.inFlight=t,this.inFlightDispatched=!1,t.raw||!i||t.batch.length<=this.compressionThreshold)return void this.dispatch(t,t.batch,!1);const s=++this.compressionEpoch;this.gzip(t.batch).then(i=>{this.compressionEpoch===s&&this.inFlight===t&&this.dispatch(t,i,!0)}).catch(()=>{this.compressionEpoch===s&&this.inFlight===t&&this.dispatch(t,t.batch,!1)})}gzip(i){return t(this,void 0,void 0,function*(){const t=new Blob([i]).stream().pipeThrough(new CompressionStream(\"gzip\"));return new Uint8Array(yield new Response(t).arrayBuffer())})}finish(){this.inFlight=null,this.inFlightDispatched=!1,this.pump()}retry(t,i,s,e){if(this.attemptsCount>=this.MAX_ATTEMPTS_COUNT)return void this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`);this.attemptsCount++;const n=new Uint8Array(i);setTimeout(()=>this.dispatch(t,n,s,e),this.ATTEMPT_TIMEOUT*this.attemptsCount)}dispatch(t,i,s,e=\"\"){var n;if(0===i.length)return console.error(\"OpenReplay: refusing to send 0-byte batch.\",{seq:t.seq,dataType:t.dataType,isCompressed:s}),this.attemptsCount=0,void this.finish();this.inFlight===t&&(this.inFlightDispatched=!0);const h={Authorization:`Bearer ${this.token}`,DataType:t.dataType};if(s&&(h[\"Content-Encoding\"]=\"gzip\"),null===this.token)return void setTimeout(()=>this.dispatch(t,i,s,\"newToken\"),500);const r=i.length<65536&&this.inflightKeepaliveBytes+i.length<=65536;r&&(this.inflightKeepaliveBytes+=i.length);let a=!1;const u=()=>{r&&!a&&(a=!0,this.inflightKeepaliveBytes-=i.length)};let o=this.ingestURL;o+=`?batch=${null!==(n=this.pageNo)&&void 0!==n?n:0}`,o+=`_${t.seq}`,o+=`_${i.byteLength}`,o+=\"_\"+(r?\"kyes\":\"kno\"),e&&(o+=`_${e}`),void 0!==t.split&&(o+=`&split=${t.split}`),fetch(o,{body:i,method:\"POST\",headers:h,keepalive:r}).then(e=>{var n;if(u(),null===(n=e.body)||void 0===n||n.cancel().catch(()=>{}),401===e.status)return this.inFlight=null,this.inFlightDispatched=!1,void this.onUnauthorised();e.status>=400?this.retry(t,i,s,`network:${e.status}`):(this.attemptsCount=0,this.finish())}).catch(e=>{u(),console.warn(\"OpenReplay:\",e),this.retry(t,i,s,`reject:${e.message}`)})}flushAll(){if(null===this.token)return;const t=this.queue.splice(0),i=this.inFlight;null===i||this.inFlightDispatched||(this.compressionEpoch++,this.inFlight=null,t.unshift(i));for(const i of t)i.raw=!0,this.dispatch(i,i.batch,!1)}clean(){this.flushAll(),this.stopped=!0,setTimeout(()=>{this.token=null,this.queue.length=0,this.inFlight=null,this.inFlightDispatched=!1},10)}}const e=new Set([60,61,71,73]),n=new Set([21,22,40,41,44,45,46,47,48,79,83,84,85,87,89,116,120,121,123]),h=new Set([17,23,24,27,28,29,30,42,63,64,78,112,115,124]),r=\"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 a{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}getCurrentCheckpoint(){return this.checkpointOffset}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 i=r.encode(t),s=i.byteLength;return!(!this.uint(s)||this.offset+s>this.size)&&(this.data.set(i,this.offset),this.offset+=s,!0)}reset(){this.offset=0,this.checkpointOffset=0}rewind(t,i){t>this.offset||i>this.checkpointOffset||(this.offset=t,this.checkpointOffset=i)}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class u extends a{encode(t){switch(t[0]){case 0:case 11:case 114:case 115:return this.uint(t[1]);case 4:case 44:case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:case 20:case 65:case 70:case 75:case 76:case 77: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:case 24:case 35:case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 12:case 52:case 61:case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:case 17:case 34:case 36:case 50:case 54: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 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 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:case 27:case 30:case 41:case 45:case 46:case 43:case 63:case 64:case 79:case 124: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 28:case 29:case 42:case 117:case 118:return this.string(t[1]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.int(t[5]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);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 55:return this.boolean(t[1]);case 57:case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:case 120:return this.int(t[1]);case 68:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 83: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])&&this.uint(t[9]);case 84:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6]);case 85: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])&&this.uint(t[11])&&this.uint(t[12])&&this.uint(t[13])&&this.uint(t[14])&&this.uint(t[15])&&this.uint(t[16])&&this.uint(t[17]);case 87:return this.string(t[1])&&this.int(t[2])&&this.int(t[3]);case 89:return this.string(t[1])&&this.int(t[2])&&this.int(t[3])&&this.int(t[4])&&this.int(t[5])&&this.string(t[6]);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 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10]);case 119:return this.string(t[1])&&this.uint(t[2]);case 121:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 122:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 123:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])}}}class o{constructor(t,i,s){this.bufferSize=t,this.version=i,this.dataType=s,this.sizeBuffer=new Uint8Array(3),this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0,this.encoder=new u(t)}push(t,i){const s=this.encoder,e=null===this.snap,n=s.getCurrentOffset(),h=s.getCurrentCheckpoint();if(e){const t={pageNo:i.pageNo,firstIndex:i.index,timestamp:i.timestamp,url:i.url,tabId:i.tabId};if(!this.writeHeader(t))return s.rewind(n,h),!1;this.snap=t,this.lastPushedTs=i.timestamp}return 0===t[0]||i.timestamp===this.lastPushedTs||this.writeMessageWithSize([0,i.timestamp])?this.writeMessageWithSize(t)?(this.lastPushedTs=i.timestamp,0!==t[0]&&(this.hasNonTimestamp=!0),!0):(s.rewind(n,h),e&&(this.snap=null),!1):(s.rewind(n,h),!1)}hasContent(){return null!==this.snap&&this.hasNonTimestamp}size(){return null===this.snap?0:this.encoder.getCurrentOffset()}flush(){if(!this.hasContent())return this.reset(),null;const t=this.encoder.flush();return this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0,t}headerOnly(t){this.reset();const i=this.writeHeader({pageNo:t.pageNo,firstIndex:t.index,timestamp:t.timestamp,url:t.url,tabId:t.tabId})?this.encoder.flush():null;return this.reset(),null!==i&&i.length>0?i:null}reset(){this.encoder.reset(),this.snap=null,this.hasNonTimestamp=!1,this.lastPushedTs=0}writeHeader(t){const i=this.encoder,s=[81,this.version,t.pageNo,t.firstIndex,t.timestamp,t.url];return!!i.uint(s[0])&&(!!i.encode(s)&&(!(i.getCurrentOffset()>this.bufferSize)&&(i.checkpoint(),!!this.writeMessageWithSize([0,t.timestamp])&&!!this.writeMessageWithSize([118,t.tabId]))))}writeMessageWithSize(t){const i=this.encoder;if(!i.uint(t[0])||!i.skip(3))return!1;const s=i.getCurrentOffset();if(!i.encode(t))return!1;const e=i.getCurrentOffset(),n=e-s;return n>16777215?(console.warn(\"OpenReplay: max message size overflow.\"),!1):!(e>this.bufferSize)&&(this.writeSizeAt(n,s-3),i.checkpoint(),!0)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}}class l{constructor(t,i,s,e,n,h,r=!1,a){this.pageNo=t,this.timestamp=i,this.url=s,this.onBatch=e,this.tabId=n,this.onOfflineEnd=h,this.localDebug=r,this.onLocalSave=a,this.nextIndex=0,this.beaconSize=2e5,this.beaconSizeLimit=1e6,this.protocolVersion=1,this.visualSent=!1,this.signalSeen=!1,this.heldOther=[],this.playerBuilder=new o(this.beaconSize,this.playerVersion(),\"player\"),this.assetBuilder=new o(this.beaconSize,3,\"assets\"),this.devtoolsBuilder=new o(this.beaconSize,4,\"devtools\"),this.analyticsBuilder=new o(this.beaconSize,5,\"analytics\")}initActive(){return 2===this.protocolVersion&&!this.visualSent}playerVersion(){return 2===this.protocolVersion?2:1}currentCtx(){return{pageNo:this.pageNo,index:this.nextIndex,timestamp:this.timestamp,url:this.url,tabId:this.tabId}}setBeaconSizeLimit(t){this.beaconSizeLimit=t}setProtocolVersion(t){if(this.protocolVersion!==t){if(this.protocolVersion=t,2===t&&!this.signalSeen)return this.playerBuilder.reset(),this.assetBuilder.reset(),this.playerBuilder=new o(this.beaconSizeLimit,this.playerVersion(),\"player\"),void(this.assetBuilder=new o(this.beaconSizeLimit,3,\"assets\"));2===t&&(this.visualSent=!0),this.playerBuilder.reset(),this.playerBuilder=new o(this.beaconSize,this.playerVersion(),\"player\")}}writeMessage(t){if(-1===t[0])return this.finaliseBatch(),this.onOfflineEnd();if(12===t[0]&&\"orloaded\"===t[2])return void(this.initActive()?this.finalizeVisual():this.signalSeen=!0);0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]);const i=this.routeMessage(t);this.pushTo(i,t)}routeMessage(t){if(2===this.protocolVersion){const i=t[0];if(e.has(i))return this.assetBuilder;if(n.has(i))return this.devtoolsBuilder;if(h.has(i))return this.analyticsBuilder}return this.playerBuilder}pushTo(t,i){const s=this.currentCtx();if(this.initActive())return void this.pushDuringInit(t,i,s);if(t.push(i,s))return void this.nextIndex++;if(t===this.assetBuilder&&this.flushBuilder(this.playerBuilder),this.flushBuilder(t),t.push(i,s))return void this.nextIndex++;const e=new o(this.beaconSizeLimit,t.version,t.dataType);if(!e.push(i,s))return void console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",i);this.nextIndex++;const n=e.flush();n&&(t===this.assetBuilder&&this.flushBuilder(this.playerBuilder),this.emitBatch(n,t.dataType,!1))}pushDuringInit(t,i,s){const e=t===this.playerBuilder||t===this.assetBuilder;if(t.push(i,s))return this.nextIndex++,void(e&&this.playerBuilder.size()+this.assetBuilder.size()>=this.beaconSizeLimit&&this.finalizeVisual());if(e)return this.finalizeVisual(),void this.pushTo(this.routeMessage(i),i);if(this.flushBuilderToHeld(t),t.push(i,s))return void this.nextIndex++;const n=new o(this.beaconSizeLimit,t.version,t.dataType);if(!n.push(i,s))return void console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",i);this.nextIndex++;const h=n.flush();h&&this.heldOther.push({batch:h,dataType:t.dataType})}flushBuilderToHeld(t){const i=t.flush();i&&this.heldOther.push({batch:i,dataType:t.dataType})}finalizeVisual(t=!1){const i=this.playerBuilder.flush(),s=this.assetBuilder.flush();this.visualSent=!0,this.playerBuilder=new o(this.beaconSize,this.playerVersion(),\"player\"),this.assetBuilder=new o(this.beaconSize,3,\"assets\");const e=i&&this.withHeader(i,\"player\",this.playerVersion()),n=s&&this.withHeader(s,\"assets\",3);if(e&&n){const i=new Uint8Array(e.length+n.length);i.set(e,0),i.set(n,e.length),this.emitBatch(i,\"visual\",t,e.length)}else e?this.emitBatch(e,\"player\",t):n&&this.emitBatch(n,\"assets\",t);for(const i of this.heldOther)this.emitBatch(i.batch,i.dataType,t);this.heldOther.length=0,this.flushBuilder(this.devtoolsBuilder,t),this.flushBuilder(this.analyticsBuilder,t)}flushBuilder(t,i=!1){const s=t.flush();return!!s&&(this.emitBatch(s,t.dataType,i),!0)}startsWithMeta(t){return t.length>0&&81===t[0]}repairHeader(t,i){const s=new o(16384,i,\"player\").headerOnly(this.currentCtx());if(!s)return null;const e=new Uint8Array(s.length+t.length);return e.set(s,0),e.set(t,s.length),e}withHeader(t,i,s){if(this.startsWithMeta(t))return t;const e=this.repairHeader(t,s);return console.warn(`OpenReplay: ${i} batch had no leading BatchMetadata (${t.length}B, head ${this.headHex(t)}) — `+(e?\"header rebuilt.\":\"could not rebuild the header, skipping.\")),e}versionOf(t){switch(t){case\"assets\":return 3;case\"devtools\":return 4;case\"analytics\":return 5;default:return this.playerVersion()}}emitBatch(t,i,s,e){const n=void 0===e?this.withHeader(t,i,this.versionOf(i)):t;if(!n)return;let h=e;if(void 0!==h&&!this.isBoundary(n,h)){const t=this.findBoundary(n);if(console.warn(`OpenReplay: ${i} batch split ${String(h)} is not a batch boundary (${n.length}B) — `+(t>0?`corrected to ${t}.`:\"no boundary found, skipping.\")),t<=0)return;h=t}this.localDebug&&this.verifyBody(n,i,h),this.localDebug&&this.onLocalSave&&this.onLocalSave(`${i}-${Date.now()}`,n.slice()),this.onBatch(n,s,i,h)}isBoundary(t,i){return i>0&&i<t.length&&81===t[i]}headHex(t){return Array.from(t.subarray(0,8),t=>t.toString(16).padStart(2,\"0\")).join(\" \")}scanBatch(t){let i=0,s=0;const e=()=>{let s=0,e=0;for(;i<t.length;){const n=t[i++];if(s+=(127&n)*Math.pow(2,e),!(128&n))return s;e+=7}return-1};for(;i<t.length;){const n=i,h=e();if(s++,h<0)return{boundary:-1,fault:`message ${s}: truncated type`};if(81===h){if(s>1)return{boundary:n,fault:null};for(let t=0;t<4;t++)if(e()<0)return{boundary:-1,fault:\"truncated BatchMetadata\"};const h=e();if(h<0||i+h>t.length)return{boundary:-1,fault:\"truncated BatchMetadata url\"};i+=h;continue}if(1===s)return{boundary:-1,fault:`leading message is type ${h}, not BatchMetadata`};if(i+3>t.length)return{boundary:-1,fault:`message ${s}: truncated size prefix`};const r=t[i]|t[i+1]<<8|t[i+2]<<16;if(i+=3,i+r>t.length)return{boundary:-1,fault:`message ${s}: size ${r} overruns the batch`};i+=r}return{boundary:-1,fault:null}}findBoundary(t){return this.scanBatch(t).boundary}verifyBody(t,i,s){if(void 0!==s)return this.verifyBody(t.subarray(0,s),`${i}:player`),void this.verifyBody(t.subarray(s),`${i}:assets`);const{boundary:e,fault:n}=this.scanBatch(t),h=null!=n?n:e>=0?`BatchMetadata at byte ${e} is not the first message`:null;null!==h&&console.warn(`OpenReplay: malformed ${i} batch — ${h} (${t.length}B, head ${this.headHex(t)}).`)}finaliseBatch(t=!1){this.initActive()?this.finalizeVisual(t):(this.flushBuilder(this.playerBuilder,t),this.flushBuilder(this.assetBuilder,t),this.flushBuilder(this.devtoolsBuilder,t),this.flushBuilder(this.analyticsBuilder,t))}clean(){this.playerBuilder.reset(),this.assetBuilder.reset(),this.devtoolsBuilder.reset(),this.analyticsBuilder.reset(),this.heldOther.length=0,this.visualSent=!1,this.signalSeen=!1}}var c;!function(t){t[t.NotActive=0]=\"NotActive\",t[t.Starting=1]=\"Starting\",t[t.Stopping=2]=\"Stopping\",t[t.Active=3]=\"Active\",t[t.Stopped=4]=\"Stopped\"}(c||(c={}));let d=null,p=null,f=c.NotActive;function g(t){p&&p.finaliseBatch(t)}function y(){return new Promise(t=>{f=c.Stopping,null!==B&&(clearInterval(B),B=null),p&&(p.clean(),p=null),d&&(d.clean(),setTimeout(()=>{d=null},20)),setTimeout(()=>{f=c.NotActive,t(null)},100)})}function m(){[c.Stopped,c.Stopping].includes(f)||(postMessage(\"a_stop\"),y().then(()=>{postMessage(\"a_start\")}))}let b,B=null;self.onmessage=({data:t})=>{var i;if(\"stop\"===t)return g(),void y().then(()=>{f=c.Stopped});if(\"forceFlushBatch\"!==t){if(\"closing\"===t)return g(!0),void(null==d||d.flushAll());if(!Array.isArray(t))return\"start\"===t.type?(f=c.Starting,d=new s(t.ingestPoint,()=>{m()},t=>{!function(t){postMessage({type:\"failure\",reason:t}),y()}(t)},t.connAttemptCount,t.connAttemptGap,t.pageNo,t.compressionThreshold),p=new l(t.pageNo,t.timestamp,t.url,(t,i,s=\"player\",e)=>{d&&d.push(t,s,e,i)},t.tabId,()=>postMessage({type:\"queue_empty\"}),null!==(i=t.localDebug)&&void 0!==i&&i,(t,i)=>{postMessage({type:\"local_save\",name:t,batch:i},[i.buffer])}),null===B&&(B=setInterval(g,3e4)),f=c.Active):\"auth\"===t.type?d?p?(\"number\"==typeof t.compressionThreshold&&d.setCompressionThreshold(t.compressionThreshold),d.authorise(t.token),t.beaconSizeLimit&&p.setBeaconSizeLimit(t.beaconSizeLimit),void(t.protocolVersion&&p.setProtocolVersion(t.protocolVersion))):(console.debug(\"OR WebWorker: writer not initialised. Received auth.\"),void m()):(console.debug(\"OR WebWorker: sender not initialised. Received auth.\"),void m()):void 0;if(p){const i=p;t.forEach(t=>{55===t[0]&&(t[1]?b=setTimeout(()=>m(),18e5):clearTimeout(b)),i.writeMessage(t)})}else postMessage(\"not_init\"),m()}else g()}}();\n";
4299
4383
  const CANCELED = 'canceled';
4300
4384
  const bufferStorageKey = 'or_buffer_1';
4301
4385
  const UnsuccessfulStart = (reason) => ({ reason, success: false });
@@ -4360,9 +4444,8 @@ class App {
4360
4444
  this.stopCallbacks = [];
4361
4445
  this.commitCallbacks = [];
4362
4446
  this.activityState = ActivityState.NotActive;
4363
- this.version = '18.1.3'; // TODO: version compatability check inside each plugin.
4447
+ this.version = '18.1.5'; // TODO: version compatability check inside each plugin.
4364
4448
  this.socketMode = false;
4365
- this.compressionThreshold = 24 * 1000;
4366
4449
  this.bc = null;
4367
4450
  this.canvasRecorder = null;
4368
4451
  this.conditionsManager = null;
@@ -5358,35 +5441,6 @@ class App {
5358
5441
  this.debug.error('worker_failed', data.reason);
5359
5442
  this._debug('worker_failed', data.reason);
5360
5443
  }
5361
- else if (data.type === 'compress') {
5362
- const batch = data.batch;
5363
- const dataType = data.dataType;
5364
- // split is a decompressed-byte offset, so it survives gzip unchanged.
5365
- const split = data.split;
5366
- const batchSize = batch.byteLength;
5367
- const hasCompressionAPI = 'CompressionStream' in globalThis;
5368
- if (batchSize > this.compressionThreshold && hasCompressionAPI) {
5369
- const blob = new Blob([batch]);
5370
- const stream = blob.stream().pipeThrough(new CompressionStream('gzip'));
5371
- new Response(stream)
5372
- .arrayBuffer()
5373
- .then((compressedBuffer) => {
5374
- this.worker?.postMessage({
5375
- type: 'compressed',
5376
- batch: new Uint8Array(compressedBuffer),
5377
- dataType,
5378
- split,
5379
- });
5380
- })
5381
- .catch((err) => {
5382
- this.debug.error('Openreplay compression error:', err);
5383
- this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType, split });
5384
- });
5385
- }
5386
- else {
5387
- this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType, split });
5388
- }
5389
- }
5390
5444
  else if (data.type === 'local_save') {
5391
5445
  const blob = new Blob([data.batch], { type: 'application/octet-stream' });
5392
5446
  const url = URL.createObjectURL(blob);
@@ -5995,6 +6049,7 @@ class App {
5995
6049
  token,
5996
6050
  beaconSizeLimit,
5997
6051
  protocolVersion,
6052
+ compressionThreshold,
5998
6053
  });
5999
6054
  }
6000
6055
  if (!isNewSession && token === sessionToken) {
@@ -6005,7 +6060,6 @@ class App {
6005
6060
  // (Re)send Metadata for the case of a new session
6006
6061
  Object.entries(this.session.getInfo().metadata).forEach(([key, value]) => this.send(Metadata(key, value)));
6007
6062
  this.localStorage.setItem(this.options.local_uuid_key, userUUID);
6008
- this.compressionThreshold = compressionThreshold;
6009
6063
  const onStartInfo = { sessionToken: token, userUUID, sessionID };
6010
6064
  // TODO: start as early as possible (before receiving the token)
6011
6065
  /** after start */
@@ -6936,12 +6990,24 @@ function Input (app, opts) {
6936
6990
  }));
6937
6991
  }
6938
6992
 
6939
- const cssEscape = (typeof CSS !== 'undefined' && CSS.escape) || ((t) => t);
6940
6993
  const docClassCache = new WeakMap();
6941
- function _getSelector(target) {
6942
- const selector = getCSSPath(target);
6994
+ function _getSelector(target, customAttributes) {
6995
+ const selector = getCSSPath(target, customAttributes);
6943
6996
  return selector || '';
6944
6997
  }
6998
+ /**
6999
+ * short selector for elements we don't build a full css path for
7000
+ * (non-clickable targets, or a label fallback when clickmaps are off)
7001
+ * */
7002
+ function getCheapSelector(target, customAttributes) {
7003
+ const attributeSelector = getCustomAttributeSelector(target, customAttributes);
7004
+ if (attributeSelector)
7005
+ return attributeSelector;
7006
+ if (target.id)
7007
+ return `#${cssEscape(target.id)}`;
7008
+ const uniqueClass = getUniqueWordLikeClass(target);
7009
+ return uniqueClass ? `${target.tagName.toLowerCase()}.${cssEscape(uniqueClass)}` : '';
7010
+ }
6945
7011
  function isClickable(element) {
6946
7012
  const tag = element.tagName.toUpperCase();
6947
7013
  return (tag === 'BUTTON' ||
@@ -6955,14 +7021,79 @@ function isClickable(element) {
6955
7021
  //|| element.className.includes("btn")
6956
7022
  // MBTODO: intercept addEventListener
6957
7023
  }
7024
+ const CLICKABLE_ROLES = [
7025
+ 'button',
7026
+ 'link',
7027
+ 'tab',
7028
+ 'menuitem',
7029
+ 'menuitemcheckbox',
7030
+ 'menuitemradio',
7031
+ 'option',
7032
+ 'checkbox',
7033
+ 'radio',
7034
+ 'switch',
7035
+ 'combobox',
7036
+ ];
7037
+ const MAX_POINTER_CLIMB = 6;
7038
+ const pointerCursorCache = new WeakMap();
7039
+ function hasPointerCursor(element) {
7040
+ const cached = pointerCursorCache.get(element);
7041
+ if (cached !== undefined)
7042
+ return cached;
7043
+ let isPointer = false;
7044
+ try {
7045
+ const view = element.ownerDocument.defaultView;
7046
+ isPointer = !!view && view.getComputedStyle(element).cursor === 'pointer';
7047
+ }
7048
+ catch {
7049
+ isPointer = false;
7050
+ }
7051
+ pointerCursorCache.set(element, isPointer);
7052
+ return isPointer;
7053
+ }
7054
+ /**
7055
+ * framework handlers (react & co) are delegated to the root, so onclick is null
7056
+ * on the div that visually is a button; these signals catch it instead.
7057
+ * computed style forces a style recalc, so it is only used on the click path
7058
+ * */
7059
+ function looksClickable(element) {
7060
+ return (element.hasAttribute('onclick') ||
7061
+ element.tagName.toUpperCase() === 'SUMMARY' ||
7062
+ element.isContentEditable === true ||
7063
+ CLICKABLE_ROLES.includes(element.getAttribute('role') || '') ||
7064
+ element.tabIndex >= 0);
7065
+ }
7066
+ function isDeepClickable(element) {
7067
+ return isClickable(element) || looksClickable(element) || hasPointerCursor(element);
7068
+ }
7069
+ /**
7070
+ * cursor is inherited, so every child of a clickable div reports a pointer too;
7071
+ * climb to the outermost element that still owns the pointer
7072
+ * */
7073
+ function resolvePointerRoot(element) {
7074
+ let result = element;
7075
+ let parent = element.parentElement;
7076
+ for (let depth = 0; parent !== null && depth < MAX_POINTER_CLIMB; depth++) {
7077
+ if (parent === element.ownerDocument.documentElement || parent === element.ownerDocument.body) {
7078
+ return result;
7079
+ }
7080
+ if (isClickable(parent) || looksClickable(parent))
7081
+ return parent;
7082
+ if (!hasPointerCursor(parent))
7083
+ return result;
7084
+ result = parent;
7085
+ parent = parent.parentElement;
7086
+ }
7087
+ return result;
7088
+ }
6958
7089
  //TODO: fix (typescript is not sure about target variable after assignation of svg)
6959
- function getTarget(target, document) {
7090
+ function getTarget(target, document, deep = false) {
6960
7091
  if (target instanceof Element) {
6961
- return _getTarget(target, document);
7092
+ return _getTarget(target, document, deep);
6962
7093
  }
6963
7094
  return null;
6964
7095
  }
6965
- function _getTarget(target, document) {
7096
+ function _getTarget(target, document, deep = false) {
6966
7097
  let element = target;
6967
7098
  while (element !== null && element !== document.documentElement) {
6968
7099
  if (hasOpenreplayAttribute(element, 'masked')) {
@@ -6989,12 +7120,22 @@ function _getTarget(target, document) {
6989
7120
  if (isClickable(element) || getLabelAttribute(element) !== null) {
6990
7121
  return element;
6991
7122
  }
7123
+ if (deep) {
7124
+ if (looksClickable(element)) {
7125
+ return element;
7126
+ }
7127
+ if (hasPointerCursor(element)) {
7128
+ return resolvePointerRoot(element);
7129
+ }
7130
+ }
6992
7131
  element = element.parentElement;
6993
7132
  }
6994
7133
  return target === document.documentElement ? null : target;
6995
7134
  }
6996
7135
  function Mouse (app, options) {
6997
7136
  const { disableClickmaps = false, customAttributes } = options || {};
7137
+ /** innerText exists on html elements only, svg/jsdom nodes would break the sanitizer */
7138
+ const getSecureInnerText = (el) => typeof el.innerText === 'string' ? app.sanitizer.getInnerTextSecure(el) : '';
6998
7139
  function getTargetLabel(target) {
6999
7140
  const dl = getLabelAttribute(target);
7000
7141
  if (dl !== null) {
@@ -7006,19 +7147,7 @@ function Mouse (app, options) {
7006
7147
  const customAttributeLabel = getCustomAttributeLabel(target, customAttributes);
7007
7148
  if (customAttributeLabel)
7008
7149
  return customAttributeLabel;
7009
- if (target.id)
7010
- return `#${target.id}`;
7011
- const classLabel = getClassSelector(target);
7012
- if (classLabel)
7013
- return classLabel;
7014
- if (isClickable(target)) {
7015
- let label = '';
7016
- if (target instanceof HTMLElement) {
7017
- label = app.sanitizer.getInnerTextSecure(target);
7018
- }
7019
- return normSpaces(label).slice(0, 100);
7020
- }
7021
- return '';
7150
+ return getTextualLabel(target, getSecureInnerText);
7022
7151
  }
7023
7152
  let mousePositionX = -1;
7024
7153
  let mousePositionY = -1;
@@ -7060,6 +7189,9 @@ function Mouse (app, options) {
7060
7189
  clearInterval(checkIntervalId);
7061
7190
  }
7062
7191
  });
7192
+ /** hover is resolved without the computed style check, so it can land on a relative */
7193
+ const isHesitationTarget = (target) => mouseTarget === target ||
7194
+ (mouseTarget !== null && (target.contains(mouseTarget) || mouseTarget.contains(target)));
7063
7195
  const sendMouseMove = () => {
7064
7196
  if (mousePositionChanged) {
7065
7197
  app.send(MouseMove(mousePositionX, mousePositionY));
@@ -7074,7 +7206,12 @@ function Mouse (app, options) {
7074
7206
  if (tagMatch) {
7075
7207
  return (selectorMap[id] = tagMatch.selector);
7076
7208
  }
7077
- return (selectorMap[id] = _getSelector(target));
7209
+ if (!isDeepClickable(target)) {
7210
+ const cheapSelector = getCheapSelector(target, customAttributes);
7211
+ if (cheapSelector)
7212
+ return (selectorMap[id] = cheapSelector);
7213
+ }
7214
+ return (selectorMap[id] = _getSelector(target, customAttributes));
7078
7215
  }
7079
7216
  const attachListener = topframe
7080
7217
  ? app.attachEventListener.bind(app) // attached/removed on start/stop
@@ -7099,7 +7236,7 @@ function Mouse (app, options) {
7099
7236
  }
7100
7237
  }, false);
7101
7238
  attachListener(document, 'click', (e) => {
7102
- const target = getTarget(e.target, document);
7239
+ const target = getTarget(e.target, document, true);
7103
7240
  if ((!e.clientX && !e.clientY) || target === null) {
7104
7241
  return;
7105
7242
  }
@@ -7112,8 +7249,10 @@ function Mouse (app, options) {
7112
7249
  const normalizedX = roundNumber(clickX / contentWidth);
7113
7250
  const normalizedY = roundNumber(clickY / contentHeight);
7114
7251
  sendMouseMove();
7115
- const label = getTargetLabel(target);
7116
- app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, app.sanitizer.privateMode ? label.replaceAll(/./g, '*') : label, isClickable(target) && !disableClickmaps ? getSelector(id, target) : '', normalizedX, normalizedY), true);
7252
+ const selector = disableClickmaps ? '' : getSelector(id, target);
7253
+ // backend drops clicks without a label, so a selector is the last resort
7254
+ const label = getTargetLabel(target) || selector || getCheapSelector(target, customAttributes);
7255
+ app.send(MouseClick(id, isHesitationTarget(target) ? Math.round(performance.now() - mouseTargetTime) : 0, app.sanitizer.privateMode ? label.replaceAll(/./g, '*') : label, selector, normalizedX, normalizedY), true);
7117
7256
  }
7118
7257
  mouseTarget = null;
7119
7258
  });
@@ -7160,18 +7299,27 @@ function wordLike(name) {
7160
7299
  }
7161
7300
  return false;
7162
7301
  }
7163
- function getCSSPath(el) {
7302
+ function getCSSPath(el, customAttributes) {
7164
7303
  if (!el || el.nodeType !== 1)
7165
7304
  return false;
7305
+ // customer configured attributes are the most stable thing we can get
7306
+ const customAttr = getCustomAttributeSelector(el, customAttributes);
7307
+ if (customAttr)
7308
+ return customAttr;
7166
7309
  if (el.id)
7167
7310
  return `#${cssEscape(el.id)}`;
7168
7311
  // if has data attributes - use them as they are more likely to be stable and unique
7169
7312
  const dataAttr = Array.from(el.attributes).find(attr => attr.name.startsWith('data-'));
7170
7313
  if (dataAttr) {
7171
- return `[${dataAttr.name}="${cssEscape(dataAttr.value)}"]`;
7314
+ return `[${dataAttr.name}="${cssAttrValue(dataAttr.value)}"]`;
7172
7315
  }
7173
7316
  const parts = [];
7174
7317
  while (el && el.nodeType === 1 && el !== el.ownerDocument) {
7318
+ const ancestorAttr = getCustomAttributeSelector(el, customAttributes);
7319
+ if (ancestorAttr) {
7320
+ parts.unshift(ancestorAttr);
7321
+ break;
7322
+ }
7175
7323
  if (el.id) {
7176
7324
  parts.unshift(`#${cssEscape(el.id)}`);
7177
7325
  break;
@@ -7205,6 +7353,15 @@ function getCSSPath(el) {
7205
7353
  }
7206
7354
  return parts.join(' > ');
7207
7355
  }
7356
+ function getUniqueWordLikeClass(el) {
7357
+ if (!el.classList?.length)
7358
+ return null;
7359
+ for (const cls of Array.from(el.classList)) {
7360
+ if (wordLike(cls) && isDocUniqueClass(cls, el.ownerDocument))
7361
+ return cls;
7362
+ }
7363
+ return null;
7364
+ }
7208
7365
  function getUniqueSiblingClass(el) {
7209
7366
  if (!el.classList?.length || !el.parentNode)
7210
7367
  return null;
@@ -9787,7 +9944,7 @@ class ConstantProperties {
9787
9944
  user_id: this.user_id,
9788
9945
  distinct_id: this.deviceId,
9789
9946
  sdk_edition: 'web',
9790
- sdk_version: '18.1.3',
9947
+ sdk_version: '18.1.5',
9791
9948
  timezone: getUTCOffsetString(),
9792
9949
  search_engine: this.searchEngine,
9793
9950
  };
@@ -10528,7 +10685,7 @@ class API {
10528
10685
  this.signalStartIssue = (reason, missingApi) => {
10529
10686
  const doNotTrack = this.checkDoNotTrack();
10530
10687
  console.log("Tracker couldn't start due to:", JSON.stringify({
10531
- trackerVersion: '18.1.3',
10688
+ trackerVersion: '18.1.5',
10532
10689
  projectKey: this.options.projectKey,
10533
10690
  doNotTrack,
10534
10691
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,