@openfeature/react-sdk 0.3.2 → 0.3.4
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 +2 -2
- package/dist/cjs/index.js +110 -127
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/index.js +111 -127
- package/dist/esm/index.js.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.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.3.
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.3.
|
|
19
|
+
<a href="https://github.com/open-feature/js-sdk/releases/tag/react-sdk-v0.3.4">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.3.4&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
package/dist/cjs/index.js
CHANGED
|
@@ -47,8 +47,8 @@ __export(src_exports, {
|
|
|
47
47
|
module.exports = __toCommonJS(src_exports);
|
|
48
48
|
|
|
49
49
|
// src/evaluation/use-feature-flag.ts
|
|
50
|
-
var
|
|
51
|
-
var
|
|
50
|
+
var import_web_sdk4 = require("@openfeature/web-sdk");
|
|
51
|
+
var import_react4 = require("react");
|
|
52
52
|
|
|
53
53
|
// src/common/options.ts
|
|
54
54
|
var DEFAULT_OPTIONS = {
|
|
@@ -60,58 +60,31 @@ var DEFAULT_OPTIONS = {
|
|
|
60
60
|
var normalizeOptions = (options = {}) => {
|
|
61
61
|
const updateOnContextChanged = options.updateOnContextChanged;
|
|
62
62
|
const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
|
|
63
|
-
const
|
|
63
|
+
const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
|
|
64
64
|
const suspendWhileReconciling = "suspendWhileReconciling" in options ? options.suspendWhileReconciling : options.suspend;
|
|
65
65
|
return {
|
|
66
66
|
// only return these if properly set (no undefined to allow overriding with spread)
|
|
67
|
-
...typeof
|
|
67
|
+
...typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 },
|
|
68
68
|
...typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling },
|
|
69
69
|
...typeof updateOnContextChanged === "boolean" && { updateOnContextChanged },
|
|
70
70
|
...typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged }
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
// src/common/
|
|
74
|
+
// src/common/suspense.ts
|
|
75
75
|
var import_web_sdk = require("@openfeature/web-sdk");
|
|
76
|
-
function
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
client.addHandler(e, suspendResolver);
|
|
88
|
-
});
|
|
89
|
-
client.addHandler(import_web_sdk.ProviderEvents.Error, suspendResolver);
|
|
76
|
+
function suspendUntilReady(client) {
|
|
77
|
+
let resolve;
|
|
78
|
+
let reject;
|
|
79
|
+
throw new Promise((_resolve, _reject) => {
|
|
80
|
+
resolve = _resolve;
|
|
81
|
+
reject = _reject;
|
|
82
|
+
client.addHandler(import_web_sdk.ProviderEvents.Ready, resolve);
|
|
83
|
+
client.addHandler(import_web_sdk.ProviderEvents.Error, reject);
|
|
84
|
+
}).finally(() => {
|
|
85
|
+
client.removeHandler(import_web_sdk.ProviderEvents.Ready, resolve);
|
|
86
|
+
client.removeHandler(import_web_sdk.ProviderEvents.Ready, reject);
|
|
90
87
|
});
|
|
91
|
-
updateState(suspenseWrapper(suspendPromise));
|
|
92
|
-
}
|
|
93
|
-
function suspenseWrapper(promise) {
|
|
94
|
-
let status = 0 /* Pending */;
|
|
95
|
-
let result;
|
|
96
|
-
const suspended = promise.then((value) => {
|
|
97
|
-
status = 1 /* Success */;
|
|
98
|
-
result = value;
|
|
99
|
-
}).catch((error) => {
|
|
100
|
-
status = 2 /* Error */;
|
|
101
|
-
result = error;
|
|
102
|
-
});
|
|
103
|
-
return () => {
|
|
104
|
-
switch (status) {
|
|
105
|
-
case 0 /* Pending */:
|
|
106
|
-
throw suspended;
|
|
107
|
-
case 1 /* Success */:
|
|
108
|
-
return result;
|
|
109
|
-
case 2 /* Error */:
|
|
110
|
-
throw result;
|
|
111
|
-
default:
|
|
112
|
-
throw new Error("Suspending promise is in an unknown state.");
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
88
|
}
|
|
116
89
|
|
|
117
90
|
// src/provider/context.ts
|
|
@@ -134,6 +107,70 @@ function useOpenFeatureClient() {
|
|
|
134
107
|
return client;
|
|
135
108
|
}
|
|
136
109
|
|
|
110
|
+
// src/provider/use-open-feature-client-status.ts
|
|
111
|
+
var import_react3 = require("react");
|
|
112
|
+
var import_web_sdk2 = require("@openfeature/web-sdk");
|
|
113
|
+
function useOpenFeatureClientStatus() {
|
|
114
|
+
const client = useOpenFeatureClient();
|
|
115
|
+
const [status, setStatus] = (0, import_react3.useState)(client.providerStatus);
|
|
116
|
+
(0, import_react3.useEffect)(() => {
|
|
117
|
+
const updateStatus = () => setStatus(client.providerStatus);
|
|
118
|
+
client.addHandler(import_web_sdk2.ProviderEvents.ConfigurationChanged, updateStatus);
|
|
119
|
+
client.addHandler(import_web_sdk2.ProviderEvents.ContextChanged, updateStatus);
|
|
120
|
+
client.addHandler(import_web_sdk2.ProviderEvents.Error, updateStatus);
|
|
121
|
+
client.addHandler(import_web_sdk2.ProviderEvents.Ready, updateStatus);
|
|
122
|
+
client.addHandler(import_web_sdk2.ProviderEvents.Stale, updateStatus);
|
|
123
|
+
client.addHandler(import_web_sdk2.ProviderEvents.Reconciling, updateStatus);
|
|
124
|
+
return () => {
|
|
125
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.ConfigurationChanged, updateStatus);
|
|
126
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.ContextChanged, updateStatus);
|
|
127
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.Error, updateStatus);
|
|
128
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.Ready, updateStatus);
|
|
129
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.Stale, updateStatus);
|
|
130
|
+
client.removeHandler(import_web_sdk2.ProviderEvents.Reconciling, updateStatus);
|
|
131
|
+
};
|
|
132
|
+
}, [client]);
|
|
133
|
+
return status;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/evaluation/hook-flag-query.ts
|
|
137
|
+
var import_web_sdk3 = require("@openfeature/web-sdk");
|
|
138
|
+
var HookFlagQuery = class {
|
|
139
|
+
constructor(_details) {
|
|
140
|
+
this._details = _details;
|
|
141
|
+
}
|
|
142
|
+
get details() {
|
|
143
|
+
return this._details;
|
|
144
|
+
}
|
|
145
|
+
get value() {
|
|
146
|
+
return this._details?.value;
|
|
147
|
+
}
|
|
148
|
+
get variant() {
|
|
149
|
+
return this._details.variant;
|
|
150
|
+
}
|
|
151
|
+
get flagMetadata() {
|
|
152
|
+
return this._details.flagMetadata;
|
|
153
|
+
}
|
|
154
|
+
get reason() {
|
|
155
|
+
return this._details.reason;
|
|
156
|
+
}
|
|
157
|
+
get isError() {
|
|
158
|
+
return !!this._details?.errorCode || this._details.reason == import_web_sdk3.StandardResolutionReasons.ERROR;
|
|
159
|
+
}
|
|
160
|
+
get errorCode() {
|
|
161
|
+
return this._details?.errorCode;
|
|
162
|
+
}
|
|
163
|
+
get errorMessage() {
|
|
164
|
+
return this._details?.errorMessage;
|
|
165
|
+
}
|
|
166
|
+
get isAuthoritative() {
|
|
167
|
+
return !this.isError && this._details.reason != import_web_sdk3.StandardResolutionReasons.STALE && this._details.reason != import_web_sdk3.StandardResolutionReasons.DISABLED;
|
|
168
|
+
}
|
|
169
|
+
get type() {
|
|
170
|
+
return typeof this._details.value;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
137
174
|
// src/evaluation/use-feature-flag.ts
|
|
138
175
|
function useFlag(flagKey, defaultValue, options) {
|
|
139
176
|
const query = typeof defaultValue === "boolean" ? new HookFlagQuery(useBooleanFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "number" ? new HookFlagQuery(useNumberFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "string" ? new HookFlagQuery(useStringFlagDetails(flagKey, defaultValue, options)) : new HookFlagQuery(useObjectFlagDetails(flagKey, defaultValue, options));
|
|
@@ -193,117 +230,63 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
|
|
|
193
230
|
}
|
|
194
231
|
function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
195
232
|
const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
|
|
196
|
-
const [, updateState] = (0, import_react3.useState)();
|
|
197
233
|
const client = useOpenFeatureClient();
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
234
|
+
const status = useOpenFeatureClientStatus();
|
|
235
|
+
if (defaultedOptions.suspendUntilReady && status === import_web_sdk4.ProviderStatus.NOT_READY) {
|
|
236
|
+
suspendUntilReady(client);
|
|
237
|
+
}
|
|
238
|
+
if (defaultedOptions.suspendWhileReconciling && status === import_web_sdk4.ProviderStatus.RECONCILING) {
|
|
239
|
+
suspendUntilReady(client);
|
|
240
|
+
}
|
|
241
|
+
const [evalutationDetails, setEvaluationDetails] = (0, import_react4.useState)(
|
|
242
|
+
resolver(client).call(client, flagKey, defaultValue, options)
|
|
243
|
+
);
|
|
244
|
+
const updateEvaluationDetailsRef = () => {
|
|
245
|
+
setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));
|
|
209
246
|
};
|
|
210
|
-
(0,
|
|
211
|
-
if (
|
|
212
|
-
client.addHandler(
|
|
213
|
-
if (defaultedOptions.suspendUntilReady) {
|
|
214
|
-
suspend(client, updateState, import_web_sdk2.ProviderEvents.Ready);
|
|
215
|
-
}
|
|
247
|
+
(0, import_react4.useEffect)(() => {
|
|
248
|
+
if (status === import_web_sdk4.ProviderStatus.NOT_READY) {
|
|
249
|
+
client.addHandler(import_web_sdk4.ProviderEvents.Ready, updateEvaluationDetailsRef);
|
|
216
250
|
}
|
|
217
251
|
if (defaultedOptions.updateOnContextChanged) {
|
|
218
|
-
client.addHandler(
|
|
219
|
-
if (defaultedOptions.suspendWhileReconciling) {
|
|
220
|
-
client.addHandler(import_web_sdk2.ProviderEvents.Reconciling, suspendRef);
|
|
221
|
-
}
|
|
252
|
+
client.addHandler(import_web_sdk4.ProviderEvents.ContextChanged, updateEvaluationDetailsRef);
|
|
222
253
|
}
|
|
223
254
|
return () => {
|
|
224
|
-
client.removeHandler(
|
|
225
|
-
client.removeHandler(
|
|
226
|
-
client.removeHandler(import_web_sdk2.ProviderEvents.Reconciling, suspendRef);
|
|
255
|
+
client.removeHandler(import_web_sdk4.ProviderEvents.Ready, updateEvaluationDetailsRef);
|
|
256
|
+
client.removeHandler(import_web_sdk4.ProviderEvents.ContextChanged, updateEvaluationDetailsRef);
|
|
227
257
|
};
|
|
228
258
|
}, []);
|
|
229
|
-
(0,
|
|
259
|
+
(0, import_react4.useEffect)(() => {
|
|
230
260
|
if (defaultedOptions.updateOnConfigurationChanged) {
|
|
231
|
-
client.addHandler(
|
|
261
|
+
client.addHandler(import_web_sdk4.ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);
|
|
232
262
|
}
|
|
233
263
|
return () => {
|
|
234
|
-
client.removeHandler(
|
|
264
|
+
client.removeHandler(import_web_sdk4.ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);
|
|
235
265
|
};
|
|
236
266
|
}, []);
|
|
237
|
-
return
|
|
267
|
+
return evalutationDetails;
|
|
238
268
|
}
|
|
239
|
-
var HookFlagQuery = class {
|
|
240
|
-
constructor(_details) {
|
|
241
|
-
this._details = _details;
|
|
242
|
-
}
|
|
243
|
-
get details() {
|
|
244
|
-
return this._details;
|
|
245
|
-
}
|
|
246
|
-
get value() {
|
|
247
|
-
return this._details?.value;
|
|
248
|
-
}
|
|
249
|
-
get variant() {
|
|
250
|
-
return this._details.variant;
|
|
251
|
-
}
|
|
252
|
-
get flagMetadata() {
|
|
253
|
-
return this._details.flagMetadata;
|
|
254
|
-
}
|
|
255
|
-
get reason() {
|
|
256
|
-
return this._details.reason;
|
|
257
|
-
}
|
|
258
|
-
get isError() {
|
|
259
|
-
return !!this._details?.errorCode || this._details.reason == import_web_sdk2.StandardResolutionReasons.ERROR;
|
|
260
|
-
}
|
|
261
|
-
get errorCode() {
|
|
262
|
-
return this._details?.errorCode;
|
|
263
|
-
}
|
|
264
|
-
get errorMessage() {
|
|
265
|
-
return this._details?.errorMessage;
|
|
266
|
-
}
|
|
267
|
-
get isAuthoritative() {
|
|
268
|
-
return !this.isError && this._details.reason != import_web_sdk2.StandardResolutionReasons.STALE && this._details.reason != import_web_sdk2.StandardResolutionReasons.DISABLED;
|
|
269
|
-
}
|
|
270
|
-
get type() {
|
|
271
|
-
return typeof this._details.value;
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
269
|
|
|
275
270
|
// src/provider/provider.tsx
|
|
276
|
-
var
|
|
271
|
+
var import_web_sdk5 = require("@openfeature/web-sdk");
|
|
277
272
|
var React3 = __toESM(require("react"));
|
|
278
273
|
function OpenFeatureProvider({ client, domain, children, ...options }) {
|
|
279
274
|
if (!client) {
|
|
280
|
-
client =
|
|
275
|
+
client = import_web_sdk5.OpenFeature.getClient(domain);
|
|
281
276
|
}
|
|
282
277
|
return /* @__PURE__ */ React3.createElement(Context.Provider, { value: { client, options } }, children);
|
|
283
278
|
}
|
|
284
279
|
|
|
285
280
|
// src/provider/use-when-provider-ready.ts
|
|
286
|
-
var
|
|
287
|
-
var import_react4 = require("react");
|
|
281
|
+
var import_web_sdk6 = require("@openfeature/web-sdk");
|
|
288
282
|
function useWhenProviderReady(options) {
|
|
289
|
-
const [, updateState] = (0, import_react4.useState)();
|
|
290
283
|
const client = useOpenFeatureClient();
|
|
284
|
+
const status = useOpenFeatureClientStatus();
|
|
291
285
|
const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (client.providerStatus === import_web_sdk4.ProviderStatus.NOT_READY) {
|
|
297
|
-
client.addHandler(import_web_sdk4.ProviderEvents.Ready, updateStateRef);
|
|
298
|
-
if (defaultedOptions.suspendUntilReady) {
|
|
299
|
-
suspend(client, updateState, import_web_sdk4.ProviderEvents.Ready);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return () => {
|
|
303
|
-
client.removeHandler(import_web_sdk4.ProviderEvents.Ready, updateStateRef);
|
|
304
|
-
};
|
|
305
|
-
}, []);
|
|
306
|
-
return client.providerStatus === import_web_sdk4.ProviderStatus.READY;
|
|
286
|
+
if (defaultedOptions.suspendUntilReady && status === import_web_sdk6.ProviderStatus.NOT_READY) {
|
|
287
|
+
suspendUntilReady(client);
|
|
288
|
+
}
|
|
289
|
+
return status === import_web_sdk6.ProviderStatus.READY;
|
|
307
290
|
}
|
|
308
291
|
|
|
309
292
|
// src/index.ts
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -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/
|
|
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 FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspend } from '../common/suspend';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { FlagQuery } from '../query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T) => 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 [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n const forceUpdate = () => {\n updateState({});\n };\n const suspendRef = () => {\n suspend(\n client,\n updateState,\n ProviderEvents.ContextChanged,\n ProviderEvents.ConfigurationChanged,\n ProviderEvents.Ready,\n );\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspendUntilReady) {\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n if (defaultedOptions.suspendWhileReconciling) {\n client.addHandler(ProviderEvents.Reconciling, suspendRef);\n }\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.Reconciling, suspendRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, []);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n// FlagQuery implementation, do not export\nclass 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 { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendUntilReady?: boolean;\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean;\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which\n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean;\n} & FlagEvaluationOptions;\n\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction } from 'react';\n\nenum SuspendState {\n Pending,\n Success,\n Error,\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * DO NOT EXPORT PUBLICLY \n * @internal\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n * @param {ProviderEvents[]} resumeEvents list of events which will resume the suspend\n */\nexport function suspend(\n client: Client,\n updateState: Dispatch<SetStateAction<object | undefined>>,\n ...resumeEvents: ProviderEvents[]\n) {\n let suspendResolver: () => void;\n\n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n resumeEvents.forEach((e) => {\n client.removeHandler(e, suspendResolver); // remove handlers once they've run\n });\n client.removeHandler(ProviderEvents.Error, suspendResolver);\n };\n resumeEvents.forEach((e) => {\n client.addHandler(e, suspendResolver);\n });\n client.addHandler(ProviderEvents.Error, suspendResolver); // we never want to throw, resolve with errors - we may make this configurable later\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nexport function suspenseWrapper<T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise\n .then((value) => {\n status = SuspendState.Success;\n result = value;\n })\n .catch((error) => {\n status = SuspendState.Error;\n result = error;\n });\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n}\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 { 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 { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspend } from '../common/suspend';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\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 [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const updateStateRef = () => {\n updateState({});\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // re-render when provider is ready\n client.addHandler(ProviderEvents.Ready, updateStateRef);\n if (defaultedOptions.suspendUntilReady) {\n // suspend and update when the provider is ready\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n return () => {\n // cleanup the handler\n client.removeHandler(ProviderEvents.Ready, updateStateRef);\n };\n }, []);\n\n return client.providerStatus === ProviderStatus.READY;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,kBAQO;AACP,IAAAC,gBAAoC;;;ACyC7B,IAAM,kBAA8C;AAAA,EACzD,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B;AASO,IAAM,mBAAgF,CAAC,UAAsC,CAAC,MAAM;AACzI,QAAM,yBAAyB,QAAQ;AACvC,QAAM,+BAA+B,QAAQ;AAG7C,
|
|
6
|
-
"names": ["import_web_sdk", "import_react", "React", "import_react", "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"],
|
|
4
|
+
"sourcesContent": ["export * from './evaluation';\nexport * from './query';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n", "import {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendUntilReady?: boolean;\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean;\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which\n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean;\n} & FlagEvaluationOptions;\n\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\n const { client } = React.useContext(Context) || {};\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>',\n );\n }\n\n return client;\n}\n", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain?: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client?: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain &\n ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n"],
|
|
5
|
+
"mappings": "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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"]
|
|
7
7
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// src/evaluation/use-feature-flag.ts
|
|
2
2
|
import {
|
|
3
|
-
ProviderEvents as
|
|
4
|
-
ProviderStatus
|
|
5
|
-
StandardResolutionReasons
|
|
3
|
+
ProviderEvents as ProviderEvents3,
|
|
4
|
+
ProviderStatus as ProviderStatus2
|
|
6
5
|
} from "@openfeature/web-sdk";
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
6
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
8
7
|
|
|
9
8
|
// src/common/options.ts
|
|
10
9
|
var DEFAULT_OPTIONS = {
|
|
@@ -16,58 +15,31 @@ var DEFAULT_OPTIONS = {
|
|
|
16
15
|
var normalizeOptions = (options = {}) => {
|
|
17
16
|
const updateOnContextChanged = options.updateOnContextChanged;
|
|
18
17
|
const updateOnConfigurationChanged = options.updateOnConfigurationChanged;
|
|
19
|
-
const
|
|
18
|
+
const suspendUntilReady2 = "suspendUntilReady" in options ? options.suspendUntilReady : options.suspend;
|
|
20
19
|
const suspendWhileReconciling = "suspendWhileReconciling" in options ? options.suspendWhileReconciling : options.suspend;
|
|
21
20
|
return {
|
|
22
21
|
// only return these if properly set (no undefined to allow overriding with spread)
|
|
23
|
-
...typeof
|
|
22
|
+
...typeof suspendUntilReady2 === "boolean" && { suspendUntilReady: suspendUntilReady2 },
|
|
24
23
|
...typeof suspendWhileReconciling === "boolean" && { suspendWhileReconciling },
|
|
25
24
|
...typeof updateOnContextChanged === "boolean" && { updateOnContextChanged },
|
|
26
25
|
...typeof updateOnConfigurationChanged === "boolean" && { updateOnConfigurationChanged }
|
|
27
26
|
};
|
|
28
27
|
};
|
|
29
28
|
|
|
30
|
-
// src/common/
|
|
29
|
+
// src/common/suspense.ts
|
|
31
30
|
import { ProviderEvents } from "@openfeature/web-sdk";
|
|
32
|
-
function
|
|
33
|
-
let
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
client.addHandler(e, suspendResolver);
|
|
44
|
-
});
|
|
45
|
-
client.addHandler(ProviderEvents.Error, suspendResolver);
|
|
31
|
+
function suspendUntilReady(client) {
|
|
32
|
+
let resolve;
|
|
33
|
+
let reject;
|
|
34
|
+
throw new Promise((_resolve, _reject) => {
|
|
35
|
+
resolve = _resolve;
|
|
36
|
+
reject = _reject;
|
|
37
|
+
client.addHandler(ProviderEvents.Ready, resolve);
|
|
38
|
+
client.addHandler(ProviderEvents.Error, reject);
|
|
39
|
+
}).finally(() => {
|
|
40
|
+
client.removeHandler(ProviderEvents.Ready, resolve);
|
|
41
|
+
client.removeHandler(ProviderEvents.Ready, reject);
|
|
46
42
|
});
|
|
47
|
-
updateState(suspenseWrapper(suspendPromise));
|
|
48
|
-
}
|
|
49
|
-
function suspenseWrapper(promise) {
|
|
50
|
-
let status = 0 /* Pending */;
|
|
51
|
-
let result;
|
|
52
|
-
const suspended = promise.then((value) => {
|
|
53
|
-
status = 1 /* Success */;
|
|
54
|
-
result = value;
|
|
55
|
-
}).catch((error) => {
|
|
56
|
-
status = 2 /* Error */;
|
|
57
|
-
result = error;
|
|
58
|
-
});
|
|
59
|
-
return () => {
|
|
60
|
-
switch (status) {
|
|
61
|
-
case 0 /* Pending */:
|
|
62
|
-
throw suspended;
|
|
63
|
-
case 1 /* Success */:
|
|
64
|
-
return result;
|
|
65
|
-
case 2 /* Error */:
|
|
66
|
-
throw result;
|
|
67
|
-
default:
|
|
68
|
-
throw new Error("Suspending promise is in an unknown state.");
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
43
|
}
|
|
72
44
|
|
|
73
45
|
// src/provider/context.ts
|
|
@@ -90,6 +62,72 @@ function useOpenFeatureClient() {
|
|
|
90
62
|
return client;
|
|
91
63
|
}
|
|
92
64
|
|
|
65
|
+
// src/provider/use-open-feature-client-status.ts
|
|
66
|
+
import { useEffect, useState } from "react";
|
|
67
|
+
import { ProviderEvents as ProviderEvents2 } from "@openfeature/web-sdk";
|
|
68
|
+
function useOpenFeatureClientStatus() {
|
|
69
|
+
const client = useOpenFeatureClient();
|
|
70
|
+
const [status, setStatus] = useState(client.providerStatus);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const updateStatus = () => setStatus(client.providerStatus);
|
|
73
|
+
client.addHandler(ProviderEvents2.ConfigurationChanged, updateStatus);
|
|
74
|
+
client.addHandler(ProviderEvents2.ContextChanged, updateStatus);
|
|
75
|
+
client.addHandler(ProviderEvents2.Error, updateStatus);
|
|
76
|
+
client.addHandler(ProviderEvents2.Ready, updateStatus);
|
|
77
|
+
client.addHandler(ProviderEvents2.Stale, updateStatus);
|
|
78
|
+
client.addHandler(ProviderEvents2.Reconciling, updateStatus);
|
|
79
|
+
return () => {
|
|
80
|
+
client.removeHandler(ProviderEvents2.ConfigurationChanged, updateStatus);
|
|
81
|
+
client.removeHandler(ProviderEvents2.ContextChanged, updateStatus);
|
|
82
|
+
client.removeHandler(ProviderEvents2.Error, updateStatus);
|
|
83
|
+
client.removeHandler(ProviderEvents2.Ready, updateStatus);
|
|
84
|
+
client.removeHandler(ProviderEvents2.Stale, updateStatus);
|
|
85
|
+
client.removeHandler(ProviderEvents2.Reconciling, updateStatus);
|
|
86
|
+
};
|
|
87
|
+
}, [client]);
|
|
88
|
+
return status;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/evaluation/hook-flag-query.ts
|
|
92
|
+
import {
|
|
93
|
+
StandardResolutionReasons
|
|
94
|
+
} from "@openfeature/web-sdk";
|
|
95
|
+
var HookFlagQuery = class {
|
|
96
|
+
constructor(_details) {
|
|
97
|
+
this._details = _details;
|
|
98
|
+
}
|
|
99
|
+
get details() {
|
|
100
|
+
return this._details;
|
|
101
|
+
}
|
|
102
|
+
get value() {
|
|
103
|
+
return this._details?.value;
|
|
104
|
+
}
|
|
105
|
+
get variant() {
|
|
106
|
+
return this._details.variant;
|
|
107
|
+
}
|
|
108
|
+
get flagMetadata() {
|
|
109
|
+
return this._details.flagMetadata;
|
|
110
|
+
}
|
|
111
|
+
get reason() {
|
|
112
|
+
return this._details.reason;
|
|
113
|
+
}
|
|
114
|
+
get isError() {
|
|
115
|
+
return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;
|
|
116
|
+
}
|
|
117
|
+
get errorCode() {
|
|
118
|
+
return this._details?.errorCode;
|
|
119
|
+
}
|
|
120
|
+
get errorMessage() {
|
|
121
|
+
return this._details?.errorMessage;
|
|
122
|
+
}
|
|
123
|
+
get isAuthoritative() {
|
|
124
|
+
return !this.isError && this._details.reason != StandardResolutionReasons.STALE && this._details.reason != StandardResolutionReasons.DISABLED;
|
|
125
|
+
}
|
|
126
|
+
get type() {
|
|
127
|
+
return typeof this._details.value;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
93
131
|
// src/evaluation/use-feature-flag.ts
|
|
94
132
|
function useFlag(flagKey, defaultValue, options) {
|
|
95
133
|
const query = typeof defaultValue === "boolean" ? new HookFlagQuery(useBooleanFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "number" ? new HookFlagQuery(useNumberFlagDetails(flagKey, defaultValue, options)) : typeof defaultValue === "string" ? new HookFlagQuery(useStringFlagDetails(flagKey, defaultValue, options)) : new HookFlagQuery(useObjectFlagDetails(flagKey, defaultValue, options));
|
|
@@ -149,84 +187,42 @@ function useObjectFlagDetails(flagKey, defaultValue, options) {
|
|
|
149
187
|
}
|
|
150
188
|
function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
151
189
|
const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
|
|
152
|
-
const [, updateState] = useState();
|
|
153
190
|
const client = useOpenFeatureClient();
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
191
|
+
const status = useOpenFeatureClientStatus();
|
|
192
|
+
if (defaultedOptions.suspendUntilReady && status === ProviderStatus2.NOT_READY) {
|
|
193
|
+
suspendUntilReady(client);
|
|
194
|
+
}
|
|
195
|
+
if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus2.RECONCILING) {
|
|
196
|
+
suspendUntilReady(client);
|
|
197
|
+
}
|
|
198
|
+
const [evalutationDetails, setEvaluationDetails] = useState2(
|
|
199
|
+
resolver(client).call(client, flagKey, defaultValue, options)
|
|
200
|
+
);
|
|
201
|
+
const updateEvaluationDetailsRef = () => {
|
|
202
|
+
setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));
|
|
165
203
|
};
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
client.addHandler(
|
|
169
|
-
if (defaultedOptions.suspendUntilReady) {
|
|
170
|
-
suspend(client, updateState, ProviderEvents2.Ready);
|
|
171
|
-
}
|
|
204
|
+
useEffect2(() => {
|
|
205
|
+
if (status === ProviderStatus2.NOT_READY) {
|
|
206
|
+
client.addHandler(ProviderEvents3.Ready, updateEvaluationDetailsRef);
|
|
172
207
|
}
|
|
173
208
|
if (defaultedOptions.updateOnContextChanged) {
|
|
174
|
-
client.addHandler(
|
|
175
|
-
if (defaultedOptions.suspendWhileReconciling) {
|
|
176
|
-
client.addHandler(ProviderEvents2.Reconciling, suspendRef);
|
|
177
|
-
}
|
|
209
|
+
client.addHandler(ProviderEvents3.ContextChanged, updateEvaluationDetailsRef);
|
|
178
210
|
}
|
|
179
211
|
return () => {
|
|
180
|
-
client.removeHandler(
|
|
181
|
-
client.removeHandler(
|
|
182
|
-
client.removeHandler(ProviderEvents2.Reconciling, suspendRef);
|
|
212
|
+
client.removeHandler(ProviderEvents3.Ready, updateEvaluationDetailsRef);
|
|
213
|
+
client.removeHandler(ProviderEvents3.ContextChanged, updateEvaluationDetailsRef);
|
|
183
214
|
};
|
|
184
215
|
}, []);
|
|
185
|
-
|
|
216
|
+
useEffect2(() => {
|
|
186
217
|
if (defaultedOptions.updateOnConfigurationChanged) {
|
|
187
|
-
client.addHandler(
|
|
218
|
+
client.addHandler(ProviderEvents3.ConfigurationChanged, updateEvaluationDetailsRef);
|
|
188
219
|
}
|
|
189
220
|
return () => {
|
|
190
|
-
client.removeHandler(
|
|
221
|
+
client.removeHandler(ProviderEvents3.ConfigurationChanged, updateEvaluationDetailsRef);
|
|
191
222
|
};
|
|
192
223
|
}, []);
|
|
193
|
-
return
|
|
224
|
+
return evalutationDetails;
|
|
194
225
|
}
|
|
195
|
-
var HookFlagQuery = class {
|
|
196
|
-
constructor(_details) {
|
|
197
|
-
this._details = _details;
|
|
198
|
-
}
|
|
199
|
-
get details() {
|
|
200
|
-
return this._details;
|
|
201
|
-
}
|
|
202
|
-
get value() {
|
|
203
|
-
return this._details?.value;
|
|
204
|
-
}
|
|
205
|
-
get variant() {
|
|
206
|
-
return this._details.variant;
|
|
207
|
-
}
|
|
208
|
-
get flagMetadata() {
|
|
209
|
-
return this._details.flagMetadata;
|
|
210
|
-
}
|
|
211
|
-
get reason() {
|
|
212
|
-
return this._details.reason;
|
|
213
|
-
}
|
|
214
|
-
get isError() {
|
|
215
|
-
return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;
|
|
216
|
-
}
|
|
217
|
-
get errorCode() {
|
|
218
|
-
return this._details?.errorCode;
|
|
219
|
-
}
|
|
220
|
-
get errorMessage() {
|
|
221
|
-
return this._details?.errorMessage;
|
|
222
|
-
}
|
|
223
|
-
get isAuthoritative() {
|
|
224
|
-
return !this.isError && this._details.reason != StandardResolutionReasons.STALE && this._details.reason != StandardResolutionReasons.DISABLED;
|
|
225
|
-
}
|
|
226
|
-
get type() {
|
|
227
|
-
return typeof this._details.value;
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
226
|
|
|
231
227
|
// src/provider/provider.tsx
|
|
232
228
|
import { OpenFeature } from "@openfeature/web-sdk";
|
|
@@ -239,27 +235,15 @@ function OpenFeatureProvider({ client, domain, children, ...options }) {
|
|
|
239
235
|
}
|
|
240
236
|
|
|
241
237
|
// src/provider/use-when-provider-ready.ts
|
|
242
|
-
import {
|
|
243
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
238
|
+
import { ProviderStatus as ProviderStatus3 } from "@openfeature/web-sdk";
|
|
244
239
|
function useWhenProviderReady(options) {
|
|
245
|
-
const [, updateState] = useState2();
|
|
246
240
|
const client = useOpenFeatureClient();
|
|
241
|
+
const status = useOpenFeatureClientStatus();
|
|
247
242
|
const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (client.providerStatus === ProviderStatus2.NOT_READY) {
|
|
253
|
-
client.addHandler(ProviderEvents3.Ready, updateStateRef);
|
|
254
|
-
if (defaultedOptions.suspendUntilReady) {
|
|
255
|
-
suspend(client, updateState, ProviderEvents3.Ready);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return () => {
|
|
259
|
-
client.removeHandler(ProviderEvents3.Ready, updateStateRef);
|
|
260
|
-
};
|
|
261
|
-
}, []);
|
|
262
|
-
return client.providerStatus === ProviderStatus2.READY;
|
|
243
|
+
if (defaultedOptions.suspendUntilReady && status === ProviderStatus3.NOT_READY) {
|
|
244
|
+
suspendUntilReady(client);
|
|
245
|
+
}
|
|
246
|
+
return status === ProviderStatus3.READY;
|
|
263
247
|
}
|
|
264
248
|
|
|
265
249
|
// src/index.ts
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/evaluation/use-feature-flag.ts", "../../src/common/options.ts", "../../src/common/
|
|
4
|
-
"sourcesContent": ["import {\n Client,\n EvaluationDetails,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspend } from '../common/suspend';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { FlagQuery } from '../query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T) => 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 [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n const forceUpdate = () => {\n updateState({});\n };\n const suspendRef = () => {\n suspend(\n client,\n updateState,\n ProviderEvents.ContextChanged,\n ProviderEvents.ConfigurationChanged,\n ProviderEvents.Ready,\n );\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, forceUpdate);\n if (defaultedOptions.suspendUntilReady) {\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, forceUpdate);\n if (defaultedOptions.suspendWhileReconciling) {\n client.addHandler(ProviderEvents.Reconciling, suspendRef);\n }\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, forceUpdate);\n client.removeHandler(ProviderEvents.ContextChanged, forceUpdate);\n client.removeHandler(ProviderEvents.Reconciling, suspendRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, forceUpdate);\n };\n }, []);\n\n return resolver(client).call(client, flagKey, defaultValue);\n}\n\n// FlagQuery implementation, do not export\nclass 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 { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendUntilReady?: boolean;\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean;\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which\n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean;\n} & FlagEvaluationOptions;\n\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\nimport { Dispatch, SetStateAction } from 'react';\n\nenum SuspendState {\n Pending,\n Success,\n Error,\n}\n\n/**\n * Suspend function. If this runs, components using the calling hook will be suspended.\n * DO NOT EXPORT PUBLICLY \n * @internal\n * @param {Client} client the OpenFeature client\n * @param {Function} updateState the state update function\n * @param {ProviderEvents[]} resumeEvents list of events which will resume the suspend\n */\nexport function suspend(\n client: Client,\n updateState: Dispatch<SetStateAction<object | undefined>>,\n ...resumeEvents: ProviderEvents[]\n) {\n let suspendResolver: () => void;\n\n const suspendPromise = new Promise<void>((resolve) => {\n suspendResolver = () => {\n resolve();\n resumeEvents.forEach((e) => {\n client.removeHandler(e, suspendResolver); // remove handlers once they've run\n });\n client.removeHandler(ProviderEvents.Error, suspendResolver);\n };\n resumeEvents.forEach((e) => {\n client.addHandler(e, suspendResolver);\n });\n client.addHandler(ProviderEvents.Error, suspendResolver); // we never want to throw, resolve with errors - we may make this configurable later\n });\n updateState(suspenseWrapper(suspendPromise));\n}\n\n/**\n * Promise wrapper that throws unresolved promises to support React suspense.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {Promise<T>} promise to wrap\n * @template T flag type\n * @returns {Function} suspense-compliant lambda\n */\nexport function suspenseWrapper<T>(promise: Promise<T>) {\n let status: SuspendState = SuspendState.Pending;\n let result: T;\n\n const suspended = promise\n .then((value) => {\n status = SuspendState.Success;\n result = value;\n })\n .catch((error) => {\n status = SuspendState.Error;\n result = error;\n });\n\n return () => {\n switch (status) {\n case SuspendState.Pending:\n throw suspended;\n case SuspendState.Success:\n return result;\n case SuspendState.Error:\n throw result;\n default:\n throw new Error('Suspending promise is in an unknown state.');\n }\n };\n}\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 { 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 { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspend } from '../common/suspend';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\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 [, updateState] = useState<object | undefined>();\n const client = useOpenFeatureClient();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const updateStateRef = () => {\n updateState({});\n };\n\n useEffect(() => {\n if (client.providerStatus === ProviderStatus.NOT_READY) {\n // re-render when provider is ready\n client.addHandler(ProviderEvents.Ready, updateStateRef);\n if (defaultedOptions.suspendUntilReady) {\n // suspend and update when the provider is ready\n suspend(client, updateState, ProviderEvents.Ready);\n }\n }\n return () => {\n // cleanup the handler\n client.removeHandler(ProviderEvents.Ready, updateStateRef);\n };\n }, []);\n\n return client.providerStatus === ProviderStatus.READY;\n}\n", "export * from './evaluation';\nexport * from './query';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n"],
|
|
5
|
-
"mappings": ";AAAA;AAAA,
|
|
6
|
-
"names": ["ProviderEvents", "
|
|
3
|
+
"sources": ["../../src/evaluation/use-feature-flag.ts", "../../src/common/options.ts", "../../src/common/suspense.ts", "../../src/provider/context.ts", "../../src/provider/use-open-feature-client.ts", "../../src/provider/use-open-feature-client-status.ts", "../../src/evaluation/hook-flag-query.ts", "../../src/provider/provider.tsx", "../../src/provider/use-when-provider-ready.ts", "../../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n Client,\n EvaluationDetails,\n FlagEvaluationOptions,\n FlagValue,\n JsonValue,\n ProviderEvents,\n ProviderStatus,\n} from '@openfeature/web-sdk';\nimport { useEffect, useState } from 'react';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { suspendUntilReady } from '../common/suspense';\nimport { useProviderOptions } from '../provider/context';\nimport { useOpenFeatureClient } from '../provider/use-open-feature-client';\nimport { useOpenFeatureClientStatus } from '../provider/use-open-feature-client-status';\nimport { FlagQuery } from '../query';\nimport { HookFlagQuery } from './hook-flag-query';\n\n// This type is a bit wild-looking, but I think we need it.\n// We have to use the conditional, because otherwise useFlag('key', false) would return false, not boolean (too constrained).\n// We have a duplicate for the hook return below, this one is just used for casting because the name isn't as clear\ntype ConstrainedFlagQuery<T> = FlagQuery<\n T extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n>;\n\n/**\n * Evaluates a feature flag generically, returning an react-flavored queryable object.\n * The resolver method to use is based on the type of the defaultValue.\n * For type-specific hooks, use {@link useBooleanFlagValue}, {@link useBooleanFlagDetails} and equivalents.\n * By default, components will re-render when the flag value changes.\n * @param {string} flagKey the flag identifier\n * @template {FlagValue} T A optional generic argument constraining the default.\n * @param {T} defaultValue the default value; used to determine what resolved type should be used.\n * @param {ReactFlagEvaluationOptions} options for this evaluation\n * @returns { FlagQuery } a queryable object containing useful information about the flag.\n */\nexport function useFlag<T extends FlagValue = FlagValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): FlagQuery<\nT extends boolean\n ? boolean\n : T extends number\n ? number\n : T extends string\n ? string\n : T extends JsonValue\n ? T\n : JsonValue\n> {\n // use the default value to determine the resolver to call\n const query =\n typeof defaultValue === 'boolean'\n ? new HookFlagQuery<boolean>(useBooleanFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'number'\n ? new HookFlagQuery<number>(useNumberFlagDetails(flagKey, defaultValue, options))\n : typeof defaultValue === 'string'\n ? new HookFlagQuery<string>(useStringFlagDetails(flagKey, defaultValue, options))\n : new HookFlagQuery<JsonValue>(useObjectFlagDetails(flagKey, defaultValue, options));\n // TS sees this as HookFlagQuery<JsonValue>, because the compiler isn't aware of the `typeof` checks above.\n return query as unknown as ConstrainedFlagQuery<T>;\n}\n\n/**\n * Evaluates a feature flag, returning a boolean.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagValue(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): boolean {\n return useBooleanFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {boolean} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<boolean>} a EvaluationDetails object for this evaluation\n */\nexport function useBooleanFlagDetails(\n flagKey: string,\n defaultValue: boolean,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<boolean> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getBooleanDetails;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a string.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagValue<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): string {\n return useStringFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {string} [T=string] A optional generic argument constraining the string\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<string>} a EvaluationDetails object for this evaluation\n */\nexport function useStringFlagDetails<T extends string = string>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<string> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getStringDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning a number.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagValue<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): number {\n return useNumberFlagDetails(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {number} [T=number] A optional generic argument constraining the number\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<number>} a EvaluationDetails object for this evaluation\n */\nexport function useNumberFlagDetails<T extends number = number>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<number> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getNumberDetails<T>;\n },\n options,\n );\n}\n\n/**\n * Evaluates a feature flag, returning an object.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {T} defaultValue the default value\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { boolean} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagValue<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): T {\n return useObjectFlagDetails<T>(flagKey, defaultValue, options).value;\n}\n\n/**\n * Evaluates a feature flag, returning evaluation details.\n * By default, components will re-render when the flag value changes.\n * For a generic hook returning a queryable interface, see {@link useFlag}.\n * @param {string} flagKey the flag identifier\n * @param {T} defaultValue the default value\n * @template {JsonValue} [T=JsonValue] A optional generic argument describing the structure\n * @param {ReactFlagEvaluationOptions} options options for this evaluation\n * @returns { EvaluationDetails<T>} a EvaluationDetails object for this evaluation\n */\nexport function useObjectFlagDetails<T extends JsonValue = JsonValue>(\n flagKey: string,\n defaultValue: T,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n return attachHandlersAndResolve(\n flagKey,\n defaultValue,\n (client) => {\n return client.getObjectDetails<T>;\n },\n options,\n );\n}\n\nfunction attachHandlersAndResolve<T extends FlagValue>(\n flagKey: string,\n defaultValue: T,\n resolver: (client: Client) => (flagKey: string, defaultValue: T, options?: FlagEvaluationOptions) => EvaluationDetails<T>,\n options?: ReactFlagEvaluationOptions,\n): EvaluationDetails<T> {\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n if (defaultedOptions.suspendWhileReconciling && status === ProviderStatus.RECONCILING) {\n suspendUntilReady(client);\n }\n\n const [evalutationDetails, setEvaluationDetails] = useState<EvaluationDetails<T>>(\n resolver(client).call(client, flagKey, defaultValue, options),\n );\n\n const updateEvaluationDetailsRef = () => {\n setEvaluationDetails(resolver(client).call(client, flagKey, defaultValue, options));\n };\n\n useEffect(() => {\n if (status === ProviderStatus.NOT_READY) {\n // update when the provider is ready\n client.addHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n }\n\n if (defaultedOptions.updateOnContextChanged) {\n // update when the context changes\n client.addHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.Ready, updateEvaluationDetailsRef);\n client.removeHandler(ProviderEvents.ContextChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n useEffect(() => {\n if (defaultedOptions.updateOnConfigurationChanged) {\n // update when the provider configuration changes\n client.addHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n }\n return () => {\n // cleanup the handlers\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateEvaluationDetailsRef);\n };\n }, []);\n\n return evalutationDetails;\n}\n", "import { FlagEvaluationOptions } from '@openfeature/web-sdk';\n\nexport type ReactFlagEvaluationOptions = ({\n /**\n * Enable or disable all suspense functionality.\n * Cannot be used in conjunction with `suspendUntilReady` and `suspendWhileReconciling` options.\n */\n suspend?: boolean;\n suspendUntilReady?: never;\n suspendWhileReconciling?: never;\n} | {\n /**\n * Suspend flag evaluations while the provider is not ready.\n * Set to false if you don't want to show suspense fallbacks until the provider is initialized.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendUntilReady?: boolean;\n /**\n * Suspend flag evaluations while the provider's context is being reconciled.\n * Set to true if you want to show suspense fallbacks while flags are re-evaluated after context changes.\n * Defaults to true.\n * Cannot be used in conjunction with `suspend` option.\n */\n suspendWhileReconciling?: boolean;\n suspend?: never;\n}) & {\n /**\n * Update the component if the provider emits a ConfigurationChanged event.\n * Set to false to prevent components from re-rendering when flag value changes\n * are received by the associated provider.\n * Defaults to true.\n */\n updateOnConfigurationChanged?: boolean;\n /**\n * Update the component when the OpenFeature context changes.\n * Set to false to prevent components from re-rendering when attributes which\n * may be factors in flag evaluation change.\n * Defaults to true.\n */\n updateOnContextChanged?: boolean;\n} & FlagEvaluationOptions;\n\nexport type NormalizedOptions = Omit<ReactFlagEvaluationOptions, 'suspend'>;\n\n/**\n * Default options.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const DEFAULT_OPTIONS: ReactFlagEvaluationOptions = {\n updateOnContextChanged: true,\n updateOnConfigurationChanged: true,\n suspendUntilReady: true,\n suspendWhileReconciling: true,\n};\n\n/**\n * Returns normalization options (all `undefined` fields removed, and `suspend` decomposed to `suspendUntilReady` and `suspendWhileReconciling`).\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @param {ReactFlagEvaluationOptions} options options to normalize\n * @returns {NormalizedOptions} normalized options\n */\nexport const normalizeOptions: (options?: ReactFlagEvaluationOptions) => NormalizedOptions = (options: ReactFlagEvaluationOptions = {}) => {\n const updateOnContextChanged = options.updateOnContextChanged;\n const updateOnConfigurationChanged = options.updateOnConfigurationChanged;\n\n // fall-back the suspense options to the catch-all `suspend` property \n const suspendUntilReady = 'suspendUntilReady' in options ? options.suspendUntilReady : options.suspend;\n const suspendWhileReconciling = 'suspendWhileReconciling' in options ? options.suspendWhileReconciling : options.suspend;\n\n return {\n // only return these if properly set (no undefined to allow overriding with spread)\n ...(typeof suspendUntilReady === 'boolean' && {suspendUntilReady}),\n ...(typeof suspendWhileReconciling === 'boolean' && {suspendWhileReconciling}),\n ...(typeof updateOnContextChanged === 'boolean' && {updateOnContextChanged}),\n ...(typeof updateOnConfigurationChanged === 'boolean' && {updateOnConfigurationChanged}),\n };\n};\n", "import { Client, ProviderEvents } from '@openfeature/web-sdk';\n\n/**\n * Suspends until the client is ready to evaluate feature flags.\n * DO NOT EXPORT PUBLICLY\n * @param {Client} client OpenFeature client\n */\nexport function suspendUntilReady(client: Client): Promise<void> {\n let resolve: (value: unknown) => void;\n let reject: () => void;\n throw new Promise((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n client.addHandler(ProviderEvents.Ready, resolve);\n client.addHandler(ProviderEvents.Error, reject);\n }).finally(() => {\n client.removeHandler(ProviderEvents.Ready, resolve);\n client.removeHandler(ProviderEvents.Ready, reject);\n });\n}\n", "import { Client } from '@openfeature/web-sdk';\nimport React from 'react';\nimport { NormalizedOptions, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\n\n/**\n * The underlying React context.\n * DO NOT EXPORT PUBLICLY\n * @internal\n */\nexport const Context = React.createContext<{ client: Client; options: ReactFlagEvaluationOptions } | undefined>(undefined);\n\n/**\n * Get a normalized copy of the options used for this OpenFeatureProvider, see {@link normalizeOptions}.\n * DO NOT EXPORT PUBLICLY\n * @internal\n * @returns {NormalizedOptions} normalized options the defaulted options, not defaulted or normalized.\n */\nexport function useProviderOptions(): NormalizedOptions {\n const { options } = React.useContext(Context) || {};\n return normalizeOptions(options);\n}\n", "import React from 'react';\nimport { Context } from './context';\nimport { Client } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link Client} instance for this OpenFeatureProvider context.\n * Note that the provider to which this is bound is determined by the OpenFeatureProvider's domain.\n * @returns {Client} client for this scope\n */\nexport function useOpenFeatureClient(): Client {\n const { client } = React.useContext(Context) || {};\n\n if (!client) {\n throw new Error(\n 'No OpenFeature client available - components using OpenFeature must be wrapped with an <OpenFeatureProvider>',\n );\n }\n\n return client;\n}\n", "import { useEffect, useState } from 'react';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { ProviderEvents, ProviderStatus } from '@openfeature/web-sdk';\n\n/**\n * Get the {@link ProviderStatus} for the OpenFeatureClient.\n * @returns {ProviderStatus} status of the client for this scope\n */\nexport function useOpenFeatureClientStatus(): ProviderStatus {\n const client = useOpenFeatureClient();\n const [status, setStatus] = useState(client.providerStatus);\n\n useEffect(() => {\n const updateStatus = () => setStatus(client.providerStatus);\n client.addHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.addHandler(ProviderEvents.ContextChanged, updateStatus);\n client.addHandler(ProviderEvents.Error, updateStatus);\n client.addHandler(ProviderEvents.Ready, updateStatus);\n client.addHandler(ProviderEvents.Stale, updateStatus);\n client.addHandler(ProviderEvents.Reconciling, updateStatus);\n return () => {\n client.removeHandler(ProviderEvents.ConfigurationChanged, updateStatus);\n client.removeHandler(ProviderEvents.ContextChanged, updateStatus);\n client.removeHandler(ProviderEvents.Error, updateStatus);\n client.removeHandler(ProviderEvents.Ready, updateStatus);\n client.removeHandler(ProviderEvents.Stale, updateStatus);\n client.removeHandler(ProviderEvents.Reconciling, updateStatus);\n };\n }, [client]);\n\n return status;\n}\n", "import {\n EvaluationDetails,\n FlagValue,\n StandardResolutionReasons\n} from '@openfeature/web-sdk';\nimport { FlagQuery } from '../query';\n\n\n// FlagQuery implementation, do not export\nexport class HookFlagQuery<T extends FlagValue = FlagValue> implements FlagQuery {\n constructor(private _details: EvaluationDetails<T>) {}\n\n get details() {\n return this._details;\n }\n\n get value() {\n return this._details?.value;\n }\n\n get variant() {\n return this._details.variant;\n }\n\n get flagMetadata() {\n return this._details.flagMetadata;\n }\n\n get reason() {\n return this._details.reason;\n }\n\n get isError() {\n return !!this._details?.errorCode || this._details.reason == StandardResolutionReasons.ERROR;\n }\n\n get errorCode() {\n return this._details?.errorCode;\n }\n\n get errorMessage() {\n return this._details?.errorMessage;\n }\n\n get isAuthoritative() {\n return (\n !this.isError &&\n this._details.reason != StandardResolutionReasons.STALE &&\n this._details.reason != StandardResolutionReasons.DISABLED\n );\n }\n\n get type() {\n return typeof this._details.value;\n }\n}\n", "import { Client, OpenFeature } from '@openfeature/web-sdk';\nimport * as React from 'react';\nimport { ReactFlagEvaluationOptions } from '../common/options';\nimport { Context } from './context';\n\ntype ClientOrDomain =\n | {\n /**\n * An identifier which logically binds clients with providers\n * @see OpenFeature.setProvider() and overloads.\n */\n domain?: string;\n client?: never;\n }\n | {\n /**\n * OpenFeature client to use.\n */\n client?: Client;\n domain?: never;\n };\n\ntype ProviderProps = {\n children?: React.ReactNode;\n} & ClientOrDomain &\n ReactFlagEvaluationOptions;\n\n /**\n * Provides a scope for evaluating feature flags by binding a client to all child components.\n * @param {ProviderProps} properties props for the context provider\n * @returns {OpenFeatureProvider} context provider\n */\nexport function OpenFeatureProvider({ client, domain, children, ...options }: ProviderProps) {\n if (!client) {\n client = OpenFeature.getClient(domain);\n }\n\n return <Context.Provider value={{ client, options }}>{children}</Context.Provider>;\n}\n", "import { ProviderStatus } from '@openfeature/web-sdk';\nimport { DEFAULT_OPTIONS, ReactFlagEvaluationOptions, normalizeOptions } from '../common/options';\nimport { useProviderOptions } from './context';\nimport { useOpenFeatureClient } from './use-open-feature-client';\nimport { useOpenFeatureClientStatus } from './use-open-feature-client-status';\nimport { suspendUntilReady } from '../common/suspense';\n\ntype Options = Pick<ReactFlagEvaluationOptions, 'suspendUntilReady'>;\n\n/**\n * Utility hook that triggers suspense until the provider is {@link ProviderStatus.READY}, without evaluating any flags.\n * Especially useful for React v16/17 \"Legacy Suspense\", in which siblings to suspending components are\n * initially mounted and then hidden (see: https://github.com/reactwg/react-18/discussions/7).\n * @param {Options} options options for suspense\n * @returns {boolean} boolean indicating if provider is {@link ProviderStatus.READY}, useful if suspense is disabled and you want to handle loaders on your own\n */\nexport function useWhenProviderReady(options?: Options): boolean {\n const client = useOpenFeatureClient();\n const status = useOpenFeatureClientStatus();\n // highest priority > evaluation hook options > provider options > default options > lowest priority\n const defaultedOptions = { ...DEFAULT_OPTIONS, ...useProviderOptions(), ...normalizeOptions(options) };\n\n // suspense\n if (defaultedOptions.suspendUntilReady && status === ProviderStatus.NOT_READY) {\n suspendUntilReady(client);\n }\n\n return status === ProviderStatus.READY;\n}\n", "export * from './evaluation';\nexport * from './query';\nexport * from './provider';\n// re-export the web-sdk so consumers can access that API from the react-sdk\nexport * from '@openfeature/web-sdk';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["ProviderEvents", "ProviderStatus", "useEffect", "useState", "suspendUntilReady", "React", "React", "ProviderEvents", "ProviderStatus", "useState", "useEffect", "ProviderEvents", "React", "ProviderStatus", "ProviderStatus"]
|
|
7
7
|
}
|