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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import * as class_variance_authority_types from 'class-variance-authority/types';
4
4
  import { VariantProps } from 'class-variance-authority';
5
+ import { PDFDocument } from 'pdf-lib';
5
6
 
6
7
  /**
7
8
  * Represents a single page in the page assembly system
@@ -39,6 +40,52 @@ type FileInfo = {
39
40
  /** Pages extracted from this file */
40
41
  pages: PageInfo[];
41
42
  };
43
+ /**
44
+ * Form field with page tracking for assembly operations
45
+ */
46
+ type TrackedFormField = {
47
+ /** Field name */
48
+ name: string;
49
+ /** Field type */
50
+ type: string;
51
+ /** Field position */
52
+ position: {
53
+ x: number;
54
+ y: number;
55
+ width: number;
56
+ height: number;
57
+ page: number;
58
+ };
59
+ /** Page ID this field is associated with (for tracking across page operations) */
60
+ pageId?: string;
61
+ /** Original file ID this field came from */
62
+ originalFileId?: string;
63
+ /** All other field properties */
64
+ label?: string;
65
+ required?: boolean;
66
+ options?: string[];
67
+ placeholder?: string;
68
+ defaultValue?: string;
69
+ assignedSignerEmail?: string;
70
+ fieldId?: string;
71
+ fontSize?: number;
72
+ multiline?: boolean;
73
+ maxLength?: number;
74
+ acknowledgements?: Array<{
75
+ id: string;
76
+ title: string;
77
+ description: string;
78
+ }>;
79
+ };
80
+ /**
81
+ * Extracted fields from a file
82
+ */
83
+ type FileExtractedFields = {
84
+ /** File ID these fields came from */
85
+ fileId: string;
86
+ /** Extracted form fields */
87
+ fields: TrackedFormField[];
88
+ };
42
89
  /**
43
90
  * State of the page assembler
44
91
  */
@@ -49,6 +96,10 @@ type PageAssemblerState = {
49
96
  selection: string[];
50
97
  /** ID of the last selected page (for range selection) */
51
98
  lastSelectedPageId?: string;
99
+ /** Form fields tracked across page operations */
100
+ formFields?: TrackedFormField[];
101
+ /** Extracted fields per file (for mapping after assembly) */
102
+ extractedFieldsByFile?: FileExtractedFields[];
52
103
  };
53
104
  /**
54
105
  * Options for assembling the final PDF
@@ -136,6 +187,18 @@ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAtt
136
187
  declare function pdfToImages(pdfBytes: Uint8Array, options?: {
137
188
  hideFormFields?: boolean;
138
189
  }): Promise<PageImage[]>;
190
+ declare function rasterizePdfToPdf(pdfBytes: Uint8Array): Promise<Uint8Array>;
191
+ /**
192
+ * Prepares uploaded PDF bytes for the pdf-lib based assembly pipeline.
193
+ * Regular PDFs pass through untouched. Encrypted PDFs (typically
194
+ * permission-restricted documents that open without a password) are
195
+ * decrypted once here so every downstream `PDFDocument.load` — assembly,
196
+ * field extraction — sees a normal document. When structural decryption is
197
+ * impossible the document is rebuilt from rendered pages as a last resort.
198
+ *
199
+ * @throws {PdfPasswordRequiredError} when the PDF needs a real password
200
+ */
201
+ declare function normalizeUploadedPdfBytes(pdfBytes: Uint8Array): Promise<Uint8Array>;
139
202
  /**
140
203
  * Converts an image file to a PDF document with a single page
141
204
  *
@@ -175,4 +238,179 @@ declare function createPdfBlobUrl(pdfBytes: Uint8Array): string;
175
238
  */
176
239
  declare function downloadPdf(pdfBytes: Uint8Array, filename: string): void;
177
240
 
