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

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');
@@ -45,7 +43,9 @@ var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMe
45
43
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
46
44
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
47
45
 
48
- // 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);
49
49
  function cn(...inputs) {
50
50
  return tailwindMerge.twMerge(clsx.clsx(inputs));
51
51
  }
@@ -576,6 +576,583 @@ var TooltipContent = React7__namespace.forwardRef(({ className, sideOffset = 4,
576
576
  }
577
577
  ));
578
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) => {
832
+ if (a.length !== b.length) return false;
833
+ let diff = 0;
834
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
835
+ return diff === 0;
836
+ };
837
+ function legacyFileKey(paddedPwd, params) {
838
+ const { revision, keyLen, O, P, id0, encryptMetadata } = params;
839
+ const pBytes = new Uint8Array(4);
840
+ new DataView(pBytes.buffer).setInt32(0, P | 0, true);
841
+ const parts = [paddedPwd, O.slice(0, 32), pBytes, id0];
842
+ if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([255, 255, 255, 255]));
843
+ let h = md5(concatBytes(...parts));
844
+ if (revision >= 3) for (let i = 0; i < 50; i++) h = md5(h.slice(0, keyLen));
845
+ return h.slice(0, keyLen);
846
+ }
847
+ function legacyComputeU(fileKey, revision, id0) {
848
+ if (revision === 2) return rc4(fileKey, PAD);
849
+ let d = md5(concatBytes(PAD, id0));
850
+ d = rc4(fileKey, d);
851
+ for (let i = 1; i <= 19; i++) d = rc4(fileKey.map((b) => b ^ i), d);
852
+ return d;
853
+ }
854
+ function legacyUMatches(fileKey, params) {
855
+ const computed = legacyComputeU(fileKey, params.revision, params.id0);
856
+ return params.revision === 2 ? bytesEqual(computed, params.U.slice(0, 32)) : bytesEqual(computed.slice(0, 16), params.U.slice(0, 16));
857
+ }
858
+ function legacyAuthenticateEmptyPassword(params) {
859
+ const userKey = legacyFileKey(PAD, params);
860
+ if (legacyUMatches(userKey, params)) return userKey;
861
+ throw new PdfPasswordRequiredError();
862
+ }
863
+ async function hash2B(password, salt, udata) {
864
+ let k = await sha2("SHA-256", concatBytes(password, salt, udata));
865
+ let e = new Uint8Array(0);
866
+ let i = 0;
867
+ do {
868
+ const block = concatBytes(password, k, udata);
869
+ const k1 = new Uint8Array(block.length * 64);
870
+ for (let rep = 0; rep < 64; rep++) k1.set(block, rep * block.length);
871
+ e = await aesCbcEncryptNoPad(k.slice(0, 16), k.slice(16, 32), k1);
872
+ let sum = 0;
873
+ for (let b = 0; b < 16; b++) sum += e[b];
874
+ const mod = sum % 3;
875
+ k = await sha2(mod === 0 ? "SHA-256" : mod === 1 ? "SHA-384" : "SHA-512", e);
876
+ i++;
877
+ } while (i < 64 || e[e.length - 1] > i - 32);
878
+ return k.slice(0, 32);
879
+ }
880
+ async function v5AuthenticateEmptyPassword(revision, U, UE) {
881
+ const pwd = new Uint8Array(0);
882
+ const zeroIv = new Uint8Array(16);
883
+ const hash = async (salt, udata) => revision === 5 ? sha2("SHA-256", concatBytes(pwd, salt, udata)) : hash2B(pwd, salt, udata);
884
+ const userHash = await hash(U.slice(32, 40), new Uint8Array(0));
885
+ if (bytesEqual(userHash, U.slice(0, 32))) {
886
+ const intermediate = await hash(U.slice(40, 48), new Uint8Array(0));
887
+ return aesCbcDecryptNoPad(intermediate, zeroIv, UE.slice(0, 32));
888
+ }
889
+ throw new PdfPasswordRequiredError();
890
+ }
891
+ var identityCipher = async (data) => data;
892
+ function rc4ObjectCipher(fileKey) {
893
+ return async (data, ref) => {
894
+ const ext = new Uint8Array([
895
+ ref.objectNumber & 255,
896
+ ref.objectNumber >> 8 & 255,
897
+ ref.objectNumber >> 16 & 255,
898
+ ref.generationNumber & 255,
899
+ ref.generationNumber >> 8 & 255
900
+ ]);
901
+ const key = md5(concatBytes(fileKey, ext)).slice(0, Math.min(fileKey.length + 5, 16));
902
+ return rc4(key, data);
903
+ };
904
+ }
905
+ var AES_SALT = new Uint8Array([115, 65, 108, 84]);
906
+ function aes128ObjectCipher(fileKey) {
907
+ return async (data, ref) => {
908
+ const ext = new Uint8Array([
909
+ ref.objectNumber & 255,
910
+ ref.objectNumber >> 8 & 255,
911
+ ref.objectNumber >> 16 & 255,
912
+ ref.generationNumber & 255,
913
+ ref.generationNumber >> 8 & 255
914
+ ]);
915
+ const key = md5(concatBytes(fileKey, ext, AES_SALT)).slice(0, 16);
916
+ return aesDecryptPdfData(key, data);
917
+ };
918
+ }
919
+ function aes256ObjectCipher(fileKey) {
920
+ return async (data) => aesDecryptPdfData(fileKey, data);
921
+ }
922
+ function dictNumber(dict, key) {
923
+ const value = dict.lookup(pdfLib.PDFName.of(key));
924
+ return value instanceof pdfLib.PDFNumber ? value.asNumber() : void 0;
925
+ }
926
+ function dictBytes(dict, key) {
927
+ const value = dict.lookup(pdfLib.PDFName.of(key));
928
+ return value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString ? value.asBytes() : void 0;
929
+ }
930
+ async function buildDocumentCiphers(encDict, id0) {
931
+ const filter = encDict.lookup(pdfLib.PDFName.of("Filter"));
932
+ if (filter !== pdfLib.PDFName.of("Standard")) {
933
+ throw new UnsupportedPdfEncryptionError(`security handler ${String(filter)}`);
934
+ }
935
+ const V = dictNumber(encDict, "V") ?? 0;
936
+ const R = dictNumber(encDict, "R") ?? 0;
937
+ const O = dictBytes(encDict, "O");
938
+ const U = dictBytes(encDict, "U");
939
+ const P = dictNumber(encDict, "P") ?? -1;
940
+ const metadataValue = encDict.lookup(pdfLib.PDFName.of("EncryptMetadata"));
941
+ const encryptMetadata = metadataValue instanceof pdfLib.PDFBool ? metadataValue.asBoolean() : true;
942
+ if (!O || !U) throw new UnsupportedPdfEncryptionError("missing /O or /U");
943
+ if (V === 1 || V === 2) {
944
+ const keyLen = V === 1 ? 5 : (dictNumber(encDict, "Length") ?? 40) / 8;
945
+ const fileKey = legacyAuthenticateEmptyPassword({ revision: R, keyLen, O, U, P, id0, encryptMetadata });
946
+ const cipher = rc4ObjectCipher(fileKey);
947
+ return { stringCipher: cipher, streamCipher: cipher, encryptMetadata };
948
+ }
949
+ if (V === 4 || V === 5) {
950
+ const cf = encDict.lookup(pdfLib.PDFName.of("CF"));
951
+ const cfmOf = (filterKey) => {
952
+ const streamFilter = encDict.lookup(pdfLib.PDFName.of(filterKey));
953
+ if (!(streamFilter instanceof pdfLib.PDFName) || streamFilter === pdfLib.PDFName.of("Identity")) return void 0;
954
+ if (!(cf instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError("missing /CF");
955
+ const cfDict = cf.lookup(streamFilter);
956
+ if (!(cfDict instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError(`missing crypt filter ${streamFilter.toString()}`);
957
+ const cfm = cfDict.lookup(pdfLib.PDFName.of("CFM"));
958
+ return cfm instanceof pdfLib.PDFName ? cfm : void 0;
959
+ };
960
+ let fileKey;
961
+ if (V === 5) {
962
+ const UE = dictBytes(encDict, "UE");
963
+ if (!UE) throw new UnsupportedPdfEncryptionError("missing /UE");
964
+ fileKey = await v5AuthenticateEmptyPassword(R, U, UE);
965
+ } else {
966
+ const cryptFilterLengthBits = () => {
967
+ if (!(cf instanceof pdfLib.PDFDict)) return void 0;
968
+ for (const filterKey of ["StmF", "StrF"]) {
969
+ const filter2 = encDict.lookup(pdfLib.PDFName.of(filterKey));
970
+ if (!(filter2 instanceof pdfLib.PDFName) || filter2 === pdfLib.PDFName.of("Identity")) continue;
971
+ const cfDict = cf.lookup(filter2);
972
+ if (!(cfDict instanceof pdfLib.PDFDict)) continue;
973
+ const len = dictNumber(cfDict, "Length");
974
+ if (len === void 0) continue;
975
+ return len < 40 ? len * 8 : len;
976
+ }
977
+ return void 0;
978
+ };
979
+ const keyLenBits = cryptFilterLengthBits() ?? dictNumber(encDict, "Length") ?? 128;
980
+ fileKey = legacyAuthenticateEmptyPassword({
981
+ revision: R,
982
+ keyLen: keyLenBits / 8,
983
+ O,
984
+ U,
985
+ P,
986
+ id0,
987
+ encryptMetadata
988
+ });
989
+ }
990
+ const cipherFor = (cfm) => {
991
+ if (!cfm || cfm === pdfLib.PDFName.of("Identity")) return identityCipher;
992
+ if (cfm === pdfLib.PDFName.of("V2")) return rc4ObjectCipher(fileKey);
993
+ if (cfm === pdfLib.PDFName.of("AESV2")) return aes128ObjectCipher(fileKey);
994
+ if (cfm === pdfLib.PDFName.of("AESV3")) return aes256ObjectCipher(fileKey);
995
+ throw new UnsupportedPdfEncryptionError(`crypt filter method ${cfm.toString()}`);
996
+ };
997
+ return {
998
+ streamCipher: cipherFor(cfmOf("StmF")),
999
+ stringCipher: cipherFor(cfmOf("StrF")),
1000
+ encryptMetadata
1001
+ };
1002
+ }
1003
+ throw new UnsupportedPdfEncryptionError(`/V ${V}`);
1004
+ }
1005
+ var toHexString = (bytes) => {
1006
+ let hex = "";
1007
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
1008
+ return new pdfLib.PDFHexString(hex.toUpperCase());
1009
+ };
1010
+ function filterIncludesCrypt(dict) {
1011
+ const filter = dict.lookup(pdfLib.PDFName.of("Filter"));
1012
+ if (filter === pdfLib.PDFName.of("Crypt")) return true;
1013
+ if (filter instanceof pdfLib.PDFArray) {
1014
+ for (let i = 0; i < filter.size(); i++) {
1015
+ if (filter.get(i) === pdfLib.PDFName.of("Crypt")) return true;
1016
+ }
1017
+ }
1018
+ return false;
1019
+ }
1020
+ function cryptFilterIsIdentity(dict) {
1021
+ const parms = dict.lookup(pdfLib.PDFName.of("DecodeParms")) ?? dict.lookup(pdfLib.PDFName.of("DP"));
1022
+ const identityParms = (p) => {
1023
+ if (!(p instanceof pdfLib.PDFDict)) return true;
1024
+ const name = p.lookup(pdfLib.PDFName.of("Name"));
1025
+ return !(name instanceof pdfLib.PDFName) || name === pdfLib.PDFName.of("Identity");
1026
+ };
1027
+ if (parms instanceof pdfLib.PDFArray) {
1028
+ for (let i = 0; i < parms.size(); i++) {
1029
+ if (!identityParms(parms.lookup(i))) return false;
1030
+ }
1031
+ return true;
1032
+ }
1033
+ return identityParms(parms);
1034
+ }
1035
+ async function decryptStringsWithin(obj, ref, stringCipher) {
1036
+ if (obj instanceof pdfLib.PDFDict) {
1037
+ const isSignature = obj.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("Sig");
1038
+ for (const [key, value] of obj.entries()) {
1039
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1040
+ if (isSignature && key === pdfLib.PDFName.of("Contents")) continue;
1041
+ obj.set(key, toHexString(await stringCipher(value.asBytes(), ref)));
1042
+ } else {
1043
+ await decryptStringsWithin(value, ref, stringCipher);
1044
+ }
1045
+ }
1046
+ } else if (obj instanceof pdfLib.PDFArray) {
1047
+ for (let i = 0; i < obj.size(); i++) {
1048
+ const value = obj.get(i);
1049
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1050
+ obj.set(i, toHexString(await stringCipher(value.asBytes(), ref)));
1051
+ } else {
1052
+ await decryptStringsWithin(value, ref, stringCipher);
1053
+ }
1054
+ }
1055
+ }
1056
+ }
1057
+ async function decryptLoadedDocument(doc) {
1058
+ const context = doc.context;
1059
+ const encryptRef = context.trailerInfo.Encrypt;
1060
+ const encDict = context.lookup(encryptRef);
1061
+ if (!(encDict instanceof pdfLib.PDFDict)) {
1062
+ throw new UnsupportedPdfEncryptionError("malformed /Encrypt dictionary");
1063
+ }
1064
+ const idArray = context.lookup(context.trailerInfo.ID);
1065
+ const idFirst = idArray instanceof pdfLib.PDFArray ? idArray.get(0) : void 0;
1066
+ const id0 = idFirst instanceof pdfLib.PDFString || idFirst instanceof pdfLib.PDFHexString ? idFirst.asBytes() : new Uint8Array(0);
1067
+ const { stringCipher, streamCipher, encryptMetadata } = await buildDocumentCiphers(encDict, id0);
1068
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1069
+ if (!(obj instanceof pdfLib.PDFInvalidObject)) continue;
1070
+ const raw = new Uint8Array(obj.sizeInBytes());
1071
+ obj.copyBytesInto(raw, 0);
1072
+ try {
1073
+ const parsed = pdfLib.PDFObjectParser.forBytes(raw, context).parseObject();
1074
+ if (parsed instanceof pdfLib.PDFRawStream && parsed.dict.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("ObjStm")) {
1075
+ context.assign(ref, parsed);
1076
+ }
1077
+ } catch {
1078
+ }
1079
+ }
1080
+ const decryptedObjectStreams = [];
1081
+ const structuralStreamRefs = [];
1082
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1083
+ if (ref === encryptRef || obj === encDict) continue;
1084
+ if (obj instanceof pdfLib.PDFRawStream) {
1085
+ const type = obj.dict.lookup(pdfLib.PDFName.of("Type"));
1086
+ if (type === pdfLib.PDFName.of("XRef")) {
1087
+ structuralStreamRefs.push(ref);
1088
+ continue;
1089
+ }
1090
+ const isSkippedMetadata = !encryptMetadata && type === pdfLib.PDFName.of("Metadata");
1091
+ if (filterIncludesCrypt(obj.dict)) {
1092
+ if (!cryptFilterIsIdentity(obj.dict)) {
1093
+ throw new UnsupportedPdfEncryptionError("stream-specific /Crypt filter");
1094
+ }
1095
+ } else if (!isSkippedMetadata) {
1096
+ const decrypted = await streamCipher(obj.contents, ref);
1097
+ const replacement = pdfLib.PDFRawStream.of(obj.dict, decrypted);
1098
+ context.assign(ref, replacement);
1099
+ if (type === pdfLib.PDFName.of("ObjStm")) {
1100
+ decryptedObjectStreams.push([ref, replacement]);
1101
+ }
1102
+ }
1103
+ await decryptStringsWithin(obj.dict, ref, stringCipher);
1104
+ } else if (obj instanceof pdfLib.PDFString || obj instanceof pdfLib.PDFHexString) {
1105
+ context.assign(ref, toHexString(await stringCipher(obj.asBytes(), ref)));
1106
+ } else {
1107
+ await decryptStringsWithin(obj, ref, stringCipher);
1108
+ }
1109
+ }
1110
+ for (const [ref, stream] of decryptedObjectStreams) {
1111
+ await pdfLib.PDFObjectStreamParser.forStream(stream).parseIntoContext();
1112
+ context.delete(ref);
1113
+ }
1114
+ for (const ref of structuralStreamRefs) context.delete(ref);
1115
+ delete context.trailerInfo.Encrypt;
1116
+ if (encryptRef instanceof pdfLib.PDFRef) context.delete(encryptRef);
1117
+ return doc.save({
1118
+ useObjectStreams: false,
1119
+ addDefaultPage: false,
1120
+ updateFieldAppearances: false
1121
+ });
1122
+ }
1123
+ async function decryptPdf(pdfBytes) {
1124
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1125
+ ignoreEncryption: true,
1126
+ updateMetadata: false
1127
+ });
1128
+ if (!doc.isEncrypted) return pdfBytes;
1129
+ return decryptLoadedDocument(doc);
1130
+ }
1131
+ var ENCRYPT_MARKER = new Uint8Array([47, 69, 110, 99, 114, 121, 112, 116]);
1132
+ function containsEncryptMarker(bytes) {
1133
+ const last = bytes.length - ENCRYPT_MARKER.length;
1134
+ outer: for (let i = 0; i <= last; i++) {
1135
+ for (let j = 0; j < ENCRYPT_MARKER.length; j++) {
1136
+ if (bytes[i + j] !== ENCRYPT_MARKER[j]) continue outer;
1137
+ }
1138
+ return true;
1139
+ }
1140
+ return false;
1141
+ }
1142
+ async function normalizePdfEncryption(pdfBytes) {
1143
+ if (!containsEncryptMarker(pdfBytes)) return pdfBytes;
1144
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1145
+ ignoreEncryption: true,
1146
+ updateMetadata: false
1147
+ });
1148
+ if (!doc.isEncrypted) return pdfBytes;
1149
+ if (typeof process === "undefined" || process.env?.NODE_ENV !== "production") {
1150
+ console.info("[PageAssembler] Encrypted PDF detected during ingestion; decrypting");
1151
+ }
1152
+ return decryptLoadedDocument(doc);
1153
+ }
1154
+
1155
+ // src/utils/pdf-helpers.ts
579
1156
  if (typeof window !== "undefined") {
580
1157
  pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
581
1158
  }
