import { readFileSync } from "node:fs";
import { join } from "node:path";
import type { Hono } from "hono";
import { publicRepoNames } from "../server/db.ts";
import type { PageContext } from "./layout.ts";
// Kepr 2's mark, in Kepr's gold.
const FAVICON = readFileSync(join(import.meta.dir, "../../public/favicon.svg"));
/** §22.6: robots.txt, the sitemap (public repos only, as everywhere, §20) and the favicon. */
export function registerHousekeeping(app: Hono, ctx: PageContext): void {
const origin = `https://${ctx.domain}`;
app.get("/robots.txt", (c) =>
c.body(`User-agent: *\nAllow: /\n\nSitemap: ${origin}/sitemap.xml\n`, 200, {
"Content-Type": "text/plain; charset=UTF-8",
}),
);
app.get("/sitemap.xml", (c) => {
const url = (path: string, changefreq: string, priority: string) =>
` ${
origin
}${path}${changefreq}${priority}\n`;
const urls = [
url("/", "daily", "1.0"),
url("/browse", "daily", "0.9"),
url("/docs", "weekly", "0.8"),
// Repo names are [A-Za-z0-9._-] (§9.2's check at sync), so they need no XML escaping.
...publicRepoNames(ctx.kepr).map((name) => url(`/${name}`, "daily", "0.7")),
];
return c.body(
`\n\n${urls.join(
"",
)}\n`,
200,
{ "Content-Type": "application/xml; charset=UTF-8", "Cache-Control": "public, max-age=3600" },
);
});
app.get("/favicon.svg", (c) =>
c.body(FAVICON, 200, {
"Content-Type": "image/svg+xml",
"Cache-Control": "public, max-age=86400",
}),
);
}