@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.
- package/README.md +11 -4
- package/dist/chat.cjs +65 -0
- package/dist/chat.d.cts +64 -0
- package/dist/chat.d.ts +64 -0
- package/dist/chat.js +65 -0
- package/dist/chunk-5XGN7UAV.js +2 -0
- package/dist/chunk-CSIP3PZ7.js +2 -0
- package/dist/chunk-V77KYPOF.js +2 -0
- package/dist/chunk-VG77TYVX.js +2 -0
- package/dist/client-Ca6xJESF.d.ts +105 -0
- package/dist/client-y1xyVF6C.d.cts +105 -0
- package/dist/config-B-cTz9n1.d.ts +94 -0
- package/dist/config-OP9Csae6.d.cts +94 -0
- package/dist/csp.cjs +3 -0
- package/dist/csp.d.cts +37 -0
- package/dist/csp.d.ts +37 -0
- package/dist/csp.js +3 -0
- package/dist/http-BCh716Vs.d.cts +14 -0
- package/dist/http-BCh716Vs.d.ts +14 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +28 -6
- package/dist/index.d.ts +28 -6
- package/dist/index.js +1 -1
- package/dist/messenger.cjs +2 -0
- package/dist/messenger.d.cts +2 -0
- package/dist/messenger.d.ts +2 -0
- package/dist/messenger.iife.js +65 -0
- package/dist/messenger.js +2 -0
- package/dist/node.cjs +1 -1
- package/dist/node.d.cts +2 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.js +1 -1
- package/dist/{transport-By6wsdny.d.ts → transport-Bj4nXmgt.d.cts} +3 -15
- package/dist/{transport-B3PxeUxW.d.cts → transport-CTPih3Jj.d.ts} +3 -15
- package/dist/types-68Sc11g8.d.cts +105 -0
- package/dist/types-68Sc11g8.d.ts +105 -0
- package/dist/web.cjs +1 -1
- package/dist/web.d.cts +4 -2
- package/dist/web.d.ts +4 -2
- package/dist/web.js +1 -1
- package/package.json +19 -3
- package/dist/chunk-FIZWZVZG.js +0 -2
- package/dist/client-B1bcIuD8.d.cts +0 -133
- 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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 };
|