@openfeature/react-sdk 0.2.0-experimental → 0.2.1-experimental

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/react-sdk-v0.2.0-experimental">
20
- <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.2.0-experimental&color=blue&style=for-the-badge" />
19
+ <a href="https://github.com/open-feature/js-sdk/releases/tag/react-sdk-v0.2.1-experimental">
20
+ <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.2.1-experimental&color=blue&style=for-the-badge" />
21
21
  </a>
22
22
  <!-- x-release-please-end -->
23
23
  <br/>
package/dist/cjs/index.js CHANGED
@@ -72,7 +72,8 @@ var useOpenFeatureClient = () => {
72
72
  var DEFAULT_OPTIONS = {
73
73
  updateOnContextChanged: true,
74
74
  updateOnConfigurationChanged: true,
75
- suspend: true
75
+ suspendUntilReady: true,
76
+ suspendWhileReconciling: false
76
77
  };
77
78
  function useBooleanFlagValue(flagKey, defaultValue, options) {
78
79
  return useBooleanFlagDetails(flagKey, defaultValue, options).value;
@@ -109,45 +110,56 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
109
110
  function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
110
111
  const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };
111
112
  const [, updateState] = (0, import_react.useState)();
113
+ const client = useOpenFeatureClient();
112
114
  const forceUpdate = () => {
113
115
  updateState({});
114
116
  };
115
- const client = useOpenFeatureClient();
117
+ const suspendRef = () => {
118
+ suspend(client, updateState, import_web_sdk2.ProviderEvents.ContextChanged, import_web_sdk2.ProviderEvents.ConfigurationChanged, import_web_sdk2.ProviderEvents.Ready);
119
+ };
116
120
  (0, import_react.useEffect)(() => {
117
- if (client.providerStatus !== import_web_sdk2.ProviderStatus.READY) {
121
+ if (client.providerStatus === import_web_sdk2.ProviderStatus.NOT_READY) {
118
122
  client.addHandler(import_web_sdk2.ProviderEvents.Ready, forceUpdate);
119
- if (defaultedOptions.suspend) {
120
- suspend(client, updateState);
123
+ if (defaultedOptions.suspendUntilReady) {
124
+ suspend(client, updateState, import_web_sdk2.ProviderEvents.Ready);
121
125
  }
122
126
  }
123
127
  if (defaultedOptions.updateOnContextChanged) {
124
128
  client.addHandler(import_web_sdk2.ProviderEvents.ContextChanged, forceUpdate);
129
+ if (defaultedOptions.suspendWhileReconciling) {
130
+ client.addHandler(import_web_sdk2.ProviderEvents.Reconciling, suspendRef);
131
+ }
125
132
  }
133
+ return () => {
134
+ client.removeHandler(import_web_sdk2.ProviderEvents.Ready, forceUpdate);
135
+ client.removeHandler(import_web_sdk2.ProviderEvents.ContextChanged, forceUpdate);
136
+ client.removeHandler(import_web_sdk2.ProviderEvents.Reconciling, suspendRef);
137
+ };
138
+ }, []);
139
+ (0, import_react.useEffect)(() => {
126
140
  if (defaultedOptions.updateOnConfigurationChanged) {
127
141
  client.addHandler(import_web_sdk2.ProviderEvents.ConfigurationChanged, forceUpdate);
128
142
  }
129
143
  return () => {
130
- client.removeHandler(import_web_sdk2.ProviderEvents.Ready, forceUpdate);
131
- client.removeHandler(import_web_sdk2.ProviderEvents.ContextChanged, forceUpdate);
132
144
  client.removeHandler(import_web_sdk2.ProviderEvents.ConfigurationChanged, forceUpdate);
133
145
  };
134
- }, [client]);
146
+ }, []);
135
147
  return resolver(client).call(client, flagKey, defaultValue);
136
148
  }
