@taserjs/router 0.1.7 → 0.1.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.cjs","names":[],"sources":["../../../src/define/middleware.ts"],"sourcesContent":["import { createMiddlewareUnitBuilder } from \"../builder/middleware-unit.js\";\nimport type {\n DefineMiddlewareResult,\n ExtractState,\n IsUnknown,\n MiddlewareRequirements,\n MiddlewareUnitBuilder,\n NextFn,\n StandaloneMiddlewareContext,\n} from \"../types/units.js\";\nimport type {\n AppContext,\n LayoutId,\n ResolveLayoutMiddlewaresState,\n ResolveLayoutsState,\n} from \"../types/index.js\";\n\nexport interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {\n /**\n * Constructs a fluent unscoped middleware builder, with optional explicit State generic.\n *\n * @example\n * ```ts\n * const auth = middleware<{ user: string }>()\n * .query(z.object({ token: z.string() }))\n * .body(\"form\", z.object({ file: z.instanceof(File) }))\n * .returns({ 401: z.string() })\n * .handler(async (ctx, next) => next({ user: \"alice\" }));\n * ```\n */\n <TState = unknown>(): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n null,\n {},\n TAppContext,\n {},\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.\n */\n <const Layout extends LayoutId, TState = unknown>(\n layout: Layout,\n ): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n {},\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.\n */\n <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(\n layouts: Layouts,\n ): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n {},\n TAppContext,\n ResolveLayoutsState<Layouts>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Defines a standalone middleware scoped to a single layout branch using a short function signature.\n */\n <\n const Layout extends LayoutId,\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layout: Layout,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n unknown,\n unknown,\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n TRequires\n >;\n\n /**\n * Defines a standalone middleware scoped to multiple layout branches using a short function signature.\n */\n <\n const Layouts extends readonly [LayoutId, ...LayoutId[]],\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layouts: Layouts,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n unknown,\n unknown,\n TAppContext,\n ResolveLayoutsState<Layouts>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n TRequires\n >;\n\n /**\n * Defines a standalone, unscoped middleware using a short function signature.\n *\n * @example\n * ```ts\n * const auth = middleware((ctx, next) => {\n * return next({ user: \"alice\" });\n * });\n * ```\n */\n <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(\n fn: (\n ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n null,\n TRequires\n >;\n}\n\nexport const middleware: MiddlewareFn<AppContext> = function middleware(\n first?: any,\n second?: any,\n): any {\n if (first === undefined) {\n return createMiddlewareUnitBuilder();\n }\n\n if (typeof first === \"string\" || Array.isArray(first)) {\n if (typeof second === \"function\") {\n return {\n handler: second,\n __middlewareAcc: undefined as unknown,\n __requiredLayouts: first,\n };\n }\n return createMiddlewareUnitBuilder(first);\n }\n\n if (typeof first === \"function\") {\n return {\n handler: first,\n __middlewareAcc: undefined as unknown,\n };\n }\n\n return createMiddlewareUnitBuilder();\n};\n"],"mappings":";;AAyLA,IAAa,aAAuC,SAAS,WAC3D,OACA,QACK;CACL,IAAI,UAAU,KAAA,GACZ,OAAO,wBAAA,4BAA4B;CAGrC,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;EACrD,IAAI,OAAO,WAAW,YACpB,OAAO;GACL,SAAS;GACT,iBAAiB,KAAA;GACjB,mBAAmB;EACrB;EAEF,OAAO,wBAAA,4BAA4B,KAAK;CAC1C;CAEA,IAAI,OAAO,UAAU,YACnB,OAAO;EACL,SAAS;EACT,iBAAiB,KAAA;CACnB;CAGF,OAAO,wBAAA,4BAA4B;AACrC"}
1
+ {"version":3,"file":"middleware.cjs","names":[],"sources":["../../../src/define/middleware.ts"],"sourcesContent":["import { createMiddlewareUnitBuilder } from \"../builder/middleware-unit.js\";\nimport type {\n DefineMiddlewareResult,\n ExtractState,\n IsUnknown,\n MiddlewareRequirements,\n MiddlewareUnitBuilder,\n NextFn,\n StandaloneMiddlewareContext,\n} from \"../types/units.js\";\nimport type {\n AppContext,\n LayoutId,\n LayoutParams,\n ResolveLayoutMiddlewaresState,\n ResolveLayoutsState,\n} from \"../types/index.js\";\n\nexport interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {\n /**\n * Defines a standalone, unscoped middleware using a short function signature.\n *\n * @example\n * ```ts\n * const auth = middleware((ctx, next) => {\n * return next({ user: \"alice\" });\n * });\n * ```\n */\n <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(\n fn: (\n ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n null,\n TRequires\n >;\n\n /**\n * Constructs a fluent unscoped middleware builder, with optional explicit State generic.\n *\n * @example\n * ```ts\n * const auth = middleware<{ user: string }>()\n * .query(z.object({ token: z.string() }))\n * .body(\"form\", z.object({ file: z.instanceof(File) }))\n * .returns({ 401: z.string() })\n * .handler(async (ctx, next) => next({ user: \"alice\" }));\n * ```\n */\n <TState = unknown>(): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n null,\n {},\n TAppContext,\n {},\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Defines a standalone middleware scoped to a single layout branch using a short function signature.\n */\n <\n const Layout extends LayoutId,\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layout: Layout,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n LayoutParams<Layout>,\n unknown,\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n TRequires\n >;\n\n /**\n * Defines a standalone middleware scoped to multiple layout branches using a short function signature.\n */\n <\n const Layouts extends readonly [LayoutId, ...LayoutId[]],\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layouts: Layouts,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n LayoutParams<Layouts[number]>,\n unknown,\n TAppContext,\n ResolveLayoutsState<Layouts>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n TRequires\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.\n */\n <const Layout extends LayoutId, TState = unknown>(\n layout: Layout,\n ): MiddlewareUnitBuilder<\n unknown,\n LayoutParams<Layout>,\n unknown,\n {},\n Layout,\n {},\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.\n */\n <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(\n layouts: Layouts,\n ): MiddlewareUnitBuilder<\n unknown,\n LayoutParams<Layouts[number]>,\n unknown,\n {},\n Layouts,\n {},\n TAppContext,\n ResolveLayoutsState<Layouts>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n}\n\nexport const middleware: MiddlewareFn<AppContext> = function middleware(\n first?: any,\n second?: any,\n): any {\n if (first === undefined) {\n return createMiddlewareUnitBuilder();\n }\n\n if (typeof first === \"string\" || Array.isArray(first)) {\n if (typeof second === \"function\") {\n return {\n handler: second,\n __middlewareAcc: undefined as unknown,\n __requiredLayouts: first,\n };\n }\n return createMiddlewareUnitBuilder(first);\n }\n\n if (typeof first === \"function\") {\n return {\n handler: first,\n __middlewareAcc: undefined as unknown,\n };\n }\n\n return createMiddlewareUnitBuilder();\n};\n"],"mappings":";;AA0LA,IAAa,aAAuC,SAAS,WAC3D,OACA,QACK;CACL,IAAI,UAAU,KAAA,GACZ,OAAO,wBAAA,4BAA4B;CAGrC,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;EACrD,IAAI,OAAO,WAAW,YACpB,OAAO;GACL,SAAS;GACT,iBAAiB,KAAA;GACjB,mBAAmB;EACrB;EAEF,OAAO,wBAAA,4BAA4B,KAAK;CAC1C;CAEA,IAAI,OAAO,UAAU,YACnB,OAAO;EACL,SAAS;EACT,iBAAiB,KAAA;CACnB;CAGF,OAAO,wBAAA,4BAA4B;AACrC"}
@@ -1,6 +1,17 @@
1
1
  import { DefineMiddlewareResult, ExtractState, IsUnknown, MiddlewareRequirements, MiddlewareUnitBuilder, NextFn, StandaloneMiddlewareContext } from '../types/units.js';
