@featureflare/react 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @featureflare/react
2
2
 
3
- React hooks and provider for FeatureFlare feature flags.
3
+ React hooks and provider for ShipIt feature flags.
4
4
 
5
5
  ## Installation
6
6
 
@@ -21,24 +21,22 @@ yarn add @featureflare/react
21
21
 
22
22
  ### Setup Provider
23
23
 
24
- Wrap your app with `FeatureFlareProvider`:
24
+ Wrap your app with `ShipItProvider`:
25
25
 
26
26
  ```typescript
27
- import { FeatureFlareProvider } from '@featureflare/react';
27
+ import { ShipItProvider } from '@featureflare/react';
28
28
 
29
29
  export function App() {
30
30
  return (
31
- <FeatureFlareProvider
31
+ <ShipItProvider
32
32
  config={{
33
- // Optional: explicit FeatureFlare API URL
34
- apiBaseUrl: 'https://flags.your-company.com',
35
- // SDK defaults to FeatureFlare Cloud Run unless overridden
33
+ // SDK automatically uses window.location.origin in browser
36
34
  sdkKey: 'your-client-key-here' // Client key for browser
37
35
  }}
38
36
  initialUser={{ id: 'user-123' }}
39
37
  >
40
38
  {/* Your app */}
41
- </FeatureFlareProvider>
39
+ </ShipItProvider>
42
40
  );
43
41
  }
44
42
  ```