178
- export { type AssembleOptions, Button, type FileInfo, PageAssembler, type PageAssemblerHandle, type PageAssemblerProps, type PageAssemblerState, type PageImage, type PageInfo, createPdfBlobUrl, PageAssembler as default, downloadPdf, imageToPdf, pdfToImages };
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. */
252
+ code: string;
253
+ recoverable: boolean;
254
+ userMessage: string;
255
+ }
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;
267
+ }
268
+ declare const UnsupportedPdfEncryptionError: UnsupportedPdfEncryptionErrorConstructor;
269
+ /**
270
+ * Decrypt an encrypted PDF that opens with an empty user password.
271
+ * Returns re-saved, fully decrypted bytes with `/Encrypt` removed.
272
+ *
273
+ * @throws {PdfPasswordRequiredError} when a non-empty password is required
274
+ * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
275
+ */
276
+ declare const decryptPdf: (pdfBytes: Uint8Array) => Promise<Uint8Array>;
277
+ /**
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
285
+ */
286
+ declare function normalizePdfEncryption(pdfBytes: Uint8Array): Promise<Uint8Array>;
287
+
288
+ /**
289
+ * PDF Field Extraction Utilities
290
+ * Extract form fields from PDFs with metadata support for preserving field properties
291
+ */
292
+
293
+ /**
294
+ * Extracted field information
295
+ */
296
+ interface ExtractedField {
297
+ name: string;
298
+ type: 'text' | 'signature' | 'initials' | 'date' | 'checkbox' | 'radio' | 'dropdown' | 'text_label';
299
+ page: number;
300
+ x: number;
301
+ y: number;
302
+ width: number;
303
+ height: number;
304
+ required: boolean;
305
+ label?: string;
306
+ placeholder?: string;
307
+ options?: string[];
308
+ fieldId?: string;
309
+ signer?: string;
310
+ }
311
+ /**
312
+ * SigniphiMetadata structure stored in PDF Info dictionary
313
+ */
314
+ interface SigniphiMetadata {
315
+ version: string;
316
+ fields: Record<string, {
317
+ fieldId?: string;
318
+ label?: string;
319
+ signer?: string;
320
+ placeholder?: string;
321
+ required?: boolean;
322
+ options?: string[];
323
+ acknowledgements?: Array<{
324
+ id: string;
325
+ title: string;
326
+ description: string;
327
+ }>;
328
+ }>;
329
+ fieldIdIndex?: Record<string, string>;
330
+ }
331
+ /**
332
+ * Extract SigniphiMetadata from a PDF document
333
+ */
334
+ declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null;
335
+ /**
336
+ * Extract form fields from a PDF document
337
+ * @param pdfBytes - PDF bytes
338
+ * @returns Array of extracted fields with all properties
339
+ */
340
+ declare function extractFieldsFromPdf(pdfBytes: Uint8Array): Promise<ExtractedField[]>;
341
+ /**
342
+ * Set SigniphiMetadata in a PDF document
343
+ */
344
+ declare function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void;
345
+
346
+ /**
347
+ * Add Form Fields to PDF
348
+ * Re-adds form fields to a PDF after page assembly operations
349
+ * This is the key to preserving form fields - don't try to preserve during copyPages,
350
+ * instead extract fields first, copy pages, then re-add fields with adjusted positions.
351
+ */
352
+ /**
353
+ * Form field type enum matching document-prepare
354
+ */
355
+ declare enum FormFieldType {
356
+ TEXT = "text",
357
+ SIGNATURE = "signature",
358
+ INITIALS = "initials",
359
+ DATE = "date",
360
+ CHECKBOX = "checkbox",
361
+ RADIO = "radio",
362
+ DROPDOWN = "dropdown",
363
+ TEXT_LABEL = "text_label"
364
+ }
365
+ /**
366
+ * Form field position
367
+ */
368
+ interface FormFieldPosition {
369
+ x: number;
370
+ y: number;
371
+ width: number;
372
+ height: number;
373
+ page: number;
374
+ }
375
+ /**
376
+ * Form field for adding to PDF
377
+ */
378
+ interface FormFieldForPdf {
379
+ name: string;
380
+ type: FormFieldType | string;
381
+ position: FormFieldPosition;
382
+ label?: string;
383
+ required?: boolean;
384
+ options?: string[];
385
+ defaultValue?: string;
386
+ placeholder?: string;
387
+ fontSize?: number;
388
+ multiline?: boolean;
389
+ maxLength?: number;
390
+ assignedSignerEmail?: string;
391
+ }
392
+ /**
393
+ * Add form fields to a PDF document
394
+ *
395
+ * @param pdfBytes - The PDF document bytes
396
+ * @param formFields - Array of form fields to add
397
+ * @param options - Options for field addition
398
+ * @returns Modified PDF bytes with form fields added
399
+ */
400
+ declare function addFormFieldsToPdf(pdfBytes: Uint8Array, formFields: FormFieldForPdf[], options?: {
401
+ removeExistingFields?: boolean;
402
+ drawLabels?: boolean;
403
+ }): Promise<Uint8Array>;
404
+ /**
405
+ * Map field positions after page assembly
406
+ * Updates field page numbers based on the final page arrangement
407
+ *
408
+ * @param fields - Original fields with positions
409
+ * @param pageMapping - Map of "originalFileId_originalPageIndex" -> newPageNumber
410
+ * @returns Fields with updated page positions
411
+ */
412
+ declare function mapFieldPositionsAfterAssembly<T extends {
413
+ position: FormFieldPosition;
414
+ }>(fields: T[], pageMapping: Map<string, number>): T[];
415
+
416
+ export { type AssembleOptions, Button, type ExtractedField, type FileExtractedFields, type FileInfo, type FormFieldForPdf, type FormFieldPosition, FormFieldType, PageAssembler, type PageAssemblerHandle, type PageAssemblerProps, type PageAssemblerState, type PageImage, type PageInfo, PdfPasswordRequiredError, type TrackedFormField, UnsupportedPdfEncryptionError, addFormFieldsToPdf, createPdfBlobUrl, decryptPdf, downloadPdf, extractFieldsFromPdf, getSigniphiMetadata, imageToPdf, mapFieldPositionsAfterAssembly, normalizePdfEncryption, normalizeUploadedPdfBytes, pdfToImages, rasterizePdfToPdf, setSigniphiMetadata };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import * as class_variance_authority_types from 'class-variance-authority/types';
4
4
  import { VariantProps } from 'class-variance-authority';
