@prodantix/sdk 0.0.1 → 0.1.0-beta.348

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +11 -4
  2. package/dist/chat.cjs +65 -0
  3. package/dist/chat.d.cts +64 -0
  4. package/dist/chat.d.ts +64 -0
  5. package/dist/chat.js +65 -0
  6. package/dist/chunk-5XGN7UAV.js +2 -0
  7. package/dist/chunk-CSIP3PZ7.js +2 -0
  8. package/dist/chunk-V77KYPOF.js +2 -0
  9. package/dist/chunk-VG77TYVX.js +2 -0
  10. package/dist/client-Ca6xJESF.d.ts +105 -0
  11. package/dist/client-y1xyVF6C.d.cts +105 -0
  12. package/dist/config-B-cTz9n1.d.ts +94 -0
  13. package/dist/config-OP9Csae6.d.cts +94 -0
  14. package/dist/csp.cjs +3 -0
  15. package/dist/csp.d.cts +37 -0
  16. package/dist/csp.d.ts +37 -0
  17. package/dist/csp.js +3 -0
  18. package/dist/http-BCh716Vs.d.cts +14 -0
  19. package/dist/http-BCh716Vs.d.ts +14 -0
  20. package/dist/index.cjs +1 -1
  21. package/dist/index.d.cts +28 -6
  22. package/dist/index.d.ts +28 -6
  23. package/dist/index.js +1 -1
  24. package/dist/messenger.cjs +2 -0
  25. package/dist/messenger.d.cts +2 -0
  26. package/dist/messenger.d.ts +2 -0
  27. package/dist/messenger.iife.js +65 -0
  28. package/dist/messenger.js +2 -0
  29. package/dist/node.cjs +1 -1
  30. package/dist/node.d.cts +2 -1
  31. package/dist/node.d.ts +2 -1
  32. package/dist/node.js +1 -1
  33. package/dist/{transport-By6wsdny.d.ts → transport-Bj4nXmgt.d.cts} +3 -15
  34. package/dist/{transport-B3PxeUxW.d.cts → transport-CTPih3Jj.d.ts} +3 -15
  35. package/dist/types-68Sc11g8.d.cts +105 -0
  36. package/dist/types-68Sc11g8.d.ts +105 -0
  37. package/dist/web.cjs +1 -1
  38. package/dist/web.d.cts +4 -2
  39. package/dist/web.d.ts +4 -2
  40. package/dist/web.js +1 -1
  41. package/package.json +19 -3
  42. package/dist/chunk-FIZWZVZG.js +0 -2
  43. package/dist/client-B1bcIuD8.d.cts +0 -133
  44. package/dist/client-B1bcIuD8.d.ts +0 -133