@@ -62,13 +60,13 @@ export function NewNav() {
62
60
 
63
61
  ### Update User
64
62
 
65
- Use the `useFeatureFlareUser` hook to get and update the current user:
63
+ Use the `useShipItUser` hook to get and update the current user:
66
64
 
67
65
  ```typescript
68
- import { useFeatureFlareUser } from '@featureflare/react';
66
+ import { useShipItUser } from '@featureflare/react';
69
67
 
70
68
  export function UserSwitcher() {
71
- const [user, setUser] = useFeatureFlareUser();
69
+ const [user, setUser] = useShipItUser();
72
70
 
73
71
  return (
74
72
  <button
@@ -87,20 +85,19 @@ export function UserSwitcher() {
87
85
 
88
86
  ## API Reference
89
87
 
90
- ### `FeatureFlareProvider`
88
+ ### `ShipItProvider`
91
89
 
92
- Provider component that wraps your app and provides the FeatureFlare client context.
90
+ Provider component that wraps your app and provides the ShipIt client context.
93
91
 
94
92
  #### Props
95
93
 
96
- - `config: FeatureFlareReactConfig` - Configuration object
97
- - `apiBaseUrl?: string` - Optional explicit FeatureFlare API base URL.
98
- - `sdkKey?: string` - Client SDK key (recommended). If not provided, reads from `FEATUREFLARE_CLIENT_KEY` env var.
94
+ - `config: ShipItReactConfig` - Configuration object
95
+ - `sdkKey?: string` - Client SDK key (recommended). If not provided, reads from `SHIPIT_CLIENT_KEY` env var.
99
96
  - `projectKey?: string` - Legacy: project key (requires `envKey`). Not recommended.
100
97
  - `envKey?: string` - Environment key (default: `'production'`). Only used with `projectKey`.
101
- - `initialUser: FeatureFlareUserPayload` - Initial user payload
102
- - `user?: FeatureFlareUserPayload` - Controlled user (requires `onUserChange`)
103
- - `onUserChange?: (user: FeatureFlareUserPayload) => void` - Callback for user changes (required if using controlled `user`)
98
+ - `initialUser: ShipItUserPayload` - Initial user payload
99
+ - `user?: ShipItUserPayload` - Controlled user (requires `onUserChange`)
100
+ - `onUserChange?: (user: ShipItUserPayload) => void` - Callback for user changes (required if using controlled `user`)
104
101
  - `children: React.ReactNode` - Your app components
105
102
 
106
103
  ### `useBoolFlag(flagKey: string, defaultValue: boolean)`
@@ -119,31 +116,31 @@ Hook to evaluate a boolean feature flag.
119
116
  const { value, loading, error } = useBoolFlag('feature-flag', false);
120
117
  ```
121
118
 
122
- ### `useFeatureFlareUser()`
119
+ ### `useShipItUser()`
123
120
 
124
121
  Hook to get and update the current user.
125
122
 
126
123
  **Returns:**
127
124
 
128
- `[user: FeatureFlareUserPayload | null, setUser: (user: FeatureFlareUserPayload) => void]`
125
+ `[user: ShipItUserPayload | null, setUser: (user: ShipItUserPayload) => void]`
129
126
 
130
127
  **Example:**
131
128
 
132
129
  ```typescript
133
- const [user, setUser] = useFeatureFlareUser();
130
+ const [user, setUser] = useShipItUser();
134
131
  ```
135
132
 
136
133
  ## Environment Variables
137
134
 
138
135
  The SDK automatically reads from environment variables if `sdkKey` is not provided:
139
136
 
140
- - `FEATUREFLARE_CLIENT_KEY` - Client SDK key
137
+ - `SHIPIT_CLIENT_KEY` - Client SDK key
141
138
 
142
139
  ```typescript
143
- // This will use FEATUREFLARE_CLIENT_KEY from env if sdkKey is not provided
144
- <FeatureFlareProvider config={{}} initialUser={{ id: 'user-123' }}>
140
+ // This will use SHIPIT_CLIENT_KEY from env if sdkKey is not provided
141
+ <ShipItProvider config={{}} initialUser={{ id: 'user-123' }}>
145
142
  {/* ... */}
146
- </FeatureFlareProvider>
143
+ </ShipItProvider>
147
144
  ```
148
145
 
149
146
  ## API Base URL
@@ -154,7 +151,7 @@ The SDK automatically uses `window.location.origin` in the browser (assumes API
154
151
 
155
152
  Use **client keys** for browser/mobile applications. Client keys are not secret and will be visible in your JavaScript bundle.
156
153
 
157
- Get your SDK keys from your FeatureFlare Console → Environments.
154
+ Get your SDK keys from your ShipIt Console → Environments.
158
155
 
159
156
  ## License
160
157
 
package/dist/index.cjs CHANGED
@@ -30,11 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- FeatureFlareProvider: () => FeatureFlareProvider,
33
+ ShipItProvider: () => ShipItProvider,
34
34
  useBoolFlag: () => useBoolFlag,
35
35
  useBoolFlags: () => useBoolFlags,
36
- useFeatureFlareContext: () => useFeatureFlareContext,
37
- useFeatureFlareUser: () => useFeatureFlareUser
36
+ useShipItContext: () => useShipItContext,
37
+ useShipItUser: () => useShipItUser
38
38
  });
39
39
  module.exports = __toCommonJS(index_exports);
40
40
 
@@ -42,44 +42,38 @@ module.exports = __toCommonJS(index_exports);
42
42
  var import_react = __toESM(require("react"), 1);
43
43
  var import_sdk_js = require("@featureflare/sdk-js");
44
44
  var import_jsx_runtime = require("react/jsx-runtime");
45
- var FeatureFlareContext = (0, import_react.createContext)(null);
46
- function FeatureFlareProvider(props) {
45
+ var ShipItContext = (0, import_react.createContext)(null);
46
+ function ShipItProvider(props) {
47
47
  if (props.user && !props.onUserChange) {
48
- throw new Error("FeatureFlareProvider: when providing `user`, also provide `onUserChange` (controlled mode).");
48
+ throw new Error("ShipItProvider: when providing `user`, also provide `onUserChange` (controlled mode).");
49
49
  }
50
50
  const [internalUser, setInternalUser] = (0, import_react.useState)(props.initialUser);
51
51
  const user = props.user ?? internalUser;
52
52
  const setUser = props.onUserChange ?? setInternalUser;
53
53
  const client = (0, import_react.useMemo)(() => {
54
- return new import_sdk_js.FeatureFlareClient({
55
- apiBaseUrl: props.config.apiBaseUrl,
54
+ return new import_sdk_js.ShipItClient({
56
55
  sdkKey: props.config.sdkKey,
57
56
  projectKey: props.config.projectKey,
58
57
  envKey: props.config.envKey
59
58
  });
60
- }, [
61
- props.config.apiBaseUrl,
62
- props.config.envKey,
63
- props.config.projectKey,
64
- props.config.sdkKey
65
- ]);
59
+ }, [props.config.envKey, props.config.projectKey, props.config.sdkKey]);
66
60
  const value = (0, import_react.useMemo)(() => ({ client, user, setUser }), [client, user]);
67
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FeatureFlareContext.Provider, { value, children: props.children });
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShipItContext.Provider, { value, children: props.children });
68
62
  }
