kitcn
Version:
kitcn - React Query integration and CLI tools for Convex
276 lines (275 loc) • 19 kB
TypeScript
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 };