@trpc/server 10.0.0-alpha.38 → 10.0.0-alpha.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.dev.js +20 -0
  2. package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.cjs.prod.js +20 -0
  3. package/adapters/aws-lambda/dist/trpc-server-adapters-aws-lambda.esm.js +20 -0
  4. package/dist/adapters/aws-lambda/index.d.ts.map +1 -1
  5. package/dist/core/index.d.ts +2 -1
  6. package/dist/core/index.d.ts.map +1 -1
  7. package/dist/core/initTRPC.d.ts +1 -1
  8. package/dist/core/internals/procedureBuilder.d.ts +37 -13
  9. package/dist/core/internals/procedureBuilder.d.ts.map +1 -1
  10. package/dist/core/procedure.d.ts +12 -8
  11. package/dist/core/procedure.d.ts.map +1 -1
  12. package/dist/core/router.d.ts +17 -3
  13. package/dist/core/router.d.ts.map +1 -1
  14. package/dist/core/types.d.ts +3 -1
  15. package/dist/core/types.d.ts.map +1 -1
  16. package/dist/index-1a25ccbd.js +33 -0
  17. package/dist/index-a3bd54c7.mjs +31 -0
  18. package/dist/index.js +186 -191
  19. package/dist/index.mjs +185 -192
  20. package/dist/shared/index.js +2 -28
  21. package/dist/shared/index.mjs +1 -31
  22. package/dist/types.d.ts +10 -0
  23. package/dist/types.d.ts.map +1 -1
  24. package/package.json +2 -2
  25. package/src/adapters/aws-lambda/index.ts +17 -0
  26. package/src/core/index.ts +2 -1
  27. package/src/core/internals/procedureBuilder.ts +264 -28
  28. package/src/core/procedure.ts +17 -10
  29. package/src/core/router.ts +79 -78
  30. package/src/core/types.ts +5 -1
  31. package/src/deprecated/interop.ts +4 -4
  32. package/src/types.ts +12 -0
  33. package/dist/core/internals/internalProcedure.d.ts +0 -78
  34. package/dist/core/internals/internalProcedure.d.ts.map +0 -1
  35. package/src/core/internals/internalProcedure.ts +0 -297
@@ -1,5 +1,7 @@
1
+ import { TRPCError } from '../../error/TRPCError';
2
+ import { getCauseFromUnknown, getErrorFromUnknown } from '../../error/utils';
1
3
  import { MaybePromise } from '../../types';
2
- import { MiddlewareFunction } from '../middleware';
4
+ import { MiddlewareFunction, MiddlewareResult } from '../middleware';
3
5
  import { Parser, inferParser } from '../parser';
4
6
  import {
5
7
  MutationProcedure,
@@ -8,9 +10,11 @@ import {
8
10
  QueryProcedure,
9
11
  SubscriptionProcedure,
10
12
  } from '../procedure';
13
+ import { ProcedureType } from '../types';
11
14
  import { RootConfig } from './config';
12
- import { createInternalBuilder } from './internalProcedure';
13
- import { ResolveOptions } from './utils';
15
+ import { ParseFn, getParseFn } from './getParseFn';
16
+ import { mergeWithoutOverrides } from './mergeWithoutOverrides';
17
+ import { ResolveOptions, middlewareMarker } from './utils';
14
18
  import { DefaultValue as FallbackValue, Overwrite, UnsetMarker } from './utils';
15
19
 
16
20
  type CreateProcedureReturnInput<
@@ -21,8 +25,8 @@ type CreateProcedureReturnInput<
21
25
  _meta: TPrev['_meta'];
22
26
  _ctx_in: TPrev['_ctx_in'];
23
27
  _ctx_out: Overwrite<TPrev['_ctx_out'], TNext['_ctx_out']>;
24
- _input_out: FallbackValue<TNext['_input_out'], TPrev['_input_out']>;
25
28
  _input_in: FallbackValue<TNext['_input_in'], TPrev['_input_in']>;
29
+ _input_out: FallbackValue<TNext['_input_out'], TPrev['_input_out']>;
26
30
  _output_in: FallbackValue<TNext['_output_in'], TPrev['_output_in']>;
27
31
  _output_out: FallbackValue<TNext['_output_out'], TPrev['_output_out']>;
28
32
  }>;
