Initial MVP: DocFast PDF API

- HTML/Markdown to PDF conversion via Puppeteer
- Invoice and receipt templates
- API key auth + rate limiting
- Dockerfile for deployment
This commit is contained in:
DocFast Bot 2026-02-14 12:38:06 +00:00
commit feee0317ae
14 changed files with 4529 additions and 0 deletions

78
src/routes/convert.ts Normal file
View file

@ -0,0 +1,78 @@
import { Router, Request, Response } from "express";
import { renderPdf } from "../services/browser.js";
import { markdownToHtml, wrapHtml } from "../services/markdown.js";
export const convertRouter = Router();
interface ConvertBody {
html?: string;
markdown?: string;
css?: string;
format?: string;
landscape?: boolean;
margin?: { top?: string; right?: string; bottom?: string; left?: string };
printBackground?: boolean;
filename?: string;
}
// POST /v1/convert/html
convertRouter.post("/html", async (req: Request, res: Response) => {
try {
const body: ConvertBody =
typeof req.body === "string" ? { html: req.body } : req.body;
if (!body.html) {
res.status(400).json({ error: "Missing 'html' field" });
return;
}
// Wrap bare HTML fragments
const fullHtml = body.html.includes("<html")
? body.html
: wrapHtml(body.html, body.css);
const pdf = await renderPdf(fullHtml, {
format: body.format,
landscape: body.landscape,
margin: body.margin,
printBackground: body.printBackground,
});
const filename = body.filename || "document.pdf";
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", `inline; filename="${filename}"`);
res.send(pdf);
} catch (err: any) {
console.error("Convert HTML error:", err);
res.status(500).json({ error: "PDF generation failed", detail: err.message });
}
});
// POST /v1/convert/markdown
convertRouter.post("/markdown", async (req: Request, res: Response) => {
try {
const body: ConvertBody =
typeof req.body === "string" ? { markdown: req.body } : req.body;
if (!body.markdown) {
res.status(400).json({ error: "Missing 'markdown' field" });
return;
}
const html = markdownToHtml(body.markdown, body.css);
const pdf = await renderPdf(html, {
format: body.format,
landscape: body.landscape,
margin: body.margin,
printBackground: body.printBackground,
});
const filename = body.filename || "document.pdf";
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", `inline; filename="${filename}"`);
res.send(pdf);
} catch (err: any) {
console.error("Convert MD error:", err);
res.status(500).json({ error: "PDF generation failed", detail: err.message });
}
});