@quonfig/react 0.0.10 → 0.0.13
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/CHANGELOG.md +37 -0
- package/README.md +119 -7
- package/dist/index.cjs +63 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +21 -3
- package/dist/index.d.ts +21 -3
- package/dist/index.mjs +64 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.13 - 2026-05-10
|
|
4
|
+
|
|
5
|
+
- **chore: declare `engines.node` >=20.9.0 + pin CI floor (qfg-y7xh).** Adds an explicit
|
|
6
|
+
`engines.node` field to `package.json` so npm warns consumers on unsupported Node, and pins the CI
|
|
7
|
+
matrix floor to 20.9.0 to match. No runtime behavior change.
|
|
8
|
+
|
|
9
|
+
## 0.0.12 - 2026-05-03
|
|
10
|
+
|
|
11
|
+
- **chore!: narrow `react` peer dep to `^18 || ^19` (qfg-bsji).** The advertised range
|
|
12
|
+
(`^16 || ^17 || ^18 || ^19`) was inaccurate since 0.0.10 — `QuonfigProvider` calls
|
|
13
|
+
`React.useSyncExternalStore`, which only exists in React 18+. Install-time signal now matches
|
|
14
|
+
runtime reality. Consumers on React 16/17 were already broken at runtime.
|
|
15
|
+
- **feat: `useFlag(key)` per-key selector hook (qfg-lkpm.6).** Subscribes to a single flag's value
|
|
16
|
+
via `useSyncExternalStore` against the underlying client's notify list. Components using
|
|
17
|
+
`useFlag('foo')` no longer re-render when an unrelated flag changes — `useQuonfig()` continues to
|
|
18
|
+
re-render on every `dataVersion` bump as before.
|
|
19
|
+
- **fix: replace module-level `globalQuonfigIsTaken` flag with `QuonfigClientContext`
|
|
20
|
+
(qfg-lkpm.6).** The flag never reset on unmount, so a Provider that mounted, unmounted, and
|
|
21
|
+
remounted at the top of the tree received a fresh `Quonfig()` instead of the module singleton. The
|
|
22
|
+
new context-based ownership keys off React tree position: a top-level provider claims the
|
|
23
|
+
singleton, nested providers mint fresh clients.
|
|
24
|
+
- **docs: Next.js / RSC integration guide.** Documents `initialFlags`, App Router and Pages Router
|
|
25
|
+
patterns, and hydration-mismatch caveats.
|
|
26
|
+
|
|
27
|
+
## 0.0.10 - 2026-05-02
|
|
28
|
+
|
|
29
|
+
- **Fix (provider): re-render on poll updates + close client on unmount (qfg-daxq, qfg-2acr).**
|
|
30
|
+
Previously, poll-driven config mutations were invisible to React because the provider's value
|
|
31
|
+
`useMemo` only depended on `contextKey`/`loading`/`instanceHash`/`settings`. Now wires the
|
|
32
|
+
`@quonfig/javascript@>=0.0.14` `subscribe()`/`dataVersion` API through
|
|
33
|
+
`React.useSyncExternalStore` so every config mutation (poll fetch, `setConfig`, hydrate) triggers
|
|
34
|
+
a re-render. Also adds a mount-only `useEffect` cleanup that calls `quonfigClient.close()` when
|
|
35
|
+
`QuonfigProvider` unmounts (drains telemetry, stops polling, stops telemetry timers) and resets
|
|
36
|
+
the StrictMode init guard so a remount cleanly re-inits — previously an SPA route swap that
|
|
37
|
+
unmounted the provider left the underlying singleton polling forever and held undrained telemetry.
|
|
38
|
+
- **Peer dep:** `@quonfig/javascript` peer floor bumped to `>=0.0.14`.
|
|
39
|
+
|
|
3
40
|
## 0.0.2 - 2025-10-12
|
|
4
41
|
|
|
5
42
|
- Support re-hydration of flags via QuonfigProvider
|
package/README.md
CHANGED
|
@@ -37,13 +37,14 @@ const WrappedApp = () => {
|
|
|
37
37
|
|
|
38
38
|
Here's an explanation of each provider prop:
|
|
39
39
|
|
|
40
|
-
| property | required | type
|
|
41
|
-
| ------------------- | -------- |
|
|
42
|
-
| `sdkKey` | yes | `string`
|
|
43
|
-
| `onError` | no | `(error) => void`
|
|
44
|
-
| `contextAttributes` | no | `Contexts`
|
|
45
|
-
| `timeout` | no | `number`
|
|
46
|
-
| `pollInterval` | no | `number`
|
|
40
|
+
| property | required | type | purpose |
|
|
41
|
+
| ------------------- | -------- | ------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `sdkKey` | yes | `string` | your Quonfig SDK key |
|
|
43
|
+
| `onError` | no | `(error) => void` | callback invoked if quonfig fails to initialize |
|
|
44
|
+
| `contextAttributes` | no | `Contexts` | this is the context attributes object you passed when setting up the provider |
|
|
45
|
+
| `timeout` | no | `number` | initialization timeout (defaults to 10 seconds) |
|
|
46
|
+
| `pollInterval` | no | `number` | configures quonfig to poll for updates every `pollInterval` ms. |
|
|
47
|
+
| `initialFlags` | no | `Record<string, unknown>` | seed flag values evaluated on the server — see [Next.js / RSC integration](#nextjs--rsc-integration) below. |
|
|
47
48
|
|
|
48
49
|
### Usage in Your Components
|
|
49
50
|
|
|
@@ -78,6 +79,117 @@ Here's an explanation of each property:
|
|
|
78
79
|
| `quonfig` | N/A | the underlying JavaScript quonfig instance |
|
|
79
80
|
| `keys` | N/A | an array of all the flag and config names in the current configuration |
|
|
80
81
|
|
|
82
|
+
### `useFlag` — per-key selector hook
|
|
83
|
+
|
|
84
|
+
`useQuonfig()` re-renders every consumer when _any_ flag value changes. For components that only
|
|
85
|
+
care about one flag, use `useFlag(key)` — it subscribes to that single key and skips re-renders when
|
|
86
|
+
unrelated flags change.
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
import { useFlag } from "@quonfig/react";
|
|
90
|
+
|
|
91
|
+
const Logo = () => {
|
|
92
|
+
const showNewLogo = useFlag("new-logo");
|
|
93
|
+
return <img src={showNewLogo ? newLogo : logo} alt="logo" />;
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If you have a typed config (via `@quonfig/cli generate`), `useFlag` returns the type declared for
|
|
98
|
+
the key.
|
|
99
|
+
|
|
100
|
+
## Next.js / RSC integration
|
|
101
|
+
|
|
102
|
+
The provider runs on the client (it uses `fetch` and `useEffect`), but you often want to seed flag
|
|
103
|
+
values on the server so the first paint reflects real data instead of defaults. Pass evaluated flags
|
|
104
|
+
through the `initialFlags` prop on `QuonfigProvider`.
|
|
105
|
+
|
|
106
|
+
### App Router (RSC)
|
|
107
|
+
|
|
108
|
+
Fetch flags in a Server Component, then pass the evaluated map to a Client Component that owns the
|
|
109
|
+
provider. `QuonfigProvider` itself must be inside a Client Component because of its hooks.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// app/quonfig-wrapper.tsx — Client Component
|
|
113
|
+
"use client";
|
|
114
|
+
|
|
115
|
+
import { QuonfigProvider } from "@quonfig/react";
|
|
116
|
+
|
|
117
|
+
export function QuonfigWrapper({ children, initialFlags, contextAttributes }) {
|
|
118
|
+
return (
|
|
119
|
+
<QuonfigProvider
|
|
120
|
+
sdkKey={process.env.NEXT_PUBLIC_QUONFIG_API_KEY!}
|
|
121
|
+
contextAttributes={contextAttributes}
|
|
122
|
+
initialFlags={initialFlags}
|
|
123
|
+
>
|
|
124
|
+
{children}
|
|
125
|
+
</QuonfigProvider>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// app/layout.tsx — Server Component
|
|
132
|
+
import { QuonfigWrapper } from "./quonfig-wrapper";
|
|
133
|
+
|
|
134
|
+
export default async function RootLayout({ children }) {
|
|
135
|
+
// Evaluate flags on the server with @quonfig/node (or similar) and
|
|
136
|
+
// hand the flat key/value map to the client provider.
|
|
137
|
+
const initialFlags = await evaluateFlagsOnServer({
|
|
138
|
+
user: { id: "1" },
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<html>
|
|
143
|
+
<body>
|
|
144
|
+
<QuonfigWrapper initialFlags={initialFlags} contextAttributes={{ user: { id: "1" } }}>
|
|
145
|
+
{children}
|
|
146
|
+
</QuonfigWrapper>
|
|
147
|
+
</body>
|
|
148
|
+
</html>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`initialFlags` is the flat-map shape `{ flagKey: value }`, e.g.
|
|
154
|
+
`{ "new-logo": true, "retry-count": 3 }`. When `initialFlags` is set, the provider hydrates
|
|
155
|
+
synchronously on first render — no loading flicker — and skips the initial fetch. Subsequent context
|
|
156
|
+
changes still trigger fetches.
|
|
157
|
+
|
|
158
|
+
### Pages Router (`getServerSideProps`)
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
export async function getServerSideProps({ req }) {
|
|
162
|
+
const initialFlags = await evaluateFlagsOnServer(extractContext(req));
|
|
163
|
+
return { props: { initialFlags } };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export default function Page({ initialFlags }) {
|
|
167
|
+
return (
|
|
168
|
+
<QuonfigProvider sdkKey={process.env.NEXT_PUBLIC_QUONFIG_API_KEY} initialFlags={initialFlags}>
|
|
169
|
+
<App />
|
|
170
|
+
</QuonfigProvider>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Hydration mismatch caveats
|
|
176
|
+
|
|
177
|
+
- Pass the **same** `contextAttributes` on the server and the client. If the client has different
|
|
178
|
+
inputs (e.g. it adds attributes from `document` or `window`), the first client render will fetch a
|
|
179
|
+
different evaluation and flag values can flicker.
|
|
180
|
+
- `initialFlags` only applies on the first render. Don't expect changing it later to swap flags out
|
|
181
|
+
— use `setConfig`/poll for that.
|
|
182
|
+
- Don't combine `initialFlags` with `pollInterval` unless you want both — the provider warns at
|
|
183
|
+
runtime if you do.
|
|
184
|
+
|
|
185
|
+
## SSR / multi-tenant rendering
|
|
186
|
+
|
|
187
|
+
`QuonfigProvider` is a client-only component (it uses `useEffect` and `fetch`), so it does not run
|
|
188
|
+
during SSR. The provider's client identity is keyed by React tree position via
|
|
189
|
+
`QuonfigClientContext`: a top-level provider claims the module singleton (so `import { quonfig }`
|
|
190
|
+
consumers see the same instance), and any nested `QuonfigProvider` mints a fresh `Quonfig()` so its
|
|
191
|
+
config can't leak into the parent tree.
|
|
192
|
+
|
|
81
193
|
## Usage in your test suite
|
|
82
194
|
|
|
83
195
|
Wrap the component under test in a `QuonfigTestProvider` and provide a config object to set up your
|
package/dist/index.cjs
CHANGED
|
@@ -12,7 +12,32 @@ var React__default = /*#__PURE__*/_interopDefault(React);
|
|
|
12
12
|
// src/version.ts
|
|
13
13
|
var version_default = "0.0.9";
|
|
14
14
|
|
|
15
|
+
// src/sdkLogger.ts
|
|
16
|
+
var NOOP = () => {
|
|
17
|
+
};
|
|
18
|
+
var PREFIX = "[quonfig]";
|
|
19
|
+
function defaultSdkLogger() {
|
|
20
|
+
return {
|
|
21
|
+
/* eslint-disable no-console */
|
|
22
|
+
debug: (message, ...args) => console.debug(PREFIX, message, ...args),
|
|
23
|
+
info: (message, ...args) => console.info(PREFIX, message, ...args),
|
|
24
|
+
warn: (message, ...args) => console.warn(PREFIX, message, ...args),
|
|
25
|
+
error: (message, ...args) => console.error(PREFIX, message, ...args)
|
|
26
|
+
/* eslint-enable no-console */
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function normalizeLogger(logger) {
|
|
30
|
+
if (!logger) return defaultSdkLogger();
|
|
31
|
+
return {
|
|
32
|
+
debug: logger.debug ? logger.debug.bind(logger) : NOOP,
|
|
33
|
+
info: logger.info ? logger.info.bind(logger) : NOOP,
|
|
34
|
+
warn: logger.warn.bind(logger),
|
|
35
|
+
error: logger.error.bind(logger)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
// src/QuonfigProvider.tsx
|
|
40
|
+
var QuonfigClientContext = React__default.default.createContext(null);
|
|
16
41
|
var defaultContext = {
|
|
17
42
|
get: (_key) => void 0,
|
|
18
43
|
getDuration: (_key) => void 0,
|
|
@@ -46,18 +71,26 @@ function createQuonfigHook(TypesafeClass) {
|
|
|
46
71
|
}
|
|
47
72
|
var useBaseQuonfig = () => React__default.default.useContext(QuonfigContext);
|
|
48
73
|
var useQuonfig = () => useBaseQuonfig();
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
function useFlag(key) {
|
|
75
|
+
var _a;
|
|
76
|
+
const client = (_a = React__default.default.useContext(QuonfigClientContext)) != null ? _a : javascript.quonfig;
|
|
77
|
+
const subscribe = React__default.default.useCallback(
|
|
78
|
+
(onChange) => client.subscribe(onChange),
|
|
79
|
+
[client]
|
|
80
|
+
);
|
|
81
|
+
const getSnapshot = React__default.default.useCallback(() => client.get(key), [client, key]);
|
|
82
|
+
const getServerSnapshot = React__default.default.useCallback(() => void 0, []);
|
|
83
|
+
return React__default.default.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
84
|
+
}
|
|
85
|
+
var useQuonfigClient = () => {
|
|
86
|
+
const parentClient = React__default.default.useContext(QuonfigClientContext);
|
|
87
|
+
const parentClientRef = React__default.default.useRef(parentClient);
|
|
88
|
+
return React__default.default.useMemo(() => parentClientRef.current ? new javascript.Quonfig() : javascript.quonfig, []);
|
|
56
89
|
};
|
|
57
|
-
var getContextKey = (contextAttributes, onError) => {
|
|
90
|
+
var getContextKey = (contextAttributes, logger, onError) => {
|
|
58
91
|
try {
|
|
59
92
|
if (Object.keys(contextAttributes).length === 0) {
|
|
60
|
-
|
|
93
|
+
logger.warn(
|
|
61
94
|
"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context"
|
|
62
95
|
);
|
|
63
96
|
}
|
|
@@ -70,9 +103,8 @@ var getContextKey = (contextAttributes, onError) => {
|
|
|
70
103
|
function QuonfigProvider({
|
|
71
104
|
sdkKey,
|
|
72
105
|
contextAttributes = {},
|
|
73
|
-
onError
|
|
74
|
-
|
|
75
|
-
},
|
|
106
|
+
onError: userOnError,
|
|
107
|
+
logger,
|
|
76
108
|
initialFlags,
|
|
77
109
|
children,
|
|
78
110
|
timeout,
|
|
@@ -84,6 +116,18 @@ function QuonfigProvider({
|
|
|
84
116
|
collectEvaluationSummaries,
|
|
85
117
|
collectLoggerNames
|
|
86
118
|
}) {
|
|
119
|
+
const normalizedLogger = React__default.default.useMemo(() => normalizeLogger(logger), [logger]);
|
|
120
|
+
const onError = React__default.default.useCallback(
|
|
121
|
+
(e) => {
|
|
122
|
+
if (userOnError) {
|
|
123
|
+
userOnError(e);
|
|
124
|
+
} else {
|
|
125
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
126
|
+
normalizedLogger.error(message, e);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
[userOnError, normalizedLogger]
|
|
130
|
+
);
|
|
87
131
|
const settings = {
|
|
88
132
|
sdkKey,
|
|
89
133
|
apiUrl,
|
|
@@ -100,13 +144,13 @@ function QuonfigProvider({
|
|
|
100
144
|
const [loading, setLoading] = React__default.default.useState(true);
|
|
101
145
|
const [initialLoad, setInitialLoad] = React__default.default.useState(true);
|
|
102
146
|
const [loadedContextKey, setLoadedContextKey] = React__default.default.useState("");
|
|
103
|
-
const quonfigClient =
|
|
147
|
+
const quonfigClient = useQuonfigClient();
|
|
104
148
|
const dataVersion = React__default.default.useSyncExternalStore(
|
|
105
149
|
React__default.default.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),
|
|
106
150
|
React__default.default.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),
|
|
107
151
|
React__default.default.useCallback(() => 0, [])
|
|
108
152
|
);
|
|
109
|
-
const contextKey = getContextKey(contextAttributes, onError);
|
|
153
|
+
const contextKey = getContextKey(contextAttributes, normalizedLogger, onError);
|
|
110
154
|
if (initialFlags && initialLoad) {
|
|
111
155
|
quonfigClient.hydrate(initialFlags);
|
|
112
156
|
setInitialLoad(false);
|
|
@@ -114,7 +158,7 @@ function QuonfigProvider({
|
|
|
114
158
|
setLoading(false);
|
|
115
159
|
mostRecentlyLoadingContextKey.current = contextKey;
|
|
116
160
|
if (pollInterval) {
|
|
117
|
-
|
|
161
|
+
normalizedLogger.warn("Polling is not supported when hydrating flags via initialFlags");
|
|
118
162
|
}
|
|
119
163
|
}
|
|
120
164
|
React__default.default.useEffect(() => {
|
|
@@ -196,7 +240,7 @@ function QuonfigProvider({
|
|
|
196
240
|
};
|
|
197
241
|
return baseContext;
|
|
198
242
|
}, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);
|
|
199
|
-
return /* @__PURE__ */ React__default.default.createElement(QuonfigContext.Provider, { value }, children);
|
|
243
|
+
return /* @__PURE__ */ React__default.default.createElement(QuonfigClientContext.Provider, { value: quonfigClient }, /* @__PURE__ */ React__default.default.createElement(QuonfigContext.Provider, { value }, children));
|
|
200
244
|
}
|
|
201
245
|
function QuonfigTestProvider({
|
|
202
246
|
sdkKey,
|
|
@@ -206,7 +250,7 @@ function QuonfigTestProvider({
|
|
|
206
250
|
const get = (key) => config[key];
|
|
207
251
|
const getDuration = (key) => config[key];
|
|
208
252
|
const isEnabled = (key) => !!get(key);
|
|
209
|
-
const quonfigClient =
|
|
253
|
+
const quonfigClient = useQuonfigClient();
|
|
210
254
|
const value = React__default.default.useMemo(() => {
|
|
211
255
|
quonfigClient.get = get;
|
|
212
256
|
quonfigClient.getDuration = getDuration;
|
|
@@ -223,7 +267,7 @@ function QuonfigTestProvider({
|
|
|
223
267
|
};
|
|
224
268
|
return baseContext;
|
|
225
269
|
}, [config, quonfigClient, sdkKey]);
|
|
226
|
-
return /* @__PURE__ */ React__default.default.createElement(QuonfigContext.Provider, { value }, children);
|
|
270
|
+
return /* @__PURE__ */ React__default.default.createElement(QuonfigClientContext.Provider, { value: quonfigClient }, /* @__PURE__ */ React__default.default.createElement(QuonfigContext.Provider, { value }, children));
|
|
227
271
|
}
|
|
228
272
|
|
|
229
273
|
Object.defineProperty(exports, "quonfig", {
|
|
@@ -233,6 +277,7 @@ Object.defineProperty(exports, "quonfig", {
|
|
|
233
277
|
exports.QuonfigProvider = QuonfigProvider;
|
|
234
278
|
exports.QuonfigTestProvider = QuonfigTestProvider;
|
|
235
279
|
exports.createQuonfigHook = createQuonfigHook;
|
|
280
|
+
exports.useFlag = useFlag;
|
|
236
281
|
exports.useQuonfig = useQuonfig;
|
|
237
282
|
//# sourceMappingURL=index.cjs.map
|
|
238
283
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts","../src/QuonfigProvider.tsx","../src/QuonfigTestProvider.tsx"],"names":["quonfig","React","Quonfig","encodeContexts"],"mappings":"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","file":"index.cjs","sourcesContent":["// AUTO-GENERATED from package.json by scripts/generate-version.mjs — do not edit.\nexport default \"0.0.9\";\n","import React, { PropsWithChildren } from \"react\";\nimport {\n quonfig,\n type InitOptions,\n type ConfigValue,\n type Contexts,\n Quonfig,\n TypedFrontEndConfigurationRaw,\n FrontEndConfigurationRaw,\n Duration,\n encodeContexts,\n} from \"@quonfig/javascript\";\nimport reactSdkVersion from \"./version\";\n\n// @quonfig/cli#generate will create interfaces into this namespace for React to consume\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface FrontEndConfigurationAccessor {}\n\nexport type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never\n ? Record<string, unknown>\n : {\n [TypedFlagKey in keyof FrontEndConfigurationAccessor]: FrontEndConfigurationAccessor[TypedFlagKey];\n };\n\ntype ClassMethods<T> = { [K in keyof T]: T[K] };\n\ntype QuonfigTypesafeClass<T = unknown> = new (\n // eslint-disable-next-line no-shadow\n quonfig: Quonfig\n) => T;\n\ntype SharedSettings = Partial<\n Pick<\n InitOptions,\n | \"sdkKey\"\n | \"apiUrls\"\n | \"domain\"\n | \"timeout\"\n | \"collectEvaluationSummaries\"\n | \"collectLoggerNames\"\n >\n> & {\n // Convenience alias for a single API URL — normalized to apiUrls=[apiUrl]\n // before being passed to the underlying SDK, which only accepts apiUrls.\n apiUrl?: string;\n // We need to redefine the afterEvaluationCallback type to ensure proper dynamic resolution of K\n afterEvaluationCallback?: <K extends keyof TypedFrontEndConfigurationRaw>(\n key: K,\n value: TypedFrontEndConfigurationRaw[K],\n contexts: Contexts | undefined\n ) => void;\n pollInterval?: number;\n onError?: (error: Error) => void;\n};\n\nexport type BaseContext = {\n get: <K extends keyof TypedFrontEndConfigurationRaw>(key: K) => TypedFrontEndConfigurationRaw[K];\n getDuration: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends Duration\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => Duration | undefined;\n contextAttributes: Contexts;\n isEnabled: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends boolean\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => boolean;\n loading: boolean;\n quonfig: typeof quonfig;\n keys: (keyof TypedFrontEndConfigurationRaw)[];\n settings: SharedSettings;\n};\n\nexport type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;\n\nexport const defaultContext: BaseContext = {\n get: (_key) => undefined,\n getDuration: (_key) => undefined,\n isEnabled: (_key) => false,\n keys: [],\n loading: true,\n contextAttributes: {},\n quonfig,\n settings: {},\n};\n\nexport const QuonfigContext = React.createContext<ProvidedContext>(\n defaultContext as ProvidedContext\n);\n\n// This is a factory function that creates a fully typed useQuonfig hook for a specific QuonfigTypesafe class\nexport function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>) {\n return function useQuonfigHook(): BaseContext & T {\n const baseContext = React.useContext(QuonfigContext);\n\n // Memoize the typesafe instance to prevent unnecessary constructor calls\n const typesafeInstance = React.useMemo(() => {\n const instance = new TypesafeClass(baseContext.quonfig);\n\n // Copy baseContext properties to typesafeInstance except for `get` + `quonfig`\n Object.assign(instance as any, {\n getDuration: baseContext.getDuration,\n contextAttributes: baseContext.contextAttributes,\n isEnabled: baseContext.isEnabled,\n loading: baseContext.loading,\n keys: baseContext.keys,\n settings: baseContext.settings,\n });\n\n return instance;\n }, [baseContext]);\n\n return typesafeInstance as BaseContext & T;\n };\n}\n\n// Basic hook for general use - requires type parameter\nexport const useBaseQuonfig = () => React.useContext(QuonfigContext);\n\n// General hook that returns the context with any explicit type\nexport const useQuonfig = (): ProvidedContext => useBaseQuonfig() as unknown as ProvidedContext;\n\nlet globalQuonfigIsTaken = false;\n\nexport const assignQuonfigClient = () => {\n if (globalQuonfigIsTaken) {\n return new Quonfig();\n }\n\n globalQuonfigIsTaken = true;\n return quonfig;\n};\n\nexport type QuonfigProviderProps = SharedSettings & {\n sdkKey: string;\n contextAttributes?: Contexts;\n initialFlags?: Record<string, unknown>;\n};\n\nconst getContextKey = (contextAttributes: Contexts, onError: (e: Error) => void): string => {\n try {\n if (Object.keys(contextAttributes).length === 0) {\n // eslint-disable-next-line no-console\n console.warn(\n \"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context\"\n );\n }\n\n return encodeContexts(contextAttributes);\n } catch (e) {\n onError(e as Error);\n return \"\";\n }\n};\n\nfunction QuonfigProvider({\n sdkKey,\n contextAttributes = {},\n onError = (e: unknown) => {\n // eslint-disable-next-line no-console\n console.error(e);\n },\n initialFlags,\n children,\n timeout,\n apiUrl,\n apiUrls,\n domain,\n pollInterval,\n afterEvaluationCallback = undefined,\n collectEvaluationSummaries,\n collectLoggerNames,\n}: PropsWithChildren<QuonfigProviderProps>) {\n const settings = {\n sdkKey,\n apiUrl,\n apiUrls,\n domain,\n timeout,\n pollInterval,\n onError,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n // We use this state to prevent a double-init when useEffect fires due to\n // StrictMode\n const mostRecentlyLoadingContextKey = React.useRef<string | undefined>(undefined);\n // We use this state to pass the loading state to the Provider (updating\n // currentLoadingContextKey won't trigger an update)\n const [loading, setLoading] = React.useState(true);\n const [initialLoad, setInitialLoad] = React.useState(true);\n // Here we track the current identity so we can reload our config when it\n // changes\n const [loadedContextKey, setLoadedContextKey] = React.useState(\"\");\n\n const quonfigClient: Quonfig = React.useMemo(() => assignQuonfigClient(), []);\n\n // qfg-daxq: re-render when the underlying client's in-memory config changes\n // (poll fetch, setConfig, hydrate). Without this the singleton mutates in\n // place and React never sees the update.\n const dataVersion = React.useSyncExternalStore(\n React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),\n React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),\n React.useCallback(() => 0, [])\n );\n\n const contextKey = getContextKey(contextAttributes, onError);\n\n if (initialFlags && initialLoad) {\n quonfigClient.hydrate(initialFlags);\n setInitialLoad(false);\n setLoadedContextKey(contextKey);\n setLoading(false);\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (pollInterval) {\n // eslint-disable-next-line no-console\n console.warn(\"Polling is not supported when hydrating flags via initialFlags\");\n }\n }\n\n React.useEffect(() => {\n setInitialLoad(false);\n\n if (mostRecentlyLoadingContextKey.current === contextKey) {\n return;\n }\n\n setLoading(true);\n try {\n if (mostRecentlyLoadingContextKey.current === undefined) {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (!sdkKey) {\n throw new Error(\"QuonfigProvider: sdkKey is required\");\n }\n\n quonfigClient.clientName = \"react\";\n quonfigClient.clientVersion = reactSdkVersion;\n\n const resolvedApiUrls = apiUrls ?? (apiUrl ? [apiUrl] : undefined);\n\n const initOptions: InitOptions = {\n context: contextAttributes,\n sdkKey,\n apiUrls: resolvedApiUrls,\n domain,\n timeout,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n quonfigClient\n .init(initOptions)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n\n if (pollInterval) {\n quonfigClient.poll({ frequencyInMs: pollInterval });\n }\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n } else {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n quonfigClient\n .updateContext(contextAttributes)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n }\n } catch (e) {\n setLoading(false);\n onError(e as Error);\n }\n }, [\n sdkKey,\n loadedContextKey,\n contextKey,\n loading,\n setLoading,\n onError,\n quonfigClient.instanceHash,\n ]);\n\n // qfg-2acr: drain telemetry + stop polling/telemetry timers when the\n // provider unmounts so route swaps don't leave the singleton polling\n // forever. Mount-only deps so context-attribute changes don't tear down\n // the SDK. In React StrictMode the synthetic unmount fires too — we\n // reset the init-guard ref so the next mount cleanly re-inits.\n React.useEffect(\n () => () => {\n quonfigClient.close().catch(() => {});\n mostRecentlyLoadingContextKey.current = undefined;\n },\n [quonfigClient]\n );\n\n const value = React.useMemo(() => {\n const baseContext: ProvidedContext = {\n isEnabled: quonfigClient.isEnabled.bind(quonfigClient),\n contextAttributes,\n get: quonfigClient.get.bind(quonfigClient),\n getDuration: quonfigClient.getDuration.bind(quonfigClient),\n keys: Object.keys(quonfigClient.extract()),\n quonfig: quonfigClient,\n loading,\n settings,\n };\n\n return baseContext;\n }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);\n\n return <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>;\n}\n\nexport { QuonfigProvider, ConfigValue, SharedSettings, QuonfigTypesafeClass };\n","import React, { PropsWithChildren } from \"react\";\nimport { QuonfigContext, assignQuonfigClient, ProvidedContext } from \"./QuonfigProvider\";\n\nexport type QuonfigTestProviderProps = {\n config: Record<string, any>;\n sdkKey?: string;\n};\n\nfunction QuonfigTestProvider({\n sdkKey,\n config,\n children,\n}: PropsWithChildren<QuonfigTestProviderProps>) {\n const get = (key: string) => config[key];\n const getDuration = (key: string) => config[key];\n const isEnabled = (key: string) => !!get(key);\n\n const quonfigClient = React.useMemo(() => assignQuonfigClient(), []);\n\n const value = React.useMemo(() => {\n quonfigClient.get = get;\n quonfigClient.getDuration = getDuration;\n quonfigClient.isEnabled = isEnabled;\n\n const baseContext: ProvidedContext = {\n isEnabled,\n contextAttributes: config.contextAttributes,\n get,\n getDuration,\n loading: false,\n quonfig: quonfigClient,\n keys: Object.keys(config),\n settings: { sdkKey: sdkKey ?? \"fake-sdk-key-via-the-test-provider\" },\n };\n\n return baseContext;\n }, [config, quonfigClient, sdkKey]);\n\n return <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>;\n}\n\nexport { QuonfigTestProvider };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/sdkLogger.ts","../src/QuonfigProvider.tsx","../src/QuonfigTestProvider.tsx"],"names":["React","quonfig","Quonfig","encodeContexts"],"mappings":"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","file":"index.cjs","sourcesContent":["// AUTO-GENERATED from package.json by scripts/generate-version.mjs — do not edit.\nexport default \"0.0.9\";\n","/**\n * Pluggable logger interface for SDK-internal warnings and errors.\n *\n * Shape mirrors @quonfig/node so the contract is uniform across the\n * TypeScript SDKs: `warn` and `error` are required; `debug` and `info` are\n * optional and become no-ops when the supplied logger does not implement\n * them.\n */\nexport interface Logger {\n debug?(message: string, ...args: unknown[]): void;\n info?(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nexport interface NormalizedLogger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nconst NOOP = (): void => {};\n\nconst PREFIX = \"[quonfig]\";\n\nfunction defaultSdkLogger(): NormalizedLogger {\n return {\n /* eslint-disable no-console */\n debug: (message, ...args) => console.debug(PREFIX, message, ...args),\n info: (message, ...args) => console.info(PREFIX, message, ...args),\n warn: (message, ...args) => console.warn(PREFIX, message, ...args),\n error: (message, ...args) => console.error(PREFIX, message, ...args),\n /* eslint-enable no-console */\n };\n}\n\nexport function normalizeLogger(logger: Logger | undefined): NormalizedLogger {\n if (!logger) return defaultSdkLogger();\n return {\n debug: logger.debug ? logger.debug.bind(logger) : NOOP,\n info: logger.info ? logger.info.bind(logger) : NOOP,\n warn: logger.warn.bind(logger),\n error: logger.error.bind(logger),\n };\n}\n","import React, { PropsWithChildren } from \"react\";\nimport {\n quonfig,\n type InitOptions,\n type ConfigValue,\n type Contexts,\n Quonfig,\n TypedFrontEndConfigurationRaw,\n FrontEndConfigurationRaw,\n Duration,\n encodeContexts,\n} from \"@quonfig/javascript\";\nimport reactSdkVersion from \"./version\";\nimport { normalizeLogger, type Logger, type NormalizedLogger } from \"./sdkLogger\";\n\n// qfg-lkpm.6: per-tree owner context. The value is the active Quonfig client\n// for this provider subtree. A null value means no Provider is above us, so\n// the next mount can claim the module-level singleton; a non-null value\n// signals \"you're nested, mint a fresh client\". This replaces the previous\n// module-level `globalQuonfigIsTaken` flag, which never reset and so leaked\n// state across test runs and (in principle) across SSR render trees.\nconst QuonfigClientContext = React.createContext<Quonfig | null>(null);\n\n// @quonfig/cli#generate will create interfaces into this namespace for React to consume\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface FrontEndConfigurationAccessor {}\n\nexport type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never\n ? Record<string, unknown>\n : {\n [TypedFlagKey in keyof FrontEndConfigurationAccessor]: FrontEndConfigurationAccessor[TypedFlagKey];\n };\n\ntype ClassMethods<T> = { [K in keyof T]: T[K] };\n\ntype QuonfigTypesafeClass<T = unknown> = new (\n // eslint-disable-next-line no-shadow\n quonfig: Quonfig\n) => T;\n\ntype SharedSettings = Partial<\n Pick<\n InitOptions,\n | \"sdkKey\"\n | \"apiUrls\"\n | \"domain\"\n | \"timeout\"\n | \"collectEvaluationSummaries\"\n | \"collectLoggerNames\"\n >\n> & {\n // Convenience alias for a single API URL — normalized to apiUrls=[apiUrl]\n // before being passed to the underlying SDK, which only accepts apiUrls.\n apiUrl?: string;\n // We need to redefine the afterEvaluationCallback type to ensure proper dynamic resolution of K\n afterEvaluationCallback?: <K extends keyof TypedFrontEndConfigurationRaw>(\n key: K,\n value: TypedFrontEndConfigurationRaw[K],\n contexts: Contexts | undefined\n ) => void;\n pollInterval?: number;\n onError?: (error: Error) => void;\n};\n\nexport type BaseContext = {\n get: <K extends keyof TypedFrontEndConfigurationRaw>(key: K) => TypedFrontEndConfigurationRaw[K];\n getDuration: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends Duration\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => Duration | undefined;\n contextAttributes: Contexts;\n isEnabled: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends boolean\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => boolean;\n loading: boolean;\n quonfig: typeof quonfig;\n keys: (keyof TypedFrontEndConfigurationRaw)[];\n settings: SharedSettings;\n};\n\nexport type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;\n\nexport const defaultContext: BaseContext = {\n get: (_key) => undefined,\n getDuration: (_key) => undefined,\n isEnabled: (_key) => false,\n keys: [],\n loading: true,\n contextAttributes: {},\n quonfig,\n settings: {},\n};\n\nexport const QuonfigContext = React.createContext<ProvidedContext>(\n defaultContext as ProvidedContext\n);\n\n// This is a factory function that creates a fully typed useQuonfig hook for a specific QuonfigTypesafe class\nexport function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>) {\n return function useQuonfigHook(): BaseContext & T {\n const baseContext = React.useContext(QuonfigContext);\n\n // Memoize the typesafe instance to prevent unnecessary constructor calls\n const typesafeInstance = React.useMemo(() => {\n const instance = new TypesafeClass(baseContext.quonfig);\n\n // Copy baseContext properties to typesafeInstance except for `get` + `quonfig`\n Object.assign(instance as any, {\n getDuration: baseContext.getDuration,\n contextAttributes: baseContext.contextAttributes,\n isEnabled: baseContext.isEnabled,\n loading: baseContext.loading,\n keys: baseContext.keys,\n settings: baseContext.settings,\n });\n\n return instance;\n }, [baseContext]);\n\n return typesafeInstance as BaseContext & T;\n };\n}\n\n// Basic hook for general use - requires type parameter\nexport const useBaseQuonfig = () => React.useContext(QuonfigContext);\n\n// General hook that returns the context with any explicit type\nexport const useQuonfig = (): ProvidedContext => useBaseQuonfig() as unknown as ProvidedContext;\n\n// qfg-lkpm.6: per-key selector hook. Subscribes via the underlying client's\n// notify list rather than React context, so a flag mutation only re-renders\n// components whose selected key actually changed. `useQuonfig()` re-renders\n// on every dataVersion bump because the context value identity changes; this\n// hook bypasses that.\nexport function useFlag<K extends keyof TypedFrontEndConfigurationRaw>(\n key: K\n): TypedFrontEndConfigurationRaw[K];\nexport function useFlag(key: string): ConfigValue;\nexport function useFlag(key: string): ConfigValue {\n const client = React.useContext(QuonfigClientContext) ?? quonfig;\n const subscribe = React.useCallback(\n (onChange: () => void) => client.subscribe(onChange),\n [client]\n );\n const getSnapshot = React.useCallback(() => client.get(key), [client, key]);\n const getServerSnapshot = React.useCallback((): ConfigValue => undefined, []);\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n// qfg-lkpm.6: replacement for the old module-level `globalQuonfigIsTaken`\n// flag. A provider asks \"is there already a Quonfig client above me in the\n// React tree?\". If yes, mint a fresh client (multi-tenant nesting); if no,\n// claim the module singleton so non-React code that imports `quonfig`\n// directly sees the same instance.\nexport const useQuonfigClient = (): Quonfig => {\n const parentClient = React.useContext(QuonfigClientContext);\n // Mount-only: parent context is fixed for the lifetime of this provider.\n const parentClientRef = React.useRef(parentClient);\n return React.useMemo(() => (parentClientRef.current ? new Quonfig() : quonfig), []);\n};\n\nexport type QuonfigProviderProps = SharedSettings & {\n sdkKey: string;\n contextAttributes?: Contexts;\n initialFlags?: Record<string, unknown>;\n logger?: Logger;\n};\n\nconst getContextKey = (\n contextAttributes: Contexts,\n logger: NormalizedLogger,\n onError: (e: Error) => void\n): string => {\n try {\n if (Object.keys(contextAttributes).length === 0) {\n logger.warn(\n \"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context\"\n );\n }\n\n return encodeContexts(contextAttributes);\n } catch (e) {\n onError(e as Error);\n return \"\";\n }\n};\n\nfunction QuonfigProvider({\n sdkKey,\n contextAttributes = {},\n onError: userOnError,\n logger,\n initialFlags,\n children,\n timeout,\n apiUrl,\n apiUrls,\n domain,\n pollInterval,\n afterEvaluationCallback = undefined,\n collectEvaluationSummaries,\n collectLoggerNames,\n}: PropsWithChildren<QuonfigProviderProps>) {\n const normalizedLogger = React.useMemo(() => normalizeLogger(logger), [logger]);\n const onError = React.useCallback(\n (e: unknown) => {\n if (userOnError) {\n userOnError(e as Error);\n } else {\n const message = e instanceof Error ? e.message : String(e);\n normalizedLogger.error(message, e);\n }\n },\n [userOnError, normalizedLogger]\n );\n const settings = {\n sdkKey,\n apiUrl,\n apiUrls,\n domain,\n timeout,\n pollInterval,\n onError,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n // We use this state to prevent a double-init when useEffect fires due to\n // StrictMode\n const mostRecentlyLoadingContextKey = React.useRef<string | undefined>(undefined);\n // We use this state to pass the loading state to the Provider (updating\n // currentLoadingContextKey won't trigger an update)\n const [loading, setLoading] = React.useState(true);\n const [initialLoad, setInitialLoad] = React.useState(true);\n // Here we track the current identity so we can reload our config when it\n // changes\n const [loadedContextKey, setLoadedContextKey] = React.useState(\"\");\n\n const quonfigClient: Quonfig = useQuonfigClient();\n\n // qfg-daxq: re-render when the underlying client's in-memory config changes\n // (poll fetch, setConfig, hydrate). Without this the singleton mutates in\n // place and React never sees the update.\n const dataVersion = React.useSyncExternalStore(\n React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),\n React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),\n React.useCallback(() => 0, [])\n );\n\n const contextKey = getContextKey(contextAttributes, normalizedLogger, onError);\n\n if (initialFlags && initialLoad) {\n quonfigClient.hydrate(initialFlags);\n setInitialLoad(false);\n setLoadedContextKey(contextKey);\n setLoading(false);\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (pollInterval) {\n normalizedLogger.warn(\"Polling is not supported when hydrating flags via initialFlags\");\n }\n }\n\n React.useEffect(() => {\n setInitialLoad(false);\n\n if (mostRecentlyLoadingContextKey.current === contextKey) {\n return;\n }\n\n setLoading(true);\n try {\n if (mostRecentlyLoadingContextKey.current === undefined) {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (!sdkKey) {\n throw new Error(\"QuonfigProvider: sdkKey is required\");\n }\n\n quonfigClient.clientName = \"react\";\n quonfigClient.clientVersion = reactSdkVersion;\n\n const resolvedApiUrls = apiUrls ?? (apiUrl ? [apiUrl] : undefined);\n\n const initOptions: InitOptions = {\n context: contextAttributes,\n sdkKey,\n apiUrls: resolvedApiUrls,\n domain,\n timeout,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n quonfigClient\n .init(initOptions)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n\n if (pollInterval) {\n quonfigClient.poll({ frequencyInMs: pollInterval });\n }\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n } else {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n quonfigClient\n .updateContext(contextAttributes)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n }\n } catch (e) {\n setLoading(false);\n onError(e as Error);\n }\n }, [\n sdkKey,\n loadedContextKey,\n contextKey,\n loading,\n setLoading,\n onError,\n quonfigClient.instanceHash,\n ]);\n\n // qfg-2acr: drain telemetry + stop polling/telemetry timers when the\n // provider unmounts so route swaps don't leave the singleton polling\n // forever. Mount-only deps so context-attribute changes don't tear down\n // the SDK. In React StrictMode the synthetic unmount fires too — we\n // reset the init-guard ref so the next mount cleanly re-inits.\n React.useEffect(\n () => () => {\n quonfigClient.close().catch(() => {});\n mostRecentlyLoadingContextKey.current = undefined;\n },\n [quonfigClient]\n );\n\n const value = React.useMemo(() => {\n const baseContext: ProvidedContext = {\n isEnabled: quonfigClient.isEnabled.bind(quonfigClient),\n contextAttributes,\n get: quonfigClient.get.bind(quonfigClient),\n getDuration: quonfigClient.getDuration.bind(quonfigClient),\n keys: Object.keys(quonfigClient.extract()),\n quonfig: quonfigClient,\n loading,\n settings,\n };\n\n return baseContext;\n }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);\n\n return (\n <QuonfigClientContext.Provider value={quonfigClient}>\n <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>\n </QuonfigClientContext.Provider>\n );\n}\n\nexport { QuonfigProvider, QuonfigClientContext, ConfigValue, SharedSettings, QuonfigTypesafeClass };\n","import React, { PropsWithChildren } from \"react\";\nimport {\n QuonfigContext,\n QuonfigClientContext,\n useQuonfigClient,\n ProvidedContext,\n} from \"./QuonfigProvider\";\n\nexport type QuonfigTestProviderProps = {\n config: Record<string, any>;\n sdkKey?: string;\n};\n\nfunction QuonfigTestProvider({\n sdkKey,\n config,\n children,\n}: PropsWithChildren<QuonfigTestProviderProps>) {\n const get = (key: string) => config[key];\n const getDuration = (key: string) => config[key];\n const isEnabled = (key: string) => !!get(key);\n\n const quonfigClient = useQuonfigClient();\n\n const value = React.useMemo(() => {\n quonfigClient.get = get;\n quonfigClient.getDuration = getDuration;\n quonfigClient.isEnabled = isEnabled;\n\n const baseContext: ProvidedContext = {\n isEnabled,\n contextAttributes: config.contextAttributes,\n get,\n getDuration,\n loading: false,\n quonfig: quonfigClient,\n keys: Object.keys(config),\n settings: { sdkKey: sdkKey ?? \"fake-sdk-key-via-the-test-provider\" },\n };\n\n return baseContext;\n }, [config, quonfigClient, sdkKey]);\n\n return (\n <QuonfigClientContext.Provider value={quonfigClient}>\n <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>\n </QuonfigClientContext.Provider>\n );\n}\n\nexport { QuonfigTestProvider };\n"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { InitOptions, TypedFrontEndConfigurationRaw, Contexts, FrontEndConfigurationRaw, Duration, quonfig, Quonfig } from '@quonfig/javascript';
|
|
1
|
+
import { InitOptions, TypedFrontEndConfigurationRaw, Contexts, FrontEndConfigurationRaw, Duration, quonfig, Quonfig, ConfigValue } from '@quonfig/javascript';
|
|
2
2
|
export { ConfigValue, Contexts, quonfig } from '@quonfig/javascript';
|
|
3
3
|
import React, { PropsWithChildren } from 'react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Pluggable logger interface for SDK-internal warnings and errors.
|
|
7
|
+
*
|
|
8
|
+
* Shape mirrors @quonfig/node so the contract is uniform across the
|
|
9
|
+
* TypeScript SDKs: `warn` and `error` are required; `debug` and `info` are
|
|
10
|
+
* optional and become no-ops when the supplied logger does not implement
|
|
11
|
+
* them.
|
|
12
|
+
*/
|
|
13
|
+
interface Logger {
|
|
14
|
+
debug?(message: string, ...args: unknown[]): void;
|
|
15
|
+
info?(message: string, ...args: unknown[]): void;
|
|
16
|
+
warn(message: string, ...args: unknown[]): void;
|
|
17
|
+
error(message: string, ...args: unknown[]): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
interface FrontEndConfigurationAccessor {
|
|
6
21
|
}
|
|
7
22
|
type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never ? Record<string, unknown> : {
|
|
@@ -34,12 +49,15 @@ type BaseContext = {
|
|
|
34
49
|
type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;
|
|
35
50
|
declare function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>): () => BaseContext & T;
|
|
36
51
|
declare const useQuonfig: () => ProvidedContext;
|
|
52
|
+
declare function useFlag<K extends keyof TypedFrontEndConfigurationRaw>(key: K): TypedFrontEndConfigurationRaw[K];
|
|
53
|
+
declare function useFlag(key: string): ConfigValue;
|
|
37
54
|
type QuonfigProviderProps = SharedSettings & {
|
|
38
55
|
sdkKey: string;
|
|
39
56
|
contextAttributes?: Contexts;
|
|
40
57
|
initialFlags?: Record<string, unknown>;
|
|
58
|
+
logger?: Logger;
|
|
41
59
|
};
|
|
42
|
-
declare function QuonfigProvider({ sdkKey, contextAttributes, onError, initialFlags, children, timeout, apiUrl, apiUrls, domain, pollInterval, afterEvaluationCallback, collectEvaluationSummaries, collectLoggerNames, }: PropsWithChildren<QuonfigProviderProps>): React.JSX.Element;
|
|
60
|
+
declare function QuonfigProvider({ sdkKey, contextAttributes, onError: userOnError, logger, initialFlags, children, timeout, apiUrl, apiUrls, domain, pollInterval, afterEvaluationCallback, collectEvaluationSummaries, collectLoggerNames, }: PropsWithChildren<QuonfigProviderProps>): React.JSX.Element;
|
|
43
61
|
|
|
44
62
|
type QuonfigTestProviderProps = {
|
|
45
63
|
config: Record<string, any>;
|
|
@@ -47,4 +65,4 @@ type QuonfigTestProviderProps = {
|
|
|
47
65
|
};
|
|
48
66
|
declare function QuonfigTestProvider({ sdkKey, config, children, }: PropsWithChildren<QuonfigTestProviderProps>): React.JSX.Element;
|
|
49
67
|
|
|
50
|
-
export { type FrontEndConfigurationAccessor, type ProvidedContext, QuonfigProvider, type QuonfigProviderProps, QuonfigTestProvider, type QuonfigTestProviderProps, type QuonfigTypesafeClass, type SharedSettings, type TypedFrontEndConfigurationAccessor, createQuonfigHook, useQuonfig };
|
|
68
|
+
export { type FrontEndConfigurationAccessor, type Logger, type ProvidedContext, QuonfigProvider, type QuonfigProviderProps, QuonfigTestProvider, type QuonfigTestProviderProps, type QuonfigTypesafeClass, type SharedSettings, type TypedFrontEndConfigurationAccessor, createQuonfigHook, useFlag, useQuonfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { InitOptions, TypedFrontEndConfigurationRaw, Contexts, FrontEndConfigurationRaw, Duration, quonfig, Quonfig } from '@quonfig/javascript';
|
|
1
|
+
import { InitOptions, TypedFrontEndConfigurationRaw, Contexts, FrontEndConfigurationRaw, Duration, quonfig, Quonfig, ConfigValue } from '@quonfig/javascript';
|
|
2
2
|
export { ConfigValue, Contexts, quonfig } from '@quonfig/javascript';
|
|
3
3
|
import React, { PropsWithChildren } from 'react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Pluggable logger interface for SDK-internal warnings and errors.
|
|
7
|
+
*
|
|
8
|
+
* Shape mirrors @quonfig/node so the contract is uniform across the
|
|
9
|
+
* TypeScript SDKs: `warn` and `error` are required; `debug` and `info` are
|
|
10
|
+
* optional and become no-ops when the supplied logger does not implement
|
|
11
|
+
* them.
|
|
12
|
+
*/
|
|
13
|
+
interface Logger {
|
|
14
|
+
debug?(message: string, ...args: unknown[]): void;
|
|
15
|
+
info?(message: string, ...args: unknown[]): void;
|
|
16
|
+
warn(message: string, ...args: unknown[]): void;
|
|
17
|
+
error(message: string, ...args: unknown[]): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
interface FrontEndConfigurationAccessor {
|
|
6
21
|
}
|
|
7
22
|
type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never ? Record<string, unknown> : {
|
|
@@ -34,12 +49,15 @@ type BaseContext = {
|
|
|
34
49
|
type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;
|
|
35
50
|
declare function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>): () => BaseContext & T;
|
|
36
51
|
declare const useQuonfig: () => ProvidedContext;
|
|
52
|
+
declare function useFlag<K extends keyof TypedFrontEndConfigurationRaw>(key: K): TypedFrontEndConfigurationRaw[K];
|
|
53
|
+
declare function useFlag(key: string): ConfigValue;
|
|
37
54
|
type QuonfigProviderProps = SharedSettings & {
|
|
38
55
|
sdkKey: string;
|
|
39
56
|
contextAttributes?: Contexts;
|
|
40
57
|
initialFlags?: Record<string, unknown>;
|
|
58
|
+
logger?: Logger;
|
|
41
59
|
};
|
|
42
|
-
declare function QuonfigProvider({ sdkKey, contextAttributes, onError, initialFlags, children, timeout, apiUrl, apiUrls, domain, pollInterval, afterEvaluationCallback, collectEvaluationSummaries, collectLoggerNames, }: PropsWithChildren<QuonfigProviderProps>): React.JSX.Element;
|
|
60
|
+
declare function QuonfigProvider({ sdkKey, contextAttributes, onError: userOnError, logger, initialFlags, children, timeout, apiUrl, apiUrls, domain, pollInterval, afterEvaluationCallback, collectEvaluationSummaries, collectLoggerNames, }: PropsWithChildren<QuonfigProviderProps>): React.JSX.Element;
|
|
43
61
|
|
|
44
62
|
type QuonfigTestProviderProps = {
|
|
45
63
|
config: Record<string, any>;
|
|
@@ -47,4 +65,4 @@ type QuonfigTestProviderProps = {
|
|
|
47
65
|
};
|
|
48
66
|
declare function QuonfigTestProvider({ sdkKey, config, children, }: PropsWithChildren<QuonfigTestProviderProps>): React.JSX.Element;
|
|
49
67
|
|
|
50
|
-
export { type FrontEndConfigurationAccessor, type ProvidedContext, QuonfigProvider, type QuonfigProviderProps, QuonfigTestProvider, type QuonfigTestProviderProps, type QuonfigTypesafeClass, type SharedSettings, type TypedFrontEndConfigurationAccessor, createQuonfigHook, useQuonfig };
|
|
68
|
+
export { type FrontEndConfigurationAccessor, type Logger, type ProvidedContext, QuonfigProvider, type QuonfigProviderProps, QuonfigTestProvider, type QuonfigTestProviderProps, type QuonfigTypesafeClass, type SharedSettings, type TypedFrontEndConfigurationAccessor, createQuonfigHook, useFlag, useQuonfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { quonfig,
|
|
1
|
+
import { quonfig, Quonfig, encodeContexts } from '@quonfig/javascript';
|
|
2
2
|
export { quonfig } from '@quonfig/javascript';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
|
|
@@ -7,7 +7,32 @@ import React from 'react';
|
|
|
7
7
|
// src/version.ts
|
|
8
8
|
var version_default = "0.0.9";
|
|
9
9
|
|
|
10
|
+
// src/sdkLogger.ts
|
|
11
|
+
var NOOP = () => {
|
|
12
|
+
};
|
|
13
|
+
var PREFIX = "[quonfig]";
|
|
14
|
+
function defaultSdkLogger() {
|
|
15
|
+
return {
|
|
16
|
+
/* eslint-disable no-console */
|
|
17
|
+
debug: (message, ...args) => console.debug(PREFIX, message, ...args),
|
|
18
|
+
info: (message, ...args) => console.info(PREFIX, message, ...args),
|
|
19
|
+
warn: (message, ...args) => console.warn(PREFIX, message, ...args),
|
|
20
|
+
error: (message, ...args) => console.error(PREFIX, message, ...args)
|
|
21
|
+
/* eslint-enable no-console */
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function normalizeLogger(logger) {
|
|
25
|
+
if (!logger) return defaultSdkLogger();
|
|
26
|
+
return {
|
|
27
|
+
debug: logger.debug ? logger.debug.bind(logger) : NOOP,
|
|
28
|
+
info: logger.info ? logger.info.bind(logger) : NOOP,
|
|
29
|
+
warn: logger.warn.bind(logger),
|
|
30
|
+
error: logger.error.bind(logger)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
10
34
|
// src/QuonfigProvider.tsx
|
|
35
|
+
var QuonfigClientContext = React.createContext(null);
|
|
11
36
|
var defaultContext = {
|
|
12
37
|
get: (_key) => void 0,
|
|
13
38
|
getDuration: (_key) => void 0,
|
|
@@ -41,18 +66,26 @@ function createQuonfigHook(TypesafeClass) {
|
|
|
41
66
|
}
|
|
42
67
|
var useBaseQuonfig = () => React.useContext(QuonfigContext);
|
|
43
68
|
var useQuonfig = () => useBaseQuonfig();
|
|
44
|
-
|
|
45
|
-
var
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
69
|
+
function useFlag(key) {
|
|
70
|
+
var _a;
|
|
71
|
+
const client = (_a = React.useContext(QuonfigClientContext)) != null ? _a : quonfig;
|
|
72
|
+
const subscribe = React.useCallback(
|
|
73
|
+
(onChange) => client.subscribe(onChange),
|
|
74
|
+
[client]
|
|
75
|
+
);
|
|
76
|
+
const getSnapshot = React.useCallback(() => client.get(key), [client, key]);
|
|
77
|
+
const getServerSnapshot = React.useCallback(() => void 0, []);
|
|
78
|
+
return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
79
|
+
}
|
|
80
|
+
var useQuonfigClient = () => {
|
|
81
|
+
const parentClient = React.useContext(QuonfigClientContext);
|
|
82
|
+
const parentClientRef = React.useRef(parentClient);
|
|
83
|
+
return React.useMemo(() => parentClientRef.current ? new Quonfig() : quonfig, []);
|
|
51
84
|
};
|
|
52
|
-
var getContextKey = (contextAttributes, onError) => {
|
|
85
|
+
var getContextKey = (contextAttributes, logger, onError) => {
|
|
53
86
|
try {
|
|
54
87
|
if (Object.keys(contextAttributes).length === 0) {
|
|
55
|
-
|
|
88
|
+
logger.warn(
|
|
56
89
|
"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context"
|
|
57
90
|
);
|
|
58
91
|
}
|
|
@@ -65,9 +98,8 @@ var getContextKey = (contextAttributes, onError) => {
|
|
|
65
98
|
function QuonfigProvider({
|
|
66
99
|
sdkKey,
|
|
67
100
|
contextAttributes = {},
|
|
68
|
-
onError
|
|
69
|
-
|
|
70
|
-
},
|
|
101
|
+
onError: userOnError,
|
|
102
|
+
logger,
|
|
71
103
|
initialFlags,
|
|
72
104
|
children,
|
|
73
105
|
timeout,
|
|
@@ -79,6 +111,18 @@ function QuonfigProvider({
|
|
|
79
111
|
collectEvaluationSummaries,
|
|
80
112
|
collectLoggerNames
|
|
81
113
|
}) {
|
|
114
|
+
const normalizedLogger = React.useMemo(() => normalizeLogger(logger), [logger]);
|
|
115
|
+
const onError = React.useCallback(
|
|
116
|
+
(e) => {
|
|
117
|
+
if (userOnError) {
|
|
118
|
+
userOnError(e);
|
|
119
|
+
} else {
|
|
120
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
121
|
+
normalizedLogger.error(message, e);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
[userOnError, normalizedLogger]
|
|
125
|
+
);
|
|
82
126
|
const settings = {
|
|
83
127
|
sdkKey,
|
|
84
128
|
apiUrl,
|
|
@@ -95,13 +139,13 @@ function QuonfigProvider({
|
|
|
95
139
|
const [loading, setLoading] = React.useState(true);
|
|
96
140
|
const [initialLoad, setInitialLoad] = React.useState(true);
|
|
97
141
|
const [loadedContextKey, setLoadedContextKey] = React.useState("");
|
|
98
|
-
const quonfigClient =
|
|
142
|
+
const quonfigClient = useQuonfigClient();
|
|
99
143
|
const dataVersion = React.useSyncExternalStore(
|
|
100
144
|
React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),
|
|
101
145
|
React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),
|
|
102
146
|
React.useCallback(() => 0, [])
|
|
103
147
|
);
|
|
104
|
-
const contextKey = getContextKey(contextAttributes, onError);
|
|
148
|
+
const contextKey = getContextKey(contextAttributes, normalizedLogger, onError);
|
|
105
149
|
if (initialFlags && initialLoad) {
|
|
106
150
|
quonfigClient.hydrate(initialFlags);
|
|
107
151
|
setInitialLoad(false);
|
|
@@ -109,7 +153,7 @@ function QuonfigProvider({
|
|
|
109
153
|
setLoading(false);
|
|
110
154
|
mostRecentlyLoadingContextKey.current = contextKey;
|
|
111
155
|
if (pollInterval) {
|
|
112
|
-
|
|
156
|
+
normalizedLogger.warn("Polling is not supported when hydrating flags via initialFlags");
|
|
113
157
|
}
|
|
114
158
|
}
|
|
115
159
|
React.useEffect(() => {
|
|
@@ -191,7 +235,7 @@ function QuonfigProvider({
|
|
|
191
235
|
};
|
|
192
236
|
return baseContext;
|
|
193
237
|
}, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);
|
|
194
|
-
return /* @__PURE__ */ React.createElement(QuonfigContext.Provider, { value }, children);
|
|
238
|
+
return /* @__PURE__ */ React.createElement(QuonfigClientContext.Provider, { value: quonfigClient }, /* @__PURE__ */ React.createElement(QuonfigContext.Provider, { value }, children));
|
|
195
239
|
}
|
|
196
240
|
function QuonfigTestProvider({
|
|
197
241
|
sdkKey,
|
|
@@ -201,7 +245,7 @@ function QuonfigTestProvider({
|
|
|
201
245
|
const get = (key) => config[key];
|
|
202
246
|
const getDuration = (key) => config[key];
|
|
203
247
|
const isEnabled = (key) => !!get(key);
|
|
204
|
-
const quonfigClient =
|
|
248
|
+
const quonfigClient = useQuonfigClient();
|
|
205
249
|
const value = React.useMemo(() => {
|
|
206
250
|
quonfigClient.get = get;
|
|
207
251
|
quonfigClient.getDuration = getDuration;
|
|
@@ -218,9 +262,9 @@ function QuonfigTestProvider({
|
|
|
218
262
|
};
|
|
219
263
|
return baseContext;
|
|
220
264
|
}, [config, quonfigClient, sdkKey]);
|
|
221
|
-
return /* @__PURE__ */ React.createElement(QuonfigContext.Provider, { value }, children);
|
|
265
|
+
return /* @__PURE__ */ React.createElement(QuonfigClientContext.Provider, { value: quonfigClient }, /* @__PURE__ */ React.createElement(QuonfigContext.Provider, { value }, children));
|
|
222
266
|
}
|
|
223
267
|
|
|
224
|
-
export { QuonfigProvider, QuonfigTestProvider, createQuonfigHook, useQuonfig };
|
|
268
|
+
export { QuonfigProvider, QuonfigTestProvider, createQuonfigHook, useFlag, useQuonfig };
|
|
225
269
|
//# sourceMappingURL=index.mjs.map
|
|
226
270
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts","../src/QuonfigProvider.tsx","../src/QuonfigTestProvider.tsx"],"names":["React"],"mappings":"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","file":"index.mjs","sourcesContent":["// AUTO-GENERATED from package.json by scripts/generate-version.mjs — do not edit.\nexport default \"0.0.9\";\n","import React, { PropsWithChildren } from \"react\";\nimport {\n quonfig,\n type InitOptions,\n type ConfigValue,\n type Contexts,\n Quonfig,\n TypedFrontEndConfigurationRaw,\n FrontEndConfigurationRaw,\n Duration,\n encodeContexts,\n} from \"@quonfig/javascript\";\nimport reactSdkVersion from \"./version\";\n\n// @quonfig/cli#generate will create interfaces into this namespace for React to consume\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface FrontEndConfigurationAccessor {}\n\nexport type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never\n ? Record<string, unknown>\n : {\n [TypedFlagKey in keyof FrontEndConfigurationAccessor]: FrontEndConfigurationAccessor[TypedFlagKey];\n };\n\ntype ClassMethods<T> = { [K in keyof T]: T[K] };\n\ntype QuonfigTypesafeClass<T = unknown> = new (\n // eslint-disable-next-line no-shadow\n quonfig: Quonfig\n) => T;\n\ntype SharedSettings = Partial<\n Pick<\n InitOptions,\n | \"sdkKey\"\n | \"apiUrls\"\n | \"domain\"\n | \"timeout\"\n | \"collectEvaluationSummaries\"\n | \"collectLoggerNames\"\n >\n> & {\n // Convenience alias for a single API URL — normalized to apiUrls=[apiUrl]\n // before being passed to the underlying SDK, which only accepts apiUrls.\n apiUrl?: string;\n // We need to redefine the afterEvaluationCallback type to ensure proper dynamic resolution of K\n afterEvaluationCallback?: <K extends keyof TypedFrontEndConfigurationRaw>(\n key: K,\n value: TypedFrontEndConfigurationRaw[K],\n contexts: Contexts | undefined\n ) => void;\n pollInterval?: number;\n onError?: (error: Error) => void;\n};\n\nexport type BaseContext = {\n get: <K extends keyof TypedFrontEndConfigurationRaw>(key: K) => TypedFrontEndConfigurationRaw[K];\n getDuration: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends Duration\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => Duration | undefined;\n contextAttributes: Contexts;\n isEnabled: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends boolean\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => boolean;\n loading: boolean;\n quonfig: typeof quonfig;\n keys: (keyof TypedFrontEndConfigurationRaw)[];\n settings: SharedSettings;\n};\n\nexport type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;\n\nexport const defaultContext: BaseContext = {\n get: (_key) => undefined,\n getDuration: (_key) => undefined,\n isEnabled: (_key) => false,\n keys: [],\n loading: true,\n contextAttributes: {},\n quonfig,\n settings: {},\n};\n\nexport const QuonfigContext = React.createContext<ProvidedContext>(\n defaultContext as ProvidedContext\n);\n\n// This is a factory function that creates a fully typed useQuonfig hook for a specific QuonfigTypesafe class\nexport function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>) {\n return function useQuonfigHook(): BaseContext & T {\n const baseContext = React.useContext(QuonfigContext);\n\n // Memoize the typesafe instance to prevent unnecessary constructor calls\n const typesafeInstance = React.useMemo(() => {\n const instance = new TypesafeClass(baseContext.quonfig);\n\n // Copy baseContext properties to typesafeInstance except for `get` + `quonfig`\n Object.assign(instance as any, {\n getDuration: baseContext.getDuration,\n contextAttributes: baseContext.contextAttributes,\n isEnabled: baseContext.isEnabled,\n loading: baseContext.loading,\n keys: baseContext.keys,\n settings: baseContext.settings,\n });\n\n return instance;\n }, [baseContext]);\n\n return typesafeInstance as BaseContext & T;\n };\n}\n\n// Basic hook for general use - requires type parameter\nexport const useBaseQuonfig = () => React.useContext(QuonfigContext);\n\n// General hook that returns the context with any explicit type\nexport const useQuonfig = (): ProvidedContext => useBaseQuonfig() as unknown as ProvidedContext;\n\nlet globalQuonfigIsTaken = false;\n\nexport const assignQuonfigClient = () => {\n if (globalQuonfigIsTaken) {\n return new Quonfig();\n }\n\n globalQuonfigIsTaken = true;\n return quonfig;\n};\n\nexport type QuonfigProviderProps = SharedSettings & {\n sdkKey: string;\n contextAttributes?: Contexts;\n initialFlags?: Record<string, unknown>;\n};\n\nconst getContextKey = (contextAttributes: Contexts, onError: (e: Error) => void): string => {\n try {\n if (Object.keys(contextAttributes).length === 0) {\n // eslint-disable-next-line no-console\n console.warn(\n \"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context\"\n );\n }\n\n return encodeContexts(contextAttributes);\n } catch (e) {\n onError(e as Error);\n return \"\";\n }\n};\n\nfunction QuonfigProvider({\n sdkKey,\n contextAttributes = {},\n onError = (e: unknown) => {\n // eslint-disable-next-line no-console\n console.error(e);\n },\n initialFlags,\n children,\n timeout,\n apiUrl,\n apiUrls,\n domain,\n pollInterval,\n afterEvaluationCallback = undefined,\n collectEvaluationSummaries,\n collectLoggerNames,\n}: PropsWithChildren<QuonfigProviderProps>) {\n const settings = {\n sdkKey,\n apiUrl,\n apiUrls,\n domain,\n timeout,\n pollInterval,\n onError,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n // We use this state to prevent a double-init when useEffect fires due to\n // StrictMode\n const mostRecentlyLoadingContextKey = React.useRef<string | undefined>(undefined);\n // We use this state to pass the loading state to the Provider (updating\n // currentLoadingContextKey won't trigger an update)\n const [loading, setLoading] = React.useState(true);\n const [initialLoad, setInitialLoad] = React.useState(true);\n // Here we track the current identity so we can reload our config when it\n // changes\n const [loadedContextKey, setLoadedContextKey] = React.useState(\"\");\n\n const quonfigClient: Quonfig = React.useMemo(() => assignQuonfigClient(), []);\n\n // qfg-daxq: re-render when the underlying client's in-memory config changes\n // (poll fetch, setConfig, hydrate). Without this the singleton mutates in\n // place and React never sees the update.\n const dataVersion = React.useSyncExternalStore(\n React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),\n React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),\n React.useCallback(() => 0, [])\n );\n\n const contextKey = getContextKey(contextAttributes, onError);\n\n if (initialFlags && initialLoad) {\n quonfigClient.hydrate(initialFlags);\n setInitialLoad(false);\n setLoadedContextKey(contextKey);\n setLoading(false);\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (pollInterval) {\n // eslint-disable-next-line no-console\n console.warn(\"Polling is not supported when hydrating flags via initialFlags\");\n }\n }\n\n React.useEffect(() => {\n setInitialLoad(false);\n\n if (mostRecentlyLoadingContextKey.current === contextKey) {\n return;\n }\n\n setLoading(true);\n try {\n if (mostRecentlyLoadingContextKey.current === undefined) {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (!sdkKey) {\n throw new Error(\"QuonfigProvider: sdkKey is required\");\n }\n\n quonfigClient.clientName = \"react\";\n quonfigClient.clientVersion = reactSdkVersion;\n\n const resolvedApiUrls = apiUrls ?? (apiUrl ? [apiUrl] : undefined);\n\n const initOptions: InitOptions = {\n context: contextAttributes,\n sdkKey,\n apiUrls: resolvedApiUrls,\n domain,\n timeout,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n quonfigClient\n .init(initOptions)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n\n if (pollInterval) {\n quonfigClient.poll({ frequencyInMs: pollInterval });\n }\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n } else {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n quonfigClient\n .updateContext(contextAttributes)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n }\n } catch (e) {\n setLoading(false);\n onError(e as Error);\n }\n }, [\n sdkKey,\n loadedContextKey,\n contextKey,\n loading,\n setLoading,\n onError,\n quonfigClient.instanceHash,\n ]);\n\n // qfg-2acr: drain telemetry + stop polling/telemetry timers when the\n // provider unmounts so route swaps don't leave the singleton polling\n // forever. Mount-only deps so context-attribute changes don't tear down\n // the SDK. In React StrictMode the synthetic unmount fires too — we\n // reset the init-guard ref so the next mount cleanly re-inits.\n React.useEffect(\n () => () => {\n quonfigClient.close().catch(() => {});\n mostRecentlyLoadingContextKey.current = undefined;\n },\n [quonfigClient]\n );\n\n const value = React.useMemo(() => {\n const baseContext: ProvidedContext = {\n isEnabled: quonfigClient.isEnabled.bind(quonfigClient),\n contextAttributes,\n get: quonfigClient.get.bind(quonfigClient),\n getDuration: quonfigClient.getDuration.bind(quonfigClient),\n keys: Object.keys(quonfigClient.extract()),\n quonfig: quonfigClient,\n loading,\n settings,\n };\n\n return baseContext;\n }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);\n\n return <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>;\n}\n\nexport { QuonfigProvider, ConfigValue, SharedSettings, QuonfigTypesafeClass };\n","import React, { PropsWithChildren } from \"react\";\nimport { QuonfigContext, assignQuonfigClient, ProvidedContext } from \"./QuonfigProvider\";\n\nexport type QuonfigTestProviderProps = {\n config: Record<string, any>;\n sdkKey?: string;\n};\n\nfunction QuonfigTestProvider({\n sdkKey,\n config,\n children,\n}: PropsWithChildren<QuonfigTestProviderProps>) {\n const get = (key: string) => config[key];\n const getDuration = (key: string) => config[key];\n const isEnabled = (key: string) => !!get(key);\n\n const quonfigClient = React.useMemo(() => assignQuonfigClient(), []);\n\n const value = React.useMemo(() => {\n quonfigClient.get = get;\n quonfigClient.getDuration = getDuration;\n quonfigClient.isEnabled = isEnabled;\n\n const baseContext: ProvidedContext = {\n isEnabled,\n contextAttributes: config.contextAttributes,\n get,\n getDuration,\n loading: false,\n quonfig: quonfigClient,\n keys: Object.keys(config),\n settings: { sdkKey: sdkKey ?? \"fake-sdk-key-via-the-test-provider\" },\n };\n\n return baseContext;\n }, [config, quonfigClient, sdkKey]);\n\n return <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>;\n}\n\nexport { QuonfigTestProvider };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/sdkLogger.ts","../src/QuonfigProvider.tsx","../src/QuonfigTestProvider.tsx"],"names":["React"],"mappings":"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","file":"index.mjs","sourcesContent":["// AUTO-GENERATED from package.json by scripts/generate-version.mjs — do not edit.\nexport default \"0.0.9\";\n","/**\n * Pluggable logger interface for SDK-internal warnings and errors.\n *\n * Shape mirrors @quonfig/node so the contract is uniform across the\n * TypeScript SDKs: `warn` and `error` are required; `debug` and `info` are\n * optional and become no-ops when the supplied logger does not implement\n * them.\n */\nexport interface Logger {\n debug?(message: string, ...args: unknown[]): void;\n info?(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nexport interface NormalizedLogger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nconst NOOP = (): void => {};\n\nconst PREFIX = \"[quonfig]\";\n\nfunction defaultSdkLogger(): NormalizedLogger {\n return {\n /* eslint-disable no-console */\n debug: (message, ...args) => console.debug(PREFIX, message, ...args),\n info: (message, ...args) => console.info(PREFIX, message, ...args),\n warn: (message, ...args) => console.warn(PREFIX, message, ...args),\n error: (message, ...args) => console.error(PREFIX, message, ...args),\n /* eslint-enable no-console */\n };\n}\n\nexport function normalizeLogger(logger: Logger | undefined): NormalizedLogger {\n if (!logger) return defaultSdkLogger();\n return {\n debug: logger.debug ? logger.debug.bind(logger) : NOOP,\n info: logger.info ? logger.info.bind(logger) : NOOP,\n warn: logger.warn.bind(logger),\n error: logger.error.bind(logger),\n };\n}\n","import React, { PropsWithChildren } from \"react\";\nimport {\n quonfig,\n type InitOptions,\n type ConfigValue,\n type Contexts,\n Quonfig,\n TypedFrontEndConfigurationRaw,\n FrontEndConfigurationRaw,\n Duration,\n encodeContexts,\n} from \"@quonfig/javascript\";\nimport reactSdkVersion from \"./version\";\nimport { normalizeLogger, type Logger, type NormalizedLogger } from \"./sdkLogger\";\n\n// qfg-lkpm.6: per-tree owner context. The value is the active Quonfig client\n// for this provider subtree. A null value means no Provider is above us, so\n// the next mount can claim the module-level singleton; a non-null value\n// signals \"you're nested, mint a fresh client\". This replaces the previous\n// module-level `globalQuonfigIsTaken` flag, which never reset and so leaked\n// state across test runs and (in principle) across SSR render trees.\nconst QuonfigClientContext = React.createContext<Quonfig | null>(null);\n\n// @quonfig/cli#generate will create interfaces into this namespace for React to consume\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface FrontEndConfigurationAccessor {}\n\nexport type TypedFrontEndConfigurationAccessor = keyof FrontEndConfigurationAccessor extends never\n ? Record<string, unknown>\n : {\n [TypedFlagKey in keyof FrontEndConfigurationAccessor]: FrontEndConfigurationAccessor[TypedFlagKey];\n };\n\ntype ClassMethods<T> = { [K in keyof T]: T[K] };\n\ntype QuonfigTypesafeClass<T = unknown> = new (\n // eslint-disable-next-line no-shadow\n quonfig: Quonfig\n) => T;\n\ntype SharedSettings = Partial<\n Pick<\n InitOptions,\n | \"sdkKey\"\n | \"apiUrls\"\n | \"domain\"\n | \"timeout\"\n | \"collectEvaluationSummaries\"\n | \"collectLoggerNames\"\n >\n> & {\n // Convenience alias for a single API URL — normalized to apiUrls=[apiUrl]\n // before being passed to the underlying SDK, which only accepts apiUrls.\n apiUrl?: string;\n // We need to redefine the afterEvaluationCallback type to ensure proper dynamic resolution of K\n afterEvaluationCallback?: <K extends keyof TypedFrontEndConfigurationRaw>(\n key: K,\n value: TypedFrontEndConfigurationRaw[K],\n contexts: Contexts | undefined\n ) => void;\n pollInterval?: number;\n onError?: (error: Error) => void;\n};\n\nexport type BaseContext = {\n get: <K extends keyof TypedFrontEndConfigurationRaw>(key: K) => TypedFrontEndConfigurationRaw[K];\n getDuration: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends Duration\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => Duration | undefined;\n contextAttributes: Contexts;\n isEnabled: <\n K extends keyof FrontEndConfigurationRaw extends never\n ? string\n : {\n [IK in keyof TypedFrontEndConfigurationRaw]: TypedFrontEndConfigurationRaw[IK] extends boolean\n ? IK\n : never;\n }[keyof TypedFrontEndConfigurationRaw],\n >(\n key: K\n ) => boolean;\n loading: boolean;\n quonfig: typeof quonfig;\n keys: (keyof TypedFrontEndConfigurationRaw)[];\n settings: SharedSettings;\n};\n\nexport type ProvidedContext = BaseContext & ClassMethods<QuonfigTypesafeClass>;\n\nexport const defaultContext: BaseContext = {\n get: (_key) => undefined,\n getDuration: (_key) => undefined,\n isEnabled: (_key) => false,\n keys: [],\n loading: true,\n contextAttributes: {},\n quonfig,\n settings: {},\n};\n\nexport const QuonfigContext = React.createContext<ProvidedContext>(\n defaultContext as ProvidedContext\n);\n\n// This is a factory function that creates a fully typed useQuonfig hook for a specific QuonfigTypesafe class\nexport function createQuonfigHook<T>(TypesafeClass: QuonfigTypesafeClass<T>) {\n return function useQuonfigHook(): BaseContext & T {\n const baseContext = React.useContext(QuonfigContext);\n\n // Memoize the typesafe instance to prevent unnecessary constructor calls\n const typesafeInstance = React.useMemo(() => {\n const instance = new TypesafeClass(baseContext.quonfig);\n\n // Copy baseContext properties to typesafeInstance except for `get` + `quonfig`\n Object.assign(instance as any, {\n getDuration: baseContext.getDuration,\n contextAttributes: baseContext.contextAttributes,\n isEnabled: baseContext.isEnabled,\n loading: baseContext.loading,\n keys: baseContext.keys,\n settings: baseContext.settings,\n });\n\n return instance;\n }, [baseContext]);\n\n return typesafeInstance as BaseContext & T;\n };\n}\n\n// Basic hook for general use - requires type parameter\nexport const useBaseQuonfig = () => React.useContext(QuonfigContext);\n\n// General hook that returns the context with any explicit type\nexport const useQuonfig = (): ProvidedContext => useBaseQuonfig() as unknown as ProvidedContext;\n\n// qfg-lkpm.6: per-key selector hook. Subscribes via the underlying client's\n// notify list rather than React context, so a flag mutation only re-renders\n// components whose selected key actually changed. `useQuonfig()` re-renders\n// on every dataVersion bump because the context value identity changes; this\n// hook bypasses that.\nexport function useFlag<K extends keyof TypedFrontEndConfigurationRaw>(\n key: K\n): TypedFrontEndConfigurationRaw[K];\nexport function useFlag(key: string): ConfigValue;\nexport function useFlag(key: string): ConfigValue {\n const client = React.useContext(QuonfigClientContext) ?? quonfig;\n const subscribe = React.useCallback(\n (onChange: () => void) => client.subscribe(onChange),\n [client]\n );\n const getSnapshot = React.useCallback(() => client.get(key), [client, key]);\n const getServerSnapshot = React.useCallback((): ConfigValue => undefined, []);\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n// qfg-lkpm.6: replacement for the old module-level `globalQuonfigIsTaken`\n// flag. A provider asks \"is there already a Quonfig client above me in the\n// React tree?\". If yes, mint a fresh client (multi-tenant nesting); if no,\n// claim the module singleton so non-React code that imports `quonfig`\n// directly sees the same instance.\nexport const useQuonfigClient = (): Quonfig => {\n const parentClient = React.useContext(QuonfigClientContext);\n // Mount-only: parent context is fixed for the lifetime of this provider.\n const parentClientRef = React.useRef(parentClient);\n return React.useMemo(() => (parentClientRef.current ? new Quonfig() : quonfig), []);\n};\n\nexport type QuonfigProviderProps = SharedSettings & {\n sdkKey: string;\n contextAttributes?: Contexts;\n initialFlags?: Record<string, unknown>;\n logger?: Logger;\n};\n\nconst getContextKey = (\n contextAttributes: Contexts,\n logger: NormalizedLogger,\n onError: (e: Error) => void\n): string => {\n try {\n if (Object.keys(contextAttributes).length === 0) {\n logger.warn(\n \"QuonfigProvider: You haven't passed any contextAttributes. See https://docs.quonfig.com/docs/sdks/react#using-context\"\n );\n }\n\n return encodeContexts(contextAttributes);\n } catch (e) {\n onError(e as Error);\n return \"\";\n }\n};\n\nfunction QuonfigProvider({\n sdkKey,\n contextAttributes = {},\n onError: userOnError,\n logger,\n initialFlags,\n children,\n timeout,\n apiUrl,\n apiUrls,\n domain,\n pollInterval,\n afterEvaluationCallback = undefined,\n collectEvaluationSummaries,\n collectLoggerNames,\n}: PropsWithChildren<QuonfigProviderProps>) {\n const normalizedLogger = React.useMemo(() => normalizeLogger(logger), [logger]);\n const onError = React.useCallback(\n (e: unknown) => {\n if (userOnError) {\n userOnError(e as Error);\n } else {\n const message = e instanceof Error ? e.message : String(e);\n normalizedLogger.error(message, e);\n }\n },\n [userOnError, normalizedLogger]\n );\n const settings = {\n sdkKey,\n apiUrl,\n apiUrls,\n domain,\n timeout,\n pollInterval,\n onError,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n // We use this state to prevent a double-init when useEffect fires due to\n // StrictMode\n const mostRecentlyLoadingContextKey = React.useRef<string | undefined>(undefined);\n // We use this state to pass the loading state to the Provider (updating\n // currentLoadingContextKey won't trigger an update)\n const [loading, setLoading] = React.useState(true);\n const [initialLoad, setInitialLoad] = React.useState(true);\n // Here we track the current identity so we can reload our config when it\n // changes\n const [loadedContextKey, setLoadedContextKey] = React.useState(\"\");\n\n const quonfigClient: Quonfig = useQuonfigClient();\n\n // qfg-daxq: re-render when the underlying client's in-memory config changes\n // (poll fetch, setConfig, hydrate). Without this the singleton mutates in\n // place and React never sees the update.\n const dataVersion = React.useSyncExternalStore(\n React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),\n React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),\n React.useCallback(() => 0, [])\n );\n\n const contextKey = getContextKey(contextAttributes, normalizedLogger, onError);\n\n if (initialFlags && initialLoad) {\n quonfigClient.hydrate(initialFlags);\n setInitialLoad(false);\n setLoadedContextKey(contextKey);\n setLoading(false);\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (pollInterval) {\n normalizedLogger.warn(\"Polling is not supported when hydrating flags via initialFlags\");\n }\n }\n\n React.useEffect(() => {\n setInitialLoad(false);\n\n if (mostRecentlyLoadingContextKey.current === contextKey) {\n return;\n }\n\n setLoading(true);\n try {\n if (mostRecentlyLoadingContextKey.current === undefined) {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n if (!sdkKey) {\n throw new Error(\"QuonfigProvider: sdkKey is required\");\n }\n\n quonfigClient.clientName = \"react\";\n quonfigClient.clientVersion = reactSdkVersion;\n\n const resolvedApiUrls = apiUrls ?? (apiUrl ? [apiUrl] : undefined);\n\n const initOptions: InitOptions = {\n context: contextAttributes,\n sdkKey,\n apiUrls: resolvedApiUrls,\n domain,\n timeout,\n afterEvaluationCallback,\n collectEvaluationSummaries,\n collectLoggerNames,\n };\n\n quonfigClient\n .init(initOptions)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n\n if (pollInterval) {\n quonfigClient.poll({ frequencyInMs: pollInterval });\n }\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n } else {\n mostRecentlyLoadingContextKey.current = contextKey;\n\n quonfigClient\n .updateContext(contextAttributes)\n .then(() => {\n setLoadedContextKey(contextKey);\n setLoading(false);\n })\n .catch((reason: any) => {\n setLoading(false);\n onError(reason);\n });\n }\n } catch (e) {\n setLoading(false);\n onError(e as Error);\n }\n }, [\n sdkKey,\n loadedContextKey,\n contextKey,\n loading,\n setLoading,\n onError,\n quonfigClient.instanceHash,\n ]);\n\n // qfg-2acr: drain telemetry + stop polling/telemetry timers when the\n // provider unmounts so route swaps don't leave the singleton polling\n // forever. Mount-only deps so context-attribute changes don't tear down\n // the SDK. In React StrictMode the synthetic unmount fires too — we\n // reset the init-guard ref so the next mount cleanly re-inits.\n React.useEffect(\n () => () => {\n quonfigClient.close().catch(() => {});\n mostRecentlyLoadingContextKey.current = undefined;\n },\n [quonfigClient]\n );\n\n const value = React.useMemo(() => {\n const baseContext: ProvidedContext = {\n isEnabled: quonfigClient.isEnabled.bind(quonfigClient),\n contextAttributes,\n get: quonfigClient.get.bind(quonfigClient),\n getDuration: quonfigClient.getDuration.bind(quonfigClient),\n keys: Object.keys(quonfigClient.extract()),\n quonfig: quonfigClient,\n loading,\n settings,\n };\n\n return baseContext;\n }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);\n\n return (\n <QuonfigClientContext.Provider value={quonfigClient}>\n <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>\n </QuonfigClientContext.Provider>\n );\n}\n\nexport { QuonfigProvider, QuonfigClientContext, ConfigValue, SharedSettings, QuonfigTypesafeClass };\n","import React, { PropsWithChildren } from \"react\";\nimport {\n QuonfigContext,\n QuonfigClientContext,\n useQuonfigClient,\n ProvidedContext,\n} from \"./QuonfigProvider\";\n\nexport type QuonfigTestProviderProps = {\n config: Record<string, any>;\n sdkKey?: string;\n};\n\nfunction QuonfigTestProvider({\n sdkKey,\n config,\n children,\n}: PropsWithChildren<QuonfigTestProviderProps>) {\n const get = (key: string) => config[key];\n const getDuration = (key: string) => config[key];\n const isEnabled = (key: string) => !!get(key);\n\n const quonfigClient = useQuonfigClient();\n\n const value = React.useMemo(() => {\n quonfigClient.get = get;\n quonfigClient.getDuration = getDuration;\n quonfigClient.isEnabled = isEnabled;\n\n const baseContext: ProvidedContext = {\n isEnabled,\n contextAttributes: config.contextAttributes,\n get,\n getDuration,\n loading: false,\n quonfig: quonfigClient,\n keys: Object.keys(config),\n settings: { sdkKey: sdkKey ?? \"fake-sdk-key-via-the-test-provider\" },\n };\n\n return baseContext;\n }, [config, quonfigClient, sdkKey]);\n\n return (\n <QuonfigClientContext.Provider value={quonfigClient}>\n <QuonfigContext.Provider value={value}>{children}</QuonfigContext.Provider>\n </QuonfigClientContext.Provider>\n );\n}\n\nexport { QuonfigTestProvider };\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageManager": "yarn@4.11.0",
|
|
3
3
|
"name": "@quonfig/react",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.13",
|
|
5
5
|
"description": "Feature Flags & Dynamic Configuration as a Service",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
"LICENSE",
|
|
29
29
|
"CHANGELOG.md"
|
|
30
30
|
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.9.0"
|
|
33
|
+
},
|
|
31
34
|
"scripts": {
|
|
32
35
|
"prebuild": "node scripts/generate-version.mjs",
|
|
33
36
|
"build": "rm -rf dist/ && tsup",
|
|
@@ -36,8 +39,22 @@
|
|
|
36
39
|
"test": "tsup && jest --verbose",
|
|
37
40
|
"lint": "eslint --ext .ts,.tsx src/",
|
|
38
41
|
"prettier": "prettier . -l",
|
|
39
|
-
"prettier:fix": "prettier --write ."
|
|
42
|
+
"prettier:fix": "prettier --write .",
|
|
43
|
+
"version": "prettier --write CHANGELOG.md README.md && git add CHANGELOG.md README.md"
|
|
40
44
|
},
|
|
45
|
+
"size-limit": [
|
|
46
|
+
{
|
|
47
|
+
"name": "dist/index.mjs (gzipped)",
|
|
48
|
+
"path": "dist/index.mjs",
|
|
49
|
+
"limit": "2 kB",
|
|
50
|
+
"gzip": true,
|
|
51
|
+
"ignore": [
|
|
52
|
+
"react",
|
|
53
|
+
"react-dom",
|
|
54
|
+
"@quonfig/javascript"
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
41
58
|
"author": "Jeffrey Chupp",
|
|
42
59
|
"license": "ISC",
|
|
43
60
|
"keywords": [
|
|
@@ -46,6 +63,7 @@
|
|
|
46
63
|
],
|
|
47
64
|
"devDependencies": {
|
|
48
65
|
"@quonfig/javascript": ">=0.0.14",
|
|
66
|
+
"@size-limit/preset-small-lib": "^11.1.6",
|
|
49
67
|
"@testing-library/jest-dom": "^5.16.5",
|
|
50
68
|
"@testing-library/react": "^13.3.0",
|
|
51
69
|
"@types/jest": "^28.1.6",
|
|
@@ -68,6 +86,7 @@
|
|
|
68
86
|
"prettier": "^3.0.0",
|
|
69
87
|
"react": "^19.1.1",
|
|
70
88
|
"react-dom": "^19.1.1",
|
|
89
|
+
"size-limit": "^11.1.6",
|
|
71
90
|
"ts-jest": "^28.0.7",
|
|
72
91
|
"ts-node": "^10.9.1",
|
|
73
92
|
"tsup": "^8.4.0",
|
|
@@ -75,6 +94,6 @@
|
|
|
75
94
|
},
|
|
76
95
|
"peerDependencies": {
|
|
77
96
|
"@quonfig/javascript": ">=0.0.14",
|
|
78
|
-
"react": "^
|
|
97
|
+
"react": "^18 || ^19"
|
|
79
98
|
}
|
|
80
99
|
}
|