import type { LocaleType, RouteMatch, Router, RouterBuilder, } from "router-segments"; import { createRouterBuilder } from "router-segments"; import type { AlpNodeApp, Context } from "./AlpNodeApp"; export type AlpRouter = Router< Locales, AlpRouteRef >; export type AlpRouteRef = (ctx: Context) => Promise | void; type ReturnType = (app: AlpNodeApp) => AlpRouteRef; export interface RouterContext { route: RouteMatch; } export const createAlpRouterBuilder = < Locales extends LocaleType, >(): RouterBuilder => createRouterBuilder(); export type UrlGenerator =

| undefined>( routeKey: string, params?: P, ) => string; export default function alpRouter( router: Router, ): ReturnType { return (app: AlpNodeApp) => { app.router = router; app.context.urlGenerator = function urlGenerator< P extends Record | undefined, >(this: Context, routeKey: string, params?: P): string { return router.toLocalizedPath(this.language as Locales, routeKey, params); }; app.context.redirectTo = function redirectTo< P extends Record | undefined, >(this: Context, to: string, params?: P): void { this.redirect( router.toLocalizedPath(this.language as Locales, to, params), ); }; return async (ctx: Context): Promise => { // eslint-disable-next-line unicorn/no-array-method-this-argument const routeMatch = router.find(ctx.request.path, ctx.language as Locales); if (!routeMatch) { ctx.status = 404; throw new Error(`Route not found: ${ctx.request.path}`); } ctx.route = routeMatch; await routeMatch.ref(ctx); }; }; }