@minisylar/express-typed-router 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/zod-router.cjs +1 -1
- package/dist/zod-router.cjs.map +1 -1
- package/dist/zod-router.d.cts +90 -68
- package/dist/zod-router.d.ts +90 -68
- package/dist/zod-router.js +2 -1
- package/dist/zod-router.js.map +1 -1
- package/package.json +1 -1
package/dist/zod-router.cjs
CHANGED
|
@@ -32,6 +32,7 @@ var TypedRouter = class {
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Add typed middleware that extends the request with additional properties
|
|
35
|
+
* and/or adds properties to response.locals
|
|
35
36
|
*/
|
|
36
37
|
useTypedMiddleware(middleware) {
|
|
37
38
|
this.router.use(middleware);
|
|
@@ -173,7 +174,6 @@ function createTypedRouterWithMiddleware(...middleware) {
|
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
//#endregion
|
|
176
|
-
exports.TypedRouter = TypedRouter;
|
|
177
177
|
exports.createTypedRouter = createTypedRouter;
|
|
178
178
|
exports.createTypedRouterWithConfig = createTypedRouterWithConfig;
|
|
179
179
|
exports.createTypedRouterWithMiddleware = createTypedRouterWithMiddleware;
|
package/dist/zod-router.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-router.cjs","names":["middleware: TypedMiddleware<T>","path: string","optionsOrHandler: any","handler?: any","method: HttpMethod","middlewares: any[]","schema: ZodType<any, any, any>","req: Request","res: Response","next: NextFunction","z","config?: RouterConfig"],"sources":["../src/zod-router.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module @minisylar/express-typed-router\n *\n * @title @minisylar/express-typed-router\n *\n * A strongly-typed Express router with Zod validation and automatic type inference for params, body, query, and middleware.\n *\n * @example\n * // Example 1: Basic usage with router-level middleware\n * const router = createTypedRouter()\n * .useTypedMiddleware(timestampMiddleware)\n * .useTypedMiddleware(requestIdMiddleware)\n *\n * router.get('/posts/:postId', (req, res) => {\n * const { postId } = req.params // Typed as { postId: string }\n * const { timestamp, requestId } = req // Both properties are now typed correctly!\n * res.json({ postId, timestamp, requestId })\n * })\n *\n * @example\n * // Example 2: Per-route middleware with automatic type inference\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware, requestIdMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content, tags } = req.body // From schema validation\n * const { timestamp, requestId } = req // From middleware - should be automatically typed!\n * res.json({ title, content, tags, timestamp, requestId })\n * }\n * )\n *\n * @example\n * // Example 3: Mixed middleware\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n * router.get(\n * '/posts/:postId',\n * {\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req // From router-level middleware\n * const { userId, hasPermission } = req // From per-route middleware\n * res.json({ postId, requestId, userId, hasPermission })\n * }\n * )\n *\n * @example\n * // Example 4: Using factory with pre-configured middleware\n * const router = createTypedRouterWithMiddleware(timestampMiddleware, requestIdMiddleware)\n * router.get('/simple/:id', (req, res) => {\n * const { id } = req.params\n * const { timestamp, requestId } = req // Already available from factory setup!\n * res.json({ id, timestamp, requestId })\n * })\n *\n * @example\n * // Example 5: Demonstrating all HTTP methods\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n *\n * // GET with query validation\n * router.get('/posts', { querySchema: QuerySchema }, (req, res) => {\n * const { limit, offset } = req.query // Typed from schema\n * const { requestId } = req // From router middleware\n * res.json({ posts: [], limit, offset, requestId })\n * })\n *\n * // POST with body validation and middleware\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content } = req.body // From body schema\n * const { requestId, timestamp } = req // From middleware\n * res.json({ id: 'new-post', title, content, requestId, timestamp })\n * }\n * )\n *\n * // PUT for full updates\n * router.put(\n * '/posts/:postId',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { title, content } = req.body\n * const { requestId, userId, hasPermission } = req\n * res.json({ postId, title, content, requestId, userId, hasPermission })\n * }\n * )\n *\n * // PATCH for partial updates\n * router.patch('/posts/:postId', { bodySchema: UpdatePostSchema }, (req, res) => {\n * const { postId } = req.params\n * const updates = req.body // Partial update object\n * const { requestId } = req\n * res.json({ postId, updates, requestId })\n * })\n *\n * // DELETE\n * router.delete('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req\n * res.json({ deleted: postId, requestId })\n * })\n *\n * // OPTIONS for CORS preflight\n * router.options('/posts/*', (req, res) => {\n * res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE')\n * res.header('Access-Control-Allow-Headers', 'Content-Type')\n * res.status(200).end()\n * })\n *\n * // HEAD for metadata only\n * router.head('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * res.header('X-Post-ID', postId)\n * res.status(200).end()\n * })\n *\n * // ALL method for catch-all routes\n * router.all('/debug/*', (req, res) => {\n * const { requestId } = req\n * res.json({\n * method: req.method,\n * path: req.path,\n * requestId\n * })\n * })\n */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport express, {\n type Request,\n type Response,\n type NextFunction,\n} from \"express\";\nimport { z, type ZodType } from \"zod\";\n\n/**\n * Extract route parameters from Express.js route patterns.\n *\n * Supports all Express.js routing patterns:\n * - Named parameters: /users/:userId → { userId: string }\n * - Multiple parameters: /users/:userId/books/:bookId → { userId: string; bookId: string }\n * - Parameters with separators: /flights/:from-:to → { from: string; to: string }\n * - Dot notation: /plantae/:genus.:species → { genus: string; species: string }\n * - Regex constraints: /user/:id(\\\\d+) → { id: string }\n * - Optional parameters: /posts/:year/:month? → { year: string; month?: string }\n * - Wildcard parameters: /files/* → { \"0\": string }\n * - Multiple wildcards: /a/star/b/star → { \"0\": string; \"1\": string }\n */\nexport type ExtractRouteParams<Path extends string> = string extends Path\n ? Record<string, string>\n : ExtractParams<Path>;\n\n/**\n * Main parameter extraction logic - enhanced for Express 5 support\n */\ntype ExtractParams<Path extends string> =\n // Handle Express 5 braces for optional segments: {/:param} or {/path/:param}\n Path extends `${infer Before}{${infer OptionalContent}}${infer After}`\n ? ExtractOptionalSegment<OptionalContent> &\n ExtractParams<`${Before}${After}`>\n : // Handle named parameters :paramName\n Path extends `${infer _Before}:${infer Rest}`\n ? ExtractSingleParam<Rest> & ExtractParams<RemoveFirstParam<Path>>\n : // Handle wildcards *\n Path extends `${infer _Before}*${infer After}`\n ? { [K in CountWildcards<_Before>]: string } & ExtractParams<After>\n : // No more parameters\n {};\n\n/**\n * Extract parameters from Express 5 optional segments in braces\n * Handles patterns like {/:param}, {.:ext}, {/optional/:param}\n */\ntype ExtractOptionalSegment<Content extends string> =\n // Handle optional parameter patterns like /:param\n Content extends `/:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `.:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `${infer _Path}:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : {};\n\n/**\n * Extract a single optional parameter from brace content\n */\ntype ExtractOptionalParam<Rest extends string> =\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}`\n ? { [K in ParamName]?: string }\n : {};\n\n/**\n * Extract a single parameter name from the rest of the path\n * Enhanced to handle Express 5 patterns and optional parameters correctly\n * Special handling for consecutive parameters like :from-:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype ExtractSingleParam<Rest extends string> =\n // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer ParamName}(${infer _Constraint})${infer _After}`\n ? { [K in ParamName]: string } // Handle consecutive parameters with separators first: param-:nextParam\n : Rest extends `${infer ParamName}-:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer ParamName}?/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?#${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?:${infer _After}`\n ? { [K in ParamName]?: string }\n : // Then handle regular delimiters (after optional parameter patterns)\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}#${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}:${infer _After}`\n ? { [K in ParamName]: string }\n : // Handle Express 5 repeating parameters (after regular delimiters)\n Rest extends `${infer ParamName}+${infer _After}`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*${infer _After}`\n ? { [K in ParamName]?: string[] }\n : // Handle optional parameters with ? (Express 4) - only at the end of a segment\n Rest extends `${infer ParamName}?${infer _After}`\n ? { [K in ParamName]?: string } // Parameter at absolute end of string\n : Rest extends string\n ? Rest extends \"\"\n ? {}\n : Rest extends `${infer ParamName}?`\n ? { [K in ParamName]?: string } // ParamName here doesn't include the ?\n : Rest extends `${infer ParamName}+`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*`\n ? { [K in ParamName]?: string[] }\n : { [K in Rest]: string }\n : {};\n\n/**\n * Remove the first parameter from path to continue parsing\n * Enhanced to handle Express 5 patterns and optional parameters\n * Handles patterns like :from-:to by removing just :from and keeping -:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype RemoveFirstParam<Path extends string> =\n Path extends `${infer Before}:${infer Rest}`\n ? // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer _ParamName}(${infer _Constraint})${infer After}`\n ? `${Before}${After}` // Handle consecutive parameters: :param-:nextParam -> -:nextParam\n : Rest extends `${infer _ParamName}-:${infer After}`\n ? `${Before}-:${After}`\n : Rest extends `${infer _ParamName}.:${infer After}`\n ? `${Before}.:${After}`\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer _ParamName}?/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}?-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?:${infer After}`\n ? `${Before}:${After}`\n : // Handle regular separators (after optional parameter patterns)\n Rest extends `${infer _ParamName}/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}:${infer After}`\n ? `${Before}:${After}`\n : // Handle Express 5 repeating parameters (after regular separators)\n Rest extends `${infer _ParamName}+${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}*${infer After}`\n ? `${Before}${After}`\n : // Handle optional parameters with ?\n Rest extends `${infer _ParamName}?${infer After}`\n ? `${Before}${After}`\n : Before\n : Path;\n\n/**\n * Count wildcards to assign proper numeric indices\n */\ntype CountWildcards<\n Path extends string,\n Count extends string = \"0\"\n> = Path extends `${infer _Before}*${infer Rest}`\n ? CountWildcards<Rest, IncrementWildcard<Count>>\n : Count;\n\n/**\n * Helper type to increment wildcard count as string\n */\ntype IncrementWildcard<T extends string> = T extends \"0\"\n ? \"1\"\n : T extends \"1\"\n ? \"2\"\n : T extends \"2\"\n ? \"3\"\n : T extends \"3\"\n ? \"4\"\n : T extends \"4\"\n ? \"5\"\n : T extends \"5\"\n ? \"6\"\n : T extends \"6\"\n ? \"7\"\n : T extends \"7\"\n ? \"8\"\n : T extends \"8\"\n ? \"9\"\n : \"10\"; // Reasonable limit for wildcards\n\n/**\n * Express middleware that adds custom properties to the request object.\n *\n * @template T - The shape of the properties added to the request.\n * @param req - The Express request object, extended with T.\n * @param res - The Express response object.\n * @param next - The next middleware function.\n */\nexport type TypedMiddleware<T extends Record<string, any>> = (\n req: Request & T,\n res: Response,\n next: NextFunction\n) => void | Promise<void>;\n\n// Utility type to infer props from middleware array\ntype InferMiddlewareProps<T extends readonly TypedMiddleware<any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<infer FirstType>\n ? Rest extends readonly TypedMiddleware<any>[]\n ? FirstType & InferMiddlewareProps<Rest>\n : FirstType\n : {}\n : {};\n\n// Enhanced Request type with proper inference\nexport type ZodRequest<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = Omit<Request, \"params\" | \"query\" | \"body\"> & {\n params: ExtractRouteParams<Path>;\n body: BodySchema extends ZodType<any, any, any>\n ? z.infer<BodySchema>\n : unknown;\n query: QuerySchema extends ZodType<any, any, any>\n ? z.infer<QuerySchema>\n : unknown;\n} & MiddlewareProps;\n\n// Route handler type\nexport type ZodRouteHandler<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = (\n req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>,\n res: Response,\n next?: NextFunction\n) => void | Promise<void> | Response | Promise<Response>;\n\n/**\n * Options for defining a typed route, including schemas and middleware.\n *\n * @template BodySchema - Zod schema for request body validation.\n * @template QuerySchema - Zod schema for query parameter validation.\n * @property bodySchema - Optional Zod schema for validating the request body.\n * @property querySchema - Optional Zod schema for validating the query string.\n * @property middleware - Optional array of TypedMiddleware for this route.\n */\nexport interface RouteOptions<\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown\n> {\n bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;\n querySchema?: QuerySchema extends ZodType<any, any, any>\n ? QuerySchema\n : never;\n middleware?: readonly TypedMiddleware<any>[];\n}\n\n// HTTP methods\nexport type HttpMethod =\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\"\n | \"options\"\n | \"head\"\n | \"all\";\n\n// Main typed router class\nexport class TypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {}\n> {\n private router: express.Router;\n\n constructor() {\n this.router = express.Router();\n }\n\n /**\n * Add typed middleware that extends the request with additional properties\n */\n useTypedMiddleware<T extends Record<string, any>>(\n middleware: TypedMiddleware<T>\n ): TypedRouter<RouterMiddlewareProps & T> {\n this.router.use(middleware as any);\n return this as any;\n }\n\n /**\n * Get the underlying Express router\n */\n getRouter(): express.Router {\n return this.router;\n }\n\n // Method overloads for GET requests with automatic middleware type inference\n get<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Special overload for middleware type inference\n get<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Combined overload for body/query schema + middleware\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema> & { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Implementation\n get(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"get\", path, optionsOrHandler, handler);\n }\n\n // Combined overload for body/query schema + middleware (most specific first)\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Body schema only + middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Middleware only\n post<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Body + Query schema without middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Just handler, no options\n post<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n post(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"post\", path, optionsOrHandler, handler);\n }\n\n // PUT method with all the same overloads as POST\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n put(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"put\", path, optionsOrHandler, handler);\n }\n\n // PATCH method with all the same overloads as POST\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"patch\", path, optionsOrHandler, handler);\n }\n\n // DELETE method (typically no body, but can have query params and middleware)\n delete<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"delete\", path, optionsOrHandler, handler);\n }\n\n // OPTIONS method (typically no body, used for CORS preflight)\n options<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n options<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n options(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"options\", path, optionsOrHandler, handler);\n }\n\n // HEAD method (like GET but only returns headers)\n head<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n head(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"head\", path, optionsOrHandler, handler);\n }\n\n // ALL method (matches all HTTP methods)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n all(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"all\", path, optionsOrHandler, handler);\n }\n\n // Helper method to register routes\n private registerRoute(\n method: HttpMethod,\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n const middlewares: any[] = [];\n\n if (typeof optionsOrHandler === \"object\") {\n const options = optionsOrHandler as RouteOptions<any, any>;\n\n // Add per-route middleware first\n if (options.middleware) {\n middlewares.push(...options.middleware);\n }\n\n // Add schema validation middleware\n if (options.bodySchema) {\n middlewares.push(\n this.createBodyValidationMiddleware(options.bodySchema)\n );\n }\n if (options.querySchema) {\n middlewares.push(\n this.createQueryValidationMiddleware(options.querySchema)\n );\n }\n\n // Add the main handler\n middlewares.push(handler);\n } else {\n // Direct handler without options\n middlewares.push(optionsOrHandler);\n }\n\n // Register with Express router\n (this.router as any)[method](path, ...middlewares);\n\n return this;\n }\n\n private createBodyValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.body = schema.parse(req.body);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n\n private createQueryValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.query = schema.parse(req.query);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n}\n\n/**\n * Create a new strongly-typed Express router instance.\n *\n * This is the simplest way to get started with @minisylar/express-typed-router.\n *\n * @example\n * import { createTypedRouter } from '@minisylar/express-typed-router';\n *\n * // Create a router and add a typed GET route\n * const router = createTypedRouter();\n * router.get('/hello/:name', (req, res) => {\n * // req.params.name is typed as string\n * res.json({ message: `Hello, ${req.params.name}!` });\n * });\n *\n * // Use with Express\n * import express from 'express';\n * const app = express();\n * app.use('/api', router.getRouter());\n */\nexport function createTypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {}\n>(): TypedRouter<RouterMiddlewareProps> {\n return new TypedRouter<RouterMiddlewareProps>();\n}\n\n// Option 2: Factory with optional configuration\n\n/**\n * Configuration options for createTypedRouterWithConfig.\n *\n * @property validateInput - (Future) Whether to enable global input validation.\n * @property errorHandler - Optional global error handler middleware for the router.\n */\nexport interface RouterConfig {\n validateInput?: boolean;\n errorHandler?: (\n error: any,\n req: Request,\n res: Response,\n next: NextFunction\n ) => void;\n}\n\n/**\n * Create a new typed router with optional configuration.\n *\n * Use this if you want to add a global error handler or future global options.\n *\n * @param config - Optional configuration for the router (e.g. error handler).\n * @returns A new TypedRouter instance.\n *\n * @example\n * import { createTypedRouterWithConfig } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithConfig({\n * errorHandler: (err, req, res, next) => {\n * res.status(500).json({ error: 'Something went wrong', details: err });\n * }\n * });\n */\nexport function createTypedRouterWithConfig<\n RouterMiddlewareProps extends Record<string, any> = {}\n>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps> {\n const router = new TypedRouter<RouterMiddlewareProps>();\n if (config?.errorHandler) {\n router.getRouter().use(config.errorHandler);\n }\n return router;\n}\n\n// Option 3: Factory with pre-configured middleware\n\n/**\n * Create a new typed router with pre-configured middleware.\n *\n * This is useful for setting up router-level middleware in a single call.\n *\n * @param middleware - One or more TypedMiddleware functions to apply to all routes.\n * @returns A new TypedRouter instance with the middleware applied.\n *\n * @example\n * import { createTypedRouterWithMiddleware } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);\n */\nexport function createTypedRouterWithMiddleware<T extends Record<string, any>>(\n ...middleware: TypedMiddleware<any>[]\n): TypedRouter<T> {\n let router = new TypedRouter() as any;\n for (const mw of middleware) {\n router = router.useTypedMiddleware(mw);\n }\n return router;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA8aA,IAAa,cAAb,MAEE;CACA,AAAQ;CAER,cAAc;AACZ,OAAK,SAAS,gBAAQ,QAAQ;CAC/B;;;;CAKD,mBACEA,YACwC;AACxC,OAAK,OAAO,IAAI,WAAkB;AAClC,SAAO;CACR;;;;CAKD,YAA4B;AAC1B,SAAO,KAAK;CACb;CAqDD,IACEC,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAyED,KACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqED,IACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAwED,MACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,SAAS,MAAM,kBAAkB,QAAQ;CACpE;CA8CD,OACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,UAAU,MAAM,kBAAkB,QAAQ;CACrE;CAsBD,QACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,WAAW,MAAM,kBAAkB,QAAQ;CACtE;CA2CD,KACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqED,IACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAGD,AAAQ,cACNC,QACAH,MACAC,kBACAC,SACoC;EACpC,MAAME,cAAqB,CAAE;AAE7B,aAAW,qBAAqB,UAAU;GACxC,MAAM,UAAU;AAGhB,OAAI,QAAQ,WACV,aAAY,KAAK,GAAG,QAAQ,WAAW;AAIzC,OAAI,QAAQ,WACV,aAAY,KACV,KAAK,+BAA+B,QAAQ,WAAW,CACxD;AAEH,OAAI,QAAQ,YACV,aAAY,KACV,KAAK,gCAAgC,QAAQ,YAAY,CAC1D;AAIH,eAAY,KAAK,QAAQ;EAC1B,MAEC,aAAY,KAAK,iBAAiB;AAIpC,EAAC,KAAK,OAAe,QAAQ,MAAM,GAAG,YAAY;AAElD,SAAO;CACR;CAED,AAAQ,+BAA+BC,QAAgC;AACrE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,OAAO,OAAO,MAAM,IAAI,KAAK;AACjC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiBC,MAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;CAED,AAAQ,gCAAgCJ,QAAgC;AACtE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,QAAQ,OAAO,MAAM,IAAI,MAAM;AACnC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiBC,MAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,oBAEwB;AACtC,QAAO,IAAI;AACZ;;;;;;;;;;;;;;;;;;AAqCD,SAAgB,4BAEdC,QAA2D;CAC3D,MAAM,SAAS,IAAI;AACnB,KAAI,QAAQ,aACV,QAAO,WAAW,CAAC,IAAI,OAAO,aAAa;AAE7C,QAAO;AACR;;;;;;;;;;;;;;AAiBD,SAAgB,gCACd,GAAG,YACa;CAChB,IAAI,SAAS,IAAI;AACjB,MAAK,MAAM,MAAM,WACf,UAAS,OAAO,mBAAmB,GAAG;AAExC,QAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"zod-router.cjs","names":["middleware: TypedMiddleware<TReq, TLocals>","path: string","optionsOrHandler: any","handler?: any","method: HttpMethod","middlewares: any[]","schema: ZodType<any, any, any>","req: Request","res: Response","next: NextFunction","z","config?: RouterConfig"],"sources":["../src/zod-router.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module @minisylar/express-typed-router\n *\n * @title @minisylar/express-typed-router\n *\n * A strongly-typed Express router with Zod validation and automatic type inference for params, body, query, and middleware.\n *\n * @example\n * // Example 1: Basic usage with router-level middleware\n * const router = createTypedRouter()\n * .useTypedMiddleware(timestampMiddleware)\n * .useTypedMiddleware(requestIdMiddleware)\n *\n * router.get('/posts/:postId', (req, res) => {\n * const { postId } = req.params // Typed as { postId: string }\n * const { timestamp, requestId } = req // Both properties are now typed correctly!\n * res.json({ postId, timestamp, requestId })\n * })\n *\n * @example\n * // Example 2: Per-route middleware with automatic type inference\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware, requestIdMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content, tags } = req.body // From schema validation\n * const { timestamp, requestId } = req // From middleware - should be automatically typed!\n * res.json({ title, content, tags, timestamp, requestId })\n * }\n * )\n *\n * @example\n * // Example 3: Mixed middleware\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n * router.get(\n * '/posts/:postId',\n * {\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req // From router-level middleware\n * const { userId, hasPermission } = req // From per-route middleware\n * res.json({ postId, requestId, userId, hasPermission })\n * }\n * )\n *\n * @example\n * // Example 4: Using factory with pre-configured middleware\n * const router = createTypedRouterWithMiddleware(timestampMiddleware, requestIdMiddleware)\n * router.get('/simple/:id', (req, res) => {\n * const { id } = req.params\n * const { timestamp, requestId } = req // Already available from factory setup!\n * res.json({ id, timestamp, requestId })\n * })\n *\n * @example\n * // Example 5: Demonstrating all HTTP methods\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n *\n * // GET with query validation\n * router.get('/posts', { querySchema: QuerySchema }, (req, res) => {\n * const { limit, offset } = req.query // Typed from schema\n * const { requestId } = req // From router middleware\n * res.json({ posts: [], limit, offset, requestId })\n * })\n *\n * // POST with body validation and middleware\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content } = req.body // From body schema\n * const { requestId, timestamp } = req // From middleware\n * res.json({ id: 'new-post', title, content, requestId, timestamp })\n * }\n * )\n *\n * // PUT for full updates\n * router.put(\n * '/posts/:postId',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { title, content } = req.body\n * const { requestId, userId, hasPermission } = req\n * res.json({ postId, title, content, requestId, userId, hasPermission })\n * }\n * )\n *\n * // PATCH for partial updates\n * router.patch('/posts/:postId', { bodySchema: UpdatePostSchema }, (req, res) => {\n * const { postId } = req.params\n * const updates = req.body // Partial update object\n * const { requestId } = req\n * res.json({ postId, updates, requestId })\n * })\n *\n * // DELETE\n * router.delete('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req\n * res.json({ deleted: postId, requestId })\n * })\n *\n * // OPTIONS for CORS preflight\n * router.options('/posts/*', (req, res) => {\n * res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE')\n * res.header('Access-Control-Allow-Headers', 'Content-Type')\n * res.status(200).end()\n * })\n *\n * // HEAD for metadata only\n * router.head('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * res.header('X-Post-ID', postId)\n * res.status(200).end()\n * })\n *\n * // ALL method for catch-all routes\n * router.all('/debug/*', (req, res) => {\n * const { requestId } = req\n * res.json({\n * method: req.method,\n * path: req.path,\n * requestId\n * })\n * })\n */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport express, {\n type Request,\n type Response,\n type NextFunction,\n} from \"express\";\nimport { z, type ZodType } from \"zod\";\n\n/**\n * Extract route parameters from Express.js route patterns.\n *\n * Supports all Express.js routing patterns:\n * - Named parameters: /users/:userId → { userId: string }\n * - Multiple parameters: /users/:userId/books/:bookId → { userId: string; bookId: string }\n * - Parameters with separators: /flights/:from-:to → { from: string; to: string }\n * - Dot notation: /plantae/:genus.:species → { genus: string; species: string }\n * - Regex constraints: /user/:id(\\\\d+) → { id: string }\n * - Optional parameters: /posts/:year/:month? → { year: string; month?: string }\n * - Wildcard parameters: /files/* → { \"0\": string }\n * - Multiple wildcards: /a/star/b/star → { \"0\": string; \"1\": string }\n */\nexport type ExtractRouteParams<Path extends string> = string extends Path\n ? Record<string, string>\n : ExtractParams<Path>;\n\n/**\n * Main parameter extraction logic - enhanced for Express 5 support\n */\ntype ExtractParams<Path extends string> =\n // Handle Express 5 braces for optional segments: {/:param} or {/path/:param}\n Path extends `${infer Before}{${infer OptionalContent}}${infer After}`\n ? ExtractOptionalSegment<OptionalContent> &\n ExtractParams<`${Before}${After}`>\n : // Handle named parameters :paramName\n Path extends `${infer _Before}:${infer Rest}`\n ? ExtractSingleParam<Rest> & ExtractParams<RemoveFirstParam<Path>>\n : // Handle wildcards *\n Path extends `${infer _Before}*${infer After}`\n ? { [K in CountWildcards<_Before>]: string } & ExtractParams<After>\n : // No more parameters\n {};\n\n/**\n * Extract parameters from Express 5 optional segments in braces\n * Handles patterns like {/:param}, {.:ext}, {/optional/:param}\n */\ntype ExtractOptionalSegment<Content extends string> =\n // Handle optional parameter patterns like /:param\n Content extends `/:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `.:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `${infer _Path}:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : {};\n\n/**\n * Extract a single optional parameter from brace content\n */\ntype ExtractOptionalParam<Rest extends string> =\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}`\n ? { [K in ParamName]?: string }\n : {};\n\n/**\n * Extract a single parameter name from the rest of the path\n * Enhanced to handle Express 5 patterns and optional parameters correctly\n * Special handling for consecutive parameters like :from-:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype ExtractSingleParam<Rest extends string> =\n // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer ParamName}(${infer _Constraint})${infer _After}`\n ? { [K in ParamName]: string } // Handle consecutive parameters with separators first: param-:nextParam\n : Rest extends `${infer ParamName}-:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer ParamName}?/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?#${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?:${infer _After}`\n ? { [K in ParamName]?: string }\n : // Then handle regular delimiters (after optional parameter patterns)\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}#${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}:${infer _After}`\n ? { [K in ParamName]: string }\n : // Handle Express 5 repeating parameters (after regular delimiters)\n Rest extends `${infer ParamName}+${infer _After}`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*${infer _After}`\n ? { [K in ParamName]?: string[] }\n : // Handle optional parameters with ? (Express 4) - only at the end of a segment\n Rest extends `${infer ParamName}?${infer _After}`\n ? { [K in ParamName]?: string } // Parameter at absolute end of string\n : Rest extends string\n ? Rest extends \"\"\n ? {}\n : Rest extends `${infer ParamName}?`\n ? { [K in ParamName]?: string } // ParamName here doesn't include the ?\n : Rest extends `${infer ParamName}+`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*`\n ? { [K in ParamName]?: string[] }\n : { [K in Rest]: string }\n : {};\n\n/**\n * Remove the first parameter from path to continue parsing\n * Enhanced to handle Express 5 patterns and optional parameters\n * Handles patterns like :from-:to by removing just :from and keeping -:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype RemoveFirstParam<Path extends string> =\n Path extends `${infer Before}:${infer Rest}`\n ? // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer _ParamName}(${infer _Constraint})${infer After}`\n ? `${Before}${After}` // Handle consecutive parameters: :param-:nextParam -> -:nextParam\n : Rest extends `${infer _ParamName}-:${infer After}`\n ? `${Before}-:${After}`\n : Rest extends `${infer _ParamName}.:${infer After}`\n ? `${Before}.:${After}`\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer _ParamName}?/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}?-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?:${infer After}`\n ? `${Before}:${After}`\n : // Handle regular separators (after optional parameter patterns)\n Rest extends `${infer _ParamName}/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}:${infer After}`\n ? `${Before}:${After}`\n : // Handle Express 5 repeating parameters (after regular separators)\n Rest extends `${infer _ParamName}+${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}*${infer After}`\n ? `${Before}${After}`\n : // Handle optional parameters with ?\n Rest extends `${infer _ParamName}?${infer After}`\n ? `${Before}${After}`\n : Before\n : Path;\n\n/**\n * Count wildcards to assign proper numeric indices\n */\ntype CountWildcards<\n Path extends string,\n Count extends string = \"0\"\n> = Path extends `${infer _Before}*${infer Rest}`\n ? CountWildcards<Rest, IncrementWildcard<Count>>\n : Count;\n\n/**\n * Helper type to increment wildcard count as string\n */\ntype IncrementWildcard<T extends string> = T extends \"0\"\n ? \"1\"\n : T extends \"1\"\n ? \"2\"\n : T extends \"2\"\n ? \"3\"\n : T extends \"3\"\n ? \"4\"\n : T extends \"4\"\n ? \"5\"\n : T extends \"5\"\n ? \"6\"\n : T extends \"6\"\n ? \"7\"\n : T extends \"7\"\n ? \"8\"\n : T extends \"8\"\n ? \"9\"\n : \"10\"; // Reasonable limit for wildcards\n\n/**\n * Express middleware that adds custom properties to the request object and/or response locals.\n *\n * @template TReq - The shape of the properties added to the request object.\n * @template TLocals - The shape of the properties added to response.locals.\n * @param req - The Express request object, extended with TReq.\n * @param res - The Express response object with typed locals.\n * @param next - The next middleware function.\n */\nexport type TypedMiddleware<\n TReq extends Record<string, any> = {},\n TLocals extends Record<string, any> = {}\n> = (\n req: Request & TReq,\n res: Response<any, TLocals>,\n next: NextFunction\n) => void | Promise<void>;\n\n/**\n * Simplified TypedMiddleware for request-only extensions (backward compatibility)\n */\nexport type RequestOnlyMiddleware<TReq extends Record<string, any>> =\n TypedMiddleware<TReq, {}>;\n\n/**\n * Simplified TypedMiddleware for response locals-only extensions\n */\nexport type LocalsOnlyMiddleware<TLocals extends Record<string, any>> =\n TypedMiddleware<{}, TLocals>;\n\n// Utility type to infer props from middleware array\ntype InferMiddlewareProps<T extends readonly TypedMiddleware<any, any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<infer FirstReq, any>\n ? Rest extends readonly TypedMiddleware<any, any>[]\n ? FirstReq & InferMiddlewareProps<Rest>\n : FirstReq\n : {}\n : {};\n\n// Utility type to infer locals from middleware array\ntype InferMiddlewareLocals<T extends readonly TypedMiddleware<any, any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<any, infer FirstLocals>\n ? Rest extends readonly TypedMiddleware<any, any>[]\n ? FirstLocals & InferMiddlewareLocals<Rest>\n : FirstLocals\n : {}\n : {};\n\n// Enhanced Request type with proper inference\nexport type ZodRequest<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = Omit<Request, \"params\" | \"query\" | \"body\"> & {\n params: ExtractRouteParams<Path>;\n body: BodySchema extends ZodType<any, any, any>\n ? z.infer<BodySchema>\n : unknown;\n query: QuerySchema extends ZodType<any, any, any>\n ? z.infer<QuerySchema>\n : unknown;\n} & MiddlewareProps;\n\n// Route handler type\nexport type ZodRouteHandler<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {},\n ResponseLocals extends Record<string, any> = {}\n> = (\n req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>,\n res: Response<any, ResponseLocals>,\n next?: NextFunction\n) => void | Promise<void> | Response | Promise<Response>;\n\n/**\n * Options for defining a typed route, including schemas and middleware.\n *\n * @template BodySchema - Zod schema for request body validation.\n * @template QuerySchema - Zod schema for query parameter validation.\n * @property bodySchema - Optional Zod schema for validating the request body.\n * @property querySchema - Optional Zod schema for validating the query string.\n * @property middleware - Optional array of TypedMiddleware for this route.\n */\nexport interface RouteOptions<\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown\n> {\n bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;\n querySchema?: QuerySchema extends ZodType<any, any, any>\n ? QuerySchema\n : never;\n middleware?: readonly TypedMiddleware<any, any>[];\n}\n\n// HTTP methods\nexport type HttpMethod =\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\"\n | \"options\"\n | \"head\"\n | \"all\";\n\n// Main typed router class\nclass TypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n> {\n private router: express.Router;\n\n constructor() {\n this.router = express.Router();\n }\n /**\n * Add typed middleware that extends the request with additional properties\n * and/or adds properties to response.locals\n */\n useTypedMiddleware<\n TReq extends Record<string, any> = {},\n TLocals extends Record<string, any> = {}\n >(\n middleware: TypedMiddleware<TReq, TLocals>\n ): TypedRouter<RouterMiddlewareProps & TReq, RouterLocals & TLocals> {\n this.router.use(middleware as any);\n return this as any;\n }\n /**\n * Get the underlying Express router\n */\n getRouter(): express.Router {\n return this.router;\n }\n // Method overloads for GET requests with automatic middleware type inference\n get<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Special overload for middleware type inference\n get<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Combined overload for body/query schema + middleware\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema> & { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n // Implementation\n get(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"get\", path, optionsOrHandler, handler);\n }\n // Combined overload for body/query schema + middleware (most specific first)\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body schema only + middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n post<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body + Query schema without middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Just handler, no options\n post<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n post(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"post\", path, optionsOrHandler, handler);\n }\n // PUT method with all the same overloads as POST\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n put(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"put\", path, optionsOrHandler, handler);\n }\n // PATCH method with all the same overloads as POST\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n patch(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"patch\", path, optionsOrHandler, handler);\n } // DELETE method (typically no body, but can have query params and middleware)\n // Most specific first: query schema + middleware\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n delete<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n delete<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n delete(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"delete\", path, optionsOrHandler, handler);\n } // OPTIONS method (typically no body, used for CORS preflight)\n // Most specific first: query schema + middleware\n options<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n options<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n options<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n options<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n options(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"options\", path, optionsOrHandler, handler);\n } // HEAD method (like GET but only returns headers)\n // Most specific first: query schema + middleware\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n head<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n head<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n head(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"head\", path, optionsOrHandler, handler);\n } // ALL method (matches all HTTP methods)\n // Most specific first: body + query + middleware\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body schema + middleware (no query)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema + middleware (no body)\n all<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body + query schemas (no middleware)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only (no schemas)\n all<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n all<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n all(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"all\", path, optionsOrHandler, handler);\n }\n // Helper method to register routes\n private registerRoute(\n method: HttpMethod,\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n const middlewares: any[] = [];\n\n if (typeof optionsOrHandler === \"object\") {\n const options = optionsOrHandler as RouteOptions<any, any>;\n\n // Add per-route middleware first\n if (options.middleware) {\n middlewares.push(...options.middleware);\n }\n\n // Add schema validation middleware\n if (options.bodySchema) {\n middlewares.push(\n this.createBodyValidationMiddleware(options.bodySchema)\n );\n }\n if (options.querySchema) {\n middlewares.push(\n this.createQueryValidationMiddleware(options.querySchema)\n );\n }\n\n // Add the main handler\n middlewares.push(handler);\n } else {\n // Direct handler without options\n middlewares.push(optionsOrHandler);\n }\n\n // Register with Express router\n (this.router as any)[method](path, ...middlewares);\n\n return this;\n }\n\n private createBodyValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.body = schema.parse(req.body);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n\n private createQueryValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.query = schema.parse(req.query);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n}\n\n/**\n * Create a new strongly-typed Express router instance.\n *\n * This is the simplest way to get started with @minisylar/express-typed-router.\n *\n * @example\n * import { createTypedRouter } from '@minisylar/express-typed-router';\n *\n * // Create a router and add a typed GET route\n * const router = createTypedRouter();\n * router.get('/hello/:name', (req, res) => {\n * // req.params.name is typed as string\n * res.json({ message: `Hello, ${req.params.name}!` });\n * });\n *\n * // Use with Express\n * import express from 'express';\n * const app = express();\n * app.use('/api', router.getRouter());\n */\nexport function createTypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n>(): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return new TypedRouter<RouterMiddlewareProps, RouterLocals>();\n}\n\n// Option 2: Factory with optional configuration\n\n/**\n * Configuration options for createTypedRouterWithConfig.\n *\n * @property validateInput - (Future) Whether to enable global input validation.\n * @property errorHandler - Optional global error handler middleware for the router.\n */\nexport interface RouterConfig {\n validateInput?: boolean;\n errorHandler?: (\n error: any,\n req: Request,\n res: Response,\n next: NextFunction\n ) => void;\n}\n\n/**\n * Create a new typed router with optional configuration.\n *\n * Use this if you want to add a global error handler or future global options.\n *\n * @param config - Optional configuration for the router (e.g. error handler).\n * @returns A new TypedRouter instance.\n *\n * @example\n * import { createTypedRouterWithConfig } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithConfig({\n * errorHandler: (err, req, res, next) => {\n * res.status(500).json({ error: 'Something went wrong', details: err });\n * }\n * });\n */\nexport function createTypedRouterWithConfig<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n const router = new TypedRouter<RouterMiddlewareProps, RouterLocals>();\n if (config?.errorHandler) {\n router.getRouter().use(config.errorHandler);\n }\n return router;\n}\n\n// Option 3: Factory with pre-configured middleware\n\n/**\n * Create a new typed router with pre-configured middleware.\n *\n * This is useful for setting up router-level middleware in a single call.\n *\n * @param middleware - One or more TypedMiddleware functions to apply to all routes.\n * @returns A new TypedRouter instance with the middleware applied.\n *\n * @example\n * import { createTypedRouterWithMiddleware } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);\n */\nexport function createTypedRouterWithMiddleware<T extends Record<string, any>>(\n ...middleware: TypedMiddleware<any, any>[]\n): TypedRouter<T> {\n let router = new TypedRouter() as any;\n for (const mw of middleware) {\n router = router.useTypedMiddleware(mw);\n }\n return router;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAycA,IAAM,cAAN,MAGE;CACA,AAAQ;CAER,cAAc;AACZ,OAAK,SAAS,gBAAQ,QAAQ;CAC/B;;;;;CAKD,mBAIEA,YACmE;AACnE,OAAK,OAAO,IAAI,WAAkB;AAClC,SAAO;CACR;;;;CAID,YAA4B;AAC1B,SAAO,KAAK;CACb;CA+DD,IACEC,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAqFD,KACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAgFD,IACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAgFD,MACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,SAAS,MAAM,kBAAkB,QAAQ;CACpE;CA6DD,OACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,UAAU,MAAM,kBAAkB,QAAQ;CACrE;CA6DD,QACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,WAAW,MAAM,kBAAkB,QAAQ;CACtE;CA6DD,KACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqGD,IACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAED,AAAQ,cACNC,QACAH,MACAC,kBACAC,SACkD;EAClD,MAAME,cAAqB,CAAE;AAE7B,aAAW,qBAAqB,UAAU;GACxC,MAAM,UAAU;AAGhB,OAAI,QAAQ,WACV,aAAY,KAAK,GAAG,QAAQ,WAAW;AAIzC,OAAI,QAAQ,WACV,aAAY,KACV,KAAK,+BAA+B,QAAQ,WAAW,CACxD;AAEH,OAAI,QAAQ,YACV,aAAY,KACV,KAAK,gCAAgC,QAAQ,YAAY,CAC1D;AAIH,eAAY,KAAK,QAAQ;EAC1B,MAEC,aAAY,KAAK,iBAAiB;AAIpC,EAAC,KAAK,OAAe,QAAQ,MAAM,GAAG,YAAY;AAElD,SAAO;CACR;CAED,AAAQ,+BAA+BC,QAAgC;AACrE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,OAAO,OAAO,MAAM,IAAI,KAAK;AACjC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiBC,MAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;CAED,AAAQ,gCAAgCJ,QAAgC;AACtE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,QAAQ,OAAO,MAAM,IAAI,MAAM;AACnC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiBC,MAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,oBAGsC;AACpD,QAAO,IAAI;AACZ;;;;;;;;;;;;;;;;;;AAqCD,SAAgB,4BAGdC,QAAyE;CACzE,MAAM,SAAS,IAAI;AACnB,KAAI,QAAQ,aACV,QAAO,WAAW,CAAC,IAAI,OAAO,aAAa;AAE7C,QAAO;AACR;;;;;;;;;;;;;;AAiBD,SAAgB,gCACd,GAAG,YACa;CAChB,IAAI,SAAS,IAAI;AACjB,MAAK,MAAM,MAAM,WACf,UAAS,OAAO,mBAAmB,GAAG;AAExC,QAAO;AACR"}
|
package/dist/zod-router.d.cts
CHANGED
|
@@ -66,21 +66,31 @@ type CountWildcards<Path extends string, Count extends string = "0"> = Path exte
|
|
|
66
66
|
*/
|
|
67
67
|
type IncrementWildcard<T extends string> = T extends "0" ? "1" : T extends "1" ? "2" : T extends "2" ? "3" : T extends "3" ? "4" : T extends "4" ? "5" : T extends "5" ? "6" : T extends "6" ? "7" : T extends "7" ? "8" : T extends "8" ? "9" : "10";
|
|
68
68
|
/**
|
|
69
|
-
* Express middleware that adds custom properties to the request object.
|
|
69
|
+
* Express middleware that adds custom properties to the request object and/or response locals.
|
|
70
70
|
*
|
|
71
|
-
* @template
|
|
72
|
-
* @
|
|
73
|
-
* @param
|
|
71
|
+
* @template TReq - The shape of the properties added to the request object.
|
|
72
|
+
* @template TLocals - The shape of the properties added to response.locals.
|
|
73
|
+
* @param req - The Express request object, extended with TReq.
|
|
74
|
+
* @param res - The Express response object with typed locals.
|
|
74
75
|
* @param next - The next middleware function.
|
|
75
76
|
*/
|
|
76
|
-
type TypedMiddleware<
|
|
77
|
-
|
|
77
|
+
type TypedMiddleware<TReq extends Record<string, any> = {}, TLocals extends Record<string, any> = {}> = (req: Request & TReq, res: Response<any, TLocals>, next: NextFunction) => void | Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Simplified TypedMiddleware for request-only extensions (backward compatibility)
|
|
80
|
+
*/
|
|
81
|
+
type RequestOnlyMiddleware<TReq extends Record<string, any>> = TypedMiddleware<TReq, {}>;
|
|
82
|
+
/**
|
|
83
|
+
* Simplified TypedMiddleware for response locals-only extensions
|
|
84
|
+
*/
|
|
85
|
+
type LocalsOnlyMiddleware<TLocals extends Record<string, any>> = TypedMiddleware<{}, TLocals>;
|
|
86
|
+
type InferMiddlewareProps<T extends readonly TypedMiddleware<any, any>[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<infer FirstReq, any> ? Rest extends readonly TypedMiddleware<any, any>[] ? FirstReq & InferMiddlewareProps<Rest> : FirstReq : {} : {};
|
|
87
|
+
type InferMiddlewareLocals<T extends readonly TypedMiddleware<any, any>[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<any, infer FirstLocals> ? Rest extends readonly TypedMiddleware<any, any>[] ? FirstLocals & InferMiddlewareLocals<Rest> : FirstLocals : {} : {};
|
|
78
88
|
type ZodRequest<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}> = Omit<Request, "params" | "query" | "body"> & {
|
|
79
89
|
params: ExtractRouteParams<Path>;
|
|
80
90
|
body: BodySchema extends ZodType<any, any, any> ? z.infer<BodySchema> : unknown;
|
|
81
91
|
query: QuerySchema extends ZodType<any, any, any> ? z.infer<QuerySchema> : unknown;
|
|
82
92
|
} & MiddlewareProps;
|
|
83
|
-
type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}> = (req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>, res: Response, next?: NextFunction) => void | Promise<void> | Response | Promise<Response>;
|
|
93
|
+
type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}, ResponseLocals extends Record<string, any> = {}> = (req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>, res: Response<any, ResponseLocals>, next?: NextFunction) => void | Promise<void> | Response | Promise<Response>;
|
|
84
94
|
/**
|
|
85
95
|
* Options for defining a typed route, including schemas and middleware.
|
|
86
96
|
*
|
|
@@ -93,110 +103,122 @@ type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<an
|
|
|
93
103
|
interface RouteOptions<BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown> {
|
|
94
104
|
bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;
|
|
95
105
|
querySchema?: QuerySchema extends ZodType<any, any, any> ? QuerySchema : never;
|
|
96
|
-
middleware?: readonly TypedMiddleware<any>[];
|
|
106
|
+
middleware?: readonly TypedMiddleware<any, any>[];
|
|
97
107
|
}
|
|
98
108
|
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "all";
|
|
99
|
-
declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}> {
|
|
109
|
+
declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}> {
|
|
100
110
|
private router;
|
|
101
111
|
constructor();
|
|
102
112
|
/**
|
|
103
113
|
* Add typed middleware that extends the request with additional properties
|
|
114
|
+
* and/or adds properties to response.locals
|
|
104
115
|
*/
|
|
105
|
-
useTypedMiddleware<
|
|
116
|
+
useTypedMiddleware<TReq extends Record<string, any> = {}, TLocals extends Record<string, any> = {}>(middleware: TypedMiddleware<TReq, TLocals>): TypedRouter<RouterMiddlewareProps & TReq, RouterLocals & TLocals>;
|
|
106
117
|
/**
|
|
107
118
|
* Get the underlying Express router
|
|
108
119
|
*/
|
|
109
120
|
getRouter(): express.Router;
|
|
110
|
-
get<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
111
|
-
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
112
|
-
get<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
121
|
+
get<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
122
|
+
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
123
|
+
get<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
113
124
|
middleware: Middleware;
|
|
114
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
115
|
-
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: RouteOptions<BodySchema, QuerySchema> & {
|
|
125
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
126
|
+
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: RouteOptions<BodySchema, QuerySchema> & {
|
|
116
127
|
middleware: Middleware;
|
|
117
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
118
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
128
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
129
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
119
130
|
bodySchema: BodySchema;
|
|
120
131
|
querySchema?: QuerySchema;
|
|
121
132
|
middleware: Middleware;
|
|
122
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
123
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
133
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
134
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
124
135
|
bodySchema: BodySchema;
|
|
125
136
|
middleware: Middleware;
|
|
126
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
127
|
-
post<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
137
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
138
|
+
post<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
128
139
|
middleware: Middleware;
|
|
129
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
130
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
131
|
-
post<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
132
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
140
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
141
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
142
|
+
post<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
143
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
133
144
|
bodySchema: BodySchema;
|
|
134
145
|
querySchema?: QuerySchema;
|
|
135
146
|
middleware: Middleware;
|
|
136
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
137
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
147
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
148
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
138
149
|
bodySchema: BodySchema;
|
|
139
150
|
middleware: Middleware;
|
|
140
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
141
|
-
put<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
151
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
152
|
+
put<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
142
153
|
middleware: Middleware;
|
|
143
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
144
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
145
|
-
put<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
146
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
154
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
155
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
156
|
+
put<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
157
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
147
158
|
bodySchema: BodySchema;
|
|
148
159
|
querySchema?: QuerySchema;
|
|
149
160
|
middleware: Middleware;
|
|
150
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
151
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
161
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
162
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
152
163
|
bodySchema: BodySchema;
|
|
153
164
|
middleware: Middleware;
|
|
154
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
155
|
-
patch<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
156
|
-
middleware: Middleware;
|
|
157
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
158
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
159
|
-
patch<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
160
|
-
delete<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
165
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
166
|
+
patch<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
161
167
|
middleware: Middleware;
|
|
162
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
163
|
-
|
|
168
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
169
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
170
|
+
patch<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
171
|
+
delete<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
164
172
|
querySchema: QuerySchema;
|
|
165
173
|
middleware: Middleware;
|
|
166
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
174
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
167
175
|
delete<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
168
176
|
querySchema: QuerySchema;
|
|
169
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
170
|
-
delete<Path extends string
|
|
171
|
-
options<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
177
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
178
|
+
delete<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
172
179
|
middleware: Middleware;
|
|
173
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
181
|
+
delete<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
182
|
+
options<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
183
|
+
querySchema: QuerySchema;
|
|
176
184
|
middleware: Middleware;
|
|
177
|
-
}, handler: ZodRouteHandler<Path, unknown,
|
|
178
|
-
|
|
185
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
186
|
+
options<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
179
187
|
querySchema: QuerySchema;
|
|
188
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
189
|
+
options<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
180
190
|
middleware: Middleware;
|
|
181
|
-
}, handler: ZodRouteHandler<Path, unknown,
|
|
191
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
192
|
+
options<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
193
|
+
head<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
194
|
+
querySchema: QuerySchema;
|
|
195
|
+
middleware: Middleware;
|
|
196
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
182
197
|
head<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
183
198
|
querySchema: QuerySchema;
|
|
184
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
185
|
-
head<Path extends string
|
|
186
|
-
|
|
199
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
200
|
+
head<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
201
|
+
middleware: Middleware;
|
|
202
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
203
|
+
head<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
204
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
187
205
|
bodySchema: BodySchema;
|
|
188
206
|
querySchema?: QuerySchema;
|
|
189
207
|
middleware: Middleware;
|
|
190
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
191
|
-
all<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
208
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
209
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
192
210
|
bodySchema: BodySchema;
|
|
193
211
|
middleware: Middleware;
|
|
194
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
195
|
-
all<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
212
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
213
|
+
all<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
214
|
+
querySchema: QuerySchema;
|
|
215
|
+
middleware: Middleware;
|
|
216
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
217
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
218
|
+
all<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
196
219
|
middleware: Middleware;
|
|
197
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
198
|
-
all<Path extends string
|
|
199
|
-
all<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
220
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
221
|
+
all<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
200
222
|
private registerRoute;
|
|
201
223
|
private createBodyValidationMiddleware;
|
|
202
224
|
private createQueryValidationMiddleware;
|
|
@@ -221,7 +243,7 @@ declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}
|
|
|
221
243
|
* const app = express();
|
|
222
244
|
* app.use('/api', router.getRouter());
|
|
223
245
|
*/
|
|
224
|
-
declare function createTypedRouter<RouterMiddlewareProps extends Record<string, any> = {}>(): TypedRouter<RouterMiddlewareProps>;
|
|
246
|
+
declare function createTypedRouter<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}>(): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
225
247
|
/**
|
|
226
248
|
* Configuration options for createTypedRouterWithConfig.
|
|
227
249
|
*
|
|
@@ -249,7 +271,7 @@ interface RouterConfig {
|
|
|
249
271
|
* }
|
|
250
272
|
* });
|
|
251
273
|
*/
|
|
252
|
-
declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Record<string, any> = {}>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps>;
|
|
274
|
+
declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
253
275
|
/**
|
|
254
276
|
* Create a new typed router with pre-configured middleware.
|
|
255
277
|
*
|
|
@@ -263,8 +285,8 @@ declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Recor
|
|
|
263
285
|
*
|
|
264
286
|
* const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);
|
|
265
287
|
*/
|
|
266
|
-
declare function createTypedRouterWithMiddleware<T extends Record<string, any>>(...middleware: TypedMiddleware<any>[]): TypedRouter<T>;
|
|
288
|
+
declare function createTypedRouterWithMiddleware<T extends Record<string, any>>(...middleware: TypedMiddleware<any, any>[]): TypedRouter<T>;
|
|
267
289
|
|
|
268
290
|
//#endregion
|
|
269
|
-
export { ExtractRouteParams, HttpMethod, RouteOptions, RouterConfig, TypedMiddleware,
|
|
291
|
+
export { ExtractRouteParams, HttpMethod, LocalsOnlyMiddleware, RequestOnlyMiddleware, RouteOptions, RouterConfig, TypedMiddleware, ZodRequest, ZodRouteHandler, createTypedRouter, createTypedRouterWithConfig, createTypedRouterWithMiddleware };
|
|
270
292
|
//# sourceMappingURL=zod-router.d.cts.map
|
package/dist/zod-router.d.ts
CHANGED
|
@@ -66,21 +66,31 @@ type CountWildcards<Path extends string, Count extends string = "0"> = Path exte
|
|
|
66
66
|
*/
|
|
67
67
|
type IncrementWildcard<T extends string> = T extends "0" ? "1" : T extends "1" ? "2" : T extends "2" ? "3" : T extends "3" ? "4" : T extends "4" ? "5" : T extends "5" ? "6" : T extends "6" ? "7" : T extends "7" ? "8" : T extends "8" ? "9" : "10";
|
|
68
68
|
/**
|
|
69
|
-
* Express middleware that adds custom properties to the request object.
|
|
69
|
+
* Express middleware that adds custom properties to the request object and/or response locals.
|
|
70
70
|
*
|
|
71
|
-
* @template
|
|
72
|
-
* @
|
|
73
|
-
* @param
|
|
71
|
+
* @template TReq - The shape of the properties added to the request object.
|
|
72
|
+
* @template TLocals - The shape of the properties added to response.locals.
|
|
73
|
+
* @param req - The Express request object, extended with TReq.
|
|
74
|
+
* @param res - The Express response object with typed locals.
|
|
74
75
|
* @param next - The next middleware function.
|
|
75
76
|
*/
|
|
76
|
-
type TypedMiddleware<
|
|
77
|
-
|
|
77
|
+
type TypedMiddleware<TReq extends Record<string, any> = {}, TLocals extends Record<string, any> = {}> = (req: Request & TReq, res: Response<any, TLocals>, next: NextFunction) => void | Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Simplified TypedMiddleware for request-only extensions (backward compatibility)
|
|
80
|
+
*/
|
|
81
|
+
type RequestOnlyMiddleware<TReq extends Record<string, any>> = TypedMiddleware<TReq, {}>;
|
|
82
|
+
/**
|
|
83
|
+
* Simplified TypedMiddleware for response locals-only extensions
|
|
84
|
+
*/
|
|
85
|
+
type LocalsOnlyMiddleware<TLocals extends Record<string, any>> = TypedMiddleware<{}, TLocals>;
|
|
86
|
+
type InferMiddlewareProps<T extends readonly TypedMiddleware<any, any>[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<infer FirstReq, any> ? Rest extends readonly TypedMiddleware<any, any>[] ? FirstReq & InferMiddlewareProps<Rest> : FirstReq : {} : {};
|
|
87
|
+
type InferMiddlewareLocals<T extends readonly TypedMiddleware<any, any>[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<any, infer FirstLocals> ? Rest extends readonly TypedMiddleware<any, any>[] ? FirstLocals & InferMiddlewareLocals<Rest> : FirstLocals : {} : {};
|
|
78
88
|
type ZodRequest<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}> = Omit<Request, "params" | "query" | "body"> & {
|
|
79
89
|
params: ExtractRouteParams<Path>;
|
|
80
90
|
body: BodySchema extends ZodType<any, any, any> ? z.infer<BodySchema> : unknown;
|
|
81
91
|
query: QuerySchema extends ZodType<any, any, any> ? z.infer<QuerySchema> : unknown;
|
|
82
92
|
} & MiddlewareProps;
|
|
83
|
-
type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}> = (req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>, res: Response, next?: NextFunction) => void | Promise<void> | Response | Promise<Response>;
|
|
93
|
+
type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown, MiddlewareProps extends Record<string, any> = {}, ResponseLocals extends Record<string, any> = {}> = (req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>, res: Response<any, ResponseLocals>, next?: NextFunction) => void | Promise<void> | Response | Promise<Response>;
|
|
84
94
|
/**
|
|
85
95
|
* Options for defining a typed route, including schemas and middleware.
|
|
86
96
|
*
|
|
@@ -93,110 +103,122 @@ type ZodRouteHandler<Path extends string = string, BodySchema extends ZodType<an
|
|
|
93
103
|
interface RouteOptions<BodySchema extends ZodType<any, any, any> | unknown = unknown, QuerySchema extends ZodType<any, any, any> | unknown = unknown> {
|
|
94
104
|
bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;
|
|
95
105
|
querySchema?: QuerySchema extends ZodType<any, any, any> ? QuerySchema : never;
|
|
96
|
-
middleware?: readonly TypedMiddleware<any>[];
|
|
106
|
+
middleware?: readonly TypedMiddleware<any, any>[];
|
|
97
107
|
}
|
|
98
108
|
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "all";
|
|
99
|
-
declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}> {
|
|
109
|
+
declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}> {
|
|
100
110
|
private router;
|
|
101
111
|
constructor();
|
|
102
112
|
/**
|
|
103
113
|
* Add typed middleware that extends the request with additional properties
|
|
114
|
+
* and/or adds properties to response.locals
|
|
104
115
|
*/
|
|
105
|
-
useTypedMiddleware<
|
|
116
|
+
useTypedMiddleware<TReq extends Record<string, any> = {}, TLocals extends Record<string, any> = {}>(middleware: TypedMiddleware<TReq, TLocals>): TypedRouter<RouterMiddlewareProps & TReq, RouterLocals & TLocals>;
|
|
106
117
|
/**
|
|
107
118
|
* Get the underlying Express router
|
|
108
119
|
*/
|
|
109
120
|
getRouter(): express.Router;
|
|
110
|
-
get<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
111
|
-
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
112
|
-
get<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
121
|
+
get<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
122
|
+
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
123
|
+
get<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
113
124
|
middleware: Middleware;
|
|
114
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
115
|
-
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: RouteOptions<BodySchema, QuerySchema> & {
|
|
125
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
126
|
+
get<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: RouteOptions<BodySchema, QuerySchema> & {
|
|
116
127
|
middleware: Middleware;
|
|
117
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
118
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
128
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
129
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
119
130
|
bodySchema: BodySchema;
|
|
120
131
|
querySchema?: QuerySchema;
|
|
121
132
|
middleware: Middleware;
|
|
122
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
123
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
133
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
134
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
124
135
|
bodySchema: BodySchema;
|
|
125
136
|
middleware: Middleware;
|
|
126
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
127
|
-
post<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
137
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
138
|
+
post<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
128
139
|
middleware: Middleware;
|
|
129
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
130
|
-
post<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
131
|
-
post<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
132
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
140
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
141
|
+
post<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
142
|
+
post<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
143
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
133
144
|
bodySchema: BodySchema;
|
|
134
145
|
querySchema?: QuerySchema;
|
|
135
146
|
middleware: Middleware;
|
|
136
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
137
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
147
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
148
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
138
149
|
bodySchema: BodySchema;
|
|
139
150
|
middleware: Middleware;
|
|
140
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
141
|
-
put<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
151
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
152
|
+
put<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
142
153
|
middleware: Middleware;
|
|
143
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
144
|
-
put<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
145
|
-
put<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
146
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
154
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
155
|
+
put<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
156
|
+
put<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
157
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
147
158
|
bodySchema: BodySchema;
|
|
148
159
|
querySchema?: QuerySchema;
|
|
149
160
|
middleware: Middleware;
|
|
150
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
151
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
161
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
162
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
152
163
|
bodySchema: BodySchema;
|
|
153
164
|
middleware: Middleware;
|
|
154
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
155
|
-
patch<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
156
|
-
middleware: Middleware;
|
|
157
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
158
|
-
patch<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
159
|
-
patch<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
160
|
-
delete<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
165
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
166
|
+
patch<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
161
167
|
middleware: Middleware;
|
|
162
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
163
|
-
|
|
168
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
169
|
+
patch<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
170
|
+
patch<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
171
|
+
delete<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
164
172
|
querySchema: QuerySchema;
|
|
165
173
|
middleware: Middleware;
|
|
166
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
174
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
167
175
|
delete<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
168
176
|
querySchema: QuerySchema;
|
|
169
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
170
|
-
delete<Path extends string
|
|
171
|
-
options<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
177
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
178
|
+
delete<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
172
179
|
middleware: Middleware;
|
|
173
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
174
|
-
|
|
175
|
-
|
|
180
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
181
|
+
delete<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
182
|
+
options<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
183
|
+
querySchema: QuerySchema;
|
|
176
184
|
middleware: Middleware;
|
|
177
|
-
}, handler: ZodRouteHandler<Path, unknown,
|
|
178
|
-
|
|
185
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
186
|
+
options<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
179
187
|
querySchema: QuerySchema;
|
|
188
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
189
|
+
options<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
180
190
|
middleware: Middleware;
|
|
181
|
-
}, handler: ZodRouteHandler<Path, unknown,
|
|
191
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
192
|
+
options<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
193
|
+
head<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
194
|
+
querySchema: QuerySchema;
|
|
195
|
+
middleware: Middleware;
|
|
196
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
182
197
|
head<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: {
|
|
183
198
|
querySchema: QuerySchema;
|
|
184
|
-
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
185
|
-
head<Path extends string
|
|
186
|
-
|
|
199
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
200
|
+
head<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
201
|
+
middleware: Middleware;
|
|
202
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
203
|
+
head<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
204
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any>, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
187
205
|
bodySchema: BodySchema;
|
|
188
206
|
querySchema?: QuerySchema;
|
|
189
207
|
middleware: Middleware;
|
|
190
|
-
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
191
|
-
all<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
208
|
+
}, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
209
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any>, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
192
210
|
bodySchema: BodySchema;
|
|
193
211
|
middleware: Middleware;
|
|
194
|
-
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
195
|
-
all<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(path: Path, options: {
|
|
212
|
+
}, handler: ZodRouteHandler<Path, BodySchema, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
213
|
+
all<Path extends string, QuerySchema extends ZodType<any, any, any> | unknown, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
214
|
+
querySchema: QuerySchema;
|
|
215
|
+
middleware: Middleware;
|
|
216
|
+
}, handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
217
|
+
all<Path extends string, BodySchema extends ZodType<any, any, any> | unknown, QuerySchema extends ZodType<any, any, any> | unknown>(path: Path, options: RouteOptions<BodySchema, QuerySchema>, handler: ZodRouteHandler<Path, BodySchema, QuerySchema, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
218
|
+
all<Path extends string, Middleware extends readonly TypedMiddleware<any, any>[]>(path: Path, options: {
|
|
196
219
|
middleware: Middleware;
|
|
197
|
-
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>>): TypedRouter<RouterMiddlewareProps>;
|
|
198
|
-
all<Path extends string
|
|
199
|
-
all<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>): TypedRouter<RouterMiddlewareProps>;
|
|
220
|
+
}, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps & InferMiddlewareProps<Middleware>, RouterLocals & InferMiddlewareLocals<Middleware>>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
221
|
+
all<Path extends string>(path: Path, handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps, RouterLocals>): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
200
222
|
private registerRoute;
|
|
201
223
|
private createBodyValidationMiddleware;
|
|
202
224
|
private createQueryValidationMiddleware;
|
|
@@ -221,7 +243,7 @@ declare class TypedRouter<RouterMiddlewareProps extends Record<string, any> = {}
|
|
|
221
243
|
* const app = express();
|
|
222
244
|
* app.use('/api', router.getRouter());
|
|
223
245
|
*/
|
|
224
|
-
declare function createTypedRouter<RouterMiddlewareProps extends Record<string, any> = {}>(): TypedRouter<RouterMiddlewareProps>;
|
|
246
|
+
declare function createTypedRouter<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}>(): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
225
247
|
/**
|
|
226
248
|
* Configuration options for createTypedRouterWithConfig.
|
|
227
249
|
*
|
|
@@ -249,7 +271,7 @@ interface RouterConfig {
|
|
|
249
271
|
* }
|
|
250
272
|
* });
|
|
251
273
|
*/
|
|
252
|
-
declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Record<string, any> = {}>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps>;
|
|
274
|
+
declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Record<string, any> = {}, RouterLocals extends Record<string, any> = {}>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps, RouterLocals>;
|
|
253
275
|
/**
|
|
254
276
|
* Create a new typed router with pre-configured middleware.
|
|
255
277
|
*
|
|
@@ -263,8 +285,8 @@ declare function createTypedRouterWithConfig<RouterMiddlewareProps extends Recor
|
|
|
263
285
|
*
|
|
264
286
|
* const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);
|
|
265
287
|
*/
|
|
266
|
-
declare function createTypedRouterWithMiddleware<T extends Record<string, any>>(...middleware: TypedMiddleware<any>[]): TypedRouter<T>;
|
|
288
|
+
declare function createTypedRouterWithMiddleware<T extends Record<string, any>>(...middleware: TypedMiddleware<any, any>[]): TypedRouter<T>;
|
|
267
289
|
|
|
268
290
|
//#endregion
|
|
269
|
-
export { ExtractRouteParams, HttpMethod, RouteOptions, RouterConfig, TypedMiddleware,
|
|
291
|
+
export { ExtractRouteParams, HttpMethod, LocalsOnlyMiddleware, RequestOnlyMiddleware, RouteOptions, RouterConfig, TypedMiddleware, ZodRequest, ZodRouteHandler, createTypedRouter, createTypedRouterWithConfig, createTypedRouterWithMiddleware };
|
|
270
292
|
//# sourceMappingURL=zod-router.d.ts.map
|
package/dist/zod-router.js
CHANGED
|
@@ -9,6 +9,7 @@ var TypedRouter = class {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Add typed middleware that extends the request with additional properties
|
|
12
|
+
* and/or adds properties to response.locals
|
|
12
13
|
*/
|
|
13
14
|
useTypedMiddleware(middleware) {
|
|
14
15
|
this.router.use(middleware);
|
|
@@ -150,5 +151,5 @@ function createTypedRouterWithMiddleware(...middleware) {
|
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
//#endregion
|
|
153
|
-
export {
|
|
154
|
+
export { createTypedRouter, createTypedRouterWithConfig, createTypedRouterWithMiddleware };
|
|
154
155
|
//# sourceMappingURL=zod-router.js.map
|
package/dist/zod-router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-router.js","names":["middleware: TypedMiddleware<T>","path: string","optionsOrHandler: any","handler?: any","method: HttpMethod","middlewares: any[]","schema: ZodType<any, any, any>","req: Request","res: Response","next: NextFunction","config?: RouterConfig"],"sources":["../src/zod-router.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module @minisylar/express-typed-router\n *\n * @title @minisylar/express-typed-router\n *\n * A strongly-typed Express router with Zod validation and automatic type inference for params, body, query, and middleware.\n *\n * @example\n * // Example 1: Basic usage with router-level middleware\n * const router = createTypedRouter()\n * .useTypedMiddleware(timestampMiddleware)\n * .useTypedMiddleware(requestIdMiddleware)\n *\n * router.get('/posts/:postId', (req, res) => {\n * const { postId } = req.params // Typed as { postId: string }\n * const { timestamp, requestId } = req // Both properties are now typed correctly!\n * res.json({ postId, timestamp, requestId })\n * })\n *\n * @example\n * // Example 2: Per-route middleware with automatic type inference\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware, requestIdMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content, tags } = req.body // From schema validation\n * const { timestamp, requestId } = req // From middleware - should be automatically typed!\n * res.json({ title, content, tags, timestamp, requestId })\n * }\n * )\n *\n * @example\n * // Example 3: Mixed middleware\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n * router.get(\n * '/posts/:postId',\n * {\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req // From router-level middleware\n * const { userId, hasPermission } = req // From per-route middleware\n * res.json({ postId, requestId, userId, hasPermission })\n * }\n * )\n *\n * @example\n * // Example 4: Using factory with pre-configured middleware\n * const router = createTypedRouterWithMiddleware(timestampMiddleware, requestIdMiddleware)\n * router.get('/simple/:id', (req, res) => {\n * const { id } = req.params\n * const { timestamp, requestId } = req // Already available from factory setup!\n * res.json({ id, timestamp, requestId })\n * })\n *\n * @example\n * // Example 5: Demonstrating all HTTP methods\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n *\n * // GET with query validation\n * router.get('/posts', { querySchema: QuerySchema }, (req, res) => {\n * const { limit, offset } = req.query // Typed from schema\n * const { requestId } = req // From router middleware\n * res.json({ posts: [], limit, offset, requestId })\n * })\n *\n * // POST with body validation and middleware\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content } = req.body // From body schema\n * const { requestId, timestamp } = req // From middleware\n * res.json({ id: 'new-post', title, content, requestId, timestamp })\n * }\n * )\n *\n * // PUT for full updates\n * router.put(\n * '/posts/:postId',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { title, content } = req.body\n * const { requestId, userId, hasPermission } = req\n * res.json({ postId, title, content, requestId, userId, hasPermission })\n * }\n * )\n *\n * // PATCH for partial updates\n * router.patch('/posts/:postId', { bodySchema: UpdatePostSchema }, (req, res) => {\n * const { postId } = req.params\n * const updates = req.body // Partial update object\n * const { requestId } = req\n * res.json({ postId, updates, requestId })\n * })\n *\n * // DELETE\n * router.delete('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req\n * res.json({ deleted: postId, requestId })\n * })\n *\n * // OPTIONS for CORS preflight\n * router.options('/posts/*', (req, res) => {\n * res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE')\n * res.header('Access-Control-Allow-Headers', 'Content-Type')\n * res.status(200).end()\n * })\n *\n * // HEAD for metadata only\n * router.head('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * res.header('X-Post-ID', postId)\n * res.status(200).end()\n * })\n *\n * // ALL method for catch-all routes\n * router.all('/debug/*', (req, res) => {\n * const { requestId } = req\n * res.json({\n * method: req.method,\n * path: req.path,\n * requestId\n * })\n * })\n */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport express, {\n type Request,\n type Response,\n type NextFunction,\n} from \"express\";\nimport { z, type ZodType } from \"zod\";\n\n/**\n * Extract route parameters from Express.js route patterns.\n *\n * Supports all Express.js routing patterns:\n * - Named parameters: /users/:userId → { userId: string }\n * - Multiple parameters: /users/:userId/books/:bookId → { userId: string; bookId: string }\n * - Parameters with separators: /flights/:from-:to → { from: string; to: string }\n * - Dot notation: /plantae/:genus.:species → { genus: string; species: string }\n * - Regex constraints: /user/:id(\\\\d+) → { id: string }\n * - Optional parameters: /posts/:year/:month? → { year: string; month?: string }\n * - Wildcard parameters: /files/* → { \"0\": string }\n * - Multiple wildcards: /a/star/b/star → { \"0\": string; \"1\": string }\n */\nexport type ExtractRouteParams<Path extends string> = string extends Path\n ? Record<string, string>\n : ExtractParams<Path>;\n\n/**\n * Main parameter extraction logic - enhanced for Express 5 support\n */\ntype ExtractParams<Path extends string> =\n // Handle Express 5 braces for optional segments: {/:param} or {/path/:param}\n Path extends `${infer Before}{${infer OptionalContent}}${infer After}`\n ? ExtractOptionalSegment<OptionalContent> &\n ExtractParams<`${Before}${After}`>\n : // Handle named parameters :paramName\n Path extends `${infer _Before}:${infer Rest}`\n ? ExtractSingleParam<Rest> & ExtractParams<RemoveFirstParam<Path>>\n : // Handle wildcards *\n Path extends `${infer _Before}*${infer After}`\n ? { [K in CountWildcards<_Before>]: string } & ExtractParams<After>\n : // No more parameters\n {};\n\n/**\n * Extract parameters from Express 5 optional segments in braces\n * Handles patterns like {/:param}, {.:ext}, {/optional/:param}\n */\ntype ExtractOptionalSegment<Content extends string> =\n // Handle optional parameter patterns like /:param\n Content extends `/:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `.:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `${infer _Path}:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : {};\n\n/**\n * Extract a single optional parameter from brace content\n */\ntype ExtractOptionalParam<Rest extends string> =\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}`\n ? { [K in ParamName]?: string }\n : {};\n\n/**\n * Extract a single parameter name from the rest of the path\n * Enhanced to handle Express 5 patterns and optional parameters correctly\n * Special handling for consecutive parameters like :from-:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype ExtractSingleParam<Rest extends string> =\n // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer ParamName}(${infer _Constraint})${infer _After}`\n ? { [K in ParamName]: string } // Handle consecutive parameters with separators first: param-:nextParam\n : Rest extends `${infer ParamName}-:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer ParamName}?/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?#${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?:${infer _After}`\n ? { [K in ParamName]?: string }\n : // Then handle regular delimiters (after optional parameter patterns)\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}#${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}:${infer _After}`\n ? { [K in ParamName]: string }\n : // Handle Express 5 repeating parameters (after regular delimiters)\n Rest extends `${infer ParamName}+${infer _After}`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*${infer _After}`\n ? { [K in ParamName]?: string[] }\n : // Handle optional parameters with ? (Express 4) - only at the end of a segment\n Rest extends `${infer ParamName}?${infer _After}`\n ? { [K in ParamName]?: string } // Parameter at absolute end of string\n : Rest extends string\n ? Rest extends \"\"\n ? {}\n : Rest extends `${infer ParamName}?`\n ? { [K in ParamName]?: string } // ParamName here doesn't include the ?\n : Rest extends `${infer ParamName}+`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*`\n ? { [K in ParamName]?: string[] }\n : { [K in Rest]: string }\n : {};\n\n/**\n * Remove the first parameter from path to continue parsing\n * Enhanced to handle Express 5 patterns and optional parameters\n * Handles patterns like :from-:to by removing just :from and keeping -:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype RemoveFirstParam<Path extends string> =\n Path extends `${infer Before}:${infer Rest}`\n ? // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer _ParamName}(${infer _Constraint})${infer After}`\n ? `${Before}${After}` // Handle consecutive parameters: :param-:nextParam -> -:nextParam\n : Rest extends `${infer _ParamName}-:${infer After}`\n ? `${Before}-:${After}`\n : Rest extends `${infer _ParamName}.:${infer After}`\n ? `${Before}.:${After}`\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer _ParamName}?/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}?-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?:${infer After}`\n ? `${Before}:${After}`\n : // Handle regular separators (after optional parameter patterns)\n Rest extends `${infer _ParamName}/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}:${infer After}`\n ? `${Before}:${After}`\n : // Handle Express 5 repeating parameters (after regular separators)\n Rest extends `${infer _ParamName}+${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}*${infer After}`\n ? `${Before}${After}`\n : // Handle optional parameters with ?\n Rest extends `${infer _ParamName}?${infer After}`\n ? `${Before}${After}`\n : Before\n : Path;\n\n/**\n * Count wildcards to assign proper numeric indices\n */\ntype CountWildcards<\n Path extends string,\n Count extends string = \"0\"\n> = Path extends `${infer _Before}*${infer Rest}`\n ? CountWildcards<Rest, IncrementWildcard<Count>>\n : Count;\n\n/**\n * Helper type to increment wildcard count as string\n */\ntype IncrementWildcard<T extends string> = T extends \"0\"\n ? \"1\"\n : T extends \"1\"\n ? \"2\"\n : T extends \"2\"\n ? \"3\"\n : T extends \"3\"\n ? \"4\"\n : T extends \"4\"\n ? \"5\"\n : T extends \"5\"\n ? \"6\"\n : T extends \"6\"\n ? \"7\"\n : T extends \"7\"\n ? \"8\"\n : T extends \"8\"\n ? \"9\"\n : \"10\"; // Reasonable limit for wildcards\n\n/**\n * Express middleware that adds custom properties to the request object.\n *\n * @template T - The shape of the properties added to the request.\n * @param req - The Express request object, extended with T.\n * @param res - The Express response object.\n * @param next - The next middleware function.\n */\nexport type TypedMiddleware<T extends Record<string, any>> = (\n req: Request & T,\n res: Response,\n next: NextFunction\n) => void | Promise<void>;\n\n// Utility type to infer props from middleware array\ntype InferMiddlewareProps<T extends readonly TypedMiddleware<any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<infer FirstType>\n ? Rest extends readonly TypedMiddleware<any>[]\n ? FirstType & InferMiddlewareProps<Rest>\n : FirstType\n : {}\n : {};\n\n// Enhanced Request type with proper inference\nexport type ZodRequest<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = Omit<Request, \"params\" | \"query\" | \"body\"> & {\n params: ExtractRouteParams<Path>;\n body: BodySchema extends ZodType<any, any, any>\n ? z.infer<BodySchema>\n : unknown;\n query: QuerySchema extends ZodType<any, any, any>\n ? z.infer<QuerySchema>\n : unknown;\n} & MiddlewareProps;\n\n// Route handler type\nexport type ZodRouteHandler<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = (\n req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>,\n res: Response,\n next?: NextFunction\n) => void | Promise<void> | Response | Promise<Response>;\n\n/**\n * Options for defining a typed route, including schemas and middleware.\n *\n * @template BodySchema - Zod schema for request body validation.\n * @template QuerySchema - Zod schema for query parameter validation.\n * @property bodySchema - Optional Zod schema for validating the request body.\n * @property querySchema - Optional Zod schema for validating the query string.\n * @property middleware - Optional array of TypedMiddleware for this route.\n */\nexport interface RouteOptions<\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown\n> {\n bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;\n querySchema?: QuerySchema extends ZodType<any, any, any>\n ? QuerySchema\n : never;\n middleware?: readonly TypedMiddleware<any>[];\n}\n\n// HTTP methods\nexport type HttpMethod =\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\"\n | \"options\"\n | \"head\"\n | \"all\";\n\n// Main typed router class\nexport class TypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {}\n> {\n private router: express.Router;\n\n constructor() {\n this.router = express.Router();\n }\n\n /**\n * Add typed middleware that extends the request with additional properties\n */\n useTypedMiddleware<T extends Record<string, any>>(\n middleware: TypedMiddleware<T>\n ): TypedRouter<RouterMiddlewareProps & T> {\n this.router.use(middleware as any);\n return this as any;\n }\n\n /**\n * Get the underlying Express router\n */\n getRouter(): express.Router {\n return this.router;\n }\n\n // Method overloads for GET requests with automatic middleware type inference\n get<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Special overload for middleware type inference\n get<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Combined overload for body/query schema + middleware\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema> & { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Implementation\n get(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"get\", path, optionsOrHandler, handler);\n }\n\n // Combined overload for body/query schema + middleware (most specific first)\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Body schema only + middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Middleware only\n post<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Body + Query schema without middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n // Just handler, no options\n post<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n post(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"post\", path, optionsOrHandler, handler);\n }\n\n // PUT method with all the same overloads as POST\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n put<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n put(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"put\", path, optionsOrHandler, handler);\n }\n\n // PATCH method with all the same overloads as POST\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n patch(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"patch\", path, optionsOrHandler, handler);\n }\n\n // DELETE method (typically no body, but can have query params and middleware)\n delete<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n delete(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"delete\", path, optionsOrHandler, handler);\n }\n\n // OPTIONS method (typically no body, used for CORS preflight)\n options<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n options<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n options(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"options\", path, optionsOrHandler, handler);\n }\n\n // HEAD method (like GET but only returns headers)\n head<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<Path, unknown, QuerySchema, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n head<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n head(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"head\", path, optionsOrHandler, handler);\n }\n\n // ALL method (matches all HTTP methods)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<Path extends string, Middleware extends readonly TypedMiddleware<any>[]>(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps\n >\n ): TypedRouter<RouterMiddlewareProps>;\n\n all<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<Path, unknown, unknown, RouterMiddlewareProps>\n ): TypedRouter<RouterMiddlewareProps>;\n\n all(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n return this.registerRoute(\"all\", path, optionsOrHandler, handler);\n }\n\n // Helper method to register routes\n private registerRoute(\n method: HttpMethod,\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps> {\n const middlewares: any[] = [];\n\n if (typeof optionsOrHandler === \"object\") {\n const options = optionsOrHandler as RouteOptions<any, any>;\n\n // Add per-route middleware first\n if (options.middleware) {\n middlewares.push(...options.middleware);\n }\n\n // Add schema validation middleware\n if (options.bodySchema) {\n middlewares.push(\n this.createBodyValidationMiddleware(options.bodySchema)\n );\n }\n if (options.querySchema) {\n middlewares.push(\n this.createQueryValidationMiddleware(options.querySchema)\n );\n }\n\n // Add the main handler\n middlewares.push(handler);\n } else {\n // Direct handler without options\n middlewares.push(optionsOrHandler);\n }\n\n // Register with Express router\n (this.router as any)[method](path, ...middlewares);\n\n return this;\n }\n\n private createBodyValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.body = schema.parse(req.body);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n\n private createQueryValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.query = schema.parse(req.query);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n}\n\n/**\n * Create a new strongly-typed Express router instance.\n *\n * This is the simplest way to get started with @minisylar/express-typed-router.\n *\n * @example\n * import { createTypedRouter } from '@minisylar/express-typed-router';\n *\n * // Create a router and add a typed GET route\n * const router = createTypedRouter();\n * router.get('/hello/:name', (req, res) => {\n * // req.params.name is typed as string\n * res.json({ message: `Hello, ${req.params.name}!` });\n * });\n *\n * // Use with Express\n * import express from 'express';\n * const app = express();\n * app.use('/api', router.getRouter());\n */\nexport function createTypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {}\n>(): TypedRouter<RouterMiddlewareProps> {\n return new TypedRouter<RouterMiddlewareProps>();\n}\n\n// Option 2: Factory with optional configuration\n\n/**\n * Configuration options for createTypedRouterWithConfig.\n *\n * @property validateInput - (Future) Whether to enable global input validation.\n * @property errorHandler - Optional global error handler middleware for the router.\n */\nexport interface RouterConfig {\n validateInput?: boolean;\n errorHandler?: (\n error: any,\n req: Request,\n res: Response,\n next: NextFunction\n ) => void;\n}\n\n/**\n * Create a new typed router with optional configuration.\n *\n * Use this if you want to add a global error handler or future global options.\n *\n * @param config - Optional configuration for the router (e.g. error handler).\n * @returns A new TypedRouter instance.\n *\n * @example\n * import { createTypedRouterWithConfig } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithConfig({\n * errorHandler: (err, req, res, next) => {\n * res.status(500).json({ error: 'Something went wrong', details: err });\n * }\n * });\n */\nexport function createTypedRouterWithConfig<\n RouterMiddlewareProps extends Record<string, any> = {}\n>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps> {\n const router = new TypedRouter<RouterMiddlewareProps>();\n if (config?.errorHandler) {\n router.getRouter().use(config.errorHandler);\n }\n return router;\n}\n\n// Option 3: Factory with pre-configured middleware\n\n/**\n * Create a new typed router with pre-configured middleware.\n *\n * This is useful for setting up router-level middleware in a single call.\n *\n * @param middleware - One or more TypedMiddleware functions to apply to all routes.\n * @returns A new TypedRouter instance with the middleware applied.\n *\n * @example\n * import { createTypedRouterWithMiddleware } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);\n */\nexport function createTypedRouterWithMiddleware<T extends Record<string, any>>(\n ...middleware: TypedMiddleware<any>[]\n): TypedRouter<T> {\n let router = new TypedRouter() as any;\n for (const mw of middleware) {\n router = router.useTypedMiddleware(mw);\n }\n return router;\n}\n"],"mappings":";;;;AA8aA,IAAa,cAAb,MAEE;CACA,AAAQ;CAER,cAAc;AACZ,OAAK,SAAS,QAAQ,QAAQ;CAC/B;;;;CAKD,mBACEA,YACwC;AACxC,OAAK,OAAO,IAAI,WAAkB;AAClC,SAAO;CACR;;;;CAKD,YAA4B;AAC1B,SAAO,KAAK;CACb;CAqDD,IACEC,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAyED,KACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqED,IACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAwED,MACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,SAAS,MAAM,kBAAkB,QAAQ;CACpE;CA8CD,OACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,UAAU,MAAM,kBAAkB,QAAQ;CACrE;CAsBD,QACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,WAAW,MAAM,kBAAkB,QAAQ;CACtE;CA2CD,KACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqED,IACEF,MACAC,kBACAC,SACoC;AACpC,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAGD,AAAQ,cACNC,QACAH,MACAC,kBACAC,SACoC;EACpC,MAAME,cAAqB,CAAE;AAE7B,aAAW,qBAAqB,UAAU;GACxC,MAAM,UAAU;AAGhB,OAAI,QAAQ,WACV,aAAY,KAAK,GAAG,QAAQ,WAAW;AAIzC,OAAI,QAAQ,WACV,aAAY,KACV,KAAK,+BAA+B,QAAQ,WAAW,CACxD;AAEH,OAAI,QAAQ,YACV,aAAY,KACV,KAAK,gCAAgC,QAAQ,YAAY,CAC1D;AAIH,eAAY,KAAK,QAAQ;EAC1B,MAEC,aAAY,KAAK,iBAAiB;AAIpC,EAAC,KAAK,OAAe,QAAQ,MAAM,GAAG,YAAY;AAElD,SAAO;CACR;CAED,AAAQ,+BAA+BC,QAAgC;AACrE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,OAAO,OAAO,MAAM,IAAI,KAAK;AACjC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiB,EAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;CAED,AAAQ,gCAAgCH,QAAgC;AACtE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,QAAQ,OAAO,MAAM,IAAI,MAAM;AACnC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiB,EAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,oBAEwB;AACtC,QAAO,IAAI;AACZ;;;;;;;;;;;;;;;;;;AAqCD,SAAgB,4BAEdC,QAA2D;CAC3D,MAAM,SAAS,IAAI;AACnB,KAAI,QAAQ,aACV,QAAO,WAAW,CAAC,IAAI,OAAO,aAAa;AAE7C,QAAO;AACR;;;;;;;;;;;;;;AAiBD,SAAgB,gCACd,GAAG,YACa;CAChB,IAAI,SAAS,IAAI;AACjB,MAAK,MAAM,MAAM,WACf,UAAS,OAAO,mBAAmB,GAAG;AAExC,QAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"zod-router.js","names":["middleware: TypedMiddleware<TReq, TLocals>","path: string","optionsOrHandler: any","handler?: any","method: HttpMethod","middlewares: any[]","schema: ZodType<any, any, any>","req: Request","res: Response","next: NextFunction","config?: RouterConfig"],"sources":["../src/zod-router.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module @minisylar/express-typed-router\n *\n * @title @minisylar/express-typed-router\n *\n * A strongly-typed Express router with Zod validation and automatic type inference for params, body, query, and middleware.\n *\n * @example\n * // Example 1: Basic usage with router-level middleware\n * const router = createTypedRouter()\n * .useTypedMiddleware(timestampMiddleware)\n * .useTypedMiddleware(requestIdMiddleware)\n *\n * router.get('/posts/:postId', (req, res) => {\n * const { postId } = req.params // Typed as { postId: string }\n * const { timestamp, requestId } = req // Both properties are now typed correctly!\n * res.json({ postId, timestamp, requestId })\n * })\n *\n * @example\n * // Example 2: Per-route middleware with automatic type inference\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware, requestIdMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content, tags } = req.body // From schema validation\n * const { timestamp, requestId } = req // From middleware - should be automatically typed!\n * res.json({ title, content, tags, timestamp, requestId })\n * }\n * )\n *\n * @example\n * // Example 3: Mixed middleware\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n * router.get(\n * '/posts/:postId',\n * {\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req // From router-level middleware\n * const { userId, hasPermission } = req // From per-route middleware\n * res.json({ postId, requestId, userId, hasPermission })\n * }\n * )\n *\n * @example\n * // Example 4: Using factory with pre-configured middleware\n * const router = createTypedRouterWithMiddleware(timestampMiddleware, requestIdMiddleware)\n * router.get('/simple/:id', (req, res) => {\n * const { id } = req.params\n * const { timestamp, requestId } = req // Already available from factory setup!\n * res.json({ id, timestamp, requestId })\n * })\n *\n * @example\n * // Example 5: Demonstrating all HTTP methods\n * const router = createTypedRouter().useTypedMiddleware(requestIdMiddleware)\n *\n * // GET with query validation\n * router.get('/posts', { querySchema: QuerySchema }, (req, res) => {\n * const { limit, offset } = req.query // Typed from schema\n * const { requestId } = req // From router middleware\n * res.json({ posts: [], limit, offset, requestId })\n * })\n *\n * // POST with body validation and middleware\n * router.post(\n * '/posts',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [timestampMiddleware] as const\n * },\n * (req, res) => {\n * const { title, content } = req.body // From body schema\n * const { requestId, timestamp } = req // From middleware\n * res.json({ id: 'new-post', title, content, requestId, timestamp })\n * }\n * )\n *\n * // PUT for full updates\n * router.put(\n * '/posts/:postId',\n * {\n * bodySchema: CreatePostSchema,\n * middleware: [authMiddleware] as const\n * },\n * (req, res) => {\n * const { postId } = req.params\n * const { title, content } = req.body\n * const { requestId, userId, hasPermission } = req\n * res.json({ postId, title, content, requestId, userId, hasPermission })\n * }\n * )\n *\n * // PATCH for partial updates\n * router.patch('/posts/:postId', { bodySchema: UpdatePostSchema }, (req, res) => {\n * const { postId } = req.params\n * const updates = req.body // Partial update object\n * const { requestId } = req\n * res.json({ postId, updates, requestId })\n * })\n *\n * // DELETE\n * router.delete('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * const { requestId } = req\n * res.json({ deleted: postId, requestId })\n * })\n *\n * // OPTIONS for CORS preflight\n * router.options('/posts/*', (req, res) => {\n * res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE')\n * res.header('Access-Control-Allow-Headers', 'Content-Type')\n * res.status(200).end()\n * })\n *\n * // HEAD for metadata only\n * router.head('/posts/:postId', (req, res) => {\n * const { postId } = req.params\n * res.header('X-Post-ID', postId)\n * res.status(200).end()\n * })\n *\n * // ALL method for catch-all routes\n * router.all('/debug/*', (req, res) => {\n * const { requestId } = req\n * res.json({\n * method: req.method,\n * path: req.path,\n * requestId\n * })\n * })\n */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport express, {\n type Request,\n type Response,\n type NextFunction,\n} from \"express\";\nimport { z, type ZodType } from \"zod\";\n\n/**\n * Extract route parameters from Express.js route patterns.\n *\n * Supports all Express.js routing patterns:\n * - Named parameters: /users/:userId → { userId: string }\n * - Multiple parameters: /users/:userId/books/:bookId → { userId: string; bookId: string }\n * - Parameters with separators: /flights/:from-:to → { from: string; to: string }\n * - Dot notation: /plantae/:genus.:species → { genus: string; species: string }\n * - Regex constraints: /user/:id(\\\\d+) → { id: string }\n * - Optional parameters: /posts/:year/:month? → { year: string; month?: string }\n * - Wildcard parameters: /files/* → { \"0\": string }\n * - Multiple wildcards: /a/star/b/star → { \"0\": string; \"1\": string }\n */\nexport type ExtractRouteParams<Path extends string> = string extends Path\n ? Record<string, string>\n : ExtractParams<Path>;\n\n/**\n * Main parameter extraction logic - enhanced for Express 5 support\n */\ntype ExtractParams<Path extends string> =\n // Handle Express 5 braces for optional segments: {/:param} or {/path/:param}\n Path extends `${infer Before}{${infer OptionalContent}}${infer After}`\n ? ExtractOptionalSegment<OptionalContent> &\n ExtractParams<`${Before}${After}`>\n : // Handle named parameters :paramName\n Path extends `${infer _Before}:${infer Rest}`\n ? ExtractSingleParam<Rest> & ExtractParams<RemoveFirstParam<Path>>\n : // Handle wildcards *\n Path extends `${infer _Before}*${infer After}`\n ? { [K in CountWildcards<_Before>]: string } & ExtractParams<After>\n : // No more parameters\n {};\n\n/**\n * Extract parameters from Express 5 optional segments in braces\n * Handles patterns like {/:param}, {.:ext}, {/optional/:param}\n */\ntype ExtractOptionalSegment<Content extends string> =\n // Handle optional parameter patterns like /:param\n Content extends `/:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `.:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : Content extends `${infer _Path}:${infer Rest}`\n ? ExtractOptionalParam<Rest>\n : {};\n\n/**\n * Extract a single optional parameter from brace content\n */\ntype ExtractOptionalParam<Rest extends string> =\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}`\n ? { [K in ParamName]?: string }\n : {};\n\n/**\n * Extract a single parameter name from the rest of the path\n * Enhanced to handle Express 5 patterns and optional parameters correctly\n * Special handling for consecutive parameters like :from-:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype ExtractSingleParam<Rest extends string> =\n // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer ParamName}(${infer _Constraint})${infer _After}`\n ? { [K in ParamName]: string } // Handle consecutive parameters with separators first: param-:nextParam\n : Rest extends `${infer ParamName}-:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.:${infer _NextParam}`\n ? { [K in ParamName]: string }\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer ParamName}?/${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?-${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?.${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?#${infer _After}`\n ? { [K in ParamName]?: string }\n : Rest extends `${infer ParamName}?:${infer _After}`\n ? { [K in ParamName]?: string }\n : // Then handle regular delimiters (after optional parameter patterns)\n Rest extends `${infer ParamName}/${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}-${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}.${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}#${infer _After}`\n ? { [K in ParamName]: string }\n : Rest extends `${infer ParamName}:${infer _After}`\n ? { [K in ParamName]: string }\n : // Handle Express 5 repeating parameters (after regular delimiters)\n Rest extends `${infer ParamName}+${infer _After}`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*${infer _After}`\n ? { [K in ParamName]?: string[] }\n : // Handle optional parameters with ? (Express 4) - only at the end of a segment\n Rest extends `${infer ParamName}?${infer _After}`\n ? { [K in ParamName]?: string } // Parameter at absolute end of string\n : Rest extends string\n ? Rest extends \"\"\n ? {}\n : Rest extends `${infer ParamName}?`\n ? { [K in ParamName]?: string } // ParamName here doesn't include the ?\n : Rest extends `${infer ParamName}+`\n ? { [K in ParamName]: string[] }\n : Rest extends `${infer ParamName}*`\n ? { [K in ParamName]?: string[] }\n : { [K in Rest]: string }\n : {};\n\n/**\n * Remove the first parameter from path to continue parsing\n * Enhanced to handle Express 5 patterns and optional parameters\n * Handles patterns like :from-:to by removing just :from and keeping -:to\n * Order matters: regex constraints must be handled before repeating parameters\n */\ntype RemoveFirstParam<Path extends string> =\n Path extends `${infer Before}:${infer Rest}`\n ? // Handle regex constraints FIRST (before +, *, ?) to avoid conflicts\n Rest extends `${infer _ParamName}(${infer _Constraint})${infer After}`\n ? `${Before}${After}` // Handle consecutive parameters: :param-:nextParam -> -:nextParam\n : Rest extends `${infer _ParamName}-:${infer After}`\n ? `${Before}-:${After}`\n : Rest extends `${infer _ParamName}.:${infer After}`\n ? `${Before}.:${After}`\n : // Handle optional parameters followed by delimiters (before regular delimiters)\n Rest extends `${infer _ParamName}?/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}?-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}?:${infer After}`\n ? `${Before}:${After}`\n : // Handle regular separators (after optional parameter patterns)\n Rest extends `${infer _ParamName}/${infer After}`\n ? `${Before}/${After}`\n : Rest extends `${infer _ParamName}-${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}.${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}#${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}:${infer After}`\n ? `${Before}:${After}`\n : // Handle Express 5 repeating parameters (after regular separators)\n Rest extends `${infer _ParamName}+${infer After}`\n ? `${Before}${After}`\n : Rest extends `${infer _ParamName}*${infer After}`\n ? `${Before}${After}`\n : // Handle optional parameters with ?\n Rest extends `${infer _ParamName}?${infer After}`\n ? `${Before}${After}`\n : Before\n : Path;\n\n/**\n * Count wildcards to assign proper numeric indices\n */\ntype CountWildcards<\n Path extends string,\n Count extends string = \"0\"\n> = Path extends `${infer _Before}*${infer Rest}`\n ? CountWildcards<Rest, IncrementWildcard<Count>>\n : Count;\n\n/**\n * Helper type to increment wildcard count as string\n */\ntype IncrementWildcard<T extends string> = T extends \"0\"\n ? \"1\"\n : T extends \"1\"\n ? \"2\"\n : T extends \"2\"\n ? \"3\"\n : T extends \"3\"\n ? \"4\"\n : T extends \"4\"\n ? \"5\"\n : T extends \"5\"\n ? \"6\"\n : T extends \"6\"\n ? \"7\"\n : T extends \"7\"\n ? \"8\"\n : T extends \"8\"\n ? \"9\"\n : \"10\"; // Reasonable limit for wildcards\n\n/**\n * Express middleware that adds custom properties to the request object and/or response locals.\n *\n * @template TReq - The shape of the properties added to the request object.\n * @template TLocals - The shape of the properties added to response.locals.\n * @param req - The Express request object, extended with TReq.\n * @param res - The Express response object with typed locals.\n * @param next - The next middleware function.\n */\nexport type TypedMiddleware<\n TReq extends Record<string, any> = {},\n TLocals extends Record<string, any> = {}\n> = (\n req: Request & TReq,\n res: Response<any, TLocals>,\n next: NextFunction\n) => void | Promise<void>;\n\n/**\n * Simplified TypedMiddleware for request-only extensions (backward compatibility)\n */\nexport type RequestOnlyMiddleware<TReq extends Record<string, any>> =\n TypedMiddleware<TReq, {}>;\n\n/**\n * Simplified TypedMiddleware for response locals-only extensions\n */\nexport type LocalsOnlyMiddleware<TLocals extends Record<string, any>> =\n TypedMiddleware<{}, TLocals>;\n\n// Utility type to infer props from middleware array\ntype InferMiddlewareProps<T extends readonly TypedMiddleware<any, any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<infer FirstReq, any>\n ? Rest extends readonly TypedMiddleware<any, any>[]\n ? FirstReq & InferMiddlewareProps<Rest>\n : FirstReq\n : {}\n : {};\n\n// Utility type to infer locals from middleware array\ntype InferMiddlewareLocals<T extends readonly TypedMiddleware<any, any>[]> =\n T extends readonly [infer First, ...infer Rest]\n ? First extends TypedMiddleware<any, infer FirstLocals>\n ? Rest extends readonly TypedMiddleware<any, any>[]\n ? FirstLocals & InferMiddlewareLocals<Rest>\n : FirstLocals\n : {}\n : {};\n\n// Enhanced Request type with proper inference\nexport type ZodRequest<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {}\n> = Omit<Request, \"params\" | \"query\" | \"body\"> & {\n params: ExtractRouteParams<Path>;\n body: BodySchema extends ZodType<any, any, any>\n ? z.infer<BodySchema>\n : unknown;\n query: QuerySchema extends ZodType<any, any, any>\n ? z.infer<QuerySchema>\n : unknown;\n} & MiddlewareProps;\n\n// Route handler type\nexport type ZodRouteHandler<\n Path extends string = string,\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown,\n MiddlewareProps extends Record<string, any> = {},\n ResponseLocals extends Record<string, any> = {}\n> = (\n req: ZodRequest<Path, BodySchema, QuerySchema, MiddlewareProps>,\n res: Response<any, ResponseLocals>,\n next?: NextFunction\n) => void | Promise<void> | Response | Promise<Response>;\n\n/**\n * Options for defining a typed route, including schemas and middleware.\n *\n * @template BodySchema - Zod schema for request body validation.\n * @template QuerySchema - Zod schema for query parameter validation.\n * @property bodySchema - Optional Zod schema for validating the request body.\n * @property querySchema - Optional Zod schema for validating the query string.\n * @property middleware - Optional array of TypedMiddleware for this route.\n */\nexport interface RouteOptions<\n BodySchema extends ZodType<any, any, any> | unknown = unknown,\n QuerySchema extends ZodType<any, any, any> | unknown = unknown\n> {\n bodySchema?: BodySchema extends ZodType<any, any, any> ? BodySchema : never;\n querySchema?: QuerySchema extends ZodType<any, any, any>\n ? QuerySchema\n : never;\n middleware?: readonly TypedMiddleware<any, any>[];\n}\n\n// HTTP methods\nexport type HttpMethod =\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\"\n | \"options\"\n | \"head\"\n | \"all\";\n\n// Main typed router class\nclass TypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n> {\n private router: express.Router;\n\n constructor() {\n this.router = express.Router();\n }\n /**\n * Add typed middleware that extends the request with additional properties\n * and/or adds properties to response.locals\n */\n useTypedMiddleware<\n TReq extends Record<string, any> = {},\n TLocals extends Record<string, any> = {}\n >(\n middleware: TypedMiddleware<TReq, TLocals>\n ): TypedRouter<RouterMiddlewareProps & TReq, RouterLocals & TLocals> {\n this.router.use(middleware as any);\n return this as any;\n }\n /**\n * Get the underlying Express router\n */\n getRouter(): express.Router {\n return this.router;\n }\n // Method overloads for GET requests with automatic middleware type inference\n get<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Special overload for middleware type inference\n get<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Combined overload for body/query schema + middleware\n get<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema> & { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n // Implementation\n get(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"get\", path, optionsOrHandler, handler);\n }\n // Combined overload for body/query schema + middleware (most specific first)\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body schema only + middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n post<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body + Query schema without middleware\n post<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Just handler, no options\n post<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n post(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"post\", path, optionsOrHandler, handler);\n }\n // PUT method with all the same overloads as POST\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n put<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n put(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"put\", path, optionsOrHandler, handler);\n }\n // PATCH method with all the same overloads as POST\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n patch<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n patch(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"patch\", path, optionsOrHandler, handler);\n } // DELETE method (typically no body, but can have query params and middleware)\n // Most specific first: query schema + middleware\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n delete<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n delete<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n delete<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n delete(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"delete\", path, optionsOrHandler, handler);\n } // OPTIONS method (typically no body, used for CORS preflight)\n // Most specific first: query schema + middleware\n options<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n options<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n options<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n options<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n options(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"options\", path, optionsOrHandler, handler);\n } // HEAD method (like GET but only returns headers)\n // Most specific first: query schema + middleware\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema only\n head<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: { querySchema: QuerySchema },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only\n head<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n head<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n head(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"head\", path, optionsOrHandler, handler);\n } // ALL method (matches all HTTP methods)\n // Most specific first: body + query + middleware\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: {\n bodySchema: BodySchema;\n querySchema?: QuerySchema;\n middleware: Middleware;\n },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body schema + middleware (no query)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any>,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { bodySchema: BodySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Query schema + middleware (no body)\n all<\n Path extends string,\n QuerySchema extends ZodType<any, any, any> | unknown,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { querySchema: QuerySchema; middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n QuerySchema,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Body + query schemas (no middleware)\n all<\n Path extends string,\n BodySchema extends ZodType<any, any, any> | unknown,\n QuerySchema extends ZodType<any, any, any> | unknown\n >(\n path: Path,\n options: RouteOptions<BodySchema, QuerySchema>,\n handler: ZodRouteHandler<\n Path,\n BodySchema,\n QuerySchema,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Middleware only (no schemas)\n all<\n Path extends string,\n Middleware extends readonly TypedMiddleware<any, any>[]\n >(\n path: Path,\n options: { middleware: Middleware },\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps & InferMiddlewareProps<Middleware>,\n RouterLocals & InferMiddlewareLocals<Middleware>\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n\n // Basic overload with no options\n all<Path extends string>(\n path: Path,\n handler: ZodRouteHandler<\n Path,\n unknown,\n unknown,\n RouterMiddlewareProps,\n RouterLocals\n >\n ): TypedRouter<RouterMiddlewareProps, RouterLocals>;\n all(\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return this.registerRoute(\"all\", path, optionsOrHandler, handler);\n }\n // Helper method to register routes\n private registerRoute(\n method: HttpMethod,\n path: string,\n optionsOrHandler: any,\n handler?: any\n ): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n const middlewares: any[] = [];\n\n if (typeof optionsOrHandler === \"object\") {\n const options = optionsOrHandler as RouteOptions<any, any>;\n\n // Add per-route middleware first\n if (options.middleware) {\n middlewares.push(...options.middleware);\n }\n\n // Add schema validation middleware\n if (options.bodySchema) {\n middlewares.push(\n this.createBodyValidationMiddleware(options.bodySchema)\n );\n }\n if (options.querySchema) {\n middlewares.push(\n this.createQueryValidationMiddleware(options.querySchema)\n );\n }\n\n // Add the main handler\n middlewares.push(handler);\n } else {\n // Direct handler without options\n middlewares.push(optionsOrHandler);\n }\n\n // Register with Express router\n (this.router as any)[method](path, ...middlewares);\n\n return this;\n }\n\n private createBodyValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.body = schema.parse(req.body);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n\n private createQueryValidationMiddleware(schema: ZodType<any, any, any>) {\n return (req: Request, res: Response, next: NextFunction) => {\n try {\n req.query = schema.parse(req.query);\n next();\n } catch (error) {\n if (error instanceof z.ZodError) {\n res.status(400).json({\n error: \"Validation failed\",\n details: error.errors,\n });\n } else {\n next(error);\n }\n }\n };\n }\n}\n\n/**\n * Create a new strongly-typed Express router instance.\n *\n * This is the simplest way to get started with @minisylar/express-typed-router.\n *\n * @example\n * import { createTypedRouter } from '@minisylar/express-typed-router';\n *\n * // Create a router and add a typed GET route\n * const router = createTypedRouter();\n * router.get('/hello/:name', (req, res) => {\n * // req.params.name is typed as string\n * res.json({ message: `Hello, ${req.params.name}!` });\n * });\n *\n * // Use with Express\n * import express from 'express';\n * const app = express();\n * app.use('/api', router.getRouter());\n */\nexport function createTypedRouter<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n>(): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n return new TypedRouter<RouterMiddlewareProps, RouterLocals>();\n}\n\n// Option 2: Factory with optional configuration\n\n/**\n * Configuration options for createTypedRouterWithConfig.\n *\n * @property validateInput - (Future) Whether to enable global input validation.\n * @property errorHandler - Optional global error handler middleware for the router.\n */\nexport interface RouterConfig {\n validateInput?: boolean;\n errorHandler?: (\n error: any,\n req: Request,\n res: Response,\n next: NextFunction\n ) => void;\n}\n\n/**\n * Create a new typed router with optional configuration.\n *\n * Use this if you want to add a global error handler or future global options.\n *\n * @param config - Optional configuration for the router (e.g. error handler).\n * @returns A new TypedRouter instance.\n *\n * @example\n * import { createTypedRouterWithConfig } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithConfig({\n * errorHandler: (err, req, res, next) => {\n * res.status(500).json({ error: 'Something went wrong', details: err });\n * }\n * });\n */\nexport function createTypedRouterWithConfig<\n RouterMiddlewareProps extends Record<string, any> = {},\n RouterLocals extends Record<string, any> = {}\n>(config?: RouterConfig): TypedRouter<RouterMiddlewareProps, RouterLocals> {\n const router = new TypedRouter<RouterMiddlewareProps, RouterLocals>();\n if (config?.errorHandler) {\n router.getRouter().use(config.errorHandler);\n }\n return router;\n}\n\n// Option 3: Factory with pre-configured middleware\n\n/**\n * Create a new typed router with pre-configured middleware.\n *\n * This is useful for setting up router-level middleware in a single call.\n *\n * @param middleware - One or more TypedMiddleware functions to apply to all routes.\n * @returns A new TypedRouter instance with the middleware applied.\n *\n * @example\n * import { createTypedRouterWithMiddleware } from '@minisylar/express-typed-router';\n *\n * const router = createTypedRouterWithMiddleware(authMiddleware, loggingMiddleware);\n */\nexport function createTypedRouterWithMiddleware<T extends Record<string, any>>(\n ...middleware: TypedMiddleware<any, any>[]\n): TypedRouter<T> {\n let router = new TypedRouter() as any;\n for (const mw of middleware) {\n router = router.useTypedMiddleware(mw);\n }\n return router;\n}\n"],"mappings":";;;;AAycA,IAAM,cAAN,MAGE;CACA,AAAQ;CAER,cAAc;AACZ,OAAK,SAAS,QAAQ,QAAQ;CAC/B;;;;;CAKD,mBAIEA,YACmE;AACnE,OAAK,OAAO,IAAI,WAAkB;AAClC,SAAO;CACR;;;;CAID,YAA4B;AAC1B,SAAO,KAAK;CACb;CA+DD,IACEC,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAqFD,KACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAgFD,IACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAgFD,MACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,SAAS,MAAM,kBAAkB,QAAQ;CACpE;CA6DD,OACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,UAAU,MAAM,kBAAkB,QAAQ;CACrE;CA6DD,QACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,WAAW,MAAM,kBAAkB,QAAQ;CACtE;CA6DD,KACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,QAAQ,MAAM,kBAAkB,QAAQ;CACnE;CAqGD,IACEF,MACAC,kBACAC,SACkD;AAClD,SAAO,KAAK,cAAc,OAAO,MAAM,kBAAkB,QAAQ;CAClE;CAED,AAAQ,cACNC,QACAH,MACAC,kBACAC,SACkD;EAClD,MAAME,cAAqB,CAAE;AAE7B,aAAW,qBAAqB,UAAU;GACxC,MAAM,UAAU;AAGhB,OAAI,QAAQ,WACV,aAAY,KAAK,GAAG,QAAQ,WAAW;AAIzC,OAAI,QAAQ,WACV,aAAY,KACV,KAAK,+BAA+B,QAAQ,WAAW,CACxD;AAEH,OAAI,QAAQ,YACV,aAAY,KACV,KAAK,gCAAgC,QAAQ,YAAY,CAC1D;AAIH,eAAY,KAAK,QAAQ;EAC1B,MAEC,aAAY,KAAK,iBAAiB;AAIpC,EAAC,KAAK,OAAe,QAAQ,MAAM,GAAG,YAAY;AAElD,SAAO;CACR;CAED,AAAQ,+BAA+BC,QAAgC;AACrE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,OAAO,OAAO,MAAM,IAAI,KAAK;AACjC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiB,EAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;CAED,AAAQ,gCAAgCH,QAAgC;AACtE,SAAO,CAACC,KAAcC,KAAeC,SAAuB;AAC1D,OAAI;AACF,QAAI,QAAQ,OAAO,MAAM,IAAI,MAAM;AACnC,UAAM;GACP,SAAQ,OAAO;AACd,QAAI,iBAAiB,EAAE,SACrB,KAAI,OAAO,IAAI,CAAC,KAAK;KACnB,OAAO;KACP,SAAS,MAAM;IAChB,EAAC;QAEF,MAAK,MAAM;GAEd;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,oBAGsC;AACpD,QAAO,IAAI;AACZ;;;;;;;;;;;;;;;;;;AAqCD,SAAgB,4BAGdC,QAAyE;CACzE,MAAM,SAAS,IAAI;AACnB,KAAI,QAAQ,aACV,QAAO,WAAW,CAAC,IAAI,OAAO,aAAa;AAE7C,QAAO;AACR;;;;;;;;;;;;;;AAiBD,SAAgB,gCACd,GAAG,YACa;CAChB,IAAI,SAAS,IAAI;AACjB,MAAK,MAAM,MAAM,WACf,UAAS,OAAO,mBAAmB,GAAG;AAExC,QAAO;AACR"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minisylar/express-typed-router",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A strongly-typed Express router with Zod validation and automatic type inference for params, body, query, and middleware",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/zod-router.cjs",
|