2
- import { AppContext, LayoutId, ResolveLayoutMiddlewaresState, ResolveLayoutsState } from '../types/index.js';
2
+ import { AppContext, LayoutId, LayoutParams, ResolveLayoutMiddlewaresState, ResolveLayoutsState } from '../types/index.js';
3
3
  export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {
4
+ /**
5
+ * Defines a standalone, unscoped middleware using a short function signature.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const auth = middleware((ctx, next) => {
10
+ * return next({ user: "alice" });
11
+ * });
12
+ * ```
13
+ */
14
+ <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, null, TRequires>;
4
15
  /**
5
16
  * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
6
17
  *
@@ -14,32 +25,21 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
14
25
  * ```
15
26
  */
16
27
  <TState = unknown>(): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, null, {}, TAppContext, {}, unknown, unknown, unknown, TState>;
17
- /**
18
- * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
19
- */
20
- <const Layout extends LayoutId, TState = unknown>(layout: Layout): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, Layout, {}, TAppContext, ResolveLayoutMiddlewaresState<Layout>, unknown, unknown, unknown, TState>;
21
- /**
22
- * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
23
- */
24
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(layouts: Layouts): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, Layouts, {}, TAppContext, ResolveLayoutsState<Layouts>, unknown, unknown, unknown, TState>;
25
28
  /**
26
29
  * Defines a standalone middleware scoped to a single layout branch using a short function signature.
27
30
  */
28
- <const Layout extends LayoutId, TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layout: Layout, fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, ResolveLayoutMiddlewaresState<Layout>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layout, TRequires>;
31
+ <const Layout extends LayoutId, TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layout: Layout, fn: (ctx: StandaloneMiddlewareContext<unknown, LayoutParams<Layout>, unknown, TAppContext, ResolveLayoutMiddlewaresState<Layout>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layout, TRequires>;
29
32
  /**
30
33
  * Defines a standalone middleware scoped to multiple layout branches using a short function signature.
31
34
  */
32
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layouts: Layouts, fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, ResolveLayoutsState<Layouts>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layouts, TRequires>;
35
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layouts: Layouts, fn: (ctx: StandaloneMiddlewareContext<unknown, LayoutParams<Layouts[number]>, unknown, TAppContext, ResolveLayoutsState<Layouts>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layouts, TRequires>;
33
36
  /**
34
- * Defines a standalone, unscoped middleware using a short function signature.
35
- *
36
- * @example
37
- * ```ts
38
- * const auth = middleware((ctx, next) => {
39
- * return next({ user: "alice" });
40
- * });
41
- * ```
37
+ * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
42
38
  */
43
- <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, null, TRequires>;
39
+ <const Layout extends LayoutId, TState = unknown>(layout: Layout): MiddlewareUnitBuilder<unknown, LayoutParams<Layout>, unknown, {}, Layout, {}, TAppContext, ResolveLayoutMiddlewaresState<Layout>, unknown, unknown, unknown, TState>;
40
+ /**
41
+ * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
42
+ */
43
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(layouts: Layouts): MiddlewareUnitBuilder<unknown, LayoutParams<Layouts[number]>, unknown, {}, Layouts, {}, TAppContext, ResolveLayoutsState<Layouts>, unknown, unknown, unknown, TState>;
44
44
  }
45
45
  export declare const middleware: MiddlewareFn<AppContext>;
@@ -1,6 +1,10 @@
1
1
  export interface RouterRegister {
2
2
  }
3
- export type { AppContext, EmptyAppContext, HttpMethod, InferInput, InferOutput, InferRouteContext, InferRouteInput, InferRouteInputFromPath, InferRouteOutput, LayoutBuilder, LayoutId, LayoutTree, Method, MiddlewareBuilder, MiddlewareDefinition, MiddlewareUnit, MiddlewareUnitBuilder, PathParams, ReturnsMap, RouteByPathMethod, RouteDefinition, RouteExport, RoutePath, Schema, Simplify, StatusCode, } from './types/index.js';
3
+ export interface RouterMiddlewaresRegister {
4
+ }
5
+ export interface RouterRoutesRegister {
6
+ }
7
+ export type { AppContext, EmptyAppContext, HttpMethod, InferInput, InferOutput, InferRouteContext, InferRouteInput, InferRouteInputFromPath, InferRouteOutput, LayoutBuilder, LayoutId, LayoutMiddlewaresMap, LayoutParams, LayoutTree, Method, MiddlewareBuilder, MiddlewareDefinition, MiddlewareUnit, MiddlewareUnitBuilder, PathParams, ReturnsMap, RouteByPathMethod, RouteDefinition, RouteExport, RoutePath, Schema, Simplify, StatusCode, } from './types/index.js';
4
8
  export type { ContextDefinition, CreateTaserAppOptions, InferAppContext, InferAppManifest, OnErrorOptions, RouteManifestShape, } from './types/app.js';
5
9
  export { ValidationError, validationErrorSchema } from '@taserjs/router-utils';
6
10
  export type { ResponseValidationFailureHandler, SuccessStatusCode } from '@taserjs/router-utils';
@@ -1 +1 @@
1
- {"version":3,"file":"hono-mw.cjs","names":[],"sources":["../../../src/middleware/hono-mw.ts"],"sourcesContent":["import { createTaserCompatHandler } from \"@taserjs/router-core\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`\n * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.\n *\n * @example\n * ```ts\n * import { honoMw } from \"@taserjs/router\";\n * import { cors } from \"hono/cors\";\n *\n * const app = t.get(\"/hello\").use(honoMw(cors()));\n * // or\n * const customCors = middleware(honoMw(cors()));\n * ```\n */\nexport function honoMw(\n middleware: MiddlewareHandler,\n): (ctx: unknown, next: any) => Promise<Response> {\n return createTaserCompatHandler(middleware) as (ctx: unknown, next: any) => Promise<Response>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,SAAgB,OACd,YACgD;CAChD,QAAA,GAAA,qBAAA,yBAAA,CAAgC,UAAU;AAC5C"}
1
+ {"version":3,"file":"hono-mw.cjs","names":[],"sources":["../../../src/middleware/hono-mw.ts"],"sourcesContent":["import { createTaserCompatHandler } from \"@taserjs/router-core\";\nimport type { MiddlewareHandler } from \"hono\";\n\nimport type { NextFn } from \"../types/units.js\";\n\n/**\n * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`\n * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.\n *\n * @example\n * ```ts\n * import { honoMw } from \"@taserjs/router\";\n * import { cors } from \"hono/cors\";\n *\n * const app = t.get(\"/hello\").use(honoMw(cors()));\n * // or\n * const customCors = middleware(honoMw(cors()));\n * ```\n */\nexport function honoMw<TState extends Record<string, unknown> = {}>(\n middleware: MiddlewareHandler,\n): (ctx: unknown, next: NextFn<TState>) => Promise<Response> {\n return createTaserCompatHandler(middleware) as (\n ctx: unknown,\n next: NextFn<TState>,\n ) => Promise<Response>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmBA,SAAgB,OACd,YAC2D;CAC3D,QAAA,GAAA,qBAAA,yBAAA,CAAgC,UAAU;AAI5C"}
@@ -1,4 +1,5 @@
1
1
  import { MiddlewareHandler } from 'hono';
2
+ import { NextFn } from '../types/units.js';
2
3
  /**
3
4
  * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`
4
5
  * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.
@@ -13,4 +14,4 @@ import { MiddlewareHandler } from 'hono';
13
14
  * const customCors = middleware(honoMw(cors()));
14
15
  * ```
15
16
  */
16
- export declare function honoMw(middleware: MiddlewareHandler): (ctx: unknown, next: any) => Promise<Response>;
17
+ export declare function honoMw<TState extends Record<string, unknown> = {}>(middleware: MiddlewareHandler): (ctx: unknown, next: NextFn<TState>) => Promise<Response>;
@@ -1,5 +1,5 @@
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';
@@ -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>;
@@ -31,21 +38,19 @@ type ParseParam<Segment extends string> = Segment extends "*" ? {
31
38
  [K in Name]: string;
32
39
  } : {};
33
40
  type ParseParamsFromSegments<S extends string> = S extends `${infer Segment}/${infer Rest}` ? ParseParam<Segment> & ParseParamsFromSegments<Rest> : ParseParam<S>;
34
- export type PathParams<Path extends string> = Path extends `/${infer Rest}` ? ParseParamsFromSegments<Rest> : {};
41
+ export type PathParams<Path extends string> = Path extends `/${infer Rest}` ? ParseParamsFromSegments<Rest> : ParseParamsFromSegments<Path>;
42
+ export type LayoutParams<Layout extends string> = PathParams<Layout>;
35
43
  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 {
44
+ type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutTree ? LayoutTree[Layout] extends {
45
+ parent: infer P extends LayoutId;
46
+ } ? P : null : null;
47
+ type LayoutMiddlewares<Layout extends LayoutId> = [Layout] extends [keyof LayoutMiddlewaresMap] ? LayoutMiddlewaresMap[Layout] extends {
43
48
  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]>,
49
+ } ? Acc : LayoutMiddlewaresMap[Layout] extends readonly unknown[] ? LayoutMiddlewaresMap[Layout] : readonly [] : readonly [];
50
+ 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 [
51
+ ...ResolveLayoutMiddlewares<Parent, [...Depth, unknown]>,
47
52
  ...LayoutMiddlewares<Layout>
48
- ] : readonly [];
53
+ ] : readonly [...LayoutMiddlewares<Layout>] : readonly [];
49
54
  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
55
  export type ResolveLayoutMiddlewaresState<Layout extends LayoutId | null> = Layout extends LayoutId ? MergeMiddlewareField<ResolveLayoutMiddlewares<Layout>, "state"> : {};
51
56
  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 +65,18 @@ type ResolveLayoutChainMiddlewares<Chain extends readonly LayoutId[]> = Chain ex
60
65
  type RouteEntry<Path extends RoutePath, TMethod extends Method> = RouteByPathMethod[Path] extends {
61
66
  [K in TMethod]: infer Entry;
62
67
  } ? 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
68
  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 [];
69
+ layouts: infer Chain extends readonly LayoutId[];
70
+ } ? Chain : readonly [];
69
71
  export type RouteLayoutMiddlewares<Path extends RoutePath, TMethod extends Method> = ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>;
70
72
  export type RouteLayoutField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
71
73
  export type RouteLayoutInputField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body"> = MergeMiddlewareInputField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
72
74
  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
75
  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">>;
76
+ query: MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>;
77
+ params: ResolveParams<PathParams<Path>, MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>>;
78
+ body: MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>;
79
+ state: RouteResolvedField<Path, TMethod, Acc, "state">;
78
80
  headers: TaserHeaders;
79
81
  cookies: TaserCookieJar;
80
82
  }>;
@@ -167,23 +169,23 @@ export type InferRouteInputFromPath<Path extends RoutePath, TMethod extends Meth
167
169
  Input: infer I;
168
170
  };
