archive.ts

1.7 KB · raw

1import type { Hono } from "hono";2import { headId, saveByPrefix } from "../mirror/queries.ts";3import { notFound, openPublicRepo, type PageContext } from "../pages/layout.ts";4import { cachedTarball } from "./cache.ts";56// Long-lived but never `immutable` (§18): a strip can change what a save's tarball holds.7const TARBALL_CACHE = "public, max-age=31536000";89export function registerTarballRoutes(app: Hono, ctx: PageContext, tarballDir: string): void {10	app.get("/:repo/archive/HEAD.tar.gz", (c) => {11		const repo = openPublicRepo(ctx, c.req.param("repo"));12		const head = repo && headId(repo.mirror);13		if (!repo || !head) return notFound(c, ctx);14		const path = `/${repo.settings.name}/archive/${head}.tar.gz`;15		// Nix pins the immutable link in its lock file, so it must be absolute.16		c.header("Link", `<https://${ctx.domain}${path}>; rel="immutable"`);17		c.header("Cache-Control", "no-cache");18		return c.redirect(path, 302);19	});2021	app.get("/:repo/archive/:id{[0-9a-f]+\\.tar\\.gz}", (c) => {22		const repo = openPublicRepo(ctx, c.req.param("repo"));23		const id = c.req.param("id").replace(/\.tar\.gz$/, "");24		const save = repo && saveByPrefix(repo.mirror, id);25		if (!repo || !save) return notFound(c, ctx);26		const name = repo.settings.name;27		if (save.id !== id) {28			c.header("Cache-Control", "public, max-age=60");29			return c.redirect(`/${name}/archive/${save.id}.tar.gz`, 302);30		}31		const bytes = cachedTarball(tarballDir, repo.mirror, name, save.id);32		c.header("Content-Type", "application/gzip");33		c.header("Content-Disposition", `attachment; filename="${name}-${save.id.slice(0, 8)}.tar.gz"`);34		c.header("Cache-Control", TARBALL_CACHE);35		return c.body(bytes);36	});37}