@@ -647,6 +1224,68 @@ async function pdfToImages(pdfBytes, options) {
647
1224
  throw error;
648
1225
  }
649
1226
  }
1227
+ var MAX_RASTER_PAGE_COUNT = 500;
1228
+ var MAX_RASTER_CANVAS_PIXELS = 4096 * 4096;
1229
+ var PREFERRED_RASTER_SCALE = 2;
1230
+ function computeRasterScale(width, height) {
1231
+ const area = width * height;
1232
+ if (!Number.isFinite(area) || area <= 0) return PREFERRED_RASTER_SCALE;
1233
+ const preferredPixels = area * PREFERRED_RASTER_SCALE * PREFERRED_RASTER_SCALE;
1234
+ if (preferredPixels <= MAX_RASTER_CANVAS_PIXELS) return PREFERRED_RASTER_SCALE;
1235
+ return Math.sqrt(MAX_RASTER_CANVAS_PIXELS / area);
1236
+ }
1237
+ async function rasterizePdfToPdf(pdfBytes) {
1238
+ if (typeof window !== "undefined") {
1239
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
1240
+ }
1241
+ let sourceDoc;
1242
+ try {
1243
+ sourceDoc = await pdfjsLib__namespace.getDocument({ data: pdfBytes.slice(0), verbosity: 0 }).promise;
1244
+ } catch (error) {
1245
+ if (error?.name === "PasswordException") {
1246
+ throw new PdfPasswordRequiredError();
1247
+ }
1248
+ throw error;
1249
+ }
1250
+ try {
1251
+ if (sourceDoc.numPages > MAX_RASTER_PAGE_COUNT) {
1252
+ throw new Error(
1253
+ `Cannot rebuild PDF: ${sourceDoc.numPages} pages exceeds the ${MAX_RASTER_PAGE_COUNT}-page limit`
1254
+ );
1255
+ }
1256
+ const outDoc = await pdfLib.PDFDocument.create();
1257
+ for (let pageNum = 1; pageNum <= sourceDoc.numPages; pageNum++) {
1258
+ const page = await sourceDoc.getPage(pageNum);
1259
+ const base = page.getViewport({ scale: 1 });
1260
+ const scale = computeRasterScale(base.width, base.height);
1261
+ const viewport = page.getViewport({ scale });
1262
+ const canvas = document.createElement("canvas");
1263
+ canvas.width = viewport.width;
1264
+ canvas.height = viewport.height;
1265
+ const context = canvas.getContext("2d");
1266
+ await page.render({ canvasContext: context, viewport }).promise;
1267
+ const png = await outDoc.embedPng(canvas.toDataURL("image/png"));
1268
+ const outPage = outDoc.addPage([base.width, base.height]);
1269
+ outPage.drawImage(png, { x: 0, y: 0, width: base.width, height: base.height });
1270
+ }
1271
+ return new Uint8Array(await outDoc.save({ useObjectStreams: false }));
1272
+ } finally {
1273
+ await sourceDoc.destroy();
1274
+ }
1275
+ }
1276
+ async function normalizeUploadedPdfBytes(pdfBytes) {
1277
+ try {
1278
+ const normalized = await normalizePdfEncryption(pdfBytes);
1279
+ return normalized === pdfBytes ? pdfBytes : new Uint8Array(normalized);
1280
+ } catch (error) {
1281
+ if (error instanceof PdfPasswordRequiredError) throw error;
1282
+ console.warn(
1283
+ "[PageAssembler] Structural decryption failed; rebuilding document from rendered pages:",
1284
+ error
1285
+ );
1286
+ return rasterizePdfToPdf(pdfBytes);
1287
+ }
1288
+ }
650
1289
  async function imageToPdf(imageFile) {
651
1290
  return new Promise((resolve, reject) => {
652
1291
  const img = new Image();
@@ -722,6 +1361,573 @@ function downloadPdf(pdfBytes, filename) {
722
1361
  a.click();
723
1362
  URL.revokeObjectURL(url);
724
1363
  }
1364
+ function getSigniphiMetadata(pdfDoc) {
1365
+ try {
1366
+ const infoRef = pdfDoc.context.trailerInfo.Info;
1367
+ if (!infoRef) {
1368
+ return null;
1369
+ }
1370
+ const infoObj = pdfDoc.context.lookup(infoRef);
1371
+ if (!infoObj || typeof infoObj.get !== "function") {
1372
+ return null;
1373
+ }
1374
+ const infoDict = infoObj;
1375
+ const metadataObj = infoDict.get(pdfLib.PDFName.of("SigniphiMetadata"));
1376
+ if (!metadataObj) {
1377
+ return null;
1378
+ }
1379
+ const metadataStr = metadataObj.toString();
1380
+ let jsonStr = metadataStr;
1381
+ if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
1382
+ jsonStr = metadataStr.slice(1, -1);
1383
+ } else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
1384
+ jsonStr = metadataStr.slice(1, -1);
1385
+ }
1386
+ const metadata = JSON.parse(jsonStr);
1387
+ return metadata;
1388
+ } catch (error) {
1389
+ console.error("Failed to load Signiphi metadata:", error);
1390
+ return null;
1391
+ }
1392
+ }
1393
+ function getBaseFieldName(encodedName) {
1394
+ let baseName = encodedName;
1395
+ if (baseName.includes("__SIGNER__")) {
1396
+ baseName = baseName.split("__SIGNER__")[0];
1397
+ }
1398
+ if (baseName.includes("__LABEL__")) {
1399
+ baseName = baseName.split("__LABEL__")[0];
1400
+ }
1401
+ if (baseName.includes("__PLACEHOLDER__")) {
1402
+ baseName = baseName.split("__PLACEHOLDER__")[0];
1403
+ }
1404
+ return baseName;
1405
+ }
1406
+ function getSignerFromFieldName(encodedName) {
1407
+ if (encodedName.includes("__SIGNER__")) {
1408
+ const parts = encodedName.split("__SIGNER__");
1409
+ if (parts[1]) {
1410
+ return parts[1].split("__")[0] || parts[1];
1411
+ }
1412
+ }
1413
+ return void 0;
1414
+ }
1415
+ function determineFieldType(fieldName, widgetType) {
1416
+ const baseName = getBaseFieldName(fieldName);
1417
+ const nameLower = baseName.toLowerCase();
1418
+ if (nameLower.includes("_signature") || nameLower.includes("signature")) {
1419
+ return "signature";
1420
+ }
1421
+ if (nameLower.includes("_initials") || nameLower.includes("initials")) {
1422
+ return "initials";
1423
+ }
1424
+ if (nameLower.includes("_date") || nameLower.includes("date")) {
1425
+ return "date";
1426
+ }
1427
+ if (widgetType === "checkbox" || nameLower.includes("checkbox")) {
1428
+ return "checkbox";
1429
+ }
1430
+ if (widgetType === "radio" || nameLower.includes("radio")) {
1431
+ return "radio";
1432
+ }
1433
+ if (widgetType === "dropdown" || widgetType === "select" || nameLower.includes("dropdown")) {
1434
+ return "dropdown";
1435
+ }
1436
+ return "text";
1437
+ }
1438
+ async function extractFieldsFromPdf(pdfBytes) {
1439
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1440
+ const fields = [];
1441
+ const metadata = getSigniphiMetadata(pdfDoc);
1442
+ const form = pdfDoc.getForm();
1443
+ const pdfFields = form.getFields();
1444
+ for (const field of pdfFields) {
1445
+ const fieldName = field.getName();
1446
+ const widgets = field.acroField.getWidgets();
1447
+ const baseName = getBaseFieldName(fieldName);
1448
+ const signerFromName = getSignerFromFieldName(fieldName);
1449
+ let required = false;
1450
+ let options;
1451
+ let widgetType;
1452
+ if (field instanceof pdfLib.PDFTextField) {
1453
+ required = field.isRequired();
1454
+ console.log(`[field-extraction] PDFTextField "${fieldName}" isRequired=${required}`);
1455
+ } else if (field instanceof pdfLib.PDFCheckBox) {
1456
+ widgetType = "checkbox";
1457
+ required = field.isRequired();
1458
+ console.log(`[field-extraction] PDFCheckBox "${fieldName}" isRequired=${required}`);
1459
+ } else if (field instanceof pdfLib.PDFDropdown) {
1460
+ widgetType = "dropdown";
1461
+ required = field.isRequired();
1462
+ options = field.getOptions();
1463
+ console.log(`[field-extraction] PDFDropdown "${fieldName}" isRequired=${required}`);
1464
+ } else if (field instanceof pdfLib.PDFRadioGroup) {
1465
+ widgetType = "radio";
1466
+ required = field.isRequired();
1467
+ options = field.getOptions();
1468
+ console.log(`[field-extraction] PDFRadioGroup "${fieldName}" isRequired=${required}`);
1469
+ } else {
1470
+ console.log(`[field-extraction] Unknown field type "${fieldName}" - defaulting required=false`);
1471
+ }
1472
+ for (const widget of widgets) {
1473
+ const rect = widget.getRectangle();
1474
+ const pageRef = widget.P();
1475
+ let pageNumber = 1;
1476
+ if (pageRef) {
1477
+ const pages = pdfDoc.getPages();
1478
+ for (let i = 0; i < pages.length; i++) {
1479
+ if (pages[i].ref === pageRef) {
1480
+ pageNumber = i + 1;
1481
+ break;
1482
+ }
1483
+ }
1484
+ }
1485
+ const pageQualifiedKey = `${baseName}_p${pageNumber}`;
1486
+ let fieldMetadata = metadata?.fields?.[pageQualifiedKey];
1487
+ if (!fieldMetadata) {
1488
+ fieldMetadata = metadata?.fields?.[fieldName];
1489
+ }
1490
+ if (!fieldMetadata && baseName !== fieldName) {
1491
+ fieldMetadata = metadata?.fields?.[baseName];
1492
+ }
1493
+ let fieldRequired = required;
1494
+ let fieldOptions = options;
1495
+ if (fieldMetadata?.required !== void 0) {
1496
+ fieldRequired = fieldMetadata.required;
1497
+ }
1498
+ if (fieldMetadata?.options?.length) {
1499
+ fieldOptions = fieldMetadata.options;
1500
+ }
1501
+ const page = pdfDoc.getPage(pageNumber - 1);
1502
+ const pageHeight = page.getHeight();
1503
+ const extractedField = {
1504
+ name: baseName,
1505
+ // Use clean base name without __SIGNER__ encoding (signer stored in signer property)
1506
+ type: determineFieldType(fieldName, widgetType),
1507
+ // Uses base name internally
1508
+ page: pageNumber,
1509
+ x: rect.x,
1510
+ y: pageHeight - rect.y - rect.height,
1511
+ // Convert from PDF coords (bottom-left) to top-left
1512
+ width: rect.width,
1513
+ height: rect.height,
1514
+ required: fieldRequired,
1515
+ options: fieldOptions,
1516
+ signer: signerFromName
1517
+ // Extract signer from encoded name
1518
+ };
1519
+ if (fieldMetadata) {
1520
+ if (fieldMetadata.fieldId) {
1521
+ extractedField.fieldId = fieldMetadata.fieldId;
1522
+ }
1523
+ if (fieldMetadata.label) {
1524
+ extractedField.label = fieldMetadata.label;
1525
+ }
1526
+ if (!extractedField.signer && fieldMetadata.signer) {
1527
+ extractedField.signer = fieldMetadata.signer;
1528
+ }
1529
+ if (fieldMetadata.placeholder) {
1530
+ extractedField.placeholder = fieldMetadata.placeholder;
1531
+ }
1532
+ }
1533
+ fields.push(extractedField);
1534
+ }
1535
+ }
1536
+ const deduplicatedFields = fields.reduce((acc, field) => {
1537
+ const newBaseName = getBaseFieldName(field.name);
1538
+ const existingIndex = acc.findIndex((f) => {
1539
+ const existingBaseName = getBaseFieldName(f.name);
1540
+ return existingBaseName === newBaseName && f.page === field.page;
1541
+ });
1542
+ if (existingIndex === -1) {
1543
+ acc.push(field);
1544
+ } else {
1545
+ const existing = acc[existingIndex];
1546
+ acc[existingIndex] = {
1547
+ ...existing,
1548
+ // Prefer non-empty values from either field
1549
+ label: existing.label || field.label,
1550
+ placeholder: existing.placeholder || field.placeholder,
1551
+ required: existing.required || field.required,
1552
+ options: existing.options?.length ? existing.options : field.options,
1553
+ fieldId: existing.fieldId || field.fieldId,
1554
+ // Prefer signer from the field that has it
1555
+ signer: existing.signer || field.signer
1556
+ };
1557
+ }
1558
+ return acc;
1559
+ }, []);
1560
+ return deduplicatedFields;
1561
+ }
1562
+ function setSigniphiMetadata(pdfDoc, metadata) {
1563
+ try {
1564
+ const infoRef = pdfDoc.context.trailerInfo.Info;
1565
+ const infoObj = pdfDoc.context.lookup(infoRef);
1566
+ if (!infoObj || typeof infoObj.set !== "function") {
1567
+ throw new Error("Info object is not a PDFDict or does not have set method");
1568
+ }
1569
+ const infoDict = infoObj;
1570
+ const metadataString = JSON.stringify(metadata);
1571
+ infoDict.set(pdfLib.PDFName.of("SigniphiMetadata"), pdfLib.PDFString.of(metadataString));
1572
+ } catch (error) {
1573
+ console.error("Failed to set Signiphi metadata:", error);
1574
+ throw error;
1575
+ }
1576
+ }
1577
+ var FormFieldType = /* @__PURE__ */ ((FormFieldType2) => {
1578
+ FormFieldType2["TEXT"] = "text";
1579
+ FormFieldType2["SIGNATURE"] = "signature";
1580
+ FormFieldType2["INITIALS"] = "initials";
1581
+ FormFieldType2["DATE"] = "date";
1582
+ FormFieldType2["CHECKBOX"] = "checkbox";
1583
+ FormFieldType2["RADIO"] = "radio";
1584
+ FormFieldType2["DROPDOWN"] = "dropdown";
1585
+ FormFieldType2["TEXT_LABEL"] = "text_label";
1586
+ return FormFieldType2;
1587
+ })(FormFieldType || {});
1588
+ function parseEncodedFieldName(encodedName) {
1589
+ let baseName = encodedName;
1590
+ let label;
1591
+ let signer;
1592
+ if (baseName.includes("__SIGNER__")) {
1593
+ const parts = baseName.split("__SIGNER__");
1594
+ baseName = parts[0];
1595
+ signer = parts[1];
1596
+ }
1597
+ if (baseName.includes("__LABEL__")) {
1598
+ const parts = baseName.split("__LABEL__");
1599
+ baseName = parts[0];
1600
+ label = parts[1];
1601
+ }
1602
+ if (baseName.includes("__PLACEHOLDER__")) {
1603
+ const parts = baseName.split("__PLACEHOLDER__");
1604
+ baseName = parts[0];
1605
+ }
1606
+ return { baseName, label, signer };
1607
+ }
1608
+ function encodeFieldNameWithSigner(fieldName, signerEmail) {
1609
+ const { baseName, signer: existingSigner } = parseEncodedFieldName(fieldName);
1610
+ const finalSigner = existingSigner || signerEmail;
1611
+ if (!finalSigner) return baseName;
1612
+ return `${baseName}__SIGNER__${finalSigner}`;
1613
+ }
1614
+ function encodeFieldNameWithLabelAndSigner(fieldName, label, signerEmail) {
1615
+ const { baseName, label: existingLabel, signer: existingSigner } = parseEncodedFieldName(fieldName);
1616
+ const finalLabel = existingLabel || label;
1617
+ const finalSigner = existingSigner || signerEmail;
1618
+ let name = baseName;
1619
+ if (finalLabel && finalLabel.trim()) {
1620
+ name = `${name}__LABEL__${finalLabel.trim()}`;
1621
+ }
1622
+ if (finalSigner) {
1623
+ name = `${name}__SIGNER__${finalSigner}`;
1624
+ }
1625
+ return name;
1626
+ }
1627
+ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
1628
+ const { removeExistingFields = false, drawLabels = false } = options;
1629
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1630
+ const form = pdfDoc.getForm();
1631
+ const pages = pdfDoc.getPages();
1632
+ if (removeExistingFields) {
1633
+ const existingFields = form.getFields();
1634
+ for (const field of existingFields) {
1635
+ try {
1636
+ const acroField = field.acroField;
1637
+ if (acroField && typeof acroField.getWidgets === "function") {
1638
+ let widgets = acroField.getWidgets();
1639
+ let safetyCounter = 0;
1640
+ const maxIterations = widgets.length + 5;
1641
+ while (widgets.length > 0 && safetyCounter < maxIterations) {
1642
+ try {
1643
+ acroField.removeWidget(widgets.length - 1);
1644
+ widgets = acroField.getWidgets();
1645
+ } catch {
1646
+ break;
1647
+ }
1648
+ safetyCounter++;
1649
+ }
1650
+ }
1651
+ form.removeField(field);
1652
+ } catch (error) {
1653
+ console.warn(`Failed to remove field ${field.getName()}:`, error);
1654
+ try {
1655
+ form.removeField(field);
1656
+ } catch {
1657
+ }
1658
+ }
1659
+ }
1660
+ }
1661
+ const font = await pdfDoc.embedFont(pdfLib.StandardFonts.Helvetica);
1662
+ const fieldNamePages = /* @__PURE__ */ new Map();
1663
+ for (const field of formFields) {
1664
+ const baseName = field.name;
1665
+ if (!fieldNamePages.has(baseName)) {
1666
+ fieldNamePages.set(baseName, /* @__PURE__ */ new Set());
1667
+ }
1668
+ fieldNamePages.get(baseName).add(field.position.page);
1669
+ }
1670
+ const conflictingNames = /* @__PURE__ */ new Set();
1671
+ for (const [name, pages2] of fieldNamePages) {
1672
+ if (pages2.size > 1) {
1673
+ conflictingNames.add(name);
1674
+ }
1675
+ }
1676
+ for (const field of formFields) {
1677
+ const pageIndex = field.position.page - 1;
1678
+ if (pageIndex < 0 || pageIndex >= pages.length) {
1679
+ console.warn(`Field ${field.name} references page ${field.position.page} but PDF only has ${pages.length} pages`);
1680
+ continue;
1681
+ }
1682
+ const page = pages[pageIndex];
1683
+ const { height: pageHeight } = page.getSize();
1684
+ const pdfX = field.position.x;
1685
+ const pdfY = pageHeight - field.position.y - field.position.height;
1686
+ const uniqueFieldName = conflictingNames.has(field.name) ? `${field.name}_p${field.position.page}` : field.name;
1687
+ try {
1688
+ const fieldType = typeof field.type === "string" ? field.type : field.type;
1689
+ switch (fieldType) {
1690
+ case "text" /* TEXT */: {
1691
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1692
+ const textField = form.createTextField(encodedName);
1693
+ textField.addToPage(page, {
1694
+ x: pdfX,
1695
+ y: pdfY,
1696
+ width: field.position.width,
1697
+ height: field.position.height,
1698
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1699
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1700
+ });
1701
+ if (field.label && field.label.trim()) {
1702
+ textField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1703
+ if (drawLabels) {
1704
+ const fontSize = Math.min(10, field.position.height * 0.4);
1705
+ const labelY = pdfY + field.position.height + 5;
1706
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1707
+ }
1708
+ }
1709
+ if (field.defaultValue && field.defaultValue.trim()) {
1710
+ textField.setText(field.defaultValue);
1711
+ }
1712
+ if (field.fontSize && field.fontSize >= 8 && field.fontSize <= 72) {
1713
+ try {
1714
+ textField.setFontSize(field.fontSize);
1715
+ } catch {
1716
+ }
1717
+ }
1718
+ if (field.multiline) {
1719
+ try {
1720
+ textField.enableMultiline();
1721
+ } catch {
1722
+ }
1723
+ }
1724
+ if (field.maxLength && field.maxLength > 0) {
1725
+ try {
1726
+ textField.setMaxLength(field.maxLength);
1727
+ } catch {
1728
+ }
1729
+ }
1730
+ if (field.required) {
1731
+ textField.enableRequired();
1732
+ }
1733
+ break;
1734
+ }
1735
+ case "checkbox" /* CHECKBOX */: {
1736
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1737
+ const checkBox = form.createCheckBox(encodedName);
1738
+ checkBox.addToPage(page, {
1739
+ x: pdfX,
1740
+ y: pdfY,
1741
+ width: field.position.width,
1742
+ height: field.position.height,
1743
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1744
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1745
+ });
1746
+ if (field.defaultValue === "true" || field.defaultValue === "checked") {
1747
+ checkBox.check();
1748
+ }
1749
+ if (field.required) {
1750
+ checkBox.enableRequired();
1751
+ }
1752
+ if (field.label && field.label.trim()) {
1753
+ try {
1754
+ checkBox.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1755
+ } catch {
1756
+ }
1757
+ if (drawLabels) {
1758
+ const fontSize = Math.min(12, field.position.height * 0.6);
1759
+ const labelX = pdfX + field.position.width + 5;
1760
+ const labelY = pdfY + (field.position.height - fontSize) / 2;
1761
+ page.drawText(field.label, { x: labelX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1762
+ }
1763
+ }
1764
+ break;
1765
+ }
1766
+ case "signature" /* SIGNATURE */: {
1767
+ const baseWithSuffix = field.name.endsWith("_signature") ? field.name : `${field.name}_signature`;
1768
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1769
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1770
+ const sigField = form.createTextField(encodedName);
1771
+ sigField.addToPage(page, {
1772
+ x: pdfX,
1773
+ y: pdfY,
1774
+ width: field.position.width,
1775
+ height: field.position.height,
1776
+ borderColor: pdfLib.rgb(0, 0, 1),
1777
+ backgroundColor: pdfLib.rgb(0.9, 0.9, 1)
1778
+ });
1779
+ if (field.label && field.label.trim()) {
1780
+ sigField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1781
+ }
1782
+ sigField.enableReadOnly();
1783
+ if (field.required) {
1784
+ sigField.enableRequired();
1785
+ }
1786
+ break;
1787
+ }
1788
+ case "initials" /* INITIALS */: {
1789
+ const baseWithSuffix = field.name.endsWith("_initials") ? field.name : `${field.name}_initials`;
1790
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1791
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1792
+ const initField = form.createTextField(encodedName);
1793
+ initField.addToPage(page, {
1794
+ x: pdfX,
1795
+ y: pdfY,
1796
+ width: field.position.width,
1797
+ height: field.position.height,
1798
+ borderColor: pdfLib.rgb(0.5, 0, 0.5),
1799
+ backgroundColor: pdfLib.rgb(1, 0.95, 1)
1800
+ });
1801
+ if (field.label && field.label.trim()) {
1802
+ initField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1803
+ }
1804
+ initField.enableReadOnly();
1805
+ if (field.required) {
1806
+ initField.enableRequired();
1807
+ }
1808
+ break;
1809
+ }
1810
+ case "date" /* DATE */: {
1811
+ const baseWithSuffix = field.name.endsWith("_date") ? field.name : `${field.name}_date`;
1812
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1813
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1814
+ const dateField = form.createTextField(encodedName);
1815
+ dateField.addToPage(page, {
1816
+ x: pdfX,
1817
+ y: pdfY,
1818
+ width: field.position.width,
1819
+ height: field.position.height,
1820
+ borderColor: pdfLib.rgb(0, 0.5, 0),
1821
+ backgroundColor: pdfLib.rgb(0.95, 1, 0.95)
1822
+ });
1823
+ if (field.label && field.label.trim()) {
1824
+ dateField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1825
+ }
1826
+ if (field.required) {
1827
+ dateField.enableRequired();
1828
+ }
1829
+ break;
1830
+ }
1831
+ case "dropdown" /* DROPDOWN */: {
1832
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1833
+ const dropdown = form.createDropdown(encodedName);
1834
+ dropdown.addToPage(page, {
1835
+ x: pdfX,
1836
+ y: pdfY,
1837
+ width: field.position.width,
1838
+ height: field.position.height,
1839
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1840
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1841
+ });
1842
+ if (field.options && field.options.length > 0) {
1843
+ dropdown.addOptions(field.options);
1844
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
1845
+ dropdown.select(field.defaultValue);
1846
+ }
1847
+ }
1848
+ if (field.label && field.label.trim()) {
1849
+ try {
1850
+ dropdown.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1851
+ } catch {
1852
+ }
1853
+ if (drawLabels) {
1854
+ const fontSize = Math.min(10, field.position.height * 0.4);
1855
+ const labelY = pdfY + field.position.height + 5;
1856
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1857
+ }
1858
+ }
1859
+ if (field.required) {
1860
+ dropdown.enableRequired();
1861
+ }
1862
+ break;
1863
+ }
1864
+ case "radio" /* RADIO */: {
1865
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1866
+ const radioGroup = form.createRadioGroup(encodedName);
1867
+ if (field.options && field.options.length > 0) {
1868
+ const optionHeight = Math.min(20, field.position.height / field.options.length);
1869
+ const spacing = field.position.height / field.options.length;
1870
+ field.options.forEach((option, index) => {
1871
+ const optionY = pdfY + field.position.height - (index + 1) * spacing + (spacing - optionHeight) / 2;
1872
+ radioGroup.addOptionToPage(option, page, {
1873
+ x: pdfX,
1874
+ y: optionY,
1875
+ width: optionHeight,
1876
+ height: optionHeight,
1877
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1878
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1879
+ });
1880
+ if (drawLabels) {
1881
+ const labelX = pdfX + optionHeight + 5;
1882
+ const labelY = optionY + optionHeight / 4;
1883
+ page.drawText(option, { x: labelX, y: labelY, size: 10, font, color: pdfLib.rgb(0, 0, 0) });
1884
+ }
1885
+ });
1886
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
1887
+ radioGroup.select(field.defaultValue);
1888
+ }
1889
+ }
1890
+ if (field.label && field.label.trim()) {
1891
+ try {
1892
+ radioGroup.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1893
+ } catch {
1894
+ }
1895
+ if (drawLabels) {
1896
+ const fontSize = 10;
1897
+ const labelY = pdfY + field.position.height + 5;
1898
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1899
+ }
1900
+ }
1901
+ if (field.required) {
1902
+ radioGroup.enableRequired();
1903
+ }
1904
+ break;
1905
+ }
1906
+ default:
1907
+ console.warn(`Unknown field type: ${fieldType} for field ${field.name}`);
1908
+ }
1909
+ } catch (error) {
1910
+ console.error(`Error adding field ${field.name}:`, error);
1911
+ }
1912
+ }
1913
+ return await pdfDoc.save();
1914
+ }
1915
+ function mapFieldPositionsAfterAssembly(fields, pageMapping) {
1916
+ return fields.map((field) => {
1917
+ const mappingKey = String(field.position.page - 1);
1918
+ const newPageNumber = pageMapping.get(mappingKey);
1919
+ if (newPageNumber !== void 0) {
1920
+ return {
1921
+ ...field,
1922
+ position: { ...field.position, page: newPageNumber }
1923
+ };
1924
+ }
1925
+ return field;
1926
+ }).filter((field) => {
1927
+ const mappingKey = String(field.position.page - 1);
1928
+ return pageMapping.has(mappingKey) || pageMapping.size === 0;
1929
+ });
1930
+ }
725
1931
  var isMultiSelectModifier = (event) => {
726
1932
  return event.ctrlKey || event.metaKey;
727
1933
  };
