@taserjs/router 0.0.5 → 0.1.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 (68) hide show
  1. package/dist/cjs/builder/app.cjs +5 -0
  2. package/dist/cjs/builder/app.cjs.map +1 -1
  3. package/dist/cjs/builder/app.d.cts +7 -7
  4. package/dist/cjs/builder/factories.cjs +4 -4
  5. package/dist/cjs/builder/factories.cjs.map +1 -1
  6. package/dist/cjs/builder/factories.d.cts +5 -51
  7. package/dist/cjs/builder/route.cjs +22 -1
  8. package/dist/cjs/builder/route.cjs.map +1 -1
  9. package/dist/cjs/builder/route.d.cts +1 -2
  10. package/dist/cjs/builder/router.cjs +3 -5
  11. package/dist/cjs/builder/router.cjs.map +1 -1
  12. package/dist/cjs/builder/router.d.cts +11 -12
  13. package/dist/cjs/define/middleware.cjs +2 -2
  14. package/dist/cjs/define/middleware.cjs.map +1 -1
  15. package/dist/cjs/define/middleware.d.cts +10 -8
  16. package/dist/cjs/index.cjs +0 -12
  17. package/dist/cjs/index.d.cts +4 -4
  18. package/dist/cjs/reply.cjs +8 -19
  19. package/dist/cjs/reply.d.cts +1 -2
  20. package/dist/cjs/stream.cjs +8 -31
  21. package/dist/cjs/stream.d.cts +1 -1
  22. package/dist/cjs/types/app.d.cts +3 -21
  23. package/dist/cjs/types/index.d.cts +29 -7
  24. package/dist/cjs/types/returns.d.cts +6 -9
  25. package/dist/cjs/types/type-utils.d.cts +7 -5
  26. package/dist/cjs/types/units.cjs.map +1 -1
  27. package/dist/cjs/types/units.d.cts +4 -10
  28. package/dist/esm/builder/app.d.ts +7 -7
  29. package/dist/esm/builder/app.js +5 -1
  30. package/dist/esm/builder/app.js.map +1 -1
  31. package/dist/esm/builder/factories.d.ts +5 -51
  32. package/dist/esm/builder/factories.js +4 -4
  33. package/dist/esm/builder/factories.js.map +1 -1
  34. package/dist/esm/builder/route.d.ts +1 -2
  35. package/dist/esm/builder/route.js +22 -1
  36. package/dist/esm/builder/route.js.map +1 -1
  37. package/dist/esm/builder/router.d.ts +11 -12
  38. package/dist/esm/builder/router.js +3 -5
  39. package/dist/esm/builder/router.js.map +1 -1
  40. package/dist/esm/define/middleware.d.ts +10 -8
  41. package/dist/esm/define/middleware.js +2 -2
  42. package/dist/esm/define/middleware.js.map +1 -1
  43. package/dist/esm/index.d.ts +4 -4
  44. package/dist/esm/index.js +2 -2
  45. package/dist/esm/reply.d.ts +1 -2
  46. package/dist/esm/reply.js +1 -2
  47. package/dist/esm/stream.d.ts +1 -1
  48. package/dist/esm/stream.js +1 -2
  49. package/dist/esm/types/app.d.ts +3 -21
  50. package/dist/esm/types/index.d.ts +29 -7
  51. package/dist/esm/types/returns.d.ts +6 -9
  52. package/dist/esm/types/type-utils.d.ts +7 -5
  53. package/dist/esm/types/units.d.ts +4 -10
  54. package/dist/esm/types/units.js.map +1 -1
  55. package/package.json +3 -3
  56. package/src/builder/app.ts +16 -5
  57. package/src/builder/factories.ts +28 -155
  58. package/src/builder/route.ts +25 -1
  59. package/src/builder/router.ts +24 -157
  60. package/src/define/middleware.ts +115 -123
  61. package/src/index.ts +5 -9
  62. package/src/reply.ts +1 -11
  63. package/src/stream.ts +1 -1
  64. package/src/types/app.ts +3 -22
  65. package/src/types/index.ts +83 -13
  66. package/src/types/returns.ts +7 -76
  67. package/src/types/type-utils.ts +9 -4
  68. package/src/types/units.ts +34 -10
