FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,11 @@
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import { createQueryUtilsProxy } from './shared';
import type { CreateQueryUtilsOptions } from './utils/createUtilityFunctions';
import { createUtilityFunctions } from './utils/createUtilityFunctions';
export function createTRPCQueryUtils<TRouter extends AnyRouter>(
opts: CreateQueryUtilsOptions<TRouter>,
) {
const utils = createUtilityFunctions(opts);
return createQueryUtilsProxy<TRouter>(utils);
}

518
node_modules/@trpc/react-query/src/createTRPCReact.tsx generated vendored Normal file
View File

@@ -0,0 +1,518 @@
import type {
DefinedInitialDataInfiniteOptions,
DefinedUseInfiniteQueryResult,
InfiniteData,
SkipToken,
UndefinedInitialDataInfiniteOptions,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
UseSuspenseInfiniteQueryOptions,
UseSuspenseInfiniteQueryResult,
UseSuspenseQueryResult,
} from '@tanstack/react-query';
import type { createTRPCClient, TRPCClientErrorLike } from '@trpc/client';
import type {
AnyProcedure,
AnyRootTypes,
AnyRouter,
inferAsyncIterableYield,
inferProcedureInput,
inferTransformedProcedureOutput,
ProcedureType,
ProtectedIntersection,
RouterRecord,
Simplify,
} from '@trpc/server/unstable-core-do-not-import';
import { createFlatProxy } from '@trpc/server/unstable-core-do-not-import';
import * as React from 'react';
import type {
TRPCUseQueries,
TRPCUseSuspenseQueries,
} from './internals/useQueries';
import type {
CreateReactUtils,
TRPCFetchInfiniteQueryOptions,
TRPCFetchQueryOptions,
} from './shared';
import { createReactDecoration, createReactQueryUtils } from './shared';
import type { CreateReactQueryHooks } from './shared/hooks/createHooksInternal';
import { createRootHooks } from './shared/hooks/createHooksInternal';
import type {
DefinedUseTRPCQueryOptions,
DefinedUseTRPCQueryResult,
TRPCHookResult,
TRPCProvider,
TRPCSubscriptionResult,
TRPCUseQueryBaseOptions,
UseTRPCMutationOptions,
UseTRPCMutationResult,
UseTRPCQueryOptions,
UseTRPCQueryResult,
UseTRPCSubscriptionOptions,
UseTRPCSuspenseQueryOptions,
} from './shared/hooks/types';
import type { CreateTRPCReactOptions } from './shared/types';
type ResolverDef = {
input: any;
output: any;
transformer: boolean;
errorShape: any;
};
/**
* @internal
*/
export interface ProcedureUseQuery<TDef extends ResolverDef> {
<TQueryFnData extends TDef['output'] = TDef['output'], TData = TQueryFnData>(
input: TDef['input'] | SkipToken,
opts: DefinedUseTRPCQueryOptions<
TQueryFnData,
TData,
TRPCClientErrorLike<{
errorShape: TDef['errorShape'];
transformer: TDef['transformer'];
}>,
TDef['output']
>,
): DefinedUseTRPCQueryResult<
TData,
TRPCClientErrorLike<{
errorShape: TDef['errorShape'];
transformer: TDef['transformer'];
}>
>;
<TQueryFnData extends TDef['output'] = TDef['output'], TData = TQueryFnData>(
input: TDef['input'] | SkipToken,
opts?: UseTRPCQueryOptions<
TQueryFnData,
TData,
TRPCClientErrorLike<TDef>,
TDef['output']
>,
): UseTRPCQueryResult<TData, TRPCClientErrorLike<TDef>>;
}
/**
* @internal
*/
export type ProcedureUsePrefetchQuery<TDef extends ResolverDef> = (
input: TDef['input'] | SkipToken,
opts?: TRPCFetchQueryOptions<TDef['output'], TRPCClientErrorLike<TDef>>,
) => void;
/**
* @remark `void` is here due to https://github.com/trpc/trpc/pull/4374
*/
type CursorInput = {
cursor?: any;
} | void;
type ReservedInfiniteQueryKeys = 'cursor' | 'direction';
type InfiniteInput<TInput> =
| Omit<TInput, ReservedInfiniteQueryKeys>
| SkipToken;
type inferCursorType<TInput> = TInput extends { cursor?: any }
? TInput['cursor']
: unknown;
type makeInfiniteQueryOptions<TCursor, TOptions> = Omit<
TOptions,
'queryKey' | 'initialPageParam' | 'queryFn' | 'queryHash' | 'queryHashFn'
> &
TRPCUseQueryBaseOptions & {
initialCursor?: TCursor;
};
type trpcInfiniteData<TDef extends ResolverDef> = Simplify<
InfiniteData<TDef['output'], inferCursorType<TDef['input']>>
>;
// references from react-query
// 1st
// declare function useInfiniteQuery<
// TQueryFnData,
// TError = DefaultError,
// TData = InfiniteData<TQueryFnData>,
// TQueryKey extends QueryKey = QueryKey,
// TPageParam = unknown,
// >(
// options: DefinedInitialDataInfiniteOptions<
// TQueryFnData,
// TError,
// TData,
// TQueryKey,
// TPageParam
// >,
// queryClient?: QueryClient,
// ): DefinedUseInfiniteQueryResult<TData, TError>;
// 2nd
// declare function useInfiniteQuery<
// TQueryFnData,
// TError = DefaultError,
// TData = InfiniteData<TQueryFnData>,
// TQueryKey extends QueryKey = QueryKey,
// TPageParam = unknown,
// >(
// options: UndefinedInitialDataInfiniteOptions<
// TQueryFnData,
// TError,
// TData,
// TQueryKey,
// TPageParam
// >,
// queryClient?: QueryClient,
// ): UseInfiniteQueryResult<TData, TError>;
// 3rd
// declare function useInfiniteQuery<
// TQueryFnData,
// TError = DefaultError,
// TData = InfiniteData<TQueryFnData>,
// TQueryKey extends QueryKey = QueryKey,
// TPageParam = unknown,
// >(
// options: UseInfiniteQueryOptions<
// TQueryFnData,
// TError,
// TData,
// TQueryFnData,
// TQueryKey,
// TPageParam
// >,
// queryClient?: QueryClient,
// ): UseInfiniteQueryResult<TData, TError>;
export interface useTRPCInfiniteQuery<TDef extends ResolverDef> {
// 1st
<TData = trpcInfiniteData<TDef>>(
input: InfiniteInput<TDef['input']>,
opts: makeInfiniteQueryOptions<
inferCursorType<TDef['input']>,
DefinedInitialDataInfiniteOptions<
// TQueryFnData,
TDef['output'],
// TError,
TRPCClientErrorLike<TDef>,
// TData,
TData,
// TQueryKey,
any,
// TPageParam
inferCursorType<TDef['input']>
>
>,
): TRPCHookResult &
DefinedUseInfiniteQueryResult<TData, TRPCClientErrorLike<TDef>>;
// 2nd
<TData = trpcInfiniteData<TDef>>(
input: InfiniteInput<TDef['input']>,
opts?: makeInfiniteQueryOptions<
inferCursorType<TDef['input']>,
UndefinedInitialDataInfiniteOptions<
// TQueryFnData,
TDef['output'],
// TError,
TRPCClientErrorLike<TDef>,
// TData,
TData,
// TQueryKey,
any,
// TPageParam
inferCursorType<TDef['input']>
>
>,
): TRPCHookResult & UseInfiniteQueryResult<TData, TRPCClientErrorLike<TDef>>;
// 3rd:
<TData = trpcInfiniteData<TDef>>(
input: InfiniteInput<TDef['input']>,
opts?: makeInfiniteQueryOptions<
inferCursorType<TDef['input']>,
UseInfiniteQueryOptions<
// TQueryFnData,
TDef['output'],
// TError,
TRPCClientErrorLike<TDef>,
// TData,
TData,
// TQueryKey,
any,
// TPageParam
inferCursorType<TDef['input']>
>
>,
): TRPCHookResult & UseInfiniteQueryResult<TData, TRPCClientErrorLike<TDef>>;
}
// references from react-query
// declare function useSuspenseInfiniteQuery<
// TQueryFnData,
// TError = DefaultError,
// TData = InfiniteData<TQueryFnData>,
// TQueryKey extends QueryKey = QueryKey,
// TPageParam = unknown,
// >(
// options: UseSuspenseInfiniteQueryOptions<
// TQueryFnData,
// TError,
// TData,
// TQueryFnData,
// TQueryKey,
// TPageParam
// >,
// queryClient?: QueryClient,
// ): UseSuspenseInfiniteQueryResult<TData, TError>;
export type useTRPCSuspenseInfiniteQuery<TDef extends ResolverDef> = (
input: InfiniteInput<TDef['input']>,
opts: makeInfiniteQueryOptions<
inferCursorType<TDef['input']>,
UseSuspenseInfiniteQueryOptions<
// TQueryFnData,
TDef['output'],
// TError,
TRPCClientErrorLike<TDef>,
// TData,
trpcInfiniteData<TDef>,
// TQueryKey,
any,
// TPageParam
inferCursorType<TDef['input']>
>
>,
) => [
trpcInfiniteData<TDef>,
TRPCHookResult &
UseSuspenseInfiniteQueryResult<
trpcInfiniteData<TDef>,
TRPCClientErrorLike<TDef>
>,
];
/**
* @internal
*/
export type MaybeDecoratedInfiniteQuery<TDef extends ResolverDef> =
TDef['input'] extends CursorInput
? {
/**
* @see https://trpc.io/docs/v11/client/react/useInfiniteQuery
*/
useInfiniteQuery: useTRPCInfiniteQuery<TDef>;
/**
* @see https://trpc.io/docs/client/react/suspense#usesuspenseinfinitequery
*/
useSuspenseInfiniteQuery: useTRPCSuspenseInfiniteQuery<TDef>;
usePrefetchInfiniteQuery: (
input: Omit<TDef['input'], ReservedInfiniteQueryKeys> | SkipToken,
opts: TRPCFetchInfiniteQueryOptions<
TDef['input'],
TDef['output'],
TRPCClientErrorLike<TDef>
>,
) => void;
}
: object;
/**
* @internal
*/
export type DecoratedQueryMethods<TDef extends ResolverDef> = {
/**
* @see https://trpc.io/docs/v11/client/react/useQuery
*/
useQuery: ProcedureUseQuery<TDef>;
usePrefetchQuery: ProcedureUsePrefetchQuery<TDef>;
/**
* @see https://trpc.io/docs/v11/client/react/suspense#usesuspensequery
*/
useSuspenseQuery: <
TQueryFnData extends TDef['output'] = TDef['output'],
TData = TQueryFnData,
>(
input: TDef['input'],
opts?: UseTRPCSuspenseQueryOptions<
TQueryFnData,
TData,
TRPCClientErrorLike<TDef>
>,
) => [
TData,
UseSuspenseQueryResult<TData, TRPCClientErrorLike<TDef>> & TRPCHookResult,
];
};
/**
* @internal
*/
export type DecoratedQuery<TDef extends ResolverDef> =
MaybeDecoratedInfiniteQuery<TDef> & DecoratedQueryMethods<TDef>;
export type DecoratedMutation<TDef extends ResolverDef> = {
/**
* @see https://trpc.io/docs/v11/client/react/useMutation
*/
useMutation: <TContext = unknown>(
opts?: UseTRPCMutationOptions<
TDef['input'],
TRPCClientErrorLike<TDef>,
TDef['output'],
TContext
>,
) => UseTRPCMutationResult<
TDef['output'],
TRPCClientErrorLike<TDef>,
TDef['input'],
TContext
>;
};
interface ProcedureUseSubscription<TDef extends ResolverDef> {
// Without skip token
(
input: TDef['input'],
opts?: UseTRPCSubscriptionOptions<
inferAsyncIterableYield<TDef['output']>,
TRPCClientErrorLike<TDef>
>,
): TRPCSubscriptionResult<
inferAsyncIterableYield<TDef['output']>,
TRPCClientErrorLike<TDef>
>;
// With skip token
(
input: TDef['input'] | SkipToken,
opts?: Omit<
UseTRPCSubscriptionOptions<
inferAsyncIterableYield<TDef['output']>,
TRPCClientErrorLike<TDef>
>,
'enabled'
>,
): TRPCSubscriptionResult<
inferAsyncIterableYield<TDef['output']>,
TRPCClientErrorLike<TDef>
>;
}
/**
* @internal
*/
export type DecorateProcedure<
TType extends ProcedureType,
TDef extends ResolverDef,
> = TType extends 'query'
? DecoratedQuery<TDef>
: TType extends 'mutation'
? DecoratedMutation<TDef>
: TType extends 'subscription'
? {
/**
* @see https://trpc.io/docs/v11/subscriptions
*/
useSubscription: ProcedureUseSubscription<TDef>;
}
: never;
/**
* @internal
*/
export type DecorateRouterRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyProcedure
? DecorateProcedure<
$Value['_def']['type'],
{
input: inferProcedureInput<$Value>;
output: inferTransformedProcedureOutput<TRoot, $Value>;
transformer: TRoot['transformer'];
errorShape: TRoot['errorShape'];
}
>
: $Value extends RouterRecord
? DecorateRouterRecord<TRoot, $Value>
: never
: never;
};
/**
* @internal
*/
export type CreateTRPCReactBase<TRouter extends AnyRouter, TSSRContext> = {
/**
* @deprecated renamed to `useUtils` and will be removed in a future tRPC version
*
* @see https://trpc.io/docs/v11/client/react/useUtils
*/
useContext(): CreateReactUtils<TRouter, TSSRContext>;
/**
* @see https://trpc.io/docs/v11/client/react/useUtils
*/
useUtils(): CreateReactUtils<TRouter, TSSRContext>;
Provider: TRPCProvider<TRouter, TSSRContext>;
createClient: typeof createTRPCClient<TRouter>;
useQueries: TRPCUseQueries<TRouter>;
useSuspenseQueries: TRPCUseSuspenseQueries<TRouter>;
};
export type CreateTRPCReact<
TRouter extends AnyRouter,
TSSRContext,
> = ProtectedIntersection<
CreateTRPCReactBase<TRouter, TSSRContext>,
DecorateRouterRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>
>;
/**
* @internal
*/
export function createHooksInternal<
TRouter extends AnyRouter,
TSSRContext = unknown,
>(trpc: CreateReactQueryHooks<TRouter, TSSRContext>) {
type CreateHooksInternal = CreateTRPCReact<TRouter, TSSRContext>;
const proxy = createReactDecoration<TRouter, TSSRContext>(
trpc,
) as DecorateRouterRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>;
return createFlatProxy<CreateHooksInternal>((key) => {
if (key === 'useContext' || key === 'useUtils') {
return () => {
const context = trpc.useUtils();
// create a stable reference of the utils context
return React.useMemo(() => {
return (createReactQueryUtils as any)(context);
}, [context]);
};
}
if (trpc.hasOwnProperty(key)) {
return (trpc as any)[key];
}
return proxy[key];
});
}
export function createTRPCReact<
TRouter extends AnyRouter,
TSSRContext = unknown,
>(
opts?: CreateTRPCReactOptions<TRouter>,
): CreateTRPCReact<TRouter, TSSRContext> {
const hooks = createRootHooks<TRouter, TSSRContext>(opts);
const proxy = createHooksInternal<TRouter, TSSRContext>(hooks);
return proxy as any;
}

