134 lines
11 KiB
Markdown
134 lines
11 KiB
Markdown
# @suaveplan/pdf - Server-tier PDF 1.4 generation toolkit (Chunks A–D): typed PDF error registry, Zod boundary schemas, OpenTelemetry counters + histograms, unit conversion, hex/RGB colour utilities, page-size + margin types, hand-rolled PDF 1.4 binary writer (with FlateDecode + AbortSignal + injectable Clock), chainable content-stream encoder, document elements (text / table / image / divider) with Zod boundaries and AbortSignal propagation, style cascade with default theme, block-flow layout engine with header/footer slots, fluent DocumentBuilder, and orchestrating renderDocument entry point round-trippable via pdf-parse.
|
||
|
||
Server-tier PDF 1.4 generation toolkit. **Chunk A foundation** — pure
|
||
utilities + cross-cutting wiring (typed error registry, Zod boundary
|
||
schemas, OpenTelemetry counters + histograms, unit + colour utilities,
|
||
page-size + margin types). The low-level writer, element primitives,
|
||
layout engine, document builder, renderer, templates, and React preview
|
||
component land in subsequent chunks (B–E). See
|
||
[`enterprise-pdf/tasks.md`](../../../../docs/design/enterprise-pdf/tasks.md)
|
||
for the chunk roadmap.
|
||
|
||
<!-- begin:auto-docs -->
|
||
## Documentation tree
|
||
|
||
- [colors](./src/colors/colors.md) — Colour utilities for `@suaveplan/pdf`. The PDF specification stores colours as three floats in the `0`-`1` range (consu…
|
||
- [colors](./src/colors/colors.md) — Colour utilities for `@suaveplan/pdf`. The PDF specification stores colours as three floats in the `0`-`1` range (consu…
|
||
- [content-stream](./src/content-stream/content-stream.md) — `ContentStreamEncoder` is the chainable builder for PDF 1.4 content streams used by every page emitted by `@suaveplan/p…
|
||
- [content-stream](./src/content-stream/content-stream.md) — `ContentStreamEncoder` is the chainable builder for PDF 1.4 content streams used by every page emitted by `@suaveplan/p…
|
||
- [divider-element](./src/divider-element/divider-element.md) — `DividerElement` renders a horizontal or vertical rule into a PDF content stream. It is the lightweight separator primi…
|
||
- [divider-element](./src/divider-element/divider-element.md) — `DividerElement` renders a horizontal or vertical rule into a PDF content stream. It is the lightweight separator primi…
|
||
- [document-builder](./src/document-builder/document-builder.md) — The `DocumentBuilder` provides a chainable, deterministic API for assembling a PDF document tree without touching the l…
|
||
- [document-builder](./src/document-builder/document-builder.md) — The `DocumentBuilder` provides a chainable, deterministic API for assembling a PDF document tree without touching the l…
|
||
- [error-codes](./src/error-codes/error-codes.md) — Declares the stable `PDF.*` error-code registry and the `PdfError` class used by every public function in `@suaveplan/p…
|
||
- [error-codes](./src/error-codes/error-codes.md) — Declares the stable `PDF.*` error-code registry and the `PdfError` class used by every public function in `@suaveplan/p…
|
||
- [image-element](./src/image-element/image-element.md) — `ImageElement` is the bitmap primitive of `@suaveplan/pdf`. It accepts raw JPEG or PNG bytes, decodes them at construct…
|
||
- [image-element](./src/image-element/image-element.md) — `ImageElement` is the bitmap primitive of `@suaveplan/pdf`. It accepts raw JPEG or PNG bytes, decodes them at construct…
|
||
- [image-registry](./src/image-registry/image-registry.md) — The `ImageRegistry` allocates and reuses PDF Image XObjects across the lifetime of a single `renderDocument` call. Each…
|
||
- [image-registry](./src/image-registry/image-registry.md) — The `ImageRegistry` allocates and reuses PDF Image XObjects across the lifetime of a single `renderDocument` call. Each…
|
||
- [layout-engine](./src/layout-engine/layout-engine.md) — The `LayoutEngine` owns the block-flow geometry the renderer walks to position each element on the page. It computes ef…
|
||
- [layout-engine](./src/layout-engine/layout-engine.md) — The `LayoutEngine` owns the block-flow geometry the renderer walks to position each element on the page. It computes ef…
|
||
- [pdf-writer](./src/pdf-writer/pdf-writer.md) — `PdfWriter` is the low-level binary writer that emits valid PDF 1.4 byte streams. It manages indirect-object allocation…
|
||
- [pdf-writer](./src/pdf-writer/pdf-writer.md) — `PdfWriter` is the low-level binary writer that emits valid PDF 1.4 byte streams. It manages indirect-object allocation…
|
||
- [render-pipeline](./src/render-pipeline/render-pipeline.md) — Internal pipeline helpers that the top-level `renderDocument` orchestrator delegates to. Splitting placement and slot-r…
|
||
- [render-pipeline](./src/render-pipeline/render-pipeline.md) — Internal pipeline helpers that the top-level `renderDocument` orchestrator delegates to. Splitting placement and slot-r…
|
||
- [renderer](./src/renderer/renderer.md) — `renderDocument` is the top-level orchestrator that turns a `Document` AST (produced by `DocumentBuilder`) into a real…
|
||
- [renderer](./src/renderer/renderer.md) — `renderDocument` is the top-level orchestrator that turns a `Document` AST (produced by `DocumentBuilder`) into a real…
|
||
- [schemas](./src/schemas/schemas.md) — Zod boundary schemas for the public surface of `@suaveplan/pdf`. Every value crossing the package boundary from untrust…
|
||
- [schemas](./src/schemas/schemas.md) — Zod boundary schemas for the public surface of `@suaveplan/pdf`. Every value crossing the package boundary from untrust…
|
||
- [style-resolver](./src/style-resolver/style-resolver.md) — The `StyleResolver` resolves a fully-populated `PdfStyle` from the package defaults, an active theme, an optional base…
|
||
- [style-resolver](./src/style-resolver/style-resolver.md) — The `StyleResolver` resolves a fully-populated `PdfStyle` from the package defaults, an active theme, an optional base…
|
||
- [table-element](./src/table-element/table-element.md) — `TableElement` is the tabular-data primitive of `@suaveplan/pdf`. It accepts a typed column definition + row array and…
|
||
- [table-element](./src/table-element/table-element.md) — `TableElement` is the tabular-data primitive of `@suaveplan/pdf`. It accepts a typed column definition + row array and…
|
||
- [telemetry](./src/telemetry/telemetry.md) — OpenTelemetry surface for `@suaveplan/pdf`. PDF generation is a load-bearing primitive in any system that emits invoice…
|
||
- [telemetry](./src/telemetry/telemetry.md) — OpenTelemetry surface for `@suaveplan/pdf`. PDF generation is a load-bearing primitive in any system that emits invoice…
|
||
- [invoice-template](./src/templates/invoice-template/invoice-template.md) — `createInvoiceTemplate(data, options?)` converts a typed `InvoiceData` payload into a renderer-ready `Document` for pro…
|
||
- [invoice-template](./src/templates/invoice-template/invoice-template.md) — `createInvoiceTemplate(data, options?)` converts a typed `InvoiceData` payload into a renderer-ready `Document` for pro…
|
||
- [receipt-template](./src/templates/receipt-template/receipt-template.md) — `createReceiptTemplate(data, options?)` converts a typed `ReceiptData` payload into a renderer-ready `Document` for com…
|
||
- [receipt-template](./src/templates/receipt-template/receipt-template.md) — `createReceiptTemplate(data, options?)` converts a typed `ReceiptData` payload into a renderer-ready `Document` for com…
|
||
- [report-template](./src/templates/report-template/report-template.md) — `createReportTemplate(data, options?)` converts a typed `ReportData` payload into a renderer-ready `Document` for multi…
|
||
- [report-template](./src/templates/report-template/report-template.md) — `createReportTemplate(data, options?)` converts a typed `ReportData` payload into a renderer-ready `Document` for multi…
|
||
- [text-element](./src/text-element/text-element.md) — `TextElement` is the flowed-text primitive of `@suaveplan/pdf`. It accepts a content string plus typography options (fo…
|
||
- [text-element](./src/text-element/text-element.md) — `TextElement` is the flowed-text primitive of `@suaveplan/pdf`. It accepts a content string plus typography options (fo…
|
||
- [types](./src/types/page-size.md) — Defines the page-size + page-config primitives used across every other module in `@suaveplan/pdf`. PDF measurements are…
|
||
- [page-size](./src/types/page-size.md) — Defines the page-size + page-config primitives used across every other module in `@suaveplan/pdf`. PDF measurements are…
|
||
- [units](./src/units/units.md) — Unit-conversion utilities for `@suaveplan/pdf`. PDF's native measurement is the **point** (`1pt = 1/72 inch`); every co…
|
||
- [units](./src/units/units.md) — Unit-conversion utilities for `@suaveplan/pdf`. PDF's native measurement is the **point** (`1pt = 1/72 inch`); every co…
|
||
<!-- end:auto-docs -->
|
||
|
||
## Install
|
||
|
||
```bash
|
||
bun add @suaveplan/pdf
|
||
```
|
||
|
||
## Surface (Chunk A)
|
||
|
||
| Subpath | Symbols |
|
||
| --- | --- |
|
||
| `@suaveplan/pdf/error-codes` | `PDF_CODES`, `PdfError`, `asPdfError`, `PdfErrorCode` |
|
||
| `@suaveplan/pdf/schemas` | `UnitSchema`, `HexColorSchema`, `RgbColorSchema`, `MarginsSchema`, `PageConfigSchema`, `DocumentMetadataSchema`, `parseOrThrow`, `parseHexColor` |
|
||
| `@suaveplan/pdf/telemetry` | `createPdfObservability`, six `record*` helpers, `PdfObservability` |
|
||
| `@suaveplan/pdf/units` | `Unit`, `toPoints`, `fromPoints`, `convert`, `parseUnit`, `formatUnit` |
|
||
| `@suaveplan/pdf/colors` | `RgbColor`, `PdfColor`, `hexToRgb`, `rgbToPdfColor`, `hexToPdfColor`, `rgbToHex`, `lighten`, `darken`, `COLORS`, `isTransparent` |
|
||
| `@suaveplan/pdf/types` | `PageSize`, `PAGE_DIMENSIONS`, `Margins`, `DEFAULT_MARGINS`, `DocumentMetadata`, `PageConfig`, `DEFAULT_PAGE_CONFIG`, `DocumentDefinition`, `PageDefinition`, `ElementNode` |
|
||
|
||
The package barrel `@suaveplan/pdf` re-exports every symbol above.
|
||
|
||
## Example
|
||
|
||
```ts
|
||
import {
|
||
convert,
|
||
hexToPdfColor,
|
||
parseOrThrow,
|
||
PageConfigSchema,
|
||
PAGE_DIMENSIONS,
|
||
PageSize,
|
||
PDF_CODES,
|
||
} from "@suaveplan/pdf";
|
||
|
||
const a4 = PAGE_DIMENSIONS[PageSize.A4];
|
||
const inchInMm = convert(1, "in", "mm"); // ≈ 25.4
|
||
const accent = hexToPdfColor("#3366cc"); // PDF-native 0-1 triple
|
||
|
||
const page = parseOrThrow(
|
||
PageConfigSchema,
|
||
requestBody.page,
|
||
PDF_CODES.INVALID_PAGE_CONFIG,
|
||
"bad page config"
|
||
);
|
||
```
|
||
|
||
## Dependencies
|
||
|
||
- `@suaveplan/error` — typed-error base.
|
||
- `@suaveplan/opentelemetry` — counter / histogram helpers.
|
||
- `@suaveplan/types` — shared `Clock` etc. for later chunks.
|
||
- `@opentelemetry/api` — meter / tracer global API.
|
||
- `zod` — boundary validation.
|
||
- `tslib` — runtime helpers.
|
||
|
||
No third-party PDF dependency. Chunk B will keep the hand-rolled PDF 1.4
|
||
writer the upstream package ships with — the spec is small enough that
|
||
shipping a custom 200 LOC implementation is preferable to pulling in
|
||
`pdfkit` (`~600 KB` unpacked, CommonJS-only, includes unrelated PNG and
|
||
font subsystems).
|
||
|
||
## Roadmap
|
||
|
||
- **Chunk B** — `pdf-writer/`, `content-stream/` (low-level binary writer + content stream encoder).
|
||
- **Chunk C** — `text-element/`, `table-element/`, `image-element/`, `divider-element/`.
|
||
- **Chunk D** — `layout-engine/`, `style-resolver/`, `document-builder/`, `renderer/`.
|
||
- **Chunk E** — `invoice-template/`, `receipt-template/`, `report-template/`, `pdf-preview/` (React).
|
||
|
||
## Quality gate
|
||
|
||
```bash
|
||
bunx turbo lint typecheck test build --filter=@suaveplan/pdf
|
||
bunx turbo test:coverage --filter=@suaveplan/pdf
|
||
```
|
||
|
||
100 / 100 / 100 / 100 Istanbul coverage on every Chunk A module.
|
||
|