@signiphi/page-assembly 0.2.0-beta.1 → 0.2.0-beta.11

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
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var React7 = require('react');
6
4
  var reactDnd = require('react-dnd');
7
5
  var reactDndHtml5Backend = require('react-dnd-html5-backend');
@@ -576,6 +574,623 @@ var TooltipContent = React7__namespace.forwardRef(({ className, sideOffset = 4,
576
574
  }
577
575
  ));
578
576
  TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
577
+ var PdfPasswordRequiredError = class extends Error {
578
+ constructor() {
579
+ const message = "This PDF is password-protected. Please remove the password and upload it again.";
580
+ super(message);
581
+ this.code = "PDF_PASSWORD_REQUIRED";
582
+ this.recoverable = true;
583
+ this.name = "PdfPasswordRequiredError";
584
+ this.userMessage = message;
585
+ }
586
+ };
587
+ var UnsupportedPdfEncryptionError = class extends Error {
588
+ constructor(detail) {
589
+ super(`This PDF uses an unsupported encryption scheme (${detail}).`);
590
+ this.name = "UnsupportedPdfEncryptionError";
591
+ this.detail = detail;
592
+ }
593
+ };
594
+ function concatBytes(...parts) {
595
+ let total = 0;
596
+ for (const p of parts) total += p.length;
597
+ const out = new Uint8Array(total);
598
+ let offset = 0;
599
+ for (const p of parts) {
600
+ out.set(p, offset);
601
+ offset += p.length;
602
+ }
603
+ return out;
604
+ }
605
+ var MD5_S = [
606
+ 7,
607
+ 12,
608
+ 17,
609
+ 22,
610
+ 7,
611
+ 12,
612
+ 17,
613
+ 22,
614
+ 7,
615
+ 12,
616
+ 17,
617
+ 22,
618
+ 7,
619
+ 12,
620
+ 17,
621
+ 22,
622
+ 5,
623
+ 9,
624
+ 14,
625
+ 20,
626
+ 5,
627
+ 9,
628
+ 14,
629
+ 20,
630
+ 5,
631
+ 9,
632
+ 14,
633
+ 20,
634
+ 5,
635
+ 9,
636
+ 14,
637
+ 20,
638
+ 4,
639
+ 11,
640
+ 16,
641
+ 23,
642
+ 4,
643
+ 11,
644
+ 16,
645
+ 23,
646
+ 4,
647
+ 11,
648
+ 16,
649
+ 23,
650
+ 4,
651
+ 11,
652
+ 16,
653
+ 23,
654
+ 6,
655
+ 10,
656
+ 15,
657
+ 21,
658
+ 6,
659
+ 10,
660
+ 15,
661
+ 21,
662
+ 6,
663
+ 10,
664
+ 15,
665
+ 21,
666
+ 6,
667
+ 10,
668
+ 15,
669
+ 21
670
+ ];
671
+ var MD5_K = (() => {
672
+ const k = new Uint32Array(64);
673
+ for (let i = 0; i < 64; i++) k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296);
674
+ return k;
675
+ })();
676
+ function md5(input) {
677
+ const bitLen = input.length * 8;
678
+ const paddedLen = (input.length + 8 >> 6) + 1 << 6;
679
+ const buf = new Uint8Array(paddedLen);
680
+ buf.set(input);
681
+ buf[input.length] = 128;
682
+ const dv = new DataView(buf.buffer);
683
+ dv.setUint32(paddedLen - 8, bitLen >>> 0, true);
684
+ dv.setUint32(paddedLen - 4, Math.floor(bitLen / 4294967296), true);
685
+ let a0 = 1732584193;
686
+ let b0 = 4023233417;
687
+ let c0 = 2562383102;
688
+ let d0 = 271733878;
689
+ const M = new Uint32Array(16);
690
+ for (let offset = 0; offset < paddedLen; offset += 64) {
691
+ for (let i = 0; i < 16; i++) M[i] = dv.getUint32(offset + i * 4, true);
692
+ let A = a0;
693
+ let B = b0;
694
+ let C = c0;
695
+ let D = d0;
696
+ for (let i = 0; i < 64; i++) {
697
+ let F;
698
+ let g;
699
+ if (i < 16) {
700
+ F = B & C | ~B & D;
701
+ g = i;
702
+ } else if (i < 32) {
703
+ F = D & B | ~D & C;
704
+ g = 5 * i + 1 & 15;
705
+ } else if (i < 48) {
706
+ F = B ^ C ^ D;
707
+ g = 3 * i + 5 & 15;
708
+ } else {
709
+ F = C ^ (B | ~D);
710
+ g = 7 * i & 15;
711
+ }
712
+ const tmp = D;
713
+ D = C;
714
+ C = B;
715
+ const x = A + F + MD5_K[i] + M[g] | 0;
716
+ const s = MD5_S[i];
717
+ B = B + (x << s | x >>> 32 - s) | 0;
718
+ A = tmp;
719
+ }
720
+ a0 = a0 + A | 0;
721
+ b0 = b0 + B | 0;
722
+ c0 = c0 + C | 0;
723
+ d0 = d0 + D | 0;
724
+ }
725
+ const out = new Uint8Array(16);
726
+ const ov = new DataView(out.buffer);
727
+ ov.setUint32(0, a0 >>> 0, true);
728
+ ov.setUint32(4, b0 >>> 0, true);
729
+ ov.setUint32(8, c0 >>> 0, true);
730
+ ov.setUint32(12, d0 >>> 0, true);
731
+ return out;
732
+ }
733
+ function rc4(key, data) {
734
+ const S = new Uint8Array(256);
735
+ for (let i2 = 0; i2 < 256; i2++) S[i2] = i2;
736
+ let j = 0;
737
+ for (let i2 = 0; i2 < 256; i2++) {
738
+ j = j + S[i2] + key[i2 % key.length] & 255;
739
+ const t = S[i2];
740
+ S[i2] = S[j];
741
+ S[j] = t;
742
+ }
743
+ const out = new Uint8Array(data.length);
744
+ let i = 0;
745
+ j = 0;
746
+ for (let k = 0; k < data.length; k++) {
747
+ i = i + 1 & 255;
748
+ j = j + S[i] & 255;
749
+ const t = S[i];
750
+ S[i] = S[j];
751
+ S[j] = t;
752
+ out[k] = data[k] ^ S[S[i] + S[j] & 255];
753
+ }
754
+ return out;
755
+ }
756
+ function getSubtle() {
757
+ const subtle = globalThis.crypto?.subtle;
758
+ if (!subtle) throw new UnsupportedPdfEncryptionError("WebCrypto is unavailable in this environment");
759
+ return subtle;
760
+ }
761
+ async function sha2(algorithm, data) {
762
+ return new Uint8Array(await getSubtle().digest(algorithm, data));
763
+ }
764
+ async function importAesKey(rawKey, usages) {
765
+ return getSubtle().importKey("raw", rawKey, "AES-CBC", false, usages);
766
+ }
767
+ async function aesCbcEncryptNoPad(rawKey, iv, data) {
768
+ const key = await importAesKey(rawKey, ["encrypt"]);
769
+ const out = new Uint8Array(await getSubtle().encrypt({ name: "AES-CBC", iv }, key, data));
770
+ return out.slice(0, data.length);
771
+ }
772
+ async function aesCbcDecryptNoPad(rawKey, iv, data) {
773
+ const key = await importAesKey(rawKey, ["encrypt", "decrypt"]);
774
+ const lastBlock = data.slice(data.length - 16);
775
+ const padBlock = new Uint8Array(
776
+ await getSubtle().encrypt({ name: "AES-CBC", iv: lastBlock }, key, new Uint8Array(0))
777
+ );
778
+ const joined = concatBytes(data, padBlock);
779
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, joined));
780
+ }
781
+ async function aesDecryptPdfData(rawKey, data) {
782
+ if (data.length < 32) return new Uint8Array(0);
783
+ const iv = data.slice(0, 16);
784
+ let ct = data.slice(16);
785
+ if (ct.length % 16 !== 0) ct = ct.slice(0, ct.length - ct.length % 16);
786
+ try {
787
+ const key = await importAesKey(rawKey, ["decrypt"]);
788
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, ct));
789
+ } catch {
790
+ const plain = await aesCbcDecryptNoPad(rawKey, iv, ct);
791
+ const padLen = plain[plain.length - 1];
792
+ return padLen >= 1 && padLen <= 16 ? plain.slice(0, plain.length - padLen) : plain;
793
+ }
794
+ }
795
+ var PAD = new Uint8Array([
796
+ 40,
797
+ 191,
798
+ 78,
799
+ 94,
800
+ 78,
801
+ 117,
802
+ 138,
803
+ 65,
804
+ 100,
805
+ 0,
806
+ 78,
807
+ 86,
808
+ 255,
809
+ 250,
810
+ 1,
811
+ 8,
812
+ 46,
813
+ 46,
814
+ 0,
815
+ 182,
816
+ 208,
817
+ 104,
818
+ 62,
819
+ 128,
820
+ 47,
821
+ 12,
822
+ 169,
823
+ 254,
824
+ 100,
825
+ 83,
826
+ 105,
827
+ 122
828
+ ]);
829
+ var bytesEqual = (a, b) => {
830
+ if (a.length !== b.length) return false;
831
+ let diff = 0;
832
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
833
+ return diff === 0;
834
+ };
835
+ function legacyFileKey(paddedPwd, params) {
836
+ const { revision, keyLen, O, P, id0, encryptMetadata } = params;
837
+ const pBytes = new Uint8Array(4);
838
+ new DataView(pBytes.buffer).setInt32(0, P | 0, true);
839
+ const parts = [paddedPwd, O.slice(0, 32), pBytes, id0];
840
+ if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([255, 255, 255, 255]));
841
+ let h = md5(concatBytes(...parts));
842
+ if (revision >= 3) for (let i = 0; i < 50; i++) h = md5(h.slice(0, keyLen));
843
+ return h.slice(0, keyLen);
844
+ }
845
+ function legacyComputeU(fileKey, revision, id0) {
846
+ if (revision === 2) return rc4(fileKey, PAD);
847
+ let d = md5(concatBytes(PAD, id0));
848
+ d = rc4(fileKey, d);
849
+ for (let i = 1; i <= 19; i++) d = rc4(fileKey.map((b) => b ^ i), d);
850
+ return d;
851
+ }
852
+ function legacyUMatches(fileKey, params) {
853
+ const computed = legacyComputeU(fileKey, params.revision, params.id0);
854
+ return params.revision === 2 ? bytesEqual(computed, params.U.slice(0, 32)) : bytesEqual(computed.slice(0, 16), params.U.slice(0, 16));
855
+ }
856
+ function legacyAuthenticateEmptyPassword(params) {
857
+ const userKey = legacyFileKey(PAD, params);
858
+ if (legacyUMatches(userKey, params)) return userKey;
859
+ throw new PdfPasswordRequiredError();
860
+ }
861
+ async function hash2B(password, salt, udata) {
862
+ let k = await sha2("SHA-256", concatBytes(password, salt, udata));
863
+ let e = new Uint8Array(0);
864
+ let i = 0;
865
+ do {
866
+ const block = concatBytes(password, k, udata);
867
+ const k1 = new Uint8Array(block.length * 64);
868
+ for (let rep = 0; rep < 64; rep++) k1.set(block, rep * block.length);
869
+ e = await aesCbcEncryptNoPad(k.slice(0, 16), k.slice(16, 32), k1);
870
+ let sum = 0;
871
+ for (let b = 0; b < 16; b++) sum += e[b];
872
+ const mod = sum % 3;
873
+ k = await sha2(mod === 0 ? "SHA-256" : mod === 1 ? "SHA-384" : "SHA-512", e);
874
+ i++;
875
+ } while (i < 64 || e[e.length - 1] > i - 32);
876
+ return k.slice(0, 32);
877
+ }
878
+ async function v5AuthenticateEmptyPassword(revision, U, UE) {
879
+ const pwd = new Uint8Array(0);
880
+ const zeroIv = new Uint8Array(16);
881
+ const hash = async (salt, udata) => revision === 5 ? sha2("SHA-256", concatBytes(pwd, salt, udata)) : hash2B(pwd, salt, udata);
882
+ const userHash = await hash(U.slice(32, 40), new Uint8Array(0));
883
+ if (bytesEqual(userHash, U.slice(0, 32))) {
884
+ const intermediate = await hash(U.slice(40, 48), new Uint8Array(0));
885
+ return aesCbcDecryptNoPad(intermediate, zeroIv, UE.slice(0, 32));
886
+ }
887
+ throw new PdfPasswordRequiredError();
888
+ }
889
+ var identityCipher = async (data) => data;
890
+ function rc4ObjectCipher(fileKey) {
891
+ return async (data, ref) => {
892
+ const ext = new Uint8Array([
893
+ ref.objectNumber & 255,
894
+ ref.objectNumber >> 8 & 255,
895
+ ref.objectNumber >> 16 & 255,
896
+ ref.generationNumber & 255,
897
+ ref.generationNumber >> 8 & 255
898
+ ]);
899
+ const key = md5(concatBytes(fileKey, ext)).slice(0, Math.min(fileKey.length + 5, 16));
900
+ return rc4(key, data);
901
+ };
902
+ }
903
+ var AES_SALT = new Uint8Array([115, 65, 108, 84]);
904
+ function aes128ObjectCipher(fileKey) {
905
+ return async (data, ref) => {
906
+ const ext = new Uint8Array([
907
+ ref.objectNumber & 255,
908
+ ref.objectNumber >> 8 & 255,
909
+ ref.objectNumber >> 16 & 255,
910
+ ref.generationNumber & 255,
911
+ ref.generationNumber >> 8 & 255
912
+ ]);
913
+ const key = md5(concatBytes(fileKey, ext, AES_SALT)).slice(0, 16);
914
+ return aesDecryptPdfData(key, data);
915
+ };
916
+ }
917
+ function aes256ObjectCipher(fileKey) {
918
+ return async (data) => aesDecryptPdfData(fileKey, data);
919
+ }
920
+ function dictNumber(dict, key) {
921
+ const value = dict.lookup(pdfLib.PDFName.of(key));
922
+ return value instanceof pdfLib.PDFNumber ? value.asNumber() : void 0;
923
+ }
924
+ function dictBytes(dict, key) {
925
+ const value = dict.lookup(pdfLib.PDFName.of(key));
926
+ return value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString ? value.asBytes() : void 0;
927
+ }
928
+ async function buildDocumentCiphers(encDict, id0) {
929
+ const filter = encDict.lookup(pdfLib.PDFName.of("Filter"));
930
+ if (filter !== pdfLib.PDFName.of("Standard")) {
931
+ throw new UnsupportedPdfEncryptionError(`security handler ${String(filter)}`);
932
+ }
933
+ const V = dictNumber(encDict, "V") ?? 0;
934
+ const R = dictNumber(encDict, "R") ?? 0;
935
+ const O = dictBytes(encDict, "O");
936
+ const U = dictBytes(encDict, "U");
937
+ const P = dictNumber(encDict, "P") ?? -1;
938
+ const metadataValue = encDict.lookup(pdfLib.PDFName.of("EncryptMetadata"));
939
+ const encryptMetadata = metadataValue instanceof pdfLib.PDFBool ? metadataValue.asBoolean() : true;
940
+ if (!O || !U) throw new UnsupportedPdfEncryptionError("missing /O or /U");
941
+ if (V === 1 || V === 2) {
942
+ const keyLen = V === 1 ? 5 : (dictNumber(encDict, "Length") ?? 40) / 8;
943
+ const fileKey = legacyAuthenticateEmptyPassword({ revision: R, keyLen, O, U, P, id0, encryptMetadata });
944
+ const cipher = rc4ObjectCipher(fileKey);
945
+ return { stringCipher: cipher, streamCipher: cipher, encryptMetadata };
946
+ }
947
+ if (V === 4 || V === 5) {
948
+ const cf = encDict.lookup(pdfLib.PDFName.of("CF"));
949
+ const cfmOf = (filterKey) => {
950
+ const streamFilter = encDict.lookup(pdfLib.PDFName.of(filterKey));
951
+ if (!(streamFilter instanceof pdfLib.PDFName) || streamFilter === pdfLib.PDFName.of("Identity")) return void 0;
952
+ if (!(cf instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError("missing /CF");
953
+ const cfDict = cf.lookup(streamFilter);
954
+ if (!(cfDict instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError(`missing crypt filter ${streamFilter.toString()}`);
955
+ const cfm = cfDict.lookup(pdfLib.PDFName.of("CFM"));
956
+ return cfm instanceof pdfLib.PDFName ? cfm : void 0;
957
+ };
958
+ let fileKey;
959
+ if (V === 5) {
960
+ const UE = dictBytes(encDict, "UE");
961
+ if (!UE) throw new UnsupportedPdfEncryptionError("missing /UE");
962
+ fileKey = await v5AuthenticateEmptyPassword(R, U, UE);
963
+ } else {
964
+ const cryptFilterLengthBits = () => {
965
+ if (!(cf instanceof pdfLib.PDFDict)) return void 0;
966
+ for (const filterKey of ["StmF", "StrF"]) {
967
+ const filter2 = encDict.lookup(pdfLib.PDFName.of(filterKey));
968
+ if (!(filter2 instanceof pdfLib.PDFName) || filter2 === pdfLib.PDFName.of("Identity")) continue;
969
+ const cfDict = cf.lookup(filter2);
970
+ if (!(cfDict instanceof pdfLib.PDFDict)) continue;
971
+ const len = dictNumber(cfDict, "Length");
972
+ if (len === void 0) continue;
973
+ return len < 40 ? len * 8 : len;
974
+ }
975
+ return void 0;
976
+ };
977
+ const keyLenBits = cryptFilterLengthBits() ?? dictNumber(encDict, "Length") ?? 128;
978
+ fileKey = legacyAuthenticateEmptyPassword({
979
+ revision: R,
980
+ keyLen: keyLenBits / 8,
981
+ O,
982
+ U,
983
+ P,
984
+ id0,
985
+ encryptMetadata
986
+ });
987
+ }
988
+ const cipherFor = (cfm) => {
989
+ if (!cfm || cfm === pdfLib.PDFName.of("Identity")) return identityCipher;
990
+ if (cfm === pdfLib.PDFName.of("V2")) return rc4ObjectCipher(fileKey);
991
+ if (cfm === pdfLib.PDFName.of("AESV2")) return aes128ObjectCipher(fileKey);
992
+ if (cfm === pdfLib.PDFName.of("AESV3")) return aes256ObjectCipher(fileKey);
993
+ throw new UnsupportedPdfEncryptionError(`crypt filter method ${cfm.toString()}`);
994
+ };
995
+ return {
996
+ streamCipher: cipherFor(cfmOf("StmF")),
997
+ stringCipher: cipherFor(cfmOf("StrF")),
998
+ encryptMetadata
999
+ };
1000
+ }
1001
+ throw new UnsupportedPdfEncryptionError(`/V ${V}`);
1002
+ }
1003
+ var toHexString = (bytes) => {
1004
+ let hex = "";
1005
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
1006
+ return new pdfLib.PDFHexString(hex.toUpperCase());
1007
+ };
1008
+ function filterIncludesCrypt(dict) {
1009
+ const filter = dict.lookup(pdfLib.PDFName.of("Filter"));
1010
+ if (filter === pdfLib.PDFName.of("Crypt")) return true;
1011
+ if (filter instanceof pdfLib.PDFArray) {
1012
+ for (let i = 0; i < filter.size(); i++) {
1013
+ if (filter.get(i) === pdfLib.PDFName.of("Crypt")) return true;
1014
+ }
1015
+ }
1016
+ return false;
1017
+ }
1018
+ function cryptFilterIsIdentity(dict) {
1019
+ const parms = dict.lookup(pdfLib.PDFName.of("DecodeParms")) ?? dict.lookup(pdfLib.PDFName.of("DP"));
1020
+ const identityParms = (p) => {
1021
+ if (!(p instanceof pdfLib.PDFDict)) return true;
1022
+ const name = p.lookup(pdfLib.PDFName.of("Name"));
1023
+ return !(name instanceof pdfLib.PDFName) || name === pdfLib.PDFName.of("Identity");
1024
+ };
1025
+ if (parms instanceof pdfLib.PDFArray) {
1026
+ for (let i = 0; i < parms.size(); i++) {
1027
+ if (!identityParms(parms.lookup(i))) return false;
1028
+ }
1029
+ return true;
1030
+ }
1031
+ return identityParms(parms);
1032
+ }
1033
+ async function decryptStringsWithin(obj, ref, stringCipher) {
1034
+ if (obj instanceof pdfLib.PDFDict) {
1035
+ const isSignature = obj.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("Sig");
1036
+ for (const [key, value] of obj.entries()) {
1037
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1038
+ if (isSignature && key === pdfLib.PDFName.of("Contents")) continue;
1039
+ obj.set(key, toHexString(await stringCipher(value.asBytes(), ref)));
1040
+ } else {
1041
+ await decryptStringsWithin(value, ref, stringCipher);
1042
+ }
1043
+ }
1044
+ } else if (obj instanceof pdfLib.PDFArray) {
1045
+ for (let i = 0; i < obj.size(); i++) {
1046
+ const value = obj.get(i);
1047
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1048
+ obj.set(i, toHexString(await stringCipher(value.asBytes(), ref)));
1049
+ } else {
1050
+ await decryptStringsWithin(value, ref, stringCipher);
1051
+ }
1052
+ }
1053
+ }
1054
+ }
1055
+ async function decryptLoadedDocument(doc) {
1056
+ const context = doc.context;
1057
+ const encryptRef = context.trailerInfo.Encrypt;
1058
+ const encDict = context.lookup(encryptRef);
1059
+ if (!(encDict instanceof pdfLib.PDFDict)) {
1060
+ throw new UnsupportedPdfEncryptionError("malformed /Encrypt dictionary");
1061
+ }
1062
+ const idArray = context.lookup(context.trailerInfo.ID);
1063
+ const idFirst = idArray instanceof pdfLib.PDFArray ? idArray.get(0) : void 0;
1064
+ const id0 = idFirst instanceof pdfLib.PDFString || idFirst instanceof pdfLib.PDFHexString ? idFirst.asBytes() : new Uint8Array(0);
1065
+ const { stringCipher, streamCipher, encryptMetadata } = await buildDocumentCiphers(encDict, id0);
1066
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1067
+ if (!(obj instanceof pdfLib.PDFInvalidObject)) continue;
1068
+ const raw = new Uint8Array(obj.sizeInBytes());
1069
+ obj.copyBytesInto(raw, 0);
1070
+ try {
1071
+ const parsed = pdfLib.PDFObjectParser.forBytes(raw, context).parseObject();
1072
+ if (parsed instanceof pdfLib.PDFRawStream && parsed.dict.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("ObjStm")) {
1073
+ context.assign(ref, parsed);
1074
+ }
1075
+ } catch {
1076
+ }
1077
+ }
1078
+ const decryptedObjectStreams = [];
1079
+ const structuralStreamRefs = [];
1080
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1081
+ if (ref === encryptRef || obj === encDict) continue;
1082
+ if (obj instanceof pdfLib.PDFRawStream) {
1083
+ const type = obj.dict.lookup(pdfLib.PDFName.of("Type"));
1084
+ if (type === pdfLib.PDFName.of("XRef")) {
1085
+ structuralStreamRefs.push(ref);
1086
+ continue;
1087
+ }
1088
+ const isSkippedMetadata = !encryptMetadata && type === pdfLib.PDFName.of("Metadata");
1089
+ if (filterIncludesCrypt(obj.dict)) {
1090
+ if (!cryptFilterIsIdentity(obj.dict)) {
1091
+ throw new UnsupportedPdfEncryptionError("stream-specific /Crypt filter");
1092
+ }
1093
+ } else if (!isSkippedMetadata) {
1094
+ const decrypted = await streamCipher(obj.contents, ref);
1095
+ const replacement = pdfLib.PDFRawStream.of(obj.dict, decrypted);
1096
+ context.assign(ref, replacement);
1097
+ if (type === pdfLib.PDFName.of("ObjStm")) {
1098
+ decryptedObjectStreams.push([ref, replacement]);
1099
+ }
1100
+ }
1101
+ await decryptStringsWithin(obj.dict, ref, stringCipher);
1102
+ } else if (obj instanceof pdfLib.PDFString || obj instanceof pdfLib.PDFHexString) {
1103
+ context.assign(ref, toHexString(await stringCipher(obj.asBytes(), ref)));
1104
+ } else {
1105
+ await decryptStringsWithin(obj, ref, stringCipher);
1106
+ }
1107
+ }
1108
+ for (const [ref, stream] of decryptedObjectStreams) {
1109
+ await pdfLib.PDFObjectStreamParser.forStream(stream).parseIntoContext();
1110
+ context.delete(ref);
1111
+ }
1112
+ for (const ref of structuralStreamRefs) context.delete(ref);
1113
+ delete context.trailerInfo.Encrypt;
1114
+ if (encryptRef instanceof pdfLib.PDFRef) context.delete(encryptRef);
1115
+ return doc.save({
1116
+ useObjectStreams: false,
1117
+ addDefaultPage: false,
1118
+ updateFieldAppearances: false
1119
+ });
1120
+ }
1121
+ async function decryptPdf(pdfBytes) {
1122
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1123
+ ignoreEncryption: true,
1124
+ updateMetadata: false
1125
+ });
1126
+ if (!doc.isEncrypted) return pdfBytes;
1127
+ return decryptLoadedDocument(doc);
1128
+ }
1129
+ var SLASH = 47;
1130
+ var HASH = 35;
1131
+ var ENCRYPT_NAME = "Encrypt";
1132
+ function hexDigit(byte) {
1133
+ if (byte === void 0) return -1;
1134
+ if (byte >= 48 && byte <= 57) return byte - 48;
1135
+ if (byte >= 65 && byte <= 70) return byte - 65 + 10;
1136
+ if (byte >= 97 && byte <= 102) return byte - 97 + 10;
1137
+ return -1;
1138
+ }
1139
+ function matchesEncryptNameAt(bytes, start) {
1140
+ let at = start;
1141
+ for (let k = 0; k < ENCRYPT_NAME.length; k++) {
1142
+ const want = ENCRYPT_NAME.charCodeAt(k);
1143
+ const byte = bytes[at];
1144
+ if (byte === want) {
1145
+ at += 1;
1146
+ continue;
1147
+ }
1148
+ if (byte === HASH) {
1149
+ const high = hexDigit(bytes[at + 1]);
1150
+ const low = hexDigit(bytes[at + 2]);
1151
+ if (high >= 0 && low >= 0 && (high << 4 | low) === want) {
1152
+ at += 3;
1153
+ continue;
1154
+ }
1155
+ }
1156
+ return false;
1157
+ }
1158
+ return true;
1159
+ }
1160
+ function containsEncryptMarker(bytes) {
1161
+ for (let i = 0; i < bytes.length; i++) {
1162
+ if (bytes[i] !== SLASH) continue;
1163
+ if (matchesEncryptNameAt(bytes, i + 1)) return true;
1164
+ }
1165
+ return false;
1166
+ }
1167
+ async function normalizePdfEncryption(pdfBytes, options) {
1168
+ if (!containsEncryptMarker(pdfBytes)) return pdfBytes;
1169
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1170
+ ignoreEncryption: true,
1171
+ updateMetadata: false
1172
+ });
1173
+ if (!doc.isEncrypted) return pdfBytes;
1174
+ options?.logger?.info("[PDF_DECRYPT] Encrypted PDF detected during ingestion; decrypting");
1175
+ return decryptLoadedDocument(doc);
1176
+ }
1177
+
1178
+ // src/utils/pdf-decrypt.ts
1179
+ var PdfPasswordRequiredError2 = PdfPasswordRequiredError;
1180
+ var UnsupportedPdfEncryptionError2 = UnsupportedPdfEncryptionError;
1181
+ var decryptPdf2 = decryptPdf;
1182
+ var consoleLogger = {
1183
+ info(message, ...args) {
1184
+ if (typeof process === "undefined" || process.env?.NODE_ENV !== "production") {
1185
+ console.info(`[PageAssembler] ${message}`, ...args);
1186
+ }
1187
+ }
1188
+ };
1189
+ function normalizePdfEncryption2(pdfBytes) {
1190
+ return normalizePdfEncryption(pdfBytes, { logger: consoleLogger });
1191
+ }
1192
+
1193
+ // src/utils/pdf-helpers.ts
579
1194
  if (typeof window !== "undefined") {
580
1195
  pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
581
1196
  }
