@signiphi/page-assembly 0.2.0-beta.2 → 0.2.0-beta.20

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');
@@ -249,8 +247,9 @@ var SelectContent = React7__namespace.forwardRef(({ className, children, positio
249
247
  position,
250
248
  style: {
251
249
  zIndex: 99999,
252
- backgroundColor: "#ffffff",
253
- border: "1px solid #e2e8f0",
250
+ backgroundColor: "hsl(var(--xpa-popover))",
251
+ color: "hsl(var(--xpa-popover-foreground))",
252
+ border: "1px solid hsl(var(--xpa-border))",
254
253
  borderRadius: "0.5rem",
255
254
  boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
256
255
  marginTop: "4px"
@@ -344,16 +343,23 @@ var AlertDialogOverlay = React7__namespace.forwardRef(({ className, ...props },
344
343
  }
345
344
  ));
346
345
  AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
347
- var AlertDialogContent = React7__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { container: document.querySelector(".signiphi-page-assembly"), children: [
346
+ var CENTERED = {
347
+ position: "fixed",
348
+ left: "50%",
349
+ top: "50%",
350
+ transform: "translate(-50%, -50%)"
351
+ };
352
+ var AlertDialogContent = React7__namespace.forwardRef(({ className, style, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { container: document.querySelector(".signiphi-page-assembly"), children: [
348
353
  /* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
349
354
  /* @__PURE__ */ jsxRuntime.jsx(
350
355
  AlertDialogPrimitive__namespace.Content,
351
356
  {
352
357
  ref,
353
358
  className: cn(
354
- "fixed left-[50%] top-[50%] z-[9999] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
359
+ "z-[9999] grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg sm:rounded-lg",
355
360
  className
356
361
  ),
362
+ style: { ...CENTERED, ...style },
357
363
  ...props
358
364
  }
359
365
  )
@@ -469,8 +475,9 @@ var DropdownMenuContent = React7__namespace.forwardRef(({ className, sideOffset
469
475
  ),
470
476
  style: {
471
477
  zIndex: 99999,
472
- backgroundColor: "#ffffff",
473
- border: "1px solid #e2e8f0",
478
+ backgroundColor: "hsl(var(--xpa-popover))",
479
+ color: "hsl(var(--xpa-popover-foreground))",
480
+ border: "1px solid hsl(var(--xpa-border))",
474
481
  borderRadius: "0.5rem",
475
482
  boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
476
483
  padding: "6px"
@@ -576,6 +583,623 @@ var TooltipContent = React7__namespace.forwardRef(({ className, sideOffset = 4,
576
583
  }
577
584
  ));
578
585
  TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
586
+ var PdfPasswordRequiredError = class extends Error {
587
+ constructor() {
588
+ const message = "This PDF is password-protected. Please remove the password and upload it again.";
589
+ super(message);
590
+ this.code = "PDF_PASSWORD_REQUIRED";
591
+ this.recoverable = true;
592
+ this.name = "PdfPasswordRequiredError";
593
+ this.userMessage = message;
594
+ }
595
+ };
596
+ var UnsupportedPdfEncryptionError = class extends Error {
597
+ constructor(detail) {
598
+ super(`This PDF uses an unsupported encryption scheme (${detail}).`);
599
+ this.name = "UnsupportedPdfEncryptionError";
600
+ this.detail = detail;
601
+ }
602
+ };
603
+ function concatBytes(...parts) {
604
+ let total = 0;
605
+ for (const p of parts) total += p.length;
606
+ const out = new Uint8Array(total);
607
+ let offset = 0;
608
+ for (const p of parts) {
609
+ out.set(p, offset);
610
+ offset += p.length;
611
+ }
612
+ return out;
613
+ }
614
+ var MD5_S = [
615
+ 7,
616
+ 12,
617
+ 17,
618
+ 22,
619
+ 7,
620
+ 12,
621
+ 17,
622
+ 22,
623
+ 7,
624
+ 12,
625
+ 17,
626
+ 22,
627
+ 7,
628
+ 12,
629
+ 17,
630
+ 22,
631
+ 5,
632
+ 9,
633
+ 14,
634
+ 20,
635
+ 5,
636
+ 9,
637
+ 14,
638
+ 20,
639
+ 5,
640
+ 9,
641
+ 14,
642
+ 20,
643
+ 5,
644
+ 9,
645
+ 14,
646
+ 20,
647
+ 4,
648
+ 11,
649
+ 16,
650
+ 23,
651
+ 4,
652
+ 11,
653
+ 16,
654
+ 23,
655
+ 4,
656
+ 11,
657
+ 16,
658
+ 23,
659
+ 4,
660
+ 11,
661
+ 16,
662
+ 23,
663
+ 6,
664
+ 10,
665
+ 15,
666
+ 21,
667
+ 6,
668
+ 10,
669
+ 15,
670
+ 21,
671
+ 6,
672
+ 10,
673
+ 15,
674
+ 21,
675
+ 6,
676
+ 10,
677
+ 15,
678
+ 21
679
+ ];
680
+ var MD5_K = (() => {
681
+ const k = new Uint32Array(64);
682
+ for (let i = 0; i < 64; i++) k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 4294967296);
683
+ return k;
684
+ })();
685
+ function md5(input) {
686
+ const bitLen = input.length * 8;
687
+ const paddedLen = (input.length + 8 >> 6) + 1 << 6;
688
+ const buf = new Uint8Array(paddedLen);
689
+ buf.set(input);
690
+ buf[input.length] = 128;
691
+ const dv = new DataView(buf.buffer);
692
+ dv.setUint32(paddedLen - 8, bitLen >>> 0, true);
693
+ dv.setUint32(paddedLen - 4, Math.floor(bitLen / 4294967296), true);
694
+ let a0 = 1732584193;
695
+ let b0 = 4023233417;
696
+ let c0 = 2562383102;
697
+ let d0 = 271733878;
698
+ const M = new Uint32Array(16);
699
+ for (let offset = 0; offset < paddedLen; offset += 64) {
700
+ for (let i = 0; i < 16; i++) M[i] = dv.getUint32(offset + i * 4, true);
701
+ let A = a0;
702
+ let B = b0;
703
+ let C = c0;
704
+ let D = d0;
705
+ for (let i = 0; i < 64; i++) {
706
+ let F;
707
+ let g;
708
+ if (i < 16) {
709
+ F = B & C | ~B & D;
710
+ g = i;
711
+ } else if (i < 32) {
712
+ F = D & B | ~D & C;
713
+ g = 5 * i + 1 & 15;
714
+ } else if (i < 48) {
715
+ F = B ^ C ^ D;
716
+ g = 3 * i + 5 & 15;
717
+ } else {
718
+ F = C ^ (B | ~D);
719
+ g = 7 * i & 15;
720
+ }
721
+ const tmp = D;
722
+ D = C;
723
+ C = B;
724
+ const x = A + F + MD5_K[i] + M[g] | 0;
725
+ const s = MD5_S[i];
726
+ B = B + (x << s | x >>> 32 - s) | 0;
727
+ A = tmp;
728
+ }
729
+ a0 = a0 + A | 0;
730
+ b0 = b0 + B | 0;
731
+ c0 = c0 + C | 0;
732
+ d0 = d0 + D | 0;
733
+ }
734
+ const out = new Uint8Array(16);
735
+ const ov = new DataView(out.buffer);
736
+ ov.setUint32(0, a0 >>> 0, true);
737
+ ov.setUint32(4, b0 >>> 0, true);
738
+ ov.setUint32(8, c0 >>> 0, true);
739
+ ov.setUint32(12, d0 >>> 0, true);
740
+ return out;
741
+ }
742
+ function rc4(key, data) {
743
+ const S = new Uint8Array(256);
744
+ for (let i2 = 0; i2 < 256; i2++) S[i2] = i2;
745
+ let j = 0;
746
+ for (let i2 = 0; i2 < 256; i2++) {
747
+ j = j + S[i2] + key[i2 % key.length] & 255;
748
+ const t = S[i2];
749
+ S[i2] = S[j];
750
+ S[j] = t;
751
+ }
752
+ const out = new Uint8Array(data.length);
753
+ let i = 0;
754
+ j = 0;
755
+ for (let k = 0; k < data.length; k++) {
756
+ i = i + 1 & 255;
757
+ j = j + S[i] & 255;
758
+ const t = S[i];
759
+ S[i] = S[j];
760
+ S[j] = t;
761
+ out[k] = data[k] ^ S[S[i] + S[j] & 255];
762
+ }
763
+ return out;
764
+ }
765
+ function getSubtle() {
766
+ const subtle = globalThis.crypto?.subtle;
767
+ if (!subtle) throw new UnsupportedPdfEncryptionError("WebCrypto is unavailable in this environment");
768
+ return subtle;
769
+ }
770
+ async function sha2(algorithm, data) {
771
+ return new Uint8Array(await getSubtle().digest(algorithm, data));
772
+ }
773
+ async function importAesKey(rawKey, usages) {
774
+ return getSubtle().importKey("raw", rawKey, "AES-CBC", false, usages);
775
+ }
776
+ async function aesCbcEncryptNoPad(rawKey, iv, data) {
777
+ const key = await importAesKey(rawKey, ["encrypt"]);
778
+ const out = new Uint8Array(await getSubtle().encrypt({ name: "AES-CBC", iv }, key, data));
779
+ return out.slice(0, data.length);
780
+ }
781
+ async function aesCbcDecryptNoPad(rawKey, iv, data) {
782
+ const key = await importAesKey(rawKey, ["encrypt", "decrypt"]);
783
+ const lastBlock = data.slice(data.length - 16);
784
+ const padBlock = new Uint8Array(
785
+ await getSubtle().encrypt({ name: "AES-CBC", iv: lastBlock }, key, new Uint8Array(0))
786
+ );
787
+ const joined = concatBytes(data, padBlock);
788
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, joined));
789
+ }
790
+ async function aesDecryptPdfData(rawKey, data) {
791
+ if (data.length < 32) return new Uint8Array(0);
792
+ const iv = data.slice(0, 16);
793
+ let ct = data.slice(16);
794
+ if (ct.length % 16 !== 0) ct = ct.slice(0, ct.length - ct.length % 16);
795
+ try {
796
+ const key = await importAesKey(rawKey, ["decrypt"]);
797
+ return new Uint8Array(await getSubtle().decrypt({ name: "AES-CBC", iv }, key, ct));
798
+ } catch {
799
+ const plain = await aesCbcDecryptNoPad(rawKey, iv, ct);
800
+ const padLen = plain[plain.length - 1];
801
+ return padLen >= 1 && padLen <= 16 ? plain.slice(0, plain.length - padLen) : plain;
802
+ }
803
+ }
804
+ var PAD = new Uint8Array([
805
+ 40,
806
+ 191,
807
+ 78,
808
+ 94,
809
+ 78,
810
+ 117,
811
+ 138,
812
+ 65,
813
+ 100,
814
+ 0,
815
+ 78,
816
+ 86,
817
+ 255,
818
+ 250,
819
+ 1,
820
+ 8,
821
+ 46,
822
+ 46,
823
+ 0,
824
+ 182,
825
+ 208,
826
+ 104,
827
+ 62,
828
+ 128,
829
+ 47,
830
+ 12,
831
+ 169,
832
+ 254,
833
+ 100,
834
+ 83,
835
+ 105,
836
+ 122
837
+ ]);
838
+ var bytesEqual = (a, b) => {
839
+ if (a.length !== b.length) return false;
840
+ let diff = 0;
841
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
842
+ return diff === 0;
843
+ };
844
+ function legacyFileKey(paddedPwd, params) {
845
+ const { revision, keyLen, O, P, id0, encryptMetadata } = params;
846
+ const pBytes = new Uint8Array(4);
847
+ new DataView(pBytes.buffer).setInt32(0, P | 0, true);
848
+ const parts = [paddedPwd, O.slice(0, 32), pBytes, id0];
849
+ if (revision >= 4 && !encryptMetadata) parts.push(new Uint8Array([255, 255, 255, 255]));
850
+ let h = md5(concatBytes(...parts));
851
+ if (revision >= 3) for (let i = 0; i < 50; i++) h = md5(h.slice(0, keyLen));
852
+ return h.slice(0, keyLen);
853
+ }
854
+ function legacyComputeU(fileKey, revision, id0) {
855
+ if (revision === 2) return rc4(fileKey, PAD);
856
+ let d = md5(concatBytes(PAD, id0));
857
+ d = rc4(fileKey, d);
858
+ for (let i = 1; i <= 19; i++) d = rc4(fileKey.map((b) => b ^ i), d);
859
+ return d;
860
+ }
861
+ function legacyUMatches(fileKey, params) {
862
+ const computed = legacyComputeU(fileKey, params.revision, params.id0);
863
+ return params.revision === 2 ? bytesEqual(computed, params.U.slice(0, 32)) : bytesEqual(computed.slice(0, 16), params.U.slice(0, 16));
864
+ }
865
+ function legacyAuthenticateEmptyPassword(params) {
866
+ const userKey = legacyFileKey(PAD, params);
867
+ if (legacyUMatches(userKey, params)) return userKey;
868
+ throw new PdfPasswordRequiredError();
869
+ }
870
+ async function hash2B(password, salt, udata) {
871
+ let k = await sha2("SHA-256", concatBytes(password, salt, udata));
872
+ let e = new Uint8Array(0);
873
+ let i = 0;
874
+ do {
875
+ const block = concatBytes(password, k, udata);
876
+ const k1 = new Uint8Array(block.length * 64);
877
+ for (let rep = 0; rep < 64; rep++) k1.set(block, rep * block.length);
878
+ e = await aesCbcEncryptNoPad(k.slice(0, 16), k.slice(16, 32), k1);
879
+ let sum = 0;
880
+ for (let b = 0; b < 16; b++) sum += e[b];
881
+ const mod = sum % 3;
882
+ k = await sha2(mod === 0 ? "SHA-256" : mod === 1 ? "SHA-384" : "SHA-512", e);
883
+ i++;
884
+ } while (i < 64 || e[e.length - 1] > i - 32);
885
+ return k.slice(0, 32);
886
+ }
887
+ async function v5AuthenticateEmptyPassword(revision, U, UE) {
888
+ const pwd = new Uint8Array(0);
889
+ const zeroIv = new Uint8Array(16);
890
+ const hash = async (salt, udata) => revision === 5 ? sha2("SHA-256", concatBytes(pwd, salt, udata)) : hash2B(pwd, salt, udata);
891
+ const userHash = await hash(U.slice(32, 40), new Uint8Array(0));
892
+ if (bytesEqual(userHash, U.slice(0, 32))) {
893
+ const intermediate = await hash(U.slice(40, 48), new Uint8Array(0));
894
+ return aesCbcDecryptNoPad(intermediate, zeroIv, UE.slice(0, 32));
895
+ }
896
+ throw new PdfPasswordRequiredError();
897
+ }
898
+ var identityCipher = async (data) => data;
899
+ function rc4ObjectCipher(fileKey) {
900
+ return async (data, ref) => {
901
+ const ext = new Uint8Array([
902
+ ref.objectNumber & 255,
903
+ ref.objectNumber >> 8 & 255,
904
+ ref.objectNumber >> 16 & 255,
905
+ ref.generationNumber & 255,
906
+ ref.generationNumber >> 8 & 255
907
+ ]);
908
+ const key = md5(concatBytes(fileKey, ext)).slice(0, Math.min(fileKey.length + 5, 16));
909
+ return rc4(key, data);
910
+ };
911
+ }
912
+ var AES_SALT = new Uint8Array([115, 65, 108, 84]);
913
+ function aes128ObjectCipher(fileKey) {
914
+ return async (data, ref) => {
915
+ const ext = new Uint8Array([
916
+ ref.objectNumber & 255,
917
+ ref.objectNumber >> 8 & 255,
918
+ ref.objectNumber >> 16 & 255,
919
+ ref.generationNumber & 255,
920
+ ref.generationNumber >> 8 & 255
921
+ ]);
922
+ const key = md5(concatBytes(fileKey, ext, AES_SALT)).slice(0, 16);
923
+ return aesDecryptPdfData(key, data);
924
+ };
925
+ }
926
+ function aes256ObjectCipher(fileKey) {
927
+ return async (data) => aesDecryptPdfData(fileKey, data);
928
+ }
929
+ function dictNumber(dict, key) {
930
+ const value = dict.lookup(pdfLib.PDFName.of(key));
931
+ return value instanceof pdfLib.PDFNumber ? value.asNumber() : void 0;
932
+ }
933
+ function dictBytes(dict, key) {
934
+ const value = dict.lookup(pdfLib.PDFName.of(key));
935
+ return value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString ? value.asBytes() : void 0;
936
+ }
937
+ async function buildDocumentCiphers(encDict, id0) {
938
+ const filter = encDict.lookup(pdfLib.PDFName.of("Filter"));
939
+ if (filter !== pdfLib.PDFName.of("Standard")) {
940
+ throw new UnsupportedPdfEncryptionError(`security handler ${String(filter)}`);
941
+ }
942
+ const V = dictNumber(encDict, "V") ?? 0;
943
+ const R = dictNumber(encDict, "R") ?? 0;
944
+ const O = dictBytes(encDict, "O");
945
+ const U = dictBytes(encDict, "U");
946
+ const P = dictNumber(encDict, "P") ?? -1;
947
+ const metadataValue = encDict.lookup(pdfLib.PDFName.of("EncryptMetadata"));
948
+ const encryptMetadata = metadataValue instanceof pdfLib.PDFBool ? metadataValue.asBoolean() : true;
949
+ if (!O || !U) throw new UnsupportedPdfEncryptionError("missing /O or /U");
950
+ if (V === 1 || V === 2) {
951
+ const keyLen = V === 1 ? 5 : (dictNumber(encDict, "Length") ?? 40) / 8;
952
+ const fileKey = legacyAuthenticateEmptyPassword({ revision: R, keyLen, O, U, P, id0, encryptMetadata });
953
+ const cipher = rc4ObjectCipher(fileKey);
954
+ return { stringCipher: cipher, streamCipher: cipher, encryptMetadata };
955
+ }
956
+ if (V === 4 || V === 5) {
957
+ const cf = encDict.lookup(pdfLib.PDFName.of("CF"));
958
+ const cfmOf = (filterKey) => {
959
+ const streamFilter = encDict.lookup(pdfLib.PDFName.of(filterKey));
960
+ if (!(streamFilter instanceof pdfLib.PDFName) || streamFilter === pdfLib.PDFName.of("Identity")) return void 0;
961
+ if (!(cf instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError("missing /CF");
962
+ const cfDict = cf.lookup(streamFilter);
963
+ if (!(cfDict instanceof pdfLib.PDFDict)) throw new UnsupportedPdfEncryptionError(`missing crypt filter ${streamFilter.toString()}`);
964
+ const cfm = cfDict.lookup(pdfLib.PDFName.of("CFM"));
965
+ return cfm instanceof pdfLib.PDFName ? cfm : void 0;
966
+ };
967
+ let fileKey;
968
+ if (V === 5) {
969
+ const UE = dictBytes(encDict, "UE");
970
+ if (!UE) throw new UnsupportedPdfEncryptionError("missing /UE");
971
+ fileKey = await v5AuthenticateEmptyPassword(R, U, UE);
972
+ } else {
973
+ const cryptFilterLengthBits = () => {
974
+ if (!(cf instanceof pdfLib.PDFDict)) return void 0;
975
+ for (const filterKey of ["StmF", "StrF"]) {
976
+ const filter2 = encDict.lookup(pdfLib.PDFName.of(filterKey));
977
+ if (!(filter2 instanceof pdfLib.PDFName) || filter2 === pdfLib.PDFName.of("Identity")) continue;
978
+ const cfDict = cf.lookup(filter2);
979
+ if (!(cfDict instanceof pdfLib.PDFDict)) continue;
980
+ const len = dictNumber(cfDict, "Length");
981
+ if (len === void 0) continue;
982
+ return len < 40 ? len * 8 : len;
983
+ }
984
+ return void 0;
985
+ };
986
+ const keyLenBits = cryptFilterLengthBits() ?? dictNumber(encDict, "Length") ?? 128;
987
+ fileKey = legacyAuthenticateEmptyPassword({
988
+ revision: R,
989
+ keyLen: keyLenBits / 8,
990
+ O,
991
+ U,
992
+ P,
993
+ id0,
994
+ encryptMetadata
995
+ });
996
+ }
997
+ const cipherFor = (cfm) => {
998
+ if (!cfm || cfm === pdfLib.PDFName.of("Identity")) return identityCipher;
999
+ if (cfm === pdfLib.PDFName.of("V2")) return rc4ObjectCipher(fileKey);
1000
+ if (cfm === pdfLib.PDFName.of("AESV2")) return aes128ObjectCipher(fileKey);
1001
+ if (cfm === pdfLib.PDFName.of("AESV3")) return aes256ObjectCipher(fileKey);
1002
+ throw new UnsupportedPdfEncryptionError(`crypt filter method ${cfm.toString()}`);
1003
+ };
1004
+ return {
1005
+ streamCipher: cipherFor(cfmOf("StmF")),
1006
+ stringCipher: cipherFor(cfmOf("StrF")),
1007
+ encryptMetadata
1008
+ };
1009
+ }
1010
+ throw new UnsupportedPdfEncryptionError(`/V ${V}`);
1011
+ }
1012
+ var toHexString = (bytes) => {
1013
+ let hex = "";
1014
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
1015
+ return new pdfLib.PDFHexString(hex.toUpperCase());
1016
+ };
1017
+ function filterIncludesCrypt(dict) {
1018
+ const filter = dict.lookup(pdfLib.PDFName.of("Filter"));
1019
+ if (filter === pdfLib.PDFName.of("Crypt")) return true;
1020
+ if (filter instanceof pdfLib.PDFArray) {
1021
+ for (let i = 0; i < filter.size(); i++) {
1022
+ if (filter.get(i) === pdfLib.PDFName.of("Crypt")) return true;
1023
+ }
1024
+ }
1025
+ return false;
1026
+ }
1027
+ function cryptFilterIsIdentity(dict) {
1028
+ const parms = dict.lookup(pdfLib.PDFName.of("DecodeParms")) ?? dict.lookup(pdfLib.PDFName.of("DP"));
1029
+ const identityParms = (p) => {
1030
+ if (!(p instanceof pdfLib.PDFDict)) return true;
1031
+ const name = p.lookup(pdfLib.PDFName.of("Name"));
1032
+ return !(name instanceof pdfLib.PDFName) || name === pdfLib.PDFName.of("Identity");
1033
+ };
1034
+ if (parms instanceof pdfLib.PDFArray) {
1035
+ for (let i = 0; i < parms.size(); i++) {
1036
+ if (!identityParms(parms.lookup(i))) return false;
1037
+ }
1038
+ return true;
1039
+ }
1040
+ return identityParms(parms);
1041
+ }
1042
+ async function decryptStringsWithin(obj, ref, stringCipher) {
1043
+ if (obj instanceof pdfLib.PDFDict) {
1044
+ const isSignature = obj.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("Sig");
1045
+ for (const [key, value] of obj.entries()) {
1046
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1047
+ if (isSignature && key === pdfLib.PDFName.of("Contents")) continue;
1048
+ obj.set(key, toHexString(await stringCipher(value.asBytes(), ref)));
1049
+ } else {
1050
+ await decryptStringsWithin(value, ref, stringCipher);
1051
+ }
1052
+ }
1053
+ } else if (obj instanceof pdfLib.PDFArray) {
1054
+ for (let i = 0; i < obj.size(); i++) {
1055
+ const value = obj.get(i);
1056
+ if (value instanceof pdfLib.PDFString || value instanceof pdfLib.PDFHexString) {
1057
+ obj.set(i, toHexString(await stringCipher(value.asBytes(), ref)));
1058
+ } else {
1059
+ await decryptStringsWithin(value, ref, stringCipher);
1060
+ }
1061
+ }
1062
+ }
1063
+ }
1064
+ async function decryptLoadedDocument(doc) {
1065
+ const context = doc.context;
1066
+ const encryptRef = context.trailerInfo.Encrypt;
1067
+ const encDict = context.lookup(encryptRef);
1068
+ if (!(encDict instanceof pdfLib.PDFDict)) {
1069
+ throw new UnsupportedPdfEncryptionError("malformed /Encrypt dictionary");
1070
+ }
1071
+ const idArray = context.lookup(context.trailerInfo.ID);
1072
+ const idFirst = idArray instanceof pdfLib.PDFArray ? idArray.get(0) : void 0;
1073
+ const id0 = idFirst instanceof pdfLib.PDFString || idFirst instanceof pdfLib.PDFHexString ? idFirst.asBytes() : new Uint8Array(0);
1074
+ const { stringCipher, streamCipher, encryptMetadata } = await buildDocumentCiphers(encDict, id0);
1075
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1076
+ if (!(obj instanceof pdfLib.PDFInvalidObject)) continue;
1077
+ const raw = new Uint8Array(obj.sizeInBytes());
1078
+ obj.copyBytesInto(raw, 0);
1079
+ try {
1080
+ const parsed = pdfLib.PDFObjectParser.forBytes(raw, context).parseObject();
1081
+ if (parsed instanceof pdfLib.PDFRawStream && parsed.dict.lookup(pdfLib.PDFName.of("Type")) === pdfLib.PDFName.of("ObjStm")) {
1082
+ context.assign(ref, parsed);
1083
+ }
1084
+ } catch {
1085
+ }
1086
+ }
1087
+ const decryptedObjectStreams = [];
1088
+ const structuralStreamRefs = [];
1089
+ for (const [ref, obj] of context.enumerateIndirectObjects()) {
1090
+ if (ref === encryptRef || obj === encDict) continue;
1091
+ if (obj instanceof pdfLib.PDFRawStream) {
1092
+ const type = obj.dict.lookup(pdfLib.PDFName.of("Type"));
1093
+ if (type === pdfLib.PDFName.of("XRef")) {
1094
+ structuralStreamRefs.push(ref);
1095
+ continue;
1096
+ }
1097
+ const isSkippedMetadata = !encryptMetadata && type === pdfLib.PDFName.of("Metadata");
1098
+ if (filterIncludesCrypt(obj.dict)) {
1099
+ if (!cryptFilterIsIdentity(obj.dict)) {
1100
+ throw new UnsupportedPdfEncryptionError("stream-specific /Crypt filter");
1101
+ }
1102
+ } else if (!isSkippedMetadata) {
1103
+ const decrypted = await streamCipher(obj.contents, ref);
1104
+ const replacement = pdfLib.PDFRawStream.of(obj.dict, decrypted);
1105
+ context.assign(ref, replacement);
1106
+ if (type === pdfLib.PDFName.of("ObjStm")) {
1107
+ decryptedObjectStreams.push([ref, replacement]);
1108
+ }
1109
+ }
1110
+ await decryptStringsWithin(obj.dict, ref, stringCipher);
1111
+ } else if (obj instanceof pdfLib.PDFString || obj instanceof pdfLib.PDFHexString) {
1112
+ context.assign(ref, toHexString(await stringCipher(obj.asBytes(), ref)));
1113
+ } else {
1114
+ await decryptStringsWithin(obj, ref, stringCipher);
1115
+ }
1116
+ }
1117
+ for (const [ref, stream] of decryptedObjectStreams) {
1118
+ await pdfLib.PDFObjectStreamParser.forStream(stream).parseIntoContext();
1119
+ context.delete(ref);
1120
+ }
1121
+ for (const ref of structuralStreamRefs) context.delete(ref);
1122
+ delete context.trailerInfo.Encrypt;
1123
+ if (encryptRef instanceof pdfLib.PDFRef) context.delete(encryptRef);
1124
+ return doc.save({
1125
+ useObjectStreams: false,
1126
+ addDefaultPage: false,
1127
+ updateFieldAppearances: false
1128
+ });
1129
+ }
1130
+ async function decryptPdf(pdfBytes) {
1131
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1132
+ ignoreEncryption: true,
1133
+ updateMetadata: false
1134
+ });
1135
+ if (!doc.isEncrypted) return pdfBytes;
1136
+ return decryptLoadedDocument(doc);
1137
+ }
1138
+ var SLASH = 47;
1139
+ var HASH = 35;
1140
+ var ENCRYPT_NAME = "Encrypt";
1141
+ function hexDigit(byte) {
1142
+ if (byte === void 0) return -1;
1143
+ if (byte >= 48 && byte <= 57) return byte - 48;
1144
+ if (byte >= 65 && byte <= 70) return byte - 65 + 10;
1145
+ if (byte >= 97 && byte <= 102) return byte - 97 + 10;
1146
+ return -1;
1147
+ }
1148
+ function matchesEncryptNameAt(bytes, start) {
1149
+ let at = start;
1150
+ for (let k = 0; k < ENCRYPT_NAME.length; k++) {
1151
+ const want = ENCRYPT_NAME.charCodeAt(k);
1152
+ const byte = bytes[at];
1153
+ if (byte === want) {
1154
+ at += 1;
1155
+ continue;
1156
+ }
1157
+ if (byte === HASH) {
1158
+ const high = hexDigit(bytes[at + 1]);
1159
+ const low = hexDigit(bytes[at + 2]);
1160
+ if (high >= 0 && low >= 0 && (high << 4 | low) === want) {
1161
+ at += 3;
1162
+ continue;
1163
+ }
1164
+ }
1165
+ return false;
1166
+ }
1167
+ return true;
1168
+ }
1169
+ function containsEncryptMarker(bytes) {
1170
+ for (let i = 0; i < bytes.length; i++) {
1171
+ if (bytes[i] !== SLASH) continue;
1172
+ if (matchesEncryptNameAt(bytes, i + 1)) return true;
1173
+ }
1174
+ return false;
1175
+ }
1176
+ async function normalizePdfEncryption(pdfBytes, options) {
1177
+ if (!containsEncryptMarker(pdfBytes)) return pdfBytes;
1178
+ const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1179
+ ignoreEncryption: true,
1180
+ updateMetadata: false
1181
+ });
1182
+ if (!doc.isEncrypted) return pdfBytes;
1183
+ options?.logger?.info("[PDF_DECRYPT] Encrypted PDF detected during ingestion; decrypting");
1184
+ return decryptLoadedDocument(doc);
1185
+ }
1186
+
1187
+ // src/utils/pdf-decrypt.ts
1188
+ var PdfPasswordRequiredError2 = PdfPasswordRequiredError;
1189
+ var UnsupportedPdfEncryptionError2 = UnsupportedPdfEncryptionError;
1190
+ var decryptPdf2 = decryptPdf;
1191
+ var consoleLogger = {
1192
+ info(message, ...args) {
1193
+ if (typeof process === "undefined" || process.env?.NODE_ENV !== "production") {
1194
+ console.info(`[PageAssembler] ${message}`, ...args);
1195
+ }
1196
+ }
1197
+ };
1198
+ function normalizePdfEncryption2(pdfBytes) {
1199
+ return normalizePdfEncryption(pdfBytes, { logger: consoleLogger });
1200
+ }
1201
+
1202
+ // src/utils/pdf-helpers.ts
579
1203
  if (typeof window !== "undefined") {
580
1204
  pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
581
1205
  }
@@ -647,6 +1271,68 @@ async function pdfToImages(pdfBytes, options) {
647
1271
  throw error;
648
1272
  }
649
1273
  }
1274
+ var MAX_RASTER_PAGE_COUNT = 500;
1275
+ var MAX_RASTER_CANVAS_PIXELS = 4096 * 4096;
1276
+ var PREFERRED_RASTER_SCALE = 2;
1277
+ function computeRasterScale(width, height) {
1278
+ const area = width * height;
1279
+ if (!Number.isFinite(area) || area <= 0) return PREFERRED_RASTER_SCALE;
1280
+ const preferredPixels = area * PREFERRED_RASTER_SCALE * PREFERRED_RASTER_SCALE;
1281
+ if (preferredPixels <= MAX_RASTER_CANVAS_PIXELS) return PREFERRED_RASTER_SCALE;
1282
+ return Math.sqrt(MAX_RASTER_CANVAS_PIXELS / area);
1283
+ }
1284
+ async function rasterizePdfToPdf(pdfBytes) {
1285
+ if (typeof window !== "undefined") {
1286
+ pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
1287
+ }
1288
+ let sourceDoc;
1289
+ try {
1290
+ sourceDoc = await pdfjsLib__namespace.getDocument({ data: pdfBytes.slice(0), verbosity: 0 }).promise;
1291
+ } catch (error) {
1292
+ if (error?.name === "PasswordException") {
1293
+ throw new PdfPasswordRequiredError2();
1294
+ }
1295
+ throw error;
1296
+ }
1297
+ try {
1298
+ if (sourceDoc.numPages > MAX_RASTER_PAGE_COUNT) {
1299
+ throw new Error(
1300
+ `Cannot rebuild PDF: ${sourceDoc.numPages} pages exceeds the ${MAX_RASTER_PAGE_COUNT}-page limit`
1301
+ );
1302
+ }
1303
+ const outDoc = await pdfLib.PDFDocument.create();
1304
+ for (let pageNum = 1; pageNum <= sourceDoc.numPages; pageNum++) {
1305
+ const page = await sourceDoc.getPage(pageNum);
1306
+ const base = page.getViewport({ scale: 1 });
1307
+ const scale = computeRasterScale(base.width, base.height);
1308
+ const viewport = page.getViewport({ scale });
1309
+ const canvas = document.createElement("canvas");
1310
+ canvas.width = viewport.width;
1311
+ canvas.height = viewport.height;
1312
+ const context = canvas.getContext("2d");
1313
+ await page.render({ canvasContext: context, viewport }).promise;
1314
+ const png = await outDoc.embedPng(canvas.toDataURL("image/png"));
1315
+ const outPage = outDoc.addPage([base.width, base.height]);
1316
+ outPage.drawImage(png, { x: 0, y: 0, width: base.width, height: base.height });
1317
+ }
1318
+ return new Uint8Array(await outDoc.save({ useObjectStreams: false }));
1319
+ } finally {
1320
+ await sourceDoc.destroy();
1321
+ }
1322
+ }
1323
+ async function normalizeUploadedPdfBytes(pdfBytes) {
1324
+ try {
1325
+ const normalized = await normalizePdfEncryption2(pdfBytes);
1326
+ return normalized === pdfBytes ? pdfBytes : new Uint8Array(normalized);
1327
+ } catch (error) {
1328
+ if (error instanceof PdfPasswordRequiredError2) throw error;
1329
+ console.warn(
1330
+ "[PageAssembler] Structural decryption failed; rebuilding document from rendered pages:",
1331
+ error
1332
+ );
1333
+ return rasterizePdfToPdf(pdfBytes);
1334
+ }
1335
+ }
650
1336
  async function imageToPdf(imageFile) {
651
1337
  return new Promise((resolve, reject) => {
652
1338
  const img = new Image();
@@ -722,6 +1408,701 @@ function downloadPdf(pdfBytes, filename) {
722
1408
  a.click();
723
1409
  URL.revokeObjectURL(url);
724
1410
  }
1411
+ var KEY = "SigniphiMetadata";
1412
+ function readMetadata(doc, pdfLib) {
1413
+ let blockPresent = false;
1414
+ try {
1415
+ const infoRef = doc.context.trailerInfo.Info;
1416
+ if (!infoRef) return { metadata: null, blockPresent };
1417
+ const info = doc.context.lookup(infoRef);
1418
+ if (!info || typeof info.get !== "function") return { metadata: null, blockPresent };
1419
+ const value = info.get(pdfLib.PDFName.of(KEY));
1420
+ if (!value) return { metadata: null, blockPresent };
1421
+ blockPresent = true;
1422
+ const json = typeof value.decodeText === "function" ? value.decodeText() : stripDelimiters(value.toString());
1423
+ return { metadata: JSON.parse(json), blockPresent };
1424
+ } catch {
1425
+ return { metadata: null, blockPresent };
1426
+ }
1427
+ }
1428
+ function writeMetadata(doc, metadata, pdfLib) {
1429
+ const info = doc.context.lookup(doc.context.trailerInfo.Info);
1430
+ if (!info || typeof info.set !== "function") {
1431
+ throw new Error("Cannot write SigniphiMetadata: the PDF has no Info dictionary");
1432
+ }
1433
+ info.set(pdfLib.PDFName.of(KEY), pdfLib.PDFHexString.fromText(JSON.stringify(metadata)));
1434
+ }
1435
+ function stripDelimiters(raw) {
1436
+ const wrapped = raw.startsWith("(") && raw.endsWith(")") || raw.startsWith("<") && raw.endsWith(">");
1437
+ return wrapped ? raw.slice(1, -1) : raw;
1438
+ }
1439
+ function textLabelPlacements(source) {
1440
+ const fields = source.metadata?.fields;
1441
+ if (!fields || !source.pages?.length) return [];
1442
+ const out = [];
1443
+ for (const [name, entry] of Object.entries(fields)) {
1444
+ if (entry.type !== "text_label" || !entry.position) continue;
1445
+ for (const { source: page, combined } of source.pages) {
1446
+ if (page === entry.position.page) out.push({ name, page: combined });
1447
+ }
1448
+ }
1449
+ return out;
1450
+ }
1451
+ function toCombinedPage(entry, page) {
1452
+ if (!entry.position && !entry.radioPositions && !entry.radioOptions) return entry;
1453
+ const carried = { ...entry };
1454
+ if (entry.position) carried.position = { ...entry.position, page };
1455
+ if (entry.radioPositions) carried.radioPositions = entry.radioPositions.map((p) => ({ ...p, page }));
1456
+ if (entry.radioOptions) {
1457
+ carried.radioOptions = entry.radioOptions.map((o) => ({ ...o, position: { ...o.position, page } }));
1458
+ }
1459
+ return carried;
1460
+ }
1461
+ function assembleMetadata(sources) {
1462
+ const merged = { version: "1.0", fields: {}, fieldIdIndex: {} };
1463
+ let radioLabelsBaked;
1464
+ let textLabelsBaked;
1465
+ let checkboxLabelsBaked;
1466
+ let legacyRadioStripped;
1467
+ for (const source of sources) {
1468
+ const meta = source.metadata;
1469
+ if (!meta || source.fields.length === 0 && !source.pages?.length) continue;
1470
+ if (meta.radioLabelsBaked === false) radioLabelsBaked = false;
1471
+ else if (meta.radioLabelsBaked === true && radioLabelsBaked === void 0) radioLabelsBaked = true;
1472
+ if (meta.textLabelsBaked === false) textLabelsBaked = false;
1473
+ else if (meta.textLabelsBaked === true && textLabelsBaked === void 0) textLabelsBaked = true;
1474
+ if (meta.checkboxLabelsBaked === false) checkboxLabelsBaked = false;
1475
+ else if (meta.checkboxLabelsBaked === true && checkboxLabelsBaked === void 0) checkboxLabelsBaked = true;
1476
+ legacyRadioStripped = meta.legacyRadioStripped === true && legacyRadioStripped !== false;
1477
+ }
1478
+ for (const source of sources) {
1479
+ const meta = source.metadata;
1480
+ if (!meta) continue;
1481
+ const sourceTextLabelsBaked = meta.textLabelsBaked !== false;
1482
+ for (const { name, page } of [...source.fields, ...textLabelPlacements(source)]) {
1483
+ const key = `${name}_p${page}`;
1484
+ const entry = meta.fields?.[name];
1485
+ if (!entry) continue;
1486
+ const carried = toCombinedPage(entry, page);
1487
+ merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
1488
+ if (entry.fieldId) merged.fieldIdIndex[entry.fieldId] = key;
1489
+ }
1490
+ }
1491
+ if (radioLabelsBaked !== void 0) merged.radioLabelsBaked = radioLabelsBaked;
1492
+ if (textLabelsBaked !== void 0) merged.textLabelsBaked = textLabelsBaked;
1493
+ if (checkboxLabelsBaked !== void 0) merged.checkboxLabelsBaked = checkboxLabelsBaked;
1494
+ if (legacyRadioStripped) merged.legacyRadioStripped = true;
1495
+ const hasEntries = Object.keys(merged.fields).length > 0;
1496
+ const hasMarkers = radioLabelsBaked !== void 0 || textLabelsBaked !== void 0 || checkboxLabelsBaked !== void 0;
1497
+ if (!hasEntries && !hasMarkers) return null;
1498
+ if (Object.keys(merged.fieldIdIndex).length === 0) delete merged.fieldIdIndex;
1499
+ return merged;
1500
+ }
1501
+ function mergeSourceMetadata(sources) {
1502
+ return assembleMetadata(sources);
1503
+ }
1504
+ function getSigniphiMetadata(pdfDoc) {
1505
+ const { metadata, blockPresent } = readMetadata(pdfDoc, { PDFName: pdfLib.PDFName });
1506
+ if (blockPresent && !metadata) {
1507
+ console.error("Failed to load Signiphi metadata: the block is present but will not parse");
1508
+ }
1509
+ return metadata;
1510
+ }
1511
+ function getBaseFieldName(encodedName) {
1512
+ let baseName = encodedName;
1513
+ if (baseName.includes("__SIGNER__")) {
1514
+ baseName = baseName.split("__SIGNER__")[0];
1515
+ }
1516
+ if (baseName.includes("__LABEL__")) {
1517
+ baseName = baseName.split("__LABEL__")[0];
1518
+ }
1519
+ if (baseName.includes("__PLACEHOLDER__")) {
1520
+ baseName = baseName.split("__PLACEHOLDER__")[0];
1521
+ }
1522
+ return baseName;
1523
+ }
1524
+ function stripFieldTypeSuffix(value) {
1525
+ const stripped = value.replace(/_(signature|initials|date)$/i, "");
1526
+ return stripped || value;
1527
+ }
1528
+ function getSignerFromFieldName(encodedName) {
1529
+ if (encodedName.includes("__SIGNER__")) {
1530
+ const parts = encodedName.split("__SIGNER__");
1531
+ if (parts[1]) {
1532
+ const segment = parts[1].split("__")[0] || parts[1];
1533
+ const isTerminal = segment === parts[1];
1534
+ return isTerminal ? stripFieldTypeSuffix(segment) : segment;
1535
+ }
1536
+ }
1537
+ return void 0;
1538
+ }
1539
+ function determineFieldType(fieldName, widgetType) {
1540
+ const baseName = getBaseFieldName(fieldName);
1541
+ const nameLower = baseName.toLowerCase();
1542
+ if (nameLower.includes("_signature") || nameLower.includes("signature")) {
1543
+ return "signature";
1544
+ }
1545
+ if (nameLower.includes("_initials") || nameLower.includes("initials")) {
1546
+ return "initials";
1547
+ }
1548
+ if (nameLower.includes("_date") || nameLower.includes("date")) {
1549
+ return "date";
1550
+ }
1551
+ if (widgetType === "checkbox" || nameLower.includes("checkbox")) {
1552
+ return "checkbox";
1553
+ }
1554
+ if (widgetType === "radio" || nameLower.includes("radio")) {
1555
+ return "radio";
1556
+ }
1557
+ if (widgetType === "dropdown" || widgetType === "select" || nameLower.includes("dropdown")) {
1558
+ return "dropdown";
1559
+ }
1560
+ return "text";
1561
+ }
1562
+ async function extractFieldsFromPdf(pdfBytes) {
1563
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1564
+ const fields = [];
1565
+ const metadata = getSigniphiMetadata(pdfDoc);
1566
+ const form = pdfDoc.getForm();
1567
+ const pdfFields = form.getFields();
1568
+ const pages = pdfDoc.getPages();
1569
+ const pageHeights = pages.map((p) => p.getHeight());
1570
+ const pageIndexByRef = new Map(pages.map((p, i) => [p.ref, i + 1]));
1571
+ const pageNumberOf = (ref) => ref && pageIndexByRef.get(ref) || 1;
1572
+ for (const field of pdfFields) {
1573
+ const fieldName = field.getName();
1574
+ const widgets = field.acroField.getWidgets();
1575
+ const baseName = getBaseFieldName(fieldName);
1576
+ const signerFromName = getSignerFromFieldName(fieldName);
1577
+ let required = false;
1578
+ let options;
1579
+ let widgetType;
1580
+ if (field instanceof pdfLib.PDFTextField) {
1581
+ required = field.isRequired();
1582
+ console.log(`[field-extraction] PDFTextField "${fieldName}" isRequired=${required}`);
1583
+ } else if (field instanceof pdfLib.PDFCheckBox) {
1584
+ widgetType = "checkbox";
1585
+ required = field.isRequired();
1586
+ console.log(`[field-extraction] PDFCheckBox "${fieldName}" isRequired=${required}`);
1587
+ } else if (field instanceof pdfLib.PDFDropdown) {
1588
+ widgetType = "dropdown";
1589
+ required = field.isRequired();
1590
+ options = field.getOptions();
1591
+ console.log(`[field-extraction] PDFDropdown "${fieldName}" isRequired=${required}`);
1592
+ } else if (field instanceof pdfLib.PDFRadioGroup) {
1593
+ widgetType = "radio";
1594
+ required = field.isRequired();
1595
+ options = field.getOptions();
1596
+ console.log(`[field-extraction] PDFRadioGroup "${fieldName}" isRequired=${required}`);
1597
+ } else {
1598
+ console.log(`[field-extraction] Unknown field type "${fieldName}" - defaulting required=false`);
1599
+ }
1600
+ const optionPositionsByPage = /* @__PURE__ */ new Map();
1601
+ if (widgetType === "radio") {
1602
+ for (const w of widgets) {
1603
+ const pageNumber = pageNumberOf(w.P());
1604
+ const r = w.getRectangle();
1605
+ const top = pageHeights[pageNumber - 1] - r.y - r.height;
1606
+ const bucket = optionPositionsByPage.get(pageNumber) ?? [];
1607
+ bucket.push({ x: r.x, y: top, width: r.width, height: r.height });
1608
+ optionPositionsByPage.set(pageNumber, bucket);
1609
+ }
1610
+ }
1611
+ for (const widget of widgets) {
1612
+ const rect = widget.getRectangle();
1613
+ const pageNumber = pageNumberOf(widget.P());
1614
+ const pageQualifiedKey = `${baseName}_p${pageNumber}`;
1615
+ let fieldMetadata = metadata?.fields?.[pageQualifiedKey];
1616
+ if (!fieldMetadata) {
1617
+ fieldMetadata = metadata?.fields?.[fieldName];
1618
+ }
1619
+ if (!fieldMetadata && baseName !== fieldName) {
1620
+ fieldMetadata = metadata?.fields?.[baseName];
1621
+ }
1622
+ let fieldRequired = required;
1623
+ let fieldOptions = options;
1624
+ if (fieldMetadata?.required !== void 0) {
1625
+ fieldRequired = fieldMetadata.required;
1626
+ }
1627
+ if (fieldMetadata?.options?.length) {
1628
+ fieldOptions = fieldMetadata.options;
1629
+ }
1630
+ const pageHeight = pageHeights[pageNumber - 1];
1631
+ const extractedField = {
1632
+ name: baseName,
1633
+ // Use clean base name without __SIGNER__ encoding (signer stored in signer property)
1634
+ // Uses base name internally. A stored date_signed is a declaration the
1635
+ // name can't express, so it wins.
1636
+ type: fieldMetadata?.type === "date_signed" ? "date_signed" : determineFieldType(fieldName, widgetType),
1637
+ page: pageNumber,
1638
+ x: rect.x,
1639
+ y: pageHeight - rect.y - rect.height,
1640
+ // Convert from PDF coords (bottom-left) to top-left
1641
+ width: rect.width,
1642
+ height: rect.height,
1643
+ required: fieldRequired,
1644
+ options: fieldOptions,
1645
+ signer: signerFromName
1646
+ // Extract signer from encoded name
1647
+ };
1648
+ if (widgetType === "radio") {
1649
+ extractedField.optionPositions = optionPositionsByPage.get(pageNumber) ?? [];
1650
+ }
1651
+ if (fieldMetadata) {
1652
+ if (fieldMetadata.fieldId) {
1653
+ extractedField.fieldId = fieldMetadata.fieldId;
1654
+ }
1655
+ if (fieldMetadata.label) {
1656
+ extractedField.label = fieldMetadata.label;
1657
+ }
1658
+ if (!extractedField.signer && fieldMetadata.signer) {
1659
+ extractedField.signer = fieldMetadata.signer;
1660
+ }
1661
+ if (fieldMetadata.placeholder) {
1662
+ extractedField.placeholder = fieldMetadata.placeholder;
1663
+ }
1664
+ }
1665
+ fields.push(extractedField);
1666
+ }
1667
+ }
1668
+ const deduplicatedFields = fields.reduce((acc, field) => {
1669
+ const newBaseName = getBaseFieldName(field.name);
1670
+ const existingIndex = acc.findIndex((f) => {
1671
+ const existingBaseName = getBaseFieldName(f.name);
1672
+ return existingBaseName === newBaseName && f.page === field.page;
1673
+ });
1674
+ if (existingIndex === -1) {
1675
+ acc.push(field);
1676
+ } else {
1677
+ const existing = acc[existingIndex];
1678
+ acc[existingIndex] = {
1679
+ ...existing,
1680
+ // Prefer non-empty values from either field
1681
+ label: existing.label || field.label,
1682
+ placeholder: existing.placeholder || field.placeholder,
1683
+ required: existing.required || field.required,
1684
+ options: existing.options?.length ? existing.options : field.options,
1685
+ fieldId: existing.fieldId || field.fieldId,
1686
+ // Prefer signer from the field that has it
1687
+ signer: existing.signer || field.signer
1688
+ };
1689
+ }
1690
+ return acc;
1691
+ }, []);
1692
+ return deduplicatedFields;
1693
+ }
1694
+ function setSigniphiMetadata(pdfDoc, metadata) {
1695
+ try {
1696
+ writeMetadata(pdfDoc, metadata, { PDFName: pdfLib.PDFName, PDFHexString: pdfLib.PDFHexString });
1697
+ } catch (error) {
1698
+ console.error("Failed to set Signiphi metadata:", error);
1699
+ throw error;
1700
+ }
1701
+ }
1702
+ var SIGNIPHI_CHECKBOX_LABEL_MARKER = "SiPL_Check";
1703
+ var RADIO_BORDER_WIDTH = 1;
1704
+ var FormFieldType = /* @__PURE__ */ ((FormFieldType2) => {
1705
+ FormFieldType2["TEXT"] = "text";
1706
+ FormFieldType2["SIGNATURE"] = "signature";
1707
+ FormFieldType2["INITIALS"] = "initials";
1708
+ FormFieldType2["DATE"] = "date";
1709
+ FormFieldType2["CHECKBOX"] = "checkbox";
1710
+ FormFieldType2["RADIO"] = "radio";
1711
+ FormFieldType2["DROPDOWN"] = "dropdown";
1712
+ FormFieldType2["TEXT_LABEL"] = "text_label";
1713
+ FormFieldType2["DATE_SIGNED"] = "date_signed";
1714
+ return FormFieldType2;
1715
+ })(FormFieldType || {});
1716
+ function parseEncodedFieldName(encodedName) {
1717
+ let baseName = encodedName;
1718
+ let label;
1719
+ let signer;
1720
+ if (baseName.includes("__SIGNER__")) {
1721
+ const parts = baseName.split("__SIGNER__");
1722
+ baseName = parts[0];
1723
+ signer = parts[1];
1724
+ }
1725
+ if (baseName.includes("__LABEL__")) {
1726
+ const parts = baseName.split("__LABEL__");
1727
+ baseName = parts[0];
1728
+ label = parts[1];
1729
+ }
1730
+ if (baseName.includes("__PLACEHOLDER__")) {
1731
+ const parts = baseName.split("__PLACEHOLDER__");
1732
+ baseName = parts[0];
1733
+ }
1734
+ return { baseName, label, signer };
1735
+ }
1736
+ function encodeFieldNameWithSigner(fieldName, signerEmail) {
1737
+ const { baseName, signer: existingSigner } = parseEncodedFieldName(fieldName);
1738
+ const finalSigner = existingSigner || signerEmail;
1739
+ if (!finalSigner) return baseName;
1740
+ return `${baseName}__SIGNER__${finalSigner}`;
1741
+ }
1742
+ function encodeFieldNameWithLabelAndSigner(fieldName, label, signerEmail) {
1743
+ const { baseName, label: existingLabel, signer: existingSigner } = parseEncodedFieldName(fieldName);
1744
+ const finalLabel = existingLabel || label;
1745
+ const finalSigner = existingSigner || signerEmail;
1746
+ let name = baseName;
1747
+ if (finalLabel && finalLabel.trim()) {
1748
+ name = `${name}__LABEL__${finalLabel.trim()}`;
1749
+ }
1750
+ if (finalSigner) {
1751
+ name = `${name}__SIGNER__${finalSigner}`;
1752
+ }
1753
+ return name;
1754
+ }
1755
+ async function addFormFieldsToPdf(pdfBytes, formFields, options = {}) {
1756
+ const { removeExistingFields = false, drawLabels = false } = options;
1757
+ const pdfDoc = await pdfLib.PDFDocument.load(pdfBytes);
1758
+ const form = pdfDoc.getForm();
1759
+ const pages = pdfDoc.getPages();
1760
+ if (removeExistingFields) {
1761
+ const existingFields = form.getFields();
1762
+ for (const field of existingFields) {
1763
+ try {
1764
+ const acroField = field.acroField;
1765
+ if (acroField && typeof acroField.getWidgets === "function") {
1766
+ let widgets = acroField.getWidgets();
1767
+ let safetyCounter = 0;
1768
+ const maxIterations = widgets.length + 5;
1769
+ while (widgets.length > 0 && safetyCounter < maxIterations) {
1770
+ try {
1771
+ acroField.removeWidget(widgets.length - 1);
1772
+ widgets = acroField.getWidgets();
1773
+ } catch {
1774
+ break;
1775
+ }
1776
+ safetyCounter++;
1777
+ }
1778
+ }
1779
+ form.removeField(field);
1780
+ } catch (error) {
1781
+ console.warn(`Failed to remove field ${field.getName()}:`, error);
1782
+ try {
1783
+ form.removeField(field);
1784
+ } catch {
1785
+ }
1786
+ }
1787
+ }
1788
+ }
1789
+ const font = await pdfDoc.embedFont(pdfLib.StandardFonts.Helvetica);
1790
+ const bakedCheckboxCaptions = /* @__PURE__ */ new Map();
1791
+ const fieldNamePages = /* @__PURE__ */ new Map();
1792
+ for (const field of formFields) {
1793
+ const baseName = field.name;
1794
+ if (!fieldNamePages.has(baseName)) {
1795
+ fieldNamePages.set(baseName, /* @__PURE__ */ new Set());
1796
+ }
1797
+ fieldNamePages.get(baseName).add(field.position.page);
1798
+ }
1799
+ const conflictingNames = /* @__PURE__ */ new Set();
1800
+ for (const [name, pages2] of fieldNamePages) {
1801
+ if (pages2.size > 1) {
1802
+ conflictingNames.add(name);
1803
+ }
1804
+ }
1805
+ for (const field of formFields) {
1806
+ const pageIndex = field.position.page - 1;
1807
+ if (pageIndex < 0 || pageIndex >= pages.length) {
1808
+ console.warn(`Field ${field.name} references page ${field.position.page} but PDF only has ${pages.length} pages`);
1809
+ continue;
1810
+ }
1811
+ const page = pages[pageIndex];
1812
+ const { height: pageHeight } = page.getSize();
1813
+ const pdfX = field.position.x;
1814
+ const pdfY = pageHeight - field.position.y - field.position.height;
1815
+ const uniqueFieldName = conflictingNames.has(field.name) ? `${field.name}_p${field.position.page}` : field.name;
1816
+ try {
1817
+ const fieldType = typeof field.type === "string" ? field.type : field.type;
1818
+ switch (fieldType) {
1819
+ case "text" /* TEXT */: {
1820
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1821
+ const textField = form.createTextField(encodedName);
1822
+ textField.addToPage(page, {
1823
+ x: pdfX,
1824
+ y: pdfY,
1825
+ width: field.position.width,
1826
+ height: field.position.height,
1827
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1828
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1829
+ });
1830
+ if (field.label && field.label.trim()) {
1831
+ textField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1832
+ if (drawLabels) {
1833
+ const fontSize = Math.min(10, field.position.height * 0.4);
1834
+ const labelY = pdfY + field.position.height + 5;
1835
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1836
+ }
1837
+ }
1838
+ if (field.defaultValue && field.defaultValue.trim()) {
1839
+ textField.setText(field.defaultValue);
1840
+ }
1841
+ if (field.fontSize && field.fontSize >= 8 && field.fontSize <= 72) {
1842
+ try {
1843
+ textField.setFontSize(field.fontSize);
1844
+ } catch {
1845
+ }
1846
+ }
1847
+ if (field.multiline) {
1848
+ try {
1849
+ textField.enableMultiline();
1850
+ } catch {
1851
+ }
1852
+ }
1853
+ if (field.maxLength && field.maxLength > 0) {
1854
+ try {
1855
+ textField.setMaxLength(field.maxLength);
1856
+ } catch {
1857
+ }
1858
+ }
1859
+ if (field.required) {
1860
+ textField.enableRequired();
1861
+ }
1862
+ break;
1863
+ }
1864
+ case "checkbox" /* CHECKBOX */: {
1865
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1866
+ const checkBox = form.createCheckBox(encodedName);
1867
+ checkBox.addToPage(page, {
1868
+ x: pdfX,
1869
+ y: pdfY,
1870
+ width: field.position.width,
1871
+ height: field.position.height,
1872
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1873
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1874
+ });
1875
+ if (field.defaultValue === "true" || field.defaultValue === "checked") {
1876
+ checkBox.check();
1877
+ }
1878
+ if (field.required) {
1879
+ checkBox.enableRequired();
1880
+ }
1881
+ if (field.label && field.label.trim()) {
1882
+ try {
1883
+ checkBox.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1884
+ } catch {
1885
+ }
1886
+ if (drawLabels) {
1887
+ const fontSize = Math.max(1, field.position.height * 0.4);
1888
+ const labelX = pdfX + field.position.width + 5;
1889
+ const labelY = pdfY + (field.position.height - fontSize) / 2;
1890
+ page.pushOperators(
1891
+ pdfLib.PDFOperator.of(pdfLib.PDFOperatorNames.BeginMarkedContent, [pdfLib.PDFName.of(SIGNIPHI_CHECKBOX_LABEL_MARKER)])
1892
+ );
1893
+ page.drawText(field.label, { x: labelX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1894
+ page.pushOperators(pdfLib.PDFOperator.of(pdfLib.PDFOperatorNames.EndMarkedContent));
1895
+ bakedCheckboxCaptions.set(encodedName, field);
1896
+ }
1897
+ }
1898
+ break;
1899
+ }
1900
+ case "signature" /* SIGNATURE */: {
1901
+ const baseWithSuffix = field.name.endsWith("_signature") ? field.name : `${field.name}_signature`;
1902
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1903
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1904
+ const sigField = form.createTextField(encodedName);
1905
+ sigField.addToPage(page, {
1906
+ x: pdfX,
1907
+ y: pdfY,
1908
+ width: field.position.width,
1909
+ height: field.position.height,
1910
+ borderColor: pdfLib.rgb(0, 0, 1),
1911
+ backgroundColor: pdfLib.rgb(0.9, 0.9, 1)
1912
+ });
1913
+ if (field.label && field.label.trim()) {
1914
+ sigField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1915
+ }
1916
+ sigField.enableReadOnly();
1917
+ if (field.required) {
1918
+ sigField.enableRequired();
1919
+ }
1920
+ break;
1921
+ }
1922
+ case "initials" /* INITIALS */: {
1923
+ const baseWithSuffix = field.name.endsWith("_initials") ? field.name : `${field.name}_initials`;
1924
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1925
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1926
+ const initField = form.createTextField(encodedName);
1927
+ initField.addToPage(page, {
1928
+ x: pdfX,
1929
+ y: pdfY,
1930
+ width: field.position.width,
1931
+ height: field.position.height,
1932
+ borderColor: pdfLib.rgb(0.5, 0, 0.5),
1933
+ backgroundColor: pdfLib.rgb(1, 0.95, 1)
1934
+ });
1935
+ if (field.label && field.label.trim()) {
1936
+ initField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1937
+ }
1938
+ initField.enableReadOnly();
1939
+ if (field.required) {
1940
+ initField.enableRequired();
1941
+ }
1942
+ break;
1943
+ }
1944
+ // DATE_SIGNED is the same widget; its metadata `type` (carried by the
1945
+ // merge, not by this pass) is what tells pdf-signer to stamp it.
1946
+ case "date" /* DATE */:
1947
+ case "date_signed" /* DATE_SIGNED */: {
1948
+ const baseWithSuffix = field.name.endsWith("_date") ? field.name : `${field.name}_date`;
1949
+ const finalName = conflictingNames.has(field.name) ? `${baseWithSuffix}_p${field.position.page}` : baseWithSuffix;
1950
+ const encodedName = encodeFieldNameWithLabelAndSigner(finalName, field.label, field.assignedSignerEmail);
1951
+ const dateField = form.createTextField(encodedName);
1952
+ dateField.addToPage(page, {
1953
+ x: pdfX,
1954
+ y: pdfY,
1955
+ width: field.position.width,
1956
+ height: field.position.height,
1957
+ borderColor: pdfLib.rgb(0, 0.5, 0),
1958
+ backgroundColor: pdfLib.rgb(0.95, 1, 0.95)
1959
+ });
1960
+ if (field.label && field.label.trim()) {
1961
+ dateField.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1962
+ }
1963
+ if (field.required) {
1964
+ dateField.enableRequired();
1965
+ }
1966
+ break;
1967
+ }
1968
+ case "dropdown" /* DROPDOWN */: {
1969
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
1970
+ const dropdown = form.createDropdown(encodedName);
1971
+ dropdown.addToPage(page, {
1972
+ x: pdfX,
1973
+ y: pdfY,
1974
+ width: field.position.width,
1975
+ height: field.position.height,
1976
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
1977
+ backgroundColor: pdfLib.rgb(1, 1, 1)
1978
+ });
1979
+ if (field.options && field.options.length > 0) {
1980
+ dropdown.addOptions(field.options);
1981
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
1982
+ dropdown.select(field.defaultValue);
1983
+ }
1984
+ }
1985
+ if (field.label && field.label.trim()) {
1986
+ try {
1987
+ dropdown.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
1988
+ } catch {
1989
+ }
1990
+ if (drawLabels) {
1991
+ const fontSize = Math.min(10, field.position.height * 0.4);
1992
+ const labelY = pdfY + field.position.height + 5;
1993
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
1994
+ }
1995
+ }
1996
+ if (field.required) {
1997
+ dropdown.enableRequired();
1998
+ }
1999
+ break;
2000
+ }
2001
+ case "radio" /* RADIO */: {
2002
+ const encodedName = encodeFieldNameWithSigner(uniqueFieldName, field.assignedSignerEmail);
2003
+ const radioGroup = form.createRadioGroup(encodedName);
2004
+ if (field.options && field.options.length > 0 && field.optionPositions?.length === field.options.length) {
2005
+ const optionPositions = field.optionPositions;
2006
+ field.options.forEach((option, index) => {
2007
+ const at = optionPositions[index];
2008
+ radioGroup.addOptionToPage(option, page, {
2009
+ x: at.x + RADIO_BORDER_WIDTH / 2,
2010
+ y: pageHeight - at.y - at.height + RADIO_BORDER_WIDTH / 2,
2011
+ width: at.width - RADIO_BORDER_WIDTH,
2012
+ height: at.height - RADIO_BORDER_WIDTH,
2013
+ borderWidth: RADIO_BORDER_WIDTH,
2014
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
2015
+ backgroundColor: pdfLib.rgb(1, 1, 1)
2016
+ });
2017
+ });
2018
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
2019
+ radioGroup.select(field.defaultValue);
2020
+ }
2021
+ } else if (field.options && field.options.length > 0) {
2022
+ const optionHeight = Math.min(20, field.position.height / field.options.length);
2023
+ const spacing = field.position.height / field.options.length;
2024
+ field.options.forEach((option, index) => {
2025
+ const optionY = pdfY + field.position.height - (index + 1) * spacing + (spacing - optionHeight) / 2;
2026
+ radioGroup.addOptionToPage(option, page, {
2027
+ x: pdfX,
2028
+ y: optionY,
2029
+ width: optionHeight,
2030
+ height: optionHeight,
2031
+ borderColor: pdfLib.rgb(0.5, 0.5, 0.5),
2032
+ backgroundColor: pdfLib.rgb(1, 1, 1)
2033
+ });
2034
+ if (drawLabels) {
2035
+ const labelX = pdfX + optionHeight + 5;
2036
+ const labelY = optionY + optionHeight / 4;
2037
+ page.drawText(option, { x: labelX, y: labelY, size: 10, font, color: pdfLib.rgb(0, 0, 0) });
2038
+ }
2039
+ });
2040
+ if (field.defaultValue && field.options.includes(field.defaultValue)) {
2041
+ radioGroup.select(field.defaultValue);
2042
+ }
2043
+ }
2044
+ if (field.label && field.label.trim()) {
2045
+ try {
2046
+ radioGroup.acroField.dict.set(pdfLib.PDFName.of("TU"), pdfLib.PDFString.of(field.label));
2047
+ } catch {
2048
+ }
2049
+ if (drawLabels) {
2050
+ const fontSize = 10;
2051
+ const labelY = pdfY + field.position.height + 5;
2052
+ page.drawText(field.label, { x: pdfX, y: labelY, size: fontSize, font, color: pdfLib.rgb(0, 0, 0) });
2053
+ }
2054
+ }
2055
+ if (field.required) {
2056
+ radioGroup.enableRequired();
2057
+ }
2058
+ break;
2059
+ }
2060
+ default:
2061
+ console.warn(`Unknown field type: ${fieldType} for field ${field.name}`);
2062
+ }
2063
+ } catch (error) {
2064
+ console.error(`Error adding field ${field.name}:`, error);
2065
+ }
2066
+ }
2067
+ recordBakedCheckboxCaptions(pdfDoc, bakedCheckboxCaptions);
2068
+ return await pdfDoc.save();
2069
+ }
2070
+ function recordBakedCheckboxCaptions(pdfDoc, captions) {
2071
+ if (captions.size === 0) return;
2072
+ try {
2073
+ const metadata = getSigniphiMetadata(pdfDoc);
2074
+ if (!metadata) return;
2075
+ metadata.fields ?? (metadata.fields = {});
2076
+ for (const [name, field] of captions) {
2077
+ metadata.fields[name] = {
2078
+ signer: field.assignedSignerEmail,
2079
+ label: field.label,
2080
+ ...metadata.fields[name],
2081
+ checkboxCaptionBaked: true
2082
+ };
2083
+ }
2084
+ setSigniphiMetadata(pdfDoc, metadata);
2085
+ } catch (error) {
2086
+ console.warn("Failed to record baked checkbox captions:", error);
2087
+ }
2088
+ }
2089
+ function mapFieldPositionsAfterAssembly(fields, pageMapping) {
2090
+ return fields.map((field) => {
2091
+ const mappingKey = String(field.position.page - 1);
2092
+ const newPageNumber = pageMapping.get(mappingKey);
2093
+ if (newPageNumber !== void 0) {
2094
+ return {
2095
+ ...field,
2096
+ position: { ...field.position, page: newPageNumber }
2097
+ };
2098
+ }
2099
+ return field;
2100
+ }).filter((field) => {
2101
+ const mappingKey = String(field.position.page - 1);
2102
+ return pageMapping.has(mappingKey) || pageMapping.size === 0;
2103
+ });
2104
+ }
2105
+ var VISIBLE_PAGE_ROWS = 2;
725
2106
  var isMultiSelectModifier = (event) => {
726
2107
  return event.ctrlKey || event.metaKey;
727
2108
  };
@@ -977,7 +2358,7 @@ var DraggablePageThumbnail = ({
977
2358
  ref,
978
2359
  "data-handler-id": handlerId,
979
2360
  className: cn(
980
- "relative group cursor-pointer border-2 rounded-lg overflow-hidden bg-white transition-all",
2361
+ "relative group cursor-pointer border-2 rounded-lg overflow-hidden bg-card transition-all",
981
2362
  isDragging && "opacity-50 scale-95",
982
2363
  isSelected ? "border-primary shadow-md" : "border-gray-200 hover:border-gray-300"
983
2364
  ),
@@ -1005,7 +2386,7 @@ var DraggablePageThumbnail = ({
1005
2386
  }
1006
2387
  },
1007
2388
  onContextMenu: handleContextMenu,
1008
- className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary focus:ring-2 bg-white/90 cursor-pointer"
2389
+ className: "h-4 w-4 rounded border-border text-primary focus:ring-primary focus:ring-2 bg-card/90 cursor-pointer"
1009
2390
  }
1010
2391
  )
1011
2392
  }
@@ -1048,21 +2429,48 @@ var ReorderablePageGrid = ({
1048
2429
  newPages.splice(hoverIndex, 0, draggedPage);
1049
2430
  onReorderPages(file.id, newPages);
1050
2431
  }, [file.id, file.pages, onReorderPages]);
1051
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4", children: file.pages.map((page, index) => /* @__PURE__ */ jsxRuntime.jsx(
1052
- DraggablePageThumbnail,
2432
+ const gridRef = React7.useRef(null);
2433
+ const [maxHeight, setMaxHeight] = React7.useState(void 0);
2434
+ React7.useEffect(() => {
2435
+ const grid = gridRef.current;
2436
+ if (!grid || typeof ResizeObserver === "undefined") return;
2437
+ const measure = () => {
2438
+ const firstThumbnail = grid.firstElementChild;
2439
+ if (!firstThumbnail) return;
2440
+ const rowHeight = firstThumbnail.getBoundingClientRect().height;
2441
+ if (rowHeight <= 0) return;
2442
+ const rowGap = parseFloat(getComputedStyle(grid).rowGap) || 0;
2443
+ setMaxHeight(Math.ceil(rowHeight * VISIBLE_PAGE_ROWS + rowGap * (VISIBLE_PAGE_ROWS - 1)));
2444
+ };
2445
+ measure();
2446
+ const observer = new ResizeObserver(measure);
2447
+ observer.observe(grid);
2448
+ if (grid.firstElementChild) observer.observe(grid.firstElementChild);
2449
+ return () => observer.disconnect();
2450
+ }, [file.pages]);
2451
+ return /* @__PURE__ */ jsxRuntime.jsx(
2452
+ "div",
1053
2453
  {
1054
- page,
1055
- fileId: file.id,
1056
- index,
1057
- isSelected: selectedPageIds.includes(page.id),
1058
- onSingleSelect: onSingleSelectPage,
1059
- onToggleSelect: onTogglePageSelect,
1060
- onRangeSelect: onRangeSelectPage,
1061
- movePageInFile,
1062
- isDraggingPageRef
1063
- },
1064
- page.id
1065
- )) });
2454
+ ref: gridRef,
2455
+ className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4 overflow-y-auto overflow-x-hidden",
2456
+ style: { maxHeight },
2457
+ children: file.pages.map((page, index) => /* @__PURE__ */ jsxRuntime.jsx(
2458
+ DraggablePageThumbnail,
2459
+ {
2460
+ page,
2461
+ fileId: file.id,
2462
+ index,
2463
+ isSelected: selectedPageIds.includes(page.id),
2464
+ onSingleSelect: onSingleSelectPage,
2465
+ onToggleSelect: onTogglePageSelect,
2466
+ onRangeSelect: onRangeSelectPage,
2467
+ movePageInFile,
2468
+ isDraggingPageRef
2469
+ },
2470
+ page.id
2471
+ ))
2472
+ }
2473
+ );
1066
2474
  };
1067
2475
  var FileDropZone = ({
1068
2476
  targetIndex,
@@ -1118,6 +2526,7 @@ var FileCard = ({
1118
2526
  const [newName, setNewName] = React7.useState(file.name);
1119
2527
  const fileSelectedPages = file.pages.filter((p) => selectedPageIds.includes(p.id));
1120
2528
  const allPagesSelected = file.pages.length > 0 && fileSelectedPages.length === file.pages.length;
2529
+ const pendingDropdownAction = React7.useRef(null);
1121
2530
  const [{ isDraggingFile }, dragFile] = reactDnd.useDrag({
1122
2531
  type: DND_TYPES.FILE,
1123
2532
  item: () => {
@@ -1222,23 +2631,38 @@ var FileCard = ({
1222
2631
  ] }) }),
1223
2632
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
1224
2633
  /* @__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
- ] })
2634
+ /* @__PURE__ */ jsxRuntime.jsxs(
2635
+ DropdownMenuContent,
2636
+ {
2637
+ align: "end",
2638
+ className: "w-52",
2639
+ onCloseAutoFocus: () => {
2640
+ pendingDropdownAction.current?.();
2641
+ pendingDropdownAction.current = null;
2642
+ },
2643
+ children: [
2644
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: () => {
2645
+ pendingDropdownAction.current = () => setIsRenaming(true);
2646
+ }, children: [
2647
+ /* @__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" }) }),
2648
+ "Rename File"
2649
+ ] }),
2650
+ /* @__PURE__ */ jsxRuntime.jsxs(
2651
+ DropdownMenuItem,
2652
+ {
2653
+ onSelect: () => {
2654
+ pendingDropdownAction.current = () => onRemoveFile(file.id);
2655
+ },
2656
+ className: "text-red-600 hover:text-red-700 hover:bg-red-50 focus:text-red-700 focus:bg-red-50",
2657
+ children: [
2658
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4 mr-2" }),
2659
+ "Remove File"
2660
+ ]
2661
+ }
2662
+ )
2663
+ ]
2664
+ }
2665
+ )
1242
2666
  ] })
1243
2667
  ] })