5
+ import { PDFDocument } from 'pdf-lib';
5
6
 
6
7
  /**
7
8
  * Represents a single page in the page assembly system
@@ -39,6 +40,52 @@ type FileInfo = {
39
40
  /** Pages extracted from this file */
40
41
  pages: PageInfo[];
41
42
  };
43
+ /**
44
+ * Form field with page tracking for assembly operations
45
+ */
46
+ type TrackedFormField = {
47
+ /** Field name */
48
+ name: string;
49
+ /** Field type */
50
+ type: string;
51
+ /** Field position */
52
+ position: {
53
+ x: number;
54
+ y: number;
55
+ width: number;
56
+ height: number;
57
+ page: number;
58
+ };
59
+ /** Page ID this field is associated with (for tracking across page operations) */
60
+ pageId?: string;
61
+ /** Original file ID this field came from */
62
+ originalFileId?: string;
63
+ /** All other field properties */
64
+ label?: string;
65
+ required?: boolean;
66
+ options?: string[];
67
+ placeholder?: string;
68
+ defaultValue?: string;
69
+ assignedSignerEmail?: string;
70
+ fieldId?: string;
71
+ fontSize?: number;
72
+ multiline?: boolean;
73
+ maxLength?: number;
74
+ acknowledgements?: Array<{
75
+ id: string;
76
+ title: string;
77
+ description: string;
78
+ }>;
79
+ };
80
+ /**
81
+ * Extracted fields from a file
82
+ */
83
+ type FileExtractedFields = {
84
+ /** File ID these fields came from */
85
+ fileId: string;
86
+ /** Extracted form fields */
87
+ fields: TrackedFormField[];
88
+ };
42
89
  /**
43
90
  * State of the page assembler
44
91
  */
