orpc-fn 0.1.0 → 0.3.0

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 (156) hide show
  1. package/README.md +70 -33
  2. package/dist/assemble-procedure.d.ts +13 -0
  3. package/dist/assemble-procedure.d.ts.map +1 -0
  4. package/dist/assemble-procedure.js +29 -0
  5. package/dist/assemble-procedure.js.map +1 -0
  6. package/dist/bound-call.d.ts +1 -1
  7. package/dist/bound-call.d.ts.map +1 -1
  8. package/dist/bound-call.js.map +1 -1
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +56 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/client.d.ts +4 -2
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +4 -2
  16. package/dist/client.js.map +1 -1
  17. package/dist/compatibility.d.ts +16 -0
  18. package/dist/compatibility.d.ts.map +1 -0
  19. package/dist/compatibility.js +4 -0
  20. package/dist/compatibility.js.map +1 -0
  21. package/dist/create-fn.d.ts +30 -34
  22. package/dist/create-fn.d.ts.map +1 -1
  23. package/dist/create-fn.js +177 -121
  24. package/dist/create-fn.js.map +1 -1
  25. package/dist/expo.d.ts +11 -25
  26. package/dist/expo.d.ts.map +1 -1
  27. package/dist/expo.js +25 -30
  28. package/dist/expo.js.map +1 -1
  29. package/dist/hono.d.ts +12 -4
  30. package/dist/hono.d.ts.map +1 -1
  31. package/dist/hono.js +29 -12
  32. package/dist/hono.js.map +1 -1
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/json-schema.d.ts +2 -0
  38. package/dist/json-schema.d.ts.map +1 -1
  39. package/dist/json-schema.js +11 -0
  40. package/dist/json-schema.js.map +1 -1
  41. package/dist/live/codec.d.ts +6 -1
  42. package/dist/live/codec.d.ts.map +1 -1
  43. package/dist/live/codec.js +14 -3
  44. package/dist/live/codec.js.map +1 -1
  45. package/dist/live/fn-live.d.ts +67 -22
  46. package/dist/live/fn-live.d.ts.map +1 -1
  47. package/dist/live/fn-live.js +98 -16
  48. package/dist/live/fn-live.js.map +1 -1
  49. package/dist/live/index.d.ts +1 -1
  50. package/dist/live/index.d.ts.map +1 -1
  51. package/dist/live/index.js.map +1 -1
  52. package/dist/live/ioredis.d.ts +4 -1
  53. package/dist/live/ioredis.d.ts.map +1 -1
  54. package/dist/live/ioredis.js +21 -2
  55. package/dist/live/ioredis.js.map +1 -1
  56. package/dist/live/lifecycle.d.ts +7 -0
  57. package/dist/live/lifecycle.d.ts.map +1 -0
  58. package/dist/live/lifecycle.js +36 -0
  59. package/dist/live/lifecycle.js.map +1 -0
  60. package/dist/live/memory.d.ts.map +1 -1
  61. package/dist/live/memory.js +4 -0
  62. package/dist/live/memory.js.map +1 -1
  63. package/dist/live/pub-sub.d.ts +81 -13
  64. package/dist/live/pub-sub.d.ts.map +1 -1
  65. package/dist/live/pub-sub.js +437 -126
  66. package/dist/live/pub-sub.js.map +1 -1
  67. package/dist/live/redis-bun.d.ts +1 -1
  68. package/dist/live/redis-bun.d.ts.map +1 -1
  69. package/dist/live/redis-bun.js +3 -5
  70. package/dist/live/redis-bun.js.map +1 -1
  71. package/dist/live/redis.d.ts +2 -2
  72. package/dist/live/redis.d.ts.map +1 -1
  73. package/dist/live/redis.js +36 -9
  74. package/dist/live/redis.js.map +1 -1
  75. package/dist/live/transport.d.ts +5 -1
  76. package/dist/live/transport.d.ts.map +1 -1
  77. package/dist/live/transport.js.map +1 -1
  78. package/dist/logger.d.ts +2 -0
  79. package/dist/logger.d.ts.map +1 -1
  80. package/dist/logger.js +21 -0
  81. package/dist/logger.js.map +1 -1
  82. package/dist/mastra.d.ts.map +1 -1
  83. package/dist/mastra.js +16 -7
  84. package/dist/mastra.js.map +1 -1
  85. package/dist/mcp/core.d.ts +41 -0
  86. package/dist/mcp/core.d.ts.map +1 -0
  87. package/dist/mcp/core.js +61 -0
  88. package/dist/mcp/core.js.map +1 -0
  89. package/dist/mcp/sdk.d.ts +12 -0
  90. package/dist/mcp/sdk.d.ts.map +1 -0
  91. package/dist/mcp/sdk.js +14 -0
  92. package/dist/mcp/sdk.js.map +1 -0
  93. package/dist/mcp/server.d.ts +11 -0
  94. package/dist/mcp/server.d.ts.map +1 -0
  95. package/dist/mcp/server.js +13 -0
  96. package/dist/mcp/server.js.map +1 -0
  97. package/dist/mcp.d.ts +3 -2
  98. package/dist/mcp.d.ts.map +1 -1
  99. package/dist/mcp.js +22 -7
  100. package/dist/mcp.js.map +1 -1
  101. package/dist/meta.d.ts +15 -7
  102. package/dist/meta.d.ts.map +1 -1
  103. package/dist/meta.js +9 -2
  104. package/dist/meta.js.map +1 -1
  105. package/dist/otel.d.ts.map +1 -1
  106. package/dist/otel.js +77 -6
  107. package/dist/otel.js.map +1 -1
  108. package/dist/route-options.d.ts +22 -0
  109. package/dist/route-options.d.ts.map +1 -0
  110. package/dist/route-options.js +67 -0
  111. package/dist/route-options.js.map +1 -0
  112. package/dist/router.d.ts +13 -1
  113. package/dist/router.d.ts.map +1 -1
  114. package/dist/router.js +35 -0
  115. package/dist/router.js.map +1 -1
  116. package/dist/timing.d.ts +8 -0
  117. package/dist/timing.d.ts.map +1 -0
  118. package/dist/timing.js +4 -0
  119. package/dist/timing.js.map +1 -0
  120. package/dist/types.d.ts +96 -41
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/types.js +6 -2
  123. package/dist/types.js.map +1 -1
  124. package/package.json +28 -3
  125. package/src/assemble-procedure.ts +42 -0
  126. package/src/bound-call.ts +4 -3
  127. package/src/cli.ts +68 -0
  128. package/src/client.ts +9 -2
  129. package/src/compatibility.ts +39 -0
  130. package/src/create-fn.ts +295 -182
  131. package/src/expo.ts +49 -44
  132. package/src/hono.ts +36 -17
  133. package/src/index.ts +7 -2
  134. package/src/json-schema.ts +16 -0
  135. package/src/live/codec.ts +22 -3
  136. package/src/live/fn-live.ts +248 -69
  137. package/src/live/index.ts +2 -0
  138. package/src/live/ioredis.ts +22 -2
  139. package/src/live/lifecycle.ts +44 -0
  140. package/src/live/memory.ts +4 -0
  141. package/src/live/pub-sub.ts +619 -168
  142. package/src/live/redis-bun.ts +7 -5
  143. package/src/live/redis.ts +37 -11
  144. package/src/live/transport.ts +4 -1
  145. package/src/logger.ts +20 -0
  146. package/src/mastra.ts +15 -7
  147. package/src/mcp/core.ts +102 -0
  148. package/src/mcp/sdk.ts +36 -0
  149. package/src/mcp/server.ts +35 -0
  150. package/src/mcp.ts +48 -20
  151. package/src/meta.ts +40 -24
  152. package/src/otel.ts +77 -10
  153. package/src/route-options.ts +100 -0
  154. package/src/router.ts +58 -1
  155. package/src/timing.ts +5 -0
  156. package/src/types.ts +186 -62
