UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

276 lines (275 loc) 19 kB
import { n as DeepPartial, o as Simplify, r as DistributiveOmit } from "../types-DF2cg_w0.js"; import { C as HttpProcedure, d as CRPCHttpRouter, j as DataTransformerOptions, p as HttpRouterRecord } from "../http-types-zsMHb_QN.js"; import { g as UnsetMarker } from "../types-CnTpHR1F.js"; import { A as HttpInputArgs, C as ReservedMutationOptions$1, S as ReservedInfiniteQueryOptions, T as StaticQueryOptsParam, _ as IsPaginated, b as PaginatedFnMeta, c as ConvexMutationKey, d as ConvexQueryMeta, f as EmptyObject, g as InfiniteQueryInput, l as ConvexQueryHookOptions, m as FUNC_REF_SYMBOL, o as ConvexActionKey, p as ExtractPaginatedItem, s as ConvexInfiniteQueryMeta, u as ConvexQueryKey, w as ReservedQueryOptions$1, y as MutationVariables } from "../types-YHpe0rsb.js"; import { FunctionArgs, FunctionReference, FunctionReturnType } from "convex/server"; import { z } from "zod"; import { DefaultError, QueryFilters, SkipToken, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query"; //#region src/react/crpc-types.d.ts /** Options returned by `convexQuery` factory */ type ConvexQueryOptions<T extends FunctionReference<'query'>> = Pick<UseQueryOptions<FunctionReturnType<T>, Error, FunctionReturnType<T>, ConvexQueryKey<T>>, 'queryKey' | 'staleTime' | 'enabled'>; /** Options returned by `convexAction` factory */ type ConvexActionOptions<T extends FunctionReference<'action'>> = Pick<UseQueryOptions<FunctionReturnType<T>, Error, FunctionReturnType<T>, ConvexActionKey<T>>, 'queryKey' | 'staleTime' | 'enabled'>; /** Query options parameter type */ type QueryOptsParam<T extends FunctionReference<'query'>> = Simplify<ConvexQueryHookOptions & DistributiveOmit<UseQueryOptions<FunctionReturnType<T>, DefaultError>, ReservedQueryOptions$1>>; /** Query options return type */ type QueryOptsReturn<T extends FunctionReference<'query'>> = ConvexQueryOptions<T> & { meta: ConvexQueryMeta; }; /** Action query options parameter type (actions don't support subscriptions) */ type ActionQueryOptsParam<T extends FunctionReference<'action'>> = DistributiveOmit<UseQueryOptions<FunctionReturnType<T>, DefaultError>, ReservedQueryOptions$1>; /** Action query options return type */ type ActionQueryOptsReturn<T extends FunctionReference<'action'>> = ConvexActionOptions<T>; /** * Decorated query procedure with queryOptions, queryKey, and queryFilter methods. * Args are optional when the function has no required parameters. * Supports skipToken for type-safe conditional queries. */ type DecorateQuery<T extends FunctionReference<'query'>> = { queryOptions: keyof FunctionArgs<T> extends never ? (args?: EmptyObject | SkipToken, opts?: QueryOptsParam<T>) => QueryOptsReturn<T> : EmptyObject extends FunctionArgs<T> ? (args?: FunctionArgs<T> | SkipToken, opts?: QueryOptsParam<T>) => QueryOptsReturn<T> : (args: FunctionArgs<T> | SkipToken, opts?: QueryOptsParam<T>) => QueryOptsReturn<T>; /** Static (non-hook) query options for event handlers and prefetching */ staticQueryOptions: keyof FunctionArgs<T> extends never ? (args?: EmptyObject | SkipToken, opts?: StaticQueryOptsParam) => ConvexQueryOptions<T> & { meta: ConvexQueryMeta; } : EmptyObject extends FunctionArgs<T> ? (args?: FunctionArgs<T> | SkipToken, opts?: StaticQueryOptsParam) => ConvexQueryOptions<T> & { meta: ConvexQueryMeta; } : (args: FunctionArgs<T> | SkipToken, opts?: StaticQueryOptsParam) => ConvexQueryOptions<T> & { meta: ConvexQueryMeta; }; /** Get query key for QueryClient methods (setQueryData, getQueryData, etc.) */ queryKey: (args?: DeepPartial<FunctionArgs<T>>) => ConvexQueryKey<T>; /** Get query filter for QueryClient methods (invalidateQueries, removeQueries, etc.) */ queryFilter: (args?: DeepPartial<FunctionArgs<T>>, filters?: DistributiveOmit<QueryFilters, 'queryKey'>) => QueryFilters; }; /** Options for infinite query - extends TanStack Query options */ type InfiniteQueryOptsParam<T extends FunctionReference<'query'> = FunctionReference<'query'>> = { /** Items per page. Optional - server uses .paginated() default if not provided. */limit?: number; /** Skip query silently when unauthenticated */ skipUnauth?: boolean; /** Placeholder data shown while loading (item array, not pagination result) */ placeholderData?: ExtractPaginatedItem<FunctionReturnType<T>>[]; } & DistributiveOmit<UseQueryOptions<FunctionReturnType<T>, DefaultError>, ReservedInfiniteQueryOptions>; /** Return type of infiniteQueryOptions - compatible with TanStack prefetch */ type ConvexInfiniteQueryOptions<T extends FunctionReference<'query'>> = Pick<UseQueryOptions<FunctionReturnType<T>, Error, FunctionReturnType<T>, ConvexQueryKey<T>>, 'queryKey' | 'staleTime' | 'enabled'> & { meta: ConvexInfiniteQueryMeta; refetchInterval: false; refetchOnMount: false; refetchOnReconnect: false; refetchOnWindowFocus: false; /** Placeholder data shown while loading (item array, not pagination result) */ placeholderData?: ExtractPaginatedItem<FunctionReturnType<T>>[]; } & DistributiveOmit<UseQueryOptions<FunctionReturnType<T>, DefaultError>, ReservedInfiniteQueryOptions>; /** Infinite query options with attached function reference (client-only) */ type ConvexInfiniteQueryOptionsWithRef<T extends FunctionReference<'query'>> = ConvexInfiniteQueryOptions<T> & { [FUNC_REF_SYMBOL]: T; }; /** Infinite query options return type */ type InfiniteQueryOptsReturn<T extends FunctionReference<'query'>> = ConvexInfiniteQueryOptionsWithRef<T>; /** * Decorated infinite query procedure. * Only available on queries that have cursor/limit in their input (paginated). * Supports skipToken for conditional queries. * Args are optional when the function has no required parameters (besides cursor/limit). */ type DecorateInfiniteQuery<T extends FunctionReference<'query'>> = { /** Create infinite query options for useInfiniteQuery and prefetch */infiniteQueryOptions: keyof InfiniteQueryInput<FunctionArgs<T>> extends never ? (args?: EmptyObject | SkipToken, opts?: InfiniteQueryOptsParam<T>) => InfiniteQueryOptsReturn<T> : EmptyObject extends InfiniteQueryInput<FunctionArgs<T>> ? (args?: InfiniteQueryInput<FunctionArgs<T>> | SkipToken, opts?: InfiniteQueryOptsParam<T>) => InfiniteQueryOptsReturn<T> : (args: InfiniteQueryInput<FunctionArgs<T>> | SkipToken, opts?: InfiniteQueryOptsParam<T>) => InfiniteQueryOptsReturn<T>; /** Get query key for infinite query (QueryClient methods like setQueryData, getQueryData) */ infiniteQueryKey: (args?: DeepPartial<InfiniteQueryInput<FunctionArgs<T>>>) => ConvexQueryKey<T>; /** Function metadata from server (auth, limit, rateLimit, role, type) */ meta: PaginatedFnMeta; }; /** * Decorated mutation procedure with mutationOptions and mutationKey methods. */ type DecorateMutation<T extends FunctionReference<'mutation'>> = { mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$1>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */ mutationKey: () => ConvexMutationKey; }; /** * Decorated action procedure with queryOptions, mutationOptions, and key methods. * Actions can be used as one-shot queries (no subscription) or as mutations. * Supports skipToken for conditional queries. */ type DecorateAction<T extends FunctionReference<'action'>> = { /** Use action as a one-shot query (no WebSocket subscription) */queryOptions: keyof FunctionArgs<T> extends never ? (args?: EmptyObject | SkipToken, opts?: ActionQueryOptsParam<T>) => ActionQueryOptsReturn<T> : EmptyObject extends FunctionArgs<T> ? (args?: FunctionArgs<T> | SkipToken, opts?: ActionQueryOptsParam<T>) => ActionQueryOptsReturn<T> : (args: FunctionArgs<T> | SkipToken, opts?: ActionQueryOptsParam<T>) => ActionQueryOptsReturn<T>; /** Static (non-hook) action query options for event handlers and prefetching */ staticQueryOptions: keyof FunctionArgs<T> extends never ? (args?: EmptyObject | SkipToken, opts?: StaticQueryOptsParam) => ConvexActionOptions<T> & { meta: ConvexQueryMeta; } : EmptyObject extends FunctionArgs<T> ? (args?: FunctionArgs<T> | SkipToken, opts?: StaticQueryOptsParam) => ConvexActionOptions<T> & { meta: ConvexQueryMeta; } : (args: FunctionArgs<T> | SkipToken, opts?: StaticQueryOptsParam) => ConvexActionOptions<T> & { meta: ConvexQueryMeta; }; /** Use action as a mutation */ mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$1>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */ mutationKey: () => ConvexMutationKey; /** Get query key for QueryClient methods */ queryKey: (args?: DeepPartial<FunctionArgs<T>>) => ConvexActionKey<T>; /** Get query filter for QueryClient methods */ queryFilter: (args?: DeepPartial<FunctionArgs<T>>, filters?: DistributiveOmit<QueryFilters, 'queryKey'>) => QueryFilters; }; /** * Recursively decorates all procedures in a Convex API object. */ type CRPCClient<TApi> = { [K in keyof TApi as K extends string ? K extends `_${string}` ? never : K : K]: TApi[K] extends FunctionReference<'query'> ? IsPaginated<FunctionArgs<TApi[K]>> extends true ? DecorateQuery<TApi[K]> & DecorateInfiniteQuery<TApi[K]> : DecorateQuery<TApi[K]> : TApi[K] extends FunctionReference<'mutation'> ? DecorateMutation<TApi[K]> : TApi[K] extends FunctionReference<'action'> ? DecorateAction<TApi[K]> : TApi[K] extends Record<string, unknown> ? CRPCClient<TApi[K]> : never }; //#endregion //#region src/react/http-proxy.d.ts /** Infer schema type or return empty object if UnsetMarker */ type InferSchemaOrEmpty<T> = T extends UnsetMarker ? object : T extends z.ZodTypeAny ? z.infer<T> : object; /** Infer merged input from HttpProcedure (flat - used internally) */ type InferHttpInput<T> = T extends HttpProcedure<infer TInput, infer _TOutput, infer TParams, infer TQuery> ? Simplify<InferSchemaOrEmpty<TParams> & InferSchemaOrEmpty<TQuery> & InferSchemaOrEmpty<TInput>> : object; /** * Extract string keys from a Zod object schema. * Used for param/query which are always strings in URLs. */ type ZodObjectKeys<T> = T extends z.ZodObject<infer Shape> ? { [K in keyof Shape]: string } : Record<string, string>; /** * Extract string or string[] keys from a Zod object schema. * Query params can have array values. */ type ZodQueryKeys<T> = T extends z.ZodObject<infer Shape> ? { [K in keyof Shape]?: string | string[] } : Record<string, string | string[]>; /** * Infer client-side args from HttpProcedure with proper nesting. * - params: only present if TParams is defined, always strings (URL path params) * - searchParams: only present if TQuery is defined, always strings (URL query params) * - form: only present if TForm is defined, typed from schema * - JSON body fields spread at root level (typed from schema) * - Client options (fetch, init, headers) always optional for per-call overrides */ type InferHttpClientArgs<T> = T extends HttpProcedure<infer TInput, infer _TOutput, infer TParams, infer TQuery, infer _TMethod, infer TForm> ? Simplify<(TParams extends UnsetMarker ? object : { params: ZodObjectKeys<TParams>; }) & (TQuery extends UnsetMarker ? object : { searchParams: ZodQueryKeys<TQuery>; }) & (TForm extends UnsetMarker ? object : TForm extends z.ZodTypeAny ? { form: z.infer<TForm>; } : object) & (TInput extends UnsetMarker ? object : TInput extends z.ZodTypeAny ? z.infer<TInput> : object) & { fetch?: typeof fetch; init?: RequestInit; headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>); }> : HttpInputArgs; /** Infer output type from HttpProcedure */ type InferHttpOutput<T> = T extends HttpProcedure<infer _TInput, infer TOutput, infer _TParams, infer _TQuery> ? TOutput extends UnsetMarker ? unknown : TOutput extends z.ZodTypeAny ? z.infer<TOutput> : unknown : unknown; /** Query key with args (3-element) or prefix key without args (2-element) for invalidation */ type HttpQueryKey = readonly ['httpQuery', string, unknown] | readonly ['httpQuery', string]; type HttpMutationKey = readonly ['httpMutation', string]; type ReservedQueryOptions = 'queryKey' | 'queryFn'; type ReservedMutationOptions = 'mutationFn'; /** Query options for GET HTTP endpoints - compatible with both useQuery and useSuspenseQuery */ type HttpQueryOptsReturn<T extends HttpProcedure> = Omit<UseQueryOptions<InferHttpOutput<T>, Error, InferHttpOutput<T>, HttpQueryKey>, 'queryFn'> & { queryFn: () => Promise<InferHttpOutput<T>>; }; /** Mutation options for POST/PUT/PATCH/DELETE HTTP endpoints - typed variables */ type HttpMutationOptsReturn<T extends HttpProcedure> = UseMutationOptions<InferHttpOutput<T>, DefaultError, InferHttpClientArgs<T>>; /** Query options (TanStack Query only - client opts go in args) */ type HttpQueryOptions<T extends HttpProcedure> = DistributiveOmit<HttpQueryOptsReturn<T>, ReservedQueryOptions>; /** Mutation options (TanStack Query only - client opts go in mutate args) */ type HttpMutationOptions<T extends HttpProcedure> = DistributiveOmit<HttpMutationOptsReturn<T>, ReservedMutationOptions>; /** * Decorated GET procedure with queryOptions and mutationOptions. * - queryOptions: For cached data fetching (useQuery/useSuspenseQuery) * - mutationOptions: For one-time actions like exports (useMutation) */ type DecorateHttpQuery<T extends HttpProcedure> = { queryOptions: keyof InferHttpInput<T> extends never ? (args?: InferHttpClientArgs<T>, opts?: HttpQueryOptions<T>) => HttpQueryOptsReturn<T> : object extends InferHttpInput<T> ? (args?: InferHttpClientArgs<T>, opts?: HttpQueryOptions<T>) => HttpQueryOptsReturn<T> : (args: InferHttpClientArgs<T>, opts?: HttpQueryOptions<T>) => HttpQueryOptsReturn<T>; /** Get query key for QueryClient methods (with args = exact match, without = prefix) */ queryKey: (args?: InferHttpClientArgs<T>) => HttpQueryKey; /** Get query filter for QueryClient methods (e.g., invalidateQueries) */ queryFilter: (args?: InferHttpClientArgs<T>, filters?: DistributiveOmit<QueryFilters, 'queryKey'>) => QueryFilters; /** Mutation options for GET endpoints (exports, downloads - no caching) */ mutationOptions: (opts?: HttpMutationOptions<T>) => HttpMutationOptsReturn<T>; /** Get mutation key for QueryClient methods */ mutationKey: () => HttpMutationKey; }; /** * Decorated POST/PUT/PATCH/DELETE procedure with mutationOptions. * The mutationFn receives typed args inferred from server schemas. */ type DecorateHttpMutation<T extends HttpProcedure> = { mutationOptions: (opts?: HttpMutationOptions<T>) => HttpMutationOptsReturn<T>; /** Get mutation key for QueryClient methods */ mutationKey: () => HttpMutationKey; }; /** Vanilla HTTP query - only direct call, no React Query */ /** * HTTP Client type from router record. * Maps each procedure to queryOptions (GET) or mutationOptions (POST/etc). * Uses infer to extract the method type literal for proper GET/non-GET distinction. */ type HttpCRPCClient<T extends HttpRouterRecord> = { [K in keyof T]: T[K] extends HttpProcedure<infer _TInput, infer _TOutput, infer _TParams, infer _TQuery, infer TMethod, infer _TForm> ? TMethod extends 'GET' ? DecorateHttpQuery<T[K]> : DecorateHttpMutation<T[K]> : T[K] extends CRPCHttpRouter<infer R> ? HttpCRPCClient<R> : T[K] extends HttpRouterRecord ? HttpCRPCClient<T[K]> : never }; /** * HTTP Client type from a CRPCHttpRouter. * Use this when your type is the router object (with _def). */ type HttpCRPCClientFromRouter<TRouter extends CRPCHttpRouter<any>> = HttpCRPCClient<TRouter['_def']['record']>; //#endregion //#region src/rsc/proxy-server.d.ts type CreateServerCRPCProxyOptions<TApi> = { api: TApi; }; /** * Extract HTTP router from TApi['http'] if present (optional). * Uses NonNullable to handle optional http property. */ type ExtractHttpRouter<TApi> = TApi extends { http?: infer R; } ? NonNullable<R> extends CRPCHttpRouter<HttpRouterRecord> ? NonNullable<R> : undefined : undefined; /** * Combined CRPC client type with optional HTTP router. * HTTP router is extracted from TApi['http'] if present. * Uses Omit to prevent type conflicts between CRPCClient and HttpCRPCClient. */ type ServerCRPCClient<TApi extends Record<string, unknown>> = ExtractHttpRouter<TApi> extends CRPCHttpRouter<HttpRouterRecord> ? CRPCClient<Omit<TApi, 'http'>> & { http: HttpCRPCClientFromRouter<ExtractHttpRouter<TApi>>; } : CRPCClient<TApi>; /** * Create a server-compatible CRPC proxy for RSC. * Only supports queryOptions (no mutations in RSC). * * Query execution (including auth) is handled by getServerQueryClientOptions. * * @example * ```tsx * // src/lib/convex/rsc.tsx * import { api } from '@convex/api'; * * // Proxy just builds query options - no auth config here * export const crpc = createServerCRPCProxy({ api }); * * // Auth + execution config in QueryClient * const queryClient = new QueryClient({ * defaultOptions: getServerQueryClientOptions({ * getToken: caller.getToken, * convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL, * }), * }); * * // app/page.tsx (RSC) * prefetch(crpc.posts.list.queryOptions()); * prefetch(crpc.http.health.queryOptions({})); * ``` */ declare function createServerCRPCProxy<TApi extends Record<string, unknown>>(options: CreateServerCRPCProxyOptions<TApi>): ServerCRPCClient<TApi>; //#endregion //#region src/rsc/server-query-client.d.ts type GetServerQueryClientOptionsParams = { /** Function to get auth token for authenticated queries. Use `caller.getToken` from your RSC setup. */getToken?: () => Promise<string | undefined>; /** Base URL for HTTP routes (e.g., NEXT_PUBLIC_CONVEX_SITE_URL). Required for crpc.http.* queries. */ convexSiteUrl?: string; /** Optional payload transformer (always composed with built-in Date support). */ transformer?: DataTransformerOptions; }; /** * Get server QueryClient options for RSC prefetching. * Handles both WebSocket queries (convexQuery/convexAction) and HTTP routes (httpQuery). * * @example * ```ts * const queryClient = new QueryClient({ * defaultOptions: { * ...getServerQueryClientOptions({ * getToken: caller.getToken, * convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL, * }), * }, * }); * ``` */ declare function getServerQueryClientOptions({ getToken, convexSiteUrl, transformer: transformerOptions }?: GetServerQueryClientOptionsParams): { queries: { staleTime: number; queryFn: ({ queryKey, meta }: { queryKey: readonly unknown[]; meta?: Record<string, unknown>; }) => Promise<any>; queryKeyHashFn: (queryKey: readonly unknown[]) => string; }; }; //#endregion export { CreateServerCRPCProxyOptions, GetServerQueryClientOptionsParams, type ServerCRPCClient, createServerCRPCProxy, getServerQueryClientOptions };