Skip to main content
Home

latest
It is unknown whether this package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
It is unknown whether this package works with Node.js
It is unknown whether this package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
35%
Published
2 months ago (0.1.12)
import { type Route as StdRoute, route } from "jsr:/@std/http@^1.0.20/unstable-route"; export interface Route<TState = unknown> extends Omit<StdRoute, "handler"> { handler: HandleRequest<TState>; } export interface Context<TState = unknown> { request: Request; params: URLPatternResult | undefined; next: () => Promise<Response>; url: URL; info: Deno.ServeHandlerInfo | undefined; state: TState; } export type HandleRequest<TState = unknown> = ( context: Context<TState>, ) => Response | Promise<Response>; export type HandleDefault = () => Response | Promise<Response>; export type HandleError = (error: Error) => Response | Promise<Response>; // Router interface that defines the shape of the router object export interface Router<TState = unknown> { routes: Route<TState>[]; initializeState: () => TState; handleDefault: HandleDefault; handleError: HandleError; fetch: ( request: Request, info?: Deno.ServeHandlerInfo, state?: TState, ) => Promise<Response>; state: (defaultState: () => TState) => Router<TState>; with: (route: Route<TState>) => Router<TState>; on: ( method: string | string[] | undefined, pathname: string, handler: HandleRequest<TState>, ) => Router<TState>; use: (data: Route<TState>[] | Router<TState>) => Router<TState>; default: (handle: HandleDefault) => Router<TState>; error: (handle: HandleError) => Router<TState>; connect: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; delete: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; get: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; head: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; options: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; patch: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; post: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; put: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; trace: (pathname: string, handler: HandleRequest<TState>) => Router<TState>; } // Default handlers const defaultNotFoundHandler = (): Response => new Response("Not found", { status: 404 }); const defaultErrorHandler = (error: Error): Response => new Response(error.message, { status: 500 }); // Create router function with explicit return type export const createRouter = <TState = unknown>(): Router<TState> => { // Execute function (implementation detail) const execute = ( router: Router<TState>, i: number, request: Request, info: Deno.ServeHandlerInfo | undefined, state: TState, ): Response | Promise<Response> => { if (i >= router.routes.length) { return router.handleDefault(); } const next = async () => await execute(router, i + 1, request, info, state); const { method, pattern, handler } = router.routes[i]; const handle = route( [ { method, pattern, handler: (request, params, info) => { const url = new URL(request.url); return handler({ request, params, url, info, next, state }); }, }, ], () => next(), ); return handle(request, info); }; // Create the router object const router: Router<TState> = { routes: [], initializeState: () => ({}) as TState, handleDefault: defaultNotFoundHandler, handleError: defaultErrorHandler, fetch: async (request, info, state) => { try { return await execute( router, 0, request, info, state ?? router.initializeState(), ); } catch (error) { if (error instanceof Error) { return await router.handleError(error); } throw error; } }, state: (defaultState) => { router.initializeState = defaultState; return router; }, with: (routeToAdd) => { router.routes.push(routeToAdd); return router; }, on: (method, pathname, handler) => { const pattern = new URLPattern({ pathname }); return router.with({ method, pattern, handler }); }, use: (data) => { if (Array.isArray(data)) { router.routes.push(...data); } else { router.routes.push(...data.routes); } return router; }, default: (handle) => { router.handleDefault = handle; return router; }, error: (handle) => { router.handleError = handle; return router; }, connect: (pathname, handler) => router.on("CONNECT", pathname, handler), delete: (pathname, handler) => router.on("DELETE", pathname, handler), get: (pathname, handler) => router.on("GET", pathname, handler), head: (pathname, handler) => router.on("HEAD", pathname, handler), options: (pathname, handler) => router.on("OPTIONS", pathname, handler), patch: (pathname, handler) => router.on("PATCH", pathname, handler), post: (pathname, handler) => router.on("POST", pathname, handler), put: (pathname, handler) => router.on("PUT", pathname, handler), trace: (pathname, handler) => router.on("TRACE", pathname, handler), }; return router satisfies Deno.ServeDefaultExport; };