package/src/types.ts CHANGED
@@ -3,7 +3,7 @@ import type {
3
3
  ErrorMap,
4
4
  InferSchemaInput,
5
5
  InferSchemaOutput,
6
- Meta,
6
+ MergedErrorMap,
7
7
  Schema
8
8
  } from '@orpc/contract'
9
9
  import type {
@@ -12,7 +12,9 @@ import type {
12
12
  Procedure,
13
13
  Route
14
14
  } from '@orpc/server'
15
- import type { ZodType, z } from 'zod'
15
+ import type { createORPCErrorConstructorMap } from '@orpc/server'
16
+ import type { StoredFnMeta } from './meta.js'
17
+ import type { NativeErrors, NativeMeta } from './compatibility.js'
16
18
  import type { BoundCall } from './bound-call.js'
17
19
  import type { FnLogger } from './logger.js'
18
20
  import type { SpanLike } from './otel.js'
@@ -93,7 +95,7 @@ export const ROUTE_OPTION_KEYS = [
93
95
  ] as const satisfies readonly (keyof Route)[]
94
96
 
95
97
  /**
96
- * `fn()` option names owned by the route itself. Guard and meta keys must not
98
+ * `fn()` option names owned by the route itself. Guard keys must not
97
99
  * reuse them: such an option would be read as the route option and the guard
98
100
  * would never run.
99
101
  */
@@ -105,12 +107,16 @@ export const RESERVED_OPTION_KEYS = [
105
107
  'output',
106
108
  'handler',
107
109
  'live',
108
- 'operationId'
110
+ 'operationId',
111
+ 'meta',
112
+ 'stream',
113
+ 'errors',
114
+ 'guardResolvers'
109
115
  ] as const
110
116
 
111
117
  export type ReservedOptionKey = (typeof RESERVED_OPTION_KEYS)[number]
112
118
 
113
- /** @internal Builds one route from a `procedures` builder; shared by `fn` and `createPubSub`. */
119
+ /** @internal Builds one route from a selected native procedure builder. */
114
120
  export type BuildProcedure = (options: {
115
121
  name: string
116
122
  procedure: string | undefined
@@ -118,10 +124,14 @@ export type BuildProcedure = (options: {
118
124
  meta: Record<string, unknown>
119
125
  input?: AnySchema | undefined
120
126
  output?: AnySchema | undefined
127
+ stream?: boolean
128
+ errors?: ErrorMap
121
129
  handler: (options: {
122
130
  input: unknown
123
- context: Record<string, unknown>
131
+ context: Record<string | symbol, unknown>
124
132
  signal?: AbortSignal
133
+ lastEventId?: string
134
+ errors: ReturnType<typeof createORPCErrorConstructorMap>
125
135
  }) => unknown
126
136
  }) => AnyProcedure
127
137
 
@@ -130,15 +140,30 @@ export type RejectKeys<T, K extends PropertyKey, TMessage extends string> = {
130
140
  [P in Extract<keyof T, K>]: TMessage
131
141
  }
132
142
 
143
+ /** Params every handler receives; extras may not reuse these names. */
144
+ type HandlerParamKey =
145
+ | 'input'
146
+ | 'context'
147
+ | 'call'
148
+ | 'signal'
149
+ | 'span'
150
+ | 'logger'
151
+ | 'errors'
152
+ | 'lastEventId'
153
+
133
154
  /**
134
155
  * Handler extras must have known keys: an index signature would claim every
135
156
  * handler param. Intersected into `createFn`'s options to reject it.
136
157
  */
137
- export type FiniteExtras<T> = string extends keyof T
138
- ? { extras: 'orpc-fn: extras need known keys, not an index signature' }
139
- : number extends keyof T
158
+ export type FiniteExtras<T> = T extends unknown
159
+ ? string extends keyof T
140
160
  ? { extras: 'orpc-fn: extras need known keys, not an index signature' }
141
- : unknown
161
+ : number extends keyof T
162
+ ? { extras: 'orpc-fn: extras need known keys, not an index signature' }
163
+ : Extract<keyof T, HandlerParamKey> extends never
164
+ ? unknown
165
+ : { extras: 'orpc-fn: extras cannot shadow handler parameters' }
166
+ : never
142
167
 
143
168
  type ProcedureOf<TBuilder> = TBuilder extends {
144
169
  handler(handler: never): infer TProcedure
@@ -162,16 +187,8 @@ export type CurrentContextOf<TBuilder> =
162
187
  ? TContext
163
188
  : never
164
189
 
165
- type ErrorMapOf<TBuilder> =
166
- ProcedureOf<TBuilder> extends {
167
- '~orpc': { errorMap: infer T extends ErrorMap }
168
- }
169
- ? T
170
- : ErrorMap
171
- type MetaOf<TBuilder> =
172
- ProcedureOf<TBuilder> extends { '~orpc': { meta: infer T extends Meta } }
173
- ? T
174
- : Meta
190
+ export type ErrorMapOf<TBuilder> = NativeErrors<ProcedureOf<TBuilder>>
191
+ type MetaOf<TBuilder> = NativeMeta<ProcedureOf<TBuilder>>
175
192
 
176
193
  /**
177
194
  * Everything `createFn` inferred from its options. Route types read from it;
@@ -181,6 +198,7 @@ export type FnDefinition = {
181
198
  procedures: Record<string, BuilderLike>
182
199
  default: string
183
200
  extras: object
201
+ extrasByProcedure?: Partial<Record<string, object>>
184
202
  guards: object
185
203
  meta: object
186
204
  tag: string
@@ -218,7 +236,12 @@ export type GuardParams<TContext, TMeta> = {
218
236
  * `fn({...})`; the guard runs only on routes that set it. Throw (usually an
219
237
  * `ORPCError`) to refuse the call.
220
238
  */
221
- export type Guard<TValue, TParams> = (value: TValue, params: TParams) => unknown
239
+ /* biome-ignore-start lint/suspicious/noConfusingVoidType: union prevents accidental value returns while accepting assertion-style guards */
240
+ export type Guard<TValue, TParams> = (
241
+ value: TValue,
242
+ params: TParams
243
+ ) => MaybePromise<void | boolean>
244
+ /* biome-ignore-end lint/suspicious/noConfusingVoidType: assertion-style guards */
222
245
 
223
246
  export type GuardOptions<TGuards> = {
224
247
  [K in keyof TGuards]?: TGuards[K] extends (
@@ -229,13 +252,28 @@ export type GuardOptions<TGuards> = {
229
252
  : never
230
253
  }
231
254
 
255
+ /** Match object spread: scoped extras replace shared keys, preserving unions. */
256
+ type MergeExtras<TShared, TScoped> = TShared extends unknown
257
+ ? TScoped extends unknown
258
+ ? Omit<TShared, keyof TScoped> & TScoped
259
+ : never
260
+ : never
261
+
232
262
  export type HandlerParams<
233
263
  TDef extends FnDefinition,
234
264
  TInput,
235
- TKey extends ProcedureKey<TDef>
265
+ TKey extends ProcedureKey<TDef>,
266
+ TErrors extends ErrorMap = Record<never, never>
236
267
  > = DistributiveOmit<
237
- TDef['extras'],
238
- 'input' | 'context' | 'call' | 'signal' | 'span' | 'logger'
268
+ MergeExtras<
269
+ TDef['extras'],
270
+ TDef extends { extrasByProcedure: infer E }
271
+ ? TKey extends keyof E
272
+ ? E[TKey]
273
+ : object
274
+ : object
275
+ >,
276
+ HandlerParamKey
239
277
  > & {
240
278
  input: TInput
241
279
  context: FnContext<TDef, TKey>
@@ -246,6 +284,12 @@ export type HandlerParams<
246
284
  /** Active OpenTelemetry span, undefined when `createFn({ otel })` is not set. */
247
285
  span: TDef['span'] | undefined
248
286
  logger: TDef['logger']
287
+ lastEventId: string | undefined
288
+ errors: ReturnType<
289
+ typeof createORPCErrorConstructorMap<
290
+ MergedErrorMap<ErrorMapOf<TDef['procedures'][TKey]>, TErrors>
291
+ >
292
+ >
249
293
  }
250
294
 
251
295
  /** Route options shared by every `fn()` overload. */
@@ -260,11 +304,22 @@ export type RouteConfig<TTag extends string = string> = Pick<
260
304
 
261
305
  export type FnRouteOptions<
262
306
  TDef extends FnDefinition,
263
- TKey extends ProcedureKey<TDef>
307
+ TKey extends ProcedureKey<TDef>,
308
+ TInput = unknown,
309
+ TErrors extends ErrorMap = Record<never, never>
264
310
  > = RouteConfig<TDef['tag']> &
265
- GuardOptions<TDef['guards']> &
266
- TDef['meta'] &
267
- ProcedureOption<TDef, TKey>
311
+ GuardOptions<TDef['guards']> & {
312
+ meta?: TDef['meta']
313
+ stream?: boolean
314
+ errors?: TErrors
315
+ guardResolvers?: {
316
+ [K in keyof TDef['guards']]?: (params: {
317
+ input: TInput
318
+ context: FnContext<TDef, TKey>
319
+ signal: AbortSignal | undefined
320
+ }) => MaybePromise<GuardOptions<TDef['guards']>[K]>
321
+ }
322
+ } & ProcedureOption<TDef, TKey>
268
323
 
269
324
  /**
270
325
  * Which `createFn({ procedures })` builder a route uses. Optional when
@@ -281,97 +336,128 @@ export type FnProcedure<
281
336
  TDef extends FnDefinition,
282
337
  TKey extends ProcedureKey<TDef>,
283
338
  TInputSchema extends Schema<unknown, unknown>,
284
- TOutputSchema extends Schema<unknown, unknown>
339
+ TOutputSchema extends Schema<unknown, unknown>,
340
+ TErrors extends ErrorMap = Record<never, never>
285
341
  > = DecoratedProcedure<
286
342
  InitialContextOf<TDef['procedures'][TKey]>,
287
343
  FnContext<TDef, TKey>,
288
344
  TInputSchema,
289
345
  TOutputSchema,
290
- ErrorMapOf<TDef['procedures'][TKey]>,
291
- MetaOf<TDef['procedures'][TKey]>
346
+ MergedErrorMap<ErrorMapOf<TDef['procedures'][TKey]>, TErrors>,
347
+ MetaOf<TDef['procedures'][TKey]> & {
348
+ 'orpc-fn': StoredFnMeta<TDef['meta'], TKey>
349
+ }
292
350
  >
293
351
 
294
- type InputOf<T> = [T] extends [ZodType] ? z.output<T> : unknown
295
- type ReturnOf<TOut, TReturn> = [TOut] extends [ZodType]
296
- ? z.input<TOut>
352
+ type InputOf<T> = [T] extends [AnySchema] ? InferSchemaOutput<T> : unknown
353
+ type ReturnOf<TOut, TReturn> = [TOut] extends [AnySchema]
354
+ ? InferSchemaInput<TOut>
297
355
  : TReturn
298
356
 
299
357
  /** `fn()`: four overloads for input/output schema × inferred. */
300
358
  export interface Fn<TDef extends FnDefinition> {
301
359
  // 1. With input + output schema
302
360
  <
303
- TInput extends ZodType,
304
- TOut extends ZodType,
305
- TKey extends ProcedureKey<TDef> = TDef['default']
361
+ TInput extends AnySchema,
362
+ TOut extends AnySchema,
363
+ TKey extends ProcedureKey<TDef> = TDef['default'],
364
+ TErrors extends ErrorMap = Record<never, never>
306
365
  >(
307
366
  options: {
308
367
  input: TInput
309
368
  output: TOut
310
369
  // The output schema parses what the handler returns: its input type.
311
370
  handler: (
312
- params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>>
313
- ) => MaybePromise<z.input<TOut>>
314
- } & FnRouteOptions<TDef, TKey>
315
- ): FnProcedure<TDef, TKey, TInput, TOut>
371
+ params: HandlerParams<
372
+ TDef,
373
+ InferSchemaOutput<TInput>,
374
+ NoInfer<TKey>,
375
+ TErrors
376
+ >
377
+ ) => MaybePromise<InferSchemaInput<TOut>>
378
+ } & FnRouteOptions<TDef, TKey, InferSchemaOutput<TInput>, TErrors>
379
+ ): FnProcedure<TDef, TKey, TInput, TOut, TErrors>
316
380
 
317
381
  // 2. With input, inferred output
318
382
  <
319
- TInput extends ZodType,
383
+ TInput extends AnySchema,
320
384
  TReturn,
321
- TKey extends ProcedureKey<TDef> = TDef['default']
385
+ TKey extends ProcedureKey<TDef> = TDef['default'],
386
+ TErrors extends ErrorMap = Record<never, never>
322
387
  >(
323
388
  options: {
324
389
  input: TInput
325
390
  output?: undefined
326
391
  handler: (
327
- params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>>
392
+ params: HandlerParams<
393
+ TDef,
394
+ InferSchemaOutput<TInput>,
395
+ NoInfer<TKey>,
396
+ TErrors
397
+ >
328
398
  ) => MaybePromise<TReturn>
329
- } & FnRouteOptions<TDef, TKey>
330
- ): FnProcedure<TDef, TKey, TInput, Schema<TReturn, TReturn>>
399
+ } & FnRouteOptions<TDef, TKey, InferSchemaOutput<TInput>, TErrors>
400
+ ): FnProcedure<TDef, TKey, TInput, Schema<TReturn, TReturn>, TErrors>
331
401
 
332
402
  // 3. No input, with output schema
333
- <TOut extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default']>(
403
+ <
404
+ TOut extends AnySchema,
405
+ TKey extends ProcedureKey<TDef> = TDef['default'],
406
+ TErrors extends ErrorMap = Record<never, never>
407
+ >(
334
408
  options: {
335
409
  input?: undefined
336
410
  output: TOut
337
411
  handler: (
338
- params: HandlerParams<TDef, unknown, NoInfer<TKey>>
339
- ) => MaybePromise<z.input<TOut>>
340
- } & FnRouteOptions<TDef, TKey>
341
- ): FnProcedure<TDef, TKey, Schema<unknown, unknown>, TOut>
412
+ params: HandlerParams<TDef, unknown, NoInfer<TKey>, TErrors>
413
+ ) => MaybePromise<InferSchemaInput<TOut>>
414
+ } & FnRouteOptions<TDef, TKey, unknown, TErrors>
415
+ ): FnProcedure<TDef, TKey, Schema<unknown, unknown>, TOut, TErrors>
342
416
 