@@ -3,8 +3,7 @@ import { createTaserCompatHandler, type Awaitable } from "@taserjs/router-core";
3
3
  import type { ReturnsMap } from "../types/returns.js";
4
4
  import type {
5
5
  AppContext,
6
- ExtractState,
7
- IsUnknown,
6
+ DefineMiddlewareResult,
8
7
  MiddlewareReturnFromParts,
9
8
  MiddlewareUnit,
10
9
  NextFn,
@@ -17,9 +16,9 @@ import type {
17
16
  } from "../types/index.js";
18
17
  import type { Schema } from "../types/schema.js";
19
18
 
20
- type HonoMiddlewareHandler = Parameters<typeof createTaserCompatHandler>[0];
19
+ export type HonoMiddlewareHandler = Parameters<typeof createTaserCompatHandler>[0];
21
20
 
22
- type HonoMiddlewareUnit = MiddlewareUnit<
21
+ export type HonoMiddlewareUnit = MiddlewareUnit<
23
22
  MiddlewareReturnFromParts<unknown, unknown, unknown, {}>,
24
23
  {},
25
24
  null,
@@ -109,145 +108,137 @@ export type MultiScopedMiddlewareOptions<
109
108
  ) => Awaitable<R>;
110
109
  };
111
110
 
112
- export function defineMiddleware(middleware: HonoMiddlewareHandler): HonoMiddlewareUnit;
111
+ export interface DefineMiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {
112
+ (middleware: HonoMiddlewareHandler): HonoMiddlewareUnit;
113
113
 
114
- export function defineMiddleware<
115
- const Layout extends LayoutId,
116
- TState = unknown,
117
- TRequires = {},
118
- TAppContext extends Record<string, unknown> = AppContext,
119
- TQuery = unknown,
120
- TParams = unknown,
121
- TBody = unknown,
122
- TReturns extends ReturnsMap = {},
123
- TQueryIn = unknown,
124
- TParamsIn = unknown,
125
- TBodyIn = unknown,
126
- R = unknown,
127
- >(
128
- layout: Layout,
129
- options: ScopedMiddlewareOptions<
130
- Layout,
131
- TState,
132
- TRequires,
114
+ <
115
+ const Layout extends LayoutId,
116
+ TState = unknown,
117
+ TRequires = {},
118
+ TQuery = unknown,
119
+ TParams = unknown,
120
+ TBody = unknown,
121
+ TReturns extends ReturnsMap = {},
122
+ TQueryIn = unknown,
123
+ TParamsIn = unknown,
124
+ TBodyIn = unknown,
125
+ R = unknown,
126
+ >(
127
+ layout: Layout,
128
+ options: ScopedMiddlewareOptions<
129
+ Layout,
130
+ TState,
131
+ TRequires,
132
+ TQuery,
133
+ TParams,
134
+ TBody,
135
+ TReturns,
136
+ TQueryIn,
137
+ TParamsIn,
138
+ TBodyIn,
139
+ TAppContext,
140
+ R
141
+ >,
142
+ ): DefineMiddlewareResult<
133
143
  TQuery,
134
144
  TParams,
135
145
  TBody,
136
- TReturns,
146
+ TState,
147
+ R,
137
148
  TQueryIn,
138
149
  TParamsIn,
139
150
  TBodyIn,
140
- TAppContext,
141
- R
142
- >,
143
- ): MiddlewareUnit<
144
- MiddlewareReturnFromParts<
145
- TQuery,
146
- TParams,
147
- TBody,
148
- IsUnknown<TState> extends true ? ExtractState<R> : TState,
149
- TQueryIn,
150
- TParamsIn,
151
- TBodyIn
152
- >,
153
- TReturns,
154
- Layout,
155
- TRequires
156
- >;
151
+ TReturns,
152
+ Layout,
153
+ TRequires
154
+ >;
157
155
 
158
- export function defineMiddleware<
159
- const Layouts extends readonly [LayoutId, ...LayoutId[]],
160
- TState = unknown,
161
- TRequires = {},
162
- TAppContext extends Record<string, unknown> = AppContext,
163
- TQuery = unknown,
164
- TParams = unknown,
165
- TBody = unknown,
166
- TReturns extends ReturnsMap = {},
167
- TQueryIn = unknown,
168
- TParamsIn = unknown,
169
- TBodyIn = unknown,
170
- R = unknown,
171
- >(
172
- layouts: Layouts,
173
- options: MultiScopedMiddlewareOptions<
174
- Layouts,
175
- TState,
176
- TRequires,
156
+ <
157
+ const Layouts extends readonly [LayoutId, ...LayoutId[]],
158
+ TState = unknown,
159
+ TRequires = {},
160
+ TQuery = unknown,
161
+ TParams = unknown,
162
+ TBody = unknown,
163
+ TReturns extends ReturnsMap = {},
164
+ TQueryIn = unknown,
165
+ TParamsIn = unknown,
166
+ TBodyIn = unknown,
167
+ R = unknown,
168
+ >(
169
+ layouts: Layouts,
170
+ options: MultiScopedMiddlewareOptions<
171
+ Layouts,
172
+ TState,
173
+ TRequires,
174
+ TQuery,
175
+ TParams,
176
+ TBody,
177
+ TReturns,
178
+ TQueryIn,
179
+ TParamsIn,
180
+ TBodyIn,
181
+ TAppContext,
182
+ R
183
+ >,
184
+ ): DefineMiddlewareResult<
177
185
  TQuery,
178
186
  TParams,
179
187
  TBody,
180
- TReturns,
188
+ TState,
189
+ R,
181
190
  TQueryIn,
182
191
  TParamsIn,
183
192
  TBodyIn,
184
- TAppContext,
185
- R
186
- >,
187
- ): MiddlewareUnit<
188
- MiddlewareReturnFromParts<
189
- TQuery,
190
- TParams,
191
- TBody,
192
- IsUnknown<TState> extends true ? ExtractState<R> : TState,
193
- TQueryIn,
194
- TParamsIn,
195
- TBodyIn
196
- >,
197
- TReturns,
198
- Layouts,
199
- TRequires
200
- >;
193
+ TReturns,
194
+ Layouts,
195
+ TRequires
196
+ >;
201
197
 
202
- export function defineMiddleware<
203
- TState = unknown,
204
- TRequires = {},
205
- TAppContext extends Record<string, unknown> = AppContext,
206
- TQuery = unknown,
207
- TParams = unknown,
208
- TBody = unknown,
209
- TReturns extends ReturnsMap = {},
210
- TQueryIn = unknown,
211
- TParamsIn = unknown,
212
- TBodyIn = unknown,
213
- R = unknown,
214
- >(
215
- options: DefineMiddlewareOptions<
216
- TState,
217
- TRequires,
198
+ <
199
+ TState = unknown,
200
+ TRequires = {},
201
+ TQuery = unknown,
202
+ TParams = unknown,
203
+ TBody = unknown,
204
+ TReturns extends ReturnsMap = {},
205
+ TQueryIn = unknown,
206
+ TParamsIn = unknown,
207
+ TBodyIn = unknown,
208
+ R = unknown,
209
+ >(
210
+ options: DefineMiddlewareOptions<
211
+ TState,
212
+ TRequires,
213
+ TQuery,
214
+ TParams,
215
+ TBody,
216
+ TReturns,
217
+ TQueryIn,
218
+ TParamsIn,
219
+ TBodyIn,
220
+ TAppContext,
221
+ R
222
+ >,
223
+ ): DefineMiddlewareResult<
218
224
  TQuery,
219
225
  TParams,
220
226
  TBody,
221
- TReturns,
227
+ TState,
228
+ R,
222
229
  TQueryIn,
223
230
  TParamsIn,
224
231
  TBodyIn,
225
- TAppContext,
226
- R
227
- >,
228
- ): MiddlewareUnit<
229
- MiddlewareReturnFromParts<
230
- TQuery,
231
- TParams,
232
- TBody,
233
- IsUnknown<TState> extends true ? ExtractState<R> : TState,
234
- TQueryIn,
235
- TParamsIn,
236
- TBodyIn
237
- >,
238
- TReturns,
239
- null,
240
- TRequires
241
- >;
232
+ TReturns,
233
+ null,
234
+ TRequires
235
+ >;
236
+ }
242
237
 
