@faststats/web 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/REPLAY_PAYLOAD.md +64 -0
- package/dist/chunks/{error-CDVOMiI9.js → error-Cd9PTS5v.js} +2 -2
- package/dist/chunks/{replay-BuX3_0xs.d.ts → replay-DvJYurEC.d.ts} +10 -2
- package/dist/chunks/replay-rTqcjOo2.js +1 -0
- package/dist/chunks/send-data-B2fYGj6v.js +1 -0
- package/dist/chunks/session-manager-Cy63ptPF.js +1 -0
- package/dist/chunks/web-vitals-Be-Cg4Po.js +1 -0
- package/dist/error.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/replay.d.ts +1 -1
- package/dist/replay.js +1 -1
- package/dist/web-vitals.js +1 -1
- package/package.json +4 -7
- package/src/analytics.ts +21 -10
- package/src/error.ts +6 -1
- package/src/replay.ts +177 -50
- package/src/utils/identifiers.ts +30 -72
- package/src/utils/session-manager.ts +416 -0
- package/src/web-vitals.ts +1 -1
- package/tests/analytics.test.ts +7 -4
- package/tests/identifiers.test.ts +15 -32
- package/tests/replay.test.ts +180 -10
- package/tests/session-manager.test.ts +161 -0
- package/dist/chunks/identifiers-CQeWm7wi.js +0 -1
- package/dist/chunks/replay-CHFW2q4E.js +0 -1
- package/dist/chunks/send-data-DL_GlsQw.js +0 -1
- package/dist/chunks/web-vitals-GwPlL7Zy.js +0 -1
- package/wrangler.toml +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# `/v1/replay` payload
|
|
2
|
+
|
|
3
|
+
Session replay batches are sent as `POST` requests to `/v1/replay`, optionally gzip-compressed via `?encoding=gzip` with `Content-Type: application/octet-stream`.
|
|
4
|
+
|
|
5
|
+
## Request body (JSON)
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"token": "site_xxx",
|
|
10
|
+
"sessionId": "uuid",
|
|
11
|
+
"windowId": "uuid",
|
|
12
|
+
"viewId": "uuid",
|
|
13
|
+
"sessionStart": 1730000000000,
|
|
14
|
+
"identifier": "optional-anon-id",
|
|
15
|
+
"batchId": "{sessionId}-{sequence}-{random}",
|
|
16
|
+
"sequence": 0,
|
|
17
|
+
"timestamp": 1730000000500,
|
|
18
|
+
"url": "https://example.com/path",
|
|
19
|
+
"isFinal": false,
|
|
20
|
+
"events": []
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Fields
|
|
25
|
+
|
|
26
|
+
| Field | Type | Description |
|
|
27
|
+
|-------|------|-------------|
|
|
28
|
+
| `token` | string | Site / project key |
|
|
29
|
+
| `sessionId` | string | User session (localStorage, shared across tabs; 30m idle / 24h max rotation) |
|
|
30
|
+
| `windowId` | string | Browser tab (sessionStorage per site key; stable across SDK remounts in same tab) |
|
|
31
|
+
| `viewId` | string | Page view within tab (new UUID on each SPA/full navigation) |
|
|
32
|
+
| `sessionStart` | number | Session start time in ms since epoch |
|
|
33
|
+
| `identifier` | string? | Anonymous user id (omitted in cookieless mode) |
|
|
34
|
+
| `batchId` | string | Idempotent key for retries (`{sessionId}-{sequence}-{uuid}`) |
|
|
35
|
+
| `sequence` | number | Monotonic batch index per recorder instance |
|
|
36
|
+
| `timestamp` | number | Batch creation time (ms since epoch) |
|
|
37
|
+
| `url` | string | Page URL when the batch was created |
|
|
38
|
+
| `isFinal` | boolean? | `true` on last batch before session rotation or tab unload |
|
|
39
|
+
| `events` | array | rrweb `eventWithTime` records |
|
|
40
|
+
|
|
41
|
+
## Custom events in `events`
|
|
42
|
+
|
|
43
|
+
SPA navigations inject a custom rrweb event:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"type": 5,
|
|
48
|
+
"timestamp": 1730000001000,
|
|
49
|
+
"data": {
|
|
50
|
+
"tag": "faststats:view",
|
|
51
|
+
"payload": {
|
|
52
|
+
"href": "https://example.com/about",
|
|
53
|
+
"viewId": "uuid"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Ingestion guidelines
|
|
60
|
+
|
|
61
|
+
1. Stitch batches by `(token, sessionId, windowId, sequence)`; dedupe retries with `batchId`.
|
|
62
|
+
2. When `sessionId` changes and the prior batch had `isFinal: true`, finalize the previous recording segment.
|
|
63
|
+
3. Group events within a tab by `viewId` (and `faststats:view` meta events for href changes).
|
|
64
|
+
4. Legacy clients may send `pageId` instead of `viewId` and omit `sessionStart` / `isFinal` — treat as older SDK versions.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./rolldown-runtime-MP-BAFHD.js";import{n as t,t as n}from"./api-urls-DaeYkG0_.js";import{n as r,
|
|
2
|
-
`).map(e=>e.trim()).filter(Boolean);function
|
|
1
|
+
import{t as e}from"./rolldown-runtime-MP-BAFHD.js";import{n as t,t as n}from"./api-urls-DaeYkG0_.js";import{n as r,r as i}from"./session-manager-Cy63ptPF.js";import{n as a,t as o}from"./send-data-B2fYGj6v.js";var s=e({default:()=>m});const c=/(?:^|\()(chrome|moz|ms-browser|safari-web)-extension:\/\//,l=e=>e?.split(`
|
|
2
|
+
`).map(e=>e.trim()).filter(Boolean);function u(e){if(e instanceof Error)return{error:e.name?.trim()||`Error`,message:e.message,stack:l(e.stack),cause:u(e.cause)};if(typeof e==`string`)return{error:`Error`,message:e}}function d(e){let t=``;for(let n=e;n;n=n.cause)t+=`${n.error}\0${n.message??``}\0`;return t}function f(e){let t=2166136261,n=3598710387;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);t=Math.imul(t^i,16777619),n=Math.imul(n^i,2246822519)}return`err_${(t>>>0).toString(16).padStart(8,`0`)}${(n>>>0).toString(16).padStart(8,`0`)}`}function p(){let e=globalThis.__SOURCEMAPS_BUILD__?.buildId;return typeof e==`string`&&e.trim()?e:void 0}var m=class{endpoint;seen=new WeakSet;queue=new Map;timer=null;started=!1;flushing=!1;constructor(e){this.options=e,this.endpoint=`${t(e.baseUrl)}${n.events}`}log(...e){this.options.debug&&console.log(`[ErrorTracker]`,...e)}start(){this.started||typeof window>`u`||(this.started=!0,window.addEventListener(`error`,this.onError),window.addEventListener(`unhandledrejection`,this.onRejection),window.addEventListener(`pagehide`,this.scheduleFlush),document.addEventListener(`visibilitychange`,this.onVisibility),this.timer=setInterval(this.scheduleFlush,this.options.flushInterval??5e3),this.log(`Started`))}stop(){!this.started||typeof window>`u`||(this.started=!1,window.removeEventListener(`error`,this.onError),window.removeEventListener(`unhandledrejection`,this.onRejection),window.removeEventListener(`pagehide`,this.scheduleFlush),document.removeEventListener(`visibilitychange`,this.onVisibility),this.timer&&clearInterval(this.timer),this.timer=null,this.scheduleFlush(),this.log(`Stopped`))}captureError(e){this.capture(`error`,e.message,!0,e)}onError=e=>{this.capture(`error`,e.message||`Unknown error`,!1,e.error,e.filename||``,e.lineno)};onRejection=e=>{let t=e.reason,n=t instanceof Error?t.message:typeof t==`string`?t:`Unhandled promise rejection`;this.capture(`unhandledrejection`,n,!1,t)};onVisibility=()=>{document.visibilityState===`hidden`&&this.scheduleFlush()};scheduleFlush=()=>{this.flush()};capture(e,t,n,r,i=``,a=``){let o=r instanceof Error?r.stack??``:``;if(c.test(`${i}\n${o}`))return;if(typeof r==`object`&&r){if(this.seen.has(r)){this.log(`Skipping duplicate:`,t);return}this.seen.add(r)}let s={error:e===`unhandledrejection`?`UnhandledRejection`:`Error`,message:t,handled:n};if(r instanceof Error){s.stack=l(r.stack);let e=u(r.cause);e&&(s.cause=e)}let p=f(`${e}\0${n?`handled`:`unhandled`}\0${t}\0${i}\0${a}\0${d(s.cause)}`),m=this.queue.get(p);m?m.count++:this.queue.set(p,{hash:p,count:1,...s}),this.log(`Captured:`,s),this.queue.size>=(this.options.maxQueueSize??50)&&this.scheduleFlush()}async flush(){if(this.flushing||this.queue.size===0)return;let e=[...this.queue.values()];this.queue.clear(),this.flushing=!0;let t=a(),n=p(),s=JSON.stringify({token:this.options.siteKey,...t?{userId:t}:{},sessionId:r(),windowId:i(this.options.siteKey),...n?{buildId:n}:{},sdkName:this.options.sdkName??`@faststats/web`,sdkVersion:this.options.sdkVersion??`0.2.14`,data:{url:location.href,page:location.pathname,referrer:document.referrer||null,title:document.title},errors:e});this.log(`Flushing:`,e);try{await o({url:this.endpoint,data:s,debug:this.options.debug,debugPrefix:`[ErrorTracker]`})||this.requeue(e)}catch{this.requeue(e)}finally{this.flushing=!1}}requeue(e){for(let t of e){let e=this.queue.get(t.hash);e?e.count+=t.count:this.queue.set(t.hash,t)}}};export{s as n,m as t};
|
|
@@ -8,6 +8,7 @@ interface ReplayTrackerOptions {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
debug?: boolean;
|
|
10
10
|
compress?: boolean;
|
|
11
|
+
cookieless?: boolean;
|
|
11
12
|
samplingPercentage?: number;
|
|
12
13
|
flushInterval?: number;
|
|
13
14
|
maxEvents?: number;
|
|
@@ -34,7 +35,8 @@ declare class ReplayTracker {
|
|
|
34
35
|
private readonly events;
|
|
35
36
|
private readonly pending;
|
|
36
37
|
private pendingSizeBytes;
|
|
37
|
-
private
|
|
38
|
+
private viewId;
|
|
39
|
+
private readonly windowId;
|
|
38
40
|
private started;
|
|
39
41
|
private startTime;
|
|
40
42
|
private sequence;
|
|
@@ -44,7 +46,9 @@ declare class ReplayTracker {
|
|
|
44
46
|
private minLengthFlushTask;
|
|
45
47
|
private stopRecording?;
|
|
46
48
|
private sending;
|
|
49
|
+
private unsubscribeRotation?;
|
|
47
50
|
constructor(options: ReplayTrackerOptions);
|
|
51
|
+
private get cookieless();
|
|
48
52
|
private get debug();
|
|
49
53
|
private get flushInterval();
|
|
50
54
|
private get maxEvents();
|
|
@@ -53,10 +57,14 @@ declare class ReplayTracker {
|
|
|
53
57
|
private get minReplayLengthMs();
|
|
54
58
|
private get shouldCompress();
|
|
55
59
|
private log;
|
|
60
|
+
private sessionContext;
|
|
56
61
|
start(): void;
|
|
62
|
+
trackPageChange(url?: string): void;
|
|
57
63
|
private beginRecording;
|
|
58
64
|
stop(): void;
|
|
59
|
-
getSessionId(): string
|
|
65
|
+
getSessionId(): string;
|
|
66
|
+
getWindowId(): string;
|
|
67
|
+
private onSessionRotated;
|
|
60
68
|
private onEvent;
|
|
61
69
|
private onUnload;
|
|
62
70
|
private onVisibilityChange;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./rolldown-runtime-MP-BAFHD.js";import{n as t,t as n}from"./api-urls-DaeYkG0_.js";import{a as r,f as i,i as a,s as o,t as s}from"./session-manager-Cy63ptPF.js";import{n as c,t as l}from"./send-data-B2fYGj6v.js";import{t as u}from"./types-CYzR5xtT.js";import{EventType as d}from"@rrweb/types";import{record as f}from"rrweb";var p=e({default:()=>v});const m={mousemove:50,mouseInteraction:!0,scroll:150,media:800,input:`last`};function h(e){return`faststats_replay_sampled_${e}`}function g(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t)}function _(e,t,n){let r=u(t);if(r>=100)return!0;if(r<=0)return!1;let i=a(e,n).sessionId,o=h(e),s=`${i}:${r}`;try{let e=sessionStorage;if(e){let t=e.getItem(o);if(t===s)return!0;if(t?.startsWith(`${i}:`))return!1}}catch{}let c=g(i)%100<r;try{sessionStorage?.setItem(o,c?s:`${i}:out`)}catch{}return c}var v=class{endpoint;compressionSupported=typeof window<`u`&&`CompressionStream`in window;sampled;events=[];pending=[];pendingSizeBytes=0;viewId=s();windowId=s();started=!1;startTime=0;sequence=0;intervalId=null;flushTask=null;retryTask=null;minLengthFlushTask=null;stopRecording;sending=!1;unsubscribeRotation;constructor(e){this.options=e,this.endpoint=`${t(e.baseUrl)}${n.replay}`,this.sampled=_(e.siteKey,e.samplingPercentage??100,e.cookieless??!1)}get cookieless(){return this.options.cookieless??!1}get debug(){return this.options.debug??!1}get flushInterval(){return this.options.flushInterval??1e4}get maxEvents(){return this.options.maxEvents??500}get maxPendingBatches(){return this.options.maxPendingBatches??30}get maxQueueSizeBytes(){return this.options.maxQueueSizeBytes??2097152}get minReplayLengthMs(){return this.options.minReplayLengthMs??3e3}get shouldCompress(){return this.options.compress??!0}log(...e){this.debug&&console.log(`[Replay]`,...e)}sessionContext(){return a(this.options.siteKey,this.cookieless)}start(){this.started||typeof window>`u`||!this.sampled||(this.started=!0,this.viewId=s(),this.startTime=r(this.cookieless),this.unsubscribeRotation=o(e=>{this.onSessionRotated(e)}),this.beginRecording(),this.intervalId=setInterval(this.requestFlush,this.flushInterval),window.addEventListener(`beforeunload`,this.onUnload),window.addEventListener(`pagehide`,this.onUnload),document.addEventListener(`visibilitychange`,this.onVisibilityChange),this.log(`Recording started`))}trackPageChange(e){if(!this.started)return;let t=e??window.location.href;this.viewId=s();let n={type:5,timestamp:Date.now(),data:{tag:`faststats:view`,payload:{href:t,viewId:this.viewId}}};this.onEvent(n,!1)}async beginRecording(){let e=this.options.recordConsole??!0?await import(`@rrweb/rrweb-plugin-console-record`):null;if(!this.started)return;let t=[];e&&t.push(e.getRecordConsolePlugin()),this.stopRecording=f({emit:this.onEvent,sampling:this.options.sampling??m,slimDOMOptions:this.options.slimDOMOptions??{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0},maskAllInputs:this.options.maskAllInputs??!0,maskInputOptions:this.options.maskInputOptions??{password:!0,email:!0,tel:!0},blockClass:this.options.blockClass,blockSelector:this.options.blockSelector,maskTextClass:this.options.maskTextClass,maskTextSelector:this.options.maskTextSelector,checkoutEveryNms:this.options.checkoutEveryNms??6e4,checkoutEveryNth:this.options.checkoutEveryNth,plugins:t})}stop(){if(this.started){if(this.started=!1,this.unsubscribeRotation?.(),this.unsubscribeRotation=void 0,this.stopRecording?.(),this.stopRecording=void 0,this.intervalId&&clearInterval(this.intervalId),this.flushTask&&clearTimeout(this.flushTask),this.retryTask&&clearTimeout(this.retryTask),this.minLengthFlushTask&&clearTimeout(this.minLengthFlushTask),this.intervalId=null,this.flushTask=null,this.retryTask=null,this.minLengthFlushTask=null,window.removeEventListener(`beforeunload`,this.onUnload),window.removeEventListener(`pagehide`,this.onUnload),document.removeEventListener(`visibilitychange`,this.onVisibilityChange),!this.hasReachedMinLength()){this.events.length=0,this.log(`Session too short (${Date.now()-this.startTime}ms), discarding events`);return}this.flush(!0,void 0,!0),this.log(`Recording stopped`)}}getSessionId(){return this.sessionContext().sessionId}getWindowId(){return this.sessionContext().windowId}onSessionRotated(e){if(this.started){if(this.events.length>0)if(!this.hasReachedMinLength())this.scheduleMinLengthFlush();else{let t=this.createBatch(this.events.splice(0),e,!0);this.enqueueBatch(t)}this.pending.length>0&&queueMicrotask(()=>void this.flush(!1))}}onEvent=(e,t)=>{if(this.events.push(e),t||this.events.length>=this.maxEvents||e.type===d.FullSnapshot&&this.hasReachedMinLength()){this.requestFlush();return}this.scheduleMinLengthFlush()};onUnload=()=>{this.flush(!0,void 0,!0)};onVisibilityChange=()=>{document.visibilityState===`hidden`&&this.flush(!0,void 0,!0)};hasReachedMinLength(){return this.minReplayLengthMs<=0||Date.now()-this.startTime>=this.minReplayLengthMs}requestFlush=()=>{this.flushTask||this.sending||this.events.length===0||(this.minLengthFlushTask&&=(clearTimeout(this.minLengthFlushTask),null),this.flushTask=setTimeout(()=>{this.flushTask=null,this.flush(!1)},0))};scheduleMinLengthFlush(){if(this.minLengthFlushTask||this.events.length===0||this.hasReachedMinLength())return;let e=Math.max(0,this.minReplayLengthMs-(Date.now()-this.startTime)),t=Math.min(e,2147483647);this.minLengthFlushTask=setTimeout(()=>{this.minLengthFlushTask=null,this.requestFlush()},t)}createBatch(e,t,n){let r=c(this.cookieless),i=this.sequence++;return{token:this.options.siteKey,sessionId:t.sessionId,windowId:this.windowId,viewId:this.viewId,sessionStart:t.sessionStart,...r?{identifier:r}:{},batchId:this.createBatchId(t.sessionId,i),sequence:i,timestamp:Date.now(),url:window.location.href,...n?{isFinal:!0}:{},events:e}}createBatchId(e,t){return`${e}-${t}-${typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`}getBatchSizeBytes(e){return new TextEncoder().encode(JSON.stringify(e)).byteLength}dropOldestPendingBatch(e){let t=this.pending.shift();t&&(this.pendingSizeBytes=Math.max(0,this.pendingSizeBytes-this.getBatchSizeBytes(t)),this.log(`${e}, dropping batch ${t.sequence}`))}enqueueBatch(e){let t=this.getBatchSizeBytes(e);if(t>this.maxQueueSizeBytes){this.log(`Replay batch ${e.sequence} is ${t}B, exceeding ${this.maxQueueSizeBytes}B queue limit; dropping`);return}for(;this.pending.length>0&&this.pendingSizeBytes+t>this.maxQueueSizeBytes;)this.dropOldestPendingBatch(`Pending queue size limit reached`);for(;this.pending.length>=this.maxPendingBatches;)this.dropOldestPendingBatch(`Pending batch limit reached`);this.pending.push(e),this.pendingSizeBytes+=t}async encodeBatch(e){let t=JSON.stringify(e);if(!this.shouldCompress||!this.compressionSupported)return{data:t,isCompressed:!1};try{let e=await this.compress(t);return this.log(`Compressed ${t.length}B -> ${e.byteLength}B (${Math.round(e.byteLength/t.length*100)}%)`),{data:e,isCompressed:!0}}catch{return this.log(`Compression failed, using uncompressed`),{data:t,isCompressed:!1}}}async flush(e,t,n){if(this.sending)return;let r=t?null:i(this.cookieless);if(r&&this.events.length>0)if(!this.hasReachedMinLength())this.scheduleMinLengthFlush();else{let e=this.createBatch(this.events.splice(0),r.prev,!0);this.enqueueBatch(e)}let a=t??this.sessionContext();if(this.events.length>0)if(!this.hasReachedMinLength())this.scheduleMinLengthFlush();else{let e=this.createBatch(this.events.splice(0),a,n);this.enqueueBatch(e)}if(this.pending.length!==0){this.sending=!0;try{for(;this.pending.length>0;){let t=this.pending[0];if(!t)break;let n=await this.encodeBatch(t);if(!await this.send(n.data,n.isCompressed,e)){this.log(`Failed to send replay batch ${t.sequence}, retrying`),this.scheduleRetry();break}this.dropOldestPendingBatch(`Sent replay batch`),e=!1}}finally{this.sending=!1}}}scheduleRetry(){this.retryTask||=setTimeout(()=>{this.retryTask=null,this.flush(!1)},1e3)}async compress(e){let t=new Blob([e]).stream().pipeThrough(new CompressionStream(`gzip`)),n=await new Response(t).arrayBuffer();return new Uint8Array(n)}send(e,t,n){return l({url:t?`${this.endpoint}?encoding=gzip`:this.endpoint,data:e,contentType:t?`application/octet-stream`:`application/json`,debug:!1,useBeacon:n,keepalive:n})??Promise.resolve(!1)}};export{p as n,v as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{o as e,t}from"./session-manager-Cy63ptPF.js";const n=`faststats_anon_id`;function r(){try{return globalThis.localStorage}catch{return}}function i(t){return t??e()?``:a()}function a(){let e=r();if(!e)return``;try{let t=e.getItem(n);if(t)return t}catch{return``}let i=t();try{e.setItem(n,i)}catch{return``}return i}function o(e){if(e)return``;try{let e=r();if(!e)return``;e.removeItem(n)}catch{return``}return a()}async function s(e){let{url:t,data:n,contentType:r=`application/json`,headers:i={},debug:a=!1,debugPrefix:o=`[Analytics]`,useBeacon:s=!0,keepalive:c=!0}=e;if(s&&typeof globalThis.navigator?.sendBeacon==`function`)try{let e=n instanceof Blob?n:typeof Blob<`u`?new Blob([n],{type:r}):n;if(globalThis.navigator.sendBeacon(t,e))return a&&console.log(`${o} Sent via beacon`),!0}catch{}try{let e=await fetch(t,{method:`POST`,body:n,headers:{"Content-Type":r,...i},keepalive:c}),s=e.ok;if(a){let t=s?`${o} Sent via fetch`:`${o} Failed: ${e.status}`;console[s?`log`:`warn`](t)}return s}catch{return a&&console.warn(`${o} Failed to send`),!1}}export{i as n,o as r,s as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=`faststats_session_id`,t=`faststats_session_activity`,n=`faststats_session_start`,r=`session_id`,i=`session_timestamp`,a=`session_start`;let o=!1,s=``,c=null;const l=new Set;function u(e,t){try{return e?.getItem(t)??null}catch{return null}}function d(e,t,n){if(!e)return!1;try{return e.setItem(t,n),!0}catch{return!1}}function f(e,t){try{e?.removeItem(t)}catch{}}function p(){try{return globalThis.localStorage}catch{return}}function m(){try{return globalThis.sessionStorage}catch{return}}function h(e,t){for(let n of l)n(e,t)}function g(){return typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}function _(e){o=e,e&&(c=null)}function v(){return o}function y(e){s=e}function b(e){return`faststats_window_id_${e}`}function x(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isFinite(t)?t:null}function S(){let o=m(),s=p(),c=u(o,r);if(!c||u(s,e)){c&&(f(o,r),f(o,i),f(o,a));return}let l=x(u(o,i)),h=x(u(o,a)),g=Date.now(),_=d(s,e,c);d(s,t,String(l??g)),d(s,n,String(h??l??g)),_&&(f(o,r),f(o,i),f(o,a))}function C(){S();let r=p(),i=u(r,e),a=x(u(r,t)),o=x(u(r,n));return!i||a===null?null:{sessionId:i,activity:a,sessionStart:o??a}}function w(r,i,a){let o=p(),s=d(o,e,r);d(o,t,i.toString()),d(o,n,a.toString()),s||(c={sessionId:r,activity:i,sessionStart:a})}function T(){let r=p();f(r,e),f(r,t),f(r,n)}function E(e,t,n){return n-e>=18e5?!0:n-t>=864e5}function D(e){return c||={sessionId:g(),sessionStart:e,activity:e},c}function O(e,t){let n=Date.now();if(e){let e=D(n);return t&&(e.activity=n),{sessionId:e.sessionId,sessionStart:e.sessionStart,rotated:!1,previous:null}}let r=C()??c;if(r&&!E(r.activity,r.sessionStart,n))return t&&w(r.sessionId,n,r.sessionStart),{sessionId:r.sessionId,sessionStart:r.sessionStart,rotated:!1,previous:null};let i=r===null?null:{sessionId:r.sessionId,sessionStart:r.sessionStart},a=g();return w(a,n,n),{sessionId:a,sessionStart:n,rotated:i!==null,previous:i}}function k(e,t){if(t??o)return O(!0,!1).sessionId;let n=b(e),r=m();if(!r)return O(!1,!1).sessionId;let i=u(r,n);if(i)return i;let a=g();return d(r,n,a),a}function A(e){f(m(),b(e))}function j(e,t){let n=t??o,r=O(n,!1),i=k(e,n),a={sessionId:r.sessionId,windowId:i,sessionStart:r.sessionStart};return r.rotated&&r.previous&&h({sessionId:r.previous.sessionId,windowId:i,sessionStart:r.previous.sessionStart},a),a}function M(e){return O(e??o,!0).sessionId}function N(e){return O(e??o,!1).sessionStart}function P(e){let t=e??o,n=O(t,!0);if(n.rotated&&n.previous){let e=s||`_default`,r={prev:{sessionId:n.previous.sessionId,windowId:k(e,t),sessionStart:n.previous.sessionStart},next:{sessionId:n.sessionId,windowId:k(e,t),sessionStart:n.sessionStart}};return h(r.prev,r.next),r}return null}function F(e){let t=e??o,n=Date.now();if(t){c&&(c.activity=n);return}let r=C()??c;r&&w(r.sessionId,n,r.sessionStart)}function I(e){let t=e??s??`_default`,n=Date.now(),r=null;if(o)c&&(r={sessionId:c.sessionId,windowId:c.sessionId,sessionStart:c.sessionStart}),c={sessionId:g(),sessionStart:n,activity:n};else{let e=C();e&&(r={sessionId:e.sessionId,windowId:k(t,!1),sessionStart:e.sessionStart}),T(),c=null}A(t);let i=j(t,o);return r&&r.sessionId!==i.sessionId&&h(r,i),i}function L(e){return l.add(e),()=>{l.delete(e)}}export{N as a,F as c,y as d,P as f,j as i,I as l,M as n,v as o,k as r,L as s,g as t,_ as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./rolldown-runtime-MP-BAFHD.js";import{n as t,t as n}from"./api-urls-DaeYkG0_.js";import{n as r}from"./session-manager-Cy63ptPF.js";import{t as i}from"./types-CYzR5xtT.js";var a=e({default:()=>o}),o=class{endpoint;sampled;metrics=new Map;started=!1;url=``;constructor(e){this.options=e,this.endpoint=`${t(e.baseUrl)}${n.vitals}`,this.sampled=Math.random()*100<i(e.samplingPercentage)}get debug(){return this.options.debug??!1}log(...e){this.debug&&console.log(`[WebVitals]`,...e)}async start(){if(this.started||typeof window>`u`)return;this.started=!0,this.url=window.location.href,document.addEventListener(`visibilitychange`,this.onHidden,{passive:!0}),window.addEventListener(`pagehide`,this.onPageHide,{passive:!0});let e=this.options.attribution?await import(`web-vitals/attribution`):await import(`web-vitals`);this.started&&(e.onCLS(this.capture,{reportAllChanges:!0}),e.onINP(this.capture,{reportAllChanges:!0}),e.onLCP(this.capture,{reportAllChanges:!0}),e.onFCP(this.capture),e.onTTFB(this.capture),this.log(`Tracking started`))}stop(){!this.started||typeof window>`u`||(this.started=!1,this.removeListeners(),this.flush())}trackPageChange(e){if(!this.started||typeof window>`u`)return;let t=e??window.location.href;t!==this.url&&(this.flush(),this.url=t)}onHidden=()=>{document.visibilityState===`hidden`&&this.flush()};onPageHide=()=>{this.flush()};capture=e=>{if(!this.started||!this.sampled)return;let t=e.name,n=e.attribution;this.metrics.set(t,{metric:t,value:e.value,attributes:{id:e.id,rating:e.rating,delta:e.delta,navigationType:e.navigationType,...n??{}}})};async flush(){if(typeof window>`u`||typeof fetch!=`function`||!this.metrics.size)return;let e=Array.from(this.metrics.values()),t=this.url;this.metrics.clear();try{let n=new AbortController,i=window.setTimeout(()=>n.abort(),3e3),a=await fetch(this.endpoint,{method:`POST`,body:JSON.stringify({sessionId:r(),vitals:e,metadata:{url:t}}),headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.options.siteKey}`},keepalive:!0,signal:n.signal});if(clearTimeout(i),!a.ok)throw Error(`HTTP ${a.status}`)}catch(e){this.log(`Failed to send metrics`,e)}}removeListeners(){document.removeEventListener(`visibilitychange`,this.onHidden),window.removeEventListener(`pagehide`,this.onPageHide)}};export{a as n,o as t};
|
package/dist/error.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./chunks/error-
|
|
1
|
+
import{t as e}from"./chunks/error-Cd9PTS5v.js";export{e as default};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as FeatureFlagEvaluation, r as fetchFeatureFlagEvaluation, t as FeatureFlagCheckContext } from "./chunks/feature-flags-BClx56v5.js";
|
|
2
|
-
import { n as ReplayTrackerOptions } from "./chunks/replay-
|
|
2
|
+
import { n as ReplayTrackerOptions } from "./chunks/replay-DvJYurEC.js";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/types.d.ts
|
|
5
5
|
interface SendDataOptions {
|
|
@@ -125,6 +125,7 @@ declare class WebAnalytics {
|
|
|
125
125
|
getConsentMode(): ConsentMode;
|
|
126
126
|
getAnonymousId(): string;
|
|
127
127
|
getSessionId(): string;
|
|
128
|
+
getWindowId(): string;
|
|
128
129
|
checkFeatureFlag(key: string, attributes?: Record<string, unknown>, opts?: {
|
|
129
130
|
externalId?: string;
|
|
130
131
|
signal?: AbortSignal;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./chunks/api-urls-DaeYkG0_.js";import{a as r,i,n as a,o,r as s,s as c,t as l}from"./chunks/identifiers-CQeWm7wi.js";import{t as u}from"./chunks/send-data-DL_GlsQw.js";import{t as d}from"./chunks/types-CYzR5xtT.js";import{n as f}from"./chunks/feature-flags-DSOCIZHK.js";function p(e){return e.replayOptions?.samplingPercentage!==void 0||e.sessionReplays?.sampling?.percentage!==void 0}function m(e,t,n){if(!(e.sessionReplays?.enabled??e.trackReplay??p(e)))return null;let r=e.replayOptions??{};return{siteKey:e.siteKey,baseUrl:t,debug:n,...r,samplingPercentage:d(r.samplingPercentage??e.sessionReplays?.sampling?.percentage)}}const h={instance:null,pendingConsentMode:void 0};function g(){return h.instance}function _(e,t){typeof window>`u`||w()||h.instance?.track(e,t??{})}function v(e,t,n){return typeof window>`u`||w()?Promise.resolve(!1):h.instance?.identify(e,t,n??{})??Promise.resolve(!1)}function y(e=!0){typeof window>`u`||w()||h.instance?.logout(e)}function b(e){if(h.instance){h.instance.setConsentMode(e);return}h.pendingConsentMode=e}function x(){b(`granted`)}function S(){b(`denied`)}function C(e){typeof window>`u`||w()||h.instance?.reportError(e)}function w(){if(typeof localStorage>`u`)return!1;let e=localStorage.getItem(`disable-faststats`);return e===`true`||e===`1`}function T(e){for(;e;){if(e instanceof HTMLAnchorElement&&e.href)return e;e=e.parentNode}return null}function E(){let e={};if(!location.search)return e;let t=new URLSearchParams(location.search);for(let n of[`utm_source`,`utm_medium`,`utm_campaign`,`utm_term`,`utm_content`]){let r=t.get(n);r&&(e[n]=r)}return e}var D=class{webEndpoint;baseUrl;featureFlagsBaseUrl;debug;started=!1;destroyed=!1;pageKey=``;navTimer=null;heartbeatTimer=null;scrollDepth=0;pageEntryTime=0;pagePath=``;pageUrl=``;pageHash=``;hasLeftCurrentPage=!1;scrollHandler=null;consentMode;cookielessWhilePending;cleanupCallbacks=[];childTrackers=[];pendingReportedErrors=[];errorTracker=null;handleVisibilityChange=()=>{document.visibilityState===`hidden`?(i(),this.leavePage(),this.stopHeartbeat()):(i(),this.enterPage(),this.startHeartbeat())};handlePageHide=()=>{this.leavePage()};handlePopState=()=>{this.navigate()};handleHashChange=()=>{this.navigate()};constructor(r){this.options=r,this.baseUrl=e(r.baseUrl),this.featureFlagsBaseUrl=t(r.featureFlagsBaseUrl),this.webEndpoint=`${this.baseUrl}${n.events}`,this.debug=r.debug??!1,this.consentMode=r.consent?.mode??`granted`,this.cookielessWhilePending=r.consent?.cookielessWhilePending??!0,h.pendingConsentMode!==void 0&&(this.consentMode=h.pendingConsentMode,h.pendingConsentMode=void 0),(r.autoTrack??!0)&&this.init()}log(e){this.debug&&console.log(`[Analytics] ${e}`)}init(){if(!(typeof window>`u`)){if(w()){this.log(`disabled`);return}h.instance=this,c(this.isCookielessMode()),setTimeout(()=>void this.start(),0)}}registerCleanup(e){this.cleanupCallbacks.push(e)}addWindowListener(e,t){window.addEventListener(e,t),this.registerCleanup(()=>window.removeEventListener(e,t))}addDocumentListener(e,t){document.addEventListener(e,t),this.registerCleanup(()=>document.removeEventListener(e,t))}patchHistory(){let e=history.pushState.bind(history),t=history.replaceState.bind(history);history.pushState=(t,n,r)=>{e(t,n,r),this.navigate()},history.replaceState=(e,n,r)=>{t(e,n,r),this.navigate()},this.registerCleanup(()=>{history.pushState=e,history.replaceState=t})}ensureStarted(){return typeof window>`u`||this.destroyed||w()?!1:(this.started||this.start(),!0)}stopHeartbeat(){this.heartbeatTimer&&=(clearInterval(this.heartbeatTimer),null)}stopNavigationTimer(){this.navTimer&&=(clearTimeout(this.navTimer),null)}stopChildTrackers(){for(let e of this.childTrackers.splice(0))e.stop?.();this.errorTracker=null}registerChildTracker(e){return!this.started||this.destroyed||h.instance!==this?(e.stop?.(),!1):(this.childTrackers.push(e),!0)}async startChildTracker(e,t,n){try{let r=await t();return!this.started||this.destroyed||h.instance!==this?(r.stop?.(),null):(r.start(),this.registerChildTracker(r)?(n?.(r),this.log(`${e} loaded`),r):null)}catch(t){return this.log(`failed to initialize ${e} tracker: ${String(t)}`),null}}async startErrorTracker(){await this.startChildTracker(`error`,async()=>{let{default:e}=await import(`./chunks/error-CDVOMiI9.js`).then(e=>e.n);return new e({siteKey:this.options.siteKey,baseUrl:this.baseUrl,debug:this.debug,sdkName:this.options.sdkName,sdkVersion:this.options.sdkVersion})},e=>{for(this.errorTracker=e;this.pendingReportedErrors.length>0;){let t=this.pendingReportedErrors.shift();t&&e.captureError(t)}})}async startWebVitalsTracker(){await this.startChildTracker(`web-vitals`,async()=>{let{default:e}=await import(`./chunks/web-vitals-GwPlL7Zy.js`).then(e=>e.n);return new e({siteKey:this.options.siteKey,baseUrl:this.baseUrl,debug:this.debug,samplingPercentage:d(this.options.webVitals?.sampling?.percentage),attribution:this.options.webVitals?.attribution??!1})})}async startReplayTracker(e){await this.startChildTracker(`replay`,async()=>{let{default:t}=await import(`./chunks/replay-CHFW2q4E.js`).then(e=>e.n);return new t(e)})}async start(){if(this.started||this.destroyed||typeof window>`u`)return;if(h.instance&&h.instance!==this){this.log(`already started by another instance`);return}if(w()){this.log(`disabled`);return}this.started=!0,h.instance=this,c(this.isCookielessMode()),a();let e=this.options,t=m(e,this.baseUrl,this.debug);t&&this.startReplayTracker(t),e.trackErrors&&this.startErrorTracker(),e.trackWebVitals&&this.startWebVitalsTracker(),this.enterPage(),this.pageview({trigger:`load`}),this.links(),this.trackScroll(),this.startHeartbeat(),this.addDocumentListener(`visibilitychange`,this.handleVisibilityChange),this.addWindowListener(`pagehide`,this.handlePageHide),this.addWindowListener(`popstate`,this.handlePopState),e.trackHash&&this.addWindowListener(`hashchange`,this.handleHashChange),this.patchHistory()}destroy(){if(!this.destroyed){for(this.started&&typeof window<`u`&&this.leavePage(),this.pendingReportedErrors.length=0,this.stopNavigationTimer(),this.stopHeartbeat(),this.scrollHandler&&typeof window<`u`&&(window.removeEventListener(`scroll`,this.scrollHandler),this.scrollHandler=null);this.cleanupCallbacks.length>0;)this.cleanupCallbacks.pop()?.();this.stopChildTrackers(),h.instance===this&&(h.instance=null),this.started=!1,this.destroyed=!0}}pageview(e={}){if(!this.ensureStarted())return;let t=`${location.pathname}|${this.options.trackHash??!1?location.hash:``}`;t!==this.pageKey&&(this.pageKey=t,this.send(`pageview`,e))}track(e,t={}){this.ensureStarted()&&this.send(e,t)}identify(e,t,r={}){if(!this.ensureStarted()||this.isCookielessMode())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):u({url:`${this.baseUrl}${n.identify}`,data:JSON.stringify({token:this.options.siteKey,identifier:l(!1),externalId:i,email:a,name:r.name?.trim()||void 0,phone:r.phone?.trim()||void 0,avatarUrl:r.avatarUrl?.trim()||void 0,traits:r.traits??{}}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] identify`,useBeacon:!1})}logout(e=!0){this.ensureStarted()&&(e&&r(this.isCookielessMode()),o())}setConsentMode(e){this.consentMode=e,c(this.isCookielessMode())}optIn(){this.setConsentMode(`granted`)}optOut(){this.setConsentMode(`denied`)}getConsentMode(){return this.consentMode}getAnonymousId(){return l(this.isCookielessMode())}getSessionId(){return a()}async checkFeatureFlag(e,t,n){if(typeof window>`u`||w())return{value:`false`};let r=n?.externalId?.trim(),i=this.getAnonymousId();if(!r&&!i)return{value:`false`};let{fetchFeatureFlagEvaluation:a}=await import(`./chunks/feature-flags-DSOCIZHK.js`).then(e=>e.t);return a(e,{baseUrl:this.featureFlagsBaseUrl,projectToken:this.options.siteKey,...i?{identifier:i}:{},...r?{externalId:r}:{},sessionId:this.getSessionId(),attributes:t,signal:n?.signal})}reportError(e){if(this.destroyed||typeof window>`u`||w()||!(this.options.trackErrors??!1)||!this.ensureStarted())return;let t=this.errorTracker;if(t){t.captureError(e);return}this.pendingReportedErrors.length>=50&&this.pendingReportedErrors.shift(),this.pendingReportedErrors.push(e)}isCookielessMode(){return this.options.cookieless||this.consentMode===`denied`?!0:this.consentMode===`pending`?this.cookielessWhilePending:!1}send(e,t={}){if(typeof window>`u`||this.destroyed||w())return;let n=l(this.isCookielessMode()),r=JSON.stringify({token:this.options.siteKey,...n?{userId:n}:{},sessionId:a(),data:{event:e,page:location.pathname,referrer:document.referrer||null,title:document.title||``,url:location.href,...E(),...t}});this.log(e),u({url:this.webEndpoint,data:r,contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}enterPage(){this.pageEntryTime=Date.now(),this.pagePath=location.pathname,this.pageUrl=location.href,this.pageHash=location.hash,this.scrollDepth=0,this.hasLeftCurrentPage=!1}leavePage(){if(this.destroyed||this.hasLeftCurrentPage)return;this.hasLeftCurrentPage=!0;let e=Date.now();this.send(`page_leave`,{page:this.pagePath,url:this.pageUrl,time_on_page:e-this.pageEntryTime,scroll_depth:this.scrollDepth,session_duration:e-s()})}trackScroll(){this.scrollHandler&&window.removeEventListener(`scroll`,this.scrollHandler);let e=()=>{let e=document.documentElement,t=document.body,n=window.innerHeight,r=Math.max(e.scrollHeight,t.scrollHeight);if(r<=n){this.scrollDepth=100;return}let i=Math.min(100,Math.round(((window.scrollY||e.scrollTop)+n)/r*100));i>this.scrollDepth&&(this.scrollDepth=i)};this.scrollHandler=e,e(),window.addEventListener(`scroll`,e,{passive:!0})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.stopHeartbeat();return}i()},300*1e3)}navigate(){!this.started||this.destroyed||(this.stopNavigationTimer(),this.navTimer=setTimeout(()=>{this.navTimer=null;let e=location.pathname!==this.pagePath,t=(this.options.trackHash??!1)&&location.hash!==this.pageHash;if(!(!e&&!t)){this.leavePage(),this.enterPage();for(let e of this.childTrackers)e.trackPageChange?.(this.pageUrl);this.trackScroll(),this.pageview({trigger:`navigation`})}},300))}links(){let e=e=>{let t=T(e.target);t&&t.host!==location.host&&this.track(`outbound_link`,{outbound_link:t.href})};this.addDocumentListener(`click`,e),this.addDocumentListener(`auxclick`,e)}};export{D as WebAnalytics,f as fetchFeatureFlagEvaluation,g as getInstance,v as identify,w as isTrackingDisabled,y as logout,x as optIn,S as optOut,C as reportError,u as sendData,b as setConsentMode,_ as trackEvent};
|
|
1
|
+
import{n as e,r as t,t as n}from"./chunks/api-urls-DaeYkG0_.js";import{a as r,c as i,d as a,i as o,l as s,n as c,u as l}from"./chunks/session-manager-Cy63ptPF.js";import{n as u,r as d,t as f}from"./chunks/send-data-B2fYGj6v.js";import{t as p}from"./chunks/types-CYzR5xtT.js";import{n as m}from"./chunks/feature-flags-DSOCIZHK.js";function h(e){return e.replayOptions?.samplingPercentage!==void 0||e.sessionReplays?.sampling?.percentage!==void 0}function g(e,t,n){if(!(e.sessionReplays?.enabled??e.trackReplay??h(e)))return null;let r=e.replayOptions??{};return{siteKey:e.siteKey,baseUrl:t,debug:n,...r,samplingPercentage:p(r.samplingPercentage??e.sessionReplays?.sampling?.percentage)}}const _={instance:null,pendingConsentMode:void 0};function v(){return _.instance}function y(e,t){typeof window>`u`||E()||_.instance?.track(e,t??{})}function b(e,t,n){return typeof window>`u`||E()?Promise.resolve(!1):_.instance?.identify(e,t,n??{})??Promise.resolve(!1)}function x(e=!0){typeof window>`u`||E()||_.instance?.logout(e)}function S(e){if(_.instance){_.instance.setConsentMode(e);return}_.pendingConsentMode=e}function C(){S(`granted`)}function w(){S(`denied`)}function T(e){typeof window>`u`||E()||_.instance?.reportError(e)}function E(){if(typeof localStorage>`u`)return!1;let e=localStorage.getItem(`disable-faststats`);return e===`true`||e===`1`}function D(e){for(;e;){if(e instanceof HTMLAnchorElement&&e.href)return e;e=e.parentNode}return null}function O(){let e={};if(!location.search)return e;let t=new URLSearchParams(location.search);for(let n of[`utm_source`,`utm_medium`,`utm_campaign`,`utm_term`,`utm_content`]){let r=t.get(n);r&&(e[n]=r)}return e}var k=class{webEndpoint;baseUrl;featureFlagsBaseUrl;debug;started=!1;destroyed=!1;pageKey=``;navTimer=null;heartbeatTimer=null;scrollDepth=0;pageEntryTime=0;pagePath=``;pageUrl=``;pageHash=``;hasLeftCurrentPage=!1;scrollHandler=null;consentMode;cookielessWhilePending;cleanupCallbacks=[];childTrackers=[];pendingReportedErrors=[];errorTracker=null;handleVisibilityChange=()=>{document.visibilityState===`hidden`?(i(),this.leavePage(),this.stopHeartbeat()):(i(),this.enterPage(),this.startHeartbeat())};handlePageHide=()=>{this.leavePage()};handlePopState=()=>{this.navigate()};handleHashChange=()=>{this.navigate()};constructor(r){this.options=r,this.baseUrl=e(r.baseUrl),this.featureFlagsBaseUrl=t(r.featureFlagsBaseUrl),this.webEndpoint=`${this.baseUrl}${n.events}`,this.debug=r.debug??!1,this.consentMode=r.consent?.mode??`granted`,this.cookielessWhilePending=r.consent?.cookielessWhilePending??!0,_.pendingConsentMode!==void 0&&(this.consentMode=_.pendingConsentMode,_.pendingConsentMode=void 0),(r.autoTrack??!0)&&this.init()}log(e){this.debug&&console.log(`[Analytics] ${e}`)}init(){if(!(typeof window>`u`)){if(E()){this.log(`disabled`);return}_.instance=this,a(this.options.siteKey),l(this.isCookielessMode()),setTimeout(()=>void this.start(),0)}}registerCleanup(e){this.cleanupCallbacks.push(e)}addWindowListener(e,t){window.addEventListener(e,t),this.registerCleanup(()=>window.removeEventListener(e,t))}addDocumentListener(e,t){document.addEventListener(e,t),this.registerCleanup(()=>document.removeEventListener(e,t))}patchHistory(){let e=history.pushState.bind(history),t=history.replaceState.bind(history);history.pushState=(t,n,r)=>{e(t,n,r),this.navigate()},history.replaceState=(e,n,r)=>{t(e,n,r),this.navigate()},this.registerCleanup(()=>{history.pushState=e,history.replaceState=t})}ensureStarted(){return typeof window>`u`||this.destroyed||E()?!1:(this.started||this.start(),!0)}stopHeartbeat(){this.heartbeatTimer&&=(clearInterval(this.heartbeatTimer),null)}stopNavigationTimer(){this.navTimer&&=(clearTimeout(this.navTimer),null)}stopChildTrackers(){for(let e of this.childTrackers.splice(0))e.stop?.();this.errorTracker=null}registerChildTracker(e){return!this.started||this.destroyed||_.instance!==this?(e.stop?.(),!1):(this.childTrackers.push(e),!0)}async startChildTracker(e,t,n){try{let r=await t();return!this.started||this.destroyed||_.instance!==this?(r.stop?.(),null):(r.start(),this.registerChildTracker(r)?(n?.(r),this.log(`${e} loaded`),r):null)}catch(t){return this.log(`failed to initialize ${e} tracker: ${String(t)}`),null}}async startErrorTracker(){await this.startChildTracker(`error`,async()=>{let{default:e}=await import(`./chunks/error-Cd9PTS5v.js`).then(e=>e.n);return new e({siteKey:this.options.siteKey,baseUrl:this.baseUrl,debug:this.debug,sdkName:this.options.sdkName,sdkVersion:this.options.sdkVersion})},e=>{for(this.errorTracker=e;this.pendingReportedErrors.length>0;){let t=this.pendingReportedErrors.shift();t&&e.captureError(t)}})}async startWebVitalsTracker(){await this.startChildTracker(`web-vitals`,async()=>{let{default:e}=await import(`./chunks/web-vitals-Be-Cg4Po.js`).then(e=>e.n);return new e({siteKey:this.options.siteKey,baseUrl:this.baseUrl,debug:this.debug,samplingPercentage:p(this.options.webVitals?.sampling?.percentage),attribution:this.options.webVitals?.attribution??!1})})}async startReplayTracker(e){await this.startChildTracker(`replay`,async()=>{let{default:t}=await import(`./chunks/replay-rTqcjOo2.js`).then(e=>e.n);return new t(e)})}async start(){if(this.started||this.destroyed||typeof window>`u`)return;if(_.instance&&_.instance!==this){this.log(`already started by another instance`);return}if(E()){this.log(`disabled`);return}this.started=!0,_.instance=this,a(this.options.siteKey),l(this.isCookielessMode()),c();let e=this.options,t=g(e,this.baseUrl,this.debug);t&&this.startReplayTracker({...t,cookieless:this.isCookielessMode()}),e.trackErrors&&this.startErrorTracker(),e.trackWebVitals&&this.startWebVitalsTracker(),this.enterPage(),this.pageview({trigger:`load`}),this.links(),this.trackScroll(),this.startHeartbeat(),this.addDocumentListener(`visibilitychange`,this.handleVisibilityChange),this.addWindowListener(`pagehide`,this.handlePageHide),this.addWindowListener(`popstate`,this.handlePopState),e.trackHash&&this.addWindowListener(`hashchange`,this.handleHashChange),this.patchHistory()}destroy(){if(!this.destroyed){for(this.started&&typeof window<`u`&&this.leavePage(),this.pendingReportedErrors.length=0,this.stopNavigationTimer(),this.stopHeartbeat(),this.scrollHandler&&typeof window<`u`&&(window.removeEventListener(`scroll`,this.scrollHandler),this.scrollHandler=null);this.cleanupCallbacks.length>0;)this.cleanupCallbacks.pop()?.();this.stopChildTrackers(),_.instance===this&&(_.instance=null),this.started=!1,this.destroyed=!0}}pageview(e={}){if(!this.ensureStarted())return;let t=`${location.pathname}|${this.options.trackHash??!1?location.hash:``}`;t!==this.pageKey&&(this.pageKey=t,this.send(`pageview`,e))}track(e,t={}){this.ensureStarted()&&this.send(e,t)}identify(e,t,r={}){if(!this.ensureStarted()||this.isCookielessMode())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):f({url:`${this.baseUrl}${n.identify}`,data:JSON.stringify({token:this.options.siteKey,identifier:u(!1),externalId:i,email:a,name:r.name?.trim()||void 0,phone:r.phone?.trim()||void 0,avatarUrl:r.avatarUrl?.trim()||void 0,traits:r.traits??{}}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] identify`,useBeacon:!1})}logout(e=!0){this.ensureStarted()&&(e&&d(this.isCookielessMode()),s(this.options.siteKey))}setConsentMode(e){this.consentMode=e,l(this.isCookielessMode())}optIn(){this.setConsentMode(`granted`)}optOut(){this.setConsentMode(`denied`)}getConsentMode(){return this.consentMode}getAnonymousId(){return u(this.isCookielessMode())}getSessionId(){return c()}getWindowId(){return o(this.options.siteKey,this.isCookielessMode()).windowId}async checkFeatureFlag(e,t,n){if(typeof window>`u`||E())return{value:`false`};let r=n?.externalId?.trim(),i=this.getAnonymousId();if(!r&&!i)return{value:`false`};let{fetchFeatureFlagEvaluation:a}=await import(`./chunks/feature-flags-DSOCIZHK.js`).then(e=>e.t);return a(e,{baseUrl:this.featureFlagsBaseUrl,projectToken:this.options.siteKey,...i?{identifier:i}:{},...r?{externalId:r}:{},sessionId:this.getSessionId(),attributes:t,signal:n?.signal})}reportError(e){if(this.destroyed||typeof window>`u`||E()||!(this.options.trackErrors??!1)||!this.ensureStarted())return;let t=this.errorTracker;if(t){t.captureError(e);return}this.pendingReportedErrors.length>=50&&this.pendingReportedErrors.shift(),this.pendingReportedErrors.push(e)}isCookielessMode(){return this.options.cookieless||this.consentMode===`denied`?!0:this.consentMode===`pending`?this.cookielessWhilePending:!1}send(e,t={}){if(typeof window>`u`||this.destroyed||E())return;let n=u(this.isCookielessMode()),r=JSON.stringify({token:this.options.siteKey,...n?{userId:n}:{},sessionId:c(),data:{event:e,page:location.pathname,referrer:document.referrer||null,title:document.title||``,url:location.href,...O(),...t}});this.log(e),f({url:this.webEndpoint,data:r,contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}enterPage(){this.pageEntryTime=Date.now(),this.pagePath=location.pathname,this.pageUrl=location.href,this.pageHash=location.hash,this.scrollDepth=0,this.hasLeftCurrentPage=!1}leavePage(){if(this.destroyed||this.hasLeftCurrentPage)return;this.hasLeftCurrentPage=!0;let e=Date.now();this.send(`page_leave`,{page:this.pagePath,url:this.pageUrl,time_on_page:e-this.pageEntryTime,scroll_depth:this.scrollDepth,session_duration:e-r()})}trackScroll(){this.scrollHandler&&window.removeEventListener(`scroll`,this.scrollHandler);let e=()=>{let e=document.documentElement,t=document.body,n=window.innerHeight,r=Math.max(e.scrollHeight,t.scrollHeight);if(r<=n){this.scrollDepth=100;return}let i=Math.min(100,Math.round(((window.scrollY||e.scrollTop)+n)/r*100));i>this.scrollDepth&&(this.scrollDepth=i)};this.scrollHandler=e,e(),window.addEventListener(`scroll`,e,{passive:!0})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.stopHeartbeat();return}i()},300*1e3)}navigate(){!this.started||this.destroyed||(this.stopNavigationTimer(),this.navTimer=setTimeout(()=>{this.navTimer=null;let e=location.pathname!==this.pagePath,t=(this.options.trackHash??!1)&&location.hash!==this.pageHash;if(!(!e&&!t)){for(let e of this.childTrackers)e.trackPageChange?.(location.href);this.leavePage(),this.enterPage(),this.trackScroll(),this.pageview({trigger:`navigation`})}},300))}links(){let e=e=>{let t=D(e.target);t&&t.host!==location.host&&this.track(`outbound_link`,{outbound_link:t.href})};this.addDocumentListener(`click`,e),this.addDocumentListener(`auxclick`,e)}};export{k as WebAnalytics,m as fetchFeatureFlagEvaluation,v as getInstance,b as identify,E as isTrackingDisabled,x as logout,C as optIn,w as optOut,T as reportError,f as sendData,S as setConsentMode,y as trackEvent};
|
package/dist/replay.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-
|
|
1
|
+
import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-DvJYurEC.js";
|
|
2
2
|
export { type ReplayTrackerOptions, ReplayTracker as default };
|
package/dist/replay.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./chunks/replay-
|
|
1
|
+
import{t as e}from"./chunks/replay-rTqcjOo2.js";export{e as default};
|
package/dist/web-vitals.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./chunks/web-vitals-
|
|
1
|
+
import{t as e}from"./chunks/web-vitals-Be-Cg4Po.js";export{e as default};
|
package/package.json
CHANGED
|
@@ -39,28 +39,25 @@
|
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
-
"version": "0.2.
|
|
42
|
+
"version": "0.2.14",
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsdown && bun run check-size",
|
|
45
45
|
"dev": "bun run build",
|
|
46
46
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
47
47
|
"test": "bun test",
|
|
48
|
-
"check-size": "node scripts/check-bundle-size.mjs"
|
|
49
|
-
"deploy:worker": "wrangler deploy"
|
|
48
|
+
"check-size": "node scripts/check-bundle-size.mjs"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
52
51
|
"@biomejs/biome": "2.4.2",
|
|
53
52
|
"@types/bun": "latest",
|
|
54
53
|
"tsdown": "^0.21.4",
|
|
55
|
-
"typescript": "^5.9.3"
|
|
56
|
-
"wrangler": "^4.66.0"
|
|
54
|
+
"typescript": "^5.9.3"
|
|
57
55
|
},
|
|
58
56
|
"dependencies": {
|
|
59
57
|
"@rrweb/rrweb-plugin-console-record": "^2.0.0-alpha.20",
|
|
60
|
-
"@rrweb/rrweb-plugin-sequential-id-record": "^2.0.0-alpha.20",
|
|
61
58
|
"@rrweb/types": "^2.0.0-alpha.20",
|
|
62
59
|
"rrweb": "^2.0.0-alpha.4",
|
|
63
60
|
"rrweb-snapshot": "^2.0.0-alpha.4",
|
|
64
|
-
"web-vitals": "^5.
|
|
61
|
+
"web-vitals": "^5.2.0"
|
|
65
62
|
}
|
|
66
63
|
}
|
package/src/analytics.ts
CHANGED
|
@@ -6,16 +6,17 @@ import {
|
|
|
6
6
|
normalizeFeatureFlagsBaseUrl,
|
|
7
7
|
URLS,
|
|
8
8
|
} from "./utils/api-urls";
|
|
9
|
+
import { getAnonymousId, resetAnonymousId } from "./utils/identifiers";
|
|
10
|
+
import { sendData } from "./utils/send-data";
|
|
9
11
|
import {
|
|
10
|
-
getAnonymousId,
|
|
11
12
|
getOrCreateSessionId,
|
|
13
|
+
getSessionContext,
|
|
12
14
|
getSessionStart,
|
|
13
15
|
refreshSessionTimestamp,
|
|
14
|
-
|
|
15
|
-
resetSessionId,
|
|
16
|
+
resetSession,
|
|
16
17
|
setCookielessMode,
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
setDefaultSiteKey,
|
|
19
|
+
} from "./utils/session-manager";
|
|
19
20
|
import {
|
|
20
21
|
normalizeSamplingPercentage,
|
|
21
22
|
type SendDataOptions,
|
|
@@ -278,6 +279,7 @@ export class WebAnalytics {
|
|
|
278
279
|
return;
|
|
279
280
|
}
|
|
280
281
|
moduleState.instance = this;
|
|
282
|
+
setDefaultSiteKey(this.options.siteKey);
|
|
281
283
|
setCookielessMode(this.isCookielessMode());
|
|
282
284
|
setTimeout(() => void this.start(), 0);
|
|
283
285
|
}
|
|
@@ -451,6 +453,7 @@ export class WebAnalytics {
|
|
|
451
453
|
|
|
452
454
|
this.started = true;
|
|
453
455
|
moduleState.instance = this;
|
|
456
|
+
setDefaultSiteKey(this.options.siteKey);
|
|
454
457
|
setCookielessMode(this.isCookielessMode());
|
|
455
458
|
getOrCreateSessionId();
|
|
456
459
|
|
|
@@ -461,7 +464,10 @@ export class WebAnalytics {
|
|
|
461
464
|
this.debug,
|
|
462
465
|
);
|
|
463
466
|
if (replayOptions) {
|
|
464
|
-
void this.startReplayTracker(
|
|
467
|
+
void this.startReplayTracker({
|
|
468
|
+
...replayOptions,
|
|
469
|
+
cookieless: this.isCookielessMode(),
|
|
470
|
+
});
|
|
465
471
|
}
|
|
466
472
|
if (opts.trackErrors) {
|
|
467
473
|
void this.startErrorTracker();
|
|
@@ -566,7 +572,7 @@ export class WebAnalytics {
|
|
|
566
572
|
if (resetAnonymousIdentity) {
|
|
567
573
|
resetAnonymousId(this.isCookielessMode());
|
|
568
574
|
}
|
|
569
|
-
|
|
575
|
+
resetSession(this.options.siteKey);
|
|
570
576
|
}
|
|
571
577
|
|
|
572
578
|
setConsentMode(mode: ConsentMode): void {
|
|
@@ -594,6 +600,11 @@ export class WebAnalytics {
|
|
|
594
600
|
return getOrCreateSessionId();
|
|
595
601
|
}
|
|
596
602
|
|
|
603
|
+
getWindowId(): string {
|
|
604
|
+
return getSessionContext(this.options.siteKey, this.isCookielessMode())
|
|
605
|
+
.windowId;
|
|
606
|
+
}
|
|
607
|
+
|
|
597
608
|
async checkFeatureFlag(
|
|
598
609
|
key: string,
|
|
599
610
|
attributes?: Record<string, unknown>,
|
|
@@ -753,11 +764,11 @@ export class WebAnalytics {
|
|
|
753
764
|
const hashChanged =
|
|
754
765
|
(this.options.trackHash ?? false) && location.hash !== this.pageHash;
|
|
755
766
|
if (!pathChanged && !hashChanged) return;
|
|
756
|
-
this.leavePage();
|
|
757
|
-
this.enterPage();
|
|
758
767
|
for (const tracker of this.childTrackers) {
|
|
759
|
-
tracker.trackPageChange?.(
|
|
768
|
+
tracker.trackPageChange?.(location.href);
|
|
760
769
|
}
|
|
770
|
+
this.leavePage();
|
|
771
|
+
this.enterPage();
|
|
761
772
|
this.trackScroll();
|
|
762
773
|
this.pageview({ trigger: "navigation" });
|
|
763
774
|
}, 300);
|
package/src/error.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { SDK_NAME, SDK_VERSION } from "./sdk";
|
|
2
2
|
import { normalizeAnalyticsBaseUrl, URLS } from "./utils/api-urls";
|
|
3
|
-
import { getAnonymousId
|
|
3
|
+
import { getAnonymousId } from "./utils/identifiers";
|
|
4
4
|
import { sendData } from "./utils/send-data";
|
|
5
|
+
import {
|
|
6
|
+
getOrCreateSessionId,
|
|
7
|
+
getOrCreateWindowId,
|
|
8
|
+
} from "./utils/session-manager";
|
|
5
9
|
|
|
6
10
|
export type ErrorEntry = {
|
|
7
11
|
error: string;
|
|
@@ -213,6 +217,7 @@ export default class ErrorTracker {
|
|
|
213
217
|
token: this.options.siteKey,
|
|
214
218
|
...(userId ? { userId } : {}),
|
|
215
219
|
sessionId: getOrCreateSessionId(),
|
|
220
|
+
windowId: getOrCreateWindowId(this.options.siteKey),
|
|
216
221
|
...(buildId ? { buildId } : {}),
|
|
217
222
|
sdkName: this.options.sdkName ?? SDK_NAME,
|
|
218
223
|
sdkVersion: this.options.sdkVersion ?? SDK_VERSION,
|