@openfeature/react-sdk 0.3.4 → 0.4.1
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 +27 -13
- package/dist/cjs/index.js +48 -16
- package/dist/cjs/index.js.map +2 -2
- package/dist/esm/index.js +51 -16
- package/dist/esm/index.js.map +2 -2
- package/dist/types.d.ts +18 -3
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.8.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.4.1">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.1&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -61,7 +61,7 @@ In addition to the feature provided by the [web sdk](https://openfeature.dev/doc
|
|
|
61
61
|
|
|
62
62
|
### Requirements
|
|
63
63
|
|
|
64
|
-
-
|
|
64
|
+
- ES2015-compatible web browser (Chrome, Edge, Firefox, etc)
|
|
65
65
|
- React version 16.8+
|
|
66
66
|
|
|
67
67
|
### Install
|
|
@@ -199,10 +199,14 @@ You can disable this feature in the hook options (or in the [OpenFeatureProvider
|
|
|
199
199
|
|
|
200
200
|
```tsx
|
|
201
201
|
function Page() {
|
|
202
|
-
const showNewMessage =
|
|
202
|
+
const { value: showNewMessage } = useFlag('new-message', false, { updateOnContextChanged: false });
|
|
203
203
|
return (
|
|
204
|
-
<
|
|
205
|
-
|
|
204
|
+
<div className="App">
|
|
205
|
+
<header className="App-header">
|
|
206
|
+
{showNewMessage ? <p>Welcome to this OpenFeature-enabled React app!</p> : <p>Welcome to this React app.</p>}
|
|
207
|
+
</header>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
206
210
|
}
|
|
207
211
|
```
|
|
208
212
|
|
|
@@ -216,10 +220,14 @@ You can disable this feature in the hook options (or in the [OpenFeatureProvider
|
|
|
216
220
|
|
|
217
221
|
```tsx
|
|
218
222
|
function Page() {
|
|
219
|
-
const showNewMessage =
|
|
223
|
+
const { value: showNewMessage } = useFlag('new-message', false, { updateOnConfigurationChanged: false });
|
|
220
224
|
return (
|
|
221
|
-
<
|
|
222
|
-
|
|
225
|
+
<div className="App">
|
|
226
|
+
<header className="App-header">
|
|
227
|
+
{showNewMessage ? <p>Welcome to this OpenFeature-enabled React app!</p> : <p>Welcome to this React app.</p>}
|
|
228
|
+
</header>
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
223
231
|
}
|
|
224
232
|
```
|
|
225
233
|
|
|
@@ -227,9 +235,14 @@ Note that if your provider doesn't support updates, this configuration has no im
|
|
|
227
235
|
|
|
228
236
|
#### Suspense Support
|
|
229
237
|
|
|
238
|
+
> [!NOTE]
|
|
239
|
+
> React suspense is an experimental feature and subject to change in future versions.
|
|
240
|
+
|
|
241
|
+
|
|
230
242
|
Frequently, providers need to perform some initial startup tasks.
|
|
231
243
|
It may be desireable not to display components with feature flags until this is complete, or when the context changes.
|
|
232
244
|
Built-in [suspense](https://react.dev/reference/react/Suspense) support makes this easy.
|
|
245
|
+
Use `useSuspenseFlag` or pass `{ suspend: true }` in the hook options to leverage this functionality.
|
|
233
246
|
|
|
234
247
|
```tsx
|
|
235
248
|
function Content() {
|
|
@@ -242,8 +255,8 @@ function Content() {
|
|
|
242
255
|
}
|
|
243
256
|
|
|
244
257
|
function Message() {
|
|
245
|
-
// component to render after READY
|
|
246
|
-
const showNewMessage =
|
|
258
|
+
// component to render after READY, equivalent to useFlag('new-message', false, { suspend: true });
|
|
259
|
+
const { value: showNewMessage } = useSuspenseFlag('new-message', false);
|
|
247
260
|
|
|
248
261
|
return (
|
|
249
262
|
<>
|
|
@@ -271,8 +284,9 @@ This can be disabled in the hook options (or in the [OpenFeatureProvider](#openf
|
|
|
271
284
|
|
|
272
285
|
The OpenFeature React SDK features built-in [suspense support](#suspense-support).
|
|
273
286
|
This means that it will render your loading fallback automatically while the your provider starts up, and during context reconciliation for any of your components using feature flags!
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
If you use suspense and neglect to create a suspense boundary around any components using feature flags, you will see this error.
|
|
288
|
+
Add a suspense boundary to resolve this issue.
|
|
289
|
+
Alternatively, you can disable this suspense (the default) by removing `suspendWhileReconciling=true`, `suspendUntilReady=true` or `suspend=true` in the [evaluation hooks](#evaluation-hooks) or the [OpenFeatureProvider](#openfeatureprovider-context-provider) (which applies to all evaluation hooks in child components).
|
|
276
290
|
|
|
277
291
|
> I get odd rendering issues, or errors when components mount, if I use the suspense features.
|
|
278
292
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
9
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __objRest = (source, exclude) => {
|
|
26
|
+
var target = {};
|
|
27
|
+
for (var prop in source)
|
|
28
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
if (source != null && __getOwnPropSymbols)
|
|
31
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
32
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
33
|
+
target[prop] = source[prop];
|
|
34
|
+
}
|
|
35
|
+
return target;
|
|
36
|
+
};
|
|
8
37
|
var __export = (target, all) => {
|
|
9
38
|
for (var name in all)
|
|
10
39
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -42,6 +71,7 @@ __export(src_exports, {
|
|
|
42
71
|
useOpenFeatureClient: () => useOpenFeatureClient,
|
|
43
72
|
useStringFlagDetails: () => useStringFlagDetails,
|
|
44
73
|
useStringFlagValue: () => useStringFlagValue,
|
|
74
|
+
useSuspenseFlag: () => useSuspenseFlag,
|
|
45
75
|
useWhenProviderReady: () => useWhenProviderReady
|
|
46
76
|
});
|
|
47
77
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -54,21 +84,15 @@ var import_react4 = require("react");
|
|
|
54
84
|
var DEFAULT_OPTIONS = {
|
|
55
85
|
updateOnContextChanged: true,
|
|
56
86
|
updateOnConfigurationChanged: true,
|
|
57
|
-
suspendUntilReady:
|
|
58
|
-
suspendWhileReconciling:
|
|
87
|
+
suspendUntilReady: false,
|
|
88
|
+
suspendWhileReconciling: false
|
|
59
89
|
};
|
|
60
90
|
var normalizeOptions = (options = {}) => {
|
|
61
91
|
const updateOnContextChanged = options.updateOnContextChanged;
|
|
62
92
|
const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
|
|
63
93
|
const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
|
|
64
94
|
const suspendWhileReconciling = "suspendWhileReconciling" in options ? options.suspendWhileReconciling : options.suspend;
|
|
65
|
-
return {
|
|
66
|
-
// only return these if properly set (no undefined to allow overriding with spread)
|
|
67
|
-
...typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 },
|
|
68
|
-
...typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling },
|
|
69
|
-
...typeof updateOnContextChanged === "boolean" && { updateOnContextChanged },
|
|
70
|
-
...typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged }
|
|
71
|
-
};
|
|
95
|
+
return __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 }), typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling }), typeof updateOnContextChanged === "boolean" && { updateOnContextChanged }), typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged });
|
|
72
96
|
};
|
|
73
97
|
|
|
74
98
|
// src/common/suspense.ts
|
|
@@ -143,7 +167,8 @@ var HookFlagQuery = class {
|
|
|
143
167
|
return this._details;
|
|
144
168
|
}
|
|
145
169
|
get value() {
|
|
146
|
-
|
|
170
|
+
var _a;
|
|
171
|
+
return (_a = this._details) == null ? void 0 : _a.value;
|
|
147
172
|
}
|
|
148
173
|
get variant() {
|
|
149
174
|
return this._details.variant;
|
|
@@ -155,13 +180,16 @@ var HookFlagQuery = class {
|
|
|
155
180
|
return this._details.reason;
|
|
156
181
|
}
|
|
157
182
|
get isError() {
|
|
158
|
-
|
|
183
|
+
var _a;
|
|
184
|
+
return !!((_a = this._details) == null ? void 0 : _a.errorCode) || this._details.reason == import_web_sdk3.StandardResolutionReasons.ERROR;
|
|
159
185
|
}
|
|
160
186
|
get errorCode() {
|
|
161
|
-
|
|
187
|
+
var _a;
|
|
188
|
+
return (_a = this._details) == null ? void 0 : _a.errorCode;
|
|
162
189
|
}
|
|
163
190
|
get errorMessage() {
|
|
164
|
-
|
|
191
|
+
var _a;
|
|
192
|
+
return (_a = this._details) == null ? void 0 : _a.errorMessage;
|
|
165
193
|
}
|
|
166
194
|
get isAuthoritative() {
|
|
167
195
|
return !this.isError && this._details.reason != import_web_sdk3.StandardResolutionReasons.STALE && this._details.reason != import_web_sdk3.StandardResolutionReasons.DISABLED;
|
|
@@ -176,6 +204,9 @@ function useFlag(flagKey, defaultValue, options) {
|
|
|
176
204
|
const query = typeof defaultValue === "boolean" ? new HookFlagQuery(useBooleanFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "number" ? new HookFlagQuery(useNumberFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "string" ? new HookFlagQuery(useStringFlagDetails(flagKey, defaultValue, options)) : new HookFlagQuery(useObjectFlagDetails(flagKey, defaultValue, options));
|
|
177
205
|
return query;
|
|
178
206
|
}
|
|
207
|
+
function useSuspenseFlag(flagKey, defaultValue, options) {
|
|
208
|
+
return useFlag(flagKey, defaultValue, __spreadProps(__spreadValues({}, options), { suspendUntilReady: true, suspendWhileReconciling: true }));
|
|
209
|
+
}
|
|
179
210
|
function useBooleanFlagValue(flagKey, defaultValue, options) {
|
|
180
211
|
return useBooleanFlagDetails(flagKey, defaultValue, options).value;
|
|
181
212
|
}
|
|
@@ -229,7 +260,7 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
|
|
|
229
260
|
);
|
|
230
261
|
}
|
|
231
262
|
function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
232
|
-
const defaultedOptions = {
|
|
263
|
+
const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
|
|
233
264
|
const client = useOpenFeatureClient();
|
|
234
265
|
const status = useOpenFeatureClientStatus();
|
|
235
266
|
if (defaultedOptions.suspendUntilReady && status === import_web_sdk4.ProviderStatus.NOT_READY) {
|
|
@@ -270,7 +301,8 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
|
270
301
|
// src/provider/provider.tsx
|
|
271
302
|
var import_web_sdk5 = require("@openfeature/web-sdk");
|
|
272
303
|
var React3 = __toESM(require("react"));
|
|
273
|
-
function OpenFeatureProvider(
|
|
304
|
+
function OpenFeatureProvider(_a) {
|
|
305
|
+
var _b = _a, { client, domain, children } = _b, options = __objRest(_b, ["client", "domain", "children"]);
|
|
274
306
|
if (!client) {
|
|
275
307
|
client = import_web_sdk5.OpenFeature.getClient(domain);
|
|
276
308
|
}
|
|
@@ -282,7 +314,7 @@ var import_web_sdk6 = require("@openfeature/web-sdk");
|
|
|
282
314
|
function useWhenProviderReady(options) {
|
|
283
315
|
const client = useOpenFeatureClient();
|
|
284
316
|
const status = useOpenFeatureClientStatus();
|
|
285
|
-
const defaultedOptions = {
|
|
317
|
+
const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
|
|
286
318
|
if (defaultedOptions.suspendUntilReady && status === import_web_sdk6.ProviderStatus.NOT_READY) {
|
|
287
319
|
suspendUntilReady(client);
|
|
288
320
|
}
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts", "../../src/evaluation/use-feature-flag.ts", "../../src/common/options.ts", "../../src/common/suspense.ts", "../../src/provider/context.ts", "../../src/provider/use-open-feature-client.ts", "../../src/provider/use-open-feature-client-status.ts", "../../src/evaluation/hook-flag-query.ts", "../../src/provider/provider.tsx", "../../src/provider/use-when-provider-ready.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './evaluation';\nexport * from './query';\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 {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\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 * Cannot be used in conjunction with `suspend` option.\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 true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\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\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\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", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\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 ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["export * from './evaluation';\nexport * from './query';\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 {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n// suspense options removed for the useSuspenseFlag hooks\ntype NoSuspenseOptions = Omit<ReactFlagEvaluationOptions, 'suspend' | 'suspendUntilReady' | 'suspendWhileReconciling'>\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n// alias to the return value of useFlag, used to keep useSuspenseFlag consistent\ntype UseFlagReturn<T extends FlagValue> = ReturnType<typeof useFlag<T>>\n\n/**\n * Equivalent to {@link useFlag} with `options: { suspend: true }`\n * @experimental Suspense is an experimental feature subject to change in future versions.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {NoSuspenseOptions} options for this evaluation\n * @returns { UseFlagReturn<T> } a queryable object containing useful information about the flag.\n */\nexport function useSuspenseFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: NoSuspenseOptions,\n): UseFlagReturn<T> {\n return useFlag(flagKey, defaultValue, { ...options, suspendUntilReady: true, suspendWhileReconciling: true });\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n * @experimental Suspense is an experimental feature subject to change in future versions.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\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 false.\n * Cannot be used in conjunction with `suspend` option.\n * @experimental Suspense is an experimental feature subject to change in future versions.\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 * Cannot be used in conjunction with `suspend` option.\n * @experimental Suspense is an experimental feature subject to change in future versions.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\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\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: false,\n suspendWhileReconciling: false,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\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", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\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 ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_web_sdk", "import_react", "suspendUntilReady", "React", "import_react", "React", "import_react", "import_web_sdk", "import_web_sdk", "import_web_sdk", "React", "import_web_sdk"]
|
|
7
7
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
1
33
|
// src/evaluation/use-feature-flag.ts
|
|
2
34
|
import {
|
|
3
35
|
ProviderEvents as ProviderEvents3,
|
|
@@ -9,21 +41,15 @@ import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
|
9
41
|
var DEFAULT_OPTIONS = {
|
|
10
42
|
updateOnContextChanged: true,
|
|
11
43
|
updateOnConfigurationChanged: true,
|
|
12
|
-
suspendUntilReady:
|
|
13
|
-
suspendWhileReconciling:
|
|
44
|
+
suspendUntilReady: false,
|
|
45
|
+
suspendWhileReconciling: false
|
|
14
46
|
};
|
|
15
47
|
var normalizeOptions = (options = {}) => {
|
|
16
48
|
const updateOnContextChanged = options.updateOnContextChanged;
|
|
17
49
|
const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
|
|
18
50
|
const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
|
|
19
51
|
const suspendWhileReconciling = "suspendWhileReconciling" in options ? options.suspendWhileReconciling : options.suspend;
|
|
20
|
-
return {
|
|
21
|
-
// only return these if properly set (no undefined to allow overriding with spread)
|
|
22
|
-
...typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 },
|
|
23
|
-
...typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling },
|
|
24
|
-
...typeof updateOnContextChanged === "boolean" && { updateOnContextChanged },
|
|
25
|
-
...typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged }
|
|
26
|
-
};
|
|
52
|
+
return __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 }), typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling }), typeof updateOnContextChanged === "boolean" && { updateOnContextChanged }), typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged });
|
|
27
53
|
};
|
|
28
54
|
|
|
29
55
|
// src/common/suspense.ts
|
|
@@ -100,7 +126,8 @@ var HookFlagQuery = class {
|
|
|
100
126
|
return this._details;
|
|
101
127
|
}
|
|
102
128
|
get value() {
|
|
103
|
-
|
|
129
|
+
var _a;
|
|
130
|
+
return (_a = this._details) == null ? void 0 : _a.value;
|
|
104
131
|
}
|
|
105
132
|
get variant() {
|
|
106
133
|
return this._details.variant;
|
|
@@ -112,13 +139,16 @@ var HookFlagQuery = class {
|
|
|
112
139
|
return this._details.reason;
|
|
113
140
|
}
|
|
114
141
|
get isError() {
|
|
115
|
-
|
|
142
|
+
var _a;
|
|
143
|
+
return !!((_a = this._details) == null ? void 0 : _a.errorCode) || this._details.reason == StandardResolutionReasons.ERROR;
|
|
116
144
|
}
|
|
117
145
|
get errorCode() {
|
|
118
|
-
|
|
146
|
+
var _a;
|
|
147
|
+
return (_a = this._details) == null ? void 0 : _a.errorCode;
|
|
119
148
|
}
|
|
120
149
|
get errorMessage() {
|
|
121
|
-
|
|
150
|
+
var _a;
|
|
151
|
+
return (_a = this._details) == null ? void 0 : _a.errorMessage;
|
|
122
152
|
}
|
|
123
153
|
get isAuthoritative() {
|
|
124
154
|
return !this.isError && this._details.reason != StandardResolutionReasons.STALE && this._details.reason != StandardResolutionReasons.DISABLED;
|
|
@@ -133,6 +163,9 @@ function useFlag(flagKey, defaultValue, options) {
|
|
|
133
163
|
const query = typeof defaultValue === "boolean" ? new HookFlagQuery(useBooleanFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "number" ? new HookFlagQuery(useNumberFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "string" ? new HookFlagQuery(useStringFlagDetails(flagKey, defaultValue, options)) : new HookFlagQuery(useObjectFlagDetails(flagKey, defaultValue, options));
|
|
134
164
|
return query;
|
|
135
165
|
}
|
|
166
|
+
function useSuspenseFlag(flagKey, defaultValue, options) {
|
|
167
|
+
return useFlag(flagKey, defaultValue, __spreadProps(__spreadValues({}, options), { suspendUntilReady: true, suspendWhileReconciling: true }));
|
|
168
|
+
}
|
|
136
169
|
function useBooleanFlagValue(flagKey, defaultValue, options) {
|
|
137
170
|
return useBooleanFlagDetails(flagKey, defaultValue, options).value;
|
|
138
171
|
}
|
|
@@ -186,7 +219,7 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
|
|
|
186
219
|
);
|
|
187
220
|
}
|
|
188
221
|
function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
189
|
-
const defaultedOptions = {
|
|
222
|
+
const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
|
|
190
223
|
const client = useOpenFeatureClient();
|
|
191
224
|
const status = useOpenFeatureClientStatus();
|
|
192
225
|
if (defaultedOptions.suspendUntilReady && status === ProviderStatus2.NOT_READY) {
|
|
@@ -227,7 +260,8 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
|
227
260
|
// src/provider/provider.tsx
|
|
228
261
|
import { OpenFeature } from "@openfeature/web-sdk";
|
|
229
262
|
import * as React3 from "react";
|
|
230
|
-
function OpenFeatureProvider(
|
|
263
|
+
function OpenFeatureProvider(_a) {
|
|
264
|
+
var _b = _a, { client, domain, children } = _b, options = __objRest(_b, ["client", "domain", "children"]);
|
|
231
265
|
if (!client) {
|
|
232
266
|
client = OpenFeature.getClient(domain);
|
|
233
267
|
}
|
|
@@ -239,7 +273,7 @@ import { ProviderStatus as ProviderStatus3 } from "@openfeature/web-sdk";
|
|
|
239
273
|
function useWhenProviderReady(options) {
|
|
240
274
|
const client = useOpenFeatureClient();
|
|
241
275
|
const status = useOpenFeatureClientStatus();
|
|
242
|
-
const defaultedOptions = {
|
|
276
|
+
const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
|
|
243
277
|
if (defaultedOptions.suspendUntilReady && status === ProviderStatus3.NOT_READY) {
|
|
244
278
|
suspendUntilReady(client);
|
|
245
279
|
}
|
|
@@ -260,6 +294,7 @@ export {
|
|
|
260
294
|
useOpenFeatureClient,
|
|
261
295
|
useStringFlagDetails,
|
|
262
296
|
useStringFlagValue,
|
|
297
|
+
useSuspenseFlag,
|
|
263
298
|
useWhenProviderReady
|
|
264
299
|
};
|
|
265
300
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/evaluation/use-feature-flag.ts", "../../src/common/options.ts", "../../src/common/suspense.ts", "../../src/provider/context.ts", "../../src/provider/use-open-feature-client.ts", "../../src/provider/use-open-feature-client-status.ts", "../../src/evaluation/hook-flag-query.ts", "../../src/provider/provider.tsx", "../../src/provider/use-when-provider-ready.ts", "../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\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 * Cannot be used in conjunction with `suspend` option.\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 true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\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\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\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", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\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 ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n", "export * from './evaluation';\nexport * from './query';\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": "
|
|
4
|
+
"sourcesContent": ["import {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n// suspense options removed for the useSuspenseFlag hooks\ntype NoSuspenseOptions = Omit<ReactFlagEvaluationOptions, 'suspend' | 'suspendUntilReady' | 'suspendWhileReconciling'>\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n// alias to the return value of useFlag, used to keep useSuspenseFlag consistent\ntype UseFlagReturn<T extends FlagValue> = ReturnType<typeof useFlag<T>>\n\n/**\n * Equivalent to {@link useFlag} with `options: { suspend: true }`\n * @experimental Suspense is an experimental feature subject to change in future versions.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {NoSuspenseOptions} options for this evaluation\n * @returns { UseFlagReturn<T> } a queryable object containing useful information about the flag.\n */\nexport function useSuspenseFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: NoSuspenseOptions,\n): UseFlagReturn<T> {\n return useFlag(flagKey, defaultValue, { ...options, suspendUntilReady: true, suspendWhileReconciling: true });\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): 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 * For a generic hook returning a queryable interface, see {@link useFlag}.\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>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n * @experimental Suspense is an experimental feature subject to change in future versions.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\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 false.\n * Cannot be used in conjunction with `suspend` option.\n * @experimental Suspense is an experimental feature subject to change in future versions.\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 * Cannot be used in conjunction with `suspend` option.\n * @experimental Suspense is an experimental feature subject to change in future versions.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\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\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: false,\n suspendWhileReconciling: false,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\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", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\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 ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n", "export * from './evaluation';\nexport * from './query';\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;AAAA,EAME,kBAAAA;AAAA,EACA,kBAAAC;AAAA,OACK;AACP,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;;;AC4C7B,IAAM,kBAA8C;AAAA,EACzD,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B;AASO,IAAM,mBAAgF,CAAC,UAAsC,CAAC,MAAM;AACzI,QAAM,yBAAyB,QAAQ;AACvC,QAAM,+BAA+B,QAAQ;AAG7C,QAAMC,qBAAoB,uBAAuB,UAAU,QAAQ,oBAAoB,QAAQ;AAC/F,QAAM,0BAA0B,6BAA6B,UAAU,QAAQ,0BAA0B,QAAQ;AAEjH,SAAO,gEAED,OAAOA,uBAAsB,aAAa,EAAC,mBAAAA,mBAAiB,IAC5D,OAAO,4BAA4B,aAAa,EAAC,wBAAuB,IACxE,OAAO,2BAA2B,aAAa,EAAC,uBAAsB,IACtE,OAAO,iCAAiC,aAAa,EAAC,6BAA4B;AAE1F;;;AClFA,SAAiB,sBAAsB;AAOhC,SAAS,kBAAkB,QAA+B;AAC/D,MAAI;AACJ,MAAI;AACJ,QAAM,IAAI,QAAQ,CAAC,UAAU,YAAY;AACvC,cAAU;AACV,aAAS;AACT,WAAO,WAAW,eAAe,OAAO,OAAO;AAC/C,WAAO,WAAW,eAAe,OAAO,MAAM;AAAA,EAChD,CAAC,EAAE,QAAQ,MAAM;AACf,WAAO,cAAc,eAAe,OAAO,OAAO;AAClD,WAAO,cAAc,eAAe,OAAO,MAAM;AAAA,EACnD,CAAC;AACH;;;AClBA,OAAO,WAAW;AAQX,IAAM,UAAU,MAAM,cAAmF,MAAS;AAQlH,SAAS,qBAAwC;AACtD,QAAM,EAAE,QAAQ,IAAI,MAAM,WAAW,OAAO,KAAK,CAAC;AAClD,SAAO,iBAAiB,OAAO;AACjC;;;ACpBA,OAAOC,YAAW;AASX,SAAS,uBAA+B;AAC7C,QAAM,EAAE,OAAO,IAAIC,OAAM,WAAW,OAAO,KAAK,CAAC;AAEjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACnBA,SAAS,WAAW,gBAAgB;AAEpC,SAAS,kBAAAC,uBAAsC;AAMxC,SAAS,6BAA6C;AAC3D,QAAM,SAAS,qBAAqB;AACpC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,OAAO,cAAc;AAE1D,YAAU,MAAM;AACd,UAAM,eAAe,MAAM,UAAU,OAAO,cAAc;AAC1D,WAAO,WAAWA,gBAAe,sBAAsB,YAAY;AACnE,WAAO,WAAWA,gBAAe,gBAAgB,YAAY;AAC7D,WAAO,WAAWA,gBAAe,OAAO,YAAY;AACpD,WAAO,WAAWA,gBAAe,OAAO,YAAY;AACpD,WAAO,WAAWA,gBAAe,OAAO,YAAY;AACpD,WAAO,WAAWA,gBAAe,aAAa,YAAY;AAC1D,WAAO,MAAM;AACX,aAAO,cAAcA,gBAAe,sBAAsB,YAAY;AACtE,aAAO,cAAcA,gBAAe,gBAAgB,YAAY;AAChE,aAAO,cAAcA,gBAAe,OAAO,YAAY;AACvD,aAAO,cAAcA,gBAAe,OAAO,YAAY;AACvD,aAAO,cAAcA,gBAAe,OAAO,YAAY;AACvD,aAAO,cAAcA,gBAAe,aAAa,YAAY;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AACT;;;AC/BA;AAAA,EAGE;AAAA,OACK;AAKA,IAAM,gBAAN,MAA0E;AAAA,EAC/E,YAAoB,UAAgC;AAAhC;AAAA,EAAiC;AAAA,EAErD,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,QAAQ;AAhBd;AAiBI,YAAO,UAAK,aAAL,mBAAe;AAAA,EACxB;AAAA,EAEA,IAAI,UAAU;AACZ,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA,IAAI,eAAe;AACjB,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA,IAAI,SAAS;AACX,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA,IAAI,UAAU;AAhChB;AAiCI,WAAO,CAAC,GAAC,UAAK,aAAL,mBAAe,cAAa,KAAK,SAAS,UAAU,0BAA0B;AAAA,EACzF;AAAA,EAEA,IAAI,YAAY;AApClB;AAqCI,YAAO,UAAK,aAAL,mBAAe;AAAA,EACxB;AAAA,EAEA,IAAI,eAAe;AAxCrB;AAyCI,YAAO,UAAK,aAAL,mBAAe;AAAA,EACxB;AAAA,EAEA,IAAI,kBAAkB;AACpB,WACE,CAAC,KAAK,WACN,KAAK,SAAS,UAAU,0BAA0B,SAClD,KAAK,SAAS,UAAU,0BAA0B;AAAA,EAEtD;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,OAAO,KAAK,SAAS;AAAA,EAC9B;AACF;;;ANRO,SAAS,QACd,SACA,cACA,SAWA;AAEA,QAAM,QACJ,OAAO,iBAAiB,YACpB,IAAI,cAAuB,sBAAsB,SAAS,cAAc,OAAO,CAAC,IAChF,OAAO,iBAAiB,WACtB,IAAI,cAAsB,qBAAqB,SAAS,cAAc,OAAO,CAAC,IAC9E,OAAO,iBAAiB,WACtB,IAAI,cAAsB,qBAAqB,SAAS,cAAc,OAAO,CAAC,IAC9E,IAAI,cAAyB,qBAAqB,SAAS,cAAc,OAAO,CAAC;AAE3F,SAAO;AACT;AAcO,SAAS,gBACd,SACA,cACA,SACkB;AAClB,SAAO,QAAQ,SAAS,cAAc,iCAAK,UAAL,EAAc,mBAAmB,MAAM,yBAAyB,KAAK,EAAC;AAC9G;AAWO,SAAS,oBACd,SACA,cACA,SACS;AACT,SAAO,sBAAsB,SAAS,cAAc,OAAO,EAAE;AAC/D;AAWO,SAAS,sBACd,SACA,cACA,SAC4B;AAC5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,WAAW;AACV,aAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAYO,SAAS,mBACd,SACA,cACA,SACQ;AACR,SAAO,qBAAqB,SAAS,cAAc,OAAO,EAAE;AAC9D;AAYO,SAAS,qBACd,SACA,cACA,SAC2B;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,WAAW;AACV,aAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAYO,SAAS,mBACd,SACA,cACA,SACQ;AACR,SAAO,qBAAqB,SAAS,cAAc,OAAO,EAAE;AAC9D;AAYO,SAAS,qBACd,SACA,cACA,SAC2B;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,WAAW;AACV,aAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAYO,SAAS,mBACd,SACA,cACA,SACG;AACH,SAAO,qBAAwB,SAAS,cAAc,OAAO,EAAE;AACjE;AAYO,SAAS,qBACd,SACA,cACA,SACsB;AACtB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,WAAW;AACV,aAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,yBACP,SACA,cACA,UACA,SACsB;AAEtB,QAAM,mBAAmB,iDAAK,kBAAoB,mBAAmB,IAAM,iBAAiB,OAAO;AACnG,QAAM,SAAS,qBAAqB;AACpC,QAAM,SAAS,2BAA2B;AAG1C,MAAI,iBAAiB,qBAAqB,WAAWC,gBAAe,WAAW;AAC7E,sBAAkB,MAAM;AAAA,EAC1B;AAEA,MAAI,iBAAiB,2BAA2B,WAAWA,gBAAe,aAAa;AACrF,sBAAkB,MAAM;AAAA,EAC1B;AAEA,QAAM,CAAC,oBAAoB,oBAAoB,IAAIC;AAAA,IACjD,SAAS,MAAM,EAAE,KAAK,QAAQ,SAAS,cAAc,OAAO;AAAA,EAC9D;AAEA,QAAM,6BAA6B,MAAM;AACvC,yBAAqB,SAAS,MAAM,EAAE,KAAK,QAAQ,SAAS,cAAc,OAAO,CAAC;AAAA,EACpF;AAEA,EAAAC,WAAU,MAAM;AACd,QAAI,WAAWF,gBAAe,WAAW;AAEvC,aAAO,WAAWG,gBAAe,OAAO,0BAA0B;AAAA,IACpE;AAEA,QAAI,iBAAiB,wBAAwB;AAE3C,aAAO,WAAWA,gBAAe,gBAAgB,0BAA0B;AAAA,IAC7E;AACA,WAAO,MAAM;AAEX,aAAO,cAAcA,gBAAe,OAAO,0BAA0B;AACrE,aAAO,cAAcA,gBAAe,gBAAgB,0BAA0B;AAAA,IAChF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,EAAAD,WAAU,MAAM;AACd,QAAI,iBAAiB,8BAA8B;AAEjD,aAAO,WAAWC,gBAAe,sBAAsB,0BAA0B;AAAA,IACnF;AACA,WAAO,MAAM;AAEX,aAAO,cAAcA,gBAAe,sBAAsB,0BAA0B;AAAA,IACtF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;AOlUA,SAAiB,mBAAmB;AACpC,YAAYC,YAAW;AA+BhB,SAAS,oBAAoB,IAAyD;AAAzD,eAAE,UAAQ,QAAQ,SAhCtD,IAgCoC,IAA+B,oBAA/B,IAA+B,CAA7B,UAAQ,UAAQ;AACpD,MAAI,CAAC,QAAQ;AACX,aAAS,YAAY,UAAU,MAAM;AAAA,EACvC;AAEA,SAAO,qCAAC,QAAQ,UAAR,EAAiB,OAAO,EAAE,QAAQ,QAAQ,KAAI,QAAS;AACjE;;;ACtCA,SAAS,kBAAAC,uBAAsB;AAgBxB,SAAS,qBAAqB,SAA4B;AAC/D,QAAM,SAAS,qBAAqB;AACpC,QAAM,SAAS,2BAA2B;AAE1C,QAAM,mBAAmB,iDAAK,kBAAoB,mBAAmB,IAAM,iBAAiB,OAAO;AAGnG,MAAI,iBAAiB,qBAAqB,WAAWC,gBAAe,WAAW;AAC7E,sBAAkB,MAAM;AAAA,EAC1B;AAEA,SAAO,WAAWA,gBAAe;AACnC;;;ACxBA,cAAc;",
|
|
6
6
|
"names": ["ProviderEvents", "ProviderStatus", "useEffect", "useState", "suspendUntilReady", "React", "React", "ProviderEvents", "ProviderStatus", "useState", "useEffect", "ProviderEvents", "React", "ProviderStatus", "ProviderStatus"]
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type ReactFlagEvaluationOptions = ({
|
|
|
7
7
|
/**
|
|
8
8
|
* Enable or disable all suspense functionality.
|
|
9
9
|
* Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.
|
|
10
|
+
* @experimental Suspense is an experimental feature subject to change in future versions.
|
|
10
11
|
*/
|
|
11
12
|
suspend?: boolean;
|
|
12
13
|
suspendUntilReady?: never;
|
|
@@ -15,15 +16,17 @@ type ReactFlagEvaluationOptions = ({
|
|
|
15
16
|
/**
|
|
16
17
|
* Suspend flag evaluations while the provider is not ready.
|
|
17
18
|
* Set to false if you don't want to show suspense fallbacks until the provider is initialized.
|
|
18
|
-
* Defaults to
|
|
19
|
+
* Defaults to false.
|
|
19
20
|
* Cannot be used in conjunction with `suspend` option.
|
|
21
|
+
* @experimental Suspense is an experimental feature subject to change in future versions.
|
|
20
22
|
*/
|
|
21
23
|
suspendUntilReady?: boolean;
|
|
22
24
|
/**
|
|
23
25
|
* Suspend flag evaluations while the provider's context is being reconciled.
|
|
24
26
|
* Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.
|
|
25
|
-
* Defaults to
|
|
27
|
+
* Defaults to false.
|
|
26
28
|
* Cannot be used in conjunction with `suspend` option.
|
|
29
|
+
* @experimental Suspense is an experimental feature subject to change in future versions.
|
|
27
30
|
*/
|
|
28
31
|
suspendWhileReconciling?: boolean;
|
|
29
32
|
suspend?: never;
|
|
@@ -92,6 +95,7 @@ interface FlagQuery<T extends FlagValue = FlagValue> {
|
|
|
92
95
|
readonly type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
|
|
93
96
|
}
|
|
94
97
|
|
|
98
|
+
type NoSuspenseOptions = Omit<ReactFlagEvaluationOptions, 'suspend' | 'suspendUntilReady' | 'suspendWhileReconciling'>;
|
|
95
99
|
/**
|
|
96
100
|
* Evaluates a feature flag generically, returning an react-flavored queryable object.
|
|
97
101
|
* The resolver method to use is based on the type of the defaultValue.
|
|
@@ -104,6 +108,17 @@ interface FlagQuery<T extends FlagValue = FlagValue> {
|
|
|
104
108
|
* @returns { FlagQuery } a queryable object containing useful information about the flag.
|
|
105
109
|
*/
|
|
106
110
|
declare function useFlag<T extends FlagValue$1 = FlagValue$1>(flagKey: string, defaultValue: T, options?: ReactFlagEvaluationOptions): FlagQuery<T extends boolean ? boolean : T extends number ? number : T extends string ? string : T extends JsonValue ? T : JsonValue>;
|
|
111
|
+
type UseFlagReturn<T extends FlagValue$1> = ReturnType<typeof useFlag<T>>;
|
|
112
|
+
/**
|
|
113
|
+
* Equivalent to {@link useFlag} with `options: { suspend: true }`
|
|
114
|
+
* @experimental Suspense is an experimental feature subject to change in future versions.
|
|
115
|
+
* @param {string} flagKey the flag identifier
|
|
116
|
+
* @template {FlagValue} T A optional generic argument constraining the default.
|
|
117
|
+
* @param {T} defaultValue the default value; used to determine what resolved type should be used.
|
|
118
|
+
* @param {NoSuspenseOptions} options for this evaluation
|
|
119
|
+
* @returns { UseFlagReturn<T> } a queryable object containing useful information about the flag.
|
|
120
|
+
*/
|
|
121
|
+
declare function useSuspenseFlag<T extends FlagValue$1 = FlagValue$1>(flagKey: string, defaultValue: T, options?: NoSuspenseOptions): UseFlagReturn<T>;
|
|
107
122
|
/**
|
|
108
123
|
* Evaluates a feature flag, returning a boolean.
|
|
109
124
|
* By default, components will re-render when the flag value changes.
|
|
@@ -232,4 +247,4 @@ type Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;
|
|
|
232
247
|
*/
|
|
233
248
|
declare function useWhenProviderReady(options?: Options): boolean;
|
|
234
249
|
|
|
235
|
-
export { FlagQuery, OpenFeatureProvider, useBooleanFlagDetails, useBooleanFlagValue, useFlag, useNumberFlagDetails, useNumberFlagValue, useObjectFlagDetails, useObjectFlagValue, useOpenFeatureClient, useStringFlagDetails, useStringFlagValue, useWhenProviderReady };
|
|
250
|
+
export { FlagQuery, OpenFeatureProvider, useBooleanFlagDetails, useBooleanFlagValue, useFlag, useNumberFlagDetails, useNumberFlagValue, useObjectFlagDetails, useObjectFlagValue, useOpenFeatureClient, useStringFlagDetails, useStringFlagValue, useSuspenseFlag, useWhenProviderReady };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfeature/react-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "OpenFeature React SDK",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"files": [
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"test": "jest --verbose",
|
|
18
18
|
"lint": "eslint ./",
|
|
19
19
|
"clean": "shx rm -rf ./dist",
|
|
20
|
-
"build:react-esm": "esbuild src/index.ts --bundle --external:react --external:@openfeature/web-sdk --sourcemap --target=
|
|
21
|
-
"build:react-cjs": "esbuild src/index.ts --bundle --external:react --external:@openfeature/web-sdk --sourcemap --target=
|
|
20
|
+
"build:react-esm": "esbuild src/index.ts --bundle --external:react --external:@openfeature/web-sdk --sourcemap --target=es2015 --platform=browser --format=esm --outfile=./dist/esm/index.js --analyze",
|
|
21
|
+
"build:react-cjs": "esbuild src/index.ts --bundle --external:react --external:@openfeature/web-sdk --sourcemap --target=es2015 --platform=browser --format=cjs --outfile=./dist/cjs/index.js --analyze",
|
|
22
22
|
"build:rollup-types": "rollup -c ../../rollup.config.mjs",
|
|
23
23
|
"build": "npm run clean && npm run build:react-esm && npm run build:react-cjs && npm run build:rollup-types",
|
|
24
24
|
"postbuild": "shx cp ./../../package.esm.json ./dist/esm/package.json",
|
|
@@ -53,4 +53,4 @@
|
|
|
53
53
|
"@openfeature/core": "*",
|
|
54
54
|
"@openfeature/web-sdk": "*"
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
}
|