@guidelytech/flags 0.0.0-stage → 0.7.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/LICENSE +21 -0
- package/README.md +134 -2
- package/dist/chunk-OY4QS3WL.js +804 -0
- package/dist/chunk-OY4QS3WL.js.map +1 -0
- package/dist/chunk-ZTY7K7P2.js +988 -0
- package/dist/chunk-ZTY7K7P2.js.map +1 -0
- package/dist/cli.cjs +1920 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +229 -0
- package/dist/cli.js.map +1 -0
- package/dist/evaluate.cjs +835 -0
- package/dist/evaluate.cjs.map +1 -0
- package/dist/evaluate.d.cts +283 -0
- package/dist/evaluate.d.ts +283 -0
- package/dist/evaluate.js +57 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/index.cjs +1884 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +314 -0
- package/dist/index.d.ts +314 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -3
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { JsonValue, EvaluationResult, Attributes, FlagsPayload, RemoteEvaluationResponse, EncryptedFlagsPayload, StickyBucketStore, ExperimentAssignment, StickyAssignments } from './evaluate.cjs';
|
|
2
|
+
export { ARRAY_OPERATORS, ATTRIBUTE_OPERATORS, AttributeCondition, AttributeOperator, BOOLEAN_OPERATORS, Condition, ConditionSegment, DATE_OPERATORS, EvaluateOptions, EvaluationReason, ExperimentNamespace, ExperimentRule, ExperimentVariation, FlagComparisonOperator, FlagCondition, FlagDefinition, FlagEventsBatch, FlagRule, FlagRuleType, FlagValueType, ForceRule, GroupCondition, HASHED_OPERATORS, HoldoutDefinition, ListSegment, NUMBER_OPERATORS, PRESENCE_OPERATORS, Prerequisite, RampStep, RolloutRule, RuleSchedule, SEMVER_OPERATORS, SegmentCondition, SegmentDefinition, SplitBucket, SplitRule, TEXT_OPERATORS, compareSemver, effectiveCoverage, evaluateAllFlags, evaluateFlag, fnv1a32, hashBucket, hashConfidential, hashConfidentialAffix, instantOf, isOn, isScheduleActive, jsonEquals, lookupAttribute, numberOf, parseSemver, sha256Hex, textOf } from './evaluate.cjs';
|
|
3
|
+
|
|
4
|
+
/** The value type a getter returns for a fallback: literals widen (`"blue"` → `string`), JSON types stay. */
|
|
5
|
+
type FlagValue<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
|
|
6
|
+
/** An evaluation result whose `value` is the caller's fallback when the flag is missing, null or of another type. */
|
|
7
|
+
interface FlagDetails<T = JsonValue> extends Omit<EvaluationResult, "value"> {
|
|
8
|
+
value: T;
|
|
9
|
+
/** The fallback was served (flag missing, value null or of the wrong type). */
|
|
10
|
+
usedFallback: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Synchronous flag getters. They never throw: problems give the fallback. */
|
|
13
|
+
interface FlagsEvaluator {
|
|
14
|
+
/** Boolean flag value; `fallback` (default `false`) when missing or not a boolean. */
|
|
15
|
+
isEnabled(key: string, fallback?: boolean): boolean;
|
|
16
|
+
/** Flag value; `fallback` when missing, null or of a different JSON type than `fallback`. */
|
|
17
|
+
getValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
18
|
+
getString(key: string, fallback: string): string;
|
|
19
|
+
getNumber(key: string, fallback: number): number;
|
|
20
|
+
getBoolean(key: string, fallback: boolean): boolean;
|
|
21
|
+
/** Object or array value. */
|
|
22
|
+
getJson<T = JsonValue>(key: string, fallback: T): T;
|
|
23
|
+
/** Value plus why it was served (reason, rule, variation, experiment). */
|
|
24
|
+
getDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
25
|
+
/** Every flag's value for these attributes (no exposures or usage are recorded). */
|
|
26
|
+
getAll(): Record<string, JsonValue>;
|
|
27
|
+
/** The attributes these getters evaluate with. */
|
|
28
|
+
getAttributes(): Attributes;
|
|
29
|
+
}
|
|
30
|
+
/** What framework bindings read from: an evaluator that can say whether it has loaded and notify changes. */
|
|
31
|
+
interface FlagsReader extends FlagsEvaluator {
|
|
32
|
+
isReady(): boolean;
|
|
33
|
+
/** Calls `listener` whenever values may have changed. Returns an unsubscribe function. */
|
|
34
|
+
subscribe(listener: () => void): () => void;
|
|
35
|
+
}
|
|
36
|
+
interface StaticFlagsInput {
|
|
37
|
+
/** A payload (or remote-evaluation results) from `client.getPayload()` on the server. */
|
|
38
|
+
payload?: FlagsPayload | RemoteEvaluationResponse | unknown;
|
|
39
|
+
attributes?: Attributes;
|
|
40
|
+
now?: Date | number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A network-free, read-only snapshot over a bootstrap payload. Framework bindings render with it
|
|
44
|
+
* on the server and during hydration so the HTML matches; it records no exposures or usage.
|
|
45
|
+
* Encrypted payloads cannot be read synchronously and give fallbacks.
|
|
46
|
+
*/
|
|
47
|
+
declare function createStaticFlags(input?: StaticFlagsInput): FlagsReader;
|
|
48
|
+
|
|
49
|
+
declare const FLAGS_SDK_NAME = "@guidelytech/flags";
|
|
50
|
+
declare const FLAGS_SDK_VERSION = "0.7.0";
|
|
51
|
+
declare const DEFAULT_FLAGS_API_URL = "https://guidelytech.com";
|
|
52
|
+
/**
|
|
53
|
+
* - `auto` — fetch at start, then every `pollIntervalSeconds`.
|
|
54
|
+
* - `lazy` — fetch when a flag is read and the cache is older than `cacheTtlSeconds` (serverless, edge).
|
|
55
|
+
* - `manual` — only `refresh()` fetches.
|
|
56
|
+
* - `stream` — server-sent events push changes; polls while the stream is down.
|
|
57
|
+
*/
|
|
58
|
+
type PollingMode = "auto" | "lazy" | "manual" | "stream";
|
|
59
|
+
/** `localOnly`: never fetch, serve overrides only. `localOverRemote`: overrides win. `remoteOverLocal`: overrides fill in flags missing remotely. */
|
|
60
|
+
type OverrideBehaviour = "localOnly" | "localOverRemote" | "remoteOverLocal";
|
|
61
|
+
/** Key/value storage for the last payload: `localStorage`-like or AsyncStorage-like (sync or async). */
|
|
62
|
+
interface FlagsStorage {
|
|
63
|
+
getItem(key: string): string | null | undefined | Promise<string | null | undefined>;
|
|
64
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
65
|
+
removeItem?(key: string): void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
interface FlagsLogger {
|
|
68
|
+
debug?(...args: unknown[]): void;
|
|
69
|
+
warn?(...args: unknown[]): void;
|
|
70
|
+
error?(...args: unknown[]): void;
|
|
71
|
+
}
|
|
72
|
+
/** What a bootstrap / `getPayload()` can hold. */
|
|
73
|
+
type FlagsBootstrap = FlagsPayload | EncryptedFlagsPayload | RemoteEvaluationResponse;
|
|
74
|
+
interface FlagsClientOptions {
|
|
75
|
+
/** Environment public key `pk_…` (the `projectId` used for tracking) or, on servers only, a secret `gly_sk_…` key. */
|
|
76
|
+
sdkKey?: string;
|
|
77
|
+
/** Alias of `sdkKey`. */
|
|
78
|
+
projectId?: string;
|
|
79
|
+
/** Base URL of your Guidely deployment (default `https://guidelytech.com`). */
|
|
80
|
+
apiUrl?: string;
|
|
81
|
+
/** `development` | `staging` | `production`. Required with a `gly_sk_` key. */
|
|
82
|
+
environment?: string;
|
|
83
|
+
/** Default attributes, merged under per-call (`forUser`) attributes. */
|
|
84
|
+
attributes?: Attributes;
|
|
85
|
+
/**
|
|
86
|
+
* Attributes supplied by a Guidely SDK integration (identity, page, device). App attributes
|
|
87
|
+
* (`attributes`, `setAttributes`) are merged over them.
|
|
88
|
+
*/
|
|
89
|
+
contextAttributes?: Attributes;
|
|
90
|
+
pollingMode?: PollingMode;
|
|
91
|
+
/** `auto` / `stream` fallback polling interval (default 60). */
|
|
92
|
+
pollIntervalSeconds?: number;
|
|
93
|
+
/** `lazy` cache lifetime (default 60). */
|
|
94
|
+
cacheTtlSeconds?: number;
|
|
95
|
+
/** Bootstrap: a payload (plain or encrypted) or remote-evaluation results, used immediately. */
|
|
96
|
+
payload?: FlagsBootstrap | null;
|
|
97
|
+
/** Bootstrap for remote evaluation: `{ version, flags }` or a map of results. */
|
|
98
|
+
remoteResults?: RemoteEvaluationResponse | Record<string, EvaluationResult> | null;
|
|
99
|
+
/** Base64 AES-256 key for environments that encrypt their payload. */
|
|
100
|
+
decryptionKey?: string;
|
|
101
|
+
/** Ask the server to evaluate (`POST /flags/evaluate`) instead of downloading rules. Needed when the environment hides rules. */
|
|
102
|
+
remoteEval?: boolean;
|
|
103
|
+
/** Debounce for re-evaluating remotely after attribute changes (default 50 ms). */
|
|
104
|
+
remoteEvalDebounceMs?: number;
|
|
105
|
+
/** Local flag values (tests, QA, kill switches) applied per `overrideBehaviour`. */
|
|
106
|
+
overrides?: Record<string, JsonValue> | null;
|
|
107
|
+
overrideBehaviour?: OverrideBehaviour;
|
|
108
|
+
/** Keeps experiment assignments stable (`InMemoryStickyBucketStore`, `LocalStorageStickyBucketStore`). */
|
|
109
|
+
stickyBucketService?: StickyBucketStore;
|
|
110
|
+
/** Persists the last payload. Default: `localStorage` in browsers, none elsewhere. `false` disables. */
|
|
111
|
+
storage?: FlagsStorage | null | false;
|
|
112
|
+
/** Browser only: read `?guidely_flags=key:value,key2:"text"` from the URL as overrides (QA). */
|
|
113
|
+
enableUrlOverrides?: boolean;
|
|
114
|
+
/** Called once per (experiment, user, variation) when a user is bucketed into an experiment. */
|
|
115
|
+
trackingCallback?: (experiment: ExperimentAssignment, result: EvaluationResult) => void;
|
|
116
|
+
/** Send experiment exposures to Guidely (`POST /flags/events`). Default: `true` unless `trackingCallback` is set. */
|
|
117
|
+
trackExposures?: boolean;
|
|
118
|
+
/** Send aggregated evaluation counts to Guidely at most every 60 s (default `true`). */
|
|
119
|
+
reportUsage?: boolean;
|
|
120
|
+
onReady?: () => void;
|
|
121
|
+
/** New payload (or remote results) applied. */
|
|
122
|
+
onChange?: (data: FlagsPayload | RemoteEvaluationResponse) => void;
|
|
123
|
+
onFlagEvaluated?: (result: EvaluationResult) => void;
|
|
124
|
+
onError?: (error: Error) => void;
|
|
125
|
+
/** Start without network activity (cached / bootstrapped data keeps serving). */
|
|
126
|
+
offline?: boolean;
|
|
127
|
+
fetch?: typeof fetch;
|
|
128
|
+
/**
|
|
129
|
+
* Defaults to `console`: `error` for failed requests (once per streak), `warn` for misuse and,
|
|
130
|
+
* in development, reads of flags that do not exist. `null` silences the client.
|
|
131
|
+
*/
|
|
132
|
+
logger?: FlagsLogger | null;
|
|
133
|
+
/** Evaluation clock (tests). */
|
|
134
|
+
now?: () => Date | number;
|
|
135
|
+
/** Reported with usage (set by Guidely SDK integrations). */
|
|
136
|
+
sdk?: {
|
|
137
|
+
name: string;
|
|
138
|
+
version: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Feature flags for one environment. Create with {@link createFlagsClient}; one per app (browser)
|
|
143
|
+
* or per process (server — use {@link FlagsClient.forUser} per request).
|
|
144
|
+
*/
|
|
145
|
+
declare class FlagsClient implements FlagsReader {
|
|
146
|
+
readonly sdkKey: string;
|
|
147
|
+
readonly apiUrl: string;
|
|
148
|
+
readonly environment: string | undefined;
|
|
149
|
+
private readonly o;
|
|
150
|
+
private readonly cfg;
|
|
151
|
+
private readonly secret;
|
|
152
|
+
private readonly log;
|
|
153
|
+
private readonly storage;
|
|
154
|
+
private readonly storageKey;
|
|
155
|
+
private readonly getters;
|
|
156
|
+
private payload;
|
|
157
|
+
/** The payload as received (possibly encrypted): what `getPayload()` hands to browsers. */
|
|
158
|
+
private raw;
|
|
159
|
+
private etag;
|
|
160
|
+
private remote;
|
|
161
|
+
private results;
|
|
162
|
+
private resultsKey;
|
|
163
|
+
private readonly resultCache;
|
|
164
|
+
private context;
|
|
165
|
+
private attributes;
|
|
166
|
+
private overrides;
|
|
167
|
+
private readonly urlOverrides;
|
|
168
|
+
private offline;
|
|
169
|
+
private destroyed;
|
|
170
|
+
private ready_;
|
|
171
|
+
private resolveReady;
|
|
172
|
+
private readonly readyPromise;
|
|
173
|
+
private readonly listeners;
|
|
174
|
+
private inflight;
|
|
175
|
+
private lastFetchAt;
|
|
176
|
+
private failures;
|
|
177
|
+
private retryAt;
|
|
178
|
+
private pollTimer;
|
|
179
|
+
private remoteTimer;
|
|
180
|
+
private flushTimer;
|
|
181
|
+
private flushDue;
|
|
182
|
+
private stream;
|
|
183
|
+
private streamConnected;
|
|
184
|
+
private streamFailures;
|
|
185
|
+
private reconnectTimer;
|
|
186
|
+
private readonly exposed;
|
|
187
|
+
private readonly usage;
|
|
188
|
+
private exposures;
|
|
189
|
+
private readonly warned;
|
|
190
|
+
private cleanups;
|
|
191
|
+
private lastError;
|
|
192
|
+
constructor(options: FlagsClientOptions);
|
|
193
|
+
/** Boolean flag value; `fallback` (default `false`) when missing or not a boolean. */
|
|
194
|
+
isEnabled(key: string, fallback?: boolean): boolean;
|
|
195
|
+
/** Flag value; `fallback` when missing, null or of a different JSON type than `fallback`. */
|
|
196
|
+
getValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
197
|
+
getString(key: string, fallback: string): string;
|
|
198
|
+
getNumber(key: string, fallback: number): number;
|
|
199
|
+
getBoolean(key: string, fallback: boolean): boolean;
|
|
200
|
+
getJson<T = JsonValue>(key: string, fallback: T): T;
|
|
201
|
+
/** Value plus reason, rule, variation and experiment assignment. */
|
|
202
|
+
getDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
203
|
+
/** Every flag's value for the current attributes (records no exposures or usage). */
|
|
204
|
+
getAll(): Record<string, JsonValue>;
|
|
205
|
+
/**
|
|
206
|
+
* Getters bound to other attributes (merged over the client's), without changing the client:
|
|
207
|
+
* the per-request pattern on servers. With remote evaluation they serve results already cached
|
|
208
|
+
* for these attributes, else fallbacks.
|
|
209
|
+
*/
|
|
210
|
+
forUser(attributes: Attributes): FlagsEvaluator;
|
|
211
|
+
/** Replaces the app attributes. */
|
|
212
|
+
setAttributes(attributes: Attributes): void;
|
|
213
|
+
/** Merges into the app attributes. */
|
|
214
|
+
updateAttributes(partial: Attributes): void;
|
|
215
|
+
/** Replaces the integration-supplied attributes (see `contextAttributes`). */
|
|
216
|
+
setContextAttributes(attributes: Attributes): void;
|
|
217
|
+
/** Context attributes with app attributes merged over them. */
|
|
218
|
+
getAttributes(): Attributes;
|
|
219
|
+
/** Replaces the overrides (`null` clears them). URL overrides stay. */
|
|
220
|
+
setOverrides(overrides: Record<string, JsonValue> | null): void;
|
|
221
|
+
private changeAttributes;
|
|
222
|
+
/** Resolves once the first load settled (bootstrap, network success or failure). Never rejects. */
|
|
223
|
+
ready(): Promise<void>;
|
|
224
|
+
isReady(): boolean;
|
|
225
|
+
/** Calls `listener` whenever values may have changed (payload, attributes, overrides, readiness). */
|
|
226
|
+
subscribe: (listener: () => void) => (() => void);
|
|
227
|
+
/** `true` stops all network activity; cached data keeps serving. `false` resumes and refreshes. */
|
|
228
|
+
setOffline(offline: boolean): void;
|
|
229
|
+
/** Fetches now (payload, or remote evaluation). Resolves when done; never rejects. */
|
|
230
|
+
refresh(): Promise<void>;
|
|
231
|
+
/**
|
|
232
|
+
* The current data for server-side rendering: pass it as `payload` to the browser client (or
|
|
233
|
+
* framework provider) to render the same values without a flash. Encrypted payloads stay
|
|
234
|
+
* encrypted; with remote evaluation it returns the results. `null` before anything loaded.
|
|
235
|
+
*/
|
|
236
|
+
getPayload(): FlagsBootstrap | null;
|
|
237
|
+
/** Sends pending usage counts and exposures now. */
|
|
238
|
+
flush(): Promise<void>;
|
|
239
|
+
/** Stops timers and streams and sends pending usage. The client keeps serving cached values. */
|
|
240
|
+
destroy(): void;
|
|
241
|
+
private overrideFor;
|
|
242
|
+
private resolve;
|
|
243
|
+
private evaluateRemoteOrLocal;
|
|
244
|
+
private all;
|
|
245
|
+
private now;
|
|
246
|
+
private record;
|
|
247
|
+
private warnOnce;
|
|
248
|
+
private setPayload;
|
|
249
|
+
private setResults;
|
|
250
|
+
/** Decrypts when needed and applies. Returns false (keeping the previous payload) when unusable. */
|
|
251
|
+
private applyRaw;
|
|
252
|
+
private loadStored;
|
|
253
|
+
private persist;
|
|
254
|
+
private url;
|
|
255
|
+
private headers;
|
|
256
|
+
private get fetcher();
|
|
257
|
+
private request;
|
|
258
|
+
private fetchNow;
|
|
259
|
+
private fetchPayload;
|
|
260
|
+
private fetchRemote;
|
|
261
|
+
private scheduleRemote;
|
|
262
|
+
private lazyRefresh;
|
|
263
|
+
private start;
|
|
264
|
+
private settle;
|
|
265
|
+
/** Arms the poll timer / stream for the current mode. */
|
|
266
|
+
private schedule;
|
|
267
|
+
private schedulePoll;
|
|
268
|
+
private stopNetwork;
|
|
269
|
+
private onStreamEvent;
|
|
270
|
+
private openStream;
|
|
271
|
+
/** The stream dropped: poll meanwhile and reconnect with backoff (`permanent`: never retry). */
|
|
272
|
+
private streamDown;
|
|
273
|
+
private scheduleFlush;
|
|
274
|
+
private takeBatch;
|
|
275
|
+
private requeue;
|
|
276
|
+
/** Page hide / destroy: `sendBeacon` for public keys, else a `keepalive` fetch. */
|
|
277
|
+
private flushOnExit;
|
|
278
|
+
private wireBrowser;
|
|
279
|
+
private notify;
|
|
280
|
+
private reportError;
|
|
281
|
+
}
|
|
282
|
+
/** Creates a flags client and starts loading (per `pollingMode`). */
|
|
283
|
+
declare function createFlagsClient(options: FlagsClientOptions): FlagsClient;
|
|
284
|
+
|
|
285
|
+
/** Sticky bucket stores (docs/feature-flags-spec.md §3.5): keep a user's experiment variation across config changes. */
|
|
286
|
+
|
|
287
|
+
/** Keeps assignments in memory for the life of the process (servers, tests). */
|
|
288
|
+
declare class InMemoryStickyBucketStore implements StickyBucketStore {
|
|
289
|
+
private readonly docs;
|
|
290
|
+
get(docKey: string): StickyAssignments | null;
|
|
291
|
+
set(docKey: string, assignments: StickyAssignments): void;
|
|
292
|
+
}
|
|
293
|
+
/** Persists assignments in `localStorage` (browsers). Falls back to memory when storage is unavailable. */
|
|
294
|
+
declare class LocalStorageStickyBucketStore implements StickyBucketStore {
|
|
295
|
+
private readonly prefix;
|
|
296
|
+
private readonly memory;
|
|
297
|
+
constructor(prefix?: string);
|
|
298
|
+
private get storage();
|
|
299
|
+
get(docKey: string): StickyAssignments | null;
|
|
300
|
+
set(docKey: string, assignments: StickyAssignments): void;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Small runtime-neutral helpers shared by the flags client. No Node built-ins, no DOM at module scope. */
|
|
304
|
+
|
|
305
|
+
/** JSON with object keys sorted: equal attribute sets give equal strings (remote-eval cache keys). */
|
|
306
|
+
declare function stableStringify(value: unknown): string;
|
|
307
|
+
declare function isEncryptedPayload(x: unknown): x is EncryptedFlagsPayload;
|
|
308
|
+
/** A remote-evaluation response (`{ version, flags: { key: EvaluationResult } }`) rather than a payload. */
|
|
309
|
+
declare function isRemoteResults(x: unknown): x is RemoteEvaluationResponse;
|
|
310
|
+
declare function isFlagsPayload(x: unknown): x is FlagsPayload;
|
|
311
|
+
/** `?guidely_flags=key:value,key2:"str"` → overrides. Values are JSON when they parse, strings otherwise. */
|
|
312
|
+
declare function parseUrlOverrides(search: string, param?: string): Record<string, JsonValue>;
|
|
313
|
+
|
|
314
|
+
export { Attributes, DEFAULT_FLAGS_API_URL, EncryptedFlagsPayload, EvaluationResult, ExperimentAssignment, FLAGS_SDK_NAME, FLAGS_SDK_VERSION, type FlagDetails, type FlagValue, type FlagsBootstrap, FlagsClient, type FlagsClientOptions, type FlagsEvaluator, type FlagsLogger, FlagsPayload, type FlagsReader, type FlagsStorage, InMemoryStickyBucketStore, JsonValue, LocalStorageStickyBucketStore, type OverrideBehaviour, type PollingMode, RemoteEvaluationResponse, type StaticFlagsInput, StickyAssignments, StickyBucketStore, createFlagsClient, createStaticFlags, isEncryptedPayload, isFlagsPayload, isRemoteResults, parseUrlOverrides, stableStringify };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { JsonValue, EvaluationResult, Attributes, FlagsPayload, RemoteEvaluationResponse, EncryptedFlagsPayload, StickyBucketStore, ExperimentAssignment, StickyAssignments } from './evaluate.js';
|
|
2
|
+
export { ARRAY_OPERATORS, ATTRIBUTE_OPERATORS, AttributeCondition, AttributeOperator, BOOLEAN_OPERATORS, Condition, ConditionSegment, DATE_OPERATORS, EvaluateOptions, EvaluationReason, ExperimentNamespace, ExperimentRule, ExperimentVariation, FlagComparisonOperator, FlagCondition, FlagDefinition, FlagEventsBatch, FlagRule, FlagRuleType, FlagValueType, ForceRule, GroupCondition, HASHED_OPERATORS, HoldoutDefinition, ListSegment, NUMBER_OPERATORS, PRESENCE_OPERATORS, Prerequisite, RampStep, RolloutRule, RuleSchedule, SEMVER_OPERATORS, SegmentCondition, SegmentDefinition, SplitBucket, SplitRule, TEXT_OPERATORS, compareSemver, effectiveCoverage, evaluateAllFlags, evaluateFlag, fnv1a32, hashBucket, hashConfidential, hashConfidentialAffix, instantOf, isOn, isScheduleActive, jsonEquals, lookupAttribute, numberOf, parseSemver, sha256Hex, textOf } from './evaluate.js';
|
|
3
|
+
|
|
4
|
+
/** The value type a getter returns for a fallback: literals widen (`"blue"` → `string`), JSON types stay. */
|
|
5
|
+
type FlagValue<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
|
|
6
|
+
/** An evaluation result whose `value` is the caller's fallback when the flag is missing, null or of another type. */
|
|
7
|
+
interface FlagDetails<T = JsonValue> extends Omit<EvaluationResult, "value"> {
|
|
8
|
+
value: T;
|
|
9
|
+
/** The fallback was served (flag missing, value null or of the wrong type). */
|
|
10
|
+
usedFallback: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Synchronous flag getters. They never throw: problems give the fallback. */
|
|
13
|
+
interface FlagsEvaluator {
|
|
14
|
+
/** Boolean flag value; `fallback` (default `false`) when missing or not a boolean. */
|
|
15
|
+
isEnabled(key: string, fallback?: boolean): boolean;
|
|
16
|
+
/** Flag value; `fallback` when missing, null or of a different JSON type than `fallback`. */
|
|
17
|
+
getValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
18
|
+
getString(key: string, fallback: string): string;
|
|
19
|
+
getNumber(key: string, fallback: number): number;
|
|
20
|
+
getBoolean(key: string, fallback: boolean): boolean;
|
|
21
|
+
/** Object or array value. */
|
|
22
|
+
getJson<T = JsonValue>(key: string, fallback: T): T;
|
|
23
|
+
/** Value plus why it was served (reason, rule, variation, experiment). */
|
|
24
|
+
getDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
25
|
+
/** Every flag's value for these attributes (no exposures or usage are recorded). */
|
|
26
|
+
getAll(): Record<string, JsonValue>;
|
|
27
|
+
/** The attributes these getters evaluate with. */
|
|
28
|
+
getAttributes(): Attributes;
|
|
29
|
+
}
|
|
30
|
+
/** What framework bindings read from: an evaluator that can say whether it has loaded and notify changes. */
|
|
31
|
+
interface FlagsReader extends FlagsEvaluator {
|
|
32
|
+
isReady(): boolean;
|
|
33
|
+
/** Calls `listener` whenever values may have changed. Returns an unsubscribe function. */
|
|
34
|
+
subscribe(listener: () => void): () => void;
|
|
35
|
+
}
|
|
36
|
+
interface StaticFlagsInput {
|
|
37
|
+
/** A payload (or remote-evaluation results) from `client.getPayload()` on the server. */
|
|
38
|
+
payload?: FlagsPayload | RemoteEvaluationResponse | unknown;
|
|
39
|
+
attributes?: Attributes;
|
|
40
|
+
now?: Date | number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A network-free, read-only snapshot over a bootstrap payload. Framework bindings render with it
|
|
44
|
+
* on the server and during hydration so the HTML matches; it records no exposures or usage.
|
|
45
|
+
* Encrypted payloads cannot be read synchronously and give fallbacks.
|
|
46
|
+
*/
|
|
47
|
+
declare function createStaticFlags(input?: StaticFlagsInput): FlagsReader;
|
|
48
|
+
|
|
49
|
+
declare const FLAGS_SDK_NAME = "@guidelytech/flags";
|
|
50
|
+
declare const FLAGS_SDK_VERSION = "0.7.0";
|
|
51
|
+
declare const DEFAULT_FLAGS_API_URL = "https://guidelytech.com";
|
|
52
|
+
/**
|
|
53
|
+
* - `auto` — fetch at start, then every `pollIntervalSeconds`.
|
|
54
|
+
* - `lazy` — fetch when a flag is read and the cache is older than `cacheTtlSeconds` (serverless, edge).
|
|
55
|
+
* - `manual` — only `refresh()` fetches.
|
|
56
|
+
* - `stream` — server-sent events push changes; polls while the stream is down.
|
|
57
|
+
*/
|
|
58
|
+
type PollingMode = "auto" | "lazy" | "manual" | "stream";
|
|
59
|
+
/** `localOnly`: never fetch, serve overrides only. `localOverRemote`: overrides win. `remoteOverLocal`: overrides fill in flags missing remotely. */
|
|
60
|
+
type OverrideBehaviour = "localOnly" | "localOverRemote" | "remoteOverLocal";
|
|
61
|
+
/** Key/value storage for the last payload: `localStorage`-like or AsyncStorage-like (sync or async). */
|
|
62
|
+
interface FlagsStorage {
|
|
63
|
+
getItem(key: string): string | null | undefined | Promise<string | null | undefined>;
|
|
64
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
65
|
+
removeItem?(key: string): void | Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
interface FlagsLogger {
|
|
68
|
+
debug?(...args: unknown[]): void;
|
|
69
|
+
warn?(...args: unknown[]): void;
|
|
70
|
+
error?(...args: unknown[]): void;
|
|
71
|
+
}
|
|
72
|
+
/** What a bootstrap / `getPayload()` can hold. */
|
|
73
|
+
type FlagsBootstrap = FlagsPayload | EncryptedFlagsPayload | RemoteEvaluationResponse;
|
|
74
|
+
interface FlagsClientOptions {
|
|
75
|
+
/** Environment public key `pk_…` (the `projectId` used for tracking) or, on servers only, a secret `gly_sk_…` key. */
|
|
76
|
+
sdkKey?: string;
|
|
77
|
+
/** Alias of `sdkKey`. */
|
|
78
|
+
projectId?: string;
|
|
79
|
+
/** Base URL of your Guidely deployment (default `https://guidelytech.com`). */
|
|
80
|
+
apiUrl?: string;
|
|
81
|
+
/** `development` | `staging` | `production`. Required with a `gly_sk_` key. */
|
|
82
|
+
environment?: string;
|
|
83
|
+
/** Default attributes, merged under per-call (`forUser`) attributes. */
|
|
84
|
+
attributes?: Attributes;
|
|
85
|
+
/**
|
|
86
|
+
* Attributes supplied by a Guidely SDK integration (identity, page, device). App attributes
|
|
87
|
+
* (`attributes`, `setAttributes`) are merged over them.
|
|
88
|
+
*/
|
|
89
|
+
contextAttributes?: Attributes;
|
|
90
|
+
pollingMode?: PollingMode;
|
|
91
|
+
/** `auto` / `stream` fallback polling interval (default 60). */
|
|
92
|
+
pollIntervalSeconds?: number;
|
|
93
|
+
/** `lazy` cache lifetime (default 60). */
|
|
94
|
+
cacheTtlSeconds?: number;
|
|
95
|
+
/** Bootstrap: a payload (plain or encrypted) or remote-evaluation results, used immediately. */
|
|
96
|
+
payload?: FlagsBootstrap | null;
|
|
97
|
+
/** Bootstrap for remote evaluation: `{ version, flags }` or a map of results. */
|
|
98
|
+
remoteResults?: RemoteEvaluationResponse | Record<string, EvaluationResult> | null;
|
|
99
|
+
/** Base64 AES-256 key for environments that encrypt their payload. */
|
|
100
|
+
decryptionKey?: string;
|
|
101
|
+
/** Ask the server to evaluate (`POST /flags/evaluate`) instead of downloading rules. Needed when the environment hides rules. */
|
|
102
|
+
remoteEval?: boolean;
|
|
103
|
+
/** Debounce for re-evaluating remotely after attribute changes (default 50 ms). */
|
|
104
|
+
remoteEvalDebounceMs?: number;
|
|
105
|
+
/** Local flag values (tests, QA, kill switches) applied per `overrideBehaviour`. */
|
|
106
|
+
overrides?: Record<string, JsonValue> | null;
|
|
107
|
+
overrideBehaviour?: OverrideBehaviour;
|
|
108
|
+
/** Keeps experiment assignments stable (`InMemoryStickyBucketStore`, `LocalStorageStickyBucketStore`). */
|
|
109
|
+
stickyBucketService?: StickyBucketStore;
|
|
110
|
+
/** Persists the last payload. Default: `localStorage` in browsers, none elsewhere. `false` disables. */
|
|
111
|
+
storage?: FlagsStorage | null | false;
|
|
112
|
+
/** Browser only: read `?guidely_flags=key:value,key2:"text"` from the URL as overrides (QA). */
|
|
113
|
+
enableUrlOverrides?: boolean;
|
|
114
|
+
/** Called once per (experiment, user, variation) when a user is bucketed into an experiment. */
|
|
115
|
+
trackingCallback?: (experiment: ExperimentAssignment, result: EvaluationResult) => void;
|
|
116
|
+
/** Send experiment exposures to Guidely (`POST /flags/events`). Default: `true` unless `trackingCallback` is set. */
|
|
117
|
+
trackExposures?: boolean;
|
|
118
|
+
/** Send aggregated evaluation counts to Guidely at most every 60 s (default `true`). */
|
|
119
|
+
reportUsage?: boolean;
|
|
120
|
+
onReady?: () => void;
|
|
121
|
+
/** New payload (or remote results) applied. */
|
|
122
|
+
onChange?: (data: FlagsPayload | RemoteEvaluationResponse) => void;
|
|
123
|
+
onFlagEvaluated?: (result: EvaluationResult) => void;
|
|
124
|
+
onError?: (error: Error) => void;
|
|
125
|
+
/** Start without network activity (cached / bootstrapped data keeps serving). */
|
|
126
|
+
offline?: boolean;
|
|
127
|
+
fetch?: typeof fetch;
|
|
128
|
+
/**
|
|
129
|
+
* Defaults to `console`: `error` for failed requests (once per streak), `warn` for misuse and,
|
|
130
|
+
* in development, reads of flags that do not exist. `null` silences the client.
|
|
131
|
+
*/
|
|
132
|
+
logger?: FlagsLogger | null;
|
|
133
|
+
/** Evaluation clock (tests). */
|
|
134
|
+
now?: () => Date | number;
|
|
135
|
+
/** Reported with usage (set by Guidely SDK integrations). */
|
|
136
|
+
sdk?: {
|
|
137
|
+
name: string;
|
|
138
|
+
version: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Feature flags for one environment. Create with {@link createFlagsClient}; one per app (browser)
|
|
143
|
+
* or per process (server — use {@link FlagsClient.forUser} per request).
|
|
144
|
+
*/
|
|
145
|
+
declare class FlagsClient implements FlagsReader {
|
|
146
|
+
readonly sdkKey: string;
|
|
147
|
+
readonly apiUrl: string;
|
|
148
|
+
readonly environment: string | undefined;
|
|
149
|
+
private readonly o;
|
|
150
|
+
private readonly cfg;
|
|
151
|
+
private readonly secret;
|
|
152
|
+
private readonly log;
|
|
153
|
+
private readonly storage;
|
|
154
|
+
private readonly storageKey;
|
|
155
|
+
private readonly getters;
|
|
156
|
+
private payload;
|
|
157
|
+
/** The payload as received (possibly encrypted): what `getPayload()` hands to browsers. */
|
|
158
|
+
private raw;
|
|
159
|
+
private etag;
|
|
160
|
+
private remote;
|
|
161
|
+
private results;
|
|
162
|
+
private resultsKey;
|
|
163
|
+
private readonly resultCache;
|
|
164
|
+
private context;
|
|
165
|
+
private attributes;
|
|
166
|
+
private overrides;
|
|
167
|
+
private readonly urlOverrides;
|
|
168
|
+
private offline;
|
|
169
|
+
private destroyed;
|
|
170
|
+
private ready_;
|
|
171
|
+
private resolveReady;
|
|
172
|
+
private readonly readyPromise;
|
|
173
|
+
private readonly listeners;
|
|
174
|
+
private inflight;
|
|
175
|
+
private lastFetchAt;
|
|
176
|
+
private failures;
|
|
177
|
+
private retryAt;
|
|
178
|
+
private pollTimer;
|
|
179
|
+
private remoteTimer;
|
|
180
|
+
private flushTimer;
|
|
181
|
+
private flushDue;
|
|
182
|
+
private stream;
|
|
183
|
+
private streamConnected;
|
|
184
|
+
private streamFailures;
|
|
185
|
+
private reconnectTimer;
|
|
186
|
+
private readonly exposed;
|
|
187
|
+
private readonly usage;
|
|
188
|
+
private exposures;
|
|
189
|
+
private readonly warned;
|
|
190
|
+
private cleanups;
|
|
191
|
+
private lastError;
|
|
192
|
+
constructor(options: FlagsClientOptions);
|
|
193
|
+
/** Boolean flag value; `fallback` (default `false`) when missing or not a boolean. */
|
|
194
|
+
isEnabled(key: string, fallback?: boolean): boolean;
|
|
195
|
+
/** Flag value; `fallback` when missing, null or of a different JSON type than `fallback`. */
|
|
196
|
+
getValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
197
|
+
getString(key: string, fallback: string): string;
|
|
198
|
+
getNumber(key: string, fallback: number): number;
|
|
199
|
+
getBoolean(key: string, fallback: boolean): boolean;
|
|
200
|
+
getJson<T = JsonValue>(key: string, fallback: T): T;
|
|
201
|
+
/** Value plus reason, rule, variation and experiment assignment. */
|
|
202
|
+
getDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
203
|
+
/** Every flag's value for the current attributes (records no exposures or usage). */
|
|
204
|
+
getAll(): Record<string, JsonValue>;
|
|
205
|
+
/**
|
|
206
|
+
* Getters bound to other attributes (merged over the client's), without changing the client:
|
|
207
|
+
* the per-request pattern on servers. With remote evaluation they serve results already cached
|
|
208
|
+
* for these attributes, else fallbacks.
|
|
209
|
+
*/
|
|
210
|
+
forUser(attributes: Attributes): FlagsEvaluator;
|
|
211
|
+
/** Replaces the app attributes. */
|
|
212
|
+
setAttributes(attributes: Attributes): void;
|
|
213
|
+
/** Merges into the app attributes. */
|
|
214
|
+
updateAttributes(partial: Attributes): void;
|
|
215
|
+
/** Replaces the integration-supplied attributes (see `contextAttributes`). */
|
|
216
|
+
setContextAttributes(attributes: Attributes): void;
|
|
217
|
+
/** Context attributes with app attributes merged over them. */
|
|
218
|
+
getAttributes(): Attributes;
|
|
219
|
+
/** Replaces the overrides (`null` clears them). URL overrides stay. */
|
|
220
|
+
setOverrides(overrides: Record<string, JsonValue> | null): void;
|
|
221
|
+
private changeAttributes;
|
|
222
|
+
/** Resolves once the first load settled (bootstrap, network success or failure). Never rejects. */
|
|
223
|
+
ready(): Promise<void>;
|
|
224
|
+
isReady(): boolean;
|
|
225
|
+
/** Calls `listener` whenever values may have changed (payload, attributes, overrides, readiness). */
|
|
226
|
+
subscribe: (listener: () => void) => (() => void);
|
|
227
|
+
/** `true` stops all network activity; cached data keeps serving. `false` resumes and refreshes. */
|
|
228
|
+
setOffline(offline: boolean): void;
|
|
229
|
+
/** Fetches now (payload, or remote evaluation). Resolves when done; never rejects. */
|
|
230
|
+
refresh(): Promise<void>;
|
|
231
|
+
/**
|
|
232
|
+
* The current data for server-side rendering: pass it as `payload` to the browser client (or
|
|
233
|
+
* framework provider) to render the same values without a flash. Encrypted payloads stay
|
|
234
|
+
* encrypted; with remote evaluation it returns the results. `null` before anything loaded.
|
|
235
|
+
*/
|
|
236
|
+
getPayload(): FlagsBootstrap | null;
|
|
237
|
+
/** Sends pending usage counts and exposures now. */
|
|
238
|
+
flush(): Promise<void>;
|
|
239
|
+
/** Stops timers and streams and sends pending usage. The client keeps serving cached values. */
|
|
240
|
+
destroy(): void;
|
|
241
|
+
private overrideFor;
|
|
242
|
+
private resolve;
|
|
243
|
+
private evaluateRemoteOrLocal;
|
|
244
|
+
private all;
|
|
245
|
+
private now;
|
|
246
|
+
private record;
|
|
247
|
+
private warnOnce;
|
|
248
|
+
private setPayload;
|
|
249
|
+
private setResults;
|
|
250
|
+
/** Decrypts when needed and applies. Returns false (keeping the previous payload) when unusable. */
|
|
251
|
+
private applyRaw;
|
|
252
|
+
private loadStored;
|
|
253
|
+
private persist;
|
|
254
|
+
private url;
|
|
255
|
+
private headers;
|
|
256
|
+
private get fetcher();
|
|
257
|
+
private request;
|
|
258
|
+
private fetchNow;
|
|
259
|
+
private fetchPayload;
|
|
260
|
+
private fetchRemote;
|
|
261
|
+
private scheduleRemote;
|
|
262
|
+
private lazyRefresh;
|
|
263
|
+
private start;
|
|
264
|
+
private settle;
|
|
265
|
+
/** Arms the poll timer / stream for the current mode. */
|
|
266
|
+
private schedule;
|
|
267
|
+
private schedulePoll;
|
|
268
|
+
private stopNetwork;
|
|
269
|
+
private onStreamEvent;
|
|
270
|
+
private openStream;
|
|
271
|
+
/** The stream dropped: poll meanwhile and reconnect with backoff (`permanent`: never retry). */
|
|
272
|
+
private streamDown;
|
|
273
|
+
private scheduleFlush;
|
|
274
|
+
private takeBatch;
|
|
275
|
+
private requeue;
|
|
276
|
+
/** Page hide / destroy: `sendBeacon` for public keys, else a `keepalive` fetch. */
|
|
277
|
+
private flushOnExit;
|
|
278
|
+
private wireBrowser;
|
|
279
|
+
private notify;
|
|
280
|
+
private reportError;
|
|
281
|
+
}
|
|
282
|
+
/** Creates a flags client and starts loading (per `pollingMode`). */
|
|
283
|
+
declare function createFlagsClient(options: FlagsClientOptions): FlagsClient;
|
|
284
|
+
|
|
285
|
+
/** Sticky bucket stores (docs/feature-flags-spec.md §3.5): keep a user's experiment variation across config changes. */
|
|
286
|
+
|
|
287
|
+
/** Keeps assignments in memory for the life of the process (servers, tests). */
|
|
288
|
+
declare class InMemoryStickyBucketStore implements StickyBucketStore {
|
|
289
|
+
private readonly docs;
|
|
290
|
+
get(docKey: string): StickyAssignments | null;
|
|
291
|
+
set(docKey: string, assignments: StickyAssignments): void;
|
|
292
|
+
}
|
|
293
|
+
/** Persists assignments in `localStorage` (browsers). Falls back to memory when storage is unavailable. */
|
|
294
|
+
declare class LocalStorageStickyBucketStore implements StickyBucketStore {
|
|
295
|
+
private readonly prefix;
|
|
296
|
+
private readonly memory;
|
|
297
|
+
constructor(prefix?: string);
|
|
298
|
+
private get storage();
|
|
299
|
+
get(docKey: string): StickyAssignments | null;
|
|
300
|
+
set(docKey: string, assignments: StickyAssignments): void;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Small runtime-neutral helpers shared by the flags client. No Node built-ins, no DOM at module scope. */
|
|
304
|
+
|
|
305
|
+
/** JSON with object keys sorted: equal attribute sets give equal strings (remote-eval cache keys). */
|
|
306
|
+
declare function stableStringify(value: unknown): string;
|
|
307
|
+
declare function isEncryptedPayload(x: unknown): x is EncryptedFlagsPayload;
|
|
308
|
+
/** A remote-evaluation response (`{ version, flags: { key: EvaluationResult } }`) rather than a payload. */
|
|
309
|
+
declare function isRemoteResults(x: unknown): x is RemoteEvaluationResponse;
|
|
310
|
+
declare function isFlagsPayload(x: unknown): x is FlagsPayload;
|
|
311
|
+
/** `?guidely_flags=key:value,key2:"str"` → overrides. Values are JSON when they parse, strings otherwise. */
|
|
312
|
+
declare function parseUrlOverrides(search: string, param?: string): Record<string, JsonValue>;
|
|
313
|
+
|
|
314
|
+
export { Attributes, DEFAULT_FLAGS_API_URL, EncryptedFlagsPayload, EvaluationResult, ExperimentAssignment, FLAGS_SDK_NAME, FLAGS_SDK_VERSION, type FlagDetails, type FlagValue, type FlagsBootstrap, FlagsClient, type FlagsClientOptions, type FlagsEvaluator, type FlagsLogger, FlagsPayload, type FlagsReader, type FlagsStorage, InMemoryStickyBucketStore, JsonValue, LocalStorageStickyBucketStore, type OverrideBehaviour, type PollingMode, RemoteEvaluationResponse, type StaticFlagsInput, StickyAssignments, StickyBucketStore, createFlagsClient, createStaticFlags, isEncryptedPayload, isFlagsPayload, isRemoteResults, parseUrlOverrides, stableStringify };
|