modern-pdf-lib 0.33.0 → 0.35.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.
Files changed (42) hide show
  1. package/README.md +3 -3
  2. package/dist/browser.cjs +10 -3
  3. package/dist/browser.d.cts +5 -5
  4. package/dist/browser.d.mts +5 -5
  5. package/dist/browser.mjs +4 -4
  6. package/dist/{compressionAnalysis-0m5jJG1_.d.mts → compressionAnalysis-4EW8MJBa.d.mts} +2 -2
  7. package/dist/{compressionAnalysis-0m5jJG1_.d.mts.map → compressionAnalysis-4EW8MJBa.d.mts.map} +1 -1
  8. package/dist/{compressionAnalysis-CSBcmi0_.d.cts → compressionAnalysis-Cz3yWa-O.d.cts} +2 -2
  9. package/dist/{compressionAnalysis-CSBcmi0_.d.cts.map → compressionAnalysis-Cz3yWa-O.d.cts.map} +1 -1
  10. package/dist/create.cjs +2 -2
  11. package/dist/create.d.cts +2 -2
  12. package/dist/create.d.mts +2 -2
  13. package/dist/create.mjs +2 -2
  14. package/dist/{fontEmbed-Bzv89wgp.d.mts → fontEmbed-CTTeV1mZ.d.mts} +2 -2
  15. package/dist/{fontEmbed-Bzv89wgp.d.mts.map → fontEmbed-CTTeV1mZ.d.mts.map} +1 -1
  16. package/dist/{fontEmbed-Dwl1XeEA.d.cts → fontEmbed-DxvWoqOt.d.cts} +2 -2
  17. package/dist/{fontEmbed-Dwl1XeEA.d.cts.map → fontEmbed-DxvWoqOt.d.cts.map} +1 -1
  18. package/dist/{index-BqYQ9lsY.d.cts → index-CIdDdXlK.d.cts} +318 -45
  19. package/dist/index-CIdDdXlK.d.cts.map +1 -0
  20. package/dist/{index-BJtSRrMf.d.mts → index-CwgepM_G.d.mts} +318 -45
  21. package/dist/index-CwgepM_G.d.mts.map +1 -0
  22. package/dist/index.cjs +10 -3
  23. package/dist/index.d.cts +5 -5
  24. package/dist/index.d.mts +5 -5
  25. package/dist/index.mjs +4 -4
  26. package/dist/{layout-xOcesNCh.mjs → layout-BZ9InKTl.mjs} +2 -2
  27. package/dist/{layout-BYXpcYtC.cjs → layout-DvciSXsr.cjs} +2 -2
  28. package/dist/parse.cjs +1 -1
  29. package/dist/parse.d.cts +2 -2
  30. package/dist/parse.d.mts +2 -2
  31. package/dist/parse.mjs +1 -1
  32. package/dist/{pdfDocument-B8tQcZqj.d.cts → pdfDocument-BX5o5hI7.d.cts} +13 -1
  33. package/dist/{pdfDocument-B-8iPl_j.d.mts.map → pdfDocument-BX5o5hI7.d.cts.map} +1 -1
  34. package/dist/{pdfDocument-B-8iPl_j.d.mts → pdfDocument-C7TItmPQ.d.mts} +13 -1
  35. package/dist/{pdfDocument-B8tQcZqj.d.cts.map → pdfDocument-C7TItmPQ.d.mts.map} +1 -1
  36. package/dist/{pdfDocument-Bh4ebDqE.cjs → pdfDocument-D5qz7duP.cjs} +376 -21
  37. package/dist/{pdfDocument-Cgkkk8F8.mjs → pdfDocument-Q0wrwKEZ.mjs} +347 -22
  38. package/dist/{src-zeRl33xQ.mjs → src-BlUlmYsU.mjs} +1300 -25
  39. package/dist/{src-BdVnpRoy.cjs → src-C-mBizNU.cjs} +1327 -22
  40. package/package.json +1 -1
  41. package/dist/index-BJtSRrMf.d.mts.map +0 -1
  42. package/dist/index-BqYQ9lsY.d.cts.map +0 -1
@@ -1,8 +1,8 @@
1
- import { A as encodeUTCTime, Br as rectangle, Bt as PageSizes, C as encodeInteger, E as encodeOctetString, F as parseDerTlv, Gr as setLineWidth, H as mergePdfs, I as toBuffer, Jr as beginText, Kn as applyFillColor, L as computeSignatureHash, M as extractIssuerAndSerial, N as extractSubjectPublicKeyInfo, O as encodeSequence, P as getSubtle, Pr as fill, Rn as restoreState, Rr as lineTo, S as encodeContextTag, Sn as formatPdfDate, T as encodeOID, Vn as saveState, Vr as setDashPattern, Xr as moveText, Yn as cmykToRgb, Yr as endText, at as sha256, b as detectKeyAlgorithm, ei as setFont, gn as buildAnnotationDict, gt as PdfParseError, k as encodeSet, mn as PdfAnnotation, n as StandardFonts, oi as setWordSpacing, qn as applyStrokeColor, qr as stroke, r as createPdf, s as setPageLabels, si as showText$1, t as PdfDocument, x as detectNamedCurve, y as decodeOidBytes, z as findSignatures, zr as moveTo } from "./pdfDocument-Cgkkk8F8.mjs";
2
- import { c as PdfRef, i as PdfName, l as PdfStream, n as PdfBool, o as PdfNumber, r as PdfDict, t as PdfArray, u as PdfString } from "./pdfObjects-CB7TEdbW.mjs";
1
+ import { $r as beginText, A as encodeUTCTime, C as encodeInteger, Dn as formatPdfDate, E as encodeOctetString, F as parseDerTlv, Gr as rectangle, Gt as PageSizes, I as toBuffer, Kn as saveState, Kr as setDashPattern, M as extractIssuerAndSerial, N as extractSubjectPublicKeyInfo, O as encodeSequence, P as getSubtle, Qn as applyStrokeColor, Qr as stroke, S as encodeContextTag, T as encodeOID, Tn as buildInfoDict, Un as restoreState, Ur as lineTo, Ut as serializePdf, V as findSignatures, W as mergePdfs, Wr as moveTo, Xr as setLineWidth, Zn as applyFillColor, ai as setFont, b as detectKeyAlgorithm, bt as PdfLexer, di as setWordSpacing, ei as endText, er as cmykToRgb, fi as showText$1, k as encodeSet, n as StandardFonts, nt as loadPdf, r as createPdf, rt as PdfEncryptionHandler, s as setPageLabels, st as sha256, t as PdfDocument, ti as moveText, vt as XrefParser, x as detectNamedCurve, xn as buildAnnotationDict, xt as PdfParseError, y as decodeOidBytes, yn as PdfAnnotation, yt as PdfObjectParser, z as computeSignatureHash, zr as fill } from "./pdfDocument-Q0wrwKEZ.mjs";
2
+ import { c as PdfRef, i as PdfName, l as PdfStream, n as PdfBool, o as PdfNumber, r as PdfDict, s as PdfObjectRegistry, t as PdfArray, u as PdfString } from "./pdfObjects-CB7TEdbW.mjs";
3
3
  import { n as decodeStreamData, r as getStreamFilters } from "./streamDecode-DCpgTocN.mjs";
4
4
  import { g as FieldFlags, v as numVal } from "./pdfForm-CfLnlsj-.mjs";
5
- import { i as parseContentStream } from "./compressionAnalysis-BEd_745I.mjs";
5
+ import { i as parseContentStream, o as extractTextWithPositions } from "./compressionAnalysis-BEd_745I.mjs";
6
6
  import { n as decodeJpegWasm } from "./bridge-7dhURZj7.mjs";
7
7
  import { r as detectRuntime } from "./loader-DkrXz-h4.mjs";
8
8
  import { deflateSync, inflateSync, unzlibSync } from "fflate";
