// 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 { // 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 }); }