10
node_modules/@trpc/react-query/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
export * from '@trpc/client';
export { getQueryKey, getMutationKey } from './internals/getQueryKey';
export {
createTRPCReact,
type CreateTRPCReact,
type CreateTRPCReactBase,
} from './createTRPCReact';
export type { inferReactQueryProcedureOptions } from './utils/inferReactQueryProcedure';
export { createTRPCQueryUtils } from './createTRPCQueryUtils';

View File

@@ -0,0 +1,350 @@
import type {
CancelOptions,
FetchInfiniteQueryOptions,
FetchQueryOptions,
InfiniteData,
InvalidateOptions,
InvalidateQueryFilters,
MutationOptions,
QueryClient,
QueryFilters,
QueryKey,
RefetchOptions,
RefetchQueryFilters,
ResetOptions,
SetDataOptions,
Updater,
} from '@tanstack/react-query';
import type {
TRPCClient,
TRPCClientError,
TRPCRequestOptions,
TRPCUntypedClient,
} from '@trpc/client';
import type {
AnyClientTypes,
AnyRouter,
DistributiveOmit,
} from '@trpc/server/unstable-core-do-not-import';
import * as React from 'react';
import type {
DefinedTRPCInfiniteQueryOptionsIn,
DefinedTRPCInfiniteQueryOptionsOut,
DefinedTRPCQueryOptionsIn,
DefinedTRPCQueryOptionsOut,
ExtractCursorType,
UndefinedTRPCInfiniteQueryOptionsIn,
UndefinedTRPCInfiniteQueryOptionsOut,
UndefinedTRPCQueryOptionsIn,
UndefinedTRPCQueryOptionsOut,
} from '../shared';
import type { TRPCMutationKey, TRPCQueryKey } from './getQueryKey';
interface TRPCUseUtilsOptions {
/**
* tRPC-related options
*/
trpc?: TRPCRequestOptions;
}
export interface TRPCFetchQueryOptions<TOutput, TError>
extends DistributiveOmit<FetchQueryOptions<TOutput, TError>, 'queryKey'>,
TRPCUseUtilsOptions {
//
}
export type TRPCFetchInfiniteQueryOptions<TInput, TOutput, TError> =
DistributiveOmit<
FetchInfiniteQueryOptions<
TOutput,
TError,
TOutput,
TRPCQueryKey,
ExtractCursorType<TInput>
>,
'queryKey' | 'initialPageParam'
> &
TRPCUseUtilsOptions & {
initialCursor?: ExtractCursorType<TInput>;
};
/** @internal */
export type SSRState = 'mounted' | 'mounting' | 'prepass' | false;
export interface TRPCContextPropsBase<TRouter extends AnyRouter, TSSRContext> {
/**
* The `TRPCClient`
*/
client: TRPCUntypedClient<TRouter>;
/**
* The SSR context when server-side rendering
* @default null
*/
ssrContext?: TSSRContext | null;
/**
* State of SSR hydration.
* - `false` if not using SSR.
* - `prepass` when doing a prepass to fetch queries' data
* - `mounting` before TRPCProvider has been rendered on the client
* - `mounted` when the TRPCProvider has been rendered on the client
* @default false
*/
ssrState?: SSRState;
/**
* @deprecated pass abortOnUnmount to `createTRPCReact` instead
* Abort loading query calls when unmounting a component - usually when navigating to a new page
* @default false
*/
abortOnUnmount?: boolean;
}
/**
* @internal
*/
export type DecoratedTRPCContextProps<
TRouter extends AnyRouter,
TSSRContext,
> = TRPCContextPropsBase<TRouter, TSSRContext> & {
client: TRPCClient<TRouter>;
};
export interface TRPCContextProps<TRouter extends AnyRouter, TSSRContext>
extends TRPCContextPropsBase<TRouter, TSSRContext> {
/**
* The react-query `QueryClient`
*/
queryClient: QueryClient;
}
export const contextProps: (keyof TRPCContextPropsBase<any, any>)[] = [
'client',
'ssrContext',
'ssrState',
'abortOnUnmount',
];
/**
* @internal
*/
export interface TRPCContextState<
TRouter extends AnyRouter,
TSSRContext = undefined,
> extends Required<TRPCContextProps<TRouter, TSSRContext>>,
TRPCQueryUtils<TRouter> {}
/**
* @internal
*/
export interface TRPCQueryUtils<TRouter extends AnyRouter> {
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/queryOptions#queryoptions
*/
queryOptions(
path: readonly string[], // <-- look into if needed
queryKey: TRPCQueryKey,
opts?: UndefinedTRPCQueryOptionsIn<
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>,
): UndefinedTRPCQueryOptionsOut<
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>;
queryOptions(
path: readonly string[], // <-- look into if needed
queryKey: TRPCQueryKey,
opts: DefinedTRPCQueryOptionsIn<
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>,
): DefinedTRPCQueryOptionsOut<
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/infiniteQueryOptions#infinitequeryoptions
*/
infiniteQueryOptions(
path: readonly string[], // <-- look into if needed
queryKey: TRPCQueryKey,
opts: UndefinedTRPCInfiniteQueryOptionsIn<
unknown,
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>,
): UndefinedTRPCInfiniteQueryOptionsOut<
unknown,
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>;
infiniteQueryOptions(
path: readonly string[], // <-- look into if needed
queryKey: TRPCQueryKey,
opts: DefinedTRPCInfiniteQueryOptionsIn<
unknown,
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>,
): DefinedTRPCInfiniteQueryOptionsOut<
unknown,
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchquery
*/
fetchQuery: (
queryKey: TRPCQueryKey,
opts?: TRPCFetchQueryOptions<unknown, TRPCClientError<TRouter>>,
) => Promise<unknown>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchinfinitequery
*/
fetchInfiniteQuery: (
queryKey: TRPCQueryKey,
opts?: TRPCFetchInfiniteQueryOptions<
unknown,
unknown,
TRPCClientError<TRouter>
>,
) => Promise<InfiniteData<unknown, unknown>>;
/**
* @see https://tanstack.com/query/v5/docs/framework/react/guides/prefetching
*/
prefetchQuery: (
queryKey: TRPCQueryKey,
opts?: TRPCFetchQueryOptions<unknown, TRPCClientError<TRouter>>,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientprefetchinfinitequery
*/
prefetchInfiniteQuery: (
queryKey: TRPCQueryKey,
opts?: TRPCFetchInfiniteQueryOptions<
unknown,
unknown,
TRPCClientError<TRouter>
>,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientensurequerydata
*/
ensureQueryData: (
queryKey: TRPCQueryKey,
opts?: TRPCFetchQueryOptions<unknown, TRPCClientError<TRouter>>,
) => Promise<unknown>;
/**
* @see https://tanstack.com/query/v5/docs/framework/react/guides/query-invalidation
*/
invalidateQueries: (
queryKey: TRPCQueryKey,
filters?: InvalidateQueryFilters<TRPCQueryKey>,
options?: InvalidateOptions,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientresetqueries
*/
resetQueries: (
queryKey: TRPCQueryKey,
filters?: QueryFilters<TRPCQueryKey>,
options?: ResetOptions,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientrefetchqueries
*/
refetchQueries: (
queryKey: TRPCQueryKey,
filters?: RefetchQueryFilters<TRPCQueryKey>,
options?: RefetchOptions,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/framework/react/guides/query-cancellation
*/
cancelQuery: (
queryKey: TRPCQueryKey,
options?: CancelOptions,
) => Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata
*/
setQueryData: (
queryKey: TRPCQueryKey,
updater: Updater<unknown, unknown>,
options?: SetDataOptions,
) => void;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetqueriesdata
*/
setQueriesData: (
queryKey: TRPCQueryKey,
filters: QueryFilters,
updater: Updater<unknown, unknown>,
options?: SetDataOptions,
) => [QueryKey, unknown][];
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata
*/
getQueryData: (queryKey: TRPCQueryKey) => unknown;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata
*/
setInfiniteQueryData: (
queryKey: TRPCQueryKey,
updater: Updater<
InfiniteData<unknown> | undefined,
InfiniteData<unknown> | undefined
>,
options?: SetDataOptions,
) => void;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata
*/
getInfiniteQueryData: (
queryKey: TRPCQueryKey,
) => InfiniteData<unknown> | undefined;
/**
* @see https://tanstack.com/query/latest/docs/reference/QueryClient/#queryclientsetmutationdefaults
*/
setMutationDefaults: (
mutationKey: TRPCMutationKey,
options:
| MutationOptions
| ((args: {
canonicalMutationFn: (input: unknown) => Promise<unknown>;
}) => MutationOptions),
) => void;
/**
* @see https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientgetmutationdefaults
*/
getMutationDefaults: (
mutationKey: TRPCMutationKey,
) => MutationOptions | undefined;
/**
* @see https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientismutating
*/
isMutating: (filters: { mutationKey: TRPCMutationKey }) => number;
}
export const TRPCContext = React.createContext?.(null as any);

View File

@@ -0,0 +1,24 @@
import type { TRPCQueryKey } from './getQueryKey';
/**
* @internal
*/
export function getClientArgs<TOptions>(
queryKey: TRPCQueryKey,
opts: TOptions,
infiniteParams?: {
pageParam: any;
direction: 'forward' | 'backward';
},
) {
const path = queryKey[0];
let input = queryKey[1]?.input;
if (infiniteParams) {
input = {
...(input ?? {}),
...(infiniteParams.pageParam ? { cursor: infiniteParams.pageParam } : {}),
direction: infiniteParams.direction,
};
}
return [path.join('.'), input, (opts as any)?.trpc] as const;
}

View File

@@ -0,0 +1,138 @@
import { skipToken } from '@tanstack/react-query';
import {
isObject,
type DeepPartial,
} from '@trpc/server/unstable-core-do-not-import';
import type { DecoratedMutation, DecoratedQuery } from '../createTRPCReact';
import type { DecorateRouterRecord } from '../shared';
export type QueryType = 'any' | 'infinite' | 'query';
export type TRPCQueryKey = [
readonly string[],
{ input?: unknown; type?: Exclude<QueryType, 'any'> }?,
];
export type TRPCMutationKey = [readonly string[]]; // = [TRPCQueryKey[0]]
type ProcedureOrRouter =
| DecoratedMutation<any>
| DecoratedQuery<any>
| DecorateRouterRecord<any, any>;
/**
* To allow easy interactions with groups of related queries, such as
* invalidating all queries of a router, we use an array as the path when
* storing in tanstack query.
**/
export function getQueryKeyInternal(
path: readonly string[],
input: unknown,
type: QueryType,
): TRPCQueryKey {
// Construct a query key that is easy to destructure and flexible for
// partial selecting etc.
// https://github.com/trpc/trpc/issues/3128
// some parts of the path may be dot-separated, split them up
const splitPath = path.flatMap((part) => part.split('.'));
if (!input && (!type || type === 'any')) {
// this matches also all mutations (see `getMutationKeyInternal`)
// for `utils.invalidate()` to match all queries (including vanilla react-query)
// we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
return splitPath.length ? [splitPath] : ([] as unknown as TRPCQueryKey);
}
if (
type === 'infinite' &&
isObject(input) &&
('direction' in input || 'cursor' in input)
) {
const {
cursor: _,
direction: __,
...inputWithoutCursorAndDirection
} = input;
return [
splitPath,
{
input: inputWithoutCursorAndDirection,
type: 'infinite',
},
];
}
return [
splitPath,
{
...(typeof input !== 'undefined' &&
input !== skipToken && { input: input }),
...(type && type !== 'any' && { type: type }),
},
];
}
export function getMutationKeyInternal(path: readonly string[]) {
return getQueryKeyInternal(path, undefined, 'any') as TRPCMutationKey;
}
type GetInfiniteQueryInput<
TProcedureInput,
TInputWithoutCursorAndDirection = Omit<
TProcedureInput,
'cursor' | 'direction'
>,
> = keyof TInputWithoutCursorAndDirection extends never
? undefined
: DeepPartial<TInputWithoutCursorAndDirection> | undefined;
/** @internal */
export type GetQueryProcedureInput<TProcedureInput> = TProcedureInput extends {
cursor?: any;
}
? GetInfiniteQueryInput<TProcedureInput>
: DeepPartial<TProcedureInput> | undefined;
type GetParams<TProcedureOrRouter extends ProcedureOrRouter> =
TProcedureOrRouter extends DecoratedQuery<infer $Def>
? [input?: GetQueryProcedureInput<$Def['input']>, type?: QueryType]
: [];
/**
* Method to extract the query key for a procedure
* @param procedureOrRouter - procedure or AnyRouter
* @param input - input to procedureOrRouter
* @param type - defaults to `any`
* @see https://trpc.io/docs/v11/getQueryKey
*/
export function getQueryKey<TProcedureOrRouter extends ProcedureOrRouter>(
procedureOrRouter: TProcedureOrRouter,
..._params: GetParams<TProcedureOrRouter>
) {
const [input, type] = _params;
// @ts-expect-error - we don't expose _def on the type layer
const path = procedureOrRouter._def().path as string[];
const queryKey = getQueryKeyInternal(path, input, type ?? 'any');
return queryKey;
}
// TODO: look over if we can't use a single type
export type QueryKeyKnown<TInput, TType extends Exclude<QueryType, 'any'>> = [
string[],
{ input?: GetQueryProcedureInput<TInput>; type: TType }?,
];
/**
* Method to extract the mutation key for a procedure
* @param procedure - procedure
* @see https://trpc.io/docs/v11/getQueryKey#mutations
*/
export function getMutationKey<TProcedure extends DecoratedMutation<any>>(
procedure: TProcedure,
) {
// @ts-expect-error - we don't expose _def on the type layer
const path = procedure._def().path as string[];
return getMutationKeyInternal(path);
}

View File

@@ -0,0 +1,55 @@
import type { QueryClient } from '@tanstack/react-query';
import * as React from 'react';
import type { TRPCQueryOptionsResult } from '../shared';
import type { TRPCHookResult } from '../shared/hooks/types';
import type { TRPCQueryKey } from './getQueryKey';
export function createTRPCOptionsResult(value: {
path: readonly string[];
}): TRPCQueryOptionsResult['trpc'] {
const path = value.path.join('.');
return {
path,
};
}
/**
* Makes a stable reference of the `trpc` prop
*/
export function useHookResult(value: {
path: readonly string[];
}): TRPCHookResult['trpc'] {
const result = createTRPCOptionsResult(value);
return React.useMemo(() => result, [result]);
}
/**
* @internal
*/
export async function buildQueryFromAsyncIterable(
asyncIterable: AsyncIterable<unknown>,
queryClient: QueryClient,
queryKey: TRPCQueryKey,
) {
const queryCache = queryClient.getQueryCache();
const query = queryCache.build(queryClient, {
queryKey,
});
query.setState({
data: [],
status: 'success',
});
const aggregate: unknown[] = [];
for await (const value of asyncIterable) {
aggregate.push(value);
query.setState({
data: [...aggregate],
});
}
return aggregate;
}

View File

@@ -0,0 +1,215 @@
import type {
QueryKey,
UseQueryOptions,
UseSuspenseQueryOptions,
UseSuspenseQueryResult,
} from '@tanstack/react-query';
import type {
AnyRouter,
DistributiveOmit,
} from '@trpc/server/unstable-core-do-not-import';
import type {
UseQueriesProcedureRecord,
UseSuspenseQueriesProcedureRecord,
UseTRPCQueryOptions,
UseTRPCQueryResult,
UseTRPCSuspenseQueryOptions,
} from '../shared';
/**
* @internal
*/
export type UseQueryOptionsForUseQueries<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = DistributiveOmit<
UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
'queryKey'
>;
/**
* @internal
*/
export type UseQueryOptionsForUseSuspenseQueries<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = DistributiveOmit<
UseSuspenseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
'queryKey'
>;
/**
* @internal
*/
export type TrpcQueryOptionsForUseQueries<TOutput, TData, TError> =
DistributiveOmit<UseTRPCQueryOptions<TOutput, TData, TError>, 'queryKey'>;
/**
* @internal
*/
export type TrpcQueryOptionsForUseSuspenseQueries<TOutput, TData, TError> =
DistributiveOmit<
UseTRPCSuspenseQueryOptions<TOutput, TData, TError>,
'queryKey'
>;
/**
* @internal
*/
export declare type QueriesResults<
TQueriesOptions extends UseQueryOptionsForUseQueries<any, any, any, any>[],
> = {
[TKey in keyof TQueriesOptions]: TQueriesOptions[TKey] extends UseQueryOptionsForUseQueries<
infer TQueryFnData,
infer TError,
infer TData,
any
>
? UseTRPCQueryResult<unknown extends TData ? TQueryFnData : TData, TError>
: never;
};
/**
* @internal
*/
export declare type SuspenseQueriesResults<
TQueriesOptions extends UseQueryOptionsForUseSuspenseQueries<
any,
any,
any,
any
>[],
> = [
{
[TKey in keyof TQueriesOptions]: TQueriesOptions[TKey] extends UseQueryOptionsForUseSuspenseQueries<
infer TQueryFnData,
any,
infer TData,
any
>
? unknown extends TData
? TQueryFnData
: TData
: never;
},
{
[TKey in keyof TQueriesOptions]: TQueriesOptions[TKey] extends UseQueryOptionsForUseSuspenseQueries<
infer TQueryFnData,
infer TError,
infer TData,
any
>
? UseSuspenseQueryResult<
unknown extends TData ? TQueryFnData : TData,
TError
>
: never;
},
];
type GetOptions<TQueryOptions> =
TQueryOptions extends UseQueryOptionsForUseQueries<any, any, any, any>
? TQueryOptions
: never;
/**
* @internal
*/
export type QueriesOptions<
TQueriesOptions extends any[],
TResult extends any[] = [],
> = TQueriesOptions extends []
? []
: TQueriesOptions extends [infer Head]
? [...TResult, GetOptions<Head>]
: TQueriesOptions extends [infer Head, ...infer Tail]
? QueriesOptions<Tail, [...TResult, GetOptions<Head>]>
: unknown[] extends TQueriesOptions
? TQueriesOptions
: TQueriesOptions extends UseQueryOptionsForUseQueries<
infer TQueryFnData,
infer TError,
infer TData,
infer TQueryKey
>[]
? UseQueryOptionsForUseQueries<
TQueryFnData,
TError,
TData,
TQueryKey
>[]
: UseQueryOptionsForUseQueries[];
type GetSuspenseOptions<TQueryOptions> =
TQueryOptions extends UseQueryOptionsForUseSuspenseQueries<any, any, any, any>
? TQueryOptions
: never;
/**
* @internal
*/
export type SuspenseQueriesOptions<
TQueriesOptions extends any[],
TResult extends any[] = [],
> = TQueriesOptions extends []
? []
: TQueriesOptions extends [infer Head]
? [...TResult, GetSuspenseOptions<Head>]
: TQueriesOptions extends [infer Head, ...infer Tail]
? SuspenseQueriesOptions<Tail, [...TResult, GetSuspenseOptions<Head>]>
: unknown[] extends TQueriesOptions
? TQueriesOptions
: TQueriesOptions extends UseQueryOptionsForUseSuspenseQueries<
infer TQueryFnData,
infer TError,
infer TData,
infer TQueryKey
>[]
? UseQueryOptionsForUseSuspenseQueries<
TQueryFnData,
TError,
TData,
TQueryKey
>[]
: UseQueryOptionsForUseSuspenseQueries[];
/**
* @internal
*/
export type TRPCUseQueries<TRouter extends AnyRouter> = <
TQueryOptions extends UseQueryOptionsForUseQueries<any, any, any, any>[],
TCombinedResult = QueriesResults<TQueryOptions>,
>(
queriesCallback: (
t: UseQueriesProcedureRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>,
) => readonly [...QueriesOptions<TQueryOptions>],
options?: {
combine?: (results: QueriesResults<TQueryOptions>) => TCombinedResult;
},
) => TCombinedResult;
/**
* @internal
*/
export type TRPCUseSuspenseQueries<TRouter extends AnyRouter> = <
TQueryOptions extends UseQueryOptionsForUseSuspenseQueries<
any,
any,
any,
any
>[],
>(
queriesCallback: (
t: UseSuspenseQueriesProcedureRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>,
) => readonly [...SuspenseQueriesOptions<TQueryOptions>],
) => SuspenseQueriesResults<TQueryOptions>;

197
node_modules/@trpc/react-query/src/rsc.tsx generated vendored Normal file
View File

@@ -0,0 +1,197 @@
/// <reference types="react/canary" />
import {
dehydrate,
HydrationBoundary,
type QueryClient,
} from '@tanstack/react-query';
import type { TRPCClientError } from '@trpc/client';
import type { inferTransformedProcedureOutput } from '@trpc/server';
import {
createRecursiveProxy,
type AnyRouter,
type inferProcedureInput,
type RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import type {
AnyProcedure,
AnyRootTypes,
inferProcedureOutput,
inferRouterRootTypes,
Maybe,
RouterCaller,
TypeError,
} from '@trpc/server/unstable-core-do-not-import';
import * as React from 'react';
import { getQueryKeyInternal } from './internals/getQueryKey';
import type {
TRPCFetchInfiniteQueryOptions,
TRPCFetchQueryOptions,
} from './shared';
const HELPERS = ['prefetch', 'prefetchInfinite'];
type DecorateProcedure<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
> = {
(
input: inferProcedureInput<TProcedure>,
): Promise<inferProcedureOutput<TProcedure>>;
prefetch: (
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchQueryOptions<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
) => Promise<void>;
prefetchInfinite: (
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchInfiniteQueryOptions<
inferProcedureInput<TProcedure>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
) => Promise<void>;
};
type DecorateRouterRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyProcedure
? DecorateProcedure<TRoot, $Value>
: $Value extends RouterRecord
? DecorateRouterRecord<TRoot, $Value>
: never
: never;
};
type Caller<TRouter extends AnyRouter> = ReturnType<
RouterCaller<inferRouterRootTypes<TRouter>, TRouter['_def']['record']>
>;
// ts-prune-ignore-next
/**
* @note This requires `@tanstack/react-query@^5.49.0`
* @note Make sure to have `dehydrate.serializeData` and `hydrate.deserializeData`
* set to your data transformer in your `QueryClient` factory.
* @example
* ```ts
* export const createQueryClient = () =>
* new QueryClient({
* defaultOptions: {
* dehydrate: {
* serializeData: transformer.serialize,
* },
* hydrate: {
* deserializeData: transformer.deserialize,
* },
* },
* });
* ```
*/
export function createHydrationHelpers<TRouter extends AnyRouter>(
caller: AnyRouter extends TRouter
? TypeError<'Generic parameter missing in `createHydrationHelpers<HERE>`'>
: Caller<TRouter>,
getQueryClient: () => QueryClient,
) {
type RootTypes = inferRouterRootTypes<TRouter>;
const wrappedProxy = createRecursiveProxy<
DecorateRouterRecord<RootTypes, TRouter['_def']['record']>
>(async (opts) => {
const path = [...opts.path];
const args = [...opts.args];
const proc = path.reduce(
(acc, key) =>
// @ts-expect-error - ??
HELPERS.includes(key) ? acc : acc[key],
caller,
) as unknown as DecorateProcedure<RootTypes, AnyProcedure>;
const input = args[0];
const promise = proc(input);
const helper = path.pop();
if (helper === 'prefetch') {
const args1 = args[1] as Maybe<
TRPCFetchInfiniteQueryOptions<any, any, any>
>;
return getQueryClient().prefetchQuery({
...args1,
queryKey: getQueryKeyInternal(path, input, 'query'),
queryFn: () => promise,
});
}
if (helper === 'prefetchInfinite') {
const args1 = args[1] as Maybe<
TRPCFetchInfiniteQueryOptions<any, any, any>
>;
return getQueryClient().prefetchInfiniteQuery({
...args1,
queryKey: getQueryKeyInternal(path, input, 'infinite'),
queryFn: () => promise,
initialPageParam: args1?.initialCursor ?? null,
});
}
return promise;
});
function HydrateClient(props: { children: React.ReactNode }) {
const dehydratedState = dehydrate(getQueryClient());
return (
<HydrationBoundary state={dehydratedState}>
{props.children}
</HydrationBoundary>
);
}
return {
/***
* Wrapped caller with prefetch helpers
* Can be used as a regular [server-side caller](https://trpc.io/docs/server/server-side-calls)
* or using prefetch helpers to put the promise into the QueryClient cache
* @example
* ```ts
* const data = await trpc.post.get("postId");
*
* // or
* void trpc.post.get.prefetch("postId");
* ```
*/
trpc: wrappedProxy,
/**
* HoC to hydrate the query client for a client component
* to pick up the prefetched promise and skip an initial
* client-side fetch.
* @example
* ```tsx
* // MyRSC.tsx
* const MyRSC = ({ params }) => {
* void trpc.post.get.prefetch(params.postId);
*
* return (
* <HydrateClient>
* <MyCC postId={params.postId} />
* </HydrateClient>
* );
* };
*
* // MyCC.tsx
* "use client"
* const MyCC = ({ postId }) => {
* const { data: post } = trpc.post.get.useQuery(postId);
* return <div>{post.title}</div>;
* };
* ```
*/
HydrateClient,
};
}

1
node_modules/@trpc/react-query/src/server/index.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export { createServerSideHelpers } from './ssgProxy';

225
node_modules/@trpc/react-query/src/server/ssgProxy.ts generated vendored Normal file
View File

@@ -0,0 +1,225 @@
import type {
DehydratedState,
DehydrateOptions,
QueryClient,
} from '@tanstack/react-query';
import { dehydrate } from '@tanstack/react-query';
import type { TRPCClient } from '@trpc/client';
import { getUntypedClient, TRPCUntypedClient } from '@trpc/client';
import type { CoercedTransformerParameters } from '@trpc/client/unstable-internals';
import {
getTransformer,
type TransformerOptions,
} from '@trpc/client/unstable-internals';
import type {
AnyQueryProcedure,
AnyRootTypes,
AnyRouter,
inferClientTypes,
inferRouterContext,
Maybe,
ProtectedIntersection,
RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import {
callProcedure,
createFlatProxy,
createRecursiveProxy,
run,
} from '@trpc/server/unstable-core-do-not-import';
import { getQueryKeyInternal } from '../internals/getQueryKey';
import type {
CreateTRPCReactQueryClientConfig,
DecorateQueryProcedure,
TRPCFetchInfiniteQueryOptions,
TRPCFetchQueryOptions,
} from '../shared';
import { getQueryClient, getQueryType } from '../shared';
type CreateSSGHelpersInternal<TRouter extends AnyRouter> = {
router: TRouter;
ctx: inferRouterContext<TRouter>;
} & TransformerOptions<inferClientTypes<TRouter>>;
interface CreateSSGHelpersExternal<TRouter extends AnyRouter> {
client: TRPCClient<TRouter> | TRPCUntypedClient<TRouter>;
}
type CreateServerSideHelpersOptions<TRouter extends AnyRouter> =
CreateTRPCReactQueryClientConfig &
(CreateSSGHelpersExternal<TRouter> | CreateSSGHelpersInternal<TRouter>);
type SSGFns =
| 'queryOptions'
| 'infiniteQueryOptions'
| 'fetch'
| 'fetchInfinite'
| 'prefetch'
| 'prefetchInfinite';
/**
* @internal
*/
type DecoratedProcedureSSGRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? Pick<DecorateQueryProcedure<TRoot, $Value>, SSGFns>
: $Value extends RouterRecord
? DecoratedProcedureSSGRecord<TRoot, $Value>
: never
: never;
};
type AnyDecoratedProcedure = Pick<DecorateQueryProcedure<any, any>, SSGFns>;
/**
* Create functions you can use for server-side rendering / static generation
* @see https://trpc.io/docs/v11/client/nextjs/server-side-helpers
*/
export function createServerSideHelpers<TRouter extends AnyRouter>(
opts: CreateServerSideHelpersOptions<TRouter>,
) {
const queryClient = getQueryClient(opts);
const transformer = getTransformer(
(opts as CoercedTransformerParameters).transformer,
);
const resolvedOpts: {
serialize: (obj: unknown) => any;
query: (queryOpts: { path: string; input: unknown }) => Promise<unknown>;
} = (() => {
if ('router' in opts) {
const { ctx, router } = opts;
return {
serialize: (obj) => transformer.output.serialize(obj),
query: (queryOpts) => {
return callProcedure({
router,
path: queryOpts.path,
getRawInput: async () => queryOpts.input,
ctx,
type: 'query',
signal: undefined,
batchIndex: 0,
});
},
};
}
const { client } = opts;
const untypedClient =
client instanceof TRPCUntypedClient ? client : getUntypedClient(client);
return {
query: (queryOpts) =>
untypedClient.query(queryOpts.path, queryOpts.input),
serialize: (obj) => transformer.output.serialize(obj),
};
})();
function _dehydrate(
opts: DehydrateOptions = {
shouldDehydrateQuery(query) {
if (query.state.status === 'pending') {
return false;
}
// makes sure to serialize errors
return true;
},
},
): DehydratedState {
const before = run(() => {
const dehydrated = dehydrate(queryClient, opts);
return {
...dehydrated,
queries: dehydrated.queries.map((query) => {
if (query.promise) {
const { promise: _, ...rest } = query;
return rest;
}
return query;
}),
};
});
const after = resolvedOpts.serialize(before);
return after;
}
type CreateSSGHelpers = ProtectedIntersection<
{
queryClient: QueryClient;
dehydrate: (opts?: DehydrateOptions) => DehydratedState;
},
DecoratedProcedureSSGRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>
>;
const proxy = createRecursiveProxy<CreateSSGHelpers>((opts) => {
const args = opts.args;
const input = args[0];
const arrayPath = [...opts.path];
const utilName = arrayPath.pop() as keyof AnyDecoratedProcedure;
const queryFn = () =>
resolvedOpts.query({ path: arrayPath.join('.'), input });
const queryKey = getQueryKeyInternal(
arrayPath,
input,
getQueryType(utilName),
);
const helperMap: Record<keyof AnyDecoratedProcedure, () => unknown> = {
queryOptions: () => {
const args1 = args[1] as Maybe<any>;
return { ...args1, queryKey, queryFn };
},
infiniteQueryOptions: () => {
const args1 = args[1] as Maybe<any>;
return { ...args1, queryKey, queryFn };
},
fetch: () => {
const args1 = args[1] as Maybe<TRPCFetchQueryOptions<any, any>>;
return queryClient.fetchQuery({ ...args1, queryKey, queryFn });
},
fetchInfinite: () => {
const args1 = args[1] as Maybe<
TRPCFetchInfiniteQueryOptions<any, any, any>
>;
return queryClient.fetchInfiniteQuery({
...args1,
queryKey,
queryFn,
initialPageParam: args1?.initialCursor ?? null,
});
},
prefetch: () => {
const args1 = args[1] as Maybe<TRPCFetchQueryOptions<any, any>>;
return queryClient.prefetchQuery({ ...args1, queryKey, queryFn });
},
prefetchInfinite: () => {
const args1 = args[1] as Maybe<
TRPCFetchInfiniteQueryOptions<any, any, any>
>;
return queryClient.prefetchInfiniteQuery({
...args1,
queryKey,
queryFn,
initialPageParam: args1?.initialCursor ?? null,
});
},
};
return helperMap[utilName]();
});
return createFlatProxy<CreateSSGHelpers>((key) => {
if (key === 'queryClient') return queryClient;
if (key === 'dehydrate') return _dehydrate;
return proxy[key];
});
}

View File

@@ -0,0 +1,779 @@
// TODO: Look into fixing react-compiler support
/* eslint-disable react-hooks/react-compiler */
import {
useInfiniteQuery as __useInfiniteQuery,
useMutation as __useMutation,
usePrefetchInfiniteQuery as __usePrefetchInfiniteQuery,
useQueries as __useQueries,
useQuery as __useQuery,
useSuspenseInfiniteQuery as __useSuspenseInfiniteQuery,
useSuspenseQueries as __useSuspenseQueries,
useSuspenseQuery as __useSuspenseQuery,
usePrefetchQuery as _usePrefetchQuery,
hashKey,
skipToken,
} from '@tanstack/react-query';
import type { TRPCClientErrorLike } from '@trpc/client';
import {
createTRPCClient,
getUntypedClient,
TRPCUntypedClient,
} from '@trpc/client';
import type { Unsubscribable } from '@trpc/server/observable';
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import { isAsyncIterable } from '@trpc/server/unstable-core-do-not-import';
import * as React from 'react';
import type { SSRState, TRPCContextState } from '../../internals/context';
import { TRPCContext } from '../../internals/context';
import { getClientArgs } from '../../internals/getClientArgs';
import type { TRPCQueryKey } from '../../internals/getQueryKey';
import {
getMutationKeyInternal,
getQueryKeyInternal,
} from '../../internals/getQueryKey';
import {
buildQueryFromAsyncIterable,
useHookResult,
} from '../../internals/trpcResult';
import type {
TRPCUseQueries,
TRPCUseSuspenseQueries,
} from '../../internals/useQueries';
import { createUtilityFunctions } from '../../utils/createUtilityFunctions';
import { createUseQueries } from '../proxy/useQueriesProxy';
import type { CreateTRPCReactOptions, UseMutationOverride } from '../types';
import type {
TRPCProvider,
TRPCQueryOptions,
TRPCSubscriptionConnectingResult,
TRPCSubscriptionIdleResult,
TRPCSubscriptionResult,
UseTRPCInfiniteQueryOptions,
UseTRPCInfiniteQueryResult,
UseTRPCMutationOptions,
UseTRPCMutationResult,
UseTRPCPrefetchInfiniteQueryOptions,
UseTRPCPrefetchQueryOptions,
UseTRPCQueryOptions,
UseTRPCQueryResult,
UseTRPCSubscriptionOptions,
UseTRPCSuspenseInfiniteQueryOptions,
UseTRPCSuspenseInfiniteQueryResult,
UseTRPCSuspenseQueryOptions,
UseTRPCSuspenseQueryResult,
} from './types';
const trackResult = <T extends object>(
result: T,
onTrackResult: (key: keyof T) => void,
): T => {
const trackedResult = new Proxy(result, {
get(target, prop) {
onTrackResult(prop as keyof T);
return target[prop as keyof T];
},
});
return trackedResult;
};
/**
* @internal
*/
export function createRootHooks<
TRouter extends AnyRouter,
TSSRContext = unknown,
>(config?: CreateTRPCReactOptions<TRouter>) {
const mutationSuccessOverride: UseMutationOverride['onSuccess'] =
config?.overrides?.useMutation?.onSuccess ??
((options) => options.originalFn());
type TError = TRPCClientErrorLike<TRouter>;
type ProviderContext = TRPCContextState<TRouter, TSSRContext>;
const Context = (config?.context ??
TRPCContext) as React.Context<ProviderContext>;
const createClient = createTRPCClient<TRouter>;
const TRPCProvider: TRPCProvider<TRouter, TSSRContext> = (props) => {
const { abortOnUnmount = false, queryClient, ssrContext } = props;
const [ssrState, setSSRState] = React.useState<SSRState>(
props.ssrState ?? false,
);
const client: TRPCUntypedClient<TRouter> =
props.client instanceof TRPCUntypedClient
? props.client
: getUntypedClient(props.client);
const fns = React.useMemo(
() =>
createUtilityFunctions({
client,
queryClient,
}),
[client, queryClient],
);
const contextValue = React.useMemo<ProviderContext>(
() => ({
abortOnUnmount,
queryClient,
client,
ssrContext: ssrContext ?? null,
ssrState,
...fns,
}),
[abortOnUnmount, client, fns, queryClient, ssrContext, ssrState],
);
React.useEffect(() => {
// Only updating state to `mounted` if we are using SSR.
// This makes it so we don't have an unnecessary re-render when opting out of SSR.
setSSRState((state) => (state ? 'mounted' : false));
}, []);
return (
<Context.Provider value={contextValue}>{props.children}</Context.Provider>
);
};
function useContext() {
const context = React.useContext(Context);
if (!context) {
throw new Error(
'Unable to find tRPC Context. Did you forget to wrap your App inside `withTRPC` HoC?',
);
}
return context;
}
/**
* Hack to make sure errors return `status`='error` when doing SSR
* @see https://github.com/trpc/trpc/pull/1645
*/
function useSSRQueryOptionsIfNeeded<
TOptions extends { retryOnMount?: boolean } | undefined,
>(queryKey: TRPCQueryKey, opts: TOptions): TOptions {
const { queryClient, ssrState } = useContext();
return ssrState &&
ssrState !== 'mounted' &&
queryClient.getQueryCache().find({ queryKey })?.state.status === 'error'
? {
retryOnMount: false,
...opts,
}
: opts;
}
function useQuery(
path: readonly string[],
input: unknown,
opts?: UseTRPCQueryOptions<unknown, unknown, TError>,
): UseTRPCQueryResult<unknown, TError> {
const context = useContext();
const { abortOnUnmount, client, ssrState, queryClient, prefetchQuery } =
context;
const queryKey = getQueryKeyInternal(path, input, 'query');
const defaultOpts = queryClient.getQueryDefaults(queryKey);
const isInputSkipToken = input === skipToken;
if (
typeof window === 'undefined' &&
ssrState === 'prepass' &&
opts?.trpc?.ssr !== false &&
(opts?.enabled ?? defaultOpts?.enabled) !== false &&
!isInputSkipToken &&
!queryClient.getQueryCache().find({ queryKey })
) {
void prefetchQuery(queryKey, opts as any);
}
const ssrOpts = useSSRQueryOptionsIfNeeded(queryKey, {
...defaultOpts,
...opts,
});
const shouldAbortOnUnmount =
opts?.trpc?.abortOnUnmount ?? config?.abortOnUnmount ?? abortOnUnmount;
const hook = __useQuery(
{
...ssrOpts,
queryKey: queryKey as any,
queryFn: isInputSkipToken
? input
: async (queryFunctionContext) => {
const actualOpts = {
...ssrOpts,
trpc: {
...ssrOpts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: { signal: null }),
},
};
const result = await client.query(
...getClientArgs(queryKey, actualOpts),
);
if (isAsyncIterable(result)) {
return buildQueryFromAsyncIterable(
result,
queryClient,
queryKey,
);
}
return result;
},
},
queryClient,
) as UseTRPCQueryResult<unknown, TError>;
hook.trpc = useHookResult({
path,
});
return hook;
}
function usePrefetchQuery(
path: string[],
input: unknown,
opts?: UseTRPCPrefetchQueryOptions<unknown, unknown, TError>,
): void {
const context = useContext();
const queryKey = getQueryKeyInternal(path, input, 'query');
const isInputSkipToken = input === skipToken;
const shouldAbortOnUnmount =
opts?.trpc?.abortOnUnmount ??
config?.abortOnUnmount ??
context.abortOnUnmount;
_usePrefetchQuery({
...opts,
queryKey: queryKey as any,
queryFn: isInputSkipToken
? input
: (queryFunctionContext) => {
const actualOpts = {
trpc: {
...opts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: {}),
},
};
return context.client.query(...getClientArgs(queryKey, actualOpts));
},
});
}
function useSuspenseQuery(
path: readonly string[],
input: unknown,
opts?: UseTRPCSuspenseQueryOptions<unknown, unknown, TError>,
): UseTRPCSuspenseQueryResult<unknown, TError> {
const context = useContext();
const queryKey = getQueryKeyInternal(path, input, 'query');
const shouldAbortOnUnmount =
opts?.trpc?.abortOnUnmount ??
config?.abortOnUnmount ??
context.abortOnUnmount;
const hook = __useSuspenseQuery(
{
...opts,
queryKey: queryKey as any,
queryFn: (queryFunctionContext) => {
const actualOpts = {
...opts,
trpc: {
...opts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: { signal: null }),
},
};
return context.client.query(...getClientArgs(queryKey, actualOpts));
},
},
context.queryClient,
) as UseTRPCQueryResult<unknown, TError>;
hook.trpc = useHookResult({
path,
});
return [hook.data, hook as any];
}
function useMutation(
path: readonly string[],
opts?: UseTRPCMutationOptions<unknown, TError, unknown, unknown>,
): UseTRPCMutationResult<unknown, TError, unknown, unknown> {
const { client, queryClient } = useContext();
const mutationKey = getMutationKeyInternal(path);
const defaultOpts = queryClient.defaultMutationOptions(
queryClient.getMutationDefaults(mutationKey),
);
const hook = __useMutation(
{
...opts,
mutationKey: mutationKey,
mutationFn: (input) => {
return client.mutation(...getClientArgs([path, { input }], opts));
},
onSuccess(...args) {
const originalFn = () =>
opts?.onSuccess?.(...args) ?? defaultOpts?.onSuccess?.(...args);
return mutationSuccessOverride({
originalFn,
queryClient,
meta: opts?.meta ?? defaultOpts?.meta ?? {},
});
},
},
queryClient,
) as UseTRPCMutationResult<unknown, TError, unknown, unknown>;
hook.trpc = useHookResult({
path,
});
return hook;
}
const initialStateIdle: Omit<TRPCSubscriptionIdleResult<unknown>, 'reset'> = {
data: undefined,
error: null,
status: 'idle',
};
const initialStateConnecting: Omit<
TRPCSubscriptionConnectingResult<unknown, TError>,
'reset'
> = {
data: undefined,
error: null,
status: 'connecting',
};
/* istanbul ignore next -- @preserve */
function useSubscription(
path: readonly string[],
input: unknown,
opts: UseTRPCSubscriptionOptions<unknown, TError>,
) {
const enabled = opts?.enabled ?? input !== skipToken;
const queryKey = hashKey(getQueryKeyInternal(path, input, 'any'));
const { client } = useContext();
const optsRef = React.useRef<typeof opts>(opts);
React.useEffect(() => {
optsRef.current = opts;
});
type $Result = TRPCSubscriptionResult<unknown, TError>;
const [trackedProps] = React.useState(new Set<keyof $Result>([]));
const addTrackedProp = React.useCallback(
(key: keyof $Result) => {
trackedProps.add(key);
},
[trackedProps],
);
const currentSubscriptionRef = React.useRef<Unsubscribable>(null);
const updateState = React.useCallback(
(callback: (prevState: $Result) => $Result) => {
const prev = resultRef.current;
const next = (resultRef.current = callback(prev));
let shouldUpdate = false;
for (const key of trackedProps) {
if (prev[key] !== next[key]) {
shouldUpdate = true;
break;
}
}
if (shouldUpdate) {
setState(trackResult(next, addTrackedProp));
}
},
[addTrackedProp, trackedProps],
);
const reset = React.useCallback((): void => {
// unsubscribe from the previous subscription
currentSubscriptionRef.current?.unsubscribe();
if (!enabled) {
updateState(() => ({ ...initialStateIdle, reset }));
return;
}
updateState(() => ({ ...initialStateConnecting, reset }));
const subscription = client.subscription(
path.join('.'),
input ?? undefined,
{
onStarted: () => {
optsRef.current.onStarted?.();
updateState((prev) => ({
...prev,
status: 'pending',
error: null,
}));
},
onData: (data) => {
optsRef.current.onData?.(data);
updateState((prev) => ({
...prev,
status: 'pending',
data,
error: null,
}));
},
onError: (error) => {
optsRef.current.onError?.(error);
updateState((prev) => ({
...prev,
status: 'error',
error,
}));
},
onConnectionStateChange: (result) => {
updateState((prev) => {
switch (result.state) {
case 'idle':
return {
...prev,
status: result.state,
error: null,
data: undefined,
};
case 'connecting':
return {
...prev,
error: result.error,
status: result.state,
};
case 'pending':
// handled when data is / onStarted
return prev;
}
});
},
onComplete: () => {
optsRef.current.onComplete?.();
// In the case of WebSockets, the connection might not be idle so `onConnectionStateChange` will not be called until the connection is closed.
// In this case, we need to set the state to idle manually.
updateState((prev) => ({
...prev,
status: 'idle',
error: null,
data: undefined,
}));
// (We might want to add a `connectionState` to the state to track the connection state separately)
},
},
);
currentSubscriptionRef.current = subscription;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [client, queryKey, enabled, updateState]);
React.useEffect(() => {
reset();
return () => {
currentSubscriptionRef.current?.unsubscribe();
};
}, [reset]);
const resultRef = React.useRef<$Result>(
enabled
? { ...initialStateConnecting, reset }
: { ...initialStateIdle, reset },
);
const [state, setState] = React.useState<$Result>(
trackResult(resultRef.current, addTrackedProp),
);
return state;
}
function useInfiniteQuery(
path: readonly string[],
input: unknown,
opts: UseTRPCInfiniteQueryOptions<unknown, unknown, TError>,
): UseTRPCInfiniteQueryResult<unknown, TError, unknown> {
const {
client,
ssrState,
prefetchInfiniteQuery,
queryClient,
abortOnUnmount,
} = useContext();
const queryKey = getQueryKeyInternal(path, input, 'infinite');
const defaultOpts = queryClient.getQueryDefaults(queryKey);
const isInputSkipToken = input === skipToken;
if (
typeof window === 'undefined' &&
ssrState === 'prepass' &&
opts?.trpc?.ssr !== false &&
(opts?.enabled ?? defaultOpts?.enabled) !== false &&
!isInputSkipToken &&
!queryClient.getQueryCache().find({ queryKey })
) {
void prefetchInfiniteQuery(queryKey, { ...defaultOpts, ...opts } as any);
}
const ssrOpts = useSSRQueryOptionsIfNeeded(queryKey, {
...defaultOpts,
...opts,
});
// request option should take priority over global
const shouldAbortOnUnmount = opts?.trpc?.abortOnUnmount ?? abortOnUnmount;
const hook = __useInfiniteQuery(
{
...ssrOpts,
initialPageParam: opts.initialCursor ?? null,
persister: opts.persister,
queryKey: queryKey as any,
queryFn: isInputSkipToken
? input
: (queryFunctionContext) => {
const actualOpts = {
...ssrOpts,
trpc: {
...ssrOpts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: { signal: null }),
},
};
return client.query(
...getClientArgs(queryKey, actualOpts, {
pageParam:
queryFunctionContext.pageParam ?? opts.initialCursor,
direction: queryFunctionContext.direction,
}),
);
},
},
queryClient,
) as UseTRPCInfiniteQueryResult<unknown, TError, unknown>;
hook.trpc = useHookResult({
path,
});
return hook;
}
function usePrefetchInfiniteQuery(
path: string[],
input: unknown,
opts: UseTRPCPrefetchInfiniteQueryOptions<unknown, unknown, TError>,
): void {
const context = useContext();
const queryKey = getQueryKeyInternal(path, input, 'infinite');
const defaultOpts = context.queryClient.getQueryDefaults(queryKey);
const isInputSkipToken = input === skipToken;
const ssrOpts = useSSRQueryOptionsIfNeeded(queryKey, {
...defaultOpts,
...opts,
});
// request option should take priority over global
const shouldAbortOnUnmount =
opts?.trpc?.abortOnUnmount ?? context.abortOnUnmount;
__usePrefetchInfiniteQuery({
...opts,
initialPageParam: opts.initialCursor ?? null,
queryKey,
queryFn: isInputSkipToken
? input
: (queryFunctionContext) => {
const actualOpts = {
...ssrOpts,
trpc: {
...ssrOpts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: {}),
},
};
return context.client.query(
...getClientArgs(queryKey, actualOpts, {
pageParam: queryFunctionContext.pageParam ?? opts.initialCursor,
direction: queryFunctionContext.direction,
}),
);
},
});
}
function useSuspenseInfiniteQuery(
path: readonly string[],
input: unknown,
opts: UseTRPCSuspenseInfiniteQueryOptions<unknown, unknown, TError>,
): UseTRPCSuspenseInfiniteQueryResult<unknown, TError, unknown> {
const context = useContext();
const queryKey = getQueryKeyInternal(path, input, 'infinite');
const defaultOpts = context.queryClient.getQueryDefaults(queryKey);
const ssrOpts = useSSRQueryOptionsIfNeeded(queryKey, {
...defaultOpts,
...opts,
});
// request option should take priority over global
const shouldAbortOnUnmount =
opts?.trpc?.abortOnUnmount ?? context.abortOnUnmount;
const hook = __useSuspenseInfiniteQuery(
{
...opts,
initialPageParam: opts.initialCursor ?? null,
queryKey,
queryFn: (queryFunctionContext) => {
const actualOpts = {
...ssrOpts,
trpc: {
...ssrOpts?.trpc,
...(shouldAbortOnUnmount
? { signal: queryFunctionContext.signal }
: {}),
},
};
return context.client.query(
...getClientArgs(queryKey, actualOpts, {
pageParam: queryFunctionContext.pageParam ?? opts.initialCursor,
direction: queryFunctionContext.direction,
}),
);
},
},
context.queryClient,
) as UseTRPCInfiniteQueryResult<unknown, TError, unknown>;
hook.trpc = useHookResult({
path,
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return [hook.data!, hook as any];
}
const useQueries: TRPCUseQueries<TRouter> = (queriesCallback, options) => {
const { ssrState, queryClient, prefetchQuery, client } = useContext();
const proxy = createUseQueries(client);
const queries = queriesCallback(proxy);
if (typeof window === 'undefined' && ssrState === 'prepass') {
for (const query of queries) {
const queryOption = query as TRPCQueryOptions<any, any>;
if (
queryOption.trpc?.ssr !== false &&
!queryClient.getQueryCache().find({ queryKey: queryOption.queryKey })
) {
void prefetchQuery(queryOption.queryKey, queryOption as any);
}
}
}
return __useQueries(
{
queries: queries.map((query) => ({
...query,
queryKey: (query as TRPCQueryOptions<any, any>).queryKey,
})),
combine: options?.combine as any,
},
queryClient,
);
};
const useSuspenseQueries: TRPCUseSuspenseQueries<TRouter> = (
queriesCallback,
) => {
const { queryClient, client } = useContext();
const proxy = createUseQueries(client);
const queries = queriesCallback(proxy);
const hook = __useSuspenseQueries(
{
queries: queries.map((query) => ({
...query,
queryFn: query.queryFn,
queryKey: (query as TRPCQueryOptions<any, any>).queryKey,
})),
},
queryClient,
);
return [hook.map((h) => h.data), hook] as any;
};
return {
Provider: TRPCProvider,
createClient,
useContext,
useUtils: useContext,
useQuery,
usePrefetchQuery,
useSuspenseQuery,
useQueries,
useSuspenseQueries,
useMutation,
useSubscription,
useInfiniteQuery,
usePrefetchInfiniteQuery,
useSuspenseInfiniteQuery,
};
}
/**
* Infer the type of a `createReactQueryHooks` function
* @internal
*/
export type CreateReactQueryHooks<
TRouter extends AnyRouter,
TSSRContext = unknown,
> = ReturnType<typeof createRootHooks<TRouter, TSSRContext>>;

View File

@@ -0,0 +1,4 @@
// NOTE: This indirection is only needed to break a circular-reference.
// After removal of `hooks/deprecated/createHooksInternal` file,
// `hooks/createHooksInternal` can be swapped for all `createRootHooks` imports.
export { createRootHooks } from './createHooksInternal';

View File

@@ -0,0 +1,315 @@
import type {
DefinedUseQueryResult,
FetchInfiniteQueryOptions,
FetchQueryOptions,
InfiniteData,
InfiniteQueryObserverSuccessResult,
InitialDataFunction,
QueryObserverSuccessResult,
QueryOptions,
UseBaseQueryOptions,
UseInfiniteQueryOptions,
UseInfiniteQueryResult,
UseMutationOptions,
UseMutationResult,
UseQueryResult,
UseSuspenseInfiniteQueryOptions,
UseSuspenseInfiniteQueryResult,
UseSuspenseQueryOptions,
UseSuspenseQueryResult,
} from '@tanstack/react-query';
import type {
CreateTRPCClientOptions,
TRPCClient,
TRPCRequestOptions,
TRPCUntypedClient,
} from '@trpc/client';
import type {
AnyRouter,
coerceAsyncIterableToArray,
DistributiveOmit,
} from '@trpc/server/unstable-core-do-not-import';
import type { JSX, ReactNode } from 'react';
import type { TRPCContextProps } from '../../internals/context';
import type { TRPCQueryKey } from '../../internals/getQueryKey';
export type OutputWithCursor<TData, TCursor = any> = {
cursor: TCursor | null;
data: TData;
};
export interface TRPCReactRequestOptions
// For RQ, we use their internal AbortSignals instead of letting the user pass their own
extends Omit<TRPCRequestOptions, 'signal'> {
/**
* Opt out of SSR for this query by passing `ssr: false`
*/
ssr?: boolean;
/**
* Opt out or into aborting request on unmount
*/
abortOnUnmount?: boolean;
}
export interface TRPCUseQueryBaseOptions {
/**
* tRPC-related options
*/
trpc?: TRPCReactRequestOptions;
}
export interface UseTRPCQueryOptions<
TOutput,
TData,
TError,
TQueryOptsData = TOutput,
> extends DistributiveOmit<
UseBaseQueryOptions<TOutput, TError, TData, TQueryOptsData, any>,
'queryKey'
>,
TRPCUseQueryBaseOptions {}
export interface UseTRPCSuspenseQueryOptions<TOutput, TData, TError>
extends DistributiveOmit<
UseSuspenseQueryOptions<TOutput, TError, TData, any>,
'queryKey'
>,
TRPCUseQueryBaseOptions {}
export interface UseTRPCPrefetchQueryOptions<TOutput, TData, TError>
extends DistributiveOmit<
FetchQueryOptions<TOutput, TError, TData, any>,
'queryKey'
>,
TRPCUseQueryBaseOptions {}
/** @internal **/
export interface DefinedUseTRPCQueryOptions<
TOutput,
TData,
TError,
TQueryOptsData = TOutput,
> extends DistributiveOmit<
UseTRPCQueryOptions<TOutput, TData, TError, TQueryOptsData>,
'queryKey'
> {
initialData: InitialDataFunction<TQueryOptsData> | TQueryOptsData;
}
export interface TRPCQueryOptions<TData, TError>
extends DistributiveOmit<QueryOptions<TData, TError, TData, any>, 'queryKey'>,
TRPCUseQueryBaseOptions {
queryKey: TRPCQueryKey;
}
export type ExtractCursorType<TInput> = TInput extends { cursor?: any }
? TInput['cursor']
: unknown;
export interface UseTRPCInfiniteQueryOptions<TInput, TOutput, TError>
extends DistributiveOmit<
UseInfiniteQueryOptions<
TOutput,
TError,
TOutput,
any,
ExtractCursorType<TInput>
>,
'queryKey' | 'initialPageParam'
>,
TRPCUseQueryBaseOptions {
initialCursor?: ExtractCursorType<TInput>;
}
export type UseTRPCPrefetchInfiniteQueryOptions<TInput, TOutput, TError> =
DistributiveOmit<
FetchInfiniteQueryOptions<
TOutput,
TError,
TOutput,
any,
ExtractCursorType<TInput>
>,
'queryKey' | 'initialPageParam'
> &
TRPCUseQueryBaseOptions & {
initialCursor?: ExtractCursorType<TInput>;
};
export interface UseTRPCSuspenseInfiniteQueryOptions<TInput, TOutput, TError>
extends DistributiveOmit<
UseSuspenseInfiniteQueryOptions<
TOutput,
TError,
TOutput,
any,
ExtractCursorType<TInput>
>,
'queryKey' | 'initialPageParam'
>,
TRPCUseQueryBaseOptions {
initialCursor?: ExtractCursorType<TInput>;
}
export interface UseTRPCMutationOptions<
TInput,
TError,
TOutput,
TContext = unknown,
> extends UseMutationOptions<TOutput, TError, TInput, TContext>,
TRPCUseQueryBaseOptions {}
export interface UseTRPCSubscriptionOptions<TOutput, TError> {
/**
* @deprecated
* use a `skipToken` from `@tanstack/react-query` instead
* this will be removed in v12
*/
enabled?: boolean;
/**
* Called when the subscription is started
*/
onStarted?: () => void;
/**
* Called when new data is received
*/
onData?: (data: TOutput) => void;
/**
* Called when an **unrecoverable error** occurs and the subscription is closed
*/
onError?: (err: TError) => void;
/**
* Called when the subscription is completed on the server
*/
onComplete?: () => void;
}
export interface TRPCSubscriptionBaseResult<TOutput, TError> {
status: 'idle' | 'connecting' | 'pending' | 'error';
data: undefined | TOutput;
error: null | TError;
/**
* Reset the subscription
*/
reset: () => void;
}
export interface TRPCSubscriptionIdleResult<TOutput>
extends TRPCSubscriptionBaseResult<TOutput, null> {
status: 'idle';
data: undefined;
error: null;
}
export interface TRPCSubscriptionConnectingResult<TOutput, TError>
extends TRPCSubscriptionBaseResult<TOutput, TError> {
status: 'connecting';
data: undefined | TOutput;
error: TError | null;
}
export interface TRPCSubscriptionPendingResult<TOutput>
extends TRPCSubscriptionBaseResult<TOutput, undefined> {
status: 'pending';
data: TOutput | undefined;
error: null;
}
export interface TRPCSubscriptionErrorResult<TOutput, TError>
extends TRPCSubscriptionBaseResult<TOutput, TError> {
status: 'error';
data: TOutput | undefined;
error: TError;
}
export type TRPCSubscriptionResult<TOutput, TError> =
| TRPCSubscriptionIdleResult<TOutput>
| TRPCSubscriptionConnectingResult<TOutput, TError>
| TRPCSubscriptionErrorResult<TOutput, TError>
| TRPCSubscriptionPendingResult<TOutput>;
export interface TRPCProviderProps<TRouter extends AnyRouter, TSSRContext>
extends Omit<TRPCContextProps<TRouter, TSSRContext>, 'client'> {
children: ReactNode;
client: TRPCClient<TRouter> | TRPCUntypedClient<TRouter>;
}
export type TRPCProvider<TRouter extends AnyRouter, TSSRContext> = (
props: TRPCProviderProps<TRouter, TSSRContext>,
) => JSX.Element;
export type CreateClient<TRouter extends AnyRouter> = (
opts: CreateTRPCClientOptions<TRouter>,
) => TRPCUntypedClient<TRouter>;
/**
* @internal
*/
export type UseTRPCQueryResult<TData, TError> = TRPCHookResult &
UseQueryResult<coerceAsyncIterableToArray<TData>, TError>;
/**
* @internal
*/
export type DefinedUseTRPCQueryResult<TData, TError> = DefinedUseQueryResult<
TData,
TError
> &
TRPCHookResult;
/**
* @internal
*/
export type UseTRPCQuerySuccessResult<TData, TError> =
QueryObserverSuccessResult<TData, TError> & TRPCHookResult;
/**
* @internal
*/
export type UseTRPCSuspenseQueryResult<TData, TError> = [
TData,
UseSuspenseQueryResult<TData, TError> & TRPCHookResult,
];
/**
* @internal
*/
export type UseTRPCInfiniteQueryResult<TData, TError, TInput> = TRPCHookResult &
UseInfiniteQueryResult<
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TError
>;
/**
* @internal
*/
export type UseTRPCInfiniteQuerySuccessResult<TData, TError, TInput> =
InfiniteQueryObserverSuccessResult<
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TError
> &
TRPCHookResult;
/**
* @internal
*/
export type UseTRPCSuspenseInfiniteQueryResult<TData, TError, TInput> = [
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
UseSuspenseInfiniteQueryResult<
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TError
> &
TRPCHookResult,
];
/**
* @internal
*/
export type UseTRPCMutationResult<TData, TError, TVariables, TContext> =
TRPCHookResult & UseMutationResult<TData, TError, TVariables, TContext>;
export interface TRPCHookResult {
trpc: {
path: string;
};
}

32
node_modules/@trpc/react-query/src/shared/index.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
export * from './proxy/decorationProxy';
export * from './proxy/utilsProxy';
export * from './proxy/useQueriesProxy';
export type {
DecorateRouterRecord,
DecorateProcedure,
} from '../createTRPCReact';
export type {
TRPCUseQueries,
TRPCUseSuspenseQueries,
} from '../internals/useQueries';
export * from './hooks/createRootHooks';
export * from './queryClient';
export * from './types';
export * from './hooks/types';
export * from './polymorphism';
export {
/**
* @deprecated this is an internal function
*/
getClientArgs,
} from '../internals/getClientArgs';
export {
/**
* @deprecated
*/
TRPCContext,
} from './../internals/context';
export * from '../internals/context';

View File

@@ -0,0 +1,4 @@
export * from './mutationLike';
export * from './queryLike';
export * from './routerLike';
export * from './utilsLike';

View File

@@ -0,0 +1,42 @@
import type {
AnyProcedure,
AnyRootTypes,
inferProcedureInput,
inferTransformedProcedureOutput,
} from '@trpc/server/unstable-core-do-not-import';
import type {
InferMutationOptions,
InferMutationResult,
} from '../../utils/inferReactQueryProcedure';
/**
* Use to describe a mutation route which matches a given mutation procedure's interface
*/
export type MutationLike<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
> = {
useMutation: (
opts?: InferMutationOptions<TRoot, TProcedure>,
) => InferMutationResult<TRoot, TProcedure>;
};
/**
* Use to unwrap a MutationLike's input
*/
export type InferMutationLikeInput<
TMutationLike extends MutationLike<any, any>,
> =
TMutationLike extends MutationLike<any, infer $Procedure>
? inferProcedureInput<$Procedure>
: never;
/**
* Use to unwrap a MutationLike's data output
*/
export type InferMutationLikeData<
TMutationLike extends MutationLike<any, any>,
> =
TMutationLike extends MutationLike<infer TRoot, infer TProcedure>
? inferTransformedProcedureOutput<TRoot, TProcedure>
: never;

View File

@@ -0,0 +1,55 @@
import type { TRPCClientErrorLike } from '@trpc/client';
import type {
AnyProcedure,
AnyRootTypes,
inferProcedureInput,
inferProcedureOutput,
inferTransformedProcedureOutput,
} from '@trpc/server/unstable-core-do-not-import';
import type { DecoratedQuery } from '../../createTRPCReact';
import type {
InferQueryOptions,
InferQueryResult,
} from '../../utils/inferReactQueryProcedure';
import type { UseTRPCSuspenseQueryResult } from '../hooks/types';
/**
* Use to request a query route which matches a given query procedure's interface
*/
export type QueryLike<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
> = {
useQuery: (
variables: inferProcedureInput<TProcedure>,
opts?: InferQueryOptions<TRoot, TProcedure, any>,
) => InferQueryResult<TRoot, TProcedure>;
useSuspenseQuery: (
variables: inferProcedureInput<TProcedure>,
opts?: InferQueryOptions<TRoot, TProcedure, any>,
) => UseTRPCSuspenseQueryResult<
inferProcedureOutput<TProcedure>,
TRPCClientErrorLike<TRoot>
>;
};
/**
* Use to unwrap a QueryLike's input
*/
export type InferQueryLikeInput<TQueryLike> =
TQueryLike extends DecoratedQuery<infer $Def>
? $Def['input']
: TQueryLike extends QueryLike<any, infer TProcedure>
? inferProcedureInput<TProcedure>
: never;
/**
* Use to unwrap a QueryLike's data output
*/
export type InferQueryLikeData<TQueryLike> =
TQueryLike extends DecoratedQuery<infer $Def>
? $Def['output']
: TQueryLike extends QueryLike<infer TRoot, infer TProcedure>
? inferTransformedProcedureOutput<TRoot, TProcedure>
: never;

View File

@@ -0,0 +1,43 @@
import type {
AnyMutationProcedure,
AnyQueryProcedure,
AnyRootTypes,
AnyRouter,
RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import type { MutationLike } from './mutationLike';
import type { QueryLike } from './queryLike';
/**
* Use to describe a route path which matches a given route's interface
*/
export type RouterLike<TRouter extends AnyRouter> = RouterLikeInner<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>;
export type RouterLikeInner<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? QueryLike<TRoot, $Value>
: $Value extends AnyMutationProcedure
? MutationLike<TRoot, $Value>
: $Value extends RouterRecord
? RouterLikeInner<TRoot, $Value>
: never
: never;
};
// /**
// * Use to describe a route path which matches a given route's interface
// */
// export type RouterLike<TRouter extends AnyRouter> = RouterLikeInner<
// TRouter['_def']['_config']['$types'],
// TRouter['_def']['procedures']
// >;
// export type RouterLikeInner<
// TRoot extends AnyRootTypes,
// TRecord extends RouterRecord,
// > = DecorateRouterRecord<TRoot, TRecord>;

View File

@@ -0,0 +1,11 @@
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import type { DecoratedProcedureUtilsRecord } from '../proxy/utilsProxy';
/**
* Use to describe a Utils/Context path which matches the given route's interface
*/
export type UtilsLike<TRouter extends AnyRouter> =
DecoratedProcedureUtilsRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>;

View File

@@ -0,0 +1,35 @@
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import { createRecursiveProxy } from '@trpc/server/unstable-core-do-not-import';
import type { CreateReactQueryHooks } from '../hooks/createHooksInternal';
/**
* Create proxy for decorating procedures
* @internal
*/
export function createReactDecoration<
TRouter extends AnyRouter,
TSSRContext = unknown,
>(hooks: CreateReactQueryHooks<TRouter, TSSRContext>) {
return createRecursiveProxy(({ path, args }) => {
const pathCopy = [...path];
// The last arg is for instance `.useMutation` or `.useQuery()`
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const lastArg = pathCopy.pop()!;
if (lastArg === 'useMutation') {
return (hooks as any)[lastArg](pathCopy, ...args);
}
if (lastArg === '_def') {
return {
path: pathCopy,
};
}
const [input, ...rest] = args;
const opts = rest[0] ?? {};
return (hooks as any)[lastArg](pathCopy, input, opts);
});
}

View File

@@ -0,0 +1,122 @@
import type { QueryOptions } from '@tanstack/react-query';
import type { TRPCClient } from '@trpc/client';
import {
getUntypedClient,
TRPCUntypedClient,
type TRPCClientError,
} from '@trpc/client';
import type {
AnyProcedure,
AnyQueryProcedure,
AnyRootTypes,
AnyRouter,
inferProcedureInput,
inferTransformedProcedureOutput,
RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import { createRecursiveProxy } from '@trpc/server/unstable-core-do-not-import';
import { getQueryKeyInternal } from '../../internals/getQueryKey';
import type {
TrpcQueryOptionsForUseQueries,
TrpcQueryOptionsForUseSuspenseQueries,
} from '../../internals/useQueries';
import type { TRPCUseQueryBaseOptions } from '../hooks/types';
type GetQueryOptions<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
> = <TData = inferTransformedProcedureOutput<TRoot, TProcedure>>(
input: inferProcedureInput<TProcedure>,
opts?: TrpcQueryOptionsForUseQueries<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TData,
TRPCClientError<TRoot>
>,
) => TrpcQueryOptionsForUseQueries<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TData,
TRPCClientError<TRoot>
>;
/**
* @internal
*/
export type UseQueriesProcedureRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? GetQueryOptions<TRoot, $Value>
: $Value extends RouterRecord
? UseQueriesProcedureRecord<TRoot, $Value>
: never
: never;
};
type GetSuspenseQueryOptions<
TRoot extends AnyRootTypes,
TProcedure extends AnyQueryProcedure,
> = <TData = inferTransformedProcedureOutput<TRoot, TProcedure>>(
input: inferProcedureInput<TProcedure>,
opts?: TrpcQueryOptionsForUseSuspenseQueries<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TData,
TRPCClientError<TRoot>
>,
) => TrpcQueryOptionsForUseSuspenseQueries<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TData,
TRPCClientError<TRoot>
>;
/**
* @internal
*/
export type UseSuspenseQueriesProcedureRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? GetSuspenseQueryOptions<TRoot, $Value>
: $Value extends RouterRecord
? UseSuspenseQueriesProcedureRecord<TRoot, $Value>
: never
: never;
};
/**
* Create proxy for `useQueries` options
* @internal
*/
export function createUseQueries<TRouter extends AnyRouter>(
client: TRPCUntypedClient<TRouter> | TRPCClient<TRouter>,
) {
const untypedClient: TRPCUntypedClient<TRouter> =
client instanceof TRPCUntypedClient ? client : getUntypedClient(client);
return createRecursiveProxy<
UseQueriesProcedureRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>
>((opts) => {
const arrayPath = opts.path;
const dotPath = arrayPath.join('.');
const [input, _opts] = opts.args as [
unknown,
Partial<QueryOptions> & TRPCUseQueryBaseOptions,
];
const options: QueryOptions = {
queryKey: getQueryKeyInternal(arrayPath, input, 'query'),
queryFn: () => {
return untypedClient.query(dotPath, input, _opts?.trpc);
},
..._opts,
};
return options;
});
}

View File

@@ -0,0 +1,553 @@
import type {
CancelOptions,
InfiniteData,
InvalidateOptions,
InvalidateQueryFilters,
Query,
QueryFilters,
QueryKey,
RefetchOptions,
RefetchQueryFilters,
ResetOptions,
SetDataOptions,
SkipToken,
Updater,
} from '@tanstack/react-query';
import type { TRPCClientError } from '@trpc/client';
import { createTRPCClientProxy } from '@trpc/client';
import type {
AnyMutationProcedure,
AnyQueryProcedure,
AnyRootTypes,
AnyRouter,
DeepPartial,
inferProcedureInput,
inferProcedureOutput,
inferTransformedProcedureOutput,
ProtectedIntersection,
RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import {
createFlatProxy,
createRecursiveProxy,
} from '@trpc/server/unstable-core-do-not-import';
import type {
DecoratedTRPCContextProps,
TRPCContextState,
TRPCFetchInfiniteQueryOptions,
TRPCFetchQueryOptions,
TRPCQueryUtils,
} from '../../internals/context';
import { contextProps } from '../../internals/context';
import type { QueryKeyKnown, QueryType } from '../../internals/getQueryKey';
import {
getMutationKeyInternal,
getQueryKeyInternal,
} from '../../internals/getQueryKey';
import type { InferMutationOptions } from '../../utils/inferReactQueryProcedure';
import type { ExtractCursorType } from '../hooks/types';
import type {
DefinedTRPCInfiniteQueryOptionsIn,
DefinedTRPCInfiniteQueryOptionsOut,
DefinedTRPCQueryOptionsIn,
DefinedTRPCQueryOptionsOut,
UndefinedTRPCInfiniteQueryOptionsIn,
UndefinedTRPCInfiniteQueryOptionsOut,
UndefinedTRPCQueryOptionsIn,
UndefinedTRPCQueryOptionsOut,
UnusedSkipTokenTRPCInfiniteQueryOptionsIn,
UnusedSkipTokenTRPCInfiniteQueryOptionsOut,
UnusedSkipTokenTRPCQueryOptionsIn,
UnusedSkipTokenTRPCQueryOptionsOut,
} from '../types';
export type DecorateQueryProcedure<
TRoot extends AnyRootTypes,
TProcedure extends AnyQueryProcedure,
> = {
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/queryOptions#queryoptions
*/
queryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure> | SkipToken,
opts: DefinedTRPCQueryOptionsIn<
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): DefinedTRPCQueryOptionsOut<TQueryFnData, TData, TRPCClientError<TRoot>>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/queryOptions#queryoptions
*/
queryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure> | SkipToken,
opts?: UnusedSkipTokenTRPCQueryOptionsIn<
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): UnusedSkipTokenTRPCQueryOptionsOut<
TQueryFnData,
TData,
TRPCClientError<TRoot>
>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/queryOptions#queryoptions
*/
queryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure> | SkipToken,
opts?: UndefinedTRPCQueryOptionsIn<
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): UndefinedTRPCQueryOptionsOut<TQueryFnData, TData, TRPCClientError<TRoot>>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/infiniteQueryOptions#infinitequeryoptions
*/
infiniteQueryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure> | SkipToken,
opts: DefinedTRPCInfiniteQueryOptionsIn<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): DefinedTRPCInfiniteQueryOptionsOut<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/infiniteQueryOptions#infinitequeryoptions
*/
infiniteQueryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure>,
opts: UnusedSkipTokenTRPCInfiniteQueryOptionsIn<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): UnusedSkipTokenTRPCInfiniteQueryOptionsOut<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>;
/**
* @see https://tanstack.com/query/latest/docs/framework/react/reference/infiniteQueryOptions#infinitequeryoptions
*/
infiniteQueryOptions<
TQueryFnData extends inferTransformedProcedureOutput<TRoot, TProcedure>,
TData = TQueryFnData,
>(
input: inferProcedureInput<TProcedure> | SkipToken,
opts?: UndefinedTRPCInfiniteQueryOptionsIn<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>,
): UndefinedTRPCInfiniteQueryOptionsOut<
inferProcedureInput<TProcedure>,
TQueryFnData,
TData,
TRPCClientError<TRoot>
>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchquery
*/
fetch(
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchQueryOptions<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
): Promise<inferTransformedProcedureOutput<TRoot, TProcedure>>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchinfinitequery
*/
fetchInfinite(
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchInfiniteQueryOptions<
inferProcedureInput<TProcedure>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
): Promise<
InfiniteData<
inferTransformedProcedureOutput<TRoot, TProcedure>,
NonNullable<ExtractCursorType<inferProcedureInput<TProcedure>>> | null
>
>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientprefetchquery
*/
prefetch(
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchQueryOptions<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientprefetchinfinitequery
*/
prefetchInfinite(
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchInfiniteQueryOptions<
inferProcedureInput<TProcedure>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientensurequerydata
*/
ensureData(
input: inferProcedureInput<TProcedure>,
opts?: TRPCFetchQueryOptions<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientError<TRoot>
>,
): Promise<inferTransformedProcedureOutput<TRoot, TProcedure>>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientinvalidatequeries
*/
invalidate(
input?: DeepPartial<inferProcedureInput<TProcedure>>,
filters?: Omit<InvalidateQueryFilters, 'predicate'> & {
predicate?: (
query: Query<
inferProcedureOutput<TProcedure>,
TRPCClientError<TRoot>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
QueryKeyKnown<
inferProcedureInput<TProcedure>,
inferProcedureInput<TProcedure> extends { cursor?: any } | void
? 'infinite'
: 'query'
>
>,
) => boolean;
},
options?: InvalidateOptions,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientrefetchqueries
*/
refetch(
input?: inferProcedureInput<TProcedure>,
filters?: RefetchQueryFilters,
options?: RefetchOptions,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientcancelqueries
*/
cancel(
input?: inferProcedureInput<TProcedure>,
options?: CancelOptions,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientresetqueries
*/
reset(
input?: inferProcedureInput<TProcedure>,
options?: ResetOptions,
): Promise<void>;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata
*/
setData(
/**
* The input of the procedure
*/
input: inferProcedureInput<TProcedure>,
updater: Updater<
inferTransformedProcedureOutput<TRoot, TProcedure> | undefined,
inferTransformedProcedureOutput<TRoot, TProcedure> | undefined
>,
options?: SetDataOptions,
): void;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata
*/
setQueriesData(
/**
* The input of the procedure
*/
input: inferProcedureInput<TProcedure>,
filters: QueryFilters,
updater: Updater<
inferTransformedProcedureOutput<TRoot, TProcedure> | undefined,
inferTransformedProcedureOutput<TRoot, TProcedure> | undefined
>,
options?: SetDataOptions,
): [QueryKey, inferTransformedProcedureOutput<TRoot, TProcedure>];
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata
*/
setInfiniteData(
input: inferProcedureInput<TProcedure>,
updater: Updater<
| InfiniteData<
inferTransformedProcedureOutput<TRoot, TProcedure>,
NonNullable<ExtractCursorType<inferProcedureInput<TProcedure>>> | null
>
| undefined,
| InfiniteData<
inferTransformedProcedureOutput<TRoot, TProcedure>,
NonNullable<ExtractCursorType<inferProcedureInput<TProcedure>>> | null
>
| undefined
>,
options?: SetDataOptions,
): void;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata
*/
getData(
input?: inferProcedureInput<TProcedure>,
): inferTransformedProcedureOutput<TRoot, TProcedure> | undefined;
/**
* @see https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata
*/
getInfiniteData(
input?: inferProcedureInput<TProcedure>,
):
| InfiniteData<
inferTransformedProcedureOutput<TRoot, TProcedure>,
NonNullable<ExtractCursorType<inferProcedureInput<TProcedure>>> | null
>
| undefined;
};
type DecorateMutationProcedure<
TRoot extends AnyRootTypes,
TProcedure extends AnyMutationProcedure,
> = {
setMutationDefaults<TMeta = unknown>(
options:
| InferMutationOptions<TRoot, TProcedure, TMeta>
| ((args: {
canonicalMutationFn: NonNullable<
InferMutationOptions<TRoot, TProcedure>['mutationFn']
>;
}) => InferMutationOptions<TRoot, TProcedure, TMeta>),
): void;
getMutationDefaults(): InferMutationOptions<TRoot, TProcedure> | undefined;
isMutating(): number;
};
/**
* this is the type that is used to add in procedures that can be used on
* an entire router
*/
type DecorateRouter = {
/**
* Invalidate the full router
* @see https://trpc.io/docs/v10/useContext#query-invalidation
* @see https://tanstack.com/query/v5/docs/framework/react/guides/query-invalidation
*/
invalidate(
input?: undefined,
filters?: InvalidateQueryFilters,
options?: InvalidateOptions,
): Promise<void>;
};
/**
* @internal
*/
export type DecoratedProcedureUtilsRecord<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = DecorateRouter & {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? DecorateQueryProcedure<TRoot, $Value>
: $Value extends AnyMutationProcedure
? DecorateMutationProcedure<TRoot, $Value>
: $Value extends RouterRecord
? DecoratedProcedureUtilsRecord<TRoot, $Value> & DecorateRouter
: never
: never;
}; // Add functions that should be available at utils root
type AnyDecoratedProcedure = DecorateQueryProcedure<any, any> &
DecorateMutationProcedure<any, any>;
export type CreateReactUtils<
TRouter extends AnyRouter,
TSSRContext,
> = ProtectedIntersection<
DecoratedTRPCContextProps<TRouter, TSSRContext>,
DecoratedProcedureUtilsRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>
>;
export type CreateQueryUtils<TRouter extends AnyRouter> =
DecoratedProcedureUtilsRecord<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>;
export const getQueryType = (
utilName: keyof AnyDecoratedProcedure,
): QueryType => {
switch (utilName) {
case 'queryOptions':
case 'fetch':
case 'ensureData':
case 'prefetch':
case 'getData':
case 'setData':
case 'setQueriesData':
return 'query';
case 'infiniteQueryOptions':
case 'fetchInfinite':
case 'prefetchInfinite':
case 'getInfiniteData':
case 'setInfiniteData':
return 'infinite';
case 'setMutationDefaults':
case 'getMutationDefaults':
case 'isMutating':
case 'cancel':
case 'invalidate':
case 'refetch':
case 'reset':
return 'any';
}
};
/**
* @internal
*/
function createRecursiveUtilsProxy<TRouter extends AnyRouter>(
context: TRPCQueryUtils<TRouter>,
) {
return createRecursiveProxy<CreateQueryUtils<TRouter>>((opts) => {
const path = [...opts.path];
const utilName = path.pop() as keyof AnyDecoratedProcedure;
const args = [...opts.args] as Parameters<
AnyDecoratedProcedure[typeof utilName]
>;
const input = args.shift(); // args can now be spread when input removed
const queryType = getQueryType(utilName);
const queryKey = getQueryKeyInternal(path, input, queryType);
const contextMap: Record<keyof AnyDecoratedProcedure, () => unknown> = {
infiniteQueryOptions: () =>
context.infiniteQueryOptions(path, queryKey, args[0]),
queryOptions: () => context.queryOptions(path, queryKey, ...args),
/**
* DecorateQueryProcedure
*/
fetch: () => context.fetchQuery(queryKey, ...args),
fetchInfinite: () => context.fetchInfiniteQuery(queryKey, args[0]),
prefetch: () => context.prefetchQuery(queryKey, ...args),
prefetchInfinite: () => context.prefetchInfiniteQuery(queryKey, args[0]),
ensureData: () => context.ensureQueryData(queryKey, ...args),
invalidate: () => context.invalidateQueries(queryKey, ...args),
reset: () => context.resetQueries(queryKey, ...args),
refetch: () => context.refetchQueries(queryKey, ...args),
cancel: () => context.cancelQuery(queryKey, ...args),
setData: () => {
context.setQueryData(queryKey, args[0], args[1]);
},
setQueriesData: () =>
context.setQueriesData(queryKey, args[0], args[1], args[2]),
setInfiniteData: () => {
context.setInfiniteQueryData(queryKey, args[0], args[1]);
},
getData: () => context.getQueryData(queryKey),
getInfiniteData: () => context.getInfiniteQueryData(queryKey),
/**
* DecorateMutationProcedure
*/
setMutationDefaults: () =>
context.setMutationDefaults(getMutationKeyInternal(path), input),
getMutationDefaults: () =>
context.getMutationDefaults(getMutationKeyInternal(path)),
isMutating: () =>
context.isMutating({ mutationKey: getMutationKeyInternal(path) }),
};
return contextMap[utilName]();
});
}
/**
* @internal
*/
export function createReactQueryUtils<TRouter extends AnyRouter, TSSRContext>(
context: TRPCContextState<AnyRouter, TSSRContext>,
) {
type CreateReactUtilsReturnType = CreateReactUtils<TRouter, TSSRContext>;
const clientProxy = createTRPCClientProxy(context.client);
const proxy = createRecursiveUtilsProxy(
context,
) as CreateReactUtilsReturnType;
return createFlatProxy<CreateReactUtilsReturnType>((key) => {
const contextName = key as (typeof contextProps)[number];
if (contextName === 'client') {
return clientProxy;
}
if (contextProps.includes(contextName)) {
return context[contextName];
}
return proxy[key];
});
}
/**
* @internal
*/
export function createQueryUtilsProxy<TRouter extends AnyRouter>(
context: TRPCQueryUtils<TRouter>,
): CreateQueryUtils<TRouter> {
return createRecursiveUtilsProxy(context);
}

View File

@@ -0,0 +1,21 @@
import type { QueryClientConfig } from '@tanstack/react-query';
import { QueryClient } from '@tanstack/react-query';
/**
* @internal
*/
export type CreateTRPCReactQueryClientConfig =
| {
queryClient?: QueryClient;
queryClientConfig?: never;
}
| {
queryClientConfig?: QueryClientConfig;
queryClient?: never;
};
/**
* @internal
*/
export const getQueryClient = (config: CreateTRPCReactQueryClientConfig) =>
config.queryClient ?? new QueryClient(config.queryClientConfig);

271
node_modules/@trpc/react-query/src/shared/types.ts generated vendored Normal file
View File

@@ -0,0 +1,271 @@
import type {
DataTag,
DefinedInitialDataInfiniteOptions,
DefinedInitialDataOptions,
InfiniteData,
QueryClient,
UndefinedInitialDataInfiniteOptions,
UndefinedInitialDataOptions,
UnusedSkipTokenInfiniteOptions,
UnusedSkipTokenOptions,
} from '@tanstack/react-query';
import type {
AnyRouter,
coerceAsyncIterableToArray,
DistributiveOmit,
MaybePromise,
} from '@trpc/server/unstable-core-do-not-import';
import type { TRPCQueryKey } from '../internals/getQueryKey';
import type { ExtractCursorType, TRPCReactRequestOptions } from './hooks/types';
export interface TRPCQueryBaseOptions {
/**
* tRPC-related options
*/
trpc?: TRPCReactRequestOptions;
}
export interface TRPCQueryOptionsResult {
trpc: {
path: string;
};
}
type TRPCOptionOverrides = 'queryKey' | 'queryFn' | 'queryHashFn' | 'queryHash';
type TRPCInfiniteOptionOverrides = TRPCOptionOverrides | 'initialPageParam';
/**
* QueryOptions API helpers
*/
export interface UndefinedTRPCQueryOptionsIn<TQueryFnData, TData, TError>
extends DistributiveOmit<
UndefinedInitialDataOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TData>,
TRPCQueryKey
>,
TRPCOptionOverrides
>,
TRPCQueryBaseOptions {}
export interface UndefinedTRPCQueryOptionsOut<TQueryFnData, TOutput, TError>
extends UndefinedInitialDataOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TOutput>,
TRPCQueryKey
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, coerceAsyncIterableToArray<TOutput>, TError>;
}
export interface DefinedTRPCQueryOptionsIn<TQueryFnData, TData, TError>
extends DistributiveOmit<
DefinedInitialDataOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TData>,
TRPCQueryKey
>,
TRPCOptionOverrides
>,
TRPCQueryBaseOptions {}
export interface DefinedTRPCQueryOptionsOut<TQueryFnData, TData, TError>
extends DefinedInitialDataOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TData>,
TRPCQueryKey
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, coerceAsyncIterableToArray<TData>, TError>;
}
export interface UnusedSkipTokenTRPCQueryOptionsIn<TQueryFnData, TData, TError>
extends DistributiveOmit<
UnusedSkipTokenOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TData>,
TRPCQueryKey
>,
TRPCOptionOverrides
>,
TRPCQueryBaseOptions {}
export interface UnusedSkipTokenTRPCQueryOptionsOut<
TQueryFnData,
TOutput,
TError,
> extends UnusedSkipTokenOptions<
coerceAsyncIterableToArray<TQueryFnData>,
TError,
coerceAsyncIterableToArray<TOutput>,
TRPCQueryKey
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, coerceAsyncIterableToArray<TOutput>, TError>;
}
/**
* InifiniteQueryOptions helpers
*/
export interface UndefinedTRPCInfiniteQueryOptionsIn<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
TRPCInfiniteOptionOverrides
>,
TRPCQueryBaseOptions {
initialCursor?: NonNullable<ExtractCursorType<TInput>> | null;
}
export interface UndefinedTRPCInfiniteQueryOptionsOut<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
UndefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
'initialPageParam'
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, TData, TError>;
initialPageParam: NonNullable<ExtractCursorType<TInput>> | null;
}
export interface DefinedTRPCInfiniteQueryOptionsIn<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
TRPCInfiniteOptionOverrides
>,
TRPCQueryBaseOptions {
initialCursor?: NonNullable<ExtractCursorType<TInput>> | null;
}
export interface DefinedTRPCInfiniteQueryOptionsOut<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
DefinedInitialDataInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
'initialPageParam'
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, TData, TError>;
initialPageParam: NonNullable<ExtractCursorType<TInput>> | null;
}
export interface UnusedSkipTokenTRPCInfiniteQueryOptionsIn<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
UnusedSkipTokenInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
TRPCInfiniteOptionOverrides
>,
TRPCQueryBaseOptions {
initialCursor?: NonNullable<ExtractCursorType<TInput>> | null;
}
export interface UnusedSkipTokenTRPCInfiniteQueryOptionsOut<
TInput,
TQueryFnData,
TData,
TError,
> extends DistributiveOmit<
UnusedSkipTokenInfiniteOptions<
TQueryFnData,
TError,
InfiniteData<TData, NonNullable<ExtractCursorType<TInput>> | null>,
TRPCQueryKey,
NonNullable<ExtractCursorType<TInput>> | null
>,
'initialPageParam'
>,
TRPCQueryOptionsResult {
queryKey: DataTag<TRPCQueryKey, TData, TError>;
initialPageParam: NonNullable<ExtractCursorType<TInput>> | null;
}
/**
* @internal
*/
export interface UseMutationOverride {
onSuccess: (opts: {
/**
* Calls the original function that was defined in the query's `onSuccess` option
*/
originalFn: () => MaybePromise<void>;
queryClient: QueryClient;
/**
* Meta data passed in from the `useMutation()` hook
*/
meta: Record<string, unknown>;
}) => MaybePromise<void>;
}
/**
* @internal
*/
export interface CreateTRPCReactOptions<_TRouter extends AnyRouter> {
/**
* Override behaviors of the built-in hooks
*/
overrides?: {
useMutation?: Partial<UseMutationOverride>;
};
/**
* Abort all queries when unmounting
* @default false
*/
abortOnUnmount?: boolean;
/**
* Override the default context provider
* @default undefined
*/
context?: React.Context<any>;
}

