@faststats/web 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ import{i as e,n as t}from"./send-data-CIbuTxPh.js";const n=`faststats_anon_id`;function r(){try{return globalThis.localStorage}catch{return}}function i(){let e=r();if(!e)return``;try{let r=e.getItem(n);if(r)return r;let i=t();return e.setItem(n,i),i}catch{return``}}function a(t){return t??e()?``:i()}function o(e){if(e)return``;try{let e=r();if(!e)return``;e.removeItem(n)}catch{return``}return i()}export{o as n,a as t};
@@ -1,4 +1,5 @@
1
1
  import { record } from "@rrweb/record";
2
+ import { LogLevel } from "@rrweb/rrweb-plugin-console-record";
2
3
 
3
4
  //#region src/replay.d.ts
4
5
  type RecordOptions = NonNullable<Parameters<typeof record>[0]>;
@@ -7,9 +8,10 @@ interface ReplayTrackerOptions {
7
8
  baseUrl?: string;
8
9
  debug?: boolean;
9
10
  compress?: boolean;
10
- samplingPercentage?: number;
11
11
  flushInterval?: number;
12
12
  maxEvents?: number;
13
+ maxBatchSizeBytes?: number;
14
+ maxLowLatencyBatchSizeBytes?: number;
13
15
  maxPendingBatches?: number;
14
16
  maxQueueSizeBytes?: number;
15
17
  minReplayLengthMs?: number;
@@ -24,6 +26,9 @@ interface ReplayTrackerOptions {
24
26
  checkoutEveryNms?: number;
25
27
  checkoutEveryNth?: number;
26
28
  recordConsole?: boolean;
29
+ consoleLevel?: LogLevel[];
30
+ consoleLengthThreshold?: number;
31
+ consoleStringLengthLimit?: number;
27
32
  }
28
33
  declare class ReplayTracker {
29
34
  private readonly options;
@@ -31,12 +36,14 @@ declare class ReplayTracker {
31
36
  private readonly compressionSupported;
32
37
  private readonly flushInterval;
33
38
  private readonly maxEvents;
39
+ private readonly maxBatchSizeBytes;
40
+ private readonly maxLowLatencyBatchSizeBytes;
34
41
  private readonly maxPendingBatches;
35
42
  private readonly maxQueueSizeBytes;
36
43
  private readonly minReplayLengthMs;
37
- private readonly sampled;
38
44
  private readonly events;
39
45
  private readonly pending;
46
+ private queuedEventsSizeBytes;
40
47
  private pendingSizeBytes;
41
48
  private viewId;
42
49
  private chunkStartedAt;
@@ -58,6 +65,11 @@ declare class ReplayTracker {
58
65
  private log;
59
66
  private clearFlushTimers;
60
67
  private clearQueues;
68
+ private storage;
69
+ private counterKey;
70
+ private readCounter;
71
+ private writeCounter;
72
+ private nextBatchSequence;
61
73
  setCookielessMode(cookieless: boolean): void;
62
74
  start(): void;
63
75
  trackPageChange(url?: string): void;
@@ -72,7 +84,9 @@ declare class ReplayTracker {
72
84
  private requestFlush;
73
85
  private scheduleMinLengthFlush;
74
86
  private enqueueEventsIfReady;
87
+ private takeEventBatches;
75
88
  private createBatch;
89
+ private eventSizeBytes;
76
90
  private batchSizeBytes;
77
91
  private dropOldestPending;
78
92
  private enqueueBatch;
@@ -0,0 +1 @@
1
+ const e=`faststats_session`;let t=!1,n=null;const r=new Set;function i(e){try{return globalThis[e]}catch{return null}}function a(){return typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}function o(){let t=i(`localStorage`);if(!t)return n;let r=t.getItem(e);if(r)try{let e=JSON.parse(r);if(e.id)return e}catch{}return n}function s(t){let r=i(`localStorage`);if(!r){n=t;return}try{r.setItem(e,JSON.stringify(t))}catch{n=t}}function c(){n=null;try{i(`localStorage`)?.removeItem(e)}catch{}}function l(e,t){return t-e.activity>=18e5||t-e.start>=864e5}function u(e,t){for(let n of r)n(e,t)}function d(e,t){let r=Date.now();if(e)return n?t&&(n.activity=r):n={id:a(),start:r,activity:r},{session:n,rotated:!1,previous:null};let i=o();if(i&&!l(i,r))return t&&(i.activity=r,s(i)),{session:i,rotated:!1,previous:null};let c=i,u={id:a(),start:r,activity:r};return s(u),{session:u,rotated:c!==null,previous:c}}function f(e,t,n){if(t)return n;let r=`faststats_window_id_${e}`,o=i(`sessionStorage`);if(!o)return n;try{let e=o.getItem(r);if(e)return e;let t=a();return o.setItem(r,t),t}catch{return n}}function p(e,t,n,r){let i=r??f(e,n,t.id);return{sessionId:t.id,windowId:i,sessionStart:t.start}}function m(e){t=e,n=null}function h(){return t}function g(e,n){let r=n??t,{session:i}=d(r,!1);return p(e,i,r)}function _(e,n){let r=n??t,{session:i,rotated:a,previous:o}=d(r,!0);if(!a||!o)return null;let s=f(e,r,i.id),c={prev:p(e,o,r,s),next:p(e,i,r,s)};return u(c.prev,c.next),c}function v(e){let r=t,o=g(e,r);if(c(),r){let e=Date.now();n={id:a(),start:e,activity:e}}else try{i(`sessionStorage`)?.removeItem(`faststats_window_id_${e}`)}catch{}let s=g(e,r);return o.sessionId!==s.sessionId&&u(o,s),s}function y(e){return r.add(e),()=>r.delete(e)}async function b(e){let{url:t,data:n,contentType:r=`application/json`,headers:i={},debug:a=!1,debugPrefix:o=`[Analytics]`,useBeacon:s=!0,keepalive:c=!0,signal:l}=e;if(l?.aborted)return!1;if(s&&typeof globalThis.navigator?.sendBeacon==`function`)try{let e=n instanceof Blob||typeof Blob>`u`?n:new Blob([n],{type:r});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,credentials:`omit`,signal:l}),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{y as a,_ as c,h as i,a as n,v as o,g as r,m as s,b as t};
package/dist/error.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a as e,i as t,r as n,t as r}from"./chunks/api-urls-Bh77rElT.js";import{i,n as a}from"./chunks/send-data-Cc1nxIlg.js";import{t as o}from"./chunks/identifiers-uytEhnH9.js";const s=/(?:^|\()(chrome|moz|ms-browser|safari-web)-extension:\/\//;function c(e,t,n,r){return t instanceof Error?{error:e,message:t.message||r,handled:n,stack:t.stack?.split(`
2
- `).map(e=>e.trim()).filter(Boolean)}:{error:e,message:typeof t==`string`?t:r,handled:n}}function l({error:e,message:t,handled:n}){return`${e}\0${t??``}\0${n}`}function u(e,t){let n=t instanceof Error?t.stack??``:``;return s.test(`${e}\n${n}`)}var d=class{options;endpoint;queue=new Map;timer=null;started=!1;flushing=!1;constructor(t){this.options=t,this.endpoint=`${e(t.baseUrl,r)}${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),this.timer=setInterval(()=>void this.flush(),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),this.timer&&clearInterval(this.timer),this.timer=null,this.flush(),this.log(`Stopped`))}onPageHidden(e=!1){e||this.flush()}captureError(e){this.enqueue(c(`Error`,e,!0,e.message))}onError=e=>{u(e.filename??``,e.error)||this.enqueue(c(`Error`,e.error,!1,e.message||`Unknown error`))};onRejection=e=>{u(``,e.reason)||this.enqueue(c(`UnhandledRejection`,e.reason,!1,`Unhandled promise rejection`))};enqueue(e){let t=l(e),n=this.queue.get(t);if(n){n.count++;return}this.queue.set(t,{...e,count:1}),this.log(`Captured:`,e),this.queue.size>=(this.options.maxQueueSize??50)&&this.flush()}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=!0;let e=this.queue;this.queue=new Map;let n=[...e.values()];this.log(`Flushing:`,n);try{let r=globalThis.__SOURCEMAPS_BUILD__?.buildId,s=o(),c=i(this.options.siteKey);if(!await a({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,...s?{userId:s}:{},sessionId:c.sessionId,windowId:c.windowId,...typeof r==`string`&&r.trim()?{buildId:r}:{},sdkName:this.options.sdkName??`@faststats/web`,sdkVersion:this.options.sdkVersion??`0.4.1`,event:`error`,...t(),properties:{},errors:n}),debug:this.options.debug,debugPrefix:`[ErrorTracker]`}))for(let[t,n]of e){let e=this.queue.get(t);e?e.count+=n.count:this.queue.set(t,n)}}finally{this.flushing=!1}}};export{d as default};
1
+ import{a as e,i as t,r as n,t as r}from"./chunks/api-urls-Bh77rElT.js";import{r as i,t as a}from"./chunks/send-data-CIbuTxPh.js";import{t as o}from"./chunks/identifiers-DcGHdsnG.js";const s=/(?:^|\()(chrome|moz|ms-browser|safari-web)-extension:\/\//;function c(e,t,n,r){return t instanceof Error?{error:e,message:t.message||r,handled:n,stack:t.stack?.split(`
2
+ `).map(e=>e.trim()).filter(Boolean)}:{error:e,message:typeof t==`string`?t:r,handled:n}}function l({error:e,message:t,handled:n}){return`${e}\0${t??``}\0${n}`}function u(e,t){let n=t instanceof Error?t.stack??``:``;return s.test(`${e}\n${n}`)}var d=class{options;endpoint;queue=new Map;timer=null;started=!1;flushing=!1;constructor(t){this.options=t,this.endpoint=`${e(t.baseUrl,r)}${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),this.timer=setInterval(()=>void this.flush(),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),this.timer&&clearInterval(this.timer),this.timer=null,this.flush(),this.log(`Stopped`))}onPageHidden(e=!1){e||this.flush()}captureError(e){this.enqueue(c(`Error`,e,!0,e.message))}onError=e=>{u(e.filename??``,e.error)||this.enqueue(c(`Error`,e.error,!1,e.message||`Unknown error`))};onRejection=e=>{u(``,e.reason)||this.enqueue(c(`UnhandledRejection`,e.reason,!1,`Unhandled promise rejection`))};enqueue(e){let t=l(e),n=this.queue.get(t);if(n){n.count++;return}this.queue.set(t,{...e,count:1}),this.log(`Captured:`,e),this.queue.size>=(this.options.maxQueueSize??50)&&this.flush()}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=!0;let e=this.queue;this.queue=new Map;let n=[...e.values()];this.log(`Flushing:`,n);try{let r=globalThis.__SOURCEMAPS_BUILD__?.buildId,s=o(),c=i(this.options.siteKey);if(!await a({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,...s?{userId:s}:{},sessionId:c.sessionId,windowId:c.windowId,...typeof r==`string`&&r.trim()?{buildId:r}:{},sdkName:this.options.sdkName??`@faststats/web`,sdkVersion:this.options.sdkVersion??`0.5.0`,event:`error`,...t(),properties:{},errors:n}),debug:this.options.debug,debugPrefix:`[ErrorTracker]`}))for(let[t,n]of e){let e=this.queue.get(t);e?e.count+=n.count:this.queue.set(t,n)}}finally{this.flushing=!1}}};export{d as default};
@@ -1 +1 @@
1
- import{a as e,n as t,r as n}from"./chunks/api-urls-Bh77rElT.js";async function r(r,i){if(!i.projectToken)throw Error(`feature flag check requires projectToken`);if(!i.identifier&&!i.externalId)throw Error(`feature flag check requires serverId or externalId`);let{baseUrl:a,projectToken:o,signal:s,attributes:c,...l}=i,u={key:r,...l};c&&Object.keys(c).length>0&&(u.attributes=c);let d={"Content-Type":`application/json`,Authorization:`Bearer ${o}`},f=`${e(a,t)}${n.flags}`,p=await fetch(f,{method:`POST`,headers:d,body:JSON.stringify(u),credentials:`omit`,signal:s});if(!p.ok){let e=``;try{let t=await p.json();typeof t.error==`string`&&t.error.length>0&&(e=` — ${t.error}`)}catch{}throw Error(`feature flag check failed: HTTP ${p.status}${e}`)}return await p.json()}export{r as fetchFeatureFlagEvaluation};
1
+ import{a as e,n as t,r as n}from"./chunks/api-urls-Bh77rElT.js";async function r(r,i){if(!i.projectToken)throw Error(`feature flag check requires projectToken`);if(!i.identifier&&!i.externalId)throw Error(`feature flag check requires serverId or externalId`);let{baseUrl:a,projectToken:o,signal:s,attributes:c,...l}=i,u={key:r,...l};c&&Object.keys(c).length>0&&(u.attributes=c);let d={"Content-Type":`application/json`,Authorization:`Bearer ${o}`},f=`${e(a,t)}${n.flags}`,p=await fetch(f,{method:`POST`,headers:d,body:JSON.stringify(u),credentials:`omit`,signal:s});if(!p.ok){let e=await p.json().catch(()=>null),t=typeof e?.error==`string`&&e.error.length>0?` — ${e.error}`:``;throw Error(`feature flag check failed: HTTP ${p.status}${t}`)}return await p.json()}export{r as fetchFeatureFlagEvaluation};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { FeatureFlagEvaluation } from "./feature-flags.js";
2
- import { n as ReplayTrackerOptions } from "./chunks/replay-BssVAUs6.js";
2
+ import { n as ReplayTrackerOptions } from "./chunks/replay-CLfrGjqj.js";
3
3
 
