/* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { Unsubscribable } from '@trpc/server/observable'; import type { AnyProcedure, AnyRouter, inferClientTypes, inferProcedureInput, InferrableClientTypes, inferTransformedProcedureOutput, ProcedureType, RouterRecord, } from '@trpc/server/unstable-core-do-not-import'; import { createFlatProxy, createRecursiveProxy, } from '@trpc/server/unstable-core-do-not-import'; import type { CreateTRPCClientOptions } from './createTRPCUntypedClient'; import type { TRPCSubscriptionObserver } from './internals/TRPCUntypedClient'; import { TRPCUntypedClient } from './internals/TRPCUntypedClient'; import type { TRPCProcedureOptions } from './internals/types'; import type { TRPCClientError } from './TRPCClientError'; /** * @public * @deprecated use {@link TRPCClient} instead, will be removed in v12 **/ export type inferRouterClient = TRPCClient; /** * @public * @deprecated use {@link TRPCClient} instead, will be removed in v12 **/ export type CreateTRPCClient = TRPCClient; const untypedClientSymbol = Symbol.for('trpc_untypedClient'); /** * @public **/ export type TRPCClient = DecoratedProcedureRecord< { transformer: TRouter['_def']['_config']['$types']['transformer']; errorShape: TRouter['_def']['_config']['$types']['errorShape']; }, TRouter['_def']['record'] > & { [untypedClientSymbol]: TRPCUntypedClient; }; /** @internal */ export type TRPCResolverDef = { input: any; output: any; transformer: boolean; errorShape: any; }; type coerceAsyncGeneratorToIterable = T extends AsyncGenerator ? AsyncIterable<$T, $Return, $Next> : T; /** @internal */ export type Resolver = ( input: TDef['input'], opts?: TRPCProcedureOptions, ) => Promise>; /** @internal */ export type SubscriptionResolver = ( input: TDef['input'], opts: Partial< TRPCSubscriptionObserver> > & TRPCProcedureOptions, ) => Unsubscribable; type DecorateProcedure< TType extends ProcedureType, TDef extends TRPCResolverDef, > = TType extends 'query' ? { query: Resolver; } : TType extends 'mutation' ? { mutate: Resolver; } : TType extends 'subscription' ? { subscribe: SubscriptionResolver; } : never; /** * @internal */ type DecoratedProcedureRecord< TRoot extends InferrableClientTypes, TRecord extends RouterRecord, > = { [TKey in keyof TRecord]: TRecord[TKey] extends infer $Value ? $Value extends AnyProcedure ? DecorateProcedure< $Value['_def']['type'], { input: inferProcedureInput<$Value>; output: inferTransformedProcedureOutput< inferClientTypes, $Value >; errorShape: inferClientTypes['errorShape']; transformer: inferClientTypes['transformer']; } > : $Value extends RouterRecord ? DecoratedProcedureRecord : never : never; }; const clientCallTypeMap: Record< keyof DecorateProcedure, ProcedureType > = { query: 'query', mutate: 'mutation', subscribe: 'subscription', }; /** @internal */ export const clientCallTypeToProcedureType = ( clientCallType: string, ): ProcedureType => { return clientCallTypeMap[clientCallType as keyof typeof clientCallTypeMap]; }; /** * @internal */ export function createTRPCClientProxy( client: TRPCUntypedClient, ): TRPCClient { const proxy = createRecursiveProxy>(({ path, args }) => { const pathCopy = [...path]; const procedureType = clientCallTypeToProcedureType(pathCopy.pop()!); const fullPath = pathCopy.join('.'); return (client[procedureType] as any)(fullPath, ...(args as any)); }); return createFlatProxy>((key) => { if (key === untypedClientSymbol) { return client; } return proxy[key]; }); } export function createTRPCClient( opts: CreateTRPCClientOptions, ): TRPCClient { const client = new TRPCUntypedClient(opts); const proxy = createTRPCClientProxy(client); return proxy; } /** * Get an untyped client from a proxy client * @internal */ export function getUntypedClient( client: TRPCClient, ): TRPCUntypedClient { return client[untypedClientSymbol]; }