@prodantix/sdk 0.0.1-beta.319

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bomdisoft
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # Prodantix SDK
2
+
3
+ Isomorphic, zero-dependency analytics + feature-flag client for Prodantix. Runs in the
4
+ browser, Node, and edge runtimes. Ships dual ESM/CJS with full TypeScript types.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ bun add @prodantix/sdk
10
+ ```
11
+
12
+ ## Browser
13
+
14
+ ```ts
15
+ import { createWebClient } from '@prodantix/sdk/web'
16
+
17
+ // PRODANTIX_PUBLIC_KEY is your pdx_pub_… project key, injected at build time.
18
+ const prodantix = createWebClient({
19
+ apiKey: PRODANTIX_PUBLIC_KEY,
20
+ host: 'https://eu.api.prodantix.com',
21
+ flagsHost: 'https://api.prodantix.com',
22
+ })
23
+
24
+ prodantix.capture('order.completed', { properties: { amount: 4200, currency: 'XAF' } })
25
+ prodantix.identify('user-42', { set: { plan: 'pro' } })
26
+
27
+ if (await prodantix.isFeatureEnabled('new-checkout')) {
28
+ // ...
29
+ }
30
+ ```
31
+
32
+ `createWebClient` wires `localStorage` persistence, `navigator.sendBeacon` delivery on page
33
+ hide, and pageview + click autocapture. Pass `autocapture: false` to disable capture, or
34
+ `autocaptureOptions: { pageviews, clicks }` to tune it.
35
+
36
+ ## Node / server
37
+
38
+ ```ts
39
+ import { createNodeClient } from '@prodantix/sdk/node'
40
+
41
+ const prodantix = createNodeClient({
42
+ apiKey: process.env.PRODANTIX_PUBLIC_KEY,
43
+ host: 'https://eu.api.prodantix.com',
44
+ })
45
+
46
+ prodantix.capture('job.completed', { properties: { queue: 'emails' } })
47
+ await prodantix.shutdown() // flush before exit
48
+ ```
49
+
50
+ ## Core
51
+
52
+ `ProdantixClient` (exported from the package root) is the runtime-agnostic core. The `web`
53
+ and `node` entrypoints are thin wrappers that inject the right storage, transport, and
54
+ lifecycle hooks. Provide your own `storage`, `transport`, `clock`, or `ids` to run it
55
+ anywhere.
56
+
57
+ ## API
58
+
59
+ | Method | Purpose |
60
+ | --- | --- |
61
+ | `capture(name, { properties?, sessionId?, timestamp? })` | Record an event. Names are lowercase-dotted (`order.completed`). |
62
+ | `identify(distinctId, { set? })` | Bind the current anonymous identity to a known user; merges history server-side. |
63
+ | `alias(alias)` | Link an additional id to the current user. |
64
+ | `group(type, key, properties?)` | Associate the user with a group. |
65
+ | `setPersonProperties(set?, setOnce?)` | Update person properties. |
66
+ | `isFeatureEnabled(key)` | Evaluate a feature flag for the current user (async). |
67
+ | `getAllFlags()` | Fetch every flag for the current user. |
68
+ | `getCachedFlag(key)` | Read the last-fetched flag value synchronously. |
69
+ | `flush()` | Send queued events now. |
70
+ | `reset()` | Clear identity (e.g. on logout). |
71
+ | `shutdown()` | Stop the flush timer and flush once. |
72
+
73
+ ## Configuration
74
+
75
+ | Option | Default | Notes |
76
+ | --- | --- | --- |
77
+ | `apiKey` | — | Public project key (`pdx_pub_…`). Required. |
78
+ | `host` | — | Ingest base URL. Required. |
79
+ | `flagsHost` | `host` | Flag-eval base URL (`GET /v1/flags`). |
80
+ | `flushAt` | `20` | Flush when this many events are queued. |
81
+ | `flushIntervalMs` | `10000` | Periodic flush interval; `0` disables the timer. |
82
+ | `maxQueueSize` | `1000` | Bounded queue; oldest events are dropped past this. |
83
+ | `maxRetries` | `3` | Transport retries (exponential backoff; 4xx fail fast). |
84
+ | `requestTimeoutMs` | `10000` | Per-request timeout. |
85
+ | `defaultProperties` | `{}` | Object or factory merged into every event. |
86
+ | `onError` | no-op | Delivery/validation error hook. |
87
+
88
+ Events are queued in memory (and persisted to `storage` where available), batched, and
89
+ delivered with retry + exponential backoff. Delivery never throws into your application;
90
+ failures surface through `onError` and the batch is retried on the next flush.
@@ -0,0 +1,2 @@
1
+ var z=Object.defineProperty;var J=(t,e,s)=>e in t?z(t,e,{enumerable:true,configurable:true,writable:true,value:s}):t[e]=s;var i=(t,e,s)=>J(t,typeof e!="symbol"?e+"":e,s);var d=class extends Error{constructor(s,r,n){super(r,n);i(this,"code");this.code=s,this.name="ProdantixError";}},y=class extends d{constructor(e){super("config",e),this.name="ConfigError";}},f=class extends d{constructor(s,r){super("validation",r);i(this,"field");this.field=s,this.name="ValidationError";}},l=class extends d{constructor(s,r,n){super("transport",s,n);i(this,"status");this.status=r,this.name="TransportError";}};var m=class{constructor(){i(this,"store",new Map);}getItem(e){return this.store.get(e)??null}removeItem(e){this.store.delete(e);}setItem(e,s){this.store.set(e,s);}};function le(){try{let t=globalThis.localStorage;if(t){let e="__pdx_probe__";return t.setItem(e,"1"),t.removeItem(e),t}}catch{return new m}return new m}var T="prodantix-js",S="0.0.1";var u=Symbol("absent");function Q(t,e){if(t==="distinct_id")return e.distinctId;let s=e.properties??{};if(Object.prototype.hasOwnProperty.call(s,t))return s[t];let r=e.attributes??{};return Object.prototype.hasOwnProperty.call(r,t)?r[t]:u}function c(t){return t===u?"undefined":String(t)}function C(t){return t===u?Number.NaN:Number(t)}function _(t){return t!==u&&t!==null&&t!==""}function P(t,e){if(!Array.isArray(e))return false;let s=c(t);return e.map(r=>String(r)).includes(s)}function R(t,e){let s=Q(t.attribute,e),r=t.value;switch(t.op){case "is_set":return _(s);case "is_not_set":return !_(s);case "eq":return c(s)===c(r===void 0?u:r);case "neq":return c(s)!==c(r===void 0?u:r);case "contains":return c(s).includes(c(r===void 0?u:r));case "in":return P(s,r);case "not_in":return Array.isArray(r)?!P(s,r):false;case "gt":return v(s,r,(n,o)=>n>o);case "gte":return v(s,r,(n,o)=>n>=o);case "lt":return v(s,r,(n,o)=>n<o);case "lte":return v(s,r,(n,o)=>n<=o);default:return false}}function v(t,e,s){let r=C(t),n=e===void 0?Number.NaN:C(e);return Number.isNaN(r)||Number.isNaN(n)?false:s(r,n)}function U(t,e){let s=`${t}:${e}`,r=2166136261;for(let n=0;n<s.length;n++)r^=s.charCodeAt(n),r=Math.imul(r,16777619);return (r>>>0)%100}function B(t,e){return t.enabled?t.targeting.length>0&&!t.targeting.every(s=>R(s,e))?{enabled:false,reason:"targeting"}:t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:U(t.key,e.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"disabled"}}function M(t,e){let s={};for(let r of t)s[r.key]=B(r,e).enabled;return s}function g(t){if(t)return t;let e=globalThis.fetch;if(typeof e=="function")return e.bind(globalThis)}function p(){let t=globalThis.AbortController;return t?new t:void 0}var A=t=>new Promise(e=>{setTimeout(e,t);});function h(t){return t.replace(/\/+$/,"")}var b=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=g(e.fetch),this.host=h(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){let s=this.fetch;if(!s)throw new l("no fetch implementation available in this runtime");let r=`${this.host}/v1/flags?distinct_id=${encodeURIComponent(e)}`,n=p(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let a=await s(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!a.ok)throw new l(`flags request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).flags??{}}finally{o!==void 0&&clearTimeout(o);}}async snapshot(){let e=this.fetch;if(!e)throw new l("no fetch implementation available in this runtime");let s=`${this.host}/v1/flags/snapshot`,r=p(),n=r?setTimeout(()=>r.abort(),this.requestTimeoutMs):void 0;try{let o=await e(s,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:r?.signal});if(!o.ok)throw new l(`flag snapshot request failed with status ${o.status}`,o.status);let a=JSON.parse(await o.text());return {flags:a.flags??[],generatedAt:a.generatedAt}}finally{n!==void 0&&clearTimeout(n);}}};var x=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=g(e.fetch),this.host=h(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async inbox(e){let s=this.requireFetch(),r=`${this.host}/v1/messages?distinct_id=${encodeURIComponent(e)}`,n=await this.request(s,r,{headers:this.authHeaders(),method:"GET"});if(!n.ok)throw new l(`inbox request failed with status ${n.status}`,n.status);return JSON.parse(await n.text()).messages??[]}async markRead(e,s){let r=this.requireFetch(),n=`${this.host}/v1/messages/read`,o=await this.request(r,n,{body:JSON.stringify({distinct_id:s,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!o.ok)throw new l(`mark-read request failed with status ${o.status}`,o.status)}requireFetch(){if(!this.fetch)throw new l("no fetch implementation available in this runtime");return this.fetch}authHeaders(){return {authorization:`Bearer ${this.projectKey}`}}async request(e,s,r){let n=p(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s,{...r,signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}};function q(t){return t>=400&&t<500&&t!==429}var I=class{constructor(e={}){i(this,"fetch");i(this,"maxRetries");i(this,"requestTimeoutMs");i(this,"baseDelayMs");i(this,"maxDelayMs");i(this,"sleep");i(this,"random");this.fetch=g(e.fetch),this.maxRetries=e.maxRetries??3,this.requestTimeoutMs=e.requestTimeoutMs??1e4,this.baseDelayMs=e.baseDelayMs??500,this.maxDelayMs=e.maxDelayMs??3e4,this.sleep=e.sleep??A,this.random=e.random??Math.random;}async send(e){let s=this.fetch;if(!s)throw new l("no fetch implementation available in this runtime");let r=JSON.stringify(e.body),n;for(let o=0;o<=this.maxRetries;o+=1){try{let a=await this.attempt(s,e,r);if(a.ok)return;if(q(a.status))throw new l(`ingest rejected batch with status ${a.status}`,a.status);n=new l(`ingest transient status ${a.status}`,a.status);}catch(a){if(a instanceof l&&a.status!==void 0&&q(a.status))throw a;n=a;}o<this.maxRetries&&await this.sleep(this.backoff(o));}throw new l("ingest delivery failed after retries",void 0,{cause:n})}async attempt(e,s,r){let n=p(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s.url,{body:r,headers:{authorization:`Bearer ${s.projectKey}`,"content-type":"application/json"},method:"POST",signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var $={now:()=>new Date};function E(t){return t.toISOString()}function H(){return globalThis.crypto}function G(t){t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[];for(let s=0;s<16;s+=1)e.push(t[s].toString(16).padStart(2,"0"));return `${e[0]}${e[1]}${e[2]}${e[3]}-${e[4]}${e[5]}-${e[6]}${e[7]}-${e[8]}${e[9]}-${e[10]}${e[11]}${e[12]}${e[13]}${e[14]}${e[15]}`}function X(){let t=H();if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let s=0;s<16;s+=1)e[s]=Math.floor(Math.random()*256);return G(e)}var N={uuid:X};var Y=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var Z=/^(?:\$|[a-z])[a-z0-9_.]*$/;function O(t){let e=0;for(let s of t)e+=1;return e}function D(t){return Y.test(t)}function W(t){return Z.test(t)}function K(t){let e=O(t);if(e<1||e>200)throw new f("distinct_id","distinct_id must be between 1 and 200 characters")}function L(t){let e=O(t);if(e<1||e>200)throw new f("event_name","event_name must be between 1 and 200 characters");if(!W(t))throw new f("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var ee=t=>{};function j(t){if(!t.apiKey||!D(t.apiKey))throw new y("apiKey must be a public project key of the form pdx_pub_<32 lowercase alphanumerics>");if(!t.host)throw new y("host is required (the ingest base URL)");let e=h(t.host),s=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??$,defaultProperties:typeof s=="function"?s:()=>s??{},flagsHost:t.flagsHost?h(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??N,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??ee,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??T,sdkVersion:t.sdkVersion??S,storage:t.storage??new m,transport:t.transport}}function V(t,e,s){L(t.eventName),K(t.distinctId);let r={distinct_id:t.distinctId,event_id:t.eventId??s.uuid(),event_name:t.eventName,properties:t.properties??{},schema_version:1,timestamp:E(t.timestamp??e.now())};return t.context&&(r.context=t.context),t.sessionId&&(r.session_id=t.sessionId),r}var w=class{constructor(e,s,r){this.storage=e;this.ids=s;this.namespace=r;i(this,"anonymousId");i(this,"distinctId");i(this,"identified");let n=e.getItem(this.key("anonymous_id"));n?this.anonymousId=n:(this.anonymousId=s.uuid(),e.setItem(this.key("anonymous_id"),this.anonymousId));let o=e.getItem(this.key("distinct_id"));o?(this.distinctId=o,this.identified=true):(this.distinctId=this.anonymousId,this.identified=false);}getAnonymousId(){return this.anonymousId}getDistinctId(){return this.distinctId}isIdentified(){return this.identified}snapshot(){return {anonymousId:this.anonymousId,distinctId:this.distinctId,identified:this.identified}}identify(e){return this.identified&&this.distinctId===e?{changed:false}:(this.distinctId=e,this.identified=true,this.storage.setItem(this.key("distinct_id"),e),{changed:true})}reset(){this.anonymousId=this.ids.uuid(),this.distinctId=this.anonymousId,this.identified=false,this.storage.setItem(this.key("anonymous_id"),this.anonymousId),this.storage.removeItem(this.key("distinct_id"));}key(e){return `pdx.${this.namespace}.${e}`}};var F=class{constructor(e,s){this.maxSize=e;this.onOverflow=s;i(this,"events",[]);}get size(){return this.events.length}enqueue(e){this.events.push(e),this.enforceCap();}restore(e){this.events.push(...e),this.enforceCap();}requeue(e){this.events.unshift(...e),this.enforceCap();}drain(e){let s=e===void 0?this.events.length:Math.min(e,this.events.length);return this.events.splice(0,s)}snapshot(){return [...this.events]}enforceCap(){if(this.events.length<=this.maxSize)return;let e=this.events.splice(0,this.events.length-this.maxSize);this.onOverflow?.({dropped:e});}};var te="queue",se=1e3,re=3e4,k=class{constructor(e){i(this,"config");i(this,"identity");i(this,"queue");i(this,"transport");i(this,"flagsClient");i(this,"messagesClient");i(this,"context");i(this,"flushTimer");i(this,"flushing",false);i(this,"cachedFlags");i(this,"cachedSnapshot");this.config=j(e),this.identity=new w(this.config.storage,this.config.ids,this.config.namespace),this.queue=new F(this.config.maxQueueSize,({dropped:s})=>{this.config.onError(new d("queue_overflow",`event queue overflow: dropped ${s.length} oldest event(s)`));}),this.transport=this.config.transport??new I({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new b({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.messagesClient=new x({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.context={sdk:this.config.sdkName,sdk_version:this.config.sdkVersion},this.config.os&&(this.context.os=this.config.os),this.config.locale&&(this.context.locale=this.config.locale),this.restoreQueue(),this.startTimer();}get distinctId(){return this.identity.getDistinctId()}get anonymousId(){return this.identity.getAnonymousId()}capture(e,s={}){try{let r={...this.config.defaultProperties(),...s.properties??{}},n=V({context:this.context,distinctId:this.identity.getDistinctId(),eventName:e,properties:r,sessionId:s.sessionId,timestamp:s.timestamp},this.config.clock,this.config.ids);this.enqueue(n);}catch(r){this.config.onError(r);}}identify(e,s={}){let r=this.identity.getAnonymousId(),n=!this.identity.isIdentified(),o=this.identity.identify(e),a={};n&&o.changed&&(a.$anon_distinct_id=r),s.set&&(a.$set=s.set),this.capture("$identify",{properties:a});}alias(e){this.capture("$create_alias",{properties:{alias:e}});}group(e,s,r){let n={$group_key:s,$group_type:e};r&&(n.$set=r),this.capture("$group",{properties:n});}setPersonProperties(e,s){let r={};e&&(r.$set=e),s&&(r.$set_once=s),this.capture("$set",{properties:r});}async getAllFlags(){let e=this.identity.getDistinctId(),s=await this.flagsClient.fetchAll(e);return this.cachedFlags={distinctId:e,flags:s},s}async isFeatureEnabled(e){return (await this.getAllFlags())[e]??false}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let s=await this.flagSnapshot();return M(s.flags,{attributes:e.attributes,distinctId:this.identity.getDistinctId(),properties:e.properties})}async isFeatureEnabledLocal(e,s){return (await this.getLocalFlags(s))[e]??false}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<re)return this.cachedSnapshot.snapshot;let s=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:s},s}async getInbox(){return this.messagesClient.inbox(this.identity.getDistinctId())}async markMessageRead(e){await this.messagesClient.markRead(e,this.identity.getDistinctId());}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=true;let e=this.queue.drain(se);try{await this.transport.send({body:{events:e,sent_at:E(this.config.clock.now())},projectKey:this.config.apiKey,url:`${this.config.host}/v1/events`}),this.persistQueue();}catch(s){this.queue.requeue(e),this.persistQueue(),this.config.onError(s);}finally{this.flushing=false;}}reset(){this.identity.reset(),this.cachedFlags=void 0,this.cachedSnapshot=void 0;}async shutdown(){this.stopTimer(),await this.flush();}enqueue(e){this.queue.enqueue(e),this.persistQueue(),this.queue.size>=this.config.flushAt&&this.flush();}persistQueue(){try{this.config.storage.setItem(this.persistKey(),JSON.stringify(this.queue.snapshot()));}catch(e){this.config.onError(e);}}restoreQueue(){try{let e=this.config.storage.getItem(this.persistKey());if(!e)return;let s=JSON.parse(e);Array.isArray(s)&&this.queue.restore(s);}catch(e){this.config.onError(e);}}startTimer(){if(this.config.flushIntervalMs<=0)return;let e=setInterval(()=>{this.flush();},this.config.flushIntervalMs),s=e;typeof s.unref=="function"&&s.unref(),this.flushTimer=e;}stopTimer(){this.flushTimer!==void 0&&(clearInterval(this.flushTimer),this.flushTimer=void 0);}persistKey(){return `pdx.${this.config.namespace}.${te}`}};function rt(t){return new k(t)}export{i as a,d as b,y as c,f as d,l as e,g as f,h as g,m as h,le as i,X as j,T as k,S as l,R as m,U as n,B as o,M as p,b as q,x as r,I as s,k as t,rt as u};//# sourceMappingURL=chunk-FIZWZVZG.js.map
2
+ //# sourceMappingURL=chunk-FIZWZVZG.js.map
@@ -0,0 +1,133 @@
1
+ type JsonPrimitive = string | number | boolean | null;
2
+ type JsonValue = JsonPrimitive | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ type EventProperties = Record<string, JsonValue>;
6
+ interface EventContext {
7
+ locale?: string;
8
+ os?: string;
9
+ sdk?: string;
10
+ sdk_version?: string;
11
+ }
12
+ interface EventEnvelope {
13
+ context?: EventContext;
14
+ distinct_id: string;
15
+ event_id: string;
16
+ event_name: string;
17
+ properties: EventProperties;
18
+ schema_version: 1;
19
+ session_id?: string;
20
+ timestamp: string;
21
+ }
22
+ interface EventBatch {
23
+ api_key?: string;
24
+ events: EventEnvelope[];
25
+ sent_at: string;
26
+ }
27
+ interface FlagsResponse {
28
+ flags: Record<string, boolean>;
29
+ }
30
+ interface InboxMessage {
31
+ body: string;
32
+ createdAt: string;
33
+ id: string;
34
+ read: boolean;
35
+ title: string;
36
+ }
37
+ interface InboxResponse {
38
+ messages: InboxMessage[];
39
+ }
40
+ interface Clock {
41
+ now(): Date;
42
+ }
43
+ interface IdFactory {
44
+ uuid(): string;
45
+ }
46
+ interface StorageAdapter {
47
+ getItem(key: string): string | null;
48
+ removeItem(key: string): void;
49
+ setItem(key: string, value: string): void;
50
+ }
51
+ interface TransportRequest {
52
+ body: EventBatch;
53
+ projectKey: string;
54
+ url: string;
55
+ }
56
+ interface Transport {
57
+ send(request: TransportRequest): Promise<void>;
58
+ }
59
+ interface ProdantixConfig {
60
+ apiKey: string;
61
+ autocapture?: boolean;
62
+ clock?: Clock;
63
+ defaultProperties?: EventProperties | (() => EventProperties);
64
+ flagsHost?: string;
65
+ flushAt?: number;
66
+ flushIntervalMs?: number;
67
+ host: string;
68
+ ids?: IdFactory;
69
+ locale?: string;
70
+ maxQueueSize?: number;
71
+ maxRetries?: number;
72
+ onError?: (error: unknown) => void;
73
+ os?: string;
74
+ requestTimeoutMs?: number;
75
+ sdkName?: string;
76
+ sdkVersion?: string;
77
+ storage?: StorageAdapter;
78
+ transport?: Transport;
79
+ }
80
+
81
+ interface LocalFlagContext {
82
+ attributes?: EventProperties;
83
+ properties?: EventProperties;
84
+ }
85
+ interface CaptureOptions {
86
+ properties?: EventProperties;
87
+ sessionId?: string;
88
+ timestamp?: Date;
89
+ }
90
+ interface IdentifyOptions {
91
+ set?: EventProperties;
92
+ }
93
+ declare class ProdantixClient {
94
+ private readonly config;
95
+ private readonly identity;
96
+ private readonly queue;
97
+ private readonly transport;
98
+ private readonly flagsClient;
99
+ private readonly messagesClient;
100
+ private readonly context;
101
+ private flushTimer?;
102
+ private flushing;
103
+ private cachedFlags?;
104
+ private cachedSnapshot?;
105
+ constructor(config: ProdantixConfig);
106
+ get distinctId(): string;
107
+ get anonymousId(): string;
108
+ capture(eventName: string, options?: CaptureOptions): void;
109
+ identify(distinctId: string, options?: IdentifyOptions): void;
110
+ alias(alias: string): void;
111
+ group(groupType: string, groupKey: string, properties?: EventProperties): void;
112
+ setPersonProperties(set?: EventProperties, setOnce?: EventProperties): void;
113
+ getAllFlags(): Promise<Record<string, boolean>>;
114
+ isFeatureEnabled(key: string): Promise<boolean>;
115
+ getCachedFlag(key: string): boolean | undefined;
116
+ getLocalFlags(context?: LocalFlagContext): Promise<Record<string, boolean>>;
117
+ isFeatureEnabledLocal(key: string, context?: LocalFlagContext): Promise<boolean>;
118
+ private flagSnapshot;
119
+ getInbox(): Promise<InboxMessage[]>;
120
+ markMessageRead(messageId: string): Promise<void>;
121
+ flush(): Promise<void>;
122
+ reset(): void;
123
+ shutdown(): Promise<void>;
124
+ private enqueue;
125
+ private persistQueue;
126
+ private restoreQueue;
127
+ private startTimer;
128
+ private stopTimer;
129
+ private persistKey;
130
+ }
131
+ declare function createClient(config: ProdantixConfig): ProdantixClient;
132
+
133
+ export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type IdFactory as I, type JsonValue as J, type LocalFlagContext as L, ProdantixClient as P, type StorageAdapter as S, type Transport as T, type Clock as a, type EventContext as b, type EventEnvelope as c, type EventProperties as d, type IdentifyOptions as e, type InboxMessage as f, type InboxResponse as g, type ProdantixConfig as h, type TransportRequest as i, createClient as j };
@@ -0,0 +1,133 @@
1
+ type JsonPrimitive = string | number | boolean | null;
2
+ type JsonValue = JsonPrimitive | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ type EventProperties = Record<string, JsonValue>;
6
+ interface EventContext {
7
+ locale?: string;
8
+ os?: string;
9
+ sdk?: string;
10
+ sdk_version?: string;
11
+ }
12
+ interface EventEnvelope {
13
+ context?: EventContext;
14
+ distinct_id: string;
15
+ event_id: string;
16
+ event_name: string;
17
+ properties: EventProperties;
18
+ schema_version: 1;
19
+ session_id?: string;
20
+ timestamp: string;
21
+ }
22
+ interface EventBatch {
23
+ api_key?: string;
24
+ events: EventEnvelope[];
25
+ sent_at: string;
26
+ }
27
+ interface FlagsResponse {
28
+ flags: Record<string, boolean>;
29
+ }
30
+ interface InboxMessage {
31
+ body: string;
32
+ createdAt: string;
33
+ id: string;
34
+ read: boolean;
35
+ title: string;
36
+ }
37
+ interface InboxResponse {
38
+ messages: InboxMessage[];
39
+ }
40
+ interface Clock {
41
+ now(): Date;
42
+ }
43
+ interface IdFactory {
44
+ uuid(): string;
45
+ }
46
+ interface StorageAdapter {
47
+ getItem(key: string): string | null;
48
+ removeItem(key: string): void;
49
+ setItem(key: string, value: string): void;
50
+ }
51
+ interface TransportRequest {
52
+ body: EventBatch;
53
+ projectKey: string;
54
+ url: string;
55
+ }
56
+ interface Transport {
57
+ send(request: TransportRequest): Promise<void>;
58
+ }
59
+ interface ProdantixConfig {
60
+ apiKey: string;
61
+ autocapture?: boolean;
62
+ clock?: Clock;
63
+ defaultProperties?: EventProperties | (() => EventProperties);
64
+ flagsHost?: string;
65
+ flushAt?: number;
66
+ flushIntervalMs?: number;
67
+ host: string;
68
+ ids?: IdFactory;
69
+ locale?: string;
70
+ maxQueueSize?: number;
71
+ maxRetries?: number;
72
+ onError?: (error: unknown) => void;
73
+ os?: string;
74
+ requestTimeoutMs?: number;
75
+ sdkName?: string;
76
+ sdkVersion?: string;
77
+ storage?: StorageAdapter;
78
+ transport?: Transport;
79
+ }
80
+
81
+ interface LocalFlagContext {
82
+ attributes?: EventProperties;
83
+ properties?: EventProperties;
84
+ }
85
+ interface CaptureOptions {
86
+ properties?: EventProperties;
87
+ sessionId?: string;
88
+ timestamp?: Date;
89
+ }
90
+ interface IdentifyOptions {
91
+ set?: EventProperties;
92
+ }
93
+ declare class ProdantixClient {
94
+ private readonly config;
95
+ private readonly identity;
96
+ private readonly queue;
97
+ private readonly transport;
98
+ private readonly flagsClient;
99
+ private readonly messagesClient;
100
+ private readonly context;
101
+ private flushTimer?;
102
+ private flushing;
103
+ private cachedFlags?;
104
+ private cachedSnapshot?;
105
+ constructor(config: ProdantixConfig);
106
+ get distinctId(): string;
107
+ get anonymousId(): string;
108
+ capture(eventName: string, options?: CaptureOptions): void;
109
+ identify(distinctId: string, options?: IdentifyOptions): void;
110
+ alias(alias: string): void;
111
+ group(groupType: string, groupKey: string, properties?: EventProperties): void;
112
+ setPersonProperties(set?: EventProperties, setOnce?: EventProperties): void;
113
+ getAllFlags(): Promise<Record<string, boolean>>;
114
+ isFeatureEnabled(key: string): Promise<boolean>;
115
+ getCachedFlag(key: string): boolean | undefined;
116
+ getLocalFlags(context?: LocalFlagContext): Promise<Record<string, boolean>>;
117
+ isFeatureEnabledLocal(key: string, context?: LocalFlagContext): Promise<boolean>;
118
+ private flagSnapshot;
119
+ getInbox(): Promise<InboxMessage[]>;
120
+ markMessageRead(messageId: string): Promise<void>;
121
+ flush(): Promise<void>;
122
+ reset(): void;
123
+ shutdown(): Promise<void>;
124
+ private enqueue;
125
+ private persistQueue;
126
+ private restoreQueue;
127
+ private startTimer;
128
+ private stopTimer;
129
+ private persistKey;
130
+ }
131
+ declare function createClient(config: ProdantixConfig): ProdantixClient;
132
+
133
+ export { type CaptureOptions as C, type EventBatch as E, type FlagsResponse as F, type IdFactory as I, type JsonValue as J, type LocalFlagContext as L, ProdantixClient as P, type StorageAdapter as S, type Transport as T, type Clock as a, type EventContext as b, type EventEnvelope as c, type EventProperties as d, type IdentifyOptions as e, type InboxMessage as f, type InboxResponse as g, type ProdantixConfig as h, type TransportRequest as i, createClient as j };
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var Q=Object.defineProperty;var U=(t,e,r)=>e in t?Q(t,e,{enumerable:true,configurable:true,writable:true,value:r}):t[e]=r;var i=(t,e,r)=>U(t,typeof e!="symbol"?e+"":e,r);var d=class extends Error{constructor(r,s,n){super(s,n);i(this,"code");this.code=r,this.name="ProdantixError";}},m=class extends d{constructor(e){super("config",e),this.name="ConfigError";}},c=class extends d{constructor(r,s){super("validation",s);i(this,"field");this.field=r,this.name="ValidationError";}},l=class extends d{constructor(r,s,n){super("transport",r,n);i(this,"status");this.status=s,this.name="TransportError";}};function g(t){if(t)return t;let e=globalThis.fetch;if(typeof e=="function")return e.bind(globalThis)}function u(){let t=globalThis.AbortController;return t?new t:void 0}var _=t=>new Promise(e=>{setTimeout(e,t);});function p(t){return t.replace(/\/+$/,"")}var y=class{constructor(){i(this,"store",new Map);}getItem(e){return this.store.get(e)??null}removeItem(e){this.store.delete(e);}setItem(e,r){this.store.set(e,r);}};var R={now:()=>new Date};function I(t){return t.toISOString()}function B(){return globalThis.crypto}function H(t){t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[];for(let r=0;r<16;r+=1)e.push(t[r].toString(16).padStart(2,"0"));return `${e[0]}${e[1]}${e[2]}${e[3]}-${e[4]}${e[5]}-${e[6]}${e[7]}-${e[8]}${e[9]}-${e[10]}${e[11]}${e[12]}${e[13]}${e[14]}${e[15]}`}function G(){let t=B();if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let r=0;r<16;r+=1)e[r]=Math.floor(Math.random()*256);return H(e)}var M={uuid:G};var X=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var Y=/^(?:\$|[a-z])[a-z0-9_.]*$/;function A(t){let e=0;for(let r of t)e+=1;return e}function q(t){return X.test(t)}function Z(t){return Y.test(t)}function $(t){let e=A(t);if(e<1||e>200)throw new c("distinct_id","distinct_id must be between 1 and 200 characters")}function N(t){let e=A(t);if(e<1||e>200)throw new c("event_name","event_name must be between 1 and 200 characters");if(!Z(t))throw new c("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var k="prodantix-js",T="0.0.1";var W=t=>{};function O(t){if(!t.apiKey||!q(t.apiKey))throw new m("apiKey must be a public project key of the form pdx_pub_<32 lowercase alphanumerics>");if(!t.host)throw new m("host is required (the ingest base URL)");let e=p(t.host),r=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??R,defaultProperties:typeof r=="function"?r:()=>r??{},flagsHost:t.flagsHost?p(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??M,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??W,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??k,sdkVersion:t.sdkVersion??T,storage:t.storage??new y,transport:t.transport}}function D(t,e,r){N(t.eventName),$(t.distinctId);let s={distinct_id:t.distinctId,event_id:t.eventId??r.uuid(),event_name:t.eventName,properties:t.properties??{},schema_version:1,timestamp:I(t.timestamp??e.now())};return t.context&&(s.context=t.context),t.sessionId&&(s.session_id=t.sessionId),s}var f=Symbol("absent");function ee(t,e){if(t==="distinct_id")return e.distinctId;let r=e.properties??{};if(Object.prototype.hasOwnProperty.call(r,t))return r[t];let s=e.attributes??{};return Object.prototype.hasOwnProperty.call(s,t)?s[t]:f}function h(t){return t===f?"undefined":String(t)}function K(t){return t===f?Number.NaN:Number(t)}function L(t){return t!==f&&t!==null&&t!==""}function j(t,e){if(!Array.isArray(e))return false;let r=h(t);return e.map(s=>String(s)).includes(r)}function C(t,e){let r=ee(t.attribute,e),s=t.value;switch(t.op){case "is_set":return L(r);case "is_not_set":return !L(r);case "eq":return h(r)===h(s===void 0?f:s);case "neq":return h(r)!==h(s===void 0?f:s);case "contains":return h(r).includes(h(s===void 0?f:s));case "in":return j(r,s);case "not_in":return Array.isArray(s)?!j(r,s):false;case "gt":return E(r,s,(n,o)=>n>o);case "gte":return E(r,s,(n,o)=>n>=o);case "lt":return E(r,s,(n,o)=>n<o);case "lte":return E(r,s,(n,o)=>n<=o);default:return false}}function E(t,e,r){let s=K(t),n=e===void 0?Number.NaN:K(e);return Number.isNaN(s)||Number.isNaN(n)?false:r(s,n)}function V(t,e){let r=`${t}:${e}`,s=2166136261;for(let n=0;n<r.length;n++)s^=r.charCodeAt(n),s=Math.imul(s,16777619);return (s>>>0)%100}function z(t,e){return t.enabled?t.targeting.length>0&&!t.targeting.every(r=>C(r,e))?{enabled:false,reason:"targeting"}:t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:V(t.key,e.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"disabled"}}function P(t,e){let r={};for(let s of t)r[s.key]=z(s,e).enabled;return r}var v=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=g(e.fetch),this.host=p(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){let r=this.fetch;if(!r)throw new l("no fetch implementation available in this runtime");let s=`${this.host}/v1/flags?distinct_id=${encodeURIComponent(e)}`,n=u(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let a=await r(s,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!a.ok)throw new l(`flags request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).flags??{}}finally{o!==void 0&&clearTimeout(o);}}async snapshot(){let e=this.fetch;if(!e)throw new l("no fetch implementation available in this runtime");let r=`${this.host}/v1/flags/snapshot`,s=u(),n=s?setTimeout(()=>s.abort(),this.requestTimeoutMs):void 0;try{let o=await e(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:s?.signal});if(!o.ok)throw new l(`flag snapshot request failed with status ${o.status}`,o.status);let a=JSON.parse(await o.text());return {flags:a.flags??[],generatedAt:a.generatedAt}}finally{n!==void 0&&clearTimeout(n);}}};var F=class{constructor(e,r,s){this.storage=e;this.ids=r;this.namespace=s;i(this,"anonymousId");i(this,"distinctId");i(this,"identified");let n=e.getItem(this.key("anonymous_id"));n?this.anonymousId=n:(this.anonymousId=r.uuid(),e.setItem(this.key("anonymous_id"),this.anonymousId));let o=e.getItem(this.key("distinct_id"));o?(this.distinctId=o,this.identified=true):(this.distinctId=this.anonymousId,this.identified=false);}getAnonymousId(){return this.anonymousId}getDistinctId(){return this.distinctId}isIdentified(){return this.identified}snapshot(){return {anonymousId:this.anonymousId,distinctId:this.distinctId,identified:this.identified}}identify(e){return this.identified&&this.distinctId===e?{changed:false}:(this.distinctId=e,this.identified=true,this.storage.setItem(this.key("distinct_id"),e),{changed:true})}reset(){this.anonymousId=this.ids.uuid(),this.distinctId=this.anonymousId,this.identified=false,this.storage.setItem(this.key("anonymous_id"),this.anonymousId),this.storage.removeItem(this.key("distinct_id"));}key(e){return `pdx.${this.namespace}.${e}`}};var x=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=g(e.fetch),this.host=p(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async inbox(e){let r=this.requireFetch(),s=`${this.host}/v1/messages?distinct_id=${encodeURIComponent(e)}`,n=await this.request(r,s,{headers:this.authHeaders(),method:"GET"});if(!n.ok)throw new l(`inbox request failed with status ${n.status}`,n.status);return JSON.parse(await n.text()).messages??[]}async markRead(e,r){let s=this.requireFetch(),n=`${this.host}/v1/messages/read`,o=await this.request(s,n,{body:JSON.stringify({distinct_id:r,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!o.ok)throw new l(`mark-read request failed with status ${o.status}`,o.status)}requireFetch(){if(!this.fetch)throw new l("no fetch implementation available in this runtime");return this.fetch}authHeaders(){return {authorization:`Bearer ${this.projectKey}`}}async request(e,r,s){let n=u(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(r,{...s,signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}};var w=class{constructor(e,r){this.maxSize=e;this.onOverflow=r;i(this,"events",[]);}get size(){return this.events.length}enqueue(e){this.events.push(e),this.enforceCap();}restore(e){this.events.push(...e),this.enforceCap();}requeue(e){this.events.unshift(...e),this.enforceCap();}drain(e){let r=e===void 0?this.events.length:Math.min(e,this.events.length);return this.events.splice(0,r)}snapshot(){return [...this.events]}enforceCap(){if(this.events.length<=this.maxSize)return;let e=this.events.splice(0,this.events.length-this.maxSize);this.onOverflow?.({dropped:e});}};function J(t){return t>=400&&t<500&&t!==429}var b=class{constructor(e={}){i(this,"fetch");i(this,"maxRetries");i(this,"requestTimeoutMs");i(this,"baseDelayMs");i(this,"maxDelayMs");i(this,"sleep");i(this,"random");this.fetch=g(e.fetch),this.maxRetries=e.maxRetries??3,this.requestTimeoutMs=e.requestTimeoutMs??1e4,this.baseDelayMs=e.baseDelayMs??500,this.maxDelayMs=e.maxDelayMs??3e4,this.sleep=e.sleep??_,this.random=e.random??Math.random;}async send(e){let r=this.fetch;if(!r)throw new l("no fetch implementation available in this runtime");let s=JSON.stringify(e.body),n;for(let o=0;o<=this.maxRetries;o+=1){try{let a=await this.attempt(r,e,s);if(a.ok)return;if(J(a.status))throw new l(`ingest rejected batch with status ${a.status}`,a.status);n=new l(`ingest transient status ${a.status}`,a.status);}catch(a){if(a instanceof l&&a.status!==void 0&&J(a.status))throw a;n=a;}o<this.maxRetries&&await this.sleep(this.backoff(o));}throw new l("ingest delivery failed after retries",void 0,{cause:n})}async attempt(e,r,s){let n=u(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(r.url,{body:s,headers:{authorization:`Bearer ${r.projectKey}`,"content-type":"application/json"},method:"POST",signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var te="queue",re=1e3,se=3e4,S=class{constructor(e){i(this,"config");i(this,"identity");i(this,"queue");i(this,"transport");i(this,"flagsClient");i(this,"messagesClient");i(this,"context");i(this,"flushTimer");i(this,"flushing",false);i(this,"cachedFlags");i(this,"cachedSnapshot");this.config=O(e),this.identity=new F(this.config.storage,this.config.ids,this.config.namespace),this.queue=new w(this.config.maxQueueSize,({dropped:r})=>{this.config.onError(new d("queue_overflow",`event queue overflow: dropped ${r.length} oldest event(s)`));}),this.transport=this.config.transport??new b({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new v({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.messagesClient=new x({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.context={sdk:this.config.sdkName,sdk_version:this.config.sdkVersion},this.config.os&&(this.context.os=this.config.os),this.config.locale&&(this.context.locale=this.config.locale),this.restoreQueue(),this.startTimer();}get distinctId(){return this.identity.getDistinctId()}get anonymousId(){return this.identity.getAnonymousId()}capture(e,r={}){try{let s={...this.config.defaultProperties(),...r.properties??{}},n=D({context:this.context,distinctId:this.identity.getDistinctId(),eventName:e,properties:s,sessionId:r.sessionId,timestamp:r.timestamp},this.config.clock,this.config.ids);this.enqueue(n);}catch(s){this.config.onError(s);}}identify(e,r={}){let s=this.identity.getAnonymousId(),n=!this.identity.isIdentified(),o=this.identity.identify(e),a={};n&&o.changed&&(a.$anon_distinct_id=s),r.set&&(a.$set=r.set),this.capture("$identify",{properties:a});}alias(e){this.capture("$create_alias",{properties:{alias:e}});}group(e,r,s){let n={$group_key:r,$group_type:e};s&&(n.$set=s),this.capture("$group",{properties:n});}setPersonProperties(e,r){let s={};e&&(s.$set=e),r&&(s.$set_once=r),this.capture("$set",{properties:s});}async getAllFlags(){let e=this.identity.getDistinctId(),r=await this.flagsClient.fetchAll(e);return this.cachedFlags={distinctId:e,flags:r},r}async isFeatureEnabled(e){return (await this.getAllFlags())[e]??false}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let r=await this.flagSnapshot();return P(r.flags,{attributes:e.attributes,distinctId:this.identity.getDistinctId(),properties:e.properties})}async isFeatureEnabledLocal(e,r){return (await this.getLocalFlags(r))[e]??false}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<se)return this.cachedSnapshot.snapshot;let r=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:r},r}async getInbox(){return this.messagesClient.inbox(this.identity.getDistinctId())}async markMessageRead(e){await this.messagesClient.markRead(e,this.identity.getDistinctId());}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=true;let e=this.queue.drain(re);try{await this.transport.send({body:{events:e,sent_at:I(this.config.clock.now())},projectKey:this.config.apiKey,url:`${this.config.host}/v1/events`}),this.persistQueue();}catch(r){this.queue.requeue(e),this.persistQueue(),this.config.onError(r);}finally{this.flushing=false;}}reset(){this.identity.reset(),this.cachedFlags=void 0,this.cachedSnapshot=void 0;}async shutdown(){this.stopTimer(),await this.flush();}enqueue(e){this.queue.enqueue(e),this.persistQueue(),this.queue.size>=this.config.flushAt&&this.flush();}persistQueue(){try{this.config.storage.setItem(this.persistKey(),JSON.stringify(this.queue.snapshot()));}catch(e){this.config.onError(e);}}restoreQueue(){try{let e=this.config.storage.getItem(this.persistKey());if(!e)return;let r=JSON.parse(e);Array.isArray(r)&&this.queue.restore(r);}catch(e){this.config.onError(e);}}startTimer(){if(this.config.flushIntervalMs<=0)return;let e=setInterval(()=>{this.flush();},this.config.flushIntervalMs),r=e;typeof r.unref=="function"&&r.unref(),this.flushTimer=e;}stopTimer(){this.flushTimer!==void 0&&(clearInterval(this.flushTimer),this.flushTimer=void 0);}persistKey(){return `pdx.${this.config.namespace}.${te}`}};function ne(t){return new S(t)}exports.ConfigError=m;exports.FetchTransport=b;exports.FlagsClient=v;exports.MemoryStorage=y;exports.MessagesClient=x;exports.ProdantixClient=S;exports.ProdantixError=d;exports.SDK_NAME=k;exports.SDK_VERSION=T;exports.TransportError=l;exports.ValidationError=c;exports.bucket=V;exports.createClient=ne;exports.evaluateAll=P;exports.evaluateFlag=z;exports.matches=C;//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,100 @@
1
+ import { J as JsonValue, f as InboxMessage, S as StorageAdapter } from './client-B1bcIuD8.cjs';
2
+ export { C as CaptureOptions, a as Clock, E as EventBatch, b as EventContext, c as EventEnvelope, d as EventProperties, F as FlagsResponse, I as IdFactory, e as IdentifyOptions, g as InboxResponse, L as LocalFlagContext, P as ProdantixClient, h as ProdantixConfig, T as Transport, i as TransportRequest, j as createClient } from './client-B1bcIuD8.cjs';
3
+ import { F as FetchLike } from './transport-B3PxeUxW.cjs';
4
+ export { a as FetchTransport } from './transport-B3PxeUxW.cjs';
5
+
6
+ type ProdantixErrorCode = 'config' | 'queue_overflow' | 'transport' | 'validation';
7
+ declare class ProdantixError extends Error {
8
+ readonly code: ProdantixErrorCode;
9
+ constructor(code: ProdantixErrorCode, message: string, options?: ErrorOptions);
10
+ }
11
+ declare class ConfigError extends ProdantixError {
12
+ constructor(message: string);
13
+ }
14
+ declare class ValidationError extends ProdantixError {
15
+ readonly field: string;
16
+ constructor(field: string, message: string);
17
+ }
18
+ declare class TransportError extends ProdantixError {
19
+ readonly status?: number;
20
+ constructor(message: string, status?: number, options?: ErrorOptions);
21
+ }
22
+
23
+ type FlagOp = 'eq' | 'neq' | 'in' | 'not_in' | 'contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_set' | 'is_not_set';
24
+ interface FlagCondition {
25
+ attribute: string;
26
+ op: FlagOp;
27
+ value?: JsonValue;
28
+ }
29
+ interface FlagEvalContext {
30
+ attributes?: Record<string, JsonValue>;
31
+ distinctId: string;
32
+ properties?: Record<string, JsonValue>;
33
+ }
34
+ declare function matches(condition: FlagCondition, ctx: FlagEvalContext): boolean;
35
+
36
+ interface FlagRule {
37
+ description?: string;
38
+ enabled: boolean;
39
+ key: string;
40
+ rolloutPercentage: number;
41
+ targeting: FlagCondition[];
42
+ }
43
+ interface FlagSnapshot {
44
+ flags: FlagRule[];
45
+ generatedAt: string;
46
+ }
47
+ interface FlagDecision {
48
+ enabled: boolean;
49
+ reason: string;
50
+ }
51
+ declare function bucket(key: string, distinctId: string): number;
52
+ declare function evaluateFlag(rule: FlagRule, ctx: FlagEvalContext): FlagDecision;
53
+ declare function evaluateAll(rules: FlagRule[], ctx: FlagEvalContext): Record<string, boolean>;
54
+
55
+ interface FlagsClientOptions {
56
+ fetch?: FetchLike;
57
+ host: string;
58
+ projectKey: string;
59
+ requestTimeoutMs?: number;
60
+ }
61
+ declare class FlagsClient {
62
+ private readonly fetch?;
63
+ private readonly host;
64
+ private readonly projectKey;
65
+ private readonly requestTimeoutMs;
66
+ constructor(options: FlagsClientOptions);
67
+ fetchAll(distinctId: string): Promise<Record<string, boolean>>;
68
+ snapshot(): Promise<FlagSnapshot>;
69
+ }
70
+
71
+ interface MessagesClientOptions {
72
+ fetch?: FetchLike;
73
+ host: string;
74
+ projectKey: string;
75
+ requestTimeoutMs?: number;
76
+ }
77
+ declare class MessagesClient {
78
+ private readonly fetch?;
79
+ private readonly host;
80
+ private readonly projectKey;
81
+ private readonly requestTimeoutMs;
82
+ constructor(options: MessagesClientOptions);
83
+ inbox(distinctId: string): Promise<InboxMessage[]>;
84
+ markRead(messageId: string, distinctId: string): Promise<void>;
85
+ private requireFetch;
86
+ private authHeaders;
87
+ private request;
88
+ }
89
+
90
+ declare class MemoryStorage implements StorageAdapter {
91
+ private readonly store;
92
+ getItem(key: string): string | null;
93
+ removeItem(key: string): void;
94
+ setItem(key: string, value: string): void;
95
+ }
96
+
97
+ declare const SDK_NAME = "prodantix-js";
98
+ declare const SDK_VERSION = "0.0.1";
99
+
100
+ export { ConfigError, type FlagCondition, type FlagDecision, type FlagEvalContext, type FlagOp, type FlagRule, type FlagSnapshot, FlagsClient, InboxMessage, JsonValue, MemoryStorage, MessagesClient, ProdantixError, type ProdantixErrorCode, SDK_NAME, SDK_VERSION, StorageAdapter, TransportError, ValidationError, bucket, evaluateAll, evaluateFlag, matches };
@@ -0,0 +1,100 @@
1
+ import { J as JsonValue, f as InboxMessage, S as StorageAdapter } from './client-B1bcIuD8.js';
2
+ export { C as CaptureOptions, a as Clock, E as EventBatch, b as EventContext, c as EventEnvelope, d as EventProperties, F as FlagsResponse, I as IdFactory, e as IdentifyOptions, g as InboxResponse, L as LocalFlagContext, P as ProdantixClient, h as ProdantixConfig, T as Transport, i as TransportRequest, j as createClient } from './client-B1bcIuD8.js';
3
+ import { F as FetchLike } from './transport-By6wsdny.js';
4
+ export { a as FetchTransport } from './transport-By6wsdny.js';
5
+
6
+ type ProdantixErrorCode = 'config' | 'queue_overflow' | 'transport' | 'validation';
7
+ declare class ProdantixError extends Error {
8
+ readonly code: ProdantixErrorCode;
9
+ constructor(code: ProdantixErrorCode, message: string, options?: ErrorOptions);
10
+ }
11
+ declare class ConfigError extends ProdantixError {
12
+ constructor(message: string);
13
+ }
14
+ declare class ValidationError extends ProdantixError {
15
+ readonly field: string;
16
+ constructor(field: string, message: string);
17
+ }
18
+ declare class TransportError extends ProdantixError {
19
+ readonly status?: number;
20
+ constructor(message: string, status?: number, options?: ErrorOptions);
21
+ }
22
+
23
+ type FlagOp = 'eq' | 'neq' | 'in' | 'not_in' | 'contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_set' | 'is_not_set';
24
+ interface FlagCondition {
25
+ attribute: string;
26
+ op: FlagOp;
27
+ value?: JsonValue;
28
+ }
29
+ interface FlagEvalContext {
30
+ attributes?: Record<string, JsonValue>;
31
+ distinctId: string;
32
+ properties?: Record<string, JsonValue>;
33
+ }
34
+ declare function matches(condition: FlagCondition, ctx: FlagEvalContext): boolean;
35
+
36
+ interface FlagRule {
37
+ description?: string;
38
+ enabled: boolean;
39
+ key: string;
40
+ rolloutPercentage: number;
41
+ targeting: FlagCondition[];
42
+ }
43
+ interface FlagSnapshot {
44
+ flags: FlagRule[];
45
+ generatedAt: string;
46
+ }
47
+ interface FlagDecision {
48
+ enabled: boolean;
49
+ reason: string;
50
+ }
51
+ declare function bucket(key: string, distinctId: string): number;
52
+ declare function evaluateFlag(rule: FlagRule, ctx: FlagEvalContext): FlagDecision;
53
+ declare function evaluateAll(rules: FlagRule[], ctx: FlagEvalContext): Record<string, boolean>;
54
+
55
+ interface FlagsClientOptions {
56
+ fetch?: FetchLike;
57
+ host: string;
58
+ projectKey: string;
59
+ requestTimeoutMs?: number;
60
+ }
61
+ declare class FlagsClient {
62
+ private readonly fetch?;
63
+ private readonly host;
64
+ private readonly projectKey;
65
+ private readonly requestTimeoutMs;
66
+ constructor(options: FlagsClientOptions);
67
+ fetchAll(distinctId: string): Promise<Record<string, boolean>>;
68
+ snapshot(): Promise<FlagSnapshot>;
69
+ }
70
+
71
+ interface MessagesClientOptions {
72
+ fetch?: FetchLike;
73
+ host: string;
74
+ projectKey: string;
75
+ requestTimeoutMs?: number;
76
+ }
77
+ declare class MessagesClient {
78
+ private readonly fetch?;
79
+ private readonly host;
80
+ private readonly projectKey;
81
+ private readonly requestTimeoutMs;
82
+ constructor(options: MessagesClientOptions);
83
+ inbox(distinctId: string): Promise<InboxMessage[]>;
84
+ markRead(messageId: string, distinctId: string): Promise<void>;
85
+ private requireFetch;
86
+ private authHeaders;
87
+ private request;
88
+ }
89
+
90
+ declare class MemoryStorage implements StorageAdapter {
91
+ private readonly store;
92
+ getItem(key: string): string | null;
93
+ removeItem(key: string): void;
94
+ setItem(key: string, value: string): void;
95
+ }
96
+
97
+ declare const SDK_NAME = "prodantix-js";
98
+ declare const SDK_VERSION = "0.0.1";
99
+
100
+ export { ConfigError, type FlagCondition, type FlagDecision, type FlagEvalContext, type FlagOp, type FlagRule, type FlagSnapshot, FlagsClient, InboxMessage, JsonValue, MemoryStorage, MessagesClient, ProdantixError, type ProdantixErrorCode, SDK_NAME, SDK_VERSION, StorageAdapter, TransportError, ValidationError, bucket, evaluateAll, evaluateFlag, matches };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export{c as ConfigError,s as FetchTransport,q as FlagsClient,h as MemoryStorage,r as MessagesClient,t as ProdantixClient,b as ProdantixError,k as SDK_NAME,l as SDK_VERSION,e as TransportError,d as ValidationError,n as bucket,u as createClient,p as evaluateAll,o as evaluateFlag,m as matches}from'./chunk-FIZWZVZG.js';//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
package/dist/node.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var J=Object.defineProperty;var Q=(t,e,s)=>e in t?J(t,e,{enumerable:true,configurable:true,writable:true,value:s}):t[e]=s;var i=(t,e,s)=>Q(t,typeof e!="symbol"?e+"":e,s);var l=class extends Error{constructor(s,r,n){super(r,n);i(this,"code");this.code=s,this.name="ProdantixError";}},g=class extends l{constructor(e){super("config",e),this.name="ConfigError";}},f=class extends l{constructor(s,r){super("validation",r);i(this,"field");this.field=s,this.name="ValidationError";}},c=class extends l{constructor(s,r,n){super("transport",s,n);i(this,"status");this.status=r,this.name="TransportError";}};function m(t){if(t)return t;let e=globalThis.fetch;if(typeof e=="function")return e.bind(globalThis)}function d(){let t=globalThis.AbortController;return t?new t:void 0}var T=t=>new Promise(e=>{setTimeout(e,t);});function u(t){return t.replace(/\/+$/,"")}var y=class{constructor(){i(this,"store",new Map);}getItem(e){return this.store.get(e)??null}removeItem(e){this.store.delete(e);}setItem(e,s){this.store.set(e,s);}};var S={now:()=>new Date};function v(t){return t.toISOString()}function U(){return globalThis.crypto}function B(t){t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[];for(let s=0;s<16;s+=1)e.push(t[s].toString(16).padStart(2,"0"));return `${e[0]}${e[1]}${e[2]}${e[3]}-${e[4]}${e[5]}-${e[6]}${e[7]}-${e[8]}${e[9]}-${e[10]}${e[11]}${e[12]}${e[13]}${e[14]}${e[15]}`}function H(){let t=U();if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let s=0;s<16;s+=1)e[s]=Math.floor(Math.random()*256);return B(e)}var P={uuid:H};var G=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var X=/^(?:\$|[a-z])[a-z0-9_.]*$/;function C(t){let e=0;for(let s of t)e+=1;return e}function _(t){return G.test(t)}function Y(t){return X.test(t)}function R(t){let e=C(t);if(e<1||e>200)throw new f("distinct_id","distinct_id must be between 1 and 200 characters")}function M(t){let e=C(t);if(e<1||e>200)throw new f("event_name","event_name must be between 1 and 200 characters");if(!Y(t))throw new f("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var A="prodantix-js",q="0.0.1";var Z=t=>{};function $(t){if(!t.apiKey||!_(t.apiKey))throw new g("apiKey must be a public project key of the form pdx_pub_<32 lowercase alphanumerics>");if(!t.host)throw new g("host is required (the ingest base URL)");let e=u(t.host),s=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??S,defaultProperties:typeof s=="function"?s:()=>s??{},flagsHost:t.flagsHost?u(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??P,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??Z,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??A,sdkVersion:t.sdkVersion??q,storage:t.storage??new y,transport:t.transport}}function N(t,e,s){M(t.eventName),R(t.distinctId);let r={distinct_id:t.distinctId,event_id:t.eventId??s.uuid(),event_name:t.eventName,properties:t.properties??{},schema_version:1,timestamp:v(t.timestamp??e.now())};return t.context&&(r.context=t.context),t.sessionId&&(r.session_id=t.sessionId),r}var h=Symbol("absent");function W(t,e){if(t==="distinct_id")return e.distinctId;let s=e.properties??{};if(Object.prototype.hasOwnProperty.call(s,t))return s[t];let r=e.attributes??{};return Object.prototype.hasOwnProperty.call(r,t)?r[t]:h}function p(t){return t===h?"undefined":String(t)}function L(t){return t===h?Number.NaN:Number(t)}function O(t){return t!==h&&t!==null&&t!==""}function D(t,e){if(!Array.isArray(e))return false;let s=p(t);return e.map(r=>String(r)).includes(s)}function K(t,e){let s=W(t.attribute,e),r=t.value;switch(t.op){case "is_set":return O(s);case "is_not_set":return !O(s);case "eq":return p(s)===p(r===void 0?h:r);case "neq":return p(s)!==p(r===void 0?h:r);case "contains":return p(s).includes(p(r===void 0?h:r));case "in":return D(s,r);case "not_in":return Array.isArray(r)?!D(s,r):false;case "gt":return x(s,r,(n,o)=>n>o);case "gte":return x(s,r,(n,o)=>n>=o);case "lt":return x(s,r,(n,o)=>n<o);case "lte":return x(s,r,(n,o)=>n<=o);default:return false}}function x(t,e,s){let r=L(t),n=e===void 0?Number.NaN:L(e);return Number.isNaN(r)||Number.isNaN(n)?false:s(r,n)}function ee(t,e){let s=`${t}:${e}`,r=2166136261;for(let n=0;n<s.length;n++)r^=s.charCodeAt(n),r=Math.imul(r,16777619);return (r>>>0)%100}function te(t,e){return t.enabled?t.targeting.length>0&&!t.targeting.every(s=>K(s,e))?{enabled:false,reason:"targeting"}:t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:ee(t.key,e.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"disabled"}}function j(t,e){let s={};for(let r of t)s[r.key]=te(r,e).enabled;return s}var b=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=m(e.fetch),this.host=u(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){let s=this.fetch;if(!s)throw new c("no fetch implementation available in this runtime");let r=`${this.host}/v1/flags?distinct_id=${encodeURIComponent(e)}`,n=d(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let a=await s(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!a.ok)throw new c(`flags request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).flags??{}}finally{o!==void 0&&clearTimeout(o);}}async snapshot(){let e=this.fetch;if(!e)throw new c("no fetch implementation available in this runtime");let s=`${this.host}/v1/flags/snapshot`,r=d(),n=r?setTimeout(()=>r.abort(),this.requestTimeoutMs):void 0;try{let o=await e(s,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:r?.signal});if(!o.ok)throw new c(`flag snapshot request failed with status ${o.status}`,o.status);let a=JSON.parse(await o.text());return {flags:a.flags??[],generatedAt:a.generatedAt}}finally{n!==void 0&&clearTimeout(n);}}};var I=class{constructor(e,s,r){this.storage=e;this.ids=s;this.namespace=r;i(this,"anonymousId");i(this,"distinctId");i(this,"identified");let n=e.getItem(this.key("anonymous_id"));n?this.anonymousId=n:(this.anonymousId=s.uuid(),e.setItem(this.key("anonymous_id"),this.anonymousId));let o=e.getItem(this.key("distinct_id"));o?(this.distinctId=o,this.identified=true):(this.distinctId=this.anonymousId,this.identified=false);}getAnonymousId(){return this.anonymousId}getDistinctId(){return this.distinctId}isIdentified(){return this.identified}snapshot(){return {anonymousId:this.anonymousId,distinctId:this.distinctId,identified:this.identified}}identify(e){return this.identified&&this.distinctId===e?{changed:false}:(this.distinctId=e,this.identified=true,this.storage.setItem(this.key("distinct_id"),e),{changed:true})}reset(){this.anonymousId=this.ids.uuid(),this.distinctId=this.anonymousId,this.identified=false,this.storage.setItem(this.key("anonymous_id"),this.anonymousId),this.storage.removeItem(this.key("distinct_id"));}key(e){return `pdx.${this.namespace}.${e}`}};var E=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=m(e.fetch),this.host=u(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async inbox(e){let s=this.requireFetch(),r=`${this.host}/v1/messages?distinct_id=${encodeURIComponent(e)}`,n=await this.request(s,r,{headers:this.authHeaders(),method:"GET"});if(!n.ok)throw new c(`inbox request failed with status ${n.status}`,n.status);return JSON.parse(await n.text()).messages??[]}async markRead(e,s){let r=this.requireFetch(),n=`${this.host}/v1/messages/read`,o=await this.request(r,n,{body:JSON.stringify({distinct_id:s,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!o.ok)throw new c(`mark-read request failed with status ${o.status}`,o.status)}requireFetch(){if(!this.fetch)throw new c("no fetch implementation available in this runtime");return this.fetch}authHeaders(){return {authorization:`Bearer ${this.projectKey}`}}async request(e,s,r){let n=d(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s,{...r,signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}};var w=class{constructor(e,s){this.maxSize=e;this.onOverflow=s;i(this,"events",[]);}get size(){return this.events.length}enqueue(e){this.events.push(e),this.enforceCap();}restore(e){this.events.push(...e),this.enforceCap();}requeue(e){this.events.unshift(...e),this.enforceCap();}drain(e){let s=e===void 0?this.events.length:Math.min(e,this.events.length);return this.events.splice(0,s)}snapshot(){return [...this.events]}enforceCap(){if(this.events.length<=this.maxSize)return;let e=this.events.splice(0,this.events.length-this.maxSize);this.onOverflow?.({dropped:e});}};function V(t){return t>=400&&t<500&&t!==429}var F=class{constructor(e={}){i(this,"fetch");i(this,"maxRetries");i(this,"requestTimeoutMs");i(this,"baseDelayMs");i(this,"maxDelayMs");i(this,"sleep");i(this,"random");this.fetch=m(e.fetch),this.maxRetries=e.maxRetries??3,this.requestTimeoutMs=e.requestTimeoutMs??1e4,this.baseDelayMs=e.baseDelayMs??500,this.maxDelayMs=e.maxDelayMs??3e4,this.sleep=e.sleep??T,this.random=e.random??Math.random;}async send(e){let s=this.fetch;if(!s)throw new c("no fetch implementation available in this runtime");let r=JSON.stringify(e.body),n;for(let o=0;o<=this.maxRetries;o+=1){try{let a=await this.attempt(s,e,r);if(a.ok)return;if(V(a.status))throw new c(`ingest rejected batch with status ${a.status}`,a.status);n=new c(`ingest transient status ${a.status}`,a.status);}catch(a){if(a instanceof c&&a.status!==void 0&&V(a.status))throw a;n=a;}o<this.maxRetries&&await this.sleep(this.backoff(o));}throw new c("ingest delivery failed after retries",void 0,{cause:n})}async attempt(e,s,r){let n=d(),o=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{return await e(s.url,{body:r,headers:{authorization:`Bearer ${s.projectKey}`,"content-type":"application/json"},method:"POST",signal:n?.signal})}finally{o!==void 0&&clearTimeout(o);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var se="queue",re=1e3,ne=3e4,k=class{constructor(e){i(this,"config");i(this,"identity");i(this,"queue");i(this,"transport");i(this,"flagsClient");i(this,"messagesClient");i(this,"context");i(this,"flushTimer");i(this,"flushing",false);i(this,"cachedFlags");i(this,"cachedSnapshot");this.config=$(e),this.identity=new I(this.config.storage,this.config.ids,this.config.namespace),this.queue=new w(this.config.maxQueueSize,({dropped:s})=>{this.config.onError(new l("queue_overflow",`event queue overflow: dropped ${s.length} oldest event(s)`));}),this.transport=this.config.transport??new F({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new b({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.messagesClient=new E({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.context={sdk:this.config.sdkName,sdk_version:this.config.sdkVersion},this.config.os&&(this.context.os=this.config.os),this.config.locale&&(this.context.locale=this.config.locale),this.restoreQueue(),this.startTimer();}get distinctId(){return this.identity.getDistinctId()}get anonymousId(){return this.identity.getAnonymousId()}capture(e,s={}){try{let r={...this.config.defaultProperties(),...s.properties??{}},n=N({context:this.context,distinctId:this.identity.getDistinctId(),eventName:e,properties:r,sessionId:s.sessionId,timestamp:s.timestamp},this.config.clock,this.config.ids);this.enqueue(n);}catch(r){this.config.onError(r);}}identify(e,s={}){let r=this.identity.getAnonymousId(),n=!this.identity.isIdentified(),o=this.identity.identify(e),a={};n&&o.changed&&(a.$anon_distinct_id=r),s.set&&(a.$set=s.set),this.capture("$identify",{properties:a});}alias(e){this.capture("$create_alias",{properties:{alias:e}});}group(e,s,r){let n={$group_key:s,$group_type:e};r&&(n.$set=r),this.capture("$group",{properties:n});}setPersonProperties(e,s){let r={};e&&(r.$set=e),s&&(r.$set_once=s),this.capture("$set",{properties:r});}async getAllFlags(){let e=this.identity.getDistinctId(),s=await this.flagsClient.fetchAll(e);return this.cachedFlags={distinctId:e,flags:s},s}async isFeatureEnabled(e){return (await this.getAllFlags())[e]??false}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let s=await this.flagSnapshot();return j(s.flags,{attributes:e.attributes,distinctId:this.identity.getDistinctId(),properties:e.properties})}async isFeatureEnabledLocal(e,s){return (await this.getLocalFlags(s))[e]??false}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<ne)return this.cachedSnapshot.snapshot;let s=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:s},s}async getInbox(){return this.messagesClient.inbox(this.identity.getDistinctId())}async markMessageRead(e){await this.messagesClient.markRead(e,this.identity.getDistinctId());}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=true;let e=this.queue.drain(re);try{await this.transport.send({body:{events:e,sent_at:v(this.config.clock.now())},projectKey:this.config.apiKey,url:`${this.config.host}/v1/events`}),this.persistQueue();}catch(s){this.queue.requeue(e),this.persistQueue(),this.config.onError(s);}finally{this.flushing=false;}}reset(){this.identity.reset(),this.cachedFlags=void 0,this.cachedSnapshot=void 0;}async shutdown(){this.stopTimer(),await this.flush();}enqueue(e){this.queue.enqueue(e),this.persistQueue(),this.queue.size>=this.config.flushAt&&this.flush();}persistQueue(){try{this.config.storage.setItem(this.persistKey(),JSON.stringify(this.queue.snapshot()));}catch(e){this.config.onError(e);}}restoreQueue(){try{let e=this.config.storage.getItem(this.persistKey());if(!e)return;let s=JSON.parse(e);Array.isArray(s)&&this.queue.restore(s);}catch(e){this.config.onError(e);}}startTimer(){if(this.config.flushIntervalMs<=0)return;let e=setInterval(()=>{this.flush();},this.config.flushIntervalMs),s=e;typeof s.unref=="function"&&s.unref(),this.flushTimer=e;}stopTimer(){this.flushTimer!==void 0&&(clearInterval(this.flushTimer),this.flushTimer=void 0);}persistKey(){return `pdx.${this.config.namespace}.${se}`}};function z(){return globalThis.process}function ie(t){z()?.on("beforeExit",()=>{t.flush();});}function at(t){let e=z(),s={...t,os:t.os??(e?.platform?e.platform.slice(0,50):void 0)},r=new k(s);return ie(r),r}exports.createNodeClient=at;//# sourceMappingURL=node.cjs.map
2
+ //# sourceMappingURL=node.cjs.map
@@ -0,0 +1,5 @@
1
+ import { h as ProdantixConfig, P as ProdantixClient } from './client-B1bcIuD8.cjs';
2
+
3
+ declare function createNodeClient(options: ProdantixConfig): ProdantixClient;
4
+
5
+ export { createNodeClient };
package/dist/node.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { h as ProdantixConfig, P as ProdantixClient } from './client-B1bcIuD8.js';
2
+
3
+ declare function createNodeClient(options: ProdantixConfig): ProdantixClient;
4
+
5
+ export { createNodeClient };
package/dist/node.js ADDED
@@ -0,0 +1,2 @@
1
+ import {t as t$1}from'./chunk-FIZWZVZG.js';function t(){return globalThis.process}function s(o){t()?.on("beforeExit",()=>{o.flush();});}function f(o){let e=t(),r={...o,os:o.os??(e?.platform?e.platform.slice(0,50):void 0)},n=new t$1(r);return s(n),n}export{f as createNodeClient};//# sourceMappingURL=node.js.map
2
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1,39 @@
1
+ import { T as Transport, i as TransportRequest } from './client-B1bcIuD8.cjs';
2
+
3
+ interface FetchResponseLike {
4
+ ok: boolean;
5
+ status: number;
6
+ text(): Promise<string>;
7
+ }
8
+ interface FetchInit {
9
+ body?: string;
10
+ headers: Record<string, string>;
11
+ method: string;
12
+ signal?: AbortSignal;
13
+ }
14
+ type FetchLike = (url: string, init: FetchInit) => Promise<FetchResponseLike>;
15
+
16
+ interface FetchTransportOptions {
17
+ baseDelayMs?: number;
18
+ fetch?: FetchLike;
19
+ maxDelayMs?: number;
20
+ maxRetries?: number;
21
+ random?: () => number;
22
+ requestTimeoutMs?: number;
23
+ sleep?: (ms: number) => Promise<void>;
24
+ }
25
+ declare class FetchTransport implements Transport {
26
+ private readonly fetch?;
27
+ private readonly maxRetries;
28
+ private readonly requestTimeoutMs;
29
+ private readonly baseDelayMs;
30
+ private readonly maxDelayMs;
31
+ private readonly sleep;
32
+ private readonly random;
33
+ constructor(options?: FetchTransportOptions);
34
+ send(request: TransportRequest): Promise<void>;
35
+ private attempt;
36
+ private backoff;
37
+ }
38
+
39
+ export { type FetchLike as F, FetchTransport as a, type FetchTransportOptions as b };
@@ -0,0 +1,39 @@
1
+ import { T as Transport, i as TransportRequest } from './client-B1bcIuD8.js';
2
+
3
+ interface FetchResponseLike {
4
+ ok: boolean;
5
+ status: number;
6
+ text(): Promise<string>;
7
+ }
8
+ interface FetchInit {
9
+ body?: string;
10
+ headers: Record<string, string>;
11
+ method: string;
12
+ signal?: AbortSignal;
13
+ }
14
+ type FetchLike = (url: string, init: FetchInit) => Promise<FetchResponseLike>;
15
+
16
+ interface FetchTransportOptions {
17
+ baseDelayMs?: number;
18
+ fetch?: FetchLike;
19
+ maxDelayMs?: number;
20
+ maxRetries?: number;
21
+ random?: () => number;
22
+ requestTimeoutMs?: number;
23
+ sleep?: (ms: number) => Promise<void>;
24
+ }
25
+ declare class FetchTransport implements Transport {
26
+ private readonly fetch?;
27
+ private readonly maxRetries;
28
+ private readonly requestTimeoutMs;
29
+ private readonly baseDelayMs;
30
+ private readonly maxDelayMs;
31
+ private readonly sleep;
32
+ private readonly random;
33
+ constructor(options?: FetchTransportOptions);
34
+ send(request: TransportRequest): Promise<void>;
35
+ private attempt;
36
+ private backoff;
37
+ }
38
+
39
+ export { type FetchLike as F, FetchTransport as a, type FetchTransportOptions as b };
package/dist/web.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var he=Object.defineProperty;var fe=(t,e,r)=>e in t?he(t,e,{enumerable:true,configurable:true,writable:true,value:r}):t[e]=r;var i=(t,e,r)=>fe(t,typeof e!="symbol"?e+"":e,r);var h=class extends Error{constructor(r,n,s){super(n,s);i(this,"code");this.code=r,this.name="ProdantixError";}},x=class extends h{constructor(e){super("config",e),this.name="ConfigError";}},y=class extends h{constructor(r,n){super("validation",n);i(this,"field");this.field=r,this.name="ValidationError";}},l=class extends h{constructor(r,n,s){super("transport",r,s);i(this,"status");this.status=n,this.name="TransportError";}};function c(t){if(t)return t;let e=globalThis.fetch;if(typeof e=="function")return e.bind(globalThis)}function f(){let t=globalThis.AbortController;return t?new t:void 0}var D=t=>new Promise(e=>{setTimeout(e,t);});function p(t){return t.replace(/\/+$/,"")}var v=class{constructor(){i(this,"store",new Map);}getItem(e){return this.store.get(e)??null}removeItem(e){this.store.delete(e);}setItem(e,r){this.store.set(e,r);}};function K(){try{let t=globalThis.localStorage;if(t){let e="__pdx_probe__";return t.setItem(e,"1"),t.removeItem(e),t}}catch{return new v}return new v}var V={now:()=>new Date};function E(t){return t.toISOString()}function me(){return globalThis.crypto}function ge(t){t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[];for(let r=0;r<16;r+=1)e.push(t[r].toString(16).padStart(2,"0"));return `${e[0]}${e[1]}${e[2]}${e[3]}-${e[4]}${e[5]}-${e[6]}${e[7]}-${e[8]}${e[9]}-${e[10]}${e[11]}${e[12]}${e[13]}${e[14]}${e[15]}`}function O(){let t=me();if(t?.randomUUID)return t.randomUUID();let e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let r=0;r<16;r+=1)e[r]=Math.floor(Math.random()*256);return ge(e)}var z={uuid:O};var ye=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var ve=/^(?:\$|[a-z])[a-z0-9_.]*$/;function j(t){let e=0;for(let r of t)e+=1;return e}function H(t){return ye.test(t)}function be(t){return ve.test(t)}function B(t){let e=j(t);if(e<1||e>200)throw new y("distinct_id","distinct_id must be between 1 and 200 characters")}function U(t){let e=j(t);if(e<1||e>200)throw new y("event_name","event_name must be between 1 and 200 characters");if(!be(t))throw new y("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var J="prodantix-js",Q="0.0.1";var xe=t=>{};function W(t){if(!t.apiKey||!H(t.apiKey))throw new x("apiKey must be a public project key of the form pdx_pub_<32 lowercase alphanumerics>");if(!t.host)throw new x("host is required (the ingest base URL)");let e=p(t.host),r=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??V,defaultProperties:typeof r=="function"?r:()=>r??{},flagsHost:t.flagsHost?p(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??z,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??xe,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??J,sdkVersion:t.sdkVersion??Q,storage:t.storage??new v,transport:t.transport}}function G(t,e,r){U(t.eventName),B(t.distinctId);let n={distinct_id:t.distinctId,event_id:t.eventId??r.uuid(),event_name:t.eventName,properties:t.properties??{},schema_version:1,timestamp:E(t.timestamp??e.now())};return t.context&&(n.context=t.context),t.sessionId&&(n.session_id=t.sessionId),n}var g=Symbol("absent");function ke(t,e){if(t==="distinct_id")return e.distinctId;let r=e.properties??{};if(Object.prototype.hasOwnProperty.call(r,t))return r[t];let n=e.attributes??{};return Object.prototype.hasOwnProperty.call(n,t)?n[t]:g}function m(t){return t===g?"undefined":String(t)}function X(t){return t===g?Number.NaN:Number(t)}function Y(t){return t!==g&&t!==null&&t!==""}function Z(t,e){if(!Array.isArray(e))return false;let r=m(t);return e.map(n=>String(n)).includes(r)}function ee(t,e){let r=ke(t.attribute,e),n=t.value;switch(t.op){case "is_set":return Y(r);case "is_not_set":return !Y(r);case "eq":return m(r)===m(n===void 0?g:n);case "neq":return m(r)!==m(n===void 0?g:n);case "contains":return m(r).includes(m(n===void 0?g:n));case "in":return Z(r,n);case "not_in":return Array.isArray(n)?!Z(r,n):false;case "gt":return I(r,n,(s,o)=>s>o);case "gte":return I(r,n,(s,o)=>s>=o);case "lt":return I(r,n,(s,o)=>s<o);case "lte":return I(r,n,(s,o)=>s<=o);default:return false}}function I(t,e,r){let n=X(t),s=e===void 0?Number.NaN:X(e);return Number.isNaN(n)||Number.isNaN(s)?false:r(n,s)}function Ee(t,e){let r=`${t}:${e}`,n=2166136261;for(let s=0;s<r.length;s++)n^=r.charCodeAt(s),n=Math.imul(n,16777619);return (n>>>0)%100}function Ie(t,e){return t.enabled?t.targeting.length>0&&!t.targeting.every(r=>ee(r,e))?{enabled:false,reason:"targeting"}:t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:Ee(t.key,e.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"disabled"}}function te(t,e){let r={};for(let n of t)r[n.key]=Ie(n,e).enabled;return r}var T=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=c(e.fetch),this.host=p(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){let r=this.fetch;if(!r)throw new l("no fetch implementation available in this runtime");let n=`${this.host}/v1/flags?distinct_id=${encodeURIComponent(e)}`,s=f(),o=s?setTimeout(()=>s.abort(),this.requestTimeoutMs):void 0;try{let a=await r(n,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:s?.signal});if(!a.ok)throw new l(`flags request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).flags??{}}finally{o!==void 0&&clearTimeout(o);}}async snapshot(){let e=this.fetch;if(!e)throw new l("no fetch implementation available in this runtime");let r=`${this.host}/v1/flags/snapshot`,n=f(),s=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let o=await e(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!o.ok)throw new l(`flag snapshot request failed with status ${o.status}`,o.status);let a=JSON.parse(await o.text());return {flags:a.flags??[],generatedAt:a.generatedAt}}finally{s!==void 0&&clearTimeout(s);}}};var w=class{constructor(e,r,n){this.storage=e;this.ids=r;this.namespace=n;i(this,"anonymousId");i(this,"distinctId");i(this,"identified");let s=e.getItem(this.key("anonymous_id"));s?this.anonymousId=s:(this.anonymousId=r.uuid(),e.setItem(this.key("anonymous_id"),this.anonymousId));let o=e.getItem(this.key("distinct_id"));o?(this.distinctId=o,this.identified=true):(this.distinctId=this.anonymousId,this.identified=false);}getAnonymousId(){return this.anonymousId}getDistinctId(){return this.distinctId}isIdentified(){return this.identified}snapshot(){return {anonymousId:this.anonymousId,distinctId:this.distinctId,identified:this.identified}}identify(e){return this.identified&&this.distinctId===e?{changed:false}:(this.distinctId=e,this.identified=true,this.storage.setItem(this.key("distinct_id"),e),{changed:true})}reset(){this.anonymousId=this.ids.uuid(),this.distinctId=this.anonymousId,this.identified=false,this.storage.setItem(this.key("anonymous_id"),this.anonymousId),this.storage.removeItem(this.key("distinct_id"));}key(e){return `pdx.${this.namespace}.${e}`}};var S=class{constructor(e){i(this,"fetch");i(this,"host");i(this,"projectKey");i(this,"requestTimeoutMs");this.fetch=c(e.fetch),this.host=p(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async inbox(e){let r=this.requireFetch(),n=`${this.host}/v1/messages?distinct_id=${encodeURIComponent(e)}`,s=await this.request(r,n,{headers:this.authHeaders(),method:"GET"});if(!s.ok)throw new l(`inbox request failed with status ${s.status}`,s.status);return JSON.parse(await s.text()).messages??[]}async markRead(e,r){let n=this.requireFetch(),s=`${this.host}/v1/messages/read`,o=await this.request(n,s,{body:JSON.stringify({distinct_id:r,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!o.ok)throw new l(`mark-read request failed with status ${o.status}`,o.status)}requireFetch(){if(!this.fetch)throw new l("no fetch implementation available in this runtime");return this.fetch}authHeaders(){return {authorization:`Bearer ${this.projectKey}`}}async request(e,r,n){let s=f(),o=s?setTimeout(()=>s.abort(),this.requestTimeoutMs):void 0;try{return await e(r,{...n,signal:s?.signal})}finally{o!==void 0&&clearTimeout(o);}}};var C=class{constructor(e,r){this.maxSize=e;this.onOverflow=r;i(this,"events",[]);}get size(){return this.events.length}enqueue(e){this.events.push(e),this.enforceCap();}restore(e){this.events.push(...e),this.enforceCap();}requeue(e){this.events.unshift(...e),this.enforceCap();}drain(e){let r=e===void 0?this.events.length:Math.min(e,this.events.length);return this.events.splice(0,r)}snapshot(){return [...this.events]}enforceCap(){if(this.events.length<=this.maxSize)return;let e=this.events.splice(0,this.events.length-this.maxSize);this.onOverflow?.({dropped:e});}};function re(t){return t>=400&&t<500&&t!==429}var b=class{constructor(e={}){i(this,"fetch");i(this,"maxRetries");i(this,"requestTimeoutMs");i(this,"baseDelayMs");i(this,"maxDelayMs");i(this,"sleep");i(this,"random");this.fetch=c(e.fetch),this.maxRetries=e.maxRetries??3,this.requestTimeoutMs=e.requestTimeoutMs??1e4,this.baseDelayMs=e.baseDelayMs??500,this.maxDelayMs=e.maxDelayMs??3e4,this.sleep=e.sleep??D,this.random=e.random??Math.random;}async send(e){let r=this.fetch;if(!r)throw new l("no fetch implementation available in this runtime");let n=JSON.stringify(e.body),s;for(let o=0;o<=this.maxRetries;o+=1){try{let a=await this.attempt(r,e,n);if(a.ok)return;if(re(a.status))throw new l(`ingest rejected batch with status ${a.status}`,a.status);s=new l(`ingest transient status ${a.status}`,a.status);}catch(a){if(a instanceof l&&a.status!==void 0&&re(a.status))throw a;s=a;}o<this.maxRetries&&await this.sleep(this.backoff(o));}throw new l("ingest delivery failed after retries",void 0,{cause:s})}async attempt(e,r,n){let s=f(),o=s?setTimeout(()=>s.abort(),this.requestTimeoutMs):void 0;try{return await e(r.url,{body:n,headers:{authorization:`Bearer ${r.projectKey}`,"content-type":"application/json"},method:"POST",signal:s?.signal})}finally{o!==void 0&&clearTimeout(o);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var Te="queue",we=1e3,Se=3e4,P=class{constructor(e){i(this,"config");i(this,"identity");i(this,"queue");i(this,"transport");i(this,"flagsClient");i(this,"messagesClient");i(this,"context");i(this,"flushTimer");i(this,"flushing",false);i(this,"cachedFlags");i(this,"cachedSnapshot");this.config=W(e),this.identity=new w(this.config.storage,this.config.ids,this.config.namespace),this.queue=new C(this.config.maxQueueSize,({dropped:r})=>{this.config.onError(new h("queue_overflow",`event queue overflow: dropped ${r.length} oldest event(s)`));}),this.transport=this.config.transport??new b({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new T({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.messagesClient=new S({host:this.config.flagsHost,projectKey:this.config.apiKey,requestTimeoutMs:this.config.requestTimeoutMs}),this.context={sdk:this.config.sdkName,sdk_version:this.config.sdkVersion},this.config.os&&(this.context.os=this.config.os),this.config.locale&&(this.context.locale=this.config.locale),this.restoreQueue(),this.startTimer();}get distinctId(){return this.identity.getDistinctId()}get anonymousId(){return this.identity.getAnonymousId()}capture(e,r={}){try{let n={...this.config.defaultProperties(),...r.properties??{}},s=G({context:this.context,distinctId:this.identity.getDistinctId(),eventName:e,properties:n,sessionId:r.sessionId,timestamp:r.timestamp},this.config.clock,this.config.ids);this.enqueue(s);}catch(n){this.config.onError(n);}}identify(e,r={}){let n=this.identity.getAnonymousId(),s=!this.identity.isIdentified(),o=this.identity.identify(e),a={};s&&o.changed&&(a.$anon_distinct_id=n),r.set&&(a.$set=r.set),this.capture("$identify",{properties:a});}alias(e){this.capture("$create_alias",{properties:{alias:e}});}group(e,r,n){let s={$group_key:r,$group_type:e};n&&(s.$set=n),this.capture("$group",{properties:s});}setPersonProperties(e,r){let n={};e&&(n.$set=e),r&&(n.$set_once=r),this.capture("$set",{properties:n});}async getAllFlags(){let e=this.identity.getDistinctId(),r=await this.flagsClient.fetchAll(e);return this.cachedFlags={distinctId:e,flags:r},r}async isFeatureEnabled(e){return (await this.getAllFlags())[e]??false}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let r=await this.flagSnapshot();return te(r.flags,{attributes:e.attributes,distinctId:this.identity.getDistinctId(),properties:e.properties})}async isFeatureEnabledLocal(e,r){return (await this.getLocalFlags(r))[e]??false}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<Se)return this.cachedSnapshot.snapshot;let r=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:r},r}async getInbox(){return this.messagesClient.inbox(this.identity.getDistinctId())}async markMessageRead(e){await this.messagesClient.markRead(e,this.identity.getDistinctId());}async flush(){if(this.flushing||this.queue.size===0)return;this.flushing=true;let e=this.queue.drain(we);try{await this.transport.send({body:{events:e,sent_at:E(this.config.clock.now())},projectKey:this.config.apiKey,url:`${this.config.host}/v1/events`}),this.persistQueue();}catch(r){this.queue.requeue(e),this.persistQueue(),this.config.onError(r);}finally{this.flushing=false;}}reset(){this.identity.reset(),this.cachedFlags=void 0,this.cachedSnapshot=void 0;}async shutdown(){this.stopTimer(),await this.flush();}enqueue(e){this.queue.enqueue(e),this.persistQueue(),this.queue.size>=this.config.flushAt&&this.flush();}persistQueue(){try{this.config.storage.setItem(this.persistKey(),JSON.stringify(this.queue.snapshot()));}catch(e){this.config.onError(e);}}restoreQueue(){try{let e=this.config.storage.getItem(this.persistKey());if(!e)return;let r=JSON.parse(e);Array.isArray(r)&&this.queue.restore(r);}catch(e){this.config.onError(e);}}startTimer(){if(this.config.flushIntervalMs<=0)return;let e=setInterval(()=>{this.flush();},this.config.flushIntervalMs),r=e;typeof r.unref=="function"&&r.unref(),this.flushTimer=e;}stopTimer(){this.flushTimer!==void 0&&(clearInterval(this.flushTimer),this.flushTimer=void 0);}persistKey(){return `pdx.${this.config.namespace}.${Te}`}};function ne(){return globalThis.location}function se(){return globalThis.document}function Ce(){return globalThis.window??globalThis}function Pe(t){return typeof t=="object"&&t!==null&&typeof t.tagName=="string"}function ie(){let t=ne(),e=se(),r={};return t&&(r.$current_url=t.href,r.$pathname=t.pathname,r.$host=t.host),e&&(e.title&&(r.$title=e.title),e.referrer&&(r.$referrer=e.referrer)),r}function Re(t){let e={$el_tag:t.tagName.toLowerCase(),$event_type:"click"},r=t.textContent?.trim();r&&(e.$el_text=r.slice(0,255)),t.id&&(e.$el_id=t.id),typeof t.className=="string"&&t.className&&(e.$el_classes=t.className);let n=t.getAttribute("href");return n&&(e.$el_href=n),e}function Ne(t){let e=globalThis.history,r=Ce(),n="",s=()=>{let u=ne(),d=u?`${u.pathname}${u.search}`:"";d!==n&&(n=d,t.capture("$pageview",{properties:ie()}));};if(s(),!e||!r)return ()=>{};let o=e.pushState.bind(e),a=e.replaceState.bind(e);return e.pushState=(...u)=>{o(...u),s();},e.replaceState=(...u)=>{a(...u),s();},r.addEventListener("popstate",s),()=>{e.pushState=o,e.replaceState=a,r.removeEventListener("popstate",s);}}function Fe(t){let e=se();if(!e)return ()=>{};let r=n=>{let s=n.target;Pe(s)&&t.capture("$autocapture",{properties:{...ie(),...Re(s)}});};return e.addEventListener("click",r,true),()=>e.removeEventListener("click",r,true)}function oe(t,e={}){let r=[];return (e.pageviews??true)&&r.push(Ne(t)),(e.clicks??true)&&r.push(Fe(t)),()=>{for(let n of r)n();}}function _e(){return globalThis.document?.visibilityState==="hidden"}function Me(t){let e=globalThis.navigator,r=globalThis.Blob;if(!e?.sendBeacon||!r)return false;let n=JSON.stringify({...t.body,api_key:t.projectKey});try{let s=new r([n],{type:"application/json"});return e.sendBeacon(t.url,s)}catch{return false}}var R=class{constructor(e={}){i(this,"fetchTransport");this.fetchTransport=new b(e);}async send(e){_e()&&Me(e)||await this.fetchTransport.send(e);}};var ae={maskAllInputs:true,maskAllText:false},Ae=new Set(["email","password","tel"]);function le(t){return t.replace(/\S/g,"*")}function N(t,e,r){return Le(e)||r.maskAllInputs?le(t):t}function F(t,e){return e.maskAllText?le(t):t}function Le(t){return Ae.has((t??"").toLowerCase())}var Oe=5e3,_=class{constructor(e){this.options=e;i(this,"buffer",[]);i(this,"seq",0);i(this,"maxEvents");this.maxEvents=Math.min(Math.max(1,e.maxEvents),Oe);}add(e){return this.buffer.push(e),this.buffer.length>=this.maxEvents?this.flush():null}flush(){if(this.buffer.length===0)return null;let e=this.buffer;this.buffer=[];let r={distinct_id:this.options.distinctId(),events:e,masked:this.options.masked,schema_version:1,seq:this.seq,session_id:this.options.sessionId,timestamp:new Date(this.options.now()).toISOString()};return this.seq+=1,r}};var $=1,q=3,$e=9,M=class{constructor(){i(this,"next",1);}allocate(){let e=this.next;return this.next+=1,e}},qe=new Set(["NOSCRIPT","SCRIPT"]);function A(t,e,r,n){if(t.nodeType===q){let s=e.allocate();return n?.(t,s),{id:s,textContent:F(t.textValue??"",r),type:"text"}}if(t.nodeType===$e){let s=e.allocate();return n?.(t,s),{childNodes:ue(t,e,r,n),id:s,type:"document"}}if(t.nodeType===$){let s=t.tagName??"";if(qe.has(s))return null;let o=e.allocate();return n?.(t,o),{attributes:De(t,r),childNodes:ue(t,e,r,n),id:o,tagName:s,type:"element"}}return null}function ue(t,e,r,n){let s=[];for(let o of t.childNodes??[]){let a=A(o,e,r,n);a&&s.push(a);}return s}function De(t,e){let r={};for(let n of t.attributes??[])r[n.name]=n.value;return t.inputValue!==void 0&&(r.value=N(t.inputValue,t.inputType,e)),r}async function pe(t,e){let r=`${p(e.replayHost)}/v1/replay`;return (await e.fetch(r,{body:JSON.stringify(t),headers:{authorization:`Bearer ${e.apiKey}`,"content-type":"application/json"},method:"POST"})).ok}var ce=new Set(["INPUT","SELECT","TEXTAREA"]),L=class{constructor(e){this.options=e;i(this,"allocator",new M);i(this,"mirror",new Map);i(this,"chunker");i(this,"fetchImpl");i(this,"observer");i(this,"timer");i(this,"started",false);this.chunker=new _({distinctId:e.distinctId,masked:e.mask.maskAllInputs,maxEvents:e.maxEvents,now:e.now,sessionId:e.sessionId}),this.fetchImpl=c(e.fetch);}start(){if(this.started)return;let e=Ke(),r=e?.documentElement;!e||!r||!this.fetchImpl||(this.started=true,this.captureFullSnapshot(r),this.observeMutations(r),this.observeInteractions(e),this.timer=setInterval(()=>this.upload(this.chunker.flush()),this.options.flushIntervalMs));}stop(){this.started&&(this.started=false,this.observer?.disconnect(),this.timer&&clearInterval(this.timer),this.upload(this.chunker.flush()));}captureFullSnapshot(e){let r=A(this.adapt(e),this.allocator,this.options.mask,(n,s)=>{let o=n.ref;o&&this.mirror.set(o,s);});r&&this.push(2,{node:r});}observeMutations(e){let r=globalThis.MutationObserver;r&&(this.observer=new r(n=>{for(let s of n)this.handleMutation(s);}),this.observer.observe(e,{attributes:true,characterData:true,childList:true,subtree:true}));}handleMutation(e){if(e.type==="characterData"){let r=this.mirror.get(e.target);r!==void 0&&this.push(3,{texts:[{id:r,value:F(e.target.textContent??"",this.options.mask)}]});return}if(e.type==="attributes"&&e.attributeName){let r=this.mirror.get(e.target),n=e.target;r!==void 0&&this.push(3,{attributes:[{attributes:{[e.attributeName]:n.getAttribute(e.attributeName)??""},id:r}]});return}if(e.type==="childList"){let r=this.mirror.get(e.target);if(r===void 0)return;for(let n of Array.from(e.addedNodes)){let s=A(this.adapt(n),this.allocator,this.options.mask,(o,a)=>{let u=o.ref;u&&this.mirror.set(u,a);});s&&this.push(3,{adds:[{node:s,parentId:r}]});}for(let n of Array.from(e.removedNodes)){let s=this.mirror.get(n);s!==void 0&&(this.push(3,{removes:[{id:s,parentId:r}]}),this.mirror.delete(n));}}}observeInteractions(e){e.addEventListener("input",r=>{let n=r.target;if(!n||!ce.has(n.tagName))return;let s=this.mirror.get(n);s!==void 0&&this.push(3,{input:{id:s,value:N(n.value??"",n.type,this.options.mask)}});},true),e.addEventListener("scroll",r=>{let n=r.target,s=n?this.mirror.get(n):void 0;this.push(3,{scroll:{id:s??0,x:n?.scrollLeft??0,y:n?.scrollTop??0}});},true);}adapt(e){let r={childNodes:[],nodeType:e.nodeType,ref:e};if(e.nodeType===q)return r.textValue=e.textContent??"",r;if(e.nodeType===$){let n=e;if(r.tagName=n.tagName,r.attributes=Array.from(n.attributes).map(s=>({name:s.name,value:s.value})),ce.has(n.tagName)){let s=n;r.inputType=s.type,r.inputValue=s.value??"";}}return r.childNodes=Array.from(e.childNodes).map(n=>this.adapt(n)),r}push(e,r){let n=this.chunker.add({data:r,timestamp:this.options.now(),type:e});n&&this.upload(n);}upload(e){!e||!this.fetchImpl||pe(e,{apiKey:this.options.apiKey,fetch:this.fetchImpl,replayHost:this.options.replayHost}).catch(r=>this.options.onError?.(r));}};function Ke(){return globalThis.document}function de(t){let e=new L({apiKey:t.apiKey,distinctId:t.distinctId,flushIntervalMs:t.flushIntervalMs??5e3,mask:{...ae,...t.mask},maxEvents:t.maxEvents??200,now:t.now??(()=>Date.now()),onError:t.onError,replayHost:t.replayHost,sessionId:t.sessionId??O()});return e.start(),e}function Ve(){return globalThis.navigator}function ze(t){let e=t?.userAgentData?.platform??t?.platform;return e?e.slice(0,50):void 0}function je(t){let e=()=>{t.flush();};globalThis.document?.addEventListener?.("visibilitychange",e),globalThis.addEventListener?.("pagehide",e);}function br(t){let{autocaptureOptions:e,replayHost:r,sessionReplay:n,sessionReplayOptions:s,...o}=t,a=Ve(),u={...o,locale:o.locale??(a?.language?a.language.slice(0,20):void 0),os:o.os??ze(a),storage:o.storage??K(),transport:o.transport??new R({maxRetries:o.maxRetries,requestTimeoutMs:o.requestTimeoutMs})},d=new P(u);return je(d),(t.autocapture??true)&&oe(d,e),n&&r&&de({apiKey:u.apiKey,distinctId:()=>d.distinctId,onError:u.onError,replayHost:r,...s}),d}exports.WebTransport=R;exports.createWebClient=br;exports.installAutocapture=oe;exports.installSessionReplay=de;//# sourceMappingURL=web.cjs.map
2
+ //# sourceMappingURL=web.cjs.map
package/dist/web.d.cts ADDED
@@ -0,0 +1,97 @@
1
+ import { P as ProdantixClient, T as Transport, i as TransportRequest, h as ProdantixConfig } from './client-B1bcIuD8.cjs';
2
+ import { b as FetchTransportOptions, F as FetchLike } from './transport-B3PxeUxW.cjs';
3
+
4
+ interface AutocaptureOptions {
5
+ clicks?: boolean;
6
+ pageviews?: boolean;
7
+ }
8
+ declare function installAutocapture(client: ProdantixClient, options?: AutocaptureOptions): () => void;
9
+
10
+ declare class WebTransport implements Transport {
11
+ private readonly fetchTransport;
12
+ constructor(options?: FetchTransportOptions);
13
+ send(request: TransportRequest): Promise<void>;
14
+ }
15
+
16
+ /** PII masking for session replay (default-on per the security rule). `maskAllInputs`
17
+ * redacts every input value; `maskAllText` redacts visible text nodes too. Password,
18
+ * email, and tel inputs are ALWAYS redacted regardless of options — turning masking
19
+ * off never exposes a credential field. */
20
+ interface MaskOptions {
21
+ maskAllInputs: boolean;
22
+ maskAllText: boolean;
23
+ }
24
+
25
+ interface RecorderOptions {
26
+ apiKey: string;
27
+ distinctId: () => string;
28
+ fetch?: FetchLike;
29
+ flushIntervalMs: number;
30
+ mask: MaskOptions;
31
+ maxEvents: number;
32
+ now: () => number;
33
+ onError?: (error: unknown) => void;
34
+ replayHost: string;
35
+ sessionId: string;
36
+ }
37
+ /** The browser session recorder (WI-6). Captures a full DOM snapshot, then streams
38
+ * incremental mutations + input/scroll interactions (input values masked), batching
39
+ * them into chunks the recorder service ingests. A node→id mirror built during the
40
+ * snapshot keeps mutation references stable. Best-effort: any capture/upload error is
41
+ * routed to `onError`, never thrown into the host page. */
42
+ declare class SessionRecorder {
43
+ private readonly options;
44
+ private readonly allocator;
45
+ private readonly mirror;
46
+ private readonly chunker;
47
+ private readonly fetchImpl?;
48
+ private observer?;
49
+ private timer?;
50
+ private started;
51
+ constructor(options: RecorderOptions);
52
+ /** Begins recording. No-op when already started or when the DOM/fetch is unavailable
53
+ * (e.g. SSR) — session replay is a browser-only enhancement. */
54
+ start(): void;
55
+ /** Stops recording and flushes any buffered events. */
56
+ stop(): void;
57
+ private captureFullSnapshot;
58
+ private observeMutations;
59
+ private handleMutation;
60
+ private observeInteractions;
61
+ private adapt;
62
+ private push;
63
+ private upload;
64
+ }
65
+
66
+ interface SessionReplayOptions {
67
+ apiKey: string;
68
+ distinctId: () => string;
69
+ flushIntervalMs?: number;
70
+ mask?: Partial<MaskOptions>;
71
+ maxEvents?: number;
72
+ now?: () => number;
73
+ onError?: (error: unknown) => void;
74
+ replayHost: string;
75
+ sessionId?: string;
76
+ }
77
+ /** Starts session replay: capture the DOM + interactions (inputs masked by default)
78
+ * and stream chunks to the recorder service. Returns the recorder so the caller can
79
+ * `stop()` it. A missing `sessionId` gets a fresh v4 uuid. */
80
+ declare function installSessionReplay(options: SessionReplayOptions): SessionRecorder;
81
+
82
+ /** Tunables for the built-in session replay, minus the identity fields
83
+ * `createWebClient` fills in (apiKey, distinctId, replayHost). */
84
+ type WebSessionReplayOptions = Pick<SessionReplayOptions, 'flushIntervalMs' | 'mask' | 'maxEvents' | 'sessionId'>;
85
+ interface WebClientOptions extends ProdantixConfig {
86
+ autocaptureOptions?: AutocaptureOptions;
87
+ /** Host of the recorder service (`eu.replay.prodantix.com`). Required to enable
88
+ * session replay. */
89
+ replayHost?: string;
90
+ /** Enable session replay (DOM + interaction capture, inputs masked by default).
91
+ * Requires `replayHost`. */
92
+ sessionReplay?: boolean;
93
+ sessionReplayOptions?: WebSessionReplayOptions;
94
+ }
95
+ declare function createWebClient(options: WebClientOptions): ProdantixClient;
96
+
97
+ export { type AutocaptureOptions, type MaskOptions, type SessionReplayOptions, type WebClientOptions, type WebSessionReplayOptions, WebTransport, createWebClient, installAutocapture, installSessionReplay };
package/dist/web.d.ts ADDED
@@ -0,0 +1,97 @@
1
+ import { P as ProdantixClient, T as Transport, i as TransportRequest, h as ProdantixConfig } from './client-B1bcIuD8.js';
2
+ import { b as FetchTransportOptions, F as FetchLike } from './transport-By6wsdny.js';
3
+
4
+ interface AutocaptureOptions {
5
+ clicks?: boolean;
6
+ pageviews?: boolean;
7
+ }
8
+ declare function installAutocapture(client: ProdantixClient, options?: AutocaptureOptions): () => void;
9
+
10
+ declare class WebTransport implements Transport {
11
+ private readonly fetchTransport;
12
+ constructor(options?: FetchTransportOptions);
13
+ send(request: TransportRequest): Promise<void>;
14
+ }
15
+
16
+ /** PII masking for session replay (default-on per the security rule). `maskAllInputs`
17
+ * redacts every input value; `maskAllText` redacts visible text nodes too. Password,
18
+ * email, and tel inputs are ALWAYS redacted regardless of options — turning masking
19
+ * off never exposes a credential field. */
20
+ interface MaskOptions {
21
+ maskAllInputs: boolean;
22
+ maskAllText: boolean;
23
+ }
24
+
25
+ interface RecorderOptions {
26
+ apiKey: string;
27
+ distinctId: () => string;
28
+ fetch?: FetchLike;
29
+ flushIntervalMs: number;
30
+ mask: MaskOptions;
31
+ maxEvents: number;
32
+ now: () => number;
33
+ onError?: (error: unknown) => void;
34
+ replayHost: string;
35
+ sessionId: string;
36
+ }
37
+ /** The browser session recorder (WI-6). Captures a full DOM snapshot, then streams
38
+ * incremental mutations + input/scroll interactions (input values masked), batching
39
+ * them into chunks the recorder service ingests. A node→id mirror built during the
40
+ * snapshot keeps mutation references stable. Best-effort: any capture/upload error is
41
+ * routed to `onError`, never thrown into the host page. */
42
+ declare class SessionRecorder {
43
+ private readonly options;
44
+ private readonly allocator;
45
+ private readonly mirror;
46
+ private readonly chunker;
47
+ private readonly fetchImpl?;
48
+ private observer?;
49
+ private timer?;
50
+ private started;
51
+ constructor(options: RecorderOptions);
52
+ /** Begins recording. No-op when already started or when the DOM/fetch is unavailable
53
+ * (e.g. SSR) — session replay is a browser-only enhancement. */
54
+ start(): void;
55
+ /** Stops recording and flushes any buffered events. */
56
+ stop(): void;
57
+ private captureFullSnapshot;
58
+ private observeMutations;
59
+ private handleMutation;
60
+ private observeInteractions;
61
+ private adapt;
62
+ private push;
63
+ private upload;
64
+ }
65
+
66
+ interface SessionReplayOptions {
67
+ apiKey: string;
68
+ distinctId: () => string;
69
+ flushIntervalMs?: number;
70
+ mask?: Partial<MaskOptions>;
71
+ maxEvents?: number;
72
+ now?: () => number;
73
+ onError?: (error: unknown) => void;
74
+ replayHost: string;
75
+ sessionId?: string;
76
+ }
77
+ /** Starts session replay: capture the DOM + interactions (inputs masked by default)
78
+ * and stream chunks to the recorder service. Returns the recorder so the caller can
79
+ * `stop()` it. A missing `sessionId` gets a fresh v4 uuid. */
80
+ declare function installSessionReplay(options: SessionReplayOptions): SessionRecorder;
81
+
82
+ /** Tunables for the built-in session replay, minus the identity fields
83
+ * `createWebClient` fills in (apiKey, distinctId, replayHost). */
84
+ type WebSessionReplayOptions = Pick<SessionReplayOptions, 'flushIntervalMs' | 'mask' | 'maxEvents' | 'sessionId'>;
85
+ interface WebClientOptions extends ProdantixConfig {
86
+ autocaptureOptions?: AutocaptureOptions;
87
+ /** Host of the recorder service (`eu.replay.prodantix.com`). Required to enable
88
+ * session replay. */
89
+ replayHost?: string;
90
+ /** Enable session replay (DOM + interaction capture, inputs masked by default).
91
+ * Requires `replayHost`. */
92
+ sessionReplay?: boolean;
93
+ sessionReplayOptions?: WebSessionReplayOptions;
94
+ }
95
+ declare function createWebClient(options: WebClientOptions): ProdantixClient;
96
+
97
+ export { type AutocaptureOptions, type MaskOptions, type SessionReplayOptions, type WebClientOptions, type WebSessionReplayOptions, WebTransport, createWebClient, installAutocapture, installSessionReplay };
package/dist/web.js ADDED
@@ -0,0 +1,2 @@
1
+ import {a,s,j as j$1,i,t,f as f$1,g as g$1}from'./chunk-FIZWZVZG.js';function w(){return globalThis.location}function S(){return globalThis.document}function D(){return globalThis.window??globalThis}function V(e){return typeof e=="object"&&e!==null&&typeof e.tagName=="string"}function O(){let e=w(),t=S(),n={};return e&&(n.$current_url=e.href,n.$pathname=e.pathname,n.$host=e.host),t&&(t.title&&(n.$title=t.title),t.referrer&&(n.$referrer=t.referrer)),n}function H(e){let t={$el_tag:e.tagName.toLowerCase(),$event_type:"click"},n=e.textContent?.trim();n&&(t.$el_text=n.slice(0,255)),e.id&&(t.$el_id=e.id),typeof e.className=="string"&&e.className&&(t.$el_classes=e.className);let i=e.getAttribute("href");return i&&(t.$el_href=i),t}function $(e){let t=globalThis.history,n=D(),i="",r=()=>{let a=w(),l=a?`${a.pathname}${a.search}`:"";l!==i&&(i=l,e.capture("$pageview",{properties:O()}));};if(r(),!t||!n)return ()=>{};let s=t.pushState.bind(t),p=t.replaceState.bind(t);return t.pushState=(...a)=>{s(...a),r();},t.replaceState=(...a)=>{p(...a),r();},n.addEventListener("popstate",r),()=>{t.pushState=s,t.replaceState=p,n.removeEventListener("popstate",r);}}function K(e){let t=S();if(!t)return ()=>{};let n=i=>{let r=i.target;V(r)&&e.capture("$autocapture",{properties:{...O(),...H(r)}});};return t.addEventListener("click",n,true),()=>t.removeEventListener("click",n,true)}function I(e,t={}){let n=[];return (t.pageviews??true)&&n.push($(e)),(t.clicks??true)&&n.push(K(e)),()=>{for(let i of n)i();}}function F(){return globalThis.document?.visibilityState==="hidden"}function B(e){let t=globalThis.navigator,n=globalThis.Blob;if(!t?.sendBeacon||!n)return false;let i=JSON.stringify({...e.body,api_key:e.projectKey});try{let r=new n([i],{type:"application/json"});return t.sendBeacon(e.url,r)}catch{return false}}var c=class{constructor(t={}){a(this,"fetchTransport");this.fetchTransport=new s(t);}async send(t){F()&&B(t)||await this.fetchTransport.send(t);}};var R={maskAllInputs:true,maskAllText:false},W=new Set(["email","password","tel"]);function A(e){return e.replace(/\S/g,"*")}function d(e,t,n){return z(t)||n.maskAllInputs?A(e):e}function f(e,t){return t.maskAllText?A(e):e}function z(e){return W.has((e??"").toLowerCase())}var U=5e3,m=class{constructor(t){this.options=t;a(this,"buffer",[]);a(this,"seq",0);a(this,"maxEvents");this.maxEvents=Math.min(Math.max(1,t.maxEvents),U);}add(t){return this.buffer.push(t),this.buffer.length>=this.maxEvents?this.flush():null}flush(){if(this.buffer.length===0)return null;let t=this.buffer;this.buffer=[];let n={distinct_id:this.options.distinctId(),events:t,masked:this.options.masked,schema_version:1,seq:this.seq,session_id:this.options.sessionId,timestamp:new Date(this.options.now()).toISOString()};return this.seq+=1,n}};var v=1,k=3,q=9,h=class{constructor(){a(this,"next",1);}allocate(){let t=this.next;return this.next+=1,t}},j=new Set(["NOSCRIPT","SCRIPT"]);function g(e,t,n,i){if(e.nodeType===k){let r=t.allocate();return i?.(e,r),{id:r,textContent:f(e.textValue??"",n),type:"text"}}if(e.nodeType===q){let r=t.allocate();return i?.(e,r),{childNodes:M(e,t,n,i),id:r,type:"document"}}if(e.nodeType===v){let r=e.tagName??"";if(j.has(r))return null;let s=t.allocate();return i?.(e,s),{attributes:X(e,n),childNodes:M(e,t,n,i),id:s,tagName:r,type:"element"}}return null}function M(e,t,n,i){let r=[];for(let s of e.childNodes??[]){let p=g(s,t,n,i);p&&r.push(p);}return r}function X(e,t){let n={};for(let i of e.attributes??[])n[i.name]=i.value;return e.inputValue!==void 0&&(n.value=d(e.inputValue,e.inputType,t)),n}async function P(e,t){let n=`${g$1(t.replayHost)}/v1/replay`;return (await t.fetch(n,{body:JSON.stringify(e),headers:{authorization:`Bearer ${t.apiKey}`,"content-type":"application/json"},method:"POST"})).ok}var C=new Set(["INPUT","SELECT","TEXTAREA"]),y=class{constructor(t){this.options=t;a(this,"allocator",new h);a(this,"mirror",new Map);a(this,"chunker");a(this,"fetchImpl");a(this,"observer");a(this,"timer");a(this,"started",false);this.chunker=new m({distinctId:t.distinctId,masked:t.mask.maskAllInputs,maxEvents:t.maxEvents,now:t.now,sessionId:t.sessionId}),this.fetchImpl=f$1(t.fetch);}start(){if(this.started)return;let t=Y(),n=t?.documentElement;!t||!n||!this.fetchImpl||(this.started=true,this.captureFullSnapshot(n),this.observeMutations(n),this.observeInteractions(t),this.timer=setInterval(()=>this.upload(this.chunker.flush()),this.options.flushIntervalMs));}stop(){this.started&&(this.started=false,this.observer?.disconnect(),this.timer&&clearInterval(this.timer),this.upload(this.chunker.flush()));}captureFullSnapshot(t){let n=g(this.adapt(t),this.allocator,this.options.mask,(i,r)=>{let s=i.ref;s&&this.mirror.set(s,r);});n&&this.push(2,{node:n});}observeMutations(t){let n=globalThis.MutationObserver;n&&(this.observer=new n(i=>{for(let r of i)this.handleMutation(r);}),this.observer.observe(t,{attributes:true,characterData:true,childList:true,subtree:true}));}handleMutation(t){if(t.type==="characterData"){let n=this.mirror.get(t.target);n!==void 0&&this.push(3,{texts:[{id:n,value:f(t.target.textContent??"",this.options.mask)}]});return}if(t.type==="attributes"&&t.attributeName){let n=this.mirror.get(t.target),i=t.target;n!==void 0&&this.push(3,{attributes:[{attributes:{[t.attributeName]:i.getAttribute(t.attributeName)??""},id:n}]});return}if(t.type==="childList"){let n=this.mirror.get(t.target);if(n===void 0)return;for(let i of Array.from(t.addedNodes)){let r=g(this.adapt(i),this.allocator,this.options.mask,(s,p)=>{let a=s.ref;a&&this.mirror.set(a,p);});r&&this.push(3,{adds:[{node:r,parentId:n}]});}for(let i of Array.from(t.removedNodes)){let r=this.mirror.get(i);r!==void 0&&(this.push(3,{removes:[{id:r,parentId:n}]}),this.mirror.delete(i));}}}observeInteractions(t){t.addEventListener("input",n=>{let i=n.target;if(!i||!C.has(i.tagName))return;let r=this.mirror.get(i);r!==void 0&&this.push(3,{input:{id:r,value:d(i.value??"",i.type,this.options.mask)}});},true),t.addEventListener("scroll",n=>{let i=n.target,r=i?this.mirror.get(i):void 0;this.push(3,{scroll:{id:r??0,x:i?.scrollLeft??0,y:i?.scrollTop??0}});},true);}adapt(t){let n={childNodes:[],nodeType:t.nodeType,ref:t};if(t.nodeType===k)return n.textValue=t.textContent??"",n;if(t.nodeType===v){let i=t;if(n.tagName=i.tagName,n.attributes=Array.from(i.attributes).map(r=>({name:r.name,value:r.value})),C.has(i.tagName)){let r=i;n.inputType=r.type,n.inputValue=r.value??"";}}return n.childNodes=Array.from(t.childNodes).map(i=>this.adapt(i)),n}push(t,n){let i=this.chunker.add({data:n,timestamp:this.options.now(),type:t});i&&this.upload(i);}upload(t){!t||!this.fetchImpl||P(t,{apiKey:this.options.apiKey,fetch:this.fetchImpl,replayHost:this.options.replayHost}).catch(n=>this.options.onError?.(n));}};function Y(){return globalThis.document}function _(e){let t=new y({apiKey:e.apiKey,distinctId:e.distinctId,flushIntervalMs:e.flushIntervalMs??5e3,mask:{...R,...e.mask},maxEvents:e.maxEvents??200,now:e.now??(()=>Date.now()),onError:e.onError,replayHost:e.replayHost,sessionId:e.sessionId??j$1()});return t.start(),t}function G(){return globalThis.navigator}function J(e){let t=e?.userAgentData?.platform??e?.platform;return t?t.slice(0,50):void 0}function Q(e){let t=()=>{e.flush();};globalThis.document?.addEventListener?.("visibilitychange",t),globalThis.addEventListener?.("pagehide",t);}function It(e){let{autocaptureOptions:t$1,replayHost:n,sessionReplay:i$1,sessionReplayOptions:r,...s}=e,p=G(),a={...s,locale:s.locale??(p?.language?p.language.slice(0,20):void 0),os:s.os??J(p),storage:s.storage??i(),transport:s.transport??new c({maxRetries:s.maxRetries,requestTimeoutMs:s.requestTimeoutMs})},l=new t(a);return Q(l),(e.autocapture??true)&&I(l,t$1),i$1&&n&&_({apiKey:a.apiKey,distinctId:()=>l.distinctId,onError:a.onError,replayHost:n,...r}),l}export{c as WebTransport,It as createWebClient,I as installAutocapture,_ as installSessionReplay};//# sourceMappingURL=web.js.map
2
+ //# sourceMappingURL=web.js.map
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "description": "Prodantix analytics + feature-flag client SDK (isomorphic, zero-dependency)",
3
+ "devDependencies": {
4
+ "@bomdisoft/typescript-config": "0.0.0",
5
+ "@types/bun": "^1.3.14",
6
+ "@types/node": "^25.9.3",
7
+ "tsup": "8.5.1",
8
+ "typescript": "^6.0.3"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./node": {
17
+ "import": "./dist/node.js",
18
+ "require": "./dist/node.cjs",
19
+ "types": "./dist/node.d.ts"
20
+ },
21
+ "./package.json": "./package.json",
22
+ "./web": {
23
+ "import": "./dist/web.js",
24
+ "require": "./dist/web.cjs",
25
+ "types": "./dist/web.d.ts"
26
+ }
27
+ },
28
+ "files": ["dist", "!dist/**/*.map"],
29
+ "homepage": "https://prodantix.com",
30
+ "license": "MIT",
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.js",
33
+ "name": "@prodantix/sdk",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "dev": "tsup --watch",
40
+ "format": "biome format --write .",
41
+ "format:check": "biome format --check .",
42
+ "lint": "biome check .",
43
+ "lint:fix": "biome check --write .",
44
+ "test:unit": "bun test --pass-with-no-tests",
45
+ "typecheck": "tsc --noEmit"
46
+ },
47
+ "sideEffects": false,
48
+ "type": "module",
49
+ "types": "./dist/index.d.ts",
50
+ "version": "0.0.1-beta.319"
51
+ }