@taserjs/router 0.1.6 → 0.1.8

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 (39) hide show
  1. package/dist/cjs/builder/factories.cjs +2 -0
  2. package/dist/cjs/builder/factories.cjs.map +1 -1
  3. package/dist/cjs/builder/factories.d.cts +2 -1
  4. package/dist/cjs/builder/standalone.cjs +3 -0
  5. package/dist/cjs/builder/standalone.cjs.map +1 -1
  6. package/dist/cjs/builder/standalone.d.cts +2 -0
  7. package/dist/cjs/define/middleware.cjs.map +1 -1
  8. package/dist/cjs/define/middleware.d.cts +20 -20
  9. package/dist/cjs/index.cjs +1 -0
  10. package/dist/cjs/index.d.cts +6 -2
  11. package/dist/cjs/middleware/hono-mw.cjs.map +1 -1
  12. package/dist/cjs/middleware/hono-mw.d.cts +2 -1
  13. package/dist/cjs/types/index.d.cts +90 -64
  14. package/dist/cjs/types/type-utils.d.cts +3 -3
  15. package/dist/cjs/types/units.d.cts +26 -20
  16. package/dist/esm/builder/factories.d.ts +2 -1
  17. package/dist/esm/builder/factories.js +2 -1
  18. package/dist/esm/builder/factories.js.map +1 -1
  19. package/dist/esm/builder/standalone.d.ts +2 -0
  20. package/dist/esm/builder/standalone.js +4 -2
  21. package/dist/esm/builder/standalone.js.map +1 -1
  22. package/dist/esm/define/middleware.d.ts +20 -20
  23. package/dist/esm/define/middleware.js.map +1 -1
  24. package/dist/esm/index.d.ts +6 -2
  25. package/dist/esm/index.js +2 -2
  26. package/dist/esm/middleware/hono-mw.d.ts +2 -1
  27. package/dist/esm/middleware/hono-mw.js.map +1 -1
  28. package/dist/esm/types/index.d.ts +90 -64
  29. package/dist/esm/types/type-utils.d.ts +3 -3
  30. package/dist/esm/types/units.d.ts +26 -20
  31. package/package.json +3 -3
  32. package/src/builder/factories.ts +3 -2
  33. package/src/builder/standalone.ts +5 -0
  34. package/src/define/middleware.ts +68 -60
  35. package/src/index.ts +4 -0
  36. package/src/middleware/hono-mw.ts +5 -3
  37. package/src/types/index.ts +215 -130
  38. package/src/types/type-utils.ts +1 -1
  39. package/src/types/units.ts +47 -22
@@ -1,14 +1,14 @@
1
1
  import { Awaitable, TaserCookieJar, TaserHeaders } from '@taserjs/router-core';
2
- import { RouterRegister } from '../index.js';
2
+ import { RouterMiddlewaresRegister, RouterRegister, RouterRoutesRegister } from '../index.js';
3
3
  import { MergeMiddlewareField, MergeMiddlewareInputField, MergePart, RequestShape, Simplify, UnionToIntersection, UnitRuntimeContext } from './type-utils.js';
4
4
  import { ReturnsMap, ValidHandlerReply } from './returns.js';
5
5
  import { Schema } from './schema.js';
6
- import { EmptyAppContext, ExtractState, Method, MiddlewareDefinition, MiddlewareReturnFromParts, MiddlewareUnit, NextFn, ValidatorParts } from './units.js';
6
+ import { EmptyAppContext, ExtractState, Method, MiddlewareDefinition, MiddlewareRequirements, MiddlewareReturnFromParts, MiddlewareUnit, NextFn, ValidatorParts } from './units.js';
7
7
  export type { Awaitable } from '@taserjs/router-core';
8
8
  export type { SchemaRequestShape, InferInput, InferOutput, Schema, StandardSchemaV1, } from './schema.js';
9
9
  export type { MergeMiddlewareField, MergeMiddlewareInputField, MergePart, RequestShape, Simplify, UnitRuntimeContext, UnwrapPart, } from './type-utils.js';
10
10
  export type { EmptyReturns, EnforceHandlerReply, HandlerReply, HasReturns, MergeReturns, ReplyFor, ReturnsMap, StatusCode, ValidHandlerReply, } from './returns.js';
11
- export type { EmptyAppContext, ExtractState, HttpMethod, IsUnknown, Method, MiddlewareDefinition, MiddlewareReturnFromParts, MiddlewareUnit, MiddlewareUnitBuilder, NextFn, NextResult, StandaloneMiddlewareContext, StateBrand, ValidatorParts, } from './units.js';
11
+ export type { EmptyAppContext, ExtractState, HttpMethod, IsUnknown, Method, MiddlewareDefinition, MiddlewareRequirements, MiddlewareReturnFromParts, MiddlewareUnit, MiddlewareUnitBuilder, NextFn, NextResult, StandaloneMiddlewareContext, StateBrand, ValidatorParts, } from './units.js';
12
12
  export type AppContext = RouterRegister extends {
13
13
  AppContext: infer C;
14
14
  } ? C : EmptyAppContext;
