@xenterprises/fastify-xpdf
v1.2.1
Published
Fastify plugin for PDF generation and manipulation. Convert HTML/Markdown to PDF, fill forms, and merge PDFs.
Readme
@xenterprises/fastify-xpdf
Fastify plugin for PDF generation and manipulation — convert HTML/Markdown to PDF, fill PDF forms, merge PDFs, and extract pages, with optional S3-compatible storage via xStorage.
Install
npm install @xenterprises/fastify-xpdfPeer dependency (optional): @xenterprises/fastify-xstorage — required only if you enable useStorage: true.
Usage
import Fastify from "fastify";
import xPDF from "@xenterprises/fastify-xpdf";
const fastify = Fastify();
await fastify.register(xPDF, {
format: "A4",
printBackground: true,
margin: { top: "1cm", right: "1cm", bottom: "1cm", left: "1cm" },
});
// Generate PDF from HTML
const result = await fastify.xPDF.generateFromHtml("<h1>Hello World</h1>");
console.log(result.buffer); // PDF Buffer
console.log(result.size); // File size in bytes
// Generate from Markdown
const md = await fastify.xPDF.generateFromMarkdown("# Title\n\nParagraph");
// Fill a PDF form
const filled = await fastify.xPDF.fillForm(pdfBuffer, {
firstName: "Jane",
agreeToTerms: true,
});
// Merge multiple PDFs
const merged = await fastify.xPDF.mergePDFs([pdf1, pdf2, pdf3]);
await fastify.close();Options
| Name | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| headless | boolean | true | No | Run Puppeteer browser in headless mode |
| args | string[] | ["--no-sandbox", "--disable-setuid-sandbox"] | No | Chrome/Chromium launch arguments |
| useStorage | boolean | false | No | Enable automatic saving to xStorage |
| defaultFolder | string | "pdfs" | No | Default storage folder for saved PDFs |
| format | string | "A4" | No | Default page format (A4, Letter, A3, A5, Tabloid, Ledger, Legal, A0–A6) |
| printBackground | boolean | true | No | Print background graphics and colors by default |
| margin | object | { top: "1cm", right: "1cm", bottom: "1cm", left: "1cm" } | No | Default page margins (CSS units) |
Decorated Properties
fastify.xPDF
All methods are available on the fastify.xPDF decorator.
generateFromHtml(html, options?)
Generate a PDF from HTML content.
| Param | Type | Description |
|-------|------|-------------|
| html | string | HTML content (required, non-empty) |
| options.filename | string | Output filename (auto-generated if omitted) |
| options.format | string | Page format override |
| options.landscape | boolean | Landscape orientation |
| options.margin | object | Page margins override |
| options.printBackground | boolean | Print background override |
| options.displayHeaderFooter | boolean | Enable header/footer |
| options.headerTemplate | string | Header HTML template |
| options.footerTemplate | string | Footer HTML template |
| options.saveToStorage | boolean | Save to xStorage |
| options.folder | string | Storage folder override |
Returns: { buffer, filename, size, storageKey?, url? }
generateFromMarkdown(markdown, options?)
Convert Markdown to PDF. Accepts the same options as generateFromHtml. The Markdown is parsed with marked and wrapped in a styled HTML template.
generateFromUrl(url, options?)
Navigate to a URL and generate a PDF of the rendered page.
| Param | Type | Description |
|-------|------|-------------|
| url | string | URL to render (required, must be valid) |
| options.waitFor | string | Puppeteer waitUntil value (default: "networkidle2") |
| options.timeout | number | Navigation timeout in ms (default: 30000) |
Plus all options from generateFromHtml.
fillForm(pdfBuffer, fieldValues, options?)
Fill PDF form fields (text, checkbox, radio, dropdown).
| Param | Type | Description |
|-------|------|-------------|
| pdfBuffer | Buffer | Source PDF with form fields |
| fieldValues | object | { fieldName: value } key-value pairs |
| options.flatten | boolean | Flatten form after filling (default: true) |
| options.filename | string | Output filename |
| options.saveToStorage | boolean | Save to xStorage |
| options.folder | string | Storage folder |
Returns: { buffer, filename, size, storageKey?, url? }
listFormFields(pdfBuffer)
List all form fields in a PDF.
Returns: [{ name, type, value }] — type is one of: text, checkbox, radio, dropdown, option, button, signature, unknown.
mergePDFs(pdfBuffers, options?)
Merge multiple PDFs into a single document.
| Param | Type | Description |
|-------|------|-------------|
| pdfBuffers | Buffer[] | Array of PDF buffers (required, non-empty) |
| options.filename | string | Output filename |
| options.saveToStorage | boolean | Save to xStorage |
| options.folder | string | Storage folder |
Returns: { buffer, filename, size, pageCount, storageKey?, url? }
extractPages(pdfBuffer, pageIndices, options?)
Extract specific pages from a PDF into a new document.
| Param | Type | Description |
|-------|------|-------------|
| pdfBuffer | Buffer | Source PDF buffer |
| pageIndices | number[] | Zero-based page indices to extract |
| options.filename | string | Output filename |
| options.saveToStorage | boolean | Save to xStorage |
| options.folder | string | Storage folder |
Returns: { buffer, filename, size, pageCount, storageKey?, url? }
getPageCount(pdfBuffer)
Get the number of pages in a PDF. Returns a number.
getMetadata(pdfBuffer)
Get PDF metadata.
Returns: { pageCount, title, author, subject, creator, creationDate, modificationDate, size }
Exported Helpers
Available via import { helpers } from "@xenterprises/fastify-xpdf/helpers":
| Helper | Description |
|--------|-------------|
| generatePdfFilename(baseName?) | Generate unique filename with timestamp |
| isValidPdfBuffer(buffer) | Check if buffer starts with %PDF header |
| getPdfMetadata(buffer) | Get { size } from a PDF buffer |
| formatPdfOptions(options, defaults) | Merge options with defaults (deep-merges margin) |
| sanitizeFilename(filename) | Remove unsafe characters, lowercase |
| wrapHtmlTemplate(content) | Wrap HTML fragment in a full styled document |
| parseMargin(margin) | Convert string or object margin to Puppeteer format |
| getPageFormat(format?) | Get { width, height } in inches for a format name |
| saveToStorage(fastify, buffer, filename, folder) | Upload PDF to xStorage if available |
Environment Variables
| Name | Required | Description |
|------|----------|-------------|
| PUPPETEER_HEADLESS | No | true/false — headless mode (default: true) |
| PUPPETEER_ARGS | No | Comma-separated Chrome args |
| PDF_DEFAULT_FORMAT | No | Default page format (default: A4) |
| PDF_USE_STORAGE | No | Enable xStorage integration (default: false) |
| PDF_DEFAULT_FOLDER | No | Default storage folder (default: pdfs) |
Error Reference
All errors are prefixed with [xPDF].
| Error | When |
|-------|------|
| [xPDF] 'headless' option must be a boolean | Invalid headless option at startup |
| [xPDF] 'args' option must be an array of strings | Invalid args option at startup |
| [xPDF] 'useStorage' option must be a boolean | Invalid useStorage option at startup |
| [xPDF] 'defaultFolder' option must be a string | Invalid defaultFolder option at startup |
| [xPDF] 'format' option must be a string | Invalid format option at startup |
| [xPDF] 'printBackground' option must be a boolean | Invalid printBackground option at startup |
| [xPDF] 'margin' option must be an object... | Invalid margin option at startup |
| [xPDF] HTML content must be a non-empty string | Empty/null HTML passed to generateFromHtml |
| [xPDF] Markdown content must be a non-empty string | Empty/null markdown passed to generateFromMarkdown |
| [xPDF] URL must be a non-empty string | Empty/null URL passed to generateFromUrl |
| [xPDF] URL must be a valid URL | Invalid URL format |
| [xPDF] Invalid PDF buffer | Non-PDF buffer passed to form/merge/extract methods |
| [xPDF] fieldValues must be an object | Non-object passed as fieldValues to fillForm |
| [xPDF] pdfBuffers must be a non-empty array... | Empty/null array passed to mergePDFs |
| [xPDF] One or more invalid PDF buffers provided | Invalid buffer in merge array |
| [xPDF] pageIndices must be a non-empty array... | Invalid pageIndices in extractPages |
| [xPDF] Each page index must be a non-negative integer | Non-integer or negative page index |
| [xPDF] Page index N out of range... | Page index exceeds PDF page count |
| [xPDF] Failed to initialize PDF browser | Puppeteer browser launch failure |
| [xPDF] Failed to process PDF during merge | Corrupt PDF during merge operation |
How It Works
The plugin uses two engines:
Puppeteer (Chrome headless) for HTML/Markdown/URL to PDF generation. A single browser instance is lazily initialized on the first generation call and reused across requests. It auto-reconnects if the browser disconnects. The browser is closed on Fastify shutdown via the
onClosehook.pdf-lib for all PDF manipulation (form filling, merging, page extraction, metadata). These operations are pure JavaScript with no browser dependency.
When useStorage: true and @xenterprises/fastify-xstorage is registered, generated PDFs can be automatically uploaded to S3-compatible storage. The saveToStorage option on each method call controls whether that specific result is uploaded.
The plugin registers itself as xPDF via fastify-plugin with a fastify >= 5.0.0 constraint and no dependencies (it can be registered in any scope).
