@laminapdf/sdk 0.2.0-alpha.3 → 0.2.0-alpha.4

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 (408) hide show
  1. package/README.md +21 -1
  2. package/dist/api.d.ts +4 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +1 -0
  5. package/dist/api.js.map +1 -1
  6. package/dist/builder.d.ts +8 -3
  7. package/dist/builder.d.ts.map +1 -1
  8. package/dist/builder.js +8 -3
  9. package/dist/builder.js.map +1 -1
  10. package/dist/document.d.ts +42 -1
  11. package/dist/document.d.ts.map +1 -1
  12. package/dist/document.js +65 -0
  13. package/dist/document.js.map +1 -1
  14. package/dist/extract-job.d.ts +100 -0
  15. package/dist/extract-job.d.ts.map +1 -0
  16. package/dist/extract-job.js +177 -0
  17. package/dist/extract-job.js.map +1 -0
  18. package/dist/extract.d.ts +1 -1
  19. package/dist/extract.d.ts.map +1 -1
  20. package/dist/extract.js.map +1 -1
  21. package/dist/generated/builder-enums.d.ts +3 -3
  22. package/dist/generated/builder-enums.d.ts.map +1 -1
  23. package/dist/generated/builder-enums.js +10 -0
  24. package/dist/generated/builder-enums.js.map +1 -1
  25. package/dist/generated/codes.d.ts +2 -2
  26. package/dist/generated/codes.d.ts.map +1 -1
  27. package/dist/generated/codes.js +55 -1
  28. package/dist/generated/codes.js.map +1 -1
  29. package/dist/generated/explain.d.ts.map +1 -1
  30. package/dist/generated/explain.js +19 -2
  31. package/dist/generated/explain.js.map +1 -1
  32. package/dist/generated/extract.d.ts +50 -3
  33. package/dist/generated/extract.d.ts.map +1 -1
  34. package/dist/source/http.d.ts +1 -1
  35. package/dist/source/http.js +1 -1
  36. package/dist/types.d.ts +19 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/dist/worker/support.d.ts +7 -1
  41. package/dist/worker/support.d.ts.map +1 -1
  42. package/dist/worker/support.js +4 -0
  43. package/dist/worker/support.js.map +1 -1
  44. package/docs/AGENTS.md +1 -1
  45. package/docs/api/README.md +20 -1
  46. package/docs/api/classes/Builder.md +1 -1
  47. package/docs/api/classes/Document.md +113 -1
  48. package/docs/api/classes/ExtractJob.md +236 -0
  49. package/docs/api/classes/Font.md +1 -1
  50. package/docs/api/classes/Image.md +1 -1
  51. package/docs/api/classes/LaminaPdfError.md +1 -1
  52. package/docs/api/classes/Page.md +1 -1
  53. package/docs/api/classes/PageRef.md +1 -1
  54. package/docs/api/classes/PageText.md +1 -1
  55. package/docs/api/classes/PageTextRun.md +1 -1
  56. package/docs/api/classes/PendingPath.md +1 -1
  57. package/docs/api/classes/SaveJob.md +1 -1
  58. package/docs/api/classes/Surface.md +10 -5
  59. package/docs/api/classes/Transaction.md +1 -1
  60. package/docs/api/functions/callbackSource.md +1 -1
  61. package/docs/api/functions/extractWithModels.md +70 -0
  62. package/docs/api/functions/httpRangeSource.md +2 -2
  63. package/docs/api/functions/init.md +1 -1
  64. package/docs/api/functions/isExtractLoaded.md +1 -1
  65. package/docs/api/functions/isInitialized.md +1 -1
  66. package/docs/api/functions/isLaminaPdfError.md +1 -1
  67. package/docs/api/functions/isTextLoaded.md +1 -1
  68. package/docs/api/functions/loadExtract.md +1 -1
  69. package/docs/api/functions/loadText.md +1 -1
  70. package/docs/api/functions/onLeak.md +1 -1
  71. package/docs/api/functions/reset.md +1 -1
  72. package/docs/api/functions/wasmMemory.md +1 -1
  73. package/docs/api/interfaces/BuilderOptions.md +1 -1
  74. package/docs/api/interfaces/ByteRange.md +1 -1
  75. package/docs/api/interfaces/ChunkOptions.md +1 -1
  76. package/docs/api/interfaces/Diagnostic.md +1 -1
  77. package/docs/api/interfaces/ExtractOptions.md +1 -1
  78. package/docs/api/interfaces/ExtractResult.md +1 -1
  79. package/docs/api/interfaces/FontInfo.md +1 -1
  80. package/docs/api/interfaces/HostModels.md +57 -0
  81. package/docs/api/interfaces/HttpRangeOptions.md +1 -1
  82. package/docs/api/interfaces/InitOptions.md +1 -1
  83. package/docs/api/interfaces/LayoutRegion.md +38 -0
  84. package/docs/api/interfaces/Leak.md +1 -1
  85. package/docs/api/interfaces/Location.md +1 -1
  86. package/docs/api/interfaces/ModelInfo.md +45 -0
  87. package/docs/api/interfaces/ModelRequest.md +45 -0
  88. package/docs/api/interfaces/Models.md +45 -0
  89. package/docs/api/interfaces/OcrWord.md +37 -0
  90. package/docs/api/interfaces/OpLog.md +1 -1
  91. package/docs/api/interfaces/OpenOptions.md +1 -1
  92. package/docs/api/interfaces/PageTextOptions.md +1 -1
  93. package/docs/api/interfaces/PathBuilder.md +1 -1
  94. package/docs/api/interfaces/QuadPoint.md +1 -1
  95. package/docs/api/interfaces/RangeOptions.md +1 -1
  96. package/docs/api/interfaces/RangeSource.md +1 -1
  97. package/docs/api/interfaces/StrokeStyle.md +1 -1
  98. package/docs/api/interfaces/TagSpec.md +3 -3
  99. package/docs/api/interfaces/TextBoxOptions.md +1 -1
  100. package/docs/api/interfaces/TextGlyph.md +1 -1
  101. package/docs/api/interfaces/TextOptions.md +1 -1
  102. package/docs/api/interfaces/WasmMemory.md +1 -1
  103. package/docs/api/type-aliases/AfRelationship.md +1 -1
  104. package/docs/api/type-aliases/Align.md +1 -1
  105. package/docs/api/type-aliases/ArtifactKind.md +2 -2
  106. package/docs/api/type-aliases/AttachmentOptions.md +1 -1
  107. package/docs/api/type-aliases/BlendMode.md +1 -1
  108. package/docs/api/type-aliases/BoxRect.md +1 -1
  109. package/docs/api/type-aliases/BuildOptions.md +1 -1
  110. package/docs/api/type-aliases/Cell.md +1 -1
  111. package/docs/api/type-aliases/Chunk.md +1 -1
  112. package/docs/api/type-aliases/Color.md +1 -1
  113. package/docs/api/type-aliases/Coordinates.md +1 -1
  114. package/docs/api/type-aliases/Direction.md +1 -1
  115. package/docs/api/type-aliases/DocumentInfo.md +1 -1
  116. package/docs/api/type-aliases/DropReason.md +2 -2
  117. package/docs/api/type-aliases/Dropped.md +1 -1
  118. package/docs/api/type-aliases/Edited.md +1 -1
  119. package/docs/api/type-aliases/ErrorCode.md +2 -2
  120. package/docs/api/type-aliases/ErrorKind.md +1 -1
  121. package/docs/api/type-aliases/ExtractFormat.md +1 -1
  122. package/docs/api/type-aliases/ExtractJobOptions.md +31 -0
  123. package/docs/api/type-aliases/ExtractStep.md +61 -0
  124. package/docs/api/type-aliases/ExtractedBlock.md +13 -1
  125. package/docs/api/type-aliases/ExtractedPage.md +9 -1
  126. package/docs/api/type-aliases/ExtractedSource.md +1 -1
  127. package/docs/api/type-aliases/Extraction.md +1 -1
  128. package/docs/api/type-aliases/FillRule.md +1 -1
  129. package/docs/api/type-aliases/Fit.md +1 -1
  130. package/docs/api/type-aliases/Flags.md +1 -1
  131. package/docs/api/type-aliases/Generator.md +5 -3
  132. package/docs/api/type-aliases/GlyphQuad.md +1 -1
  133. package/docs/api/type-aliases/InfoPatch.md +1 -1
  134. package/docs/api/type-aliases/LaminaPdfWarning.md +1 -1
  135. package/docs/api/type-aliases/LimitName.md +1 -1
  136. package/docs/api/type-aliases/Limits.md +1 -1
  137. package/docs/api/type-aliases/LineBox.md +1 -1
  138. package/docs/api/type-aliases/LineCap.md +1 -1
  139. package/docs/api/type-aliases/LineJoin.md +1 -1
  140. package/docs/api/type-aliases/LinkTarget.md +1 -1
  141. package/docs/api/type-aliases/Metadata.md +1 -1
  142. package/docs/api/type-aliases/ModelResult.md +15 -0
  143. package/docs/api/type-aliases/Op.md +1 -1
  144. package/docs/api/type-aliases/OutlineEntry.md +1 -1
  145. package/docs/api/type-aliases/OutlineNode.md +15 -0
  146. package/docs/api/type-aliases/Overflow.md +1 -1
  147. package/docs/api/type-aliases/PageInfo.md +1 -1
  148. package/docs/api/type-aliases/PageLabel.md +1 -1
  149. package/docs/api/type-aliases/PageSizeName.md +1 -1
  150. package/docs/api/type-aliases/Point.md +1 -1
  151. package/docs/api/type-aliases/Profile.md +1 -1
  152. package/docs/api/type-aliases/Progress.md +1 -1
  153. package/docs/api/type-aliases/ReadingOrder.md +1 -1
  154. package/docs/api/type-aliases/Rect.md +1 -1
  155. package/docs/api/type-aliases/Region.md +1 -1
  156. package/docs/api/type-aliases/RegionLabel.md +15 -0
  157. package/docs/api/type-aliases/RenderMode.md +1 -1
  158. package/docs/api/type-aliases/Rotation.md +1 -1
  159. package/docs/api/type-aliases/SaveOptions.md +1 -1
  160. package/docs/api/type-aliases/SaveReport.md +1 -1
  161. package/docs/api/type-aliases/Span.md +12 -1
  162. package/docs/api/type-aliases/SplitOn.md +1 -1
  163. package/docs/api/type-aliases/Standard14.md +1 -1
  164. package/docs/api/type-aliases/StructRef.md +1 -1
  165. package/docs/api/type-aliases/StructSource.md +1 -1
  166. package/docs/api/type-aliases/StructureKid.md +15 -0
  167. package/docs/api/type-aliases/StructureNode.md +16 -0
  168. package/docs/api/type-aliases/TableDetector.md +1 -1
  169. package/docs/api/type-aliases/TableMode.md +1 -1
  170. package/docs/api/type-aliases/TableScope.md +1 -1
  171. package/docs/api/type-aliases/Tag.md +1 -1
  172. package/docs/api/type-aliases/TagName.md +1 -1
  173. package/docs/api/type-aliases/Target.md +15 -0
  174. package/docs/api/type-aliases/TargetView.md +18 -0
  175. package/docs/api/type-aliases/TextLayer.md +72 -0
  176. package/docs/api/type-aliases/TextLayerStatus.md +15 -0
  177. package/docs/api/type-aliases/TextLayout.md +1 -1
  178. package/docs/api/type-aliases/TextRange.md +1 -1
  179. package/docs/api/type-aliases/TextRunInfo.md +1 -1
  180. package/docs/api/type-aliases/Transform.md +1 -1
  181. package/docs/api/type-aliases/UndoOutcome.md +1 -1
  182. package/docs/api/type-aliases/ViewerPreferences.md +1 -1
  183. package/docs/api/type-aliases/WarningCode.md +2 -2
  184. package/docs/api/type-aliases/WasmSource.md +1 -1
  185. package/docs/api/variables/Matrix.md +1 -1
  186. package/docs/api/variables/PAGE_SIZES.md +1 -1
  187. package/docs/api/variables/TAG_NAMES.md +2 -2
  188. package/docs/errors/README.md +18 -1
  189. package/docs/errors/aes-padding-invalid.md +1 -1
  190. package/docs/errors/already-initialized.md +1 -1
  191. package/docs/errors/binary-output-to-terminal.md +1 -1
  192. package/docs/errors/builder-finished.md +1 -1
  193. package/docs/errors/cancelled.md +1 -1
  194. package/docs/errors/cmap-invalid.md +1 -1
  195. package/docs/errors/collection-index.md +1 -1
  196. package/docs/errors/color-components.md +1 -1
  197. package/docs/errors/content-bad-operands.md +1 -1
  198. package/docs/errors/content-path-unpainted.md +1 -1
  199. package/docs/errors/content-resource-missing.md +1 -1
  200. package/docs/errors/content-syntax.md +1 -1
  201. package/docs/errors/content-unbalanced-bt.md +1 -1
  202. package/docs/errors/content-unbalanced-marked.md +1 -1
  203. package/docs/errors/content-unbalanced-q.md +1 -1
  204. package/docs/errors/content-unknown-operator.md +1 -1
  205. package/docs/errors/covered-text.md +33 -0
  206. package/docs/errors/data-pending.md +1 -1
  207. package/docs/errors/decompress.md +1 -1
  208. package/docs/errors/device-color-without-output-intent.md +1 -1
  209. package/docs/errors/direct-page.md +1 -1
  210. package/docs/errors/disposed.md +1 -1
  211. package/docs/errors/document-changed.md +1 -1
  212. package/docs/errors/embedded-file-forbidden.md +1 -1
  213. package/docs/errors/embedded-file-without-mime-type.md +1 -1
  214. package/docs/errors/encoding-full.md +1 -1
  215. package/docs/errors/encrypted-base.md +1 -1
  216. package/docs/errors/extract-column-order-uncertain.md +38 -0
  217. package/docs/errors/extract-limit-blocks.md +1 -1
  218. package/docs/errors/extract-module-not-loaded.md +1 -1
  219. package/docs/errors/extract-needs-ocr.md +37 -0
  220. package/docs/errors/extract-reading-order-ambiguous.md +1 -1
  221. package/docs/errors/extract-struct-tree-ignored.md +1 -1
  222. package/docs/errors/extract-table-ambiguous.md +1 -1
  223. package/docs/errors/extract-table-limit.md +1 -1
  224. package/docs/errors/extract-untagged-content.md +1 -1
  225. package/docs/errors/fetch-failed.md +3 -3
  226. package/docs/errors/flate-truncated.md +1 -1
  227. package/docs/errors/flow-content-too-large.md +34 -0
  228. package/docs/errors/flow-keep-broken.md +34 -0
  229. package/docs/errors/flow-layout-unstable.md +38 -0
  230. package/docs/errors/font-invalid.md +1 -1
  231. package/docs/errors/font-mismatch.md +1 -1
  232. package/docs/errors/font-not-embeddable.md +1 -1
  233. package/docs/errors/font-not-embedded.md +1 -1
  234. package/docs/errors/font-not-shapable.md +1 -1
  235. package/docs/errors/glyph-out-of-range.md +1 -1
  236. package/docs/errors/glyph-without-unicode.md +7 -5
  237. package/docs/errors/heading-level-skipped.md +1 -1
  238. package/docs/errors/image-data-length.md +1 -1
  239. package/docs/errors/image-too-large.md +1 -1
  240. package/docs/errors/inline-image-unterminated.md +1 -1
  241. package/docs/errors/input-unreadable.md +1 -1
  242. package/docs/errors/instance-reset.md +1 -1
  243. package/docs/errors/invalid-argument.md +1 -1
  244. package/docs/errors/invalid-axis-value.md +1 -1
  245. package/docs/errors/invalid-box.md +1 -1
  246. package/docs/errors/invalid-color.md +1 -1
  247. package/docs/errors/invalid-command-line.md +1 -1
  248. package/docs/errors/invalid-date.md +1 -1
  249. package/docs/errors/invalid-entry.md +1 -1
  250. package/docs/errors/invalid-feature.md +1 -1
  251. package/docs/errors/invalid-font.md +1 -1
  252. package/docs/errors/invalid-geometry.md +1 -1
  253. package/docs/errors/invalid-icc-profile.md +1 -1
  254. package/docs/errors/invalid-image.md +1 -1
  255. package/docs/errors/invalid-op-log.md +1 -1
  256. package/docs/errors/invalid-page-label.md +1 -1
  257. package/docs/errors/invalid-page-labels.md +1 -1
  258. package/docs/errors/invalid-page-range.md +1 -1
  259. package/docs/errors/invalid-rotate.md +1 -1
  260. package/docs/errors/invalid-spans.md +39 -0
  261. package/docs/errors/invalid-structure-nesting.md +1 -1
  262. package/docs/errors/invalid-structure.md +1 -1
  263. package/docs/errors/invalid-text-range.md +1 -1
  264. package/docs/errors/job-finished.md +1 -1
  265. package/docs/errors/limit-exceeded.md +1 -1
  266. package/docs/errors/link-without-contents.md +1 -1
  267. package/docs/errors/link-without-structure.md +1 -1
  268. package/docs/errors/markdown-html-ignored.md +33 -0
  269. package/docs/errors/markdown-image-missing.md +34 -0
  270. package/docs/errors/missing-alt-text.md +1 -1
  271. package/docs/errors/missing-glyph.md +1 -1
  272. package/docs/errors/missing-header.md +1 -1
  273. package/docs/errors/missing-lang.md +1 -1
  274. package/docs/errors/missing-root.md +1 -1
  275. package/docs/errors/missing-title.md +1 -1
  276. package/docs/errors/model-failed.md +33 -0
  277. package/docs/errors/model-needs-host.md +40 -0
  278. package/docs/errors/model-result-unexpected.md +36 -0
  279. package/docs/errors/name-tree-node-skipped.md +1 -1
  280. package/docs/errors/nested-transaction.md +1 -1
  281. package/docs/errors/no-pending-save.md +1 -1
  282. package/docs/errors/no-transaction.md +1 -1
  283. package/docs/errors/not-initialized.md +1 -1
  284. package/docs/errors/not-pdf.md +1 -1
  285. package/docs/errors/not-rebased.md +1 -1
  286. package/docs/errors/object-number-out-of-range.md +1 -1
  287. package/docs/errors/objstm-index-mismatch.md +1 -1
  288. package/docs/errors/out-of-memory.md +1 -1
  289. package/docs/errors/outline-cycle.md +1 -1
  290. package/docs/errors/outline-item-skipped.md +1 -1
  291. package/docs/errors/output-unwritable.md +1 -1
  292. package/docs/errors/overwrite-refused.md +1 -1
  293. package/docs/errors/page-count-mismatch.md +1 -1
  294. package/docs/errors/page-index-out-of-range.md +1 -1
  295. package/docs/errors/page-tree-node-skipped.md +1 -1
  296. package/docs/errors/password-required.md +1 -1
  297. package/docs/errors/path-outside-roots.md +1 -1
  298. package/docs/errors/perms-mismatch.md +1 -1
  299. package/docs/errors/profile-version-conflict.md +1 -1
  300. package/docs/errors/redaction-not-applied.md +32 -0
  301. package/docs/errors/reference-cycle.md +1 -1
  302. package/docs/errors/render-backend-unavailable.md +1 -1
  303. package/docs/errors/render-failed.md +1 -1
  304. package/docs/errors/render-too-large.md +1 -1
  305. package/docs/errors/repaired-base.md +1 -1
  306. package/docs/errors/requires-rewrite.md +1 -1
  307. package/docs/errors/revision-index-out-of-range.md +34 -0
  308. package/docs/errors/saved-not-rebased.md +1 -1
  309. package/docs/errors/sink-not-empty.md +1 -1
  310. package/docs/errors/sink.md +1 -1
  311. package/docs/errors/source-budget-exceeded.md +1 -1
  312. package/docs/errors/source-changed.md +1 -1
  313. package/docs/errors/source.md +1 -1
  314. package/docs/errors/stale-generation.md +1 -1
  315. package/docs/errors/stream-length-recovered.md +1 -1
  316. package/docs/errors/strict.md +1 -1
  317. package/docs/errors/subset-failed.md +1 -1
  318. package/docs/errors/syntax.md +1 -1
  319. package/docs/errors/tag-element-not-open.md +41 -0
  320. package/docs/errors/tag-element-unclosed.md +34 -0
  321. package/docs/errors/text-in-earlier-revision.md +36 -0
  322. package/docs/errors/text-module-not-loaded.md +1 -1
  323. package/docs/errors/text-overflow.md +1 -1
  324. package/docs/errors/tounicode-conflict.md +1 -1
  325. package/docs/errors/type.md +1 -1
  326. package/docs/errors/unexpected-eof.md +1 -1
  327. package/docs/errors/unknown-axis.md +1 -1
  328. package/docs/errors/unknown-code.md +1 -1
  329. package/docs/errors/unknown-destination.md +1 -1
  330. package/docs/errors/unknown-font.md +1 -1
  331. package/docs/errors/unknown-option.md +1 -1
  332. package/docs/errors/unknown-page.md +1 -1
  333. package/docs/errors/unmapped-glyph.md +1 -1
  334. package/docs/errors/unnumbered-heading-misused.md +1 -1
  335. package/docs/errors/unset-object.md +1 -1
  336. package/docs/errors/unsupported-filter.md +1 -1
  337. package/docs/errors/unsupported-image.md +1 -1
  338. package/docs/errors/unsupported-layout-option.md +1 -1
  339. package/docs/errors/unsupported-security-handler.md +1 -1
  340. package/docs/errors/unsupported-version.md +1 -1
  341. package/docs/errors/untagged-content.md +1 -1
  342. package/docs/errors/warnings-truncated.md +1 -1
  343. package/docs/errors/wasm-trap.md +1 -1
  344. package/docs/errors/whole-font-rebuilt.md +1 -1
  345. package/docs/errors/worker-crashed.md +1 -1
  346. package/docs/errors/worker-failed.md +1 -1
  347. package/docs/errors/worker-version-mismatch.md +1 -1
  348. package/docs/errors/would-invalidate-signatures.md +1 -1
  349. package/docs/errors/wrong-document.md +1 -1
  350. package/docs/errors/wrong-password.md +1 -1
  351. package/docs/errors/xobject-cycle.md +1 -1
  352. package/docs/errors/xref-repaired.md +1 -1
  353. package/docs/errors/xrefstm-ignored.md +1 -1
  354. package/docs/llms.txt +7 -1
  355. package/docs/pages/concepts/dependencies.md +2 -2
  356. package/docs/pages/concepts/drawing-pages.md +76 -0
  357. package/docs/pages/concepts/errors-and-warnings.md +6 -2
  358. package/docs/pages/concepts/how-lamina-thinks.md +13 -1
  359. package/docs/pages/concepts/pages-and-coordinates.md +9 -1
  360. package/docs/pages/guides/accessible-pdfs.md +3 -1
  361. package/docs/pages/guides/archival-pdfs.md +5 -1
  362. package/docs/pages/guides/edit-a-pdf.md +8 -2
  363. package/docs/pages/guides/flowing-pages.md +379 -0
  364. package/docs/pages/guides/fonts-and-text.md +3 -1
  365. package/docs/pages/guides/images-and-vectors.md +3 -1
  366. package/docs/pages/guides/keep-the-page-responsive.md +8 -4
  367. package/docs/pages/guides/links-outlines-and-metadata.md +3 -1
  368. package/docs/pages/guides/open-large-files.md +69 -0
  369. package/docs/pages/guides/password-protected-files.md +1 -1
  370. package/docs/pages/guides/save-a-pdf.md +12 -2
  371. package/docs/pages/guides/test-generated-pdfs.md +324 -0
  372. package/docs/pages/guides/untrusted-files.md +3 -1
  373. package/docs/pages/index.md +2 -2
  374. package/docs/pages/install.md +9 -5
  375. package/docs/pages/quick-start/browser.md +5 -1
  376. package/docs/pages/quick-start/bun.md +5 -1
  377. package/docs/pages/quick-start/deno.md +5 -1
  378. package/docs/pages/quick-start/node.md +5 -1
  379. package/docs/pages/quick-start/rust.md +6 -2
  380. package/docs/pages/quick-start/workers.md +2 -2
  381. package/docs/pages/recipes/cloudflare-worker.md +1 -1
  382. package/docs/pages/recipes/element-flow.md +248 -0
  383. package/docs/pages/recipes/extract-markdown.md +44 -6
  384. package/docs/pages/recipes/generate-then-edit.md +13 -6
  385. package/docs/pages/recipes/hello.md +13 -6
  386. package/docs/pages/recipes/images-and-vectors.md +13 -6
  387. package/docs/pages/recipes/invoice.md +13 -6
  388. package/docs/pages/recipes/links-and-outlines.md +13 -6
  389. package/docs/pages/recipes/multilingual.md +13 -6
  390. package/docs/pages/recipes/open-untrusted.md +1 -1
  391. package/docs/pages/recipes/pdf-a-archive.md +13 -6
  392. package/docs/pages/recipes/pdf-a3-invoice-with-xml.md +13 -6
  393. package/docs/pages/recipes/pdf-ua-report.md +13 -6
  394. package/docs/pages/recipes/report.md +2 -2
  395. package/docs/pages/recipes/web-worker-client.md +1 -1
  396. package/docs/pages/recipes.md +3 -2
  397. package/docs/pages/reference/benchmarks.md +93 -0
  398. package/docs/pages/reference/changelog.md +49 -1
  399. package/docs/pages/reference/codes.md +1 -1
  400. package/docs/pages/reference/glossary.md +1 -1
  401. package/docs/pages/reference/rust.md +11 -11
  402. package/docs/pages/reference/stability.md +3 -3
  403. package/docs/pages/start/coding-agents.md +1 -1
  404. package/docs/pages/start/first-pdf.md +6 -2
  405. package/docs/pages/troubleshooting.md +1 -1
  406. package/docs/schemas/error.schema.json +18 -1
  407. package/package.json +4 -2
  408. package/schemas/error.schema.json +18 -1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Multilingual text"
