pdf-oxide 0.3.24

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 (62) hide show
  1. package/README.md +218 -0
  2. package/binding.gyp +35 -0
  3. package/package.json +78 -0
  4. package/src/builders/annotation-builder.ts +367 -0
  5. package/src/builders/conversion-options-builder.ts +257 -0
  6. package/src/builders/index.ts +12 -0
  7. package/src/builders/metadata-builder.ts +317 -0
  8. package/src/builders/pdf-builder.ts +386 -0
  9. package/src/builders/search-options-builder.ts +151 -0
  10. package/src/document-editor-manager.ts +318 -0
  11. package/src/errors.ts +1629 -0
  12. package/src/form-field-manager.ts +666 -0
  13. package/src/hybrid-ml-manager.ts +283 -0
  14. package/src/index.ts +453 -0
  15. package/src/managers/accessibility-manager.ts +338 -0
  16. package/src/managers/annotation-manager.ts +439 -0
  17. package/src/managers/barcode-manager.ts +235 -0
  18. package/src/managers/batch-manager.ts +533 -0
  19. package/src/managers/cache-manager.ts +486 -0
  20. package/src/managers/compliance-manager.ts +375 -0
  21. package/src/managers/content-manager.ts +339 -0
  22. package/src/managers/document-utility-manager.ts +922 -0
  23. package/src/managers/dom-pdf-creator.ts +365 -0
  24. package/src/managers/editing-manager.ts +514 -0
  25. package/src/managers/enterprise-manager.ts +478 -0
  26. package/src/managers/extended-managers.ts +437 -0
  27. package/src/managers/extraction-manager.ts +583 -0
  28. package/src/managers/final-utilities.ts +429 -0
  29. package/src/managers/hybrid-ml-advanced.ts +479 -0
  30. package/src/managers/index.ts +239 -0
  31. package/src/managers/layer-manager.ts +500 -0
  32. package/src/managers/metadata-manager.ts +303 -0
  33. package/src/managers/ocr-manager.ts +756 -0
  34. package/src/managers/optimization-manager.ts +262 -0
  35. package/src/managers/outline-manager.ts +196 -0
  36. package/src/managers/page-manager.ts +289 -0
  37. package/src/managers/pattern-detection.ts +440 -0
  38. package/src/managers/rendering-manager.ts +863 -0
  39. package/src/managers/search-manager.ts +385 -0
  40. package/src/managers/security-manager.ts +345 -0
  41. package/src/managers/signature-manager.ts +1664 -0
  42. package/src/managers/streams.ts +618 -0
  43. package/src/managers/xfa-manager.ts +500 -0
  44. package/src/pdf-creator-manager.ts +494 -0
  45. package/src/properties.ts +522 -0
  46. package/src/result-accessors-manager.ts +867 -0
  47. package/src/tests/advanced-features.test.ts +414 -0
  48. package/src/tests/advanced.test.ts +266 -0
  49. package/src/tests/extended-managers.test.ts +316 -0
  50. package/src/tests/final-utilities.test.ts +455 -0
  51. package/src/tests/foundation.test.ts +315 -0
  52. package/src/tests/high-demand.test.ts +257 -0
  53. package/src/tests/specialized.test.ts +97 -0
  54. package/src/thumbnail-manager.ts +272 -0
  55. package/src/types/common.ts +142 -0
  56. package/src/types/document-types.ts +457 -0
  57. package/src/types/index.ts +6 -0
  58. package/src/types/manager-types.ts +284 -0
  59. package/src/types/native-bindings.ts +517 -0
  60. package/src/workers/index.ts +7 -0
  61. package/src/workers/pool.ts +274 -0
  62. package/src/workers/worker.ts +131 -0
