pretext-pdf 0.4.6 → 0.5.1

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 (63) hide show
  1. package/CHANGELOG.md +333 -333
  2. package/README.md +3 -3
  3. package/dist/assets.d.ts +3 -0
  4. package/dist/assets.d.ts.map +1 -1
  5. package/dist/assets.js +111 -21
  6. package/dist/assets.js.map +1 -1
  7. package/dist/builder.d.ts +22 -1
  8. package/dist/builder.d.ts.map +1 -1
  9. package/dist/builder.js +38 -1
  10. package/dist/builder.js.map +1 -1
  11. package/dist/errors.d.ts +1 -1
  12. package/dist/errors.d.ts.map +1 -1
  13. package/dist/errors.js.map +1 -1
  14. package/dist/fonts.d.ts.map +1 -1
  15. package/dist/fonts.js +36 -1
  16. package/dist/fonts.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +36 -15
  20. package/dist/index.js.map +1 -1
  21. package/dist/measure-blocks.d.ts +25 -0
  22. package/dist/measure-blocks.d.ts.map +1 -0
  23. package/dist/measure-blocks.js +1019 -0
  24. package/dist/measure-blocks.js.map +1 -0
  25. package/dist/measure-text.d.ts +53 -0
  26. package/dist/measure-text.d.ts.map +1 -0
  27. package/dist/measure-text.js +435 -0
  28. package/dist/measure-text.js.map +1 -0
  29. package/dist/measure.d.ts +15 -35
  30. package/dist/measure.d.ts.map +1 -1
  31. package/dist/measure.js +42 -1066
  32. package/dist/measure.js.map +1 -1
  33. package/dist/paginate.d.ts.map +1 -1
  34. package/dist/paginate.js +14 -12
  35. package/dist/paginate.js.map +1 -1
  36. package/dist/render-blocks.d.ts +24 -0
  37. package/dist/render-blocks.d.ts.map +1 -0
  38. package/dist/render-blocks.js +937 -0
  39. package/dist/render-blocks.js.map +1 -0
  40. package/dist/render-extras.d.ts +18 -0
  41. package/dist/render-extras.d.ts.map +1 -0
  42. package/dist/render-extras.js +325 -0
  43. package/dist/render-extras.js.map +1 -0
  44. package/dist/render-utils.d.ts +59 -0
  45. package/dist/render-utils.d.ts.map +1 -0
  46. package/dist/render-utils.js +219 -0
  47. package/dist/render-utils.js.map +1 -0
  48. package/dist/render.d.ts.map +1 -1
  49. package/dist/render.js +10 -1372
  50. package/dist/render.js.map +1 -1
  51. package/dist/rich-text.d.ts +4 -0
  52. package/dist/rich-text.d.ts.map +1 -1
  53. package/dist/rich-text.js +4 -0
  54. package/dist/rich-text.js.map +1 -1
  55. package/dist/types.d.ts +108 -5
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/validate.d.ts.map +1 -1
  58. package/dist/validate.js +195 -15
  59. package/dist/validate.js.map +1 -1
  60. package/docs/screenshots/showcase-invoice.png +0 -0
  61. package/docs/screenshots/showcase-report.png +0 -0
  62. package/docs/screenshots/showcase-resume.png +0 -0
  63. package/package.json +130 -128
