import type { Context, Hono } from "hono"; import { isSafePath, isVersion } from "../bucket/repo.ts"; import { publicRepo } from "../server/db.ts"; import { notFound, type PageContext, pathUrl } from "./layout.ts"; // §28: Kepr 2's addresses. Every move is a 301: none of them will ever point anywhere else. const PANELS = new Map([ ["issues", "/issues"], ["builds", "/releases"], ["archives", "/archives"], ["trust", ""], ]); // Accounts, tickets, drafts, feeds, and Koh 2's offer and protocol endpoints (Kepr 2's `protocol.zig`). const GONE = [ "/tickets/*", "/drafts/*", "/join", "/cli-auth", "/api/cli-auth/*", "/api/repos/*", "/api/releases/upload", "/protocol/*", "/feed", "/:repo/feed", ]; // §22.1's own routes under `//releases/`, which a version would otherwise shadow. const RELEASE_ROUTES = new Set(["latest", "latest.json", "history.json"]); /** Registered ahead of the repo page, so `/source` and the gone paths are never taken for repos. */ export function registerKepr2Routes(app: Hono, ctx: PageContext): void { // §20: a move of a private or unknown repo would reveal it, so it 404s like every repo route. const moved = (c: Context, rest: string) => { const repo = c.req.param("repo") ?? ""; if (!publicRepo(ctx.kepr, repo)) return notFound(c, ctx); return c.redirect(`/${encodeURIComponent(repo)}${rest}`, 301); }; for (const path of GONE) app.all(path, (c) => c.text("Gone", 410)); app.get("/source", (c) => c.redirect("/kepr", 301)); app.get("/:repo", async (c, next) => { const panel = PANELS.get(c.req.query("panel") ?? ""); if (panel === undefined) return next(); return moved(c, panel); }); app.get("/:repo/releases/:version", async (c, next) => { const version = c.req.param("version"); if (RELEASE_ROUTES.has(version)) return next(); if (!isVersion(version)) return notFound(c, ctx); return moved(c, `/releases#${version}`); }); app.get("/:repo/file", (c) => { const path = c.req.query("path") ?? ""; if (!isSafePath(path)) return notFound(c, ctx); return moved(c, `/files/${pathUrl(path)}`); }); app.get("/:repo/bundle", (c) => moved(c, "/archive/HEAD.tar.gz")); app.get("/:repo/bundle.blake3", (c) => moved(c, "/archive/HEAD.tar.gz")); }