@featureflare/react 0.0.25 → 0.0.27
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 +74 -3
- package/dist/index.cjs +182 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -13
- package/dist/index.d.ts +33 -13
- package/dist/index.js +184 -86
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,15 @@ export function App() {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<FeatureFlareProvider
|
|
41
|
+
<FeatureFlareProvider
|
|
42
|
+
config={{
|
|
43
|
+
...config,
|
|
44
|
+
bootstrap: {
|
|
45
|
+
flags: { 'new-nav': true }
|
|
46
|
+
}
|
|
47
|
+
}}
|
|
48
|
+
initialUser={{ id: 'user-123', key: 'user-123' }}
|
|
49
|
+
>
|
|
42
50
|
<FlagsBootstrap />
|
|
43
51
|
{/* app */}
|
|
44
52
|
</FeatureFlareProvider>
|
|
@@ -49,10 +57,10 @@ export function App() {
|
|
|
49
57
|
### Read One Flag
|
|
50
58
|
|
|
51
59
|
```typescript
|
|
52
|
-
import {
|
|
60
|
+
import { useFlag } from '@featureflare/react';
|
|
53
61
|
|
|
54
62
|
export function NewNav() {
|
|
55
|
-
const { value, loading, error } =
|
|
63
|
+
const { value, loading, error } = useFlag('new-nav', false);
|
|
56
64
|
|
|
57
65
|
if (loading) return <div>Loading...</div>;
|
|
58
66
|
if (error) return <div>Error: {error}</div>;
|
|
@@ -61,6 +69,58 @@ export function NewNav() {
|
|
|
61
69
|
}
|
|
62
70
|
```
|
|
63
71
|
|
|
72
|
+
### SSR/HTML Bootstrap (anti-flicker working flow)
|
|
73
|
+
|
|
74
|
+
Server-side (example in Next.js `getServerSideProps`):
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { FeatureFlareClient } from '@featureflare/sdk-js';
|
|
78
|
+
|
|
79
|
+
export async function getServerSideProps() {
|
|
80
|
+
const user = { id: 'user-123', key: 'user-123' };
|
|
81
|
+
const sdk = new FeatureFlareClient({
|
|
82
|
+
apiBaseUrl: process.env.FEATUREFLARE_API_BASE_URL,
|
|
83
|
+
sdkKey: process.env.FEATUREFLARE_SERVER_SDK_KEY
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const nav = await sdk.bool('new-nav', user, false);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
props: {
|
|
90
|
+
user,
|
|
91
|
+
ffBootstrap: {
|
|
92
|
+
flags: { 'new-nav': nav }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Client-side provider wiring:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { FeatureFlareProvider, resolveFeatureFlareBrowserConfig } from '@featureflare/react';
|
|
103
|
+
|
|
104
|
+
export default function Page({ user, ffBootstrap }) {
|
|
105
|
+
const config = resolveFeatureFlareBrowserConfig();
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<FeatureFlareProvider
|
|
109
|
+
config={{
|
|
110
|
+
...config,
|
|
111
|
+
bootstrap: ffBootstrap
|
|
112
|
+
}}
|
|
113
|
+
initialUser={user}
|
|
114
|
+
>
|
|
115
|
+
{/* First render uses bootstrap synchronously; no loading flicker for these flags */}
|
|
116
|
+
<App />
|
|
117
|
+
</FeatureFlareProvider>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For non-SSR apps, inject a bootstrap JSON payload into HTML before app startup and pass it to `config.bootstrap` the same way.
|
|
123
|
+
|
|
64
124
|
## API
|
|
65
125
|
|
|
66
126
|
### `FeatureFlareProvider`
|
|
@@ -93,6 +153,7 @@ Returns:
|
|
|
93
153
|
|
|
94
154
|
Signatures:
|
|
95
155
|
|
|
156
|
+
- `useFlags(keys: string[], defaultValue?: boolean)` → `{ values, loading, errors }`
|
|
96
157
|
- `useFlags(input?: { user?: FeatureFlareUserPayload; defaultValue?: boolean; refreshIntervalMs?: number; hiddenRefreshIntervalMs?: number; pauseWhenHidden?: boolean; enabled?: boolean })`
|
|
97
158
|
- `useFlags(defaultValue?: boolean, options?: { refreshIntervalMs?: number; hiddenRefreshIntervalMs?: number; pauseWhenHidden?: boolean; enabled?: boolean })`
|
|
98
159
|
|
|
@@ -102,6 +163,14 @@ Returns:
|
|
|
102
163
|
- `loading: boolean`
|
|
103
164
|
- `error: string | null`
|
|
104
165
|
|
|
166
|
+
### `useFlag(key, defaultValue?)`
|
|
167
|
+
|
|
168
|
+
Selector-based single-flag subscription. Components only re-render when that flag changes.
|
|
169
|
+
|
|
170
|
+
### `useFlagDiagnostics(key)`
|
|
171
|
+
|
|
172
|
+
Returns per-flag runtime diagnostics (source, stale state, cache timestamps, latency).
|
|
173
|
+
|
|
105
174
|
Behavior:
|
|
106
175
|
|
|
107
176
|
- Immediate fetch on mount/user change.
|
|
@@ -117,3 +186,5 @@ Behavior:
|
|
|
117
186
|
## Security: Client-side flags are not authorization
|
|
118
187
|
|
|
119
188
|
Client keys can be extracted from your frontend bundle. **Never gate truly sensitive operations solely with client-evaluated flags**—enforce authorization on your backend.
|
|
189
|
+
- `config.bootstrap?: { flags, killSwitches }` for SSR/HTML bootstrap to avoid first-render flicker
|
|
190
|
+
- `config.timeoutMs | maxRetries | backoffMs | jitter | cacheTtlMs | staleTtlMs | realtime` are forwarded to the SDK client
|
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,8 @@ __export(index_exports, {
|
|
|
36
36
|
useBoolFlags: () => useBoolFlags,
|
|
37
37
|
useFeatureFlareContext: () => useFeatureFlareContext,
|
|
38
38
|
useFeatureFlareUser: () => useFeatureFlareUser,
|
|
39
|
+
useFlag: () => useFlag,
|
|
40
|
+
useFlagDiagnostics: () => useFlagDiagnostics,
|
|
39
41
|
useFlags: () => useFlags
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -70,6 +72,29 @@ function normalizeSubscriptionOptions(options) {
|
|
|
70
72
|
enabled: options?.enabled ?? true
|
|
71
73
|
};
|
|
72
74
|
}
|
|
75
|
+
function flagsToMap(flags) {
|
|
76
|
+
const map = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const flag of flags) {
|
|
78
|
+
map.set(flag.key, flag.value);
|
|
79
|
+
}
|
|
80
|
+
return map;
|
|
81
|
+
}
|
|
82
|
+
function diffFlagKeys(prev, next) {
|
|
83
|
+
const changed = /* @__PURE__ */ new Set();
|
|
84
|
+
const prevMap = flagsToMap(prev);
|
|
85
|
+
const nextMap = flagsToMap(next);
|
|
86
|
+
for (const [key, value] of prevMap.entries()) {
|
|
87
|
+
if (!nextMap.has(key) || nextMap.get(key) !== value) {
|
|
88
|
+
changed.add(key);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const [key, value] of nextMap.entries()) {
|
|
92
|
+
if (!prevMap.has(key) || prevMap.get(key) !== value) {
|
|
93
|
+
changed.add(key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return changed;
|
|
97
|
+
}
|
|
73
98
|
function createFlagsStore(client, getUser) {
|
|
74
99
|
const entries = /* @__PURE__ */ new Map();
|
|
75
100
|
let nextSubscriberId = 1;
|
|
@@ -78,10 +103,11 @@ function createFlagsStore(client, getUser) {
|
|
|
78
103
|
const key = defaultValue ? "1" : "0";
|
|
79
104
|
const existing = entries.get(key);
|
|
80
105
|
if (existing) return existing;
|
|
106
|
+
const cached = client.getCachedFlags();
|
|
81
107
|
const created = {
|
|
82
108
|
defaultValue,
|
|
83
|
-
snapshot: { flags:
|
|
84
|
-
listeners: /* @__PURE__ */ new
|
|
109
|
+
snapshot: { flags: cached.flags, loading: !cached.hasData, error: null },
|
|
110
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
85
111
|
subscribers: /* @__PURE__ */ new Map(),
|
|
86
112
|
timer: null,
|
|
87
113
|
inFlight: false
|
|
@@ -89,8 +115,12 @@ function createFlagsStore(client, getUser) {
|
|
|
89
115
|
entries.set(key, created);
|
|
90
116
|
return created;
|
|
91
117
|
};
|
|
92
|
-
const emit = (entry) => {
|
|
93
|
-
for (const listener of entry.listeners)
|
|
118
|
+
const emit = (entry, changedKeys = null) => {
|
|
119
|
+
for (const { listener, flagKey } of entry.listeners.values()) {
|
|
120
|
+
if (!flagKey || changedKeys === null || changedKeys.has(flagKey)) {
|
|
121
|
+
listener();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
94
124
|
};
|
|
95
125
|
const getEffectiveOptions = (entry) => {
|
|
96
126
|
const active = [...entry.subscribers.values()].filter((s) => s.enabled);
|
|
@@ -136,13 +166,17 @@ function createFlagsStore(client, getUser) {
|
|
|
136
166
|
if (entry.inFlight) return;
|
|
137
167
|
entry.inFlight = true;
|
|
138
168
|
try {
|
|
169
|
+
const previousFlags = entry.snapshot.flags;
|
|
139
170
|
const flags = await client.flags(getUser(), defaultValue);
|
|
171
|
+
const changed = diffFlagKeys(previousFlags, flags);
|
|
140
172
|
entry.snapshot = { flags, loading: false, error: null };
|
|
141
|
-
|
|
173
|
+
if (changed.size > 0 || previousFlags.length === 0) {
|
|
174
|
+
emit(entry, changed);
|
|
175
|
+
}
|
|
142
176
|
} catch (error) {
|
|
143
177
|
const message = error instanceof Error ? error.message : String(error);
|
|
144
178
|
entry.snapshot = { ...entry.snapshot, loading: false, error: message };
|
|
145
|
-
emit(entry);
|
|
179
|
+
emit(entry, null);
|
|
146
180
|
} finally {
|
|
147
181
|
entry.inFlight = false;
|
|
148
182
|
schedule(entry);
|
|
@@ -151,14 +185,14 @@ function createFlagsStore(client, getUser) {
|
|
|
151
185
|
const refreshNow = (defaultValue) => {
|
|
152
186
|
const entry = getEntry(defaultValue);
|
|
153
187
|
entry.snapshot = { ...entry.snapshot, loading: true, error: null };
|
|
154
|
-
emit(entry);
|
|
188
|
+
emit(entry, null);
|
|
155
189
|
void refresh(defaultValue, true);
|
|
156
190
|
};
|
|
157
|
-
const subscribe = (defaultValue, listener, options) => {
|
|
191
|
+
const subscribe = (defaultValue, listener, options, flagKey) => {
|
|
158
192
|
const entry = getEntry(defaultValue);
|
|
159
193
|
const subscriberId = nextSubscriberId;
|
|
160
194
|
nextSubscriberId += 1;
|
|
161
|
-
entry.listeners.
|
|
195
|
+
entry.listeners.set(subscriberId, { listener, flagKey });
|
|
162
196
|
entry.subscribers.set(subscriberId, normalizeSubscriptionOptions(options));
|
|
163
197
|
const effective = getEffectiveOptions(entry);
|
|
164
198
|
if (effective.enabled && !entry.inFlight && entry.snapshot.loading) {
|
|
@@ -167,7 +201,7 @@ function createFlagsStore(client, getUser) {
|
|
|
167
201
|
schedule(entry);
|
|
168
202
|
}
|
|
169
203
|
return () => {
|
|
170
|
-
entry.listeners.delete(
|
|
204
|
+
entry.listeners.delete(subscriberId);
|
|
171
205
|
entry.subscribers.delete(subscriberId);
|
|
172
206
|
schedule(entry);
|
|
173
207
|
};
|
|
@@ -175,7 +209,7 @@ function createFlagsStore(client, getUser) {
|
|
|
175
209
|
const updateUser = () => {
|
|
176
210
|
for (const entry of entries.values()) {
|
|
177
211
|
entry.snapshot = { ...entry.snapshot, loading: true, error: null };
|
|
178
|
-
emit(entry);
|
|
212
|
+
emit(entry, null);
|
|
179
213
|
void refresh(entry.defaultValue);
|
|
180
214
|
}
|
|
181
215
|
};
|
|
@@ -187,10 +221,28 @@ function createFlagsStore(client, getUser) {
|
|
|
187
221
|
void refresh(entry.defaultValue);
|
|
188
222
|
}
|
|
189
223
|
};
|
|
224
|
+
const unsubscribeClientUpdate = typeof client.on === "function" ? client.on(
|
|
225
|
+
"update",
|
|
226
|
+
({ changedKeys }) => {
|
|
227
|
+
const changedSet = new Set(changedKeys);
|
|
228
|
+
for (const entry of entries.values()) {
|
|
229
|
+
const previous = entry.snapshot.flags;
|
|
230
|
+
const next = client.getCachedFlags().flags;
|
|
231
|
+
const diff = diffFlagKeys(previous, next);
|
|
232
|
+
if (diff.size === 0) continue;
|
|
233
|
+
const intersects = [...diff].some((key) => changedSet.has(key));
|
|
234
|
+
if (!intersects && changedSet.size > 0) continue;
|
|
235
|
+
entry.snapshot = { ...entry.snapshot, flags: next, loading: false, error: null };
|
|
236
|
+
emit(entry, diff);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
) : () => {
|
|
240
|
+
};
|
|
190
241
|
if (typeof document !== "undefined") {
|
|
191
242
|
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
192
243
|
}
|
|
193
244
|
const dispose = () => {
|
|
245
|
+
unsubscribeClientUpdate();
|
|
194
246
|
if (typeof document !== "undefined") {
|
|
195
247
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
196
248
|
}
|
|
@@ -209,7 +261,12 @@ function createFlagsStore(client, getUser) {
|
|
|
209
261
|
return getEntry(defaultValue).snapshot;
|
|
210
262
|
},
|
|
211
263
|
refreshNow,
|
|
212
|
-
|
|
264
|
+
subscribeAll(defaultValue, listener, options) {
|
|
265
|
+
return subscribe(defaultValue, listener, options);
|
|
266
|
+
},
|
|
267
|
+
subscribeFlag(flagKey, defaultValue, listener, options) {
|
|
268
|
+
return subscribe(defaultValue, listener, options, flagKey);
|
|
269
|
+
},
|
|
213
270
|
updateUser,
|
|
214
271
|
dispose
|
|
215
272
|
};
|
|
@@ -228,13 +285,33 @@ function FeatureFlareProvider(props) {
|
|
|
228
285
|
apiBaseUrl: props.config.apiBaseUrl,
|
|
229
286
|
sdkKey: props.config.sdkKey,
|
|
230
287
|
projectKey: props.config.projectKey,
|
|
231
|
-
envKey: props.config.envKey
|
|
288
|
+
envKey: props.config.envKey,
|
|
289
|
+
timeoutMs: props.config.timeoutMs,
|
|
290
|
+
maxRetries: props.config.maxRetries,
|
|
291
|
+
backoffMs: props.config.backoffMs,
|
|
292
|
+
jitter: props.config.jitter,
|
|
293
|
+
cacheTtlMs: props.config.cacheTtlMs,
|
|
294
|
+
staleTtlMs: props.config.staleTtlMs,
|
|
295
|
+
bootstrap: props.config.bootstrap,
|
|
296
|
+
persistentCache: props.config.persistentCache,
|
|
297
|
+
onMetric: props.config.onMetric,
|
|
298
|
+
realtime: props.config.realtime
|
|
232
299
|
});
|
|
233
300
|
}, [
|
|
234
301
|
props.config.apiBaseUrl,
|
|
302
|
+
props.config.backoffMs,
|
|
303
|
+
props.config.bootstrap,
|
|
304
|
+
props.config.cacheTtlMs,
|
|
235
305
|
props.config.envKey,
|
|
306
|
+
props.config.jitter,
|
|
307
|
+
props.config.maxRetries,
|
|
308
|
+
props.config.onMetric,
|
|
309
|
+
props.config.persistentCache,
|
|
236
310
|
props.config.projectKey,
|
|
237
|
-
props.config.
|
|
311
|
+
props.config.realtime,
|
|
312
|
+
props.config.sdkKey,
|
|
313
|
+
props.config.staleTtlMs,
|
|
314
|
+
props.config.timeoutMs
|
|
238
315
|
]);
|
|
239
316
|
const flagsStore = (0, import_react.useMemo)(() => createFlagsStore(client, () => userRef.current), [client]);
|
|
240
317
|
(0, import_react.useEffect)(() => {
|
|
@@ -244,8 +321,9 @@ function FeatureFlareProvider(props) {
|
|
|
244
321
|
(0, import_react.useEffect)(() => {
|
|
245
322
|
return () => {
|
|
246
323
|
flagsStore.dispose();
|
|
324
|
+
client.dispose();
|
|
247
325
|
};
|
|
248
|
-
}, [flagsStore]);
|
|
326
|
+
}, [client, flagsStore]);
|
|
249
327
|
const value = (0, import_react.useMemo)(
|
|
250
328
|
() => ({
|
|
251
329
|
client,
|
|
@@ -253,7 +331,9 @@ function FeatureFlareProvider(props) {
|
|
|
253
331
|
setUser,
|
|
254
332
|
getFlagsState: flagsStore.getState,
|
|
255
333
|
refreshFlags: flagsStore.refreshNow,
|
|
256
|
-
subscribeFlags: flagsStore.
|
|
334
|
+
subscribeFlags: flagsStore.subscribeAll,
|
|
335
|
+
subscribeFlag: (flagKey, defaultValue, listener, options) => flagsStore.subscribeFlag(flagKey, defaultValue, listener, options),
|
|
336
|
+
getFlagDiagnostics: (flagKey) => client.getFlagDiagnostics(flagKey)
|
|
257
337
|
}),
|
|
258
338
|
[client, flagsStore, setUser, user]
|
|
259
339
|
);
|
|
@@ -277,83 +357,75 @@ function userFingerprint(user) {
|
|
|
277
357
|
meta: user.meta ?? {}
|
|
278
358
|
});
|
|
279
359
|
}
|
|
360
|
+
function mapFlags(flags) {
|
|
361
|
+
const values = {};
|
|
362
|
+
for (const flag of flags) {
|
|
363
|
+
values[flag.key] = flag.value;
|
|
364
|
+
}
|
|
365
|
+
return values;
|
|
366
|
+
}
|
|
280
367
|
function useFeatureFlareUser() {
|
|
281
368
|
const { user, setUser } = useFeatureFlareContext();
|
|
282
369
|
return [user, setUser];
|
|
283
370
|
}
|
|
284
|
-
function
|
|
285
|
-
const {
|
|
286
|
-
const [state, setState] = (0, import_react2.useState)({ value: defaultValue, loading: true, error: null });
|
|
287
|
-
const userId = user.id ?? user.key ?? "";
|
|
288
|
-
const key = (0, import_react2.useMemo)(() => `${flagKey}:${userId}`, [flagKey, userId]);
|
|
289
|
-
const lastKey = (0, import_react2.useRef)("");
|
|
371
|
+
function useFlag(flagKey, defaultValue = false) {
|
|
372
|
+
const { subscribeFlag, getFlagsState, refreshFlags } = useFeatureFlareContext();
|
|
290
373
|
(0, import_react2.useEffect)(() => {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
305
|
-
setState({ value: defaultValue, loading: false, error: msg });
|
|
306
|
-
}
|
|
307
|
-
})();
|
|
308
|
-
return () => {
|
|
309
|
-
cancelled = true;
|
|
310
|
-
};
|
|
311
|
-
}, [client, defaultValue, flagKey, key, user]);
|
|
312
|
-
return state;
|
|
374
|
+
refreshFlags(defaultValue);
|
|
375
|
+
}, [defaultValue, refreshFlags]);
|
|
376
|
+
const subscribe = (0, import_react2.useMemo)(
|
|
377
|
+
() => (onStoreChange) => subscribeFlag(flagKey, defaultValue, onStoreChange),
|
|
378
|
+
[defaultValue, flagKey, subscribeFlag]
|
|
379
|
+
);
|
|
380
|
+
const state = (0, import_react2.useSyncExternalStore)(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);
|
|
381
|
+
const value = state.flags.find((entry) => entry.key === flagKey)?.value ?? defaultValue;
|
|
382
|
+
return {
|
|
383
|
+
value,
|
|
384
|
+
loading: state.loading,
|
|
385
|
+
error: state.error
|
|
386
|
+
};
|
|
313
387
|
}
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
const sortedKeys = (0, import_react2.useMemo)(() => [...flagKeys].map((k) => k.trim()).filter(Boolean).sort(), [flagKeys]);
|
|
317
|
-
const userId = user.id ?? user.key ?? "";
|
|
318
|
-
const key = (0, import_react2.useMemo)(() => `${sortedKeys.join(",")}:${userId}`, [sortedKeys, userId]);
|
|
319
|
-
const [state, setState] = (0, import_react2.useState)({ values: {}, loading: true, errors: {} });
|
|
320
|
-
const lastKey = (0, import_react2.useRef)("");
|
|
321
|
-
(0, import_react2.useEffect)(() => {
|
|
322
|
-
let cancelled = false;
|
|
323
|
-
const nextKey = key;
|
|
324
|
-
lastKey.current = nextKey;
|
|
325
|
-
setState({ values: {}, loading: true, errors: {} });
|
|
326
|
-
(async () => {
|
|
327
|
-
const values = {};
|
|
328
|
-
const errors = {};
|
|
329
|
-
await Promise.all(
|
|
330
|
-
sortedKeys.map(async (flagKey) => {
|
|
331
|
-
try {
|
|
332
|
-
values[flagKey] = await client.bool(flagKey, user, defaultValue);
|
|
333
|
-
} catch (e) {
|
|
334
|
-
values[flagKey] = defaultValue;
|
|
335
|
-
errors[flagKey] = e instanceof Error ? e.message : String(e);
|
|
336
|
-
}
|
|
337
|
-
})
|
|
338
|
-
);
|
|
339
|
-
if (cancelled) return;
|
|
340
|
-
if (lastKey.current !== nextKey) return;
|
|
341
|
-
setState({ values, loading: false, errors });
|
|
342
|
-
})();
|
|
343
|
-
return () => {
|
|
344
|
-
cancelled = true;
|
|
345
|
-
};
|
|
346
|
-
}, [client, defaultValue, key, sortedKeys, user]);
|
|
347
|
-
return state;
|
|
388
|
+
function useBoolFlag(flagKey, defaultValue = false) {
|
|
389
|
+
return useFlag(flagKey, defaultValue);
|
|
348
390
|
}
|
|
349
|
-
function useFlags(
|
|
350
|
-
const { subscribeFlags, getFlagsState, refreshFlags, setUser } = useFeatureFlareContext();
|
|
391
|
+
function useFlags(defaultValueOrInputOrKeys = false, optionsOrDefaultValue = {}) {
|
|
392
|
+
const { subscribeFlags, subscribeFlag, getFlagsState, refreshFlags, setUser } = useFeatureFlareContext();
|
|
393
|
+
if (Array.isArray(defaultValueOrInputOrKeys)) {
|
|
394
|
+
const keys = [...defaultValueOrInputOrKeys].map((key) => key.trim()).filter(Boolean);
|
|
395
|
+
const defaultValue2 = typeof optionsOrDefaultValue === "boolean" ? optionsOrDefaultValue : false;
|
|
396
|
+
(0, import_react2.useEffect)(() => {
|
|
397
|
+
refreshFlags(defaultValue2);
|
|
398
|
+
}, [defaultValue2, refreshFlags]);
|
|
399
|
+
const subscribe2 = (0, import_react2.useMemo)(
|
|
400
|
+
() => (onStoreChange) => {
|
|
401
|
+
const unsubs = keys.map((key) => subscribeFlag(key, defaultValue2, onStoreChange));
|
|
402
|
+
return () => {
|
|
403
|
+
for (const unsub of unsubs) unsub();
|
|
404
|
+
};
|
|
405
|
+
},
|
|
406
|
+
[defaultValue2, keys, subscribeFlag]
|
|
407
|
+
);
|
|
408
|
+
const state = (0, import_react2.useSyncExternalStore)(subscribe2, () => getFlagsState(defaultValue2), () => EMPTY_FLAGS_STATE);
|
|
409
|
+
const values = mapFlags(state.flags);
|
|
410
|
+
const filtered = {};
|
|
411
|
+
for (const key of keys) {
|
|
412
|
+
filtered[key] = values[key] ?? defaultValue2;
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
values: filtered,
|
|
416
|
+
loading: state.loading,
|
|
417
|
+
errors: state.error ? { __global: state.error } : {}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
351
420
|
const parsed = (0, import_react2.useMemo)(() => {
|
|
352
|
-
if (typeof
|
|
353
|
-
return {
|
|
421
|
+
if (typeof defaultValueOrInputOrKeys === "boolean") {
|
|
422
|
+
return {
|
|
423
|
+
...typeof optionsOrDefaultValue === "object" && optionsOrDefaultValue !== null ? optionsOrDefaultValue : {},
|
|
424
|
+
defaultValue: defaultValueOrInputOrKeys
|
|
425
|
+
};
|
|
354
426
|
}
|
|
355
|
-
return
|
|
356
|
-
}, [
|
|
427
|
+
return defaultValueOrInputOrKeys ?? {};
|
|
428
|
+
}, [defaultValueOrInputOrKeys, optionsOrDefaultValue]);
|
|
357
429
|
const defaultValue = parsed.defaultValue ?? false;
|
|
358
430
|
const normalizedOptions = (0, import_react2.useMemo)(
|
|
359
431
|
() => ({
|
|
@@ -382,6 +454,30 @@ function useFlags(defaultValueOrInput = false, options = {}) {
|
|
|
382
454
|
);
|
|
383
455
|
return (0, import_react2.useSyncExternalStore)(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);
|
|
384
456
|
}
|
|
457
|
+
function useBoolFlags(flagKeys, defaultValue = false) {
|
|
458
|
+
return useFlags(flagKeys, defaultValue);
|
|
459
|
+
}
|
|
460
|
+
function useFlagDiagnostics(flagKey, defaultValue = false) {
|
|
461
|
+
const { getFlagDiagnostics, subscribeFlag } = useFeatureFlareContext();
|
|
462
|
+
const subscribe = (0, import_react2.useMemo)(
|
|
463
|
+
() => (onStoreChange) => subscribeFlag(flagKey, defaultValue, onStoreChange),
|
|
464
|
+
[defaultValue, flagKey, subscribeFlag]
|
|
465
|
+
);
|
|
466
|
+
const metadata = (0, import_react2.useSyncExternalStore)(
|
|
467
|
+
subscribe,
|
|
468
|
+
() => getFlagDiagnostics(flagKey),
|
|
469
|
+
() => null
|
|
470
|
+
);
|
|
471
|
+
return {
|
|
472
|
+
source: metadata?.source ?? "unknown",
|
|
473
|
+
reason: metadata?.reason ?? "unknown",
|
|
474
|
+
isStale: metadata?.isStale ?? false,
|
|
475
|
+
updatedAt: metadata?.updatedAt,
|
|
476
|
+
staleAt: metadata?.staleAt,
|
|
477
|
+
expiresAt: metadata?.expiresAt,
|
|
478
|
+
latencyMs: metadata?.latencyMs
|
|
479
|
+
};
|
|
480
|
+
}
|
|
385
481
|
// Annotate the CommonJS export names for ESM import in node:
|
|
386
482
|
0 && (module.exports = {
|
|
387
483
|
FeatureFlareProvider,
|
|
@@ -390,6 +486,8 @@ function useFlags(defaultValueOrInput = false, options = {}) {
|
|
|
390
486
|
useBoolFlags,
|
|
391
487
|
useFeatureFlareContext,
|
|
392
488
|
useFeatureFlareUser,
|
|
489
|
+
useFlag,
|
|
490
|
+
useFlagDiagnostics,
|
|
393
491
|
useFlags
|
|
394
492
|
});
|
|
395
493
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export * from './provider.js';\nexport * from './hooks.js';\nexport type { FeatureFlareUserPayload } from '@featureflare/sdk-js';\n","import React, { createContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { FeatureFlareClient, type FeatureFlareUserPayload } from '@featureflare/sdk-js';\n\nexport type FeatureFlareEnvironmentKey = 'development' | 'staging' | 'production';\n\nexport type FeatureFlareReactConfig = {\n /** Optional: explicit FeatureFlare API base URL. */\n apiBaseUrl?: string;\n /** Recommended: use a client key (featureflare_cli_...). */\n sdkKey?: string;\n /** Legacy/insecure browser mode: uses /api/v1/eval (no sdkKey). */\n projectKey?: string;\n envKey?: FeatureFlareEnvironmentKey | string;\n};\n\nexport function resolveFeatureFlareBrowserConfig(input?: {\n envKey?: FeatureFlareEnvironmentKey;\n apiBaseUrl?: string;\n}): FeatureFlareReactConfig {\n const explicitEnv = input?.envKey;\n const envFromVars =\n typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_ENV_KEY?.trim().toLowerCase() : '';\n\n const resolvedEnv: FeatureFlareEnvironmentKey | undefined =\n explicitEnv ??\n (envFromVars === 'development' || envFromVars === 'staging' || envFromVars === 'production'\n ? envFromVars\n : undefined);\n\n const apiBaseUrl =\n input?.apiBaseUrl ??\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_API_BASE_URL?.trim() : undefined);\n\n const sdkKeyDevelopment =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEVELOPMENT?.trim() : '') ||\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEV?.trim() : '') ||\n '';\n const sdkKeyStaging =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_STAGING?.trim() : '') || '';\n const sdkKeyProduction =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PRODUCTION?.trim() : '') ||\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PROD?.trim() : '') ||\n '';\n const sdkKeyDefault =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY?.trim() : '') || '';\n\n const sdkKey =\n (resolvedEnv === 'development' ? sdkKeyDevelopment : '') ||\n (resolvedEnv === 'staging' ? sdkKeyStaging : '') ||\n (resolvedEnv === 'production' ? sdkKeyProduction : '') ||\n sdkKeyDefault ||\n undefined;\n\n return {\n apiBaseUrl,\n envKey: resolvedEnv,\n sdkKey\n };\n}\n\ntype FeatureFlareContextValue = {\n client: FeatureFlareClient;\n user: FeatureFlareUserPayload;\n setUser: (next: FeatureFlareUserPayload) => void;\n getFlagsState: (defaultValue: boolean) => FlagsState;\n refreshFlags: (defaultValue: boolean) => void;\n subscribeFlags: (\n defaultValue: boolean,\n listener: () => void,\n options?: FlagsSubscriptionOptions\n ) => () => void;\n};\n\nexport type FlagsState = {\n flags: Array<{ key: string; value: boolean }>;\n loading: boolean;\n error: string | null;\n};\n\nexport type FlagsSubscriptionOptions = {\n refreshIntervalMs?: number;\n hiddenRefreshIntervalMs?: number;\n pauseWhenHidden?: boolean;\n enabled?: boolean;\n};\n\ntype NormalizedFlagsSubscriptionOptions = {\n refreshIntervalMs: number;\n hiddenRefreshIntervalMs: number;\n pauseWhenHidden: boolean;\n enabled: boolean;\n};\n\ntype FlagsStoreEntry = {\n defaultValue: boolean;\n snapshot: FlagsState;\n listeners: Set<() => void>;\n subscribers: Map<number, NormalizedFlagsSubscriptionOptions>;\n timer: ReturnType<typeof setTimeout> | null;\n inFlight: boolean;\n};\n\nfunction normalizeSubscriptionOptions(options?: FlagsSubscriptionOptions): NormalizedFlagsSubscriptionOptions {\n const refreshIntervalMs =\n Number.isFinite(options?.refreshIntervalMs) && (options?.refreshIntervalMs ?? 0) > 0\n ? Number(options?.refreshIntervalMs)\n : 10000;\n const hiddenRefreshIntervalMs =\n Number.isFinite(options?.hiddenRefreshIntervalMs) && (options?.hiddenRefreshIntervalMs ?? 0) > 0\n ? Number(options?.hiddenRefreshIntervalMs)\n : Math.max(refreshIntervalMs * 6, 60000);\n\n return {\n refreshIntervalMs,\n hiddenRefreshIntervalMs,\n pauseWhenHidden: options?.pauseWhenHidden ?? true,\n enabled: options?.enabled ?? true\n };\n}\n\nfunction createFlagsStore(client: FeatureFlareClient, getUser: () => FeatureFlareUserPayload) {\n const entries = new Map<string, FlagsStoreEntry>();\n let nextSubscriberId = 1;\n\n const isHidden = () => typeof document !== 'undefined' && document.visibilityState === 'hidden';\n\n const getEntry = (defaultValue: boolean): FlagsStoreEntry => {\n const key = defaultValue ? '1' : '0';\n const existing = entries.get(key);\n if (existing) return existing;\n const created: FlagsStoreEntry = {\n defaultValue,\n snapshot: { flags: [], loading: true, error: null },\n listeners: new Set(),\n subscribers: new Map(),\n timer: null,\n inFlight: false\n };\n entries.set(key, created);\n return created;\n };\n\n const emit = (entry: FlagsStoreEntry) => {\n for (const listener of entry.listeners) listener();\n };\n\n const getEffectiveOptions = (entry: FlagsStoreEntry) => {\n const active = [...entry.subscribers.values()].filter((s) => s.enabled);\n if (active.length === 0) {\n return { enabled: false as const, refreshIntervalMs: 0, hiddenRefreshIntervalMs: 0, pauseWhenHidden: true };\n }\n\n const refreshIntervalMs = active.reduce((min, s) => Math.min(min, s.refreshIntervalMs), Number.POSITIVE_INFINITY);\n const hiddenActive = active.filter((s) => !s.pauseWhenHidden);\n const hiddenRefreshIntervalMs =\n hiddenActive.length > 0\n ? hiddenActive.reduce((min, s) => Math.min(min, s.hiddenRefreshIntervalMs), Number.POSITIVE_INFINITY)\n : 0;\n\n return {\n enabled: true as const,\n refreshIntervalMs: Number.isFinite(refreshIntervalMs) ? refreshIntervalMs : 10000,\n hiddenRefreshIntervalMs,\n pauseWhenHidden: hiddenActive.length === 0\n };\n };\n\n const schedule = (entry: FlagsStoreEntry) => {\n if (entry.timer !== null) {\n clearTimeout(entry.timer);\n entry.timer = null;\n }\n\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled) return;\n\n if (isHidden()) {\n if (effective.pauseWhenHidden) return;\n entry.timer = setTimeout(() => {\n void refresh(entry.defaultValue);\n }, effective.hiddenRefreshIntervalMs);\n return;\n }\n\n entry.timer = setTimeout(() => {\n void refresh(entry.defaultValue);\n }, effective.refreshIntervalMs);\n };\n\n const refresh = async (defaultValue: boolean, force = false) => {\n const entry = getEntry(defaultValue);\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled && !force) return;\n\n if (!force && isHidden() && effective.pauseWhenHidden) {\n schedule(entry);\n return;\n }\n\n if (entry.inFlight) return;\n entry.inFlight = true;\n\n try {\n const flags = await client.flags(getUser(), defaultValue);\n entry.snapshot = { flags, loading: false, error: null };\n emit(entry);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n entry.snapshot = { ...entry.snapshot, loading: false, error: message };\n emit(entry);\n } finally {\n entry.inFlight = false;\n schedule(entry);\n }\n };\n\n const refreshNow = (defaultValue: boolean) => {\n const entry = getEntry(defaultValue);\n entry.snapshot = { ...entry.snapshot, loading: true, error: null };\n emit(entry);\n void refresh(defaultValue, true);\n };\n\n const subscribe = (\n defaultValue: boolean,\n listener: () => void,\n options?: FlagsSubscriptionOptions\n ): (() => void) => {\n const entry = getEntry(defaultValue);\n const subscriberId = nextSubscriberId;\n nextSubscriberId += 1;\n\n entry.listeners.add(listener);\n entry.subscribers.set(subscriberId, normalizeSubscriptionOptions(options));\n\n const effective = getEffectiveOptions(entry);\n if (effective.enabled && !entry.inFlight && entry.snapshot.loading) {\n void refresh(defaultValue);\n } else {\n schedule(entry);\n }\n\n return () => {\n entry.listeners.delete(listener);\n entry.subscribers.delete(subscriberId);\n schedule(entry);\n };\n };\n\n const updateUser = () => {\n for (const entry of entries.values()) {\n entry.snapshot = { ...entry.snapshot, loading: true, error: null };\n emit(entry);\n void refresh(entry.defaultValue);\n }\n };\n\n const handleVisibilityChange = () => {\n if (isHidden()) return;\n for (const entry of entries.values()) {\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled) continue;\n void refresh(entry.defaultValue);\n }\n };\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', handleVisibilityChange);\n }\n\n const dispose = () => {\n if (typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n }\n for (const entry of entries.values()) {\n if (entry.timer !== null) {\n clearTimeout(entry.timer);\n }\n entry.timer = null;\n entry.listeners.clear();\n entry.subscribers.clear();\n }\n entries.clear();\n };\n\n return {\n getState(defaultValue: boolean): FlagsState {\n return getEntry(defaultValue).snapshot;\n },\n refreshNow,\n subscribe,\n updateUser,\n dispose\n };\n}\n\nconst FeatureFlareContext = createContext<FeatureFlareContextValue | null>(null);\n\nexport function FeatureFlareProvider(props: {\n config: FeatureFlareReactConfig;\n initialUser: FeatureFlareUserPayload;\n user?: FeatureFlareUserPayload;\n onUserChange?: (next: FeatureFlareUserPayload) => void;\n children: React.ReactNode;\n}) {\n if (props.user && !props.onUserChange) {\n throw new Error('FeatureFlareProvider: when providing `user`, also provide `onUserChange` (controlled mode).');\n }\n\n const [internalUser, setInternalUser] = useState<FeatureFlareUserPayload>(props.initialUser);\n const user = props.user ?? internalUser;\n const setUser = props.onUserChange ?? setInternalUser;\n const userRef = useRef<FeatureFlareUserPayload>(user);\n\n const client = useMemo(() => {\n return new FeatureFlareClient({\n apiBaseUrl: props.config.apiBaseUrl,\n sdkKey: props.config.sdkKey,\n projectKey: props.config.projectKey,\n envKey: props.config.envKey\n });\n }, [\n props.config.apiBaseUrl,\n props.config.envKey,\n props.config.projectKey,\n props.config.sdkKey\n ]);\n\n const flagsStore = useMemo(() => createFlagsStore(client, () => userRef.current), [client]);\n\n useEffect(() => {\n userRef.current = user;\n flagsStore.updateUser();\n }, [flagsStore, user]);\n\n useEffect(() => {\n return () => {\n flagsStore.dispose();\n };\n }, [flagsStore]);\n\n const value = useMemo(\n () => ({\n client,\n user,\n setUser,\n getFlagsState: flagsStore.getState,\n refreshFlags: flagsStore.refreshNow,\n subscribeFlags: flagsStore.subscribe\n }),\n [client, flagsStore, setUser, user]\n );\n return <FeatureFlareContext.Provider value={value}>{props.children}</FeatureFlareContext.Provider>;\n}\n\nexport function useFeatureFlareContext(): FeatureFlareContextValue {\n const ctx = React.useContext(FeatureFlareContext);\n if (!ctx) throw new Error('useFeatureFlareContext must be used within <FeatureFlareProvider>.');\n return ctx;\n}\n","import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport type { FeatureFlareUserPayload } from '@featureflare/sdk-js';\nimport { useFeatureFlareContext, type FlagsSubscriptionOptions } from './provider.js';\n\ntype BoolFlagState = {\n value: boolean;\n loading: boolean;\n error: string | null;\n};\n\ntype BoolFlagsState = {\n values: Record<string, boolean>;\n loading: boolean;\n errors: Record<string, string>;\n};\n\ntype FlagsState = {\n flags: Array<{ key: string; value: boolean }>;\n loading: boolean;\n error: string | null;\n};\n\ntype UseFlagsOptions = FlagsSubscriptionOptions;\n\ntype UseFlagsInput = UseFlagsOptions & {\n defaultValue?: boolean;\n user?: FeatureFlareUserPayload;\n};\n\nconst EMPTY_FLAGS_STATE: FlagsState = { flags: [], loading: true, error: null };\n\nfunction userFingerprint(user?: FeatureFlareUserPayload): string {\n if (!user) return '';\n return JSON.stringify({\n id: user.id ?? '',\n key: user.key ?? '',\n email: user.email ?? '',\n meta: user.meta ?? {}\n });\n}\n\nexport function useFeatureFlareUser(): [FeatureFlareUserPayload, (next: FeatureFlareUserPayload) => void] {\n const { user, setUser } = useFeatureFlareContext();\n return [user, setUser];\n}\n\nexport function useBoolFlag(flagKey: string, defaultValue = false): BoolFlagState {\n const { client, user } = useFeatureFlareContext();\n const [state, setState] = useState<BoolFlagState>({ value: defaultValue, loading: true, error: null });\n const userId = user.id ?? user.key ?? '';\n const key = useMemo(() => `${flagKey}:${userId}`, [flagKey, userId]);\n const lastKey = useRef<string>('');\n\n useEffect(() => {\n let cancelled = false;\n const nextKey = key;\n lastKey.current = nextKey;\n setState((s) => ({ ...s, loading: true, error: null }));\n\n (async () => {\n try {\n const v = await client.bool(flagKey, user, defaultValue);\n if (cancelled) return;\n if (lastKey.current !== nextKey) return;\n setState({ value: v, loading: false, error: null });\n } catch (e) {\n if (cancelled) return;\n if (lastKey.current !== nextKey) return;\n const msg = e instanceof Error ? e.message : String(e);\n setState({ value: defaultValue, loading: false, error: msg });\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [client, defaultValue, flagKey, key, user]);\n\n return state;\n}\n\nexport function useBoolFlags(flagKeys: string[], defaultValue = false): BoolFlagsState {\n const { client, user } = useFeatureFlareContext();\n const sortedKeys = useMemo(() => [...flagKeys].map((k) => k.trim()).filter(Boolean).sort(), [flagKeys]);\n const userId = user.id ?? user.key ?? '';\n const key = useMemo(() => `${sortedKeys.join(',')}:${userId}`, [sortedKeys, userId]);\n const [state, setState] = useState<BoolFlagsState>({ values: {}, loading: true, errors: {} });\n const lastKey = useRef<string>('');\n\n useEffect(() => {\n let cancelled = false;\n const nextKey = key;\n lastKey.current = nextKey;\n setState({ values: {}, loading: true, errors: {} });\n\n (async () => {\n const values: Record<string, boolean> = {};\n const errors: Record<string, string> = {};\n await Promise.all(\n sortedKeys.map(async (flagKey) => {\n try {\n values[flagKey] = await client.bool(flagKey, user, defaultValue);\n } catch (e) {\n values[flagKey] = defaultValue;\n errors[flagKey] = e instanceof Error ? e.message : String(e);\n }\n })\n );\n\n if (cancelled) return;\n if (lastKey.current !== nextKey) return;\n setState({ values, loading: false, errors });\n })();\n\n return () => {\n cancelled = true;\n };\n }, [client, defaultValue, key, sortedKeys, user]);\n\n return state;\n}\n\nexport function useFlags(input?: UseFlagsInput): FlagsState;\nexport function useFlags(defaultValue?: boolean, options?: UseFlagsOptions): FlagsState;\nexport function useFlags(defaultValueOrInput: boolean | UseFlagsInput = false, options: UseFlagsOptions = {}): FlagsState {\n const { subscribeFlags, getFlagsState, refreshFlags, setUser } = useFeatureFlareContext();\n\n const parsed = useMemo<UseFlagsInput>(() => {\n if (typeof defaultValueOrInput === 'boolean') {\n return { ...options, defaultValue: defaultValueOrInput };\n }\n return defaultValueOrInput ?? {};\n }, [defaultValueOrInput, options]);\n\n const defaultValue = parsed.defaultValue ?? false;\n\n const normalizedOptions = useMemo<UseFlagsOptions>(\n () => ({\n enabled: parsed.enabled ?? true,\n refreshIntervalMs: parsed.refreshIntervalMs,\n hiddenRefreshIntervalMs: parsed.hiddenRefreshIntervalMs,\n pauseWhenHidden: parsed.pauseWhenHidden ?? true\n }),\n [parsed.enabled, parsed.hiddenRefreshIntervalMs, parsed.pauseWhenHidden, parsed.refreshIntervalMs]\n );\n\n const appliedUserRef = useRef<string>('');\n const parsedUserFingerprint = useMemo(() => userFingerprint(parsed.user), [parsed.user]);\n\n useEffect(() => {\n if (!parsed.user) return;\n if (appliedUserRef.current === parsedUserFingerprint) return;\n setUser(parsed.user);\n appliedUserRef.current = parsedUserFingerprint;\n }, [parsed.user, parsedUserFingerprint, setUser]);\n\n useEffect(() => {\n if (normalizedOptions.enabled === false) return;\n refreshFlags(defaultValue);\n }, [defaultValue, normalizedOptions.enabled, parsedUserFingerprint, refreshFlags]);\n\n const subscribe = useMemo(\n () =>\n (onStoreChange: () => void) =>\n subscribeFlags(defaultValue, onStoreChange, normalizedOptions),\n [defaultValue, normalizedOptions, subscribeFlags]\n );\n\n return useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);\n}\n"],"mappings":"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","names":["React","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export * from './provider.js';\nexport * from './hooks.js';\nexport type { FeatureFlareUserPayload } from '@featureflare/sdk-js';\n","import React, { createContext, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n FeatureFlareClient,\n type FeatureFlareBootstrapPayload,\n type FeatureFlareEvaluationMetadata,\n type FeatureFlareMetricName,\n type FeatureFlareMetricTags,\n type FeatureFlarePersistentCacheAdapter,\n type FeatureFlareUserPayload\n} from '@featureflare/sdk-js';\n\nexport type FeatureFlareEnvironmentKey = 'development' | 'staging' | 'production';\n\nexport type FeatureFlareReactConfig = {\n /** Optional: explicit FeatureFlare API base URL. */\n apiBaseUrl?: string;\n /** Recommended: use a client key (featureflare_cli_...). */\n sdkKey?: string;\n /** Legacy/insecure browser mode: uses /api/v1/eval (no sdkKey). */\n projectKey?: string;\n envKey?: FeatureFlareEnvironmentKey | string;\n timeoutMs?: number;\n maxRetries?: number;\n backoffMs?: number;\n jitter?: number;\n cacheTtlMs?: number;\n staleTtlMs?: number;\n bootstrap?: FeatureFlareBootstrapPayload;\n persistentCache?: FeatureFlarePersistentCacheAdapter;\n onMetric?: (metricName: FeatureFlareMetricName, value: number, tags?: FeatureFlareMetricTags) => void;\n realtime?: {\n enabled?: boolean;\n pollingIntervalMs?: number;\n ssePath?: string;\n };\n};\n\nexport function resolveFeatureFlareBrowserConfig(input?: {\n envKey?: FeatureFlareEnvironmentKey;\n apiBaseUrl?: string;\n}): FeatureFlareReactConfig {\n const explicitEnv = input?.envKey;\n const envFromVars =\n typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_ENV_KEY?.trim().toLowerCase() : '';\n\n const resolvedEnv: FeatureFlareEnvironmentKey | undefined =\n explicitEnv ??\n (envFromVars === 'development' || envFromVars === 'staging' || envFromVars === 'production'\n ? envFromVars\n : undefined);\n\n const apiBaseUrl =\n input?.apiBaseUrl ??\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_API_BASE_URL?.trim() : undefined);\n\n const sdkKeyDevelopment =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEVELOPMENT?.trim() : '') ||\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEV?.trim() : '') ||\n '';\n const sdkKeyStaging =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_STAGING?.trim() : '') || '';\n const sdkKeyProduction =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PRODUCTION?.trim() : '') ||\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PROD?.trim() : '') ||\n '';\n const sdkKeyDefault =\n (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY?.trim() : '') || '';\n\n const sdkKey =\n (resolvedEnv === 'development' ? sdkKeyDevelopment : '') ||\n (resolvedEnv === 'staging' ? sdkKeyStaging : '') ||\n (resolvedEnv === 'production' ? sdkKeyProduction : '') ||\n sdkKeyDefault ||\n undefined;\n\n return {\n apiBaseUrl,\n envKey: resolvedEnv,\n sdkKey\n };\n}\n\ntype FeatureFlareContextValue = {\n client: FeatureFlareClient;\n user: FeatureFlareUserPayload;\n setUser: (next: FeatureFlareUserPayload) => void;\n getFlagsState: (defaultValue: boolean) => FlagsState;\n refreshFlags: (defaultValue: boolean) => void;\n subscribeFlags: (\n defaultValue: boolean,\n listener: () => void,\n options?: FlagsSubscriptionOptions\n ) => () => void;\n subscribeFlag: (\n flagKey: string,\n defaultValue: boolean,\n listener: () => void,\n options?: FlagsSubscriptionOptions\n ) => () => void;\n getFlagDiagnostics: (flagKey: string) => FeatureFlareEvaluationMetadata | null;\n};\n\nexport type FlagsState = {\n flags: Array<{ key: string; value: boolean }>;\n loading: boolean;\n error: string | null;\n};\n\nexport type FlagsSubscriptionOptions = {\n refreshIntervalMs?: number;\n hiddenRefreshIntervalMs?: number;\n pauseWhenHidden?: boolean;\n enabled?: boolean;\n};\n\ntype NormalizedFlagsSubscriptionOptions = {\n refreshIntervalMs: number;\n hiddenRefreshIntervalMs: number;\n pauseWhenHidden: boolean;\n enabled: boolean;\n};\n\ntype ListenerEntry = {\n listener: () => void;\n flagKey?: string;\n};\n\ntype FlagsStoreEntry = {\n defaultValue: boolean;\n snapshot: FlagsState;\n listeners: Map<number, ListenerEntry>;\n subscribers: Map<number, NormalizedFlagsSubscriptionOptions>;\n timer: ReturnType<typeof setTimeout> | null;\n inFlight: boolean;\n};\n\nfunction normalizeSubscriptionOptions(options?: FlagsSubscriptionOptions): NormalizedFlagsSubscriptionOptions {\n const refreshIntervalMs =\n Number.isFinite(options?.refreshIntervalMs) && (options?.refreshIntervalMs ?? 0) > 0\n ? Number(options?.refreshIntervalMs)\n : 10000;\n const hiddenRefreshIntervalMs =\n Number.isFinite(options?.hiddenRefreshIntervalMs) && (options?.hiddenRefreshIntervalMs ?? 0) > 0\n ? Number(options?.hiddenRefreshIntervalMs)\n : Math.max(refreshIntervalMs * 6, 60000);\n\n return {\n refreshIntervalMs,\n hiddenRefreshIntervalMs,\n pauseWhenHidden: options?.pauseWhenHidden ?? true,\n enabled: options?.enabled ?? true\n };\n}\n\nfunction flagsToMap(flags: Array<{ key: string; value: boolean }>): Map<string, boolean> {\n const map = new Map<string, boolean>();\n for (const flag of flags) {\n map.set(flag.key, flag.value);\n }\n return map;\n}\n\nfunction diffFlagKeys(prev: Array<{ key: string; value: boolean }>, next: Array<{ key: string; value: boolean }>): Set<string> {\n const changed = new Set<string>();\n const prevMap = flagsToMap(prev);\n const nextMap = flagsToMap(next);\n\n for (const [key, value] of prevMap.entries()) {\n if (!nextMap.has(key) || nextMap.get(key) !== value) {\n changed.add(key);\n }\n }\n\n for (const [key, value] of nextMap.entries()) {\n if (!prevMap.has(key) || prevMap.get(key) !== value) {\n changed.add(key);\n }\n }\n\n return changed;\n}\n\nfunction createFlagsStore(client: FeatureFlareClient, getUser: () => FeatureFlareUserPayload) {\n const entries = new Map<string, FlagsStoreEntry>();\n let nextSubscriberId = 1;\n\n const isHidden = () => typeof document !== 'undefined' && document.visibilityState === 'hidden';\n\n const getEntry = (defaultValue: boolean): FlagsStoreEntry => {\n const key = defaultValue ? '1' : '0';\n const existing = entries.get(key);\n if (existing) return existing;\n\n const cached = client.getCachedFlags();\n const created: FlagsStoreEntry = {\n defaultValue,\n snapshot: { flags: cached.flags, loading: !cached.hasData, error: null },\n listeners: new Map(),\n subscribers: new Map(),\n timer: null,\n inFlight: false\n };\n entries.set(key, created);\n return created;\n };\n\n const emit = (entry: FlagsStoreEntry, changedKeys: Set<string> | null = null) => {\n for (const { listener, flagKey } of entry.listeners.values()) {\n if (!flagKey || changedKeys === null || changedKeys.has(flagKey)) {\n listener();\n }\n }\n };\n\n const getEffectiveOptions = (entry: FlagsStoreEntry) => {\n const active = [...entry.subscribers.values()].filter((s) => s.enabled);\n if (active.length === 0) {\n return { enabled: false as const, refreshIntervalMs: 0, hiddenRefreshIntervalMs: 0, pauseWhenHidden: true };\n }\n\n const refreshIntervalMs = active.reduce((min, s) => Math.min(min, s.refreshIntervalMs), Number.POSITIVE_INFINITY);\n const hiddenActive = active.filter((s) => !s.pauseWhenHidden);\n const hiddenRefreshIntervalMs =\n hiddenActive.length > 0\n ? hiddenActive.reduce((min, s) => Math.min(min, s.hiddenRefreshIntervalMs), Number.POSITIVE_INFINITY)\n : 0;\n\n return {\n enabled: true as const,\n refreshIntervalMs: Number.isFinite(refreshIntervalMs) ? refreshIntervalMs : 10000,\n hiddenRefreshIntervalMs,\n pauseWhenHidden: hiddenActive.length === 0\n };\n };\n\n const schedule = (entry: FlagsStoreEntry) => {\n if (entry.timer !== null) {\n clearTimeout(entry.timer);\n entry.timer = null;\n }\n\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled) return;\n\n if (isHidden()) {\n if (effective.pauseWhenHidden) return;\n entry.timer = setTimeout(() => {\n void refresh(entry.defaultValue);\n }, effective.hiddenRefreshIntervalMs);\n return;\n }\n\n entry.timer = setTimeout(() => {\n void refresh(entry.defaultValue);\n }, effective.refreshIntervalMs);\n };\n\n const refresh = async (defaultValue: boolean, force = false) => {\n const entry = getEntry(defaultValue);\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled && !force) return;\n\n if (!force && isHidden() && effective.pauseWhenHidden) {\n schedule(entry);\n return;\n }\n\n if (entry.inFlight) return;\n entry.inFlight = true;\n\n try {\n const previousFlags = entry.snapshot.flags;\n const flags = await client.flags(getUser(), defaultValue);\n const changed = diffFlagKeys(previousFlags, flags);\n entry.snapshot = { flags, loading: false, error: null };\n if (changed.size > 0 || previousFlags.length === 0) {\n emit(entry, changed);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n entry.snapshot = { ...entry.snapshot, loading: false, error: message };\n emit(entry, null);\n } finally {\n entry.inFlight = false;\n schedule(entry);\n }\n };\n\n const refreshNow = (defaultValue: boolean) => {\n const entry = getEntry(defaultValue);\n entry.snapshot = { ...entry.snapshot, loading: true, error: null };\n emit(entry, null);\n void refresh(defaultValue, true);\n };\n\n const subscribe = (\n defaultValue: boolean,\n listener: () => void,\n options?: FlagsSubscriptionOptions,\n flagKey?: string\n ): (() => void) => {\n const entry = getEntry(defaultValue);\n const subscriberId = nextSubscriberId;\n nextSubscriberId += 1;\n\n entry.listeners.set(subscriberId, { listener, flagKey });\n entry.subscribers.set(subscriberId, normalizeSubscriptionOptions(options));\n\n const effective = getEffectiveOptions(entry);\n if (effective.enabled && !entry.inFlight && entry.snapshot.loading) {\n void refresh(defaultValue);\n } else {\n schedule(entry);\n }\n\n return () => {\n entry.listeners.delete(subscriberId);\n entry.subscribers.delete(subscriberId);\n schedule(entry);\n };\n };\n\n const updateUser = () => {\n for (const entry of entries.values()) {\n entry.snapshot = { ...entry.snapshot, loading: true, error: null };\n emit(entry, null);\n void refresh(entry.defaultValue);\n }\n };\n\n const handleVisibilityChange = () => {\n if (isHidden()) return;\n for (const entry of entries.values()) {\n const effective = getEffectiveOptions(entry);\n if (!effective.enabled) continue;\n void refresh(entry.defaultValue);\n }\n };\n\n const unsubscribeClientUpdate =\n typeof (client as { on?: unknown }).on === 'function'\n ? (client as { on: (event: 'update', listener: (payload: { changedKeys: string[] }) => void) => () => void }).on(\n 'update',\n ({ changedKeys }) => {\n const changedSet = new Set(changedKeys);\n for (const entry of entries.values()) {\n const previous = entry.snapshot.flags;\n const next = client.getCachedFlags().flags;\n const diff = diffFlagKeys(previous, next);\n if (diff.size === 0) continue;\n const intersects = [...diff].some((key) => changedSet.has(key));\n if (!intersects && changedSet.size > 0) continue;\n entry.snapshot = { ...entry.snapshot, flags: next, loading: false, error: null };\n emit(entry, diff);\n }\n }\n )\n : () => {};\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', handleVisibilityChange);\n }\n\n const dispose = () => {\n unsubscribeClientUpdate();\n if (typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n }\n for (const entry of entries.values()) {\n if (entry.timer !== null) {\n clearTimeout(entry.timer);\n }\n entry.timer = null;\n entry.listeners.clear();\n entry.subscribers.clear();\n }\n entries.clear();\n };\n\n return {\n getState(defaultValue: boolean): FlagsState {\n return getEntry(defaultValue).snapshot;\n },\n refreshNow,\n subscribeAll(defaultValue: boolean, listener: () => void, options?: FlagsSubscriptionOptions) {\n return subscribe(defaultValue, listener, options);\n },\n subscribeFlag(flagKey: string, defaultValue: boolean, listener: () => void, options?: FlagsSubscriptionOptions) {\n return subscribe(defaultValue, listener, options, flagKey);\n },\n updateUser,\n dispose\n };\n}\n\nconst FeatureFlareContext = createContext<FeatureFlareContextValue | null>(null);\n\nexport function FeatureFlareProvider(props: {\n config: FeatureFlareReactConfig;\n initialUser: FeatureFlareUserPayload;\n user?: FeatureFlareUserPayload;\n onUserChange?: (next: FeatureFlareUserPayload) => void;\n children: React.ReactNode;\n}) {\n if (props.user && !props.onUserChange) {\n throw new Error('FeatureFlareProvider: when providing `user`, also provide `onUserChange` (controlled mode).');\n }\n\n const [internalUser, setInternalUser] = useState<FeatureFlareUserPayload>(props.initialUser);\n const user = props.user ?? internalUser;\n const setUser = props.onUserChange ?? setInternalUser;\n const userRef = useRef<FeatureFlareUserPayload>(user);\n\n const client = useMemo(() => {\n return new FeatureFlareClient({\n apiBaseUrl: props.config.apiBaseUrl,\n sdkKey: props.config.sdkKey,\n projectKey: props.config.projectKey,\n envKey: props.config.envKey,\n timeoutMs: props.config.timeoutMs,\n maxRetries: props.config.maxRetries,\n backoffMs: props.config.backoffMs,\n jitter: props.config.jitter,\n cacheTtlMs: props.config.cacheTtlMs,\n staleTtlMs: props.config.staleTtlMs,\n bootstrap: props.config.bootstrap,\n persistentCache: props.config.persistentCache,\n onMetric: props.config.onMetric,\n realtime: props.config.realtime\n });\n }, [\n props.config.apiBaseUrl,\n props.config.backoffMs,\n props.config.bootstrap,\n props.config.cacheTtlMs,\n props.config.envKey,\n props.config.jitter,\n props.config.maxRetries,\n props.config.onMetric,\n props.config.persistentCache,\n props.config.projectKey,\n props.config.realtime,\n props.config.sdkKey,\n props.config.staleTtlMs,\n props.config.timeoutMs\n ]);\n\n const flagsStore = useMemo(() => createFlagsStore(client, () => userRef.current), [client]);\n\n useEffect(() => {\n userRef.current = user;\n flagsStore.updateUser();\n }, [flagsStore, user]);\n\n useEffect(() => {\n return () => {\n flagsStore.dispose();\n client.dispose();\n };\n }, [client, flagsStore]);\n\n const value = useMemo(\n () => ({\n client,\n user,\n setUser,\n getFlagsState: flagsStore.getState,\n refreshFlags: flagsStore.refreshNow,\n subscribeFlags: flagsStore.subscribeAll,\n subscribeFlag: (flagKey: string, defaultValue: boolean, listener: () => void, options?: FlagsSubscriptionOptions) =>\n flagsStore.subscribeFlag(flagKey, defaultValue, listener, options),\n getFlagDiagnostics: (flagKey: string) => client.getFlagDiagnostics(flagKey)\n }),\n [client, flagsStore, setUser, user]\n );\n return <FeatureFlareContext.Provider value={value}>{props.children}</FeatureFlareContext.Provider>;\n}\n\nexport function useFeatureFlareContext(): FeatureFlareContextValue {\n const ctx = React.useContext(FeatureFlareContext);\n if (!ctx) throw new Error('useFeatureFlareContext must be used within <FeatureFlareProvider>.');\n return ctx;\n}\n","import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { FeatureFlareEvaluationMetadata, FeatureFlareUserPayload } from '@featureflare/sdk-js';\nimport { useFeatureFlareContext, type FlagsState, type FlagsSubscriptionOptions } from './provider.js';\n\ntype BoolFlagState = {\n value: boolean;\n loading: boolean;\n error: string | null;\n};\n\ntype BoolFlagsState = {\n values: Record<string, boolean>;\n loading: boolean;\n errors: Record<string, string>;\n};\n\ntype UseFlagsOptions = FlagsSubscriptionOptions;\n\ntype UseFlagsInput = UseFlagsOptions & {\n defaultValue?: boolean;\n user?: FeatureFlareUserPayload;\n};\n\nexport type FlagDiagnostics = {\n source: FeatureFlareEvaluationMetadata['source'] | 'unknown';\n reason: FeatureFlareEvaluationMetadata['reason'] | 'unknown';\n isStale: boolean;\n updatedAt?: number;\n staleAt?: number;\n expiresAt?: number;\n latencyMs?: number;\n};\n\nconst EMPTY_FLAGS_STATE: FlagsState = { flags: [], loading: true, error: null };\n\nfunction userFingerprint(user?: FeatureFlareUserPayload): string {\n if (!user) return '';\n return JSON.stringify({\n id: user.id ?? '',\n key: user.key ?? '',\n email: user.email ?? '',\n meta: user.meta ?? {}\n });\n}\n\nfunction mapFlags(flags: Array<{ key: string; value: boolean }>): Record<string, boolean> {\n const values: Record<string, boolean> = {};\n for (const flag of flags) {\n values[flag.key] = flag.value;\n }\n return values;\n}\n\nexport function useFeatureFlareUser(): [FeatureFlareUserPayload, (next: FeatureFlareUserPayload) => void] {\n const { user, setUser } = useFeatureFlareContext();\n return [user, setUser];\n}\n\nexport function useFlag(flagKey: string, defaultValue = false): BoolFlagState {\n const { subscribeFlag, getFlagsState, refreshFlags } = useFeatureFlareContext();\n\n useEffect(() => {\n refreshFlags(defaultValue);\n }, [defaultValue, refreshFlags]);\n\n const subscribe = useMemo(\n () =>\n (onStoreChange: () => void) =>\n subscribeFlag(flagKey, defaultValue, onStoreChange),\n [defaultValue, flagKey, subscribeFlag]\n );\n\n const state = useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);\n const value = state.flags.find((entry) => entry.key === flagKey)?.value ?? defaultValue;\n\n return {\n value,\n loading: state.loading,\n error: state.error\n };\n}\n\nexport function useBoolFlag(flagKey: string, defaultValue = false): BoolFlagState {\n return useFlag(flagKey, defaultValue);\n}\n\nexport function useFlags(flagKeys: string[], defaultValue?: boolean): BoolFlagsState;\nexport function useFlags(input?: UseFlagsInput): FlagsState;\nexport function useFlags(defaultValue?: boolean, options?: UseFlagsOptions): FlagsState;\nexport function useFlags(\n defaultValueOrInputOrKeys: boolean | UseFlagsInput | string[] = false,\n optionsOrDefaultValue: UseFlagsOptions | boolean = {}\n): FlagsState | BoolFlagsState {\n const { subscribeFlags, subscribeFlag, getFlagsState, refreshFlags, setUser } = useFeatureFlareContext();\n\n if (Array.isArray(defaultValueOrInputOrKeys)) {\n const keys = [...defaultValueOrInputOrKeys].map((key) => key.trim()).filter(Boolean);\n const defaultValue =\n typeof optionsOrDefaultValue === 'boolean' ? optionsOrDefaultValue : false;\n\n useEffect(() => {\n refreshFlags(defaultValue);\n }, [defaultValue, refreshFlags]);\n\n const subscribe = useMemo(\n () =>\n (onStoreChange: () => void) => {\n const unsubs = keys.map((key) => subscribeFlag(key, defaultValue, onStoreChange));\n return () => {\n for (const unsub of unsubs) unsub();\n };\n },\n [defaultValue, keys, subscribeFlag]\n );\n\n const state = useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);\n const values = mapFlags(state.flags);\n const filtered: Record<string, boolean> = {};\n for (const key of keys) {\n filtered[key] = values[key] ?? defaultValue;\n }\n\n return {\n values: filtered,\n loading: state.loading,\n errors: state.error ? { __global: state.error } : {}\n };\n }\n\n const parsed = useMemo<UseFlagsInput>(() => {\n if (typeof defaultValueOrInputOrKeys === 'boolean') {\n return {\n ...(typeof optionsOrDefaultValue === 'object' && optionsOrDefaultValue !== null ? optionsOrDefaultValue : {}),\n defaultValue: defaultValueOrInputOrKeys\n };\n }\n return defaultValueOrInputOrKeys ?? {};\n }, [defaultValueOrInputOrKeys, optionsOrDefaultValue]);\n\n const defaultValue = parsed.defaultValue ?? false;\n\n const normalizedOptions = useMemo<UseFlagsOptions>(\n () => ({\n enabled: parsed.enabled ?? true,\n refreshIntervalMs: parsed.refreshIntervalMs,\n hiddenRefreshIntervalMs: parsed.hiddenRefreshIntervalMs,\n pauseWhenHidden: parsed.pauseWhenHidden ?? true\n }),\n [parsed.enabled, parsed.hiddenRefreshIntervalMs, parsed.pauseWhenHidden, parsed.refreshIntervalMs]\n );\n\n const appliedUserRef = useRef<string>('');\n const parsedUserFingerprint = useMemo(() => userFingerprint(parsed.user), [parsed.user]);\n\n useEffect(() => {\n if (!parsed.user) return;\n if (appliedUserRef.current === parsedUserFingerprint) return;\n setUser(parsed.user);\n appliedUserRef.current = parsedUserFingerprint;\n }, [parsed.user, parsedUserFingerprint, setUser]);\n\n useEffect(() => {\n if (normalizedOptions.enabled === false) return;\n refreshFlags(defaultValue);\n }, [defaultValue, normalizedOptions.enabled, parsedUserFingerprint, refreshFlags]);\n\n const subscribe = useMemo(\n () =>\n (onStoreChange: () => void) =>\n subscribeFlags(defaultValue, onStoreChange, normalizedOptions),\n [defaultValue, normalizedOptions, subscribeFlags]\n );\n\n return useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);\n}\n\nexport function useBoolFlags(flagKeys: string[], defaultValue = false): BoolFlagsState {\n return useFlags(flagKeys, defaultValue);\n}\n\nexport function useFlagDiagnostics(flagKey: string, defaultValue = false): FlagDiagnostics {\n const { getFlagDiagnostics, subscribeFlag } = useFeatureFlareContext();\n\n const subscribe = useMemo(\n () =>\n (onStoreChange: () => void) =>\n subscribeFlag(flagKey, defaultValue, onStoreChange),\n [defaultValue, flagKey, subscribeFlag]\n );\n\n const metadata = useSyncExternalStore(\n subscribe,\n () => getFlagDiagnostics(flagKey),\n () => null\n );\n\n return {\n source: metadata?.source ?? 'unknown',\n reason: metadata?.reason ?? 'unknown',\n isStale: metadata?.isStale ?? false,\n updatedAt: metadata?.updatedAt,\n staleAt: metadata?.staleAt,\n expiresAt: metadata?.expiresAt,\n latencyMs: metadata?.latencyMs\n };\n}\n"],"mappings":"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","names":["React","import_react","defaultValue","subscribe"]}
|