@openfeature/react-sdk 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.4.0">
20
- <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.0&color=blue&style=for-the-badge" />
19
+ <a href="https://github.com/open-feature/js-sdk/releases/tag/react-sdk-v0.4.2">
20
+ <img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.4.2&color=blue&style=for-the-badge" />
21
21
  </a>
22
22
  <!-- x-release-please-end -->
23
23
  <br/>
@@ -54,6 +54,7 @@ In addition to the feature provided by the [web sdk](https://openfeature.dev/doc
54
54
  - [Re-rendering with Context Changes](#re-rendering-with-context-changes)
55
55
  - [Re-rendering with Flag Configuration Changes](#re-rendering-with-flag-configuration-changes)
56
56
  - [Suspense Support](#suspense-support)
57
+ - [Testing](#testing)
57
58
  - [FAQ and troubleshooting](#faq-and-troubleshooting)
58
59
  - [Resources](#resources)
59
60
 
@@ -61,7 +62,7 @@ In addition to the feature provided by the [web sdk](https://openfeature.dev/doc
61
62
 
62
63
  ### Requirements
63
64
 
64
- - ES2022-compatible web browser (Chrome, Edge, Firefox, etc)
65
+ - ES2015-compatible web browser (Chrome, Edge, Firefox, etc)
65
66
  - React version 16.8+
66
67
 
67
68
  ### Install
@@ -278,6 +279,67 @@ function Fallback() {
278
279
 
279
280
  This can be disabled in the hook options (or in the [OpenFeatureProvider](#openfeatureprovider-context-provider)).
280
281
 
282
+ ### Testing
283
+
284
+ The React SDK includes a built-in context provider for testing.
285
+ This allows you to easily test components that use evaluation hooks, such as `useFlag`.
286
+ If you try to test a component (in this case, `MyComponent`) which uses an evaluation hook, you might see an error message like:
287
+
288
+ ```
289
+ No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>.
290
+ ```
291
+
292
+ You can resolve this by simply wrapping your component under test in the OpenFeatureTestProvider:
293
+
294
+ ```tsx
295
+ // use default values for all evaluations
296
+ <OpenFeatureTestProvider>
297
+ <MyComponent />
298
+ </OpenFeatureTestProvider>
299
+ ```
300
+
301
+ The basic configuration above will simply use the default value provided in code.
302
+ If you'd like to control the values returned by the evaluation hooks, you can pass a map of flag keys and values:
303
+
304
+ ```tsx
305
+ // return `true` for all evaluations of `'my-boolean-flag'`
306
+ <OpenFeatureTestProvider flagValueMap={{ 'my-boolean-flag': true }}>
307
+ <MyComponent />
308
+ </OpenFeatureTestProvider>
309
+ ```
310
+
311
+ Additionally, you can pass an artificial delay for the provider startup to test your suspense boundaries or loaders/spinners impacted by feature flags:
312
+
313
+ ```tsx
314
+ // delay the provider start by 1000ms and then return `true` for all evaluations of `'my-boolean-flag'`
315
+ <OpenFeatureTestProvider delayMs={1000} flagValueMap={{ 'my-boolean-flag': true }}>
316
+ <MyComponent />
317
+ </OpenFeatureTestProvider>
318
+ ```
319
+
320
+ For maximum control, you can also pass your own mock provider implementation.
321
+ The type of this option is `Partial<Provider>`, so you can pass an incomplete implementation:
322
+
323
+ ```tsx
324
+ class MyTestProvider implements Partial<Provider> {
325
+ // implement the relevant resolver
326
+ resolveBooleanEvaluation(): ResolutionDetails<boolean> {
327
+ return {
328
+ value: true,
329
+ variant: 'my-variant',
330
+ reason: 'MY_REASON',
331
+ };
332
+ }
333
+ }
334
+ ```
335
+
336
+ ```tsx
337
+ // use your custom testing provider
338
+ <OpenFeatureTestProvider provider={new MyTestProvider()}>
339
+ <MyComponent />
340
+ </OpenFeatureTestProvider>,
341
+ ```
342
+
281
343
  ## FAQ and troubleshooting
282
344
 
283
345
  > I get an error that says something like: `A React component suspended while rendering, but no fallback UI was specified.`
package/dist/cjs/index.js CHANGED
@@ -1,10 +1,40 @@
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 __reflectGet = Reflect.get;
13
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
+ var __spreadValues = (a, b) => {
15
+ for (var prop in b || (b = {}))
16
+ if (__hasOwnProp.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ if (__getOwnPropSymbols)
19
+ for (var prop of __getOwnPropSymbols(b)) {
20
+ if (__propIsEnum.call(b, prop))
21
+ __defNormalProp(a, prop, b[prop]);
22
+ }
23
+ return a;
24
+ };
25
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
26
+ var __objRest = (source, exclude) => {
27
+ var target = {};
28
+ for (var prop in source)
29
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
30
+ target[prop] = source[prop];
31
+ if (source != null && __getOwnPropSymbols)
32
+ for (var prop of __getOwnPropSymbols(source)) {
33
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
34
+ target[prop] = source[prop];
35
+ }
36
+ return target;
37
+ };
8
38
  var __export = (target, all) => {
9
39
  for (var name in all)
10
40
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,11 +57,33 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
57
  mod
28
58
  ));
29
59
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
60
+ var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
61
+ var __async = (__this, __arguments, generator) => {
62
+ return new Promise((resolve, reject) => {
63
+ var fulfilled = (value) => {
64
+ try {
65
+ step(generator.next(value));
66
+ } catch (e) {
67
+ reject(e);
68
+ }
69
+ };
70
+ var rejected = (value) => {
71
+ try {
72
+ step(generator.throw(value));
73
+ } catch (e) {
74
+ reject(e);
75
+ }
76
+ };
77
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
78
+ step((generator = generator.apply(__this, __arguments)).next());
79
+ });
80
+ };
30
81
 
31
82
  // src/index.ts
32
83
  var src_exports = {};
33
84
  __export(src_exports, {
34
85
  OpenFeatureProvider: () => OpenFeatureProvider,
86
+ OpenFeatureTestProvider: () => OpenFeatureTestProvider,
35
87
  useBooleanFlagDetails: () => useBooleanFlagDetails,
36
88
  useBooleanFlagValue: () => useBooleanFlagValue,
37
89
  useFlag: () => useFlag,
@@ -63,13 +115,7 @@ var normalizeOptions = (options = {}) => {
63
115
  const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
64
116
  const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
65
117
  const suspendWhileReconciling = "suspendWhileReconciling" in options ? options.suspendWhileReconciling : options.suspend;
66
- return {
67
- // only return these if properly set (no undefined to allow overriding with spread)
68
- ...typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 },
69
- ...typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling },
70
- ...typeof updateOnContextChanged === "boolean" && { updateOnContextChanged },
71
- ...typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged }
72
- };
118
+ return __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 }), typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling }), typeof updateOnContextChanged === "boolean" && { updateOnContextChanged }), typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged });
73
119
  };
74
120
 
75
121
  // src/common/suspense.ts
@@ -102,7 +148,7 @@ function useOpenFeatureClient() {
102
148
  const { client } = import_react2.default.useContext(Context) || {};
103
149
  if (!client) {
104
150
  throw new Error(
105
- "No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>"
151
+ "No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>. If you are seeing this in a test, see: https://openfeature.dev/docs/reference/technologies/client/web/react#testing"
106
152
  );
107
153
  }
108
154
  return client;
@@ -144,7 +190,8 @@ var HookFlagQuery = class {
144
190
  return this._details;
145
191
  }
146
192
  get value() {
147
- return this._details?.value;
193
+ var _a;
194
+ return (_a = this._details) == null ? void 0 : _a.value;
148
195
  }
149
196
  get variant() {
150
197
  return this._details.variant;
@@ -156,13 +203,16 @@ var HookFlagQuery = class {
156
203
  return this._details.reason;
157
204
  }
158
205
  get isError() {
159
- return !!this._details?.errorCode || this._details.reason == import_web_sdk3.StandardResolutionReasons.ERROR;
206
+ var _a;
207
+ return !!((_a = this._details) == null ? void 0 : _a.errorCode) || this._details.reason == import_web_sdk3.StandardResolutionReasons.ERROR;
160
208
  }
161
209
  get errorCode() {
162
- return this._details?.errorCode;
210
+ var _a;
211
+ return (_a = this._details) == null ? void 0 : _a.errorCode;
163
212
  }
164
213
  get errorMessage() {
165
- return this._details?.errorMessage;
214
+ var _a;
215
+ return (_a = this._details) == null ? void 0 : _a.errorMessage;
166
216
  }
167
217
  get isAuthoritative() {
168
218
  return !this.isError && this._details.reason != import_web_sdk3.StandardResolutionReasons.STALE && this._details.reason != import_web_sdk3.StandardResolutionReasons.DISABLED;
@@ -178,7 +228,7 @@ function useFlag(flagKey, defaultValue, options) {
178
228
  return query;
179
229
  }
180
230
  function useSuspenseFlag(flagKey, defaultValue, options) {
181
- return useFlag(flagKey, defaultValue, { ...options, suspendUntilReady: true, suspendWhileReconciling: true });
231
+ return useFlag(flagKey, defaultValue, __spreadProps(__spreadValues({}, options), { suspendUntilReady: true, suspendWhileReconciling: true }));
182
232
  }
183
233
  function useBooleanFlagValue(flagKey, defaultValue, options) {
184
234
  return useBooleanFlagDetails(flagKey, defaultValue, options).value;
@@ -233,7 +283,7 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
233
283
  );
234
284
  }
235
285
  function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
236
- const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
286
+ const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
237
287
  const client = useOpenFeatureClient();
238
288
  const status = useOpenFeatureClientStatus();
239
289
  if (defaultedOptions.suspendUntilReady && status === import_web_sdk4.ProviderStatus.NOT_READY) {
@@ -274,7 +324,8 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
274
324
  // src/provider/provider.tsx
275
325
  var import_web_sdk5 = require("@openfeature/web-sdk");
276
326
  var React3 = __toESM(require("react"));
277
- function OpenFeatureProvider({ client, domain, children, ...options }) {
327
+ function OpenFeatureProvider(_a) {
328
+ var _b = _a, { client, domain, children } = _b, options = __objRest(_b, ["client", "domain", "children"]);
278
329
  if (!client) {
279
330
  client = import_web_sdk5.OpenFeature.getClient(domain);
280
331
  }
@@ -286,13 +337,64 @@ var import_web_sdk6 = require("@openfeature/web-sdk");
286
337
  function useWhenProviderReady(options) {
287
338
  const client = useOpenFeatureClient();
288
339
  const status = useOpenFeatureClientStatus();
289
- const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
340
+ const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
290
341
  if (defaultedOptions.suspendUntilReady && status === import_web_sdk6.ProviderStatus.NOT_READY) {
291
342
  suspendUntilReady(client);
292
343
  }
293
344
  return status === import_web_sdk6.ProviderStatus.READY;
294
345
  }
295
346
 
347
+ // src/provider/test-provider.tsx
348
+ var import_web_sdk7 = require("@openfeature/web-sdk");
349
+ var import_react5 = __toESM(require("react"));
350
+ var TEST_VARIANT = "test-variant";
351
+ var TEST_PROVIDER = "test-provider";
352
+ var TestProvider = class _TestProvider extends import_web_sdk7.InMemoryProvider {
353
+ constructor(flagValueMap, delay = 0) {
354
+ const flagConfig = Object.entries(flagValueMap).reduce((acc, flag) => {
355
+ return __spreadProps(__spreadValues({}, acc), {
356
+ [flag[0]]: {
357
+ variants: {
358
+ [TEST_VARIANT]: flag[1]
359
+ },
360
+ defaultVariant: TEST_VARIANT,
361
+ disabled: false
362
+ }
363
+ });
364
+ }, {});
365
+ super(flagConfig);
366
+ this.delay = delay;
367
+ }
368
+ initialize(context) {
369
+ return __async(this, null, function* () {
370
+ yield Promise.all([__superGet(_TestProvider.prototype, this, "initialize").call(this, context), new Promise((resolve) => setTimeout(resolve, this.delay))]);
371
+ });
372
+ }
373
+ onContextChange() {
374
+ return __async(this, null, function* () {
375
+ return new Promise((resolve) => setTimeout(resolve, this.delay));
376
+ });
377
+ }
378
+ };
379
+ function OpenFeatureTestProvider(testProviderOptions) {
380
+ const { flagValueMap, provider } = testProviderOptions;
381
+ const effectiveProvider = flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || import_web_sdk7.NOOP_PROVIDER;
382
+ testProviderOptions.domain ? import_web_sdk7.OpenFeature.setProvider(testProviderOptions.domain, effectiveProvider) : import_web_sdk7.OpenFeature.setProvider(effectiveProvider);
383
+ return /* @__PURE__ */ import_react5.default.createElement(OpenFeatureProvider, __spreadProps(__spreadValues({}, testProviderOptions), { domain: testProviderOptions.domain }), testProviderOptions.children);
384
+ }
385
+ function mixInNoop(provider = {}) {
386
+ for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(import_web_sdk7.NOOP_PROVIDER)).filter((prop2) => prop2 !== "constructor")) {
387
+ const patchedProvider = provider;
388
+ if (!Object.getPrototypeOf(patchedProvider)[prop] && !patchedProvider[prop]) {
389
+ patchedProvider[prop] = Object.getPrototypeOf(import_web_sdk7.NOOP_PROVIDER)[prop];
390
+ }
391
+ }
392
+ if (!provider.metadata || !provider.metadata.name) {
393
+ provider.metadata = { name: TEST_PROVIDER };
394
+ }
395
+ return provider;
396
+ }
397
+
296
398
  // src/index.ts
297
399
  __reExport(src_exports, require("@openfeature/web-sdk"), module.exports);
298
400
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 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// 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
- "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"]
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", "../../src/provider/test-provider.tsx"],
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>. If you are seeing this in a test, see: https://openfeature.dev/docs/reference/technologies/client/web/react#testing',\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", "import {\n EvaluationContext,\n InMemoryProvider,\n JsonValue,\n NOOP_PROVIDER,\n OpenFeature,\n Provider,\n} from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions } from '../common/options';\nimport { OpenFeatureProvider } from './provider';\n\ntype FlagValueMap = { [flagKey: string]: JsonValue };\ntype FlagConfig = ConstructorParameters<typeof InMemoryProvider>[0];\ntype TestProviderProps = Omit<React.ComponentProps<typeof OpenFeatureProvider>, 'client'> &\n (\n | {\n provider?: never;\n /**\n * Optional map of flagKeys to flagValues for this OpenFeatureTestProvider context.\n * If not supplied, all flag evaluations will default.\n */\n flagValueMap?: FlagValueMap;\n /**\n * Optional delay for the underlying test provider's readiness and reconciliation.\n * Defaults to 0.\n */\n delayMs?: number;\n }\n | {\n /**\n * An optional partial provider to pass for full control over the flag resolution for this OpenFeatureTestProvider context.\n * Any un-implemented methods or properties will no-op.\n */\n provider?: Partial<Provider>;\n flagValueMap?: never;\n delayMs?: never;\n }\n );\n\n const TEST_VARIANT = 'test-variant';\n const TEST_PROVIDER = 'test-provider';\n\n// internal provider which is basically the in-memory provider with a simpler config and some optional fake delays\nclass TestProvider extends InMemoryProvider {\n constructor(\n flagValueMap: FlagValueMap,\n private delay = 0,\n ) {\n // convert the simple flagValueMap into an in-memory config\n const flagConfig = Object.entries(flagValueMap).reduce((acc: FlagConfig, flag): FlagConfig => {\n return {\n ...acc,\n [flag[0]]: {\n variants: {\n [TEST_VARIANT]: flag[1],\n },\n defaultVariant: TEST_VARIANT,\n disabled: false,\n },\n };\n }, {});\n super(flagConfig);\n }\n\n async initialize(context?: EvaluationContext | undefined): Promise<void> {\n await Promise.all([super.initialize(context), new Promise<void>((resolve) => setTimeout(resolve, this.delay))]);\n }\n\n async onContextChange() {\n return new Promise<void>((resolve) => setTimeout(resolve, this.delay));\n }\n}\n\n/**\n * A React Context provider based on the {@link InMemoryProvider}, specifically built for testing.\n * Use this for testing components that use flag evaluation hooks.\n * @param {TestProviderProps} testProviderOptions options for the OpenFeatureTestProvider\n * @returns {OpenFeatureProvider} OpenFeatureTestProvider\n */\nexport function OpenFeatureTestProvider(testProviderOptions: TestProviderProps) {\n const { flagValueMap, provider } = testProviderOptions;\n const effectiveProvider = (\n flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || NOOP_PROVIDER\n ) as Provider;\n testProviderOptions.domain\n ? OpenFeature.setProvider(testProviderOptions.domain, effectiveProvider)\n : OpenFeature.setProvider(effectiveProvider);\n\n return (\n <OpenFeatureProvider {...(testProviderOptions as NormalizedOptions)} domain={testProviderOptions.domain}>\n {testProviderOptions.children}\n </OpenFeatureProvider>\n );\n}\n\n// mix in the no-op provider when the partial is passed\nfunction mixInNoop(provider: Partial<Provider> = {}) {\n // fill in any missing methods with no-ops\n for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(NOOP_PROVIDER)).filter(prop => prop !== 'constructor')) {\n const patchedProvider = provider as {[key: string]: keyof Provider};\n if (!Object.getPrototypeOf(patchedProvider)[prop] && !patchedProvider[prop]) {\n patchedProvider[prop] = Object.getPrototypeOf(NOOP_PROVIDER)[prop];\n }\n }\n // fill in the metadata if missing\n if (!provider.metadata || !provider.metadata.name) {\n (provider.metadata as unknown) = { name: TEST_PROVIDER };\n }\n return provider;\n}"],
5
+ "mappings": "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",
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", "import_web_sdk", "import_react", "React", "prop"]
7
7
  }
package/dist/esm/index.js CHANGED
@@ -1,3 +1,58 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __reflectGet = Reflect.get;
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __spreadValues = (a, b) => {
11
+ for (var prop in b || (b = {}))
12
+ if (__hasOwnProp.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ if (__getOwnPropSymbols)
15
+ for (var prop of __getOwnPropSymbols(b)) {
16
+ if (__propIsEnum.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ }
19
+ return a;
20
+ };
21
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
22
+ var __objRest = (source, exclude) => {
23
+ var target = {};
24
+ for (var prop in source)
25
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
26
+ target[prop] = source[prop];
27
+ if (source != null && __getOwnPropSymbols)
28
+ for (var prop of __getOwnPropSymbols(source)) {
29
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
30
+ target[prop] = source[prop];
31
+ }
32
+ return target;
33
+ };
34
+ var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
35
+ var __async = (__this, __arguments, generator) => {
36
+ return new Promise((resolve, reject) => {
37
+ var fulfilled = (value) => {
38
+ try {
39
+ step(generator.next(value));
40
+ } catch (e) {
41
+ reject(e);
42
+ }
43
+ };
44
+ var rejected = (value) => {
45
+ try {
46
+ step(generator.throw(value));
47
+ } catch (e) {
48
+ reject(e);
49
+ }
50
+ };
51
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
52
+ step((generator = generator.apply(__this, __arguments)).next());
53
+ });
54
+ };
55
+
1
56
  // src/evaluation/use-feature-flag.ts
2
57
  import {
3
58
  ProviderEvents as ProviderEvents3,
@@ -17,13 +72,7 @@ var normalizeOptions = (options = {}) => {
17
72
  const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
18
73
  const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
19
74
  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
- };
75
+ return __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 }), typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling }), typeof updateOnContextChanged === "boolean" && { updateOnContextChanged }), typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged });
27
76
  };