@@ -21,7 +21,14 @@ export type LayoutId = RouterRegister extends {
21
21
  export type LayoutTree = RouterRegister extends {
22
22
  LayoutTree: infer T;
23
23
  } ? T : Record<never, never>;
24
- export type RouteByPathMethod = RouterRegister extends {
24
+ export type LayoutMiddlewaresMap = RouterMiddlewaresRegister extends {
25
+ LayoutMiddlewares: infer M;
26
+ } ? M : RouterRegister extends {
27
+ LayoutMiddlewares: infer M;
28
+ } ? M : Record<never, never>;
29
+ export type RouteByPathMethod = RouterRoutesRegister extends {
30
+ RouteByPathMethod: infer R;
31
+ } ? R : RouterRegister extends {
25
32
  RouteByPathMethod: infer R;
26
33
  } ? R : Record<never, never>;
27
34
  export type LayoutBuilder<TAppContext extends Record<string, unknown> = AppContext> = <const Layout extends LayoutId>(layout: Layout) => MiddlewareBuilder<Layout, readonly [], TAppContext>;
@@ -33,19 +40,16 @@ type ParseParam<Segment extends string> = Segment extends "*" ? {
33
40
  type ParseParamsFromSegments<S extends string> = S extends `${infer Segment}/${infer Rest}` ? ParseParam<Segment> & ParseParamsFromSegments<Rest> : ParseParam<S>;
34
41
  export type PathParams<Path extends string> = Path extends `/${infer Rest}` ? ParseParamsFromSegments<Rest> : {};
35
42
  export type ResolveParams<TPathParams, TSchemaParams> = TSchemaParams extends Record<string, unknown> ? [keyof TSchemaParams] extends [never] ? TPathParams : Simplify<Omit<TPathParams, keyof TSchemaParams> & TSchemaParams> : TPathParams;
36
- type LayoutParentsMap = RouterRegister extends {
37
- LayoutParents: infer LP extends Record<string, unknown>;
38
- } ? LP : {};
39
- type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutParentsMap ? LayoutParentsMap[Layout] extends LayoutId ? LayoutParentsMap[Layout] : null : LayoutTree[Layout] extends {
40
- parent: infer Parent extends LayoutId | null;
41
- } ? Parent : null;
42
- type LayoutMiddlewares<Layout extends LayoutId> = LayoutTree[Layout]["middlewares"] extends {
43
+ type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutTree ? LayoutTree[Layout] extends {
44
+ parent: infer P extends LayoutId;
45
+ } ? P : null : null;
46
+ type LayoutMiddlewares<Layout extends LayoutId> = [Layout] extends [keyof LayoutMiddlewaresMap] ? LayoutMiddlewaresMap[Layout] extends {
43
47
  readonly __acc?: infer Acc extends readonly unknown[];
44
- } ? Acc : LayoutTree[Layout]["middlewares"] extends infer Acc extends readonly unknown[] ? Acc : readonly [];
45
- type ResolveLayoutMiddlewares<Layout extends LayoutId | null, Depth extends readonly unknown[] = []> = Depth["length"] extends 10 ? readonly [] : Layout extends LayoutId ? readonly [
46
- ...ResolveLayoutMiddlewares<LayoutParent<Layout>, [...Depth, unknown]>,
48
+ } ? Acc : LayoutMiddlewaresMap[Layout] extends readonly unknown[] ? LayoutMiddlewaresMap[Layout] : readonly [] : readonly [];
49
+ type ResolveLayoutMiddlewares<Layout extends LayoutId | null, Depth extends readonly unknown[] = []> = Depth["length"] extends 10 ? readonly [] : [Layout] extends [LayoutId] ? LayoutParent<Layout> extends infer Parent extends LayoutId ? readonly [
50
+ ...ResolveLayoutMiddlewares<Parent, [...Depth, unknown]>,
47
51
  ...LayoutMiddlewares<Layout>
48
- ] : readonly [];
52
+ ] : readonly [...LayoutMiddlewares<Layout>] : readonly [];
49
53
  export type ResolveLayoutIdChain<L extends LayoutId | null, Depth extends readonly unknown[] = []> = Depth["length"] extends 10 ? readonly [] : L extends LayoutId ? readonly [...ResolveLayoutIdChain<LayoutParent<L>, [...Depth, unknown]>, L] : readonly [];
50
54
  export type ResolveLayoutMiddlewaresState<Layout extends LayoutId | null> = Layout extends LayoutId ? MergeMiddlewareField<ResolveLayoutMiddlewares<Layout>, "state"> : {};
51
55
  export type ResolveLayoutsState<Layouts extends LayoutId | readonly LayoutId[]> = Layouts extends LayoutId ? ResolveLayoutMiddlewaresState<Layouts> : Layouts extends readonly LayoutId[] ? UnionToIntersection<Layouts[number] extends infer L extends LayoutId ? ResolveLayoutMiddlewaresState<L> : never> : {};
@@ -60,21 +64,18 @@ type ResolveLayoutChainMiddlewares<Chain extends readonly LayoutId[]> = Chain ex
60
64
  type RouteEntry<Path extends RoutePath, TMethod extends Method> = RouteByPathMethod[Path] extends {
61
65
  [K in TMethod]: infer Entry;
62
66
  } ? Entry : never;
63
- type RouteParent<Path extends RoutePath, TMethod extends Method> = RouteEntry<Path, TMethod> extends {
64
- parent: infer Parent extends LayoutId | null;
65
- } ? Parent : null;
66
67
  type RouteLayoutChain<Path extends RoutePath, TMethod extends Method> = RouteEntry<Path, TMethod> extends {
67
- layoutChain: infer Chain extends readonly LayoutId[];
68
- } ? Chain : RouteParent<Path, TMethod> extends LayoutId ? readonly [RouteParent<Path, TMethod>] : readonly [];
68
+ layouts: infer Chain extends readonly LayoutId[];
69
+ } ? Chain : readonly [];
69
70
  export type RouteLayoutMiddlewares<Path extends RoutePath, TMethod extends Method> = ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>;
70
71
  export type RouteLayoutField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
71
72
  export type RouteLayoutInputField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body"> = MergeMiddlewareInputField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
72
73
  type RouteResolvedField<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], Field extends "query" | "params" | "body" | "state"> = RouteLayoutField<Path, TMethod, Field> & MergeMiddlewareField<Acc, Field>;
73
74
  export type RouteChainContext<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], TQuery, TParams, TBody, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & UnitRuntimeContext & {
74
- query: Simplify<MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>>;
75
- params: Simplify<ResolveParams<PathParams<Path>, MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>>>;
76
- body: Simplify<MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>>;
77
- state: Simplify<RouteResolvedField<Path, TMethod, Acc, "state">>;
75
+ query: MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>;
76
+ params: ResolveParams<PathParams<Path>, MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>>;
77
+ body: MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>;
78
+ state: RouteResolvedField<Path, TMethod, Acc, "state">;
78
79
  headers: TaserHeaders;
79
80
  cookies: TaserCookieJar;
80
81
  }>;