@@ -1118,6 +2324,7 @@ var FileCard = ({
1118
2324
  const [newName, setNewName] = React7.useState(file.name);
1119
2325
  const fileSelectedPages = file.pages.filter((p) => selectedPageIds.includes(p.id));
1120
2326
  const allPagesSelected = file.pages.length > 0 && fileSelectedPages.length === file.pages.length;
2327
+ const pendingDropdownAction = React7.useRef(null);
1121
2328
  const [{ isDraggingFile }, dragFile] = reactDnd.useDrag({
1122
2329
  type: DND_TYPES.FILE,
1123
2330
  item: () => {
@@ -1222,23 +2429,38 @@ var FileCard = ({
1222
2429
  ] }) }),
1223
2430
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
1224
2431
  /* @__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
- ] })
2432
+ /* @__PURE__ */ jsxRuntime.jsxs(
2433
+ DropdownMenuContent,
2434
+ {
2435
+ align: "end",
2436
+ className: "w-52",
2437
+ onCloseAutoFocus: () => {
2438
+ pendingDropdownAction.current?.();
2439
+ pendingDropdownAction.current = null;
2440
+ },
2441
+ children: [
2442
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: () => {
2443
+ pendingDropdownAction.current = () => setIsRenaming(true);
2444
+ }, children: [
2445
+ /* @__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" }) }),
2446
+ "Rename File"
2447
+ ] }),
2448
+ /* @__PURE__ */ jsxRuntime.jsxs(
2449
+ DropdownMenuItem,
2450
+ {
2451
+ onSelect: () => {
2452
+ pendingDropdownAction.current = () => onRemoveFile(file.id);
2453
+ },
2454
+ className: "text-red-600 hover:text-red-700 hover:bg-red-50 focus:text-red-700 focus:bg-red-50",
2455
+ children: [
2456
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
2457
+ "Remove File"
2458
+ ]
2459
+ }
2460
+ )
2461
+ ]
2462
+ }
2463
+ )
1242
2464
  ] })
