syntaxai/tdd.md · main · src / d21_handlers_content.ts

d21_handlers_content.ts 37 lines · 1482 bytes raw
// c21 — public read-only render for sxdoc-backed pages.
//
// Routes (mounted in c21_app.ts):
//   GET /p/:slug              — single-segment fast path via routes table
//   GET /p/<multi-segment>    — multi-segment via appFetch regex fallback
//
// Composes c13_database (loadDocument), c51_render_sxdoc (sxToHtml),
// and c51_render_layout (renderPage chrome). Drafts (status=draft) 404
// publicly — only published pages are reachable.
//
// Scope note: posts get their own Ghost-style permalink in Fase 4
// (/blog/{primary_tag}/{slug}). For now only pages are public. Hitting
// /p/<slug> when a row exists with type=post still 404's so we can't
// accidentally leak a draft post-shape via the page route.

import { loadDocument } from "./c13_database.ts";
import { sxToHtml } from "./b51_render_sxdoc.ts";
import { htmlResponse, renderPage, renderNotFound } from "./b51_render_layout.ts";

export const publicPageHandler = async (
  req: Request & { params: { slug: string } },
): Promise<Response> => renderPublicPage(req.params.slug);

export const renderPublicPage = async (slug: string): Promise<Response> => {
  const row = loadDocument(slug, "page");
  if (!row || row.status !== "published") {
    const html = await renderNotFound(`/p/${slug}`);
    return htmlResponse(html, 404);
  }
  const html = await renderPage({
    title: `${row.title} — tdd.md`,
    bodyHtml: sxToHtml(row.doc),
    ogPath: `https://tdd.md/p/${slug}`,
  });
  return htmlResponse(html);
};