@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.d.mts +347 -1
- package/dist/index.d.ts +347 -1
- package/dist/index.js +1733 -59
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1724 -59
- package/dist/index.mjs.map +1 -1
- package/dist/styles/index.css +238 -166
- package/dist/styles/index.d.ts +1 -0
- package/package.json +94 -85
- package/src/styles/index.css +164 -109
- package/src/styles/index.d.ts +1 -0
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,59 @@ 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
|
+
/** RADIO: each option's circle rect, top-origin, on `position.page`. */
|
|
68
|
+
optionPositions?: Array<{
|
|
69
|
+
x: number;
|
|
70
|
+
y: number;
|
|
71
|
+
width: number;
|
|
72
|
+
height: number;
|
|
73
|
+
}>;
|
|
74
|
+
placeholder?: string;
|
|
75
|
+
defaultValue?: string;
|
|
76
|
+
assignedSignerEmail?: string;
|
|
77
|
+
fieldId?: string;
|
|
78
|
+
fontSize?: number;
|
|
79
|
+
multiline?: boolean;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
acknowledgements?: Array<{
|
|
82
|
+
id: string;
|
|
83
|
+
title: string;
|
|
84
|
+
description: string;
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Extracted fields from a file
|
|
89
|
+
*/
|
|
90
|
+
type FileExtractedFields = {
|
|
91
|
+
/** File ID these fields came from */
|
|
92
|
+
fileId: string;
|
|
93
|
+
/** Extracted form fields */
|
|
94
|
+
fields: TrackedFormField[];
|
|
95
|
+
};
|
|
42
96
|
/**
|
|
43
97
|
* State of the page assembler
|
|
44
98
|
*/
|
|
@@ -49,6 +103,10 @@ type PageAssemblerState = {
|
|
|
49
103
|
selection: string[];
|
|
50
104
|
/** ID of the last selected page (for range selection) */
|
|
51
105
|
lastSelectedPageId?: string;
|
|
106
|
+
/** Form fields tracked across page operations */
|
|
107
|
+
formFields?: TrackedFormField[];
|
|
108
|
+
/** Extracted fields per file (for mapping after assembly) */
|
|
109
|
+
extractedFieldsByFile?: FileExtractedFields[];
|
|
52
110
|
};
|
|
53
111
|
/**
|
|
54
112
|
* Options for assembling the final PDF
|
|
@@ -136,6 +194,18 @@ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAtt
|
|
|
136
194
|
declare function pdfToImages(pdfBytes: Uint8Array, options?: {
|
|
137
195
|
hideFormFields?: boolean;
|
|
138
196
|
}): Promise<PageImage[]>;
|
|
197
|
+
declare function rasterizePdfToPdf(pdfBytes: Uint8Array): Promise<Uint8Array>;
|
|
198
|
+
/**
|
|
199
|
+
* Prepares uploaded PDF bytes for the pdf-lib based assembly pipeline.
|
|
200
|
+
* Regular PDFs pass through untouched. Encrypted PDFs (typically
|
|
201
|
+
* permission-restricted documents that open without a password) are
|
|
202
|
+
* decrypted once here so every downstream `PDFDocument.load` — assembly,
|
|
203
|
+
* field extraction — sees a normal document. When structural decryption is
|
|
204
|
+
* impossible the document is rebuilt from rendered pages as a last resort.
|
|
205
|
+
*
|
|
206
|
+
* @throws {PdfPasswordRequiredError} when the PDF needs a real password
|
|
207
|
+
*/
|
|
208
|
+
declare function normalizeUploadedPdfBytes(pdfBytes: Uint8Array): Promise<Uint8Array>;
|
|
139
209
|
/**
|
|
140
210
|
* Converts an image file to a PDF document with a single page
|
|
141
211
|
*
|
|
@@ -175,4 +245,280 @@ declare function createPdfBlobUrl(pdfBytes: Uint8Array): string;
|
|
|
175
245
|
*/
|
|
176
246
|
declare function downloadPdf(pdfBytes: Uint8Array, filename: string): void;
|
|
177
247
|
|
|
178
|
-
|
|
248
|
+
interface PdfPasswordRequiredErrorConstructor {
|
|
249
|
+
new (): PdfPasswordRequiredError;
|
|
250
|
+
readonly prototype: PdfPasswordRequiredError;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Thrown when the PDF needs a non-empty user password, which this package
|
|
254
|
+
* cannot supply. Match it with {@link isPdfPasswordRequiredError} rather than
|
|
255
|
+
* `instanceof` — see the header note on copies.
|
|
256
|
+
*/
|
|
257
|
+
interface PdfPasswordRequiredError extends Error {
|
|
258
|
+
/** Always `'PDF_PASSWORD_REQUIRED'`. The check that survives package boundaries. */
|
|
259
|
+
code: string;
|
|
260
|
+
recoverable: boolean;
|
|
261
|
+
userMessage: string;
|
|
262
|
+
}
|
|
263
|
+
declare const PdfPasswordRequiredError: PdfPasswordRequiredErrorConstructor;
|
|
264
|
+
interface UnsupportedPdfEncryptionErrorConstructor {
|
|
265
|
+
new (detail: string): UnsupportedPdfEncryptionError;
|
|
266
|
+
readonly prototype: UnsupportedPdfEncryptionError;
|
|
267
|
+
}
|
|
268
|
+
/** Thrown for security handlers this decryptor does not implement. */
|
|
269
|
+
interface UnsupportedPdfEncryptionError extends Error {
|
|
270
|
+
/** Always `'UnsupportedPdfEncryptionError'`. */
|
|
271
|
+
name: string;
|
|
272
|
+
/** The scheme that is not supported, e.g. `'V5 /R6'`. */
|
|
273
|
+
readonly detail: string;
|
|
274
|
+
}
|
|
275
|
+
declare const UnsupportedPdfEncryptionError: UnsupportedPdfEncryptionErrorConstructor;
|
|
276
|
+
/**
|
|
277
|
+
* Decrypt an encrypted PDF that opens with an empty user password.
|
|
278
|
+
* Returns re-saved, fully decrypted bytes with `/Encrypt` removed.
|
|
279
|
+
*
|
|
280
|
+
* @throws {PdfPasswordRequiredError} when a non-empty password is required
|
|
281
|
+
* @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
|
|
282
|
+
*/
|
|
283
|
+
declare const decryptPdf: (pdfBytes: Uint8Array) => Promise<Uint8Array>;
|
|
284
|
+
/**
|
|
285
|
+
* Ingestion gate — see `@signiphi/pdf-crypto`'s `normalizePdfEncryption`.
|
|
286
|
+
* Returns the bytes untouched (same reference) for ordinary PDFs; decrypts and
|
|
287
|
+
* re-saves encrypted ones so every downstream `PDFDocument.load` (page
|
|
288
|
+
* assembly, field extraction) sees a normal document.
|
|
289
|
+
*
|
|
290
|
+
* @throws {PdfPasswordRequiredError} when a non-empty password is required
|
|
291
|
+
* @throws {UnsupportedPdfEncryptionError} for non-standard security handlers
|
|
292
|
+
*/
|
|
293
|
+
declare function normalizePdfEncryption(pdfBytes: Uint8Array): Promise<Uint8Array>;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* PDF Field Extraction Utilities
|
|
297
|
+
* Extract form fields from PDFs with metadata support for preserving field properties
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Extracted field information
|
|
302
|
+
*/
|
|
303
|
+
interface ExtractedField {
|
|
304
|
+
name: string;
|
|
305
|
+
type: 'text' | 'signature' | 'initials' | 'date' | 'date_signed' | 'checkbox' | 'radio' | 'dropdown' | 'text_label';
|
|
306
|
+
page: number;
|
|
307
|
+
x: number;
|
|
308
|
+
y: number;
|
|
309
|
+
width: number;
|
|
310
|
+
height: number;
|
|
311
|
+
required: boolean;
|
|
312
|
+
label?: string;
|
|
313
|
+
placeholder?: string;
|
|
314
|
+
options?: string[];
|
|
315
|
+
fieldId?: string;
|
|
316
|
+
signer?: string;
|
|
317
|
+
/**
|
|
318
|
+
* RADIO: each option's circle widget rect on this page, top-origin, in
|
|
319
|
+
* option order — exactly as read, so a re-add can put every circle back
|
|
320
|
+
* where it was. `x/y/width/height` above is only the first circle.
|
|
321
|
+
*/
|
|
322
|
+
optionPositions?: Array<{
|
|
323
|
+
x: number;
|
|
324
|
+
y: number;
|
|
325
|
+
width: number;
|
|
326
|
+
height: number;
|
|
327
|
+
}>;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* One field's metadata entry, as stored in the block.
|
|
331
|
+
*/
|
|
332
|
+
interface SigniphiFieldMetadata {
|
|
333
|
+
fieldId?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Persisted field type. Read for one value: `date_signed`, which the name
|
|
336
|
+
* guess can only see as a date. Every other key (`autofillTag`, `dateFormat`,
|
|
337
|
+
* …) is carried through the merge untouched without being declared here.
|
|
338
|
+
*/
|
|
339
|
+
type?: ExtractedField['type'];
|
|
340
|
+
label?: string;
|
|
341
|
+
signer?: string;
|
|
342
|
+
placeholder?: string;
|
|
343
|
+
required?: boolean;
|
|
344
|
+
options?: string[];
|
|
345
|
+
acknowledgements?: Array<{
|
|
346
|
+
id: string;
|
|
347
|
+
title: string;
|
|
348
|
+
description: string;
|
|
349
|
+
}>;
|
|
350
|
+
/**
|
|
351
|
+
* TEXT_LABEL only: this entry's text is already in the page stream, so the
|
|
352
|
+
* sign-time pass must not redraw it. See `mergeSourceMetadata`, which sets it
|
|
353
|
+
* when a source that had baked its labels is merged with one that deferred.
|
|
354
|
+
*/
|
|
355
|
+
textLabelBaked?: boolean;
|
|
356
|
+
/**
|
|
357
|
+
* CHECKBOX only: this field's caption is already in the page stream, written
|
|
358
|
+
* by document-prepare's bake. Declared so the merge carries it through — it
|
|
359
|
+
* is what pdf-signer's `checkboxLabelSource` actually decides on, the
|
|
360
|
+
* document-level `checkboxLabelsBaked` below being only the bake's mode.
|
|
361
|
+
* Nothing here sets or reads it.
|
|
362
|
+
*/
|
|
363
|
+
checkboxCaptionBaked?: boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Persisted geometry, written by `document-prepare` for RADIO and TEXT_LABEL
|
|
366
|
+
* fields only. Declared here for ONE reason: its `page` is the SOURCE
|
|
367
|
+
* document's page number, and the merge has to rewrite it to the combined
|
|
368
|
+
* one. Nothing in page-assembly reads x/y/width/height.
|
|
369
|
+
*/
|
|
370
|
+
position?: SigniphiFieldPosition;
|
|
371
|
+
/** Radio-only, per-option. Re-paged alongside {@link SigniphiFieldMetadata.position}. */
|
|
372
|
+
radioPositions?: SigniphiFieldPosition[];
|
|
373
|
+
/** Radio-only bound list (options ↔ circle positions); its pages are re-paged too. */
|
|
374
|
+
radioOptions?: Array<{
|
|
375
|
+
label: string;
|
|
376
|
+
exportValue: string;
|
|
377
|
+
position: SigniphiFieldPosition;
|
|
378
|
+
}>;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* A persisted field rect, as `document-prepare` writes it. `page` is 1-indexed
|
|
382
|
+
* and scoped to the document it was written in — which is exactly why the merge
|
|
383
|
+
* cannot carry it across unchanged.
|
|
384
|
+
*/
|
|
385
|
+
interface SigniphiFieldPosition {
|
|
386
|
+
x: number;
|
|
387
|
+
y: number;
|
|
388
|
+
width: number;
|
|
389
|
+
height: number;
|
|
390
|
+
page: number;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* SigniphiMetadata structure stored in PDF Info dictionary.
|
|
394
|
+
*
|
|
395
|
+
* Exported because `getSigniphiMetadata` / `setSigniphiMetadata` are public
|
|
396
|
+
* (`utils/index.ts`) and a caller cannot name their argument otherwise — which
|
|
397
|
+
* is what pushed the call sites here into `as never` casts that would have
|
|
398
|
+
* silenced any future shape mismatch.
|
|
399
|
+
*/
|
|
400
|
+
interface SigniphiMetadata {
|
|
401
|
+
version: string;
|
|
402
|
+
fields: Record<string, SigniphiFieldMetadata>;
|
|
403
|
+
fieldIdIndex?: Record<string, string>;
|
|
404
|
+
/**
|
|
405
|
+
* Document-level: radio group and option text is already drawn into the page
|
|
406
|
+
* stream, so the sign-time pass must not redraw it. Absent on legacy PDFs,
|
|
407
|
+
* which pdf-signer reads as "draw".
|
|
408
|
+
*/
|
|
409
|
+
radioLabelsBaked?: boolean;
|
|
410
|
+
/**
|
|
411
|
+
* Document-level: `false` means TEXT_LABEL text was deliberately NOT baked
|
|
412
|
+
* (multi-signer), so the sign-time pass redraws it per signer. Absent/`true`
|
|
413
|
+
* means it is already in the page stream.
|
|
414
|
+
*/
|
|
415
|
+
textLabelsBaked?: boolean;
|
|
416
|
+
/**
|
|
417
|
+
* Document-level: `false` means CHECKBOX captions were deliberately NOT baked
|
|
418
|
+
* beside their boxes (multi-signer), so the sign-time pass draws them per
|
|
419
|
+
* signer. `true` means they are already in the page stream. Absent means the
|
|
420
|
+
* source predates baked captions, which pdf-signer also reads as "draw".
|
|
421
|
+
*/
|
|
422
|
+
checkboxLabelsBaked?: boolean;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Extract SigniphiMetadata from a PDF document. Delegates to the contract
|
|
426
|
+
* package's reader; null when there is no block or it will not parse.
|
|
427
|
+
*/
|
|
428
|
+
declare function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null;
|
|
429
|
+
/**
|
|
430
|
+
* Extract form fields from a PDF document
|
|
431
|
+
* @param pdfBytes - PDF bytes
|
|
432
|
+
* @returns Array of extracted fields with all properties
|
|
433
|
+
*/
|
|
434
|
+
declare function extractFieldsFromPdf(pdfBytes: Uint8Array): Promise<ExtractedField[]>;
|
|
435
|
+
/**
|
|
436
|
+
* Set SigniphiMetadata in a PDF document. Delegates to the contract package's
|
|
437
|
+
* writer, which stores hex and throws on failure.
|
|
438
|
+
*/
|
|
439
|
+
declare function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Add Form Fields to PDF
|
|
443
|
+
* Re-adds form fields to a PDF after page assembly operations
|
|
444
|
+
* This is the key to preserving form fields - don't try to preserve during copyPages,
|
|
445
|
+
* instead extract fields first, copy pages, then re-add fields with adjusted positions.
|
|
446
|
+
*/
|
|
447
|
+
/**
|
|
448
|
+
* Form field type enum matching document-prepare
|
|
449
|
+
*/
|
|
450
|
+
declare enum FormFieldType {
|
|
451
|
+
TEXT = "text",
|
|
452
|
+
SIGNATURE = "signature",
|
|
453
|
+
INITIALS = "initials",
|
|
454
|
+
DATE = "date",
|
|
455
|
+
CHECKBOX = "checkbox",
|
|
456
|
+
RADIO = "radio",
|
|
457
|
+
DROPDOWN = "dropdown",
|
|
458
|
+
TEXT_LABEL = "text_label",
|
|
459
|
+
/** A DATE the signer never edits: stamped at signing. Re-added exactly like DATE. */
|
|
460
|
+
DATE_SIGNED = "date_signed"
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Form field position
|
|
464
|
+
*/
|
|
465
|
+
interface FormFieldPosition {
|
|
466
|
+
x: number;
|
|
467
|
+
y: number;
|
|
468
|
+
width: number;
|
|
469
|
+
height: number;
|
|
470
|
+
page: number;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Form field for adding to PDF
|
|
474
|
+
*/
|
|
475
|
+
interface FormFieldForPdf {
|
|
476
|
+
name: string;
|
|
477
|
+
type: FormFieldType | string;
|
|
478
|
+
position: FormFieldPosition;
|
|
479
|
+
label?: string;
|
|
480
|
+
required?: boolean;
|
|
481
|
+
options?: string[];
|
|
482
|
+
defaultValue?: string;
|
|
483
|
+
placeholder?: string;
|
|
484
|
+
fontSize?: number;
|
|
485
|
+
multiline?: boolean;
|
|
486
|
+
maxLength?: number;
|
|
487
|
+
assignedSignerEmail?: string;
|
|
488
|
+
/**
|
|
489
|
+
* RADIO: each option's circle widget rect, top-origin, on `position.page`,
|
|
490
|
+
* as `extractFieldsFromPdf` read it. When it covers every option, the circles
|
|
491
|
+
* are re-added exactly there instead of being laid out afresh in `position`.
|
|
492
|
+
*/
|
|
493
|
+
optionPositions?: Array<{
|
|
494
|
+
x: number;
|
|
495
|
+
y: number;
|
|
496
|
+
width: number;
|
|
497
|
+
height: number;
|
|
498
|
+
}>;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Add form fields to a PDF document
|
|
502
|
+
*
|
|
503
|
+
* @param pdfBytes - The PDF document bytes
|
|
504
|
+
* @param formFields - Array of form fields to add
|
|
505
|
+
* @param options - Options for field addition
|
|
506
|
+
* @returns Modified PDF bytes with form fields added
|
|
507
|
+
*/
|
|
508
|
+
declare function addFormFieldsToPdf(pdfBytes: Uint8Array, formFields: FormFieldForPdf[], options?: {
|
|
509
|
+
removeExistingFields?: boolean;
|
|
510
|
+
drawLabels?: boolean;
|
|
511
|
+
}): Promise<Uint8Array>;
|
|
512
|
+
/**
|
|
513
|
+
* Map field positions after page assembly
|
|
514
|
+
* Updates field page numbers based on the final page arrangement
|
|
515
|
+
*
|
|
516
|
+
* @param fields - Original fields with positions
|
|
517
|
+
* @param pageMapping - Map of "originalFileId_originalPageIndex" -> newPageNumber
|
|
518
|
+
* @returns Fields with updated page positions
|
|
519
|
+
*/
|
|
520
|
+
declare function mapFieldPositionsAfterAssembly<T extends {
|
|
521
|
+
position: FormFieldPosition;
|
|
522
|
+
}>(fields: T[], pageMapping: Map<string, number>): T[];
|
|
523
|
+
|
|
524
|
+
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 };
|