1243
2465
  ] })
1244
2466
  ] }) }),
@@ -1347,6 +2569,7 @@ var PageAssembler = React7.forwardRef(
1347
2569
  );
1348
2570
  const [isLoading, setIsLoading] = React7.useState(false);
1349
2571
  const [processingStatus, setProcessingStatus] = React7.useState("");
2572
+ const [uploadError, setUploadError] = React7.useState(null);
1350
2573
  const [showDeleteConfirm, setShowDeleteConfirm] = React7.useState(false);
1351
2574
  const [showRemoveFileConfirm, setShowRemoveFileConfirm] = React7.useState(false);
1352
2575
  const [fileToRemove, setFileToRemove] = React7.useState(null);
@@ -1354,6 +2577,7 @@ var PageAssembler = React7.forwardRef(
1354
2577
  const processedInitialPdfRef = React7.useRef(null);
1355
2578
  const isDraggingPage = React7.useRef(false);
1356
2579
  const onChangeRef = React7.useRef(onChange);
2580
+ const originalBytesCache = React7.useRef(/* @__PURE__ */ new Map());
1357
2581
  const summary = React7.useMemo(() => ({
1358
2582
  totalFiles: state.files.length,
1359
2583
  totalPages: state.files.reduce((sum, file) => sum + file.pages.length, 0)
@@ -1387,6 +2611,7 @@ var PageAssembler = React7.forwardRef(
1387
2611
  } else {
1388
2612
  pdfBytes = new Uint8Array(pdf);
1389
2613
  }
2614
+ pdfBytes = await normalizeUploadedPdfBytes(pdfBytes);
1390
2615
  const defensiveCopy = new Uint8Array(pdfBytes);
1391
2616
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1392
2617
  if (pages.length === 0) {
@@ -1423,6 +2648,7 @@ var PageAssembler = React7.forwardRef(
1423
2648
  originalFileId: fileId
1424
2649
  }))
1425
2650
  };
2651
+ originalBytesCache.current.set(fileId, originalBytes);
1426
2652
  dispatch({ type: "ADD_FILE", payload: file });
1427
2653
  } catch (error) {
1428
2654
  console.error("Error processing initial PDF:", error);
@@ -1431,8 +2657,9 @@ var PageAssembler = React7.forwardRef(
1431
2657
  setProcessingStatus("");
1432
2658
  }
1433
2659
  }, []);
