← All @molecule/* packages · App templates

@molecule/api-pdf

Core interface · pdf · API (Node) · v1.0.1 · Apache-2.0

PDF generation and manipulation core interface for molecule.dev

npm install @molecule/api-pdf

npm · Source on GitHub

How it works

@molecule/api-pdf is the pdf core interface on the API (Node) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 2 providers: @molecule/api-pdf-pdfkit, @molecule/api-pdf-puppeteer.

import { setProvider, fromHTML, merge, getPageCount } from '@molecule/api-pdf'
import { provider as puppeteer } from '@molecule/api-pdf-puppeteer'

setProvider(puppeteer)
const pdf = await fromHTML('<h1>Hello World</h1>', { format: 'A4', margin: { top: '1cm' } })
const pageCount = await getPageCount(pdf)
const merged = await merge([pdf, anotherPdf])

Providers (2): @molecule/api-pdf-pdfkit, @molecule/api-pdf-puppeteer

Works with: @molecule/api-bond, @molecule/api-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Provider-agnostic PDF generation and manipulation interface for molecule.dev.

Defines the PDFProvider interface for generating PDFs from HTML or templates, merging documents, adding watermarks, counting pages, and rendering pages as images. Bond packages (Puppeteer, PDFKit, etc.) implement this interface. Application code uses the convenience functions (fromHTML, fromTemplate, merge, addWatermark, getPageCount, getMetadata, toImages) which delegate to the bonded provider.

Quick Start

import { setProvider, fromHTML, merge, getPageCount } from '@molecule/api-pdf'
import { provider as puppeteer } from '@molecule/api-pdf-puppeteer'

setProvider(puppeteer)
const pdf = await fromHTML('<h1>Hello World</h1>', { format: 'A4', margin: { top: '1cm' } })
const pageCount = await getPageCount(pdf)
const merged = await merge([pdf, anotherPdf])

Type

core

Installation

npm install @molecule/api-pdf @molecule/api-bond @molecule/api-i18n

API

Interfaces

Margin

Page margin specification in CSS-style units (e.g., '1cm', '0.5in', '20px').

interface Margin {
  /** Top margin. */
  top?: string

  /** Right margin. */
  right?: string

  /** Bottom margin. */
  bottom?: string

  /** Left margin. */
  left?: string
}

PDFMetadata

Metadata extracted from a PDF buffer.

interface PDFMetadata {
  /** Total number of pages. */
  pageCount: number

  /** Document title, if set. */
  title?: string

  /** Document author, if set. */
  author?: string

  /** Document subject, if set. */
  subject?: string

  /** Document creator application, if set. */
  creator?: string

  /** Document creation date, if available. */
  creationDate?: Date

  /** Document modification date, if available. */
  modificationDate?: Date
}

PDFOptions

Options for PDF generation.

interface PDFOptions {
  /** Page size format. Defaults to `'A4'`. */
  format?: PageFormat

  /** Whether to use landscape orientation. Defaults to `false`. */
  landscape?: boolean

  /** Page margins. */
  margin?: Margin

  /** HTML template for the page header. */
  headerTemplate?: string

  /** HTML template for the page footer. */
  footerTemplate?: string

  /** Whether to print background graphics. Defaults to `false`. */
  printBackground?: boolean

  /** Paper width in CSS units (overrides `format`). */
  width?: string

  /** Paper height in CSS units (overrides `format`). */
  height?: string

  /** Page ranges to print (e.g., `'1-5'`, `'1,3,5-7'`). */
  pageRanges?: string

  /** Scale of the webpage rendering. Defaults to `1`. Must be between 0.1 and 2. */
  scale?: number
}

PDFProvider

PDF generation and manipulation provider interface.

All PDF providers must implement this interface. Bond packages (Puppeteer, PDFKit, etc.) provide concrete implementations.

interface PDFProvider {
  /**
   * Generates a PDF from an HTML string.
   *
   * @param html - The HTML content to render as a PDF.
   * @param options - PDF generation options (page size, margins, etc.).
   * @returns The generated PDF as a Buffer.
   */
  fromHTML(html: string, options?: PDFOptions): Promise<Buffer>

