@openfeature/web-sdk 0.4.0 → 0.4.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/dist/cjs/index.js CHANGED
@@ -450,7 +450,6 @@ __export(src_exports, {
450
450
  InvalidContextError: () => InvalidContextError,
451
451
  LOG_LEVELS: () => LOG_LEVELS,
452
452
  NOOP_PROVIDER: () => NOOP_PROVIDER,
453
- NOOP_TRANSACTION_CONTEXT_PROPAGATOR: () => NOOP_TRANSACTION_CONTEXT_PROPAGATOR,
454
453
  OpenFeature: () => OpenFeature,
455
454
  OpenFeatureAPI: () => OpenFeatureAPI,
456
455
  OpenFeatureClient: () => OpenFeatureClient,
@@ -467,6 +466,7 @@ __export(src_exports, {
467
466
  isObject: () => isObject,
468
467
  isString: () => isString,
469
468
  objectOrUndefined: () => objectOrUndefined,
469
+ statusMatchesEvent: () => statusMatchesEvent,
470
470
  stringOrUndefined: () => stringOrUndefined
471
471
  });
472
472
  module.exports = __toCommonJS(src_exports);
@@ -588,6 +588,15 @@ var InvalidContextError = class extends OpenFeatureError {
588
588
  }
589
589
  };
590
590
 
591
+ // ../shared/src/provider/provider.ts
592
+ var ProviderStatus = /* @__PURE__ */ ((ProviderStatus2) => {
593
+ ProviderStatus2["NOT_READY"] = "NOT_READY";
594
+ ProviderStatus2["READY"] = "READY";
595
+ ProviderStatus2["ERROR"] = "ERROR";
596
+ ProviderStatus2["STALE"] = "STALE";
597
+ return ProviderStatus2;
598
+ })(ProviderStatus || {});
599
+
591
600
  // ../shared/src/events/events.ts
592
601
  var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => {
593
602
  ProviderEvents2["Ready"] = "PROVIDER_READY";
@@ -597,6 +606,20 @@ var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => {
597
606
  return ProviderEvents2;
598
607
  })(ProviderEvents || {});
599
608
 
609
+ // ../shared/src/events/event-utils.ts
610
+ var eventStatusMap = {
611
+ ["READY" /* READY */]: "PROVIDER_READY" /* Ready */,
612
+ ["ERROR" /* ERROR */]: "PROVIDER_ERROR" /* Error */,
613
+ ["STALE" /* STALE */]: "PROVIDER_STALE" /* Stale */,
614
+ ["NOT_READY" /* NOT_READY */]: void 0
615
+ };
616
+ var statusMatchesEvent = (event, status) => {
617
+ return !status && event === "PROVIDER_READY" /* Ready */ || eventStatusMap[status] === event;
618
+ };
619
+
620
+ // ../shared/src/events/open-feature-event-emitter.ts
621
+ var import_events2 = __toESM(require_events());
622
+
600
623
  // ../shared/src/logger/default-logger.ts
601
624
  var DefaultLogger = class {
602
625
  error(...args) {
@@ -651,13 +674,12 @@ var SafeLogger = class {
651
674
  };
652
675
 
653
676
  // ../shared/src/events/open-feature-event-emitter.ts
654
- var import_events = __toESM(require_events());
655
677
  var GenericEventEmitter = class {
656
678
  constructor(globalLogger) {
657
679
  this.globalLogger = globalLogger;
658
680
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
659
681
  this._handlers = /* @__PURE__ */ new WeakMap();
660
- this.eventEmitter = new import_events.default({ captureRejections: true });
682
+ this.eventEmitter = new import_events2.default({ captureRejections: true });
661
683
  this.eventEmitter.on("error", (err) => {
662
684
  var _a;
663
685
  (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
@@ -667,8 +689,8 @@ var GenericEventEmitter = class {
667
689
  this.eventEmitter.emit(eventType, context);
668
690
  }
669
691
  addHandler(eventType, handler) {
670
- const asyncHandler = (context) => __async(this, null, function* () {
671
- yield handler(context);
692
+ const asyncHandler = (details) => __async(this, null, function* () {
693
+ yield handler(details);
672
694
  });
673
695
  this._handlers.set(handler, asyncHandler);
674
696
  this.eventEmitter.on(eventType, asyncHandler);
@@ -704,25 +726,6 @@ var OpenFeatureEventEmitter = class extends GenericEventEmitter {
704
726
  var InternalEventEmitter = class extends GenericEventEmitter {
705
727
  };
706
728
 
707
- // ../shared/src/provider/provider.ts
708
- var ProviderStatus = /* @__PURE__ */ ((ProviderStatus2) => {
709
- ProviderStatus2["NOT_READY"] = "NOT_READY";
710
- ProviderStatus2["READY"] = "READY";
711
- ProviderStatus2["ERROR"] = "ERROR";
712
- return ProviderStatus2;
713
- })(ProviderStatus || {});
714
-
715
- // ../shared/src/transaction-context/no-op-transaction-context-propagator.ts
716
- var NoopTransactionContextPropagator = class {
717
- getTransactionContext() {
718
- return {};
719
- }
720
- setTransactionContext(_, callback) {
721
- callback();
722
- }
723
- };
724
- var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator();
725
-
726
729
  // ../shared/src/type-guards.ts
727
730
  function isString(value) {
728
731
  return typeof value === "string";
@@ -744,15 +747,15 @@ function isDefined(input) {
744
747
 
745
748
  // ../shared/src/open-feature.ts
746
749
  var OpenFeatureCommonAPI = class {
747
- constructor() {
750
+ constructor(category) {
748
751
  this._hooks = [];
749
- this._transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR;
750
752
  this._context = {};
751
753
  this._logger = new DefaultLogger();
752
754
  this._events = new InternalEventEmitter(() => this._logger);
753
755
  this._clientEventHandlers = /* @__PURE__ */ new Map();
754
756
  this._clientProviders = /* @__PURE__ */ new Map();
755
757
  this._clientEvents = /* @__PURE__ */ new Map();
758
+ this._runsOn = category;
756
759
  }
757
760
  addHooks(...hooks) {
758
761
  this._hooks = [...this._hooks, ...hooks];
@@ -779,11 +782,24 @@ var OpenFeatureCommonAPI = class {
779
782
  /**
780
783
  * Adds a handler for the given provider event type.
781
784
  * The handlers are called in the order they have been added.
782
- * When changing the provider, the currently attached handlers will listen to the events of the new provider.
785
+ * API (global) events run for all providers.
783
786
  * @param {ProviderEvents} eventType The provider event type to listen to
784
787
  * @param {EventHandler} handler The handler to run on occurrence of the event type
785
788
  */
786
789
  addHandler(eventType, handler) {
790
+ [.../* @__PURE__ */ new Map([[void 0, this._defaultProvider]]), ...this._clientProviders].forEach((keyProviderTuple) => {
791
+ var _a;
792
+ const clientName = keyProviderTuple[0];
793
+ const provider = keyProviderTuple[1];
794
+ const shouldRunNow = statusMatchesEvent(eventType, keyProviderTuple[1].status);
795
+ if (shouldRunNow) {
796
+ try {
797
+ handler({ clientName, providerName: provider.metadata.name });
798
+ } catch (err) {
799
+ (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
800
+ }
801
+ }
802
+ });
787
803
  this._events.addHandler(eventType, handler);
788
804
  }
789
805
  /**
@@ -802,43 +818,66 @@ var OpenFeatureCommonAPI = class {
802
818
  getHandlers(eventType) {
803
819
  return this._events.getHandlers(eventType);
804
820
  }
821
+ setProviderAndWait(clientOrProvider, providerOrUndefined) {
822
+ return __async(this, null, function* () {
823
+ yield this.setAwaitableProvider(clientOrProvider, providerOrUndefined);
824
+ });
825
+ }
805
826
  setProvider(clientOrProvider, providerOrUndefined) {
806
- var _a, _b, _c, _d, _e, _f, _g;
827
+ const maybePromise = this.setAwaitableProvider(clientOrProvider, providerOrUndefined);
828
+ if (maybePromise) {
829
+ maybePromise.catch(() => {
830
+ });
831
+ }
832
+ return this;
833
+ }
834
+ setAwaitableProvider(clientOrProvider, providerOrUndefined) {
835
+ var _a, _b, _c, _d, _e, _f;
807
836
  const clientName = stringOrUndefined(clientOrProvider);
808
837
  const provider = (_a = objectOrUndefined(clientOrProvider)) != null ? _a : objectOrUndefined(providerOrUndefined);
809
838
  if (!provider) {
810
- return this;
839
+ this._logger.debug("No provider defined, ignoring setProvider call");
840
+ return;
811
841
  }
812
842
  const oldProvider = this.getProviderForClient(clientName);
843
+ const providerName = provider.metadata.name;
813
844
  if (oldProvider === provider) {
814
- return this;
845
+ this._logger.debug("Provider is already set, ignoring setProvider call");
846
+ return;
847
+ }
848
+ if (!provider.runsOn) {
849
+ this._logger.debug(`Provider '${provider.metadata.name}' has not defined its intended use.`);
850
+ } else if (provider.runsOn !== this._runsOn) {
851
+ throw new GeneralError(`Provider '${provider.metadata.name}' is intended for use on the ${provider.runsOn}.`);
815
852
  }
816
853
  const emitters = this.getAssociatedEventEmitters(clientName);
817
854
  if (typeof provider.initialize === "function" && provider.status === void 0) {
818
855
  const activeLogger = this._logger || console;
819
856
  activeLogger.warn(
820
- `Provider ${(_b = provider == null ? void 0 : provider.metadata) == null ? void 0 : _b.name} implements 'initialize' but not 'status'. Please implement 'status'.`
857
+ `Provider ${providerName} implements 'initialize' but not 'status'. Please implement 'status'.`
821
858
  );
822
859
  }
860
+ let initializationPromise = void 0;
823
861
  if ((provider == null ? void 0 : provider.status) === "NOT_READY" /* NOT_READY */ && typeof provider.initialize === "function") {
824
- (_e = (_d = (_c = provider.initialize) == null ? void 0 : _c.call(provider, this._context)) == null ? void 0 : _d.then(() => {
862
+ initializationPromise = (_d = (_c = (_b = provider.initialize) == null ? void 0 : _b.call(provider, this._context)) == null ? void 0 : _c.then(() => {
825
863
  var _a2;
826
864
  this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
827
- emitter == null ? void 0 : emitter.emit("PROVIDER_READY" /* Ready */, { clientName });
865
+ emitter == null ? void 0 : emitter.emit("PROVIDER_READY" /* Ready */, { clientName, providerName });
828
866
  });
829
- (_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */, { clientName });
830
- })) == null ? void 0 : _e.catch((error) => {
867
+ (_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */, { clientName, providerName });
868
+ })) == null ? void 0 : _d.catch((error) => {
831
869
  var _a2;
832
870
  this.getAssociatedEventEmitters(clientName).forEach((emitter) => {
833
- emitter == null ? void 0 : emitter.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message });
871
+ emitter == null ? void 0 : emitter.emit("PROVIDER_ERROR" /* Error */, { clientName, providerName, message: error.message });
834
872
  });
835
- (_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message });
873
+ (_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */, { clientName, providerName, message: error.message });
874
+ throw error;
836
875
  });
837
876
  } else {
838
877
  emitters.forEach((emitter) => {
839
- emitter == null ? void 0 : emitter.emit("PROVIDER_READY" /* Ready */, { clientName });
878
+ emitter == null ? void 0 : emitter.emit("PROVIDER_READY" /* Ready */, { clientName, providerName });
840
879
  });
841
- (_f = this._events) == null ? void 0 : _f.emit("PROVIDER_READY" /* Ready */, { clientName });
880
+ (_e = this._events) == null ? void 0 : _e.emit("PROVIDER_READY" /* Ready */, { clientName, providerName });
842
881
  }
843
882
  if (clientName) {
844
883
  this._clientProviders.set(clientName, provider);
@@ -847,9 +886,9 @@ var OpenFeatureCommonAPI = class {
847
886
  }
848
887
  this.transferListeners(oldProvider, provider, clientName, emitters);
849
888
  if (![...this._clientProviders.values(), this._defaultProvider].includes(oldProvider)) {
850
- (_g = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _g.call(oldProvider);
889
+ (_f = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _f.call(oldProvider);
851
890
  }
852
- return this;
891
+ return initializationPromise;
853
892
  }
854
893
  getProviderForClient(name) {
855
894
  var _a;
@@ -870,7 +909,7 @@ var OpenFeatureCommonAPI = class {
870
909
  (eventType) => {
871
910
  var _a;
872
911
  return (_a = clientProvider.events) == null ? void 0 : _a.addHandler(eventType, (details) => __async(this, null, function* () {
873
- newEmitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName: name }));
912
+ newEmitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName: name, providerName: clientProvider.metadata.name }));
874
913
  }));
875
914
  }
876
915
  );
@@ -899,9 +938,9 @@ var OpenFeatureCommonAPI = class {
899
938
  const newClientHandlers = Object.values(ProviderEvents).map((eventType) => {
900
939
  const handler = (details) => __async(this, null, function* () {
901
940
  emitters.forEach((emitter) => {
902
- emitter == null ? void 0 : emitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName }));
941
+ emitter == null ? void 0 : emitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName, providerName: newProvider.metadata.name }));
903
942
  });
904
- this._events.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName }));
943
+ this._events.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName, providerName: newProvider.metadata.name }));
905
944
  });
906
945
  return [eventType, handler];
907
946
  });
@@ -926,40 +965,28 @@ var OpenFeatureCommonAPI = class {
926
965
  try {
927
966
  yield (_a2 = provider.onClose) == null ? void 0 : _a2.call(provider);
928
967
  } catch (err) {
929
- this.handleShutdownError(this._defaultProvider, err);
968
+ this.handleShutdownError(provider, err);
930
969
  }
931
970
  }))