@@ -647,6 +1262,68 @@ async function pdfToImages(pdfBytes, options) {
647
1262
  throw error;
648
1263
  }
649
1264
  }
1265
+ var MAX_RASTER_PAGE_COUNT = 500;
1266
+ var MAX_RASTER_CANVAS_PIXELS = 4096 * 4096;
1267
+ var PREFERRED_RASTER_SCALE = 2;
1268
+ function computeRasterScale(width, height) {
1269
+ const area = width * height;
1270
+ if (!Number.isFinite(area) || area <= 0) return PREFERRED_RASTER_SCALE;
1271
+ const preferredPixels = area * PREFERRED_RASTER_SCALE * PREFERRED_RASTER_SCALE;
1272
+ if (preferredPixels <= MAX_RASTER_CANVAS_PIXELS) return PREFERRED_RASTER_SCALE;
1273
+ return Math.sqrt(MAX_RASTER_CANVAS_PIXELS / area);
1274
+ }
1275
+ async function rasterizePdfToPdf(pdfBytes) {
1276
+ if (typeof window !== "undefined") {
1277
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
1278
+ }
1279
+ let sourceDoc;
1280
+ try {
1281
+ sourceDoc = await pdfjsLib__namespace.getDocument({ data: pdfBytes.slice(0), verbosity: 0 }).promise;
1282
+ } catch (error) {
1283
+ if (error?.name === "PasswordException") {
1284
+ throw new PdfPasswordRequiredError2();
1285
+ }
1286
+ throw error;
1287
+ }
1288
+ try {
1289
+ if (sourceDoc.numPages > MAX_RASTER_PAGE_COUNT) {
1290
+ throw new Error(
1291
+ `Cannot rebuild PDF: ${sourceDoc.numPages} pages exceeds the ${MAX_RASTER_PAGE_COUNT}-page limit`
1292
+ );
1293
+ }
1294
+ const outDoc = await pdfLib.PDFDocument.create();
1295
+ for (let pageNum = 1; pageNum <= sourceDoc.numPages; pageNum++) {
1296
+ const page = await sourceDoc.getPage(pageNum);
1297
+ const base = page.getViewport({ scale: 1 });
1298
+ const scale = computeRasterScale(base.width, base.height);
1299
+ const viewport = page.getViewport({ scale });
1300
+ const canvas = document.createElement("canvas");
1301
+ canvas.width = viewport.width;
1302
+ canvas.height = viewport.height;
1303
+ const context = canvas.getContext("2d");
1304
+ await page.render({ canvasContext: context, viewport }).promise;
1305
+ const png = await outDoc.embedPng(canvas.toDataURL("image/png"));
1306
+ const outPage = outDoc.addPage([base.width, base.height]);
1307
+ outPage.drawImage(png, { x: 0, y: 0, width: base.width, height: base.height });
1308
+ }
1309
+ return new Uint8Array(await outDoc.save({ useObjectStreams: false }));
1310
+ } finally {
1311
+ await sourceDoc.destroy();
1312
+ }
1313
+ }
1314
+ async function normalizeUploadedPdfBytes(pdfBytes) {
1315
+ try {
1316
+ const normalized = await normalizePdfEncryption2(pdfBytes);
1317
+ return normalized === pdfBytes ? pdfBytes : new Uint8Array(normalized);
1318
+ } catch (error) {
1319
+ if (error instanceof PdfPasswordRequiredError2) throw error;
1320
+ console.warn(
1321
+ "[PageAssembler] Structural decryption failed; rebuilding document from rendered pages:",
1322
+ error
1323
+ );
1324
+ return rasterizePdfToPdf(pdfBytes);
1325
+ }
1326
+ }
650
1327
  async function imageToPdf(imageFile) {
651
1328
  return new Promise((resolve, reject) => {
652
1329
  const img = new Image();
@@ -722,6 +1399,573 @@ function downloadPdf(pdfBytes, filename) {
722
1399
  a.click();
723
1400
  URL.revokeObjectURL(url);
724
1401
  }
1402
+ function getSigniphiMetadata(pdfDoc) {
1403
+ try {
1404
+ const infoRef = pdfDoc.context.trailerInfo.Info;
1405
+ if (!infoRef) {
1406
+ return null;
1407
+ }
1408
+ const infoObj = pdfDoc.context.lookup(infoRef);
1409
+ if (!infoObj || typeof infoObj.get !== "function") {
1410
+ return null;
1411
+ }
1412
+ const infoDict = infoObj;
1413
+ const metadataObj = infoDict.get(pdfLib.PDFName.of("SigniphiMetadata"));
1414
+ if (!metadataObj) {
1415
+ return null;
1416
+ }
1417
+ const metadataStr = metadataObj.toString();
1418
+ let jsonStr = metadataStr;
1419
+ if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
1420
+ jsonStr = metadataStr.slice(1, -1);
1421
+ } else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
1422
+ jsonStr = metadataStr.slice(1, -1);
1423
+ }
1424
+ const metadata = JSON.parse(jsonStr);
1425
+ return metadata;
1426
+ } catch (error) {
1427
+ console.error("Failed to load Signiphi metadata:", error);
1428
+ return null;
1429
+ }
1430
+ }
1431
+ function getBaseFieldName(encodedName) {
1432
+ let baseName = encodedName;
1433
+ if (baseName.includes("__SIGNER__")) {
1434
+ baseName = baseName.split("__SIGNER__")[0];
1435
+ }
1436
+ if (baseName.includes("__LABEL__")) {
1437
+ baseName = baseName.split("__LABEL__")[0];
1438
+ }
1439
+ if (baseName.includes("__PLACEHOLDER__")) {
1440
+ baseName = baseName.split("__PLACEHOLDER__")[0];
1441
+ }
1442
+ return baseName;
1443
+ }
1444
+ function getSignerFromFieldName(encodedName) {
1445
+ if (encodedName.includes("__SIGNER__")) {
1446
+ const parts = encodedName.split("__SIGNER__");
1447
+ if (parts[1]) {
1448
+ return parts[1].split("__")[0] || parts[1];
1449
+ }
1450
+ }
1451
+ return void 0;
1452
+ }
1453
+ function determineFieldType(fieldName, widgetType) {
1454
+ const baseName = getBaseFieldName(fieldName);
1455
+ const nameLower = baseName.toLowerCase();
1456
+ if (nameLower.includes("_signature") || nameLower.includes("signature")) {
1457
+ return "signature";
1458
+ }
1459
+ if (nameLower.includes("_initials") || nameLower.includes("initials")) {
1460
+ return "initials";
1461
+ }
1462
+ if (nameLower.includes("_date") || nameLower.includes("date")) {
1463
+ return "date";
1464
+ }
1465
+ if (widgetType === "checkbox" || nameLower.includes("checkbox")) {
1466
+ return "checkbox";
1467
+ }
1468
+ if (widgetType === "radio" || nameLower.includes("radio")) {
1469
+ return "radio";
1470
+ }
1471
+ if (widgetType === "dropdown" || widgetType === "select" || nameLower.includes("dropdown")) {
1472
+ return "dropdown";
1473
+ }
1474
+ return "text";
1475
+ }
1476
+ async function extractFieldsFromPdf(pdfBytes) {
1477
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1478
+ const fields = [];
1479
+ const metadata = getSigniphiMetadata(pdfDoc);
1480
+ const form = pdfDoc.getForm();
1481
+ const pdfFields = form.getFields();
1482
+ for (const field of pdfFields) {
1483
+ const fieldName = field.getName();
1484
+ const widgets = field.acroField.getWidgets();
1485
+ const baseName = getBaseFieldName(fieldName);
1486
+ const signerFromName = getSignerFromFieldName(fieldName);
1487
+ let required = false;
1488
+ let options;
1489
+ let widgetType;
1490
+ if (field instanceof pdfLib.PDFTextField) {
1491
+ required = field.isRequired();
1492
+ console.log(`[field-extraction] PDFTextField "${fieldName}" isRequired=${required}`);
1493
+ } else if (field instanceof pdfLib.PDFCheckBox) {
1494
+ widgetType = "checkbox";
1495
+ required = field.isRequired();
1496
+ console.log(`[field-extraction] PDFCheckBox "${fieldName}" isRequired=${required}`);
1497
+ } else if (field instanceof pdfLib.PDFDropdown) {
1498
+ widgetType = "dropdown";
1499
+ required = field.isRequired();
1500
+ options = field.getOptions();
1501
+ console.log(`[field-extraction] PDFDropdown "${fieldName}" isRequired=${required}`);
1502
+ } else if (field instanceof pdfLib.PDFRadioGroup) {
1503
+ widgetType = "radio";
1504
+ required = field.isRequired();
1505
+ options = field.getOptions();
1506
+ console.log(`[field-extraction] PDFRadioGroup "${fieldName}" isRequired=${required}`);
1507
+ } else {
1508
+ console.log(`[field-extraction] Unknown field type "${fieldName}" - defaulting required=false`);
1509
+ }
1510
+ for (const widget of widgets) {
1511
+ const rect = widget.getRectangle();
1512
+ const pageRef = widget.P();
1513
+ let pageNumber = 1;
1514
+ if (pageRef) {
1515
+ const pages = pdfDoc.getPages();
1516
+ for (let i = 0; i < pages.length; i++) {
1517
+ if (pages[i].ref === pageRef) {
1518
+ pageNumber = i + 1;
1519
+ break;
1520
+ }
1521
+ }
1522
+ }
1523
+ const pageQualifiedKey = `${baseName}_p${pageNumber}`;
1524
+ let fieldMetadata = metadata?.fields?.[pageQualifiedKey];
1525
+ if (!fieldMetadata) {
1526
+ fieldMetadata = metadata?.fields?.[fieldName];
1527
+ }
1528
+ if (!fieldMetadata && baseName !== fieldName) {
1529
+ fieldMetadata = metadata?.fields?.[baseName];
1530
+ }
1531
+ let fieldRequired = required;
1532
+ let fieldOptions = options;
1533
+ if (fieldMetadata?.required !== void 0) {
1534
+ fieldRequired = fieldMetadata.required;
1535
+ }
1536
+ if (fieldMetadata?.options?.length) {
1537
+ fieldOptions = fieldMetadata.options;
1538
+ }
1539
+ const page = pdfDoc.getPage(pageNumber - 1);
1540
+ const pageHeight = page.getHeight();
1541
+ const extractedField = {
1542
+ name: baseName,
1543
+ // Use clean base name without __SIGNER__ encoding (signer stored in signer property)
1544
+ type: determineFieldType(fieldName, widgetType),
1545
+ // Uses base name internally
1546
+ page: pageNumber,
1547
+ x: rect.x,
1548
+ y: pageHeight - rect.y - rect.height,
1549
+ // Convert from PDF coords (bottom-left) to top-left
1550
+ width: rect.width,
1551
+ height: rect.height,
1552
+ required: fieldRequired,
1553
+ options: fieldOptions,
1554
+ signer: signerFromName
1555
+ // Extract signer from encoded name
1556
+ };
1557
+ if (fieldMetadata) {
1558
+ if (fieldMetadata.fieldId) {
1559
+ extractedField.fieldId = fieldMetadata.fieldId;
1560
+ }
1561
+ if (fieldMetadata.label) {
1562
+ extractedField.label = fieldMetadata.label;
1563
+ }
1564
+ if (!extractedField.signer && fieldMetadata.signer) {
1565
+ extractedField.signer = fieldMetadata.signer;
1566
+ }
1567
+ if (fieldMetadata.placeholder) {
1568
+ extractedField.placeholder = fieldMetadata.placeholder;
1569
+ }
1570
+ }
1571
+ fields.push(extractedField);
1572
+ }
1573
+ }
1574
+ const deduplicatedFields = fields.reduce((acc, field) => {
1575
+ const newBaseName = getBaseFieldName(field.name);
1576
+ const existingIndex = acc.findIndex((f) => {
1577
+ const existingBaseName = getBaseFieldName(f.name);
1578
+ return existingBaseName === newBaseName && f.page === field.page;
1579
+ });
1580
+ if (existingIndex === -1) {
1581
+ acc.push(field);
1582
+ } else {
1583
+ const existing = acc[existingIndex];
1584
+ acc[existingIndex] = {
1585
+ ...existing,
1586
+ // Prefer non-empty values from either field
1587
+ label: existing.label || field.label,
1588
+ placeholder: existing.placeholder || field.placeholder,
1589
+ required: existing.required || field.required,
1590
+ options: existing.options?.length ? existing.options : field.options,
1591
+ fieldId: existing.fieldId || field.fieldId,
1592
+ // Prefer signer from the field that has it
1593
+ signer: existing.signer || field.signer
1594
+ };
1595
+ }
1596
+ return acc;
1597
+ }, []);
1598
+ return deduplicatedFields;
1599
+ }
1600
+ function setSigniphiMetadata(pdfDoc, metadata) {
1601
+ try {
1602
+ const infoRef = pdfDoc.context.trailerInfo.Info;
1603
+ const infoObj = pdfDoc.context.lookup(infoRef);
1604
+ if (!infoObj || typeof infoObj.set !== "function") {
1605
+ throw new Error("Info object is not a PDFDict or does not have set method");
1606
+ }
1607
+ const infoDict = infoObj;
1608
+ const metadataString = JSON.stringify(metadata);
1609
+ infoDict.set(pdfLib.PDFName.of("SigniphiMetadata"), pdfLib.PDFString.of(metadataString));
1610
+ } catch (error) {
1611
+ console.error("Failed to set Signiphi metadata:", error);
1612
+ throw error;
1613
+ }
1614
+ }
1615
+ var FormFieldType = /* @__PURE__ */ ((FormFieldType2) => {
1616
+ FormFieldType2["TEXT"] = "text";
1617
+ FormFieldType2["SIGNATURE"] = "signature";
1618
+ FormFieldType2["INITIALS"] = "initials";
1619
+ FormFieldType2["DATE"] = "date";
1620
+ FormFieldType2["CHECKBOX"] = "checkbox";
1621
+ FormFieldType2["RADIO"] = "radio";
1622
+ FormFieldType2["DROPDOWN"] = "dropdown";
1623
+ FormFieldType2["TEXT_LABEL"] = "text_label";
1624
+ return FormFieldType2;
1625
+ })(FormFieldType || {});
1626
+ function parseEncodedFieldName(encodedName) {
1627
+ let baseName = encodedName;
1628
+ let label;
1629
+ let signer;
1630
+ if (baseName.includes("__SIGNER__")) {
1631
+ const parts = baseName.split("__SIGNER__");
1632
+ baseName = parts[0];
1633
+ signer = parts[1];
1634
+ }
1635
+ if (baseName.includes("__LABEL__")) {
1636
+ const parts = baseName.split("__LABEL__");
1637
+ baseName = parts[0];
1638
+ label = parts[1];
1639
+ }
1640
+ if (baseName.includes("__PLACEHOLDER__")) {
1641
+ const parts = baseName.split("__PLACEHOLDER__");
1642
+ baseName = parts[0];
1643
+ }
1644
+ return { baseName, label, signer };
1645
+ }
1646
+ function encodeFieldNameWithSigner(fieldName, signerEmail) {
1647
+ const { baseName, signer: existingSigner } = parseEncodedFieldName(fieldName);
1648
+ const finalSigner = existingSigner || signerEmail;
1649
+ if (!finalSigner) return baseName;
1650
+ return `${baseName}__SIGNER__${finalSigner}`;
1651
+ }
1652
+ function encodeFieldNameWithLabelAndSigner(fieldName, label, signerEmail) {
1653
+ const { baseName, label: existingLabel, signer: existingSigner } = parseEncodedFieldName(fieldName);
1654
+ const finalLabel = existingLabel || label;
1655
+ const finalSigner = existingSigner || signerEmail;
1656
+ let name = baseName;
1657
+ if (finalLabel && finalLabel.trim()) {
1658
+ name = `${name}__LABEL__${finalLabel.trim()}`;
1659
+ }
1660
+ if (finalSigner) {
1661
+ name = `${name}__SIGNER__${finalSigner}`;
1662
+ }
1663
+ return name;
1664
+ }
1665
+ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
1666
+ const { removeExistingFields = false, drawLabels = false } = options;
1667
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1668
+ const form = pdfDoc.getForm();
1669
+ const pages = pdfDoc.getPages();
1670
+ if (removeExistingFields) {
1671
+ const existingFields = form.getFields();
1672
+ for (const field of existingFields) {
1673
+ try {
1674
+ const acroField = field.acroField;
1675
+ if (acroField && typeof acroField.getWidgets === "function") {
1676
+ let widgets = acroField.getWidgets();
1677
+ let safetyCounter = 0;
1678
+ const maxIterations = widgets.length + 5;
1679
+ while (widgets.length > 0 && safetyCounter < maxIterations) {
1680
+ try {
1681
+ acroField.removeWidget(widgets.length - 1);
1682
+ widgets = acroField.getWidgets();
1683
+ } catch {
1684
+ break;
1685
+ }
1686
+ safetyCounter++;
1687
+ }
1688
+ }
1689
+ form.removeField(field);
1690
+ } catch (error) {
1691
+ console.warn(`Failed to remove field ${field.getName()}:`, error);
1692
+ try {
1693
+ form.removeField(field);
1694
+ } catch {
1695
+ }
1696
+ }
1697
+ }
1698
+ }
1699
+ const font = await pdfDoc.embedFont(pdfLib.StandardFonts.Helvetica);
1700
+ const fieldNamePages = /* @__PURE__ */ new Map();
1701
+ for (const field of formFields) {
1702
+ const baseName = field.name;
1703
+ if (!fieldNamePages.has(baseName)) {
1704
+ fieldNamePages.set(baseName, /* @__PURE__ */ new Set());
1705
+ }
1706
+ fieldNamePages.get(baseName).add(field.position.page);
1707
+ }
1708
+ const conflictingNames = /* @__PURE__ */ new Set();
1709
+ for (const [name, pages2] of fieldNamePages) {
1710
+ if (pages2.size > 1) {
1711
+ conflictingNames.add(name);
1712
+ }
1713
+ }
1714
+ for (const field of formFields) {
1715
+ const pageIndex = field.position.page - 1;
1716
+ if (pageIndex < 0 || pageIndex >= pages.length) {
1717
+ console.warn(`Field ${field.name} references page ${field.position.page} but PDF only has ${pages.length} pages`);
1718
+ continue;
1719
+ }
1720
+ const page = pages[pageIndex];
1721
+ const { height: pageHeight } = page.getSize();
1722
+ const pdfX = field.position.x;
1723
+ const pdfY = pageHeight - field.position.y - field.position.height;
1724
+ const uniqueFieldName = conflictingNames.has(field.name) ? `${field.name}_p${field.position.page}` : field.name;
1725
+ try {
1726
+ const fieldType = typeof field.type === "string" ? field.type : field.type;
1727
+ switch (fieldType) {
1728
+ case "text" /* TEXT */: {
1729
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1730
+ const textField = form.createTextField(encodedName);
1731
+ textField.addToPage(page, {
1732
+ x: pdfX,
1733
+ y: pdfY,
1734
+ width: field.position.width,
1735
+ height: field.position.height,
1736
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1737
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1738
+ });
1739
+ if (field.label && field.label.trim()) {
1740
+ textField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1741
+ if (drawLabels) {
1742
+ const fontSize = Math.min(10, field.position.height * 0.4);
1743
+ const labelY = pdfY + field.position.height + 5;
1744
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1745
+ }
1746
+ }
1747
+ if (field.defaultValue && field.defaultValue.trim()) {
1748
+ textField.setText(field.defaultValue);
1749
+ }
1750
+ if (field.fontSize && field.fontSize >= 8 && field.fontSize <= 72) {
1751
+ try {
1752
+ textField.setFontSize(field.fontSize);
1753
+ } catch {
1754
+ }
1755
+ }
1756
+ if (field.multiline) {
1757
+ try {
1758
+ textField.enableMultiline();
1759
+ } catch {
1760
+ }
1761
+ }
1762
+ if (field.maxLength && field.maxLength > 0) {
1763
+ try {
1764
+ textField.setMaxLength(field.maxLength);
1765
+ } catch {
1766
+ }
1767
+ }
1768
+ if (field.required) {
1769
+ textField.enableRequired();
1770
+ }
1771
+ break;
1772
+ }
1773
+ case "checkbox" /* CHECKBOX */: {
1774
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1775
+ const checkBox = form.createCheckBox(encodedName);
1776
+ checkBox.addToPage(page, {
1777
+ x: pdfX,
1778
+ y: pdfY,
1779
+ width: field.position.width,
1780
+ height: field.position.height,
1781
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1782
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1783
+ });
1784
+ if (field.defaultValue === "true" || field.defaultValue === "checked") {
1785
+ checkBox.check();
1786
+ }
1787
+ if (field.required) {
1788
+ checkBox.enableRequired();
1789
+ }
1790
+ if (field.label && field.label.trim()) {
1791
+ try {
1792
+ checkBox.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1793
+ } catch {
1794
+ }
1795
+ if (drawLabels) {
1796
+ const fontSize = Math.min(12, field.position.height * 0.6);
1797
+ const labelX = pdfX + field.position.width + 5;
1798
+ const labelY = pdfY + (field.position.height - fontSize) / 2;
1799
+ page.drawText(field.label, { x: labelX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1800
+ }
1801
+ }
1802
+ break;
1803
+ }
1804
+ case "signature" /* SIGNATURE */: {
1805
+ const baseWithSuffix = field.name.endsWith("_signature") ? field.name : `${field.name}_signature`;
1806
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1807
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1808
+ const sigField = form.createTextField(encodedName);
1809
+ sigField.addToPage(page, {
1810
+ x: pdfX,
1811
+ y: pdfY,
1812
+ width: field.position.width,
1813
+ height: field.position.height,
1814
+ borderColor: pdfLib.rgb(0, 0, 1),
1815
+ backgroundColor: pdfLib.rgb(0.9, 0.9, 1)
1816
+ });
1817
+ if (field.label && field.label.trim()) {
1818
+ sigField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1819
+ }
1820
+ sigField.enableReadOnly();
1821
+ if (field.required) {
1822
+ sigField.enableRequired();
1823
+ }
1824
+ break;
1825
+ }
1826
+ case "initials" /* INITIALS */: {
1827
+ const baseWithSuffix = field.name.endsWith("_initials") ? field.name : `${field.name}_initials`;
1828
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1829
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1830
+ const initField = form.createTextField(encodedName);
1831
+ initField.addToPage(page, {
1832
+ x: pdfX,
1833
+ y: pdfY,
1834
+ width: field.position.width,
1835
+ height: field.position.height,
1836
+ borderColor: pdfLib.rgb(0.5, 0, 0.5),
1837
+ backgroundColor: pdfLib.rgb(1, 0.95, 1)
1838
+ });
1839
+ if (field.label && field.label.trim()) {
1840
+ initField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1841
+ }
1842
+ initField.enableReadOnly();
1843
+ if (field.required) {
1844
+ initField.enableRequired();
1845
+ }
1846
+ break;
1847
+ }
1848
+ case "date" /* DATE */: {
1849
+ const baseWithSuffix = field.name.endsWith("_date") ? field.name : `${field.name}_date`;
1850
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1851
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1852
+ const dateField = form.createTextField(encodedName);
1853
+ dateField.addToPage(page, {
1854
+ x: pdfX,
1855
+ y: pdfY,
1856
+ width: field.position.width,
1857
+ height: field.position.height,
1858
+ borderColor: pdfLib.rgb(0, 0.5, 0),
1859
+ backgroundColor: pdfLib.rgb(0.95, 1, 0.95)
1860
+ });
1861
+ if (field.label && field.label.trim()) {
1862
+ dateField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1863
+ }
1864
+ if (field.required) {
1865
+ dateField.enableRequired();
1866
+ }
1867
+ break;
1868
+ }
1869
+ case "dropdown" /* DROPDOWN */: {
1870
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1871
+ const dropdown = form.createDropdown(encodedName);
1872
+ dropdown.addToPage(page, {
1873
+ x: pdfX,
1874
+ y: pdfY,
1875
+ width: field.position.width,
1876
+ height: field.position.height,
1877
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1878
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1879
+ });
1880
+ if (field.options && field.options.length > 0) {
1881
+ dropdown.addOptions(field.options);
1882
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
1883
+ dropdown.select(field.defaultValue);
1884
+ }
1885
+ }
1886
+ if (field.label && field.label.trim()) {
1887
+ try {
1888
+ dropdown.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1889
+ } catch {
1890
+ }
1891
+ if (drawLabels) {
1892
+ const fontSize = Math.min(10, field.position.height * 0.4);
1893
+ const labelY = pdfY + field.position.height + 5;
1894
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1895
+ }
1896
+ }
1897
+ if (field.required) {
1898
+ dropdown.enableRequired();
1899
+ }
1900
+ break;
1901
+ }
1902
+ case "radio" /* RADIO */: {
1903
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1904
+ const radioGroup = form.createRadioGroup(encodedName);
1905
+ if (field.options && field.options.length > 0) {
1906
+ const optionHeight = Math.min(20, field.position.height / field.options.length);
1907
+ const spacing = field.position.height / field.options.length;
1908
+ field.options.forEach((option, index) => {
1909
+ const optionY = pdfY + field.position.height - (index + 1) * spacing + (spacing - optionHeight) / 2;
1910
+ radioGroup.addOptionToPage(option, page, {
1911
+ x: pdfX,
1912
+ y: optionY,
1913
+ width: optionHeight,
1914
+ height: optionHeight,
1915
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1916
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1917
+ });
1918
+ if (drawLabels) {
1919
+ const labelX = pdfX + optionHeight + 5;
1920
+ const labelY = optionY + optionHeight / 4;
1921
+ page.drawText(option, { x: labelX, y: labelY, size: 10, font, color: pdfLib.rgb(0, 0, 0) });
1922
+ }
1923
+ });
1924
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
1925
+ radioGroup.select(field.defaultValue);
1926
+ }
1927
+ }
1928
+ if (field.label && field.label.trim()) {
1929
+ try {
1930
+ radioGroup.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1931
+ } catch {
1932
+ }
1933
+ if (drawLabels) {
1934
+ const fontSize = 10;
1935
+ const labelY = pdfY + field.position.height + 5;
1936
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1937
+ }
1938
+ }
1939
+ if (field.required) {
1940
+ radioGroup.enableRequired();
1941
+ }
1942
+ break;
1943
+ }
1944
+ default:
1945
+ console.warn(`Unknown field type: ${fieldType} for field ${field.name}`);
1946
+ }
1947
+ } catch (error) {
1948
+ console.error(`Error adding field ${field.name}:`, error);
1949
+ }
1950
+ }
1951
+ return await pdfDoc.save();
1952
+ }
1953
+ function mapFieldPositionsAfterAssembly(fields, pageMapping) {
1954
+ return fields.map((field) => {
1955
+ const mappingKey = String(field.position.page - 1);
1956
+ const newPageNumber = pageMapping.get(mappingKey);
1957
+ if (newPageNumber !== void 0) {
1958
+ return {
1959
+ ...field,
1960
+ position: { ...field.position, page: newPageNumber }
1961
+ };
1962
+ }
1963
+ return field;
1964
+ }).filter((field) => {
1965
+ const mappingKey = String(field.position.page - 1);
1966
+ return pageMapping.has(mappingKey) || pageMapping.size === 0;
1967
+ });
1968
+ }
725
1969
  var isMultiSelectModifier = (event) => {
726
1970
  return event.ctrlKey || event.metaKey;
727
1971
  };
