@signiphi/page-assembly 0.2.0-beta.7 → 0.2.0-beta.9

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/dist/index.js CHANGED
@@ -43,7 +43,9 @@ var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMe
43
43
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
44
44
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
45
45
 
46
- // src/components/PageAssembler.tsx
46
+ var __defProp = Object.defineProperty;
47
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
48
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
47
49
  function cn(...inputs) {
48
50
  return tailwindMerge.twMerge(clsx.clsx(inputs));
49
51
  }
@@ -574,6 +576,528 @@ var TooltipContent = React7__namespace.forwardRef(({ className, sideOffset = 4,
574
576
  }
575
577
  ));
576
578
  TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
579
+ var PdfPasswordRequiredError = class extends Error {
580
+ constructor() {
581
+ const message = "This PDF is password-protected. Please remove the password and upload it again.";
582
+ super(message);
583
+ __publicField(this, "code", "PDF_PASSWORD_REQUIRED");
584
+ __publicField(this, "recoverable", true);
585
+ __publicField(this, "userMessage");
586
+ this.name = "PdfPasswordRequiredError";
587
+ this.userMessage = message;
588
+ }
589
+ };
590
+ var UnsupportedPdfEncryptionError = class extends Error {
591
+ constructor(detail) {
592
+ super(`This PDF uses an unsupported encryption scheme (${detail}).`);
593
+ this.name = "UnsupportedPdfEncryptionError";
594
+ }
595
+ };
596
+ function concatBytes(...parts) {
597
+ let total = 0;
598
+ for (const p of parts) total += p.length;
599
+ const out = new Uint8Array(total);
600
+ let offset = 0;
601
+ for (const p of parts) {
602
+ out.set(p, offset);
603
+ offset += p.length;
604
+ }
605
+ return out;
606
+ }
607
+ var MD5_S = [
608
+ 7,
609
+ 12,
610
+ 17,
611
+ 22,
612
+ 7,
613
+ 12,
614
+ 17,
615
+ 22,
616
+ 7,
617
+ 12,
618
+ 17,
619
+ 22,
620
+ 7,
621
+ 12,
622
+ 17,
623
+ 22,
624
+ 5,
625
+ 9,
626
+ 14,
627
+ 20,
628
+ 5,
629
+ 9,
630
+ 14,
631
+ 20,
632
+ 5,
633
+ 9,
634
+ 14,
635
+ 20,
636
+ 5,
637
+ 9,
638
+ 14,
639
+ 20,
640
+ 4,
641
+ 11,
642
+ 16,
643
+ 23,
644
+ 4,
645
+ 11,
646
+ 16,
647
+ 23,
648
+ 4,
649
+ 11,
650
+ 16,
651
+ 23,
652
+ 4,
653
+ 11,
654
+ 16,
655
+ 23,
656
+ 6,
657
+ 10,
658
+ 15,
659
+ 21,
660
+ 6,
661
+ 10,
662
+ 15,
663
+ 21,
664
+ 6,
665
+ 10,
666
+ 15,
667
+ 21,
668
+ 6,
669
+ 10,
670
+ 15,
671
+ 21
672
+ ];
673
+ var MD5_K = (() => {
674
+ const k = new Uint32Array(64);
675
+ for (let i = 0; i < 64; i++) k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296);
676
+ return k;
677
+ })();
678
+ function md5(input) {
679
+ const bitLen = input.length * 8;
680
+ const paddedLen = (input.length + 8 >> 6) + 1 << 6;
681
+ const buf = new Uint8Array(paddedLen);
682
+ buf.set(input);
683
+ buf[input.length] = 128;
684
+ const dv = new DataView(buf.buffer);
685
+ dv.setUint32(paddedLen - 8, bitLen >>> 0, true);
686
+ dv.setUint32(paddedLen - 4, Math.floor(bitLen / 4294967296), true);
687
+ let a0 = 1732584193;
688
+ let b0 = 4023233417;
689
+ let c0 = 2562383102;
690
+ let d0 = 271733878;
691
+ const M = new Uint32Array(16);
692
+ for (let offset = 0; offset < paddedLen; offset += 64) {
693
+ for (let i = 0; i < 16; i++) M[i] = dv.getUint32(offset + i * 4, true);
694
+ let A = a0;
695
+ let B = b0;
696
+ let C = c0;
697
+ let D = d0;
698
+ for (let i = 0; i < 64; i++) {
699
+ let F;
700
+ let g;
701
+ if (i < 16) {
702
+ F = B & C | ~B & D;
703
+ g = i;
704
+ } else if (i < 32) {
705
+ F = D & B | ~D & C;
706
+ g = 5 * i + 1 & 15;
707
+ } else if (i < 48) {
708
+ F = B ^ C ^ D;
709
+ g = 3 * i + 5 & 15;
710
+ } else {
711
+ F = C ^ (B | ~D);
712
+ g = 7 * i & 15;
713
+ }
714
+ const tmp = D;
715
+ D = C;
716
+ C = B;
717
+ const x = A + F + MD5_K[i] + M[g] | 0;
718
+ const s = MD5_S[i];
719
+ B = B + (x << s | x >>> 32 - s) | 0;
720
+ A = tmp;
721
+ }
722
+ a0 = a0 + A | 0;
723
+ b0 = b0 + B | 0;
724
+ c0 = c0 + C | 0;
725
+ d0 = d0 + D | 0;
726
+ }
727
+ const out = new Uint8Array(16);
728
+ const ov = new DataView(out.buffer);
729
+ ov.setUint32(0, a0 >>> 0, true);
730
+ ov.setUint32(4, b0 >>> 0, true);
731
+ ov.setUint32(8, c0 >>> 0, true);
732
+ ov.setUint32(12, d0 >>> 0, true);
733
+ return out;
734
+ }
735
+ function rc4(key, data) {
736
+ const S = new Uint8Array(256);
737
+ for (let i2 = 0; i2 < 256; i2++) S[i2] = i2;
738
+ let j = 0;
739
+ for (let i2 = 0; i2 < 256; i2++) {
740
+ j = j + S[i2] + key[i2 % key.length] & 255;
741
+ const t = S[i2];
742
+ S[i2] = S[j];
743
+ S[j] = t;
744
+ }
745
+ const out = new Uint8Array(data.length);
746
+ let i = 0;
747
+ j = 0;
748
+ for (let k = 0; k < data.length; k++) {
749
+ i = i + 1 & 255;
750
+ j = j + S[i] & 255;
751
+ const t = S[i];
752
+ S[i] = S[j];
753
+ S[j] = t;
754
+ out[k] = data[k] ^ S[S[i] + S[j] & 255];
755
+ }
756
+ return out;
757
+ }
758
+ function getSubtle() {
759
+ const subtle = globalThis.crypto?.subtle;
760
+ if (!subtle) throw new UnsupportedPdfEncryptionError("WebCrypto is unavailable in this environment");
761
+ return subtle;
762
+ }
763
+ async function sha2(algorithm, data) {
764
+ return new Uint8Array(await getSubtle().digest(algorithm, data));
765
+ }
766
+ async function importAesKey(rawKey, usages) {
767
+ return getSubtle().importKey("raw", rawKey, "AES-CBC", false, usages);
768
+ }
769
+ async function aesCbcEncryptNoPad(rawKey, iv, data) {
770
+ const key = await importAesKey(rawKey, ["encrypt"]);
771
+ const out = new Uint8Array(await getSubtle().encrypt({ name: "AES-CBC", iv }, key, data));
772
+ return out.slice(0, data.length);
773
+ }
774
+ async function aesCbcDecryptNoPad(rawKey, iv, data) {
775
+ const key = await importAesKey(rawKey, ["encrypt", "decrypt"]);
776
+ const lastBlock = data.slice(data.length - 16);
777
+ const padBlock = new Uint8Array(
778
+ await getSubtle().encrypt({ name: "AES-CBC", iv: lastBlock }, key, new Uint8Array(0))
779
+ );
780
+ const joined = concatBytes(data, padBlock);
781
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, joined));
782
+ }
783
+ async function aesDecryptPdfData(rawKey, data) {
784
+ if (data.length < 32) return new Uint8Array(0);
785
+ const iv = data.slice(0, 16);
786
+ let ct = data.slice(16);
787
+ if (ct.length % 16 !== 0) ct = ct.slice(0, ct.length - ct.length % 16);
788
+ try {
789
+ const key = await importAesKey(rawKey, ["decrypt"]);
790
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, ct));
791
+ } catch {
792
+ const plain = await aesCbcDecryptNoPad(rawKey, iv, ct);
793
+ const padLen = plain[plain.length - 1];
794
+ return padLen >= 1 && padLen <= 16 ? plain.slice(0, plain.length - padLen) : plain;
795
+ }
796
+ }
797
+ var PAD = new Uint8Array([
798
+ 40,
799
+ 191,
800
+ 78,
801
+ 94,
802
+ 78,
803
+ 117,
804
+ 138,
805
+ 65,
806
+ 100,
807
+ 0,
808
+ 78,
809
+ 86,
810
+ 255,
811
+ 250,
812
+ 1,
813
+ 8,
814
+ 46,
815
+ 46,
816
+ 0,
817
+ 182,
818
+ 208,
819
+ 104,
820
+ 62,
821
+ 128,
822
+ 47,
823
+ 12,
824
+ 169,
825
+ 254,
826
+ 100,
827
+ 83,
828
+ 105,
829
+ 122
830
+ ]);
831
+ var bytesEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
832
+ function legacyFileKey(paddedPwd, params) {
833
+ const { revision, keyLen, O, P, id0, encryptMetadata } = params;
834
+ const pBytes = new Uint8Array(4);
835
+ new DataView(pBytes.buffer).setInt32(0, P | 0, true);
836
+ const parts = [paddedPwd, O.slice(0, 32), pBytes, id0];
837
+ if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([255, 255, 255, 255]));
838
+ let h = md5(concatBytes(...parts));
839
+ if (revision >= 3) for (let i = 0; i < 50; i++) h = md5(h.slice(0, keyLen));
840
+ return h.slice(0, keyLen);
841
+ }
842
+ function legacyComputeU(fileKey, revision, id0) {
843
+ if (revision === 2) return rc4(fileKey, PAD);
844
+ let d = md5(concatBytes(PAD, id0));
845
+ d = rc4(fileKey, d);
846
+ for (let i = 1; i <= 19; i++) d = rc4(fileKey.map((b) => b ^ i), d);
847
+ return d;
848
+ }
849
+ function legacyUMatches(fileKey, params) {
850
+ const computed = legacyComputeU(fileKey, params.revision, params.id0);
851
+ return params.revision === 2 ? bytesEqual(computed, params.U.slice(0, 32)) : bytesEqual(computed.slice(0, 16), params.U.slice(0, 16));
852
+ }
853
+ function legacyAuthenticateEmptyPassword(params) {
854
+ const userKey = legacyFileKey(PAD, params);
855
+ if (legacyUMatches(userKey, params)) return userKey;
856
+ const { revision, keyLen } = params;
857
+ let h = md5(PAD);
858
+ if (revision >= 3) for (let i = 0; i < 50; i++) h = md5(h);
859
+ const ownerKey = h.slice(0, keyLen);
860
+ let recovered = params.O.slice(0, 32);
861
+ if (revision === 2) {
862
+ recovered = rc4(ownerKey, recovered);
863
+ } else {
864
+ for (let i = 19; i >= 0; i--) recovered = rc4(ownerKey.map((b) => b ^ i), recovered);
865
+ }
866
+ const viaOwner = legacyFileKey(recovered, params);
867
+ if (legacyUMatches(viaOwner, params)) return viaOwner;
868
+ throw new PdfPasswordRequiredError();
869
+ }
870
+ async function hash2B(password, salt, udata) {
871
+ let k = await sha2("SHA-256", concatBytes(password, salt, udata));
872
+ let e = new Uint8Array(0);
873
+ let i = 0;
874
+ do {
875
+ const block = concatBytes(password, k, udata);
876
+ const k1 = new Uint8Array(block.length * 64);
877
+ for (let rep = 0; rep < 64; rep++) k1.set(block, rep * block.length);
878
+ e = await aesCbcEncryptNoPad(k.slice(0, 16), k.slice(16, 32), k1);
879
+ let sum = 0;
880
+ for (let b = 0; b < 16; b++) sum += e[b];
881
+ const mod = sum % 3;
882
+ k = await sha2(mod === 0 ? "SHA-256" : mod === 1 ? "SHA-384" : "SHA-512", e);
883
+ i++;
884
+ } while (i < 64 || e[e.length - 1] > i - 32);
885
+ return k.slice(0, 32);
886
+ }
887
+ async function v5AuthenticateEmptyPassword(revision, U, O, UE, OE) {
888
+ const pwd = new Uint8Array(0);
889
+ const zeroIv = new Uint8Array(16);
890
+ const hash = async (salt, udata) => revision === 5 ? sha2("SHA-256", concatBytes(pwd, salt, udata)) : hash2B(pwd, salt, udata);
891
+ const userHash = await hash(U.slice(32, 40), new Uint8Array(0));
892
+ if (bytesEqual(userHash, U.slice(0, 32))) {
893
+ const intermediate = await hash(U.slice(40, 48), new Uint8Array(0));
894
+ return aesCbcDecryptNoPad(intermediate, zeroIv, UE.slice(0, 32));
895
+ }
896
+ const u48 = U.slice(0, 48);
897
+ const ownerHash = await hash(O.slice(32, 40), u48);
898
+ if (bytesEqual(ownerHash, O.slice(0, 32))) {
899
+ const intermediate = await hash(O.slice(40, 48), u48);
900
+ return aesCbcDecryptNoPad(intermediate, zeroIv, OE.slice(0, 32));
901
+ }
902
+ throw new PdfPasswordRequiredError();
903
+ }
904
+ var identityCipher = async (data) => data;
905
+ function rc4ObjectCipher(fileKey) {
906
+ return async (data, ref) => {
907
+ const ext = new Uint8Array([
908
+ ref.objectNumber & 255,
909
+ ref.objectNumber >> 8 & 255,
910
+ ref.objectNumber >> 16 & 255,
911
+ ref.generationNumber & 255,
912
+ ref.generationNumber >> 8 & 255
913
+ ]);
914
+ const key = md5(concatBytes(fileKey, ext)).slice(0, Math.min(fileKey.length + 5, 16));
915
+ return rc4(key, data);
916
+ };
917
+ }
918
+ var AES_SALT = new Uint8Array([115, 65, 108, 84]);
919
+ function aes128ObjectCipher(fileKey) {
920
+ return async (data, ref) => {
921
+ const ext = new Uint8Array([
922
+ ref.objectNumber & 255,
923
+ ref.objectNumber >> 8 & 255,
924
+ ref.objectNumber >> 16 & 255,
925
+ ref.generationNumber & 255,
926
+ ref.generationNumber >> 8 & 255
927
+ ]);
928
+ const key = md5(concatBytes(fileKey, ext, AES_SALT)).slice(0, 16);
929
+ return aesDecryptPdfData(key, data);
930
+ };
931
+ }
932
+ function aes256ObjectCipher(fileKey) {
933
+ return async (data) => aesDecryptPdfData(fileKey, data);
934
+ }
935
+ function dictNumber(dict, key) {
936
+ const value = dict.lookup(pdfLib.PDFName.of(key));
937
+ return value instanceof pdfLib.PDFNumber ? value.asNumber() : void 0;
938
+ }
939
+ function dictBytes(dict, key) {
940
+ const value = dict.lookup(pdfLib.PDFName.of(key));
941
+ return value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString ? value.asBytes() : void 0;
942
+ }
943
+ async function buildDocumentCiphers(encDict, id0) {
944
+ const filter = encDict.lookup(pdfLib.PDFName.of("Filter"));
945
+ if (filter !== pdfLib.PDFName.of("Standard")) {
946
+ throw new UnsupportedPdfEncryptionError(`security handler ${String(filter)}`);
947
+ }
948
+ const V = dictNumber(encDict, "V") ?? 0;
949
+ const R = dictNumber(encDict, "R") ?? 0;
950
+ const O = dictBytes(encDict, "O");
951
+ const U = dictBytes(encDict, "U");
952
+ const P = dictNumber(encDict, "P") ?? -1;
953
+ const metadataValue = encDict.lookup(pdfLib.PDFName.of("EncryptMetadata"));
954
+ const encryptMetadata = metadataValue instanceof pdfLib.PDFBool ? metadataValue.asBoolean() : true;
955
+ if (!O || !U) throw new UnsupportedPdfEncryptionError("missing /O or /U");
956
+ if (V === 1 || V === 2) {
957
+ const keyLen = V === 1 ? 5 : (dictNumber(encDict, "Length") ?? 40) / 8;
958
+ const fileKey = legacyAuthenticateEmptyPassword({ revision: R, keyLen, O, U, P, id0, encryptMetadata });
959
+ const cipher = rc4ObjectCipher(fileKey);
960
+ return { stringCipher: cipher, streamCipher: cipher, encryptMetadata };
961
+ }
962
+ if (V === 4 || V === 5) {
963
+ const cf = encDict.lookup(pdfLib.PDFName.of("CF"));
964
+ const cfmOf = (filterKey) => {
965
+ const streamFilter = encDict.lookup(pdfLib.PDFName.of(filterKey));
966
+ if (!(streamFilter instanceof pdfLib.PDFName) || streamFilter === pdfLib.PDFName.of("Identity")) return void 0;
967
+ if (!(cf instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError("missing /CF");
968
+ const cfDict = cf.lookup(streamFilter);
969
+ if (!(cfDict instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError(`missing crypt filter ${streamFilter.toString()}`);
970
+ const cfm = cfDict.lookup(pdfLib.PDFName.of("CFM"));
971
+ return cfm instanceof pdfLib.PDFName ? cfm : void 0;
972
+ };
973
+ let fileKey;
974
+ if (V === 5) {
975
+ const UE = dictBytes(encDict, "UE");
976
+ const OE = dictBytes(encDict, "OE");
977
+ if (!UE || !OE) throw new UnsupportedPdfEncryptionError("missing /UE or /OE");
978
+ fileKey = await v5AuthenticateEmptyPassword(R, U, O, UE, OE);
979
+ } else {
980
+ const keyLen = (dictNumber(encDict, "Length") ?? 40) / 8;
981
+ fileKey = legacyAuthenticateEmptyPassword({ revision: R, keyLen, O, U, P, id0, encryptMetadata });
982
+ }
983
+ const cipherFor = (cfm) => {
984
+ if (!cfm || cfm === pdfLib.PDFName.of("Identity")) return identityCipher;
985
+ if (cfm === pdfLib.PDFName.of("V2")) return rc4ObjectCipher(fileKey);
986
+ if (cfm === pdfLib.PDFName.of("AESV2")) return aes128ObjectCipher(fileKey);
987
+ if (cfm === pdfLib.PDFName.of("AESV3")) return aes256ObjectCipher(fileKey);
988
+ throw new UnsupportedPdfEncryptionError(`crypt filter method ${cfm.toString()}`);
989
+ };
990
+ return {
991
+ streamCipher: cipherFor(cfmOf("StmF")),
992
+ stringCipher: cipherFor(cfmOf("StrF")),
993
+ encryptMetadata
994
+ };
995
+ }
996
+ throw new UnsupportedPdfEncryptionError(`/V ${V}`);
997
+ }
998
+ var toHexString = (bytes) => {
999
+ let hex = "";
1000
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
1001
+ return new pdfLib.PDFHexString(hex.toUpperCase());
1002
+ };
1003
+ function filterIncludesCrypt(dict) {
1004
+ const filter = dict.lookup(pdfLib.PDFName.of("Filter"));
1005
+ if (filter === pdfLib.PDFName.of("Crypt")) return true;
1006
+ if (filter instanceof pdfLib.PDFArray) {
1007
+ for (let i = 0; i < filter.size(); i++) {
1008
+ if (filter.get(i) === pdfLib.PDFName.of("Crypt")) return true;
1009
+ }
1010
+ }
1011
+ return false;
1012
+ }
1013
+ async function decryptStringsWithin(obj, ref, stringCipher) {
1014
+ if (obj instanceof pdfLib.PDFDict) {
1015
+ const isSignature = obj.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("Sig");
1016
+ for (const [key, value] of obj.entries()) {
1017
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1018
+ if (isSignature && key === pdfLib.PDFName.of("Contents")) continue;
1019
+ obj.set(key, toHexString(await stringCipher(value.asBytes(), ref)));
1020
+ } else {
1021
+ await decryptStringsWithin(value, ref, stringCipher);
1022
+ }
1023
+ }
1024
+ } else if (obj instanceof pdfLib.PDFArray) {
1025
+ for (let i = 0; i < obj.size(); i++) {
1026
+ const value = obj.get(i);
1027
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1028
+ obj.set(i, toHexString(await stringCipher(value.asBytes(), ref)));
1029
+ } else {
1030
+ await decryptStringsWithin(value, ref, stringCipher);
1031
+ }
1032
+ }
1033
+ }
1034
+ }
1035
+ async function decryptLoadedDocument(doc) {
1036
+ const context = doc.context;
1037
+ const encryptRef = context.trailerInfo.Encrypt;
1038
+ const encDict = context.lookup(encryptRef);
1039
+ if (!(encDict instanceof pdfLib.PDFDict)) {
1040
+ throw new UnsupportedPdfEncryptionError("malformed /Encrypt dictionary");
1041
+ }
1042
+ const idArray = context.lookup(context.trailerInfo.ID);
1043
+ const idFirst = idArray instanceof pdfLib.PDFArray ? idArray.get(0) : void 0;
1044
+ const id0 = idFirst instanceof pdfLib.PDFString || idFirst instanceof pdfLib.PDFHexString ? idFirst.asBytes() : new Uint8Array(0);
1045
+ const { stringCipher, streamCipher, encryptMetadata } = await buildDocumentCiphers(encDict, id0);
1046
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1047
+ if (ref === encryptRef || obj === encDict) continue;
1048
+ if (obj instanceof pdfLib.PDFRawStream) {
1049
+ const type = obj.dict.lookup(pdfLib.PDFName.of("Type"));
1050
+ const isXrefStream = type === pdfLib.PDFName.of("XRef");
1051
+ const isSkippedMetadata = !encryptMetadata && type === pdfLib.PDFName.of("Metadata");
1052
+ if (!isXrefStream && !isSkippedMetadata && !filterIncludesCrypt(obj.dict)) {
1053
+ const decrypted = await streamCipher(obj.contents, ref);
1054
+ context.assign(ref, pdfLib.PDFRawStream.of(obj.dict, decrypted));
1055
+ }
1056
+ await decryptStringsWithin(obj.dict, ref, stringCipher);
1057
+ } else if (obj instanceof pdfLib.PDFString || obj instanceof pdfLib.PDFHexString) {
1058
+ context.assign(ref, toHexString(await stringCipher(obj.asBytes(), ref)));
1059
+ } else {
1060
+ await decryptStringsWithin(obj, ref, stringCipher);
1061
+ }
1062
+ }
1063
+ delete context.trailerInfo.Encrypt;
1064
+ if (encryptRef instanceof pdfLib.PDFRef) context.delete(encryptRef);
1065
+ return doc.save({ useObjectStreams: false });
1066
+ }
1067
+ async function decryptPdf(pdfBytes) {
1068
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1069
+ ignoreEncryption: true,
1070
+ updateMetadata: false
1071
+ });
1072
+ if (!doc.isEncrypted) return pdfBytes;
1073
+ return decryptLoadedDocument(doc);
1074
+ }
1075
+ var ENCRYPT_MARKER = new Uint8Array([47, 69, 110, 99, 114, 121, 112, 116]);
1076
+ function containsEncryptMarker(bytes) {
1077
+ const last = bytes.length - ENCRYPT_MARKER.length;
1078
+ outer: for (let i = 0; i <= last; i++) {
1079
+ for (let j = 0; j < ENCRYPT_MARKER.length; j++) {
1080
+ if (bytes[i + j] !== ENCRYPT_MARKER[j]) continue outer;
1081
+ }
1082
+ return true;
1083
+ }
1084
+ return false;
1085
+ }
1086
+ function isEncryptedPdfError(error) {
1087
+ return error instanceof pdfLib.EncryptedPDFError || error instanceof Error && error.message.includes("is encrypted");
1088
+ }
1089
+ async function normalizePdfEncryption(pdfBytes) {
1090
+ if (!containsEncryptMarker(pdfBytes)) return pdfBytes;
1091
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1092
+ ignoreEncryption: true,
1093
+ updateMetadata: false
1094
+ });
1095
+ if (!doc.isEncrypted) return pdfBytes;
1096
+ console.info("[PageAssembler] Encrypted PDF detected during ingestion; decrypting");
1097
+ return decryptLoadedDocument(doc);
1098
+ }
1099
+
1100
+ // src/utils/pdf-helpers.ts
577
1101
  if (typeof window !== "undefined") {
578
1102
  pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
579
1103
  }