69
- function useFeatureFlareContext() {
70
- const ctx = import_react.default.useContext(FeatureFlareContext);
71
- if (!ctx) throw new Error("useFeatureFlareContext must be used within <FeatureFlareProvider>.");
63
+ function useShipItContext() {
64
+ const ctx = import_react.default.useContext(ShipItContext);
65
+ if (!ctx) throw new Error("useShipItContext must be used within <ShipItProvider>.");
72
66
  return ctx;
73
67
  }
74
68
 
75
69
  // src/hooks.ts
76
70
  var import_react2 = require("react");
77
- function useFeatureFlareUser() {
78
- const { user, setUser } = useFeatureFlareContext();
71
+ function useShipItUser() {
72
+ const { user, setUser } = useShipItContext();
79
73
  return [user, setUser];
80
74
  }
81
75
  function useBoolFlag(flagKey, defaultValue = false) {
82
- const { client, user } = useFeatureFlareContext();
76
+ const { client, user } = useShipItContext();
83
77
  const [state, setState] = (0, import_react2.useState)({ value: defaultValue, loading: true, error: null });
84
78
  const userId = user.id ?? user.key ?? "";
85
79
  const key = (0, import_react2.useMemo)(() => `${flagKey}:${userId}`, [flagKey, userId]);
@@ -109,7 +103,7 @@ function useBoolFlag(flagKey, defaultValue = false) {
109
103
  return state;
110
104
  }
111
105
  function useBoolFlags(flagKeys, defaultValue = false) {
112
- const { client, user } = useFeatureFlareContext();
106
+ const { client, user } = useShipItContext();
113
107
  const sortedKeys = (0, import_react2.useMemo)(() => [...flagKeys].map((k) => k.trim()).filter(Boolean).sort(), [flagKeys]);
114
108
  const userId = user.id ?? user.key ?? "";
115
109
  const key = (0, import_react2.useMemo)(() => `${sortedKeys.join(",")}:${userId}`, [sortedKeys, userId]);
@@ -145,10 +139,10 @@ function useBoolFlags(flagKeys, defaultValue = false) {
145
139
  }
146
140
  // Annotate the CommonJS export names for ESM import in node:
147
141
  0 && (module.exports = {
148
- FeatureFlareProvider,
142
+ ShipItProvider,
149
143
  useBoolFlag,
150
144
  useBoolFlags,
151
- useFeatureFlareContext,
152
- useFeatureFlareUser
145
+ useShipItContext,
146
+ useShipItUser
153
147
  });
154
148
  //# sourceMappingURL=index.cjs.map
@@ -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, 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":["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 { ShipItUserPayload } from '@featureflare/sdk-js';\n","import React, { createContext, useMemo, useState } from 'react';\nimport { ShipItClient, type ShipItUserPayload } from '@featureflare/sdk-js';\n\ntype ShipItReactConfig = {\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 ShipItContextValue = {\n client: ShipItClient;\n user: ShipItUserPayload;\n setUser: (next: ShipItUserPayload) => void;\n};\n\nconst ShipItContext = createContext<ShipItContextValue | null>(null);\n\nexport function ShipItProvider(props: {\n config: ShipItReactConfig;\n initialUser: ShipItUserPayload;\n user?: ShipItUserPayload;\n onUserChange?: (next: ShipItUserPayload) => void;\n children: React.ReactNode;\n}) {\n if (props.user && !props.onUserChange) {\n throw new Error('ShipItProvider: when providing `user`, also provide `onUserChange` (controlled mode).');\n }\n\n const [internalUser, setInternalUser] = useState<ShipItUserPayload>(props.initialUser);\n const user = props.user ?? internalUser;\n const setUser = props.onUserChange ?? setInternalUser;\n\n const client = useMemo(() => {\n return new ShipItClient({\n sdkKey: props.config.sdkKey,\n projectKey: props.config.projectKey,\n envKey: props.config.envKey\n });\n }, [props.config.envKey, props.config.projectKey, props.config.sdkKey]);\n\n const value = useMemo(() => ({ client, user, setUser }), [client, user]);\n return <ShipItContext.Provider value={value}>{props.children}</ShipItContext.Provider>;\n}\n\nexport function useShipItContext(): ShipItContextValue {\n const ctx = React.useContext(ShipItContext);\n if (!ctx) throw new Error('useShipItContext must be used within <ShipItProvider>.');\n return ctx;\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type { ShipItUserPayload } from '@featureflare/sdk-js';\nimport { useShipItContext } 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 useShipItUser(): [ShipItUserPayload, (next: ShipItUserPayload) => void] {\n const { user, setUser } = useShipItContext();\n return [user, setUser];\n}\n\nexport function useBoolFlag(flagKey: string, defaultValue = false): BoolFlagState {\n const { client, user } = useShipItContext();\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 } = useShipItContext();\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":["React","import_react"]}
package/dist/index.d.cts CHANGED
@@ -1,30 +1,28 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { FeatureFlareUserPayload, FeatureFlareClient } from '@featureflare/sdk-js';
4
- export { FeatureFlareUserPayload } from '@featureflare/sdk-js';
3
+ import { ShipItUserPayload, ShipItClient } from '@featureflare/sdk-js';
4
+ export { ShipItUserPayload } from '@featureflare/sdk-js';
5
5
 
6
- type FeatureFlareReactConfig = {
7
- /** Optional: explicit FeatureFlare API base URL. */
8
- apiBaseUrl?: string;
6
+ type ShipItReactConfig = {
9
7
  /** Recommended: use a client key (featureflare_cli_...). */
10
8
  sdkKey?: string;
11
9
  /** Legacy/insecure browser mode: uses /api/v1/eval (no sdkKey). */
12
10
  projectKey?: string;
13
11
  envKey?: string;
14
12
  };
15
- type FeatureFlareContextValue = {
16
- client: FeatureFlareClient;
17
- user: FeatureFlareUserPayload;
18
- setUser: (next: FeatureFlareUserPayload) => void;
13
+ type ShipItContextValue = {
14
+ client: ShipItClient;
15
+ user: ShipItUserPayload;
16
+ setUser: (next: ShipItUserPayload) => void;
19
17
  };
20
- declare function FeatureFlareProvider(props: {
21
- config: FeatureFlareReactConfig;
22
- initialUser: FeatureFlareUserPayload;
23
- user?: FeatureFlareUserPayload;
24
- onUserChange?: (next: FeatureFlareUserPayload) => void;
18
+ declare function ShipItProvider(props: {
19
+ config: ShipItReactConfig;
20
+ initialUser: ShipItUserPayload;
21
+ user?: ShipItUserPayload;
22
+ onUserChange?: (next: ShipItUserPayload) => void;
25
23
  children: React.ReactNode;
26
24
  }): react_jsx_runtime.JSX.Element;
27
- declare function useFeatureFlareContext(): FeatureFlareContextValue;
25
+ declare function useShipItContext(): ShipItContextValue;
28
26
 
29
27
  type BoolFlagState = {
30
28
  value: boolean;
@@ -36,8 +34,8 @@ type BoolFlagsState = {
36
34
  loading: boolean;
37
35
  errors: Record<string, string>;
38
36
  };
39
- declare function useFeatureFlareUser(): [FeatureFlareUserPayload, (next: FeatureFlareUserPayload) => void];
37
+ declare function useShipItUser(): [ShipItUserPayload, (next: ShipItUserPayload) => void];
40
38
  declare function useBoolFlag(flagKey: string, defaultValue?: boolean): BoolFlagState;
41
39
  declare function useBoolFlags(flagKeys: string[], defaultValue?: boolean): BoolFlagsState;
42
40
 
43
- export { FeatureFlareProvider, useBoolFlag, useBoolFlags, useFeatureFlareContext, useFeatureFlareUser };
41
+ export { ShipItProvider, useBoolFlag, useBoolFlags, useShipItContext, useShipItUser };
package/dist/index.d.ts CHANGED
@@ -1,30 +1,28 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { FeatureFlareUserPayload, FeatureFlareClient } from '@featureflare/sdk-js';
4
- export { FeatureFlareUserPayload } from '@featureflare/sdk-js';
3
+ import { ShipItUserPayload, ShipItClient } from '@featureflare/sdk-js';
4
+ export { ShipItUserPayload } from '@featureflare/sdk-js';
5
5
 
6
- type FeatureFlareReactConfig = {
7
- /** Optional: explicit FeatureFlare API base URL. */
8
- apiBaseUrl?: string;
6
+ type ShipItReactConfig = {
9
7
  /** Recommended: use a client key (featureflare_cli_...). */
10
8
  sdkKey?: string;
11
9
  /** Legacy/insecure browser mode: uses /api/v1/eval (no sdkKey). */
12
10
  projectKey?: string;
13
11
  envKey?: string;
14
12
  };
15
- type FeatureFlareContextValue = {
16
- client: FeatureFlareClient;
17
- user: FeatureFlareUserPayload;
18
- setUser: (next: FeatureFlareUserPayload) => void;
13
+ type ShipItContextValue = {
14
+ client: ShipItClient;
15
+ user: ShipItUserPayload;
16
+ setUser: (next: ShipItUserPayload) => void;
19
17
  };
20
- declare function FeatureFlareProvider(props: {
21
- config: FeatureFlareReactConfig;
22
- initialUser: FeatureFlareUserPayload;
23
- user?: FeatureFlareUserPayload;
24
- onUserChange?: (next: FeatureFlareUserPayload) => void;
18
+ declare function ShipItProvider(props: {
19
+ config: ShipItReactConfig;
20
+ initialUser: ShipItUserPayload;
21
+ user?: ShipItUserPayload;
22
+ onUserChange?: (next: ShipItUserPayload) => void;
25
23
  children: React.ReactNode;
26
24
  }): react_jsx_runtime.JSX.Element;
27
- declare function useFeatureFlareContext(): FeatureFlareContextValue;
25
+ declare function useShipItContext(): ShipItContextValue;
28
26
 
29
27
  type BoolFlagState = {
30
28
  value: boolean;
@@ -36,8 +34,8 @@ type BoolFlagsState = {
36
34
  loading: boolean;
37
35
  errors: Record<string, string>;
38
36
  };
39
- declare function useFeatureFlareUser(): [FeatureFlareUserPayload, (next: FeatureFlareUserPayload) => void];
37
+ declare function useShipItUser(): [ShipItUserPayload, (next: ShipItUserPayload) => void];
40
38
  declare function useBoolFlag(flagKey: string, defaultValue?: boolean): BoolFlagState;
41
39
  declare function useBoolFlags(flagKeys: string[], defaultValue?: boolean): BoolFlagsState;
42
40
 
43
- export { FeatureFlareProvider, useBoolFlag, useBoolFlags, useFeatureFlareContext, useFeatureFlareUser };
41
+ export { ShipItProvider, useBoolFlag, useBoolFlags, useShipItContext, useShipItUser };
package/dist/index.js CHANGED
@@ -1,45 +1,39 @@
1
1
  // src/provider.tsx
2
2
  import React, { createContext, useMemo, useState } from "react";
3
- import { FeatureFlareClient } from "@featureflare/sdk-js";
3
+ import { ShipItClient } from "@featureflare/sdk-js";
4
4
  import { jsx } from "react/jsx-runtime";
5
- var FeatureFlareContext = createContext(null);
6
- function FeatureFlareProvider(props) {
5
+ var ShipItContext = createContext(null);
6
+ function ShipItProvider(props) {
7
7
  if (props.user && !props.onUserChange) {
8
- throw new Error("FeatureFlareProvider: when providing `user`, also provide `onUserChange` (controlled mode).");
8
+ throw new Error("ShipItProvider: when providing `user`, also provide `onUserChange` (controlled mode).");
9
9
  }
10
10
  const [internalUser, setInternalUser] = useState(props.initialUser);
11
11
  const user = props.user ?? internalUser;
12
12
  const setUser = props.onUserChange ?? setInternalUser;
13
13
  const client = useMemo(() => {
14
- return new FeatureFlareClient({
15
- apiBaseUrl: props.config.apiBaseUrl,
14
+ return new ShipItClient({
16
15
  sdkKey: props.config.sdkKey,
17
16
  projectKey: props.config.projectKey,
18
17
  envKey: props.config.envKey
19
18
  });
20
- }, [
21
- props.config.apiBaseUrl,
22
- props.config.envKey,
23
- props.config.projectKey,
24
- props.config.sdkKey
25
- ]);
19
+ }, [props.config.envKey, props.config.projectKey, props.config.sdkKey]);
26
20
  const value = useMemo(() => ({ client, user, setUser }), [client, user]);
27
- return /* @__PURE__ */ jsx(FeatureFlareContext.Provider, { value, children: props.children });
21
+ return /* @__PURE__ */ jsx(ShipItContext.Provider, { value, children: props.children });
28
22
  }
29
- function useFeatureFlareContext() {
30
- const ctx = React.useContext(FeatureFlareContext);
31
- if (!ctx) throw new Error("useFeatureFlareContext must be used within <FeatureFlareProvider>.");
23
+ function useShipItContext() {
24
+ const ctx = React.useContext(ShipItContext);
25
+ if (!ctx) throw new Error("useShipItContext must be used within <ShipItProvider>.");
32
26
  return ctx;
33
27
  }
34
28
 
35
29
  // src/hooks.ts
36
30
  import { useEffect, useMemo as useMemo2, useRef, useState as useState2 } from "react";
37
- function useFeatureFlareUser() {
38
- const { user, setUser } = useFeatureFlareContext();
31
+ function useShipItUser() {
32
+ const { user, setUser } = useShipItContext();
39
33
  return [user, setUser];
40
34
  }
41
35
  function useBoolFlag(flagKey, defaultValue = false) {
42
- const { client, user } = useFeatureFlareContext();
36
+ const { client, user } = useShipItContext();
43
37
  const [state, setState] = useState2({ value: defaultValue, loading: true, error: null });
44
38
  const userId = user.id ?? user.key ?? "";
45
39
  const key = useMemo2(() => `${flagKey}:${userId}`, [flagKey, userId]);
@@ -69,7 +63,7 @@ function useBoolFlag(flagKey, defaultValue = false) {
69
63
  return state;
70
64
  }
71
65
  function useBoolFlags(flagKeys, defaultValue = false) {
72
- const { client, user } = useFeatureFlareContext();
66
+ const { client, user } = useShipItContext();
73
67
  const sortedKeys = useMemo2(() => [...flagKeys].map((k) => k.trim()).filter(Boolean).sort(), [flagKeys]);
74
68
  const userId = user.id ?? user.key ?? "";
75
69
  const key = useMemo2(() => `${sortedKeys.join(",")}:${userId}`, [sortedKeys, userId]);
@@ -104,10 +98,10 @@ function useBoolFlags(flagKeys, defaultValue = false) {
104
98
  return state;
105
99
  }
106
100
  export {
107
- FeatureFlareProvider,
101
+ ShipItProvider,
108
102
  useBoolFlag,
109
103
  useBoolFlags,
110
- useFeatureFlareContext,
111
- useFeatureFlareUser
104
+ useShipItContext,
105
+ useShipItUser
112
106
  };
113
107
  //# 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":";AAAA,OAAO,SAAS,eAAe,SAAS,gBAAgB;AACxD,SAAS,0BAAwD;AAkDxD;AAhCT,IAAM,sBAAsB,cAA+C,IAAI;AAExE,SAAS,qBAAqB,OAMlC;AACD,MAAI,MAAM,QAAQ,CAAC,MAAM,cAAc;AACrC,UAAM,IAAI,MAAM,6FAA6F;AAAA,EAC/G;AAEA,QAAM,CAAC,cAAc,eAAe,IAAI,SAAkC,MAAM,WAAW;AAC3F,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,MAAM,gBAAgB;AAEtC,QAAM,SAAS,QAAQ,MAAM;AAC3B,WAAO,IAAI,mBAAmB;AAAA,MAC5B,YAAY,MAAM,OAAO;AAAA,MACzB,QAAQ,MAAM,OAAO;AAAA,MACrB,YAAY,MAAM,OAAO;AAAA,MACzB,QAAQ,MAAM,OAAO;AAAA,IACvB,CAAC;AAAA,EACH,GAAG;AAAA,IACD,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf,CAAC;AAED,QAAM,QAAQ,QAAQ,OAAO,EAAE,QAAQ,MAAM,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC;AACvE,SAAO,oBAAC,oBAAoB,UAApB,EAA6B,OAAe,gBAAM,UAAS;AACrE;AAEO,SAAS,yBAAmD;AACjE,QAAM,MAAM,MAAM,WAAW,mBAAmB;AAChD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,oEAAoE;AAC9F,SAAO;AACT;;;AC1DA,SAAS,WAAW,WAAAA,UAAS,QAAQ,YAAAC,iBAAgB;AAgB9C,SAAS,sBAA0F;AACxG,QAAM,EAAE,MAAM,QAAQ,IAAI,uBAAuB;AACjD,SAAO,CAAC,MAAM,OAAO;AACvB;AAEO,SAAS,YAAY,SAAiB,eAAe,OAAsB;AAChF,QAAM,EAAE,QAAQ,KAAK,IAAI,uBAAuB;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAwB,EAAE,OAAO,cAAc,SAAS,MAAM,OAAO,KAAK,CAAC;AACrG,QAAM,SAAS,KAAK,MAAM,KAAK,OAAO;AACtC,QAAM,MAAMC,SAAQ,MAAM,GAAG,OAAO,IAAI,MAAM,IAAI,CAAC,SAAS,MAAM,CAAC;AACnE,QAAM,UAAU,OAAe,EAAE;AAEjC,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,UAAU;AAChB,YAAQ,UAAU;AAClB,aAAS,CAAC,OAAO,EAAE,GAAG,GAAG,SAAS,MAAM,OAAO,KAAK,EAAE;AAEtD,KAAC,YAAY;AACX,UAAI;AACF,cAAM,IAAI,MAAM,OAAO,KAAK,SAAS,MAAM,YAAY;AACvD,YAAI,UAAW;AACf,YAAI,QAAQ,YAAY,QAAS;AACjC,iBAAS,EAAE,OAAO,GAAG,SAAS,OAAO,OAAO,KAAK,CAAC;AAAA,MACpD,SAAS,GAAG;AACV,YAAI,UAAW;AACf,YAAI,QAAQ,YAAY,QAAS;AACjC,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,EAAE,OAAO,cAAc,SAAS,OAAO,OAAO,IAAI,CAAC;AAAA,MAC9D;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,SAAS,KAAK,IAAI,CAAC;AAE7C,SAAO;AACT;AAEO,SAAS,aAAa,UAAoB,eAAe,OAAuB;AACrF,QAAM,EAAE,QAAQ,KAAK,IAAI,uBAAuB;AAChD,QAAM,aAAaA,SAAQ,MAAM,CAAC,GAAG,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAAC,QAAQ,CAAC;AACtG,QAAM,SAAS,KAAK,MAAM,KAAK,OAAO;AACtC,QAAM,MAAMA,SAAQ,MAAM,GAAG,WAAW,KAAK,GAAG,CAAC,IAAI,MAAM,IAAI,CAAC,YAAY,MAAM,CAAC;AACnF,QAAM,CAAC,OAAO,QAAQ,IAAID,UAAyB,EAAE,QAAQ,CAAC,GAAG,SAAS,MAAM,QAAQ,CAAC,EAAE,CAAC;AAC5F,QAAM,UAAU,OAAe,EAAE;AAEjC,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,UAAU;AAChB,YAAQ,UAAU;AAClB,aAAS,EAAE,QAAQ,CAAC,GAAG,SAAS,MAAM,QAAQ,CAAC,EAAE,CAAC;AAElD,KAAC,YAAY;AACX,YAAM,SAAkC,CAAC;AACzC,YAAM,SAAiC,CAAC;AACxC,YAAM,QAAQ;AAAA,QACZ,WAAW,IAAI,OAAO,YAAY;AAChC,cAAI;AACF,mBAAO,OAAO,IAAI,MAAM,OAAO,KAAK,SAAS,MAAM,YAAY;AAAA,UACjE,SAAS,GAAG;AACV,mBAAO,OAAO,IAAI;AAClB,mBAAO,OAAO,IAAI,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,UAC7D;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI,UAAW;AACf,UAAI,QAAQ,YAAY,QAAS;AACjC,eAAS,EAAE,QAAQ,SAAS,OAAO,OAAO,CAAC;AAAA,IAC7C,GAAG;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,cAAc,KAAK,YAAY,IAAI,CAAC;AAEhD,SAAO;AACT;","names":["useMemo","useState","useState","useMemo"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import React, { createContext, useMemo, useState } from 'react';\nimport { ShipItClient, type ShipItUserPayload } from '@featureflare/sdk-js';\n\ntype ShipItReactConfig = {\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 ShipItContextValue = {\n client: ShipItClient;\n user: ShipItUserPayload;\n setUser: (next: ShipItUserPayload) => void;\n};\n\nconst ShipItContext = createContext<ShipItContextValue | null>(null);\n\nexport function ShipItProvider(props: {\n config: ShipItReactConfig;\n initialUser: ShipItUserPayload;\n user?: ShipItUserPayload;\n onUserChange?: (next: ShipItUserPayload) => void;\n children: React.ReactNode;\n}) {\n if (props.user && !props.onUserChange) {\n throw new Error('ShipItProvider: when providing `user`, also provide `onUserChange` (controlled mode).');\n }\n\n const [internalUser, setInternalUser] = useState<ShipItUserPayload>(props.initialUser);\n const user = props.user ?? internalUser;\n const setUser = props.onUserChange ?? setInternalUser;\n\n const client = useMemo(() => {\n return new ShipItClient({\n sdkKey: props.config.sdkKey,\n projectKey: props.config.projectKey,\n envKey: props.config.envKey\n });\n }, [props.config.envKey, props.config.projectKey, props.config.sdkKey]);\n\n const value = useMemo(() => ({ client, user, setUser }), [client, user]);\n return <ShipItContext.Provider value={value}>{props.children}</ShipItContext.Provider>;\n}\n\nexport function useShipItContext(): ShipItContextValue {\n const ctx = React.useContext(ShipItContext);\n if (!ctx) throw new Error('useShipItContext must be used within <ShipItProvider>.');\n return ctx;\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type { ShipItUserPayload } from '@featureflare/sdk-js';\nimport { useShipItContext } 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 useShipItUser(): [ShipItUserPayload, (next: ShipItUserPayload) => void] {\n const { user, setUser } = useShipItContext();\n return [user, setUser];\n}\n\nexport function useBoolFlag(flagKey: string, defaultValue = false): BoolFlagState {\n const { client, user } = useShipItContext();\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 } = useShipItContext();\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"]}
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",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -33,7 +33,7 @@
33
33
  "react-dom": ">=18"
34
34
  },
35
35
  "dependencies": {
36
- "@featureflare/sdk-js": "0.0.5"
36
+ "@featureflare/sdk-js": "0.0.6"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.2",