3
3
  description: "Latin, Arabic, Devanagari, Hebrew and Chinese on one page, each in its own embedded font, as a shaped line and a wrapped paragraph."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/multilingual/"
6
6
  ---
7
7
 
@@ -13,7 +13,9 @@ You'll put five scripts on one page: Latin, Arabic, Devanagari, Hebrew and Chine
13
13
 
14
14
  The function takes one font file per script, draws each script's line and paragraph, and returns the PDF's bytes. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
15
15
 
16
- <TabItem label="TypeScript">`packages/sdk/examples/multilingual.ts`:
16
+ **TypeScript**
17
+
18
+ `packages/sdk/examples/multilingual.ts`:
17
19
 
18
20
  ```ts
19
21
  // Five scripts on one page, each as a single line and as a wrapped paragraph. The scripts are
@@ -69,8 +71,11 @@ export function multilingual(fonts: readonly Uint8Array[], options: BuilderOptio
69
71
  using doc = b.finish();
70
72
  return doc.save();
71
73
  }
72
- ```</TabItem>
73
- <TabItem label="Rust">`crates/laminapdf/examples/multilingual.rs`:
74
+ ```
75
+
76
+ **Rust**
77
+
78
+ `crates/laminapdf/examples/multilingual.rs`:
74
79
 
75
80
  ````rust
76
81
  //! Five scripts on one page, each as a single line and as a wrapped paragraph.
@@ -167,9 +172,11 @@ pub(crate) fn build(options: BuildOptions, fonts: Vec<Vec<u8>>) -> Result<Vec<u8
167
172
  let mut doc = b.finish()?;
168
173
  Ok(doc.save(&SaveOptions::new())?.bytes)
169
174
  }
170
- ````</TabItem>
175
+ ````
176
+
177
+ **Result:** [multilingual.pdf](https://docs.laminapdf.com/examples/pdf/multilingual.pdf)
171
178
 
172
- The result is one A4 page, with each script set in its own Noto font: [open the reference PDF](https://docs.laminapdf.com/examples/pdf/multilingual.pdf).
179
+ The result is one A4 page, with each script set in its own Noto font. The Result tab shows it, with a link to the PDF.
173
180
 
174
181
  ## How it works
175
182
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Open someone else's file"
3
3
  description: "Open an uploaded PDF with an optional password and tighter limits, and get its page count and warnings, or the error, back as a value."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/open-untrusted/"
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "A PDF/A archive"
3
3
  description: "An order confirmation for long-term archiving, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1, with an embedded font and a photo."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/pdf-a-archive/"
6
6
  ---
7
7
 
@@ -13,7 +13,9 @@ You'll write a letter confirming an order as a PDF/A file, which looks the same
13
13
 
14
14
  The function takes the level, `2b` or `2u`, and builds the same letter under that level's profiles. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
15
15
 
16
- <TabItem label="TypeScript">`packages/sdk/examples/pdf-a-archive.ts`:
16
+ **TypeScript**
17
+
18
+ `packages/sdk/examples/pdf-a-archive.ts`:
17
19
 
18
20
  ```ts
