@spotify-confidence/openfeature-server-provider-local 0.6.0 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.0](https://github.com/spotify/confidence-resolver/compare/openfeature-provider-js-v0.6.0...openfeature-provider-js-v0.7.0) (2026-01-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * inlined WASM for improved portability ([#243](https://github.com/spotify/confidence-resolver/issues/243)) ([8d86283](https://github.com/spotify/confidence-resolver/commit/8d862837244ffd9099bfeb56b42e203212e73a96))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * rust-guest bumped from 0.1.12 to 0.1.13
16
+
3
17
  ## [0.6.0](https://github.com/spotify/confidence-resolver/compare/openfeature-provider-js-v0.5.1...openfeature-provider-js-v0.6.0) (2026-01-15)
4
18
 
5
19
 
package/README.md CHANGED
@@ -3,12 +3,14 @@
3
3
  OpenFeature provider for the Spotify Confidence resolver (local mode, powered by WebAssembly). It periodically fetches resolver state, evaluates flags locally, and flushes evaluation logs to the Confidence backend.
4
4
 
5
5
  ## Features
6
+
6
7
  - Local flag evaluation via WASM (no per-eval network calls)
7
8
  - Automatic state refresh and batched flag log flushing
8
9
  - Pluggable `fetch` with retries, timeouts and routing
9
10
  - Optional logging using `debug`
10
11
 
11
12
  ## Requirements
13
+
12
14
  - Node.js 18+ (built-in `fetch`) or provide a compatible `fetch`
13
15
  - WebAssembly support (Node 18+/modern browsers)
14
16
 
@@ -24,6 +26,7 @@ yarn add debug
24
26
  ```
25
27
 
26
28
  Notes:
29
+
27
30
  - `debug` is an optional peer. Install it if you want logs. Without it, logging is a no-op.
28
31
  - Types and bundling are ESM-first; Node is supported, and a browser build is provided for modern bundlers.
29
32
 
@@ -34,6 +37,7 @@ Notes:
34
37
  You'll need a **client secret** from Confidence to use this provider.
35
38
 
36
39
  **📖 See the [Integration Guide: Getting Your Credentials](../INTEGRATION_GUIDE.md#getting-your-credentials)** for step-by-step instructions on:
40
+
37
41
  - How to navigate the Confidence dashboard
38
42
  - Creating a Backend integration
39
43
  - Creating a test flag for verification
@@ -104,6 +108,7 @@ const context = {
104
108
  The provider uses a **default value fallback** pattern - when evaluation fails, it returns your specified default value instead of throwing an error.
105
109
 
106
110
  **📖 See the [Integration Guide: Error Handling](../INTEGRATION_GUIDE.md#error-handling)** for:
111
+
107
112
  - Common failure scenarios
108
113
  - Error codes and meanings
109
114
  - Production best practices
@@ -119,8 +124,8 @@ const enabled = await client.getBooleanValue('my-flag.enabled', false, context);
119
124
  // For detailed error information, use getBooleanDetails()
120
125
  const details = await client.getBooleanDetails('my-flag.enabled', false, context);
121
126
  if (details.errorCode) {
122
- console.error('Flag evaluation error:', details.errorMessage);
123
- console.log('Reason:', details.reason);
127
+ console.error('Flag evaluation error:', details.errorMessage);
128
+ console.log('Reason:', details.reason);
124
129
  }
125
130
  ```
126
131
 
@@ -135,11 +140,71 @@ if (details.errorCode) {
135
140
  - `fetch` (optional): Custom `fetch` implementation. Required for Node < 18; for Node 18+ you can omit.
136
141
 
137
142
  The provider periodically:
143
+
138
144
  - Refreshes resolver state (configurable via `stateUpdateInterval`, default every 30s)
139
145
  - Flushes flag evaluation logs to the backend (configurable via `flushInterval`, default every 10s)
140
146
 
141
147
  ---
142
148
 
149
+ ## Exports and WASM Loading
150
+
151
+ The package provides multiple exports for different environments:
152
+
153
+ ### Default export (recommended)
154
+
155
+ ```ts
156
+ import { createConfidenceServerProvider } from '@spotify-confidence/openfeature-server-provider-local';
157
+ ```
158
+
159
+ The WASM is **inlined as a data URL** — this is the most portable option and should work across virtually all environments. The tradeoff is a larger bundle (~700kB), but this isn't a problem for the intended server-side usage.
160
+
161
+ No configuration needed.
162
+
163
+ ### `./node` — Traditional Node.js
164
+
165
+ ```ts
166
+ import { createConfidenceServerProvider } from '@spotify-confidence/openfeature-server-provider-local/node';
167
+ ```
168
+
169
+ Uses `fs.readFile()` to load WASM from the installed package. Works well in a regular Node.js environment with node_modules.
170
+
171
+ You can customize the WASM path if needed:
172
+
173
+ ```ts
174
+ const provider = createConfidenceServerProvider({
175
+ flagClientSecret: '...',
176
+ wasmPath: '/custom/path/to/confidence_resolver.wasm',
177
+ });
178
+ ```
179
+
180
+ ### `./fetch` — Modern and standards compliant environments
181
+
182
+ ```ts
183
+ import { createConfidenceServerProvider } from '@spotify-confidence/openfeature-server-provider-local/fetch';
184
+ ```
185
+
186
+ Uses `fetch()` with `import.meta.url` to load WASM. Works in Deno, Bun, and browsers with bundlers that properly handle asset URLs (Vite, Rollup, etc.).
187
+
188
+ You can customize the WASM URL if needed:
189
+
190
+ ```ts
191
+ const provider = createConfidenceServerProvider({
192
+ flagClientSecret: '...',
193
+ wasmUrl: '/assets/confidence_resolver.wasm',
194
+ });
195
+ ```
196
+
197
+ ### A note on browser usage
198
+
199
+ While browsers are mentioned in this doc, this package is intended for server-side use only. Two concerns for browser usage:
200
+
201
+ - Size: The WASM+JS is currently ~270kb gzipped, too large for typical client bundles.
202
+ - Security: In a browser, all flag rules and variants are exposed to users.
203
+
204
+ That said, the package does work in browsers, and there may be specialized use cases where these tradeoffs are acceptable.
205
+
206
+ ---
207
+
143
208
  ## Materialization Stores
144
209
 
145
210
  Materialization stores provide persistent storage for sticky variant assignments and custom targeting segments. This enables two key use cases:
@@ -164,11 +229,13 @@ const provider = createConfidenceServerProvider({
164
229
  ```
165
230
 
166
231
  **When to use**:
232
+
167
233
  - You need sticky assignments or materialized segments but don't want to manage storage infrastructure
168
234
  - Quick prototyping or getting started
169
235
  - Lower-volume applications where network latency is acceptable
170
236
 
171
237
  **Trade-offs**:
238
+
172
239
  - Additional network calls during flag resolution (adds latency)
173
240
  - Lower performance compared to local storage implementations (Redis, DynamoDB, etc.)
174
241
 
@@ -200,6 +267,7 @@ For read-only stores (e.g., pre-populated materialized segments without sticky a
200
267
  ### When to Use Materialization Stores
201
268
 
202
269
  Consider implementing a materialization store if:
270
+
203
271
  - You need to support sticky variant assignments for experiments
204
272
  - You use materialized segments for custom targeting
205
273
  - You want to minimize network latency during flag resolution
@@ -214,10 +282,12 @@ If you don't use sticky assignments or materialized segments, the default behavi
214
282
  Logging uses the `debug` library if present; otherwise, all log calls are no-ops.
215
283
 
216
284
  Namespaces:
285
+
217
286
  - Core: `cnfd:*`
218
287
  - Fetch/middleware: `cnfd:fetch:*` (e.g. retries, auth renewals, request summaries)
219
288
 
220
289
  Log levels are hierarchical:
290
+
221
291
  - `cnfd:debug` enables debug, info, warn, and error
222
292
  - `cnfd:info` enables info, warn, and error
223
293
  - `cnfd:warn` enables warn and error
@@ -226,6 +296,7 @@ Log levels are hierarchical:
226
296
  Enable logs:
227
297
 
228
298
  - Node:
299
+
229
300
  ```bash
230
301
  DEBUG=cnfd:* node app.js
231
302
  # or narrower
@@ -233,6 +304,7 @@ DEBUG=cnfd:info,cnfd:fetch:* node app.js
233
304
  ```
234
305
 
235
306
  - Browser (in DevTools console):
307
+
236
308
  ```js
237
309
  localStorage.debug = 'cnfd:*';
238
310
  ```
@@ -245,19 +317,6 @@ yarn add debug
245
317
 
246
318
  ---
247
319
 
248
- ## WebAssembly asset notes
249
-
250
- - Node: the WASM (`confidence_resolver.wasm`) is resolved from the installed package automatically; no extra config needed.
251
- - Browser: the ESM build resolves the WASM via `new URL('confidence_resolver.wasm', import.meta.url)` so modern bundlers (Vite/Rollup/Webpack 5 asset modules) will include it. If your bundler does not, configure it to treat the `.wasm` file as a static asset.
252
-
253
- ---
254
-
255
- ## Using in browsers
256
-
257
- The package exports a browser ESM build that compiles the WASM via streaming and uses the global `fetch`. Integrate it with your OpenFeature SDK variant for the web similarly to Node, then register the provider before evaluation. Credentials must be available to the runtime (e.g. through your app’s configuration layer).
258
-
259
- ---
260
-
261
320
  ## Testing
262
321
 
263
322
  - You can inject a custom `fetch` via the `fetch` option to stub network behavior in tests.
Binary file
@@ -0,0 +1,466 @@
1
+ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
2
+ import { EvaluationContext, JsonValue, Provider, ProviderMetadata, ProviderStatus, ResolutionDetails } from "@openfeature/server-sdk";
3
+
4
+ //#region src/proto/confidence/flags/types/v1/types.d.ts
5
+ /** Schema for the value of a flag. */
6
+ interface FlagSchema {
7
+ /** Schema if this is a struct */
8
+ structSchema?: FlagSchema_StructFlagSchema | undefined;
9
+ /** Schema if this is a list */
10
+ listSchema?: FlagSchema_ListFlagSchema | undefined;
11
+ /** Schema if this is an int */
12
+ intSchema?: FlagSchema_IntFlagSchema | undefined;
13
+ /** Schema if this is a double */
14
+ doubleSchema?: FlagSchema_DoubleFlagSchema | undefined;
15
+ /** Schema if this is a string */
16
+ stringSchema?: FlagSchema_StringFlagSchema | undefined;
17
+ /** Schema if this is a bool */
18
+ boolSchema?: FlagSchema_BoolFlagSchema | undefined;
19
+ }
20
+ /** A schema of nested fields. */
21
+ interface FlagSchema_StructFlagSchema {
22
+ /** Map of field name to the schema for the field */
23
+ schema: {
24
+ [key: string]: FlagSchema;
25
+ };
26
+ }
27
+ /** A number that has a decimal place. */
28
+ interface FlagSchema_DoubleFlagSchema {}
29
+ /** A whole number without a decimal point. */
30
+ interface FlagSchema_IntFlagSchema {}
31
+ /** A string. */
32
+ interface FlagSchema_StringFlagSchema {}
33
+ /** A boolean: true or false. */
34
+ interface FlagSchema_BoolFlagSchema {}
35
+ /** A list of values. */
36
+ interface FlagSchema_ListFlagSchema {
37
+ /** The schema for the elements in the list */
38
+ elementSchema?: FlagSchema | undefined;
39
+ }
40
+ declare const FlagSchema: MessageFns$5<FlagSchema>;
41
+ declare const FlagSchema_StructFlagSchema: MessageFns$5<FlagSchema_StructFlagSchema>;
42
+ declare const FlagSchema_DoubleFlagSchema: MessageFns$5<FlagSchema_DoubleFlagSchema>;
43
+ declare const FlagSchema_IntFlagSchema: MessageFns$5<FlagSchema_IntFlagSchema>;
44
+ declare const FlagSchema_StringFlagSchema: MessageFns$5<FlagSchema_StringFlagSchema>;
45
+ declare const FlagSchema_BoolFlagSchema: MessageFns$5<FlagSchema_BoolFlagSchema>;
46
+ declare const FlagSchema_ListFlagSchema: MessageFns$5<FlagSchema_ListFlagSchema>;
47
+ type Builtin$5 = Date | Function | Uint8Array | string | number | boolean | undefined;
48
+ type DeepPartial$5<T> = T extends Builtin$5 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$5<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$5<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$5<T[K]> } : Partial<T>;
49
+ type KeysOfUnion$5<T> = T extends T ? keyof T : never;
50
+ type Exact$5<P, I extends P> = P extends Builtin$5 ? P : P & { [K in keyof P]: Exact$5<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion$5<P>>]: never };
51
+ interface MessageFns$5<T> {
52
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
53
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
54
+ fromJSON(object: any): T;
55
+ toJSON(message: T): unknown;
56
+ create<I extends Exact$5<DeepPartial$5<T>, I>>(base?: I): T;
57
+ fromPartial<I extends Exact$5<DeepPartial$5<T>, I>>(object: I): T;
58
+ }
59
+ //#endregion
60
+ //#region src/proto/confidence/flags/resolver/v1/types.d.ts
61
+ declare enum ResolveReason {
62
+ /** RESOLVE_REASON_UNSPECIFIED - Unspecified enum. */
63
+ RESOLVE_REASON_UNSPECIFIED = 0,
64
+ /** RESOLVE_REASON_MATCH - The flag was successfully resolved because one rule matched. */
65
+ RESOLVE_REASON_MATCH = 1,
66
+ /** RESOLVE_REASON_NO_SEGMENT_MATCH - The flag could not be resolved because no rule matched. */
67
+ RESOLVE_REASON_NO_SEGMENT_MATCH = 2,
68
+ /**
69
+ * RESOLVE_REASON_NO_TREATMENT_MATCH - The flag could not be resolved because the matching rule had no variant
70
+ * that could be assigned.
71
+ *
72
+ * @deprecated
73
+ */
74
+ RESOLVE_REASON_NO_TREATMENT_MATCH = 3,
75
+ /** RESOLVE_REASON_FLAG_ARCHIVED - The flag could not be resolved because it was archived. */
76
+ RESOLVE_REASON_FLAG_ARCHIVED = 4,
77
+ /** RESOLVE_REASON_TARGETING_KEY_ERROR - The flag could not be resolved because the targeting key field was invalid */
78
+ RESOLVE_REASON_TARGETING_KEY_ERROR = 5,
79
+ /** RESOLVE_REASON_ERROR - Unknown error occurred during the resolve */
80
+ RESOLVE_REASON_ERROR = 6,
81
+ UNRECOGNIZED = -1,
82
+ }
83
+ declare enum SdkId {
84
+ SDK_ID_UNSPECIFIED = 0,
85
+ SDK_ID_JAVA_PROVIDER = 1,
86
+ SDK_ID_KOTLIN_PROVIDER = 2,
87
+ SDK_ID_SWIFT_PROVIDER = 3,
88
+ SDK_ID_JS_WEB_PROVIDER = 4,
89
+ SDK_ID_JS_SERVER_PROVIDER = 5,
90
+ SDK_ID_PYTHON_PROVIDER = 6,
91
+ SDK_ID_GO_PROVIDER = 7,
92
+ SDK_ID_RUBY_PROVIDER = 8,
93
+ SDK_ID_RUST_PROVIDER = 9,
94
+ SDK_ID_JAVA_CONFIDENCE = 10,
95
+ SDK_ID_KOTLIN_CONFIDENCE = 11,
96
+ SDK_ID_SWIFT_CONFIDENCE = 12,
97
+ SDK_ID_JS_CONFIDENCE = 13,
98
+ SDK_ID_PYTHON_CONFIDENCE = 14,
99
+ SDK_ID_GO_CONFIDENCE = 15,
100
+ SDK_ID_RUST_CONFIDENCE = 16,
101
+ SDK_ID_FLUTTER_IOS_CONFIDENCE = 17,
102
+ SDK_ID_FLUTTER_ANDROID_CONFIDENCE = 18,
103
+ SDK_ID_DOTNET_CONFIDENCE = 19,
104
+ SDK_ID_GO_LOCAL_PROVIDER = 20,
105
+ SDK_ID_JAVA_LOCAL_PROVIDER = 21,
106
+ SDK_ID_JS_LOCAL_SERVER_PROVIDER = 22,
107
+ UNRECOGNIZED = -1,
108
+ }
109
+ interface Sdk {
110
+ /** Name of a Confidence SDKs. */
111
+ id?: SdkId | undefined;
112
+ /** Custom name for non-Confidence SDKs. */
113
+ customId?: string | undefined;
114
+ /** Version of the SDK. */
115
+ version: string;
116
+ }
117
+ declare const Sdk: MessageFns$4<Sdk>;
118
+ type Builtin$4 = Date | Function | Uint8Array | string | number | boolean | undefined;
119
+ type DeepPartial$4<T> = T extends Builtin$4 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$4<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$4<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$4<T[K]> } : Partial<T>;
120
+ type KeysOfUnion$4<T> = T extends T ? keyof T : never;
121
+ type Exact$4<P, I extends P> = P extends Builtin$4 ? P : P & { [K in keyof P]: Exact$4<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion$4<P>>]: never };
122
+ interface MessageFns$4<T> {
123
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
124
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
125
+ fromJSON(object: any): T;
126
+ toJSON(message: T): unknown;
127
+ create<I extends Exact$4<DeepPartial$4<T>, I>>(base?: I): T;
128
+ fromPartial<I extends Exact$4<DeepPartial$4<T>, I>>(object: I): T;
129
+ }
130
+ //#endregion
131
+ //#region src/proto/confidence/flags/resolver/v1/api.d.ts
132
+ interface ResolveFlagsRequest {
133
+ /**
134
+ * If non-empty, the specific flags are resolved, otherwise all flags
135
+ * available to the client will be resolved.
136
+ */
137
+ flags: string[];
138
+ /**
139
+ * An object that contains data used in the flag resolve. For example,
140
+ * the targeting key e.g. the id of the randomization unit, other attributes
141
+ * like country or version that are used for targeting.
142
+ */
143
+ evaluationContext?: {
144
+ [key: string]: any;
145
+ } | undefined;
146
+ /**
147
+ * Credentials for the client. It is used to identify the client and find
148
+ * the flags that are available to it.
149
+ */
150
+ clientSecret: string;
151
+ /**
152
+ * Determines whether the flags should be applied directly as part of the
153
+ * resolve, or delayed until `ApplyFlag` is called. A flag is typically
154
+ * applied when it is used, if this occurs much later than the resolve, then
155
+ * `apply` should likely be set to false.
156
+ * In a local resolve case it is encouraged to set this to `true`
157
+ */
158
+ apply: boolean;
159
+ /** Information about the SDK used to initiate the request. */
160
+ sdk?: Sdk | undefined;
161
+ }
162
+ interface ResolveFlagsResponse {
163
+ /**
164
+ * The list of all flags that could be resolved. Note: if any flag was
165
+ * archived it will not be included in this list.
166
+ */
167
+ resolvedFlags: ResolvedFlag[];
168
+ /**
169
+ * An opaque token that is used when `apply` is set to false in `ResolveFlags`.
170
+ * When `apply` is set to false, the token must be passed to `ApplyFlags`.
171
+ */
172
+ resolveToken: Uint8Array;
173
+ /** Unique identifier for this particular resolve request. */
174
+ resolveId: string;
175
+ }
176
+ interface ResolvedFlag {
177
+ /** The id of the flag that as resolved. */
178
+ flag: string;
179
+ /** The id of the resolved variant has the format `flags/abc/variants/xyz`. */
180
+ variant: string;
181
+ /**
182
+ * The value corresponding to the variant. It will always be a json object,
183
+ * for example `{ "color": "red", "size": 12 }`.
184
+ */
185
+ value?: {
186
+ [key: string]: any;
187
+ } | undefined;
188
+ /** The schema of the value that was returned. */
189
+ flagSchema?: FlagSchema_StructFlagSchema | undefined;
190
+ /** The reason to why the flag could be resolved or not. */
191
+ reason: ResolveReason;
192
+ }
193
+ declare const ResolveFlagsRequest: MessageFns$3<ResolveFlagsRequest>;
194
+ declare const ResolveFlagsResponse: MessageFns$3<ResolveFlagsResponse>;
195
+ declare const ResolvedFlag: MessageFns$3<ResolvedFlag>;
196
+ type Builtin$3 = Date | Function | Uint8Array | string | number | boolean | undefined;
197
+ type DeepPartial$3<T> = T extends Builtin$3 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$3<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$3<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$3<T[K]> } : Partial<T>;
198
+ type KeysOfUnion$3<T> = T extends T ? keyof T : never;
199
+ type Exact$3<P, I extends P> = P extends Builtin$3 ? P : P & { [K in keyof P]: Exact$3<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion$3<P>>]: never };
200
+ interface MessageFns$3<T> {
201
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
202
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
203
+ fromJSON(object: any): T;
204
+ toJSON(message: T): unknown;
205
+ create<I extends Exact$3<DeepPartial$3<T>, I>>(base?: I): T;
206
+ fromPartial<I extends Exact$3<DeepPartial$3<T>, I>>(object: I): T;
207
+ }
208
+ //#endregion
209
+ //#region src/proto/confidence/flags/resolver/v1/internal_api.d.ts
210
+ interface VariantReadOp {
211
+ unit: string;
212
+ materialization: string;
213
+ rule: string;
214
+ }
215
+ interface InclusionReadOp {
216
+ unit: string;
217
+ materialization: string;
218
+ }
219
+ interface ReadOp$1 {
220
+ variantReadOp?: VariantReadOp | undefined;
221
+ inclusionReadOp?: InclusionReadOp | undefined;
222
+ }
223
+ interface ReadOperationsRequest {
224
+ ops: ReadOp$1[];
225
+ }
226
+ interface VariantData {
227
+ unit: string;
228
+ materialization: string;
229
+ rule: string;
230
+ variant: string;
231
+ }
232
+ interface InclusionData {
233
+ unit: string;
234
+ materialization: string;
235
+ isIncluded: boolean;
236
+ }
237
+ interface ReadResult {
238
+ variantResult?: VariantData | undefined;
239
+ inclusionResult?: InclusionData | undefined;
240
+ }
241
+ declare const VariantReadOp: MessageFns$2<VariantReadOp>;
242
+ declare const InclusionReadOp: MessageFns$2<InclusionReadOp>;
243
+ declare const ReadOp$1: MessageFns$2<ReadOp$1>;
244
+ declare const ReadOperationsRequest: MessageFns$2<ReadOperationsRequest>;
245
+ declare const VariantData: MessageFns$2<VariantData>;
246
+ declare const InclusionData: MessageFns$2<InclusionData>;
247
+ declare const ReadResult: MessageFns$2<ReadResult>;
248
+ type Builtin$2 = Date | Function | Uint8Array | string | number | boolean | undefined;
249
+ type DeepPartial$2<T> = T extends Builtin$2 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$2<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$2<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$2<T[K]> } : Partial<T>;
250
+ type KeysOfUnion$2<T> = T extends T ? keyof T : never;
251
+ type Exact$2<P, I extends P> = P extends Builtin$2 ? P : P & { [K in keyof P]: Exact$2<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion$2<P>>]: never };
252
+ interface MessageFns$2<T> {
253
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
254
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
255
+ fromJSON(object: any): T;
256
+ toJSON(message: T): unknown;
257
+ create<I extends Exact$2<DeepPartial$2<T>, I>>(base?: I): T;
258
+ fromPartial<I extends Exact$2<DeepPartial$2<T>, I>>(object: I): T;
259
+ }
260
+ //#endregion
261
+ //#region src/proto/confidence/wasm/wasm_api.d.ts
262
+ /** Request for resolving flags with sticky (materialized) assignments */
263
+ interface ResolveWithStickyRequest {
264
+ /** The standard resolve request */
265
+ resolveRequest?: ResolveFlagsRequest | undefined;
266
+ /** if a materialization info is missing, we want tor return to the caller immediately */
267
+ failFastOnSticky: boolean;
268
+ /** if we should support sticky or completely skip the flag if they had sticky rules */
269
+ notProcessSticky: boolean;
270
+ /** Context about the materialization required for the resolve */
271
+ materializations: ReadResult[];
272
+ }
273
+ /** Response from resolving with sticky assignments */
274
+ interface ResolveWithStickyResponse {
275
+ success?: ResolveWithStickyResponse_Success | undefined;
276
+ readOpsRequest?: ReadOperationsRequest | undefined;
277
+ }
278
+ /** Successful resolution with materialization updates */
279
+ interface ResolveWithStickyResponse_Success {
280
+ response?: ResolveFlagsResponse | undefined;
281
+ /** New assignments that should be stored */
282
+ materializationUpdates: VariantData[];
283
+ }
284
+ declare const ResolveWithStickyRequest: MessageFns$1<ResolveWithStickyRequest>;
285
+ declare const ResolveWithStickyResponse: MessageFns$1<ResolveWithStickyResponse>;
286
+ declare const ResolveWithStickyResponse_Success: MessageFns$1<ResolveWithStickyResponse_Success>;
287
+ type Builtin$1 = Date | Function | Uint8Array | string | number | boolean | undefined;
288
+ type DeepPartial$1<T> = T extends Builtin$1 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$1<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$1<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$1<T[K]> } : Partial<T>;
289
+ type KeysOfUnion$1<T> = T extends T ? keyof T : never;
290
+ type Exact$1<P, I extends P> = P extends Builtin$1 ? P : P & { [K in keyof P]: Exact$1<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion$1<P>>]: never };
291
+ interface MessageFns$1<T> {
292
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
293
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
294
+ fromJSON(object: any): T;
295
+ toJSON(message: T): unknown;
296
+ create<I extends Exact$1<DeepPartial$1<T>, I>>(base?: I): T;
297
+ fromPartial<I extends Exact$1<DeepPartial$1<T>, I>>(object: I): T;
298
+ }
299
+ //#endregion
300
+ //#region src/proto/confidence/wasm/messages.d.ts
301
+ interface SetResolverStateRequest {
302
+ state: Uint8Array;
303
+ accountId: string;
304
+ }
305
+ declare const SetResolverStateRequest: MessageFns<SetResolverStateRequest>;
306
+ type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
307
+ type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> } : Partial<T>;
308
+ type KeysOfUnion<T> = T extends T ? keyof T : never;
309
+ type Exact<P, I extends P> = P extends Builtin ? P : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
310
+ interface MessageFns<T> {
311
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
312
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
313
+ fromJSON(object: any): T;
314
+ toJSON(message: T): unknown;
315
+ create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;
316
+ fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;
317
+ }
318
+ //#endregion
319
+ //#region src/LocalResolver.d.ts
320
+ interface LocalResolver {
321
+ resolveWithSticky(request: ResolveWithStickyRequest): ResolveWithStickyResponse;
322
+ setResolverState(request: SetResolverStateRequest): void;
323
+ flushLogs(): Uint8Array;
324
+ flushAssigned(): Uint8Array;
325
+ }
326
+ //#endregion
327
+ //#region src/materialization.d.ts
328
+ declare namespace MaterializationStore {
329
+ namespace ReadOp {
330
+ interface Variant {
331
+ readonly op: "variant";
332
+ readonly unit: string;
333
+ readonly materialization: string;
334
+ readonly rule: string;
335
+ }
336
+ interface Inclusion {
337
+ readonly op: "inclusion";
338
+ readonly unit: string;
339
+ readonly materialization: string;
340
+ }
341
+ }
342
+ type ReadOp = ReadOp.Variant | ReadOp.Inclusion;
343
+ namespace ReadResult {
344
+ interface Variant {
345
+ readonly op: "variant";
346
+ readonly unit: string;
347
+ readonly materialization: string;
348
+ readonly rule: string;
349
+ readonly variant?: string;
350
+ }
351
+ interface Inclusion {
352
+ readonly op: "inclusion";
353
+ readonly unit: string;
354
+ readonly materialization: string;
355
+ readonly included: boolean;
356
+ }
357
+ }
358
+ type ReadResult = ReadResult.Inclusion | ReadResult.Variant;
359
+ namespace WriteOp {
360
+ interface Variant {
361
+ readonly op: "variant";
362
+ readonly unit: string;
363
+ readonly materialization: string;
364
+ readonly rule: string;
365
+ readonly variant: string;
366
+ }
367
+ }
368
+ type WriteOp = WriteOp.Variant;
369
+ }
370
+ /**
371
+ * Interface for storing and retrieving materialization data.
372
+ *
373
+ * Implementations can use any storage backend (e.g., Redis, BigTable, Cassandra, DynamoDB,
374
+ * or simple key-value stores) as long as they fulfill this contract.
375
+ *
376
+ * @see The README for conceptual documentation on sticky assignments and materialized segments.
377
+ */
378
+ interface MaterializationStore {
379
+ /**
380
+ * Reads materialization data for the given operations.
381
+ *
382
+ * For `variant` operations, returns the stored variant assignment (if any) for a unit/materialization/rule combination.
383
+ * For `inclusion` operations, returns whether a unit is included in a materialized segment.
384
+ *
385
+ * @param readOps - The read operations to perform.
386
+ * @returns Results for each operation. The order of results does not need to match the order of operations;
387
+ * callers match results to operations using the `unit`, `materialization`, and `op` fields.
388
+ */
389
+ readMaterializations(readOps: MaterializationStore.ReadOp[]): Promise<MaterializationStore.ReadResult[]>;
390
+ /**
391
+ * Persists variant assignments for sticky bucketing.
392
+ *
393
+ * This method is optional. Omit it for read-only stores that only serve pre-populated
394
+ * materialized segments without supporting runtime sticky assignment writes.
395
+ *
396
+ * @param writeOps - The variant assignments to persist.
397
+ */
398
+ writeMaterializations?(writeOps: MaterializationStore.WriteOp[]): Promise<void>;
399
+ }
400
+ //#endregion
401
+ //#region src/ConfidenceServerProviderLocal.d.ts
402
+ interface ProviderOptions {
403
+ flagClientSecret: string;
404
+ initializeTimeout?: number;
405
+ /** Interval in milliseconds between state polling updates. Defaults to 30000ms. */
406
+ stateUpdateInterval?: number;
407
+ /** Interval in milliseconds between log flushes. Defaults to 10000ms. */
408
+ flushInterval?: number;
409
+ fetch?: typeof fetch;
410
+ materializationStore?: MaterializationStore | "CONFIDENCE_REMOTE_STORE";
411
+ }
412
+ /**
413
+ * OpenFeature Provider for Confidence Server SDK (Local Mode)
414
+ * @public
415
+ */
416
+ declare class ConfidenceServerProviderLocal implements Provider {
417
+ private resolverOrPromise;
418
+ private options;
419
+ /** Static data about the provider */
420
+ readonly metadata: ProviderMetadata;
421
+ /** Current status of the provider. Can be READY, NOT_READY, ERROR, STALE and FATAL. */
422
+ status: ProviderStatus;
423
+ private readonly main;
424
+ private readonly fetch;
425
+ private readonly stateUpdateInterval;
426
+ private readonly flushInterval;
427
+ private readonly materializationStore;
428
+ private stateEtag;
429
+ private get resolver();
430
+ constructor(resolverOrPromise: LocalResolver | Promise<LocalResolver>, options: ProviderOptions);
431
+ initialize(context?: EvaluationContext): Promise<void>;
432
+ onClose(): Promise<void>;
433
+ evaluate<T>(flagKey: string, defaultValue: T, context: EvaluationContext): Promise<ResolutionDetails<T>>;
434
+ private resolveWithSticky;
435
+ /**
436
+ * Extract and validate the value from a resolved flag.
437
+ */
438
+ private extractValue;
439
+ updateState(signal?: AbortSignal): Promise<void>;
440
+ flush(signal?: AbortSignal): Promise<void>;
441
+ private flushAssigned;
442
+ private sendFlagLogs;
443
+ private readMaterializations;
444
+ private writeMaterializations;
445
+ private static convertReason;
446
+ private static convertEvaluationContext;
447
+ /** Resolves with an evaluation of a Boolean flag */
448
+ resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext): Promise<ResolutionDetails<boolean>>;
449
+ /** Resolves with an evaluation of a Numbers flag */
450
+ resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext): Promise<ResolutionDetails<number>>;
451
+ /** Resolves with an evaluation of an Object flag */
452
+ resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext): Promise<ResolutionDetails<T>>;
453
+ /** Resolves with an evaluation of a String flag */
454
+ resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
455
+ }
456
+ //#endregion
457
+ //#region src/index.fetch.d.ts
458
+ interface ProviderOptionsExt extends ProviderOptions {
459
+ wasmUrl?: URL | string;
460
+ }
461
+ declare function createConfidenceServerProvider({
462
+ wasmUrl,
463
+ ...options
464
+ }: ProviderOptionsExt): ConfidenceServerProviderLocal;
465
+ //#endregion
466
+ export { type MaterializationStore, ProviderOptionsExt, createConfidenceServerProvider };