2660
+ const hasRestorableState = !!initialState && initialState.files.length > 0;
1434
2661
  React7.useEffect(() => {
1435
- if (initialPdf && !initialState) {
2662
+ if (initialPdf && state.files.length === 0 && !hasRestorableState) {
1436
2663
  const pdfIdentifier = initialPdf instanceof Uint8Array ? `uint8array-${initialPdf.length}-${initialPdf[0]}-${initialPdf[initialPdf.length - 1]}` : `${initialPdf.constructor.name}-${initialPdf.size || initialPdf.byteLength}`;
1437
2664
  if (processedInitialPdfRef.current === pdfIdentifier) {
1438
2665
  return;
@@ -1440,15 +2667,16 @@ var PageAssembler = React7.forwardRef(
1440
2667
  processedInitialPdfRef.current = pdfIdentifier;
1441
2668
  processInitialPdf(initialPdf);
1442
2669
  }
1443
- }, [initialPdf, initialState, processInitialPdf]);
2670
+ }, [initialPdf, state.files.length, hasRestorableState, processInitialPdf]);
1444
2671
  React7.useEffect(() => {
1445
- if (initialState) {
2672
+ if (initialState && initialState.files.length > 0) {
1446
2673
  dispatch({ type: "RESET", payload: initialState });
1447
2674
  }
1448
2675
  }, [initialState]);
1449
2676
  const processFiles = React7.useCallback(async (files) => {
1450
2677
  const fileArray = Array.from(files);
1451
2678
  const maxFileSize = (limits?.maxFileSizeMB || 10) * 1024 * 1024;
2679
+ setUploadError(null);
1452
2680
  setIsLoading(true);
1453
2681
  setProcessingStatus(`Processing ${fileArray.length} file${fileArray.length !== 1 ? "s" : ""}...`);
1454
2682
  for (const file of fileArray) {
@@ -1473,8 +2701,9 @@ var PageAssembler = React7.forwardRef(
1473
2701
  if (file.type === "application/pdf") {
1474
2702
  setProcessingStatus(`Processing PDF: ${file.name}`);
1475
2703
  const arrayBuffer = await file.arrayBuffer();
1476
- const pdfBytes = new Uint8Array(arrayBuffer);
2704
+ const pdfBytes = await normalizeUploadedPdfBytes(new Uint8Array(arrayBuffer));
1477
2705
  fileInfo.originalBytes = new Uint8Array(pdfBytes);
2706
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1478
2707
  const defensiveCopy = new Uint8Array(pdfBytes);
1479
2708
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1480
2709
  fileInfo.pages = pages.map((page, index) => ({
@@ -1491,6 +2720,7 @@ var PageAssembler = React7.forwardRef(
1491
2720
  const arrayBuffer = await file.arrayBuffer();
1492
2721
  const imageBytes = new Uint8Array(arrayBuffer);
1493
2722
  fileInfo.originalBytes = new Uint8Array(imageBytes);
2723
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1494
2724
  const thumbUrl = URL.createObjectURL(file);
1495
2725
  const img = new Image();
1496
2726
  const dimensions = await new Promise((resolve) => {
@@ -1521,6 +2751,11 @@ var PageAssembler = React7.forwardRef(
1521
2751
  dispatch({ type: "ADD_FILE", payload: fileInfo });
1522
2752
  } catch (error) {
1523
2753
  console.error(`Error processing file ${file.name}:`, error);
2754
+ if (error instanceof PdfPasswordRequiredError) {
2755
+ setUploadError(`${file.name}: ${error.userMessage}`);
2756
+ } else {
2757
+ setUploadError(`Failed to process "${file.name}". The file may be corrupted or unsupported.`);
2758
+ }
1524
2759
  }
1525
2760
  }
1526
2761
  setIsLoading(false);
@@ -1618,21 +2853,205 @@ var PageAssembler = React7.forwardRef(
1618
2853
  setIsLoading(true);
1619
2854
  setProcessingStatus("Assembling PDF...");
1620
2855
  try {
1621
- const { PDFDocument: PDFDocument2 } = await import('pdf-lib');
1622
- const combinedDoc = await PDFDocument2.create();
2856
+ const { PDFDocument: PDFDocument5, PDFName: PDFName4, PDFString: PDFString4 } = await import('pdf-lib');
1623
2857
  const loadedPdfs = /* @__PURE__ */ new Map();
1624
2858
  const fileMap = /* @__PURE__ */ new Map();
2859
+ const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
2860
+ const imageFiles = state.files.filter((f) => f.type === "image");
2861
+ const isSinglePdfScenario = pdfFiles.length === 1 && imageFiles.length === 0;
1625
2862
  for (const file of state.files) {
1626
2863
  fileMap.set(file.id, file);
1627
- if (file.type === "pdf" && file.originalBytes) {
2864
+ if (file.type === "pdf" && file.originalBytes && file.originalBytes.length > 0) {
1628
2865
  try {
1629
- const sourcePdf = await PDFDocument2.load(file.originalBytes);
2866
+ const sourcePdf = await PDFDocument5.load(file.originalBytes);
1630
2867
  loadedPdfs.set(file.id, sourcePdf);
1631
2868
  } catch (error) {
1632
2869
  console.error(`Error loading PDF for file ${file.id}:`, error);
1633
2870
  }
1634
2871
  }
1635
2872
  }
2873
+ const referencedFileIds = /* @__PURE__ */ new Set();
2874
+ for (const file of state.files) {
2875
+ for (const page of file.pages) {
2876
+ const originalFileId = page.originalFileId || file.id;
2877
+ if (!loadedPdfs.has(originalFileId)) {
2878
+ referencedFileIds.add(originalFileId);
2879
+ }
2880
+ }
2881
+ }
2882
+ for (const fileId of referencedFileIds) {
2883
+ const cachedBytes = originalBytesCache.current.get(fileId);
2884
+ if (cachedBytes && cachedBytes.length > 0) {
2885
+ try {
2886
+ console.log(`[PageAssembler] Loading PDF from cache for deleted file ${fileId}`);
2887
+ const sourcePdf = await PDFDocument5.load(cachedBytes);
2888
+ loadedPdfs.set(fileId, sourcePdf);
2889
+ } catch (error) {
2890
+ console.error(`Error loading cached PDF for file ${fileId}:`, error);
2891
+ }
2892
+ }
2893
+ }
2894
+ console.log("[PageAssembler] Checking single PDF scenario:", {
2895
+ isSinglePdfScenario,
2896
+ pdfFilesCount: pdfFiles.length,
2897
+ imageFilesCount: imageFiles.length
2898
+ });
2899
+ if (isSinglePdfScenario && pdfFiles[0]) {
2900
+ const sourceFile = pdfFiles[0];
2901
+ const sourcePdf = loadedPdfs.get(sourceFile.id);
2902
+ console.log("[PageAssembler] Single PDF check:", {
2903
+ sourcePdfLoaded: !!sourcePdf,
2904
+ pagesCount: sourceFile.pages.length,
2905
+ originalBytesLength: sourceFile.originalBytes?.length
2906
+ });
2907
+ if (sourcePdf) {
2908
+ const desiredPageIndices = sourceFile.pages.map((p) => p.srcIndex);
2909
+ const originalPageCount = sourcePdf.getPageCount();
2910
+ const allPagesFromSameFile = sourceFile.pages.every(
2911
+ (p) => (p.originalFileId || sourceFile.id) === sourceFile.id
2912
+ );
2913
+ const isOriginalOrder = desiredPageIndices.length === originalPageCount && desiredPageIndices.every((idx, i) => idx === i);
2914
+ console.log("[PageAssembler] Original bytes check:", {
2915
+ allPagesFromSameFile,
2916
+ isOriginalOrder,
2917
+ desiredPageIndices,
2918
+ originalPageCount
2919
+ });
2920
+ if (allPagesFromSameFile && isOriginalOrder) {
2921
+ console.log("[PageAssembler] \u2705 Returning ORIGINAL bytes (form fields preserved)");
2922
+ const arrayBuffer2 = sourceFile.originalBytes.buffer.slice(
2923
+ sourceFile.originalBytes.byteOffset,
2924
+ sourceFile.originalBytes.byteOffset + sourceFile.originalBytes.byteLength
2925
+ );
2926
+ const blob2 = new Blob([arrayBuffer2], { type: "application/pdf" });
2927
+ return blob2;
2928
+ } else {
2929
+ console.log("[PageAssembler] \u26A0\uFE0F Pages modified, will use copyPages (form fields may be lost)");
2930
+ }
2931
+ }
2932
+ }
2933
+ console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
2934
+ const allExtractedFields = [];
2935
+ const mergedMetadata = {
2936
+ version: "1.0",
2937
+ fields: {},
2938
+ fieldIdIndex: {}
2939
+ };
2940
+ const filePageUsage = /* @__PURE__ */ new Map();
2941
+ for (const file of state.files) {
2942
+ for (const page of file.pages) {
2943
+ const originalFileId = page.originalFileId || file.id;
2944
+ if (!filePageUsage.has(originalFileId)) {
2945
+ filePageUsage.set(originalFileId, /* @__PURE__ */ new Map());
2946
+ }
2947
+ const pageUsage = filePageUsage.get(originalFileId);
2948
+ if (!pageUsage.has(page.srcIndex)) {
2949
+ pageUsage.set(page.srcIndex, []);
2950
+ }
2951
+ pageUsage.get(page.srcIndex).push(page);
2952
+ }
2953
+ }
2954
+ let combinedPageIndex = 0;
2955
+ const pageIdToNewPageNumber = /* @__PURE__ */ new Map();
2956
+ for (const file of state.files) {
2957
+ for (const page of file.pages) {
2958
+ combinedPageIndex++;
2959
+ pageIdToNewPageNumber.set(page.id, combinedPageIndex);
2960
+ }
2961
+ }
2962
+ console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
2963
+ const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
2964
+ let sourceMetadata = null;
2965
+ if (sourcePdf) {
2966
+ try {
2967
+ const sourceInfoRef = sourcePdf.context.trailerInfo.Info;
2968
+ if (sourceInfoRef) {
2969
+ const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
2970
+ if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
2971
+ const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
2972
+ if (metadataObj) {
2973
+ const metadataStr = metadataObj.toString();
2974
+ let jsonStr = metadataStr;
2975
+ if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
2976
+ jsonStr = metadataStr.slice(1, -1);
2977
+ }
2978
+ sourceMetadata = JSON.parse(jsonStr);
2979
+ }
2980
+ }
2981
+ }
2982
+ } catch (metadataError) {
2983
+ console.warn(`Could not read metadata from PDF ${fileName}:`, metadataError);
2984
+ }
2985
+ }
2986
+ console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
2987
+ const extractedFields = await extractFieldsFromPdf(pdfBytes2);
2988
+ console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
2989
+ const pageUsageForFile = filePageUsage.get(fileId) || /* @__PURE__ */ new Map();
2990
+ for (const field of extractedFields) {
2991
+ const originalPage = field.page;
2992
+ const srcIndex = originalPage - 1;
2993
+ const pageInstances = pageUsageForFile.get(srcIndex) || [];
2994
+ for (const pageInstance of pageInstances) {
2995
+ const newPageNumber = pageIdToNewPageNumber.get(pageInstance.id);
2996
+ if (newPageNumber !== void 0) {
2997
+ const trackedField = {
2998
+ name: field.name,
2999
+ type: field.type,
3000
+ position: {
3001
+ x: field.x,
3002
+ y: field.y,
3003
+ width: field.width,
3004
+ height: field.height,
3005
+ page: newPageNumber
3006
+ // Updated to new page number
3007
+ },
3008
+ pageId: pageInstance.id,
3009
+ originalFileId: fileId,
3010
+ label: field.label,
3011
+ required: field.required,
3012
+ options: field.options,
3013
+ placeholder: field.placeholder,
3014
+ fieldId: field.fieldId,
3015
+ assignedSignerEmail: field.signer
3016
+ };
3017
+ allExtractedFields.push(trackedField);
3018
+ console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
3019
+ const metadataKey = `${field.name}_p${newPageNumber}`;
3020
+ if (sourceMetadata?.fields?.[field.name]) {
3021
+ mergedMetadata.fields[metadataKey] = sourceMetadata.fields[field.name];
3022
+ }
3023
+ if (sourceMetadata?.fieldIdIndex?.[field.name]) {
3024
+ mergedMetadata.fieldIdIndex[metadataKey] = sourceMetadata.fieldIdIndex[field.name];
3025
+ }
3026
+ }
3027
+ }
3028
+ }
3029
+ };
3030
+ const processedFileIds = /* @__PURE__ */ new Set();
3031
+ for (const file of state.files) {
3032
+ if (file.type !== "pdf" || !file.originalBytes || file.originalBytes.length === 0) continue;
3033
+ try {
3034
+ await extractAndMapFields(file.id, file.name, file.originalBytes, loadedPdfs.get(file.id));
3035
+ processedFileIds.add(file.id);
3036
+ } catch (extractError) {
3037
+ console.error(`Error extracting fields from ${file.name}:`, extractError);
3038
+ }
3039
+ }
3040
+ for (const fileId of referencedFileIds) {
3041
+ if (processedFileIds.has(fileId)) continue;
3042
+ const cachedBytes = originalBytesCache.current.get(fileId);
3043
+ if (cachedBytes && cachedBytes.length > 0) {
3044
+ try {
3045
+ console.log(`[PageAssembler] Extracting fields from cached file ${fileId}`);
3046
+ await extractAndMapFields(fileId, `Cached file ${fileId}`, cachedBytes, loadedPdfs.get(fileId));
3047
+ } catch (extractError) {
3048
+ console.error(`Error extracting fields from cached file ${fileId}:`, extractError);
3049
+ }
3050
+ }
3051
+ }
3052
+ console.log(`[PageAssembler] Total extracted fields: ${allExtractedFields.length}`);
3053
+ console.log(`[PageAssembler] Field names:`, allExtractedFields.map((f) => `${f.name} (page ${f.position.page})`));
3054
+ const combinedDoc = await PDFDocument5.create();
1636
3055
  for (const file of state.files) {
1637
3056
  if (file.pages.length === 0) continue;
1638
3057
  for (const page of file.pages) {
@@ -1652,7 +3071,17 @@ var PageAssembler = React7.forwardRef(
1652
3071
  if (page.srcIndex >= 0 && page.srcIndex < sourcePageCount) {
1653
3072
  try {
1654
3073
  const copiedPages = await combinedDoc.copyPages(sourcePdf, [page.srcIndex]);
1655
- copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
3074
+ copiedPages.forEach((copiedPage) => {
3075
+ try {
3076
+ const annotsRef = copiedPage.node.get(PDFName4.of("Annots"));
3077
+ if (annotsRef) {
3078
+ copiedPage.node.delete(PDFName4.of("Annots"));
3079
+ }
3080
+ } catch (annotError) {
3081
+ console.warn("Could not remove annotations from copied page:", annotError);
3082
+ }
3083
+ combinedDoc.addPage(copiedPage);
3084
+ });
1656
3085
  } catch (copyError) {
1657
3086
  console.error(`Error copying page ${page.srcIndex}:`, copyError);
1658
3087
  throw new Error(`Failed to copy page: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
@@ -1661,7 +3090,7 @@ var PageAssembler = React7.forwardRef(
1661
3090
  } else if (sourceFile.type === "image" && sourceFile.originalFile) {
1662
3091
  try {
1663
3092
  const imagePdfBytes = await imageToPdf(sourceFile.originalFile);
1664
- const imagePdf = await PDFDocument2.load(imagePdfBytes);
3093
+ const imagePdf = await PDFDocument5.load(imagePdfBytes);
1665
3094
  const copiedPages = await combinedDoc.copyPages(imagePdf, [0]);
1666
3095
  copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1667
3096
  } catch (imageError) {
@@ -1671,8 +3100,48 @@ var PageAssembler = React7.forwardRef(
1671
3100
  }
1672
3101
  }
1673
3102
  }
1674
- const pdfBytes = await combinedDoc.save();
1675
- const blob = new Blob([pdfBytes.buffer], { type: "application/pdf" });
3103
+ if (Object.keys(mergedMetadata.fields).length > 0) {
3104
+ try {
3105
+ const newInfoRef = combinedDoc.context.trailerInfo.Info;
3106
+ if (newInfoRef) {
3107
+ const newInfoDict = combinedDoc.context.lookup(newInfoRef);
3108
+ if (newInfoDict && typeof newInfoDict.set === "function") {
3109
+ newInfoDict.set(
3110
+ PDFName4.of("SigniphiMetadata"),
3111
+ PDFString4.of(JSON.stringify(mergedMetadata))
3112
+ );
3113
+ }
3114
+ }
3115
+ } catch (metadataError) {
3116
+ console.warn("Could not write merged metadata:", metadataError);
3117
+ }
3118
+ }
3119
+ let pdfBytes = await combinedDoc.save();
3120
+ if (allExtractedFields.length > 0) {
3121
+ console.log(`[PageAssembler] Re-adding ${allExtractedFields.length} fields to combined document`);
3122
+ const fieldsForPdf = allExtractedFields.map((field) => ({
3123
+ name: field.name,
3124
+ type: field.type,
3125
+ position: field.position,
3126
+ label: field.label,
3127
+ required: field.required,
3128
+ options: field.options,
3129
+ placeholder: field.placeholder,
3130
+ assignedSignerEmail: field.assignedSignerEmail
3131
+ }));
3132
+ try {
3133
+ pdfBytes = await addFormFieldsToPdf(pdfBytes, fieldsForPdf, {
3134
+ removeExistingFields: true,
3135
+ // Remove any orphaned field references
3136
+ drawLabels: false
3137
+ });
3138
+ console.log("[PageAssembler] \u2705 Successfully re-added form fields to combined PDF");
3139
+ } catch (addFieldsError) {
3140
+ console.error("[PageAssembler] Error re-adding fields:", addFieldsError);
3141
+ }
3142
+ }
3143
+ const arrayBuffer = pdfBytes.buffer.slice(pdfBytes.byteOffset, pdfBytes.byteOffset + pdfBytes.byteLength);
3144
+ const blob = new Blob([arrayBuffer], { type: "application/pdf" });
1676
3145
  return blob;
1677
3146
  } catch (error) {
1678
3147
  console.error("Error assembling PDF:", error);
@@ -1686,7 +3155,7 @@ var PageAssembler = React7.forwardRef(
1686
3155
  isBusy: () => isLoading,
1687
3156
  getState: () => state
1688
3157
  }), [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: [
3158
+ 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
3159
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1691
3160
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1692
3161
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-medium", children: "Page Assembly" }),
@@ -1725,6 +3194,10 @@ var PageAssembler = React7.forwardRef(
1725
3194
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
1726
3195
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: processingStatus })
1727
3196
  ] }) }),
3197
+ 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: [
3198
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4 text-destructive flex-shrink-0" }),
3199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: uploadError })
3200
+ ] }) }),
1728
3201
  /* @__PURE__ */ jsxRuntime.jsx(
1729
3202
  BulkActionBar,
1730
3203
  {
@@ -1777,9 +3250,9 @@ var PageAssembler = React7.forwardRef(
1777
3250
  ]
1778
3251
  }
1779
3252
  ) : !disableFileUpload && /* @__PURE__ */ jsxRuntime.jsx(
1780
- Card,
3253
+ "div",
1781
3254
  {
1782
- className: "p-12 border-dashed border-2 border-gray-300 hover:border-gray-400 transition-colors cursor-pointer",
3255
+ 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
3256
  onClick: handleFileUpload,
1784
3257
  onDrop: handleDrop,
1785
3258
  onDragOver: handleDragOver,
@@ -1859,14 +3332,24 @@ function debounce(func, wait) {
1859
3332
  timeout = setTimeout(() => func(...args), wait);
1860
3333
  });
1861
3334
  }
1862
- var PageAssembler_default = PageAssembler;
1863
3335
 
1864
3336
  exports.Button = Button;
3337
+ exports.FormFieldType = FormFieldType;
1865
3338
  exports.PageAssembler = PageAssembler;
3339
+ exports.PdfPasswordRequiredError = PdfPasswordRequiredError;
3340
+ exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError;
3341
+ exports.addFormFieldsToPdf = addFormFieldsToPdf;
1866
3342
  exports.createPdfBlobUrl = createPdfBlobUrl;
1867
- exports.default = PageAssembler_default;
3343
+ exports.decryptPdf = decryptPdf;
1868
3344
  exports.downloadPdf = downloadPdf;
3345
+ exports.extractFieldsFromPdf = extractFieldsFromPdf;
3346
+ exports.getSigniphiMetadata = getSigniphiMetadata;
1869
3347
  exports.imageToPdf = imageToPdf;
3348
+ exports.mapFieldPositionsAfterAssembly = mapFieldPositionsAfterAssembly;
3349
+ exports.normalizePdfEncryption = normalizePdfEncryption;
3350
+ exports.normalizeUploadedPdfBytes = normalizeUploadedPdfBytes;
1870
3351
  exports.pdfToImages = pdfToImages;
3352
+ exports.rasterizePdfToPdf = rasterizePdfToPdf;
3353
+ exports.setSigniphiMetadata = setSigniphiMetadata;
1871
3354
  //# sourceMappingURL=index.js.map
1872
3355
  //# sourceMappingURL=index.js.map