import { useCallback } from "react"; import type { SWRConfiguration, SWRResponse } from "swr"; import useSWR from "swr"; import type { Pending } from "./async-op.ts"; import type { IndieTabletopClient } from "./client.ts"; import { swrResponseToResult } from "./result/swr.ts"; /** * Creates a `useInvokeClient` hook that makes it ergonomic to invoke * client methods. * * Note that only methods starting with `get` are picked up. This hook is * intended for making easy fetches, not for form submissions. */ export function createUseInvokeClient(c: C) { // eslint-disable-next-line @typescript-eslint/no-explicit-any type Fn = (...args: any) => any; return function useInvokeClient( /** * ITC Client's method name. */ method: K, /** * Method's arguments. * * **IMPORTANT**: Must be an array or primitive values as it is directly * used as a `useCallback` dependecy array. */ args: C[K] extends Fn ? Parameters : never, options?: { performFetch?: boolean; swr?: SWRConfiguration; }, ): C[K] extends Fn ? [Awaited> | Pending, SWRResponse] : never { const { performFetch = true } = options ?? {}; const callback = useCallback(() => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return (c[method] as Fn)(...args); // eslint-disable-next-line react-hooks/exhaustive-deps }, [method, ...args]); const cacheKey = [method, ...args].join(":"); const swr = useSWR(performFetch ? cacheKey : null, callback, options?.swr); return [swrResponseToResult(swr), swr] as never; }; }