@@ -0,0 +1,105 @@
1
+ import { d as EventProperties, P as ProdantixConfig, e as FlagVariant, I as InboxMessage } from './types-68Sc11g8.cjs';
2
+
3
+ interface LocalFlagContext {
4
+ attributes?: EventProperties;
5
+ /** The cohorts the current distinct id belongs to. When omitted and the
6
+ * snapshot names a cohort, the client fetches them once per distinct id. */
7
+ cohorts?: string[];
8
+ properties?: EventProperties;
9
+ }
10
+ interface CaptureOptions {
11
+ properties?: EventProperties;
12
+ sessionId?: string;
13
+ timestamp?: Date;
14
+ }
15
+ /**
16
+ * The profile keys the platform itself understands.
17
+ *
18
+ * They are ordinary properties on the wire; the only thing that makes them
19
+ * special is the `$` prefix, which is how this platform marks a name it owns
20
+ * rather than one the caller chose. Passing them through `traits` means never
21
+ * having to remember whether the console reads `email` or `$email`: an
22
+ * unprefixed `email` is a property of your own and stays one, and would never
23
+ * reach the Email column.
24
+ */
25
+ interface PersonTraits {
26
+ avatar?: string;
27
+ email?: string;
28
+ name?: string;
29
+ phone?: string;
30
+ }
31
+ interface IdentifyOptions {
32
+ /** Arbitrary profile properties your own code defines. */
33
+ set?: EventProperties;
34
+ /** The reserved traits the console renders as fields. */
35
+ traits?: PersonTraits;
36
+ }
37
+ declare class ProdantixClient {
38
+ private readonly config;
39
+ private readonly identity;
40
+ private readonly queue;
41
+ private readonly transport;
42
+ private readonly flagsClient;
43
+ private readonly messagesClient;
44
+ private readonly context;
45
+ private flushTimer?;
46
+ private flushing;
47
+ private cachedFlags?;
48
+ private cachedSnapshot?;
49
+ private membershipCache?;
50
+ private stream?;
51
+ private shutDown;
52
+ /** One `$feature_flag_called` per (distinct id, flag, response) per client
53
+ * lifetime: the experiment engine attributes on the FIRST exposure, so a
54
+ * second event for the same answer would only cost the project an event. */
55
+ private readonly exposures;
56
+ constructor(config: ProdantixConfig);
57
+ get distinctId(): string;
58
+ get anonymousId(): string;
59
+ capture(eventName: string, options?: CaptureOptions): void;
60
+ identify(distinctId: string, options?: IdentifyOptions): void;
61
+ alias(alias: string): void;
62
+ group(groupType: string, groupKey: string, properties?: EventProperties): void;
63
+ setPersonProperties(set?: EventProperties, setOnce?: EventProperties): void;
64
+ /**
65
+ * Attach the reserved traits to whoever is current, without an identify.
66
+ *
67
+ * This does NOT make the person identified: only `identify()` does that, so a
68
+ * trait set on an anonymous visitor leaves them anonymous and carrying an
69
+ * address, which is exactly what a newsletter signup before login looks like.
70
+ */
71
+ setPersonTraits(traits: PersonTraits): void;
72
+ getAllFlags(): Promise<Record<string, boolean>>;
73
+ isFeatureEnabled(key: string): Promise<boolean>;
74
+ /** The assigned variation for one flag, or null when the flag is unknown or
75
+ * carries no variations. Records the exposure either way. */
76
+ getVariant(key: string): Promise<FlagVariant | null>;
77
+ getVariantLocal(key: string, context?: LocalFlagContext): Promise<FlagVariant | null>;
78
+ private recordExposure;
79
+ getCachedFlag(key: string): boolean | undefined;
80
+ getLocalFlags(context?: LocalFlagContext): Promise<Record<string, boolean>>;
81
+ isFeatureEnabledLocal(key: string, context?: LocalFlagContext): Promise<boolean>;
82
+ /** The evaluation context for a local read. Memberships come from the caller
83
+ * when supplied, else from the server once per distinct id per snapshot
84
+ * TTL, and only when the snapshot names a cohort at all. */
85
+ private localContext;
86
+ private flagSnapshot;
87
+ /** Opens the flag stream once, when streaming was asked for and the snapshot
88
+ * names a gateway. A pushed change drops the cached snapshot and refetches
89
+ * it; a refused handshake stays closed, a dropped one reopens. */
90
+ private maybeStream;
91
+ getInbox(): Promise<InboxMessage[]>;
92
+ markMessageRead(messageId: string): Promise<void>;
93
+ flush(): Promise<void>;
94
+ reset(): void;
95
+ shutdown(): Promise<void>;
96
+ private enqueue;
97
+ private persistQueue;
98
+ private restoreQueue;
99
+ private startTimer;
100
+ private stopTimer;
101
+ private persistKey;
102
+ }
103
+ declare function createClient(config: ProdantixConfig): ProdantixClient;
104
+
105
+ export { type CaptureOptions as C, type IdentifyOptions as I, type LocalFlagContext as L, ProdantixClient as P, createClient as c };
@@ -0,0 +1,94 @@
1
+ import { F as FetchLike } from './http-BCh716Vs.js';
2
+
3
+ interface ChatTurn {
4
+ id: string;
5
+ authorKind: 'end_user' | 'agent' | 'ai';
6
+ authorId: string | null;
7
+ body: string;
8
+ createdAt: string;
9
+ }
10
+ interface ChatThread {
11
+ id: string;
12
+ status: string;
13
+ turns: ChatTurn[];
14
+ }
15
+ interface ChatClientOptions {
16
+ apiKey: string;
17
+ host: string;
18
+ distinctId: string;
19
+ storage?: ChatStorage;
20
+ fetchImpl?: FetchLike;
21
+ onError?: (error: unknown) => void;
22
+ }
23
+ interface ChatIdentity {
24
+ userId: string;
25
+ userHash: string;
26
+ }
27
+ interface ChatStorage {
28
+ get(key: string): string | null;
29
+ set(key: string, value: string): void;
30
+ remove(key: string): void;
31
+ }
32
+ declare class ChatClient {
33
+ private readonly options;
34
+ private readonly fetchImpl?;
35
+ private readonly host;
36
+ private readonly storage?;
37
+ private handle;
38
+ private identity;
39
+ constructor(options: ChatClientOptions);
40
+ get hasThread(): boolean;
41
+ get socketAuth(): {
42
+ conversationId: string;
43
+ conversationToken: string;
44
+ projectKey: string;
45
+ } | null;
46
+ identify(identity: ChatIdentity): void;
47
+ ensureThread(subject?: string): Promise<boolean>;
48
+ send(body: string): Promise<ChatTurn | null>;
49
+ load(): Promise<ChatThread | null>;
50
+ private readHandle;
51
+ private request;
52
+ }
53
+
54
+ type MessengerSkin = 'concierge' | 'console' | 'quiet';
55
+ type LauncherStyle = 'avatar_circle' | 'circle_filled' | 'circle_outlined' | 'pill_labelled' | 'pill_team' | 'squircle_filled';
56
+ type BubbleStyle = 'hairline' | 'outlined' | 'rounded' | 'tailed';
57
+ type NamePlacement = 'above' | 'avatar_only' | 'gutter' | 'hidden' | 'inline';
58
+ type TimestampStyle = 'cluster' | 'latency' | 'none' | 'trailing' | 'with_name';
59
+ interface AppearanceSettings {
60
+ bubbleStyle: BubbleStyle;
61
+ launcherStyle: LauncherStyle;
62
+ namePlacement: NamePlacement;
63
+ skin: MessengerSkin;
64
+ timestampStyle: TimestampStyle;
65
+ }
66
+ declare const DEFAULT_APPEARANCE_SETTINGS: AppearanceSettings;
67
+ declare function resolveAppearance(config: Partial<AppearanceSettings> | null | undefined): AppearanceSettings;
68
+
69
+ interface MessengerConfig extends AppearanceSettings {
70
+ enabled: boolean;
71
+ launcherPosition: 'bottom_left' | 'bottom_right';
72
+ launcherOffsetX: number;
73
+ launcherOffsetY: number;
74
+ accentColor: string;
75
+ greeting: string;
76
+ awayMessage: string;
77
+ availability: unknown;
78
+ version: string;
79
+ starterPrompts: string[];
80
+ socketUrl: string;
81
+ }
82
+ interface MessengerConfigOptions {
83
+ apiKey: string;
84
+ host: string;
85
+ locale?: string;
86
+ storage?: ChatStorage;
87
+ fetchImpl?: FetchLike;
88
+ onError?: (error: unknown) => void;
89
+ }
90
+ declare const MESSENGER_CACHE_KEY = "prodantix.messenger.config";
91
+ declare function cachedMessengerConfig(storage: ChatStorage | undefined, apiKey: string): MessengerConfig | null;
92
+ declare function fetchMessengerConfig(options: MessengerConfigOptions): Promise<MessengerConfig | null>;
93
+
94
+ export { type AppearanceSettings as A, type BubbleStyle as B, ChatClient as C, DEFAULT_APPEARANCE_SETTINGS as D, type LauncherStyle as L, type MessengerConfig as M, type NamePlacement as N, type TimestampStyle as T, type ChatTurn as a, type ChatIdentity as b, type ChatClientOptions as c, type ChatStorage as d, type ChatThread as e, type MessengerSkin as f, MESSENGER_CACHE_KEY as g, type MessengerConfigOptions as h, cachedMessengerConfig as i, fetchMessengerConfig as j, resolveAppearance as r };
@@ -0,0 +1,94 @@
1
+ import { F as FetchLike } from './http-BCh716Vs.cjs';
2
+
3
+ interface ChatTurn {
4
+ id: string;
5
+ authorKind: 'end_user' | 'agent' | 'ai';
6
+ authorId: string | null;
7
+ body: string;
8
+ createdAt: string;
9
+ }
10
+ interface ChatThread {
11
+ id: string;
12
+ status: string;
13
+ turns: ChatTurn[];
14
+ }
15
+ interface ChatClientOptions {
16
+ apiKey: string;
17
+ host: string;
18
+ distinctId: string;
19
+ storage?: ChatStorage;
20
+ fetchImpl?: FetchLike;
21
+ onError?: (error: unknown) => void;
22
+ }
23
+ interface ChatIdentity {
24
+ userId: string;
25
+ userHash: string;
26
+ }
27
+ interface ChatStorage {
28
+ get(key: string): string | null;
29
+ set(key: string, value: string): void;
30
+ remove(key: string): void;
31
+ }
32
+ declare class ChatClient {
33
+ private readonly options;
34
+ private readonly fetchImpl?;
35
+ private readonly host;
36
+ private readonly storage?;
37
+ private handle;
38
+ private identity;
39
+ constructor(options: ChatClientOptions);
40
+ get hasThread(): boolean;
41
+ get socketAuth(): {
42
+ conversationId: string;
43
+ conversationToken: string;
44
+ projectKey: string;
45
+ } | null;
46
+ identify(identity: ChatIdentity): void;
47
+ ensureThread(subject?: string): Promise<boolean>;
48
+ send(body: string): Promise<ChatTurn | null>;
49
+ load(): Promise<ChatThread | null>;
50
+ private readHandle;
51
+ private request;
52
+ }
53
+
54
+ type MessengerSkin = 'concierge' | 'console' | 'quiet';
55
+ type LauncherStyle = 'avatar_circle' | 'circle_filled' | 'circle_outlined' | 'pill_labelled' | 'pill_team' | 'squircle_filled';
56
+ type BubbleStyle = 'hairline' | 'outlined' | 'rounded' | 'tailed';
57
+ type NamePlacement = 'above' | 'avatar_only' | 'gutter' | 'hidden' | 'inline';
58
+ type TimestampStyle = 'cluster' | 'latency' | 'none' | 'trailing' | 'with_name';
59
+ interface AppearanceSettings {
60
+ bubbleStyle: BubbleStyle;
61
+ launcherStyle: LauncherStyle;
62
+ namePlacement: NamePlacement;
63
+ skin: MessengerSkin;
64
+ timestampStyle: TimestampStyle;
65
+ }
66
+ declare const DEFAULT_APPEARANCE_SETTINGS: AppearanceSettings;
67
+ declare function resolveAppearance(config: Partial<AppearanceSettings> | null | undefined): AppearanceSettings;
68
+
69
+ interface MessengerConfig extends AppearanceSettings {
70
+ enabled: boolean;
71
+ launcherPosition: 'bottom_left' | 'bottom_right';
72
+ launcherOffsetX: number;
73
+ launcherOffsetY: number;
74
+ accentColor: string;
75
+ greeting: string;
76
+ awayMessage: string;
77
+ availability: unknown;
78
+ version: string;
79
+ starterPrompts: string[];
80
+ socketUrl: string;
81
+ }
82
+ interface MessengerConfigOptions {
83
+ apiKey: string;
84
+ host: string;
85
+ locale?: string;
86
+ storage?: ChatStorage;
87
+ fetchImpl?: FetchLike;
88
+ onError?: (error: unknown) => void;
89
+ }
90
+ declare const MESSENGER_CACHE_KEY = "prodantix.messenger.config";
91
+ declare function cachedMessengerConfig(storage: ChatStorage | undefined, apiKey: string): MessengerConfig | null;
92
+ declare function fetchMessengerConfig(options: MessengerConfigOptions): Promise<MessengerConfig | null>;
93
+
94
+ export { type AppearanceSettings as A, type BubbleStyle as B, ChatClient as C, DEFAULT_APPEARANCE_SETTINGS as D, type LauncherStyle as L, type MessengerConfig as M, type NamePlacement as N, type TimestampStyle as T, type ChatTurn as a, type ChatIdentity as b, type ChatClientOptions as c, type ChatStorage as d, type ChatThread as e, type MessengerSkin as f, MESSENGER_CACHE_KEY as g, type MessengerConfigOptions as h, cachedMessengerConfig as i, fetchMessengerConfig as j, resolveAppearance as r };
package/dist/csp.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';function r(n){let t=n?.trim()??"";if(t==="")return null;try{return new URL(t).origin}catch{return null}}function s(n){return n.startsWith("https://")?`wss://${n.slice(8)}`:n.startsWith("http://")?`ws://${n.slice(7)}`:null}function i(n){return [...new Set(["'self'",...n.filter(t=>t!==null)])].join(" ")}function l(n,t=[]){let e=r(n.edge);return i([...t,r(n.ingest),e,e===null?null:s(e),r(n.replay)])}function o(n,t=[]){return i([...t,r(n.edge)])}
2
+ exports.prodantixConnectSrc=l;exports.prodantixScriptSrc=o;//# sourceMappingURL=csp.cjs.map
3
+ //# sourceMappingURL=csp.cjs.map
package/dist/csp.d.cts ADDED
@@ -0,0 +1,37 @@
1
+ /** The content-security-policy sources an app needs to reach prodantix.
2
+ *
3
+ * Imported by `next.config.ts`, so this module must stay free of React and of
4
+ * anything that only resolves in the browser. A browser-only import here breaks
5
+ * the BUILD rather than the page, which is at least loud.
6
+ *
7
+ * Moved out of `@bomdisoft/analytics` when that package was retired, and
8
+ * extended. The original emitted the analytics host alone, which was correct
9
+ * while events were the only thing the SDK sent. The messenger adds a websocket
10
+ * and a script, and a policy that is too narrow fails only in a visitor's
11
+ * browser console: nine sites permitted the analytics host and would have
12
+ * blocked the messenger with nothing on our side to show for it.
13
+ *
14
+ * Every app that installs the SDK posts to `${host}/v1/…`, and a policy of
15
+ * `'self'` blocks that in every environment, not only locally: these hosts are
16
+ * different origins from the site in staging and production too. Analytics
17
+ * never worked from any of these apps until that was derived from the same env
18
+ * var the component reads.
19
+ */
20
+ interface ProdantixHosts {
21
+ /** Event ingest, e.g. `https://eu.api.prodantix.com`. */
22
+ ingest?: string;
23
+ /** The public browser edge: flags, messages, conversations, the messenger. */
24
+ edge?: string;
25
+ /** Session replay, when the app enables it. */
26
+ replay?: string;
27
+ }
28
+ /** Everything the SDK CONNECTS to: ingest, the edge, replay, and the edge's
29
+ * websocket. */
30
+ declare function prodantixConnectSrc(hosts: ProdantixHosts, extra?: readonly string[]): string;
31
+ /** Where a SCRIPT may be fetched from, which is the edge alone: it serves
32
+ * `/messenger.js` and the other hosts serve no script at all. Emitting them
33
+ * here would widen the policy for nothing, and a needlessly wide script-src is
34
+ * the one direction of CSP error that never announces itself. */
35
+ declare function prodantixScriptSrc(hosts: ProdantixHosts, extra?: readonly string[]): string;
36
+
37
+ export { type ProdantixHosts, prodantixConnectSrc, prodantixScriptSrc };
package/dist/csp.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ /** The content-security-policy sources an app needs to reach prodantix.
2
+ *
3
+ * Imported by `next.config.ts`, so this module must stay free of React and of
4
+ * anything that only resolves in the browser. A browser-only import here breaks
5
+ * the BUILD rather than the page, which is at least loud.
6
+ *
7
+ * Moved out of `@bomdisoft/analytics` when that package was retired, and
8
+ * extended. The original emitted the analytics host alone, which was correct
9
+ * while events were the only thing the SDK sent. The messenger adds a websocket
10
+ * and a script, and a policy that is too narrow fails only in a visitor's
11
+ * browser console: nine sites permitted the analytics host and would have
12
+ * blocked the messenger with nothing on our side to show for it.
13
+ *
14
+ * Every app that installs the SDK posts to `${host}/v1/…`, and a policy of
15
+ * `'self'` blocks that in every environment, not only locally: these hosts are
16
+ * different origins from the site in staging and production too. Analytics
17
+ * never worked from any of these apps until that was derived from the same env
18
+ * var the component reads.
19
+ */
20
+ interface ProdantixHosts {
21
+ /** Event ingest, e.g. `https://eu.api.prodantix.com`. */
22
+ ingest?: string;
23
+ /** The public browser edge: flags, messages, conversations, the messenger. */
24
+ edge?: string;
25
+ /** Session replay, when the app enables it. */
26
+ replay?: string;
27
+ }
28
+ /** Everything the SDK CONNECTS to: ingest, the edge, replay, and the edge's
29
+ * websocket. */
30
+ declare function prodantixConnectSrc(hosts: ProdantixHosts, extra?: readonly string[]): string;
31
+ /** Where a SCRIPT may be fetched from, which is the edge alone: it serves
32
+ * `/messenger.js` and the other hosts serve no script at all. Emitting them
33
+ * here would widen the policy for nothing, and a needlessly wide script-src is
34
+ * the one direction of CSP error that never announces itself. */
35
+ declare function prodantixScriptSrc(hosts: ProdantixHosts, extra?: readonly string[]): string;
36
+
37
+ export { type ProdantixHosts, prodantixConnectSrc, prodantixScriptSrc };
package/dist/csp.js ADDED
@@ -0,0 +1,3 @@
1
+ import'./chunk-5XGN7UAV.js';function r(n){let t=n?.trim()??"";if(t==="")return null;try{return new URL(t).origin}catch{return null}}function s(n){return n.startsWith("https://")?`wss://${n.slice(8)}`:n.startsWith("http://")?`ws://${n.slice(7)}`:null}function i(n){return [...new Set(["'self'",...n.filter(t=>t!==null)])].join(" ")}function l(n,t=[]){let e=r(n.edge);return i([...t,r(n.ingest),e,e===null?null:s(e),r(n.replay)])}function o(n,t=[]){return i([...t,r(n.edge)])}
2
+ export{l as prodantixConnectSrc,o as prodantixScriptSrc};//# sourceMappingURL=csp.js.map
3
+ //# sourceMappingURL=csp.js.map
@@ -0,0 +1,14 @@
1
+ interface FetchResponseLike {
2
+ ok: boolean;
3
+ status: number;
4
+ text(): Promise<string>;
5
+ }
6
+ interface FetchInit {
7
+ body?: string;
8
+ headers: Record<string, string>;
9
+ method: string;
10
+ signal?: AbortSignal;
11
+ }
12
+ type FetchLike = (url: string, init: FetchInit) => Promise<FetchResponseLike>;
13
+
14
+ export type { FetchLike as F };
@@ -0,0 +1,14 @@
1
+ interface FetchResponseLike {
2
+ ok: boolean;
3
+ status: number;
4
+ text(): Promise<string>;
5
+ }
6
+ interface FetchInit {
7
+ body?: string;
8
+ headers: Record<string, string>;
9
+ method: string;
10
+ signal?: AbortSignal;
11
+ }
12
+ type FetchLike = (url: string, init: FetchInit) => Promise<FetchResponseLike>;
13
+
14
+ export type { FetchLike as F };
package/dist/index.cjs CHANGED
@@ -1,2 +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
1
+ 'use strict';var ie=Object.defineProperty;var oe=(t,e,r)=>e in t?ie(t,e,{enumerable:true,configurable:true,writable:true,value:r}):t[e]=r;var o=(t,e,r)=>oe(t,typeof e!="symbol"?e+"":e,r);var u=class extends Error{constructor(r,n,s){super(n,s);o(this,"code");this.code=r,this.name="ProdantixError";}},m=class extends u{constructor(e){super("config",e),this.name="ConfigError";}},p=class extends u{constructor(r,n){super("validation",n);o(this,"field");this.field=r,this.name="ValidationError";}},l=class extends u{constructor(r,n,s){super("transport",r,s);o(this,"status");this.status=n,this.name="TransportError";}};function y(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 K=t=>new Promise(e=>{setTimeout(e,t);});function h(t){return t.replace(/\/+$/,"")}var v=class{constructor(){o(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 D={now:()=>new Date};function I(t){return t.toISOString()}function ae(){return globalThis.crypto}function le(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 ce(){let t=ae();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 le(e)}var L={uuid:ce};var ue=/^pdx_pub_(?:(?:live|test)_)?[a-z0-9]{32}$/;var de=/^(?:\$|[a-z])[a-z0-9_.]*$/;function V(t){let e=0;for(let r of t)e+=1;return e}function j(t){return ue.test(t)}function pe(t){return de.test(t)}function G(t){let e=V(t);if(e<1||e>200)throw new p("distinct_id","distinct_id must be between 1 and 200 characters")}function U(t){let e=V(t);if(e<1||e>200)throw new p("event_name","event_name must be between 1 and 200 characters");if(!pe(t))throw new p("event_name","event_name must match /^(\\$|[a-z])[a-z0-9_.]*$/")}var P="prodantix-js",R="0.0.1";var he=t=>{};function z(t){if(!t.apiKey||!j(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=h(t.host),r=t.defaultProperties;return {apiKey:t.apiKey,autocapture:t.autocapture??false,clock:t.clock??D,defaultProperties:typeof r=="function"?r:()=>r??{},flagsHost:t.flagsHost?h(t.flagsHost):e,flushAt:t.flushAt??20,flushIntervalMs:t.flushIntervalMs??1e4,host:e,ids:t.ids??L,locale:t.locale,maxQueueSize:t.maxQueueSize??1e3,maxRetries:t.maxRetries??3,namespace:t.apiKey.slice(0,16),onError:t.onError??he,os:t.os,requestTimeoutMs:t.requestTimeoutMs??1e4,sdkName:t.sdkName??P,sdkVersion:t.sdkVersion??R,socketFactory:t.socketFactory,storage:t.storage??new v,streamFlags:t.streamFlags??false,transport:t.transport}}function H(t,e,r){U(t.eventName),G(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:I(t.timestamp??e.now())};return t.context&&(n.context=t.context),t.sessionId&&(n.session_id=t.sessionId),n}var g=Symbol("absent");function fe(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 f(t){return t===g?"undefined":String(t)}function J(t){return t===g?Number.NaN:Number(t)}function B(t){return t!==g&&t!==null&&t!==""}function Q(t,e){if(!Array.isArray(e))return false;let r=f(t);return e.map(n=>String(n)).includes(r)}function N(t,e){let r=fe(t.attribute,e),n=t.value;switch(t.op){case "is_set":return B(r);case "is_not_set":return !B(r);case "eq":return f(r)===f(n===void 0?g:n);case "neq":return f(r)!==f(n===void 0?g:n);case "contains":return f(r).includes(f(n===void 0?g:n));case "in":return Q(r,n);case "not_in":return Array.isArray(n)?!Q(r,n):false;case "gt":return S(r,n,(s,i)=>s>i);case "gte":return S(r,n,(s,i)=>s>=i);case "lt":return S(r,n,(s,i)=>s<i);case "lte":return S(r,n,(s,i)=>s<=i);case "in_cohort":return typeof n=="string"&&n!==""&&(e.cohorts??[]).includes(n);case "not_in_cohort":return typeof n=="string"&&n!==""&&!(e.cohorts??[]).includes(n);default:return false}}function S(t,e,r){let n=J(t),s=e===void 0?Number.NaN:J(e);return Number.isNaN(n)||Number.isNaN(s)?false:r(n,s)}function $(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 A(t,e){return t.targeting.length===0||t.targeting.every(r=>N(r,e))}function W(t,e){let r=$(t.key,e.distinctId),n=t.variations??[];if(n.length===0)return t.rolloutPercentage>=100||r<t.rolloutPercentage?"true":"false";let s=0;for(let i=n.length-1;i>=0;i--)if(s+=n[i].weight,r<s)return n[i].key;return n[0].key}function O(t,e,r,n){for(let s of t.prerequisites??[]){if(n.includes(s.flagKey))return false;let i=e.find(c=>c.key===s.flagKey);if(!i||!i.enabled)return false;n.push(i.key);let a=O(i,e,r,n)&&A(i,r)&&W(i,r)===s.variationKey;if(n.pop(),!a)return false}return true}function b(t,e,r){return t.enabled?O(t,e,r,[t.key])?A(t,r)?t.rolloutPercentage>=100?{enabled:true,reason:"rollout_full"}:$(t.key,r.distinctId)<t.rolloutPercentage?{enabled:true,reason:"rollout"}:{enabled:false,reason:"rollout_excluded"}:{enabled:false,reason:"targeting"}:{enabled:false,reason:"prerequisite"}:{enabled:false,reason:"disabled"}}function ge(t,e){return b(t,[],e)}function M(t,e){let r={};for(let n of t)r[n.key]=b(n,t,e).enabled;return r}function k(t,e,r){let n=t.variations??[],s=n[0];if(!s)return null;if(!t.enabled||!O(t,e,r,[t.key])||!A(t,r))return s;let i=W(t,r);return n.find(a=>a.key===i)??s}function me(t,e){return k(t,[],e)}function ye(t,e,r){let n=t.find(s=>s.key===e);return n?k(n,t,r)?.value??null:null}function X(t){return t.some(e=>e.targeting.some(r=>r.op==="in_cohort"||r.op==="not_in_cohort"))}function Y(t){return `40${JSON.stringify(t)}`}function Z(){return "3"}function ee(t){let e=t.charAt(0),r=t.slice(1);if(e==="2")return {kind:"ping"};if(e==="1")return {kind:"disconnect"};if(e==="0"){let a=q(r);return {kind:"open",pingInterval:typeof a?.pingInterval=="number"?a.pingInterval:25e3,pingTimeout:typeof a?.pingTimeout=="number"?a.pingTimeout:2e4}}if(e!=="4")return {kind:"other"};let n=r.charAt(0),s=r.slice(1);if(n==="0")return {kind:"connected"};if(n==="1")return {kind:"disconnect"};if(n==="4"){let a=q(s);return {kind:"connectError",message:typeof a?.message=="string"?a.message:"refused"}}if(n!=="2")return {kind:"other"};let i=q(s);return !Array.isArray(i)||typeof i[0]!="string"?{kind:"other"}:{kind:"event",name:i[0],payload:i[1]}}function q(t){try{return JSON.parse(t)}catch{return null}}var ve="/socket.io/?EIO=4&transport=websocket",be=250,C=class{constructor(e){this.options=e;o(this,"socket",null);o(this,"heartbeat",null);o(this,"pending",null);o(this,"lastKey","");o(this,"ready",false);o(this,"closed",false);o(this,"heartbeatWindow",45e3);o(this,"factory");o(this,"setTimer");o(this,"clearTimer");this.factory=e.socketFactory??ke,this.setTimer=e.setTimer??((r,n)=>setTimeout(r,n)),this.clearTimer=e.clearTimer??(r=>clearTimeout(r));}open(){if(this.socket||this.closed)return;let e=`${this.options.host.replace(/^http/,"ws").replace(/\/+$/,"")}${ve}`,r;try{r=this.factory(e);}catch{this.options.onClosed(false);return}this.socket=r,r.onmessage=n=>this.receive(String(n.data)),r.onerror=()=>r.close(),r.onclose=()=>this.fell();}close(){this.closed=true,this.stopHeartbeat(),this.pending!==null&&this.clearTimer(this.pending),this.pending=null;let e=this.socket;this.socket=null,e?.close();}receive(e){let r=ee(e);if(r.kind==="open"){this.armHeartbeat(r.pingInterval+r.pingTimeout),this.socket?.send(Y({projectKey:this.options.projectKey}));return}if(r.kind==="ping"){this.armHeartbeat(),this.socket?.send(Z());return}if(r.kind==="connectError"||r.kind==="disconnect"){this.stopHeartbeat(),this.socket?.close();return}if(r.kind==="event"){if(r.name==="ready"){this.ready=true;return}if(r.name==="flagChange"){let n=r.payload?.key;this.lastKey=typeof n=="string"?n:"",this.pending===null&&(this.pending=this.setTimer(()=>{this.pending=null,this.options.onChange(this.lastKey);},be));}}}fell(){this.stopHeartbeat();let e=this.ready;this.socket=null,this.ready=false,this.closed||this.options.onClosed(e);}armHeartbeat(e){e!==void 0&&(this.heartbeatWindow=e),this.stopHeartbeat(),this.heartbeat=this.setTimer(()=>this.socket?.close(),this.heartbeatWindow);}stopHeartbeat(){this.heartbeat!==null&&this.clearTimer(this.heartbeat),this.heartbeat=null;}};function ke(t){let e=globalThis.WebSocket;if(!e)throw new Error("no WebSocket");return new e(t)}var x=class{constructor(e){o(this,"fetch");o(this,"host");o(this,"projectKey");o(this,"requestTimeoutMs");this.fetch=y(e.fetch),this.host=h(e.host),this.projectKey=e.projectKey,this.requestTimeoutMs=e.requestTimeoutMs??1e4;}async fetchAll(e){return (await this.fetchDecisions(e)).flags}async fetchDecisions(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=d(),i=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);let c=JSON.parse(await a.text());return {flags:c.flags??{},variants:c.variants??{}}}finally{i!==void 0&&clearTimeout(i);}}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=d(),s=n?setTimeout(()=>n.abort(),this.requestTimeoutMs):void 0;try{let i=await e(r,{headers:{authorization:`Bearer ${this.projectKey}`},method:"GET",signal:n?.signal});if(!i.ok)throw new l(`flag snapshot request failed with status ${i.status}`,i.status);let a=JSON.parse(await i.text()),c={flags:a.flags??[],generatedAt:a.generatedAt};return typeof a.socketUrl=="string"&&a.socketUrl!==""&&(c.socketUrl=a.socketUrl),c}finally{s!==void 0&&clearTimeout(s);}}async memberships(e){let r=this.fetch;if(!r)throw new l("no fetch implementation available in this runtime");let n=`${this.host}/v1/flags/memberships?distinct_id=${encodeURIComponent(e)}`,s=d(),i=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(`memberships request failed with status ${a.status}`,a.status);return JSON.parse(await a.text()).cohorts??[]}finally{i!==void 0&&clearTimeout(i);}}};var T=class{constructor(e,r,n){this.storage=e;this.ids=r;this.namespace=n;o(this,"anonymousId");o(this,"distinctId");o(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 i=e.getItem(this.key("distinct_id"));i?(this.distinctId=i,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){o(this,"fetch");o(this,"host");o(this,"projectKey");o(this,"requestTimeoutMs");this.fetch=y(e.fetch),this.host=h(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`,i=await this.request(n,s,{body:JSON.stringify({distinct_id:r,message_id:e}),headers:{...this.authHeaders(),"content-type":"application/json"},method:"POST"});if(!i.ok)throw new l(`mark-read request failed with status ${i.status}`,i.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=d(),i=s?setTimeout(()=>s.abort(),this.requestTimeoutMs):void 0;try{return await e(r,{...n,signal:s?.signal})}finally{i!==void 0&&clearTimeout(i);}}};var w=class{constructor(e,r){this.maxSize=e;this.onOverflow=r;o(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 te(t){return t>=400&&t<500&&t!==429}var F=class{constructor(e={}){o(this,"fetch");o(this,"maxRetries");o(this,"requestTimeoutMs");o(this,"baseDelayMs");o(this,"maxDelayMs");o(this,"sleep");o(this,"random");this.fetch=y(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??K,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 i=0;i<=this.maxRetries;i+=1){try{let a=await this.attempt(r,e,n);if(a.ok)return;if(te(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&&te(a.status))throw a;s=a;}i<this.maxRetries&&await this.sleep(this.backoff(i));}throw new l("ingest delivery failed after retries",void 0,{cause:s})}async attempt(e,r,n){let s=d(),i=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{i!==void 0&&clearTimeout(i);}}backoff(e){return Math.min(this.maxDelayMs,this.baseDelayMs*2**e)+this.random()*this.baseDelayMs}};var xe="queue",Ee=1e3,re=3e4,ne=t=>{let e={};return t.avatar!==void 0&&(e.$avatar=t.avatar),t.email!==void 0&&(e.$email=t.email),t.name!==void 0&&(e.$name=t.name),t.phone!==void 0&&(e.$phone=t.phone),e},_=class{constructor(e){o(this,"config");o(this,"identity");o(this,"queue");o(this,"transport");o(this,"flagsClient");o(this,"messagesClient");o(this,"context");o(this,"flushTimer");o(this,"flushing",false);o(this,"cachedFlags");o(this,"cachedSnapshot");o(this,"membershipCache");o(this,"stream");o(this,"shutDown",false);o(this,"exposures",new Set);this.config=z(e),this.identity=new T(this.config.storage,this.config.ids,this.config.namespace),this.queue=new w(this.config.maxQueueSize,({dropped:r})=>{this.config.onError(new u("queue_overflow",`event queue overflow: dropped ${r.length} oldest event(s)`));}),this.transport=this.config.transport??new F({maxRetries:this.config.maxRetries,requestTimeoutMs:this.config.requestTimeoutMs}),this.flagsClient=new x({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,r={}){try{let n={...this.config.defaultProperties(),...r.properties??{}},s=H({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(),i=this.identity.identify(e),a={};s&&i.changed&&(a.$anon_distinct_id=n);let c={...ne(r.traits??{}),...r.set??{}};Object.keys(c).length>0&&(a.$set=c),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});}setPersonTraits(e){let r=ne(e);Object.keys(r).length!==0&&this.capture("$set",{properties:{$set:r}});}async getAllFlags(){let e=this.identity.getDistinctId(),r=await this.flagsClient.fetchDecisions(e);return this.cachedFlags={distinctId:e,flags:r.flags,variants:r.variants??{}},r.flags}async isFeatureEnabled(e){let n=(await this.getAllFlags())[e]??false;return this.recordExposure(e,this.cachedFlags?.variants[e]?.key??String(n)),n}async getVariant(e){let r=await this.getAllFlags(),n=this.cachedFlags?.variants[e]??null;return this.recordExposure(e,n?.key??String(r[e]??false)),n}async getVariantLocal(e,r={}){let n=await this.flagSnapshot(),s=n.flags.find(se=>se.key===e),i=await this.localContext(r,n.flags),a=s?k(s,n.flags,i):null,c=s?b(s,n.flags,i).enabled:false;return this.recordExposure(e,a?.key??String(c)),a?{key:a.key,value:a.value}:null}recordExposure(e,r){let n=`${this.identity.getDistinctId()} ${e} ${r}`;this.exposures.has(n)||(this.exposures.add(n),this.capture("$feature_flag_called",{properties:{$feature_flag:e,$feature_flag_response:r}}));}getCachedFlag(e){if(!(!this.cachedFlags||this.cachedFlags.distinctId!==this.distinctId))return this.cachedFlags.flags[e]}async getLocalFlags(e={}){let r=await this.flagSnapshot();return M(r.flags,await this.localContext(e,r.flags))}async isFeatureEnabledLocal(e,r={}){let n=await this.flagSnapshot(),s=n.flags.find(c=>c.key===e),i=await this.localContext(r,n.flags),a=s?b(s,n.flags,i).enabled:false;return this.recordExposure(e,(s?k(s,n.flags,i)?.key:void 0)??String(a)),a}async localContext(e,r){let n=this.identity.getDistinctId(),s=e.cohorts;if(s===void 0&&X(r)){let i=this.config.clock.now().getTime();this.membershipCache&&this.membershipCache.distinctId===n&&i-this.membershipCache.fetchedAt<re?s=this.membershipCache.cohorts:(s=await this.flagsClient.memberships(n),this.membershipCache={cohorts:s,distinctId:n,fetchedAt:i});}return {attributes:e.attributes,cohorts:s,distinctId:n,properties:e.properties}}async flagSnapshot(){let e=this.config.clock.now().getTime();if(this.cachedSnapshot&&e-this.cachedSnapshot.fetchedAt<re)return this.cachedSnapshot.snapshot;let r=await this.flagsClient.snapshot();return this.cachedSnapshot={fetchedAt:e,snapshot:r},this.maybeStream(r),r}maybeStream(e){if(!this.config.streamFlags||this.shutDown||this.stream||!e.socketUrl)return;let r=new C({host:e.socketUrl,onChange:()=>{this.cachedSnapshot=void 0,this.flagSnapshot().catch(n=>this.config.onError(n));},onClosed:n=>{this.stream=void 0,n&&this.maybeStream(e);},projectKey:this.config.apiKey,socketFactory:this.config.socketFactory});this.stream=r,r.open();}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(Ee);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,this.membershipCache=void 0;}async shutdown(){this.shutDown=true,this.stopTimer(),this.stream?.close(),this.stream=void 0,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}.${xe}`}};function Fe(t){return new _(t)}exports.ConfigError=m;exports.FetchTransport=F;exports.FlagsClient=x;exports.MemoryStorage=v;exports.MessagesClient=E;exports.ProdantixClient=_;exports.ProdantixError=u;exports.SDK_NAME=P;exports.SDK_VERSION=R;exports.TransportError=l;exports.ValidationError=p;exports.assignVariant=me;exports.bucket=$;exports.createClient=Fe;exports.evaluateAll=M;exports.evaluateFlag=ge;exports.getVariant=ye;exports.matches=N;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -1,7 +1,8 @@
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';
1
+ export { C as CaptureOptions, I as IdentifyOptions, L as LocalFlagContext, P as ProdantixClient, c as createClient } from './client-y1xyVF6C.cjs';
2
+ import { J as JsonValue, F as FlagsResponse, I as InboxMessage, a as StorageAdapter } from './types-68Sc11g8.cjs';
3
+ export { C as Clock, E as EventBatch, b as EventContext, c as EventEnvelope, d as EventProperties, e as FlagVariant, f as IdFactory, g as InboxResponse, P as ProdantixConfig, T as Transport, h as TransportRequest } from './types-68Sc11g8.cjs';
4
+ import { F as FetchLike } from './http-BCh716Vs.cjs';
5
+ export { F as FetchTransport } from './transport-Bj4nXmgt.cjs';
5
6
 
6
7
  type ProdantixErrorCode = 'config' | 'queue_overflow' | 'transport' | 'validation';
7
8
  declare class ProdantixError extends Error {
@@ -20,7 +21,7 @@ declare class TransportError extends ProdantixError {
20
21
  constructor(message: string, status?: number, options?: ErrorOptions);
21
22
  }
22
23
 
23
- type FlagOp = 'eq' | 'neq' | 'in' | 'not_in' | 'contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_set' | 'is_not_set';
24
+ type FlagOp = 'eq' | 'neq' | 'in' | 'not_in' | 'contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'is_set' | 'is_not_set' | 'in_cohort' | 'not_in_cohort';
24
25
  interface FlagCondition {
25
26
  attribute: string;
26
27
  op: FlagOp;
@@ -28,21 +29,36 @@ interface FlagCondition {
28
29
  }
29
30
  interface FlagEvalContext {
30
31
  attributes?: Record<string, JsonValue>;
32
+ cohorts?: string[];
31
33
  distinctId: string;
32
34
  properties?: Record<string, JsonValue>;
33
35
  }
34
36
  declare function matches(condition: FlagCondition, ctx: FlagEvalContext): boolean;
35
37
 
38
+ interface FlagVariation {
39
+ key: string;
40
+ value: unknown;
41
+ weight: number;
42
+ }
43
+ interface FlagPrerequisite {
44
+ flagKey: string;
45
+ variationKey: string;
46
+ }
36
47
  interface FlagRule {
37
48
  description?: string;
38
49
  enabled: boolean;
50
+ intent?: string;
39
51
  key: string;
52
+ prerequisites?: FlagPrerequisite[];
40
53
  rolloutPercentage: number;
41
54
  targeting: FlagCondition[];
55
+ type?: string;
56
+ variations?: FlagVariation[];
42
57
  }
43
58
  interface FlagSnapshot {
44
59
  flags: FlagRule[];
45
60
  generatedAt: string;
61
+ socketUrl?: string;
46
62
  }
47
63
  interface FlagDecision {
48
64
  enabled: boolean;
@@ -51,6 +67,8 @@ interface FlagDecision {
51
67
  declare function bucket(key: string, distinctId: string): number;
52
68
  declare function evaluateFlag(rule: FlagRule, ctx: FlagEvalContext): FlagDecision;
53
69
  declare function evaluateAll(rules: FlagRule[], ctx: FlagEvalContext): Record<string, boolean>;
70
+ declare function assignVariant(rule: FlagRule, ctx: FlagEvalContext): FlagVariation | null;
71
+ declare function getVariant(rules: FlagRule[], key: string, ctx: FlagEvalContext): unknown;
54
72
 
55
73
  interface FlagsClientOptions {
56
74
  fetch?: FetchLike;
@@ -65,7 +83,11 @@ declare class FlagsClient {
65
83
  private readonly requestTimeoutMs;
66
84
  constructor(options: FlagsClientOptions);
67
85
  fetchAll(distinctId: string): Promise<Record<string, boolean>>;
86
+ fetchDecisions(distinctId: string): Promise<FlagsResponse>;
68
87
  snapshot(): Promise<FlagSnapshot>;
88
+ /** The cohorts a distinct id belongs to, for local evaluation of cohort
89
+ * conditions against the same membership store the server reads. */
90
+ memberships(distinctId: string): Promise<string[]>;
69
91
  }
70
92
 
71
93
  interface MessagesClientOptions {
@@ -97,4 +119,4 @@ declare class MemoryStorage implements StorageAdapter {
97
119
  declare const SDK_NAME = "prodantix-js";
98
120
  declare const SDK_VERSION = "0.0.1";
99
121
 
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 };
122
+ export { ConfigError, type FlagCondition, type FlagDecision, type FlagEvalContext, type FlagOp, type FlagRule, type FlagSnapshot, type FlagVariation, FlagsClient, FlagsResponse, InboxMessage, JsonValue, MemoryStorage, MessagesClient, ProdantixError, type ProdantixErrorCode, SDK_NAME, SDK_VERSION, StorageAdapter, TransportError, ValidationError, assignVariant, bucket, evaluateAll, evaluateFlag, getVariant, matches };