package/src/errors.ts ADDED
@@ -0,0 +1,1629 @@
1
+ /**
2
+ * Unified Error Handling for PDF Oxide
3
+ *
4
+ * Provides comprehensive exception hierarchy consistent across all language bindings.
5
+ * Uses 4-digit error codes organized by category (1000-9999).
6
+ *
7
+ * Error Code System:
8
+ * - 1000-1999: Parse errors
9
+ * - 2000-2999: I/O errors
10
+ * - 3000-3999: Encryption errors
11
+ * - 4000-4999: State errors
12
+ * - 5000-5999: Unsupported feature errors
13
+ * - 6000-6999: Validation errors
14
+ * - 7000-7999: Rendering errors
15
+ * - 8000-8999: Search errors
16
+ * - 9000-9999: Other errors (compliance, OCR, etc.)
17
+ */
18
+
19
+ import type { PdfErrorDetails } from './types/common';
20
+
21
+ /**
22
+ * Error categories for classification and handling
23
+ */
24
+ export enum ErrorCategory {
25
+ VALIDATION = 'validation',
26
+ IO = 'io',
27
+ ENCRYPTION = 'encryption',
28
+ PARSING = 'parsing',
29
+ RENDERING = 'rendering',
30
+ SEARCH = 'search',
31
+ PERMISSION = 'permission',
32
+ RESOURCE = 'resource',
33
+ STATE = 'state',
34
+ UNSUPPORTED = 'unsupported',
35
+ COMPLIANCE = 'compliance',
36
+ OCR = 'ocr',
37
+ SIGNATURE = 'signature',
38
+ REDACTION = 'redaction',
39
+ UNKNOWN = 'unknown',
40
+ }
41
+
42
+ /**
43
+ * Error severity levels for prioritization and monitoring
44
+ */
45
+ export enum ErrorSeverity {
46
+ LOW = 'low',
47
+ MEDIUM = 'medium',
48
+ HIGH = 'high',
49
+ CRITICAL = 'critical',
50
+ }
51
+
52
+ /**
53
+ * Recovery information for error handling
54
+ */
55
+ export interface ErrorRecovery {
56
+ canRetry: boolean;
57
+ retryAfterMs?: number;
58
+ suggestions: string[];
59
+ alternativeApproach?: string;
60
+ }
61
+
62
+ /**
63
+ * Base class for all PDF Oxide errors.
64
+ *
65
+ * @class PdfException
66
+ * @extends {Error}
67
+ * @property {string} code - 4-digit error code (XXXX format)
68
+ * @property {string} message - Human-readable error message
69
+ * @property {PdfErrorDetails} details - Additional context information
70
+ *
71
+ * @example
72
+ * try {
73
+ * // PDF operation
74
+ * } catch (err) {
75
+ * if (err instanceof PdfException) {
76
+ * console.log(`[${err.code}] ${err.message}`);
77
+ * console.log('Context:', err.details);
78
+ * }
79
+ * }
80
+ */
81
+ export class PdfException extends Error {
82
+ public readonly code: string;
83
+ public readonly message: string;
84
+ public readonly details: PdfErrorDetails;
85
+ public readonly category: ErrorCategory;
86
+ public readonly severity: ErrorSeverity;
87
+ public readonly recovery: ErrorRecovery;
88
+
89
+ /**
90
+ * Creates a new PdfException.
91
+ *
92
+ * @param code - 4-digit error code
93
+ * @param message - Human-readable error message
94
+ * @param category - Error category for classification
95
+ * @param severity - Error severity level
96
+ * @param details - Additional context information
97
+ * @param recovery - Recovery information
98
+ */
99
+ constructor(
100
+ code: string,
101
+ message: string,
102
+ category: ErrorCategory = ErrorCategory.UNKNOWN,
103
+ severity: ErrorSeverity = ErrorSeverity.HIGH,
104
+ details: PdfErrorDetails = {},
105
+ recovery: Partial<ErrorRecovery> = {}
106
+ ) {
107
+ if (!code || code.length !== 4 || !/^\d{4}$/.test(code)) {
108
+ throw new Error('Code must be 4 digits');
109
+ }
110
+
111
+ super(`[${code}] ${message}`);
112
+ this.name = this.constructor.name;
113
+ this.code = code;
114
+ this.message = message;
115
+ this.category = category;
116
+ this.severity = severity;
117
+ this.details = {
118
+ timestamp: new Date().toISOString(),
119
+ ...details,
120
+ };
121
+ this.recovery = {
122
+ canRetry: false,
123
+ suggestions: [],
124
+ ...recovery,
125
+ };
126
+
127
+ // Maintain proper stack trace for where our error was thrown
128
+ if (Error.captureStackTrace) {
129
+ Error.captureStackTrace(this, this.constructor);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Adds operational context to this exception for better diagnostics.
135
+ *
136
+ * @param operation - Name of the operation that failed
137
+ * @param context - Additional context key-value pairs
138
+ * @returns This exception for method chaining
139
+ *
140
+ * @example
141
+ * throw new FileNotFound('Not found')
142
+ * .withContext('openFile', { path: '/tmp/doc.pdf' });
143
+ */
144
+ withContext(operation: string, context: Record<string, any> = {}): this {
145
+ this.details.operation = operation;
146
+ this.details.context = { ...this.details.context, ...context };
147
+ return this;
148
+ }
149
+
150
+ /**
151
+ * Get a comprehensive error message with all details
152
+ * @returns Formatted error message with context and suggestions
153
+ */
154
+ getFullMessage(): string {
155
+ const parts: string[] = [
156
+ `[${this.code}] ${this.message}`,
157
+ `Category: ${this.category} | Severity: ${this.severity}`,
158
+ ];
159
+
160
+ if (this.details.operation) {
161
+ parts.push(`Operation: ${this.details.operation}`);
162
+ }
163
+
164
+ if (this.details.context && Object.keys(this.details.context).length > 0) {
165
+ const contextStr = Object.entries(this.details.context)
166
+ .map(([key, value]) => ` ${key}: ${JSON.stringify(value)}`)
167
+ .join('\n');
168
+ parts.push(`Context:\n${contextStr}`);
169
+ }
170
+
171
+ if (this.recovery.suggestions.length > 0) {
172
+ const suggestionsStr = this.recovery.suggestions
173
+ .map((s) => ` • ${s}`)
174
+ .join('\n');
175
+ parts.push(`Recovery Suggestions:\n${suggestionsStr}`);
176
+ }
177
+
178
+ if (this.recovery.alternativeApproach) {
179
+ parts.push(`Alternative Approach: ${this.recovery.alternativeApproach}`);
180
+ }
181
+
182
+ if (this.recovery.canRetry) {
183
+ const retryMsg = this.recovery.retryAfterMs
184
+ ? `retry after ${this.recovery.retryAfterMs}ms`
185
+ : 'retry';
186
+ parts.push(`Status: Retryable (${retryMsg})`);
187
+ }
188
+
189
+ return parts.join('\n');
190
+ }
191
+
192
+ /**
193
+ * Convert error to JSON for logging/monitoring
194
+ * @returns JSON representation of the error
195
+ */
196
+ toJSON() {
197
+ return {
198
+ name: this.name,
199
+ code: this.code,
200
+ message: this.message,
201
+ category: this.category,
202
+ severity: this.severity,
203
+ details: this.details,
204
+ recovery: this.recovery,
205
+ stack: this.stack,
206
+ };
207
+ }
208
+ }
209
+
210
+ // ===== Parse Errors (1000-1999) =====
211
+
212
+ export class ParseException extends PdfException {
213
+ constructor(message: string, details: PdfErrorDetails = {}) {
214
+ super(
215
+ '1000',
216
+ message,
217
+ ErrorCategory.PARSING,
218
+ ErrorSeverity.HIGH,
219
+ details,
220
+ {
221
+ canRetry: false,
222
+ suggestions: [
223
+ 'Verify the PDF file is not corrupted',
224
+ 'Try opening the file with Adobe Reader',
225
+ 'Check that the file is a valid PDF',
226
+ ],
227
+ }
228
+ );
229
+ }
230
+ }
231
+
232
+ export class InvalidStructure extends PdfException {
233
+ constructor(message: string, details: PdfErrorDetails = {}) {
234
+ super(
235
+ '1101',
236
+ message,
237
+ ErrorCategory.PARSING,
238
+ ErrorSeverity.HIGH,
239
+ details,
240
+ {
241
+ canRetry: false,
242
+ suggestions: [
243
+ 'The PDF structure is invalid or incomplete',
244
+ 'Try re-saving the PDF with a PDF tool',
245
+ 'Contact the PDF creator for a corrected version',
246
+ ],
247
+ }
248
+ );
249
+ }
250
+ }
251
+
252
+ export class CorruptedData extends PdfException {
253
+ constructor(message: string, details: PdfErrorDetails = {}) {
254
+ super(
255
+ '1200',
256
+ message,
257
+ ErrorCategory.PARSING,
258
+ ErrorSeverity.HIGH,
259
+ details,
260
+ {
261
+ canRetry: false,
262
+ suggestions: [
263
+ 'PDF file may be corrupted or damaged',
264
+ 'Try opening the file with Adobe Reader',
265
+ 'Attempt to recover the file using a PDF recovery tool',
266
+ ],
267
+ }
268
+ );
269
+ }
270
+ }
271
+
272
+ export class UnsupportedVersion extends PdfException {
273
+ constructor(message: string, details: PdfErrorDetails = {}) {
274
+ super(
275
+ '1300',
276
+ message,
277
+ ErrorCategory.UNSUPPORTED,
278
+ ErrorSeverity.MEDIUM,
279
+ details,
280
+ {
281
+ canRetry: false,
282
+ suggestions: [
283
+ 'This PDF version is not supported',
284
+ 'Try converting the PDF to a standard format',
285
+ 'Update your PDF library to a newer version',
286
+ ],
287
+ alternativeApproach:
288
+ 'Use a PDF converter tool to convert to standard PDF format',
289
+ }
290
+ );
291
+ }
292
+ }
293
+
294
+ // ===== I/O Errors (2000-2999) =====
295
+
296
+ export class IoException extends PdfException {
297
+ constructor(message: string, details: PdfErrorDetails = {}) {
298
+ super(
299
+ '2000',
300
+ message,
301
+ ErrorCategory.IO,
302
+ ErrorSeverity.HIGH,
303
+ details,
304
+ {
305
+ canRetry: true,
306
+ retryAfterMs: 1000,
307
+ suggestions: [
308
+ 'Check file permissions (readable)',
309
+ 'Verify file path exists',
310
+ 'Ensure disk space available',
311
+ 'Check file is not locked by another process',
312
+ ],
313
+ }
314
+ );
315
+ }
316
+ }
317
+
318
+ export class FileNotFound extends PdfException {
319
+ constructor(message: string, details: PdfErrorDetails = {}) {
320
+ super(
321
+ '2100',
322
+ message,
323
+ ErrorCategory.IO,
324
+ ErrorSeverity.MEDIUM,
325
+ details,
326
+ {
327
+ canRetry: false,
328
+ suggestions: [
329
+ 'Verify the file path is correct',
330
+ 'Check that the file exists',
331
+ 'Ensure the path is absolute or properly resolved',
332
+ ],
333
+ }
334
+ );
335
+ }
336
+ }
337
+
338
+ export class PermissionDenied extends PdfException {
339
+ constructor(message: string, details: PdfErrorDetails = {}) {
340
+ super(
341
+ '2200',
342
+ message,
343
+ ErrorCategory.PERMISSION,
344
+ ErrorSeverity.HIGH,
345
+ details,
346
+ {
347
+ canRetry: false,
348
+ suggestions: [
349
+ 'Check file permissions using chmod/ls -l',
350
+ 'Ensure the process has read permissions',
351
+ 'Try running with appropriate permissions',
352
+ ],
353
+ alternativeApproach:
354
+ 'Copy the file to a location with proper permissions',
355
+ }
356
+ );
357
+ }
358
+ }
359
+
360
+ export class DiskFull extends PdfException {
361
+ constructor(message: string, details: PdfErrorDetails = {}) {
362
+ super(
363
+ '2300',
364
+ message,
365
+ ErrorCategory.RESOURCE,
366
+ ErrorSeverity.CRITICAL,
367
+ details,
368
+ {
369
+ canRetry: true,
370
+ retryAfterMs: 2000,
371
+ suggestions: [
372
+ 'Free up disk space',
373
+ 'Delete unnecessary files',
374
+ 'Archive old files to external storage',
375
+ ],
376
+ alternativeApproach:
377
+ 'Process the PDF on a device with more available storage',
378
+ }
379
+ );
380
+ }
381
+ }
382
+
383
+ export class NetworkError extends PdfException {
384
+ constructor(message: string, details: PdfErrorDetails = {}) {
385
+ super(
386
+ '2400',
387
+ message,
388
+ ErrorCategory.IO,
389
+ ErrorSeverity.MEDIUM,
390
+ details,
391
+ {
392
+ canRetry: true,
393
+ retryAfterMs: 2000,
394
+ suggestions: [
395
+ 'Check network connectivity',
396
+ 'Verify the remote server is reachable',
397
+ 'Check firewall and proxy settings',
398
+ ],
399
+ }
400
+ );
401
+ }
402
+ }
403
+
404
+ // ===== Encryption Errors (3000-3999) =====
405
+
406
+ export class EncryptionException extends PdfException {
407
+ constructor(message: string, details: PdfErrorDetails = {}) {
408
+ super(
409
+ '3000',
410
+ message,
411
+ ErrorCategory.ENCRYPTION,
412
+ ErrorSeverity.HIGH,
413
+ details,
414
+ {
415
+ canRetry: false,
416
+ suggestions: [
417
+ 'Check if PDF requires password',
418
+ 'Verify encryption credentials',
419
+ 'Try opening PDF in Adobe Reader to verify',
420
+ ],
421
+ }
422
+ );
423
+ }
424
+ }
425
+
426
+ export class InvalidPassword extends PdfException {
427
+ constructor(message: string, details: PdfErrorDetails = {}) {
428
+ super(
429
+ '3100',
430
+ message,
431
+ ErrorCategory.ENCRYPTION,
432
+ ErrorSeverity.MEDIUM,
433
+ details,
434
+ {
435
+ canRetry: true,
436
+ retryAfterMs: 1000,
437
+ suggestions: [
438
+ 'Verify the password is correct',
439
+ 'Check for leading/trailing spaces',
440
+ 'Ensure correct keyboard layout is selected',
441
+ 'Try password with different case',
442
+ ],
443
+ }
444
+ );
445
+ }
446
+ }
447
+
448
+ export class DecryptionFailed extends PdfException {
449
+ constructor(message: string, details: PdfErrorDetails = {}) {
450
+ super(
451
+ '3200',
452
+ message,
453
+ ErrorCategory.ENCRYPTION,
454
+ ErrorSeverity.HIGH,
455
+ details,
456
+ {
457
+ canRetry: false,
458
+ suggestions: [
459
+ 'File may be corrupted',
460
+ 'Encryption method may be unsupported',
461
+ 'Try opening with different PDF reader',
462
+ ],
463
+ }
464
+ );
465
+ }
466
+ }
467
+
468
+ export class UnsupportedAlgorithm extends PdfException {
469
+ constructor(message: string, details: PdfErrorDetails = {}) {
470
+ super(
471
+ '3300',
472
+ message,
473
+ ErrorCategory.ENCRYPTION,
474
+ ErrorSeverity.MEDIUM,
475
+ details,
476
+ {
477
+ canRetry: false,
478
+ suggestions: [
479
+ 'This encryption algorithm is not supported',
480
+ 'Convert PDF with different encryption algorithm',
481
+ 'Contact PDF creator for unencrypted version',
482
+ ],
483
+ alternativeApproach:
484
+ 'Use Adobe Acrobat to re-save with supported encryption',
485
+ }
486
+ );
487
+ }
488
+ }
489
+
490
+ // ===== State Errors (4000-4999) =====
491
+
492
+ export class InvalidStateException extends PdfException {
493
+ constructor(message: string, details: PdfErrorDetails = {}) {
494
+ super(
495
+ '4000',
496
+ message,
497
+ ErrorCategory.STATE,
498
+ ErrorSeverity.HIGH,
499
+ details,
500
+ {
501
+ canRetry: false,
502
+ suggestions: [
503
+ 'Ensure the document is in the correct state for this operation',
504
+ 'Check that required initialization steps were completed',
505
+ 'Verify operation order and dependencies',
506
+ ],
507
+ }
508
+ );
509
+ }
510
+ }
511
+
512
+ export class DocumentClosed extends PdfException {
513
+ constructor(message: string, details: PdfErrorDetails = {}) {
514
+ super(
515
+ '4100',
516
+ message,
517
+ ErrorCategory.STATE,
518
+ ErrorSeverity.HIGH,
519
+ details,
520
+ {
521
+ canRetry: false,
522
+ suggestions: [
523
+ 'The document has been closed and cannot be used',
524
+ 'Create a new document instance or reopen the file',
525
+ 'Check that the document is not being used after closure',
526
+ ],
527
+ }
528
+ );
529
+ }
530
+ }
531
+
532
+ export class OperationNotAllowed extends PdfException {
533
+ constructor(message: string, details: PdfErrorDetails = {}) {
534
+ super(
535
+ '4200',
536
+ message,
537
+ ErrorCategory.STATE,
538
+ ErrorSeverity.MEDIUM,
539
+ details,
540
+ {
541
+ canRetry: false,
542
+ suggestions: [
543
+ 'This operation is not allowed in the current document state',
544
+ 'Check document permissions and security settings',
545
+ 'Ensure document is writable (not read-only)',
546
+ ],
547
+ }
548
+ );
549
+ }
550
+ }
551
+
552
+ export class InvalidOperation extends PdfException {
553
+ constructor(message: string, details: PdfErrorDetails = {}) {
554
+ super(
555
+ '4300',
556
+ message,
557
+ ErrorCategory.STATE,
558
+ ErrorSeverity.MEDIUM,
559
+ details,
560
+ {
561
+ canRetry: false,
562
+ suggestions: [
563
+ 'This operation cannot be performed on this document',
564
+ 'Verify the document format and content type',
565
+ 'Check operation prerequisites are met',
566
+ ],
567
+ }
568
+ );
569
+ }
570
+ }
571
+
572
+ // ===== Unsupported Feature Errors (5000-5999) =====
573
+
574
+ export class UnsupportedFeatureException extends PdfException {
575
+ constructor(message: string, details: PdfErrorDetails = {}) {
576
+ super(
577
+ '5000',
578
+ message,
579
+ ErrorCategory.UNSUPPORTED,
580
+ ErrorSeverity.MEDIUM,
581
+ details,
582
+ {
583
+ canRetry: false,
584
+ suggestions: [
585
+ 'This PDF feature is not supported',
586
+ 'Check the documentation for supported features',
587
+ 'Consider using a different PDF tool for this operation',
588
+ ],
589
+ }
590
+ );
591
+ }
592
+ }
593
+
594
+ export class FeatureNotImplemented extends PdfException {
595
+ constructor(message: string, details: PdfErrorDetails = {}) {
596
+ super(
597
+ '5100',
598
+ message,
599
+ ErrorCategory.UNSUPPORTED,
600
+ ErrorSeverity.LOW,
601
+ details,
602
+ {
603
+ canRetry: false,
604
+ suggestions: [
605
+ 'This feature is not yet implemented',
606
+ 'Check the library changelog for planned features',
607
+ 'File a feature request if this is important for your use case',
608
+ ],
609
+ }
610
+ );
611
+ }
612
+ }
613
+
614
+ export class FormatNotSupported extends PdfException {
615
+ constructor(message: string, details: PdfErrorDetails = {}) {
616
+ super(
617
+ '5200',
618
+ message,
619
+ ErrorCategory.UNSUPPORTED,
620
+ ErrorSeverity.MEDIUM,
621
+ details,
622
+ {
623
+ canRetry: false,
624
+ suggestions: [
625
+ 'The document format is not supported',
626
+ 'Try converting to a standard format first',
627
+ 'Check documentation for supported formats',
628
+ ],
629
+ alternativeApproach: 'Convert the document using a format converter',
630
+ }
631
+ );
632
+ }
633
+ }
634
+
635
+ export class EncodingNotSupported extends PdfException {
636
+ constructor(message: string, details: PdfErrorDetails = {}) {
637
+ super(
638
+ '5300',
639
+ message,
640
+ ErrorCategory.UNSUPPORTED,
641
+ ErrorSeverity.MEDIUM,
642
+ details,
643
+ {
644
+ canRetry: false,
645
+ suggestions: [
646
+ 'The character encoding is not supported',
647
+ 'Try using a different character encoding',
648
+ 'Check that the PDF text is properly encoded',
649
+ ],
650
+ }
651
+ );
652
+ }
653
+ }
654
+
655
+ // ===== Validation Errors (6000-6999) =====
656
+
657
+ export class ValidationException extends PdfException {
658
+ constructor(message: string, details: PdfErrorDetails = {}) {
659
+ super(
660
+ '6000',
661
+ message,
662
+ ErrorCategory.VALIDATION,
663
+ ErrorSeverity.MEDIUM,
664
+ details,
665
+ {
666
+ canRetry: false,
667
+ suggestions: [
668
+ 'Verify all parameters are valid and properly formatted',
669
+ 'Check the API documentation for parameter requirements',
670
+ 'Ensure all required fields are provided',
671
+ ],
672
+ }
673
+ );
674
+ }
675
+ }
676
+
677
+ export class InvalidParameter extends PdfException {
678
+ constructor(message: string, details: PdfErrorDetails = {}) {
679
+ super(
680
+ '6100',
681
+ message,
682
+ ErrorCategory.VALIDATION,
683
+ ErrorSeverity.MEDIUM,
684
+ details,
685
+ {
686
+ canRetry: false,
687
+ suggestions: [
688
+ 'Check that all parameters are valid',
689
+ 'Review the function signature and parameter types',
690
+ 'Ensure parameter values are within valid ranges',
691
+ ],
692
+ }
693
+ );
694
+ }
695
+ }
696
+
697
+ export class InvalidValue extends PdfException {
698
+ constructor(message: string, details: PdfErrorDetails = {}) {
699
+ super(
700
+ '6200',
701
+ message,
702
+ ErrorCategory.VALIDATION,
703
+ ErrorSeverity.MEDIUM,
704
+ details,
705
+ {
706
+ canRetry: false,
707
+ suggestions: [
708
+ 'Verify the value is correct and properly formatted',
709
+ 'Check acceptable value ranges in the documentation',
710
+ 'Ensure the value type matches the expected type',
711
+ ],
712
+ }
713
+ );
714
+ }
715
+ }
716
+
717
+ export class MissingRequired extends PdfException {
718
+ constructor(message: string, details: PdfErrorDetails = {}) {
719
+ super(
720
+ '6300',
721
+ message,
722
+ ErrorCategory.VALIDATION,
723
+ ErrorSeverity.MEDIUM,
724
+ details,
725
+ {
726
+ canRetry: false,
727
+ suggestions: [
728
+ 'Provide the required parameter or field',
729
+ 'Check the API documentation for required fields',
730
+ 'Ensure no required parameters are omitted',
731
+ ],
732
+ }
733
+ );
734
+ }
735
+ }
736
+
737
+ export class TypeMismatch extends PdfException {
738
+ constructor(message: string, details: PdfErrorDetails = {}) {
739
+ super(
740
+ '6400',
741
+ message,
742
+ ErrorCategory.VALIDATION,
743
+ ErrorSeverity.MEDIUM,
744
+ details,
745
+ {
746
+ canRetry: false,
747
+ suggestions: [
748
+ 'Verify the parameter type matches the expected type',
749
+ 'Convert the value to the correct type',
750
+ 'Check the function signature in the documentation',
751
+ ],
752
+ }
753
+ );
754
+ }
755
+ }
756
+
757
+ // ===== Rendering Errors (7000-7999) =====
758
+
759
+ export class RenderingException extends PdfException {
760
+ constructor(message: string, details: PdfErrorDetails = {}) {
761
+ super(
762
+ '7000',
763
+ message,
764
+ ErrorCategory.RENDERING,
765
+ ErrorSeverity.HIGH,
766
+ details,
767
+ {
768
+ canRetry: true,
769
+ retryAfterMs: 1000,
770
+ suggestions: [
771
+ 'Check that the PDF content is valid',
772
+ 'Verify rendering parameters are correct',
773
+ 'Try rendering a different page to isolate the issue',
774
+ ],
775
+ }
776
+ );
777
+ }
778
+ }
779
+
780
+ export class RenderFailed extends PdfException {
781
+ constructor(message: string, details: PdfErrorDetails = {}) {
782
+ super(
783
+ '7100',
784
+ message,
785
+ ErrorCategory.RENDERING,
786
+ ErrorSeverity.HIGH,
787
+ details,
788
+ {
789
+ canRetry: true,
790
+ retryAfterMs: 1000,
791
+ suggestions: [
792
+ 'The rendering operation failed',
793
+ 'Check available system resources',
794
+ 'Try rendering with lower quality settings',
795
+ ],
796
+ }
797
+ );
798
+ }
799
+ }
800
+
801
+ export class UnsupportedRenderFormat extends PdfException {
802
+ constructor(message: string, details: PdfErrorDetails = {}) {
803
+ super(
804
+ '7200',
805
+ message,
806
+ ErrorCategory.RENDERING,
807
+ ErrorSeverity.MEDIUM,
808
+ details,
809
+ {
810
+ canRetry: false,
811
+ suggestions: [
812
+ 'The render format is not supported',
813
+ 'Use a supported format (PNG, JPG, PDF, SVG)',
814
+ 'Check documentation for supported rendering formats',
815
+ ],
816
+ }
817
+ );
818
+ }
819
+ }
820
+
821
+ export class InsufficientMemory extends PdfException {
822
+ constructor(message: string, details: PdfErrorDetails = {}) {
823
+ super(
824
+ '7300',
825
+ message,
826
+ ErrorCategory.RESOURCE,
827
+ ErrorSeverity.CRITICAL,
828
+ details,
829
+ {
830
+ canRetry: true,
831
+ retryAfterMs: 2000,
832
+ suggestions: [
833
+ 'Free up system memory',
834
+ 'Close other applications to reduce memory usage',
835
+ 'Reduce render resolution or quality',
836
+ ],
837
+ alternativeApproach:
838
+ 'Process the document on a system with more available memory',
839
+ }
840
+ );
841
+ }
842
+ }
843
+
844
+ // ===== Search Errors (8000-8999) =====
845
+
846
+ export class SearchException extends PdfException {
847
+ constructor(message: string, details: PdfErrorDetails = {}) {
848
+ super(
849
+ '8000',
850
+ message,
851
+ ErrorCategory.SEARCH,
852
+ ErrorSeverity.MEDIUM,
853
+ details,
854
+ {
855
+ canRetry: true,
856
+ retryAfterMs: 500,
857
+ suggestions: [
858
+ 'Verify the search term is valid',
859
+ 'Check that the document contains searchable text',
860
+ 'Try a simpler search pattern',
861
+ ],
862
+ }
863
+ );
864
+ }
865
+ }
866
+
867
+ export class SearchFailed extends PdfException {
868
+ constructor(message: string, details: PdfErrorDetails = {}) {
869
+ super(
870
+ '8100',
871
+ message,
872
+ ErrorCategory.SEARCH,
873
+ ErrorSeverity.MEDIUM,
874
+ details,
875
+ {
876
+ canRetry: true,
877
+ retryAfterMs: 500,
878
+ suggestions: [
879
+ 'The search operation failed',
880
+ 'Verify the document is not corrupted',
881
+ 'Check that the search parameters are valid',
882
+ ],
883
+ }
884
+ );
885
+ }
886
+ }
887
+
888
+ export class InvalidPattern extends PdfException {
889
+ constructor(message: string, details: PdfErrorDetails = {}) {
890
+ super(
891
+ '8200',
892
+ message,
893
+ ErrorCategory.VALIDATION,
894
+ ErrorSeverity.MEDIUM,
895
+ details,
896
+ {
897
+ canRetry: false,
898
+ suggestions: [
899
+ 'The search pattern is invalid',
900
+ 'Check the regular expression syntax',
901
+ 'Escape special characters if needed',
902
+ ],
903
+ }
904
+ );
905
+ }
906
+ }
907
+
908
+ export class IndexCorrupted extends PdfException {
909
+ constructor(message: string, details: PdfErrorDetails = {}) {
910
+ super(
911
+ '8300',
912
+ message,
913
+ ErrorCategory.SEARCH,
914
+ ErrorSeverity.HIGH,
915
+ details,
916
+ {
917
+ canRetry: true,
918
+ retryAfterMs: 1000,
919
+ suggestions: [
920
+ 'The search index may be corrupted',
921
+ 'Try rebuilding the search index',
922
+ 'Verify the PDF document is valid',
923
+ ],
924
+ }
925
+ );
926
+ }
927
+ }
928
+
929
+ // ===== Signature Errors (8500-8599) =====
930
+
931
+ export class SignatureException extends PdfException {
932
+ constructor(message: string, details: PdfErrorDetails = {}) {
933
+ super(
934
+ '8500',
935
+ message,
936
+ ErrorCategory.SIGNATURE,
937
+ ErrorSeverity.HIGH,
938
+ details,
939
+ {
940
+ canRetry: false,
941
+ suggestions: [
942
+ 'Verify the certificate file path and password are correct',
943
+ 'Ensure the certificate contains a valid private key for signing',
944
+ 'Check that the PDF data is valid and not corrupted',
945
+ 'Confirm the signing algorithm is supported',
946
+ ],
947
+ }
948
+ );
949
+ }
950
+ }
951
+
952
+ export class CertificateLoadFailed extends PdfException {
953
+ constructor(message: string, details: PdfErrorDetails = {}) {
954
+ super(
955
+ '8501',
956
+ message,
957
+ ErrorCategory.SIGNATURE,
958
+ ErrorSeverity.HIGH,
959
+ details,
960
+ {
961
+ canRetry: false,
962
+ suggestions: [
963
+ 'Verify the certificate file exists and is readable',
964
+ 'Check the password for PKCS#12 files',
965
+ 'Ensure the PEM files are properly formatted',
966
+ 'Confirm the certificate and key match',
967
+ ],
968
+ }
969
+ );
970
+ }
971
+ }
972
+
973
+ export class SigningFailed extends PdfException {
974
+ constructor(message: string, details: PdfErrorDetails = {}) {
975
+ super(
976
+ '8502',
977
+ message,
978
+ ErrorCategory.SIGNATURE,
979
+ ErrorSeverity.HIGH,
980
+ details,
981
+ {
982
+ canRetry: true,
983
+ retryAfterMs: 1000,
984
+ suggestions: [
985
+ 'Verify the credentials have a valid private key',
986
+ 'Check that the PDF data is not corrupted',
987
+ 'Ensure the signing algorithm is compatible with the certificate',
988
+ 'Try a different signature subfilter',
989
+ ],
990
+ }
991
+ );
992
+ }
993
+ }
994
+
995
+ // ===== Redaction Errors (8600-8699) =====
996
+
997
+ export class RedactionException extends PdfException {
998
+ constructor(message: string, details: PdfErrorDetails = {}) {
999
+ super(
1000
+ '8600',
1001
+ message,
1002
+ ErrorCategory.REDACTION,
1003
+ ErrorSeverity.HIGH,
1004
+ details,
1005
+ {
1006
+ canRetry: false,
1007
+ suggestions: [
1008
+ 'Verify the redaction area coordinates are valid',
1009
+ 'Ensure the document is opened for editing',
1010
+ 'Check that the page index is within range',
1011
+ 'Confirm the document is not read-only or encrypted',
1012
+ ],
1013
+ }
1014
+ );
1015
+ }
1016
+ }
1017
+
1018
+ // ===== Accessibility Errors (9500-9599) =====
1019
+
1020
+ export class AccessibilityException extends PdfException {
1021
+ constructor(message: string, details: PdfErrorDetails = {}) {
1022
+ super(
1023
+ '9500',
1024
+ message,
1025
+ ErrorCategory.VALIDATION,
1026
+ ErrorSeverity.HIGH,
1027
+ details,
1028
+ {
1029
+ canRetry: false,
1030
+ suggestions: [
1031
+ 'Check the document structure and tagging',
1032
+ 'Verify alt text is set for images and figures',
1033
+ 'Ensure document language and title are specified',
1034
+ 'Run accessibility validation to identify issues',
1035
+ ],
1036
+ }
1037
+ );
1038
+ }
1039
+ }
1040
+
1041
+ // ===== Optimization Errors (9600-9699) =====
1042
+
1043
+ export class OptimizationException extends PdfException {
1044
+ constructor(message: string, details: PdfErrorDetails = {}) {
1045
+ super(
1046
+ '9600',
1047
+ message,
1048
+ ErrorCategory.RESOURCE,
1049
+ ErrorSeverity.MEDIUM,
1050
+ details,
1051
+ {
1052
+ canRetry: true,
1053
+ retryAfterMs: 1000,
1054
+ suggestions: [
1055
+ 'Check that the document is not corrupted',
1056
+ 'Verify sufficient disk space for optimization',
1057
+ 'Try optimizing with different settings (DPI, quality)',
1058
+ 'Ensure document is not encrypted or read-only',
1059
+ ],
1060
+ }
1061
+ );
1062
+ }
1063
+ }
1064
+
1065
+ // ===== Compliance Errors (9000-9100) =====
1066
+
1067
+ export class ComplianceException extends PdfException {
1068
+ constructor(message: string, details: PdfErrorDetails = {}) {
1069
+ super(
1070
+ '9000',
1071
+ message,
1072
+ ErrorCategory.COMPLIANCE,
1073
+ ErrorSeverity.HIGH,
1074
+ details,
1075
+ {
1076
+ canRetry: false,
1077
+ suggestions: [
1078
+ 'Check PDF compliance level requirements',
1079
+ 'Verify document meets compliance standards',
1080
+ 'Review compliance validation report',
1081
+ ],
1082
+ }
1083
+ );
1084
+ }
1085
+ }
1086
+
1087
+ export class InvalidCompliance extends PdfException {
1088
+ constructor(message: string, details: PdfErrorDetails = {}) {
1089
+ super(
1090
+ '9100',
1091
+ message,
1092
+ ErrorCategory.COMPLIANCE,
1093
+ ErrorSeverity.HIGH,
1094
+ details,
1095
+ {
1096
+ canRetry: false,
1097
+ suggestions: [
1098
+ 'The document does not meet compliance requirements',
1099
+ 'Fix the compliance issues identified',
1100
+ 'Convert the document to a compliant format',
1101
+ ],
1102
+ }
1103
+ );
1104
+ }
1105
+ }
1106
+
1107
+ export class ValidationFailed extends PdfException {
1108
+ constructor(message: string, details: PdfErrorDetails = {}) {
1109
+ super(
1110
+ '9150',
1111
+ message,
1112
+ ErrorCategory.COMPLIANCE,
1113
+ ErrorSeverity.MEDIUM,
1114
+ details,
1115
+ {
1116
+ canRetry: true,
1117
+ retryAfterMs: 1000,
1118
+ suggestions: [
1119
+ 'Validation failed for this document',
1120
+ 'Check the validation error details',
1121
+ 'Fix the identified issues and retry',
1122
+ ],
1123
+ }
1124
+ );
1125
+ }
1126
+ }
1127
+
1128
+ // ===== OCR Errors (9200-9300) =====
1129
+
1130
+ export class OcrException extends PdfException {
1131
+ constructor(message: string, details: PdfErrorDetails = {}) {
1132
+ super(
1133
+ '9200',
1134
+ message,
1135
+ ErrorCategory.OCR,
1136
+ ErrorSeverity.MEDIUM,
1137
+ details,
1138
+ {
1139
+ canRetry: true,
1140
+ retryAfterMs: 2000,
1141
+ suggestions: [
1142
+ 'OCR processing failed',
1143
+ 'Verify the image quality is sufficient',
1144
+ 'Check that the document language is supported',
1145
+ ],
1146
+ }
1147
+ );
1148
+ }
1149
+ }
1150
+
1151
+ export class RecognitionFailed extends PdfException {
1152
+ constructor(message: string, details: PdfErrorDetails = {}) {
1153
+ super(
1154
+ '9201',
1155
+ message,
1156
+ ErrorCategory.OCR,
1157
+ ErrorSeverity.MEDIUM,
1158
+ details,
1159
+ {
1160
+ canRetry: true,
1161
+ retryAfterMs: 2000,
1162
+ suggestions: [
1163
+ 'Text recognition failed',
1164
+ 'Try improving the image quality',
1165
+ 'Ensure the document language is set correctly',
1166
+ ],
1167
+ }
1168
+ );
1169
+ }
1170
+ }
1171
+
1172
+ export class LanguageNotSupported extends PdfException {
1173
+ constructor(message: string, details: PdfErrorDetails = {}) {
1174
+ super(
1175
+ '9202',
1176
+ message,
1177
+ ErrorCategory.OCR,
1178
+ ErrorSeverity.MEDIUM,
1179
+ details,
1180
+ {
1181
+ canRetry: false,
1182
+ suggestions: [
1183
+ 'The document language is not supported for OCR',
1184
+ 'Check available language packs',
1185
+ 'Install language support if available',
1186
+ ],
1187
+ }
1188
+ );
1189
+ }
1190
+ }
1191
+
1192
+ export class ImageProcessingFailed extends PdfException {
1193
+ constructor(message: string, details: PdfErrorDetails = {}) {
1194
+ super(
1195
+ '9203',
1196
+ message,
1197
+ ErrorCategory.OCR,
1198
+ ErrorSeverity.MEDIUM,
1199
+ details,
1200
+ {
1201
+ canRetry: true,
1202
+ retryAfterMs: 2000,
1203
+ suggestions: [
1204
+ 'Image processing failed',
1205
+ 'Verify image format and encoding',
1206
+ 'Try with a higher quality image',
1207
+ ],
1208
+ }
1209
+ );
1210
+ }
1211
+ }
1212
+
1213
+ // ===== Other Errors (9900-9999) =====
1214
+
1215
+ export class UnknownError extends PdfException {
1216
+ constructor(message: string, details: PdfErrorDetails = {}) {
1217
+ super(
1218
+ '9900',
1219
+ message,
1220
+ ErrorCategory.UNKNOWN,
1221
+ ErrorSeverity.HIGH,
1222
+ details,
1223
+ {
1224
+ canRetry: true,
1225
+ retryAfterMs: 1000,
1226
+ suggestions: [
1227
+ 'An unknown error occurred',
1228
+ 'Check the error message for details',
1229
+ 'Try the operation again',
1230
+ 'File a bug report if the problem persists',
1231
+ ],
1232
+ }
1233
+ );
1234
+ }
1235
+ }
1236
+
1237
+ export class InternalError extends PdfException {
1238
+ constructor(message: string, details: PdfErrorDetails = {}) {
1239
+ super(
1240
+ '9901',
1241
+ message,
1242
+ ErrorCategory.UNKNOWN,
1243
+ ErrorSeverity.CRITICAL,
1244
+ details,
1245
+ {
1246
+ canRetry: true,
1247
+ retryAfterMs: 2000,
1248
+ suggestions: [
1249
+ 'An internal error occurred',
1250
+ 'Please restart the application',
1251
+ 'Check system resources',
1252
+ 'File a bug report with error details',
1253
+ ],
1254
+ }
1255
+ );
1256
+ }
1257
+ }
1258
+
1259
+ // ===== Error Mapping from Rust FFI =====
1260
+
1261
+ /**
1262
+ * Maps Rust error type names to JavaScript exception types.
1263
+ */
1264
+ export const ERROR_MAP: Record<string, new (message: string, details?: PdfErrorDetails) => PdfException> = {
1265
+ // Parse errors
1266
+ InvalidStructure,
1267
+ CorruptedData,
1268
+ UnsupportedVersion,
1269
+
1270
+ // I/O errors
1271
+ FileNotFound,
1272
+ PermissionDenied,
1273
+ DiskFull,
1274
+ NetworkError,
1275
+
1276
+ // Encryption errors
1277
+ InvalidPassword,
1278
+ DecryptionFailed,
1279
+ UnsupportedAlgorithm,
1280
+
1281
+ // State errors
1282
+ DocumentClosed,
1283
+ OperationNotAllowed,
1284
+ InvalidOperation,
1285
+
1286
+ // Unsupported features
1287
+ FeatureNotImplemented,
1288
+ FormatNotSupported,
1289
+ EncodingNotSupported,
1290
+
1291
+ // Validation errors
1292
+ InvalidParameter,
1293
+ InvalidValue,
1294
+ MissingRequired,
1295
+ TypeMismatch,
1296
+
1297
+ // Rendering errors
1298
+ RenderFailed,
1299
+ UnsupportedRenderFormat,
1300
+ InsufficientMemory,
1301
+
1302
+ // Search errors
1303
+ SearchFailed,
1304
+ InvalidPattern,
1305
+ IndexCorrupted,
1306
+
1307
+ // Signature errors
1308
+ SignatureException,
1309
+ CertificateLoadFailed,
1310
+ SigningFailed,
1311
+
1312
+ // Redaction errors
1313
+ RedactionException,
1314
+
1315
+ // Accessibility errors
1316
+ AccessibilityException,
1317
+
1318
+ // Optimization errors
1319
+ OptimizationException,
1320
+
1321
+ // Other errors
1322
+ ComplianceException,
1323
+ OcrException,
1324
+ UnknownError,
1325
+ };
1326
+
1327
+ /**
1328
+ * Maps a Rust error type to a JavaScript exception.
1329
+ *
1330
+ * @param rustErrorType - Rust error type name
1331
+ * @param message - Error message
1332
+ * @param details - Additional context
1333
+ * @returns Appropriate error instance
1334
+ *
1335
+ * @example
1336
+ * try {
1337
+ * // Native call
1338
+ * } catch (err) {
1339
+ * const jsErr = mapError('FileNotFound', 'File does not exist', { path: '/tmp/doc.pdf' });
1340
+ * throw jsErr;
1341
+ * }
1342
+ */
1343
+ export function mapError(
1344
+ rustErrorType: string,
1345
+ message: string,
1346
+ details: PdfErrorDetails = {}
1347
+ ): PdfException {
1348
+ const ErrorClass = ERROR_MAP[rustErrorType] || UnknownError;
1349
+ return new ErrorClass(message, details);
1350
+ }
1351
+
1352
+ /**
1353
+ * Maps a numeric FFI error code from the Rust layer to a JavaScript exception.
1354
+ *
1355
+ * FFI Error Codes:
1356
+ * - 0: Success (no error)
1357
+ * - 1: I/O error
1358
+ * - 2: Parse error
1359
+ * - 3: Encryption error
1360
+ * - 4: Invalid state error
1361
+ * - 5: Rendering unsupported
1362
+ * - 6: OCR unsupported
1363
+ * - 7: Invalid argument
1364
+ * - 8: Signature error
1365
+ * - 100: Internal/generic error
1366
+ *
1367
+ * @param errorCode - Numeric FFI error code from native layer
1368
+ * @param message - Optional error message override
1369
+ * @returns Appropriate error instance
1370
+ *
1371
+ * @example
1372
+ * const errorCode = nativeCall();
1373
+ * if (errorCode !== 0) {
1374
+ * throw mapFfiErrorCode(errorCode, 'Operation failed');
1375
+ * }
1376
+ */
1377
+ export function mapFfiErrorCode(
1378
+ errorCode: number,
1379
+ message?: string
1380
+ ): PdfException {
1381
+ switch (errorCode) {
1382
+ case 0:
1383
+ return new UnknownError(message ?? 'Success (no error)');
1384
+ case 1:
1385
+ return new IoException(message ?? 'I/O error: File not found, permission denied, or read/write failed');
1386
+ case 2:
1387
+ return new ParseException(message ?? 'Parse error: Invalid PDF structure or content stream');
1388
+ case 3:
1389
+ return new EncryptionException(message ?? 'Encryption error: Incorrect password or unsupported encryption');
1390
+ case 4:
1391
+ return new InvalidStateException(message ?? 'Invalid state: Operation not allowed in current document state');
1392
+ case 5:
1393
+ return new UnsupportedFeatureException(message ?? 'Feature not enabled: Rendering support not compiled in');
1394
+ case 6:
1395
+ return new UnsupportedFeatureException(message ?? 'Feature not enabled: OCR support not compiled in');
1396
+ case 7:
1397
+ return new InvalidParameter(message ?? 'Invalid argument: Null pointer or invalid parameter passed');
1398
+ case 8:
1399
+ return new SignatureException(message ?? 'Signature error: Certificate loading, signing, or verification failed');
1400
+ case 9:
1401
+ return new RedactionException(message ?? 'Redaction error: Content redaction or metadata scrubbing failed');
1402
+ case 10:
1403
+ return new ComplianceException(message ?? 'Compliance error: PDF/A, PDF/X, or PDF/UA conversion or validation failed');
1404
+ case 11:
1405
+ return new AccessibilityException(message ?? 'Accessibility error: Tagging, structure tree, or alt text operation failed');
1406
+ case 12:
1407
+ return new OptimizationException(message ?? 'Optimization error: Font subsetting, image downsampling, or deduplication failed');
1408
+ default:
1409
+ return new UnknownError(message ?? `Unknown error (code: ${errorCode})`);
1410
+ }
1411
+ }
1412
+
1413
+ /**
1414
+ * Creates an error with optional context.
1415
+ *
1416
+ * @param code - 4-digit error code
1417
+ * @param message - Error message
1418
+ * @param options - Configuration options
1419
+ * @returns Created exception
1420
+ *
1421
+ * @example
1422
+ * const err = createError('7100', 'Rendering failed', {
1423
+ * operation: 'renderPage',
1424
+ * context: { page: 0, format: 'png' }
1425
+ * });
1426
+ */
1427
+ export function createError(
1428
+ code: string,
1429
+ message: string,
1430
+ options: {
1431
+ operation?: string;
1432
+ context?: Record<string, any>;
1433
+ } = {}
1434
+ ): PdfException {
1435
+ // Map code to appropriate error class
1436
+ const codeMap: Record<string, new (message: string, details?: PdfErrorDetails) => PdfException> = {
1437
+ '1101': InvalidStructure,
1438
+ '1200': CorruptedData,
1439
+ '1300': UnsupportedVersion,
1440
+ '2100': FileNotFound,
1441
+ '2200': PermissionDenied,
1442
+ '2300': DiskFull,
1443
+ '2400': NetworkError,
1444
+ '3100': InvalidPassword,
1445
+ '3200': DecryptionFailed,
1446
+ '3300': UnsupportedAlgorithm,
1447
+ '4100': DocumentClosed,
1448
+ '4200': OperationNotAllowed,
1449
+ '4300': InvalidOperation,
1450
+ '5100': FeatureNotImplemented,
1451
+ '5200': FormatNotSupported,
1452
+ '5300': EncodingNotSupported,
1453
+ '6100': InvalidParameter,
1454
+ '6200': InvalidValue,
1455
+ '6300': MissingRequired,
1456
+ '6400': TypeMismatch,
1457
+ '7100': RenderFailed,
1458
+ '7200': UnsupportedRenderFormat,
1459
+ '7300': InsufficientMemory,
1460
+ '8100': SearchFailed,
1461
+ '8200': InvalidPattern,
1462
+ '8300': IndexCorrupted,
1463
+ '8500': SignatureException,
1464
+ '8501': CertificateLoadFailed,
1465
+ '8502': SigningFailed,
1466
+ '8600': RedactionException,
1467
+ '9500': AccessibilityException,
1468
+ '9600': OptimizationException,
1469
+ '9100': InvalidCompliance,
1470
+ '9150': ValidationFailed,
1471
+ '9200': OcrException,
1472
+ '9201': RecognitionFailed,
1473
+ '9202': LanguageNotSupported,
1474
+ '9203': ImageProcessingFailed,
1475
+ };
1476
+
1477
+ const ErrorClass = codeMap[code];
1478
+ const context = options.context || {};
1479
+
1480
+ let err: PdfException;
1481
+ if (ErrorClass) {
1482
+ err = new ErrorClass(message, context);
1483
+ } else {
1484
+ err = new PdfException(
1485
+ code,
1486
+ message,
1487
+ ErrorCategory.UNKNOWN,
1488
+ ErrorSeverity.HIGH,
1489
+ context
1490
+ );
1491
+ }
1492
+
1493
+ if (options.operation) {
1494
+ err.withContext(options.operation, context);
1495
+ }
1496
+
1497
+ return err;
1498
+ }
1499
+
1500
+ /**
1501
+ * Maps native error to appropriate PDF exception.
1502
+ *
1503
+ * @param error - The error to wrap
1504
+ * @returns Wrapped exception
1505
+ *
1506
+ * @example
1507
+ * try {
1508
+ * // Native call
1509
+ * } catch (err) {
1510
+ * const wrapped = wrapError(err);
1511
+ * console.log(wrapped.code); // e.g., "2100"
1512
+ * }
1513
+ */
1514
+ export function wrapError(error: unknown): PdfException {
1515
+ // If already a PdfException, return as-is
1516
+ if (error instanceof PdfException) {
1517
+ return error;
1518
+ }
1519
+
1520
+ let code = '9900';
1521
+ let message = 'Unknown error occurred';
1522
+ let details: PdfErrorDetails = {};
1523
+
1524
+ // Handle Error objects
1525
+ if (error instanceof Error) {
1526
+ message = error.message;
1527
+
1528
+ // Try to extract code from message format: [XXXX] message
1529
+ const codeMatch = message.match(/^\[(\d{4})\]/);
1530
+ if (codeMatch && codeMatch[1]) {
1531
+ code = codeMatch[1];
1532
+ message = message.replace(/^\[\d{4}\]\s*/, '');
1533
+ }
1534
+
1535
+ // Copy additional properties
1536
+ const props = Object.getOwnPropertyNames(error);
1537
+ for (const prop of props) {
1538
+ if (prop !== 'message' && prop !== 'name' && prop !== 'stack') {
1539
+ details[prop as keyof PdfErrorDetails] = (error as any)[prop];
1540
+ }
1541
+ }
1542
+ }
1543
+ // Handle plain objects
1544
+ else if (error && typeof error === 'object') {
1545
+ const obj = error as Record<string, any>;
1546
+ if (obj.code) {
1547
+ code = String(obj.code);
1548
+ // Convert string codes to 4-digit if needed
1549
+ if (!/^\d{4}$/.test(code)) {
1550
+ code = '9900';
1551
+ }
1552
+ }
1553
+ if (obj.message && typeof obj.message === 'string') {
1554
+ message = obj.message;
1555
+ }
1556
+ details = obj as PdfErrorDetails;
1557
+ }
1558
+ // Handle strings
1559
+ else if (typeof error === 'string') {
1560
+ message = error;
1561
+ }
1562
+
1563
+ try {
1564
+ return new PdfException(
1565
+ code,
1566
+ message,
1567
+ ErrorCategory.UNKNOWN,
1568
+ ErrorSeverity.HIGH,
1569
+ details
1570
+ );
1571
+ } catch {
1572
+ // If code validation fails, use generic error
1573
+ return new UnknownError(message, details);
1574
+ }
1575
+ }
1576
+
1577
+ /**
1578
+ * Function signature for methods to be wrapped
1579
+ */
1580
+ type MethodFunction = (...args: any[]) => any;
1581
+ type AsyncMethodFunction = (...args: any[]) => Promise<any>;
1582
+
1583
+ /**
1584
+ * Creates a method wrapper that catches native errors and converts them.
1585
+ *
1586
+ * @param fn - The method to wrap
1587
+ * @param thisArg - The context (this) to bind
1588
+ * @returns Wrapped function with error conversion
1589
+ *
1590
+ * @example
1591
+ * const wrapped = wrapMethod(nativeMethod, this);
1592
+ * const result = wrapped(arg1, arg2); // Throws PdfException on error
1593
+ */
1594
+ export function wrapMethod<T extends MethodFunction>(
1595
+ fn: T,
1596
+ thisArg: any = null
1597
+ ): T {
1598
+ return function (this: any, ...args: any[]) {
1599
+ try {
1600
+ return fn.apply(thisArg || this, args);
1601
+ } catch (nativeErr) {
1602
+ throw wrapError(nativeErr);
1603
+ }
1604
+ } as T;
1605
+ }
1606
+
1607
+ /**
1608
+ * Creates an async method wrapper that catches native errors.
1609
+ *
1610
+ * @param fn - The async method to wrap
1611
+ * @param thisArg - The context (this) to bind
1612
+ * @returns Wrapped async function with error conversion
1613
+ *
1614
+ * @example
1615
+ * const wrapped = wrapAsyncMethod(nativeAsyncMethod, this);
1616
+ * const result = await wrapped(arg1, arg2); // Throws PdfException on error
1617
+ */
1618
+ export function wrapAsyncMethod<T extends AsyncMethodFunction>(
1619
+ fn: T,
1620
+ thisArg: any = null
1621
+ ): T {
1622
+ return async function (this: any, ...args: any[]) {
1623
+ try {
1624
+ return await fn.apply(thisArg || this, args);
1625
+ } catch (nativeErr) {
1626
+ throw wrapError(nativeErr);
1627
+ }
1628
+ } as T;
1629
+ }