343
417
  // 4. No input, inferred output
344
- <TReturn, TKey extends ProcedureKey<TDef> = TDef['default']>(
418
+ <
419
+ TReturn,
420
+ TKey extends ProcedureKey<TDef> = TDef['default'],
421
+ TErrors extends ErrorMap = Record<never, never>
422
+ >(
345
423
  options: {
346
424
  input?: undefined
347
425
  output?: undefined
348
426
  handler: (
349
- params: HandlerParams<TDef, unknown, NoInfer<TKey>>
427
+ params: HandlerParams<TDef, unknown, NoInfer<TKey>, TErrors>
350
428
  ) => MaybePromise<TReturn>
351
- } & FnRouteOptions<TDef, TKey>
352
- ): FnProcedure<TDef, TKey, Schema<unknown, unknown>, Schema<TReturn, TReturn>>
429
+ } & FnRouteOptions<TDef, TKey, unknown, TErrors>
430
+ ): FnProcedure<
431
+ TDef,
432
+ TKey,
433
+ Schema<unknown, unknown>,
434
+ Schema<TReturn, TReturn>,
435
+ TErrors
436
+ >
353
437
 
354
438
  // 5. Never matches valid code first; it only words the type errors, which
355
439
  // TypeScript reports against the last overload.
356
440
  <