1244
2668
  ] }) }),
@@ -1290,7 +2714,7 @@ var BulkActionBar = ({
1290
2714
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Move selected pages to another file" }) })
1291
2715
  ] }) }),
1292
2716
  /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: onMovePages, children: [
1293
- /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "move-select", className: "w-48 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Choose file..." }) }),
2717
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: "move-select", className: "w-48 bg-card", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Choose file..." }) }),
1294
2718
  /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: files.map((file) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: file.id, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1295
2719
  file.type === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "h-4 w-4" }),
1296
2720
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: file.name })
@@ -1319,7 +2743,7 @@ var BulkActionBar = ({
1319
2743
  variant: "outline",
1320
2744
  size: "sm",
1321
2745
  onClick: onClearSelection,
1322
- className: "bg-white",
2746
+ className: "bg-card",
1323
2747
  children: "Clear Selection"
1324
2748
  }
1325
2749
  )
@@ -1347,6 +2771,7 @@ var PageAssembler = React7.forwardRef(
1347
2771
  );
1348
2772
  const [isLoading, setIsLoading] = React7.useState(false);
1349
2773
  const [processingStatus, setProcessingStatus] = React7.useState("");
2774
+ const [uploadError, setUploadError] = React7.useState(null);
1350
2775
  const [showDeleteConfirm, setShowDeleteConfirm] = React7.useState(false);