932
971
  );
933
972
  });
934
973
  }
974
+ clearProvidersAndSetDefault(defaultProvider) {
975
+ return __async(this, null, function* () {
976
+ try {
977
+ yield this.close();
978
+ } catch (err) {
979
+ this._logger.error("Unable to cleanly close providers. Resetting to the default configuration.");
980
+ } finally {
981
+ this._clientProviders.clear();
982
+ this._defaultProvider = defaultProvider;
983
+ }
984
+ });
985
+ }
935
986
  handleShutdownError(provider, err) {
936
987
  this._logger.error(`Error during shutdown of provider ${provider.metadata.name}: ${err}`);
937
988
  this._logger.error(err == null ? void 0 : err.stack);
938
989
  }
939
- setTransactionContextPropagator(transactionContextPropagator) {
940
- const baseMessage = "Invalid TransactionContextPropagator, will not be set: ";
941
- if (typeof (transactionContextPropagator == null ? void 0 : transactionContextPropagator.getTransactionContext) !== "function") {
942
- this._logger.error(`${baseMessage}: getTransactionContext is not a function.`);
943
- } else if (typeof (transactionContextPropagator == null ? void 0 : transactionContextPropagator.setTransactionContext) !== "function") {
944
- this._logger.error(`${baseMessage}: setTransactionContext is not a function.`);
945
- } else {
946
- this._transactionContextPropagator = transactionContextPropagator;
947
- }
948
- return this;
949
- }
950
- setTransactionContext(transactionContext, callback, ...args) {
951
- this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args);
952
- }
953
- getTransactionContext() {
954
- try {
955
- return this._transactionContextPropagator.getTransactionContext();
956
- } catch (err) {
957
- const error = err;
958
- this._logger.error(`Error getting transaction context: ${error == null ? void 0 : error.message}, returning empty context.`);
959
- this._logger.error(error == null ? void 0 : error.stack);
960
- return {};
961
- }
962
- }
963
990
  };