@@ -38,10 +42,10 @@ export interface ProcedureBuilder<TParams extends ProcedureParams> {
38
42
  _meta: TParams['_meta'];
39
43
  _ctx_in: TParams['_ctx_in'];
40
44
  _ctx_out: TParams['_ctx_out'];
41
- _output_in: TParams['_output_in'];
42
- _output_out: TParams['_output_out'];
43
45
  _input_in: inferParser<$TParser>['in'];
44
46
  _input_out: inferParser<$TParser>['out'];
47
+ _output_in: TParams['_output_in'];
48
+ _output_out: TParams['_output_out'];
45
49
  }>;
46
50
  /**
47
51
  * Add an output parser to the procedure.
@@ -72,7 +76,7 @@ export interface ProcedureBuilder<TParams extends ProcedureParams> {
72
76
  * Extend the procedure with another procedure.
73
77
  * @warning The TypeScript inference fails when chaining concatenated procedures.
74
78
  */
75
- unstable_concat<$ProcedureReturnInput extends ProcedureBuilder<any>>(
79
+ unstable_concat<$ProcedureReturnInput extends AnyProcedureBuilder>(
76
80
  proc: $ProcedureReturnInput,
77
81
  ): $ProcedureReturnInput extends ProcedureBuilder<infer $TParams>
78
82
  ? CreateProcedureReturnInput<TParams, $TParams>
@@ -94,24 +98,7 @@ export interface ProcedureBuilder<TParams extends ProcedureParams> {
94
98
  >
95
99
  >
96
100
  : Procedure<TParams>;
97
- /**
98
- * Query procedure
99
- */
100
- query<$TOutput>(
101
- resolver: (
102
- opts: ResolveOptions<TParams>,
103
- ) => MaybePromise<FallbackValue<TParams['_output_in'], $TOutput>>,
104
- ): UnsetMarker extends TParams['_output_out']
105
- ? QueryProcedure<
106
- Overwrite<
107
- TParams,
108
- {
109
- _output_in: $TOutput;
110
- _output_out: $TOutput;
111
- }
112
- >
113
- >
114
- : QueryProcedure<TParams>;
101
+
115
102
  /**
116
103
  * Query procedure
117
104
  */
@@ -168,17 +155,266 @@ export interface ProcedureBuilder<TParams extends ProcedureParams> {
168
155
  >
169
156
  >
170
157
  : SubscriptionProcedure<TParams>;
158
+ /**
159
+ * @internal
160
+ */
161
+ _def: {
162
+ input?: Parser;
163
+ output?: Parser;
164
+ meta?: Record<string, unknown>;
165
+ resolver?: ProcedureBuilderResolver;
166
+ middlewares: ProcedureBuilderMiddleware[];
167
+ mutation?: boolean;
168
+ query?: boolean;
169
+ subscription?: boolean;
170
+ };
171
171
  }
172
172
 
173
- export function createBuilder<TConfig extends RootConfig>(): ProcedureBuilder<{
173
+ type AnyProcedureBuilder = ProcedureBuilder<any>;
174
+ export type ProcedureBuilderDef = AnyProcedureBuilder['_def'];
175
+
176
+ export type ProcedureBuilderMiddleware = MiddlewareFunction<any, any>;
177
+
178
+ export type ProcedureBuilderResolver = (
179
+ opts: ResolveOptions<any>,
180
+ ) => Promise<unknown>;
181
+
182
+ function createNewBuilder(
183
+ def1: ProcedureBuilderDef,
184
+ def2: Partial<ProcedureBuilderDef>,
185
+ ) {
186
+ const { middlewares = [], ...rest } = def2;
187
+
188
+ // TODO: maybe have a fn here to warn about calls
189
+ return createBuilder({
190
+ ...mergeWithoutOverrides(def1, rest),
191
+ middlewares: [...def1.middlewares, ...middlewares],
192
+ } as any);
193
+ }
194
+
195
+ export function createBuilder<TConfig extends RootConfig>(
196
+ initDef?: ProcedureBuilderDef,
197
+ ): ProcedureBuilder<{
174
198
  _config: TConfig;
175
199
  _ctx_in: TConfig['ctx'];
176
200
  _ctx_out: TConfig['ctx'];
177
- _input_out: UnsetMarker;
178
201
  _input_in: UnsetMarker;
202
+ _input_out: UnsetMarker;
179
203
  _output_in: UnsetMarker;
180
204
  _output_out: UnsetMarker;
181
205
  _meta: TConfig['meta'];
182
206
  }> {
183
- return createInternalBuilder() as any;
207
+ const _def: ProcedureBuilderDef = initDef || {
208
+ middlewares: [],
209
+ };
210
+
211
+ return {
212
+ _def,
213
+ input(input) {
214
+ const parser = getParseFn(input);
215
+ return createNewBuilder(_def, {
216
+ input,
217
+ middlewares: [createInputMiddleware(parser)],
218
+ }) as AnyProcedureBuilder;
219
+ },
220
+ output(output: Parser) {
221
+ const parseOutput = getParseFn(output);
222
+ return createNewBuilder(_def, {
223
+ output,
224
+ middlewares: [createOutputMiddleware(parseOutput)],
225
+ }) as AnyProcedureBuilder;
226
+ },
227
+ meta(meta) {
228
+ return createNewBuilder(_def, {
229
+ meta: meta as Record<string, unknown>,
230
+ }) as AnyProcedureBuilder;
231
+ },
232
+ /** @deprecated **/
233
+ resolve(resolver) {
234
+ return createResolver(_def, resolver);
235
+ },
236
+ unstable_concat(builder) {
237
+ return createNewBuilder(_def, builder._def) as any;
238
+ },
239
+ use(middleware) {
240
+ return createNewBuilder(_def, {
241
+ middlewares: [middleware],
242
+ }) as AnyProcedureBuilder;
243
+ },
244
+ query(resolver) {
245
+ return createResolver(
246
+ { ..._def, query: true },
247
+ resolver,
248
+ ) as QueryProcedure<any>;
249
+ },
250
+ mutation(resolver) {
251
+ return createResolver(
252
+ { ..._def, mutation: true },
253
+ resolver,
254
+ ) as MutationProcedure<any>;
255
+ },
256
+ subscription(resolver) {
257
+ return createResolver(
258
+ { ..._def, subscription: true },
259
+ resolver,
260
+ ) as SubscriptionProcedure<any>;
261
+ },
262
+ };
263
+ }
264
+
265
+ export function createInputMiddleware<T>(
266
+ parse: ParseFn<T>,
267
+ ): ProcedureBuilderMiddleware {
268
+ return async function inputMiddleware({ next, rawInput }) {
269
+ let input: ReturnType<typeof parse>;
270
+ try {
271
+ input = await parse(rawInput);
272
+ } catch (cause) {
273
+ throw new TRPCError({
274
+ code: 'BAD_REQUEST',
275
+ cause: getCauseFromUnknown(cause),
276
+ });
277
+ }
278
+ // TODO fix this typing?
279
+ return next({ input } as any);
280
+ };
281
+ }
282
+
283
+ export function createOutputMiddleware<T>(
284
+ parse: ParseFn<T>,
285
+ ): ProcedureBuilderMiddleware {
286
+ return async function outputMiddleware({ next }) {
287
+ const result = await next();
288
+ if (!result.ok) {
289
+ // pass through failures without validating
290
+ return result;
291
+ }
292
+ try {
293
+ const data = await parse(result.data);
294
+ return {
295
+ ...result,
296
+ data,
297
+ };
298
+ } catch (cause) {
299
+ throw new TRPCError({
300
+ message: 'Output validation failed',
301
+ code: 'INTERNAL_SERVER_ERROR',
302
+ cause: getCauseFromUnknown(cause),
303
+ });
304
+ }
305
+ };
306
+ }
307
+
308
+ function createResolver(
309
+ _def: ProcedureBuilderDef,
310
+ resolver: (opts: ResolveOptions<any>) => MaybePromise<any>,
311
+ ) {
312
+ const finalBuilder = createNewBuilder(_def, {
313
+ resolver,
314
+ middlewares: [
315
+ async function resolveMiddleware(opts) {
316
+ const data = await resolver(opts);
317
+ return {
318
+ marker: middlewareMarker,
319
+ ok: true,
320
+ data,
321
+ ctx: opts.ctx,
322
+ } as const;
323
+ },
324
+ ],
325
+ });
326
+
327
+ return createProcedureCaller(finalBuilder._def);
328
+ }
329
+
330
+ /**
331
+ * @internal
332
+ */
333
+ export interface ProcedureCallOptions {
334
+ ctx: unknown;
335
+ rawInput: unknown;
336
+ input?: unknown;
337
+ path: string;
338
+ type: ProcedureType;
339
+ }
340
+
341
+ const codeblock = `
342
+ If you want to call this function on the server, you do the following:
343
+ This is a client-only function.
344
+
345
+ const caller = appRouter.createCaller({
346
+ /* ... your context */
347
+ });
348
+
349
+ const result = await caller.call('myProcedure', input);
350
+ `.trim();
351
+
352
+ function createProcedureCaller(_def: ProcedureBuilderDef): Procedure<any> {
353
+ const procedure = async function resolve(opts: ProcedureCallOptions) {
354
+ // is direct server-side call
355
+ if (!opts || !('rawInput' in opts)) {
356
+ throw new Error(codeblock);
357
+ }
358
+
359
+ // run the middlewares recursively with the resolver as the last one
360
+ const callRecursive = async (
361
+ callOpts: { ctx: any; index: number; input?: unknown } = {
362
+ index: 0,
363
+ ctx: opts.ctx,
364
+ },
365
+ ): Promise<MiddlewareResult<any>> => {
366
+ try {
367
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
368
+ const middleware = _def.middlewares[callOpts.index]!;
369
+ const result = await middleware({
370
+ ctx: callOpts.ctx,
371
+ type: opts.type,
372
+ path: opts.path,
373
+ rawInput: opts.rawInput,
374
+ meta: _def.meta,
375
+ input: callOpts.input,
376
+ next: async (nextOpts?: { ctx: any; input?: any }) => {
377
+ return await callRecursive({
378
+ index: callOpts.index + 1,
379
+ ctx:
380
+ nextOpts && 'ctx' in nextOpts
381
+ ? { ...callOpts.ctx, ...nextOpts.ctx }
382
+ : callOpts.ctx,
383
+ input:
384
+ nextOpts && 'input' in nextOpts
385
+ ? nextOpts.input
386
+ : callOpts.input,
387
+ });
388
+ },
389
+ });
390
+ return result;
391
+ } catch (cause) {
392
+ return {
393
+ ok: false,
394
+ error: getErrorFromUnknown(cause),
395
+ marker: middlewareMarker,
396
+ };
397
+ }
398
+ };
399
+
400
+ // there's always at least one "next" since we wrap this.resolver in a middleware
401
+ const result = await callRecursive();
402
+
403
+ if (!result) {
404
+ throw new TRPCError({
405
+ code: 'INTERNAL_SERVER_ERROR',
406
+ message:
407
+ 'No result from middlewares - did you forget to `return next()`?',
408
+ });
409
+ }
410
+ if (!result.ok) {
411
+ // re-throw original error
412
+ throw result.error;
413
+ }
414
+ return result.data;
415
+ };
416
+ procedure._def = _def;
417
+ procedure.meta = _def.meta;
418
+
419
+ return procedure as Procedure<any>;
184
420
  }
@@ -1,6 +1,10 @@
1
1
  import { DefaultErrorShape } from '../error/formatter';
2
2
  import { CombinedDataTransformer } from '../transformer';
3
3
  import { RootConfig } from './internals/config';
4
+ import {
5
+ ProcedureBuilderDef,
6
+ ProcedureCallOptions,
7
+ } from './internals/procedureBuilder';
4
8
  import { UnsetMarker } from './internals/utils';
5
9
 
6
10
  type ClientContext = Record<string, unknown>;
@@ -46,19 +50,19 @@ export interface ProcedureParams<
46
50
  /**
47
51
  * @internal
48
52
  */
49
- _output_in: TOutputIn;
53
+ _input_in: TInputIn;
50
54
  /**
51
55
  * @internal
52
56
  */
53
- _output_out: TOutputOut;
57
+ _input_out: TInputOut;
54
58
  /**
55
59
  * @internal
56
60
  */
57
- _input_in: TInputIn;
61
+ _output_in: TOutputIn;
58
62
  /**
59
63
  * @internal
60
64
  */
61
- _input_out: TInputOut;
65
+ _output_out: TOutputOut;
62
66
  }
63
67
 
64
68
  /**
@@ -72,37 +76,40 @@ export type ProcedureArgs<TParams extends ProcedureParams> =
72
76
  : [input: TParams['_input_in'], opts?: ProcedureOptions];
73
77
 
74
78
  /**
79
+ *
75
80
  * @internal
76
81
  */
77
82
  export interface ProcedureBase<TParams extends ProcedureParams> {
78
- _def: TParams;
83
+ _def: TParams & ProcedureBuilderDef;
79
84
  /**
80
85
  * @deprecated use `._def.meta` instead
81
86
  */
82
87
  meta?: TParams['_meta'];
83
88
  _procedure: true;
89
+ /**
90
+ * @internal
91
+ */
92
+ (opts: ProcedureCallOptions): Promise<unknown>;
84
93
  }
85
94
 
86
95
  export interface QueryProcedure<TParams extends ProcedureParams>
87
96
  extends ProcedureBase<TParams> {
88
97
  _query: true;
89
- query(...args: ProcedureArgs<TParams>): Promise<TParams['_output_out']>;
90
98
  }
91
99
 
92
100
  export interface MutationProcedure<TParams extends ProcedureParams>
93
101
  extends ProcedureBase<TParams> {
94
102
  _mutation: true;
95
- mutate(...args: ProcedureArgs<TParams>): Promise<TParams['_output_out']>;
96
103
  }
97
104
 
98
105
  export interface SubscriptionProcedure<TParams extends ProcedureParams>
99
106
  extends ProcedureBase<TParams> {
100
107
  _subscription: true;
101
- subscription(
102
- ...args: ProcedureArgs<TParams>
103
- ): Promise<TParams['_output_out']>;
104
108
  }
109
+
105
110
  export type Procedure<TParams extends ProcedureParams> =
106
111
  | QueryProcedure<TParams>
107
112
  | MutationProcedure<TParams>
108
113
  | SubscriptionProcedure<TParams>;
114
+
115
+ export type AnyProcedure = Procedure<any>;
@@ -9,21 +9,21 @@ import {
9
9
  } from '../error/formatter';
10
10
  import { getHTTPStatusCodeFromError } from '../http/internals/getHTTPStatusCode';
11
11
  import { TRPCErrorShape, TRPC_ERROR_CODES_BY_KEY } from '../rpc';
12
+ import { createProxy } from '../shared';
12
13
  import { CombinedDataTransformer, defaultTransformer } from '../transformer';
13
14
  import { RootConfig } from './internals/config';
14
- import {
15
- InternalProcedure,
16
- InternalProcedureCallOptions,
17
- } from './internals/internalProcedure';
18
15
  import { mergeWithoutOverrides } from './internals/mergeWithoutOverrides';
19
16
  import { omitPrototype } from './internals/omitPrototype';
17
+ import { ProcedureCallOptions } from './internals/procedureBuilder';
20
18
  import {
19
+ AnyProcedure,
21
20
  MutationProcedure,
22
21
  Procedure,
22
+ ProcedureArgs,
23
23
  QueryProcedure,
24
24
  SubscriptionProcedure,
25
25
  } from './procedure';
26
- import { ProcedureType } from './types';
26
+ import { ProcedureType, procedureTypes } from './types';
27
27
 
28
28
  type ProcedureRecord = Record<string, Procedure<any>>;
29
29
 
@@ -122,11 +122,24 @@ type inferHandlerFn<TProcedures extends Record<string, Procedure<any>>> = <
122
122
  ...args: inferHandlerInput<TProcedure>
123
123
  ) => Promise<inferProcedureOutput<TProcedure>>;
124
124
 
125
+ type DecorateProcedure<TProcedure extends Procedure<any>> = (
126
+ input: ProcedureArgs<TProcedure['_def']>[0],
127
+ ) => Promise<TProcedure['_def']['_output_out']>;
128
+
129
+ type assertProcedure<T> = T extends Procedure<any> ? T : never;
130
+
125
131
  /**
126
- * This only exists b/c of interop mode
127
132
  * @internal
128
133
  */
134
+ type DecoratedProcedureRecord<TProcedures extends ProcedureRouterRecord> = {
135
+ [TKey in keyof TProcedures]: TProcedures[TKey] extends AnyRouter
136
+ ? DecoratedProcedureRecord<TProcedures[TKey]['_def']['record']>
137
+ : DecorateProcedure<assertProcedure<TProcedures[TKey]>>;
138
+ };
129
139
 
140
+ /**
141
+ * @internal
142
+ */
130
143
  type RouterCaller<TDef extends AnyRouterDef> = (ctx: TDef['_ctx']) => {
131
144
  /**
132
145
  * @deprecated
@@ -140,7 +153,7 @@ type RouterCaller<TDef extends AnyRouterDef> = (ctx: TDef['_ctx']) => {
140
153
  * @deprecated
141
154
  */
142
155
  subscription: inferHandlerFn<TDef['subscriptions']>;
143
- };
156
+ } & DecoratedProcedureRecord<TDef['record']>;
144
157
 
