@molecule/api-pdf
Core interface · pdf · API (Node) · v1.0.2 · Apache-2.0
PDF generation and manipulation core interface for molecule.dev
npm install @molecule/api-pdfHow 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 3 providers: @molecule/api-pdf-molecule, @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 (3): @molecule/api-pdf-molecule, @molecule/api-pdf-pdfkit, @molecule/api-pdf-puppeteer
Works with: @molecule/api-bond, @molecule/api-i18n
Reference
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.
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.tsJSDoc, not this file.
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
}
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
}
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
}
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
}
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
}
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[]>
}
Types
PageFormat
Standard page size formats.
type PageFormat = 'A3' | 'A4' | 'A5' | 'Letter' | 'Legal' | 'Tabloid'
Functions
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.
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.
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.
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.
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.
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.
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.
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
| Provider | Package |
|---|---|
| Molecule (hosted) | @molecule/api-pdf-molecule |
| 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/toImagesare OPTIONAL onPDFProvider; the convenience functions THROW when the bonded provider doesn't implement them (e.g. the PDFKit bond has notoImages). CheckgetProvider().toImagesbefore exposing a page-preview feature, or pick a bond that supports it. -
fromHTMLfidelity 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 aContent-Type: application/pdfresponse or store via the uploads package — neverJSON.stringifya Buffer into an API payload, and avoid holding many large PDFs in memory at once. -
HTML from user input is an injection surface.
fromTemplateHTML-escapes the interpolateddatavalues for you (like Handlebars{{ }});fromHTMLdoes 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>/ CSSurl()/<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 asdata: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-Typeisapplication/pdfand the body's first bytes are the%PDFmagic (hex25 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).