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,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>;
}