@@ -277,7 +277,7 @@ function compressStream(stream, level) {
277
277
  * @returns The incremental save result.
278
278
  */
279
279
  async function saveDocumentIncremental(originalBytes, doc, options) {
280
- const { buildDocumentStructure } = await import("./pdfDocument-Cgkkk8F8.mjs").then((n) => n.Cn);
280
+ const { buildDocumentStructure } = await import("./pdfDocument-Q0wrwKEZ.mjs").then((n) => n.On);
281
281
  const registry = doc.getRegistry();
282
282
  const structure = buildDocumentStructure(doc.getInternalPages().map((p) => p.finalize()), {
283
283
  producer: doc.getProducer(),
@@ -4280,7 +4280,7 @@ function findChangedObjects(original, modified) {
4280
4280
  continue;
4281
4281
  }
4282
4282
  if (computeObjectHash(origObj.content) !== computeObjectHash(modObj.content)) {
4283
- if (!bytesEqual(origObj.content, modObj.content)) changedObjNums.push(objNum);
4283
+ if (!bytesEqual$1(origObj.content, modObj.content)) changedObjNums.push(objNum);
4284
4284
  }
4285
4285
  }
4286
4286
  return changedObjNums.sort((a, b) => a - b);
@@ -4288,7 +4288,7 @@ function findChangedObjects(original, modified) {
4288
4288
  /**
4289
4289
  * Compare two Uint8Arrays for equality.
4290
4290
  */
4291
- function bytesEqual(a, b) {
4291
+ function bytesEqual$1(a, b) {
4292
4292
  if (a.length !== b.length) return false;
4293
4293
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
4294
4294
  return true;
@@ -4326,7 +4326,7 @@ function optimizeIncrementalSave(originalPdf, changes) {
4326
4326
  const changeHash = computeObjectHash(change.newContent);
4327
4327
  const origObj = originalObjs.get(change.objectNumber);
4328
4328
  if (origObj) {
4329
- if (computeObjectHash(origObj.content) === changeHash && bytesEqual(origObj.content, change.newContent)) continue;
4329
+ if (computeObjectHash(origObj.content) === changeHash && bytesEqual$1(origObj.content, change.newContent)) continue;
4330
4330
  }
4331
4331
  const dedupeKey = `${change.objectNumber}:${change.generationNumber}:${changeHash}`;
4332
4332
  if (seenHashes.has(dedupeKey)) continue;
@@ -24457,7 +24457,7 @@ function extractCrlUrls(cert) {
24457
24457
  /**
24458
24458
  * Extract the DER-encoded subject Name from a certificate.
24459
24459
  */
24460
- function extractSubjectDer$1(certDer) {
24460
+ function extractSubjectDer$2(certDer) {
24461
24461
  const tbsCert = parseDerTlv(certDer, 0).children[0];
24462
24462
  let idx = 0;
24463
24463
  if (tbsCert.children[0].tag === 160) idx = 1;
@@ -24468,7 +24468,7 @@ function extractSubjectDer$1(certDer) {
24468
24468
  /**
24469
24469
  * Extract the DER-encoded issuer Name from a certificate.
24470
24470
  */
24471
- function extractIssuerDer$1(certDer) {
24471
+ function extractIssuerDer$2(certDer) {
24472
24472
  const tbsCert = parseDerTlv(certDer, 0).children[0];
24473
24473
  let idx = 0;
24474
24474
  if (tbsCert.children[0].tag === 160) idx = 1;
@@ -24590,7 +24590,7 @@ var TrustStore = class {
24590
24590
  */
24591
24591
  async isTrusted(cert) {
24592
24592
  await this._ready;
24593
- const key = await computeSubjectKey(extractSubjectDer$1(cert));
24593
+ const key = await computeSubjectKey(extractSubjectDer$2(cert));
24594
24594
  const entries = this._certs.get(key);
24595
24595
  if (!entries) return false;
24596
24596
  return entries.some((e) => compareBytes$1(e.der, cert));
@@ -24607,7 +24607,7 @@ var TrustStore = class {
24607
24607
  */
24608
24608
  async findIssuer(cert) {
24609
24609
  await this._ready;
24610
- const key = await computeSubjectKey(extractIssuerDer$1(cert));
24610
+ const key = await computeSubjectKey(extractIssuerDer$2(cert));
24611
24611
  const entries = this._certs.get(key);
24612
24612
  if (!entries || entries.length === 0) return null;
24613
24613
  return entries[0].der;
@@ -24641,7 +24641,7 @@ var TrustStore = class {
24641
24641
  * Add a single certificate to the store.
24642
24642
  */
24643
24643
  async _addOne(cert) {
24644
- const key = await computeSubjectKey(extractSubjectDer$1(cert));
24644
+ const key = await computeSubjectKey(extractSubjectDer$2(cert));
24645
24645
  const entry = {
24646
24646
  der: cert,
24647
24647
  serialBytes: extractSerialBytes(cert),
@@ -26729,7 +26729,7 @@ function parseAsn1Time(node) {
26729
26729
  /**
26730
26730
  * Extract the subject raw DER bytes from a certificate.
26731
26731
  */
26732
- function extractSubjectDer(certDer) {
26732
+ function extractSubjectDer$1(certDer) {
26733
26733
  const tbsCert = parseDerTlv(certDer, 0).children[0];
26734
26734
  let idx = 0;
26735
26735
  if (tbsCert.children[0].tag === 160) idx = 1;
@@ -26740,7 +26740,7 @@ function extractSubjectDer(certDer) {
26740
26740
  /**
26741
26741
  * Extract the issuer raw DER bytes from a certificate.
26742
26742
  */
26743
- function extractIssuerDer(certDer) {
26743
+ function extractIssuerDer$1(certDer) {
26744
26744
  const tbsCert = parseDerTlv(certDer, 0).children[0];
26745
26745
  let idx = 0;
26746
26746
  if (tbsCert.children[0].tag === 160) idx = 1;
@@ -26794,8 +26794,8 @@ function isCA(certDer) {
26794
26794
  * Check if a certificate is self-signed (subject === issuer).
26795
26795
  */
26796
26796
  function isSelfSigned(certDer) {
26797
- const subjectDer = extractSubjectDer(certDer);
26798
- const issuerDer = extractIssuerDer(certDer);
26797
+ const subjectDer = extractSubjectDer$1(certDer);
26798
+ const issuerDer = extractIssuerDer$1(certDer);
26799
26799
  if (subjectDer.length !== issuerDer.length) return false;
26800
26800
  for (let i = 0; i < subjectDer.length; i++) if (subjectDer[i] !== issuerDer[i]) return false;
26801
26801
  return true;
@@ -26993,9 +26993,9 @@ function buildCertificateChain(leaf, intermediates) {
26993
26993
  chain,
26994
26994
  complete: true
26995
26995
  };
26996
- const currentIssuerDer = extractIssuerDer(current);
26996
+ const currentIssuerDer = extractIssuerDer$1(current);
26997
26997
  let foundIdx = -1;
26998
- for (let i = 0; i < available.length; i++) if (namesEqual(currentIssuerDer, extractSubjectDer(available[i]))) {
26998
+ for (let i = 0; i < available.length; i++) if (namesEqual(currentIssuerDer, extractSubjectDer$1(available[i]))) {
26999
26999
  foundIdx = i;
27000
27000
  break;
27001
27001
  }
@@ -27083,8 +27083,8 @@ async function validateCertificateChain(chain, options) {
27083
27083
  if (!signatureValid) certErrors.push("Root certificate self-signature verification failed");
27084
27084
  } else {
27085
27085
  let foundTrusted = false;
27086
- const certIssuerDer = extractIssuerDer(certDer);
27087
- for (const trusted of trustedCerts) if (namesEqual(certIssuerDer, extractSubjectDer(trusted))) {
27086
+ const certIssuerDer = extractIssuerDer$1(certDer);
27087
+ for (const trusted of trustedCerts) if (namesEqual(certIssuerDer, extractSubjectDer$1(trusted))) {
27088
27088
  signatureValid = await verifyCertSignature(certDer, trusted);
27089
27089
  foundTrusted = true;
27090
27090
  break;
@@ -27841,6 +27841,1281 @@ function extractNodeBytesFromParent(fullBuffer, parent, child) {
27841
27841
  return fullBuffer.subarray(start, start + child.totalLength);
27842
27842
  }
27843
27843
  //#endregion
27844
+ //#region src/signature/certPathBuilder.ts
27845
+ /**
27846
+ * @module signature/certPathBuilder
27847
+ *
27848
+ * Certification-path (trust-chain) construction per RFC 5280 §6.1.
27849
+ *
27850
+ * Given a leaf certificate, a pool of intermediate CA certificates, and a
27851
+ * set of trust anchors, {@link buildCertPath} assembles the ordered chain
27852
+ *
27853
+ * ```
27854
+ * leaf -> intermediate -> ... -> (issuer that is a trust anchor)
27855
+ * ```
27856
+ *
27857
+ * by matching, at each step, the *current* certificate's **issuer** Name to
27858
+ * a candidate certificate's **subject** Name (RFC 5280 §4.1.2.4 / §4.1.2.6).
27859
+ * When both certificates additionally carry the relevant key-identifier
27860
+ * extensions, the candidate's **Subject Key Identifier** (SKI, OID
27861
+ * `2.5.29.14`, RFC 5280 §4.2.1.2) must equal the current certificate's
27862
+ * **Authority Key Identifier** (AKI `keyIdentifier`, OID `2.5.29.35`,
27863
+ * RFC 5280 §4.2.1.1) for the link to be accepted. If only one side carries
27864
+ * the identifier, name matching alone is used (RFC 5280 §6.1.4 treats key
27865
+ * identifiers as a hint, not a hard requirement).
27866
+ *
27867
+ * Building stops when:
27868
+ * - the current certificate (or a matched issuer) is a member of `anchors`
27869
+ * → `complete: true`, `anchor` set, and `path` excludes the anchor; or
27870
+ * - no issuer can be found among `intermediates`/`anchors`
27871
+ * → `complete: false` (partial path returned).
27872
+ *
27873
+ * Loop protection: a certificate already present in the constructed path is
27874
+ * never revisited (RFC 5280 §6.1 prohibits a certificate appearing more than
27875
+ * once in a certification path).
27876
+ *
27877
+ * Name matching uses byte-for-byte equality of the DER-encoded `Name`. This
27878
+ * is the exact-match comparison permitted by RFC 5280 §7.1 when both names
27879
+ * are produced by conforming encoders (as is the case for fixtures generated
27880
+ * here and for the overwhelming majority of real-world CAs).
27881
+ *
27882
+ * References:
27883
+ * - RFC 5280 §4.1.2.4 (issuer), §4.1.2.6 (subject)
27884
+ * - RFC 5280 §4.2.1.1 (Authority Key Identifier, OID 2.5.29.35)
27885
+ * - RFC 5280 §4.2.1.2 (Subject Key Identifier, OID 2.5.29.14)
27886
+ * - RFC 5280 §6.1 (Certification Path Validation — path construction)
27887
+ *
27888
+ * @packageDocumentation
27889
+ */
27890
+ /** Subject Key Identifier — RFC 5280 §4.2.1.2. */
27891
+ const OID_SUBJECT_KEY_IDENTIFIER = "2.5.29.14";
27892
+ /** Authority Key Identifier — RFC 5280 §4.2.1.1. */
27893
+ const OID_AUTHORITY_KEY_IDENTIFIER = "2.5.29.35";
27894
+ /**
27895
+ * Reconstruct the absolute byte range of a child node within the original
27896
+ * certificate buffer, returning the full TLV (header + value) as a subarray
27897
+ * that shares the cert's underlying ArrayBuffer.
27898
+ *
27899
+ * `parentNode.data` is a subarray of `certDer`; `child.offset` is the child's
27900
+ * offset within that parent value; `child.totalLength` covers header + value.
27901
+ */
27902
+ function sliceChild(certDer, parentNode, child) {
27903
+ const start = child.offset + (parentNode.data.byteOffset - certDer.byteOffset);
27904
+ return certDer.subarray(start, start + child.totalLength);
27905
+ }
27906
+ /**
27907
+ * Resolve the TBSCertificate node and the index offset that accounts for the
27908
+ * optional `version [0] EXPLICIT` field.
27909
+ *
27910
+ * TBSCertificate ::= SEQUENCE {
27911
+ * version [0] EXPLICIT INTEGER DEFAULT v1, -- tag 0xA0 when present
27912
+ * serialNumber INTEGER,
27913
+ * signature AlgorithmIdentifier,
27914
+ * issuer Name,
27915
+ * validity Validity,
27916
+ * subject Name,
27917
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
27918
+ * ... extensions [3] EXPLICIT ...
27919
+ * }
27920
+ */
27921
+ function tbsContext(certDer) {
27922
+ const tbs = parseDerTlv(certDer, 0).children[0];
27923
+ if (!tbs) throw new Error("Malformed certificate: missing TBSCertificate");
27924
+ const first = tbs.children[0];
27925
+ return {
27926
+ tbs,
27927
+ idx: first && first.tag === 160 ? 1 : 0
27928
+ };
27929
+ }
27930
+ /** Extract the raw DER bytes of the issuer Name (RFC 5280 §4.1.2.4). */
27931
+ function extractIssuerDer(certDer) {
27932
+ const { tbs, idx } = tbsContext(certDer);
27933
+ const issuerNode = tbs.children[idx + 2];
27934
+ if (!issuerNode) throw new Error("Malformed certificate: missing issuer");
27935
+ return sliceChild(certDer, tbs, issuerNode);
27936
+ }
27937
+ /** Extract the raw DER bytes of the subject Name (RFC 5280 §4.1.2.6). */
27938
+ function extractSubjectDer(certDer) {
27939
+ const { tbs, idx } = tbsContext(certDer);
27940
+ const subjectNode = tbs.children[idx + 4];
27941
+ if (!subjectNode) throw new Error("Malformed certificate: missing subject");
27942
+ return sliceChild(certDer, tbs, subjectNode);
27943
+ }
27944
+ /**
27945
+ * Extract the list of Extension nodes (each a SEQUENCE) from a certificate,
27946
+ * or an empty array when no extensions are present.
27947
+ *
27948
+ * extensions [3] EXPLICIT SEQUENCE OF Extension
27949
+ * Extension ::= SEQUENCE { extnID OID, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING }
27950
+ */
27951
+ function extractExtensionNodes(certDer) {
27952
+ try {
27953
+ const { tbs } = tbsContext(certDer);
27954
+ for (const child of tbs.children) if (child.tag === 163 && child.children.length > 0) return child.children[0].children;
27955
+ } catch {}
27956
+ return [];
27957
+ }
27958
+ /**
27959
+ * Locate the `extnValue` OCTET STRING contents for a given extension OID.
27960
+ * Returns the raw bytes inside the OCTET STRING (the DER of the extension's
27961
+ * value), or `undefined` if the extension is absent.
27962
+ */
27963
+ function findExtensionValue(certDer, oid) {
27964
+ for (const ext of extractExtensionNodes(certDer)) {
27965
+ const oidNode = ext.children[0];
27966
+ if (!oidNode) continue;
27967
+ if (decodeOidBytes(oidNode.data) !== oid) continue;
27968
+ const valueNode = ext.children[ext.children.length - 1];
27969
+ if (!valueNode) return void 0;
27970
+ return valueNode.data;
27971
+ }
27972
+ }
27973
+ /**
27974
+ * Extract the Subject Key Identifier (key bytes) — RFC 5280 §4.2.1.2.
27975
+ *
27976
+ * SubjectKeyIdentifier ::= KeyIdentifier
27977
+ * KeyIdentifier ::= OCTET STRING
27978
+ *
27979
+ * extnValue (an OCTET STRING) wraps the KeyIdentifier OCTET STRING, so we
27980
+ * parse one inner OCTET STRING to obtain the raw identifier bytes.
27981
+ */
27982
+ function extractSki(certDer) {
27983
+ const extnValue = findExtensionValue(certDer, OID_SUBJECT_KEY_IDENTIFIER);
27984
+ if (!extnValue) return void 0;
27985
+ try {
27986
+ const inner = parseDerTlv(extnValue, 0);
27987
+ if (inner.tag !== 4) return void 0;
27988
+ return inner.data;
27989
+ } catch {
27990
+ return;
27991
+ }
27992
+ }
27993
+ /**
27994
+ * Extract the Authority Key Identifier `keyIdentifier` — RFC 5280 §4.2.1.1.
27995
+ *
27996
+ * AuthorityKeyIdentifier ::= SEQUENCE {
27997
+ * keyIdentifier [0] KeyIdentifier OPTIONAL, -- IMPLICIT OCTET STRING, tag 0x80
27998
+ * authorityCertIssuer [1] GeneralNames OPTIONAL,
27999
+ * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
28000
+ *
28001
+ * extnValue (an OCTET STRING) wraps the SEQUENCE. We return the bytes of the
28002
+ * `[0]` IMPLICIT field (context tag 0x80), or `undefined` if absent.
28003
+ */
28004
+ function extractAkiKeyId(certDer) {
28005
+ const extnValue = findExtensionValue(certDer, OID_AUTHORITY_KEY_IDENTIFIER);
28006
+ if (!extnValue) return void 0;
28007
+ try {
28008
+ const seq = parseDerTlv(extnValue, 0);
28009
+ if (seq.tag !== 48) return void 0;
28010
+ for (const field of seq.children) if (field.tag === 128) return field.data;
28011
+ } catch {
28012
+ return;
28013
+ }
28014
+ }
28015
+ /** Byte-for-byte equality of two arrays. */
28016
+ function bytesEqual(a, b) {
28017
+ if (a.length !== b.length) return false;
28018
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
28019
+ return true;
28020
+ }
28021
+ /**
28022
+ * Determine whether `candidate` could be the issuer of `cert`:
28023
+ * the candidate's subject DN must equal the cert's issuer DN, and — only when
28024
+ * BOTH key identifiers are present — the candidate's SKI must equal the cert's
28025
+ * AKI keyIdentifier (RFC 5280 §6.1.4 / §4.2.1.1).
28026
+ */
28027
+ function isIssuerOf(cert, candidate) {
28028
+ if (!bytesEqual(extractIssuerDer(cert), extractSubjectDer(candidate))) return false;
28029
+ const aki = extractAkiKeyId(cert);
28030
+ const ski = extractSki(candidate);
28031
+ if (aki && ski) return bytesEqual(aki, ski);
28032
+ return true;
28033
+ }
28034
+ /**
28035
+ * Build an ordered certification path from a leaf certificate to a trust
28036
+ * anchor per RFC 5280 §6.1.
28037
+ *
28038
+ * @param leafCertDer DER-encoded end-entity (leaf) certificate.
28039
+ * @param intermediates DER-encoded intermediate CA certificates (any order).
28040
+ * @param anchors DER-encoded trust anchors (root or directly-trusted CAs).
28041
+ * @returns {@link CertPathResult} — `path` is leaf-first and
28042
+ * excludes the anchor; `anchor` is reported separately
28043
+ * when the path is `complete`.
28044
+ *
28045
+ * @example
28046
+ * ```ts
28047
+ * const { path, complete, anchor } = buildCertPath(leaf, [intermediate], [root]);
28048
+ * // path = [leaf, intermediate], complete = true, anchor = root
28049
+ * ```
28050
+ */
28051
+ function buildCertPath(leafCertDer, intermediates, anchors) {
28052
+ const leafAnchor = anchors.find((a) => bytesEqual(a, leafCertDer));
28053
+ if (leafAnchor) return {
28054
+ path: [leafCertDer],
28055
+ complete: true,
28056
+ anchor: leafAnchor
28057
+ };
28058
+ const path = [leafCertDer];
28059
+ let current = leafCertDer;
28060
+ const maxDepth = intermediates.length + anchors.length + 2;
28061
+ for (let depth = 0; depth < maxDepth; depth++) {
28062
+ const anchor = anchors.find((a) => isIssuerOf(current, a));
28063
+ if (anchor) return {
28064
+ path,
28065
+ complete: true,
28066
+ anchor
28067
+ };
28068
+ const next = intermediates.find((c) => isIssuerOf(current, c) && !path.some((p) => bytesEqual(p, c)));
28069
+ if (!next) return {
28070
+ path,
28071
+ complete: false,
28072
+ anchor: void 0
28073
+ };
28074
+ path.push(next);
28075
+ current = next;
28076
+ }
28077
+ return {
28078
+ path,
28079
+ complete: false,
28080
+ anchor: void 0
28081
+ };
28082
+ }
28083
+ //#endregion
28084
+ //#region src/security/threatScanner.ts
28085
+ /** Numeric rank for severities so we can take a maximum. */
28086
+ const SEVERITY_RANK = {
28087
+ low: 1,
28088
+ medium: 2,
28089
+ high: 3
28090
+ };
28091
+ /** Reverse lookup from rank back to severity. */
28092
+ const RANK_SEVERITY = [
28093
+ "low",
28094
+ "medium",
28095
+ "high"
28096
+ ];
28097
+ /**
28098
+ * File-name extensions that denote directly executable / script payloads.
28099
+ * An attachment ending in one of these is treated as high severity because a
28100
+ * viewer's "open attachment" (or a `/Launch` action targeting it) can run it.
28101
+ */
28102
+ const EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
28103
+ "exe",
28104
+ "com",
28105
+ "scr",
28106
+ "pif",
28107
+ "cpl",
28108
+ "msi",
28109
+ "msp",
28110
+ "mst",
28111
+ "dll",
28112
+ "sys",
28113
+ "drv",
28114
+ "ocx",
28115
+ "bat",
28116
+ "cmd",
28117
+ "ps1",
28118
+ "psm1",
28119
+ "vbs",
28120
+ "vbe",
28121
+ "vb",
28122
+ "wsf",
28123
+ "wsh",
28124
+ "js",
28125
+ "jse",
28126
+ "jar",
28127
+ "class",
28128
+ "sh",
28129
+ "bash",
28130
+ "zsh",
28131
+ "ksh",
28132
+ "csh",
28133
+ "command",
28134
+ "app",
28135
+ "dmg",
28136
+ "pkg",
28137
+ "lnk",
28138
+ "url",
28139
+ "reg",
28140
+ "hta",
28141
+ "gadget",
28142
+ "inf",
28143
+ "scf",
28144
+ "apk",
28145
+ "deb",
28146
+ "rpm",
28147
+ "run",
28148
+ "bin",
28149
+ "elf",
28150
+ "so",
28151
+ "dylib",
28152
+ "py",
28153
+ "pyc",
28154
+ "pyw",
28155
+ "rb",
28156
+ "pl",
28157
+ "php"
28158
+ ]);
28159
+ /** Read a `PdfName` value (without the leading `/`) from a dict entry. */
28160
+ function nameValue$1(obj) {
28161
+ if (obj !== void 0 && obj.kind === "name") {
28162
+ const v = obj.value;
28163
+ return v.startsWith("/") ? v.slice(1) : v;
28164
+ }
28165
+ }
28166
+ /** Read a `PdfString` value from a dict entry. */
28167
+ function stringValue(obj) {
28168
+ if (obj !== void 0 && obj.kind === "string") return obj.value;
28169
+ }
28170
+ /** Format a `PdfRef` as the canonical `"N G R"` string, if available. */
28171
+ function refString(ref) {
28172
+ return ref ? `${ref.objectNumber} ${ref.generationNumber} R` : void 0;
28173
+ }
28174
+ /** Lower-case file extension of a name, or `''` when there is none. */
28175
+ function extensionOf(name) {
28176
+ const base = name.replace(/[\\/]+/g, "/").split("/").pop() ?? name;
28177
+ const dot = base.lastIndexOf(".");
28178
+ if (dot < 0 || dot === base.length - 1) return "";
28179
+ return base.slice(dot + 1).toLowerCase();
28180
+ }
28181
+ /**
28182
+ * Scan a PDF for hostile constructs and return a {@link ThreatReport}.
28183
+ *
28184
+ * The scan never executes any document content. It parses the PDF and walks
28185
+ * the parsed object graph (see the module header for the precise method and
28186
+ * ISO 32000 references). When parsing fails, a guarded raw-byte fallback runs.
28187
+ *
28188
+ * @param pdf Raw PDF bytes.
28189
+ * @returns A report of findings plus the aggregate `riskLevel`.
28190
+ */
28191
+ async function scanPdfThreats(pdf) {
28192
+ const findings = [];
28193
+ let scannedGraph = false;
28194
+ try {
28195
+ scanObjectGraph((await loadPdf(pdf, { ignoreEncryption: true })).getRegistry(), findings);
28196
+ scannedGraph = true;
28197
+ } catch {
28198
+ scannedGraph = false;
28199
+ }
28200
+ if (!scannedGraph) scanRawBytesFallback(pdf, findings);
28201
+ return {
28202
+ findings,
28203
+ riskLevel: aggregateRisk(findings)
28204
+ };
28205
+ }
28206
+ /**
28207
+ * Walk every registered object and emit findings.
28208
+ *
28209
+ * We iterate the registry (every resolved indirect object). For each
28210
+ * dictionary (including stream dictionaries) we inspect that dict's *own
28211
+ * keys* and, where relevant, the resolved action-subtype `/S` *name*. Content
28212
+ * streams' raw bytes are never substring-scanned here, which is what makes the
28213
+ * scan precise (drawn text that merely says "JavaScript" is not a finding).
28214
+ */
28215
+ function scanObjectGraph(registry, findings) {
28216
+ for (const entry of registry) {
28217
+ const obj = entry.object;
28218
+ const refStr = refString(entry.ref);
28219
+ let dict;
28220
+ if (obj.kind === "dict") dict = obj;
28221
+ else if (obj.kind === "stream") dict = obj.dict;
28222
+ if (dict === void 0) continue;
28223
+ inspectDict(dict, refStr, findings);
28224
+ }
28225
+ }
28226
+ /**
28227
+ * Inspect a single dictionary's keys/values for dangerous constructs.
28228
+ *
28229
+ * @param dict The dictionary (or stream dictionary).
28230
+ * @param refStr The owning object's `"N G R"` string, if known.
28231
+ * @param findings Accumulator.
28232
+ */
28233
+ function inspectDict(dict, refStr, findings) {
28234
+ if (dict.has("/OpenAction")) findings.push({
28235
+ category: "OpenAction",
28236
+ severity: "medium",
28237
+ detail: "Document defines an /OpenAction that runs automatically when the PDF is opened (ISO 32000 §12.6.3).",
28238
+ objectRef: refStr
28239
+ });
28240
+ if (dict.has("/AA")) findings.push({
28241
+ category: "AA",
28242
+ severity: "medium",
28243
+ detail: "Document or object defines /AA additional actions that fire on viewer events such as open/close/print/save (ISO 32000 §12.6.2).",
28244
+ objectRef: refStr
28245
+ });
28246
+ if (dict.has("/JavaScript")) findings.push({
28247
+ category: "JavaScript",
28248
+ severity: "high",
28249
+ detail: "A /JavaScript name tree (catalog /Names → /JavaScript) is present; these scripts execute automatically on open (ISO 32000 §12.6.4.16, §7.7.4).",
28250
+ objectRef: refStr
28251
+ });
28252
+ const subtype = nameValue$1(dict.get("/S"));
28253
+ if (subtype !== void 0) inspectActionSubtype(subtype, dict, refStr, findings);
28254
+ if (dict.has("/XFA")) findings.push({
28255
+ category: "XFA",
28256
+ severity: "low",
28257
+ detail: "Document contains an XFA form (/AcroForm → /XFA, ISO 32000 §12.7.8); XFA carries its own scripting and data-binding model.",
28258
+ objectRef: refStr
28259
+ });
28260
+ const annotSubtype = nameValue$1(dict.get("/Subtype"));
28261
+ if (annotSubtype === "RichMedia") findings.push({
28262
+ category: "RichMedia",
28263
+ severity: "low",
28264
+ detail: "Rich-media annotation (/Subtype /RichMedia, ISO 32000-2 §13.6) embeds interactive multimedia (e.g. Flash/video).",
28265
+ objectRef: refStr
28266
+ });
28267
+ else if (annotSubtype === "Movie") findings.push({
28268
+ category: "Movie",
28269
+ severity: "low",
28270
+ detail: "Movie annotation (/Subtype /Movie, ISO 32000 §13.4) embeds video/animation content.",
28271
+ objectRef: refStr
28272
+ });
28273
+ else if (annotSubtype === "Sound") findings.push({
28274
+ category: "Sound",
28275
+ severity: "low",
28276
+ detail: "Sound annotation (/Subtype /Sound, ISO 32000 §13.3) embeds audio content.",
28277
+ objectRef: refStr
28278
+ });
28279
+ if (dict.has("/RichMedia") && annotSubtype !== "RichMedia") findings.push({
28280
+ category: "RichMedia",
28281
+ severity: "low",
28282
+ detail: "Object references rich-media content via a /RichMedia entry (ISO 32000-2 §13.6).",
28283
+ objectRef: refStr
28284
+ });
28285
+ if (dict.has("/Movie") && annotSubtype !== "Movie") findings.push({
28286
+ category: "Movie",
28287
+ severity: "low",
28288
+ detail: "Object references movie content via a /Movie entry (ISO 32000 §13.4).",
28289
+ objectRef: refStr
28290
+ });
28291
+ if (dict.has("/Sound") && annotSubtype !== "Sound" && subtype !== "Sound") findings.push({
28292
+ category: "Sound",
28293
+ severity: "low",
28294
+ detail: "Object references sound content via a /Sound entry (ISO 32000 §13.3).",
28295
+ objectRef: refStr
28296
+ });
28297
+ if (nameValue$1(dict.get("/Type")) === "Filespec" || dict.has("/EF")) {
28298
+ const fileName = stringValue(dict.get("/UF")) ?? stringValue(dict.get("/F"));
28299
+ if (fileName !== void 0) {
28300
+ const ext = extensionOf(fileName);
28301
+ if (ext !== "" && EXECUTABLE_EXTENSIONS.has(ext)) findings.push({
28302
+ category: "EmbeddedFile",
28303
+ severity: "high",
28304
+ detail: `Embedded file "${fileName}" has an executable/script extension ".${ext}" (ISO 32000 §7.11.3/§7.11.4); opening it can run code.`,
28305
+ objectRef: refStr
28306
+ });
28307
+ }
28308
+ }
28309
+ }
28310
+ /**
28311
+ * Flag a dangerous action `/S` subtype. Subtypes are ISO 32000 §12.6.4 /
28312
+ * §12.7.5 action types.
28313
+ */
28314
+ function inspectActionSubtype(subtype, dict, refStr, findings) {
28315
+ switch (subtype) {
28316
+ case "JavaScript":
28317
+ findings.push({
28318
+ category: "JavaScript",
28319
+ severity: "high",
28320
+ detail: "JavaScript action (/S /JavaScript, ISO 32000 §12.6.4.16) executes script in the viewer.",
28321
+ objectRef: refStr
28322
+ });
28323
+ break;
28324
+ case "Launch":
28325
+ findings.push({
28326
+ category: "Launch",
28327
+ severity: "high",
28328
+ detail: "Launch action (/S /Launch, ISO 32000 §12.6.4.5) can run an external application or open a file.",
28329
+ objectRef: refStr
28330
+ });
28331
+ break;
28332
+ case "URI":
28333
+ findings.push({
28334
+ category: "URI",
28335
+ severity: "medium",
28336
+ detail: `URI action (/S /URI, ISO 32000 §12.6.4.7) opens a remote URL ${describeUri(dict)}.`,
28337
+ objectRef: refStr
28338
+ });
28339
+ break;
28340
+ case "SubmitForm":
28341
+ findings.push({
28342
+ category: "SubmitForm",
28343
+ severity: "medium",
28344
+ detail: "SubmitForm action (/S /SubmitForm, ISO 32000 §12.7.5.2) sends form data to a URL (potential data exfiltration).",
28345
+ objectRef: refStr
28346
+ });
28347
+ break;
28348
+ case "ImportData":
28349
+ findings.push({
28350
+ category: "ImportData",
28351
+ severity: "low",
28352
+ detail: "ImportData action (/S /ImportData, ISO 32000 §12.7.5.4) imports external form data.",
28353
+ objectRef: refStr
28354
+ });
28355
+ break;
28356
+ case "GoToR":
28357
+ findings.push({
28358
+ category: "GoToR",
28359
+ severity: "low",
28360
+ detail: "Remote Go-To action (/S /GoToR, ISO 32000 §12.6.4.3) targets an external document.",
28361
+ objectRef: refStr
28362
+ });
28363
+ break;
28364
+ case "Movie":
28365
+ findings.push({
28366
+ category: "Movie",
28367
+ severity: "low",
28368
+ detail: "Movie action (/S /Movie, ISO 32000 §12.6.4.10) plays embedded video.",
28369
+ objectRef: refStr
28370
+ });
28371
+ break;
28372
+ case "Sound":
28373
+ findings.push({
28374
+ category: "Sound",
28375
+ severity: "low",
28376
+ detail: "Sound action (/S /Sound, ISO 32000 §12.6.4.8) plays embedded audio.",
28377
+ objectRef: refStr
28378
+ });
28379
+ break;
28380
+ default: break;
28381
+ }
28382
+ }
28383
+ /** Append the target URL of a /URI action to the detail string, if present. */
28384
+ function describeUri(dict) {
28385
+ const uri = stringValue(dict.get("/URI"));
28386
+ return uri !== void 0 ? `→ "${uri}"` : "";
28387
+ }
28388
+ /**
28389
+ * Best-effort raw-byte fallback used only when the PDF cannot be parsed.
28390
+ *
28391
+ * To stay precise we match constructs only in their *structural* dictionary
28392
+ * form — action subtypes as `/S /Type` (optionally without the inner space)
28393
+ * and `/OpenAction`/`/AA`/`/JavaScript` as dictionary keys (a `/` immediately
28394
+ * followed by the token and then a PDF delimiter). This avoids flagging the
28395
+ * same words when they appear as content-stream text or inside a literal
28396
+ * string. It is heuristic and clearly less reliable than the graph walk.
28397
+ */
28398
+ function scanRawBytesFallback(pdf, findings) {
28399
+ const text = new TextDecoder("latin1").decode(pdf);
28400
+ const keyForm = (key) => new RegExp(`/${key}(?=[\\s/(<\\[\\]>]|$)`);
28401
+ if (keyForm("OpenAction").test(text)) findings.push({
28402
+ category: "OpenAction",
28403
+ severity: "medium",
28404
+ detail: "Raw scan: /OpenAction key present (ISO 32000 §12.6.3)."
28405
+ });
28406
+ if (keyForm("AA").test(text)) findings.push({
28407
+ category: "AA",
28408
+ severity: "medium",
28409
+ detail: "Raw scan: /AA additional-actions key present (ISO 32000 §12.6.2)."
28410
+ });
28411
+ if (keyForm("JavaScript").test(text) || /\/S\s*\/JavaScript\b/.test(text)) findings.push({
28412
+ category: "JavaScript",
28413
+ severity: "high",
28414
+ detail: "Raw scan: JavaScript action/name tree present (ISO 32000 §12.6.4.16)."
28415
+ });
28416
+ if (/\/S\s*\/Launch\b/.test(text)) findings.push({
28417
+ category: "Launch",
28418
+ severity: "high",
28419
+ detail: "Raw scan: /S /Launch action present (ISO 32000 §12.6.4.5)."
28420
+ });
28421
+ if (/\/S\s*\/URI\b/.test(text)) findings.push({
28422
+ category: "URI",
28423
+ severity: "medium",
28424
+ detail: "Raw scan: /S /URI action present (ISO 32000 §12.6.4.7)."
28425
+ });
28426
+ if (/\/S\s*\/SubmitForm\b/.test(text)) findings.push({
28427
+ category: "SubmitForm",
28428
+ severity: "medium",
28429
+ detail: "Raw scan: /S /SubmitForm action present (ISO 32000 §12.7.5.2)."
28430
+ });
28431
+ if (/\/S\s*\/ImportData\b/.test(text)) findings.push({
28432
+ category: "ImportData",
28433
+ severity: "low",
28434
+ detail: "Raw scan: /S /ImportData action present (ISO 32000 §12.7.5.4)."
28435
+ });
28436
+ if (/\/S\s*\/GoToR\b/.test(text)) findings.push({
28437
+ category: "GoToR",
28438
+ severity: "low",
28439
+ detail: "Raw scan: /S /GoToR remote go-to present (ISO 32000 §12.6.4.3)."
28440
+ });
28441
+ if (/\/Subtype\s*\/RichMedia\b/.test(text) || keyForm("RichMedia").test(text)) findings.push({
28442
+ category: "RichMedia",
28443
+ severity: "low",
28444
+ detail: "Raw scan: RichMedia annotation present (ISO 32000-2 §13.6)."
28445
+ });
28446
+ if (/\/Subtype\s*\/Movie\b/.test(text) || /\/S\s*\/Movie\b/.test(text)) findings.push({
28447
+ category: "Movie",
28448
+ severity: "low",
28449
+ detail: "Raw scan: Movie content/action present (ISO 32000 §13.4)."
28450
+ });
28451
+ if (/\/Subtype\s*\/Sound\b/.test(text) || /\/S\s*\/Sound\b/.test(text)) findings.push({
28452
+ category: "Sound",
28453
+ severity: "low",
28454
+ detail: "Raw scan: Sound content/action present (ISO 32000 §13.3)."
28455
+ });
28456
+ if (keyForm("XFA").test(text)) findings.push({
28457
+ category: "XFA",
28458
+ severity: "low",
28459
+ detail: "Raw scan: /XFA form present (ISO 32000 §12.7.8)."
28460
+ });
28461
+ }
28462
+ /** Maximum severity across findings, or `'none'` when there are none. */
28463
+ function aggregateRisk(findings) {
28464
+ let maxRank = 0;
28465
+ for (const f of findings) {
28466
+ const rank = SEVERITY_RANK[f.severity];
28467
+ if (rank > maxRank) maxRank = rank;
28468
+ }
28469
+ if (maxRank === 0) return "none";
28470
+ return RANK_SEVERITY[maxRank - 1];
28471
+ }
28472
+ //#endregion
28473
+ //#region src/security/sanitize.ts
28474
+ /**
28475
+ * @module security/sanitize
28476
+ *
28477
+ * PDF sanitizer — produce a cleaned copy of a PDF with active / hidden
28478
+ * content neutralised.
28479
+ *
28480
+ * The sanitizer removes four classes of potentially dangerous or
28481
+ * privacy-leaking content from a document, each independently toggleable:
28482
+ *
28483
+ * - **javascript** — document-level JavaScript: the catalog's
28484
+ * `/Names → /JavaScript` name tree (ISO 32000-1 §7.7.4 / §12.6.4.16)
28485
+ * and the catalog's `/AA` (document additional-actions) dictionary
28486
+ * (§12.6.3) plus any page-level `/AA`.
28487
+ * - **openActions** — the catalog's auto-run `/OpenAction` (§12.3.4 / §12.6.4).
28488
+ * - **embeddedFiles** — embedded file attachments: the catalog's
28489
+ * `/Names → /EmbeddedFiles` name tree (§7.7.4 / §7.11.4) and the
28490
+ * PDF 2.0 catalog `/AF` (associated files) array (§7.11.4).
28491
+ * - **metadata** — the XMP `/Metadata` stream (§14.3.2) and the document
28492
+ * information `/Info` dictionary (§14.3.3).
28493
+ *
28494
+ * Implementation strategy (verified against this library's parser/writer):
28495
+ * the cleaned bytes are produced by mutating the *parsed object graph* in
28496
+ * place and re-serializing the registry directly through
28497
+ * {@link serializePdf}, **without** rebuilding the catalog. This is what
28498
+ * lets a disabled option genuinely preserve its content — the original
28499
+ * catalog (minus the removed references) is written verbatim.
28500
+ *
28501
+ * Removing a reference from the catalog is not sufficient on its own: the
28502
+ * underlying object (a JavaScript action dictionary, an `/EmbeddedFile`
28503
+ * stream, an XMP metadata stream, …) would otherwise remain physically
28504
+ * present in the output as an orphan. To guarantee the payload bytes are
28505
+ * actually gone, after deleting references this module runs the registry's
28506
+ * reachability filter from the catalog + info roots, dropping every object
28507
+ * no longer referenced.
28508
+ *
28509
+ * @packageDocumentation
28510
+ */
28511
+ /**
28512
+ * Resolve a {@link PdfObject} that may be an indirect reference to its
28513
+ * underlying value using the registry. Non-refs are returned as-is.
28514
+ * Returns `undefined` if a ref cannot be resolved.
28515
+ */
28516
+ function resolve$2(obj, registry) {
28517
+ if (obj === void 0) return void 0;
28518
+ if (obj instanceof PdfRef) return registry.resolve(obj);
28519
+ return obj;
28520
+ }
28521
+ /** Resolve `obj` and return it only if it is a {@link PdfDict}. */
28522
+ function asDict(obj, registry) {
28523
+ const resolved = resolve$2(obj, registry);
28524
+ return resolved instanceof PdfDict ? resolved : void 0;
28525
+ }
28526
+ /** Read a {@link PdfString} value, resolving an indirect reference if needed. */
28527
+ function asStringValue(obj, registry) {
28528
+ const resolved = resolve$2(obj, registry);
28529
+ return resolved instanceof PdfString ? resolved.value : void 0;
28530
+ }
28531
+ /**
28532
+ * Collect every distinct `/Type /Catalog` dictionary registered in the
28533
+ * document, paired with its reference. A well-formed PDF has exactly one,
28534
+ * but malformed or incrementally-updated files can register more than one;
28535
+ * sanitizing all of them is the conservative, correct choice. The first
28536
+ * entry is treated as the document root.
28537
+ */
28538
+ function findCatalogEntries(registry) {
28539
+ const byObjNum = /* @__PURE__ */ new Map();
28540
+ for (const { ref, object } of registry) if (object instanceof PdfDict) {
28541
+ const type = object.get("/Type");
28542
+ if (type instanceof PdfName && type.value === "/Catalog") {
28543
+ if (!byObjNum.has(ref.objectNumber)) byObjNum.set(ref.objectNumber, {
28544
+ ref,
28545
+ dict: object
28546
+ });
28547
+ }
28548
+ }
28549
+ return [...byObjNum.values()];
28550
+ }
28551
+ /** Collect every distinct `/Type /Page` dictionary in the registry. */
28552
+ function findPages(registry) {
28553
+ const pages = /* @__PURE__ */ new Set();
28554
+ for (const { object } of registry) if (object instanceof PdfDict) {
28555
+ const type = object.get("/Type");
28556
+ if (type instanceof PdfName && type.value === "/Page") pages.add(object);
28557
+ }
28558
+ return [...pages];
28559
+ }
28560
+ /**
28561
+ * Determine whether a PDF name tree (ISO 32000-1 §7.7.4) contains at least
28562
+ * one entry. A name-tree node holds either a `/Names` array of
28563
+ * `[key value key value …]` pairs (leaf) or a `/Kids` array of child node
28564
+ * references (intermediate). The tree is walked recursively with a visited
28565
+ * guard against cyclic references in malformed files.
28566
+ */
28567
+ function nameTreeHasEntries(node, registry, visited = /* @__PURE__ */ new Set()) {
28568
+ const dict = asDict(node, registry);
28569
+ if (dict === void 0 || visited.has(dict)) return false;
28570
+ visited.add(dict);
28571
+ const names = resolve$2(dict.get("/Names"), registry);
28572
+ if (names instanceof PdfArray && names.length >= 2) return true;
28573
+ const kids = resolve$2(dict.get("/Kids"), registry);
28574
+ if (kids instanceof PdfArray) {
28575
+ for (const kid of kids.items) if (nameTreeHasEntries(kid, registry, visited)) return true;
28576
+ }
28577
+ return false;
28578
+ }
28579
+ /** Return the catalog's resolved `/Names` sub-dictionary, if present. */
28580
+ function getNamesDict(catalog, registry) {
28581
+ return asDict(catalog.get("/Names"), registry);
28582
+ }
28583
+ /**
28584
+ * Determine whether an additional-actions (`/AA`) dictionary contains any
28585
+ * action whose `/S` (action type) is `/JavaScript`. Each value in an `/AA`
28586
+ * dictionary is itself an action dictionary (§12.6.3).
28587
+ */
28588
+ function aaHasJavaScript(aa, registry) {
28589
+ if (aa === void 0) return false;
28590
+ for (const [, value] of aa) {
28591
+ const action = asDict(value, registry);
28592
+ if (action === void 0) continue;
28593
+ const s = action.get("/S");
28594
+ if (s instanceof PdfName && s.value === "/JavaScript") return true;
28595
+ }
28596
+ return false;
28597
+ }
28598
+ /**
28599
+ * Descriptive `/Info` keys that constitute identifying metadata. The
28600
+ * auto-generated `/Producer`, `/CreationDate`, and `/ModDate` are NOT
28601
+ * treated as "present" for reporting purposes: a freshly created document
28602
+ * carries those by default and must still be considered clean. (When
28603
+ * metadata removal runs, the entire `/Info` dict is dropped regardless.)
28604
+ */
28605
+ const DESCRIPTIVE_INFO_KEYS = [
28606
+ "/Title",
28607
+ "/Author",
28608
+ "/Subject",
28609
+ "/Keywords",
28610
+ "/Creator"
28611
+ ];
28612
+ /**
28613
+ * Locate the trailer's `/Info` dictionary in the registry. The parser does
28614
+ * not expose the trailer publicly, so the Info dict is identified
28615
+ * structurally: it is a dictionary that is NOT a catalog/page/pages node
28616
+ * and carries at least one recognised document-information key.
28617
+ */
28618
+ function findInfoDict(registry, catalogs) {
28619
+ const catalogDicts = new Set(catalogs.map((c) => c.dict));
28620
+ const INFO_KEYS = [
28621
+ "/Title",
28622
+ "/Author",
28623
+ "/Subject",
28624
+ "/Keywords",
28625
+ "/Creator",
28626
+ "/Producer",
28627
+ "/CreationDate",
28628
+ "/ModDate",
28629
+ "/Trapped"
28630
+ ];
28631
+ for (const { object } of registry) {
28632
+ if (!(object instanceof PdfDict) || catalogDicts.has(object)) continue;
28633
+ const type = object.get("/Type");
28634
+ if (type instanceof PdfName) {
28635
+ const v = type.value;
28636
+ if (v === "/Catalog" || v === "/Pages" || v === "/Page" || v === "/Font") continue;
28637
+ }
28638
+ if (INFO_KEYS.some((k) => object.has(k))) return object;
28639
+ }
28640
+ }
28641
+ /** Read descriptive metadata from an `/Info` dict into a typed bag. */
28642
+ function readInfoMetadata(info, registry) {
28643
+ const meta = {};
28644
+ if (info === void 0) return meta;
28645
+ const title = asStringValue(info.get("/Title"), registry);
28646
+ if (title !== void 0) meta.title = title;
28647
+ const author = asStringValue(info.get("/Author"), registry);
28648
+ if (author !== void 0) meta.author = author;
28649
+ const subject = asStringValue(info.get("/Subject"), registry);
28650
+ if (subject !== void 0) meta.subject = subject;
28651
+ const keywords = asStringValue(info.get("/Keywords"), registry);
28652
+ if (keywords !== void 0) meta.keywords = keywords;
28653
+ const creator = asStringValue(info.get("/Creator"), registry);
28654
+ if (creator !== void 0) meta.creator = creator;
28655
+ const producer = asStringValue(info.get("/Producer"), registry);
28656
+ if (producer !== void 0) meta.producer = producer;
28657
+ return meta;
28658
+ }
28659
+ /**
28660
+ * Produce a cleaned copy of a PDF with active / hidden content neutralised.
28661
+ *
28662
+ * Loads the PDF, removes each enabled class of content from the parsed
28663
+ * object graph, prunes the orphaned objects, re-serializes the cleaned
28664
+ * document, and returns the new bytes alongside a report listing the
28665
+ * classes that were actually present and removed.
28666
+ *
28667
+ * @param pdf The source PDF bytes.
28668
+ * @param options Which classes to remove (each defaults to `true`).
28669
+ * @returns The cleaned PDF bytes and a {@link SanitizeReport}.
28670
+ *
28671
+ * @example
28672
+ * ```ts
28673
+ * const { pdf, report } = await sanitizePdf(bytes);
28674
+ * // report.removed === ['javascript', 'embeddedFiles', 'metadata']
28675
+ * ```
28676
+ */
28677
+ async function sanitizePdf(pdf, options) {
28678
+ const removeJavaScript = options?.javascript ?? true;
28679
+ const removeOpenActions = options?.openActions ?? true;
28680
+ const removeEmbeddedFiles = options?.embeddedFiles ?? true;
28681
+ const removeMetadata = options?.metadata ?? true;
28682
+ const registry = (await loadPdf(pdf)).getRegistry();
28683
+ const catalogs = findCatalogEntries(registry);
28684
+ if (catalogs.length === 0) return {
28685
+ pdf,
28686
+ report: { removed: [] }
28687
+ };
28688
+ const pages = findPages(registry);
28689
+ const infoDict = findInfoDict(registry, catalogs);
28690
+ const removed = /* @__PURE__ */ new Set();
28691
+ if (removeJavaScript) {
28692
+ for (const { dict: catalog } of catalogs) {
28693
+ const names = getNamesDict(catalog, registry);
28694
+ if (names !== void 0 && nameTreeHasEntries(names.get("/JavaScript"), registry)) removed.add("javascript");
28695
+ if (aaHasJavaScript(asDict(catalog.get("/AA"), registry), registry)) removed.add("javascript");
28696
+ }
28697
+ for (const page of pages) if (aaHasJavaScript(asDict(page.get("/AA"), registry), registry)) removed.add("javascript");
28698
+ for (const { dict: catalog } of catalogs) {
28699
+ const names = getNamesDict(catalog, registry);
28700
+ if (names !== void 0) {
28701
+ names.delete("/JavaScript");
28702
+ if (names.size === 0) catalog.delete("/Names");
28703
+ }
28704
+ catalog.delete("/AA");
28705
+ }
28706
+ for (const page of pages) page.delete("/AA");
28707
+ }
28708
+ if (removeOpenActions) {
28709
+ for (const { dict: catalog } of catalogs) if (catalog.has("/OpenAction")) {
28710
+ removed.add("openActions");
28711
+ catalog.delete("/OpenAction");
28712
+ }
28713
+ }
28714
+ if (removeEmbeddedFiles) {
28715
+ for (const { dict: catalog } of catalogs) {
28716
+ const names = getNamesDict(catalog, registry);
28717
+ if (names !== void 0 && nameTreeHasEntries(names.get("/EmbeddedFiles"), registry)) removed.add("embeddedFiles");
28718
+ const af = resolve$2(catalog.get("/AF"), registry);
28719
+ if (af instanceof PdfArray && af.length > 0) removed.add("embeddedFiles");
28720
+ }
28721
+ for (const { dict: catalog } of catalogs) {
28722
+ const names = getNamesDict(catalog, registry);
28723
+ if (names !== void 0) {
28724
+ names.delete("/EmbeddedFiles");
28725
+ if (names.size === 0) catalog.delete("/Names");
28726
+ }
28727
+ catalog.delete("/AF");
28728
+ }
28729
+ }
28730
+ const preservedMeta = readInfoMetadata(infoDict, registry);
28731
+ if (removeMetadata) {
28732
+ let metadataPresent = false;
28733
+ for (const { dict: catalog } of catalogs) if (resolve$2(catalog.get("/Metadata"), registry) instanceof PdfStream) metadataPresent = true;
28734
+ if (infoDict !== void 0 && DESCRIPTIVE_INFO_KEYS.some((k) => infoDict.has(k))) metadataPresent = true;
28735
+ if (metadataPresent) removed.add("metadata");
28736
+ for (const { dict: catalog } of catalogs) catalog.delete("/Metadata");
28737
+ if (infoDict !== void 0) for (const [key] of [...infoDict]) infoDict.delete(key);
28738
+ }
28739
+ const root = catalogs[0];
28740
+ const pagesRef = root.dict.get("/Pages");
28741
+ let infoRef;
28742
+ if (removeMetadata) infoRef = buildInfoDict({}, registry);
28743
+ else infoRef = buildInfoDict(preservedMeta, registry);
28744
+ const structure = {
28745
+ catalogRef: root.ref,
28746
+ infoRef,
28747
+ pagesRef: pagesRef instanceof PdfRef ? pagesRef : root.ref
28748
+ };
28749
+ registry.filterReachable([structure.catalogRef, structure.infoRef]);
28750
+ return {
28751
+ pdf: await serializePdf(registry, structure, { compress: true }),
28752
+ report: { removed: [...removed] }
28753
+ };
28754
+ }
28755
+ //#endregion
28756
+ //#region src/security/redactionVerifier.ts
28757
+ /**
28758
+ * @module security/redactionVerifier
28759
+ *
28760
+ * Detect FAILED / fake redactions — text that is still extractable underneath
28761
+ * a redaction region.
28762
+ *
28763
+ * A *secure* redaction physically removes the underlying text-showing
28764
+ * operators from the page content stream (see `redactRegions` in
28765
+ * `../render/redactContent.js`), so the redacted text cannot be recovered by
28766
+ * copy/paste, text extraction, or raw stream inspection. A *fake* redaction
28767
+ * merely paints an opaque black box on top of the page while the original text
28768
+ * remains in the byte stream — a genuine, well-documented security failure
28769
+ * (the "select-all-and-copy" leak). This verifier finds those leaks.
28770
+ *
28771
+ * ## How it works
28772
+ *
28773
+ * For each page named by a region:
28774
+ * 1. The page's content stream is decoded
28775
+ * (`PdfPage.getContentStream()`) and parsed (`parseContentStream`).
28776
+ * 2. `extractTextWithPositions` replays the text/graphics-state machine and
28777
+ * yields one positioned {@link import('../parser/textExtractor.js').TextItem}
28778
+ * per shown text run, with its page-space origin and size.
28779
+ * 3. Every text item whose bounding box intersects a region rectangle is
28780
+ * reported as a leak. `clean` is true iff there are no leaks.
28781
+ *
28782
+ * ## Coordinate / encoding conventions (confirmed, not assumed)
28783
+ *
28784
+ * - **Space:** PDF user space — the coordinate space produced by
28785
+ * `extractTextWithPositions`. Origin is **bottom-left**, the y-axis points
28786
+ * **up**, and units are **PDF points** (1/72 inch). This matches
28787
+ * `RedactRect` in `../render/redactContent.js` ("page space, PDF points,
28788
+ * y-up, lower-left origin"), so a {@link RedactionRegion} uses exactly the
28789
+ * same convention: `(x, y)` is the lower-left corner and `width` / `height`
28790
+ * extend in the +x / +y directions.
28791
+ * - **Glyph box:** a `TextItem` reports `(x, y)` = the text origin
28792
+ * (baseline-left), `width` extending +x, and `height` (equal to the font
28793
+ * size) extending +y. The run's axis-aligned box is therefore
28794
+ * `[x, y, x + width, y + height]`. Note `width`/`height` are heuristic
28795
+ * estimates from `extractTextWithPositions` (0.5·fontSize per character;
28796
+ * height = fontSize) because per-glyph font metrics are not available there;
28797
+ * intersection testing tolerates this by treating any overlap as a leak.
28798
+ * - **Text decoding:** strings are decoded by `extractTextWithPositions` using
28799
+ * the font's `/ToUnicode` CMap when present, else WinAnsiEncoding (1-byte) or
28800
+ * 2-byte Identity-H for CID fonts — see `../parser/textExtractor.js`.
28801
+ *
28802
+ * ## Region auto-detection is intentionally NOT performed
28803
+ *
28804
+ * The `regions` argument is **required**. Deriving candidate regions from the
28805
+ * PDF itself is not reliable through the public API and is not fabricated here:
28806
+ * - Filled black rectangles in the content stream are indistinguishable from
28807
+ * legitimate black-filled graphics (chart bars, rules, design elements), so
28808
+ * a heuristic would produce false positives/negatives.
28809
+ * - `/Redact` annotations (ISO 32000-2 §12.5.6.23) *do* carry explicit
28810
+ * `/Rect` / `/QuadPoints` regions, but a loaded page's original annotation
28811
+ * dictionaries are not exposed through a stable public `PdfPage` accessor,
28812
+ * so reading them here is not possible without reaching into private state.
28813
+ * Callers must therefore pass the regions they redacted (or believe were
28814
+ * redacted). When `regions` is omitted or empty, {@link verifyRedactions}
28815
+ * throws.
28816
+ *
28817
+ * @packageDocumentation
28818
+ */
28819
+ /**
28820
+ * Axis-aligned bounding box of a text run in page space (bottom-left origin).
28821
+ * `width`/`height` may be zero (empty text); such runs never intersect.
28822
+ */
28823
+ function itemBox(item) {
28824
+ const x0 = item.x;
28825
+ const y0 = item.y;
28826
+ const x1 = item.x + item.width;
28827
+ const y1 = item.y + item.height;
28828
+ return {
28829
+ minX: Math.min(x0, x1),
28830
+ minY: Math.min(y0, y1),
28831
+ maxX: Math.max(x0, x1),
28832
+ maxY: Math.max(y0, y1)
28833
+ };
28834
+ }
28835
+ /**
28836
+ * Whether a text run's box overlaps a region rectangle.
28837
+ *
28838
+ * Uses the standard separating-axis test for axis-aligned rectangles: they
28839
+ * overlap unless one is entirely to the left/right/above/below the other.
28840
+ * Touching edges count as overlap (inclusive bounds), matching the intersection
28841
+ * test in `../render/redactContent.js`.
28842
+ */
28843
+ function intersects$1(box, region) {
28844
+ const rMinX = region.x;
28845
+ const rMinY = region.y;
28846
+ const rMaxX = region.x + region.width;
28847
+ const rMaxY = region.y + region.height;
28848
+ return box.minX <= rMaxX && box.maxX >= rMinX && box.minY <= rMaxY && box.maxY >= rMinY;
28849
+ }
28850
+ /**
28851
+ * Verify that the given regions of a PDF contain no still-extractable text,
28852
+ * detecting fake / failed redactions.
28853
+ *
28854
+ * For each region, the corresponding page's text is extracted with positions
28855
+ * and any text run whose bounding box intersects the region is reported as a
28856
+ * {@link RedactionLeak}. A clean result means no text was found under any
28857
+ * region (the redactions truly removed the content, or there was none to begin
28858
+ * with).
28859
+ *
28860
+ * @param pdf The PDF file bytes to inspect.
28861
+ * @param regions The regions to check (REQUIRED — see the module docs for why
28862
+ * automatic region detection is not performed). Coordinates are
28863
+ * in PDF user space: origin bottom-left, y-up, units in points;
28864
+ * `(x, y)` is the lower-left corner.
28865
+ * @returns A report listing every leak; `clean` is true iff there are
28866
+ * none.
28867
+ * @throws `TypeError` if `regions` is omitted or empty.
28868
+ *
28869
+ * @example
28870
+ * ```ts
28871
+ * const report = await verifyRedactions(pdfBytes, [
28872
+ * { page: 0, x: 45, y: 545, width: 120, height: 25 },
28873
+ * ]);
28874
+ * if (!report.clean) {
28875
+ * for (const leak of report.leaks) {
28876
+ * console.warn(`Leak on page ${leak.page}: "${leak.text}"`);
28877
+ * }
28878
+ * }
28879
+ * ```
28880
+ */
28881
+ async function verifyRedactions(pdf, regions) {
28882
+ if (regions === void 0 || regions.length === 0) throw new TypeError("verifyRedactions requires an explicit, non-empty `regions` array. Automatic redaction-region detection is not performed: black-filled rectangles are indistinguishable from legitimate graphics, and a loaded page's original /Redact annotations are not exposed through a stable public API. Pass the regions you redacted (PDF points, bottom-left origin, y-up).");
28883
+ const doc = await loadPdf(pdf);
28884
+ const pageCount = doc.getPageCount();
28885
+ const itemsByPage = /* @__PURE__ */ new Map();
28886
+ const getItems = (pageIndex) => {
28887
+ const cached = itemsByPage.get(pageIndex);
28888
+ if (cached !== void 0) return cached;
28889
+ let items = [];
28890
+ if (pageIndex >= 0 && pageIndex < pageCount) {
28891
+ const page = doc.getPage(pageIndex);
28892
+ items = extractTextWithPositions(parseContentStream(page.getContentStream()), page.getOriginalResources());
28893
+ }
28894
+ itemsByPage.set(pageIndex, items);
28895
+ return items;
28896
+ };
28897
+ const leaks = [];
28898
+ for (const region of regions) {
28899
+ if (region.width <= 0 || region.height <= 0) continue;
28900
+ const items = getItems(region.page);
28901
+ for (const item of items) {
28902
+ if (item.text.length === 0) continue;
28903
+ const box = itemBox(item);
28904
+ if (box.maxX === box.minX && box.maxY === box.minY) continue;
28905
+ if (intersects$1(box, region)) leaks.push({
28906
+ page: region.page,
28907
+ text: item.text,
28908
+ x: item.x,
28909
+ y: item.y
28910
+ });
28911
+ }
28912
+ }
28913
+ return {
28914
+ leaks,
28915
+ clean: leaks.length === 0,
28916
+ regionsChecked: regions.length
28917
+ };
28918
+ }
28919
+ //#endregion
28920
+ //#region src/security/encryptionInspector.ts
28921
+ const BIT_PRINT = 4;
28922
+ const BIT_MODIFY = 8;
28923
+ const BIT_COPY = 16;
28924
+ const BIT_ANNOTATE = 32;
28925
+ const BIT_FILL_FORMS = 256;
28926
+ const BIT_ASSEMBLE = 1024;
28927
+ const BIT_PRINT_HIGH_RES = 2048;
28928
+ /**
28929
+ * Inspect a PDF's encryption + permission posture.
28930
+ *
28931
+ * @param pdf The raw PDF file bytes.
28932
+ * @returns A {@link EncryptionReport}. If the trailer has no
28933
+ * `/Encrypt` entry (or the file is unparseable) the report is
28934
+ * `{ encrypted: false }`.
28935
+ */
28936
+ async function inspectEncryption(pdf) {
28937
+ const located = await locateEncryptDict(pdf);
28938
+ if (located === void 0) return { encrypted: false };
28939
+ const { encryptDict, fileId, encryptRef } = located;
28940
+ const filterName = getName(encryptDict, "/Filter");
28941
+ let handler;
28942
+ if (filterName === "/Standard") handler = "password";
28943
+ else if (filterName === "/Adobe.PubSec") handler = "publicKey";
28944
+ const version = getNumber(encryptDict, "/V");
28945
+ const revision = getNumber(encryptDict, "/R");
28946
+ const { method, keyBits } = decodeAlgorithm(encryptDict, version);
28947
+ let permissions;
28948
+ const pValue = getNumber(encryptDict, "/P");
28949
+ if (handler === "password" && pValue !== void 0) permissions = decodePermissionBits(pValue);
28950
+ let emptyUserPassword;
28951
+ if (handler === "password") emptyUserPassword = await testEmptyUserPassword(encryptDict, fileId);
28952
+ const report = { encrypted: true };
28953
+ if (method !== void 0) report.method = method;
28954
+ if (keyBits !== void 0) report.keyBits = keyBits;
28955
+ if (version !== void 0) report.version = version;
28956
+ if (revision !== void 0) report.revision = revision;
28957
+ if (handler !== void 0) report.handler = handler;
28958
+ if (emptyUserPassword !== void 0) report.emptyUserPassword = emptyUserPassword;
28959
+ if (permissions !== void 0) report.permissions = permissions;
28960
+ return report;
28961
+ }
28962
+ /**
28963
+ * Parse just enough of the PDF (header + xref + trailer) to resolve the
28964
+ * `/Encrypt` dictionary and the first element of the `/ID` array.
28965
+ *
28966
+ * Returns `undefined` when the file has no `/Encrypt` entry or when it
28967
+ * cannot be parsed far enough to find one.
28968
+ */
28969
+ async function locateEncryptDict(pdf) {
28970
+ if (pdf.length < 8) return void 0;
28971
+ let encryptRef;
28972
+ let fileIdFirst;
28973
+ let entry;
28974
+ let objectParser;
28975
+ try {
28976
+ objectParser = new PdfObjectParser(new PdfLexer(pdf), new PdfObjectRegistry());
28977
+ const { entries, trailer } = await new XrefParser(pdf, objectParser).parseXref();
28978
+ encryptRef = trailer.encryptRef;
28979
+ if (encryptRef === void 0) return void 0;
28980
+ fileIdFirst = trailer.id?.[0] ?? /* @__PURE__ */ new Uint8Array(0);
28981
+ entry = entries.get(encryptRef.objectNumber);
28982
+ } catch {
28983
+ return;
28984
+ }
28985
+ if (entry === void 0 || entry.type !== "in-use") return void 0;
28986
+ let encryptObj;
28987
+ try {
28988
+ const { object } = objectParser.parseIndirectObjectAt(entry.offset);
28989
+ encryptObj = object;
28990
+ } catch {
28991
+ return;
28992
+ }
28993
+ if (encryptObj.kind !== "dict") return void 0;
28994
+ return {
28995
+ encryptDict: encryptObj,
28996
+ encryptRef,
28997
+ fileId: fileIdFirst
28998
+ };
28999
+ }
29000
+ /**
29001
+ * Decode the bulk cipher and key length from an encryption dictionary.
29002
+ *
29003
+ * - V=1: 40-bit RC4 (Table 20/21).
29004
+ * - V=2: RC4 with `/Length` bits.
29005
+ * - V=4: inspect the crypt filter `/CFM` of the filter named by `/StmF`
29006
+ * (falling back to `/StdCF`): `/V2` → RC4, `/AESV2` → 128-bit AES,
29007
+ * `/AESV3` → 256-bit AES, `/Identity`/`/None` → no encryption.
29008
+ * - V=5: 256-bit AES (`/AESV3`).
29009
+ */
29010
+ function decodeAlgorithm(dict, version) {
29011
+ const lengthBits = getNumber(dict, "/Length");
29012
+ if (version === 1) return {
29013
+ method: "rc4",
29014
+ keyBits: 40
29015
+ };
29016
+ if (version === 2) return {
29017
+ method: "rc4",
29018
+ keyBits: lengthBits ?? 40
29019
+ };
29020
+ if (version === 5) return {
29021
+ method: "aes",
29022
+ keyBits: 256
29023
+ };
29024
+ if (version === 4) {
29025
+ const cfm = resolveCryptFilterMethod(dict);
29026
+ if (cfm === "/AESV3") return {
29027
+ method: "aes",
29028
+ keyBits: 256
29029
+ };
29030
+ if (cfm === "/AESV2") return {
29031
+ method: "aes",
29032
+ keyBits: lengthBits ?? 128
29033
+ };
29034
+ if (cfm === "/V2") return {
29035
+ method: "rc4",
29036
+ keyBits: lengthBits ?? 128
29037
+ };
29038
+ return {
29039
+ method: void 0,
29040
+ keyBits: lengthBits ?? void 0
29041
+ };
29042
+ }
29043
+ return {
29044
+ method: void 0,
29045
+ keyBits: lengthBits ?? void 0
29046
+ };
29047
+ }
29048
+ /**
29049
+ * For V=4 documents, resolve the `/CFM` (crypt filter method) name of the
29050
+ * stream crypt filter. Looks up `/StmF` in `/CF`, then falls back to the
29051
+ * conventional `/StdCF` entry.
29052
+ */
29053
+ function resolveCryptFilterMethod(dict) {
29054
+ const cf = dict.get("/CF");
29055
+ if (cf === void 0 || cf.kind !== "dict") return void 0;
29056
+ const cfDict = cf;
29057
+ let filterName = getName(dict, "/StmF");
29058
+ if (filterName === "/Identity") return "/Identity";
29059
+ let stdCf = filterName !== void 0 ? cfDict.get(filterName) : void 0;
29060
+ if (stdCf === void 0 || stdCf.kind !== "dict") {
29061
+ stdCf = cfDict.get("/StdCF");
29062
+ filterName = "/StdCF";
29063
+ }
29064
+ if (stdCf === void 0 || stdCf.kind !== "dict") return void 0;
29065
+ return getName(stdCf, "/CFM");
29066
+ }
29067
+ /**
29068
+ * Decode the 32-bit `/P` integer into individual permission flags.
29069
+ *
29070
+ * The `/P` value is a *signed* 32-bit integer; bitwise AND in JavaScript
29071
+ * operates on the 32-bit two's-complement representation, so masks apply
29072
+ * correctly even when `/P` is negative (the usual case, since reserved
29073
+ * high bits are set to 1).
29074
+ */
29075
+ function decodePermissionBits(p) {
29076
+ const has = (mask) => (p & mask) !== 0;
29077
+ const copy = has(BIT_COPY);
29078
+ return {
29079
+ print: has(BIT_PRINT),
29080
+ modify: has(BIT_MODIFY),
29081
+ copy,
29082
+ annotate: has(BIT_ANNOTATE),
29083
+ fillForms: has(BIT_FILL_FORMS),
29084
+ extract: copy,
29085
+ assemble: has(BIT_ASSEMBLE),
29086
+ printHighRes: has(BIT_PRINT_HIGH_RES)
29087
+ };
29088
+ }
29089
+ /**
29090
+ * Test whether the empty user password (`""`) authenticates against the
29091
+ * standard security handler. Reuses {@link PdfEncryptionHandler.fromEncryptDict},
29092
+ * which throws when the password is incorrect; a successful return means
29093
+ * the empty password derived a valid file key.
29094
+ *
29095
+ * Returns `undefined` when the test cannot be performed (e.g. the handler
29096
+ * implementation does not support the document's /V/R).
29097
+ */
29098
+ async function testEmptyUserPassword(dict, fileId) {
29099
+ try {
29100
+ await PdfEncryptionHandler.fromEncryptDict(dict, fileId, "");
29101
+ return true;
29102
+ } catch (err) {
29103
+ const message = err instanceof Error ? err.message : String(err);
29104
+ if (/password/i.test(message)) return false;
29105
+ return;
29106
+ }
29107
+ }
29108
+ /** Read a `/Name` value (including the leading `/`) from a dict. */
29109
+ function getName(dict, key) {
29110
+ const obj = dict.get(key);
29111
+ if (obj !== void 0 && obj.kind === "name") return obj.value;
29112
+ }
29113
+ /** Read a numeric value from a dict. */
29114
+ function getNumber(dict, key) {
29115
+ const obj = dict.get(key);
29116
+ if (obj !== void 0 && obj.kind === "number") return obj.value;
29117
+ }
29118
+ //#endregion
27844
29119
  //#region src/render/matrix.ts
27845
29120
  /** The identity transform. */
27846
29121
  function identity() {
@@ -31649,15 +32924,15 @@ async function initWasm(options) {
31649
32924
  if (wasmInitialized) return;
31650
32925
  const inits = [];
31651
32926
  if (options.deflate || options.deflateWasm) inits.push((async () => {
31652
- const { initDeflateWasm } = await import("./pdfDocument-Cgkkk8F8.mjs").then((n) => n.zt);
32927
+ const { initDeflateWasm } = await import("./pdfDocument-Q0wrwKEZ.mjs").then((n) => n.Wt);
31653
32928
  await initDeflateWasm(options.deflateWasm);
31654
32929
  })());
31655
32930
  if (options.png || options.pngWasm) inits.push((async () => {
31656
- const { initPngWasm } = await import("./pdfDocument-Cgkkk8F8.mjs").then((n) => n.At);
32931
+ const { initPngWasm } = await import("./pdfDocument-Q0wrwKEZ.mjs").then((n) => n.Ft);
31657
32932
  await initPngWasm(options.pngWasm);
31658
32933
  })());
31659
32934
  if (options.fonts || options.fontWasm) inits.push((async () => {
31660
- const { initSubsetWasm } = await import("./pdfDocument-Cgkkk8F8.mjs").then((n) => n.Pt);
32935
+ const { initSubsetWasm } = await import("./pdfDocument-Q0wrwKEZ.mjs").then((n) => n.zt);
31661
32936
  await initSubsetWasm(options.fontWasm);
31662
32937
  })());
31663
32938
  if (options.jpeg || options.jpegWasm) inits.push((async () => {
@@ -31668,6 +32943,6 @@ async function initWasm(options) {
31668
32943
  wasmInitialized = true;
31669
32944
  }
31670
32945
  //#endregion
31671
- export { extractEmbeddedRevocationData as $, PdfSquareAnnotation as $a, getSupportedLevels as $i, timestampPlugin as $n, readEan13 as $r, h as $t, buildSoftMaskNone as A, buildDocMdpReference as Aa, webpToPng as Ai, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as An, StreamingParseError as Ar, extractOcspUrl as At, redactRegions as B, parseTimestampResponse as Ba, recompressImage as Bi, MATHML_NAMESPACE as Bn, estimateTextWidth as Br, formatDate as Bt, tagTableHeaderCell as C, getCounterSignatures as Ca, valuesToModules as Ci, identityTransferFunction as Cn, saveDocumentIncremental as Co, InvalidFieldNamePartError as Cr, parseTileInfo as Ct, buildImageSoftMask as D, getFieldLocks as Da, encodePngFromPixels as Di, buildCollection as Dn, PluginError as Dr, extractCrlUrls as Dt, buildColorKeyMask as E, buildFieldLockDict as Ea, embedTiffDirect as Ei, markdownToPdf as En, NoSuchFieldError as Er, downloadCrl as Et, attachAssociatedFiles as F, findExistingSignatures as Fa, injectJpegMetadata as Fi, labToRgb as Fn, replaceTemplateVariables as Fr, addVisibilityAction as Ft, extractImages as G, PdfPopupAnnotation as Ga, countOccurrences as Gi, buildRequirement as Gn, applyTablePreset as Gr, isWoff as Gt, compareImages as H, searchTextItems as Ha, enforcePdfAFull as Hi, buildNamespace as Hn, truncateText as Hr, AFNumber_Format as Ht, registerEmbeddedFile as I, parseExistingTrailer as Ia, analyzeJpegMarkers as Ii, DEFAULT_SARIF_TOOL_NAME as In, toAlpha as Ir, setFieldVisibility as It, renderPageToCanvas as J, PdfStampAnnotation as Ja, createAssociatedFile as Ji, extractTables as Jn, professionalPreset as Jr, signDeferred as Jt, generateThumbnail as K, PdfRedactAnnotation as Ka, stripProhibitedFeatures as Ki, buildRequirements as Kn, borderedPreset as Kr, isWoff2 as Kt, RenderCache as L, saveIncrementalWithSignaturePreservation as La, downscaleImage as Li, SARIF_SCHEMA_URI as Ln, toRoman as Lr, validateFieldValue as Lt, buildUnencryptedWrapper as M, setCertificationLevel as Ma, embedTiffCmyk as Mi, buildCalGray as Mn, applyHeaderFooter as Mr, getFieldValue as Mt, attachOutputIntents as N, validateSignatureChain as Na, isCmykTiff as Ni, buildCalRGB as Nn, applyHeaderFooterToPage as Nr, resolveFieldReference as Nt, buildStencilMask as O, detectModifications as Oa, recompressWebP as Oi, reconstructLines as On, RemovePageFromEmptyDocumentError as Or, isCertificateRevoked as Ot, buildPageOutputIntent as P, appendIncrementalUpdate as Pa, extractJpegMetadata as Pi, buildLab as Pn, formatDate$1 as Pr, setFieldValue as Pt, interpretPage as Q, PdfPolygonAnnotation as Qa, getProfile as Qi, metadataPlugin as Qn, readCode39 as Qr, gtsPdfVtVersion as Qt, computeTileGrid as R, validateByteRangeIntegrity as Ra, estimateJpegQuality as Ri, toJsonReport as Rn, applyOverflow as Rr, AFSpecial_Format as Rt, tagTableDataCell as S, addCounterSignature as Sa, encodeCode128Values as Si, buildType5Halftone as Sn, ChangeTracker as So, InvalidColorError as Sr, decodeTileRegion as St, buildBlackPointCompensationExtGState as T, addFieldLock as Ta, canDirectEmbed as Ti, evaluateFunction as Tn, MissingOnValueCheckError as Tr, TrustStore as Tt, comparePages as U, PdfFileAttachmentAnnotation as Ua, generatePdfAXmp as Ui, buildNamespacesArray as Un, wrapText$2 as Ur, formatNumber$1 as Ut, applyOcr as V, requestTimestamp as Va, applyRedaction as Vi, PDF2_NAMESPACE as Vn, shrinkFontSize as Vr, parseAcrobatDate as Vt, extractFonts as W, PdfCaretAnnotation as Wa, generatePdfAXmpBytes as Wi, buildPieceInfo as Wn, applyPreset as Wr, decodeWoff as Wt, renderPageToImage as X, PdfLineAnnotation as Xa, parseXmpMetadata as Xi, tableToJson as Xn, readBarcode as Xr, buildPdfVtDParts as Xt, rasterize as Y, PdfCircleAnnotation as Ya, extractXmpMetadata as Yi, tableToCsv as Yn, stripedPreset as Yr, createWorkerPool as Yt, interpretContentStream as Z, PdfPolyLineAnnotation as Za, validateXmpMetadata as Zi, accessibilityPlugin as Zn, readCode128 as Zr, buildVtDpm as Zt, tagLink as _, findChangedObjects as _a, code39ToOperators as _i, validateBoxGeometry as _n, createXmpStream as _o, ExceededMaxLengthError as _r, offsetSignedToUnsigned as _t, assembleFacturX as a, buildOutputIntent as aa, dataMatrixToOperators as ai, generateXRechnungCii as an, generateCircleAppearance as ao, batchMerge as ar, buildCertificateChain as at, tagParagraph as b, embedLtvData as ba, code128ToOperators as bi, buildThresholdHalftone as bn, buildDeviceNColorSpace as bo, FontNotEmbeddedError as br, assembleTiles as bt, buildWtpdfIdentificationXmp as c, detectTransparency as ca, encodeUpcA as ci, buildFunctionShading as cn, generateInkAppearance as co, getBookmarks as cr, layoutColumns as ct, autoTagPage as d, validatePdfA as da, ean13ToOperators as di, levenshtein as dn, generateSquigglyAppearance as do, flattenField as dr, buildPdfXOutputIntent as dt, isValidLevel as ea, readEan8 as ei, renderToPdf as en, PdfHighlightAnnotation as eo, StreamingPdfParser as er, verifyOfflineRevocation as et, buildPdfUa2Xmp as f, delinearizePdf as fa, ean8ToOperators as fi, renderCodeFrame as fn, generateStrikeOutAppearance as fo, flattenFields as fr, enforcePdfX as ft, tagHeading as g, computeObjectHash as ga, itfToOperators as gi, buildPdfX6OutputIntent as gn, buildXmpMetadata as go, EncryptedPdfError as gr, normalizeComponentDepth as gt, tagFigure as h, linearizePdf as ha, encodeItf as hi, buildGtsPdfxVersion as hn, PdfTextAnnotation as ho, CombedTextLayoutError as hr, getComponentDepths as ht, validateEn16931 as i, getToUnicodeCmap as ia, pdf417ToOperators as ii, generateOrderX as in, PdfFreeTextAnnotation as io, batchFlatten as ir, validateKeyUsage as it, buildEncryptedPayload as j, getCertificationLevel as ja, convertTiffCmykToRgb as ji, buildDocTimeStampDict as jn, UnexpectedFieldTypeError as jr, createSandbox as jt, buildSoftMaskGroupExtGState as k, MdpPermission as ka, webpToJpeg as ki, reconstructParagraphs as kn, RichTextFieldReadError as kr, checkCertificateStatus as kt, convertPdfAConformanceXmp as l, flattenTransparency as la, upcAToOperators as li, sampleShadingColor as ln, generateLineAppearance as lo, removeAllBookmarks as lr, layoutParagraph as lt, LIST_NUMBERING_KEY as m, isLinearized as ma, encodeEan8 as mi, buildBoxDict as mn, PdfLinkAnnotation as mo, BatchProcessingError as mr, downscale16To8 as mt, detectFacturXProfile as n, generateWinAnsiToUnicodeCmap as na, renderStyledBarcode as ni, resolveFallback as nn, PdfStrikeOutAnnotation as no, enforcePdfUa as nr, validateCertificatePolicy as nt, buildFacturXXmp as o, SRGB_ICC_PROFILE as oa, encodeDataMatrix as oi, buildPdfA4Xmp as on, generateFreeTextAppearance as oo, processBatch as or, validateCertificateChain as ot, validatePdfUa2 as p, getLinearizationInfo as pa, encodeEan13 as pi, generateCiiXml as pn, generateUnderlineAppearance as po, flattenForm as pr, validatePdfX as pt, renderDisplayListToCanvas as q, PdfInkAnnotation as qa, buildAfArray as qi, buildDPartRoot as qn, minimalPreset as qr, readWoffHeader as qt, parseCiiXml as r, generateZapfDingbatsToUnicodeCmap as ra, encodePdf417 as ri, splitByScript as rn, PdfUnderlineAnnotation as ro, validatePdfUa as rr, validateExtendedKeyUsage as rt, buildPdfRIdentificationXmp as s, generateSrgbIccProfile as sa, calculateUpcCheckDigit as si, pdfA4Rules as sn, generateHighlightAppearance as so, addBookmark as sr, findHyphenationPoints as st, initWasm as t, generateSymbolToUnicodeCmap as ta, calculateBarcodeDimensions as ti, createRangeFetcher as tn, PdfSquigglyAnnotation as to, PdfDocumentBuilder as tr, EKU_OIDS as tt, preflightPdfA as u, enforcePdfA as ua, calculateEanCheckDigit as ui, didYouMean as un, generateSquareAppearance as uo, removeBookmark as ur, layoutTextFlow as ut, tagList as v, optimizeIncrementalSave as va, computeCode39CheckDigit as vi, STANDARD_SPOT_FUNCTIONS as vn, parseXmpMetadata$1 as vo, FieldAlreadyExistsError as vr, summarizeBitDepth as vt, tagTableRow as w, diffSignedContent as wa, PdfWorker as wi, nameHalftone as wn, saveIncremental as wo, InvalidPageSizeError as wr, verifySignatureDetailed as wt, tagTable as x, hasLtvData as xa, encodeCode128 as xi, buildType1Halftone as xn, buildSeparationColorSpace as xo, ForeignPageError as xr, decodeTile as xt, tagListItem as y, buildDssDictionary as ya, encodeCode39 as yi, buildSampledTransferFunction as yn, PDFOperator as yo, FieldExistsAsNonTerminalError as yr, upscale8To16 as yt, renderPageTile as z, buildTimestampRequest as za, optimizeImage as zi, toSarif as zn, ellipsisText as zr, AFDate_FormatEx as zt };
32946
+ export { inspectEncryption as $, PdfStampAnnotation as $a, createAssociatedFile as $i, extractTables as $n, professionalPreset as $r, signDeferred as $t, buildSoftMaskNone as A, addFieldLock as Aa, canDirectEmbed as Ai, evaluateFunction as An, MissingOnValueCheckError as Ar, TrustStore as At, redactRegions as B, findExistingSignatures as Ba, injectJpegMetadata as Bi, labToRgb as Bn, replaceTemplateVariables as Br, addVisibilityAction as Bt, tagTableHeaderCell as C, optimizeIncrementalSave as Ca, computeCode39CheckDigit as Ci, STANDARD_SPOT_FUNCTIONS as Cn, parseXmpMetadata$1 as Co, FieldAlreadyExistsError as Cr, summarizeBitDepth as Ct, buildImageSoftMask as D, addCounterSignature as Da, encodeCode128Values as Di, buildType5Halftone as Dn, ChangeTracker as Do, InvalidColorError as Dr, decodeTileRegion as Dt, buildColorKeyMask as E, hasLtvData as Ea, encodeCode128 as Ei, buildType1Halftone as En, buildSeparationColorSpace as Eo, ForeignPageError as Er, decodeTile as Et, attachAssociatedFiles as F, buildDocMdpReference as Fa, webpToPng as Fi, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as Fn, StreamingParseError as Fr, extractOcspUrl as Ft, extractImages as G, parseTimestampResponse as Ga, recompressImage as Gi, MATHML_NAMESPACE as Gn, estimateTextWidth as Gr, formatDate as Gt, compareImages as H, saveIncrementalWithSignaturePreservation as Ha, downscaleImage as Hi, SARIF_SCHEMA_URI as Hn, toRoman as Hr, validateFieldValue as Ht, registerEmbeddedFile as I, getCertificationLevel as Ia, convertTiffCmykToRgb as Ii, buildDocTimeStampDict as In, UnexpectedFieldTypeError as Ir, createSandbox as It, renderPageToCanvas as J, PdfFileAttachmentAnnotation as Ja, generatePdfAXmp as Ji, buildNamespacesArray as Jn, wrapText$2 as Jr, formatNumber$1 as Jt, generateThumbnail as K, requestTimestamp as Ka, applyRedaction as Ki, PDF2_NAMESPACE as Kn, shrinkFontSize as Kr, parseAcrobatDate as Kt, RenderCache as L, setCertificationLevel as La, embedTiffCmyk as Li, buildCalGray as Ln, applyHeaderFooter as Lr, getFieldValue as Lt, buildUnencryptedWrapper as M, getFieldLocks as Ma, encodePngFromPixels as Mi, buildCollection as Mn, PluginError as Mr, extractCrlUrls as Mt, attachOutputIntents as N, detectModifications as Na, recompressWebP as Ni, reconstructLines as Nn, RemovePageFromEmptyDocumentError as Nr, isCertificateRevoked as Nt, buildStencilMask as O, getCounterSignatures as Oa, valuesToModules as Oi, identityTransferFunction as On, saveDocumentIncremental as Oo, InvalidFieldNamePartError as Or, parseTileInfo as Ot, buildPageOutputIntent as P, MdpPermission as Pa, webpToJpeg as Pi, reconstructParagraphs as Pn, RichTextFieldReadError as Pr, checkCertificateStatus as Pt, interpretPage as Q, PdfInkAnnotation as Qa, buildAfArray as Qi, buildDPartRoot as Qn, minimalPreset as Qr, readWoffHeader as Qt, computeTileGrid as R, validateSignatureChain as Ra, isCmykTiff as Ri, buildCalRGB as Rn, applyHeaderFooterToPage as Rr, resolveFieldReference as Rt, tagTableDataCell as S, findChangedObjects as Sa, code39ToOperators as Si, validateBoxGeometry as Sn, createXmpStream as So, ExceededMaxLengthError as Sr, offsetSignedToUnsigned as St, buildBlackPointCompensationExtGState as T, embedLtvData as Ta, code128ToOperators as Ti, buildThresholdHalftone as Tn, buildDeviceNColorSpace as To, FontNotEmbeddedError as Tr, assembleTiles as Tt, comparePages as U, validateByteRangeIntegrity as Ua, estimateJpegQuality as Ui, toJsonReport as Un, applyOverflow as Ur, AFSpecial_Format as Ut, applyOcr as V, parseExistingTrailer as Va, analyzeJpegMarkers as Vi, DEFAULT_SARIF_TOOL_NAME as Vn, toAlpha as Vr, setFieldVisibility as Vt, extractFonts as W, buildTimestampRequest as Wa, optimizeImage as Wi, toSarif as Wn, ellipsisText as Wr, AFDate_FormatEx as Wt, renderPageToImage as X, PdfPopupAnnotation as Xa, countOccurrences as Xi, buildRequirement as Xn, applyTablePreset as Xr, isWoff as Xt, rasterize as Y, PdfCaretAnnotation as Ya, generatePdfAXmpBytes as Yi, buildPieceInfo as Yn, applyPreset as Yr, decodeWoff as Yt, interpretContentStream as Z, PdfRedactAnnotation as Za, stripProhibitedFeatures as Zi, buildRequirements as Zn, borderedPreset as Zr, isWoff2 as Zt, tagLink as _, delinearizePdf as _a, ean8ToOperators as _i, renderCodeFrame as _n, generateStrikeOutAppearance as _o, flattenFields as _r, enforcePdfX as _t, assembleFacturX as a, isValidLevel as aa, readEan8 as ai, renderToPdf as an, PdfHighlightAnnotation as ao, StreamingPdfParser as ar, verifyOfflineRevocation as at, tagParagraph as b, linearizePdf as ba, encodeItf as bi, buildGtsPdfxVersion as bn, PdfTextAnnotation as bo, CombedTextLayoutError as br, getComponentDepths as bt, buildWtpdfIdentificationXmp as c, generateZapfDingbatsToUnicodeCmap as ca, encodePdf417 as ci, splitByScript as cn, PdfUnderlineAnnotation as co, validatePdfUa as cr, validateExtendedKeyUsage as ct, autoTagPage as d, SRGB_ICC_PROFILE as da, encodeDataMatrix as di, buildPdfA4Xmp as dn, generateFreeTextAppearance as do, processBatch as dr, validateCertificateChain as dt, extractXmpMetadata as ea, stripedPreset as ei, createWorkerPool as en, PdfCircleAnnotation as eo, tableToCsv as er, verifyRedactions as et, buildPdfUa2Xmp as f, generateSrgbIccProfile as fa, calculateUpcCheckDigit as fi, pdfA4Rules as fn, generateHighlightAppearance as fo, addBookmark as fr, findHyphenationPoints as ft, tagHeading as g, validatePdfA as ga, ean13ToOperators as gi, levenshtein as gn, generateSquigglyAppearance as go, flattenField as gr, buildPdfXOutputIntent as gt, tagFigure as h, enforcePdfA as ha, calculateEanCheckDigit as hi, didYouMean as hn, generateSquareAppearance as ho, removeBookmark as hr, layoutTextFlow as ht, validateEn16931 as i, getSupportedLevels as ia, readEan13 as ii, h as in, PdfSquareAnnotation as io, timestampPlugin as ir, extractEmbeddedRevocationData as it, buildEncryptedPayload as j, buildFieldLockDict as ja, embedTiffDirect as ji, markdownToPdf as jn, NoSuchFieldError as jr, downloadCrl as jt, buildSoftMaskGroupExtGState as k, diffSignedContent as ka, PdfWorker as ki, nameHalftone as kn, saveIncremental as ko, InvalidPageSizeError as kr, verifySignatureDetailed as kt, convertPdfAConformanceXmp as l, getToUnicodeCmap as la, pdf417ToOperators as li, generateOrderX as ln, PdfFreeTextAnnotation as lo, batchFlatten as lr, validateKeyUsage as lt, LIST_NUMBERING_KEY as m, flattenTransparency as ma, upcAToOperators as mi, sampleShadingColor as mn, generateLineAppearance as mo, removeAllBookmarks as mr, layoutParagraph as mt, detectFacturXProfile as n, validateXmpMetadata as na, readCode128 as ni, buildVtDpm as nn, PdfPolyLineAnnotation as no, accessibilityPlugin as nr, scanPdfThreats as nt, buildFacturXXmp as o, generateSymbolToUnicodeCmap as oa, calculateBarcodeDimensions as oi, createRangeFetcher as on, PdfSquigglyAnnotation as oo, PdfDocumentBuilder as or, EKU_OIDS as ot, validatePdfUa2 as p, detectTransparency as pa, encodeUpcA as pi, buildFunctionShading as pn, generateInkAppearance as po, getBookmarks as pr, layoutColumns as pt, renderDisplayListToCanvas as q, searchTextItems as qa, enforcePdfAFull as qi, buildNamespace as qn, truncateText as qr, AFNumber_Format as qt, parseCiiXml as r, getProfile as ra, readCode39 as ri, gtsPdfVtVersion as rn, PdfPolygonAnnotation as ro, metadataPlugin as rr, buildCertPath as rt, buildPdfRIdentificationXmp as s, generateWinAnsiToUnicodeCmap as sa, renderStyledBarcode as si, resolveFallback as sn, PdfStrikeOutAnnotation as so, enforcePdfUa as sr, validateCertificatePolicy as st, initWasm as t, parseXmpMetadata as ta, readBarcode as ti, buildPdfVtDParts as tn, PdfLineAnnotation as to, tableToJson as tr, sanitizePdf as tt, preflightPdfA as u, buildOutputIntent as ua, dataMatrixToOperators as ui, generateXRechnungCii as un, generateCircleAppearance as uo, batchMerge as ur, buildCertificateChain as ut, tagList as v, getLinearizationInfo as va, encodeEan13 as vi, generateCiiXml as vn, generateUnderlineAppearance as vo, flattenForm as vr, validatePdfX as vt, tagTableRow as w, buildDssDictionary as wa, encodeCode39 as wi, buildSampledTransferFunction as wn, PDFOperator as wo, FieldExistsAsNonTerminalError as wr, upscale8To16 as wt, tagTable as x, computeObjectHash as xa, itfToOperators as xi, buildPdfX6OutputIntent as xn, buildXmpMetadata as xo, EncryptedPdfError as xr, normalizeComponentDepth as xt, tagListItem as y, isLinearized as ya, encodeEan8 as yi, buildBoxDict as yn, PdfLinkAnnotation as yo, BatchProcessingError as yr, downscale16To8 as yt, renderPageTile as z, appendIncrementalUpdate as za, extractJpegMetadata as zi, buildLab as zn, formatDate$1 as zr, setFieldValue as zt };
31672
32947
 
31673
- //# sourceMappingURL=src-zeRl33xQ.mjs.map
32948
+ //# sourceMappingURL=src-BlUlmYsU.mjs.map