import { useQuery, useQueryClient, useMutation, type UseQueryOptions, type UseMutationOptions, } from "@tanstack/react-query"; import { useEffect } from "react"; import type { RpcEventSchema, RpcSchema } from "@yaakapp-internal/proxy-lib"; import { minPromiseMillis } from "@yaakapp-internal/ui"; import { listen, rpc } from "./rpc"; type Req = RpcSchema[K][0]; type Res = RpcSchema[K][1]; /** * React Query wrapper for RPC commands. * Automatically caches by [cmd, payload] and supports all useQuery options. */ export function useRpcQuery( cmd: K, payload: Req, opts?: Omit>, "queryKey" | "queryFn">, ) { return useQuery>({ queryKey: [cmd, payload], queryFn: () => rpc(cmd, payload), ...opts, }); } /** * React Query mutation wrapper for RPC commands. */ export function useRpcMutation( cmd: K, opts?: Omit, Error, Req>, "mutationFn">, ) { return useMutation, Error, Req>({ mutationFn: (payload) => minPromiseMillis(rpc(cmd, payload)), ...opts, }); } /** * Subscribe to an RPC event. Cleans up automatically on unmount. */ export function useRpcEvent( event: K & string, callback: (payload: RpcEventSchema[K]) => void, ) { useEffect(() => { return listen(event, callback); }, [event, callback]); } /** * Combines useRpcQuery with an event listener that invalidates the query * whenever the specified event fires, keeping data fresh automatically. */ export function useRpcQueryWithEvent< K extends keyof RpcSchema, E extends keyof RpcEventSchema & string, >( cmd: K, payload: Req, event: E, opts?: Omit>, "queryKey" | "queryFn">, ) { const queryClient = useQueryClient(); const query = useRpcQuery(cmd, payload, opts); useRpcEvent(event, () => { queryClient.invalidateQueries({ queryKey: [cmd, payload] }); }); return query; }