@openreplay/tracker 17.2.5 → 18.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/dist/lib/index.js CHANGED
@@ -1207,13 +1207,6 @@ function BatchMetadata(version, pageNo, firstIndex, timestamp, location) {
1207
1207
  location,
1208
1208
  ];
1209
1209
  }
1210
- function PartitionedMessage(partNo, partTotal) {
1211
- return [
1212
- 82 /* Messages.Type.PartitionedMessage */,
1213
- partNo,
1214
- partTotal,
1215
- ];
1216
- }
1217
1210
  function NetworkRequest(type, method, url, request, response, status, timestamp, duration, transferredBodySize) {
1218
1211
  return [
1219
1212
  83 /* Messages.Type.NetworkRequest */,
@@ -1425,7 +1418,6 @@ var _Messages = /*#__PURE__*/Object.freeze({
1425
1418
  OTable: OTable,
1426
1419
  PageLoadTiming: PageLoadTiming,
1427
1420
  PageRenderTiming: PageRenderTiming,
1428
- PartitionedMessage: PartitionedMessage,
1429
1421
  PerformanceTrack: PerformanceTrack,
1430
1422
  Profiler: Profiler,
1431
1423
  Redux: Redux,
@@ -1520,11 +1512,157 @@ function Performance (app, opts) {
1520
1512
  }
1521
1513
  }
1522
1514
 
1515
+ /**
1516
+ * Two-tier tag matching:
1517
+ * 1. Fast fingerprint lookup by id, data-attr,
1518
+ * or class from the selector's last segment
1519
+ * 2. Fallback iteration using native element.matches()
1520
+ */
1521
+ class TagMatcher {
1522
+ constructor() {
1523
+ this.tags = [];
1524
+ this.byId = new Map();
1525
+ this.byDataAttr = new Map();
1526
+ this.byClass = new Map();
1527
+ this.fallback = [];
1528
+ }
1529
+ setTags(tags) {
1530
+ this.tags = tags;
1531
+ this.byId.clear();
1532
+ this.byDataAttr.clear();
1533
+ this.byClass.clear();
1534
+ this.fallback = [];
1535
+ for (const tag of tags) {
1536
+ const last = lastSegment(tag.selector);
1537
+ if (!last) {
1538
+ this.fallback.push(tag);
1539
+ continue;
1540
+ }
1541
+ if (last.startsWith('#')) {
1542
+ this.byId.set(last.slice(1), tag);
1543
+ }
1544
+ else if (last.startsWith('[data-')) {
1545
+ this.byDataAttr.set(last, tag);
1546
+ }
1547
+ else {
1548
+ const cls = extractClass(last);
1549
+ if (cls) {
1550
+ this.byClass.set(cls, tag);
1551
+ }
1552
+ else {
1553
+ this.fallback.push(tag);
1554
+ }
1555
+ }
1556
+ }
1557
+ }
1558
+ getTags() {
1559
+ return this.tags;
1560
+ }
1561
+ /** Match element, its parent, or direct children against known tag selectors */
1562
+ match(el) {
1563
+ const direct = this.matchExact(el);
1564
+ if (direct)
1565
+ return direct;
1566
+ if (el.parentElement) {
1567
+ const parent = this.matchExact(el.parentElement);
1568
+ if (parent)
1569
+ return parent;
1570
+ }
1571
+ const children = el.children;
1572
+ for (let i = 0; i < children.length; i++) {
1573
+ const child = this.matchExact(children[i]);
1574
+ if (child)
1575
+ return child;
1576
+ }
1577
+ return null;
1578
+ }
1579
+ matchExact(el) {
1580
+ if (el.id && this.byId.has(el.id)) {
1581
+ const tag = this.byId.get(el.id);
1582
+ if (safeMatches(el, tag.selector) && matchesLocation(tag))
1583
+ return tag;
1584
+ }
1585
+ if (this.byDataAttr.size > 0) {
1586
+ const attrs = el.attributes;
1587
+ for (let i = 0; i < attrs.length; i++) {
1588
+ const attr = attrs[i];
1589
+ if (attr.name.startsWith('data-')) {
1590
+ const key = `[${attr.name}="${attr.value}"]`;
1591
+ if (this.byDataAttr.has(key)) {
1592
+ const tag = this.byDataAttr.get(key);
1593
+ if (safeMatches(el, tag.selector) && matchesLocation(tag))
1594
+ return tag;
1595
+ }
1596
+ }
1597
+ }
1598
+ }
1599
+ if (this.byClass.size > 0 && el.classList) {
1600
+ for (let i = 0; i < el.classList.length; i++) {
1601
+ const cls = el.classList[i];
1602
+ if (this.byClass.has(cls)) {
1603
+ const tag = this.byClass.get(cls);
1604
+ if (safeMatches(el, tag.selector) && matchesLocation(tag))
1605
+ return tag;
1606
+ }
1607
+ }
1608
+ }
1609
+ for (const tag of this.fallback) {
1610
+ if (safeMatches(el, tag.selector) && matchesLocation(tag))
1611
+ return tag;
1612
+ }
1613
+ return null;
1614
+ }
1615
+ clear() {
1616
+ this.tags = [];
1617
+ this.byId.clear();
1618
+ this.byDataAttr.clear();
1619
+ this.byClass.clear();
1620
+ this.fallback = [];
1621
+ }
1622
+ }
1623
+ /** Last combinator-separated segment of a CSS selector */
1624
+ function lastSegment(selector) {
1625
+ const trimmed = selector.trim();
1626
+ if (!trimmed)
1627
+ return null;
1628
+ const parts = trimmed.split(/\s*[>+~ ]\s*/);
1629
+ const last = parts[parts.length - 1]?.trim();
1630
+ return last || null;
1631
+ }
1632
+ /** First class name from a selector segment, e.g. "div.my-class" -> "my-class" */
1633
+ function extractClass(segment) {
1634
+ const match = segment.match(/\.([a-zA-Z_-][\w-]*)/);
1635
+ return match ? match[1] : null;
1636
+ }
1637
+ function safeMatches(el, selector) {
1638
+ try {
1639
+ return el.matches(selector);
1640
+ }
1641
+ catch {
1642
+ return false;
1643
+ }
1644
+ }
1645
+ function matchesLocation(tag) {
1646
+ if (!tag.location)
1647
+ return true;
1648
+ try {
1649
+ const loc = tag.location;
1650
+ if (loc.startsWith('/')) {
1651
+ return window.location.pathname === loc;
1652
+ }
1653
+ return window.location.href === loc;
1654
+ }
1655
+ catch {
1656
+ return true;
1657
+ }
1658
+ }
1659
+
1523
1660
  const WATCHED_TAGS_KEY = '__or__watched_tags__';
1524
1661
  class TagWatcher {
1525
1662
  constructor(params) {
1526
1663
  this.interval = null;
1527
1664
  this.tags = [];
1665
+ this.matcher = new TagMatcher();
1528
1666
  this.sessionStorage = params.sessionStorage;
1529
1667
  this.errLog = params.errLog;
1530
1668
  this.onTag = params.onTag;
@@ -1565,12 +1703,15 @@ class TagWatcher {
1565
1703
  }
1566
1704
  setTags(tags) {
1567
1705
  this.tags = tags;
1706
+ this.matcher.setTags(tags);
1568
1707
  if (this.interval) {
1569
1708
  clearInterval(this.interval);
1570
1709
  this.interval = null;
1571
1710
  }
1572
1711
  this.interval = setInterval(() => {
1573
1712
  this.tags.forEach((tag) => {
1713
+ if (!matchesLocation(tag))
1714
+ return;
1574
1715
  const possibleEls = document.querySelectorAll(tag.selector);
1575
1716
  if (possibleEls.length > 0) {
1576
1717
  const el = possibleEls[0];
@@ -1582,13 +1723,17 @@ class TagWatcher {
1582
1723
  }, 500);
1583
1724
  }
1584
1725
  onTagRendered(tagId) {
1585
- if (this.tags.findIndex(t => t.id === tagId)) {
1586
- this.tags = this.tags.filter((tag) => tag.id !== tagId);
1726
+ const tag = this.tags.find(t => t.id === tagId);
1727
+ if (tag) {
1728
+ this.tags = this.tags.filter((t) => t.id !== tagId);
1729
+ if (!matchesLocation(tag))
1730
+ return;
1587
1731
  }
1588
1732
  this.onTag(tagId);
1589
1733
  }
1590
1734
  clear() {
1591
1735
  this.tags = [];
1736
+ this.matcher.clear();
1592
1737
  if (this.interval) {
1593
1738
  clearInterval(this.interval);
1594
1739
  this.interval = null;
@@ -3754,7 +3899,7 @@ class Ticker {
3754
3899
  * this value is injected during build time via rollup
3755
3900
  * */
3756
3901
  // @ts-ignore
3757
- 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.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){if(this.busy||!this.token)this.queue.push(t);else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t);else{const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}else this.busy=!1}retry(t,s,i){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout((()=>this.sendBatch(t,s,i)),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,s,i){var e;const n=null==i?void 0:i.toString().replace(/^([^_]+)_([^_]+).*/,\"$1_$2_$3\");this.busy=!0;const h={Authorization:`Bearer ${this.token}`};s&&(h[\"Content-Encoding\"]=\"gzip\"),null!==this.token?fetch(`${this.ingestURL}?batch=${null!==(e=this.pageNo)&&void 0!==e?e:\"noPageNum\"}_${null!=n?n:\"noBatchNum\"}`,{body:t,method:\"POST\",headers:h,keepalive:t.length<65536}).then((e=>{if(401===e.status)return this.busy=!1,void this.onUnauthorised();e.status>=400?this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_network:${e.status}`):(this.attemptsCount=0,this.sendNext())})).catch((e=>{console.warn(\"OpenReplay:\",e),this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_reject:${e.message}`)})):setTimeout((()=>{this.sendBatch(t,s,`${null!=i?i:\"noBatchNum\"}_newToken`)}),500)}sendCompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!0,s)}sendUncompressed(t){const s=++this.lastBatchNum;this.sendBatch(t,!1,s)}clean(){this.sendNext(),setTimeout((()=>{this.token=null,this.queue.length=0}),10)}}const s=\"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 i{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,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 i=s.encode(t),e=i.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(i,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}}class e extends i{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:case 82: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 n{constructor(t,s,i,n,h,r){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=n,this.tabId=h,this.onOfflineEnd=r,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new e(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.checkpoints=[],this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}prepare(){if(!this.encoder.isEmpty)return;this.checkpoints.length=0;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url],s=[0,this.timestamp],i=[118,this.tabId];this.writeType(t),this.writeFields(t),this.writeWithSize(s),this.writeWithSize(i),this.isEmpty=!0}writeWithSize(t){const s=this.encoder;if(!this.writeType(t)||!s.skip(3))return!1;const i=s.getCurrentOffset(),e=this.writeFields(t);if(e){const e=s.getCurrentOffset()-i;if(e>16777215)return console.warn(\"OpenReplay: max message size overflow.\"),!1;this.writeSizeAt(e,i-3),s.checkpoint(),this.checkpoints.push(s.getCurrentOffset()),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(-1===t[0])return this.finaliseBatch(),this.onOfflineEnd();0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new e(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",t,this),this.encoder=new e(this.beaconSize),this.prepare()))}finaliseBatch(t=!1){if(this.isEmpty)return;const s=this.encoder.flush();this.onBatch(s,t),this.prepare()}clean(){this.encoder.reset(),this.checkpoints.length=0}}var h;!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\"}(h||(h={}));let r=null,u=null,a=h.NotActive;function o(t){u&&u.finaliseBatch(t)}function c(){return new Promise((t=>{a=h.Stopping,null!==p&&(clearInterval(p),p=null),u&&(u.clean(),u=null),r&&(r.clean(),setTimeout((()=>{r=null}),20)),setTimeout((()=>{a=h.NotActive,t(null)}),100)}))}function g(){[h.Stopped,h.Stopping].includes(a)||(postMessage(\"a_stop\"),c().then((()=>{postMessage(\"a_start\")})))}let l,p=null;self.onmessage=({data:s})=>{if(\"stop\"===s)return o(),void c().then((()=>{a=h.Stopped}));if(\"forceFlushBatch\"!==s)if(\"closing\"!==s){if(!Array.isArray(s)){if(\"compressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Compressed batch.\"),void g();s.batch&&r.sendCompressed(s.batch)}if(\"uncompressed\"===s.type){if(!r)return console.debug(\"OR WebWorker: sender not initialised. Uncompressed batch.\"),void g();s.batch&&r.sendUncompressed(s.batch)}return\"start\"===s.type?(a=h.Starting,r=new t(s.ingestPoint,(()=>{g()}),(t=>{!function(t){postMessage({type:\"failure\",reason:t}),c()}(t)}),s.connAttemptCount,s.connAttemptGap,(t=>{postMessage({type:\"compress\",batch:t},[t.buffer])}),s.pageNo),u=new n(s.pageNo,s.timestamp,s.url,((t,s)=>{r&&(s?r.sendUncompressed(t):r.push(t))}),s.tabId,(()=>postMessage({type:\"queue_empty\"}))),null===p&&(p=setInterval(o,3e4)),a=h.Active):\"auth\"===s.type?r?u?(r.authorise(s.token),void(s.beaconSizeLimit&&u.setBeaconSizeLimit(s.beaconSizeLimit))):(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(u){const t=u;s.forEach((s=>{55===s[0]&&(s[1]?l=setTimeout((()=>g()),18e5):clearTimeout(l)),t.writeMessage(s)}))}else postMessage(\"not_init\"),g()}else o(!0);else o()}}();\n";
3902
+ 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.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\"){if(this.busy||!this.token)this.queue.push({batch:t,dataType:s});else if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t,s);else{const i=++this.lastBatchNum;this.sendBatch(t,!1,i,s)}}sendNext(){const t=this.queue.shift();if(t)if(this.busy=!0,this.isCompressing&&this.onCompress)this.onCompress(t.batch,t.dataType);else{const s=++this.lastBatchNum;this.sendBatch(t.batch,!1,s,t.dataType)}else this.busy=!1}retry(t,s,i,e=\"player\"){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout((()=>this.sendBatch(t,s,i,e)),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t,s,i,e=\"player\"){var n;const h=null==i?void 0:i.toString().replace(/^([^_]+)_([^_]+).*/,\"$1_$2_$3\");this.busy=!0;const r={Authorization:`Bearer ${this.token}`,DataType:e};s&&(r[\"Content-Encoding\"]=\"gzip\"),null!==this.token?fetch(`${this.ingestURL}?batch=${null!==(n=this.pageNo)&&void 0!==n?n:\"noPageNum\"}_${null!=h?h:\"noBatchNum\"}`,{body:t,method:\"POST\",headers:r,keepalive:t.length<65536}).then((n=>{if(401===n.status)return this.busy=!1,void this.onUnauthorised();n.status>=400?this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_network:${n.status}`,e):(this.attemptsCount=0,this.sendNext())})).catch((n=>{console.warn(\"OpenReplay:\",n),this.retry(t,s,`${null!=i?i:\"noBatchNum\"}_reject:${n.message}`,e)})):setTimeout((()=>{this.sendBatch(t,s,`${null!=i?i:\"noBatchNum\"}_newToken`,e)}),500)}sendCompressed(t,s=\"player\"){const i=++this.lastBatchNum;this.sendBatch(t,!0,i,s)}sendUncompressed(t,s=\"player\"){const i=++this.lastBatchNum;this.sendBatch(t,!1,i,s)}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}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}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,e,n,h,a=!1,o){this.pageNo=t,this.timestamp=s,this.url=i,this.onBatch=e,this.tabId=n,this.onOfflineEnd=h,this.localDebug=a,this.onLocalSave=o,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new r(this.beaconSize),this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.prepared=!1,this.checkpoints=[],this.assetMessages=[],this.devtoolsMessages=[],this.analyticsMessages=[],this.firstAssetIndex=0,this.firstAssetTimestamp=0,this.firstDevtoolsIndex=0,this.firstDevtoolsTimestamp=0,this.firstAnalyticsIndex=0,this.firstAnalyticsTimestamp=0,this.protocolVersion=1,this.beaconSizeLimit=1e6}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,s){for(let s=0;s<3;s++)this.sizeBuffer[s]=t>>8*s;this.encoder.set(this.sizeBuffer,s)}prepare(){if(this.prepared)return;this.prepared=!0,this.checkpoints.length=0;const t=[81,2===this.protocolVersion?2:1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const s=this.encoder;if(!this.writeType(t)||!s.skip(3))return!1;const i=s.getCurrentOffset(),e=this.writeFields(t);if(e){const e=s.getCurrentOffset()-i;if(e>16777215)return console.warn(\"OpenReplay: max message size overflow.\"),!1;this.writeSizeAt(e,i-3),s.checkpoint(),this.checkpoints.push(s.getCurrentOffset()),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}setProtocolVersion(t){this.protocolVersion=t}writeMessage(t){if(-1===t[0])return this.finaliseBatch(),this.onOfflineEnd();if(0===t[0]&&(this.timestamp=t[1]),122===t[0]&&(this.url=t[1]),2===this.protocolVersion){if(s.has(t[0]))return 0===this.assetMessages.length&&(this.firstAssetIndex=this.nextIndex,this.firstAssetTimestamp=this.timestamp),this.assetMessages.push(t),void this.nextIndex++;if(i.has(t[0]))return 0===this.devtoolsMessages.length&&(this.firstDevtoolsIndex=this.nextIndex,this.firstDevtoolsTimestamp=this.timestamp),this.devtoolsMessages.push(t),void this.nextIndex++;if(e.has(t[0]))return 0===this.analyticsMessages.length&&(this.firstAnalyticsIndex=this.nextIndex,this.firstAnalyticsTimestamp=this.timestamp),this.analyticsMessages.push(t),void this.nextIndex++}this.prepare(),this.writeWithSize(t)||(this.finaliseBatch(),this.prepare(),this.writeWithSize(t)||(this.encoder=new r(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn(\"OpenReplay: beacon size overflow. Skipping large message.\",t,this),this.encoder=new r(this.beaconSize)))}finaliseBatch(t=!1){const s=this.prepared&&!this.isEmpty,i=this.assetMessages.length>0,e=this.devtoolsMessages.length>0,n=this.analyticsMessages.length>0;if(!(s||i||e||n))return;const h=this.url;if(s){const s=this.encoder.flush();this.localDebug&&this.onLocalSave&&this.onLocalSave(`${Date.now()}-mob`,s.slice()),this.onBatch(s,t,\"player\")}else this.encoder.reset();if(i){const s=this.buildSeparateBatch(3,this.firstAssetIndex,this.firstAssetTimestamp,h,this.assetMessages);this.localDebug&&this.onLocalSave&&this.onLocalSave(`assets-${Date.now()}`,s.slice()),this.onBatch(s,t,\"assets\"),this.assetMessages.length=0}if(e){const s=this.buildSeparateBatch(4,this.firstDevtoolsIndex,this.firstDevtoolsTimestamp,h,this.devtoolsMessages);this.localDebug&&this.onLocalSave&&this.onLocalSave(`devtools-${Date.now()}`,s.slice()),this.onBatch(s,t,\"devtools\"),this.devtoolsMessages.length=0}if(n){const s=this.buildSeparateBatch(5,this.firstAnalyticsIndex,this.firstAnalyticsTimestamp,h,this.analyticsMessages);this.localDebug&&this.onLocalSave&&this.onLocalSave(`analytics-${Date.now()}`,s.slice()),this.onBatch(s,t,\"analytics\"),this.analyticsMessages.length=0}this.prepared=!1}buildSeparateBatch(t,s,i,e,n){const h=new r(this.beaconSizeLimit),a=new Uint8Array(3),o=t=>{h.uint(t[0]),h.skip(3);const s=h.getCurrentOffset();h.encode(t);const i=h.getCurrentOffset()-s;for(let t=0;t<3;t++)a[t]=i>>8*t;h.set(a,s-3),h.checkpoint()},c=[81,t,this.pageNo,s,i,e];h.uint(c[0]),h.encode(c),o([0,i]),o([118,this.tabId]);for(const t of n)o(t);return h.flush()}clean(){this.encoder.reset(),this.checkpoints.length=0,this.assetMessages.length=0,this.devtoolsMessages.length=0,this.analyticsMessages.length=0,this.prepared=!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 c=null,u=null,l=o.NotActive;function p(t){u&&u.finaliseBatch(t)}function g(){return new Promise((t=>{l=o.Stopping,null!==m&&(clearInterval(m),m=null),u&&(u.clean(),u=null),c&&(c.clean(),setTimeout((()=>{c=null}),20)),setTimeout((()=>{l=o.NotActive,t(null)}),100)}))}function f(){[o.Stopped,o.Stopping].includes(l)||(postMessage(\"a_stop\"),g().then((()=>{postMessage(\"a_start\")})))}let d,m=null;self.onmessage=({data:s})=>{var i;if(\"stop\"===s)return p(),void g().then((()=>{l=o.Stopped}));if(\"forceFlushBatch\"!==s)if(\"closing\"!==s){if(!Array.isArray(s)){if(\"compressed\"===s.type){if(!c)return console.debug(\"OR WebWorker: sender not initialised. Compressed batch.\"),void f();s.batch&&c.sendCompressed(s.batch,s.dataType)}if(\"uncompressed\"===s.type){if(!c)return console.debug(\"OR WebWorker: sender not initialised. Uncompressed batch.\"),void f();s.batch&&c.sendUncompressed(s.batch,s.dataType)}return\"start\"===s.type?(l=o.Starting,c=new t(s.ingestPoint,(()=>{f()}),(t=>{!function(t){postMessage({type:\"failure\",reason:t}),g()}(t)}),s.connAttemptCount,s.connAttemptGap,((t,s)=>{postMessage({type:\"compress\",batch:t,dataType:s},[t.buffer])}),s.pageNo),u=new a(s.pageNo,s.timestamp,s.url,((t,s,i=\"player\")=>{if(!c)return;const e=function(t){const s=[];let i=0;const e=()=>{let s=0,e=0;for(;i<t.length;){const n=t[i++];if(s|=(127&n)<<e,!(128&n))return s;e+=7}return null},n=()=>{if(i+3>t.length)return null;const s=t[i]|t[i+1]<<8|t[i+2]<<16;return i+=3,s},h=new Set([80,81,82]);for(;i<t.length;){const t=e();if(null===t)break;if(s.push(t),h.has(t)){if(81===t){e(),e(),e(),e();const t=e();null!==t&&(i+=t)}else 82===t&&(e(),e());continue}const r=n();if(null===r)break;i+=r}return s}(t);console.debug(`[OR batch] dataType=${i} msgs=${e.length} types=`,e),s?c.sendUncompressed(t,i):c.push(t,i)}),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===m&&(m=setInterval(p,3e4)),l=o.Active):\"auth\"===s.type?c?u?(c.authorise(s.token),s.beaconSizeLimit&&u.setBeaconSizeLimit(s.beaconSizeLimit),void(s.protocolVersion&&u.setProtocolVersion(s.protocolVersion))):(console.debug(\"OR WebWorker: writer not initialised. Received auth.\"),void f()):(console.debug(\"OR WebWorker: sender not initialised. Received auth.\"),void f()):void 0}if(u){const t=u;s.forEach((s=>{55===s[0]&&(s[1]?d=setTimeout((()=>f()),18e5):clearTimeout(d)),t.writeMessage(s)}))}else postMessage(\"not_init\"),f()}else p(!0);else p()}}();\n";
3758
3903
  const CANCELED = 'canceled';
3759
3904
  const bufferStorageKey = 'or_buffer_1';
3760
3905
  const UnsuccessfulStart = (reason) => ({ reason, success: false });
@@ -3796,6 +3941,9 @@ const proto = {
3796
3941
  reset: 'reset-your-session-please',
3797
3942
  };
3798
3943
  class App {
3944
+ get tagMatcher() {
3945
+ return this.tagWatcher.matcher;
3946
+ }
3799
3947
  constructor(projectKey, sessionToken, options, signalError, insideIframe) {
3800
3948
  this.signalError = signalError;
3801
3949
  this.insideIframe = insideIframe;
@@ -3810,7 +3958,7 @@ class App {
3810
3958
  this.stopCallbacks = [];
3811
3959
  this.commitCallbacks = [];
3812
3960
  this.activityState = ActivityState.NotActive;
3813
- this.version = '17.2.5'; // TODO: version compatability check inside each plugin.
3961
+ this.version = '18.0.0'; // TODO: version compatability check inside each plugin.
3814
3962
  this.socketMode = false;
3815
3963
  this.compressionThreshold = 24 * 1000;
3816
3964
  this.bc = null;
@@ -3835,6 +3983,9 @@ class App {
3835
3983
  if (this.active())
3836
3984
  return;
3837
3985
  try {
3986
+ if (data.token) {
3987
+ this.session.setSessionToken(data.token, this.projectKey);
3988
+ }
3838
3989
  this.allowAppStart();
3839
3990
  void this.start();
3840
3991
  }
@@ -3975,8 +4126,12 @@ class App {
3975
4126
  }
3976
4127
  if (this.pollingQueue[nextCommand].includes(data.context)) {
3977
4128
  this.pollingQueue[nextCommand] = this.pollingQueue[nextCommand].filter((c) => c !== data.context);
4129
+ const message = { line: nextCommand };
4130
+ if (nextCommand === proto.startIframe) {
4131
+ message.token = this.session.getSessionToken(this.projectKey);
4132
+ }
3978
4133
  // @ts-ignore
3979
- event.source?.postMessage({ line: nextCommand }, '*');
4134
+ event.source?.postMessage(message, '*');
3980
4135
  if (this.pollingQueue[nextCommand].length === 0) {
3981
4136
  this.pollingQueue.order.shift();
3982
4137
  }
@@ -4160,6 +4315,7 @@ class App {
4160
4315
  __is_snippet: false,
4161
4316
  __debug_report_edp: null,
4162
4317
  __debug__: LogLevel.Silent,
4318
+ __local_debug: false,
4163
4319
  localStorage: null,
4164
4320
  sessionStorage: null,
4165
4321
  forceSingleTab: false,
@@ -4401,6 +4557,7 @@ class App {
4401
4557
  }
4402
4558
  else if (data.type === 'compress') {
4403
4559
  const batch = data.batch;
4560
+ const dataType = data.dataType;
4404
4561
  const batchSize = batch.byteLength;
4405
4562
  const hasCompressionAPI = 'CompressionStream' in globalThis;
4406
4563
  if (batchSize > this.compressionThreshold && hasCompressionAPI) {
@@ -4412,17 +4569,27 @@ class App {
4412
4569
  this.worker?.postMessage({
4413
4570
  type: 'compressed',
4414
4571
  batch: new Uint8Array(compressedBuffer),
4572
+ dataType,
4415
4573
  });
4416
4574
  })
4417
4575
  .catch((err) => {
4418
4576
  this.debug.error('Openreplay compression error:', err);
4419
- this.worker?.postMessage({ type: 'uncompressed', batch: batch });
4577
+ this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType });
4420
4578
  });
4421
4579
  }
4422
4580
  else {
4423
- this.worker?.postMessage({ type: 'uncompressed', batch: batch });
4581
+ this.worker?.postMessage({ type: 'uncompressed', batch: batch, dataType });
4424
4582
  }
4425
4583
  }
4584
+ else if (data.type === 'local_save') {
4585
+ const blob = new Blob([data.batch], { type: 'application/octet-stream' });
4586
+ const url = URL.createObjectURL(blob);
4587
+ const a = document.createElement('a');
4588
+ a.href = url;
4589
+ a.download = data.name;
4590
+ a.click();
4591
+ URL.revokeObjectURL(url);
4592
+ }
4426
4593
  else if (data.type === 'queue_empty') {
4427
4594
  this.onSessionSent();
4428
4595
  }
@@ -4461,19 +4628,31 @@ class App {
4461
4628
  this.messages.length = 0;
4462
4629
  return;
4463
4630
  }
4464
- if (this.worker === undefined || !this.messages.length) {
4631
+ if (this.worker === undefined) {
4465
4632
  return;
4466
4633
  }
4467
4634
  if (!this.messages.length) {
4468
- // Release empty batches every 30 secs (1000 * 30ms)
4635
+ // Send a keepalive batch every ~30s (1000 * 30ms) to keep the session active
4469
4636
  if (this.emptyBatchCounter < 1000) {
4470
4637
  this.emptyBatchCounter++;
4471
4638
  return;
4472
4639
  }
4640
+ // Keepalive: send just Timestamp + TabData so the session stays alive
4641
+ this.emptyBatchCounter = 0;
4642
+ try {
4643
+ this.worker?.postMessage([Timestamp(this.timestamp()), TabData(this.session.getTabId())]);
4644
+ }
4645
+ catch (e) {
4646
+ this._debug('worker_keepalive', e);
4647
+ }
4648
+ return;
4473
4649
  }
4474
4650
  this.emptyBatchCounter = 0;
4475
4651
  try {
4476
4652
  requestIdleCb(() => {
4653
+ if (!this.messages.length) {
4654
+ return;
4655
+ }
4477
4656
  this.messages.unshift(Timestamp(this.timestamp()), TabData(this.session.getTabId()));
4478
4657
  this.worker?.postMessage(this.messages);
4479
4658
  this.commitCallbacks.forEach((cb) => cb(this.messages));
@@ -4629,9 +4808,15 @@ class App {
4629
4808
  }
4630
4809
  }
4631
4810
  checkSessionToken(forceNew) {
4632
- const lsReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
4633
- const needNewSessionID = forceNew || lsReset;
4811
+ const PROTO_VERSION = "2";
4812
+ const needReset = this.sessionStorage.getItem(this.options.session_reset_key) !== null;
4813
+ let needNewSessionID = forceNew || needReset;
4634
4814
  const sessionToken = this.session.getSessionToken(this.projectKey);
4815
+ if (sessionToken) {
4816
+ const storedVersion = this.sessionStorage.getItem(`${this.options.session_token_key}_version`);
4817
+ needNewSessionID = !storedVersion || storedVersion !== PROTO_VERSION;
4818
+ this.sessionStorage.setItem(`${this.options.session_token_key}_version`, PROTO_VERSION);
4819
+ }
4635
4820
  return needNewSessionID || !sessionToken;
4636
4821
  }
4637
4822
  /**
@@ -4809,6 +4994,7 @@ class App {
4809
4994
  connAttemptCount: this.options.connAttemptCount,
4810
4995
  connAttemptGap: this.options.connAttemptGap,
4811
4996
  tabId: this.session.getTabId(),
4997
+ localDebug: this.options.__local_debug,
4812
4998
  });
4813
4999
  const r = await fetch(this.options.ingestPoint + '/v1/web/start', {
4814
5000
  method: 'POST',
@@ -4827,11 +5013,12 @@ class App {
4827
5013
  timezone: getTimezone(),
4828
5014
  }),
4829
5015
  });
4830
- const { token, userBrowser, userCity, userCountry, userDevice, userOS, userState, beaconSizeLimit, projectID, } = await r.json();
5016
+ const { token, userBrowser, userCity, userCountry, userDevice, userOS, userState, beaconSizeLimit, projectID, protocolVersion: offlineProtocolVersion, } = await r.json();
4831
5017
  this.worker?.postMessage({
4832
5018
  type: 'auth',
4833
5019
  token,
4834
5020
  beaconSizeLimit,
5021
+ protocolVersion: offlineProtocolVersion,
4835
5022
  });
4836
5023
  this.session.assign({ projectID });
4837
5024
  this.session.setUserInfo({
@@ -4893,6 +5080,7 @@ class App {
4893
5080
  connAttemptCount: this.options.connAttemptCount,
4894
5081
  connAttemptGap: this.options.connAttemptGap,
4895
5082
  tabId: this.session.getTabId(),
5083
+ localDebug: this.options.__local_debug,
4896
5084
  });
4897
5085
  const sessionToken = this.session.getSessionToken(this.projectKey);
4898
5086
  const isNewSession = this.checkSessionToken(startOpts.forceNew);
@@ -4935,7 +5123,7 @@ class App {
4935
5123
  delay, // derived from token
4936
5124
  sessionID, // derived from token
4937
5125
  startTimestamp, // real startTS (server time), derived from sessionID
4938
- userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, framesSupport, assistOnly: socketOnly, } = await r.json();
5126
+ userBrowser, userCity, userCountry, userDevice, userOS, userState, canvasEnabled, canvasQuality, canvasFPS, framesSupport, assistOnly: socketOnly, protocolVersion, } = await r.json();
4939
5127
  if (typeof token !== 'string' ||
4940
5128
  typeof userUUID !== 'string' ||
4941
5129
  (typeof startTimestamp !== 'number' && typeof startTimestamp !== 'undefined') ||
@@ -4976,6 +5164,7 @@ class App {
4976
5164
  type: 'auth',
4977
5165
  token,
4978
5166
  beaconSizeLimit,
5167
+ protocolVersion,
4979
5168
  });
4980
5169
  }
4981
5170
  if (!isNewSession && token === sessionToken) {
@@ -5737,6 +5926,18 @@ function Input (app, opts) {
5737
5926
  defaultInputMode: InputMode.Obscured,
5738
5927
  obscureInputDates: false,
5739
5928
  }, opts);
5929
+ const tagSelectorMap = new Map();
5930
+ function getTagSelector(id, node) {
5931
+ const cached = tagSelectorMap.get(id);
5932
+ if (cached !== undefined)
5933
+ return cached;
5934
+ const tagMatch = app.tagMatcher.match(node);
5935
+ if (tagMatch) {
5936
+ tagSelectorMap.set(id, tagMatch.selector);
5937
+ return tagMatch.selector;
5938
+ }
5939
+ return null;
5940
+ }
5740
5941
  function getInputValue(id, node) {
5741
5942
  let value = node.value;
5742
5943
  let inputMode = options.defaultInputMode;
@@ -5772,6 +5973,7 @@ function Input (app, opts) {
5772
5973
  app.attachStopCallback(() => {
5773
5974
  inputValues.clear();
5774
5975
  checkboxValues.clear();
5976
+ tagSelectorMap.clear();
5775
5977
  });
5776
5978
  function trackInputValue(id, node) {
5777
5979
  if (inputValues.get(id) === node.value) {
@@ -5804,7 +6006,7 @@ function Input (app, opts) {
5804
6006
  }, 3);
5805
6007
  function sendInputChange(id, node, hesitationTime, inputTime) {
5806
6008
  const { value, mask } = getInputValue(id, node);
5807
- let label = getInputLabel(node, options.customAttributes);
6009
+ let label = getTagSelector(id, node) || getInputLabel(node, options.customAttributes);
5808
6010
  if (app.sanitizer.privateMode) {
5809
6011
  label = label.replaceAll(/./g, '*');
5810
6012
  }
@@ -5987,7 +6189,13 @@ function Mouse (app, options) {
5987
6189
  };
5988
6190
  const patchDocument = (document, topframe = false) => {
5989
6191
  function getSelector(id, target) {
5990
- return (selectorMap[id] = selectorMap[id] || _getSelector(target));
6192
+ if (selectorMap[id])
6193
+ return selectorMap[id];
6194
+ const tagMatch = app.tagMatcher.match(target);
6195
+ if (tagMatch) {
6196
+ return (selectorMap[id] = tagMatch.selector);
6197
+ }
6198
+ return (selectorMap[id] = _getSelector(target));
5991
6199
  }
5992
6200
  const attachListener = topframe
5993
6201
  ? app.attachEventListener.bind(app) // attached/removed on start/stop
@@ -8665,7 +8873,7 @@ class ConstantProperties {
8665
8873
  user_id: this.user_id,
8666
8874
  distinct_id: this.deviceId,
8667
8875
  sdk_edition: 'web',
8668
- sdk_version: '17.2.5',
8876
+ sdk_version: '18.0.0',
8669
8877
  timezone: getUTCOffsetString(),
8670
8878
  search_engine: this.searchEngine,
8671
8879
  };
@@ -9367,7 +9575,7 @@ class API {
9367
9575
  this.signalStartIssue = (reason, missingApi) => {
9368
9576
  const doNotTrack = this.checkDoNotTrack();
9369
9577
  console.log("Tracker couldn't start due to:", JSON.stringify({
9370
- trackerVersion: '17.2.5',
9578
+ trackerVersion: '18.0.0',
9371
9579
  projectKey: this.options.projectKey,
9372
9580
  doNotTrack,
9373
9581
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,