@featureflare/react 0.0.5 → 0.0.6-beta.259

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/dist/index.js CHANGED
@@ -1,7 +1,234 @@
1
1
  // src/provider.tsx
2
- import React, { createContext, useMemo, useState } from "react";
3
- import { FeatureFlareClient } from "@featureflare/sdk-js";
2
+ import React, { createContext, useEffect, useMemo, useRef, useState } from "react";
3
+ import {
4
+ FeatureFlareClient
5
+ } from "@featureflare/sdk-js";
4
6
  import { jsx } from "react/jsx-runtime";
7
+ function resolveFeatureFlareBrowserConfig(input) {
8
+ const explicitEnv = input?.envKey;
9
+ const envFromVars = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_ENV_KEY?.trim().toLowerCase() : "";
10
+ const resolvedEnv = explicitEnv ?? (envFromVars === "development" || envFromVars === "staging" || envFromVars === "production" ? envFromVars : void 0);
11
+ const apiBaseUrl = input?.apiBaseUrl ?? (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_API_BASE_URL?.trim() : void 0);
12
+ const sdkKeyDevelopment = (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEVELOPMENT?.trim() : "") || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_DEV?.trim() : "") || "";
13
+ const sdkKeyStaging = (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_STAGING?.trim() : "") || "";
14
+ const sdkKeyProduction = (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PRODUCTION?.trim() : "") || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY_PROD?.trim() : "") || "";
15
+ const sdkKeyDefault = (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_FEATUREFLARE_CLIENT_KEY?.trim() : "") || "";
16
+ const sdkKey = (resolvedEnv === "development" ? sdkKeyDevelopment : "") || (resolvedEnv === "staging" ? sdkKeyStaging : "") || (resolvedEnv === "production" ? sdkKeyProduction : "") || sdkKeyDefault || void 0;
17
+ return {
18
+ apiBaseUrl,
19
+ envKey: resolvedEnv,
20
+ sdkKey
21
+ };
22
+ }
23
+ function normalizeSubscriptionOptions(options) {
24
+ const refreshIntervalMs = Number.isFinite(options?.refreshIntervalMs) && (options?.refreshIntervalMs ?? 0) > 0 ? Number(options?.refreshIntervalMs) : 1e4;
25
+ const hiddenRefreshIntervalMs = Number.isFinite(options?.hiddenRefreshIntervalMs) && (options?.hiddenRefreshIntervalMs ?? 0) > 0 ? Number(options?.hiddenRefreshIntervalMs) : Math.max(refreshIntervalMs * 6, 6e4);
26
+ return {
27
+ refreshIntervalMs,
28
+ hiddenRefreshIntervalMs,
29
+ pauseWhenHidden: options?.pauseWhenHidden ?? true,
30
+ enabled: options?.enabled ?? true
31
+ };
32
+ }
33
+ function flagsToMap(flags) {
34
+ const map = /* @__PURE__ */ new Map();
35
+ for (const flag of flags) {
36
+ map.set(flag.key, flag.value);
37
+ }
38
+ return map;
39
+ }
40
+ function diffFlagKeys(prev, next) {
41
+ const changed = /* @__PURE__ */ new Set();
42
+ const prevMap = flagsToMap(prev);
43
+ const nextMap = flagsToMap(next);
44
+ for (const [key, value] of prevMap.entries()) {
45
+ if (!nextMap.has(key) || nextMap.get(key) !== value) {
46
+ changed.add(key);
47
+ }
48
+ }
49
+ for (const [key, value] of nextMap.entries()) {
50
+ if (!prevMap.has(key) || prevMap.get(key) !== value) {
51
+ changed.add(key);
52
+ }
53
+ }
54
+ return changed;
55
+ }
56
+ function createFlagsStore(client, getUser) {
57
+ const entries = /* @__PURE__ */ new Map();
58
+ let nextSubscriberId = 1;
59
+ const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
60
+ const getEntry = (defaultValue) => {
61
+ const key = defaultValue ? "1" : "0";
62
+ const existing = entries.get(key);
63
+ if (existing) return existing;
64
+ const cached = client.getCachedFlags();
65
+ const created = {
66
+ defaultValue,
67
+ snapshot: { flags: cached.flags, loading: !cached.hasData, error: null },
68
+ listeners: /* @__PURE__ */ new Map(),
69
+ subscribers: /* @__PURE__ */ new Map(),
70
+ timer: null,
71
+ inFlight: false
72
+ };
73
+ entries.set(key, created);
74
+ return created;
75
+ };
76
+ const emit = (entry, changedKeys = null) => {
77
+ for (const { listener, flagKey } of entry.listeners.values()) {
78
+ if (!flagKey || changedKeys === null || changedKeys.has(flagKey)) {
79
+ listener();
80
+ }
81
+ }
82
+ };
83
+ const getEffectiveOptions = (entry) => {
84
+ const active = [...entry.subscribers.values()].filter((s) => s.enabled);
85
+ if (active.length === 0) {
86
+ return { enabled: false, refreshIntervalMs: 0, hiddenRefreshIntervalMs: 0, pauseWhenHidden: true };
87
+ }
88
+ const refreshIntervalMs = active.reduce((min, s) => Math.min(min, s.refreshIntervalMs), Number.POSITIVE_INFINITY);
89
+ const hiddenActive = active.filter((s) => !s.pauseWhenHidden);
90
+ const hiddenRefreshIntervalMs = hiddenActive.length > 0 ? hiddenActive.reduce((min, s) => Math.min(min, s.hiddenRefreshIntervalMs), Number.POSITIVE_INFINITY) : 0;
91
+ return {
92
+ enabled: true,
93
+ refreshIntervalMs: Number.isFinite(refreshIntervalMs) ? refreshIntervalMs : 1e4,
94
+ hiddenRefreshIntervalMs,
95
+ pauseWhenHidden: hiddenActive.length === 0
96
+ };
97
+ };
98
+ const schedule = (entry) => {
99
+ if (entry.timer !== null) {
100
+ clearTimeout(entry.timer);
101
+ entry.timer = null;
102
+ }
103
+ const effective = getEffectiveOptions(entry);
104
+ if (!effective.enabled) return;
105
+ if (isHidden()) {
106
+ if (effective.pauseWhenHidden) return;
107
+ entry.timer = setTimeout(() => {
108
+ void refresh(entry.defaultValue);
109
+ }, effective.hiddenRefreshIntervalMs);
110
+ return;
111
+ }
112
+ entry.timer = setTimeout(() => {
113
+ void refresh(entry.defaultValue);
114
+ }, effective.refreshIntervalMs);
115
+ };
116
+ const refresh = async (defaultValue, force = false) => {
117
+ const entry = getEntry(defaultValue);
118
+ const effective = getEffectiveOptions(entry);
119
+ if (!effective.enabled && !force) return;
120
+ if (!force && isHidden() && effective.pauseWhenHidden) {
121
+ schedule(entry);
122
+ return;
123
+ }
124
+ if (entry.inFlight) return;
125
+ entry.inFlight = true;
126
+ try {
127
+ const previousFlags = entry.snapshot.flags;
128
+ const flags = await client.flags(getUser(), defaultValue);
129
+ const changed = diffFlagKeys(previousFlags, flags);
130
+ entry.snapshot = { flags, loading: false, error: null };
131
+ if (changed.size > 0 || previousFlags.length === 0) {
132
+ emit(entry, changed);
133
+ }
134
+ } catch (error) {
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ entry.snapshot = { ...entry.snapshot, loading: false, error: message };
137
+ emit(entry, null);
138
+ } finally {
139
+ entry.inFlight = false;
140
+ schedule(entry);
141
+ }
142
+ };
143
+ const refreshNow = (defaultValue) => {
144
+ const entry = getEntry(defaultValue);
145
+ entry.snapshot = { ...entry.snapshot, loading: true, error: null };
146
+ emit(entry, null);
147
+ void refresh(defaultValue, true);
148
+ };
149
+ const subscribe = (defaultValue, listener, options, flagKey) => {
150
+ const entry = getEntry(defaultValue);
151
+ const subscriberId = nextSubscriberId;
152
+ nextSubscriberId += 1;
153
+ entry.listeners.set(subscriberId, { listener, flagKey });
154
+ entry.subscribers.set(subscriberId, normalizeSubscriptionOptions(options));
155
+ const effective = getEffectiveOptions(entry);
156
+ if (effective.enabled && !entry.inFlight && entry.snapshot.loading) {
157
+ void refresh(defaultValue);
158
+ } else {
159
+ schedule(entry);
160
+ }
161
+ return () => {
162
+ entry.listeners.delete(subscriberId);
163
+ entry.subscribers.delete(subscriberId);
164
+ schedule(entry);
165
+ };
166
+ };
167
+ const updateUser = () => {
168
+ for (const entry of entries.values()) {
169
+ entry.snapshot = { ...entry.snapshot, loading: true, error: null };
170
+ emit(entry, null);
171
+ void refresh(entry.defaultValue);
172
+ }
173
+ };
174
+ const handleVisibilityChange = () => {
175
+ if (isHidden()) return;
176
+ for (const entry of entries.values()) {
177
+ const effective = getEffectiveOptions(entry);
178
+ if (!effective.enabled) continue;
179
+ void refresh(entry.defaultValue);
180
+ }
181
+ };
182
+ const unsubscribeClientUpdate = typeof client.on === "function" ? client.on(
183
+ "update",
184
+ ({ changedKeys }) => {
185
+ const changedSet = new Set(changedKeys);
186
+ for (const entry of entries.values()) {
187
+ const previous = entry.snapshot.flags;
188
+ const next = client.getCachedFlags().flags;
189
+ const diff = diffFlagKeys(previous, next);
190
+ if (diff.size === 0) continue;
191
+ const intersects = [...diff].some((key) => changedSet.has(key));
192
+ if (!intersects && changedSet.size > 0) continue;
193
+ entry.snapshot = { ...entry.snapshot, flags: next, loading: false, error: null };
194
+ emit(entry, diff);
195
+ }
196
+ }
197
+ ) : () => {
198
+ };
199
+ if (typeof document !== "undefined") {
200
+ document.addEventListener("visibilitychange", handleVisibilityChange);
201
+ }
202
+ const dispose = () => {
203
+ unsubscribeClientUpdate();
204
+ if (typeof document !== "undefined") {
205
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
206
+ }
207
+ for (const entry of entries.values()) {
208
+ if (entry.timer !== null) {
209
+ clearTimeout(entry.timer);
210
+ }
211
+ entry.timer = null;
212
+ entry.listeners.clear();
213
+ entry.subscribers.clear();
214
+ }
215
+ entries.clear();
216
+ };
217
+ return {
218
+ getState(defaultValue) {
219
+ return getEntry(defaultValue).snapshot;
220
+ },
221
+ refreshNow,
222
+ subscribeAll(defaultValue, listener, options) {
223
+ return subscribe(defaultValue, listener, options);
224
+ },
225
+ subscribeFlag(flagKey, defaultValue, listener, options) {
226
+ return subscribe(defaultValue, listener, options, flagKey);
227
+ },
228
+ updateUser,
229
+ dispose
230
+ };
231
+ }
5
232
  var FeatureFlareContext = createContext(null);
