@replanejs/react 0.7.0 → 0.7.1
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.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -82,7 +82,7 @@ declare function ReplaneProvider<T extends object>(props: ReplaneProviderProps<T
|
|
|
82
82
|
//# sourceMappingURL=provider.d.ts.map
|
|
83
83
|
//#endregion
|
|
84
84
|
//#region src/hooks.d.ts
|
|
85
|
-
declare function useReplane<T extends object =
|
|
85
|
+
declare function useReplane<T extends object = Record<string, unknown>>(): ReplaneContextValue<T>;
|
|
86
86
|
declare function useConfig<T>(name: string, options?: {
|
|
87
87
|
context?: Record<string, string | number | boolean | null>;
|
|
88
88
|
}): T;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/provider.tsx","../src/hooks.ts","../src/useReplaneClient.ts"],"sourcesContent":[],"mappings":";;;;;UAIiB;UACP,cAAc;;AADxB;;;AACU,UAOO,8BAPP,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAa;EAON,MAAA,EAEP,aAFO,CAEO,CAFP,CAAA;EAA8B,QAAA,EAGnC,SAHmC;;;;AAG1B;AAOJ,UAAA,+BAA+B,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA;EAAA,OAEhB,EAArB,oBAAqB,CAAA,CAAA,CAAA;EAAC,QAAtB,EACC,SADD;EAAoB;;;AAgBN;EAIb,MAAA,CAAA,EAdD,SAcC;EAAoB;;;;;EAEG,QAAA,CAAA,EAAA,OAAA;;;;ECgDnB,OAAA,CAAA,EAAA,CAAA,KAAA,EDtDI,KCsDW,EAAA,GAAA,IAAA;;AAA+C,KDlDlE,oBCkDkE,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,GDjD1E,8BCiD0E,CDjD3C,CCiD2C,CAAA,GDhD1E,+BCgD0E,CDhD1C,CCgD0C,CAAA;;;AAAE;;;;;;;AD1FhF;;;;AACuB;AAOvB;;;;;AAGqB;AAOrB;;;;;;;AAkByB;AAIzB;;;;;;AAEmC;;;;ACgDnC;;AAA8E,iBAA9D,eAA8D,CAAA,UAAA,MAAA,CAAA,CAAA,KAAA,EAArB,oBAAqB,CAAA,CAAA,CAAA,CAAA,EAAE,kBAAA,CAAA,GAAA,CAAA,OAAF;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/provider.tsx","../src/hooks.ts","../src/useReplaneClient.ts"],"sourcesContent":[],"mappings":";;;;;UAIiB;UACP,cAAc;;AADxB;;;AACU,UAOO,8BAPP,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAa;EAON,MAAA,EAEP,aAFO,CAEO,CAFP,CAAA;EAA8B,QAAA,EAGnC,SAHmC;;;;AAG1B;AAOJ,UAAA,+BAA+B,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA;EAAA,OAEhB,EAArB,oBAAqB,CAAA,CAAA,CAAA;EAAC,QAAtB,EACC,SADD;EAAoB;;;AAgBN;EAIb,MAAA,CAAA,EAdD,SAcC;EAAoB;;;;;EAEG,QAAA,CAAA,EAAA,OAAA;;;;ECgDnB,OAAA,CAAA,EAAA,CAAA,KAAA,EDtDI,KCsDW,EAAA,GAAA,IAAA;;AAA+C,KDlDlE,oBCkDkE,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,GDjD1E,8BCiD0E,CDjD3C,CCiD2C,CAAA,GDhD1E,+BCgD0E,CDhD1C,CCgD0C,CAAA;;;AAAE;;;;;;;AD1FhF;;;;AACuB;AAOvB;;;;;AAGqB;AAOrB;;;;;;;AAkByB;AAIzB;;;;;;AAEmC;;;;ACgDnC;;AAA8E,iBAA9D,eAA8D,CAAA,UAAA,MAAA,CAAA,CAAA,KAAA,EAArB,oBAAqB,CAAA,CAAA,CAAA,CAAA,EAAE,kBAAA,CAAA,GAAA,CAAA,OAAF;;;;iBC1F9D,8BAA8B,4BAA4B,oBAAoB;iBAQ9E;YAEQ;IACrB;AFXH;;;;AAwCA;;;;AAEoC,iBGgFpB,kBHhFoB,CAAA,UAAA,MAAA,CAAA,CAAA,OAAA,CAAA,EGgF2B,oBHhF3B,CGgFgD,CHhFhD,CAAA,CAAA,EAAA,IAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ declare function ReplaneProvider<T extends object>(props: ReplaneProviderProps<T
|
|
|
82
82
|
//# sourceMappingURL=provider.d.ts.map
|
|
83
83
|
//#endregion
|
|
84
84
|
//#region src/hooks.d.ts
|
|
85
|
-
declare function useReplane<T extends object =
|
|
85
|
+
declare function useReplane<T extends object = Record<string, unknown>>(): ReplaneContextValue<T>;
|
|
86
86
|
declare function useConfig<T>(name: string, options?: {
|
|
87
87
|
context?: Record<string, string | number | boolean | null>;
|
|
88
88
|
}): T;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/provider.tsx","../src/hooks.ts","../src/useReplaneClient.ts"],"sourcesContent":[],"mappings":";;;;;UAIiB;UACP,cAAc;;AADxB;;;AACU,UAOO,8BAPP,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAa;EAON,MAAA,EAEP,aAFO,CAEO,CAFP,CAAA;EAA8B,QAAA,EAGnC,SAHmC;;;;AAG1B;AAOJ,UAAA,+BAA+B,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA;EAAA,OAEhB,EAArB,oBAAqB,CAAA,CAAA,CAAA;EAAC,QAAtB,EACC,SADD;EAAoB;;;AAgBN;EAIb,MAAA,CAAA,EAdD,SAcC;EAAoB;;;;;EAEG,QAAA,CAAA,EAAA,OAAA;;;;ECgDnB,OAAA,CAAA,EAAA,CAAA,KAAA,EDtDI,KCsDW,EAAA,GAAA,IAAA;;AAA+C,KDlDlE,oBCkDkE,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,GDjD1E,8BCiD0E,CDjD3C,CCiD2C,CAAA,GDhD1E,+BCgD0E,CDhD1C,CCgD0C,CAAA;;;AAAE;;;;;;;AD1FhF;;;;AACuB;AAOvB;;;;;AAGqB;AAOrB;;;;;;;AAkByB;AAIzB;;;;;;AAEmC;;;;ACgDnC;;AAA8E,iBAA9D,eAA8D,CAAA,UAAA,MAAA,CAAA,CAAA,KAAA,EAArB,oBAAqB,CAAA,CAAA,CAAA,CAAA,EAAE,kBAAA,CAAA,GAAA,CAAA,OAAF;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/provider.tsx","../src/hooks.ts","../src/useReplaneClient.ts"],"sourcesContent":[],"mappings":";;;;;UAIiB;UACP,cAAc;;AADxB;;;AACU,UAOO,8BAPP,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAa;EAON,MAAA,EAEP,aAFO,CAEO,CAFP,CAAA;EAA8B,QAAA,EAGnC,SAHmC;;;;AAG1B;AAOJ,UAAA,+BAA+B,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA;EAAA,OAEhB,EAArB,oBAAqB,CAAA,CAAA,CAAA;EAAC,QAAtB,EACC,SADD;EAAoB;;;AAgBN;EAIb,MAAA,CAAA,EAdD,SAcC;EAAoB;;;;;EAEG,QAAA,CAAA,EAAA,OAAA;;;;ECgDnB,OAAA,CAAA,EAAA,CAAA,KAAA,EDtDI,KCsDW,EAAA,GAAA,IAAA;;AAA+C,KDlDlE,oBCkDkE,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,GDjD1E,8BCiD0E,CDjD3C,CCiD2C,CAAA,GDhD1E,+BCgD0E,CDhD1C,CCgD0C,CAAA;;;AAAE;;;;;;;AD1FhF;;;;AACuB;AAOvB;;;;;AAGqB;AAOrB;;;;;;;AAkByB;AAIzB;;;;;;AAEmC;;;;ACgDnC;;AAA8E,iBAA9D,eAA8D,CAAA,UAAA,MAAA,CAAA,CAAA,KAAA,EAArB,oBAAqB,CAAA,CAAA,CAAA,CAAA,EAAE,kBAAA,CAAA,GAAA,CAAA,OAAF;;;;iBC1F9D,8BAA8B,4BAA4B,oBAAoB;iBAQ9E;YAEQ;IACrB;AFXH;;;;AAwCA;;;;AAEoC,iBGgFpB,kBHhFoB,CAAA,UAAA,MAAA,CAAA,CAAA,OAAA,CAAA,EGgF2B,oBHhF3B,CGgFgD,CHhFhD,CAAA,CAAA,EAAA,IAAA"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["options: ReplaneClientOptions<T>","onError?: (error: Error) => void","options?: ReplaneClientOptions<T>","props: ReplaneProviderProps<T>","value: ReplaneContextValue<T>","props: ReplaneProviderProps<T>","name: string","options?: { context?: Record<string, string | number | boolean | null> }"],"sources":["../src/context.ts","../src/useReplaneClient.ts","../src/types.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext } from \"react\";\nimport type { ReplaneContextValue } from \"./types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const ReplaneContext = createContext<ReplaneContextValue<any> | null>(null);\n","import { useEffect, useRef, useState } from \"react\";\nimport { createReplaneClient } from \"@replanejs/sdk\";\nimport type { ReplaneClient, ReplaneClientOptions } from \"@replanejs/sdk\";\n\ntype ClientState<T extends object> =\n | { status: \"loading\"; client: null; error: null }\n | { status: \"ready\"; client: ReplaneClient<T>; error: null }\n | { status: \"error\"; client: null; error: Error };\n\n// Cache for suspense promise tracking\nconst suspenseCache = new Map<\n string,\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n promise: Promise<ReplaneClient<any>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n result?: ReplaneClient<any>;\n error?: Error;\n }\n>();\n\nfunction getCacheKey<T extends object>(options: ReplaneClientOptions<T>): string {\n return `${options.baseUrl}:${options.sdkKey}`;\n}\n\n/**\n * Hook to manage ReplaneClient creation internally.\n * Handles loading state and cleanup.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useReplaneClient<T extends object = any>(\n options: ReplaneClientOptions<T>,\n onError?: (error: Error) => void\n): ClientState<T> {\n const [state, setState] = useState<ClientState<T>>({\n status: \"loading\",\n client: null,\n error: null,\n });\n const clientRef = useRef<ReplaneClient<T> | null>(null);\n const optionsRef = useRef(options);\n\n useEffect(() => {\n let cancelled = false;\n\n async function initClient() {\n try {\n const client = await createReplaneClient<T>(optionsRef.current);\n if (cancelled) {\n client.close();\n return;\n }\n clientRef.current = client;\n setState({ status: \"ready\", client, error: null });\n } catch (err) {\n if (cancelled) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setState({ status: \"error\", client: null, error });\n onError?.(error);\n }\n }\n\n initClient();\n\n return () => {\n cancelled = true;\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n };\n // We intentionally only run this effect once on mount\n // Options changes would require remounting the provider\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return state;\n}\n\n/**\n * Hook for Suspense-based client creation.\n * Throws a promise while loading, throws error on failure.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useReplaneClientSuspense<T extends object = any>(\n options: ReplaneClientOptions<T>\n): ReplaneClient<T> {\n const cacheKey = getCacheKey(options);\n const cached = suspenseCache.get(cacheKey);\n\n if (cached) {\n if (cached.error) {\n throw cached.error;\n }\n if (cached.result) {\n return cached.result as ReplaneClient<T>;\n }\n // Still loading, throw the promise\n throw cached.promise;\n }\n\n // First time - create the promise\n const promise = createReplaneClient<T>(options)\n .then((client) => {\n const entry = suspenseCache.get(cacheKey);\n if (entry) {\n entry.result = client;\n }\n return client;\n })\n .catch((err) => {\n const entry = suspenseCache.get(cacheKey);\n if (entry) {\n entry.error = err instanceof Error ? err : new Error(String(err));\n }\n throw err;\n });\n\n suspenseCache.set(cacheKey, { promise });\n throw promise;\n}\n\n/**\n * Clear the suspense cache for a specific options configuration.\n * Useful for testing or when you need to force re-initialization.\n */\nexport function clearSuspenseCache<T extends object>(options?: ReplaneClientOptions<T>): void {\n if (options) {\n suspenseCache.delete(getCacheKey(options));\n } else {\n suspenseCache.clear();\n }\n}\n","import type { ReplaneClient, ReplaneClientOptions } from \"@replanejs/sdk\";\nimport type { ReactNode } from \"react\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneContextValue<T extends object = any> {\n client: ReplaneClient<T>;\n}\n\n/**\n * Props for ReplaneProvider when using a pre-created client.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneProviderWithClientProps<T extends object = any> {\n /** Pre-created ReplaneClient instance */\n client: ReplaneClient<T>;\n children: ReactNode;\n}\n\n/**\n * Props for ReplaneProvider when letting it manage the client internally.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneProviderWithOptionsProps<T extends object = any> {\n /** Options to create the ReplaneClient */\n options: ReplaneClientOptions<T>;\n children: ReactNode;\n /**\n * Optional loading component to show while the client is initializing.\n * If not provided and suspense is false/undefined, children will not render until ready.\n */\n loader?: ReactNode;\n /**\n * If true, uses React Suspense for loading state.\n * The provider will throw a promise that Suspense can catch.\n * @default false\n */\n suspense?: boolean;\n /**\n * Callback when client initialization fails.\n */\n onError?: (error: Error) => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ReplaneProviderProps<T extends object = any> =\n | ReplaneProviderWithClientProps<T>\n | ReplaneProviderWithOptionsProps<T>;\n\n/**\n * Type guard to check if props contain a pre-created client.\n */\nexport function hasClient<T extends object>(\n props: ReplaneProviderProps<T>\n): props is ReplaneProviderWithClientProps<T> {\n return \"client\" in props && props.client !== undefined;\n}\n","import { useMemo } from \"react\";\nimport { ReplaneContext } from \"./context\";\nimport { useReplaneClient, useReplaneClientSuspense } from \"./useReplaneClient\";\nimport type {\n ReplaneProviderProps,\n ReplaneProviderWithClientProps,\n ReplaneProviderWithOptionsProps,\n ReplaneContextValue,\n} from \"./types\";\nimport { hasClient } from \"./types\";\n\n/**\n * Internal provider component for pre-created client.\n */\nfunction ReplaneProviderWithClient<T extends object>({\n client,\n children,\n}: ReplaneProviderWithClientProps<T>) {\n const value = useMemo<ReplaneContextValue<T>>(() => ({ client }), [client]);\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Internal provider component for options-based client creation (non-suspense).\n */\nfunction ReplaneProviderWithOptions<T extends object>({\n options,\n children,\n loader,\n onError,\n}: ReplaneProviderWithOptionsProps<T>) {\n const state = useReplaneClient<T>(options, onError);\n\n if (state.status === \"loading\") {\n return <>{loader ?? null}</>;\n }\n\n if (state.status === \"error\") {\n // Error was already reported via onError callback\n // Return loader or null to prevent rendering children without a client\n return <>{loader ?? null}</>;\n }\n\n const value: ReplaneContextValue<T> = { client: state.client };\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Internal provider component for options-based client creation with Suspense.\n */\nfunction ReplaneProviderWithSuspense<T extends object>({\n options,\n children,\n}: ReplaneProviderWithOptionsProps<T>) {\n const client = useReplaneClientSuspense<T>(options);\n const value = useMemo<ReplaneContextValue<T>>(() => ({ client }), [client]);\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Provider component that makes a ReplaneClient available to the component tree.\n *\n * Can be used in two ways:\n *\n * 1. With a pre-created client:\n * ```tsx\n * const client = await createReplaneClient({ ... });\n * <ReplaneProvider client={client}>\n * <App />\n * </ReplaneProvider>\n * ```\n *\n * 2. With options (client managed internally):\n * ```tsx\n * <ReplaneProvider\n * options={{ baseUrl: '...', sdkKey: '...' }}\n * loader={<LoadingSpinner />}\n * >\n * <App />\n * </ReplaneProvider>\n * ```\n *\n * 3. With Suspense:\n * ```tsx\n * <Suspense fallback={<LoadingSpinner />}>\n * <ReplaneProvider\n * options={{ baseUrl: '...', sdkKey: '...' }}\n * suspense\n * >\n * <App />\n * </ReplaneProvider>\n * </Suspense>\n * ```\n */\nexport function ReplaneProvider<T extends object>(props: ReplaneProviderProps<T>) {\n if (hasClient(props)) {\n return <ReplaneProviderWithClient {...props} />;\n }\n\n if (props.suspense) {\n return <ReplaneProviderWithSuspense {...props} />;\n }\n\n return <ReplaneProviderWithOptions {...props} />;\n}\n","import { useContext, useSyncExternalStore } from \"react\";\nimport { ReplaneContext } from \"./context\";\nimport type { ReplaneContextValue } from \"./types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useReplane<T extends object = any>(): ReplaneContextValue<T> {\n const context = useContext(ReplaneContext);\n if (!context) {\n throw new Error(\"useReplane must be used within a ReplaneProvider\");\n }\n return context as ReplaneContextValue<T>;\n}\n\nexport function useConfig<T>(\n name: string,\n options?: { context?: Record<string, string | number | boolean | null> }\n): T {\n const { client } = useReplane();\n\n const value = useSyncExternalStore(\n (onStoreChange) => {\n return client.subscribe(name, onStoreChange);\n },\n () => client.get(name, options) as T,\n () => client.get(name, options) as T\n );\n\n return value;\n}\n"],"mappings":";;;;;AAIA,MAAa,iBAAiB,cAA+C,KAAK;;;;ACMlF,MAAM,gBAAgB,IAAI;AAW1B,SAAS,YAA8BA,SAA0C;AAC/E,SAAQ,EAAE,QAAQ,QAAQ,GAAG,QAAQ,OAAO;AAC7C;;;;;AAOD,SAAgB,iBACdA,SACAC,SACgB;CAChB,MAAM,CAAC,OAAO,SAAS,GAAG,SAAyB;EACjD,QAAQ;EACR,QAAQ;EACR,OAAO;CACR,EAAC;CACF,MAAM,YAAY,OAAgC,KAAK;CACvD,MAAM,aAAa,OAAO,QAAQ;AAElC,WAAU,MAAM;EACd,IAAI,YAAY;EAEhB,eAAe,aAAa;AAC1B,OAAI;IACF,MAAM,SAAS,MAAM,oBAAuB,WAAW,QAAQ;AAC/D,QAAI,WAAW;AACb,YAAO,OAAO;AACd;IACD;AACD,cAAU,UAAU;AACpB,aAAS;KAAE,QAAQ;KAAS;KAAQ,OAAO;IAAM,EAAC;GACnD,SAAQ,KAAK;AACZ,QAAI,UAAW;IACf,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI;AAChE,aAAS;KAAE,QAAQ;KAAS,QAAQ;KAAM;IAAO,EAAC;AAClD,cAAU,MAAM;GACjB;EACF;AAED,cAAY;AAEZ,SAAO,MAAM;AACX,eAAY;AACZ,OAAI,UAAU,SAAS;AACrB,cAAU,QAAQ,OAAO;AACzB,cAAU,UAAU;GACrB;EACF;CAIF,GAAE,CAAE,EAAC;AAEN,QAAO;AACR;;;;;AAOD,SAAgB,yBACdD,SACkB;CAClB,MAAM,WAAW,YAAY,QAAQ;CACrC,MAAM,SAAS,cAAc,IAAI,SAAS;AAE1C,KAAI,QAAQ;AACV,MAAI,OAAO,MACT,OAAM,OAAO;AAEf,MAAI,OAAO,OACT,QAAO,OAAO;AAGhB,QAAM,OAAO;CACd;CAGD,MAAM,UAAU,oBAAuB,QAAQ,CAC5C,KAAK,CAAC,WAAW;EAChB,MAAM,QAAQ,cAAc,IAAI,SAAS;AACzC,MAAI,MACF,OAAM,SAAS;AAEjB,SAAO;CACR,EAAC,CACD,MAAM,CAAC,QAAQ;EACd,MAAM,QAAQ,cAAc,IAAI,SAAS;AACzC,MAAI,MACF,OAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI;AAElE,QAAM;CACP,EAAC;AAEJ,eAAc,IAAI,UAAU,EAAE,QAAS,EAAC;AACxC,OAAM;AACP;;;;;AAMD,SAAgB,mBAAqCE,SAAyC;AAC5F,KAAI,QACF,eAAc,OAAO,YAAY,QAAQ,CAAC;KAE1C,eAAc,OAAO;AAExB;;;;;;;ACjFD,SAAgB,UACdC,OAC4C;AAC5C,QAAO,YAAY,SAAS,MAAM;AACnC;;;;;;;ACzCD,SAAS,0BAA4C,EACnD,QACA,UACkC,EAAE;CACpC,MAAM,QAAQ,QAAgC,OAAO,EAAE,OAAQ,IAAG,CAAC,MAAO,EAAC;AAC3E,wBAAO,IAAC,eAAe;EAAgB;EAAQ;GAAmC;AACnF;;;;AAKD,SAAS,2BAA6C,EACpD,SACA,UACA,QACA,SACmC,EAAE;CACrC,MAAM,QAAQ,iBAAoB,SAAS,QAAQ;AAEnD,KAAI,MAAM,WAAW,UACnB,wBAAO,0BAAG,UAAU,OAAQ;AAG9B,KAAI,MAAM,WAAW,QAGnB,wBAAO,0BAAG,UAAU,OAAQ;CAG9B,MAAMC,QAAgC,EAAE,QAAQ,MAAM,OAAQ;AAC9D,wBAAO,IAAC,eAAe;EAAgB;EAAQ;GAAmC;AACnF;;;;AAKD,SAAS,4BAA8C,EACrD,SACA,UACmC,EAAE;CACrC,MAAM,SAAS,yBAA4B,QAAQ;CACnD,MAAM,QAAQ,QAAgC,OAAO,EAAE,OAAQ,IAAG,CAAC,MAAO,EAAC;AAC3E,wBAAO,IAAC,eAAe;EAAgB;EAAQ;GAAmC;AACnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCD,SAAgB,gBAAkCC,OAAgC;AAChF,KAAI,UAAU,MAAM,CAClB,wBAAO,IAAC,6BAA0B,GAAI,QAAS;AAGjD,KAAI,MAAM,SACR,wBAAO,IAAC,+BAA4B,GAAI,QAAS;AAGnD,wBAAO,IAAC,8BAA2B,GAAI,QAAS;AACjD;;;;ACnGD,SAAgB,aAA6D;CAC3E,MAAM,UAAU,WAAW,eAAe;AAC1C,MAAK,QACH,OAAM,IAAI,MAAM;AAElB,QAAO;AACR;AAED,SAAgB,UACdC,MACAC,SACG;CACH,MAAM,EAAE,QAAQ,GAAG,YAAY;CAE/B,MAAM,QAAQ,qBACZ,CAAC,kBAAkB;AACjB,SAAO,OAAO,UAAU,MAAM,cAAc;CAC7C,GACD,MAAM,OAAO,IAAI,MAAM,QAAQ,EAC/B,MAAM,OAAO,IAAI,MAAM,QAAQ,CAChC;AAED,QAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["options: ReplaneClientOptions<T>","onError?: (error: Error) => void","options?: ReplaneClientOptions<T>","props: ReplaneProviderProps<T>","value: ReplaneContextValue<T>","props: ReplaneProviderProps<T>","name: string","options?: { context?: Record<string, string | number | boolean | null> }"],"sources":["../src/context.ts","../src/useReplaneClient.ts","../src/types.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext } from \"react\";\nimport type { ReplaneContextValue } from \"./types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const ReplaneContext = createContext<ReplaneContextValue<any> | null>(null);\n","import { useEffect, useRef, useState } from \"react\";\nimport { createReplaneClient } from \"@replanejs/sdk\";\nimport type { ReplaneClient, ReplaneClientOptions } from \"@replanejs/sdk\";\n\ntype ClientState<T extends object> =\n | { status: \"loading\"; client: null; error: null }\n | { status: \"ready\"; client: ReplaneClient<T>; error: null }\n | { status: \"error\"; client: null; error: Error };\n\n// Cache for suspense promise tracking\nconst suspenseCache = new Map<\n string,\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n promise: Promise<ReplaneClient<any>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n result?: ReplaneClient<any>;\n error?: Error;\n }\n>();\n\nfunction getCacheKey<T extends object>(options: ReplaneClientOptions<T>): string {\n return `${options.baseUrl}:${options.sdkKey}`;\n}\n\n/**\n * Hook to manage ReplaneClient creation internally.\n * Handles loading state and cleanup.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useReplaneClient<T extends object = any>(\n options: ReplaneClientOptions<T>,\n onError?: (error: Error) => void\n): ClientState<T> {\n const [state, setState] = useState<ClientState<T>>({\n status: \"loading\",\n client: null,\n error: null,\n });\n const clientRef = useRef<ReplaneClient<T> | null>(null);\n const optionsRef = useRef(options);\n\n useEffect(() => {\n let cancelled = false;\n\n async function initClient() {\n try {\n const client = await createReplaneClient<T>(optionsRef.current);\n if (cancelled) {\n client.close();\n return;\n }\n clientRef.current = client;\n setState({ status: \"ready\", client, error: null });\n } catch (err) {\n if (cancelled) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setState({ status: \"error\", client: null, error });\n onError?.(error);\n }\n }\n\n initClient();\n\n return () => {\n cancelled = true;\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n };\n // We intentionally only run this effect once on mount\n // Options changes would require remounting the provider\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return state;\n}\n\n/**\n * Hook for Suspense-based client creation.\n * Throws a promise while loading, throws error on failure.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useReplaneClientSuspense<T extends object = any>(\n options: ReplaneClientOptions<T>\n): ReplaneClient<T> {\n const cacheKey = getCacheKey(options);\n const cached = suspenseCache.get(cacheKey);\n\n if (cached) {\n if (cached.error) {\n throw cached.error;\n }\n if (cached.result) {\n return cached.result as ReplaneClient<T>;\n }\n // Still loading, throw the promise\n throw cached.promise;\n }\n\n // First time - create the promise\n const promise = createReplaneClient<T>(options)\n .then((client) => {\n const entry = suspenseCache.get(cacheKey);\n if (entry) {\n entry.result = client;\n }\n return client;\n })\n .catch((err) => {\n const entry = suspenseCache.get(cacheKey);\n if (entry) {\n entry.error = err instanceof Error ? err : new Error(String(err));\n }\n throw err;\n });\n\n suspenseCache.set(cacheKey, { promise });\n throw promise;\n}\n\n/**\n * Clear the suspense cache for a specific options configuration.\n * Useful for testing or when you need to force re-initialization.\n */\nexport function clearSuspenseCache<T extends object>(options?: ReplaneClientOptions<T>): void {\n if (options) {\n suspenseCache.delete(getCacheKey(options));\n } else {\n suspenseCache.clear();\n }\n}\n","import type { ReplaneClient, ReplaneClientOptions } from \"@replanejs/sdk\";\nimport type { ReactNode } from \"react\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneContextValue<T extends object = any> {\n client: ReplaneClient<T>;\n}\n\n/**\n * Props for ReplaneProvider when using a pre-created client.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneProviderWithClientProps<T extends object = any> {\n /** Pre-created ReplaneClient instance */\n client: ReplaneClient<T>;\n children: ReactNode;\n}\n\n/**\n * Props for ReplaneProvider when letting it manage the client internally.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface ReplaneProviderWithOptionsProps<T extends object = any> {\n /** Options to create the ReplaneClient */\n options: ReplaneClientOptions<T>;\n children: ReactNode;\n /**\n * Optional loading component to show while the client is initializing.\n * If not provided and suspense is false/undefined, children will not render until ready.\n */\n loader?: ReactNode;\n /**\n * If true, uses React Suspense for loading state.\n * The provider will throw a promise that Suspense can catch.\n * @default false\n */\n suspense?: boolean;\n /**\n * Callback when client initialization fails.\n */\n onError?: (error: Error) => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ReplaneProviderProps<T extends object = any> =\n | ReplaneProviderWithClientProps<T>\n | ReplaneProviderWithOptionsProps<T>;\n\n/**\n * Type guard to check if props contain a pre-created client.\n */\nexport function hasClient<T extends object>(\n props: ReplaneProviderProps<T>\n): props is ReplaneProviderWithClientProps<T> {\n return \"client\" in props && props.client !== undefined;\n}\n","import { useMemo } from \"react\";\nimport { ReplaneContext } from \"./context\";\nimport { useReplaneClient, useReplaneClientSuspense } from \"./useReplaneClient\";\nimport type {\n ReplaneProviderProps,\n ReplaneProviderWithClientProps,\n ReplaneProviderWithOptionsProps,\n ReplaneContextValue,\n} from \"./types\";\nimport { hasClient } from \"./types\";\n\n/**\n * Internal provider component for pre-created client.\n */\nfunction ReplaneProviderWithClient<T extends object>({\n client,\n children,\n}: ReplaneProviderWithClientProps<T>) {\n const value = useMemo<ReplaneContextValue<T>>(() => ({ client }), [client]);\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Internal provider component for options-based client creation (non-suspense).\n */\nfunction ReplaneProviderWithOptions<T extends object>({\n options,\n children,\n loader,\n onError,\n}: ReplaneProviderWithOptionsProps<T>) {\n const state = useReplaneClient<T>(options, onError);\n\n if (state.status === \"loading\") {\n return <>{loader ?? null}</>;\n }\n\n if (state.status === \"error\") {\n // Error was already reported via onError callback\n // Return loader or null to prevent rendering children without a client\n return <>{loader ?? null}</>;\n }\n\n const value: ReplaneContextValue<T> = { client: state.client };\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Internal provider component for options-based client creation with Suspense.\n */\nfunction ReplaneProviderWithSuspense<T extends object>({\n options,\n children,\n}: ReplaneProviderWithOptionsProps<T>) {\n const client = useReplaneClientSuspense<T>(options);\n const value = useMemo<ReplaneContextValue<T>>(() => ({ client }), [client]);\n return <ReplaneContext.Provider value={value}>{children}</ReplaneContext.Provider>;\n}\n\n/**\n * Provider component that makes a ReplaneClient available to the component tree.\n *\n * Can be used in two ways:\n *\n * 1. With a pre-created client:\n * ```tsx\n * const client = await createReplaneClient({ ... });\n * <ReplaneProvider client={client}>\n * <App />\n * </ReplaneProvider>\n * ```\n *\n * 2. With options (client managed internally):\n * ```tsx\n * <ReplaneProvider\n * options={{ baseUrl: '...', sdkKey: '...' }}\n * loader={<LoadingSpinner />}\n * >\n * <App />\n * </ReplaneProvider>\n * ```\n *\n * 3. With Suspense:\n * ```tsx\n * <Suspense fallback={<LoadingSpinner />}>\n * <ReplaneProvider\n * options={{ baseUrl: '...', sdkKey: '...' }}\n * suspense\n * >\n * <App />\n * </ReplaneProvider>\n * </Suspense>\n * ```\n */\nexport function ReplaneProvider<T extends object>(props: ReplaneProviderProps<T>) {\n if (hasClient(props)) {\n return <ReplaneProviderWithClient {...props} />;\n }\n\n if (props.suspense) {\n return <ReplaneProviderWithSuspense {...props} />;\n }\n\n return <ReplaneProviderWithOptions {...props} />;\n}\n","import { useContext, useSyncExternalStore } from \"react\";\nimport { ReplaneContext } from \"./context\";\nimport type { ReplaneContextValue } from \"./types\";\n\nexport function useReplane<T extends object = Record<string, unknown>>(): ReplaneContextValue<T> {\n const context = useContext(ReplaneContext);\n if (!context) {\n throw new Error(\"useReplane must be used within a ReplaneProvider\");\n }\n return context as ReplaneContextValue<T>;\n}\n\nexport function useConfig<T>(\n name: string,\n options?: { context?: Record<string, string | number | boolean | null> }\n): T {\n const { client } = useReplane();\n\n const value = useSyncExternalStore(\n (onStoreChange) => {\n return client.subscribe(name, onStoreChange);\n },\n () => client.get(name, options) as T,\n () => client.get(name, options) as T\n );\n\n return value;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replanejs/react",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "React SDK for Replane - feature flags and remote configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"react": ">=18.0.0"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@replanejs/sdk": "0.7.
|
|
43
|
+
"@replanejs/sdk": "^0.7.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@testing-library/jest-dom": "^6.9.1",
|