@signiphi/page-assembly 0.2.0-beta.13 → 0.2.0-beta.14

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.mjs CHANGED
@@ -14,7 +14,7 @@ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
14
14
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
15
15
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
16
16
  import * as pdfjsLib from 'pdfjs-dist';
17
- import { PDFDocument, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup, StandardFonts, rgb, PDFName, PDFString, PDFDict, PDFArray, PDFHexString, PDFInvalidObject, PDFObjectParser, PDFRawStream, PDFObjectStreamParser, PDFRef, PDFBool, PDFNumber } from 'pdf-lib';
17
+ import { PDFDocument, PDFName, PDFTextField, PDFCheckBox, PDFDropdown, PDFRadioGroup, PDFHexString, StandardFonts, rgb, PDFString, PDFDict, PDFArray, PDFInvalidObject, PDFObjectParser, PDFRawStream, PDFObjectStreamParser, PDFRef, PDFBool, PDFNumber } from 'pdf-lib';
18
18
 
19
19
  // src/components/PageAssembler.tsx
20
20
  function cn(...inputs) {
@@ -1372,6 +1372,51 @@ function downloadPdf(pdfBytes, filename) {
1372
1372
  a.click();
1373
1373
  URL.revokeObjectURL(url);
1374
1374
  }
1375
+ function toCombinedPage(entry, page) {
1376
+ if (!entry.position && !entry.radioPositions && !entry.radioOptions) return entry;
1377
+ const carried = { ...entry };
1378
+ if (entry.position) carried.position = { ...entry.position, page };
1379
+ if (entry.radioPositions) carried.radioPositions = entry.radioPositions.map((p) => ({ ...p, page }));
1380
+ if (entry.radioOptions) {
1381
+ carried.radioOptions = entry.radioOptions.map((o) => ({ ...o, position: { ...o.position, page } }));
1382
+ }
1383
+ return carried;
1384
+ }
1385
+ function mergeSourceMetadata(sources) {
1386
+ const merged = { version: "1.0", fields: {}, fieldIdIndex: {} };
1387
+ let radioLabelsBaked;
1388
+ let textLabelsBaked;
1389
+ for (const source of sources) {
1390
+ const meta = source.metadata;
1391
+ if (!meta || source.fields.length === 0) continue;
1392
+ if (meta.radioLabelsBaked === false) radioLabelsBaked = false;
1393
+ else if (meta.radioLabelsBaked === true && radioLabelsBaked === void 0) radioLabelsBaked = true;
1394
+ if (meta.textLabelsBaked === false) textLabelsBaked = false;
1395
+ else if (meta.textLabelsBaked === true && textLabelsBaked === void 0) textLabelsBaked = true;
1396
+ }
1397
+ for (const source of sources) {
1398
+ const meta = source.metadata;
1399
+ if (!meta) continue;
1400
+ const sourceTextLabelsBaked = meta.textLabelsBaked !== false;
1401
+ for (const { name, page } of source.fields) {
1402
+ const key = `${name}_p${page}`;
1403
+ const entry = meta.fields?.[name];
1404
+ if (entry) {
1405
+ const carried = toCombinedPage(entry, page);
1406
+ merged.fields[key] = textLabelsBaked === false && sourceTextLabelsBaked ? { ...carried, textLabelBaked: true } : carried;
1407
+ }
1408
+ const fieldId = meta.fieldIdIndex?.[name];
1409
+ if (fieldId) merged.fieldIdIndex[key] = fieldId;
1410
+ }
1411
+ }
1412
+ if (radioLabelsBaked !== void 0) merged.radioLabelsBaked = radioLabelsBaked;
1413
+ if (textLabelsBaked !== void 0) merged.textLabelsBaked = textLabelsBaked;
1414
+ const hasEntries = Object.keys(merged.fields).length > 0;
1415
+ const hasMarkers = radioLabelsBaked !== void 0 || textLabelsBaked !== void 0;
1416
+ if (!hasEntries && !hasMarkers) return null;
1417
+ if (Object.keys(merged.fieldIdIndex).length === 0) delete merged.fieldIdIndex;
1418
+ return merged;
1419
+ }
1375
1420
  function getSigniphiMetadata(pdfDoc) {
1376
1421
  try {
1377
1422
  const infoRef = pdfDoc.context.trailerInfo.Info;
@@ -1387,12 +1432,17 @@ function getSigniphiMetadata(pdfDoc) {
1387
1432
  if (!metadataObj) {
1388
1433
  return null;
1389
1434
  }
1390
- const metadataStr = metadataObj.toString();
1391
- let jsonStr = metadataStr;
1392
- if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
1393
- jsonStr = metadataStr.slice(1, -1);
1394
- } else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
1395
- jsonStr = metadataStr.slice(1, -1);
1435
+ let jsonStr;
1436
+ if (typeof metadataObj.decodeText === "function") {
1437
+ jsonStr = metadataObj.decodeText();
1438
+ } else {
1439
+ const metadataStr = metadataObj.toString();
1440
+ jsonStr = metadataStr;
1441
+ if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
1442
+ jsonStr = metadataStr.slice(1, -1);
1443
+ } else if (metadataStr.startsWith("<") && metadataStr.endsWith(">")) {
1444
+ jsonStr = metadataStr.slice(1, -1);
1445
+ }
1396
1446
  }
1397
1447
  const metadata = JSON.parse(jsonStr);
1398
1448
  return metadata;
@@ -1585,7 +1635,7 @@ function setSigniphiMetadata(pdfDoc, metadata) {
1585
1635
  }
1586
1636
  const infoDict = infoObj;
1587
1637
  const metadataString = JSON.stringify(metadata);
1588
- infoDict.set(PDFName.of("SigniphiMetadata"), PDFString.of(metadataString));
1638
+ infoDict.set(PDFName.of("SigniphiMetadata"), PDFHexString.fromText(metadataString));
1589
1639
  } catch (error) {
1590
1640
  console.error("Failed to set Signiphi metadata:", error);
1591
1641
  throw error;
@@ -2898,7 +2948,7 @@ var PageAssembler = forwardRef(
2898
2948
  setIsLoading(true);
2899
2949
  setProcessingStatus("Assembling PDF...");
2900
2950
  try {
2901
- const { PDFDocument: PDFDocument5, PDFName: PDFName4, PDFString: PDFString4 } = await import('pdf-lib');
2951
+ const { PDFDocument: PDFDocument5, PDFName: PDFName4 } = await import('pdf-lib');
2902
2952
  const loadedPdfs = /* @__PURE__ */ new Map();
2903
2953
  const fileMap = /* @__PURE__ */ new Map();
2904
2954
  const pdfFiles = state.files.filter((f) => f.type === "pdf" && f.originalBytes?.length > 0);
@@ -2977,11 +3027,7 @@ var PageAssembler = forwardRef(
2977
3027
  }
2978
3028
  console.log("[PageAssembler] Starting multi-PDF assembly with field preservation");
2979
3029
  const allExtractedFields = [];
2980
- const mergedMetadata = {
2981
- version: "1.0",
2982
- fields: {},
2983
- fieldIdIndex: {}
2984
- };
3030
+ const metadataSources = [];
2985
3031
  const filePageUsage = /* @__PURE__ */ new Map();
2986
3032
  for (const file of state.files) {
2987
3033
  for (const page of file.pages) {
@@ -3006,28 +3052,12 @@ var PageAssembler = forwardRef(
3006
3052
  }
3007
3053
  console.log("[PageAssembler] Page mapping:", Object.fromEntries(pageIdToNewPageNumber));
3008
3054
  const extractAndMapFields = async (fileId, fileName, pdfBytes2, sourcePdf) => {
3009
- let sourceMetadata = null;
3010
- if (sourcePdf) {
3011
- try {
3012
- const sourceInfoRef = sourcePdf.context.trailerInfo.Info;
3013
- if (sourceInfoRef) {
3014
- const sourceInfoDict = sourcePdf.context.lookup(sourceInfoRef);
3015
- if (sourceInfoDict && typeof sourceInfoDict.get === "function") {
3016
- const metadataObj = sourceInfoDict.get(PDFName4.of("SigniphiMetadata"));
3017
- if (metadataObj) {
3018
- const metadataStr = metadataObj.toString();
3019
- let jsonStr = metadataStr;
3020
- if (metadataStr.startsWith("(") && metadataStr.endsWith(")")) {
3021
- jsonStr = metadataStr.slice(1, -1);
3022
- }
3023
- sourceMetadata = JSON.parse(jsonStr);
3024
- }
3025
- }
3026
- }
3027
- } catch (metadataError) {
3028
- console.warn(`Could not read metadata from PDF ${fileName}:`, metadataError);
3029
- }
3055
+ const sourceMetadata = sourcePdf ? getSigniphiMetadata(sourcePdf) : null;
3056
+ if (sourcePdf && !sourceMetadata) {
3057
+ console.warn(`[PageAssembler] No readable SigniphiMetadata in "${fileName}"`);
3030
3058
  }
3059
+ const placements = [];
3060
+ metadataSources.push({ metadata: sourceMetadata, fields: placements });
3031
3061
  console.log(`[PageAssembler] Extracting fields from "${fileName}"`);
3032
3062
  const extractedFields = await extractFieldsFromPdf(pdfBytes2);
3033
3063
  console.log(`[PageAssembler] Found ${extractedFields.length} fields in "${fileName}"`);
@@ -3061,13 +3091,7 @@ var PageAssembler = forwardRef(
3061
3091
  };
3062
3092
  allExtractedFields.push(trackedField);
3063
3093
  console.log(`[PageAssembler] Mapped field "${field.name}" from page ${originalPage} to page ${newPageNumber}`);
3064
- const metadataKey = `${field.name}_p${newPageNumber}`;
3065
- if (sourceMetadata?.fields?.[field.name]) {
3066
- mergedMetadata.fields[metadataKey] = sourceMetadata.fields[field.name];
3067
- }
3068
- if (sourceMetadata?.fieldIdIndex?.[field.name]) {
3069
- mergedMetadata.fieldIdIndex[metadataKey] = sourceMetadata.fieldIdIndex[field.name];
3070
- }
3094
+ placements.push({ name: field.name, page: newPageNumber });
3071
3095
  }
3072
3096
  }
3073
3097
  }
@@ -3145,21 +3169,15 @@ var PageAssembler = forwardRef(
3145
3169
  }
3146
3170
  }
3147
3171
  }
3148
- if (Object.keys(mergedMetadata.fields).length > 0) {
3172
+ const mergedMetadata = mergeSourceMetadata(metadataSources);
3173
+ if (mergedMetadata) {
3149
3174
  try {
3150
- const newInfoRef = combinedDoc.context.trailerInfo.Info;
3151
- if (newInfoRef) {
3152
- const newInfoDict = combinedDoc.context.lookup(newInfoRef);
3153
- if (newInfoDict && typeof newInfoDict.set === "function") {
3154
- newInfoDict.set(
3155
- PDFName4.of("SigniphiMetadata"),
3156
- PDFString4.of(JSON.stringify(mergedMetadata))
3157
- );
3158
- }
3159
- }
3175
+ setSigniphiMetadata(combinedDoc, mergedMetadata);
3160
3176
  } catch (metadataError) {
3161
3177
  console.warn("Could not write merged metadata:", metadataError);
3162
3178
  }
3179
+ } else {
3180
+ console.warn("[PageAssembler] No source metadata survived the merge; the assembled document will read as unprepared downstream");
3163
3181
  }
3164
3182
  let pdfBytes = await combinedDoc.save();
3165
3183
  if (allExtractedFields.length > 0) {