@taserjs/router 0.1.6 → 0.1.7
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.
- package/dist/cjs/builder/factories.cjs +2 -0
- package/dist/cjs/builder/factories.cjs.map +1 -1
- package/dist/cjs/builder/factories.d.cts +2 -1
- package/dist/cjs/builder/standalone.cjs +3 -0
- package/dist/cjs/builder/standalone.cjs.map +1 -1
- package/dist/cjs/builder/standalone.d.cts +2 -0
- package/dist/cjs/define/middleware.cjs.map +1 -1
- package/dist/cjs/define/middleware.d.cts +4 -4
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/types/index.d.cts +71 -34
- package/dist/cjs/types/units.d.cts +22 -16
- package/dist/esm/builder/factories.d.ts +2 -1
- package/dist/esm/builder/factories.js +2 -1
- package/dist/esm/builder/factories.js.map +1 -1
- package/dist/esm/builder/standalone.d.ts +2 -0
- package/dist/esm/builder/standalone.js +4 -2
- package/dist/esm/builder/standalone.js.map +1 -1
- package/dist/esm/define/middleware.d.ts +4 -4
- package/dist/esm/define/middleware.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/types/index.d.ts +71 -34
- package/dist/esm/types/units.d.ts +22 -16
- package/package.json +3 -3
- package/src/builder/factories.ts +3 -2
- package/src/builder/standalone.ts +5 -0
- package/src/define/middleware.ts +14 -6
- package/src/index.ts +1 -0
- package/src/types/index.ts +168 -67
- package/src/types/units.ts +43 -18
|
@@ -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 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
|
|
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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type { AppContext, EmptyAppContext, HttpMethod, InferInput, InferOutput,
|
|
|
4
4
|
export type { ContextDefinition, CreateTaserAppOptions, InferAppContext, InferAppManifest, OnErrorOptions, RouteManifestShape, } from './types/app.js';
|
|
5
5
|
export { ValidationError, validationErrorSchema } from '@taserjs/router-utils';
|
|
6
6
|
export type { ResponseValidationFailureHandler, SuccessStatusCode } from '@taserjs/router-utils';
|
|
7
|
-
export { all, any, del, get, head, layout, middleware, options, patch, post, put, t, type TaserNamespace, } from './builder/standalone.js';
|
|
7
|
+
export { all, any, del, get, head, layout, middleware, options, patch, post, put, query, t, type TaserNamespace, } from './builder/standalone.js';
|
|
8
8
|
export { createTaserApp, TaserRouter } from './builder/router.js';
|
|
9
9
|
export { TaserApp } from './builder/app.js';
|
|
10
10
|
export { createContext } from './context/create-context.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { all, any, del, get, head, layout, middleware, options, patch, post, put, t } from "./builder/standalone.js";
|
|
1
|
+
import { all, any, del, get, head, layout, middleware, options, patch, post, put, query, t } from "./builder/standalone.js";
|
|
2
2
|
import { TaserApp } from "./builder/app.js";
|
|
3
3
|
import { TaserRouter, createTaserApp } from "./builder/router.js";
|
|
4
4
|
import { createContext } from "./context/create-context.js";
|
|
5
5
|
import { honoMw } from "./middleware/hono-mw.js";
|
|
6
6
|
import { ValidationError, validationErrorSchema } from "@taserjs/router-utils";
|
|
7
|
-
export { TaserApp, TaserRouter, ValidationError, all, any, createContext, createTaserApp, del, get, head, honoMw, layout, middleware, options, patch, post, put, t, validationErrorSchema };
|
|
7
|
+
export { TaserApp, TaserRouter, ValidationError, all, any, createContext, createTaserApp, del, get, head, honoMw, layout, middleware, options, patch, post, put, query, t, validationErrorSchema };
|
|
@@ -3,12 +3,12 @@ import { RouterRegister } 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;
|
|
@@ -121,7 +121,25 @@ type IsEmptyObject<T> = [keyof T] extends [never] ? true : false;
|
|
|
121
121
|
export type IsLayoutAllowed<TRequiredLayouts, TChain extends readonly LayoutId[]> = [
|
|
122
122
|
TRequiredLayouts
|
|
123
123
|
] 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
|
|
124
|
+
export type IsRequirementsSatisfied<TActual extends {
|
|
125
|
+
query?: unknown;
|
|
126
|
+
params?: unknown;
|
|
127
|
+
body?: unknown;
|
|
128
|
+
state?: unknown;
|
|
129
|
+
}, 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 {
|
|
130
|
+
state: infer S extends Record<string, unknown>;
|
|
131
|
+
} ? [TActual["state"]] extends [S] ? true : false : true) extends false ? false : (TRequires extends {
|
|
132
|
+
query: infer Q extends Record<string, unknown>;
|
|
133
|
+
} ? [TActual["query"]] extends [Q] ? true : false : true) extends false ? false : (TRequires extends {
|
|
134
|
+
params: infer P extends Record<string, unknown>;
|
|
135
|
+
} ? [TActual["params"]] extends [P] ? true : false : true) extends false ? false : (TRequires extends {
|
|
136
|
+
body: infer B;
|
|
137
|
+
} ? unknown extends B ? true : [TRequires["body"]] extends [undefined] ? true : [TActual["body"]] extends [B] ? true : false : true) extends false ? false : true;
|
|
138
|
+
export type IsStateSatisfied<TActualState, TRequiredState> = IsRequirementsSatisfied<{
|
|
139
|
+
state: TActualState;
|
|
140
|
+
}, {
|
|
141
|
+
state: TRequiredState extends Record<string, unknown> ? TRequiredState : {};
|
|
142
|
+
}>;
|
|
125
143
|
type InputFacet<T, K extends string> = IsNever<T> extends true ? {} : IsEmptyObject<T> extends true ? {} : {
|
|
126
144
|
[Key in K]: T;
|
|
127
145
|
};
|
|
@@ -166,18 +184,26 @@ export type MiddlewareBuilder<Layout extends LayoutId, Acc extends readonly unkn
|
|
|
166
184
|
readonly $Infer: {
|
|
167
185
|
Context: MiddlewareChainContext<Layout, Acc, unknown, unknown, unknown, TAppContext>;
|
|
168
186
|
};
|
|
169
|
-
use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown,
|
|
187
|
+
use<TAcc, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown, TRequires extends MiddlewareRequirements = {}>(unit: [
|
|
170
188
|
IsLayoutAllowed<TRequiredLayouts, ResolveLayoutIdChain<Layout>>,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
189
|
+
IsRequirementsSatisfied<{
|
|
190
|
+
query: MiddlewareChainField<Layout, Acc, "query">;
|
|
191
|
+
params: MiddlewareChainField<Layout, Acc, "params">;
|
|
192
|
+
body: MiddlewareChainField<Layout, Acc, "body">;
|
|
193
|
+
state: MiddlewareChainField<Layout, Acc, "state">;
|
|
194
|
+
}, 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>;
|
|
181
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>;
|
|
182
208
|
};
|
|
183
209
|
export type RouteExport<Path extends RoutePath, TMethod extends Method, Acc extends readonly unknown[], TReturns extends ReturnsMap = {}, TOutput = Response> = {
|
|
@@ -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
|
|
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>):
|
|
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>):
|
|
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):
|
|
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,40 @@ 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
|
|
246
|
-
body<TBody, TBodyIn = unknown>(schema: Schema<TBody, TBodyIn>):
|
|
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>):
|
|
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> : {
|
|
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>;
|
|
289
|
+
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
|
+
};
|
|
291
|
+
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
292
|
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
293
|
export type InferRouteContext<R> = R extends {
|
|
257
294
|
$Infer: {
|
|
@@ -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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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,
|
|
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
|
|
61
|
+
readonly __requirements?: TRequires;
|
|
56
62
|
};
|
|
57
|
-
export type MiddlewareUnitBuilder<TQuery = unknown, TParams = unknown, TBody = unknown, TReturns extends ReturnsMap = {}, TRequiredLayouts = unknown,
|
|
58
|
-
query<Q, QIn = unknown>(schema: Schema<Q, QIn>): MiddlewareUnitBuilder<Q, TParams, TBody, TReturns, TRequiredLayouts,
|
|
59
|
-
params<P, PIn = unknown>(schema: Schema<P, PIn>): MiddlewareUnitBuilder<TQuery, P, TBody, TReturns, TRequiredLayouts,
|
|
60
|
-
body<B, BIn = unknown>(schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts,
|
|
61
|
-
body<Mode extends "json" | "form" | "urlencoded", B, BIn = unknown>(mode: Mode, schema: Schema<B, BIn>): MiddlewareUnitBuilder<TQuery, TParams, B, TReturns, TRequiredLayouts,
|
|
62
|
-
returns<const M extends ReturnsMap>(map: M): MiddlewareUnitBuilder<TQuery, TParams, TBody, Omit<TReturns, keyof M> & M, TRequiredLayouts,
|
|
63
|
-
requires<Requires extends
|
|
64
|
-
handler<R>(fn: (ctx: StandaloneMiddlewareContext<TQuery, TParams, TBody, TAppContext, TInheritedState
|
|
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.
|
|
3
|
+
"version": "0.1.7",
|
|
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.
|
|
151
|
-
"@taserjs/router-utils": "0.1.
|
|
150
|
+
"@taserjs/router-core": "0.1.7",
|
|
151
|
+
"@taserjs/router-utils": "0.1.7"
|
|
152
152
|
},
|
|
153
153
|
"devDependencies": {
|
|
154
154
|
"@tanstack/vite-config": "^0.6.0",
|
package/src/builder/factories.ts
CHANGED
|
@@ -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,
|
package/src/define/middleware.ts
CHANGED
|
@@ -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,
|
|
@@ -85,7 +86,12 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
|
|
|
85
86
|
/**
|
|
86
87
|
* Defines a standalone middleware scoped to a single layout branch using a short function signature.
|
|
87
88
|
*/
|
|
88
|
-
<
|
|
89
|
+
<
|
|
90
|
+
const Layout extends LayoutId,
|
|
91
|
+
TState = unknown,
|
|
92
|
+
TRequires extends MiddlewareRequirements = {},
|
|
93
|
+
R = unknown,
|
|
94
|
+
>(
|
|
89
95
|
layout: Layout,
|
|
90
96
|
fn: (
|
|
91
97
|
ctx: StandaloneMiddlewareContext<
|
|
@@ -93,7 +99,8 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
|
|
|
93
99
|
unknown,
|
|
94
100
|
unknown,
|
|
95
101
|
TAppContext,
|
|
96
|
-
ResolveLayoutMiddlewaresState<Layout
|
|
102
|
+
ResolveLayoutMiddlewaresState<Layout>,
|
|
103
|
+
TRequires
|
|
97
104
|
>,
|
|
98
105
|
next: NextFn<NoInfer<TState>>,
|
|
99
106
|
) => R,
|
|
@@ -117,7 +124,7 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
|
|
|
117
124
|
<
|
|
118
125
|
const Layouts extends readonly [LayoutId, ...LayoutId[]],
|
|
119
126
|
TState = unknown,
|
|
120
|
-
TRequires = {},
|
|
127
|
+
TRequires extends MiddlewareRequirements = {},
|
|
121
128
|
R = unknown,
|
|
122
129
|
>(
|
|
123
130
|
layouts: Layouts,
|
|
@@ -127,7 +134,8 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
|
|
|
127
134
|
unknown,
|
|
128
135
|
unknown,
|
|
129
136
|
TAppContext,
|
|
130
|
-
ResolveLayoutsState<Layouts
|
|
137
|
+
ResolveLayoutsState<Layouts>,
|
|
138
|
+
TRequires
|
|
131
139
|
>,
|
|
132
140
|
next: NextFn<NoInfer<TState>>,
|
|
133
141
|
) => R,
|
|
@@ -155,9 +163,9 @@ export interface MiddlewareFn<TAppContext extends Record<string, unknown> = AppC
|
|
|
155
163
|
* });
|
|
156
164
|
* ```
|
|
157
165
|
*/
|
|
158
|
-
<TState = unknown, TRequires = {}, R = unknown>(
|
|
166
|
+
<TState = unknown, TRequires extends MiddlewareRequirements = {}, R = unknown>(
|
|
159
167
|
fn: (
|
|
160
|
-
ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, TRequires>,
|
|
168
|
+
ctx: StandaloneMiddlewareContext<unknown, unknown, unknown, TAppContext, {}, TRequires>,
|
|
161
169
|
next: NextFn<NoInfer<TState>>,
|
|
162
170
|
) => R,
|
|
163
171
|
): DefineMiddlewareResult<
|