@@ -1118,6 +2362,7 @@ var FileCard = ({
1118
2362
  const [newName, setNewName] = React7.useState(file.name);
1119
2363
  const fileSelectedPages = file.pages.filter((p) => selectedPageIds.includes(p.id));
1120
2364
  const allPagesSelected = file.pages.length > 0 && fileSelectedPages.length === file.pages.length;
2365
+ const pendingDropdownAction = React7.useRef(null);
1121
2366
  const [{ isDraggingFile }, dragFile] = reactDnd.useDrag({
1122
2367
  type: DND_TYPES.FILE,
1123
2368
  item: () => {
@@ -1222,23 +2467,38 @@ var FileCard = ({
1222
2467
  ] }) }),
1223
2468
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
1224
2469
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "hover:bg-gray-100 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "h-4 w-4" }) }) }),
1225
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-52", children: [
1226
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onClick: () => setIsRenaming(true), children: [
1227
- /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-4 w-4 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
1228
- "Rename File"
1229
- ] }),
1230
- /* @__PURE__ */ jsxRuntime.jsxs(
1231
- DropdownMenuItem,
1232
- {
1233
- onClick: () => onRemoveFile(file.id),
1234
- className: "text-red-600 hover:text-red-700 hover:bg-red-50 focus:text-red-700 focus:bg-red-50",
1235
- children: [
1236
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
1237
- "Remove File"
1238
- ]
1239
- }
1240
- )
1241
- ] })
2470
+ /* @__PURE__ */ jsxRuntime.jsxs(
2471
+ DropdownMenuContent,
2472
+ {
2473
+ align: "end",
2474
+ className: "w-52",
2475
+ onCloseAutoFocus: () => {
2476
+ pendingDropdownAction.current?.();
2477
+ pendingDropdownAction.current = null;
2478
+ },
2479
+ children: [
2480
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: () => {
2481
+ pendingDropdownAction.current = () => setIsRenaming(true);
2482
+ }, children: [
2483
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-4 w-4 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
2484
+ "Rename File"
2485
+ ] }),
2486
+ /* @__PURE__ */ jsxRuntime.jsxs(
2487
+ DropdownMenuItem,
2488
+ {
2489
+ onSelect: () => {
2490
+ pendingDropdownAction.current = () => onRemoveFile(file.id);
2491
+ },
2492
+ className: "text-red-600 hover:text-red-700 hover:bg-red-50 focus:text-red-700 focus:bg-red-50",
2493
+ children: [
2494
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
2495
+ "Remove File"
2496
+ ]
2497
+ }
2498
+ )
2499
+ ]
2500
+ }
2501
+ )
1242
2502
  ] })