357
441
  TReturn,
358
- TInput extends ZodType | undefined = undefined,
359
- TOut extends ZodType | undefined = undefined,
360
- TKey extends ProcedureKey<TDef> = TDef['default']
442
+ TInput extends AnySchema | undefined = undefined,
443
+ TOut extends AnySchema | undefined = undefined,
444
+ TKey extends ProcedureKey<TDef> = TDef['default'],
445
+ TErrors extends ErrorMap = Record<never, never>
361
446
  >(
362
447
  options: {
363
448
  input?: TInput
364
449
  output?: TOut
365
450
  // The output schema parses what the handler returns: its input type.
366
451
  handler: (
367
- params: HandlerParams<TDef, InputOf<TInput>, NoInfer<TKey>>
452
+ params: HandlerParams<TDef, InputOf<TInput>, NoInfer<TKey>, TErrors>
368
453
  ) => MaybePromise<ReturnOf<TOut, TReturn>>
369
- } & FnRouteOptions<TDef, TKey>
454
+ } & FnRouteOptions<TDef, TKey, InputOf<TInput>, TErrors>
370
455
  ): FnProcedure<
371
456
  TDef,
372
457
  TKey,
373
- [TInput] extends [ZodType] ? TInput : Schema<unknown, unknown>,
374
- [TOut] extends [ZodType] ? TOut : Schema<TReturn, TReturn>
458
+ [TInput] extends [AnySchema] ? TInput : Schema<unknown, unknown>,
459
+ [TOut] extends [AnySchema] ? TOut : Schema<TReturn, TReturn>,
460
+ TErrors
375
461
  >
