Skip to main content

Fast, code-first PDF generation from structured data. No browser, no Chromium.

Project description

TrustRender

Structured business PDFs from code. Pre-render validated. No browser. No Chromium.

Website: trustrender.dev PyPI: pypi.org/project/trustrender

Why TrustRender

  • Pre-render validation — catches bad payloads before they reach the renderer
  • Compliance support — EN 16931 / ZUGFeRD for the supported e-invoice path
  • Provenance and hashing — records template, data, and output fingerprints for traceability
  • Operationally lean — no browser or Chromium dependency

TrustRender renders invoices, statements, receipts, and similar structured documents using Typst as the layout engine and Jinja2 for data binding. It ships as a Python library, CLI, and HTTP server.

Non-goals

TrustRender is not:

  • arbitrary HTML-to-PDF conversion
  • a browser or headless renderer
  • a visual or WYSIWYG editor
  • a multi-format converter

It does one thing: structured business PDFs from code.

Install

pip install trustrender

Requires Python 3.11+ and the Typst CLI binary (brew install typst on macOS, or typst.app).

For e-invoice support: pip install "trustrender[zugferd]"

Development

git clone https://github.com/verityengine/trustrender.git
cd trustrender
pip install -e ".[dev]"

Verify

trustrender doctor --smoke

Checks Python version, backends, fonts, and runs a real render + server health check.

Security

trustrender serve has no built-in authentication, authorization, TLS, or rate limiting. It is designed to run as a backend service behind a reverse proxy. Do not expose the server port to the public internet.

If you deploy TrustRender as an HTTP server:

  • Place it behind a reverse proxy (Nginx, Caddy, Traefik, cloud load balancer) that handles TLS termination and authentication.
  • The /render endpoint accepts template source code via the template_source field. Without authentication, any client that can reach the server can submit arbitrary templates for rendering.
  • The /template-source endpoint returns raw template file contents. Restrict access if templates contain business logic you consider sensitive.
  • Backpressure (503 when at concurrency limit) is the only built-in traffic control. It is not a substitute for rate limiting.
  • The server binds to 127.0.0.1 by default. Passing --host 0.0.0.0 opens it to all interfaces — do this only behind a proxy.

TrustRender is a rendering engine, not a security boundary. Treat it like a database: powerful, essential, and never internet-facing without a gateway.

Quick start

pip install trustrender && trustrender quickstart

Creates a sample invoice template, starts the server, and opens the app in your browser. Render your first PDF in under 30 seconds.

Python:

from trustrender import render

pdf = render("invoice.j2.typ", "invoice_data.json", output="invoice.pdf")

CLI:

trustrender render invoice.j2.typ invoice_data.json -o invoice.pdf

Server:

trustrender serve --templates . --dashboard --port 8190

Why TrustRender

Validated before render

Every render() call on a .j2.typ template validates data against the template's inferred contract by default. Missing fields, null values, and wrong structural types are rejected with specific field-level errors before Typst compilation starts.

TrustRenderError: Data validation failed: 11 field errors in invoice.j2.typ
  sender: missing required field (expected: object)
  items: missing required field (expected: list[object])
  invoice_date: missing required field

preflight() goes further: structural validation, semantic checks, font verification, compliance eligibility, and text safety scanning — all without rendering.

No browser dependency

No Chromium, no Puppeteer, no headless browser. Typst compiles directly to PDF. The server runs renders as killable subprocesses with real timeout enforcement.

Measured on Apple Silicon (macOS, Python 3.12, Typst 0.14): 1,000-row invoice renders in 211ms (33 pages). Server throughput: 53.8 RPS. Peak RSS: 69.5 MB.

EN 16931 e-invoicing (narrow scope)

Supports a narrow subset of EN 16931 e-invoicing: domestic German B2B invoices with standard VAT, in EUR, via SEPA payment only. Reverse charge, cross-border, allowances/discounts, and non-EUR currencies are not supported. This is not full German e-invoicing mandate coverage. PDF/A-3b output with embedded CII XML. When the optional facturx library is installed (pip install "trustrender[zugferd]"), XSD and Schematron validation run before embedding; without it, field-level and arithmetic consistency validation still run but schema validation is skipped.

trustrender render einvoice.j2.typ data.json -o invoice.pdf --zugferd en16931

Supported: DE, EUR, standard VAT (single or mixed rates), invoices and credit notes. Not supported (fails loudly): reverse charge, cross-border, allowances/charges, non-EUR, zero/negative tax rates.

See docs/einvoice-scope.md for the full scope matrix.

Output provenance

Embeds a cryptographic generation proof in the PDF: template hash, data hash, engine version, timestamp, and a combined proof hash. Verifiable without re-rendering.