@@ -121,7 +122,25 @@ type IsEmptyObject<T> = [keyof T] extends [never] ? true : false;
121
122
  export type IsLayoutAllowed<TRequiredLayouts, TChain extends readonly LayoutId[]> = [
122
123
  TRequiredLayouts
123
124
  ] extends [never] ? true : [unknown] extends [TRequiredLayouts] ? true : [null] extends [TRequiredLayouts] ? true : [undefined] extends [TRequiredLayouts] ? true : TRequiredLayouts extends LayoutId ? TRequiredLayouts extends TChain[number] ? true : false : TRequiredLayouts extends readonly LayoutId[] ? [TRequiredLayouts[number] & TChain[number]] extends [never] ? false : true : true;
124
- export type IsStateSatisfied<TActualState, TRequiredState> = [TRequiredState] extends [never] ? true : [unknown] extends [TRequiredState] ? true : [null] extends [TRequiredState] ? true : [undefined] extends [TRequiredState] ? true : [IsEmptyObject<TRequiredState>] extends [true] ? true : [TActualState] extends [TRequiredState] ? true : false;
125
+ export type IsRequirementsSatisfied<TActual extends {
126
+ query?: unknown;
127
+ params?: unknown;
128
+ body?: unknown;
129
+ state?: unknown;
130
+ }, TRequires extends MiddlewareRequirements> = [TRequires] extends [never] ? true : [unknown] extends [TRequires] ? true : [null] extends [TRequires] ? true : [undefined] extends [TRequires] ? true : [IsEmptyObject<TRequires>] extends [true] ? true : (TRequires extends {
131
+ state: infer S extends Record<string, unknown>;
132
+ } ? [TActual["state"]] extends [S] ? true : false : true) extends false ? false : (TRequires extends {
133
+ query: infer Q extends Record<string, unknown>;
134
+ } ? [TActual["query"]] extends [Q] ? true : false : true) extends false ? false : (TRequires extends {
135
+ params: infer P extends Record<string, unknown>;
136
+ } ? [TActual["params"]] extends [P] ? true : false : true) extends false ? false : (TRequires extends {
137
+ body: infer B;
138
+ } ? unknown extends B ? true : [TRequires["body"]] extends [undefined] ? true : [TActual["body"]] extends [B] ? true : false : true) extends false ? false : true;
139
+ export type IsStateSatisfied<TActualState, TRequiredState> = IsRequirementsSatisfied<{
140
+ state: TActualState;
141
+ }, {
142
+ state: TRequiredState extends Record<string, unknown> ? TRequiredState : {};
143
+ }>;
125
144
  type InputFacet<T, K extends string> = IsNever<T> extends true ? {} : IsEmptyObject<T> extends true ? {} : {
126
145
  [Key in K]: T;
127
146
  };
@@ -149,36 +168,43 @@ export type InferRouteInputFromPath<Path extends RoutePath, TMethod extends Meth
149
168
  Input: infer I;
150
169
  };
151
170
  } ? I : never : never;
152
- export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field>;
171
+ export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = [LayoutParent<Layout>] extends [infer Parent extends LayoutId] ? MergeMiddlewareField<ResolveLayoutMiddlewares<Parent>, Field> : {};
153
172
  type MiddlewareChainField<Layout extends LayoutId, Acc extends readonly unknown[], Field extends "query" | "params" | "body" | "state"> = MiddlewareLayoutField<Layout, Field> & MergeMiddlewareField<Acc, Field>;
154
- export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery, TParams, TBody, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & UnitRuntimeContext & {
173
+ export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery = unknown, TParams = unknown, TBody = unknown, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & {
174
+ readonly request: Request;
175
+ readonly method: Method;
176
+ readonly url: URL;
177
+ readonly headers: TaserHeaders;
178
+ readonly cookies: TaserCookieJar;
155
179
  query: Simplify<MergePart<TQuery, MiddlewareChainField<Layout, Acc, "query">>>;
156
180
  params: Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>;
157
181
  body: Simplify<MergePart<TBody, MiddlewareChainField<Layout, Acc, "body">>>;
158
182
  state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
159
- headers: TaserHeaders;
160
- cookies: TaserCookieJar;
161
183
  }>;
162
184
  export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unknown[] = readonly [], TAppContext extends Record<string, unknown> = AppContext> = {
163
185
  readonly layout: Layout;
164
186
  readonly middlewares: readonly MiddlewareDefinition[];
165
187
  readonly __acc?: Acc;
166
- readonly $Infer: {
167
- Context: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>;
168
- };
169
- use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequiredState = unknown>(unit: MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequiredState>, ..._assert: [
188
+ use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}>(unit: [
170
189
  IsLayoutAllowed<TRequiredLayouts, ResolveLayoutIdChain<Layout>>,
171
- IsStateSatisfied<MiddlewareChainField<Layout, Acc, "state">, TRequiredState>
172
- ] extends [true, true] ? [] : [
173
- {
174
- error: "Middleware cannot be attached to this layout";
175
- requiredLayouts: TRequiredLayouts;
176
- layoutChain: ResolveLayoutIdChain<Layout>;
177
- requiredState: TRequiredState;
178
- actualState: MiddlewareChainField<Layout, Acc, "state">;
179
- }
180
- ]): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
181
- use<R = unknown>(fn: (ctx: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>, next: NextFn) => Awaitable<R>): MiddlewareBuilder<Layout, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], TAppContext>;
190
+ IsRequirementsSatisfied<{
191
+ query: MiddlewareChainField<Layout, Acc, "query">;
192
+ params: MiddlewareChainField<Layout, Acc, "params">;
193
+ body: MiddlewareChainField<Layout, Acc, "body">;
194
+ state: MiddlewareChainField<Layout, Acc, "state">;
195
+ }, TRequires>
196
+ ] extends [true, true] ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires> : never): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
197
+ use<R = unknown>(fn: (ctx: Simplify<TAppContext & {
198
+ readonly request: Request;
199
+ readonly method: Method;
200
+ readonly url: URL;
201
+ readonly headers: TaserHeaders;
202
+ readonly cookies: TaserCookieJar;
203
+ query: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "query">>>;
204
+ params: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "params">>>;
205
+ body: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "body">>>;
206
+ state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
207
+ }>, next: NextFn) => Awaitable<R>): MiddlewareBuilder<Layout, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], TAppContext>;
182
208
  };