  /**
   * Generates a PDF from a template string with data interpolation.
   *
   * The template format is provider-dependent (e.g., Handlebars, Mustache).
   * Providers should document their supported template syntax.
   *
   * @param template - The template string.
   * @param data - Data to interpolate into the template.
   * @param options - PDF generation options.
   * @returns The generated PDF as a Buffer.
   */
  fromTemplate(
    template: string,
    data: Record<string, unknown>,
    options?: PDFOptions,
  ): Promise<Buffer>

  /**
   * Merges multiple PDF buffers into a single PDF document.
   *
   * @param pdfs - An array of PDF buffers to merge.
   * @returns The merged PDF as a Buffer.
   */
  merge(pdfs: Buffer[]): Promise<Buffer>

  /**
   * Adds a text watermark to every page of a PDF.
   *
   * @param pdf - The source PDF buffer.
   * @param text - The watermark text.
   * @param options - Watermark styling and placement options.
   * @returns The watermarked PDF as a Buffer.
   */
  addWatermark(pdf: Buffer, text: string, options?: WatermarkOptions): Promise<Buffer>

  /**
   * Returns the total number of pages in a PDF.
   *
   * @param pdf - The PDF buffer.
   * @returns The page count.
   */
  getPageCount(pdf: Buffer): Promise<number>

  /**
   * Extracts metadata from a PDF buffer.
   *
   * @param pdf - The PDF buffer.
   * @returns Metadata about the PDF document.
   */
  getMetadata?(pdf: Buffer): Promise<PDFMetadata>

  /**
   * Renders PDF pages as image buffers.
   *
   * @param pdf - The PDF buffer.
   * @param options - Rendering options (format, DPI, specific pages).
   * @returns An array of image buffers, one per rendered page.
   */
  toImages?(pdf: Buffer, options?: RenderOptions): Promise<Buffer[]>
}

RenderOptions

Options for rendering PDF pages to images.

interface RenderOptions {
  /** Output image format. Defaults to `'png'`. */
  format?: 'png' | 'jpeg'

  /** DPI resolution. Defaults to `150`. */
  dpi?: number

  /** Specific page numbers to render (1-based). If omitted, all pages are rendered. */
  pages?: number[]

  /** Quality percentage for JPEG output (1–100). Defaults to `80`. */
  quality?: number
}

WatermarkOptions

Options for watermark placement.

interface WatermarkOptions {
  /** Font size in points. Defaults to `48`. */
  fontSize?: number

  /** Text color (CSS color string). Defaults to `'rgba(0, 0, 0, 0.15)'`. */
  color?: string

  /** Rotation angle in degrees. Defaults to `-45`. */
  rotation?: number

  /** Opacity (0–1). Defaults to `0.15`. */
  opacity?: number
}

Types

PageFormat

Standard page size formats.

type PageFormat = 'A3' | 'A4' | 'A5' | 'Letter' | 'Legal' | 'Tabloid'

Functions

addWatermark(pdf, text, options)

Adds a text watermark to every page of a PDF.

function addWatermark(
  pdf: Buffer<ArrayBufferLike>,
  text: string,
  options?: WatermarkOptions,
): Promise<Buffer<ArrayBufferLike>>
  • pdf — The source PDF buffer.
  • text — The watermark text.
  • options — Watermark styling and placement options.

Returns: The watermarked PDF as a Buffer.

fromHTML(html, options)

Generates a PDF from an HTML string.

function fromHTML(html: string, options?: PDFOptions): Promise<Buffer<ArrayBufferLike>>
  • html — The HTML content to render as a PDF.
  • options — PDF generation options (page size, margins, etc.).

Returns: The generated PDF as a Buffer.

fromTemplate(template, data, options)

Generates a PDF from a template string with data interpolation.

function fromTemplate(
  template: string,
  data: Record<string, unknown>,
  options?: PDFOptions,
): Promise<Buffer<ArrayBufferLike>>
  • template — The template string.
  • data — Data to interpolate into the template.
  • options — PDF generation options.

Returns: The generated PDF as a Buffer.

getMetadata(pdf)

Extracts metadata from a PDF buffer.

function getMetadata(pdf: Buffer<ArrayBufferLike>): Promise<PDFMetadata>
  • pdf — The PDF buffer.

Returns: Metadata about the PDF document.

getPageCount(pdf)

Returns the total number of pages in a PDF.

function getPageCount(pdf: Buffer<ArrayBufferLike>): Promise<number>
  • pdf — The PDF buffer.