6
233
  function FeatureFlareProvider(props) {
7
234
  if (props.user && !props.onUserChange) {
@@ -10,20 +237,64 @@ function FeatureFlareProvider(props) {
10
237
  const [internalUser, setInternalUser] = useState(props.initialUser);
11
238
  const user = props.user ?? internalUser;
12
239
  const setUser = props.onUserChange ?? setInternalUser;
240
+ const userRef = useRef(user);
13
241
  const client = useMemo(() => {
14
242
  return new FeatureFlareClient({
15
243
  apiBaseUrl: props.config.apiBaseUrl,
16
244
  sdkKey: props.config.sdkKey,
17
245
  projectKey: props.config.projectKey,
18
- envKey: props.config.envKey
246
+ envKey: props.config.envKey,
247
+ timeoutMs: props.config.timeoutMs,
248
+ maxRetries: props.config.maxRetries,
249
+ backoffMs: props.config.backoffMs,
250
+ jitter: props.config.jitter,
251
+ cacheTtlMs: props.config.cacheTtlMs,
252
+ staleTtlMs: props.config.staleTtlMs,
253
+ bootstrap: props.config.bootstrap,
254
+ persistentCache: props.config.persistentCache,
255
+ onMetric: props.config.onMetric,
256
+ realtime: props.config.realtime
19
257
  });
20
258
  }, [
21
259
  props.config.apiBaseUrl,
260
+ props.config.backoffMs,
261
+ props.config.bootstrap,
262
+ props.config.cacheTtlMs,
22
263
  props.config.envKey,
264
+ props.config.jitter,
265
+ props.config.maxRetries,
266
+ props.config.onMetric,
267
+ props.config.persistentCache,
23
268
  props.config.projectKey,
24
- props.config.sdkKey
269
+ props.config.realtime,
270
+ props.config.sdkKey,
271
+ props.config.staleTtlMs,
272
+ props.config.timeoutMs
25
273
  ]);
26
- const value = useMemo(() => ({ client, user, setUser }), [client, user]);
274
+ const flagsStore = useMemo(() => createFlagsStore(client, () => userRef.current), [client]);
275
+ useEffect(() => {
276
+ userRef.current = user;
277
+ flagsStore.updateUser();
278
+ }, [flagsStore, user]);
279
+ useEffect(() => {
280
+ return () => {
281
+ flagsStore.dispose();
282
+ client.dispose();
283
+ };
284
+ }, [client, flagsStore]);
285
+ const value = useMemo(
286
+ () => ({
287
+ client,
288
+ user,
289
+ setUser,
290
+ getFlagsState: flagsStore.getState,
291
+ refreshFlags: flagsStore.refreshNow,
292
+ subscribeFlags: flagsStore.subscribeAll,
293
+ subscribeFlag: (flagKey, defaultValue, listener, options) => flagsStore.subscribeFlag(flagKey, defaultValue, listener, options),
294
+ getFlagDiagnostics: (flagKey) => client.getFlagDiagnostics(flagKey)
295
+ }),
296
+ [client, flagsStore, setUser, user]
297
+ );
27
298
  return /* @__PURE__ */ jsx(FeatureFlareContext.Provider, { value, children: props.children });
28
299
  }
29
300
  function useFeatureFlareContext() {
@@ -33,81 +304,159 @@ function useFeatureFlareContext() {
33
304
  }
34
305
 
35
306
  // src/hooks.ts
36
- import { useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
307
+ import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useSyncExternalStore } from "react";
308
+ var EMPTY_FLAGS_STATE = { flags: [], loading: true, error: null };
309
+ function userFingerprint(user) {
310
+ if (!user) return "";
311
+ return JSON.stringify({
312
+ id: user.id ?? "",
313
+ key: user.key ?? "",
314
+ email: user.email ?? "",
315
+ meta: user.meta ?? {}
316
+ });
317
+ }
318
+ function mapFlags(flags) {
319
+ const values = {};
320
+ for (const flag of flags) {
321
+ values[flag.key] = flag.value;
322
+ }
323
+ return values;
324
+ }
37
325
  function useFeatureFlareUser() {
38
326
  const { user, setUser } = useFeatureFlareContext();
39
327
  return [user, setUser];
40
328
  }
329
+ function useFlag(flagKey, defaultValue = false) {
330
+ const { subscribeFlag, getFlagsState, refreshFlags } = useFeatureFlareContext();
331
+ useEffect2(() => {
332
+ refreshFlags(defaultValue);
333
+ }, [defaultValue, refreshFlags]);
334
+ const subscribe = useMemo2(
335
+ () => (onStoreChange) => subscribeFlag(flagKey, defaultValue, onStoreChange),
336
+ [defaultValue, flagKey, subscribeFlag]
337
+ );
338
+ const state = useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);
339
+ const value = state.flags.find((entry) => entry.key === flagKey)?.value ?? defaultValue;
340
+ return {
341
+ value,
342
+ loading: state.loading,
343
+ error: state.error
344
+ };
345
+ }
41
346
  function useBoolFlag(flagKey, defaultValue = false) {
42
- const { client, user } = useFeatureFlareContext();
43
- const [state, setState] = useState2({ value: defaultValue, loading: true, error: null });
44
- const userId = user.id ?? user.key ?? "";
45
- const key = useMemo2(() => `${flagKey}:${userId}`, [flagKey, userId]);
46
- const lastKey = useRef("");
47
- useEffect(() => {
48
- let cancelled = false;
49
- const nextKey = key;
50
- lastKey.current = nextKey;
51
- setState((s) => ({ ...s, loading: true, error: null }));
52
- (async () => {
53
- try {
54
- const v = await client.bool(flagKey, user, defaultValue);
55
- if (cancelled) return;
56
- if (lastKey.current !== nextKey) return;
57
- setState({ value: v, loading: false, error: null });
58
- } catch (e) {
59
- if (cancelled) return;
60
- if (lastKey.current !== nextKey) return;
61
- const msg = e instanceof Error ? e.message : String(e);
62
- setState({ value: defaultValue, loading: false, error: msg });
63
- }
64
- })();
65
- return () => {
66
- cancelled = true;
67
- };
68
- }, [client, defaultValue, flagKey, key, user]);
69
- return state;
347
+ return useFlag(flagKey, defaultValue);
70
348
  }
71
- function useBoolFlags(flagKeys, defaultValue = false) {
72
- const { client, user } = useFeatureFlareContext();
73
- const sortedKeys = useMemo2(() => [...flagKeys].map((k) => k.trim()).filter(Boolean).sort(), [flagKeys]);
74
- const userId = user.id ?? user.key ?? "";
75
- const key = useMemo2(() => `${sortedKeys.join(",")}:${userId}`, [sortedKeys, userId]);
76
- const [state, setState] = useState2({ values: {}, loading: true, errors: {} });
77
- const lastKey = useRef("");
78
- useEffect(() => {
79
- let cancelled = false;
80
- const nextKey = key;
81
- lastKey.current = nextKey;
82
- setState({ values: {}, loading: true, errors: {} });
83
- (async () => {
84
- const values = {};
85
- const errors = {};
86
- await Promise.all(
87
- sortedKeys.map(async (flagKey) => {
88
- try {
89
- values[flagKey] = await client.bool(flagKey, user, defaultValue);
90
- } catch (e) {
91
- values[flagKey] = defaultValue;
92
- errors[flagKey] = e instanceof Error ? e.message : String(e);
93
- }
94
- })
95
- );
96
- if (cancelled) return;
97
- if (lastKey.current !== nextKey) return;
98
- setState({ values, loading: false, errors });
99
- })();
100
- return () => {
101
- cancelled = true;
349
+ function useFlags(defaultValueOrInputOrKeys = false, optionsOrDefaultValue = {}) {
350
+ const { subscribeFlags, subscribeFlag, getFlagsState, refreshFlags, setUser } = useFeatureFlareContext();
351
+ if (Array.isArray(defaultValueOrInputOrKeys)) {
352
+ const keys = [...defaultValueOrInputOrKeys].map((key) => key.trim()).filter(Boolean);
353
+ const defaultValue2 = typeof optionsOrDefaultValue === "boolean" ? optionsOrDefaultValue : false;
354
+ useEffect2(() => {
355
+ refreshFlags(defaultValue2);
356
+ }, [defaultValue2, refreshFlags]);
357
+ const subscribe2 = useMemo2(
358
+ () => (onStoreChange) => {
359
+ const unsubs = keys.map((key) => subscribeFlag(key, defaultValue2, onStoreChange));
360
+ return () => {
361
+ for (const unsub of unsubs) unsub();
362
+ };
363
+ },
364
+ [defaultValue2, keys, subscribeFlag]
365
+ );
366
+ const state = useSyncExternalStore(subscribe2, () => getFlagsState(defaultValue2), () => EMPTY_FLAGS_STATE);
367
+ const values = mapFlags(state.flags);
368
+ const filtered = {};
369
+ for (const key of keys) {
370
+ filtered[key] = values[key] ?? defaultValue2;
371
+ }
372
+ return {
373
+ values: filtered,
374
+ loading: state.loading,
375
+ errors: state.error ? { __global: state.error } : {}
102
376
  };
103
- }, [client, defaultValue, key, sortedKeys, user]);
104
- return state;
377
+ }
378
+ const parsed = useMemo2(() => {
379
+ if (typeof defaultValueOrInputOrKeys === "boolean") {
380
+ return {
381
+ ...typeof optionsOrDefaultValue === "object" && optionsOrDefaultValue !== null ? optionsOrDefaultValue : {},
382
+ defaultValue: defaultValueOrInputOrKeys
383
+ };
384
+ }
385
+ return defaultValueOrInputOrKeys ?? {};
386
+ }, [defaultValueOrInputOrKeys, optionsOrDefaultValue]);
387
+ const defaultValue = parsed.defaultValue ?? false;
388
+ const normalizedOptions = useMemo2(
389
+ () => ({
390
+ enabled: parsed.enabled ?? true,
391
+ refreshIntervalMs: parsed.refreshIntervalMs,
392
+ hiddenRefreshIntervalMs: parsed.hiddenRefreshIntervalMs,
393
+ pauseWhenHidden: parsed.pauseWhenHidden ?? true
394
+ }),
395
+ [parsed.enabled, parsed.hiddenRefreshIntervalMs, parsed.pauseWhenHidden, parsed.refreshIntervalMs]
396
+ );
397
+ const appliedUserRef = useRef2("");
398
+ const parsedUserFingerprint = useMemo2(() => userFingerprint(parsed.user), [parsed.user]);
399
+ useEffect2(() => {
400
+ if (!parsed.user) return;
401
+ if (appliedUserRef.current === parsedUserFingerprint) return;
402
+ setUser(parsed.user);
403
+ appliedUserRef.current = parsedUserFingerprint;
404
+ }, [parsed.user, parsedUserFingerprint, setUser]);
405
+ useEffect2(() => {
406
+ if (normalizedOptions.enabled === false) return;
407
+ refreshFlags(defaultValue);
408
+ }, [defaultValue, normalizedOptions.enabled, parsedUserFingerprint, refreshFlags]);
409
+ const subscribe = useMemo2(
410
+ () => (onStoreChange) => subscribeFlags(defaultValue, onStoreChange, normalizedOptions),
411
+ [defaultValue, normalizedOptions, subscribeFlags]
412
+ );
413
+ return useSyncExternalStore(subscribe, () => getFlagsState(defaultValue), () => EMPTY_FLAGS_STATE);
414
+ }
415
+ function useBoolFlags(flagKeysOrDefaultValue = false, optionsOrDefaultValue = {}) {
416
+ if (Array.isArray(flagKeysOrDefaultValue)) {
417
+ const defaultValue = typeof optionsOrDefaultValue === "boolean" ? optionsOrDefaultValue : false;
418
+ return useFlags(flagKeysOrDefaultValue, defaultValue);
419
+ }
420
+ const state = useFlags(
421
+ flagKeysOrDefaultValue,
422
+ typeof optionsOrDefaultValue === "object" && optionsOrDefaultValue !== null ? optionsOrDefaultValue : {}
423
+ );
424
+ return {
425
+ values: mapFlags(state.flags),
426
+ loading: state.loading,
427
+ errors: state.error ? { __global: state.error } : {}
428
+ };
429
+ }
430
+ function useFlagDiagnostics(flagKey, defaultValue = false) {
431
+ const { getFlagDiagnostics, subscribeFlag } = useFeatureFlareContext();
432
+ const subscribe = useMemo2(
433
+ () => (onStoreChange) => subscribeFlag(flagKey, defaultValue, onStoreChange),
434
+ [defaultValue, flagKey, subscribeFlag]
435
+ );
436
+ const metadata = useSyncExternalStore(
437
+ subscribe,
438
+ () => getFlagDiagnostics(flagKey),
439
+ () => null
440
+ );
441
+ return {
442
+ source: metadata?.source ?? "unknown",
443
+ reason: metadata?.reason ?? "unknown",
444
+ isStale: metadata?.isStale ?? false,
445
+ updatedAt: metadata?.updatedAt,
446
+ staleAt: metadata?.staleAt,
447
+ expiresAt: metadata?.expiresAt,
448
+ latencyMs: metadata?.latencyMs
449
+ };
105
450
  }
106
451
  export {
107
452
  FeatureFlareProvider,
453
+ resolveFeatureFlareBrowserConfig,
108
454
  useBoolFlag,
109
455
  useBoolFlags,
110
456
  useFeatureFlareContext,
111
- useFeatureFlareUser
457
+ useFeatureFlareUser,
458
+ useFlag,
459
+ useFlagDiagnostics,
460
+ useFlags
112
461
  };
113
462
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import React, { createContext, useMemo, useState } from 'react';\nimport { FeatureFlareClient, type FeatureFlareUserPayload } from '@featureflare/sdk-js';\n\ntype 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?: string;\n};\n\ntype FeatureFlareContextValue = {\n client: FeatureFlareClient;\n user: FeatureFlareUserPayload;\n setUser: (next: FeatureFlareUserPayload) => void;\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\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 value = useMemo(() => ({ client, user, setUser }), [client, user]);\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 } from 'react';\nimport type { FeatureFlareUserPayload } from '@featureflare/sdk-js';\nimport { useFeatureFlareContext } 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\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"],"mappings":"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","names":["useMemo","useState","useState","useMemo"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["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?: boolean): BoolFlagsState;\nexport function useBoolFlags(defaultValue?: boolean, options?: UseFlagsOptions): BoolFlagsState;\nexport function useBoolFlags(\n flagKeysOrDefaultValue: string[] | boolean = false,\n optionsOrDefaultValue: UseFlagsOptions | boolean = {}\n): BoolFlagsState {\n if (Array.isArray(flagKeysOrDefaultValue)) {\n const defaultValue =\n typeof optionsOrDefaultValue === 'boolean' ? optionsOrDefaultValue : false;\n return useFlags(flagKeysOrDefaultValue, defaultValue);\n }\n\n const state = useFlags(\n flagKeysOrDefaultValue,\n typeof optionsOrDefaultValue === 'object' && optionsOrDefaultValue !== null\n ? optionsOrDefaultValue\n : {}\n ) as FlagsState;\n return {\n values: mapFlags(state.flags),\n loading: state.loading,\n errors: state.error ? { __global: state.error } : {}\n };\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":["useEffect","useMemo","useRef","useEffect","useMemo","defaultValue","subscribe","useRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featureflare/react",
3
- "version": "0.0.5",
3
+ "version": "0.0.6-beta.259",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -33,12 +33,12 @@
33
33
  "react-dom": ">=18"
34
34
  },
35
35
  "dependencies": {
36
- "@featureflare/sdk-js": "0.0.5"
36
+ "@featureflare/sdk-js": "0.0.6-beta.259"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.2",
40
- "@types/react": "^18.3.12",
41
- "@types/react-dom": "^18.3.1",
40
+ "@types/react": "^19.0.0",
41
+ "@types/react-dom": "^19.0.0",
42
42
  "eslint": "^9.16.0",
43
43
  "prettier": "^3.4.2",
44
44
  "tsup": "^8.3.5",