from trustrender.provenance import verify_provenance
result = verify_provenance(pdf_bytes, "invoice.j2.typ", original_data)
# result.verified → True if hashes match

Not a digital signature. A generation proof: "was this document produced from this data using this template?"

CLI

trustrender render <template> <data.json> -o <output.pdf> [--zugferd en16931] [--provenance] [--no-validate]
trustrender preflight <template> <data.json> [--semantic] [--strict]
trustrender check <template> [--data <data.json>]
trustrender serve --templates <dir> [--port 8190] [--dashboard] [--history <path>]
trustrender audit <template> <data.json> -o <output.pdf> [--baseline-dir <dir>]
trustrender doctor [--smoke]

Full flag reference: trustrender <command> --help.

HTTP server

Method Path Purpose
POST /render Render template to PDF
POST /preflight Pre-render readiness check
GET /health Health check
GET /template-source?name= Raw template source
GET /history Render trace list (requires --history)
GET /dashboard Ops dashboard (requires --dashboard)

Backpressure: max 8 concurrent renders (configurable), 503 when at capacity. Max body: 10 MB (configurable). Timeout: 30s (subprocess killed on expiry).

See docs/server.md for full API detail, error model, and configuration.

Bundled templates

Template File Description
Invoice examples/invoice.j2.typ Standard invoice with line items
E-Invoice examples/einvoice.j2.typ ZUGFeRD EN 16931 compliant
Statement examples/statement.j2.typ Account/transaction statement
Receipt examples/receipt.j2.typ Point-of-sale receipt
Letter examples/letter.j2.typ Business letter
Report examples/report.j2.typ Executive report with metrics

Each has a matching _data.json file in examples/.

Docker

docker build -t trustrender .
docker run -p 8190:8190 trustrender

Mount custom templates or fonts:

docker run -p 8190:8190 \
  -v /path/to/templates:/templates -e TRUSTRENDER_TEMPLATES_DIR=/templates \
  -v /path/to/fonts:/fonts -e TRUSTRENDER_FONT_PATH=/fonts \
  trustrender

Configuration

Variable Purpose Default
TRUSTRENDER_BACKEND typst-py or typst-cli Auto-detect
TRUSTRENDER_FONT_PATH Font directory Bundled Inter fonts
TRUSTRENDER_TEMPLATES_DIR Template directory for serve
TRUSTRENDER_MAX_BODY_SIZE Max request body (bytes) 10 MB

Development

make dev                    # editable install + dev deps
trustrender doctor --smoke  # verify environment
make test                   # pytest
make lint                   # ruff
make docker                 # build image
make help                   # all targets

854 tests (unit, integration, contract, semantic, ZUGFeRD, provenance, ugly-data, font, pagination, text safety, Schematron).

Documentation

Topic Link
Validation & readiness docs/validation.md
E-invoice scope matrix docs/einvoice-scope.md
HTTP server & error model docs/server.md
Templates & escaping docs/templates.md
Fonts docs/fonts.md
Provenance docs/provenance.md
Known limits docs/known-limits.md

Caveats

  • Typst silently substitutes fonts when a declared font is missing — preflight and doctor catch this for configured font paths, but the render path itself does not error
  • Source mapping from generated Typst back to Jinja2 source is limited
  • typst_markup() intentionally bypasses escaping — template author's responsibility
  • Code/math mode contexts are not auto-escaped (text-interpolation only)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trustrender-0.1.9.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

trustrender-0.1.9-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file trustrender-0.1.9.tar.gz.

File metadata

  • Download URL: trustrender-0.1.9.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trustrender-0.1.9.tar.gz
Algorithm Hash digest
SHA256 87bc6772ba0817e80679d980d38edb28faf153037c277a2d04b0b792cae6f6a3
MD5 da994d14b539169ee56c33706a4b56f4
BLAKE2b-256 abd45af4392f49b9ecf3cdaa19190b7264f479c4a9ea3f772b9039a6f4b7b7e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for trustrender-0.1.9.tar.gz:

Publisher: publish.yml on verityengine/trustrender

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file trustrender-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: trustrender-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for trustrender-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 f46b50dcf4c48d16b4a835338a3d69b503b973659dc3b7a66df3b122d82b7c1f
MD5 1b698ecdb791129b1a5213f5c48ed06d
BLAKE2b-256 ee95c15a33a1d80286a30a8743c553f2f117f03584bf21fcc9efdd326b008944

See more details on using hashes here.

Provenance

The following attestation bundles were made for trustrender-0.1.9-py3-none-any.whl:

Publisher: publish.yml on verityengine/trustrender

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page