1243
2503
  ] })
1244
2504
  ] }) }),
@@ -1347,6 +2607,7 @@ var PageAssembler = React7.forwardRef(
1347
2607
  );
1348
2608
  const [isLoading, setIsLoading] = React7.useState(false);
1349
2609
  const [processingStatus, setProcessingStatus] = React7.useState("");
2610
+ const [uploadError, setUploadError] = React7.useState(null);
1350
2611
  const [showDeleteConfirm, setShowDeleteConfirm] = React7.useState(false);
1351
2612
  const [showRemoveFileConfirm, setShowRemoveFileConfirm] = React7.useState(false);
1352
2613
  const [fileToRemove, setFileToRemove] = React7.useState(null);
@@ -1354,6 +2615,7 @@ var PageAssembler = React7.forwardRef(
1354
2615
  const processedInitialPdfRef = React7.useRef(null);
1355
2616
  const isDraggingPage = React7.useRef(false);
1356
2617
  const onChangeRef = React7.useRef(onChange);
2618
+ const originalBytesCache = React7.useRef(/* @__PURE__ */ new Map());
1357
2619
  const summary = React7.useMemo(() => ({
1358
2620
  totalFiles: state.files.length,
1359
2621
  totalPages: state.files.reduce((sum, file) => sum + file.pages.length, 0)
@@ -1387,6 +2649,7 @@ var PageAssembler = React7.forwardRef(
1387
2649
  } else {
1388
2650
  pdfBytes = new Uint8Array(pdf);
1389
2651
  }
2652
+ pdfBytes = await normalizeUploadedPdfBytes(pdfBytes);
1390
2653
  const defensiveCopy = new Uint8Array(pdfBytes);
1391
2654
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1392
2655
  if (pages.length === 0) {
@@ -1423,6 +2686,7 @@ var PageAssembler = React7.forwardRef(
1423
2686
  originalFileId: fileId
1424
2687
  }))
1425
2688
  };
2689
+ originalBytesCache.current.set(fileId, originalBytes);
1426
2690
  dispatch({ type: "ADD_FILE", payload: file });
1427
2691
  } catch (error) {
1428
2692
  console.error("Error processing initial PDF:", error);
@@ -1431,8 +2695,9 @@ var PageAssembler = React7.forwardRef(
1431
2695
  setProcessingStatus("");
1432
2696
  }
1433
2697
  }, []);
