UNPKG

@stacksjs/router

Version:
73 lines (72 loc) 3.13 kB
import { log } from "@stacksjs/logging"; import { route } from "./stacks-router"; const NO_PREFIX_KEYS = ["web"]; export async function loadRoutes(registry) { for (const [key, definition] of Object.entries(registry)) { const config = normalizeDefinition(definition), prefix = config.prefix !== void 0 ? config.prefix ? config.prefix.startsWith("/") ? config.prefix : `/${config.prefix}` : void 0 : NO_PREFIX_KEYS.includes(key) ? void 0 : `/${key}`, middleware = normalizeMiddleware(config.middleware); log.debug(`[route-loader] Loading: ${config.path} prefix=${prefix || "/"} middleware=[${middleware.join(", ")}]`); try { if (prefix || middleware.length > 0) await route.group({ prefix, middleware: middleware.length > 0 ? middleware : void 0 }, async () => { await importRouteFile(config.path); }); else await importRouteFile(config.path); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.error(`[Routes] Failed to load route file '${config.path}': ${message}`); throw Error(`Route loading failed for '${config.path}': ${message}`); } } await loadFrameworkRoutes(); } async function loadFrameworkRoutes() { if (process.env.STACKS_SKIP_DEFAULT_ROUTES === "1") return; try { const { frameworkPath } = await import("@stacksjs/path"), bootstrapPath = frameworkPath("defaults/bootstrap.ts"); if (await Bun.file(bootstrapPath).exists()) await import(bootstrapPath); } catch (error) { const message = error instanceof Error ? error.message : String(error); if (!message.includes("Cannot find module") && !message.includes("MODULE_NOT_FOUND")) console.error(`[Routes] Failed to load framework bootstrap: ${message}`); } } function assertSafeRouteName(routeName) { if (typeof routeName !== "string" || routeName.length === 0) throw Error("[route-loader] Invalid route path: empty or non-string"); if (routeName.includes("\x00")) throw Error("[route-loader] Invalid route path: null byte"); let decoded; try { decoded = decodeURIComponent(routeName); } catch { throw Error("[route-loader] Invalid route path: malformed URL encoding"); } const cleanPath = decoded.replace(/\.ts$/, ""); if (cleanPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(cleanPath)) throw Error(`[route-loader] Invalid route path: absolute paths not allowed (${cleanPath})`); if (cleanPath.split(/[/\\]/).some((s) => s === "..")) throw Error(`[route-loader] Invalid route path: '..' segment not allowed (${cleanPath})`); return cleanPath; } async function importRouteFile(routeName) { const cleanPath = assertSafeRouteName(routeName), { projectPath } = await import("@stacksjs/path"); await import(projectPath(`routes/${cleanPath}`)); } function normalizeDefinition(def) { if (typeof def === "string") return { path: def }; return def; } function normalizeMiddleware(middleware) { if (!middleware) return []; if (typeof middleware === "string") return [middleware]; return middleware; }