kepr2.ts

2.1 KB · raw

1import type { Hono } from "hono";2import { isSafePath, isVersion } from "../bucket/repo.ts";3import { notFound, type PageContext, pathUrl } from "./layout.ts";45// §28: Kepr 2's addresses. Every move is a 301: none of them will ever point anywhere else.6const PANELS = new Map([7	["issues", "/issues"],8	["builds", "/releases"],9	["archives", "/archives"],10	["trust", ""],11]);12// Accounts, tickets, drafts, feeds, and Koh 2's offer and protocol endpoints (Kepr 2's `protocol.zig`).13const GONE = [14	"/tickets/*",15	"/drafts/*",16	"/join",17	"/cli-auth",18	"/api/cli-auth/*",19	"/api/repos/*",20	"/api/releases/upload",21	"/protocol/*",22	"/feed",23	"/:repo/feed",24];25// §22.1's own routes under `/<repo>/releases/`, which a version would otherwise shadow.26const RELEASE_ROUTES = new Set(["latest", "latest.json", "history.json"]);2728/** Registered ahead of the repo page, so `/source` and the gone paths are never taken for repos. */29export function registerKepr2Routes(app: Hono, ctx: PageContext): void {30	for (const path of GONE) app.all(path, (c) => c.text("Gone", 410));31	app.get("/source", (c) => c.redirect("/kepr", 301));32	app.get("/:repo", async (c, next) => {33		const panel = PANELS.get(c.req.query("panel") ?? "");34		if (panel === undefined) return next();35		return c.redirect(`/${encodeURIComponent(c.req.param("repo"))}${panel}`, 301);36	});37	app.get("/:repo/releases/:version", async (c, next) => {38		const version = c.req.param("version");39		if (RELEASE_ROUTES.has(version)) return next();40		if (!isVersion(version)) return notFound(c, ctx);41		return c.redirect(`/${encodeURIComponent(c.req.param("repo"))}/releases#${version}`, 301);42	});43	app.get("/:repo/file", (c) => {44		const path = c.req.query("path") ?? "";45		if (!isSafePath(path)) return notFound(c, ctx);46		return c.redirect(`/${encodeURIComponent(c.req.param("repo"))}/files/${pathUrl(path)}`, 301);47	});48	app.get("/:repo/bundle", (c) => c.redirect(headTarball(c.req.param("repo")), 301));49	app.get("/:repo/bundle.blake3", (c) => c.redirect(headTarball(c.req.param("repo")), 301));50}5152const headTarball = (repo: string) => `/${encodeURIComponent(repo)}/archive/HEAD.tar.gz`;