trustrender 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. trustrender-0.1.0/LICENSE +21 -0
  2. trustrender-0.1.0/PKG-INFO +262 -0
  3. trustrender-0.1.0/README.md +227 -0
  4. trustrender-0.1.0/pyproject.toml +63 -0
  5. trustrender-0.1.0/setup.cfg +4 -0
  6. trustrender-0.1.0/src/trustrender/__init__.py +607 -0
  7. trustrender-0.1.0/src/trustrender/cli.py +783 -0
  8. trustrender-0.1.0/src/trustrender/contract.py +767 -0
  9. trustrender-0.1.0/src/trustrender/dashboard.py +371 -0
  10. trustrender-0.1.0/src/trustrender/doctor.py +363 -0
  11. trustrender-0.1.0/src/trustrender/engine.py +364 -0
  12. trustrender-0.1.0/src/trustrender/errors.py +112 -0
  13. trustrender-0.1.0/src/trustrender/filters.py +57 -0
  14. trustrender-0.1.0/src/trustrender/fingerprint.py +700 -0
  15. trustrender-0.1.0/src/trustrender/fonts/Inter/Inter-Bold.ttf +0 -0
  16. trustrender-0.1.0/src/trustrender/fonts/Inter/Inter-BoldItalic.ttf +0 -0
  17. trustrender-0.1.0/src/trustrender/fonts/Inter/Inter-Italic.ttf +0 -0
  18. trustrender-0.1.0/src/trustrender/fonts/Inter/Inter-Regular.ttf +0 -0
  19. trustrender-0.1.0/src/trustrender/fonts/Inter/LICENSE.txt +92 -0
  20. trustrender-0.1.0/src/trustrender/playground/assets/index-NINB-pNr.js +31 -0
  21. trustrender-0.1.0/src/trustrender/playground/assets/index-V6TpJlAv.css +2 -0
  22. trustrender-0.1.0/src/trustrender/playground/assets/pdf.worker-C1breYqn.mjs +56901 -0
  23. trustrender-0.1.0/src/trustrender/playground/favicon.svg +14 -0
  24. trustrender-0.1.0/src/trustrender/playground/icons.svg +24 -0
  25. trustrender-0.1.0/src/trustrender/playground/index.html +17 -0
  26. trustrender-0.1.0/src/trustrender/provenance.py +257 -0
  27. trustrender-0.1.0/src/trustrender/readiness.py +659 -0
  28. trustrender-0.1.0/src/trustrender/regression.py +580 -0
  29. trustrender-0.1.0/src/trustrender/semantic.py +688 -0
  30. trustrender-0.1.0/src/trustrender/server.py +577 -0
  31. trustrender-0.1.0/src/trustrender/templates.py +149 -0
  32. trustrender-0.1.0/src/trustrender/trace.py +321 -0
  33. trustrender-0.1.0/src/trustrender/zugferd.py +565 -0
  34. trustrender-0.1.0/src/trustrender.egg-info/PKG-INFO +262 -0
  35. trustrender-0.1.0/src/trustrender.egg-info/SOURCES.txt +62 -0
  36. trustrender-0.1.0/src/trustrender.egg-info/dependency_links.txt +1 -0
  37. trustrender-0.1.0/src/trustrender.egg-info/entry_points.txt +2 -0
  38. trustrender-0.1.0/src/trustrender.egg-info/requires.txt +15 -0
  39. trustrender-0.1.0/src/trustrender.egg-info/top_level.txt +1 -0
  40. trustrender-0.1.0/tests/test_audit_e2e.py +399 -0
  41. trustrender-0.1.0/tests/test_cli.py +104 -0
  42. trustrender-0.1.0/tests/test_contract.py +585 -0
  43. trustrender-0.1.0/tests/test_doctor.py +273 -0
  44. trustrender-0.1.0/tests/test_engine.py +351 -0
  45. trustrender-0.1.0/tests/test_error_pipeline.py +447 -0
  46. trustrender-0.1.0/tests/test_errors.py +98 -0
  47. trustrender-0.1.0/tests/test_filters.py +93 -0
  48. trustrender-0.1.0/tests/test_fingerprint.py +192 -0
  49. trustrender-0.1.0/tests/test_fingerprint_stress.py +383 -0
  50. trustrender-0.1.0/tests/test_fonts.py +327 -0
  51. trustrender-0.1.0/tests/test_pagination.py +246 -0
  52. trustrender-0.1.0/tests/test_provenance.py +166 -0
  53. trustrender-0.1.0/tests/test_readiness.py +364 -0
  54. trustrender-0.1.0/tests/test_regression.py +310 -0
  55. trustrender-0.1.0/tests/test_regression_stress.py +429 -0
  56. trustrender-0.1.0/tests/test_render.py +109 -0
  57. trustrender-0.1.0/tests/test_semantic.py +838 -0
  58. trustrender-0.1.0/tests/test_semantic_stress.py +461 -0
  59. trustrender-0.1.0/tests/test_server.py +556 -0
  60. trustrender-0.1.0/tests/test_templates.py +247 -0
  61. trustrender-0.1.0/tests/test_trace.py +196 -0
  62. trustrender-0.1.0/tests/test_ugly_data.py +525 -0
  63. trustrender-0.1.0/tests/test_ugly_data_pressure.py +940 -0
  64. trustrender-0.1.0/tests/test_zugferd.py +790 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Verity Engine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.4
