vyzora-sdk 0.1.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.
- package/README.md +73 -0
- package/dist/index.d.mts +60 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @vyzora/sdk
|
|
2
|
+
|
|
3
|
+
> Lightweight, production-grade analytics SDK for Vyzora. Framework agnostic, under 7kb minified, and built for reliability.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Framework Agnostic**: Works with Vanilla JS, React, Next.js, Vue, and any SPA.
|
|
8
|
+
- **Lightweight**: < 7KB minified (~1.9KB gzipped) with zero external dependencies.
|
|
9
|
+
- **Resilient Batching**: Automatically batches events and flushes them intelligently to reduce network overhead.
|
|
10
|
+
- **Smart Transport**: Uses `navigator.sendBeacon` for reliable tracking on page unload, with `fetch(keepalive)` fallback.
|
|
11
|
+
- **Auto-Tracking**: Automatically collects environment metadata (Browser, OS, Screen) and tracks SPA page transitions.
|
|
12
|
+
- **Privacy First**: Explicit opt-in (disabled by default) and no tracking until initialized with `enabled: true`.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @vyzora/sdk
|
|
18
|
+
# or
|
|
19
|
+
yarn add @vyzora/sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Simple Initialization
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { Vyzora } from '@vyzora/sdk';
|
|
28
|
+
|
|
29
|
+
const vyzora = new Vyzora({
|
|
30
|
+
apiKey: 'your_project_api_key',
|
|
31
|
+
enabled: true, // Required to activate tracking
|
|
32
|
+
debug: process.env.NODE_ENV === 'development'
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Tracking Custom Events
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
vyzora.track('purchase_completed', {
|
|
40
|
+
amount: 49.99,
|
|
41
|
+
currency: 'USD',
|
|
42
|
+
item: 'Pro Subscription'
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Manual Pageviews
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
vyzora.pageview('/custom-path');
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Identity Management
|
|
53
|
+
|
|
54
|
+
Link anonymous events to a known user ID:
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
vyzora.identify('user_123456');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuration Options
|
|
61
|
+
|
|
62
|
+
| Option | Type | Default | Description |
|
|
63
|
+
|--------|------|---------|-------------|
|
|
64
|
+
| `apiKey` | `string` | **Required** | Your project's 64-character API key. |
|
|
65
|
+
| `enabled` | `boolean` | `false` | Must be `true` to active the SDK. |
|
|
66
|
+
| `endpoint` | `string` | `https://api.vyzora.io/api/ingest` | Backend ingest URL. |
|
|
67
|
+
| `batchSize` | `number` | `20` | Max events per batch before flushing. |
|
|
68
|
+
| `flushInterval`| `number` | `10000` | Auto-flush interval in milliseconds. |
|
|
69
|
+
| `debug` | `boolean` | `false` | Enable console logging for help in development. |
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT © [Vyzora](https://vyzora.io)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
interface VyzoraConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
batchSize?: number;
|
|
7
|
+
flushInterval?: number;
|
|
8
|
+
}
|
|
9
|
+
interface AutoMetadata {
|
|
10
|
+
browser?: string;
|
|
11
|
+
browserVersion?: string;
|
|
12
|
+
os?: string;
|
|
13
|
+
deviceType?: 'desktop' | 'mobile' | 'tablet' | 'unknown';
|
|
14
|
+
screenWidth?: number;
|
|
15
|
+
screenHeight?: number;
|
|
16
|
+
language?: string;
|
|
17
|
+
referrer?: string;
|
|
18
|
+
timezone?: string;
|
|
19
|
+
[key: string]: unknown | undefined;
|
|
20
|
+
}
|
|
21
|
+
interface InternalEvent {
|
|
22
|
+
sessionId: string;
|
|
23
|
+
visitorId: string;
|
|
24
|
+
eventType: string;
|
|
25
|
+
path: string;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
interface IngestEvent {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
visitorId: string;
|
|
31
|
+
eventType: string;
|
|
32
|
+
path: string;
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
interface IngestPayload {
|
|
36
|
+
apiKey: string;
|
|
37
|
+
events: IngestEvent[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare class Vyzora {
|
|
41
|
+
private readonly apiKey;
|
|
42
|
+
private readonly endpoint;
|
|
43
|
+
private readonly enabled;
|
|
44
|
+
private readonly debug;
|
|
45
|
+
private queue;
|
|
46
|
+
private customVisitorId;
|
|
47
|
+
private logger;
|
|
48
|
+
private lastTrackedPath;
|
|
49
|
+
constructor(config: VyzoraConfig);
|
|
50
|
+
track(eventType: string, metadata?: Record<string, unknown>): void;
|
|
51
|
+
pageview(path?: string): void;
|
|
52
|
+
identify(visitorId: string): void;
|
|
53
|
+
flush(): Promise<void>;
|
|
54
|
+
resetSession(): void;
|
|
55
|
+
destroy(): void;
|
|
56
|
+
private hookPageTracking;
|
|
57
|
+
private wrapHistoryMethod;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { type AutoMetadata, type IngestPayload, type InternalEvent, Vyzora, type VyzoraConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
interface VyzoraConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
batchSize?: number;
|
|
7
|
+
flushInterval?: number;
|
|
8
|
+
}
|
|
9
|
+
interface AutoMetadata {
|
|
10
|
+
browser?: string;
|
|
11
|
+
browserVersion?: string;
|
|
12
|
+
os?: string;
|
|
13
|
+
deviceType?: 'desktop' | 'mobile' | 'tablet' | 'unknown';
|
|
14
|
+
screenWidth?: number;
|
|
15
|
+
screenHeight?: number;
|
|
16
|
+
language?: string;
|
|
17
|
+
referrer?: string;
|
|
18
|
+
timezone?: string;
|
|
19
|
+
[key: string]: unknown | undefined;
|
|
20
|
+
}
|
|
21
|
+
interface InternalEvent {
|
|
22
|
+
sessionId: string;
|
|
23
|
+
visitorId: string;
|
|
24
|
+
eventType: string;
|
|
25
|
+
path: string;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
interface IngestEvent {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
visitorId: string;
|
|
31
|
+
eventType: string;
|
|
32
|
+
path: string;
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
interface IngestPayload {
|
|
36
|
+
apiKey: string;
|
|
37
|
+
events: IngestEvent[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare class Vyzora {
|
|
41
|
+
private readonly apiKey;
|
|
42
|
+
private readonly endpoint;
|
|
43
|
+
private readonly enabled;
|
|
44
|
+
private readonly debug;
|
|
45
|
+
private queue;
|
|
46
|
+
private customVisitorId;
|
|
47
|
+
private logger;
|
|
48
|
+
private lastTrackedPath;
|
|
49
|
+
constructor(config: VyzoraConfig);
|
|
50
|
+
track(eventType: string, metadata?: Record<string, unknown>): void;
|
|
51
|
+
pageview(path?: string): void;
|
|
52
|
+
identify(visitorId: string): void;
|
|
53
|
+
flush(): Promise<void>;
|
|
54
|
+
resetSession(): void;
|
|
55
|
+
destroy(): void;
|
|
56
|
+
private hookPageTracking;
|
|
57
|
+
private wrapHistoryMethod;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { type AutoMetadata, type IngestPayload, type InternalEvent, Vyzora, type VyzoraConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
'use strict';/* @vyzora/sdk - lightweight analytics - MIT license */
|
|
2
|
+
var L=Object.defineProperty;var x=Object.getOwnPropertySymbols;var P=Object.prototype.hasOwnProperty,V=Object.prototype.propertyIsEnumerable;var w=(t,e,i)=>e in t?L(t,e,{enumerable:true,configurable:true,writable:true,value:i}):t[e]=i,g=(t,e)=>{for(var i in e||(e={}))P.call(e,i)&&w(t,i,e[i]);if(x)for(var i of x(e))V.call(e,i)&&w(t,i,e[i]);return t};async function b(t,e,i,n,r){if(i.length===0)return;let s=JSON.stringify({apiKey:e,events:i}),u={"Content-Type":"application/json"};if(typeof navigator!="undefined"&&typeof navigator.sendBeacon=="function"){let l=new Blob([s],{type:"application/json"});if(navigator.sendBeacon(t,l)){r.log("Batch sent via sendBeacon",{count:i.length});return}}await h(t,s,u,n,r);}async function h(t,e,i,n,r,o=0){try{let s=await fetch(t,{method:"POST",headers:i,body:e,keepalive:!0});r.log(`Batch flush (attempt ${o+1}) \u2192`,s.status),!s.ok&&o===0&&setTimeout(()=>h(t,e,i,n,r,1),2e3);}catch(s){o===0&&setTimeout(()=>h(t,e,i,n,r,1),2e3);}}var a=class{constructor(e){this.events=[];this.timer=null;this.handleVisibility=()=>{document.visibilityState==="hidden"&&this.flush();};this.handlePageHide=()=>{this.flush();};this.endpoint=e.endpoint,this.apiKey=e.apiKey,this.batchSize=e.batchSize,this.flushInterval=e.flushInterval,this.debug=e.debug,this.logger=e.logger;}start(){this.timer===null&&(this.timer=setInterval(()=>{this.logger.log("Auto-flush triggered"),this.flush();},this.flushInterval),typeof document!="undefined"&&document.addEventListener("visibilitychange",this.handleVisibility),typeof window!="undefined"&&window.addEventListener("pagehide",this.handlePageHide));}push(e){this.events.push(e),this.logger.log(`Event queued: ${e.eventType} (queue=${this.events.length})`),this.events.length>=this.batchSize&&this.flush();}async flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.events.length);this.logger.log(`Flushing ${e.length} event(s)`),await b(this.endpoint,this.apiKey,e,this.debug,this.logger);}destroy(){this.timer!==null&&(clearInterval(this.timer),this.timer=null),typeof document!="undefined"&&document.removeEventListener("visibilitychange",this.handleVisibility),typeof window!="undefined"&&window.removeEventListener("pagehide",this.handlePageHide),this.flush();}};var S="vyzora_visitor_id";function I(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return (t==="x"?e:e&3|8).toString(16)})}function c(){try{let t=localStorage.getItem(S);return t||(t=I(),localStorage.setItem(S,t)),t}catch(t){return I()}}var p="vyzora_session_id",f="vyzora_session_ts";function E(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return (t==="x"?e:e&3|8).toString(16)})}function T(){return Date.now()}function v(){var t;try{let e=parseInt((t=sessionStorage.getItem(f))!=null?t:"0",10),i=T()-e>18e5,n=sessionStorage.getItem(p);return (!n||i)&&(n=E(),sessionStorage.setItem(p,n)),sessionStorage.setItem(f,String(T())),n}catch(e){return E()}}function _(){try{sessionStorage.removeItem(p),sessionStorage.removeItem(f);}catch(t){}}function k(t){let e=[[/Edg\/(\S+)/,"Edge"],[/OPR\/(\S+)/,"Opera"],[/SamsungBrowser\/(\S+)/,"Samsung"],[/Firefox\/(\S+)/,"Firefox"],[/Chrome\/(\S+)/,"Chrome"],[/Safari\/(\S+)/,"Safari"]];for(let[i,n]of e){let r=t.match(i);if(r)return {browser:n,version:r[1].split(".")[0]}}return {browser:"Unknown",version:""}}function A(t){return /Windows NT/i.test(t)?"Windows":/Mac OS X/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}function M(t){return /Mobi/i.test(t)?"mobile":/Tablet|iPad/i.test(t)?"tablet":"desktop"}function y(){var t,e,i,n,r,o;if(typeof window=="undefined"||typeof navigator=="undefined")return {};try{let s=navigator.userAgent,{browser:u,version:l}=k(s);return {browser:u,browserVersion:l,os:A(s),deviceType:M(s),screenWidth:(t=window.screen)==null?void 0:t.width,screenHeight:(e=window.screen)==null?void 0:e.height,language:navigator.language,referrer:document.referrer||void 0,timezone:(o=(r=(i=Intl==null?void 0:Intl.DateTimeFormat)==null?void 0:(n=i.call(Intl)).resolvedOptions)==null?void 0:r.call(n))==null?void 0:o.timeZone}}catch(s){return {}}}var d=class{constructor(e=false){this.debug=e;}log(e,...i){this.debug&&console.warn(`[Vyzora] ${e}`,...i);}warn(e,...i){console.warn(`[Vyzora] ${e}`,...i);}error(e,...i){console.error(`[Vyzora] ${e}`,...i);}};var U="http://localhost:3001/api/ingest",z=20,D=1e4,m=class{constructor(e){this.queue=null;this.customVisitorId=null;this.lastTrackedPath=null;var i,n,r,o;if(!e.apiKey)throw new Error("[Vyzora] apiKey is required.");if(this.apiKey=e.apiKey,this.endpoint=(i=e.endpoint)!=null?i:U,this.enabled=e.enabled===true,this.debug=(n=e.debug)!=null?n:false,this.logger=new d(this.debug),!this.enabled){this.logger.log("SDK is disabled. Set enabled: true to activate.");return}typeof window!="undefined"&&(this.queue=new a({endpoint:this.endpoint,apiKey:this.apiKey,batchSize:(r=e.batchSize)!=null?r:z,flushInterval:(o=e.flushInterval)!=null?o:D,debug:this.debug,logger:this.logger}),this.queue.start(),this.hookPageTracking(),this.logger.log("SDK initialised."));}track(e,i){var n;if(!(!this.enabled||!this.queue))try{let r=y(),o=g(g({},r),i);this.queue.push({sessionId:v(),visitorId:(n=this.customVisitorId)!=null?n:c(),eventType:e,path:typeof window!="undefined"?window.location.pathname:"/",metadata:Object.keys(o).length>0?o:void 0});}catch(r){}}pageview(e){var i;if(!(!this.enabled||!this.queue))try{let n=e!=null?e:typeof window!="undefined"?window.location.pathname:"/";if(n===this.lastTrackedPath)return;this.lastTrackedPath=n;let r=y();this.queue.push({sessionId:v(),visitorId:(i=this.customVisitorId)!=null?i:c(),eventType:"pageview",path:n,metadata:Object.keys(r).length>0?r:void 0});}catch(n){}}identify(e){this.enabled&&(this.customVisitorId=e,this.logger.log("Visitor identified:",e));}async flush(){!this.enabled||!this.queue||await this.queue.flush();}resetSession(){_();}destroy(){var e;(e=this.queue)==null||e.destroy(),this.queue=null;}hookPageTracking(){typeof window!="undefined"&&(window.addEventListener("load",()=>this.pageview(),{once:true}),this.wrapHistoryMethod("pushState"),this.wrapHistoryMethod("replaceState"),window.addEventListener("popstate",()=>this.pageview()));}wrapHistoryMethod(e){var n;let i=(n=history[e])==null?void 0:n.bind(history);typeof i=="function"&&(history[e]=(...r)=>{i(...r),this.pageview();});}};
|
|
3
|
+
exports.Vyzora=m;//# sourceMappingURL=index.js.map
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/visitor.ts","../src/session.ts","../src/metadata.ts","../src/logger.ts","../src/core.ts"],"names":["sendBatch","endpoint","apiKey","events","debug","logger","body","headers","blob","fetchWithRetry","attempt","res","e","Queue","opts","event","batch","VISITOR_KEY","generateUUID","c","r","getVisitorId","id","SESSION_KEY","SESSION_TS_KEY","now","getSessionId","_a","lastTs","expired","resetSession","detectBrowser","ua","rules","re","name","m","detectOS","detectDevice","collectMetadata","_b","_c","_d","_e","_f","browser","version","Logger","message","args","DEFAULT_ENDPOINT","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL","Vyzora","config","eventType","metadata","autoMeta","merged","__spreadValues","path","resolvedPath","visitorId","method","original"],"mappings":"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","file":"index.js","sourcesContent":["import type { InternalEvent, IngestPayload } from './types';\r\nimport type { Logger } from './logger';\r\n\r\nconst RETRY_DELAY_MS = 2000;\r\n\r\nexport async function sendBatch(\r\n endpoint: string,\r\n apiKey: string,\r\n events: InternalEvent[],\r\n debug: boolean,\r\n logger: Logger\r\n): Promise<void> {\r\n if (events.length === 0) return;\r\n\r\n const payload: IngestPayload = { apiKey, events };\r\n const body = JSON.stringify(payload);\r\n const headers = { 'Content-Type': 'application/json' };\r\n\r\n if (\r\n typeof navigator !== 'undefined' &&\r\n typeof navigator.sendBeacon === 'function'\r\n ) {\r\n const blob = new Blob([body], { type: 'application/json' });\r\n const sent = navigator.sendBeacon(endpoint, blob);\r\n if (sent) {\r\n logger.log('Batch sent via sendBeacon', { count: events.length });\r\n return;\r\n }\r\n }\r\n\r\n await fetchWithRetry(endpoint, body, headers, debug, logger);\r\n}\r\n\r\nasync function fetchWithRetry(\r\n endpoint: string,\r\n body: string,\r\n headers: Record<string, string>,\r\n debug: boolean,\r\n logger: Logger,\r\n attempt = 0\r\n): Promise<void> {\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: 'POST',\r\n headers,\r\n body,\r\n keepalive: true,\r\n });\r\n\r\n logger.log(`Batch flush (attempt ${attempt + 1}) →`, res.status);\r\n\r\n if (!res.ok && attempt === 0) {\r\n setTimeout(\r\n () => fetchWithRetry(endpoint, body, headers, debug, logger, 1),\r\n RETRY_DELAY_MS\r\n );\r\n }\r\n } catch {\r\n if (attempt === 0) {\r\n setTimeout(\r\n () => fetchWithRetry(endpoint, body, headers, debug, logger, 1),\r\n RETRY_DELAY_MS\r\n );\r\n }\r\n }\r\n}\r\n","import type { InternalEvent } from './types';\r\nimport { sendBatch } from './transport';\r\nimport { Logger } from './logger';\r\n\r\nexport class Queue {\r\n private events: InternalEvent[] = [];\r\n private timer: ReturnType<typeof setInterval> | null = null;\r\n private endpoint: string;\r\n private apiKey: string;\r\n private batchSize: number;\r\n private flushInterval: number;\r\n private debug: boolean;\r\n private logger: Logger;\r\n\r\n constructor(opts: {\r\n endpoint: string;\r\n apiKey: string;\r\n batchSize: number;\r\n flushInterval: number;\r\n debug: boolean;\r\n logger: Logger;\r\n }) {\r\n this.endpoint = opts.endpoint;\r\n this.apiKey = opts.apiKey;\r\n this.batchSize = opts.batchSize;\r\n this.flushInterval = opts.flushInterval;\r\n this.debug = opts.debug;\r\n this.logger = opts.logger;\r\n }\r\n\r\n start(): void {\r\n if (this.timer !== null) return;\r\n this.timer = setInterval(() => {\r\n // console.warn(\"INTERVAL TRIGGERED\");\r\n this.logger.log('Auto-flush triggered');\r\n void this.flush();\r\n }, this.flushInterval);\r\n\r\n if (typeof document !== 'undefined') {\r\n document.addEventListener('visibilitychange', this.handleVisibility);\r\n }\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('pagehide', this.handlePageHide);\r\n }\r\n }\r\n\r\n push(event: InternalEvent): void {\r\n this.events.push(event);\r\n // console.warn(\"EVENT PUSHED. Queue length:\", this.events.length);\r\n\r\n this.logger.log(`Event queued: ${event.eventType} (queue=${this.events.length})`);\r\n if (this.events.length >= this.batchSize) {\r\n void this.flush();\r\n }\r\n }\r\n\r\n async flush(): Promise<void> {\r\n if (this.events.length === 0) return;\r\n const batch = this.events.splice(0, this.events.length);\r\n this.logger.log(`Flushing ${batch.length} event(s)`);\r\n await sendBatch(this.endpoint, this.apiKey, batch, this.debug, this.logger);\r\n }\r\n\r\n destroy(): void {\r\n // console.warn(\"⚠️ SDK QUEUE DESTROY CALLED\");\r\n\r\n if (this.timer !== null) {\r\n clearInterval(this.timer);\r\n this.timer = null;\r\n }\r\n if (typeof document !== 'undefined') {\r\n document.removeEventListener('visibilitychange', this.handleVisibility);\r\n }\r\n if (typeof window !== 'undefined') {\r\n window.removeEventListener('pagehide', this.handlePageHide);\r\n }\r\n void this.flush();\r\n }\r\n\r\n private handleVisibility = (): void => {\r\n // console.warn(\"VISIBILITY CHANGE:\", document.visibilityState);\r\n\r\n if (document.visibilityState === 'hidden') {\r\n void this.flush();\r\n }\r\n };\r\n\r\n private handlePageHide = (): void => {\r\n // console.warn(\"PAGEHIDE FLUSH\");\r\n void this.flush();\r\n };\r\n}\r\n","const VISITOR_KEY = 'vyzora_visitor_id';\r\n\r\nfunction generateUUID(): string {\r\n if (\r\n typeof crypto !== 'undefined' &&\r\n typeof crypto.randomUUID === 'function'\r\n ) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nexport function getVisitorId(): string {\r\n try {\r\n let id = localStorage.getItem(VISITOR_KEY);\r\n if (!id) {\r\n id = generateUUID();\r\n localStorage.setItem(VISITOR_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n return generateUUID();\r\n }\r\n}\r\n","const SESSION_KEY = 'vyzora_session_id';\r\nconst SESSION_TS_KEY = 'vyzora_session_ts';\r\nconst INACTIVITY_MS = 30 * 60 * 1000;\r\n\r\nfunction generateUUID(): string {\r\n if (\r\n typeof crypto !== 'undefined' &&\r\n typeof crypto.randomUUID === 'function'\r\n ) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nfunction now(): number {\r\n return Date.now();\r\n}\r\n\r\nexport function getSessionId(): string {\r\n try {\r\n const lastTs = parseInt(sessionStorage.getItem(SESSION_TS_KEY) ?? '0', 10);\r\n const expired = now() - lastTs > INACTIVITY_MS;\r\n\r\n let id = sessionStorage.getItem(SESSION_KEY);\r\n if (!id || expired) {\r\n id = generateUUID();\r\n sessionStorage.setItem(SESSION_KEY, id);\r\n }\r\n\r\n sessionStorage.setItem(SESSION_TS_KEY, String(now()));\r\n return id;\r\n } catch {\r\n return generateUUID();\r\n }\r\n}\r\n\r\nexport function resetSession(): void {\r\n try {\r\n sessionStorage.removeItem(SESSION_KEY);\r\n sessionStorage.removeItem(SESSION_TS_KEY);\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n","import type { AutoMetadata } from './types';\r\n\r\nfunction detectBrowser(ua: string): { browser: string; version: string } {\r\n const rules: [RegExp, string][] = [\r\n [/Edg\\/(\\S+)/, 'Edge'],\r\n [/OPR\\/(\\S+)/, 'Opera'],\r\n [/SamsungBrowser\\/(\\S+)/, 'Samsung'],\r\n [/Firefox\\/(\\S+)/, 'Firefox'],\r\n [/Chrome\\/(\\S+)/, 'Chrome'],\r\n [/Safari\\/(\\S+)/, 'Safari'],\r\n ];\r\n for (const [re, name] of rules) {\r\n const m = ua.match(re);\r\n if (m) return { browser: name, version: m[1].split('.')[0] };\r\n }\r\n return { browser: 'Unknown', version: '' };\r\n}\r\n\r\nfunction detectOS(ua: string): string {\r\n if (/Windows NT/i.test(ua)) return 'Windows';\r\n if (/Mac OS X/i.test(ua)) return 'macOS';\r\n if (/Android/i.test(ua)) return 'Android';\r\n if (/iPhone|iPad|iPod/i.test(ua)) return 'iOS';\r\n if (/Linux/i.test(ua)) return 'Linux';\r\n return 'Unknown';\r\n}\r\n\r\nfunction detectDevice(ua: string): AutoMetadata['deviceType'] {\r\n if (/Mobi/i.test(ua)) return 'mobile';\r\n if (/Tablet|iPad/i.test(ua)) return 'tablet';\r\n return 'desktop';\r\n}\r\n\r\nexport function collectMetadata(): AutoMetadata {\r\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\r\n return {};\r\n }\r\n\r\n try {\r\n const ua = navigator.userAgent;\r\n const { browser, version } = detectBrowser(ua);\r\n\r\n return {\r\n browser,\r\n browserVersion: version,\r\n os: detectOS(ua),\r\n deviceType: detectDevice(ua),\r\n screenWidth: window.screen?.width,\r\n screenHeight: window.screen?.height,\r\n language: navigator.language,\r\n referrer: document.referrer || undefined,\r\n timezone: Intl?.DateTimeFormat?.().resolvedOptions?.()?.timeZone,\r\n };\r\n } catch {\r\n return {};\r\n }\r\n}\r\n","\r\nexport class Logger {\r\n private debug: boolean;\r\n\r\n constructor(debug: boolean = false) {\r\n this.debug = debug;\r\n }\r\n\r\n log(message: string, ...args: unknown[]): void {\r\n if (!this.debug) return;\r\n console.warn(`[Vyzora] ${message}`, ...args);\r\n }\r\n\r\n warn(message: string, ...args: unknown[]): void {\r\n console.warn(`[Vyzora] ${message}`, ...args);\r\n }\r\n\r\n error(message: string, ...args: unknown[]): void {\r\n console.error(`[Vyzora] ${message}`, ...args);\r\n }\r\n}\r\n","import type { VyzoraConfig } from './types';\r\nimport { Queue } from './queue';\r\nimport { getVisitorId } from './visitor';\r\nimport { getSessionId, resetSession } from './session';\r\nimport { collectMetadata } from './metadata';\r\nimport { Logger } from './logger';\r\n\r\n// @ts-expect-error - __VYZORA_API_URL__ is injected by tsup at build-time\r\nconst DEFAULT_ENDPOINT = __VYZORA_API_URL__;\r\nconst DEFAULT_BATCH_SIZE = 20;\r\nconst DEFAULT_FLUSH_INTERVAL = 10000;\r\n\r\nexport class Vyzora {\r\n private readonly apiKey: string;\r\n private readonly endpoint: string;\r\n private readonly enabled: boolean;\r\n private readonly debug: boolean;\r\n private queue: Queue | null = null;\r\n private customVisitorId: string | null = null;\r\n private logger: Logger;\r\n private lastTrackedPath: string | null = null;\r\n\r\n constructor(config: VyzoraConfig) {\r\n if (!config.apiKey) {\r\n throw new Error('[Vyzora] apiKey is required.');\r\n }\r\n\r\n this.apiKey = config.apiKey;\r\n this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\r\n this.enabled = config.enabled === true;\r\n this.debug = config.debug ?? false;\r\n this.logger = new Logger(this.debug);\r\n\r\n if (!this.enabled) {\r\n this.logger.log('SDK is disabled. Set enabled: true to activate.');\r\n return;\r\n }\r\n\r\n if (typeof window === 'undefined') return;\r\n\r\n this.queue = new Queue({\r\n endpoint: this.endpoint,\r\n apiKey: this.apiKey,\r\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\r\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\r\n debug: this.debug,\r\n logger: this.logger,\r\n });\r\n this.queue.start();\r\n\r\n this.hookPageTracking();\r\n\r\n this.logger.log('SDK initialised.');\r\n }\r\n\r\n track(eventType: string, metadata?: Record<string, unknown>): void {\r\n if (!this.enabled || !this.queue) return;\r\n try {\r\n const autoMeta = collectMetadata();\r\n const merged: Record<string, unknown> = { ...autoMeta, ...metadata };\r\n\r\n this.queue.push({\r\n sessionId: getSessionId(),\r\n visitorId: this.customVisitorId ?? getVisitorId(),\r\n eventType,\r\n path: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n metadata: Object.keys(merged).length > 0 ? merged : undefined,\r\n });\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n pageview(path?: string): void {\r\n if (!this.enabled || !this.queue) return;\r\n try {\r\n const resolvedPath =\r\n path ?? (typeof window !== 'undefined' ? window.location.pathname : '/');\r\n\r\n // Avoid double tracking the same path in immediate succession (e.g. load + pushState)\r\n if (resolvedPath === this.lastTrackedPath) return;\r\n this.lastTrackedPath = resolvedPath;\r\n\r\n const autoMeta = collectMetadata();\r\n\r\n this.queue.push({\r\n sessionId: getSessionId(),\r\n visitorId: this.customVisitorId ?? getVisitorId(),\r\n eventType: 'pageview',\r\n path: resolvedPath,\r\n metadata: Object.keys(autoMeta).length > 0 ? autoMeta : undefined,\r\n });\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n identify(visitorId: string): void {\r\n if (!this.enabled) return;\r\n this.customVisitorId = visitorId;\r\n this.logger.log('Visitor identified:', visitorId);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n if (!this.enabled || !this.queue) return;\r\n await this.queue.flush();\r\n }\r\n\r\n resetSession(): void {\r\n resetSession();\r\n }\r\n\r\n destroy(): void {\r\n this.queue?.destroy();\r\n this.queue = null;\r\n }\r\n\r\n\r\n private hookPageTracking(): void {\r\n if (typeof window === 'undefined') return;\r\n\r\n // Initial pageview on load\r\n window.addEventListener('load', () => this.pageview(), { once: true });\r\n\r\n // SPA navigation — intercept history.pushState and history.replaceState\r\n this.wrapHistoryMethod('pushState');\r\n this.wrapHistoryMethod('replaceState');\r\n\r\n // Back/forward navigation\r\n window.addEventListener('popstate', () => this.pageview());\r\n }\r\n\r\n private wrapHistoryMethod(method: 'pushState' | 'replaceState'): void {\r\n const original = history[method]?.bind(history);\r\n if (typeof original !== 'function') return;\r\n\r\n history[method] = (...args) => {\r\n original(...args);\r\n this.pageview();\r\n };\r\n }\r\n}\r\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/* @vyzora/sdk - lightweight analytics - MIT license */
|
|
2
|
+
var L=Object.defineProperty;var x=Object.getOwnPropertySymbols;var P=Object.prototype.hasOwnProperty,V=Object.prototype.propertyIsEnumerable;var w=(t,e,i)=>e in t?L(t,e,{enumerable:true,configurable:true,writable:true,value:i}):t[e]=i,g=(t,e)=>{for(var i in e||(e={}))P.call(e,i)&&w(t,i,e[i]);if(x)for(var i of x(e))V.call(e,i)&&w(t,i,e[i]);return t};async function b(t,e,i,n,r){if(i.length===0)return;let s=JSON.stringify({apiKey:e,events:i}),u={"Content-Type":"application/json"};if(typeof navigator!="undefined"&&typeof navigator.sendBeacon=="function"){let l=new Blob([s],{type:"application/json"});if(navigator.sendBeacon(t,l)){r.log("Batch sent via sendBeacon",{count:i.length});return}}await h(t,s,u,n,r);}async function h(t,e,i,n,r,o=0){try{let s=await fetch(t,{method:"POST",headers:i,body:e,keepalive:!0});r.log(`Batch flush (attempt ${o+1}) \u2192`,s.status),!s.ok&&o===0&&setTimeout(()=>h(t,e,i,n,r,1),2e3);}catch(s){o===0&&setTimeout(()=>h(t,e,i,n,r,1),2e3);}}var a=class{constructor(e){this.events=[];this.timer=null;this.handleVisibility=()=>{document.visibilityState==="hidden"&&this.flush();};this.handlePageHide=()=>{this.flush();};this.endpoint=e.endpoint,this.apiKey=e.apiKey,this.batchSize=e.batchSize,this.flushInterval=e.flushInterval,this.debug=e.debug,this.logger=e.logger;}start(){this.timer===null&&(this.timer=setInterval(()=>{this.logger.log("Auto-flush triggered"),this.flush();},this.flushInterval),typeof document!="undefined"&&document.addEventListener("visibilitychange",this.handleVisibility),typeof window!="undefined"&&window.addEventListener("pagehide",this.handlePageHide));}push(e){this.events.push(e),this.logger.log(`Event queued: ${e.eventType} (queue=${this.events.length})`),this.events.length>=this.batchSize&&this.flush();}async flush(){if(this.events.length===0)return;let e=this.events.splice(0,this.events.length);this.logger.log(`Flushing ${e.length} event(s)`),await b(this.endpoint,this.apiKey,e,this.debug,this.logger);}destroy(){this.timer!==null&&(clearInterval(this.timer),this.timer=null),typeof document!="undefined"&&document.removeEventListener("visibilitychange",this.handleVisibility),typeof window!="undefined"&&window.removeEventListener("pagehide",this.handlePageHide),this.flush();}};var S="vyzora_visitor_id";function I(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return (t==="x"?e:e&3|8).toString(16)})}function c(){try{let t=localStorage.getItem(S);return t||(t=I(),localStorage.setItem(S,t)),t}catch(t){return I()}}var p="vyzora_session_id",f="vyzora_session_ts";function E(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return (t==="x"?e:e&3|8).toString(16)})}function T(){return Date.now()}function v(){var t;try{let e=parseInt((t=sessionStorage.getItem(f))!=null?t:"0",10),i=T()-e>18e5,n=sessionStorage.getItem(p);return (!n||i)&&(n=E(),sessionStorage.setItem(p,n)),sessionStorage.setItem(f,String(T())),n}catch(e){return E()}}function _(){try{sessionStorage.removeItem(p),sessionStorage.removeItem(f);}catch(t){}}function k(t){let e=[[/Edg\/(\S+)/,"Edge"],[/OPR\/(\S+)/,"Opera"],[/SamsungBrowser\/(\S+)/,"Samsung"],[/Firefox\/(\S+)/,"Firefox"],[/Chrome\/(\S+)/,"Chrome"],[/Safari\/(\S+)/,"Safari"]];for(let[i,n]of e){let r=t.match(i);if(r)return {browser:n,version:r[1].split(".")[0]}}return {browser:"Unknown",version:""}}function A(t){return /Windows NT/i.test(t)?"Windows":/Mac OS X/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}function M(t){return /Mobi/i.test(t)?"mobile":/Tablet|iPad/i.test(t)?"tablet":"desktop"}function y(){var t,e,i,n,r,o;if(typeof window=="undefined"||typeof navigator=="undefined")return {};try{let s=navigator.userAgent,{browser:u,version:l}=k(s);return {browser:u,browserVersion:l,os:A(s),deviceType:M(s),screenWidth:(t=window.screen)==null?void 0:t.width,screenHeight:(e=window.screen)==null?void 0:e.height,language:navigator.language,referrer:document.referrer||void 0,timezone:(o=(r=(i=Intl==null?void 0:Intl.DateTimeFormat)==null?void 0:(n=i.call(Intl)).resolvedOptions)==null?void 0:r.call(n))==null?void 0:o.timeZone}}catch(s){return {}}}var d=class{constructor(e=false){this.debug=e;}log(e,...i){this.debug&&console.warn(`[Vyzora] ${e}`,...i);}warn(e,...i){console.warn(`[Vyzora] ${e}`,...i);}error(e,...i){console.error(`[Vyzora] ${e}`,...i);}};var U="http://localhost:3001/api/ingest",z=20,D=1e4,m=class{constructor(e){this.queue=null;this.customVisitorId=null;this.lastTrackedPath=null;var i,n,r,o;if(!e.apiKey)throw new Error("[Vyzora] apiKey is required.");if(this.apiKey=e.apiKey,this.endpoint=(i=e.endpoint)!=null?i:U,this.enabled=e.enabled===true,this.debug=(n=e.debug)!=null?n:false,this.logger=new d(this.debug),!this.enabled){this.logger.log("SDK is disabled. Set enabled: true to activate.");return}typeof window!="undefined"&&(this.queue=new a({endpoint:this.endpoint,apiKey:this.apiKey,batchSize:(r=e.batchSize)!=null?r:z,flushInterval:(o=e.flushInterval)!=null?o:D,debug:this.debug,logger:this.logger}),this.queue.start(),this.hookPageTracking(),this.logger.log("SDK initialised."));}track(e,i){var n;if(!(!this.enabled||!this.queue))try{let r=y(),o=g(g({},r),i);this.queue.push({sessionId:v(),visitorId:(n=this.customVisitorId)!=null?n:c(),eventType:e,path:typeof window!="undefined"?window.location.pathname:"/",metadata:Object.keys(o).length>0?o:void 0});}catch(r){}}pageview(e){var i;if(!(!this.enabled||!this.queue))try{let n=e!=null?e:typeof window!="undefined"?window.location.pathname:"/";if(n===this.lastTrackedPath)return;this.lastTrackedPath=n;let r=y();this.queue.push({sessionId:v(),visitorId:(i=this.customVisitorId)!=null?i:c(),eventType:"pageview",path:n,metadata:Object.keys(r).length>0?r:void 0});}catch(n){}}identify(e){this.enabled&&(this.customVisitorId=e,this.logger.log("Visitor identified:",e));}async flush(){!this.enabled||!this.queue||await this.queue.flush();}resetSession(){_();}destroy(){var e;(e=this.queue)==null||e.destroy(),this.queue=null;}hookPageTracking(){typeof window!="undefined"&&(window.addEventListener("load",()=>this.pageview(),{once:true}),this.wrapHistoryMethod("pushState"),this.wrapHistoryMethod("replaceState"),window.addEventListener("popstate",()=>this.pageview()));}wrapHistoryMethod(e){var n;let i=(n=history[e])==null?void 0:n.bind(history);typeof i=="function"&&(history[e]=(...r)=>{i(...r),this.pageview();});}};
|
|
3
|
+
export{m as Vyzora};//# sourceMappingURL=index.mjs.map
|
|
4
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transport.ts","../src/queue.ts","../src/visitor.ts","../src/session.ts","../src/metadata.ts","../src/logger.ts","../src/core.ts"],"names":["sendBatch","endpoint","apiKey","events","debug","logger","body","headers","blob","fetchWithRetry","attempt","res","e","Queue","opts","event","batch","VISITOR_KEY","generateUUID","c","r","getVisitorId","id","SESSION_KEY","SESSION_TS_KEY","now","getSessionId","_a","lastTs","expired","resetSession","detectBrowser","ua","rules","re","name","m","detectOS","detectDevice","collectMetadata","_b","_c","_d","_e","_f","browser","version","Logger","message","args","DEFAULT_ENDPOINT","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL","Vyzora","config","eventType","metadata","autoMeta","merged","__spreadValues","path","resolvedPath","visitorId","method","original"],"mappings":";AAKA,IAAA,CAAA,CAAA,MAAA,CAAA,cAAA,CAAA,IAAA,CAAA,CAAA,MAAA,CAAA,qBAAA,CAAA,IAAA,CAAA,CAAA,MAAA,CAAA,SAAA,CAAA,cAAA,CAAA,CAAA,CAAA,MAAA,CAAA,SAAA,CAAA,oBAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,UAAA,CAAA,IAAA,CAAA,YAAA,CAAA,IAAA,CAAA,QAAA,CAAA,IAAA,CAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,IAAA,IAAA,CAAA,IAAA,CAAA,GAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,IAAA,IAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,eAAsBA,CAAAA,CAClBC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACa,CACb,GAAIF,CAAAA,CAAO,MAAA,GAAW,CAAA,CAAG,OAGzB,IAAMG,EAAO,IAAA,CAAK,SAAA,CADa,CAAE,MAAA,CAAAJ,CAAAA,CAAQ,MAAA,CAAAC,CAAO,CACb,EAC7BI,CAAAA,CAAU,CAAE,cAAA,CAAgB,kBAAmB,EAErD,GACI,OAAO,SAAA,EAAc,WAAA,EACrB,OAAO,SAAA,CAAU,UAAA,EAAe,UAAA,CAClC,CACE,IAAMC,CAAAA,CAAO,IAAI,IAAA,CAAK,CAACF,CAAI,CAAA,CAAG,CAAE,IAAA,CAAM,kBAAmB,CAAC,CAAA,CAE1D,GADa,SAAA,CAAU,WAAWL,CAAAA,CAAUO,CAAI,CAAA,CACtC,CACNH,CAAAA,CAAO,GAAA,CAAI,2BAAA,CAA6B,CAAE,MAAOF,CAAAA,CAAO,MAAO,CAAC,CAAA,CAChE,MACJ,CACJ,CAEA,MAAMM,CAAAA,CAAeR,EAAUK,CAAAA,CAAMC,CAAAA,CAASH,CAAAA,CAAOC,CAAM,EAC/D,CAEA,eAAeI,CAAAA,CACXR,EACAK,CAAAA,CACAC,CAAAA,CACAH,CAAAA,CACAC,CAAAA,CACAK,EAAU,CAAA,CACG,CACb,GAAI,CACA,IAAMC,CAAAA,CAAM,MAAM,KAAA,CAAMV,CAAAA,CAAU,CAC9B,MAAA,CAAQ,MAAA,CACR,OAAA,CAAAM,EACA,IAAA,CAAAD,CAAAA,CACA,SAAA,CAAW,CAAA,CACf,CAAC,CAAA,CAEDD,CAAAA,CAAO,GAAA,CAAI,CAAA,qBAAA,EAAwBK,EAAU,CAAC,CAAA,QAAA,CAAA,CAAOC,CAAAA,CAAI,MAAM,CAAA,CAE3D,CAACA,CAAAA,CAAI,EAAA,EAAMD,IAAY,CAAA,EACvB,UAAA,CACI,IAAMD,CAAAA,CAAeR,EAAUK,CAAAA,CAAMC,CAAAA,CAASH,CAAAA,CAAOC,CAAAA,CAAQ,CAAC,CAAA,CAC9D,GACJ,EAER,CAAA,MAAQO,CAAAA,CAAA,CACAF,CAAAA,GAAY,CAAA,EACZ,WACI,IAAMD,CAAAA,CAAeR,CAAAA,CAAUK,CAAAA,CAAMC,EAASH,CAAAA,CAAOC,CAAAA,CAAQ,CAAC,CAAA,CAC9D,GACJ,EAER,CACJ,CC7DO,IAAMQ,CAAAA,CAAN,KAAY,CAUf,WAAA,CAAYC,EAOT,CAhBH,IAAA,CAAQ,MAAA,CAA0B,EAAC,CACnC,IAAA,CAAQ,KAAA,CAA+C,IAAA,CAyEvD,KAAQ,gBAAA,CAAmB,IAAY,CAG/B,QAAA,CAAS,eAAA,GAAoB,QAAA,EACxB,IAAA,CAAK,KAAA,GAElB,CAAA,CAEA,IAAA,CAAQ,cAAA,CAAiB,IAAY,CAE5B,IAAA,CAAK,KAAA,GACd,CAAA,CApEI,KAAK,QAAA,CAAWA,CAAAA,CAAK,QAAA,CACrB,IAAA,CAAK,MAAA,CAASA,CAAAA,CAAK,MAAA,CACnB,IAAA,CAAK,UAAYA,CAAAA,CAAK,SAAA,CACtB,IAAA,CAAK,aAAA,CAAgBA,EAAK,aAAA,CAC1B,IAAA,CAAK,KAAA,CAAQA,CAAAA,CAAK,MAClB,IAAA,CAAK,MAAA,CAASA,CAAAA,CAAK,OACvB,CAEA,KAAA,EAAc,CACN,IAAA,CAAK,QAAU,IAAA,GACnB,IAAA,CAAK,KAAA,CAAQ,WAAA,CAAY,IAAM,CAE3B,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,sBAAsB,CAAA,CACjC,IAAA,CAAK,KAAA,GACd,CAAA,CAAG,IAAA,CAAK,aAAa,CAAA,CAEjB,OAAO,QAAA,EAAa,WAAA,EACpB,QAAA,CAAS,gBAAA,CAAiB,mBAAoB,IAAA,CAAK,gBAAgB,CAAA,CAEnE,OAAO,QAAW,WAAA,EAClB,MAAA,CAAO,gBAAA,CAAiB,UAAA,CAAY,IAAA,CAAK,cAAc,CAAA,EAE/D,CAEA,KAAKC,CAAAA,CAA4B,CAC7B,IAAA,CAAK,MAAA,CAAO,KAAKA,CAAK,CAAA,CAGtB,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,cAAA,EAAiBA,CAAAA,CAAM,SAAS,CAAA,QAAA,EAAW,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,CAAA,CAAG,EAC5E,IAAA,CAAK,MAAA,CAAO,MAAA,EAAU,IAAA,CAAK,WACtB,IAAA,CAAK,KAAA,GAElB,CAEA,MAAM,KAAA,EAAuB,CACzB,GAAI,IAAA,CAAK,MAAA,CAAO,MAAA,GAAW,CAAA,CAAG,OAC9B,IAAMC,CAAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,EAAG,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,CACtD,KAAK,MAAA,CAAO,GAAA,CAAI,CAAA,SAAA,EAAYA,CAAAA,CAAM,MAAM,CAAA,SAAA,CAAW,CAAA,CACnD,MAAMhB,EAAU,IAAA,CAAK,QAAA,CAAU,IAAA,CAAK,MAAA,CAAQgB,CAAAA,CAAO,IAAA,CAAK,KAAA,CAAO,IAAA,CAAK,MAAM,EAC9E,CAEA,OAAA,EAAgB,CAGR,IAAA,CAAK,KAAA,GAAU,IAAA,GACf,aAAA,CAAc,KAAK,KAAK,CAAA,CACxB,IAAA,CAAK,KAAA,CAAQ,MAEb,OAAO,QAAA,EAAa,WAAA,EACpB,QAAA,CAAS,oBAAoB,kBAAA,CAAoB,IAAA,CAAK,gBAAgB,CAAA,CAEtE,OAAO,MAAA,EAAW,WAAA,EAClB,MAAA,CAAO,oBAAoB,UAAA,CAAY,IAAA,CAAK,cAAc,CAAA,CAEzD,KAAK,KAAA,GACd,CAcJ,CAAA,CC3FA,IAAMC,CAAAA,CAAc,mBAAA,CAEpB,SAASC,CAAAA,EAAuB,CAC5B,OACI,OAAO,MAAA,EAAW,aAClB,OAAO,MAAA,CAAO,UAAA,EAAe,UAAA,CAEtB,OAAO,UAAA,EAAW,CAEtB,sCAAA,CAAuC,OAAA,CAAQ,QAAUC,CAAAA,EAAM,CAClE,IAAMC,CAAAA,CAAK,IAAA,CAAK,MAAA,EAAO,CAAI,EAAA,CAAM,EAEjC,OAAA,CADUD,CAAAA,GAAM,GAAA,CAAMC,CAAAA,CAAKA,EAAI,CAAA,CAAO,CAAA,EAC7B,QAAA,CAAS,EAAE,CACxB,CAAC,CACL,CAEO,SAASC,CAAAA,EAAuB,CACnC,GAAI,CACA,IAAIC,CAAAA,CAAK,YAAA,CAAa,OAAA,CAAQL,CAAW,EACzC,OAAKK,CAAAA,GACDA,CAAAA,CAAKJ,CAAAA,GACL,YAAA,CAAa,OAAA,CAAQD,CAAAA,CAAaK,CAAE,CAAA,CAAA,CAEjCA,CACX,CAAA,MAAQV,CAAAA,CAAA,CACJ,OAAOM,CAAAA,EACX,CACJ,CC3BA,IAAMK,CAAAA,CAAc,mBAAA,CACdC,CAAAA,CAAiB,oBAGvB,SAASN,CAAAA,EAAuB,CAC5B,OACI,OAAO,MAAA,EAAW,WAAA,EAClB,OAAO,OAAO,UAAA,EAAe,UAAA,CAEtB,MAAA,CAAO,UAAA,GAEX,sCAAA,CAAuC,OAAA,CAAQ,OAAA,CAAUC,CAAAA,EAAM,CAClE,IAAMC,CAAAA,CAAK,IAAA,CAAK,MAAA,EAAO,CAAI,EAAA,CAAM,CAAA,CAEjC,OAAA,CADUD,IAAM,GAAA,CAAMC,CAAAA,CAAKA,CAAAA,CAAI,CAAA,CAAO,CAAA,EAC7B,QAAA,CAAS,EAAE,CACxB,CAAC,CACL,CAEA,SAASK,CAAAA,EAAc,CACnB,OAAO,IAAA,CAAK,GAAA,EAChB,CAEO,SAASC,CAAAA,EAAuB,CAtBvC,IAAAC,CAAAA,CAuBI,GAAI,CACA,IAAMC,EAAS,QAAA,CAAA,CAASD,CAAAA,CAAA,cAAA,CAAe,OAAA,CAAQH,CAAc,CAAA,GAArC,IAAA,CAAAG,CAAAA,CAA0C,IAAK,EAAE,CAAA,CACnEE,CAAAA,CAAUJ,CAAAA,GAAQG,CAAAA,CAAS,IAAA,CAE7BN,CAAAA,CAAK,cAAA,CAAe,QAAQC,CAAW,CAAA,CAC3C,OAAA,CAAI,CAACD,CAAAA,EAAMO,CAAAA,IACPP,CAAAA,CAAKJ,CAAAA,GACL,cAAA,CAAe,OAAA,CAAQK,CAAAA,CAAaD,CAAE,GAG1C,cAAA,CAAe,OAAA,CAAQE,CAAAA,CAAgB,MAAA,CAAOC,GAAK,CAAC,CAAA,CAC7CH,CACX,CAAA,MAAQ,CAAA,CAAA,CACJ,OAAOJ,CAAAA,EACX,CACJ,CAEO,SAASY,CAAAA,EAAqB,CACjC,GAAI,CACA,cAAA,CAAe,UAAA,CAAWP,CAAW,CAAA,CACrC,cAAA,CAAe,UAAA,CAAWC,CAAc,EAC5C,CAAA,MAAQZ,CAAAA,CAAA,CAER,CACJ,CC7CA,SAASmB,CAAAA,CAAcC,CAAAA,CAAkD,CACrE,IAAMC,CAAAA,CAA4B,CAC9B,CAAC,aAAc,MAAM,CAAA,CACrB,CAAC,YAAA,CAAc,OAAO,CAAA,CACtB,CAAC,uBAAA,CAAyB,SAAS,CAAA,CACnC,CAAC,gBAAA,CAAkB,SAAS,EAC5B,CAAC,eAAA,CAAiB,QAAQ,CAAA,CAC1B,CAAC,eAAA,CAAiB,QAAQ,CAC9B,CAAA,CACA,IAAA,GAAW,CAACC,CAAAA,CAAIC,CAAI,IAAKF,CAAAA,CAAO,CAC5B,IAAMG,CAAAA,CAAIJ,EAAG,KAAA,CAAME,CAAE,CAAA,CACrB,GAAIE,EAAG,OAAO,CAAE,OAAA,CAASD,CAAAA,CAAM,OAAA,CAASC,CAAAA,CAAE,CAAC,CAAA,CAAE,MAAM,GAAG,CAAA,CAAE,CAAC,CAAE,CAC/D,CACA,OAAO,CAAE,QAAS,SAAA,CAAW,OAAA,CAAS,EAAG,CAC7C,CAEA,SAASC,CAAAA,CAASL,CAAAA,CAAoB,CAClC,OAAI,aAAA,CAAc,IAAA,CAAKA,CAAE,EAAU,SAAA,CAC/B,WAAA,CAAY,IAAA,CAAKA,CAAE,EAAU,OAAA,CAC7B,UAAA,CAAW,IAAA,CAAKA,CAAE,CAAA,CAAU,SAAA,CAC5B,mBAAA,CAAoB,IAAA,CAAKA,CAAE,CAAA,CAAU,KAAA,CACrC,QAAA,CAAS,IAAA,CAAKA,CAAE,CAAA,CAAU,OAAA,CACvB,SACX,CAEA,SAASM,CAAAA,CAAaN,CAAAA,CAAwC,CAC1D,OAAI,OAAA,CAAQ,IAAA,CAAKA,CAAE,CAAA,CAAU,SACzB,cAAA,CAAe,IAAA,CAAKA,CAAE,CAAA,CAAU,SAC7B,SACX,CAEO,SAASO,CAAAA,EAAgC,CAjChD,IAAAZ,CAAAA,CAAAa,CAAAA,CAAAC,CAAAA,CAAAC,CAAAA,CAAAC,CAAAA,CAAAC,CAAAA,CAkCI,GAAI,OAAO,MAAA,EAAW,WAAA,EAAe,OAAO,SAAA,EAAc,YACtD,OAAO,EAAC,CAGZ,GAAI,CACA,IAAMZ,CAAAA,CAAK,SAAA,CAAU,SAAA,CACf,CAAE,OAAA,CAAAa,CAAAA,CAAS,OAAA,CAAAC,CAAQ,CAAA,CAAIf,CAAAA,CAAcC,CAAE,CAAA,CAE7C,OAAO,CACH,OAAA,CAAAa,CAAAA,CACA,cAAA,CAAgBC,EAChB,EAAA,CAAIT,CAAAA,CAASL,CAAE,CAAA,CACf,UAAA,CAAYM,CAAAA,CAAaN,CAAE,CAAA,CAC3B,aAAaL,CAAAA,CAAA,MAAA,CAAO,MAAA,GAAP,IAAA,CAAA,KAAA,CAAA,CAAAA,EAAe,KAAA,CAC5B,YAAA,CAAA,CAAca,CAAAA,CAAA,MAAA,CAAO,SAAP,IAAA,CAAA,KAAA,CAAA,CAAAA,CAAAA,CAAe,MAAA,CAC7B,QAAA,CAAU,SAAA,CAAU,QAAA,CACpB,QAAA,CAAU,QAAA,CAAS,UAAY,KAAA,CAAA,CAC/B,QAAA,CAAA,CAAUI,CAAAA,CAAAA,CAAAD,CAAAA,CAAAA,CAAAF,EAAA,IAAA,EAAA,IAAA,CAAA,KAAA,CAAA,CAAA,IAAA,CAAM,cAAA,GAAN,IAAA,CAAA,KAAA,CAAA,CAAA,CAAAC,CAAAA,CAAAD,EAAA,IAAA,CAAA,IAAA,CAAA,EAAyB,eAAA,GAAzB,IAAA,CAAA,KAAA,CAAA,CAAAE,CAAAA,CAAA,IAAA,CAAAD,CAAAA,CAAAA,GAAA,IAAA,CAAA,KAAA,CAAA,CAAAE,CAAAA,CAA8C,QAC5D,CACJ,CAAA,MAAQhC,CAAAA,CAAA,CACJ,OAAO,EACX,CACJ,CCvDO,IAAMmC,CAAAA,CAAN,KAAa,CAGhB,WAAA,CAAY3C,CAAAA,CAAiB,KAAA,CAAO,CAChC,KAAK,KAAA,CAAQA,EACjB,CAEA,GAAA,CAAI4C,KAAoBC,CAAAA,CAAuB,CACtC,IAAA,CAAK,KAAA,EACV,QAAQ,IAAA,CAAK,CAAA,SAAA,EAAYD,CAAO,CAAA,CAAA,CAAI,GAAGC,CAAI,EAC/C,CAEA,KAAKD,CAAAA,CAAAA,GAAoBC,CAAAA,CAAuB,CAC5C,OAAA,CAAQ,KAAK,CAAA,SAAA,EAAYD,CAAO,CAAA,CAAA,CAAI,GAAGC,CAAI,EAC/C,CAEA,KAAA,CAAMD,CAAAA,CAAAA,GAAoBC,CAAAA,CAAuB,CAC7C,OAAA,CAAQ,KAAA,CAAM,YAAYD,CAAO,CAAA,CAAA,CAAI,GAAGC,CAAI,EAChD,CACJ,CAAA,CCZA,IAAMC,CAAAA,CAAmB,mCACnBC,CAAAA,CAAqB,EAAA,CACrBC,CAAAA,CAAyB,GAAA,CAElBC,CAAAA,CAAN,KAAa,CAUhB,WAAA,CAAYC,EAAsB,CALlC,IAAA,CAAQ,KAAA,CAAsB,IAAA,CAC9B,KAAQ,eAAA,CAAiC,IAAA,CAEzC,IAAA,CAAQ,eAAA,CAAiC,KApB7C,IAAA3B,CAAAA,CAAAa,CAAAA,CAAAC,CAAAA,CAAAC,CAAAA,CAuBQ,GAAI,CAACY,CAAAA,CAAO,OACR,MAAM,IAAI,KAAA,CAAM,8BAA8B,EASlD,GANA,IAAA,CAAK,MAAA,CAASA,CAAAA,CAAO,OACrB,IAAA,CAAK,QAAA,CAAA,CAAW3B,CAAAA,CAAA2B,CAAAA,CAAO,QAAA,GAAP,IAAA,CAAA3B,CAAAA,CAAmBuB,CAAAA,CACnC,KAAK,OAAA,CAAUI,CAAAA,CAAO,OAAA,GAAY,IAAA,CAClC,KAAK,KAAA,CAAA,CAAQd,CAAAA,CAAAc,CAAAA,CAAO,KAAA,GAAP,KAAAd,CAAAA,CAAgB,KAAA,CAC7B,IAAA,CAAK,MAAA,CAAS,IAAIO,CAAAA,CAAO,IAAA,CAAK,KAAK,EAE/B,CAAC,IAAA,CAAK,OAAA,CAAS,CACf,KAAK,MAAA,CAAO,GAAA,CAAI,iDAAiD,CAAA,CACjE,MACJ,CAEI,OAAO,MAAA,EAAW,WAAA,GAEtB,IAAA,CAAK,KAAA,CAAQ,IAAIlC,CAAAA,CAAM,CACnB,QAAA,CAAU,IAAA,CAAK,QAAA,CACf,MAAA,CAAQ,IAAA,CAAK,MAAA,CACb,SAAA,CAAA,CAAW4B,CAAAA,CAAAa,EAAO,SAAA,GAAP,IAAA,CAAAb,CAAAA,CAAoBU,CAAAA,CAC/B,aAAA,CAAA,CAAeT,CAAAA,CAAAY,CAAAA,CAAO,aAAA,GAAP,KAAAZ,CAAAA,CAAwBU,CAAAA,CACvC,KAAA,CAAO,IAAA,CAAK,MACZ,MAAA,CAAQ,IAAA,CAAK,MACjB,CAAC,EACD,IAAA,CAAK,KAAA,CAAM,KAAA,EAAM,CAEjB,IAAA,CAAK,gBAAA,EAAiB,CAEtB,IAAA,CAAK,OAAO,GAAA,CAAI,kBAAkB,CAAA,EACtC,CAEA,MAAMG,CAAAA,CAAmBC,CAAAA,CAA0C,CAvDvE,IAAA7B,EAwDQ,GAAI,EAAA,CAAC,IAAA,CAAK,OAAA,EAAW,CAAC,IAAA,CAAK,KAAA,CAAA,CAC3B,GAAI,CACA,IAAM8B,CAAAA,CAAWlB,CAAAA,EAAgB,CAC3BmB,EAAkCC,CAAAA,CAAAA,CAAAA,CAAA,EAAA,CAAKF,CAAAA,CAAAA,CAAaD,CAAAA,CAAAA,CAE1D,KAAK,KAAA,CAAM,IAAA,CAAK,CACZ,SAAA,CAAW9B,CAAAA,EAAa,CACxB,SAAA,CAAA,CAAWC,CAAAA,CAAA,KAAK,eAAA,GAAL,IAAA,CAAAA,CAAAA,CAAwBN,CAAAA,GACnC,SAAA,CAAAkC,CAAAA,CACA,IAAA,CAAM,OAAO,QAAW,WAAA,CAAc,MAAA,CAAO,QAAA,CAAS,QAAA,CAAW,GAAA,CACjE,QAAA,CAAU,MAAA,CAAO,IAAA,CAAKG,CAAM,CAAA,CAAE,MAAA,CAAS,CAAA,CAAIA,CAAAA,CAAS,MACxD,CAAC,EACL,CAAA,MAAQ9C,CAAAA,CAAA,CAER,CACJ,CAEA,QAAA,CAASgD,CAAAA,CAAqB,CAzElC,IAAAjC,CAAAA,CA0EQ,GAAI,GAAC,IAAA,CAAK,OAAA,EAAW,CAAC,IAAA,CAAK,OAC3B,GAAI,CACA,IAAMkC,CAAAA,CACFD,GAAA,IAAA,CAAAA,CAAAA,CAAS,OAAO,MAAA,EAAW,WAAA,CAAc,MAAA,CAAO,QAAA,CAAS,QAAA,CAAW,IAGxE,GAAIC,CAAAA,GAAiB,IAAA,CAAK,eAAA,CAAiB,OAC3C,IAAA,CAAK,eAAA,CAAkBA,CAAAA,CAEvB,IAAMJ,EAAWlB,CAAAA,EAAgB,CAEjC,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,CACZ,SAAA,CAAWb,CAAAA,GACX,SAAA,CAAA,CAAWC,CAAAA,CAAA,IAAA,CAAK,eAAA,GAAL,KAAAA,CAAAA,CAAwBN,CAAAA,EAAa,CAChD,SAAA,CAAW,WACX,IAAA,CAAMwC,CAAAA,CACN,QAAA,CAAU,MAAA,CAAO,IAAA,CAAKJ,CAAQ,CAAA,CAAE,MAAA,CAAS,EAAIA,CAAAA,CAAW,KAAA,CAC5D,CAAC,EACL,OAAQ7C,CAAAA,CAAA,CAER,CACJ,CAEA,SAASkD,CAAAA,CAAyB,CACzB,IAAA,CAAK,OAAA,GACV,IAAA,CAAK,eAAA,CAAkBA,CAAAA,CACvB,IAAA,CAAK,OAAO,GAAA,CAAI,qBAAA,CAAuBA,CAAS,CAAA,EACpD,CAEA,MAAM,KAAA,EAAuB,CACrB,CAAC,KAAK,OAAA,EAAW,CAAC,IAAA,CAAK,KAAA,EAC3B,MAAM,IAAA,CAAK,KAAA,CAAM,KAAA,GACrB,CAEA,YAAA,EAAqB,CACjBhC,CAAAA,GACJ,CAEA,OAAA,EAAgB,CAhHpB,IAAAH,GAiHQA,CAAAA,CAAA,IAAA,CAAK,KAAA,GAAL,IAAA,EAAAA,CAAAA,CAAY,OAAA,EAAA,CACZ,IAAA,CAAK,KAAA,CAAQ,KACjB,CAGQ,gBAAA,EAAyB,CACzB,OAAO,QAAW,WAAA,GAGtB,MAAA,CAAO,gBAAA,CAAiB,MAAA,CAAQ,IAAM,IAAA,CAAK,QAAA,EAAS,CAAG,CAAE,IAAA,CAAM,IAAK,CAAC,CAAA,CAGrE,KAAK,iBAAA,CAAkB,WAAW,CAAA,CAClC,IAAA,CAAK,kBAAkB,cAAc,CAAA,CAGrC,MAAA,CAAO,gBAAA,CAAiB,WAAY,IAAM,IAAA,CAAK,QAAA,EAAU,CAAA,EAC7D,CAEQ,iBAAA,CAAkBoC,CAAAA,CAA4C,CApI1E,IAAApC,CAAAA,CAqIQ,IAAMqC,CAAAA,CAAAA,CAAWrC,EAAA,OAAA,CAAQoC,CAAM,CAAA,GAAd,IAAA,CAAA,MAAA,CAAApC,EAAiB,IAAA,CAAK,OAAA,CAAA,CACnC,OAAOqC,CAAAA,EAAa,UAAA,GAExB,OAAA,CAAQD,CAAM,CAAA,CAAI,IAAId,CAAAA,GAAS,CAC3Be,CAAAA,CAAS,GAAGf,CAAI,CAAA,CAChB,IAAA,CAAK,QAAA,GACT,GACJ,CACJ","file":"index.mjs","sourcesContent":["import type { InternalEvent, IngestPayload } from './types';\r\nimport type { Logger } from './logger';\r\n\r\nconst RETRY_DELAY_MS = 2000;\r\n\r\nexport async function sendBatch(\r\n endpoint: string,\r\n apiKey: string,\r\n events: InternalEvent[],\r\n debug: boolean,\r\n logger: Logger\r\n): Promise<void> {\r\n if (events.length === 0) return;\r\n\r\n const payload: IngestPayload = { apiKey, events };\r\n const body = JSON.stringify(payload);\r\n const headers = { 'Content-Type': 'application/json' };\r\n\r\n if (\r\n typeof navigator !== 'undefined' &&\r\n typeof navigator.sendBeacon === 'function'\r\n ) {\r\n const blob = new Blob([body], { type: 'application/json' });\r\n const sent = navigator.sendBeacon(endpoint, blob);\r\n if (sent) {\r\n logger.log('Batch sent via sendBeacon', { count: events.length });\r\n return;\r\n }\r\n }\r\n\r\n await fetchWithRetry(endpoint, body, headers, debug, logger);\r\n}\r\n\r\nasync function fetchWithRetry(\r\n endpoint: string,\r\n body: string,\r\n headers: Record<string, string>,\r\n debug: boolean,\r\n logger: Logger,\r\n attempt = 0\r\n): Promise<void> {\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: 'POST',\r\n headers,\r\n body,\r\n keepalive: true,\r\n });\r\n\r\n logger.log(`Batch flush (attempt ${attempt + 1}) →`, res.status);\r\n\r\n if (!res.ok && attempt === 0) {\r\n setTimeout(\r\n () => fetchWithRetry(endpoint, body, headers, debug, logger, 1),\r\n RETRY_DELAY_MS\r\n );\r\n }\r\n } catch {\r\n if (attempt === 0) {\r\n setTimeout(\r\n () => fetchWithRetry(endpoint, body, headers, debug, logger, 1),\r\n RETRY_DELAY_MS\r\n );\r\n }\r\n }\r\n}\r\n","import type { InternalEvent } from './types';\r\nimport { sendBatch } from './transport';\r\nimport { Logger } from './logger';\r\n\r\nexport class Queue {\r\n private events: InternalEvent[] = [];\r\n private timer: ReturnType<typeof setInterval> | null = null;\r\n private endpoint: string;\r\n private apiKey: string;\r\n private batchSize: number;\r\n private flushInterval: number;\r\n private debug: boolean;\r\n private logger: Logger;\r\n\r\n constructor(opts: {\r\n endpoint: string;\r\n apiKey: string;\r\n batchSize: number;\r\n flushInterval: number;\r\n debug: boolean;\r\n logger: Logger;\r\n }) {\r\n this.endpoint = opts.endpoint;\r\n this.apiKey = opts.apiKey;\r\n this.batchSize = opts.batchSize;\r\n this.flushInterval = opts.flushInterval;\r\n this.debug = opts.debug;\r\n this.logger = opts.logger;\r\n }\r\n\r\n start(): void {\r\n if (this.timer !== null) return;\r\n this.timer = setInterval(() => {\r\n // console.warn(\"INTERVAL TRIGGERED\");\r\n this.logger.log('Auto-flush triggered');\r\n void this.flush();\r\n }, this.flushInterval);\r\n\r\n if (typeof document !== 'undefined') {\r\n document.addEventListener('visibilitychange', this.handleVisibility);\r\n }\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('pagehide', this.handlePageHide);\r\n }\r\n }\r\n\r\n push(event: InternalEvent): void {\r\n this.events.push(event);\r\n // console.warn(\"EVENT PUSHED. Queue length:\", this.events.length);\r\n\r\n this.logger.log(`Event queued: ${event.eventType} (queue=${this.events.length})`);\r\n if (this.events.length >= this.batchSize) {\r\n void this.flush();\r\n }\r\n }\r\n\r\n async flush(): Promise<void> {\r\n if (this.events.length === 0) return;\r\n const batch = this.events.splice(0, this.events.length);\r\n this.logger.log(`Flushing ${batch.length} event(s)`);\r\n await sendBatch(this.endpoint, this.apiKey, batch, this.debug, this.logger);\r\n }\r\n\r\n destroy(): void {\r\n // console.warn(\"⚠️ SDK QUEUE DESTROY CALLED\");\r\n\r\n if (this.timer !== null) {\r\n clearInterval(this.timer);\r\n this.timer = null;\r\n }\r\n if (typeof document !== 'undefined') {\r\n document.removeEventListener('visibilitychange', this.handleVisibility);\r\n }\r\n if (typeof window !== 'undefined') {\r\n window.removeEventListener('pagehide', this.handlePageHide);\r\n }\r\n void this.flush();\r\n }\r\n\r\n private handleVisibility = (): void => {\r\n // console.warn(\"VISIBILITY CHANGE:\", document.visibilityState);\r\n\r\n if (document.visibilityState === 'hidden') {\r\n void this.flush();\r\n }\r\n };\r\n\r\n private handlePageHide = (): void => {\r\n // console.warn(\"PAGEHIDE FLUSH\");\r\n void this.flush();\r\n };\r\n}\r\n","const VISITOR_KEY = 'vyzora_visitor_id';\r\n\r\nfunction generateUUID(): string {\r\n if (\r\n typeof crypto !== 'undefined' &&\r\n typeof crypto.randomUUID === 'function'\r\n ) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nexport function getVisitorId(): string {\r\n try {\r\n let id = localStorage.getItem(VISITOR_KEY);\r\n if (!id) {\r\n id = generateUUID();\r\n localStorage.setItem(VISITOR_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n return generateUUID();\r\n }\r\n}\r\n","const SESSION_KEY = 'vyzora_session_id';\r\nconst SESSION_TS_KEY = 'vyzora_session_ts';\r\nconst INACTIVITY_MS = 30 * 60 * 1000;\r\n\r\nfunction generateUUID(): string {\r\n if (\r\n typeof crypto !== 'undefined' &&\r\n typeof crypto.randomUUID === 'function'\r\n ) {\r\n return crypto.randomUUID();\r\n }\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nfunction now(): number {\r\n return Date.now();\r\n}\r\n\r\nexport function getSessionId(): string {\r\n try {\r\n const lastTs = parseInt(sessionStorage.getItem(SESSION_TS_KEY) ?? '0', 10);\r\n const expired = now() - lastTs > INACTIVITY_MS;\r\n\r\n let id = sessionStorage.getItem(SESSION_KEY);\r\n if (!id || expired) {\r\n id = generateUUID();\r\n sessionStorage.setItem(SESSION_KEY, id);\r\n }\r\n\r\n sessionStorage.setItem(SESSION_TS_KEY, String(now()));\r\n return id;\r\n } catch {\r\n return generateUUID();\r\n }\r\n}\r\n\r\nexport function resetSession(): void {\r\n try {\r\n sessionStorage.removeItem(SESSION_KEY);\r\n sessionStorage.removeItem(SESSION_TS_KEY);\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n","import type { AutoMetadata } from './types';\r\n\r\nfunction detectBrowser(ua: string): { browser: string; version: string } {\r\n const rules: [RegExp, string][] = [\r\n [/Edg\\/(\\S+)/, 'Edge'],\r\n [/OPR\\/(\\S+)/, 'Opera'],\r\n [/SamsungBrowser\\/(\\S+)/, 'Samsung'],\r\n [/Firefox\\/(\\S+)/, 'Firefox'],\r\n [/Chrome\\/(\\S+)/, 'Chrome'],\r\n [/Safari\\/(\\S+)/, 'Safari'],\r\n ];\r\n for (const [re, name] of rules) {\r\n const m = ua.match(re);\r\n if (m) return { browser: name, version: m[1].split('.')[0] };\r\n }\r\n return { browser: 'Unknown', version: '' };\r\n}\r\n\r\nfunction detectOS(ua: string): string {\r\n if (/Windows NT/i.test(ua)) return 'Windows';\r\n if (/Mac OS X/i.test(ua)) return 'macOS';\r\n if (/Android/i.test(ua)) return 'Android';\r\n if (/iPhone|iPad|iPod/i.test(ua)) return 'iOS';\r\n if (/Linux/i.test(ua)) return 'Linux';\r\n return 'Unknown';\r\n}\r\n\r\nfunction detectDevice(ua: string): AutoMetadata['deviceType'] {\r\n if (/Mobi/i.test(ua)) return 'mobile';\r\n if (/Tablet|iPad/i.test(ua)) return 'tablet';\r\n return 'desktop';\r\n}\r\n\r\nexport function collectMetadata(): AutoMetadata {\r\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\r\n return {};\r\n }\r\n\r\n try {\r\n const ua = navigator.userAgent;\r\n const { browser, version } = detectBrowser(ua);\r\n\r\n return {\r\n browser,\r\n browserVersion: version,\r\n os: detectOS(ua),\r\n deviceType: detectDevice(ua),\r\n screenWidth: window.screen?.width,\r\n screenHeight: window.screen?.height,\r\n language: navigator.language,\r\n referrer: document.referrer || undefined,\r\n timezone: Intl?.DateTimeFormat?.().resolvedOptions?.()?.timeZone,\r\n };\r\n } catch {\r\n return {};\r\n }\r\n}\r\n","\r\nexport class Logger {\r\n private debug: boolean;\r\n\r\n constructor(debug: boolean = false) {\r\n this.debug = debug;\r\n }\r\n\r\n log(message: string, ...args: unknown[]): void {\r\n if (!this.debug) return;\r\n console.warn(`[Vyzora] ${message}`, ...args);\r\n }\r\n\r\n warn(message: string, ...args: unknown[]): void {\r\n console.warn(`[Vyzora] ${message}`, ...args);\r\n }\r\n\r\n error(message: string, ...args: unknown[]): void {\r\n console.error(`[Vyzora] ${message}`, ...args);\r\n }\r\n}\r\n","import type { VyzoraConfig } from './types';\r\nimport { Queue } from './queue';\r\nimport { getVisitorId } from './visitor';\r\nimport { getSessionId, resetSession } from './session';\r\nimport { collectMetadata } from './metadata';\r\nimport { Logger } from './logger';\r\n\r\n// @ts-expect-error - __VYZORA_API_URL__ is injected by tsup at build-time\r\nconst DEFAULT_ENDPOINT = __VYZORA_API_URL__;\r\nconst DEFAULT_BATCH_SIZE = 20;\r\nconst DEFAULT_FLUSH_INTERVAL = 10000;\r\n\r\nexport class Vyzora {\r\n private readonly apiKey: string;\r\n private readonly endpoint: string;\r\n private readonly enabled: boolean;\r\n private readonly debug: boolean;\r\n private queue: Queue | null = null;\r\n private customVisitorId: string | null = null;\r\n private logger: Logger;\r\n private lastTrackedPath: string | null = null;\r\n\r\n constructor(config: VyzoraConfig) {\r\n if (!config.apiKey) {\r\n throw new Error('[Vyzora] apiKey is required.');\r\n }\r\n\r\n this.apiKey = config.apiKey;\r\n this.endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\r\n this.enabled = config.enabled === true;\r\n this.debug = config.debug ?? false;\r\n this.logger = new Logger(this.debug);\r\n\r\n if (!this.enabled) {\r\n this.logger.log('SDK is disabled. Set enabled: true to activate.');\r\n return;\r\n }\r\n\r\n if (typeof window === 'undefined') return;\r\n\r\n this.queue = new Queue({\r\n endpoint: this.endpoint,\r\n apiKey: this.apiKey,\r\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\r\n flushInterval: config.flushInterval ?? DEFAULT_FLUSH_INTERVAL,\r\n debug: this.debug,\r\n logger: this.logger,\r\n });\r\n this.queue.start();\r\n\r\n this.hookPageTracking();\r\n\r\n this.logger.log('SDK initialised.');\r\n }\r\n\r\n track(eventType: string, metadata?: Record<string, unknown>): void {\r\n if (!this.enabled || !this.queue) return;\r\n try {\r\n const autoMeta = collectMetadata();\r\n const merged: Record<string, unknown> = { ...autoMeta, ...metadata };\r\n\r\n this.queue.push({\r\n sessionId: getSessionId(),\r\n visitorId: this.customVisitorId ?? getVisitorId(),\r\n eventType,\r\n path: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n metadata: Object.keys(merged).length > 0 ? merged : undefined,\r\n });\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n pageview(path?: string): void {\r\n if (!this.enabled || !this.queue) return;\r\n try {\r\n const resolvedPath =\r\n path ?? (typeof window !== 'undefined' ? window.location.pathname : '/');\r\n\r\n // Avoid double tracking the same path in immediate succession (e.g. load + pushState)\r\n if (resolvedPath === this.lastTrackedPath) return;\r\n this.lastTrackedPath = resolvedPath;\r\n\r\n const autoMeta = collectMetadata();\r\n\r\n this.queue.push({\r\n sessionId: getSessionId(),\r\n visitorId: this.customVisitorId ?? getVisitorId(),\r\n eventType: 'pageview',\r\n path: resolvedPath,\r\n metadata: Object.keys(autoMeta).length > 0 ? autoMeta : undefined,\r\n });\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n identify(visitorId: string): void {\r\n if (!this.enabled) return;\r\n this.customVisitorId = visitorId;\r\n this.logger.log('Visitor identified:', visitorId);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n if (!this.enabled || !this.queue) return;\r\n await this.queue.flush();\r\n }\r\n\r\n resetSession(): void {\r\n resetSession();\r\n }\r\n\r\n destroy(): void {\r\n this.queue?.destroy();\r\n this.queue = null;\r\n }\r\n\r\n\r\n private hookPageTracking(): void {\r\n if (typeof window === 'undefined') return;\r\n\r\n // Initial pageview on load\r\n window.addEventListener('load', () => this.pageview(), { once: true });\r\n\r\n // SPA navigation — intercept history.pushState and history.replaceState\r\n this.wrapHistoryMethod('pushState');\r\n this.wrapHistoryMethod('replaceState');\r\n\r\n // Back/forward navigation\r\n window.addEventListener('popstate', () => this.pageview());\r\n }\r\n\r\n private wrapHistoryMethod(method: 'pushState' | 'replaceState'): void {\r\n const original = history[method]?.bind(history);\r\n if (typeof original !== 'function') return;\r\n\r\n history[method] = (...args) => {\r\n original(...args);\r\n this.pageview();\r\n };\r\n }\r\n}\r\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vyzora-sdk",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "Vyzora Analytics SDK — lightweight, framework-agnostic client-side event tracking",
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"lint": "eslint src --max-warnings 10",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"analytics",
|
|
31
|
+
"tracking",
|
|
32
|
+
"pageview",
|
|
33
|
+
"vyzora",
|
|
34
|
+
"sdk",
|
|
35
|
+
"lightweight"
|
|
36
|
+
],
|
|
37
|
+
"author": "Vyzora",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@eslint/js": "^9.0.0",
|
|
41
|
+
"@types/node": "^25.3.0",
|
|
42
|
+
"dotenv": "^17.3.1",
|
|
43
|
+
"eslint": "^9.0.0",
|
|
44
|
+
"tsup": "^8.5.1",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"typescript-eslint": "^8.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|