@openfeature/server-sdk 1.7.0 → 1.7.2
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 +29 -9
- package/dist/cjs/index.js +42 -14
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/index.js +19 -3
- package/dist/esm/index.js.map +3 -3
- package/dist/types.d.ts +587 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
<!-- x-hide-in-docs-end -->
|
|
13
13
|
<!-- The 'github-badges' class is used in the docs -->
|
|
14
14
|
<p align="center" class="github-badges">
|
|
15
|
-
<a href="https://github.com/open-feature/spec/
|
|
15
|
+
<a href="https://github.com/open-feature/spec/releases/tag/v0.7.0">
|
|
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.7.
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.7.
|
|
19
|
+
<a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.7.2">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.7.2&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
</p>
|
|
37
37
|
<!-- x-hide-in-docs-start -->
|
|
38
38
|
|
|
39
|
-
[OpenFeature](https://openfeature.dev) is an open
|
|
39
|
+
[OpenFeature](https://openfeature.dev) is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.
|
|
40
40
|
|
|
41
41
|
<!-- x-hide-in-docs-end -->
|
|
42
42
|
|
|
@@ -57,7 +57,8 @@ npm install --save @openfeature/server-sdk
|
|
|
57
57
|
#### yarn
|
|
58
58
|
|
|
59
59
|
```sh
|
|
60
|
-
yarn
|
|
60
|
+
# yarn requires manual installation of the @openfeature/core peer-dependency
|
|
61
|
+
yarn add @openfeature/server-sdk @openfeature/core
|
|
61
62
|
```
|
|
62
63
|
|
|
63
64
|
### Usage
|
|
@@ -66,7 +67,7 @@ yarn add @openfeature/server-sdk
|
|
|
66
67
|
import { OpenFeature } from '@openfeature/server-sdk';
|
|
67
68
|
|
|
68
69
|
// Register your feature flag provider
|
|
69
|
-
OpenFeature.
|
|
70
|
+
await OpenFeature.setProviderAndWait(new YourProviderOfChoice());
|
|
70
71
|
|
|
71
72
|
// create a new client
|
|
72
73
|
const client = OpenFeature.getClient();
|
|
@@ -106,10 +107,24 @@ If the provider you're looking for hasn't been created yet, see the [develop a p
|
|
|
106
107
|
|
|
107
108
|
Once you've added a provider as a dependency, it can be registered with OpenFeature like this:
|
|
108
109
|
|
|
110
|
+
#### Awaitable
|
|
111
|
+
|
|
112
|
+
To register a provider and ensure it is ready before further actions are taken, you can use the `setProviderAndWait` method as shown below:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
await OpenFeature.setProviderAndWait(new MyProvider());
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Synchronous
|
|
119
|
+
|
|
120
|
+
To register a provider in a synchronous manner, you can use the `setProvider` method as shown below:
|
|
121
|
+
|
|
109
122
|
```ts
|
|
110
|
-
OpenFeature.setProvider(new MyProvider())
|
|
123
|
+
OpenFeature.setProvider(new MyProvider());
|
|
111
124
|
```
|
|
112
125
|
|
|
126
|
+
Once the provider has been registered, the status can be tracked using [events](#eventing).
|
|
127
|
+
|
|
113
128
|
In some situations, it may be beneficial to register multiple providers in the same application.
|
|
114
129
|
This is possible using [named clients](#named-clients), which is covered in more details below.
|
|
115
130
|
|
|
@@ -210,6 +225,9 @@ const clientWithDefault = OpenFeature.getClient();
|
|
|
210
225
|
const clientForCache = OpenFeature.getClient("otherClient");
|
|
211
226
|
```
|
|
212
227
|
|
|
228
|
+
Named providers can be set in an awaitable or synchronous way.
|
|
229
|
+
For more details, please refer to the [providers](#providers) section.
|
|
230
|
+
|
|
213
231
|
### Eventing
|
|
214
232
|
|
|
215
233
|
Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions.
|
|
@@ -223,13 +241,13 @@ import { OpenFeature, ProviderEvents } from '@openfeature/server-sdk';
|
|
|
223
241
|
|
|
224
242
|
// OpenFeature API
|
|
225
243
|
OpenFeature.addHandler(ProviderEvents.Ready, (eventDetails) => {
|
|
226
|
-
console.log(`Ready event from: ${eventDetails?.
|
|
244
|
+
console.log(`Ready event from: ${eventDetails?.providerName}:`, eventDetails);
|
|
227
245
|
});
|
|
228
246
|
|
|
229
247
|
// Specific client
|
|
230
248
|
const client = OpenFeature.getClient();
|
|
231
249
|
client.addHandler(ProviderEvents.Error, (eventDetails) => {
|
|
232
|
-
console.log(`Error event from: ${eventDetails?.
|
|
250
|
+
console.log(`Error event from: ${eventDetails?.providerName}:`, eventDetails);
|
|
233
251
|
});
|
|
234
252
|
```
|
|
235
253
|
|
|
@@ -257,6 +275,8 @@ import { JsonValue, Provider, ResolutionDetails } from '@openfeature/server-sdk'
|
|
|
257
275
|
|
|
258
276
|
// implement the provider interface
|
|
259
277
|
class MyProvider implements Provider {
|
|
278
|
+
// Adds runtime validation that the provider is used with the expected SDK
|
|
279
|
+
public readonly runsOn = 'server';
|
|
260
280
|
|
|
261
281
|
readonly metadata = {
|
|
262
282
|
name: 'My Provider',
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __defProps = Object.defineProperties;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
8
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
11
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
12
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -33,6 +35,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
33
35
|
return to;
|
|
34
36
|
};
|
|
35
37
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
38
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
39
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
40
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
41
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
42
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
43
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
44
|
+
mod
|
|
45
|
+
));
|
|
36
46
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
47
|
var __async = (__this, __arguments, generator) => {
|
|
38
48
|
return new Promise((resolve, reject) => {
|
|
@@ -63,12 +73,13 @@ __export(src_exports, {
|
|
|
63
73
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR: () => NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
64
74
|
OpenFeature: () => OpenFeature,
|
|
65
75
|
OpenFeatureAPI: () => OpenFeatureAPI,
|
|
66
|
-
OpenFeatureClient: () => OpenFeatureClient
|
|
76
|
+
OpenFeatureClient: () => OpenFeatureClient,
|
|
77
|
+
OpenFeatureEventEmitter: () => OpenFeatureEventEmitter
|
|
67
78
|
});
|
|
68
79
|
module.exports = __toCommonJS(src_exports);
|
|
69
80
|
|
|
70
81
|
// src/client/open-feature-client.ts
|
|
71
|
-
var
|
|
82
|
+
var import_core6 = require("@openfeature/core");
|
|
72
83
|
|
|
73
84
|
// src/provider/no-op-provider.ts
|
|
74
85
|
var import_core = require("@openfeature/core");
|
|
@@ -120,7 +131,7 @@ var VariantFoundError = class extends import_core2.OpenFeatureError {
|
|
|
120
131
|
// src/provider/in-memory-provider/in-memory-provider.ts
|
|
121
132
|
var InMemoryProvider = class {
|
|
122
133
|
constructor(flagConfiguration = {}) {
|
|
123
|
-
this.events = new
|
|
134
|
+
this.events = new OpenFeatureEventEmitter();
|
|
124
135
|
this.runsOn = "server";
|
|
125
136
|
this.metadata = {
|
|
126
137
|
name: "in-memory"
|
|
@@ -196,7 +207,7 @@ var InMemoryProvider = class {
|
|
|
196
207
|
};
|
|
197
208
|
|
|
198
209
|
// src/open-feature.ts
|
|
199
|
-
var
|
|
210
|
+
var import_core5 = require("@openfeature/core");
|
|
200
211
|
|
|
201
212
|
// src/transaction-context/no-op-transaction-context-propagator.ts
|
|
202
213
|
var NoopTransactionContextPropagator = class {
|
|
@@ -209,14 +220,30 @@ var NoopTransactionContextPropagator = class {
|
|
|
209
220
|
};
|
|
210
221
|
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
|
|
211
222
|
|
|
223
|
+
// src/events/open-feature-event-emitter.ts
|
|
224
|
+
var import_core4 = require("@openfeature/core");
|
|
225
|
+
var import_events = __toESM(require("events"));
|
|
226
|
+
var OpenFeatureEventEmitter = class extends import_core4.GenericEventEmitter {
|
|
227
|
+
constructor() {
|
|
228
|
+
super();
|
|
229
|
+
this.eventEmitter = new import_events.default({ captureRejections: true });
|
|
230
|
+
this.eventEmitter.on("error", (err) => {
|
|
231
|
+
var _a;
|
|
232
|
+
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
212
237
|
// src/open-feature.ts
|
|
213
238
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api");
|
|
214
239
|
var _globalThis = globalThis;
|
|
215
|
-
var OpenFeatureAPI = class extends
|
|
240
|
+
var OpenFeatureAPI = class extends import_core5.OpenFeatureCommonAPI {
|
|
216
241
|
constructor() {
|
|
217
242
|
super("server");
|
|
218
|
-
this.
|
|
243
|
+
this._events = new OpenFeatureEventEmitter();
|
|
219
244
|
this._defaultProvider = NOOP_PROVIDER;
|
|
245
|
+
this._createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
246
|
+
this._transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
|
|
220
247
|
}
|
|
221
248
|
/**
|
|
222
249
|
* Gets a singleton instance of the OpenFeature API.
|
|
@@ -241,9 +268,9 @@ var OpenFeatureAPI = class extends import_core4.OpenFeatureCommonAPI {
|
|
|
241
268
|
}
|
|
242
269
|
getClient(nameOrContext, versionOrContext, contextOrUndefined) {
|
|
243
270
|
var _a, _b;
|
|
244
|
-
const name = (0,
|
|
245
|
-
const version = (0,
|
|
246
|
-
const context = (_b = (_a = (0,
|
|
271
|
+
const name = (0, import_core5.stringOrUndefined)(nameOrContext);
|
|
272
|
+
const version = (0, import_core5.stringOrUndefined)(versionOrContext);
|
|
273
|
+
const context = (_b = (_a = (0, import_core5.objectOrUndefined)(nameOrContext)) != null ? _a : (0, import_core5.objectOrUndefined)(versionOrContext)) != null ? _b : (0, import_core5.objectOrUndefined)(contextOrUndefined);
|
|
247
274
|
return new OpenFeatureClient(
|
|
248
275
|
() => this.getProviderForClient(name),
|
|
249
276
|
() => this.buildAndCacheEventEmitterForClient(name),
|
|
@@ -306,7 +333,7 @@ var OpenFeatureClient = class {
|
|
|
306
333
|
addHandler(eventType, handler) {
|
|
307
334
|
var _a;
|
|
308
335
|
this.emitterAccessor().addHandler(eventType, handler);
|
|
309
|
-
const shouldRunNow = (0,
|
|
336
|
+
const shouldRunNow = (0, import_core6.statusMatchesEvent)(eventType, this._provider.status);
|
|
310
337
|
if (shouldRunNow) {
|
|
311
338
|
try {
|
|
312
339
|
handler({ clientName: this.metadata.name, providerName: this._provider.metadata.name });
|
|
@@ -322,7 +349,7 @@ var OpenFeatureClient = class {
|
|
|
322
349
|
return this.emitterAccessor().getHandlers(eventType);
|
|
323
350
|
}
|
|
324
351
|
setLogger(logger) {
|
|
325
|
-
this._clientLogger = new
|
|
352
|
+
this._clientLogger = new import_core6.SafeLogger(logger);
|
|
326
353
|
return this;
|
|
327
354
|
}
|
|
328
355
|
setContext(context) {
|
|
@@ -429,13 +456,13 @@ var OpenFeatureClient = class {
|
|
|
429
456
|
return evaluationDetails;
|
|
430
457
|
} catch (err) {
|
|
431
458
|
const errorMessage = err == null ? void 0 : err.message;
|
|
432
|
-
const errorCode = (err == null ? void 0 : err.code) ||
|
|
459
|
+
const errorCode = (err == null ? void 0 : err.code) || import_core6.ErrorCode.GENERAL;
|
|
433
460
|
yield this.errorHooks(allHooksReversed, hookContext, err, options);
|
|
434
461
|
return {
|
|
435
462
|
errorCode,
|
|
436
463
|
errorMessage,
|
|
437
464
|
value: defaultValue,
|
|
438
|
-
reason:
|
|
465
|
+
reason: import_core6.StandardResolutionReasons.ERROR,
|
|
439
466
|
flagMetadata: Object.freeze({}),
|
|
440
467
|
flagKey
|
|
441
468
|
};
|
|
@@ -511,6 +538,7 @@ __reExport(src_exports, require("@openfeature/core"), module.exports);
|
|
|
511
538
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
512
539
|
OpenFeature,
|
|
513
540
|
OpenFeatureAPI,
|
|
514
|
-
OpenFeatureClient
|
|
541
|
+
OpenFeatureClient,
|
|
542
|
+
OpenFeatureEventEmitter
|
|
515
543
|
});
|
|
516
544
|
//# 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/open-feature.ts", "../../src/transaction-context/no-op-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 '@openfeature/core';\n", "import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n Hook,\n HookContext,\n InternalEventEmitter,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderEvents,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n name?: 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 name: this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): 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({ clientName: this.metadata.name, providerName: this._provider.metadata.name });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>) {\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<FlagValue>[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook<FlagValue>[] {\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 OpenFeatureEventEmitter,\n ProviderEvents,\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';\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';\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>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<Provider>>\n{\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n protected _defaultProvider: Provider = NOOP_PROVIDER;\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 unnamed OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * All unnamed clients use the same 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 named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, version: string, context?: EvaluationContext): Client;\n getClient(\n nameOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext\n ): Client {\n const name = stringOrUndefined(nameOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(nameOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(name),\n () => this.buildAndCacheEventEmitterForClient(name),\n () => this._logger,\n { name, 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"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["import_core", "import_core", "import_core", "import_core", "err"]
|
|
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/open-feature.ts", "../../src/transaction-context/no-op-transaction-context-propagator.ts", "../../src/events/open-feature-event-emitter.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 '@openfeature/core';\n", "import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n Hook,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderEvents,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\n\ntype OpenFeatureClientOptions = {\n name?: 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 name: this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): 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({ clientName: this.metadata.name, providerName: this._provider.metadata.name });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>) {\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<FlagValue>[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook<FlagValue>[] {\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 ProviderEvents,\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 } 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';\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>\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 unnamed OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * All unnamed clients use the same 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 named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, version: string, context?: EvaluationContext): Client;\n getClient(\n nameOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext\n ): Client {\n const name = stringOrUndefined(nameOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(nameOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(name),\n () => this.buildAndCacheEventEmitterForClient(name),\n () => this._logger,\n { name, 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';\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 {\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};"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_core", "import_core", "import_core", "import_core", "import_core", "EventEmitter", "err"]
|
|
7
7
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -84,7 +84,6 @@ import {
|
|
|
84
84
|
FlagNotFoundError,
|
|
85
85
|
GeneralError,
|
|
86
86
|
OpenFeatureError as OpenFeatureError2,
|
|
87
|
-
OpenFeatureEventEmitter,
|
|
88
87
|
ProviderEvents,
|
|
89
88
|
StandardResolutionReasons,
|
|
90
89
|
TypeMismatchError
|
|
@@ -197,14 +196,30 @@ var NoopTransactionContextPropagator = class {
|
|
|
197
196
|
};
|
|
198
197
|
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
|
|
199
198
|
|
|
199
|
+
// src/events/open-feature-event-emitter.ts
|
|
200
|
+
import { GenericEventEmitter } from "@openfeature/core";
|
|
201
|
+
import EventEmitter from "events";
|
|
202
|
+
var OpenFeatureEventEmitter = class extends GenericEventEmitter {
|
|
203
|
+
constructor() {
|
|
204
|
+
super();
|
|
205
|
+
this.eventEmitter = new EventEmitter({ captureRejections: true });
|
|
206
|
+
this.eventEmitter.on("error", (err) => {
|
|
207
|
+
var _a;
|
|
208
|
+
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
200
213
|
// src/open-feature.ts
|
|
201
214
|
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api");
|
|
202
215
|
var _globalThis = globalThis;
|
|
203
216
|
var OpenFeatureAPI = class extends OpenFeatureCommonAPI {
|
|
204
217
|
constructor() {
|
|
205
218
|
super("server");
|
|
206
|
-
this.
|
|
219
|
+
this._events = new OpenFeatureEventEmitter();
|
|
207
220
|
this._defaultProvider = NOOP_PROVIDER;
|
|
221
|
+
this._createEventEmitter = () => new OpenFeatureEventEmitter();
|
|
222
|
+
this._transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
|
|
208
223
|
}
|
|
209
224
|
/**
|
|
210
225
|
* Gets a singleton instance of the OpenFeature API.
|
|
@@ -498,6 +513,7 @@ export {
|
|
|
498
513
|
NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
|
|
499
514
|
OpenFeature,
|
|
500
515
|
OpenFeatureAPI,
|
|
501
|
-
OpenFeatureClient
|
|
516
|
+
OpenFeatureClient,
|
|
517
|
+
OpenFeatureEventEmitter
|
|
502
518
|
};
|
|
503
519
|
//# 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/open-feature.ts", "../../src/transaction-context/no-op-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 Hook,\n HookContext,\n InternalEventEmitter,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderEvents,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\n\ntype OpenFeatureClientOptions = {\n name?: 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 name: this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): 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({ clientName: this.metadata.name, providerName: this._provider.metadata.name });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>) {\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<FlagValue>[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook<FlagValue>[] {\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 OpenFeatureEventEmitter,\n ProviderEvents,\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';\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';\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>\n implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<Provider>>\n{\n private _transactionContextPropagator: TransactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;\n protected _defaultProvider: Provider = NOOP_PROVIDER;\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 unnamed OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * All unnamed clients use the same 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 named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, version: string, context?: EvaluationContext): Client;\n getClient(\n nameOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext\n ): Client {\n const name = stringOrUndefined(nameOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(nameOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(name),\n () => this.buildAndCacheEventEmitterForClient(name),\n () => this._logger,\n { name, 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", "export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from '@openfeature/core';\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,EAEE,aAAAA;AAAA,
|
|
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/open-feature.ts", "../../src/transaction-context/no-op-transaction-context-propagator.ts", "../../src/events/open-feature-event-emitter.ts", "../../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n ClientMetadata,\n ErrorCode,\n EvaluationContext,\n EvaluationDetails,\n EventHandler,\n FlagValue,\n FlagValueType,\n Hook,\n HookContext,\n JsonValue,\n Logger,\n ManageContext,\n OpenFeatureError,\n ProviderEvents,\n ResolutionDetails,\n SafeLogger,\n StandardResolutionReasons,\n statusMatchesEvent\n} from '@openfeature/core';\nimport { FlagEvaluationOptions } from '../evaluation';\nimport { OpenFeature } from '../open-feature';\nimport { Provider } from '../provider';\nimport { Client } from './client';\nimport { InternalEventEmitter } from '../events/internal/internal-event-emitter';\n\ntype OpenFeatureClientOptions = {\n name?: 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 name: this.options.name,\n version: this.options.version,\n providerMetadata: this.providerAccessor().metadata,\n };\n }\n\n addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): 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({ clientName: this.metadata.name, providerName: this._provider.metadata.name });\n } catch (err) {\n this._logger?.error('Error running event handler:', err);\n }\n }\n }\n\n removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>) {\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<FlagValue>[]): OpenFeatureClient {\n this._hooks = [...this._hooks, ...hooks];\n return this;\n }\n\n getHooks(): Hook<FlagValue>[] {\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 ProviderEvents,\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 } 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';\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>\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 unnamed OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * All unnamed clients use the same 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 named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, context?: EvaluationContext): Client;\n /**\n * A factory function for creating new named OpenFeature clients. Clients can contain\n * their own state (e.g. logger, hook, context). Multiple clients can be used\n * to segment feature flag configuration.\n *\n * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.\n * Otherwise, the default provider is used until a provider is assigned to that name.\n * @param {string} name The name of the client\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(name: string, version: string, context?: EvaluationContext): Client;\n getClient(\n nameOrContext?: string | EvaluationContext,\n versionOrContext?: string | EvaluationContext,\n contextOrUndefined?: EvaluationContext\n ): Client {\n const name = stringOrUndefined(nameOrContext);\n const version = stringOrUndefined(versionOrContext);\n const context =\n objectOrUndefined<EvaluationContext>(nameOrContext) ??\n objectOrUndefined<EvaluationContext>(versionOrContext) ??\n objectOrUndefined<EvaluationContext>(contextOrUndefined);\n\n return new OpenFeatureClient(\n () => this.getProviderForClient(name),\n () => this.buildAndCacheEventEmitterForClient(name),\n () => this._logger,\n { name, 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';\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 {\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};", "export * from './client';\nexport * from './provider';\nexport * from './evaluation';\nexport * from './open-feature';\nexport * from './transaction-context';\nexport * from './events';\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,5 +1,566 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
|
|
3
|
+
type FlagValueType = 'boolean' | 'string' | 'number' | 'object';
|
|
4
|
+
type PrimitiveValue = null | boolean | string | number;
|
|
5
|
+
type JsonObject = {
|
|
6
|
+
[key: string]: JsonValue;
|
|
7
|
+
};
|
|
8
|
+
type JsonArray = JsonValue[];
|
|
9
|
+
/**
|
|
10
|
+
* Represents a JSON node value.
|
|
11
|
+
*/
|
|
12
|
+
type JsonValue = PrimitiveValue | JsonObject | JsonArray;
|
|
13
|
+
/**
|
|
14
|
+
* Represents a JSON node value, or Date.
|
|
15
|
+
*/
|
|
16
|
+
type FlagValue = boolean | string | number | JsonValue;
|
|
17
|
+
type ResolutionReason = keyof typeof StandardResolutionReasons | (string & Record<never, never>);
|
|
18
|
+
/**
|
|
19
|
+
* A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number.
|
|
20
|
+
*
|
|
21
|
+
* This structure is populated by a provider for use by an Application Author (via the Evaluation API) or an Application Integrator (via hooks).
|
|
22
|
+
*/
|
|
23
|
+
type FlagMetadata = Record<string, string | number | boolean>;
|
|
24
|
+
type ResolutionDetails<U> = {
|
|
25
|
+
value: U;
|
|
26
|
+
variant?: string;
|
|
27
|
+
flagMetadata?: FlagMetadata;
|
|
28
|
+
reason?: ResolutionReason;
|
|
29
|
+
errorCode?: ErrorCode;
|
|
30
|
+
errorMessage?: string;
|
|
31
|
+
};
|
|
32
|
+
type EvaluationDetails<T extends FlagValue> = {
|
|
33
|
+
flagKey: string;
|
|
34
|
+
flagMetadata: Readonly<FlagMetadata>;
|
|
35
|
+
} & ResolutionDetails<T>;
|
|
36
|
+
declare const StandardResolutionReasons: {
|
|
37
|
+
/**
|
|
38
|
+
* The resolved value was the result of a dynamic evaluation, such as a rule or specific user-targeting.
|
|
39
|
+
*/
|
|
40
|
+
readonly TARGETING_MATCH: "TARGETING_MATCH";
|
|
41
|
+
/**
|
|
42
|
+
* The resolved value was the result of pseudorandom assignment.
|
|
43
|
+
*/
|
|
44
|
+
readonly SPLIT: "SPLIT";
|
|
45
|
+
/**
|
|
46
|
+
* The resolved value was the result of the flag being disabled in the management system.
|
|
47
|
+
*/
|
|
48
|
+
readonly DISABLED: "DISABLED";
|
|
49
|
+
/**
|
|
50
|
+
* The resolved value was configured statically, or otherwise fell back to a pre-configured value.
|
|
51
|
+
*/
|
|
52
|
+
readonly DEFAULT: "DEFAULT";
|
|
53
|
+
/**
|
|
54
|
+
* The reason for the resolved value could not be determined.
|
|
55
|
+
*/
|
|
56
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
57
|
+
/**
|
|
58
|
+
* The resolved value is static (no dynamic evaluation).
|
|
59
|
+
*/
|
|
60
|
+
readonly STATIC: "STATIC";
|
|
61
|
+
/**
|
|
62
|
+
* The resolved value was retrieved from cache.
|
|
63
|
+
*/
|
|
64
|
+
readonly CACHED: "CACHED";
|
|
65
|
+
/**
|
|
66
|
+
* The resolved value was the result of an error.
|
|
67
|
+
*
|
|
68
|
+
* Note: The `errorCode` and `errorMessage` fields may contain additional details of this error.
|
|
69
|
+
*/
|
|
70
|
+
readonly ERROR: "ERROR";
|
|
71
|
+
};
|
|
72
|
+
declare enum ErrorCode {
|
|
73
|
+
/**
|
|
74
|
+
* The value was resolved before the provider was ready.
|
|
75
|
+
*/
|
|
76
|
+
PROVIDER_NOT_READY = "PROVIDER_NOT_READY",
|
|
77
|
+
/**
|
|
78
|
+
* The flag could not be found.
|
|
79
|
+
*/
|
|
80
|
+
FLAG_NOT_FOUND = "FLAG_NOT_FOUND",
|
|
81
|
+
/**
|
|
82
|
+
* An error was encountered parsing data, such as a flag configuration.
|
|
83
|
+
*/
|
|
84
|
+
PARSE_ERROR = "PARSE_ERROR",
|
|
85
|
+
/**
|
|
86
|
+
* The type of the flag value does not match the expected type.
|
|
87
|
+
*/
|
|
88
|
+
TYPE_MISMATCH = "TYPE_MISMATCH",
|
|
89
|
+
/**
|
|
90
|
+
* The provider requires a targeting key and one was not provided in the evaluation context.
|
|
91
|
+
*/
|
|
92
|
+
TARGETING_KEY_MISSING = "TARGETING_KEY_MISSING",
|
|
93
|
+
/**
|
|
94
|
+
* The evaluation context does not meet provider requirements.
|
|
95
|
+
*/
|
|
96
|
+
INVALID_CONTEXT = "INVALID_CONTEXT",
|
|
97
|
+
/**
|
|
98
|
+
* An error with an unspecified code.
|
|
99
|
+
*/
|
|
100
|
+
GENERAL = "GENERAL"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type EvaluationContextValue = PrimitiveValue | Date | {
|
|
104
|
+
[key: string]: EvaluationContextValue;
|
|
105
|
+
} | EvaluationContextValue[];
|
|
106
|
+
/**
|
|
107
|
+
* A container for arbitrary contextual data that can be used as a basis for dynamic evaluation
|
|
108
|
+
*/
|
|
109
|
+
type EvaluationContext = {
|
|
110
|
+
/**
|
|
111
|
+
* A string uniquely identifying the subject (end-user, or client service) of a flag evaluation.
|
|
112
|
+
* Providers may require this field for fractional flag evaluation, rules, or overrides targeting specific users.
|
|
113
|
+
* Such providers may behave unpredictably if a targeting key is not specified at flag resolution.
|
|
114
|
+
*/
|
|
115
|
+
targetingKey?: string;
|
|
116
|
+
} & Record<string, EvaluationContextValue>;
|
|
117
|
+
interface ManageContext<T> {
|
|
118
|
+
/**
|
|
119
|
+
* Access the evaluation context set on the receiver.
|
|
120
|
+
* @returns {EvaluationContext} Evaluation context
|
|
121
|
+
*/
|
|
122
|
+
getContext(): EvaluationContext;
|
|
123
|
+
/**
|
|
124
|
+
* Sets evaluation context that will be used during flag evaluations
|
|
125
|
+
* on this receiver.
|
|
126
|
+
* @template T The type of the receiver
|
|
127
|
+
* @param {EvaluationContext} context Evaluation context
|
|
128
|
+
* @returns {T} The receiver (this object)
|
|
129
|
+
*/
|
|
130
|
+
setContext(context: EvaluationContext): T;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare enum ProviderEvents {
|
|
134
|
+
/**
|
|
135
|
+
* The provider is ready to evaluate flags.
|
|
136
|
+
*/
|
|
137
|
+
Ready = "PROVIDER_READY",
|
|
138
|
+
/**
|
|
139
|
+
* The provider is in an error state.
|
|
140
|
+
*/
|
|
141
|
+
Error = "PROVIDER_ERROR",
|
|
142
|
+
/**
|
|
143
|
+
* The flag configuration in the source-of-truth has changed.
|
|
144
|
+
*/
|
|
145
|
+
ConfigurationChanged = "PROVIDER_CONFIGURATION_CHANGED",
|
|
146
|
+
/**
|
|
147
|
+
* The provider's cached state is no longer valid and may not be up-to-date with the source of truth.
|
|
148
|
+
*/
|
|
149
|
+
Stale = "PROVIDER_STALE"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Returns true if the provider's status corresponds to the event.
|
|
154
|
+
* If the provider's status is not defined, it matches READY.
|
|
155
|
+
* @param {ProviderEvents} event event to match
|
|
156
|
+
* @param {ProviderStatus} status status of provider
|
|
157
|
+
* @returns {boolean} boolean indicating if the provider status corresponds to the event.
|
|
158
|
+
*/
|
|
159
|
+
declare const statusMatchesEvent: (event: ProviderEvents, status?: ProviderStatus) => boolean;
|
|
160
|
+
|
|
161
|
+
type EventMetadata = {
|
|
162
|
+
[key: string]: string | boolean | number;
|
|
163
|
+
};
|
|
164
|
+
type CommonEventDetails = {
|
|
165
|
+
providerName: string;
|
|
166
|
+
clientName?: string;
|
|
167
|
+
};
|
|
168
|
+
type CommonEventProps = {
|
|
169
|
+
message?: string;
|
|
170
|
+
metadata?: EventMetadata;
|
|
171
|
+
};
|
|
172
|
+
type ReadyEvent = CommonEventProps;
|
|
173
|
+
type ErrorEvent = CommonEventProps;
|
|
174
|
+
type StaleEvent = CommonEventProps;
|
|
175
|
+
type ConfigChangeEvent = CommonEventProps & {
|
|
176
|
+
flagsChanged?: string[];
|
|
177
|
+
};
|
|
178
|
+
type EventMap = {
|
|
179
|
+
[ProviderEvents.Ready]: ReadyEvent;
|
|
180
|
+
[ProviderEvents.Error]: ErrorEvent;
|
|
181
|
+
[ProviderEvents.Stale]: StaleEvent;
|
|
182
|
+
[ProviderEvents.ConfigurationChanged]: ConfigChangeEvent;
|
|
183
|
+
};
|
|
184
|
+
type EventContext<T extends ProviderEvents, U extends Record<string, unknown> = Record<string, unknown>> = EventMap[T] & U;
|
|
185
|
+
type EventDetails<T extends ProviderEvents> = EventContext<T> & CommonEventDetails;
|
|
186
|
+
type EventHandler<T extends ProviderEvents> = (eventDetails?: EventDetails<T>) => Promise<unknown> | unknown;
|
|
187
|
+
interface Eventing {
|
|
188
|
+
/**
|
|
189
|
+
* Adds a handler for the given provider event type.
|
|
190
|
+
* The handlers are called in the order they have been added.
|
|
191
|
+
* @param {ProviderEvents} eventType The provider event type to listen to
|
|
192
|
+
* @param {EventHandler} handler The handler to run on occurrence of the event type
|
|
193
|
+
*/
|
|
194
|
+
addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
195
|
+
/**
|
|
196
|
+
* Removes a handler for the given provider event type.
|
|
197
|
+
* @param {ProviderEvents} eventType The provider event type to remove the listener for
|
|
198
|
+
* @param {EventHandler} handler The handler to remove for the provider event type
|
|
199
|
+
*/
|
|
200
|
+
removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
201
|
+
/**
|
|
202
|
+
* Gets the current handlers for the given provider event type.
|
|
203
|
+
* @param {ProviderEvents} eventType The provider event type to get the current handlers for
|
|
204
|
+
* @returns {EventHandler[]} The handlers currently attached to the given provider event type
|
|
205
|
+
*/
|
|
206
|
+
getHandlers<T extends ProviderEvents>(eventType: T): EventHandler<T>[];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
interface Logger {
|
|
210
|
+
error(...args: unknown[]): void;
|
|
211
|
+
warn(...args: unknown[]): void;
|
|
212
|
+
info(...args: unknown[]): void;
|
|
213
|
+
debug(...args: unknown[]): void;
|
|
214
|
+
}
|
|
215
|
+
interface ManageLogger<T> {
|
|
216
|
+
/**
|
|
217
|
+
* Sets a logger on this receiver. This logger supersedes to the global logger
|
|
218
|
+
* and is passed to various components in the SDK.
|
|
219
|
+
* The logger configured on the global API object will be used for all evaluations,
|
|
220
|
+
* unless overridden in a particular client.
|
|
221
|
+
* @template T The type of the receiver
|
|
222
|
+
* @param {Logger} logger The logger to be used
|
|
223
|
+
* @returns {T} The receiver (this object)
|
|
224
|
+
*/
|
|
225
|
+
setLogger(logger: Logger): T;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
declare class DefaultLogger implements Logger {
|
|
229
|
+
error(...args: unknown[]): void;
|
|
230
|
+
warn(...args: unknown[]): void;
|
|
231
|
+
info(): void;
|
|
232
|
+
debug(): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
declare const LOG_LEVELS: Array<keyof Logger>;
|
|
236
|
+
declare class SafeLogger implements Logger {
|
|
237
|
+
private readonly logger;
|
|
238
|
+
private readonly fallbackLogger;
|
|
239
|
+
constructor(logger: Logger);
|
|
240
|
+
error(...args: unknown[]): void;
|
|
241
|
+
warn(...args: unknown[]): void;
|
|
242
|
+
info(...args: unknown[]): void;
|
|
243
|
+
debug(...args: unknown[]): void;
|
|
244
|
+
private log;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The GenericEventEmitter should only be used within the SDK. It supports additional properties that can be included
|
|
249
|
+
* in the event details.
|
|
250
|
+
*/
|
|
251
|
+
declare abstract class GenericEventEmitter<AdditionalContext extends Record<string, unknown> = Record<string, unknown>> implements ManageLogger<GenericEventEmitter<AdditionalContext>> {
|
|
252
|
+
private readonly globalLogger?;
|
|
253
|
+
protected abstract readonly eventEmitter: NodeJS.EventEmitter;
|
|
254
|
+
private readonly _handlers;
|
|
255
|
+
private _eventLogger?;
|
|
256
|
+
constructor(globalLogger?: (() => Logger) | undefined);
|
|
257
|
+
emit<T extends ProviderEvents>(eventType: T, context?: EventContext<T, AdditionalContext>): void;
|
|
258
|
+
addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
259
|
+
removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
260
|
+
removeAllHandlers(eventType?: ProviderEvents): void;
|
|
261
|
+
getHandlers<T extends ProviderEvents>(eventType: T): EventHandler<T>[];
|
|
262
|
+
setLogger(logger: Logger): this;
|
|
263
|
+
protected get _logger(): Logger | undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
interface Metadata {
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Defines where the library is intended to be run.
|
|
271
|
+
*/
|
|
272
|
+
type Paradigm = 'server' | 'client';
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The state of the provider.
|
|
276
|
+
*/
|
|
277
|
+
declare enum ProviderStatus {
|
|
278
|
+
/**
|
|
279
|
+
* The provider has not been initialized and cannot yet evaluate flags.
|
|
280
|
+
*/
|
|
281
|
+
NOT_READY = "NOT_READY",
|
|
282
|
+
/**
|
|
283
|
+
* The provider is ready to resolve flags.
|
|
284
|
+
*/
|
|
285
|
+
READY = "READY",
|
|
286
|
+
/**
|
|
287
|
+
* The provider is in an error state and unable to evaluate flags.
|
|
288
|
+
*/
|
|
289
|
+
ERROR = "ERROR",
|
|
290
|
+
/**
|
|
291
|
+
* The provider's cached state is no longer valid and may not be up-to-date with the source of truth.
|
|
292
|
+
*/
|
|
293
|
+
STALE = "STALE"
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Static data about the provider.
|
|
297
|
+
*/
|
|
298
|
+
interface ProviderMetadata extends Metadata {
|
|
299
|
+
readonly name: string;
|
|
300
|
+
}
|
|
301
|
+
interface CommonProvider {
|
|
302
|
+
readonly metadata: ProviderMetadata;
|
|
303
|
+
/**
|
|
304
|
+
* Represents where the provider is intended to be run. If defined,
|
|
305
|
+
* the SDK will enforce that the defined paradigm at runtime.
|
|
306
|
+
*/
|
|
307
|
+
readonly runsOn?: Paradigm;
|
|
308
|
+
/**
|
|
309
|
+
* Returns a representation of the current readiness of the provider.
|
|
310
|
+
* If the provider needs to be initialized, it should return {@link ProviderStatus.READY}.
|
|
311
|
+
* If the provider is in an error state, it should return {@link ProviderStatus.ERROR}.
|
|
312
|
+
* If the provider is functioning normally, it should return {@link ProviderStatus.NOT_READY}.
|
|
313
|
+
*
|
|
314
|
+
* _Providers which do not implement this method are assumed to be ready immediately._
|
|
315
|
+
*/
|
|
316
|
+
readonly status?: ProviderStatus;
|
|
317
|
+
/**
|
|
318
|
+
* An event emitter for ProviderEvents.
|
|
319
|
+
* @see ProviderEvents
|
|
320
|
+
*/
|
|
321
|
+
events?: GenericEventEmitter;
|
|
322
|
+
/**
|
|
323
|
+
* A function used to shut down the provider.
|
|
324
|
+
* Called when this provider is replaced with a new one, or when the OpenFeature is shut down.
|
|
325
|
+
*/
|
|
326
|
+
onClose?(): Promise<void>;
|
|
327
|
+
/**
|
|
328
|
+
* A function used to setup the provider.
|
|
329
|
+
* Called by the SDK after the provider is set if the provider's status is {@link ProviderStatus.NOT_READY}.
|
|
330
|
+
* When the returned promise resolves, the SDK fires the ProviderEvents.Ready event.
|
|
331
|
+
* If the returned promise rejects, the SDK fires the ProviderEvents.Error event.
|
|
332
|
+
* Use this function to perform any context-dependent setup within the provider.
|
|
333
|
+
* @param context
|
|
334
|
+
*/
|
|
335
|
+
initialize?(context?: EvaluationContext): Promise<void>;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
interface ClientMetadata extends Metadata {
|
|
339
|
+
readonly version?: string;
|
|
340
|
+
readonly name?: string;
|
|
341
|
+
readonly providerMetadata: ProviderMetadata;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
type HookHints = Readonly<Record<string, unknown>>;
|
|
345
|
+
interface HookContext<T extends FlagValue = FlagValue> {
|
|
346
|
+
readonly flagKey: string;
|
|
347
|
+
readonly defaultValue: T;
|
|
348
|
+
readonly flagValueType: FlagValueType;
|
|
349
|
+
readonly context: Readonly<EvaluationContext>;
|
|
350
|
+
readonly clientMetadata: ClientMetadata;
|
|
351
|
+
readonly providerMetadata: ProviderMetadata;
|
|
352
|
+
readonly logger: Logger;
|
|
353
|
+
}
|
|
354
|
+
interface BeforeHookContext extends HookContext {
|
|
355
|
+
context: EvaluationContext;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
interface Hook<T extends FlagValue = FlagValue> {
|
|
359
|
+
/**
|
|
360
|
+
* Runs before flag values are resolved from the provider.
|
|
361
|
+
* If an EvaluationContext is returned, it will be merged with the pre-existing EvaluationContext.
|
|
362
|
+
* @param hookContext
|
|
363
|
+
* @param hookHints
|
|
364
|
+
*/
|
|
365
|
+
before?(hookContext: BeforeHookContext, hookHints?: HookHints): Promise<EvaluationContext | void> | EvaluationContext | void;
|
|
366
|
+
/**
|
|
367
|
+
* Runs after flag values are successfully resolved from the provider.
|
|
368
|
+
* @param hookContext
|
|
369
|
+
* @param evaluationDetails
|
|
370
|
+
* @param hookHints
|
|
371
|
+
*/
|
|
372
|
+
after?(hookContext: Readonly<HookContext<T>>, evaluationDetails: EvaluationDetails<T>, hookHints?: HookHints): Promise<void> | void;
|
|
373
|
+
/**
|
|
374
|
+
* Runs in the event of an unhandled error or promise rejection during flag resolution, or any attached hooks.
|
|
375
|
+
* @param hookContext
|
|
376
|
+
* @param error
|
|
377
|
+
* @param hookHints
|
|
378
|
+
*/
|
|
379
|
+
error?(hookContext: Readonly<HookContext<T>>, error: unknown, hookHints?: HookHints): Promise<void> | void;
|
|
380
|
+
/**
|
|
381
|
+
* Runs after all other hook stages, regardless of success or error.
|
|
382
|
+
* Errors thrown here are unhandled by the client and will surface in application code.
|
|
383
|
+
* @param hookContext
|
|
384
|
+
* @param hookHints
|
|
385
|
+
*/
|
|
386
|
+
finally?(hookContext: Readonly<HookContext<T>>, hookHints?: HookHints): Promise<void> | void;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
interface EvaluationLifeCycle<T> {
|
|
390
|
+
/**
|
|
391
|
+
* Adds hooks that will run during flag evaluations on this receiver.
|
|
392
|
+
* Hooks are executed in the order they were registered. Adding additional hooks
|
|
393
|
+
* will not remove existing hooks.
|
|
394
|
+
* Hooks registered on the global API object run with all evaluations.
|
|
395
|
+
* Hooks registered on the client run with all evaluations on that client.
|
|
396
|
+
* @template T The type of the receiver
|
|
397
|
+
* @param {Hook<FlagValue>[]} hooks A list of hooks that should always run
|
|
398
|
+
* @returns {T} The receiver (this object)
|
|
399
|
+
*/
|
|
400
|
+
addHooks(...hooks: Hook<FlagValue>[]): T;
|
|
401
|
+
/**
|
|
402
|
+
* Access all the hooks that are registered on this receiver.
|
|
403
|
+
* @returns {Hook<FlagValue>[]} A list of the client hooks
|
|
404
|
+
*/
|
|
405
|
+
getHooks(): Hook<FlagValue>[];
|
|
406
|
+
/**
|
|
407
|
+
* Clears all the hooks that are registered on this receiver.
|
|
408
|
+
* @template T The type of the receiver
|
|
409
|
+
* @returns {T} The receiver (this object)
|
|
410
|
+
*/
|
|
411
|
+
clearHooks(): T;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
declare abstract class OpenFeatureError extends Error {
|
|
415
|
+
abstract code: ErrorCode;
|
|
416
|
+
constructor(message?: string);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
declare class GeneralError extends OpenFeatureError {
|
|
420
|
+
code: ErrorCode;
|
|
421
|
+
constructor(message?: string);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
declare class FlagNotFoundError extends OpenFeatureError {
|
|
425
|
+
code: ErrorCode;
|
|
426
|
+
constructor(message?: string);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
declare class ParseError extends OpenFeatureError {
|
|
430
|
+
code: ErrorCode;
|
|
431
|
+
constructor(message?: string);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
declare class TypeMismatchError extends OpenFeatureError {
|
|
435
|
+
code: ErrorCode;
|
|
436
|
+
constructor(message?: string);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
declare class TargetingKeyMissingError extends OpenFeatureError {
|
|
440
|
+
code: ErrorCode;
|
|
441
|
+
constructor(message?: string);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
declare class InvalidContextError extends OpenFeatureError {
|
|
445
|
+
code: ErrorCode;
|
|
446
|
+
constructor(message?: string);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Checks whether the parameter is a string.
|
|
451
|
+
* @param {unknown} value The value to check
|
|
452
|
+
* @returns {value is string} True if the value is a string
|
|
453
|
+
*/
|
|
454
|
+
declare function isString(value: unknown): value is string;
|
|
455
|
+
/**
|
|
456
|
+
* Returns the parameter if it is a string, otherwise returns undefined.
|
|
457
|
+
* @param {unknown} value The value to check
|
|
458
|
+
* @returns {string|undefined} The parameter if it is a string, otherwise undefined
|
|
459
|
+
*/
|
|
460
|
+
declare function stringOrUndefined(value: unknown): string | undefined;
|
|
461
|
+
/**
|
|
462
|
+
* Checks whether the parameter is an object.
|
|
463
|
+
* @param {unknown} value The value to check
|
|
464
|
+
* @returns {value is string} True if the value is an object
|
|
465
|
+
*/
|
|
466
|
+
declare function isObject<T extends object>(value: unknown): value is T;
|
|
467
|
+
/**
|
|
468
|
+
* Returns the parameter if it is an object, otherwise returns undefined.
|
|
469
|
+
* @param {unknown} value The value to check
|
|
470
|
+
* @returns {object|undefined} The parameter if it is an object, otherwise undefined
|
|
471
|
+
*/
|
|
472
|
+
declare function objectOrUndefined<T extends object>(value: unknown): T | undefined;
|
|
473
|
+
|
|
474
|
+
declare abstract class OpenFeatureCommonAPI<P extends CommonProvider = CommonProvider> implements Eventing, EvaluationLifeCycle<OpenFeatureCommonAPI<P>>, ManageLogger<OpenFeatureCommonAPI<P>> {
|
|
475
|
+
protected abstract _createEventEmitter(): GenericEventEmitter;
|
|
476
|
+
protected abstract _defaultProvider: P;
|
|
477
|
+
protected abstract readonly _events: GenericEventEmitter;
|
|
478
|
+
protected _hooks: Hook[];
|
|
479
|
+
protected _context: EvaluationContext;
|
|
480
|
+
protected _logger: Logger;
|
|
481
|
+
private readonly _clientEventHandlers;
|
|
482
|
+
protected _clientProviders: Map<string, P>;
|
|
483
|
+
protected _clientEvents: Map<string | undefined, GenericEventEmitter>;
|
|
484
|
+
protected _runsOn: Paradigm;
|
|
485
|
+
constructor(category: Paradigm);
|
|
486
|
+
addHooks(...hooks: Hook<FlagValue>[]): this;
|
|
487
|
+
getHooks(): Hook<FlagValue>[];
|
|
488
|
+
clearHooks(): this;
|
|
489
|
+
setLogger(logger: Logger): this;
|
|
490
|
+
/**
|
|
491
|
+
* Get metadata about registered provider.
|
|
492
|
+
* @returns {ProviderMetadata} Provider Metadata
|
|
493
|
+
*/
|
|
494
|
+
get providerMetadata(): ProviderMetadata;
|
|
495
|
+
/**
|
|
496
|
+
* Adds a handler for the given provider event type.
|
|
497
|
+
* The handlers are called in the order they have been added.
|
|
498
|
+
* API (global) events run for all providers.
|
|
499
|
+
* @param {ProviderEvents} eventType The provider event type to listen to
|
|
500
|
+
* @param {EventHandler} handler The handler to run on occurrence of the event type
|
|
501
|
+
*/
|
|
502
|
+
addHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
503
|
+
/**
|
|
504
|
+
* Removes a handler for the given provider event type.
|
|
505
|
+
* @param {ProviderEvents} eventType The provider event type to remove the listener for
|
|
506
|
+
* @param {EventHandler} handler The handler to remove for the provider event type
|
|
507
|
+
*/
|
|
508
|
+
removeHandler<T extends ProviderEvents>(eventType: T, handler: EventHandler<T>): void;
|
|
509
|
+
/**
|
|
510
|
+
* Gets the current handlers for the given provider event type.
|
|
511
|
+
* @param {ProviderEvents} eventType The provider event type to get the current handlers for
|
|
512
|
+
* @returns {EventHandler[]} The handlers currently attached to the given provider event type
|
|
513
|
+
*/
|
|
514
|
+
getHandlers<T extends ProviderEvents>(eventType: T): EventHandler<T>[];
|
|
515
|
+
/**
|
|
516
|
+
* Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
|
|
517
|
+
* This provider will be used by unnamed clients and named clients to which no provider is bound.
|
|
518
|
+
* Setting a provider supersedes the current provider used in new and existing clients without a name.
|
|
519
|
+
* @template P
|
|
520
|
+
* @param {P} provider The provider responsible for flag evaluations.
|
|
521
|
+
* @returns {Promise<void>}
|
|
522
|
+
* @throws Uncaught exceptions thrown by the provider during initialization.
|
|
523
|
+
*/
|
|
524
|
+
setProviderAndWait(provider: P): Promise<void>;
|
|
525
|
+
/**
|
|
526
|
+
* Sets the provider that OpenFeature will use for flag evaluations of providers with the given name.
|
|
527
|
+
* A promise is returned that resolves when the provider is ready.
|
|
528
|
+
* Setting a provider supersedes the current provider used in new and existing clients with that name.
|
|
529
|
+
* @template P
|
|
530
|
+
* @param {string} clientName The name to identify the client
|
|
531
|
+
* @param {P} provider The provider responsible for flag evaluations.
|
|
532
|
+
* @returns {Promise<void>}
|
|
533
|
+
* @throws Uncaught exceptions thrown by the provider during initialization.
|
|
534
|
+
*/
|
|
535
|
+
setProviderAndWait(clientName: string, provider: P): Promise<void>;
|
|
536
|
+
/**
|
|
537
|
+
* Sets the default provider for flag evaluations.
|
|
538
|
+
* This provider will be used by unnamed clients and named clients to which no provider is bound.
|
|
539
|
+
* Setting a provider supersedes the current provider used in new and existing clients without a name.
|
|
540
|
+
* @template P
|
|
541
|
+
* @param {P} provider The provider responsible for flag evaluations.
|
|
542
|
+
* @returns {this} OpenFeature API
|
|
543
|
+
*/
|
|
544
|
+
setProvider(provider: P): this;
|
|
545
|
+
/**
|
|
546
|
+
* Sets the provider that OpenFeature will use for flag evaluations of providers with the given name.
|
|
547
|
+
* Setting a provider supersedes the current provider used in new and existing clients with that name.
|
|
548
|
+
* @template P
|
|
549
|
+
* @param {string} clientName The name to identify the client
|
|
550
|
+
* @param {P} provider The provider responsible for flag evaluations.
|
|
551
|
+
* @returns {this} OpenFeature API
|
|
552
|
+
*/
|
|
553
|
+
setProvider(clientName: string, provider: P): this;
|
|
554
|
+
private setAwaitableProvider;
|
|
555
|
+
protected getProviderForClient(name?: string): P;
|
|
556
|
+
protected buildAndCacheEventEmitterForClient(name?: string): GenericEventEmitter;
|
|
557
|
+
private getUnboundEmitters;
|
|
558
|
+
private getAssociatedEventEmitters;
|
|
559
|
+
private transferListeners;
|
|
560
|
+
close(): Promise<void>;
|
|
561
|
+
protected clearProvidersAndSetDefault(defaultProvider: P): Promise<void>;
|
|
562
|
+
private handleShutdownError;
|
|
563
|
+
}
|
|
3
564
|
|
|
4
565
|
interface FlagEvaluationOptions {
|
|
5
566
|
hooks?: Hook[];
|
|
@@ -202,6 +763,14 @@ declare class InMemoryProvider implements Provider {
|
|
|
202
763
|
private lookupFlagValue;
|
|
203
764
|
}
|
|
204
765
|
|
|
766
|
+
/**
|
|
767
|
+
* The InternalEventEmitter is not exported publicly and should only be used within the SDK. It extends the
|
|
768
|
+
* OpenFeatureEventEmitter to include additional properties that can be included
|
|
769
|
+
* in the event details.
|
|
770
|
+
*/
|
|
771
|
+
declare abstract class InternalEventEmitter extends GenericEventEmitter<CommonEventDetails> {
|
|
772
|
+
}
|
|
773
|
+
|
|
205
774
|
type OpenFeatureClientOptions = {
|
|
206
775
|
name?: string;
|
|
207
776
|
version?: string;
|
|
@@ -294,9 +863,23 @@ declare class NoopTransactionContextPropagator implements TransactionContextProp
|
|
|
294
863
|
}
|
|
295
864
|
declare const NOOP_TRANSACTION_CONTEXT_PROPAGATOR: NoopTransactionContextPropagator;
|
|
296
865
|
|
|
866
|
+
/**
|
|
867
|
+
* The OpenFeatureEventEmitter can be used by provider developers to emit
|
|
868
|
+
* events at various parts of the provider lifecycle.
|
|
869
|
+
*
|
|
870
|
+
* NOTE: Ready and error events are automatically emitted by the SDK based on
|
|
871
|
+
* the result of the initialize method.
|
|
872
|
+
*/
|
|
873
|
+
declare class OpenFeatureEventEmitter extends GenericEventEmitter {
|
|
874
|
+
protected readonly eventEmitter: EventEmitter;
|
|
875
|
+
constructor();
|
|
876
|
+
}
|
|
877
|
+
|
|
297
878
|
declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider> implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<Provider>> {
|
|
298
|
-
|
|
879
|
+
protected _events: OpenFeatureEventEmitter;
|
|
299
880
|
protected _defaultProvider: Provider;
|
|
881
|
+
protected _createEventEmitter: () => OpenFeatureEventEmitter;
|
|
882
|
+
private _transactionContextPropagator;
|
|
300
883
|
private constructor();
|
|
301
884
|
/**
|
|
302
885
|
* Gets a singleton instance of the OpenFeature API.
|
|
@@ -356,4 +939,4 @@ declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider> implements M
|
|
|
356
939
|
*/
|
|
357
940
|
declare const OpenFeature: OpenFeatureAPI;
|
|
358
941
|
|
|
359
|
-
export { Client, Features, FlagEvaluationOptions, InMemoryProvider, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, Provider, TransactionContext, TransactionContextPropagator };
|
|
942
|
+
export { BeforeHookContext, Client, ClientMetadata, CommonEventDetails, CommonProvider, ConfigChangeEvent, DefaultLogger, ErrorCode, ErrorEvent, EvaluationContext, EvaluationContextValue, EvaluationDetails, EvaluationLifeCycle, EventContext, EventDetails, EventHandler, EventMetadata, Eventing, Features, FlagEvaluationOptions, FlagMetadata, FlagNotFoundError, FlagValue, FlagValueType, GeneralError, GenericEventEmitter, Hook, HookContext, HookHints, InMemoryProvider, InvalidContextError, JsonArray, JsonObject, JsonValue, LOG_LEVELS, Logger, ManageContext, ManageLogger, ManageTransactionContextPropagator, Metadata, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureCommonAPI, OpenFeatureError, OpenFeatureEventEmitter, Paradigm, ParseError, PrimitiveValue, Provider, ProviderEvents, ProviderMetadata, ProviderStatus, ReadyEvent, ResolutionDetails, ResolutionReason, SafeLogger, StaleEvent, StandardResolutionReasons, TargetingKeyMissingError, TransactionContext, TransactionContextPropagator, TypeMismatchError, isObject, isString, objectOrUndefined, statusMatchesEvent, stringOrUndefined };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfeature/server-sdk",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
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.18"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@openfeature/core": "0.0.
|
|
54
|
+
"@openfeature/core": "0.0.18"
|
|
55
55
|
}
|
|
56
56
|
}
|