@openfeature/server-sdk 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -18
- package/dist/cjs/index.js +74 -48
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/index.js +68 -31
- package/dist/esm/index.js.map +3 -3
- package/dist/types.d.ts +77 -52
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.7.0&color=yellow&style=for-the-badge" />
|
|
17
17
|
</a>
|
|
18
18
|
<!-- x-release-please-start-version -->
|
|
19
|
-
<a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.
|
|
19
|
+
<a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.13.0">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.13.0&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -86,16 +86,17 @@ See [here](https://open-feature.github.io/js-sdk/modules/_openfeature_server_sdk
|
|
|
86
86
|
|
|
87
87
|
## 🌟 Features
|
|
88
88
|
|
|
89
|
-
| Status | Features
|
|
90
|
-
|
|
91
|
-
| ✅ | [Providers](#providers)
|
|
92
|
-
| ✅ | [Targeting](#targeting)
|
|
93
|
-
| ✅ | [Hooks](#hooks)
|
|
94
|
-
| ✅ | [Logging](#logging)
|
|
95
|
-
| ✅ | [Domains](#domains)
|
|
96
|
-
| ✅ | [Eventing](#eventing)
|
|
97
|
-
| ✅ | [Shutdown](#shutdown)
|
|
98
|
-
| ✅ | [
|
|
89
|
+
| Status | Features | Description |
|
|
90
|
+
|--------|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
91
|
+
| ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
|
|
92
|
+
| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
|
|
93
|
+
| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
|
|
94
|
+
| ✅ | [Logging](#logging) | Integrate with popular logging packages. |
|
|
95
|
+
| ✅ | [Domains](#domains) | Logically bind clients with providers. |
|
|
96
|
+
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
|
|
97
|
+
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
|
|
98
|
+
| ✅ | [Transaction Context Propagation](#transaction-context-propagation) | Set a specific [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) for a transaction (e.g. an HTTP request or a thread) | |
|
|
99
|
+
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
|
|
99
100
|
|
|
100
101
|
<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
|
|
101
102
|
|
|
@@ -113,7 +114,7 @@ To register a provider and ensure it is ready before further actions are taken,
|
|
|
113
114
|
|
|
114
115
|
```ts
|
|
115
116
|
await OpenFeature.setProviderAndWait(new MyProvider());
|
|
116
|
-
```
|
|
117
|
+
```
|
|
117
118
|
|
|
118
119
|
#### Synchronous
|
|
119
120
|
|
|
@@ -186,7 +187,7 @@ import type { Logger } from "@openfeature/server-sdk";
|
|
|
186
187
|
// The logger can be anything that conforms with the Logger interface
|
|
187
188
|
const logger: Logger = console;
|
|
188
189
|
|
|
189
|
-
// Sets a global logger
|
|
190
|
+
// Sets a global logger
|
|
190
191
|
OpenFeature.setLogger(logger);
|
|
191
192
|
|
|
192
193
|
// Sets a client logger
|
|
@@ -251,6 +252,32 @@ client.addHandler(ProviderEvents.Error, (eventDetails) => {
|
|
|
251
252
|
});
|
|
252
253
|
```
|
|
253
254
|
|
|
255
|
+
### Transaction Context Propagation
|
|
256
|
+
|
|
257
|
+
Transaction context is a container for transaction-specific evaluation context (e.g. user id, user agent, IP).
|
|
258
|
+
Transaction context can be set where specific data is available (e.g. an auth service or request handler) and by using the transaction context propagator it will automatically be applied to all flag evaluations within a transaction (e.g. a request or thread).
|
|
259
|
+
|
|
260
|
+
The following example shows an Express middleware using transaction context propagation to propagate the request ip and user id into request scoped transaction context.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import express, { Request, Response, NextFunction } from "express";
|
|
264
|
+
import { OpenFeature, AsyncLocalStorageTransactionContextPropagator } from '@openfeature/server-sdk';
|
|
265
|
+
|
|
266
|
+
OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionContextPropagator())
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* This example is based on an express middleware.
|
|
270
|
+
*/
|
|
271
|
+
const app = express();
|
|
272
|
+
app.use((req: Request, res: Response, next: NextFunction) => {
|
|
273
|
+
const ip = res.headers.get("X-Forwarded-For")
|
|
274
|
+
OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => {
|
|
275
|
+
// The transaction context is used in any flag evaluation throughout the whole call chain of next
|
|
276
|
+
next();
|
|
277
|
+
});
|
|
278
|
+
})
|
|
279
|
+
```
|
|
280
|
+
|
|
254
281
|
### Shutdown
|
|
255
282
|
|
|
256
283
|
The OpenFeature API provides a close function to perform a cleanup of all registered providers.
|
|
@@ -279,7 +306,6 @@ import {
|
|
|
279
306
|
Logger,
|
|
280
307
|
Provider,
|
|
281
308
|
ProviderEventEmitter,
|
|
282
|
-
ProviderStatus,
|
|
283
309
|
ResolutionDetails
|
|
284
310
|
} from '@openfeature/server-sdk';
|
|
285
311
|
|
|
@@ -305,10 +331,8 @@ class MyProvider implements Provider {
|
|
|
305
331
|
// code to evaluate an object
|
|
306
332
|
}
|
|
307
333
|
|
|
308
|
-
status?: ProviderStatus | undefined;
|
|
309
|
-
|
|
310
334
|
// implement with "new OpenFeatureEventEmitter()", and use "emit()" to emit events
|
|
311
|
-
events?: ProviderEventEmitter<AnyProviderEvent> | undefined;
|
|
335
|
+
events?: ProviderEventEmitter<AnyProviderEvent> | undefined;
|
|
312
336
|
|
|
313
337
|
initialize?(context?: EvaluationContext | undefined): Promise<void> {
|
|
314
338
|
// code to initialize your provider
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -18,19 +16,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
18
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
-
mod
|
|
28
|
-
));
|
|
29
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
20
|
|
|
31
21
|
// src/index.ts
|
|
32
22
|
var src_exports = {};
|
|
33
23
|
__export(src_exports, {
|
|
24
|
+
AsyncLocalStorageTransactionContextPropagator: () => AsyncLocalStorageTransactionContextPropagator,
|
|
34
25
|
InMemoryProvider: () => InMemoryProvider,
|
|
35
26
|
NOOP_PROVIDER: () => NOOP_PROVIDER,
|
|
36
27
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR: () => NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
@@ -38,23 +29,42 @@ __export(src_exports, {
|
|
|
38
29
|
OpenFeatureAPI: () => OpenFeatureAPI,
|
|
39
30
|
OpenFeatureClient: () => OpenFeatureClient,
|
|
40
31
|
OpenFeatureEventEmitter: () => OpenFeatureEventEmitter,
|
|
41
|
-
ProviderEvents: () =>
|
|
32
|
+
ProviderEvents: () => import_core2.ServerProviderEvents,
|
|
33
|
+
ProviderStatus: () => import_core3.ServerProviderStatus
|
|
42
34
|
});
|
|
43
35
|
module.exports = __toCommonJS(src_exports);
|
|
44
36
|
|
|
45
37
|
// src/client/open-feature-client.ts
|
|
46
38
|
var import_core7 = require("@openfeature/core");
|
|
47
39
|
|
|
48
|
-
// src/
|
|
40
|
+
// src/open-feature.ts
|
|
41
|
+
var import_core6 = require("@openfeature/core");
|
|
42
|
+
|
|
43
|
+
// src/events/open-feature-event-emitter.ts
|
|
49
44
|
var import_core = require("@openfeature/core");
|
|
45
|
+
var import_node_events = require("events");
|
|
46
|
+
var OpenFeatureEventEmitter = class extends import_core.GenericEventEmitter {
|
|
47
|
+
eventEmitter = new import_node_events.EventEmitter({ captureRejections: true });
|
|
48
|
+
constructor() {
|
|
49
|
+
super();
|
|
50
|
+
this.eventEmitter.on("error", (err) => {
|
|
51
|
+
this._logger?.error("Error running event handler:", err);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// src/events/events.ts
|
|
57
|
+
var import_core2 = require("@openfeature/core");
|
|
58
|
+
|
|
59
|
+
// src/provider/provider.ts
|
|
60
|
+
var import_core3 = require("@openfeature/core");
|
|
61
|
+
|
|
62
|
+
// src/provider/no-op-provider.ts
|
|
50
63
|
var REASON_NO_OP = "No-op";
|
|
51
64
|
var NoopFeatureProvider = class {
|
|
52
65
|
metadata = {
|
|
53
66
|
name: "No-op Provider"
|
|
54
67
|
};
|
|
55
|
-
get status() {
|
|
56
|
-
return import_core.ProviderStatus.NOT_READY;
|
|
57
|
-
}
|
|
58
68
|
resolveBooleanEvaluation(_, defaultValue) {
|
|
59
69
|
return this.noOp(defaultValue);
|
|
60
70
|
}
|
|
@@ -77,17 +87,17 @@ var NoopFeatureProvider = class {
|
|
|
77
87
|
var NOOP_PROVIDER = new NoopFeatureProvider();
|
|
78
88
|
|
|
79
89
|
// src/provider/in-memory-provider/in-memory-provider.ts
|
|
80
|
-
var
|
|
90
|
+
var import_core5 = require("@openfeature/core");
|
|
81
91
|
|
|
82
92
|
// src/provider/in-memory-provider/variant-not-found-error.ts
|
|
83
|
-
var
|
|
84
|
-
var VariantFoundError = class _VariantFoundError extends
|
|
93
|
+
var import_core4 = require("@openfeature/core");
|
|
94
|
+
var VariantFoundError = class _VariantFoundError extends import_core4.OpenFeatureError {
|
|
85
95
|
code;
|
|
86
96
|
constructor(message) {
|
|
87
97
|
super(message);
|
|
88
98
|
Object.setPrototypeOf(this, _VariantFoundError.prototype);
|
|
89
99
|
this.name = "VariantFoundError";
|
|
90
|
-
this.code =
|
|
100
|
+
this.code = import_core4.ErrorCode.GENERAL;
|
|
91
101
|
}
|
|
92
102
|
};
|
|
93
103
|
|
|
@@ -109,7 +119,7 @@ var InMemoryProvider = class {
|
|
|
109
119
|
putConfiguration(flagConfiguration) {
|
|
110
120
|
const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
|
|
111
121
|
this._flagConfiguration = { ...flagConfiguration };
|
|
112
|
-
this.events.emit(
|
|
122
|
+
this.events.emit(import_core2.ServerProviderEvents.ConfigurationChanged, { flagsChanged });
|
|
113
123
|
}
|
|
114
124
|
resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
|
|
115
125
|
return this.resolveFlagWithReason(flagKey, defaultValue, context, logger);
|
|
@@ -127,12 +137,12 @@ var InMemoryProvider = class {
|
|
|
127
137
|
try {
|
|
128
138
|
const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);
|
|
129
139
|
if (typeof resolutionResult?.value != typeof defaultValue) {
|
|
130
|
-
throw new
|
|
140
|
+
throw new import_core5.TypeMismatchError();
|
|
131
141
|
}
|
|
132
142
|
return resolutionResult;
|
|
133
143
|
} catch (error) {
|
|
134
|
-
if (!(error instanceof
|
|
135
|
-
throw new
|
|
144
|
+
if (!(error instanceof import_core5.OpenFeatureError)) {
|
|
145
|
+
throw new import_core5.GeneralError(error?.message || "unknown error");
|
|
136
146
|
}
|
|
137
147
|
throw error;
|
|
138
148
|
}
|
|
@@ -141,11 +151,11 @@ var InMemoryProvider = class {
|
|
|
141
151
|
if (!(flagKey in this._flagConfiguration)) {
|
|
142
152
|
const message = `no flag found with key ${flagKey}`;
|
|
143
153
|
logger?.debug(message);
|
|
144
|
-
throw new
|
|
154
|
+
throw new import_core5.FlagNotFoundError(message);
|
|
145
155
|
}
|
|
146
156
|
const flagSpec = this._flagConfiguration[flagKey];
|
|
147
157
|
if (flagSpec.disabled) {
|
|
148
|
-
return { value: defaultValue, reason:
|
|
158
|
+
return { value: defaultValue, reason: import_core5.StandardResolutionReasons.DISABLED };
|
|
149
159
|
}
|
|
150
160
|
const isContextEval = ctx && flagSpec?.contextEvaluator;
|
|
151
161
|
const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;
|
|
@@ -158,47 +168,42 @@ var InMemoryProvider = class {
|
|
|
158
168
|
return {
|
|
159
169
|
value,
|
|
160
170
|
...variant && { variant },
|
|
161
|
-
reason: isContextEval ?
|
|
171
|
+
reason: isContextEval ? import_core5.StandardResolutionReasons.TARGETING_MATCH : import_core5.StandardResolutionReasons.STATIC
|
|
162
172
|
};
|
|
163
173
|
}
|
|
164
174
|
};
|
|
165
175
|
|
|
166
|
-
// src/open-feature.ts
|
|
167
|
-
var import_core6 = require("@openfeature/core");
|
|
168
|
-
|
|
169
176
|
// src/transaction-context/no-op-transaction-context-propagator.ts
|
|
170
177
|
var NoopTransactionContextPropagator = class {
|
|
171
178
|
getTransactionContext() {
|
|
172
179
|
return {};
|
|
173
180
|
}
|
|
174
|
-
setTransactionContext(_, callback) {
|
|
175
|
-
callback();
|
|
181
|
+
setTransactionContext(_, callback, ...args) {
|
|
182
|
+
callback(...args);
|
|
176
183
|
}
|
|
177
184
|
};
|
|
178
185
|
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
|
|
179
186
|
|
|
180
|
-
// src/
|
|
181
|
-
var
|
|
182
|
-
var
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
});
|
|
187
|
+
// src/transaction-context/async-local-storage-transaction-context-propagator.ts
|
|
188
|
+
var import_async_hooks = require("async_hooks");
|
|
189
|
+
var AsyncLocalStorageTransactionContextPropagator = class {
|
|
190
|
+
asyncLocalStorage = new import_async_hooks.AsyncLocalStorage();
|
|
191
|
+
getTransactionContext() {
|
|
192
|
+
return this.asyncLocalStorage.getStore() ?? {};
|
|
193
|
+
}
|
|
194
|
+
setTransactionContext(transactionContext, callback, ...args) {
|
|
195
|
+
this.asyncLocalStorage.run(transactionContext, callback, ...args);
|
|
190
196
|
}
|
|
191
197
|
};
|
|
192
198
|
|
|
193
|
-
// src/events/events.ts
|
|
194
|
-
var import_core5 = require("@openfeature/core");
|
|
195
|
-
|
|
196
199
|
// src/open-feature.ts
|
|
197
200
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api");
|
|
198
201
|
var _globalThis = globalThis;
|
|
199
202
|
var OpenFeatureAPI = class _OpenFeatureAPI extends import_core6.OpenFeatureCommonAPI {
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
_statusEnumType = import_core3.ServerProviderStatus;
|
|
204
|
+
_apiEmitter = new OpenFeatureEventEmitter();
|
|
205
|
+
_defaultProvider = new import_core6.ProviderWrapper(NOOP_PROVIDER, import_core3.ServerProviderStatus.NOT_READY, this._statusEnumType);
|
|
206
|
+
_domainScopedProviders = /* @__PURE__ */ new Map();
|
|
202
207
|
_createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
203
208
|
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
|
|
204
209
|
constructor() {
|
|
@@ -218,6 +223,12 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core6.OpenFeatureCommo
|
|
|
218
223
|
_globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
|
|
219
224
|
return instance;
|
|
220
225
|
}
|
|
226
|
+
getProviderStatus(domain) {
|
|
227
|
+
if (!domain) {
|
|
228
|
+
return this._defaultProvider.status;
|
|
229
|
+
}
|
|
230
|
+
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;
|
|
231
|
+
}
|
|
221
232
|
setContext(context) {
|
|
222
233
|
this._context = context;
|
|
223
234
|
return this;
|
|
@@ -231,6 +242,7 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core6.OpenFeatureCommo
|
|
|
231
242
|
const context = (0, import_core6.objectOrUndefined)(domainOrContext) ?? (0, import_core6.objectOrUndefined)(versionOrContext) ?? (0, import_core6.objectOrUndefined)(contextOrUndefined);
|
|
232
243
|
return new OpenFeatureClient(
|
|
233
244
|
() => this.getProviderForClient(domain),
|
|
245
|
+
() => this.getProviderStatus(domain),
|
|
234
246
|
() => this.buildAndCacheEventEmitterForClient(domain),
|
|
235
247
|
() => this._logger,
|
|
236
248
|
{ domain, version },
|
|
@@ -273,8 +285,9 @@ var OpenFeature = OpenFeatureAPI.getInstance();
|
|
|
273
285
|
|
|
274
286
|
// src/client/open-feature-client.ts
|
|
275
287
|
var OpenFeatureClient = class {
|
|
276
|
-
constructor(providerAccessor, emitterAccessor, globalLogger, options, context = {}) {
|
|
288
|
+
constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options, context = {}) {
|
|
277
289
|
this.providerAccessor = providerAccessor;
|
|
290
|
+
this.providerStatusAccessor = providerStatusAccessor;
|
|
278
291
|
this.emitterAccessor = emitterAccessor;
|
|
279
292
|
this.globalLogger = globalLogger;
|
|
280
293
|
this.options = options;
|
|
@@ -292,9 +305,12 @@ var OpenFeatureClient = class {
|
|
|
292
305
|
providerMetadata: this.providerAccessor().metadata
|
|
293
306
|
};
|
|
294
307
|
}
|
|
308
|
+
get providerStatus() {
|
|
309
|
+
return this.providerStatusAccessor();
|
|
310
|
+
}
|
|
295
311
|
addHandler(eventType, handler) {
|
|
296
312
|
this.emitterAccessor().addHandler(eventType, handler);
|
|
297
|
-
const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this.
|
|
313
|
+
const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._providerStatus);
|
|
298
314
|
if (shouldRunNow) {
|
|
299
315
|
try {
|
|
300
316
|
handler({
|
|
@@ -407,6 +423,11 @@ var OpenFeatureClient = class {
|
|
|
407
423
|
};
|
|
408
424
|
try {
|
|
409
425
|
const frozenContext = await this.beforeHooks(allHooks, hookContext, options);
|
|
426
|
+
if (this.providerStatus === import_core3.ServerProviderStatus.NOT_READY) {
|
|
427
|
+
throw new import_core7.ProviderNotReadyError("provider has not yet initialized");
|
|
428
|
+
} else if (this.providerStatus === import_core3.ServerProviderStatus.FATAL) {
|
|
429
|
+
throw new import_core7.ProviderFatalError("provider is in an irrecoverable error state");
|
|
430
|
+
}
|
|
410
431
|
const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);
|
|
411
432
|
const evaluationDetails = {
|
|
412
433
|
...resolution,
|
|
@@ -475,6 +496,9 @@ var OpenFeatureClient = class {
|
|
|
475
496
|
get _provider() {
|
|
476
497
|
return this.providerAccessor();
|
|
477
498
|
}
|
|
499
|
+
get _providerStatus() {
|
|
500
|
+
return this.providerStatusAccessor();
|
|
501
|
+
}
|
|
478
502
|
get _logger() {
|
|
479
503
|
return this._clientLogger || this.globalLogger();
|
|
480
504
|
}
|
|
@@ -484,6 +508,7 @@ var OpenFeatureClient = class {
|
|
|
484
508
|
__reExport(src_exports, require("@openfeature/core"), module.exports);
|
|
485
509
|
// Annotate the CommonJS export names for ESM import in node:
|
|
486
510
|
0 && (module.exports = {
|
|
511
|
+
AsyncLocalStorageTransactionContextPropagator,
|
|
487
512
|
InMemoryProvider,
|
|
488
513
|
NOOP_PROVIDER,
|
|
489
514
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
@@ -492,6 +517,7 @@ __reExport(src_exports, require("@openfeature/core"), module.exports);
|
|
|
492
517
|
OpenFeatureClient,
|
|
493
518
|
OpenFeatureEventEmitter,
|
|
494
519
|
ProviderEvents,
|
|
520
|
+
ProviderStatus,
|
|
495
521
|
...require("@openfeature/core")
|
|
496
522
|
});
|
|
497
523
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/index.ts", "../../src/client/open-feature-client.ts", "../../src/provider/no-op-provider.ts", "../../src/provider/in-memory-provider/in-memory-provider.ts", "../../src/provider/in-memory-provider/variant-not-found-error.ts", "../../src/
|
|
4
|
-
"sourcesContent": ["export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from './events';\nexport * from './hooks';\nexport * from '@openfeature/core';\n", "import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent,\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { ProviderEvents } from '../events';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\nimport { Hook } from '../hooks';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n /**\n * @deprecated Use `domain` instead.\n */\n name?: string;\n domain?: string;\n version?: string;\n};\n\nexport class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> {\n private _context: EvaluationContext;\n private _hooks: Hook[] = [];\n private _clientLogger?: Logger;\n\n constructor(\n // we always want the client to use the current provider,\n // so pass a function to always access the currently registered one.\n private readonly providerAccessor: () => Provider,\n private readonly emitterAccessor: () => InternalEventEmitter,\n private readonly globalLogger: () => Logger,\n private readonly options: OpenFeatureClientOptions,\n context: EvaluationContext = {},\n ) {\n this._context = context;\n }\n\n get metadata(): ClientMetadata {\n return {\n // Use domain if name is not provided\n name: this.options.domain ?? this.options.name,\n domain: this.options.domain ?? this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler(eventType: ProviderEvents, handler: EventHandler): void {\n this.emitterAccessor().addHandler(eventType, handler);\n const shouldRunNow = statusMatchesEvent(eventType, this._provider.status);\n\n if (shouldRunNow) {\n // run immediately, we're in the matching state\n try {\n handler({\n clientName: this.metadata.name,\n domain: this.metadata.domain,\n providerName: this._provider.metadata.name,\n });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler(eventType: ProviderEvents, handler: EventHandler) {\n this.emitterAccessor().removeHandler(eventType, handler);\n }\n\n getHandlers(eventType: ProviderEvents) {\n return this.emitterAccessor().getHandlers(eventType);\n }\n\n setLogger(logger: Logger): OpenFeatureClient {\n this._clientLogger = new SafeLogger(logger);\n return this;\n }\n\n setContext(context: EvaluationContext): OpenFeatureClient {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n addHooks(...hooks: Hook[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook[] {\n return this._hooks;\n }\n\n clearHooks(): OpenFeatureClient {\n this._hooks = [];\n return this;\n }\n\n async getBooleanValue(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<boolean> {\n return (await this.getBooleanDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getBooleanDetails(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<boolean>> {\n return this.evaluate<boolean>(\n flagKey,\n this._provider.resolveBooleanEvaluation,\n defaultValue,\n 'boolean',\n context,\n options,\n );\n }\n\n async getStringValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getStringDetails<T>(flagKey, defaultValue, context, options)).value;\n }\n\n getStringDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted string generic argument.\n this._provider.resolveStringEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'string',\n context,\n options,\n );\n }\n\n async getNumberValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getNumberDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getNumberDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted number generic argument.\n this._provider.resolveNumberEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'number',\n context,\n options,\n );\n }\n\n async getObjectValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getObjectDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getObjectDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(flagKey, this._provider.resolveObjectEvaluation, defaultValue, 'object', context, options);\n }\n\n private async evaluate<T extends FlagValue>(\n flagKey: string,\n resolver: (\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ) => Promise<ResolutionDetails<T>>,\n defaultValue: T,\n flagType: FlagValueType,\n invocationContext: EvaluationContext = {},\n options: FlagEvaluationOptions = {},\n ): Promise<EvaluationDetails<T>> {\n // merge global, client, and evaluation context\n\n const allHooks = [\n ...OpenFeature.getHooks(),\n ...this.getHooks(),\n ...(options.hooks || []),\n ...(this._provider.hooks || []),\n ];\n const allHooksReversed = [...allHooks].reverse();\n\n // merge global and client contexts\n const mergedContext = {\n ...OpenFeature.getContext(),\n ...OpenFeature.getTransactionContext(),\n ...this._context,\n ...invocationContext,\n };\n\n // this reference cannot change during the course of evaluation\n // it may be used as a key in WeakMaps\n const hookContext: Readonly<HookContext> = {\n flagKey,\n defaultValue,\n flagValueType: flagType,\n clientMetadata: this.metadata,\n providerMetadata: OpenFeature.providerMetadata,\n context: mergedContext,\n logger: this._logger,\n };\n\n try {\n const frozenContext = await this.beforeHooks(allHooks, hookContext, options);\n\n // run the referenced resolver, binding the provider.\n const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);\n\n const evaluationDetails = {\n ...resolution,\n flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),\n flagKey,\n };\n\n await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);\n\n return evaluationDetails;\n } catch (err: unknown) {\n const errorMessage: string = (err as Error)?.message;\n const errorCode: ErrorCode = (err as OpenFeatureError)?.code || ErrorCode.GENERAL;\n\n await this.errorHooks(allHooksReversed, hookContext, err, options);\n\n return {\n errorCode,\n errorMessage,\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n flagMetadata: Object.freeze({}),\n flagKey,\n };\n } finally {\n await this.finallyHooks(allHooksReversed, hookContext, options);\n }\n }\n\n private async beforeHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n for (const hook of hooks) {\n // freeze the hookContext\n Object.freeze(hookContext);\n\n // use Object.assign to avoid modification of frozen hookContext\n Object.assign(hookContext.context, {\n ...hookContext.context,\n ...(await hook?.before?.(hookContext, Object.freeze(options.hookHints))),\n });\n }\n\n // after before hooks, freeze the EvaluationContext.\n return Object.freeze(hookContext.context);\n }\n\n private async afterHooks(\n hooks: Hook[],\n hookContext: HookContext,\n evaluationDetails: EvaluationDetails<FlagValue>,\n options: FlagEvaluationOptions,\n ) {\n // run \"after\" hooks sequentially\n for (const hook of hooks) {\n await hook?.after?.(hookContext, evaluationDetails, options.hookHints);\n }\n }\n\n private async errorHooks(hooks: Hook[], hookContext: HookContext, err: unknown, options: FlagEvaluationOptions) {\n // run \"error\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.error?.(hookContext, err, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'error' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private async finallyHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n // run \"finally\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.finally?.(hookContext, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'finally' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private get _provider(): Provider {\n return this.providerAccessor();\n }\n\n private get _logger() {\n return this._clientLogger || this.globalLogger();\n }\n}\n", "import { ResolutionDetails, JsonValue, ProviderStatus } from '@openfeature/core';\nimport { Provider } from './provider';\n\nconst REASON_NO_OP = 'No-op';\n\n/**\n * The No-op provider is set by default, and simply always returns the default value.\n */\nclass NoopFeatureProvider implements Provider {\n readonly metadata = {\n name: 'No-op Provider',\n } as const;\n\n get status(): ProviderStatus {\n /**\n * This is due to the NoopProvider not being a real provider.\n * We do not want it to trigger the Ready event handlers, so we never set this to ready.\n * With the NoopProvider assigned, the client can be assumed to be uninitialized.\n * https://github.com/open-feature/js-sdk/pull/429#discussion_r1202642654\n */\n return ProviderStatus.NOT_READY;\n }\n\n resolveBooleanEvaluation(_: string, defaultValue: boolean): Promise<ResolutionDetails<boolean>> {\n return this.noOp(defaultValue);\n }\n\n resolveStringEvaluation(_: string, defaultValue: string): Promise<ResolutionDetails<string>> {\n return this.noOp(defaultValue);\n }\n\n resolveNumberEvaluation(_: string, defaultValue: number): Promise<ResolutionDetails<number>> {\n return this.noOp(defaultValue);\n }\n\n resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): Promise<ResolutionDetails<T>> {\n return this.noOp<T>(defaultValue);\n }\n\n private noOp<T>(defaultValue: T) {\n return Promise.resolve({\n value: defaultValue,\n reason: REASON_NO_OP,\n });\n }\n}\n\nexport const NOOP_PROVIDER = new NoopFeatureProvider();\n", "import {\n EvaluationContext,\n FlagNotFoundError,\n FlagValueType,\n GeneralError,\n JsonValue,\n Logger,\n OpenFeatureError,\n ResolutionDetails,\n StandardResolutionReasons,\n TypeMismatchError\n} from '@openfeature/core';\nimport { Provider } from '../provider';\nimport { Flag, FlagConfiguration } from './flag-configuration';\nimport { VariantFoundError } from './variant-not-found-error';\nimport { OpenFeatureEventEmitter, ProviderEvents } from '../..';\n\n/**\n * A simple OpenFeature provider intended for demos and as a test stub.\n */\nexport class InMemoryProvider implements Provider {\n public readonly events = new OpenFeatureEventEmitter();\n public readonly runsOn = 'server';\n readonly metadata = {\n name: 'in-memory',\n } as const;\n private _flagConfiguration: FlagConfiguration;\n\n constructor(flagConfiguration: FlagConfiguration = {}) {\n this._flagConfiguration = { ...flagConfiguration };\n }\n\n /**\n * Overwrites the configured flags.\n * @param { FlagConfiguration } flagConfiguration new flag configuration\n */\n putConfiguration(flagConfiguration: FlagConfiguration) {\n const flagsChanged = Object.entries(flagConfiguration)\n .filter(([key, value]) => this._flagConfiguration[key] !== value)\n .map(([key]) => key);\n\n this._flagConfiguration = { ...flagConfiguration };\n this.events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });\n }\n\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<boolean>> {\n return this.resolveFlagWithReason<boolean>(flagKey, defaultValue, context, logger);\n }\n\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<number>> {\n return this.resolveFlagWithReason<number>(flagKey, defaultValue, context, logger);\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<string>> {\n return this.resolveFlagWithReason<string>(flagKey, defaultValue, context, logger);\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n return this.resolveFlagWithReason<T>(flagKey, defaultValue, context, logger);\n }\n\n private async resolveFlagWithReason<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n try {\n const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);\n\n if (typeof resolutionResult?.value != typeof defaultValue) {\n throw new TypeMismatchError();\n }\n\n return resolutionResult;\n } catch (error: unknown) {\n if (!(error instanceof OpenFeatureError)) {\n throw new GeneralError((error as Error)?.message || 'unknown error'); \n }\n throw error;\n }\n }\n\n private lookupFlagValue<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): ResolutionDetails<T> {\n if (!(flagKey in this._flagConfiguration)) {\n const message = `no flag found with key ${flagKey}`;\n logger?.debug(message);\n throw new FlagNotFoundError(message);\n }\n const flagSpec: Flag = this._flagConfiguration[flagKey];\n\n if (flagSpec.disabled) {\n return { value: defaultValue, reason: StandardResolutionReasons.DISABLED };\n }\n\n const isContextEval = ctx && flagSpec?.contextEvaluator;\n const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;\n\n const value = variant && flagSpec?.variants[variant];\n\n if (value === undefined) {\n const message = `no value associated with variant ${variant}`;\n logger?.error(message);\n throw new VariantFoundError(message);\n }\n\n return {\n value: value as T,\n ...(variant && { variant }),\n reason: isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC,\n };\n }\n}\n", "import { ErrorCode, OpenFeatureError } from '@openfeature/core';\n\n/**\n * A custom error for the in-memory provider.\n * Indicates the resolved or default variant doesn't exist.\n */\nexport class VariantFoundError extends OpenFeatureError {\n code: ErrorCode;\n constructor(message?: string) {\n super(message);\n Object.setPrototypeOf(this, VariantFoundError.prototype);\n this.name = 'VariantFoundError';\n this.code = ErrorCode.GENERAL;\n }\n}\n", "import { NOOP_PROVIDER, Provider } from './provider';\nimport {\n ManageContext,\n OpenFeatureCommonAPI,\n EvaluationContext,\n objectOrUndefined,\n stringOrUndefined,\n} from '@openfeature/core';\nimport {\n ManageTransactionContextPropagator,\n NOOP_TRANSACTION_CONTEXT_PROPAGATOR,\n TransactionContext,\n TransactionContextPropagator,\n} from './transaction-context';\nimport { Client, OpenFeatureClient } from './client';\nimport { OpenFeatureEventEmitter } from './events';\nimport { Hook } from './hooks';\n\n// use a symbol as a key for the global singleton\nconst GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/js-sdk/api');\n\ntype OpenFeatureGlobal = {\n [GLOBAL_OPENFEATURE_API_KEY]?: OpenFeatureAPI;\n};\nconst _globalThis = globalThis as OpenFeatureGlobal;\n\nexport class OpenFeatureAPI\n extends OpenFeatureCommonAPI<Provider, Hook>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<Provider>>\n{\n protected _events = new OpenFeatureEventEmitter();\n protected _defaultProvider: Provider = NOOP_PROVIDER;\n protected _createEventEmitter = () => new OpenFeatureEventEmitter();\n\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n\n private constructor() {\n super('server');\n }\n\n /**\n * Gets a singleton instance of the OpenFeature API.\n * @ignore\n * @returns {OpenFeatureAPI} OpenFeature API\n */\n static getInstance(): OpenFeatureAPI {\n const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];\n if (globalApi) {\n return globalApi;\n }\n\n const instance = new OpenFeatureAPI();\n _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;\n return instance;\n }\n\n setContext(context: EvaluationContext): this {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n /**\n * A factory function for creating new domainless OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * All domainless or unbound clients use the default provider set via {@link this.setProvider setProvider}.\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {string} version The version of the client (only used for metadata)\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, version: string, context?: EvaluationContext): Client;\n getClient(\n domainOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext,\n ): Client {\n const domain = stringOrUndefined(domainOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(domainOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(domain),\n () => this.buildAndCacheEventEmitterForClient(domain),\n () => this._logger,\n { domain, version },\n context,\n );\n }\n\n /**\n * Clears all registered providers and resets the default provider.\n * @returns {Promise<void>}\n */\n clearProviders(): Promise<void> {\n return super.clearProvidersAndSetDefault(NOOP_PROVIDER);\n }\n\n setTransactionContextPropagator(\n transactionContextPropagator: TransactionContextPropagator,\n ): OpenFeatureCommonAPI<Provider> {\n const baseMessage = 'Invalid TransactionContextPropagator, will not be set: ';\n if (typeof transactionContextPropagator?.getTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: getTransactionContext is not a function.`);\n } else if (typeof transactionContextPropagator?.setTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: setTransactionContext is not a function.`);\n } else {\n this._transactionContextPropagator = transactionContextPropagator;\n }\n return this;\n }\n\n setTransactionContext<R>(\n transactionContext: TransactionContext,\n callback: (...args: unknown[]) => R,\n ...args: unknown[]\n ): void {\n this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args);\n }\n\n getTransactionContext(): TransactionContext {\n try {\n return this._transactionContextPropagator.getTransactionContext();\n } catch (err: unknown) {\n const error = err as Error | undefined;\n this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`);\n this._logger.error(error?.stack);\n return {};\n }\n }\n}\n\n/**\n * A singleton instance of the OpenFeature API.\n * @returns {OpenFeatureAPI} OpenFeature API\n */\nexport const OpenFeature = OpenFeatureAPI.getInstance();\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContextPropagator } from './transaction-context';\n\nclass NoopTransactionContextPropagator implements TransactionContextPropagator {\n getTransactionContext(): EvaluationContext {\n return {};\n }\n\n setTransactionContext(_: EvaluationContext, callback: () => void): void {\n callback();\n }\n}\n\nexport const NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();\n", "import { GenericEventEmitter } from '@openfeature/core';\nimport EventEmitter from 'events';\nimport { ProviderEvents } from './events';\n\n/**\n * The OpenFeatureEventEmitter can be used by provider developers to emit\n * events at various parts of the provider lifecycle.\n * \n * NOTE: Ready and error events are automatically emitted by the SDK based on\n * the result of the initialize method.\n */\nexport class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEvents> {\n protected readonly eventEmitter = new EventEmitter({ captureRejections: true });\n\n constructor() {\n super();\n this.eventEmitter.on('error', (err) => {\n this._logger?.error('Error running event handler:', err);\n });\n }\n};", "import { ServerProviderEvents } from '@openfeature/core';\n\nexport { ServerProviderEvents as ProviderEvents };"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["import_core", "import_core", "import_core", "import_core", "import_core", "
|
|
3
|
+
"sources": ["../../src/index.ts", "../../src/client/open-feature-client.ts", "../../src/open-feature.ts", "../../src/events/open-feature-event-emitter.ts", "../../src/events/events.ts", "../../src/provider/provider.ts", "../../src/provider/no-op-provider.ts", "../../src/provider/in-memory-provider/in-memory-provider.ts", "../../src/provider/in-memory-provider/variant-not-found-error.ts", "../../src/transaction-context/no-op-transaction-context-propagator.ts", "../../src/transaction-context/async-local-storage-transaction-context-propagator.ts"],
|
|
4
|
+
"sourcesContent": ["export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from './events';\nexport * from './hooks';\nexport * from '@openfeature/core';\n", "import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderFatalError,\n ProviderNotReadyError,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent,\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { ProviderEvents } from '../events';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\nimport { Hook } from '../hooks';\nimport { OpenFeature } from '../open-feature';\nimport { Provider, ProviderStatus } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n /**\n * @deprecated Use `domain` instead.\n */\n name?: string;\n domain?: string;\n version?: string;\n};\n\nexport class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> {\n private _context: EvaluationContext;\n private _hooks: Hook[] = [];\n private _clientLogger?: Logger;\n\n constructor(\n // we always want the client to use the current provider,\n // so pass a function to always access the currently registered one.\n private readonly providerAccessor: () => Provider,\n private readonly providerStatusAccessor: () => ProviderStatus,\n private readonly emitterAccessor: () => InternalEventEmitter,\n private readonly globalLogger: () => Logger,\n private readonly options: OpenFeatureClientOptions,\n context: EvaluationContext = {},\n ) {\n this._context = context;\n }\n\n get metadata(): ClientMetadata {\n return {\n // Use domain if name is not provided\n name: this.options.domain ?? this.options.name,\n domain: this.options.domain ?? this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n get providerStatus(): ProviderStatus {\n return this.providerStatusAccessor();\n }\n\n addHandler(eventType: ProviderEvents, handler: EventHandler): void {\n this.emitterAccessor().addHandler(eventType, handler);\n const shouldRunNow = statusMatchesEvent(eventType, this._providerStatus);\n\n if (shouldRunNow) {\n // run immediately, we're in the matching state\n try {\n handler({\n clientName: this.metadata.name,\n domain: this.metadata.domain,\n providerName: this._provider.metadata.name,\n });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler(eventType: ProviderEvents, handler: EventHandler) {\n this.emitterAccessor().removeHandler(eventType, handler);\n }\n\n getHandlers(eventType: ProviderEvents) {\n return this.emitterAccessor().getHandlers(eventType);\n }\n\n setLogger(logger: Logger): OpenFeatureClient {\n this._clientLogger = new SafeLogger(logger);\n return this;\n }\n\n setContext(context: EvaluationContext): OpenFeatureClient {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n addHooks(...hooks: Hook[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook[] {\n return this._hooks;\n }\n\n clearHooks(): OpenFeatureClient {\n this._hooks = [];\n return this;\n }\n\n async getBooleanValue(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<boolean> {\n return (await this.getBooleanDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getBooleanDetails(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<boolean>> {\n return this.evaluate<boolean>(\n flagKey,\n this._provider.resolveBooleanEvaluation,\n defaultValue,\n 'boolean',\n context,\n options,\n );\n }\n\n async getStringValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getStringDetails<T>(flagKey, defaultValue, context, options)).value;\n }\n\n getStringDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted string generic argument.\n this._provider.resolveStringEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'string',\n context,\n options,\n );\n }\n\n async getNumberValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getNumberDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getNumberDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted number generic argument.\n this._provider.resolveNumberEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'number',\n context,\n options,\n );\n }\n\n async getObjectValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getObjectDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getObjectDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(flagKey, this._provider.resolveObjectEvaluation, defaultValue, 'object', context, options);\n }\n\n private async evaluate<T extends FlagValue>(\n flagKey: string,\n resolver: (\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ) => Promise<ResolutionDetails<T>>,\n defaultValue: T,\n flagType: FlagValueType,\n invocationContext: EvaluationContext = {},\n options: FlagEvaluationOptions = {},\n ): Promise<EvaluationDetails<T>> {\n // merge global, client, and evaluation context\n\n const allHooks = [\n ...OpenFeature.getHooks(),\n ...this.getHooks(),\n ...(options.hooks || []),\n ...(this._provider.hooks || []),\n ];\n const allHooksReversed = [...allHooks].reverse();\n\n // merge global and client contexts\n const mergedContext = {\n ...OpenFeature.getContext(),\n ...OpenFeature.getTransactionContext(),\n ...this._context,\n ...invocationContext,\n };\n\n // this reference cannot change during the course of evaluation\n // it may be used as a key in WeakMaps\n const hookContext: Readonly<HookContext> = {\n flagKey,\n defaultValue,\n flagValueType: flagType,\n clientMetadata: this.metadata,\n providerMetadata: OpenFeature.providerMetadata,\n context: mergedContext,\n logger: this._logger,\n };\n\n try {\n const frozenContext = await this.beforeHooks(allHooks, hookContext, options);\n\n // short circuit evaluation entirely if provider is in a bad state\n if (this.providerStatus === ProviderStatus.NOT_READY) {\n throw new ProviderNotReadyError('provider has not yet initialized');\n } else if (this.providerStatus === ProviderStatus.FATAL) {\n throw new ProviderFatalError('provider is in an irrecoverable error state');\n }\n\n // run the referenced resolver, binding the provider.\n const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);\n\n const evaluationDetails = {\n ...resolution,\n flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),\n flagKey,\n };\n\n await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);\n\n return evaluationDetails;\n } catch (err: unknown) {\n const errorMessage: string = (err as Error)?.message;\n const errorCode: ErrorCode = (err as OpenFeatureError)?.code || ErrorCode.GENERAL;\n\n await this.errorHooks(allHooksReversed, hookContext, err, options);\n\n return {\n errorCode,\n errorMessage,\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n flagMetadata: Object.freeze({}),\n flagKey,\n };\n } finally {\n await this.finallyHooks(allHooksReversed, hookContext, options);\n }\n }\n\n private async beforeHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n for (const hook of hooks) {\n // freeze the hookContext\n Object.freeze(hookContext);\n\n // use Object.assign to avoid modification of frozen hookContext\n Object.assign(hookContext.context, {\n ...hookContext.context,\n ...(await hook?.before?.(hookContext, Object.freeze(options.hookHints))),\n });\n }\n\n // after before hooks, freeze the EvaluationContext.\n return Object.freeze(hookContext.context);\n }\n\n private async afterHooks(\n hooks: Hook[],\n hookContext: HookContext,\n evaluationDetails: EvaluationDetails<FlagValue>,\n options: FlagEvaluationOptions,\n ) {\n // run \"after\" hooks sequentially\n for (const hook of hooks) {\n await hook?.after?.(hookContext, evaluationDetails, options.hookHints);\n }\n }\n\n private async errorHooks(hooks: Hook[], hookContext: HookContext, err: unknown, options: FlagEvaluationOptions) {\n // run \"error\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.error?.(hookContext, err, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'error' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private async finallyHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n // run \"finally\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.finally?.(hookContext, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'finally' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private get _provider(): Provider {\n return this.providerAccessor();\n }\n\n private get _providerStatus(): ProviderStatus {\n return this.providerStatusAccessor();\n }\n\n private get _logger() {\n return this._clientLogger || this.globalLogger();\n }\n}\n", "import {\n EvaluationContext,\n ManageContext,\n OpenFeatureCommonAPI,\n ProviderWrapper,\n objectOrUndefined,\n stringOrUndefined,\n} from '@openfeature/core';\nimport { Client, OpenFeatureClient } from './client';\nimport { OpenFeatureEventEmitter } from './events';\nimport { Hook } from './hooks';\nimport { NOOP_PROVIDER, Provider, ProviderStatus } from './provider';\nimport {\n ManageTransactionContextPropagator,\n NOOP_TRANSACTION_CONTEXT_PROPAGATOR,\n TransactionContext,\n TransactionContextPropagator,\n} from './transaction-context';\nimport { ServerProviderStatus } from '@openfeature/core';\n\n// use a symbol as a key for the global singleton\nconst GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/js-sdk/api');\n\ntype OpenFeatureGlobal = {\n [GLOBAL_OPENFEATURE_API_KEY]?: OpenFeatureAPI;\n};\nconst _globalThis = globalThis as OpenFeatureGlobal;\n\nexport class OpenFeatureAPI\n extends OpenFeatureCommonAPI<ServerProviderStatus, Provider, Hook>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<ServerProviderStatus, Provider>>\n{\n protected _statusEnumType: typeof ProviderStatus = ProviderStatus;\n protected _apiEmitter = new OpenFeatureEventEmitter();\n protected _defaultProvider: ProviderWrapper<Provider, ServerProviderStatus> = new ProviderWrapper(NOOP_PROVIDER, ProviderStatus.NOT_READY, this._statusEnumType);\n protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ServerProviderStatus>> = new Map();\n protected _createEventEmitter = () => new OpenFeatureEventEmitter();\n\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n\n private constructor() {\n super('server');\n }\n\n /**\n * Gets a singleton instance of the OpenFeature API.\n * @ignore\n * @returns {OpenFeatureAPI} OpenFeature API\n */\n static getInstance(): OpenFeatureAPI {\n const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];\n if (globalApi) {\n return globalApi;\n }\n\n const instance = new OpenFeatureAPI();\n _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;\n return instance;\n }\n\n private getProviderStatus(domain?: string): ProviderStatus {\n if (!domain) {\n return this._defaultProvider.status;\n }\n\n return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;\n }\n\n setContext(context: EvaluationContext): this {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n /**\n * A factory function for creating new domainless OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * All domainless or unbound clients use the default provider set via {@link this.setProvider setProvider}.\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {string} version The version of the client (only used for metadata)\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, version: string, context?: EvaluationContext): Client;\n getClient(\n domainOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext,\n ): Client {\n const domain = stringOrUndefined(domainOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(domainOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(domain),\n () => this.getProviderStatus(domain),\n () => this.buildAndCacheEventEmitterForClient(domain),\n () => this._logger,\n { domain, version },\n context,\n );\n }\n\n /**\n * Clears all registered providers and resets the default provider.\n * @returns {Promise<void>}\n */\n clearProviders(): Promise<void> {\n return super.clearProvidersAndSetDefault(NOOP_PROVIDER);\n }\n\n setTransactionContextPropagator(\n transactionContextPropagator: TransactionContextPropagator,\n ): OpenFeatureCommonAPI<ServerProviderStatus, Provider> {\n const baseMessage = 'Invalid TransactionContextPropagator, will not be set: ';\n if (typeof transactionContextPropagator?.getTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: getTransactionContext is not a function.`);\n } else if (typeof transactionContextPropagator?.setTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: setTransactionContext is not a function.`);\n } else {\n this._transactionContextPropagator = transactionContextPropagator;\n }\n return this;\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n transactionContext: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args);\n }\n\n getTransactionContext(): TransactionContext {\n try {\n return this._transactionContextPropagator.getTransactionContext();\n } catch (err: unknown) {\n const error = err as Error | undefined;\n this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`);\n this._logger.error(error?.stack);\n return {};\n }\n }\n}\n\n/**\n * A singleton instance of the OpenFeature API.\n * @returns {OpenFeatureAPI} OpenFeature API\n */\nexport const OpenFeature = OpenFeatureAPI.getInstance();\n", "import { GenericEventEmitter } from '@openfeature/core';\nimport { EventEmitter } from 'node:events';\nimport { ProviderEvents } from './events';\n\n/**\n * The OpenFeatureEventEmitter can be used by provider developers to emit\n * events at various parts of the provider lifecycle.\n * \n * NOTE: Ready and error events are automatically emitted by the SDK based on\n * the result of the initialize method.\n */\nexport class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEvents> {\n protected readonly eventEmitter = new EventEmitter({ captureRejections: true });\n\n constructor() {\n super();\n this.eventEmitter.on('error', (err) => {\n this._logger?.error('Error running event handler:', err);\n });\n }\n};", "import { ServerProviderEvents } from '@openfeature/core';\n\nexport { ServerProviderEvents as ProviderEvents };", "import { CommonProvider, EvaluationContext, JsonValue, Logger, ResolutionDetails, ServerProviderStatus } from '@openfeature/core';\nimport { Hook } from '../hooks';\n\nexport { ServerProviderStatus as ProviderStatus };\n\n/**\n * Interface that providers must implement to resolve flag values for their particular\n * backend or vendor.\n *\n * Implementation for resolving all the required flag types must be defined.\n */\nexport interface Provider extends CommonProvider<ServerProviderStatus> {\n /**\n * A provider hook exposes a mechanism for provider authors to register hooks\n * to tap into various stages of the flag evaluation lifecycle. These hooks can\n * be used to perform side effects and mutate the context for purposes of the\n * provider. Provider hooks are not configured or controlled by the application author.\n */\n readonly hooks?: Hook[];\n\n /**\n * Resolve a boolean flag and its evaluation details.\n */\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<boolean>>;\n\n /**\n * Resolve a string flag and its evaluation details.\n */\n resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<string>>;\n\n /**\n * Resolve a numeric flag and its evaluation details.\n */\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<number>>;\n\n /**\n * Resolve and parse an object flag and its evaluation details.\n */\n resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<T>>;\n}\n", "import { JsonValue, ResolutionDetails } from '@openfeature/core';\nimport { Provider } from './provider';\n\nconst REASON_NO_OP = 'No-op';\n\n/**\n * The No-op provider is set by default, and simply always returns the default value.\n */\nclass NoopFeatureProvider implements Provider {\n readonly metadata = {\n name: 'No-op Provider',\n } as const;\n\n resolveBooleanEvaluation(_: string, defaultValue: boolean): Promise<ResolutionDetails<boolean>> {\n return this.noOp(defaultValue);\n }\n\n resolveStringEvaluation(_: string, defaultValue: string): Promise<ResolutionDetails<string>> {\n return this.noOp(defaultValue);\n }\n\n resolveNumberEvaluation(_: string, defaultValue: number): Promise<ResolutionDetails<number>> {\n return this.noOp(defaultValue);\n }\n\n resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): Promise<ResolutionDetails<T>> {\n return this.noOp<T>(defaultValue);\n }\n\n private noOp<T>(defaultValue: T) {\n return Promise.resolve({\n value: defaultValue,\n reason: REASON_NO_OP,\n });\n }\n}\n\nexport const NOOP_PROVIDER = new NoopFeatureProvider();\n", "import {\n EvaluationContext,\n FlagNotFoundError,\n FlagValueType,\n GeneralError,\n JsonValue,\n Logger,\n OpenFeatureError,\n ResolutionDetails,\n StandardResolutionReasons,\n TypeMismatchError\n} from '@openfeature/core';\nimport { Provider } from '../provider';\nimport { Flag, FlagConfiguration } from './flag-configuration';\nimport { VariantFoundError } from './variant-not-found-error';\nimport { OpenFeatureEventEmitter, ProviderEvents } from '../..';\n\n/**\n * A simple OpenFeature provider intended for demos and as a test stub.\n */\nexport class InMemoryProvider implements Provider {\n public readonly events = new OpenFeatureEventEmitter();\n public readonly runsOn = 'server';\n readonly metadata = {\n name: 'in-memory',\n } as const;\n private _flagConfiguration: FlagConfiguration;\n\n constructor(flagConfiguration: FlagConfiguration = {}) {\n this._flagConfiguration = { ...flagConfiguration };\n }\n\n /**\n * Overwrites the configured flags.\n * @param { FlagConfiguration } flagConfiguration new flag configuration\n */\n putConfiguration(flagConfiguration: FlagConfiguration) {\n const flagsChanged = Object.entries(flagConfiguration)\n .filter(([key, value]) => this._flagConfiguration[key] !== value)\n .map(([key]) => key);\n\n this._flagConfiguration = { ...flagConfiguration };\n this.events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });\n }\n\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<boolean>> {\n return this.resolveFlagWithReason<boolean>(flagKey, defaultValue, context, logger);\n }\n\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<number>> {\n return this.resolveFlagWithReason<number>(flagKey, defaultValue, context, logger);\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<string>> {\n return this.resolveFlagWithReason<string>(flagKey, defaultValue, context, logger);\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n return this.resolveFlagWithReason<T>(flagKey, defaultValue, context, logger);\n }\n\n private async resolveFlagWithReason<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n try {\n const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);\n\n if (typeof resolutionResult?.value != typeof defaultValue) {\n throw new TypeMismatchError();\n }\n\n return resolutionResult;\n } catch (error: unknown) {\n if (!(error instanceof OpenFeatureError)) {\n throw new GeneralError((error as Error)?.message || 'unknown error'); \n }\n throw error;\n }\n }\n\n private lookupFlagValue<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): ResolutionDetails<T> {\n if (!(flagKey in this._flagConfiguration)) {\n const message = `no flag found with key ${flagKey}`;\n logger?.debug(message);\n throw new FlagNotFoundError(message);\n }\n const flagSpec: Flag = this._flagConfiguration[flagKey];\n\n if (flagSpec.disabled) {\n return { value: defaultValue, reason: StandardResolutionReasons.DISABLED };\n }\n\n const isContextEval = ctx && flagSpec?.contextEvaluator;\n const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;\n\n const value = variant && flagSpec?.variants[variant];\n\n if (value === undefined) {\n const message = `no value associated with variant ${variant}`;\n logger?.error(message);\n throw new VariantFoundError(message);\n }\n\n return {\n value: value as T,\n ...(variant && { variant }),\n reason: isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC,\n };\n }\n}\n", "import { ErrorCode, OpenFeatureError } from '@openfeature/core';\n\n/**\n * A custom error for the in-memory provider.\n * Indicates the resolved or default variant doesn't exist.\n */\nexport class VariantFoundError extends OpenFeatureError {\n code: ErrorCode;\n constructor(message?: string) {\n super(message);\n Object.setPrototypeOf(this, VariantFoundError.prototype);\n this.name = 'VariantFoundError';\n this.code = ErrorCode.GENERAL;\n }\n}\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContext, TransactionContextPropagator } from './transaction-context';\n\nclass NoopTransactionContextPropagator implements TransactionContextPropagator {\n getTransactionContext(): EvaluationContext {\n return {};\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n _: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n callback(...args);\n }\n}\n\nexport const NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContext, TransactionContextPropagator } from './transaction-context';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport class AsyncLocalStorageTransactionContextPropagator implements TransactionContextPropagator {\n private asyncLocalStorage = new AsyncLocalStorage<EvaluationContext>();\n\n getTransactionContext(): EvaluationContext {\n return this.asyncLocalStorage.getStore() ?? {};\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n transactionContext: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n this.asyncLocalStorage.run(transactionContext, callback, ...args);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_core", "import_core", "import_core", "import_core", "import_core", "import_core", "err"]
|
|
7
7
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,21 +1,46 @@
|
|
|
1
1
|
// src/client/open-feature-client.ts
|
|
2
2
|
import {
|
|
3
3
|
ErrorCode as ErrorCode2,
|
|
4
|
+
ProviderFatalError,
|
|
5
|
+
ProviderNotReadyError,
|
|
4
6
|
SafeLogger,
|
|
5
7
|
StandardResolutionReasons as StandardResolutionReasons2,
|
|
6
8
|
statusMatchesEvent
|
|
7
9
|
} from "@openfeature/core";
|
|
8
10
|
|
|
11
|
+
// src/open-feature.ts
|
|
12
|
+
import {
|
|
13
|
+
OpenFeatureCommonAPI,
|
|
14
|
+
ProviderWrapper,
|
|
15
|
+
objectOrUndefined,
|
|
16
|
+
stringOrUndefined
|
|
17
|
+
} from "@openfeature/core";
|
|
18
|
+
|
|
19
|
+
// src/events/open-feature-event-emitter.ts
|
|
20
|
+
import { GenericEventEmitter } from "@openfeature/core";
|
|
21
|
+
import { EventEmitter } from "events";
|
|
22
|
+
var OpenFeatureEventEmitter = class extends GenericEventEmitter {
|
|
23
|
+
eventEmitter = new EventEmitter({ captureRejections: true });
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
this.eventEmitter.on("error", (err) => {
|
|
27
|
+
this._logger?.error("Error running event handler:", err);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/events/events.ts
|
|
33
|
+
import { ServerProviderEvents } from "@openfeature/core";
|
|
34
|
+
|
|
35
|
+
// src/provider/provider.ts
|
|
36
|
+
import { ServerProviderStatus } from "@openfeature/core";
|
|
37
|
+
|
|
9
38
|
// src/provider/no-op-provider.ts
|
|
10
|
-
import { ProviderStatus } from "@openfeature/core";
|
|
11
39
|
var REASON_NO_OP = "No-op";
|
|
12
40
|
var NoopFeatureProvider = class {
|
|
13
41
|
metadata = {
|
|
14
42
|
name: "No-op Provider"
|
|
15
43
|
};
|
|
16
|
-
get status() {
|
|
17
|
-
return ProviderStatus.NOT_READY;
|
|
18
|
-
}
|
|
19
44
|
resolveBooleanEvaluation(_, defaultValue) {
|
|
20
45
|
return this.noOp(defaultValue);
|
|
21
46
|
}
|
|
@@ -130,46 +155,37 @@ var InMemoryProvider = class {
|
|
|
130
155
|
}
|
|
131
156
|
};
|
|
132
157
|
|
|
133
|
-
// src/open-feature.ts
|
|
134
|
-
import {
|
|
135
|
-
OpenFeatureCommonAPI,
|
|
136
|
-
objectOrUndefined,
|
|
137
|
-
stringOrUndefined
|
|
138
|
-
} from "@openfeature/core";
|
|
139
|
-
|
|
140
158
|
// src/transaction-context/no-op-transaction-context-propagator.ts
|
|
141
159
|
var NoopTransactionContextPropagator = class {
|
|
142
160
|
getTransactionContext() {
|
|
143
161
|
return {};
|
|
144
162
|
}
|
|
145
|
-
setTransactionContext(_, callback) {
|
|
146
|
-
callback();
|
|
163
|
+
setTransactionContext(_, callback, ...args) {
|
|
164
|
+
callback(...args);
|
|
147
165
|
}
|
|
148
166
|
};
|
|
149
167
|
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
|
|
150
168
|
|
|
151
|
-
// src/
|
|
152
|
-
import {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
});
|
|
169
|
+
// src/transaction-context/async-local-storage-transaction-context-propagator.ts
|
|
170
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
171
|
+
var AsyncLocalStorageTransactionContextPropagator = class {
|
|
172
|
+
asyncLocalStorage = new AsyncLocalStorage();
|
|
173
|
+
getTransactionContext() {
|
|
174
|
+
return this.asyncLocalStorage.getStore() ?? {};
|
|
175
|
+
}
|
|
176
|
+
setTransactionContext(transactionContext, callback, ...args) {
|
|
177
|
+
this.asyncLocalStorage.run(transactionContext, callback, ...args);
|
|
161
178
|
}
|
|
162
179
|
};
|
|
163
180
|
|
|
164
|
-
// src/events/events.ts
|
|
165
|
-
import { ServerProviderEvents } from "@openfeature/core";
|
|
166
|
-
|
|
167
181
|
// src/open-feature.ts
|
|
168
182
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api");
|
|
169
183
|
var _globalThis = globalThis;
|
|
170
184
|
var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
_statusEnumType = ServerProviderStatus;
|
|
186
|
+
_apiEmitter = new OpenFeatureEventEmitter();
|
|
187
|
+
_defaultProvider = new ProviderWrapper(NOOP_PROVIDER, ServerProviderStatus.NOT_READY, this._statusEnumType);
|
|
188
|
+
_domainScopedProviders = /* @__PURE__ */ new Map();
|
|
173
189
|
_createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
174
190
|
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
|
|
175
191
|
constructor() {
|
|
@@ -189,6 +205,12 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
|
|
|
189
205
|
_globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
|
|
190
206
|
return instance;
|
|
191
207
|
}
|
|
208
|
+
getProviderStatus(domain) {
|
|
209
|
+
if (!domain) {
|
|
210
|
+
return this._defaultProvider.status;
|
|
211
|
+
}
|
|
212
|
+
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;
|
|
213
|
+
}
|
|
192
214
|
setContext(context) {
|
|
193
215
|
this._context = context;
|
|
194
216
|
return this;
|
|
@@ -202,6 +224,7 @@ var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
|
|
|
202
224
|
const context = objectOrUndefined(domainOrContext) ?? objectOrUndefined(versionOrContext) ?? objectOrUndefined(contextOrUndefined);
|
|
203
225
|
return new OpenFeatureClient(
|
|
204
226
|
() => this.getProviderForClient(domain),
|
|
227
|
+
() => this.getProviderStatus(domain),
|
|
205
228
|
() => this.buildAndCacheEventEmitterForClient(domain),
|
|
206
229
|
() => this._logger,
|
|
207
230
|
{ domain, version },
|
|
@@ -244,8 +267,9 @@ var OpenFeature = OpenFeatureAPI.getInstance();
|
|
|
244
267
|
|
|
245
268
|
// src/client/open-feature-client.ts
|
|
246
269
|
var OpenFeatureClient = class {
|
|
247
|
-
constructor(providerAccessor, emitterAccessor, globalLogger, options, context = {}) {
|
|
270
|
+
constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options, context = {}) {
|
|
248
271
|
this.providerAccessor = providerAccessor;
|
|
272
|
+
this.providerStatusAccessor = providerStatusAccessor;
|
|
249
273
|
this.emitterAccessor = emitterAccessor;
|
|
250
274
|
this.globalLogger = globalLogger;
|
|
251
275
|
this.options = options;
|
|
@@ -263,9 +287,12 @@ var OpenFeatureClient = class {
|
|
|
263
287
|
providerMetadata: this.providerAccessor().metadata
|
|
264
288
|
};
|
|
265
289
|
}
|
|
290
|
+
get providerStatus() {
|
|
291
|
+
return this.providerStatusAccessor();
|
|
292
|
+
}
|
|
266
293
|
addHandler(eventType, handler) {
|
|
267
294
|
this.emitterAccessor().addHandler(eventType, handler);
|
|
268
|
-
const shouldRunNow = statusMatchesEvent(eventType, this.
|
|
295
|
+
const shouldRunNow = statusMatchesEvent(eventType, this._providerStatus);
|
|
269
296
|
if (shouldRunNow) {
|
|
270
297
|
try {
|
|
271
298
|
handler({
|
|
@@ -378,6 +405,11 @@ var OpenFeatureClient = class {
|
|
|
378
405
|
};
|
|
379
406
|
try {
|
|
380
407
|
const frozenContext = await this.beforeHooks(allHooks, hookContext, options);
|
|
408
|
+
if (this.providerStatus === ServerProviderStatus.NOT_READY) {
|
|
409
|
+
throw new ProviderNotReadyError("provider has not yet initialized");
|
|
410
|
+
} else if (this.providerStatus === ServerProviderStatus.FATAL) {
|
|
411
|
+
throw new ProviderFatalError("provider is in an irrecoverable error state");
|
|
412
|
+
}
|
|
381
413
|
const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);
|
|
382
414
|
const evaluationDetails = {
|
|
383
415
|
...resolution,
|
|
@@ -446,6 +478,9 @@ var OpenFeatureClient = class {
|
|
|
446
478
|
get _provider() {
|
|
447
479
|
return this.providerAccessor();
|
|
448
480
|
}
|
|
481
|
+
get _providerStatus() {
|
|
482
|
+
return this.providerStatusAccessor();
|
|
483
|
+
}
|
|
449
484
|
get _logger() {
|
|
450
485
|
return this._clientLogger || this.globalLogger();
|
|
451
486
|
}
|
|
@@ -454,6 +489,7 @@ var OpenFeatureClient = class {
|
|
|
454
489
|
// src/index.ts
|
|
455
490
|
export * from "@openfeature/core";
|
|
456
491
|
export {
|
|
492
|
+
AsyncLocalStorageTransactionContextPropagator,
|
|
457
493
|
InMemoryProvider,
|
|
458
494
|
NOOP_PROVIDER,
|
|
459
495
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
@@ -461,6 +497,7 @@ export {
|
|
|
461
497
|
OpenFeatureAPI,
|
|
462
498
|
OpenFeatureClient,
|
|
463
499
|
OpenFeatureEventEmitter,
|
|
464
|
-
ServerProviderEvents as ProviderEvents
|
|
500
|
+
ServerProviderEvents as ProviderEvents,
|
|
501
|
+
ServerProviderStatus as ProviderStatus
|
|
465
502
|
};
|
|
466
503
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/client/open-feature-client.ts", "../../src/provider/no-op-provider.ts", "../../src/provider/in-memory-provider/in-memory-provider.ts", "../../src/provider/in-memory-provider/variant-not-found-error.ts", "../../src/
|
|
4
|
-
"sourcesContent": ["import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent,\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { ProviderEvents } from '../events';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\nimport { Hook } from '../hooks';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n /**\n * @deprecated Use `domain` instead.\n */\n name?: string;\n domain?: string;\n version?: string;\n};\n\nexport class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> {\n private _context: EvaluationContext;\n private _hooks: Hook[] = [];\n private _clientLogger?: Logger;\n\n constructor(\n // we always want the client to use the current provider,\n // so pass a function to always access the currently registered one.\n private readonly providerAccessor: () => Provider,\n private readonly emitterAccessor: () => InternalEventEmitter,\n private readonly globalLogger: () => Logger,\n private readonly options: OpenFeatureClientOptions,\n context: EvaluationContext = {},\n ) {\n this._context = context;\n }\n\n get metadata(): ClientMetadata {\n return {\n // Use domain if name is not provided\n name: this.options.domain ?? this.options.name,\n domain: this.options.domain ?? this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler(eventType: ProviderEvents, handler: EventHandler): void {\n this.emitterAccessor().addHandler(eventType, handler);\n const shouldRunNow = statusMatchesEvent(eventType, this._provider.status);\n\n if (shouldRunNow) {\n // run immediately, we're in the matching state\n try {\n handler({\n clientName: this.metadata.name,\n domain: this.metadata.domain,\n providerName: this._provider.metadata.name,\n });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler(eventType: ProviderEvents, handler: EventHandler) {\n this.emitterAccessor().removeHandler(eventType, handler);\n }\n\n getHandlers(eventType: ProviderEvents) {\n return this.emitterAccessor().getHandlers(eventType);\n }\n\n setLogger(logger: Logger): OpenFeatureClient {\n this._clientLogger = new SafeLogger(logger);\n return this;\n }\n\n setContext(context: EvaluationContext): OpenFeatureClient {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n addHooks(...hooks: Hook[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook[] {\n return this._hooks;\n }\n\n clearHooks(): OpenFeatureClient {\n this._hooks = [];\n return this;\n }\n\n async getBooleanValue(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<boolean> {\n return (await this.getBooleanDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getBooleanDetails(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<boolean>> {\n return this.evaluate<boolean>(\n flagKey,\n this._provider.resolveBooleanEvaluation,\n defaultValue,\n 'boolean',\n context,\n options,\n );\n }\n\n async getStringValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getStringDetails<T>(flagKey, defaultValue, context, options)).value;\n }\n\n getStringDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted string generic argument.\n this._provider.resolveStringEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'string',\n context,\n options,\n );\n }\n\n async getNumberValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getNumberDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getNumberDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted number generic argument.\n this._provider.resolveNumberEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'number',\n context,\n options,\n );\n }\n\n async getObjectValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getObjectDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getObjectDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(flagKey, this._provider.resolveObjectEvaluation, defaultValue, 'object', context, options);\n }\n\n private async evaluate<T extends FlagValue>(\n flagKey: string,\n resolver: (\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ) => Promise<ResolutionDetails<T>>,\n defaultValue: T,\n flagType: FlagValueType,\n invocationContext: EvaluationContext = {},\n options: FlagEvaluationOptions = {},\n ): Promise<EvaluationDetails<T>> {\n // merge global, client, and evaluation context\n\n const allHooks = [\n ...OpenFeature.getHooks(),\n ...this.getHooks(),\n ...(options.hooks || []),\n ...(this._provider.hooks || []),\n ];\n const allHooksReversed = [...allHooks].reverse();\n\n // merge global and client contexts\n const mergedContext = {\n ...OpenFeature.getContext(),\n ...OpenFeature.getTransactionContext(),\n ...this._context,\n ...invocationContext,\n };\n\n // this reference cannot change during the course of evaluation\n // it may be used as a key in WeakMaps\n const hookContext: Readonly<HookContext> = {\n flagKey,\n defaultValue,\n flagValueType: flagType,\n clientMetadata: this.metadata,\n providerMetadata: OpenFeature.providerMetadata,\n context: mergedContext,\n logger: this._logger,\n };\n\n try {\n const frozenContext = await this.beforeHooks(allHooks, hookContext, options);\n\n // run the referenced resolver, binding the provider.\n const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);\n\n const evaluationDetails = {\n ...resolution,\n flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),\n flagKey,\n };\n\n await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);\n\n return evaluationDetails;\n } catch (err: unknown) {\n const errorMessage: string = (err as Error)?.message;\n const errorCode: ErrorCode = (err as OpenFeatureError)?.code || ErrorCode.GENERAL;\n\n await this.errorHooks(allHooksReversed, hookContext, err, options);\n\n return {\n errorCode,\n errorMessage,\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n flagMetadata: Object.freeze({}),\n flagKey,\n };\n } finally {\n await this.finallyHooks(allHooksReversed, hookContext, options);\n }\n }\n\n private async beforeHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n for (const hook of hooks) {\n // freeze the hookContext\n Object.freeze(hookContext);\n\n // use Object.assign to avoid modification of frozen hookContext\n Object.assign(hookContext.context, {\n ...hookContext.context,\n ...(await hook?.before?.(hookContext, Object.freeze(options.hookHints))),\n });\n }\n\n // after before hooks, freeze the EvaluationContext.\n return Object.freeze(hookContext.context);\n }\n\n private async afterHooks(\n hooks: Hook[],\n hookContext: HookContext,\n evaluationDetails: EvaluationDetails<FlagValue>,\n options: FlagEvaluationOptions,\n ) {\n // run \"after\" hooks sequentially\n for (const hook of hooks) {\n await hook?.after?.(hookContext, evaluationDetails, options.hookHints);\n }\n }\n\n private async errorHooks(hooks: Hook[], hookContext: HookContext, err: unknown, options: FlagEvaluationOptions) {\n // run \"error\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.error?.(hookContext, err, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'error' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private async finallyHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n // run \"finally\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.finally?.(hookContext, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'finally' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private get _provider(): Provider {\n return this.providerAccessor();\n }\n\n private get _logger() {\n return this._clientLogger || this.globalLogger();\n }\n}\n", "import { ResolutionDetails, JsonValue, ProviderStatus } from '@openfeature/core';\nimport { Provider } from './provider';\n\nconst REASON_NO_OP = 'No-op';\n\n/**\n * The No-op provider is set by default, and simply always returns the default value.\n */\nclass NoopFeatureProvider implements Provider {\n readonly metadata = {\n name: 'No-op Provider',\n } as const;\n\n get status(): ProviderStatus {\n /**\n * This is due to the NoopProvider not being a real provider.\n * We do not want it to trigger the Ready event handlers, so we never set this to ready.\n * With the NoopProvider assigned, the client can be assumed to be uninitialized.\n * https://github.com/open-feature/js-sdk/pull/429#discussion_r1202642654\n */\n return ProviderStatus.NOT_READY;\n }\n\n resolveBooleanEvaluation(_: string, defaultValue: boolean): Promise<ResolutionDetails<boolean>> {\n return this.noOp(defaultValue);\n }\n\n resolveStringEvaluation(_: string, defaultValue: string): Promise<ResolutionDetails<string>> {\n return this.noOp(defaultValue);\n }\n\n resolveNumberEvaluation(_: string, defaultValue: number): Promise<ResolutionDetails<number>> {\n return this.noOp(defaultValue);\n }\n\n resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): Promise<ResolutionDetails<T>> {\n return this.noOp<T>(defaultValue);\n }\n\n private noOp<T>(defaultValue: T) {\n return Promise.resolve({\n value: defaultValue,\n reason: REASON_NO_OP,\n });\n }\n}\n\nexport const NOOP_PROVIDER = new NoopFeatureProvider();\n", "import {\n EvaluationContext,\n FlagNotFoundError,\n FlagValueType,\n GeneralError,\n JsonValue,\n Logger,\n OpenFeatureError,\n ResolutionDetails,\n StandardResolutionReasons,\n TypeMismatchError\n} from '@openfeature/core';\nimport { Provider } from '../provider';\nimport { Flag, FlagConfiguration } from './flag-configuration';\nimport { VariantFoundError } from './variant-not-found-error';\nimport { OpenFeatureEventEmitter, ProviderEvents } from '../..';\n\n/**\n * A simple OpenFeature provider intended for demos and as a test stub.\n */\nexport class InMemoryProvider implements Provider {\n public readonly events = new OpenFeatureEventEmitter();\n public readonly runsOn = 'server';\n readonly metadata = {\n name: 'in-memory',\n } as const;\n private _flagConfiguration: FlagConfiguration;\n\n constructor(flagConfiguration: FlagConfiguration = {}) {\n this._flagConfiguration = { ...flagConfiguration };\n }\n\n /**\n * Overwrites the configured flags.\n * @param { FlagConfiguration } flagConfiguration new flag configuration\n */\n putConfiguration(flagConfiguration: FlagConfiguration) {\n const flagsChanged = Object.entries(flagConfiguration)\n .filter(([key, value]) => this._flagConfiguration[key] !== value)\n .map(([key]) => key);\n\n this._flagConfiguration = { ...flagConfiguration };\n this.events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });\n }\n\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<boolean>> {\n return this.resolveFlagWithReason<boolean>(flagKey, defaultValue, context, logger);\n }\n\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<number>> {\n return this.resolveFlagWithReason<number>(flagKey, defaultValue, context, logger);\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<string>> {\n return this.resolveFlagWithReason<string>(flagKey, defaultValue, context, logger);\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n return this.resolveFlagWithReason<T>(flagKey, defaultValue, context, logger);\n }\n\n private async resolveFlagWithReason<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n try {\n const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);\n\n if (typeof resolutionResult?.value != typeof defaultValue) {\n throw new TypeMismatchError();\n }\n\n return resolutionResult;\n } catch (error: unknown) {\n if (!(error instanceof OpenFeatureError)) {\n throw new GeneralError((error as Error)?.message || 'unknown error'); \n }\n throw error;\n }\n }\n\n private lookupFlagValue<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): ResolutionDetails<T> {\n if (!(flagKey in this._flagConfiguration)) {\n const message = `no flag found with key ${flagKey}`;\n logger?.debug(message);\n throw new FlagNotFoundError(message);\n }\n const flagSpec: Flag = this._flagConfiguration[flagKey];\n\n if (flagSpec.disabled) {\n return { value: defaultValue, reason: StandardResolutionReasons.DISABLED };\n }\n\n const isContextEval = ctx && flagSpec?.contextEvaluator;\n const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;\n\n const value = variant && flagSpec?.variants[variant];\n\n if (value === undefined) {\n const message = `no value associated with variant ${variant}`;\n logger?.error(message);\n throw new VariantFoundError(message);\n }\n\n return {\n value: value as T,\n ...(variant && { variant }),\n reason: isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC,\n };\n }\n}\n", "import { ErrorCode, OpenFeatureError } from '@openfeature/core';\n\n/**\n * A custom error for the in-memory provider.\n * Indicates the resolved or default variant doesn't exist.\n */\nexport class VariantFoundError extends OpenFeatureError {\n code: ErrorCode;\n constructor(message?: string) {\n super(message);\n Object.setPrototypeOf(this, VariantFoundError.prototype);\n this.name = 'VariantFoundError';\n this.code = ErrorCode.GENERAL;\n }\n}\n", "import { NOOP_PROVIDER, Provider } from './provider';\nimport {\n ManageContext,\n OpenFeatureCommonAPI,\n EvaluationContext,\n objectOrUndefined,\n stringOrUndefined,\n} from '@openfeature/core';\nimport {\n ManageTransactionContextPropagator,\n NOOP_TRANSACTION_CONTEXT_PROPAGATOR,\n TransactionContext,\n TransactionContextPropagator,\n} from './transaction-context';\nimport { Client, OpenFeatureClient } from './client';\nimport { OpenFeatureEventEmitter } from './events';\nimport { Hook } from './hooks';\n\n// use a symbol as a key for the global singleton\nconst GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/js-sdk/api');\n\ntype OpenFeatureGlobal = {\n [GLOBAL_OPENFEATURE_API_KEY]?: OpenFeatureAPI;\n};\nconst _globalThis = globalThis as OpenFeatureGlobal;\n\nexport class OpenFeatureAPI\n extends OpenFeatureCommonAPI<Provider, Hook>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<Provider>>\n{\n protected _events = new OpenFeatureEventEmitter();\n protected _defaultProvider: Provider = NOOP_PROVIDER;\n protected _createEventEmitter = () => new OpenFeatureEventEmitter();\n\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n\n private constructor() {\n super('server');\n }\n\n /**\n * Gets a singleton instance of the OpenFeature API.\n * @ignore\n * @returns {OpenFeatureAPI} OpenFeature API\n */\n static getInstance(): OpenFeatureAPI {\n const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];\n if (globalApi) {\n return globalApi;\n }\n\n const instance = new OpenFeatureAPI();\n _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;\n return instance;\n }\n\n setContext(context: EvaluationContext): this {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n /**\n * A factory function for creating new domainless OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * All domainless or unbound clients use the default provider set via {@link this.setProvider setProvider}.\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {string} version The version of the client (only used for metadata)\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, version: string, context?: EvaluationContext): Client;\n getClient(\n domainOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext,\n ): Client {\n const domain = stringOrUndefined(domainOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(domainOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(domain),\n () => this.buildAndCacheEventEmitterForClient(domain),\n () => this._logger,\n { domain, version },\n context,\n );\n }\n\n /**\n * Clears all registered providers and resets the default provider.\n * @returns {Promise<void>}\n */\n clearProviders(): Promise<void> {\n return super.clearProvidersAndSetDefault(NOOP_PROVIDER);\n }\n\n setTransactionContextPropagator(\n transactionContextPropagator: TransactionContextPropagator,\n ): OpenFeatureCommonAPI<Provider> {\n const baseMessage = 'Invalid TransactionContextPropagator, will not be set: ';\n if (typeof transactionContextPropagator?.getTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: getTransactionContext is not a function.`);\n } else if (typeof transactionContextPropagator?.setTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: setTransactionContext is not a function.`);\n } else {\n this._transactionContextPropagator = transactionContextPropagator;\n }\n return this;\n }\n\n setTransactionContext<R>(\n transactionContext: TransactionContext,\n callback: (...args: unknown[]) => R,\n ...args: unknown[]\n ): void {\n this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args);\n }\n\n getTransactionContext(): TransactionContext {\n try {\n return this._transactionContextPropagator.getTransactionContext();\n } catch (err: unknown) {\n const error = err as Error | undefined;\n this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`);\n this._logger.error(error?.stack);\n return {};\n }\n }\n}\n\n/**\n * A singleton instance of the OpenFeature API.\n * @returns {OpenFeatureAPI} OpenFeature API\n */\nexport const OpenFeature = OpenFeatureAPI.getInstance();\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContextPropagator } from './transaction-context';\n\nclass NoopTransactionContextPropagator implements TransactionContextPropagator {\n getTransactionContext(): EvaluationContext {\n return {};\n }\n\n setTransactionContext(_: EvaluationContext, callback: () => void): void {\n callback();\n }\n}\n\nexport const NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();\n", "import { GenericEventEmitter } from '@openfeature/core';\nimport EventEmitter from 'events';\nimport { ProviderEvents } from './events';\n\n/**\n * The OpenFeatureEventEmitter can be used by provider developers to emit\n * events at various parts of the provider lifecycle.\n * \n * NOTE: Ready and error events are automatically emitted by the SDK based on\n * the result of the initialize method.\n */\nexport class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEvents> {\n protected readonly eventEmitter = new EventEmitter({ captureRejections: true });\n\n constructor() {\n super();\n this.eventEmitter.on('error', (err) => {\n this._logger?.error('Error running event handler:', err);\n });\n }\n};", "import { ServerProviderEvents } from '@openfeature/core';\n\nexport { ServerProviderEvents as ProviderEvents };", "export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from './events';\nexport * from './hooks';\nexport * from '@openfeature/core';\n"],
|
|
5
|
-
"mappings": ";AAAA;AAAA,EAEE,aAAAA;AAAA,
|
|
3
|
+
"sources": ["../../src/client/open-feature-client.ts", "../../src/open-feature.ts", "../../src/events/open-feature-event-emitter.ts", "../../src/events/events.ts", "../../src/provider/provider.ts", "../../src/provider/no-op-provider.ts", "../../src/provider/in-memory-provider/in-memory-provider.ts", "../../src/provider/in-memory-provider/variant-not-found-error.ts", "../../src/transaction-context/no-op-transaction-context-propagator.ts", "../../src/transaction-context/async-local-storage-transaction-context-propagator.ts", "../../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderFatalError,\n ProviderNotReadyError,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent,\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { ProviderEvents } from '../events';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\nimport { Hook } from '../hooks';\nimport { OpenFeature } from '../open-feature';\nimport { Provider, ProviderStatus } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n /**\n * @deprecated Use `domain` instead.\n */\n name?: string;\n domain?: string;\n version?: string;\n};\n\nexport class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> {\n private _context: EvaluationContext;\n private _hooks: Hook[] = [];\n private _clientLogger?: Logger;\n\n constructor(\n // we always want the client to use the current provider,\n // so pass a function to always access the currently registered one.\n private readonly providerAccessor: () => Provider,\n private readonly providerStatusAccessor: () => ProviderStatus,\n private readonly emitterAccessor: () => InternalEventEmitter,\n private readonly globalLogger: () => Logger,\n private readonly options: OpenFeatureClientOptions,\n context: EvaluationContext = {},\n ) {\n this._context = context;\n }\n\n get metadata(): ClientMetadata {\n return {\n // Use domain if name is not provided\n name: this.options.domain ?? this.options.name,\n domain: this.options.domain ?? this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n get providerStatus(): ProviderStatus {\n return this.providerStatusAccessor();\n }\n\n addHandler(eventType: ProviderEvents, handler: EventHandler): void {\n this.emitterAccessor().addHandler(eventType, handler);\n const shouldRunNow = statusMatchesEvent(eventType, this._providerStatus);\n\n if (shouldRunNow) {\n // run immediately, we're in the matching state\n try {\n handler({\n clientName: this.metadata.name,\n domain: this.metadata.domain,\n providerName: this._provider.metadata.name,\n });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler(eventType: ProviderEvents, handler: EventHandler) {\n this.emitterAccessor().removeHandler(eventType, handler);\n }\n\n getHandlers(eventType: ProviderEvents) {\n return this.emitterAccessor().getHandlers(eventType);\n }\n\n setLogger(logger: Logger): OpenFeatureClient {\n this._clientLogger = new SafeLogger(logger);\n return this;\n }\n\n setContext(context: EvaluationContext): OpenFeatureClient {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n addHooks(...hooks: Hook[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook[] {\n return this._hooks;\n }\n\n clearHooks(): OpenFeatureClient {\n this._hooks = [];\n return this;\n }\n\n async getBooleanValue(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<boolean> {\n return (await this.getBooleanDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getBooleanDetails(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<boolean>> {\n return this.evaluate<boolean>(\n flagKey,\n this._provider.resolveBooleanEvaluation,\n defaultValue,\n 'boolean',\n context,\n options,\n );\n }\n\n async getStringValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getStringDetails<T>(flagKey, defaultValue, context, options)).value;\n }\n\n getStringDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted string generic argument.\n this._provider.resolveStringEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'string',\n context,\n options,\n );\n }\n\n async getNumberValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getNumberDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getNumberDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(\n flagKey,\n // this isolates providers from our restricted number generic argument.\n this._provider.resolveNumberEvaluation as () => Promise<EvaluationDetails<T>>,\n defaultValue,\n 'number',\n context,\n options,\n );\n }\n\n async getObjectValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<T> {\n return (await this.getObjectDetails(flagKey, defaultValue, context, options)).value;\n }\n\n getObjectDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n options?: FlagEvaluationOptions,\n ): Promise<EvaluationDetails<T>> {\n return this.evaluate<T>(flagKey, this._provider.resolveObjectEvaluation, defaultValue, 'object', context, options);\n }\n\n private async evaluate<T extends FlagValue>(\n flagKey: string,\n resolver: (\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ) => Promise<ResolutionDetails<T>>,\n defaultValue: T,\n flagType: FlagValueType,\n invocationContext: EvaluationContext = {},\n options: FlagEvaluationOptions = {},\n ): Promise<EvaluationDetails<T>> {\n // merge global, client, and evaluation context\n\n const allHooks = [\n ...OpenFeature.getHooks(),\n ...this.getHooks(),\n ...(options.hooks || []),\n ...(this._provider.hooks || []),\n ];\n const allHooksReversed = [...allHooks].reverse();\n\n // merge global and client contexts\n const mergedContext = {\n ...OpenFeature.getContext(),\n ...OpenFeature.getTransactionContext(),\n ...this._context,\n ...invocationContext,\n };\n\n // this reference cannot change during the course of evaluation\n // it may be used as a key in WeakMaps\n const hookContext: Readonly<HookContext> = {\n flagKey,\n defaultValue,\n flagValueType: flagType,\n clientMetadata: this.metadata,\n providerMetadata: OpenFeature.providerMetadata,\n context: mergedContext,\n logger: this._logger,\n };\n\n try {\n const frozenContext = await this.beforeHooks(allHooks, hookContext, options);\n\n // short circuit evaluation entirely if provider is in a bad state\n if (this.providerStatus === ProviderStatus.NOT_READY) {\n throw new ProviderNotReadyError('provider has not yet initialized');\n } else if (this.providerStatus === ProviderStatus.FATAL) {\n throw new ProviderFatalError('provider is in an irrecoverable error state');\n }\n\n // run the referenced resolver, binding the provider.\n const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);\n\n const evaluationDetails = {\n ...resolution,\n flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),\n flagKey,\n };\n\n await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);\n\n return evaluationDetails;\n } catch (err: unknown) {\n const errorMessage: string = (err as Error)?.message;\n const errorCode: ErrorCode = (err as OpenFeatureError)?.code || ErrorCode.GENERAL;\n\n await this.errorHooks(allHooksReversed, hookContext, err, options);\n\n return {\n errorCode,\n errorMessage,\n value: defaultValue,\n reason: StandardResolutionReasons.ERROR,\n flagMetadata: Object.freeze({}),\n flagKey,\n };\n } finally {\n await this.finallyHooks(allHooksReversed, hookContext, options);\n }\n }\n\n private async beforeHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n for (const hook of hooks) {\n // freeze the hookContext\n Object.freeze(hookContext);\n\n // use Object.assign to avoid modification of frozen hookContext\n Object.assign(hookContext.context, {\n ...hookContext.context,\n ...(await hook?.before?.(hookContext, Object.freeze(options.hookHints))),\n });\n }\n\n // after before hooks, freeze the EvaluationContext.\n return Object.freeze(hookContext.context);\n }\n\n private async afterHooks(\n hooks: Hook[],\n hookContext: HookContext,\n evaluationDetails: EvaluationDetails<FlagValue>,\n options: FlagEvaluationOptions,\n ) {\n // run \"after\" hooks sequentially\n for (const hook of hooks) {\n await hook?.after?.(hookContext, evaluationDetails, options.hookHints);\n }\n }\n\n private async errorHooks(hooks: Hook[], hookContext: HookContext, err: unknown, options: FlagEvaluationOptions) {\n // run \"error\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.error?.(hookContext, err, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'error' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private async finallyHooks(hooks: Hook[], hookContext: HookContext, options: FlagEvaluationOptions) {\n // run \"finally\" hooks sequentially\n for (const hook of hooks) {\n try {\n await hook?.finally?.(hookContext, options.hookHints);\n } catch (err) {\n this._logger.error(`Unhandled error during 'finally' hook: ${err}`);\n if (err instanceof Error) {\n this._logger.error(err.stack);\n }\n this._logger.error((err as Error)?.stack);\n }\n }\n }\n\n private get _provider(): Provider {\n return this.providerAccessor();\n }\n\n private get _providerStatus(): ProviderStatus {\n return this.providerStatusAccessor();\n }\n\n private get _logger() {\n return this._clientLogger || this.globalLogger();\n }\n}\n", "import {\n EvaluationContext,\n ManageContext,\n OpenFeatureCommonAPI,\n ProviderWrapper,\n objectOrUndefined,\n stringOrUndefined,\n} from '@openfeature/core';\nimport { Client, OpenFeatureClient } from './client';\nimport { OpenFeatureEventEmitter } from './events';\nimport { Hook } from './hooks';\nimport { NOOP_PROVIDER, Provider, ProviderStatus } from './provider';\nimport {\n ManageTransactionContextPropagator,\n NOOP_TRANSACTION_CONTEXT_PROPAGATOR,\n TransactionContext,\n TransactionContextPropagator,\n} from './transaction-context';\nimport { ServerProviderStatus } from '@openfeature/core';\n\n// use a symbol as a key for the global singleton\nconst GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/js-sdk/api');\n\ntype OpenFeatureGlobal = {\n [GLOBAL_OPENFEATURE_API_KEY]?: OpenFeatureAPI;\n};\nconst _globalThis = globalThis as OpenFeatureGlobal;\n\nexport class OpenFeatureAPI\n extends OpenFeatureCommonAPI<ServerProviderStatus, Provider, Hook>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<ServerProviderStatus, Provider>>\n{\n protected _statusEnumType: typeof ProviderStatus = ProviderStatus;\n protected _apiEmitter = new OpenFeatureEventEmitter();\n protected _defaultProvider: ProviderWrapper<Provider, ServerProviderStatus> = new ProviderWrapper(NOOP_PROVIDER, ProviderStatus.NOT_READY, this._statusEnumType);\n protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ServerProviderStatus>> = new Map();\n protected _createEventEmitter = () => new OpenFeatureEventEmitter();\n\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n\n private constructor() {\n super('server');\n }\n\n /**\n * Gets a singleton instance of the OpenFeature API.\n * @ignore\n * @returns {OpenFeatureAPI} OpenFeature API\n */\n static getInstance(): OpenFeatureAPI {\n const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];\n if (globalApi) {\n return globalApi;\n }\n\n const instance = new OpenFeatureAPI();\n _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;\n return instance;\n }\n\n private getProviderStatus(domain?: string): ProviderStatus {\n if (!domain) {\n return this._defaultProvider.status;\n }\n\n return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;\n }\n\n setContext(context: EvaluationContext): this {\n this._context = context;\n return this;\n }\n\n getContext(): EvaluationContext {\n return this._context;\n }\n\n /**\n * A factory function for creating new domainless OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * All domainless or unbound clients use the default provider set via {@link this.setProvider setProvider}.\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new domain scoped OpenFeature clients.\n * Clients can contain their own state (e.g. logger, hook, context).\n * Multiple clients can be used to segment feature flag configuration.\n *\n * If there is already a provider bound to this domain via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that domain.\n * @param {string} domain An identifier which logically binds clients with providers\n * @param {string} version The version of the client (only used for metadata)\n * @param {EvaluationContext} context Evaluation context that should be set on the client to used during flag evaluations\n * @returns {Client} OpenFeature Client\n */\n getClient(domain: string, version: string, context?: EvaluationContext): Client;\n getClient(\n domainOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext,\n ): Client {\n const domain = stringOrUndefined(domainOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(domainOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(domain),\n () => this.getProviderStatus(domain),\n () => this.buildAndCacheEventEmitterForClient(domain),\n () => this._logger,\n { domain, version },\n context,\n );\n }\n\n /**\n * Clears all registered providers and resets the default provider.\n * @returns {Promise<void>}\n */\n clearProviders(): Promise<void> {\n return super.clearProvidersAndSetDefault(NOOP_PROVIDER);\n }\n\n setTransactionContextPropagator(\n transactionContextPropagator: TransactionContextPropagator,\n ): OpenFeatureCommonAPI<ServerProviderStatus, Provider> {\n const baseMessage = 'Invalid TransactionContextPropagator, will not be set: ';\n if (typeof transactionContextPropagator?.getTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: getTransactionContext is not a function.`);\n } else if (typeof transactionContextPropagator?.setTransactionContext !== 'function') {\n this._logger.error(`${baseMessage}: setTransactionContext is not a function.`);\n } else {\n this._transactionContextPropagator = transactionContextPropagator;\n }\n return this;\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n transactionContext: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args);\n }\n\n getTransactionContext(): TransactionContext {\n try {\n return this._transactionContextPropagator.getTransactionContext();\n } catch (err: unknown) {\n const error = err as Error | undefined;\n this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`);\n this._logger.error(error?.stack);\n return {};\n }\n }\n}\n\n/**\n * A singleton instance of the OpenFeature API.\n * @returns {OpenFeatureAPI} OpenFeature API\n */\nexport const OpenFeature = OpenFeatureAPI.getInstance();\n", "import { GenericEventEmitter } from '@openfeature/core';\nimport { EventEmitter } from 'node:events';\nimport { ProviderEvents } from './events';\n\n/**\n * The OpenFeatureEventEmitter can be used by provider developers to emit\n * events at various parts of the provider lifecycle.\n * \n * NOTE: Ready and error events are automatically emitted by the SDK based on\n * the result of the initialize method.\n */\nexport class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEvents> {\n protected readonly eventEmitter = new EventEmitter({ captureRejections: true });\n\n constructor() {\n super();\n this.eventEmitter.on('error', (err) => {\n this._logger?.error('Error running event handler:', err);\n });\n }\n};", "import { ServerProviderEvents } from '@openfeature/core';\n\nexport { ServerProviderEvents as ProviderEvents };", "import { CommonProvider, EvaluationContext, JsonValue, Logger, ResolutionDetails, ServerProviderStatus } from '@openfeature/core';\nimport { Hook } from '../hooks';\n\nexport { ServerProviderStatus as ProviderStatus };\n\n/**\n * Interface that providers must implement to resolve flag values for their particular\n * backend or vendor.\n *\n * Implementation for resolving all the required flag types must be defined.\n */\nexport interface Provider extends CommonProvider<ServerProviderStatus> {\n /**\n * A provider hook exposes a mechanism for provider authors to register hooks\n * to tap into various stages of the flag evaluation lifecycle. These hooks can\n * be used to perform side effects and mutate the context for purposes of the\n * provider. Provider hooks are not configured or controlled by the application author.\n */\n readonly hooks?: Hook[];\n\n /**\n * Resolve a boolean flag and its evaluation details.\n */\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<boolean>>;\n\n /**\n * Resolve a string flag and its evaluation details.\n */\n resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<string>>;\n\n /**\n * Resolve a numeric flag and its evaluation details.\n */\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<number>>;\n\n /**\n * Resolve and parse an object flag and its evaluation details.\n */\n resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext,\n logger: Logger,\n ): Promise<ResolutionDetails<T>>;\n}\n", "import { JsonValue, ResolutionDetails } from '@openfeature/core';\nimport { Provider } from './provider';\n\nconst REASON_NO_OP = 'No-op';\n\n/**\n * The No-op provider is set by default, and simply always returns the default value.\n */\nclass NoopFeatureProvider implements Provider {\n readonly metadata = {\n name: 'No-op Provider',\n } as const;\n\n resolveBooleanEvaluation(_: string, defaultValue: boolean): Promise<ResolutionDetails<boolean>> {\n return this.noOp(defaultValue);\n }\n\n resolveStringEvaluation(_: string, defaultValue: string): Promise<ResolutionDetails<string>> {\n return this.noOp(defaultValue);\n }\n\n resolveNumberEvaluation(_: string, defaultValue: number): Promise<ResolutionDetails<number>> {\n return this.noOp(defaultValue);\n }\n\n resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): Promise<ResolutionDetails<T>> {\n return this.noOp<T>(defaultValue);\n }\n\n private noOp<T>(defaultValue: T) {\n return Promise.resolve({\n value: defaultValue,\n reason: REASON_NO_OP,\n });\n }\n}\n\nexport const NOOP_PROVIDER = new NoopFeatureProvider();\n", "import {\n EvaluationContext,\n FlagNotFoundError,\n FlagValueType,\n GeneralError,\n JsonValue,\n Logger,\n OpenFeatureError,\n ResolutionDetails,\n StandardResolutionReasons,\n TypeMismatchError\n} from '@openfeature/core';\nimport { Provider } from '../provider';\nimport { Flag, FlagConfiguration } from './flag-configuration';\nimport { VariantFoundError } from './variant-not-found-error';\nimport { OpenFeatureEventEmitter, ProviderEvents } from '../..';\n\n/**\n * A simple OpenFeature provider intended for demos and as a test stub.\n */\nexport class InMemoryProvider implements Provider {\n public readonly events = new OpenFeatureEventEmitter();\n public readonly runsOn = 'server';\n readonly metadata = {\n name: 'in-memory',\n } as const;\n private _flagConfiguration: FlagConfiguration;\n\n constructor(flagConfiguration: FlagConfiguration = {}) {\n this._flagConfiguration = { ...flagConfiguration };\n }\n\n /**\n * Overwrites the configured flags.\n * @param { FlagConfiguration } flagConfiguration new flag configuration\n */\n putConfiguration(flagConfiguration: FlagConfiguration) {\n const flagsChanged = Object.entries(flagConfiguration)\n .filter(([key, value]) => this._flagConfiguration[key] !== value)\n .map(([key]) => key);\n\n this._flagConfiguration = { ...flagConfiguration };\n this.events.emit(ProviderEvents.ConfigurationChanged, { flagsChanged });\n }\n\n resolveBooleanEvaluation(\n flagKey: string,\n defaultValue: boolean,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<boolean>> {\n return this.resolveFlagWithReason<boolean>(flagKey, defaultValue, context, logger);\n }\n\n resolveNumberEvaluation(\n flagKey: string,\n defaultValue: number,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<number>> {\n return this.resolveFlagWithReason<number>(flagKey, defaultValue, context, logger);\n }\n\n async resolveStringEvaluation(\n flagKey: string,\n defaultValue: string,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<string>> {\n return this.resolveFlagWithReason<string>(flagKey, defaultValue, context, logger);\n }\n\n async resolveObjectEvaluation<T extends JsonValue>(\n flagKey: string,\n defaultValue: T,\n context?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n return this.resolveFlagWithReason<T>(flagKey, defaultValue, context, logger);\n }\n\n private async resolveFlagWithReason<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): Promise<ResolutionDetails<T>> {\n try {\n const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);\n\n if (typeof resolutionResult?.value != typeof defaultValue) {\n throw new TypeMismatchError();\n }\n\n return resolutionResult;\n } catch (error: unknown) {\n if (!(error instanceof OpenFeatureError)) {\n throw new GeneralError((error as Error)?.message || 'unknown error'); \n }\n throw error;\n }\n }\n\n private lookupFlagValue<T extends JsonValue | FlagValueType>(\n flagKey: string,\n defaultValue: T,\n ctx?: EvaluationContext,\n logger?: Logger,\n ): ResolutionDetails<T> {\n if (!(flagKey in this._flagConfiguration)) {\n const message = `no flag found with key ${flagKey}`;\n logger?.debug(message);\n throw new FlagNotFoundError(message);\n }\n const flagSpec: Flag = this._flagConfiguration[flagKey];\n\n if (flagSpec.disabled) {\n return { value: defaultValue, reason: StandardResolutionReasons.DISABLED };\n }\n\n const isContextEval = ctx && flagSpec?.contextEvaluator;\n const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;\n\n const value = variant && flagSpec?.variants[variant];\n\n if (value === undefined) {\n const message = `no value associated with variant ${variant}`;\n logger?.error(message);\n throw new VariantFoundError(message);\n }\n\n return {\n value: value as T,\n ...(variant && { variant }),\n reason: isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC,\n };\n }\n}\n", "import { ErrorCode, OpenFeatureError } from '@openfeature/core';\n\n/**\n * A custom error for the in-memory provider.\n * Indicates the resolved or default variant doesn't exist.\n */\nexport class VariantFoundError extends OpenFeatureError {\n code: ErrorCode;\n constructor(message?: string) {\n super(message);\n Object.setPrototypeOf(this, VariantFoundError.prototype);\n this.name = 'VariantFoundError';\n this.code = ErrorCode.GENERAL;\n }\n}\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContext, TransactionContextPropagator } from './transaction-context';\n\nclass NoopTransactionContextPropagator implements TransactionContextPropagator {\n getTransactionContext(): EvaluationContext {\n return {};\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n _: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n callback(...args);\n }\n}\n\nexport const NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();\n", "import { EvaluationContext } from '@openfeature/core';\nimport { TransactionContext, TransactionContextPropagator } from './transaction-context';\nimport { AsyncLocalStorage } from 'async_hooks';\n\nexport class AsyncLocalStorageTransactionContextPropagator implements TransactionContextPropagator {\n private asyncLocalStorage = new AsyncLocalStorage<EvaluationContext>();\n\n getTransactionContext(): EvaluationContext {\n return this.asyncLocalStorage.getStore() ?? {};\n }\n\n setTransactionContext<TArgs extends unknown[], R>(\n transactionContext: TransactionContext,\n callback: (...args: TArgs) => R,\n ...args: TArgs\n ): void {\n this.asyncLocalStorage.run(transactionContext, callback, ...args);\n }\n}\n", "export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from './events';\nexport * from './hooks';\nexport * from '@openfeature/core';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["ErrorCode", "StandardResolutionReasons", "OpenFeatureError", "OpenFeatureError", "ErrorCode", "StandardResolutionReasons", "err"]
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _openfeature_core from '@openfeature/core';
|
|
2
|
+
import { BaseHook, FlagValue, EvaluationContext, HookHints, EvaluationDetails, JsonValue, CommonProvider, ServerProviderStatus, Logger, ResolutionDetails, GenericEventEmitter, ServerProviderEvents, EvaluationLifeCycle, ManageContext, ManageLogger, Eventing, ClientMetadata, EventHandler, OpenFeatureCommonAPI, ProviderWrapper } from '@openfeature/core';
|
|
2
3
|
export * from '@openfeature/core';
|
|
3
|
-
export { ServerProviderEvents as ProviderEvents } from '@openfeature/core';
|
|
4
|
-
import EventEmitter from 'events';
|
|
4
|
+
export { ServerProviderEvents as ProviderEvents, ServerProviderStatus as ProviderStatus } from '@openfeature/core';
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
5
6
|
|
|
6
7
|
type Hook = BaseHook<FlagValue, Promise<EvaluationContext | void> | EvaluationContext | void, Promise<void> | void>;
|
|
7
8
|
|
|
@@ -96,37 +97,13 @@ interface Features {
|
|
|
96
97
|
getObjectDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<EvaluationDetails<T>>;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
interface Client extends EvaluationLifeCycle<Client>, Features, ManageContext<Client>, ManageLogger<Client>, Eventing {
|
|
100
|
-
readonly metadata: ClientMetadata;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* The OpenFeatureEventEmitter can be used by provider developers to emit
|
|
105
|
-
* events at various parts of the provider lifecycle.
|
|
106
|
-
*
|
|
107
|
-
* NOTE: Ready and error events are automatically emitted by the SDK based on
|
|
108
|
-
* the result of the initialize method.
|
|
109
|
-
*/
|
|
110
|
-
declare class OpenFeatureEventEmitter extends GenericEventEmitter<ServerProviderEvents> {
|
|
111
|
-
protected readonly eventEmitter: EventEmitter;
|
|
112
|
-
constructor();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* The InternalEventEmitter is not exported publicly and should only be used within the SDK. It extends the
|
|
117
|
-
* OpenFeatureEventEmitter to include additional properties that can be included
|
|
118
|
-
* in the event details.
|
|
119
|
-
*/
|
|
120
|
-
declare abstract class InternalEventEmitter extends GenericEventEmitter<ServerProviderEvents> {
|
|
121
|
-
}
|
|
122
|
-
|
|
123
100
|
/**
|
|
124
101
|
* Interface that providers must implement to resolve flag values for their particular
|
|
125
102
|
* backend or vendor.
|
|
126
103
|
*
|
|
127
104
|
* Implementation for resolving all the required flag types must be defined.
|
|
128
105
|
*/
|
|
129
|
-
interface Provider extends CommonProvider {
|
|
106
|
+
interface Provider extends CommonProvider<ServerProviderStatus> {
|
|
130
107
|
/**
|
|
131
108
|
* A provider hook exposes a mechanism for provider authors to register hooks
|
|
132
109
|
* to tap into various stages of the flag evaluation lifecycle. These hooks can
|
|
@@ -159,7 +136,6 @@ declare class NoopFeatureProvider implements Provider {
|
|
|
159
136
|
readonly metadata: {
|
|
160
137
|
readonly name: "No-op Provider";
|
|
161
138
|
};
|
|
162
|
-
get status(): ProviderStatus;
|
|
163
139
|
resolveBooleanEvaluation(_: string, defaultValue: boolean): Promise<ResolutionDetails<boolean>>;
|
|
164
140
|
resolveStringEvaluation(_: string, defaultValue: string): Promise<ResolutionDetails<string>>;
|
|
165
141
|
resolveNumberEvaluation(_: string, defaultValue: number): Promise<ResolutionDetails<number>>;
|
|
@@ -226,6 +202,34 @@ declare class InMemoryProvider implements Provider {
|
|
|
226
202
|
private lookupFlagValue;
|
|
227
203
|
}
|
|
228
204
|
|
|
205
|
+
/**
|
|
206
|
+
* The OpenFeatureEventEmitter can be used by provider developers to emit
|
|
207
|
+
* events at various parts of the provider lifecycle.
|
|
208
|
+
*
|
|
209
|
+
* NOTE: Ready and error events are automatically emitted by the SDK based on
|
|
210
|
+
* the result of the initialize method.
|
|
211
|
+
*/
|
|
212
|
+
declare class OpenFeatureEventEmitter extends GenericEventEmitter<ServerProviderEvents> {
|
|
213
|
+
protected readonly eventEmitter: EventEmitter;
|
|
214
|
+
constructor();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface Client extends EvaluationLifeCycle<Client>, Features, ManageContext<Client>, ManageLogger<Client>, Eventing<ServerProviderEvents> {
|
|
218
|
+
readonly metadata: ClientMetadata;
|
|
219
|
+
/**
|
|
220
|
+
* Returns the status of the associated provider.
|
|
221
|
+
*/
|
|
222
|
+
readonly providerStatus: ServerProviderStatus;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The InternalEventEmitter is not exported publicly and should only be used within the SDK. It extends the
|
|
227
|
+
* OpenFeatureEventEmitter to include additional properties that can be included
|
|
228
|
+
* in the event details.
|
|
229
|
+
*/
|
|
230
|
+
declare abstract class InternalEventEmitter extends GenericEventEmitter<ServerProviderEvents> {
|
|
231
|
+
}
|
|
232
|
+
|
|
229
233
|
type OpenFeatureClientOptions = {
|
|
230
234
|
/**
|
|
231
235
|
* @deprecated Use `domain` instead.
|
|
@@ -236,17 +240,19 @@ type OpenFeatureClientOptions = {
|
|
|
236
240
|
};
|
|
237
241
|
declare class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> {
|
|
238
242
|
private readonly providerAccessor;
|
|
243
|
+
private readonly providerStatusAccessor;
|
|
239
244
|
private readonly emitterAccessor;
|
|
240
245
|
private readonly globalLogger;
|
|
241
246
|
private readonly options;
|
|
242
247
|
private _context;
|
|
243
248
|
private _hooks;
|
|
244
249
|
private _clientLogger?;
|
|
245
|
-
constructor(providerAccessor: () => Provider, emitterAccessor: () => InternalEventEmitter, globalLogger: () => Logger, options: OpenFeatureClientOptions, context?: EvaluationContext);
|
|
250
|
+
constructor(providerAccessor: () => Provider, providerStatusAccessor: () => ServerProviderStatus, emitterAccessor: () => InternalEventEmitter, globalLogger: () => Logger, options: OpenFeatureClientOptions, context?: EvaluationContext);
|
|
246
251
|
get metadata(): ClientMetadata;
|
|
252
|
+
get providerStatus(): ServerProviderStatus;
|
|
247
253
|
addHandler(eventType: ServerProviderEvents, handler: EventHandler): void;
|
|
248
254
|
removeHandler(eventType: ServerProviderEvents, handler: EventHandler): void;
|
|
249
|
-
getHandlers(eventType: ServerProviderEvents): EventHandler[];
|
|
255
|
+
getHandlers(eventType: ServerProviderEvents): EventHandler<ServerProviderEvents | _openfeature_core.AllProviderEvents>[];
|
|
250
256
|
setLogger(logger: Logger): OpenFeatureClient;
|
|
251
257
|
setContext(context: EvaluationContext): OpenFeatureClient;
|
|
252
258
|
getContext(): EvaluationContext;
|
|
@@ -267,6 +273,7 @@ declare class OpenFeatureClient implements Client, ManageContext<OpenFeatureClie
|
|
|
267
273
|
private errorHooks;
|
|
268
274
|
private finallyHooks;
|
|
269
275
|
private get _provider();
|
|
276
|
+
private get _providerStatus();
|
|
270
277
|
private get _logger();
|
|
271
278
|
}
|
|
272
279
|
|
|
@@ -278,13 +285,9 @@ declare class OpenFeatureClient implements Client, ManageContext<OpenFeatureClie
|
|
|
278
285
|
type TransactionContext = EvaluationContext;
|
|
279
286
|
interface ManageTransactionContextPropagator<T> extends TransactionContextPropagator {
|
|
280
287
|
/**
|
|
281
|
-
* EXPERIMENTAL: Transaction context propagation is experimental and subject to change.
|
|
282
|
-
* The OpenFeature Enhancement Proposal regarding transaction context can be found [here](https://github.com/open-feature/ofep/pull/32).
|
|
283
|
-
*
|
|
284
288
|
* Sets a transaction context propagator on this receiver. The transaction context
|
|
285
289
|
* propagator is responsible for persisting context for the duration of a single
|
|
286
290
|
* transaction.
|
|
287
|
-
* @experimental
|
|
288
291
|
* @template T The type of the receiver
|
|
289
292
|
* @param {TransactionContextPropagator} transactionContextPropagator The context propagator to be used
|
|
290
293
|
* @returns {T} The receiver (this object)
|
|
@@ -293,38 +296,59 @@ interface ManageTransactionContextPropagator<T> extends TransactionContextPropag
|
|
|
293
296
|
}
|
|
294
297
|
interface TransactionContextPropagator {
|
|
295
298
|
/**
|
|
296
|
-
* EXPERIMENTAL: Transaction context propagation is experimental and subject to change.
|
|
297
|
-
* The OpenFeature Enhancement Proposal regarding transaction context can be found [here](https://github.com/open-feature/ofep/pull/32).
|
|
298
|
-
*
|
|
299
299
|
* Returns the currently defined transaction context using the registered transaction
|
|
300
300
|
* context propagator.
|
|
301
|
-
* @experimental
|
|
302
301
|
* @returns {TransactionContext} The current transaction context
|
|
303
302
|
*/
|
|
304
303
|
getTransactionContext(): TransactionContext;
|
|
305
304
|
/**
|
|
306
|
-
* EXPERIMENTAL: Transaction context propagation is experimental and subject to change.
|
|
307
|
-
* The OpenFeature Enhancement Proposal regarding transaction context can be found [here](https://github.com/open-feature/ofep/pull/32).
|
|
308
|
-
*
|
|
309
305
|
* Sets the transaction context using the registered transaction context propagator.
|
|
310
|
-
* @
|
|
306
|
+
* Runs the {@link callback} function, in which the {@link transactionContext} will be available by calling
|
|
307
|
+
* {@link this#getTransactionContext}.
|
|
308
|
+
*
|
|
309
|
+
* The {@link TransactionContextPropagator} must persist the {@link transactionContext} and make it available
|
|
310
|
+
* to {@link callback} via {@link this#getTransactionContext}.
|
|
311
|
+
*
|
|
312
|
+
* The precedence of merging context can be seen in {@link https://openfeature.dev/specification/sections/evaluation-context#requirement-323 the specification}.
|
|
313
|
+
*
|
|
314
|
+
* Example:
|
|
315
|
+
*
|
|
316
|
+
* ```js
|
|
317
|
+
* app.use((req: Request, res: Response, next: NextFunction) => {
|
|
318
|
+
* const ip = res.headers.get("X-Forwarded-For")
|
|
319
|
+
* OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => {
|
|
320
|
+
* // The transaction context is used in any flag evaluation throughout the whole call chain of next
|
|
321
|
+
* next();
|
|
322
|
+
* });
|
|
323
|
+
* })
|
|
324
|
+
*
|
|
325
|
+
* ```
|
|
326
|
+
* @template TArgs The optional args passed to the callback function
|
|
311
327
|
* @template R The return value of the callback
|
|
312
328
|
* @param {TransactionContext} transactionContext The transaction specific context
|
|
313
|
-
* @param {(...args: unknown[]) => R} callback Callback function
|
|
329
|
+
* @param {(...args: unknown[]) => R} callback Callback function to run
|
|
314
330
|
* @param {...unknown[]} args Optional arguments that are passed to the callback function
|
|
315
331
|
*/
|
|
316
|
-
setTransactionContext<R>(transactionContext: TransactionContext, callback: (...args:
|
|
332
|
+
setTransactionContext<TArgs extends unknown[], R>(transactionContext: TransactionContext, callback: (...args: TArgs) => R, ...args: TArgs): void;
|
|
317
333
|
}
|
|
318
334
|
|
|
319
335
|
declare class NoopTransactionContextPropagator implements TransactionContextPropagator {
|
|
320
336
|
getTransactionContext(): EvaluationContext;
|
|
321
|
-
setTransactionContext(_:
|
|
337
|
+
setTransactionContext<TArgs extends unknown[], R>(_: TransactionContext, callback: (...args: TArgs) => R, ...args: TArgs): void;
|
|
322
338
|
}
|
|
323
339
|
declare const NOOP_TRANSACTION_CONTEXT_PROPAGATOR: NoopTransactionContextPropagator;
|
|
324
340
|
|
|
325
|
-
declare class
|
|
326
|
-
|
|
327
|
-
|
|
341
|
+
declare class AsyncLocalStorageTransactionContextPropagator implements TransactionContextPropagator {
|
|
342
|
+
private asyncLocalStorage;
|
|
343
|
+
getTransactionContext(): EvaluationContext;
|
|
344
|
+
setTransactionContext<TArgs extends unknown[], R>(transactionContext: TransactionContext, callback: (...args: TArgs) => R, ...args: TArgs): void;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
declare class OpenFeatureAPI extends OpenFeatureCommonAPI<ServerProviderStatus, Provider, Hook> implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<ServerProviderStatus, Provider>> {
|
|
348
|
+
protected _statusEnumType: typeof ServerProviderStatus;
|
|
349
|
+
protected _apiEmitter: OpenFeatureEventEmitter;
|
|
350
|
+
protected _defaultProvider: ProviderWrapper<Provider, ServerProviderStatus>;
|
|
351
|
+
protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ServerProviderStatus>>;
|
|
328
352
|
protected _createEventEmitter: () => OpenFeatureEventEmitter;
|
|
329
353
|
private _transactionContextPropagator;
|
|
330
354
|
private constructor();
|
|
@@ -334,6 +358,7 @@ declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider, Hook> implem
|
|
|
334
358
|
* @returns {OpenFeatureAPI} OpenFeature API
|
|
335
359
|
*/
|
|
336
360
|
static getInstance(): OpenFeatureAPI;
|
|
361
|
+
private getProviderStatus;
|
|
337
362
|
setContext(context: EvaluationContext): this;
|
|
338
363
|
getContext(): EvaluationContext;
|
|
339
364
|
/**
|
|
@@ -376,8 +401,8 @@ declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider, Hook> implem
|
|
|
376
401
|
* @returns {Promise<void>}
|
|
377
402
|
*/
|
|
378
403
|
clearProviders(): Promise<void>;
|
|
379
|
-
setTransactionContextPropagator(transactionContextPropagator: TransactionContextPropagator): OpenFeatureCommonAPI<Provider>;
|
|
380
|
-
setTransactionContext<R>(transactionContext: TransactionContext, callback: (...args:
|
|
404
|
+
setTransactionContextPropagator(transactionContextPropagator: TransactionContextPropagator): OpenFeatureCommonAPI<ServerProviderStatus, Provider>;
|
|
405
|
+
setTransactionContext<TArgs extends unknown[], R>(transactionContext: TransactionContext, callback: (...args: TArgs) => R, ...args: TArgs): void;
|
|
381
406
|
getTransactionContext(): TransactionContext;
|
|
382
407
|
}
|
|
383
408
|
/**
|
|
@@ -386,4 +411,4 @@ declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider, Hook> implem
|
|
|
386
411
|
*/
|
|
387
412
|
declare const OpenFeature: OpenFeatureAPI;
|
|
388
413
|
|
|
389
|
-
export { Client, Features, FlagEvaluationOptions, Hook, InMemoryProvider, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureEventEmitter, Provider, TransactionContext, TransactionContextPropagator };
|
|
414
|
+
export { AsyncLocalStorageTransactionContextPropagator, Client, Features, FlagEvaluationOptions, Hook, InMemoryProvider, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureEventEmitter, Provider, TransactionContext, TransactionContextPropagator };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfeature/server-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "OpenFeature SDK for JavaScript",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"files": [
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"node": ">=16"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@openfeature/core": "0.0.
|
|
51
|
+
"@openfeature/core": "0.0.27"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@openfeature/core": "0.0.
|
|
54
|
+
"@openfeature/core": "0.0.27"
|
|
55
55
|
}
|
|
56
56
|
}
|