@inferevents/sdk 0.1.3 → 0.1.5

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 ADDED
@@ -0,0 +1,140 @@
1
+ # @inferevents/sdk
2
+
3
+ Event collection SDK for [Infer](https://infer.events) — analytics designed for AI agents, not dashboards.
4
+
5
+ 3KB. Zero dependencies. Auto-tracks page views, clicks, sessions, and errors out of the box.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @inferevents/sdk
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```typescript
16
+ import { init, track, identify } from "@inferevents/sdk";
17
+
18
+ init({
19
+ projectId: "pk_write_...", // your write key (safe to embed in client JS)
20
+ autoTrack: true, // auto-tracks page views, clicks, sessions, errors
21
+ });
22
+
23
+ // Track custom events
24
+ track("signup_completed", { plan: "pro" });
25
+
26
+ // Identify a user (links anonymous activity to a known user)
27
+ identify("user_123", { email: "alice@example.com" });
28
+ ```
29
+
30
+ ## API
31
+
32
+ ### `init(config)`
33
+
34
+ Initialize the SDK. Must be called before other methods (events queued before init are replayed automatically).
35
+
36
+ ```typescript
37
+ init({
38
+ projectId: string; // Required. Your write key (pk_write_...)
39
+ endpoint?: string; // API endpoint (default: https://api.infer.events)
40
+ autoTrack?: boolean; // Enable auto-tracking (default: false)
41
+ batchSize?: number; // Events per batch (default: 20)
42
+ flushInterval?: number; // Flush interval in ms (default: 10000)
43
+ debug?: boolean; // Console logging (default: false)
44
+ });
45
+ ```
46
+
47
+ ### `track(eventName, properties?)`
48
+
49
+ Track a custom event.
50
+
51
+ ```typescript
52
+ track("purchase", { amount: 49.99, currency: "USD" });
53
+ track("feature_used", { feature: "export" });
54
+ ```
55
+
56
+ ### `identify(userId, traits?)`
57
+
58
+ Link the current anonymous user to a known user ID. All past and future events are associated with this identity.
59
+
60
+ ```typescript
61
+ identify("user_123", { name: "Alice", plan: "pro" });
62
+ ```
63
+
64
+ ### `page(name?)`
65
+
66
+ Track a page view. Called automatically if `autoTrack: true`.
67
+
68
+ ```typescript
69
+ page("Pricing");
70
+ ```
71
+
72
+ ### `screen(name)`
73
+
74
+ Track a screen view (React Native / mobile).
75
+
76
+ ```typescript
77
+ screen("Settings");
78
+ ```
79
+
80
+ ### `flush()`
81
+
82
+ Manually flush the event queue. Events are batched and sent automatically, but you can force a flush.
83
+
84
+ ```typescript
85
+ await flush();
86
+ ```
87
+
88
+ ### `reset()`
89
+
90
+ Clear the current user identity. Use on logout to start a new anonymous session.
91
+
92
+ ```typescript
93
+ reset();
94
+ ```
95
+
96
+ ### `destroy()`
97
+
98
+ Tear down the SDK, clear timers and listeners.
99
+
100
+ ## Auto-tracking
101
+
102
+ When `autoTrack: true`, the SDK automatically captures:
103
+
104
+ | Event | Trigger |
105
+ |-------|---------|
106
+ | `page_view` | Page navigation (History API) |
107
+ | `session_start` | New browser session |
108
+ | `click` | Clicks on interactive elements (buttons, links) |
109
+ | `form_submit` | Form submissions |
110
+ | `error` | Uncaught JavaScript errors |
111
+
112
+ ## Context
113
+
114
+ Every event includes auto-collected context:
115
+
116
+ | Field | Source |
117
+ |-------|--------|
118
+ | `browser` | User agent |
119
+ | `os` | Parsed from UA (macOS, Windows, iOS, Android, Linux) |
120
+ | `device_type` | Mobile, Tablet, or Desktop |
121
+ | `page_url` | `window.location.href` |
122
+ | `pathname` | `window.location.pathname` |
123
+ | `referrer` | `document.referrer` |
124
+ | `locale` | `navigator.language` |
125
+ | `timezone` | `Intl.DateTimeFormat` timezone |
126
+ | `screen_width` / `screen_height` | Screen dimensions |
127
+
128
+ Server-side geo enrichment (country, city, region) is added at ingestion time.
129
+
130
+ ## How it works
131
+
132
+ - Events are queued in memory and flushed every 10 seconds (or when batch size is reached)
133
+ - On page unload, queued events are sent via `fetch` with `keepalive: true`
134
+ - Unflushed events are persisted to `localStorage` and restored on next page load
135
+ - Failed sends are retried with exponential backoff
136
+ - Each event gets a UUID for deduplication (server-side `ON CONFLICT DO NOTHING`)
137
+
138
+ ## License
139
+
140
+ MIT
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var h=false;function S(e){h=e;}function a(e,...t){h&&console.log(`[infer] ${e}`,...t);}function g(e,...t){h&&console.warn(`[infer] ${e}`,...t);}function E(e,...t){h&&console.error(`[infer] ${e}`,...t);}var b="infer_event_queue",p=1e3,i=[];function _(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function T(e){i.length>=p&&(g("Queue full, dropping oldest event"),i.shift()),i.push(e),a(`Queued event: ${e.event_name} (${i.length} in queue)`);}function I(e){return i.splice(0,e)}function m(){return i.length}function l(e){i=[...e,...i],i.length>p&&(i=i.slice(i.length-p));}function d(){let e=_();if(!(!e||i.length===0))try{e.setItem(b,JSON.stringify(i)),a("Persisted queue to localStorage:",i.length);}catch{}}function A(){let e=_();if(e)try{let t=e.getItem(b);if(t){let n=JSON.parse(t);Array.isArray(n)&&(i=[...n,...i],i.length>p&&(i=i.slice(i.length-p)),a("Restored queue from localStorage:",n.length)),e.removeItem(b);}}catch{}}var P="0.1.0";function Q(){return typeof window<"u"&&typeof document<"u"}function C(){let e={platform:"web",sdk_version:P};if(!Q())return e;typeof navigator<"u"&&(e.browser=navigator.userAgent,e.locale=navigator.language),typeof screen<"u"&&(e.screen_width=screen.width,e.screen_height=screen.height);try{e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;}catch{}return e.page_url=window.location.href,e.pathname=window.location.pathname,e.page_title=document.title,e.referrer=document.referrer||void 0,e.os=q(navigator.userAgent),e.device_type=D(navigator.userAgent),e}function q(e){return /Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iPhone|iPad|iPod/.test(e)?"iOS":/Linux/.test(e)?"Linux":/CrOS/.test(e)?"ChromeOS":"Unknown"}function D(e){return /Mobi|Android.*Mobile|iPhone|iPod/.test(e)?"Mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)?"Tablet":"Desktop"}var k="infer_anonymous_id",u=null,y=null,v={};function x(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function R(){if(u)return u;let e=x();if(e){let t=e.getItem(k);if(t)return u=t,u}if(u=crypto.randomUUID(),a("Generated anonymous_id:",u),e)try{e.setItem(k,u);}catch{}return u}function L(){return y}function N(e,t){y=e,t&&(v={...v,...t}),a("Identity set:",y,v);}function $(){y=null,v={},u=null;let e=x();if(e)try{e.removeItem(k);}catch{}}var O="infer_session_last_active";var U={pageView:true,session:true,click:true,formSubmit:true,error:true};function j(e){return e===false?null:e===true?{...U}:{...U,...e}}function M(e,t){if(typeof window>"u")return ()=>{};let n=[];return t.session&&z(e),t.pageView&&n.push(B(e)),t.click&&n.push(F(e)),t.formSubmit&&n.push(Y(e)),t.error&&n.push(V(e)),()=>{for(let r of n)r();}}function z(e){try{let t=Date.now(),n=sessionStorage.getItem(O);(!n||t-Number(n)>18e5)&&e.trackInternal("session_start",{}),sessionStorage.setItem(O,String(t));}catch{}}function B(e){e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});let t=history.pushState.bind(history),n=history.replaceState.bind(history),r=()=>{e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});};return history.pushState=function(...o){t(...o),r();},history.replaceState=function(...o){n(...o),r();},window.addEventListener("popstate",r),()=>{history.pushState=t,history.replaceState=n,window.removeEventListener("popstate",r);}}function F(e){let t=n=>{let r=n.target;if(!r)return;let o=r.closest("a, button, [role='button'], input[type='submit']");if(!o)return;let c={tag:o.tagName.toLowerCase()};o.id&&(c.element_id=o.id),o.className&&typeof o.className=="string"&&(c.element_class=o.className),o.tagName==="A"&&(c.href=o.href),e.trackInternal("click",c);};return document.addEventListener("click",t,{capture:true}),()=>document.removeEventListener("click",t,{capture:true})}function Y(e){let t=n=>{let r=n.target;if(!r)return;let o={};r.id&&(o.form_id=r.id),r.action&&(o.form_action=r.action),r.method&&(o.form_method=r.method.toUpperCase()),e.trackInternal("form_submit",o);};return document.addEventListener("submit",t,{capture:true}),()=>document.removeEventListener("submit",t,{capture:true})}function V(e){let t=r=>{e.trackInternal("error",{message:r.message||"Unknown error",filename:r.filename||null,lineno:r.lineno||null,colno:r.colno||null});},n=r=>{let o=r.reason instanceof Error?r.reason.message:typeof r.reason=="string"?r.reason:"Unhandled promise rejection";e.trackInternal("error",{message:o,type:"unhandledrejection"});};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",n);}}var H="https://api.infer.events",J=20,K=1e4,X=3e4,Z=1e3,w=class{config;flushTimer=null;teardownAutoTrack=null;flushing=false;retryCount=0;constructor(t){if(!t.projectId||typeof t.projectId!="string")throw new Error("[infer] projectId is required");if(S(t.debug??false),this.config={projectId:t.projectId,endpoint:t.endpoint??H,batchSize:t.batchSize??J,flushInterval:t.flushInterval??K},a("Initialized with config:",this.config),A(),this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval),typeof window<"u"){let r=()=>{d(),this.sendBeacon();};window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&r();}),window.addEventListener("pagehide",r);}let n=j(t.autoTrack??false);n&&(this.teardownAutoTrack=M(this,n));}track(t,n){this.enqueueEvent("track",t,n??{});}identify(t,n){N(t,n),this.enqueueEvent("identify","identify",n??{});}page(t){let n={};t&&(n.name=t),typeof window<"u"&&(n.url=window.location.href,n.path=window.location.pathname,n.title=document.title),this.enqueueEvent("page","page_view",n);}screen(t){this.enqueueEvent("screen","screen_view",{name:t});}trackInternal(t,n){this.enqueueEvent("track",t,n);}async flush(){if(this.flushing||m()===0)return;this.flushing=true;let t=I(this.config.batchSize);a(`Flushing ${t.length} events`);try{let n=await fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t})});n.ok?(this.retryCount=0,a(`Flushed ${t.length} events successfully`)):n.status>=500?(g(`Server error ${n.status}, will retry`),l(t),this.scheduleRetry()):E(`Client error ${n.status}, dropping batch`);}catch(n){g("Network error, will retry:",n),l(t),this.scheduleRetry();}finally{this.flushing=false;}m()>0&&this.flush();}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoTrack&&(this.teardownAutoTrack(),this.teardownAutoTrack=null),d();}enqueueEvent(t,n,r){let o={event_id:crypto.randomUUID(),project_id:this.config.projectId,anonymous_id:R(),event_name:n,event_type:t,properties:r,context:C(),timestamp:new Date().toISOString()},c=L();c&&(o.user_id=c),T(o),m()>=this.config.batchSize&&this.flush();}sendBeacon(){let t=I(this.config.batchSize);if(t.length!==0)try{fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t}),keepalive:!0}).then(n=>{n.ok?a(`Beacon sent ${t.length} events`):(l(t),d());}).catch(()=>{l(t),d();});}catch{l(t),d();}}scheduleRetry(){this.retryCount++;let t=Math.min(Z*Math.pow(2,this.retryCount-1)+Math.random()*1e3,X);a(`Retry #${this.retryCount} in ${Math.round(t)}ms`),setTimeout(()=>{this.flush();},t);}};var s=null,f=[];function fe(e){s&&s.destroy(),s=new w(e);for(let t of f)switch(t.type){case "track":s.track(...t.args);break;case "identify":s.identify(...t.args);break;case "page":s.page(...t.args);break;case "screen":s.screen(...t.args);break}return f=[],s}function ge(e,t){if(!s){f.push({type:"track",args:[e,t]});return}s.track(e,t);}function pe(e,t){if(!s){f.push({type:"identify",args:[e,t]});return}s.identify(e,t);}function he(e){if(!s){f.push({type:"page",args:[e]});return}s.page(e);}function me(e){if(!s){f.push({type:"screen",args:[e]});return}s.screen(e);}async function ve(){s&&await s.flush();}function ye(){s&&(s.destroy(),s=null);}
2
- exports.destroy=ye;exports.flush=ve;exports.identify=pe;exports.init=fe;exports.page=he;exports.reset=$;exports.screen=me;exports.track=ge;
1
+ 'use strict';var h=false;function E(e){h=e;}function a(e,...t){h&&console.log(`[infer] ${e}`,...t);}function g(e,...t){h&&console.warn(`[infer] ${e}`,...t);}function w(e,...t){h&&console.error(`[infer] ${e}`,...t);}var I="infer_event_queue",p=1e3,i=[];function _(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function T(e){i.length>=p&&(g("Queue full, dropping oldest event"),i.shift()),i.push(e),a(`Queued event: ${e.event_name} (${i.length} in queue)`);}function S(e){return i.splice(0,e)}function m(){return i.length}function l(e){i=[...e,...i],i.length>p&&(i=i.slice(i.length-p));}function d(){let e=_();if(!(!e||i.length===0))try{e.setItem(I,JSON.stringify(i)),a("Persisted queue to localStorage:",i.length);}catch{}}function C(){let e=_();if(e)try{let t=e.getItem(I);if(t){let n=JSON.parse(t);Array.isArray(n)&&(i=[...n,...i],i.length>p&&(i=i.slice(i.length-p)),a("Restored queue from localStorage:",n.length)),e.removeItem(I);}}catch{}}var Q="0.1.0";function $(){return typeof window<"u"&&typeof document<"u"}function A(){let e={platform:"web",sdk_version:Q};if(!$())return e;typeof navigator<"u"&&(e.browser=navigator.userAgent,e.locale=navigator.language),typeof screen<"u"&&(e.screen_width=screen.width,e.screen_height=screen.height);try{e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;}catch{}return e.page_url=window.location.href,e.pathname=window.location.pathname,e.page_title=document.title,e.referrer=document.referrer||void 0,e.os=q(navigator.userAgent),e.device_type=D(navigator.userAgent),e}function q(e){return /Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iPhone|iPad|iPod/.test(e)?"iOS":/Linux/.test(e)?"Linux":/CrOS/.test(e)?"ChromeOS":"Unknown"}function D(e){return /Mobi|Android.*Mobile|iPhone|iPod/.test(e)?"Mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)?"Tablet":"Desktop"}var k="infer_anonymous_id",u=null,y=null,v={};function x(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function R(){if(u)return u;let e=x();if(e){let t=e.getItem(k);if(t)return u=t,u}if(u=crypto.randomUUID(),a("Generated anonymous_id:",u),e)try{e.setItem(k,u);}catch{}return u}function L(){return y}function N(e,t){y=e,t&&(v={...v,...t}),a("Identity set:",y,v);}function z(){y=null,v={},u=null;let e=x();if(e)try{e.removeItem(k);}catch{}}var O="infer_session_last_active";var U={pageView:true,session:true,click:true,formSubmit:true,error:true};function j(e){return e===false?null:e===true?{...U}:{...U,...e}}function M(e,t){if(typeof window>"u")return ()=>{};let n=[];return t.session&&B(e),t.pageView&&n.push(F(e)),t.click&&n.push(Y(e)),t.formSubmit&&n.push(V(e)),t.error&&n.push(H(e)),()=>{for(let r of n)r();}}function B(e){try{let t=Date.now(),n=sessionStorage.getItem(O);(!n||t-Number(n)>18e5)&&e.trackInternal("session_start",{}),sessionStorage.setItem(O,String(t));}catch{}}function F(e){e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});let t=history.pushState.bind(history),n=history.replaceState.bind(history),r=()=>{e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});};return history.pushState=function(...o){t(...o),r();},history.replaceState=function(...o){n(...o),r();},window.addEventListener("popstate",r),()=>{history.pushState=t,history.replaceState=n,window.removeEventListener("popstate",r);}}function Y(e){let t=n=>{let r=n.target;if(!r)return;let o=r.closest("a, button, [role='button'], input[type='submit']");if(!o)return;let c={tag:o.tagName.toLowerCase()};o.id&&(c.element_id=o.id),o.className&&typeof o.className=="string"&&(c.element_class=o.className),o.tagName==="A"&&(c.href=o.href),e.trackInternal("click",c);};return document.addEventListener("click",t,{capture:true}),()=>document.removeEventListener("click",t,{capture:true})}function V(e){let t=n=>{let r=n.target;if(!r)return;let o={};r.id&&(o.form_id=r.id),r.action&&(o.form_action=r.action),r.method&&(o.form_method=r.method.toUpperCase()),e.trackInternal("form_submit",o);};return document.addEventListener("submit",t,{capture:true}),()=>document.removeEventListener("submit",t,{capture:true})}function H(e){let t=r=>{e.trackInternal("error",{message:r.message||"Unknown error",filename:r.filename||null,lineno:r.lineno||null,colno:r.colno||null});},n=r=>{let o=r.reason instanceof Error?r.reason.message:typeof r.reason=="string"?r.reason:"Unhandled promise rejection";e.trackInternal("error",{message:o,type:"unhandledrejection"});};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",n);}}var J="https://api.infer.events",K=20,X=1e4,Z=3e4,W=1e3,P=5,b=class{config;flushTimer=null;teardownAutoTrack=null;flushing=false;retryCount=0;disabled=false;constructor(t){if(!t.projectId||typeof t.projectId!="string")throw new Error("[infer] projectId is required");if(E(t.debug??false),this.config={projectId:t.projectId,endpoint:t.endpoint??J,batchSize:t.batchSize??K,flushInterval:t.flushInterval??X},a("Initialized with config:",this.config),C(),this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval),typeof window<"u"){let r=()=>{d(),this.sendBeacon();};window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&r();}),window.addEventListener("pagehide",r);}let n=j(t.autoTrack??false);n&&(this.teardownAutoTrack=M(this,n));}track(t,n){this.enqueueEvent("track",t,n??{});}identify(t,n){N(t,n),this.enqueueEvent("identify","identify",n??{});}page(t){let n={};t&&(n.name=t),typeof window<"u"&&(n.url=window.location.href,n.path=window.location.pathname,n.title=document.title),this.enqueueEvent("page","page_view",n);}screen(t){this.enqueueEvent("screen","screen_view",{name:t});}trackInternal(t,n){this.enqueueEvent("track",t,n);}async flush(){if(this.disabled||this.flushing||m()===0)return;this.flushing=true;let t=S(this.config.batchSize);a(`Flushing ${t.length} events`);try{let n=await fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t})});n.ok?(this.retryCount=0,a(`Flushed ${t.length} events successfully`)):n.status>=500?(g(`Server error ${n.status}, will retry`),l(t),this.scheduleRetry()):w(`Client error ${n.status}, dropping batch`);}catch(n){if(this.retryCount>=P){w(`Cannot connect to ${this.config.endpoint} after ${P} attempts. If your site uses a Content Security Policy, add ${this.config.endpoint} to connect-src. Events will be dropped until the page is reloaded.`),this.disabled=true;return}g("Network error, will retry:",n),l(t),this.scheduleRetry();}finally{this.flushing=false;}m()>0&&this.flush();}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoTrack&&(this.teardownAutoTrack(),this.teardownAutoTrack=null),d();}enqueueEvent(t,n,r){let o={event_id:crypto.randomUUID(),project_id:this.config.projectId,anonymous_id:R(),event_name:n,event_type:t,properties:r,context:A(),timestamp:new Date().toISOString()},c=L();c&&(o.user_id=c),T(o),m()>=this.config.batchSize&&this.flush();}sendBeacon(){let t=S(this.config.batchSize);if(t.length!==0)try{fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t}),keepalive:!0}).then(n=>{n.ok?a(`Beacon sent ${t.length} events`):(l(t),d());}).catch(()=>{l(t),d();});}catch{l(t),d();}}scheduleRetry(){this.retryCount++;let t=Math.min(W*Math.pow(2,this.retryCount-1)+Math.random()*1e3,Z);a(`Retry #${this.retryCount} in ${Math.round(t)}ms`),setTimeout(()=>{this.flush();},t);}};var s=null,f=[];function ge(e){s&&s.destroy(),s=new b(e);for(let t of f)switch(t.type){case "track":s.track(...t.args);break;case "identify":s.identify(...t.args);break;case "page":s.page(...t.args);break;case "screen":s.screen(...t.args);break}return f=[],s}function pe(e,t){if(!s){f.push({type:"track",args:[e,t]});return}s.track(e,t);}function he(e,t){if(!s){f.push({type:"identify",args:[e,t]});return}s.identify(e,t);}function me(e){if(!s){f.push({type:"page",args:[e]});return}s.page(e);}function ve(e){if(!s){f.push({type:"screen",args:[e]});return}s.screen(e);}async function ye(){s&&await s.flush();}function be(){s&&(s.destroy(),s=null);}
2
+ exports.destroy=be;exports.flush=ye;exports.identify=he;exports.init=ge;exports.page=me;exports.reset=z;exports.screen=ve;exports.track=pe;
package/dist/index.d.cts CHANGED
@@ -20,6 +20,7 @@ declare class InferClient {
20
20
  private teardownAutoTrack;
21
21
  private flushing;
22
22
  private retryCount;
23
+ private disabled;
23
24
  constructor(config: InferConfig);
24
25
  track(eventName: string, properties?: Record<string, string | number | boolean | null>): void;
25
26
  identify(newUserId: string, traits?: Record<string, string | number | boolean | null>): void;
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ declare class InferClient {
20
20
  private teardownAutoTrack;
21
21
  private flushing;
22
22
  private retryCount;
23
+ private disabled;
23
24
  constructor(config: InferConfig);
24
25
  track(eventName: string, properties?: Record<string, string | number | boolean | null>): void;
25
26
  identify(newUserId: string, traits?: Record<string, string | number | boolean | null>): void;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var h=false;function S(e){h=e;}function a(e,...t){h&&console.log(`[infer] ${e}`,...t);}function g(e,...t){h&&console.warn(`[infer] ${e}`,...t);}function E(e,...t){h&&console.error(`[infer] ${e}`,...t);}var b="infer_event_queue",p=1e3,i=[];function _(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function T(e){i.length>=p&&(g("Queue full, dropping oldest event"),i.shift()),i.push(e),a(`Queued event: ${e.event_name} (${i.length} in queue)`);}function I(e){return i.splice(0,e)}function m(){return i.length}function l(e){i=[...e,...i],i.length>p&&(i=i.slice(i.length-p));}function d(){let e=_();if(!(!e||i.length===0))try{e.setItem(b,JSON.stringify(i)),a("Persisted queue to localStorage:",i.length);}catch{}}function A(){let e=_();if(e)try{let t=e.getItem(b);if(t){let n=JSON.parse(t);Array.isArray(n)&&(i=[...n,...i],i.length>p&&(i=i.slice(i.length-p)),a("Restored queue from localStorage:",n.length)),e.removeItem(b);}}catch{}}var P="0.1.0";function Q(){return typeof window<"u"&&typeof document<"u"}function C(){let e={platform:"web",sdk_version:P};if(!Q())return e;typeof navigator<"u"&&(e.browser=navigator.userAgent,e.locale=navigator.language),typeof screen<"u"&&(e.screen_width=screen.width,e.screen_height=screen.height);try{e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;}catch{}return e.page_url=window.location.href,e.pathname=window.location.pathname,e.page_title=document.title,e.referrer=document.referrer||void 0,e.os=q(navigator.userAgent),e.device_type=D(navigator.userAgent),e}function q(e){return /Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iPhone|iPad|iPod/.test(e)?"iOS":/Linux/.test(e)?"Linux":/CrOS/.test(e)?"ChromeOS":"Unknown"}function D(e){return /Mobi|Android.*Mobile|iPhone|iPod/.test(e)?"Mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)?"Tablet":"Desktop"}var k="infer_anonymous_id",u=null,y=null,v={};function x(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function R(){if(u)return u;let e=x();if(e){let t=e.getItem(k);if(t)return u=t,u}if(u=crypto.randomUUID(),a("Generated anonymous_id:",u),e)try{e.setItem(k,u);}catch{}return u}function L(){return y}function N(e,t){y=e,t&&(v={...v,...t}),a("Identity set:",y,v);}function $(){y=null,v={},u=null;let e=x();if(e)try{e.removeItem(k);}catch{}}var O="infer_session_last_active";var U={pageView:true,session:true,click:true,formSubmit:true,error:true};function j(e){return e===false?null:e===true?{...U}:{...U,...e}}function M(e,t){if(typeof window>"u")return ()=>{};let n=[];return t.session&&z(e),t.pageView&&n.push(B(e)),t.click&&n.push(F(e)),t.formSubmit&&n.push(Y(e)),t.error&&n.push(V(e)),()=>{for(let r of n)r();}}function z(e){try{let t=Date.now(),n=sessionStorage.getItem(O);(!n||t-Number(n)>18e5)&&e.trackInternal("session_start",{}),sessionStorage.setItem(O,String(t));}catch{}}function B(e){e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});let t=history.pushState.bind(history),n=history.replaceState.bind(history),r=()=>{e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});};return history.pushState=function(...o){t(...o),r();},history.replaceState=function(...o){n(...o),r();},window.addEventListener("popstate",r),()=>{history.pushState=t,history.replaceState=n,window.removeEventListener("popstate",r);}}function F(e){let t=n=>{let r=n.target;if(!r)return;let o=r.closest("a, button, [role='button'], input[type='submit']");if(!o)return;let c={tag:o.tagName.toLowerCase()};o.id&&(c.element_id=o.id),o.className&&typeof o.className=="string"&&(c.element_class=o.className),o.tagName==="A"&&(c.href=o.href),e.trackInternal("click",c);};return document.addEventListener("click",t,{capture:true}),()=>document.removeEventListener("click",t,{capture:true})}function Y(e){let t=n=>{let r=n.target;if(!r)return;let o={};r.id&&(o.form_id=r.id),r.action&&(o.form_action=r.action),r.method&&(o.form_method=r.method.toUpperCase()),e.trackInternal("form_submit",o);};return document.addEventListener("submit",t,{capture:true}),()=>document.removeEventListener("submit",t,{capture:true})}function V(e){let t=r=>{e.trackInternal("error",{message:r.message||"Unknown error",filename:r.filename||null,lineno:r.lineno||null,colno:r.colno||null});},n=r=>{let o=r.reason instanceof Error?r.reason.message:typeof r.reason=="string"?r.reason:"Unhandled promise rejection";e.trackInternal("error",{message:o,type:"unhandledrejection"});};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",n);}}var H="https://api.infer.events",J=20,K=1e4,X=3e4,Z=1e3,w=class{config;flushTimer=null;teardownAutoTrack=null;flushing=false;retryCount=0;constructor(t){if(!t.projectId||typeof t.projectId!="string")throw new Error("[infer] projectId is required");if(S(t.debug??false),this.config={projectId:t.projectId,endpoint:t.endpoint??H,batchSize:t.batchSize??J,flushInterval:t.flushInterval??K},a("Initialized with config:",this.config),A(),this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval),typeof window<"u"){let r=()=>{d(),this.sendBeacon();};window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&r();}),window.addEventListener("pagehide",r);}let n=j(t.autoTrack??false);n&&(this.teardownAutoTrack=M(this,n));}track(t,n){this.enqueueEvent("track",t,n??{});}identify(t,n){N(t,n),this.enqueueEvent("identify","identify",n??{});}page(t){let n={};t&&(n.name=t),typeof window<"u"&&(n.url=window.location.href,n.path=window.location.pathname,n.title=document.title),this.enqueueEvent("page","page_view",n);}screen(t){this.enqueueEvent("screen","screen_view",{name:t});}trackInternal(t,n){this.enqueueEvent("track",t,n);}async flush(){if(this.flushing||m()===0)return;this.flushing=true;let t=I(this.config.batchSize);a(`Flushing ${t.length} events`);try{let n=await fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t})});n.ok?(this.retryCount=0,a(`Flushed ${t.length} events successfully`)):n.status>=500?(g(`Server error ${n.status}, will retry`),l(t),this.scheduleRetry()):E(`Client error ${n.status}, dropping batch`);}catch(n){g("Network error, will retry:",n),l(t),this.scheduleRetry();}finally{this.flushing=false;}m()>0&&this.flush();}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoTrack&&(this.teardownAutoTrack(),this.teardownAutoTrack=null),d();}enqueueEvent(t,n,r){let o={event_id:crypto.randomUUID(),project_id:this.config.projectId,anonymous_id:R(),event_name:n,event_type:t,properties:r,context:C(),timestamp:new Date().toISOString()},c=L();c&&(o.user_id=c),T(o),m()>=this.config.batchSize&&this.flush();}sendBeacon(){let t=I(this.config.batchSize);if(t.length!==0)try{fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t}),keepalive:!0}).then(n=>{n.ok?a(`Beacon sent ${t.length} events`):(l(t),d());}).catch(()=>{l(t),d();});}catch{l(t),d();}}scheduleRetry(){this.retryCount++;let t=Math.min(Z*Math.pow(2,this.retryCount-1)+Math.random()*1e3,X);a(`Retry #${this.retryCount} in ${Math.round(t)}ms`),setTimeout(()=>{this.flush();},t);}};var s=null,f=[];function fe(e){s&&s.destroy(),s=new w(e);for(let t of f)switch(t.type){case "track":s.track(...t.args);break;case "identify":s.identify(...t.args);break;case "page":s.page(...t.args);break;case "screen":s.screen(...t.args);break}return f=[],s}function ge(e,t){if(!s){f.push({type:"track",args:[e,t]});return}s.track(e,t);}function pe(e,t){if(!s){f.push({type:"identify",args:[e,t]});return}s.identify(e,t);}function he(e){if(!s){f.push({type:"page",args:[e]});return}s.page(e);}function me(e){if(!s){f.push({type:"screen",args:[e]});return}s.screen(e);}async function ve(){s&&await s.flush();}function ye(){s&&(s.destroy(),s=null);}