169
171
  } ? I : never : never;
170
- export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field>;
172
+ export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = [LayoutParent<Layout>] extends [infer Parent extends LayoutId] ? MergeMiddlewareField<ResolveLayoutMiddlewares<Parent>, Field> : {};
171
173
  type MiddlewareChainField<Layout extends LayoutId, Acc extends readonly unknown[], Field extends "query" | "params" | "body" | "state"> = MiddlewareLayoutField<Layout, Field> & MergeMiddlewareField<Acc, Field>;
172
- export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery, TParams, TBody, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & UnitRuntimeContext & {
174
+ export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery = unknown, TParams = unknown, TBody = unknown, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & {
175
+ readonly request: Request;
176
+ readonly method: Method;
177
+ readonly url: URL;
178
+ readonly headers: TaserHeaders;
179
+ readonly cookies: TaserCookieJar;
173
180
  query: Simplify<MergePart<TQuery, MiddlewareChainField<Layout, Acc, "query">>>;
174
- params: Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>;
181
+ params: Simplify<ResolveParams<LayoutParams<Layout>, Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>>>;
175
182
  body: Simplify<MergePart<TBody, MiddlewareChainField<Layout, Acc, "body">>>;
176
183
  state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
177
- headers: TaserHeaders;
178
- cookies: TaserCookieJar;
179
184
  }>;
180
185
  export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unknown[] = readonly [], TAppContext extends Record<string, unknown> = AppContext> = {
181
186
  readonly layout: Layout;
182
187
  readonly middlewares: readonly MiddlewareDefinition[];
183
188
  readonly __acc?: Acc;
184
- readonly $Infer: {
185
- Context: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>;
186
- };
187
189
  use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}>(unit: [
188
190
  IsLayoutAllowed<TRequiredLayouts, ResolveLayoutIdChain<Layout>>,
189
191
  IsRequirementsSatisfied<{
@@ -192,19 +194,18 @@ export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unkn
192
194
  body: MiddlewareChainField<Layout, Acc, "body">;
193
195
  state: MiddlewareChainField<Layout, Acc, "state">;
194
196
  }, TRequires>
195
- ] extends [true, true] ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires> : {
196
- error: "Middleware cannot be attached to this layout";
197
- requiredLayouts: TRequiredLayouts;
198
- layoutChain: ResolveLayoutIdChain<Layout>;
199
- requirements: TRequires;
200
- actual: {
201
- query: MiddlewareChainField<Layout, Acc, "query">;
202
- params: MiddlewareChainField<Layout, Acc, "params">;
203
- body: MiddlewareChainField<Layout, Acc, "body">;
204
- state: MiddlewareChainField<Layout, Acc, "state">;
205
- };
206
- }): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
207
- 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>;
197
+ ] extends [true, true] ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires> : never): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
198
+ use<R = unknown>(fn: (ctx: Simplify<TAppContext & {
199
+ readonly request: Request;
200
+ readonly method: Method;
201
+ readonly url: URL;
202
+ readonly headers: TaserHeaders;
203
+ readonly cookies: TaserCookieJar;
204
+ query: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "query">>>;
205
+ params: Simplify<ResolveParams<LayoutParams<Layout>, Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "params">>>>>;
206
+ body: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "body">>>;
207
+ state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
208
+ }>, next: NextFn) => Awaitable<R>): MiddlewareBuilder<Layout, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], TAppContext>;
208
209
  };
209
210
  export type RouteExport<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], TReturns extends ReturnsMap = {}, TOutput = Response> = {
210
211
  readonly path: Path;
@@ -274,18 +275,7 @@ export type RouteMiddlewareBuilder<Path extends RoutePath, TMethod extends Metho
274
275
  body: RouteResolvedField<Path, TMethod, Acc, "body">;
275
276
  state: RouteResolvedField<Path, TMethod, Acc, "state">;
276
277
  }, TRequires>
277
- ] extends [true, true] ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires> : {
278
- error: "Middleware cannot be attached to this route";
279
- requiredLayouts: TRequiredLayouts;
280
- routeLayoutChain: RouteLayoutChain<Path, TMethod>;
281
- requirements: TRequires;
282
- actual: {
283
- query: RouteResolvedField<Path, TMethod, Acc, "query">;
284
- params: ResolveParams<PathParams<Path>, RouteResolvedField<Path, TMethod, Acc, "params">>;
285
- body: RouteResolvedField<Path, TMethod, Acc, "body">;
286
- state: RouteResolvedField<Path, TMethod, Acc, "state">;
287
- };
288
- }): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
278
+ ] extends [true, true] ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires> : never): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
289
279
  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>;
290
280
  };
291
281
  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>;
@@ -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>;
@@ -1,6 +1,17 @@
1
1
  import { DefineMiddlewareResult, ExtractState, IsUnknown, MiddlewareRequirements, MiddlewareUnitBuilder, NextFn, StandaloneMiddlewareContext } from '../types/units.js';