2698
+ const hasRestorableState = !!initialState && initialState.files.length > 0;
1434
2699
  React7.useEffect(() => {
1435
- if (initialPdf && !initialState) {
2700
+ if (initialPdf && state.files.length === 0 && !hasRestorableState) {
1436
2701
  const pdfIdentifier = initialPdf instanceof Uint8Array ? `uint8array-${initialPdf.length}-${initialPdf[0]}-${initialPdf[initialPdf.length - 1]}` : `${initialPdf.constructor.name}-${initialPdf.size || initialPdf.byteLength}`;
1437
2702
  if (processedInitialPdfRef.current === pdfIdentifier) {
1438
2703
  return;
@@ -1440,15 +2705,16 @@ var PageAssembler = React7.forwardRef(
1440
2705
  processedInitialPdfRef.current = pdfIdentifier;
1441
2706
  processInitialPdf(initialPdf);
1442
2707
  }
1443
- }, [initialPdf, initialState, processInitialPdf]);
2708
+ }, [initialPdf, state.files.length, hasRestorableState, processInitialPdf]);
1444
2709
  React7.useEffect(() => {
1445
- if (initialState) {
2710
+ if (initialState && initialState.files.length > 0) {
1446
2711
  dispatch({ type: "RESET", payload: initialState });
1447
2712
  }
1448
2713
  }, [initialState]);
1449
2714
  const processFiles = React7.useCallback(async (files) => {
1450
2715
  const fileArray = Array.from(files);
1451
2716
  const maxFileSize = (limits?.maxFileSizeMB || 10) * 1024 * 1024;
2717
+ setUploadError(null);
1452
2718
  setIsLoading(true);
1453
2719
  setProcessingStatus(`Processing ${fileArray.length} file${fileArray.length !== 1 ? "s" : ""}...`);
1454
2720
  for (const file of fileArray) {
@@ -1473,8 +2739,9 @@ var PageAssembler = React7.forwardRef(
1473
2739
  if (file.type === "application/pdf") {
1474
2740
  setProcessingStatus(`Processing PDF: ${file.name}`);
1475
2741
  const arrayBuffer = await file.arrayBuffer();
1476
- const pdfBytes = new Uint8Array(arrayBuffer);
2742
+ const pdfBytes = await normalizeUploadedPdfBytes(new Uint8Array(arrayBuffer));
1477
2743
  fileInfo.originalBytes = new Uint8Array(pdfBytes);
2744
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1478
2745
  const defensiveCopy = new Uint8Array(pdfBytes);
1479
2746
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1480
2747
  fileInfo.pages = pages.map((page, index) => ({
@@ -1491,6 +2758,7 @@ var PageAssembler = React7.forwardRef(
1491
2758
  const arrayBuffer = await file.arrayBuffer();
1492
2759
  const imageBytes = new Uint8Array(arrayBuffer);
1493
2760
  fileInfo.originalBytes = new Uint8Array(imageBytes);
2761
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1494
2762
  const thumbUrl = URL.createObjectURL(file);
1495
2763
  const img = new Image();
1496
2764
  const dimensions = await new Promise((resolve) => {
@@ -1521,6 +2789,11 @@ var PageAssembler = React7.forwardRef(
1521
2789
  dispatch({ type: "ADD_FILE", payload: fileInfo });
1522
2790
  } catch (error) {
1523
2791
  console.error(`Error processing file ${file.name}:`, error);
2792
+ if (error instanceof PdfPasswordRequiredError2) {
2793
+ setUploadError(`${file.name}: ${error.userMessage}`);
2794
+ } else {
2795
+ setUploadError(`Failed to process "${file.name}". The file may be corrupted or unsupported.`);
2796
+ }
1524
2797
  }
1525
2798
  }
1526
2799
  setIsLoading(false);
@@ -1618,21 +2891,205 @@ var PageAssembler = React7.forwardRef(
1618
2891
  setIsLoading(true);
1619
2892
  setProcessingStatus("Assembling PDF...");
1620
2893
  try {
1621
- const { PDFDocument: PDFDocument2 } = await import('pdf-lib');
1622
- const combinedDoc = await PDFDocument2.create();
2894
+ const { PDFDocument: PDFDocument5, PDFName: PDFName4, PDFString: PDFString4 } = await import('pdf-lib');
1623
2895
  const loadedPdfs = /* @__PURE__ */ new Map();
1624
2896
  const fileMap = /* @__PURE__ */ new Map();
2897
+ const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
2898
+ const imageFiles = state.files.filter((f) => f.type === "image");
2899
+ const isSinglePdfScenario = pdfFiles.length === 1 && imageFiles.length === 0;
1625
2900
  for (const file of state.files) {
1626
2901
  fileMap.set(file.id, file);
1627
- if (file.type === "pdf" && file.originalBytes) {
2902
+ if (file.type === "pdf" && file.originalBytes && file.originalBytes.length > 0) {
1628
2903
  try {
1629
- const sourcePdf = await PDFDocument2.load(file.originalBytes);
2904
+ const sourcePdf = await PDFDocument5.load(file.originalBytes);
1630
2905
  loadedPdfs.set(file.id, sourcePdf);
1631
2906
  } catch (error) {
1632
2907
  console.error(`Error loading PDF for file ${file.id}:`, error);
1633
2908
  }
1634
2909
  }
1635
2910
  }
2911
+ const referencedFileIds = /* @__PURE__ */ new Set();
2912
+ for (const file of state.files) {
2913
+ for (const page of file.pages) {
2914
+ const originalFileId = page.originalFileId || file.id;
2915
+ if (!loadedPdfs.has(originalFileId)) {
2916
+ referencedFileIds.add(originalFileId);
2917
+ }
2918
+ }
2919
+ }
2920
+ for (const fileId of referencedFileIds) {
2921
+ const cachedBytes = originalBytesCache.current.get(fileId);
2922
+ if (cachedBytes && cachedBytes.length > 0) {
2923
+ try {
2924
+ console.log(`[PageAssembler] Loading PDF from cache for deleted file ${fileId}`);
2925
+ const sourcePdf = await PDFDocument5.load(cachedBytes);
2926
+ loadedPdfs.set(fileId, sourcePdf);
2927
+ } catch (error) {
2928
+ console.error(`Error loading cached PDF for file ${fileId}:`, error);
2929
+ }
2930
+ }
2931
+ }
2932
+ console.log("[PageAssembler] Checking single PDF scenario:", {
2933
+ isSinglePdfScenario,
2934
+ pdfFilesCount: pdfFiles.length,
2935
+ imageFilesCount: imageFiles.length
2936
+ });
2937
+ if (isSinglePdfScenario && pdfFiles[0]) {
2938
+ const sourceFile = pdfFiles[0];
2939
+ const sourcePdf = loadedPdfs.get(sourceFile.id);
2940
+ console.log("[PageAssembler] Single PDF check:", {
2941
+ sourcePdfLoaded: !!sourcePdf,
2942
+ pagesCount: sourceFile.pages.length,
2943
+ originalBytesLength: sourceFile.originalBytes?.length
2944
+ });
2945
+ if (sourcePdf) {
2946
+ const desiredPageIndices = sourceFile.pages.map((p) => p.srcIndex);
2947
+ const originalPageCount = sourcePdf.getPageCount();
2948
+ const allPagesFromSameFile = sourceFile.pages.every(
2949
+ (p) => (p.originalFileId || sourceFile.id) === sourceFile.id
2950
+ );
2951
+ const isOriginalOrder = desiredPageIndices.length === originalPageCount && desiredPageIndices.every((idx, i) => idx === i);
2952
+ console.log("[PageAssembler] Original bytes check:", {
2953
+ allPagesFromSameFile,
2954
+ isOriginalOrder,
2955
+ desiredPageIndices,
2956
+ originalPageCount
2957
+ });
2958
+ if (allPagesFromSameFile && isOriginalOrder) {
2959
+ console.log("[PageAssembler] \u2705 Returning ORIGINAL bytes (form fields preserved)");
2960
+ const arrayBuffer2 = sourceFile.originalBytes.buffer.slice(
2961
+ sourceFile.originalBytes.byteOffset,
2962
+ sourceFile.originalBytes.byteOffset + sourceFile.originalBytes.byteLength
2963
+ );
2964
+ const blob2 = new Blob([arrayBuffer2], { type: "application/pdf" });
2965
+ return blob2;
2966
+ } else {
2967
+ console.log("[PageAssembler] \u26A0\uFE0F Pages modified, will use copyPages (form fields may be lost)");
2968
+ }
2969
+ }
2970
+ }
2971
+ console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
2972
+ const allExtractedFields = [];
2973
+ const mergedMetadata = {
2974
+ version: "1.0",
2975
+ fields: {},
2976
+ fieldIdIndex: {}
2977
+ };
2978
+ const filePageUsage = /* @__PURE__ */ new Map();
2979
+ for (const file of state.files) {
2980
+ for (const page of file.pages) {
2981
+ const originalFileId = page.originalFileId || file.id;
2982
+ if (!filePageUsage.has(originalFileId)) {
2983
+ filePageUsage.set(originalFileId, /* @__PURE__ */ new Map());
2984
+ }
2985
+ const pageUsage = filePageUsage.get(originalFileId);
2986
+ if (!pageUsage.has(page.srcIndex)) {
2987
+ pageUsage.set(page.srcIndex, []);
2988
+ }
2989
+ pageUsage.get(page.srcIndex).push(page);
2990
+ }
2991
+ }
2992
+ let combinedPageIndex = 0;
2993
+ const pageIdToNewPageNumber = /* @__PURE__ */ new Map();
2994
+ for (const file of state.files) {
2995
+ for (const page of file.pages) {
2996
+ combinedPageIndex++;
2997
+ pageIdToNewPageNumber.set(page.id, combinedPageIndex);
2998
+ }
2999
+ }
3000
+ console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
3001
+ const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
3002
+ let sourceMetadata = null;
3003
+ if (sourcePdf) {
3004
+ try {
3005
+ const sourceInfoRef = sourcePdf.context.trailerInfo.Info;
3006
+ if (sourceInfoRef) {
3007
+ const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
3008
+ if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
3009
+ const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
3010
+ if (metadataObj) {
3011
+ const metadataStr = metadataObj.toString();
3012
+ let jsonStr = metadataStr;
3013
+ if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
3014
+ jsonStr = metadataStr.slice(1, -1);
3015
+ }
3016
+ sourceMetadata = JSON.parse(jsonStr);
3017
+ }
3018
+ }
3019
+ }
3020
+ } catch (metadataError) {
3021
+ console.warn(`Could not read metadata from PDF ${fileName}:`, metadataError);
3022
+ }
3023
+ }
3024
+ console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
3025
+ const extractedFields = await extractFieldsFromPdf(pdfBytes2);
3026
+ console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
3027
+ const pageUsageForFile = filePageUsage.get(fileId) || /* @__PURE__ */ new Map();
3028
+ for (const field of extractedFields) {
3029
+ const originalPage = field.page;
3030
+ const srcIndex = originalPage - 1;
3031
+ const pageInstances = pageUsageForFile.get(srcIndex) || [];
3032
+ for (const pageInstance of pageInstances) {
3033
+ const newPageNumber = pageIdToNewPageNumber.get(pageInstance.id);
3034
+ if (newPageNumber !== void 0) {
3035
+ const trackedField = {
3036
+ name: field.name,
3037
+ type: field.type,
3038
+ position: {
3039
+ x: field.x,
3040
+ y: field.y,
3041
+ width: field.width,
3042
+ height: field.height,
3043
+ page: newPageNumber
3044
+ // Updated to new page number
3045
+ },
3046
+ pageId: pageInstance.id,
3047
+ originalFileId: fileId,
3048
+ label: field.label,
3049
+ required: field.required,
3050
+ options: field.options,
3051
+ placeholder: field.placeholder,
3052
+ fieldId: field.fieldId,
3053
+ assignedSignerEmail: field.signer
3054
+ };
3055
+ allExtractedFields.push(trackedField);
3056
+ console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
3057
+ const metadataKey = `${field.name}_p${newPageNumber}`;
3058
+ if (sourceMetadata?.fields?.[field.name]) {
3059
+ mergedMetadata.fields[metadataKey] = sourceMetadata.fields[field.name];
3060
+ }
3061
+ if (sourceMetadata?.fieldIdIndex?.[field.name]) {
3062
+ mergedMetadata.fieldIdIndex[metadataKey] = sourceMetadata.fieldIdIndex[field.name];
3063
+ }
3064
+ }
3065
+ }
3066
+ }
3067
+ };
3068
+ const processedFileIds = /* @__PURE__ */ new Set();
3069
+ for (const file of state.files) {
3070
+ if (file.type !== "pdf" || !file.originalBytes || file.originalBytes.length === 0) continue;
3071
+ try {
3072
+ await extractAndMapFields(file.id, file.name, file.originalBytes, loadedPdfs.get(file.id));
3073
+ processedFileIds.add(file.id);
3074
+ } catch (extractError) {
3075
+ console.error(`Error extracting fields from ${file.name}:`, extractError);
3076
+ }
3077
+ }
3078
+ for (const fileId of referencedFileIds) {
3079
+ if (processedFileIds.has(fileId)) continue;
3080
+ const cachedBytes = originalBytesCache.current.get(fileId);
3081
+ if (cachedBytes && cachedBytes.length > 0) {
3082
+ try {
3083
+ console.log(`[PageAssembler] Extracting fields from cached file ${fileId}`);
3084
+ await extractAndMapFields(fileId, `Cached file ${fileId}`, cachedBytes, loadedPdfs.get(fileId));
3085
+ } catch (extractError) {
3086
+ console.error(`Error extracting fields from cached file ${fileId}:`, extractError);
3087
+ }
3088
+ }
3089
+ }
3090
+ console.log(`[PageAssembler] Total extracted fields: ${allExtractedFields.length}`);
3091
+ console.log(`[PageAssembler] Field names:`, allExtractedFields.map((f) => `${f.name} (page ${f.position.page})`));
3092
+ const combinedDoc = await PDFDocument5.create();
1636
3093
  for (const file of state.files) {
1637
3094
  if (file.pages.length === 0) continue;
1638
3095
  for (const page of file.pages) {
@@ -1652,7 +3109,17 @@ var PageAssembler = React7.forwardRef(
1652
3109
  if (page.srcIndex >= 0 && page.srcIndex < sourcePageCount) {
1653
3110
  try {
1654
3111
  const copiedPages = await combinedDoc.copyPages(sourcePdf, [page.srcIndex]);
1655
- copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
3112
+ copiedPages.forEach((copiedPage) => {
3113
+ try {
3114
+ const annotsRef = copiedPage.node.get(PDFName4.of("Annots"));
3115
+ if (annotsRef) {
3116
+ copiedPage.node.delete(PDFName4.of("Annots"));
3117
+ }
3118
+ } catch (annotError) {
3119
+ console.warn("Could not remove annotations from copied page:", annotError);
3120
+ }
3121
+ combinedDoc.addPage(copiedPage);
3122
+ });
1656
3123
  } catch (copyError) {
1657
3124
  console.error(`Error copying page ${page.srcIndex}:`, copyError);
1658
3125
  throw new Error(`Failed to copy page: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
@@ -1661,7 +3128,7 @@ var PageAssembler = React7.forwardRef(
1661
3128
  } else if (sourceFile.type === "image" && sourceFile.originalFile) {
1662
3129
  try {
1663
3130
  const imagePdfBytes = await imageToPdf(sourceFile.originalFile);
1664
- const imagePdf = await PDFDocument2.load(imagePdfBytes);
3131
+ const imagePdf = await PDFDocument5.load(imagePdfBytes);
1665
3132
  const copiedPages = await combinedDoc.copyPages(imagePdf, [0]);
1666
3133
  copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1667
3134
  } catch (imageError) {
@@ -1671,8 +3138,48 @@ var PageAssembler = React7.forwardRef(
1671
3138
  }
1672
3139
  }
1673
3140
  }
1674
- const pdfBytes = await combinedDoc.save();
1675
- const blob = new Blob([pdfBytes.buffer], { type: "application/pdf" });
3141
+ if (Object.keys(mergedMetadata.fields).length > 0) {
3142
+ try {
3143
+ const newInfoRef = combinedDoc.context.trailerInfo.Info;
3144
+ if (newInfoRef) {
3145
+ const newInfoDict = combinedDoc.context.lookup(newInfoRef);
3146
+ if (newInfoDict && typeof newInfoDict.set === "function") {
3147
+ newInfoDict.set(
3148
+ PDFName4.of("SigniphiMetadata"),
3149
+ PDFString4.of(JSON.stringify(mergedMetadata))
3150
+ );
3151
+ }
3152
+ }
3153
+ } catch (metadataError) {
3154
+ console.warn("Could not write merged metadata:", metadataError);
3155
+ }
3156
+ }
3157
+ let pdfBytes = await combinedDoc.save();
3158
+ if (allExtractedFields.length > 0) {
3159
+ console.log(`[PageAssembler] Re-adding ${allExtractedFields.length} fields to combined document`);
3160
+ const fieldsForPdf = allExtractedFields.map((field) => ({
3161
+ name: field.name,
3162
+ type: field.type,
3163
+ position: field.position,
3164
+ label: field.label,
3165
+ required: field.required,
3166
+ options: field.options,
3167
+ placeholder: field.placeholder,
3168
+ assignedSignerEmail: field.assignedSignerEmail
3169
+ }));
3170
+ try {
3171
+ pdfBytes = await addFormFieldsToPdf(pdfBytes, fieldsForPdf, {
3172
+ removeExistingFields: true,
3173
+ // Remove any orphaned field references
3174
+ drawLabels: false
3175
+ });
3176
+ console.log("[PageAssembler] \u2705 Successfully re-added form fields to combined PDF");
3177
+ } catch (addFieldsError) {
3178
+ console.error("[PageAssembler] Error re-adding fields:", addFieldsError);
3179
+ }
3180
+ }
3181
+ const arrayBuffer = pdfBytes.buffer.slice(pdfBytes.byteOffset, pdfBytes.byteOffset + pdfBytes.byteLength);
3182
+ const blob = new Blob([arrayBuffer], { type: "application/pdf" });
1676
3183
  return blob;
1677
3184
  } catch (error) {
1678
3185
  console.error("Error assembling PDF:", error);
@@ -1686,7 +3193,7 @@ var PageAssembler = React7.forwardRef(
1686
3193
  isBusy: () => isLoading,
1687
3194
  getState: () => state
1688
3195
  }), [state, summary, isLoading]);
1689
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(reactDnd.DndProvider, { backend: reactDndHtml5Backend.HTML5Backend, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-6 pb-6", className), children: [
3196
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(reactDnd.DndProvider, { backend: reactDndHtml5Backend.HTML5Backend, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-3", className), children: [
1690
3197
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1691
3198
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1692
3199
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium", children: "Page Assembly" }),
@@ -1725,6 +3232,10 @@ var PageAssembler = React7.forwardRef(
1725
3232
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
1726
3233
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: processingStatus })
1727
3234
  ] }) }),
3235
+ 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: [
3236
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4 text-destructive flex-shrink-0" }),
3237
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: uploadError })
3238
+ ] }) }),
1728
3239
  /* @__PURE__ */ jsxRuntime.jsx(
1729
3240
  BulkActionBar,
1730
3241
  {
@@ -1777,9 +3288,9 @@ var PageAssembler = React7.forwardRef(
1777
3288
  ]
1778
3289
  }
1779
3290
  ) : !disableFileUpload && /* @__PURE__ */ jsxRuntime.jsx(
1780
- Card,
3291
+ "div",
1781
3292
  {
1782
- className: "p-12 border-dashed border-2 border-gray-300 hover:border-gray-400 transition-colors cursor-pointer",
3293
+ className: "p-12 rounded-lg bg-card text-card-foreground cursor-pointer transition-all border-2 border-dashed border-border hover:border-primary/60 hover:bg-primary/10",
1783
3294
  onClick: handleFileUpload,
1784
3295
  onDrop: handleDrop,
1785
3296
  onDragOver: handleDragOver,
@@ -1859,14 +3370,24 @@ function debounce(func, wait) {
1859
3370
  timeout = setTimeout(() => func(...args), wait);
1860
3371
  });
1861
3372
  }
1862
- var PageAssembler_default = PageAssembler;
1863
3373
 
1864
3374
  exports.Button = Button;
3375
+ exports.FormFieldType = FormFieldType;
1865
3376
  exports.PageAssembler = PageAssembler;
3377
+ exports.PdfPasswordRequiredError = PdfPasswordRequiredError2;
3378
+ exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError2;
3379
+ exports.addFormFieldsToPdf = addFormFieldsToPdf;
1866
3380
  exports.createPdfBlobUrl = createPdfBlobUrl;
1867
- exports.default = PageAssembler_default;
3381
+ exports.decryptPdf = decryptPdf2;
1868
3382
  exports.downloadPdf = downloadPdf;
3383
+ exports.extractFieldsFromPdf = extractFieldsFromPdf;
3384
+ exports.getSigniphiMetadata = getSigniphiMetadata;
1869
3385
  exports.imageToPdf = imageToPdf;
3386
+ exports.mapFieldPositionsAfterAssembly = mapFieldPositionsAfterAssembly;
3387
+ exports.normalizePdfEncryption = normalizePdfEncryption2;
3388
+ exports.normalizeUploadedPdfBytes = normalizeUploadedPdfBytes;
1870
3389
  exports.pdfToImages = pdfToImages;
3390
+ exports.rasterizePdfToPdf = rasterizePdfToPdf;
3391
+ exports.setSigniphiMetadata = setSigniphiMetadata;
1871
3392
  //# sourceMappingURL=index.js.map
1872
3393
  //# sourceMappingURL=index.js.map