@visulima/connect 1.2.0 → 1.3.1
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/CHANGELOG.md +14 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -7
- package/src/adapter/express.ts +0 -18
- package/src/adapter/with-zod.ts +0 -35
- package/src/edge.ts +0 -165
- package/src/index.ts +0 -22
- package/src/node.ts +0 -173
- package/src/regexparam.d.ts +0 -10
- package/src/router.ts +0 -195
- package/src/types.d.ts +0 -36
- package/src/utils/send-json.ts +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## @visulima/connect [1.3.1](https://github.com/visulima/visulima/compare/@visulima/connect@1.3.0...@visulima/connect@1.3.1) (2022-12-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* added correct folder to files key in package.json ([da9f987](https://github.com/visulima/visulima/commit/da9f9871462a0b2663046cde5f05e9a90df4c496))
|
|
7
|
+
|
|
8
|
+
## @visulima/connect [1.3.0](https://github.com/visulima/visulima/compare/@visulima/connect@1.2.0...@visulima/connect@1.3.0) (2022-11-16)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **health-check:** adding new health-check package ([#17](https://github.com/visulima/visulima/issues/17)) ([2e2a89f](https://github.com/visulima/visulima/commit/2e2a89fe85214237c9f55bf00d76b69de691ee3e))
|
|
14
|
+
|
|
1
15
|
## @visulima/connect [1.2.0](https://github.com/visulima/visulima/compare/@visulima/connect@1.1.1...@visulima/connect@1.2.0) (2022-11-15)
|
|
2
16
|
|
|
3
17
|
|
package/dist/index.js
CHANGED
|
@@ -142,7 +142,7 @@ var Router = class {
|
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
// src/edge.ts
|
|
145
|
-
var onNoMatch = async (request) => new Response(request.method
|
|
145
|
+
var onNoMatch = async (request) => new Response(request.method === "HEAD" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });
|
|
146
146
|
var onError = async (error) => {
|
|
147
147
|
console.error(error);
|
|
148
148
|
return new Response("Internal Server Error", { status: 500 });
|
|
@@ -231,7 +231,7 @@ var express_default = expressWrapper;
|
|
|
231
231
|
// src/node.ts
|
|
232
232
|
var onNoMatch2 = async (request, response) => {
|
|
233
233
|
response.statusCode = 404;
|
|
234
|
-
response.end(request.method
|
|
234
|
+
response.end(request.method === "HEAD" ? void 0 : `Route ${request.method} ${request.url} not found`);
|
|
235
235
|
};
|
|
236
236
|
var onError2 = async (error, _request, response) => {
|
|
237
237
|
response.statusCode = 500;
|
|
@@ -240,7 +240,7 @@ var onError2 = async (error, _request, response) => {
|
|
|
240
240
|
};
|
|
241
241
|
function getPathname2(url) {
|
|
242
242
|
const queryIndex = url.indexOf("?");
|
|
243
|
-
return queryIndex
|
|
243
|
+
return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));
|
|
244
244
|
}
|
|
245
245
|
var NodeRouter = class {
|
|
246
246
|
constructor(options = {}) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["onNoMatch","onError","getPathname"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodError, ZodObject } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request extends object,\n Response extends unknown,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: RouteMatch | Nextable<H>, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: RouteMatch | Nextable<H> | Router<H>, ...fns: (Nextable<H> | Router<H>)[]) {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string) {\n return new Router<H>(base, [...this.routes]);\n }\n\n static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line radar/cognitive-complexity\n find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line radar/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-ignore @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-ignore @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const base = function_.base as string;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (stripPathname[0] != \"/\") {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport { Route, Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method !== \"HEAD\" ? `Route ${request.method} ${request.url} not found` : null, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }) {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl || new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n || (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<R, Context>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<R, Context>>,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>,\n ...fns: (Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>)[]\n ) {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: R, context_: Context) {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n) {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method !== \"HEAD\" ? `Route ${request.method} ${request.url} not found` : undefined);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string) {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex !== -1 ? url.slice(0, Math.max(0, queryIndex)) : url;\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch;\n this.onError = options.onError || onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<Request, Response>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<Request, Response>>,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(\n zodOrRouteOrFunction as Schema,\n routeOrFunction,\n )];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ) {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ) => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: any): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"names":["onNoMatch","onError","getPathname"],"mappings":"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","sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodError, ZodObject } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request extends object,\n Response extends unknown,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: RouteMatch | Nextable<H>, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: RouteMatch | Nextable<H> | Router<H>, ...fns: (Nextable<H> | Router<H>)[]) {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string) {\n return new Router<H>(base, [...this.routes]);\n }\n\n static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line radar/cognitive-complexity\n find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line radar/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-ignore @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-ignore @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const base = function_.base as string;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (stripPathname[0] != \"/\") {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport { Route, Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }) {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl || new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n || (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<R, Context>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<R, Context>>,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>,\n ...fns: (Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>)[]\n ) {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: R, context_: Context) {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n) {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string) {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch;\n this.onError = options.onError || onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<Request, Response>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<Request, Response>>,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(\n zodOrRouteOrFunction as Schema,\n routeOrFunction,\n )];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ) {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ) => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: any): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -142,7 +142,7 @@ var Router = class {
|
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
// src/edge.ts
|
|
145
|
-
var onNoMatch = async (request) => new Response(request.method
|
|
145
|
+
var onNoMatch = async (request) => new Response(request.method === "HEAD" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });
|
|
146
146
|
var onError = async (error) => {
|
|
147
147
|
console.error(error);
|
|
148
148
|
return new Response("Internal Server Error", { status: 500 });
|
|
@@ -231,7 +231,7 @@ var express_default = expressWrapper;
|
|
|
231
231
|
// src/node.ts
|
|
232
232
|
var onNoMatch2 = async (request, response) => {
|
|
233
233
|
response.statusCode = 404;
|
|
234
|
-
response.end(request.method
|
|
234
|
+
response.end(request.method === "HEAD" ? void 0 : `Route ${request.method} ${request.url} not found`);
|
|
235
235
|
};
|
|
236
236
|
var onError2 = async (error, _request, response) => {
|
|
237
237
|
response.statusCode = 500;
|
|
@@ -240,7 +240,7 @@ var onError2 = async (error, _request, response) => {
|
|
|
240
240
|
};
|
|
241
241
|
function getPathname2(url) {
|
|
242
242
|
const queryIndex = url.indexOf("?");
|
|
243
|
-
return queryIndex
|
|
243
|
+
return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));
|
|
244
244
|
}
|
|
245
245
|
var NodeRouter = class {
|
|
246
246
|
constructor(options = {}) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodError, ZodObject } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request extends object,\n Response extends unknown,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: RouteMatch | Nextable<H>, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: RouteMatch | Nextable<H> | Router<H>, ...fns: (Nextable<H> | Router<H>)[]) {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string) {\n return new Router<H>(base, [...this.routes]);\n }\n\n static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line radar/cognitive-complexity\n find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line radar/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-ignore @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-ignore @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const base = function_.base as string;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (stripPathname[0] != \"/\") {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport { Route, Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method !== \"HEAD\" ? `Route ${request.method} ${request.url} not found` : null, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }) {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl || new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n || (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<R, Context>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<R, Context>>,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>,\n ...fns: (Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>)[]\n ) {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: R, context_: Context) {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n) {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method !== \"HEAD\" ? `Route ${request.method} ${request.url} not found` : undefined);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string) {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex !== -1 ? url.slice(0, Math.max(0, queryIndex)) : url;\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch;\n this.onError = options.onError || onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<Request, Response>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<Request, Response>>,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(\n zodOrRouteOrFunction as Schema,\n routeOrFunction,\n )];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ) {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ) => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: any): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"],"mappings":"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","names":["onNoMatch","onError","getPathname"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter/with-zod.ts","../src/router.ts","../src/edge.ts","../src/adapter/express.ts","../src/node.ts","../src/utils/send-json.ts"],"sourcesContent":["import createHttpError from \"http-errors\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodError, ZodObject } from \"zod\";\n\nimport type { Nextable, NextHandler } from \"../types\";\n\nconst withZod = <\n Request extends object,\n Response extends unknown,\n Handler extends Nextable<any>,\n Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n >(\n schema: Schema,\n handler: Handler,\n ): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {\n let transformedRequest: Request = request;\n\n try {\n transformedRequest = (await schema.parseAsync(request)) as Request;\n } catch (error: any) {\n let { message } = error;\n\n // eslint-disable-next-line unicorn/consistent-destructuring\n if (error instanceof ZodError && typeof error.format === \"function\") {\n // eslint-disable-next-line unicorn/consistent-destructuring\n message = error.issues.map((issue) => `${issue.path.join(\"/\")} - ${issue.message}`).join(\"/n\");\n }\n\n throw createHttpError(422, message);\n }\n\n return handler(transformedRequest, response, next);\n };\n\nexport default withZod;\n","/**\n * Agnostic router class\n * Adapted from lukeed/trouter library:\n * https://github.com/lukeed/trouter/blob/master/index.mjs\n */\nimport { parse } from \"regexparam\";\n\nimport type {\n FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,\n} from \"./types\";\n\nexport type Route<H> = {\n method: HttpMethod | \"\";\n fns: (H | Router<H extends FunctionLike ? H : never>)[];\n isMiddleware: boolean;\n} & (\n | {\n keys: string[] | false;\n pattern: RegExp;\n }\n | { matchAll: true }\n);\n\nexport class Router<H extends FunctionLike> {\n constructor(public base: string = \"/\", public routes: Route<Nextable<H>>[] = []) {}\n\n public add(method: HttpMethod | \"\", route: RouteMatch | Nextable<H>, ...fns: Nextable<H>[]): this {\n if (typeof route === \"function\") {\n fns.unshift(route);\n // eslint-disable-next-line no-param-reassign\n route = \"\";\n }\n\n if (route === \"\") {\n this.routes.push({\n matchAll: true,\n method,\n fns,\n isMiddleware: false,\n });\n } else {\n const { keys, pattern } = parse(route);\n\n this.routes.push({\n keys,\n pattern,\n method,\n fns,\n isMiddleware: false,\n });\n }\n\n return this;\n }\n\n public use(base: RouteMatch | Nextable<H> | Router<H>, ...fns: (Nextable<H> | Router<H>)[]) {\n if (typeof base === \"function\" || base instanceof Router) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n // mount subrouter\n // eslint-disable-next-line no-param-reassign\n fns = fns.map((function_) => {\n if (function_ instanceof Router) {\n if (typeof base === \"string\") return function_.clone(base);\n throw new Error(\"Mounting a router to RegExp base is not supported\");\n }\n return function_;\n });\n\n const { keys, pattern } = parse(base, true);\n\n this.routes.push({\n keys,\n pattern,\n method: \"\",\n fns,\n isMiddleware: true,\n });\n\n return this;\n }\n\n public clone(base?: string) {\n return new Router<H>(base, [...this.routes]);\n }\n\n static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {\n let index = 0;\n\n // eslint-disable-next-line no-plusplus\n const next = () => (fns[++index] as FunctionLike)(...arguments_, next);\n\n return (fns[index] as FunctionLike)(...arguments_, next);\n }\n\n // eslint-disable-next-line radar/cognitive-complexity\n find(method: HttpMethod, pathname: string): FindResult<H> {\n let middleOnly = true;\n\n const fns: Nextable<H>[] = [];\n const parameters: Record<string, string> = {};\n const isHead = method === \"HEAD\";\n\n // eslint-disable-next-line radar/cognitive-complexity\n Object.values(this.routes).forEach((route) => {\n if (\n route.method !== method\n // matches any method\n && route.method !== \"\"\n // The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...\n && !(isHead && route.method === \"GET\")\n ) {\n return;\n }\n\n let matched = false;\n\n if (\"matchAll\" in route) {\n matched = true;\n } else if (route.keys === false) {\n // routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n // eslint-disable-next-line no-void\n if (matches.groups !== void 0) {\n Object.keys(matches.groups).forEach((key) => {\n // @ts-ignore @TODO: fix this\n parameters[key] = matches.groups[key] as string;\n });\n }\n\n matched = true;\n } else if (route.keys.length > 0) {\n const matches = route.pattern.exec(pathname);\n\n if (matches === null) {\n return;\n }\n\n for (let index = 0; index < route.keys.length;) {\n const parameterKey = route.keys[index];\n\n // @ts-ignore @TODO: fix this\n // eslint-disable-next-line no-plusplus\n parameters[parameterKey] = matches[++index];\n }\n\n matched = true;\n } else if (route.pattern.test(pathname)) {\n matched = true;\n } // else not a match\n\n if (matched) {\n fns.push(\n ...route.fns.flatMap((function_) => {\n if (function_ instanceof Router) {\n const base = function_.base as string;\n\n let stripPathname = pathname.slice(base.length);\n\n // fix stripped pathname, not sure why this happens\n // eslint-disable-next-line eqeqeq\n if (stripPathname[0] != \"/\") {\n stripPathname = `/${stripPathname}`;\n }\n\n // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument\n const result = function_.find(method, stripPathname);\n\n if (!result.middleOnly) {\n middleOnly = false;\n }\n\n // merge params\n Object.assign(parameters, result.params);\n\n return result.fns;\n }\n\n return function_;\n }),\n );\n if (!route.isMiddleware) middleOnly = false;\n }\n });\n\n return { fns, params: parameters, middleOnly };\n }\n}\n","import type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport { Route, Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\n// eslint-disable-next-line max-len\nconst onNoMatch = async (request: Request) => new Response(request.method === \"HEAD\" ? null : `Route ${request.method} ${request.url} not found`, { status: 404 });\n\nconst onError = async (error: unknown) => {\n // eslint-disable-next-line no-console\n console.error(error);\n return new Response(\"Internal Server Error\", { status: 500 });\n};\n\nexport function getPathname(request: Request & { nextUrl?: URL }) {\n // eslint-disable-next-line compat/compat\n return (request.nextUrl || new URL(request.url)).pathname;\n}\n\n// eslint-disable-next-line max-len\nexport type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;\n\nexport class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {\n private router = new Router<RequestHandler<R, Context>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;\n this.onError = options.onError\n || (onError as unknown as (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<R, Context>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<R, Context>>,\n ...fns: Nextable<RequestHandler<R, Context>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>,\n ...fns: (Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>)[]\n ) {\n if (typeof base === \"function\" || base instanceof EdgeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n\n this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: R, context_: Context) {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, context_);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: R, context_: Context): Promise<any> => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request));\n\n this.prepareRequest(request, result);\n\n try {\n return await (result.fns.length === 0 || result.middleOnly\n ? this.onNoMatch(request, context_, routes)\n : Router.exec(result.fns, request, context_));\n } catch (error) {\n return this.onError(error, request, context_, routes);\n }\n };\n }\n}\n\nexport function createEdgeRouter<R extends Request, Context>(\n options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},\n) {\n return new EdgeRouter<R, Context, Response>(options);\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { RequestHandler } from \"../node\";\nimport type { Nextable } from \"../types\";\n\ntype NextFunction = (error?: any) => void;\n\nconst expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(\n function_: ExpressRequestHandler<Request, Response>,\n // eslint-disable-next-line compat/compat\n): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {\n function_(request, response, (error) => (error ? reject(error) : resolve()));\n // eslint-disable-next-line promise/no-callback-in-promise\n }).then(next);\n\nexport type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;\n\nexport default expressWrapper;\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { AnyZodObject } from \"zod\";\nimport { ZodObject } from \"zod\";\n\nimport withZod from \"./adapter/with-zod\";\nimport type { Route } from \"./router\";\nimport { Router } from \"./router\";\nimport type {\n FindResult,\n FunctionLike,\n HandlerOptions,\n HttpMethod,\n Nextable,\n RouteMatch,\n RoutesExtendedRequestHandler,\n RouteShortcutMethod,\n ValueOrPromise,\n} from \"./types\";\n\nconst onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 404;\n response.end(request.method === \"HEAD\" ? undefined : `Route ${request.method} ${request.url} not found`);\n};\n\nconst onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {\n response.statusCode = 500;\n // eslint-disable-next-line no-console\n console.error(error);\n\n response.end(\"Internal Server Error\");\n};\n\nexport function getPathname(url: string) {\n const queryIndex = url.indexOf(\"?\");\n\n return queryIndex === -1 ? url : url.slice(0, Math.max(0, queryIndex));\n}\n\nexport type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;\n\nexport class NodeRouter<\n Request extends IncomingMessage = IncomingMessage,\n Response extends ServerResponse = ServerResponse,\n Schema extends AnyZodObject = ZodObject<any>,\n> {\n private router = new Router<RequestHandler<Request, Response>>();\n\n private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;\n\n private readonly onError: (\n error: unknown,\n ...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>\n ) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;\n\n constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {\n this.onNoMatch = options.onNoMatch || onNoMatch;\n this.onError = options.onError || onError;\n }\n\n private add(\n method: HttpMethod | \"\",\n routeOrFunction: RouteMatch | Nextable<RequestHandler<Request, Response>>,\n zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<Request, Response>>,\n ...fns: Nextable<RequestHandler<Request, Response>>[]\n ) {\n if (typeof routeOrFunction === \"string\" && typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n } else if (typeof zodOrRouteOrFunction === \"object\") {\n // eslint-disable-next-line unicorn/prefer-ternary\n if (typeof routeOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(\n zodOrRouteOrFunction as Schema,\n routeOrFunction,\n )];\n } else {\n // eslint-disable-next-line no-param-reassign,max-len\n fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));\n }\n } else if (typeof zodOrRouteOrFunction === \"function\") {\n // eslint-disable-next-line no-param-reassign\n fns = [zodOrRouteOrFunction];\n }\n\n this.router.add(method, routeOrFunction, ...fns);\n\n return this;\n }\n\n public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"\");\n\n public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"GET\");\n\n public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"HEAD\");\n\n public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"POST\");\n\n public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PUT\");\n\n public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"PATCH\");\n\n public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, \"DELETE\");\n\n public use(\n base: RouteMatch | Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>,\n ...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]\n ) {\n if (typeof base === \"function\" || base instanceof NodeRouter) {\n fns.unshift(base);\n // eslint-disable-next-line no-param-reassign\n base = \"/\";\n }\n this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));\n\n return this;\n }\n\n // eslint-disable-next-line class-methods-use-this\n private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {\n request.params = {\n ...findResult.params,\n ...request.params, // original params will take precedence\n };\n }\n\n public clone() {\n const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });\n\n r.router = this.router.clone();\n\n return r;\n }\n\n async run(request: Request, response: Response): Promise<unknown> {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n if (result.fns.length === 0) {\n return;\n }\n\n this.prepareRequest(request, result);\n\n // eslint-disable-next-line consistent-return\n return Router.exec(result.fns, request, response);\n }\n\n handler() {\n const { routes } = this.router as Router<FunctionLike>;\n\n return async (request: Request, response: Response) => {\n // eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument\n const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));\n\n this.prepareRequest(request, result);\n\n try {\n await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));\n } catch (error) {\n await this.onError(error, request, response, routes);\n }\n };\n }\n}\n\nexport const createRouter = <\n Request extends IncomingMessage,\n Response extends ServerResponse,\n Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,\n>(\n options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},\n ) => new NodeRouter<Request, Response, Schema>(options);\n","import type { ServerResponse } from \"node:http\";\n\n/**\n * Send `JSON` object\n * @param {ServerResponse} response response object\n * @param {number} statusCode\n * @param {any} jsonBody of data\n */\nconst sendJson = (response: ServerResponse, statusCode: number, jsonBody: any): void => {\n // Set header to application/json\n response.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n\n response.statusCode = statusCode;\n response.end(JSON.stringify(jsonBody, null, 2));\n};\n\nexport default sendJson;\n"],"mappings":"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","names":["onNoMatch","onError","getPathname"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/connect",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "The minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2 with support for zod validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"javascript",
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
"source": "src/index.ts",
|
|
53
53
|
"types": "dist/index.d.ts",
|
|
54
54
|
"files": [
|
|
55
|
-
"
|
|
56
|
-
"dist",
|
|
55
|
+
"dist/**",
|
|
57
56
|
"README.md",
|
|
58
57
|
"CHANGELOG.md",
|
|
59
58
|
"LICENSE.md"
|
|
@@ -64,7 +63,7 @@
|
|
|
64
63
|
"clean": "rimraf node_modules dist",
|
|
65
64
|
"coverage": "vitest run --coverage",
|
|
66
65
|
"dev": "pnpm predev && pnpm run build --watch",
|
|
67
|
-
"lint:eslint": "cross-env NO_LOGS=true eslint --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs",
|
|
66
|
+
"lint:eslint": "cross-env NO_LOGS=true eslint . --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs --cache --cache-strategy content .",
|
|
68
67
|
"lint:eslint:fix": "pnpm run lint:eslint --fix",
|
|
69
68
|
"test": "vitest"
|
|
70
69
|
},
|
|
@@ -80,7 +79,7 @@
|
|
|
80
79
|
"@types/node": "^18.11.5",
|
|
81
80
|
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
|
82
81
|
"@typescript-eslint/parser": "^5.41.0",
|
|
83
|
-
"@vitest/coverage-c8": "^0.
|
|
82
|
+
"@vitest/coverage-c8": "^0.25.0",
|
|
84
83
|
"c8": "^7.12.0",
|
|
85
84
|
"cross-env": "^7.0.3",
|
|
86
85
|
"eslint": "^8.26.0",
|
|
@@ -101,7 +100,7 @@
|
|
|
101
100
|
"eslint-plugin-simple-import-sort": "^8.0.0",
|
|
102
101
|
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
103
102
|
"eslint-plugin-testing-library": "^5.9.1",
|
|
104
|
-
"eslint-plugin-unicorn": "^
|
|
103
|
+
"eslint-plugin-unicorn": "^45.0.0",
|
|
105
104
|
"eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0",
|
|
106
105
|
"eslint-plugin-you-dont-need-momentjs": "^1.6.0",
|
|
107
106
|
"express": "^4.18.2",
|
|
@@ -113,7 +112,7 @@
|
|
|
113
112
|
"semantic-release": "^19.0.5",
|
|
114
113
|
"tsup": "^6.3.0",
|
|
115
114
|
"typescript": "^4.8.4",
|
|
116
|
-
"vitest": "^0.
|
|
115
|
+
"vitest": "^0.25.0",
|
|
117
116
|
"zod": "^3.19.1"
|
|
118
117
|
},
|
|
119
118
|
"peerDependencies": {
|
package/src/adapter/express.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
|
|
3
|
-
import type { RequestHandler } from "../node";
|
|
4
|
-
import type { Nextable } from "../types";
|
|
5
|
-
|
|
6
|
-
type NextFunction = (error?: any) => void;
|
|
7
|
-
|
|
8
|
-
const expressWrapper = <Request extends IncomingMessage, Response extends ServerResponse>(
|
|
9
|
-
function_: ExpressRequestHandler<Request, Response>,
|
|
10
|
-
// eslint-disable-next-line compat/compat
|
|
11
|
-
): Nextable<RequestHandler<Request, Response>> => (request, response, next) => new Promise<void>((resolve, reject) => {
|
|
12
|
-
function_(request, response, (error) => (error ? reject(error) : resolve()));
|
|
13
|
-
// eslint-disable-next-line promise/no-callback-in-promise
|
|
14
|
-
}).then(next);
|
|
15
|
-
|
|
16
|
-
export type ExpressRequestHandler<Request, Response> = (request: Request, response: Response, next: NextFunction) => void;
|
|
17
|
-
|
|
18
|
-
export default expressWrapper;
|
package/src/adapter/with-zod.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import createHttpError from "http-errors";
|
|
2
|
-
import type { AnyZodObject } from "zod";
|
|
3
|
-
import { ZodError, ZodObject } from "zod";
|
|
4
|
-
|
|
5
|
-
import type { Nextable, NextHandler } from "../types";
|
|
6
|
-
|
|
7
|
-
const withZod = <
|
|
8
|
-
Request extends object,
|
|
9
|
-
Response extends unknown,
|
|
10
|
-
Handler extends Nextable<any>,
|
|
11
|
-
Schema extends ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,
|
|
12
|
-
>(
|
|
13
|
-
schema: Schema,
|
|
14
|
-
handler: Handler,
|
|
15
|
-
): ((request: Request, response: Response, next: NextHandler) => Promise<Response>) => async (request: Request, response: Response, next) => {
|
|
16
|
-
let transformedRequest: Request = request;
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
transformedRequest = (await schema.parseAsync(request)) as Request;
|
|
20
|
-
} catch (error: any) {
|
|
21
|
-
let { message } = error;
|
|
22
|
-
|
|
23
|
-
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
24
|
-
if (error instanceof ZodError && typeof error.format === "function") {
|
|
25
|
-
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
26
|
-
message = error.issues.map((issue) => `${issue.path.join("/")} - ${issue.message}`).join("/n");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
throw createHttpError(422, message);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return handler(transformedRequest, response, next);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default withZod;
|
package/src/edge.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import type { AnyZodObject } from "zod";
|
|
2
|
-
import { ZodObject } from "zod";
|
|
3
|
-
|
|
4
|
-
import withZod from "./adapter/with-zod";
|
|
5
|
-
import { Route, Router } from "./router";
|
|
6
|
-
import type {
|
|
7
|
-
FindResult,
|
|
8
|
-
FunctionLike,
|
|
9
|
-
HandlerOptions,
|
|
10
|
-
HttpMethod,
|
|
11
|
-
Nextable,
|
|
12
|
-
RouteMatch,
|
|
13
|
-
RoutesExtendedRequestHandler,
|
|
14
|
-
RouteShortcutMethod,
|
|
15
|
-
ValueOrPromise,
|
|
16
|
-
} from "./types";
|
|
17
|
-
|
|
18
|
-
// eslint-disable-next-line max-len
|
|
19
|
-
const onNoMatch = async (request: Request) => new Response(request.method !== "HEAD" ? `Route ${request.method} ${request.url} not found` : null, { status: 404 });
|
|
20
|
-
|
|
21
|
-
const onError = async (error: unknown) => {
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
|
-
console.error(error);
|
|
24
|
-
return new Response("Internal Server Error", { status: 500 });
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export function getPathname(request: Request & { nextUrl?: URL }) {
|
|
28
|
-
// eslint-disable-next-line compat/compat
|
|
29
|
-
return (request.nextUrl || new URL(request.url)).pathname;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line max-len
|
|
33
|
-
export type RequestHandler<R extends Request, Context> = (request: R, context_: Context) => ValueOrPromise<Response | void>;
|
|
34
|
-
|
|
35
|
-
export class EdgeRouter<R extends Request = Request, Context = unknown, RResponse extends Response = Response, Schema extends AnyZodObject = ZodObject<any>> {
|
|
36
|
-
private router = new Router<RequestHandler<R, Context>>();
|
|
37
|
-
|
|
38
|
-
private readonly onNoMatch: RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;
|
|
39
|
-
|
|
40
|
-
private readonly onError: (
|
|
41
|
-
error: unknown,
|
|
42
|
-
...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>
|
|
43
|
-
) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>;
|
|
44
|
-
|
|
45
|
-
constructor(options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>> = {}) {
|
|
46
|
-
this.onNoMatch = options.onNoMatch || onNoMatch as unknown as RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>;
|
|
47
|
-
this.onError = options.onError
|
|
48
|
-
|| (onError as unknown as (
|
|
49
|
-
error: unknown,
|
|
50
|
-
...arguments_: Parameters<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>
|
|
51
|
-
) => ReturnType<RoutesExtendedRequestHandler<R, Context, RResponse, Route<Nextable<FunctionLike>>[]>>);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private add(
|
|
55
|
-
method: HttpMethod | "",
|
|
56
|
-
routeOrFunction: RouteMatch | Nextable<RequestHandler<R, Context>>,
|
|
57
|
-
zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<R, Context>>,
|
|
58
|
-
...fns: Nextable<RequestHandler<R, Context>>[]
|
|
59
|
-
) {
|
|
60
|
-
if (typeof routeOrFunction === "string" && typeof zodOrRouteOrFunction === "function") {
|
|
61
|
-
// eslint-disable-next-line no-param-reassign
|
|
62
|
-
fns = [zodOrRouteOrFunction];
|
|
63
|
-
} else if (typeof zodOrRouteOrFunction === "object") {
|
|
64
|
-
// eslint-disable-next-line unicorn/prefer-ternary
|
|
65
|
-
if (typeof routeOrFunction === "function") {
|
|
66
|
-
// eslint-disable-next-line no-param-reassign
|
|
67
|
-
fns = [withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, routeOrFunction)];
|
|
68
|
-
} else {
|
|
69
|
-
// eslint-disable-next-line no-param-reassign,max-len
|
|
70
|
-
fns = fns.map((function_) => withZod<R, Context, Nextable<RequestHandler<R, Context>>, Schema>(zodOrRouteOrFunction as Schema, function_));
|
|
71
|
-
}
|
|
72
|
-
} else if (typeof zodOrRouteOrFunction === "function") {
|
|
73
|
-
// eslint-disable-next-line no-param-reassign
|
|
74
|
-
fns = [zodOrRouteOrFunction];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this.router.add(method, routeOrFunction, ...fns);
|
|
78
|
-
|
|
79
|
-
return this;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
public all: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "");
|
|
83
|
-
|
|
84
|
-
public get: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "GET");
|
|
85
|
-
|
|
86
|
-
public head: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "HEAD");
|
|
87
|
-
|
|
88
|
-
public post: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "POST");
|
|
89
|
-
|
|
90
|
-
public put: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "PUT");
|
|
91
|
-
|
|
92
|
-
public patch: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "PATCH");
|
|
93
|
-
|
|
94
|
-
public delete: RouteShortcutMethod<this, Schema, RequestHandler<R, Context>> = this.add.bind(this, "DELETE");
|
|
95
|
-
|
|
96
|
-
public use(
|
|
97
|
-
base: RouteMatch | Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>,
|
|
98
|
-
...fns: (Nextable<RequestHandler<R, Context>> | EdgeRouter<R, Context>)[]
|
|
99
|
-
) {
|
|
100
|
-
if (typeof base === "function" || base instanceof EdgeRouter) {
|
|
101
|
-
fns.unshift(base);
|
|
102
|
-
// eslint-disable-next-line no-param-reassign
|
|
103
|
-
base = "/";
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
this.router.use(base, ...fns.map((function_) => (function_ instanceof EdgeRouter ? function_.router : function_)));
|
|
107
|
-
|
|
108
|
-
return this;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// eslint-disable-next-line class-methods-use-this
|
|
112
|
-
private prepareRequest(request: R & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<R, Context>>) {
|
|
113
|
-
request.params = {
|
|
114
|
-
...findResult.params,
|
|
115
|
-
...request.params, // original params will take precedence
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
public clone() {
|
|
120
|
-
const r = new EdgeRouter<R, Context, RResponse, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });
|
|
121
|
-
|
|
122
|
-
r.router = this.router.clone();
|
|
123
|
-
|
|
124
|
-
return r;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async run(request: R, context_: Context) {
|
|
128
|
-
// eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument
|
|
129
|
-
const result = this.router.find(request.method as HttpMethod, getPathname(request));
|
|
130
|
-
|
|
131
|
-
if (result.fns.length === 0) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
this.prepareRequest(request, result);
|
|
136
|
-
|
|
137
|
-
// eslint-disable-next-line consistent-return
|
|
138
|
-
return Router.exec(result.fns, request, context_);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
handler() {
|
|
142
|
-
const { routes } = this.router as Router<FunctionLike>;
|
|
143
|
-
|
|
144
|
-
return async (request: R, context_: Context): Promise<any> => {
|
|
145
|
-
// eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument
|
|
146
|
-
const result = this.router.find(request.method as HttpMethod, getPathname(request));
|
|
147
|
-
|
|
148
|
-
this.prepareRequest(request, result);
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
return await (result.fns.length === 0 || result.middleOnly
|
|
152
|
-
? this.onNoMatch(request, context_, routes)
|
|
153
|
-
: Router.exec(result.fns, request, context_));
|
|
154
|
-
} catch (error) {
|
|
155
|
-
return this.onError(error, request, context_, routes);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function createEdgeRouter<R extends Request, Context>(
|
|
162
|
-
options: HandlerOptions<RoutesExtendedRequestHandler<R, Context, Response, Route<Nextable<FunctionLike>>[]>> = {},
|
|
163
|
-
) {
|
|
164
|
-
return new EdgeRouter<R, Context, Response>(options);
|
|
165
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export type { RequestHandler as EdgeRequestHandler } from "./edge";
|
|
2
|
-
export { createEdgeRouter, EdgeRouter } from "./edge";
|
|
3
|
-
|
|
4
|
-
export type { ExpressRequestHandler } from "./adapter/express";
|
|
5
|
-
export { default as expressWrapper } from "./adapter/express";
|
|
6
|
-
|
|
7
|
-
export type { RequestHandler as NodeRequestHandler } from "./node";
|
|
8
|
-
export { createRouter as createNodeRouter, NodeRouter } from "./node";
|
|
9
|
-
|
|
10
|
-
// @deprecated Use `createNodeRouter` instead
|
|
11
|
-
export { createRouter } from "./node";
|
|
12
|
-
|
|
13
|
-
export type { Route } from "./router";
|
|
14
|
-
export { Router } from "./router";
|
|
15
|
-
|
|
16
|
-
export { default as withZod } from "./adapter/with-zod";
|
|
17
|
-
|
|
18
|
-
export type {
|
|
19
|
-
HandlerOptions, NextHandler, FunctionLike, Nextable, ValueOrPromise, FindResult, RouteShortcutMethod, HttpMethod,
|
|
20
|
-
} from "./types";
|
|
21
|
-
|
|
22
|
-
export { default as sendJson } from "./utils/send-json";
|
package/src/node.ts
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import type { AnyZodObject } from "zod";
|
|
3
|
-
import { ZodObject } from "zod";
|
|
4
|
-
|
|
5
|
-
import withZod from "./adapter/with-zod";
|
|
6
|
-
import type { Route } from "./router";
|
|
7
|
-
import { Router } from "./router";
|
|
8
|
-
import type {
|
|
9
|
-
FindResult,
|
|
10
|
-
FunctionLike,
|
|
11
|
-
HandlerOptions,
|
|
12
|
-
HttpMethod,
|
|
13
|
-
Nextable,
|
|
14
|
-
RouteMatch,
|
|
15
|
-
RoutesExtendedRequestHandler,
|
|
16
|
-
RouteShortcutMethod,
|
|
17
|
-
ValueOrPromise,
|
|
18
|
-
} from "./types";
|
|
19
|
-
|
|
20
|
-
const onNoMatch = async (request: IncomingMessage, response: ServerResponse) => {
|
|
21
|
-
response.statusCode = 404;
|
|
22
|
-
response.end(request.method !== "HEAD" ? `Route ${request.method} ${request.url} not found` : undefined);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const onError = async (error: unknown, _request: IncomingMessage, response: ServerResponse) => {
|
|
26
|
-
response.statusCode = 500;
|
|
27
|
-
// eslint-disable-next-line no-console
|
|
28
|
-
console.error(error);
|
|
29
|
-
|
|
30
|
-
response.end("Internal Server Error");
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function getPathname(url: string) {
|
|
34
|
-
const queryIndex = url.indexOf("?");
|
|
35
|
-
|
|
36
|
-
return queryIndex !== -1 ? url.slice(0, Math.max(0, queryIndex)) : url;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type RequestHandler<Request extends IncomingMessage, Response extends ServerResponse> = (request: Request, response: Response) => ValueOrPromise<void>;
|
|
40
|
-
|
|
41
|
-
export class NodeRouter<
|
|
42
|
-
Request extends IncomingMessage = IncomingMessage,
|
|
43
|
-
Response extends ServerResponse = ServerResponse,
|
|
44
|
-
Schema extends AnyZodObject = ZodObject<any>,
|
|
45
|
-
> {
|
|
46
|
-
private router = new Router<RequestHandler<Request, Response>>();
|
|
47
|
-
|
|
48
|
-
private readonly onNoMatch: RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>;
|
|
49
|
-
|
|
50
|
-
private readonly onError: (
|
|
51
|
-
error: unknown,
|
|
52
|
-
...arguments_: Parameters<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>
|
|
53
|
-
) => ReturnType<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>>;
|
|
54
|
-
|
|
55
|
-
constructor(options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {}) {
|
|
56
|
-
this.onNoMatch = options.onNoMatch || onNoMatch;
|
|
57
|
-
this.onError = options.onError || onError;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private add(
|
|
61
|
-
method: HttpMethod | "",
|
|
62
|
-
routeOrFunction: RouteMatch | Nextable<RequestHandler<Request, Response>>,
|
|
63
|
-
zodOrRouteOrFunction?: RouteMatch | Schema | Nextable<RequestHandler<Request, Response>>,
|
|
64
|
-
...fns: Nextable<RequestHandler<Request, Response>>[]
|
|
65
|
-
) {
|
|
66
|
-
if (typeof routeOrFunction === "string" && typeof zodOrRouteOrFunction === "function") {
|
|
67
|
-
// eslint-disable-next-line no-param-reassign
|
|
68
|
-
fns = [zodOrRouteOrFunction];
|
|
69
|
-
} else if (typeof zodOrRouteOrFunction === "object") {
|
|
70
|
-
// eslint-disable-next-line unicorn/prefer-ternary
|
|
71
|
-
if (typeof routeOrFunction === "function") {
|
|
72
|
-
// eslint-disable-next-line no-param-reassign
|
|
73
|
-
fns = [withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(
|
|
74
|
-
zodOrRouteOrFunction as Schema,
|
|
75
|
-
routeOrFunction,
|
|
76
|
-
)];
|
|
77
|
-
} else {
|
|
78
|
-
// eslint-disable-next-line no-param-reassign,max-len
|
|
79
|
-
fns = fns.map((function_) => withZod<Request, Response, Nextable<RequestHandler<Request, Response>>, Schema>(zodOrRouteOrFunction as Schema, function_));
|
|
80
|
-
}
|
|
81
|
-
} else if (typeof zodOrRouteOrFunction === "function") {
|
|
82
|
-
// eslint-disable-next-line no-param-reassign
|
|
83
|
-
fns = [zodOrRouteOrFunction];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.router.add(method, routeOrFunction, ...fns);
|
|
87
|
-
|
|
88
|
-
return this;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public all: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "");
|
|
92
|
-
|
|
93
|
-
public get: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "GET");
|
|
94
|
-
|
|
95
|
-
public head: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "HEAD");
|
|
96
|
-
|
|
97
|
-
public post: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "POST");
|
|
98
|
-
|
|
99
|
-
public put: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "PUT");
|
|
100
|
-
|
|
101
|
-
public patch: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "PATCH");
|
|
102
|
-
|
|
103
|
-
public delete: RouteShortcutMethod<this, Schema, RequestHandler<Request, Response>> = this.add.bind(this, "DELETE");
|
|
104
|
-
|
|
105
|
-
public use(
|
|
106
|
-
base: RouteMatch | Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>,
|
|
107
|
-
...fns: (Nextable<RequestHandler<Request, Response>> | NodeRouter<Request, Response, Schema>)[]
|
|
108
|
-
) {
|
|
109
|
-
if (typeof base === "function" || base instanceof NodeRouter) {
|
|
110
|
-
fns.unshift(base);
|
|
111
|
-
// eslint-disable-next-line no-param-reassign
|
|
112
|
-
base = "/";
|
|
113
|
-
}
|
|
114
|
-
this.router.use(base, ...fns.map((function_) => (function_ instanceof NodeRouter ? function_.router : function_)));
|
|
115
|
-
|
|
116
|
-
return this;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// eslint-disable-next-line class-methods-use-this
|
|
120
|
-
private prepareRequest(request: Request & { params?: Record<string, unknown> }, findResult: FindResult<RequestHandler<Request, Response>>) {
|
|
121
|
-
request.params = {
|
|
122
|
-
...findResult.params,
|
|
123
|
-
...request.params, // original params will take precedence
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
public clone() {
|
|
128
|
-
const r = new NodeRouter<Request, Response, Schema>({ onNoMatch: this.onNoMatch, onError: this.onError });
|
|
129
|
-
|
|
130
|
-
r.router = this.router.clone();
|
|
131
|
-
|
|
132
|
-
return r;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async run(request: Request, response: Response): Promise<unknown> {
|
|
136
|
-
// eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument
|
|
137
|
-
const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));
|
|
138
|
-
|
|
139
|
-
if (result.fns.length === 0) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
this.prepareRequest(request, result);
|
|
144
|
-
|
|
145
|
-
// eslint-disable-next-line consistent-return
|
|
146
|
-
return Router.exec(result.fns, request, response);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
handler() {
|
|
150
|
-
const { routes } = this.router as Router<FunctionLike>;
|
|
151
|
-
|
|
152
|
-
return async (request: Request, response: Response) => {
|
|
153
|
-
// eslint-disable-next-line unicorn/no-array-callback-reference,unicorn/no-array-method-this-argument
|
|
154
|
-
const result = this.router.find(request.method as HttpMethod, getPathname(request.url as string));
|
|
155
|
-
|
|
156
|
-
this.prepareRequest(request, result);
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
await (result.fns.length === 0 || result.middleOnly ? this.onNoMatch(request, response, routes) : Router.exec(result.fns, request, response));
|
|
160
|
-
} catch (error) {
|
|
161
|
-
await this.onError(error, request, response, routes);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export const createRouter = <
|
|
168
|
-
Request extends IncomingMessage,
|
|
169
|
-
Response extends ServerResponse,
|
|
170
|
-
Schema extends AnyZodObject = ZodObject<{ body?: AnyZodObject; headers?: AnyZodObject; query?: AnyZodObject }>,
|
|
171
|
-
>(
|
|
172
|
-
options: HandlerOptions<RoutesExtendedRequestHandler<Request, Response, Response, Route<Nextable<FunctionLike>>[]>> = {},
|
|
173
|
-
) => new NodeRouter<Request, Response, Schema>(options);
|
package/src/regexparam.d.ts
DELETED
package/src/router.ts
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agnostic router class
|
|
3
|
-
* Adapted from lukeed/trouter library:
|
|
4
|
-
* https://github.com/lukeed/trouter/blob/master/index.mjs
|
|
5
|
-
*/
|
|
6
|
-
import { parse } from "regexparam";
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
FindResult, FunctionLike, HttpMethod, Nextable, RouteMatch,
|
|
10
|
-
} from "./types";
|
|
11
|
-
|
|
12
|
-
export type Route<H> = {
|
|
13
|
-
method: HttpMethod | "";
|
|
14
|
-
fns: (H | Router<H extends FunctionLike ? H : never>)[];
|
|
15
|
-
isMiddleware: boolean;
|
|
16
|
-
} & (
|
|
17
|
-
| {
|
|
18
|
-
keys: string[] | false;
|
|
19
|
-
pattern: RegExp;
|
|
20
|
-
}
|
|
21
|
-
| { matchAll: true }
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
export class Router<H extends FunctionLike> {
|
|
25
|
-
constructor(public base: string = "/", public routes: Route<Nextable<H>>[] = []) {}
|
|
26
|
-
|
|
27
|
-
public add(method: HttpMethod | "", route: RouteMatch | Nextable<H>, ...fns: Nextable<H>[]): this {
|
|
28
|
-
if (typeof route === "function") {
|
|
29
|
-
fns.unshift(route);
|
|
30
|
-
// eslint-disable-next-line no-param-reassign
|
|
31
|
-
route = "";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (route === "") {
|
|
35
|
-
this.routes.push({
|
|
36
|
-
matchAll: true,
|
|
37
|
-
method,
|
|
38
|
-
fns,
|
|
39
|
-
isMiddleware: false,
|
|
40
|
-
});
|
|
41
|
-
} else {
|
|
42
|
-
const { keys, pattern } = parse(route);
|
|
43
|
-
|
|
44
|
-
this.routes.push({
|
|
45
|
-
keys,
|
|
46
|
-
pattern,
|
|
47
|
-
method,
|
|
48
|
-
fns,
|
|
49
|
-
isMiddleware: false,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return this;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public use(base: RouteMatch | Nextable<H> | Router<H>, ...fns: (Nextable<H> | Router<H>)[]) {
|
|
57
|
-
if (typeof base === "function" || base instanceof Router) {
|
|
58
|
-
fns.unshift(base);
|
|
59
|
-
// eslint-disable-next-line no-param-reassign
|
|
60
|
-
base = "/";
|
|
61
|
-
}
|
|
62
|
-
// mount subrouter
|
|
63
|
-
// eslint-disable-next-line no-param-reassign
|
|
64
|
-
fns = fns.map((function_) => {
|
|
65
|
-
if (function_ instanceof Router) {
|
|
66
|
-
if (typeof base === "string") return function_.clone(base);
|
|
67
|
-
throw new Error("Mounting a router to RegExp base is not supported");
|
|
68
|
-
}
|
|
69
|
-
return function_;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const { keys, pattern } = parse(base, true);
|
|
73
|
-
|
|
74
|
-
this.routes.push({
|
|
75
|
-
keys,
|
|
76
|
-
pattern,
|
|
77
|
-
method: "",
|
|
78
|
-
fns,
|
|
79
|
-
isMiddleware: true,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public clone(base?: string) {
|
|
86
|
-
return new Router<H>(base, [...this.routes]);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
static async exec<H extends FunctionLike>(fns: Nextable<H>[], ...arguments_: Parameters<H>): Promise<unknown> {
|
|
90
|
-
let index = 0;
|
|
91
|
-
|
|
92
|
-
// eslint-disable-next-line no-plusplus
|
|
93
|
-
const next = () => (fns[++index] as FunctionLike)(...arguments_, next);
|
|
94
|
-
|
|
95
|
-
return (fns[index] as FunctionLike)(...arguments_, next);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// eslint-disable-next-line radar/cognitive-complexity
|
|
99
|
-
find(method: HttpMethod, pathname: string): FindResult<H> {
|
|
100
|
-
let middleOnly = true;
|
|
101
|
-
|
|
102
|
-
const fns: Nextable<H>[] = [];
|
|
103
|
-
const parameters: Record<string, string> = {};
|
|
104
|
-
const isHead = method === "HEAD";
|
|
105
|
-
|
|
106
|
-
// eslint-disable-next-line radar/cognitive-complexity
|
|
107
|
-
Object.values(this.routes).forEach((route) => {
|
|
108
|
-
if (
|
|
109
|
-
route.method !== method
|
|
110
|
-
// matches any method
|
|
111
|
-
&& route.method !== ""
|
|
112
|
-
// The HEAD method requests that the target resource transfer a representation of its state, as for a GET request...
|
|
113
|
-
&& !(isHead && route.method === "GET")
|
|
114
|
-
) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let matched = false;
|
|
119
|
-
|
|
120
|
-
if ("matchAll" in route) {
|
|
121
|
-
matched = true;
|
|
122
|
-
} else if (route.keys === false) {
|
|
123
|
-
// routes.key is RegExp: https://github.com/lukeed/regexparam/blob/master/src/index.js#L2
|
|
124
|
-
const matches = route.pattern.exec(pathname);
|
|
125
|
-
|
|
126
|
-
if (matches === null) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// eslint-disable-next-line no-void
|
|
131
|
-
if (matches.groups !== void 0) {
|
|
132
|
-
Object.keys(matches.groups).forEach((key) => {
|
|
133
|
-
// @ts-ignore @TODO: fix this
|
|
134
|
-
parameters[key] = matches.groups[key] as string;
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
matched = true;
|
|
139
|
-
} else if (route.keys.length > 0) {
|
|
140
|
-
const matches = route.pattern.exec(pathname);
|
|
141
|
-
|
|
142
|
-
if (matches === null) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
for (let index = 0; index < route.keys.length;) {
|
|
147
|
-
const parameterKey = route.keys[index];
|
|
148
|
-
|
|
149
|
-
// @ts-ignore @TODO: fix this
|
|
150
|
-
// eslint-disable-next-line no-plusplus
|
|
151
|
-
parameters[parameterKey] = matches[++index];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
matched = true;
|
|
155
|
-
} else if (route.pattern.test(pathname)) {
|
|
156
|
-
matched = true;
|
|
157
|
-
} // else not a match
|
|
158
|
-
|
|
159
|
-
if (matched) {
|
|
160
|
-
fns.push(
|
|
161
|
-
...route.fns.flatMap((function_) => {
|
|
162
|
-
if (function_ instanceof Router) {
|
|
163
|
-
const base = function_.base as string;
|
|
164
|
-
|
|
165
|
-
let stripPathname = pathname.slice(base.length);
|
|
166
|
-
|
|
167
|
-
// fix stripped pathname, not sure why this happens
|
|
168
|
-
// eslint-disable-next-line eqeqeq
|
|
169
|
-
if (stripPathname[0] != "/") {
|
|
170
|
-
stripPathname = `/${stripPathname}`;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument
|
|
174
|
-
const result = function_.find(method, stripPathname);
|
|
175
|
-
|
|
176
|
-
if (!result.middleOnly) {
|
|
177
|
-
middleOnly = false;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// merge params
|
|
181
|
-
Object.assign(parameters, result.params);
|
|
182
|
-
|
|
183
|
-
return result.fns;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return function_;
|
|
187
|
-
}),
|
|
188
|
-
);
|
|
189
|
-
if (!route.isMiddleware) middleOnly = false;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
return { fns, params: parameters, middleOnly };
|
|
194
|
-
}
|
|
195
|
-
}
|
package/src/types.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { AnyZodObject } from "zod";
|
|
2
|
-
|
|
3
|
-
export type HttpMethod = "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
4
|
-
|
|
5
|
-
export type FunctionLike = (...arguments_: any[]) => unknown;
|
|
6
|
-
|
|
7
|
-
export type RouteMatch = string | RegExp;
|
|
8
|
-
|
|
9
|
-
export type NextHandler = () => ValueOrPromise<any>;
|
|
10
|
-
|
|
11
|
-
export type Nextable<H extends FunctionLike> = (...arguments_: [...Parameters<H>, NextHandler]) => ValueOrPromise<any>;
|
|
12
|
-
|
|
13
|
-
export type FindResult<H extends FunctionLike> = {
|
|
14
|
-
fns: Nextable<H>[];
|
|
15
|
-
params: Record<string, string>;
|
|
16
|
-
middleOnly: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type RoutesExtendedRequestHandler<Request extends object, Context extends unknown, RResponse extends unknown, Routes> = (
|
|
20
|
-
request: Request,
|
|
21
|
-
response: Context,
|
|
22
|
-
routes: Routes,
|
|
23
|
-
) => ValueOrPromise<RResponse | void>;
|
|
24
|
-
|
|
25
|
-
export interface HandlerOptions<Handler extends FunctionLike> {
|
|
26
|
-
onNoMatch?: Handler;
|
|
27
|
-
onError?: (error: unknown, ...arguments_: Parameters<Handler>) => ReturnType<Handler>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type ValueOrPromise<T> = T | Promise<T>;
|
|
31
|
-
|
|
32
|
-
export type RouteShortcutMethod<This, Schema extends AnyZodObject, H extends FunctionLike> = (
|
|
33
|
-
route: RouteMatch | Nextable<H>,
|
|
34
|
-
zodSchemaOrRouteOrFns?: Schema | RouteMatch | Nextable<H> | string,
|
|
35
|
-
...fns: Nextable<H>[]
|
|
36
|
-
) => This;
|
package/src/utils/send-json.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ServerResponse } from "node:http";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Send `JSON` object
|
|
5
|
-
* @param {ServerResponse} response response object
|
|
6
|
-
* @param {number} statusCode
|
|
7
|
-
* @param {any} jsonBody of data
|
|
8
|
-
*/
|
|
9
|
-
const sendJson = (response: ServerResponse, statusCode: number, jsonBody: any): void => {
|
|
10
|
-
// Set header to application/json
|
|
11
|
-
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
12
|
-
|
|
13
|
-
response.statusCode = statusCode;
|
|
14
|
-
response.end(JSON.stringify(jsonBody, null, 2));
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default sendJson;
|