4
4
  //#region src/analytics.d.ts
5
5
  type ConsentMode = "pending" | "granted" | "denied";
@@ -24,16 +24,10 @@ interface WebAnalyticsOptions {
24
24
  };
25
25
  webVitals?: {
26
26
  enabled?: boolean;
27
- sampling?: {
28
- percentage?: number;
29
- };
30
27
  attribution?: boolean;
31
28
  };
32
29
  sessionReplays?: {
33
30
  enabled?: boolean;
34
- sampling?: {
35
- percentage?: number;
36
- };
37
31
  };
38
32
  errorTracking?: {
39
33
  enabled?: boolean;
@@ -60,19 +54,23 @@ declare class WebAnalytics {
60
54
  private started;
61
55
  private destroyed;
62
56
  private epoch;
63
- private navTimer;
64
57
  private heartbeatTimer;
65
58
  private pageKey;
66
59
  private entry;
67
60
  private left;
61
+ private initialPageviewPending;
62
+ private initialPageviewTrigger;
68
63
  private consentMode;
69
64
  private readonly pendingBehavior;
70
65
  private readonly cleanup;
71
66
  private readonly childTrackers;
67
+ private readonly outboundLinks;
72
68
  constructor(options: WebAnalyticsOptions);
73
69
  private log;
70
+ private isTrackingBlocked;
74
71
  private ensureActive;
75
72
  private canTrack;
73
+ private canSendEvents;
76
74
  private cookieless;
77
75
  private touch;
78
76
  private bind;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as e,i as t,n,r,t as i}from"./chunks/api-urls-Bh77rElT.js";import{c as a,i as o,l as s,n as c,t as l,u}from"./chunks/send-data-Cc1nxIlg.js";import{n as d,t as f}from"./chunks/identifiers-uytEhnH9.js";let p=null,m;function h(){return p}function g(e,t){typeof window>`u`||C()||p?.track(e,t??{})}function _(e,t,n){return typeof window>`u`||C()?Promise.resolve(!1):p?.identify(e,t,n??{})??Promise.resolve(!1)}function v(e=!0){typeof window>`u`||C()||p?.logout(e)}function y(e){p?p.setConsentMode(e):m=e}function b(){y(`granted`)}function x(){y(`denied`)}function S(e){typeof window>`u`||C()||p?.reportError(e)}function C(){try{let e=globalThis.localStorage?.getItem(`disable-faststats`);return e===`true`||e===`1`}catch{return!1}}var w=class{options;baseUrl;debug;started=!1;destroyed=!1;epoch=0;navTimer=null;heartbeatTimer=null;pageKey=``;entry={path:``,url:``,hash:``};left=!1;consentMode;pendingBehavior;cleanup=[];childTrackers=[];constructor(t){if(this.options=t,this.baseUrl=e(t.baseUrl,i),this.debug=t.debug??!1,this.consentMode=m??t.consent?.mode??`granted`,m=void 0,this.pendingBehavior=t.consent?.pendingBehavior??`anonymous`,t.autoTrack??!0){if(typeof window>`u`)return;if(C()){this.log(`disabled`);return}setTimeout(()=>void this.start(),0)}}log(e){this.debug&&console.log(`[Analytics] ${e}`)}ensureActive(){return typeof window>`u`||this.destroyed||C()?!1:(this.started||this.start(),this.started&&!this.destroyed&&p===this)}canTrack(){return!(this.consentMode===`pending`&&this.pendingBehavior===`disabled`)}cookieless(){return!!this.options.cookieless||this.consentMode===`denied`||this.consentMode===`pending`&&this.pendingBehavior===`anonymous`}touch(){this.canTrack()&&u(this.options.siteKey,this.cookieless())}bind(e,t,n,r){e.addEventListener(t,n,r),this.cleanup.push(()=>e.removeEventListener(t,n,r))}loadChild(e,t){let n=this.epoch;t().then(async t=>{if(this.epoch!==n||!this.started||(await t.start(),this.epoch!==n||!this.started))return t.stop?.();this.childTrackers.push(t),this.log(`${e} loaded`)}).catch(t=>this.log(`failed to initialize ${e} tracker: ${String(t)}`))}loadOptionalTrackers(){let e=this.options,t={siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug};if(e.sessionReplays?.enabled){let n=e.replayOptions??{};this.loadChild(`replay`,async()=>{let{default:r}=await import(`./replay.js`);return new r({...t,...n,samplingPercentage:l(n.samplingPercentage??e.sessionReplays?.sampling?.percentage)})})}e.errorTracking?.enabled&&this.loadChild(`error`,async()=>{let{default:n}=await import(`./error.js`);return new n({...t,sdkName:e.sdkName,sdkVersion:e.sdkVersion})}),e.webVitals?.enabled&&this.loadChild(`web-vitals`,async()=>{let{default:n}=await import(`./web-vitals.js`);return new n({...t,samplingPercentage:l(e.webVitals?.sampling?.percentage),attribution:e.webVitals?.attribution??!1})})}beginTracking(e){this.touch(),this.loadOptionalTrackers(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageKey=``,this.pageview({trigger:e})}onLinkClick=e=>{let t=e.target;for(;t;){if(t instanceof HTMLAnchorElement&&t.href&&t.host!==location.host){this.track(`outbound_link`,{outbound_link:t.href});return}t=t.parentNode}};onVisibilityChange=()=>{if(this.touch(),document.visibilityState===`hidden`){for(let e of this.childTrackers)e.onPageHidden?.();this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.startHeartbeat()};onPageHide=e=>{let t=e.persisted;for(let e of this.childTrackers)e.onPageHidden?.(t);t||this.leavePage()};onPageShow=e=>{for(let t of this.childTrackers)t.onPageShow?.(e.persisted)};async start(){if(this.started||this.destroyed||typeof window>`u`)return;if(p&&p!==this){this.log(`already started by another instance`);return}if(C()){this.log(`disabled`);return}this.started=!0,p=this,s(this.cookieless()),this.canTrack()&&this.beginTracking(`load`),this.startHeartbeat();let e=()=>this.navigate(),t=[[document,`click`,this.onLinkClick],[document,`auxclick`,this.onLinkClick],[document,`visibilitychange`,this.onVisibilityChange],[window,`pagehide`,this.onPageHide],[window,`pageshow`,this.onPageShow],[window,`popstate`,e]];(this.options.trackHash??!1)&&t.push([window,`hashchange`,e]);for(let[e,n,r]of t)this.bind(e,n,r);for(let e of[`pushState`,`replaceState`]){let t=history[e].bind(history);history[e]=(e,n,r)=>{t(e,n,r),this.navigate()},this.cleanup.push(()=>{history[e]=t})}}destroy(){if(!this.destroyed){this.epoch++,this.started&&typeof window<`u`&&this.leavePage(),this.navTimer&&clearTimeout(this.navTimer),this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;for(let e of this.cleanup.splice(0))e();for(let e of this.childTrackers.splice(0))e.stop?.();p===this&&(p=null),this.started=!1,this.destroyed=!0}}pageview(e={}){if(!this.ensureActive())return;let t=this.options.trackHash??!1,n=`${location.pathname}|${t?location.hash:``}`;n!==this.pageKey&&(this.pageKey=n,this.send(`pageview`,e))}track(e,t={}){if(!this.ensureActive())return;let n=e.trim();n&&this.send(n,t)}identify(e,t,n={}){if(!this.ensureActive()||!this.canTrack()||this.cookieless())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):c({url:`${this.baseUrl}${r.identify}`,data:JSON.stringify({token:this.options.siteKey,identifier:this.getAnonymousId(),externalId:i,email:a,name:n.name?.trim()||void 0,phone:n.phone?.trim()||void 0,avatarUrl:n.avatarUrl?.trim()||void 0,traits:n.traits??{}}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] identify`,useBeacon:!1})}logout(e=!0){this.ensureActive()&&(e&&d(this.cookieless()),a(this.options.siteKey))}setConsentMode(e){let t=!this.canTrack();this.consentMode=e;let n=this.cookieless();s(n);for(let e of this.childTrackers)e.setCookielessMode?.(n);t&&this.canTrack()&&this.started&&this.beginTracking(`consent`)}getConsentMode(){return this.consentMode}getAnonymousId(){return this.canTrack()?f(this.cookieless()):``}getSessionId(){return o(this.options.siteKey,this.cookieless()).sessionId}getWindowId(){return o(this.options.siteKey,this.cookieless()).windowId}async checkFeatureFlag(t,r,i){if(typeof window>`u`||C()||!this.canTrack())return{value:`false`};let a=i?.externalId?.trim(),o=this.getAnonymousId();if(!a&&!o)return{value:`false`};let{fetchFeatureFlagEvaluation:s}=await import(`./feature-flags.js`);return s(t,{baseUrl:e(this.options.featureFlagsBaseUrl,n),projectToken:this.options.siteKey,...o?{identifier:o}:{},...a?{externalId:a}:{},sessionId:this.getSessionId(),attributes:r,signal:i?.signal})}reportError(e){!this.ensureActive()||!this.options.errorTracking?.enabled||!this.canTrack()||this.childTrackers.find(e=>`captureError`in e)?.captureError(e)}send(e,n={},i={}){if(typeof window>`u`||this.destroyed||C()||!this.canTrack())return;let a=this.cookieless(),s=f(a),l=o(this.options.siteKey,a);this.log(e),c({url:`${this.baseUrl}${r.events}`,data:JSON.stringify({token:this.options.siteKey,...s?{userId:s}:{},sessionId:l.sessionId,windowId:l.windowId,event:e,...t(),...i,properties:n}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}leavePage(){if(this.destroyed||this.left)return;this.left=!0;let e=o(this.options.siteKey,this.cookieless());this.send(`page_leave`,{session_duration:Date.now()-e.sessionStart},{page:this.entry.path,url:this.entry.url})}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.touch()},300*1e3)}navigate(){!this.started||this.destroyed||(this.navTimer&&clearTimeout(this.navTimer),this.navTimer=setTimeout(()=>{this.navTimer=null;let e=this.options.trackHash??!1;if(!(location.pathname===this.entry.path&&(!e||location.hash===this.entry.hash))){for(let e of this.childTrackers)e.trackPageChange?.(location.href);this.leavePage(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageview({trigger:`navigation`})}},300))}};export{w as WebAnalytics,h as getInstance,_ as identify,C as isTrackingDisabled,v as logout,b as optIn,x as optOut,S as reportError,y as setConsentMode,g as trackEvent};
1
+ import{a as e,i as t,n,r,t as i}from"./chunks/api-urls-Bh77rElT.js";import{c as a,o,r as s,s as c,t as l}from"./chunks/send-data-CIbuTxPh.js";import{n as u,t as d}from"./chunks/identifiers-DcGHdsnG.js";var f=class{lastActivation=null;getHref(e){if(!(e instanceof MouseEvent)||!p(e))return null;let t=m(e);return!t||this.isDuplicate(e,t.href)?null:t.href}isDuplicate(e,t){let n={button:e.button,href:t,clientX:e.clientX,clientY:e.clientY,at:Date.now()},r=this.lastActivation;return this.lastActivation=n,!!(r&&r.href===n.href&&r.button===n.button&&r.clientX===n.clientX&&r.clientY===n.clientY&&n.at-r.at<=500)}};function p(e){return e.defaultPrevented?!1:e.type===`click`?e.button===0:e.type===`auxclick`?e.button===1:!1}function m(e){for(let t of e.composedPath())if(h(t))return t;let t=e.target;for(;t;){if(h(t))return t;t=t.parentNode}return null}function h(e){return e instanceof HTMLAnchorElement&&!!e.href&&e.host!==location.host}let g=null,_;function v(){return g}function y(e,t){typeof window>`u`||E()||g?.track(e,t??{})}function b(e,t,n){return typeof window>`u`||E()?Promise.resolve(!1):g?.identify(e,t,n??{})??Promise.resolve(!1)}function x(e=!0){typeof window>`u`||E()||g?.logout(e)}function S(e){g?g.setConsentMode(e):_=e}function C(){S(`granted`)}function w(){S(`denied`)}function T(e){typeof window>`u`||E()||g?.reportError(e)}function E(){try{let e=globalThis.localStorage?.getItem(`disable-faststats`);return e===`true`||e===`1`}catch{return!1}}var D=class{options;baseUrl;debug;started=!1;destroyed=!1;epoch=0;heartbeatTimer=null;pageKey=``;entry={path:``,url:``,hash:``};left=!1;initialPageviewPending=!1;initialPageviewTrigger=`load`;consentMode;pendingBehavior;cleanup=[];childTrackers=[];outboundLinks=new f;constructor(t){if(this.options=t,this.baseUrl=e(t.baseUrl,i),this.debug=t.debug??!1,this.consentMode=_??t.consent?.mode??`granted`,_=void 0,this.pendingBehavior=t.consent?.pendingBehavior??`anonymous`,t.autoTrack??!0){if(typeof window>`u`)return;if(E()){this.log(`disabled`);return}setTimeout(()=>void this.start(),0)}}log(e){this.debug&&console.log(`[Analytics] ${e}`)}isTrackingBlocked(){return typeof window>`u`||this.destroyed||E()}ensureActive(){return this.isTrackingBlocked()?!1:(this.started||this.start(),this.started&&!this.destroyed&&g===this)}canTrack(){return!(this.consentMode===`pending`&&this.pendingBehavior===`disabled`)}canSendEvents(){return!this.isTrackingBlocked()&&this.canTrack()}cookieless(){return!!this.options.cookieless||this.consentMode===`denied`||this.consentMode===`pending`&&this.pendingBehavior===`anonymous`}touch(){this.canTrack()&&a(this.options.siteKey,this.cookieless())}bind(e,t,n,r){e.addEventListener(t,n,r),this.cleanup.push(()=>e.removeEventListener(t,n,r))}loadChild(e,t){let n=this.epoch;t().then(async t=>{if(this.epoch!==n||!this.started||(await t.start(),this.epoch!==n||!this.started))return t.stop?.();this.childTrackers.push(t),this.log(`${e} loaded`)}).catch(t=>this.log(`failed to initialize ${e} tracker: ${String(t)}`))}loadOptionalTrackers(){let e=this.options,t={siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug};if(e.sessionReplays?.enabled){let n=e.replayOptions??{};this.loadChild(`replay`,async()=>{let{default:e}=await import(`./replay.js`);return new e({...t,...n})})}e.errorTracking?.enabled&&this.loadChild(`error`,async()=>{let{default:n}=await import(`./error.js`);return new n({...t,sdkName:e.sdkName,sdkVersion:e.sdkVersion})}),e.webVitals?.enabled&&this.loadChild(`web-vitals`,async()=>{let{default:n}=await import(`./web-vitals.js`);return new n({...t,attribution:e.webVitals?.attribution??!1})})}beginTracking(e){if(this.touch(),this.loadOptionalTrackers(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageKey=``,document.visibilityState===`visible`){this.pageview({trigger:e});return}this.initialPageviewTrigger=e,this.initialPageviewPending=!0}onLinkClick=e=>{let t=this.outboundLinks.getHref(e);t&&this.track(`outbound_link`,{outbound_link:t})};onVisibilityChange=()=>{if(this.touch(),document.visibilityState===`hidden`){for(let e of this.childTrackers)e.onPageHidden?.();this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.startHeartbeat(),this.initialPageviewPending&&(this.initialPageviewPending=!1,this.pageview({trigger:this.initialPageviewTrigger}))};onPageHide=e=>{let t=e.persisted;for(let e of this.childTrackers)e.onPageHidden?.(t);t||this.leavePage()};onPageShow=e=>{for(let t of this.childTrackers)t.onPageShow?.(e.persisted)};async start(){if(this.started)return;if(this.isTrackingBlocked()){E()&&this.log(`disabled`);return}if(g&&g!==this){this.log(`already started by another instance`);return}this.started=!0,g=this,c(this.cookieless());let e=()=>this.navigate(),t=[[document,`click`,this.onLinkClick,!0],[document,`auxclick`,this.onLinkClick,!0],[document,`visibilitychange`,this.onVisibilityChange,void 0],[window,`pagehide`,this.onPageHide,void 0],[window,`pageshow`,this.onPageShow,void 0],[window,`popstate`,e,void 0]];(this.options.trackHash??!1)&&t.push([window,`hashchange`,e,void 0]);for(let[e,n,r,i]of t)this.bind(e,n,r,i);for(let e of[`pushState`,`replaceState`]){let t=history[e].bind(history);history[e]=(e,n,r)=>{t(e,n,r),this.navigate()},this.cleanup.push(()=>{history[e]=t})}this.startHeartbeat(),this.canTrack()&&this.beginTracking(`load`)}destroy(){if(!this.destroyed){this.epoch++,this.started&&typeof window<`u`&&this.leavePage(),this.initialPageviewPending=!1,this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;for(let e of this.cleanup.splice(0))e();for(let e of this.childTrackers.splice(0))e.stop?.();g===this&&(g=null),this.started=!1,this.destroyed=!0}}pageview(e={}){if(!this.ensureActive())return;let t=this.options.trackHash??!1,n=`${location.pathname}|${t?location.hash:``}`;n!==this.pageKey&&(this.pageKey=n,this.send(`pageview`,e))}track(e,t={}){if(!this.ensureActive())return;let n=e.trim();n&&this.send(n,t)}identify(e,t,n={}){if(!this.ensureActive()||!this.canTrack()||this.cookieless())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):l({url:`${this.baseUrl}${r.identify}`,data:JSON.stringify({token:this.options.siteKey,identifier:this.getAnonymousId(),externalId:i,email:a,name:n.name?.trim()||void 0,phone:n.phone?.trim()||void 0,avatarUrl:n.avatarUrl?.trim()||void 0,traits:n.traits??{}}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] identify`,useBeacon:!1})}logout(e=!0){this.ensureActive()&&(e&&u(this.cookieless()),o(this.options.siteKey))}setConsentMode(e){let t=!this.canTrack();this.consentMode=e;let n=this.cookieless();c(n);for(let e of this.childTrackers)e.setCookielessMode?.(n);t&&this.canTrack()&&this.started&&this.beginTracking(`consent`)}getConsentMode(){return this.consentMode}getAnonymousId(){return this.canTrack()?d(this.cookieless()):``}getSessionId(){return s(this.options.siteKey,this.cookieless()).sessionId}getWindowId(){return s(this.options.siteKey,this.cookieless()).windowId}async checkFeatureFlag(t,r,i){if(typeof window>`u`||E()||!this.canTrack())return{value:`false`};let a=i?.externalId?.trim(),o=this.getAnonymousId();if(!a&&!o)return{value:`false`};let{fetchFeatureFlagEvaluation:s}=await import(`./feature-flags.js`);return s(t,{baseUrl:e(this.options.featureFlagsBaseUrl,n),projectToken:this.options.siteKey,...o?{identifier:o}:{},...a?{externalId:a}:{},sessionId:this.getSessionId(),attributes:r,signal:i?.signal})}reportError(e){!this.ensureActive()||!this.options.errorTracking?.enabled||!this.canTrack()||this.childTrackers.find(e=>e.captureError)?.captureError?.(e)}send(e,n={},i={}){if(!this.canSendEvents())return;let a=this.cookieless(),o=d(a),c=s(this.options.siteKey,a);this.log(e),l({url:`${this.baseUrl}${r.events}`,data:JSON.stringify({token:this.options.siteKey,...o?{userId:o}:{},sessionId:c.sessionId,windowId:c.windowId,event:e,...t(),...i,properties:n}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}leavePage(){if(this.destroyed||this.left)return;this.left=!0;let e=s(this.options.siteKey,this.cookieless());this.send(`page_leave`,{session_duration:Date.now()-e.sessionStart},{page:this.entry.path,url:this.entry.url})}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=null;return}this.touch()},300*1e3)}navigate(){if(!this.started||this.destroyed)return;let e=this.options.trackHash??!1;if(!(location.pathname===this.entry.path&&(!e||location.hash===this.entry.hash))){for(let e of this.childTrackers)e.trackPageChange?.(location.href);this.leavePage(),this.entry={path:location.pathname,url:location.href,hash:location.hash},this.left=!1,this.pageview({trigger:`navigation`})}}};export{D as WebAnalytics,v as getInstance,b as identify,E as isTrackingDisabled,x as logout,C as optIn,w as optOut,T as reportError,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-BssVAUs6.js";
1
+ import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-CLfrGjqj.js";
2
2
  export { ReplayTrackerOptions, ReplayTracker as default };
package/dist/replay.js CHANGED
@@ -1 +1 @@
1
- import{a as e,r as t,t as n}from"./chunks/api-urls-Bh77rElT.js";import{a as r,i,n as a,o,r as s,s as c,t as l,u}from"./chunks/send-data-Cc1nxIlg.js";import{t as d}from"./chunks/identifiers-uytEhnH9.js";import{record as f}from"@rrweb/record";const p={mousemove:50,mouseInteraction:!0,scroll:150,media:800,input:`last`};function m(e){return`faststats_replay_sampled_${e}`}function h(e,t){let n=l(t);if(n>=100)return!0;if(n<=0)return!1;let a=i(e).sessionId,o=m(e),s=`${a}:${n}`;try{let e=sessionStorage?.getItem(o);if(e===s)return!0;if(e?.startsWith(`${a}:`))return!1}catch{}let c=r(a)%100<n;try{sessionStorage?.setItem(o,c?s:`${a}:out`)}catch{}return c}var g=class{options;endpoint;compressionSupported=typeof window<`u`&&`CompressionStream`in window;flushInterval;maxEvents;maxPendingBatches;maxQueueSizeBytes;minReplayLengthMs;sampled;events=[];pending=[];pendingSizeBytes=0;viewId=s();chunkStartedAt=0;started=!1;startGeneration=0;startTime=0;sequence=0;intervalId=null;flushTask=null;retryTask=null;minLengthFlushTask=null;stopRecording;sending=!1;flushQueued=!1;flushQueuedLowLatency=!1;unsubscribeRotation;lastCookielessMode=o();constructor(r){this.options=r,this.endpoint=`${e(r.baseUrl,n)}${t.replay}`,this.flushInterval=r.flushInterval??1e4,this.maxEvents=r.maxEvents??500,this.maxPendingBatches=r.maxPendingBatches??30,this.maxQueueSizeBytes=r.maxQueueSizeBytes??2097152,this.minReplayLengthMs=r.minReplayLengthMs??3e3,this.sampled=h(r.siteKey,r.samplingPercentage??100)}log(...e){this.options.debug&&console.log(`[Replay]`,...e)}clearFlushTimers(){this.flushTask&&clearTimeout(this.flushTask),this.retryTask&&clearTimeout(this.retryTask),this.minLengthFlushTask&&clearTimeout(this.minLengthFlushTask),this.flushTask=null,this.retryTask=null,this.minLengthFlushTask=null}clearQueues(){this.events.length=0,this.pending.length=0,this.pendingSizeBytes=0}setCookielessMode(e){this.lastCookielessMode!==e&&(this.lastCookielessMode=e,e&&(this.clearQueues(),this.clearFlushTimers()),this.startTime=i(this.options.siteKey).sessionStart,this.chunkStartedAt=Date.now())}start(){if(this.started||typeof window>`u`||!this.sampled)return;this.started=!0,this.viewId=s(),this.startTime=i(this.options.siteKey).sessionStart,this.chunkStartedAt=Date.now(),this.unsubscribeRotation=c(e=>{this.onSessionRotated(e)});let e=++this.startGeneration;this.beginRecording(e),this.intervalId=setInterval(this.requestFlush,this.flushInterval),window.addEventListener(`beforeunload`,this.onUnload),this.log(`Recording started`)}trackPageChange(e){this.started&&(this.viewId=s(),this.chunkStartedAt=Date.now(),this.onEvent({type:5,timestamp:Date.now(),data:{tag:`faststats:view`,payload:{href:e??window.location.href,viewId:this.viewId}}},!1))}onPageHidden(e=!1){e||this.flush(!0,!0)}onPageShow(e=!1){!e||!this.started||this.pending.length>0&&this.flush(!1)}async beginRecording(e){let t=this.options.recordConsole===!1?null:await import(`@rrweb/rrweb-plugin-console-record`);if(e!==this.startGeneration)return;let n=[];t&&n.push(t.getRecordConsolePlugin());let r=f({emit:this.onEvent,sampling:this.options.sampling??p,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:n});if(e!==this.startGeneration){r?.();return}this.stopRecording=r}stop(){this.started&&(this.started=!1,this.startGeneration++,this.unsubscribeRotation?.(),this.unsubscribeRotation=void 0,this.stopRecording?.(),this.stopRecording=void 0,this.intervalId&&clearInterval(this.intervalId),this.clearFlushTimers(),this.intervalId=null,window.removeEventListener(`beforeunload`,this.onUnload),this.hasReachedMinLength()||(this.events.length=0,this.log(`Session too short (${Date.now()-this.startTime}ms), discarding events`)),this.flush(!0,!0),this.log(`Recording stopped`))}onSessionRotated(e){this.started&&(this.enqueueEventsIfReady(e,!0),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===2&&this.hasReachedMinLength()){this.requestFlush();return}this.scheduleMinLengthFlush()};onUnload=()=>{this.flush(!0,!0)};hasReachedMinLength(){return this.minReplayLengthMs<=0||Date.now()-this.startTime>=this.minReplayLengthMs}requestFlush=()=>{this.flushTask||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));this.minLengthFlushTask=setTimeout(()=>{this.minLengthFlushTask=null,this.requestFlush()},Math.min(e,2147483647))}enqueueEventsIfReady(e,t){if(this.events.length!==0){if(!t&&!this.hasReachedMinLength()){this.scheduleMinLengthFlush();return}this.enqueueBatch(this.createBatch(this.events.splice(0),e,t))}}createBatch(e,t,n){let r=d(),i=this.sequence++,a=this.chunkStartedAt,o=Date.now();return this.chunkStartedAt=o,{token:this.options.siteKey,sessionId:t.sessionId,windowId:t.windowId,viewId:this.viewId,sessionStart:t.sessionStart,chunkStartedAt:a,chunkEndedAt:o,...r?{identifier:r}:{},batchId:`${t.sessionId}-${i}-${a}`,sequence:i,timestamp:o,url:window.location.href,...n?{isFinal:!0}:{},events:e}}batchSizeBytes(e){return new TextEncoder().encode(JSON.stringify(e)).byteLength}dropOldestPending(e){let t=this.pending.shift();t&&(this.pendingSizeBytes=Math.max(0,this.pendingSizeBytes-this.batchSizeBytes(t)),this.log(`${e}, dropping batch ${t.sequence}`))}enqueueBatch(e){let t=this.batchSizeBytes(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>=this.maxPendingBatches||this.pendingSizeBytes+t>this.maxQueueSizeBytes)&&this.pending.length>0;)this.dropOldestPending(`Pending queue limit reached`);this.pending.push(e),this.pendingSizeBytes+=t}async flush(e,t){let n=u(this.options.siteKey);if(n&&this.enqueueEventsIfReady(n.prev,!0),this.enqueueEventsIfReady(i(this.options.siteKey),t),this.pending.length!==0){if(this.sending){this.flushQueued=!0,this.flushQueuedLowLatency||=e;return}this.sending=!0;try{for(;this.pending.length>0;){let t=this.pending[0];if(!t)break;if(!await this.sendBatch(t,e)){this.log(`Failed to send replay batch ${t.sequence}, retrying`),this.scheduleRetry();break}this.dropOldestPending(`Sent replay batch`),e=!1}}finally{if(this.sending=!1,this.flushQueued){let e=this.flushQueuedLowLatency;this.flushQueued=!1,this.flushQueuedLowLatency=!1,this.flush(e)}}}}scheduleRetry(){this.retryTask||=setTimeout(()=>{this.retryTask=null,this.flush(!1)},1e3)}async sendBatch(e,t){let n=JSON.stringify(e),r={debug:!1,useBeacon:t,keepalive:t};if(!t&&(this.options.compress??!0)&&this.compressionSupported)try{let e=new Blob([n]).stream().pipeThrough(new CompressionStream(`gzip`)),t=new Uint8Array(await new Response(e).arrayBuffer());return this.log(`Compressed ${n.length}B -> ${t.byteLength}B (${Math.round(t.byteLength/n.length*100)}%)`),a({url:`${this.endpoint}?encoding=gzip`,data:t,contentType:`application/octet-stream`,...r})}catch{this.log(`Compression failed, using uncompressed`)}return a({url:this.endpoint,data:n,contentType:`application/json`,...r})}};export{g as default};
1
+ import{a as e,r as t,t as n}from"./chunks/api-urls-Bh77rElT.js";import{a as r,c as i,i as a,n as o,r as s,t as c}from"./chunks/send-data-CIbuTxPh.js";import{t as l}from"./chunks/identifiers-DcGHdsnG.js";import{record as u}from"@rrweb/record";const d=new TextEncoder,f=new WeakMap;var p=class{options;endpoint;compressionSupported=typeof window<`u`&&`CompressionStream`in window;flushInterval;maxEvents;maxBatchSizeBytes;maxLowLatencyBatchSizeBytes;maxPendingBatches;maxQueueSizeBytes;minReplayLengthMs;events=[];pending=[];queuedEventsSizeBytes=0;pendingSizeBytes=0;viewId=o();chunkStartedAt=0;started=!1;startGeneration=0;startTime=0;sequence=0;intervalId=null;flushTask=null;retryTask=null;minLengthFlushTask=null;stopRecording;sending=!1;flushQueued=!1;flushQueuedLowLatency=!1;unsubscribeRotation;lastCookielessMode=a();constructor(r){this.options=r,this.endpoint=`${e(r.baseUrl,n)}${t.replay}`,this.flushInterval=r.flushInterval??5e3,this.maxEvents=r.maxEvents??1e3,this.maxBatchSizeBytes=r.maxBatchSizeBytes??524288,this.maxLowLatencyBatchSizeBytes=r.maxLowLatencyBatchSizeBytes??61440,this.maxPendingBatches=r.maxPendingBatches??30,this.maxQueueSizeBytes=r.maxQueueSizeBytes??2097152,this.minReplayLengthMs=r.minReplayLengthMs??3e3}log(...e){this.options.debug&&console.log(`[Replay]`,...e)}clearFlushTimers(){this.flushTask&&clearTimeout(this.flushTask),this.retryTask&&clearTimeout(this.retryTask),this.minLengthFlushTask&&clearTimeout(this.minLengthFlushTask),this.flushTask=null,this.retryTask=null,this.minLengthFlushTask=null}clearQueues(){this.events.length=0,this.queuedEventsSizeBytes=0,this.pending.length=0,this.pendingSizeBytes=0}storage(){try{return globalThis.sessionStorage}catch{return null}}counterKey(e){return`faststats_replay_batch_sequence_${this.options.siteKey}_${e.windowId}`}readCounter(e){let t=this.storage()?.getItem(this.counterKey(e));if(!t)return this.sequence;let n=Number.parseInt(t,10);return Number.isFinite(n)&&n>=0?n:this.sequence}writeCounter(e,t){this.sequence=t;try{this.storage()?.setItem(this.counterKey(e),String(t))}catch{}}nextBatchSequence(e){let t=this.readCounter(e);return this.writeCounter(e,t+1),t}setCookielessMode(e){this.lastCookielessMode!==e&&(this.lastCookielessMode=e,e&&(this.clearQueues(),this.clearFlushTimers()),this.startTime=s(this.options.siteKey).sessionStart,this.chunkStartedAt=Date.now())}start(){if(this.started||typeof window>`u`)return;this.started=!0,this.viewId=o(),this.startTime=s(this.options.siteKey).sessionStart,this.chunkStartedAt=Date.now(),this.unsubscribeRotation=r(e=>{this.onSessionRotated(e)});let e=++this.startGeneration;this.beginRecording(e),this.intervalId=setInterval(()=>this.requestFlush(`interval`),this.flushInterval),window.addEventListener(`beforeunload`,this.onUnload),this.log(`Recording started`)}trackPageChange(e){this.started&&(this.viewId=o(),this.chunkStartedAt=Date.now(),this.onEvent({type:5,timestamp:Date.now(),data:{tag:`faststats:view`,payload:{href:e??window.location.href,viewId:this.viewId}}},!1))}onPageHidden(e=!1){e||this.flush(!0,!0,`pageHidden`)}onPageShow(e=!1){!e||!this.started||this.pending.length>0&&this.flush(!1,!1,`pageShow`)}async beginRecording(e){let[t,n]=await Promise.all([this.options.recordConsole===!1?Promise.resolve(null):import(`@rrweb/rrweb-plugin-console-record`),import(`@rrweb/rrweb-plugin-sequential-id-record`)]);if(e!==this.startGeneration)return;let r=[n.getRecordSequentialIdPlugin({key:`_faststatsSeqId`})];t&&r.push(t.getRecordConsolePlugin({level:this.options.consoleLevel??[`error`,`warn`,`info`,`log`],lengthThreshold:this.options.consoleLengthThreshold??200,stringifyOptions:{numOfKeysLimit:25,depthOfLimit:3,stringLengthLimit:this.options.consoleStringLengthLimit??500}}));let i=u({emit:this.onEvent,sampling:this.options.sampling??{mousemove:50,mouseInteraction:!0,scroll:150,media:800,input:`last`},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:r});if(e!==this.startGeneration){i?.();return}this.stopRecording=i}stop(){this.started&&(this.started=!1,this.startGeneration++,this.unsubscribeRotation?.(),this.unsubscribeRotation=void 0,this.stopRecording?.(),this.stopRecording=void 0,this.intervalId&&clearInterval(this.intervalId),this.clearFlushTimers(),this.intervalId=null,window.removeEventListener(`beforeunload`,this.onUnload),this.hasReachedMinLength()||(this.events.length=0,this.queuedEventsSizeBytes=0,this.log(`Session too short (${Date.now()-this.startTime}ms), discarding events`)),this.flush(!0,!0,`stop`),this.log(`Recording stopped`))}onSessionRotated(e){this.started&&(this.enqueueEventsIfReady(e,!0,`sessionRotate`),this.pending.length>0&&queueMicrotask(()=>void this.flush(!1)))}onEvent=(e,t)=>{if(this.events.push(e),this.queuedEventsSizeBytes+=this.eventSizeBytes(e),t){this.requestFlush(`checkout`);return}if(this.events.length>=this.maxEvents){this.requestFlush(`maxEvents`);return}if(this.queuedEventsSizeBytes>=this.maxBatchSizeBytes){this.requestFlush(`maxBytes`);return}if(e.type===2&&this.hasReachedMinLength()){this.requestFlush(`fullSnapshot`);return}this.scheduleMinLengthFlush()};onUnload=()=>{this.flush(!0,!0,`unload`)};hasReachedMinLength(){return this.minReplayLengthMs<=0||Date.now()-this.startTime>=this.minReplayLengthMs}requestFlush=(e=`manual`)=>{this.flushTask||this.events.length===0||(this.minLengthFlushTask&&=(clearTimeout(this.minLengthFlushTask),null),this.flushTask=setTimeout(()=>{this.flushTask=null,this.flush(!1,!1,e)},0))};scheduleMinLengthFlush(){if(this.minLengthFlushTask||this.events.length===0||this.hasReachedMinLength())return;let e=Math.max(0,this.minReplayLengthMs-(Date.now()-this.startTime));this.minLengthFlushTask=setTimeout(()=>{this.minLengthFlushTask=null,this.requestFlush(`minLength`)},Math.min(e,2147483647))}enqueueEventsIfReady(e,t,n=`manual`,r=this.maxBatchSizeBytes){if(this.events.length===0)return;if(!t&&!this.hasReachedMinLength()){this.scheduleMinLengthFlush();return}let i=this.takeEventBatches(r);for(let r=0;r<i.length;r+=1)this.enqueueBatch(this.createBatch(i[r]??[],e,t&&r===i.length-1,n));this.queuedEventsSizeBytes=0}takeEventBatches(e){let t=[],n=[],r=0;for(let i of this.events.splice(0)){let a=this.eventSizeBytes(i);n.length>0&&r+a>e&&(t.push(n),n=[],r=0),n.push(i),r+=a}return n.length>0&&t.push(n),t}createBatch(e,t,n,r=`manual`){let i=l(),a=this.nextBatchSequence(t),o=this.chunkStartedAt,s=Date.now();return this.chunkStartedAt=s,{token:this.options.siteKey,sessionId:t.sessionId,windowId:t.windowId,viewId:this.viewId,sessionStart:t.sessionStart,chunkStartedAt:o,chunkEndedAt:s,...i?{identifier:i}:{},batchId:`${t.sessionId}-${a}-${o}`,sequence:a,timestamp:s,url:window.location.href,...n?{isFinal:!0}:{},flushReason:r,events:e}}eventSizeBytes(e){return d.encode(JSON.stringify(e)).byteLength+1}batchSizeBytes(e){let t=f.get(e);if(t!==void 0)return t;let n=d.encode(JSON.stringify(e)).byteLength;return f.set(e,n),n}dropOldestPending(e){let t=this.pending.shift();t&&(this.pendingSizeBytes=Math.max(0,this.pendingSizeBytes-this.batchSizeBytes(t)),this.log(`${e}, dropping batch ${t.sequence}`))}enqueueBatch(e){let t=this.batchSizeBytes(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>=this.maxPendingBatches||this.pendingSizeBytes+t>this.maxQueueSizeBytes)&&this.pending.length>0;)this.dropOldestPending(`Pending queue limit reached`);this.pending.push(e),this.pendingSizeBytes+=t}async flush(e,t,n=`manual`){let r=i(this.options.siteKey);if(r&&this.enqueueEventsIfReady(r.prev,!0,`sessionRotate`),this.enqueueEventsIfReady(s(this.options.siteKey),t,n,e?this.maxLowLatencyBatchSizeBytes:this.maxBatchSizeBytes),this.pending.length!==0){if(this.sending){this.flushQueued=!0,this.flushQueuedLowLatency||=e;return}this.sending=!0;try{for(;this.pending.length>0;){let t=this.pending[0];if(!t)break;if(!await this.sendBatch(t,e)){this.log(`Failed to send replay batch ${t.sequence}, retrying`),this.scheduleRetry();break}this.dropOldestPending(`Sent replay batch`)}}finally{if(this.sending=!1,this.flushQueued){let e=this.flushQueuedLowLatency;this.flushQueued=!1,this.flushQueuedLowLatency=!1,this.flush(e)}}}}scheduleRetry(){this.retryTask||=setTimeout(()=>{this.retryTask=null,this.flush(!1)},1e3)}async sendBatch(e,t){let n=JSON.stringify(e),r={useBeacon:t,keepalive:t};if(!t&&(this.options.compress??!0)&&this.compressionSupported)try{let e=new Blob([n]).stream().pipeThrough(new CompressionStream(`gzip`)),t=new Uint8Array(await new Response(e).arrayBuffer());return this.log(`Compressed ${n.length}B -> ${t.byteLength}B (${Math.round(t.byteLength/n.length*100)}%)`),c({url:`${this.endpoint}?encoding=gzip`,data:t,contentType:`application/octet-stream`,...r})}catch{this.log(`Compression failed, using uncompressed`)}return c({url:this.endpoint,data:n,contentType:`application/json`,...r})}};export{p as default};
@@ -3,23 +3,23 @@ interface WebVitalsOptions {
3
3
  siteKey: string;
4
4
  baseUrl?: string;
5
5
  debug?: boolean;
6
- samplingPercentage?: number;
7
6
  attribution?: boolean;
8
7
  }
