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

pdfnative-cli

v1.5.0

Published

Official CLI for pdfnative — render JSON to PDF (typography engine, 27 Unicode scripts + custom fonts, math, COLRv1 colour emoji, 9 native vector chart types, CMYK and PDF/X-4 print production with bleed/printer marks/colour bars, PDF/A, bookmarks, stream

Readme

pdfnative-cli

CI CodeQL npm version npm downloads zero extra runtime dependencies TypeScript License: MIT npm provenance OpenSSF Scorecard

pdfnative website

Official CLI for the pdfnative library — render JSON to PDF, apply digital signatures, verify them, and inspect PDF conformance, directly from the terminal. Zero extra runtime dependencies.

What's new in v1.5.0 — built on pdfnative 1.8.0. render gains a typography engine (widow/orphan control, keep-with-next, justification, optical margins, soft hyphens, French punctuation spacing, kerning and OpenType features — layout.typography plus four flags), CMYK colours and printer's colour bars, PDF/X-4 output (--pdfx pdfx4 --output-intent-icc <cmyk.icc> --trapped) checked by inspect --check pdfx, 27 Unicode scripts (+ Lao, Tai Tham, New Tai Lue, Tai Le, Cham; ha/yo/ig/sw aliases) and custom fonts (--font-file). Output is now byte-reproducible: a global --creation-date (or SOURCE_DATE_EPOCH) pins every date in UTC. Global flags may now precede the command; annotate gains link; sign --timestamp-timeout; verify flags SHA-1 timestamp imprints; inspect --iso-dates; doctor reports fonts, Unicode and conformance targets. The repository ships the same engineering as the engine: one quality gate, a byte-exact sample baseline, a PDF/A + PDF/X conformance corpus, hardened CI with attestations, and a documentation verifier. Zero breaking changes. See release notes and docs/AGENT_CONTRACT.md.

⭐ Star pdfnative — the zero-dependency PDF engine that powers this CLI.

Highlights

  • render — pipe a JSON document into a production-ready PDF. Encryption (AES-128/256), watermarks (text + image), page templates, PDF/A archival, 27 Unicode scripts + COLRv1 colour emoji + a bundled math font (--font math), native vector charts (bar, barH, line, pie, donut — pdfnative ≥ 1.6.0), PDF bookmarks (--outline), layout introspection (--inspect-layout / --debug-layout), streaming (single-pass, page-by-page, or true constant-memory --stream-true), and a hybrid flags + --layout file.json model.
  • Typography (v1.5.0, pdfnative ≥ 1.8.0) — layout.typography brings paragraph breaking (widows/orphans, keepWithNext, splittable paragraphs), align: "justify", optical margin alignment, soft hyphens, French punctuation spacing with unit binding (150 € never breaks), kerning, OpenType features (onum, smcp, tnum, …) and exact base-14 metrics. Four high-frequency flags — --split-paragraphs, --keep-headings-with-next, --kerning, --font-features <tag,…> — cover the common cases; the rest rides in --layout.
  • CMYK & PDF/X-4 (v1.5.0) — every colour accepts CMYK ("c m y k" or [c,m,y,k]), printer's marks gain colour bars, and render --pdfx pdfx4 --output-intent-icc <cmyk.icc> --trapped false writes a PDF/X-4 file whose claim inspect --check pdfx re-validates with pdfnative's structural validator (PDFX_* diagnostics, --strict gating). A 22-file conformance corpus (PDF/A via veraPDF, PDF/X via the validator) guards every release.
  • Reproducible output (v1.5.0) — the global --creation-date <iso8601> (or SOURCE_DATE_EPOCH) pins /CreationDate, xmp:CreateDate, the {date} placeholder and the trailer /ID, all in UTC, so the same input renders to byte-identical bytes on every host and in every timezone. The repository's own 91-sample baseline is held to that promise.
  • 27 scripts & custom fonts (v1.5.0) — --font lo|nod|khb|tdd|cjm add Lao, Tai Tham, New Tai Lue, Tai Le and Cham; ha/yo/ig/sw alias latin for Hausa, Yoruba, Igbo and Swahili; --font-file <path.ttf>[:name] registers your own TrueType/OpenType file (32 MiB cap, magic-byte and parser validation — never from a JSON payload). --variant table embeds fonts too, so table renders can claim PDF/A.
  • extract-text / fill / encrypt / decrypt (v1.3.0, pdfnative ≥ 1.6.0) — extract reading-order text as text/JSON/NDJSON for RAG & agents (no OCR); fill, flatten & export AcroForms with an incremental save (signatures stay valid; fill --export gives a read→edit→fill round-trip); re-secure with AES-128/256 or remove encryption. merge / split / extract gain --password, --encrypt, and constant-memory --stream.
  • doctor — an offline environment/capability preflight (CLI/Node/pdfnative versions, Web Crypto CSPRNG required by encrypt, command count, and — v1.5.0 — the bundled font inventory probed on disk, the Unicode version and the PDF/A + PDF/X conformance targets). Text or --json; exit 0/1 — an ideal agent pre-flight.
  • sign — CMS/PKCS#7 digital signatures with full metadata (--reason, --name, --location, --contact, --signing-time) and intermediate CA chains via --cert-chain (repeatable). Uses native node:crypto for constant-time signatures by default (--pure-crypto opts out). Keys loaded from env vars or files; never logged. v1.4.0 adds a functional RFC 3161 --timestamp <tsa-url> (PAdES B-T), PAdES profile (--profile pades — ETSI.CAdES.detached, ESS signing-certificate-v2), sha384/512 digests (RSA), multi-signatures (--allow-multiple / --field-name), and visible signature placement (--signature-rect / --signature-page); v1.5.0 adds --timestamp-timeout <ms> for the TSA round-trip.
  • PAdES long-term signatures (v1.4.0, pdfnative ≥ 1.7.0) — the full B-T → B-LT → B-LTA ladder: sign --timestamp <tsa> --profile pades (B-T) → ltv add --online (B-LT: OCSP + CRL validation data archived into /DSS + /VRI) → doc-timestamp --url <tsa> (B-LTA: a /DocTimeStamp revision, repeatable for renewal) → ltv add --online. The ltv collect / ltv embed split supports air-gapped pipelines — collect on a connected machine, embed fully offline. All network access is explicit opt-in and SSRF-guarded.
  • metadata / compare (v1.4.0) — update /Info + XMP metadata with an incremental save (existing signatures stay valid); diff two PDFs by text + structure with CI-friendly exit codes (identical → 0, different → 1 / E_CHECK_FAILED).
  • batch --manifest (v1.4.0) — a declarative, sequential multi-command pipeline (render → sign → verify → …) in one JSON file, with @<id> output references and an --allow-network gate so untrusted manifests can never trigger network I/O.
  • Print production & charts v2 (v1.4.0, pdfnative ≥ 1.7.0) — render layout gains bleed/trim/art/crop boxes, printer marks, userUnit, ICC output intents, and viewer preferences (duplex, numCopies, …); charts grow to 9 types (stacked bars, area, scatter) with dual axes, log/time/category x-axes, and data labels. render --strict turns PDF/A conformance diagnostics into a hard error before the first output byte.
  • inspect — PDF version, page count, encryption, PDF/A and PDF/X conformance, signature count, metadata (--iso-dates normalises PDF dates to ISO 8601 — v1.5.0), page labels, markup/link annotations (--annotations), PDF/UA (ISO 14289-1) structural validation and a PDF/X-4 validation report (--pdfx). --verbose, --pages, and --check pdfa|signed|encrypted|pdfua|pdfx for CI assertions.
  • verify — verify every CMS/PKCS#7 signature: byte-range integrity, RSA/ECDSA signature value (RSA now also sha384/512), certificate chain, trust roots, RFC 3161 timestamp (PAdES-T), /DocTimeStamp revisions (PAdES B-LTA), and OCSP + CRL revocation (embedded /DSS offline by default, opt-in SSRF-guarded online). JSON & text output, --strict, --revocation, --revocation-policy; a SHA-1 timestamp imprint is reported as a weak digest and refused under --strict (v1.5.0).
  • merge / split / extract — page-tree operations (pdfnative ≥ 1.5.0): concatenate several PDFs, split one PDF into many (per-page or per-range), or pull selected pages into a new PDF. --drop-annotations and --max-output-size guards included.
  • annotate — attach markup annotations (highlight, text note, square, line, …) and — v1.5.0 — link annotations (url, validated: http/https/mailto only) to an existing PDF via a JSON spec, using an incremental save so the original bytes — and any existing signature — stay intact.
  • govern — expose pdfnative's AI-governance / HITL contract: govern rules, govern policy, and govern verify-issue <draft.md> to gate an issue/PR draft (exit 1 / E_POLICY on violation) before a human reviews and submits it.
  • batch — render every JSON file in a directory to PDF in parallel, reusing the full render pipeline, with a per-file summary and bounded --concurrency.
  • completion — emit bash, zsh, fish, or powershell shell-completion scripts.
  • schema — print a versioned JSON Schema (Draft 2020-12) for any CLI input/output shape, plus schema manifest (a machine-readable capability manifest) and llms.txt, so agents can self-validate and discover the CLI's tools.
  • Agent-native — a global --json status/error envelope, 12 stable E_* error codes, and a --dry-run validation mode let autonomous AI agents and CI drive the CLI deterministically; global flags may precede or follow the command name (v1.5.0). Token-economy levers — --summary (minimal verdict), --fields (dot-path projection), and compact JSON under --json — shrink agent output ~90 %. See docs/AGENT_CONTRACT.md.
  • Engineered like the engine (v1.5.0) — one quality gate (npm run gate) with fast / CI / publish profiles, a byte-exact sample baseline (test-output/samples/ vs tests/regression/baselines/samples.sha256.json), a PDF/A + PDF/X conformance corpus, hardened workflows (egress-audited runners, SHA-pinned actions, Trusted Publishing, SBOM + build attestations), a documentation verifier (npm run verify:docs) and a committed Claude Code layer with a human-in-the-loop guard hook — 1403 tests.
  • AI-governance / HITL — the govern command surfaces pdfnative's Human-in-the-Loop contract to agents: they act as draftsmen, never autonomous submitters. govern verify-issue gates a local draft; a human always reviews and submits.
  • .pdfnativerc.json — optional config file for default flags (global + per-command); precedence is CLI flags > env > config.
  • Zero extra dependencies — pdfnative is the sole runtime dependency.
  • Offline by default — no network access unless you explicitly opt in with verify --revocation online, sign --timestamp, ltv --online, doc-timestamp --url, or batch --allow-network — and every request passes an SSRF guard (no redirects).
  • Stdin / stdout by default — every command is shell-pipeline friendly.
  • Secret-safe — signing keys, certs, encryption passwords never appear in error output or stderr. PEM material redacted; layout-file attachments[].data injection blocked.
  • ESM-first, TypeScript strict — built with tsup, typed declarations included.
  • NPM provenance — signed builds via GitHub Actions OIDC.

Supported Features

| Feature | Status | Notes | |---------|--------|-------| | Commands | | | | render JSON → PDF | ✅ | Streaming, hybrid layout model, multilingual fonts, bookmarks, layout introspection | | sign digital signatures | ✅ | RSA/ECDSA (CMS/PKCS#7), metadata fields, cert chains, native node:crypto | | inspect PDF metadata | ✅ | --verbose, --pages, --pdfua, --pdfx, --iso-dates, --annotations, --form-fields, --encryption, --password, page labels, --check … | | verify signature verification | ✅ | Integrity + chain + trust + timestamp + revocation; --strict | | extract-text reading-order text | ✅ | --format text\|json\|ndjson, --runs, --pages, --password; RAG/agent-native (no OCR) | | fill fill / flatten / export AcroForms | ✅ | --data <values.json>, --flatten, --export (values → --data map); incremental save | | encrypt / decrypt | ✅ | AES-128/256 re-encryption & transparent decryption (--password, --stream) | | doctor preflight | ✅ | CLI/Node/pdfnative versions, Web Crypto (CSPRNG), command count, font inventory, Unicode version, conformance targets; text or --json | | merge concatenate PDFs | ✅ | Page-tree API; --password, --encrypt, --stream, --drop-annotations, --max-output-size | | split one PDF → many | ✅ | Per-page (default) or per-range (--pages); --password, --encrypt, --stream | | extract selected pages | ✅ | 1-based --pages list/range; --password, --encrypt, --stream | | annotate markup + link annotations | ✅ | Incremental save (signatures preserved); JSON spec via --annotations; link type with URL validation (v1.5.0) | | govern AI-governance / HITL | ✅ | rules / policy / verify-issue; gates drafts with E_POLICY | | batch parallel rendering | ✅ | Directory → PDFs, --concurrency, --fail-fast | | completion shell scripts | ✅ | bash / zsh / fish / powershell | | schema JSON Schema export | ✅ | Per-command schemas + summaries + status + manifest (capability manifest) | | .pdfnativerc.json config file | ✅ | Global + per-command defaults; flags > env > config | | Agent / automation | | | | Global --json envelope | ✅ | Status on success, { ok, error: { code, message } } on failure | | Stable error codes | ✅ | 12 codes: E_USAGE, E_INPUT, E_PARSE, E_IO, E_SIGN, E_VERIFY_FAILED, E_CHECK_FAILED, E_POLICY, E_UNSUPPORTED, E_PASSWORD, E_NETWORK, E_RUNTIME | | Global flags before the command | ✅ | pdfnative --json --dry-run render … ≡ pdfnative render … --json --dry-run (v1.5.0) | | Reproducible output | ✅ | Global --creation-date <iso8601> / SOURCE_DATE_EPOCH → byte-identical PDFs across hosts and timezones (v1.5.0) | | Capability manifest | ✅ | schema manifest (JSON) + llms.txt — for agent tool discovery | | --dry-run validation | ✅ | render / sign / batch / merge / split / extract / annotate / fill / encrypt / decrypt / metadata / ltv / doc-timestamp | | Document Blocks | | | | Headings, paragraphs, lists | ✅ | Full text styling support | | Tables | ✅ | Headers, rows, multi-page | | Barcodes | ✅ | QR, Code 128, EAN-13, Data Matrix, PDF417 | | Charts | ✅ | chart block: bar, barH, line, pie, donut (native PDF paths, pdfnative ≥ 1.6.0) | | Hyperlinks | ✅ | URL validation, blue underlined text | | Form fields | ✅ | Text, checkbox, radio, dropdown, listbox | | Page breaks, spacers | ✅ | Explicit pagination control | | Table of contents | ✅ | Auto-generated with /GoTo links | | Advanced Layouts (v0.2.0) | | | | PDF/A archival (1b, 2b, 2u, 3b) | ✅ | --tagged pdfa<level> (preferred) or --conformance (deprecated); validated against the veraPDF reference validator in CI (blocking) | | Streaming output | ✅ | --stream (single-pass) for large documents | | Compression | ✅ | --compress flag | | Encryption (AES-128/256) | ✅ | --encrypt-* flags + env-var precedence | | Watermarks (text + image) | ✅ | --watermark-text, --watermark-image, --watermark-position | | Headers / footers with placeholders | ✅ | --header-{l,c,r}, --footer-{l,c,r}, {page}/{pages}/{date}/{title} | | Custom page sizes | ✅ | --page-size A4\|Letter\|… or WxH in points | | Custom margins | ✅ | --margin <N> or --margin <t,r,b,l> | | PDF/A-3 attachments | ✅ | --attachment <path>:<mime>:<rel>:<desc> (repeatable) | | Multilingual fonts | ✅ | 27 Unicode scripts via --font <code> --lang <code> (e.g. th, ja, ar, te, si, km, lo, cjm); Latin built-in | | Table-centric variant (PdfParams) | ✅ | --variant table | | Full PdfLayoutOptions | ✅ | --layout <file.json> | | Signing (v0.2.0) | | | | RSA signatures (rsa-sha256) | ✅ | Default algorithm | | ECDSA signatures (ecdsa-sha256) | ✅ | P-256 SEC1 / PKCS#8 keys (v0.3.0) | | Auto signature-placeholder injection | ✅ | One-command sign of any rendered PDF (v0.3.0) | | Signature metadata | ✅ | --reason, --name, --location, --contact, --signing-time | | Cert chains (intermediate CAs) | ✅ | --cert-chain <pem> (repeatable) or PDFNATIVE_SIGN_CHAIN env | | Verification (v0.2.0+) | | | | Byte-range integrity (SHA-256) | ✅ | Recomputed and compared with CMS messageDigest attribute | | CMS signature-value verification | ✅ | RSA-SHA256 + ECDSA-SHA256 (v0.3.0) | | Certificate chain verification | ✅ | Via pdfnative verifyCertSignature | | Trust roots | ✅ | --trust <root.pem> (repeatable) + self-signed acceptance | | RFC 3161 timestamp recognition | ✅ | Reported as timestampPresent | | RFC 3161 timestamp validation (PAdES-T) | ✅ | TSA signature, messageImprint binding, chain, genTime | | OCSP revocation (RFC 6960) | ✅ | Embedded /DSS + opt-in online via AIA (SSRF-guarded) | | CRL revocation (RFC 5280) | ✅ | Embedded /DSS + opt-in online via CDP (SSRF-guarded) | | Revocation policy | ✅ | --revocation offline\|online\|disabled, --revocation-policy soft-fail\|strict | | Sign-side LTV (timestamp embedding / DSS) | ✅ | v1.4.0: sign --timestamp, ltv collect\|embed\|add, doc-timestamp (see below) | | Render iteration | | | | Smart tables | ✅ | --table-wrap, --repeat-header, --zebra, --cell-padding, --min-row-height | | Page-by-page streaming | ✅ | --stream-page-by-page (TOC- and {pages}-compatible) | | True constant-memory streaming | ✅ | --stream-true (parts freed as emitted; byte-identical output) | | Configurable block cap | ✅ | --max-blocks <n> (default 100 000) | | PDF/UA structural validation | ✅ | inspect --pdfua / --check pdfua (ISO 14289-1) — developer-time gate, not a substitute for veraPDF | | --watch re-render on file change | ✅ | 200 ms debounce, requires file --output | | --template <file.json> | ✅ | Deep-merge base under input (caller wins) | | --font bundled shortcuts | ✅ | Repeatable allow-list: latin, emoji, color-emoji, math, 27 script codes + 4 latin aliases (ha, yo, ig, sw) | | Page-tree & annotations (v1.2.0) | | | | Merge PDFs | ✅ | merge <a.pdf> <b.pdf> … (or repeatable --input) → --output | | Split PDF | ✅ | split --output-dir <dir> per-page, or --pages 1-2,3-4 per-range | | Extract pages | ✅ | extract --pages 4,1-2 (1-based; order preserved, repeats allowed) | | Drop annotations on copy | ✅ | --drop-annotations on merge / split / extract | | Output-size guard | ✅ | --max-output-size <bytes> on merge / split / extract | | Markup annotations | ✅ | annotate --annotations <spec.json> — highlight, text, square, circle, line, freetext, … | | Incremental save | ✅ | annotate preserves original bytes (existing signatures stay valid) | | Inspect annotations | ✅ | inspect --annotations lists markup + link annotations | | Page labels | ✅ | inspect reports /PageLabels when present | | Bookmarks & layout (v1.2.0) | | | | PDF bookmarks (outline) | ✅ | render --outline auto (from headings) or --outline <tree.json> | | Math / technical symbols | ✅ | render --font math (Noto Sans Math; auto-routed code points) | | Layout inspection report | ✅ | render --inspect-layout → LayoutInspection JSON (no PDF) | | Layout debug overlay | ✅ | render --debug-layout [margins,content,cells] | | Signing crypto (v1.2.0) | | | | Native constant-time crypto | ✅ | sign uses node:crypto by default (side-channel-resistant) | | Pure-JS crypto fallback | ✅ | sign --pure-crypto forces pdfnative's portable bignum path | | AI-governance / HITL (v1.2.0) | | | | Governance rules / policy | ✅ | govern rules (protocol) / govern policy (machine-readable JSON) | | Draft verification gate | ✅ | govern verify-issue <draft.md> → exit 1 / E_POLICY on violation | | Text, forms, encryption & charts (v1.3.0, pdfnative ≥ 1.6.0) | | | | Text extraction | ✅ | extract-text --format text\|json\|ndjson (reading order, --runs, --password); no OCR | | Fill AcroForms | ✅ | fill --data <values.json> (incremental save; encrypted PDFs via --password) | | Flatten AcroForms | ✅ | fill --flatten (stamp appearances, remove interactive fields) | | Export form values | ✅ | fill --export → --data-shaped JSON map (read → edit → fill round-trip) | | Encrypt / decrypt | ✅ | encrypt --owner-password … (AES-128/256) / decrypt --password … (--stream) | | Encrypted page-tree sources | ✅ | --password on merge / split / extract / inspect | | Re-encrypt page-tree output | ✅ | --encrypt [aes-128\|aes-256] on merge / split / extract | | Constant-memory streaming | ✅ | --stream (+ --chunk-size) on merge / split / extract / encrypt / decrypt | | Native vector charts | ✅ | chart document block: bar, barH, line, pie, donut (pure PDF paths, tagged /Figure) | | List form fields / encryption | ✅ | inspect --form-fields / inspect --encryption | | Unified render encryption flags | ✅ | render --encrypt [aes-128\|aes-256] --owner-password … (same vocab as merge/split/extract) | | Environment preflight | ✅ | doctor (versions, Web Crypto/CSPRNG, command count; text or --json) | | Capability manifest | ✅ | schema manifest + llms.txt for agent tool discovery | | PowerShell completion | ✅ | completion powershell | | Long-term signatures & document ops (v1.4.0, pdfnative ≥ 1.7.0) | | | | RFC 3161 signing timestamp (PAdES B-T) | ✅ | sign --timestamp <tsa-url> (+ --timestamp-digest, --timestamp-nonce); opt-in network, SSRF-guarded | | PAdES signature profile | ✅ | sign --profile pades (ETSI.CAdES.detached, ESS signing-certificate-v2) | | CMS digest selection | ✅ | sign --digest sha256\|sha384\|sha512 (RSA; ECDSA is sha256-only) | | Multiple signatures | ✅ | sign --allow-multiple + --field-name (default stays idempotent single-signature) | | Visible signature placement | ✅ | sign --signature-rect "x1,y1,x2,y2" + --signature-page (+ --placeholder-bytes) | | LTV validation data (PAdES B-LT) | ✅ | ltv collect\|embed\|add — OCSP + CRL into /DSS + /VRI; collect needs --online, embed is fully offline (air-gapped) | | Document timestamp (PAdES B-LTA) | ✅ | doc-timestamp --url <tsa> — /DocTimeStamp (ETSI.RFC3161) incremental revision, repeatable for renewal | | Verify B-LTA / sha384-512 | ✅ | verify validates /DocTimeStamp revisions as RFC 3161 tokens; accepts rsa-sha384 / rsa-sha512; reports fieldName + isDocTimestamp | | Signature inventory | ✅ | inspect --signatures (fieldName, subFilter, byteRange, isDocTimestamp, isPlaceholder — never signature bytes) + --check "signatures>=N" | | Metadata editing | ✅ | metadata --title/--author/--subject/--keywords/--mod-date or --from-json — incremental save, signatures stay valid | | PDF comparison | ✅ | compare a.pdf b.pdf --mode text\|structure\|both — exit 0 identical, exit 1 / E_CHECK_FAILED on differences; no visual diff | | Manifest pipelines | ✅ | batch --manifest tasks.json — sequential fail-fast tasks, @<id> references, --allow-network gate, --continue-on-error | | PDF/A strict gating | ✅ | render --strict — conformance diagnostics become E_CHECK_FAILED before any output byte (else stderr warnings + diagnostics[] under --json) | | Charts v2 | ✅ | 9 types (+ stackedBar, stackedBarH, area, scatter), series.xValues, yAxis: right + axis2, log scale, category/linear/time x-axis, data labels, label stride/rotation | | Print production | ✅ | layout.print (bleed, trimBox, bleedBox, artBox, cropBox, marks, userUnit 1–75000), layout.outputIntent (ICC RGB), layout.viewerPreferences (duplex, pickTrayByPDFSize, printPageRange, numCopies) | | Image blocks by path | ✅ | { "type": "image", "src": "logo.png" } (relative to the input JSON) or dataBase64 | | Encrypted annotate | ✅ | annotate --password — appended objects re-encrypted under the existing scheme | | Page-box preservation | ✅ | merge / split / extract now preserve BleedBox/TrimBox/ArtBox/UserUnit (pdfnative ≥ 1.7.0; previously dropped) | | Anti zip-bomb cap | ✅ | Global --max-inflate-size <bytes> — cap on any decompressed stream while parsing (default 100 MiB) | | Network error code | ✅ | Stable E_NETWORK — opt-in network operation failed (TSA / OCSP / CRL fetch) | | Typography, PDF/X-4, CMYK & reproducible output (v1.5.0, pdfnative ≥ 1.8.0) | | | | Typography engine | ✅ | layout.typography — widows/orphans, keepWithNext, splittable paragraphs, paragraph align: "justify", optical margins, soft hyphens (U+00AD, always honoured), punctuation spacing ("fr" / "fr-CA" preset or a rules array + unit binding), kerning, OpenType fontFeatures, exact base-14 metrics | | Typography flags | ✅ | render --split-paragraphs, --keep-headings-with-next, --kerning, --font-features <tag,…> (merged into layout.typography; flags win over --layout) | | CMYK colours | ✅ | Every colour field and flag accepts "c m y k" (0–1) or [c,m,y,k] (percent) beside hex / RGB; DeviceCMYK operators emitted | | Printer's colour bars | ✅ | layout.print.marks.colourBars: true \| { tints, size } | | PDF/X-4 output | ✅ | render --pdfx pdfx4 --output-intent-icc <cmyk.icc> [--output-intent-id <s>] [--trapped true\|false\|unknown]; coherence errors → E_INPUT, PDFX_* diagnostics → --strict / E_CHECK_FAILED; envelope carries pdfx | | PDF/X check | ✅ | inspect --pdfx (full report) and --check pdfx (exit 0/1); pdfxConformance always reported; --summary adds pdfx | | 27 Unicode scripts | ✅ | + lo (Lao), nod (Tai Tham), khb (New Tai Lue), tdd (Tai Le), cjm (Cham); ha / yo / ig / sw alias latin | | Custom fonts | ✅ | render --font-file <path.ttf>[:name] (repeatable; 32 MiB cap, magic bytes, parseFontData + validateFontData; never from JSON) | | Table variant fonts | ✅ | --variant table --font latin --lang latin embeds fonts, so table renders can claim PDF/A | | Reproducible dates | ✅ | Global --creation-date <iso8601> (or SOURCE_DATE_EPOCH) pins /CreationDate, xmp:CreateDate, {date}, trailer /ID, in UTC; envelope carries creationDate | | Layout revival | ✅ | --layout files and inline layout accept creationDate (ISO string), outputIntent.iccProfile (number[]), nested typography / outputIntent merges one level | | ISO dates in inspect | ✅ | inspect --iso-dates normalises metadata.creationDate / modDate from D:YYYY… to ISO 8601 | | Link annotations | ✅ | annotate type link (rect + url; http / https / mailto, validated) | | TSA timeout | ✅ | sign --timestamp-timeout <ms> (with --timestamp); envelope timestamp.timeoutMs | | Weak timestamp digest | ✅ | verify reports timestampDigest and notes a SHA-1 messageImprint; refused under --strict | | Global flags first | ✅ | pdfnative --json --dry-run <command> … — every global flag is accepted before the command name | | doctor capabilities | ✅ | fonts (31 modules / 27 scripts probed on disk), unicode (USE_UNICODE_VERSION), conformance (pdfa1b,pdfa2b,pdfa2u,pdfa3b,pdfx4) | | SSRF ranges | ✅ | Benchmarking 198.18.0.0/15, TEST-NET-1 192.0.2.0/24 and NAT64 64:ff9b::/96 join the blocked ranges | | Layout file cap | ✅ | --layout files share the 50 MB JSON cap; ICC profiles 16 MiB (acsp signature checked) |

Note: everything listed works today. Planned work is tracked in ROADMAP.md.

PDF/A & PDF/X status (v1.5.0)

The CLI's PDF/A outputs are validated against the veraPDF reference validator in CI (blocking), and its PDF/X-4 outputs against pdfnative's structural PDF/X validator: a corpus of 22 files produced by the CLI itself — 18 claiming PDF/A (renders across all four levels plus attachments, headers/footers, outline, watermark, a table-variant render with embedded fonts, an AcroForm, Gray and CMYK output intents, an incremental PAdES signature and a metadata update) and 4 claiming PDF/X-4 (a CMYK and a Gray print render, a signed print render and a negative canary broken by an annotation outside the page boxes) — is checked against the profile each file claims in XMP. It includes negative canaries that the validators must reject — so a validator that accepts everything fails the run instead of turning it green. The PDF/A recipe is --tagged pdfa<level> --font latin --lang latin (fonts must be embedded per ISO 19005; the sRGB OutputIntent is emitted automatically by the engine); the PDF/X-4 recipe is --pdfx pdfx4 --output-intent-icc <cmyk.icc> --font latin --lang latin --trapped false --strict. Run the same gates locally with npm run corpus:pdfa && npm run validate:pdfx && npm run validate:pdfa — without veraPDF installed the PDF/A step prints install hints and exits 0 as a skip, not a pass (npx tsx scripts/gate.ts --publish --require-all turns the skip into a failure). See CONTRIBUTING.md for details. Not a certification — validation evidence against a specific veraPDF version (1.30.2) and the engine's own PDF/X-4 validator (not a certified preflight tool).

Installation

npm install --global pdfnative-cli

Or run without installing:

npx pdfnative-cli render --input doc.json --output report.pdf

Requirements: Node.js ≥ 22 (Node 20 reached end-of-life 2026-04-30; CI runs 22/24) | Bun | Deno (node dist/cli.cjs)

Documentation

  • 📘 Quick Start (below) — Get rendering in 5 minutes
  • 🏛️ KNOWLEDGE_BASE.md — Full CLI reference, architecture, integration patterns
  • 🤖 AGENT_CONTRACT.md — The process contract for autonomous agents (envelopes, error codes, token economy)
  • 📚 samples/README.md — runnable samples organized by feature
  • 🔧 pdfnative library — Underlying PDF engine docs
  • ❓ FAQ — Common questions & troubleshooting

Quick Start

Render a PDF from JSON

# From a file
pdfnative render --input document.json --output report.pdf

# From stdin
cat document.json | pdfnative render --output report.pdf

# Streaming (large documents)
pdfnative render --input big-doc.json --output report.pdf --stream

# True constant-memory streaming (lowest peak memory; byte-identical)
pdfnative render --input big-doc.json --output report.pdf --stream-true

# PDF/A conformance (embed the bundled Latin font — ISO 19005 requires embedded
# fonts; this recipe is what the blocking veraPDF CI gate validates)
pdfnative render --input document.json --output archived.pdf \
  --tagged pdfa2b --font latin --lang latin

document.json is a DocumentParams object (pdfnative schema render prints the full shape, typography and PDF/X included):

{
  "title": "Monthly Report",
  "blocks": [
    { "type": "heading", "text": "Monthly Report", "level": 1 },
    { "type": "paragraph", "text": "Summary for April 2026." },
    { "type": "list", "style": "bullet", "items": ["Revenue: +18%", "NPS: 72"] }
  ],
  "footerText": "Confidential",
  "metadata": { "author": "Finance Team", "subject": "April 2026 Report" }
}

Typography, PDF/X-4 & reproducible output (v1.5.0)

# Typography: split long paragraphs across pages, keep headings with their body,
# kern the bundled Latin font and turn on old-style numerals
pdfnative render --input report.json --output report.pdf --font latin --lang latin \
  --split-paragraphs --keep-headings-with-next --kerning --font-features onum,smcp

# The full typography surface lives in layout.typography (JSON or --layout file):
# widows/orphans, justify, optical margins, soft hyphens, French spacing + unit binding
pdfnative render --input report.json --output report.pdf --layout typography.json

# PDF/X-4 for print: CMYK output intent, trapped flag, strict diagnostics — then re-check
pdfnative render --input brochure.json --output brochure.pdf \
  --pdfx pdfx4 --output-intent-icc press.icc --font latin --lang latin --trapped false --strict
pdfnative inspect --input brochure.pdf --check pdfx          # exit 0 when the claim holds

# Reproducible bytes: pin the creation instant (or export SOURCE_DATE_EPOCH=1767225600)
pdfnative render --input doc.json --output a.pdf --creation-date 2026-01-01T00:00:00Z
TZ=Asia/Tokyo pdfnative render --input doc.json --output b.pdf --creation-date 2026-01-01T00:00:00Z
sha256sum a.pdf b.pdf                                        # identical

Sign a PDF

# Keys from environment variables (recommended for CI/CD)
export PDFNATIVE_SIGN_KEY="$(cat private.pem)"
export PDFNATIVE_SIGN_CERT="$(cat cert.pem)"
pdfnative sign --input document.pdf --output signed.pdf

# Keys from files
pdfnative sign --input document.pdf --output signed.pdf \
  --key private.pem --cert cert.pem

Inspect a PDF

# JSON output (default)
pdfnative inspect --input report.pdf

# Human-readable
pdfnative inspect --input report.pdf --format text

# PDF/UA (ISO 14289-1) structural validation report
pdfnative inspect --input report.pdf --pdfua

# CI accessibility gate (exit 1 if not PDF/UA-structurally-valid)
pdfnative inspect --input report.pdf --check pdfua

# PDF/X-4 validation report, ISO 8601 dates (v1.5.0)
pdfnative inspect --input brochure.pdf --pdfx --iso-dates --fields pdfx.valid,metadata.creationDate

# From stdin
cat report.pdf | pdfnative inspect

Example output:

{
  "version": "1.7",
  "pageCount": 3,
  "encrypted": false,
  "pdfaConformance": "2b",
  "signatures": 1,
  "metadata": {
    "title": "Monthly Report",
    "author": "Nizoka",
    "creationDate": "D:20260427120000+00'00'"
  }
}

Merge, split & extract pages (v1.2.0)

# Concatenate several PDFs (sources as positional args or repeated --input)
pdfnative merge a.pdf b.pdf c.pdf --output combined.pdf

# Split one PDF into one file per page
pdfnative split --input report.pdf --output-dir pages/ --prefix page

# Split into ranges — one output per comma-separated segment
pdfnative split --input report.pdf --output-dir out/ --pages "1-2,3-4"

# Extract selected pages (1-based; order preserved, repeats allowed)
pdfnative extract --input report.pdf --output cover.pdf --pages "4,1-2"

Extract text, fill forms & encrypt (v1.3.0)

# Extract reading-order text as NDJSON (one object per page — ideal for RAG/agents)
pdfnative extract-text --input report.pdf --format ndjson > pages.ndjson

# Export a form's current values, edit, then fill (read → edit → fill)
pdfnative fill --input form.pdf --export > values.json
pdfnative fill --input form.pdf --data values.json --output filled.pdf
pdfnative fill --input filled.pdf --flatten --output flat.pdf

# Preflight the environment (agents: gate `encrypt` on this)
pdfnative doctor --format json

# Encrypt with AES-256, confirm the scheme, then decrypt
pdfnative encrypt --input report.pdf --output secure.pdf \
  --owner-password "$OWNER" --user-password "$USER" --algorithm aes-256
pdfnative inspect --input secure.pdf --encryption --password "$USER"
pdfnative decrypt --input secure.pdf --output plain.pdf --password "$USER"

# Render native vector charts from a document with a `chart` block
pdfnative render --input dashboard.json --output dashboard.pdf

Long-term signatures, compare & metadata (v1.4.0)

The canonical PAdES ladder — each rung is one command, network access is always an explicit opt-in (--timestamp / --online / --url), SSRF-guarded, no redirects:

# B-T  — sign with a PAdES profile and an RFC 3161 trusted timestamp
pdfnative sign --input doc.pdf --output signed.pdf \
  --profile pades --timestamp https://tsa.example.com/tsr

# B-LT — archive the OCSP/CRL validation data into /DSS + /VRI
pdfnative ltv add --input signed.pdf --output lt.pdf --online

# B-LTA — append a document timestamp covering every byte (repeat to renew)
pdfnative doc-timestamp --input lt.pdf --output lta.pdf --url https://tsa.example.com/tsr
pdfnative ltv add --input lta.pdf --output archived.pdf --online

# Air-gapped variant: collect on a connected machine, embed fully offline
pdfnative ltv collect --input signed.pdf --output ltv.json --online
pdfnative ltv embed   --input signed.pdf --data ltv.json --output lt.pdf
# Diff two PDFs by text + structure (exit 0 identical, exit 1 on differences)
pdfnative compare original.pdf revised.pdf --mode both --format json

# Update /Info + XMP metadata without breaking existing signatures (incremental save)
pdfnative metadata --input signed.pdf --output retitled.pdf \
  --title "Q3 Report (final)" --author "Finance Team"

# Verify the whole ladder — /DocTimeStamp revisions are validated as RFC 3161 tokens
pdfnative verify --input archived.pdf --strict
pdfnative inspect --input archived.pdf --signatures --check "signatures>=1"

Annotate a PDF (v1.2.0)

# Attach markup annotations from a JSON spec (incremental save — signatures stay intact)
pdfnative annotate --input report.pdf --output annotated.pdf \
  --annotations notes.json

# List them back out
pdfnative inspect --input annotated.pdf --annotations --format text

notes.json is a JSON array (or { "annotations": [...] }), each entry a markup or link annotation plus a 1-based page:

{
  "annotations": [
    { "page": 1, "type": "highlight", "rect": [72, 700, 320, 715], "color": "#FFD400", "contents": "Check this figure." },
    { "page": 1, "type": "text", "rect": [330, 700, 350, 720], "icon": "Comment", "contents": "Needs a citation." },
    { "page": 1, "type": "link", "rect": [72, 640, 300, 655], "url": "https://pdfnative.dev" }
  ]
}

Render bookmarks & introspect layout (v1.2.0)

# Add a bookmark tree derived from the document's headings
pdfnative render --input doc.json --output book.pdf --outline auto

# …or supply an explicit OutlineItem[] tree
pdfnative render --input doc.json --output book.pdf --outline outline.json

# Register the bundled math font so ∑ ∫ √ π render as real glyphs
pdfnative render --input math.json --output math.pdf --font latin --font math

# Emit a LayoutInspection JSON report instead of a PDF
pdfnative render --input doc.json --output layout.json --inspect-layout

# Render a PDF with debug guides overlaid
pdfnative render --input doc.json --output debug.pdf --debug-layout margins,content,cells

AI-governance / Human-in-the-Loop (v1.2.0)

Agents act as draftsmen: they may draft an issue/PR locally, but a human must review and submit it. Nothing here touches the network.

# Print the human/agent protocol and the machine-readable policy
pdfnative govern rules
pdfnative govern policy --pretty

# Gate a locally-authored draft (exit 1 / E_POLICY on a violation)
pdfnative govern verify-issue ./draft.md

Examples

Ready-to-run examples are in samples/, organized by feature category:

| Category | Examples | Description | |----------|----------|-------------| | render/document/ | 6 files | Minimal, report, all-blocks reference, invoice, technical spec, --max-blocks guard | | render/table/ | 2 files | Project status, financial summary | | render/table-smart/, table-variant/ | 1 + 1 files | Smart-table flags; --variant table (PdfParams, fonts embedded since v1.5.0) | | render/barcode/ | 3 files | QR code, Code 128 shipping label, EAN-13 product | | render/form/ | 2 files | Contact form, survey | | render/toc/ | 1 file | Document with auto-generated table of contents | | render/link/ | 1 file | Resource directory with hyperlinks | | render/watermark/ | 3 files | Draft watermark, confidential watermark, CLI-flag styling | | render/layout/ | 3 files | US Letter, A5 portrait, A4 landscape | | render/headers-footers/, template/ | 1 + 2 files | Page-number placeholders; --template deep-merge | | render/pdfa/, attachments/ | 5 + 1 files | PDF/A-1b, PDF/A-2b, PDF/A-2u, PDF/A-3b archival conformance; (v1.5.0) an AcroForm under PDF/A-2b; PDF/A-3b XML attachment | | render/encryption/ | 2 files | AES-128 / AES-256 protected renders | | render/outline/ | 2 files | PDF bookmarks — --outline auto + explicit tree | | render/math/ | 1 file | Math/technical symbols via --font math | | render/inspect-layout/ | scripts | --inspect-layout report + --debug-layout guides | | render/font/ | 5 files | Bundled font presets: Latin, the 1.3.0 scripts, emoji, (v1.5.0) the five 1.8.0 scripts, --font-file, colour-emoji skin tones / ZWJ sequences / flags | | render/multilang/ | 11 files | Thai, Japanese, multilingual drivers, (v1.5.0) Lao, Tai Tham / New Tai Lue / Tai Le / Cham, Hausa / Yoruba / Igbo / Swahili, and four families (European & Caucasian, right-to-left, Indic, Chinese & Korean) — every one of the 27 script codes is rendered by the corpus | | render/chart/ | 5 files | Native vector charts — bar/line/pie/donut plus (v1.4.0) stacked bars, area/scatter, dual axes, log & time axes | | render/print/ | 7 files | Print production — bleed/trim boxes + printer's marks, viewer preferences, (v1.5.0) CMYK colours, colour bars, PDF/X-4 with a synthetic CMYK profile | | render/typography/ | 7 files | (v1.5.0) Paragraph breaking, justify + optical margins + soft hyphens, French (fr, fr-CA) and custom punctuation spacing, unit binding, kerning + OpenType features, per-block keepWithNext / splittable | | render/base14/ | 1 file | (v1.5.0) layout.typography.metrics: "exact" on the base-14 path — rendered with no --font flag, the only place the option acts | | render/reproducible/ | 2 files | (v1.5.0) --creation-date / SOURCE_DATE_EPOCH — the double-render script proves byte identity across timezones | | render/watch/ | scripts | --watch re-render on change | | merge/ | scripts | Concatenate PDFs (page-tree) | | split/ | scripts | Split one PDF per-page or per-range | | extract/ | scripts | Pull selected pages into a new PDF | | extract-text/ | scripts | Reading-order text (text / json / ndjson) | | fill/ | scripts | Fill, flatten & export AcroForms | | encrypt/ | scripts | Encrypt / decrypt round-trip (AES-256, --stream) | | doctor/ | 2 pairs | Environment / capability preflight; (v1.5.0) fonts, Unicode and conformance targets | | metadata/ | scripts | Update /Info + XMP metadata (incremental save) | | compare/ | scripts | Diff two PDFs by text + structure | | annotate/ | 2 pairs | Attach markup annotations (incremental save); (v1.5.0) link annotations | | govern/ | scripts | AI-governance / HITL: rules, policy, verify-issue | | sign/ | 10 pairs | Digital signature incl. timestamp (B-T), LTV ladder, multi-signatures, native vs pure-JS crypto, (v1.5.0) --timestamp-timeout (Bash + PowerShell) | | verify/ | 7 pairs | Signature verification: trust roots, revocation, strict mode, (v1.5.0) weak-digest note | | inspect/ | 10 pairs | JSON & text inspection incl. --annotations, --signatures, (v1.5.0) --check pdfx and --iso-dates (Bash + PowerShell) | | batch/ | 3 pairs | Directory render and --manifest pipelines | | agent/ | 5 pairs | --json + --dry-run, schema, the error envelope, token economy, (v1.5.0) global flags before the command | | completion/, config/ | 1 + 1 pairs | Shell completions; .pdfnativerc.json defaults | | streaming/ | 2 pairs | Streaming render (single-pass, page-by-page, true constant-memory) |

Render every sample at once (the same run the CI baseline uses):

npm run build && npm run test:generate     # → test-output/samples/ (91 sample PDFs, byte-stable)
npx tsx scripts/verify-samples.ts          # compare with tests/regression/baselines/samples.sha256.json

PDFNATIVE_CLI=$(which pdfnative) npm run test:generate drives a globally installed binary instead.

See samples/README.md for full descriptions, block type reference, and integration patterns (GitHub Actions, Docker, TypeScript).


Command Reference

The 21 commands are grouped by purpose (the global pdfnative --help shows the same grouping):

| Group | Commands | |-------|----------| | Create & edit | render, fill, annotate, metadata | | Page tree | merge, split, extract | | Security | sign, verify, ltv, doc-timestamp, encrypt, decrypt | | Read & extract | inspect, extract-text, compare | | Automation & meta | batch, doctor, schema, completion, govern |

pdfnative render

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Path to a JSON file (DocumentParams or PdfParams if --variant table) | | --output <file> | stdout | Output PDF path | | --stream | false | Single-pass streaming output (AsyncGenerator); no TOC, no {pages} | | --stream-page-by-page | false | Stream at PDF object boundaries (TOC- and {pages}-compatible) | | --stream-true | false | True constant-memory streaming; parts freed as emitted; byte-identical; no TOC, no {pages} | | --chunk-size <bytes> | 65536 | Chunk size for --stream / --stream-true (not --stream-page-by-page) | | --variant <kind> | document | document (default) or table (selects buildPDFBytes) | | --layout <file.json> | — | Load a Partial<PdfLayoutOptions> (CLI flags override) | | --page-size <size> | from layout file or pdfnative default | Named (a4, letter, legal, a3, tabloid, a5) or WxH in points | | --margin <N> or --margin <t,r,b,l> | from layout / default | Page margins in points | | --compress | false | Enable FlateDecode compression | | --max-blocks <n> | 100000 | Maximum document blocks before pdfnative aborts (large-report guard) | | --tagged <level> | none | PDF/A: none, pdfa1b, pdfa2b, pdfa2u, pdfa3b (mutually exclusive with --pdfx) | | --pdfx <target> | none | (v1.5.0) PDF/X: pdfx4 (ISO 15930-7). Requires a CMYK ICC output intent (--output-intent-icc or layout.outputIntent), refuses encryption and PDF/A in the same file (E_INPUT / exit 2); the --json envelope carries pdfx | | --output-intent-icc <file.icc> | — | (v1.5.0) ICC profile for layout.outputIntent.iccProfile (16 MiB cap, acsp signature checked; prtr CMYK required for PDF/X) | | --output-intent-id <s> | ICC file basename | (v1.5.0) outputIntent.outputConditionIdentifier | | --trapped true\|false\|unknown | — | (v1.5.0) /Trapped + pdf:Trapped (PDF/X-4 requires true or false) | | --strict | false | Escalate the 9 diagnostic codes — PDF/A (PDFA_NO_FONT_ENTRIES, PDFA_UNEMBEDDED_FORM_FONT, PDFA_DEVICE_CMYK_IMAGE, PDFA_*), PDF/X (PDFX_NO_FONT_ENTRIES, PDFX_DEVICE_CMYK, PDFX_ANNOTATIONS) and TYPOGRAPHY_FEATURE_INEFFECTIVE — into an error (exit 1, E_CHECK_FAILED) before any output byte; without it they are stderr warnings + a diagnostics[] array in the --json envelope | | --split-paragraphs | false | (v1.5.0) layout.typography.splitParagraphs — long paragraphs may break across pages (widow/orphan rules apply) | | --keep-headings-with-next | false | (v1.5.0) layout.typography.keepHeadingsWithNext — a heading never ends a page alone | | --kerning | false | (v1.5.0) layout.typography.kerning — GPOS pair kerning for embedded fonts | | --font-features <tag,…> | — | (v1.5.0) layout.typography.fontFeatures — OpenType feature tags (onum, smcp, tnum, …; ligature features are not applied by the engine; four alphanumerics each) | | --conformance <1b\|2b\|3b> | — | Deprecated — use --tagged pdfa<level> | | --watermark-text <s> / --watermark-image <path> | — | Text or image watermark | | --watermark-opacity <0-1> / --watermark-angle <deg> / --watermark-color <#hex> / --watermark-font-size <pt> / --watermark-position background\|foreground | — | Watermark styling | | --watermark-position background\|foreground | background | Render order | | --header-{left,center,right} <tpl> | — | Header template; placeholders {page}, {pages}, {date}, {title} | | --footer-{left,center,right} <tpl> | — | Footer template; same placeholders | | --encrypt [aes-128\|aes-256] | — | Enable encryption (bare = aes-128). Same vocabulary as merge/split/extract | | --owner-password <s> | $PDFNATIVE_ENCRYPT_OWNER_PASS | Owner password (required to encrypt) | | --user-password <s> | $PDFNATIVE_ENCRYPT_USER_PASS | Optional user (open) password | | --permissions <list> | all denied | Comma list: print,copy,modify,extract | | (legacy aliases) | — | --encrypt-algorithm, --encrypt-owner-pass, --encrypt-user-pass, --encrypt-permissions still work | | --attachment <path>[:mime[:rel[:desc]]] (repeatable) | — | PDF/A-3 file attachment | | --lang <code,code> | — | Activate registered font loaders for non-Latin scripts (th, ja, ar, te, si, km, lo, …); Latin is built-in. Aliases ha, yo, ig, sw resolve to latin | | --font <name> (repeatable) | — | Register a bundled font shortcut. Allow-list: latin, emoji, color-emoji, math, and the 27 script codes ar hy bn ru hi am ka el he ja km ko my pl zh si ta te th bo tr vi + (v1.5.0) lo nod khb tdd cjm; ha yo ig sw alias latin. The name doubles as the --lang code. --variant table embeds them too | | --font-file <path.ttf>[:name] (repeatable) | — | (v1.5.0) Register a custom TrueType/OpenType font from disk (name defaults to the file stem, [a-z0-9-]; added to --lang). 32 MiB cap, magic bytes (00 01 00 00 / true / OTTO — collections and WOFF refused), parsed and validated by pdfnative before use; a name colliding with the allow-list is a usage error. Never loadable from a JSON payload | | --outline auto\|<file.json> | — | Add a PDF bookmark tree: auto derives it from headings; a path loads an explicit OutlineItem[] tree | | --inspect-layout | false | Emit a LayoutInspection JSON report instead of a PDF (document variant only) | | --debug-layout [margins,content,cells] | — | Overlay layout debug guides on the rendered PDF (bare flag = all) |

Document & layout JSON (v1.5.0, pdfnative ≥ 1.8.0) — layout.typography (widows, orphans, splitParagraphs, keepHeadingsWithNext: true | { minLines }, opticalMargins, punctuationSpacing: "fr" | "fr-CA" | [{ char, side, space }], unitBinding, bindShortWords, hyphenationLanguage, kerning, fontFeatures: [tag, …], metrics: "exact" — base-14 path only, inert once --font registers a font; soft hyphens U+00AD are honoured unconditionally), paragraph align: "justify", block-level keepWithNext / splittable; every colour accepts CMYK ("c m y k" 0–1 or [c,m,y,k] percent) beside hex / RGB; layout.print.marks.colourBars: true | { tints, size }; layout.pdfx: "pdfx4" with a prtr CMYK layout.outputIntent (iccProfile as a number array in JSON); layout.creationDate (ISO string) — flags win over the file, nested typography / outputIntent objects merge one level deep. --strict also covers the TYPOGRAPHY_FEATURE_INEFFECTIVE diagnostic (a requested feature the font cannot honour).

Document & layout JSON (v1.4.0, pdfnative ≥ 1.7.0) — no new flags, richer JSON: image blocks accept src (a path resolved relative to the --input JSON's directory) as an alternative to dataBase64; chart blocks grow to 9 types (bar, barH, stackedBar, stackedBarH, line, area, scatter, pie, donut) with series[].xValues, series[].yAxis: "right" + axis2, axis.scale: "log", xAxis: category|linear|time, dataLabels, labelStride, and labelRotation; the --layout file gains print (bleed, trimBox, bleedBox, artBox, cropBox, printer marks, userUnit 1–75000), outputIntent (ICC RGB) and viewerPreferences (duplex, pickTrayByPDFSize, printPageRange, numCopies); params.metadata accepts author/subject/keywords/trapped. Validate with pdfnative schema render.

See samples/render/ for a working example of every category.

pdfnative sign

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Path to the input PDF | | --output <file> | stdout | Output signed PDF path | | --key <file> | $PDFNATIVE_SIGN_KEY | Path to PEM private key (env var takes precedence) | | --cert <file> | $PDFNATIVE_SIGN_CERT | Path to PEM certificate (env var takes precedence) | | --cert-chain <file> (repeatable) | $PDFNATIVE_SIGN_CHAIN | Intermediate CA PEMs | | --algorithm rsa-sha256\|ecdsa-sha256 | rsa-sha256 | Signature algorithm (RSA or P-256 ECDSA) | | --digest sha256\|sha384\|sha512 | sha256 | CMS digest algorithm (RSA only; ecdsa-sha256 is sha256-only) | | --profile pkcs7\|pades | pkcs7 | pades = ETSI.CAdES.detached (PAdES B-B: ESS signing-certificate-v2, omits signing-time) | | --reason <s> | — | Reason for signing (PDF metadata) | | --name <s> | — | Signer name (PDF metadata) | | --location <s> | — | Signing location (PDF metadata) | | --contact <s> | — | Signer contact (PDF metadata) | | --signing-time <ISO 8601> | now | Explicit signing timestamp | | --timestamp <tsa-url> | — | Embed a verified RFC 3161 timestamp token at signing time (PAdES B-T with --profile pades). Opt-in network, SSRF-guarded. TSA failure → E_NETWORK; malformed response → E_PARSE; never a silent fallback | | --timestamp-digest sha256\|sha384\|sha512 | sha256 | Digest for the TSA message imprint | | --timestamp-nonce <hex> | random 8 bytes | Explicit TSA request nonce | | --timestamp-timeout <ms> | 10000 | (v1.5.0) Timeout for the TSA round-trip (positive integer; usage error without --timestamp); reported as timestamp.timeoutMs | | --allow-multiple | false | Allow signing an already-signed PDF (appends a signature field); default stays idempotent single-signature (1.x behaviour) | | --field-name <name> | auto | Signature form-field name | | --signature-rect "x1,y1,x2,y2" | invisible | Visible signature widget rectangle (PDF points) | | --signature-page <n> | 1 | 1-based page for the signature widget | | --placeholder-bytes <n> | auto | Explicit /Contents placeholder size (overrides the estimate) | | --pure-crypto | false | Force pdfnative's pure-JS RSA/ECDSA math instead of the default native node:crypto (constant-time) provider |

Without --timestamp the command performs no network I/O, and --dry-run never touches the network even when --timestamp is present. Under --json, a timestamped signature adds timestamp: { url, digest, timeoutMs? } to the success envelope. --signing-time is a deliberate legal instant and is not pinned by the global --creation-date.

pdfnative inspect

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Path to the PDF to inspect | | --output <file> | stdout | Output report path | | --format json\|text | json | Output format | | --verbose | false | Add trailer keys, catalog keys, object count, XMP | | --pages | false | Add per-page metadata array (width/height/rotation + cropBox/trimBox/bleedBox/artBox/userUnit when present) | | --annotations | false | List markup + link annotations per page (page labels are reported automatically when present) | | --form-fields | false | List AcroForm fields (name, type, value, required/read-only, options) | | --encryption | false | Report the encryption scheme (algorithm, revision, authenticatedAs), or null | | --signatures | false | Signature-field inventory: fieldName, subFilter, byteRange, isDocTimestamp, isPlaceholder, sigObjNum, contentsLength — never the signature bytes | | --password <s> | — | Password for an encrypted PDF (env: PDFNATIVE_PASSWORD) | | --pdfua | false | Add a PDF/UA (ISO 14289-1) structural validation report (valid + errors + warnings) | | --pdfx | false | (v1.5.0) Add a PDF/X-4 validation report (pdfx: { valid, target, errors, warnings }, pdfnative's validatePdfX); pdfxConformance (XMP GTS_PDFXVersion) is always reported | | --iso-dates | false | (v1.5.0) Normalise metadata.creationDate / modDate from D:YYYYMMDD… to ISO 8601 (unparsable strings are left as is) | | --check pdfa\|signed\|encrypted\|pdfua\|pdfx\|"signatures>=N" (repeatable) | — | CI-friendly assertion; AND semantics; sets exit code (0 = pass, 1 = fail). signatures>=N counts real signatures (placeholders and /DocTimeStamp fields excluded); pdfx requires a PDF/X-4 claim that validates |

v1.4.0 also fixes the top-level signatures and formFields counters, which previously always reported 0, and reports metadata.trapped when present. --summary returns { pages, encrypted, signatures, pdfa, pdfx }.

pdfnative verify

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Path to the (possibly signed) PDF | | --format json\|text | json | Output format | | --strict | false | Exit 1 on any failure or zero signatures (CI-friendly) | | --trust <root.pem> (repeatable) | self-signed only | Trusted root certificates (PEM) | | --revocation offline\|online\|disabled | offline | Revocation source: embedded /DSS only, also fetch online (SSRF-guarded), or skip | | --revocation-policy soft-fail\|strict | soft-fail | strict fails the signature on any non-good status; soft-fail only fails on explicit revoked |

Scope: byte-range integrity (SHA-256), full CMS signature value (RSA-PKCS#1 v1.5 — SHA-256/384/512, reported as rsa-sha256/rsa-sha384/rsa-sha512 — plus ECDSA-SHA256 over P-256), certificate chain + trust, RFC 3161 timestamp validation (PAdES-T), and OCSP (RFC 6960) + CRL (RFC 5280) revocation — embedded from the PDF /DSS offline by default, with opt-in online fetching through an SSRF-guarded HTTP client. v1.4.0 additions: each signature also reports its fieldName and isDocTimestamp, and /DocTimeStamp revisions (PAdES B-LTA) are validated as RFC 3161 timestamp tokens. v1.5.0: each timestamp reports its messageImprint algorithm as timestampDigest; a SHA-1 imprint adds the note weak digest: RFC 3161 messageImprint uses SHA-1 (refused under --strict) and, under --strict, fails the timestamp (E_VERIFY_FAILED). Sign-side LTV lives in sign --timestamp, ltv and doc-timestamp.

pdfnative ltv

PAdES B-LT: archive the certificates, OCSP responses and CRLs needed to validate the document's signatures long after certificates expire, into the PDF's /DSS + /VRI dictionaries (incremental save — existing signatures stay valid).

pdfnative ltv collect --input signed.pdf --online [--output ltv.json]  # fetch → replayable JSON
pdfnative ltv embed   --input signed.pdf --data ltv.json [--output out.pdf]  # 100 % offline
pdfnative ltv add     --input signed.pdf --online [--output out.pdf]   # collect + embed

collect requires --online (explicit network opt-in, SSRF-guarded, no redirects) and emits a replayable JSON file (schema subject: ltv-data). embed never performs network I/O — the collect/embed split supports air-gapped pipelines: collect on a connected machine, embed offline. add does both in one pass.

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Signed source PDF | | --output <file> | stdout | Output: JSON (collect) or PDF (embed / add) | | --online | — (required for collect / add) | Explicit opt-in for network fetches (SSRF-guarded, no redirects) | | --prefer ocsp\|crl | ocsp | Preferred revocation source | | --extra-cert <pem> (repeatable) | — | Extra chain certificates (PEM) | | --data <file> | — (required for embed) | Previously collected ltv-data JSON | | --timeout <ms> | 10000 | Network timeout | | --dry-run | false | Validate inputs; no output, no network |

The canonical PAdES ladder:

sign --timestamp <tsa> --profile pades   →  B-T
ltv add --online                         →  B-LT
doc-timestamp --url <tsa>                →  B-LTA
ltv add --online                         →  LTV for the doc-timestamp itself

pdfnative doc-timestamp

PAdES B-LTA: append a /DocTimeStamp signature field (SubFilter /ETSI.RFC3161, ISO 32000-2 §12.8.5) covering every byte of the document, as an incremental revision — earlier revisions stay byte-identical. Repeat periodically to renew LTA protection.

| Flag | Default | Description | |------|---------|-------------| | --input <file> | stdin | Signed source PDF | | --output <file> | stdout | Output PDF | | --url <tsa-url> | — (required) | RFC 3161 TSA URL (explicit network opt-in; SSRF-guarded, no redirects) | | --digest sha256\|sha384\|sha512 | sha256 | Timestamp message-imprint digest | | --field-name <name> | DocTimeStamp1 | Timestamp field name (auto-suffixed on collision) | | --placeholder-bytes <n> | 12288 | /Contents placeholder size | | --nonce <hex> | random | Explicit TSA request nonce | | --timeout <ms> | 10000 | Network timeout | | --dry-run | false | Validate inputs; no output, no network |

TSA failures map to E_NETWORK; a malformed TSA response maps to E_PARSE. verify validates /DocTimeStamp revisions as RFC 3161 tokens (isDocTimestamp: true).

pdfnative batch

Two modes: directory mode (render every *.json in a direct