View File

@@ -0,0 +1,269 @@
import type { QueryFunctionContext } from '@tanstack/react-query';
import {
infiniteQueryOptions,
queryOptions,
skipToken,
type QueryClient,
} from '@tanstack/react-query';
import type { TRPCClient, TRPCClientError } from '@trpc/client';
import { getUntypedClient, TRPCUntypedClient } from '@trpc/client';
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import { isAsyncIterable } from '@trpc/server/unstable-core-do-not-import';
import type { AnyClientTypes } from '@trpc/server/unstable-core-do-not-import/clientish/inferrable';
import { getClientArgs } from '../internals/getClientArgs';
import type { TRPCQueryKey } from '../internals/getQueryKey';
import {
buildQueryFromAsyncIterable,
createTRPCOptionsResult,
} from '../internals/trpcResult';
import type { DefinedTRPCQueryOptionsOut } from '../shared';
import { type TRPCQueryUtils } from '../shared';
export interface CreateQueryUtilsOptions<TRouter extends AnyRouter> {
/**
* The `TRPCClient`
*/
client: TRPCClient<TRouter> | TRPCUntypedClient<TRouter>;
/**
* The `QueryClient` from `react-query`
*/
queryClient: QueryClient;
}
/**
* Creates a set of utility functions that can be used to interact with `react-query`
* @param opts the `TRPCClient` and `QueryClient` to use
* @returns a set of utility functions that can be used to interact with `react-query`
* @internal
*/
export function createUtilityFunctions<TRouter extends AnyRouter>(
opts: CreateQueryUtilsOptions<TRouter>,
): TRPCQueryUtils<TRouter> {
const { client, queryClient } = opts;
const untypedClient =
client instanceof TRPCUntypedClient ? client : getUntypedClient(client);
return {
infiniteQueryOptions: (path, queryKey, opts) => {
const inputIsSkipToken = queryKey[1]?.input === skipToken;
const queryFn = async (
queryFnContext: QueryFunctionContext<TRPCQueryKey, unknown>,
): Promise<unknown> => {
const actualOpts = {
...opts,
trpc: {
...opts?.trpc,
...(opts?.trpc?.abortOnUnmount
? { signal: queryFnContext.signal }
: { signal: null }),
},
};
const result = await untypedClient.query(
...getClientArgs(queryKey, actualOpts, {
direction: queryFnContext.direction,
pageParam: queryFnContext.pageParam,
}),
);
return result;
};
return Object.assign(
infiniteQueryOptions({
...opts,
initialData: opts?.initialData as any,
queryKey,
queryFn: inputIsSkipToken ? skipToken : queryFn,
initialPageParam: (opts?.initialCursor as any) ?? null,
}),
{ trpc: createTRPCOptionsResult({ path }) },
);
},
queryOptions: (path, queryKey, opts) => {
const inputIsSkipToken = queryKey[1]?.input === skipToken;
const queryFn = async (
queryFnContext: QueryFunctionContext<TRPCQueryKey>,
): Promise<unknown> => {
const actualOpts = {
...opts,
trpc: {
...opts?.trpc,
...(opts?.trpc?.abortOnUnmount
? { signal: queryFnContext.signal }
: { signal: null }),
},
};
const result = await untypedClient.query(
...getClientArgs(queryKey, actualOpts),
);
if (isAsyncIterable(result)) {
return buildQueryFromAsyncIterable(result, queryClient, queryKey);
}
return result;
};
return Object.assign(
queryOptions({
...opts,
initialData: opts?.initialData,
queryKey,
queryFn: inputIsSkipToken ? skipToken : queryFn,
}),
{ trpc: createTRPCOptionsResult({ path }) },
) as DefinedTRPCQueryOptionsOut<
unknown,
unknown,
TRPCClientError<AnyClientTypes>
>;
},
fetchQuery: (queryKey, opts) => {
return queryClient.fetchQuery({
...opts,
queryKey,
queryFn: () => untypedClient.query(...getClientArgs(queryKey, opts)),
});
},
fetchInfiniteQuery: (queryKey, opts) => {
return queryClient.fetchInfiniteQuery({
...opts,
queryKey,
queryFn: ({ pageParam, direction }) => {
return untypedClient.query(
...getClientArgs(queryKey, opts, { pageParam, direction }),
);
},
initialPageParam: opts?.initialCursor ?? null,
});
},
prefetchQuery: (queryKey, opts) => {
return queryClient.prefetchQuery({
...opts,
queryKey,
queryFn: () => untypedClient.query(...getClientArgs(queryKey, opts)),
});
},
prefetchInfiniteQuery: (queryKey, opts) => {
return queryClient.prefetchInfiniteQuery({
...opts,
queryKey,
queryFn: ({ pageParam, direction }) => {
return untypedClient.query(
...getClientArgs(queryKey, opts, { pageParam, direction }),
);
},
initialPageParam: opts?.initialCursor ?? null,
});
},
ensureQueryData: (queryKey, opts) => {
return queryClient.ensureQueryData({
...opts,
queryKey,
queryFn: () => untypedClient.query(...getClientArgs(queryKey, opts)),
});
},
invalidateQueries: (queryKey, filters, options) => {
return queryClient.invalidateQueries(
{
...filters,
queryKey,
},
options,
);
},
resetQueries: (queryKey, filters, options) => {
return queryClient.resetQueries(
{
...filters,
queryKey,
},
options,
);
},
refetchQueries: (queryKey, filters, options) => {
return queryClient.refetchQueries(
{
...filters,
queryKey,
},
options,
);
},
cancelQuery: (queryKey, options) => {
return queryClient.cancelQueries(
{
queryKey,
},
options,
);
},
setQueryData: (queryKey, updater, options) => {
return queryClient.setQueryData(queryKey, updater as any, options);
},
// eslint-disable-next-line max-params
setQueriesData: (queryKey, filters, updater, options) => {
return queryClient.setQueriesData(
{
...filters,
queryKey,
},
updater,
options,
);
},
getQueryData: (queryKey) => {
return queryClient.getQueryData(queryKey);
},
setInfiniteQueryData: (queryKey, updater, options) => {
return queryClient.setQueryData(queryKey, updater as any, options);
},
getInfiniteQueryData: (queryKey) => {
return queryClient.getQueryData(queryKey);
},
setMutationDefaults: (mutationKey, options) => {
const path = mutationKey[0];
const canonicalMutationFn = (input: unknown) => {
return untypedClient.mutation(
...getClientArgs([path, { input }], opts),
);
};
return queryClient.setMutationDefaults(
mutationKey,
typeof options === 'function'
? options({ canonicalMutationFn })
: options,
);
},
getMutationDefaults: (mutationKey) => {
return queryClient.getMutationDefaults(mutationKey);
},
isMutating: (filters) => {
return queryClient.isMutating({
...filters,
exact: true,
});
},
};
}