9
8
  declare class WebVitalsTracker {
10
9
  private readonly options;
11
10
  private readonly endpoint;
12
- private readonly sampled;
13
11
  private metrics;
14
12
  private started;
15
13
  private flushing;
16
- private url;
14
+ private initialUrl;
15
+ private currentUrl;
17
16
  constructor(options: WebVitalsOptions);
18
17
  start(): Promise<void>;
19
18
  stop(): void;
20
19
  onPageHidden(persisted?: boolean): void;
21
20
  trackPageChange(url?: string): void;
22
21
  private onMetric;
22
+ private getMetricUrl;
23
23
  private flush;
24
24
  }
25
25
  //#endregion
@@ -1 +1 @@
1
- import{a as e,r as t,t as n}from"./chunks/api-urls-Bh77rElT.js";import{a as r,i,n as a,t as o}from"./chunks/send-data-Cc1nxIlg.js";var s=class{options;endpoint;sampled;metrics=new Map;started=!1;flushing=!1;url=``;constructor(a){this.options=a,this.endpoint=`${e(a.baseUrl,n)}${t.vitals}`;let s=o(a.samplingPercentage);this.sampled=s>=100||s>0&&r(i(a.siteKey).sessionId)%100<s}async start(){if(this.started||typeof window>`u`)return;this.started=!0,this.url=window.location.href;let e=await(this.options.attribution?import(`web-vitals/attribution`):import(`web-vitals`));if(!this.started)return;let t={reportAllChanges:!0};e.onCLS(this.onMetric,t),e.onINP(this.onMetric,t),e.onLCP(this.onMetric,t),e.onFCP(this.onMetric),e.onTTFB(this.onMetric)}stop(){this.started&&(this.started=!1,this.flush())}onPageHidden(e=!1){e||this.flush()}trackPageChange(e){if(!this.started)return;let t=e??window.location.href;t!==this.url&&(this.flush(),this.url=t)}onMetric=e=>{if(!this.started||!this.sampled)return;let t=e.name,{id:n,rating:r,delta:i,navigationType:a}=e,o=`attribution`in e&&e.attribution?e.attribution:void 0;this.metrics.set(t,{metric:t,value:e.value,attributes:{id:n,rating:r,delta:i,navigationType:a,...o}})};flush(){if(!this.metrics.size||this.flushing)return;this.flushing=!0;let e=this.metrics;this.metrics=new Map;let t=i(this.options.siteKey);a({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,sessionId:t.sessionId,windowId:t.windowId,vitals:[...e.values()],metadata:{url:this.url}}),debug:this.options.debug,debugPrefix:`[WebVitals]`}).then(t=>{if(!t)for(let[t,n]of e)this.metrics.has(t)||this.metrics.set(t,n);this.flushing=!1})}};export{s as default};
1
+ import{a as e,r as t,t as n}from"./chunks/api-urls-Bh77rElT.js";import{r,t as i}from"./chunks/send-data-CIbuTxPh.js";var a=class{options;endpoint;metrics=new Map;started=!1;flushing=!1;initialUrl=``;currentUrl=``;constructor(r){this.options=r,this.endpoint=`${e(r.baseUrl,n)}${t.vitals}`}async start(){if(this.started||typeof window>`u`)return;this.started=!0,this.initialUrl=window.location.href,this.currentUrl=this.initialUrl;let e=await(this.options.attribution?import(`web-vitals/attribution`):import(`web-vitals`));if(!this.started)return;let t={reportAllChanges:!0};e.onCLS(this.onMetric,t),e.onINP(this.onMetric,t),e.onLCP(this.onMetric,t),e.onFCP(this.onMetric),e.onTTFB(this.onMetric)}stop(){this.started&&(this.started=!1,this.flush())}onPageHidden(e=!1){e||this.flush()}trackPageChange(e){if(!this.started)return;let t=e??window.location.href;t!==this.currentUrl&&(this.currentUrl=t)}onMetric=e=>{if(!this.started)return;let t=e.name,n=this.getMetricUrl(t),{id:r,rating:i,delta:a,navigationType:o}=e,s=`attribution`in e&&e.attribution?e.attribution:void 0;this.metrics.set(`${n}\n${t}`,{metric:t,url:n,value:e.value,attributes:{id:r,rating:i,delta:a,navigationType:o,...s}})};getMetricUrl(e){return e===`FCP`||e===`LCP`||e===`TTFB`?this.initialUrl:this.currentUrl||this.initialUrl}flush(){if(!this.metrics.size||this.flushing)return;this.flushing=!0;let e=this.metrics;this.metrics=new Map;let t=r(this.options.siteKey),n=new Map;for(let t of e.values()){let e=n.get(t.url)??[];e.push(t),n.set(t.url,e)}Promise.all([...n].map(([e,n])=>i({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,sessionId:t.sessionId,windowId:t.windowId,vitals:n.map(({url:e,...t})=>t),metadata:{url:e}}),debug:this.options.debug,debugPrefix:`[WebVitals]`}).then(t=>({ok:t,url:e,vitals:n})))).then(e=>{for(let t of e)if(!t.ok)for(let e of t.vitals){let n=`${t.url}\n${e.metric}`;this.metrics.has(n)||this.metrics.set(n,e)}this.flushing=!1})}};export{a as default};
package/package.json CHANGED
@@ -42,7 +42,7 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "version": "0.4.1",
45
+ "version": "0.5.0",
46
46
  "scripts": {
47
47
  "build": "tsdown && bun run check-size",
48
48
  "dev": "bun run build",
@@ -57,8 +57,9 @@
57
57
  "typescript": "^6.0.3"
58
58
  },