2
- export{ye as destroy,ve as flush,pe as identify,fe as init,he as page,$ as reset,me as screen,ge as track};
1
+ var h=false;function E(e){h=e;}function a(e,...t){h&&console.log(`[infer] ${e}`,...t);}function g(e,...t){h&&console.warn(`[infer] ${e}`,...t);}function w(e,...t){h&&console.error(`[infer] ${e}`,...t);}var I="infer_event_queue",p=1e3,i=[];function _(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function T(e){i.length>=p&&(g("Queue full, dropping oldest event"),i.shift()),i.push(e),a(`Queued event: ${e.event_name} (${i.length} in queue)`);}function S(e){return i.splice(0,e)}function m(){return i.length}function l(e){i=[...e,...i],i.length>p&&(i=i.slice(i.length-p));}function d(){let e=_();if(!(!e||i.length===0))try{e.setItem(I,JSON.stringify(i)),a("Persisted queue to localStorage:",i.length);}catch{}}function C(){let e=_();if(e)try{let t=e.getItem(I);if(t){let n=JSON.parse(t);Array.isArray(n)&&(i=[...n,...i],i.length>p&&(i=i.slice(i.length-p)),a("Restored queue from localStorage:",n.length)),e.removeItem(I);}}catch{}}var Q="0.1.0";function $(){return typeof window<"u"&&typeof document<"u"}function A(){let e={platform:"web",sdk_version:Q};if(!$())return e;typeof navigator<"u"&&(e.browser=navigator.userAgent,e.locale=navigator.language),typeof screen<"u"&&(e.screen_width=screen.width,e.screen_height=screen.height);try{e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone;}catch{}return e.page_url=window.location.href,e.pathname=window.location.pathname,e.page_title=document.title,e.referrer=document.referrer||void 0,e.os=q(navigator.userAgent),e.device_type=D(navigator.userAgent),e}function q(e){return /Windows/.test(e)?"Windows":/Mac OS X/.test(e)?"macOS":/Android/.test(e)?"Android":/iPhone|iPad|iPod/.test(e)?"iOS":/Linux/.test(e)?"Linux":/CrOS/.test(e)?"ChromeOS":"Unknown"}function D(e){return /Mobi|Android.*Mobile|iPhone|iPod/.test(e)?"Mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(e)?"Tablet":"Desktop"}var k="infer_anonymous_id",u=null,y=null,v={};function x(){try{return typeof localStorage<"u"?localStorage:null}catch{return null}}function R(){if(u)return u;let e=x();if(e){let t=e.getItem(k);if(t)return u=t,u}if(u=crypto.randomUUID(),a("Generated anonymous_id:",u),e)try{e.setItem(k,u);}catch{}return u}function L(){return y}function N(e,t){y=e,t&&(v={...v,...t}),a("Identity set:",y,v);}function z(){y=null,v={},u=null;let e=x();if(e)try{e.removeItem(k);}catch{}}var O="infer_session_last_active";var U={pageView:true,session:true,click:true,formSubmit:true,error:true};function j(e){return e===false?null:e===true?{...U}:{...U,...e}}function M(e,t){if(typeof window>"u")return ()=>{};let n=[];return t.session&&B(e),t.pageView&&n.push(F(e)),t.click&&n.push(Y(e)),t.formSubmit&&n.push(V(e)),t.error&&n.push(H(e)),()=>{for(let r of n)r();}}function B(e){try{let t=Date.now(),n=sessionStorage.getItem(O);(!n||t-Number(n)>18e5)&&e.trackInternal("session_start",{}),sessionStorage.setItem(O,String(t));}catch{}}function F(e){e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});let t=history.pushState.bind(history),n=history.replaceState.bind(history),r=()=>{e.trackInternal("page_view",{url:window.location.href,path:window.location.pathname,title:document.title});};return history.pushState=function(...o){t(...o),r();},history.replaceState=function(...o){n(...o),r();},window.addEventListener("popstate",r),()=>{history.pushState=t,history.replaceState=n,window.removeEventListener("popstate",r);}}function Y(e){let t=n=>{let r=n.target;if(!r)return;let o=r.closest("a, button, [role='button'], input[type='submit']");if(!o)return;let c={tag:o.tagName.toLowerCase()};o.id&&(c.element_id=o.id),o.className&&typeof o.className=="string"&&(c.element_class=o.className),o.tagName==="A"&&(c.href=o.href),e.trackInternal("click",c);};return document.addEventListener("click",t,{capture:true}),()=>document.removeEventListener("click",t,{capture:true})}function V(e){let t=n=>{let r=n.target;if(!r)return;let o={};r.id&&(o.form_id=r.id),r.action&&(o.form_action=r.action),r.method&&(o.form_method=r.method.toUpperCase()),e.trackInternal("form_submit",o);};return document.addEventListener("submit",t,{capture:true}),()=>document.removeEventListener("submit",t,{capture:true})}function H(e){let t=r=>{e.trackInternal("error",{message:r.message||"Unknown error",filename:r.filename||null,lineno:r.lineno||null,colno:r.colno||null});},n=r=>{let o=r.reason instanceof Error?r.reason.message:typeof r.reason=="string"?r.reason:"Unhandled promise rejection";e.trackInternal("error",{message:o,type:"unhandledrejection"});};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",n);}}var J="https://api.infer.events",K=20,X=1e4,Z=3e4,W=1e3,P=5,b=class{config;flushTimer=null;teardownAutoTrack=null;flushing=false;retryCount=0;disabled=false;constructor(t){if(!t.projectId||typeof t.projectId!="string")throw new Error("[infer] projectId is required");if(E(t.debug??false),this.config={projectId:t.projectId,endpoint:t.endpoint??J,batchSize:t.batchSize??K,flushInterval:t.flushInterval??X},a("Initialized with config:",this.config),C(),this.flushTimer=setInterval(()=>{this.flush();},this.config.flushInterval),typeof window<"u"){let r=()=>{d(),this.sendBeacon();};window.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&r();}),window.addEventListener("pagehide",r);}let n=j(t.autoTrack??false);n&&(this.teardownAutoTrack=M(this,n));}track(t,n){this.enqueueEvent("track",t,n??{});}identify(t,n){N(t,n),this.enqueueEvent("identify","identify",n??{});}page(t){let n={};t&&(n.name=t),typeof window<"u"&&(n.url=window.location.href,n.path=window.location.pathname,n.title=document.title),this.enqueueEvent("page","page_view",n);}screen(t){this.enqueueEvent("screen","screen_view",{name:t});}trackInternal(t,n){this.enqueueEvent("track",t,n);}async flush(){if(this.disabled||this.flushing||m()===0)return;this.flushing=true;let t=S(this.config.batchSize);a(`Flushing ${t.length} events`);try{let n=await fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t})});n.ok?(this.retryCount=0,a(`Flushed ${t.length} events successfully`)):n.status>=500?(g(`Server error ${n.status}, will retry`),l(t),this.scheduleRetry()):w(`Client error ${n.status}, dropping batch`);}catch(n){if(this.retryCount>=P){w(`Cannot connect to ${this.config.endpoint} after ${P} attempts. If your site uses a Content Security Policy, add ${this.config.endpoint} to connect-src. Events will be dropped until the page is reloaded.`),this.disabled=true;return}g("Network error, will retry:",n),l(t),this.scheduleRetry();}finally{this.flushing=false;}m()>0&&this.flush();}destroy(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.teardownAutoTrack&&(this.teardownAutoTrack(),this.teardownAutoTrack=null),d();}enqueueEvent(t,n,r){let o={event_id:crypto.randomUUID(),project_id:this.config.projectId,anonymous_id:R(),event_name:n,event_type:t,properties:r,context:A(),timestamp:new Date().toISOString()},c=L();c&&(o.user_id=c),T(o),m()>=this.config.batchSize&&this.flush();}sendBeacon(){let t=S(this.config.batchSize);if(t.length!==0)try{fetch(`${this.config.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.projectId}`},body:JSON.stringify({events:t}),keepalive:!0}).then(n=>{n.ok?a(`Beacon sent ${t.length} events`):(l(t),d());}).catch(()=>{l(t),d();});}catch{l(t),d();}}scheduleRetry(){this.retryCount++;let t=Math.min(W*Math.pow(2,this.retryCount-1)+Math.random()*1e3,Z);a(`Retry #${this.retryCount} in ${Math.round(t)}ms`),setTimeout(()=>{this.flush();},t);}};var s=null,f=[];function ge(e){s&&s.destroy(),s=new b(e);for(let t of f)switch(t.type){case "track":s.track(...t.args);break;case "identify":s.identify(...t.args);break;case "page":s.page(...t.args);break;case "screen":s.screen(...t.args);break}return f=[],s}function pe(e,t){if(!s){f.push({type:"track",args:[e,t]});return}s.track(e,t);}function he(e,t){if(!s){f.push({type:"identify",args:[e,t]});return}s.identify(e,t);}function me(e){if(!s){f.push({type:"page",args:[e]});return}s.page(e);}function ve(e){if(!s){f.push({type:"screen",args:[e]});return}s.screen(e);}async function ye(){s&&await s.flush();}function be(){s&&(s.destroy(),s=null);}
2
+ export{be as destroy,ye as flush,he as identify,ge as init,me as page,z as reset,ve as screen,pe as track};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inferevents/sdk",
3
- "version": "0.1.3",
4
- "description": "Lightweight JavaScript SDK for Infer analytics",
3
+ "version": "0.1.5",
4
+ "description": "Event collection SDK for Infer analytics designed for AI agents, not dashboards",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -19,7 +19,8 @@
19
19
  }
20
20
  },
21
21
  "files": [
22
- "dist"
22
+ "dist",
23
+ "README.md"
23
24
  ],
24
25
  "scripts": {
25
26
  "build": "tsup",