pdf-oxide 0.3.37 → 0.3.39

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 (65) hide show
  1. package/lib/builders/document-builder.d.ts +350 -0
  2. package/lib/builders/document-builder.js +724 -0
  3. package/lib/builders/index.d.ts +4 -2
  4. package/lib/builders/index.js +4 -2
  5. package/lib/builders/pdf-builder.d.ts +2 -0
  6. package/lib/builders/pdf-builder.js +12 -0
  7. package/lib/builders/streaming-table.d.ts +49 -0
  8. package/lib/builders/streaming-table.js +110 -0
  9. package/lib/document-editor.d.ts +122 -0
  10. package/lib/document-editor.js +313 -0
  11. package/lib/errors.js +3 -4
  12. package/lib/form-field-manager.js +3 -1
  13. package/lib/index.d.ts +41 -7
  14. package/lib/index.js +266 -90
  15. package/lib/managers/accessibility-manager.js +19 -8
  16. package/lib/managers/annotation-manager.js +9 -9
  17. package/lib/managers/barcode-manager.js +18 -7
  18. package/lib/managers/batch-manager.js +2 -5
  19. package/lib/managers/cache-manager.js +1 -3
  20. package/lib/managers/compliance-manager.js +58 -19
  21. package/lib/managers/document-utility-manager.js +6 -6
  22. package/lib/managers/dom-pdf-creator.js +9 -9
  23. package/lib/managers/enterprise-manager.js +4 -1
  24. package/lib/managers/extended-managers.js +8 -1
  25. package/lib/managers/extraction-manager.js +7 -2
  26. package/lib/managers/final-utilities.d.ts +3 -3
  27. package/lib/managers/final-utilities.js +9 -4
  28. package/lib/managers/hybrid-ml-advanced.js +22 -6
  29. package/lib/managers/index.d.ts +22 -22
  30. package/lib/managers/index.js +23 -23
  31. package/lib/managers/layer-manager.js +20 -21
  32. package/lib/managers/ocr-manager.d.ts +2 -2
  33. package/lib/managers/ocr-manager.js +7 -7
  34. package/lib/managers/optimization-manager.js +24 -4
  35. package/lib/managers/page-manager.js +5 -6
  36. package/lib/managers/pattern-detection.d.ts +1 -1
  37. package/lib/managers/pattern-detection.js +4 -6
  38. package/lib/managers/search-manager.js +3 -3
  39. package/lib/managers/signature-manager.d.ts +14 -0
  40. package/lib/managers/signature-manager.js +185 -40
  41. package/lib/managers/streams.js +8 -2
  42. package/lib/managers/xfa-manager.js +69 -19
  43. package/lib/native-loader.d.ts +7 -0
  44. package/lib/native-loader.js +62 -0
  45. package/lib/native.d.ts +16 -0
  46. package/lib/native.js +69 -0
  47. package/lib/pdf-creator-manager.js +4 -1
  48. package/lib/result-accessors-manager.js +3 -1
  49. package/lib/timestamp.d.ts +54 -0
  50. package/lib/timestamp.js +115 -0
  51. package/lib/tsa-client.d.ts +44 -0
  52. package/lib/tsa-client.js +67 -0
  53. package/lib/types/common.d.ts +80 -1
  54. package/lib/types/common.js +14 -1
  55. package/lib/types/index.d.ts +1 -1
  56. package/lib/types/index.js +1 -1
  57. package/lib/types/manager-types.js +4 -2
  58. package/lib/workers/index.d.ts +1 -1
  59. package/lib/workers/pool.js +2 -4
  60. package/package.json +17 -11
  61. package/prebuilds/darwin-arm64/pdf_oxide.node +0 -0
  62. package/prebuilds/darwin-x64/pdf_oxide.node +0 -0
  63. package/prebuilds/linux-arm64/pdf_oxide.node +0 -0
  64. package/prebuilds/linux-x64/pdf_oxide.node +0 -0
  65. package/prebuilds/win32-x64/pdf_oxide.node +0 -0
@@ -179,7 +179,9 @@ export class SignatureManager extends EventEmitter {
179
179
  try {
180
180
  result = JSON.parse(this.native.verify_signatures());
181
181
  }
182
- catch { /* defaults */ }
182
+ catch {
183
+ /* defaults */
184
+ }
183
185
  }
184
186
  this.setCached(cacheKey, result);
185
187
  this.emit('signaturesVerified', { isValid: result.isValid, issueCount: result.issues.length });
@@ -194,7 +196,9 @@ export class SignatureManager extends EventEmitter {
194
196
  try {
195
197
  result = JSON.parse(this.native.verify_signature(signatureName));
196
198
  }
197
- catch { /* defaults */ }
199
+ catch {
200
+ /* defaults */
201
+ }
198
202
  }
