X Enterprises

fastify-xpdf

Fastify 5 plugin for PDF generation and manipulation — HTML/Markdown/URL to PDF via Puppeteer, form filling, merging, page extraction, and metadata via pdf-lib, with optional S3 storage.

fastify-xpdf

PDF generation and manipulation for Fastify 5. Uses Puppeteer (Chrome headless) for HTML/Markdown/URL rendering and pdf-lib for form filling, merging, page extraction, and metadata — with optional automatic upload to S3-compatible storage via @xenterprises/fastify-xstorage.

Installation

npm install @xenterprises/fastify-xpdf

# Optional — required only if useStorage: true
npm install @xenterprises/fastify-xstorage

Quick Start

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" },
});

fastify.get("/reports/:id/pdf", async (request, reply) => {
  const html = await renderReportHtml(request.params.id);
  const { buffer } = await fastify.xPDF.generateFromHtml(html);
  return reply
    .header("Content-Type", "application/pdf")
    .header("Content-Disposition", 'attachment; filename="report.pdf"')
    .send(buffer);
});

await fastify.listen({ port: 3000 });

Options

NameTypeDefaultRequiredDescription
headlessbooleantrueNoRun Puppeteer in headless mode
argsstring[]["--no-sandbox", "--disable-setuid-sandbox"]NoChrome launch arguments
useStoragebooleanfalseNoEnable automatic upload to xStorage
defaultFolderstring"pdfs"NoDefault storage folder for saved PDFs
formatstring"A4"NoDefault page format (A4, Letter, A3, A5, Tabloid, etc.)
printBackgroundbooleantrueNoPrint background graphics and colours
marginobject{ top: "1cm", right: "1cm", bottom: "1cm", left: "1cm" }NoDefault page margins (CSS units)

Methods

All methods are on fastify.xPDF.

Generation (Puppeteer-based):

Form operations (pdf-lib):

Manipulation (pdf-lib):

Exported Helpers

Available via import { helpers } from "@xenterprises/fastify-xpdf/helpers":

HelperDescription
generatePdfFilename(baseName?)Generate a unique filename with timestamp
isValidPdfBuffer(buffer)Returns true if buffer starts with %PDF header
getPdfMetadata(buffer)Returns { size } from a PDF buffer
formatPdfOptions(options, defaults)Merge per-call options with plugin defaults
sanitizeFilename(filename)Remove unsafe characters and lowercase
wrapHtmlTemplate(content)Wrap an HTML fragment in a full styled document
parseMargin(margin)Convert string or object margin to Puppeteer format
getPageFormat(format?)Return { width, height } in inches for a format name
saveToStorage(fastify, buffer, filename, folder)Upload a PDF buffer to xStorage

Error Reference

All errors use the [xPDF] prefix.

ErrorCause
[xPDF] 'headless' option must be a booleanNon-boolean headless at registration
[xPDF] 'args' option must be an array of stringsNon-array args at registration
[xPDF] 'useStorage' option must be a booleanNon-boolean useStorage
[xPDF] 'defaultFolder' option must be a stringNon-string defaultFolder
[xPDF] 'format' option must be a stringNon-string format
[xPDF] 'printBackground' option must be a booleanNon-boolean printBackground
[xPDF] 'margin' option must be an object...Invalid margin at registration
[xPDF] HTML content must be a non-empty stringEmpty/null HTML in generateFromHtml
[xPDF] Markdown content must be a non-empty stringEmpty/null markdown
[xPDF] URL must be a non-empty stringEmpty/null URL
[xPDF] URL must be a valid URLMalformed URL string
[xPDF] Invalid PDF bufferNon-PDF buffer passed to manipulation methods
[xPDF] fieldValues must be an objectNon-object fieldValues in fillForm
[xPDF] pdfBuffers must be a non-empty array...Empty/null array in mergePDFs
[xPDF] One or more invalid PDF buffers providedInvalid 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 integerNon-integer or negative index
[xPDF] Page index N out of range...Index exceeds PDF page count
[xPDF] Failed to initialize PDF browserPuppeteer browser launch failure
[xPDF] Failed to process PDF during mergeCorrupt PDF encountered during merge

Environment Variables

VariableRequiredDescription
PUPPETEER_HEADLESSNotrue/false — headless mode (default: true)
PUPPETEER_ARGSNoComma-separated Chrome launch arguments
PDF_DEFAULT_FORMATNoDefault page format (default: A4)
PDF_USE_STORAGENoEnable xStorage integration (default: false)
PDF_DEFAULT_FOLDERNoDefault storage folder (default: pdfs)

How It Works

The plugin uses two engines. Puppeteer handles HTML, Markdown, and URL-to-PDF generation: a single Chrome browser instance is lazily initialised on the first generation call, reused across requests, and closed via Fastify's onClose hook on shutdown. It auto-reconnects if the browser disconnects. pdf-lib handles all manipulation operations (form filling, merging, page extraction, metadata) in pure JavaScript with no browser. When useStorage: true and @xenterprises/fastify-xstorage is registered on the same Fastify instance, any method accepting saveToStorage: true will upload the result buffer to S3-compatible storage and include storageKey and url in the response. The plugin decorates Fastify with fastify.xPDF with a fastify >= 5.0.0 constraint.

AI Context

package: "@xenterprises/fastify-xpdf"
type: fastify-plugin
use-when: PDF generation from HTML/Markdown/URL via Puppeteer; PDF manipulation (form fill, merge, extract pages, metadata) via pdf-lib
decorator: fastify.xPDF (generateFromHtml, generateFromMarkdown, generateFromUrl, fillForm, listFormFields, mergePDFs, extractPages, getPageCount, getMetadata)
env: PUPPETEER_HEADLESS, PUPPETEER_ARGS, PDF_DEFAULT_FORMAT, PDF_USE_STORAGE, PDF_DEFAULT_FOLDER (all optional)
helper-exports: "@xenterprises/fastify-xpdf/helpers" (generatePdfFilename, isValidPdfBuffer, sanitizeFilename, wrapHtmlTemplate, parseMargin, etc.)
optional-integration: fastify-xstorage — register first if useStorage: true
Copyright © 2026