import { DefaultErrorShape, defaultFormatter, ErrorFormatter, ErrorFormatterShape, } from './error/formatter'; import { CreateRootConfigTypes, isServerDefault, RootConfig, RootConfigTypes, RuntimeConfig, } from './internals/config'; import { mergeRouters } from './internals/mergeRouters'; import { createBuilder } from './internals/procedureBuilder'; import { Overwrite, PickFirstDefined, ValidateShape } from './internals/utils'; import { createMiddlewareFactory } from './middleware'; import { createCallerFactory, createRouterFactory } from './router'; import { createFlatProxy } from './shared/createProxy'; import { DataTransformerOptions, DefaultDataTransformer, defaultTransformer, getDataTransformer, } from './transformer'; import { Unwrap } from './types'; type PartialRootConfigTypes = Partial; type CreateRootConfigTypesFromPartial = CreateRootConfigTypes<{ ctx: TTypes['ctx'] extends RootConfigTypes['ctx'] ? TTypes['ctx'] : object; meta: TTypes['meta'] extends RootConfigTypes['meta'] ? TTypes['meta'] : object; errorShape: TTypes['errorShape']; transformer: DataTransformerOptions; }>; /** * TODO: This can be improved: * - We should be able to chain `.meta()`/`.context()` only once * - Simplify typings * - Doesn't need to be a class but it doesn't really hurt either */ class TRPCBuilder { context< TNewContext extends | RootConfigTypes['ctx'] | ((...args: unknown[]) => RootConfigTypes['ctx']), >() { type NextParams = Overwrite }>; return new TRPCBuilder(); } meta() { type NextParams = Overwrite; return new TRPCBuilder(); } create< TOptions extends Partial< RuntimeConfig> >, >( options?: | ValidateShape< TOptions, Partial>> > | undefined, ) { return createTRPCInner()(options); } } /** * Initialize tRPC - done exactly once per backend */ export const initTRPC = new TRPCBuilder(); function createTRPCInner() { type $Generics = CreateRootConfigTypesFromPartial; type $Context = $Generics['ctx']; type $Meta = $Generics['meta']; type $Runtime = Partial>; return function initTRPCInner( runtime?: ValidateShape, ) { type $Formatter = PickFirstDefined< TOptions['errorFormatter'], ErrorFormatter<$Context, DefaultErrorShape> >; type $Transformer = TOptions['transformer'] extends DataTransformerOptions ? TOptions['transformer'] : DefaultDataTransformer; type $ErrorShape = ErrorFormatterShape<$Formatter>; type $Config = RootConfig<{ ctx: $Context; meta: $Meta; errorShape: $ErrorShape; transformer: $Transformer; }>; const errorFormatter = runtime?.errorFormatter ?? defaultFormatter; const transformer = getDataTransformer( runtime?.transformer ?? defaultTransformer, ) as $Transformer; const config: $Config = { transformer, isDev: runtime?.isDev ?? // eslint-disable-next-line @typescript-eslint/dot-notation globalThis.process?.env?.['NODE_ENV'] !== 'production', allowOutsideOfServer: runtime?.allowOutsideOfServer ?? false, errorFormatter, isServer: runtime?.isServer ?? isServerDefault, /** * @internal */ $types: createFlatProxy((key) => { throw new Error( `Tried to access "$types.${key}" which is not available at runtime`, ); }), }; { // Server check const isServer: boolean = runtime?.isServer ?? isServerDefault; if (!isServer && runtime?.allowOutsideOfServer !== true) { throw new Error( `You're trying to use @trpc/server in a non-server environment. This is not supported by default.`, ); } } return { /** * These are just types, they can't be used * @internal */ _config: config, /** * Builder object for creating procedures * @see https://trpc.io/docs/server/procedures */ procedure: createBuilder< $Config['$types']['ctx'], $Config['$types']['meta'] >({ meta: runtime?.defaultMeta, }), /** * Create reusable middlewares * @see https://trpc.io/docs/server/middlewares */ middleware: createMiddlewareFactory< $Config['$types']['ctx'], $Config['$types']['meta'] >(), /** * Create a router * @see https://trpc.io/docs/server/routers */ router: createRouterFactory<$Config>(config), /** * Merge Routers * @see https://trpc.io/docs/server/merging-routers */ mergeRouters, /** * Create a server-side caller for a router * @see https://trpc.io/docs/server/server-side-calls */ createCallerFactory: createCallerFactory<$Config>(), }; }; }