@openfeature/web-sdk 0.4.7 → 0.4.9

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/web-sdk-v0.4.7">
20
- <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.7&color=blue&style=for-the-badge" />
19
+ <a href="https://github.com/open-feature/js-sdk/releases/tag/web-sdk-v0.4.9">
20
+ <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.9&color=blue&style=for-the-badge" />
21
21
  </a>
22
22
  <!-- x-release-please-end -->
23
23
  <br/>
package/dist/cjs/index.js CHANGED
@@ -9,6 +9,7 @@ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
9
  var __getProtoOf = Object.getPrototypeOf;
10
10
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
11
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __reflectGet = Reflect.get;
12
13
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
14
  var __spreadValues = (a, b) => {
14
15
  for (var prop in b || (b = {}))
@@ -47,6 +48,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
47
48
  mod
48
49
  ));
49
50
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
51
+ var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
50
52
  var __async = (__this, __arguments, generator) => {
51
53
  return new Promise((resolve, reject) => {
52
54
  var fulfilled = (value) => {
@@ -448,18 +450,36 @@ __export(src_exports, {
448
450
  OpenFeature: () => OpenFeature,
449
451
  OpenFeatureAPI: () => OpenFeatureAPI,
450
452
  OpenFeatureClient: () => OpenFeatureClient,
451
- OpenFeatureEventEmitter: () => OpenFeatureEventEmitter
453
+ OpenFeatureEventEmitter: () => OpenFeatureEventEmitter,
454
+ ProviderEvents: () => import_core2.ClientProviderEvents
452
455
  });
453
456
  module.exports = __toCommonJS(src_exports);
454
457
 
455
458
  // src/client/open-feature-client.ts
456
- var import_core6 = require("@openfeature/core");
459
+ var import_core7 = require("@openfeature/core");
457
460
 
458
461
  // src/open-feature.ts
459
- var import_core5 = require("@openfeature/core");
462
+ var import_core6 = require("@openfeature/core");
460
463
 
461
- // src/provider/no-op-provider.ts
464
+ // src/events/open-feature-event-emitter.ts
462
465
  var import_core = require("@openfeature/core");
466
+ var import_events = __toESM(require_events());
467
+ var OpenFeatureEventEmitter = class extends import_core.GenericEventEmitter {
468
+ constructor() {
469
+ super();
470
+ this.eventEmitter = new import_events.default({ captureRejections: true });
471
+ this.eventEmitter.on("error", (err) => {
472
+ var _a;
473
+ (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
474
+ });
475
+ }
476
+ };
477
+
478
+ // src/events/events.ts
479
+ var import_core2 = require("@openfeature/core");
480
+
481
+ // src/provider/no-op-provider.ts
482
+ var import_core3 = require("@openfeature/core");
463
483
  var REASON_NO_OP = "No-op";
464
484
  var NoopFeatureProvider = class {
465
485
  constructor() {
@@ -468,7 +488,7 @@ var NoopFeatureProvider = class {
468
488
  };
469
489
  }
470
490
  get status() {
471
- return import_core.ProviderStatus.NOT_READY;
491
+ return import_core3.ProviderStatus.NOT_READY;
472
492
  }
473
493
  resolveBooleanEvaluation(_, defaultValue) {
474
494
  return this.noOp(defaultValue);
@@ -492,30 +512,16 @@ var NoopFeatureProvider = class {
492
512
  var NOOP_PROVIDER = new NoopFeatureProvider();
493
513
 
494
514
  // src/provider/in-memory-provider/in-memory-provider.ts
495
- var import_core4 = require("@openfeature/core");
496
-
497
- // src/events/open-feature-event-emitter.ts
498
- var import_core2 = require("@openfeature/core");
499
- var import_events = __toESM(require_events());
500
- var OpenFeatureEventEmitter = class extends import_core2.GenericEventEmitter {
501
- constructor() {
502
- super();
503
- this.eventEmitter = new import_events.default({ captureRejections: true });
504
- this.eventEmitter.on("error", (err) => {
505
- var _a;
506
- (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
507
- });
508
- }
509
- };
515
+ var import_core5 = require("@openfeature/core");
510
516
 
511
517
  // src/provider/in-memory-provider/variant-not-found-error.ts
512
- var import_core3 = require("@openfeature/core");
513
- var VariantNotFoundError = class extends import_core3.OpenFeatureError {
518
+ var import_core4 = require("@openfeature/core");
519
+ var VariantNotFoundError = class extends import_core4.OpenFeatureError {
514
520
  constructor(message) {
515
521
  super(message);
516
522
  Object.setPrototypeOf(this, VariantNotFoundError.prototype);
517
523
  this.name = "VariantNotFoundError";
518
- this.code = import_core3.ErrorCode.GENERAL;
524
+ this.code = import_core4.ErrorCode.GENERAL;
519
525
  }
520
526
  };
521
527
 
@@ -524,7 +530,7 @@ var InMemoryProvider = class {
524
530
  constructor(flagConfiguration = {}) {
525
531
  this.events = new OpenFeatureEventEmitter();
526
532
  this.runsOn = "client";
527
- this.status = import_core4.ProviderStatus.NOT_READY;
533
+ this.status = import_core5.ProviderStatus.NOT_READY;
528
534
  this.metadata = {
529
535
  name: "in-memory"
530
536
  };
@@ -537,9 +543,9 @@ var InMemoryProvider = class {
537
543
  this.resolveFlagWithReason(key, context);
538
544
  }
539
545
  this._context = context;
540
- this.status = import_core4.ProviderStatus.READY;
546
+ this.status = import_core5.ProviderStatus.READY;
541
547
  } catch (error) {
542
- this.status = import_core4.ProviderStatus.ERROR;
548
+ this.status = import_core5.ProviderStatus.ERROR;
543
549
  throw error;
544
550
  }
545
551
  });
@@ -551,15 +557,15 @@ var InMemoryProvider = class {
551
557
  putConfiguration(flagConfiguration) {
552
558
  return __async(this, null, function* () {
553
559
  const flagsChanged = Object.entries(flagConfiguration).filter(([key, value]) => this._flagConfiguration[key] !== value).map(([key]) => key);
554
- this.status = import_core4.ProviderStatus.STALE;
555
- this.events.emit(import_core4.ProviderEvents.Stale);
560
+ this.status = import_core5.ProviderStatus.STALE;
561
+ this.events.emit(import_core2.ClientProviderEvents.Stale);
556
562
  this._flagConfiguration = __spreadValues({}, flagConfiguration);
557
- this.events.emit(import_core4.ProviderEvents.ConfigurationChanged, { flagsChanged });
563
+ this.events.emit(import_core2.ClientProviderEvents.ConfigurationChanged, { flagsChanged });
558
564
  try {
559
565
  yield this.initialize(this._context);
560
- this.events.emit(import_core4.ProviderEvents.Ready);
566
+ this.events.emit(import_core2.ClientProviderEvents.Ready);
561
567
  } catch (err) {
562
- this.events.emit(import_core4.ProviderEvents.Error);
568
+ this.events.emit(import_core2.ClientProviderEvents.Error);
563
569
  throw err;
564
570
  }
565
571
  });
@@ -580,10 +586,10 @@ var InMemoryProvider = class {
580
586
  if (!(flagKey in this._flagConfiguration)) {
581
587
  const message = `no flag found with key ${flagKey}`;
582
588
  logger == null ? void 0 : logger.debug(message);
583
- throw new import_core4.FlagNotFoundError(message);
589
+ throw new import_core5.FlagNotFoundError(message);
584
590
  }
585
591
  if (this._flagConfiguration[flagKey].disabled) {
586
- return { value: defaultValue, reason: import_core4.StandardResolutionReasons.DISABLED };
592
+ return { value: defaultValue, reason: import_core5.StandardResolutionReasons.DISABLED };
587
593
  }
588
594
  const resolvedFlag = this.resolveFlagWithReason(flagKey, context);
589
595
  if (resolvedFlag.value === void 0) {
@@ -592,7 +598,7 @@ var InMemoryProvider = class {
592
598
  throw new VariantNotFoundError(message);
593
599
  }
594
600
  if (typeof resolvedFlag.value != typeof defaultValue) {
595
- throw new import_core4.TypeMismatchError();
601
+ throw new import_core5.TypeMismatchError();
596
602
  }
597
603
  return resolvedFlag;
598
604
  }
@@ -601,8 +607,8 @@ var InMemoryProvider = class {
601
607
  const resolutionResult = this.lookupFlagValue(flagKey, ctx);
602
608
  return resolutionResult;
603
609
  } catch (error) {
604
- if (!(error instanceof import_core4.OpenFeatureError)) {
605
- throw new import_core4.GeneralError((error == null ? void 0 : error.message) || "unknown error");
610
+ if (!(error instanceof import_core5.OpenFeatureError)) {
611
+ throw new import_core5.GeneralError((error == null ? void 0 : error.message) || "unknown error");
606
612
  }
607
613
  throw error;
608
614
  }
@@ -613,8 +619,8 @@ var InMemoryProvider = class {
613
619
  const isContextEval = ctx && (flagSpec == null ? void 0 : flagSpec.contextEvaluator);
614
620
  const variant = isContextEval ? (_a = flagSpec.contextEvaluator) == null ? void 0 : _a.call(flagSpec, ctx) : flagSpec.defaultVariant;
615
621
  const value = variant && (flagSpec == null ? void 0 : flagSpec.variants[variant]);
616
- const evalReason = isContextEval ? import_core4.StandardResolutionReasons.TARGETING_MATCH : import_core4.StandardResolutionReasons.STATIC;
617
- const reason = this.status === import_core4.ProviderStatus.STALE ? import_core4.StandardResolutionReasons.CACHED : evalReason;
622
+ const evalReason = isContextEval ? import_core5.StandardResolutionReasons.TARGETING_MATCH : import_core5.StandardResolutionReasons.STATIC;
623
+ const reason = this.status === import_core5.ProviderStatus.STALE ? import_core5.StandardResolutionReasons.CACHED : evalReason;
618
624
  return __spreadProps(__spreadValues({
619
625
  value
620
626
  }, variant && { variant }), {
@@ -626,13 +632,13 @@ var InMemoryProvider = class {
626
632
  // src/open-feature.ts
627
633
  var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
628
634
  var _globalThis = globalThis;
629
- var OpenFeatureAPI = class extends import_core5.OpenFeatureCommonAPI {
630
- // eslint-disable-next-line @typescript-eslint/no-empty-function
635
+ var OpenFeatureAPI = class extends import_core6.OpenFeatureCommonAPI {
631
636
  constructor() {
632
637
  super("client");
633
638
  this._events = new OpenFeatureEventEmitter();
634
639
  this._defaultProvider = NOOP_PROVIDER;
635
640
  this._createEventEmitter = () => new OpenFeatureEventEmitter();
641
+ this._namedProviderContext = /* @__PURE__ */ new Map();
636
642
  }
637
643
  /**
638
644
  * Gets a singleton instance of the OpenFeature API.
@@ -648,26 +654,74 @@ var OpenFeatureAPI = class extends import_core5.OpenFeatureCommonAPI {
648
654
  _globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
649
655
  return instance;
650
656
  }
651
- setContext(context) {
657
+ setContext(nameOrContext, contextOrUndefined) {
652
658
  return __async(this, null, function* () {
653
- const oldContext = this._context;
654
- this._context = context;
655
- const allProviders = [this._defaultProvider, ...this._clientProviders.values()];
656
- yield Promise.all(
657
- allProviders.map((provider) => __async(this, null, function* () {
658
- var _a, _b;
659
- try {
660
- return yield (_a = provider.onContextChange) == null ? void 0 : _a.call(provider, oldContext, context);
661
- } catch (err) {
662
- (_b = this._logger) == null ? void 0 : _b.error(`Error running context change handler of provider ${provider.metadata.name}:`, err);
663
- }
664
- }))
665
- );
659
+ var _a, _b;
660
+ const clientName = (0, import_core6.stringOrUndefined)(nameOrContext);
661
+ const context = (_b = (_a = (0, import_core6.objectOrUndefined)(nameOrContext)) != null ? _a : (0, import_core6.objectOrUndefined)(contextOrUndefined)) != null ? _b : {};
662
+ if (clientName) {
663
+ const provider = this._clientProviders.get(clientName);
664
+ if (provider) {
665
+ const oldContext = this.getContext(clientName);
666
+ this._namedProviderContext.set(clientName, context);
667
+ yield this.runProviderContextChangeHandler(clientName, provider, oldContext, context);
668
+ } else {
669
+ this._namedProviderContext.set(clientName, context);
670
+ }
671
+ } else {
672
+ const oldContext = this._context;
673
+ this._context = context;
674
+ const providersWithoutContextOverride = Array.from(this._clientProviders.entries()).filter(([name]) => !this._namedProviderContext.has(name)).reduce((acc, [, provider]) => {
675
+ acc.push(provider);
676
+ return acc;
677
+ }, []);
678
+ const allProviders = [this._defaultProvider, ...providersWithoutContextOverride];
679
+ yield Promise.all(
680
+ allProviders.map((provider) => this.runProviderContextChangeHandler(void 0, provider, oldContext, context))
681
+ );
682
+ }
666
683
  });
667
684
  }
668
- getContext() {
685
+ getContext(nameOrUndefined) {
686
+ const clientName = (0, import_core6.stringOrUndefined)(nameOrUndefined);
687
+ if (clientName) {
688
+ const context = this._namedProviderContext.get(clientName);
689
+ if (context) {
690
+ return context;
691
+ } else {
692
+ this._logger.debug(`Unable to find context for '${clientName}'.`);
693
+ }
694
+ }
669
695
  return this._context;
670
696
  }
697
+ clearContext(nameOrUndefined) {
698
+ return __async(this, null, function* () {
699
+ const clientName = (0, import_core6.stringOrUndefined)(nameOrUndefined);
700
+ if (clientName) {
701
+ const provider = this._clientProviders.get(clientName);
702
+ if (provider) {
703
+ const oldContext = this.getContext(clientName);
704
+ this._namedProviderContext.delete(clientName);
705
+ const newContext = this.getContext();
706
+ yield this.runProviderContextChangeHandler(clientName, provider, oldContext, newContext);
707
+ } else {
708
+ this._namedProviderContext.delete(clientName);
709
+ }
710
+ } else {
711
+ return this.setContext({});
712
+ }
713
+ });
714
+ }
715
+ /**
716
+ * Resets the global evaluation context and removes the evaluation context for
717
+ * all named clients.
718
+ */
719
+ clearContexts() {
720
+ return __async(this, null, function* () {
721
+ yield this.clearContext();
722
+ yield Promise.allSettled(Array.from(this._clientProviders.keys()).map((name) => this.clearContext(name)));
723
+ });
724
+ }
671
725
  /**
672
726
  * A factory function for creating new named OpenFeature clients. Clients can contain
673
727
  * their own state (e.g. logger, hook, context). Multiple clients can be used
@@ -694,7 +748,30 @@ var OpenFeatureAPI = class extends import_core5.OpenFeatureCommonAPI {
694
748
  * @returns {Promise<void>}
695
749
  */
696
750
  clearProviders() {
697
- return super.clearProvidersAndSetDefault(NOOP_PROVIDER);
751
+ return __async(this, null, function* () {
752
+ yield __superGet(OpenFeatureAPI.prototype, this, "clearProvidersAndSetDefault").call(this, NOOP_PROVIDER);
753
+ this._namedProviderContext.clear();
754
+ });
755
+ }
756
+ runProviderContextChangeHandler(clientName, provider, oldContext, newContext) {
757
+ return __async(this, null, function* () {
758
+ var _a;
759
+ const providerName = provider.metadata.name;
760
+ return (_a = provider.onContextChange) == null ? void 0 : _a.call(provider, oldContext, newContext).then(() => {
761
+ var _a2;
762
+ this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
763
+ emitter == null ? void 0 : emitter.emit(import_core2.ClientProviderEvents.ContextChanged, { clientName, providerName });
764
+ });
765
+ (_a2 = this._events) == null ? void 0 : _a2.emit(import_core2.ClientProviderEvents.ContextChanged, { clientName, providerName });
766
+ }).catch((err) => {
767
+ var _a2, _b;
768
+ (_a2 = this._logger) == null ? void 0 : _a2.error(`Error running ${provider.metadata.name}'s context change handler:`, err);
769
+ this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
770
+ emitter == null ? void 0 : emitter.emit(import_core2.ClientProviderEvents.Error, { clientName, providerName, message: err == null ? void 0 : err.message });
771
+ });
772
+ (_b = this._events) == null ? void 0 : _b.emit(import_core2.ClientProviderEvents.Error, { clientName, providerName, message: err == null ? void 0 : err.message });
773
+ });
774
+ });
698
775
  }
699
776
  };
700
777
  var OpenFeature = OpenFeatureAPI.getInstance();
@@ -715,11 +792,15 @@ var OpenFeatureClient = class {
715
792
  providerMetadata: this.providerAccessor().metadata
716
793
  };
717
794
  }
795
+ get providerStatus() {
796
+ var _a;
797
+ return ((_a = this.providerAccessor()) == null ? void 0 : _a.status) || import_core7.ProviderStatus.READY;
798
+ }
718
799
  addHandler(eventType, handler) {
719
800
  var _a;
720
801
  this.emitterAccessor().addHandler(eventType, handler);
721
- const providerReady = !this._provider.status || this._provider.status === import_core6.ProviderStatus.READY;
722
- if (eventType === import_core6.ProviderEvents.Ready && providerReady) {
802
+ const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._provider.status);
803
+ if (shouldRunNow) {
723
804
  try {
724
805
  handler({ clientName: this.metadata.name, providerName: this._provider.metadata.name });
725
806
  } catch (err) {
@@ -734,7 +815,7 @@ var OpenFeatureClient = class {
734
815
  return this.emitterAccessor().getHandlers(eventType);
735
816
  }
736
817
  setLogger(logger) {
737
- this._clientLogger = new import_core6.SafeLogger(logger);
818
+ this._clientLogger = new import_core7.SafeLogger(logger);
738
819
  return this;
739
820
  }
740
821
  addHooks(...hooks) {
@@ -816,13 +897,13 @@ var OpenFeatureClient = class {
816
897
  return evaluationDetails;
817
898
  } catch (err) {
818
899
  const errorMessage = err == null ? void 0 : err.message;
819
- const errorCode = (err == null ? void 0 : err.code) || import_core6.ErrorCode.GENERAL;
900
+ const errorCode = (err == null ? void 0 : err.code) || import_core7.ErrorCode.GENERAL;
820
901
  this.errorHooks(allHooksReversed, hookContext, err, options);
821
902
  return {
822
903
  errorCode,
823
904
  errorMessage,
824
905
  value: defaultValue,
825
- reason: import_core6.StandardResolutionReasons.ERROR,
906
+ reason: import_core7.StandardResolutionReasons.ERROR,
826
907
  flagMetadata: Object.freeze({}),
827
908
  flagKey
828
909
  };