199
203
  this.setCached(cacheKey, result);
200
204
  return result;
@@ -236,12 +240,20 @@ export class SignatureManager extends EventEmitter {
236
240
  const certId = `cert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
237
241
  const nativeResult = await this.document?.loadCertificate?.(certData, password, format);
238
242
  const info = nativeResult?.info ?? {
239
- subject: nativeResult?.subject ?? 'Unknown', issuer: nativeResult?.issuer ?? 'Unknown',
240
- serialNumber: nativeResult?.serialNumber ?? '', validFrom: new Date(nativeResult?.validFrom ?? Date.now()),
243
+ subject: nativeResult?.subject ?? 'Unknown',
244
+ issuer: nativeResult?.issuer ?? 'Unknown',
245
+ serialNumber: nativeResult?.serialNumber ?? '',
246
+ validFrom: new Date(nativeResult?.validFrom ?? Date.now()),
241
247
  validTo: new Date(nativeResult?.validTo ?? Date.now() + 365 * 24 * 60 * 60 * 1000),
242
- isValid: nativeResult?.isValid ?? false, isSelfSigned: nativeResult?.isSelfSigned ?? false,
248
+ isValid: nativeResult?.isValid ?? false,
249
+ isSelfSigned: nativeResult?.isSelfSigned ?? false,
250
+ };
251
+ const loadedCert = {
252
+ certificateId: certId,
253
+ info,
254
+ hasPrivateKey: nativeResult?.hasPrivateKey ?? true,
255
+ chain: nativeResult?.chain,
243
256
  };
244
- const loadedCert = { certificateId: certId, info, hasPrivateKey: nativeResult?.hasPrivateKey ?? true, chain: nativeResult?.chain };
245
257
  this.loadedCertificates.set(certId, loadedCert);
246
258
  this.emit('certificate-loaded', { certificateId: certId, subject: info.subject });
247
259
  return loadedCert;
@@ -258,12 +270,19 @@ export class SignatureManager extends EventEmitter {
258
270
  if (!nativeResult)
259
271
  throw new Error('Failed to load PEM certificate');
260
272
  const info = {
261
- subject: nativeResult.subject ?? 'Unknown', issuer: nativeResult.issuer ?? 'Unknown',
262
- serialNumber: nativeResult.serialNumber ?? '', validFrom: new Date(nativeResult.validFrom ?? Date.now()),
273
+ subject: nativeResult.subject ?? 'Unknown',
274
+ issuer: nativeResult.issuer ?? 'Unknown',
275
+ serialNumber: nativeResult.serialNumber ?? '',
276
+ validFrom: new Date(nativeResult.validFrom ?? Date.now()),
263
277
  validTo: new Date(nativeResult.validTo ?? Date.now() + 365 * 24 * 60 * 60 * 1000),
264
- isValid: nativeResult.isValid ?? false, isSelfSigned: nativeResult.isSelfSigned ?? false,
278
+ isValid: nativeResult.isValid ?? false,
279
+ isSelfSigned: nativeResult.isSelfSigned ?? false,
280
+ };
281
+ const loadedCert = {
282
+ certificateId: certId,
283
+ info,
284
+ hasPrivateKey: !!privateKeyPem,
265
285
  };
266
- const loadedCert = { certificateId: certId, info, hasPrivateKey: !!privateKeyPem };
267
286
  this.loadedCertificates.set(certId, loadedCert);
268
287
  this.emit('certificate-loaded', { certificateId: certId, subject: info.subject });
269
288
  return loadedCert;
@@ -283,7 +302,7 @@ export class SignatureManager extends EventEmitter {
283
302
  return null;
284
303
  if (cert.chain)
285
304
  return cert.chain;
286
- return await this.document?.getCertificateChain?.(certificateId) ?? null;
305
+ return (await this.document?.getCertificateChain?.(certificateId)) ?? null;
287
306
  }
288
307
  catch (error) {
289
308
  this.emit('error', error);
@@ -296,11 +315,19 @@ export class SignatureManager extends EventEmitter {
296
315
  if (!cert)
297
316
  return { valid: false, errors: ['Certificate not found'], warnings: [] };
298
317
  const result = await this.document?.validateCertificate?.(certificateId);
299
- return result ?? { valid: cert.info.isValid, errors: cert.info.isValid ? [] : ['Certificate validation failed'], warnings: [] };
318
+ return (result ?? {
319
+ valid: cert.info.isValid,
320
+ errors: cert.info.isValid ? [] : ['Certificate validation failed'],
321
+ warnings: [],
322
+ });
300
323
  }
301
324
  catch (error) {
302
325
  this.emit('error', error);
303
- return { valid: false, errors: [error instanceof Error ? error.message : 'Unknown error'], warnings: [] };
326
+ return {
327
+ valid: false,
328
+ errors: [error instanceof Error ? error.message : 'Unknown error'],
329
+ warnings: [],
330
+ };
304
331
  }
305
332
  }
306
333
  getLoadedCertificates() {
@@ -317,7 +344,12 @@ export class SignatureManager extends EventEmitter {
317
344
  // ===========================================================================
318
345
  async addSignatureField(config) {
319
346
  try {
320
- const result = await this.document?.addSignatureField?.(config.fieldName, config.pageIndex, config.x, config.y, config.width, config.height, { appearance: config.appearance, tooltip: config.tooltip, isRequired: config.isRequired, isReadOnly: config.isReadOnly });
347
+ const result = await this.document?.addSignatureField?.(config.fieldName, config.pageIndex, config.x, config.y, config.width, config.height, {
348
+ appearance: config.appearance,
349
+ tooltip: config.tooltip,
350
+ isRequired: config.isRequired,
351
+ isReadOnly: config.isReadOnly,
352
+ });
321
353
  if (result !== false) {
322
354
  this.createdFields.set(config.fieldName, config);
323
355
  this.clearCachePattern('signatures:');
@@ -347,7 +379,7 @@ export class SignatureManager extends EventEmitter {
347
379
  }
348
380
  async getSignatureFieldNames() {
349
381
  try {
350
- return await this.document?.getSignatureFields?.() ?? [];
382
+ return (await this.document?.getSignatureFields?.()) ?? [];
351
383
  }
352
384
  catch (error) {
353
385
  this.emit('error', error);
@@ -387,7 +419,9 @@ export class SignatureManager extends EventEmitter {
387
419
  if (!cert.hasPrivateKey)
388
420
  return { success: false, error: 'Certificate does not have private key' };
389
421
  const nativeResult = await this.document?.signDocument?.(fieldName, certId, {
390
- reason: options?.reason, location: options?.location, contactInfo: options?.contactInfo,
422
+ reason: options?.reason,
423
+ location: options?.location,
424
+ contactInfo: options?.contactInfo,
391
425
  signatureType: options?.signatureType ?? SignatureType.APPROVAL,
392
426
  certificationPermission: options?.certificationPermission,
393
427
  algorithm: options?.algorithm ?? SignatureAlgorithm.RSA_SHA256,
@@ -397,16 +431,28 @@ export class SignatureManager extends EventEmitter {
397
431
  const signingTime = new Date();
398
432
  let timestampTime;
399
433
  if (options?.embedTimestamp && options?.timestampServerUrl) {
400
- const tsResult = await this.embedTimestamp(fieldName, { serverUrl: options.timestampServerUrl, hashAlgorithm: options.digestAlgorithm });
434
+ const tsResult = await this.embedTimestamp(fieldName, {
435
+ serverUrl: options.timestampServerUrl,
436
+ hashAlgorithm: options.digestAlgorithm,
437
+ });
401
438
  if (tsResult.status === TimestampStatus.SUCCESS)
402
439
  timestampTime = tsResult.timestamp;
403
440
  }
404
441
  if (options?.enableLtv)
405
- await this.enableLtvForSignature(fieldName, { ocspResponderUrl: options.ocspResponderUrl, crlDistributionPoints: options.crlDistributionPoints });
442
+ await this.enableLtvForSignature(fieldName, {
443
+ ocspResponderUrl: options.ocspResponderUrl,
444
+ crlDistributionPoints: options.crlDistributionPoints,
445
+ });
406
446
  const signatureId = `sig_${fieldName}_${Date.now()}`;
407
447
  this.clearCachePattern('signatures:');
408
448
  this.emit('document-signed', { signatureId, fieldName, signingTime, timestampTime });
409
- return { success: true, signatureId, signingTime, timestampTime, warnings: nativeResult?.warnings };
449
+ return {
450
+ success: true,
451
+ signatureId,
452
+ signingTime,
453
+ timestampTime,
454
+ warnings: nativeResult?.warnings,
455
+ };
410
456
  }
411
457
  catch (error) {
412
458
  this.emit('error', error);
@@ -414,7 +460,11 @@ export class SignatureManager extends EventEmitter {
414
460
  }
415
461
  }
416
462
  async certifyDocument(fieldName, certificate, permission, options) {
417
- return this.signDocument(fieldName, certificate, { ...options, signatureType: SignatureType.CERTIFICATION, certificationPermission: permission });
463
+ return this.signDocument(fieldName, certificate, {
464
+ ...options,
465
+ signatureType: SignatureType.CERTIFICATION,
466
+ certificationPermission: permission,
467
+ });
418
468
  }
419
469
  async signInvisibly(certificate, options) {
420
470
  try {
@@ -430,7 +480,15 @@ export class SignatureManager extends EventEmitter {
430
480
  async counterSign(certificate, options) {
431
481
  try {
432
482
  const fieldName = `CounterSig_${Date.now()}`;
433
- await this.addSignatureField({ fieldName, pageIndex: 0, x: 100, y: 100, width: 200, height: 50, appearance: options?.appearance });
483
+ await this.addSignatureField({
484
+ fieldName,
485
+ pageIndex: 0,
486
+ x: 100,
487
+ y: 100,
488
+ width: 200,
489
+ height: 50,
490
+ appearance: options?.appearance,
491
+ });
434
492
  return this.signDocument(fieldName, certificate, options);
435
493
  }
436
494
  catch (error) {
@@ -450,7 +508,10 @@ export class SignatureManager extends EventEmitter {
450
508
  }
451
509
  async prepareForExternalSigning(fieldName, options) {
452
510
  try {
453
- const result = await this.document?.prepareForExternalSigning?.(fieldName, { estimatedSize: options?.estimatedSize ?? 8192, digestAlgorithm: options?.digestAlgorithm ?? DigestAlgorithm.SHA256 });
511
+ const result = await this.document?.prepareForExternalSigning?.(fieldName, {
512
+ estimatedSize: options?.estimatedSize ?? 8192,
513
+ digestAlgorithm: options?.digestAlgorithm ?? DigestAlgorithm.SHA256,
514
+ });
454
515
  this.emit('prepared-for-external-signing', { fieldName });
455
516
  return result ?? null;
456
517
  }
@@ -464,16 +525,36 @@ export class SignatureManager extends EventEmitter {
464
525
  // ===========================================================================
465
526
  async embedTimestamp(fieldName, config) {
466
527
  try {
467
- const result = await this.document?.embedTimestamp?.(fieldName, { serverUrl: config.serverUrl, username: config.username, password: config.password, hashAlgorithm: config.hashAlgorithm ?? DigestAlgorithm.SHA256, timeout: config.timeout ?? 30000, policy: config.policy, nonce: config.nonce ?? true, certReq: config.certReq ?? true });
528
+ const result = await this.document?.embedTimestamp?.(fieldName, {
529
+ serverUrl: config.serverUrl,
530
+ username: config.username,
531
+ password: config.password,
532
+ hashAlgorithm: config.hashAlgorithm ?? DigestAlgorithm.SHA256,
533
+ timeout: config.timeout ?? 30000,
534
+ policy: config.policy,
535
+ nonce: config.nonce ?? true,
536
+ certReq: config.certReq ?? true,
537
+ });
468
538
  if (result?.success) {
469
539
  this.emit('timestamp-embedded', { fieldName, timestamp: result.timestamp });
470
- return { status: TimestampStatus.SUCCESS, timestamp: new Date(result.timestamp), serialNumber: result.serialNumber, tsaName: result.tsaName };
540
+ return {
541
+ status: TimestampStatus.SUCCESS,
542
+ timestamp: new Date(result.timestamp),
543
+ serialNumber: result.serialNumber,
544
+ tsaName: result.tsaName,
545
+ };
471
546
  }
472
- return { status: TimestampStatus.FAILED, error: result?.error ?? 'Timestamp embedding failed' };
547
+ return {
548
+ status: TimestampStatus.FAILED,
549
+ error: result?.error ?? 'Timestamp embedding failed',
550
+ };
473
551
  }
474
552
  catch (error) {
475
553
  this.emit('error', error);
476
- return { status: TimestampStatus.FAILED, error: error instanceof Error ? error.message : 'Unknown error' };
554
+ return {
555
+ status: TimestampStatus.FAILED,
556
+ error: error instanceof Error ? error.message : 'Unknown error',
557
+ };
477
558
  }
478
559
  }
479
560
  async addDocumentTimestamp(config) {
@@ -483,18 +564,32 @@ export class SignatureManager extends EventEmitter {
483
564
  const result = await this.document?.addDocumentTimestamp?.(fieldName, config);
484
565
  if (result?.success) {
485
566
  this.emit('document-timestamp-added', { timestamp: result.timestamp });
486
- return { status: TimestampStatus.SUCCESS, timestamp: new Date(result.timestamp), serialNumber: result.serialNumber, tsaName: result.tsaName };
567
+ return {
568
+ status: TimestampStatus.SUCCESS,
569
+ timestamp: new Date(result.timestamp),
570
+ serialNumber: result.serialNumber,
571
+ tsaName: result.tsaName,
572
+ };
487
573
  }
488
- return { status: TimestampStatus.FAILED, error: result?.error ?? 'Document timestamp failed' };
574
+ return {
575
+ status: TimestampStatus.FAILED,
576
+ error: result?.error ?? 'Document timestamp failed',
577
+ };
489
578
  }
490
579
  catch (error) {
491
580
  this.emit('error', error);
492
- return { status: TimestampStatus.FAILED, error: error instanceof Error ? error.message : 'Unknown error' };
581
+ return {
582
+ status: TimestampStatus.FAILED,
583
+ error: error instanceof Error ? error.message : 'Unknown error',
584
+ };
493
585
  }
494
586
  }
495
587
  async validateTimestamp(fieldName) {
496
588
  try {
497
- return await this.document?.validateTimestamp?.(fieldName) ?? { valid: false, errors: ['Timestamp validation not available'] };
589
+ return ((await this.document?.validateTimestamp?.(fieldName)) ?? {
590
+ valid: false,
591
+ errors: ['Timestamp validation not available'],
592
+ });
498
593
  }
499
594
  catch (error) {
500
595
  this.emit('error', error);
@@ -503,7 +598,7 @@ export class SignatureManager extends EventEmitter {
503
598
  }
504
599
  async getTimestampInfo(fieldName) {
505
600
  try {
506
- return await this.document?.getTimestampInfo?.(fieldName) ?? null;
601
+ return (await this.document?.getTimestampInfo?.(fieldName)) ?? null;
507
602
  }
508
603
  catch (error) {
509
604
  this.emit('error', error);
@@ -515,7 +610,10 @@ export class SignatureManager extends EventEmitter {
515
610
  // ===========================================================================
516
611
  async enableLtvForSignature(fieldName, options) {
517
612
  try {
518
- const result = await this.document?.enableLtvForSignature?.(fieldName, { ocspResponderUrl: options?.ocspResponderUrl, crlDistributionPoints: options?.crlDistributionPoints });
613
+ const result = await this.document?.enableLtvForSignature?.(fieldName, {
614
+ ocspResponderUrl: options?.ocspResponderUrl,
615
+ crlDistributionPoints: options?.crlDistributionPoints,
616
+ });
519
617
  if (result)
520
618
  this.emit('ltv-enabled', { fieldName });
521
619
  return !!result;
@@ -554,7 +652,7 @@ export class SignatureManager extends EventEmitter {
554
652
  }
555
653
  async hasLtvEnabled(fieldName) {
556
654
  try {
557
- return await this.document?.hasLtvEnabled?.(fieldName) ?? false;
655
+ return (await this.document?.hasLtvEnabled?.(fieldName)) ?? false;
558
656
  }
559
657
  catch (error) {
560
658
  this.emit('error', error);
@@ -632,15 +730,20 @@ export class SignatureManager extends EventEmitter {
632
730
  try {
633
731
  const [notBefore, notAfter] = await this.getCertificateValidity(index);
634
732
  const certificate = {
635
- subject: await this.getCertificateSubject(index), issuer: await this.getCertificateIssuer(index),
636
- serial: await this.getCertificateSerial(index), notBefore, notAfter,
733
+ subject: await this.getCertificateSubject(index),
734
+ issuer: await this.getCertificateIssuer(index),
735
+ serial: await this.getCertificateSerial(index),
736
+ notBefore,
737
+ notAfter,
637
738
  isValid: await this.isCertificateValidByIndex(index),
638
739
  };
639
740
  return {
640
- signerName: await this.getSignerName(index), signingTime: await this.getSigningTime(index),
741
+ signerName: await this.getSignerName(index),
742
+ signingTime: await this.getSigningTime(index),
641
743
  reason: (await this.getSigningReason(index)) || undefined,
642
744
  location: (await this.getSigningLocation(index)) || undefined,
643
- certificate, isValid: true,
745
+ certificate,
746
+ isValid: true,
644
747
  };
645
748
  }
646
749
  catch (error) {
@@ -1339,7 +1442,11 @@ export class SignatureManager extends EventEmitter {
1339
1442
  this.emit('cacheCleared');
1340
1443
  }
1341
1444
  getCacheStats() {
1342
- return { cacheSize: this.resultCache.size, maxCacheSize: this.maxCacheSize, entries: Array.from(this.resultCache.keys()) };
1445
+ return {
1446
+ cacheSize: this.resultCache.size,
1447
+ maxCacheSize: this.maxCacheSize,
1448
+ entries: Array.from(this.resultCache.keys()),
1449
+ };
1343
1450
  }
1344
1451
  destroy() {
1345
1452
  this.loadedCertificates.clear();
@@ -1347,6 +1454,42 @@ export class SignatureManager extends EventEmitter {
1347
1454
  this.resultCache.clear();
1348
1455
  this.removeAllListeners();
1349
1456
  }
1457
+ /**
1458
+ * Sign a PDF from raw bytes using PEM credentials.
1459
+ *
1460
+ * Calls the native `signPdfBytes` FFI function (two-pass ByteRange writer).
1461
+ * Credentials are loaded and freed within this call.
1462
+ *
1463
+ * @param pdfData - Buffer containing the PDF document bytes
1464
+ * @param certPem - PEM-encoded certificate string
1465
+ * @param keyPem - PEM-encoded private key string
1466
+ * @param reason - Optional signature reason
1467
+ * @param location - Optional signature location
1468
+ * @returns Buffer containing the signed PDF
1469
+ */
1470
+ async signPdfData(pdfData, certPem, keyPem, reason, location) {
1471
+ if (!this.native?.certificateLoadFromPem) {
1472
+ throw new SignatureException('Native signing not available: certificateLoadFromPem not found');
1473
+ }
1474
+ if (!this.native?.signPdfBytes) {
1475
+ throw new SignatureException('Native signing not available: signPdfBytes not found');
1476
+ }
1477
+ const certHandle = this.native.certificateLoadFromPem(certPem, keyPem);
1478
+ if (!certHandle) {
1479
+ throw new SignatureException('Failed to load PEM certificate');
1480
+ }
1481
+ try {
1482
+ const result = this.native.signPdfBytes(pdfData, certHandle, reason ?? null, location ?? null);
1483
+ if (!result)
1484
+ throw new SignatureException('signPdfBytes returned null');
1485
+ return Buffer.from(result);
1486
+ }
1487
+ finally {
1488
+ if (this.native?.pdf_certificate_free) {
1489
+ this.native.pdf_certificate_free(certHandle);
1490
+ }
1491
+ }
1492
+ }
1350
1493
  // Private helpers
1351
1494
  setCached(key, value) {
1352
1495
  this.resultCache.set(key, value);
@@ -1357,8 +1500,10 @@ export class SignatureManager extends EventEmitter {
1357
1500
  }
1358
1501
  }
1359
1502
  clearCachePattern(prefix) {
1360
- const keysToDelete = Array.from(this.resultCache.keys()).filter(key => key.startsWith(prefix));
1361
- keysToDelete.forEach(key => this.resultCache.delete(key));
1503
+ const keysToDelete = Array.from(this.resultCache.keys()).filter((key) => key.startsWith(prefix));
1504
+ keysToDelete.forEach((key) => {
1505
+ this.resultCache.delete(key);
1506
+ });
1362
1507
  }
1363
1508
  }
1364
1509
  export default SignatureManager;
@@ -70,10 +70,16 @@ export class SearchStream extends Readable {
70
70
  try {
71
71
  // Perform search
72
72
  if (this.pageIndex !== undefined) {
73
- this._results = (this.searchManager.search(this.searchTerm, this.pageIndex, { caseSensitive: this.caseSensitive, wholeWords: this.wholeWords }) || []);
73
+ this._results = (this.searchManager.search(this.searchTerm, this.pageIndex, {
74
+ caseSensitive: this.caseSensitive,
75
+ wholeWords: this.wholeWords,
76
+ }) || []);
74
77
  }
75
78
  else {
76
- this._results = (this.searchManager.searchAll(this.searchTerm, { caseSensitive: this.caseSensitive, wholeWords: this.wholeWords }) || []);
79
+ this._results = (this.searchManager.searchAll(this.searchTerm, {
80
+ caseSensitive: this.caseSensitive,
81
+ wholeWords: this.wholeWords,
82
+ }) || []);
77
83
  }
78
84
  // Apply max results limit
79
85
  if (this._results && this._results.length > this.maxResults) {
@@ -142,7 +142,7 @@ export class XfaManager extends EventEmitter {
142
142
  }
143
143
  async getFieldValue(fieldName) {
144
144
  try {
145
- return await this.document?.getXfaFieldValue?.(fieldName) ?? null;
145
+ return (await this.document?.getXfaFieldValue?.(fieldName)) ?? null;
146
146
  }
147
147
  catch (error) {
148
148
  this.emit('error', error);
@@ -300,21 +300,56 @@ export class XfaManager extends EventEmitter {
300
300
  // ===========================================================================
301
301
  // Field Creation (from XfaCreationManager)
302
302
  // ===========================================================================
303
- async addTextField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.TEXT }); }
304
- async addNumericField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.NUMERIC }); }
305
- async addDateField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.DATE }); }
306
- async addCheckboxField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.CHECKBOX }); }
307
- async addRadioGroup(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.RADIO }); }
308
- async addDropdownField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.DROPDOWN }); }
309
- async addSignatureField(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.SIGNATURE }); }
310
- async addButton(pageIndex, config) { return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.BUTTON }); }
303
+ async addTextField(pageIndex, config) {
304
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.TEXT });
305
+ }
306
+ async addNumericField(pageIndex, config) {
307
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.NUMERIC });
308
+ }
309
+ async addDateField(pageIndex, config) {
310
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.DATE });
311
+ }
312
+ async addCheckboxField(pageIndex, config) {
313
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.CHECKBOX });
314
+ }
315
+ async addRadioGroup(pageIndex, config) {
316
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.RADIO });
317
+ }
318
+ async addDropdownField(pageIndex, config) {
319
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.DROPDOWN });
320
+ }
321
+ async addSignatureField(pageIndex, config) {
322
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.SIGNATURE });
323
+ }
324
+ async addButton(pageIndex, config) {
325
+ return this.addField(pageIndex, { ...config, fieldType: XfaFieldType.BUTTON });
326
+ }
311
327
  async addField(pageIndex, config) {
312
328
  try {
313
329
  if (!this.formCreated)
314
330
  throw new Error('No XFA form created');
315
331
  const fieldId = `xfa_field_${config.name}_${Date.now()}`;
316
- await this.document?.addXfaField?.(pageIndex, config.name, config.fieldType, config.x, config.y, config.width, config.height, { caption: config.caption, defaultValue: config.defaultValue, tooltip: config.tooltip, isRequired: config.isRequired, isReadOnly: config.isReadOnly, isHidden: config.isHidden, maxLength: config.maxLength, options: config.options, font: config.font, border: config.border, margin: config.margin, bindingType: config.bindingType, bindingPath: config.bindingPath });
317
- const handle = { fieldId, name: config.name, fieldType: config.fieldType, pageIndex };
332
+ await this.document?.addXfaField?.(pageIndex, config.name, config.fieldType, config.x, config.y, config.width, config.height, {
333
+ caption: config.caption,
334
+ defaultValue: config.defaultValue,
335
+ tooltip: config.tooltip,
336
+ isRequired: config.isRequired,
337
+ isReadOnly: config.isReadOnly,
338
+ isHidden: config.isHidden,
339
+ maxLength: config.maxLength,
340
+ options: config.options,
341
+ font: config.font,
342
+ border: config.border,
343
+ margin: config.margin,
344
+ bindingType: config.bindingType,
345
+ bindingPath: config.bindingPath,
346
+ });
347
+ const handle = {
348
+ fieldId,
349
+ name: config.name,
350
+ fieldType: config.fieldType,
351
+ pageIndex,
352
+ };
318
353
  this.createdFields.set(fieldId, handle);
319
354
  this.emit('field-added', handle);
320
355
  return handle;
@@ -374,7 +409,9 @@ export class XfaManager extends EventEmitter {
374
409
  // ===========================================================================
375
410
  async importXfaData(data, options) {
376
411
  try {
377
- const result = await this.document?.importXfaData?.(data, options.format, { validate: options.validateOnImport });
412
+ const result = await this.document?.importXfaData?.(data, options.format, {
413
+ validate: options.validateOnImport,
414
+ });
378
415
  this.emit('data-imported', { format: options.format });
379
416
  return !!result;
380
417
  }
@@ -385,7 +422,10 @@ export class XfaManager extends EventEmitter {
385
422
  }
386
423
  async exportXfaData(options) {
387
424
  try {
388
- const result = await this.document?.exportXfaData?.(options.format, { includeEmpty: options.includeEmptyFields, includeCalculated: options.includeCalculatedFields });
425
+ const result = await this.document?.exportXfaData?.(options.format, {
426
+ includeEmpty: options.includeEmptyFields,
427
+ includeCalculated: options.includeCalculatedFields,
428
+ });
389
429
  this.emit('data-exported', { format: options.format });
390
430
  return result ?? null;
391
431
  }
@@ -396,7 +436,7 @@ export class XfaManager extends EventEmitter {
396
436
  }
397
437
  async exportAsXdp() {
398
438
  try {
399
- return await this.document?.exportXfaAsXdp?.() ?? null;
439
+ return (await this.document?.exportXfaAsXdp?.()) ?? null;
400
440
  }
401
441
  catch (error) {
402
442
  this.emit('error', error);
@@ -455,18 +495,28 @@ export class XfaManager extends EventEmitter {
455
495
  // ===========================================================================
456
496
  async validateForm() {
457
497
  try {
458
- return await this.document?.validateXfaForm?.() ?? { valid: true, issues: [] };
498
+ return (await this.document?.validateXfaForm?.()) ?? { valid: true, issues: [] };
459
499
  }
460
500
  catch (error) {
461
501
  this.emit('error', error);
462
502
  return { valid: false, issues: [error instanceof Error ? error.message : 'Unknown error'] };
463
503
  }
464
504
  }
465
- getCreatedFields() { return Array.from(this.createdFields.values()); }
466
- hasForm() { return this.formCreated || this.hasXfa(); }
467
- clearCache() { this.cache.clear(); }
505
+ getCreatedFields() {
506
+ return Array.from(this.createdFields.values());
507
+ }
508
+ hasForm() {
509
+ return this.formCreated || this.hasXfa();
510
+ }
511
+ clearCache() {
512
+ this.cache.clear();
513
+ }
468
514
  getCacheStats() {
469
- return { cacheSize: this.cache.size, maxCacheSize: this.maxCacheSize, entries: Array.from(this.cache.keys()) };
515
+ return {
516
+ cacheSize: this.cache.size,
517
+ maxCacheSize: this.maxCacheSize,
518
+ entries: Array.from(this.cache.keys()),
519
+ };
470
520
  }
471
521
  destroy() {
472
522
  this.createdFields.clear();
@@ -0,0 +1,7 @@
1
+ type NativeModule = Record<string, any>;
2
+ /**
3
+ * Returns the loaded native module, loading it on first call. Throws if the
4
+ * prebuilt .node is missing and the development fallback also fails.
5
+ */
6
+ export declare function getNative(): NativeModule;
7
+ export {};
@@ -0,0 +1,62 @@
1
+ // Shared loader for the pdf-oxide native N-API module.
2
+ //
3
+ // The top-level index.ts owns the primary load, but standalone classes like
4
+ // Timestamp and TsaClient need access too. Rather than plumb the module
5
+ // object through every constructor, both files import `getNative()` here.
6
+ //
7
+ // The loader resolves the prebuilt .node via the same prebuilds/<triple>
8
+ // layout index.ts uses, with fallbacks for development builds.
9
+ import { createRequire } from 'node:module';
10
+ import { dirname, join } from 'node:path';
11
+ import { arch, platform } from 'node:process';
12
+ import { fileURLToPath } from 'node:url';
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const require = createRequire(import.meta.url);
16
+ let cached = null;
17
+ function prebuildPath() {
18
+ const paths = {
19
+ darwin: {
20
+ x64: '../prebuilds/darwin-x64/pdf_oxide.node',
21
+ arm64: '../prebuilds/darwin-arm64/pdf_oxide.node',
22
+ },
23
+ linux: {
24
+ x64: '../prebuilds/linux-x64/pdf_oxide.node',
25
+ arm64: '../prebuilds/linux-arm64/pdf_oxide.node',
26
+ },
27
+ win32: {
28
+ x64: '../prebuilds/win32-x64/pdf_oxide.node',
29
+ },
30
+ };
31
+ const plat = paths[platform];
32
+ const rel = plat?.[arch];
33
+ if (!rel) {
34
+ throw new Error(`Unsupported platform: ${platform}/${arch}`);
35
+ }
36
+ return join(__dirname, rel);
37
+ }
38
+ /**
39
+ * Returns the loaded native module, loading it on first call. Throws if the
40
+ * prebuilt .node is missing and the development fallback also fails.
41
+ */
42
+ export function getNative() {
43
+ if (cached)
44
+ return cached;
45
+ try {
46
+ cached = require(prebuildPath());
47
+ }
48
+ catch (e) {
49
+ if (process.env.NODE_ENV === 'development' || process.env.NAPI_DEV) {
50
+ try {
51
+ cached = require('../build/Release/pdf_oxide.node');
52
+ }
53
+ catch {
54
+ throw e;
55
+ }
56
+ }
57
+ else {
58
+ throw e;
59
+ }
60
+ }
61
+ return cached;
62
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared loader for the pdf-oxide N-API addon.
3
+ *
4
+ * Extracted so that modules which can't import from `./index.ts`
5
+ * (due to the index ↔ editor / builder cycle) can still reach the
6
+ * addon through the same prebuild-aware resolver. The published
7
+ * package ships a platform-specific `.node` file under
8
+ * `prebuilds/<triple>/`; loading the addon through this helper is
9
+ * what makes `DocumentEditor` / `DocumentBuilder` work for consumers
10
+ * installed from npm (where `build/Release/` does not exist).
11
+ *
12
+ * In development mode (`NODE_ENV=development` or `NAPI_DEV` set), we
13
+ * fall back to `../build/Release/pdf_oxide.node` — the node-gyp
14
+ * output that in-tree tests run against.
15
+ */
16
+ export declare function loadNative(): any;