@quonfig/react 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -101,6 +101,11 @@ function QuonfigProvider({
101
101
  const [initialLoad, setInitialLoad] = React__default.default.useState(true);
102
102
  const [loadedContextKey, setLoadedContextKey] = React__default.default.useState("");
103
103
  const quonfigClient = React__default.default.useMemo(() => assignQuonfigClient(), []);
104
+ const dataVersion = React__default.default.useSyncExternalStore(
105
+ React__default.default.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),
106
+ React__default.default.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),
107
+ React__default.default.useCallback(() => 0, [])
108
+ );
104
109
  const contextKey = getContextKey(contextAttributes, onError);
105
110
  if (initialFlags && initialLoad) {
106
111
  quonfigClient.hydrate(initialFlags);
@@ -170,6 +175,14 @@ function QuonfigProvider({
170
175
  onError,
171
176
  quonfigClient.instanceHash
172
177
  ]);
178
+ React__default.default.useEffect(
179
+ () => () => {
180
+ quonfigClient.close().catch(() => {
181
+ });
182
+ mostRecentlyLoadingContextKey.current = void 0;
183
+ },
184
+ [quonfigClient]
185
+ );
173
186
  const value = React__default.default.useMemo(() => {
174
187
  const baseContext = {
175
188
  isEnabled: quonfigClient.isEnabled.bind(quonfigClient),
@@ -182,7 +195,7 @@ function QuonfigProvider({
182
195
  settings
183
196
  };
184
197
  return baseContext;
185
- }, [loadedContextKey, loading, quonfigClient.instanceHash, settings]);
198
+ }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);
186
199
  return /* @__PURE__ */ React__default.default.createElement(QuonfigContext.Provider, { value }, children);
187
200
  }
188
201
  function QuonfigTestProvider({
@@ -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 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 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]);\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/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"]}
package/dist/index.mjs CHANGED
@@ -96,6 +96,11 @@ function QuonfigProvider({
96
96
  const [initialLoad, setInitialLoad] = React.useState(true);
97
97
  const [loadedContextKey, setLoadedContextKey] = React.useState("");
98
98
  const quonfigClient = React.useMemo(() => assignQuonfigClient(), []);
99
+ const dataVersion = React.useSyncExternalStore(
100
+ React.useCallback((onChange) => quonfigClient.subscribe(onChange), [quonfigClient]),
101
+ React.useCallback(() => quonfigClient.dataVersion, [quonfigClient]),
102
+ React.useCallback(() => 0, [])
103
+ );
99
104
  const contextKey = getContextKey(contextAttributes, onError);
100
105
  if (initialFlags && initialLoad) {
101
106
  quonfigClient.hydrate(initialFlags);
@@ -165,6 +170,14 @@ function QuonfigProvider({
165
170
  onError,
166
171
  quonfigClient.instanceHash
167
172
  ]);
173
+ React.useEffect(
174
+ () => () => {
175
+ quonfigClient.close().catch(() => {
176
+ });
177
+ mostRecentlyLoadingContextKey.current = void 0;
178
+ },
179
+ [quonfigClient]
180
+ );
168
181
  const value = React.useMemo(() => {
169
182
  const baseContext = {
170
183
  isEnabled: quonfigClient.isEnabled.bind(quonfigClient),
@@ -177,7 +190,7 @@ function QuonfigProvider({
177
190
  settings
178
191
  };
179
192
  return baseContext;
180
- }, [loadedContextKey, loading, quonfigClient.instanceHash, settings]);
193
+ }, [loadedContextKey, loading, quonfigClient.instanceHash, settings, dataVersion]);
181
194
  return /* @__PURE__ */ React.createElement(QuonfigContext.Provider, { value }, children);
182
195
  }
183
196
  function QuonfigTestProvider({
@@ -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 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 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]);\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/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"]}
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.9",
4
+ "version": "0.0.10",
5
5
  "description": "Feature Flags & Dynamic Configuration as a Service",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -45,7 +45,7 @@
45
45
  "config"
46
46
  ],
47
47
  "devDependencies": {
48
- "@quonfig/javascript": ">=0.0.13",
48
+ "@quonfig/javascript": ">=0.0.14",
49
49
  "@testing-library/jest-dom": "^5.16.5",
50
50
  "@testing-library/react": "^13.3.0",
51
51
  "@types/jest": "^28.1.6",
@@ -74,7 +74,7 @@
74
74
  "typescript": "^4.7.4"
75
75
  },
76
76
  "peerDependencies": {
77
- "@quonfig/javascript": ">=0.0.13",
77
+ "@quonfig/javascript": ">=0.0.14",
78
78
  "react": "^16 || ^17 || ^18 || ^19"
79
79
  }
80
80
  }