@@ -645,6 +1169,53 @@ async function pdfToImages(pdfBytes, options) {
645
1169
  throw error;
646
1170
  }
647
1171
  }
1172
+ async function rasterizePdfToPdf(pdfBytes) {
1173
+ if (typeof window !== "undefined") {
1174
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
1175
+ }
1176
+ let sourceDoc;
1177
+ try {
1178
+ sourceDoc = await pdfjsLib__namespace.getDocument({ data: pdfBytes.slice(0), verbosity: 0 }).promise;
1179
+ } catch (error) {
1180
+ if (error?.name === "PasswordException") {
1181
+ throw new PdfPasswordRequiredError();
1182
+ }
1183
+ throw error;
1184
+ }
1185
+ try {
1186
+ const outDoc = await pdfLib.PDFDocument.create();
1187
+ for (let pageNum = 1; pageNum <= sourceDoc.numPages; pageNum++) {
1188
+ const page = await sourceDoc.getPage(pageNum);
1189
+ const viewport = page.getViewport({ scale: 2 });
1190
+ const canvas = document.createElement("canvas");
1191
+ canvas.width = viewport.width;
1192
+ canvas.height = viewport.height;
1193
+ const context = canvas.getContext("2d");
1194
+ await page.render({ canvasContext: context, viewport }).promise;
1195
+ const png = await outDoc.embedPng(canvas.toDataURL("image/png"));
1196
+ const pageWidth = viewport.width / 2;
1197
+ const pageHeight = viewport.height / 2;
1198
+ const outPage = outDoc.addPage([pageWidth, pageHeight]);
1199
+ outPage.drawImage(png, { x: 0, y: 0, width: pageWidth, height: pageHeight });
1200
+ }
1201
+ return new Uint8Array(await outDoc.save({ useObjectStreams: false }));
1202
+ } finally {
1203
+ await sourceDoc.destroy();
1204
+ }
1205
+ }
1206
+ async function normalizeUploadedPdfBytes(pdfBytes) {
1207
+ try {
1208
+ const normalized = await normalizePdfEncryption(pdfBytes);
1209
+ return normalized === pdfBytes ? pdfBytes : new Uint8Array(normalized);
1210
+ } catch (error) {
1211
+ if (error instanceof PdfPasswordRequiredError) throw error;
1212
+ console.warn(
1213
+ "[PageAssembler] Structural decryption failed; rebuilding document from rendered pages:",
1214
+ error
1215
+ );
1216
+ return rasterizePdfToPdf(pdfBytes);
1217
+ }
1218
+ }
648
1219
  async function imageToPdf(imageFile) {
649
1220
  return new Promise((resolve, reject) => {
650
1221
  const img = new Image();
@@ -1928,6 +2499,7 @@ var PageAssembler = React7.forwardRef(
1928
2499
  );
1929
2500
  const [isLoading, setIsLoading] = React7.useState(false);
1930
2501
  const [processingStatus, setProcessingStatus] = React7.useState("");
2502
+ const [uploadError, setUploadError] = React7.useState(null);
1931
2503
  const [showDeleteConfirm, setShowDeleteConfirm] = React7.useState(false);
1932
2504
  const [showRemoveFileConfirm, setShowRemoveFileConfirm] = React7.useState(false);
1933
2505
  const [fileToRemove, setFileToRemove] = React7.useState(null);
@@ -1969,6 +2541,7 @@ var PageAssembler = React7.forwardRef(
1969
2541
  } else {
1970
2542
  pdfBytes = new Uint8Array(pdf);
1971
2543
  }
2544
+ pdfBytes = await normalizeUploadedPdfBytes(pdfBytes);
1972
2545
  const defensiveCopy = new Uint8Array(pdfBytes);
1973
2546
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1974
2547
  if (pages.length === 0) {
@@ -2014,8 +2587,9 @@ var PageAssembler = React7.forwardRef(
2014
2587
  setProcessingStatus("");
2015
2588
  }
2016
2589
  }, []);
2590
+ const hasRestorableState = !!initialState && initialState.files.length > 0;
2017
2591
  React7.useEffect(() => {
2018
- if (initialPdf && !initialState) {
2592
+ if (initialPdf && state.files.length === 0 && !hasRestorableState) {
2019
2593
  const pdfIdentifier = initialPdf instanceof Uint8Array ? `uint8array-${initialPdf.length}-${initialPdf[0]}-${initialPdf[initialPdf.length - 1]}` : `${initialPdf.constructor.name}-${initialPdf.size || initialPdf.byteLength}`;
2020
2594
  if (processedInitialPdfRef.current === pdfIdentifier) {
2021
2595
  return;
@@ -2023,15 +2597,16 @@ var PageAssembler = React7.forwardRef(
2023
2597
  processedInitialPdfRef.current = pdfIdentifier;
2024
2598
  processInitialPdf(initialPdf);
2025
2599
  }
2026
- }, [initialPdf, initialState, processInitialPdf]);
2600
+ }, [initialPdf, state.files.length, hasRestorableState, processInitialPdf]);
2027
2601
  React7.useEffect(() => {
2028
- if (initialState) {
2602
+ if (initialState && initialState.files.length > 0) {
2029
2603
  dispatch({ type: "RESET", payload: initialState });
2030
2604
  }
2031
2605
  }, [initialState]);
2032
2606
  const processFiles = React7.useCallback(async (files) => {
2033
2607
  const fileArray = Array.from(files);
2034
2608
  const maxFileSize = (limits?.maxFileSizeMB || 10) * 1024 * 1024;
2609
+ setUploadError(null);
2035
2610
  setIsLoading(true);
2036
2611
  setProcessingStatus(`Processing ${fileArray.length} file${fileArray.length !== 1 ? "s" : ""}...`);
2037
2612
  for (const file of fileArray) {
@@ -2056,7 +2631,7 @@ var PageAssembler = React7.forwardRef(
2056
2631
  if (file.type === "application/pdf") {
2057
2632
  setProcessingStatus(`Processing PDF: ${file.name}`);
2058
2633
  const arrayBuffer = await file.arrayBuffer();
2059
- const pdfBytes = new Uint8Array(arrayBuffer);
2634
+ const pdfBytes = await normalizeUploadedPdfBytes(new Uint8Array(arrayBuffer));
2060
2635
  fileInfo.originalBytes = new Uint8Array(pdfBytes);
2061
2636
  originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
2062
2637
  const defensiveCopy = new Uint8Array(pdfBytes);
@@ -2106,6 +2681,11 @@ var PageAssembler = React7.forwardRef(
2106
2681
  dispatch({ type: "ADD_FILE", payload: fileInfo });
2107
2682
  } catch (error) {
2108
2683
  console.error(`Error processing file ${file.name}:`, error);
2684
+ if (error instanceof PdfPasswordRequiredError) {
2685
+ setUploadError(`${file.name}: ${error.userMessage}`);
2686
+ } else {
2687
+ setUploadError(`Failed to process "${file.name}". The file may be corrupted or unsupported.`);
2688
+ }
2109
2689
  }
2110
2690
  }
2111
2691
  setIsLoading(false);
@@ -2203,7 +2783,7 @@ var PageAssembler = React7.forwardRef(
2203
2783
  setIsLoading(true);
2204
2784
  setProcessingStatus("Assembling PDF...");
2205
2785
  try {
2206
- const { PDFDocument: PDFDocument4, PDFName: PDFName3, PDFString: PDFString3 } = await import('pdf-lib');
2786
+ const { PDFDocument: PDFDocument5, PDFName: PDFName4, PDFString: PDFString4 } = await import('pdf-lib');
2207
2787
  const loadedPdfs = /* @__PURE__ */ new Map();
2208
2788
  const fileMap = /* @__PURE__ */ new Map();
2209
2789
  const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
@@ -2213,7 +2793,7 @@ var PageAssembler = React7.forwardRef(
2213
2793
  fileMap.set(file.id, file);
2214
2794
  if (file.type === "pdf" && file.originalBytes && file.originalBytes.length > 0) {
2215
2795
  try {
2216
- const sourcePdf = await PDFDocument4.load(file.originalBytes);
2796
+ const sourcePdf = await PDFDocument5.load(file.originalBytes);
2217
2797
  loadedPdfs.set(file.id, sourcePdf);
2218
2798
  } catch (error) {
2219
2799
  console.error(`Error loading PDF for file ${file.id}:`, error);
@@ -2234,7 +2814,7 @@ var PageAssembler = React7.forwardRef(
2234
2814
  if (cachedBytes && cachedBytes.length > 0) {
2235
2815
  try {
2236
2816
  console.log(`[PageAssembler] Loading PDF from cache for deleted file ${fileId}`);
2237
- const sourcePdf = await PDFDocument4.load(cachedBytes);
2817
+ const sourcePdf = await PDFDocument5.load(cachedBytes);
2238
2818
  loadedPdfs.set(fileId, sourcePdf);
2239
2819
  } catch (error) {
2240
2820
  console.error(`Error loading cached PDF for file ${fileId}:`, error);
@@ -2318,7 +2898,7 @@ var PageAssembler = React7.forwardRef(
2318
2898
  if (sourceInfoRef) {
2319
2899
  const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
2320
2900
  if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
2321
- const metadataObj = sourceInfoDict.get(PDFName3.of("SigniphiMetadata"));
2901
+ const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
2322
2902
  if (metadataObj) {
2323
2903
  const metadataStr = metadataObj.toString();
2324
2904
  let jsonStr = metadataStr;
@@ -2401,7 +2981,7 @@ var PageAssembler = React7.forwardRef(
2401
2981
  }
2402
2982
  console.log(`[PageAssembler] Total extracted fields: ${allExtractedFields.length}`);
2403
2983
  console.log(`[PageAssembler] Field names:`, allExtractedFields.map((f) => `${f.name} (page ${f.position.page})`));
2404
- const combinedDoc = await PDFDocument4.create();
2984
+ const combinedDoc = await PDFDocument5.create();
2405
2985
  for (const file of state.files) {
2406
2986
  if (file.pages.length === 0) continue;
2407
2987
  for (const page of file.pages) {
@@ -2423,9 +3003,9 @@ var PageAssembler = React7.forwardRef(
2423
3003
  const copiedPages = await combinedDoc.copyPages(sourcePdf, [page.srcIndex]);
2424
3004
  copiedPages.forEach((copiedPage) => {
2425
3005
  try {
2426
- const annotsRef = copiedPage.node.get(PDFName3.of("Annots"));
3006
+ const annotsRef = copiedPage.node.get(PDFName4.of("Annots"));
2427
3007
  if (annotsRef) {
2428
- copiedPage.node.delete(PDFName3.of("Annots"));
3008
+ copiedPage.node.delete(PDFName4.of("Annots"));
2429
3009
  }
2430
3010
  } catch (annotError) {
2431
3011
  console.warn("Could not remove annotations from copied page:", annotError);
@@ -2440,7 +3020,7 @@ var PageAssembler = React7.forwardRef(
2440
3020
  } else if (sourceFile.type === "image" && sourceFile.originalFile) {
2441
3021
  try {
2442
3022
  const imagePdfBytes = await imageToPdf(sourceFile.originalFile);
2443
- const imagePdf = await PDFDocument4.load(imagePdfBytes);
3023
+ const imagePdf = await PDFDocument5.load(imagePdfBytes);
2444
3024
  const copiedPages = await combinedDoc.copyPages(imagePdf, [0]);
2445
3025
  copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
2446
3026
  } catch (imageError) {
@@ -2457,8 +3037,8 @@ var PageAssembler = React7.forwardRef(
2457
3037
  const newInfoDict = combinedDoc.context.lookup(newInfoRef);
2458
3038
  if (newInfoDict && typeof newInfoDict.set === "function") {
2459
3039
  newInfoDict.set(
2460
- PDFName3.of("SigniphiMetadata"),
2461
- PDFString3.of(JSON.stringify(mergedMetadata))
3040
+ PDFName4.of("SigniphiMetadata"),
3041
+ PDFString4.of(JSON.stringify(mergedMetadata))
2462
3042
  );
2463
3043
  }
2464
3044
  }
@@ -2544,6 +3124,10 @@ var PageAssembler = React7.forwardRef(
2544
3124
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
2545
3125
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: processingStatus })
2546
3126
  ] }) }),
3127
+ uploadError && !isLoading && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-destructive/50 bg-destructive/5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
3128
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4 text-destructive flex-shrink-0" }),
3129
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: uploadError })
3130
+ ] }) }),
2547
3131
  /* @__PURE__ */ jsxRuntime.jsx(
2548
3132
  BulkActionBar,
2549
3133
  {
@@ -2682,14 +3266,21 @@ function debounce(func, wait) {
2682
3266
  exports.Button = Button;
2683
3267
  exports.FormFieldType = FormFieldType;
2684
3268
  exports.PageAssembler = PageAssembler;
3269
+ exports.PdfPasswordRequiredError = PdfPasswordRequiredError;
3270
+ exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError;
2685
3271
  exports.addFormFieldsToPdf = addFormFieldsToPdf;
2686
3272
  exports.createPdfBlobUrl = createPdfBlobUrl;
3273
+ exports.decryptPdf = decryptPdf;
2687
3274
  exports.downloadPdf = downloadPdf;
2688
3275
  exports.extractFieldsFromPdf = extractFieldsFromPdf;
2689
3276
  exports.getSigniphiMetadata = getSigniphiMetadata;
2690
3277
  exports.imageToPdf = imageToPdf;
3278
+ exports.isEncryptedPdfError = isEncryptedPdfError;
2691
3279
  exports.mapFieldPositionsAfterAssembly = mapFieldPositionsAfterAssembly;
3280
+ exports.normalizePdfEncryption = normalizePdfEncryption;
3281
+ exports.normalizeUploadedPdfBytes = normalizeUploadedPdfBytes;
2692
3282
  exports.pdfToImages = pdfToImages;
3283
+ exports.rasterizePdfToPdf = rasterizePdfToPdf;
2693
3284
  exports.setSigniphiMetadata = setSigniphiMetadata;
2694
3285
  //# sourceMappingURL=index.js.map
2695
3286
  //# sourceMappingURL=index.js.map