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