@openfeature/react-sdk 0.1.1-experimental → 0.2.0-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 +11 -8
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +2 -2
- package/dist/types.d.ts +6 -13
- package/package.json +1 -1
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.
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.
|
|
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" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -42,7 +42,7 @@ The OpenFeature React SDK adds React-specific functionality to the [OpenFeature
|
|
|
42
42
|
|
|
43
43
|
In addition to the feature provided by the [web sdk](https://openfeature.dev/docs/reference/technologies/client/web), capabilities include:
|
|
44
44
|
|
|
45
|
-
- [Multiple Providers and
|
|
45
|
+
- [Multiple Providers and domains](#multiple-providers-and-domains)
|
|
46
46
|
- [Re-rendering with Context Changes](#re-rendering-with-context-changes)
|
|
47
47
|
- [Re-rendering with Flag Configuration Changes](#re-rendering-with-flag-configuration-changes)
|
|
48
48
|
- [Suspense Support](#suspense-support)
|
|
@@ -130,15 +130,16 @@ const {
|
|
|
130
130
|
} = useBooleanFlagDetails('new-message', false);
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
### Multiple Providers and
|
|
133
|
+
### Multiple Providers and Domains
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
|
|
136
|
+
Multiple providers can be used by passing a `domain` to the `OpenFeatureProvider`:
|
|
136
137
|
|
|
137
138
|
```tsx
|
|
138
|
-
// Flags within this
|
|
139
|
+
// Flags within this domain will use the a client/provider associated with `my-domain`,
|
|
139
140
|
function App() {
|
|
140
141
|
return (
|
|
141
|
-
<OpenFeatureProvider
|
|
142
|
+
<OpenFeatureProvider domain={'my-domain'}>
|
|
142
143
|
<Page></Page>
|
|
143
144
|
</OpenFeatureProvider>
|
|
144
145
|
);
|
|
@@ -148,9 +149,11 @@ function App() {
|
|
|
148
149
|
This is analogous to:
|
|
149
150
|
|
|
150
151
|
```ts
|
|
151
|
-
OpenFeature.getClient('
|
|
152
|
+
OpenFeature.getClient('my-domain');
|
|
152
153
|
```
|
|
153
154
|
|
|
155
|
+
For more information about `domains`, refer to the [web SDK](https://github.com/open-feature/js-sdk/blob/main/packages/client/README.md).
|
|
156
|
+
|
|
154
157
|
### Re-rendering with Context Changes
|
|
155
158
|
|
|
156
159
|
By default, if the OpenFeature [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) is modified, components will be re-rendered.
|
package/dist/cjs/index.js
CHANGED
|
@@ -52,9 +52,9 @@ var import_react = require("react");
|
|
|
52
52
|
var React = __toESM(require("react"));
|
|
53
53
|
var import_web_sdk = require("@openfeature/web-sdk");
|
|
54
54
|
var Context = React.createContext(void 0);
|
|
55
|
-
var OpenFeatureProvider = ({ client,
|
|
55
|
+
var OpenFeatureProvider = ({ client, domain, children }) => {
|
|
56
56
|
if (!client) {
|
|
57
|
-
client = import_web_sdk.OpenFeature.getClient(
|
|
57
|
+
client = import_web_sdk.OpenFeature.getClient(domain);
|
|
58
58
|
}
|
|
59
59
|
return /* @__PURE__ */ React.createElement(Context.Provider, { value: client }, children);
|
|
60
60
|
};
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -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 ClientOrClientName =\n | {\n /**\n * The name of the client.\n * @see OpenFeature.setProvider() and overloads.\n */\n clientName: string;\n /**\n * OpenFeature client to use.\n */\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n /**\n * The name of the client.\n * @see OpenFeature.setProvider() and overloads.\n */\n clientName?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrClientName;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, clientName, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(clientName);\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,kBAAuH;AACvH,mBAA8D;;;ACD9D,YAAuB;AACvB,qBAAoC;
|
|
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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",
|
|
6
6
|
"names": ["import_web_sdk"]
|
|
7
7
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -6,9 +6,9 @@ import { useEffect, useState } from "react";
|
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { OpenFeature } from "@openfeature/web-sdk";
|
|
8
8
|
var Context = React.createContext(void 0);
|
|
9
|
-
var OpenFeatureProvider = ({ client,
|
|
9
|
+
var OpenFeatureProvider = ({ client, domain, children }) => {
|
|
10
10
|
if (!client) {
|
|
11
|
-
client = OpenFeature.getClient(
|
|
11
|
+
client = OpenFeature.getClient(domain);
|
|
12
12
|
}
|
|
13
13
|
return /* @__PURE__ */ React.createElement(Context.Provider, { value: client }, children);
|
|
14
14
|
};
|
package/dist/esm/index.js.map
CHANGED
|
@@ -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 ClientOrClientName =\n | {\n /**\n * The name of the client.\n * @see OpenFeature.setProvider() and overloads.\n */\n clientName: string;\n /**\n * OpenFeature client to use.\n */\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client: Client;\n /**\n * The name of the client.\n * @see OpenFeature.setProvider() and overloads.\n */\n clientName?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrClientName;\n\nconst Context = React.createContext<Client | undefined>(undefined);\n\nexport const OpenFeatureProvider = ({ client, clientName, children }: ProviderProps) => {\n if (!client) {\n client = OpenFeature.getClient(clientName);\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;
|
|
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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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -103,31 +103,24 @@ declare function useObjectFlagValue<T extends JsonValue = JsonValue>(flagKey: st
|
|
|
103
103
|
*/
|
|
104
104
|
declare function useObjectFlagDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): EvaluationDetails<T>;
|
|
105
105
|
|
|
106
|
-
type
|
|
106
|
+
type ClientOrDomain = {
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
108
|
+
* An identifier which logically binds clients with providers
|
|
109
109
|
* @see OpenFeature.setProvider() and overloads.
|
|
110
110
|
*/
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* OpenFeature client to use.
|
|
114
|
-
*/
|
|
111
|
+
domain: string;
|
|
115
112
|
client?: never;
|
|
116
113
|
} | {
|
|
117
114
|
/**
|
|
118
115
|
* OpenFeature client to use.
|
|
119
116
|
*/
|
|
120
117
|
client: Client;
|
|
121
|
-
|
|
122
|
-
* The name of the client.
|
|
123
|
-
* @see OpenFeature.setProvider() and overloads.
|
|
124
|
-
*/
|
|
125
|
-
clientName?: never;
|
|
118
|
+
domain?: never;
|
|
126
119
|
};
|
|
127
120
|
type ProviderProps = {
|
|
128
121
|
children?: React.ReactNode;
|
|
129
|
-
} &
|
|
130
|
-
declare const OpenFeatureProvider: ({ client,
|
|
122
|
+
} & ClientOrDomain;
|
|
123
|
+
declare const OpenFeatureProvider: ({ client, domain, children }: ProviderProps) => React.JSX.Element;
|
|
131
124
|
declare const useOpenFeatureClient: () => Client;
|
|
132
125
|
|
|
133
126
|
export { OpenFeatureProvider, useBooleanFlagDetails, useBooleanFlagValue, useNumberFlagDetails, useNumberFlagValue, useObjectFlagDetails, useObjectFlagValue, useOpenFeatureClient, useStringFlagDetails, useStringFlagValue };
|