19
21
  // An archival letter, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1.
@@ -78,8 +80,11 @@ function draw(s: Surface, font: Font, photo: Image): void {
78
80
  s.text("Acme Widgets Ltd, 1 Example Street, London", { font, size: BODY, at: [MARGIN, FOOTER_BASELINE] }),
79
81
  );
80
82
  }
81
- ```</TabItem>
82
- <TabItem label="Rust">`crates/laminapdf/examples/pdf_a_archive.rs`:
83
+ ```
84
+
85
+ **Rust**
86
+
87
+ `crates/laminapdf/examples/pdf_a_archive.rs`:
83
88
 
84
89
  ```rust
85
90
  //! An archival letter, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1.
@@ -182,9 +187,11 @@ fn draw(s: &mut Surface, font: &FontHandle, photo: &Image) -> Result<(), BuildEr
182
187
  let footer = "Acme Widgets Ltd, 1 Example Street, London";
183
188
  s.tag(TagKind::P, |s| s.text(footer, font, BODY, FOOTER_AT).map(drop))
184
189
  }
185
- ```</TabItem>
190
+ ```
191
+
192
+ **Result:** [pdf_a_archive-2b.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2b.pdf), [pdf_a_archive-2u.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2u.pdf)
186
193
 
187
- The result is one A4 letter under a translucent blue band, with a photo beside its text: open the [PDF/A-2b](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2b.pdf) or the [PDF/A-2u](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2u.pdf) reference PDF.
194
+ The result is one A4 letter under a translucent blue band, with a photo beside its text: the Result tab shows both versions, PDF/A-2b and PDF/A-2u, with links to the PDFs.
188
195
 
189
196
  ## How it works
190
197
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "A PDF/A-3 invoice with XML"
3
3
  description: "A PDF/A-3b invoice that carries the same invoice as an attached XML file, for people to read and for software to process."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/pdf-a3-invoice-with-xml/"
6
6
  ---
7
7
 
@@ -13,7 +13,9 @@ You'll write a one-page invoice as PDF/A-3b, with the same invoice attached as X
13
13
 
14
14
  The function draws the invoice, writes the same items as XML and attaches that file before it finishes. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
15
15
 
16
- <TabItem label="TypeScript">`packages/sdk/examples/pdf-a3-invoice-with-xml.ts`:
16
+ **TypeScript**
17
+
18
+ `packages/sdk/examples/pdf-a3-invoice-with-xml.ts`:
17
19
 
18
20
  ```ts