145
158
  export interface Router<TDef extends AnyRouterDef> {
146
159
  _def: RouterDef<
@@ -153,8 +166,6 @@ export interface Router<TDef extends AnyRouterDef> {
153
166
  errorFormatter: TDef['errorFormatter'];
154
167
  /** @deprecated **/
155
168
  transformer: TDef['transformer'];
156
-
157
- // FIXME rename me and deprecate
158
169
  createCaller: RouterCaller<TDef>;
159
170
  // FIXME rename me and deprecate
160
171
  getErrorShape(opts: {
@@ -183,13 +194,12 @@ export type RouterBuildOptions<TContext> = Partial<
183
194
 
184
195
  export type AnyRouter = Router<any>;
185
196
 
186
- function createRouterProxy(callback: (...args: [string, ...unknown[]]) => any) {
187
- return new Proxy({} as any, {
188
- get(_, path: string) {
189
- return (...args: unknown[]) => callback(path, ...args);
190
- },
191
- });
197
+ function isRouter(
198
+ procedureOrRouter: AnyProcedure | AnyRouter,
199
+ ): procedureOrRouter is AnyRouter {
200
+ return 'router' in procedureOrRouter._def;
192
201
  }
202
+
193
203
  const emptyRouter = {
194
204
  _ctx: null as any,
195
205
  _errorShape: null as any,
@@ -226,9 +236,8 @@ export function createRouterFactory<TConfig extends RootConfig>(
226
236
  for (const [key, procedureOrRouter] of Object.entries(procedures ?? {})) {
227
237
  const newPath = `${path}${key}`;
228
238
 
229
- if (typeof procedureOrRouter === 'object') {
230
- const router = procedureOrRouter as AnyRouter;
231
- recursiveGetPaths(router._def.procedures, `${newPath}.`);
239
+ if (isRouter(procedureOrRouter)) {
240
+ recursiveGetPaths(procedureOrRouter._def.procedures, `${newPath}.`);
232
241
  continue;
233
242
  }
234
243
 
@@ -268,74 +277,46 @@ export function createRouterFactory<TConfig extends RootConfig>(
268
277
  .reduce((acc, [key, val]) => ({ ...acc, [key]: val }), {}),
269
278
  };
270
279
 
271
- function callProcedure(opts: InternalProcedureCallOptions) {
272
- const { type, path } = opts;
273
-
274
- if (!(path in _def.procedures) || !_def.procedures[path]['_def'][type]) {
275
- throw new TRPCError({
276
- code: 'NOT_FOUND',
277
- message: `No "${type}"-procedure on path "${path}"`,
278
- });
279
- }
280
-
281
- const procedure = _def.procedures[path] as InternalProcedure;
282
-
283
- return procedure(opts);
284
- }
285
280
  const router: AnyRouter = {
286
281
  ...opts,
287
282
  _def,
288
283
  transformer: _def.transformer,
289
284
  errorFormatter: _def.errorFormatter,
290
285
  createCaller(ctx) {
291
- return {
292
- query: (path, ...args) =>
293
- callProcedure({
294
- path,
295
- rawInput: args[0],
296
- ctx,
297
- type: 'query',
298
- }) as any,
299
- mutation: (path, ...args) =>
300
- callProcedure({
301
- path,
302
- rawInput: args[0],
286
+ const proxy = createProxy(({ path, args }) => {
287
+ // interop mode
288
+ if (
289
+ path.length === 1 &&
290
+ procedureTypes.includes(path[0] as ProcedureType)
291
+ ) {
292
+ return callProcedure({
293
+ procedures: _def.procedures,
294
+ path: args[0] as string,
295
+ rawInput: args[1],
303
296
  ctx,
304
- type: 'mutation',
305
- }) as any,
306
- subscription: (path, ...args) =>
307
- callProcedure({
308
- path,
309
- rawInput: args[0],
310
- ctx,
311
- type: 'subscription',
312
- }) as any,
297
+ type: path[0] as ProcedureType,
298
+ });
299
+ }
313
300
 
314
- queries: createRouterProxy((path, rawInput) =>
315
- callProcedure({
316
- path,
317
- rawInput,
318
- ctx,
319
- type: 'query',
320
- }),
321
- ),
322
- mutations: createRouterProxy((path, rawInput) =>
323
- callProcedure({
324
- path,
325
- rawInput,
326
- ctx,
327
- type: 'mutation',
328
- }),
329
- ),
330
- subscriptions: createRouterProxy((path, rawInput) =>
331
- callProcedure({
332
- path,
333
- rawInput,
334
- ctx,
335
- type: 'subscription',
336
- }),
337
- ),
338
- };
301
+ const fullPath = path.join('.');
302
+ const procedure = _def.procedures[fullPath] as AnyProcedure;
303
+
304
+ let type: ProcedureType = 'query';
305
+ if (procedure._def.mutation) {
306
+ type = 'mutation';
307
+ } else if (procedure._def.subscription) {
308
+ type = 'subscription';
309
+ }
310
+
311
+ return procedure({
312
+ path: fullPath,
313
+ rawInput: args[0],
314
+ ctx,
315
+ type,
316
+ });
317
+ });
318
+
319
+ return proxy as ReturnType<RouterCaller<any>>;
339
320
  },
340
321
  getErrorShape(opts) {
341
322
  const { path, error } = opts;
@@ -363,3 +344,23 @@ export function createRouterFactory<TConfig extends RootConfig>(
363
344
  return router as any;
364
345
  };
365
346
  }
347
+
348
+ /**
349
+ * @internal
350
+ */
351
+ export function callProcedure(
352
+ opts: ProcedureCallOptions & { procedures: ProcedureRouterRecord },
353
+ ) {
354
+ const { type, path } = opts;
355
+
356
+ if (!(path in opts.procedures) || !opts.procedures[path]?._def[type]) {
357
+ throw new TRPCError({
358
+ code: 'NOT_FOUND',
359
+ message: `No "${type}"-procedure on path "${path}"`,
360
+ });
361
+ }
362
+
363
+ const procedure = opts.procedures[path] as AnyProcedure;
364
+
365
+ return procedure(opts);
366
+ }
package/src/core/types.ts CHANGED
@@ -17,10 +17,11 @@ export type inferRouterError<TRouter extends AnyRouter> =
17
17
  export type inferRouterMeta<TRouter extends AnyRouter> =
18
18
  inferRouterDef<TRouter>['_meta'];
19
19
 
20
+ export const procedureTypes = ['query', 'mutation', 'subscription'] as const;
20
21
  /**
21
22
  * @public
22
23
  */
23
- export type ProcedureType = 'query' | 'mutation' | 'subscription';
24
+ export type ProcedureType = typeof procedureTypes[number];
24
25
 
25
26
  export type inferHandlerInput<TProcedure extends Procedure<any>> =
26
27
  ProcedureArgs<inferProcedureParams<TProcedure>>;
@@ -52,3 +53,6 @@ export type inferSubscriptionOutput<
52
53
  > = inferObservableValue<
53
54
  inferProcedureOutput<TRouter['_def']['subscriptions'][TPath]>
54
55
  >;
56
+
57
+ export type inferProcedureClientError<T extends Procedure<any>> =
58
+ inferProcedureParams<T>['_config']['errorShape'];