export class ApiRequestError extends Error { readonly log?: string; constructor(message: string, log?: string) { super(message); this.name = "ApiRequestError"; this.log = log; } } async function errorOf(res: Response, fallback: string): Promise { let message = fallback; let log: string | undefined; try { const data: unknown = await res.json(); if (data && typeof data === "object") { if ("error" in data && typeof data.error === "string") message = data.error; if ("log" in data && typeof data.log === "string") log = data.log; } } catch { /* non-JSON error body */ } return new ApiRequestError(message, log); } export async function post(path: string, body: unknown): Promise { const res = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (!res.ok) throw await errorOf(res, `${path} failed (${res.status})`); return res.json() as Promise; } /** * Compile LaTeX to a PDF blob. * Dev: the Vite middleware at /local/compile runs the machine's real pdflatex. * Deployed: that route 404s and we fall back to the Worker's remote compile proxy. */ export async function compilePdf(latex: string): Promise { const local = await fetch("/local/compile", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ latex }), }); if (local.ok) return local.blob(); if (local.status === 422) throw await errorOf(local, "pdflatex failed"); const remote = await fetch("/api/pdf", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ latex }), }); if (remote.ok) return remote.blob(); throw await errorOf(remote, `PDF compile failed (${remote.status})`); }