243
- export function defineMiddleware(
244
- first:
245
- | string
246
- | readonly string[]
247
- | HonoMiddlewareHandler
248
- | DefineMiddlewareOptions<any, any, any, any, any, any, any, any, any, any, any>,
249
- second?: DefineMiddlewareOptions<any, any, any, any, any, any, any, any, any, any, any>,
250
- ): unknown {
238
+ export const defineMiddleware: DefineMiddlewareFn<AppContext> = function defineMiddleware(
239
+ first: any,
240
+ second?: any,
241
+ ): any {
251
242
  if (typeof first === "string" || Array.isArray(first)) {
252
243
  const options = second!;
253
244
  const unit = {
@@ -262,7 +253,8 @@ export function defineMiddleware(
262
253
  if (typeof first === "function") {
263
254
  const honoMiddleware = first as HonoMiddlewareHandler;
264
255
  return defineMiddleware({
265
- handler: (ctx, next) => createTaserCompatHandler(honoMiddleware)(ctx, next),
256
+ handler: (ctx: unknown, next: (state?: Record<string, unknown>) => unknown) =>
257
+ createTaserCompatHandler(honoMiddleware)(ctx, next),
266
258
  });
267
259
  }
268
260
 
@@ -286,4 +278,4 @@ export function defineMiddleware(
286
278
  };
287
279
 
288
280
  return unit;
289
- }
281
+ };
package/src/index.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  export type { RouterRegister } from "./register.js";
2
2
  export type {
3
+ HttpMethod,
3
4
  InferInput,
4
5
  InferOutput,
5
6
  InferRouteContext,
6
7
  InferRouteInput,
7
8
  InferRouteOutput,
8
9
  Method,
10
+ MiddlewareDefinition,
9
11
  PathParams,
10
12
  ReturnsMap,
11
13
  RouteDefinition,
@@ -13,6 +15,7 @@ export type {
13
15
  RoutePath,
14
16
  Schema,
15
17
  Simplify,
18
+ StatusCode,
16
19
  } from "./types/index.js";
17
20
  export type {
18
21
  ContextDefinition,
@@ -21,17 +24,10 @@ export type {
21
24
  InferAppManifest,
22
25
  OnErrorOptions,
23
26
  RouteManifestShape,
24
- TaserHandler,
25
27
  } from "./types/app.js";
26
28
 
27
- export { reply, stream, ValidationError, validationErrorSchema } from "@taserjs/router-utils";
28
- export type {
29
- ReplyBodyKind,
30
- ReplyOf,
31
- ResponseValidationFailureHandler,
32
- SuccessReplyData,
33
- SuccessStatusCode,
34
- } from "@taserjs/router-utils";
29
+ export { ValidationError, validationErrorSchema } from "@taserjs/router-utils";
30
+ export type { ResponseValidationFailureHandler, SuccessStatusCode } from "@taserjs/router-utils";
35
31
 
36
32
  export { createTaserApp, TaserRouter } from "./builder/router.js";
37
33
  export { TaserApp } from "./builder/app.js";
package/src/reply.ts CHANGED
@@ -1,11 +1 @@
1
- export { errorReply, reply, successReply } from "@taserjs/router-utils/reply";
2
- export type {
3
- BinaryBody,
4
- BodyKind,
5
- FileReplyInit,
6
- RedirectInit,
7
- ReplyBodyKind,
8
- ReplyInit,
9
- ReplyOf,
10
- SuccessReplyData,
11
- } from "@taserjs/router-utils/reply";
1
+ export * from "@taserjs/router-utils/reply";
package/src/stream.ts CHANGED
@@ -1 +1 @@
1
- export { blob, buffer, file, pipe, stream } from "@taserjs/router-utils";
1
+ export * from "@taserjs/router-utils/stream";
package/src/types/app.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RouteManifestShape } from "@taserjs/router-core";
1
+ import type { CookieRuntimeConfig, RouteManifestShape } from "@taserjs/router-core";
2
2
  import type { ResponseValidationFailureHandler } from "@taserjs/router-utils";
3
3
 
4
4
  import type { TaserApp } from "../builder/app.js";
@@ -6,23 +6,13 @@ import type { ReturnsMap } from "./returns.js";
6
6
  import type { Schema } from "./schema.js";
7
7
 
8
8
  export type CreateTaserAppOptions = {
9
- basePath?: string;
10
9
  response?: {
11
10
  /** Validate handler replies against returns maps. Default true. */
12
11
  validate?: boolean;
13
12
  onValidationFailure?: ResponseValidationFailureHandler;
14
13
  };
15
14
  /** Global cookie defaults and signing secret. Per-call `ctx.cookies.set` options override defaults. */
16
- cookies?: {
17
- secret?: string | BufferSource;
18
- path?: string;
19
- httpOnly?: boolean;
20
- sameSite?: "Strict" | "Lax" | "None" | "strict" | "lax" | "none";
21
- secure?: boolean;
22
- domain?: string;
23
- maxAge?: number;
24
- expires?: Date;
25
- };
15
+ cookies?: CookieRuntimeConfig;
26
16
  };
27
17
 
28
18
  export type ContextDefinition<
@@ -43,7 +33,7 @@ export type OnErrorOptions<TResponses extends ReturnsMap = ReturnsMap> = {
43
33
  };
44
34
 
45
35
  export type InferAppManifest<TApp> =
46
- TApp extends TaserApp<infer TManifest>
36
+ TApp extends TaserApp<infer TManifest, any>
47
37
  ? TManifest
48
38
  : TApp extends { manifest: infer TManifest }
49
39
  ? TManifest
@@ -51,15 +41,6 @@ export type InferAppManifest<TApp> =
51
41
  ? TApp
52
42
  : never;
53
43
 
54
- export type TaserHandler<TFrameworkApp> = {
55
- /**
56
- * Mount the Taser handler on a framework app.
57
- * Use universal wildcard patterns (`/*`, `/prefix/*`) for Hono/Fastify.
58
- * Use framework-native splat patterns for Express (e.g. `/{*splat}`, `/*splat`).
59
- */
60
- mount(pattern: string, frameworkApp: TFrameworkApp): void;
61
- };
62
-
63
44
  export type { RouteManifestShape } from "@taserjs/router-core";
64
45
 
65
46
  export type { Schema };
@@ -5,9 +5,9 @@ import type {
5
5
  MergeMiddlewareInputField,
6
6
  MergePart,
7
7
  RequestShape,
8
- RuntimeContextFields,
9
8
  Simplify,
10
9
  UnionToIntersection,
10
+ UnitRuntimeContext,
11
11
  } from "./type-utils.js";
12
12
  import type { ReturnsMap, ValidHandlerReply } from "./returns.js";
13
13
  import type { Schema } from "./schema.js";
@@ -39,6 +39,7 @@ export type {
39
39
  MergePart,
40
40
  RequestShape,
41
41
  Simplify,
42
+ UnitRuntimeContext,
42
43
  UnwrapPart,
43
44
  } from "./type-utils.js";
44
45
  export type {
@@ -167,13 +168,29 @@ type RouteLayoutChain<Path extends RoutePath, TMethod extends Method> =
167
168
  ? readonly [RouteParent<Path, TMethod>]
168
169
  : readonly [];
169
170
 
171
+ export type RouteLayoutMiddlewares<
172
+ Path extends RoutePath,
173
+ TMethod extends Method,
174
+ > = ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>;
175
+
176
+ export type RouteLayoutField<
177
+ Path extends RoutePath,
178
+ TMethod extends Method,
179
+ Field extends "query" | "params" | "body" | "state",
180
+ > = MergeMiddlewareField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
181
+
182
+ export type RouteLayoutInputField<
183
+ Path extends RoutePath,
184
+ TMethod extends Method,
185
+ Field extends "query" | "params" | "body",
186
+ > = MergeMiddlewareInputField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
187
+
170
188
  type RouteResolvedField<
171
189
  Path extends RoutePath,
172
190
  TMethod extends Method,
173
191
  Acc extends readonly unknown[],
174
192
  Field extends "query" | "params" | "body" | "state",
175
- > = MergeMiddlewareField<ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>, Field> &
176
- MergeMiddlewareField<Acc, Field>;
193
+ > = RouteLayoutField<Path, TMethod, Field> & MergeMiddlewareField<Acc, Field>;
177
194
 
178
195
  type RouteChainField<
179
196
  Path extends RoutePath,
@@ -182,8 +199,6 @@ type RouteChainField<
182
199
  Field extends "query" | "params" | "body" | "state",
183
200
  > = RouteResolvedField<Path, TMethod, Acc, Field>;
184
201
 
185
- type UnitRuntimeContext = Omit<RuntimeContextFields, "var">;
186
-
187
202
  export type RouteChainContext<
188
203
  Path extends RoutePath,
189
204
  TMethod extends Method,
@@ -292,11 +307,7 @@ type RouteResolvedInputField<
292
307
  TMethod extends Method,
293
308
  Acc extends readonly unknown[],
294
309
  Field extends "query" | "params" | "body",
295
- > = MergeMiddlewareInputField<
296
- ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>,
297
- Field
298
- > &
299
- MergeMiddlewareInputField<Acc, Field>;
310
+ > = RouteLayoutInputField<Path, TMethod, Field> & MergeMiddlewareInputField<Acc, Field>;
300
311
 
301
312
  type IsNever<T> = [T] extends [never] ? true : false;
302
313
 
@@ -414,12 +425,16 @@ export type InferRouteInputFromPath<Path extends RoutePath, TMethod extends Meth
414
425
  : never
415
426
  : never;
416
427
 
428
+ export type MiddlewareLayoutField<
429
+ Layout extends LayoutId,
430
+ Field extends "query" | "params" | "body" | "state",
431
+ > = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field>;
432
+
417
433
  type MiddlewareChainField<
418
434
  Layout extends LayoutId,
419
435
  Acc extends readonly unknown[],
420
436
  Field extends "query" | "params" | "body" | "state",
421
- > = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field> &
422
- MergeMiddlewareField<Acc, Field>;
437
+ > = MiddlewareLayoutField<Layout, Field> & MergeMiddlewareField<Acc, Field>;
423
438
 
424
439
  export type MiddlewareChainContext<
425
440
  Layout extends LayoutId,
@@ -519,6 +534,7 @@ export type RouteExport<
519
534
  readonly middlewares: readonly MiddlewareDefinition[];
520
535
  readonly handlerMiddlewares: readonly MiddlewareDefinition[];
521
536
  readonly returns?: TReturns;
537
+ readonly bodyMode?: "json" | "form" | "urlencoded";
522
538
  handler: (ctx: unknown) => Awaitable<Response>;
523
539
  readonly $Infer: {
524
540
  Context: TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS"
@@ -557,7 +573,7 @@ type RouteHandleResult<
557
573
  };
558
574
  };
559
575
 
560
- export type RouteBuilder<
576
+ export type RouteBuilderBase<
561
577
  Path extends RoutePath,
562
578
  TMethod extends Method,
563
579
  Acc extends readonly unknown[] = readonly [],
@@ -576,6 +592,26 @@ export type RouteBuilder<
576
592
  : RouteHandleInput<Path, TMethod, Acc, Validators>;
577
593
  Output: TReturns;
578
594
  };
595
+ query<TQuery, TQueryIn = unknown>(
596
+ schema: Schema<TQuery, TQueryIn>,
597
+ ): RouteBuilder<
598
+ Path,
599
+ TMethod,
600
+ Acc,
601
+ Omit<Validators, "query" | "queryIn"> & { query: TQuery; queryIn: TQueryIn },
602
+ TReturns,
603
+ TAppContext
604
+ >;
605
+ params<TParams, TParamsIn = unknown>(
606
+ schema: Schema<TParams, TParamsIn>,
607
+ ): RouteBuilder<
608
+ Path,
609
+ TMethod,
610
+ Acc,
611
+ Omit<Validators, "params" | "paramsIn"> & { params: TParams; paramsIn: TParamsIn },
612
+ TReturns,
613
+ TAppContext
614
+ >;
579
615
  returns<const M extends ReturnsMap>(
580
616
  map: M,
581
617
  ): RouteBuilder<Path, TMethod, Acc, Validators, Omit<TReturns, keyof M> & M, TAppContext>;
@@ -676,6 +712,40 @@ export type RouteBuilder<
676
712
  >;
677
713
  };
678
714
 
715
+ export type RouteBuilder<
716
+ Path extends RoutePath,
717
+ TMethod extends Method,
718
+ Acc extends readonly unknown[] = readonly [],
719
+ Validators extends ValidatorParts = {},
720
+ TReturns extends ReturnsMap = {},
721
+ TAppContext extends Record<string, unknown> = AppContext,
722
+ > = RouteBuilderBase<Path, TMethod, Acc, Validators, TReturns, TAppContext> &
723
+ (TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS"
724
+ ? {}
725
+ : {
726
+ body<TBody, TBodyIn = unknown>(
727
+ schema: Schema<TBody, TBodyIn>,
728
+ ): RouteBuilder<
729
+ Path,
730
+ TMethod,
731
+ Acc,
732
+ Omit<Validators, "body" | "bodyIn"> & { body: TBody; bodyIn: TBodyIn },
733
+ TReturns,
734
+ TAppContext
735
+ >;
736
+ body<Mode extends "json" | "form" | "urlencoded", TBody, TBodyIn = unknown>(
737
+ mode: Mode,
738
+ schema: Schema<TBody, TBodyIn>,
739
+ ): RouteBuilder<
740
+ Path,
741
+ TMethod,
742
+ Acc,
743
+ Omit<Validators, "body" | "bodyIn"> & { body: TBody; bodyIn: TBodyIn },
744
+ TReturns,
745
+ TAppContext
746
+ >;
747
+ });
748
+
679
749
  export type HandlerBuilder<
680
750
  Acc extends readonly unknown[] = readonly [],
681
751
  Validators extends ValidatorParts = {},
@@ -1,82 +1,15 @@
1
- import type { ReplyOf } from "@taserjs/router-utils";
1
+ import type { ReplyOf } from "@taserjs/router-utils/reply";
2
+ import type { StatusCode } from "@taserjs/router-utils";
2
3
 
3
4
  import type { Simplify } from "./type-utils.js";
4
5
  import type { Schema } from "./schema.js";
5
6
  import type { InferOutput } from "./schema.js";
6
7
 
7
- /**
8
- * Known HTTP status codes. `number & {}` allows custom codes while keeping
9
- * literal autocomplete / inference for well-known values.
10
- */
11
- export type StatusCode =
12
- | 100
13
- | 101
14
- | 102
15
- | 103
16
- | 200
17
- | 201
18
- | 202
19
- | 203
20
- | 204
21
- | 205
22
- | 206
23
- | 207
24
- | 208
25
- | 226
26
- | 300
27
- | 301
28
- | 302
29
- | 303
30
- | 304
31
- | 305
32
- | 306
33
- | 307
34
- | 308
35
- | 400
36
- | 401
37
- | 402
38
- | 403
39
- | 404
40
- | 405
41
- | 406
42
- | 407
43
- | 408
44
- | 409
45
- | 410
46
- | 411
47
- | 412
48
- | 413
49
- | 414
50
- | 415
51
- | 416
52
- | 417
53
- | 418
54
- | 421
55
- | 422
56
- | 423
57
- | 424
58
- | 425
59
- | 426
60
- | 428
61
- | 429
62
- | 431
63
- | 451
64
- | 500
65
- | 501
66
- | 502
67
- | 503
68
- | 504
69
- | 505
70
- | 506
71
- | 507
72
- | 508
73
- | 510
74
- | 511
75
- | (number & {});
8
+ export type { StatusCode };
76
9
 
77
10
  /** Status-code → Standard Schema map for route/middleware/handler outputs. */
78
11
  export type ReturnsMap = {
79
- readonly [K in StatusCode]?: Schema<unknown>;
12
+ readonly [status: number]: Schema<unknown> | undefined;
80
13
  };
81
14
 
82
15
  /** Later map wins on overlapping status keys. */
@@ -84,12 +17,10 @@ export type MergeReturns<A extends ReturnsMap, B extends ReturnsMap> = Omit<A, k
84
17
 
85
18
  /** Typed reply union for statuses declared in a returns map. */
86
19
  export type ReplyFor<M extends ReturnsMap> = {
87
- [S in keyof M]-?: S extends StatusCode
88
- ? M[S] extends Schema<unknown>
89
- ? ReplyOf<S, Simplify<InferOutput<M[S]>>>
90
- : never
20
+ [S in keyof M & number]: M[S] extends Schema<unknown>
21
+ ? ReplyOf<S, Simplify<InferOutput<M[S]>>>
91
22
  : never;
92
- }[keyof M];
23
+ }[keyof M & number];
93
24
 
94
25
  export type EmptyReturns = {};
95
26