@awacloud/pdf 0.0.0-stage → 1.0.0
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.
- package/CHANGELOG.md +609 -0
- package/LICENSE +661 -0
- package/NOTICE +77 -0
- package/README.md +363 -2
- package/dist/build/index.js +21 -0
- package/dist/build/pdf-full-rw.js +10972 -0
- package/dist/build/pdf-full-rw.meta.json +105 -0
- package/dist/build/pdf-full-rw.min.js +53 -0
- package/dist/build/pdf-full.js +6078 -0
- package/dist/build/pdf-full.meta.json +90 -0
- package/dist/build/pdf-full.min.js +32 -0
- package/dist/build/pdf-large-rw.js +10367 -0
- package/dist/build/pdf-large-rw.meta.json +99 -0
- package/dist/build/pdf-large-rw.min.js +53 -0
- package/dist/build/pdf-large.js +5473 -0
- package/dist/build/pdf-large.meta.json +84 -0
- package/dist/build/pdf-large.min.js +32 -0
- package/dist/build/pdf-legacy-rw.js +12402 -0
- package/dist/build/pdf-legacy-rw.meta.json +110 -0
- package/dist/build/pdf-legacy-rw.min.js +53 -0
- package/dist/build/pdf-legacy.js +7508 -0
- package/dist/build/pdf-legacy.meta.json +95 -0
- package/dist/build/pdf-legacy.min.js +32 -0
- package/dist/build/pdf-rw.js +7578 -0
- package/dist/build/pdf-rw.meta.json +77 -0
- package/dist/build/pdf-rw.min.js +53 -0
- package/dist/build/pdf.js +2684 -0
- package/dist/build/pdf.meta.json +62 -0
- package/dist/build/pdf.min.js +32 -0
- package/dist/standalone/pdf-full-rw.js +16798 -0
- package/dist/standalone/pdf-full-rw.meta.json +78 -0
- package/dist/standalone/pdf-full-rw.min.js +56 -0
- package/dist/standalone/pdf-full.js +11904 -0
- package/dist/standalone/pdf-full.meta.json +63 -0
- package/dist/standalone/pdf-full.min.js +35 -0
- package/dist/standalone/pdf-large-rw.js +16193 -0
- package/dist/standalone/pdf-large-rw.meta.json +72 -0
- package/dist/standalone/pdf-large-rw.min.js +56 -0
- package/dist/standalone/pdf-large.js +11299 -0
- package/dist/standalone/pdf-large.meta.json +57 -0
- package/dist/standalone/pdf-large.min.js +35 -0
- package/dist/standalone/pdf-legacy-rw.js +18228 -0
- package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
- package/dist/standalone/pdf-legacy-rw.min.js +56 -0
- package/dist/standalone/pdf-legacy.js +13334 -0
- package/dist/standalone/pdf-legacy.meta.json +68 -0
- package/dist/standalone/pdf-legacy.min.js +35 -0
- package/dist/standalone/pdf-rw.js +13404 -0
- package/dist/standalone/pdf-rw.meta.json +50 -0
- package/dist/standalone/pdf-rw.min.js +56 -0
- package/dist/standalone/pdf.js +8510 -0
- package/dist/standalone/pdf.meta.json +35 -0
- package/dist/standalone/pdf.min.js +35 -0
- package/docs/README.md +53 -0
- package/docs/api/README.md +38 -0
- package/docs/api/_shared/README.md +91 -0
- package/docs/api/action/README.md +29 -0
- package/docs/api/action/action.md +81 -0
- package/docs/api/action/goTo.md +66 -0
- package/docs/api/action/launch.md +58 -0
- package/docs/api/action/named.md +55 -0
- package/docs/api/action/uri.md +54 -0
- package/docs/api/annot/README.md +53 -0
- package/docs/api/annot/annot.md +114 -0
- package/docs/api/annot/fileAttach.md +53 -0
- package/docs/api/annot/freeText.md +68 -0
- package/docs/api/annot/ink.md +69 -0
- package/docs/api/annot/link.md +74 -0
- package/docs/api/annot/markup.md +83 -0
- package/docs/api/annot/popup.md +52 -0
- package/docs/api/annot/projection.md +56 -0
- package/docs/api/annot/redact.md +67 -0
- package/docs/api/annot/square.md +87 -0
- package/docs/api/annot/stamp.md +54 -0
- package/docs/api/annot/text.md +69 -0
- package/docs/api/annot/widget.md +69 -0
- package/docs/api/associatedFiles/README.md +9 -0
- package/docs/api/associatedFiles/associatedFiles.md +78 -0
- package/docs/api/bundles/README.md +68 -0
- package/docs/api/bundles/dist-matrix.md +165 -0
- package/docs/api/bundles/pdf-full.md +148 -0
- package/docs/api/bundles/pdf-large.md +144 -0
- package/docs/api/bundles/pdf-legacy.md +169 -0
- package/docs/api/content/README.md +29 -0
- package/docs/api/content/color.md +99 -0
- package/docs/api/content/graphics.md +114 -0
- package/docs/api/content/images.md +124 -0
- package/docs/api/content/ops.md +100 -0
- package/docs/api/content/stream.md +107 -0
- package/docs/api/content/text.md +98 -0
- package/docs/api/crypto/README.md +29 -0
- package/docs/api/crypto/aesGcm.md +72 -0
- package/docs/api/crypto/permissions.md +79 -0
- package/docs/api/crypto/security.md +98 -0
- package/docs/api/crypto/standardV4.md +104 -0
- package/docs/api/crypto/standardV5.md +84 -0
- package/docs/api/crypto/standardV6.md +93 -0
- package/docs/api/destination/README.md +9 -0
- package/docs/api/destination/destination.md +79 -0
- package/docs/api/document/README.md +29 -0
- package/docs/api/document/builder.md +281 -0
- package/docs/api/document/catalog.md +98 -0
- package/docs/api/document/document.md +187 -0
- package/docs/api/document/encryptedWriter.md +149 -0
- package/docs/api/document/incrementalWriter.md +148 -0
- package/docs/api/document/page.md +99 -0
- package/docs/api/document/pages.md +82 -0
- package/docs/api/document/resources.md +102 -0
- package/docs/api/document/writer.md +157 -0
- package/docs/api/document/xrefStreamWriter.md +122 -0
- package/docs/api/embedded/README.md +13 -0
- package/docs/api/embedded/collection.md +80 -0
- package/docs/api/embedded/embeddedFile.md +86 -0
- package/docs/api/embedded/fileSpec.md +87 -0
- package/docs/api/errors.md +110 -0
- package/docs/api/extra/3d-richmedia.md +76 -0
- package/docs/api/extra/README.md +99 -0
- package/docs/api/extra/annot-extended.md +71 -0
- package/docs/api/extra/associated-files.md +70 -0
- package/docs/api/extra/ccitt-fax-decoder.md +74 -0
- package/docs/api/extra/color-spaces-extended.md +72 -0
- package/docs/api/extra/content-ops-extended.md +82 -0
- package/docs/api/extra/document-parts.md +69 -0
- package/docs/api/extra/embedded-files-portfolio.md +87 -0
- package/docs/api/extra/font-cid-typed.md +77 -0
- package/docs/api/extra/font-color-tagging.md +76 -0
- package/docs/api/extra/form-actions-extended.md +75 -0
- package/docs/api/extra/info-dict-deprecated.md +72 -0
- package/docs/api/extra/jbig2-read.md +80 -0
- package/docs/api/extra/legacy-deprecated-annots.md +89 -0
- package/docs/api/extra/legacy-deprecated-filters.md +78 -0
- package/docs/api/extra/legacy-rc4-read.md +74 -0
- package/docs/api/extra/legacy-xfa-read.md +65 -0
- package/docs/api/extra/linearization-write.md +71 -0
- package/docs/api/extra/misc.md +93 -0
- package/docs/api/extra/optional-content-extended.md +83 -0
- package/docs/api/extra/pdf-a-output-intent.md +65 -0
- package/docs/api/extra/pdf-sandbox.md +76 -0
- package/docs/api/extra/pdf-ua-tagged.md +63 -0
- package/docs/api/extra/pdf-x-prepress.md +65 -0
- package/docs/api/extra/redaction-iso32005.md +65 -0
- package/docs/api/extra/shading-typed.md +73 -0
- package/docs/api/extra/sig-aes-gcm.md +69 -0
- package/docs/api/extra/sig-pades.md +103 -0
- package/docs/api/extra/tagged-pdf-typed.md +78 -0
- package/docs/api/extra/transparency-typed.md +74 -0
- package/docs/api/extra/well-tagged-pdf.md +61 -0
- package/docs/api/extra/xmp-extended.md +65 -0
- package/docs/api/font/README.md +25 -0
- package/docs/api/font/embed.md +157 -0
- package/docs/api/font/encoding.md +95 -0
- package/docs/api/font/font.md +97 -0
- package/docs/api/font/type3.md +89 -0
- package/docs/api/form/README.md +35 -0
- package/docs/api/form/acroform.md +88 -0
- package/docs/api/form/appearance.md +87 -0
- package/docs/api/form/button.md +97 -0
- package/docs/api/form/choice.md +96 -0
- package/docs/api/form/fieldTree.md +93 -0
- package/docs/api/form/signature.md +90 -0
- package/docs/api/form/text.md +88 -0
- package/docs/api/linearization/README.md +11 -0
- package/docs/api/linearization/linearization.md +81 -0
- package/docs/api/main.md +116 -0
- package/docs/api/metadata/README.md +10 -0
- package/docs/api/metadata/info.md +70 -0
- package/docs/api/metadata/xmp.md +62 -0
- package/docs/api/ocg/README.md +23 -0
- package/docs/api/ocg/config.md +95 -0
- package/docs/api/ocg/ocg.md +77 -0
- package/docs/api/outline/README.md +11 -0
- package/docs/api/outline/outline.md +107 -0
- package/docs/api/pdf.md +152 -0
- package/docs/api/prepress/README.md +10 -0
- package/docs/api/prepress/outputIntent.md +79 -0
- package/docs/api/prepress/pageBoundary.md +75 -0
- package/docs/api/sig/README.md +32 -0
- package/docs/api/sig/byteRange.md +120 -0
- package/docs/api/sig/certChain.md +84 -0
- package/docs/api/sig/dss.md +111 -0
- package/docs/api/sig/oids.md +76 -0
- package/docs/api/sig/sha1.md +72 -0
- package/docs/api/sig/sign.md +317 -0
- package/docs/api/sig/signature.md +178 -0
- package/docs/api/sig/timestamp.md +84 -0
- package/docs/api/syntax/README.md +29 -0
- package/docs/api/syntax/crossRefStream.md +115 -0
- package/docs/api/syntax/filters/README.md +50 -0
- package/docs/api/syntax/filters/ascii85.md +76 -0
- package/docs/api/syntax/filters/asciiHex.md +73 -0
- package/docs/api/syntax/filters/dispatch.md +125 -0
- package/docs/api/syntax/filters/flate.md +134 -0
- package/docs/api/syntax/filters/runLength.md +78 -0
- package/docs/api/syntax/objStream.md +88 -0
- package/docs/api/syntax/parser-obj.md +97 -0
- package/docs/api/syntax/parser.md +151 -0
- package/docs/api/syntax/serializer.md +109 -0
- package/docs/api/syntax/tokenizer.md +104 -0
- package/docs/api/syntax/trailer.md +85 -0
- package/docs/api/syntax/xref.md +139 -0
- package/docs/api/tagged/README.md +25 -0
- package/docs/api/tagged/classMap.md +67 -0
- package/docs/api/tagged/markedContent.md +62 -0
- package/docs/api/tagged/parentTree.md +67 -0
- package/docs/api/tagged/roleMap.md +67 -0
- package/docs/api/tagged/structElement.md +76 -0
- package/docs/api/tagged/structTree.md +75 -0
- package/docs/guide/coverage.md +113 -0
- package/docs/guide/crypto.md +121 -0
- package/docs/guide/extending.md +76 -0
- package/docs/guide/getting-started.md +75 -0
- package/docs/guide/legacy-1.7.md +42 -0
- package/docs/guide/pades-integration.md +579 -0
- package/docs/guide/read-pdf.md +89 -0
- package/package.json +97 -4
- package/src/_shared/index.js +179 -0
- package/src/action/action.js +119 -0
- package/src/action/goTo.js +89 -0
- package/src/action/launch.js +61 -0
- package/src/action/named.js +54 -0
- package/src/action/uri.js +51 -0
- package/src/annot/annot.js +212 -0
- package/src/annot/fileAttach.js +55 -0
- package/src/annot/freeText.js +82 -0
- package/src/annot/ink.js +77 -0
- package/src/annot/link.js +77 -0
- package/src/annot/markup.js +91 -0
- package/src/annot/popup.js +53 -0
- package/src/annot/projection.js +52 -0
- package/src/annot/redact.js +87 -0
- package/src/annot/square.js +132 -0
- package/src/annot/stamp.js +48 -0
- package/src/annot/text.js +54 -0
- package/src/annot/widget.js +61 -0
- package/src/associatedFiles/associatedFiles.js +86 -0
- package/src/bundles/pdf-full.js +91 -0
- package/src/bundles/pdf-large.js +81 -0
- package/src/bundles/pdf-legacy.js +107 -0
- package/src/content/color.js +114 -0
- package/src/content/graphics.js +192 -0
- package/src/content/images.js +160 -0
- package/src/content/ops.js +137 -0
- package/src/content/stream.js +154 -0
- package/src/content/text.js +125 -0
- package/src/crypto/aesGcm.js +123 -0
- package/src/crypto/permissions.js +112 -0
- package/src/crypto/security.js +327 -0
- package/src/crypto/standardV4.js +443 -0
- package/src/crypto/standardV5.js +306 -0
- package/src/crypto/standardV6.js +334 -0
- package/src/destination/destination.js +183 -0
- package/src/document/builder.js +618 -0
- package/src/document/catalog.js +100 -0
- package/src/document/document.js +472 -0
- package/src/document/encryptedWriter.js +554 -0
- package/src/document/incrementalWriter.js +514 -0
- package/src/document/page.js +131 -0
- package/src/document/pages.js +103 -0
- package/src/document/resources.js +146 -0
- package/src/document/writer.js +211 -0
- package/src/document/xrefStreamWriter.js +353 -0
- package/src/embedded/collection.js +102 -0
- package/src/embedded/embeddedFile.js +99 -0
- package/src/embedded/fileSpec.js +137 -0
- package/src/errors.js +78 -0
- package/src/extra/3d-richmedia.js +171 -0
- package/src/extra/annot-extended.js +200 -0
- package/src/extra/associated-files.js +131 -0
- package/src/extra/ccitt-fax-decoder.js +776 -0
- package/src/extra/color-spaces-extended.js +196 -0
- package/src/extra/content-ops-extended.js +153 -0
- package/src/extra/document-parts.js +149 -0
- package/src/extra/embedded-files-portfolio.js +234 -0
- package/src/extra/font-cid-typed.js +185 -0
- package/src/extra/font-color-tagging.js +144 -0
- package/src/extra/form-actions-extended.js +196 -0
- package/src/extra/info-dict-deprecated.js +137 -0
- package/src/extra/jbig2-read.js +169 -0
- package/src/extra/legacy-deprecated-annots.js +198 -0
- package/src/extra/legacy-deprecated-filters.js +167 -0
- package/src/extra/legacy-rc4-read.js +235 -0
- package/src/extra/legacy-xfa-read.js +104 -0
- package/src/extra/linearization-write.js +97 -0
- package/src/extra/misc.js +217 -0
- package/src/extra/optional-content-extended.js +142 -0
- package/src/extra/pdf-a-output-intent.js +112 -0
- package/src/extra/pdf-sandbox.js +88 -0
- package/src/extra/pdf-ua-tagged.js +116 -0
- package/src/extra/pdf-x-prepress.js +114 -0
- package/src/extra/redaction-iso32005.js +136 -0
- package/src/extra/shading-typed.js +222 -0
- package/src/extra/sig-aes-gcm.js +135 -0
- package/src/extra/sig-pades.js +242 -0
- package/src/extra/tagged-pdf-typed.js +203 -0
- package/src/extra/transparency-typed.js +135 -0
- package/src/extra/well-tagged-pdf.js +138 -0
- package/src/extra/xmp-extended.js +190 -0
- package/src/font/embed.js +480 -0
- package/src/font/encoding.js +92 -0
- package/src/font/font.js +101 -0
- package/src/font/type3.js +75 -0
- package/src/form/acroform.js +94 -0
- package/src/form/appearance.js +90 -0
- package/src/form/button.js +105 -0
- package/src/form/choice.js +152 -0
- package/src/form/fieldTree.js +120 -0
- package/src/form/signature.js +100 -0
- package/src/form/text.js +101 -0
- package/src/linearization/linearization.js +107 -0
- package/src/main.js +411 -0
- package/src/metadata/info.js +87 -0
- package/src/metadata/xmp.js +62 -0
- package/src/ocg/config.js +156 -0
- package/src/ocg/ocg.js +124 -0
- package/src/outline/outline.js +157 -0
- package/src/pdf.js +133 -0
- package/src/prepress/outputIntent.js +118 -0
- package/src/prepress/pageBoundary.js +108 -0
- package/src/sig/byteRange.js +306 -0
- package/src/sig/certChain.js +247 -0
- package/src/sig/dss.js +317 -0
- package/src/sig/oids.js +157 -0
- package/src/sig/sha1.js +142 -0
- package/src/sig/sign.js +1899 -0
- package/src/sig/signature.js +1441 -0
- package/src/sig/timestamp.js +236 -0
- package/src/syntax/crossRefStream.js +133 -0
- package/src/syntax/filters/ascii85.js +122 -0
- package/src/syntax/filters/asciiHex.js +83 -0
- package/src/syntax/filters/dispatch.js +176 -0
- package/src/syntax/filters/flate.js +316 -0
- package/src/syntax/filters/runLength.js +96 -0
- package/src/syntax/objStream.js +99 -0
- package/src/syntax/parser-obj.js +52 -0
- package/src/syntax/parser.js +321 -0
- package/src/syntax/serializer.js +221 -0
- package/src/syntax/tokenizer.js +290 -0
- package/src/syntax/trailer.js +76 -0
- package/src/syntax/xref.js +341 -0
- package/src/tagged/classMap.js +81 -0
- package/src/tagged/markedContent.js +123 -0
- package/src/tagged/parentTree.js +126 -0
- package/src/tagged/roleMap.js +107 -0
- package/src/tagged/structElement.js +138 -0
- package/src/tagged/structTree.js +94 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
4
|
+
|
|
5
|
+
Spec reference: ISO 32000-2:2020 (PDF 2.0). Legacy read tolerance:
|
|
6
|
+
ISO 32000-1:2008 (PDF 1.7).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.0.0] - 2026-10-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Core surface (L0)** — typed object graph + classical xref + page-tree
|
|
15
|
+
walker. `pdfErrors` exposes `PdfError`, `ParseError`, `RenderError`,
|
|
16
|
+
`ContractError`, `EncryptionError`; every throw in the package uses these
|
|
17
|
+
classes with a kebab-case, namespaced `code` and a structured `context`.
|
|
18
|
+
`pdfTokenizer` (binary lexer, ISO 32000-2 §7.2), `pdfParser`/`pdfParserObj`/
|
|
19
|
+
`pdfParserStream` (typed object parser, §7.3 — `null`/`bool`/`int`/`real`/
|
|
20
|
+
`name`/`string`/`array`/`dict`/`ref`/`stream`), `pdfXref` (classical xref,
|
|
21
|
+
§7.5.4), `pdfTrailer`, `pdfCatalog` (§7.7.2), `pdfPages` (balanced
|
|
22
|
+
page-tree walker, cycle + depth detection), `pdfPage` (§7.7.3.3),
|
|
23
|
+
`pdfDocument` (top-level reader, `/Prev` xref chaining). Top-level `pdf`
|
|
24
|
+
factory exposes `.read()`, `.header()`, `.use(...)` (idempotent by name),
|
|
25
|
+
`.usedExtension()`, `.write()`.
|
|
26
|
+
- **Writer + filters (L1)** — `pdfSerializer` (typed-object → bytes,
|
|
27
|
+
canonical real-number formatting, `#xx` name escapes, automatic hex form
|
|
28
|
+
for binary strings), `pdfWriter` (`writeDocument(...)` emits the header it
|
|
29
|
+
is given, `%PDF-2.0` by default),
|
|
30
|
+
`pdfBuilder` (constructive DSL — `addPage`/`addContent`/`addFont`/
|
|
31
|
+
`addMetadata`/`setVersion`/`setId`/`.build()` — builds a document
|
|
32
|
+
from-scratch with no `pdf.read()` upstream). Five filters: `pdfFlate`
|
|
33
|
+
(delegates to `@awacloud/fw/io/compress/zlib`, full `/Predictor` PNG (10–15,
|
|
34
|
+
incl. optimum) + TIFF (2) encode **and** decode), `pdfAsciiHex`,
|
|
35
|
+
`pdfAscii85` (incl. `z` shorthand + `~>` EOD), `pdfRunLength`,
|
|
36
|
+
`pdfFilterDispatch` (`/Filter`+`/DecodeParms` chain walker, abbreviation
|
|
37
|
+
table, DCT/JPX passthrough). Compressed-object readers `pdfObjStream`
|
|
38
|
+
(§7.5.7) and `pdfCrossRefStream` (§7.5.8).
|
|
39
|
+
- **Content streams + fonts + AcroForm (L2)** — `pdfContentStream` (~70
|
|
40
|
+
operators per ISO 32000-2 Table 60, inline-image `BI…ID…EI` capture),
|
|
41
|
+
`pdfContentOps` (operator catalogue), `pdfGraphics` (`GStateStack`,
|
|
42
|
+
`q`/`Q`, CTM), `pdfText` (Td/TD/Tm/T* tracking, `extractText`),
|
|
43
|
+
`pdfColor`, `pdfImages` (XObject typing), `pdfResources` (page-tree
|
|
44
|
+
parent-chain resolution). Font glue to `@awacloud/fonts`: `pdfFont` (every
|
|
45
|
+
ISO subtype), `pdfFontEncoding`, `pdfType3`, `pdfFontEmbed` (single
|
|
46
|
+
adapter to `@awacloud/fonts/embed-pdf` for subset embedding). AcroForm
|
|
47
|
+
baseline: `pdfAcroForm`, `pdfFieldTree`, `pdfButtonField`, `pdfTextField`,
|
|
48
|
+
`pdfChoiceField`, `pdfSignatureField`, `pdfAppearance`.
|
|
49
|
+
- **Annotations, tagged PDF, OCG, outlines/actions/destinations, embedded
|
|
50
|
+
files, linearization, metadata, prepress, associated files (L3)** —
|
|
51
|
+
`pdfAnnot` orchestrator + 12 subtype typers (Text, Link, FreeText,
|
|
52
|
+
shape family via `pdfShapeAnnot`, markup family via `pdfMarkupAnnot`,
|
|
53
|
+
Ink, Stamp, FileAttachment, Widget, Popup, Projection, Redact —
|
|
54
|
+
ISO 32005). `pdfStructTree`/`pdfStructElement`/`pdfRoleMap`/
|
|
55
|
+
`pdfParentTree`/`pdfClassMap`/`pdfMarkedContent` (StructTreeRoot
|
|
56
|
+
walking, heterogeneous `/K` children, RoleMap + Namespaces per Table
|
|
57
|
+
364–365, MCID resolution + extraction). `pdfOCG`/`pdfOCConfig`.
|
|
58
|
+
`pdfOutline`, `pdfDestination`, `pdfAction` + GoTo/GoToR/GoToE/URI/
|
|
59
|
+
Named/Launch typers. `pdfFileSpec`/`pdfEmbeddedFile`/`pdfCollection`
|
|
60
|
+
(PDF Portfolio). `pdfLinearization` (types the `/Linearized` parameter
|
|
61
|
+
dictionary, read-only). `pdfInfo`/`pdfXmp`.
|
|
62
|
+
`pdfOutputIntent`/`pdfPageBoundary` (PDF/A, PDF/X, PDF/E; effective
|
|
63
|
+
Crop/Trim/Bleed/Art box resolution). `pdfAssociatedFiles` (`/AF` +
|
|
64
|
+
`/AFRelationship`, PDF 2.0).
|
|
65
|
+
- **Encryption, decrypt + encrypt (L3)** — `pdfSecurity` (Security Handler
|
|
66
|
+
dispatcher), `pdfStandardV4` (PDF 1.6/ISO 32000-1 §7.6.3 — AESV2
|
|
67
|
+
AES-128-CBC and V2 RC4-128, `/O`/`/U` derivation, per-object key
|
|
68
|
+
derivation, string/stream/embedded-file encrypt **and** decrypt
|
|
69
|
+
round-trip), `pdfStandardV5` (PDF 1.7 — AES-256-CBC + SHA-256),
|
|
70
|
+
`pdfStandardV6` (PDF 2.0 — Algorithm 2.B hardening loop + Algorithm 8
|
|
71
|
+
FEK unwrap, SHA-256/384/512 selection), `pdfPermissions` (`/Perms`
|
|
72
|
+
Algorithm 13), `pdfAesGcm` (TS 32003 AES-GCM crypt filter, decode
|
|
73
|
+
**and** encode), `pdfEncryptedWriter` (`writeDocument`-style encrypted
|
|
74
|
+
write path — V4/V5 R=5/V6 R=6, `/CFM AESV4` GCM opt-in). All crypto via
|
|
75
|
+
`@awacloud/fw/crypto/*` (pure JS, worker-safe). `read` does not decrypt:
|
|
76
|
+
it refuses an encrypted file unless `allowEncrypted: true` is passed, and
|
|
77
|
+
the handlers are then called by the caller.
|
|
78
|
+
- **Digital signatures, verify + generate** —
|
|
79
|
+
`pdfSignature`/`pdfByteRange`/`pdfTimestamp`/`pdfCertChain`/
|
|
80
|
+
`pdfDssBuilder`: Sig/DocTimeStamp typing, PKCS#7 detached blob locator,
|
|
81
|
+
ByteRange compute/extract, RFC 3161 TSP parser, X.509 cert chain
|
|
82
|
+
extraction (CMS SignedData + PEM), structural chain ordering check, DSS
|
|
83
|
+
dict typing. **`verifySignature(...)` performs full public-key
|
|
84
|
+
verification** — `verifyPk` wires RSA-PSS (PKCS#1 v1.5 refused per fw
|
|
85
|
+
policy), ECDSA (P-256/P-384/P-521), Ed25519; the result carries
|
|
86
|
+
`verified: true` (alias `valid`), `pkVerified: true`, `computedDigest`
|
|
87
|
+
when the digest chain and PK-verify both succeed — the digest-only
|
|
88
|
+
structural pass this superseded is gone (see Security).
|
|
89
|
+
**`pdfSign.sign(pdfBytes, opts)`** generates PAdES signatures at all
|
|
90
|
+
four levels: **B** (single embedded PKCS#7, no TSA), **T** (adds an
|
|
91
|
+
RFC 3161 timestamp token via a caller-supplied
|
|
92
|
+
`opts.tsaSign({ digest, hashAlg })` callback), **LT** (appends a `/DSS`
|
|
93
|
+
dict with certs via `pdfIncrementalWriter`), **LTA** (appends a
|
|
94
|
+
`/DocTimeStamp` on top of the LT bytes). `verifyAllSignatures` /
|
|
95
|
+
`validateBLtaChain` round-trip a full B→T→LT→LTA chain end-to-end
|
|
96
|
+
(`tsaVerified`/`imprintVerified` on the reconstructed `DocTimeStamp`).
|
|
97
|
+
`validateDocMdp(ref)` validates MDP `/P` 1/2/3 + `/DigestMethod` +
|
|
98
|
+
`/V` `1.2`/`2.2` tolerance. Algorithms: RSA-PSS, ECDSA, Ed25519 across
|
|
99
|
+
both verify and sign.
|
|
100
|
+
- **Constructive + incremental writers** — `pdfIncrementalWriter`
|
|
101
|
+
.`appendIncremental(pdfBytes, updates)` emits `originalBytes ‖
|
|
102
|
+
updatedObjs ‖ xref ‖ trailer ‖ %%EOF` with a `/Prev` chain (the
|
|
103
|
+
mechanism `pdfSign`'s LT/LTA levels build on). `pdfXrefStreamWriter`
|
|
104
|
+
(`src/document/xrefStreamWriter.js`) implements
|
|
105
|
+
`writeXrefStreamDocument(model, opts)` — native `/Type /XRef` emission
|
|
106
|
+
(PDF 1.5+/2.0) with an opt-in `useObjStm` grouping non-stream indirects
|
|
107
|
+
into compressed `/Type /ObjStm` wrappers (§7.5.7). It is registered in
|
|
108
|
+
`src/main.js` `modules`, re-exported by name from the root entry, and
|
|
109
|
+
ships in every Read+Write `dist/` root.
|
|
110
|
+
- **Parser hardening** — `parserLimits` (`maxDepth: 200`,
|
|
111
|
+
`maxArrayLen: 1_000_000`, `maxStreamBytes: 256 MiB`), adjustable at
|
|
112
|
+
runtime via `setParserLimits(partial)`; `findEndstream` accepts an
|
|
113
|
+
explicit `maxScanBytes`.
|
|
114
|
+
- **Shared helper factory `pdfShared`** (`src/_shared/index.js`) —
|
|
115
|
+
canonical magic bytes (`HEADER_PREFIX`, `EOF_MARKER`, `BINARY_MARKER`),
|
|
116
|
+
frozen `ASCII` byte-constant table, character-class predicates per
|
|
117
|
+
§7.2 (`isWs`/`isEol`/`isDigit`/`isHex`/`isDelim`/`isRegular`/
|
|
118
|
+
`hexNibble`), the `HEX_LO` lookup table, codec instances and wrappers
|
|
119
|
+
(`encodeAscii`/`decodeUtf8`/`decodeUtf8Lenient`/`decodeLatin1`), byte
|
|
120
|
+
helpers (`pad10`/`hexLit`/`bytesEqual`/`concatBytes`). `pdfTokenizer`
|
|
121
|
+
and the top-level `pdf` declare it as a dependency; the filters, the
|
|
122
|
+
writer and the serializer still carry their own inline copies of some of
|
|
123
|
+
these helpers. `pdfSigOids` consolidates the OID → dispatch-label tables
|
|
124
|
+
(`DIGEST_OIDS`, `SIG_DISPATCH_OIDS`, `KEY_ALG_OIDS`,
|
|
125
|
+
`SIG_ALG_OIDS_VERBOSE`, `OID_TST_INFO`, `OID_AA_TIMESTAMP`, `shortOid`)
|
|
126
|
+
previously duplicated across `signature.js`/`timestamp.js`/`certChain.js`
|
|
127
|
+
into one factory, which all three now declare as a dependency.
|
|
128
|
+
- **Coverage extras** (opt-in, the `extras` array of `src/main.js` — 32
|
|
129
|
+
modules under `src/extra/` — tree-shaken when unused) reach the PDF 2.0
|
|
130
|
+
long-tail + PDF 1.7 read tolerance:
|
|
131
|
+
**P0** (common) — `content-ops-extended`,
|
|
132
|
+
`font-cid-typed`, `font-color-tagging`, `tagged-pdf-typed`,
|
|
133
|
+
`annot-extended`, `pdf-a-output-intent`, `pdf-ua-tagged`. **P1**
|
|
134
|
+
(extended) — `form-actions-extended`, `color-spaces-extended`,
|
|
135
|
+
`shading-typed`, `transparency-typed`, `sig-pades`, `sig-aes-gcm`,
|
|
136
|
+
`document-parts` (ISO TS 32004), `redaction-iso32005`,
|
|
137
|
+
`pdf-x-prepress`, `well-tagged-pdf` (WTPDF 1.0),
|
|
138
|
+
`optional-content-extended`, `embedded-files-portfolio`,
|
|
139
|
+
`associated-files`, `xmp-extended`. **P2** (tail) —
|
|
140
|
+
`linearization-write` (builds the `/Linearized` dictionary and a
|
|
141
|
+
zero-length hint-stream placeholder; it does not produce a linearized
|
|
142
|
+
file), `3d-richmedia`, `jbig2-read` (segment-header enumeration, decode
|
|
143
|
+
intentionally not implemented), `legacy-xfa-read`,
|
|
144
|
+
`legacy-rc4-read` (RC4 known-answer-test verified),
|
|
145
|
+
`legacy-deprecated-filters` (LZWDecode via fw + DCT/JPX passthrough;
|
|
146
|
+
CCITTFax delegates to the sibling `ccitt-fax-decoder` codec — see
|
|
147
|
+
below), `legacy-deprecated-annots` (Sound/Movie/Screen typing). **P3**
|
|
148
|
+
(misc) — `misc` (SpiderInfo/Threads/Legal/Requirements/NeedsRendering),
|
|
149
|
+
`info-dict-deprecated` (Info dict lint). Plus two modules added after
|
|
150
|
+
the initial P0–P3 pass: **`pdf-sandbox`** (`pdfSandbox.lintActions(...)`
|
|
151
|
+
— classifies `/Launch`/`/JavaScript`/`/SubmitForm`/`/ImportData`/`/URI`,
|
|
152
|
+
bundled opt-in via `pdf-full`) and **`ccitt-fax-decoder`** (a **full
|
|
153
|
+
ITU-T T.4/T.6 codec**, encode + decode, for K<0 Group 4, K=0 Group 3
|
|
154
|
+
1D, K>0 Group 3 mixed — split out once the original header-only stub
|
|
155
|
+
was completed; consumed by `legacy-deprecated-filters` as a
|
|
156
|
+
dependency, and covered by both suites' tests). The legacy decoders are
|
|
157
|
+
called through their extras' own API; they are not registered into
|
|
158
|
+
`pdfFilterDispatch`.
|
|
159
|
+
- **Bundles** — three ergonomic compositions of core + extras, each a
|
|
160
|
+
pure fw descriptor consumed via `ModuleRuntime.resolve(...)`:
|
|
161
|
+
**`pdfLargeBundle`** (`@awacloud/pdf/pdf-large`, P0+P1, the common PDF
|
|
162
|
+
2.0 features), **`pdfFullBundle`** (`@awacloud/pdf/pdf-full`, +P2+P3,
|
|
163
|
+
every PDF 2.0 extra), **`pdfLegacyBundle`** (`@awacloud/pdf/pdf-legacy`, +
|
|
164
|
+
`legacy-*` family, reads PDF 1.7; `write` still emits a `%PDF-2.0`
|
|
165
|
+
header and re-emits legacy content — XFA, RC4 encryption, LZW streams,
|
|
166
|
+
Sound/Movie annotations — as it was read, without converting it). Each
|
|
167
|
+
resolved bundle exposes `.read`, `.write`, `.use`, `.usedExtension`,
|
|
168
|
+
`.header`, and every wired extra under its factory name; re-applying a
|
|
169
|
+
bundle is a no-op. See `docs/api/bundles/README.md` for the per-bundle
|
|
170
|
+
extras breakdown.
|
|
171
|
+
- **Pre-built bundles — two-surface `dist/`, Read and Read+Write families.**
|
|
172
|
+
`tools/generate-bundles.mjs` (`bun run gen:bundles`, a thin wrapper
|
|
173
|
+
around `@awacloud/tool-prebuild-generator`) emits two path-discriminated
|
|
174
|
+
surfaces side by side under `dist/`: `dist/standalone/<root>.
|
|
175
|
+
{js,min.js,meta.json}` (`dependencies: []`, every fw + pdf-local
|
|
176
|
+
factory inlined, zero runtime registration) and
|
|
177
|
+
`dist/build/<root>.{js,min.js,meta.json}` (declares the fw modules as
|
|
178
|
+
dependencies, inlines only the pdf-local factories, smallest payload).
|
|
179
|
+
The roots form a two-family × size matrix: the four assembly roots
|
|
180
|
+
(`pdf`, `pdf-large`, `pdf-full`, `pdf-legacy`) are the **Read** family,
|
|
181
|
+
and four `-rw` roots (`pdf-rw`, `pdf-large-rw`, `pdf-full-rw`,
|
|
182
|
+
`pdf-legacy-rw`) form the **Read+Write** family — each the Read root's
|
|
183
|
+
segment plus the write inventory, with `pdfXrefStreamWriter` shipping in
|
|
184
|
+
every `-rw` root — on both surfaces, 8 roots × 2 surfaces. Strictly
|
|
185
|
+
additive: adding the `-rw` roots left the four Read roots unchanged.
|
|
186
|
+
`dist/build/index.js` is a barrel re-exporting the whole `@awacloud/pdf`
|
|
187
|
+
namespace. `package.json` exposes `./build/*` and `./standalone/*`.
|
|
188
|
+
Output is byte-deterministic across runs (no build stamp); the root
|
|
189
|
+
`.gitignore`'s blanket `dist/` exclusion is re-included via the
|
|
190
|
+
package's own `.gitignore` (`!dist/`+`!dist/**`). See
|
|
191
|
+
[`docs/api/bundles/dist-matrix.md`](docs/api/bundles/dist-matrix.md).
|
|
192
|
+
- **Documentation** — `docs/README.md` top-level index; `docs/api/` one
|
|
193
|
+
page per source module (core, `_shared/`, `extra/`, `bundles/`),
|
|
194
|
+
following the `@awacloud/fw` module-page format; `docs/guide/` — getting
|
|
195
|
+
started, read pipeline, extension hook, coverage (with `parserLimits`),
|
|
196
|
+
crypto (AES-CBC malleability risk, `verified` vs `valid` semantics,
|
|
197
|
+
`auditByteRange`, `pdfSandbox`), PDF 1.7 legacy reading, and PAdES
|
|
198
|
+
signing and verification.
|
|
199
|
+
- **Tests + integration** — one sibling test file per source module,
|
|
200
|
+
co-located in `src/`; integration suite under `tests/`:
|
|
201
|
+
`roundtrip.integration.test.js` (wires the full stack through
|
|
202
|
+
`@awacloud/fw` `ModuleRuntime`, read → write → read on fixtures sized 1–10
|
|
203
|
+
pages, every `factory.toString()` transportability assertion),
|
|
204
|
+
`legacy-conversion.test.js` (`%PDF-1.x` header tolerance),
|
|
205
|
+
`fuzz.test.js` (empty/garbage/truncated/no-xref/bad-header inputs →
|
|
206
|
+
typed `PdfError`, never a bare `Error`), `_helpers/build.js` (shared
|
|
207
|
+
fixture builder). The package's coverage floor is `awa.coverageFloor` in
|
|
208
|
+
`package.json`.
|
|
209
|
+
- **Architecture** — clean binary format (no ZIP; `%PDF-2.0` header +
|
|
210
|
+
indirect objects + xref + trailer); worker-safe factories
|
|
211
|
+
(`factory.toString()` serializable, no closure on mutable
|
|
212
|
+
module-level state — see Changed); zero external dependency beyond
|
|
213
|
+
`@awacloud/fw` + `@awacloud/fonts` (both workspace); content stream parsed to
|
|
214
|
+
an operator list, not interpreted (rendering / coordinate math is
|
|
215
|
+
left to the caller); fonts always delegated to `@awacloud/fonts` (even
|
|
216
|
+
standard-14 metrics); AcroForm field inheritance resolved at lookup
|
|
217
|
+
time, never collapsed onto children, to preserve roundtrip fidelity;
|
|
218
|
+
bundle composition is layered (`pdf-full ⊃ pdf-large`,
|
|
219
|
+
`pdf-legacy ⊃ pdf-full`).
|
|
220
|
+
- **Package surface** — `package.json` exposes:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
. src/main.js 5 descriptor arrays + every core descriptor by name
|
|
224
|
+
./pdf src/pdf.js top-level orchestrator only
|
|
225
|
+
./errors src/errors.js pdfErrors
|
|
226
|
+
./serializer src/syntax/serializer.js
|
|
227
|
+
./filters/* src/syntax/filters/*.js
|
|
228
|
+
./annot/* src/annot/*.js
|
|
229
|
+
./tagged/* src/tagged/*.js
|
|
230
|
+
./crypto/* src/crypto/*.js
|
|
231
|
+
./sig/* src/sig/*.js
|
|
232
|
+
./ocg/* src/ocg/*.js
|
|
233
|
+
./action/* src/action/*.js
|
|
234
|
+
./embedded/* src/embedded/*.js
|
|
235
|
+
./metadata/* src/metadata/*.js
|
|
236
|
+
./prepress/* src/prepress/*.js
|
|
237
|
+
./extra/* src/extra/*.js the opt-in extras
|
|
238
|
+
./bundles/* src/bundles/*.js 3 compositions
|
|
239
|
+
./pdf-large src/bundles/pdf-large.js
|
|
240
|
+
./pdf-full src/bundles/pdf-full.js
|
|
241
|
+
./pdf-legacy src/bundles/pdf-legacy.js
|
|
242
|
+
./build/* dist/build/* two-surface prebuilt (fw-DI variant)
|
|
243
|
+
./standalone/* dist/standalone/* two-surface prebuilt (framework-free)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Note: `src/document/*` (writer, builder, incremental/xref-stream
|
|
247
|
+
writers, catalog, pages, resources) has no dedicated subpath export —
|
|
248
|
+
reachable only through the root entry's additive named re-exports
|
|
249
|
+
(below). `awa.maturity: "L4"` (the initial core surface shipped at
|
|
250
|
+
L0, then progressed L0 → L1 → L2 → L3 → L4 through the factory-only
|
|
251
|
+
refactor and the read/write gap closure).
|
|
252
|
+
- **`addFont` `encoding` option.** A non-embedded `addFont`
|
|
253
|
+
spec accepts an optional `encoding` — `WinAnsiEncoding`,
|
|
254
|
+
`MacRomanEncoding` or `StandardEncoding` — emitted as `/Encoding /<name>`
|
|
255
|
+
after the existing keys, so a Standard-14 simple font can declare how its
|
|
256
|
+
codes map to glyphs. Absent (or `undefined`) emits nothing and the bytes
|
|
257
|
+
are unchanged; an unknown value, or `encoding` combined with `embedded`,
|
|
258
|
+
throws `pdf/builder/bad-font` with `{ name, encoding }` in its `context`.
|
|
259
|
+
- **`./<family>/*.js` export twins.** All twelve wildcard families
|
|
260
|
+
of the `exports` map (`./filters/*`, `./annot/*`, `./tagged/*`,
|
|
261
|
+
`./crypto/*`, `./sig/*`, `./ocg/*`, `./action/*`, `./embedded/*`,
|
|
262
|
+
`./metadata/*`, `./prepress/*`, `./extra/*`, `./bundles/*`) gain a
|
|
263
|
+
`./<family>/*.js` twin, so a specifier written with the `.js` suffix
|
|
264
|
+
(e.g. `@awacloud/pdf/extra/sig-pades.js`) resolves to the same file under
|
|
265
|
+
Node and under a browser prefix import map. The existing forms are
|
|
266
|
+
unchanged.
|
|
267
|
+
- **`pdf.write(model, opts)` options.** `strict` forwards to
|
|
268
|
+
`assembleIndirects`; the lenient skip list is exposed as `skippedObjects`
|
|
269
|
+
and through `onSkipped`.
|
|
270
|
+
- **`sign()` signs encrypted bases.** The signature field's `/T` is
|
|
271
|
+
encrypted with the document key derived from `opts.password` (standard
|
|
272
|
+
security handler, AESV2/AESV3); RC4 and AES-GCM bases are refused with
|
|
273
|
+
typed errors. This supersedes the encrypted-base exception (signature-only
|
|
274
|
+
update, no field) noted under Fixed.
|
|
275
|
+
- **PAdES LT and LTA on encrypted bases.** The DSS streams, the VRI
|
|
276
|
+
strings and the document-timestamp field are encrypted with the document
|
|
277
|
+
key; the signature `/Contents` stay clear, as the standard requires.
|
|
278
|
+
- **External-oracle tests.** OpenSSL-produced ECDSA and Ed25519 CMS
|
|
279
|
+
signatures verify, and `sign()` output matches their structure.
|
|
280
|
+
- **Ed25519 signatures declare ISO/TS 32002.** The Ed25519 signing update
|
|
281
|
+
re-emits the Catalog with `/Extensions` declaring the `ISO_` developer
|
|
282
|
+
extension (`/ExtensionLevel 32002`, ISO/TS 32002 §4), merged with any
|
|
283
|
+
existing extensions dictionary, and sets `/Version /2.0` on a document
|
|
284
|
+
below PDF 2.0. A malformed `/Extensions` is refused
|
|
285
|
+
(`pdf/sign/bad-extensions`). ECDSA and RSA-PSS output is unchanged.
|
|
286
|
+
|
|
287
|
+
### Changed
|
|
288
|
+
|
|
289
|
+
- **API reference pages and source comments describe each opt-in module by
|
|
290
|
+
what it covers** — internal milestone labels are removed from the `extra/`
|
|
291
|
+
pages and the module, crypto and signature comments.
|
|
292
|
+
- **Standard 14 font dictionaries are shared across pages.**
|
|
293
|
+
`pdfBuilder.addFont` (non-embedded) writes one font dictionary per
|
|
294
|
+
distinct `(baseFont, subtype, encoding)` and every page that uses it
|
|
295
|
+
references that object. A document that repeats a font on several pages
|
|
296
|
+
gets smaller: a 3-page document using 4 faces drops from 12 font
|
|
297
|
+
dictionaries to 4. Documents without a repeated font are unchanged.
|
|
298
|
+
- **Truncated FlateDecode streams decode to their prefix.**
|
|
299
|
+
`pdfFlate.decode` returns the bytes decoded before a FlateDecode stream
|
|
300
|
+
ends without its final block, flagged by a non-enumerable
|
|
301
|
+
`truncated: true`, instead of throwing `pdf/flate/inflate-failed`.
|
|
302
|
+
Content streams of such files now extract. Other inflate errors still
|
|
303
|
+
throw `pdf/flate/inflate-failed`.
|
|
304
|
+
- **Documentation pass.** The README follows the published-package
|
|
305
|
+
layout (installation, quick start, sub-path table with targets, maturity,
|
|
306
|
+
licence, project links) with executed quick-start snippets and no
|
|
307
|
+
hand-typed counts; guides open with their purpose and prerequisites; the
|
|
308
|
+
coverage and bundle pages state what the filter dispatch, the legacy
|
|
309
|
+
extras and `write` actually do; reference pages were checked against the
|
|
310
|
+
resolved module surfaces; a `pdfShared` reference page was added; links
|
|
311
|
+
to the historical audit pages, which no longer ship, were removed.
|
|
312
|
+
- **The Read+Write prebuilt bundles include signature verification.**
|
|
313
|
+
Every `-rw` root under `dist/build/` and `dist/standalone/` ships
|
|
314
|
+
`pdfSignature` beside `pdfSign`, so an invoked bundle exposes
|
|
315
|
+
`verifySignature` and `verifyAllSignatures`. Each `-rw` `.min.js` grows by
|
|
316
|
+
about 21.8 KB (6.4 KB gzipped); the Read bundles are unchanged.
|
|
317
|
+
- **Dist** — dist regenerated with the licence banner: every committed
|
|
318
|
+
`dist/**/*.js` / `.min.js` opens with the package's `/*! … */` legal block
|
|
319
|
+
(content from the source repository's licence matrix), each `*.meta.json`
|
|
320
|
+
`bytes` entry is measured on the final bytes, and there is no `builtAt`
|
|
321
|
+
timestamp — `bun run gen:bundles` is byte-deterministic; the fixed
|
|
322
|
+
`sign.js` (no hard-coded `/Root 1 0 R` trailer; whole-token `/ByteRange`
|
|
323
|
+
gap) ships in every `-rw` bundle.
|
|
324
|
+
- **`/ByteRange` gap: the signer emits the whole `<…>` token; the verifier
|
|
325
|
+
accepts exactly two forms.** `pdfSign.sign` (the `/Sig`, and the
|
|
326
|
+
LTA `/DocTimeStamp` through the same emitter) now leaves the whole
|
|
327
|
+
`/Contents <…>` token out of the signed ranges, delimiters included —
|
|
328
|
+
ISO 32000-2 §12.8.3.3.1 requires the string to "fit precisely in the space
|
|
329
|
+
between the ranges", and PDFBox and pyHanko emit and check that form (b).
|
|
330
|
+
It previously left out the hex digits only (form a).
|
|
331
|
+
`computeByteRange` takes the token span as an optional fourth argument
|
|
332
|
+
(`opts.token`, new code `pdf/sig/byterange/bad-token`); its three-argument
|
|
333
|
+
call is unchanged. `auditByteRange` accepts a gap that is exactly the token
|
|
334
|
+
or exactly the digits, and reports which in the additive `gapForm` field
|
|
335
|
+
(`'token' | 'digits' | null`); before, it accepted the token only and
|
|
336
|
+
flagged `pdfSign`'s own output. `verifySignature` / `verifyAllSignatures`
|
|
337
|
+
now apply that rule to every `/Sig`: any other gap gives `verified: false`
|
|
338
|
+
with `gap-start-mismatch` / `gap-end-mismatch` in `errors`. This is a
|
|
339
|
+
tightening — measured on 2026-09-23, the verify path had no gap check at
|
|
340
|
+
all: a gap of `<` + digits, or digits + `>`, re-signed over its own ranges
|
|
341
|
+
verified `true`; both are now refused. Signatures written in form (a) —
|
|
342
|
+
every signed PDF committed in the repo — are not re-signed and keep
|
|
343
|
+
verifying.
|
|
344
|
+
- **`/DocTimeStamp` `/ByteRange` gap check.** `verifyAllSignatures` applies
|
|
345
|
+
the same rule to every `/DocTimeStamp`: a gap that is not exactly the
|
|
346
|
+
`<…>` token or exactly the hex digits gives `verified: false` with
|
|
347
|
+
`gap-start-mismatch` / `gap-end-mismatch` in `errors` (`imprintVerified`
|
|
348
|
+
still reports the imprint alone), and each `timestamps[]` entry gains the
|
|
349
|
+
additive `gapForm` field (`'token' | 'digits' | null`, present on every
|
|
350
|
+
entry). A tightening: an off-by-one DocTimeStamp gap re-stamped over its
|
|
351
|
+
own ranges verified `true` before.
|
|
352
|
+
- **Package contents** — the npm tarball ships `NOTICE` (dual licence +
|
|
353
|
+
trademark notice, commercial-licence contact) next to `LICENSE`; the pre-publication
|
|
354
|
+
checklist no longer ships. Package `description` corrected: the shipped
|
|
355
|
+
signature surface covers PKCS#7/PAdES sign **and** verify.
|
|
356
|
+
- **`main.js` restructured as a declarative manifest** — no runtime
|
|
357
|
+
bootstrap, no re-export of resolved instances, no import of built
|
|
358
|
+
bundles. Exports `fw_require` (the `@awacloud/fw` factories consumed by
|
|
359
|
+
fw-bound modules, completed with every provider's transitive deps, e.g.
|
|
360
|
+
`zlib`→`deflate`→`bitstream`/`huffman`, `pem`→`b64`,
|
|
361
|
+
`rsa`/`ecc`→`bn`/`random`/`hex`/`hmac`), `pkg_require` (cross-package
|
|
362
|
+
bridge re-exporting `@awacloud/fonts`' own `fw_require`+`modules` plus 4
|
|
363
|
+
internal `embed-pdf/subsetForPdf/*` helper descriptors it doesn't itself
|
|
364
|
+
export, so `pdfFontEmbed`'s full dependency graph resolves through a bare
|
|
365
|
+
`@awacloud/pdf` registration), `modules` (the core factories,
|
|
366
|
+
topologically ordered), `extras` (opt-in), `bundle` (3 descriptors).
|
|
367
|
+
Every `modules` descriptor is additionally re-exported by binding name so
|
|
368
|
+
a sibling composer (e.g. `@awacloud/oconv`, `@awacloud/facturx`) can
|
|
369
|
+
resolve any pdf dependency through the bare `@awacloud/pdf` specifier —
|
|
370
|
+
purely additive, the five arrays stay byte-unchanged; the `extras` and
|
|
371
|
+
`bundle` descriptors are not re-exported by name.
|
|
372
|
+
`tools/generate-bundles.mjs` is a thin wrapper over
|
|
373
|
+
`@awacloud/tool-prebuild-generator` (see Added — two-surface `dist/`).
|
|
374
|
+
- **Factory-only strict** — the five error classes
|
|
375
|
+
(`PdfError`/`ParseError`/`RenderError`/`ContractError`/
|
|
376
|
+
`EncryptionError`) are declared **inside** `pdfErrors`'s factory body;
|
|
377
|
+
every consumer declares `'pdfErrors'` as a dependency and destructures
|
|
378
|
+
the classes from the injected `errors` parameter instead of a
|
|
379
|
+
top-level `import { ParseError } from '../errors.js'`. Each
|
|
380
|
+
`pdfErrors.factory()` call therefore creates its own classes; a
|
|
381
|
+
`ModuleRuntime` caches the resolved instance, so the modules of one
|
|
382
|
+
runtime share them. The transitional ESM compatibility shim that
|
|
383
|
+
temporarily re-exported the five classes as named bindings is fully
|
|
384
|
+
retired (see Removed). `pdfSigOids` likewise moved its 8 top-level
|
|
385
|
+
`export const`/`export function` OID tables into its factory body, with
|
|
386
|
+
`signature.js`/`timestamp.js`/`certChain.js` receiving them via DI.
|
|
387
|
+
Across the refactor, every factory in the package is worker-safe:
|
|
388
|
+
module-level constants/helpers a factory body referenced are relocated
|
|
389
|
+
or inlined into that factory, so `factory.toString()` rehydrates in a
|
|
390
|
+
Web Worker without resolving an external module symbol (pinned by
|
|
391
|
+
`tests/roundtrip.integration.test.js`'s worker-safety assertion over
|
|
392
|
+
every registered factory).
|
|
393
|
+
- **Bundles simplified to pure fw descriptors** — `pdfLargeBundle`/
|
|
394
|
+
`pdfFullBundle`/`pdfLegacyBundle` are `{ name, dependencies, factory }`
|
|
395
|
+
descriptors whose factory wires each resolved extra into the core
|
|
396
|
+
`pdf` via `.use({ name, register })` and returns the enriched
|
|
397
|
+
instance; consumption is exclusively `ModuleRuntime.resolve(...)`
|
|
398
|
+
(see Removed for the retired imperative builders).
|
|
399
|
+
- **`verifySignature(...)` result shape (breaking)** — carries
|
|
400
|
+
`verified`, `valid` (alias, mirrors `verified`), `pkVerified`,
|
|
401
|
+
`computedDigest`, in place of the earlier structural-only
|
|
402
|
+
`{ valid: errors.length === 0, errors, signerCerts, hashAlg,
|
|
403
|
+
signatureAlg }`. See Security for the vulnerability this closes.
|
|
404
|
+
`pdfSignature.dependencies` gained `'bitArray'`.
|
|
405
|
+
- **Error codes namespaced by origin** — granular kebab-case codes
|
|
406
|
+
(`pdf/flate/bad-predictor`, `pdf/sig/byterange/*`, `pdf/parser/*`, …)
|
|
407
|
+
replace earlier placeholder-style codes; every raised error carries a
|
|
408
|
+
structured `context`. `pdf/ts/parse` and `pdf/ts/parse-failed` records
|
|
409
|
+
keep the underlying error as `cause`; a `pdf/sig/digest-failed` record is
|
|
410
|
+
`{ code, message }`, with the underlying error's message appended to
|
|
411
|
+
`message`.
|
|
412
|
+
- **Hash streaming for `/ByteRange`** — `verifySignature` uses
|
|
413
|
+
`hashMod.fn` + `update`/`finalize` when `bitArray` is available,
|
|
414
|
+
avoiding an `O(document size)` intermediate buffer allocation;
|
|
415
|
+
falls back to `hashMod.hash(...)` otherwise.
|
|
416
|
+
- **`standardV6` scratch buffer** — the hardening loop (Algorithm 2.B)
|
|
417
|
+
reuses a scratch buffer for AES-128 key scheduling instead of
|
|
418
|
+
allocating per round.
|
|
419
|
+
- **Packaging** — `awa.maturity` progressed `L0` → `L1` → `L2` → `L3` →
|
|
420
|
+
`L4`; `package.json` carries `description`, `keywords`, `engines`,
|
|
421
|
+
`sideEffects: false`, and the legal and project metadata (`license`
|
|
422
|
+
`AGPL-3.0-only`, `author`, `repository`, `bugs`, `homepage`); `LICENSE`
|
|
423
|
+
and `NOTICE` ship in the tarball.
|
|
424
|
+
- **`sign()` documentation.** The `sign()` JSDoc lists every option the
|
|
425
|
+
body reads.
|
|
426
|
+
- **Ed25519 viewer support documented.** Adobe Acrobat Reader does not
|
|
427
|
+
validate Ed25519 (EdDSA) signatures, including OpenSSL-produced ones;
|
|
428
|
+
OpenSSL 3.5 and later verify them. The PAdES guide recommends ECDSA P-256
|
|
429
|
+
where Acrobat must validate the signature, and its algorithm claim row
|
|
430
|
+
carries that caveat.
|
|
431
|
+
|
|
432
|
+
### Deprecated
|
|
433
|
+
|
|
434
|
+
- **`valid` on signature verification results.** The `valid` field of
|
|
435
|
+
`verifySignature` / `verifyAllSignatures` results (signatures and
|
|
436
|
+
document timestamps) is deprecated: read `verified`. It carries the same
|
|
437
|
+
value and is kept for compatibility.
|
|
438
|
+
|
|
439
|
+
### Fixed
|
|
440
|
+
|
|
441
|
+
- **Identity crypt filters on V=5 mean no encryption.** On V=5 (R=5 and
|
|
442
|
+
R=6) files, a `/StmF`, `/StrF` or `/EFF` named `Identity`, or absent,
|
|
443
|
+
now resolves to `Identity`: those strings and streams are left as they
|
|
444
|
+
are instead of being decrypted as AES-256, and `sign()` no longer
|
|
445
|
+
encrypts its new strings on such files.
|
|
446
|
+
- **The PAdES guide's external-TSA example runs.** The `tsaSign` example
|
|
447
|
+
is executed by the test suite, and the guide's verification-report
|
|
448
|
+
sample shows SHA-512 for Ed25519.
|
|
449
|
+
- **Source comments match the code.** The comments of the legacy-filters
|
|
450
|
+
extra, the writer, the filter dispatcher, the legacy bundle, `pdfShared`
|
|
451
|
+
and the font-embed adapter describe the current behaviour: CCITT decoder
|
|
452
|
+
delegation, header bytes, the dispatch map, no conversion on write, and
|
|
453
|
+
the codec helpers.
|
|
454
|
+
- **Documentation links resolve from the npm tarball.** Links that pointed
|
|
455
|
+
outside the package now point at the public repository at this release's
|
|
456
|
+
tag, so they resolve from the tarball; references to sources that are not
|
|
457
|
+
published are plain-text citations.
|
|
458
|
+
|
|
459
|
+
- **`readDocument` opens PDF 1.5+ cross-reference streams and object
|
|
460
|
+
streams.** The top-level reader now picks a cross-reference form per
|
|
461
|
+
section: an `xref` keyword takes the classical table path, anything
|
|
462
|
+
else is parsed as a `/Type /XRef` stream (§7.5.8). Mixed `/Prev`
|
|
463
|
+
chains (a classical incremental section over an xref-stream base, or
|
|
464
|
+
the reverse) and hybrid-reference files (a classical trailer carrying
|
|
465
|
+
`/XRefStm`) resolve end to end, and objects held in a `/Type /ObjStm`
|
|
466
|
+
container (§7.5.7) are materialised on demand by `doc._raw.resolve`,
|
|
467
|
+
each container decoded once per document. `xref.sections[i]` gains
|
|
468
|
+
`kind` (`'table' | 'stream'`) and an indirect materialised from a
|
|
469
|
+
container carries `objStm`; the public `readDocument` signature and
|
|
470
|
+
return shape are otherwise unchanged.
|
|
471
|
+
- **`/DecodeParms` reach the decoders as plain values.** Filter dispatch
|
|
472
|
+
now marshals the typed dictionary (or array of dictionaries) into plain
|
|
473
|
+
parameters, so a `/Predictor` (e.g. PNG predictor 12 on cross-reference
|
|
474
|
+
streams) is actually applied instead of silently skipped.
|
|
475
|
+
- **`readDocument` survives two real-world shapes.** `/Root` is resolved
|
|
476
|
+
across a chain of cross-reference streams whose sections carry it in
|
|
477
|
+
different trailers (merged newest first), and a non-catalog object marked
|
|
478
|
+
free but still referenced degrades to a recorded loss instead of a throw;
|
|
479
|
+
the returned document gains a `losses` array for these.
|
|
480
|
+
A document whose catalog itself is free is still refused.
|
|
481
|
+
- **Indirect page resources are resolved.** `typeResources` /
|
|
482
|
+
`resolvePageResources` accept an optional `resolveRef`, so a page whose
|
|
483
|
+
`/ExtGState` (or another resource category) is an indirect reference no
|
|
484
|
+
longer drops the whole resource map, fonts included.
|
|
485
|
+
- **`appendIncremental` extends cross-reference-stream bases** with an
|
|
486
|
+
uncompressed `/Type /XRef` section carrying `/Prev` and `/Root`; the
|
|
487
|
+
classical-table path is byte-unchanged. A hybrid-reference base (a
|
|
488
|
+
classical trailer with `/XRefStm`) is refused with
|
|
489
|
+
`pdf/incremental/hybrid-base`, and a `startxref` that designates neither
|
|
490
|
+
form with `pdf/incremental/unsupported-base`. `pdfXref` gains
|
|
491
|
+
`readXrefStreamDict` and `buildXrefStream`.
|
|
492
|
+
- **Signing over cross-reference-stream and object-stream bases now yields
|
|
493
|
+
a document that re-reads.** `pdfSign.sign()` appends the signature (and
|
|
494
|
+
the LTA DocTimeStamp) through `pdfIncrementalWriter`, so the signature
|
|
495
|
+
section follows the base's cross-reference form (table or stream) and
|
|
496
|
+
carries `/Root`, `/Info` and `/ID` from the merged trailer instead of a
|
|
497
|
+
hard-coded `/Root 1 0 R`. The signature takes the first object number at
|
|
498
|
+
or past the merged `/Size`, so it no longer overwrites an object held in
|
|
499
|
+
an object stream. At LT/LTA the Catalog is resolved through
|
|
500
|
+
`readDocument` from `/Root`, whatever its number or container, instead
|
|
501
|
+
of a byte scan for `1 0 obj`. A hybrid-reference base is refused
|
|
502
|
+
with `pdf/incremental/hybrid-base`, and nothing is written.
|
|
503
|
+
`pdfIncrementalWriter` gains `appendIncrementalWithOffsets` and
|
|
504
|
+
`readBaseTrailer`, and `appendIncremental`'s output is unchanged.
|
|
505
|
+
`pdfSign` gains a `pdfDocument` dependency, appended last. It is required
|
|
506
|
+
only at LT/LTA and reported as `pdf/sign/no-document-reader`. Every level
|
|
507
|
+
now requires `pdfIncrementalWriter`.
|
|
508
|
+
|
|
509
|
+
- **`pdfSign.sign()` registers the signature in a signature
|
|
510
|
+
field.** The `/Sig` update now also writes an invisible `/FT /Sig`
|
|
511
|
+
field merged with its widget (`/T Signature<n>`, `/V`, `/Rect [0 0 0 0]`,
|
|
512
|
+
`/F 132`, `/P` page 1), the page 1 `/Annots` entry and the Catalog
|
|
513
|
+
`/AcroForm` (`/Fields`, `/SigFlags 3`), per ISO 32000-2 §12.7.5.5, so
|
|
514
|
+
viewers list the signature. The LTA `/DocTimeStamp` gets its own field.
|
|
515
|
+
`pdf/sign/no-document-reader` now fires at **every** level, because the
|
|
516
|
+
field needs the Catalog and page 1 — this supersedes the LT/LTA-only rule
|
|
517
|
+
above. An encrypted base keeps the signature-only update (no field).
|
|
518
|
+
- **`assembleIndirects` reports the objects it could not
|
|
519
|
+
resolve.** Read-then-write no longer drops an unresolvable object
|
|
520
|
+
without a trace: every skipped `{ num, gen, code }` is listed on the
|
|
521
|
+
returned array's non-enumerable `skippedObjects` property, and
|
|
522
|
+
`assembleIndirects(model, { strict: true })` throws a `RenderError` coded
|
|
523
|
+
`pdf/writer/unresolvable-objects` whose `context.objects` is that list.
|
|
524
|
+
The default stays lenient and the output for a fully resolvable model is
|
|
525
|
+
unchanged.
|
|
526
|
+
- **ECDSA signature value is DER.** The ECDSA CMS signature value is now
|
|
527
|
+
the DER `ECDSA-Sig-Value`; the verifier accepts the DER form and the
|
|
528
|
+
earlier raw r||s.
|
|
529
|
+
- **Ed25519 signs over SHA-512.** Ed25519 signatures use SHA-512 as
|
|
530
|
+
RFC 8419 requires; `hashAlg` defaults to `sha512` for Ed25519 and any
|
|
531
|
+
other value is refused (`pdf/sign/ed25519-requires-sha512`).
|
|
532
|
+
- **One-byte `/ToUnicode` codespace for simple fonts.** `embedSimple`
|
|
533
|
+
writes a one-byte `/ToUnicode` codespace matching its WinAnsi codes.
|
|
534
|
+
- **Update trailers repeat `/Encrypt`.** Incremental updates written by
|
|
535
|
+
`pdfIncrementalWriter` / `pdfXref.buildXrefStream` can repeat the base's
|
|
536
|
+
`/Encrypt` (`opts.encrypt`); `sign()` does so over encrypted bases.
|
|
537
|
+
- **CMS signed attributes in DER order.** CMS signed attributes are written
|
|
538
|
+
in DER SET OF order, so verifiers that re-encode them (OpenSSL with
|
|
539
|
+
Ed25519) accept the signature.
|
|
540
|
+
|
|
541
|
+
### Removed
|
|
542
|
+
|
|
543
|
+
- **`pdfParserStream`**, the stream-body helpers module. No module depended
|
|
544
|
+
on it and `pdfParser` carries its own helpers. It is no longer in
|
|
545
|
+
`modules` and no longer a named export of `@awacloud/pdf`.
|
|
546
|
+
- **The `prebuilt/` bundle directory** that used to sit under
|
|
547
|
+
`src/bundles/`, and `tools/generate-prebuilds.mjs`/
|
|
548
|
+
`bun run gen:prebuilds` — retired in favour of the two-surface
|
|
549
|
+
`dist/build/` + `dist/standalone/` convention (see Added). Exported
|
|
550
|
+
factory names and resolve keys are unchanged; only the on-disk
|
|
551
|
+
location and generator moved (`tools/generate-bundles.mjs`/
|
|
552
|
+
`bun run gen:bundles`).
|
|
553
|
+
- **Imperative bundle builders** `buildPdfLarge`, `buildPdfFull`,
|
|
554
|
+
`buildPdfLegacy` and the constants `PDF_LARGE_EXTRAS`,
|
|
555
|
+
`PDF_FULL_EXTRAS`, `PDF_LEGACY_EXTRAS` — consumption is now
|
|
556
|
+
exclusively `ModuleRuntime.resolve('pdfLargeBundle' | 'pdfFullBundle'
|
|
557
|
+
| 'pdfLegacyBundle')`; the extras list lives in
|
|
558
|
+
`bundleDescriptor.dependencies`.
|
|
559
|
+
- **Named re-exports of extras from the bundle entry points** — import
|
|
560
|
+
an extra from its canonical module (`@awacloud/pdf/extra/...`), or
|
|
561
|
+
register the `extras` array exported by `@awacloud/pdf` (the root entry
|
|
562
|
+
does not re-export extras by name).
|
|
563
|
+
- **Top-level error-class named exports** (`PdfError`, `ParseError`,
|
|
564
|
+
`RenderError`, `ContractError`, `EncryptionError`) from `@awacloud/pdf`/
|
|
565
|
+
`@awacloud/pdf/errors`, and the transitional ESM compatibility shim that
|
|
566
|
+
temporarily preserved them during the factory-only migration.
|
|
567
|
+
Consumers resolve via `pdfErrors`:
|
|
568
|
+
|
|
569
|
+
```js
|
|
570
|
+
import { pdfErrors } from '@awacloud/pdf';
|
|
571
|
+
const { PdfError, ParseError, isPdfError } = pdfErrors.factory();
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
or `runtime.resolve('pdfErrors')`.
|
|
575
|
+
|
|
576
|
+
### Security
|
|
577
|
+
|
|
578
|
+
- **The encrypted writer uses cryptographic randomness only.**
|
|
579
|
+
`pdfEncryptedWriter` no longer falls back to `Math.random` for keys,
|
|
580
|
+
salts and IVs. It uses `encrypt.randomBytes` when given, else
|
|
581
|
+
`crypto.getRandomValues`; with neither it throws an `EncryptionError`
|
|
582
|
+
with code `pdf/crypto/enc-writer/no-random`.
|
|
583
|
+
- **Signature verification — end of the silent false-positive.**
|
|
584
|
+
Before public-key wiring, `verifySignature(...)` returned
|
|
585
|
+
`valid: errors.length === 0` without ever invoking `rsa.pssVerify` /
|
|
586
|
+
`ecc.verify` / `ed25519.verify` — a PKCS#7 structurally valid but
|
|
587
|
+
cryptographically forged signature reported `valid: true` to a naïve
|
|
588
|
+
consumer. `verified`/`valid` are now `true` only once the digest
|
|
589
|
+
chain **and** PK-verify both succeed (see Changed).
|
|
590
|
+
- **`auditByteRange(...)`** (`src/sig/byteRange.js`) — public helper
|
|
591
|
+
detecting six `/ByteRange` attack vectors: `self-overlap`,
|
|
592
|
+
`gap-start-mismatch`, `gap-end-mismatch`, `cross-overlap`,
|
|
593
|
+
`incomplete-coverage` (opt-in `requireFullCoverage`),
|
|
594
|
+
`non-zero-start`. Exposed via `runtime.resolve('pdfByteRange')`.
|
|
595
|
+
- **Sandboxed action flag** — every typer for `/Launch`, `/JavaScript`,
|
|
596
|
+
`/SubmitForm`, `/ImportData`, `/URI` adds `sandboxed: true` to its
|
|
597
|
+
returned record, alongside the existing `securityWarning`, so a naïve
|
|
598
|
+
consumer can't mistake a typed action record for an execution
|
|
599
|
+
instruction. The opt-in `pdfSandbox` module (`pdf-full` bundle)
|
|
600
|
+
additionally exposes `lintActions([...])` → `{ hasErrors,
|
|
601
|
+
hasActiveContent, issues }`.
|
|
602
|
+
- **Parser hardening** — see Added (`parserLimits`): depth cap, array
|
|
603
|
+
literal cap, stream fallback-scan quota, each raising a typed
|
|
604
|
+
`pdf/parser/*` error.
|
|
605
|
+
- **Encryption** — Standard Security Handler V4/V5/V6 decrypt + encrypt
|
|
606
|
+
(AES-128/256-CBC, and RC4-128 through the V4 handler's `V2` crypt
|
|
607
|
+
filter), AES-GCM (TS 32003) decrypt + encrypt. The older RC4 revisions
|
|
608
|
+
(40-bit R2, 128-bit R3) are read-only, through the opt-in
|
|
609
|
+
`legacy-rc4-read` extra of the `pdf-legacy` bundle.
|