137
- function suspend(client, updateState) {
149
+ function suspend(client, updateState, ...resumeEvents) {
138
150
  let suspendResolver;
139
- let suspendRejecter;
140
151
  const suspendPromise = new Promise((resolve) => {
141
152
  suspendResolver = () => {
142
153
  resolve();
143
- client.removeHandler(import_web_sdk2.ProviderEvents.Ready, suspendResolver);
144
- };
145
- suspendRejecter = () => {
146
- resolve();
147
- client.removeHandler(import_web_sdk2.ProviderEvents.Error, suspendRejecter);
154
+ resumeEvents.forEach((e) => {
155
+ client.removeHandler(e, suspendResolver);
156
+ });
157
+ client.removeHandler(import_web_sdk2.ProviderEvents.Error, suspendResolver);
148
158
  };
149
- client.addHandler(import_web_sdk2.ProviderEvents.Ready, suspendResolver);
150
- client.addHandler(import_web_sdk2.ProviderEvents.Error, suspendRejecter);
159
+ resumeEvents.forEach((e) => {
160
+ client.addHandler(e, suspendResolver);
161
+ });
162
+ client.addHandler(import_web_sdk2.ProviderEvents.Error, suspendResolver);
151
163
  });
152
164
  updateState(suspenseWrapper(suspendPromise));
153
165
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts", "../../src/use-feature-flag.ts", "../../src/provider.tsx"],
4
- "sourcesContent": ["export * from './use-feature-flag';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n", "import { Client, EvaluationDetails, FlagEvaluationOptions, FlagValue, JsonValue, ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction, useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './provider';\n\ntype ReactFlagEvaluationOptions = {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to use React Suspense API.\n * Defaults to true.\n */\n suspend?: boolean,\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean,\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which \n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean,\n} & FlagEvaluationOptions;\n\nconst DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspend: true,\n};\n\nenum SuspendState {\n Pending,\n Success,\n Error\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getBooleanDetails;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getStringDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getNumberDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getObjectDetails<T>;\n }, options);\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(flagKey: string, defaultValue: T, resolver: (client: Client) => (flagKey: string, defaultValue: T) => EvaluationDetails<T>, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };\n const [, updateState] = useState<object | undefined>();\n const forceUpdate = () => {\n updateState({});\n };\n const client = useOpenFeatureClient();\n\n useEffect(() => {\n\n if (client.providerStatus !== ProviderStatus.READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspend) {\n suspend(client, updateState);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n }\n\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers (we can do this unconditionally with no impact)\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, [client]);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n */\nfunction suspend(client: Client, updateState: Dispatch<SetStateAction<object | undefined>>) {\n let suspendResolver: () => void;\n let suspendRejecter: () => void;\n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n client.removeHandler(ProviderEvents.Ready, suspendResolver); // remove handler once it's run\n };\n suspendRejecter = () => {\n resolve(); // we still resolve here, since we don't want to throw errors\n client.removeHandler(ProviderEvents.Error, suspendRejecter); // remove handler once it's run\n };\n client.addHandler(ProviderEvents.Ready, suspendResolver);\n client.addHandler(ProviderEvents.Error, suspendRejecter);\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nfunction suspenseWrapper <T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise.then(\n (value) => {\n status = SuspendState.Success;\n result = value;\n },\n (error) => {\n status = SuspendState.Error;\n result = error;\n }\n );\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n};", "import * as React from 'react';\nimport { Client, OpenFeature } from '@openfeature/web-sdk';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, domain, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={client}>{children}</Context.Provider>;\n};\n\nexport const useOpenFeatureClient = () => {\n const client = React.useContext(Context);\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>'\n );\n }\n\n return client;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export * from './use-feature-flag';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n", "import { Client, EvaluationDetails, FlagEvaluationOptions, FlagValue, JsonValue, ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction, useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './provider';\n\ntype ReactFlagEvaluationOptions = {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n */\n suspendUntilReady?: boolean,\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to false.\n */\n suspendWhileReconciling?: boolean,\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean,\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which \n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean,\n} & FlagEvaluationOptions;\n\nconst DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: false,\n};\n\nenum SuspendState {\n Pending,\n Success,\n Error\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getBooleanDetails;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getStringDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getNumberDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getObjectDetails<T>;\n }, options);\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(flagKey: string, defaultValue: T, resolver: (client: Client) => (flagKey: string, defaultValue: T) => EvaluationDetails<T>, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };\n const [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n const forceUpdate = () => {\n updateState({});\n };\n const suspendRef = () => {\n suspend(client, updateState, ProviderEvents.ContextChanged, ProviderEvents.ConfigurationChanged, ProviderEvents.Ready);\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspendUntilReady) {\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n if (defaultedOptions.suspendWhileReconciling) {\n client.addHandler(ProviderEvents.Reconciling, suspendRef);\n }\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.Reconciling, suspendRef);\n };\n }, []);\n \n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, []);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n * @param {ProviderEvents[]} resumeEvents list of events which will resume the suspend\n */\nfunction suspend(client: Client, updateState: Dispatch<SetStateAction<object | undefined>>, ...resumeEvents: ProviderEvents[]) {\n\n let suspendResolver: () => void;\n \n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n resumeEvents.forEach((e) => {\n client.removeHandler(e, suspendResolver); // remove handlers once they've run\n });\n client.removeHandler(ProviderEvents.Error, suspendResolver);\n };\n resumeEvents.forEach((e) => {\n client.addHandler(e, suspendResolver);\n });\n client.addHandler(ProviderEvents.Error, suspendResolver); // we never want to throw, resolve with errors - we may make this configurable later\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nfunction suspenseWrapper <T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise.then(\n (value) => {\n status = SuspendState.Success;\n result = value;\n },\n (error) => {\n status = SuspendState.Error;\n result = error;\n }\n );\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n};", "import * as React from 'react';\nimport { Client, OpenFeature } from '@openfeature/web-sdk';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, domain, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={client}>{children}</Context.Provider>;\n};\n\nexport const useOpenFeatureClient = () => {\n const client = React.useContext(Context);\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>'\n );\n }\n\n return client;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_web_sdk"]
7
7
  }
package/dist/esm/index.js CHANGED
@@ -26,7 +26,8 @@ var useOpenFeatureClient = () => {
26
26
  var DEFAULT_OPTIONS = {
27
27
  updateOnContextChanged: true,
28
28
  updateOnConfigurationChanged: true,
29
- suspend: true
29
+ suspendUntilReady: true,
30
+ suspendWhileReconciling: false
30
31
  };
31
32
  function useBooleanFlagValue(flagKey, defaultValue, options) {
32
33
  return useBooleanFlagDetails(flagKey, defaultValue, options).value;
@@ -63,45 +64,56 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
63
64
  function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
64
65
  const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };
65
66
  const [, updateState] = useState();
67
+ const client = useOpenFeatureClient();
66
68
  const forceUpdate = () => {
67
69
  updateState({});
68
70
  };
69
- const client = useOpenFeatureClient();
71
+ const suspendRef = () => {
72
+ suspend(client, updateState, ProviderEvents.ContextChanged, ProviderEvents.ConfigurationChanged, ProviderEvents.Ready);
73
+ };
70
74
  useEffect(() => {
71
- if (client.providerStatus !== ProviderStatus.READY) {
75
+ if (client.providerStatus === ProviderStatus.NOT_READY) {
72
76
  client.addHandler(ProviderEvents.Ready, forceUpdate);
73
- if (defaultedOptions.suspend) {
74
- suspend(client, updateState);
77
+ if (defaultedOptions.suspendUntilReady) {
78
+ suspend(client, updateState, ProviderEvents.Ready);
75
79
  }
76
80
  }
77
81
  if (defaultedOptions.updateOnContextChanged) {
78
82
  client.addHandler(ProviderEvents.ContextChanged, forceUpdate);
83
+ if (defaultedOptions.suspendWhileReconciling) {
84
+ client.addHandler(ProviderEvents.Reconciling, suspendRef);
85
+ }
79
86
  }
87
+ return () => {
88
+ client.removeHandler(ProviderEvents.Ready, forceUpdate);
89
+ client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);
90
+ client.removeHandler(ProviderEvents.Reconciling, suspendRef);
91
+ };
92
+ }, []);
93
+ useEffect(() => {
80
94
  if (defaultedOptions.updateOnConfigurationChanged) {
81
95
  client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);
82
96
  }
83
97
  return () => {
84
- client.removeHandler(ProviderEvents.Ready, forceUpdate);
85
- client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);
86
98
  client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);
87
99
  };
88
- }, [client]);
100
+ }, []);
89
101
  return resolver(client).call(client, flagKey, defaultValue);