View File

@@ -0,0 +1,94 @@
import type { TRPCClientErrorLike } from '@trpc/client';
import type {
AnyMutationProcedure,
AnyProcedure,
AnyQueryProcedure,
AnyRootTypes,
AnyRouter,
inferProcedureInput,
inferTransformedProcedureOutput,
RouterRecord,
} from '@trpc/server/unstable-core-do-not-import';
import type {
UseTRPCMutationOptions,
UseTRPCMutationResult,
UseTRPCQueryOptions,
UseTRPCQueryResult,
} from '../shared';
/**
* @internal
*/
export type InferQueryOptions<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
TData = inferTransformedProcedureOutput<TRoot, TProcedure>,
> = Omit<
UseTRPCQueryOptions<
inferTransformedProcedureOutput<TRoot, TProcedure>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientErrorLike<TRoot>,
TData
>,
'select' | 'queryFn'
>;
/**
* @internal
*/
export type InferMutationOptions<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
TMeta = unknown,
> = UseTRPCMutationOptions<
inferProcedureInput<TProcedure>,
TRPCClientErrorLike<TRoot>,
inferTransformedProcedureOutput<TRoot, TProcedure>,
TMeta
>;
/**
* @internal
*/
export type InferQueryResult<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
> = UseTRPCQueryResult<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientErrorLike<TRoot>
>;
/**
* @internal
*/
export type InferMutationResult<
TRoot extends AnyRootTypes,
TProcedure extends AnyProcedure,
TContext = unknown,
> = UseTRPCMutationResult<
inferTransformedProcedureOutput<TRoot, TProcedure>,
TRPCClientErrorLike<TRoot>,
inferProcedureInput<TProcedure>,
TContext
>;
type inferReactQueryProcedureOptionsInner<
TRoot extends AnyRootTypes,
TRecord extends RouterRecord,
> = {
[TKey in keyof TRecord]: TRecord[TKey] extends infer $Value
? $Value extends AnyQueryProcedure
? InferQueryOptions<TRoot, $Value>
: $Value extends AnyMutationProcedure
? InferMutationOptions<TRoot, $Value>
: $Value extends RouterRecord
? inferReactQueryProcedureOptionsInner<TRoot, $Value>
: never
: never;
};
export type inferReactQueryProcedureOptions<TRouter extends AnyRouter> =
inferReactQueryProcedureOptionsInner<
TRouter['_def']['_config']['$types'],
TRouter['_def']['record']
>;