28
77
 
29
78
  // src/common/suspense.ts
@@ -56,7 +105,7 @@ function useOpenFeatureClient() {
56
105
  const { client } = React2.useContext(Context) || {};
57
106
  if (!client) {
58
107
  throw new Error(
59
- "No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>"
108
+ "No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>. If you are seeing this in a test, see: https://openfeature.dev/docs/reference/technologies/client/web/react#testing"
60
109
  );
61
110
  }
62
111
  return client;
@@ -100,7 +149,8 @@ var HookFlagQuery = class {
100
149
  return this._details;
101
150
  }
102
151
  get value() {
103
- return this._details?.value;
152
+ var _a;
153
+ return (_a = this._details) == null ? void 0 : _a.value;
104
154
  }
105
155
  get variant() {
106
156
  return this._details.variant;
@@ -112,13 +162,16 @@ var HookFlagQuery = class {
112
162
  return this._details.reason;
113
163
  }
114
164
  get isError() {
115
- return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;
165
+ var _a;
166
+ return !!((_a = this._details) == null ? void 0 : _a.errorCode) || this._details.reason == StandardResolutionReasons.ERROR;
116
167
  }
117
168
  get errorCode() {
118
- return this._details?.errorCode;
169
+ var _a;
170
+ return (_a = this._details) == null ? void 0 : _a.errorCode;
119
171
  }
120
172
  get errorMessage() {
121
- return this._details?.errorMessage;
173
+ var _a;
174
+ return (_a = this._details) == null ? void 0 : _a.errorMessage;
122
175
  }
123
176
  get isAuthoritative() {
124
177
  return !this.isError && this._details.reason != StandardResolutionReasons.STALE && this._details.reason != StandardResolutionReasons.DISABLED;
@@ -134,7 +187,7 @@ function useFlag(flagKey, defaultValue, options) {
134
187
  return query;
135
188
  }
136
189
  function useSuspenseFlag(flagKey, defaultValue, options) {
137
- return useFlag(flagKey, defaultValue, { ...options, suspendUntilReady: true, suspendWhileReconciling: true });
190
+ return useFlag(flagKey, defaultValue, __spreadProps(__spreadValues({}, options), { suspendUntilReady: true, suspendWhileReconciling: true }));
138
191
  }
139
192
  function useBooleanFlagValue(flagKey, defaultValue, options) {
140
193
  return useBooleanFlagDetails(flagKey, defaultValue, options).value;
@@ -189,7 +242,7 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
189
242
  );
190
243
  }
191
244
  function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
192
- const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
245
+ const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
193
246
  const client = useOpenFeatureClient();
194
247
  const status = useOpenFeatureClientStatus();
195
248
  if (defaultedOptions.suspendUntilReady && status === ProviderStatus2.NOT_READY) {
@@ -230,7 +283,8 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
230
283
  // src/provider/provider.tsx
231
284
  import { OpenFeature } from "@openfeature/web-sdk";
232
285
  import * as React3 from "react";
233
- function OpenFeatureProvider({ client, domain, children, ...options }) {
286
+ function OpenFeatureProvider(_a) {
287
+ var _b = _a, { client, domain, children } = _b, options = __objRest(_b, ["client", "domain", "children"]);
234
288
  if (!client) {
235
289
  client = OpenFeature.getClient(domain);
236
290
  }
@@ -242,17 +296,73 @@ import { ProviderStatus as ProviderStatus3 } from "@openfeature/web-sdk";
242
296
  function useWhenProviderReady(options) {
243
297
  const client = useOpenFeatureClient();
244
298
  const status = useOpenFeatureClientStatus();
245
- const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
299
+ const defaultedOptions = __spreadValues(__spreadValues(__spreadValues({}, DEFAULT_OPTIONS), useProviderOptions()), normalizeOptions(options));
246
300
  if (defaultedOptions.suspendUntilReady && status === ProviderStatus3.NOT_READY) {
247
301
  suspendUntilReady(client);
248
302
  }
249
303
  return status === ProviderStatus3.READY;
250
304
  }
251
305
 
306
+ // src/provider/test-provider.tsx
307
+ import {
308
+ InMemoryProvider,
309
+ NOOP_PROVIDER,
310
+ OpenFeature as OpenFeature2
311
+ } from "@openfeature/web-sdk";
312
+ import React4 from "react";
313
+ var TEST_VARIANT = "test-variant";
314
+ var TEST_PROVIDER = "test-provider";
315
+ var TestProvider = class _TestProvider extends InMemoryProvider {
316
+ constructor(flagValueMap, delay = 0) {
317
+ const flagConfig = Object.entries(flagValueMap).reduce((acc, flag) => {
318
+ return __spreadProps(__spreadValues({}, acc), {
319
+ [flag[0]]: {
320
+ variants: {
321
+ [TEST_VARIANT]: flag[1]
322
+ },
323
+ defaultVariant: TEST_VARIANT,
324
+ disabled: false
325
+ }
326
+ });
327
+ }, {});
328
+ super(flagConfig);
329
+ this.delay = delay;
330
+ }
331
+ initialize(context) {
332
+ return __async(this, null, function* () {
333
+ yield Promise.all([__superGet(_TestProvider.prototype, this, "initialize").call(this, context), new Promise((resolve) => setTimeout(resolve, this.delay))]);
334
+ });
335
+ }
336
+ onContextChange() {
337
+ return __async(this, null, function* () {
338
+ return new Promise((resolve) => setTimeout(resolve, this.delay));
339
+ });
340
+ }
341
+ };
342
+ function OpenFeatureTestProvider(testProviderOptions) {
343
+ const { flagValueMap, provider } = testProviderOptions;
344
+ const effectiveProvider = flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || NOOP_PROVIDER;
345
+ testProviderOptions.domain ? OpenFeature2.setProvider(testProviderOptions.domain, effectiveProvider) : OpenFeature2.setProvider(effectiveProvider);
346
+ return /* @__PURE__ */ React4.createElement(OpenFeatureProvider, __spreadProps(__spreadValues({}, testProviderOptions), { domain: testProviderOptions.domain }), testProviderOptions.children);
347
+ }
348
+ function mixInNoop(provider = {}) {
349
+ for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(NOOP_PROVIDER)).filter((prop2) => prop2 !== "constructor")) {
350
+ const patchedProvider = provider;
351
+ if (!Object.getPrototypeOf(patchedProvider)[prop] && !patchedProvider[prop]) {
352
+ patchedProvider[prop] = Object.getPrototypeOf(NOOP_PROVIDER)[prop];
353
+ }
354
+ }
355
+ if (!provider.metadata || !provider.metadata.name) {
356
+ provider.metadata = { name: TEST_PROVIDER };
357
+ }
358
+ return provider;
359
+ }
360
+
252
361
  // src/index.ts
253
362
  export * from "@openfeature/web-sdk";
254
363
  export {
255
364
  OpenFeatureProvider,
365
+ OpenFeatureTestProvider,
256
366
  useBooleanFlagDetails,
257
367
  useBooleanFlagValue,
258
368
  useFlag,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 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// 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": "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",
6
- "names": ["ProviderEvents", "ProviderStatus", "useEffect", "useState", "suspendUntilReady", "React", "React", "ProviderEvents", "ProviderStatus", "useState", "useEffect", "ProviderEvents", "React", "ProviderStatus", "ProviderStatus"]
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/provider/test-provider.tsx", "../../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// 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>. If you are seeing this in a test, see: https://openfeature.dev/docs/reference/technologies/client/web/react#testing',\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", "import {\n EvaluationContext,\n InMemoryProvider,\n JsonValue,\n NOOP_PROVIDER,\n OpenFeature,\n Provider,\n} from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions } from '../common/options';\nimport { OpenFeatureProvider } from './provider';\n\ntype FlagValueMap = { [flagKey: string]: JsonValue };\ntype FlagConfig = ConstructorParameters<typeof InMemoryProvider>[0];\ntype TestProviderProps = Omit<React.ComponentProps<typeof OpenFeatureProvider>, 'client'> &\n (\n | {\n provider?: never;\n /**\n * Optional map of flagKeys to flagValues for this OpenFeatureTestProvider context.\n * If not supplied, all flag evaluations will default.\n */\n flagValueMap?: FlagValueMap;\n /**\n * Optional delay for the underlying test provider's readiness and reconciliation.\n * Defaults to 0.\n */\n delayMs?: number;\n }\n | {\n /**\n * An optional partial provider to pass for full control over the flag resolution for this OpenFeatureTestProvider context.\n * Any un-implemented methods or properties will no-op.\n */\n provider?: Partial<Provider>;\n flagValueMap?: never;\n delayMs?: never;\n }\n );\n\n const TEST_VARIANT = 'test-variant';\n const TEST_PROVIDER = 'test-provider';\n\n// internal provider which is basically the in-memory provider with a simpler config and some optional fake delays\nclass TestProvider extends InMemoryProvider {\n constructor(\n flagValueMap: FlagValueMap,\n private delay = 0,\n ) {\n // convert the simple flagValueMap into an in-memory config\n const flagConfig = Object.entries(flagValueMap).reduce((acc: FlagConfig, flag): FlagConfig => {\n return {\n ...acc,\n [flag[0]]: {\n variants: {\n [TEST_VARIANT]: flag[1],\n },\n defaultVariant: TEST_VARIANT,\n disabled: false,\n },\n };\n }, {});\n super(flagConfig);\n }\n\n async initialize(context?: EvaluationContext | undefined): Promise<void> {\n await Promise.all([super.initialize(context), new Promise<void>((resolve) => setTimeout(resolve, this.delay))]);\n }\n\n async onContextChange() {\n return new Promise<void>((resolve) => setTimeout(resolve, this.delay));\n }\n}\n\n/**\n * A React Context provider based on the {@link InMemoryProvider}, specifically built for testing.\n * Use this for testing components that use flag evaluation hooks.\n * @param {TestProviderProps} testProviderOptions options for the OpenFeatureTestProvider\n * @returns {OpenFeatureProvider} OpenFeatureTestProvider\n */\nexport function OpenFeatureTestProvider(testProviderOptions: TestProviderProps) {\n const { flagValueMap, provider } = testProviderOptions;\n const effectiveProvider = (\n flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || NOOP_PROVIDER\n ) as Provider;\n testProviderOptions.domain\n ? OpenFeature.setProvider(testProviderOptions.domain, effectiveProvider)\n : OpenFeature.setProvider(effectiveProvider);\n\n return (\n <OpenFeatureProvider {...(testProviderOptions as NormalizedOptions)} domain={testProviderOptions.domain}>\n {testProviderOptions.children}\n </OpenFeatureProvider>\n );\n}\n\n// mix in the no-op provider when the partial is passed\nfunction mixInNoop(provider: Partial<Provider> = {}) {\n // fill in any missing methods with no-ops\n for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(NOOP_PROVIDER)).filter(prop => prop !== 'constructor')) {\n const patchedProvider = provider as {[key: string]: keyof Provider};\n if (!Object.getPrototypeOf(patchedProvider)[prop] && !patchedProvider[prop]) {\n patchedProvider[prop] = Object.getPrototypeOf(NOOP_PROVIDER)[prop];\n }\n }\n // fill in the metadata if missing\n if (!provider.metadata || !provider.metadata.name) {\n (provider.metadata as unknown) = { name: TEST_PROVIDER };\n }\n return provider;\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": "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",
6
+ "names": ["ProviderEvents", "ProviderStatus", "useEffect", "useState", "suspendUntilReady", "React", "React", "ProviderEvents", "ProviderStatus", "useState", "useEffect", "ProviderEvents", "React", "ProviderStatus", "ProviderStatus", "OpenFeature", "React", "OpenFeature", "React", "prop"]
7
7
  }
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { FlagEvaluationOptions, FlagValue as FlagValue$1, JsonValue, EvaluationDetails as EvaluationDetails$1, Client } from '@openfeature/web-sdk';
1
+ import { FlagEvaluationOptions, FlagValue as FlagValue$1, JsonValue, EvaluationDetails as EvaluationDetails$1, Client, Provider } from '@openfeature/web-sdk';
2
2
  export * from '@openfeature/web-sdk';
3
3
  import { FlagValue, EvaluationDetails, FlagMetadata, StandardResolutionReasons, ErrorCode } from '@openfeature/core';
4
4
  import * as React from 'react';
5
+ import React__default from 'react';
5
6
 
6
7
  type ReactFlagEvaluationOptions = ({
7
8
  /**
@@ -247,4 +248,36 @@ type Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;
247
248
  */
248
249
  declare function useWhenProviderReady(options?: Options): boolean;
249
250
 
250
- export { FlagQuery, OpenFeatureProvider, useBooleanFlagDetails, useBooleanFlagValue, useFlag, useNumberFlagDetails, useNumberFlagValue, useObjectFlagDetails, useObjectFlagValue, useOpenFeatureClient, useStringFlagDetails, useStringFlagValue, useSuspenseFlag, useWhenProviderReady };
251
+ type FlagValueMap = {
252
+ [flagKey: string]: JsonValue;
253
+ };
254
+ type TestProviderProps = Omit<React__default.ComponentProps<typeof OpenFeatureProvider>, 'client'> & ({
255
+ provider?: never;
256
+ /**
257
+ * Optional map of flagKeys to flagValues for this OpenFeatureTestProvider context.
258
+ * If not supplied, all flag evaluations will default.
259
+ */
260
+ flagValueMap?: FlagValueMap;
261
+ /**
262
+ * Optional delay for the underlying test provider's readiness and reconciliation.
263
+ * Defaults to 0.
264
+ */
265
+ delayMs?: number;
266
+ } | {
267
+ /**
268
+ * An optional partial provider to pass for full control over the flag resolution for this OpenFeatureTestProvider context.
269
+ * Any un-implemented methods or properties will no-op.
270
+ */
271
+ provider?: Partial<Provider>;
272
+ flagValueMap?: never;
273
+ delayMs?: never;
274
+ });
275
+ /**
276
+ * A React Context provider based on the {@link InMemoryProvider}, specifically built for testing.
277
+ * Use this for testing components that use flag evaluation hooks.
278
+ * @param {TestProviderProps} testProviderOptions options for the OpenFeatureTestProvider
279
+ * @returns {OpenFeatureProvider} OpenFeatureTestProvider
280
+ */
281
+ declare function OpenFeatureTestProvider(testProviderOptions: TestProviderProps): React__default.JSX.Element;
282
+
283
+ export { FlagQuery, OpenFeatureProvider, OpenFeatureTestProvider, 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.4.0",
3
+ "version": "0.4.2",
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=es2022 --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=es2022 --platform=browser --format=cjs --outfile=./dist/cjs/index.js --analyze",
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
+ }