@faststats/web 0.2.14 → 0.3.1

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.
Files changed (53) hide show
  1. package/dist/chunks/api-urls-nKmJnyjD.js +1 -0
  2. package/dist/chunks/identifiers-DrjjHcKB.js +1 -0
  3. package/dist/chunks/{replay-DvJYurEC.d.ts → replay-DR_T0Iz4.d.ts} +12 -17
  4. package/dist/chunks/send-data-Cb4xlYF0.js +1 -0
  5. package/dist/error.d.ts +4 -12
  6. package/dist/error.js +2 -1
  7. package/dist/feature-flags.d.ts +19 -2
  8. package/dist/feature-flags.js +1 -1
  9. package/dist/index.d.ts +28 -59
  10. package/dist/index.js +1 -1
  11. package/dist/replay.d.ts +2 -2
  12. package/dist/replay.js +1 -1
  13. package/dist/web-vitals.d.ts +5 -8
  14. package/dist/web-vitals.js +1 -1
  15. package/package.json +7 -6
  16. package/CHANGELOG.md +0 -184
  17. package/REPLAY_PAYLOAD.md +0 -64
  18. package/dist/chunks/api-urls-DaeYkG0_.js +0 -1
  19. package/dist/chunks/error-Cd9PTS5v.js +0 -2
  20. package/dist/chunks/feature-flags-BClx56v5.d.ts +0 -19
  21. package/dist/chunks/feature-flags-DSOCIZHK.js +0 -1
  22. package/dist/chunks/replay-rTqcjOo2.js +0 -1
  23. package/dist/chunks/rolldown-runtime-MP-BAFHD.js +0 -1
  24. package/dist/chunks/send-data-B2fYGj6v.js +0 -1
  25. package/dist/chunks/session-manager-Cy63ptPF.js +0 -1
  26. package/dist/chunks/types-CYzR5xtT.js +0 -1
  27. package/dist/chunks/web-vitals-Be-Cg4Po.js +0 -1
  28. package/scripts/check-bundle-size.mjs +0 -96
  29. package/src/analytics.ts +0 -787
  30. package/src/entries/error.ts +0 -6
  31. package/src/entries/feature-flags.ts +0 -5
  32. package/src/entries/main.ts +0 -21
  33. package/src/entries/replay.ts +0 -1
  34. package/src/entries/web-vitals.ts +0 -1
  35. package/src/env.d.ts +0 -2
  36. package/src/error.ts +0 -257
  37. package/src/feature-flags.ts +0 -84
  38. package/src/replay.ts +0 -596
  39. package/src/sdk.ts +0 -8
  40. package/src/utils/api-urls.ts +0 -24
  41. package/src/utils/identifiers.ts +0 -47
  42. package/src/utils/send-data.ts +0 -52
  43. package/src/utils/session-manager.ts +0 -416
  44. package/src/utils/types.ts +0 -15
  45. package/src/web-vitals.ts +0 -159
  46. package/tests/analytics.test.ts +0 -453
  47. package/tests/identifiers.test.ts +0 -78
  48. package/tests/replay.test.ts +0 -582
  49. package/tests/session-manager.test.ts +0 -161
  50. package/tests/web-vitals.test.ts +0 -208
  51. package/tsconfig.json +0 -30
  52. package/tsdown.config.ts +0 -27
  53. package/worker/index.ts +0 -22
@@ -0,0 +1 @@
1
+ function e(e){return e.replace(/\/+$/,``)}function t(t,n){return t===void 0||t===``?n:e(t)||n}function n(e){return t(e,`https://metrics.faststats.dev`)}function r(e){return t(e,`https://flags.faststats.dev`)}const i={events:`/v1/web`,identify:`/v1/identify`,replay:`/v1/replay`,vitals:`/v1/vitals`,flags:`/v1/check`};function a(){return{page:location.pathname,url:location.href,referrer:document.referrer||null,title:document.title||``}}export{r as i,a as n,n as r,i as t};
@@ -0,0 +1 @@
1
+ import{l as e,r as t}from"./send-data-Cb4xlYF0.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,8 +1,7 @@
1
- import { eventWithTime } from "@rrweb/types";
2
- import { recordOptions } from "rrweb/typings/types";
3
- import { SlimDOMOptions } from "rrweb-snapshot";
1
+ import { record } from "@rrweb/record";
4
2
 
5
3
  //#region src/replay.d.ts