1351
2776
  const [showRemoveFileConfirm, setShowRemoveFileConfirm] = React7.useState(false);
1352
2777
  const [fileToRemove, setFileToRemove] = React7.useState(null);
@@ -1354,6 +2779,7 @@ var PageAssembler = React7.forwardRef(
1354
2779
  const processedInitialPdfRef = React7.useRef(null);
1355
2780
  const isDraggingPage = React7.useRef(false);
1356
2781
  const onChangeRef = React7.useRef(onChange);
2782
+ const originalBytesCache = React7.useRef(/* @__PURE__ */ new Map());
1357
2783
  const summary = React7.useMemo(() => ({
1358
2784
  totalFiles: state.files.length,
1359
2785
  totalPages: state.files.reduce((sum, file) => sum + file.pages.length, 0)
@@ -1387,6 +2813,7 @@ var PageAssembler = React7.forwardRef(
1387
2813
  } else {
1388
2814
  pdfBytes = new Uint8Array(pdf);
1389
2815
  }
2816
+ pdfBytes = await normalizeUploadedPdfBytes(pdfBytes);
1390
2817
  const defensiveCopy = new Uint8Array(pdfBytes);
1391
2818
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1392
2819
  if (pages.length === 0) {
@@ -1423,6 +2850,7 @@ var PageAssembler = React7.forwardRef(
1423
2850
  originalFileId: fileId
1424
2851
  }))
1425
2852
  };
2853
+ originalBytesCache.current.set(fileId, originalBytes);
1426
2854
  dispatch({ type: "ADD_FILE", payload: file });
1427
2855
  } catch (error) {
1428
2856
  console.error("Error processing initial PDF:", error);
@@ -1431,8 +2859,9 @@ var PageAssembler = React7.forwardRef(
1431
2859
  setProcessingStatus("");
1432
2860
  }
1433
2861
  }, []);
