@signiphi/pdf-signer 0.2.0-beta.2 → 0.2.0-beta.21

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.
Files changed (197) hide show
  1. package/assets/viewer.html +1 -5
  2. package/dist/components/index.js +2746 -901
  3. package/dist/components/index.js.map +1 -1
  4. package/dist/components/index.mjs +2513 -669
  5. package/dist/components/index.mjs.map +1 -1
  6. package/dist/core/index.js +420 -20
  7. package/dist/core/index.js.map +1 -1
  8. package/dist/core/index.mjs +420 -20
  9. package/dist/core/index.mjs.map +1 -1
  10. package/dist/hooks/index.js +506 -211
  11. package/dist/hooks/index.js.map +1 -1
  12. package/dist/hooks/index.mjs +507 -212
  13. package/dist/hooks/index.mjs.map +1 -1
  14. package/dist/index.css +214 -191
  15. package/dist/index.css.map +1 -1
  16. package/dist/index.js +3019 -893
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +2762 -653
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/styles/index.css +202 -172
  21. package/dist/types/index.js.map +1 -1
  22. package/dist/types/index.mjs.map +1 -1
  23. package/dist/utils/index.js +792 -147
  24. package/dist/utils/index.js.map +1 -1
  25. package/dist/utils/index.mjs +777 -148
  26. package/dist/utils/index.mjs.map +1 -1
  27. package/package.json +2 -2
  28. package/scripts/copy-utils.js +14 -3
  29. package/src/styles/index.css +33 -3
  30. package/dist/__tests__/helpers/fixtures.d.ts +0 -43
  31. package/dist/__tests__/helpers/fixtures.d.ts.map +0 -1
  32. package/dist/__tests__/helpers/mocks.d.ts +0 -333
  33. package/dist/__tests__/helpers/mocks.d.ts.map +0 -1
  34. package/dist/__tests__/setup.d.ts +0 -6
  35. package/dist/__tests__/setup.d.ts.map +0 -1
  36. package/dist/components/AcknowledgementModal.d.ts +0 -21
  37. package/dist/components/AcknowledgementModal.d.ts.map +0 -1
  38. package/dist/components/AcknowledgementsSidebar.d.ts +0 -22
  39. package/dist/components/AcknowledgementsSidebar.d.ts.map +0 -1
  40. package/dist/components/AttachmentUpload.d.ts +0 -17
  41. package/dist/components/AttachmentUpload.d.ts.map +0 -1
  42. package/dist/components/EditableFieldsPanel.d.ts +0 -30
  43. package/dist/components/EditableFieldsPanel.d.ts.map +0 -1
  44. package/dist/components/ErrorBoundary.d.ts +0 -67
  45. package/dist/components/ErrorBoundary.d.ts.map +0 -1
  46. package/dist/components/FormFieldsView.d.ts +0 -46
  47. package/dist/components/FormFieldsView.d.ts.map +0 -1
  48. package/dist/components/InitialsModal.d.ts +0 -16
  49. package/dist/components/InitialsModal.d.ts.map +0 -1
  50. package/dist/components/PdfViewerStyled.d.ts +0 -16
  51. package/dist/components/PdfViewerStyled.d.ts.map +0 -1
  52. package/dist/components/PoweredBySigniphi.d.ts +0 -11
  53. package/dist/components/PoweredBySigniphi.d.ts.map +0 -1
  54. package/dist/components/RequiredFieldNavigation.d.ts +0 -18
  55. package/dist/components/RequiredFieldNavigation.d.ts.map +0 -1
  56. package/dist/components/SignatureCanvas.d.ts +0 -12
  57. package/dist/components/SignatureCanvas.d.ts.map +0 -1
  58. package/dist/components/SignatureInitialsBox.d.ts +0 -25
  59. package/dist/components/SignatureInitialsBox.d.ts.map +0 -1
  60. package/dist/components/SignatureModal.d.ts +0 -21
  61. package/dist/components/SignatureModal.d.ts.map +0 -1
  62. package/dist/components/SigningInstructions.d.ts +0 -12
  63. package/dist/components/SigningInstructions.d.ts.map +0 -1
  64. package/dist/components/SubmissionForm.d.ts +0 -52
  65. package/dist/components/SubmissionForm.d.ts.map +0 -1
  66. package/dist/components/UnacknowledgedFieldsModal.d.ts +0 -23
  67. package/dist/components/UnacknowledgedFieldsModal.d.ts.map +0 -1
  68. package/dist/components/ViewToggleToolbar.d.ts +0 -38
  69. package/dist/components/ViewToggleToolbar.d.ts.map +0 -1
  70. package/dist/components/form-fields/CheckboxRenderer.d.ts +0 -10
  71. package/dist/components/form-fields/CheckboxRenderer.d.ts.map +0 -1
  72. package/dist/components/form-fields/DateFieldRenderer.d.ts +0 -14
  73. package/dist/components/form-fields/DateFieldRenderer.d.ts.map +0 -1
  74. package/dist/components/form-fields/DropdownRenderer.d.ts +0 -14
  75. package/dist/components/form-fields/DropdownRenderer.d.ts.map +0 -1
  76. package/dist/components/form-fields/FormFieldRenderer.d.ts +0 -22
  77. package/dist/components/form-fields/FormFieldRenderer.d.ts.map +0 -1
  78. package/dist/components/form-fields/InitialsFieldRenderer.d.ts +0 -16
  79. package/dist/components/form-fields/InitialsFieldRenderer.d.ts.map +0 -1
  80. package/dist/components/form-fields/RadioGroupRenderer.d.ts +0 -10
  81. package/dist/components/form-fields/RadioGroupRenderer.d.ts.map +0 -1
  82. package/dist/components/form-fields/SignatureFieldRenderer.d.ts +0 -16
  83. package/dist/components/form-fields/SignatureFieldRenderer.d.ts.map +0 -1
  84. package/dist/components/form-fields/TextFieldRenderer.d.ts +0 -14
  85. package/dist/components/form-fields/TextFieldRenderer.d.ts.map +0 -1
  86. package/dist/components/form-fields/TextLabelRenderer.d.ts +0 -14
  87. package/dist/components/form-fields/TextLabelRenderer.d.ts.map +0 -1
  88. package/dist/components/form-fields/index.d.ts +0 -14
  89. package/dist/components/form-fields/index.d.ts.map +0 -1
  90. package/dist/components/index.d.ts +0 -17
  91. package/dist/components/index.d.ts.map +0 -1
  92. package/dist/core/PdfViewerCore.d.ts +0 -19
  93. package/dist/core/PdfViewerCore.d.ts.map +0 -1
  94. package/dist/core/SignatureCaptureCore.d.ts +0 -37
  95. package/dist/core/SignatureCaptureCore.d.ts.map +0 -1
  96. package/dist/core/index.d.ts +0 -3
  97. package/dist/core/index.d.ts.map +0 -1
  98. package/dist/hooks/index.d.ts +0 -9
  99. package/dist/hooks/index.d.ts.map +0 -1
  100. package/dist/hooks/useAcknowledgements.d.ts +0 -50
  101. package/dist/hooks/useAcknowledgements.d.ts.map +0 -1
  102. package/dist/hooks/useAttachments.d.ts +0 -25
  103. package/dist/hooks/useAttachments.d.ts.map +0 -1
  104. package/dist/hooks/useFieldFiltering.d.ts +0 -29
  105. package/dist/hooks/useFieldFiltering.d.ts.map +0 -1
  106. package/dist/hooks/useFormFields.d.ts +0 -23
  107. package/dist/hooks/useFormFields.d.ts.map +0 -1
  108. package/dist/hooks/useMultiSignerContext.d.ts +0 -25
  109. package/dist/hooks/useMultiSignerContext.d.ts.map +0 -1
  110. package/dist/hooks/usePdfViewer.d.ts +0 -52
  111. package/dist/hooks/usePdfViewer.d.ts.map +0 -1
  112. package/dist/hooks/useRequiredFieldNavigation.d.ts +0 -16
  113. package/dist/hooks/useRequiredFieldNavigation.d.ts.map +0 -1
  114. package/dist/hooks/useSignatureCapture.d.ts +0 -17
  115. package/dist/hooks/useSignatureCapture.d.ts.map +0 -1
  116. package/dist/hooks/useSignatures.d.ts +0 -29
  117. package/dist/hooks/useSignatures.d.ts.map +0 -1
  118. package/dist/index.d.ts +0 -17
  119. package/dist/index.d.ts.map +0 -1
  120. package/dist/integrations/index.d.ts +0 -6
  121. package/dist/integrations/index.d.ts.map +0 -1
  122. package/dist/integrations/next-config.d.ts +0 -46
  123. package/dist/integrations/next-config.d.ts.map +0 -1
  124. package/dist/integrations/vite-plugin.d.ts +0 -48
  125. package/dist/integrations/vite-plugin.d.ts.map +0 -1
  126. package/dist/lib/index.d.ts +0 -3
  127. package/dist/lib/index.d.ts.map +0 -1
  128. package/dist/lib/ui/accordion.d.ts +0 -8
  129. package/dist/lib/ui/accordion.d.ts.map +0 -1
  130. package/dist/lib/ui/alert.d.ts +0 -9
  131. package/dist/lib/ui/alert.d.ts.map +0 -1
  132. package/dist/lib/ui/button.d.ts +0 -12
  133. package/dist/lib/ui/button.d.ts.map +0 -1
  134. package/dist/lib/ui/calendar.d.ts +0 -10
  135. package/dist/lib/ui/calendar.d.ts.map +0 -1
  136. package/dist/lib/ui/card.d.ts +0 -9
  137. package/dist/lib/ui/card.d.ts.map +0 -1
  138. package/dist/lib/ui/checkbox.d.ts +0 -5
  139. package/dist/lib/ui/checkbox.d.ts.map +0 -1
  140. package/dist/lib/ui/dialog.d.ts +0 -20
  141. package/dist/lib/ui/dialog.d.ts.map +0 -1
  142. package/dist/lib/ui/index.d.ts +0 -13
  143. package/dist/lib/ui/index.d.ts.map +0 -1
  144. package/dist/lib/ui/input.d.ts +0 -6
  145. package/dist/lib/ui/input.d.ts.map +0 -1
  146. package/dist/lib/ui/label.d.ts +0 -6
  147. package/dist/lib/ui/label.d.ts.map +0 -1
  148. package/dist/lib/ui/popover.d.ts +0 -7
  149. package/dist/lib/ui/popover.d.ts.map +0 -1
  150. package/dist/lib/ui/radio-group.d.ts +0 -6
  151. package/dist/lib/ui/radio-group.d.ts.map +0 -1
  152. package/dist/lib/ui/select.d.ts +0 -14
  153. package/dist/lib/ui/select.d.ts.map +0 -1
  154. package/dist/lib/utils.d.ts +0 -7
  155. package/dist/lib/utils.d.ts.map +0 -1
  156. package/dist/types/index.d.ts +0 -278
  157. package/dist/types/index.d.ts.map +0 -1
  158. package/dist/utils/attachment-validators.d.ts +0 -118
  159. package/dist/utils/attachment-validators.d.ts.map +0 -1
  160. package/dist/utils/audit-trail.d.ts +0 -27
  161. package/dist/utils/audit-trail.d.ts.map +0 -1
  162. package/dist/utils/date-validation.d.ts +0 -30
  163. package/dist/utils/date-validation.d.ts.map +0 -1
  164. package/dist/utils/errors.d.ts +0 -106
  165. package/dist/utils/errors.d.ts.map +0 -1
  166. package/dist/utils/field-extraction.d.ts +0 -36
  167. package/dist/utils/field-extraction.d.ts.map +0 -1
  168. package/dist/utils/field-visibility.d.ts +0 -104
  169. package/dist/utils/field-visibility.d.ts.map +0 -1
  170. package/dist/utils/index.d.ts +0 -18
  171. package/dist/utils/index.d.ts.map +0 -1
  172. package/dist/utils/logger.d.ts +0 -16
  173. package/dist/utils/logger.d.ts.map +0 -1
  174. package/dist/utils/pdf-field-type-helpers.d.ts +0 -78
  175. package/dist/utils/pdf-field-type-helpers.d.ts.map +0 -1
  176. package/dist/utils/pdf-helpers.d.ts +0 -38
  177. package/dist/utils/pdf-helpers.d.ts.map +0 -1
  178. package/dist/utils/pdf-lib-loader.d.ts +0 -45
  179. package/dist/utils/pdf-lib-loader.d.ts.map +0 -1
  180. package/dist/utils/pdf-manipulation.d.ts +0 -93
  181. package/dist/utils/pdf-manipulation.d.ts.map +0 -1
  182. package/dist/utils/pdf-metadata.d.ts +0 -41
  183. package/dist/utils/pdf-metadata.d.ts.map +0 -1
  184. package/dist/utils/pdf-validators.d.ts +0 -149
  185. package/dist/utils/pdf-validators.d.ts.map +0 -1
  186. package/dist/utils/pdf-viewer-filter.d.ts +0 -35
  187. package/dist/utils/pdf-viewer-filter.d.ts.map +0 -1
  188. package/dist/utils/pdf-widget-helpers.d.ts +0 -98
  189. package/dist/utils/pdf-widget-helpers.d.ts.map +0 -1
  190. package/dist/utils/pdfjs-config.d.ts +0 -56
  191. package/dist/utils/pdfjs-config.d.ts.map +0 -1
  192. package/dist/utils/pdfjs-version-check.d.ts +0 -28
  193. package/dist/utils/pdfjs-version-check.d.ts.map +0 -1
  194. package/dist/utils/performance-monitor.d.ts +0 -172
  195. package/dist/utils/performance-monitor.d.ts.map +0 -1
  196. package/dist/utils/tracking.d.ts +0 -89
  197. package/dist/utils/tracking.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/logger.ts","../../src/utils/pdf-validators.ts","../../src/utils/pdf-helpers.ts","../../src/utils/pdf-metadata.ts","../../src/utils/pdf-lib-loader.ts","../../src/utils/field-visibility.ts","../../src/utils/pdf-widget-helpers.ts","../../src/utils/pdf-field-type-helpers.ts","../../src/utils/pdf-manipulation.ts","../../src/utils/field-extraction.ts","../../src/utils/pdfjs-config.ts","../../src/utils/errors.ts","../../src/utils/attachment-validators.ts","../../src/utils/date-validation.ts","../../src/utils/pdf-viewer-filter.ts","../../src/hooks/usePdfViewer.ts","../../src/hooks/useFormFields.ts","../../src/hooks/useSignatureCapture.ts","../../src/hooks/useSignatures.ts","../../src/hooks/useFieldFiltering.ts","../../src/hooks/useAttachments.ts","../../src/hooks/useMultiSignerContext.ts","../../src/hooks/useAcknowledgements.ts"],"names":["PDFName","isValidDate","PDFDocument","rgb","useState","useCallback","value","useRef","validateSignatures","useMemo"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * Logger Utility\r\n * Centralized logging system with environment-based log level control\r\n */\r\n\r\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\ninterface Logger {\r\n debug(message: string, ...args: unknown[]): void;\r\n info(message: string, ...args: unknown[]): void;\r\n warn(message: string, ...args: unknown[]): void;\r\n error(message: string, ...args: unknown[]): void;\r\n}\r\n\r\n/**\r\n * Determines if the current environment is production\r\n */\r\nfunction isProduction(): boolean {\r\n return typeof process !== 'undefined' && process.env.NODE_ENV === 'production';\r\n}\r\n\r\n/**\r\n * Creates a formatted log prefix\r\n */\r\nfunction createPrefix(level: LogLevel): string {\r\n return `[@signiphi/pdf-signer] [${level.toUpperCase()}]`;\r\n}\r\n\r\n/**\r\n * Creates the logger instance with environment-based behavior\r\n */\r\nfunction createLogger(): Logger {\r\n const isProd = isProduction();\r\n\r\n return {\r\n debug(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.log(createPrefix('debug'), message, ...args);\r\n }\r\n },\r\n\r\n info(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.log(createPrefix('info'), message, ...args);\r\n }\r\n },\r\n\r\n warn(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.warn(createPrefix('warn'), message, ...args);\r\n }\r\n },\r\n\r\n error(message: string, ...args: unknown[]): void {\r\n // Errors are shown in both development and production\r\n console.error(createPrefix('error'), message, ...args);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Singleton logger instance\r\n */\r\nexport const logger = createLogger();\r\n\r\n\r\n\r\n","/**\r\n * PDF Validation Utilities\r\n * Common validation functions used across the package\r\n */\r\n\r\nimport type { FormField } from '../types';\r\n\r\n/**\r\n * Validate that bytes represent a valid PDF file\r\n * \r\n * Checks for:\r\n * - Non-empty bytes\r\n * - Valid PDF header (%PDF-)\r\n * \r\n * @param pdfBytes - The PDF bytes to validate\r\n * @returns Validation result with valid flag and optional error message\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validatePdfBytes(pdfBytes);\r\n * if (!result.valid) {\r\n * console.error(result.error);\r\n * return;\r\n * }\r\n * ```\r\n */\r\nexport function validatePdfBytes(pdfBytes: Uint8Array): { \r\n valid: boolean; \r\n error?: string \r\n} {\r\n // Check for empty bytes\r\n if (!pdfBytes || pdfBytes.length === 0) {\r\n return { \r\n valid: false, \r\n error: 'PDF bytes are empty' \r\n };\r\n }\r\n \r\n // Check for valid PDF header\r\n const header = new TextDecoder().decode(pdfBytes.slice(0, 12));\r\n if (!header.startsWith('%PDF-')) {\r\n return { \r\n valid: false, \r\n error: 'Invalid PDF format: Missing PDF header' \r\n };\r\n }\r\n \r\n return { valid: true };\r\n}\r\n\r\n/**\r\n * Check if a label is auto-generated (not user-typed)\r\n * \r\n * Auto-generated labels are simple type names like \"Text\", \"Signature\", etc.\r\n * These are default labels assigned by the form builder and should not be\r\n * displayed to users in the same way as custom labels.\r\n * \r\n * Works identically in both single-signer and multi-signer flows.\r\n * \r\n * @param label - The label to check\r\n * @returns true if the label is auto-generated, false if it's a custom user label\r\n * \r\n * @example\r\n * ```ts\r\n * isAutoGeneratedLabel('Signature') // true\r\n * isAutoGeneratedLabel('Sign here please') // false\r\n * isAutoGeneratedLabel('') // true\r\n * ```\r\n */\r\nexport function isAutoGeneratedLabel(label: string): boolean {\r\n if (!label || !label.trim()) return true;\r\n \r\n const autoLabels = [\r\n 'Signature',\r\n 'Initials',\r\n 'Date',\r\n 'Text',\r\n 'Checkbox',\r\n 'Dropdown',\r\n 'Option',\r\n 'Radio',\r\n ];\r\n \r\n return autoLabels.includes(label.trim());\r\n}\r\n\r\n/**\r\n * Validate field values object\r\n * \r\n * Checks that the values object is properly formatted and contains\r\n * only string values for field IDs.\r\n * \r\n * @param values - Field values to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFieldValues({ field1: 'value1', field2: 'value2' });\r\n * if (!result.valid) {\r\n * console.error('Validation errors:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFieldValues(values: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if values is an object\r\n if (!values || typeof values !== 'object') {\r\n errors.push('Field values must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n // Check each value is a string\r\n const valuesObj = values as Record<string, unknown>;\r\n for (const [key, value] of Object.entries(valuesObj)) {\r\n if (typeof value !== 'string') {\r\n errors.push(`Field value for \"${key}\" must be a string, got ${typeof value}`);\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate signatures object\r\n * \r\n * Checks that signatures are properly formatted data URLs.\r\n * \r\n * @param signatures - Signatures to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateSignatures({\r\n * sig1: 'data:image/png;base64,iVBORw0KG...',\r\n * sig2: 'data:image/png;base64,iVBORw0KG...'\r\n * });\r\n * if (!result.valid) {\r\n * console.error('Invalid signatures:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateSignatures(signatures: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if signatures is an object\r\n if (!signatures || typeof signatures !== 'object') {\r\n errors.push('Signatures must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n // Check each signature is a valid data URL\r\n const sigsObj = signatures as Record<string, unknown>;\r\n for (const [key, value] of Object.entries(sigsObj)) {\r\n if (typeof value !== 'string') {\r\n errors.push(`Signature for \"${key}\" must be a string, got ${typeof value}`);\r\n continue;\r\n }\r\n \r\n // Validate data URL format\r\n if (!value.startsWith('data:image/')) {\r\n errors.push(`Signature for \"${key}\" must be a data URL starting with \"data:image/\"`);\r\n }\r\n \r\n // Check for base64 data\r\n const parts = value.split(',');\r\n if (parts.length !== 2 || !parts[1]) {\r\n errors.push(`Signature for \"${key}\" has invalid data URL format (missing base64 data)`);\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate a form field definition\r\n * \r\n * Checks that a field has all required properties and they are valid.\r\n * \r\n * @param field - Form field to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFormField({\r\n * id: 'field1',\r\n * name: 'firstName',\r\n * type: FormFieldType.TEXT,\r\n * label: 'First Name',\r\n * position: { x: 100, y: 200, width: 150, height: 30, page: 1 },\r\n * required: true\r\n * });\r\n * if (!result.valid) {\r\n * console.error('Field validation errors:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFormField(field: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if field is an object\r\n if (!field || typeof field !== 'object') {\r\n errors.push('Form field must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n const f = field as Partial<FormField>;\r\n \r\n // Required properties\r\n if (!f.id || typeof f.id !== 'string') {\r\n errors.push('Field must have a valid \"id\" string');\r\n }\r\n \r\n if (!f.type || typeof f.type !== 'string') {\r\n errors.push('Field must have a valid \"type\" string');\r\n }\r\n \r\n if (!f.name || typeof f.name !== 'string') {\r\n errors.push('Field must have a valid \"name\" string');\r\n }\r\n \r\n if (!f.label || typeof f.label !== 'string') {\r\n errors.push('Field must have a valid \"label\" string');\r\n }\r\n \r\n // Validate position\r\n if (!f.position || typeof f.position !== 'object') {\r\n errors.push('Field must have a valid \"position\" object');\r\n } else {\r\n const pos = f.position;\r\n if (typeof pos.x !== 'number') {\r\n errors.push('Field position must have a numeric \"x\" coordinate');\r\n }\r\n if (typeof pos.y !== 'number') {\r\n errors.push('Field position must have a numeric \"y\" coordinate');\r\n }\r\n if (typeof pos.width !== 'number' || pos.width <= 0) {\r\n errors.push('Field position must have a positive \"width\"');\r\n }\r\n if (typeof pos.height !== 'number' || pos.height <= 0) {\r\n errors.push('Field position must have a positive \"height\"');\r\n }\r\n if (typeof pos.page !== 'number' || pos.page < 1) {\r\n errors.push('Field position must have a valid \"page\" number (1-indexed)');\r\n }\r\n }\r\n \r\n if (typeof f.required !== 'boolean') {\r\n errors.push('Field must have a boolean \"required\" property');\r\n }\r\n \r\n // Optional properties validation\r\n if (f.fontSize !== undefined && (typeof f.fontSize !== 'number' || f.fontSize < 8 || f.fontSize > 72)) {\r\n errors.push('Field fontSize must be a number between 8 and 72');\r\n }\r\n \r\n if (f.maxLength !== undefined && (typeof f.maxLength !== 'number' || f.maxLength <= 0)) {\r\n errors.push('Field maxLength must be a positive number');\r\n }\r\n \r\n if (f.options !== undefined && !Array.isArray(f.options)) {\r\n errors.push('Field options must be an array');\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate PDF URL format\r\n * \r\n * Accepts absolute URLs, relative paths, and data URLs.\r\n * \r\n * @param url - URL to validate\r\n * @returns Validation result with valid flag and optional error message\r\n * \r\n * @example\r\n * ```ts\r\n * // Absolute URLs\r\n * validatePdfUrl('https://example.com/document.pdf'); // valid\r\n * validatePdfUrl('http://localhost:3000/doc.pdf'); // valid\r\n * \r\n * // Relative paths\r\n * validatePdfUrl('/public/document.pdf'); // valid\r\n * validatePdfUrl('./document.pdf'); // valid\r\n * \r\n * // Data URLs and blobs\r\n * validatePdfUrl('data:application/pdf;base64,...'); // valid\r\n * validatePdfUrl('blob:http://localhost/...'); // valid\r\n * \r\n * // Local files\r\n * validatePdfUrl('file:///C:/path/to/file.pdf'); // valid\r\n * ```\r\n */\r\nexport function validatePdfUrl(url: unknown): {\r\n valid: boolean;\r\n error?: string;\r\n} {\r\n if (typeof url !== 'string') {\r\n return { valid: false, error: 'URL must be a string' };\r\n }\r\n \r\n if (!url || url.trim().length === 0) {\r\n return { valid: false, error: 'URL cannot be empty' };\r\n }\r\n \r\n const trimmedUrl = url.trim();\r\n \r\n // Check for absolute URLs with protocols\r\n const validPrefixes = ['http://', 'https://', 'blob:', 'data:', 'file://'];\r\n const hasValidPrefix = validPrefixes.some(prefix => trimmedUrl.startsWith(prefix));\r\n \r\n if (hasValidPrefix) {\r\n return { valid: true };\r\n }\r\n \r\n // Allow relative paths (start with / or ./ or ../)\r\n if (trimmedUrl.startsWith('/') || trimmedUrl.startsWith('./') || trimmedUrl.startsWith('../')) {\r\n return { valid: true };\r\n }\r\n \r\n // Reject URLs that look malformed\r\n return {\r\n valid: false,\r\n error: 'URL must be an absolute URL (http://, https://, blob:, data:, file://) or a relative path (/, ./, ../)',\r\n };\r\n}\r\n\r\n","/**\r\n * PDF utility helper functions\r\n */\r\n\r\nimport { logger } from \"./logger\";\r\nimport { validatePdfBytes } from \"./pdf-validators\";\r\n\r\n/**\r\n * Create a blob URL from PDF bytes for preview\r\n */\r\nexport function createPdfBlobUrl(pdfBytes: Uint8Array): string {\r\n const blob = new Blob([pdfBytes as BlobPart], { type: 'application/pdf' });\r\n return URL.createObjectURL(blob);\r\n}\r\n\r\n/**\r\n * Download PDF file\r\n */\r\nexport function downloadPdf(pdfBytes: Uint8Array, filename: string): void {\r\n const url = createPdfBlobUrl(pdfBytes);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = filename;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n}\r\n\r\n/**\r\n * Convert URL to PDF bytes\r\n * @param url - The URL to fetch the PDF from\r\n * @returns PDF bytes as Uint8Array\r\n */\r\nexport async function urlToPdfBytes(url: string): Promise<Uint8Array> {\r\n try {\r\n const response = await fetch(url);\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer();\r\n\r\n // Create a new Uint8Array and copy the data to avoid detached ArrayBuffer issues\r\n const pdfBytes = new Uint8Array(arrayBuffer.byteLength);\r\n pdfBytes.set(new Uint8Array(arrayBuffer));\r\n\r\n // Validate that we have a PDF\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n throw new Error(validation.error || 'Invalid PDF format');\r\n }\r\n\r\n return pdfBytes;\r\n } catch (error) {\r\n logger.error('Error fetching PDF from URL:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Validate that data is a valid PDF\r\n */\r\nexport function isValidPdf(pdfBytes: Uint8Array): boolean {\r\n const validation = validatePdfBytes(pdfBytes);\r\n return validation.valid;\r\n}\r\n\r\n/**\r\n * Convert base64 data URL to image bytes\r\n */\r\nexport function dataUrlToBytes(dataUrl: string): Uint8Array {\r\n const base64Data = dataUrl.split(',')[1];\r\n if (!base64Data) {\r\n throw new Error('Invalid data URL format: missing base64 data');\r\n }\r\n return Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));\r\n}\r\n\r\n/**\r\n * Format field name for display\r\n */\r\nexport function formatFieldName(fieldName: string): string {\r\n return fieldName\r\n .replace(/[_-]/g, ' ')\r\n .replace(/\\b\\w/g, (l) => l.toUpperCase())\r\n .replace('Signature', '')\r\n .replace('Initials', '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Check if a field is a signature field\r\n */\r\nexport function isSignatureField(fieldName: string): boolean {\r\n return fieldName.toLowerCase().includes('signature');\r\n}\r\n\r\n/**\r\n * Check if a field is an initials field\r\n */\r\nexport function isInitialsField(fieldName: string): boolean {\r\n return fieldName.toLowerCase().includes('initials');\r\n}\r\n\r\n","/**\r\n * PDF Metadata Utilities\r\n * Functions for storing and retrieving Signiphi metadata in PDF documents\r\n */\r\n\r\nimport type { PDFDocument, PDFName as PDFNameType, PDFString as PDFStringType } from 'pdf-lib';\r\nimport { Acknowledgement } from '../types';\r\n\r\n// Module-level variables for pdf-lib classes (loaded dynamically)\r\nlet PDFName: typeof PDFNameType;\r\nlet PDFString: typeof PDFStringType;\r\n\r\n/**\r\n * Initialize PDF classes from dynamically loaded pdf-lib module\r\n * Must be called before using getSigniphiMetadata or setSigniphiMetadata\r\n */\r\nexport function initPdfMetadata(pdfLibModule: any): void {\r\n PDFName = pdfLibModule.PDFName;\r\n PDFString = pdfLibModule.PDFString;\r\n}\r\n\r\n/**\r\n * Metadata for a single form field\r\n */\r\nexport interface FieldMetadata {\r\n fieldId?: string; // Immutable UUID for reliable field identification\r\n label?: string;\r\n signer?: string;\r\n placeholder?: string;\r\n acknowledgements?: Acknowledgement[];\r\n}\r\n\r\n/**\r\n * Complete metadata structure stored in PDF\r\n */\r\nexport interface SigniphiMetadata {\r\n version: string;\r\n fields: Record<string, FieldMetadata>; // Key is the clean field name\r\n}\r\n\r\n/**\r\n * Stores Signiphi metadata in the PDF's document information dictionary\r\n * @param pdfDoc - The PDF document to store metadata in\r\n * @param metadata - The metadata object to store\r\n */\r\nexport function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void {\r\n try {\r\n if (!PDFName || !PDFString) {\r\n console.error('PDF metadata classes not initialized. Call initPdfMetadata first.');\r\n return;\r\n }\r\n \r\n const infoRef = pdfDoc.context.trailerInfo.Info;\r\n const infoObj = pdfDoc.context.lookup(infoRef);\r\n if (!infoObj || typeof (infoObj as any).set !== 'function') {\r\n throw new Error('Info object is not a PDFDict or does not have set method');\r\n }\r\n const infoDict = infoObj as any;\r\n const metadataString = JSON.stringify(metadata);\r\n \r\n // Set the metadata\r\n infoDict.set(PDFName.of('SigniphiMetadata'), PDFString.of(metadataString));\r\n } catch (error) {\r\n console.error('Failed to set Signiphi metadata:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves Signiphi metadata from the PDF's document information dictionary\r\n * @param pdfDoc - The PDF document to read metadata from\r\n * @returns The metadata object if found, null otherwise\r\n */\r\nexport function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null {\r\n try {\r\n if (!PDFName || !PDFString) {\r\n console.error('PDF metadata classes not initialized. Call initPdfMetadata first.');\r\n return null;\r\n }\r\n \r\n const infoRef = pdfDoc.context.trailerInfo.Info;\r\n const infoObj = pdfDoc.context.lookup(infoRef);\r\n \r\n if (!infoObj || typeof (infoObj as any).get !== 'function' || !(infoObj as any).dict) {\r\n return null;\r\n }\r\n \r\n const infoDict = infoObj as any;\r\n const metadataObj = infoDict.get(PDFName.of('SigniphiMetadata'));\r\n \r\n if (!metadataObj) {\r\n return null;\r\n }\r\n \r\n // PDFString objects are encoded as \"(content)\" in their toString() representation\r\n const metadataStr = metadataObj.toString();\r\n \r\n // Extract content from PDF string format: (content) or <hex>\r\n let jsonStr = metadataStr;\r\n const parenMatch = metadataStr.match(/^\\((.*)\\)$/);\r\n if (parenMatch && parenMatch[1]) {\r\n jsonStr = parenMatch[1];\r\n } else {\r\n const hexMatch = metadataStr.match(/^<(.*)>$/);\r\n if (hexMatch && hexMatch[1]) {\r\n // Convert hex to string if needed\r\n jsonStr = hexMatch[1];\r\n }\r\n }\r\n \r\n const metadata = JSON.parse(jsonStr);\r\n return metadata;\r\n } catch (error) {\r\n console.error('Failed to load Signiphi metadata:', error);\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Lazy loader for pdf-lib\r\n * \r\n * This module provides a lazy loading mechanism for the pdf-lib library (~150KB).\r\n * By deferring the import until actually needed, we can significantly reduce\r\n * the initial bundle size for consumers who only view PDFs without filling forms.\r\n * \r\n * The pdf-lib library is only loaded when:\r\n * - fillPdf() is called\r\n * - combinePdfs() is called\r\n * - Other PDF manipulation functions are used\r\n */\r\n\r\n// Cache the promise to ensure we only import once\r\nlet pdfLibPromise: Promise<typeof import('pdf-lib')> | null = null;\r\n\r\n/**\r\n * Dynamically import pdf-lib library\r\n * \r\n * This function lazily loads pdf-lib only when needed. The import is cached\r\n * so subsequent calls return the same promise, avoiding multiple imports.\r\n * \r\n * @returns Promise resolving to the pdf-lib module\r\n * \r\n * @example\r\n * ```typescript\r\n * const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n * const pdfDoc = await PDFDocument.load(pdfBytes);\r\n * ```\r\n */\r\nexport async function loadPdfLib() {\r\n if (!pdfLibPromise) {\r\n pdfLibPromise = import('pdf-lib');\r\n }\r\n return pdfLibPromise;\r\n}\r\n\r\n/**\r\n * Check if pdf-lib has been loaded\r\n * \r\n * Useful for debugging and testing to verify lazy loading behavior.\r\n * \r\n * @returns true if pdf-lib has been loaded, false otherwise\r\n */\r\nexport function isPdfLibLoaded(): boolean {\r\n return pdfLibPromise !== null;\r\n}\r\n\r\n/**\r\n * Reset the pdf-lib cache (primarily for testing)\r\n * \r\n * This should only be used in test environments to reset state\r\n * between tests.\r\n * \r\n * @internal\r\n */\r\nexport function resetPdfLibCache(): void {\r\n pdfLibPromise = null;\r\n}\r\n\r\n","/**\r\n * Field Visibility Utilities\r\n * Core logic for determining which fields are visible/editable in multi-signer mode\r\n * \r\n * CRITICAL: This logic must work identically in both flows:\r\n * - Single-signer flow: isMultiSigner = false, all fields visible\r\n * - Multi-signer flow: isMultiSigner = true, filtered by assignment rules\r\n */\r\n\r\nimport type { EsignFormField, MultiSignerContext } from '../types';\r\n\r\n/**\r\n * Determine if a field should be visible to the current signer\r\n * \r\n * Implements the 5-rule visibility logic used throughout the application:\r\n * - Rule 1: Unassigned fields → only final signer sees them\r\n * - Rule 2: Direct assignment → show if assigned to current signer\r\n * - Rule 3: Recipients group → only primary signers (signOrder === 1)\r\n * - Rule 4: Signers group → only final signer\r\n * - Rule 5: Assigned to different signer → hide\r\n * \r\n * @param field - The form field to check\r\n * @param multiSignerContext - Multi-signer context with current signer info\r\n * @returns true if field should be visible, false if hidden\r\n * \r\n * @example Single-signer flow\r\n * ```ts\r\n * const context = { isMultiSigner: false, ... };\r\n * isFieldVisibleToSigner(anyField, context); // always returns true\r\n * ```\r\n * \r\n * @example Multi-signer flow\r\n * ```ts\r\n * const context = {\r\n * isMultiSigner: true,\r\n * currentSignerEmail: 'signer1@example.com',\r\n * isPrimarySigner: true,\r\n * isFinalSigner: false\r\n * };\r\n * \r\n * // Unassigned field - only final signer sees it\r\n * isFieldVisibleToSigner({ assignedSignerEmail: undefined, ... }, context); // false\r\n * \r\n * // Direct assignment to current signer\r\n * isFieldVisibleToSigner({ assignedSignerEmail: 'signer1@example.com', ... }, context); // true\r\n * \r\n * // Recipients group - primary signer sees it\r\n * isFieldVisibleToSigner({ assignedSignerEmail: 'recipients', ... }, context); // true\r\n * ```\r\n */\r\nexport function isFieldVisibleToSigner(\r\n field: EsignFormField,\r\n multiSignerContext: MultiSignerContext\r\n): boolean {\r\n // Single-signer mode: all fields are visible\r\n if (!multiSignerContext.isMultiSigner) {\r\n return true;\r\n }\r\n\r\n const { currentSignerEmail, isPrimarySigner, isFinalSigner } = multiSignerContext;\r\n\r\n // RULE 1: Unassigned fields - only final signer sees them\r\n if (!field.assignedSignerEmail) {\r\n return isFinalSigner;\r\n }\r\n\r\n // RULE 2: Direct assignment - show if assigned to current signer\r\n if (field.assignedSignerEmail === currentSignerEmail) {\r\n return true;\r\n }\r\n\r\n // RULE 3: Recipients group - only primary signers (signOrder === 1)\r\n if (field.assignedSignerEmail.includes('recipients')) {\r\n return isPrimarySigner;\r\n }\r\n\r\n // RULE 4: Signers group - only final signer\r\n if (field.assignedSignerEmail.includes('signers')) {\r\n return isFinalSigner;\r\n }\r\n\r\n // RULE 5: Assigned to different signer - hide\r\n return false;\r\n}\r\n\r\n/**\r\n * Filter an array of fields to only those visible to the current signer\r\n * \r\n * @param fields - All form fields\r\n * @param multiSignerContext - Multi-signer context\r\n * @returns Filtered array of visible fields\r\n * \r\n * @example\r\n * ```ts\r\n * const allFields = [...]; // 10 fields\r\n * const context = { isMultiSigner: true, isPrimarySigner: true, ... };\r\n * const visible = filterFieldsBySigner(allFields, context); // 5 fields (only primary signer's)\r\n * ```\r\n */\r\nexport function filterFieldsBySigner(\r\n fields: EsignFormField[],\r\n multiSignerContext: MultiSignerContext\r\n): EsignFormField[] {\r\n // Single-signer mode: return all fields\r\n if (!multiSignerContext.isMultiSigner) {\r\n return fields;\r\n }\r\n\r\n // Multi-signer mode: filter using visibility logic\r\n return fields.filter(field => isFieldVisibleToSigner(field, multiSignerContext));\r\n}\r\n\r\n/**\r\n * Determine if a field should be flattened (made non-editable) by the current signer\r\n * \r\n * Used during PDF submission to determine which fields to flatten.\r\n * In multi-signer mode, only flatten fields assigned to current signer.\r\n * In single-signer mode, flatten all fields.\r\n * \r\n * CRITICAL: This affects PDF flattening behavior - must preserve exact logic!\r\n * \r\n * @param field - The form field to check\r\n * @param multiSignerContext - Multi-signer context\r\n * @returns true if current signer should flatten this field\r\n * \r\n * @example Single-signer flow\r\n * ```ts\r\n * const context = { isMultiSigner: false, ... };\r\n * shouldFlattenField(anyField, context); // always returns true\r\n * ```\r\n * \r\n * @example Multi-signer flow\r\n * ```ts\r\n * const context = {\r\n * isMultiSigner: true,\r\n * currentSignerEmail: 'signer1@example.com',\r\n * isPrimarySigner: true,\r\n * isFinalSigner: false\r\n * };\r\n * \r\n * // Current signer's field - flatten it\r\n * shouldFlattenField({ assignedSignerEmail: 'signer1@example.com', ... }, context); // true\r\n * \r\n * // Different signer's field - don't flatten (keep editable for them)\r\n * shouldFlattenField({ assignedSignerEmail: 'signer2@example.com', ... }, context); // false\r\n * \r\n * // Unassigned field - only final signer flattens\r\n * shouldFlattenField({ assignedSignerEmail: undefined, ... }, context); // false (not final)\r\n * ```\r\n */\r\nexport function shouldFlattenField(\r\n field: EsignFormField,\r\n multiSignerContext: MultiSignerContext\r\n): boolean {\r\n // Single-signer mode: flatten all fields\r\n if (!multiSignerContext.isMultiSigner) {\r\n return true;\r\n }\r\n\r\n const { currentSignerEmail, isPrimarySigner, isFinalSigner } = multiSignerContext;\r\n\r\n // RULE 1: Unassigned fields - only final signer flattens them\r\n if (!field.assignedSignerEmail) {\r\n return isFinalSigner;\r\n }\r\n\r\n // RULE 2: Direct assignment - flatten if assigned to current signer\r\n if (field.assignedSignerEmail === currentSignerEmail) {\r\n return true;\r\n }\r\n\r\n // RULE 3: Recipients group - only primaries flatten them\r\n if (field.assignedSignerEmail.includes('recipients')) {\r\n return isPrimarySigner;\r\n }\r\n\r\n // RULE 4: Signers group - only final signer flattens them\r\n if (field.assignedSignerEmail.includes('signers')) {\r\n return isFinalSigner;\r\n }\r\n\r\n // RULE 5: Assigned to different signer - DON'T flatten (keep editable for them)\r\n return false;\r\n}\r\n\r\n","/**\r\n * PDF Widget Helper Utilities\r\n * Common utilities for working with PDF widgets and pages\r\n * \r\n * Used across pdf-manipulation.ts and pdf-viewer-filter.ts\r\n */\r\n\r\nimport type { PDFPage } from 'pdf-lib';\r\n\r\n/**\r\n * Extended type for PDF pages with ref property\r\n */\r\ninterface PDFPageWithRef {\r\n ref: unknown;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Find the page index for a given page reference\r\n * \r\n * This is a common pattern used when working with PDF widgets to determine\r\n * which page a widget belongs to by comparing page references.\r\n * \r\n * @param pages - Array of PDF pages\r\n * @param pageRef - The page reference to search for\r\n * @returns Page index (0-based), or -1 if not found\r\n * \r\n * @example\r\n * ```ts\r\n * const widget = widgets[0];\r\n * const pageRef = widget.P?.();\r\n * const pageIndex = findPageIndexByRef(pages, pageRef);\r\n * if (pageIndex >= 0) {\r\n * const page = pages[pageIndex];\r\n * // Draw on the page\r\n * }\r\n * ```\r\n */\r\nexport function findPageIndexByRef(\r\n pages: PDFPage[],\r\n pageRef: unknown\r\n): number {\r\n if (!pageRef) return -1;\r\n \r\n for (let i = 0; i < pages.length; i++) {\r\n const page = pages[i] as unknown as PDFPageWithRef;\r\n if (page.ref === pageRef) {\r\n return i;\r\n }\r\n }\r\n \r\n return -1;\r\n}\r\n\r\n/**\r\n * Extended type for PDF widgets with rectangle and page methods\r\n */\r\nexport interface PDFWidgetWithExtensions {\r\n getRectangle?: () => { x: number; y: number; width: number; height: number } | undefined;\r\n P?: () => unknown;\r\n}\r\n\r\n/**\r\n * Get widget rectangle and its page\r\n * \r\n * Helper to extract both the rectangle coordinates and the page that a widget\r\n * belongs to in a single operation.\r\n * \r\n * @param widget - The PDF widget\r\n * @param pages - Array of PDF pages\r\n * @returns Object with rect, page, and pageIndex, or null if unable to determine\r\n * \r\n * @example\r\n * ```ts\r\n * for (const widget of widgets) {\r\n * const result = getWidgetRectangleAndPage(widget, pages);\r\n * if (result) {\r\n * const { rect, page, pageIndex } = result;\r\n * // Draw something at rect coordinates on page\r\n * page.drawRectangle({ x: rect.x, y: rect.y, ... });\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function getWidgetRectangleAndPage(\r\n widget: PDFWidgetWithExtensions,\r\n pages: PDFPage[]\r\n): {\r\n rect: { x: number; y: number; width: number; height: number };\r\n page: PDFPage;\r\n pageIndex: number;\r\n} | null {\r\n const rect = widget.getRectangle?.();\r\n if (!rect) return null;\r\n \r\n const pageRef = widget.P?.();\r\n if (!pageRef) return null;\r\n \r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n if (pageIndex === -1) return null;\r\n \r\n const page = pages[pageIndex];\r\n if (!page) return null;\r\n \r\n return { rect, page, pageIndex };\r\n}\r\n\r\n/**\r\n * Find page index with fallback to single-page PDFs\r\n * \r\n * Same as findPageIndexByRef but with a fallback: if pageRef lookup fails\r\n * and there's only one page in the document, returns index 0.\r\n * \r\n * This is useful for label drawing where single-page PDFs might not have\r\n * proper page references but we can safely assume page 0.\r\n * \r\n * @param pages - Array of PDF pages\r\n * @param pageRef - The page reference to search for\r\n * @returns Page index (0-based), 0 if single-page PDF, or -1 if not found\r\n * \r\n * @example\r\n * ```ts\r\n * // Used in pdf-viewer-filter for label drawing\r\n * const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n * if (pageIndex >= 0) {\r\n * const page = pages[pageIndex];\r\n * page.drawText(label, ...);\r\n * }\r\n * ```\r\n */\r\nexport function findPageIndexWithFallback(\r\n pages: PDFPage[],\r\n pageRef: unknown\r\n): number {\r\n if (!pageRef) {\r\n // No page ref - fallback to page 0 if single-page PDF\r\n return pages.length === 1 ? 0 : -1;\r\n }\r\n \r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n \r\n // If not found but single-page PDF, assume page 0\r\n if (pageIndex === -1 && pages.length === 1) {\r\n return 0;\r\n }\r\n \r\n return pageIndex;\r\n}\r\n\r\n","/**\r\n * PDF Field Type Helper Utilities\r\n * Common utilities for detecting field types and extracting values\r\n * \r\n * Used across pdf-manipulation.ts for consistent field processing\r\n */\r\n\r\n/**\r\n * PDF form field type for operations\r\n */\r\ninterface PDFFormField {\r\n getName(): string;\r\n constructor: { name: string };\r\n getText?(): string;\r\n setText?(text: string): void;\r\n isRequired?(): boolean;\r\n isChecked?(): boolean;\r\n getSelected?(): string[];\r\n enableReadOnly?(): void;\r\n}\r\n\r\n/**\r\n * Detect the field type from a PDF field\r\n * \r\n * Maps pdf-lib's field constructor names to standardized type strings.\r\n * \r\n * @param field - The PDF form field\r\n * @returns Standardized field type string\r\n * \r\n * @example\r\n * ```ts\r\n * const fieldType = detectFieldType(field);\r\n * // Returns: 'text', 'checkbox', 'dropdown', 'radiogroup', 'signature', etc.\r\n * ```\r\n */\r\nexport function detectFieldType(field: PDFFormField): string {\r\n const typeName = field.constructor.name;\r\n \r\n if (typeName === 'PDFTextField') {\r\n return 'text';\r\n } else if (typeName === 'PDFCheckBox') {\r\n return 'checkbox';\r\n } else if (typeName === 'PDFDropdown') {\r\n return 'dropdown';\r\n } else if (typeName === 'PDFOptionList') {\r\n return 'optionlist';\r\n } else if (typeName === 'PDFRadioGroup') {\r\n return 'radiogroup';\r\n } else if (typeName === 'PDFSignature') {\r\n return 'signature';\r\n }\r\n \r\n return 'unknown';\r\n}\r\n\r\n/**\r\n * Extract the current value from a PDF field based on its type\r\n * \r\n * Handles different field types appropriately:\r\n * - Text fields: getText()\r\n * - Checkboxes: isChecked() → 'true'/'false'\r\n * - Dropdowns: getSelected()[0]\r\n * - Radio groups: getSelected()[0]\r\n * \r\n * @param field - The PDF form field\r\n * @param fieldType - The field type (from detectFieldType)\r\n * @returns The field value as a string, or empty string if no value\r\n * \r\n * @example\r\n * ```ts\r\n * const fieldType = detectFieldType(field);\r\n * const value = extractFieldValue(field, fieldType);\r\n * ```\r\n */\r\nexport function extractFieldValue(field: PDFFormField, fieldType: string): string {\r\n try {\r\n switch (fieldType) {\r\n case 'text':\r\n return field.getText?.() || '';\r\n \r\n case 'checkbox':\r\n return field.isChecked?.() ? 'true' : 'false';\r\n \r\n case 'dropdown':\r\n case 'optionlist':\r\n case 'radiogroup':\r\n return field.getSelected?.()?.[0] || '';\r\n \r\n default:\r\n return '';\r\n }\r\n } catch (error) {\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Check if a field is required based on field metadata and name patterns\r\n * \r\n * Attempts to determine required status through:\r\n * 1. field.isRequired() method (if available)\r\n * 2. Field name patterns (signature, initials, required)\r\n * 3. Field type (signatures are always required)\r\n * \r\n * @param field - The PDF form field\r\n * @param fieldName - The field name\r\n * @param fieldType - The field type (from detectFieldType)\r\n * @returns true if field is required\r\n * \r\n * @example\r\n * ```ts\r\n * const isRequired = isRequiredField(field, 'signature_1', 'text');\r\n * // Returns: true (signature fields are required)\r\n * ```\r\n */\r\nexport function isRequiredField(\r\n field: PDFFormField,\r\n fieldName: string,\r\n fieldType: string\r\n): boolean {\r\n // Signature fields are always required\r\n if (fieldType === 'signature') {\r\n return true;\r\n }\r\n \r\n // Try the isRequired method if available\r\n try {\r\n if (field.isRequired?.()) {\r\n return true;\r\n }\r\n } catch {\r\n // isRequired() not available or threw error\r\n }\r\n \r\n // Check field name patterns\r\n if (\r\n fieldName.includes('signature') ||\r\n fieldName.includes('initials') ||\r\n fieldName.includes('required')\r\n ) {\r\n return true;\r\n }\r\n \r\n return false;\r\n}\r\n\r\n","/**\r\n * PDF Manipulation Utilities\r\n * Core utilities for PDF processing, page manipulation, and file combining\r\n */\r\n\r\nimport * as pdfjsLib from 'pdfjs-dist';\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport { \r\n PdfPage, \r\n EsignFormField, \r\n FormFieldType, \r\n FormFieldPosition,\r\n MultiSignerContext \r\n} from '../types';\r\nimport { logger } from './logger';\r\nimport { validatePdfBytes, isAutoGeneratedLabel } from './pdf-validators';\r\nimport { isFieldVisibleToSigner, shouldFlattenField } from './field-visibility';\r\nimport { findPageIndexByRef, getWidgetRectangleAndPage, type PDFWidgetWithExtensions } from './pdf-widget-helpers';\r\nimport { detectFieldType, extractFieldValue, isRequiredField } from './pdf-field-type-helpers';\r\n\r\n// PDF.js worker is automatically configured by pdfjs-config module\r\n\r\n// Type definitions for PDF internal structures\r\ninterface PDFFieldWithAcro {\r\n getName(): string;\r\n acroField?: {\r\n getWidgets?: () => PDFWidget[];\r\n };\r\n constructor: { name: string };\r\n}\r\n\r\ninterface PDFWidget {\r\n getRectangle?: () => { x: number; y: number; width: number; height: number };\r\n P?: () => unknown;\r\n}\r\n\r\n/**\r\n * Convert PDF pages to images for rendering in the UI using PDF.js\r\n */\r\nexport async function pdfToImages(\r\n pdfBytes: Uint8Array,\r\n options?: { hideFormFields?: boolean }\r\n): Promise<PdfPage[]> {\r\n try {\r\n // Validate PDF bytes\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n logger.error('Invalid PDF:', validation.error);\r\n throw new Error(validation.error || 'Invalid PDF format');\r\n }\r\n\r\n // Load PDF with PDF.js\r\n const loadingTask = pdfjsLib.getDocument({\r\n data: pdfBytes,\r\n verbosity: 0,\r\n });\r\n const pdfDoc = await loadingTask.promise;\r\n\r\n const pages: PdfPage[] = [];\r\n\r\n // Try to load with pdf-lib for dimension comparison\r\n let pdfLibDoc = null;\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n pdfLibDoc = await PDFDocument.load(pdfBytes);\r\n } catch {\r\n // PDF.js dimensions will be used instead\r\n }\r\n\r\n for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {\r\n const page = await pdfDoc.getPage(pageNum);\r\n const viewport = page.getViewport({ scale: 2.0 });\r\n\r\n // Get actual PDF dimensions\r\n let pdfWidth = viewport.width / 2.0;\r\n let pdfHeight = viewport.height / 2.0;\r\n\r\n // Use pdf-lib dimensions if available for consistency\r\n if (pdfLibDoc) {\r\n try {\r\n const pdfLibPage = pdfLibDoc.getPage(pageNum - 1);\r\n pdfWidth = pdfLibPage.getWidth();\r\n pdfHeight = pdfLibPage.getHeight();\r\n } catch {\r\n // Use PDF.js dimensions as fallback\r\n }\r\n }\r\n\r\n // Create canvas at the scaled size for high quality rendering\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n canvas.height = viewport.height;\r\n canvas.width = viewport.width;\r\n\r\n // Render PDF page to canvas\r\n const hideFormFields = options?.hideFormFields ?? false;\r\n const renderContext: any = {\r\n canvasContext: context,\r\n viewport: viewport,\r\n renderInteractiveForms: !hideFormFields,\r\n ...(hideFormFields && {\r\n annotationMode: 0,\r\n renderAnnotations: false,\r\n renderForms: false,\r\n }),\r\n };\r\n\r\n await page.render(renderContext).promise;\r\n\r\n // Convert canvas to data URL\r\n const imageUrl = canvas.toDataURL('image/png');\r\n\r\n pages.push({\r\n pageNumber: pageNum,\r\n width: pdfWidth,\r\n height: pdfHeight,\r\n imageUrl,\r\n renderWidth: viewport.width,\r\n renderHeight: viewport.height,\r\n });\r\n }\r\n\r\n return pages;\r\n } catch (error) {\r\n logger.error('Error converting PDF to images with PDF.js:', error);\r\n return await fallbackPdfToImages(pdfBytes);\r\n }\r\n}\r\n\r\n/**\r\n * Fallback function to create placeholder images when PDF.js fails\r\n */\r\nasync function fallbackPdfToImages(pdfBytes: Uint8Array): Promise<PdfPage[]> {\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n const pdf = await PDFDocument.load(pdfBytes);\r\n const pages: PdfPage[] = [];\r\n\r\n for (let i = 0; i < pdf.getPageCount(); i++) {\r\n const page = pdf.getPage(i);\r\n const { width, height } = page.getSize();\r\n \r\n // Create placeholder canvas\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n \r\n const scale = 1.5;\r\n canvas.width = width * scale;\r\n canvas.height = height * scale;\r\n \r\n // Draw placeholder\r\n context.fillStyle = '#ffffff';\r\n context.fillRect(0, 0, canvas.width, canvas.height);\r\n context.strokeStyle = '#e5e7eb';\r\n context.lineWidth = 2;\r\n context.strokeRect(0, 0, canvas.width, canvas.height);\r\n context.fillStyle = '#6b7280';\r\n context.font = 'bold 24px system-ui';\r\n context.textAlign = 'center';\r\n context.fillText(`Page ${i + 1}`, canvas.width / 2, canvas.height / 2 - 20);\r\n context.font = '16px system-ui';\r\n context.fillStyle = '#9ca3af';\r\n context.fillText('PDF preview not available', canvas.width / 2, canvas.height / 2 + 20);\r\n \r\n const imageUrl = canvas.toDataURL('image/png');\r\n \r\n pages.push({\r\n pageNumber: i + 1,\r\n width,\r\n height,\r\n imageUrl,\r\n renderWidth: canvas.width,\r\n renderHeight: canvas.height,\r\n });\r\n }\r\n\r\n return pages;\r\n } catch (error) {\r\n logger.error('Error with pdf-lib fallback:', error);\r\n // Return single error page\r\n return [createErrorPage()];\r\n }\r\n}\r\n\r\n/**\r\n * Create an error page when all processing fails\r\n */\r\nfunction createErrorPage(): PdfPage {\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n canvas.width = 600;\r\n canvas.height = 800;\r\n \r\n context.fillStyle = '#ffffff';\r\n context.fillRect(0, 0, canvas.width, canvas.height);\r\n context.strokeStyle = '#e5e7eb';\r\n context.lineWidth = 2;\r\n context.strokeRect(0, 0, canvas.width, canvas.height);\r\n context.fillStyle = '#ef4444';\r\n context.font = 'bold 20px system-ui';\r\n context.textAlign = 'center';\r\n context.fillText('PDF Processing Error', canvas.width / 2, canvas.height / 2 - 20);\r\n context.font = '14px system-ui';\r\n context.fillStyle = '#6b7280';\r\n context.fillText('Unable to process the uploaded PDF file', canvas.width / 2, canvas.height / 2 + 20);\r\n \r\n return {\r\n pageNumber: 1,\r\n width: 600,\r\n height: 800,\r\n imageUrl: canvas.toDataURL('image/png'),\r\n renderWidth: canvas.width,\r\n renderHeight: canvas.height,\r\n };\r\n}\r\n\r\n// Type definitions for PDF form field operations\r\ninterface PDFFormField {\r\n getName(): string;\r\n constructor: { name: string };\r\n getText?(): string;\r\n setText?(text: string): void;\r\n isRequired?(): boolean;\r\n isChecked?(): boolean;\r\n getSelected?(): string[];\r\n enableReadOnly?(): void;\r\n}\r\n\r\ninterface PDFFormFieldWithAcro extends PDFFormField {\r\n acroField: {\r\n getWidgets(): unknown[];\r\n removeWidget(index: number): void;\r\n };\r\n}\r\n\r\ninterface PDFDict {\r\n get(key: unknown): unknown;\r\n delete(key: unknown): void;\r\n}\r\n\r\n/**\r\n * Remove all existing form fields from a PDF using robust widget cleanup\r\n * @param pdfBytes - The PDF bytes\r\n * @param stripAllAnnotations - If true, removes all annotations from pages (more aggressive cleanup)\r\n * @returns The PDF bytes with all form fields removed\r\n */\r\nexport async function removeAllFormFields(pdfBytes: Uint8Array, stripAllAnnotations = false): Promise<Uint8Array> {\r\n try {\r\n // Validate PDF data first\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n return pdfBytes;\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n if (stripAllAnnotations) {\r\n // More aggressive approach: strip all annotations from all pages\r\n const pages = pdfDoc.getPages();\r\n \r\n for (let i = 0; i < pages.length; i++) {\r\n const page = pages[i];\r\n \r\n try {\r\n // Access the page's annotation array\r\n const pageRef = (page as any).ref;\r\n const pageDictObj = pdfDoc.context.lookup(pageRef);\r\n \r\n if (pageDictObj) {\r\n const pageDict = pageDictObj as unknown as PDFDict;\r\n \r\n if (pageDict && pageDict.get && pageDict.delete) {\r\n const annotsRef = pageDict.get((pdfDoc.context as any).obj('Annots'));\r\n \r\n if (annotsRef) {\r\n pageDict.delete((pdfDoc.context as any).obj('Annots'));\r\n }\r\n } else {\r\n }\r\n } else {\r\n }\r\n } catch (pageError) {\r\n }\r\n }\r\n } else {\r\n // Robust widget-based removal approach\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n if (fields.length === 0) {\r\n return pdfBytes;\r\n }\r\n \r\n // Remove all fields using robust widget cleanup\r\n for (const field of fields) {\r\n try {\r\n const acroField = (field as unknown as PDFFormFieldWithAcro).acroField;\r\n if (acroField && typeof acroField.getWidgets === 'function') {\r\n let widgets = acroField.getWidgets();\r\n \r\n // Remove widgets one by one with safety counter\r\n let safetyCounter = 0;\r\n const maxIterations = widgets.length + 5;\r\n \r\n while (widgets.length > 0 && safetyCounter < maxIterations) {\r\n try {\r\n const widgetIndex = widgets.length - 1;\r\n acroField.removeWidget(widgetIndex);\r\n widgets = acroField.getWidgets();\r\n } catch (widgetError) {\r\n break;\r\n }\r\n safetyCounter++;\r\n }\r\n \r\n if (safetyCounter >= maxIterations) {\r\n }\r\n }\r\n \r\n form.removeField(field as any);\r\n } catch (error) {\r\n \r\n try {\r\n form.removeField(field as any);\r\n } catch (fallbackError) {\r\n }\r\n }\r\n }\r\n \r\n const remainingFields = form.getFields();\r\n if (remainingFields.length > 0) {\r\n }\r\n }\r\n \r\n const updatedPdfBytes = await pdfDoc.save();\r\n return updatedPdfBytes;\r\n } catch (error) {\r\n logger.error('Error removing form fields from PDF:', error);\r\n return pdfBytes;\r\n }\r\n}\r\n\r\n/**\r\n * Read existing PDF form fields and their properties\r\n */\r\nexport async function readPdfFormFields(pdfBytes: Uint8Array): Promise<{\r\n name: string;\r\n type: string;\r\n required: boolean;\r\n value?: string;\r\n}[]> {\r\n try {\r\n // Validate PDF data first\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n return [];\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n if (fields.length === 0) {\r\n return [];\r\n }\r\n \r\n const formFields = fields.map(field => {\r\n const fieldName = field.getName();\r\n const pdfField = field as unknown as PDFFormField;\r\n \r\n try {\r\n // Use centralized field type detection and value extraction\r\n const fieldType = detectFieldType(pdfField);\r\n const value = extractFieldValue(pdfField, fieldType);\r\n const required = isRequiredField(pdfField, fieldName, fieldType);\r\n \r\n return {\r\n name: fieldName,\r\n type: fieldType,\r\n required,\r\n value\r\n };\r\n } catch (fieldError) {\r\n // Fallback to defaults on error\r\n return {\r\n name: fieldName,\r\n type: 'text',\r\n required: false,\r\n value: ''\r\n };\r\n }\r\n });\r\n \r\n return formFields;\r\n } catch (error) {\r\n logger.error('Error reading PDF form fields:', error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Read current PDF form field values (including user-filled data)\r\n */\r\nexport async function readCurrentPdfFormValues(pdfBytes: Uint8Array): Promise<Record<string, string>> {\r\n try {\r\n if (!pdfBytes || pdfBytes.length === 0) {\r\n return {};\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n const currentValues: Record<string, string> = {};\r\n \r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const pdfField = field as unknown as PDFFormField;\r\n \r\n try {\r\n // Use centralized field type detection and value extraction\r\n const fieldType = detectFieldType(pdfField);\r\n const value = extractFieldValue(pdfField, fieldType);\r\n \r\n currentValues[fieldName] = value;\r\n } catch (fieldError) {\r\n currentValues[fieldName] = '';\r\n }\r\n }\r\n \r\n return currentValues;\r\n } catch (error) {\r\n logger.error('Error reading current PDF form values:', error);\r\n return {};\r\n }\r\n}\r\n\r\n/**\r\n * Validate PDF form fields against provided values\r\n * In multi-signer mode, only validates fields visible to the current signer\r\n */\r\nexport async function validatePdfFormFields(\r\n pdfBytes: Uint8Array,\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>,\r\n extractedFields?: EsignFormField[], // Pass extracted fields to know which are visible\r\n multiSignerContext?: MultiSignerContext // Pass context to filter validation\r\n): Promise<string[]> {\r\n try {\r\n const pdfFormFields = await readPdfFormFields(pdfBytes);\r\n const errors: string[] = [];\r\n \r\n \r\n for (const field of pdfFormFields) {\r\n if (field.required) {\r\n // In multi-signer mode, only validate fields visible to current signer\r\n if (multiSignerContext?.isMultiSigner && extractedFields) {\r\n const extractedField = extractedFields.find(f => f.name === field.name);\r\n if (!extractedField) {\r\n // Field not in extractedFields means it's not visible to current signer\r\n continue;\r\n }\r\n }\r\n \r\n let hasValue = false;\r\n const fieldValue = fieldValues[field.name];\r\n const signatureValue = signatures[field.name];\r\n const mainSignature = signatures['signature_field_main'];\r\n const mainInitials = signatures['initials_field_main'] || fieldValues['initials_field_main'];\r\n \r\n if (field.name.includes('signature') || field.type === 'signature') {\r\n hasValue = !!(signatureValue || fieldValue || mainSignature);\r\n } else if (field.name.includes('initials')) {\r\n hasValue = !!(signatureValue || fieldValue || mainInitials);\r\n } else {\r\n hasValue = !!(fieldValue || field.value);\r\n }\r\n \r\n if (!hasValue) {\r\n let friendlyName = field.name.replace(/[_-]/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase());\r\n \r\n if (field.name.includes('signature')) {\r\n friendlyName = 'Signature';\r\n } else if (field.name.includes('initials')) {\r\n friendlyName = 'Initials';\r\n }\r\n \r\n errors.push(`${friendlyName} is required`);\r\n }\r\n }\r\n }\r\n \r\n return errors;\r\n } catch (error) {\r\n logger.error('Error validating PDF form fields:', error);\r\n return ['Unable to validate form fields. Please ensure all required fields are completed.'];\r\n }\r\n}\r\n\r\n/**\r\n * Validate PDF form fields against current form state\r\n */\r\nexport async function validateCurrentPdfState(\r\n pdfBytes: Uint8Array,\r\n signatures: Record<string, string>,\r\n formFieldValues: Record<string, string> = {}\r\n): Promise<string[]> {\r\n try {\r\n const pdfFormFields = await readPdfFormFields(pdfBytes);\r\n const currentValues = await readCurrentPdfFormValues(pdfBytes);\r\n const errors: string[] = [];\r\n \r\n for (const field of pdfFormFields) {\r\n const isSignatureField = field.name.includes('signature') && field.type === 'text';\r\n const isInitialsField = field.name.includes('initials') && field.type === 'text';\r\n \r\n if (field.required || isSignatureField || isInitialsField) {\r\n let hasValue = false;\r\n const currentValue = currentValues[field.name] || '';\r\n \r\n if (isSignatureField) {\r\n hasValue = !!signatures[field.name];\r\n } else if (isInitialsField) {\r\n hasValue = !!signatures[field.name] || !!(formFieldValues[field.name]?.trim()) || currentValue.trim() !== '';\r\n } else {\r\n hasValue = currentValue.trim() !== '';\r\n }\r\n \r\n if (!hasValue) {\r\n let friendlyName = field.name.replace(/[_-]/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase());\r\n \r\n if (field.name.includes('signature')) {\r\n friendlyName = 'Signature';\r\n } else if (field.name.includes('initials')) {\r\n friendlyName = 'Initials';\r\n }\r\n \r\n errors.push(`${friendlyName} is required`);\r\n }\r\n }\r\n }\r\n \r\n return errors;\r\n } catch (error) {\r\n logger.error('Error validating current PDF state:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Fill PDF with signature images and form field values, then flatten the form\r\n * @param pdfBytes - The PDF bytes\r\n * @param signatures - The signature data URLs (field name -> base64 PNG)\r\n * @param formFieldValues - The form field values to fill\r\n * @returns The filled and flattened PDF bytes\r\n */\r\nexport async function fillPdfWithSignatures(\r\n pdfBytes: Uint8Array,\r\n signatures: Record<string, string>,\r\n formFieldValues: Record<string, string> = {},\r\n currentSignerEmail?: string,\r\n extractedFormFields?: EsignFormField[],\r\n metadata?: { submissionId?: string; documentId?: string; author?: string; signerEmail?: string; signerInitials?: string; createdAt?: Date },\r\n auditTrail?: { userAgent?: string; screenResolution?: string; timezone?: string; language?: string; platform?: string; ipAddress?: string; geolocation?: { latitude: number; longitude: number; accuracy?: number } },\r\n multiSignerContext?: { isMultiSigner: boolean; currentSigner: any; currentSignerEmail: string; isPrimarySigner: boolean; isFinalSigner: boolean }\r\n): Promise<Uint8Array> {\r\n try {\r\n const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const pages = pdfDoc.getPages();\r\n \r\n // Get field positions and page numbers\r\n const { pageMap: fieldPageMap, positionMap: fieldPositionMap } = await getFieldPageNumbers(pdfBytes);\r\n \r\n // STEP 1: Fill all text form fields\r\n \r\n const fields = form.getFields();\r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const fieldValue = formFieldValues[fieldName];\r\n \r\n if (!fieldValue) {\r\n // Log missing values for radio fields to diagnose\r\n if (fieldName.includes('radio')) {\r\n }\r\n continue;\r\n }\r\n \r\n try {\r\n const fieldTypeName = field.constructor.name;\r\n \r\n // Handle text fields\r\n if (fieldTypeName === 'PDFTextField' || fieldTypeName === 'PDFTextField2') {\r\n const textField = field as any;\r\n textField.setText?.(fieldValue);\r\n }\r\n // Handle checkbox fields\r\n else if (fieldTypeName === 'PDFCheckBox' || fieldTypeName === 'PDFCheckBox2') {\r\n const checkBox = field as any;\r\n if (fieldValue === 'true' || fieldValue === 'Yes' || fieldValue === 'checked' || fieldValue === 'On') {\r\n checkBox.check?.();\r\n } else {\r\n checkBox.uncheck?.();\r\n }\r\n }\r\n // Handle radio group fields\r\n else if (fieldTypeName === 'PDFRadioGroup' || fieldTypeName === 'PDFRadioGroup2') {\r\n const radioGroup = field as any;\r\n \r\n // Skip invalid values (boolean strings from checkbox-like behavior)\r\n if (fieldValue === 'true' || fieldValue === 'false') {\r\n continue;\r\n }\r\n \r\n // Handle __RADIO_OPTION_INDEX_ pattern\r\n const idxMatch = fieldValue.match(/__RADIO_OPTION_INDEX_(\\d+)__/);\r\n if (idxMatch && idxMatch[1]) {\r\n const selectedIndex = parseInt(idxMatch[1], 10);\r\n const options = radioGroup.getOptions?.() || [];\r\n if (selectedIndex >= 0 && selectedIndex < options.length) {\r\n radioGroup.select?.(options[selectedIndex]);\r\n }\r\n } else {\r\n // Try to use the value directly if it's a valid option\r\n const options = radioGroup.getOptions?.() || [];\r\n if (options.includes(fieldValue)) {\r\n radioGroup.select?.(fieldValue);\r\n } else {\r\n }\r\n }\r\n }\r\n // Handle dropdown fields\r\n else if (fieldTypeName === 'PDFDropdown' || fieldTypeName === 'PDFDropdown2') {\r\n const dropdown = field as any;\r\n dropdown.select?.(fieldValue);\r\n }\r\n } catch (fieldError) {\r\n logger.error(`Error setting field \"${fieldName}\":`, fieldError);\r\n }\r\n }\r\n\r\n // Update form field appearances to ensure radio button selections render correctly\r\n // This is critical for radio buttons to display properly in PDF viewers\r\n // Fix based on dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n try {\r\n form.updateFieldAppearances();\r\n \r\n // CRITICAL: Set NeedAppearances to false to tell PDF viewers to use the appearance streams we generated\r\n // This is essential for Chrome's PDF viewer which strictly requires appearance dictionaries\r\n const PDFName = pdfLib.PDFName;\r\n const acroForm = pdfDoc.catalog.lookup(PDFName.of('AcroForm'));\r\n if (acroForm && typeof acroForm === 'object' && 'set' in acroForm) {\r\n (acroForm as any).set(PDFName.of('NeedAppearances'), false);\r\n }\r\n } catch (appearanceError) {\r\n // Some PDFs may not support this operation - fail gracefully\r\n logger.warn('Could not update field appearances:', appearanceError);\r\n }\r\n\r\n // STEP 2: Apply signature images to ALL signature fields\r\n const mainSignatureData = signatures['signature_field_main'];\r\n if (mainSignatureData && mainSignatureData.trim()) {\r\n \r\n // Find ALL signature field names (excluding text_ prefix and non-signature fields)\r\n // Match dockmaster patterns including '_es_:signer:signature' for esign integration\r\n const signatureFieldNames = [\r\n 'signature', 'Signature', 'SIGNATURE',\r\n 'sign', 'Sign', 'SIGN',\r\n '_es_:signer:signature'\r\n ];\r\n let foundSignatureFields = Object.keys(fieldPageMap).filter(fieldName => {\r\n const hasSignaturePattern = signatureFieldNames.some(pattern => \r\n fieldName.toLowerCase().includes(pattern.toLowerCase())\r\n );\r\n const isNotTextField = !fieldName.toLowerCase().startsWith('text_');\r\n return hasSignaturePattern && isNotTextField;\r\n });\r\n \r\n // CRITICAL: Filter to only ACTUAL signature fields, not checkbox/radio/dropdown\r\n if (extractedFormFields && extractedFormFields.length > 0) {\r\n const currentSignerSignatureFields = foundSignatureFields.filter(fieldName => {\r\n const fieldInfo = extractedFormFields.find(f => f.name === fieldName);\r\n if (!fieldInfo) {\r\n return false;\r\n }\r\n \r\n // CRITICAL FIX: Only process ACTUAL signature fields, NOT initials\r\n // Signature images should ONLY be applied to signature fields\r\n // Initials are handled separately as text (not images)\r\n // Fix based on dm-web-frontend commit 30895b5 (Oct 29, 2025)\r\n const isActualSignatureField = (fieldInfo.type === 'signature' ||\r\n fieldName.toLowerCase().includes('signature'))\r\n && !fieldName.toLowerCase().includes('initials'); // Explicitly exclude initials\r\n\r\n if (!isActualSignatureField) {\r\n return false;\r\n }\r\n \r\n // Use centralized visibility logic for multi-signer and single-signer modes\r\n const isVisible = multiSignerContext \r\n ? isFieldVisibleToSigner(fieldInfo, multiSignerContext)\r\n : true; // Single signer mode: all fields visible\r\n \r\n return isVisible;\r\n });\r\n foundSignatureFields = currentSignerSignatureFields;\r\n }\r\n \r\n \r\n if (foundSignatureFields.length > 0) {\r\n try {\r\n // Detect image format with binary signature detection\r\n let signatureImage;\r\n if (mainSignatureData.includes('data:image/png')) {\r\n signatureImage = await pdfDoc.embedPng(mainSignatureData);\r\n } else if (mainSignatureData.includes('data:image/jpeg') || mainSignatureData.includes('data:image/jpg')) {\r\n signatureImage = await pdfDoc.embedJpg(mainSignatureData);\r\n } else {\r\n // Fallback: detect by binary signature\r\n const base64Data = mainSignatureData.split(',')[1];\r\n if (!base64Data) {\r\n throw new Error('Invalid signature data format: missing base64 data');\r\n }\r\n const binaryData = atob(base64Data);\r\n \r\n // Check PNG signature (first 8 bytes: 89 50 4E 47 0D 0A 1A 0A)\r\n if (binaryData.charCodeAt(0) === 0x89 && \r\n binaryData.charCodeAt(1) === 0x50 && \r\n binaryData.charCodeAt(2) === 0x4E && \r\n binaryData.charCodeAt(3) === 0x47) {\r\n signatureImage = await pdfDoc.embedPng(mainSignatureData);\r\n } \r\n // Check JPEG signature (first 3 bytes: FF D8 FF)\r\n else if (binaryData.charCodeAt(0) === 0xFF && \r\n binaryData.charCodeAt(1) === 0xD8 && \r\n binaryData.charCodeAt(2) === 0xFF) {\r\n signatureImage = await pdfDoc.embedJpg(mainSignatureData);\r\n } \r\n else {\r\n throw new Error('Unsupported image format. Please use PNG or JPEG.');\r\n }\r\n }\r\n \r\n // Draw signature images using EXACT field coordinates\r\n for (const fieldName of foundSignatureFields) {\r\n \r\n const pageNumber = fieldPageMap[fieldName];\r\n \r\n if (pageNumber && pageNumber <= pages.length) {\r\n const page = pages[pageNumber - 1]; // Convert to 0-based index\r\n if (!page) continue;\r\n \r\n // Get EXACT field position from the map\r\n const fieldPosition = fieldPositionMap[fieldName];\r\n \r\n if (fieldPosition) {\r\n // Use EXACT field coordinates (NO CENTERING)\r\n const x = fieldPosition.x;\r\n const y = fieldPosition.y;\r\n const width = Math.max(fieldPosition.width, 80);\r\n const height = Math.max(fieldPosition.height, 30);\r\n \r\n // Scale signature to fit the field\r\n const signatureDims = signatureImage.scaleToFit(width - 4, height - 4);\r\n \r\n // FIXED POSITIONING: Use exact field coordinates\r\n const finalX = x;\r\n const finalY = y;\r\n \r\n \r\n page.drawImage(signatureImage, {\r\n x: finalX,\r\n y: finalY,\r\n width: signatureDims.width,\r\n height: signatureDims.height,\r\n });\r\n \r\n } else {\r\n }\r\n } else {\r\n }\r\n }\r\n } catch (error) {\r\n logger.error('Error applying signatures:', error);\r\n }\r\n }\r\n }\r\n \r\n // STEP 3: Apply initials to ALL initials fields\r\n console.log('[FLATTEN] === APPLYING INITIALS ===');\r\n console.log('[FLATTEN] formFieldValues keys:', Object.keys(formFieldValues));\r\n console.log('[FLATTEN] Initials fields in formFieldValues:', Object.keys(formFieldValues).filter(k => k.toLowerCase().includes('initials')));\r\n const mainInitialsData = formFieldValues['initials_field_main'];\r\n console.log('[FLATTEN] mainInitialsData from initials_field_main:', mainInitialsData ? mainInitialsData.substring(0, 50) : '(MISSING)');\r\n if (mainInitialsData && mainInitialsData.trim()) {\r\n \r\n console.log('[FLATTEN] fieldPageMap keys:', Object.keys(fieldPageMap));\r\n console.log('[FLATTEN] Looking for initials fields in fieldPageMap...');\r\n\r\n const initialsFieldNames = ['initials', 'Initials', 'INITIALS'];\r\n let foundInitialsFields = Object.keys(fieldPageMap).filter(fieldName =>\r\n initialsFieldNames.some(pattern => fieldName.toLowerCase().includes(pattern.toLowerCase()))\r\n );\r\n console.log('[FLATTEN] After pattern matching in fieldPageMap:', foundInitialsFields);\r\n\r\n // Filter by signer if needed\r\n if (extractedFormFields && extractedFormFields.length > 0) {\r\n foundInitialsFields = foundInitialsFields.filter(fieldName => {\r\n const fieldInfo = extractedFormFields.find(f => f.name === fieldName);\r\n if (!fieldInfo) return false;\r\n\r\n const isActualInitialsField = fieldInfo.type === 'initials' ||\r\n fieldName.toLowerCase().includes('initials');\r\n if (!isActualInitialsField) return false;\r\n\r\n // Use centralized visibility logic for multi-signer and single-signer modes\r\n const isVisible = multiSignerContext\r\n ? isFieldVisibleToSigner(fieldInfo, multiSignerContext)\r\n : true; // Single signer mode: all fields visible\r\n\r\n return isVisible;\r\n });\r\n }\r\n\r\n console.log('[FLATTEN] Found', foundInitialsFields.length, 'initials fields to flatten:', foundInitialsFields);\r\n if (foundInitialsFields.length > 0) {\r\n try {\r\n const font = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n\r\n for (const fieldName of foundInitialsFields) {\r\n console.log('[FLATTEN] Processing initials field:', fieldName);\r\n const pageNumber = fieldPageMap[fieldName];\r\n console.log('[FLATTEN] Page number:', pageNumber);\r\n if (pageNumber && pageNumber <= pages.length) {\r\n const page = pages[pageNumber - 1];\r\n if (!page) {\r\n console.log('[FLATTEN] ❌ Page not found');\r\n continue;\r\n }\r\n\r\n const fieldPosition = fieldPositionMap[fieldName];\r\n console.log('[FLATTEN] Field position:', fieldPosition);\r\n if (fieldPosition) {\r\n const x = fieldPosition.x;\r\n const y = fieldPosition.y;\r\n const height = Math.max(fieldPosition.height, 20);\r\n\r\n const fontSize = Math.min(height * 0.7, 14);\r\n\r\n // EXACT positioning (no centering)\r\n const finalX = x + 2;\r\n const finalY = y + (height - fontSize) / 2;\r\n\r\n console.log('[FLATTEN] ✅ Drawing initials at:', { x: finalX, y: finalY, fontSize, text: mainInitialsData });\r\n page.drawText(mainInitialsData, {\r\n x: finalX,\r\n y: finalY,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n\r\n } else {\r\n console.log('[FLATTEN] ❌ Field position not found in position map');\r\n }\r\n } else {\r\n console.log('[FLATTEN] ❌ Invalid page number or page out of bounds');\r\n }\r\n }\r\n } catch (error) {\r\n logger.error('Error applying initials:', error);\r\n }\r\n }\r\n }\r\n \r\n // STEP 4: Flatten form fields based on multi-signer mode\r\n \r\n const allFormFields = form.getFields();\r\n \r\n let fieldsToFlatten;\r\n \r\n if (multiSignerContext?.isMultiSigner) {\r\n // PARTIAL FLATTENING: Only flatten current signer's fields (Dockmaster logic lines 2500-2526)\r\n \r\n fieldsToFlatten = allFormFields.filter(f => {\r\n const fieldName = f.getName();\r\n \r\n if (!extractedFormFields || extractedFormFields.length === 0) {\r\n return true; // Flatten all if no field info\r\n }\r\n \r\n const fieldInfo = extractedFormFields.find(fi => fi.name === fieldName);\r\n if (!fieldInfo) {\r\n return true; // Flatten unknown fields\r\n }\r\n \r\n // Use centralized flattening logic\r\n return shouldFlattenField(fieldInfo, multiSignerContext);\r\n });\r\n } else {\r\n // COMPLETE FLATTENING: Flatten all fields (single signer mode)\r\n fieldsToFlatten = allFormFields;\r\n }\r\n \r\n // Helper interfaces for widget access\r\n interface PDFFieldWithAcro {\r\n acroField?: {\r\n getWidgets?: () => PDFWidget[];\r\n dict?: any;\r\n };\r\n }\r\n \r\n let flattenedCount = 0;\r\n \r\n for (const field of fieldsToFlatten) {\r\n const fieldName = field.getName();\r\n const fieldType = field.constructor.name;\r\n \r\n try {\r\n // Get user entered value\r\n const userEnteredValue = formFieldValues[fieldName];\r\n \r\n // Check if this is a signature/initials field\r\n const isSignatureField = fieldName.toLowerCase().includes('signature') || fieldType.includes('Signature');\r\n const isInitialsField = fieldName.toLowerCase().includes('initials') || fieldType.includes('Initials');\r\n \r\n if (isSignatureField || isInitialsField) {\r\n // Signature/initials fields were already drawn in STEP 2/3, just remove the field\r\n form.removeField(field);\r\n flattenedCount++;\r\n continue;\r\n }\r\n \r\n // Get field widgets for drawing\r\n const fieldWithWidgets = field as unknown as PDFFieldWithAcro;\r\n const widgets = fieldWithWidgets.acroField?.getWidgets?.() || [];\r\n \r\n // Handle different field types - draw their content\r\n if (fieldType === 'PDFCheckBox' || fieldType === 'PDFCheckBox2') {\r\n // Checkbox field - draw checkbox with checkmark if checked\r\n const stringValue = String(userEnteredValue || '');\r\n const isChecked = stringValue === 'true' || stringValue === 'Yes' || \r\n stringValue === 'On' || stringValue === 'checked';\r\n \r\n \r\n if (isChecked) {\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw checkbox border\r\n const checkboxSize = Math.min(rect.width, rect.height) * 0.6;\r\n const checkboxX = rect.x + (rect.width - checkboxSize) / 2;\r\n const checkboxY = rect.y + (rect.height - checkboxSize) / 2;\r\n \r\n page.drawRectangle({\r\n x: checkboxX,\r\n y: checkboxY,\r\n width: checkboxSize,\r\n height: checkboxSize,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n });\r\n \r\n // Draw checkmark using \"X\"\r\n const checkSize = checkboxSize * 0.6;\r\n const textWidth = checkSize * 0.6;\r\n const textHeight = checkSize * 0.8;\r\n \r\n page.drawText('X', {\r\n x: checkboxX + (checkboxSize - textWidth) / 2,\r\n y: checkboxY + (checkboxSize - textHeight) / 2 + textHeight * 0.2,\r\n size: checkSize,\r\n font: await pdfDoc.embedFont(StandardFonts.HelveticaBold),\r\n color: rgb(0, 0, 0),\r\n });\r\n \r\n }\r\n }\r\n } else if (fieldType === 'PDFRadioGroup' || fieldType === 'PDFRadioGroup2') {\r\n // Radio group field - draw all radio buttons, fill the selected one\r\n const radioGroup = field as any;\r\n \r\n // Get field info for labels and options (need this before determining selectedIndex)\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n \r\n // Get the ACTUAL selected value from the PDF field (after it was set)\r\n let actualSelectedValue = '';\r\n try {\r\n actualSelectedValue = radioGroup.getSelected?.() || '';\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: radioGroup.getSelected() returned: \"${actualSelectedValue}\"`);\r\n } catch (e) {\r\n // Fallback to user entered value if we can't read the field\r\n actualSelectedValue = userEnteredValue ? String(userEnteredValue) : '';\r\n logger.warn(`[FLATTEN RADIO] Field ${fieldName}: could not read selected value, using userEnteredValue: \"${actualSelectedValue}\"`);\r\n }\r\n \r\n // Determine selected index\r\n let selectedIndex = -1;\r\n \r\n // Get all options from the radio group\r\n const radioOptions = radioGroup.getOptions?.() || [];\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: radioGroup.getOptions() returned ${radioOptions.length} options:`, radioOptions);\r\n \r\n // If we have an actual selected value from the field, find its index\r\n if (actualSelectedValue && radioOptions.length > 0) {\r\n selectedIndex = radioOptions.findIndex((opt: string) => opt === actualSelectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: found actualSelectedValue \"${actualSelectedValue}\" at index ${selectedIndex}`);\r\n }\r\n \r\n // Fallback: try to parse from user entered value if we didn't find it above\r\n if (selectedIndex === -1 && userEnteredValue) {\r\n const selectedValue = String(userEnteredValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: selectedIndex still -1, trying to parse from userEnteredValue: \"${selectedValue}\"`);\r\n \r\n // Handle __RADIO_OPTION_INDEX_ pattern directly\r\n if (selectedValue.startsWith('__RADIO_OPTION_INDEX_')) {\r\n const indexMatch = selectedValue.match(/__RADIO_OPTION_INDEX_(\\d+)__/);\r\n if (indexMatch && indexMatch[1]) {\r\n selectedIndex = parseInt(indexMatch[1], 10);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: extracted index ${selectedIndex} from __RADIO_OPTION_INDEX_ pattern`);\r\n }\r\n } \r\n // Handle numeric string (just an index)\r\n else if (/^\\d+$/.test(selectedValue)) {\r\n selectedIndex = parseInt(selectedValue, 10);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: parsed numeric index ${selectedIndex}`);\r\n }\r\n // Match against actual option values from field info\r\n else if (fieldInfo?.options && selectedValue) {\r\n selectedIndex = fieldInfo.options.findIndex(option => option === selectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: matched \"${selectedValue}\" in fieldInfo.options at index ${selectedIndex}`);\r\n }\r\n // Match against radio group options\r\n else if (radioOptions.length > 0) {\r\n selectedIndex = radioOptions.findIndex((opt: string) => opt === selectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: matched \"${selectedValue}\" in radioOptions at index ${selectedIndex}`);\r\n }\r\n }\r\n \r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: FINAL selectedIndex = ${selectedIndex}, will draw filled circle at this index`);\r\n const labelFont = await pdfDoc.embedFont('Helvetica-Bold');\r\n const drawnGroupLabels = new Set<string>();\r\n const drawnOptionLabels = new Set<string>();\r\n \r\n // Draw borders for ALL radio buttons\r\n for (let i = 0; i < widgets.length; i++) {\r\n const widget = widgets[i];\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page, pageIndex } = result;\r\n \r\n // Draw radio GROUP label (once, above first widget)\r\n // Only draw if it's a user-typed custom label (not auto-generated)\r\n if (i === 0 && fieldInfo?.label && fieldInfo.label.trim() && !isAutoGeneratedLabel(fieldInfo.label)) {\r\n const groupLabelKey = `${pageIndex}-${fieldName}-grouplabel`;\r\n if (!drawnGroupLabels.has(groupLabelKey)) {\r\n const labelY = rect.y + rect.height + 3;\r\n page.drawText(fieldInfo.label, {\r\n x: rect.x,\r\n y: labelY,\r\n size: 8,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnGroupLabels.add(groupLabelKey);\r\n }\r\n } else if (i === 0 && isAutoGeneratedLabel(fieldInfo?.label || '')) {\r\n }\r\n \r\n // Draw radio button border (circle)\r\n const radioSize = Math.min(rect.width, rect.height) * 0.5;\r\n const radioX = rect.x + (rect.width - radioSize) / 2;\r\n const radioY = rect.y + (rect.height - radioSize) / 2;\r\n \r\n page.drawCircle({\r\n x: radioX + radioSize / 2,\r\n y: radioY + radioSize / 2,\r\n size: radioSize,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n });\r\n \r\n // Draw filled circle ONLY for selected option\r\n if (i === selectedIndex) {\r\n const circleSize = radioSize * 0.5;\r\n page.drawCircle({\r\n x: radioX + radioSize / 2,\r\n y: radioY + radioSize / 2,\r\n size: circleSize,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw option text next to each radio button\r\n if (fieldInfo?.options && fieldInfo.options.length > i) {\r\n const optionText = fieldInfo.options[i];\r\n const optionKey = `${pageIndex}-${fieldName}-opt-${i}`;\r\n \r\n if (optionText && !drawnOptionLabels.has(optionKey)) {\r\n page.drawText(optionText, {\r\n x: rect.x + rect.width + 4,\r\n y: rect.y + (rect.height - 8) / 2,\r\n size: 8,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOptionLabels.add(optionKey);\r\n }\r\n }\r\n }\r\n \r\n if (fieldInfo?.options) {\r\n }\r\n } else if (fieldType === 'PDFDropdown' || fieldType === 'PDFDropdown2') {\r\n // Dropdown field - draw the selected value\r\n const selectedValue = userEnteredValue ? String(userEnteredValue) : '';\r\n \r\n \r\n if (selectedValue && selectedValue.trim()) {\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw the selected value\r\n page.drawText(selectedValue, {\r\n x: rect.x + 2,\r\n y: rect.y + 2,\r\n size: 10,\r\n font: await pdfDoc.embedFont(StandardFonts.Helvetica),\r\n color: rgb(0, 0, 0),\r\n });\r\n \r\n }\r\n }\r\n } else {\r\n // Text field or other field types - draw the field value\r\n const fieldValue = userEnteredValue ? String(userEnteredValue) : '';\r\n \r\n \r\n if (fieldValue && fieldValue.trim()) {\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw the field value\r\n page.drawText(fieldValue, {\r\n x: rect.x + 2,\r\n y: rect.y + 2,\r\n size: 10,\r\n font: await pdfDoc.embedFont(StandardFonts.Helvetica),\r\n color: rgb(0, 0, 0),\r\n });\r\n \r\n }\r\n }\r\n }\r\n \r\n // Remove the field to flatten it\r\n form.removeField(field);\r\n flattenedCount++;\r\n } catch (error) {\r\n }\r\n }\r\n \r\n const remainingFields = form.getFields();\r\n \r\n // Verify flattening worked\r\n if (multiSignerContext?.isMultiSigner) {\r\n // MULTI-SIGNER MODE: Remaining fields are EXPECTED (for other signers)\r\n const expectedRemainingCount = allFormFields.length - fieldsToFlatten.length;\r\n if (remainingFields.length === expectedRemainingCount) {\r\n } else {\r\n }\r\n } else {\r\n // SINGLE-SIGNER MODE: All fields should be flattened\r\n if (remainingFields.length > 0) {\r\n logger.error(`MANUAL FLATTENING INCOMPLETE: ${remainingFields.length} fields still exist!`);\r\n logger.error(`Remaining fields:`, remainingFields.map(f => f.getName()));\r\n \r\n // Try basic flattening as final fallback (only in single-signer mode)\r\n try {\r\n form.flatten();\r\n const finalRemainingFields = form.getFields();\r\n \r\n if (finalRemainingFields.length > 0) {\r\n logger.error(`ALL FLATTENING METHODS FAILED: ${finalRemainingFields.length} fields still exist!`);\r\n logger.error(`Final remaining fields:`, finalRemainingFields.map(f => f.getName()));\r\n }\r\n } catch (fallbackError) {\r\n logger.error('Fallback flattening failed:', fallbackError);\r\n }\r\n } else {\r\n }\r\n }\r\n \r\n // STEP 6: Set document metadata for tracking and compliance\r\n try {\r\n // Set document metadata based on submission data\r\n // Set Title (with default if not provided)\r\n const documentTitle = metadata?.documentId \r\n ? `Document ID: ${metadata.documentId}`\r\n : 'Signed Document';\r\n pdfDoc.setTitle(documentTitle);\r\n \r\n // Set Subject (with default if not provided)\r\n const documentSubject = metadata?.submissionId\r\n ? `Submission ID: ${metadata.submissionId}`\r\n : metadata?.signerEmail\r\n ? `Signed by ${metadata.signerEmail}`\r\n : 'Digitally Signed Document';\r\n pdfDoc.setSubject(documentSubject);\r\n \r\n // Set Author (with default if not provided)\r\n const documentAuthor = metadata?.author || metadata?.signerEmail || 'Unknown';\r\n pdfDoc.setAuthor(documentAuthor);\r\n \r\n pdfDoc.setProducer('Created by signiphi (https://signiphi.ai/)');\r\n \r\n if (metadata?.signerEmail) {\r\n pdfDoc.setCreator(`Signer: ${metadata.signerEmail}`);\r\n }\r\n \r\n // Set creation date from submission\r\n if (metadata?.createdAt) {\r\n pdfDoc.setCreationDate(metadata.createdAt);\r\n }\r\n \r\n // Set current date as modification date\r\n pdfDoc.setModificationDate(new Date());\r\n \r\n // Set keywords for searchability and tracking\r\n const keywords: string[] = [];\r\n \r\n // Add signer email if available\r\n if (metadata?.signerEmail) {\r\n keywords.push(metadata.signerEmail);\r\n }\r\n \r\n // Add initials to metadata if available\r\n if (metadata?.signerInitials && metadata.signerInitials.trim()) {\r\n keywords.push(`Initials:${metadata.signerInitials.trim()}`);\r\n }\r\n \r\n // Add audit trail data for compliance and forensics\r\n if (auditTrail) {\r\n try {\r\n // Device/Browser information\r\n if (auditTrail.userAgent) {\r\n keywords.push(`UserAgent:${auditTrail.userAgent}`);\r\n }\r\n \r\n // Screen resolution as device identifier\r\n if (auditTrail.screenResolution) {\r\n keywords.push(`Screen:${auditTrail.screenResolution}`);\r\n }\r\n \r\n // Timezone\r\n if (auditTrail.timezone) {\r\n keywords.push(`Timezone:${auditTrail.timezone}`);\r\n }\r\n \r\n // Language settings\r\n if (auditTrail.language) {\r\n keywords.push(`Language:${auditTrail.language}`);\r\n }\r\n \r\n // Platform information\r\n if (auditTrail.platform) {\r\n keywords.push(`Platform:${auditTrail.platform}`);\r\n }\r\n \r\n // IP address\r\n if (auditTrail.ipAddress) {\r\n keywords.push(`IP:${auditTrail.ipAddress}`);\r\n }\r\n \r\n // Geolocation data\r\n if (auditTrail.geolocation) {\r\n const { latitude, longitude, accuracy } = auditTrail.geolocation;\r\n const lat = latitude.toFixed(4);\r\n const lon = longitude.toFixed(4);\r\n keywords.push(`Location:${lat},${lon}`);\r\n \r\n // Add accuracy if available\r\n if (accuracy !== undefined) {\r\n keywords.push(`LocationAccuracy:${accuracy}m`);\r\n }\r\n }\r\n } catch (auditError) {\r\n logger.warn('⚠️ Error adding audit trail to keywords:', auditError)\r\n }\r\n }\r\n \r\n if (keywords.length > 0) {\r\n pdfDoc.setKeywords(keywords);\r\n }\r\n } catch (error) {\r\n logger.error('Failed to set document metadata:', error);\r\n }\r\n \r\n const finalPdfBytes = await pdfDoc.save();\r\n return finalPdfBytes;\r\n } catch (error) {\r\n logger.error('Error filling PDF with signatures:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Fill form fields and replace signature/initials with actual signature images\r\n * This is used when fields are rendered as overlays on the PDF\r\n * @param pdfBytes - The PDF bytes\r\n * @param formFields - The form fields with their positions\r\n * @param fieldValues - The field values to fill\r\n * @param signatures - The signature images (base64 data URLs)\r\n * @returns The filled PDF bytes\r\n */\r\nexport async function fillFormFieldsWithSignatures(\r\n pdfBytes: Uint8Array,\r\n formFields: EsignFormField[],\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>\r\n): Promise<Uint8Array> {\r\n try {\r\n const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const pages = pdfDoc.getPages();\r\n const font = await pdfDoc.embedFont(StandardFonts.Helvetica);\r\n\r\n for (const field of formFields) {\r\n const pageIndex = field.position.page - 1;\r\n \r\n if (pageIndex < 0 || pageIndex >= pages.length) {\r\n continue;\r\n }\r\n\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const { height: pageHeight } = page.getSize();\r\n\r\n // Convert coordinates from top-left (UI) to bottom-left (PDF)\r\n const pdfX = field.position.x;\r\n const pdfY = pageHeight - field.position.y - field.position.height;\r\n\r\n try {\r\n switch (field.type) {\r\n case FormFieldType.TEXT: {\r\n const value = fieldValues[field.id] || '';\r\n if (value) {\r\n // Use field fontSize if specified, otherwise calculate based on field height\r\n const fontSize = field.fontSize && field.fontSize >= 8 && field.fontSize <= 72 \r\n ? field.fontSize \r\n : Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2, // Small padding\r\n y: pdfY + (field.position.height - fontSize) / 2, // Center vertically\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4, // Leave padding\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.DATE: {\r\n const value = fieldValues[field.id] || '';\r\n if (value) {\r\n const fontSize = field.fontSize && field.fontSize >= 8 && field.fontSize <= 72 \r\n ? field.fontSize \r\n : Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.CHECKBOX: {\r\n const value = fieldValues[field.id] || '';\r\n if (value === 'true') {\r\n // Draw a checkmark\r\n const checkSize = Math.min(field.position.width, field.position.height) * 0.6;\r\n const checkX = pdfX + (field.position.width - checkSize) / 2;\r\n const checkY = pdfY + (field.position.height - checkSize) / 2;\r\n \r\n page.drawText('✓', {\r\n x: checkX,\r\n y: checkY,\r\n size: checkSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.SIGNATURE: {\r\n const signatureDataUrl = signatures[field.id];\r\n if (signatureDataUrl) {\r\n // Convert base64 data URL to image bytes\r\n const base64Data = signatureDataUrl.split(',')[1];\r\n if (!base64Data) {\r\n logger.error('Invalid signature data URL format for field:', field.id);\r\n break;\r\n }\r\n const imageBytes = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));\r\n \r\n // Embed the image\r\n const image = await pdfDoc.embedPng(imageBytes);\r\n \r\n // Calculate dimensions to fit within the field while maintaining aspect ratio\r\n const imageSize = image.size();\r\n const fieldAspectRatio = field.position.width / field.position.height;\r\n const imageAspectRatio = imageSize.width / imageSize.height;\r\n \r\n let drawWidth = field.position.width;\r\n let drawHeight = field.position.height;\r\n \r\n if (imageAspectRatio > fieldAspectRatio) {\r\n // Image is wider than field - fit to width\r\n drawHeight = drawWidth / imageAspectRatio;\r\n } else {\r\n // Image is taller than field - fit to height\r\n drawWidth = drawHeight * imageAspectRatio;\r\n }\r\n \r\n // Center the image within the field\r\n const imageX = pdfX + (field.position.width - drawWidth) / 2;\r\n const imageY = pdfY + (field.position.height - drawHeight) / 2;\r\n \r\n // Draw the image\r\n page.drawImage(image, {\r\n x: imageX,\r\n y: imageY,\r\n width: drawWidth,\r\n height: drawHeight,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.INITIALS: {\r\n const value = fieldValues[field.id] || '';\r\n if (value) {\r\n // Use a cursive font for initials\r\n const fontSize = Math.min(18, field.position.height * 0.8);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.DROPDOWN: {\r\n const value = fieldValues[field.id] || '';\r\n if (value) {\r\n const fontSize = Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n default:\r\n break;\r\n }\r\n } catch (fieldError) {\r\n logger.error(`Error processing field ${field.name}:`, fieldError);\r\n }\r\n }\r\n\r\n return await pdfDoc.save();\r\n} catch (error) {\r\n logger.error('Error filling form fields:', error);\r\n throw error;\r\n}\r\n}\r\n\r\n/**\r\n * Extract field positions and page numbers from a PDF document\r\n * Returns maps for field name -> page number and field name -> position\r\n */\r\nexport async function getFieldPageNumbers(\r\n pdfBytes: Uint8Array\r\n): Promise<{\r\n pageMap: Record<string, number>;\r\n positionMap: Record<string, FormFieldPosition>;\r\n}> {\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n const pages = pdfDoc.getPages();\r\n\r\n const pageMap: Record<string, number> = {};\r\n const positionMap: Record<string, FormFieldPosition> = {};\r\n\r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const fieldWithAcro = field as unknown as PDFFieldWithAcro;\r\n const widgets = fieldWithAcro.acroField?.getWidgets?.() ?? [];\r\n\r\n if (widgets.length > 0) {\r\n // Use the first widget to determine page and position\r\n const widget = widgets[0];\r\n if (!widget) continue;\r\n const rect = widget.getRectangle?.();\r\n const pageRef = widget.P?.();\r\n\r\n if (rect && pageRef) {\r\n // Find which page this widget belongs to\r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n\r\n if (pageIndex !== -1) {\r\n const pageNumber = pageIndex + 1; // Convert to 1-indexed\r\n pageMap[fieldName] = pageNumber;\r\n\r\n // Store position information\r\n positionMap[fieldName] = {\r\n x: rect.x,\r\n y: rect.y,\r\n width: rect.width,\r\n height: rect.height,\r\n page: pageNumber,\r\n };\r\n }\r\n }\r\n }\r\n }\r\n\r\n return { pageMap, positionMap };\r\n} catch (error) {\r\n logger.error('Error extracting field page numbers:', error);\r\n return { pageMap: {}, positionMap: {} };\r\n}\r\n}\r\n\r\n","/**\r\n * PDF Form Field Extraction Utilities\r\n * Functions for extracting and decoding form fields from PDFs\r\n */\r\n\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport { EsignFormField, FormFieldType } from '../types';\r\nimport { logger } from './logger';\r\nimport type { PDFName as PDFNameType } from 'pdf-lib';\r\nimport { getSigniphiMetadata, initPdfMetadata, type FieldMetadata } from './pdf-metadata';\r\n\r\n// Module-level variable to hold PDFName after pdf-lib is loaded\r\nlet PDFName: typeof PDFNameType;\r\n\r\n// Type definitions for PDF field extensions\r\ninterface PDFFieldWithExtensions {\r\n acroField?: {\r\n getWidgets?: () => Array<{\r\n hasFlag?: (flag: number) => boolean;\r\n }>;\r\n dict?: {\r\n get: (key: unknown) => unknown;\r\n };\r\n };\r\n getOptions?: () => string[];\r\n isRequired?: () => boolean;\r\n constructor: { name: string };\r\n getName(): string;\r\n}\r\n\r\n/**\r\n * Extract visible form fields from a PDF document\r\n * @param pdfBytes - The PDF bytes to extract fields from\r\n * @param currentSignerEmail - Optional email of the current signer (for multi-signer filtering)\r\n * @returns Array of extracted form fields\r\n */\r\nexport async function extractVisibleFormFields(\r\n pdfBytes: Uint8Array,\r\n currentSignerEmail?: string\r\n): Promise<EsignFormField[]> {\r\n try {\r\n const pdfLibModule = await loadPdfLib();\r\n const { PDFDocument, AnnotationFlags, PDFName: PDFNameClass } = pdfLibModule;\r\n PDFName = PDFNameClass; // Assign to module-level variable for use in helper functions\r\n \r\n // Initialize pdf-metadata module with PDFName and PDFString\r\n initPdfMetadata(pdfLibModule);\r\n \r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Load metadata from PDF document information dictionary\r\n const metadata = getSigniphiMetadata(pdfDoc);\r\n \r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n const visibleFields: EsignFormField[] = [];\r\n let hasAnyInitialsFields = false; // For single-signer mode\r\n let hasInitialsFieldsForCurrentSigner = false; // For multi-signer mode\r\n \r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n \r\n // Get widgets for this field to check visibility\r\n const fieldWithExtensions = field as unknown as PDFFieldWithExtensions;\r\n const widgets = fieldWithExtensions.acroField?.getWidgets?.() ?? [];\r\n \r\n let isVisible = true;\r\n \r\n // Check if any widget is hidden using AnnotationFlags\r\n for (const widget of widgets) {\r\n const hasHiddenFlag = widget.hasFlag?.(AnnotationFlags.Hidden) ?? false;\r\n const hasNoViewFlag = widget.hasFlag?.(AnnotationFlags.NoView) ?? false;\r\n \r\n if (hasHiddenFlag || hasNoViewFlag) {\r\n isVisible = false;\r\n break;\r\n }\r\n }\r\n \r\n if (isVisible) {\r\n // Extract the clean field name (without suffixes) for metadata lookup\r\n const cleanFieldNameForMetadata = fieldName.replace(/_signature$|_initials$|_date$/i, '');\r\n\r\n // Get field metadata from PDF metadata or fall back to parsing field name (for old PDFs)\r\n // CRITICAL: Try both the suffixed name and the clean name for metadata lookup\r\n const fieldMetadata: FieldMetadata = metadata?.fields[fieldName]\r\n || metadata?.fields[cleanFieldNameForMetadata]\r\n || (() => {\r\n // Backward compatibility: decode from field name if no metadata exists\r\n const decoded = decodeFieldName(fieldName);\r\n return {\r\n label: decoded.displayLabel,\r\n signer: decoded.assignedSignerEmail,\r\n placeholder: decoded.fieldPlaceholder,\r\n acknowledgements: decoded.acknowledgements\r\n };\r\n })();\r\n \r\n // NOTE: We do NOT filter by signer during extraction in multi-signer mode!\r\n // All fields must be extracted so that:\r\n // 1. useFieldFiltering can properly filter fields for display\r\n // 2. Partial flattening knows about all fields (flatten current signer's fields only)\r\n // 3. PDF viewer filtering can remove non-visible fields from the rendered PDF\r\n // The filtering happens at the display level via useFieldFiltering hook.\r\n \r\n // Determine field type based on pdf-lib field type\r\n let fieldType = FormFieldType.TEXT;\r\n const fieldTypeName = field.constructor.name;\r\n \r\n // Extract the clean field name (without suffixes for type detection)\r\n const cleanFieldName = fieldName.replace(/_signature$|_initials$|_date$/i, '');\r\n \r\n // CRITICAL: Properly detect signature/initials fields (not checkboxes/radios)\r\n // More defensive than dockmaster - explicitly exclude CheckBox/Radio to prevent false positives\r\n const isActualSignatureField = fieldTypeName.includes('Signature') || \r\n (cleanFieldName.toLowerCase().includes('signature') && \r\n !fieldTypeName.includes('CheckBox') && \r\n !fieldTypeName.includes('Radio'));\r\n const isActualInitialsField = cleanFieldName.toLowerCase().includes('initials') &&\r\n !fieldTypeName.includes('CheckBox') && \r\n !fieldTypeName.includes('Radio');\r\n \r\n if (isActualSignatureField) {\r\n fieldType = FormFieldType.SIGNATURE;\r\n } else if (isActualInitialsField) {\r\n fieldType = FormFieldType.INITIALS;\r\n \r\n // Track initials fields for proper sidebar display logic:\r\n // - hasAnyInitialsFields: ANY initials exist (for single-signer fallback)\r\n // - hasInitialsFieldsForCurrentSigner: initials assigned to this signer (for multi-signer)\r\n hasAnyInitialsFields = true;\r\n \r\n // Check if this initials field is assigned to current signer\r\n if (currentSignerEmail && fieldMetadata.signer === currentSignerEmail) {\r\n hasInitialsFieldsForCurrentSigner = true;\r\n }\r\n } else if (cleanFieldName.toLowerCase().includes('date')) {\r\n fieldType = FormFieldType.DATE;\r\n } else if (fieldTypeName.includes('CheckBox')) {\r\n fieldType = FormFieldType.CHECKBOX;\r\n } else if (fieldTypeName.toLowerCase().includes('dropdown')) {\r\n fieldType = FormFieldType.DROPDOWN;\r\n } else if (fieldTypeName.includes('Radio')) {\r\n fieldType = FormFieldType.RADIO;\r\n }\r\n \r\n // Generate display label - Try TU metadata first, then metadata label, then fallback\r\n let displayLabel = fieldMetadata.label || '';\r\n \r\n // PRIORITY 1: Try to get label from TU (tooltip/user-visible) metadata\r\n if (!displayLabel || !displayLabel.trim()) {\r\n try {\r\n const tuLabel = extractTULabel(fieldWithExtensions);\r\n if (tuLabel && tuLabel.trim()) {\r\n displayLabel = tuLabel;\r\n }\r\n } catch (tuError) {\r\n }\r\n }\r\n \r\n // PRIORITY 2: Use label from metadata (already set above from fieldMetadata.label)\r\n \r\n // PRIORITY 3: Generate fallback label from field name\r\n if (!displayLabel || !displayLabel.trim()) {\r\n displayLabel = generateFallbackLabel(cleanFieldName, fieldType);\r\n }\r\n \r\n // Create EsignFormField\r\n const esignField: EsignFormField = {\r\n id: fieldName, // Keep original encoded name as ID\r\n fieldId: fieldMetadata.fieldId || fieldName, // Use fieldId from metadata, fallback to fieldName for backward compatibility\r\n name: fieldName, // Keep original for removal later\r\n type: fieldType,\r\n label: displayLabel, // Use friendly label for display\r\n position: { x: 0, y: 0, width: 100, height: 30, page: 1 }, // Default position\r\n required: fieldWithExtensions.isRequired?.() ?? false,\r\n placeholder: fieldMetadata.placeholder || '', // Use metadata placeholder\r\n assignedSignerEmail: fieldMetadata.signer, // Add assigned signer from metadata\r\n acknowledgements: fieldMetadata.acknowledgements, // Add acknowledgements from metadata\r\n };\r\n \r\n // Add options for dropdown and radio fields\r\n if (fieldType === FormFieldType.DROPDOWN || fieldType === FormFieldType.RADIO) {\r\n try {\r\n const options = fieldWithExtensions.getOptions?.() ?? [];\r\n esignField.options = options;\r\n if (options.length > 0) {\r\n }\r\n } catch (error) {\r\n logger.warn('Error extracting options for field:', error);\r\n }\r\n }\r\n \r\n visibleFields.push(esignField);\r\n }\r\n }\r\n \r\n // Add main signature and initials fields at the BEGINNING\r\n // Only create if PDF has these fields OR if explicitly required\r\n const mainFields: EsignFormField[] = [];\r\n \r\n // ALWAYS create signature field - it's attached to the document on submission regardless\r\n mainFields.push({\r\n id: 'signature_field_main',\r\n fieldId: 'signature_field_main', // Fixed ID for main signature field\r\n name: 'signature_field_main',\r\n type: FormFieldType.SIGNATURE,\r\n label: 'Your Signature (will be applied to all signature fields)',\r\n position: { x: 0, y: 0, width: 200, height: 60, page: 1 },\r\n required: true,\r\n placeholder: 'Draw or upload your signature',\r\n assignedSignerEmail: currentSignerEmail,\r\n });\r\n \r\n // Create initials field based on mode:\r\n // - Multi-signer mode (currentSignerEmail provided AND matches assigned fields):\r\n // Only create if current signer has initials fields assigned to them\r\n // - Single-signer mode (currentSignerEmail not provided OR doesn't match any assignments):\r\n // Create if ANY initials fields exist in the PDF\r\n // When present, always make it required\r\n const shouldCreateInitialsField = hasInitialsFieldsForCurrentSigner || \r\n (hasAnyInitialsFields && !currentSignerEmail);\r\n \r\n if (shouldCreateInitialsField) {\r\n if (hasInitialsFieldsForCurrentSigner) {\r\n } else {\r\n }\r\n \r\n mainFields.push({\r\n id: 'initials_field_main',\r\n fieldId: 'initials_field_main', // Fixed ID for main initials field\r\n name: 'initials_field_main',\r\n type: FormFieldType.INITIALS,\r\n label: 'Your Initials (will be applied to all initials fields)',\r\n position: { x: 0, y: 0, width: 100, height: 40, page: 1 },\r\n required: true,\r\n placeholder: 'Enter your initials',\r\n assignedSignerEmail: currentSignerEmail,\r\n });\r\n }\r\n \r\n // Return main fields FIRST, then other fields\r\n return [...mainFields, ...visibleFields];\r\n } catch (error) {\r\n logger.error('Error extracting visible form fields from PDF:', error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Decode a field name to extract label, signer email, and placeholder\r\n * Format: fieldName__LABEL__labelText__SIGNER__email__PLACEHOLDER__placeholderText\r\n * \r\n * @deprecated This function is deprecated and kept only for backward compatibility with old PDFs.\r\n * New PDFs store metadata in the PDF's document information dictionary instead of encoding it in field names.\r\n * Use getSigniphiMetadata() for new PDFs.\r\n */\r\nexport function decodeFieldName(fieldName: string): {\r\n decodedFieldName: string;\r\n displayLabel: string;\r\n assignedSignerEmail?: string;\r\n fieldPlaceholder: string;\r\n acknowledgements?: Array<{id: string; title: string; description: string}>;\r\n} {\r\n let decodedFieldName = fieldName;\r\n let displayLabel = '';\r\n let assignedSignerEmail: string | undefined = undefined;\r\n let fieldPlaceholder = '';\r\n let acknowledgements: Array<{id: string; title: string; description: string}> | undefined = undefined;\r\n \r\n // Extract acknowledgements if present (must be last)\r\n if (fieldName.includes('__ACK__')) {\r\n const ackMarkerIndex = fieldName.indexOf('__ACK__');\r\n const beforeAck = fieldName.substring(0, ackMarkerIndex);\r\n const ackEncoded = fieldName.substring(ackMarkerIndex + 7); // Skip \"__ACK__\"\r\n \r\n try {\r\n // Decode base64 and parse JSON\r\n const ackData = atob(ackEncoded);\r\n acknowledgements = JSON.parse(ackData);\r\n } catch (e) {\r\n console.warn('Failed to decode acknowledgements:', e);\r\n }\r\n \r\n // Continue processing the rest of the field name\r\n fieldName = beforeAck;\r\n decodedFieldName = fieldName;\r\n }\r\n \r\n // Extract label if present\r\n if (fieldName.includes('__LABEL__')) {\r\n const labelMarkerIndex = fieldName.indexOf('__LABEL__');\r\n decodedFieldName = fieldName.substring(0, labelMarkerIndex);\r\n \r\n const afterLabel = fieldName.substring(labelMarkerIndex + 9); // Skip \"__LABEL__\"\r\n \r\n // Extract signer email if present\r\n if (afterLabel.includes('__SIGNER__')) {\r\n const signerMarkerIndex = afterLabel.indexOf('__SIGNER__');\r\n displayLabel = afterLabel.substring(0, signerMarkerIndex);\r\n const afterSigner = afterLabel.substring(signerMarkerIndex + 10); // Skip \"__SIGNER__\"\r\n \r\n // Extract placeholder if present\r\n if (afterSigner.includes('__PLACEHOLDER__')) {\r\n const placeholderMarkerIndex = afterSigner.indexOf('__PLACEHOLDER__');\r\n assignedSignerEmail = afterSigner.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterSigner.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n assignedSignerEmail = afterSigner;\r\n }\r\n } else if (afterLabel.includes('__PLACEHOLDER__')) {\r\n // Label and placeholder but no signer\r\n const placeholderMarkerIndex = afterLabel.indexOf('__PLACEHOLDER__');\r\n displayLabel = afterLabel.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterLabel.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n displayLabel = afterLabel;\r\n }\r\n } else if (fieldName.includes('__SIGNER__')) {\r\n // Old format without label\r\n const signerMarkerIndex = fieldName.indexOf('__SIGNER__');\r\n decodedFieldName = fieldName.substring(0, signerMarkerIndex);\r\n const afterSigner = fieldName.substring(signerMarkerIndex + 10); // Skip \"__SIGNER__\"\r\n \r\n // Extract placeholder if present\r\n if (afterSigner.includes('__PLACEHOLDER__')) {\r\n const placeholderMarkerIndex = afterSigner.indexOf('__PLACEHOLDER__');\r\n assignedSignerEmail = afterSigner.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterSigner.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n assignedSignerEmail = afterSigner;\r\n }\r\n } else if (fieldName.includes('__PLACEHOLDER__')) {\r\n // Only placeholder present\r\n const placeholderMarkerIndex = fieldName.indexOf('__PLACEHOLDER__');\r\n decodedFieldName = fieldName.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = fieldName.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n }\r\n \r\n return {\r\n decodedFieldName,\r\n displayLabel,\r\n assignedSignerEmail,\r\n fieldPlaceholder,\r\n acknowledgements\r\n };\r\n}\r\n\r\n/**\r\n * Generate a fallback label from a decoded field name\r\n */\r\nexport function generateFallbackLabel(decodedFieldName: string, fieldType: FormFieldType): string {\r\n let displayLabel = decodedFieldName;\r\n \r\n // Remove \"_signature\", \"_initials\", \"_date\" suffixes added by pdf-lib\r\n displayLabel = displayLabel.replace(/_signature$/i, '').replace(/_initials$/i, '').replace(/_date$/i, '');\r\n \r\n // Handle different naming patterns:\r\n // 1. Pure timestamp fields: \"text_1234567890\" → \"Text\"\r\n // 2. Descriptive fields: \"text_Primary_1\" → \"Text Primary\"\r\n // 3. Custom fields: \"customer_name\" → \"Customer Name\"\r\n \r\n if (/^(text|signature|initials|date)_\\d+$/i.test(displayLabel)) {\r\n // Pattern 1: Pure timestamp fields\r\n if (fieldType === FormFieldType.SIGNATURE) return 'Signature';\r\n if (fieldType === FormFieldType.INITIALS) return 'Initials';\r\n if (fieldType === FormFieldType.DATE) return 'Date';\r\n if (fieldType === FormFieldType.TEXT) return 'Text';\r\n if (fieldType === FormFieldType.CHECKBOX) return 'Checkbox';\r\n if (fieldType === FormFieldType.DROPDOWN) return 'Dropdown';\r\n if (fieldType === FormFieldType.RADIO) return 'Option';\r\n } else {\r\n // Pattern 2 & 3: Convert underscores to spaces, remove trailing numbers, capitalize\r\n displayLabel = displayLabel\r\n .replace(/_/g, ' ') // Convert underscores to spaces\r\n .replace(/\\s+\\d+$/g, '') // Remove trailing numbers (e.g., \" 1\")\r\n .trim()\r\n .split(' ') // Split into words\r\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word\r\n .join(' ');\r\n }\r\n \r\n return displayLabel;\r\n}\r\n\r\n/**\r\n * Extract label from TU (tooltip) metadata in PDF field\r\n * @param field - The PDF field with extensions\r\n * @returns The extracted label or empty string\r\n */\r\nfunction extractTULabel(field: PDFFieldWithExtensions): string {\r\n try {\r\n if (!field.acroField?.dict) {\r\n return '';\r\n }\r\n \r\n const tuLabel = field.acroField.dict.get(PDFName.of('TU'));\r\n if (!tuLabel) {\r\n return '';\r\n }\r\n \r\n // PDFString has a decodeText() method or toString()\r\n const tuValue = tuLabel.toString();\r\n if (!tuValue || !tuValue.trim()) {\r\n return '';\r\n }\r\n \r\n // Handle PDF string encoding - extract content between parentheses or angle brackets\r\n // PDF strings are encoded as \"(text)\" or \"<hex>\"\r\n if (tuValue.startsWith('(') || tuValue.startsWith('<')) {\r\n const match = tuValue.match(/^\\((.*)\\)$/) || tuValue.match(/^<(.*)>$/);\r\n if (match && match[1]) {\r\n return match[1];\r\n }\r\n }\r\n \r\n // If no special encoding, return as-is\r\n return tuValue;\r\n } catch (error) {\r\n return '';\r\n }\r\n}\r\n\r\n","/**\r\n * PDF.js Configuration Provider\r\n * Manages global configuration for PDF.js worker and viewer paths\r\n * \r\n * COMPATIBILITY NOTE: This module is designed to work with both Vite and Next.js/webpack.\r\n * The worker source URL is computed lazily to avoid issues with webpack's handling of import.meta.\r\n */\r\n\r\nimport type { PdfJsConfig } from '../types';\r\nimport * as pdfjsLib from 'pdfjs-dist';\r\n\r\n/**\r\n * CDN paths for PDF.js (exported for manual fallback configuration)\r\n * Note: CDN URLs may cause CORS issues in some environments\r\n * \r\n * @example\r\n * // Manually configure CDN (not recommended)\r\n * setPdfJsConfig({ \r\n * viewerBasePath: CDN_VIEWER,\r\n * workerSrc: CDN_WORKER \r\n * });\r\n */\r\nexport const CDN_WORKER = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@5.3.93/build/pdf.worker.mjs';\r\nexport const CDN_VIEWER = 'https://mozilla.github.io/pdf.js';\r\n\r\n/**\r\n * Internal flag to track if worker source has been computed\r\n */\r\nlet _workerSrcComputed = false;\r\nlet _cachedWorkerSrc: string | null = null;\r\n\r\n/**\r\n * Get the worker source URL (computed lazily to avoid webpack import.meta issues)\r\n * - In browser environments, the bundler resolves the URL from node_modules\r\n * - The worker is loaded from the user's bundle (no CORS issues)\r\n * \r\n * This function uses lazy evaluation to avoid triggering webpack's\r\n * \"Critical dependency: Accessing import.meta directly is unsupported\" warning\r\n * at module load time.\r\n */\r\nfunction getDefaultWorkerSrc(): string {\r\n // Return cached value if already computed\r\n if (_workerSrcComputed && _cachedWorkerSrc !== null) {\r\n return _cachedWorkerSrc;\r\n }\r\n\r\n // Default fallback\r\n let workerSrc = '/pdfjs/build/pdf.worker.mjs';\r\n\r\n // Only attempt import.meta resolution in browser environment\r\n if (typeof window !== 'undefined' && typeof URL !== 'undefined') {\r\n try {\r\n // Check if import.meta is available (ESM environment like Vite)\r\n // Use indirect access to avoid webpack static analysis issues\r\n const meta = (function() {\r\n try {\r\n // This pattern avoids webpack's direct import.meta detection\r\n return new Function('return import.meta')();\r\n } catch {\r\n return null;\r\n }\r\n })();\r\n\r\n if (meta && meta.url) {\r\n workerSrc = new URL('pdfjs-dist/build/pdf.worker.mjs', meta.url).href;\r\n }\r\n } catch {\r\n // Fallback for environments that don't support import.meta.url (Next.js/webpack)\r\n // Use the public path fallback\r\n }\r\n }\r\n\r\n // Cache the result\r\n _workerSrcComputed = true;\r\n _cachedWorkerSrc = workerSrc;\r\n\r\n return workerSrc;\r\n}\r\n\r\n/**\r\n * Default configuration for PDF.js\r\n * \r\n * By default, the package uses:\r\n * - Worker: Loaded from node_modules (bundled by your build tool)\r\n * - Viewer: Served from /pdfjs/ (automatically copied by postinstall)\r\n * \r\n * The postinstall script automatically copies viewer files to your public/pdfjs/ directory.\r\n * If setup fails, run: npx signiphi-setup\r\n * \r\n * NOTE: workerSrc is initialized to null and computed lazily on first access\r\n * to ensure compatibility with Next.js/webpack environments.\r\n */\r\nlet globalConfig: Required<PdfJsConfig> = {\r\n viewerBasePath: '/pdfjs',\r\n workerSrc: '', // Lazy-initialized below\r\n};\r\n\r\n// Flag to track if globalConfig.workerSrc has been initialized\r\nlet _configInitialized = false;\r\n\r\n/**\r\n * Ensure config is initialized (called lazily)\r\n */\r\nfunction ensureConfigInitialized(): void {\r\n if (!_configInitialized) {\r\n globalConfig.workerSrc = getDefaultWorkerSrc();\r\n _configInitialized = true;\r\n \r\n // Initialize PDF.js worker in browser environment\r\n if (typeof window !== 'undefined') {\r\n pdfjsLib.GlobalWorkerOptions.workerSrc = globalConfig.workerSrc;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Set PDF.js configuration\r\n * @param config - Partial configuration to merge with defaults\r\n * \r\n * @example\r\n * // Use self-hosted PDF.js files\r\n * setPdfJsConfig({ viewerBasePath: '/pdfjs' });\r\n * \r\n * @example\r\n * // Use custom CDN\r\n * setPdfJsConfig({ \r\n * viewerBasePath: 'https://my-cdn.com/pdfjs',\r\n * workerSrc: 'https://my-cdn.com/pdfjs/build/pdf.worker.mjs'\r\n * });\r\n */\r\nexport function setPdfJsConfig(config: Partial<PdfJsConfig>): void {\r\n // Ensure default config is computed first\r\n ensureConfigInitialized();\r\n \r\n if (config.viewerBasePath !== undefined) {\r\n globalConfig.viewerBasePath = config.viewerBasePath;\r\n }\r\n \r\n if (config.workerSrc !== undefined) {\r\n globalConfig.workerSrc = config.workerSrc;\r\n } else if (config.viewerBasePath !== undefined) {\r\n // Auto-update workerSrc based on viewerBasePath\r\n globalConfig.workerSrc = `${config.viewerBasePath}/build/pdf.worker.mjs`;\r\n }\r\n\r\n // Update PDF.js worker if in browser environment\r\n if (typeof window !== 'undefined') {\r\n pdfjsLib.GlobalWorkerOptions.workerSrc = globalConfig.workerSrc;\r\n }\r\n}\r\n\r\n/**\r\n * Get current PDF.js configuration\r\n * @returns Current configuration\r\n */\r\nexport function getPdfJsConfig(): Required<PdfJsConfig> {\r\n // Ensure config is initialized before returning\r\n ensureConfigInitialized();\r\n return { ...globalConfig };\r\n}\r\n\r\n/**\r\n * Reset configuration to defaults (local files)\r\n */\r\nexport function resetPdfJsConfig(): void {\r\n // Clear cached worker src to force recomputation\r\n _workerSrcComputed = false;\r\n _cachedWorkerSrc = null;\r\n _configInitialized = false;\r\n \r\n // Re-initialize with fresh defaults\r\n ensureConfigInitialized();\r\n}\r\n\r\n/**\r\n * Initialize PDF.js configuration\r\n * This is called automatically when the first PDF operation is attempted,\r\n * but can also be called manually to pre-initialize the configuration.\r\n * \r\n * Unlike previous versions, this does NOT run at module load time to\r\n * ensure compatibility with Next.js/webpack environments.\r\n */\r\nexport function initializePdfJs(): void {\r\n ensureConfigInitialized();\r\n}\r\n\r\n","/**\r\n * Custom Error Classes\r\n * Domain-specific error types for better error handling and debugging\r\n */\r\n\r\n/**\r\n * Error thrown when PDF validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * const validation = validatePdfBytes(bytes);\r\n * if (!validation.valid) {\r\n * throw new PdfValidationError(validation.error || 'Invalid PDF');\r\n * }\r\n * ```\r\n */\r\nexport class PdfValidationError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'PdfValidationError';\r\n // Maintains proper stack trace for where error was thrown (V8 only)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, PdfValidationError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown during PDF processing operations\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * const pdfDoc = await PDFDocument.load(bytes);\r\n * } catch (err) {\r\n * throw new PdfProcessingError('Failed to load PDF document', err);\r\n * }\r\n * ```\r\n */\r\nexport class PdfProcessingError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'PdfProcessingError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, PdfProcessingError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown for form field related issues\r\n * \r\n * @example\r\n * ```ts\r\n * if (!field.value && field.required) {\r\n * throw new FormFieldError(\r\n * 'Required field is empty',\r\n * field.name\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport class FormFieldError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly fieldName?: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'FormFieldError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, FormFieldError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown for attachment validation failures\r\n * \r\n * @example\r\n * ```ts\r\n * if (file.size > maxFileSize) {\r\n * throw new AttachmentValidationError(\r\n * `File size exceeds limit: ${file.name}`,\r\n * file.name\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport class AttachmentValidationError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly fileName?: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'AttachmentValidationError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, AttachmentValidationError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a PdfValidationError\r\n */\r\nexport function isPdfValidationError(error: unknown): error is PdfValidationError {\r\n return error instanceof PdfValidationError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a PdfProcessingError\r\n */\r\nexport function isPdfProcessingError(error: unknown): error is PdfProcessingError {\r\n return error instanceof PdfProcessingError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a FormFieldError\r\n */\r\nexport function isFormFieldError(error: unknown): error is FormFieldError {\r\n return error instanceof FormFieldError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is an AttachmentValidationError\r\n */\r\nexport function isAttachmentValidationError(error: unknown): error is AttachmentValidationError {\r\n return error instanceof AttachmentValidationError;\r\n}\r\n\r\n/**\r\n * Extract error message from unknown error type\r\n * \r\n * @param error - The error to extract message from\r\n * @param defaultMessage - Default message if extraction fails\r\n * @returns Error message string\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * // ... operation\r\n * } catch (err) {\r\n * const message = getErrorMessage(err, 'Operation failed');\r\n * logger.error(message);\r\n * }\r\n * ```\r\n */\r\nexport function getErrorMessage(error: unknown, defaultMessage = 'Unknown error'): string {\r\n if (error instanceof Error) {\r\n return error.message;\r\n }\r\n if (typeof error === 'string') {\r\n return error;\r\n }\r\n return defaultMessage;\r\n}\r\n\r\n","/**\r\n * Attachment Validation Utilities\r\n * Validation functions for file attachments\r\n */\r\n\r\nimport type { AttachmentConstraints, Attachment } from '../types';\r\nimport { AttachmentValidationError } from './errors';\r\n\r\n/**\r\n * Default attachment constraints\r\n */\r\nexport const DEFAULT_ATTACHMENT_CONSTRAINTS: AttachmentConstraints = {\r\n maxFileSize: 10 * 1024 * 1024, // 10MB\r\n maxTotalSize: 50 * 1024 * 1024, // 50MB\r\n maxFiles: 10,\r\n allowedTypes: ['image/*', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],\r\n allowedExtensions: ['.pdf', '.jpg', '.jpeg', '.png', '.gif', '.doc', '.docx'],\r\n};\r\n\r\n/**\r\n * Validate a single file against constraints\r\n * \r\n * @param file - File to validate\r\n * @param constraints - Validation constraints\r\n * @returns Validation result with errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFile(file, DEFAULT_ATTACHMENT_CONSTRAINTS);\r\n * if (result.errors.length > 0) {\r\n * console.error('File validation failed:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFile(\r\n file: File,\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n\r\n // Validate file size\r\n if (file.size > constraints.maxFileSize) {\r\n const maxMB = (constraints.maxFileSize / 1024 / 1024).toFixed(1);\r\n const fileMB = (file.size / 1024 / 1024).toFixed(1);\r\n errors.push(`File \"${file.name}\" is too large (${fileMB}MB). Maximum size is ${maxMB}MB.`);\r\n }\r\n\r\n // Validate file type (MIME type)\r\n const isTypeAllowed = constraints.allowedTypes.some((allowedType) => {\r\n if (allowedType.endsWith('/*')) {\r\n // Wildcard type (e.g., 'image/*')\r\n const prefix = allowedType.slice(0, -2);\r\n return file.type.startsWith(prefix);\r\n }\r\n return file.type === allowedType;\r\n });\r\n\r\n if (!isTypeAllowed && constraints.allowedTypes.length > 0) {\r\n errors.push(\r\n `File type \"${file.type}\" is not allowed for \"${file.name}\". Allowed types: ${constraints.allowedTypes.join(', ')}`\r\n );\r\n }\r\n\r\n // Validate file extension\r\n if (constraints.allowedExtensions && constraints.allowedExtensions.length > 0) {\r\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();\r\n const isExtAllowed = constraints.allowedExtensions.some(\r\n (ext) => ext.toLowerCase() === fileExt\r\n );\r\n\r\n if (!isExtAllowed) {\r\n errors.push(\r\n `File extension \"${fileExt}\" is not allowed for \"${file.name}\". Allowed extensions: ${constraints.allowedExtensions.join(', ')}`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate multiple files against constraints\r\n * \r\n * @param files - Files to validate\r\n * @param existingAttachments - Existing attachments to consider for total size/count\r\n * @param constraints - Validation constraints\r\n * @returns Validation result with errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFiles(newFiles, existingAttachments, DEFAULT_ATTACHMENT_CONSTRAINTS);\r\n * if (result.errors.length > 0) {\r\n * alert('Some files cannot be uploaded: ' + result.errors.join(', '));\r\n * }\r\n * ```\r\n */\r\nexport function validateFiles(\r\n files: File[],\r\n existingAttachments: Attachment[] = [],\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n\r\n // Validate total number of files\r\n const totalFiles = files.length + existingAttachments.length;\r\n if (totalFiles > constraints.maxFiles) {\r\n errors.push(\r\n `Too many files. Maximum allowed is ${constraints.maxFiles}, you have ${totalFiles} files total.`\r\n );\r\n }\r\n\r\n // Validate total size\r\n const existingSize = existingAttachments.reduce((sum, att) => sum + att.size, 0);\r\n const newFilesSize = files.reduce((sum, file) => sum + file.size, 0);\r\n const totalSize = existingSize + newFilesSize;\r\n\r\n if (totalSize > constraints.maxTotalSize) {\r\n const maxMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n const totalMB = (totalSize / 1024 / 1024).toFixed(1);\r\n errors.push(\r\n `Total size of all files is too large (${totalMB}MB). Maximum total size is ${maxMB}MB.`\r\n );\r\n }\r\n\r\n // Validate each individual file\r\n for (const file of files) {\r\n const fileResult = validateFile(file, constraints);\r\n errors.push(...fileResult.errors);\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate file and throw error if invalid\r\n * \r\n * Convenience function that throws AttachmentValidationError if validation fails.\r\n * \r\n * @param file - File to validate\r\n * @param constraints - Validation constraints\r\n * @throws {AttachmentValidationError} If validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * validateFileOrThrow(file);\r\n * // File is valid, proceed with upload\r\n * } catch (err) {\r\n * if (err instanceof AttachmentValidationError) {\r\n * alert(err.message);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function validateFileOrThrow(\r\n file: File,\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): void {\r\n const result = validateFile(file, constraints);\r\n if (!result.valid) {\r\n throw new AttachmentValidationError(\r\n `File validation failed: ${result.errors.join('; ')}`,\r\n file.name,\r\n { file, errors: result.errors }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate multiple files and throw error if invalid\r\n * \r\n * @param files - Files to validate\r\n * @param existingAttachments - Existing attachments\r\n * @param constraints - Validation constraints\r\n * @throws {AttachmentValidationError} If validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * validateFilesOrThrow(selectedFiles, currentAttachments);\r\n * // All files are valid\r\n * } catch (err) {\r\n * if (err instanceof AttachmentValidationError) {\r\n * alert(err.message);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function validateFilesOrThrow(\r\n files: File[],\r\n existingAttachments: Attachment[] = [],\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): void {\r\n const result = validateFiles(files, existingAttachments, constraints);\r\n if (!result.valid) {\r\n throw new AttachmentValidationError(\r\n `File validation failed: ${result.errors.join('; ')}`,\r\n undefined,\r\n { files, errors: result.errors }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file type is an image\r\n * \r\n * @param fileType - MIME type of the file\r\n * @returns true if the file is an image\r\n * \r\n * @example\r\n * ```ts\r\n * if (isImageType(file.type)) {\r\n * // Generate preview\r\n * }\r\n * ```\r\n */\r\nexport function isImageType(fileType: string): boolean {\r\n return fileType.startsWith('image/');\r\n}\r\n\r\n/**\r\n * Format file size for display\r\n * \r\n * @param bytes - File size in bytes\r\n * @returns Formatted size string (e.g., \"1.5 MB\")\r\n * \r\n * @example\r\n * ```ts\r\n * const sizeDisplay = formatFileSize(file.size); // \"1.5 MB\"\r\n * ```\r\n */\r\nexport function formatFileSize(bytes: number): string {\r\n if (bytes === 0) return '0 Bytes';\r\n \r\n const k = 1024;\r\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n \r\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];\r\n}\r\n\r\n","/**\r\n * Date Validation and Parsing Utility\r\n * Handles parsing of various date formats and validation\r\n */\r\n\r\nimport { parse, isValid as isValidDate, parseISO } from 'date-fns';\r\n\r\nexport interface DateValidationResult {\r\n isValid: boolean;\r\n date: Date | null;\r\n isoString: string | null;\r\n originalValue: string;\r\n error?: string;\r\n}\r\n\r\nfunction toIsoDateString(date: Date): string {\r\n const year = date.getFullYear();\r\n const month = String(date.getMonth() + 1).padStart(2, '0');\r\n const day = String(date.getDate()).padStart(2, '0');\r\n return `${year}-${month}-${day}`;\r\n}\r\n\r\n/**\r\n * Parse and validate a date string from various formats\r\n * Attempts to parse common formats: ISO, US, EU, timestamps\r\n * \r\n * Format priority:\r\n * 1. ISO 8601 (YYYY-MM-DD)\r\n * 2. US format (MM/DD/YYYY) - assumes US format for ambiguous dates\r\n * 3. EU format (DD/MM/YYYY)\r\n * 4. Timestamp (numeric string)\r\n * \r\n * @param value - The date string to parse\r\n * @returns Validation result with parsed date or error\r\n */\r\nexport function parseAndValidateDate(value: string | null | undefined): DateValidationResult {\r\n const originalValue = String(value || '');\r\n \r\n // Handle empty values\r\n if (!value || value.trim() === '') {\r\n return {\r\n isValid: false,\r\n date: null,\r\n isoString: null,\r\n originalValue,\r\n error: 'Date is required',\r\n };\r\n }\r\n\r\n const trimmedValue = value.trim();\r\n const sanitizedValue = trimmedValue\r\n // Remove ordinal suffixes (1st, 2nd, 3rd, 21st, etc.)\r\n .replace(/(\\d+)(st|nd|rd|th)/gi, '$1')\r\n // Normalize commas to spaces for natural language inputs\r\n .replace(/,/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim();\r\n\r\n // Try ISO 8601 format first (YYYY-MM-DD)\r\n try {\r\n const isoDate = parseISO(trimmedValue);\r\n if (isValidDate(isoDate) && !isNaN(isoDate.getTime())) {\r\n return {\r\n isValid: true,\r\n date: isoDate,\r\n isoString: trimmedValue,\r\n originalValue,\r\n };\r\n }\r\n } catch {\r\n // Continue to next format\r\n }\r\n\r\n // Handle two-digit year inputs like 01/05/24 by assuming 2000-based year\r\n const shortYearMatch = sanitizedValue.match(/^(\\d{1,2})[\\/.\\-](\\d{1,2})[\\/.\\-](\\d{2})$/);\r\n if (shortYearMatch) {\r\n const [, monthStr, dayStr, yearStr] = shortYearMatch;\r\n const month = parseInt(monthStr ?? '', 10);\r\n const day = parseInt(dayStr ?? '', 10);\r\n const year = 2000 + parseInt(yearStr ?? '', 10);\r\n const candidate = new Date(year, month - 1, day);\r\n if (isValidDate(candidate) && !isNaN(candidate.getTime())) {\r\n return {\r\n isValid: true,\r\n date: candidate,\r\n isoString: toIsoDateString(candidate),\r\n originalValue,\r\n };\r\n }\r\n }\r\n\r\n // Try common date formats\r\n const formats = [\r\n // US formats (MM/DD/YYYY - assume US for ambiguous dates)\r\n { pattern: 'MM/dd/yyyy', name: 'US format (MM/DD/YYYY)' },\r\n { pattern: 'M/d/yyyy', name: 'US format (M/D/YYYY)' },\r\n { pattern: 'MM-dd-yyyy', name: 'US format (MM-DD-YYYY)' },\r\n { pattern: 'M-d-yyyy', name: 'US format (M-D-YYYY)' },\r\n { pattern: 'MM/dd/yy', name: 'US format (MM/DD/YY)' },\r\n { pattern: 'M/d/yy', name: 'US format (M/D/YY)' },\r\n { pattern: 'MM-dd-yy', name: 'US format (MM-DD-YY)' },\r\n { pattern: 'M-d-yy', name: 'US format (M-D-YY)' },\r\n \r\n // EU formats (DD/MM/YYYY)\r\n { pattern: 'dd/MM/yyyy', name: 'EU format (DD/MM/YYYY)' },\r\n { pattern: 'd/M/yyyy', name: 'EU format (D/M/YYYY)' },\r\n { pattern: 'dd.MM.yyyy', name: 'EU format (DD.MM.YYYY)' },\r\n { pattern: 'd.M.yyyy', name: 'EU format (D.M.YYYY)' },\r\n \r\n // Full month names\r\n { pattern: 'MMMM d, yyyy', name: 'Month name format (January 1, 2024)' },\r\n { pattern: 'MMM d, yyyy', name: 'Short month format (Jan 1, 2024)' },\r\n { pattern: 'MMMM d yyyy', name: 'Month name format without comma (January 1 2024)' },\r\n { pattern: 'MMM d yyyy', name: 'Short month without comma (Jan 1 2024)' },\r\n { pattern: 'd MMMM yyyy', name: 'EU month format (1 January 2024)' },\r\n { pattern: 'd MMM yyyy', name: 'EU month short format (1 Jan 2024)' },\r\n { pattern: 'd MMM, yyyy', name: 'EU month short with comma (1 Jan, 2024)' },\r\n \r\n // Year first formats\r\n { pattern: 'yyyy/MM/dd', name: 'ISO-like format (YYYY/MM/DD)' },\r\n { pattern: 'yyyy-MM-dd', name: 'ISO format with dashes' },\r\n ];\r\n\r\n const referenceDate = new Date();\r\n\r\n for (const { pattern } of formats) {\r\n try {\r\n const parsedDate = parse(sanitizedValue, pattern, referenceDate);\r\n if (isValidDate(parsedDate) && !isNaN(parsedDate.getTime())) {\r\n // Convert to ISO string format (YYYY-MM-DD)\r\n const isoString = toIsoDateString(parsedDate);\r\n \r\n return {\r\n isValid: true,\r\n date: parsedDate,\r\n isoString,\r\n originalValue,\r\n };\r\n }\r\n } catch {\r\n // Continue to next format\r\n }\r\n }\r\n\r\n // Try parsing as timestamp (milliseconds)\r\n if (/^\\d+$/.test(trimmedValue)) {\r\n try {\r\n const timestamp = parseInt(trimmedValue, 10);\r\n const date = new Date(timestamp);\r\n if (isValidDate(date) && !isNaN(date.getTime())) {\r\n const isoString = toIsoDateString(date);\r\n \r\n return {\r\n isValid: true,\r\n date,\r\n isoString,\r\n originalValue,\r\n };\r\n }\r\n } catch {\r\n // Not a valid timestamp\r\n }\r\n }\r\n\r\n // Lenient fallback using native Date parsing after sanitization\r\n const nativeParsed = new Date(sanitizedValue);\r\n if (isValidDate(nativeParsed) && !isNaN(nativeParsed.getTime())) {\r\n return {\r\n isValid: true,\r\n date: nativeParsed,\r\n isoString: toIsoDateString(nativeParsed),\r\n originalValue,\r\n };\r\n }\r\n\r\n // All formats failed\r\n return {\r\n isValid: false,\r\n date: null,\r\n isoString: null,\r\n originalValue,\r\n error: `Invalid date format: \"${trimmedValue}\". Please use a date picker or format like MM/DD/YYYY.`,\r\n };\r\n}\r\n\r\n/**\r\n * Validate if a string is a valid ISO date (YYYY-MM-DD)\r\n */\r\nexport function isValidISODate(value: string | null | undefined): boolean {\r\n if (!value || typeof value !== 'string') {\r\n return false;\r\n }\r\n\r\n const isoPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\r\n if (!isoPattern.test(value)) {\r\n return false;\r\n }\r\n\r\n try {\r\n const date = parseISO(value);\r\n return isValidDate(date) && !isNaN(date.getTime());\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n","/**\r\n * PDF Viewer Filtering Utility\r\n * Removes other signers' fields from PDF for viewer display\r\n * Based on Dockmaster's field removal logic (lines 977-1037)\r\n */\r\n\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport type { PDFDocument } from 'pdf-lib';\r\nimport type { EsignFormField, MultiSignerContext } from '../types';\r\nimport { FormFieldType } from '../types';\r\nimport { logger } from './logger';\r\nimport { isAutoGeneratedLabel } from './pdf-validators';\r\nimport { isFieldVisibleToSigner } from './field-visibility';\r\nimport { findPageIndexWithFallback, type PDFWidgetWithExtensions } from './pdf-widget-helpers';\r\n\r\n// Extended types for pdf-lib widgets (for label drawing)\r\ninterface PDFFieldWithExtensions {\r\n acroField?: {\r\n getWidgets?: () => unknown[];\r\n };\r\n}\r\n\r\n/**\r\n * Draw cosmetic labels on PDF fields for viewer display\r\n * Based on dm-web-frontend's label drawing logic (commit aafc786)\r\n * \r\n * @param pdfDoc - The PDF document to draw labels on\r\n * @param fieldsToLabel - Fields visible to current signer that need labels\r\n * @param rgb - The rgb function from pdf-lib\r\n */\r\nasync function drawFieldLabelsOnPdf(\r\n pdfDoc: PDFDocument,\r\n fieldsToLabel: EsignFormField[],\r\n rgb: (r: number, g: number, b: number) => any\r\n): Promise<void> {\r\n\r\n try {\r\n // Embed font for labels\r\n const labelFont = await pdfDoc.embedFont('Helvetica-Bold');\r\n const pages = pdfDoc.getPages();\r\n const form = pdfDoc.getForm();\r\n const drawnOnce = new Set<string>();\r\n\r\n for (const field of fieldsToLabel) {\r\n // Skip fields without labels EXCEPT radio fields which need option texts drawn\r\n // Fix from dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n // Match dm-web-frontend submission.page.tsx lines 1427-1433\r\n const isRadioField = field.type === FormFieldType.RADIO;\r\n const hasRadioOptions = isRadioField && field.options && field.options.length > 0;\r\n \r\n // Skip fields without custom labels EXCEPT radio fields which need option texts drawn\r\n const hasCustomLabel = field.label && field.label.trim() && !isAutoGeneratedLabel(field.label);\r\n \r\n if (!hasCustomLabel && !hasRadioOptions) {\r\n continue;\r\n }\r\n\r\n const pdfField = form.getFieldMaybe(field.name);\r\n if (!pdfField) {\r\n continue;\r\n }\r\n\r\n // Get widgets for this field\r\n const fieldWithExtensions = pdfField as unknown as PDFFieldWithExtensions;\r\n const widgets = (fieldWithExtensions.acroField?.getWidgets?.() || []) as PDFWidgetWithExtensions[];\r\n \r\n if (widgets.length === 0) continue;\r\n\r\n // Handle radio fields specially\r\n // Match dm-web-frontend submission.page.tsx lines 1440-1496\r\n if (isRadioField) {\r\n // Draw radio GROUP label (once per field)\r\n if (field.label && field.label.trim() && !isAutoGeneratedLabel(field.label)) {\r\n const firstWidget = widgets[0];\r\n if (!firstWidget) continue;\r\n const firstRect = firstWidget.getRectangle?.();\r\n \r\n if (firstRect) {\r\n const pageRef = firstWidget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n \r\n if (pageIndex >= 0) {\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const groupLabelKey = `${pageIndex}-${field.name}-grouplabel`;\r\n \r\n // Only draw if not already drawn\r\n if (!drawnOnce.has(groupLabelKey)) {\r\n // Match dm-web-frontend: size 10, position y + height + 5\r\n const labelY = firstRect.y + firstRect.height + 5;\r\n page.drawText(field.label, {\r\n x: firstRect.x,\r\n y: labelY,\r\n size: 10,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOnce.add(groupLabelKey);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Draw each option text ONLY if explicit options exist\r\n // Match dm-web-frontend: size 10, position x + width + 6, centered vertically\r\n if (field.options && field.options.length > 0) {\r\n for (let i = 0; i < widgets.length; i++) {\r\n const widget = widgets[i];\r\n if (!widget) continue;\r\n const rect = widget.getRectangle?.();\r\n if (!rect) continue;\r\n\r\n const pageRef = widget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n \r\n if (pageIndex >= 0) {\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const optionTexts = field.options;\r\n const optionText = optionTexts[i] || optionTexts[0];\r\n const optionKey = `${pageIndex}-${field.name}-opt-${i}`;\r\n \r\n if (optionText && !drawnOnce.has(optionKey)) {\r\n page.drawText(optionText, {\r\n x: rect.x + rect.width + 6,\r\n y: rect.y + (rect.height - 10) / 2,\r\n size: 10,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOnce.add(optionKey);\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n // For other fields, draw label once\r\n // Match dm-web-frontend submission.page.tsx lines 1498-1534\r\n const widget = widgets[0];\r\n if (!widget) continue;\r\n const rect = widget.getRectangle?.();\r\n if (!rect) continue;\r\n\r\n const pageRef = widget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n \r\n if (pageIndex >= 0 && pageIndex < pages.length) {\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const key = `${pageIndex}-${field.name}`;\r\n \r\n if (!drawnOnce.has(key)) {\r\n // Only draw if it's a user-typed custom label (not auto-generated)\r\n if (!isAutoGeneratedLabel(field.label)) {\r\n // Match dm-web-frontend: checkbox size 10, other fields size 9\r\n if (field.type === FormFieldType.CHECKBOX) {\r\n // Checkbox label to the right - size 10, position x + width + 5\r\n page.drawText(field.label, {\r\n x: rect.x + rect.width + 5,\r\n y: rect.y + (rect.height * 0.2),\r\n size: 10,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n } else {\r\n // Other field labels above the field - size 9, position y + height + 5\r\n const labelY = rect.y + rect.height + 5;\r\n page.drawText(field.label, {\r\n x: rect.x,\r\n y: labelY,\r\n size: 9,\r\n font: labelFont,\r\n color: rgb(0.3, 0.3, 0.3),\r\n });\r\n }\r\n drawnOnce.add(key);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Update form field appearances to ensure radio button selections render correctly\r\n // Fix from dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n try {\r\n form.updateFieldAppearances();\r\n } catch (appearanceError) {\r\n // Non-critical error - just log and continue\r\n }\r\n\r\n } catch (error) {\r\n // Non-critical error - just log and continue without labels\r\n logger.error('Error drawing field labels:', error);\r\n // Don't throw - allow the PDF to be used without labels\r\n }\r\n}\r\n\r\n/**\r\n * Filter PDF for current signer by removing other signers' fields\r\n * This creates a modified PDF for the viewer while preserving the original\r\n * \r\n * @param pdfBytes - Original PDF bytes with ALL fields\r\n * @param allFields - All form fields extracted from the PDF\r\n * @param multiSignerContext - Multi-signer context\r\n * @returns Modified PDF bytes with other signers' fields removed (for viewer only)\r\n * \r\n * @example\r\n * ```ts\r\n * const originalPdfBytes = await urlToPdfBytes(pdfUrl);\r\n * const allFields = await extractFormFields(originalPdfBytes);\r\n * \r\n * if (multiSignerContext.isMultiSigner) {\r\n * // Create filtered PDF for viewer\r\n * const viewerPdfBytes = await filterPdfForCurrentSigner(\r\n * originalPdfBytes,\r\n * allFields,\r\n * multiSignerContext\r\n * );\r\n * loadPdfIntoViewer(viewerPdfBytes);\r\n * \r\n * // CRITICAL: Keep originalPdfBytes for submission\r\n * }\r\n * ```\r\n */\r\nexport async function filterPdfForCurrentSigner(\r\n pdfBytes: Uint8Array,\r\n allFields: EsignFormField[],\r\n multiSignerContext: MultiSignerContext\r\n): Promise<Uint8Array> {\r\n // Single signer mode: no filtering needed, but we still draw labels\r\n if (!multiSignerContext.isMultiSigner) {\r\n \r\n try {\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Draw labels on all fields (no filtering in single-signer mode)\r\n await drawFieldLabelsOnPdf(pdfDoc, allFields, rgb);\r\n \r\n // Save and return the labeled PDF\r\n const labeledBytes = await pdfDoc.save();\r\n return labeledBytes;\r\n } catch (error) {\r\n return pdfBytes;\r\n }\r\n }\r\n\r\n // Determine which fields to remove using centralized visibility logic\r\n const otherSignersFields = allFields.filter(f => {\r\n // RULE 0: TEXT_LABEL fields are ALWAYS visible to all signers\r\n // They are flattened into the PDF and should never be hidden\r\n // Fix based on dm-web-frontend commit e81bbdd (Oct 29, 2025)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return false; // Never remove TEXT_LABEL fields\r\n }\r\n\r\n // Use centralized visibility logic: if NOT visible, should be removed\r\n return !isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n\r\n\r\n // If no fields to remove, still draw labels on remaining fields\r\n // Match dm-web-frontend submission.page.tsx lines 1588-1730\r\n if (otherSignersFields.length === 0) {\r\n try {\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Draw labels on all visible fields (no removal needed)\r\n const fieldsToLabel = allFields.filter(f => {\r\n // Include TEXT_LABEL fields (always visible)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return true;\r\n }\r\n // Use centralized visibility logic\r\n return isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n \r\n await drawFieldLabelsOnPdf(pdfDoc, fieldsToLabel, rgb);\r\n \r\n // Save and return the labeled PDF\r\n const labeledBytes = await pdfDoc.save();\r\n return labeledBytes;\r\n } catch (error) {\r\n // If label drawing fails, return original\r\n return pdfBytes;\r\n }\r\n }\r\n\r\n // Load a fresh copy of the PDF for modification\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const freshPdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = freshPdfDoc.getForm();\r\n\r\n // Remove other signers' fields from the form\r\n let removedCount = 0;\r\n let notFoundCount = 0;\r\n\r\n for (const field of otherSignersFields) {\r\n try {\r\n const pdfField = form.getFieldMaybe(field.name);\r\n if (pdfField) {\r\n form.removeField(pdfField);\r\n removedCount++;\r\n } else {\r\n notFoundCount++;\r\n }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : 'Unknown error';\r\n logger.error('Error removing field:', errorMsg);\r\n }\r\n }\r\n\r\n // Draw labels on remaining fields (cosmetic enhancement for viewer)\r\n // Based on dm-web-frontend's label drawing logic (commit aafc786)\r\n try {\r\n // Determine which fields to label (fields visible to current signer)\r\n const fieldsToLabel = allFields.filter(f => {\r\n // Include TEXT_LABEL fields (always visible)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return true;\r\n }\r\n\r\n // Use centralized visibility logic\r\n return isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n\r\n await drawFieldLabelsOnPdf(freshPdfDoc, fieldsToLabel, rgb);\r\n } catch (labelError) {\r\n // Continue without labels - not critical for functionality\r\n }\r\n\r\n // Save the modified PDF\r\n const modifiedPdfBytes = await freshPdfDoc.save();\r\n\r\n\r\n return modifiedPdfBytes;\r\n}\r\n\r\n","import { useRef, useState, useCallback } from 'react';\nimport type { PdfViewerRef, EsignFormField, MultiSignerContext } from '../types';\nimport {\n extractVisibleFormFields,\n fillPdfWithSignatures,\n validatePdfFormFields,\n urlToPdfBytes,\n createPdfBlobUrl,\n logger,\n validatePdfUrl,\n validateFieldValues,\n validateSignatures,\n PdfValidationError,\n PdfProcessingError,\n initializePdfJs,\n} from '../utils';\nimport { filterPdfForCurrentSigner } from '../utils/pdf-viewer-filter';\nimport { loadPdfLib } from '../utils/pdf-lib-loader';\n\n/**\n * Hook to manage PDF viewer state and operations with multi-signer support\n * \n * @param multiSignerContext - Multi-signer context (from useMultiSignerContext)\n */\nexport function usePdfViewer(\n multiSignerContext?: MultiSignerContext\n) {\n const viewerRef = useRef<PdfViewerRef>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n const [pdfUrl, setPdfUrl] = useState<string | null>(null);\n \n // CRITICAL: Store both original and viewer PDF bytes\n // Original PDF has ALL fields (used for submission/flattening)\n // Viewer PDF has only current signer's fields (used for display)\n const [originalPdfBytes, setOriginalPdfBytes] = useState<Uint8Array | null>(null);\n const [_viewerPdfBytes, setViewerPdfBytes] = useState<Uint8Array | null>(null);\n const [extractedFields, setExtractedFields] = useState<EsignFormField[]>([]);\n\n const loadPdf = useCallback(async (url: string) => {\n setIsLoading(true);\n setError(null);\n setIsLoaded(false);\n setPdfUrl(url);\n\n try {\n // Initialize PDF.js configuration (lazy, only runs once)\n // This ensures the worker is configured before any PDF operations\n initializePdfJs();\n \n // Validate URL format\n const urlValidation = validatePdfUrl(url);\n if (!urlValidation.valid) {\n throw new PdfValidationError(urlValidation.error || 'Invalid PDF URL');\n }\n\n // Load PDF bytes for processing\n const bytes = await urlToPdfBytes(url);\n \n // Store as original PDF (with ALL fields)\n setOriginalPdfBytes(bytes);\n setViewerPdfBytes(bytes); // Initially same as original\n \n // Load PDF in viewer\n await viewerRef.current?.loadPdf(url);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to load PDF';\n logger.error('Error loading PDF:', err);\n setError(errorMessage);\n setOriginalPdfBytes(null);\n setViewerPdfBytes(null);\n }\n }, []);\n\n const handleLoad = useCallback(() => {\n setIsLoading(false);\n setIsLoaded(true);\n setError(null);\n }, []);\n\n const handleError = useCallback((errorMessage: string) => {\n setIsLoading(false);\n setIsLoaded(false);\n setError(errorMessage);\n }, []);\n\n const getFormFieldValues = useCallback(async () => {\n if (!viewerRef.current) {\n return {};\n }\n return await viewerRef.current.getFormFieldValues();\n }, []);\n\n const setFormFieldValues = useCallback(async (values: Record<string, string>) => {\n if (!viewerRef.current) {\n return;\n }\n return await viewerRef.current.setFormFieldValues(values);\n }, []);\n\n const getAllFieldNames = useCallback(async () => {\n if (!viewerRef.current) {\n return [];\n }\n return await viewerRef.current.getAllFieldNames();\n }, []);\n\n const saveDocument = useCallback(async () => {\n if (!viewerRef.current) {\n return null;\n }\n return await viewerRef.current.saveDocument();\n }, []);\n\n /**\n * Extract form fields from the current PDF\n * If multi-signer, creates a filtered PDF for the viewer\n */\n const extractFormFields = useCallback(\n async (currentSignerEmail?: string) => {\n if (!originalPdfBytes) {\n throw new Error('No PDF loaded');\n }\n\n try {\n \n // Extract fields from original PDF (with ALL fields)\n const fields = await extractVisibleFormFields(\n originalPdfBytes, \n currentSignerEmail\n );\n setExtractedFields(fields);\n \n\n // If multi-signer mode, create a filtered PDF for the viewer\n if (multiSignerContext?.isMultiSigner) {\n \n // Create filtered PDF with other signers' fields removed\n const filteredBytes = await filterPdfForCurrentSigner(\n originalPdfBytes,\n fields,\n multiSignerContext\n );\n \n setViewerPdfBytes(filteredBytes);\n \n // Reload viewer with filtered PDF\n const filteredBlobUrl = createPdfBlobUrl(filteredBytes);\n await viewerRef.current?.loadPdf(filteredBlobUrl);\n \n } else {\n \n // Single-signer mode: call filterPdfForCurrentSigner to draw labels\n // (it will skip filtering but draw labels)\n const labeledBytes = await filterPdfForCurrentSigner(\n originalPdfBytes,\n fields,\n multiSignerContext || { \n isMultiSigner: false,\n currentSigner: null,\n currentSignerEmail: '', \n isPrimarySigner: true, \n isFinalSigner: true \n }\n );\n \n setViewerPdfBytes(labeledBytes);\n \n // Reload viewer with labeled PDF\n const labeledBlobUrl = createPdfBlobUrl(labeledBytes);\n await viewerRef.current?.loadPdf(labeledBlobUrl);\n \n }\n \n // Inject placeholders into PDF.js viewer (after reload if filtered)\n if (viewerRef.current && fields.length > 0) {\n // Small delay to ensure viewer has loaded\n await new Promise(resolve => setTimeout(resolve, 100));\n viewerRef.current.injectPlaceholders(fields);\n }\n \n return fields;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to extract form fields';\n throw new Error(errorMessage);\n }\n },\n [originalPdfBytes, multiSignerContext]\n );\n\n /**\n * Fill the PDF with form values and signatures, then return the filled PDF bytes\n * CRITICAL: Always uses originalPdfBytes (with ALL fields) for proper flattening\n */\n const fillPdf = useCallback(\n async (\n fieldValues: Record<string, string>,\n signatures: Record<string, string>,\n currentSignerEmail?: string,\n metadata?: { submissionId?: string; documentId?: string; author?: string; signerEmail?: string; signerInitials?: string; createdAt?: Date },\n auditTrail?: { userAgent?: string; screenResolution?: string; timezone?: string; language?: string; platform?: string; ipAddress?: string; geolocation?: { latitude: number; longitude: number; accuracy?: number } }\n ): Promise<Uint8Array> => {\n if (!originalPdfBytes) {\n throw new PdfProcessingError('No PDF loaded');\n }\n\n try {\n // Validate inputs\n const valuesValidation = validateFieldValues(fieldValues);\n if (!valuesValidation.valid) {\n logger.warn('Field values validation warnings:', valuesValidation.errors);\n // Don't throw - allow submission with warnings\n }\n\n const sigsValidation = validateSignatures(signatures);\n if (!sigsValidation.valid) {\n logger.warn('Signatures validation warnings:', sigsValidation.errors);\n // Don't throw - allow submission with warnings\n }\n\n const filledPdfBytes = await fillPdfWithSignatures(\n originalPdfBytes, // CRITICAL: Use original PDF with ALL fields\n signatures,\n fieldValues,\n currentSignerEmail,\n extractedFields, // Pass extracted fields for proper signature filtering\n metadata,\n auditTrail,\n multiSignerContext // Pass multi-signer context for partial flattening\n );\n return filledPdfBytes;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fill PDF';\n logger.error('Error filling PDF:', err);\n throw new PdfProcessingError(errorMessage, err);\n }\n },\n [originalPdfBytes, extractedFields, multiSignerContext]\n );\n\n /**\n * Validate that all required fields are filled\n */\n const validatePdf = useCallback(\n async (\n fieldValues: Record<string, string>,\n signatures: Record<string, string>,\n visibleFields?: EsignFormField[] // Optional: pass filtered fields for multi-signer validation\n ): Promise<{ isValid: boolean; errors: string[] }> => {\n if (!originalPdfBytes) {\n throw new Error('No PDF loaded');\n }\n\n try {\n // Use visibleFields if provided (for multi-signer), otherwise use extractedFields\n const fieldsToValidate = visibleFields || extractedFields;\n const errors = await validatePdfFormFields(\n originalPdfBytes, \n fieldValues, \n signatures,\n fieldsToValidate, // Pass visible/filtered fields for validation\n multiSignerContext // Pass multi-signer context for validation filtering\n );\n return {\n isValid: errors.length === 0,\n errors,\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to validate PDF';\n throw new Error(errorMessage);\n }\n },\n [originalPdfBytes, extractedFields, multiSignerContext]\n );\n\n /**\n * Get required field status from PDF metadata using pdf-lib\n * Returns a map of field names to their required status\n */\n const getRequiredFieldsMap = useCallback(async (): Promise<Record<string, boolean>> => {\n if (!originalPdfBytes) {\n return {};\n }\n\n try {\n const { PDFDocument } = await loadPdfLib();\n const pdfDoc = await PDFDocument.load(originalPdfBytes);\n const form = pdfDoc.getForm();\n const fields = form.getFields();\n\n const requiredMap: Record<string, boolean> = {};\n for (const field of fields) {\n const fieldName = field.getName();\n const isRequired = field.isRequired();\n requiredMap[fieldName] = isRequired;\n }\n\n return requiredMap;\n } catch (err) {\n logger.error('Failed to get required fields map:', err);\n return {};\n }\n }, [originalPdfBytes]);\n\n /**\n * Get the current PDF bytes (original with ALL fields)\n */\n const getCurrentPdfBytes = useCallback(() => {\n return originalPdfBytes;\n }, [originalPdfBytes]);\n\n /**\n * Reload the PDF with new bytes (for preview after filling)\n */\n const reloadPdfWithBytes = useCallback(\n async (newPdfBytes: Uint8Array) => {\n try {\n // Create a blob URL from the new PDF bytes\n const blobUrl = createPdfBlobUrl(newPdfBytes);\n \n // Update state\n setOriginalPdfBytes(newPdfBytes);\n setViewerPdfBytes(newPdfBytes);\n setPdfUrl(blobUrl);\n \n // Reload in viewer\n await viewerRef.current?.loadPdf(blobUrl);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to reload PDF';\n setError(errorMessage);\n }\n },\n []\n );\n\n /**\n * Reset the hook state\n */\n const reset = useCallback(() => {\n setIsLoading(false);\n setError(null);\n setIsLoaded(false);\n setPdfUrl(null);\n setOriginalPdfBytes(null);\n setViewerPdfBytes(null);\n setExtractedFields([]);\n }, []);\n\n return {\n // Ref and state\n viewerRef,\n isLoading,\n error,\n isLoaded,\n pdfUrl,\n pdfBytes: originalPdfBytes, // Expose as pdfBytes for backward compatibility\n extractedFields,\n \n // Basic operations\n loadPdf,\n handleLoad,\n handleError,\n getFormFieldValues,\n setFormFieldValues,\n getAllFieldNames,\n saveDocument,\n \n // Enhanced operations\n extractFormFields,\n fillPdf,\n validatePdf,\n getRequiredFieldsMap,\n getCurrentPdfBytes,\n reloadPdfWithBytes,\n reset,\n };\n}\n\n","import { useState, useCallback } from 'react';\r\nimport type { FormField, ValidationError, FormFieldType } from '../types';\r\nimport { isValidISODate } from '../utils/date-validation';\r\n\r\n/**\r\n * Hook to manage form field state and validation\r\n */\r\nexport function useFormFields(fields: FormField[] = []) {\r\n const [fieldValues, setFieldValues] = useState<Record<string, string>>({});\r\n const [errors, setErrors] = useState<ValidationError[]>([]);\r\n const [touched, setTouched] = useState<Record<string, boolean>>({});\r\n\r\n const updateField = useCallback((fieldId: string, value: string) => {\r\n setFieldValues((prev) => ({\r\n ...prev,\r\n [fieldId]: value,\r\n }));\r\n // Mark field as touched\r\n setTouched((prev) => ({\r\n ...prev,\r\n [fieldId]: true,\r\n }));\r\n // Clear error for this field when value is updated\r\n setErrors((prev) => prev.filter((err) => err.field !== fieldId));\r\n }, []);\r\n\r\n const updateMultipleFields = useCallback((values: Record<string, string>) => {\r\n setFieldValues((prev) => ({\r\n ...prev,\r\n ...values,\r\n }));\r\n // Mark all updated fields as touched\r\n const touchedFields = Object.keys(values).reduce((acc, key) => {\r\n acc[key] = true;\r\n return acc;\r\n }, {} as Record<string, boolean>);\r\n setTouched((prev) => ({\r\n ...prev,\r\n ...touchedFields,\r\n }));\r\n // Clear errors for updated fields\r\n const updatedFieldIds = Object.keys(values);\r\n setErrors((prev) => prev.filter((err) => !updatedFieldIds.includes(err.field)));\r\n }, []);\r\n\r\n const validateField = useCallback(\r\n (fieldId: string) => {\r\n const field = fields.find((f) => f.id === fieldId);\r\n if (!field) return true;\r\n\r\n const value = fieldValues[fieldId];\r\n const newErrors = errors.filter((e) => e.field !== fieldId);\r\n\r\n if (field.required) {\r\n if (!value || value.trim() === '') {\r\n newErrors.push({\r\n field: fieldId,\r\n message: `${field.label || field.name} is required`,\r\n });\r\n }\r\n }\r\n\r\n // Additional validation for specific field types\r\n if (value && field.maxLength && value.length > field.maxLength) {\r\n newErrors.push({\r\n field: fieldId,\r\n message: `${field.label || field.name} must be at most ${field.maxLength} characters`,\r\n });\r\n }\r\n\r\n // Date validation\r\n if (value && field.type === ('date' as FormFieldType)) {\r\n if (!isValidISODate(value)) {\r\n newErrors.push({\r\n field: fieldId,\r\n message: 'Please enter a valid date',\r\n });\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return newErrors.length === errors.length - newErrors.filter((e) => e.field === fieldId).length;\r\n },\r\n [fields, fieldValues, errors]\r\n );\r\n\r\n const validateFields = useCallback(\r\n (signatures?: Record<string, string>) => {\r\n const newErrors: ValidationError[] = [];\r\n\r\n for (const field of fields) {\r\n if (field.required) {\r\n const value = fieldValues[field.id];\r\n \r\n // Check signature fields separately\r\n if (\r\n (field.type === 'signature' as FormFieldType || field.type === 'initials' as FormFieldType) &&\r\n signatures\r\n ) {\r\n if (!signatures[field.id]) {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${field.label || field.name} is required`,\r\n });\r\n }\r\n } else if (!value || value.trim() === '') {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${field.label || field.name} is required`,\r\n });\r\n }\r\n }\r\n\r\n // Validate maxLength\r\n const value = fieldValues[field.id];\r\n if (value && field.maxLength && value.length > field.maxLength) {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${field.label || field.name} must be at most ${field.maxLength} characters`,\r\n });\r\n }\r\n\r\n // Date validation\r\n if (value && field.type === ('date' as FormFieldType)) {\r\n if (!isValidISODate(value)) {\r\n newErrors.push({\r\n field: field.id,\r\n message: 'Please enter a valid date',\r\n });\r\n }\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return newErrors.length === 0;\r\n },\r\n [fields, fieldValues]\r\n );\r\n\r\n const resetFields = useCallback(() => {\r\n setFieldValues({});\r\n setErrors([]);\r\n setTouched({});\r\n }, []);\r\n\r\n const resetValidation = useCallback(() => {\r\n setErrors([]);\r\n }, []);\r\n\r\n const getFieldValue = useCallback(\r\n (fieldId: string) => {\r\n return fieldValues[fieldId] || '';\r\n },\r\n [fieldValues]\r\n );\r\n\r\n const getFieldError = useCallback(\r\n (fieldId: string) => {\r\n const error = errors.find((e) => e.field === fieldId);\r\n return error?.message;\r\n },\r\n [errors]\r\n );\r\n\r\n const isFieldTouched = useCallback(\r\n (fieldId: string) => {\r\n return touched[fieldId] || false;\r\n },\r\n [touched]\r\n );\r\n\r\n const setFieldValue = updateField; // Alias for consistency\r\n const setMultipleFieldValues = updateMultipleFields; // Alias for consistency\r\n const clearFields = resetFields; // Alias for consistency\r\n\r\n const hasErrors = errors.length > 0;\r\n\r\n return {\r\n fieldValues,\r\n errors,\r\n hasErrors,\r\n touched,\r\n updateField,\r\n updateMultipleFields,\r\n validateField,\r\n validateFields,\r\n resetFields,\r\n resetValidation,\r\n getFieldValue,\r\n getFieldError,\r\n isFieldTouched,\r\n // Aliases\r\n setFieldValue,\r\n setMultipleFieldValues,\r\n clearFields,\r\n };\r\n}\r\n\r\n","import { useRef, useState, useCallback } from 'react';\r\nimport type { SignatureCanvasRef } from '../types';\r\n\r\n/**\r\n * Hook to manage signature capture state and operations\r\n */\r\nexport function useSignatureCapture() {\r\n const canvasRef = useRef<SignatureCanvasRef>(null);\r\n const [signatureDataUrl, setSignatureDataUrl] = useState<string | null>(null);\r\n const [uploadedImage, setUploadedImage] = useState<string | null>(null);\r\n const [uploadError, setUploadError] = useState<string | null>(null);\r\n\r\n const clear = useCallback(() => {\r\n canvasRef.current?.clear();\r\n setSignatureDataUrl(null);\r\n }, []);\r\n\r\n const saveSignature = useCallback(() => {\r\n const dataUrl = canvasRef.current?.getSignatureDataUrl();\r\n if (dataUrl) {\r\n setSignatureDataUrl(dataUrl);\r\n return dataUrl;\r\n }\r\n return null;\r\n }, []);\r\n\r\n const isEmpty = useCallback(() => {\r\n return canvasRef.current?.isEmpty() ?? true;\r\n }, []);\r\n\r\n const handleFileUpload = useCallback((file: File) => {\r\n setUploadError(null);\r\n\r\n // Validate file type\r\n const allowedTypes = ['image/png', 'image/jpeg', 'image/jpg'];\r\n if (!allowedTypes.includes(file.type.toLowerCase())) {\r\n setUploadError('Please upload a PNG or JPEG image file.');\r\n return;\r\n }\r\n\r\n // Validate file size (max 5MB)\r\n const maxSizeInBytes = 5 * 1024 * 1024;\r\n if (file.size > maxSizeInBytes) {\r\n setUploadError('File size must be less than 5MB. Please choose a smaller image.');\r\n return;\r\n }\r\n\r\n const reader = new FileReader();\r\n reader.onload = (event) => {\r\n if (typeof event.target?.result === 'string') {\r\n setUploadedImage(event.target.result);\r\n setSignatureDataUrl(event.target.result);\r\n setUploadError(null);\r\n }\r\n };\r\n reader.onerror = () => {\r\n setUploadError('Failed to read the image file. Please try again.');\r\n };\r\n reader.readAsDataURL(file);\r\n }, []);\r\n\r\n const clearUpload = useCallback(() => {\r\n setUploadedImage(null);\r\n setUploadError(null);\r\n setSignatureDataUrl(null);\r\n }, []);\r\n\r\n const reset = useCallback(() => {\r\n clear();\r\n clearUpload();\r\n }, [clear, clearUpload]);\r\n\r\n return {\r\n canvasRef,\r\n signatureDataUrl,\r\n uploadedImage,\r\n uploadError,\r\n clear,\r\n saveSignature,\r\n isEmpty,\r\n handleFileUpload,\r\n clearUpload,\r\n reset,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook to manage signature and initials state\r\n */\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport type { FormField, FormFieldType } from '../types';\r\n\r\nexport interface SignatureData {\r\n [fieldId: string]: string; // Base64 data URL\r\n}\r\n\r\n/**\r\n * Hook for managing signatures and initials\r\n */\r\nexport function useSignatures() {\r\n const [signatures, setSignatures] = useState<SignatureData>({});\r\n\r\n // State for collected signatures (for auto-placement)\r\n const [collectedSignature, setCollectedSignature] = useState<string | null>(null);\r\n const [collectedInitials, setCollectedInitials] = useState<string | null>(null);\r\n\r\n /**\r\n * Add or update a signature for a field\r\n */\r\n const setSignature = useCallback((fieldId: string, dataUrl: string) => {\r\n setSignatures((prev) => ({\r\n ...prev,\r\n [fieldId]: dataUrl,\r\n }));\r\n }, []);\r\n\r\n /**\r\n * Remove a signature for a field\r\n */\r\n const clearSignature = useCallback((fieldId: string) => {\r\n setSignatures((prev) => {\r\n const newSignatures = { ...prev };\r\n delete newSignatures[fieldId];\r\n return newSignatures;\r\n });\r\n }, []);\r\n\r\n /**\r\n * Clear all signatures\r\n */\r\n const clearAllSignatures = useCallback(() => {\r\n setSignatures({});\r\n }, []);\r\n\r\n /**\r\n * Check if a field has a signature\r\n */\r\n const hasSignature = useCallback(\r\n (fieldId: string) => {\r\n return !!signatures[fieldId];\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Get signature data URL for a field\r\n */\r\n const getSignature = useCallback(\r\n (fieldId: string) => {\r\n return signatures[fieldId] || null;\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Validate that all required signature fields have signatures\r\n */\r\n const validateSignatures = useCallback(\r\n (fields: FormField[], currentSignatures?: SignatureData) => {\r\n const signaturesToCheck = currentSignatures ?? signatures;\r\n const errors: string[] = [];\r\n\r\n for (const field of fields) {\r\n if (field.required && (field.type === 'signature' as FormFieldType || field.type === 'initials' as FormFieldType)) {\r\n if (!signaturesToCheck[field.id]) {\r\n errors.push(`${field.label || field.name} is required`);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n };\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Get count of signatures\r\n */\r\n const signatureCount = Object.keys(signatures).length;\r\n\r\n /**\r\n * Check if any signatures exist\r\n */\r\n const hasAnySignatures = signatureCount > 0;\r\n\r\n /**\r\n * Collect a signature or initials for auto-placement\r\n */\r\n const collectSignature = useCallback((type: 'signature' | 'initials', dataUrl: string) => {\r\n if (type === 'signature') {\r\n setCollectedSignature(dataUrl);\r\n } else {\r\n setCollectedInitials(dataUrl);\r\n }\r\n }, []);\r\n\r\n /**\r\n * Check if we have a collected signature or initials\r\n */\r\n const hasCollectedSignature = useCallback((type: 'signature' | 'initials'): boolean => {\r\n return type === 'signature'\r\n ? collectedSignature !== null\r\n : collectedInitials !== null;\r\n }, [collectedSignature, collectedInitials]);\r\n\r\n /**\r\n * Get the collected signature or initials\r\n */\r\n const getCollectedSignature = useCallback((type: 'signature' | 'initials'): string | null => {\r\n return type === 'signature' ? collectedSignature : collectedInitials;\r\n }, [collectedSignature, collectedInitials]);\r\n\r\n /**\r\n * Clear collected signatures\r\n */\r\n const clearCollectedSignatures = useCallback(() => {\r\n setCollectedSignature(null);\r\n setCollectedInitials(null);\r\n }, []);\r\n\r\n return {\r\n signatures,\r\n setSignature,\r\n clearSignature,\r\n clearAllSignatures,\r\n hasSignature,\r\n getSignature,\r\n validateSignatures,\r\n signatureCount,\r\n hasAnySignatures,\r\n // Auto-place functionality\r\n collectSignature,\r\n hasCollectedSignature,\r\n getCollectedSignature,\r\n clearCollectedSignatures,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook for filtering form fields by signer with multi-signer support\r\n * Implements Dockmaster's exact field visibility logic\r\n */\r\n\r\nimport { useMemo } from 'react';\r\nimport type { EsignFormField, MultiSignerContext } from '../types';\r\nimport { isFieldVisibleToSigner, filterFieldsBySigner } from '../utils/field-visibility';\r\n\r\n/**\r\n * Hook for filtering form fields based on multi-signer context\r\n * \r\n * @param allFields - All form fields extracted from the PDF\r\n * @param multiSignerContext - Multi-signer context (from useMultiSignerContext)\r\n * @returns Filtered fields and utility functions\r\n * \r\n * @example\r\n * ```tsx\r\n * const context = useMultiSignerContext(currentSigner, isMultipleSignature, totalSigners);\r\n * const { filteredFields } = useFieldFiltering(allFields, context);\r\n * ```\r\n */\r\nexport function useFieldFiltering(\r\n allFields: EsignFormField[],\r\n multiSignerContext: MultiSignerContext\r\n) {\r\n /**\r\n * Filtered fields based on Dockmaster's multi-signer visibility logic\r\n */\r\n const filteredFields = useMemo(() => {\r\n // First, hide non-main signature/initials fields from UI\r\n // EXCEPTION: Keep ALL signature/initials fields (they need visual indicators even without acknowledgements)\r\n let fields = allFields.filter((field) => {\r\n // Keep signature_field_main and initials_field_main\r\n if (field.id === 'signature_field_main' || field.id === 'initials_field_main') {\r\n return true;\r\n }\r\n\r\n // Keep ALL signature/initials fields (for acknowledgements AND visual indicators)\r\n // Previously we only kept fields with acknowledgements, but fields without acknowledgements\r\n // also need to be tracked so they can show visual indicators when signed\r\n if (field.type === 'signature' || field.type === 'initials') {\r\n return true;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n // Apply multi-signer filtering using centralized visibility logic\r\n return filterFieldsBySigner(fields, multiSignerContext);\r\n }, [allFields, multiSignerContext]);\r\n\r\n /**\r\n * Required fields from filtered set\r\n */\r\n const requiredFields = useMemo(() => {\r\n return filteredFields.filter((field) => field.required);\r\n }, [filteredFields]);\r\n\r\n /**\r\n * Optional fields from filtered set\r\n */\r\n const optionalFields = useMemo(() => {\r\n return filteredFields.filter((field) => !field.required);\r\n }, [filteredFields]);\r\n\r\n /**\r\n * Check if a field is visible to current signer\r\n * Uses the same logic as filteredFields for consistency\r\n */\r\n const isFieldVisible = (field: EsignFormField): boolean => {\r\n return isFieldVisibleToSigner(field, multiSignerContext);\r\n };\r\n\r\n return {\r\n // Filtered fields\r\n filteredFields,\r\n requiredFields,\r\n optionalFields,\r\n \r\n // Utilities\r\n isFieldVisible,\r\n \r\n // Counts\r\n totalFields: allFields.length,\r\n filteredCount: filteredFields.length,\r\n requiredCount: requiredFields.length,\r\n optionalCount: optionalFields.length,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook for managing file attachments\r\n * Handles file uploads, validation, and state management\r\n */\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport type {\r\n Attachment,\r\n AttachmentConstraints,\r\n AttachmentValidationResult,\r\n} from '../types';\r\nimport { logger, validateFile, isImageType, formatFileSize, DEFAULT_ATTACHMENT_CONSTRAINTS } from '../utils';\r\n\r\n/**\r\n * Generate a unique ID for attachments\r\n */\r\nfunction generateAttachmentId(): string {\r\n return `att_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Create a preview for image files\r\n */\r\nasync function createPreview(file: File): Promise<string | undefined> {\r\n if (!isImageType(file.type)) {\r\n return undefined;\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onload = () => resolve(reader.result as string);\r\n reader.onerror = reject;\r\n reader.readAsDataURL(file);\r\n });\r\n}\r\n\r\nexport interface UseAttachmentsOptions {\r\n constraints?: Partial<AttachmentConstraints>;\r\n onError?: (errors: string[]) => void;\r\n}\r\n\r\nexport function useAttachments(options: UseAttachmentsOptions = {}) {\r\n const [attachments, setAttachments] = useState<Attachment[]>([]);\r\n const [isUploading, setIsUploading] = useState(false);\r\n const [validationErrors, setValidationErrors] = useState<string[]>([]);\r\n\r\n const constraints: AttachmentConstraints = {\r\n ...DEFAULT_ATTACHMENT_CONSTRAINTS,\r\n ...options.constraints,\r\n };\r\n\r\n /**\r\n * Add files to attachments\r\n */\r\n const addFiles = useCallback(\r\n async (files: File[] | FileList) => {\r\n setIsUploading(true);\r\n setValidationErrors([]);\r\n\r\n const fileArray = Array.from(files);\r\n const errors: string[] = [];\r\n const newAttachments: Attachment[] = [];\r\n\r\n for (const file of fileArray) {\r\n // Validate file\r\n const validation = validateFile(file, constraints);\r\n\r\n if (!validation.valid) {\r\n errors.push(...validation.errors);\r\n continue;\r\n }\r\n \r\n // Check total constraints manually\r\n const currentTotalSize = [...attachments, ...newAttachments].reduce((sum, att) => sum + att.size, 0);\r\n if (currentTotalSize + file.size > constraints.maxTotalSize) {\r\n const maxTotalMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n errors.push(`Adding \"${file.name}\" would exceed total size limit of ${maxTotalMB}MB`);\r\n continue;\r\n }\r\n \r\n if ([...attachments, ...newAttachments].length >= constraints.maxFiles) {\r\n errors.push(`Maximum of ${constraints.maxFiles} files allowed`);\r\n continue;\r\n }\r\n\r\n // Create attachment\r\n try {\r\n const preview = await createPreview(file);\r\n const attachment: Attachment = {\r\n id: generateAttachmentId(),\r\n file,\r\n name: file.name,\r\n size: file.size,\r\n type: file.type,\r\n uploadedAt: new Date(),\r\n preview,\r\n };\r\n newAttachments.push(attachment);\r\n } catch (error) {\r\n logger.error('Error creating attachment:', error);\r\n errors.push(`Failed to process file \"${file.name}\"`);\r\n }\r\n }\r\n\r\n // Update state\r\n if (newAttachments.length > 0) {\r\n setAttachments(prev => [...prev, ...newAttachments]);\r\n }\r\n\r\n if (errors.length > 0) {\r\n setValidationErrors(errors);\r\n options.onError?.(errors);\r\n }\r\n\r\n setIsUploading(false);\r\n\r\n return {\r\n added: newAttachments.length,\r\n errors,\r\n };\r\n },\r\n [attachments, constraints, options]\r\n );\r\n\r\n /**\r\n * Remove an attachment by ID\r\n */\r\n const removeAttachment = useCallback((attachmentId: string) => {\r\n setAttachments(prev => prev.filter(att => att.id !== attachmentId));\r\n setValidationErrors([]);\r\n }, []);\r\n\r\n /**\r\n * Clear all attachments\r\n */\r\n const clearAttachments = useCallback(() => {\r\n setAttachments([]);\r\n setValidationErrors([]);\r\n }, []);\r\n\r\n /**\r\n * Get total size of all attachments\r\n */\r\n const getTotalSize = useCallback(() => {\r\n return attachments.reduce((sum, att) => sum + att.size, 0);\r\n }, [attachments]);\r\n\r\n /**\r\n * Format bytes to human-readable string\r\n */\r\n const formatSize = useCallback((bytes: number): string => {\r\n return formatFileSize(bytes);\r\n }, []);\r\n\r\n /**\r\n * Validate all current attachments\r\n */\r\n const validateAll = useCallback((): AttachmentValidationResult => {\r\n const errors: string[] = [];\r\n\r\n // Check total size\r\n const totalSize = getTotalSize();\r\n if (totalSize > constraints.maxTotalSize) {\r\n const maxTotalMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n errors.push(`Total file size (${formatSize(totalSize)}) exceeds ${maxTotalMB}MB limit`);\r\n }\r\n\r\n // Check number of files\r\n if (attachments.length > constraints.maxFiles) {\r\n errors.push(`Maximum of ${constraints.maxFiles} files allowed (currently ${attachments.length})`);\r\n }\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n };\r\n }, [attachments, constraints, getTotalSize, formatSize]);\r\n\r\n return {\r\n // State\r\n attachments,\r\n isUploading,\r\n validationErrors,\r\n constraints,\r\n\r\n // Actions\r\n addFiles,\r\n removeAttachment,\r\n clearAttachments,\r\n\r\n // Utilities\r\n getTotalSize,\r\n formatSize,\r\n validateAll,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook for managing multi-signer context and determining signer roles\r\n */\r\n\r\nimport { useMemo } from 'react';\r\nimport type { Signer, MultiSignerContext } from '../types';\r\n\r\n/**\r\n * Calculate multi-signer context from simplified props\r\n * \r\n * @param currentSigner - The signer who is currently viewing/signing (if multi-signer)\r\n * @param isMultipleSignature - Whether this is a multi-signer document\r\n * @param totalSigners - Total number of signers (for determining if current is final)\r\n * @returns MultiSignerContext with calculated roles and flags\r\n * \r\n * @example\r\n * ```tsx\r\n * const context = useMultiSignerContext(\r\n * { id: '1', email: 'user@example.com', name: 'John', signOrder: 1, status: 'pending' },\r\n * true,\r\n * 3\r\n * );\r\n * // context.isPrimarySigner === true (signOrder === 1)\r\n * // context.isFinalSigner === false (signOrder !== totalSigners)\r\n * ```\r\n */\r\nexport function useMultiSignerContext(\r\n currentSigner?: Signer,\r\n isMultipleSignature?: boolean,\r\n totalSigners?: number\r\n): MultiSignerContext {\r\n return useMemo(() => {\r\n // Single signer mode (default)\r\n if (!isMultipleSignature || !currentSigner) {\r\n return {\r\n isMultiSigner: false,\r\n currentSigner: null,\r\n currentSignerEmail: '',\r\n isPrimarySigner: false,\r\n isFinalSigner: false,\r\n };\r\n }\r\n \r\n // Multi-signer mode - calculate roles based on signOrder\r\n const isPrimarySigner = currentSigner.signOrder === 1;\r\n \r\n // If totalSigners is provided, check if current signer is the last one\r\n // If not provided, assume current signer is final (safe default)\r\n const isFinalSigner = totalSigners \r\n ? currentSigner.signOrder === totalSigners \r\n : true;\r\n \r\n \r\n return {\r\n isMultiSigner: true,\r\n currentSigner,\r\n currentSignerEmail: currentSigner.email,\r\n isPrimarySigner,\r\n isFinalSigner,\r\n };\r\n }, [currentSigner, isMultipleSignature, totalSigners]);\r\n}\r\n\r\n","import { useState, useCallback, useMemo } from 'react';\r\nimport type { EsignFormField, Acknowledgement } from '../types';\r\n\r\ninterface AcknowledgementProgress {\r\n current: number;\r\n total: number;\r\n}\r\n\r\ninterface UnacknowledgedFieldDetail {\r\n field: EsignFormField;\r\n unacknowledgedItems: Acknowledgement[];\r\n}\r\n\r\ninterface UseAcknowledgementsReturn {\r\n acknowledgeItem: (fieldId: string, ackId: string) => void;\r\n isAcknowledged: (fieldId: string, ackId?: string) => boolean;\r\n isFieldFullyAcknowledged: (fieldId: string) => boolean;\r\n getFieldAcknowledgementProgress: (fieldId: string) => AcknowledgementProgress;\r\n acknowledgeAllForField: (fieldId: string) => void;\r\n getFieldsWithAcknowledgements: (fields: EsignFormField[]) => EsignFormField[];\r\n hasUnacknowledgedFields: (fields: EsignFormField[]) => boolean;\r\n getUnacknowledgedFields: (fields: EsignFormField[]) => EsignFormField[];\r\n getUnacknowledgedFieldsDetailed: (fields: EsignFormField[]) => UnacknowledgedFieldDetail[];\r\n resetAcknowledgements: () => void;\r\n}\r\n\r\n/**\r\n * Hook for managing acknowledgement state across form fields\r\n * \r\n * Tracks which acknowledgements have been accepted by the signer.\r\n * Acknowledgements are field-level requirements that must be explicitly\r\n * accepted before the field can be interacted with or submitted.\r\n * \r\n * State is stored in memory and resets on component unmount/page refresh.\r\n * \r\n * @param fields - Array of form fields that may contain acknowledgements\r\n * @returns Object with acknowledgement state management functions\r\n * \r\n * @example\r\n * ```tsx\r\n * const {\r\n * acknowledgeItem,\r\n * isFieldFullyAcknowledged,\r\n * hasUnacknowledgedFields\r\n * } = useAcknowledgements(fields);\r\n * \r\n * // Check if field can be submitted\r\n * if (hasUnacknowledgedFields(fields)) {\r\n * // Show acknowledgement modal\r\n * }\r\n * ```\r\n */\r\nexport function useAcknowledgements(\r\n fields: EsignFormField[]\r\n): UseAcknowledgementsReturn {\r\n // Map of fieldId -> Set of acknowledged acknowledgement IDs\r\n const [acknowledgedMap, setAcknowledgedMap] = useState<Map<string, Set<string>>>(\r\n new Map()\r\n );\r\n\r\n // Get all fields that have acknowledgements\r\n const getFieldsWithAcknowledgements = useCallback((fieldsToFilter: EsignFormField[]) => {\r\n return fieldsToFilter.filter(\r\n field => field.acknowledgements && field.acknowledgements.length > 0\r\n );\r\n }, []);\r\n\r\n // Acknowledge a specific acknowledgement item for a field\r\n const acknowledgeItem = useCallback((fieldId: string, ackId: string) => {\r\n setAcknowledgedMap(prev => {\r\n const newMap = new Map(prev);\r\n const fieldAcks = newMap.get(fieldId) || new Set<string>();\r\n fieldAcks.add(ackId);\r\n newMap.set(fieldId, fieldAcks);\r\n return newMap;\r\n });\r\n }, []);\r\n\r\n // Check if a specific acknowledgement or all acknowledgements are acknowledged\r\n const isAcknowledged = useCallback((fieldId: string, ackId?: string) => {\r\n const fieldAcks = acknowledgedMap.get(fieldId);\r\n if (!fieldAcks) return false;\r\n \r\n if (ackId) {\r\n return fieldAcks.has(ackId);\r\n }\r\n \r\n // If no ackId provided, check if any are acknowledged\r\n return fieldAcks.size > 0;\r\n }, [acknowledgedMap]);\r\n\r\n // Check if all acknowledgements for a field are acknowledged\r\n const isFieldFullyAcknowledged = useCallback((fieldId: string) => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements || field.acknowledgements.length === 0) {\r\n return true; // No acknowledgements means fully acknowledged\r\n }\r\n\r\n const fieldAcks = acknowledgedMap.get(fieldId);\r\n if (!fieldAcks) return false;\r\n\r\n return field.acknowledgements.every(ack => fieldAcks.has(ack.id));\r\n }, [fields, acknowledgedMap]);\r\n\r\n // Get acknowledgement progress for a field\r\n const getFieldAcknowledgementProgress = useCallback((fieldId: string): AcknowledgementProgress => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements || field.acknowledgements.length === 0) {\r\n return { current: 0, total: 0 };\r\n }\r\n\r\n const fieldAcks = acknowledgedMap.get(fieldId) || new Set<string>();\r\n return {\r\n current: fieldAcks.size,\r\n total: field.acknowledgements.length\r\n };\r\n }, [fields, acknowledgedMap]);\r\n\r\n // Acknowledge all acknowledgements for a field\r\n const acknowledgeAllForField = useCallback((fieldId: string) => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements) return;\r\n\r\n setAcknowledgedMap(prev => {\r\n const newMap = new Map(prev);\r\n const allAckIds = new Set(field.acknowledgements!.map(ack => ack.id));\r\n newMap.set(fieldId, allAckIds);\r\n return newMap;\r\n });\r\n }, [fields]);\r\n\r\n // Check if there are any unacknowledged fields\r\n const hasUnacknowledgedFields = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n const fieldsWithAcks = getFieldsWithAcknowledgements(fieldsToCheck);\r\n return fieldsWithAcks.some(field => !isFieldFullyAcknowledged(field.id));\r\n }, [getFieldsWithAcknowledgements, isFieldFullyAcknowledged]);\r\n\r\n // Get list of fields that have unacknowledged items\r\n const getUnacknowledgedFields = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n const fieldsWithAcks = getFieldsWithAcknowledgements(fieldsToCheck);\r\n return fieldsWithAcks.filter(field => !isFieldFullyAcknowledged(field.id));\r\n }, [getFieldsWithAcknowledgements, isFieldFullyAcknowledged]);\r\n\r\n // Get detailed information about fields with unacknowledged items\r\n const getUnacknowledgedFieldsDetailed = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n return fieldsToCheck\r\n .filter(field => field.acknowledgements && field.acknowledgements.length > 0)\r\n .map(field => ({\r\n field,\r\n unacknowledgedItems: field.acknowledgements!.filter(\r\n ack => !isAcknowledged(field.id, ack.id)\r\n )\r\n }))\r\n .filter(({ unacknowledgedItems }) => unacknowledgedItems.length > 0);\r\n }, [isAcknowledged]);\r\n\r\n // Reset all acknowledgements (for testing or form reset)\r\n const resetAcknowledgements = useCallback(() => {\r\n setAcknowledgedMap(new Map());\r\n }, []);\r\n\r\n return {\r\n acknowledgeItem,\r\n isAcknowledged,\r\n isFieldFullyAcknowledged,\r\n getFieldAcknowledgementProgress,\r\n acknowledgeAllForField,\r\n getFieldsWithAcknowledgements,\r\n hasUnacknowledgedFields,\r\n getUnacknowledgedFields,\r\n getUnacknowledgedFieldsDetailed,\r\n resetAcknowledgements,\r\n };\r\n}\r\n\r\n"]}
1
+ {"version":3,"sources":["../../src/utils/logger.ts","../../src/utils/pdf-validators.ts","../../src/utils/pdf-helpers.ts","../../src/utils/pdf-metadata.ts","../../src/utils/pdf-lib-loader.ts","../../src/utils/field-visibility.ts","../../src/utils/pdf-widget-helpers.ts","../../src/utils/pdf-field-type-helpers.ts","../../src/utils/pdf-manipulation.ts","../../src/utils/field-extraction.ts","../../src/utils/pdfjs-config.ts","../../src/utils/errors.ts","../../src/utils/attachment-validators.ts","../../src/utils/date-validation-iso.ts","../../src/utils/pdf-viewer-filter.ts","../../src/hooks/usePdfViewer.ts","../../src/hooks/useFormFields.ts","../../src/hooks/useSignatureCapture.ts","../../src/hooks/useSignatures.ts","../../src/hooks/useFieldFiltering.ts","../../src/hooks/useAttachments.ts","../../src/hooks/useMultiSignerContext.ts","../../src/hooks/useAcknowledgements.ts"],"names":["f","PDFName","isValidDate","PDFDocument","rgb","useState","useRef","useCallback","value","validateSignatures","useMemo","useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * Logger Utility\r\n * Centralized logging system with environment-based log level control\r\n */\r\n\r\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\ninterface Logger {\r\n debug(message: string, ...args: unknown[]): void;\r\n info(message: string, ...args: unknown[]): void;\r\n warn(message: string, ...args: unknown[]): void;\r\n error(message: string, ...args: unknown[]): void;\r\n}\r\n\r\n/**\r\n * Determines if the current environment is production\r\n */\r\nfunction isProduction(): boolean {\r\n return typeof process !== 'undefined' && process.env.NODE_ENV === 'production';\r\n}\r\n\r\n/**\r\n * Creates a formatted log prefix\r\n */\r\nfunction createPrefix(level: LogLevel): string {\r\n return `[@signiphi/pdf-signer] [${level.toUpperCase()}]`;\r\n}\r\n\r\n/**\r\n * Creates the logger instance with environment-based behavior\r\n */\r\nfunction createLogger(): Logger {\r\n const isProd = isProduction();\r\n\r\n return {\r\n debug(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.log(createPrefix('debug'), message, ...args);\r\n }\r\n },\r\n\r\n info(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.log(createPrefix('info'), message, ...args);\r\n }\r\n },\r\n\r\n warn(message: string, ...args: unknown[]): void {\r\n if (!isProd) {\r\n console.warn(createPrefix('warn'), message, ...args);\r\n }\r\n },\r\n\r\n error(message: string, ...args: unknown[]): void {\r\n // Errors are shown in both development and production\r\n console.error(createPrefix('error'), message, ...args);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Singleton logger instance\r\n */\r\nexport const logger = createLogger();\r\n\r\n\r\n\r\n","/**\r\n * PDF Validation Utilities\r\n * Common validation functions used across the package\r\n */\r\n\r\nimport type { FormField } from '../types';\r\n\r\n/**\r\n * Validate that bytes represent a valid PDF file\r\n * \r\n * Checks for:\r\n * - Non-empty bytes\r\n * - Valid PDF header (%PDF-)\r\n * \r\n * @param pdfBytes - The PDF bytes to validate\r\n * @returns Validation result with valid flag and optional error message\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validatePdfBytes(pdfBytes);\r\n * if (!result.valid) {\r\n * console.error(result.error);\r\n * return;\r\n * }\r\n * ```\r\n */\r\nexport function validatePdfBytes(pdfBytes: Uint8Array): { \r\n valid: boolean; \r\n error?: string \r\n} {\r\n // Check for empty bytes\r\n if (!pdfBytes || pdfBytes.length === 0) {\r\n return { \r\n valid: false, \r\n error: 'PDF bytes are empty' \r\n };\r\n }\r\n \r\n // Check for valid PDF header\r\n const header = new TextDecoder().decode(pdfBytes.slice(0, 12));\r\n if (!header.startsWith('%PDF-')) {\r\n return { \r\n valid: false, \r\n error: 'Invalid PDF format: Missing PDF header' \r\n };\r\n }\r\n \r\n return { valid: true };\r\n}\r\n\r\n/**\r\n * Check if a label is auto-generated (not user-typed)\r\n *\r\n * Auto-generated labels include:\r\n * - Simple type names: \"Text\", \"Signature\", etc.\r\n * - Type + timestamp: \"Dropdown 12413423423\", \"Text 1768236803505\"\r\n * - Pure timestamps: \"12413423423\"\r\n * - Type + numbers: \"Dropdown1\", \"Text_2\"\r\n *\r\n * These are default labels assigned by the form builder and should not be\r\n * displayed to users in the same way as custom labels.\r\n *\r\n * Works identically in both single-signer and multi-signer flows.\r\n *\r\n * @param label - The label to check\r\n * @returns true if the label is auto-generated, false if it's a custom user label\r\n *\r\n * @example\r\n * ```ts\r\n * isAutoGeneratedLabel('Signature') // true\r\n * isAutoGeneratedLabel('Dropdown 12413423423') // true\r\n * isAutoGeneratedLabel('Sign here please') // false\r\n * isAutoGeneratedLabel('') // true\r\n * ```\r\n */\r\nexport function isAutoGeneratedLabel(label: string): boolean {\r\n if (!label || !label.trim()) return true;\r\n\r\n const trimmed = label.trim();\r\n\r\n const autoLabels = [\r\n 'Signature',\r\n 'Initials',\r\n 'Date',\r\n 'Text',\r\n 'Checkbox',\r\n 'Dropdown',\r\n 'Option',\r\n 'Radio',\r\n ];\r\n\r\n // Check for simple type names\r\n if (autoLabels.includes(trimmed)) return true;\r\n\r\n // Check for pure timestamps (10+ digit numbers)\r\n if (/^\\d{10,}$/.test(trimmed)) return true;\r\n\r\n // Check for type + timestamp pattern: \"Dropdown 12413423423\" or \"Text_1768236803505\"\r\n const typeTimestampPattern = new RegExp(\r\n `^(${autoLabels.join('|')})[\\\\s_-]?\\\\d{10,}$`,\r\n 'i'\r\n );\r\n if (typeTimestampPattern.test(trimmed)) return true;\r\n\r\n // Check for type + short number: \"Dropdown1\", \"Text_2\", \"Signature 3\"\r\n const typeNumberPattern = new RegExp(\r\n `^(${autoLabels.join('|')})[\\\\s_-]?\\\\d{1,3}$`,\r\n 'i'\r\n );\r\n if (typeNumberPattern.test(trimmed)) return true;\r\n\r\n // Check for corrupted labels with repeated type words: \"Date 1767730185976 Date Date Date...\"\r\n // These occur when PDFs are saved multiple times and field names get concatenated\r\n const typeWordsJoined = autoLabels.join('|');\r\n const corruptedPattern = new RegExp(\r\n `^(${typeWordsJoined})[\\\\s_-]?\\\\d{10,}[\\\\s_-]?(${typeWordsJoined})+`,\r\n 'i'\r\n );\r\n if (corruptedPattern.test(trimmed)) return true;\r\n\r\n // Check for labels that are just repeated type words: \"Date Date Date\" or \"Signature Signature\"\r\n const repeatedTypePattern = new RegExp(\r\n `^((${typeWordsJoined})[\\\\s_-]+)+(${typeWordsJoined})$`,\r\n 'i'\r\n );\r\n if (repeatedTypePattern.test(trimmed)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if a field has a drawable label (user-set custom label that should be rendered on the PDF)\r\n *\r\n * Returns false when:\r\n * - Label is empty or whitespace\r\n * - Label was auto-generated from field name during extraction (isLabelAutoGenerated flag)\r\n * - Label matches known auto-generated patterns (e.g., \"Text\", \"Signature 1\")\r\n *\r\n * @param field - Object with label and optional isLabelAutoGenerated flag\r\n * @returns true if the label should be drawn on the PDF\r\n */\r\nexport function hasDrawableLabel(field: { label?: string; isLabelAutoGenerated?: boolean }): boolean {\r\n if (!field.label || !field.label.trim()) return false;\r\n if (field.isLabelAutoGenerated) return false;\r\n if (isAutoGeneratedLabel(field.label)) return false;\r\n return true;\r\n}\r\n\r\n/**\r\n * Get a user-friendly display name for a field\r\n *\r\n * If the label is meaningful (not auto-generated), returns the label.\r\n * Otherwise, returns a clean field type name.\r\n *\r\n * @param field - Object with label and type properties\r\n * @returns A user-friendly name for display in error messages\r\n */\r\nexport function getFieldDisplayName(field: { label?: string; type?: string; name?: string }): string {\r\n // If label exists and is not auto-generated, use it\r\n if (field.label && !isAutoGeneratedLabel(field.label)) {\r\n return field.label;\r\n }\r\n\r\n // Map field types to friendly names\r\n const typeNames: Record<string, string> = {\r\n 'text': 'Text field',\r\n 'signature': 'Signature',\r\n 'initials': 'Initials',\r\n 'date': 'Date field',\r\n 'checkbox': 'Checkbox',\r\n 'dropdown': 'Dropdown',\r\n 'radio': 'Radio selection',\r\n 'radiogroup': 'Radio selection',\r\n 'text_label': 'Text label',\r\n };\r\n\r\n if (field.type) {\r\n const typeName = typeNames[field.type.toLowerCase()];\r\n if (typeName) {\r\n return typeName;\r\n }\r\n }\r\n\r\n // Fallback: clean up the field name\r\n if (field.name) {\r\n // Remove timestamps and clean up\r\n let cleaned = field.name\r\n .replace(/_?(signature|initials|date)$/i, '') // Remove type suffixes\r\n .replace(/[_-]\\d{10,}$/, '') // Remove timestamps\r\n .replace(/[_-]/g, ' ') // Replace separators with spaces\r\n .trim();\r\n\r\n if (cleaned && !isAutoGeneratedLabel(cleaned)) {\r\n return cleaned.replace(/\\b\\w/g, l => l.toUpperCase()); // Title case\r\n }\r\n }\r\n\r\n return 'This field';\r\n}\r\n\r\n/**\r\n * Validate field values object\r\n * \r\n * Checks that the values object is properly formatted and contains\r\n * only string values for field IDs.\r\n * \r\n * @param values - Field values to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFieldValues({ field1: 'value1', field2: 'value2' });\r\n * if (!result.valid) {\r\n * console.error('Validation errors:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFieldValues(values: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if values is an object\r\n if (!values || typeof values !== 'object') {\r\n errors.push('Field values must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n // Check each value is a string\r\n const valuesObj = values as Record<string, unknown>;\r\n for (const [key, value] of Object.entries(valuesObj)) {\r\n if (typeof value !== 'string') {\r\n errors.push(`Field value for \"${key}\" must be a string, got ${typeof value}`);\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate signatures object\r\n * \r\n * Checks that signatures are properly formatted data URLs.\r\n * \r\n * @param signatures - Signatures to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateSignatures({\r\n * sig1: 'data:image/png;base64,iVBORw0KG...',\r\n * sig2: 'data:image/png;base64,iVBORw0KG...'\r\n * });\r\n * if (!result.valid) {\r\n * console.error('Invalid signatures:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateSignatures(signatures: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if signatures is an object\r\n if (!signatures || typeof signatures !== 'object') {\r\n errors.push('Signatures must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n // Check each signature is a valid data URL\r\n const sigsObj = signatures as Record<string, unknown>;\r\n for (const [key, value] of Object.entries(sigsObj)) {\r\n if (typeof value !== 'string') {\r\n errors.push(`Signature for \"${key}\" must be a string, got ${typeof value}`);\r\n continue;\r\n }\r\n \r\n // Validate data URL format\r\n if (!value.startsWith('data:image/')) {\r\n errors.push(`Signature for \"${key}\" must be a data URL starting with \"data:image/\"`);\r\n }\r\n \r\n // Check for base64 data\r\n const parts = value.split(',');\r\n if (parts.length !== 2 || !parts[1]) {\r\n errors.push(`Signature for \"${key}\" has invalid data URL format (missing base64 data)`);\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate a form field definition\r\n * \r\n * Checks that a field has all required properties and they are valid.\r\n * \r\n * @param field - Form field to validate\r\n * @returns Validation result with valid flag and errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFormField({\r\n * id: 'field1',\r\n * name: 'firstName',\r\n * type: FormFieldType.TEXT,\r\n * label: 'First Name',\r\n * position: { x: 100, y: 200, width: 150, height: 30, page: 1 },\r\n * required: true\r\n * });\r\n * if (!result.valid) {\r\n * console.error('Field validation errors:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFormField(field: unknown): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n \r\n // Check if field is an object\r\n if (!field || typeof field !== 'object') {\r\n errors.push('Form field must be an object');\r\n return { valid: false, errors };\r\n }\r\n \r\n const f = field as Partial<FormField>;\r\n \r\n // Required properties\r\n if (!f.id || typeof f.id !== 'string') {\r\n errors.push('Field must have a valid \"id\" string');\r\n }\r\n \r\n if (!f.type || typeof f.type !== 'string') {\r\n errors.push('Field must have a valid \"type\" string');\r\n }\r\n \r\n if (!f.name || typeof f.name !== 'string') {\r\n errors.push('Field must have a valid \"name\" string');\r\n }\r\n \r\n if (!f.label || typeof f.label !== 'string') {\r\n errors.push('Field must have a valid \"label\" string');\r\n }\r\n \r\n // Validate position\r\n if (!f.position || typeof f.position !== 'object') {\r\n errors.push('Field must have a valid \"position\" object');\r\n } else {\r\n const pos = f.position;\r\n if (typeof pos.x !== 'number') {\r\n errors.push('Field position must have a numeric \"x\" coordinate');\r\n }\r\n if (typeof pos.y !== 'number') {\r\n errors.push('Field position must have a numeric \"y\" coordinate');\r\n }\r\n if (typeof pos.width !== 'number' || pos.width <= 0) {\r\n errors.push('Field position must have a positive \"width\"');\r\n }\r\n if (typeof pos.height !== 'number' || pos.height <= 0) {\r\n errors.push('Field position must have a positive \"height\"');\r\n }\r\n if (typeof pos.page !== 'number' || pos.page < 1) {\r\n errors.push('Field position must have a valid \"page\" number (1-indexed)');\r\n }\r\n }\r\n \r\n if (typeof f.required !== 'boolean') {\r\n errors.push('Field must have a boolean \"required\" property');\r\n }\r\n \r\n // Optional properties validation\r\n if (f.fontSize !== undefined && (typeof f.fontSize !== 'number' || f.fontSize < 8 || f.fontSize > 72)) {\r\n errors.push('Field fontSize must be a number between 8 and 72');\r\n }\r\n \r\n if (f.maxLength !== undefined && (typeof f.maxLength !== 'number' || f.maxLength <= 0)) {\r\n errors.push('Field maxLength must be a positive number');\r\n }\r\n \r\n if (f.options !== undefined && !Array.isArray(f.options)) {\r\n errors.push('Field options must be an array');\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate PDF URL format\r\n * \r\n * Accepts absolute URLs, relative paths, and data URLs.\r\n * \r\n * @param url - URL to validate\r\n * @returns Validation result with valid flag and optional error message\r\n * \r\n * @example\r\n * ```ts\r\n * // Absolute URLs\r\n * validatePdfUrl('https://example.com/document.pdf'); // valid\r\n * validatePdfUrl('http://localhost:3000/doc.pdf'); // valid\r\n * \r\n * // Relative paths\r\n * validatePdfUrl('/public/document.pdf'); // valid\r\n * validatePdfUrl('./document.pdf'); // valid\r\n * \r\n * // Data URLs and blobs\r\n * validatePdfUrl('data:application/pdf;base64,...'); // valid\r\n * validatePdfUrl('blob:http://localhost/...'); // valid\r\n * \r\n * // Local files\r\n * validatePdfUrl('file:///C:/path/to/file.pdf'); // valid\r\n * ```\r\n */\r\nexport function validatePdfUrl(url: unknown): {\r\n valid: boolean;\r\n error?: string;\r\n} {\r\n if (typeof url !== 'string') {\r\n return { valid: false, error: 'URL must be a string' };\r\n }\r\n \r\n if (!url || url.trim().length === 0) {\r\n return { valid: false, error: 'URL cannot be empty' };\r\n }\r\n \r\n const trimmedUrl = url.trim();\r\n \r\n // Check for absolute URLs with protocols\r\n const validPrefixes = ['http://', 'https://', 'blob:', 'data:', 'file://'];\r\n const hasValidPrefix = validPrefixes.some(prefix => trimmedUrl.startsWith(prefix));\r\n \r\n if (hasValidPrefix) {\r\n return { valid: true };\r\n }\r\n \r\n // Allow relative paths (start with / or ./ or ../)\r\n if (trimmedUrl.startsWith('/') || trimmedUrl.startsWith('./') || trimmedUrl.startsWith('../')) {\r\n return { valid: true };\r\n }\r\n \r\n // Reject URLs that look malformed\r\n return {\r\n valid: false,\r\n error: 'URL must be an absolute URL (http://, https://, blob:, data:, file://) or a relative path (/, ./, ../)',\r\n };\r\n}\r\n\r\n","/**\r\n * PDF utility helper functions\r\n */\r\n\r\nimport { logger } from \"./logger\";\r\nimport { validatePdfBytes } from \"./pdf-validators\";\r\n\r\n/**\r\n * Create a blob URL from PDF bytes for preview\r\n */\r\nexport function createPdfBlobUrl(pdfBytes: Uint8Array): string {\r\n const blob = new Blob([pdfBytes as BlobPart], { type: 'application/pdf' });\r\n return URL.createObjectURL(blob);\r\n}\r\n\r\n/**\r\n * Download PDF file\r\n */\r\nexport function downloadPdf(pdfBytes: Uint8Array, filename: string): void {\r\n const url = createPdfBlobUrl(pdfBytes);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = filename;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n}\r\n\r\n/**\r\n * Convert URL to PDF bytes\r\n * @param url - The URL to fetch the PDF from\r\n * @returns PDF bytes as Uint8Array\r\n */\r\nexport async function urlToPdfBytes(url: string): Promise<Uint8Array> {\r\n try {\r\n const response = await fetch(url);\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer();\r\n\r\n // Create a new Uint8Array and copy the data to avoid detached ArrayBuffer issues\r\n const pdfBytes = new Uint8Array(arrayBuffer.byteLength);\r\n pdfBytes.set(new Uint8Array(arrayBuffer));\r\n\r\n // Validate that we have a PDF\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n throw new Error(validation.error || 'Invalid PDF format');\r\n }\r\n\r\n return pdfBytes;\r\n } catch (error) {\r\n logger.error('Error fetching PDF from URL:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Validate that data is a valid PDF\r\n */\r\nexport function isValidPdf(pdfBytes: Uint8Array): boolean {\r\n const validation = validatePdfBytes(pdfBytes);\r\n return validation.valid;\r\n}\r\n\r\n/**\r\n * Convert base64 data URL to image bytes\r\n */\r\nexport function dataUrlToBytes(dataUrl: string): Uint8Array {\r\n const base64Data = dataUrl.split(',')[1];\r\n if (!base64Data) {\r\n throw new Error('Invalid data URL format: missing base64 data');\r\n }\r\n return Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0));\r\n}\r\n\r\n/**\r\n * Format field name for display\r\n */\r\nexport function formatFieldName(fieldName: string): string {\r\n return fieldName\r\n .replace(/[_-]/g, ' ')\r\n .replace(/\\b\\w/g, (l) => l.toUpperCase())\r\n .replace('Signature', '')\r\n .replace('Initials', '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Check if a field is a signature field\r\n */\r\nexport function isSignatureField(fieldName: string): boolean {\r\n return fieldName.toLowerCase().includes('signature');\r\n}\r\n\r\n/**\r\n * Check if a field is an initials field\r\n */\r\nexport function isInitialsField(fieldName: string): boolean {\r\n return fieldName.toLowerCase().includes('initials');\r\n}\r\n\r\n","/**\r\n * PDF Metadata Utilities\r\n * Functions for storing and retrieving Signiphi metadata in PDF documents\r\n */\r\n\r\nimport type { PDFDocument, PDFName as PDFNameType, PDFString as PDFStringType } from 'pdf-lib';\r\nimport { Acknowledgement } from '../types';\r\n\r\n// Module-level variables for pdf-lib classes (loaded dynamically)\r\nlet PDFName: typeof PDFNameType;\r\nlet PDFString: typeof PDFStringType;\r\n\r\n/**\r\n * Initialize PDF classes from dynamically loaded pdf-lib module\r\n * Must be called before using getSigniphiMetadata or setSigniphiMetadata\r\n */\r\nexport function initPdfMetadata(pdfLibModule: any): void {\r\n PDFName = pdfLibModule.PDFName;\r\n PDFString = pdfLibModule.PDFString;\r\n}\r\n\r\n/**\r\n * Metadata for a single form field\r\n */\r\nexport interface FieldMetadata {\r\n fieldId?: string; // Immutable UUID for reliable field identification\r\n label?: string;\r\n signer?: string;\r\n placeholder?: string;\r\n acknowledgements?: Acknowledgement[];\r\n required?: boolean;\r\n options?: string[]; // For radio and dropdown fields\r\n}\r\n\r\n/**\r\n * Complete metadata structure stored in PDF\r\n */\r\nexport interface SigniphiMetadata {\r\n version: string;\r\n fields: Record<string, FieldMetadata>; // Key is the actual PDF field name (with suffixes for date/signature/initials)\r\n fieldIdIndex?: Record<string, string>; // UUID → field name mapping for fast lookups\r\n}\r\n\r\n/**\r\n * Stores Signiphi metadata in the PDF's document information dictionary\r\n * @param pdfDoc - The PDF document to store metadata in\r\n * @param metadata - The metadata object to store\r\n */\r\nexport function setSigniphiMetadata(pdfDoc: PDFDocument, metadata: SigniphiMetadata): void {\r\n try {\r\n if (!PDFName || !PDFString) {\r\n console.error('PDF metadata classes not initialized. Call initPdfMetadata first.');\r\n return;\r\n }\r\n \r\n const infoRef = pdfDoc.context.trailerInfo.Info;\r\n const infoObj = pdfDoc.context.lookup(infoRef);\r\n if (!infoObj || typeof (infoObj as any).set !== 'function') {\r\n throw new Error('Info object is not a PDFDict or does not have set method');\r\n }\r\n const infoDict = infoObj as any;\r\n const metadataString = JSON.stringify(metadata);\r\n \r\n // Set the metadata\r\n infoDict.set(PDFName.of('SigniphiMetadata'), PDFString.of(metadataString));\r\n } catch (error) {\r\n console.error('Failed to set Signiphi metadata:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves Signiphi metadata from the PDF's document information dictionary\r\n * @param pdfDoc - The PDF document to read metadata from\r\n * @returns The metadata object if found, null otherwise\r\n */\r\nexport function getSigniphiMetadata(pdfDoc: PDFDocument): SigniphiMetadata | null {\r\n try {\r\n if (!PDFName || !PDFString) {\r\n console.error('PDF metadata classes not initialized. Call initPdfMetadata first.');\r\n return null;\r\n }\r\n \r\n const infoRef = pdfDoc.context.trailerInfo.Info;\r\n const infoObj = pdfDoc.context.lookup(infoRef);\r\n \r\n if (!infoObj || typeof (infoObj as any).get !== 'function' || !(infoObj as any).dict) {\r\n return null;\r\n }\r\n \r\n const infoDict = infoObj as any;\r\n const metadataObj = infoDict.get(PDFName.of('SigniphiMetadata'));\r\n \r\n if (!metadataObj) {\r\n return null;\r\n }\r\n \r\n // PDFString objects are encoded as \"(content)\" in their toString() representation\r\n const metadataStr = metadataObj.toString();\r\n \r\n // Extract content from PDF string format: (content) or <hex>\r\n let jsonStr = metadataStr;\r\n const parenMatch = metadataStr.match(/^\\((.*)\\)$/);\r\n if (parenMatch && parenMatch[1]) {\r\n jsonStr = parenMatch[1];\r\n } else {\r\n const hexMatch = metadataStr.match(/^<(.*)>$/);\r\n if (hexMatch && hexMatch[1]) {\r\n // Convert hex to string if needed\r\n jsonStr = hexMatch[1];\r\n }\r\n }\r\n \r\n const metadata = JSON.parse(jsonStr);\r\n return metadata;\r\n } catch (error) {\r\n console.error('Failed to load Signiphi metadata:', error);\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Lazy loader for pdf-lib\r\n * \r\n * This module provides a lazy loading mechanism for the pdf-lib library (~150KB).\r\n * By deferring the import until actually needed, we can significantly reduce\r\n * the initial bundle size for consumers who only view PDFs without filling forms.\r\n * \r\n * The pdf-lib library is only loaded when:\r\n * - fillPdf() is called\r\n * - combinePdfs() is called\r\n * - Other PDF manipulation functions are used\r\n */\r\n\r\n// Cache the promise to ensure we only import once\r\nlet pdfLibPromise: Promise<typeof import('pdf-lib')> | null = null;\r\n\r\n/**\r\n * Dynamically import pdf-lib library\r\n * \r\n * This function lazily loads pdf-lib only when needed. The import is cached\r\n * so subsequent calls return the same promise, avoiding multiple imports.\r\n * \r\n * @returns Promise resolving to the pdf-lib module\r\n * \r\n * @example\r\n * ```typescript\r\n * const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n * const pdfDoc = await PDFDocument.load(pdfBytes);\r\n * ```\r\n */\r\nexport async function loadPdfLib() {\r\n if (!pdfLibPromise) {\r\n pdfLibPromise = import('pdf-lib');\r\n }\r\n return pdfLibPromise;\r\n}\r\n\r\n/**\r\n * Check if pdf-lib has been loaded\r\n * \r\n * Useful for debugging and testing to verify lazy loading behavior.\r\n * \r\n * @returns true if pdf-lib has been loaded, false otherwise\r\n */\r\nexport function isPdfLibLoaded(): boolean {\r\n return pdfLibPromise !== null;\r\n}\r\n\r\n/**\r\n * Reset the pdf-lib cache (primarily for testing)\r\n * \r\n * This should only be used in test environments to reset state\r\n * between tests.\r\n * \r\n * @internal\r\n */\r\nexport function resetPdfLibCache(): void {\r\n pdfLibPromise = null;\r\n}\r\n\r\n","/**\n * Field Visibility Utilities\n * Core logic for determining which fields are visible/editable in multi-signer mode\n * \n * XIGNIPHI MODEL: All signers are equal - no primary/secondary hierarchy\n * Signers are ordered by signOrder for sequential signing only\n * \n * CRITICAL: This logic must work identically in both flows:\n * - Single-signer flow: isMultiSigner = false, all fields visible\n * - Multi-signer flow: isMultiSigner = true, filtered by assignment rules\n */\n\nimport type { EsignFormField, MultiSignerContext } from '../types';\n\n/**\n * Determine if a field should be visible to the current signer\n * \n * Implements signiphi's simple 4-rule visibility logic:\n * - Rule 1: Unassigned fields → visible to all signers\n * - Rule 2: Direct assignment → show if assigned to current signer\n * - Rule 3: Grouped assignments (\"to-recipients\", \"additional-signers\") → visible to all signers\n * - Rule 4: Assigned to different specific signer → hide\n * \n * @param field - The form field to check\n * @param multiSignerContext - Multi-signer context with current signer info\n * @returns true if field should be visible, false if hidden\n * \n * @example Single-signer flow\n * ```ts\n * const context = { isMultiSigner: false, ... };\n * isFieldVisibleToSigner(anyField, context); // always returns true\n * ```\n * \n * @example Multi-signer flow\n * ```ts\n * const context = {\n * isMultiSigner: true,\n * currentSignerEmail: 'signer1@example.com',\n * isPrimarySigner: false, // Not used in signiphi\n * isFinalSigner: false // Not used in signiphi\n * };\n * \n * // Unassigned field - all signers see it\n * isFieldVisibleToSigner({ assignedSignerEmail: undefined, ... }, context); // true\n * \n * // Direct assignment to current signer\n * isFieldVisibleToSigner({ assignedSignerEmail: 'signer1@example.com', ... }, context); // true\n * \n * // Grouped assignment - all signers see it\n * isFieldVisibleToSigner({ assignedSignerEmail: 'to-recipients', ... }, context); // true\n * ```\n */\nexport function isFieldVisibleToSigner(\n field: EsignFormField,\n multiSignerContext: MultiSignerContext\n): boolean {\n // Single-signer mode: all fields are visible\n if (!multiSignerContext.isMultiSigner) {\n return true;\n }\n\n const { currentSignerEmail } = multiSignerContext;\n\n // RULE 1: Unassigned fields - visible to all signers (signiphi's flat model)\n if (!field.assignedSignerEmail) {\n return true;\n }\n\n // RULE 2: Direct assignment - show if assigned to current signer\n if (field.assignedSignerEmail === currentSignerEmail) {\n return true;\n }\n\n // RULE 3: Grouped assignments - visible to all signers (convenience feature)\n // \"to-recipients\" means field assigned to ALL signers\n // \"additional-signers\" is legacy but works the same way\n if (field.assignedSignerEmail === 'to-recipients' || \n field.assignedSignerEmail === 'additional-signers') {\n return true;\n }\n\n // RULE 4: Assigned to different specific signer - hide\n return false;\n}\n\n/**\n * Filter an array of fields to only those visible to the current signer\n * \n * @param fields - All form fields\n * @param multiSignerContext - Multi-signer context\n * @returns Filtered array of visible fields\n * \n * @example\n * ```ts\n * const allFields = [...]; // 10 fields\n * const context = { isMultiSigner: true, isPrimarySigner: true, ... };\n * const visible = filterFieldsBySigner(allFields, context); // 5 fields (only primary signer's)\n * ```\n */\nexport function filterFieldsBySigner(\n fields: EsignFormField[],\n multiSignerContext: MultiSignerContext\n): EsignFormField[] {\n // Single-signer mode: return all fields\n if (!multiSignerContext.isMultiSigner) {\n return fields;\n }\n\n // Multi-signer mode: filter using visibility logic\n return fields.filter(field => isFieldVisibleToSigner(field, multiSignerContext));\n}\n\n/**\n * Determine if a field should be flattened (made non-editable) by the current signer\n * \n * Used during PDF submission to determine which fields to flatten.\n * In multi-signer mode, only flatten fields assigned to current signer.\n * In single-signer mode, flatten all fields.\n * \n * XIGNIPHI MODEL: Flatten fields visible/assigned to current signer\n * \n * CRITICAL: This affects PDF flattening behavior - must preserve exact logic!\n * \n * @param field - The form field to check\n * @param multiSignerContext - Multi-signer context\n * @returns true if current signer should flatten this field\n * \n * @example Single-signer flow\n * ```ts\n * const context = { isMultiSigner: false, ... };\n * shouldFlattenField(anyField, context); // always returns true\n * ```\n * \n * @example Multi-signer flow\n * ```ts\n * const context = {\n * isMultiSigner: true,\n * currentSignerEmail: 'signer1@example.com',\n * isPrimarySigner: false, // Not used in signiphi\n * isFinalSigner: false // Not used in signiphi\n * };\n * \n * // Current signer's field - flatten it\n * shouldFlattenField({ assignedSignerEmail: 'signer1@example.com', ... }, context); // true\n * \n * // Different signer's field - don't flatten (keep editable for them)\n * shouldFlattenField({ assignedSignerEmail: 'signer2@example.com', ... }, context); // false\n * \n * // Unassigned field - all signers flatten (visible to all)\n * shouldFlattenField({ assignedSignerEmail: undefined, ... }, context); // true\n * ```\n */\nexport function shouldFlattenField(\n field: EsignFormField,\n multiSignerContext: MultiSignerContext\n): boolean {\n // Single-signer mode: flatten all fields\n if (!multiSignerContext.isMultiSigner) {\n return true;\n }\n\n const { currentSignerEmail } = multiSignerContext;\n\n // RULE 1: Unassigned fields - all signers flatten them (visible to all)\n if (!field.assignedSignerEmail) {\n return true;\n }\n\n // RULE 2: Direct assignment - flatten if assigned to current signer\n if (field.assignedSignerEmail === currentSignerEmail) {\n return true;\n }\n\n // RULE 3: Grouped assignments - all signers flatten them (visible to all)\n if (field.assignedSignerEmail === 'to-recipients' || \n field.assignedSignerEmail === 'additional-signers') {\n return true;\n }\n\n // RULE 4: Assigned to different specific signer - DON'T flatten (keep editable for them)\n return false;\n}\n\n","/**\r\n * PDF Widget Helper Utilities\r\n * Common utilities for working with PDF widgets and pages\r\n * \r\n * Used across pdf-manipulation.ts and pdf-viewer-filter.ts\r\n */\r\n\r\nimport type { PDFPage } from 'pdf-lib';\r\n\r\n/**\r\n * Extended type for PDF pages with ref property\r\n */\r\ninterface PDFPageWithRef {\r\n ref: unknown;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Find the page index for a given page reference\r\n * \r\n * This is a common pattern used when working with PDF widgets to determine\r\n * which page a widget belongs to by comparing page references.\r\n * \r\n * @param pages - Array of PDF pages\r\n * @param pageRef - The page reference to search for\r\n * @returns Page index (0-based), or -1 if not found\r\n * \r\n * @example\r\n * ```ts\r\n * const widget = widgets[0];\r\n * const pageRef = widget.P?.();\r\n * const pageIndex = findPageIndexByRef(pages, pageRef);\r\n * if (pageIndex >= 0) {\r\n * const page = pages[pageIndex];\r\n * // Draw on the page\r\n * }\r\n * ```\r\n */\r\nexport function findPageIndexByRef(\r\n pages: PDFPage[],\r\n pageRef: unknown\r\n): number {\r\n if (!pageRef) return -1;\r\n \r\n for (let i = 0; i < pages.length; i++) {\r\n const page = pages[i] as unknown as PDFPageWithRef;\r\n if (page.ref === pageRef) {\r\n return i;\r\n }\r\n }\r\n \r\n return -1;\r\n}\r\n\r\n/**\r\n * Extended type for PDF widgets with rectangle and page methods\r\n */\r\nexport interface PDFWidgetWithExtensions {\r\n getRectangle?: () => { x: number; y: number; width: number; height: number } | undefined;\r\n P?: () => unknown;\r\n}\r\n\r\n/**\r\n * Get widget rectangle and its page\r\n * \r\n * Helper to extract both the rectangle coordinates and the page that a widget\r\n * belongs to in a single operation.\r\n * \r\n * @param widget - The PDF widget\r\n * @param pages - Array of PDF pages\r\n * @returns Object with rect, page, and pageIndex, or null if unable to determine\r\n * \r\n * @example\r\n * ```ts\r\n * for (const widget of widgets) {\r\n * const result = getWidgetRectangleAndPage(widget, pages);\r\n * if (result) {\r\n * const { rect, page, pageIndex } = result;\r\n * // Draw something at rect coordinates on page\r\n * page.drawRectangle({ x: rect.x, y: rect.y, ... });\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function getWidgetRectangleAndPage(\r\n widget: PDFWidgetWithExtensions,\r\n pages: PDFPage[]\r\n): {\r\n rect: { x: number; y: number; width: number; height: number };\r\n page: PDFPage;\r\n pageIndex: number;\r\n} | null {\r\n const rect = widget.getRectangle?.();\r\n if (!rect) return null;\r\n \r\n const pageRef = widget.P?.();\r\n if (!pageRef) return null;\r\n \r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n if (pageIndex === -1) return null;\r\n \r\n const page = pages[pageIndex];\r\n if (!page) return null;\r\n \r\n return { rect, page, pageIndex };\r\n}\r\n\r\n/**\r\n * Find page index with fallback to single-page PDFs\r\n * \r\n * Same as findPageIndexByRef but with a fallback: if pageRef lookup fails\r\n * and there's only one page in the document, returns index 0.\r\n * \r\n * This is useful for label drawing where single-page PDFs might not have\r\n * proper page references but we can safely assume page 0.\r\n * \r\n * @param pages - Array of PDF pages\r\n * @param pageRef - The page reference to search for\r\n * @returns Page index (0-based), 0 if single-page PDF, or -1 if not found\r\n * \r\n * @example\r\n * ```ts\r\n * // Used in pdf-viewer-filter for label drawing\r\n * const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n * if (pageIndex >= 0) {\r\n * const page = pages[pageIndex];\r\n * page.drawText(label, ...);\r\n * }\r\n * ```\r\n */\r\nexport function findPageIndexWithFallback(\r\n pages: PDFPage[],\r\n pageRef: unknown\r\n): number {\r\n if (!pageRef) {\r\n // No page ref - fallback to page 0 if single-page PDF\r\n return pages.length === 1 ? 0 : -1;\r\n }\r\n \r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n \r\n // If not found but single-page PDF, assume page 0\r\n if (pageIndex === -1 && pages.length === 1) {\r\n return 0;\r\n }\r\n \r\n return pageIndex;\r\n}\r\n\r\n","/**\r\n * PDF Field Type Helper Utilities\r\n * Common utilities for detecting field types and extracting values\r\n *\r\n * Used across pdf-manipulation.ts for consistent field processing\r\n *\r\n * IMPORTANT: Uses duck typing (method detection) instead of constructor.name\r\n * to ensure minification-safe field type detection. Constructor names are\r\n * renamed during minification, breaking string comparisons.\r\n */\r\n\r\n/**\r\n * PDF form field type for operations\r\n */\r\ninterface PDFFormField {\r\n getName(): string;\r\n getText?(): string;\r\n setText?(text: string): void;\r\n isRequired?(): boolean;\r\n isChecked?(): boolean;\r\n check?(): void;\r\n uncheck?(): void;\r\n getSelected?(): string[];\r\n getOptions?(): string[];\r\n select?(value: string): void;\r\n setOptions?(options: string[]): void;\r\n addOptions?(options: string[]): void;\r\n enableReadOnly?(): void;\r\n}\r\n\r\n/**\r\n * Detect the field type from a PDF field using duck typing\r\n *\r\n * Uses method presence detection instead of constructor.name to ensure\r\n * minification-safe field type detection. Each pdf-lib field type has\r\n * unique methods that can be used to identify it.\r\n *\r\n * @param field - The PDF form field\r\n * @returns Standardized field type string\r\n *\r\n * @example\r\n * ```ts\r\n * const fieldType = detectFieldType(field);\r\n * // Returns: 'text', 'checkbox', 'dropdown', 'radiogroup', 'signature', etc.\r\n * ```\r\n */\r\nexport function detectFieldType(field: PDFFormField): string {\r\n const f = field as any;\r\n\r\n // Checkbox: has check/uncheck methods (unique to checkboxes)\r\n if (typeof f.check === 'function' && typeof f.uncheck === 'function') {\r\n return 'checkbox';\r\n }\r\n\r\n // Radio: has select/getOptions but NOT check (distinguishes from checkbox)\r\n // and NOT setOptions (distinguishes from dropdown)\r\n if (typeof f.select === 'function' &&\r\n typeof f.getOptions === 'function' &&\r\n typeof f.check !== 'function' &&\r\n typeof f.setOptions !== 'function') {\r\n return 'radiogroup';\r\n }\r\n\r\n // Dropdown: has select/getOptions AND setOptions or addOptions\r\n if (typeof f.select === 'function' &&\r\n typeof f.getOptions === 'function' &&\r\n (typeof f.setOptions === 'function' || typeof f.addOptions === 'function')) {\r\n return 'dropdown';\r\n }\r\n\r\n // OptionList: has getOptions and setOptions but no select\r\n if (typeof f.getOptions === 'function' &&\r\n typeof f.setOptions === 'function' &&\r\n typeof f.select !== 'function') {\r\n return 'optionlist';\r\n }\r\n\r\n // Text: has getText/setText methods\r\n if (typeof f.getText === 'function' && typeof f.setText === 'function') {\r\n return 'text';\r\n }\r\n\r\n // Signature: no editable methods (no getText, no check, no select)\r\n if (typeof f.getText !== 'function' &&\r\n typeof f.check !== 'function' &&\r\n typeof f.select !== 'function') {\r\n return 'signature';\r\n }\r\n\r\n return 'unknown';\r\n}\r\n\r\n/**\r\n * Extract the current value from a PDF field based on its type\r\n * \r\n * Handles different field types appropriately:\r\n * - Text fields: getText()\r\n * - Checkboxes: isChecked() → 'true'/'false'\r\n * - Dropdowns: getSelected()[0]\r\n * - Radio groups: getSelected()[0]\r\n * \r\n * @param field - The PDF form field\r\n * @param fieldType - The field type (from detectFieldType)\r\n * @returns The field value as a string, or empty string if no value\r\n * \r\n * @example\r\n * ```ts\r\n * const fieldType = detectFieldType(field);\r\n * const value = extractFieldValue(field, fieldType);\r\n * ```\r\n */\r\nexport function extractFieldValue(field: PDFFormField, fieldType: string): string {\r\n try {\r\n switch (fieldType) {\r\n case 'text':\r\n case 'date':\r\n return field.getText?.() || '';\r\n\r\n case 'checkbox':\r\n return field.isChecked?.() ? 'true' : 'false';\r\n\r\n case 'dropdown':\r\n case 'optionlist': {\r\n // Dropdowns return an array from getSelected()\r\n const selected = field.getSelected?.();\r\n return Array.isArray(selected) ? selected[0] || '' : String(selected || '');\r\n }\r\n\r\n case 'radiogroup':\r\n case 'radio': {\r\n // Radio groups return a string from getSelected(), not an array\r\n const radioSelected = field.getSelected?.();\r\n return radioSelected ? String(radioSelected) : '';\r\n }\r\n\r\n default:\r\n return '';\r\n }\r\n } catch (error) {\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Check if a field is required based on field metadata and name patterns\r\n * \r\n * Attempts to determine required status through:\r\n * 1. field.isRequired() method (if available)\r\n * 2. Field name patterns (signature, initials, required)\r\n * 3. Field type (signatures are always required)\r\n * \r\n * @param field - The PDF form field\r\n * @param fieldName - The field name\r\n * @param fieldType - The field type (from detectFieldType)\r\n * @returns true if field is required\r\n * \r\n * @example\r\n * ```ts\r\n * const isRequired = isRequiredField(field, 'signature_1', 'text');\r\n * // Returns: true (signature fields are required)\r\n * ```\r\n */\r\nexport function isRequiredField(\r\n field: PDFFormField,\r\n fieldName: string,\r\n fieldType: string\r\n): boolean {\r\n // Signature fields are always required\r\n if (fieldType === 'signature') {\r\n return true;\r\n }\r\n \r\n // Try the isRequired method if available\r\n try {\r\n if (field.isRequired?.()) {\r\n return true;\r\n }\r\n } catch {\r\n // isRequired() not available or threw error\r\n }\r\n \r\n // Check field name patterns\r\n if (\r\n fieldName.includes('signature') ||\r\n fieldName.includes('initials') ||\r\n fieldName.includes('required')\r\n ) {\r\n return true;\r\n }\r\n \r\n return false;\r\n}\r\n\r\n","/**\r\n * PDF Manipulation Utilities\r\n * Core utilities for PDF processing, page manipulation, and file combining\r\n */\r\n\r\nimport * as pdfjsLib from 'pdfjs-dist';\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport { \r\n PdfPage, \r\n EsignFormField, \r\n FormFieldType, \r\n FormFieldPosition,\r\n MultiSignerContext \r\n} from '../types';\r\nimport { logger } from './logger';\r\nimport { validatePdfBytes, isAutoGeneratedLabel, hasDrawableLabel, getFieldDisplayName } from './pdf-validators';\r\nimport { isFieldVisibleToSigner, shouldFlattenField } from './field-visibility';\r\nimport { findPageIndexByRef, getWidgetRectangleAndPage, type PDFWidgetWithExtensions } from './pdf-widget-helpers';\r\nimport { detectFieldType, extractFieldValue, isRequiredField } from './pdf-field-type-helpers';\r\n\r\n// PDF.js worker is automatically configured by pdfjs-config module\r\n\r\n// Type definitions for PDF internal structures\r\ninterface PDFFieldWithAcro {\r\n getName(): string;\r\n acroField?: {\r\n getWidgets?: () => PDFWidget[];\r\n dict?: any; // PDF dictionary for accessing metadata\r\n };\r\n constructor: { name: string };\r\n}\r\n\r\ninterface PDFWidget {\r\n getRectangle?: () => { x: number; y: number; width: number; height: number };\r\n P?: () => unknown;\r\n}\r\n\r\n/**\r\n * Convert PDF pages to images for rendering in the UI using PDF.js\r\n */\r\nexport async function pdfToImages(\r\n pdfBytes: Uint8Array,\r\n options?: { hideFormFields?: boolean }\r\n): Promise<PdfPage[]> {\r\n try {\r\n // Validate PDF bytes\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n logger.error('Invalid PDF:', validation.error);\r\n throw new Error(validation.error || 'Invalid PDF format');\r\n }\r\n\r\n // Load PDF with PDF.js\r\n const loadingTask = pdfjsLib.getDocument({\r\n data: pdfBytes,\r\n verbosity: 0,\r\n });\r\n const pdfDoc = await loadingTask.promise;\r\n\r\n const pages: PdfPage[] = [];\r\n\r\n // Try to load with pdf-lib for dimension comparison\r\n let pdfLibDoc = null;\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n pdfLibDoc = await PDFDocument.load(pdfBytes);\r\n } catch {\r\n // PDF.js dimensions will be used instead\r\n }\r\n\r\n for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {\r\n const page = await pdfDoc.getPage(pageNum);\r\n const viewport = page.getViewport({ scale: 2.0 });\r\n\r\n // Get actual PDF dimensions\r\n let pdfWidth = viewport.width / 2.0;\r\n let pdfHeight = viewport.height / 2.0;\r\n\r\n // Use pdf-lib dimensions if available for consistency\r\n if (pdfLibDoc) {\r\n try {\r\n const pdfLibPage = pdfLibDoc.getPage(pageNum - 1);\r\n pdfWidth = pdfLibPage.getWidth();\r\n pdfHeight = pdfLibPage.getHeight();\r\n } catch {\r\n // Use PDF.js dimensions as fallback\r\n }\r\n }\r\n\r\n // Create canvas at the scaled size for high quality rendering\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n canvas.height = viewport.height;\r\n canvas.width = viewport.width;\r\n\r\n // Render PDF page to canvas\r\n const hideFormFields = options?.hideFormFields ?? false;\r\n const renderContext: any = {\r\n canvasContext: context,\r\n viewport: viewport,\r\n renderInteractiveForms: !hideFormFields,\r\n ...(hideFormFields && {\r\n annotationMode: 0,\r\n renderAnnotations: false,\r\n renderForms: false,\r\n }),\r\n };\r\n\r\n await page.render(renderContext).promise;\r\n\r\n // Convert canvas to data URL\r\n const imageUrl = canvas.toDataURL('image/png');\r\n\r\n pages.push({\r\n pageNumber: pageNum,\r\n width: pdfWidth,\r\n height: pdfHeight,\r\n imageUrl,\r\n renderWidth: viewport.width,\r\n renderHeight: viewport.height,\r\n });\r\n }\r\n\r\n return pages;\r\n } catch (error) {\r\n logger.error('Error converting PDF to images with PDF.js:', error);\r\n return await fallbackPdfToImages(pdfBytes);\r\n }\r\n}\r\n\r\n/**\r\n * Fallback function to create placeholder images when PDF.js fails\r\n */\r\nasync function fallbackPdfToImages(pdfBytes: Uint8Array): Promise<PdfPage[]> {\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n const pdf = await PDFDocument.load(pdfBytes);\r\n const pages: PdfPage[] = [];\r\n\r\n for (let i = 0; i < pdf.getPageCount(); i++) {\r\n const page = pdf.getPage(i);\r\n const { width, height } = page.getSize();\r\n \r\n // Create placeholder canvas\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n \r\n const scale = 1.5;\r\n canvas.width = width * scale;\r\n canvas.height = height * scale;\r\n \r\n // Draw placeholder\r\n context.fillStyle = '#ffffff';\r\n context.fillRect(0, 0, canvas.width, canvas.height);\r\n context.strokeStyle = '#e5e7eb';\r\n context.lineWidth = 2;\r\n context.strokeRect(0, 0, canvas.width, canvas.height);\r\n context.fillStyle = '#6b7280';\r\n context.font = 'bold 24px system-ui';\r\n context.textAlign = 'center';\r\n context.fillText(`Page ${i + 1}`, canvas.width / 2, canvas.height / 2 - 20);\r\n context.font = '16px system-ui';\r\n context.fillStyle = '#9ca3af';\r\n context.fillText('PDF preview not available', canvas.width / 2, canvas.height / 2 + 20);\r\n \r\n const imageUrl = canvas.toDataURL('image/png');\r\n \r\n pages.push({\r\n pageNumber: i + 1,\r\n width,\r\n height,\r\n imageUrl,\r\n renderWidth: canvas.width,\r\n renderHeight: canvas.height,\r\n });\r\n }\r\n\r\n return pages;\r\n } catch (error) {\r\n logger.error('Error with pdf-lib fallback:', error);\r\n // Return single error page\r\n return [createErrorPage()];\r\n }\r\n}\r\n\r\n/**\r\n * Create an error page when all processing fails\r\n */\r\nfunction createErrorPage(): PdfPage {\r\n const canvas = document.createElement('canvas');\r\n const context = canvas.getContext('2d')!;\r\n canvas.width = 600;\r\n canvas.height = 800;\r\n \r\n context.fillStyle = '#ffffff';\r\n context.fillRect(0, 0, canvas.width, canvas.height);\r\n context.strokeStyle = '#e5e7eb';\r\n context.lineWidth = 2;\r\n context.strokeRect(0, 0, canvas.width, canvas.height);\r\n context.fillStyle = '#ef4444';\r\n context.font = 'bold 20px system-ui';\r\n context.textAlign = 'center';\r\n context.fillText('PDF Processing Error', canvas.width / 2, canvas.height / 2 - 20);\r\n context.font = '14px system-ui';\r\n context.fillStyle = '#6b7280';\r\n context.fillText('Unable to process the uploaded PDF file', canvas.width / 2, canvas.height / 2 + 20);\r\n \r\n return {\r\n pageNumber: 1,\r\n width: 600,\r\n height: 800,\r\n imageUrl: canvas.toDataURL('image/png'),\r\n renderWidth: canvas.width,\r\n renderHeight: canvas.height,\r\n };\r\n}\r\n\r\n// Type definitions for PDF form field operations\r\ninterface PDFFormField {\r\n getName(): string;\r\n constructor: { name: string };\r\n getText?(): string;\r\n setText?(text: string): void;\r\n isRequired?(): boolean;\r\n isChecked?(): boolean;\r\n getSelected?(): string[];\r\n enableReadOnly?(): void;\r\n}\r\n\r\ninterface PDFFormFieldWithAcro extends PDFFormField {\r\n acroField: {\r\n getWidgets(): unknown[];\r\n removeWidget(index: number): void;\r\n };\r\n}\r\n\r\ninterface PDFDict {\r\n get(key: unknown): unknown;\r\n delete(key: unknown): void;\r\n}\r\n\r\n/**\r\n * Remove all existing form fields from a PDF using robust widget cleanup\r\n * @param pdfBytes - The PDF bytes\r\n * @param stripAllAnnotations - If true, removes all annotations from pages (more aggressive cleanup)\r\n * @returns The PDF bytes with all form fields removed\r\n */\r\nexport async function removeAllFormFields(pdfBytes: Uint8Array, stripAllAnnotations = false): Promise<Uint8Array> {\r\n try {\r\n // Validate PDF data first\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n return pdfBytes;\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n if (stripAllAnnotations) {\r\n // More aggressive approach: strip all annotations from all pages\r\n const pages = pdfDoc.getPages();\r\n \r\n for (let i = 0; i < pages.length; i++) {\r\n const page = pages[i];\r\n \r\n try {\r\n // Access the page's annotation array\r\n const pageRef = (page as any).ref;\r\n const pageDictObj = pdfDoc.context.lookup(pageRef);\r\n \r\n if (pageDictObj) {\r\n const pageDict = pageDictObj as unknown as PDFDict;\r\n \r\n if (pageDict && pageDict.get && pageDict.delete) {\r\n const annotsRef = pageDict.get((pdfDoc.context as any).obj('Annots'));\r\n \r\n if (annotsRef) {\r\n pageDict.delete((pdfDoc.context as any).obj('Annots'));\r\n }\r\n } else {\r\n }\r\n } else {\r\n }\r\n } catch (pageError) {\r\n }\r\n }\r\n } else {\r\n // Robust widget-based removal approach\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n if (fields.length === 0) {\r\n return pdfBytes;\r\n }\r\n \r\n // Remove all fields using robust widget cleanup\r\n for (const field of fields) {\r\n try {\r\n const acroField = (field as unknown as PDFFormFieldWithAcro).acroField;\r\n if (acroField && typeof acroField.getWidgets === 'function') {\r\n let widgets = acroField.getWidgets();\r\n \r\n // Remove widgets one by one with safety counter\r\n let safetyCounter = 0;\r\n const maxIterations = widgets.length + 5;\r\n \r\n while (widgets.length > 0 && safetyCounter < maxIterations) {\r\n try {\r\n const widgetIndex = widgets.length - 1;\r\n acroField.removeWidget(widgetIndex);\r\n widgets = acroField.getWidgets();\r\n } catch (widgetError) {\r\n break;\r\n }\r\n safetyCounter++;\r\n }\r\n \r\n if (safetyCounter >= maxIterations) {\r\n }\r\n }\r\n \r\n form.removeField(field as any);\r\n } catch (error) {\r\n \r\n try {\r\n form.removeField(field as any);\r\n } catch (fallbackError) {\r\n }\r\n }\r\n }\r\n \r\n const remainingFields = form.getFields();\r\n if (remainingFields.length > 0) {\r\n }\r\n }\r\n \r\n const updatedPdfBytes = await pdfDoc.save();\r\n return updatedPdfBytes;\r\n } catch (error) {\r\n logger.error('Error removing form fields from PDF:', error);\r\n return pdfBytes;\r\n }\r\n}\r\n\r\n/**\r\n * Read existing PDF form fields and their properties\r\n */\r\nexport async function readPdfFormFields(pdfBytes: Uint8Array): Promise<{\r\n name: string;\r\n type: string;\r\n required: boolean;\r\n value?: string;\r\n}[]> {\r\n try {\r\n // Validate PDF data first\r\n const validation = validatePdfBytes(pdfBytes);\r\n if (!validation.valid) {\r\n return [];\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n if (fields.length === 0) {\r\n return [];\r\n }\r\n \r\n const formFields = fields.map(field => {\r\n const fieldName = field.getName();\r\n const pdfField = field as unknown as PDFFormField;\r\n \r\n try {\r\n // Use centralized field type detection and value extraction\r\n const fieldType = detectFieldType(pdfField);\r\n const value = extractFieldValue(pdfField, fieldType);\r\n const required = isRequiredField(pdfField, fieldName, fieldType);\r\n \r\n return {\r\n name: fieldName,\r\n type: fieldType,\r\n required,\r\n value\r\n };\r\n } catch (fieldError) {\r\n // Fallback to defaults on error\r\n return {\r\n name: fieldName,\r\n type: 'text',\r\n required: false,\r\n value: ''\r\n };\r\n }\r\n });\r\n \r\n return formFields;\r\n } catch (error) {\r\n logger.error('Error reading PDF form fields:', error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Read current PDF form field values (including user-filled data)\r\n */\r\nexport async function readCurrentPdfFormValues(pdfBytes: Uint8Array): Promise<Record<string, string>> {\r\n try {\r\n if (!pdfBytes || pdfBytes.length === 0) {\r\n return {};\r\n }\r\n \r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n \r\n const currentValues: Record<string, string> = {};\r\n \r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const pdfField = field as unknown as PDFFormField;\r\n \r\n try {\r\n // Use centralized field type detection and value extraction\r\n const fieldType = detectFieldType(pdfField);\r\n const value = extractFieldValue(pdfField, fieldType);\r\n \r\n currentValues[fieldName] = value;\r\n } catch (fieldError) {\r\n currentValues[fieldName] = '';\r\n }\r\n }\r\n \r\n return currentValues;\r\n } catch (error) {\r\n logger.error('Error reading current PDF form values:', error);\r\n return {};\r\n }\r\n}\r\n\r\n/**\r\n * Validate PDF form fields against provided values\r\n * In multi-signer mode, only validates fields visible to the current signer\r\n */\r\nexport async function validatePdfFormFields(\r\n pdfBytes: Uint8Array,\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>,\r\n extractedFields?: EsignFormField[], // Pass extracted fields to know which are visible\r\n multiSignerContext?: MultiSignerContext // Pass context to filter validation\r\n): Promise<string[]> {\r\n try {\r\n const pdfFormFields = await readPdfFormFields(pdfBytes);\r\n const errors: string[] = [];\r\n \r\n \r\n for (const field of pdfFormFields) {\r\n if (field.required) {\r\n // Look up the matching extracted field for proper label/type info\r\n const extractedField = extractedFields?.find(f => f.name === field.name);\r\n\r\n // In multi-signer mode, only validate fields visible to current signer\r\n if (multiSignerContext?.isMultiSigner && extractedFields) {\r\n if (!extractedField) {\r\n // Field not in extractedFields means it's not visible to current signer\r\n continue;\r\n }\r\n }\r\n\r\n // Skip fields already validated at the SubmissionForm level (date, signature, initials)\r\n // to avoid duplicate error messages. The raw PDF type for dates is 'text', so we\r\n // use the extractedField type which has the correct logical type.\r\n const logicalType = extractedField?.type || field.type;\r\n if (logicalType === 'date' || logicalType === 'signature' || logicalType === 'initials') {\r\n continue;\r\n }\r\n\r\n let hasValue = false;\r\n const fieldValue = fieldValues[field.name];\r\n const signatureValue = signatures[field.name];\r\n const mainSignature = signatures['signature_field_main'];\r\n const mainInitials = signatures['initials_field_main'] || fieldValues['initials_field_main'];\r\n\r\n if (field.name.includes('signature') || field.type === 'signature') {\r\n hasValue = !!(signatureValue || fieldValue || mainSignature);\r\n } else if (field.name.includes('initials')) {\r\n hasValue = !!(signatureValue || fieldValue || mainInitials);\r\n } else if (field.type === 'checkbox' || logicalType === 'checkbox') {\r\n // Checkbox: value is 'true'/'false' string - must be specifically 'true' (checked)\r\n hasValue = fieldValue === 'true' || field.value === 'true';\r\n } else {\r\n hasValue = !!(fieldValue || field.value);\r\n }\r\n\r\n if (!hasValue) {\r\n // Use extractedField label and type for proper display names\r\n const friendlyName = getFieldDisplayName({\r\n label: extractedField?.label,\r\n name: field.name,\r\n type: logicalType\r\n });\r\n\r\n errors.push(`${friendlyName} is required`);\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n } catch (error) {\r\n logger.error('Error validating PDF form fields:', error);\r\n return ['Unable to validate form fields. Please ensure all required fields are completed.'];\r\n }\r\n}\r\n\r\n/**\r\n * Validate PDF form fields against current form state\r\n */\r\nexport async function validateCurrentPdfState(\r\n pdfBytes: Uint8Array,\r\n signatures: Record<string, string>,\r\n formFieldValues: Record<string, string> = {}\r\n): Promise<string[]> {\r\n try {\r\n const pdfFormFields = await readPdfFormFields(pdfBytes);\r\n const currentValues = await readCurrentPdfFormValues(pdfBytes);\r\n const errors: string[] = [];\r\n \r\n for (const field of pdfFormFields) {\r\n const isSignatureField = field.name.includes('signature') && field.type === 'text';\r\n const isInitialsField = field.name.includes('initials') && field.type === 'text';\r\n \r\n if (field.required || isSignatureField || isInitialsField) {\r\n let hasValue = false;\r\n const currentValue = currentValues[field.name] || '';\r\n \r\n if (isSignatureField) {\r\n hasValue = !!signatures[field.name];\r\n } else if (isInitialsField) {\r\n hasValue = !!signatures[field.name] || !!(formFieldValues[field.name]?.trim()) || currentValue.trim() !== '';\r\n } else {\r\n hasValue = currentValue.trim() !== '';\r\n }\r\n \r\n if (!hasValue) {\r\n // Use centralized friendly name logic that handles auto-generated labels\r\n const friendlyName = getFieldDisplayName({\r\n name: field.name,\r\n type: field.type\r\n });\r\n\r\n errors.push(`${friendlyName} is required`);\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n } catch (error) {\r\n logger.error('Error validating current PDF state:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Helper function to extract font size from a field\r\n * Priority: 1) extractedFormFields metadata, 2) DA field, 3) TU field, 4) default 10px\r\n */\r\nfunction extractFieldFontSize(\r\n fieldName: string,\r\n field: any,\r\n extractedFormFields?: EsignFormField[]\r\n): number {\r\n const DEFAULT_FONT_SIZE = 10;\r\n const MIN_FONT_SIZE = 8;\r\n const MAX_FONT_SIZE = 72;\r\n\r\n // 1. Try extractedFormFields metadata first (runtime information)\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n if (fieldInfo?.fontSize && fieldInfo.fontSize >= MIN_FONT_SIZE && fieldInfo.fontSize <= MAX_FONT_SIZE) {\r\n return fieldInfo.fontSize;\r\n }\r\n\r\n // 2. Try DA (Default Appearance) field - standard PDF font size location\r\n const daFontSize = extractFromDAField(field);\r\n if (daFontSize !== null) {\r\n return daFontSize;\r\n }\r\n\r\n // 3. Try TU (alternate text) field - custom fontSize metadata format\r\n const tuFontSize = extractFromTUField(field);\r\n if (tuFontSize !== null) {\r\n return tuFontSize;\r\n }\r\n\r\n // 4. Default fallback\r\n return DEFAULT_FONT_SIZE;\r\n}\r\n\r\n/**\r\n * Extract font size from DA (Default Appearance) field\r\n * Format: \"0 0 0 rg\\n/Helvetica 16 Tf\"\r\n */\r\nfunction extractFromDAField(field: any): number | null {\r\n try {\r\n const fieldWithAcro = field as unknown as PDFFieldWithAcro;\r\n const dict = fieldWithAcro.acroField?.dict;\r\n if (!dict) return null;\r\n\r\n const daKey = dict.context?.obj?.('DA') || 'DA';\r\n const daEntry = dict.lookup?.(daKey) || dict.get?.(daKey);\r\n if (!daEntry) return null;\r\n\r\n // Get DA string value\r\n let daValue = '';\r\n if (typeof daEntry.decodeText === 'function') {\r\n daValue = daEntry.decodeText();\r\n } else if (typeof daEntry.asString === 'function') {\r\n daValue = daEntry.asString();\r\n } else {\r\n daValue = String(daEntry);\r\n }\r\n\r\n // Match pattern like \"/Helvetica 24 Tf\" or \"24 Tf\"\r\n const daMatch = daValue.match(/\\s+(\\d+)\\s+Tf/i);\r\n if (daMatch?.[1]) {\r\n const fontSize = parseInt(daMatch[1], 10);\r\n if (fontSize >= 8 && fontSize <= 72) {\r\n return fontSize;\r\n }\r\n }\r\n } catch {\r\n // Silently fail\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract font size from TU (alternate text) field\r\n * Format: \"Label Text|fontSize:16\"\r\n */\r\nfunction extractFromTUField(field: any): number | null {\r\n try {\r\n const fieldWithAcro = field as unknown as PDFFieldWithAcro;\r\n const dict = fieldWithAcro.acroField?.dict;\r\n if (!dict) return null;\r\n\r\n const tuKey = dict.context?.obj?.('TU') || 'TU';\r\n const tuEntry = dict.lookup?.(tuKey) || dict.get?.(tuKey);\r\n if (!tuEntry) return null;\r\n\r\n // Get TU string value\r\n let tuValue = '';\r\n if (typeof tuEntry.decodeText === 'function') {\r\n tuValue = tuEntry.decodeText();\r\n } else if (typeof tuEntry.asString === 'function') {\r\n tuValue = tuEntry.asString();\r\n } else {\r\n tuValue = String(tuEntry);\r\n }\r\n\r\n // Parse custom format: \"Label|fontSize:16\"\r\n tuValue = tuValue.replace(/^\\(|\\)$|^<|>$/g, '');\r\n const match = tuValue.match(/\\|fontSize:(\\d+)$/);\r\n if (match?.[1]) {\r\n const fontSize = parseInt(match[1], 10);\r\n if (fontSize >= 8 && fontSize <= 72) {\r\n return fontSize;\r\n }\r\n }\r\n } catch {\r\n // Silently fail\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Fill PDF with signature images and form field values, then flatten the form\r\n * @param pdfBytes - The PDF bytes\r\n * @param signatures - The signature data URLs (field name -> base64 PNG)\r\n * @param formFieldValues - The form field values to fill\r\n * @returns The filled and flattened PDF bytes\r\n */\r\nexport async function fillPdfWithSignatures(\r\n pdfBytes: Uint8Array,\r\n signatures: Record<string, string>,\r\n formFieldValues: Record<string, string> = {},\r\n _currentSignerEmail?: string, // Deprecated: use multiSignerContext.currentSignerEmail instead\r\n extractedFormFields?: EsignFormField[],\r\n metadata?: { submissionId?: string; documentId?: string; author?: string; signerEmail?: string; signerInitials?: string; createdAt?: Date },\r\n auditTrail?: { userAgent?: string; screenResolution?: string; timezone?: string; language?: string; platform?: string; ipAddress?: string; geolocation?: { latitude: number; longitude: number; accuracy?: number } },\r\n multiSignerContext?: { isMultiSigner: boolean; currentSigner: any; currentSignerEmail: string; isPrimarySigner: boolean; isFinalSigner: boolean }\r\n): Promise<Uint8Array> {\r\n try {\r\n const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const pages = pdfDoc.getPages();\r\n \r\n // Get field positions and page numbers\r\n const { pageMap: fieldPageMap, positionMap: fieldPositionMap } = await getFieldPageNumbers(pdfBytes);\r\n \r\n // STEP 1: Fill all text form fields\r\n \r\n const fields = form.getFields();\r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const fieldValue = formFieldValues[fieldName];\r\n \r\n if (!fieldValue) {\r\n // Log missing values for radio fields to diagnose\r\n if (fieldName.includes('radio')) {\r\n }\r\n continue;\r\n }\r\n \r\n try {\r\n // Use duck typing for field type detection (minification-safe)\r\n // Constructor names get renamed during minification, breaking string comparisons\r\n const f = field as any;\r\n const isTextField = typeof f.getText === 'function' && typeof f.setText === 'function';\r\n const isCheckbox = typeof f.check === 'function' && typeof f.uncheck === 'function';\r\n const isRadio = typeof f.select === 'function' &&\r\n typeof f.getOptions === 'function' &&\r\n typeof f.check !== 'function' &&\r\n typeof f.setOptions !== 'function';\r\n const isDropdown = typeof f.select === 'function' &&\r\n (typeof f.setOptions === 'function' || typeof f.addOptions === 'function');\r\n\r\n // Handle text fields\r\n if (isTextField) {\r\n f.setText?.(fieldValue);\r\n }\r\n // Handle checkbox fields\r\n else if (isCheckbox) {\r\n if (fieldValue === 'true' || fieldValue === 'Yes' || fieldValue === 'checked' || fieldValue === 'On') {\r\n f.check?.();\r\n } else {\r\n f.uncheck?.();\r\n }\r\n }\r\n // Handle radio group fields\r\n else if (isRadio) {\r\n // Skip invalid values (boolean strings from checkbox-like behavior)\r\n if (fieldValue === 'true' || fieldValue === 'false') {\r\n continue;\r\n }\r\n\r\n // Handle __RADIO_OPTION_INDEX_ pattern\r\n const idxMatch = fieldValue.match(/__RADIO_OPTION_INDEX_(\\d+)__/);\r\n if (idxMatch && idxMatch[1]) {\r\n const selectedIndex = parseInt(idxMatch[1], 10);\r\n const options = f.getOptions?.() || [];\r\n if (selectedIndex >= 0 && selectedIndex < options.length) {\r\n f.select?.(options[selectedIndex]);\r\n }\r\n } else {\r\n // Try to use the value directly if it's a valid option\r\n const options = f.getOptions?.() || [];\r\n if (options.includes(fieldValue)) {\r\n f.select?.(fieldValue);\r\n } else {\r\n }\r\n }\r\n }\r\n // Handle dropdown fields\r\n else if (isDropdown) {\r\n f.select?.(fieldValue);\r\n }\r\n } catch (fieldError) {\r\n logger.error(`Error setting field \"${fieldName}\":`, fieldError);\r\n }\r\n }\r\n\r\n // Update form field appearances to ensure radio button selections render correctly\r\n // This is critical for radio buttons to display properly in PDF viewers\r\n // Fix based on dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n try {\r\n form.updateFieldAppearances();\r\n \r\n // NOTE: We skip setting NeedAppearances to false because accessing the catalog\r\n // can corrupt the PDF structure. Modern PDF viewers handle this correctly without it.\r\n \r\n } catch (appearanceError) {\r\n // Some PDFs may not support this operation - fail gracefully\r\n logger.warn('Could not update field appearances:', appearanceError);\r\n }\r\n\r\n // STEP 2: Apply signature images to ALL signature fields\r\n const mainSignatureData = signatures['signature_field_main'];\r\n if (mainSignatureData && mainSignatureData.trim()) {\r\n \r\n // Find ALL signature field names (excluding text_ prefix and non-signature fields)\r\n // Match dockmaster patterns including '_es_:signer:signature' for esign integration\r\n const signatureFieldNames = [\r\n 'signature', 'Signature', 'SIGNATURE',\r\n 'sign', 'Sign', 'SIGN',\r\n '_es_:signer:signature'\r\n ];\r\n let foundSignatureFields = Object.keys(fieldPageMap).filter(fieldName => {\r\n const hasSignaturePattern = signatureFieldNames.some(pattern => \r\n fieldName.toLowerCase().includes(pattern.toLowerCase())\r\n );\r\n const isNotTextField = !fieldName.toLowerCase().startsWith('text_');\r\n return hasSignaturePattern && isNotTextField;\r\n });\r\n \r\n // CRITICAL: Filter to only ACTUAL signature fields, not checkbox/radio/dropdown\r\n if (extractedFormFields && extractedFormFields.length > 0) {\r\n const currentSignerSignatureFields = foundSignatureFields.filter(fieldName => {\r\n const fieldInfo = extractedFormFields.find(f => f.name === fieldName);\r\n if (!fieldInfo) {\r\n return false;\r\n }\r\n \r\n // CRITICAL FIX: Only process ACTUAL signature fields, NOT initials\r\n // Signature images should ONLY be applied to signature fields\r\n // Initials are handled separately as text (not images)\r\n // Fix based on dm-web-frontend commit 30895b5 (Oct 29, 2025)\r\n const isActualSignatureField = (fieldInfo.type === 'signature' ||\r\n fieldName.toLowerCase().includes('signature'))\r\n && !fieldName.toLowerCase().includes('initials'); // Explicitly exclude initials\r\n\r\n if (!isActualSignatureField) {\r\n return false;\r\n }\r\n \r\n // Use centralized visibility logic for multi-signer and single-signer modes\r\n const isVisible = multiSignerContext \r\n ? isFieldVisibleToSigner(fieldInfo, multiSignerContext)\r\n : true; // Single signer mode: all fields visible\r\n \r\n return isVisible;\r\n });\r\n foundSignatureFields = currentSignerSignatureFields;\r\n }\r\n \r\n \r\n if (foundSignatureFields.length > 0) {\r\n try {\r\n // Detect image format with binary signature detection\r\n let signatureImage;\r\n if (mainSignatureData.includes('data:image/png')) {\r\n signatureImage = await pdfDoc.embedPng(mainSignatureData);\r\n } else if (mainSignatureData.includes('data:image/jpeg') || mainSignatureData.includes('data:image/jpg')) {\r\n signatureImage = await pdfDoc.embedJpg(mainSignatureData);\r\n } else {\r\n // Fallback: detect by binary signature\r\n const base64Data = mainSignatureData.split(',')[1];\r\n if (!base64Data) {\r\n throw new Error('Invalid signature data format: missing base64 data');\r\n }\r\n const binaryData = atob(base64Data);\r\n \r\n // Check PNG signature (first 8 bytes: 89 50 4E 47 0D 0A 1A 0A)\r\n if (binaryData.charCodeAt(0) === 0x89 && \r\n binaryData.charCodeAt(1) === 0x50 && \r\n binaryData.charCodeAt(2) === 0x4E && \r\n binaryData.charCodeAt(3) === 0x47) {\r\n signatureImage = await pdfDoc.embedPng(mainSignatureData);\r\n } \r\n // Check JPEG signature (first 3 bytes: FF D8 FF)\r\n else if (binaryData.charCodeAt(0) === 0xFF && \r\n binaryData.charCodeAt(1) === 0xD8 && \r\n binaryData.charCodeAt(2) === 0xFF) {\r\n signatureImage = await pdfDoc.embedJpg(mainSignatureData);\r\n } \r\n else {\r\n throw new Error('Unsupported image format. Please use PNG or JPEG.');\r\n }\r\n }\r\n \r\n // Draw signature images using EXACT field coordinates\r\n for (const fieldName of foundSignatureFields) {\r\n \r\n const pageNumber = fieldPageMap[fieldName];\r\n \r\n if (pageNumber && pageNumber <= pages.length) {\r\n const page = pages[pageNumber - 1]; // Convert to 0-based index\r\n if (!page) continue;\r\n \r\n // Get EXACT field position from the map\r\n const fieldPosition = fieldPositionMap[fieldName];\r\n \r\n if (fieldPosition) {\r\n // Use EXACT field coordinates (NO CENTERING)\r\n const x = fieldPosition.x;\r\n const y = fieldPosition.y;\r\n const width = Math.max(fieldPosition.width, 80);\r\n const height = Math.max(fieldPosition.height, 30);\r\n \r\n // Draw label above signature field (same sizing as text fields)\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n const labelFontSize = Math.min(10, height * 0.4);\r\n const labelX = x;\r\n const labelY = y + height + 5; // Above the field\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Scale signature to fit the field\r\n const signatureDims = signatureImage.scaleToFit(width - 4, height - 4);\r\n \r\n // FIXED POSITIONING: Use exact field coordinates\r\n const finalX = x;\r\n const finalY = y;\r\n \r\n \r\n page.drawImage(signatureImage, {\r\n x: finalX,\r\n y: finalY,\r\n width: signatureDims.width,\r\n height: signatureDims.height,\r\n });\r\n \r\n } else {\r\n }\r\n } else {\r\n }\r\n }\r\n } catch (error) {\r\n logger.error('Error applying signatures:', error);\r\n }\r\n }\r\n }\r\n \r\n // STEP 3: Apply initials to ALL initials fields\r\n console.log('[FLATTEN] === APPLYING INITIALS ===');\r\n console.log('[FLATTEN] formFieldValues keys:', Object.keys(formFieldValues));\r\n console.log('[FLATTEN] Initials fields in formFieldValues:', Object.keys(formFieldValues).filter(k => k.toLowerCase().includes('initials')));\r\n const mainInitialsData = formFieldValues['initials_field_main'];\r\n console.log('[FLATTEN] mainInitialsData from initials_field_main:', mainInitialsData ? mainInitialsData.substring(0, 50) : '(MISSING)');\r\n if (mainInitialsData && mainInitialsData.trim()) {\r\n \r\n console.log('[FLATTEN] fieldPageMap keys:', Object.keys(fieldPageMap));\r\n console.log('[FLATTEN] Looking for initials fields in fieldPageMap...');\r\n\r\n const initialsFieldNames = ['initials', 'Initials', 'INITIALS'];\r\n let foundInitialsFields = Object.keys(fieldPageMap).filter(fieldName =>\r\n initialsFieldNames.some(pattern => fieldName.toLowerCase().includes(pattern.toLowerCase()))\r\n );\r\n console.log('[FLATTEN] After pattern matching in fieldPageMap:', foundInitialsFields);\r\n\r\n // Filter by signer if needed\r\n if (extractedFormFields && extractedFormFields.length > 0) {\r\n foundInitialsFields = foundInitialsFields.filter(fieldName => {\r\n // Try exact name match first, then strip suffix for fallback\r\n const fieldInfo = extractedFormFields.find(f => f.name === fieldName)\r\n || extractedFormFields.find(f => f.name === fieldName.replace(/_initials$/i, ''))\r\n || extractedFormFields.find(f => fieldName.startsWith(f.name));\r\n if (!fieldInfo) return false;\r\n\r\n const isActualInitialsField = fieldInfo.type === 'initials' ||\r\n fieldName.toLowerCase().includes('initials');\r\n if (!isActualInitialsField) return false;\r\n\r\n // Use centralized visibility logic for multi-signer and single-signer modes\r\n const isVisible = multiSignerContext\r\n ? isFieldVisibleToSigner(fieldInfo, multiSignerContext)\r\n : true; // Single signer mode: all fields visible\r\n\r\n return isVisible;\r\n });\r\n }\r\n\r\n console.log('[FLATTEN] Found', foundInitialsFields.length, 'initials fields to flatten:', foundInitialsFields);\r\n if (foundInitialsFields.length > 0) {\r\n try {\r\n const font = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n\r\n for (const fieldName of foundInitialsFields) {\r\n console.log('[FLATTEN] Processing initials field:', fieldName);\r\n const pageNumber = fieldPageMap[fieldName];\r\n console.log('[FLATTEN] Page number:', pageNumber);\r\n if (pageNumber && pageNumber <= pages.length) {\r\n const page = pages[pageNumber - 1];\r\n if (!page) {\r\n console.log('[FLATTEN] ❌ Page not found');\r\n continue;\r\n }\r\n\r\n const fieldPosition = fieldPositionMap[fieldName];\r\n console.log('[FLATTEN] Field position:', fieldPosition);\r\n if (fieldPosition) {\r\n const x = fieldPosition.x;\r\n const y = fieldPosition.y;\r\n const height = Math.max(fieldPosition.height, 20);\r\n\r\n const fontSize = Math.min(height * 0.7, 14);\r\n\r\n // Draw label above initials field\r\n // Try multiple matching strategies: exact name, stripped suffix, prefix, fieldId\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName)\r\n || extractedFormFields?.find(f => f.name === fieldName.replace(/_initials$/i, ''))\r\n || extractedFormFields?.find(f => fieldName.startsWith(f.name))\r\n || extractedFormFields?.find(f => f.fieldId && fieldName.includes(f.fieldId))\r\n || extractedFormFields?.find(f => f.type === 'initials' && f.name !== 'initials_field_main');\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFontSize = Math.min(10, height * 0.4);\r\n const labelX = x;\r\n const labelY = y + height + 5; // Above the field\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n\r\n // EXACT positioning (no centering)\r\n const finalX = x + 2;\r\n const finalY = y + (height - fontSize) / 2;\r\n\r\n console.log('[FLATTEN] ✅ Drawing initials at:', { x: finalX, y: finalY, fontSize, text: mainInitialsData });\r\n page.drawText(mainInitialsData, {\r\n x: finalX,\r\n y: finalY,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n\r\n } else {\r\n console.log('[FLATTEN] ❌ Field position not found in position map');\r\n }\r\n } else {\r\n console.log('[FLATTEN] ❌ Invalid page number or page out of bounds');\r\n }\r\n }\r\n } catch (error) {\r\n logger.error('Error applying initials:', error);\r\n }\r\n }\r\n }\r\n \r\n // STEP 4: Flatten form fields based on multi-signer mode\r\n \r\n const allFormFields = form.getFields();\r\n \r\n let fieldsToFlatten;\r\n \r\n if (multiSignerContext?.isMultiSigner) {\r\n // PARTIAL FLATTENING: Only flatten current signer's fields (Dockmaster logic lines 2500-2526)\r\n \r\n fieldsToFlatten = allFormFields.filter(f => {\r\n const fieldName = f.getName();\r\n \r\n if (!extractedFormFields || extractedFormFields.length === 0) {\r\n return true; // Flatten all if no field info\r\n }\r\n \r\n const fieldInfo = extractedFormFields.find(fi => fi.name === fieldName);\r\n if (!fieldInfo) {\r\n return true; // Flatten unknown fields\r\n }\r\n \r\n // Use centralized flattening logic\r\n return shouldFlattenField(fieldInfo, multiSignerContext);\r\n });\r\n } else {\r\n // COMPLETE FLATTENING: Flatten all fields (single signer mode)\r\n fieldsToFlatten = allFormFields;\r\n }\r\n \r\n // Helper interfaces for widget access\r\n interface PDFFieldWithAcro {\r\n acroField?: {\r\n getWidgets?: () => PDFWidget[];\r\n dict?: any;\r\n };\r\n }\r\n \r\n let flattenedCount = 0;\r\n \r\n for (const field of fieldsToFlatten) {\r\n const fieldName = field.getName();\r\n\r\n // Use duck typing for field type detection (minification-safe)\r\n // Constructor names get renamed during minification, breaking string comparisons\r\n const f = field as any;\r\n const isCheckboxField = typeof f.check === 'function' && typeof f.uncheck === 'function';\r\n const isRadioField = typeof f.select === 'function' &&\r\n typeof f.getOptions === 'function' &&\r\n typeof f.check !== 'function' &&\r\n typeof f.setOptions !== 'function';\r\n const isDropdownField = typeof f.select === 'function' &&\r\n (typeof f.setOptions === 'function' || typeof f.addOptions === 'function');\r\n const isTextField = typeof f.getText === 'function' && typeof f.setText === 'function';\r\n // Signature fields have no editable methods\r\n const isSignatureType = !isCheckboxField && !isRadioField && !isDropdownField && !isTextField;\r\n\r\n try {\r\n // Get user entered value\r\n const userEnteredValue = formFieldValues[fieldName];\r\n\r\n // Check if this is a signature/initials field\r\n const isSignatureField = fieldName.toLowerCase().includes('signature') || isSignatureType;\r\n const isInitialsField = fieldName.toLowerCase().includes('initials');\r\n\r\n if (isSignatureField || isInitialsField) {\r\n // Signature/initials fields were already drawn in STEP 2/3, just remove the field\r\n form.removeField(field);\r\n flattenedCount++;\r\n continue;\r\n }\r\n\r\n // Get field widgets for drawing\r\n const fieldWithWidgets = field as unknown as PDFFieldWithAcro;\r\n const widgets = fieldWithWidgets.acroField?.getWidgets?.() || [];\r\n\r\n // Handle different field types - draw their content\r\n if (isCheckboxField) {\r\n // Checkbox field - draw checkbox with checkmark if checked\r\n const stringValue = String(userEnteredValue || '');\r\n const isChecked = stringValue === 'true' || stringValue === 'Yes' || \r\n stringValue === 'On' || stringValue === 'checked';\r\n \r\n // Get field info for label\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n const labelFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n \r\n if (isChecked) {\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw checkbox label to the right\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFontSize = Math.min(10, rect.height * 0.4);\r\n const labelX = rect.x + rect.width + 5; // To the right of checkbox\r\n const labelY = rect.y + (rect.height - labelFontSize) / 2;\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw checkbox border - use full field rect size\r\n const checkboxSize = Math.min(rect.width, rect.height);\r\n const checkboxX = rect.x + (rect.width - checkboxSize) / 2;\r\n const checkboxY = rect.y + (rect.height - checkboxSize) / 2;\r\n\r\n page.drawRectangle({\r\n x: checkboxX,\r\n y: checkboxY,\r\n width: checkboxSize,\r\n height: checkboxSize,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n });\r\n\r\n // Draw X using proper font metrics for centering\r\n const checkFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n const checkFontSize = checkboxSize * 0.7;\r\n const textWidth = checkFont.widthOfTextAtSize('X', checkFontSize);\r\n const textHeight = checkFont.heightAtSize(checkFontSize);\r\n\r\n page.drawText('X', {\r\n x: checkboxX + (checkboxSize - textWidth) / 2,\r\n y: checkboxY + (checkboxSize - textHeight) / 2 + textHeight * 0.15,\r\n size: checkFontSize,\r\n font: checkFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n \r\n }\r\n } else {\r\n // Draw checkbox border and label even when unchecked\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw checkbox border (empty, no checkmark) - use full field rect size\r\n const checkboxSize = Math.min(rect.width, rect.height);\r\n const checkboxX = rect.x + (rect.width - checkboxSize) / 2;\r\n const checkboxY = rect.y + (rect.height - checkboxSize) / 2;\r\n\r\n page.drawRectangle({\r\n x: checkboxX,\r\n y: checkboxY,\r\n width: checkboxSize,\r\n height: checkboxSize,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n });\r\n \r\n // Draw label if present\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFontSize = Math.min(12, rect.height * 0.6);\r\n const labelX = rect.x + rect.width + 5;\r\n const labelY = rect.y + (rect.height - labelFontSize) / 2;\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n }\r\n }\r\n } else if (isRadioField) {\r\n // Radio group field - draw all radio buttons, fill the selected one\r\n const radioGroup = f;\r\n \r\n // Get field info for labels and options (need this before determining selectedIndex)\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n \r\n // Get the ACTUAL selected value from the PDF field (after it was set)\r\n let actualSelectedValue = '';\r\n try {\r\n actualSelectedValue = radioGroup.getSelected?.() || '';\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: radioGroup.getSelected() returned: \"${actualSelectedValue}\"`);\r\n } catch (e) {\r\n // Fallback to user entered value if we can't read the field\r\n actualSelectedValue = userEnteredValue ? String(userEnteredValue) : '';\r\n logger.warn(`[FLATTEN RADIO] Field ${fieldName}: could not read selected value, using userEnteredValue: \"${actualSelectedValue}\"`);\r\n }\r\n \r\n // Determine selected index\r\n let selectedIndex = -1;\r\n \r\n // Get all options from the radio group\r\n const radioOptions = radioGroup.getOptions?.() || [];\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: radioGroup.getOptions() returned ${radioOptions.length} options:`, radioOptions);\r\n \r\n // If we have an actual selected value from the field, find its index\r\n if (actualSelectedValue && radioOptions.length > 0) {\r\n selectedIndex = radioOptions.findIndex((opt: string) => opt === actualSelectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: found actualSelectedValue \"${actualSelectedValue}\" at index ${selectedIndex}`);\r\n }\r\n \r\n // Fallback: try to parse from user entered value if we didn't find it above\r\n if (selectedIndex === -1 && userEnteredValue) {\r\n const selectedValue = String(userEnteredValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: selectedIndex still -1, trying to parse from userEnteredValue: \"${selectedValue}\"`);\r\n \r\n // Handle __RADIO_OPTION_INDEX_ pattern directly\r\n if (selectedValue.startsWith('__RADIO_OPTION_INDEX_')) {\r\n const indexMatch = selectedValue.match(/__RADIO_OPTION_INDEX_(\\d+)__/);\r\n if (indexMatch && indexMatch[1]) {\r\n selectedIndex = parseInt(indexMatch[1], 10);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: extracted index ${selectedIndex} from __RADIO_OPTION_INDEX_ pattern`);\r\n }\r\n } \r\n // Handle numeric string (just an index)\r\n else if (/^\\d+$/.test(selectedValue)) {\r\n selectedIndex = parseInt(selectedValue, 10);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: parsed numeric index ${selectedIndex}`);\r\n }\r\n // Match against actual option values from field info\r\n else if (fieldInfo?.options && selectedValue) {\r\n selectedIndex = fieldInfo.options.findIndex(option => option === selectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: matched \"${selectedValue}\" in fieldInfo.options at index ${selectedIndex}`);\r\n }\r\n // Match against radio group options\r\n else if (radioOptions.length > 0) {\r\n selectedIndex = radioOptions.findIndex((opt: string) => opt === selectedValue);\r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: matched \"${selectedValue}\" in radioOptions at index ${selectedIndex}`);\r\n }\r\n }\r\n \r\n logger.info(`[FLATTEN RADIO] Field ${fieldName}: FINAL selectedIndex = ${selectedIndex}, will draw filled circle at this index`);\r\n const labelFont = await pdfDoc.embedFont('Helvetica-Bold');\r\n const drawnGroupLabels = new Set<string>();\r\n const drawnOptionLabels = new Set<string>();\r\n \r\n // Draw borders for ALL radio buttons\r\n for (let i = 0; i < widgets.length; i++) {\r\n const widget = widgets[i];\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page, pageIndex } = result;\r\n \r\n // Draw radio GROUP label (once, above first widget)\r\n // Only draw if it's a user-typed custom label (not auto-generated)\r\n if (i === 0 && fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const groupLabelKey = `${pageIndex}-${fieldName}-grouplabel`;\r\n if (!drawnGroupLabels.has(groupLabelKey)) {\r\n const labelFontSize = Math.min(10, rect.height * 0.4);\r\n const labelY = rect.y + rect.height + 3;\r\n page.drawText(fieldInfo.label, {\r\n x: rect.x,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnGroupLabels.add(groupLabelKey);\r\n }\r\n } else if (i === 0 && isAutoGeneratedLabel(fieldInfo?.label || '')) {\r\n }\r\n \r\n // Draw radio button border (circle)\r\n const radioSize = Math.min(rect.width, rect.height);\r\n const centerX = rect.x + rect.width / 2;\r\n const centerY = rect.y + rect.height / 2;\r\n\r\n page.drawCircle({\r\n x: centerX,\r\n y: centerY,\r\n size: radioSize / 2,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n });\r\n\r\n // Draw filled circle ONLY for selected option\r\n if (i === selectedIndex) {\r\n page.drawCircle({\r\n x: centerX,\r\n y: centerY,\r\n size: radioSize / 4,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n\r\n // Draw option text next to each radio button\r\n // Same positioning as preview (pdf-viewer-filter.ts)\r\n if (fieldInfo?.options && fieldInfo.options.length > i) {\r\n const optionText = fieldInfo.options[i];\r\n const optionKey = `${pageIndex}-${fieldName}-opt-${i}`;\r\n\r\n if (optionText && !drawnOptionLabels.has(optionKey)) {\r\n page.drawText(optionText, {\r\n x: rect.x + rect.width + 4,\r\n y: rect.y + (rect.height - 7) / 2,\r\n size: 7,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOptionLabels.add(optionKey);\r\n }\r\n }\r\n }\r\n \r\n if (fieldInfo?.options) {\r\n }\r\n } else if (isDropdownField) {\r\n // Dropdown field - draw the selected value with 14px font\r\n const selectedValue = userEnteredValue ? String(userEnteredValue) : '';\r\n \r\n // Get field info for label\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n const labelFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n \r\n // Draw label for dropdown fields (even when empty)\r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw label above the field\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFontSize = Math.min(10, rect.height * 0.4);\r\n const labelX = rect.x;\r\n const labelY = rect.y + rect.height + 5;\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw value only if present\r\n if (selectedValue && selectedValue.trim()) {\r\n page.drawText(selectedValue, {\r\n x: rect.x + 2,\r\n y: rect.y + 2,\r\n size: 14,\r\n font: await pdfDoc.embedFont(StandardFonts.Helvetica),\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n }\r\n } else {\r\n // Text field or other field types (including date) - draw the field value\r\n const fieldValue = userEnteredValue ? String(userEnteredValue) : '';\r\n \r\n // Get field info for label\r\n const fieldInfo = extractedFormFields?.find(f => f.name === fieldName);\r\n const labelFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);\r\n \r\n // Draw label for text/date fields (even when empty)\r\n // Check if this is a date field\r\n const isDateField = fieldName.toLowerCase().includes('date') || fieldName.toLowerCase().includes('_date');\r\n \r\n // Use 14px for date fields, otherwise extract font size\r\n const fontSize = isDateField ? 14 : extractFieldFontSize(fieldName, field, extractedFormFields);\r\n \r\n for (const widget of widgets) {\r\n const result = getWidgetRectangleAndPage(widget as unknown as PDFWidgetWithExtensions, pages);\r\n if (!result) continue;\r\n \r\n const { rect, page } = result;\r\n \r\n // Draw label above the field (dm-web-frontend pattern)\r\n if (fieldInfo && hasDrawableLabel(fieldInfo)) {\r\n const labelFontSize = Math.min(10, rect.height * 0.4);\r\n const labelX = rect.x;\r\n const labelY = rect.y + rect.height + 5; // Above the field\r\n page.drawText(fieldInfo.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw value only if present\r\n if (fieldValue && fieldValue.trim()) {\r\n page.drawText(fieldValue, {\r\n x: rect.x + 2,\r\n y: rect.y + 2,\r\n size: fontSize,\r\n font: await pdfDoc.embedFont(StandardFonts.Helvetica),\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n }\r\n }\r\n \r\n // Remove the field to flatten it\r\n form.removeField(field);\r\n flattenedCount++;\r\n } catch (error) {\r\n }\r\n }\r\n \r\n const remainingFields = form.getFields();\r\n \r\n // Verify flattening worked\r\n if (multiSignerContext?.isMultiSigner) {\r\n // MULTI-SIGNER MODE: Remaining fields are EXPECTED (for other signers)\r\n const expectedRemainingCount = allFormFields.length - fieldsToFlatten.length;\r\n if (remainingFields.length === expectedRemainingCount) {\r\n } else {\r\n }\r\n } else {\r\n // SINGLE-SIGNER MODE: All fields should be flattened\r\n if (remainingFields.length > 0) {\r\n logger.error(`MANUAL FLATTENING INCOMPLETE: ${remainingFields.length} fields still exist!`);\r\n logger.error(`Remaining fields:`, remainingFields.map(f => f.getName()));\r\n \r\n // Try basic flattening as final fallback (only in single-signer mode)\r\n try {\r\n form.flatten();\r\n const finalRemainingFields = form.getFields();\r\n \r\n if (finalRemainingFields.length > 0) {\r\n logger.error(`ALL FLATTENING METHODS FAILED: ${finalRemainingFields.length} fields still exist!`);\r\n logger.error(`Final remaining fields:`, finalRemainingFields.map(f => f.getName()));\r\n }\r\n } catch (fallbackError) {\r\n logger.error('Fallback flattening failed:', fallbackError);\r\n }\r\n } else {\r\n }\r\n }\r\n \r\n // STEP 6: Set document metadata for tracking and compliance\r\n try {\r\n // Set document metadata based on submission data\r\n // Set Title (with default if not provided)\r\n const documentTitle = metadata?.documentId \r\n ? `Document ID: ${metadata.documentId}`\r\n : 'Signed Document';\r\n pdfDoc.setTitle(documentTitle);\r\n \r\n // Set Subject (with default if not provided)\r\n const documentSubject = metadata?.submissionId\r\n ? `Submission ID: ${metadata.submissionId}`\r\n : metadata?.signerEmail\r\n ? `Signed by ${metadata.signerEmail}`\r\n : 'Digitally Signed Document';\r\n pdfDoc.setSubject(documentSubject);\r\n \r\n // Set Author (with default if not provided)\r\n const documentAuthor = metadata?.author || metadata?.signerEmail || 'Unknown';\r\n pdfDoc.setAuthor(documentAuthor);\r\n \r\n pdfDoc.setProducer('Created by signiphi (https://signiphi.ai/)');\r\n \r\n if (metadata?.signerEmail) {\r\n pdfDoc.setCreator(`Signer: ${metadata.signerEmail}`);\r\n }\r\n \r\n // Set creation date from submission\r\n if (metadata?.createdAt) {\r\n pdfDoc.setCreationDate(metadata.createdAt);\r\n }\r\n \r\n // Set current date as modification date\r\n pdfDoc.setModificationDate(new Date());\r\n \r\n // Set keywords for searchability and tracking\r\n const keywords: string[] = [];\r\n \r\n // Add signer email if available\r\n if (metadata?.signerEmail) {\r\n keywords.push(metadata.signerEmail);\r\n }\r\n \r\n // Add initials to metadata if available\r\n if (metadata?.signerInitials && metadata.signerInitials.trim()) {\r\n keywords.push(`Initials:${metadata.signerInitials.trim()}`);\r\n }\r\n \r\n // Add audit trail data for compliance and forensics\r\n if (auditTrail) {\r\n try {\r\n // Device/Browser information\r\n if (auditTrail.userAgent) {\r\n keywords.push(`UserAgent:${auditTrail.userAgent}`);\r\n }\r\n \r\n // Screen resolution as device identifier\r\n if (auditTrail.screenResolution) {\r\n keywords.push(`Screen:${auditTrail.screenResolution}`);\r\n }\r\n \r\n // Timezone\r\n if (auditTrail.timezone) {\r\n keywords.push(`Timezone:${auditTrail.timezone}`);\r\n }\r\n \r\n // Language settings\r\n if (auditTrail.language) {\r\n keywords.push(`Language:${auditTrail.language}`);\r\n }\r\n \r\n // Platform information\r\n if (auditTrail.platform) {\r\n keywords.push(`Platform:${auditTrail.platform}`);\r\n }\r\n \r\n // IP address\r\n if (auditTrail.ipAddress) {\r\n keywords.push(`IP:${auditTrail.ipAddress}`);\r\n }\r\n \r\n // Geolocation data\r\n if (auditTrail.geolocation) {\r\n const { latitude, longitude, accuracy } = auditTrail.geolocation;\r\n const lat = latitude.toFixed(4);\r\n const lon = longitude.toFixed(4);\r\n keywords.push(`Location:${lat},${lon}`);\r\n \r\n // Add accuracy if available\r\n if (accuracy !== undefined) {\r\n keywords.push(`LocationAccuracy:${accuracy}m`);\r\n }\r\n }\r\n } catch (auditError) {\r\n logger.warn('⚠️ Error adding audit trail to keywords:', auditError)\r\n }\r\n }\r\n \r\n if (keywords.length > 0) {\r\n pdfDoc.setKeywords(keywords);\r\n }\r\n } catch (error) {\r\n logger.error('Failed to set document metadata:', error);\r\n }\r\n \r\n const finalPdfBytes = await pdfDoc.save();\r\n return finalPdfBytes;\r\n } catch (error) {\r\n logger.error('Error filling PDF with signatures:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Fill form fields and replace signature/initials with actual signature images\r\n * This is used when fields are rendered as overlays on the PDF\r\n * @param pdfBytes - The PDF bytes\r\n * @param formFields - The form fields with their positions\r\n * @param fieldValues - The field values to fill\r\n * @param signatures - The signature images (base64 data URLs)\r\n * @returns The filled PDF bytes\r\n */\r\nexport async function fillFormFieldsWithSignatures(\r\n pdfBytes: Uint8Array,\r\n formFields: EsignFormField[],\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>\r\n): Promise<Uint8Array> {\r\n try {\r\n const { PDFDocument, rgb, StandardFonts } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const pages = pdfDoc.getPages();\r\n const font = await pdfDoc.embedFont(StandardFonts.Helvetica);\r\n\r\n for (const field of formFields) {\r\n const pageIndex = field.position.page - 1;\r\n \r\n if (pageIndex < 0 || pageIndex >= pages.length) {\r\n continue;\r\n }\r\n\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const { height: pageHeight } = page.getSize();\r\n\r\n // Convert coordinates from top-left (UI) to bottom-left (PDF)\r\n const pdfX = field.position.x;\r\n const pdfY = pageHeight - field.position.y - field.position.height;\r\n\r\n try {\r\n switch (field.type) {\r\n case FormFieldType.TEXT: {\r\n const value = fieldValues[field.id] || '';\r\n \r\n // Draw label above field\r\n if (hasDrawableLabel(field)) {\r\n const labelFontSize = Math.min(10, field.position.height * 0.4);\r\n const labelX = pdfX;\r\n const labelY = pdfY + field.position.height + 5;\r\n page.drawText(field.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw value if present\r\n if (value) {\r\n const fontSize = field.fontSize && field.fontSize >= 8 && field.fontSize <= 72\r\n ? field.fontSize\r\n : Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.DATE: {\r\n const value = fieldValues[field.id] || '';\r\n \r\n // Draw label above field\r\n if (hasDrawableLabel(field)) {\r\n const labelFontSize = Math.min(10, field.position.height * 0.4);\r\n const labelX = pdfX;\r\n const labelY = pdfY + field.position.height + 5;\r\n page.drawText(field.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw value if present\r\n if (value) {\r\n const fontSize = field.fontSize && field.fontSize >= 8 && field.fontSize <= 72 \r\n ? field.fontSize \r\n : Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.CHECKBOX: {\r\n const value = fieldValues[field.id] || '';\r\n \r\n // Draw checkbox border for both checked and unchecked states\r\n const checkboxSize = Math.min(field.position.width, field.position.height) * 0.7;\r\n const checkboxX = pdfX + (field.position.width - checkboxSize) / 2;\r\n const checkboxY = pdfY + (field.position.height - checkboxSize) / 2;\r\n \r\n page.drawRectangle({\r\n x: checkboxX,\r\n y: checkboxY,\r\n width: checkboxSize,\r\n height: checkboxSize,\r\n borderColor: rgb(0, 0, 0),\r\n borderWidth: 1,\r\n color: rgb(1, 1, 1),\r\n });\r\n \r\n // Draw checkmark if checked\r\n if (value === 'true') {\r\n const checkSize = checkboxSize * 0.7;\r\n const checkX = checkboxX + (checkboxSize - checkSize) / 2;\r\n const checkY = checkboxY + (checkboxSize - checkSize) / 2;\r\n \r\n page.drawText('✓', {\r\n x: checkX,\r\n y: checkY,\r\n size: checkSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n break;\r\n }\r\n\r\n case FormFieldType.SIGNATURE: {\r\n const signatureDataUrl = signatures[field.id];\r\n if (signatureDataUrl) {\r\n // Convert base64 data URL to image bytes\r\n const base64Data = signatureDataUrl.split(',')[1];\r\n if (!base64Data) {\r\n logger.error('Invalid signature data URL format for field:', field.id);\r\n break;\r\n }\r\n const imageBytes = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));\r\n \r\n // Embed the image\r\n const image = await pdfDoc.embedPng(imageBytes);\r\n \r\n // Calculate dimensions to fit within the field while maintaining aspect ratio\r\n const imageSize = image.size();\r\n const fieldAspectRatio = field.position.width / field.position.height;\r\n const imageAspectRatio = imageSize.width / imageSize.height;\r\n \r\n let drawWidth = field.position.width;\r\n let drawHeight = field.position.height;\r\n \r\n if (imageAspectRatio > fieldAspectRatio) {\r\n // Image is wider than field - fit to width\r\n drawHeight = drawWidth / imageAspectRatio;\r\n } else {\r\n // Image is taller than field - fit to height\r\n drawWidth = drawHeight * imageAspectRatio;\r\n }\r\n \r\n // Center the image within the field\r\n const imageX = pdfX + (field.position.width - drawWidth) / 2;\r\n const imageY = pdfY + (field.position.height - drawHeight) / 2;\r\n \r\n // Draw the image\r\n page.drawImage(image, {\r\n x: imageX,\r\n y: imageY,\r\n width: drawWidth,\r\n height: drawHeight,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.INITIALS: {\r\n const value = fieldValues[field.id] || '';\r\n if (value) {\r\n // Use a cursive font for initials\r\n const fontSize = Math.min(18, field.position.height * 0.8);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case FormFieldType.DROPDOWN: {\r\n const value = fieldValues[field.id] || '';\r\n \r\n // Draw label above field\r\n if (hasDrawableLabel(field)) {\r\n const labelFontSize = Math.min(10, field.position.height * 0.4);\r\n const labelX = pdfX;\r\n const labelY = pdfY + field.position.height + 5; // Above the field\r\n page.drawText(field.label, {\r\n x: labelX,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n \r\n // Draw value if present\r\n if (value) {\r\n const fontSize = Math.min(12, field.position.height * 0.6);\r\n page.drawText(value, {\r\n x: pdfX + 2,\r\n y: pdfY + (field.position.height - fontSize) / 2,\r\n size: fontSize,\r\n font: font,\r\n color: rgb(0, 0, 0),\r\n maxWidth: field.position.width - 4,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n default:\r\n break;\r\n }\r\n } catch (fieldError) {\r\n logger.error(`Error processing field ${field.name}:`, fieldError);\r\n }\r\n }\r\n\r\n return await pdfDoc.save();\r\n} catch (error) {\r\n logger.error('Error filling form fields:', error);\r\n throw error;\r\n}\r\n}\r\n\r\n/**\r\n * Extract field positions and page numbers from a PDF document\r\n * Returns maps for field name -> page number and field name -> position\r\n */\r\nexport async function getFieldPageNumbers(\r\n pdfBytes: Uint8Array\r\n): Promise<{\r\n pageMap: Record<string, number>;\r\n positionMap: Record<string, FormFieldPosition>;\r\n}> {\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n const pages = pdfDoc.getPages();\r\n\r\n const pageMap: Record<string, number> = {};\r\n const positionMap: Record<string, FormFieldPosition> = {};\r\n\r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const fieldWithAcro = field as unknown as PDFFieldWithAcro;\r\n const widgets = fieldWithAcro.acroField?.getWidgets?.() ?? [];\r\n\r\n if (widgets.length > 0) {\r\n // Use the first widget to determine page and position\r\n const widget = widgets[0];\r\n if (!widget) continue;\r\n const rect = widget.getRectangle?.();\r\n const pageRef = widget.P?.();\r\n\r\n if (rect && pageRef) {\r\n // Find which page this widget belongs to\r\n const pageIndex = findPageIndexByRef(pages, pageRef);\r\n\r\n if (pageIndex !== -1) {\r\n const pageNumber = pageIndex + 1; // Convert to 1-indexed\r\n pageMap[fieldName] = pageNumber;\r\n\r\n // Store position information\r\n positionMap[fieldName] = {\r\n x: rect.x,\r\n y: rect.y,\r\n width: rect.width,\r\n height: rect.height,\r\n page: pageNumber,\r\n };\r\n }\r\n }\r\n }\r\n }\r\n\r\n return { pageMap, positionMap };\r\n} catch (error) {\r\n logger.error('Error extracting field page numbers:', error);\r\n return { pageMap: {}, positionMap: {} };\r\n}\r\n}\r\n\r\n","/**\r\n * PDF Form Field Extraction Utilities\r\n * Functions for extracting and decoding form fields from PDFs\r\n */\r\n\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport { EsignFormField, FormFieldType } from '../types';\r\nimport { logger } from './logger';\r\nimport type { PDFName as PDFNameType } from 'pdf-lib';\r\nimport { getSigniphiMetadata, initPdfMetadata, type FieldMetadata } from './pdf-metadata';\r\nimport { extractFieldValue } from './pdf-field-type-helpers';\r\n\r\n// Module-level variable to hold PDFName after pdf-lib is loaded\r\nlet PDFName: typeof PDFNameType;\r\n\r\n// Type definitions for PDF field extensions\r\ninterface PDFFieldWithExtensions {\r\n acroField?: {\r\n getWidgets?: () => Array<{\r\n hasFlag?: (flag: number) => boolean;\r\n }>;\r\n dict?: {\r\n get: (key: unknown) => unknown;\r\n };\r\n };\r\n getOptions?: () => string[];\r\n isRequired?: () => boolean;\r\n constructor: { name: string };\r\n getName(): string;\r\n}\r\n\r\n/**\r\n * Extract visible form fields from a PDF document\r\n * @param pdfBytes - The PDF bytes to extract fields from\r\n * @param currentSignerEmail - Optional email of the current signer (for multi-signer filtering)\r\n * @returns Array of extracted form fields\r\n */\r\nexport async function extractVisibleFormFields(\r\n pdfBytes: Uint8Array,\r\n currentSignerEmail?: string\r\n): Promise<EsignFormField[]> {\r\n try {\r\n const pdfLibModule = await loadPdfLib();\r\n const { PDFDocument, AnnotationFlags, PDFName: PDFNameClass } = pdfLibModule;\r\n PDFName = PDFNameClass; // Assign to module-level variable for use in helper functions\r\n \r\n // Initialize pdf-metadata module with PDFName and PDFString\r\n initPdfMetadata(pdfLibModule);\r\n \r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Load metadata from PDF document information dictionary\r\n const metadata = getSigniphiMetadata(pdfDoc);\r\n \r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n const visibleFields: EsignFormField[] = [];\r\n let hasAnyInitialsFields = false; // For single-signer mode\r\n \r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n \r\n // Get widgets for this field to check visibility\r\n const fieldWithExtensions = field as unknown as PDFFieldWithExtensions;\r\n const widgets = fieldWithExtensions.acroField?.getWidgets?.() ?? [];\r\n \r\n let isVisible = true;\r\n \r\n // Check if any widget is hidden using AnnotationFlags\r\n for (const widget of widgets) {\r\n const hasHiddenFlag = widget.hasFlag?.(AnnotationFlags.Hidden) ?? false;\r\n const hasNoViewFlag = widget.hasFlag?.(AnnotationFlags.NoView) ?? false;\r\n \r\n if (hasHiddenFlag || hasNoViewFlag) {\r\n isVisible = false;\r\n break;\r\n }\r\n }\r\n \r\n if (isVisible) {\r\n // Extract the clean field name (without suffixes) for metadata lookup\r\n const cleanFieldNameForMetadata = fieldName.replace(/_signature$|_initials$|_date$/i, '');\r\n\r\n // Get field metadata from PDF metadata or fall back to parsing field name (for old PDFs)\r\n // CRITICAL: Try both the suffixed name and the clean name for metadata lookup\r\n const fieldMetadata: FieldMetadata = metadata?.fields[fieldName]\r\n || metadata?.fields[cleanFieldNameForMetadata]\r\n || (() => {\r\n // Backward compatibility: decode from field name if no metadata exists\r\n const decoded = decodeFieldName(fieldName);\r\n return {\r\n label: decoded.displayLabel,\r\n signer: decoded.assignedSignerEmail,\r\n placeholder: decoded.fieldPlaceholder,\r\n acknowledgements: decoded.acknowledgements\r\n };\r\n })();\r\n \r\n // NOTE: We do NOT filter by signer during extraction in multi-signer mode!\r\n // All fields must be extracted so that:\r\n // 1. useFieldFiltering can properly filter fields for display\r\n // 2. Partial flattening knows about all fields (flatten current signer's fields only)\r\n // 3. PDF viewer filtering can remove non-visible fields from the rendered PDF\r\n // The filtering happens at the display level via useFieldFiltering hook.\r\n \r\n // Determine field type based on pdf-lib field type using duck typing (minification-safe)\r\n // Constructor names get renamed during minification, breaking string comparisons\r\n let fieldType = FormFieldType.TEXT;\r\n const f = field as any;\r\n\r\n // Duck typing: detect field type by method presence\r\n const isCheckboxField = typeof f.check === 'function' && typeof f.uncheck === 'function';\r\n const isRadioField = typeof f.select === 'function' &&\r\n typeof f.getOptions === 'function' &&\r\n typeof f.check !== 'function' &&\r\n typeof f.setOptions !== 'function';\r\n const isDropdownField = typeof f.select === 'function' &&\r\n (typeof f.setOptions === 'function' || typeof f.addOptions === 'function');\r\n const isTextField = typeof f.getText === 'function' && typeof f.setText === 'function';\r\n // Signature fields have no editable methods\r\n const isSignatureType = !isCheckboxField && !isRadioField && !isDropdownField && !isTextField;\r\n\r\n // Extract the clean field name (without suffixes for type detection)\r\n const cleanFieldName = fieldName.replace(/_signature$|_initials$|_date$/i, '');\r\n\r\n // CRITICAL: Properly detect signature/initials fields (not checkboxes/radios)\r\n // Use duck typing to exclude checkbox/radio fields\r\n const isActualSignatureField = isSignatureType ||\r\n (cleanFieldName.toLowerCase().includes('signature') &&\r\n !isCheckboxField &&\r\n !isRadioField);\r\n const isActualInitialsField = cleanFieldName.toLowerCase().includes('initials') &&\r\n !isCheckboxField &&\r\n !isRadioField;\r\n\r\n if (isActualSignatureField) {\r\n fieldType = FormFieldType.SIGNATURE;\r\n } else if (isActualInitialsField) {\r\n fieldType = FormFieldType.INITIALS;\r\n\r\n // Track initials fields for proper sidebar display logic\r\n hasAnyInitialsFields = true;\r\n } else if (cleanFieldName.toLowerCase().includes('date')) {\r\n fieldType = FormFieldType.DATE;\r\n } else if (isCheckboxField) {\r\n fieldType = FormFieldType.CHECKBOX;\r\n } else if (isDropdownField) {\r\n fieldType = FormFieldType.DROPDOWN;\r\n } else if (isRadioField) {\r\n fieldType = FormFieldType.RADIO;\r\n }\r\n \r\n // Generate display label - Try TU metadata first, then metadata label, then fallback\r\n let displayLabel = fieldMetadata.label || '';\r\n let isLabelAutoGenerated = false;\r\n\r\n // PRIORITY 1: Try to get label from TU (tooltip/user-visible) metadata\r\n if (!displayLabel || !displayLabel.trim()) {\r\n try {\r\n const tuLabel = extractTULabel(fieldWithExtensions);\r\n if (tuLabel && tuLabel.trim()) {\r\n displayLabel = tuLabel;\r\n }\r\n } catch (tuError) {\r\n }\r\n }\r\n\r\n // PRIORITY 2: Use label from metadata (already set above from fieldMetadata.label)\r\n\r\n // PRIORITY 3: Generate fallback label from field name\r\n // This provides a display label for the UI sidebar, but should NOT be drawn on the PDF\r\n if (!displayLabel || !displayLabel.trim()) {\r\n displayLabel = generateFallbackLabel(cleanFieldName, fieldType);\r\n isLabelAutoGenerated = true;\r\n }\r\n\r\n // Create EsignFormField\r\n const esignField: EsignFormField = {\r\n id: fieldName, // Keep original encoded name as ID\r\n fieldId: fieldMetadata.fieldId || fieldName, // Use fieldId from metadata, fallback to fieldName for backward compatibility\r\n name: fieldName, // Keep original for removal later\r\n type: fieldType,\r\n label: displayLabel, // Use friendly label for display\r\n isLabelAutoGenerated, // True when label was generated from field name (should not be drawn on PDF)\r\n position: { x: 0, y: 0, width: 100, height: 30, page: 1 }, // Default position\r\n required: fieldWithExtensions.isRequired?.() ?? false,\r\n placeholder: fieldMetadata.placeholder || '', // Use metadata placeholder\r\n assignedSignerEmail: fieldMetadata.signer, // Add assigned signer from metadata\r\n acknowledgements: fieldMetadata.acknowledgements, // Add acknowledgements from metadata\r\n };\r\n \r\n // Add options for dropdown and radio fields\r\n if (fieldType === FormFieldType.DROPDOWN || fieldType === FormFieldType.RADIO) {\r\n try {\r\n const options = fieldWithExtensions.getOptions?.() ?? [];\r\n esignField.options = options;\r\n if (options.length > 0) {\r\n }\r\n } catch (error) {\r\n logger.warn('Error extracting options for field:', error);\r\n }\r\n }\r\n\r\n // Read current field value from PDF (for pre-filled fields)\r\n try {\r\n const currentValue = extractFieldValue(f as any, esignField.type);\r\n if (currentValue) {\r\n esignField.defaultValue = currentValue;\r\n }\r\n } catch {\r\n // Ignore errors reading field values\r\n }\r\n\r\n visibleFields.push(esignField);\r\n }\r\n }\r\n \r\n // Add main signature and initials fields at the BEGINNING\r\n // Only create if PDF has these fields OR if explicitly required\r\n const mainFields: EsignFormField[] = [];\r\n \r\n // ALWAYS create signature field - it's attached to the document on submission regardless\r\n mainFields.push({\r\n id: 'signature_field_main',\r\n fieldId: 'signature_field_main', // Fixed ID for main signature field\r\n name: 'signature_field_main',\r\n type: FormFieldType.SIGNATURE,\r\n label: 'Your Signature (will be applied to all signature fields)',\r\n position: { x: 0, y: 0, width: 200, height: 60, page: 1 },\r\n required: true,\r\n placeholder: 'Draw or upload your signature',\r\n assignedSignerEmail: currentSignerEmail,\r\n });\r\n \r\n // Create initials field if ANY initials fields exist in the PDF\r\n // The UI layer (useFieldFiltering) handles filtering fields by signer assignment\r\n // This ensures the initials section always appears when initials fields are present\r\n const shouldCreateInitialsField = hasAnyInitialsFields;\r\n \r\n if (shouldCreateInitialsField) {\r\n mainFields.push({\r\n id: 'initials_field_main',\r\n fieldId: 'initials_field_main', // Fixed ID for main initials field\r\n name: 'initials_field_main',\r\n type: FormFieldType.INITIALS,\r\n label: 'Your Initials (will be applied to all initials fields)',\r\n position: { x: 0, y: 0, width: 100, height: 40, page: 1 },\r\n required: true,\r\n placeholder: 'Enter your initials',\r\n assignedSignerEmail: currentSignerEmail,\r\n });\r\n }\r\n \r\n // Return main fields FIRST, then other fields\r\n return [...mainFields, ...visibleFields];\r\n } catch (error) {\r\n logger.error('Error extracting visible form fields from PDF:', error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Decode a field name to extract label, signer email, and placeholder\r\n * Format: fieldName__LABEL__labelText__SIGNER__email__PLACEHOLDER__placeholderText\r\n * \r\n * @deprecated This function is deprecated and kept only for backward compatibility with old PDFs.\r\n * New PDFs store metadata in the PDF's document information dictionary instead of encoding it in field names.\r\n * Use getSigniphiMetadata() for new PDFs.\r\n */\r\nexport function decodeFieldName(fieldName: string): {\r\n decodedFieldName: string;\r\n displayLabel: string;\r\n assignedSignerEmail?: string;\r\n fieldPlaceholder: string;\r\n acknowledgements?: Array<{id: string; title: string; description: string}>;\r\n} {\r\n let decodedFieldName = fieldName;\r\n let displayLabel = '';\r\n let assignedSignerEmail: string | undefined = undefined;\r\n let fieldPlaceholder = '';\r\n let acknowledgements: Array<{id: string; title: string; description: string}> | undefined = undefined;\r\n \r\n // Extract acknowledgements if present (must be last)\r\n if (fieldName.includes('__ACK__')) {\r\n const ackMarkerIndex = fieldName.indexOf('__ACK__');\r\n const beforeAck = fieldName.substring(0, ackMarkerIndex);\r\n const ackEncoded = fieldName.substring(ackMarkerIndex + 7); // Skip \"__ACK__\"\r\n \r\n try {\r\n // Decode base64 and parse JSON\r\n const ackData = atob(ackEncoded);\r\n acknowledgements = JSON.parse(ackData);\r\n } catch (e) {\r\n console.warn('Failed to decode acknowledgements:', e);\r\n }\r\n \r\n // Continue processing the rest of the field name\r\n fieldName = beforeAck;\r\n decodedFieldName = fieldName;\r\n }\r\n \r\n // Extract label if present\r\n if (fieldName.includes('__LABEL__')) {\r\n const labelMarkerIndex = fieldName.indexOf('__LABEL__');\r\n decodedFieldName = fieldName.substring(0, labelMarkerIndex);\r\n \r\n const afterLabel = fieldName.substring(labelMarkerIndex + 9); // Skip \"__LABEL__\"\r\n \r\n // Extract signer email if present\r\n if (afterLabel.includes('__SIGNER__')) {\r\n const signerMarkerIndex = afterLabel.indexOf('__SIGNER__');\r\n displayLabel = afterLabel.substring(0, signerMarkerIndex);\r\n const afterSigner = afterLabel.substring(signerMarkerIndex + 10); // Skip \"__SIGNER__\"\r\n \r\n // Extract placeholder if present\r\n if (afterSigner.includes('__PLACEHOLDER__')) {\r\n const placeholderMarkerIndex = afterSigner.indexOf('__PLACEHOLDER__');\r\n assignedSignerEmail = afterSigner.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterSigner.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n assignedSignerEmail = afterSigner;\r\n }\r\n } else if (afterLabel.includes('__PLACEHOLDER__')) {\r\n // Label and placeholder but no signer\r\n const placeholderMarkerIndex = afterLabel.indexOf('__PLACEHOLDER__');\r\n displayLabel = afterLabel.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterLabel.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n displayLabel = afterLabel;\r\n }\r\n } else if (fieldName.includes('__SIGNER__')) {\r\n // Old format without label\r\n const signerMarkerIndex = fieldName.indexOf('__SIGNER__');\r\n decodedFieldName = fieldName.substring(0, signerMarkerIndex);\r\n const afterSigner = fieldName.substring(signerMarkerIndex + 10); // Skip \"__SIGNER__\"\r\n \r\n // Extract placeholder if present\r\n if (afterSigner.includes('__PLACEHOLDER__')) {\r\n const placeholderMarkerIndex = afterSigner.indexOf('__PLACEHOLDER__');\r\n assignedSignerEmail = afterSigner.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = afterSigner.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n } else {\r\n assignedSignerEmail = afterSigner;\r\n }\r\n } else if (fieldName.includes('__PLACEHOLDER__')) {\r\n // Only placeholder present\r\n const placeholderMarkerIndex = fieldName.indexOf('__PLACEHOLDER__');\r\n decodedFieldName = fieldName.substring(0, placeholderMarkerIndex);\r\n fieldPlaceholder = fieldName.substring(placeholderMarkerIndex + 15); // Skip \"__PLACEHOLDER__\"\r\n }\r\n \r\n return {\r\n decodedFieldName,\r\n displayLabel,\r\n assignedSignerEmail,\r\n fieldPlaceholder,\r\n acknowledgements\r\n };\r\n}\r\n\r\n/**\r\n * Generate a fallback label from a decoded field name\r\n */\r\nexport function generateFallbackLabel(decodedFieldName: string, fieldType: FormFieldType): string {\r\n let displayLabel = decodedFieldName;\r\n \r\n // Remove ALL consecutive \"_signature\", \"_initials\", \"_date\" suffixes added by pdf-lib\r\n // This handles multiple suffixes from repeated PDF exports\r\n let prevLabel = '';\r\n while (displayLabel !== prevLabel) {\r\n prevLabel = displayLabel;\r\n displayLabel = displayLabel.replace(/_signature$/i, '').replace(/_initials$/i, '').replace(/_date$/i, '');\r\n }\r\n \r\n // Handle different naming patterns:\r\n // 1. Pure timestamp fields: \"text_1234567890\" → \"Text\"\r\n // 2. Timestamp with repeated type: \"Signature_1768236781866_Signature_Signature\" → \"Signature\"\r\n // 3. Descriptive fields: \"text_Primary_1\" → \"Text Primary\"\r\n // 4. Custom fields: \"customer_name\" → \"Customer Name\"\r\n \r\n // Pattern 1 & 2: Field name starts with type_timestamp (regardless of what follows)\r\n // This catches both \"text_1234567890\" and \"Signature_1768236781866_Signature_Signature\"\r\n if (/^(text|signature|initials|date|checkbox|radio|dropdown)_\\d+/i.test(displayLabel)) {\r\n // Auto-generated field name - return simple type name based on actual field type\r\n if (fieldType === FormFieldType.SIGNATURE) return 'Signature';\r\n if (fieldType === FormFieldType.INITIALS) return 'Initials';\r\n if (fieldType === FormFieldType.DATE) return 'Date';\r\n if (fieldType === FormFieldType.TEXT) return 'Text';\r\n if (fieldType === FormFieldType.CHECKBOX) return 'Checkbox';\r\n if (fieldType === FormFieldType.DROPDOWN) return 'Dropdown';\r\n if (fieldType === FormFieldType.RADIO) return 'Option';\r\n if (fieldType === FormFieldType.TEXT_LABEL) return 'Text Label';\r\n }\r\n \r\n // Pattern 3 & 4: Convert underscores to spaces, remove trailing numbers, capitalize\r\n displayLabel = displayLabel\r\n .replace(/_/g, ' ') // Convert underscores to spaces\r\n .replace(/\\s+\\d+$/g, '') // Remove trailing numbers (e.g., \" 1\")\r\n .trim()\r\n .split(' ') // Split into words\r\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word\r\n .join(' ');\r\n \r\n return displayLabel;\r\n}\r\n\r\n/**\r\n * Extract label from TU (tooltip) metadata in PDF field\r\n * @param field - The PDF field with extensions\r\n * @returns The extracted label or empty string\r\n */\r\nfunction extractTULabel(field: PDFFieldWithExtensions): string {\r\n try {\r\n if (!field.acroField?.dict) {\r\n return '';\r\n }\r\n \r\n const tuLabel = field.acroField.dict.get(PDFName.of('TU'));\r\n if (!tuLabel) {\r\n return '';\r\n }\r\n \r\n // PDFString has a decodeText() method or toString()\r\n const tuValue = tuLabel.toString();\r\n if (!tuValue || !tuValue.trim()) {\r\n return '';\r\n }\r\n \r\n // Handle PDF string encoding - extract content between parentheses or angle brackets\r\n // PDF strings are encoded as \"(text)\" or \"<hex>\"\r\n if (tuValue.startsWith('(') || tuValue.startsWith('<')) {\r\n const match = tuValue.match(/^\\((.*)\\)$/) || tuValue.match(/^<(.*)>$/);\r\n if (match && match[1]) {\r\n return match[1];\r\n }\r\n }\r\n \r\n // If no special encoding, return as-is\r\n return tuValue;\r\n } catch (error) {\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * Find field by UUID using the fieldIdIndex\r\n * This is the SECURE way to lookup fields in multi-signer workflows\r\n * @param fields - Array of fields to search\r\n * @param uuid - The UUID to find\r\n * @returns The field or undefined\r\n */\r\nexport function findFieldByUuid(fields: EsignFormField[], uuid: string): EsignFormField | undefined {\r\n return fields.find(f => f.fieldId === uuid);\r\n}\r\n\r\n/**\r\n * Resolve a field name or UUID to the actual field\r\n * Priority: UUID lookup first (secure), then field name fallback\r\n * @param fields - Array of fields\r\n * @param identifier - Either a UUID or field name\r\n * @returns The field or undefined\r\n */\r\nexport function resolveField(fields: EsignFormField[], identifier: string): EsignFormField | undefined {\r\n // PRIORITY 1: Try UUID lookup (most secure, works across renames)\r\n let field = findFieldByUuid(fields, identifier);\r\n if (field) {\r\n return field;\r\n }\r\n \r\n // PRIORITY 2: Try by field.id\r\n field = fields.find(f => f.id === identifier);\r\n if (field) {\r\n return field;\r\n }\r\n \r\n // PRIORITY 3: Try by field.name\r\n field = fields.find(f => f.name === identifier);\r\n if (field) {\r\n return field;\r\n }\r\n \r\n // PRIORITY 4: Try without suffixes (for date/signature/initials fields)\r\n const cleanIdentifier = identifier.replace(/_signature$|_initials$|_date$/i, '');\r\n return fields.find(f => f.fieldId === cleanIdentifier || f.id === cleanIdentifier || f.name === cleanIdentifier);\r\n}\r\n\r\n/**\r\n * Get all fields assigned to a specific signer by UUID\r\n * @param fields - Array of fields\r\n * @param signerEmail - Email of the signer\r\n * @returns Array of field UUIDs assigned to this signer\r\n */\r\nexport function getFieldUuidsForSigner(fields: EsignFormField[], signerEmail: string): string[] {\r\n return fields\r\n .filter(f => f.assignedSignerEmail === signerEmail && f.fieldId)\r\n .map(f => f.fieldId!);\r\n}\r\n\r\n","/**\r\n * PDF.js Configuration Provider\r\n * Manages global configuration for PDF.js worker and viewer paths\r\n * \r\n * COMPATIBILITY NOTE: This module is designed to work with both Vite and Next.js/webpack.\r\n * The worker source URL is computed lazily to avoid issues with webpack's handling of import.meta.\r\n */\r\n\r\nimport type { PdfJsConfig } from '../types';\r\nimport * as pdfjsLib from 'pdfjs-dist';\r\n\r\n/**\r\n * CDN paths for PDF.js (exported for manual fallback configuration)\r\n * Note: CDN URLs may cause CORS issues in some environments\r\n * \r\n * @example\r\n * // Manually configure CDN (not recommended)\r\n * setPdfJsConfig({ \r\n * viewerBasePath: CDN_VIEWER,\r\n * workerSrc: CDN_WORKER \r\n * });\r\n */\r\nexport const CDN_WORKER = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@5.3.93/build/pdf.worker.mjs';\r\nexport const CDN_VIEWER = 'https://mozilla.github.io/pdf.js';\r\n\r\n/**\r\n * Internal flag to track if worker source has been computed\r\n */\r\nlet _workerSrcComputed = false;\r\nlet _cachedWorkerSrc: string | null = null;\r\n\r\n/**\r\n * Get the worker source URL (computed lazily to avoid webpack import.meta issues)\r\n * - In browser environments, the bundler resolves the URL from node_modules\r\n * - The worker is loaded from the user's bundle (no CORS issues)\r\n * \r\n * This function uses lazy evaluation to avoid triggering webpack's\r\n * \"Critical dependency: Accessing import.meta directly is unsupported\" warning\r\n * at module load time.\r\n */\r\nfunction getDefaultWorkerSrc(): string {\r\n // Return cached value if already computed\r\n if (_workerSrcComputed && _cachedWorkerSrc !== null) {\r\n return _cachedWorkerSrc;\r\n }\r\n\r\n // Default fallback\r\n let workerSrc = '/pdfjs/build/pdf.worker.mjs';\r\n\r\n // Only attempt import.meta resolution in browser environment\r\n if (typeof window !== 'undefined' && typeof URL !== 'undefined') {\r\n try {\r\n // Check if import.meta is available (ESM environment like Vite)\r\n // Use indirect access to avoid webpack static analysis issues\r\n const meta = (function() {\r\n try {\r\n // This pattern avoids webpack's direct import.meta detection\r\n return new Function('return import.meta')();\r\n } catch {\r\n return null;\r\n }\r\n })();\r\n\r\n if (meta && meta.url) {\r\n workerSrc = new URL('pdfjs-dist/build/pdf.worker.mjs', meta.url).href;\r\n }\r\n } catch {\r\n // Fallback for environments that don't support import.meta.url (Next.js/webpack)\r\n // Use the public path fallback\r\n }\r\n }\r\n\r\n // Cache the result\r\n _workerSrcComputed = true;\r\n _cachedWorkerSrc = workerSrc;\r\n\r\n return workerSrc;\r\n}\r\n\r\n/**\r\n * Default configuration for PDF.js\r\n * \r\n * By default, the package uses:\r\n * - Worker: Loaded from node_modules (bundled by your build tool)\r\n * - Viewer: Served from /pdfjs/ (automatically copied by postinstall)\r\n * \r\n * The postinstall script automatically copies viewer files to your public/pdfjs/ directory.\r\n * If setup fails, run: npx signiphi-setup\r\n * \r\n * NOTE: workerSrc is initialized to null and computed lazily on first access\r\n * to ensure compatibility with Next.js/webpack environments.\r\n */\r\nlet globalConfig: Required<PdfJsConfig> = {\r\n viewerBasePath: '/pdfjs',\r\n workerSrc: '', // Lazy-initialized below\r\n};\r\n\r\n// Flag to track if globalConfig.workerSrc has been initialized\r\nlet _configInitialized = false;\r\n\r\n/**\r\n * Ensure config is initialized (called lazily)\r\n */\r\nfunction ensureConfigInitialized(): void {\r\n if (!_configInitialized) {\r\n globalConfig.workerSrc = getDefaultWorkerSrc();\r\n _configInitialized = true;\r\n \r\n // Initialize PDF.js worker in browser environment\r\n if (typeof window !== 'undefined') {\r\n pdfjsLib.GlobalWorkerOptions.workerSrc = globalConfig.workerSrc;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Set PDF.js configuration\r\n * @param config - Partial configuration to merge with defaults\r\n * \r\n * @example\r\n * // Use self-hosted PDF.js files\r\n * setPdfJsConfig({ viewerBasePath: '/pdfjs' });\r\n * \r\n * @example\r\n * // Use custom CDN\r\n * setPdfJsConfig({ \r\n * viewerBasePath: 'https://my-cdn.com/pdfjs',\r\n * workerSrc: 'https://my-cdn.com/pdfjs/build/pdf.worker.mjs'\r\n * });\r\n */\r\nexport function setPdfJsConfig(config: Partial<PdfJsConfig>): void {\r\n // Ensure default config is computed first\r\n ensureConfigInitialized();\r\n \r\n if (config.viewerBasePath !== undefined) {\r\n globalConfig.viewerBasePath = config.viewerBasePath;\r\n }\r\n \r\n if (config.workerSrc !== undefined) {\r\n globalConfig.workerSrc = config.workerSrc;\r\n } else if (config.viewerBasePath !== undefined) {\r\n // Auto-update workerSrc based on viewerBasePath\r\n globalConfig.workerSrc = `${config.viewerBasePath}/build/pdf.worker.mjs`;\r\n }\r\n\r\n // Update PDF.js worker if in browser environment\r\n if (typeof window !== 'undefined') {\r\n pdfjsLib.GlobalWorkerOptions.workerSrc = globalConfig.workerSrc;\r\n }\r\n}\r\n\r\n/**\r\n * Get current PDF.js configuration\r\n * @returns Current configuration\r\n */\r\nexport function getPdfJsConfig(): Required<PdfJsConfig> {\r\n // Ensure config is initialized before returning\r\n ensureConfigInitialized();\r\n return { ...globalConfig };\r\n}\r\n\r\n/**\r\n * Reset configuration to defaults (local files)\r\n */\r\nexport function resetPdfJsConfig(): void {\r\n // Clear cached worker src to force recomputation\r\n _workerSrcComputed = false;\r\n _cachedWorkerSrc = null;\r\n _configInitialized = false;\r\n \r\n // Re-initialize with fresh defaults\r\n ensureConfigInitialized();\r\n}\r\n\r\n/**\r\n * Initialize PDF.js configuration\r\n * This is called automatically when the first PDF operation is attempted,\r\n * but can also be called manually to pre-initialize the configuration.\r\n * \r\n * Unlike previous versions, this does NOT run at module load time to\r\n * ensure compatibility with Next.js/webpack environments.\r\n */\r\nexport function initializePdfJs(): void {\r\n ensureConfigInitialized();\r\n}\r\n\r\n","/**\r\n * Custom Error Classes\r\n * Domain-specific error types for better error handling and debugging\r\n */\r\n\r\n/**\r\n * Error thrown when PDF validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * const validation = validatePdfBytes(bytes);\r\n * if (!validation.valid) {\r\n * throw new PdfValidationError(validation.error || 'Invalid PDF');\r\n * }\r\n * ```\r\n */\r\nexport class PdfValidationError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'PdfValidationError';\r\n // Maintains proper stack trace for where error was thrown (V8 only)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, PdfValidationError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown during PDF processing operations\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * const pdfDoc = await PDFDocument.load(bytes);\r\n * } catch (err) {\r\n * throw new PdfProcessingError('Failed to load PDF document', err);\r\n * }\r\n * ```\r\n */\r\nexport class PdfProcessingError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'PdfProcessingError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, PdfProcessingError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown for form field related issues\r\n * \r\n * @example\r\n * ```ts\r\n * if (!field.value && field.required) {\r\n * throw new FormFieldError(\r\n * 'Required field is empty',\r\n * field.name\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport class FormFieldError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly fieldName?: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'FormFieldError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, FormFieldError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Error thrown for attachment validation failures\r\n * \r\n * @example\r\n * ```ts\r\n * if (file.size > maxFileSize) {\r\n * throw new AttachmentValidationError(\r\n * `File size exceeds limit: ${file.name}`,\r\n * file.name\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport class AttachmentValidationError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly fileName?: string,\r\n public readonly details?: unknown\r\n ) {\r\n super(message);\r\n this.name = 'AttachmentValidationError';\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, AttachmentValidationError);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a PdfValidationError\r\n */\r\nexport function isPdfValidationError(error: unknown): error is PdfValidationError {\r\n return error instanceof PdfValidationError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a PdfProcessingError\r\n */\r\nexport function isPdfProcessingError(error: unknown): error is PdfProcessingError {\r\n return error instanceof PdfProcessingError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a FormFieldError\r\n */\r\nexport function isFormFieldError(error: unknown): error is FormFieldError {\r\n return error instanceof FormFieldError;\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is an AttachmentValidationError\r\n */\r\nexport function isAttachmentValidationError(error: unknown): error is AttachmentValidationError {\r\n return error instanceof AttachmentValidationError;\r\n}\r\n\r\n/**\r\n * Extract error message from unknown error type\r\n * \r\n * @param error - The error to extract message from\r\n * @param defaultMessage - Default message if extraction fails\r\n * @returns Error message string\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * // ... operation\r\n * } catch (err) {\r\n * const message = getErrorMessage(err, 'Operation failed');\r\n * logger.error(message);\r\n * }\r\n * ```\r\n */\r\nexport function getErrorMessage(error: unknown, defaultMessage = 'Unknown error'): string {\r\n if (error instanceof Error) {\r\n return error.message;\r\n }\r\n if (typeof error === 'string') {\r\n return error;\r\n }\r\n return defaultMessage;\r\n}\r\n\r\n","/**\r\n * Attachment Validation Utilities\r\n * Validation functions for file attachments\r\n */\r\n\r\nimport type { AttachmentConstraints, Attachment } from '../types';\r\nimport { AttachmentValidationError } from './errors';\r\n\r\n/**\r\n * Default attachment constraints\r\n */\r\nexport const DEFAULT_ATTACHMENT_CONSTRAINTS: AttachmentConstraints = {\r\n maxFileSize: 25 * 1024 * 1024, // 25MB\r\n maxTotalSize: 50 * 1024 * 1024, // 50MB\r\n maxFiles: 10,\r\n allowedTypes: ['image/*', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],\r\n allowedExtensions: ['.pdf', '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.doc', '.docx'],\r\n};\r\n\r\n/**\r\n * Validate a single file against constraints\r\n * \r\n * @param file - File to validate\r\n * @param constraints - Validation constraints\r\n * @returns Validation result with errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFile(file, DEFAULT_ATTACHMENT_CONSTRAINTS);\r\n * if (result.errors.length > 0) {\r\n * console.error('File validation failed:', result.errors);\r\n * }\r\n * ```\r\n */\r\nexport function validateFile(\r\n file: File,\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n\r\n // Validate file size\r\n if (file.size > constraints.maxFileSize) {\r\n const maxMB = (constraints.maxFileSize / 1024 / 1024).toFixed(1);\r\n const fileMB = (file.size / 1024 / 1024).toFixed(1);\r\n errors.push(`File \"${file.name}\" is too large (${fileMB}MB). Maximum size is ${maxMB}MB.`);\r\n }\r\n\r\n // Validate file type (MIME type)\r\n const isTypeAllowed = constraints.allowedTypes.some((allowedType) => {\r\n if (allowedType.endsWith('/*')) {\r\n // Wildcard type (e.g., 'image/*')\r\n const prefix = allowedType.slice(0, -2);\r\n return file.type.startsWith(prefix);\r\n }\r\n return file.type === allowedType;\r\n });\r\n\r\n if (!isTypeAllowed && constraints.allowedTypes.length > 0) {\r\n errors.push(\r\n `File type \"${file.type}\" is not allowed for \"${file.name}\". Allowed types: ${constraints.allowedTypes.join(', ')}`\r\n );\r\n }\r\n\r\n // Validate file extension\r\n if (constraints.allowedExtensions && constraints.allowedExtensions.length > 0) {\r\n const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();\r\n const isExtAllowed = constraints.allowedExtensions.some(\r\n (ext) => ext.toLowerCase() === fileExt\r\n );\r\n\r\n if (!isExtAllowed) {\r\n errors.push(\r\n `File extension \"${fileExt}\" is not allowed for \"${file.name}\". Allowed extensions: ${constraints.allowedExtensions.join(', ')}`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate multiple files against constraints\r\n * \r\n * @param files - Files to validate\r\n * @param existingAttachments - Existing attachments to consider for total size/count\r\n * @param constraints - Validation constraints\r\n * @returns Validation result with errors array\r\n * \r\n * @example\r\n * ```ts\r\n * const result = validateFiles(newFiles, existingAttachments, DEFAULT_ATTACHMENT_CONSTRAINTS);\r\n * if (result.errors.length > 0) {\r\n * alert('Some files cannot be uploaded: ' + result.errors.join(', '));\r\n * }\r\n * ```\r\n */\r\nexport function validateFiles(\r\n files: File[],\r\n existingAttachments: Attachment[] = [],\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): {\r\n valid: boolean;\r\n errors: string[];\r\n} {\r\n const errors: string[] = [];\r\n\r\n // Validate total number of files\r\n const totalFiles = files.length + existingAttachments.length;\r\n if (totalFiles > constraints.maxFiles) {\r\n errors.push(\r\n `Too many files. Maximum allowed is ${constraints.maxFiles}, you have ${totalFiles} files total.`\r\n );\r\n }\r\n\r\n // Validate total size\r\n const existingSize = existingAttachments.reduce((sum, att) => sum + att.size, 0);\r\n const newFilesSize = files.reduce((sum, file) => sum + file.size, 0);\r\n const totalSize = existingSize + newFilesSize;\r\n\r\n if (totalSize > constraints.maxTotalSize) {\r\n const maxMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n const totalMB = (totalSize / 1024 / 1024).toFixed(1);\r\n errors.push(\r\n `Total size of all files is too large (${totalMB}MB). Maximum total size is ${maxMB}MB.`\r\n );\r\n }\r\n\r\n // Validate each individual file\r\n for (const file of files) {\r\n const fileResult = validateFile(file, constraints);\r\n errors.push(...fileResult.errors);\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Validate file and throw error if invalid\r\n * \r\n * Convenience function that throws AttachmentValidationError if validation fails.\r\n * \r\n * @param file - File to validate\r\n * @param constraints - Validation constraints\r\n * @throws {AttachmentValidationError} If validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * validateFileOrThrow(file);\r\n * // File is valid, proceed with upload\r\n * } catch (err) {\r\n * if (err instanceof AttachmentValidationError) {\r\n * alert(err.message);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function validateFileOrThrow(\r\n file: File,\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): void {\r\n const result = validateFile(file, constraints);\r\n if (!result.valid) {\r\n throw new AttachmentValidationError(\r\n `File validation failed: ${result.errors.join('; ')}`,\r\n file.name,\r\n { file, errors: result.errors }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate multiple files and throw error if invalid\r\n * \r\n * @param files - Files to validate\r\n * @param existingAttachments - Existing attachments\r\n * @param constraints - Validation constraints\r\n * @throws {AttachmentValidationError} If validation fails\r\n * \r\n * @example\r\n * ```ts\r\n * try {\r\n * validateFilesOrThrow(selectedFiles, currentAttachments);\r\n * // All files are valid\r\n * } catch (err) {\r\n * if (err instanceof AttachmentValidationError) {\r\n * alert(err.message);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function validateFilesOrThrow(\r\n files: File[],\r\n existingAttachments: Attachment[] = [],\r\n constraints: AttachmentConstraints = DEFAULT_ATTACHMENT_CONSTRAINTS\r\n): void {\r\n const result = validateFiles(files, existingAttachments, constraints);\r\n if (!result.valid) {\r\n throw new AttachmentValidationError(\r\n `File validation failed: ${result.errors.join('; ')}`,\r\n undefined,\r\n { files, errors: result.errors }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file type is an image\r\n * \r\n * @param fileType - MIME type of the file\r\n * @returns true if the file is an image\r\n * \r\n * @example\r\n * ```ts\r\n * if (isImageType(file.type)) {\r\n * // Generate preview\r\n * }\r\n * ```\r\n */\r\nexport function isImageType(fileType: string): boolean {\r\n return fileType.startsWith('image/');\r\n}\r\n\r\n/**\r\n * Format file size for display\r\n * \r\n * @param bytes - File size in bytes\r\n * @returns Formatted size string (e.g., \"1.5 MB\")\r\n * \r\n * @example\r\n * ```ts\r\n * const sizeDisplay = formatFileSize(file.size); // \"1.5 MB\"\r\n * ```\r\n */\r\nexport function formatFileSize(bytes: number): string {\r\n if (bytes === 0) return '0 Bytes';\r\n \r\n const k = 1024;\r\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n \r\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];\r\n}\r\n\r\n","/**\r\n * ISO Date Validation Utility\r\n * Lightweight validation for ISO 8601 date strings (YYYY-MM-DD)\r\n * Separated from full date-validation to avoid pulling in the heavier `parse` dependency\r\n * from date-fns when only ISO validation is needed.\r\n */\r\n\r\nimport { isValid as isValidDate, parseISO } from 'date-fns';\r\n\r\n/**\r\n * Validate if a string is a valid ISO date (YYYY-MM-DD)\r\n */\r\nexport function isValidISODate(value: string | null | undefined): boolean {\r\n if (!value || typeof value !== 'string') {\r\n return false;\r\n }\r\n\r\n const isoPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\r\n if (!isoPattern.test(value)) {\r\n return false;\r\n }\r\n\r\n try {\r\n const date = parseISO(value);\r\n return isValidDate(date) && !isNaN(date.getTime());\r\n } catch {\r\n return false;\r\n }\r\n}\r\n","/**\r\n * PDF Viewer Filtering Utility\r\n * Removes other signers' fields from PDF for viewer display\r\n * Based on Dockmaster's field removal logic (lines 977-1037)\r\n */\r\n\r\nimport { loadPdfLib } from './pdf-lib-loader';\r\nimport type { PDFDocument } from 'pdf-lib';\r\nimport type { EsignFormField, MultiSignerContext } from '../types';\r\nimport { FormFieldType } from '../types';\r\nimport { logger } from './logger';\r\nimport { hasDrawableLabel } from './pdf-validators';\r\nimport { isFieldVisibleToSigner } from './field-visibility';\r\nimport { findPageIndexWithFallback, type PDFWidgetWithExtensions } from './pdf-widget-helpers';\r\n\r\n// Extended types for pdf-lib widgets (for label drawing)\r\ninterface PDFFieldWithExtensions {\r\n acroField?: {\r\n getWidgets?: () => unknown[];\r\n removeWidget?: (index: number) => void;\r\n };\r\n}\r\n\r\n// Interface for PDF form (needed for robust removal)\r\ninterface PDFFormWithRemove {\r\n removeField(field: unknown): void;\r\n getFieldMaybe(name: string): unknown | undefined;\r\n}\r\n\r\n/**\r\n * Robustly removes a single form field by first removing all its widgets (visual annotations)\r\n * and then removing the field from the AcroForm.\r\n */\r\nfunction robustlyRemoveField(form: PDFFormWithRemove, field: unknown): boolean {\r\n try {\r\n // Phase 1: Remove all widgets (visual annotations) from the field\r\n const fieldWithAcro = field as PDFFieldWithExtensions;\r\n if (fieldWithAcro.acroField && typeof fieldWithAcro.acroField.getWidgets === 'function') {\r\n let widgets = fieldWithAcro.acroField.getWidgets() || [];\r\n\r\n // Remove widgets one by one from the end with safety counter\r\n let safetyCounter = 0;\r\n const maxIterations = widgets.length + 5;\r\n\r\n while (widgets.length > 0 && safetyCounter < maxIterations) {\r\n try {\r\n const widgetIndex = widgets.length - 1;\r\n fieldWithAcro.acroField.removeWidget?.(widgetIndex);\r\n widgets = fieldWithAcro.acroField.getWidgets() || [];\r\n } catch {\r\n break;\r\n }\r\n safetyCounter++;\r\n }\r\n }\r\n\r\n // Phase 2: Remove the field from AcroForm\r\n form.removeField(field);\r\n return true;\r\n } catch (error) {\r\n // Fallback: try simpler removal\r\n try {\r\n form.removeField(field);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Draw cosmetic labels on PDF fields for viewer display\r\n * Based on dm-web-frontend's label drawing logic (commit aafc786)\r\n *\r\n * @param pdfDoc - The PDF document to draw labels on\r\n * @param fieldsToLabel - Fields visible to current signer that need labels\r\n * @param rgb - The rgb function from pdf-lib\r\n */\r\nasync function drawFieldLabelsOnPdf(\r\n pdfDoc: PDFDocument,\r\n fieldsToLabel: EsignFormField[],\r\n rgb: (r: number, g: number, b: number) => any\r\n): Promise<void> {\r\n\r\n try {\r\n // Embed font for labels\r\n const labelFont = await pdfDoc.embedFont('Helvetica-Bold');\r\n const pages = pdfDoc.getPages();\r\n const form = pdfDoc.getForm();\r\n const drawnOnce = new Set<string>();\r\n\r\n for (const field of fieldsToLabel) {\r\n // Skip fields without labels EXCEPT radio fields which need option texts drawn\r\n // Fix from dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n // Match dm-web-frontend submission.page.tsx lines 1427-1433\r\n const isRadioField = field.type === FormFieldType.RADIO;\r\n const hasRadioOptions = isRadioField && field.options && field.options.length > 0;\r\n\r\n // Skip fields without custom labels EXCEPT radio fields which need option texts drawn\r\n if (!hasDrawableLabel(field) && !hasRadioOptions) {\r\n continue;\r\n }\r\n\r\n const pdfField = form.getFieldMaybe(field.name);\r\n if (!pdfField) {\r\n continue;\r\n }\r\n\r\n // Get widgets for this field\r\n const fieldWithExtensions = pdfField as unknown as PDFFieldWithExtensions;\r\n const widgets = (fieldWithExtensions.acroField?.getWidgets?.() || []) as PDFWidgetWithExtensions[];\r\n\r\n if (widgets.length === 0) continue;\r\n\r\n // Handle radio fields specially\r\n if (isRadioField) {\r\n // Draw radio GROUP label (once per field, above first widget)\r\n if (hasDrawableLabel(field)) {\r\n const firstWidget = widgets[0];\r\n if (firstWidget) {\r\n const firstRect = firstWidget.getRectangle?.();\r\n if (firstRect) {\r\n const pageRef = firstWidget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n\r\n if (pageIndex >= 0) {\r\n const page = pages[pageIndex];\r\n if (page) {\r\n const groupLabelKey = `${pageIndex}-${field.name}-grouplabel`;\r\n\r\n if (!drawnOnce.has(groupLabelKey)) {\r\n const radioLabelFontSize = Math.min(10, firstRect.height * 0.4);\r\n const labelY = firstRect.y + firstRect.height + 5;\r\n page.drawText(field.label, {\r\n x: firstRect.x,\r\n y: labelY,\r\n size: radioLabelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOnce.add(groupLabelKey);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Draw radio OPTION labels (next to each radio button)\r\n // Same approach as flattening code in pdf-manipulation.ts\r\n if (field.options && field.options.length > 0) {\r\n for (let i = 0; i < widgets.length; i++) {\r\n const widget = widgets[i];\r\n if (!widget) continue;\r\n\r\n const rect = widget.getRectangle?.();\r\n if (!rect) continue;\r\n\r\n const pageRef = widget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n\r\n if (pageIndex >= 0 && pageIndex < pages.length) {\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n\r\n const optionText = field.options[i];\r\n const optionKey = `${pageIndex}-${field.name}-opt-${i}`;\r\n\r\n if (optionText && !drawnOnce.has(optionKey)) {\r\n // Draw option label to the right of radio button\r\n // Size 7 to match flattening, positioned to align with radio circle center\r\n page.drawText(optionText, {\r\n x: rect.x + rect.width + 4,\r\n y: rect.y + (rect.height - 7) / 2,\r\n size: 7,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n drawnOnce.add(optionKey);\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n // For other fields, draw label once\r\n // Match dm-web-frontend submission.page.tsx lines 1498-1534\r\n const widget = widgets[0];\r\n if (!widget) continue;\r\n const rect = widget.getRectangle?.();\r\n if (!rect) continue;\r\n\r\n const pageRef = widget.P?.();\r\n const pageIndex = findPageIndexWithFallback(pages, pageRef);\r\n\r\n if (pageIndex >= 0 && pageIndex < pages.length) {\r\n const page = pages[pageIndex];\r\n if (!page) continue;\r\n const key = `${pageIndex}-${field.name}`;\r\n\r\n if (!drawnOnce.has(key)) {\r\n // Only draw if it's a user-typed custom label (not auto-generated or fallback)\r\n if (hasDrawableLabel(field)) {\r\n const labelFontSize = Math.min(10, rect.height * 0.4);\r\n if (field.type === FormFieldType.CHECKBOX) {\r\n // Checkbox label to the right\r\n page.drawText(field.label, {\r\n x: rect.x + rect.width + 5,\r\n y: rect.y + (rect.height - labelFontSize) / 2,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n } else {\r\n // Other field labels above the field\r\n const labelY = rect.y + rect.height + 5;\r\n page.drawText(field.label, {\r\n x: rect.x,\r\n y: labelY,\r\n size: labelFontSize,\r\n font: labelFont,\r\n color: rgb(0, 0, 0),\r\n });\r\n }\r\n drawnOnce.add(key);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Update form field appearances to ensure radio button selections render correctly\r\n // Fix from dm-web-frontend commit aafc786 (Oct 29, 2025)\r\n try {\r\n form.updateFieldAppearances();\r\n } catch (appearanceError) {\r\n // Non-critical error - just log and continue\r\n }\r\n\r\n } catch (error) {\r\n // Non-critical error - just log and continue without labels\r\n logger.error('Error drawing field labels:', error);\r\n // Don't throw - allow the PDF to be used without labels\r\n }\r\n}\r\n\r\n/**\r\n * Filter PDF for current signer by removing other signers' fields\r\n * This creates a modified PDF for the viewer while preserving the original\r\n * \r\n * @param pdfBytes - Original PDF bytes with ALL fields\r\n * @param allFields - All form fields extracted from the PDF\r\n * @param multiSignerContext - Multi-signer context\r\n * @returns Modified PDF bytes with other signers' fields removed (for viewer only)\r\n * \r\n * @example\r\n * ```ts\r\n * const originalPdfBytes = await urlToPdfBytes(pdfUrl);\r\n * const allFields = await extractFormFields(originalPdfBytes);\r\n * \r\n * if (multiSignerContext.isMultiSigner) {\r\n * // Create filtered PDF for viewer\r\n * const viewerPdfBytes = await filterPdfForCurrentSigner(\r\n * originalPdfBytes,\r\n * allFields,\r\n * multiSignerContext\r\n * );\r\n * loadPdfIntoViewer(viewerPdfBytes);\r\n * \r\n * // CRITICAL: Keep originalPdfBytes for submission\r\n * }\r\n * ```\r\n */\r\nexport async function filterPdfForCurrentSigner(\r\n pdfBytes: Uint8Array,\r\n allFields: EsignFormField[],\r\n multiSignerContext: MultiSignerContext\r\n): Promise<Uint8Array> {\r\n // Single signer mode: no filtering needed, but we still draw labels\r\n if (!multiSignerContext.isMultiSigner) {\r\n \r\n try {\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Draw labels on all fields (no filtering in single-signer mode)\r\n await drawFieldLabelsOnPdf(pdfDoc, allFields, rgb);\r\n \r\n // Save and return the labeled PDF\r\n const labeledBytes = await pdfDoc.save();\r\n return labeledBytes;\r\n } catch (error) {\r\n return pdfBytes;\r\n }\r\n }\r\n\r\n // Determine which fields to remove using centralized visibility logic\r\n const otherSignersFields = allFields.filter(f => {\r\n // RULE 0: TEXT_LABEL fields are ALWAYS visible to all signers\r\n // They are flattened into the PDF and should never be hidden\r\n // Fix based on dm-web-frontend commit e81bbdd (Oct 29, 2025)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return false; // Never remove TEXT_LABEL fields\r\n }\r\n\r\n // Use centralized visibility logic: if NOT visible, should be removed\r\n return !isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n\r\n\r\n // If no fields to remove, still draw labels on remaining fields\r\n // Match dm-web-frontend submission.page.tsx lines 1588-1730\r\n if (otherSignersFields.length === 0) {\r\n try {\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(pdfBytes);\r\n \r\n // Draw labels on all visible fields (no removal needed)\r\n const fieldsToLabel = allFields.filter(f => {\r\n // Include TEXT_LABEL fields (always visible)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return true;\r\n }\r\n // Use centralized visibility logic\r\n return isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n \r\n await drawFieldLabelsOnPdf(pdfDoc, fieldsToLabel, rgb);\r\n \r\n // Save and return the labeled PDF\r\n const labeledBytes = await pdfDoc.save();\r\n return labeledBytes;\r\n } catch (error) {\r\n // If label drawing fails, return original\r\n return pdfBytes;\r\n }\r\n }\r\n\r\n // Load a fresh copy of the PDF for modification\r\n const { PDFDocument, rgb } = await loadPdfLib();\r\n const freshPdfDoc = await PDFDocument.load(pdfBytes);\r\n const form = freshPdfDoc.getForm();\r\n\r\n // Remove other signers' fields from the form\r\n let removedCount = 0;\r\n let notFoundCount = 0;\r\n\r\n for (const field of otherSignersFields) {\r\n try {\r\n const pdfField = form.getFieldMaybe(field.name);\r\n if (pdfField) {\r\n // Use robust removal that cleans up widgets before removing field\r\n robustlyRemoveField(form as unknown as PDFFormWithRemove, pdfField);\r\n removedCount++;\r\n } else {\r\n notFoundCount++;\r\n }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : 'Unknown error';\r\n logger.error('Error removing field:', errorMsg);\r\n }\r\n }\r\n\r\n // Draw labels on remaining fields (cosmetic enhancement for viewer)\r\n // Based on dm-web-frontend's label drawing logic (commit aafc786)\r\n try {\r\n // Determine which fields to label (fields visible to current signer)\r\n const fieldsToLabel = allFields.filter(f => {\r\n // Include TEXT_LABEL fields (always visible)\r\n if (f.type === FormFieldType.TEXT_LABEL) {\r\n return true;\r\n }\r\n\r\n // Use centralized visibility logic\r\n return isFieldVisibleToSigner(f, multiSignerContext);\r\n });\r\n\r\n await drawFieldLabelsOnPdf(freshPdfDoc, fieldsToLabel, rgb);\r\n } catch (labelError) {\r\n // Continue without labels - not critical for functionality\r\n }\r\n\r\n // Save the modified PDF\r\n const modifiedPdfBytes = await freshPdfDoc.save();\r\n\r\n\r\n return modifiedPdfBytes;\r\n}\r\n\r\n","import { useRef, useState, useCallback } from 'react';\r\nimport type { PdfViewerRef, EsignFormField, MultiSignerContext } from '../types';\r\nimport {\r\n extractVisibleFormFields,\r\n fillPdfWithSignatures,\r\n validatePdfFormFields,\r\n urlToPdfBytes,\r\n createPdfBlobUrl,\r\n logger,\r\n validatePdfUrl,\r\n validateFieldValues,\r\n validateSignatures,\r\n PdfValidationError,\r\n PdfProcessingError,\r\n initializePdfJs,\r\n} from '../utils';\r\nimport { filterPdfForCurrentSigner } from '../utils/pdf-viewer-filter';\r\nimport { loadPdfLib } from '../utils/pdf-lib-loader';\r\n\r\n/**\r\n * Hook to manage PDF viewer state and operations with multi-signer support\r\n * \r\n * @param multiSignerContext - Multi-signer context (from useMultiSignerContext)\r\n */\r\nexport function usePdfViewer(\r\n multiSignerContext?: MultiSignerContext\r\n) {\r\n const viewerRef = useRef<PdfViewerRef>(null);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [isLoaded, setIsLoaded] = useState(false);\r\n const [pdfUrl, setPdfUrl] = useState<string | null>(null);\r\n \r\n // CRITICAL: Store both original and viewer PDF bytes\r\n // Original PDF has ALL fields (used for submission/flattening)\r\n // Viewer PDF has only current signer's fields (used for display)\r\n const [originalPdfBytes, setOriginalPdfBytes] = useState<Uint8Array | null>(null);\r\n const [_viewerPdfBytes, setViewerPdfBytes] = useState<Uint8Array | null>(null);\r\n const [extractedFields, setExtractedFields] = useState<EsignFormField[]>([]);\r\n\r\n const loadPdf = useCallback(async (url: string, signerEmailForExtraction?: string) => {\r\n setIsLoading(true);\r\n setError(null);\r\n setIsLoaded(false);\r\n setPdfUrl(url);\r\n\r\n try {\r\n // Initialize PDF.js configuration (lazy, only runs once)\r\n // This ensures the worker is configured before any PDF operations\r\n initializePdfJs();\r\n\r\n // Validate URL format\r\n const urlValidation = validatePdfUrl(url);\r\n if (!urlValidation.valid) {\r\n throw new PdfValidationError(urlValidation.error || 'Invalid PDF URL');\r\n }\r\n\r\n // Load PDF bytes for processing\r\n const bytes = await urlToPdfBytes(url);\r\n\r\n // Store as original PDF (with ALL fields)\r\n setOriginalPdfBytes(bytes);\r\n\r\n // Extract fields and filter BEFORE loading into viewer to prevent flash\r\n const fields = await extractVisibleFormFields(bytes, signerEmailForExtraction);\r\n setExtractedFields(fields);\r\n\r\n // Filter PDF for current signer (or just add labels for single-signer)\r\n const filteredBytes = await filterPdfForCurrentSigner(\r\n bytes,\r\n fields,\r\n multiSignerContext || {\r\n isMultiSigner: false,\r\n currentSigner: null,\r\n currentSignerEmail: '',\r\n isPrimarySigner: true,\r\n isFinalSigner: true\r\n }\r\n );\r\n setViewerPdfBytes(filteredBytes);\r\n\r\n // Load the filtered/labeled PDF into viewer (no flash!)\r\n const blobUrl = createPdfBlobUrl(filteredBytes);\r\n await viewerRef.current?.loadPdf(blobUrl);\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to load PDF';\r\n logger.error('Error loading PDF:', err);\r\n setError(errorMessage);\r\n setOriginalPdfBytes(null);\r\n setViewerPdfBytes(null);\r\n }\r\n }, [multiSignerContext]);\r\n\r\n const handleLoad = useCallback(() => {\r\n setIsLoading(false);\r\n setIsLoaded(true);\r\n setError(null);\r\n }, []);\r\n\r\n const handleError = useCallback((errorMessage: string) => {\r\n setIsLoading(false);\r\n setIsLoaded(false);\r\n setError(errorMessage);\r\n }, []);\r\n\r\n const getFormFieldValues = useCallback(async () => {\r\n if (!viewerRef.current) {\r\n return {};\r\n }\r\n return await viewerRef.current.getFormFieldValues();\r\n }, []);\r\n\r\n const setFormFieldValues = useCallback(async (values: Record<string, string>) => {\r\n if (!viewerRef.current) {\r\n return;\r\n }\r\n return await viewerRef.current.setFormFieldValues(values);\r\n }, []);\r\n\r\n const getAllFieldNames = useCallback(async () => {\r\n if (!viewerRef.current) {\r\n return [];\r\n }\r\n return await viewerRef.current.getAllFieldNames();\r\n }, []);\r\n\r\n const saveDocument = useCallback(async () => {\r\n if (!viewerRef.current) {\r\n return null;\r\n }\r\n return await viewerRef.current.saveDocument();\r\n }, []);\r\n\r\n /**\r\n * Inject placeholders and radio labels into the PDF viewer\r\n * Field extraction and filtering is now done in loadPdf to prevent flash\r\n */\r\n const extractFormFields = useCallback(\r\n async (_currentSignerEmail?: string) => {\r\n // Fields are already extracted in loadPdf, just inject placeholders\r\n if (viewerRef.current && extractedFields.length > 0) {\r\n // Small delay to ensure viewer has loaded\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n viewerRef.current.injectPlaceholders(extractedFields);\r\n // Inject radio labels as HTML elements (aligned with PDF.js rendered widgets)\r\n viewerRef.current.injectRadioLabels(extractedFields);\r\n }\r\n\r\n return extractedFields;\r\n },\r\n [extractedFields]\r\n );\r\n\r\n /**\r\n * Fill the PDF with form values and signatures, then return the filled PDF bytes\r\n * CRITICAL: Always uses originalPdfBytes (with ALL fields) for proper flattening\r\n */\r\n const fillPdf = useCallback(\r\n async (\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>,\r\n currentSignerEmail?: string,\r\n metadata?: { submissionId?: string; documentId?: string; author?: string; signerEmail?: string; signerInitials?: string; createdAt?: Date },\r\n auditTrail?: { userAgent?: string; screenResolution?: string; timezone?: string; language?: string; platform?: string; ipAddress?: string; geolocation?: { latitude: number; longitude: number; accuracy?: number } }\r\n ): Promise<Uint8Array> => {\r\n if (!originalPdfBytes) {\r\n throw new PdfProcessingError('No PDF loaded');\r\n }\r\n\r\n try {\r\n // Validate inputs\r\n const valuesValidation = validateFieldValues(fieldValues);\r\n if (!valuesValidation.valid) {\r\n logger.warn('Field values validation warnings:', valuesValidation.errors);\r\n // Don't throw - allow submission with warnings\r\n }\r\n\r\n const sigsValidation = validateSignatures(signatures);\r\n if (!sigsValidation.valid) {\r\n logger.warn('Signatures validation warnings:', sigsValidation.errors);\r\n // Don't throw - allow submission with warnings\r\n }\r\n\r\n const filledPdfBytes = await fillPdfWithSignatures(\r\n originalPdfBytes, // CRITICAL: Use original PDF with ALL fields\r\n signatures,\r\n fieldValues,\r\n currentSignerEmail,\r\n extractedFields, // Pass extracted fields for proper signature filtering\r\n metadata,\r\n auditTrail,\r\n multiSignerContext // Pass multi-signer context for partial flattening\r\n );\r\n return filledPdfBytes;\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to fill PDF';\r\n logger.error('Error filling PDF:', err);\r\n throw new PdfProcessingError(errorMessage, err);\r\n }\r\n },\r\n [originalPdfBytes, extractedFields, multiSignerContext]\r\n );\r\n\r\n /**\r\n * Validate that all required fields are filled\r\n */\r\n const validatePdf = useCallback(\r\n async (\r\n fieldValues: Record<string, string>,\r\n signatures: Record<string, string>,\r\n visibleFields?: EsignFormField[] // Optional: pass filtered fields for multi-signer validation\r\n ): Promise<{ isValid: boolean; errors: string[] }> => {\r\n if (!originalPdfBytes) {\r\n throw new Error('No PDF loaded');\r\n }\r\n\r\n try {\r\n // Use visibleFields if provided (for multi-signer), otherwise use extractedFields\r\n const fieldsToValidate = visibleFields || extractedFields;\r\n const errors = await validatePdfFormFields(\r\n originalPdfBytes, \r\n fieldValues, \r\n signatures,\r\n fieldsToValidate, // Pass visible/filtered fields for validation\r\n multiSignerContext // Pass multi-signer context for validation filtering\r\n );\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n };\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to validate PDF';\r\n throw new Error(errorMessage);\r\n }\r\n },\r\n [originalPdfBytes, extractedFields, multiSignerContext]\r\n );\r\n\r\n /**\r\n * Get required field status from PDF metadata using pdf-lib\r\n * Returns a map of field names to their required status\r\n */\r\n const getRequiredFieldsMap = useCallback(async (): Promise<Record<string, boolean>> => {\r\n if (!originalPdfBytes) {\r\n return {};\r\n }\r\n\r\n try {\r\n const { PDFDocument } = await loadPdfLib();\r\n const pdfDoc = await PDFDocument.load(originalPdfBytes);\r\n const form = pdfDoc.getForm();\r\n const fields = form.getFields();\r\n\r\n const requiredMap: Record<string, boolean> = {};\r\n for (const field of fields) {\r\n const fieldName = field.getName();\r\n const isRequired = field.isRequired();\r\n requiredMap[fieldName] = isRequired;\r\n }\r\n\r\n return requiredMap;\r\n } catch (err) {\r\n logger.error('Failed to get required fields map:', err);\r\n return {};\r\n }\r\n }, [originalPdfBytes]);\r\n\r\n /**\r\n * Get the current PDF bytes (original with ALL fields)\r\n */\r\n const getCurrentPdfBytes = useCallback(() => {\r\n return originalPdfBytes;\r\n }, [originalPdfBytes]);\r\n\r\n /**\r\n * Reload the PDF with new bytes (for preview after filling)\r\n */\r\n const reloadPdfWithBytes = useCallback(\r\n async (newPdfBytes: Uint8Array) => {\r\n try {\r\n // Create a blob URL from the new PDF bytes\r\n const blobUrl = createPdfBlobUrl(newPdfBytes);\r\n \r\n // Update state\r\n setOriginalPdfBytes(newPdfBytes);\r\n setViewerPdfBytes(newPdfBytes);\r\n setPdfUrl(blobUrl);\r\n \r\n // Reload in viewer\r\n await viewerRef.current?.loadPdf(blobUrl);\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to reload PDF';\r\n setError(errorMessage);\r\n }\r\n },\r\n []\r\n );\r\n\r\n /**\r\n * Reset the hook state\r\n */\r\n const reset = useCallback(() => {\r\n setIsLoading(false);\r\n setError(null);\r\n setIsLoaded(false);\r\n setPdfUrl(null);\r\n setOriginalPdfBytes(null);\r\n setViewerPdfBytes(null);\r\n setExtractedFields([]);\r\n }, []);\r\n\r\n return {\r\n // Ref and state\r\n viewerRef,\r\n isLoading,\r\n error,\r\n isLoaded,\r\n pdfUrl,\r\n pdfBytes: originalPdfBytes, // Expose as pdfBytes for backward compatibility\r\n extractedFields,\r\n \r\n // Basic operations\r\n loadPdf,\r\n handleLoad,\r\n handleError,\r\n getFormFieldValues,\r\n setFormFieldValues,\r\n getAllFieldNames,\r\n saveDocument,\r\n \r\n // Enhanced operations\r\n extractFormFields,\r\n fillPdf,\r\n validatePdf,\r\n getRequiredFieldsMap,\r\n getCurrentPdfBytes,\r\n reloadPdfWithBytes,\r\n reset,\r\n };\r\n}\r\n\r\n","import { useState, useCallback, useEffect, useRef } from 'react';\r\nimport type { FormField, ValidationError, FormFieldType } from '../types';\r\nimport { isValidISODate } from '../utils/date-validation-iso';\r\nimport { getFieldDisplayName } from '../utils/pdf-validators';\r\n\r\n/**\r\n * Hook to manage form field state and validation\r\n */\r\nexport function useFormFields(fields: FormField[] = []) {\r\n const [fieldValues, setFieldValues] = useState<Record<string, string>>({});\r\n\r\n // Seed field values from defaultValue when fields arrive or change.\r\n // Tracks which field IDs have been seeded so new fields get defaults\r\n // without overwriting user-edited values on existing fields.\r\n const seededFieldsRef = useRef<Set<string>>(new Set());\r\n useEffect(() => {\r\n if (fields.length === 0) return;\r\n const defaults: Record<string, string> = {};\r\n for (const field of fields) {\r\n if (\r\n field.defaultValue &&\r\n field.defaultValue.trim() &&\r\n !seededFieldsRef.current.has(field.id)\r\n ) {\r\n defaults[field.id] = field.defaultValue;\r\n seededFieldsRef.current.add(field.id);\r\n }\r\n }\r\n if (Object.keys(defaults).length > 0) {\r\n setFieldValues((prev) => ({ ...defaults, ...prev }));\r\n }\r\n }, [fields]);\r\n const [errors, setErrors] = useState<ValidationError[]>([]);\r\n const [touched, setTouched] = useState<Record<string, boolean>>({});\r\n\r\n const updateField = useCallback((fieldId: string, value: string) => {\r\n setFieldValues((prev) => ({\r\n ...prev,\r\n [fieldId]: value,\r\n }));\r\n // Mark field as touched\r\n setTouched((prev) => ({\r\n ...prev,\r\n [fieldId]: true,\r\n }));\r\n // Clear error for this field when value is updated\r\n setErrors((prev) => prev.filter((err) => err.field !== fieldId));\r\n }, []);\r\n\r\n const updateMultipleFields = useCallback((values: Record<string, string>) => {\r\n setFieldValues((prev) => ({\r\n ...prev,\r\n ...values,\r\n }));\r\n // Mark all updated fields as touched\r\n const touchedFields = Object.keys(values).reduce((acc, key) => {\r\n acc[key] = true;\r\n return acc;\r\n }, {} as Record<string, boolean>);\r\n setTouched((prev) => ({\r\n ...prev,\r\n ...touchedFields,\r\n }));\r\n // Clear errors for updated fields\r\n const updatedFieldIds = Object.keys(values);\r\n setErrors((prev) => prev.filter((err) => !updatedFieldIds.includes(err.field)));\r\n }, []);\r\n\r\n const validateField = useCallback(\r\n (fieldId: string) => {\r\n const field = fields.find((f) => f.id === fieldId);\r\n if (!field) return true;\r\n\r\n const value = fieldValues[fieldId];\r\n const newErrors = errors.filter((e) => e.field !== fieldId);\r\n\r\n if (field.required) {\r\n if (!value || value.trim() === '') {\r\n newErrors.push({\r\n field: fieldId,\r\n message: `${getFieldDisplayName(field)} is required`,\r\n });\r\n }\r\n }\r\n\r\n // Additional validation for specific field types\r\n if (value && field.maxLength && value.length > field.maxLength) {\r\n newErrors.push({\r\n field: fieldId,\r\n message: `${getFieldDisplayName(field)} must be at most ${field.maxLength} characters`,\r\n });\r\n }\r\n\r\n // Date validation\r\n if (value && field.type === ('date' as FormFieldType)) {\r\n if (!isValidISODate(value)) {\r\n newErrors.push({\r\n field: fieldId,\r\n message: 'Please enter a valid date',\r\n });\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return newErrors.length === errors.length - newErrors.filter((e) => e.field === fieldId).length;\r\n },\r\n [fields, fieldValues, errors]\r\n );\r\n\r\n const validateFields = useCallback(\r\n (signatures?: Record<string, string>) => {\r\n const newErrors: ValidationError[] = [];\r\n\r\n for (const field of fields) {\r\n if (field.required) {\r\n const value = fieldValues[field.id];\r\n \r\n // Check signature fields separately\r\n if (\r\n (field.type === 'signature' as FormFieldType || field.type === 'initials' as FormFieldType) &&\r\n signatures\r\n ) {\r\n if (!signatures[field.id]) {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${getFieldDisplayName(field)} is required`,\r\n });\r\n }\r\n } else if (!value || value.trim() === '') {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${getFieldDisplayName(field)} is required`,\r\n });\r\n }\r\n }\r\n\r\n // Validate maxLength\r\n const value = fieldValues[field.id];\r\n if (value && field.maxLength && value.length > field.maxLength) {\r\n newErrors.push({\r\n field: field.id,\r\n message: `${getFieldDisplayName(field)} must be at most ${field.maxLength} characters`,\r\n });\r\n }\r\n\r\n // Date validation\r\n if (value && field.type === ('date' as FormFieldType)) {\r\n if (!isValidISODate(value)) {\r\n newErrors.push({\r\n field: field.id,\r\n message: 'Please enter a valid date',\r\n });\r\n }\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return newErrors.length === 0;\r\n },\r\n [fields, fieldValues]\r\n );\r\n\r\n const resetFields = useCallback(() => {\r\n setFieldValues({});\r\n setErrors([]);\r\n setTouched({});\r\n }, []);\r\n\r\n const resetValidation = useCallback(() => {\r\n setErrors([]);\r\n }, []);\r\n\r\n const getFieldValue = useCallback(\r\n (fieldId: string) => {\r\n return fieldValues[fieldId] || '';\r\n },\r\n [fieldValues]\r\n );\r\n\r\n const getFieldError = useCallback(\r\n (fieldId: string) => {\r\n const error = errors.find((e) => e.field === fieldId);\r\n return error?.message;\r\n },\r\n [errors]\r\n );\r\n\r\n const isFieldTouched = useCallback(\r\n (fieldId: string) => {\r\n return touched[fieldId] || false;\r\n },\r\n [touched]\r\n );\r\n\r\n const setFieldValue = updateField; // Alias for consistency\r\n const setMultipleFieldValues = updateMultipleFields; // Alias for consistency\r\n const clearFields = resetFields; // Alias for consistency\r\n\r\n const hasErrors = errors.length > 0;\r\n\r\n return {\r\n fieldValues,\r\n errors,\r\n hasErrors,\r\n touched,\r\n updateField,\r\n updateMultipleFields,\r\n validateField,\r\n validateFields,\r\n resetFields,\r\n resetValidation,\r\n getFieldValue,\r\n getFieldError,\r\n isFieldTouched,\r\n // Aliases\r\n setFieldValue,\r\n setMultipleFieldValues,\r\n clearFields,\r\n };\r\n}\r\n\r\n","import { useRef, useState, useCallback } from 'react';\r\nimport type { SignatureCanvasRef } from '../types';\r\n\r\n/**\r\n * Hook to manage signature capture state and operations\r\n */\r\nexport function useSignatureCapture() {\r\n const canvasRef = useRef<SignatureCanvasRef>(null);\r\n const [signatureDataUrl, setSignatureDataUrl] = useState<string | null>(null);\r\n const [uploadedImage, setUploadedImage] = useState<string | null>(null);\r\n const [uploadError, setUploadError] = useState<string | null>(null);\r\n\r\n const clear = useCallback(() => {\r\n canvasRef.current?.clear();\r\n setSignatureDataUrl(null);\r\n }, []);\r\n\r\n const saveSignature = useCallback(() => {\r\n const dataUrl = canvasRef.current?.getSignatureDataUrl();\r\n if (dataUrl) {\r\n setSignatureDataUrl(dataUrl);\r\n return dataUrl;\r\n }\r\n return null;\r\n }, []);\r\n\r\n const isEmpty = useCallback(() => {\r\n return canvasRef.current?.isEmpty() ?? true;\r\n }, []);\r\n\r\n const handleFileUpload = useCallback((file: File) => {\r\n setUploadError(null);\r\n\r\n // Validate file type\r\n const allowedTypes = ['image/png', 'image/jpeg', 'image/jpg'];\r\n if (!allowedTypes.includes(file.type.toLowerCase())) {\r\n setUploadError('Please upload a PNG or JPEG image file.');\r\n return;\r\n }\r\n\r\n // Validate file size (max 5MB)\r\n const maxSizeInBytes = 5 * 1024 * 1024;\r\n if (file.size > maxSizeInBytes) {\r\n setUploadError('File size must be less than 5MB. Please choose a smaller image.');\r\n return;\r\n }\r\n\r\n const reader = new FileReader();\r\n reader.onload = (event) => {\r\n if (typeof event.target?.result === 'string') {\r\n setUploadedImage(event.target.result);\r\n setSignatureDataUrl(event.target.result);\r\n setUploadError(null);\r\n }\r\n };\r\n reader.onerror = () => {\r\n setUploadError('Failed to read the image file. Please try again.');\r\n };\r\n reader.readAsDataURL(file);\r\n }, []);\r\n\r\n const clearUpload = useCallback(() => {\r\n setUploadedImage(null);\r\n setUploadError(null);\r\n setSignatureDataUrl(null);\r\n }, []);\r\n\r\n const reset = useCallback(() => {\r\n clear();\r\n clearUpload();\r\n }, [clear, clearUpload]);\r\n\r\n return {\r\n canvasRef,\r\n signatureDataUrl,\r\n uploadedImage,\r\n uploadError,\r\n clear,\r\n saveSignature,\r\n isEmpty,\r\n handleFileUpload,\r\n clearUpload,\r\n reset,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook to manage signature and initials state\r\n */\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport type { FormField, FormFieldType } from '../types';\r\nimport { getFieldDisplayName } from '../utils/pdf-validators';\r\n\r\nexport interface SignatureData {\r\n [fieldId: string]: string; // Base64 data URL\r\n}\r\n\r\n/**\r\n * Hook for managing signatures and initials\r\n */\r\nexport function useSignatures() {\r\n const [signatures, setSignatures] = useState<SignatureData>({});\r\n\r\n // State for collected signatures (for auto-placement)\r\n const [collectedSignature, setCollectedSignature] = useState<string | null>(null);\r\n const [collectedInitials, setCollectedInitials] = useState<string | null>(null);\r\n\r\n /**\r\n * Add or update a signature for a field\r\n */\r\n const setSignature = useCallback((fieldId: string, dataUrl: string) => {\r\n setSignatures((prev) => ({\r\n ...prev,\r\n [fieldId]: dataUrl,\r\n }));\r\n }, []);\r\n\r\n /**\r\n * Remove a signature for a field\r\n */\r\n const clearSignature = useCallback((fieldId: string) => {\r\n setSignatures((prev) => {\r\n const newSignatures = { ...prev };\r\n delete newSignatures[fieldId];\r\n return newSignatures;\r\n });\r\n }, []);\r\n\r\n /**\r\n * Clear all signatures\r\n */\r\n const clearAllSignatures = useCallback(() => {\r\n setSignatures({});\r\n }, []);\r\n\r\n /**\r\n * Check if a field has a signature\r\n */\r\n const hasSignature = useCallback(\r\n (fieldId: string) => {\r\n return !!signatures[fieldId];\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Get signature data URL for a field\r\n */\r\n const getSignature = useCallback(\r\n (fieldId: string) => {\r\n return signatures[fieldId] || null;\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Validate that all required signature fields have signatures\r\n */\r\n const validateSignatures = useCallback(\r\n (fields: FormField[], currentSignatures?: SignatureData) => {\r\n const signaturesToCheck = currentSignatures ?? signatures;\r\n const errors: string[] = [];\r\n\r\n for (const field of fields) {\r\n if (field.required && (field.type === 'signature' as FormFieldType || field.type === 'initials' as FormFieldType)) {\r\n if (!signaturesToCheck[field.id]) {\r\n errors.push(`${getFieldDisplayName(field)} is required`);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n };\r\n },\r\n [signatures]\r\n );\r\n\r\n /**\r\n * Get count of signatures\r\n */\r\n const signatureCount = Object.keys(signatures).length;\r\n\r\n /**\r\n * Check if any signatures exist\r\n */\r\n const hasAnySignatures = signatureCount > 0;\r\n\r\n /**\r\n * Collect a signature or initials for auto-placement\r\n */\r\n const collectSignature = useCallback((type: 'signature' | 'initials', dataUrl: string) => {\r\n if (type === 'signature') {\r\n setCollectedSignature(dataUrl);\r\n } else {\r\n setCollectedInitials(dataUrl);\r\n }\r\n }, []);\r\n\r\n /**\r\n * Check if we have a collected signature or initials\r\n */\r\n const hasCollectedSignature = useCallback((type: 'signature' | 'initials'): boolean => {\r\n return type === 'signature'\r\n ? collectedSignature !== null\r\n : collectedInitials !== null;\r\n }, [collectedSignature, collectedInitials]);\r\n\r\n /**\r\n * Get the collected signature or initials\r\n */\r\n const getCollectedSignature = useCallback((type: 'signature' | 'initials'): string | null => {\r\n return type === 'signature' ? collectedSignature : collectedInitials;\r\n }, [collectedSignature, collectedInitials]);\r\n\r\n /**\r\n * Clear collected signatures\r\n */\r\n const clearCollectedSignatures = useCallback(() => {\r\n setCollectedSignature(null);\r\n setCollectedInitials(null);\r\n }, []);\r\n\r\n return {\r\n signatures,\r\n setSignature,\r\n clearSignature,\r\n clearAllSignatures,\r\n hasSignature,\r\n getSignature,\r\n validateSignatures,\r\n signatureCount,\r\n hasAnySignatures,\r\n // Auto-place functionality\r\n collectSignature,\r\n hasCollectedSignature,\r\n getCollectedSignature,\r\n clearCollectedSignatures,\r\n };\r\n}\r\n\r\n","/**\n * Hook for filtering form fields by signer with multi-signer support\n * Implements Dockmaster's exact field visibility logic\n */\n\nimport { useMemo } from 'react';\nimport type { EsignFormField, MultiSignerContext } from '../types';\nimport { isFieldVisibleToSigner, filterFieldsBySigner } from '../utils/field-visibility';\n\n/**\n * Hook for filtering form fields based on multi-signer context\n * \n * @param allFields - All form fields extracted from the PDF\n * @param multiSignerContext - Multi-signer context (from useMultiSignerContext)\n * @returns Filtered fields and utility functions\n * \n * @example\n * ```tsx\n * const context = useMultiSignerContext(currentSigner, isMultipleSignature, totalSigners);\n * const { filteredFields } = useFieldFiltering(allFields, context);\n * ```\n */\nexport function useFieldFiltering(\n allFields: EsignFormField[],\n multiSignerContext: MultiSignerContext\n) {\n /**\n * Filtered fields based on Dockmaster's multi-signer visibility logic\n */\n const filteredFields = useMemo(() => {\n // First, hide non-main signature/initials fields from UI\n // EXCEPTION: Keep ALL signature/initials fields (they need visual indicators even without acknowledgements)\n let fields = allFields.filter((field) => {\n // Keep signature_field_main and initials_field_main\n if (field.id === 'signature_field_main' || field.id === 'initials_field_main') {\n return true;\n }\n\n // Keep ALL signature/initials fields (for acknowledgements AND visual indicators)\n // Previously we only kept fields with acknowledgements, but fields without acknowledgements\n // also need to be tracked so they can show visual indicators when signed\n if (field.type === 'signature' || field.type === 'initials') {\n return true;\n }\n\n return true;\n });\n\n // Apply multi-signer filtering using centralized visibility logic\n return filterFieldsBySigner(fields, multiSignerContext);\n }, [allFields, multiSignerContext]);\n\n /**\n * Required fields from filtered set\n */\n const requiredFields = useMemo(() => {\n return filteredFields.filter((field) => field.required);\n }, [filteredFields]);\n\n /**\n * Optional fields from filtered set\n */\n const optionalFields = useMemo(() => {\n return filteredFields.filter((field) => !field.required);\n }, [filteredFields]);\n\n /**\n * Check if a field is visible to current signer\n * Uses the same logic as filteredFields for consistency\n */\n const isFieldVisible = (field: EsignFormField): boolean => {\n return isFieldVisibleToSigner(field, multiSignerContext);\n };\n\n return {\n // Filtered fields\n filteredFields,\n requiredFields,\n optionalFields,\n \n // Utilities\n isFieldVisible,\n \n // Counts\n totalFields: allFields.length,\n filteredCount: filteredFields.length,\n requiredCount: requiredFields.length,\n optionalCount: optionalFields.length,\n };\n}\n\n","/**\r\n * Hook for managing file attachments\r\n * Handles file uploads, validation, and state management\r\n */\r\n\r\nimport { useState, useCallback } from 'react';\r\nimport type {\r\n Attachment,\r\n AttachmentConstraints,\r\n AttachmentValidationResult,\r\n} from '../types';\r\nimport { logger, validateFile, isImageType, formatFileSize, DEFAULT_ATTACHMENT_CONSTRAINTS } from '../utils';\r\n\r\n/**\r\n * Generate a unique ID for attachments\r\n */\r\nfunction generateAttachmentId(): string {\r\n return `att_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Create a preview for image files\r\n */\r\nasync function createPreview(file: File): Promise<string | undefined> {\r\n if (!isImageType(file.type)) {\r\n return undefined;\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onload = () => resolve(reader.result as string);\r\n reader.onerror = reject;\r\n reader.readAsDataURL(file);\r\n });\r\n}\r\n\r\nexport interface UseAttachmentsOptions {\r\n constraints?: Partial<AttachmentConstraints>;\r\n onError?: (errors: string[]) => void;\r\n}\r\n\r\nexport function useAttachments(options: UseAttachmentsOptions = {}) {\r\n const [attachments, setAttachments] = useState<Attachment[]>([]);\r\n const [isUploading, setIsUploading] = useState(false);\r\n const [validationErrors, setValidationErrors] = useState<string[]>([]);\r\n\r\n const constraints: AttachmentConstraints = {\r\n ...DEFAULT_ATTACHMENT_CONSTRAINTS,\r\n ...options.constraints,\r\n };\r\n\r\n /**\r\n * Add files to attachments\r\n */\r\n const addFiles = useCallback(\r\n async (files: File[] | FileList) => {\r\n setIsUploading(true);\r\n setValidationErrors([]);\r\n\r\n const fileArray = Array.from(files);\r\n const errors: string[] = [];\r\n const newAttachments: Attachment[] = [];\r\n\r\n for (const file of fileArray) {\r\n // Validate file\r\n const validation = validateFile(file, constraints);\r\n\r\n if (!validation.valid) {\r\n errors.push(...validation.errors);\r\n continue;\r\n }\r\n\r\n // Check for duplicate file name\r\n const isDuplicate = [...attachments, ...newAttachments].some(\r\n (att) => att.name.toLowerCase() === file.name.toLowerCase()\r\n );\r\n if (isDuplicate) {\r\n errors.push(`\"${file.name}\" is already attached`);\r\n continue;\r\n }\r\n\r\n // Check total constraints manually\r\n const currentTotalSize = [...attachments, ...newAttachments].reduce((sum, att) => sum + att.size, 0);\r\n if (currentTotalSize + file.size > constraints.maxTotalSize) {\r\n const maxTotalMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n errors.push(`Adding \"${file.name}\" would exceed total size limit of ${maxTotalMB}MB`);\r\n continue;\r\n }\r\n \r\n if ([...attachments, ...newAttachments].length >= constraints.maxFiles) {\r\n errors.push(`Maximum of ${constraints.maxFiles} files allowed`);\r\n continue;\r\n }\r\n\r\n // Create attachment\r\n try {\r\n const preview = await createPreview(file);\r\n const attachment: Attachment = {\r\n id: generateAttachmentId(),\r\n file,\r\n name: file.name,\r\n size: file.size,\r\n type: file.type,\r\n uploadedAt: new Date(),\r\n preview,\r\n };\r\n newAttachments.push(attachment);\r\n } catch (error) {\r\n logger.error('Error creating attachment:', error);\r\n errors.push(`Failed to process file \"${file.name}\"`);\r\n }\r\n }\r\n\r\n // Update state\r\n if (newAttachments.length > 0) {\r\n setAttachments(prev => [...prev, ...newAttachments]);\r\n }\r\n\r\n if (errors.length > 0) {\r\n setValidationErrors(errors);\r\n options.onError?.(errors);\r\n }\r\n\r\n setIsUploading(false);\r\n\r\n return {\r\n added: newAttachments.length,\r\n errors,\r\n };\r\n },\r\n [attachments, constraints, options]\r\n );\r\n\r\n /**\r\n * Remove an attachment by ID\r\n */\r\n const removeAttachment = useCallback((attachmentId: string) => {\r\n setAttachments(prev => prev.filter(att => att.id !== attachmentId));\r\n setValidationErrors([]);\r\n }, []);\r\n\r\n /**\r\n * Clear all attachments\r\n */\r\n const clearAttachments = useCallback(() => {\r\n setAttachments([]);\r\n setValidationErrors([]);\r\n }, []);\r\n\r\n /**\r\n * Clear validation errors only\r\n */\r\n const clearValidationErrors = useCallback(() => {\r\n setValidationErrors([]);\r\n }, []);\r\n\r\n /**\r\n * Get total size of all attachments\r\n */\r\n const getTotalSize = useCallback(() => {\r\n return attachments.reduce((sum, att) => sum + att.size, 0);\r\n }, [attachments]);\r\n\r\n /**\r\n * Format bytes to human-readable string\r\n */\r\n const formatSize = useCallback((bytes: number): string => {\r\n return formatFileSize(bytes);\r\n }, []);\r\n\r\n /**\r\n * Validate all current attachments\r\n */\r\n const validateAll = useCallback((): AttachmentValidationResult => {\r\n const errors: string[] = [];\r\n\r\n // Check total size\r\n const totalSize = getTotalSize();\r\n if (totalSize > constraints.maxTotalSize) {\r\n const maxTotalMB = (constraints.maxTotalSize / 1024 / 1024).toFixed(1);\r\n errors.push(`Total file size (${formatSize(totalSize)}) exceeds ${maxTotalMB}MB limit`);\r\n }\r\n\r\n // Check number of files\r\n if (attachments.length > constraints.maxFiles) {\r\n errors.push(`Maximum of ${constraints.maxFiles} files allowed (currently ${attachments.length})`);\r\n }\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n errors,\r\n };\r\n }, [attachments, constraints, getTotalSize, formatSize]);\r\n\r\n return {\r\n // State\r\n attachments,\r\n isUploading,\r\n validationErrors,\r\n constraints,\r\n\r\n // Actions\r\n addFiles,\r\n removeAttachment,\r\n clearAttachments,\r\n clearValidationErrors,\r\n\r\n // Utilities\r\n getTotalSize,\r\n formatSize,\r\n validateAll,\r\n };\r\n}\r\n\r\n","/**\r\n * Hook for managing multi-signer context and determining signer roles\r\n */\r\n\r\nimport { useMemo } from 'react';\r\nimport type { Signer, MultiSignerContext } from '../types';\r\n\r\n/**\r\n * Calculate multi-signer context from simplified props\r\n * \r\n * @param currentSigner - The signer who is currently viewing/signing (if multi-signer)\r\n * @param isMultipleSignature - Whether this is a multi-signer document\r\n * @param totalSigners - Total number of signers (for determining if current is final)\r\n * @returns MultiSignerContext with calculated roles and flags\r\n * \r\n * @example\r\n * ```tsx\r\n * const context = useMultiSignerContext(\r\n * { id: '1', email: 'user@example.com', name: 'John', signOrder: 1, status: 'pending' },\r\n * true,\r\n * 3\r\n * );\r\n * // context.isPrimarySigner === true (signOrder === 1)\r\n * // context.isFinalSigner === false (signOrder !== totalSigners)\r\n * ```\r\n */\r\nexport function useMultiSignerContext(\r\n currentSigner?: Signer,\r\n isMultipleSignature?: boolean,\r\n totalSigners?: number\r\n): MultiSignerContext {\r\n return useMemo(() => {\r\n // Single signer mode (default)\r\n if (!isMultipleSignature || !currentSigner) {\r\n return {\r\n isMultiSigner: false,\r\n currentSigner: null,\r\n currentSignerEmail: '',\r\n isPrimarySigner: false,\r\n isFinalSigner: false,\r\n };\r\n }\r\n \r\n // Multi-signer mode - calculate roles based on signOrder\r\n const isPrimarySigner = currentSigner.signOrder === 1;\r\n \r\n // If totalSigners is provided, check if current signer is the last one\r\n // If not provided, assume current signer is final (safe default)\r\n const isFinalSigner = totalSigners \r\n ? currentSigner.signOrder === totalSigners \r\n : true;\r\n \r\n \r\n return {\r\n isMultiSigner: true,\r\n currentSigner,\r\n currentSignerEmail: currentSigner.email,\r\n isPrimarySigner,\r\n isFinalSigner,\r\n };\r\n }, [currentSigner, isMultipleSignature, totalSigners]);\r\n}\r\n\r\n","import { useState, useCallback, useRef, useEffect } from 'react';\r\nimport type { EsignFormField, Acknowledgement } from '../types';\r\n\r\ninterface AcknowledgementProgress {\r\n current: number;\r\n total: number;\r\n}\r\n\r\ninterface UnacknowledgedFieldDetail {\r\n field: EsignFormField;\r\n unacknowledgedItems: Acknowledgement[];\r\n}\r\n\r\ninterface UseAcknowledgementsReturn {\r\n acknowledgeItem: (fieldId: string, ackId: string) => void;\r\n isAcknowledged: (fieldId: string, ackId?: string) => boolean;\r\n isFieldFullyAcknowledged: (fieldId: string) => boolean;\r\n getFieldAcknowledgementProgress: (fieldId: string) => AcknowledgementProgress;\r\n acknowledgeAllForField: (fieldId: string) => void;\r\n getFieldsWithAcknowledgements: (fields: EsignFormField[]) => EsignFormField[];\r\n hasUnacknowledgedFields: (fields: EsignFormField[]) => boolean;\r\n getUnacknowledgedFields: (fields: EsignFormField[]) => EsignFormField[];\r\n getUnacknowledgedFieldsDetailed: (fields: EsignFormField[]) => UnacknowledgedFieldDetail[];\r\n resetAcknowledgements: () => void;\r\n}\r\n\r\n/**\r\n * Hook for managing acknowledgement state across form fields\r\n * \r\n * Tracks which acknowledgements have been accepted by the signer.\r\n * Acknowledgements are field-level requirements that must be explicitly\r\n * accepted before the field can be interacted with or submitted.\r\n * \r\n * State is stored in memory and resets on component unmount/page refresh.\r\n * \r\n * @param fields - Array of form fields that may contain acknowledgements\r\n * @returns Object with acknowledgement state management functions\r\n * \r\n * @example\r\n * ```tsx\r\n * const {\r\n * acknowledgeItem,\r\n * isFieldFullyAcknowledged,\r\n * hasUnacknowledgedFields\r\n * } = useAcknowledgements(fields);\r\n * \r\n * // Check if field can be submitted\r\n * if (hasUnacknowledgedFields(fields)) {\r\n * // Show acknowledgement modal\r\n * }\r\n * ```\r\n */\r\nexport function useAcknowledgements(\r\n fields: EsignFormField[]\r\n): UseAcknowledgementsReturn {\r\n // Map of fieldId -> Set of acknowledged acknowledgement IDs\r\n const [acknowledgedMap, setAcknowledgedMap] = useState<Map<string, Set<string>>>(\r\n new Map()\r\n );\r\n\r\n // Keep a ref to always have access to the latest acknowledgedMap\r\n // This allows isFieldFullyAcknowledged to read fresh state even in stale closures\r\n const acknowledgedMapRef = useRef(acknowledgedMap);\r\n useEffect(() => {\r\n acknowledgedMapRef.current = acknowledgedMap;\r\n }, [acknowledgedMap]);\r\n\r\n // Get all fields that have acknowledgements\r\n const getFieldsWithAcknowledgements = useCallback((fieldsToFilter: EsignFormField[]) => {\r\n return fieldsToFilter.filter(\r\n field => field.acknowledgements && field.acknowledgements.length > 0\r\n );\r\n }, []);\r\n\r\n // Acknowledge a specific acknowledgement item for a field\r\n const acknowledgeItem = useCallback((fieldId: string, ackId: string) => {\r\n setAcknowledgedMap(prev => {\r\n const newMap = new Map(prev);\r\n const fieldAcks = newMap.get(fieldId) || new Set<string>();\r\n fieldAcks.add(ackId);\r\n newMap.set(fieldId, fieldAcks);\r\n\r\n // Directly update the ref so isFieldFullyAcknowledged sees the change immediately\r\n // (useEffect that syncs the ref won't run until after render)\r\n acknowledgedMapRef.current = newMap;\r\n\r\n return newMap;\r\n });\r\n }, []);\r\n\r\n // Check if a specific acknowledgement or all acknowledgements are acknowledged\r\n // Uses acknowledgedMapRef to always read fresh state, even when called from stale closures\r\n const isAcknowledged = useCallback((fieldId: string, ackId?: string) => {\r\n // Use ref to get the latest state\r\n const fieldAcks = acknowledgedMapRef.current.get(fieldId);\r\n if (!fieldAcks) return false;\r\n\r\n if (ackId) {\r\n return fieldAcks.has(ackId);\r\n }\r\n\r\n // If no ackId provided, check if any are acknowledged\r\n return fieldAcks.size > 0;\r\n }, []);\r\n\r\n // Check if all acknowledgements for a field are acknowledged\r\n // Uses acknowledgedMapRef to always read fresh state, even when called from stale closures\r\n const isFieldFullyAcknowledged = useCallback((fieldId: string) => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements || field.acknowledgements.length === 0) {\r\n return true; // No acknowledgements means fully acknowledged\r\n }\r\n\r\n // Use ref to get the latest state, not the captured closure value\r\n const fieldAcks = acknowledgedMapRef.current.get(fieldId);\r\n if (!fieldAcks) return false;\r\n\r\n return field.acknowledgements.every(ack => fieldAcks.has(ack.id));\r\n }, [fields]);\r\n\r\n // Get acknowledgement progress for a field\r\n const getFieldAcknowledgementProgress = useCallback((fieldId: string): AcknowledgementProgress => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements || field.acknowledgements.length === 0) {\r\n return { current: 0, total: 0 };\r\n }\r\n\r\n const fieldAcks = acknowledgedMap.get(fieldId) || new Set<string>();\r\n return {\r\n current: fieldAcks.size,\r\n total: field.acknowledgements.length\r\n };\r\n }, [fields, acknowledgedMap]);\r\n\r\n // Acknowledge all acknowledgements for a field\r\n const acknowledgeAllForField = useCallback((fieldId: string) => {\r\n const field = fields.find(f => f.id === fieldId);\r\n if (!field || !field.acknowledgements) return;\r\n\r\n setAcknowledgedMap(prev => {\r\n const newMap = new Map(prev);\r\n const allAckIds = new Set(field.acknowledgements!.map(ack => ack.id));\r\n newMap.set(fieldId, allAckIds);\r\n return newMap;\r\n });\r\n }, [fields]);\r\n\r\n // Check if there are any unacknowledged fields\r\n const hasUnacknowledgedFields = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n const fieldsWithAcks = getFieldsWithAcknowledgements(fieldsToCheck);\r\n return fieldsWithAcks.some(field => !isFieldFullyAcknowledged(field.id));\r\n }, [getFieldsWithAcknowledgements, isFieldFullyAcknowledged]);\r\n\r\n // Get list of fields that have unacknowledged items\r\n const getUnacknowledgedFields = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n const fieldsWithAcks = getFieldsWithAcknowledgements(fieldsToCheck);\r\n return fieldsWithAcks.filter(field => !isFieldFullyAcknowledged(field.id));\r\n }, [getFieldsWithAcknowledgements, isFieldFullyAcknowledged]);\r\n\r\n // Get detailed information about fields with unacknowledged items\r\n const getUnacknowledgedFieldsDetailed = useCallback((fieldsToCheck: EsignFormField[]) => {\r\n return fieldsToCheck\r\n .filter(field => field.acknowledgements && field.acknowledgements.length > 0)\r\n .map(field => ({\r\n field,\r\n unacknowledgedItems: field.acknowledgements!.filter(\r\n ack => !isAcknowledged(field.id, ack.id)\r\n )\r\n }))\r\n .filter(({ unacknowledgedItems }) => unacknowledgedItems.length > 0);\r\n }, [isAcknowledged]);\r\n\r\n // Reset all acknowledgements (for testing or form reset)\r\n const resetAcknowledgements = useCallback(() => {\r\n setAcknowledgedMap(new Map());\r\n }, []);\r\n\r\n return {\r\n acknowledgeItem,\r\n isAcknowledged,\r\n isFieldFullyAcknowledged,\r\n getFieldAcknowledgementProgress,\r\n acknowledgeAllForField,\r\n getFieldsWithAcknowledgements,\r\n hasUnacknowledgedFields,\r\n getUnacknowledgedFields,\r\n getUnacknowledgedFieldsDetailed,\r\n resetAcknowledgements,\r\n };\r\n}\r\n\r\n"]}