@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 +14 -0
- package/README.md +74 -15
- package/dist/confidence_resolver.wasm +0 -0
- package/dist/index.fetch.d.ts +466 -0
- package/dist/{index.browser.js → index.fetch.js} +21 -13
- package/dist/{index.browser.d.ts → index.inlined.d.ts} +6 -4
- package/dist/index.inlined.js +2958 -0
- package/dist/index.node.d.ts +11 -4
- package/dist/index.node.js +25 -17
- package/package.json +13 -16
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
|
-
|
|
123
|
-
|
|
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 };
|