2
- import { AppContext, LayoutId, ResolveLayoutMiddlewaresState, ResolveLayoutsState } from '../types/index.js';
2
+ import { AppContext, LayoutId, LayoutParams, ResolveLayoutMiddlewaresState, ResolveLayoutsState } from '../types/index.js';
3
3
  export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {
4
+ /**
5
+ * Defines a standalone, unscoped middleware using a short function signature.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const auth = middleware((ctx, next) => {
10
+ * return next({ user: "alice" });
11
+ * });
12
+ * ```
13
+ */
14
+ <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, null, TRequires>;
4
15
  /**
5
16
  * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
6
17
  *
@@ -14,32 +25,21 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
14
25
  * ```
15
26
  */
16
27
  <TState = unknown>(): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, null, {}, TAppContext, {}, unknown, unknown, unknown, TState>;
17
- /**
18
- * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
19
- */
20
- <const Layout extends LayoutId, TState = unknown>(layout: Layout): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, Layout, {}, TAppContext, ResolveLayoutMiddlewaresState<Layout>, unknown, unknown, unknown, TState>;
21
- /**
22
- * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
23
- */
24
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(layouts: Layouts): MiddlewareUnitBuilder<unknown, unknown, unknown, {}, Layouts, {}, TAppContext, ResolveLayoutsState<Layouts>, unknown, unknown, unknown, TState>;
25
28
  /**
26
29
  * Defines a standalone middleware scoped to a single layout branch using a short function signature.
27
30
  */
28
- <const Layout extends LayoutId, TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layout: Layout, fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, ResolveLayoutMiddlewaresState<Layout>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layout, TRequires>;
31
+ <const Layout extends LayoutId, TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layout: Layout, fn: (ctx: StandaloneMiddlewareContext<unknown, LayoutParams<Layout>, unknown, TAppContext, ResolveLayoutMiddlewaresState<Layout>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layout, TRequires>;
29
32
  /**
30
33
  * Defines a standalone middleware scoped to multiple layout branches using a short function signature.
31
34
  */
32
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layouts: Layouts, fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, ResolveLayoutsState<Layouts>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layouts, TRequires>;
35
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(layouts: Layouts, fn: (ctx: StandaloneMiddlewareContext<unknown, LayoutParams<Layouts[number]>, unknown, TAppContext, ResolveLayoutsState<Layouts>, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, Layouts, TRequires>;
33
36
  /**
34
- * Defines a standalone, unscoped middleware using a short function signature.
35
- *
36
- * @example
37
- * ```ts
38
- * const auth = middleware((ctx, next) => {
39
- * return next({ user: "alice" });
40
- * });
41
- * ```
37
+ * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
42
38
  */
43
- <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(fn: (ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>, next: NextFn<NoInfer<TState>>) => R): DefineMiddlewareResult<unknown, unknown, unknown, IsUnknown<TState> extends true ? ExtractState<R> : TState, R, unknown, unknown, unknown, {}, null, TRequires>;
39
+ <const Layout extends LayoutId, TState = unknown>(layout: Layout): MiddlewareUnitBuilder<unknown, LayoutParams<Layout>, unknown, {}, Layout, {}, TAppContext, ResolveLayoutMiddlewaresState<Layout>, unknown, unknown, unknown, TState>;
40
+ /**
41
+ * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
42
+ */
43
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(layouts: Layouts): MiddlewareUnitBuilder<unknown, LayoutParams<Layouts[number]>, unknown, {}, Layouts, {}, TAppContext, ResolveLayoutsState<Layouts>, unknown, unknown, unknown, TState>;
44
44
  }
45
45
  export declare const middleware: MiddlewareFn<AppContext>;
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","names":[],"sources":["../../../src/define/middleware.ts"],"sourcesContent":["import { createMiddlewareUnitBuilder } from \"../builder/middleware-unit.js\";\nimport type {\n DefineMiddlewareResult,\n ExtractState,\n IsUnknown,\n MiddlewareRequirements,\n MiddlewareUnitBuilder,\n NextFn,\n StandaloneMiddlewareContext,\n} from \"../types/units.js\";\nimport type {\n AppContext,\n LayoutId,\n ResolveLayoutMiddlewaresState,\n ResolveLayoutsState,\n} from \"../types/index.js\";\n\nexport interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {\n /**\n * Constructs a fluent unscoped middleware builder, with optional explicit State generic.\n *\n * @example\n * ```ts\n * const auth = middleware<{ user: string }>()\n * .query(z.object({ token: z.string() }))\n * .body(\"form\", z.object({ file: z.instanceof(File) }))\n * .returns({ 401: z.string() })\n * .handler(async (ctx, next) => next({ user: \"alice\" }));\n * ```\n */\n <TState = unknown>(): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n null,\n {},\n TAppContext,\n {},\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.\n */\n <const Layout extends LayoutId, TState = unknown>(\n layout: Layout,\n ): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n {},\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.\n */\n <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(\n layouts: Layouts,\n ): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n {},\n TAppContext,\n ResolveLayoutsState<Layouts>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Defines a standalone middleware scoped to a single layout branch using a short function signature.\n */\n <\n const Layout extends LayoutId,\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layout: Layout,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n unknown,\n unknown,\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n TRequires\n >;\n\n /**\n * Defines a standalone middleware scoped to multiple layout branches using a short function signature.\n */\n <\n const Layouts extends readonly [LayoutId, ...LayoutId[]],\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layouts: Layouts,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n unknown,\n unknown,\n TAppContext,\n ResolveLayoutsState<Layouts>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n TRequires\n >;\n\n /**\n * Defines a standalone, unscoped middleware using a short function signature.\n *\n * @example\n * ```ts\n * const auth = middleware((ctx, next) => {\n * return next({ user: \"alice\" });\n * });\n * ```\n */\n <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(\n fn: (\n ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n null,\n TRequires\n >;\n}\n\nexport const middleware: MiddlewareFn<AppContext> = function middleware(\n first?: any,\n second?: any,\n): any {\n if (first === undefined) {\n return createMiddlewareUnitBuilder();\n }\n\n if (typeof first === \"string\" || Array.isArray(first)) {\n if (typeof second === \"function\") {\n return {\n handler: second,\n __middlewareAcc: undefined as unknown,\n __requiredLayouts: first,\n };\n }\n return createMiddlewareUnitBuilder(first);\n }\n\n if (typeof first === \"function\") {\n return {\n handler: first,\n __middlewareAcc: undefined as unknown,\n };\n }\n\n return createMiddlewareUnitBuilder();\n};\n"],"mappings":";;AAyLA,IAAa,aAAuC,SAAS,WAC3D,OACA,QACK;CACL,IAAI,UAAU,KAAA,GACZ,OAAO,4BAA4B;CAGrC,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;EACrD,IAAI,OAAO,WAAW,YACpB,OAAO;GACL,SAAS;GACT,iBAAiB,KAAA;GACjB,mBAAmB;EACrB;EAEF,OAAO,4BAA4B,KAAK;CAC1C;CAEA,IAAI,OAAO,UAAU,YACnB,OAAO;EACL,SAAS;EACT,iBAAiB,KAAA;CACnB;CAGF,OAAO,4BAA4B;AACrC"}
1
+ {"version":3,"file":"middleware.js","names":[],"sources":["../../../src/define/middleware.ts"],"sourcesContent":["import { createMiddlewareUnitBuilder } from \"../builder/middleware-unit.js\";\nimport type {\n DefineMiddlewareResult,\n ExtractState,\n IsUnknown,\n MiddlewareRequirements,\n MiddlewareUnitBuilder,\n NextFn,\n StandaloneMiddlewareContext,\n} from \"../types/units.js\";\nimport type {\n AppContext,\n LayoutId,\n LayoutParams,\n ResolveLayoutMiddlewaresState,\n ResolveLayoutsState,\n} from \"../types/index.js\";\n\nexport interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {\n /**\n * Defines a standalone, unscoped middleware using a short function signature.\n *\n * @example\n * ```ts\n * const auth = middleware((ctx, next) => {\n * return next({ user: \"alice\" });\n * });\n * ```\n */\n <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(\n fn: (\n ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n null,\n TRequires\n >;\n\n /**\n * Constructs a fluent unscoped middleware builder, with optional explicit State generic.\n *\n * @example\n * ```ts\n * const auth = middleware<{ user: string }>()\n * .query(z.object({ token: z.string() }))\n * .body(\"form\", z.object({ file: z.instanceof(File) }))\n * .returns({ 401: z.string() })\n * .handler(async (ctx, next) => next({ user: \"alice\" }));\n * ```\n */\n <TState = unknown>(): MiddlewareUnitBuilder<\n unknown,\n unknown,\n unknown,\n {},\n null,\n {},\n TAppContext,\n {},\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Defines a standalone middleware scoped to a single layout branch using a short function signature.\n */\n <\n const Layout extends LayoutId,\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layout: Layout,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n LayoutParams<Layout>,\n unknown,\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layout,\n TRequires\n >;\n\n /**\n * Defines a standalone middleware scoped to multiple layout branches using a short function signature.\n */\n <\n const Layouts extends readonly [LayoutId, ...LayoutId[]],\n TState = unknown,\n TRequires extends MiddlewareRequirements = {},\n R = unknown,\n >(\n layouts: Layouts,\n fn: (\n ctx: StandaloneMiddlewareContext<\n unknown,\n LayoutParams<Layouts[number]>,\n unknown,\n TAppContext,\n ResolveLayoutsState<Layouts>,\n TRequires\n >,\n next: NextFn<NoInfer<TState>>,\n ) => R,\n ): DefineMiddlewareResult<\n unknown,\n unknown,\n unknown,\n IsUnknown<TState> extends true ? ExtractState<R> : TState,\n R,\n unknown,\n unknown,\n unknown,\n {},\n Layouts,\n TRequires\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.\n */\n <const Layout extends LayoutId, TState = unknown>(\n layout: Layout,\n ): MiddlewareUnitBuilder<\n unknown,\n LayoutParams<Layout>,\n unknown,\n {},\n Layout,\n {},\n TAppContext,\n ResolveLayoutMiddlewaresState<Layout>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n\n /**\n * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.\n */\n <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(\n layouts: Layouts,\n ): MiddlewareUnitBuilder<\n unknown,\n LayoutParams<Layouts[number]>,\n unknown,\n {},\n Layouts,\n {},\n TAppContext,\n ResolveLayoutsState<Layouts>,\n unknown,\n unknown,\n unknown,\n TState\n >;\n}\n\nexport const middleware: MiddlewareFn<AppContext> = function middleware(\n first?: any,\n second?: any,\n): any {\n if (first === undefined) {\n return createMiddlewareUnitBuilder();\n }\n\n if (typeof first === \"string\" || Array.isArray(first)) {\n if (typeof second === \"function\") {\n return {\n handler: second,\n __middlewareAcc: undefined as unknown,\n __requiredLayouts: first,\n };\n }\n return createMiddlewareUnitBuilder(first);\n }\n\n if (typeof first === \"function\") {\n return {\n handler: first,\n __middlewareAcc: undefined as unknown,\n };\n }\n\n return createMiddlewareUnitBuilder();\n};\n"],"mappings":";;AA0LA,IAAa,aAAuC,SAAS,WAC3D,OACA,QACK;CACL,IAAI,UAAU,KAAA,GACZ,OAAO,4BAA4B;CAGrC,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;EACrD,IAAI,OAAO,WAAW,YACpB,OAAO;GACL,SAAS;GACT,iBAAiB,KAAA;GACjB,mBAAmB;EACrB;EAEF,OAAO,4BAA4B,KAAK;CAC1C;CAEA,IAAI,OAAO,UAAU,YACnB,OAAO;EACL,SAAS;EACT,iBAAiB,KAAA;CACnB;CAGF,OAAO,4BAA4B;AACrC"}
@@ -1,6 +1,10 @@
1
1
  export interface RouterRegister {
2
2
  }
3
- export type { AppContext, EmptyAppContext, HttpMethod, InferInput, InferOutput, InferRouteContext, InferRouteInput, InferRouteInputFromPath, InferRouteOutput, LayoutBuilder, LayoutId, LayoutTree, Method, MiddlewareBuilder, MiddlewareDefinition, MiddlewareUnit, MiddlewareUnitBuilder, PathParams, ReturnsMap, RouteByPathMethod, RouteDefinition, RouteExport, RoutePath, Schema, Simplify, StatusCode, } from './types/index.js';
3
+ export interface RouterMiddlewaresRegister {
4
+ }
5
+ export interface RouterRoutesRegister {
6
+ }
7
+ export type { AppContext, EmptyAppContext, HttpMethod, InferInput, InferOutput, InferRouteContext, InferRouteInput, InferRouteInputFromPath, InferRouteOutput, LayoutBuilder, LayoutId, LayoutMiddlewaresMap, LayoutParams, LayoutTree, Method, MiddlewareBuilder, MiddlewareDefinition, MiddlewareUnit, MiddlewareUnitBuilder, PathParams, ReturnsMap, RouteByPathMethod, RouteDefinition, RouteExport, RoutePath, Schema, Simplify, StatusCode, } from './types/index.js';
4
8
  export type { ContextDefinition, CreateTaserAppOptions, InferAppContext, InferAppManifest, OnErrorOptions, RouteManifestShape, } from './types/app.js';
5
9
  export { ValidationError, validationErrorSchema } from '@taserjs/router-utils';
6
10
  export type { ResponseValidationFailureHandler, SuccessStatusCode } from '@taserjs/router-utils';
@@ -1,4 +1,5 @@
1
1
  import { MiddlewareHandler } from 'hono';
2
+ import { NextFn } from '../types/units.js';
2
3
  /**
3
4
  * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`
4
5
  * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.
@@ -13,4 +14,4 @@ import { MiddlewareHandler } from 'hono';
13
14
  * const customCors = middleware(honoMw(cors()));
14
15
  * ```
15
16
  */
16
- export declare function honoMw(middleware: MiddlewareHandler): (ctx: unknown, next: any) => Promise<Response>;
17
+ export declare function honoMw<TState extends Record<string, unknown> = {}>(middleware: MiddlewareHandler): (ctx: unknown, next: NextFn<TState>) => Promise<Response>;
@@ -1 +1 @@
1
- {"version":3,"file":"hono-mw.js","names":[],"sources":["../../../src/middleware/hono-mw.ts"],"sourcesContent":["import { createTaserCompatHandler } from \"@taserjs/router-core\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`\n * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.\n *\n * @example\n * ```ts\n * import { honoMw } from \"@taserjs/router\";\n * import { cors } from \"hono/cors\";\n *\n * const app = t.get(\"/hello\").use(honoMw(cors()));\n * // or\n * const customCors = middleware(honoMw(cors()));\n * ```\n */\nexport function honoMw(\n middleware: MiddlewareHandler,\n): (ctx: unknown, next: any) => Promise<Response> {\n return createTaserCompatHandler(middleware) as (ctx: unknown, next: any) => Promise<Response>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,SAAgB,OACd,YACgD;CAChD,OAAO,yBAAyB,UAAU;AAC5C"}
1
+ {"version":3,"file":"hono-mw.js","names":[],"sources":["../../../src/middleware/hono-mw.ts"],"sourcesContent":["import { createTaserCompatHandler } from \"@taserjs/router-core\";\nimport type { MiddlewareHandler } from \"hono\";\n\nimport type { NextFn } from \"../types/units.js\";\n\n/**\n * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`\n * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.\n *\n * @example\n * ```ts\n * import { honoMw } from \"@taserjs/router\";\n * import { cors } from \"hono/cors\";\n *\n * const app = t.get(\"/hello\").use(honoMw(cors()));\n * // or\n * const customCors = middleware(honoMw(cors()));\n * ```\n */\nexport function honoMw<TState extends Record<string, unknown> = {}>(\n middleware: MiddlewareHandler,\n): (ctx: unknown, next: NextFn<TState>) => Promise<Response> {\n return createTaserCompatHandler(middleware) as (\n ctx: unknown,\n next: NextFn<TState>,\n ) => Promise<Response>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmBA,SAAgB,OACd,YAC2D;CAC3D,OAAO,yBAAyB,UAAU;AAI5C"}
@@ -1,5 +1,5 @@
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';
@@ -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>;
@@ -31,21 +38,19 @@ type ParseParam<Segment extends string> = Segment extends "*" ? {
31
38
  [K in Name]: string;
32
39
  } : {};
33
40
  type ParseParamsFromSegments<S extends string> = S extends `${infer Segment}/${infer Rest}` ? ParseParam<Segment> & ParseParamsFromSegments<Rest> : ParseParam<S>;
34
- export type PathParams<Path extends string> = Path extends `/${infer Rest}` ? ParseParamsFromSegments<Rest> : {};
41
+ export type PathParams<Path extends string> = Path extends `/${infer Rest}` ? ParseParamsFromSegments<Rest> : ParseParamsFromSegments<Path>;
42
+ export type LayoutParams<Layout extends string> = PathParams<Layout>;
35
43
  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 {
44
+ type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutTree ? LayoutTree[Layout] extends {
45
+ parent: infer P extends LayoutId;
46
+ } ? P : null : null;
47
+ type LayoutMiddlewares<Layout extends LayoutId> = [Layout] extends [keyof LayoutMiddlewaresMap] ? LayoutMiddlewaresMap[Layout] extends {
43
48
  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]>,
49
+ } ? Acc : LayoutMiddlewaresMap[Layout] extends readonly unknown[] ? LayoutMiddlewaresMap[Layout] : readonly [] : readonly [];
50
+ 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 [
51
+ ...ResolveLayoutMiddlewares<Parent, [...Depth, unknown]>,
47
52
  ...LayoutMiddlewares<Layout>
48
- ] : readonly [];
53
+ ] : readonly [...LayoutMiddlewares<Layout>] : readonly [];
49
54
  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
55
  export type ResolveLayoutMiddlewaresState<Layout extends LayoutId | null> = Layout extends LayoutId ? MergeMiddlewareField<ResolveLayoutMiddlewares<Layout>, "state"> : {};
51
56
  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 +65,18 @@ type ResolveLayoutChainMiddlewares<Chain extends readonly LayoutId[]> = Chain ex
60
65
  type RouteEntry<Path extends RoutePath, TMethod extends Method> = RouteByPathMethod[Path] extends {
61
66
  [K in TMethod]: infer Entry;
62
67
  } ? 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
68
  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 [];
69
+ layouts: infer Chain extends readonly LayoutId[];
70
+ } ? Chain : readonly [];
69
71
  export type RouteLayoutMiddlewares<Path extends RoutePath, TMethod extends Method> = ResolveLayoutChainMiddlewares<RouteLayoutChain<Path, TMethod>>;
70
72
  export type RouteLayoutField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
71
73
  export type RouteLayoutInputField<Path extends RoutePath, TMethod extends Method, Field extends "query" | "params" | "body"> = MergeMiddlewareInputField<RouteLayoutMiddlewares<Path, TMethod>, Field>;
72
74
  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
75
  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">>;
76
+ query: MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>;
77
+ params: ResolveParams<PathParams<Path>, MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>>;
78
+ body: MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>;
79
+ state: RouteResolvedField<Path, TMethod, Acc, "state">;
78
80
  headers: TaserHeaders;
79
81
  cookies: TaserCookieJar;
80
82
  }>;
