1import type { Context, Hono } from "hono";2import { isSafePath, isVersion } from "../bucket/repo.ts";3import { publicRepo } from "../server/db.ts";4import { notFound, type PageContext, pathUrl } from "./layout.ts";567const PANELS = new Map([8 ["issues", "/issues"],9 ["builds", "/releases"],10 ["archives", "/archives"],11 ["trust", ""],12]);1314const GONE = [15 "/tickets/*",16 "/drafts/*",17 "/join",18 "/cli-auth",19 "/api/cli-auth/*",20 "/api/repos/*",21 "/api/releases/upload",22 "/protocol/*",23 "/feed",24 "/:repo/feed",25];2627const RELEASE_ROUTES = new Set(["latest", "latest.json", "history.json"]);282930export function registerKepr2Routes(app: Hono, ctx: PageContext): void {31 32 const moved = (c: Context, rest: string) => {33 const repo = c.req.param("repo") ?? "";34 if (!publicRepo(ctx.kepr, repo)) return notFound(c, ctx);35 return c.redirect(`/${encodeURIComponent(repo)}${rest}`, 301);36 };37 for (const path of GONE) app.all(path, (c) => c.text("Gone", 410));38 app.get("/source", (c) => c.redirect("/kepr", 301));39 app.get("/:repo", async (c, next) => {40 const panel = PANELS.get(c.req.query("panel") ?? "");41 if (panel === undefined) return next();42 return moved(c, panel);43 });44 app.get("/:repo/releases/:version", async (c, next) => {45 const version = c.req.param("version");46 if (RELEASE_ROUTES.has(version)) return next();47 if (!isVersion(version)) return notFound(c, ctx);48 return moved(c, `/releases#${version}`);49 });50 app.get("/:repo/file", (c) => {51 const path = c.req.query("path") ?? "";52 if (!isSafePath(path)) return notFound(c, ctx);53 return moved(c, `/files/${pathUrl(path)}`);54 });55 app.get("/:repo/bundle", (c) => moved(c, "/archive/HEAD.tar.gz"));56 app.get("/:repo/bundle.blake3", (c) => moved(c, "/archive/HEAD.tar.gz"));57}