package/CHANGELOG.md CHANGED
@@ -1,333 +1,333 @@
1
- # Changelog
2
-
3
- All notable changes to pretext-pdf are documented here.
4
- Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/)
5
-
6
- ---
7
-
8
- ## [Unreleased]
9
-
10
- ### Planned (Phase 9+)
11
-
12
- - Phase 9A: Digital signatures (cryptographic PKCS#7 via `@signpdf/signpdf`)
13
- - Phase 9B: Image floats (text flowing alongside images — requires paginator rewrite)
14
- - Phase 9C: Font subsetting pre-computation (explicit glyph hints for icon fonts)
15
-
16
- ---
17
-
18
- ## [0.4.0] — 2026-04-08
19
-
20
- ### Breaking Changes
21
- - **Migrated from `pdf-lib` to `@cantoo/pdf-lib`** — `@cantoo/pdf-lib` is now a direct `dependency` (always installed). Previously it was an optional peer dependency required only for encryption. This removes the `ENCRYPTION_NOT_AVAILABLE` error code and the separate `npm install @cantoo/pdf-lib` installation step. Encryption now works out of the box.
22
- - **`ENCRYPTION_NOT_AVAILABLE` error code removed** — encryption is now always available. Update any `switch` statements that handled this code.
23
-
24
- ### Why this change
25
- `pdf-lib` (the original) has not received a meaningful commit since November 2021. `@cantoo/pdf-lib` is the actively maintained fork (v2.6.5, 107+ releases, MIT license). pretext-pdf was already using `@cantoo/pdf-lib` for encryption — this commit makes it the single source of truth for all PDF operations.
26
-
27
- ### Added
28
- - `test/pretext-api-contract.test.ts` — canary test that asserts `@chenglou/pretext` exports the exact functions pretext-pdf depends on. Breaks loudly if pretext changes its API.
29
- - `docs/ROADMAP.md` — public multi-phase development plan
30
-
31
- ### Changed
32
- - `@chenglou/pretext` version pinned to exact `0.0.3` (no caret) — prevents surprise breaking changes from upstream auto-updates
33
- - `test:contract` script added — runs the pretext API contract test before the full test suite
34
- - All internal comments updated from `pdf-lib` to `@cantoo/pdf-lib`
35
-
36
- ---
37
-
38
- ## [0.3.1] — 2026-04-08
39
-
40
- ### Fixed
41
- - **Critical: Font resolution when installed as npm package** — `@fontsource/inter` is now resolved via `createRequire(import.meta.url)` instead of a hardcoded relative path. Previously, `path.join(__dirname, '..', 'node_modules', '@fontsource', 'inter', ...)` failed when npm hoisted the dependency to the consumer's top-level `node_modules`, causing `FONT_LOAD_FAILED` on every install. Now resolves correctly regardless of npm hoisting behavior.
42
-
43
- ---
44
-
45
- ## [0.3.0] — 2026-04-08
46
-
47
- ### Added (Phase 8B — Interactive Forms)
48
- - New `form-field` element type — creates interactive AcroForm fields in PDFs
49
- - `fieldType: 'text' | 'checkbox' | 'radio' | 'dropdown' | 'button'`
50
- - `label` renders above the field as static text
51
- - Text fields: `defaultValue`, `multiline`, `placeholder`, `maxLength`
52
- - Checkboxes: `checked` initial state
53
- - Radio groups and dropdowns: `options` array, `defaultSelected`
54
- - `doc.flattenForms: true` — bakes all fields into static content
55
- - Custom `borderColor`, `backgroundColor`, `width`, `height`, `fontSize` per field
56
- - New error codes: `FORM_FIELD_NAME_DUPLICATE` (duplicate `name` across fields), `FORM_FLATTEN_FAILED`
57
- - Post-render `form.updateFieldAppearances()` ensures proper display in all PDF readers
58
- - 10 comprehensive tests covering all form field types
59
-
60
- ### Added (Phase 8E — Signature Placeholder)
61
- - `doc.signature` — visual signature box drawn on a specified page
62
- - Fields: `signerName`, `reason`, `location`, `x`, `y`, `width`, `height`, `page`, `borderColor`, `fontSize`
63
- - Draws signature line, date line, and optional text inside a bordered rectangle
64
- - `page` is 0-indexed, defaults to last page, clamps gracefully if out of range
65
- - 6 comprehensive tests
66
-
67
- ### Added (Phase 8D — Callout Boxes)
68
- - New `callout` element type — styled highlight box with optional title
69
- - Preset styles: `style: 'info'` (blue), `'warning'` (amber), `'tip'` (green), `'note'` (gray)
70
- - Optional `title` rendered bold above content with left border accent
71
- - Fully customizable: `backgroundColor`, `borderColor`, `color`, `titleColor`, `padding`
72
- - Paginates correctly across pages (reuses blockquote pagination logic)
73
- - 8 comprehensive tests
74
-
75
- ### Added (Phase 8F — Document Metadata Extensions)
76
- - `doc.metadata.language` — sets PDF `/Lang` catalog entry (BCP47 tag e.g. `'en-US'`, `'hi'`)
77
- - `doc.metadata.producer` — sets PDF producer field (e.g. `'MyApp v2.1'`)
78
- - Both fields validate as non-empty strings
79
- - 5 comprehensive tests
80
-
81
- ---
82
-
83
- ## [0.2.0] — 2026-04-08
84
-
85
- ### Added (Phase 8H — Inline Formatting)
86
- - `verticalAlign: 'superscript' | 'subscript'` on `InlineSpan` in rich-paragraphs
87
- - Superscript renders at 65% font size, baseline shifted up by 40% of font size
88
- - Subscript renders at 65% font size, baseline shifted down by 20% of font size
89
- - `letterSpacing?: number` on `ParagraphElement`, `HeadingElement`, `RichParagraphElement` — extra pt between characters
90
- - `smallCaps?: boolean` on those same three element types — simulated via uppercase + 80% fontSize
91
- - Character-by-character rendering for letterSpacing (pdf-lib has no native spacing param)
92
- - 8 comprehensive tests covering all inline formatting functionality
93
-
94
- ### Added (Phase 8A — Annotations/Comments)
95
- - New `comment` element type — sticky note annotation at position in document
96
- - `annotation?: AnnotationSpec` on `ParagraphElement` and `HeadingElement` — attach note to element
97
- - Supports: `contents`, `author`, `color` (hex), `open` (popup default state)
98
- - Uses PDF `Subtype: 'Text'` annotation (sticky note icon in PDF viewers)
99
- - 8 comprehensive tests covering all annotation functionality
100
-
101
- ### Added (Phase 8C — Document Assembly)
102
- - New `merge(pdfs: Uint8Array[])` exported function — combine pre-rendered PDFs
103
- - New `assemble(parts: AssemblyPart[])` exported function — mix rendered docs + existing PDFs
104
- - `AssemblyPart` interface: `{ doc?: PdfDocument, pdf?: Uint8Array }`
105
- - New error codes: `ASSEMBLY_EMPTY`, `ASSEMBLY_FAILED`
106
- - 8 comprehensive tests covering all assembly functionality
107
-
108
- ### Fixed
109
- - **CI case-sensitivity bug**: `test/phase-7-integration.test.ts` used `'en-US'` (uppercase) for hyphenation language. On Linux CI (case-sensitive filesystem) this failed with `UNSUPPORTED_LANGUAGE`. Changed to `'en-us'` to match package name `hyphenation.en-us`.
110
-
111
- ---
112
-
113
- ## [0.1.1] — 2026-04-08
114
-
115
- ### Added
116
- - **Phase 8G: Hyperlinks** — Complete link annotation support:
117
- - `paragraph.url` for external URI links on paragraphs
118
- - `heading.url` for external URI links on headings
119
- - `heading.anchor` for named PDF destinations (internal cross-references)
120
- - `InlineSpan.href` for external and internal `#anchorId` links in rich-paragraphs
121
- - `mailto:` scheme support for email links
122
- - GoTo annotations for internal anchor references
123
- - 9 comprehensive tests covering all hyperlink functionality
124
-
125
- ### Fixed
126
- - **Memory leak in test suite**: Removed module-level `_hypherCache` in `src/measure.ts` that accumulated ~188KB per language across 255+ test runs. Changed from cached Hypher instances to fresh instances per call (negligible performance impact, massive memory savings).
127
- - **Node.js version compatibility**: Replaced `--experimental-strip-types` with `tsx` runner to support Node.js 18.x, 20.x, and 22.x in CI
128
- - **Broken CI examples**: Removed references to non-existent Phase 8 example scripts from GitHub Actions workflow
129
- - **README examples mismatch**: Updated Examples section to only list 5 existing Phase 7 examples (watermark, bookmarks, toc, rtl, encryption)
130
- - **Test suite OOM issues**: Split large test files (paginate.test.ts) into paginate-basic.test.ts to work around Node.js `--experimental-strip-types` heap exhaustion bug on files >17KB
131
-
132
- ### Changed
133
- - `test:unit` now runs only `test/paginate-basic.test.ts` (fast, no canvas overhead)
134
- - Reorganized test scripts: `test:unit`, `test:validate`, `test:e2e`, `test:phases` for better memory management
135
- - Moved internal planning documentation to archive (preserved, not published)
136
- - `devDependencies`: Added `@napi-rs/canvas` explicitly (was missing, causing CI failures)
137
-
138
- ### Added
139
- - `CONTRIBUTING.md`: Development setup, TDD workflow, PR process guide
140
- - `CHENG_LOU_EMAIL_DRAFT.md`: Template for requesting endorsement from pretext creator
141
- - `examples/comparison-pdfmake.ts`: pdfmake version of invoice for typography comparison
142
-
143
- ---
144
-
145
- ## [0.1.0] — 2026-04-07
146
-
147
- ### Added (Phase 7G — Encryption)
148
- - `doc.encryption` configuration for password-protecting PDFs
149
- - User password and owner password support
150
- - Granular permission restrictions: printing, copying, modifying, annotating
151
- - Lazy-loads `@cantoo/pdf-lib` (optional peer dependency) — zero cost when not used
152
- - Error code: `ENCRYPTION_NOT_AVAILABLE` when encryption is requested but dependency not installed
153
-
154
- ### Added (Phase 7F — RTL Text Support)
155
- - Right-to-left text support for Arabic, Hebrew, and other RTL languages
156
- - Unicode bidirectional text algorithm via `bidi-js`
157
- - `dir` attribute on text elements: `'ltr'` | `'rtl'` | `'auto'` for per-element control
158
- - RTL text works with headings, paragraphs, lists, tables, and all text elements
159
- - Automatic detection of mixed LTR/RTL content
160
-
161
- ### Added (Phase 7E — SVG Support)
162
- - `{ type: 'svg', svg: '<...' }` element for embedding SVG graphics
163
- - SVG rasterization via `@napi-rs/canvas`
164
- - ViewBox auto-sizing: automatic height calculation from viewBox aspect ratio
165
- - Explicit sizing: `width` and `height` parameters for precise control
166
- - Alignment options: `align: 'left' | 'center' | 'right'`
167
- - Multi-page support: SVGs paginate correctly across page breaks
168
- - Error code: `SVG_RENDER_FAILED` for SVG rasterization errors
169
-
170
- ### Added (Phase 7D — Table of Contents)
171
- - `{ type: 'toc' }` element for automatic TOC generation
172
- - Two-pass rendering pipeline ensures accurate page numbers
173
- - Configurable: `title`, `showTitle`, `minLevel`/`maxLevel`, dot leaders, level indentation
174
- - Auto-indexed from heading structure (H1, H2, H3, etc.)
175
- - Supports custom formatting via `fontSize`, `color`, `spaceAfter` parameters
176
-
177
- ### Added (Phase 7C — Hyphenation)
178
- - Automatic word hyphenation for better justified text layout
179
- - `doc.hyphenation: { language: 'en-US' }` for document-level config
180
- - Liang's algorithm via `hypher` package for accurate break points
181
- - Configurable: `minWordLength`, `leftMin`, `rightMin`, per-element `hyphenate: false` opt-out
182
- - Language support: includes `hyphenation.en-us` (additional languages via npm packages)
183
- - Error code: `UNSUPPORTED_LANGUAGE` when language not available
184
-
185
- ### Added (Phase 7B — Watermarks)
186
- - `doc.watermark` for text or image watermarks on every page
187
- - Text watermarks: `text`, `fontSize`, `fontWeight`, `color`, `opacity`, `rotation`
188
- - Image watermarks: `image` (Uint8Array), `opacity`, `rotation`, `color` (tint)
189
- - Watermarks render behind content (lower z-index)
190
- - Rotation bounds: -360 ≤ rotation ≤ 360 degrees
191
- - Validation: must provide either text or image, never both required
192
-
193
- ### Added (Phase 7A — Bookmarks / PDF Outline)
194
- - PDF sidebar bookmarks auto-generated from heading structure
195
- - Enabled by default: `bookmarks: true` or `bookmarks: { minLevel: 1, maxLevel: 3 }`
196
- - Level filtering: include/exclude heading levels from outline
197
- - Per-heading opt-out: `bookmark: false` on heading elements
198
- - Keyboard navigation: Cmd/Ctrl+Opt/Alt+O in PDF readers to toggle bookmark sidebar
199
-
200
- ### Added (Phase 6 — Advanced Features)
201
- - Header and footer support with {{pageNumber}} and {{totalPages}} tokens
202
- - Text decoration: strikethrough, underline
203
- - Text alignment: left, center, right, justify
204
- - Line height control: custom line-height multipliers
205
- - Column layout with multi-column content flow
206
- - Tables with colspan/rowspan support
207
-
208
- ### Added (Phase 5 — Rich Text / Builder API)
209
- - Fluent builder API for programmatic document construction
210
- - Rich text element with nested formatting (bold, italic, links)
211
- - Inline code and code blocks with syntax highlighting
212
- - Block quotes with custom styling
213
- - Horizontal rules (hr element)
214
- - Numbered and bulleted lists with nesting
215
-
216
- ### Added (Phases 1–4 — Core Engine)
217
- - Core PDF generation via `pdf-lib`
218
- - Element types: paragraph, heading, table, image, list, code, blockquote
219
- - Font support: Inter bundled, custom TTF embedding
220
- - Document metadata: title, author, subject, keywords, created date
221
- - Page sizing: A4, A3, A5, Letter, Legal, or custom dimensions
222
- - Margins: top, bottom, left, right per page
223
- - Multi-page pagination with orphan/widow control
224
- - Image formats: PNG, JPG, WebP
225
- - Table features: custom column widths, cell padding, borders, header styling
226
- - Colors: hex color codes throughout (text, backgrounds, borders)
227
-
228
- ---
229
-
230
- ## Features by Phase
231
-
232
- | Phase | Feature | Status | Tests | Version |
233
- |-------|---------|--------|-------|---------|
234
- | 7A | Bookmarks / PDF Outline | ✅ Complete | 8 | 0.1.0 |
235
- | 7B | Watermarks | ✅ Complete | 8 | 0.1.0 |
236
- | 7C | Hyphenation | ✅ Complete | 10 | 0.1.0 |
237
- | 7D | Table of Contents | ✅ Complete | 10 | 0.1.0 |
238
- | 7E | SVG Support | ✅ Complete | 8 | 0.1.0 |
239
- | 7F | RTL Text Support | ✅ Complete | 12 | 0.1.0 |
240
- | 7G | Encryption | ✅ Complete | 7 | 0.1.0 |
241
- | Integration | Feature Combinations | ✅ Complete | 6 | 0.1.0 |
242
- | 6 | Advanced Features | ✅ Complete | — | 0.1.0 |
243
- | 5 | Rich Text / Builder API | ✅ Complete | — | 0.1.0 |
244
- | 1–4 | Core Engine | ✅ Complete | — | 0.1.0 |
245
-
246
- ---
247
-
248
- ## How to Use Examples
249
-
250
- All Phase 7 features have working examples in the `examples/` directory. Run them with:
251
-
252
- ```bash
253
- npm run example:watermark # Phase 7B — Watermarks
254
- npm run example:bookmarks # Phase 7A — Bookmarks
255
- npm run example:toc # Phase 7D — Table of Contents
256
- npm run example:rtl # Phase 7F — RTL Text Support
257
- npm run example:encryption # Phase 7G — Encryption
258
- ```
259
-
260
- PDF output is written to `output/phase7-*.pdf`.
261
-
262
- ---
263
-
264
- ## Test Coverage
265
-
266
- All phases include comprehensive test coverage:
267
-
268
- ```bash
269
- npm test # Run all 75+ tests
270
- npm run test:unit # Unit tests only
271
- npm run test:e2e # End-to-end tests
272
- npm run test:visual # Visual regression tests
273
- ```
274
-
275
- ---
276
-
277
- ## Dependencies
278
-
279
- ### Required
280
- - `@chenglou/pretext` — Pretext text layout engine
281
- - `pdf-lib` — PDF document manipulation
282
- - `@fontsource/inter` — Font: Inter (bundled)
283
- - `bidi-js` — Bidirectional text algorithm (Phase 7F)
284
- - `hypher` — Hyphenation algorithm (Phase 7C)
285
- - `hyphenation.en-us` — English hyphenation patterns (Phase 7C)
286
-
287
- ### Optional (Peer)
288
- - `@napi-rs/canvas` — SVG rasterization (Phase 7E)
289
- - `@cantoo/pdf-lib` — PDF encryption (Phase 7G)
290
-
291
- ---
292
-
293
- ## Architecture
294
-
295
- pretext-pdf uses a modular, layered architecture:
296
-
297
- ```
298
- render(doc) → validate → layout → paginate → render-pages → PDF bytes
299
- ```
300
-
301
- Each phase adds features orthogonally:
302
- - Phase 1–4: Core engine, pagination, typography
303
- - Phase 5: Rich text and builder patterns
304
- - Phase 6: Advanced layout and formatting
305
- - Phase 7: Security, internationalization, accessibility
306
-
307
- ---
308
-
309
- ## Future Roadmap
310
-
311
- Potential Phase 8+ features (not yet implemented):
312
- - Hyperlinks and anchors
313
- - Justified text alignment
314
- - Enhanced text decorations
315
- - Font subsetting for file size reduction
316
- - Browser compatibility improvements
317
- - Performance optimizations
318
-
319
- ---
320
-
321
- ## Contributing
322
-
323
- pretext-pdf is actively maintained. To report issues, request features, or contribute:
324
-
325
- 1. Check existing issues on the project repo
326
- 2. Write failing tests first (TDD)
327
- 3. Submit pull requests with test coverage ≥80%
328
-
329
- ---
330
-
331
- ## License
332
-
333
- Check LICENSE file in repository root.
1
+ # Changelog
2
+
3
+ All notable changes to pretext-pdf are documented here.
4
+ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/)
5
+
6
+ ---
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Planned (Phase 9+)
11
+
12
+ - Phase 9A: Digital signatures (cryptographic PKCS#7 via `@signpdf/signpdf`)
13
+ - Phase 9B: Image floats (text flowing alongside images — requires paginator rewrite)
14
+ - Phase 9C: Font subsetting pre-computation (explicit glyph hints for icon fonts)
15
+
16
+ ---
17
+
18
+ ## [0.4.0] — 2026-04-08
19
+
20
+ ### Breaking Changes
21
+ - **Migrated from `pdf-lib` to `@cantoo/pdf-lib`** — `@cantoo/pdf-lib` is now a direct `dependency` (always installed). Previously it was an optional peer dependency required only for encryption. This removes the `ENCRYPTION_NOT_AVAILABLE` error code and the separate `npm install @cantoo/pdf-lib` installation step. Encryption now works out of the box.
22
+ - **`ENCRYPTION_NOT_AVAILABLE` error code removed** — encryption is now always available. Update any `switch` statements that handled this code.
23
+
24
+ ### Why this change
25
+ `pdf-lib` (the original) has not received a meaningful commit since November 2021. `@cantoo/pdf-lib` is the actively maintained fork (v2.6.5, 107+ releases, MIT license). pretext-pdf was already using `@cantoo/pdf-lib` for encryption — this commit makes it the single source of truth for all PDF operations.
26
+
27
+ ### Added
28
+ - `test/pretext-api-contract.test.ts` — canary test that asserts `@chenglou/pretext` exports the exact functions pretext-pdf depends on. Breaks loudly if pretext changes its API.
29
+ - `docs/ROADMAP.md` — public multi-phase development plan
30
+
31
+ ### Changed
32
+ - `@chenglou/pretext` version pinned to exact `0.0.3` (no caret) — prevents surprise breaking changes from upstream auto-updates
33
+ - `test:contract` script added — runs the pretext API contract test before the full test suite
34
+ - All internal comments updated from `pdf-lib` to `@cantoo/pdf-lib`
35
+
36
+ ---
37
+
38
+ ## [0.3.1] — 2026-04-08
39
+
40
+ ### Fixed
41
+ - **Critical: Font resolution when installed as npm package** — `@fontsource/inter` is now resolved via `createRequire(import.meta.url)` instead of a hardcoded relative path. Previously, `path.join(__dirname, '..', 'node_modules', '@fontsource', 'inter', ...)` failed when npm hoisted the dependency to the consumer's top-level `node_modules`, causing `FONT_LOAD_FAILED` on every install. Now resolves correctly regardless of npm hoisting behavior.
42
+
43
+ ---
44
+
45
+ ## [0.3.0] — 2026-04-08
46
+
47
+ ### Added (Phase 8B — Interactive Forms)
48
+ - New `form-field` element type — creates interactive AcroForm fields in PDFs
49
+ - `fieldType: 'text' | 'checkbox' | 'radio' | 'dropdown' | 'button'`
50
+ - `label` renders above the field as static text
51
+ - Text fields: `defaultValue`, `multiline`, `placeholder`, `maxLength`
52
+ - Checkboxes: `checked` initial state
53
+ - Radio groups and dropdowns: `options` array, `defaultSelected`
54
+ - `doc.flattenForms: true` — bakes all fields into static content
55
+ - Custom `borderColor`, `backgroundColor`, `width`, `height`, `fontSize` per field
56
+ - New error codes: `FORM_FIELD_NAME_DUPLICATE` (duplicate `name` across fields), `FORM_FLATTEN_FAILED`
57
+ - Post-render `form.updateFieldAppearances()` ensures proper display in all PDF readers
58
+ - 10 comprehensive tests covering all form field types
59
+
60
+ ### Added (Phase 8E — Signature Placeholder)
61
+ - `doc.signature` — visual signature box drawn on a specified page
62
+ - Fields: `signerName`, `reason`, `location`, `x`, `y`, `width`, `height`, `page`, `borderColor`, `fontSize`
63
+ - Draws signature line, date line, and optional text inside a bordered rectangle
64
+ - `page` is 0-indexed, defaults to last page, clamps gracefully if out of range
65
+ - 6 comprehensive tests
66
+
67
+ ### Added (Phase 8D — Callout Boxes)
68
+ - New `callout` element type — styled highlight box with optional title
69
+ - Preset styles: `style: 'info'` (blue), `'warning'` (amber), `'tip'` (green), `'note'` (gray)
70
+ - Optional `title` rendered bold above content with left border accent
71
+ - Fully customizable: `backgroundColor`, `borderColor`, `color`, `titleColor`, `padding`
72
+ - Paginates correctly across pages (reuses blockquote pagination logic)
73
+ - 8 comprehensive tests
74
+
75
+ ### Added (Phase 8F — Document Metadata Extensions)
76
+ - `doc.metadata.language` — sets PDF `/Lang` catalog entry (BCP47 tag e.g. `'en-US'`, `'hi'`)
77
+ - `doc.metadata.producer` — sets PDF producer field (e.g. `'MyApp v2.1'`)
78
+ - Both fields validate as non-empty strings
79
+ - 5 comprehensive tests
80
+
81
+ ---
82
+
83
+ ## [0.2.0] — 2026-04-08
84
+
85
+ ### Added (Phase 8H — Inline Formatting)
86
+ - `verticalAlign: 'superscript' | 'subscript'` on `InlineSpan` in rich-paragraphs
87
+ - Superscript renders at 65% font size, baseline shifted up by 40% of font size
88
+ - Subscript renders at 65% font size, baseline shifted down by 20% of font size
89
+ - `letterSpacing?: number` on `ParagraphElement`, `HeadingElement`, `RichParagraphElement` — extra pt between characters
90
+ - `smallCaps?: boolean` on those same three element types — simulated via uppercase + 80% fontSize
91
+ - Character-by-character rendering for letterSpacing (pdf-lib has no native spacing param)
92
+ - 8 comprehensive tests covering all inline formatting functionality
93
+
94
+ ### Added (Phase 8A — Annotations/Comments)
95
+ - New `comment` element type — sticky note annotation at position in document
96
+ - `annotation?: AnnotationSpec` on `ParagraphElement` and `HeadingElement` — attach note to element
97
+ - Supports: `contents`, `author`, `color` (hex), `open` (popup default state)
98
+ - Uses PDF `Subtype: 'Text'` annotation (sticky note icon in PDF viewers)
99
+ - 8 comprehensive tests covering all annotation functionality
100
+
101
+ ### Added (Phase 8C — Document Assembly)
102
+ - New `merge(pdfs: Uint8Array[])` exported function — combine pre-rendered PDFs
103
+ - New `assemble(parts: AssemblyPart[])` exported function — mix rendered docs + existing PDFs
104
+ - `AssemblyPart` interface: `{ doc?: PdfDocument, pdf?: Uint8Array }`
105
+ - New error codes: `ASSEMBLY_EMPTY`, `ASSEMBLY_FAILED`
106
+ - 8 comprehensive tests covering all assembly functionality
107
+
108
+ ### Fixed
109
+ - **CI case-sensitivity bug**: `test/phase-7-integration.test.ts` used `'en-US'` (uppercase) for hyphenation language. On Linux CI (case-sensitive filesystem) this failed with `UNSUPPORTED_LANGUAGE`. Changed to `'en-us'` to match package name `hyphenation.en-us`.
110
+
111
+ ---
112
+
113
+ ## [0.1.1] — 2026-04-08
114
+
115
+ ### Added
116
+ - **Phase 8G: Hyperlinks** — Complete link annotation support:
117
+ - `paragraph.url` for external URI links on paragraphs
118
+ - `heading.url` for external URI links on headings
119
+ - `heading.anchor` for named PDF destinations (internal cross-references)
120
+ - `InlineSpan.href` for external and internal `#anchorId` links in rich-paragraphs
121
+ - `mailto:` scheme support for email links
122
+ - GoTo annotations for internal anchor references
123
+ - 9 comprehensive tests covering all hyperlink functionality
124
+
125
+ ### Fixed
126
+ - **Memory leak in test suite**: Removed module-level `_hypherCache` in `src/measure.ts` that accumulated ~188KB per language across 255+ test runs. Changed from cached Hypher instances to fresh instances per call (negligible performance impact, massive memory savings).
127
+ - **Node.js version compatibility**: Replaced `--experimental-strip-types` with `tsx` runner to support Node.js 18.x, 20.x, and 22.x in CI
128
+ - **Broken CI examples**: Removed references to non-existent Phase 8 example scripts from GitHub Actions workflow
129
+ - **README examples mismatch**: Updated Examples section to only list 5 existing Phase 7 examples (watermark, bookmarks, toc, rtl, encryption)
130
+ - **Test suite OOM issues**: Split large test files (paginate.test.ts) into paginate-basic.test.ts to work around Node.js `--experimental-strip-types` heap exhaustion bug on files >17KB
131
+
132
+ ### Changed
133
+ - `test:unit` now runs only `test/paginate-basic.test.ts` (fast, no canvas overhead)
134
+ - Reorganized test scripts: `test:unit`, `test:validate`, `test:e2e`, `test:phases` for better memory management
135
+ - Moved internal planning documentation to archive (preserved, not published)
136
+ - `devDependencies`: Added `@napi-rs/canvas` explicitly (was missing, causing CI failures)
137
+
138
+ ### Added
139
+ - `CONTRIBUTING.md`: Development setup, TDD workflow, PR process guide
140
+ - `CHENG_LOU_EMAIL_DRAFT.md`: Template for requesting endorsement from pretext creator
141
+ - `examples/comparison-pdfmake.ts`: pdfmake version of invoice for typography comparison
142
+
143
+ ---
144
+
145
+ ## [0.1.0] — 2026-04-07
146
+
147
+ ### Added (Phase 7G — Encryption)
148
+ - `doc.encryption` configuration for password-protecting PDFs
149
+ - User password and owner password support
150
+ - Granular permission restrictions: printing, copying, modifying, annotating
151
+ - Lazy-loads `@cantoo/pdf-lib` (optional peer dependency) — zero cost when not used
152
+ - Error code: `ENCRYPTION_NOT_AVAILABLE` when encryption is requested but dependency not installed
153
+
154
+ ### Added (Phase 7F — RTL Text Support)
155
+ - Right-to-left text support for Arabic, Hebrew, and other RTL languages
156
+ - Unicode bidirectional text algorithm via `bidi-js`
157
+ - `dir` attribute on text elements: `'ltr'` | `'rtl'` | `'auto'` for per-element control
158
+ - RTL text works with headings, paragraphs, lists, tables, and all text elements
159
+ - Automatic detection of mixed LTR/RTL content
160
+
161
+ ### Added (Phase 7E — SVG Support)
162
+ - `{ type: 'svg', svg: '<...' }` element for embedding SVG graphics
163
+ - SVG rasterization via `@napi-rs/canvas`
164
+ - ViewBox auto-sizing: automatic height calculation from viewBox aspect ratio
165
+ - Explicit sizing: `width` and `height` parameters for precise control
166
+ - Alignment options: `align: 'left' | 'center' | 'right'`
167
+ - Multi-page support: SVGs paginate correctly across page breaks
168
+ - Error code: `SVG_RENDER_FAILED` for SVG rasterization errors
169
+
170
+ ### Added (Phase 7D — Table of Contents)
171
+ - `{ type: 'toc' }` element for automatic TOC generation
172
+ - Two-pass rendering pipeline ensures accurate page numbers
173
+ - Configurable: `title`, `showTitle`, `minLevel`/`maxLevel`, dot leaders, level indentation
174
+ - Auto-indexed from heading structure (H1, H2, H3, etc.)
175
+ - Supports custom formatting via `fontSize`, `color`, `spaceAfter` parameters
176
+
177
+ ### Added (Phase 7C — Hyphenation)
178
+ - Automatic word hyphenation for better justified text layout
179
+ - `doc.hyphenation: { language: 'en-US' }` for document-level config
180
+ - Liang's algorithm via `hypher` package for accurate break points
181
+ - Configurable: `minWordLength`, `leftMin`, `rightMin`, per-element `hyphenate: false` opt-out
182
+ - Language support: includes `hyphenation.en-us` (additional languages via npm packages)
183
+ - Error code: `UNSUPPORTED_LANGUAGE` when language not available
184
+
185
+ ### Added (Phase 7B — Watermarks)
186
+ - `doc.watermark` for text or image watermarks on every page
187
+ - Text watermarks: `text`, `fontSize`, `fontWeight`, `color`, `opacity`, `rotation`
188
+ - Image watermarks: `image` (Uint8Array), `opacity`, `rotation`, `color` (tint)
189
+ - Watermarks render behind content (lower z-index)
190
+ - Rotation bounds: -360 ≤ rotation ≤ 360 degrees
191
+ - Validation: must provide either text or image, never both required
192
+
193
+ ### Added (Phase 7A — Bookmarks / PDF Outline)
194
+ - PDF sidebar bookmarks auto-generated from heading structure
195
+ - Enabled by default: `bookmarks: true` or `bookmarks: { minLevel: 1, maxLevel: 3 }`
196
+ - Level filtering: include/exclude heading levels from outline
197
+ - Per-heading opt-out: `bookmark: false` on heading elements
198
+ - Keyboard navigation: Cmd/Ctrl+Opt/Alt+O in PDF readers to toggle bookmark sidebar
199
+
200
+ ### Added (Phase 6 — Advanced Features)
201
+ - Header and footer support with {{pageNumber}} and {{totalPages}} tokens
202
+ - Text decoration: strikethrough, underline
203
+ - Text alignment: left, center, right, justify
204
+ - Line height control: custom line-height multipliers
205
+ - Column layout with multi-column content flow
206
+ - Tables with colspan/rowspan support
207
+
208
+ ### Added (Phase 5 — Rich Text / Builder API)
209
+ - Fluent builder API for programmatic document construction
210
+ - Rich text element with nested formatting (bold, italic, links)
211
+ - Inline code and code blocks with syntax highlighting
212
+ - Block quotes with custom styling
213
+ - Horizontal rules (hr element)
214
+ - Numbered and bulleted lists with nesting
215
+
216
+ ### Added (Phases 1–4 — Core Engine)
217
+ - Core PDF generation via `pdf-lib`
218
+ - Element types: paragraph, heading, table, image, list, code, blockquote
219
+ - Font support: Inter bundled, custom TTF embedding
220
+ - Document metadata: title, author, subject, keywords, created date
221
+ - Page sizing: A4, A3, A5, Letter, Legal, or custom dimensions
222
+ - Margins: top, bottom, left, right per page
223
+ - Multi-page pagination with orphan/widow control
224
+ - Image formats: PNG, JPG, WebP
225
+ - Table features: custom column widths, cell padding, borders, header styling
226
+ - Colors: hex color codes throughout (text, backgrounds, borders)
227
+
228
+ ---
229
+
230
+ ## Features by Phase
231
+
232
+ | Phase | Feature | Status | Tests | Version |
233
+ |-------|---------|--------|-------|---------|
234
+ | 7A | Bookmarks / PDF Outline | ✅ Complete | 8 | 0.1.0 |
235
+ | 7B | Watermarks | ✅ Complete | 8 | 0.1.0 |
236
+ | 7C | Hyphenation | ✅ Complete | 10 | 0.1.0 |
237
+ | 7D | Table of Contents | ✅ Complete | 10 | 0.1.0 |
238
+ | 7E | SVG Support | ✅ Complete | 8 | 0.1.0 |
239
+ | 7F | RTL Text Support | ✅ Complete | 12 | 0.1.0 |
240
+ | 7G | Encryption | ✅ Complete | 7 | 0.1.0 |
241
+ | Integration | Feature Combinations | ✅ Complete | 6 | 0.1.0 |
242
+ | 6 | Advanced Features | ✅ Complete | — | 0.1.0 |
243
+ | 5 | Rich Text / Builder API | ✅ Complete | — | 0.1.0 |
244
+ | 1–4 | Core Engine | ✅ Complete | — | 0.1.0 |
245
+
246
+ ---
247
+
248
+ ## How to Use Examples
249
+
250
+ All Phase 7 features have working examples in the `examples/` directory. Run them with:
251
+
252
+ ```bash
253
+ npm run example:watermark # Phase 7B — Watermarks
254
+ npm run example:bookmarks # Phase 7A — Bookmarks
255
+ npm run example:toc # Phase 7D — Table of Contents
256
+ npm run example:rtl # Phase 7F — RTL Text Support
257
+ npm run example:encryption # Phase 7G — Encryption
258
+ ```
259
+
260
+ PDF output is written to `output/phase7-*.pdf`.
261
+
262
+ ---
263
+
264
+ ## Test Coverage
265
+
266
+ All phases include comprehensive test coverage:
267
+
268
+ ```bash
269
+ npm test # Run all 75+ tests
270
+ npm run test:unit # Unit tests only
271
+ npm run test:e2e # End-to-end tests
272
+ npm run test:visual # Visual regression tests
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Dependencies
278
+
279
+ ### Required
280
+ - `@chenglou/pretext` — Pretext text layout engine
281
+ - `pdf-lib` — PDF document manipulation
282
+ - `@fontsource/inter` — Font: Inter (bundled)
283
+ - `bidi-js` — Bidirectional text algorithm (Phase 7F)
284
+ - `hypher` — Hyphenation algorithm (Phase 7C)
285
+ - `hyphenation.en-us` — English hyphenation patterns (Phase 7C)
286
+
287
+ ### Optional (Peer)
288
+ - `@napi-rs/canvas` — SVG rasterization (Phase 7E)
289
+ - `@cantoo/pdf-lib` — PDF encryption (Phase 7G)
290
+
291
+ ---
292
+
293
+ ## Architecture
294
+
295
+ pretext-pdf uses a modular, layered architecture:
296
+
297
+ ```
298
+ render(doc) → validate → layout → paginate → render-pages → PDF bytes
299
+ ```
300
+
301
+ Each phase adds features orthogonally:
302
+ - Phase 1–4: Core engine, pagination, typography
303
+ - Phase 5: Rich text and builder patterns
304
+ - Phase 6: Advanced layout and formatting
305
+ - Phase 7: Security, internationalization, accessibility
306
+
307
+ ---
308
+
309
+ ## Future Roadmap
310
+
311
+ Potential Phase 8+ features (not yet implemented):
312
+ - Hyperlinks and anchors
313
+ - Justified text alignment
314
+ - Enhanced text decorations
315
+ - Font subsetting for file size reduction
316
+ - Browser compatibility improvements
317
+ - Performance optimizations
318
+
319
+ ---
320
+
321
+ ## Contributing
322
+
323
+ pretext-pdf is actively maintained. To report issues, request features, or contribute:
324
+
325
+ 1. Check existing issues on the project repo
326
+ 2. Write failing tests first (TDD)
327
+ 3. Submit pull requests with test coverage ≥80%
328
+
329
+ ---
330
+
331
+ ## License
332
+
333
+ Check LICENSE file in repository root.