@@ -167,23 +169,23 @@ export type InferRouteInputFromPath<Path extends RoutePath, TMethod extends Meth
167
169
  Input: infer I;
168
170
  };
169
171
  } ? I : never : never;
170
- export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field>;
172
+ export type MiddlewareLayoutField<Layout extends LayoutId, Field extends "query" | "params" | "body" | "state"> = [LayoutParent<Layout>] extends [infer Parent extends LayoutId] ? MergeMiddlewareField<ResolveLayoutMiddlewares<Parent>, Field> : {};
171
173
  type MiddlewareChainField<Layout extends LayoutId, Acc extends readonly unknown[], Field extends "query" | "params" | "body" | "state"> = MiddlewareLayoutField<Layout, Field> & MergeMiddlewareField<Acc, Field>;
172
- export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery, TParams, TBody, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & UnitRuntimeContext & {
174
+ export type MiddlewareChainContext<Layout extends LayoutId, Acc extends readonly unknown[], TQuery = unknown, TParams = unknown, TBody = unknown, TAppContext extends Record<string, unknown> = AppContext> = Simplify<TAppContext & {
175
+ readonly request: Request;
176
+ readonly method: Method;
177
+ readonly url: URL;
178
+ readonly headers: TaserHeaders;
179
+ readonly cookies: TaserCookieJar;
173
180
  query: Simplify<MergePart<TQuery, MiddlewareChainField<Layout, Acc, "query">>>;
174
- params: Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>;
181
+ params: Simplify<ResolveParams<LayoutParams<Layout>, Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>>>;
175
182
  body: Simplify<MergePart<TBody, MiddlewareChainField<Layout, Acc, "body">>>;
176
183
  state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
177
- headers: TaserHeaders;
178
- cookies: TaserCookieJar;
179
184
  }>;
180
185
  export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unknown[] = readonly [], TAppContext extends Record<string, unknown> = AppContext> = {
181
186
  readonly layout: Layout;
182
187
  readonly middlewares: readonly MiddlewareDefinition[];
183
188
  readonly __acc?: Acc;
184
- readonly $Infer: {
185
- Context: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>;
186
- };
187
189
  use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}>(unit: [
188
190
  IsLayoutAllowed<TRequiredLayouts, ResolveLayoutIdChain<Layout>>,
189
191
  IsRequirementsSatisfied<{
@@ -192,19 +194,18 @@ export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unkn
192
194
  body: MiddlewareChainField<Layout, Acc, "body">;
193
195
  state: MiddlewareChainField<Layout, Acc, "state">;
194
196
  }, TRequires>
195
- ] extends [true, true] ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires> : {
196
- error: "Middleware cannot be attached to this layout";
197
- requiredLayouts: TRequiredLayouts;
198
- layoutChain: ResolveLayoutIdChain<Layout>;
199
- requirements: TRequires;
200
- actual: {
201
- query: MiddlewareChainField<Layout, Acc, "query">;
202
- params: MiddlewareChainField<Layout, Acc, "params">;
203
- body: MiddlewareChainField<Layout, Acc, "body">;
204
- state: MiddlewareChainField<Layout, Acc, "state">;
205
- };
206
- }): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
207
- 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>;
197
+ ] extends [true, true] ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires> : never): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
198
+ use<R = unknown>(fn: (ctx: Simplify<TAppContext & {
199
+ readonly request: Request;
200
+ readonly method: Method;
201
+ readonly url: URL;
202
+ readonly headers: TaserHeaders;
203
+ readonly cookies: TaserCookieJar;
204
+ query: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "query">>>;
205
+ params: Simplify<ResolveParams<LayoutParams<Layout>, Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "params">>>>>;
206
+ body: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "body">>>;
207
+ state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
208
+ }>, next: NextFn) => Awaitable<R>): MiddlewareBuilder<Layout, readonly [...Acc, MiddlewareReturnFromParts<unknown, unknown, unknown, ExtractState<R>>], TAppContext>;
208
209
  };
