import type { DataTag, DefinedInitialDataOptions, QueryClient, QueryFunction, SkipToken, UndefinedInitialDataOptions, UnusedSkipTokenOptions, } from '@tanstack/react-query'; import { queryOptions, skipToken } from '@tanstack/react-query'; import type { TRPCClientErrorLike, TRPCUntypedClient } from '@trpc/client'; import type { coerceAsyncIterableToArray, DistributiveOmit, } from '@trpc/server/unstable-core-do-not-import'; import { isAsyncIterable } from '@trpc/server/unstable-core-do-not-import'; import type { DefaultFeatureFlags, FeatureFlags, ResolverDef, TRPCQueryBaseOptions, TRPCQueryKey, TRPCQueryOptionsResult, } from './types'; import { buildQueryFromAsyncIterable, createTRPCOptionsResult, getClientArgs, unwrapLazyArg, } from './utils'; type ReservedOptions = 'queryKey' | 'queryFn' | 'queryHashFn' | 'queryHash'; interface UndefinedTRPCQueryOptionsIn< TQueryFnData, TData, TError, TFeatureFlags extends FeatureFlags, > extends DistributiveOmit< UndefinedInitialDataOptions< coerceAsyncIterableToArray, TError, coerceAsyncIterableToArray, TRPCQueryKey >, ReservedOptions >, TRPCQueryBaseOptions {} interface UndefinedTRPCQueryOptionsOut< TQueryFnData, TOutput, TError, TFeatureFlags extends FeatureFlags, > extends UndefinedInitialDataOptions< coerceAsyncIterableToArray, TError, coerceAsyncIterableToArray, TRPCQueryKey >, TRPCQueryOptionsResult { queryKey: DataTag< TRPCQueryKey, coerceAsyncIterableToArray, TError >; } interface DefinedTRPCQueryOptionsIn< TQueryFnData, TData, TError, TFeatureFlags extends FeatureFlags, > extends DistributiveOmit< DefinedInitialDataOptions< coerceAsyncIterableToArray>, TError, coerceAsyncIterableToArray, TRPCQueryKey >, ReservedOptions >, TRPCQueryBaseOptions {} interface DefinedTRPCQueryOptionsOut< TQueryFnData, TData, TError, TFeatureFlags extends FeatureFlags, > extends DefinedInitialDataOptions< coerceAsyncIterableToArray, TError, coerceAsyncIterableToArray, TRPCQueryKey >, TRPCQueryOptionsResult { queryKey: DataTag< TRPCQueryKey, coerceAsyncIterableToArray, TError >; } interface UnusedSkipTokenTRPCQueryOptionsIn< TQueryFnData, TData, TError, TFeatureFlags extends FeatureFlags, > extends DistributiveOmit< UnusedSkipTokenOptions< coerceAsyncIterableToArray, TError, coerceAsyncIterableToArray, TRPCQueryKey >, ReservedOptions >, TRPCQueryBaseOptions {} interface UnusedSkipTokenTRPCQueryOptionsOut< TQueryFnData, TOutput, TError, TFeatureFlags extends FeatureFlags, > extends UnusedSkipTokenOptions< coerceAsyncIterableToArray, TError, coerceAsyncIterableToArray, TRPCQueryKey >, TRPCQueryOptionsResult { queryKey: DataTag< TRPCQueryKey, coerceAsyncIterableToArray, TError >; } export interface TRPCQueryOptions< TDef extends ResolverDef, TFeatureFlags extends FeatureFlags = DefaultFeatureFlags, > { ( input: TDef['input'] | SkipToken, opts: DefinedTRPCQueryOptionsIn< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >, ): DefinedTRPCQueryOptionsOut< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >; ( input: TDef['input'], opts?: UnusedSkipTokenTRPCQueryOptionsIn< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >, ): UnusedSkipTokenTRPCQueryOptionsOut< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >; ( input: TDef['input'] | SkipToken, opts?: UndefinedTRPCQueryOptionsIn< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >, ): UndefinedTRPCQueryOptionsOut< TQueryFnData, TData, TRPCClientErrorLike<{ transformer: TDef['transformer']; errorShape: TDef['errorShape']; }>, TFeatureFlags >; } type AnyTRPCQueryOptionsIn = | DefinedTRPCQueryOptionsIn | UnusedSkipTokenTRPCQueryOptionsIn | UndefinedTRPCQueryOptionsIn; type AnyTRPCQueryOptionsOut< TFeatureFlags extends FeatureFlags = DefaultFeatureFlags, > = | DefinedTRPCQueryOptionsOut | UnusedSkipTokenTRPCQueryOptionsOut | UndefinedTRPCQueryOptionsOut; /** * @internal */ export function trpcQueryOptions(args: { input: unknown; query: typeof TRPCUntypedClient.prototype.query; queryClient: QueryClient | (() => QueryClient); path: string[]; queryKey: TRPCQueryKey; opts: AnyTRPCQueryOptionsIn | undefined; }): AnyTRPCQueryOptionsOut { const { input, query, path, queryKey, opts } = args; const queryClient = unwrapLazyArg(args.queryClient); const inputIsSkipToken = input === skipToken; const queryFn: QueryFunction< unknown, TRPCQueryKey > = async (queryFnContext) => { const actualOpts = { ...opts, trpc: { ...opts?.trpc, ...(opts?.trpc?.abortOnUnmount ? { signal: queryFnContext.signal } : { signal: null }), }, }; const queryKey = queryFnContext.queryKey; const result = await query(...getClientArgs(queryKey, actualOpts)); if (isAsyncIterable(result)) { return buildQueryFromAsyncIterable(result, queryClient, queryKey); } return result; }; return Object.assign( queryOptions({ ...opts, queryKey: queryKey, queryFn: inputIsSkipToken ? skipToken : queryFn, }), { trpc: createTRPCOptionsResult({ path }) }, ); }