964
991
 
965
992
  // src/provider/no-op-provider.ts
@@ -1000,7 +1027,7 @@ var _globalThis = globalThis;
1000
1027
  var OpenFeatureAPI = class extends OpenFeatureCommonAPI {
1001
1028
  // eslint-disable-next-line @typescript-eslint/no-empty-function
1002
1029
  constructor() {
1003
- super();
1030
+ super("client");
1004
1031
  this._defaultProvider = NOOP_PROVIDER;
1005
1032
  }
1006
1033
  /**
@@ -1058,6 +1085,13 @@ var OpenFeatureAPI = class extends OpenFeatureCommonAPI {
1058
1085
  { name, version }
1059
1086
  );
1060
1087
  }
1088
+ /**
1089
+ * Clears all registered providers and resets the default provider.
1090
+ * @returns {Promise<void>}
1091
+ */
1092
+ clearProviders() {
1093
+ return super.clearProvidersAndSetDefault(NOOP_PROVIDER);
1094
+ }
1061
1095
  };
1062
1096
  var OpenFeature = OpenFeatureAPI.getInstance();
1063
1097
 
@@ -1083,7 +1117,7 @@ var OpenFeatureClient = class {
1083
1117
  const providerReady = !this._provider.status || this._provider.status === "READY" /* READY */;
1084
1118
  if (eventType === "PROVIDER_READY" /* Ready */ && providerReady) {
1085
1119
  try {
1086
- handler({ clientName: this.metadata.name });
1120
+ handler({ clientName: this.metadata.name, providerName: this._provider.metadata.name });
1087
1121
  } catch (err) {
1088
1122
  (_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
1089
1123
  }