▍ humdrum codex / soft
1.5 KB raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// lib/pdf.ts — render the /print newspaper to a PDF via headless Chrome.
// Server-only. Refreshes stale sources first so the edition is current.

import { mkdirSync } from "node:fs";
import { resolve } from "node:path";
import puppeteer from "puppeteer";
import { listSources, insertEdition } from "@/lib/store";
import { ensureFresh } from "@/lib/refresh";
import type { EditionRow } from "@/db/schema";

const EDITIONS_DIR = resolve(process.cwd(), "editions");
const BASE_URL = process.env.SITE_URL ?? "http://localhost:4317";

export async function generateEdition(): Promise<EditionRow> {
  // Make the data current before snapshotting it into the paper.
  await Promise.all(
    listSources()
      .filter((s) => s.enabled)
      .map((s) => ensureFresh(s, { force: true })),
  );

  mkdirSync(EDITIONS_DIR, { recursive: true });
  const now = new Date();
  const date = now.toISOString().slice(0, 10);
  const stamp = now.toISOString().slice(0, 19).replace(/[:T]/g, "-");
  const pdfPath = resolve(EDITIONS_DIR, `edition-${stamp}.pdf`);

  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto(`${BASE_URL}/print`, { waitUntil: "networkidle0", timeout: 45_000 });
    await page.pdf({
      path: pdfPath,
      format: "letter", // match US Letter paper — A4 is taller and clips on duplex
      printBackground: true,
      preferCSSPageSize: true,
    });
  } finally {
    await browser.close();
  }

  return insertEdition({ date, pdfPath });
}