@openfeature/server-sdk 1.11.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,8 +16,8 @@
16
16
  <img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.7.0&color=yellow&style=for-the-badge" />
17
17
  </a>
18
18
  <!-- x-release-please-start-version -->
19
- <a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.11.0">
20
- <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.11.0&color=blue&style=for-the-badge" />
19
+ <a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.13.0">
20
+ <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.13.0&color=blue&style=for-the-badge" />
21
21
  </a>
22
22
  <!-- x-release-please-end -->
23
23
  <br/>
@@ -86,16 +86,17 @@ See [here](https://open-feature.github.io/js-sdk/modules/_openfeature_server_sdk
86
86
 
87
87
  ## 🌟 Features
88
88
 
89
- | Status | Features | Description |
90
- | ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
91
- | ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
92
- | ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
93
- | ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
94
- | ✅ | [Logging](#logging) | Integrate with popular logging packages. |
95
- | ✅ | [Named clients](#named-clients) | Utilize multiple providers in a single application. |
96
- | ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
97
- | ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
98
- | ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
89
+ | Status | Features | Description |
90
+ |--------|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
91
+ | ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
92
+ | ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
93
+ | ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
94
+ | ✅ | [Logging](#logging) | Integrate with popular logging packages. |
95
+ | ✅ | [Domains](#domains) | Logically bind clients with providers. |
96
+ | ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
97
+ | ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
98
+ | ✅ | [Transaction Context Propagation](#transaction-context-propagation) | Set a specific [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) for a transaction (e.g. an HTTP request or a thread) | |
99
+ | ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
99
100
 
100
101
  <sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
101
102
 
@@ -113,7 +114,7 @@ To register a provider and ensure it is ready before further actions are taken,
113
114
 
114
115
  ```ts
115
116
  await OpenFeature.setProviderAndWait(new MyProvider());
116
- ```
117
+ ```
117
118
 
118
119
  #### Synchronous
119
120
 
@@ -126,7 +127,7 @@ OpenFeature.setProvider(new MyProvider());
126
127
  Once the provider has been registered, the status can be tracked using [events](#eventing).
127
128
 
128
129
  In some situations, it may be beneficial to register multiple providers in the same application.
129
- This is possible using [named clients](#named-clients), which is covered in more details below.
130
+ This is possible using [domains](#domains), which is covered in more details below.
130
131
 
131
132
  ### Targeting
132
133
 
@@ -154,7 +155,7 @@ const boolValue = await client.getBooleanValue('some-flag', false, requestContex
154
155
 
155
156
  ### Hooks
156
157
 
157
- [Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle
158
+ [Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
158
159
  Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Hook&instant_search%5BrefinementList%5D%5Bcategory%5D%5B0%5D=Server-side&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=JavaScript) for a complete list of available hooks.
159
160
  If the hook you're looking for hasn't been created yet, see the [develop a hook](#develop-a-hook) section to learn how to build it yourself.
160
161
 
@@ -176,7 +177,7 @@ const boolValue = await client.getBooleanValue("bool-flag", false, { hooks: [new
176
177
 
177
178
  ### Logging
178
179
 
179
- The JS SDK will log warning and errors to the console by default.
180
+ The Node.JS SDK will log warnings and errors to the console by default.
180
181
  This behavior can be overridden by passing a custom logger either globally or per client.
181
182
  A custom logger must implement the [Logger interface](../shared/src/logger/logger.ts).
182
183
 
@@ -186,7 +187,7 @@ import type { Logger } from "@openfeature/server-sdk";
186
187
  // The logger can be anything that conforms with the Logger interface
187
188
  const logger: Logger = console;
188
189
 
189
- // Sets a global logger
190
+ // Sets a global logger
190
191
  OpenFeature.setLogger(logger);
191
192
 
192
193
  // Sets a client logger
@@ -194,11 +195,11 @@ const client = OpenFeature.getClient();
194
195
  client.setLogger(logger);
195
196
  ```
196
197
 
197
- ### Named clients
198
+ ### Domains
198
199
 
199
- Clients can be given a name.
200
- A name is a logical identifier which can be used to associate clients with a particular provider.
201
- If a name has no associated provider, the global provider is used.
200
+ Clients can be assigned to a domain.
201
+ A domain is a logical identifier which can be used to associate clients with a particular provider.
202
+ If a domain has no associated provider, the default provider is used.
202
203
 
203
204
  ```ts
204
205
  import { OpenFeature, InMemoryProvider } from "@openfeature/server-sdk";
@@ -216,16 +217,16 @@ const myFlags = {
216
217
 
217
218
  // Registering the default provider
218
219
  OpenFeature.setProvider(InMemoryProvider(myFlags));
219
- // Registering a named provider
220
- OpenFeature.setProvider("otherClient", new InMemoryProvider(someOtherFlags));
220
+ // Registering a provider to a domain
221
+ OpenFeature.setProvider("my-domain", new InMemoryProvider(someOtherFlags));
221
222
 
222
- // A Client backed by default provider
223
+ // A Client bound to the default provider
223
224
  const clientWithDefault = OpenFeature.getClient();
224
- // A Client backed by NewCachedProvider
225
- const clientForCache = OpenFeature.getClient("otherClient");
225
+ // A Client bound to the InMemoryProvider provider
226
+ const domainScopedClient = OpenFeature.getClient("my-domain");
226
227
  ```
227
228
 
228
- Named providers can be set in an awaitable or synchronous way.
229
+ Domains can be defined on a provider during registration.
229
230
  For more details, please refer to the [providers](#providers) section.
230
231
 
231
232
  ### Eventing
@@ -251,6 +252,32 @@ client.addHandler(ProviderEvents.Error, (eventDetails) => {
251
252
  });
252
253
  ```
253
254
 
255
+ ### Transaction Context Propagation
256
+
257
+ Transaction context is a container for transaction-specific evaluation context (e.g. user id, user agent, IP).
258
+ Transaction context can be set where specific data is available (e.g. an auth service or request handler) and by using the transaction context propagator it will automatically be applied to all flag evaluations within a transaction (e.g. a request or thread).
259
+
260
+ The following example shows an Express middleware using transaction context propagation to propagate the request ip and user id into request scoped transaction context.
261
+
262
+ ```ts
263
+ import express, { Request, Response, NextFunction } from "express";
264
+ import { OpenFeature, AsyncLocalStorageTransactionContextPropagator } from '@openfeature/server-sdk';
265
+
266
+ OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionContextPropagator())
267
+
268
+ /**
269
+ * This example is based on an express middleware.
270
+ */
271
+ const app = express();
272
+ app.use((req: Request, res: Response, next: NextFunction) => {
273
+ const ip = res.headers.get("X-Forwarded-For")
274
+ OpenFeature.setTransactionContext({ targetingKey: req.user.id, ipAddress: ip }, () => {
275
+ // The transaction context is used in any flag evaluation throughout the whole call chain of next
276
+ next();
277
+ });
278
+ })
279
+ ```
280
+
254
281
  ### Shutdown
255
282
 
256
283
  The OpenFeature API provides a close function to perform a cleanup of all registered providers.
@@ -279,7 +306,6 @@ import {
279
306
  Logger,
280
307
  Provider,
281
308
  ProviderEventEmitter,
282
- ProviderStatus,
283
309
  ResolutionDetails
284
310
  } from '@openfeature/server-sdk';
285
311
 
@@ -305,10 +331,8 @@ class MyProvider implements Provider {
305
331
  // code to evaluate an object
306
332
  }
307
333
 
308
- status?: ProviderStatus | undefined;
309
-
310
334
  // implement with "new OpenFeatureEventEmitter()", and use "emit()" to emit events
311
- events?: ProviderEventEmitter<AnyProviderEvent> | undefined;
335
+ events?: ProviderEventEmitter<AnyProviderEvent> | undefined;
312
336
 
313
337
  initialize?(context?: EvaluationContext | undefined): Promise<void> {
314
338
  // code to initialize your provider
package/dist/cjs/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -18,19 +16,12 @@ var __copyProps = (to, from, except, desc) => {
18
16
  return to;
19
17
  };
20
18
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
20
 
31
21
  // src/index.ts
32
22
  var src_exports = {};
33
23
  __export(src_exports, {
24
+ AsyncLocalStorageTransactionContextPropagator: () => AsyncLocalStorageTransactionContextPropagator,
34
25
  InMemoryProvider: () => InMemoryProvider,
35
26
  NOOP_PROVIDER: () => NOOP_PROVIDER,
36
27
  NOOP_TRANSACTION_CONTEXT_PROPAGATOR: () => NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
@@ -38,23 +29,42 @@ __export(src_exports, {
38
29
  OpenFeatureAPI: () => OpenFeatureAPI,
39
30
  OpenFeatureClient: () => OpenFeatureClient,
40
31
  OpenFeatureEventEmitter: () => OpenFeatureEventEmitter,
41
- ProviderEvents: () => import_core5.ServerProviderEvents
32
+ ProviderEvents: () => import_core2.ServerProviderEvents,
33
+ ProviderStatus: () => import_core3.ServerProviderStatus
42
34
  });
43
35
  module.exports = __toCommonJS(src_exports);
44
36
 
45
37
  // src/client/open-feature-client.ts
46
38
  var import_core7 = require("@openfeature/core");
47
39
 
48
- // src/provider/no-op-provider.ts
40
+ // src/open-feature.ts
41
+ var import_core6 = require("@openfeature/core");
42
+
43
+ // src/events/open-feature-event-emitter.ts
49
44
  var import_core = require("@openfeature/core");
45
+ var import_node_events = require("events");
46
+ var OpenFeatureEventEmitter = class extends import_core.GenericEventEmitter {
47
+ eventEmitter = new import_node_events.EventEmitter({ captureRejections: true });
48
+ constructor() {
49
+ super();
50
+ this.eventEmitter.on("error", (err) => {
51
+ this._logger?.error("Error running event handler:", err);
52
+ });
53
+ }
54
+ };
55
+
56
+ // src/events/events.ts
57
+ var import_core2 = require("@openfeature/core");
58
+
59
+ // src/provider/provider.ts
60
+ var import_core3 = require("@openfeature/core");
61
+
62
+ // src/provider/no-op-provider.ts
50
63
  var REASON_NO_OP = "No-op";
51
64
  var NoopFeatureProvider = class {
52
65
  metadata = {
53
66
  name: "No-op Provider"
54
67
  };
55
- get status() {
56
- return import_core.ProviderStatus.NOT_READY;
57
- }
58
68
  resolveBooleanEvaluation(_, defaultValue) {
59
69
  return this.noOp(defaultValue);
60
70
  }
@@ -77,17 +87,17 @@ var NoopFeatureProvider = class {
77
87
  var NOOP_PROVIDER = new NoopFeatureProvider();
78
88
 
79
89
  // src/provider/in-memory-provider/in-memory-provider.ts
80
- var import_core3 = require("@openfeature/core");
90
+ var import_core5 = require("@openfeature/core");
81
91
 
82
92
  // src/provider/in-memory-provider/variant-not-found-error.ts
83
- var import_core2 = require("@openfeature/core");
84
- var VariantFoundError = class extends import_core2.OpenFeatureError {
93
+ var import_core4 = require("@openfeature/core");
94
+ var VariantFoundError = class _VariantFoundError extends import_core4.OpenFeatureError {
85
95
  code;
86
96
  constructor(message) {
87
97
  super(message);
88
- Object.setPrototypeOf(this, VariantFoundError.prototype);
98
+ Object.setPrototypeOf(this, _VariantFoundError.prototype);
89
99
  this.name = "VariantFoundError";
90
- this.code = import_core2.ErrorCode.GENERAL;
100
+ this.code = import_core4.ErrorCode.GENERAL;
91
101
  }
92
102
  };
93
103
 
@@ -109,7 +119,7 @@ var InMemoryProvider = class {
109
119
  putConfiguration(flagConfiguration) {
110
120
  const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
111
121
  this._flagConfiguration = { ...flagConfiguration };
112
- this.events.emit(import_core5.ServerProviderEvents.ConfigurationChanged, { flagsChanged });
122
+ this.events.emit(import_core2.ServerProviderEvents.ConfigurationChanged, { flagsChanged });
113
123
  }
114
124
  resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
115
125
  return this.resolveFlagWithReason(flagKey, defaultValue, context, logger);
@@ -127,12 +137,12 @@ var InMemoryProvider = class {
127
137
  try {
128
138
  const resolutionResult = this.lookupFlagValue(flagKey, defaultValue, ctx, logger);
129
139
  if (typeof resolutionResult?.value != typeof defaultValue) {
130
- throw new import_core3.TypeMismatchError();
140
+ throw new import_core5.TypeMismatchError();
131
141
  }
132
142
  return resolutionResult;
133
143
  } catch (error) {
134
- if (!(error instanceof import_core3.OpenFeatureError)) {
135
- throw new import_core3.GeneralError(error?.message || "unknown error");
144
+ if (!(error instanceof import_core5.OpenFeatureError)) {
145
+ throw new import_core5.GeneralError(error?.message || "unknown error");
136
146
  }
137
147
  throw error;
138
148
  }
@@ -141,11 +151,11 @@ var InMemoryProvider = class {
141
151
  if (!(flagKey in this._flagConfiguration)) {
142
152
  const message = `no flag found with key ${flagKey}`;
143
153
  logger?.debug(message);
144
- throw new import_core3.FlagNotFoundError(message);
154
+ throw new import_core5.FlagNotFoundError(message);
145
155
  }
146
156
  const flagSpec = this._flagConfiguration[flagKey];
147
157
  if (flagSpec.disabled) {
148
- return { value: defaultValue, reason: import_core3.StandardResolutionReasons.DISABLED };
158
+ return { value: defaultValue, reason: import_core5.StandardResolutionReasons.DISABLED };
149
159
  }
150
160
  const isContextEval = ctx && flagSpec?.contextEvaluator;
151
161
  const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;
@@ -158,47 +168,42 @@ var InMemoryProvider = class {
158
168
  return {
159
169
  value,
160
170
  ...variant && { variant },
161
- reason: isContextEval ? import_core3.StandardResolutionReasons.TARGETING_MATCH : import_core3.StandardResolutionReasons.STATIC
171
+ reason: isContextEval ? import_core5.StandardResolutionReasons.TARGETING_MATCH : import_core5.StandardResolutionReasons.STATIC
162
172
  };
163
173
  }
164
174
  };
165
175
 
166
- // src/open-feature.ts
167
- var import_core6 = require("@openfeature/core");
168
-
169
176
  // src/transaction-context/no-op-transaction-context-propagator.ts
170
177
  var NoopTransactionContextPropagator = class {
171
178
  getTransactionContext() {
172
179
  return {};
173
180
  }
174
- setTransactionContext(_, callback) {
175
- callback();
181
+ setTransactionContext(_, callback, ...args) {
182
+ callback(...args);
176
183
  }
177
184
  };
178
185
  var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
179
186
 
180
- // src/events/open-feature-event-emitter.ts
181
- var import_core4 = require("@openfeature/core");
182
- var import_events = __toESM(require("events"));
183
- var OpenFeatureEventEmitter = class extends import_core4.GenericEventEmitter {
184
- eventEmitter = new import_events.default({ captureRejections: true });
185
- constructor() {
186
- super();
187
- this.eventEmitter.on("error", (err) => {
188
- this._logger?.error("Error running event handler:", err);
189
- });
187
+ // src/transaction-context/async-local-storage-transaction-context-propagator.ts
188
+ var import_async_hooks = require("async_hooks");
189
+ var AsyncLocalStorageTransactionContextPropagator = class {
190
+ asyncLocalStorage = new import_async_hooks.AsyncLocalStorage();
191
+ getTransactionContext() {
192
+ return this.asyncLocalStorage.getStore() ?? {};
193
+ }
194
+ setTransactionContext(transactionContext, callback, ...args) {
195
+ this.asyncLocalStorage.run(transactionContext, callback, ...args);
190
196
  }
191
197
  };
192
198
 
193
- // src/events/events.ts
194
- var import_core5 = require("@openfeature/core");
195
-
196
199
  // src/open-feature.ts
197
200
  var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api");
198
201
  var _globalThis = globalThis;
199
- var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
200
- _events = new OpenFeatureEventEmitter();
201
- _defaultProvider = NOOP_PROVIDER;
202
+ var OpenFeatureAPI = class _OpenFeatureAPI extends import_core6.OpenFeatureCommonAPI {
203
+ _statusEnumType = import_core3.ServerProviderStatus;
204
+ _apiEmitter = new OpenFeatureEventEmitter();
205
+ _defaultProvider = new import_core6.ProviderWrapper(NOOP_PROVIDER, import_core3.ServerProviderStatus.NOT_READY, this._statusEnumType);
206
+ _domainScopedProviders = /* @__PURE__ */ new Map();
202
207
  _createEventEmitter = () => new OpenFeatureEventEmitter();
203
208
  _transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
204
209
  constructor() {
@@ -214,10 +219,16 @@ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
214
219
  if (globalApi) {
215
220
  return globalApi;
216
221
  }
217
- const instance = new OpenFeatureAPI();
222
+ const instance = new _OpenFeatureAPI();
218
223
  _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
219
224
  return instance;
220
225
  }
226
+ getProviderStatus(domain) {
227
+ if (!domain) {
228
+ return this._defaultProvider.status;
229
+ }
230
+ return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;
231
+ }
221
232
  setContext(context) {
222
233
  this._context = context;
223
234
  return this;
@@ -225,15 +236,16 @@ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
225
236
  getContext() {
226
237
  return this._context;
227
238
  }
228
- getClient(nameOrContext, versionOrContext, contextOrUndefined) {
229
- const name = (0, import_core6.stringOrUndefined)(nameOrContext);
239
+ getClient(domainOrContext, versionOrContext, contextOrUndefined) {
240
+ const domain = (0, import_core6.stringOrUndefined)(domainOrContext);
230
241
  const version = (0, import_core6.stringOrUndefined)(versionOrContext);
231
- const context = (0, import_core6.objectOrUndefined)(nameOrContext) ?? (0, import_core6.objectOrUndefined)(versionOrContext) ?? (0, import_core6.objectOrUndefined)(contextOrUndefined);
242
+ const context = (0, import_core6.objectOrUndefined)(domainOrContext) ?? (0, import_core6.objectOrUndefined)(versionOrContext) ?? (0, import_core6.objectOrUndefined)(contextOrUndefined);
232
243
  return new OpenFeatureClient(
233
- () => this.getProviderForClient(name),
234
- () => this.buildAndCacheEventEmitterForClient(name),
244
+ () => this.getProviderForClient(domain),
245
+ () => this.getProviderStatus(domain),
246
+ () => this.buildAndCacheEventEmitterForClient(domain),
235
247
  () => this._logger,
236
- { name, version },
248
+ { domain, version },
237
249
  context
238
250
  );
239
251
  }
@@ -273,8 +285,9 @@ var OpenFeature = OpenFeatureAPI.getInstance();
273
285
 
274
286
  // src/client/open-feature-client.ts
275
287
  var OpenFeatureClient = class {
276
- constructor(providerAccessor, emitterAccessor, globalLogger, options, context = {}) {
288
+ constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options, context = {}) {
277
289
  this.providerAccessor = providerAccessor;
290
+ this.providerStatusAccessor = providerStatusAccessor;
278
291
  this.emitterAccessor = emitterAccessor;
279
292
  this.globalLogger = globalLogger;
280
293
  this.options = options;
@@ -285,17 +298,26 @@ var OpenFeatureClient = class {
285
298
  _clientLogger;
286
299
  get metadata() {
287
300
  return {
288
- name: this.options.name,
301
+ // Use domain if name is not provided
302
+ name: this.options.domain ?? this.options.name,
303
+ domain: this.options.domain ?? this.options.name,
289
304
  version: this.options.version,
290
305
  providerMetadata: this.providerAccessor().metadata
291
306
  };
292
307
  }
308
+ get providerStatus() {
309
+ return this.providerStatusAccessor();
310
+ }
293
311
  addHandler(eventType, handler) {
294
312
  this.emitterAccessor().addHandler(eventType, handler);
295
- const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._provider.status);
313
+ const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._providerStatus);
296
314
  if (shouldRunNow) {
297
315
  try {
298
- handler({ clientName: this.metadata.name, providerName: this._provider.metadata.name });
316
+ handler({
317
+ clientName: this.metadata.name,
318
+ domain: this.metadata.domain,
319
+ providerName: this._provider.metadata.name
320
+ });
299
321
  } catch (err) {
300
322
  this._logger?.error("Error running event handler:", err);
301
323
  }
@@ -401,6 +423,11 @@ var OpenFeatureClient = class {
401
423
  };
402
424
  try {
403
425
  const frozenContext = await this.beforeHooks(allHooks, hookContext, options);
426
+ if (this.providerStatus === import_core3.ServerProviderStatus.NOT_READY) {
427
+ throw new import_core7.ProviderNotReadyError("provider has not yet initialized");
428
+ } else if (this.providerStatus === import_core3.ServerProviderStatus.FATAL) {
429
+ throw new import_core7.ProviderFatalError("provider is in an irrecoverable error state");
430
+ }
404
431
  const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger);
405
432
  const evaluationDetails = {
406
433
  ...resolution,
@@ -469,6 +496,9 @@ var OpenFeatureClient = class {
469
496
  get _provider() {
470
497
  return this.providerAccessor();
471
498
  }
499
+ get _providerStatus() {
500
+ return this.providerStatusAccessor();
501
+ }
472
502
  get _logger() {
473
503
  return this._clientLogger || this.globalLogger();
474
504
  }
@@ -478,6 +508,7 @@ var OpenFeatureClient = class {
478
508
  __reExport(src_exports, require("@openfeature/core"), module.exports);
479
509
  // Annotate the CommonJS export names for ESM import in node:
480
510
  0 && (module.exports = {
511
+ AsyncLocalStorageTransactionContextPropagator,
481
512
  InMemoryProvider,
482
513
  NOOP_PROVIDER,
483
514
  NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
@@ -485,6 +516,8 @@ __reExport(src_exports, require("@openfeature/core"), module.exports);
485
516
  OpenFeatureAPI,
486
517
  OpenFeatureClient,
487
518
  OpenFeatureEventEmitter,
488
- ProviderEvents
519
+ ProviderEvents,
520
+ ProviderStatus,
521
+ ...require("@openfeature/core")
489
522
  });
490
523
  //# sourceMappingURL=index.js.map