59
59
  "dependencies": {
60
- "@rrweb/rrweb-plugin-console-record": "^2.0.1",
61
- "@rrweb/record": "^2.0.1",
60
+ "@rrweb/record": "^2.1.0",
61
+ "@rrweb/rrweb-plugin-console-record": "^2.1.0",
62
+ "@rrweb/rrweb-plugin-sequential-id-record": "^2.1.0",
62
63
  "web-vitals": "^5.3.0"
63
64
  }
64
65
  }
@@ -1 +0,0 @@
1
- import{o as e,r as t}from"./send-data-Cc1nxIlg.js";const n=`faststats_anon_id`;function r(){try{return globalThis.localStorage}catch{return}}function i(){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 a(t){return t??e()?``:i()}function o(e){if(e)return``;try{let e=r();if(!e)return``;e.removeItem(n)}catch{return``}return i()}export{o as n,a as t};
@@ -1 +0,0 @@
1
- const e=`faststats_session`;let t=!1,n=null;const r=new Set;function i(){try{return globalThis.localStorage}catch{return null}}function a(){try{return globalThis.sessionStorage}catch{return null}}function o(){return typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}function s(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 c(){let t=i();if(!t)return n;let r=t.getItem(e);if(r)try{let e=JSON.parse(r);if(e.id)return e}catch{}let a=t.getItem(`faststats_session_id`),o=t.getItem(`faststats_session_activity`),s=o===null?NaN:Number(o);if(!a||!Number.isFinite(s))return n;let c=t.getItem(`faststats_session_start`),u=c===null?s:Number(c),d={id:a,start:Number.isFinite(u)?u:s,activity:s};return l(d),t.removeItem(`faststats_session_id`),t.removeItem(`faststats_session_activity`),t.removeItem(`faststats_session_start`),d}function l(t){let r=i();if(!r){n=t;return}try{r.setItem(e,JSON.stringify(t))}catch{n=t}}function u(){n=null;try{i()?.removeItem(e)}catch{}}function d(e,t){return t-e.activity>=18e5||t-e.start>=864e5}function f(e,t){for(let n of r)n(e,t)}function p(e,t){let r=Date.now();if(e)return n?t&&(n.activity=r):n={id:o(),start:r,activity:r},{session:n,rotated:!1,previous:null};let i=c();if(i&&!d(i,r))return t&&(i.activity=r,l(i)),{session:i,rotated:!1,previous:null};let a=i,s={id:o(),start:r,activity:r};return l(s),{session:s,rotated:a!==null,previous:a}}function m(e,t,n){if(t)return n;let r=`faststats_window_id_${e}`,i=a();if(!i)return n;try{let e=i.getItem(r);if(e)return e;let t=o();return i.setItem(r,t),t}catch{return n}}function h(e,t,n,r){let i=r??m(e,n,t.id);return{sessionId:t.id,windowId:i,sessionStart:t.start}}function g(e){t=e,n=null}function _(){return t}function v(e,n){let r=n??t,{session:i}=p(r,!1);return h(e,i,r)}function y(e,n){let r=n??t,{session:i,rotated:a,previous:o}=p(r,!0);if(!a||!o)return null;let s=m(e,r,i.id),c={prev:h(e,o,r,s),next:h(e,i,r,s)};return f(c.prev,c.next),c}function b(e){let r=t,i=v(e,r);if(u(),r){let e=Date.now();n={id:o(),start:e,activity:e}}else try{a()?.removeItem(`faststats_window_id_${e}`)}catch{}let s=v(e,r);return i.sessionId!==s.sessionId&&f(i,s),s}function x(e){return r.add(e),()=>r.delete(e)}function S(e){return typeof e!=`number`||!Number.isFinite(e)?100:Math.max(0,Math.min(100,e))}async function C(e){let{url:t,data:n,contentType:r=`application/json`,headers:i={},debug:a=!1,debugPrefix:o=`[Analytics]`,useBeacon:s=!0,keepalive:c=!0,signal:l}=e;if(l?.aborted)return!1;if(s&&typeof globalThis.navigator?.sendBeacon==`function`)try{let e=n instanceof Blob||typeof Blob>`u`?n:new Blob([n],{type:r});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,credentials:`omit`,signal:l}),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{s as a,b as c,v as i,g as l,C as n,_ as o,o as r,x as s,S as t,y as u};