syntaxai/tdd.md · main · src / d21_handlers_source.ts
// c21 — handler: serves the raw markdown source of an editable doc
// page from the main domain. Replaces the previous "view source on
// git.tdd.md" link so the docs site doesn't depend on the Forgejo
// subdomain for "view source". Reuses c32_edit_resolve so the same
// allowlist (sama / guides / blog + safe slug regex) protects both
// the editor and the raw view from path traversal.
import { resolveEdit } from "./b32_edit_resolve.ts";
import { renderNotFound, htmlResponse } from "./b51_render_layout.ts";
// The route literal is `/content/:section/:filename` and the handler
// requires the filename to end in `.md`. We don't use `:slug.md`
// because Bun's path parser treats that as a single param literally
// named "slug.md", which makes the URL un-typeable.
export const rawSourceHandler = async (
req: Request & { params: { section: string; filename: string } },
): Promise<Response> => {
const fullPath = `/content/${req.params.section}/${req.params.filename}`;
const notFound = async (): Promise<Response> => {
const html = await renderNotFound(fullPath);
return htmlResponse(html, 404);
};
if (!req.params.filename.endsWith(".md")) return await notFound();
const slug = req.params.filename.slice(0, -3);
const resolved = resolveEdit(req.params.section, slug);
if (!resolved) return await notFound();
const file = Bun.file(`./${resolved.filePath}`);
if (!(await file.exists())) return await notFound();
// text/plain so browsers render the markdown source inline rather
// than offering a download. UTF-8 is fixed because the content/ dir
// is UTF-8 throughout (verified by sama-verify).
return new Response(await file.text(), {
headers: {
"Content-Type": "text/plain; charset=utf-8",
"Cache-Control": "public, max-age=60",
},
});
};