examples/storefront Public
// A small method and path router. Patterns use :name for one segment and a final * for the// rest of the path, which arrives as params.rest.export type Params = Record<string, string>;export type Handler = (req: Request, params: Params) => Promise<Response> | Response;type Route = { method: string; re: RegExp; keys: string[]; handler: Handler };export type Match = { handler: Handler; params: Params } | "method_not_allowed" | null;export class Router { private readonly routes: Route[] = []; on(method: string, pattern: string, handler: Handler): this { const keys: string[] = []; const source = pattern .split("/") .map((seg) => { if (seg === "*") { keys.push("rest"); return "(.+)"; } if (seg.startsWith(":")) { keys.push(seg.slice(1)); return "([^/]+)"; } return seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }) .join("/"); this.routes.push({ method, re: new RegExp(`^${source}$`), keys, handler }); return this; } // Throws URIError when a segment is not valid percent-encoding. match(method: string, path: string): Match { let pathMatched = false; for (const r of this.routes) { const m = r.re.exec(path); if (!m) continue; pathMatched = true; if (r.method !== method && !(method === "HEAD" && r.method === "GET")) continue; const params: Params = {}; r.keys.forEach((k, i) => { params[k] = decodeURIComponent(m[i + 1]!); }); return { handler: r.handler, params }; } return pathMatched ? "method_not_allowed" : null; }}