2
+ Name: trustrender
3
+ Version: 0.1.0
4
+ Summary: Fast, code-first PDF generation from structured data. No browser, no Chromium.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://trustrender.dev
7
+ Project-URL: Documentation, https://trustrender.dev
8
+ Project-URL: Source, https://github.com/verityengine/trustrender
9
+ Project-URL: Issues, https://github.com/verityengine/trustrender/issues
10
+ Project-URL: Changelog, https://github.com/verityengine/trustrender/releases
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Office/Business :: Financial
17
+ Classifier: Topic :: Text Processing :: Markup
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: typst>=0.14
22
+ Requires-Dist: jinja2>=3.1
23
+ Requires-Dist: starlette>=0.40
24
+ Requires-Dist: uvicorn>=0.30
25
+ Requires-Dist: drafthorse>=2024.0
26
+ Requires-Dist: pypdf>=4.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8.0; extra == "dev"
29
+ Requires-Dist: ruff>=0.4; extra == "dev"
30
+ Requires-Dist: httpx>=0.27; extra == "dev"
31
+ Requires-Dist: factur-x>=3.0; extra == "dev"
32
+ Provides-Extra: zugferd
33
+ Requires-Dist: factur-x>=3.0; extra == "zugferd"
34
+ Dynamic: license-file
35
+
36
+ # TrustRender
37
+
38
+ Structured business PDFs from code. Pre-render validated. No browser. No Chromium.
39
+
40
+ ## Why TrustRender
41
+
42
+ - **Pre-render validation** — catches bad payloads before they reach the renderer
43
+ - **Compliance support** — EN 16931 / ZUGFeRD for the supported e-invoice path
44
+ - **Provenance and hashing** — records template, data, and output fingerprints for traceability
45
+ - **Operationally lean** — no browser or Chromium dependency
46
+
47
+ TrustRender renders invoices, statements, receipts, and similar structured documents using [Typst](https://typst.app/) as the layout engine and Jinja2 for data binding. It ships as a Python library, CLI, and HTTP server.
48
+
49
+ ### Non-goals
50
+
51
+ TrustRender is not:
52
+
53
+ - arbitrary HTML-to-PDF conversion
54
+ - a browser or headless renderer
55
+ - a visual or WYSIWYG editor
56
+ - a multi-format converter
57
+
58
+ It does one thing: structured business PDFs from code.
59
+
60
+ ## Install
61
+
62
+ ```
63
+ git clone https://github.com/verityengine/trustrender.git
64
+ cd trustrender
65
+ pip install .
66
+ ```
67
+
68
+ Requires Python 3.11+ and the Typst CLI binary (`brew install typst` on macOS, or [typst.app](https://typst.app/)).
69
+
70
+ For development: `pip install -e ".[dev]"` or `make dev`.
71
+
72
+ ### Verify
73
+
74
+ ```
75
+ trustrender doctor --smoke
76
+ ```
77
+
78
+ Checks Python version, backends, fonts, and runs a real render + server health check.
79
+
80
+ ## Security
81
+
82
+ **`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.
83
+
84
+ If you deploy TrustRender as an HTTP server:
85
+
86
+ - Place it behind a reverse proxy (Nginx, Caddy, Traefik, cloud load balancer) that handles TLS termination and authentication.
87
+ - 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.
88
+ - The `/template-source` endpoint returns raw template file contents. Restrict access if templates contain business logic you consider sensitive.
89
+ - Backpressure (503 when at concurrency limit) is the only built-in traffic control. It is not a substitute for rate limiting.
90
+ - 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.
91
+
92
+ TrustRender is a rendering engine, not a security boundary. Treat it like a database: powerful, essential, and never internet-facing without a gateway.
93
+
94
+ ## Quick start
95
+
96
+ **Python:**
97
+
98
+ ```python
99
+ from trustrender import render
100
+
101
+ pdf = render("examples/invoice.j2.typ", "examples/invoice_data.json", output="invoice.pdf")
102
+ ```
103
+
104
+ **CLI:**
105
+
106
+ ```
107
+ trustrender render examples/invoice.j2.typ examples/invoice_data.json -o invoice.pdf
108
+ ```
109
+
110
+ **Server:**
111
+
112
+ ```
113
+ trustrender serve --templates examples/ --port 8190
114
+ curl -X POST http://localhost:8190/render \
115
+ -H "Content-Type: application/json" \
116
+ --data @examples/request_invoice.json -o invoice.pdf
117
+ ```
118
+
119
+ ## Why TrustRender
120
+
121
+ ### Validated before render
122
+
123
+ 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.
124
+
125
+ ```
126
+ TrustRenderError: Data validation failed: 11 field errors in invoice.j2.typ
127
+ sender: missing required field (expected: object)
128
+ items: missing required field (expected: list[object])
129
+ invoice_date: missing required field
130
+ ```
131
+
132
+ `preflight()` goes further: structural validation, semantic checks, font verification, compliance eligibility, and text safety scanning — all without rendering.
133
+
134
+ ### No browser dependency
135
+
136
+ No Chromium, no Puppeteer, no headless browser. Typst compiles directly to PDF. The server runs renders as killable subprocesses with real timeout enforcement.
137
+
138
+ 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.
139
+
140
+ ### EN 16931 e-invoicing (narrow scope)
141
+
142
+ 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.
143
+
144
+ ```
145
+ trustrender render einvoice.j2.typ data.json -o invoice.pdf --zugferd en16931
146
+ ```
147
+
148
+ Supported: DE, EUR, standard VAT (single or mixed rates), invoices and credit notes.
149
+ Not supported (fails loudly): reverse charge, cross-border, allowances/charges, non-EUR, zero/negative tax rates.
150
+
151
+ See [docs/einvoice-scope.md](docs/einvoice-scope.md) for the full scope matrix.
152
+
153
+ ### Output provenance
154
+
155
+ Embeds a cryptographic generation proof in the PDF: template hash, data hash, engine version, timestamp, and a combined proof hash. Verifiable without re-rendering.
156
+
157
+ ```python
158
+ from trustrender.provenance import verify_provenance
159
+ result = verify_provenance(pdf_bytes, "invoice.j2.typ", original_data)
160
+ # result.verified → True if hashes match
161
+ ```
162
+
163
+ Not a digital signature. A generation proof: "was this document produced from this data using this template?"
164
+
165
+ ## CLI
166
+
167
+ ```
168
+ trustrender render <template> <data.json> -o <output.pdf> [--zugferd en16931] [--provenance] [--no-validate]
169
+ trustrender preflight <template> <data.json> [--semantic] [--strict]
170
+ trustrender check <template> [--data <data.json>]
171
+ trustrender serve --templates <dir> [--port 8190] [--dashboard] [--history <path>]
172
+ trustrender audit <template> <data.json> -o <output.pdf> [--baseline-dir <dir>]
173
+ trustrender doctor [--smoke]
174
+ ```
175
+
176
+ Full flag reference: `trustrender <command> --help`.
177
+
178
+ ## HTTP server
179
+
180
+ | Method | Path | Purpose |
181
+ |--------|------|---------|
182
+ | `POST` | `/render` | Render template to PDF |
183
+ | `POST` | `/preflight` | Pre-render readiness check |
184
+ | `GET` | `/health` | Health check |
185
+ | `GET` | `/template-source?name=` | Raw template source |
186
+ | `GET` | `/history` | Render trace list (requires `--history`) |
187
+ | `GET` | `/dashboard` | Ops dashboard (requires `--dashboard`) |
188
+
189
+ Backpressure: max 8 concurrent renders (configurable), 503 when at capacity.
190
+ Max body: 10 MB (configurable). Timeout: 30s (subprocess killed on expiry).
191
+
192
+ See [docs/server.md](docs/server.md) for full API detail, error model, and configuration.
193
+
194
+ ## Bundled templates
195
+
196
+ | Template | File | Description |
197
+ |----------|------|-------------|
198
+ | Invoice | `examples/invoice.j2.typ` | Standard invoice with line items |
199
+ | E-Invoice | `examples/einvoice.j2.typ` | ZUGFeRD EN 16931 compliant |
200
+ | Statement | `examples/statement.j2.typ` | Account/transaction statement |
201
+ | Receipt | `examples/receipt.j2.typ` | Point-of-sale receipt |
202
+ | Letter | `examples/letter.j2.typ` | Business letter |
203
+ | Report | `examples/report.j2.typ` | Executive report with metrics |
204
+
205
+ Each has a matching `_data.json` file in `examples/`.
206
+
207
+ ## Docker
208
+
209
+ ```
210
+ docker build -t trustrender .
211
+ docker run -p 8190:8190 trustrender
212
+ ```
213
+
214
+ Mount custom templates or fonts:
215
+
216
+ ```
217
+ docker run -p 8190:8190 \
218
+ -v /path/to/templates:/templates -e TRUSTRENDER_TEMPLATES_DIR=/templates \
219
+ -v /path/to/fonts:/fonts -e TRUSTRENDER_FONT_PATH=/fonts \
220
+ trustrender
221
+ ```
222
+
223
+ ## Configuration
224
+
225
+ | Variable | Purpose | Default |
226
+ |----------|---------|---------|
227
+ | `TRUSTRENDER_BACKEND` | `typst-py` or `typst-cli` | Auto-detect |
228
+ | `TRUSTRENDER_FONT_PATH` | Font directory | Bundled Inter fonts |
229
+ | `TRUSTRENDER_TEMPLATES_DIR` | Template directory for `serve` | — |
230
+ | `TRUSTRENDER_MAX_BODY_SIZE` | Max request body (bytes) | 10 MB |
231
+
232
+ ## Development
233
+
234
+ ```
235
+ make dev # editable install + dev deps
236
+ trustrender doctor --smoke # verify environment
237
+ make test # pytest
238
+ make lint # ruff
239
+ make docker # build image
240
+ make help # all targets
241
+ ```
242
+
243
+ 854 tests (unit, integration, contract, semantic, ZUGFeRD, provenance, ugly-data, font, pagination, text safety, Schematron).
244
+
245
+ ## Documentation
246
+
247
+ | Topic | Link |
248
+ |-------|------|
249
+ | Validation & readiness | [docs/validation.md](docs/validation.md) |
250
+ | E-invoice scope matrix | [docs/einvoice-scope.md](docs/einvoice-scope.md) |
251
+ | HTTP server & error model | [docs/server.md](docs/server.md) |
252
+ | Templates & escaping | [docs/templates.md](docs/templates.md) |
253
+ | Fonts | [docs/fonts.md](docs/fonts.md) |
254
+ | Provenance | [docs/provenance.md](docs/provenance.md) |
255
+ | Known limits | [docs/known-limits.md](docs/known-limits.md) |
256
+
257
+ ## Caveats
258
+
259
+ - 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
260
+ - Source mapping from generated Typst back to Jinja2 source is limited
261
+ - `typst_markup()` intentionally bypasses escaping — template author's responsibility
262
+ - Code/math mode contexts are not auto-escaped (text-interpolation only)
@@ -0,0 +1,227 @@
1
+ # TrustRender
2
+
3
+ Structured business PDFs from code. Pre-render validated. No browser. No Chromium.
4
+
5
+ ## Why TrustRender
6
+
7
+ - **Pre-render validation** — catches bad payloads before they reach the renderer
8
+ - **Compliance support** — EN 16931 / ZUGFeRD for the supported e-invoice path
9
+ - **Provenance and hashing** — records template, data, and output fingerprints for traceability
10
+ - **Operationally lean** — no browser or Chromium dependency
11
+
12
+ TrustRender renders invoices, statements, receipts, and similar structured documents using [Typst](https://typst.app/) as the layout engine and Jinja2 for data binding. It ships as a Python library, CLI, and HTTP server.
13
+
14
+ ### Non-goals
15
+
16
+ TrustRender is not:
17
+
18
+ - arbitrary HTML-to-PDF conversion
19
+ - a browser or headless renderer
20
+ - a visual or WYSIWYG editor
21
+ - a multi-format converter
22
+
23
+ It does one thing: structured business PDFs from code.
24
+
25
+ ## Install
26
+
27
+ ```
28
+ git clone https://github.com/verityengine/trustrender.git
29
+ cd trustrender
30
+ pip install .
31
+ ```
32
+
33
+ Requires Python 3.11+ and the Typst CLI binary (`brew install typst` on macOS, or [typst.app](https://typst.app/)).
34
+
35
+ For development: `pip install -e ".[dev]"` or `make dev`.
36
+
37
+ ### Verify
38
+
39
+ ```
40
+ trustrender doctor --smoke
41
+ ```
42
+
43
+ Checks Python version, backends, fonts, and runs a real render + server health check.
44
+
45
+ ## Security
46
+
47
+ **`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.
48
+
49
+ If you deploy TrustRender as an HTTP server:
50
+
51
+ - Place it behind a reverse proxy (Nginx, Caddy, Traefik, cloud load balancer) that handles TLS termination and authentication.
52
+ - 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.
53
+ - The `/template-source` endpoint returns raw template file contents. Restrict access if templates contain business logic you consider sensitive.
54
+ - Backpressure (503 when at concurrency limit) is the only built-in traffic control. It is not a substitute for rate limiting.
55
+ - 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.
56
+
57
+ TrustRender is a rendering engine, not a security boundary. Treat it like a database: powerful, essential, and never internet-facing without a gateway.
58
+
59
+ ## Quick start
60
+
61
+ **Python:**
62
+
63
+ ```python
64
+ from trustrender import render
65
+
66
+ pdf = render("examples/invoice.j2.typ", "examples/invoice_data.json", output="invoice.pdf")
67
+ ```
68
+
69
+ **CLI:**
70
+
71
+ ```
72
+ trustrender render examples/invoice.j2.typ examples/invoice_data.json -o invoice.pdf
73
+ ```
74
+
75
+ **Server:**
76
+
77
+ ```
78
+ trustrender serve --templates examples/ --port 8190
79
+ curl -X POST http://localhost:8190/render \
80
+ -H "Content-Type: application/json" \
81
+ --data @examples/request_invoice.json -o invoice.pdf
82
+ ```
83
+
84
+ ## Why TrustRender
85
+
86
+ ### Validated before render
87
+
88
+ 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.
89
+
90
+ ```
91
+ TrustRenderError: Data validation failed: 11 field errors in invoice.j2.typ
92
+ sender: missing required field (expected: object)
93
+ items: missing required field (expected: list[object])
94
+ invoice_date: missing required field
95
+ ```
96
+
97
+ `preflight()` goes further: structural validation, semantic checks, font verification, compliance eligibility, and text safety scanning — all without rendering.
98
+
99
+ ### No browser dependency
100
+
101
+ No Chromium, no Puppeteer, no headless browser. Typst compiles directly to PDF. The server runs renders as killable subprocesses with real timeout enforcement.
102
+
103
+ 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.
104
+
105
+ ### EN 16931 e-invoicing (narrow scope)
106
+
107
+ 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.
108
+
109
+ ```
110
+ trustrender render einvoice.j2.typ data.json -o invoice.pdf --zugferd en16931
111
+ ```
112
+
113
+ Supported: DE, EUR, standard VAT (single or mixed rates), invoices and credit notes.
114
+ Not supported (fails loudly): reverse charge, cross-border, allowances/charges, non-EUR, zero/negative tax rates.
115
+
116
+ See [docs/einvoice-scope.md](docs/einvoice-scope.md) for the full scope matrix.
117
+
118
+ ### Output provenance
119
+
120
+ Embeds a cryptographic generation proof in the PDF: template hash, data hash, engine version, timestamp, and a combined proof hash. Verifiable without re-rendering.
121
+
122
+ ```python
123
+ from trustrender.provenance import verify_provenance
124
+ result = verify_provenance(pdf_bytes, "invoice.j2.typ", original_data)
125
+ # result.verified → True if hashes match
126
+ ```
127
+
128
+ Not a digital signature. A generation proof: "was this document produced from this data using this template?"
129
+
130
+ ## CLI
131
+
132
+ ```
133
+ trustrender render <template> <data.json> -o <output.pdf> [--zugferd en16931] [--provenance] [--no-validate]
134
+ trustrender preflight <template> <data.json> [--semantic] [--strict]
135
+ trustrender check <template> [--data <data.json>]
136
+ trustrender serve --templates <dir> [--port 8190] [--dashboard] [--history <path>]
137
+ trustrender audit <template> <data.json> -o <output.pdf> [--baseline-dir <dir>]
138
+ trustrender doctor [--smoke]
139
+ ```
140
+
141
+ Full flag reference: `trustrender <command> --help`.
142
+
143
+ ## HTTP server
144
+
145
+ | Method | Path | Purpose |
146
+ |--------|------|---------|
147
+ | `POST` | `/render` | Render template to PDF |
148
+ | `POST` | `/preflight` | Pre-render readiness check |
149
+ | `GET` | `/health` | Health check |
150
+ | `GET` | `/template-source?name=` | Raw template source |
151
+ | `GET` | `/history` | Render trace list (requires `--history`) |
152
+ | `GET` | `/dashboard` | Ops dashboard (requires `--dashboard`) |
153
+
154
+ Backpressure: max 8 concurrent renders (configurable), 503 when at capacity.
155
+ Max body: 10 MB (configurable). Timeout: 30s (subprocess killed on expiry).
156
+
157
+ See [docs/server.md](docs/server.md) for full API detail, error model, and configuration.
158
+
159
+ ## Bundled templates
160
+
161
+ | Template | File | Description |
162
+ |----------|------|-------------|
163
+ | Invoice | `examples/invoice.j2.typ` | Standard invoice with line items |
164
+ | E-Invoice | `examples/einvoice.j2.typ` | ZUGFeRD EN 16931 compliant |
165
+ | Statement | `examples/statement.j2.typ` | Account/transaction statement |
166
+ | Receipt | `examples/receipt.j2.typ` | Point-of-sale receipt |
167
+ | Letter | `examples/letter.j2.typ` | Business letter |
168
+ | Report | `examples/report.j2.typ` | Executive report with metrics |
169
+
170
+ Each has a matching `_data.json` file in `examples/`.
171
+
172
+ ## Docker
173
+
174
+ ```
175
+ docker build -t trustrender .
176
+ docker run -p 8190:8190 trustrender
177
+ ```
178
+
179
+ Mount custom templates or fonts:
180
+
181
+ ```
182
+ docker run -p 8190:8190 \
183
+ -v /path/to/templates:/templates -e TRUSTRENDER_TEMPLATES_DIR=/templates \
184
+ -v /path/to/fonts:/fonts -e TRUSTRENDER_FONT_PATH=/fonts \
185
+ trustrender
186
+ ```
187
+
188
+ ## Configuration
189
+
190
+ | Variable | Purpose | Default |
191
+ |----------|---------|---------|
192
+ | `TRUSTRENDER_BACKEND` | `typst-py` or `typst-cli` | Auto-detect |
193
+ | `TRUSTRENDER_FONT_PATH` | Font directory | Bundled Inter fonts |
194
+ | `TRUSTRENDER_TEMPLATES_DIR` | Template directory for `serve` | — |
195
+ | `TRUSTRENDER_MAX_BODY_SIZE` | Max request body (bytes) | 10 MB |
196
+
197
+ ## Development
198
+
199
+ ```
200
+ make dev # editable install + dev deps
201
+ trustrender doctor --smoke # verify environment
202
+ make test # pytest
203
+ make lint # ruff
204
+ make docker # build image
205
+ make help # all targets
206
+ ```
207
+
208
+ 854 tests (unit, integration, contract, semantic, ZUGFeRD, provenance, ugly-data, font, pagination, text safety, Schematron).
209
+
210
+ ## Documentation
211
+
212
+ | Topic | Link |
213
+ |-------|------|
214
+ | Validation & readiness | [docs/validation.md](docs/validation.md) |
215
+ | E-invoice scope matrix | [docs/einvoice-scope.md](docs/einvoice-scope.md) |
216
+ | HTTP server & error model | [docs/server.md](docs/server.md) |
217
+ | Templates & escaping | [docs/templates.md](docs/templates.md) |
218
+ | Fonts | [docs/fonts.md](docs/fonts.md) |
219
+ | Provenance | [docs/provenance.md](docs/provenance.md) |
220
+ | Known limits | [docs/known-limits.md](docs/known-limits.md) |
221
+
222
+ ## Caveats
223
+
224
+ - 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
225
+ - Source mapping from generated Typst back to Jinja2 source is limited
226
+ - `typst_markup()` intentionally bypasses escaping — template author's responsibility
227
+ - Code/math mode contexts are not auto-escaped (text-interpolation only)
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "trustrender"
7
+ version = "0.1.0"
8
+ description = "Fast, code-first PDF generation from structured data. No browser, no Chromium."
9
+ license = "MIT"
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Developers",
13
+
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Topic :: Office/Business :: Financial",
18
+ "Topic :: Text Processing :: Markup",
19
+ ]
20
+ readme = "README.md"
21
+ requires-python = ">=3.11"
22
+ dependencies = [
23
+ "typst>=0.14",
24
+ "jinja2>=3.1",
25
+ "starlette>=0.40",
26
+ "uvicorn>=0.30",
27
+ "drafthorse>=2024.0",
28
+ "pypdf>=4.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://trustrender.dev"
33
+ Documentation = "https://trustrender.dev"
34
+ Source = "https://github.com/verityengine/trustrender"
35
+ Issues = "https://github.com/verityengine/trustrender/issues"
36
+ Changelog = "https://github.com/verityengine/trustrender/releases"
37
+
38
+ [project.scripts]
39
+ trustrender = "trustrender.cli:main"
40
+
41
+ [project.optional-dependencies]
42
+ dev = [
43
+ "pytest>=8.0",
44
+ "ruff>=0.4",
45
+ "httpx>=0.27",
46
+ "factur-x>=3.0",
47
+ ]
48
+ zugferd = [
49
+ "factur-x>=3.0",
50
+ ]
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = ["src"]
54
+
55
+ [tool.setuptools.package-data]
56
+ trustrender = ["playground/**/*", "fonts/**/*"]
57
+
58
+ [tool.ruff]
59
+ line-length = 99
60
+ target-version = "py311"
61
+
62
+ [tool.ruff.lint]
63
+ select = ["E", "F", "I", "W"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+