376
462
  }
377
463
 
@@ -381,9 +467,47 @@ export type FnCompletedEvent<TContext = unknown, TSpan = SpanLike> = {
381
467
  procedure: string
382
468
  durationMs: number
383
469
  success: boolean
470
+ /** False when authentication or input validation prevented handler execution. */
471
+ handlerStarted: boolean
384
472
  error: unknown
385
473
  input: unknown
386
474
  context: TContext
387
475
  span: TSpan | undefined
388
476
  meta: Record<string, unknown>
389
477
  }
478
+
479
+ /** Factory hooks retain the builder key/context relationship. */
480
+ export type ProcedureHookParams<
481
+ TProcedures extends Record<string, BuilderLike>,
482
+ TExtra = object
483
+ > = {
484
+ [K in keyof TProcedures & string]: TExtra & {
485
+ procedure: K
486
+ context: CurrentContextOf<TProcedures[K]>
487
+ }
488
+ }[keyof TProcedures & string]
489
+
490
+ export type CompletedHookEvent<
491
+ TProcedures extends Record<string, BuilderLike>,
492
+ TSpan
493
+ > = {
494
+ [K in keyof TProcedures & string]: Omit<
495
+ FnCompletedEvent<unknown, TSpan>,
496
+ 'context' | 'procedure' | 'handlerStarted'
497
+ > & { procedure: K } & (
498
+ | { handlerStarted: true; context: CurrentContextOf<TProcedures[K]> }
499
+ | { handlerStarted: false; context: InitialContextOf<TProcedures[K]> }
500
+ )
501
+ }[keyof TProcedures & string]
502
+
503
+ /**
504
+ * Intersected into each scoped extras function's return type: rejects index
505
+ * signatures and handler-parameter names at the offending property. A
506
+ * top-level conditional over the whole map broke inference when zero-argument
507
+ * and context-reading functions were mixed.
508
+ */
509
+ export type ScopedExtrasGuard<T> = (string extends keyof T
510
+ ? { 'orpc-fn: scoped extras need finite keys': never }
511
+ : number extends keyof T
512
+ ? { 'orpc-fn: scoped extras need finite keys': never }
513
+ : unknown) & { [K in HandlerParamKey]?: never }