19
21
  // A PDF/A-3b invoice that carries the same invoice as XML, attached for software to read.
@@ -98,8 +100,11 @@ function draw(s: Surface, font: Font): void {
98
100
  link: { target: { type: "uri", uri: "https://example.com/invoices/42" }, contents: "Invoice 42 online" },
99
101
  });
100
102
  }
101
- ```</TabItem>
102
- <TabItem label="Rust">`crates/laminapdf/examples/pdf_a3_invoice_with_xml.rs`:
103
+ ```
104
+
105
+ **Rust**
106
+
107
+ `crates/laminapdf/examples/pdf_a3_invoice_with_xml.rs`:
103
108
 
104
109
  ```rust
105
110
  //! A PDF/A-3b invoice that carries the same invoice as XML, attached for software to read.
@@ -200,9 +205,11 @@ fn draw(s: &mut Surface, font: &FontHandle) -> Result<(), BuildError> {
200
205
  note.link(online, Some("Invoice 42 online".into()));
201
206
  Ok(())
202
207
  }
203
- ```</TabItem>
208
+ ```
209
+
210
+ **Result:** [pdf_a3_invoice_with_xml.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a3_invoice_with_xml.pdf)
204
211
 
205
- The result is one A4 page with three line items and a total of € 99.40, carrying `invoice-42.xml`: [open the reference PDF](https://docs.laminapdf.com/examples/pdf/pdf_a3_invoice_with_xml.pdf). Viewers that show attachments list it there.
212
+ The result is one A4 page with three line items and a total of € 99.40, carrying `invoice-42.xml`. The Result tab shows it, with a link to the PDF. Viewers that show attachments list it there.
206
213
 
207
214
  ## How it works
208
215
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "A PDF/UA report"
3
3
  description: "A one-page sales report a screen reader can follow, with headings, a table, a described chart and a link, checked against PDF/UA-1 as it's built."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/pdf-ua-report/"
6
6
  ---
7
7
 
@@ -13,7 +13,9 @@ You'll build a one-page sales report that a screen reader can follow: headings,
13
13
 
14
14
  The function turns on the PDF/UA-1 profile, then draws each part of the report inside a tag that says what it is: a heading, a table cell, a figure. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
15
15
 
16
- <TabItem label="TypeScript">`packages/sdk/examples/pdf-ua-report.ts`:
16
+ **TypeScript**
17
+
18
+ `packages/sdk/examples/pdf-ua-report.ts`:
17
19
 
18
20
  ```ts
19
21
  // An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
@@ -110,8 +112,11 @@ function chart(s: Surface): void {
110
112
  });
111
113
  });
112
114
  }
113
- ```</TabItem>
114
- <TabItem label="Rust">`crates/laminapdf/examples/pdf_ua_report.rs`:
115
+ ```
116
+
117
+ **Rust**
118
+
119
+ `crates/laminapdf/examples/pdf_ua_report.rs`:
115
120
 
116
121
  ```rust
117
122
  //! An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
@@ -214,9 +219,11 @@ fn chart(s: &mut Surface) -> Result<(), BuildError> {
214
219
  Ok(())
215
220
  })
216
221
  }
217
- ```</TabItem>
222
+ ```
223
+
224
+ **Result:** [pdf_ua_report.pdf](https://docs.laminapdf.com/examples/pdf/pdf_ua_report.pdf)
218
225
 
219
- The result is one A4 page that reads, in order, as a title, a summary, a table of four quarters, a bar chart and a link: [open the reference PDF](https://docs.laminapdf.com/examples/pdf/pdf_ua_report.pdf).
226
+ The result is one A4 page that reads, in order, as a title, a summary, a table of four quarters, a bar chart and a link. The Result tab shows it, with a link to the PDF.
220
227
 
221
228
  ## How it works
222
229
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "A 100-page report"
3
3
  description: "A 100-page A4 report with two embedded fonts and a table on every page, the document Lamina PDF times in each JavaScript runtime."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/report/"
6
6
  ---
7
7
 
@@ -104,7 +104,7 @@ function cell([left, width]: readonly [number, number], baseline: number): Rect
104
104
  }
105
105
  ```