209
210
  export type RouteExport<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], TReturns extends ReturnsMap = {}, TOutput = Response> = {
210
211
  readonly path: Path;
@@ -274,18 +275,7 @@ export type RouteMiddlewareBuilder<Path extends RoutePath, TMethod extends Metho
274
275
  body: RouteResolvedField<Path, TMethod, Acc, "body">;
275
276
  state: RouteResolvedField<Path, TMethod, Acc, "state">;
276
277
  }, TRequires>
277
- ] extends [true, true] ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires> : {
278
- error: "Middleware cannot be attached to this route";
279
- requiredLayouts: TRequiredLayouts;
280
- routeLayoutChain: RouteLayoutChain<Path, TMethod>;
281
- requirements: TRequires;
282
- actual: {
283
- query: RouteResolvedField<Path, TMethod, Acc, "query">;
284
- params: ResolveParams<PathParams<Path>, RouteResolvedField<Path, TMethod, Acc, "params">>;
285
- body: RouteResolvedField<Path, TMethod, Acc, "body">;
286
- state: RouteResolvedField<Path, TMethod, Acc, "state">;
287
- };
288
- }): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
278
+ ] extends [true, true] ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires> : never): RouteMiddlewareBuilder<Path, TMethod, readonly [...Acc, TAcc], Validators, Omit<TReturns, keyof UReturns> & UReturns, TAppContext>;
289
279
  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>;
290
280
  };
291
281
  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>;
@@ -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>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taserjs/router",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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.7",
151
- "@taserjs/router-utils": "0.1.7"
150
+ "@taserjs/router-core": "0.1.9",
151
+ "@taserjs/router-utils": "0.1.9"
152
152
  },