2862
+ const hasRestorableState = !!initialState && initialState.files.length > 0;
1434
2863
  React7.useEffect(() => {
1435
- if (initialPdf && !initialState) {
2864
+ if (initialPdf && state.files.length === 0 && !hasRestorableState) {
1436
2865
  const pdfIdentifier = initialPdf instanceof Uint8Array ? `uint8array-${initialPdf.length}-${initialPdf[0]}-${initialPdf[initialPdf.length - 1]}` : `${initialPdf.constructor.name}-${initialPdf.size || initialPdf.byteLength}`;
1437
2866
  if (processedInitialPdfRef.current === pdfIdentifier) {
1438
2867
  return;
@@ -1440,15 +2869,16 @@ var PageAssembler = React7.forwardRef(
1440
2869
  processedInitialPdfRef.current = pdfIdentifier;
1441
2870
  processInitialPdf(initialPdf);
1442
2871
  }
1443
- }, [initialPdf, initialState, processInitialPdf]);
2872
+ }, [initialPdf, state.files.length, hasRestorableState, processInitialPdf]);
1444
2873
  React7.useEffect(() => {
1445
- if (initialState) {
2874
+ if (initialState && initialState.files.length > 0) {
1446
2875
  dispatch({ type: "RESET", payload: initialState });
1447
2876
  }
1448
2877
  }, [initialState]);
1449
2878
  const processFiles = React7.useCallback(async (files) => {
1450
2879
  const fileArray = Array.from(files);
1451
2880
  const maxFileSize = (limits?.maxFileSizeMB || 10) * 1024 * 1024;
2881
+ setUploadError(null);
1452
2882
  setIsLoading(true);
1453
2883
  setProcessingStatus(`Processing ${fileArray.length} file${fileArray.length !== 1 ? "s" : ""}...`);
1454
2884
  for (const file of fileArray) {
@@ -1473,8 +2903,9 @@ var PageAssembler = React7.forwardRef(
1473
2903
  if (file.type === "application/pdf") {
1474
2904
  setProcessingStatus(`Processing PDF: ${file.name}`);
1475
2905
  const arrayBuffer = await file.arrayBuffer();
1476
- const pdfBytes = new Uint8Array(arrayBuffer);
2906
+ const pdfBytes = await normalizeUploadedPdfBytes(new Uint8Array(arrayBuffer));
1477
2907
  fileInfo.originalBytes = new Uint8Array(pdfBytes);
2908
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1478
2909
  const defensiveCopy = new Uint8Array(pdfBytes);
1479
2910
  const pages = await pdfToImages(defensiveCopy, { hideFormFields: true });
1480
2911
  fileInfo.pages = pages.map((page, index) => ({
@@ -1491,6 +2922,7 @@ var PageAssembler = React7.forwardRef(
1491
2922
  const arrayBuffer = await file.arrayBuffer();
1492
2923
  const imageBytes = new Uint8Array(arrayBuffer);
1493
2924
  fileInfo.originalBytes = new Uint8Array(imageBytes);
2925
+ originalBytesCache.current.set(fileInfo.id, fileInfo.originalBytes);
1494
2926
  const thumbUrl = URL.createObjectURL(file);
1495
2927
  const img = new Image();
1496
2928
  const dimensions = await new Promise((resolve) => {
@@ -1521,6 +2953,11 @@ var PageAssembler = React7.forwardRef(
1521
2953
  dispatch({ type: "ADD_FILE", payload: fileInfo });
1522
2954
  } catch (error) {
1523
2955
  console.error(`Error processing file ${file.name}:`, error);
2956
+ if (error instanceof PdfPasswordRequiredError2) {
2957
+ setUploadError(`${file.name}: ${error.userMessage}`);
2958
+ } else {
2959
+ setUploadError(`Failed to process "${file.name}". The file may be corrupted or unsupported.`);
2960
+ }
1524
2961
  }
1525
2962
  }
1526
2963
  setIsLoading(false);
@@ -1618,21 +3055,207 @@ var PageAssembler = React7.forwardRef(
1618
3055
  setIsLoading(true);
1619
3056
  setProcessingStatus("Assembling PDF...");
1620
3057
  try {
1621
- const { PDFDocument: PDFDocument2 } = await import('pdf-lib');
1622
- const combinedDoc = await PDFDocument2.create();
3058
+ const { PDFDocument: PDFDocument5, PDFName: PDFName4 } = await import('pdf-lib');
1623
3059
  const loadedPdfs = /* @__PURE__ */ new Map();
1624
3060
  const fileMap = /* @__PURE__ */ new Map();
3061
+ const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
3062
+ const imageFiles = state.files.filter((f) => f.type === "image");
3063
+ const isSinglePdfScenario = pdfFiles.length === 1 && imageFiles.length === 0;
1625
3064
  for (const file of state.files) {
1626
3065
  fileMap.set(file.id, file);
1627
3066
  if (file.type === "pdf" && file.originalBytes && file.originalBytes.length > 0) {
1628
3067
  try {
1629
- const sourcePdf = await PDFDocument2.load(file.originalBytes);
3068
+ const sourcePdf = await PDFDocument5.load(file.originalBytes);
1630
3069
  loadedPdfs.set(file.id, sourcePdf);
1631
3070
  } catch (error) {
1632
3071
  console.error(`Error loading PDF for file ${file.id}:`, error);
1633
3072
  }
1634
3073
  }
1635
3074
  }
3075
+ const referencedFileIds = /* @__PURE__ */ new Set();
3076
+ for (const file of state.files) {
3077
+ for (const page of file.pages) {
3078
+ const originalFileId = page.originalFileId || file.id;
3079
+ if (!loadedPdfs.has(originalFileId)) {
3080
+ referencedFileIds.add(originalFileId);
3081
+ }
3082
+ }
3083
+ }
3084
+ for (const fileId of referencedFileIds) {
3085
+ const cachedBytes = originalBytesCache.current.get(fileId);
3086
+ if (cachedBytes && cachedBytes.length > 0) {
3087
+ try {
3088
+ console.log(`[PageAssembler] Loading PDF from cache for deleted file ${fileId}`);
3089
+ const sourcePdf = await PDFDocument5.load(cachedBytes);
3090
+ loadedPdfs.set(fileId, sourcePdf);
3091
+ } catch (error) {
3092
+ console.error(`Error loading cached PDF for file ${fileId}:`, error);
3093
+ }
3094
+ }
3095
+ }
3096
+ console.log("[PageAssembler] Checking single PDF scenario:", {
3097
+ isSinglePdfScenario,
3098
+ pdfFilesCount: pdfFiles.length,
3099
+ imageFilesCount: imageFiles.length
3100
+ });
3101
+ if (isSinglePdfScenario && pdfFiles[0]) {
3102
+ const sourceFile = pdfFiles[0];
3103
+ const sourcePdf = loadedPdfs.get(sourceFile.id);
3104
+ console.log("[PageAssembler] Single PDF check:", {
3105
+ sourcePdfLoaded: !!sourcePdf,
3106
+ pagesCount: sourceFile.pages.length,
3107
+ originalBytesLength: sourceFile.originalBytes?.length
3108
+ });
3109
+ if (sourcePdf) {
3110
+ const desiredPageIndices = sourceFile.pages.map((p) => p.srcIndex);
3111
+ const originalPageCount = sourcePdf.getPageCount();
3112
+ const allPagesFromSameFile = sourceFile.pages.every(
3113
+ (p) => (p.originalFileId || sourceFile.id) === sourceFile.id
3114
+ );
3115
+ const isOriginalOrder = desiredPageIndices.length === originalPageCount && desiredPageIndices.every((idx, i) => idx === i);
3116
+ console.log("[PageAssembler] Original bytes check:", {
3117
+ allPagesFromSameFile,
3118
+ isOriginalOrder,
3119
+ desiredPageIndices,
3120
+ originalPageCount
3121
+ });
3122
+ if (allPagesFromSameFile && isOriginalOrder) {
3123
+ console.log("[PageAssembler] \u2705 Returning ORIGINAL bytes (form fields preserved)");
3124
+ const arrayBuffer2 = sourceFile.originalBytes.buffer.slice(
3125
+ sourceFile.originalBytes.byteOffset,
3126
+ sourceFile.originalBytes.byteOffset + sourceFile.originalBytes.byteLength
3127
+ );
3128
+ const blob2 = new Blob([arrayBuffer2], { type: "application/pdf" });
3129
+ return blob2;
3130
+ } else {
3131
+ console.log("[PageAssembler] \u26A0\uFE0F Pages modified, will use copyPages (form fields may be lost)");
3132
+ }
3133
+ }
3134
+ }
3135
+ console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
3136
+ const allExtractedFields = [];
3137
+ const metadataSources = [];
3138
+ const filePageUsage = /* @__PURE__ */ new Map();
3139
+ for (const file of state.files) {
3140
+ for (const page of file.pages) {
3141
+ const originalFileId = page.originalFileId || file.id;
3142
+ if (!filePageUsage.has(originalFileId)) {
3143
+ filePageUsage.set(originalFileId, /* @__PURE__ */ new Map());
3144
+ }
3145
+ const pageUsage = filePageUsage.get(originalFileId);
3146
+ if (!pageUsage.has(page.srcIndex)) {
3147
+ pageUsage.set(page.srcIndex, []);
3148
+ }
3149
+ pageUsage.get(page.srcIndex).push(page);
3150
+ }
3151
+ }
3152
+ let combinedPageIndex = 0;
3153
+ const pageIdToNewPageNumber = /* @__PURE__ */ new Map();
3154
+ for (const file of state.files) {
3155
+ for (const page of file.pages) {
3156
+ combinedPageIndex++;
3157
+ pageIdToNewPageNumber.set(page.id, combinedPageIndex);
3158
+ }
3159
+ }
3160
+ console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
3161
+ const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
3162
+ const sourceMetadata = sourcePdf ? getSigniphiMetadata(sourcePdf) : null;
3163
+ if (sourcePdf && !sourceMetadata) {
3164
+ console.warn(`[PageAssembler] No readable SigniphiMetadata in "${fileName}"`);
3165
+ }
3166
+ const pageUsageForFile = filePageUsage.get(fileId) || /* @__PURE__ */ new Map();
3167
+ const placements = [];
3168
+ const pageLandings = [];
3169
+ for (const [srcIndex, pageInstances] of pageUsageForFile) {
3170
+ for (const pageInstance of pageInstances) {
3171
+ const combined = pageIdToNewPageNumber.get(pageInstance.id);
3172
+ if (combined !== void 0) pageLandings.push({ source: srcIndex + 1, combined });
3173
+ }
3174
+ }
3175
+ metadataSources.push({ metadata: sourceMetadata, fields: placements, pages: pageLandings });
3176
+ console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
3177
+ const extractedFields = await extractFieldsFromPdf(pdfBytes2);
3178
+ console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
3179
+ for (const field of extractedFields) {
3180
+ const originalPage = field.page;
3181
+ const srcIndex = originalPage - 1;
3182
+ const pageInstances = pageUsageForFile.get(srcIndex) || [];
3183
+ for (const pageInstance of pageInstances) {
3184
+ const newPageNumber = pageIdToNewPageNumber.get(pageInstance.id);
3185
+ if (newPageNumber !== void 0) {
3186
+ const trackedField = {
3187
+ name: field.name,
3188
+ type: field.type,
3189
+ position: {
3190
+ x: field.x,
3191
+ y: field.y,
3192
+ width: field.width,
3193
+ height: field.height,
3194
+ page: newPageNumber
3195
+ // Updated to new page number
3196
+ },
3197
+ pageId: pageInstance.id,
3198
+ originalFileId: fileId,
3199
+ label: field.label,
3200
+ required: field.required,
3201
+ options: field.options,
3202
+ optionPositions: field.optionPositions,
3203
+ placeholder: field.placeholder,
3204
+ fieldId: field.fieldId,
3205
+ assignedSignerEmail: field.signer
3206
+ };
3207
+ allExtractedFields.push(trackedField);
3208
+ console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
3209
+ placements.push({ name: field.name, page: newPageNumber });
3210
+ }
3211
+ }
3212
+ }
3213
+ };
3214
+ const processedFileIds = /* @__PURE__ */ new Set();
3215
+ for (const file of state.files) {
3216
+ if (file.type !== "pdf" || !file.originalBytes || file.originalBytes.length === 0) continue;
3217
+ try {
3218
+ await extractAndMapFields(file.id, file.name, file.originalBytes, loadedPdfs.get(file.id));
3219
+ processedFileIds.add(file.id);
3220
+ } catch (extractError) {
3221
+ console.error(`Error extracting fields from ${file.name}:`, extractError);
3222
+ }
3223
+ }
3224
+ for (const fileId of referencedFileIds) {
3225
+ if (processedFileIds.has(fileId)) continue;
3226
+ const cachedBytes = originalBytesCache.current.get(fileId);
3227
+ if (cachedBytes && cachedBytes.length > 0) {
3228
+ try {
3229
+ console.log(`[PageAssembler] Extracting fields from cached file ${fileId}`);
3230
+ await extractAndMapFields(fileId, `Cached file ${fileId}`, cachedBytes, loadedPdfs.get(fileId));
3231
+ } catch (extractError) {
3232
+ console.error(`Error extracting fields from cached file ${fileId}:`, extractError);
3233
+ }
3234
+ }
3235
+ }
3236
+ console.log(`[PageAssembler] Total extracted fields: ${allExtractedFields.length}`);
3237
+ console.log(`[PageAssembler] Field names:`, allExtractedFields.map((f) => `${f.name} (page ${f.position.page})`));
3238
+ const combinedDoc = await PDFDocument5.create();
3239
+ const copyOrderBySource = /* @__PURE__ */ new Map();
3240
+ for (const file of state.files) {
3241
+ for (const page of file.pages) {
3242
+ const originalFileId = page.originalFileId || file.id;
3243
+ const sourcePdf = fileMap.get(originalFileId)?.type === "pdf" ? loadedPdfs.get(originalFileId) : void 0;
3244
+ if (!sourcePdf || page.srcIndex < 0 || page.srcIndex >= sourcePdf.getPageCount()) continue;
3245
+ const order = copyOrderBySource.get(originalFileId) ?? [];
3246
+ order.push(page.srcIndex);
3247
+ copyOrderBySource.set(originalFileId, order);
3248
+ }
3249
+ }
3250
+ const copiedPagesBySource = /* @__PURE__ */ new Map();
3251
+ for (const [fileId, order] of copyOrderBySource) {
3252
+ try {
3253
+ copiedPagesBySource.set(fileId, await combinedDoc.copyPages(loadedPdfs.get(fileId), order));
3254
+ } catch (copyError) {
3255
+ console.error(`Error copying pages from ${fileId}:`, copyError);
3256
+ throw new Error(`Failed to copy page: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
3257
+ }
3258
+ }
1636
3259
  for (const file of state.files) {
1637
3260
  if (file.pages.length === 0) continue;
1638
3261
  for (const page of file.pages) {
@@ -1650,18 +3273,21 @@ var PageAssembler = React7.forwardRef(
1650
3273
  }
1651
3274
  const sourcePageCount = sourcePdf.getPageCount();
1652
3275
  if (page.srcIndex >= 0 && page.srcIndex < sourcePageCount) {
3276
+ const copiedPage = copiedPagesBySource.get(originalFileId).shift();
1653
3277
  try {
1654
- const copiedPages = await combinedDoc.copyPages(sourcePdf, [page.srcIndex]);
1655
- copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1656
- } catch (copyError) {
1657
- console.error(`Error copying page ${page.srcIndex}:`, copyError);
1658
- throw new Error(`Failed to copy page: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
3278
+ const annotsRef = copiedPage.node.get(PDFName4.of("Annots"));
3279
+ if (annotsRef) {
3280
+ copiedPage.node.delete(PDFName4.of("Annots"));
3281
+ }
3282
+ } catch (annotError) {
3283
+ console.warn("Could not remove annotations from copied page:", annotError);
1659
3284
  }
3285
+ combinedDoc.addPage(copiedPage);
1660
3286
  }
1661
3287
  } else if (sourceFile.type === "image" && sourceFile.originalFile) {
1662
3288
  try {
1663
3289
  const imagePdfBytes = await imageToPdf(sourceFile.originalFile);
1664
- const imagePdf = await PDFDocument2.load(imagePdfBytes);
3290
+ const imagePdf = await PDFDocument5.load(imagePdfBytes);
1665
3291
  const copiedPages = await combinedDoc.copyPages(imagePdf, [0]);
1666
3292
  copiedPages.forEach((copiedPage) => combinedDoc.addPage(copiedPage));
1667
3293
  } catch (imageError) {
@@ -1671,7 +3297,41 @@ var PageAssembler = React7.forwardRef(
1671
3297
  }
1672
3298
  }
1673
3299
  }
1674
- const pdfBytes = await combinedDoc.save();
3300
+ const mergedMetadata = mergeSourceMetadata(metadataSources);
3301
+ if (mergedMetadata) {
3302
+ try {
3303
+ setSigniphiMetadata(combinedDoc, mergedMetadata);
3304
+ } catch (metadataError) {
3305
+ console.warn("Could not write merged metadata:", metadataError);
3306
+ }
3307
+ } else {
3308
+ console.warn("[PageAssembler] No source metadata survived the merge; the assembled document will read as unprepared downstream");
3309
+ }
3310
+ let pdfBytes = await combinedDoc.save();
3311
+ if (allExtractedFields.length > 0) {
3312
+ console.log(`[PageAssembler] Re-adding ${allExtractedFields.length} fields to combined document`);
3313
+ const fieldsForPdf = allExtractedFields.map((field) => ({
3314
+ name: field.name,
3315
+ type: field.type,
3316
+ position: field.position,
3317
+ label: field.label,
3318
+ required: field.required,
3319
+ options: field.options,
3320
+ optionPositions: field.optionPositions,
3321
+ placeholder: field.placeholder,
3322
+ assignedSignerEmail: field.assignedSignerEmail
3323
+ }));
3324
+ try {
3325
+ pdfBytes = await addFormFieldsToPdf(pdfBytes, fieldsForPdf, {
3326
+ removeExistingFields: true,
3327
+ // Remove any orphaned field references
3328
+ drawLabels: false
3329
+ });
3330
+ console.log("[PageAssembler] \u2705 Successfully re-added form fields to combined PDF");
3331
+ } catch (addFieldsError) {
3332
+ console.error("[PageAssembler] Error re-adding fields:", addFieldsError);
3333
+ }
3334
+ }
1675
3335
  const arrayBuffer = pdfBytes.buffer.slice(pdfBytes.byteOffset, pdfBytes.byteOffset + pdfBytes.byteLength);
1676
3336
  const blob = new Blob([arrayBuffer], { type: "application/pdf" });
1677
3337
  return blob;
@@ -1726,6 +3386,10 @@ var PageAssembler = React7.forwardRef(
1726
3386
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }),
1727
3387
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: processingStatus })
1728
3388
  ] }) }),
3389
+ 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: [
3390
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4 text-destructive flex-shrink-0" }),
3391
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: uploadError })
3392
+ ] }) }),
1729
3393
  /* @__PURE__ */ jsxRuntime.jsx(
1730
3394
  BulkActionBar,
1731
3395
  {
@@ -1860,14 +3524,24 @@ function debounce(func, wait) {
1860
3524
  timeout = setTimeout(() => func(...args), wait);
1861
3525
  });
1862
3526
  }