@@ -49,6 +96,10 @@ type PageAssemblerState = {
49
96
  selection: string[];
50
97
  /** ID of the last selected page (for range selection) */
51
98
  lastSelectedPageId?: string;
99
+ /** Form fields tracked across page operations */
100
+ formFields?: TrackedFormField[];
101
+ /** Extracted fields per file (for mapping after assembly) */
102
+ extractedFieldsByFile?: FileExtractedFields[];
52
103
  };
53
104
  /**
54
105
  * Options for assembling the final PDF
@@ -136,6 +187,18 @@ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAtt
136
187
  declare function pdfToImages(pdfBytes: Uint8Array, options?: {
137
188
  hideFormFields?: boolean;
138
189
  }): Promise<PageImage[]>;
190
+ declare function rasterizePdfToPdf(pdfBytes: Uint8Array): Promise<Uint8Array>;
191
+ /**
192
+ * Prepares uploaded PDF bytes for the pdf-lib based assembly pipeline.
193
+ * Regular PDFs pass through untouched. Encrypted PDFs (typically
194
+ * permission-restricted documents that open without a password) are
195
+ * decrypted once here so every downstream `PDFDocument.load` — assembly,
196
+ * field extraction — sees a normal document. When structural decryption is
197
+ * impossible the document is rebuilt from rendered pages as a last resort.
198
+ *
199
+ * @throws {PdfPasswordRequiredError} when the PDF needs a real password
200
+ */
201
+ declare function normalizeUploadedPdfBytes(pdfBytes: Uint8Array): Promise<Uint8Array>;
139
202
  /**
140
203
  * Converts an image file to a PDF document with a single page
141
204
  *
@@ -175,4 +238,179 @@ declare function createPdfBlobUrl(pdfBytes: Uint8Array): string;
175
238
  */
176
239
  declare function downloadPdf(pdfBytes: Uint8Array, filename: string): void;
177
240
 