183
209
  export type RouteExport<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], TReturns extends ReturnsMap = {}, TOutput = Response> = {
184
210
  readonly path: Path;
@@ -205,7 +231,7 @@ type RouteHandleResult<Path extends RoutePath, TMethod extends Method, Acc exten
205
231
  Output: TOutput;
206
232
  };
207
233
  };
208
- export type RouteBuilderBase<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = {
234
+ export type RouteContractBuilderBase<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = {
209
235
  readonly path: Path;
210
236
  readonly method: TMethod;
211
237
  readonly $Infer: {
@@ -213,28 +239,15 @@ export type RouteBuilderBase<Path extends RoutePath, TMethod extends Method, Acc
213
239
  Input: TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS" ? RouteHandleInputWithoutBody<Path, TMethod, Acc, Validators> : RouteHandleInput<Path, TMethod, Acc, Validators>;
214
240
  Output: TReturns;
215
241
  };
216
- query<TQuery, TQueryIn = unknown>(schema: Schema<TQuery, TQueryIn>): RouteBuilder<Path, TMethod, Acc, Omit<Validators, "query" | "queryIn"> & {
242
+ query<TQuery, TQueryIn = unknown>(schema: Schema<TQuery, TQueryIn>): RouteContractBuilder<Path, TMethod, Acc, Omit<Validators, "query" | "queryIn"> & {
217
243
  query: TQuery;
218
244
  queryIn: TQueryIn;
219
245
  }, TReturns, TAppContext>;
220
- params<TParams, TParamsIn = unknown>(schema: Schema<TParams, TParamsIn>): RouteBuilder<Path, TMethod, Acc, Omit<Validators, "params" | "paramsIn"> & {
246
+ params<TParams, TParamsIn = unknown>(schema: Schema<TParams, TParamsIn>): RouteContractBuilder<Path, TMethod, Acc, Omit<Validators, "params" | "paramsIn"> & {
221
247
  params: TParams;
222
248
  paramsIn: TParamsIn;
223
249
  }, TReturns, TAppContext>;
224
- returns<const M extends ReturnsMap>(map: M): RouteBuilder<Path, TMethod, Acc, Validators, Omit<TReturns, keyof M> & M, TAppContext>;
225
- use<TAcc, UReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequiredState = unknown>(unit: MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequiredState>, ..._assert: [
226
- IsLayoutAllowed<TRequiredLayouts, RouteLayoutChain<Path, TMethod>>,
227
- IsStateSatisfied<RouteResolvedField<Path, TMethod, Acc, "state">, TRequiredState>
228
- ] extends [true, true] ? [] : [
229
- {
230
- error: "Middleware cannot be attached to this route";
231
- requiredLayouts: TRequiredLayouts;
232
- routeLayoutChain: RouteLayoutChain<Path, TMethod>;
233
- requiredState: TRequiredState;
234
- actualState: RouteResolvedField<Path, TMethod, Acc, "state">;
235
- }
236
- ]): RouteBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
237
- use<R = unknown>(fn: (ctx: RouteChainContext<Path, TMethod, Acc, unknown, unknown, unknown, TAppContext>, next: NextFn) => Awaitable<R>): RouteBuilder<Path, TMethod, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], Validators, TReturns, TAppContext>;
250
+ returns<const M extends ReturnsMap>(map: M): RouteContractBuilder<Path, TMethod, Acc, Validators, Omit<TReturns, keyof M> & M, TAppContext>;
238
251
  handler<R extends Response = Response>(fn: (ctx: TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS" ? RouteHandleContextWithoutBody<Path, TMethod, Acc, Validators, TAppContext> : RouteHandleContext<Path, TMethod, Acc, Validators, TAppContext>) => Awaitable<R>, ..._assert: [R] extends [ValidHandlerReply<R, TReturns>] ? [] : [
239
252
  {
240
253
  expected: ValidHandlerReply<R, TReturns>;
@@ -242,16 +255,29 @@ export type RouteBuilderBase<Path extends RoutePath, TMethod extends Method, Acc
242
255
  }
243
256
  ]): RouteHandleResult<Path, TMethod, Acc, Validators, TReturns, R, TAppContext>;
244
257
  };
245
- export type RouteBuilder<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = RouteBuilderBase<Path, TMethod, Acc, Validators, TReturns, TAppContext> & (TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS" ? {} : {
246
- body<TBody, TBodyIn = unknown>(schema: Schema<TBody, TBodyIn>): RouteBuilder<Path, TMethod, Acc, Omit<Validators, "body" | "bodyIn"> & {
258
+ export type RouteContractBuilder<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = RouteContractBuilderBase<Path, TMethod, Acc, Validators, TReturns, TAppContext> & (TMethod extends "GET" | "DELETE" | "HEAD" | "OPTIONS" ? {} : {
259
+ body<TBody, TBodyIn = unknown>(schema: Schema<TBody, TBodyIn>): RouteContractBuilder<Path, TMethod, Acc, Omit<Validators, "body" | "bodyIn"> & {
247
260
  body: TBody;
248
261
  bodyIn: TBodyIn;
249
262
  }, TReturns, TAppContext>;
250
- body<Mode extends "json" | "form" | "urlencoded", TBody, TBodyIn = unknown>(mode: Mode, schema: Schema<TBody, TBodyIn>): RouteBuilder<Path, TMethod, Acc, Omit<Validators, "body" | "bodyIn"> & {
263
+ body<Mode extends "json" | "form" | "urlencoded", TBody, TBodyIn = unknown>(mode: Mode, schema: Schema<TBody, TBodyIn>): RouteContractBuilder<Path, TMethod, Acc, Omit<Validators, "body" | "bodyIn"> & {
251
264
  body: TBody;
252
265
  bodyIn: TBodyIn;
253
266
  }, TReturns, TAppContext>;
254
267
  });
268
+ export type RouteMiddlewareBuilder<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = RouteContractBuilder<Path, TMethod, Acc, Validators, TReturns, TAppContext> & {
269
+ use<TAcc, UReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}>(unit: [
270
+ IsLayoutAllowed<TRequiredLayouts, RouteLayoutChain<Path, TMethod>>,
271
+ IsRequirementsSatisfied<{
272
+ query: RouteResolvedField<Path, TMethod, Acc, "query">;
273
+ params: ResolveParams<PathParams<Path>, RouteResolvedField<Path, TMethod, Acc, "params">>;
274
+ body: RouteResolvedField<Path, TMethod, Acc, "body">;
275
+ state: RouteResolvedField<Path, TMethod, Acc, "state">;
276
+ }, TRequires>
277
+ ] extends [true, true] ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires> : never): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
278
+ use<R = unknown>(fn: (ctx: RouteChainContext<Path, TMethod, Acc, unknown, unknown, unknown, TAppContext>, next: NextFn) => Awaitable<R>): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], Validators, TReturns, TAppContext>;
279
+ };
280
+ export type RouteBuilder<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[] = readonly [], Validators extends ValidatorParts = {}, TReturns extends ReturnsMap = {}, TAppContext extends Record<string, unknown> = AppContext> = RouteMiddlewareBuilder<Path, TMethod, Acc, Validators, TReturns, TAppContext>;
255
281
  export type RouteDefinition<Path extends RoutePath = RoutePath, TMethod extends Method = Method, Acc extends readonly unknown[] = readonly unknown[], Validators extends ValidatorParts = ValidatorParts, TReturns extends ReturnsMap = ReturnsMap, TOutput = Response, TAppContext extends Record<string, unknown> = AppContext> = RouteHandleResult<Path, TMethod, Acc, Validators, TReturns, TOutput, TAppContext>;
256
282
  export type InferRouteContext<R> = R extends {
257
283
  $Infer: {
@@ -7,9 +7,9 @@ export type MiddlewareInputFieldName = "query" | "params" | "body";
7
7
  export type UnwrapPart<T> = unknown extends T ? {} : T;
8
8
  export type MergePart<T, Base> = unknown extends T ? Base : Base & T;
9
9
  /** Collapse intersections so `Omit`/`keyof` treat the result as one object type. */
10
- export type Simplify<T> = {
11
- [K in keyof T]: T[K];
12
- } & {};
10
+ export type Simplify<T> = [T] extends [infer U] ? {
11
+ [K in keyof U]: U[K];
12
+ } : never;
13
13
  /**
14
14
  * Request prop: when schema input is `unknown` (e.g. zod coerce),
15
15
  * fall back to the validated output type.
@@ -26,10 +26,10 @@ export type IsUnknown<T> = [unknown] extends [T] ? true : false;
26
26
  export type NextFn<TExpectedState = unknown> = IsUnknown<TExpectedState> extends true ? <S extends Record<string, unknown> = {}>(state?: S) => Promise<NextResult<S>> : (state: TExpectedState) => Promise<NextResult<TExpectedState>>;
27
27
  export type MiddlewareDefinition = CoreMiddlewareDefinition<ReturnsMap>;
28
28
  export type MiddlewareReturnFromParts<TQuery, TParams, TBody, TState, TQueryIn = TQuery, TParamsIn = TParams, TBodyIn = TBody> = {
29
- query: Simplify<UnwrapPart<TQuery>>;
30
- params: Simplify<UnwrapPart<TParams>>;
31
- body: Simplify<UnwrapPart<TBody>>;
32
- state: Simplify<UnwrapPart<TState>>;
29
+ query: UnwrapPart<TQuery>;
30
+ params: UnwrapPart<TParams>;
31
+ body: UnwrapPart<TBody>;
32
+ state: UnwrapPart<TState>;
33
33
  /** Pre-parse shapes merged into route `$Infer.Input`. */
34
34
  input: {
35
35
  query: RequestShape<TQueryIn, TQuery>;
@@ -37,29 +37,35 @@ export type MiddlewareReturnFromParts<TQuery, TParams, TBody, TState, TQueryIn =
37
37
  body: RequestShape<TBodyIn, TBody>;
38
38
  };
39
39
  };
40
- export type DefineMiddlewareResult<TQuery, TParams, TBody, TState, R, TQueryIn = TQuery, TParamsIn = TParams, TBodyIn = TBody, TReturns extends ReturnsMap = {}, TLayout = null, TRequires = {}> = MiddlewareUnit<MiddlewareReturnFromParts<TQuery, TParams, TBody, IsUnknown<TState> extends true ? ExtractState<R> : TState, TQueryIn, TParamsIn, TBodyIn>, TReturns, TLayout, TRequires>;
41
- export type StandaloneMiddlewareContext<TQuery = unknown, TParams = unknown, TBody = unknown, TAppContext extends Record<string, unknown> = EmptyAppContext, TState = {}> = Simplify<TAppContext & UnitRuntimeContext & {
42
- query: Simplify<UnwrapPart<TQuery>>;
43
- params: Simplify<UnwrapPart<TParams>>;
44
- body: Simplify<UnwrapPart<TBody>>;
45
- state: Simplify<UnwrapPart<TState>>;
40
+ export type MiddlewareRequirements = {
41
+ query?: Record<string, unknown>;
42
+ params?: Record<string, unknown>;
43
+ body?: unknown;
44
+ state?: Record<string, unknown>;
45
+ };
46
+ export type DefineMiddlewareResult<TQuery, TParams, TBody, TState, R, TQueryIn = TQuery, TParamsIn = TParams, TBodyIn = TBody, TReturns extends ReturnsMap = {}, TLayout = null, TRequires extends MiddlewareRequirements = {}> = MiddlewareUnit<MiddlewareReturnFromParts<TQuery, TParams, TBody, IsUnknown<TState> extends true ? ExtractState<R> : TState, TQueryIn, TParamsIn, TBodyIn>, TReturns, TLayout, TRequires>;
47
+ export type StandaloneMiddlewareContext<TQuery = unknown, TParams = unknown, TBody = unknown, TAppContext extends Record<string, unknown> = EmptyAppContext, TState = {}, TRequires extends MiddlewareRequirements = {}> = Simplify<TAppContext & UnitRuntimeContext & {
48
+ query: Simplify<UnwrapPart<TQuery> & (TRequires["query"] extends Record<string, unknown> ? TRequires["query"] : {})>;
49
+ params: Simplify<UnwrapPart<TParams> & (TRequires["params"] extends Record<string, unknown> ? TRequires["params"] : {})>;
50
+ body: Simplify<UnwrapPart<TBody> & (unknown extends TRequires["body"] ? {} : [TRequires["body"]] extends [undefined] ? {} : TRequires["body"])>;
51
+ state: Simplify<UnwrapPart<TState> & (TRequires["state"] extends Record<string, unknown> ? TRequires["state"] : {})>;
46
52
  headers: TaserHeaders;
47
53
  cookies: TaserCookieJar;
48
54
  }>;
49
55
  export declare const MiddlewareUnitBrand: unique symbol;
50
- export type MiddlewareUnit<TAcc = unknown, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequiredState = unknown> = MiddlewareDefinition & {
56
+ export type MiddlewareUnit<TAcc = unknown, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}> = MiddlewareDefinition & {
51
57
  readonly [MiddlewareUnitBrand]: true;
52
58
  readonly __middlewareAcc: TAcc;
53
59
  readonly __returns?: TReturns;
54
60
  readonly __requiredLayouts?: TRequiredLayouts;
55
- readonly __requiredState?: TRequiredState;
61
+ readonly __requirements?: TRequires;
56
62
  };
57
- export type MiddlewareUnitBuilder<TQuery = unknown, TParams = unknown, TBody = unknown, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequiredState = {}, TAppContext extends Record<string, unknown> = EmptyAppContext, TInheritedState = {}, TQueryIn = unknown, TParamsIn = unknown, TBodyIn = unknown, TExpectedState = unknown> = MiddlewareUnit<MiddlewareReturnFromParts<TQuery, TParams, TBody, IsUnknown<TExpectedState> extends true ? {} : TExpectedState, TQueryIn, TParamsIn, TBodyIn>, TReturns, TRequiredLayouts, TRequiredState> & {
58
- query<Q, QIn = unknown>(schema: Schema<Q, QIn>): MiddlewareUnitBuilder<Q, TParams, TBody, TReturns, TRequiredLayouts, TRequiredState, TAppContext, TInheritedState, QIn, TParamsIn, TBodyIn, TExpectedState>;
59
- params<P, PIn = unknown>(schema: Schema<P, PIn>): MiddlewareUnitBuilder<TQuery, P, TBody, TReturns, TRequiredLayouts, TRequiredState, TAppContext, TInheritedState, TQueryIn, PIn, TBodyIn, TExpectedState>;
60
- body<B, BIn = unknown>(schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts, TRequiredState, TAppContext, TInheritedState, TQueryIn, TParamsIn, BIn, TExpectedState>;
61
- body<Mode extends "json" | "form" | "urlencoded", B, BIn = unknown>(mode: Mode, schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts, TRequiredState, TAppContext, TInheritedState, TQueryIn, TParamsIn, BIn, TExpectedState>;
62
- returns<const M extends ReturnsMap>(map: M): MiddlewareUnitBuilder<TQuery, TParams, TBody, Omit<TReturns, keyof M> & M, TRequiredLayouts, TRequiredState, TAppContext, TInheritedState, TQueryIn, TParamsIn, TBodyIn, TExpectedState>;
63
- requires<Requires extends Record<string, unknown>>(): MiddlewareUnitBuilder<TQuery, TParams, TBody, TReturns, TRequiredLayouts, TRequiredState & Requires, TAppContext, TInheritedState, TQueryIn, TParamsIn, TBodyIn, TExpectedState>;
64
- handler<R>(fn: (ctx: StandaloneMiddlewareContext<TQuery, TParams, TBody, TAppContext, TInheritedState & TRequiredState>, next: NextFn<TExpectedState>) => R): DefineMiddlewareResult<TQuery, TParams, TBody, IsUnknown<TExpectedState> extends true ? ExtractState<R> : TExpectedState, R, TQueryIn, TParamsIn, TBodyIn, TReturns, TRequiredLayouts, TRequiredState>;
63
+ export type MiddlewareUnitBuilder<TQuery = unknown, TParams = unknown, TBody = unknown, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}, TAppContext extends Record<string, unknown> = EmptyAppContext, TInheritedState = {}, TQueryIn = unknown, TParamsIn = unknown, TBodyIn = unknown, TExpectedState = unknown> = MiddlewareUnit<MiddlewareReturnFromParts<TQuery, TParams, TBody, IsUnknown<TExpectedState> extends true ? {} : TExpectedState, TQueryIn, TParamsIn, TBodyIn>, TReturns, TRequiredLayouts, TRequires> & {
64
+ query<Q, QIn = unknown>(schema: Schema<Q, QIn>): MiddlewareUnitBuilder<Q, TParams, TBody, TReturns, TRequiredLayouts, TRequires, TAppContext, TInheritedState, QIn, TParamsIn, TBodyIn, TExpectedState>;
65
+ params<P, PIn = unknown>(schema: Schema<P, PIn>): MiddlewareUnitBuilder<TQuery, P, TBody, TReturns, TRequiredLayouts, TRequires, TAppContext, TInheritedState, TQueryIn, PIn, TBodyIn, TExpectedState>;
66
+ body<B, BIn = unknown>(schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts, TRequires, TAppContext, TInheritedState, TQueryIn, TParamsIn, BIn, TExpectedState>;
67
+ body<Mode extends "json" | "form" | "urlencoded", B, BIn = unknown>(mode: Mode, schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts, TRequires, TAppContext, TInheritedState, TQueryIn, TParamsIn, BIn, TExpectedState>;
68
+ returns<const M extends ReturnsMap>(map: M): MiddlewareUnitBuilder<TQuery, TParams, TBody, Omit<TReturns, keyof M> & M, TRequiredLayouts, TRequires, TAppContext, TInheritedState, TQueryIn, TParamsIn, TBodyIn, TExpectedState>;
69
+ requires<Requires extends MiddlewareRequirements>(): MiddlewareUnitBuilder<TQuery, TParams, TBody, TReturns, TRequiredLayouts, TRequires & Requires, TAppContext, TInheritedState, TQueryIn, TParamsIn, TBodyIn, TExpectedState>;
70
+ handler<R>(fn: (ctx: StandaloneMiddlewareContext<TQuery, TParams, TBody, TAppContext, TInheritedState, TRequires>, next: NextFn<TExpectedState>) => R): DefineMiddlewareResult<TQuery, TParams, TBody, IsUnknown<TExpectedState> extends true ? ExtractState<R> : TExpectedState, R, TQueryIn, TParamsIn, TBodyIn, TReturns, TRequiredLayouts, TRequires>;
65
71
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taserjs/router",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Type-safe Node.js router with runtime validation and middleware",
5
5
  "license": "ISC",
6
6
  "repository": {
@@ -147,8 +147,8 @@
147
147
  "dependencies": {
148
148
  "@standard-schema/spec": "^1.1.0",
149
149
  "hono": "^4.10.3",
150
- "@taserjs/router-core": "0.1.6",
151
- "@taserjs/router-utils": "0.1.6"
150
+ "@taserjs/router-core": "0.1.8",
151
+ "@taserjs/router-utils": "0.1.8"
152
152
  },
153
153
  "devDependencies": {
154
154
  "@tanstack/vite-config": "^0.6.0",
@@ -10,7 +10,7 @@ export type CreateWithoutBodyRoute<
10
10
  ) => RouteBuilder<Path, M, readonly [], {}, {}, TAppContext>;
11
11
 
12
12
  export type CreateWithBodyRoute<
13
- M extends "POST" | "PUT" | "PATCH",
13
+ M extends "POST" | "PUT" | "PATCH" | "QUERY",
14
14
  TAppContext extends Record<string, unknown> = AppContext,
15
15
  > = <const Path extends RoutePath>(
16
16
  path: Path,
@@ -37,7 +37,7 @@ function createWithoutBodyRoute<M extends "GET" | "DELETE" | "OPTIONS" | "HEAD">
37
37
  createRouteBuilder(path, method)) as unknown as CreateWithoutBodyRoute<M>;
38
38
  }
39
39
 
40
- function createWithBodyRoute<M extends "POST" | "PUT" | "PATCH">(
40
+ function createWithBodyRoute<M extends "POST" | "PUT" | "PATCH" | "QUERY">(
41
41
  method: M,
42
42
  ): CreateWithBodyRoute<M> {
43
43
  return ((path: string) => createRouteBuilder(path, method)) as unknown as CreateWithBodyRoute<M>;
@@ -50,6 +50,7 @@ export const createHeadRoute = createWithoutBodyRoute("HEAD");
50
50
  export const createPostRoute = createWithBodyRoute("POST");
51
51
  export const createPutRoute = createWithBodyRoute("PUT");
52
52
  export const createPatchRoute = createWithBodyRoute("PATCH");
53
+ export const createQueryRoute = createWithBodyRoute("QUERY");
53
54
 
54
55
  export const createAnyRoute: CreateAnyRoute = ((path: string, methods: readonly HttpMethod[]) =>
55
56
  createRouteBuilder(path, "ANY", methods)) as unknown as CreateAnyRoute;
@@ -9,6 +9,7 @@ import {
9
9
  createPatchRoute,
10
10
  createPostRoute,
11
11
  createPutRoute,
12
+ createQueryRoute,
12
13
  type CreateAllRoute,
13
14
  type CreateAnyRoute,
14
15
  type CreateWithBodyRoute,
@@ -35,6 +36,8 @@ export const options: CreateWithoutBodyRoute<"OPTIONS", AppContext> =
35
36
  createOptionsRoute as CreateWithoutBodyRoute<"OPTIONS", AppContext>;
36
37
  export const head: CreateWithoutBodyRoute<"HEAD", AppContext> =
37
38
  createHeadRoute as CreateWithoutBodyRoute<"HEAD", AppContext>;
39
+ export const query: CreateWithBodyRoute<"QUERY", AppContext> =
40
+ createQueryRoute as CreateWithBodyRoute<"QUERY", AppContext>;
38
41
  export const any: CreateAnyRoute<AppContext> = createAnyRoute as CreateAnyRoute<AppContext>;
39
42
  export const all: CreateAllRoute<AppContext> = createAllRoute as CreateAllRoute<AppContext>;
40
43
 
@@ -49,6 +52,7 @@ export type TaserNamespace<TAppContext extends Record<string, unknown> = AppCont
49
52
  readonly delete: CreateWithoutBodyRoute<"DELETE", TAppContext>;
50
53
  readonly options: CreateWithoutBodyRoute<"OPTIONS", TAppContext>;
51
54
  readonly head: CreateWithoutBodyRoute<"HEAD", TAppContext>;
55
+ readonly query: CreateWithBodyRoute<"QUERY", TAppContext>;
52
56
  readonly any: CreateAnyRoute<TAppContext>;
53
57
  readonly all: CreateAllRoute<TAppContext>;
54
58
  readonly layout: LayoutBuilder<TAppContext>;
@@ -63,6 +67,7 @@ export const t: TaserNamespace<AppContext> = {
63
67
  delete: del,
64
68
  options,
65
69
  head,
70
+ query,
66
71
  any,
67
72
  all,
68
73
  layout,
@@ -3,6 +3,7 @@ import type {
3
3
  DefineMiddlewareResult,
4
4
  ExtractState,
5
5
  IsUnknown,
6
+ MiddlewareRequirements,
6
7
  MiddlewareUnitBuilder,
7
8
  NextFn,
8
9
  StandaloneMiddlewareContext,
@@ -16,66 +17,55 @@ import type {
16
17
 
17
18
  export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {
18
19
  /**
19
- * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
20
+ * Defines a standalone, unscoped middleware using a short function signature.
20
21
  *
21
22
  * @example
22
23
  * ```ts
23
- * const auth = middleware<{ user: string }>()
24
- * .query(z.object({ token: z.string() }))
25
- * .body("form", z.object({ file: z.instanceof(File) }))
26
- * .returns({ 401: z.string() })
27
- * .handler(async (ctx, next) => next({ user: "alice" }));
24
+ * const auth = middleware((ctx, next) => {
25
+ * return next({ user: "alice" });
26
+ * });
28
27
  * ```
29
28
  */
30
- <TState = unknown>(): MiddlewareUnitBuilder<
31
- unknown,
32
- unknown,
33
- unknown,
34
- {},
35
- null,
36
- {},
37
- TAppContext,
38
- {},
29
+ <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(
30
+ fn: (
31
+ ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,
32
+ next: NextFn<NoInfer<TState>>,
33
+ ) => R,
34
+ ): DefineMiddlewareResult<
39
35
  unknown,
40
36
  unknown,
41
37
  unknown,
42
- TState
43
- >;
44
-
45
- /**
46
- * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
47
- */
48
- <const Layout extends LayoutId, TState = unknown>(
49
- layout: Layout,
50
- ): MiddlewareUnitBuilder<
38
+ IsUnknown<TState> extends true ? ExtractState<R> : TState,
39
+ R,
51
40
  unknown,
52
41
  unknown,
53
42
  unknown,
54
43
  {},
55
- Layout,
56
- {},
57
- TAppContext,
58
- ResolveLayoutMiddlewaresState<Layout>,
59
- unknown,
60
- unknown,
61
- unknown,
62
- TState
44
+ null,
45
+ TRequires
63
46
  >;
64
47
 
65
48
  /**
66
- * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
49
+ * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const auth = middleware<{ user: string }>()
54
+ * .query(z.object({ token: z.string() }))
55
+ * .body("form", z.object({ file: z.instanceof(File) }))
56
+ * .returns({ 401: z.string() })
57
+ * .handler(async (ctx, next) => next({ user: "alice" }));
58
+ * ```
67
59
  */
68
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(
69
- layouts: Layouts,
70
- ): MiddlewareUnitBuilder<
60
+ <TState = unknown>(): MiddlewareUnitBuilder<
71
61
  unknown,
72
62
  unknown,
73
63
  unknown,
74
64
  {},
75
- Layouts,
65
+ null,
76
66
  {},
77
67
  TAppContext,
78
- ResolveLayoutsState<Layouts>,
68
+ {},
79
69
  unknown,
80
70
  unknown,
81
71
  unknown,
@@ -85,7 +75,12 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
85
75
  /**
86
76
  * Defines a standalone middleware scoped to a single layout branch using a short function signature.
87
77
  */
88
- <const Layout extends LayoutId, TState = unknown, TRequires = {}, R = unknown>(
78
+ <
79
+ const Layout extends LayoutId,
80
+ TState = unknown,
81
+ TRequires extends MiddlewareRequirements = {},
82
+ R = unknown,
83
+ >(
89
84
  layout: Layout,
90
85
  fn: (
91
86
  ctx: StandaloneMiddlewareContext<
@@ -93,7 +88,8 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
93
88
  unknown,
94
89
  unknown,
95
90
  TAppContext,
96
- ResolveLayoutMiddlewaresState<Layout> & TRequires
91
+ ResolveLayoutMiddlewaresState<Layout>,
92
+ TRequires
97
93
  >,
98
94
  next: NextFn<NoInfer<TState>>,
99
95
  ) => R,
@@ -117,7 +113,7 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
117
113
  <
118
114
  const Layouts extends readonly [LayoutId, ...LayoutId[]],
119
115
  TState = unknown,
120
- TRequires = {},
116
+ TRequires extends MiddlewareRequirements = {},
121
117
  R = unknown,
122
118
  >(
123
119
  layouts: Layouts,
@@ -127,7 +123,8 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
127
123
  unknown,
128
124
  unknown,
129
125
  TAppContext,
130
- ResolveLayoutsState<Layouts> & TRequires
126
+ ResolveLayoutsState<Layouts>,
127
+ TRequires
131
128
  >,
132
129
  next: NextFn<NoInfer<TState>>,
133
130
  ) => R,
@@ -146,32 +143,43 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
146
143
  >;
147
144
 
148
145
  /**
149
- * Defines a standalone, unscoped middleware using a short function signature.
150
- *
151
- * @example
152
- * ```ts
153
- * const auth = middleware((ctx, next) => {
154
- * return next({ user: "alice" });
155
- * });
156
- * ```
146
+ * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
157
147
  */
158
- <TState = unknown, TRequires = {}, R = unknown>(
159
- fn: (
160
- ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, TRequires>,
161
- next: NextFn<NoInfer<TState>>,
162
- ) => R,
163
- ): DefineMiddlewareResult<
148
+ <const Layout extends LayoutId, TState = unknown>(
149
+ layout: Layout,
150
+ ): MiddlewareUnitBuilder<
164
151
  unknown,
165
152
  unknown,
166
153
  unknown,
167
- IsUnknown<TState> extends true ? ExtractState<R> : TState,
168
- R,
154
+ {},
155
+ Layout,
156
+ {},
157
+ TAppContext,
158
+ ResolveLayoutMiddlewaresState<Layout>,
159
+ unknown,
160
+ unknown,
161
+ unknown,
162
+ TState
163
+ >;
164
+
165
+ /**
166
+ * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
167
+ */
168
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(
169
+ layouts: Layouts,
170
+ ): MiddlewareUnitBuilder<
169
171
  unknown,
170
172
  unknown,
171
173
  unknown,
172
174
  {},
173
- null,
174
- TRequires
175
+ Layouts,
176
+ {},
177
+ TAppContext,
178
+ ResolveLayoutsState<Layouts>,
179
+ unknown,
180
+ unknown,
181
+ unknown,
182
+ TState
175
183
  >;
176
184
  }
177
185