1863
- var PageAssembler_default = PageAssembler;
1864
3527
 
1865
3528
  exports.Button = Button;
3529
+ exports.FormFieldType = FormFieldType;
1866
3530
  exports.PageAssembler = PageAssembler;
3531
+ exports.PdfPasswordRequiredError = PdfPasswordRequiredError2;
3532
+ exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError2;
3533
+ exports.addFormFieldsToPdf = addFormFieldsToPdf;
1867
3534
  exports.createPdfBlobUrl = createPdfBlobUrl;
1868
- exports.default = PageAssembler_default;
3535
+ exports.decryptPdf = decryptPdf2;
1869
3536
  exports.downloadPdf = downloadPdf;
3537
+ exports.extractFieldsFromPdf = extractFieldsFromPdf;
3538
+ exports.getSigniphiMetadata = getSigniphiMetadata;
1870
3539
  exports.imageToPdf = imageToPdf;
3540
+ exports.mapFieldPositionsAfterAssembly = mapFieldPositionsAfterAssembly;
3541
+ exports.normalizePdfEncryption = normalizePdfEncryption2;
3542
+ exports.normalizeUploadedPdfBytes = normalizeUploadedPdfBytes;
1871
3543
  exports.pdfToImages = pdfToImages;
3544
+ exports.rasterizePdfToPdf = rasterizePdfToPdf;
3545
+ exports.setSigniphiMetadata = setSigniphiMetadata;
1872
3546
  //# sourceMappingURL=index.js.map
1873
3547
  //# sourceMappingURL=index.js.map