From 5c8a1de7692597a6724e8f6a579b4904570b5954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Charles?= Date: Tue, 17 Dec 2024 19:06:54 +0100 Subject: [PATCH] chore --- packages/router/src/index.ts | 83 ++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts index 8d94c1c0..966134ae 100644 --- a/packages/router/src/index.ts +++ b/packages/router/src/index.ts @@ -1,20 +1,67 @@ -import type { UniversalHandler, UniversalMiddleware } from "@universal-middleware/core"; +import type { AnyFn, UniversalHandler, UniversalMiddleware } from "@universal-middleware/core"; import { pipe, universalSymbol } from "@universal-middleware/core"; import { createHandler, createMiddleware } from "@universal-middleware/hono"; import type { Hono } from "hono"; import { type RouterContext, addRoute, createRouter, findRoute } from "rou3"; -export interface RouteDefinition { - method: "get"; - path: string; - handler: UniversalHandler; +export const pathSymbol = Symbol.for("unPath"); +export const methodSymbol = Symbol.for("unMethod"); +export const orderSymbol = Symbol.for("unOrder"); + +export enum MiddlewareOrder { + // Pre-handler Middlewares + GUARD = -1000, // Guard middleware: Ensures specific conditions or headers are met before proceeding. + AUTHENTICATION = -900, // Authentication middleware: Verifies user credentials or tokens. + AUTHORIZATION = -800, // Authorization middleware: Ensures the user has permissions for the route. + RATE_LIMITING = -700, // Rate limiting middleware: Prevents excessive requests from a client. + INPUT_VALIDATION = -600, // Input validation middleware: Validates the request payload or query parameters. + CORS = -500, // CORS middleware: Handles Cross-Origin Resource Sharing settings. + PARSING = -400, // Parsing middleware: Parses body payloads (e.g., JSON, URL-encoded, multipart). + CUSTOM_PRE_PROCESSING = -300, // Custom pre-processing middleware: Any custom logic before the main handler. + + // Main Handler + HANDLER = 0, // Main handler that generates the response. + + // Post-handler Middlewares + RESPONSE_TRANSFORM = 100, // Response transformation middleware: Modifies the response payload. + HEADER_MANAGEMENT = 200, // Header management middleware: Adds or modifies HTTP headers (e.g., caching, content type). + RESPONSE_COMPRESSION = 300, // Response compression middleware: Compresses the response payload (e.g., gzip, brotli). + RESPONSE_CACHING = 400, // Response caching middleware: Implements caching strategies (e.g., ETag, cache-control). + LOGGING = 500, // Logging middleware: Logs request and response information. + ERROR_HANDLING = 600, // Error handling middleware: Processes errors and returns user-friendly responses. + CUSTOM_POST_PROCESSING = 700, // Custom post-processing middleware: Any custom logic after the response is generated. } -export type MiddlewareDefinition = [middleware: UniversalMiddleware, order: number]; +export type HttpMethod = "GET"; +export type RouteDefinition = UniversalHandler & { [methodSymbol]: HttpMethod; [pathSymbol]: string }; +export type MiddlewareDefinition = UniversalMiddleware & { [orderSymbol]: MiddlewareOrder | number }; export interface UniversalRouterInterface { - use(middleware: UniversalMiddleware, order?: number): this; - route(method: RouteDefinition["method"], path: string, handler: UniversalHandler): this; + use(middleware: MiddlewareDefinition): this; + route(handler: RouteDefinition): this; +} + +function cloneFunction(originalFn: F): F { + // Create a clone of the function + const clonedFn = originalFn.bind(null) as F; + + // Copy over all properties from the original function to the clone + Object.defineProperties(clonedFn, Object.getOwnPropertyDescriptors(originalFn)); + + return clonedFn; +} + +export function withOrder(middleware: UniversalMiddleware, order: MiddlewareOrder | number): MiddlewareDefinition { + const m = cloneFunction(middleware) as MiddlewareDefinition; + m[orderSymbol] = order; + return m; +} + +export function withRoute(handler: UniversalHandler, method: HttpMethod, path: string): RouteDefinition { + const h = cloneFunction(handler) as RouteDefinition; + h[methodSymbol] = method; + h[pathSymbol] = path; + return h; } export class UniversalRouter implements UniversalRouterInterface { @@ -29,13 +76,12 @@ export class UniversalRouter implements UniversalRouterInterface { use(middleware: UniversalMiddleware, order?: number) { this.#computedMiddleware = undefined; - this.#middlewares.push([middleware, order ?? 0]); + this.#middlewares.push(withOrder(middleware, order ?? 0)); return this; } - // TODO https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods - route(method: RouteDefinition["method"], path: string, handler: UniversalHandler) { - addRoute(this.router, method.toLocaleUpperCase() as Uppercase, path, handler); + route(handler: RouteDefinition) { + addRoute(this.router, handler[methodSymbol], handler[pathSymbol], handler); return this; } @@ -82,8 +128,11 @@ export class UniversalHonoRouter implements UniversalRouterInterface { return this; } - route(method: RouteDefinition["method"], path: string, handler: UniversalHandler) { - this.#app[method](path, createHandler(() => handler)()); + route(handler: RouteDefinition) { + this.#app[handler[methodSymbol].toLocaleLowerCase() as Lowercase]( + handler[pathSymbol], + createHandler(() => handler)(), + ); return this; } } @@ -101,15 +150,15 @@ export function apply( } if (routes) { for (const r of routes) { - router.route(r.method, r.path, r.handler); + router.route(r); } } } function ordered(middlewares: MiddlewareDefinition[]) { return Array.from(middlewares) - .sort((a, b) => a[1] - b[1]) - .map((x) => x[0]); + .sort((a, b) => a[orderSymbol] - b[orderSymbol]) + .map((x) => x); } // middlewares