4
+ type RecordOptions = NonNullable<Parameters<typeof record>[0]>;
6
5
  interface ReplayTrackerOptions {
7
6
  siteKey: string;
8
7
  baseUrl?: string;
@@ -15,10 +14,10 @@ interface ReplayTrackerOptions {
15
14
  maxPendingBatches?: number;
16
15
  maxQueueSizeBytes?: number;
17
16
  minReplayLengthMs?: number;
18
- sampling?: recordOptions<eventWithTime>["sampling"];
19
- slimDOMOptions?: SlimDOMOptions;
17
+ sampling?: RecordOptions["sampling"];
18
+ slimDOMOptions?: RecordOptions["slimDOMOptions"];
20
19
  maskAllInputs?: boolean;
21
- maskInputOptions?: recordOptions<eventWithTime>["maskInputOptions"];
20
+ maskInputOptions?: RecordOptions["maskInputOptions"];
22
21
  blockClass?: string;
23
22
  blockSelector?: string;
24
23
  maskTextClass?: string;
@@ -36,7 +35,7 @@ declare class ReplayTracker {
36
35
  private readonly pending;
37
36
  private pendingSizeBytes;
38
37
  private viewId;
39
- private readonly windowId;
38
+ private chunkStartedAt;
40
39
  private started;
41
40
  private startTime;
42
41
  private sequence;
@@ -47,40 +46,36 @@ declare class ReplayTracker {
47
46
  private stopRecording?;
48
47
  private sending;
49
48
  private unsubscribeRotation?;
49
+ private cookieless;
50
50
  constructor(options: ReplayTrackerOptions);
51
- private get cookieless();
52
- private get debug();
53
51
  private get flushInterval();
54
52
  private get maxEvents();
55
53
  private get maxPendingBatches();
56
54
  private get maxQueueSizeBytes();
57
55
  private get minReplayLengthMs();
58
- private get shouldCompress();
59
56
  private log;
60
57
  private sessionContext;
58
+ setCookielessMode(cookieless: boolean): void;
59
+ private resetChunk;
61
60
  start(): void;
62
61
  trackPageChange(url?: string): void;
62
+ onPageHidden(persisted?: boolean): void;
63
+ onPageShow(persisted?: boolean): void;
63
64
  private beginRecording;
64
65
  stop(): void;
65
- getSessionId(): string;
66
- getWindowId(): string;
67
66
  private onSessionRotated;
68
67
  private onEvent;
69
68
  private onUnload;
70
- private onVisibilityChange;
71
69
  private hasReachedMinLength;
72
70
  private requestFlush;
73
71
  private scheduleMinLengthFlush;
74
72
  private createBatch;
75
- private createBatchId;
76
73
  private getBatchSizeBytes;
77
74
  private dropOldestPendingBatch;
78
75
  private enqueueBatch;
79
- private encodeBatch;
80
76
  private flush;
81
77
  private scheduleRetry;
82
- private compress;
83
- private send;
78
+ private sendBatch;
84
79
  }
85
80
  //#endregion
86
81
  export { ReplayTrackerOptions as n, ReplayTracker as t };
@@ -0,0 +1 @@
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(e){if(!e)return null;try{let t=JSON.parse(e);if(typeof t.id==`string`&&t.id&&Number.isFinite(t.start)&&t.start>0&&Number.isFinite(t.activity)&&t.activity>0)return t}catch{}return null}function l(){let t=i();if(!t)return n;let r=c(t.getItem(e));if(r)return r;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 l=t.getItem(`faststats_session_start`),d=l===null?s:Number(l),f={id:a,start:Number.isFinite(d)?d:s,activity:s};return u(f),t.removeItem(`faststats_session_id`),t.removeItem(`faststats_session_activity`),t.removeItem(`faststats_session_start`),f}function u(t){let r=i();if(!r){n=t;return}try{r.setItem(e,JSON.stringify(t))}catch{n=t}}function d(){n=null;try{i()?.removeItem(e)}catch{}}function f(e,t){return t-e.activity>=18e5||t-e.start>=864e5}function p(e,t){for(let n of r)n(e,t)}function m(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=l();if(i&&!f(i,r))return t&&(i.activity=r,u(i)),{session:i,rotated:!1,previous:null};let a=i,s={id:o(),start:r,activity:r};return u(s),{session:s,rotated:a!==null,previous:a}}function h(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 g(e,t,n,r){let i=r??h(e,n,t.id);return{sessionId:t.id,windowId:i,sessionStart:t.start}}function _(e){t=e,e&&(n=null)}function v(){return t}function y(e,n){let r=n??t,{session:i}=m(r,!1);return h(e,r,i.id)}function b(e,n){let r=n??t,{session:i}=m(r,!1);return g(e,i,r)}function x(e){return m(e??t,!0).session.id}function S(e){return m(e??t,!1).session.start}function C(e,n){let r=n??t,{session:i,rotated:a,previous:o}=m(r,!0);if(!a||!o)return null;let s=h(e,r,i.id),c={prev:g(e,o,r,s),next:g(e,i,r,s)};return p(c.prev,c.next),c}function w(e){let r=t,i=b(e,r);if(d(),r){let e=Date.now();n={id:o(),start:e,activity:e}}else try{a()?.removeItem(`faststats_window_id_${e}`)}catch{}let s=b(e,r);return i.sessionId!==s.sessionId&&p(i,s),s}function T(e){return r.add(e),()=>r.delete(e)}function E(e){return typeof e!=`number`||!Number.isFinite(e)?100:Math.max(0,Math.min(100,e))}async function D(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?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{}if(typeof globalThis.fetch!=`function`)return a&&console.warn(`${o} Failed to send`),!1;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,s as c,w as d,_ as f,x as i,v as l,D as n,b as o,C as p,o as r,S as s,E as t,T as u};
package/dist/error.d.ts CHANGED
@@ -4,11 +4,6 @@ type ErrorEntry = {
4
4
  message?: string;
5
5
  stack?: string[];
6
6
  handled?: boolean;
7
- cause?: ErrorEntry;
8
- };
9
- type ErrorTracking = ErrorEntry & {
10
- hash: string;
11
- count: number;
12
7
  };
13
8
  interface ErrorTrackingOptions {
14
9
  siteKey: string;
@@ -22,8 +17,7 @@ interface ErrorTrackingOptions {
22
17
  declare class ErrorTracker {
23
18
  private readonly options;
24
19
  private readonly endpoint;
25
- private readonly seen;
26
- private readonly queue;
20
+ private queue;
27
21
  private timer;
28
22
  private started;
29
23
  private flushing;
@@ -31,14 +25,12 @@ declare class ErrorTracker {
31
25
  private log;
32
26
  start(): void;
33
27
  stop(): void;
28
+ onPageHidden(persisted?: boolean): void;
34
29
  captureError(error: Error): void;
35
30
  private onError;
36
31
  private onRejection;
37
- private onVisibility;
38
- private scheduleFlush;
39
- private capture;
32
+ private enqueue;
40
33
  private flush;
41
- private requeue;
42
34
  }
43
35
  //#endregion
44
- export { type ErrorEntry, type ErrorTracking, type ErrorTrackingOptions, ErrorTracker as default };
36
+ export { ErrorEntry, ErrorTrackingOptions, ErrorTracker as default };
package/dist/error.js CHANGED
@@ -1 +1,2 @@
1
- import{t as e}from"./chunks/error-Cd9PTS5v.js";export{e as default};
1
+ import{n as e,r as t,t as n}from"./chunks/api-urls-nKmJnyjD.js";import{a as r,i,n as a}from"./chunks/send-data-Cb4xlYF0.js";import{t as o}from"./chunks/identifiers-DrjjHcKB.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{endpoint;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),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 t=this.queue;this.queue=new Map;let n=[...t.values()];this.log(`Flushing:`,n);try{let s=globalThis.__SOURCEMAPS_BUILD__?.buildId,c=o();if(!await a({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,...c?{userId:c}:{},sessionId:i(),windowId:r(this.options.siteKey),...typeof s==`string`&&s.trim()?{buildId:s}:{},sdkName:this.options.sdkName??`@faststats/web`,sdkVersion:this.options.sdkVersion??`0.3.1`,event:`error`,...e(),properties:{},errors:n}),debug:this.options.debug,debugPrefix:`[ErrorTracker]`}))for(let[e,n]of t){let t=this.queue.get(e);t?t.count+=n.count:this.queue.set(e,n)}}finally{this.flushing=!1}}};export{d as default};
@@ -1,2 +1,19 @@
1
- import { n as FeatureFlagEvaluation, r as fetchFeatureFlagEvaluation, t as FeatureFlagCheckContext } from "./chunks/feature-flags-BClx56v5.js";
2
- export { type FeatureFlagCheckContext, type FeatureFlagEvaluation, fetchFeatureFlagEvaluation };
1
+ //#region src/feature-flags.d.ts
2
+ type FeatureFlagEvaluation = {
3
+ value: string;
4
+ variantKey?: string;
5
+ variantValue?: string;
6
+ };
7
+ type FeatureFlagCheckContext = {
8
+ baseUrl?: string;
9
+ projectToken?: string;
10
+ projectId?: string;
11
+ identifier?: string;
12
+ externalId?: string;
13
+ sessionId?: string;
14
+ attributes?: Record<string, unknown>;
15
+ signal?: AbortSignal;
16
+ };
17
+ declare function fetchFeatureFlagEvaluation(flagKey: string, context: FeatureFlagCheckContext): Promise<FeatureFlagEvaluation>;
18
+ //#endregion
19
+ export { FeatureFlagCheckContext, FeatureFlagEvaluation, fetchFeatureFlagEvaluation };
@@ -1 +1 @@
1
- import{n as e}from"./chunks/feature-flags-DSOCIZHK.js";export{e as fetchFeatureFlagEvaluation};
1
+ import{i as e,t}from"./chunks/api-urls-nKmJnyjD.js";async function n(n,r){if(r.projectToken&&r.projectId)throw Error(`provide either projectToken or projectId, not both`);let i=r.projectToken,a=r.projectId,o=r.identifier,s=r.externalId,c=r.sessionId;if(!i&&!a)throw Error(`feature flag check requires projectToken or projectId`);if(!o&&!s)throw Error(`feature flag check requires serverId or externalId`);let l={key:n,...a?{projectId:a}:{},...o?{identifier:o}:{},...s?{externalId:s}:{},...c?{sessionId:c}:{}},u=r.attributes??{};Object.keys(u).length>0&&(l.attributes=u);let d={"Content-Type":`application/json`};i&&(d.Authorization=`Bearer ${i}`);let f=`${e(r.baseUrl)}${t.flags}`,p=await fetch(f,{method:`POST`,headers:d,body:JSON.stringify(l),credentials:`omit`,signal:r.signal});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{n as fetchFeatureFlagEvaluation};
package/dist/index.d.ts CHANGED
@@ -1,39 +1,8 @@
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-DvJYurEC.js";
1
+ import { FeatureFlagEvaluation } from "./feature-flags.js";
2
+ import { n as ReplayTrackerOptions } from "./chunks/replay-DR_T0Iz4.js";
3
3
 
4
- //#region src/utils/types.d.ts
5
- interface SendDataOptions {
6
- url: string;
7
- data: string | Blob | Uint8Array;
8
- contentType?: string;
9
- headers?: Record<string, string>;
10
- debug?: boolean;
11
- debugPrefix?: string;
12
- useBeacon?: boolean;
13
- keepalive?: boolean;
14
- }
15
- //#endregion
16
- //#region src/utils/send-data.d.ts
17
- declare function sendData(options: SendDataOptions): Promise<boolean>;
18
- //#endregion
19
4
  //#region src/analytics.d.ts
20
- type Dict = Record<string, unknown>;
21
- interface SamplingOptions {
22
- percentage?: number;
23
- }
24
- interface WebVitalsConfig {
25
- sampling?: SamplingOptions;
26
- attribution?: boolean;
27
- }
28
- interface SessionReplayConfig {
29
- enabled?: boolean;
30
- sampling?: SamplingOptions;
31
- }
32
5
  type ConsentMode = "pending" | "granted" | "denied";
33
- interface ConsentConfig {
34
- mode?: ConsentMode;
35
- cookielessWhilePending?: boolean;
36
- }
37
6
  interface IdentifyOptions {
38
7
  name?: string;
39
8
  phone?: string;
@@ -51,9 +20,23 @@ interface WebAnalyticsOptions {
51
20
  trackWebVitals?: boolean;
52
21
  trackReplay?: boolean;
53
22
  cookieless?: boolean;
54
- consent?: ConsentConfig;
55
- webVitals?: WebVitalsConfig;
56
- sessionReplays?: SessionReplayConfig;
23
+ consent?: {
24
+ mode?: ConsentMode;
25
+ cookielessWhilePending?: boolean;
26
+ };
27
+ webVitals?: {
28
+ enabled?: boolean;
29
+ sampling?: {
30
+ percentage?: number;
31
+ };
32
+ attribution?: boolean;
33
+ };
34
+ sessionReplays?: {
35
+ enabled?: boolean;
36
+ sampling?: {
37
+ percentage?: number;
38
+ };
39
+ };
57
40
  replayOptions?: Partial<ReplayTrackerOptions>;
58
41
  /** @internal */
59
42
  sdkName?: string;
@@ -80,13 +63,10 @@ declare class WebAnalytics {
80
63
  private pageKey;
81
64
  private navTimer;
82
65
  private heartbeatTimer;
83
- private scrollDepth;
84
- private pageEntryTime;
85
66
  private pagePath;
86
67
  private pageUrl;
87
68
  private pageHash;
88
69
  private hasLeftCurrentPage;
89
- private scrollHandler;
90
70
  private consentMode;
91
71
  private readonly cookielessWhilePending;
92
72
  private readonly cleanupCallbacks;
@@ -95,33 +75,23 @@ declare class WebAnalytics {
95
75
  private errorTracker;
96
76
  private readonly handleVisibilityChange;
97
77
  private readonly handlePageHide;
98
- private readonly handlePopState;
99
- private readonly handleHashChange;
78
+ private readonly handlePageShow;
100
79
  constructor(options: WebAnalyticsOptions);
101
80
  private log;
102
81
  private init;
103
- private registerCleanup;
104
- private addWindowListener;
105
- private addDocumentListener;
106
- private patchHistory;
107
82
  private ensureStarted;
108
- private stopHeartbeat;
109
- private stopNavigationTimer;
110
- private stopChildTrackers;
111
- private registerChildTracker;
83
+ private addListener;
84
+ private patchHistory;
85
+ private notifyChildren;
112
86
  private startChildTracker;
113
- private startErrorTracker;
114
- private startWebVitalsTracker;
115
- private startReplayTracker;
87
+ private startOptionalTrackers;
116
88
  start(): Promise<void>;
117
89
  destroy(): void;
118
- pageview(extra?: Dict): void;
119
- track(name: string, extra?: Dict): void;
90
+ pageview(extra?: Record<string, unknown>): void;
91
+ track(name: string, extra?: Record<string, unknown>): void;
120
92
  identify(externalId: string, email: string, options?: IdentifyOptions): Promise<boolean>;
121
93
  logout(resetAnonymousIdentity?: boolean): void;
122
94
  setConsentMode(mode: ConsentMode): void;
123
- optIn(): void;
124
- optOut(): void;
125
95
  getConsentMode(): ConsentMode;
126
96
  getAnonymousId(): string;
127
97
  getSessionId(): string;
@@ -135,10 +105,9 @@ declare class WebAnalytics {
135
105
  private send;
136
106
  private enterPage;
137
107
  private leavePage;
138
- private trackScroll;
139
108
  private startHeartbeat;
109
+ private stopHeartbeat;
140
110
  private navigate;
141
- private links;
142
111
  }
143
112
  //#endregion
144
- export { type ConsentMode, type FeatureFlagCheckContext, type FeatureFlagEvaluation, type IdentifyOptions, WebAnalytics, type WebAnalyticsOptions, fetchFeatureFlagEvaluation, getInstance, identify, isTrackingDisabled, logout, optIn, optOut, reportError, sendData, setConsentMode, trackEvent };
113
+ export { type ConsentMode, type FeatureFlagEvaluation, type IdentifyOptions, WebAnalytics, type WebAnalyticsOptions, getInstance, identify, isTrackingDisabled, logout, optIn, optOut, reportError, setConsentMode, trackEvent };
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,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};
1
+ import{i as e,n as t,r as n,t as r}from"./chunks/api-urls-nKmJnyjD.js";import{d as i,f as a,i as o,n as s,o as c,p as l,t as u}from"./chunks/send-data-Cb4xlYF0.js";import{n as d,t as f}from"./chunks/identifiers-DrjjHcKB.js";const p=new Set([`browser`,`browser_version`,`device`,`os`,`os_version`,`referrer`,`utm_source`,`utm_medium`,`utm_campaign`,`utm_term`,`utm_content`,`title`,`page`,`url`]);function m(e){let t={},n={};for(let[r,i]of Object.entries(e))(p.has(r)?t:n)[r]=i;return{dimensions:t,properties:n}}const h={instance:null,pendingConsentMode:void 0};function g(){return typeof window>`u`||T()?null:h.instance}function _(){return h.instance}function v(e,t){g()?.track(e,t??{})}function y(e,t,n){return g()?.identify(e,t,n??{})??Promise.resolve(!1)}function b(e=!0){g()?.logout(e)}function x(e){h.instance?h.instance.setConsentMode(e):h.pendingConsentMode=e}function S(){x(`granted`)}function C(){x(`denied`)}function w(e){g()?.reportError(e)}function T(){try{let e=globalThis.localStorage?.getItem(`disable-faststats`);return e===`true`||e===`1`}catch{return!1}}function E(e){for(;e;){if(e instanceof HTMLAnchorElement&&e.href)return e;e=e.parentNode}return null}function D(){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 O=class{webEndpoint;baseUrl;featureFlagsBaseUrl;debug;started=!1;destroyed=!1;pageKey=``;navTimer=null;heartbeatTimer=null;pagePath=``;pageUrl=``;pageHash=``;hasLeftCurrentPage=!1;consentMode;cookielessWhilePending;cleanupCallbacks=[];childTrackers=[];pendingReportedErrors=[];errorTracker=null;handleVisibilityChange=()=>{if(l(this.options.siteKey,this.isCookielessMode()),document.visibilityState===`hidden`){this.notifyChildren(`onPageHidden`),this.stopHeartbeat();return}this.startHeartbeat()};handlePageHide=e=>{this.notifyChildren(`onPageHidden`,e.persisted),e.persisted||this.leavePage()};handlePageShow=e=>{this.notifyChildren(`onPageShow`,e.persisted)};constructor(t){this.options=t,this.baseUrl=n(t.baseUrl),this.featureFlagsBaseUrl=e(t.featureFlagsBaseUrl),this.webEndpoint=`${this.baseUrl}${r.events}`,this.debug=t.debug??!1,this.consentMode=h.pendingConsentMode??t.consent?.mode??`granted`,h.pendingConsentMode=void 0,this.cookielessWhilePending=t.consent?.cookielessWhilePending??!0,(t.autoTrack??!0)&&this.init()}log(e){this.debug&&console.log(`[Analytics] ${e}`)}init(){if(typeof window>`u`||T()){T()&&this.log(`disabled`);return}setTimeout(()=>void this.start(),0)}ensureStarted(){return typeof window>`u`||this.destroyed||T()?!1:(this.started||this.start(),this.started&&!this.destroyed&&h.instance===this)}addListener(e,t,n,r){e.addEventListener(t,n,r),this.cleanupCallbacks.push(()=>e.removeEventListener(t,n,r))}patchHistory(){for(let e of[`pushState`,`replaceState`]){let t=history[e].bind(history);history[e]=(e,n,r)=>{t(e,n,r),this.navigate()},this.cleanupCallbacks.push(()=>{history[e]=t})}}notifyChildren(e,t=!1){for(let n of this.childTrackers)n[e]?.(t)}async startChildTracker(e,t){try{let n=await t();return!this.started||this.destroyed||h.instance!==this||(await Promise.resolve(n.start()),!this.started||this.destroyed||h.instance!==this)?(n.stop?.(),null):(this.childTrackers.push(n),this.log(`${e} loaded`),n)}catch(t){return this.log(`failed to initialize ${e} tracker: ${String(t)}`),null}}startOptionalTrackers(){let e=this.options;if(e.sessionReplays?.enabled??e.trackReplay){let t=e.replayOptions??{};this.startChildTracker(`replay`,async()=>{let{default:n}=await import(`./replay.js`);return new n({siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug,...t,samplingPercentage:u(t.samplingPercentage??e.sessionReplays?.sampling?.percentage),cookieless:this.isCookielessMode()})})}e.trackErrors&&this.startChildTracker(`error`,async()=>{let{default:t}=await import(`./error.js`);return new t({siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug,sdkName:e.sdkName,sdkVersion:e.sdkVersion})}).then(e=>{if(e){this.errorTracker=e;for(let t of this.pendingReportedErrors.splice(0))e.captureError(t)}}),(e.trackWebVitals??e.webVitals?.enabled)&&this.startChildTracker(`web-vitals`,async()=>{let{default:t}=await import(`./web-vitals.js`);return new t({siteKey:e.siteKey,baseUrl:this.baseUrl,debug:this.debug,samplingPercentage:u(e.webVitals?.sampling?.percentage),attribution:e.webVitals?.attribution??!1})})}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(T()){this.log(`disabled`);return}this.started=!0,h.instance=this,a(this.isCookielessMode()),o(),this.startOptionalTrackers(),this.enterPage(),this.pageview({trigger:`load`}),this.startHeartbeat();let e=e=>{let t=E(e.target);t&&t.host!==location.host&&this.track(`outbound_link`,{outbound_link:t.href})};this.addListener(document,`click`,e),this.addListener(document,`auxclick`,e),this.addListener(document,`visibilitychange`,this.handleVisibilityChange),this.addListener(window,`pagehide`,this.handlePageHide),this.addListener(window,`pageshow`,this.handlePageShow),this.addListener(window,`popstate`,()=>this.navigate()),this.options.trackHash&&this.addListener(window,`hashchange`,()=>this.navigate()),this.patchHistory()}destroy(){if(!this.destroyed){this.started&&typeof window<`u`&&this.leavePage(),this.pendingReportedErrors.length=0,this.navTimer&&clearTimeout(this.navTimer),this.stopHeartbeat();for(let e of this.cleanupCallbacks.splice(0))e();for(let e of this.childTrackers.splice(0))e.stop?.();this.errorTracker=null,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={}){if(!this.ensureStarted())return;let n=e.trim();n&&this.send(n,t)}identify(e,t,n={}){if(!this.ensureStarted()||this.isCookielessMode())return Promise.resolve(!1);let i=e.trim(),a=t.trim();return!i||!a?Promise.resolve(!1):s({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.ensureStarted()&&(e&&d(this.isCookielessMode()),i(this.options.siteKey))}setConsentMode(e){this.consentMode=e;let t=this.isCookielessMode();a(t);for(let e of this.childTrackers)e.setCookielessMode?.(t)}getConsentMode(){return this.consentMode}getAnonymousId(){return f(this.isCookielessMode())}getSessionId(){return o()}getWindowId(){return c(this.options.siteKey,this.isCookielessMode()).windowId}async checkFeatureFlag(e,t,n){if(typeof window>`u`||T())return{value:`false`};let r=n?.externalId?.trim(),i=this.getAnonymousId();if(!r&&!i)return{value:`false`};let{fetchFeatureFlagEvaluation:a}=await import(`./feature-flags.js`);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.ensureStarted()||!(this.options.trackErrors??!1))){if(this.errorTracker){this.errorTracker.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,n={}){if(typeof window>`u`||this.destroyed||T())return;let r=this.isCookielessMode(),i=f(r),a=c(this.options.siteKey,r),{dimensions:o,properties:l}=m(n);this.log(e),s({url:this.webEndpoint,data:JSON.stringify({token:this.options.siteKey,...i?{userId:i}:{},sessionId:a.sessionId,event:e,...t(),...D(),...o,properties:l}),contentType:`text/plain`,debug:this.debug,debugPrefix:`[Analytics] ${e}`})}enterPage(){this.pagePath=location.pathname,this.pageUrl=location.href,this.pageHash=location.hash,this.hasLeftCurrentPage=!1}leavePage(){if(this.destroyed||this.hasLeftCurrentPage)return;this.hasLeftCurrentPage=!0;let e=c(this.options.siteKey,this.isCookielessMode());this.send(`page_leave`,{page:this.pagePath,url:this.pageUrl,session_duration:Date.now()-e.sessionStart})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(document.visibilityState===`hidden`){this.stopHeartbeat();return}l(this.options.siteKey,this.isCookielessMode())},300*1e3)}stopHeartbeat(){this.heartbeatTimer&&=(clearInterval(this.heartbeatTimer),null)}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.pagePath&&(!e||location.hash===this.pageHash))){for(let e of this.childTrackers)e.trackPageChange?.(location.href);this.leavePage(),this.enterPage(),this.pageview({trigger:`navigation`})}},300))}};export{O as WebAnalytics,_ as getInstance,y as identify,T as isTrackingDisabled,b as logout,S as optIn,C as optOut,w as reportError,x as setConsentMode,v as trackEvent};
package/dist/replay.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-DvJYurEC.js";
2
- export { type ReplayTrackerOptions, ReplayTracker as default };
1
+ import { n as ReplayTrackerOptions, t as ReplayTracker } from "./chunks/replay-DR_T0Iz4.js";
2
+ export { ReplayTrackerOptions, ReplayTracker as default };
package/dist/replay.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./chunks/replay-rTqcjOo2.js";export{e as default};
1
+ import{r as e,t}from"./chunks/api-urls-nKmJnyjD.js";import{c as n,n as r,o as i,p as a,r as o,s,t as c,u as l}from"./chunks/send-data-Cb4xlYF0.js";import{t as u}from"./chunks/identifiers-DrjjHcKB.js";import{record as d}from"@rrweb/record";const f={mousemove:50,mouseInteraction:!0,scroll:150,media:800,input:`last`};function p(e){return`faststats_replay_sampled_${e}`}function m(e,t,r){let a=c(t);if(a>=100)return!0;if(a<=0)return!1;let o=i(e,r).sessionId,s=p(e),l=`${o}:${a}`;try{let e=sessionStorage;if(e){let t=e.getItem(s);if(t===l)return!0;if(t?.startsWith(`${o}:`))return!1}}catch{}let u=n(o)%100<a;try{sessionStorage?.setItem(s,u?l:`${o}:out`)}catch{}return u}var h=class{endpoint;compressionSupported=typeof window<`u`&&`CompressionStream`in window;sampled;events=[];pending=[];pendingSizeBytes=0;viewId=o();chunkStartedAt=0;started=!1;startTime=0;sequence=0;intervalId=null;flushTask=null;retryTask=null;minLengthFlushTask=null;stopRecording;sending=!1;unsubscribeRotation;cookieless;constructor(n){this.options=n,this.endpoint=`${e(n.baseUrl)}${t.replay}`,this.cookieless=n.cookieless??!1,this.sampled=m(n.siteKey,n.samplingPercentage??100,this.cookieless)}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}log(...e){this.options.debug&&console.log(`[Replay]`,...e)}sessionContext(){return i(this.options.siteKey,this.cookieless)}setCookielessMode(e){this.cookieless!==e&&(this.cookieless=e,e&&(this.events.length=0,this.pending.length=0,this.pendingSizeBytes=0,this.flushTask&&clearTimeout(this.flushTask),this.retryTask&&clearTimeout(this.retryTask),this.minLengthFlushTask&&clearTimeout(this.minLengthFlushTask),this.flushTask=null,this.retryTask=null,this.minLengthFlushTask=null),this.startTime=s(this.cookieless),this.resetChunk())}resetChunk(){this.chunkStartedAt=Date.now()}start(){this.started||typeof window>`u`||!this.sampled||(this.started=!0,this.viewId=o(),this.startTime=s(this.cookieless),this.resetChunk(),this.unsubscribeRotation=l(e=>{this.onSessionRotated(e)}),this.beginRecording(),this.intervalId=setInterval(this.requestFlush,this.flushInterval),window.addEventListener(`beforeunload`,this.onUnload),this.log(`Recording started`))}trackPageChange(e){if(!this.started)return;let t=e??window.location.href;this.viewId=o(),this.resetChunk();let n={type:5,timestamp:Date.now(),data:{tag:`faststats:view`,payload:{href:t,viewId:this.viewId}}};this.onEvent(n,!1)}onPageHidden(e=!1){e||this.flush(!0,void 0,!0)}onPageShow(e=!1){!e||!this.started||this.pending.length>0&&this.flush(!1)}async beginRecording(){let e=this.options.recordConsole??!1?await import(`@rrweb/rrweb-plugin-console-record`):null;if(!this.started)return;let t=[];e&&t.push(e.getRecordConsolePlugin()),this.stopRecording=d({emit:this.onEvent,sampling:this.options.sampling??f,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),!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`)}}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===2&&this.hasReachedMinLength()){this.requestFlush();return}this.scheduleMinLengthFlush()};onUnload=()=>{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=u(this.cookieless),i=this.sequence++,a=Date.now(),o=this.chunkStartedAt,s={token:this.options.siteKey,sessionId:t.sessionId,windowId:t.windowId,viewId:this.viewId,sessionStart:t.sessionStart,chunkStartedAt:o,chunkEndedAt:a,...r?{identifier:r}:{},batchId:`${t.sessionId}-${i}-${o}`,sequence:i,timestamp:a,url:window.location.href,...n?{isFinal:!0}:{},events:e};return this.resetChunk(),s}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 flush(e,t,n){if(this.sending)return;let r=t?null:a(this.options.siteKey,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 i=t??this.sessionContext();if(this.events.length>0)if(!this.hasReachedMinLength())this.scheduleMinLengthFlush();else{let e=this.createBatch(this.events.splice(0),i,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;if(!await this.sendBatch(t,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 sendBatch(e,t){let n=JSON.stringify(e),i={debug:!1,useBeacon:t,keepalive:t};if((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)}%)`),r({url:`${this.endpoint}?encoding=gzip`,data:t,contentType:`application/octet-stream`,...i})??Promise.resolve(!1)}catch{this.log(`Compression failed, using uncompressed`)}return r({url:this.endpoint,data:n,contentType:`application/json`,...i})??Promise.resolve(!1)}};export{h as default};
@@ -10,20 +10,17 @@ declare class WebVitalsTracker {
10
10
  private readonly options;
11
11
  private readonly endpoint;
12
12
  private readonly sampled;
13
- private readonly metrics;
13
+ private metrics;
14
14
  private started;
15
+ private flushing;
15
16
  private url;
16
17
  constructor(options: WebVitalsOptions);
17
- private get debug();
18
- private log;
19
18
  start(): Promise<void>;
20
19
  stop(): void;
20
+ onPageHidden(persisted?: boolean): void;
21
21
  trackPageChange(url?: string): void;
22
- private onHidden;
23
- private onPageHide;
24
- private capture;
22
+ private onMetric;
25
23
  private flush;
26
- private removeListeners;
27
24
  }
28
25
  //#endregion
29
- export { type WebVitalsOptions, WebVitalsTracker as default };
26
+ export { WebVitalsOptions, WebVitalsTracker as default };
@@ -1 +1 @@
1
- import{t as e}from"./chunks/web-vitals-Be-Cg4Po.js";export{e as default};
1
+ import{r as e,t}from"./chunks/api-urls-nKmJnyjD.js";import{c as n,i as r,n as i,t as a}from"./chunks/send-data-Cb4xlYF0.js";var o=class{endpoint;sampled;metrics=new Map;started=!1;flushing=!1;url=``;constructor(i){this.options=i,this.endpoint=`${e(i.baseUrl)}${t.vitals}`;let o=a(i.samplingPercentage);this.sampled=o>=100||o>0&&n(r())%100<o}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,i({url:this.endpoint,data:JSON.stringify({token:this.options.siteKey,sessionId:r(),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{o as default};
package/package.json CHANGED
@@ -35,11 +35,14 @@
35
35
  }
36
36
  },
37
37
  "type": "module",
38
+ "files": [
39
+ "dist"
40
+ ],
38
41
  "sideEffects": false,
39
42
  "publishConfig": {
40
43
  "access": "public"
41
44
  },
42
- "version": "0.2.14",
45
+ "version": "0.3.1",
43
46
  "scripts": {
44
47
  "build": "tsdown && bun run check-size",
45
48
  "dev": "bun run build",
@@ -54,10 +57,8 @@
54
57
  "typescript": "^5.9.3"
55
58
  },
56
59
  "dependencies": {
57
- "@rrweb/rrweb-plugin-console-record": "^2.0.0-alpha.20",
58
- "@rrweb/types": "^2.0.0-alpha.20",
59
- "rrweb": "^2.0.0-alpha.4",
60
- "rrweb-snapshot": "^2.0.0-alpha.4",
61
- "web-vitals": "^5.2.0"
60
+ "@rrweb/rrweb-plugin-console-record": "^2.0.1",
61
+ "@rrweb/record": "^2.0.1",
62
+ "web-vitals": "^5.3.0"
62
63
  }
63
64
  }
package/CHANGELOG.md DELETED
@@ -1,184 +0,0 @@
1
- # @faststats/web
2
-
3
- ## 0.2.14
4
-
5
- ### Patch Changes
6
-
7
- - bebbb67: chore: update web-vitals to 5.2.0
8
- - ab51be7: fix: tag replay batches with per-tab window and page ids instead of rrweb sequential ids
9
-
10
- ## 0.2.13
11
-
12
- ### Patch Changes
13
-
14
- - 28fb1ce: chore: provide session_id to flag validation service
15
-
16
- ## 0.2.12
17
-
18
- ### Patch Changes
19
-
20
- - d96a750: fix: refreshSessionTimestamp on replay page hide
21
-
22
- ## 0.2.11
23
-
24
- ### Patch Changes
25
-
26
- - 754b67f: fix(replays): dedupe secquences to reduce risk of duplicate data sending
27
- - d21ce42: refactor: more reliable and unified data sending
28
-
29
- ## 0.2.10
30
-
31
- ## 0.2.9
32
-
33
- ### Patch Changes
34
-
35
- - dd3bbcb: fix: make identify call async
36
-
37
- ## 0.2.8
38
-
39
- ### Patch Changes
40
-
41
- - 5d0afa5: perf: shrink bundle and improve treeshaking
42
-
43
- - mark package as side-effect free (`"sideEffects": false`)
44
- - add subpath exports: `@faststats/web/feature-flags`, `/replay`, `/error`, `/web-vitals`
45
- - lazy-load `fetchFeatureFlagEvaluation` from `checkFeatureFlag`
46
- - default web-vitals to the core build; opt into attribution via `webVitals.attribution: true`
47
- - dynamically import rrweb sequential-id and console plugins (console only when `recordConsole !== false`)
48
- - import `EventType` from `@rrweb/types` instead of the rrweb barrel so consumer bundlers can prune the playback engine, packer, and replay-side console plugin
49
- - move `@rrweb/types` from devDependencies to dependencies (now a runtime import)
50
- - main entry filename is now `dist/index.js` (was `dist/module.js`); the public entry no longer re-exports `featureFlagsCheckUrl` / `normalizeFeatureFlagsBaseUrl`
51
- - per-entry raw + gzip budgets enforced by `scripts/check-bundle-size.mjs`
52
-
53
- - cdf521f: chore: report sdk name and version for error tracking
54
- - a844fed: fix: enable compression for replays by default
55
-
56
- ## 0.2.7
57
-
58
- ### Patch Changes
59
-
60
- - 08f3719: fix: don't rotate session_id while replay
61
-
62
- ## 0.2.6
63
-
64
- ### Patch Changes
65
-
66
- - 7d57d50: fix: replay flushing issues
67
-
68
- ## 0.2.5
69
-
70
- ### Patch Changes
71
-
72
- - dd932a0: fix: replay config mismatch
73
-
74
- ## 0.2.4
75
-
76
- ### Patch Changes
77
-
78
- - 547db41: fix: resolve old type issues
79
-
80
- ## 0.2.3
81
-
82
- ### Patch Changes
83
-
84
- - 3371933: fix: use identifier rather then server_id
85
-
86
- ## 0.2.2
87
-
88
- ### Patch Changes
89
-
90
- - 9d7369d: fix: remove useless evaluation object from response
91
- - 7b79f71: fix: use header over body for project token
92
- - 7317c3c: fix: remove useless enabled propery
93
-
94
- ## 0.2.1
95
-
96
- ### Patch Changes
97
-
98
- - d80a042: fix: use new check endpoint
99
-
100
- ## 0.2.0
101
-
102
- ### Minor Changes
103
-
104
- - 55032f8: feat: add feature flags
105
-
106
- ### Patch Changes
107
-
108
- - 98385da: refactor: reduce bundle size and make results more stable
109
-
110
- ## 0.1.9
111
-
112
- ### Patch Changes
113
-
114
- - b9f489f: fix racecondition because of gzip
115
-
116
- ## 0.1.8
117
-
118
- ### Patch Changes
119
-
120
- - 29dbdea: add initial snapshot metadata
121
-
122
- ## 0.1.7
123
-
124
- ### Patch Changes
125
-
126
- - 7d6d563: fix: better sending
127
-
128
- ## 0.1.6
129
-
130
- ### Patch Changes
131
-
132
- - 48a1008: refactor: perf & bulletproof parts of the core sdk
133
-
134
- ## 0.1.5
135
-
136
- ### Patch Changes
137
-
138
- - f7347cd: fix: Improve replay flushing
139
-
140
- ## 0.1.4
141
-
142
- ### Patch Changes
143
-
144
- - 376922e: updates
145
-
146
- ## 0.1.3
147
-
148
- ## 0.1.2
149
-
150
- ### Patch Changes
151
-
152
- - 5d1cc90: fix: enforce proper minimum duration of 3 seconds
153
-
154
- ## 0.1.1
155
-
156
- ### Patch Changes
157
-
158
- - 2326d00: fix: some cleanup
159
-
160
- ## 0.1.0
161
-
162
- ### Minor Changes
163
-
164
- - c63d783: Remove all window globals; use module-level instance and dependency injection. Add dynamic imports for ErrorTracker, WebVitalsTracker, ReplayTracker (tree-shakable). Export identify, logout, setConsentMode, optIn, optOut, getInstance from @faststats/web. React package now uses getInstance instead of window.
165
-
166
- ## 0.0.4
167
-
168
- ### Patch Changes
169
-
170
- - 93393c0: Remove redundant isTrackingDisabled checks from sub-trackers (ErrorTracker, WebVitalsTracker, ReplayTracker).
171
- Simplify web vitals config - single source of truth (trackWebVitals ?? webVitals?.enabled ?? hasWebVitalsSampling).
172
- Fix custom events via trackEvent: set window.\_\_FA_webAnalyticsInstance in init() so it works before async start() completes.
173
-
174
- ## 0.0.3
175
-
176
- ### Patch Changes
177
-
178
- - bb3dcd1: ESM only for now
179
-
180
- ## 0.0.2
181
-
182
- ### Patch Changes
183
-
184
- - f1f66de: feat: add track event function