106
106
 
107
- The result is 100 A4 pages, one per region. It has no reference PDF to open. Instead, Lamina PDF's tests build and time the report in every JavaScript runtime and check its SHA-256 there, as does the Rust benchmark that builds the same bytes.
107
+ The result is 100 A4 pages, one per region. It has no reference PDF to open. Instead, Lamina PDF's tests build and time the report in every JavaScript runtime and check its SHA-256 there, as does the Rust benchmark that builds the same bytes. [Benchmarks](../../pages/reference/benchmarks.md) has the timings.
108
108
 
109
109
  ## How it works
110
110
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Save in a Web Worker"
3
3
  description: "Open and save a PDF in a Web Worker, so a large file never freezes the page, with progress as it saves and a signal that stops the work."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/web-worker-client/"
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Recipes"
3
3
  description: "Complete Lamina PDF programs, from one page of text to an archived invoice, each with its code and the PDF it writes."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/recipes/"
6
6
  ---
7
7
 
@@ -11,7 +11,7 @@ Complete Lamina PDF programs, from one page of text to an archived invoice, each
11
11
 
12
12
  Each recipe is a complete program to copy: what it makes, the code, how it works and what to change. Pick the one closest to the document you need, and change it from there.
13
13
 
14
- Most recipes exist twice, in Rust and in TypeScript, and both write exactly the same bytes. Lamina PDF's tests check that on every change, in Rust and in every JavaScript runtime: Node, Chromium, Firefox, WebKit, Deno, Bun and workerd. Each recipe shows the tested code, and its reference PDF is the file that code writes.
14
+ Most recipes exist twice, in Rust and in TypeScript, and both write exactly the same bytes. Lamina PDF's tests check that on every change, in Rust and in every JavaScript runtime: Node, Chromium, Firefox, WebKit, Deno, Bun and workerd. Each recipe shows the tested code, and its reference PDF is the file that code writes. To test your own PDFs the same way, see [Test the PDFs you generate](../pages/guides/test-generated-pdfs.md).
15
15
 
16
16
  To run a Rust recipe from a checkout of Lamina PDF, use `cargo run -p laminapdf --example <name>`. Its header comment lists the arguments it takes, such as the font or image files it reads.
17
17
 