90
102
  }
91
- function suspend(client, updateState) {
103
+ function suspend(client, updateState, ...resumeEvents) {
92
104
  let suspendResolver;
93
- let suspendRejecter;
94
105
  const suspendPromise = new Promise((resolve) => {
95
106
  suspendResolver = () => {
96
107
  resolve();
97
- client.removeHandler(ProviderEvents.Ready, suspendResolver);
98
- };
99
- suspendRejecter = () => {
100
- resolve();
101
- client.removeHandler(ProviderEvents.Error, suspendRejecter);
108
+ resumeEvents.forEach((e) => {
109
+ client.removeHandler(e, suspendResolver);
110
+ });
111
+ client.removeHandler(ProviderEvents.Error, suspendResolver);
102
112
  };
103
- client.addHandler(ProviderEvents.Ready, suspendResolver);
104
- client.addHandler(ProviderEvents.Error, suspendRejecter);
113
+ resumeEvents.forEach((e) => {
114
+ client.addHandler(e, suspendResolver);
115
+ });
116
+ client.addHandler(ProviderEvents.Error, suspendResolver);
105
117
  });
106
118
  updateState(suspenseWrapper(suspendPromise));
107
119
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/use-feature-flag.ts", "../../src/provider.tsx", "../../src/index.ts"],
4
- "sourcesContent": ["import { Client, EvaluationDetails, FlagEvaluationOptions, FlagValue, JsonValue, ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction, useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './provider';\n\ntype ReactFlagEvaluationOptions = {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to use React Suspense API.\n * Defaults to true.\n */\n suspend?: boolean,\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean,\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which \n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean,\n} & FlagEvaluationOptions;\n\nconst DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspend: true,\n};\n\nenum SuspendState {\n Pending,\n Success,\n Error\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getBooleanDetails;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getStringDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getNumberDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getObjectDetails<T>;\n }, options);\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(flagKey: string, defaultValue: T, resolver: (client: Client) => (flagKey: string, defaultValue: T) => EvaluationDetails<T>, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };\n const [, updateState] = useState<object | undefined>();\n const forceUpdate = () => {\n updateState({});\n };\n const client = useOpenFeatureClient();\n\n useEffect(() => {\n\n if (client.providerStatus !== ProviderStatus.READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspend) {\n suspend(client, updateState);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n }\n\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers (we can do this unconditionally with no impact)\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, [client]);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n */\nfunction suspend(client: Client, updateState: Dispatch<SetStateAction<object | undefined>>) {\n let suspendResolver: () => void;\n let suspendRejecter: () => void;\n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n client.removeHandler(ProviderEvents.Ready, suspendResolver); // remove handler once it's run\n };\n suspendRejecter = () => {\n resolve(); // we still resolve here, since we don't want to throw errors\n client.removeHandler(ProviderEvents.Error, suspendRejecter); // remove handler once it's run\n };\n client.addHandler(ProviderEvents.Ready, suspendResolver);\n client.addHandler(ProviderEvents.Error, suspendRejecter);\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nfunction suspenseWrapper <T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise.then(\n (value) => {\n status = SuspendState.Success;\n result = value;\n },\n (error) => {\n status = SuspendState.Error;\n result = error;\n }\n );\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n};", "import * as React from 'react';\nimport { Client, OpenFeature } from '@openfeature/web-sdk';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, domain, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={client}>{children}</Context.Provider>;\n};\n\nexport const useOpenFeatureClient = () => {\n const client = React.useContext(Context);\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>'\n );\n }\n\n return client;\n};\n", "export * from './use-feature-flag';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Client, EvaluationDetails, FlagEvaluationOptions, FlagValue, JsonValue, ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction, useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './provider';\n\ntype ReactFlagEvaluationOptions = {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n */\n suspendUntilReady?: boolean,\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to false.\n */\n suspendWhileReconciling?: boolean,\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean,\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which \n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean,\n} & FlagEvaluationOptions;\n\nconst DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: false,\n};\n\nenum SuspendState {\n Pending,\n Success,\n Error\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(flagKey: string, defaultValue: boolean, options?: ReactFlagEvaluationOptions): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getBooleanDetails;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getStringDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getNumberDetails<T>;\n }, options);\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n return attachHandlersAndResolve(flagKey, defaultValue, (client) => {\n return client.getObjectDetails<T>;\n }, options);\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(flagKey: string, defaultValue: T, resolver: (client: Client) => (flagKey: string, defaultValue: T) => EvaluationDetails<T>, options?: ReactFlagEvaluationOptions): EvaluationDetails<T> {\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...options };\n const [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n const forceUpdate = () => {\n updateState({});\n };\n const suspendRef = () => {\n suspend(client, updateState, ProviderEvents.ContextChanged, ProviderEvents.ConfigurationChanged, ProviderEvents.Ready);\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspendUntilReady) {\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n if (defaultedOptions.suspendWhileReconciling) {\n client.addHandler(ProviderEvents.Reconciling, suspendRef);\n }\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.Reconciling, suspendRef);\n };\n }, []);\n \n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, []);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n * @param {ProviderEvents[]} resumeEvents list of events which will resume the suspend\n */\nfunction suspend(client: Client, updateState: Dispatch<SetStateAction<object | undefined>>, ...resumeEvents: ProviderEvents[]) {\n\n let suspendResolver: () => void;\n \n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n resumeEvents.forEach((e) => {\n client.removeHandler(e, suspendResolver); // remove handlers once they've run\n });\n client.removeHandler(ProviderEvents.Error, suspendResolver);\n };\n resumeEvents.forEach((e) => {\n client.addHandler(e, suspendResolver);\n });\n client.addHandler(ProviderEvents.Error, suspendResolver); // we never want to throw, resolve with errors - we may make this configurable later\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nfunction suspenseWrapper <T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise.then(\n (value) => {\n status = SuspendState.Success;\n result = value;\n },\n (error) => {\n status = SuspendState.Error;\n result = error;\n }\n );\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n};", "import * as React from 'react';\nimport { Client, OpenFeature } from '@openfeature/web-sdk';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, domain, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={client}>{children}</Context.Provider>;\n};\n\nexport const useOpenFeatureClient = () => {\n const client = React.useContext(Context);\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>'\n );\n }\n\n return client;\n};\n", "export * from './use-feature-flag';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n"],
5
+ "mappings": ";AAAA,SAAiF,gBAAgB,sBAAsB;AACvH,SAAmC,WAAW,gBAAgB;;;ACD9D,YAAY,WAAW;AACvB,SAAiB,mBAAmB;AAuBpC,IAAM,UAAgB,oBAAkC,MAAS;AAE1D,IAAM,sBAAsB,CAAC,EAAE,QAAQ,QAAQ,SAAS,MAAqB;AAClF,MAAI,CAAC,QAAQ;AACX,aAAS,YAAY,UAAU,MAAM;AAAA,EACvC;AAEA,SAAO,oCAAC,QAAQ,UAAR,EAAiB,OAAO,UAAS,QAAS;AACpD;AAEO,IAAM,uBAAuB,MAAM;AACxC,QAAM,SAAe,iBAAW,OAAO;AAEvC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ADXA,IAAM,kBAA8C;AAAA,EAClD,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B;AAgBO,SAAS,oBAAoB,SAAiB,cAAuB,SAA+C;AACzH,SAAO,sBAAsB,SAAS,cAAc,OAAO,EAAE;AAC/D;AAUO,SAAS,sBAAsB,SAAiB,cAAuB,SAAkE;AAC9I,SAAO,yBAAyB,SAAS,cAAc,CAAC,WAAW;AACjE,WAAO,OAAO;AAAA,EAChB,GAAI,OAAO;AACb;AAWO,SAAS,mBAA8C,SAAiB,cAAiB,SAAyC;AACvI,SAAO,qBAAqB,SAAS,cAAc,OAAO,EAAE;AAC9D;AAWO,SAAS,qBAAgD,SAAiB,cAAiB,SAA4D;AAC5J,SAAO,yBAAyB,SAAS,cAAc,CAAC,WAAW;AACjE,WAAO,OAAO;AAAA,EAChB,GAAI,OAAO;AACb;AAWO,SAAS,mBAA8C,SAAiB,cAAiB,SAAyC;AACvI,SAAO,qBAAqB,SAAS,cAAc,OAAO,EAAE;AAC9D;AAWO,SAAS,qBAAgD,SAAiB,cAAiB,SAA4D;AAC5J,SAAO,yBAAyB,SAAS,cAAc,CAAC,WAAW;AACjE,WAAO,OAAO;AAAA,EAChB,GAAI,OAAO;AACb;AAWO,SAAS,mBAAoD,SAAiB,cAAiB,SAAyC;AAC7I,SAAO,qBAAwB,SAAS,cAAc,OAAO,EAAE;AACjE;AAWO,SAAS,qBAAsD,SAAiB,cAAiB,SAA4D;AAClK,SAAO,yBAAyB,SAAS,cAAc,CAAC,WAAW;AACjE,WAAO,OAAO;AAAA,EAChB,GAAI,OAAO;AACb;AAEA,SAAS,yBAA8C,SAAiB,cAAiB,UAA0F,SAA4D;AAC7O,QAAM,mBAAmB,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAC1D,QAAM,CAAC,EAAE,WAAW,IAAI,SAA6B;AACrD,QAAM,SAAS,qBAAqB;AACpC,QAAM,cAAc,MAAM;AACxB,gBAAY,CAAC,CAAC;AAAA,EAChB;AACA,QAAM,aAAa,MAAM;AACvB,YAAQ,QAAQ,aAAa,eAAe,gBAAgB,eAAe,sBAAsB,eAAe,KAAK;AAAA,EACvH;AAEA,YAAU,MAAM;AACd,QAAI,OAAO,mBAAmB,eAAe,WAAW;AAEtD,aAAO,WAAW,eAAe,OAAO,WAAW;AACnD,UAAI,iBAAiB,mBAAmB;AACtC,gBAAQ,QAAQ,aAAa,eAAe,KAAK;AAAA,MACnD;AAAA,IACF;AAEA,QAAI,iBAAiB,wBAAwB;AAE3C,aAAO,WAAW,eAAe,gBAAgB,WAAW;AAC5D,UAAI,iBAAiB,yBAAyB;AAC5C,eAAO,WAAW,eAAe,aAAa,UAAU;AAAA,MAC1D;AAAA,IACF;AACA,WAAO,MAAM;AAEX,aAAO,cAAc,eAAe,OAAO,WAAW;AACtD,aAAO,cAAc,eAAe,gBAAgB,WAAW;AAC/D,aAAO,cAAc,eAAe,aAAa,UAAU;AAAA,IAC7D;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,iBAAiB,8BAA8B;AAEjD,aAAO,WAAW,eAAe,sBAAsB,WAAW;AAAA,IACpE;AACA,WAAO,MAAM;AAEX,aAAO,cAAc,eAAe,sBAAsB,WAAW;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO,SAAS,MAAM,EAAE,KAAK,QAAQ,SAAS,YAAY;AAC5D;AAQA,SAAS,QAAQ,QAAgB,gBAA8D,cAAgC;AAE7H,MAAI;AAEJ,QAAM,iBAAiB,IAAI,QAAc,CAAC,YAAY;AACpD,sBAAkB,MAAM;AACtB,cAAQ;AACR,mBAAa,QAAQ,CAAC,MAAM;AAC1B,eAAO,cAAc,GAAG,eAAe;AAAA,MACzC,CAAC;AACD,aAAO,cAAc,eAAe,OAAO,eAAe;AAAA,IAC5D;AACA,iBAAa,QAAQ,CAAC,MAAM;AAC1B,aAAO,WAAW,GAAG,eAAe;AAAA,IACtC,CAAC;AACD,WAAO,WAAW,eAAe,OAAO,eAAe;AAAA,EACzD,CAAC;AACD,cAAY,gBAAgB,cAAc,CAAC;AAC7C;AAQA,SAAS,gBAAoB,SAAqB;AAChD,MAAI,SAAuB;AAC3B,MAAI;AAEJ,QAAM,YAAY,QAAQ;AAAA,IACxB,CAAC,UAAU;AACT,eAAS;AACT,eAAS;AAAA,IACX;AAAA,IACA,CAAC,UAAU;AACT,eAAS;AACT,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO,MAAM;AACX,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,cAAM;AAAA,MACR,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,cAAM;AAAA,MACR;AACE,cAAM,IAAI,MAAM,4CAA4C;AAAA,IAChE;AAAA,EACF;AACF;;;AErQA,cAAc;",
6
6
  "names": []
7
7
  }