153
153
  "devDependencies": {
154
154
  "@tanstack/vite-config": "^0.6.0",
@@ -11,72 +11,62 @@ import type {
11
11
  import type {
12
12
  AppContext,
13
13
  LayoutId,
14
+ LayoutParams,
14
15
  ResolveLayoutMiddlewaresState,
15
16
  ResolveLayoutsState,
16
17
  } from "../types/index.js";
17
18
 
18
19
  export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppContext> {
19
20
  /**
20
- * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
21
+ * Defines a standalone, unscoped middleware using a short function signature.
21
22
  *
22
23
  * @example
23
24
  * ```ts
24
- * const auth = middleware<{ user: string }>()
25
- * .query(z.object({ token: z.string() }))
26
- * .body("form", z.object({ file: z.instanceof(File) }))
27
- * .returns({ 401: z.string() })
28
- * .handler(async (ctx, next) => next({ user: "alice" }));
25
+ * const auth = middleware((ctx, next) => {
26
+ * return next({ user: "alice" });
27
+ * });
29
28
  * ```
30
29
  */
31
- <TState = unknown>(): MiddlewareUnitBuilder<
32
- unknown,
33
- unknown,
34
- unknown,
35
- {},
36
- null,
37
- {},
38
- TAppContext,
39
- {},
30
+ <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(
31
+ fn: (
32
+ ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,
33
+ next: NextFn<NoInfer<TState>>,
34
+ ) => R,
35
+ ): DefineMiddlewareResult<
40
36
  unknown,
41
37
  unknown,
42
38
  unknown,
43
- TState
44
- >;
45
-
46
- /**
47
- * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
48
- */
49
- <const Layout extends LayoutId, TState = unknown>(
50
- layout: Layout,
51
- ): MiddlewareUnitBuilder<
39
+ IsUnknown<TState> extends true ? ExtractState<R> : TState,
40
+ R,
52
41
  unknown,
53
42
  unknown,
54
43
  unknown,
55
44
  {},
56
- Layout,
57
- {},
58
- TAppContext,
59
- ResolveLayoutMiddlewaresState<Layout>,
60
- unknown,
61
- unknown,
62
- unknown,
63
- TState
45
+ null,
46
+ TRequires
64
47
  >;
65
48
 
66
49
  /**
67
- * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
50
+ * Constructs a fluent unscoped middleware builder, with optional explicit State generic.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const auth = middleware<{ user: string }>()
55
+ * .query(z.object({ token: z.string() }))
56
+ * .body("form", z.object({ file: z.instanceof(File) }))
57
+ * .returns({ 401: z.string() })
58
+ * .handler(async (ctx, next) => next({ user: "alice" }));
59
+ * ```
68
60
  */
69
- <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(
70
- layouts: Layouts,
71
- ): MiddlewareUnitBuilder<
61
+ <TState = unknown>(): MiddlewareUnitBuilder<
72
62
  unknown,
73
63
  unknown,
74
64
  unknown,
75
65
  {},
76
- Layouts,
66
+ null,
77
67
  {},
78
68
  TAppContext,
79
- ResolveLayoutsState<Layouts>,
69
+ {},
80
70
  unknown,
81
71
  unknown,
82
72
  unknown,
@@ -96,7 +86,7 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
96
86
  fn: (
97
87
  ctx: StandaloneMiddlewareContext<
98
88
  unknown,
99
- unknown,
89
+ LayoutParams<Layout>,
100
90
  unknown,
101
91
  TAppContext,
102
92
  ResolveLayoutMiddlewaresState<Layout>,
@@ -131,7 +121,7 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
131
121
  fn: (
132
122
  ctx: StandaloneMiddlewareContext<
133
123
  unknown,
134
- unknown,
124
+ LayoutParams<Layouts[number]>,
135
125
  unknown,
136
126
  TAppContext,
137
127
  ResolveLayoutsState<Layouts>,
@@ -154,32 +144,43 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
154
144
  >;
155
145
 
156
146
  /**
157
- * Defines a standalone, unscoped middleware using a short function signature.
158
- *
159
- * @example
160
- * ```ts
161
- * const auth = middleware((ctx, next) => {
162
- * return next({ user: "alice" });
163
- * });
164
- * ```
147
+ * Constructs a fluent middleware builder scoped to a single layout branch, with optional explicit State generic.
165
148
  */
166
- <TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(
167
- fn: (
168
- ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,
169
- next: NextFn<NoInfer<TState>>,
170
- ) => R,
171
- ): DefineMiddlewareResult<
149
+ <const Layout extends LayoutId, TState = unknown>(
150
+ layout: Layout,
151
+ ): MiddlewareUnitBuilder<
172
152
  unknown,
153
+ LayoutParams<Layout>,
154
+ unknown,
155
+ {},
156
+ Layout,
157
+ {},
158
+ TAppContext,
159
+ ResolveLayoutMiddlewaresState<Layout>,
173
160
  unknown,
174
161
  unknown,
175
- IsUnknown<TState> extends true ? ExtractState<R> : TState,
176
- R,
177
162
  unknown,
163
+ TState
164
+ >;
165
+
166
+ /**
167
+ * Constructs a fluent middleware builder scoped to multiple layout branches (branch union), with optional explicit State generic.
168
+ */
169
+ <const Layouts extends readonly [LayoutId, ...LayoutId[]], TState = unknown>(
170
+ layouts: Layouts,
171
+ ): MiddlewareUnitBuilder<
178
172
  unknown,
173
+ LayoutParams<Layouts[number]>,
179
174
  unknown,
180
175
  {},
181
- null,
182
- TRequires
176
+ Layouts,
177
+ {},
178
+ TAppContext,
179
+ ResolveLayoutsState<Layouts>,
180
+ unknown,
181
+ unknown,
182
+ unknown,
183
+ TState
183
184
  >;
184
185
  }
185
186
 
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export interface RouterRegister {}
2
+ export interface RouterMiddlewaresRegister {}
3
+ export interface RouterRoutesRegister {}
2
4
  export type {
3
5
  AppContext,
4
6
  EmptyAppContext,
@@ -11,6 +13,8 @@ export type {
11
13
  InferRouteOutput,
12
14
  LayoutBuilder,
13
15
  LayoutId,
16
+ LayoutMiddlewaresMap,
17
+ LayoutParams,
14
18
  LayoutTree,
15
19
  Method,
16
20
  MiddlewareBuilder,
@@ -1,6 +1,8 @@
1
1
  import { createTaserCompatHandler } from "@taserjs/router-core";
2
2
  import type { MiddlewareHandler } from "hono";
3
3
 
4
+ import type { NextFn } from "../types/units.js";
5
+
4
6
  /**
5
7
  * Adapts a standard Web / Hono-compatible middleware function `(c, next) => ...`
6
8
  * into a Taser-compatible middleware handler function `(ctx, next) => Promise<Response>`.
@@ -15,8 +17,11 @@ import type { MiddlewareHandler } from "hono";
15
17
  * const customCors = middleware(honoMw(cors()));
16
18
  * ```
17
19
  */
18
- export function honoMw(
20
+ export function honoMw<TState extends Record<string, unknown> = {}>(
19
21
  middleware: MiddlewareHandler,
20
- ): (ctx: unknown, next: any) => Promise<Response> {
21
- return createTaserCompatHandler(middleware) as (ctx: unknown, next: any) => Promise<Response>;
22
+ ): (ctx: unknown, next: NextFn<TState>) => Promise<Response> {
23
+ return createTaserCompatHandler(middleware) as (
24
+ ctx: unknown,
25
+ next: NextFn<TState>,
26
+ ) => Promise<Response>;
22
27
  }
@@ -1,5 +1,5 @@
1
1
  import type { Awaitable, TaserCookieJar, TaserHeaders } from "@taserjs/router-core";
2
- import type { RouterRegister } from "../index.js";
2
+ import type { RouterMiddlewaresRegister, RouterRegister, RouterRoutesRegister } from "../index.js";
3
3
  import type {
4
4
  MergeMiddlewareField,
5
5
  MergeMiddlewareInputField,
@@ -74,9 +74,18 @@ export type AppContext = RouterRegister extends { AppContext: infer C } ? C : Em
74
74
  export type RoutePath = RouterRegister extends { RoutePath: infer P } ? P : never;
75
75
  export type LayoutId = RouterRegister extends { LayoutId: infer L } ? L : never;
76
76
  export type LayoutTree = RouterRegister extends { LayoutTree: infer T } ? T : Record<never, never>;
77
- export type RouteByPathMethod = RouterRegister extends { RouteByPathMethod: infer R }
77
+ export type LayoutMiddlewaresMap = RouterMiddlewaresRegister extends {
78
+ LayoutMiddlewares: infer M;
79
+ }
80
+ ? M
81
+ : RouterRegister extends { LayoutMiddlewares: infer M }
82
+ ? M
83
+ : Record<never, never>;
84
+ export type RouteByPathMethod = RouterRoutesRegister extends { RouteByPathMethod: infer R }
78
85
  ? R
79
- : Record<never, never>;
86
+ : RouterRegister extends { RouteByPathMethod: infer R }
87
+ ? R
88
+ : Record<never, never>;
80
89
 
81
90
  export type LayoutBuilder<TAppContext extends Record<string, unknown> = AppContext> = <
82
91
  const Layout extends LayoutId,
@@ -98,7 +107,9 @@ type ParseParamsFromSegments<S extends string> = S extends `${infer Segment}/${i
98
107
 
99
108
  export type PathParams<Path extends string> = Path extends `/${infer Rest}`
100
109
  ? ParseParamsFromSegments<Rest>
101
- : {};
110
+ : ParseParamsFromSegments<Path>;
111
+
112
+ export type LayoutParams<Layout extends string> = PathParams<Layout>;
102
113
 
103
114
  export type ResolveParams<TPathParams, TSchemaParams> =
104
115
  TSchemaParams extends Record<string, unknown>
@@ -107,40 +118,32 @@ export type ResolveParams<TPathParams, TSchemaParams> =
107
118
  : Simplify<Omit<TPathParams, keyof TSchemaParams> & TSchemaParams>
108
119
  : TPathParams;
109
120
 
110
- type LayoutParentsMap = RouterRegister extends {
111
- LayoutParents: infer LP extends Record<string, unknown>;
112
- }
113
- ? LP
114
- : {};
115
-
116
- type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutParentsMap
117
- ? LayoutParentsMap[Layout] extends LayoutId
118
- ? LayoutParentsMap[Layout]
121
+ type LayoutParent<Layout extends LayoutId> = Layout extends keyof LayoutTree
122
+ ? LayoutTree[Layout] extends { parent: infer P extends LayoutId }
123
+ ? P
119
124
  : null
120
- : LayoutTree[Layout] extends {
121
- parent: infer Parent extends LayoutId | null;
122
- }
123
- ? Parent
124
- : null;
125
-
126
- type LayoutMiddlewares<Layout extends LayoutId> = LayoutTree[Layout]["middlewares"] extends {
127
- readonly __acc?: infer Acc extends readonly unknown[];
128
- }
129
- ? Acc
130
- : LayoutTree[Layout]["middlewares"] extends infer Acc extends readonly unknown[]
125
+ : null;
126
+
127
+ type LayoutMiddlewares<Layout extends LayoutId> = [Layout] extends [keyof LayoutMiddlewaresMap]
128
+ ? LayoutMiddlewaresMap[Layout] extends { readonly __acc?: infer Acc extends readonly unknown[] }
131
129
  ? Acc
132
- : readonly [];
130
+ : LayoutMiddlewaresMap[Layout] extends readonly unknown[]
131
+ ? LayoutMiddlewaresMap[Layout]
132
+ : readonly []
133
+ : readonly [];
133
134
 
134
135
  type ResolveLayoutMiddlewares<
135
136
  Layout extends LayoutId | null,
136
137
  Depth extends readonly unknown[] = [],
137
138
  > = Depth["length"] extends 10
138
139
  ? readonly []
139
- : Layout extends LayoutId
140
- ? readonly [
141
- ...ResolveLayoutMiddlewares<LayoutParent<Layout>, [...Depth, unknown]>,
142
- ...LayoutMiddlewares<Layout>,
143
- ]
140
+ : [Layout] extends [LayoutId]
141
+ ? LayoutParent<Layout> extends infer Parent extends LayoutId
142
+ ? readonly [
143
+ ...ResolveLayoutMiddlewares<Parent, [...Depth, unknown]>,
144
+ ...LayoutMiddlewares<Layout>,
145
+ ]
146
+ : readonly [...LayoutMiddlewares<Layout>]
144
147
  : readonly [];
145
148
 
146
149
  export type ResolveLayoutIdChain<
@@ -184,17 +187,10 @@ type RouteEntry<Path extends RoutePath, TMethod extends Method> = RouteByPathMet
184
187
  ? Entry
185
188
  : never;
186
189
 
187
- type RouteParent<Path extends RoutePath, TMethod extends Method> =
188
- RouteEntry<Path, TMethod> extends { parent: infer Parent extends LayoutId | null }
189
- ? Parent
190
- : null;
191
-
192
190
  type RouteLayoutChain<Path extends RoutePath, TMethod extends Method> =
193
- RouteEntry<Path, TMethod> extends { layoutChain: infer Chain extends readonly LayoutId[] }
191
+ RouteEntry<Path, TMethod> extends { layouts: infer Chain extends readonly LayoutId[] }
194
192
  ? Chain
195
- : RouteParent<Path, TMethod> extends LayoutId
196
- ? readonly [RouteParent<Path, TMethod>]
197
- : readonly [];
193
+ : readonly [];
198
194
 
199
195
  export type RouteLayoutMiddlewares<
200
196
  Path extends RoutePath,
@@ -231,15 +227,13 @@ export type RouteChainContext<
231
227
  > = Simplify<
232
228
  TAppContext &
233
229
  UnitRuntimeContext & {
234
- query: Simplify<MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>>;
235
- params: Simplify<
236
- ResolveParams<
237
- PathParams<Path>,
238
- MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>
239
- >
230
+ query: MergePart<TQuery, RouteResolvedField<Path, TMethod, Acc, "query">>;
231
+ params: ResolveParams<
232
+ PathParams<Path>,
233
+ MergePart<TParams, RouteResolvedField<Path, TMethod, Acc, "params">>
240
234
  >;
241
- body: Simplify<MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>>;
242
- state: Simplify<RouteResolvedField<Path, TMethod, Acc, "state">>;
235
+ body: MergePart<TBody, RouteResolvedField<Path, TMethod, Acc, "body">>;
236
+ state: RouteResolvedField<Path, TMethod, Acc, "state">;
243
237
  headers: TaserHeaders;
244
238
  cookies: TaserCookieJar;
245
239
  }
@@ -496,7 +490,9 @@ export type InferRouteInputFromPath<Path extends RoutePath, TMethod extends Meth
496
490
  export type MiddlewareLayoutField<
497
491
  Layout extends LayoutId,
498
492
  Field extends "query" | "params" | "body" | "state",
499
- > = MergeMiddlewareField<ResolveLayoutMiddlewares<LayoutParent<Layout>>, Field>;
493
+ > = [LayoutParent<Layout>] extends [infer Parent extends LayoutId]
494
+ ? MergeMiddlewareField<ResolveLayoutMiddlewares<Parent>, Field>
495
+ : {};
500
496
 
501
497
  type MiddlewareChainField<
502
498
  Layout extends LayoutId,
@@ -507,20 +503,27 @@ type MiddlewareChainField<
507
503
  export type MiddlewareChainContext<
508
504
  Layout extends LayoutId,
509
505
  Acc extends readonly unknown[],
510
- TQuery,
511
- TParams,
512
- TBody,
506
+ TQuery = unknown,
507
+ TParams = unknown,
508
+ TBody = unknown,
513
509
  TAppContext extends Record<string, unknown> = AppContext,
514
510
  > = Simplify<
515
- TAppContext &
516
- UnitRuntimeContext & {
517
- query: Simplify<MergePart<TQuery, MiddlewareChainField<Layout, Acc, "query">>>;
518
- params: Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>;
519
- body: Simplify<MergePart<TBody, MiddlewareChainField<Layout, Acc, "body">>>;
520
- state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
521
- headers: TaserHeaders;
522
- cookies: TaserCookieJar;
523
- }
511
+ TAppContext & {
512
+ readonly request: Request;
513
+ readonly method: Method;
514
+ readonly url: URL;
515
+ readonly headers: TaserHeaders;
516
+ readonly cookies: TaserCookieJar;
517
+ query: Simplify<MergePart<TQuery, MiddlewareChainField<Layout, Acc, "query">>>;
518
+ params: Simplify<
519
+ ResolveParams<
520
+ LayoutParams<Layout>,
521
+ Simplify<MergePart<TParams, MiddlewareChainField<Layout, Acc, "params">>>
522
+ >
523
+ >;
524
+ body: Simplify<MergePart<TBody, MiddlewareChainField<Layout, Acc, "body">>>;
525
+ state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
526
+ }
524
527
  >;
525
528
 
526
529
  export type MiddlewareBuilder<
@@ -531,9 +534,6 @@ export type MiddlewareBuilder<
531
534
  readonly layout: Layout;
532
535
  readonly middlewares: readonly MiddlewareDefinition[];
533
536
  readonly __acc?: Acc;
534
- readonly $Infer: {
535
- Context: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>;
536
- };
537
537
  use<
538
538
  TAcc,
539
539
  TReturns extends ReturnsMap = {},
@@ -553,22 +553,28 @@ export type MiddlewareBuilder<
553
553
  >,
554
554
  ] extends [true, true]
555
555
  ? MiddlewareUnit<TAcc, TReturns, TRequiredLayouts, TRequires>
556
- : {
557
- error: "Middleware cannot be attached to this layout";
558
- requiredLayouts: TRequiredLayouts;
559
- layoutChain: ResolveLayoutIdChain<Layout>;
560
- requirements: TRequires;
561
- actual: {
562
- query: MiddlewareChainField<Layout, Acc, "query">;
563
- params: MiddlewareChainField<Layout, Acc, "params">;
564
- body: MiddlewareChainField<Layout, Acc, "body">;
565
- state: MiddlewareChainField<Layout, Acc, "state">;
566
- };
567
- },
556
+ : never,
568
557
  ): MiddlewareBuilder<Layout, readonly [...Acc, TAcc], TAppContext>;
569
558
  use<R = unknown>(
570
559
  fn: (
571
- ctx: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>,
560
+ ctx: Simplify<
561
+ TAppContext & {
562
+ readonly request: Request;
563
+ readonly method: Method;
564
+ readonly url: URL;
565
+ readonly headers: TaserHeaders;
566
+ readonly cookies: TaserCookieJar;
567
+ query: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "query">>>;
568
+ params: Simplify<
569
+ ResolveParams<
570
+ LayoutParams<Layout>,
571
+ Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "params">>>
572
+ >
573
+ >;
574
+ body: Simplify<MergePart<unknown, MiddlewareChainField<Layout, Acc, "body">>>;
575
+ state: Simplify<MiddlewareChainField<Layout, Acc, "state">>;
576
+ }
577
+ >,
572
578
  next: NextFn,
573
579
  ) => Awaitable<R>,
574
580
  ): MiddlewareBuilder<
@@ -747,21 +753,7 @@ export type RouteMiddlewareBuilder<
747
753
  >,
748
754
  ] extends [true, true]
749
755
  ? MiddlewareUnit<TAcc, UReturns, TRequiredLayouts, TRequires>
750
- : {
751
- error: "Middleware cannot be attached to this route";
752
- requiredLayouts: TRequiredLayouts;
753
- routeLayoutChain: RouteLayoutChain<Path, TMethod>;
754
- requirements: TRequires;
755
- actual: {
756
- query: RouteResolvedField<Path, TMethod, Acc, "query">;
757
- params: ResolveParams<
758
- PathParams<Path>,
759
- RouteResolvedField<Path, TMethod, Acc, "params">
760
- >;
761
- body: RouteResolvedField<Path, TMethod, Acc, "body">;
762
- state: RouteResolvedField<Path, TMethod, Acc, "state">;
763
- };
764
- },
756
+ : never,
765
757
  ): RouteMiddlewareBuilder<
766
758
  Path,
767
759
  TMethod,
@@ -13,7 +13,7 @@ export type UnwrapPart<T> = unknown extends T ? {} : T;
13
13
  export type MergePart<T, Base> = unknown extends T ? Base : Base & T;
14
14
 
15
15
  /** Collapse intersections so `Omit`/`keyof` treat the result as one object type. */
16
- export type Simplify<T> = { [K in keyof T]: T[K] } & {};
16
+ export type Simplify<T> = [T] extends [infer U] ? { [K in keyof U]: U[K] } : never;
17
17
 
18
18
  /**
19
19
  * Request prop: when schema input is `unknown` (e.g. zod coerce),
@@ -68,10 +68,10 @@ export type MiddlewareReturnFromParts<
68
68
  TParamsIn = TParams,
69
69
  TBodyIn = TBody,
70
70
  > = {
71
- query: Simplify<UnwrapPart<TQuery>>;
72
- params: Simplify<UnwrapPart<TParams>>;
73
- body: Simplify<UnwrapPart<TBody>>;
74
- state: Simplify<UnwrapPart<TState>>;
71
+ query: UnwrapPart<TQuery>;
72
+ params: UnwrapPart<TParams>;
73
+ body: UnwrapPart<TBody>;
74
+ state: UnwrapPart<TState>;
75
75
  /** Pre-parse shapes merged into route `$Infer.Input`. */
76
76
  input: {
77
77
  query: RequestShape<TQueryIn, TQuery>;