@interfere/react 10.0.1-canary.1 → 11.0.0-canary.2
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/README.md +1 -1
- package/dist/api.d.mts.map +1 -1
- package/dist/error-boundary.d.mts.map +1 -1
- package/dist/internal/browser-context.d.mts.map +1 -1
- package/dist/internal/browser-context.mjs.map +1 -1
- package/dist/internal/capture-boundary.d.mts.map +1 -1
- package/dist/internal/capture-boundary.mjs.map +1 -1
- package/dist/internal/config.d.mts.map +1 -1
- package/dist/internal/config.mjs.map +1 -1
- package/dist/internal/console-patch.d.mts.map +1 -1
- package/dist/internal/kernel-registry.d.mts.map +1 -1
- package/dist/internal/kernel.d.mts +10 -2
- package/dist/internal/kernel.d.mts.map +1 -1
- package/dist/internal/kernel.mjs +1 -1
- package/dist/internal/kernel.mjs.map +1 -1
- package/dist/internal/otel/exporter.d.mts.map +1 -1
- package/dist/internal/otel/exporter.mjs.map +1 -1
- package/dist/internal/otel/index.d.mts +2 -2
- package/dist/internal/otel/instrumentations.d.mts +24 -1
- package/dist/internal/otel/instrumentations.d.mts.map +1 -1
- package/dist/internal/otel/instrumentations.mjs +1 -1
- package/dist/internal/otel/instrumentations.mjs.map +1 -1
- package/dist/internal/otel/page-scope-context-manager.d.mts.map +1 -1
- package/dist/internal/otel/propagation.d.mts.map +1 -1
- package/dist/internal/otel/propagation.mjs.map +1 -1
- package/dist/internal/otel/provider.d.mts.map +1 -1
- package/dist/internal/otel/provider.mjs +1 -1
- package/dist/internal/otel/provider.mjs.map +1 -1
- package/dist/internal/page-lifecycle.d.mts +2 -15
- package/dist/internal/page-lifecycle.d.mts.map +1 -1
- package/dist/internal/page-lifecycle.mjs +1 -1
- package/dist/internal/page-lifecycle.mjs.map +1 -1
- package/dist/internal/plugin-runtime.d.mts.map +1 -1
- package/dist/internal/sw.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugins/errors.d.mts.map +1 -1
- package/dist/plugins/errors.mjs.map +1 -1
- package/dist/plugins/lib/loader.d.mts.map +1 -1
- package/dist/plugins/lib/loader.mjs +1 -1
- package/dist/plugins/lib/loader.mjs.map +1 -1
- package/dist/plugins/rage-clicks.d.mts.map +1 -1
- package/dist/plugins/rage-clicks.mjs.map +1 -1
- package/dist/plugins/replay/buffer.d.mts +13 -0
- package/dist/plugins/replay/buffer.d.mts.map +1 -0
- package/dist/plugins/replay/buffer.mjs +1 -0
- package/dist/plugins/replay/buffer.mjs.map +1 -0
- package/dist/plugins/replay/chunking.d.mts +21 -0
- package/dist/plugins/replay/chunking.d.mts.map +1 -0
- package/dist/plugins/replay/chunking.mjs +1 -0
- package/dist/plugins/replay/chunking.mjs.map +1 -0
- package/dist/plugins/replay/compressor-host.d.mts +9 -0
- package/dist/plugins/replay/compressor-host.d.mts.map +1 -0
- package/dist/plugins/replay/compressor-host.mjs +1 -0
- package/dist/plugins/replay/compressor-host.mjs.map +1 -0
- package/dist/plugins/replay/delivery.d.mts +23 -0
- package/dist/plugins/replay/delivery.d.mts.map +1 -0
- package/dist/plugins/replay/delivery.mjs +1 -0
- package/dist/plugins/replay/delivery.mjs.map +1 -0
- package/dist/plugins/replay/index.d.mts +6 -0
- package/dist/plugins/replay/index.d.mts.map +1 -0
- package/dist/plugins/replay/index.mjs +1 -0
- package/dist/plugins/replay/index.mjs.map +1 -0
- package/dist/plugins/replay/recorder.d.mts +8 -0
- package/dist/plugins/replay/recorder.d.mts.map +1 -0
- package/dist/plugins/replay/recorder.mjs +1 -0
- package/dist/plugins/replay/recorder.mjs.map +1 -0
- package/dist/provider.d.mts.map +1 -1
- package/dist/sw.mjs +1 -1
- package/dist/tracking/api.d.mts.map +1 -1
- package/dist/tracking/api.mjs +1 -1
- package/dist/tracking/api.mjs.map +1 -1
- package/dist/tracking/device.d.mts.map +1 -1
- package/dist/tracking/device.mjs.map +1 -1
- package/dist/tracking/geo.d.mts.map +1 -1
- package/dist/tracking/session.d.mts.map +1 -1
- package/dist/util/bot.d.mts.map +1 -1
- package/dist/util/global.d.mts.map +1 -1
- package/dist/util/log.d.mts.map +1 -1
- package/package.json +15 -14
- package/dist/plugins/replay.d.mts +0 -6
- package/dist/plugins/replay.d.mts.map +0 -1
- package/dist/plugins/replay.mjs +0 -1
- package/dist/plugins/replay.mjs.map +0 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/plugins/replay/recorder.d.ts
|
|
2
|
+
interface ReplayRecorder {
|
|
3
|
+
stop(): void;
|
|
4
|
+
takeFullSnapshot(): void;
|
|
5
|
+
}
|
|
6
|
+
declare function startReplayRecorder(onEvent: (event: unknown) => void): Promise<ReplayRecorder | null>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { ReplayRecorder, startReplayRecorder };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.mts","names":[],"sources":["../../../src/plugins/replay/recorder.ts"],"mappings":";UAQiB,cAAA;EACf,IAAA;EACA,gBAAgB;AAAA;AAAA,iBAGI,mBAAA,CACpB,OAAA,GAAU,KAAA,qBACT,OAAO,CAAC,cAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger}from"../../util/log.mjs";const log=createLogger(`replay`);async function startReplayRecorder(onEvent){try{let rrweb=await import(`rrweb`),stop=rrweb.record({emit:onEvent,recordAfter:`load`,inlineStylesheet:!0,slimDOMOptions:`all`,sampling:{mousemove:50,scroll:150,media:800}})??null;return{stop:()=>{stop?.()},takeFullSnapshot:()=>{try{rrweb.record.takeFullSnapshot?.(!0)}catch(error){log.warn(`takeFullSnapshot failed: %o`,error)}}}}catch{return log.error(`rrweb failed to load, replay disabled`),null}}export{startReplayRecorder};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.mjs","names":[],"sources":["../../../src/plugins/replay/recorder.ts"],"sourcesContent":["import { createLogger } from \"../../util/log.js\";\n\nconst log = createLogger(\"replay\");\n\nconst MOUSEMOVE_SAMPLE_MS = 50;\nconst SCROLL_SAMPLE_MS = 150;\nconst MEDIA_SAMPLE_MS = 800;\n\nexport interface ReplayRecorder {\n stop(): void;\n takeFullSnapshot(): void;\n}\n\nexport async function startReplayRecorder(\n onEvent: (event: unknown) => void\n): Promise<ReplayRecorder | null> {\n try {\n const rrweb = await import(\"rrweb\");\n const stop =\n rrweb.record({\n emit: onEvent,\n recordAfter: \"load\",\n inlineStylesheet: true,\n slimDOMOptions: \"all\",\n sampling: {\n mousemove: MOUSEMOVE_SAMPLE_MS,\n scroll: SCROLL_SAMPLE_MS,\n media: MEDIA_SAMPLE_MS,\n },\n }) ?? null;\n\n return {\n stop: () => {\n stop?.();\n },\n takeFullSnapshot: () => {\n try {\n rrweb.record.takeFullSnapshot?.(true);\n } catch (error) {\n log.warn(\"takeFullSnapshot failed: %o\", error);\n }\n },\n };\n } catch {\n log.error(\"rrweb failed to load, replay disabled\");\n return null;\n }\n}\n"],"mappings":"6CAEA,MAAM,IAAM,aAAa,QAAQ,EAWjC,eAAsB,oBACpB,QACgC,CAChC,GAAI,CACF,IAAM,MAAQ,MAAM,OAAO,SACrB,KACJ,MAAM,OAAO,CACX,KAAM,QACN,YAAa,OACb,iBAAkB,GAClB,eAAgB,MAChB,SAAU,CACR,UAAW,GACX,OAAQ,IACR,MAAO,GACT,CACF,CAAC,GAAK,KAER,MAAO,CACL,SAAY,CACV,OAAO,CACT,EACA,qBAAwB,CACtB,GAAI,CACF,MAAM,OAAO,mBAAmB,EAAI,CACtC,OAAS,MAAO,CACd,IAAI,KAAK,8BAA+B,KAAK,CAC/C,CACF,CACF,CACF,MAAQ,CAEN,OADA,IAAI,MAAM,uCAAuC,EAC1C,IACT,CACF"}
|
package/dist/provider.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;;UAmBU,sBAAA,SAA+B,iBAAA;EACvC,OAAA,GAAU,YAAA;EADF;;;;;;;;;;;;;;;AAyBM;EAPd,aAAA;EAU+B;;;;;;EAH/B,MAAA,EAAQ,MAAA;AAAA;AAAA,iBAGM,iBAAA
|
|
1
|
+
{"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;;UAmBU,sBAAA,SAA+B,iBAAA;EACvC,OAAA,GAAU,YAAA;EADF;;;;;;;;;;;;;;;AAyBM;EAPd,aAAA;EAU+B;;;;;;EAH/B,MAAA,EAAQ,MAAA;AAAA;AAAA,iBAGM,iBAAA;EACd,MAAA;EACA,QAAA;EACA,OAAA;EACA;AAAA,GACC,sBAAA,GAAyB,SAAA;AAAA,iBAwBZ,YAAA,IAAgB,qBAAqB;AAAA,iBAQrC,UAAA"}
|
package/dist/sw.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// AUTOGENERATED by scripts/build-sw.ts — do not edit.
|
|
2
|
-
export const SW_SCRIPT = "(function(){try{self[`workbox:core:7.4.0`]&&_()}catch{}let e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n};var t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}};let n=(e,t)=>t.some(t=>e instanceof t),r,i;function a(){return r||=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]}function o(){return i||=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey]}let s=new WeakMap,c=new WeakMap,l=new WeakMap,u=new WeakMap,d=new WeakMap;function f(e){let t=new Promise((t,n)=>{let r=()=>{e.removeEventListener(`success`,i),e.removeEventListener(`error`,a)},i=()=>{t(y(e.result)),r()},a=()=>{n(e.error),r()};e.addEventListener(`success`,i),e.addEventListener(`error`,a)});return t.then(t=>{t instanceof IDBCursor&&s.set(t,e)}).catch(()=>{}),d.set(t,e),t}function p(e){if(c.has(e))return;let t=new Promise((t,n)=>{let r=()=>{e.removeEventListener(`complete`,i),e.removeEventListener(`error`,a),e.removeEventListener(`abort`,a)},i=()=>{t(),r()},a=()=>{n(e.error||new DOMException(`AbortError`,`AbortError`)),r()};e.addEventListener(`complete`,i),e.addEventListener(`error`,a),e.addEventListener(`abort`,a)});c.set(e,t)}let m={get(e,t,n){if(e instanceof IDBTransaction){if(t===`done`)return c.get(e);if(t===`objectStoreNames`)return e.objectStoreNames||l.get(e);if(t===`store`)return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return y(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t===`done`||t===`store`)?!0:t in e}};function h(e){m=e(m)}function g(e){return e===IDBDatabase.prototype.transaction&&!(`objectStoreNames`in IDBTransaction.prototype)?function(t,...n){let r=e.call(b(this),t,...n);return l.set(r,t.sort?t.sort():[t]),y(r)}:o().includes(e)?function(...t){return e.apply(b(this),t),y(s.get(this))}:function(...t){return y(e.apply(b(this),t))}}function v(e){return typeof e==`function`?g(e):(e instanceof IDBTransaction&&p(e),n(e,a())?new Proxy(e,m):e)}function y(e){if(e instanceof IDBRequest)return f(e);if(u.has(e))return u.get(e);let t=v(e);return t!==e&&(u.set(e,t),d.set(t,e)),t}let b=e=>d.get(e);function x(e,t,{blocked:n,upgrade:r,blocking:i,terminated:a}={}){let o=indexedDB.open(e,t),s=y(o);return r&&o.addEventListener(`upgradeneeded`,e=>{r(y(o.result),e.oldVersion,e.newVersion,y(o.transaction),e)}),n&&o.addEventListener(`blocked`,e=>n(e.oldVersion,e.newVersion,e)),s.then(e=>{a&&e.addEventListener(`close`,()=>a()),i&&e.addEventListener(`versionchange`,e=>i(e.oldVersion,e.newVersion,e))}).catch(()=>{}),s}let S=[`get`,`getKey`,`getAll`,`getAllKeys`,`count`],C=[`put`,`add`,`delete`,`clear`],w=new Map;function T(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t==`string`))return;if(w.get(t))return w.get(t);let n=t.replace(/FromIndex$/,``),r=t!==n,i=C.includes(n);if(!(n in(r?IDBIndex:IDBObjectStore).prototype)||!(i||S.includes(n)))return;let a=async function(e,...t){let a=this.transaction(e,i?`readwrite`:`readonly`),o=a.store;return r&&(o=o.index(t.shift())),(await Promise.all([o[n](...t),i&&a.done]))[0]};return w.set(t,a),a}h(e=>({...e,get:(t,n,r)=>T(t,n)||e.get(t,n,r),has:(t,n)=>!!T(t,n)||e.has(t,n)}));try{self[`workbox:background-sync:7.4.0`]&&_()}catch{}let E=`requests`,D=`queueName`;var O=class{constructor(){this._db=null}async addEntry(e){let t=(await this.getDb()).transaction(E,`readwrite`,{durability:`relaxed`});await t.store.add(e),await t.done}async getFirstEntryId(){return(await(await this.getDb()).transaction(E).store.openCursor())?.value.id}async getAllEntriesByQueueName(e){return await(await this.getDb()).getAllFromIndex(E,D,IDBKeyRange.only(e))||[]}async getEntryCountByQueueName(e){return(await this.getDb()).countFromIndex(E,D,IDBKeyRange.only(e))}async deleteEntry(e){await(await this.getDb()).delete(E,e)}async getFirstEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),`next`)}async getLastEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),`prev`)}async getEndEntryFromIndex(e,t){return(await(await this.getDb()).transaction(E).store.index(D).openCursor(e,t))?.value}async getDb(){return this._db||=await x(`workbox-background-sync`,3,{upgrade:this._upgradeDb}),this._db}_upgradeDb(e,t){t>0&&t<3&&e.objectStoreNames.contains(E)&&e.deleteObjectStore(E),e.createObjectStore(E,{autoIncrement:!0,keyPath:`id`}).createIndex(D,D,{unique:!1})}},k=class{constructor(e){this._queueName=e,this._queueDb=new O}async pushEntry(e){delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async unshiftEntry(e){let t=await this._queueDb.getFirstEntryId();t?e.id=t-1:delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async popEntry(){return this._removeEntry(await this._queueDb.getLastEntryByQueueName(this._queueName))}async shiftEntry(){return this._removeEntry(await this._queueDb.getFirstEntryByQueueName(this._queueName))}async getAll(){return await this._queueDb.getAllEntriesByQueueName(this._queueName)}async size(){return await this._queueDb.getEntryCountByQueueName(this._queueName)}async deleteEntry(e){await this._queueDb.deleteEntry(e)}async _removeEntry(e){return e&&await this.deleteEntry(e.id),e}};let A=[`method`,`referrer`,`referrerPolicy`,`mode`,`credentials`,`cache`,`redirect`,`integrity`,`keepalive`];var j=class e{static async fromRequest(t){let n={url:t.url,headers:{}};t.method!==`GET`&&(n.body=await t.clone().arrayBuffer());for(let[e,r]of t.headers.entries())n.headers[e]=r;for(let e of A)t[e]!==void 0&&(n[e]=t[e]);return new e(n)}constructor(e){e.mode===`navigate`&&(e.mode=`same-origin`),this._requestData=e}toObject(){let e=Object.assign({},this._requestData);return e.headers=Object.assign({},this._requestData.headers),e.body&&=e.body.slice(0),e}toRequest(){return new Request(this._requestData.url,this._requestData)}clone(){return new e(this.toObject())}};let M=`workbox-background-sync`,N=new Set,P=e=>{let t={request:new j(e.requestData).toRequest(),timestamp:e.timestamp};return e.metadata&&(t.metadata=e.metadata),t};var F=class{constructor(e,{forceSyncFallback:n,onSync:r,maxRetentionTime:i}={}){if(this._syncInProgress=!1,this._requestsAddedDuringSync=!1,N.has(e))throw new t(`duplicate-queue-name`,{name:e});N.add(e),this._name=e,this._onSync=r||this.replayRequests,this._maxRetentionTime=i||10080,this._forceSyncFallback=!!n,this._queueStore=new k(this._name),this._addSyncListener()}get name(){return this._name}async pushRequest(e){await this._addRequest(e,`push`)}async unshiftRequest(e){await this._addRequest(e,`unshift`)}async popRequest(){return this._removeRequest(`pop`)}async shiftRequest(){return this._removeRequest(`shift`)}async getAll(){let e=await this._queueStore.getAll(),t=Date.now(),n=[];for(let r of e){let e=this._maxRetentionTime*60*1e3;t-r.timestamp>e?await this._queueStore.deleteEntry(r.id):n.push(P(r))}return n}async size(){return await this._queueStore.size()}async _addRequest({request:e,metadata:t,timestamp:n=Date.now()},r){let i={requestData:(await j.fromRequest(e.clone())).toObject(),timestamp:n};switch(t&&(i.metadata=t),r){case`push`:await this._queueStore.pushEntry(i);break;case`unshift`:await this._queueStore.unshiftEntry(i);break}this._syncInProgress?this._requestsAddedDuringSync=!0:await this.registerSync()}async _removeRequest(e){let t=Date.now(),n;switch(e){case`pop`:n=await this._queueStore.popEntry();break;case`shift`:n=await this._queueStore.shiftEntry();break}if(n){let r=this._maxRetentionTime*60*1e3;return t-n.timestamp>r?this._removeRequest(e):P(n)}else return}async replayRequests(){let e;for(;e=await this.shiftRequest();)try{await fetch(e.request.clone())}catch{throw await this.unshiftRequest(e),new t(`queue-replay-failed`,{name:this._name})}}async registerSync(){if(`sync`in self.registration&&!this._forceSyncFallback)try{await self.registration.sync.register(`${M}:${this._name}`)}catch{}}_addSyncListener(){`sync`in self.registration&&!this._forceSyncFallback?self.addEventListener(`sync`,e=>{e.tag===`${M}:${this._name}`&&e.waitUntil((async()=>{this._syncInProgress=!0;let t;try{await this._onSync({queue:this})}catch(e){if(e instanceof Error)throw t=e,t}finally{this._requestsAddedDuringSync&&!(t&&!e.lastChance)&&await this.registerSync(),this._syncInProgress=!1,this._requestsAddedDuringSync=!1}})())}):this._onSync({queue:this})}static get _queueNames(){return N}};let I={status:202,statusText:`Queued`};async function L(e){let t=await self.clients.matchAll({includeUncontrolled:!1});for(let n of t)n.postMessage(e)}async function R(e){let t=await e.getAll(),n=0;for(let e of t){let t=e.metadata;typeof t?.bytes==`number`&&(n+=t.bytes)}return n}async function z(e,t){let n=await R(e);for(;n+t>10485760;){let t=await e.shiftRequest();if(!t)break;let r=t.metadata;n-=r?.bytes??0,await L({type:`interfere.sw.dropped`,url:t.request.url,reason:`queue_size_cap`})}}async function B(e,t){let n=t.clone(),r=(await n.clone().arrayBuffer()).byteLength;await z(e,r),await e.pushRequest({request:n,metadata:{bytes:r}}),await L({type:`interfere.sw.queued`,url:t.url})}let V=new F(`interfere-ingest`,{maxRetentionTime:1440,onSync:async({queue:e})=>{let t=await e.shiftRequest();for(;t;){try{let e=await fetch(t.request.clone());if(!e.ok&&(e.status>=500||e.status===429))throw Error(`retry status ${e.status}`);await L({type:`interfere.sw.replayed`,url:t.request.url})}catch(n){throw await e.unshiftRequest(t),n}t=await e.shiftRequest()}}});self.addEventListener(`install`,()=>{self.skipWaiting()}),self.addEventListener(`activate`,e=>{e.waitUntil((async()=>{await self.clients.claim(),V.replayRequests().catch(()=>{})})())}),self.addEventListener(`fetch`,e=>{let{request:t}=e;if(t.method!==`POST`)return;let n;try{n=new URL(t.url)}catch{return}n.pathname.startsWith(`/api/interfere/`)&&e.respondWith((async()=>{try{let e=await fetch(t.clone());return e.ok?e:e.status>=500||e.status===429?(await B(V,t),new Response(null,I)):e}catch{return await B(V,t),new Response(null,I)}})())})})();";
|
|
2
|
+
export const SW_SCRIPT = "(function(){try{self[`workbox:core:7.4.0`]&&_()}catch{}let e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n};var t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}};let n=(e,t)=>t.some(t=>e instanceof t),r,i;function a(){return r||=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]}function o(){return i||=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey]}let s=new WeakMap,c=new WeakMap,l=new WeakMap,u=new WeakMap,d=new WeakMap;function f(e){let t=new Promise((t,n)=>{let r=()=>{e.removeEventListener(`success`,i),e.removeEventListener(`error`,a)},i=()=>{t(y(e.result)),r()},a=()=>{n(e.error),r()};e.addEventListener(`success`,i),e.addEventListener(`error`,a)});return t.then(t=>{t instanceof IDBCursor&&s.set(t,e)}).catch(()=>{}),d.set(t,e),t}function p(e){if(c.has(e))return;let t=new Promise((t,n)=>{let r=()=>{e.removeEventListener(`complete`,i),e.removeEventListener(`error`,a),e.removeEventListener(`abort`,a)},i=()=>{t(),r()},a=()=>{n(e.error||new DOMException(`AbortError`,`AbortError`)),r()};e.addEventListener(`complete`,i),e.addEventListener(`error`,a),e.addEventListener(`abort`,a)});c.set(e,t)}let m={get(e,t,n){if(e instanceof IDBTransaction){if(t===`done`)return c.get(e);if(t===`objectStoreNames`)return e.objectStoreNames||l.get(e);if(t===`store`)return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return y(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t===`done`||t===`store`)?!0:t in e}};function h(e){m=e(m)}function g(e){return e===IDBDatabase.prototype.transaction&&!(`objectStoreNames`in IDBTransaction.prototype)?function(t,...n){let r=e.call(b(this),t,...n);return l.set(r,t.sort?t.sort():[t]),y(r)}:o().includes(e)?function(...t){return e.apply(b(this),t),y(s.get(this))}:function(...t){return y(e.apply(b(this),t))}}function v(e){return typeof e==`function`?g(e):(e instanceof IDBTransaction&&p(e),n(e,a())?new Proxy(e,m):e)}function y(e){if(e instanceof IDBRequest)return f(e);if(u.has(e))return u.get(e);let t=v(e);return t!==e&&(u.set(e,t),d.set(t,e)),t}let b=e=>d.get(e);function x(e,t,{blocked:n,upgrade:r,blocking:i,terminated:a}={}){let o=indexedDB.open(e,t),s=y(o);return r&&o.addEventListener(`upgradeneeded`,e=>{r(y(o.result),e.oldVersion,e.newVersion,y(o.transaction),e)}),n&&o.addEventListener(`blocked`,e=>n(e.oldVersion,e.newVersion,e)),s.then(e=>{a&&e.addEventListener(`close`,()=>a()),i&&e.addEventListener(`versionchange`,e=>i(e.oldVersion,e.newVersion,e))}).catch(()=>{}),s}let S=[`get`,`getKey`,`getAll`,`getAllKeys`,`count`],C=[`put`,`add`,`delete`,`clear`],w=new Map;function T(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t==`string`))return;if(w.get(t))return w.get(t);let n=t.replace(/FromIndex$/,``),r=t!==n,i=C.includes(n);if(!(n in(r?IDBIndex:IDBObjectStore).prototype)||!(i||S.includes(n)))return;let a=async function(e,...t){let a=this.transaction(e,i?`readwrite`:`readonly`),o=a.store;return r&&(o=o.index(t.shift())),(await Promise.all([o[n](...t),i&&a.done]))[0]};return w.set(t,a),a}h(e=>({...e,get:(t,n,r)=>T(t,n)||e.get(t,n,r),has:(t,n)=>!!T(t,n)||e.has(t,n)}));try{self[`workbox:background-sync:7.4.0`]&&_()}catch{}let E=`requests`,D=`queueName`;var O=class{constructor(){this._db=null}async addEntry(e){let t=(await this.getDb()).transaction(E,`readwrite`,{durability:`relaxed`});await t.store.add(e),await t.done}async getFirstEntryId(){return(await(await this.getDb()).transaction(E).store.openCursor())?.value.id}async getAllEntriesByQueueName(e){return await(await this.getDb()).getAllFromIndex(E,D,IDBKeyRange.only(e))||[]}async getEntryCountByQueueName(e){return(await this.getDb()).countFromIndex(E,D,IDBKeyRange.only(e))}async deleteEntry(e){await(await this.getDb()).delete(E,e)}async getFirstEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),`next`)}async getLastEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),`prev`)}async getEndEntryFromIndex(e,t){return(await(await this.getDb()).transaction(E).store.index(D).openCursor(e,t))?.value}async getDb(){return this._db||=await x(`workbox-background-sync`,3,{upgrade:this._upgradeDb}),this._db}_upgradeDb(e,t){t>0&&t<3&&e.objectStoreNames.contains(E)&&e.deleteObjectStore(E),e.createObjectStore(E,{autoIncrement:!0,keyPath:`id`}).createIndex(D,D,{unique:!1})}},k=class{constructor(e){this._queueName=e,this._queueDb=new O}async pushEntry(e){delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async unshiftEntry(e){let t=await this._queueDb.getFirstEntryId();t?e.id=t-1:delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async popEntry(){return this._removeEntry(await this._queueDb.getLastEntryByQueueName(this._queueName))}async shiftEntry(){return this._removeEntry(await this._queueDb.getFirstEntryByQueueName(this._queueName))}async getAll(){return await this._queueDb.getAllEntriesByQueueName(this._queueName)}async size(){return await this._queueDb.getEntryCountByQueueName(this._queueName)}async deleteEntry(e){await this._queueDb.deleteEntry(e)}async _removeEntry(e){return e&&await this.deleteEntry(e.id),e}};let A=[`method`,`referrer`,`referrerPolicy`,`mode`,`credentials`,`cache`,`redirect`,`integrity`,`keepalive`];var j=class e{static async fromRequest(t){let n={url:t.url,headers:{}};t.method!==`GET`&&(n.body=await t.clone().arrayBuffer());for(let[e,r]of t.headers.entries())n.headers[e]=r;for(let e of A)t[e]!==void 0&&(n[e]=t[e]);return new e(n)}constructor(e){e.mode===`navigate`&&(e.mode=`same-origin`),this._requestData=e}toObject(){let e=Object.assign({},this._requestData);return e.headers=Object.assign({},this._requestData.headers),e.body&&=e.body.slice(0),e}toRequest(){return new Request(this._requestData.url,this._requestData)}clone(){return new e(this.toObject())}};let M=`workbox-background-sync`,N=new Set,P=e=>{let t={request:new j(e.requestData).toRequest(),timestamp:e.timestamp};return e.metadata&&(t.metadata=e.metadata),t};var F=class{constructor(e,{forceSyncFallback:n,onSync:r,maxRetentionTime:i}={}){if(this._syncInProgress=!1,this._requestsAddedDuringSync=!1,N.has(e))throw new t(`duplicate-queue-name`,{name:e});N.add(e),this._name=e,this._onSync=r||this.replayRequests,this._maxRetentionTime=i||10080,this._forceSyncFallback=!!n,this._queueStore=new k(this._name),this._addSyncListener()}get name(){return this._name}async pushRequest(e){await this._addRequest(e,`push`)}async unshiftRequest(e){await this._addRequest(e,`unshift`)}async popRequest(){return this._removeRequest(`pop`)}async shiftRequest(){return this._removeRequest(`shift`)}async getAll(){let e=await this._queueStore.getAll(),t=Date.now(),n=[];for(let r of e){let e=this._maxRetentionTime*60*1e3;t-r.timestamp>e?await this._queueStore.deleteEntry(r.id):n.push(P(r))}return n}async size(){return await this._queueStore.size()}async _addRequest({request:e,metadata:t,timestamp:n=Date.now()},r){let i={requestData:(await j.fromRequest(e.clone())).toObject(),timestamp:n};switch(t&&(i.metadata=t),r){case`push`:await this._queueStore.pushEntry(i);break;case`unshift`:await this._queueStore.unshiftEntry(i);break}this._syncInProgress?this._requestsAddedDuringSync=!0:await this.registerSync()}async _removeRequest(e){let t=Date.now(),n;switch(e){case`pop`:n=await this._queueStore.popEntry();break;case`shift`:n=await this._queueStore.shiftEntry();break}if(n){let r=this._maxRetentionTime*60*1e3;return t-n.timestamp>r?this._removeRequest(e):P(n)}else return}async replayRequests(){let e;for(;e=await this.shiftRequest();)try{await fetch(e.request.clone())}catch{throw await this.unshiftRequest(e),new t(`queue-replay-failed`,{name:this._name})}}async registerSync(){if(`sync`in self.registration&&!this._forceSyncFallback)try{await self.registration.sync.register(`${M}:${this._name}`)}catch{}}_addSyncListener(){`sync`in self.registration&&!this._forceSyncFallback?self.addEventListener(`sync`,e=>{e.tag===`${M}:${this._name}`&&e.waitUntil((async()=>{this._syncInProgress=!0;let t;try{await this._onSync({queue:this})}catch(e){if(e instanceof Error)throw t=e,t}finally{this._requestsAddedDuringSync&&!(t&&!e.lastChance)&&await this.registerSync(),this._syncInProgress=!1,this._requestsAddedDuringSync=!1}})())}):this._onSync({queue:this})}static get _queueNames(){return N}};let I={status:202,statusText:`Queued`};async function L(e){let t=await self.clients.matchAll({includeUncontrolled:!1});for(let n of t)n.postMessage(e)}async function R(e){let t=await e.getAll(),n=0;for(let e of t){let t=e.metadata;typeof t?.bytes==`number`&&(n+=t.bytes)}return n}async function z(e,t){let n=await R(e);for(;n+t>10485760;){let t=await e.shiftRequest();if(!t)break;let r=t.metadata;n-=r?.bytes??0,await L({type:`interfere.sw.dropped`,url:t.request.url,reason:`queue_size_cap`})}}async function B(e,t){let n=t.clone(),r=(await n.clone().arrayBuffer()).byteLength;await z(e,r),await e.pushRequest({request:n,metadata:{bytes:r}}),await L({type:`interfere.sw.queued`,url:t.url})}let V=new F(`interfere-ingest`,{maxRetentionTime:1440,onSync:async({queue:e})=>{let t=await e.shiftRequest();for(;t;){try{let e=await fetch(t.request.clone());if(!e.ok&&(e.status>=500||e.status===429))throw Error(`retry status ${e.status}`);await L({type:`interfere.sw.replayed`,url:t.request.url})}catch(n){throw await e.unshiftRequest(t),n}t=await e.shiftRequest()}}});self.addEventListener(`install`,()=>{self.skipWaiting()}),self.addEventListener(`activate`,e=>{e.waitUntil((async()=>{await self.clients.claim(),V.replayRequests().catch(()=>void 0)})())}),self.addEventListener(`fetch`,e=>{let{request:t}=e;if(t.method!==`POST`)return;let n;try{n=new URL(t.url)}catch{return}n.pathname.startsWith(`/api/interfere/`)&&e.respondWith((async()=>{try{let e=await fetch(t.clone());return e.ok?e:e.status>=500||e.status===429?(await B(V,t),new Response(null,I)):e}catch{return await B(V,t),new Response(null,I)}})())})})();";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.mts","names":[],"sources":["../../src/tracking/api.ts"],"mappings":";;;;;;;UAgBiB,qBAAA;EACf,MAAA,GAAS,aAAA;EACT,OAAA,UAAiB,UAAA,CAAW,KAAA;EAC5B,GAAA,GAAM,WAAA;EACN,MAAA,EAAQ,YAAA;AAAA;AAAA,cAGG,cAAA;EAAA,iBACM,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,MAAA;EAAA,iBACA,GAAA;EAAA,QAET,GAAA;EAAA,QACA,eAAA;EAAA,QACA,mBAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;EAAA,QACA,UAAA;cAEI,IAAA,EAAM,qBAAA;EAOlB,KAAA
|
|
1
|
+
{"version":3,"file":"api.d.mts","names":[],"sources":["../../src/tracking/api.ts"],"mappings":";;;;;;;UAgBiB,qBAAA;EACf,MAAA,GAAS,aAAA;EACT,OAAA,UAAiB,UAAA,CAAW,KAAA;EAC5B,GAAA,GAAM,WAAA;EACN,MAAA,EAAQ,YAAA;AAAA;AAAA,cAGG,cAAA;EAAA,iBACM,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,MAAA;EAAA,iBACA,GAAA;EAAA,QAET,GAAA;EAAA,QACA,eAAA;EAAA,QACA,mBAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;EAAA,QACA,UAAA;cAEI,IAAA,EAAM,qBAAA;EAOlB,KAAA;EASA,SAAA,IAAa,SAAA;EAQb,QAAA;EAIA,WAAA;EAIA,SAAA;EA7CyB;;;;;EAsDzB,OAAA,IAAW,MAAA;EAiBX,WAAA,IAAe,cAAA;EAIT,QAAA,CAAS,MAAA,EAAQ,cAAA,GAAiB,OAAA;EA2CxC,aAAA;EAKA,OAAA;EAAA,QAQQ,cAAA;EAAA,QAOA,YAAA;EAAA,QAcA,WAAA;EAAA,QA0BM,QAAA;AAAA"}
|
package/dist/tracking/api.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"../util/log.mjs";import{appendPathBeforeQuery}from"../internal/config.mjs";import{DeviceManager}from"./device.mjs";import{GeoDetector}from"./geo.mjs";import{SessionManager}from"./session.mjs";const log=createLogger(`tracking`);var SessionTracker=class{target;fetcher;device;geo;mgr=null;currentIdentity=null;identifiedSessionId=null;syncedSessionId=null;syncAttemptMs=0;generation=0;constructor(opts){this.target=opts.target,this.fetcher=opts.fetcher??globalThis.fetch.bind(globalThis),this.device=opts.device??new DeviceManager,this.geo=opts.geo??new GeoDetector}start(){this.device.init(),this.geo.detect(),this.mgr=new SessionManager(id=>{this.onRotate(id).catch(()=>
|
|
1
|
+
import{createLogger}from"../util/log.mjs";import{appendPathBeforeQuery}from"../internal/config.mjs";import{DeviceManager}from"./device.mjs";import{GeoDetector}from"./geo.mjs";import{SessionManager}from"./session.mjs";const log=createLogger(`tracking`);var SessionTracker=class{target;fetcher;device;geo;mgr=null;currentIdentity=null;identifiedSessionId=null;syncedSessionId=null;syncAttemptMs=0;generation=0;constructor(opts){this.target=opts.target,this.fetcher=opts.fetcher??globalThis.fetch.bind(globalThis),this.device=opts.device??new DeviceManager,this.geo=opts.geo??new GeoDetector}start(){this.device.init(),this.geo.detect(),this.mgr=new SessionManager(id=>{this.onRotate(id).catch(()=>void 0)})}sessionId(){let id=this.mgr?.getSessionId()??null;return id&&this.ensureSynced(id),id}windowId(){return this.mgr?.getWindowId()??null}getDeviceId(){return this.device.getDeviceId()}getFpHash(){return this.device.getFpHash()}headers(){let h={},sid=this.mgr?.getSessionId()??null;sid&&(h[`x-interfere-session`]=sid);let wid=this.mgr?.getWindowId()??null;wid&&(h[`x-interfere-window`]=wid);let did=this.device.getDeviceId();return did&&(h[`x-interfere-device`]=did),h}getIdentity(){return this.currentIdentity}async identify(params){if(!this.mgr)return;let sessionId=this.mgr.getSessionId();if(this.identifiedSessionId===sessionId){log.debug(`skipped, already identified for session %s`,sessionId);return}this.currentIdentity=params,this.identifiedSessionId=sessionId;let gen=this.generation,[fpHash,country]=await Promise.all([this.device.whenFingerprintReady(),this.geo.detect()]),deviceId=this.device.getDeviceId();if(gen!==this.generation){this.identifiedSessionId=null;return}log.info(`POST session %s → identify`,sessionId),this.fetcher(appendPathBeforeQuery(this.target.url,`/identify`),{method:`POST`,headers:this.requestHeaders(),body:JSON.stringify({sessionId,deviceId,fpHash,...params,...country&&{country}}),keepalive:!0,signal:AbortSignal.timeout(1e4)}).catch(()=>{this.identifiedSessionId=null,log.warn(`identify failed for session %s`,sessionId)})}clearIdentity(){this.currentIdentity=null,this.identifiedSessionId=null}dispose(){this.generation+=1,this.clearIdentity(),this.syncedSessionId=null,this.syncAttemptMs=0,this.mgr=null}requestHeaders(){return{...Object.fromEntries(this.target.headers.entries()),...this.headers()}}ensureSynced(sessionId){this.syncedSessionId!==sessionId&&(Date.now()-this.syncAttemptMs<5e3||this.syncSession(sessionId,this.device.getDeviceId(),this.device.getFpHash()))}syncSession(sessionId,deviceId,fpHash){this.syncAttemptMs=Date.now(),this.syncedSessionId=sessionId,this.fetcher(this.target.url,{method:`POST`,headers:this.requestHeaders(),body:JSON.stringify({sessionId,deviceId,fpHash}),keepalive:!0,signal:AbortSignal.timeout(1e4)}).then(res=>{res.ok||(this.syncedSessionId=null)}).catch(()=>{this.syncedSessionId=null,log.warn(`session sync failed, will retry`)})}async onRotate(sessionId){this.syncedSessionId=null,this.syncAttemptMs=Date.now();let gen=this.generation,fpHash=await this.device.whenFingerprintReady(),deviceId=this.device.getDeviceId();gen===this.generation&&(log.debug(`POST session %s (device=%s fp=%s)`,sessionId,deviceId??`pending`,fpHash??`none`),this.syncSession(sessionId,deviceId,fpHash))}};export{SessionTracker};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.mjs","names":[],"sources":["../../src/tracking/api.ts"],"sourcesContent":["import type { SessionId } from \"@interfere/types/data/session\";\nimport type { IdentifyParams } from \"@interfere/types/sdk/identify\";\n\nimport {\n appendPathBeforeQuery,\n type IngestTarget,\n} from \"../internal/config.js\";\nimport { createLogger } from \"../util/log.js\";\nimport { DeviceManager } from \"./device.js\";\nimport { GeoDetector } from \"./geo.js\";\nimport { SessionManager } from \"./session.js\";\n\nconst log = createLogger(\"tracking\");\n\nconst SYNC_COOLDOWN_MS = 5000;\n\nexport interface SessionTrackerOptions {\n device?: DeviceManager;\n fetcher?: typeof globalThis.fetch;\n geo?: GeoDetector;\n target: IngestTarget;\n}\n\nexport class SessionTracker {\n private readonly target: IngestTarget;\n private readonly fetcher: typeof globalThis.fetch;\n private readonly device: DeviceManager;\n private readonly geo: GeoDetector;\n\n private mgr: SessionManager | null = null;\n private currentIdentity: IdentifyParams | null = null;\n private identifiedSessionId: string | null = null;\n private syncedSessionId: string | null = null;\n private syncAttemptMs = 0;\n private generation = 0;\n\n constructor(opts: SessionTrackerOptions) {\n this.target = opts.target;\n this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);\n this.device = opts.device ?? new DeviceManager();\n this.geo = opts.geo ?? new GeoDetector();\n }\n\n start(): void {\n this.device.init();\n
|
|
1
|
+
{"version":3,"file":"api.mjs","names":[],"sources":["../../src/tracking/api.ts"],"sourcesContent":["import type { SessionId } from \"@interfere/types/data/session\";\nimport type { IdentifyParams } from \"@interfere/types/sdk/identify\";\n\nimport {\n appendPathBeforeQuery,\n type IngestTarget,\n} from \"../internal/config.js\";\nimport { createLogger } from \"../util/log.js\";\nimport { DeviceManager } from \"./device.js\";\nimport { GeoDetector } from \"./geo.js\";\nimport { SessionManager } from \"./session.js\";\n\nconst log = createLogger(\"tracking\");\n\nconst SYNC_COOLDOWN_MS = 5000;\n\nexport interface SessionTrackerOptions {\n device?: DeviceManager;\n fetcher?: typeof globalThis.fetch;\n geo?: GeoDetector;\n target: IngestTarget;\n}\n\nexport class SessionTracker {\n private readonly target: IngestTarget;\n private readonly fetcher: typeof globalThis.fetch;\n private readonly device: DeviceManager;\n private readonly geo: GeoDetector;\n\n private mgr: SessionManager | null = null;\n private currentIdentity: IdentifyParams | null = null;\n private identifiedSessionId: string | null = null;\n private syncedSessionId: string | null = null;\n private syncAttemptMs = 0;\n private generation = 0;\n\n constructor(opts: SessionTrackerOptions) {\n this.target = opts.target;\n this.fetcher = opts.fetcher ?? globalThis.fetch.bind(globalThis);\n this.device = opts.device ?? new DeviceManager();\n this.geo = opts.geo ?? new GeoDetector();\n }\n\n start(): void {\n this.device.init();\n\n this.geo.detect();\n this.mgr = new SessionManager((id) => {\n this.onRotate(id).catch(() => undefined);\n });\n }\n\n sessionId(): SessionId | null {\n const id = this.mgr?.getSessionId() ?? null;\n if (id) {\n this.ensureSynced(id);\n }\n return id;\n }\n\n windowId(): string | null {\n return this.mgr?.getWindowId() ?? null;\n }\n\n getDeviceId(): string | null {\n return this.device.getDeviceId();\n }\n\n getFpHash(): string | null {\n return this.device.getFpHash();\n }\n\n /**\n * Identity headers (session / window / device). Layered onto the\n * session/identify POSTs alongside the target's static headers\n * (content-type + auth + force-enable).\n */\n headers(): Record<string, string> {\n const h: Record<string, string> = {};\n const sid = this.mgr?.getSessionId() ?? null;\n if (sid) {\n h[\"x-interfere-session\"] = sid;\n }\n const wid = this.mgr?.getWindowId() ?? null;\n if (wid) {\n h[\"x-interfere-window\"] = wid;\n }\n const did = this.device.getDeviceId();\n if (did) {\n h[\"x-interfere-device\"] = did;\n }\n return h;\n }\n\n getIdentity(): IdentifyParams | null {\n return this.currentIdentity;\n }\n\n async identify(params: IdentifyParams): Promise<void> {\n if (!this.mgr) {\n return;\n }\n const sessionId = this.mgr.getSessionId();\n if (this.identifiedSessionId === sessionId) {\n log.debug(\"skipped, already identified for session %s\", sessionId);\n return;\n }\n\n this.currentIdentity = params;\n this.identifiedSessionId = sessionId;\n\n const gen = this.generation;\n const [fpHash, country] = await Promise.all([\n this.device.whenFingerprintReady(),\n this.geo.detect(),\n ]);\n const deviceId = this.device.getDeviceId();\n if (gen !== this.generation) {\n this.identifiedSessionId = null;\n return;\n }\n\n log.info(\"POST session %s → identify\", sessionId);\n this.fetcher(appendPathBeforeQuery(this.target.url, \"/identify\"), {\n method: \"POST\",\n headers: this.requestHeaders(),\n body: JSON.stringify({\n sessionId,\n deviceId,\n fpHash,\n ...params,\n ...(country && { country }),\n }),\n keepalive: true,\n signal: AbortSignal.timeout(10_000),\n }).catch(() => {\n this.identifiedSessionId = null;\n log.warn(\"identify failed for session %s\", sessionId);\n });\n }\n\n clearIdentity(): void {\n this.currentIdentity = null;\n this.identifiedSessionId = null;\n }\n\n dispose(): void {\n this.generation += 1;\n this.clearIdentity();\n this.syncedSessionId = null;\n this.syncAttemptMs = 0;\n this.mgr = null;\n }\n\n private requestHeaders(): Record<string, string> {\n return {\n ...Object.fromEntries(this.target.headers.entries()),\n ...this.headers(),\n };\n }\n\n private ensureSynced(sessionId: string): void {\n if (this.syncedSessionId === sessionId) {\n return;\n }\n if (Date.now() - this.syncAttemptMs < SYNC_COOLDOWN_MS) {\n return;\n }\n this.syncSession(\n sessionId,\n this.device.getDeviceId(),\n this.device.getFpHash()\n );\n }\n\n private syncSession(\n sessionId: string,\n deviceId: string | null,\n fpHash: string | null\n ): void {\n this.syncAttemptMs = Date.now();\n this.syncedSessionId = sessionId;\n\n this.fetcher(this.target.url, {\n method: \"POST\",\n headers: this.requestHeaders(),\n body: JSON.stringify({ sessionId, deviceId, fpHash }),\n keepalive: true,\n signal: AbortSignal.timeout(10_000),\n })\n .then((res) => {\n if (!res.ok) {\n this.syncedSessionId = null;\n }\n })\n .catch(() => {\n this.syncedSessionId = null;\n log.warn(\"session sync failed, will retry\");\n });\n }\n\n private async onRotate(sessionId: string): Promise<void> {\n this.syncedSessionId = null;\n this.syncAttemptMs = Date.now();\n const gen = this.generation;\n const fpHash = await this.device.whenFingerprintReady();\n const deviceId = this.device.getDeviceId();\n if (gen !== this.generation) {\n return;\n }\n log.debug(\n \"POST session %s (device=%s fp=%s)\",\n sessionId,\n deviceId ?? \"pending\",\n fpHash ?? \"none\"\n );\n this.syncSession(sessionId, deviceId, fpHash);\n }\n}\n"],"mappings":"yNAYA,MAAM,IAAM,aAAa,UAAU,EAWnC,IAAa,eAAb,KAA4B,CAC1B,OACA,QACA,OACA,IAEA,IAAqC,KACrC,gBAAiD,KACjD,oBAA6C,KAC7C,gBAAyC,KACzC,cAAwB,EACxB,WAAqB,EAErB,YAAY,KAA6B,CACvC,KAAK,OAAS,KAAK,OACnB,KAAK,QAAU,KAAK,SAAW,WAAW,MAAM,KAAK,UAAU,EAC/D,KAAK,OAAS,KAAK,QAAU,IAAI,cACjC,KAAK,IAAM,KAAK,KAAO,IAAI,WAC7B,CAEA,OAAc,CACZ,KAAK,OAAO,KAAK,EAEjB,KAAK,IAAI,OAAO,EAChB,KAAK,IAAM,IAAI,eAAgB,IAAO,CACpC,KAAK,SAAS,EAAE,EAAE,UAAY,IAAA,EAAS,CACzC,CAAC,CACH,CAEA,WAA8B,CAC5B,IAAM,GAAK,KAAK,KAAK,aAAa,GAAK,KAIvC,OAHI,IACF,KAAK,aAAa,EAAE,EAEf,EACT,CAEA,UAA0B,CACxB,OAAO,KAAK,KAAK,YAAY,GAAK,IACpC,CAEA,aAA6B,CAC3B,OAAO,KAAK,OAAO,YAAY,CACjC,CAEA,WAA2B,CACzB,OAAO,KAAK,OAAO,UAAU,CAC/B,CAOA,SAAkC,CAChC,IAAM,EAA4B,CAAC,EAC7B,IAAM,KAAK,KAAK,aAAa,GAAK,KACpC,MACF,EAAE,uBAAyB,KAE7B,IAAM,IAAM,KAAK,KAAK,YAAY,GAAK,KACnC,MACF,EAAE,sBAAwB,KAE5B,IAAM,IAAM,KAAK,OAAO,YAAY,EAIpC,OAHI,MACF,EAAE,sBAAwB,KAErB,CACT,CAEA,aAAqC,CACnC,OAAO,KAAK,eACd,CAEA,MAAM,SAAS,OAAuC,CACpD,GAAI,CAAC,KAAK,IACR,OAEF,IAAM,UAAY,KAAK,IAAI,aAAa,EACxC,GAAI,KAAK,sBAAwB,UAAW,CAC1C,IAAI,MAAM,6CAA8C,SAAS,EACjE,MACF,CAEA,KAAK,gBAAkB,OACvB,KAAK,oBAAsB,UAE3B,IAAM,IAAM,KAAK,WACX,CAAC,OAAQ,SAAW,MAAM,QAAQ,IAAI,CAC1C,KAAK,OAAO,qBAAqB,EACjC,KAAK,IAAI,OAAO,CAClB,CAAC,EACK,SAAW,KAAK,OAAO,YAAY,EACzC,GAAI,MAAQ,KAAK,WAAY,CAC3B,KAAK,oBAAsB,KAC3B,MACF,CAEA,IAAI,KAAK,6BAA8B,SAAS,EAChD,KAAK,QAAQ,sBAAsB,KAAK,OAAO,IAAK,WAAW,EAAG,CAChE,OAAQ,OACR,QAAS,KAAK,eAAe,EAC7B,KAAM,KAAK,UAAU,CACnB,UACA,SACA,OACA,GAAG,OACH,GAAI,SAAW,CAAE,OAAQ,CAC3B,CAAC,EACD,UAAW,GACX,OAAQ,YAAY,QAAQ,GAAM,CACpC,CAAC,EAAE,UAAY,CACb,KAAK,oBAAsB,KAC3B,IAAI,KAAK,iCAAkC,SAAS,CACtD,CAAC,CACH,CAEA,eAAsB,CACpB,KAAK,gBAAkB,KACvB,KAAK,oBAAsB,IAC7B,CAEA,SAAgB,CACd,KAAK,YAAc,EACnB,KAAK,cAAc,EACnB,KAAK,gBAAkB,KACvB,KAAK,cAAgB,EACrB,KAAK,IAAM,IACb,CAEA,gBAAiD,CAC/C,MAAO,CACL,GAAG,OAAO,YAAY,KAAK,OAAO,QAAQ,QAAQ,CAAC,EACnD,GAAG,KAAK,QAAQ,CAClB,CACF,CAEA,aAAqB,UAAyB,CACxC,KAAK,kBAAoB,YAGzB,KAAK,IAAI,EAAI,KAAK,cAAgB,KAGtC,KAAK,YACH,UACA,KAAK,OAAO,YAAY,EACxB,KAAK,OAAO,UAAU,CACxB,EACF,CAEA,YACE,UACA,SACA,OACM,CACN,KAAK,cAAgB,KAAK,IAAI,EAC9B,KAAK,gBAAkB,UAEvB,KAAK,QAAQ,KAAK,OAAO,IAAK,CAC5B,OAAQ,OACR,QAAS,KAAK,eAAe,EAC7B,KAAM,KAAK,UAAU,CAAE,UAAW,SAAU,MAAO,CAAC,EACpD,UAAW,GACX,OAAQ,YAAY,QAAQ,GAAM,CACpC,CAAC,EACE,KAAM,KAAQ,CACR,IAAI,KACP,KAAK,gBAAkB,KAE3B,CAAC,EACA,UAAY,CACX,KAAK,gBAAkB,KACvB,IAAI,KAAK,iCAAiC,CAC5C,CAAC,CACL,CAEA,MAAc,SAAS,UAAkC,CACvD,KAAK,gBAAkB,KACvB,KAAK,cAAgB,KAAK,IAAI,EAC9B,IAAM,IAAM,KAAK,WACX,OAAS,MAAM,KAAK,OAAO,qBAAqB,EAChD,SAAW,KAAK,OAAO,YAAY,EACrC,MAAQ,KAAK,aAGjB,IAAI,MACF,oCACA,UACA,UAAY,UACZ,QAAU,MACZ,EACA,KAAK,YAAY,UAAW,SAAU,MAAM,EAC9C,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.mts","names":[],"sources":["../../src/tracking/device.ts"],"mappings":";;AAgBA;;;;AAA+C;AAW/C;;KAXY,mBAAA,SAA4B,OAAO;;AAWZ;AAuEnC;;;;;iBAvEgB,QAAA,
|
|
1
|
+
{"version":3,"file":"device.d.mts","names":[],"sources":["../../src/tracking/device.ts"],"mappings":";;AAgBA;;;;AAA+C;AAW/C;;KAXY,mBAAA,SAA4B,OAAO;;AAWZ;AAuEnC;;;;;iBAvEgB,QAAA,IAAY,OAAO;AAAA,cAuEtB,aAAA;EAAA,QACH,QAAA;EAAA,QACA,MAAA;EAAA,QACA,SAAA;EAAA,iBACS,mBAAA;cAEL,mBAAA,GAAsB,mBAAA;EAKlC,IAAA;EAAA,QAkCQ,gBAAA;EAgBR,WAAA;EAIA,SAAA;EAIA,oBAAA,IAAwB,OAAO;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.mjs","names":[],"sources":["../../src/tracking/device.ts"],"sourcesContent":["import { createLogger } from \"../util/log.js\";\n\nconst log = createLogger(\"device\");\n\nconst LS_KEY = \"interfere:device_id\";\nconst COOKIE_NAME = \"interfere_did\";\nconst COOKIE_MAX_AGE_DAYS = 400;\n\n/**\n * Producer of an opaque, stable per-browser fingerprint hash. The default\n * dynamic-imports the FingerprintJS OSS library and self-defers via\n * `requestIdleCallback` so the ~1.5s of synchronous font / canvas / WebGL\n * probing the library performs on a cold load doesn't land on the\n * hydration tick. Tests inject a fixed-value provider that resolves\n * immediately — they pay nothing for the production deferral.\n */\nexport type FingerprintProvider = () => Promise<string | null>;\n\nconst FP_IDLE_TIMEOUT_MS = 5000;\n\n/**\n * Resolves on the next browser idle frame, capped at 5s. Falls back to\n * `setTimeout(0)` (next macrotask) on hosts without\n * `requestIdleCallback`. Exported only for the unit test that pins the\n * \"default provider gates fingerprint work via RIC\" contract — not part\n * of the package's public surface.\n */\nexport function whenIdle(): Promise<void> {\n return new Promise((resolve) => {\n if (typeof globalThis.requestIdleCallback === \"function\") {\n globalThis.requestIdleCallback(() => resolve(), {\n timeout: FP_IDLE_TIMEOUT_MS,\n });\n return;\n }\n setTimeout(resolve, 0);\n });\n}\n\nconst defaultFingerprintProvider: FingerprintProvider = async () => {\n await whenIdle();\n try {\n const FingerprintJS = await import(\"@fingerprintjs/fingerprintjs\");\n const fp = await FingerprintJS.load();\n const result = await fp.get();\n if (!result.visitorId) {\n log.error(\n \"Fingerprinting returned an empty visitor id; visitor identity will be cookie-only\"\n );\n\n return null;\n }\n return result.visitorId;\n } catch (err) {\n log.error(\n \"fingerprint init failed; visitor identity will be cookie-only\",\n err\n );\n\n return null;\n }\n};\n\nfunction tryLocalStorage(): Storage | null {\n try {\n const s = globalThis.localStorage;\n const key = \"__interfere_device_probe__\";\n s.setItem(key, \"1\");\n s.removeItem(key);\n return s;\n } catch {\n return null;\n }\n}\n\nfunction getCookie(name: string): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const match = document.cookie\n .split(\"; \")\n .find((c) => c.startsWith(`${name}=`));\n return match ? decodeURIComponent(match.split(\"=\")[1] ?? \"\") : null;\n}\n\nfunction setCookie(name: string, value: string): void {\n if (typeof document === \"undefined\") {\n return;\n }\n const maxAge = COOKIE_MAX_AGE_DAYS * 24 * 60 * 60;\n // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API is async and not universally supported; synchronous access is required here\n document.cookie = `${name}=${encodeURIComponent(value)};path=/;max-age=${maxAge};SameSite=Lax`;\n}\n\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\nexport class DeviceManager {\n private deviceId: string | null = null;\n private fpHash: string | null = null;\n private fpPending: Promise<string | null> | null = null;\n private readonly fingerprintProvider: FingerprintProvider;\n\n constructor(fingerprintProvider?: FingerprintProvider) {\n this.fingerprintProvider =\n fingerprintProvider ?? defaultFingerprintProvider;\n }\n\n init(): void {\n if (this.deviceId) {\n return;\n }\n\n const ls = tryLocalStorage();\n const fromLs = ls?.getItem(LS_KEY) ?? null;\n const fromCookie = getCookie(COOKIE_NAME);\n\n this.deviceId = fromLs ?? fromCookie ?? generateId();\n\n if (!fromLs && ls) {\n ls.setItem(LS_KEY, this.deviceId);\n }\n if (!fromCookie) {\n setCookie(COOKIE_NAME, this.deviceId);\n }\n if (fromLs && !fromCookie) {\n setCookie(COOKIE_NAME, this.deviceId);\n }\n if (fromCookie && !fromLs && ls) {\n ls.setItem(LS_KEY, this.deviceId);\n }\n\n log.debug(\n \"device %s (ls=%s cookie=%s)\",\n this.deviceId,\n !!fromLs,\n !!fromCookie\n );\n\n this.startFingerprint();\n }\n\n private startFingerprint(): void {\n if (this.fpHash || this.fpPending) {\n return;\n }\n\n this.fpPending = (async () => {\n const hash = await this.fingerprintProvider();\n this.fpHash = hash;\n if (hash) {\n log.debug(\"fpHash %s\", hash);\n }\n
|
|
1
|
+
{"version":3,"file":"device.mjs","names":[],"sources":["../../src/tracking/device.ts"],"sourcesContent":["import { createLogger } from \"../util/log.js\";\n\nconst log = createLogger(\"device\");\n\nconst LS_KEY = \"interfere:device_id\";\nconst COOKIE_NAME = \"interfere_did\";\nconst COOKIE_MAX_AGE_DAYS = 400;\n\n/**\n * Producer of an opaque, stable per-browser fingerprint hash. The default\n * dynamic-imports the FingerprintJS OSS library and self-defers via\n * `requestIdleCallback` so the ~1.5s of synchronous font / canvas / WebGL\n * probing the library performs on a cold load doesn't land on the\n * hydration tick. Tests inject a fixed-value provider that resolves\n * immediately — they pay nothing for the production deferral.\n */\nexport type FingerprintProvider = () => Promise<string | null>;\n\nconst FP_IDLE_TIMEOUT_MS = 5000;\n\n/**\n * Resolves on the next browser idle frame, capped at 5s. Falls back to\n * `setTimeout(0)` (next macrotask) on hosts without\n * `requestIdleCallback`. Exported only for the unit test that pins the\n * \"default provider gates fingerprint work via RIC\" contract — not part\n * of the package's public surface.\n */\nexport function whenIdle(): Promise<void> {\n return new Promise((resolve) => {\n if (typeof globalThis.requestIdleCallback === \"function\") {\n globalThis.requestIdleCallback(() => resolve(), {\n timeout: FP_IDLE_TIMEOUT_MS,\n });\n return;\n }\n setTimeout(resolve, 0);\n });\n}\n\nconst defaultFingerprintProvider: FingerprintProvider = async () => {\n await whenIdle();\n try {\n const FingerprintJS = await import(\"@fingerprintjs/fingerprintjs\");\n const fp = await FingerprintJS.load();\n const result = await fp.get();\n if (!result.visitorId) {\n log.error(\n \"Fingerprinting returned an empty visitor id; visitor identity will be cookie-only\"\n );\n\n return null;\n }\n return result.visitorId;\n } catch (err) {\n log.error(\n \"fingerprint init failed; visitor identity will be cookie-only\",\n err\n );\n\n return null;\n }\n};\n\nfunction tryLocalStorage(): Storage | null {\n try {\n const s = globalThis.localStorage;\n const key = \"__interfere_device_probe__\";\n s.setItem(key, \"1\");\n s.removeItem(key);\n return s;\n } catch {\n return null;\n }\n}\n\nfunction getCookie(name: string): string | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const match = document.cookie\n .split(\"; \")\n .find((c) => c.startsWith(`${name}=`));\n return match ? decodeURIComponent(match.split(\"=\")[1] ?? \"\") : null;\n}\n\nfunction setCookie(name: string, value: string): void {\n if (typeof document === \"undefined\") {\n return;\n }\n const maxAge = COOKIE_MAX_AGE_DAYS * 24 * 60 * 60;\n // biome-ignore lint/suspicious/noDocumentCookie: Cookie Store API is async and not universally supported; synchronous access is required here\n document.cookie = `${name}=${encodeURIComponent(value)};path=/;max-age=${maxAge};SameSite=Lax`;\n}\n\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\nexport class DeviceManager {\n private deviceId: string | null = null;\n private fpHash: string | null = null;\n private fpPending: Promise<string | null> | null = null;\n private readonly fingerprintProvider: FingerprintProvider;\n\n constructor(fingerprintProvider?: FingerprintProvider) {\n this.fingerprintProvider =\n fingerprintProvider ?? defaultFingerprintProvider;\n }\n\n init(): void {\n if (this.deviceId) {\n return;\n }\n\n const ls = tryLocalStorage();\n const fromLs = ls?.getItem(LS_KEY) ?? null;\n const fromCookie = getCookie(COOKIE_NAME);\n\n this.deviceId = fromLs ?? fromCookie ?? generateId();\n\n if (!fromLs && ls) {\n ls.setItem(LS_KEY, this.deviceId);\n }\n if (!fromCookie) {\n setCookie(COOKIE_NAME, this.deviceId);\n }\n if (fromLs && !fromCookie) {\n setCookie(COOKIE_NAME, this.deviceId);\n }\n if (fromCookie && !fromLs && ls) {\n ls.setItem(LS_KEY, this.deviceId);\n }\n\n log.debug(\n \"device %s (ls=%s cookie=%s)\",\n this.deviceId,\n !!fromLs,\n !!fromCookie\n );\n\n this.startFingerprint();\n }\n\n private startFingerprint(): void {\n if (this.fpHash || this.fpPending) {\n return;\n }\n\n this.fpPending = (async () => {\n const hash = await this.fingerprintProvider();\n this.fpHash = hash;\n if (hash) {\n log.debug(\"fpHash %s\", hash);\n }\n\n return hash;\n })();\n }\n\n getDeviceId(): string | null {\n return this.deviceId;\n }\n\n getFpHash(): string | null {\n return this.fpHash;\n }\n\n whenFingerprintReady(): Promise<string | null> {\n if (this.fpHash) {\n return Promise.resolve(this.fpHash);\n }\n return this.fpPending ?? Promise.resolve(null);\n }\n}\n"],"mappings":"0CAEA,MAAM,IAAM,aAAa,QAAQ,EAE3B,OAAS,sBACT,YAAc,gBAsBpB,SAAgB,UAA0B,CACxC,OAAO,IAAI,QAAS,SAAY,CAC9B,GAAI,OAAO,WAAW,qBAAwB,WAAY,CACxD,WAAW,wBAA0B,QAAQ,EAAG,CAC9C,QAAS,GACX,CAAC,EACD,MACF,CACA,WAAW,QAAS,CAAC,CACvB,CAAC,CACH,CAEA,MAAM,2BAAkD,SAAY,CAClE,MAAM,SAAS,EACf,GAAI,CAGF,IAAM,OAAS,MAAM,MADJ,MADW,OAAO,iCACJ,KAAK,GACZ,IAAI,EAQ5B,OAPK,OAAO,UAOL,OAAO,WANZ,IAAI,MACF,mFACF,EAEO,KAGX,OAAS,IAAK,CAMZ,OALA,IAAI,MACF,gEACA,GACF,EAEO,IACT,CACF,EAEA,SAAS,iBAAkC,CACzC,GAAI,CACF,IAAM,EAAI,WAAW,aACf,IAAM,6BAGZ,OAFA,EAAE,QAAQ,IAAK,GAAG,EAClB,EAAE,WAAW,GAAG,EACT,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAAS,UAAU,KAA6B,CAC9C,GAAI,OAAO,SAAa,IACtB,OAAO,KAET,IAAM,MAAQ,SAAS,OACpB,MAAM,IAAI,EACV,KAAM,GAAM,EAAE,WAAW,GAAG,KAAK,EAAE,CAAC,EACvC,OAAO,MAAQ,mBAAmB,MAAM,MAAM,GAAG,EAAE,IAAM,EAAE,EAAI,IACjE,CAEA,SAAS,UAAU,KAAc,MAAqB,CAChD,OAAO,SAAa,MAKxB,SAAS,OAAS,GAAG,KAAK,GAAG,mBAAmB,KAAK,EAAE,kBAFxC,IAAsB,GAAK,GAAK,GAEiC,eAClF,CAEA,SAAS,YAAqB,CAC5B,OAAO,OAAO,WAAW,CAC3B,CAEA,IAAa,cAAb,KAA2B,CACzB,SAAkC,KAClC,OAAgC,KAChC,UAAmD,KACnD,oBAEA,YAAY,oBAA2C,CACrD,KAAK,oBACH,qBAAuB,0BAC3B,CAEA,MAAa,CACX,GAAI,KAAK,SACP,OAGF,IAAM,GAAK,gBAAgB,EACrB,OAAS,IAAI,QAAQ,MAAM,GAAK,KAChC,WAAa,UAAU,WAAW,EAExC,KAAK,SAAW,QAAU,YAAc,WAAW,EAE/C,CAAC,QAAU,IACb,GAAG,QAAQ,OAAQ,KAAK,QAAQ,EAE7B,YACH,UAAU,YAAa,KAAK,QAAQ,EAElC,QAAU,CAAC,YACb,UAAU,YAAa,KAAK,QAAQ,EAElC,YAAc,CAAC,QAAU,IAC3B,GAAG,QAAQ,OAAQ,KAAK,QAAQ,EAGlC,IAAI,MACF,8BACA,KAAK,SACL,CAAC,CAAC,OACF,CAAC,CAAC,UACJ,EAEA,KAAK,iBAAiB,CACxB,CAEA,kBAAiC,CAC3B,KAAK,QAAU,KAAK,YAIxB,KAAK,WAAa,SAAY,CAC5B,IAAM,KAAO,MAAM,KAAK,oBAAoB,EAM5C,MALA,MAAK,OAAS,KACV,MACF,IAAI,MAAM,YAAa,IAAI,EAGtB,IACT,GAAG,EACL,CAEA,aAA6B,CAC3B,OAAO,KAAK,QACd,CAEA,WAA2B,CACzB,OAAO,KAAK,MACd,CAEA,sBAA+C,CAI7C,OAHI,KAAK,OACA,QAAQ,QAAQ,KAAK,MAAM,EAE7B,KAAK,WAAa,QAAQ,QAAQ,IAAI,CAC/C,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geo.d.mts","names":[],"sources":["../../src/tracking/geo.ts"],"mappings":";cAea,WAAA;EAAA,QACH,MAAA;EAAA,QACA,OAAA;EAAA,QACA,MAAA;EAAA,iBACS,OAAA;cAEL,OAAA,UAAiB,UAAA,CAAW,KAAA;EAIxC,MAAA,
|
|
1
|
+
{"version":3,"file":"geo.d.mts","names":[],"sources":["../../src/tracking/geo.ts"],"mappings":";cAea,WAAA;EAAA,QACH,MAAA;EAAA,QACA,OAAA;EAAA,QACA,MAAA;EAAA,iBACS,OAAA;cAEL,OAAA,UAAiB,UAAA,CAAW,KAAA;EAIxC,MAAA,IAAU,OAAO;EAuBjB,UAAA;EAAA,QAIc,gBAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.mts","names":[],"sources":["../../src/tracking/session.ts"],"mappings":";;;KAqBY,QAAA,IAAY,SAAiB;AAAA,cAE5B,cAAA;EACX,SAAA;EACA,QAAA;EAAA,iBACiB,KAAA;EAAA,iBACA,OAAA;EAAA,iBACA,QAAA;EAAA,QACT,cAAA;cAEI,QAAA,GAAW,QAAA;EAOvB,YAAA,
|
|
1
|
+
{"version":3,"file":"session.d.mts","names":[],"sources":["../../src/tracking/session.ts"],"mappings":";;;KAqBY,QAAA,IAAY,SAAiB;AAAA,cAE5B,cAAA;EACX,SAAA;EACA,QAAA;EAAA,iBACiB,KAAA;EAAA,iBACA,OAAA;EAAA,iBACA,QAAA;EAAA,QACT,cAAA;cAEI,QAAA,GAAW,QAAA;EAOvB,YAAA,IAAgB,SAAS;EAQzB,WAAA;EAAA,QAgBQ,OAAA;EAAA,QAWA,MAAA;EAAA,QAQA,KAAA;EAAA,QAKA,SAAA;AAAA"}
|
package/dist/util/bot.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bot.d.mts","names":[],"sources":["../../src/util/bot.ts"],"mappings":";;AAQA;;;;AAA8B;iBAAd,cAAA
|
|
1
|
+
{"version":3,"file":"bot.d.mts","names":[],"sources":["../../src/util/bot.ts"],"mappings":";;AAQA;;;;AAA8B;iBAAd,cAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global.d.mts","names":[],"sources":["../../src/util/global.ts"],"mappings":";;AAMA;;;;;iBAAgB,SAAA,
|
|
1
|
+
{"version":3,"file":"global.d.mts","names":[],"sources":["../../src/util/global.ts"],"mappings":";;AAMA;;;;;iBAAgB,SAAA,IAAa,GAAA,WAAc,CAAC"}
|
package/dist/util/log.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.d.mts","names":[],"sources":["../../src/util/log.ts"],"mappings":";KAAY,QAAA;AAAA,iBA6BI,WAAA,CAAY,KAAe,EAAR,QAAQ;AAAA,iBAI3B,WAAA,
|
|
1
|
+
{"version":3,"file":"log.d.mts","names":[],"sources":["../../src/util/log.ts"],"mappings":";KAAY,QAAA;AAAA,iBA6BI,WAAA,CAAY,KAAe,EAAR,QAAQ;AAAA,iBAI3B,WAAA,IAAe,QAAQ;AAAA,UAKtB,MAAA;EACf,KAAA,IAAS,IAAA;EACT,KAAA,IAAS,IAAA;EACT,IAAA,IAAQ,IAAA;EACR,IAAA,IAAQ,IAAA;AAAA;AAAA,iBAeM,YAAA,CAAa,KAAA,WAAgB,MAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interfere/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0-canary.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Client-side React SDK for Interfere. Error tracking, session replay, and analytics.",
|
|
6
6
|
"keywords": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"author": "Interfere <support@interfere.com> (https://interfere.com)",
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "git+https://
|
|
20
|
+
"url": "git+https://interfere.ghe.com/interfere/interfere.git",
|
|
21
21
|
"directory": "src/packages/public/react"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
"scripts": {
|
|
83
83
|
"build": "tsdown",
|
|
84
84
|
"test": "vitest run",
|
|
85
|
-
"typecheck": "tsgo --noEmit
|
|
85
|
+
"typecheck": "tsgo --noEmit",
|
|
86
86
|
"typegen": "bun run scripts/build-sw.ts"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@fingerprintjs/fingerprintjs": "^5.2.0",
|
|
90
90
|
"@interfere/constants": "^9.0.2-canary.0",
|
|
91
|
-
"@interfere/types": "^9.0.3-canary.
|
|
91
|
+
"@interfere/types": "^9.0.3-canary.1",
|
|
92
92
|
"@opentelemetry/api": "^1.9.1",
|
|
93
93
|
"@opentelemetry/api-logs": "^0.218.0",
|
|
94
94
|
"@opentelemetry/context-zone": "^2.7.1",
|
|
@@ -112,9 +112,9 @@
|
|
|
112
112
|
"@opentelemetry/sdk-trace-web": "^2.7.1",
|
|
113
113
|
"@opentelemetry/web-common": "^0.218.0",
|
|
114
114
|
"@ua-parser-js/pro-enterprise": "^2.0.6",
|
|
115
|
-
"rrweb": "2.0.0
|
|
115
|
+
"rrweb": "2.0.0",
|
|
116
116
|
"uuid": "^14.0.0",
|
|
117
|
-
"web-vitals": "^5.
|
|
117
|
+
"web-vitals": "^5.3.0",
|
|
118
118
|
"workbox-background-sync": "^7.4.0",
|
|
119
119
|
"workbox-routing": "^7.4.0",
|
|
120
120
|
"workbox-strategies": "^7.4.0"
|
|
@@ -134,20 +134,21 @@
|
|
|
134
134
|
"devDependencies": {
|
|
135
135
|
"@interfere/test-utils": "^9.0.0",
|
|
136
136
|
"@interfere/typescript-config": "^9.0.0",
|
|
137
|
-
"@rrweb/types": "2.0.0
|
|
137
|
+
"@rrweb/types": "2.0.0",
|
|
138
138
|
"@types/node": "^24.12.0",
|
|
139
139
|
"@types/react": "19.2.15",
|
|
140
140
|
"@types/react-dom": "19.2.3",
|
|
141
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
142
|
-
"@vitest/browser": "4.1.
|
|
143
|
-
"@vitest/browser-playwright": "4.1.
|
|
144
|
-
"@vitest/coverage-v8": "
|
|
141
|
+
"@typescript/native-preview": "7.0.0-dev.20260601.1",
|
|
142
|
+
"@vitest/browser": "4.1.8",
|
|
143
|
+
"@vitest/browser-playwright": "4.1.8",
|
|
144
|
+
"@vitest/coverage-v8": "4.1.8",
|
|
145
|
+
"fflate": "^0.8.3",
|
|
145
146
|
"playwright": "^1.60.0",
|
|
146
147
|
"react": "^19.2.6",
|
|
147
148
|
"react-dom": "^19.2.6",
|
|
148
|
-
"rolldown": "
|
|
149
|
-
"tsdown": "
|
|
150
|
-
"vitest": "
|
|
149
|
+
"rolldown": "1.0.3",
|
|
150
|
+
"tsdown": "0.22.1",
|
|
151
|
+
"vitest": "4.1.8",
|
|
151
152
|
"vitest-browser-react": "2.2.0"
|
|
152
153
|
}
|
|
153
154
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"replay.d.mts","names":[],"sources":["../../src/plugins/replay.ts"],"mappings":";;;cAyFa,YAAA,EAAc,MA4E1B"}
|
package/dist/plugins/replay.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createLogger}from"../util/log.mjs";import{appendPathBeforeQuery,resolveTargets}from"../internal/config.mjs";import{onPageHidden}from"../internal/page-lifecycle.mjs";import{trace}from"@opentelemetry/api";const log=createLogger(`replay`);async function deliverChunk({ctx,uploadBaseUrl,authHeaders,payload}){let sessionId=ctx.getSessionId();if(!sessionId)return;let body=JSON.stringify(payload.events),sizeBytes=body.length,res=await fetch(appendPathBeforeQuery(uploadBaseUrl,`/v2/replay/upload/${encodeURIComponent(sessionId)}`),{method:`POST`,headers:{...authHeaders,"content-type":`application/json`},body});if(!res.ok){log.warn(`replay chunk upload rejected (%d)`,res.status);return}let{objectKey}=await res.json();trace.getTracer(`@interfere/react/replay`).startSpan(`replay.chunk`,{attributes:{"replay.chunk.uri":objectKey,"replay.chunk.size_bytes":sizeBytes,"replay.chunk.event_count":payload.events.length,...payload.firstTs===null?{}:{"replay.chunk.first_event_ts":payload.firstTs},...payload.lastTs===null?{}:{"replay.chunk.last_event_ts":payload.lastTs}}}).end()}const replayPlugin={name:`replay`,setup(ctx){let targets=resolveTargets(),uploadBaseUrl=targets.collectorBaseUrl,authHeaders=Object.fromEntries(targets.ingest.headers.entries()),stopFn=null,events=[],flushTimer=null,firstTs=null,lastTs=null,flush=()=>{if(events.length===0)return;let chunk=events;events=[];let payload={events:chunk,firstTs,lastTs};firstTs=null,lastTs=null,deliverChunk({ctx,uploadBaseUrl,authHeaders,payload}).catch(error=>{log.warn(`replay chunk dropped: %o`,error)})},unsubscribeHidden=null;return(async()=>{try{stopFn=(await import(`rrweb`)).record({emit(event){let ts=Date.now();firstTs===null&&(firstTs=ts),lastTs=ts,events.push(JSON.stringify(event))}})??null,flushTimer=setInterval(flush,1e4),unsubscribeHidden=onPageHidden(flush),log.debug(`recording started`)}catch{log.error(`rrweb failed to load, replay disabled`)}})(),()=>{flush(),stopFn?.(),flushTimer&&clearInterval(flushTimer),unsubscribeHidden?.()}}};export{replayPlugin as default,replayPlugin};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"replay.mjs","names":[],"sources":["../../src/plugins/replay.ts"],"sourcesContent":["import { trace } from \"@opentelemetry/api\";\n\nimport { appendPathBeforeQuery, resolveTargets } from \"../internal/config.js\";\nimport { onPageHidden } from \"../internal/page-lifecycle.js\";\nimport { createLogger } from \"../util/log.js\";\nimport type { Plugin, PluginContext } from \"./lib/types.js\";\n\nconst log = createLogger(\"replay\");\n\nconst FLUSH_INTERVAL_MS = 10_000;\nconst UPLOAD_PATH_PREFIX = \"/v2/replay/upload/\";\nconst TRACER_NAME = \"@interfere/react/replay\";\n\ninterface UploadResponse {\n objectKey: string;\n}\n\ninterface ChunkPayload {\n events: string[];\n firstTs: number | null;\n lastTs: number | null;\n}\n\ninterface DeliverInput {\n authHeaders: Record<string, string>;\n ctx: PluginContext;\n payload: ChunkPayload;\n uploadBaseUrl: string;\n}\n\n/**\n * POSTs the chunk's events array to the collector. The collector writes\n * to R2 server-side and returns the object key we stamp onto the\n * `replay.chunk` span event. Single round trip; if the request fails,\n * the chunk is dropped — replay is best-effort and the customer's next\n * session will still record cleanly.\n */\nasync function deliverChunk({\n ctx,\n uploadBaseUrl,\n authHeaders,\n payload,\n}: DeliverInput): Promise<void> {\n const sessionId = ctx.getSessionId();\n if (!sessionId) {\n return;\n }\n\n const body = JSON.stringify(payload.events);\n const sizeBytes = body.length;\n\n const res = await fetch(\n appendPathBeforeQuery(\n uploadBaseUrl,\n `${UPLOAD_PATH_PREFIX}${encodeURIComponent(sessionId)}`\n ),\n {\n method: \"POST\",\n headers: { ...authHeaders, \"content-type\": \"application/json\" },\n body,\n }\n );\n if (!res.ok) {\n log.warn(\"replay chunk upload rejected (%d)\", res.status);\n return;\n }\n\n const { objectKey } = (await res.json()) as UploadResponse;\n\n // Span-per-chunk is the cleanest OTel mapping: replay chunks are\n // events-in-time, not \"things that happened during a span\", so the\n // span itself carries the attrs. Mapper picks up by name later\n // (PRD 3 replay UI work).\n const span = trace.getTracer(TRACER_NAME).startSpan(\"replay.chunk\", {\n attributes: {\n \"replay.chunk.uri\": objectKey,\n \"replay.chunk.size_bytes\": sizeBytes,\n \"replay.chunk.event_count\": payload.events.length,\n ...(payload.firstTs === null\n ? {}\n : { \"replay.chunk.first_event_ts\": payload.firstTs }),\n ...(payload.lastTs === null\n ? {}\n : { \"replay.chunk.last_event_ts\": payload.lastTs }),\n },\n });\n span.end();\n}\n\nexport const replayPlugin: Plugin = {\n name: \"replay\",\n\n setup(ctx) {\n const targets = resolveTargets();\n const uploadBaseUrl = targets.collectorBaseUrl;\n const authHeaders = Object.fromEntries(targets.ingest.headers.entries());\n\n let stopFn: (() => void) | null = null;\n let events: string[] = [];\n let flushTimer: ReturnType<typeof setInterval> | null = null;\n let firstTs: number | null = null;\n let lastTs: number | null = null;\n\n const flush = () => {\n if (events.length === 0) {\n return;\n }\n const chunk = events;\n events = [];\n const payload: ChunkPayload = {\n events: chunk,\n firstTs,\n lastTs,\n };\n firstTs = null;\n lastTs = null;\n\n // Fire-and-forget; replay capture must never block the rrweb event\n // loop. Failed chunks are dropped — replay is best-effort and the\n // next session will still record cleanly.\n deliverChunk({ ctx, uploadBaseUrl, authHeaders, payload }).catch(\n (error: unknown) => {\n log.warn(\"replay chunk dropped: %o\", error);\n }\n );\n };\n\n let unsubscribeHidden: (() => void) | null = null;\n\n const init = async () => {\n try {\n const rrweb = await import(\"rrweb\");\n stopFn =\n rrweb.record({\n emit(event) {\n const ts = Date.now();\n if (firstTs === null) {\n firstTs = ts;\n }\n lastTs = ts;\n events.push(JSON.stringify(event));\n },\n }) ?? null;\n\n flushTimer = setInterval(flush, FLUSH_INTERVAL_MS);\n unsubscribeHidden = onPageHidden(flush);\n log.debug(\"recording started\");\n } catch {\n log.error(\"rrweb failed to load, replay disabled\");\n }\n };\n\n // `init()` swallows rrweb load failures internally — no outer `.catch`\n // needed (it can never reject).\n init();\n\n return () => {\n flush();\n stopFn?.();\n if (flushTimer) {\n clearInterval(flushTimer);\n }\n unsubscribeHidden?.();\n };\n },\n};\n\nexport default replayPlugin;\n"],"mappings":"kNAOA,MAAM,IAAM,aAAa,QAAQ,EA8BjC,eAAe,aAAa,CAC1B,IACA,cACA,YACA,SAC8B,CAC9B,IAAM,UAAY,IAAI,aAAa,EACnC,GAAI,CAAC,UACH,OAGF,IAAM,KAAO,KAAK,UAAU,QAAQ,MAAM,EACpC,UAAY,KAAK,OAEjB,IAAM,MAAM,MAChB,sBACE,cACA,qBAAwB,mBAAmB,SAAS,GACtD,EACA,CACE,OAAQ,OACR,QAAS,CAAE,GAAG,YAAa,eAAgB,kBAAmB,EAC9D,IACF,CACF,EACA,GAAI,CAAC,IAAI,GAAI,CACX,IAAI,KAAK,oCAAqC,IAAI,MAAM,EACxD,MACF,CAEA,GAAM,CAAE,WAAe,MAAM,IAAI,KAAK,EAmBtC,MAbmB,UAAU,yBAAW,EAAE,UAAU,eAAgB,CAClE,WAAY,CACV,mBAAoB,UACpB,0BAA2B,UAC3B,2BAA4B,QAAQ,OAAO,OAC3C,GAAI,QAAQ,UAAY,KACpB,CAAC,EACD,CAAE,8BAA+B,QAAQ,OAAQ,EACrD,GAAI,QAAQ,SAAW,KACnB,CAAC,EACD,CAAE,6BAA8B,QAAQ,MAAO,CACrD,CACF,CACG,EAAE,IAAI,CACX,CAEA,MAAa,aAAuB,CAClC,KAAM,SAEN,MAAM,IAAK,CACT,IAAM,QAAU,eAAe,EACzB,cAAgB,QAAQ,iBACxB,YAAc,OAAO,YAAY,QAAQ,OAAO,QAAQ,QAAQ,CAAC,EAEnE,OAA8B,KAC9B,OAAmB,CAAC,EACpB,WAAoD,KACpD,QAAyB,KACzB,OAAwB,KAEtB,UAAc,CAClB,GAAI,OAAO,SAAW,EACpB,OAEF,IAAM,MAAQ,OACd,OAAS,CAAC,EACV,IAAM,QAAwB,CAC5B,OAAQ,MACR,QACA,MACF,EACA,QAAU,KACV,OAAS,KAKT,aAAa,CAAE,IAAK,cAAe,YAAa,OAAQ,CAAC,EAAE,MACxD,OAAmB,CAClB,IAAI,KAAK,2BAA4B,KAAK,CAC5C,CACF,CACF,EAEI,kBAAyC,KA6B7C,OAFA,SAzByB,CACvB,GAAI,CAEF,QACE,MAFkB,OAAO,UAEnB,OAAO,CACX,KAAK,MAAO,CACV,IAAM,GAAK,KAAK,IAAI,EAChB,UAAY,OACd,QAAU,IAEZ,OAAS,GACT,OAAO,KAAK,KAAK,UAAU,KAAK,CAAC,CACnC,CACF,CAAC,GAAK,KAER,WAAa,YAAY,MAAO,GAAiB,EACjD,kBAAoB,aAAa,KAAK,EACtC,IAAI,MAAM,mBAAmB,CAC/B,MAAQ,CACN,IAAI,MAAM,uCAAuC,CACnD,CACF,GAIK,MAEQ,CACX,MAAM,EACN,SAAS,EACL,YACF,cAAc,UAAU,EAE1B,oBAAoB,CACtB,CACF,CACF"}
|