@openfeature/web-sdk 1.0.3 → 1.2.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/dist/esm/index.js CHANGED
@@ -1,9 +1,27 @@
1
1
  var __create = Object.create;
2
2
  var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
8
  var __getProtoOf = Object.getPrototypeOf;
6
9
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __reflectGet = Reflect.get;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7
25
  var __commonJS = (cb, mod) => function __require() {
8
26
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
27
  };
@@ -23,6 +41,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
41
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
42
  mod
25
43
  ));
44
+ var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
45
+ var __async = (__this, __arguments, generator) => {
46
+ return new Promise((resolve, reject) => {
47
+ var fulfilled = (value) => {
48
+ try {
49
+ step(generator.next(value));
50
+ } catch (e) {
51
+ reject(e);
52
+ }
53
+ };
54
+ var rejected = (value) => {
55
+ try {
56
+ step(generator.throw(value));
57
+ } catch (e) {
58
+ reject(e);
59
+ }
60
+ };
61
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
62
+ step((generator = generator.apply(__this, __arguments)).next());
63
+ });
64
+ };
26
65
 
27
66
  // ../../node_modules/eventemitter3/index.js
28
67
  var require_eventemitter3 = __commonJS({
@@ -206,50 +245,17 @@ var require_eventemitter3 = __commonJS({
206
245
  }
207
246
  });
208
247
 
209
- // src/client/open-feature-client.ts
210
- import {
211
- ErrorCode as ErrorCode2,
212
- ProviderFatalError,
213
- ProviderNotReadyError,
214
- SafeLogger,
215
- StandardResolutionReasons as StandardResolutionReasons2,
216
- statusMatchesEvent
217
- } from "@openfeature/core";
218
-
219
- // src/open-feature.ts
220
- import {
221
- OpenFeatureCommonAPI,
222
- ProviderWrapper,
223
- objectOrUndefined,
224
- stringOrUndefined
225
- } from "@openfeature/core";
226
-
227
- // src/events/open-feature-event-emitter.ts
228
- import { GenericEventEmitter } from "@openfeature/core";
229
-
230
- // ../../node_modules/eventemitter3/index.mjs
231
- var import_index = __toESM(require_eventemitter3(), 1);
232
-
233
- // src/events/open-feature-event-emitter.ts
234
- var OpenFeatureEventEmitter = class extends GenericEventEmitter {
235
- eventEmitter = new import_index.default();
236
- constructor() {
237
- super();
238
- }
239
- };
240
-
241
- // src/events/events.ts
242
- import { ClientProviderEvents } from "@openfeature/core";
243
-
244
248
  // src/provider/provider.ts
245
249
  import { ClientProviderStatus } from "@openfeature/core";
246
250
 
247
251
  // src/provider/no-op-provider.ts
248
252
  var REASON_NO_OP = "No-op";
249
253
  var NoopFeatureProvider = class {
250
- metadata = {
251
- name: "No-op Provider"
252
- };
254
+ constructor() {
255
+ this.metadata = {
256
+ name: "No-op Provider"
257
+ };
258
+ }
253
259
  resolveBooleanEvaluation(_, defaultValue) {
254
260
  return this.noOp(defaultValue);
255
261
  }
@@ -280,10 +286,26 @@ import {
280
286
  TypeMismatchError
281
287
  } from "@openfeature/core";
282
288
 
289
+ // src/events/open-feature-event-emitter.ts
290
+ import { GenericEventEmitter } from "@openfeature/core";
291
+
292
+ // ../../node_modules/eventemitter3/index.mjs
293
+ var import_index = __toESM(require_eventemitter3(), 1);
294
+
295
+ // src/events/open-feature-event-emitter.ts
296
+ var OpenFeatureEventEmitter = class extends GenericEventEmitter {
297
+ constructor() {
298
+ super();
299
+ this.eventEmitter = new import_index.default();
300
+ }
301
+ };
302
+
303
+ // src/events/events.ts
304
+ import { ClientProviderEvents } from "@openfeature/core";
305
+
283
306
  // src/provider/in-memory-provider/variant-not-found-error.ts
284
307
  import { ErrorCode, OpenFeatureError } from "@openfeature/core";
285
308
  var VariantNotFoundError = class _VariantNotFoundError extends OpenFeatureError {
286
- code;
287
309
  constructor(message) {
288
310
  super(message);
289
311
  Object.setPrototypeOf(this, _VariantNotFoundError.prototype);
@@ -294,40 +316,42 @@ var VariantNotFoundError = class _VariantNotFoundError extends OpenFeatureError
294
316
 
295
317
  // src/provider/in-memory-provider/in-memory-provider.ts
296
318
  var InMemoryProvider = class {
297
- events = new OpenFeatureEventEmitter();
298
- runsOn = "client";
299
- metadata = {
300
- name: "in-memory"
301
- };
302
- _flagConfiguration;
303
- _context;
304
319
  constructor(flagConfiguration = {}) {
305
- this._flagConfiguration = { ...flagConfiguration };
320
+ this.events = new OpenFeatureEventEmitter();
321
+ this.runsOn = "client";
322
+ this.metadata = {
323
+ name: "in-memory"
324
+ };
325
+ this._flagConfiguration = __spreadValues({}, flagConfiguration);
306
326
  }
307
- async initialize(context) {
308
- try {
309
- for (const key in this._flagConfiguration) {
310
- this.resolveFlagWithReason(key, context);
327
+ initialize(context) {
328
+ return __async(this, null, function* () {
329
+ try {
330
+ for (const key in this._flagConfiguration) {
331
+ this.resolveFlagWithReason(key, context);
332
+ }
333
+ this._context = context;
334
+ } catch (err) {
335
+ throw new GeneralError("initialization failure", { cause: err });
311
336
  }
312
- this._context = context;
313
- } catch (err) {
314
- throw new Error("initialization failure", { cause: err });
315
- }
337
+ });
316
338
  }
317
339
  /**
318
340
  * Overwrites the configured flags.
319
341
  * @param { FlagConfiguration } flagConfiguration new flag configuration
320
342
  */
321
- async putConfiguration(flagConfiguration) {
322
- const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
323
- this._flagConfiguration = { ...flagConfiguration };
324
- try {
325
- await this.initialize(this._context);
326
- this.events.emit(ClientProviderEvents.ConfigurationChanged, { flagsChanged });
327
- } catch (err) {
328
- this.events.emit(ClientProviderEvents.Error);
329
- throw err;
330
- }
343
+ putConfiguration(flagConfiguration) {
344
+ return __async(this, null, function* () {
345
+ const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
346
+ this._flagConfiguration = __spreadValues({}, flagConfiguration);
347
+ try {
348
+ yield this.initialize(this._context);
349
+ this.events.emit(ClientProviderEvents.ConfigurationChanged, { flagsChanged });
350
+ } catch (err) {
351
+ this.events.emit(ClientProviderEvents.Error);
352
+ throw err;
353
+ }
354
+ });
331
355
  }
332
356
  resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
333
357
  return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
@@ -344,7 +368,7 @@ var InMemoryProvider = class {
344
368
  resolveAndCheckFlag(flagKey, defaultValue, context, logger) {
345
369
  if (!(flagKey in this._flagConfiguration)) {
346
370
  const message = `no flag found with key ${flagKey}`;
347
- logger?.debug(message);
371
+ logger == null ? void 0 : logger.debug(message);
348
372
  throw new FlagNotFoundError(message);
349
373
  }
350
374
  if (this._flagConfiguration[flagKey].disabled) {
@@ -353,7 +377,7 @@ var InMemoryProvider = class {
353
377
  const resolvedFlag = this.resolveFlagWithReason(flagKey, context);
354
378
  if (resolvedFlag.value === void 0) {
355
379
  const message = `no value associated with variant provided for ${flagKey} found`;
356
- logger?.error(message);
380
+ logger == null ? void 0 : logger.error(message);
357
381
  throw new VariantNotFoundError(message);
358
382
  }
359
383
  if (typeof resolvedFlag.value != typeof defaultValue) {
@@ -367,192 +391,44 @@ var InMemoryProvider = class {
367
391
  return resolutionResult;
368
392
  } catch (error) {
369
393
  if (!(error instanceof OpenFeatureError2)) {
370
- throw new GeneralError(error?.message || "unknown error");
394
+ throw new GeneralError((error == null ? void 0 : error.message) || "unknown error");
371
395
  }
372
396
  throw error;
373
397
  }
374
398
  }
375
399
  lookupFlagValue(flagKey, ctx) {
400
+ var _a;
376
401
  const flagSpec = this._flagConfiguration[flagKey];
377
- const isContextEval = ctx && flagSpec?.contextEvaluator;
378
- const variant = isContextEval ? flagSpec.contextEvaluator?.(ctx) : flagSpec.defaultVariant;
379
- const value = variant && flagSpec?.variants[variant];
402
+ const isContextEval = ctx && (flagSpec == null ? void 0 : flagSpec.contextEvaluator);
403
+ const variant = isContextEval ? (_a = flagSpec.contextEvaluator) == null ? void 0 : _a.call(flagSpec, ctx) : flagSpec.defaultVariant;
404
+ const value = variant && (flagSpec == null ? void 0 : flagSpec.variants[variant]);
380
405
  const reason = isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC;
381
- return {
382
- value,
383
- ...variant && { variant },
406
+ return __spreadProps(__spreadValues({
407
+ value
408
+ }, variant && { variant }), {
384
409
  reason
385
- };
410
+ });
386
411
  }
387
412
  };
388
413
 
389
414
  // src/open-feature.ts
390
- var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
391
- var _globalThis = globalThis;
392
- var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
393
- _statusEnumType = ClientProviderStatus;
394
- _apiEmitter = new OpenFeatureEventEmitter();
395
- _defaultProvider = new ProviderWrapper(NOOP_PROVIDER, ClientProviderStatus.NOT_READY, this._statusEnumType);
396
- _domainScopedProviders = /* @__PURE__ */ new Map();
397
- _createEventEmitter = () => new OpenFeatureEventEmitter();
398
- constructor() {
399
- super("client");
400
- }
401
- /**
402
- * Gets a singleton instance of the OpenFeature API.
403
- * @ignore
404
- * @returns {OpenFeatureAPI} OpenFeature API
405
- */
406
- static getInstance() {
407
- const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];
408
- if (globalApi) {
409
- return globalApi;
410
- }
411
- const instance = new _OpenFeatureAPI();
412
- _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
413
- return instance;
414
- }
415
- getProviderStatus(domain) {
416
- if (!domain) {
417
- return this._defaultProvider.status;
418
- }
419
- return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;
420
- }
421
- async setContext(domainOrContext, contextOrUndefined) {
422
- const domain = stringOrUndefined(domainOrContext);
423
- const context = objectOrUndefined(domainOrContext) ?? objectOrUndefined(contextOrUndefined) ?? {};
424
- if (domain) {
425
- const wrapper = this._domainScopedProviders.get(domain);
426
- if (wrapper) {
427
- const oldContext = this.getContext(domain);
428
- this._domainScopedContext.set(domain, context);
429
- await this.runProviderContextChangeHandler(domain, wrapper, oldContext, context);
430
- } else {
431
- this._domainScopedContext.set(domain, context);
432
- }
433
- } else {
434
- const oldContext = this._context;
435
- this._context = context;
436
- const unboundProviders = Array.from(this._domainScopedProviders.entries()).filter(([domain2]) => !this._domainScopedContext.has(domain2)).reduce((acc, [domain2, wrapper]) => {
437
- acc.push({ domain: domain2, wrapper });
438
- return acc;
439
- }, []);
440
- const allDomainRecords = [
441
- // add in the default (no domain)
442
- { domain: void 0, wrapper: this._defaultProvider },
443
- ...unboundProviders
444
- ];
445
- await Promise.all(
446
- allDomainRecords.map(
447
- (dm) => this.runProviderContextChangeHandler(dm.domain, dm.wrapper, oldContext, context)
448
- )
449
- );
450
- }
451
- }
452
- getContext(domainOrUndefined) {
453
- const domain = stringOrUndefined(domainOrUndefined);
454
- if (domain) {
455
- const context = this._domainScopedContext.get(domain);
456
- if (context) {
457
- return context;
458
- } else {
459
- this._logger.debug(`Unable to find context for '${domain}'.`);
460
- }
461
- }
462
- return this._context;
463
- }
464
- async clearContext(domainOrUndefined) {
465
- const domain = stringOrUndefined(domainOrUndefined);
466
- if (domain) {
467
- const wrapper = this._domainScopedProviders.get(domain);
468
- if (wrapper) {
469
- const oldContext = this.getContext(domain);
470
- this._domainScopedContext.delete(domain);
471
- const newContext = this.getContext();
472
- await this.runProviderContextChangeHandler(domain, wrapper, oldContext, newContext);
473
- } else {
474
- this._domainScopedContext.delete(domain);
475
- }
476
- } else {
477
- return this.setContext({});
478
- }
479
- }
480
- /**
481
- * Resets the global evaluation context and removes the evaluation context for
482
- * all domains.
483
- */
484
- async clearContexts() {
485
- await this.clearContext();
486
- await Promise.allSettled(Array.from(this._domainScopedProviders.keys()).map((domain) => this.clearContext(domain)));
487
- }
488
- /**
489
- * A factory function for creating new named OpenFeature clients. Clients can contain
490
- * their own state (e.g. logger, hook, context). Multiple clients can be used
491
- * to segment feature flag configuration.
492
- *
493
- * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.
494
- * Otherwise, the default provider is used until a provider is assigned to that name.
495
- * @param {string} domain An identifier which logically binds clients with providers
496
- * @param {string} version The version of the client (only used for metadata)
497
- * @returns {Client} OpenFeature Client
498
- */
499
- getClient(domain, version) {
500
- return new OpenFeatureClient(
501
- // functions are passed here to make sure that these values are always up to date,
502
- // and so we don't have to make these public properties on the API class.
503
- () => this.getProviderForClient(domain),
504
- () => this.getProviderStatus(domain),
505
- () => this.buildAndCacheEventEmitterForClient(domain),
506
- () => this._logger,
507
- { domain, version }
508
- );
509
- }
510
- /**
511
- * Clears all registered providers and resets the default provider.
512
- * @returns {Promise<void>}
513
- */
514
- async clearProviders() {
515
- await super.clearProvidersAndSetDefault(NOOP_PROVIDER);
516
- this._domainScopedContext.clear();
517
- }
518
- async runProviderContextChangeHandler(domain, wrapper, oldContext, newContext) {
519
- const providerName = wrapper.provider?.metadata?.name || "unnamed-provider";
520
- try {
521
- if (typeof wrapper.provider.onContextChange === "function") {
522
- wrapper.incrementPendingContextChanges();
523
- wrapper.status = this._statusEnumType.RECONCILING;
524
- this.getAssociatedEventEmitters(domain).forEach((emitter) => {
525
- emitter?.emit(ClientProviderEvents.Reconciling, { domain, providerName });
526
- });
527
- this._apiEmitter?.emit(ClientProviderEvents.Reconciling, { domain, providerName });
528
- await wrapper.provider.onContextChange(oldContext, newContext);
529
- wrapper.decrementPendingContextChanges();
530
- }
531
- wrapper.status = this._statusEnumType.READY;
532
- if (wrapper.allContextChangesSettled) {
533
- this.getAssociatedEventEmitters(domain).forEach((emitter) => {
534
- emitter?.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
535
- });
536
- this._apiEmitter?.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
537
- }
538
- } catch (err) {
539
- wrapper.decrementPendingContextChanges();
540
- wrapper.status = this._statusEnumType.ERROR;
541
- if (wrapper.allContextChangesSettled) {
542
- const error = err;
543
- const message = `Error running ${providerName}'s context change handler: ${error?.message}`;
544
- this._logger?.error(`${message}`, err);
545
- this.getAssociatedEventEmitters(domain).forEach((emitter) => {
546
- emitter?.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
547
- });
548
- this._apiEmitter?.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
549
- }
550
- }
551
- }
552
- };
553
- var OpenFeature = OpenFeatureAPI.getInstance();
415
+ import {
416
+ OpenFeatureCommonAPI,
417
+ ProviderWrapper,
418
+ objectOrUndefined,
419
+ stringOrUndefined
420
+ } from "@openfeature/core";
554
421
 
555
- // src/client/open-feature-client.ts
422
+ // src/client/internal/open-feature-client.ts
423
+ import {
424
+ ErrorCode as ErrorCode2,
425
+ ProviderFatalError,
426
+ ProviderNotReadyError,
427
+ SafeLogger,
428
+ StandardResolutionReasons as StandardResolutionReasons2,
429
+ instantiateErrorByErrorCode,
430
+ statusMatchesEvent
431
+ } from "@openfeature/core";
556
432
  var OpenFeatureClient = class {
557
433
  constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options) {
558
434
  this.providerAccessor = providerAccessor;
@@ -560,14 +436,14 @@ var OpenFeatureClient = class {
560
436
  this.emitterAccessor = emitterAccessor;
561
437
  this.globalLogger = globalLogger;
562
438
  this.options = options;
439
+ this._hooks = [];
563
440
  }
564
- _hooks = [];
565
- _clientLogger;
566
441
  get metadata() {
442
+ var _a, _b;
567
443
  return {
568
444
  // Use domain if name is not provided
569
- name: this.options.domain ?? this.options.name,
570
- domain: this.options.domain ?? this.options.name,
445
+ name: (_a = this.options.domain) != null ? _a : this.options.name,
446
+ domain: (_b = this.options.domain) != null ? _b : this.options.name,
571
447
  version: this.options.version,
572
448
  providerMetadata: this.providerAccessor().metadata
573
449
  };
@@ -576,6 +452,7 @@ var OpenFeatureClient = class {
576
452
  return this.providerStatusAccessor();
577
453
  }
578
454
  addHandler(eventType, handler) {
455
+ var _a;
579
456
  this.emitterAccessor().addHandler(eventType, handler);
580
457
  const shouldRunNow = statusMatchesEvent(eventType, this.providerStatus);
581
458
  if (shouldRunNow) {
@@ -586,7 +463,7 @@ var OpenFeatureClient = class {
586
463
  providerName: this._provider.metadata.name
587
464
  });
588
465
  } catch (err) {
589
- this._logger?.error("Error running event handler:", err);
466
+ (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
590
467
  }
591
468
  }
592
469
  }
@@ -650,6 +527,7 @@ var OpenFeatureClient = class {
650
527
  return this.evaluate(flagKey, this._provider.resolveObjectEvaluation, defaultValue, "object", options);
651
528
  }
652
529
  evaluate(flagKey, resolver, defaultValue, flagType, options = {}) {
530
+ var _a, _b;
653
531
  const allHooks = [
654
532
  ...OpenFeature.getHooks(),
655
533
  ...this.getHooks(),
@@ -657,9 +535,7 @@ var OpenFeatureClient = class {
657
535
  ...this._provider.hooks || []
658
536
  ];
659
537
  const allHooksReversed = [...allHooks].reverse();
660
- const context = {
661
- ...OpenFeature.getContext(this?.options?.domain)
662
- };
538
+ const context = __spreadValues({}, OpenFeature.getContext((_a = this == null ? void 0 : this.options) == null ? void 0 : _a.domain));
663
539
  const hookContext = {
664
540
  flagKey,
665
541
  defaultValue,
@@ -677,16 +553,18 @@ var OpenFeatureClient = class {
677
553
  throw new ProviderFatalError("provider is in an irrecoverable error state");
678
554
  }
679
555
  const resolution = resolver.call(this._provider, flagKey, defaultValue, context, this._logger);
680
- const evaluationDetails = {
681
- ...resolution,
682
- flagMetadata: Object.freeze(resolution.flagMetadata ?? {}),
556
+ const evaluationDetails = __spreadProps(__spreadValues({}, resolution), {
557
+ flagMetadata: Object.freeze((_b = resolution.flagMetadata) != null ? _b : {}),
683
558
  flagKey
684
- };
559
+ });
560
+ if (evaluationDetails.errorCode) {
561
+ throw instantiateErrorByErrorCode(evaluationDetails.errorCode);
562
+ }
685
563
  this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options);
686
564
  return evaluationDetails;
687
565
  } catch (err) {
688
- const errorMessage = err?.message;
689
- const errorCode = err?.code || ErrorCode2.GENERAL;
566
+ const errorMessage = err == null ? void 0 : err.message;
567
+ const errorCode = (err == null ? void 0 : err.code) || ErrorCode2.GENERAL;
690
568
  this.errorHooks(allHooksReversed, hookContext, err, options);
691
569
  return {
692
570
  errorCode,
@@ -701,40 +579,44 @@ var OpenFeatureClient = class {
701
579
  }
702
580
  }
703
581
  beforeHooks(hooks, hookContext, options) {
582
+ var _a;
704
583
  Object.freeze(hookContext);
705
584
  Object.freeze(hookContext.context);
706
585
  for (const hook of hooks) {
707
- hook?.before?.(hookContext, Object.freeze(options.hookHints));
586
+ (_a = hook == null ? void 0 : hook.before) == null ? void 0 : _a.call(hook, hookContext, Object.freeze(options.hookHints));
708
587
  }
709
588
  }
710
589
  afterHooks(hooks, hookContext, evaluationDetails, options) {
590
+ var _a;
711
591
  for (const hook of hooks) {
712
- hook?.after?.(hookContext, evaluationDetails, options.hookHints);
592
+ (_a = hook == null ? void 0 : hook.after) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, options.hookHints);
713
593
  }
714
594
  }
715
595
  errorHooks(hooks, hookContext, err, options) {
596
+ var _a;
716
597
  for (const hook of hooks) {
717
598
  try {
718
- hook?.error?.(hookContext, err, options.hookHints);
599
+ (_a = hook == null ? void 0 : hook.error) == null ? void 0 : _a.call(hook, hookContext, err, options.hookHints);
719
600
  } catch (err2) {
720
601
  this._logger.error(`Unhandled error during 'error' hook: ${err2}`);
721
602
  if (err2 instanceof Error) {
722
603
  this._logger.error(err2.stack);
723
604
  }
724
- this._logger.error(err2?.stack);
605
+ this._logger.error(err2 == null ? void 0 : err2.stack);
725
606
  }
726
607
  }
727
608
  }
728
609
  finallyHooks(hooks, hookContext, options) {
610
+ var _a;
729
611
  for (const hook of hooks) {
730
612
  try {
731
- hook?.finally?.(hookContext, options.hookHints);
613
+ (_a = hook == null ? void 0 : hook.finally) == null ? void 0 : _a.call(hook, hookContext, options.hookHints);
732
614
  } catch (err) {
733
615
  this._logger.error(`Unhandled error during 'finally' hook: ${err}`);
734
616
  if (err instanceof Error) {
735
617
  this._logger.error(err.stack);
736
618
  }
737
- this._logger.error(err?.stack);
619
+ this._logger.error(err == null ? void 0 : err.stack);
738
620
  }
739
621
  }
740
622
  }
@@ -746,6 +628,222 @@ var OpenFeatureClient = class {
746
628
  }
747
629
  };
748
630
 
631
+ // src/open-feature.ts
632
+ var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
633
+ var _globalThis = globalThis;
634
+ var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
635
+ constructor() {
636
+ super("client");
637
+ this._statusEnumType = ClientProviderStatus;
638
+ this._apiEmitter = new OpenFeatureEventEmitter();
639
+ this._defaultProvider = new ProviderWrapper(
640
+ NOOP_PROVIDER,
641
+ ClientProviderStatus.NOT_READY,
642
+ this._statusEnumType
643
+ );
644
+ this._domainScopedProviders = /* @__PURE__ */ new Map();
645
+ this._createEventEmitter = () => new OpenFeatureEventEmitter();
646
+ }
647
+ /**
648
+ * Gets a singleton instance of the OpenFeature API.
649
+ * @ignore
650
+ * @returns {OpenFeatureAPI} OpenFeature API
651
+ */
652
+ static getInstance() {
653
+ const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];
654
+ if (globalApi) {
655
+ return globalApi;
656
+ }
657
+ const instance = new _OpenFeatureAPI();
658
+ _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
659
+ return instance;
660
+ }
661
+ getProviderStatus(domain) {
662
+ var _a, _b;
663
+ if (!domain) {
664
+ return this._defaultProvider.status;
665
+ }
666
+ return (_b = (_a = this._domainScopedProviders.get(domain)) == null ? void 0 : _a.status) != null ? _b : this._defaultProvider.status;
667
+ }
668
+ setProviderAndWait(clientOrProvider, providerContextOrUndefined, contextOrUndefined) {
669
+ return __async(this, null, function* () {
670
+ const domain = stringOrUndefined(clientOrProvider);
671
+ const provider = domain ? objectOrUndefined(providerContextOrUndefined) : objectOrUndefined(clientOrProvider);
672
+ const context = domain ? objectOrUndefined(contextOrUndefined) : objectOrUndefined(providerContextOrUndefined);
673
+ if (context) {
674
+ if (domain) {
675
+ this._domainScopedContext.set(domain, context);
676
+ } else {
677
+ this._context = context;
678
+ }
679
+ }
680
+ yield this.setAwaitableProvider(domain, provider);
681
+ });
682
+ }
683
+ setProvider(domainOrProvider, providerContextOrUndefined, contextOrUndefined) {
684
+ const domain = stringOrUndefined(domainOrProvider);
685
+ const provider = domain ? objectOrUndefined(providerContextOrUndefined) : objectOrUndefined(domainOrProvider);
686
+ const context = domain ? objectOrUndefined(contextOrUndefined) : objectOrUndefined(providerContextOrUndefined);
687
+ if (context) {
688
+ if (domain) {
689
+ this._domainScopedContext.set(domain, context);
690
+ } else {
691
+ this._context = context;
692
+ }
693
+ }
694
+ const maybePromise = this.setAwaitableProvider(domain, provider);
695
+ Promise.resolve(maybePromise).catch((err) => {
696
+ this._logger.error("Error during provider initialization:", err);
697
+ });
698
+ return this;
699
+ }
700
+ setContext(domainOrContext, contextOrUndefined) {
701
+ return __async(this, null, function* () {
702
+ var _a, _b;
703
+ const domain = stringOrUndefined(domainOrContext);
704
+ const context = (_b = (_a = objectOrUndefined(domainOrContext)) != null ? _a : objectOrUndefined(contextOrUndefined)) != null ? _b : {};
705
+ if (domain) {
706
+ const wrapper = this._domainScopedProviders.get(domain);
707
+ if (wrapper) {
708
+ const oldContext = this.getContext(domain);
709
+ this._domainScopedContext.set(domain, context);
710
+ yield this.runProviderContextChangeHandler(domain, wrapper, oldContext, context);
711
+ } else {
712
+ this._domainScopedContext.set(domain, context);
713
+ }
714
+ } else {
715
+ const oldContext = this._context;
716
+ this._context = context;
717
+ const unboundProviders = Array.from(this._domainScopedProviders.entries()).filter(([domain2]) => !this._domainScopedContext.has(domain2)).reduce((acc, [domain2, wrapper]) => {
718
+ acc.push({ domain: domain2, wrapper });
719
+ return acc;
720
+ }, []);
721
+ const allDomainRecords = [
722
+ // add in the default (no domain)
723
+ { domain: void 0, wrapper: this._defaultProvider },
724
+ ...unboundProviders
725
+ ];
726
+ yield Promise.all(
727
+ allDomainRecords.map((dm) => this.runProviderContextChangeHandler(dm.domain, dm.wrapper, oldContext, context))
728
+ );
729
+ }
730
+ });
731
+ }
732
+ getContext(domainOrUndefined) {
733
+ const domain = stringOrUndefined(domainOrUndefined);
734
+ if (domain) {
735
+ const context = this._domainScopedContext.get(domain);
736
+ if (context) {
737
+ return context;
738
+ } else {
739
+ this._logger.debug(`Unable to find context for '${domain}'.`);
740
+ }
741
+ }
742
+ return this._context;
743
+ }
744
+ clearContext(domainOrUndefined) {
745
+ return __async(this, null, function* () {
746
+ const domain = stringOrUndefined(domainOrUndefined);
747
+ if (domain) {
748
+ const wrapper = this._domainScopedProviders.get(domain);
749
+ if (wrapper) {
750
+ const oldContext = this.getContext(domain);
751
+ this._domainScopedContext.delete(domain);
752
+ const newContext = this.getContext();
753
+ yield this.runProviderContextChangeHandler(domain, wrapper, oldContext, newContext);
754
+ } else {
755
+ this._domainScopedContext.delete(domain);
756
+ }
757
+ } else {
758
+ return this.setContext({});
759
+ }
760
+ });
761
+ }
762
+ /**
763
+ * Resets the global evaluation context and removes the evaluation context for
764
+ * all domains.
765
+ */
766
+ clearContexts() {
767
+ return __async(this, null, function* () {
768
+ yield this.clearContext();
769
+ yield Promise.allSettled(Array.from(this._domainScopedProviders.keys()).map((domain) => this.clearContext(domain)));
770
+ });
771
+ }
772
+ /**
773
+ * A factory function for creating new named OpenFeature clients. Clients can contain
774
+ * their own state (e.g. logger, hook, context). Multiple clients can be used
775
+ * to segment feature flag configuration.
776
+ *
777
+ * If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.
778
+ * Otherwise, the default provider is used until a provider is assigned to that name.
779
+ * @param {string} domain An identifier which logically binds clients with providers
780
+ * @param {string} version The version of the client (only used for metadata)
781
+ * @returns {Client} OpenFeature Client
782
+ */
783
+ getClient(domain, version) {
784
+ return new OpenFeatureClient(
785
+ // functions are passed here to make sure that these values are always up to date,
786
+ // and so we don't have to make these public properties on the API class.
787
+ () => this.getProviderForClient(domain),
788
+ () => this.getProviderStatus(domain),
789
+ () => this.buildAndCacheEventEmitterForClient(domain),
790
+ () => this._logger,
791
+ { domain, version }
792
+ );
793
+ }
794
+ /**
795
+ * Clears all registered providers and resets the default provider.
796
+ * @returns {Promise<void>}
797
+ */
798
+ clearProviders() {
799
+ return __async(this, null, function* () {
800
+ yield __superGet(_OpenFeatureAPI.prototype, this, "clearProvidersAndSetDefault").call(this, NOOP_PROVIDER);
801
+ this._domainScopedContext.clear();
802
+ });
803
+ }
804
+ runProviderContextChangeHandler(domain, wrapper, oldContext, newContext) {
805
+ return __async(this, null, function* () {
806
+ var _a, _b, _c, _d, _e, _f;
807
+ const providerName = ((_b = (_a = wrapper.provider) == null ? void 0 : _a.metadata) == null ? void 0 : _b.name) || "unnamed-provider";
808
+ try {
809
+ if (typeof wrapper.provider.onContextChange === "function") {
810
+ const maybePromise = wrapper.provider.onContextChange(oldContext, newContext);
811
+ if (typeof (maybePromise == null ? void 0 : maybePromise.then) === "function") {
812
+ wrapper.incrementPendingContextChanges();
813
+ wrapper.status = this._statusEnumType.RECONCILING;
814
+ this.getAssociatedEventEmitters(domain).forEach((emitter) => {
815
+ emitter == null ? void 0 : emitter.emit(ClientProviderEvents.Reconciling, { domain, providerName });
816
+ });
817
+ (_c = this._apiEmitter) == null ? void 0 : _c.emit(ClientProviderEvents.Reconciling, { domain, providerName });
818
+ yield maybePromise;
819
+ wrapper.decrementPendingContextChanges();
820
+ }
821
+ }
822
+ wrapper.status = this._statusEnumType.READY;
823
+ if (wrapper.allContextChangesSettled) {
824
+ this.getAssociatedEventEmitters(domain).forEach((emitter) => {
825
+ emitter == null ? void 0 : emitter.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
826
+ });
827
+ (_d = this._apiEmitter) == null ? void 0 : _d.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
828
+ }
829
+ } catch (err) {
830
+ wrapper.decrementPendingContextChanges();
831
+ wrapper.status = this._statusEnumType.ERROR;
832
+ if (wrapper.allContextChangesSettled) {
833
+ const error = err;
834
+ const message = `Error running ${providerName}'s context change handler: ${error == null ? void 0 : error.message}`;
835
+ (_e = this._logger) == null ? void 0 : _e.error(`${message}`, err);
836
+ this.getAssociatedEventEmitters(domain).forEach((emitter) => {
837
+ emitter == null ? void 0 : emitter.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
838
+ });
839
+ (_f = this._apiEmitter) == null ? void 0 : _f.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
840
+ }
841
+ }
842
+ });
843
+ }
844
+ };
845
+ var OpenFeature = OpenFeatureAPI.getInstance();
846
+
749
847
  // src/index.ts
750
848
  export * from "@openfeature/core";
751
849
  export {
@@ -753,7 +851,6 @@ export {
753
851
  NOOP_PROVIDER,
754
852
  OpenFeature,
755
853
  OpenFeatureAPI,
756
- OpenFeatureClient,
757
854
  OpenFeatureEventEmitter,
758
855
  ClientProviderEvents as ProviderEvents,
759
856
  ClientProviderStatus as ProviderStatus