Returns: The page count.

getProvider()

Retrieves the bonded PDF provider, throwing if none is configured.

function getProvider(): PDFProvider

Returns: The bonded PDF provider.

hasProvider()

Checks whether a PDF provider is currently bonded.

function hasProvider(): boolean

Returns: true if a PDF provider is bonded.

merge(pdfs)

Merges multiple PDF buffers into a single PDF document.

function merge(pdfs: Buffer<ArrayBufferLike>[]): Promise<Buffer<ArrayBufferLike>>
  • pdfs — An array of PDF buffers to merge.

Returns: The merged PDF as a Buffer.

setProvider(provider)

Registers a PDF provider as the active singleton. Called by bond packages during application startup.

function setProvider(provider: PDFProvider): void
  • provider — The PDF provider implementation to bond.

toImages(pdf, options)

Renders PDF pages as image buffers.

function toImages(
  pdf: Buffer<ArrayBufferLike>,
  options?: RenderOptions,
): Promise<Buffer<ArrayBufferLike>[]>
  • pdf — The PDF buffer.
  • options — Rendering options (format, DPI, specific pages).

Returns: An array of image buffers, one per rendered page.

Available Providers

ProviderPackage
PDFKit (programmatic)@molecule/api-pdf-pdfkit
Puppeteer (HTML to PDF)@molecule/api-pdf-puppeteer

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-bond ^1.0.1
  • @molecule/api-i18n ^1.0.1

Runtime Dependencies

  • @molecule/api-bond

  • @molecule/api-i18n

  • Capabilities differ by bond — feature-detect before using the optional methods. getMetadata/toImages are OPTIONAL on {@link PDFProvider}; the convenience functions THROW when the bonded provider doesn't implement them (e.g. the PDFKit bond has no toImages). Check getProvider().toImages before exposing a page-preview feature, or pick a bond that supports it.

  • fromHTML fidelity is provider-dependent. Browser-engine bonds (Puppeteer) render full HTML/CSS; programmatic bonds (PDFKit) do a basic HTML-to-text approximation — do not expect styled output from a non-browser bond.

  • Results are Buffers: send them with a Content-Type: application/pdf response or store via the uploads package — never JSON.stringify a Buffer into an API payload, and avoid holding many large PDFs in memory at once.

  • HTML from user input is an injection surface. fromTemplate HTML-escapes the interpolated data values for you (like Handlebars {{ }}); fromHTML does NOT — escape values yourself before assembling the string, or a malicious value can forge or restyle document content.

  • A browser-engine bond renders server-side, so resource URLs in the HTML are fetched by YOUR server (SSRF). An <img src> / CSS url() / <iframe> pointing at an internal address (169.254.169.254, 10.…, localhost) is requested with your server's network access — and can pull the response into the PDF. Never build the HTML from an untrusted URL; if a document must include user-provided images, fetch + validate them through an SSRF-safe path first and embed as data: URIs, rather than letting the renderer load them.

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual documents (invoice, report, receipt, contract) and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • Every document the app generates has a working Download/Export control that returns a REAL PDF — not an HTML error page or a JSON-stringified Buffer. Inspect the actual response: Content-Type is application/pdf and the body's first bytes are the %PDF magic (hex 25 50 44 46). Fetch the endpoint and check both — a body that starts with < or { is a failure dressed up as a download.
  • Opening the downloaded PDF shows the record's real values (names, line items, dates, totals) — not placeholder/template text or a blank page.
  • Edit a record and re-export: the new PDF reflects the changed values, and two different records produce two visibly different PDFs (not the same cached bytes for every id).
  • If the app shows page previews or reads document info, it feature-detects (getProvider().toImages / .getMetadata) or bonds a provider that supports them — both are OPTIONAL and THROW on bonds that lack them (e.g. PDFKit), so a preview built on an unsupporting bond errors at runtime, not compile time.
  • Styled output (CSS layout, backgrounds, web fonts) actually renders — which requires a browser-engine bond (Puppeteer). On PDFKit the same HTML collapses to a plain-text approximation; if the design matters, that's the wrong bond.
  • Export is authorized: a signed-in user cannot fetch another user's document by guessing or incrementing an id — the endpoint scopes every PDF to its owner (a guessed id returns 403/404, never someone else's invoice).