@@ -21,6 +21,7 @@ To run a Rust recipe from a checkout of Lamina PDF, use `cargo run -p laminapdf
21
21
  - [An invoice](../pages/recipes/invoice.md): an embedded font, a table of line items, and tags for screen readers.
22
22
  - [Multilingual text](../pages/recipes/multilingual.md): five scripts, each in its own embedded font.
23
23
  - [Images and vectors](../pages/recipes/images-and-vectors.md): paths, colour, transparency, a clip and two images.
24
+ - [Element flow](../pages/recipes/element-flow.md): a report whose parts each start below the one before, over two pages.
24
25
  - [Links and outlines](../pages/recipes/links-and-outlines.md): links, an outline and page labels.
25
26
 
26
27
  ## Edit a PDF
@@ -0,0 +1,93 @@
1
+ ---
2
+ title: "Benchmarks"
3
+ description: "How fast Lamina PDF makes PDFs in each runtime, how large its WebAssembly files are, and how well it extracts text on a public benchmark."
4
+ version: "0.2.0-alpha.4"
5
+ url: "https://docs.laminapdf.com/reference/benchmarks/"
6
+ ---
7
+
8
+ # Benchmarks
9
+
10
+ How fast Lamina PDF makes PDFs in each runtime, how large its WebAssembly files are, and how well it extracts text on a public benchmark.
11
+
12
+ These are Lamina PDF's measured numbers: how long it takes to make a PDF in each runtime, how much your app downloads, and how well it extracts text from a public benchmark of real pages. Each table states the version, the date and the machine it came from, so you can judge how the numbers apply to yours.
13
+
14
+ ## How long a PDF takes to make
15
+
16
+ Each figure is the time to build a document and save it to bytes, after the WebAssembly module has loaded. Every runtime builds the same three documents and gets the same bytes:
17
+
18
+ - **First PDF:** the first one-page "Hello" PDF after `init()`, before the runtime has optimised anything.
19
+ - **Hello:** the same PDF afterwards, the median of 20 builds.
20
+ - **One-page invoice:** the [invoice recipe](../../pages/recipes/invoice.md), a tagged A4 page with an embedded font and a table of items, the median of 20 builds.
21
+ - **100-page report:** the [report recipe](../../pages/recipes/report.md), with two embedded fonts and a table on every page, the median of 3 builds.
22
+
23
+ | Runtime | Version | First PDF | Hello | One-page invoice | 100-page report | WebAssembly memory |
24
+ | --- | --- | ---: | ---: | ---: | ---: | ---: |
25
+ | Node 24 | 24.19.0 | 19.8 ms | 0.8 ms | 3.5 ms | 222 ms | 4.3 MB |
26
+ | Deno | 2.9.6 | 23.8 ms | 0.7 ms | 3.6 ms | 238 ms | 4.3 MB |
27
+ | Bun | 1.4.4 | 14.9 ms | 1.4 ms | 3.6 ms | 151 ms | 4.3 MB |
28
+ | Cloudflare Workers (workerd) | 4.152.0 | 25.0 ms | 2.0 ms | 5.0 ms | 226 ms | 4.3 MB |
29
+ | Chromium | 1.64.1 | 18.3 ms | 0.7 ms | 3.7 ms | 215 ms | 4.3 MB |
30
+ | Firefox | 1.64.1 | 2.0 ms | 1.0 ms | 5.0 ms | 313 ms | 4.3 MB |
31
+ | WebKit (Safari's engine) | 1.64.1 | 28.0 ms | 2.5 ms | 4.0 ms | 169 ms | 4.3 MB |
32
+ | Rust, native | 1.99.1 | – | – | 0.9 ms | 45.9 ms | – |
33
+
34
+ Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.2 when the run began.
35
+
36
+ The browsers run in Playwright at the version shown, and Cloudflare Workers run in workerd through wrangler. WebAssembly memory is the modules' memory after the reports, in megabytes of 1,000,000 bytes. It never shrinks, so it is their peak. The JavaScript heap isn't included. The native Rust row is the same invoice and report built by the `laminapdf` crate, the median build as measured by criterion, a Rust benchmarking library.
37
+
38
+ ## How much your app downloads
39
+
40
+ `@laminapdf/sdk` loads one WebAssembly file, chosen by what you use. `base` reads, edits and saves documents and draws shapes and images; `text` adds fonts and text; `extract` adds text extraction without the fonts. Each file has a size budget, and a change that grows a file past its budget can't be merged until the budget is raised on purpose.
41
+
42
+ | File | Gzip | Brotli | Budget (gzip) |
43
+ | --- | ---: | ---: | ---: |
44
+ | `lamina_pdf_base.wasm` | 400.0 kB | 318.2 kB | 410.0 kB |
45
+ | `lamina_pdf_extract.wasm` | 668.1 kB | 519.0 kB | 690.0 kB |
46
+ | `lamina_pdf_pdfium.wasm` | 2,158.0 kB | 1,653.6 kB | 2,243.2 kB |
47
+ | `lamina_pdf_render_hayro.wasm` | 1,781.7 kB | 1,392.4 kB | 1,855.0 kB |
48
+ | `lamina_pdf_text.wasm` | 1,153.0 kB | 875.5 kB | 1,200.0 kB |
49
+ | `@laminapdf/sdk` (JavaScript) | 19.2 kB | – | 20.0 kB |
50
+ | `@laminapdf/sdk/worker` (JavaScript) | 4.7 kB | – | 5.0 kB |
51
+ | `@laminapdf/sdk/worker/entry` (JavaScript) | 19.2 kB | – | 20.0 kB |
52
+
53
+ Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.2 when the run began.
54
+
55
+ Sizes are in kilobytes of 1,000 bytes, as a server sends them compressed. The JavaScript rows are `@laminapdf/sdk`'s code, minified: its API with the code that loads the WebAssembly, then the Web Worker client and the file that runs in the Web Worker.
56
+
57
+ ## How well it extracts text
58
+
59
+ [olmOCR-bench](https://huggingface.co/datasets/allenai/olmOCR-bench), by the Allen Institute for AI, checks extracted text with small tests. A test checks that one passage comes before another, that a table cell sits beside its neighbours, or that a page's running header is left out. These figures use the three subsets made of pages that store their text, not scans, and the benchmark's own tests score the Markdown that Lamina PDF writes.
60
+
61
+ | Subset | What it checks | Pages | Tests | Passed | Score |
62
+ | --- | --- | ---: | ---: | ---: | ---: |
63
+ | `multi_column` | reading order: 884 tests that one passage comes before another, on 231 multi-column pages | 231 | 884 | 461 | 52.1 % |
64
+ | `table_tests` | tables: 1,020 tests that a cell's neighbours (up, down, left, right, headings) are right, and 2 baseline tests, on 188 pages | 188 | 1,022 | 245 | 24.0 % |
65
+ | `headers_footers` | running headers, footers and page numbers left out: 753 tests, and 7 baseline tests, on 266 pages | 266 | 760 | 457 | 60.1 % |
66
+ | Baseline | the page gave text, without long repeats (one test per page) | – | 676 | 578 | 85.5 % |
67
+
68
+ Overall, as the benchmark averages its groups, 55.4 %; without the baseline group, 45.4 %. 672 pages were extracted and 13 failed. On one thread that is 428 pages a second, with a median of 2.0 ms a page.
69
+
70
+ Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.7 when the run began.
71
+
72
+ Every page in the benchmark is a file of its own, so the time per page includes opening the file. A page with no text, such as a scan, counts against the score, as it would for you. Lamina PDF reads one page at a time on one thread here, without a layout model or OCR.
73
+
74
+ ### Also looking for tables without ruled lines
75
+
76
+ Most tables in the benchmark have no ruled lines. Extraction finds tables like these when you ask it to look for text lined up in columns too: `tables: "lattice-and-stream"` in TypeScript, `TableMode::LatticeAndStream` in Rust. It finds more tables, but it reads some multi-column pages as tables, which costs those pages their reading order.
77
+
78
+ | Subset | What it checks | Pages | Tests | Passed | Score |
79
+ | --- | --- | ---: | ---: | ---: | ---: |
80
+ | `multi_column` | reading order: 884 tests that one passage comes before another, on 231 multi-column pages | 231 | 884 | 131 | 14.8 % |
81
+ | `table_tests` | tables: 1,020 tests that a cell's neighbours (up, down, left, right, headings) are right, and 2 baseline tests, on 188 pages | 188 | 1,022 | 480 | 47.0 % |
82
+ | `headers_footers` | running headers, footers and page numbers left out: 753 tests, and 7 baseline tests, on 266 pages | 266 | 760 | 456 | 60.0 % |
83
+ | Baseline | the page gave text, without long repeats (one test per page) | – | 676 | 578 | 85.5 % |
84
+
85
+ Overall, as the benchmark averages its groups, 51.8 %; without the baseline group, 40.6 %. 672 pages were extracted and 13 failed. On one thread that is 375 pages a second, with a median of 2.0 ms a page.
86
+
87
+ Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.4 when the run began.
88
+
89
+ ## Where these numbers come from
90
+
91
+ One command runs every measurement on one machine and writes the file this page reads, so no figure here is typed by hand. The numbers are one machine's, taken before a release. Each version of these docs keeps the numbers measured for it. Each table gives the machine's load average as its run began: how many jobs were running or waiting for a processor. A load average well above the core count means other jobs shared the machine, so the timings are slower than its best.
92
+
93
+ Next: [make your first PDF](../../pages/start/first-pdf.md) and time it on your own machine.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Changelog"
3
3
  description: "What changed in each Lamina PDF release, newest first."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/reference/changelog/"
6
6
  ---
7
7
 
@@ -11,6 +11,54 @@ What changed in each Lamina PDF release, newest first.
11
11
 
12
12
  Every Lamina PDF package shares one version, so each entry covers all of them, from the Rust crates to `@laminapdf/sdk` and the viewer. Breaking changes come first, under **Minor Changes**, as the [stability policy](../../pages/reference/stability.md) explains. Versions from `0.2.0-alpha.2` on are on npm and crates.io; earlier ones were never published.
13
13
 
14
+ ## 0.2.0-alpha.4
15
+
16
+ ### Minor Changes
17
+
18
+ - Extraction now leaves out text painted over by a later shape, image or annotation, as a reader can't see it either. A black box drawn over two words of a line takes those words out and keeps the rest of the line, so `Pay [box] now.` reads `Pay now.`. Covered text is listed under `dropped` with the new reason `covered`, its box and how many characters it held, never its text; `drop: { keepSpans: true }` shows it to an auditor. Only opaque paint drawn after the text covers it. A translucent box, a highlighter, shading under the text, a box in an optional layer and a scanned page's image over its own text layer all leave the text in. For Rust callers, `Flags` gains `covered`, `DropReason` gains `Covered`, and `BlendMode` now lives in `laminapdf-model` (`laminapdf::BlendMode` is unchanged).
19
+ - Running headers, footers and watermarks can now say what they are. `surface.artifact("footer", s => …)` marks its content as a footer attached to the bottom of the page (`/Subtype /Footer /Attached [/Bottom]`), `"header"` as a header attached to the top, and `"watermark"` as a watermark. `"pagination"` still writes the plain form. In Rust it is `Artifact::footer()`, `Artifact::header()` and `Artifact::watermark()`, with `with_attached` for other edges.
20
+
21
+ A paragraph split by a page break can now stay one paragraph for screen readers. In Rust, `surface.open_element(TagKind::P)` places it, `surface.resume(id, |s| …)` draws its content on that page or a later one, and `builder.close_element(id)` writes it.
22
+
23
+ `surface.measure_text_box(…)` (Rust) returns the layout `text_box` would draw, without drawing it.
24
+
25
+ Arabic text with diacritics now builds under PDF/UA-1 and PDF/A-2u: a letter the font draws as a body and a dot no longer fails with `glyph-without-unicode`.
26
+ - Rust flows can now have footnotes, a contents page and bookmarks. A footnote is a raised number in the text, numbered through the flow, with its note at the foot of the same page; a line whose notes don't fit moves to the next page with them. A contents page lists the headings with dot leaders, the page each one starts on and a link to it. The flow is laid out a second time to fill in the page numbers, and the new error code `flow-layout-unstable` reports a fault if they ever fail to settle. Every heading gets a bookmark in the document's outline, nested by level, which `Flow::with_outline(false)` turns off. Tagged documents can also use the `TOC`, `TOCI` and `Reference` structure types, which `@laminapdf/sdk` now accepts as tag names.
27
+ - Rust callers can now pour a document into as many pages as it needs. `Builder::flow` takes blocks (headings, paragraphs of styled text and links, lists, figures, spacers, page breaks and groups kept together) and a page template. The template sets the margins, a header, a footer and an optional different first page. Paragraphs split only between lines, leaving at least two lines at the foot and the head of a page. Headings stay with what follows them, and figures move whole. Headers and footers can show `{page}`, `{pages}`, `{section}` and `{title}`, so "Page 3 of 12" is right on every page. The output is tagged: each paragraph stays one element across pages, and headers and footers are marked as page furniture. New codes: `flow-content-too-large` for a line or figure taller than a page, and the warning `flow-keep-broken` for blocks kept together that can't fit on one page. The TypeScript package doesn't have flows yet.
28
+ - Rust flows can now hold tables that run across pages. A table's header rows repeat at the top of every page it continues on, no body row is split between pages, and its footer rows, such as a total, stay on the page of the last body row. Each column takes a fixed width, a share of the free width, or its widest cell's width, and the widths are worked out once so the columns line up on every page. Cells hold paragraphs, can span columns and align their text; a table sets its cells' padding and can have a frame, rules and a shaded header. The output is tagged as one table across all its pages, and the repeated header rows are marked as page furniture, so screen readers and text extraction read the header once. Tagged documents can also use the `THead`, `TBody` and `TFoot` structure types, which `@laminapdf/sdk` now accepts as tag names.
29
+ - Rust callers can now turn Markdown into flowing, tagged pages: `Builder::markdown(text, &MarkdownBuildOptions)` reads CommonMark with tables, footnotes, strikethrough and task lists, takes the title, language, author and subject from front matter, and lays the document out with the flow layer. Links to `#a-heading` go to that heading, and a table runs across pages with its header repeated. Images come only from the caller, through `MarkdownBuildOptions::with_image`; nothing is fetched. Raw HTML and images that weren't passed are left out with the warnings `markdown-html-ignored` and `markdown-image-missing`, which give the position in the Markdown, never its text.
30
+
31
+ If you pass no fonts, the builder sets the document in Helvetica and Courier, which flows can now use. They set Latin text only, and a PDF/UA-1 build refuses them.
32
+
33
+ Flows also gain code spans and code blocks, struck-out text, block quotes (`BlockQuote`), thematic breaks and lists that start at any number. The `laminapdf` crate's new `markdown` feature is on by default.
34
+ - Text runs and text boxes now say where the next element can start. What `surface.text()` and `surface.textBox()` return has a `bottom`: the bottom of the last line that draws something, where the next text box's top can go. In Rust it is `TextRun::bottom()` and `TextLayout::bottom()`. It is left out when nothing is drawn, such as empty text, text of only white space, or a box too short for one line, so an empty section adds no gap. A clipped box gives its last drawn line; check `overflow !== undefined` before treating the text as placed.
35
+ - Read a document's outline and named destinations, and move through it with thumbnails. `Document.outline()` gives the outline's items with their titles, whether each starts expanded, and where each goes: a page and a view in page space (points from the displayed page's top-left, y down), whichever coordinates the file used. `Document.namedDestination(name)` finds one named destination. Both need the extract or text module, like `page.text()`.
36
+
37
+ In `@laminapdf/viewer`, `ViewerClient.outline()` and `namedDestination(name)` read them in the document Web Worker, and `Viewer.goToDestination(target)` shows an item's or a destination's target, with each kind of fit. `ThumbnailStrip` is a list of the pages as small pictures. It mounts only the thumbnails near its view, renders after the main view's pages and goes to a page on a click or a key.
38
+ - `doc.structureTree()` reads a tagged document's structure tree: its elements in reading order, down to the marked content each owns on a page. Each element gives its standard type (`H1`, `P`, `LI`, `Figure` …), alternate text, language and actual text; custom types resolve through the role map. A text run's `mcid` links it to its element, so a viewer can give assistive technology a document's headings, paragraphs, lists and tables.
39
+
40
+ `doc.isTagged` says whether the document claims to be tagged. Both need the extract or text module, as `page.text()` does. For Rust callers, `Document::structure_tree()` returns `StructureNode`s.
41
+ - Rust callers can now lay out a paragraph whose words change font, size or language: a bold word inside a sentence, a superscript, an Arabic name in an English line. `laminapdf_text::break_spans` takes the text and a list of `StyledSpan`s, each covering a stretch of it with its own fonts, size, baseline rise, language and OpenType features. Lines still break only where the text allows, so a style change inside a word never splits it. Spans of one style are shaped together, so kerning carries across them. Each line reports its ascent and descent from its tallest run, and `pdf_line_run` draws a superscript's rise. `break_lines` is unchanged. Spans that don't cover the text once, in order, that split a letter from its accent, or that name no font or a font past the list fail with the new error code `invalid-spans`.
42
+ - The Rust façade reads a document's outline (`Document::outline()`) and named destinations (`Document::named_destination(name)`), each target a page index and a view in page space. The extract and text modules give them to JavaScript as `WasmDocument.outline()` and `namedDestination(name)`.
43
+ - The viewer is sharp at every zoom level. It sized each page's canvas and sharp tiles from the page's CSS width times the pixel ratio, while the renderer sizes the page in 32-bit floats, so at most zoom levels the right-hand tile came out one pixel wider than the page. The renderer refused it, and the rest of the page stayed blurry. `@laminapdf/render` now exports `pagePixels`, the page's size in pixels at a scale as its planner computes it, and the viewer sizes canvases and tiles with it.
44
+ - The viewer keeps the page in view sharp at every zoom up to 800 %. Each page's canvas now holds at most 8 million pixels; a larger page keeps that canvas as a backdrop, and a detail canvas over the part in view takes the sharp tiles at the full pixel ratio. The detail canvas's size follows the viewport rather than the zoom, so the canvases fit the same memory as before. `createViewer` takes a `detailPool` option, and the render stats count `detailCanvases`.
45
+ - Find now lists its results. `viewer.find.results()` gives every match found so far in document order, each with its page and a snippet of the text around it, and `goTo(ordinal)` goes to one. The web reader shows them in a Results tab in the sidebar while find is open.
46
+ - Find text across a whole document. `viewer.find` searches from the current page forward and wraps round, so scrolling never waits. Results stream in by page, and the first match shows as soon as it's found. `next()` and `previous()` move between matches and scroll each into view, and the matches on the page are highlighted. Options cover case, whole words and diacritics. Match counts agree with pdf.js's find. `ViewerClient.find(query, options, pages)` is the call underneath.
47
+ - The document worker now counts every network request it makes from the moment it starts: `client.networkLog()` returns them all, with the requests its Content Security Policy blocked, and the `network` and `csp-violation` events report each as it happens. `watchNetwork` does the counting and is exported for the page too: it wraps `fetch`, `XMLHttpRequest`, `WebSocket` and `sendBeacon` and reads everything else the browser loads from Resource Timing.
48
+ - The viewer opens remote PDFs: `client.open({ url })` makes the document worker fetch the file itself with HTTP Range requests, so its bytes never pass through the page. Lamina PDF reads the file range by range, and a render fetches the bytes it needs, so page 1 of a large file appears after a small part of it has arrived. Requests send no cookies or referrer and skip the HTTP cache. A server that ignores `Range` sends the whole file, which the viewer accepts up to 256 MiB. The new `progress` event reports how much has been read.
49
+ - Every page's text is selectable and copyable, and a tagged document reads well in a screen reader. The viewer lays one transparent span over each text run of Lamina PDF's extraction, aligned to the rendered glyphs at every zoom and rotation, in any script. A selection runs from one page into the next, and the pages it touches stay mounted while you scroll away. Copy writes the extracted text in reading order. A tagged document's structure tree becomes a hidden tree of headings, paragraphs, lists, tables and figures that owns the spans.
50
+
51
+ `createViewer`'s `text` option turns the layer off or sets `outline`, `untaggedLabel` and `onSelection`. `Viewer.keepMounted(pages)` pins pages. `ViewerClient.pageText(index)` and `structure()` give a page's runs and glyph quads and the document's structure tree. The document Web Worker loads the extract module once the render backend is ready, so the first page never waits for it.
52
+
53
+ ### Patch Changes
54
+
55
+ - `ViewerClient.open` now returns the document's title from its metadata as `title`, when the file has one, so an app can name its window after the document.
56
+ - A mouse drag selects a page's text again. The layer slots above the text covered the whole page and took every press; every slot but `text` now lets the pointer through. A layer added with `addLayer` gets such a slot too, so an element in it that should be clicked, such as a link, sets `pointer-events: auto` on itself.
57
+
58
+ A selection's colour no longer hides the text it selects: the text layer (`.lamina-text-layer`) now has `mix-blend-mode: multiply`, so an opaque `::selection` tint shows under the ink.
59
+ - The page no longer flickers while zooming. Each pause in a pinch or ctrl+wheel zoom repainted the page for its new zoom with the blurry low-resolution pass, throwing away the sharp pixels it showed; the repaint now keeps those pixels, scaled, until the sharp tiles for the new zoom replace them.
60
+ - When you zoom out far enough that more than three pages show, every page now turns sharp. Before, the first three did and the rest stayed blurry for good, because the canvas pool's rounding to whole pixels counted as a cap and every page waited for one of three detail canvases.
61
+
14
62
  ## 0.2.0-alpha.3
15
63
 
16
64
  ### Minor Changes
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Error and warning codes"
3
3
  description: "Every code Lamina PDF raises, generated from fixtures/codes.json when the site is built."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/reference/codes/"
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Glossary"
3
3
  description: "The PDF and Lamina PDF terms the docs use, each in a sentence or two."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/reference/glossary/"
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Rust API (rustdoc)"
3
3
  description: "Where to read the API documentation of the Lamina PDF crates."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/reference/rust/"
6
6
  ---
7
7
 
@@ -9,19 +9,19 @@ url: "https://docs.laminapdf.com/reference/rust/"
9
9
 
10
10
  Where to read the API documentation of the Lamina PDF crates.
11
11
 
12
- docs.rs builds the API documentation of every Lamina PDF crate on crates.io. Start with [`laminapdf` on docs.rs](https://docs.rs/laminapdf/0.2.0-alpha.3/laminapdf/), the crate to depend on. It wraps the core crates and holds `Document`, `Builder`, `Error`, `Warning`, jobs and `CancelToken`.
12
+ docs.rs builds the API documentation of every Lamina PDF crate on crates.io. Start with [`laminapdf` on docs.rs](https://docs.rs/laminapdf/0.2.0-alpha.4/laminapdf/), the crate to depend on. It wraps the core crates and holds `Document`, `Builder`, `Error`, `Warning`, jobs and `CancelToken`.
13
13
 
14
14
  The other crates are documented the same way:
15
15
 
16
- - [`laminapdf-syntax`](https://docs.rs/laminapdf-syntax/0.2.0-alpha.3/laminapdf_syntax/)
17
- - [`laminapdf-cos`](https://docs.rs/laminapdf-cos/0.2.0-alpha.3/laminapdf_cos/)
18
- - [`laminapdf-model`](https://docs.rs/laminapdf-model/0.2.0-alpha.3/laminapdf_model/)
19
- - [`laminapdf-ops`](https://docs.rs/laminapdf-ops/0.2.0-alpha.3/laminapdf_ops/)
20
- - [`laminapdf-save`](https://docs.rs/laminapdf-save/0.2.0-alpha.3/laminapdf_save/)
21
- - [`laminapdf-content`](https://docs.rs/laminapdf-content/0.2.0-alpha.3/laminapdf_content/)
22
- - [`laminapdf-text`](https://docs.rs/laminapdf-text/0.2.0-alpha.3/laminapdf_text/)
23
- - [`laminapdf-build`](https://docs.rs/laminapdf-build/0.2.0-alpha.3/laminapdf_build/)
24
- - [`laminapdf-render-pdfium`](https://docs.rs/laminapdf-render-pdfium/0.2.0-alpha.3/laminapdf_render_pdfium/)
16
+ - [`laminapdf-syntax`](https://docs.rs/laminapdf-syntax/0.2.0-alpha.4/laminapdf_syntax/)
17
+ - [`laminapdf-cos`](https://docs.rs/laminapdf-cos/0.2.0-alpha.4/laminapdf_cos/)
18
+ - [`laminapdf-model`](https://docs.rs/laminapdf-model/0.2.0-alpha.4/laminapdf_model/)
19
+ - [`laminapdf-ops`](https://docs.rs/laminapdf-ops/0.2.0-alpha.4/laminapdf_ops/)
20
+ - [`laminapdf-save`](https://docs.rs/laminapdf-save/0.2.0-alpha.4/laminapdf_save/)
21
+ - [`laminapdf-content`](https://docs.rs/laminapdf-content/0.2.0-alpha.4/laminapdf_content/)
22
+ - [`laminapdf-text`](https://docs.rs/laminapdf-text/0.2.0-alpha.4/laminapdf_text/)
23
+ - [`laminapdf-build`](https://docs.rs/laminapdf-build/0.2.0-alpha.4/laminapdf_build/)
24
+ - [`laminapdf-render-pdfium`](https://docs.rs/laminapdf-render-pdfium/0.2.0-alpha.4/laminapdf_render_pdfium/)
25
25
 
26
26
  docs.rs couldn't build `laminapdf-source` and `laminapdf-render` at 0.2.0-alpha.2, so their docs come with the next release; until then, build them yourself as below. [Install](../../pages/install.md#every-published-package) lists every crate, with its page on crates.io.
27
27
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Stability policy"
3
3
  description: "What a Lamina PDF version number promises, and what stays the same in every version."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/reference/stability/"
6
6
  ---
7
7
 
@@ -17,7 +17,7 @@ Every crate and every npm package shares one version, and they are released toge
17
17
 
18
18
  ## What a version number tells you
19
19
 
20
- - **Alphas promise nothing to each other.** Anything can change between `0.2.0-alpha.1` and `0.2.0-alpha.2`. While you try an alpha, pin the exact version: `npm install --save-exact @laminapdf/sdk@0.2.0-alpha.3`, and `laminapdf = "=0.2.0-alpha.3"` in `Cargo.toml`.
20
+ - **Alphas promise nothing to each other.** Anything can change between `0.2.0-alpha.1` and `0.2.0-alpha.2`. While you try an alpha, pin the exact version: `npm install --save-exact @laminapdf/sdk@0.2.0-alpha.4`, and `laminapdf = "=0.2.0-alpha.4"` in `Cargo.toml`.
21
21
  - **The `alpha` tag names the newest alpha.** `npm install @laminapdf/sdk@alpha` gets it. A plain `npm install @laminapdf/sdk` gets a `0.0.0` placeholder that only reserves the name.
22
22
  - **After the alphas, `0.x` versions follow SemVer as Cargo reads it.** A breaking change raises the minor version (`0.2` to `0.3`), and features and fixes raise the patch (`0.2.0` to `0.2.1`). So an upgrade within one `0.x` line never needs a code change.
23
23
 
@@ -40,7 +40,7 @@ Four promises hold across every version, `0.x` and alphas included:
40
40
  - **Error and warning codes are never renamed or reused** for another meaning. A retired code stays in the [code reference](../../errors/README.md) with the version that retired it, and keeps its page. New codes can appear in any release, so handle a code you don't know.
41
41
  - **The error object only grows.** Each error names its schema, `laminapdf.error/1`. Within one schema, a field can be added, but never removed or given another type.
42
42
  - **Saved edit logs keep loading.** A log names its format version (`{ v: 1, ops }`, as [Edit a PDF](../../pages/guides/edit-a-pdf.md#replay-edits-stored-as-json) shows). A new op or optional field keeps the version. A changed or removed one raises it, and every older version still loads.
43
- - **The same input gives the same bytes everywhere.** With the same input, options and version, Rust and every JavaScript runtime write identical files.
43
+ - **The same input gives the same bytes everywhere.** With the same input, options and version, Rust and every JavaScript runtime write identical files, so you can [test your PDFs against reference PDFs](../../pages/guides/test-generated-pdfs.md).
44
44
 
45
45
  ## How the promises are checked
46
46
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Use Lamina PDF with coding agents"
3
3
  description: "Point a coding agent at the docs inside the installed package, so its answers match the version you use."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/start/coding-agents/"
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Your first PDF"
3
3
  description: "Write hello.pdf from Node in five minutes."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/start/first-pdf/"
6
6
  ---
7
7
 
@@ -18,7 +18,7 @@ You need Node 24.2 or newer, which runs `.ts` files directly. Create a folder an
18
18
  ```sh
19
19
  mkdir hello-pdf && cd hello-pdf
20
20
  npm init -y && npm pkg set type=module
21
- npm install @laminapdf/sdk@0.2.0-alpha.3
21
+ npm install @laminapdf/sdk@0.2.0-alpha.4
22
22
  ```
23
23
 
24
24
  Lamina PDF is in alpha, so the install names the version these docs describe. `@laminapdf/sdk` brings its WebAssembly modules, `@laminapdf/wasm`, with it. [Install](../../pages/install.md) covers other package managers and Rust.
@@ -27,6 +27,8 @@ Lamina PDF is in alpha, so the install names the version these docs describe. `@
27
27
 
28
28
  Save this app as `hello.ts`. It loads Lamina PDF, builds the page and writes it to `hello.pdf`:
29
29
 
30
+ **TypeScript**
31
+
30
32
  `packages/sdk/examples/quick-start/node.ts`:
31
33
 
32
34
  ```ts
@@ -62,6 +64,8 @@ export async function hello(
62
64
  if (import.meta.main) await hello();
63
65
  ```
64
66
 
67
+ **Result:** [hello.pdf](https://docs.laminapdf.com/examples/pdf/hello.pdf)
68
+
65
69
  ## Run it
66
70
 
67
71
  ```sh
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Troubleshooting"
3
3
  description: "The problems people hit with Lamina PDF, from a missing init() to a signed file that won't save, with the cause and the fix of each."
4
- version: "0.2.0-alpha.3"
4
+ version: "0.2.0-alpha.4"
5
5
  url: "https://docs.laminapdf.com/troubleshooting/"
6
6
  ---
7
7
 
@@ -49,6 +49,7 @@
49
49
  "wrong-document",
50
50
  "invalid-feature",
51
51
  "invalid-text-range",
52
+ "invalid-spans",
52
53
  "unsupported-layout-option",
53
54
  "font-mismatch",
54
55
  "encoding-full",
@@ -65,6 +66,8 @@
65
66
  "page-index-out-of-range",
66
67
  "unknown-destination",
67
68
  "invalid-page-labels",
69
+ "tag-element-not-open",
70
+ "tag-element-unclosed",
68
71
  "profile-version-conflict",
69
72
  "missing-title",
70
73
  "missing-lang",
@@ -80,12 +83,18 @@
80
83
  "device-color-without-output-intent",
81
84
  "embedded-file-forbidden",
82
85
  "embedded-file-without-mime-type",
86
+ "flow-content-too-large",
87
+ "flow-layout-unstable",
83
88
  "render-too-large",
84
89
  "render-failed",
85
90
  "render-backend-unavailable",
91
+ "model-failed",
92
+ "model-result-unexpected",
93
+ "model-needs-host",
86
94
  "cancelled",
87
95
  "job-finished",
88
96
  "document-changed",
97
+ "revision-index-out-of-range",
89
98
  "builder-finished",
90
99
  "disposed",
91
100
  "invalid-argument",
@@ -250,8 +259,16 @@
250
259
  "extract-table-limit",
251
260
  "extract-struct-tree-ignored",
252
261
  "extract-untagged-content",
262
+ "extract-needs-ocr",
263
+ "extract-column-order-uncertain",
253
264
  "tounicode-conflict",
254
- "whole-font-rebuilt"
265
+ "whole-font-rebuilt",
266
+ "flow-keep-broken",
267
+ "markdown-html-ignored",
268
+ "markdown-image-missing",
269
+ "covered-text",
270
+ "redaction-not-applied",
271
+ "text-in-earlier-revision"
255
272
  ]
256
273
  },
257
274
  "data": {