@signiphi/pdf-signer 0.1.1

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 (192) hide show
  1. package/INSTALLING_LOCALLY.md +184 -0
  2. package/LICENSE +2 -0
  3. package/README.md +1093 -0
  4. package/assets/viewer.html +314 -0
  5. package/dist/__tests__/helpers/fixtures.d.ts +43 -0
  6. package/dist/__tests__/helpers/fixtures.d.ts.map +1 -0
  7. package/dist/__tests__/helpers/mocks.d.ts +333 -0
  8. package/dist/__tests__/helpers/mocks.d.ts.map +1 -0
  9. package/dist/__tests__/setup.d.ts +6 -0
  10. package/dist/__tests__/setup.d.ts.map +1 -0
  11. package/dist/components/AttachmentUpload.d.ts +17 -0
  12. package/dist/components/AttachmentUpload.d.ts.map +1 -0
  13. package/dist/components/EditableFieldsPanel.d.ts +30 -0
  14. package/dist/components/EditableFieldsPanel.d.ts.map +1 -0
  15. package/dist/components/ErrorBoundary.d.ts +67 -0
  16. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  17. package/dist/components/FormFieldsView.d.ts +42 -0
  18. package/dist/components/FormFieldsView.d.ts.map +1 -0
  19. package/dist/components/PdfViewerStyled.d.ts +16 -0
  20. package/dist/components/PdfViewerStyled.d.ts.map +1 -0
  21. package/dist/components/PoweredBySigniphi.d.ts +11 -0
  22. package/dist/components/PoweredBySigniphi.d.ts.map +1 -0
  23. package/dist/components/SignatureCanvas.d.ts +12 -0
  24. package/dist/components/SignatureCanvas.d.ts.map +1 -0
  25. package/dist/components/SignatureInitialsBox.d.ts +23 -0
  26. package/dist/components/SignatureInitialsBox.d.ts.map +1 -0
  27. package/dist/components/SignatureModal.d.ts +22 -0
  28. package/dist/components/SignatureModal.d.ts.map +1 -0
  29. package/dist/components/SigningInstructions.d.ts +12 -0
  30. package/dist/components/SigningInstructions.d.ts.map +1 -0
  31. package/dist/components/SubmissionForm.d.ts +52 -0
  32. package/dist/components/SubmissionForm.d.ts.map +1 -0
  33. package/dist/components/ViewToggleToolbar.d.ts +30 -0
  34. package/dist/components/ViewToggleToolbar.d.ts.map +1 -0
  35. package/dist/components/form-fields/CheckboxRenderer.d.ts +10 -0
  36. package/dist/components/form-fields/CheckboxRenderer.d.ts.map +1 -0
  37. package/dist/components/form-fields/DateFieldRenderer.d.ts +14 -0
  38. package/dist/components/form-fields/DateFieldRenderer.d.ts.map +1 -0
  39. package/dist/components/form-fields/DropdownRenderer.d.ts +14 -0
  40. package/dist/components/form-fields/DropdownRenderer.d.ts.map +1 -0
  41. package/dist/components/form-fields/FormFieldRenderer.d.ts +20 -0
  42. package/dist/components/form-fields/FormFieldRenderer.d.ts.map +1 -0
  43. package/dist/components/form-fields/InitialsFieldRenderer.d.ts +14 -0
  44. package/dist/components/form-fields/InitialsFieldRenderer.d.ts.map +1 -0
  45. package/dist/components/form-fields/RadioGroupRenderer.d.ts +10 -0
  46. package/dist/components/form-fields/RadioGroupRenderer.d.ts.map +1 -0
  47. package/dist/components/form-fields/SignatureFieldRenderer.d.ts +16 -0
  48. package/dist/components/form-fields/SignatureFieldRenderer.d.ts.map +1 -0
  49. package/dist/components/form-fields/TextFieldRenderer.d.ts +14 -0
  50. package/dist/components/form-fields/TextFieldRenderer.d.ts.map +1 -0
  51. package/dist/components/form-fields/TextLabelRenderer.d.ts +14 -0
  52. package/dist/components/form-fields/TextLabelRenderer.d.ts.map +1 -0
  53. package/dist/components/form-fields/index.d.ts +14 -0
  54. package/dist/components/form-fields/index.d.ts.map +1 -0
  55. package/dist/components/index.d.ts +14 -0
  56. package/dist/components/index.d.ts.map +1 -0
  57. package/dist/components/index.js +6297 -0
  58. package/dist/components/index.js.map +1 -0
  59. package/dist/components/index.mjs +6248 -0
  60. package/dist/components/index.mjs.map +1 -0
  61. package/dist/core/PdfViewerCore.d.ts +19 -0
  62. package/dist/core/PdfViewerCore.d.ts.map +1 -0
  63. package/dist/core/SignatureCaptureCore.d.ts +37 -0
  64. package/dist/core/SignatureCaptureCore.d.ts.map +1 -0
  65. package/dist/core/index.d.ts +3 -0
  66. package/dist/core/index.d.ts.map +1 -0
  67. package/dist/core/index.js +907 -0
  68. package/dist/core/index.js.map +1 -0
  69. package/dist/core/index.mjs +884 -0
  70. package/dist/core/index.mjs.map +1 -0
  71. package/dist/hooks/index.d.ts +8 -0
  72. package/dist/hooks/index.d.ts.map +1 -0
  73. package/dist/hooks/index.js +2167 -0
  74. package/dist/hooks/index.js.map +1 -0
  75. package/dist/hooks/index.mjs +2139 -0
  76. package/dist/hooks/index.mjs.map +1 -0
  77. package/dist/hooks/useAttachments.d.ts +25 -0
  78. package/dist/hooks/useAttachments.d.ts.map +1 -0
  79. package/dist/hooks/useFieldFiltering.d.ts +29 -0
  80. package/dist/hooks/useFieldFiltering.d.ts.map +1 -0
  81. package/dist/hooks/useFormFields.d.ts +23 -0
  82. package/dist/hooks/useFormFields.d.ts.map +1 -0
  83. package/dist/hooks/useMultiSignerContext.d.ts +25 -0
  84. package/dist/hooks/useMultiSignerContext.d.ts.map +1 -0
  85. package/dist/hooks/usePdfViewer.d.ts +52 -0
  86. package/dist/hooks/usePdfViewer.d.ts.map +1 -0
  87. package/dist/hooks/useSignatureCapture.d.ts +17 -0
  88. package/dist/hooks/useSignatureCapture.d.ts.map +1 -0
  89. package/dist/hooks/useSignatures.d.ts +25 -0
  90. package/dist/hooks/useSignatures.d.ts.map +1 -0
  91. package/dist/index.css +4929 -0
  92. package/dist/index.css.map +1 -0
  93. package/dist/index.d.ts +17 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +7220 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/index.mjs +7093 -0
  98. package/dist/index.mjs.map +1 -0
  99. package/dist/integrations/index.d.ts +6 -0
  100. package/dist/integrations/index.d.ts.map +1 -0
  101. package/dist/integrations/index.js +242 -0
  102. package/dist/integrations/index.js.map +1 -0
  103. package/dist/integrations/index.mjs +218 -0
  104. package/dist/integrations/index.mjs.map +1 -0
  105. package/dist/integrations/next-config.d.ts +46 -0
  106. package/dist/integrations/next-config.d.ts.map +1 -0
  107. package/dist/integrations/vite-plugin.d.ts +48 -0
  108. package/dist/integrations/vite-plugin.d.ts.map +1 -0
  109. package/dist/lib/index.d.ts +3 -0
  110. package/dist/lib/index.d.ts.map +1 -0
  111. package/dist/lib/ui/alert.d.ts +9 -0
  112. package/dist/lib/ui/alert.d.ts.map +1 -0
  113. package/dist/lib/ui/button.d.ts +12 -0
  114. package/dist/lib/ui/button.d.ts.map +1 -0
  115. package/dist/lib/ui/calendar.d.ts +10 -0
  116. package/dist/lib/ui/calendar.d.ts.map +1 -0
  117. package/dist/lib/ui/card.d.ts +9 -0
  118. package/dist/lib/ui/card.d.ts.map +1 -0
  119. package/dist/lib/ui/checkbox.d.ts +5 -0
  120. package/dist/lib/ui/checkbox.d.ts.map +1 -0
  121. package/dist/lib/ui/dialog.d.ts +20 -0
  122. package/dist/lib/ui/dialog.d.ts.map +1 -0
  123. package/dist/lib/ui/index.d.ts +12 -0
  124. package/dist/lib/ui/index.d.ts.map +1 -0
  125. package/dist/lib/ui/input.d.ts +6 -0
  126. package/dist/lib/ui/input.d.ts.map +1 -0
  127. package/dist/lib/ui/label.d.ts +6 -0
  128. package/dist/lib/ui/label.d.ts.map +1 -0
  129. package/dist/lib/ui/popover.d.ts +7 -0
  130. package/dist/lib/ui/popover.d.ts.map +1 -0
  131. package/dist/lib/ui/radio-group.d.ts +6 -0
  132. package/dist/lib/ui/radio-group.d.ts.map +1 -0
  133. package/dist/lib/ui/select.d.ts +14 -0
  134. package/dist/lib/ui/select.d.ts.map +1 -0
  135. package/dist/lib/utils.d.ts +7 -0
  136. package/dist/lib/utils.d.ts.map +1 -0
  137. package/dist/styles/index.css +5004 -0
  138. package/dist/types/index.d.ts +265 -0
  139. package/dist/types/index.d.ts.map +1 -0
  140. package/dist/types/index.js +26 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/types/index.mjs +23 -0
  143. package/dist/types/index.mjs.map +1 -0
  144. package/dist/utils/attachment-validators.d.ts +118 -0
  145. package/dist/utils/attachment-validators.d.ts.map +1 -0
  146. package/dist/utils/audit-trail.d.ts +27 -0
  147. package/dist/utils/audit-trail.d.ts.map +1 -0
  148. package/dist/utils/date-validation.d.ts +30 -0
  149. package/dist/utils/date-validation.d.ts.map +1 -0
  150. package/dist/utils/errors.d.ts +106 -0
  151. package/dist/utils/errors.d.ts.map +1 -0
  152. package/dist/utils/field-extraction.d.ts +27 -0
  153. package/dist/utils/field-extraction.d.ts.map +1 -0
  154. package/dist/utils/field-visibility.d.ts +104 -0
  155. package/dist/utils/field-visibility.d.ts.map +1 -0
  156. package/dist/utils/index.d.ts +17 -0
  157. package/dist/utils/index.d.ts.map +1 -0
  158. package/dist/utils/index.js +2501 -0
  159. package/dist/utils/index.js.map +1 -0
  160. package/dist/utils/index.mjs +2404 -0
  161. package/dist/utils/index.mjs.map +1 -0
  162. package/dist/utils/logger.d.ts +16 -0
  163. package/dist/utils/logger.d.ts.map +1 -0
  164. package/dist/utils/pdf-field-type-helpers.d.ts +78 -0
  165. package/dist/utils/pdf-field-type-helpers.d.ts.map +1 -0
  166. package/dist/utils/pdf-helpers.d.ts +38 -0
  167. package/dist/utils/pdf-helpers.d.ts.map +1 -0
  168. package/dist/utils/pdf-lib-loader.d.ts +45 -0
  169. package/dist/utils/pdf-lib-loader.d.ts.map +1 -0
  170. package/dist/utils/pdf-manipulation.d.ts +93 -0
  171. package/dist/utils/pdf-manipulation.d.ts.map +1 -0
  172. package/dist/utils/pdf-validators.d.ts +149 -0
  173. package/dist/utils/pdf-validators.d.ts.map +1 -0
  174. package/dist/utils/pdf-viewer-filter.d.ts +35 -0
  175. package/dist/utils/pdf-viewer-filter.d.ts.map +1 -0
  176. package/dist/utils/pdf-widget-helpers.d.ts +98 -0
  177. package/dist/utils/pdf-widget-helpers.d.ts.map +1 -0
  178. package/dist/utils/pdfjs-config.d.ts +56 -0
  179. package/dist/utils/pdfjs-config.d.ts.map +1 -0
  180. package/dist/utils/pdfjs-version-check.d.ts +28 -0
  181. package/dist/utils/pdfjs-version-check.d.ts.map +1 -0
  182. package/dist/utils/performance-monitor.d.ts +172 -0
  183. package/dist/utils/performance-monitor.d.ts.map +1 -0
  184. package/dist/utils/tracking.d.ts +89 -0
  185. package/dist/utils/tracking.d.ts.map +1 -0
  186. package/package.json +180 -0
  187. package/scripts/analyze-bundle.js +271 -0
  188. package/scripts/copy-utils.js +227 -0
  189. package/scripts/copy-utils.test.js +164 -0
  190. package/scripts/postinstall.js +109 -0
  191. package/scripts/setup.js +108 -0
  192. package/src/styles/index.css +139 -0
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bundle Size Analysis Script
4
+ *
5
+ * Analyzes the built bundle sizes and generates a detailed report.
6
+ * Compares against defined budgets and warns if exceeded.
7
+ *
8
+ * Usage:
9
+ * node scripts/analyze-bundle.js
10
+ * node scripts/analyze-bundle.js --format=json
11
+ * node scripts/analyze-bundle.js --check-budgets
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const zlib = require('zlib');
17
+
18
+ // Bundle size budgets (in bytes)
19
+ const BUDGETS = {
20
+ 'index.mjs': { raw: 200 * 1024, gzip: 60 * 1024 },
21
+ 'core/index.mjs': { raw: 50 * 1024, gzip: 15 * 1024 },
22
+ 'components/index.mjs': { raw: 120 * 1024, gzip: 35 * 1024 },
23
+ 'hooks/index.mjs': { raw: 80 * 1024, gzip: 25 * 1024 },
24
+ 'types/index.mjs': { raw: 5 * 1024, gzip: 2 * 1024 },
25
+ 'utils/index.mjs': { raw: 100 * 1024, gzip: 30 * 1024 },
26
+ };
27
+
28
+ /**
29
+ * Get file size in different compression formats
30
+ */
31
+ function getFileSizes(filePath) {
32
+ if (!fs.existsSync(filePath)) {
33
+ return null;
34
+ }
35
+
36
+ const content = fs.readFileSync(filePath);
37
+ const raw = content.length;
38
+ const gzipped = zlib.gzipSync(content, { level: 9 }).length;
39
+ const brotli = zlib.brotliCompressSync(content).length;
40
+
41
+ return { raw, gzipped, brotli };
42
+ }
43
+
44
+ /**
45
+ * Format bytes to human-readable string
46
+ */
47
+ function formatBytes(bytes) {
48
+ if (bytes === 0) return '0 B';
49
+ const k = 1024;
50
+ const sizes = ['B', 'KB', 'MB', 'GB'];
51
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
52
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
53
+ }
54
+
55
+ /**
56
+ * Check if size exceeds budget
57
+ */
58
+ function checkBudget(filePath, sizes) {
59
+ const budget = BUDGETS[filePath];
60
+ if (!budget) return { withinBudget: true };
61
+
62
+ const rawExceeded = sizes.raw > budget.raw;
63
+ const gzipExceeded = sizes.gzipped > budget.gzip;
64
+
65
+ return {
66
+ withinBudget: !rawExceeded && !gzipExceeded,
67
+ rawExceeded,
68
+ gzipExceeded,
69
+ rawPercent: (sizes.raw / budget.raw * 100).toFixed(1),
70
+ gzipPercent: (sizes.gzipped / budget.gzip * 100).toFixed(1),
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Analyze all bundle files
76
+ */
77
+ function analyzeBundles() {
78
+ const distDir = path.join(__dirname, '..', 'dist');
79
+ const files = [
80
+ 'index.mjs',
81
+ 'index.js',
82
+ 'core/index.mjs',
83
+ 'core/index.js',
84
+ 'components/index.mjs',
85
+ 'components/index.js',
86
+ 'hooks/index.mjs',
87
+ 'hooks/index.js',
88
+ 'types/index.mjs',
89
+ 'types/index.js',
90
+ 'utils/index.mjs',
91
+ 'utils/index.js',
92
+ ];
93
+
94
+ const results = [];
95
+ let totalRaw = 0;
96
+ let totalGzipped = 0;
97
+ let totalBrotli = 0;
98
+ let budgetViolations = 0;
99
+
100
+ for (const file of files) {
101
+ const filePath = path.join(distDir, file);
102
+ const sizes = getFileSizes(filePath);
103
+
104
+ if (!sizes) {
105
+ console.warn(`⚠️ File not found: ${file}`);
106
+ continue;
107
+ }
108
+
109
+ const budgetCheck = checkBudget(file, sizes);
110
+
111
+ results.push({
112
+ file,
113
+ sizes,
114
+ budgetCheck,
115
+ });
116
+
117
+ totalRaw += sizes.raw;
118
+ totalGzipped += sizes.gzipped;
119
+ totalBrotli += sizes.brotli;
120
+
121
+ if (!budgetCheck.withinBudget) {
122
+ budgetViolations++;
123
+ }
124
+ }
125
+
126
+ return {
127
+ results,
128
+ totals: {
129
+ raw: totalRaw,
130
+ gzipped: totalGzipped,
131
+ brotli: totalBrotli,
132
+ },
133
+ budgetViolations,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Generate markdown report
139
+ */
140
+ function generateMarkdownReport(analysis) {
141
+ const lines = [];
142
+
143
+ lines.push('# Bundle Size Analysis Report');
144
+ lines.push('');
145
+ lines.push(`**Generated:** ${new Date().toISOString()}`);
146
+ lines.push('');
147
+
148
+ // Summary
149
+ lines.push('## Summary');
150
+ lines.push('');
151
+ lines.push(`- **Total Raw Size:** ${formatBytes(analysis.totals.raw)}`);
152
+ lines.push(`- **Total Gzipped:** ${formatBytes(analysis.totals.gzipped)}`);
153
+ lines.push(`- **Total Brotli:** ${formatBytes(analysis.totals.brotli)}`);
154
+ lines.push(`- **Budget Violations:** ${analysis.budgetViolations}`);
155
+ lines.push('');
156
+
157
+ // Detailed results
158
+ lines.push('## Entry Points');
159
+ lines.push('');
160
+
161
+ for (const result of analysis.results) {
162
+ const { file, sizes, budgetCheck } = result;
163
+ const icon = budgetCheck.withinBudget ? '✅' : '❌';
164
+
165
+ lines.push(`### ${icon} \`${file}\``);
166
+ lines.push('');
167
+ lines.push('| Format | Size | Budget Status |');
168
+ lines.push('|--------|------|---------------|');
169
+ lines.push(`| Raw | ${formatBytes(sizes.raw)} | ${budgetCheck.rawPercent ? `${budgetCheck.rawPercent}% of budget` : 'N/A'} |`);
170
+ lines.push(`| Gzipped | ${formatBytes(sizes.gzipped)} | ${budgetCheck.gzipPercent ? `${budgetCheck.gzipPercent}% of budget` : 'N/A'} |`);
171
+ lines.push(`| Brotli | ${formatBytes(sizes.brotli)} | - |`);
172
+ lines.push('');
173
+
174
+ if (!budgetCheck.withinBudget) {
175
+ lines.push('**⚠️ Budget Exceeded:**');
176
+ if (budgetCheck.rawExceeded) {
177
+ lines.push(`- Raw size exceeds budget (${budgetCheck.rawPercent}%)`);
178
+ }
179
+ if (budgetCheck.gzipExceeded) {
180
+ lines.push(`- Gzipped size exceeds budget (${budgetCheck.gzipPercent}%)`);
181
+ }
182
+ lines.push('');
183
+ }
184
+ }
185
+
186
+ return lines.join('\n');
187
+ }
188
+
189
+ /**
190
+ * Generate JSON report
191
+ */
192
+ function generateJsonReport(analysis) {
193
+ return JSON.stringify(analysis, null, 2);
194
+ }
195
+
196
+ /**
197
+ * Generate console report
198
+ */
199
+ function generateConsoleReport(analysis) {
200
+ console.log('\n╔════════════════════════════════════════════════╗');
201
+ console.log('║ Bundle Size Analysis Report ║');
202
+ console.log('╚════════════════════════════════════════════════╝\n');
203
+
204
+ console.log('📦 Total Sizes:');
205
+ console.log(` Raw: ${formatBytes(analysis.totals.raw)}`);
206
+ console.log(` Gzipped: ${formatBytes(analysis.totals.gzipped)}`);
207
+ console.log(` Brotli: ${formatBytes(analysis.totals.brotli)}`);
208
+ console.log('');
209
+
210
+ console.log('📊 Entry Points:\n');
211
+
212
+ for (const result of analysis.results) {
213
+ const { file, sizes, budgetCheck } = result;
214
+ const icon = budgetCheck.withinBudget ? '✅' : '❌';
215
+
216
+ console.log(`${icon} ${file}`);
217
+ console.log(` Raw: ${formatBytes(sizes.raw).padEnd(12)} ${budgetCheck.rawPercent ? `(${budgetCheck.rawPercent}% of budget)` : ''}`);
218
+ console.log(` Gzipped: ${formatBytes(sizes.gzipped).padEnd(12)} ${budgetCheck.gzipPercent ? `(${budgetCheck.gzipPercent}% of budget)` : ''}`);
219
+ console.log(` Brotli: ${formatBytes(sizes.brotli)}`);
220
+
221
+ if (!budgetCheck.withinBudget) {
222
+ console.log(' ⚠️ Budget exceeded!');
223
+ }
224
+ console.log('');
225
+ }
226
+
227
+ if (analysis.budgetViolations > 0) {
228
+ console.log(`⚠️ ${analysis.budgetViolations} budget violation(s) detected!\n`);
229
+ process.exit(1);
230
+ } else {
231
+ console.log('✅ All bundles within budget limits!\n');
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Main function
237
+ */
238
+ function main() {
239
+ const args = process.argv.slice(2);
240
+ const format = args.find(arg => arg.startsWith('--format='))?.split('=')[1] || 'console';
241
+ const checkBudgets = args.includes('--check-budgets');
242
+
243
+ console.log('🔍 Analyzing bundle sizes...\n');
244
+
245
+ const analysis = analyzeBundles();
246
+
247
+ switch (format) {
248
+ case 'json':
249
+ console.log(generateJsonReport(analysis));
250
+ break;
251
+ case 'markdown':
252
+ console.log(generateMarkdownReport(analysis));
253
+ break;
254
+ case 'console':
255
+ default:
256
+ generateConsoleReport(analysis);
257
+ break;
258
+ }
259
+
260
+ if (checkBudgets && analysis.budgetViolations > 0) {
261
+ process.exit(1);
262
+ }
263
+ }
264
+
265
+ // Run if called directly
266
+ if (require.main === module) {
267
+ main();
268
+ }
269
+
270
+ module.exports = { analyzeBundles, generateMarkdownReport, generateJsonReport };
271
+
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Shared utilities for copying PDF.js files
5
+ * Used by both postinstall.js and setup.js
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ /**
12
+ * Get the pdfjs-dist version from package.json
13
+ */
14
+ function getPdfjsVersion() {
15
+ try {
16
+ const packageJsonPath = path.join(__dirname, '../package.json');
17
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
18
+ return packageJson.dependencies['pdfjs-dist'];
19
+ } catch (error) {
20
+ return 'unknown';
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Get the saved version from target directory
26
+ */
27
+ function getSavedVersion(targetDir) {
28
+ try {
29
+ const versionFile = path.join(targetDir, '.version');
30
+ if (fs.existsSync(versionFile)) {
31
+ return fs.readFileSync(versionFile, 'utf8').trim();
32
+ }
33
+ } catch (error) {
34
+ // Ignore
35
+ }
36
+ return null;
37
+ }
38
+
39
+ /**
40
+ * Copy a directory recursively
41
+ */
42
+ function copyDirectory(src, dest) {
43
+ if (!fs.existsSync(src)) {
44
+ return false;
45
+ }
46
+
47
+ fs.mkdirSync(dest, { recursive: true });
48
+
49
+ const entries = fs.readdirSync(src, { withFileTypes: true });
50
+
51
+ for (const entry of entries) {
52
+ const srcPath = path.join(src, entry.name);
53
+ const destPath = path.join(dest, entry.name);
54
+
55
+ if (entry.isDirectory()) {
56
+ copyDirectory(srcPath, destPath);
57
+ } else {
58
+ fs.copyFileSync(srcPath, destPath);
59
+ }
60
+ }
61
+
62
+ return true;
63
+ }
64
+
65
+ /**
66
+ * Find the pdfjs-dist package directory
67
+ */
68
+ function findPdfjsDistPath() {
69
+ // Try require.resolve first (most reliable)
70
+ try {
71
+ const pdfjsPackagePath = require.resolve('pdfjs-dist/package.json');
72
+ return path.dirname(pdfjsPackagePath);
73
+ } catch (e) {
74
+ // Fallback to path searching
75
+ }
76
+
77
+ // Start from our package's node_modules
78
+ let currentDir = __dirname;
79
+
80
+ // Go up to our package root
81
+ currentDir = path.join(currentDir, '..');
82
+
83
+ // Common locations to check
84
+ const searchPaths = [
85
+ // In the same node_modules (peer)
86
+ path.join(currentDir, '..', 'pdfjs-dist'),
87
+ // In our node_modules
88
+ path.join(currentDir, 'node_modules', 'pdfjs-dist'),
89
+ // In parent project's node_modules
90
+ path.join(currentDir, '..', '..', 'pdfjs-dist'),
91
+ // In parent project's node_modules (one more level up for monorepos)
92
+ path.join(currentDir, '..', '..', '..', 'pdfjs-dist'),
93
+ // Try from process.cwd() (user's project root)
94
+ path.join(process.cwd(), 'node_modules', 'pdfjs-dist'),
95
+ ];
96
+
97
+ for (const searchPath of searchPaths) {
98
+ if (fs.existsSync(searchPath)) {
99
+ return searchPath;
100
+ }
101
+ }
102
+
103
+ return null;
104
+ }
105
+
106
+ /**
107
+ * Find the user's project root and public directory
108
+ */
109
+ function findPublicDirectory() {
110
+ // Try process.cwd() first (where user ran npm install)
111
+ let projectRoot = process.cwd();
112
+
113
+ // Verify it's a project root (has package.json or node_modules)
114
+ if (!fs.existsSync(path.join(projectRoot, 'package.json')) &&
115
+ !fs.existsSync(path.join(projectRoot, 'node_modules'))) {
116
+ // Fallback: navigate up from our package location
117
+ let currentDir = path.join(__dirname, '..');
118
+ let searchDir = currentDir;
119
+
120
+ for (let i = 0; i < 5; i++) {
121
+ const parentDir = path.dirname(searchDir);
122
+ const nodeModulesDir = path.join(parentDir, 'node_modules');
123
+ const ourPackageDir = path.join(nodeModulesDir, '@signiphi', 'pdf-signer');
124
+
125
+ if (fs.existsSync(nodeModulesDir) && fs.existsSync(ourPackageDir)) {
126
+ projectRoot = parentDir;
127
+ break;
128
+ }
129
+
130
+ searchDir = parentDir;
131
+ }
132
+ }
133
+
134
+ // Common public directory patterns
135
+ const publicDirCandidates = [
136
+ path.join(projectRoot, 'public'),
137
+ path.join(projectRoot, 'static'),
138
+ path.join(projectRoot, 'dist', 'public'),
139
+ path.join(projectRoot, 'src', 'public'),
140
+ ];
141
+
142
+ for (const candidate of publicDirCandidates) {
143
+ if (fs.existsSync(candidate)) {
144
+ return candidate;
145
+ }
146
+ }
147
+
148
+ // Default to public directory (will be created if it doesn't exist)
149
+ return path.join(projectRoot, 'public');
150
+ }
151
+
152
+ /**
153
+ * Copy PDF.js files to target directory
154
+ * @param {string} targetDir - Target directory (e.g., public/pdfjs)
155
+ * @param {boolean} force - Force overwrite even if up to date
156
+ * @returns {boolean} Success status
157
+ */
158
+ function copyPdfJsFiles(targetDir, force = false) {
159
+ // Find pdfjs-dist - try require.resolve first (most reliable)
160
+ let pdfjsPath = null;
161
+ try {
162
+ const pdfjsPackagePath = require.resolve('pdfjs-dist/package.json');
163
+ pdfjsPath = path.dirname(pdfjsPackagePath);
164
+ } catch (e) {
165
+ // Fallback to path searching
166
+ pdfjsPath = findPdfjsDistPath();
167
+ }
168
+
169
+ if (!pdfjsPath || !fs.existsSync(pdfjsPath)) {
170
+ throw new Error('pdfjs-dist package not found. Make sure it is installed.');
171
+ }
172
+
173
+ // Check if already up to date
174
+ if (!force) {
175
+ const currentVersion = getPdfjsVersion();
176
+ const savedVersion = getSavedVersion(targetDir);
177
+
178
+ if (currentVersion === savedVersion && fs.existsSync(targetDir)) {
179
+ return false; // Already up to date
180
+ }
181
+ }
182
+
183
+ // Create target directory
184
+ fs.mkdirSync(targetDir, { recursive: true });
185
+
186
+ // Copy build directory (contains pdf.worker.mjs and other build files)
187
+ const buildSrc = path.join(pdfjsPath, 'build');
188
+ const buildDest = path.join(targetDir, 'build');
189
+ if (!copyDirectory(buildSrc, buildDest)) {
190
+ throw new Error('Failed to copy build directory');
191
+ }
192
+
193
+ // Copy web directory (contains pdf_viewer.mjs, css, and assets)
194
+ const webSrc = path.join(pdfjsPath, 'web');
195
+ const webDest = path.join(targetDir, 'web');
196
+ if (!copyDirectory(webSrc, webDest)) {
197
+ throw new Error('Failed to copy web directory');
198
+ }
199
+
200
+ // Copy custom viewer.html from our package assets
201
+ // PDF.js 5.x no longer includes viewer.html, so we provide our own
202
+ const customViewerSrc = path.join(__dirname, '..', 'assets', 'viewer.html');
203
+ const customViewerDest = path.join(webDest, 'viewer.html');
204
+
205
+ if (fs.existsSync(customViewerSrc)) {
206
+ fs.copyFileSync(customViewerSrc, customViewerDest);
207
+ } else {
208
+ throw new Error('Custom viewer.html template not found in package assets');
209
+ }
210
+
211
+ // Write version file
212
+ const currentVersion = getPdfjsVersion();
213
+ const versionFile = path.join(targetDir, '.version');
214
+ fs.writeFileSync(versionFile, currentVersion, 'utf8');
215
+
216
+ return true; // Copy successful
217
+ }
218
+
219
+ module.exports = {
220
+ getPdfjsVersion,
221
+ getSavedVersion,
222
+ copyDirectory,
223
+ findPdfjsDistPath,
224
+ findPublicDirectory,
225
+ copyPdfJsFiles,
226
+ };
227
+
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Tests for copy-utils.js
3
+ * Note: These are basic smoke tests. Full integration tests would require actual file system operations.
4
+ */
5
+
6
+ const { describe, it, expect, beforeEach, afterEach } = require('vitest');
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const copyUtils = require('./copy-utils.js');
10
+
11
+ describe('copy-utils', () => {
12
+ describe('getPdfjsVersion', () => {
13
+ it('should return a version string', () => {
14
+ const version = copyUtils.getPdfjsVersion();
15
+ expect(version).toBeDefined();
16
+ expect(typeof version).toBe('string');
17
+ // Should be a valid version or 'unknown'
18
+ expect(version).toMatch(/^\d+\.\d+\.\d+$|^unknown$/);
19
+ });
20
+ });
21
+
22
+ describe('getSavedVersion', () => {
23
+ const testDir = path.join(__dirname, '__test_temp__');
24
+ const versionFile = path.join(testDir, '.version');
25
+
26
+ beforeEach(() => {
27
+ // Create test directory
28
+ if (!fs.existsSync(testDir)) {
29
+ fs.mkdirSync(testDir, { recursive: true });
30
+ }
31
+ });
32
+
33
+ afterEach(() => {
34
+ // Cleanup test directory
35
+ if (fs.existsSync(testDir)) {
36
+ fs.rmSync(testDir, { recursive: true, force: true });
37
+ }
38
+ });
39
+
40
+ it('should return null if version file does not exist', () => {
41
+ const version = copyUtils.getSavedVersion(testDir);
42
+ expect(version).toBeNull();
43
+ });
44
+
45
+ it('should return version from .version file', () => {
46
+ fs.writeFileSync(versionFile, '5.3.93', 'utf8');
47
+ const version = copyUtils.getSavedVersion(testDir);
48
+ expect(version).toBe('5.3.93');
49
+ });
50
+
51
+ it('should trim whitespace from version file', () => {
52
+ fs.writeFileSync(versionFile, ' 5.3.93 \n', 'utf8');
53
+ const version = copyUtils.getSavedVersion(testDir);
54
+ expect(version).toBe('5.3.93');
55
+ });
56
+ });
57
+
58
+ describe('findPdfjsDistPath', () => {
59
+ it('should find pdfjs-dist package', () => {
60
+ const pdfjsPath = copyUtils.findPdfjsDistPath();
61
+ // Should either find it or return null (if not installed)
62
+ if (pdfjsPath) {
63
+ expect(fs.existsSync(pdfjsPath)).toBe(true);
64
+ expect(pdfjsPath).toContain('pdfjs-dist');
65
+ }
66
+ });
67
+ });
68
+
69
+ describe('copyDirectory', () => {
70
+ const testSrcDir = path.join(__dirname, '__test_src__');
71
+ const testDestDir = path.join(__dirname, '__test_dest__');
72
+
73
+ beforeEach(() => {
74
+ // Create test source directory with sample files
75
+ if (!fs.existsSync(testSrcDir)) {
76
+ fs.mkdirSync(testSrcDir, { recursive: true });
77
+ fs.writeFileSync(path.join(testSrcDir, 'test.txt'), 'test content');
78
+ fs.mkdirSync(path.join(testSrcDir, 'subdir'), { recursive: true });
79
+ fs.writeFileSync(path.join(testSrcDir, 'subdir', 'nested.txt'), 'nested content');
80
+ }
81
+ });
82
+
83
+ afterEach(() => {
84
+ // Cleanup test directories
85
+ if (fs.existsSync(testSrcDir)) {
86
+ fs.rmSync(testSrcDir, { recursive: true, force: true });
87
+ }
88
+ if (fs.existsSync(testDestDir)) {
89
+ fs.rmSync(testDestDir, { recursive: true, force: true });
90
+ }
91
+ });
92
+
93
+ it('should copy directory and its contents', () => {
94
+ const result = copyUtils.copyDirectory(testSrcDir, testDestDir);
95
+
96
+ expect(result).toBe(true);
97
+ expect(fs.existsSync(testDestDir)).toBe(true);
98
+ expect(fs.existsSync(path.join(testDestDir, 'test.txt'))).toBe(true);
99
+ expect(fs.existsSync(path.join(testDestDir, 'subdir', 'nested.txt'))).toBe(true);
100
+
101
+ const content = fs.readFileSync(path.join(testDestDir, 'test.txt'), 'utf8');
102
+ expect(content).toBe('test content');
103
+ });
104
+
105
+ it('should return false if source does not exist', () => {
106
+ const result = copyUtils.copyDirectory('/nonexistent/path', testDestDir);
107
+ expect(result).toBe(false);
108
+ });
109
+ });
110
+
111
+ describe('copyPdfJsFiles', () => {
112
+ const testTargetDir = path.join(__dirname, '__test_pdfjs__');
113
+
114
+ afterEach(() => {
115
+ // Cleanup test directory
116
+ if (fs.existsSync(testTargetDir)) {
117
+ fs.rmSync(testTargetDir, { recursive: true, force: true });
118
+ }
119
+ });
120
+
121
+ it('should handle missing pdfjs-dist gracefully', () => {
122
+ // This test might fail if pdfjs-dist is actually installed
123
+ // It's mainly to check that the function doesn't crash
124
+ try {
125
+ copyUtils.copyPdfJsFiles(testTargetDir, false);
126
+ } catch (error) {
127
+ // Expected to throw if pdfjs-dist is not found
128
+ expect(error.message).toContain('pdfjs-dist');
129
+ }
130
+ });
131
+
132
+ it('should not copy if already up to date', () => {
133
+ const pdfjsPath = copyUtils.findPdfjsDistPath();
134
+ if (!pdfjsPath) {
135
+ // Skip test if pdfjs-dist is not available
136
+ return;
137
+ }
138
+
139
+ // First copy
140
+ copyUtils.copyPdfJsFiles(testTargetDir, false);
141
+ expect(fs.existsSync(testTargetDir)).toBe(true);
142
+
143
+ // Second copy should not happen (up to date)
144
+ const result = copyUtils.copyPdfJsFiles(testTargetDir, false);
145
+ expect(result).toBe(false);
146
+ });
147
+
148
+ it('should force copy when force flag is true', () => {
149
+ const pdfjsPath = copyUtils.findPdfjsDistPath();
150
+ if (!pdfjsPath) {
151
+ // Skip test if pdfjs-dist is not available
152
+ return;
153
+ }
154
+
155
+ // First copy
156
+ copyUtils.copyPdfJsFiles(testTargetDir, false);
157
+
158
+ // Force copy should always happen
159
+ const result = copyUtils.copyPdfJsFiles(testTargetDir, true);
160
+ expect(result).toBe(true);
161
+ });
162
+ });
163
+ });
164
+