178
- export { type AssembleOptions, Button, type FileInfo, PageAssembler, type PageAssemblerHandle, type PageAssemblerProps, type PageAssemblerState, type PageImage, type PageInfo, createPdfBlobUrl, PageAssembler as default, downloadPdf, imageToPdf, pdfToImages };
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. */
252
+ code: string;
253
+ recoverable: boolean;
254
+ userMessage: string;
255
+ }
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;
267
+ }
268
+ declare const UnsupportedPdfEncryptionError: UnsupportedPdfEncryptionErrorConstructor;
269
+ /**
270
+ * Decrypt an encrypted PDF that opens with an empty user password.
271
+ * Returns re-saved, fully decrypted bytes with `/Encrypt` removed.
272
+ *
273
+ * @throws {PdfPasswordRequiredError} when a non-empty password is required
274
+ * @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
275
+ */
276
+ declare const decryptPdf: (pdfBytes: Uint8Array) => Promise<Uint8Array>;
277
+ /**
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
285
+ */
286
+ declare function normalizePdfEncryption(pdfBytes: Uint8Array): Promise<Uint8Array>;
287
+
288
+ /**
289
+ * PDF Field Extraction Utilities
290
+ * Extract form fields from PDFs with metadata support for preserving field properties
291
+ */
292
+
293
+ /**
294
+ * Extracted field information
295
+ */
296
+ interface ExtractedField {
297
+ name: string;
298
+ type: 'text' | 'signature' | 'initials' | 'date' | 'checkbox' | 'radio' | 'dropdown' | 'text_label';
299
+ page: number;
300
+ x: number;
301
+ y: number;
302
+ width: number;
303
+ height: number;
304
+ required: boolean;
305
+ label?: string;
306
+ placeholder?: string;
307
+ options?: string[];
308
+ fieldId?: string;
309
+ signer?: string;
310
+ }
311
+ /**
312
+ * SigniphiMetadata structure stored in PDF Info dictionary
313
+ */
314
+ interface SigniphiMetadata {
315
+ version: string;
316
+ fields: Record<string, {
317
+ fieldId?: string;
318
+ label?: string;
319
+ signer?: string;
320
+ placeholder?: string;
321
+ required?: boolean;
322
+ options?: string[];
323
+ acknowledgements?: Array<{
324
+ id: string;
325
+ title: string;
326
+ description: string;
327
+ }>;
328
+ }>;
329
+ fieldIdIndex?: Record<string, string>;
330
+ }
331
+ /**
332
+ * Extract SigniphiMetadata from a PDF document
333
+ */
334
+ declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null;
335
+ /**
336
+ * Extract form fields from a PDF document
337
+ * @param pdfBytes - PDF bytes
338
+ * @returns Array of extracted fields with all properties
339
+ */
340
+ declare function extractFieldsFromPdf(pdfBytes: Uint8Array): Promise<ExtractedField[]>;
341
+ /**
342
+ * Set SigniphiMetadata in a PDF document
343
+ */
344
+ declare function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void;
345
+
346
+ /**
347
+ * Add Form Fields to PDF
348
+ * Re-adds form fields to a PDF after page assembly operations
349
+ * This is the key to preserving form fields - don't try to preserve during copyPages,
350
+ * instead extract fields first, copy pages, then re-add fields with adjusted positions.
351
+ */
352
+ /**
353
+ * Form field type enum matching document-prepare
354
+ */
355
+ declare enum FormFieldType {
356
+ TEXT = "text",
357
+ SIGNATURE = "signature",
358
+ INITIALS = "initials",
359
+ DATE = "date",
360
+ CHECKBOX = "checkbox",
361
+ RADIO = "radio",
362
+ DROPDOWN = "dropdown",
363
+ TEXT_LABEL = "text_label"
364
+ }
365
+ /**
366
+ * Form field position
367
+ */
368
+ interface FormFieldPosition {
369
+ x: number;
370
+ y: number;
371
+ width: number;
372
+ height: number;
373
+ page: number;
374
+ }
375
+ /**
376
+ * Form field for adding to PDF
377
+ */
378
+ interface FormFieldForPdf {
379
+ name: string;
380
+ type: FormFieldType | string;
381
+ position: FormFieldPosition;
382
+ label?: string;
383
+ required?: boolean;
384
+ options?: string[];
385
+ defaultValue?: string;
386
+ placeholder?: string;
387
+ fontSize?: number;
388
+ multiline?: boolean;
389
+ maxLength?: number;
390
+ assignedSignerEmail?: string;
391
+ }
392
+ /**
393
+ * Add form fields to a PDF document
394
+ *
395
+ * @param pdfBytes - The PDF document bytes
396
+ * @param formFields - Array of form fields to add
397
+ * @param options - Options for field addition
398
+ * @returns Modified PDF bytes with form fields added
399
+ */
400
+ declare function addFormFieldsToPdf(pdfBytes: Uint8Array, formFields: FormFieldForPdf[], options?: {
401
+ removeExistingFields?: boolean;
402
+ drawLabels?: boolean;
403
+ }): Promise<Uint8Array>;
404
+ /**
405
+ * Map field positions after page assembly
406
+ * Updates field page numbers based on the final page arrangement
407
+ *
408
+ * @param fields - Original fields with positions
409
+ * @param pageMapping - Map of "originalFileId_originalPageIndex" -> newPageNumber
410
+ * @returns Fields with updated page positions
411
+ */
412
+ declare function mapFieldPositionsAfterAssembly<T extends {
413
+ position: FormFieldPosition;
414
+ }>(fields: T[], pageMapping: Map<string, number>): T[];
415
+
416
+ export { type AssembleOptions, Button, type ExtractedField, type FileExtractedFields, type FileInfo, type FormFieldForPdf, type FormFieldPosition, FormFieldType, PageAssembler, type PageAssemblerHandle, type PageAssemblerProps, type PageAssemblerState, type PageImage, type PageInfo, PdfPasswordRequiredError, type TrackedFormField, UnsupportedPdfEncryptionError, addFormFieldsToPdf, createPdfBlobUrl, decryptPdf, downloadPdf, extractFieldsFromPdf, getSigniphiMetadata, imageToPdf, mapFieldPositionsAfterAssembly, normalizePdfEncryption, normalizeUploadedPdfBytes, pdfToImages, rasterizePdfToPdf, setSigniphiMetadata };