kepr2.ts

2.2 KB · raw

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";56// §28: Kepr 2's addresses. Every move is a 301: none of them will ever point anywhere else.7const PANELS = new Map([8	["issues", "/issues"],9	["builds", "/releases"],10	["archives", "/archives"],11	["trust", ""],12]);13// Accounts, tickets, drafts, feeds, and Koh 2's offer and protocol endpoints (Kepr 2's `protocol.zig`).14const 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];26// §22.1's own routes under `/<repo>/releases/`, which a version would otherwise shadow.27const RELEASE_ROUTES = new Set(["latest", "latest.json", "history.json"]);2829/** Registered ahead of the repo page, so `/source` and the gone paths are never taken for repos. */30export function registerKepr2Routes(app: Hono, ctx: PageContext): void {31	// §20: a move of a private or unknown repo would reveal it, so it 404s like every repo route.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}