npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-xpdf

Peer 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:

  1. 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 onClose hook.

  2. 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).