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

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.d.mts CHANGED
@@ -238,15 +238,34 @@ declare function createPdfBlobUrl(pdfBytes: Uint8Array): string;
238
238
  */
239
239
  declare function downloadPdf(pdfBytes: Uint8Array, filename: string): void;
240
240
 
241
- declare class PdfPasswordRequiredError extends Error {
241
+ interface PdfPasswordRequiredErrorConstructor {
242
+ new (): PdfPasswordRequiredError;
243
+ readonly prototype: PdfPasswordRequiredError;
244
+ }
245
+ /**
246
+ * Thrown when the PDF needs a non-empty user password, which this package
247
+ * cannot supply. Match it with {@link isPdfPasswordRequiredError} rather than
248
+ * `instanceof` — see the header note on copies.
249
+ */
250
+ interface PdfPasswordRequiredError extends Error {
251
+ /** Always `'PDF_PASSWORD_REQUIRED'`. The check that survives package boundaries. */
242
252
  code: string;
243
253
  recoverable: boolean;
244
254
  userMessage: string;
245
- constructor();
246
255
  }
247
- declare class UnsupportedPdfEncryptionError extends Error {
248
- constructor(detail: string);
256
+ declare const PdfPasswordRequiredError: PdfPasswordRequiredErrorConstructor;
257
+ interface UnsupportedPdfEncryptionErrorConstructor {
258
+ new (detail: string): UnsupportedPdfEncryptionError;
259
+ readonly prototype: UnsupportedPdfEncryptionError;
260
+ }
261
+ /** Thrown for security handlers this decryptor does not implement. */
262
+ interface UnsupportedPdfEncryptionError extends Error {
263
+ /** Always `'UnsupportedPdfEncryptionError'`. */
264
+ name: string;
265
+ /** The scheme that is not supported, e.g. `'V5 /R6'`. */
266
+ readonly detail: string;
249
267
  }
268
+ declare const UnsupportedPdfEncryptionError: UnsupportedPdfEncryptionErrorConstructor;
250
269
  /**
251
270
  * Decrypt an encrypted PDF that opens with an empty user password.
252
271
  * Returns re-saved, fully decrypted bytes with `/Encrypt` removed.
@@ -254,11 +273,15 @@ declare class UnsupportedPdfEncryptionError extends Error {
254
273
  * @throws {PdfPasswordRequiredError} when a non-empty password is required
255
274
  * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
256
275
  */
257
- declare function decryptPdf(pdfBytes: Uint8Array): Promise<Uint8Array>;
276
+ declare const decryptPdf: (pdfBytes: Uint8Array) => Promise<Uint8Array>;
258
277
  /**
259
- * Ingestion gate: returns the bytes untouched for regular PDFs, and a
260
- * decrypted re-save for encrypted ones so every downstream `PDFDocument.load`
261
- * (page assembly, field extraction) sees a normal document.
278
+ * Ingestion gate see `@signiphi/pdf-crypto`'s `normalizePdfEncryption`.
279
+ * Returns the bytes untouched (same reference) for ordinary PDFs; decrypts and
280
+ * re-saves encrypted ones so every downstream `PDFDocument.load` (page
281
+ * assembly, field extraction) sees a normal document.
282
+ *
283
+ * @throws {PdfPasswordRequiredError} when a non-empty password is required
284
+ * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
262
285
  */
263
286
  declare function normalizePdfEncryption(pdfBytes: Uint8Array): Promise<Uint8Array>;
264
287
 
package/dist/index.d.ts CHANGED
@@ -238,15 +238,34 @@ declare function createPdfBlobUrl(pdfBytes: Uint8Array): string;
238
238
  */
239
239
  declare function downloadPdf(pdfBytes: Uint8Array, filename: string): void;
240
240
 
241
- declare class PdfPasswordRequiredError extends Error {
241
+ interface PdfPasswordRequiredErrorConstructor {
242
+ new (): PdfPasswordRequiredError;
243
+ readonly prototype: PdfPasswordRequiredError;
244
+ }
245
+ /**
246
+ * Thrown when the PDF needs a non-empty user password, which this package
247
+ * cannot supply. Match it with {@link isPdfPasswordRequiredError} rather than
248
+ * `instanceof` — see the header note on copies.
249
+ */
250
+ interface PdfPasswordRequiredError extends Error {
251
+ /** Always `'PDF_PASSWORD_REQUIRED'`. The check that survives package boundaries. */
242
252
  code: string;
243
253
  recoverable: boolean;
244
254
  userMessage: string;
245
- constructor();
246
255
  }
247
- declare class UnsupportedPdfEncryptionError extends Error {
248
- constructor(detail: string);
256
+ declare const PdfPasswordRequiredError: PdfPasswordRequiredErrorConstructor;
257
+ interface UnsupportedPdfEncryptionErrorConstructor {
258
+ new (detail: string): UnsupportedPdfEncryptionError;
259
+ readonly prototype: UnsupportedPdfEncryptionError;
260
+ }
261
+ /** Thrown for security handlers this decryptor does not implement. */
262
+ interface UnsupportedPdfEncryptionError extends Error {
263
+ /** Always `'UnsupportedPdfEncryptionError'`. */
264
+ name: string;
265
+ /** The scheme that is not supported, e.g. `'V5 /R6'`. */
266
+ readonly detail: string;
249
267
  }
268
+ declare const UnsupportedPdfEncryptionError: UnsupportedPdfEncryptionErrorConstructor;
250
269
  /**
251
270
  * Decrypt an encrypted PDF that opens with an empty user password.
252
271
  * Returns re-saved, fully decrypted bytes with `/Encrypt` removed.
@@ -254,11 +273,15 @@ declare class UnsupportedPdfEncryptionError extends Error {
254
273
  * @throws {PdfPasswordRequiredError} when a non-empty password is required
255
274
  * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
256
275
  */
257
- declare function decryptPdf(pdfBytes: Uint8Array): Promise<Uint8Array>;
276
+ declare const decryptPdf: (pdfBytes: Uint8Array) => Promise<Uint8Array>;
258
277
  /**
259
- * Ingestion gate: returns the bytes untouched for regular PDFs, and a
260
- * decrypted re-save for encrypted ones so every downstream `PDFDocument.load`
261
- * (page assembly, field extraction) sees a normal document.
278
+ * Ingestion gate see `@signiphi/pdf-crypto`'s `normalizePdfEncryption`.
279
+ * Returns the bytes untouched (same reference) for ordinary PDFs; decrypts and
280
+ * re-saves encrypted ones so every downstream `PDFDocument.load` (page
281
+ * assembly, field extraction) sees a normal document.
282
+ *
283
+ * @throws {PdfPasswordRequiredError} when a non-empty password is required
284
+ * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
262
285
  */
263
286
  declare function normalizePdfEncryption(pdfBytes: Uint8Array): Promise<Uint8Array>;
264
287
 
package/dist/index.js CHANGED
@@ -43,9 +43,7 @@ var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMe
43
43
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
44
44
  var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
45
45
 
46
- var __defProp = Object.defineProperty;
47
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
48
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
46
+ // src/components/PageAssembler.tsx
49
47
  function cn(...inputs) {
50
48
  return tailwindMerge.twMerge(clsx.clsx(inputs));
51
49
  }
@@ -580,9 +578,8 @@ var PdfPasswordRequiredError = class extends Error {
580
578
  constructor() {
581
579
  const message = "This PDF is password-protected. Please remove the password and upload it again.";
582
580
  super(message);
583
- __publicField(this, "code", "PDF_PASSWORD_REQUIRED");
584
- __publicField(this, "recoverable", true);
585
- __publicField(this, "userMessage");
581
+ this.code = "PDF_PASSWORD_REQUIRED";
582
+ this.recoverable = true;
586
583
  this.name = "PdfPasswordRequiredError";
587
584
  this.userMessage = message;
588
585
  }
@@ -591,6 +588,7 @@ var UnsupportedPdfEncryptionError = class extends Error {
591
588
  constructor(detail) {
592
589
  super(`This PDF uses an unsupported encryption scheme (${detail}).`);
593
590
  this.name = "UnsupportedPdfEncryptionError";
591
+ this.detail = detail;
594
592
  }
595
593
  };
596
594
  function concatBytes(...parts) {
@@ -1128,30 +1126,70 @@ async function decryptPdf(pdfBytes) {
1128
1126
  if (!doc.isEncrypted) return pdfBytes;
1129
1127
  return decryptLoadedDocument(doc);
1130
1128
  }
1131
- var ENCRYPT_MARKER = new Uint8Array([47, 69, 110, 99, 114, 121, 112, 116]);
1132
- function containsEncryptMarker(bytes) {
1133
- const last = bytes.length - ENCRYPT_MARKER.length;
1134
- outer: for (let i = 0; i <= last; i++) {
1135
- for (let j = 0; j < ENCRYPT_MARKER.length; j++) {
1136
- if (bytes[i + j] !== ENCRYPT_MARKER[j]) continue outer;
1129
+ var SLASH = 47;
1130
+ var HASH = 35;
1131
+ var ENCRYPT_NAME = "Encrypt";
1132
+ function hexDigit(byte) {
1133
+ if (byte === void 0) return -1;
1134
+ if (byte >= 48 && byte <= 57) return byte - 48;
1135
+ if (byte >= 65 && byte <= 70) return byte - 65 + 10;
1136
+ if (byte >= 97 && byte <= 102) return byte - 97 + 10;
1137
+ return -1;
1138
+ }
1139
+ function matchesEncryptNameAt(bytes, start) {
1140
+ let at = start;
1141
+ for (let k = 0; k < ENCRYPT_NAME.length; k++) {
1142
+ const want = ENCRYPT_NAME.charCodeAt(k);
1143
+ const byte = bytes[at];
1144
+ if (byte === want) {
1145
+ at += 1;
1146
+ continue;
1137
1147
  }
1138
- return true;
1148
+ if (byte === HASH) {
1149
+ const high = hexDigit(bytes[at + 1]);
1150
+ const low = hexDigit(bytes[at + 2]);
1151
+ if (high >= 0 && low >= 0 && (high << 4 | low) === want) {
1152
+ at += 3;
1153
+ continue;
1154
+ }
1155
+ }
1156
+ return false;
1157
+ }
1158
+ return true;
1159
+ }
1160
+ function containsEncryptMarker(bytes) {
1161
+ for (let i = 0; i < bytes.length; i++) {
1162
+ if (bytes[i] !== SLASH) continue;
1163
+ if (matchesEncryptNameAt(bytes, i + 1)) return true;
1139
1164
  }
1140
1165
  return false;
1141
1166
  }
1142
- async function normalizePdfEncryption(pdfBytes) {
1167
+ async function normalizePdfEncryption(pdfBytes, options) {
1143
1168
  if (!containsEncryptMarker(pdfBytes)) return pdfBytes;
1144
1169
  const doc = await pdfLib.PDFDocument.load(pdfBytes.slice(), {
1145
1170
  ignoreEncryption: true,
1146
1171
  updateMetadata: false
1147
1172
  });
1148
1173
  if (!doc.isEncrypted) return pdfBytes;
1149
- if (typeof process === "undefined" || process.env?.NODE_ENV !== "production") {
1150
- console.info("[PageAssembler] Encrypted PDF detected during ingestion; decrypting");
1151
- }
1174
+ options?.logger?.info("[PDF_DECRYPT] Encrypted PDF detected during ingestion; decrypting");
1152
1175
  return decryptLoadedDocument(doc);
1153
1176
  }
1154
1177
 
1178
+ // src/utils/pdf-decrypt.ts
1179
+ var PdfPasswordRequiredError2 = PdfPasswordRequiredError;
1180
+ var UnsupportedPdfEncryptionError2 = UnsupportedPdfEncryptionError;
1181
+ var decryptPdf2 = decryptPdf;
1182
+ var consoleLogger = {
1183
+ info(message, ...args) {
1184
+ if (typeof process === "undefined" || process.env?.NODE_ENV !== "production") {
1185
+ console.info(`[PageAssembler] ${message}`, ...args);
1186
+ }
1187
+ }
1188
+ };
1189
+ function normalizePdfEncryption2(pdfBytes) {
1190
+ return normalizePdfEncryption(pdfBytes, { logger: consoleLogger });
1191
+ }
1192
+
1155
1193
  // src/utils/pdf-helpers.ts
1156
1194
  if (typeof window !== "undefined") {
1157
1195
  pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = "/pdfjs/build/pdf.worker.mjs";
@@ -1243,7 +1281,7 @@ async function rasterizePdfToPdf(pdfBytes) {
1243
1281
  sourceDoc = await pdfjsLib__namespace.getDocument({ data: pdfBytes.slice(0), verbosity: 0 }).promise;
1244
1282
  } catch (error) {
1245
1283
  if (error?.name === "PasswordException") {
1246
- throw new PdfPasswordRequiredError();
1284
+ throw new PdfPasswordRequiredError2();
1247
1285
  }
1248
1286
  throw error;
1249
1287
  }
@@ -1275,10 +1313,10 @@ async function rasterizePdfToPdf(pdfBytes) {
1275
1313
  }
1276
1314
  async function normalizeUploadedPdfBytes(pdfBytes) {
1277
1315
  try {
1278
- const normalized = await normalizePdfEncryption(pdfBytes);
1316
+ const normalized = await normalizePdfEncryption2(pdfBytes);
1279
1317
  return normalized === pdfBytes ? pdfBytes : new Uint8Array(normalized);
1280
1318
  } catch (error) {
1281
- if (error instanceof PdfPasswordRequiredError) throw error;
1319
+ if (error instanceof PdfPasswordRequiredError2) throw error;
1282
1320
  console.warn(
1283
1321
  "[PageAssembler] Structural decryption failed; rebuilding document from rendered pages:",
1284
1322
  error
@@ -1403,11 +1441,17 @@ function getBaseFieldName(encodedName) {
1403
1441
  }
1404
1442
  return baseName;
1405
1443
  }
1444
+ function stripFieldTypeSuffix(value) {
1445
+ const stripped = value.replace(/_(signature|initials|date)$/i, "");
1446
+ return stripped || value;
1447
+ }
1406
1448
  function getSignerFromFieldName(encodedName) {
1407
1449
  if (encodedName.includes("__SIGNER__")) {
1408
1450
  const parts = encodedName.split("__SIGNER__");
1409
1451
  if (parts[1]) {
1410
- return parts[1].split("__")[0] || parts[1];
1452
+ const segment = parts[1].split("__")[0] || parts[1];
1453
+ const isTerminal = segment === parts[1];
1454
+ return isTerminal ? stripFieldTypeSuffix(segment) : segment;
1411
1455
  }
1412
1456
  }
1413
1457
  return void 0;
@@ -2751,7 +2795,7 @@ var PageAssembler = React7.forwardRef(
2751
2795
  dispatch({ type: "ADD_FILE", payload: fileInfo });
2752
2796
  } catch (error) {
2753
2797
  console.error(`Error processing file ${file.name}:`, error);
2754
- if (error instanceof PdfPasswordRequiredError) {
2798
+ if (error instanceof PdfPasswordRequiredError2) {
2755
2799
  setUploadError(`${file.name}: ${error.userMessage}`);
2756
2800
  } else {
2757
2801
  setUploadError(`Failed to process "${file.name}". The file may be corrupted or unsupported.`);
@@ -3336,17 +3380,17 @@ function debounce(func, wait) {
3336
3380
  exports.Button = Button;
3337
3381
  exports.FormFieldType = FormFieldType;
3338
3382
  exports.PageAssembler = PageAssembler;
3339
- exports.PdfPasswordRequiredError = PdfPasswordRequiredError;
3340
- exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError;
3383
+ exports.PdfPasswordRequiredError = PdfPasswordRequiredError2;
3384
+ exports.UnsupportedPdfEncryptionError = UnsupportedPdfEncryptionError2;
3341
3385
  exports.addFormFieldsToPdf = addFormFieldsToPdf;
3342
3386
  exports.createPdfBlobUrl = createPdfBlobUrl;
3343
- exports.decryptPdf = decryptPdf;
3387
+ exports.decryptPdf = decryptPdf2;
3344
3388
  exports.downloadPdf = downloadPdf;
3345
3389
  exports.extractFieldsFromPdf = extractFieldsFromPdf;
3346
3390
  exports.getSigniphiMetadata = getSigniphiMetadata;
3347
3391
  exports.imageToPdf = imageToPdf;
3348
3392
  exports.mapFieldPositionsAfterAssembly = mapFieldPositionsAfterAssembly;
3349
- exports.normalizePdfEncryption = normalizePdfEncryption;
3393
+ exports.normalizePdfEncryption = normalizePdfEncryption2;
3350
3394
  exports.normalizeUploadedPdfBytes = normalizeUploadedPdfBytes;
3351
3395
  exports.pdfToImages = pdfToImages;
3352
3396
  exports.rasterizePdfToPdf = rasterizePdfToPdf;