housekeeping.ts

1.6 KB · raw

1import { readFileSync } from "node:fs";2import { join } from "node:path";3import type { Hono } from "hono";4import { publicRepoNames } from "../server/db.ts";5import type { PageContext } from "./layout.ts";67// Kepr 2's mark, in Kepr's gold.8const FAVICON = readFileSync(join(import.meta.dir, "../../public/favicon.svg"));910/** §22.6: robots.txt, the sitemap (public repos only, as everywhere, §20) and the favicon. */11export function registerHousekeeping(app: Hono, ctx: PageContext): void {12	const origin = `https://${ctx.domain}`;13	app.get("/robots.txt", (c) =>14		c.body(`User-agent: *\nAllow: /\n\nSitemap: ${origin}/sitemap.xml\n`, 200, {15			"Content-Type": "text/plain; charset=UTF-8",16		}),17	);18	app.get("/sitemap.xml", (c) => {19		const url = (path: string, changefreq: string, priority: string) =>20			`  <url><loc>${21				origin22			}${path}</loc><changefreq>${changefreq}</changefreq><priority>${priority}</priority></url>\n`;23		const urls = [24			url("/", "daily", "1.0"),25			url("/browse", "daily", "0.9"),26			url("/docs", "weekly", "0.8"),27			// Repo names are [A-Za-z0-9._-] (§9.2's check at sync), so they need no XML escaping.28			...publicRepoNames(ctx.kepr).map((name) => url(`/${name}`, "daily", "0.7")),29		];30		return c.body(31			`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls.join(32				"",33			)}</urlset>\n`,34			200,35			{ "Content-Type": "application/xml; charset=UTF-8", "Cache-Control": "public, max-age=3600" },36		);37	});38	app.get("/favicon.svg", (c) =>39		c.body(FAVICON, 200, {40			"Content-Type": "image/svg+xml",41			"Cache-Control": "public, max-age=86400",42		}),43	);44}