@shipeasy/sdk 6.2.0 → 7.0.0
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 +1 -4
- package/dist/client/index.d.mts +147 -22
- package/dist/client/index.d.ts +147 -22
- package/dist/client/index.js +304 -125
- package/dist/client/index.mjs +303 -125
- package/dist/openfeature-server/index.d.mts +129 -8
- package/dist/openfeature-server/index.d.ts +129 -8
- package/dist/openfeature-server/index.js +66 -1
- package/dist/openfeature-server/index.mjs +66 -1
- package/dist/openfeature-web/index.d.mts +99 -27
- package/dist/openfeature-web/index.d.ts +99 -27
- package/dist/server/index.d.mts +166 -21
- package/dist/server/index.d.ts +166 -21
- package/dist/server/index.js +358 -131
- package/dist/server/index.mjs +357 -131
- package/docs/skill/SKILL.md +29 -25
- package/package.json +9 -6
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/web-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -23,25 +25,6 @@ interface User {
|
|
|
23
25
|
user_id?: string;
|
|
24
26
|
[attr: string]: unknown;
|
|
25
27
|
}
|
|
26
|
-
interface ExperimentResult<P> {
|
|
27
|
-
inExperiment: boolean;
|
|
28
|
-
group: string;
|
|
29
|
-
params: P;
|
|
30
|
-
}
|
|
31
|
-
/** Options object form of `getExperiment` — the legacy `decode`/`variants`
|
|
32
|
-
* positional args plus per-call exposure control. */
|
|
33
|
-
interface GetExperimentOptions<P> {
|
|
34
|
-
/** Decode the raw stored params into the typed shape callers want. */
|
|
35
|
-
decode?: (raw: unknown) => P;
|
|
36
|
-
/** Variant-specific param overrides merged on top of group params. */
|
|
37
|
-
variants?: Record<string, Partial<P>>;
|
|
38
|
-
/**
|
|
39
|
-
* Override automatic exposure logging for this read. Defaults to the client's
|
|
40
|
-
* setting (`disableAutoExposure` flips it). `false` reads the variant without
|
|
41
|
-
* logging an exposure — pair with `logExposure(name)` at render time.
|
|
42
|
-
*/
|
|
43
|
-
logExposure?: boolean;
|
|
44
|
-
}
|
|
45
28
|
/**
|
|
46
29
|
* Why a flag evaluated the way it did (LaunchDarkly variationDetail parity).
|
|
47
30
|
* Computed at the client boundary:
|
|
@@ -73,11 +56,19 @@ interface EvalExpResult {
|
|
|
73
56
|
inExperiment: boolean;
|
|
74
57
|
group: string;
|
|
75
58
|
params: Record<string, unknown>;
|
|
59
|
+
/** The universe this experiment belongs to — lets `universe(name).assign()`
|
|
60
|
+
* find the enrolled experiment within a universe. */
|
|
61
|
+
universe?: string;
|
|
76
62
|
}
|
|
77
63
|
interface EvalResponse {
|
|
78
64
|
flags: Record<string, boolean>;
|
|
79
65
|
configs: Record<string, unknown>;
|
|
80
66
|
experiments: Record<string, EvalExpResult>;
|
|
67
|
+
/** Per-universe param defaults (name → default map) so `universe(name).get()`
|
|
68
|
+
* resolves to the universe default even when the unit is not enrolled. */
|
|
69
|
+
universes?: Record<string, {
|
|
70
|
+
defaults: Record<string, unknown>;
|
|
71
|
+
}>;
|
|
81
72
|
/**
|
|
82
73
|
* Killswitch state, flattened by the server. A boolean means the killswitch
|
|
83
74
|
* is whole-killed; an object means it's not whole-killed and carries per-
|
|
@@ -91,6 +82,23 @@ interface EvalResponse {
|
|
|
91
82
|
*/
|
|
92
83
|
sticky?: Record<string, StickyCookieEntry>;
|
|
93
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* The result of `universe(name).assign()` — the visitor's standing in a universe.
|
|
87
|
+
* A universe is a mutual-exclusion pool, so the visitor lands in **at most one**
|
|
88
|
+
* experiment. Never throws: an un-enrolled visitor still resolves `get()` to the
|
|
89
|
+
* universe defaults (or your fallback). `assign()` auto-logs one exposure when
|
|
90
|
+
* enrolled (subject to `disableAutoExposure`).
|
|
91
|
+
*/
|
|
92
|
+
interface Assignment {
|
|
93
|
+
/** The experiment the visitor landed in, or `null` when not enrolled. */
|
|
94
|
+
readonly name: string | null;
|
|
95
|
+
/** The assigned variant/group name, or `null` when not enrolled. */
|
|
96
|
+
readonly group: string | null;
|
|
97
|
+
/** True iff the visitor is enrolled in an experiment in this universe. */
|
|
98
|
+
readonly enrolled: boolean;
|
|
99
|
+
/** Read a resolved param: variant override ?? universe default ?? `fallback`. */
|
|
100
|
+
get<T = unknown>(field: string, fallback?: T): T | undefined;
|
|
101
|
+
}
|
|
94
102
|
/** One persisted sticky assignment: group + 8-char salt prefix (reshuffle key). */
|
|
95
103
|
interface StickyCookieEntry {
|
|
96
104
|
g: string;
|
|
@@ -102,6 +110,33 @@ interface AutoCollectGroups {
|
|
|
102
110
|
engagement: boolean;
|
|
103
111
|
}
|
|
104
112
|
type EngineEnv = "dev" | "staging" | "prod";
|
|
113
|
+
/**
|
|
114
|
+
* A pluggable persistence backend for the anonymous id. Primarily for non-DOM
|
|
115
|
+
* runtimes (React Native / Expo) where there is no cookie or `localStorage`, so
|
|
116
|
+
* the anon id would otherwise regenerate every app launch and re-bucket the
|
|
117
|
+
* visitor. Point it at `@react-native-async-storage/async-storage` (or any
|
|
118
|
+
* store) and the SDK hydrates a stable id before the first `/sdk/evaluate`:
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
122
|
+
* configure({
|
|
123
|
+
* clientKey: "...",
|
|
124
|
+
* anonymousStore: {
|
|
125
|
+
* get: (k) => AsyncStorage.getItem(k),
|
|
126
|
+
* set: (k, v) => AsyncStorage.setItem(k, v),
|
|
127
|
+
* remove: (k) => AsyncStorage.removeItem(k),
|
|
128
|
+
* },
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* Methods may be sync or async — the SDK awaits either. Any thrown error is
|
|
133
|
+
* swallowed (the in-memory id is used as a fallback).
|
|
134
|
+
*/
|
|
135
|
+
interface AnonymousStore {
|
|
136
|
+
get(key: string): string | null | Promise<string | null>;
|
|
137
|
+
set(key: string, value: string): void | Promise<void>;
|
|
138
|
+
remove(key: string): void | Promise<void>;
|
|
139
|
+
}
|
|
105
140
|
interface EngineOptions {
|
|
106
141
|
sdkKey: string;
|
|
107
142
|
baseUrl?: string;
|
|
@@ -131,6 +166,22 @@ interface EngineOptions {
|
|
|
131
166
|
disableTelemetry?: boolean;
|
|
132
167
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
133
168
|
telemetryUrl?: string;
|
|
169
|
+
/**
|
|
170
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
171
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
172
|
+
* track/logExposure/see) fails silently — returning a safe default instead of
|
|
173
|
+
* throwing — and surfaces the swallowed error through this level. Ordering:
|
|
174
|
+
* `silent` < `error` < `warn` < `info` < `debug`. Defaults to `"warn"`.
|
|
175
|
+
*/
|
|
176
|
+
logLevel?: LogLevel;
|
|
177
|
+
/**
|
|
178
|
+
* Opt out of SDK-internal error self-monitoring. When one of the SDK's own
|
|
179
|
+
* last-resort guards catches an internal failure (an "on our end" bug), the
|
|
180
|
+
* SDK reports it to Shipeasy's own project so we can track SDK bugs across
|
|
181
|
+
* apps — never to your project. ON by default; forced off in test mode. Pass
|
|
182
|
+
* `true` to disable.
|
|
183
|
+
*/
|
|
184
|
+
disableInternalErrorReporting?: boolean;
|
|
134
185
|
/**
|
|
135
186
|
* Suppress automatic exposure logging in `getExperiment` (Statsig's
|
|
136
187
|
* `disableExposureLogging`). Default false — reading an enrolled variant
|
|
@@ -154,6 +205,14 @@ interface EngineOptions {
|
|
|
154
205
|
* lever. Pass `false` to opt out (pure deterministic eval).
|
|
155
206
|
*/
|
|
156
207
|
stickyBucketing?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Pluggable persistence for the anonymous id (React Native / Expo, or any
|
|
210
|
+
* runtime without a cookie / `localStorage`). When set, the SDK hydrates the
|
|
211
|
+
* stored id before the first `/sdk/evaluate` so bucketing stays stable across
|
|
212
|
+
* app launches; on a fresh device it persists the freshly-minted id. See
|
|
213
|
+
* {@link AnonymousStore}.
|
|
214
|
+
*/
|
|
215
|
+
anonymousStore?: AnonymousStore;
|
|
157
216
|
/**
|
|
158
217
|
* Test mode — no network at all. identify()/init are no-ops (never call
|
|
159
218
|
* /sdk/evaluate), track() is a no-op, telemetry is forced off, and the client
|
|
@@ -174,6 +233,7 @@ declare class Engine {
|
|
|
174
233
|
private readonly env;
|
|
175
234
|
private evalResult;
|
|
176
235
|
private anonId;
|
|
236
|
+
private anonReady;
|
|
177
237
|
private userId;
|
|
178
238
|
private buffer;
|
|
179
239
|
private telemetry;
|
|
@@ -188,6 +248,13 @@ declare class Engine {
|
|
|
188
248
|
private readonly experimentOverrides;
|
|
189
249
|
private onOverrideChange;
|
|
190
250
|
constructor(opts: EngineOptions);
|
|
251
|
+
/**
|
|
252
|
+
* Consult the caller-supplied {@link AnonymousStore}: adopt a persisted id so
|
|
253
|
+
* the visitor buckets identically across app launches, or persist the id just
|
|
254
|
+
* minted by getOrCreateAnonId() on a fresh device. Best-effort — any store
|
|
255
|
+
* failure leaves the in-memory id in place.
|
|
256
|
+
*/
|
|
257
|
+
private hydrateAnonFromStore;
|
|
191
258
|
/**
|
|
192
259
|
* Build a no-network, immediately-usable browser client for tests
|
|
193
260
|
* (Statsig-style). identify() is a no-op (never calls /sdk/evaluate), track()
|
|
@@ -241,16 +308,21 @@ declare class Engine {
|
|
|
241
308
|
getFlag(name: string, defaultValue?: boolean): boolean;
|
|
242
309
|
getConfig<T = unknown>(name: string, decode?: (raw: unknown) => T): T | undefined;
|
|
243
310
|
getConfig<T = unknown>(name: string, opts: GetConfigOptions<T>): T;
|
|
244
|
-
getExperiment<P extends Record<string, unknown>>(name: string, defaultParams: P, decode?: (raw: unknown) => P, variants?: Record<string, Partial<P>>): ExperimentResult<P>;
|
|
245
|
-
getExperiment<P extends Record<string, unknown>>(name: string, defaultParams: P, opts: GetExperimentOptions<P>): ExperimentResult<P>;
|
|
246
311
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* the
|
|
250
|
-
*
|
|
251
|
-
* `
|
|
312
|
+
* Assign the visitor within a universe: `universe("checkout").assign()`. A
|
|
313
|
+
* universe is a mutual-exclusion pool, so the visitor lands in ≤1 experiment;
|
|
314
|
+
* the returned {@link Assignment} exposes `.group` / `.get(field, fallback)`
|
|
315
|
+
* and auto-logs one exposure when enrolled (unless `disableAutoExposure` or
|
|
316
|
+
* `assign({ logExposure: false })`). An un-enrolled visitor still resolves
|
|
317
|
+
* `get()` to the universe defaults. This is the sole experiment read path —
|
|
318
|
+
* there is no `getExperiment` (ask a universe, not an experiment).
|
|
252
319
|
*/
|
|
253
|
-
|
|
320
|
+
universe(name: string): {
|
|
321
|
+
assign(opts?: {
|
|
322
|
+
logExposure?: boolean;
|
|
323
|
+
}): Assignment;
|
|
324
|
+
};
|
|
325
|
+
private assignUniverse;
|
|
254
326
|
/**
|
|
255
327
|
* Subscribe to state changes — fires after identify() completes and on
|
|
256
328
|
* `se:override:change` events from the devtools overlay. Returns an
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Provider, EvaluationContext, Logger, ResolutionDetails, JsonValue } from '@openfeature/web-sdk';
|
|
2
2
|
|
|
3
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
4
|
+
|
|
3
5
|
type SeeExtras = Record<string, string | number | boolean | null | undefined>;
|
|
4
6
|
type SeeKind = "caught" | "uncaught" | "unhandled_rejection" | "network" | "violation";
|
|
5
7
|
/** Built by `causesThe(subject).to(outcome)` — never constructed by hand. */
|
|
@@ -23,25 +25,6 @@ interface User {
|
|
|
23
25
|
user_id?: string;
|
|
24
26
|
[attr: string]: unknown;
|
|
25
27
|
}
|
|
26
|
-
interface ExperimentResult<P> {
|
|
27
|
-
inExperiment: boolean;
|
|
28
|
-
group: string;
|
|
29
|
-
params: P;
|
|
30
|
-
}
|
|
31
|
-
/** Options object form of `getExperiment` — the legacy `decode`/`variants`
|
|
32
|
-
* positional args plus per-call exposure control. */
|
|
33
|
-
interface GetExperimentOptions<P> {
|
|
34
|
-
/** Decode the raw stored params into the typed shape callers want. */
|
|
35
|
-
decode?: (raw: unknown) => P;
|
|
36
|
-
/** Variant-specific param overrides merged on top of group params. */
|
|
37
|
-
variants?: Record<string, Partial<P>>;
|
|
38
|
-
/**
|
|
39
|
-
* Override automatic exposure logging for this read. Defaults to the client's
|
|
40
|
-
* setting (`disableAutoExposure` flips it). `false` reads the variant without
|
|
41
|
-
* logging an exposure — pair with `logExposure(name)` at render time.
|
|
42
|
-
*/
|
|
43
|
-
logExposure?: boolean;
|
|
44
|
-
}
|
|
45
28
|
/**
|
|
46
29
|
* Why a flag evaluated the way it did (LaunchDarkly variationDetail parity).
|
|
47
30
|
* Computed at the client boundary:
|
|
@@ -73,11 +56,19 @@ interface EvalExpResult {
|
|
|
73
56
|
inExperiment: boolean;
|
|
74
57
|
group: string;
|
|
75
58
|
params: Record<string, unknown>;
|
|
59
|
+
/** The universe this experiment belongs to — lets `universe(name).assign()`
|
|
60
|
+
* find the enrolled experiment within a universe. */
|
|
61
|
+
universe?: string;
|
|
76
62
|
}
|
|
77
63
|
interface EvalResponse {
|
|
78
64
|
flags: Record<string, boolean>;
|
|
79
65
|
configs: Record<string, unknown>;
|
|
80
66
|
experiments: Record<string, EvalExpResult>;
|
|
67
|
+
/** Per-universe param defaults (name → default map) so `universe(name).get()`
|
|
68
|
+
* resolves to the universe default even when the unit is not enrolled. */
|
|
69
|
+
universes?: Record<string, {
|
|
70
|
+
defaults: Record<string, unknown>;
|
|
71
|
+
}>;
|
|
81
72
|
/**
|
|
82
73
|
* Killswitch state, flattened by the server. A boolean means the killswitch
|
|
83
74
|
* is whole-killed; an object means it's not whole-killed and carries per-
|
|
@@ -91,6 +82,23 @@ interface EvalResponse {
|
|
|
91
82
|
*/
|
|
92
83
|
sticky?: Record<string, StickyCookieEntry>;
|
|
93
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* The result of `universe(name).assign()` — the visitor's standing in a universe.
|
|
87
|
+
* A universe is a mutual-exclusion pool, so the visitor lands in **at most one**
|
|
88
|
+
* experiment. Never throws: an un-enrolled visitor still resolves `get()` to the
|
|
89
|
+
* universe defaults (or your fallback). `assign()` auto-logs one exposure when
|
|
90
|
+
* enrolled (subject to `disableAutoExposure`).
|
|
91
|
+
*/
|
|
92
|
+
interface Assignment {
|
|
93
|
+
/** The experiment the visitor landed in, or `null` when not enrolled. */
|
|
94
|
+
readonly name: string | null;
|
|
95
|
+
/** The assigned variant/group name, or `null` when not enrolled. */
|
|
96
|
+
readonly group: string | null;
|
|
97
|
+
/** True iff the visitor is enrolled in an experiment in this universe. */
|
|
98
|
+
readonly enrolled: boolean;
|
|
99
|
+
/** Read a resolved param: variant override ?? universe default ?? `fallback`. */
|
|
100
|
+
get<T = unknown>(field: string, fallback?: T): T | undefined;
|
|
101
|
+
}
|
|
94
102
|
/** One persisted sticky assignment: group + 8-char salt prefix (reshuffle key). */
|
|
95
103
|
interface StickyCookieEntry {
|
|
96
104
|
g: string;
|
|
@@ -102,6 +110,33 @@ interface AutoCollectGroups {
|
|
|
102
110
|
engagement: boolean;
|
|
103
111
|
}
|
|
104
112
|
type EngineEnv = "dev" | "staging" | "prod";
|
|
113
|
+
/**
|
|
114
|
+
* A pluggable persistence backend for the anonymous id. Primarily for non-DOM
|
|
115
|
+
* runtimes (React Native / Expo) where there is no cookie or `localStorage`, so
|
|
116
|
+
* the anon id would otherwise regenerate every app launch and re-bucket the
|
|
117
|
+
* visitor. Point it at `@react-native-async-storage/async-storage` (or any
|
|
118
|
+
* store) and the SDK hydrates a stable id before the first `/sdk/evaluate`:
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
122
|
+
* configure({
|
|
123
|
+
* clientKey: "...",
|
|
124
|
+
* anonymousStore: {
|
|
125
|
+
* get: (k) => AsyncStorage.getItem(k),
|
|
126
|
+
* set: (k, v) => AsyncStorage.setItem(k, v),
|
|
127
|
+
* remove: (k) => AsyncStorage.removeItem(k),
|
|
128
|
+
* },
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* Methods may be sync or async — the SDK awaits either. Any thrown error is
|
|
133
|
+
* swallowed (the in-memory id is used as a fallback).
|
|
134
|
+
*/
|
|
135
|
+
interface AnonymousStore {
|
|
136
|
+
get(key: string): string | null | Promise<string | null>;
|
|
137
|
+
set(key: string, value: string): void | Promise<void>;
|
|
138
|
+
remove(key: string): void | Promise<void>;
|
|
139
|
+
}
|
|
105
140
|
interface EngineOptions {
|
|
106
141
|
sdkKey: string;
|
|
107
142
|
baseUrl?: string;
|
|
@@ -131,6 +166,22 @@ interface EngineOptions {
|
|
|
131
166
|
disableTelemetry?: boolean;
|
|
132
167
|
/** Override the telemetry beacon host. Defaults to {@link DEFAULT_TELEMETRY_URL}. */
|
|
133
168
|
telemetryUrl?: string;
|
|
169
|
+
/**
|
|
170
|
+
* How chatty the SDK is on `console` when it catches an error internally.
|
|
171
|
+
* Every public runtime method (getFlag/getConfig/getExperiment/getKillswitch/
|
|
172
|
+
* track/logExposure/see) fails silently — returning a safe default instead of
|
|
173
|
+
* throwing — and surfaces the swallowed error through this level. Ordering:
|
|
174
|
+
* `silent` < `error` < `warn` < `info` < `debug`. Defaults to `"warn"`.
|
|
175
|
+
*/
|
|
176
|
+
logLevel?: LogLevel;
|
|
177
|
+
/**
|
|
178
|
+
* Opt out of SDK-internal error self-monitoring. When one of the SDK's own
|
|
179
|
+
* last-resort guards catches an internal failure (an "on our end" bug), the
|
|
180
|
+
* SDK reports it to Shipeasy's own project so we can track SDK bugs across
|
|
181
|
+
* apps — never to your project. ON by default; forced off in test mode. Pass
|
|
182
|
+
* `true` to disable.
|
|
183
|
+
*/
|
|
184
|
+
disableInternalErrorReporting?: boolean;
|
|
134
185
|
/**
|
|
135
186
|
* Suppress automatic exposure logging in `getExperiment` (Statsig's
|
|
136
187
|
* `disableExposureLogging`). Default false — reading an enrolled variant
|
|
@@ -154,6 +205,14 @@ interface EngineOptions {
|
|
|
154
205
|
* lever. Pass `false` to opt out (pure deterministic eval).
|
|
155
206
|
*/
|
|
156
207
|
stickyBucketing?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Pluggable persistence for the anonymous id (React Native / Expo, or any
|
|
210
|
+
* runtime without a cookie / `localStorage`). When set, the SDK hydrates the
|
|
211
|
+
* stored id before the first `/sdk/evaluate` so bucketing stays stable across
|
|
212
|
+
* app launches; on a fresh device it persists the freshly-minted id. See
|
|
213
|
+
* {@link AnonymousStore}.
|
|
214
|
+
*/
|
|
215
|
+
anonymousStore?: AnonymousStore;
|
|
157
216
|
/**
|
|
158
217
|
* Test mode — no network at all. identify()/init are no-ops (never call
|
|
159
218
|
* /sdk/evaluate), track() is a no-op, telemetry is forced off, and the client
|
|
@@ -174,6 +233,7 @@ declare class Engine {
|
|
|
174
233
|
private readonly env;
|
|
175
234
|
private evalResult;
|
|
176
235
|
private anonId;
|
|
236
|
+
private anonReady;
|
|
177
237
|
private userId;
|
|
178
238
|
private buffer;
|
|
179
239
|
private telemetry;
|
|
@@ -188,6 +248,13 @@ declare class Engine {
|
|
|
188
248
|
private readonly experimentOverrides;
|
|
189
249
|
private onOverrideChange;
|
|
190
250
|
constructor(opts: EngineOptions);
|
|
251
|
+
/**
|
|
252
|
+
* Consult the caller-supplied {@link AnonymousStore}: adopt a persisted id so
|
|
253
|
+
* the visitor buckets identically across app launches, or persist the id just
|
|
254
|
+
* minted by getOrCreateAnonId() on a fresh device. Best-effort — any store
|
|
255
|
+
* failure leaves the in-memory id in place.
|
|
256
|
+
*/
|
|
257
|
+
private hydrateAnonFromStore;
|
|
191
258
|
/**
|
|
192
259
|
* Build a no-network, immediately-usable browser client for tests
|
|
193
260
|
* (Statsig-style). identify() is a no-op (never calls /sdk/evaluate), track()
|
|
@@ -241,16 +308,21 @@ declare class Engine {
|
|
|
241
308
|
getFlag(name: string, defaultValue?: boolean): boolean;
|
|
242
309
|
getConfig<T = unknown>(name: string, decode?: (raw: unknown) => T): T | undefined;
|
|
243
310
|
getConfig<T = unknown>(name: string, opts: GetConfigOptions<T>): T;
|
|
244
|
-
getExperiment<P extends Record<string, unknown>>(name: string, defaultParams: P, decode?: (raw: unknown) => P, variants?: Record<string, Partial<P>>): ExperimentResult<P>;
|
|
245
|
-
getExperiment<P extends Record<string, unknown>>(name: string, defaultParams: P, opts: GetExperimentOptions<P>): ExperimentResult<P>;
|
|
246
311
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* the
|
|
250
|
-
*
|
|
251
|
-
* `
|
|
312
|
+
* Assign the visitor within a universe: `universe("checkout").assign()`. A
|
|
313
|
+
* universe is a mutual-exclusion pool, so the visitor lands in ≤1 experiment;
|
|
314
|
+
* the returned {@link Assignment} exposes `.group` / `.get(field, fallback)`
|
|
315
|
+
* and auto-logs one exposure when enrolled (unless `disableAutoExposure` or
|
|
316
|
+
* `assign({ logExposure: false })`). An un-enrolled visitor still resolves
|
|
317
|
+
* `get()` to the universe defaults. This is the sole experiment read path —
|
|
318
|
+
* there is no `getExperiment` (ask a universe, not an experiment).
|
|
252
319
|
*/
|
|
253
|
-
|
|
320
|
+
universe(name: string): {
|
|
321
|
+
assign(opts?: {
|
|
322
|
+
logExposure?: boolean;
|
|
323
|
+
}): Assignment;
|
|
324
|
+
};
|
|
325
|
+
private assignUniverse;
|
|
254
326
|
/**
|
|
255
327
|
* Subscribe to state changes — fires after identify() completes and on
|
|
256
328
|
* `se:override:change` events from the devtools overlay. Returns an
|