@fin.cx/skr 1.1.0 → 1.2.0

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 (46) hide show
  1. package/dist_ts/index.d.ts +6 -0
  2. package/dist_ts/index.js +7 -1
  3. package/dist_ts/plugins.d.ts +8 -1
  4. package/dist_ts/plugins.js +10 -2
  5. package/dist_ts/skr.api.d.ts +70 -0
  6. package/dist_ts/skr.api.js +348 -1
  7. package/dist_ts/skr.export.accounts.d.ts +53 -0
  8. package/dist_ts/skr.export.accounts.js +111 -0
  9. package/dist_ts/skr.export.balances.d.ts +59 -0
  10. package/dist_ts/skr.export.balances.js +205 -0
  11. package/dist_ts/skr.export.d.ts +110 -0
  12. package/dist_ts/skr.export.js +315 -0
  13. package/dist_ts/skr.export.ledger.d.ts +95 -0
  14. package/dist_ts/skr.export.ledger.js +164 -0
  15. package/dist_ts/skr.export.pdf.d.ts +82 -0
  16. package/dist_ts/skr.export.pdf.js +548 -0
  17. package/dist_ts/skr.invoice.adapter.d.ts +98 -0
  18. package/dist_ts/skr.invoice.adapter.js +476 -0
  19. package/dist_ts/skr.invoice.booking.d.ts +102 -0
  20. package/dist_ts/skr.invoice.booking.js +556 -0
  21. package/dist_ts/skr.invoice.entity.d.ts +287 -0
  22. package/dist_ts/skr.invoice.entity.js +2 -0
  23. package/dist_ts/skr.invoice.mapper.d.ts +69 -0
  24. package/dist_ts/skr.invoice.mapper.js +401 -0
  25. package/dist_ts/skr.invoice.storage.d.ts +140 -0
  26. package/dist_ts/skr.invoice.storage.js +529 -0
  27. package/dist_ts/skr.security.d.ts +65 -0
  28. package/dist_ts/skr.security.js +319 -0
  29. package/dist_ts/skr.types.d.ts +1 -0
  30. package/package.json +17 -12
  31. package/readme.md +207 -16
  32. package/ts/index.ts +6 -0
  33. package/ts/plugins.ts +22 -1
  34. package/ts/skr.api.ts +485 -0
  35. package/ts/skr.export.accounts.ts +154 -0
  36. package/ts/skr.export.balances.ts +270 -0
  37. package/ts/skr.export.ledger.ts +249 -0
  38. package/ts/skr.export.pdf.ts +601 -0
  39. package/ts/skr.export.ts +443 -0
  40. package/ts/skr.invoice.adapter.ts +581 -0
  41. package/ts/skr.invoice.booking.ts +738 -0
  42. package/ts/skr.invoice.entity.ts +351 -0
  43. package/ts/skr.invoice.mapper.ts +486 -0
  44. package/ts/skr.invoice.storage.ts +710 -0
  45. package/ts/skr.security.ts +405 -0
  46. package/ts/skr.types.ts +1 -0
@@ -0,0 +1,529 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as path from 'path';
3
+ /**
4
+ * Content-addressed storage for invoices
5
+ * Integrates with BagIt archive structure for GoBD compliance
6
+ */
7
+ export class InvoiceStorage {
8
+ constructor(exportPath) {
9
+ this.MAX_CACHE_SIZE = 10000; // Maximum number of cached entries
10
+ this.cacheAccessOrder = []; // Track access order for LRU eviction
11
+ this.MAX_PDF_SIZE = 50 * 1024 * 1024; // 50MB max
12
+ this.exportPath = exportPath;
13
+ this.logger = new plugins.smartlog.ConsoleLog();
14
+ this.registryPath = path.join(exportPath, 'data', 'documents', 'invoices', 'registry.ndjson');
15
+ this.metadataCache = new Map();
16
+ }
17
+ /**
18
+ * Manage cache size using LRU eviction
19
+ */
20
+ manageCacheSize() {
21
+ if (this.metadataCache.size > this.MAX_CACHE_SIZE) {
22
+ // Remove least recently used entries
23
+ const entriesToRemove = Math.min(100, Math.floor(this.MAX_CACHE_SIZE * 0.1)); // Remove 10% or 100 entries
24
+ const keysToRemove = this.cacheAccessOrder.splice(0, entriesToRemove);
25
+ for (const key of keysToRemove) {
26
+ this.metadataCache.delete(key);
27
+ }
28
+ this.logger.log('info', `Evicted ${entriesToRemove} entries from metadata cache`);
29
+ }
30
+ }
31
+ /**
32
+ * Update cache access order for LRU
33
+ */
34
+ touchCacheEntry(key) {
35
+ const index = this.cacheAccessOrder.indexOf(key);
36
+ if (index > -1) {
37
+ this.cacheAccessOrder.splice(index, 1);
38
+ }
39
+ this.cacheAccessOrder.push(key);
40
+ }
41
+ /**
42
+ * Initialize storage directories
43
+ */
44
+ async initialize() {
45
+ const dirs = [
46
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'inbound'),
47
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'inbound', 'metadata'),
48
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'outbound'),
49
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'outbound', 'metadata'),
50
+ path.join(this.exportPath, 'data', 'validation')
51
+ ];
52
+ for (const dir of dirs) {
53
+ await plugins.smartfile.fs.ensureDir(dir);
54
+ }
55
+ // Load existing registry if it exists
56
+ await this.loadRegistry();
57
+ }
58
+ /**
59
+ * Store an invoice with content addressing
60
+ */
61
+ async storeInvoice(invoice, pdfBuffer) {
62
+ try {
63
+ // Validate PDF size if provided
64
+ if (pdfBuffer && pdfBuffer.length > this.MAX_PDF_SIZE) {
65
+ throw new Error(`PDF file too large: ${pdfBuffer.length} bytes (max ${this.MAX_PDF_SIZE} bytes)`);
66
+ }
67
+ // Calculate hashes
68
+ const xmlHash = await this.calculateHash(invoice.xmlContent || '');
69
+ const pdfHash = pdfBuffer ? await this.calculateHash(pdfBuffer) : undefined;
70
+ const contentHash = xmlHash; // Primary content hash is XML
71
+ // Check for duplicates
72
+ const duplicateCheck = await this.checkDuplicate(invoice, contentHash);
73
+ if (duplicateCheck.isDuplicate) {
74
+ this.logger.log('warn', `Duplicate invoice detected: ${invoice.invoiceNumber}`);
75
+ return duplicateCheck.matchedContentHash || contentHash;
76
+ }
77
+ // Determine storage path
78
+ const direction = invoice.direction;
79
+ const basePath = path.join(this.exportPath, 'data', 'documents', 'invoices', direction);
80
+ // Create filename with content hash
81
+ const dateStr = invoice.issueDate.toISOString().split('T')[0];
82
+ const sanitizedNumber = invoice.invoiceNumber.replace(/[^a-zA-Z0-9-_]/g, '_');
83
+ const xmlFilename = `${contentHash.substring(0, 8)}_${dateStr}_${sanitizedNumber}.xml`;
84
+ const xmlPath = path.join(basePath, xmlFilename);
85
+ // Store XML
86
+ await plugins.smartfile.memory.toFs(invoice.xmlContent || '', xmlPath);
87
+ // Store PDF if available
88
+ let pdfFilename;
89
+ if (pdfBuffer) {
90
+ pdfFilename = xmlFilename.replace('.xml', '.pdf');
91
+ const pdfPath = path.join(basePath, pdfFilename);
92
+ await plugins.smartfile.memory.toFs(pdfBuffer, pdfPath);
93
+ // Also store PDF/A-3 with embedded XML if supported
94
+ if (invoice.format === 'zugferd' || invoice.format === 'facturx') {
95
+ const pdfA3Filename = xmlFilename.replace('.xml', '_pdfa3.pdf');
96
+ const pdfA3Path = path.join(basePath, pdfA3Filename);
97
+ // The PDF should already have embedded XML if it's ZUGFeRD/Factur-X
98
+ await plugins.smartfile.memory.toFs(pdfBuffer, pdfA3Path);
99
+ }
100
+ }
101
+ // Create and store metadata
102
+ const metadata = {
103
+ invoiceId: invoice.id,
104
+ invoiceNumber: invoice.invoiceNumber,
105
+ direction: invoice.direction,
106
+ issueDate: invoice.issueDate.toISOString(),
107
+ supplierName: invoice.supplier.name,
108
+ customerName: invoice.customer.name,
109
+ totalAmount: invoice.payableAmount,
110
+ currency: invoice.currencyCode,
111
+ contentHash,
112
+ pdfHash,
113
+ xmlHash,
114
+ journalEntryId: invoice.bookingInfo?.journalEntryId,
115
+ transactionIds: invoice.bookingInfo?.transactionIds,
116
+ validationResult: {
117
+ isValid: invoice.validationResult?.isValid || false,
118
+ errors: this.countErrors(invoice.validationResult),
119
+ warnings: this.countWarnings(invoice.validationResult)
120
+ },
121
+ parserVersion: invoice.metadata?.parserVersion || '5.1.4',
122
+ storedAt: new Date().toISOString(),
123
+ storedBy: invoice.createdBy
124
+ };
125
+ const metadataPath = path.join(basePath, 'metadata', `${contentHash}.json`);
126
+ await plugins.smartfile.memory.toFs(JSON.stringify(metadata, null, 2), metadataPath);
127
+ // Update registry
128
+ await this.updateRegistry(invoice.id, contentHash, metadata);
129
+ // Cache metadata with LRU management
130
+ this.setCacheEntry(contentHash, metadata);
131
+ this.logger.log('info', `Invoice stored: ${invoice.invoiceNumber} (${contentHash})`);
132
+ return contentHash;
133
+ }
134
+ catch (error) {
135
+ this.logger.log('error', `Failed to store invoice: ${error}`);
136
+ throw new Error(`Invoice storage failed: ${error.message}`);
137
+ }
138
+ }
139
+ /**
140
+ * Retrieve an invoice by content hash
141
+ */
142
+ async retrieveInvoice(contentHash) {
143
+ try {
144
+ // Check cache first
145
+ const metadata = this.getCacheEntry(contentHash);
146
+ if (!metadata) {
147
+ this.logger.log('warn', `Invoice not found: ${contentHash}`);
148
+ return null;
149
+ }
150
+ // Load XML content
151
+ const xmlPath = await this.findInvoiceFile(contentHash, '.xml');
152
+ if (!xmlPath) {
153
+ throw new Error(`XML file not found for invoice ${contentHash}`);
154
+ }
155
+ const xmlContent = await plugins.smartfile.fs.toStringSync(xmlPath);
156
+ // Load PDF if exists
157
+ let pdfContent;
158
+ const pdfPath = await this.findInvoiceFile(contentHash, '.pdf');
159
+ if (pdfPath) {
160
+ pdfContent = await plugins.smartfile.fs.toBuffer(pdfPath);
161
+ }
162
+ // Reconstruct invoice object (partial)
163
+ const invoice = {
164
+ id: metadata.invoiceId,
165
+ invoiceNumber: metadata.invoiceNumber,
166
+ direction: metadata.direction,
167
+ issueDate: new Date(metadata.issueDate),
168
+ supplier: {
169
+ name: metadata.supplierName,
170
+ id: '',
171
+ address: { countryCode: 'DE' }
172
+ },
173
+ customer: {
174
+ name: metadata.customerName,
175
+ id: '',
176
+ address: { countryCode: 'DE' }
177
+ },
178
+ payableAmount: metadata.totalAmount,
179
+ currencyCode: metadata.currency,
180
+ contentHash: metadata.contentHash,
181
+ xmlContent,
182
+ pdfContent,
183
+ pdfHash: metadata.pdfHash
184
+ };
185
+ return invoice;
186
+ }
187
+ catch (error) {
188
+ this.logger.log('error', `Failed to retrieve invoice: ${error}`);
189
+ return null;
190
+ }
191
+ }
192
+ /**
193
+ * Check for duplicate invoices
194
+ */
195
+ async checkDuplicate(invoice, contentHash) {
196
+ // Check by content hash (exact match)
197
+ const existing = this.getCacheEntry(contentHash);
198
+ if (existing) {
199
+ return {
200
+ isDuplicate: true,
201
+ matchedInvoiceId: existing.invoiceId,
202
+ matchedContentHash: contentHash,
203
+ matchedFields: ['contentHash'],
204
+ confidence: 100
205
+ };
206
+ }
207
+ // Check by invoice number and supplier/customer
208
+ for (const [hash, metadata] of this.metadataCache.entries()) {
209
+ if (metadata.invoiceNumber === invoice.invoiceNumber &&
210
+ metadata.direction === invoice.direction) {
211
+ // Same invoice number and direction
212
+ if (invoice.direction === 'inbound' && metadata.supplierName === invoice.supplier.name) {
213
+ // Same supplier
214
+ return {
215
+ isDuplicate: true,
216
+ matchedInvoiceId: metadata.invoiceId,
217
+ matchedContentHash: hash,
218
+ matchedFields: ['invoiceNumber', 'supplier'],
219
+ confidence: 95
220
+ };
221
+ }
222
+ else if (invoice.direction === 'outbound' && metadata.customerName === invoice.customer.name) {
223
+ // Same customer
224
+ return {
225
+ isDuplicate: true,
226
+ matchedInvoiceId: metadata.invoiceId,
227
+ matchedContentHash: hash,
228
+ matchedFields: ['invoiceNumber', 'customer'],
229
+ confidence: 95
230
+ };
231
+ }
232
+ }
233
+ // Check by amount and date within tolerance
234
+ const dateTolerance = 7 * 24 * 60 * 60 * 1000; // 7 days
235
+ const amountTolerance = 0.01;
236
+ if (Math.abs(metadata.totalAmount - invoice.payableAmount) < amountTolerance &&
237
+ Math.abs(new Date(metadata.issueDate).getTime() - invoice.issueDate.getTime()) < dateTolerance &&
238
+ metadata.direction === invoice.direction) {
239
+ if ((invoice.direction === 'inbound' && metadata.supplierName === invoice.supplier.name) ||
240
+ (invoice.direction === 'outbound' && metadata.customerName === invoice.customer.name)) {
241
+ return {
242
+ isDuplicate: true,
243
+ matchedInvoiceId: metadata.invoiceId,
244
+ matchedContentHash: hash,
245
+ matchedFields: ['amount', 'date', 'party'],
246
+ confidence: 85
247
+ };
248
+ }
249
+ }
250
+ }
251
+ return {
252
+ isDuplicate: false,
253
+ confidence: 0
254
+ };
255
+ }
256
+ /**
257
+ * Search invoices by filter
258
+ */
259
+ async searchInvoices(filter) {
260
+ const results = [];
261
+ for (const metadata of this.metadataCache.values()) {
262
+ if (this.matchesFilter(metadata, filter)) {
263
+ results.push(metadata);
264
+ }
265
+ }
266
+ // Sort by date descending
267
+ results.sort((a, b) => new Date(b.issueDate).getTime() - new Date(a.issueDate).getTime());
268
+ return results;
269
+ }
270
+ /**
271
+ * Get storage statistics
272
+ */
273
+ async getStatistics() {
274
+ let totalSize = 0;
275
+ let inboundCount = 0;
276
+ let outboundCount = 0;
277
+ for (const metadata of this.metadataCache.values()) {
278
+ if (metadata.direction === 'inbound') {
279
+ inboundCount++;
280
+ }
281
+ else {
282
+ outboundCount++;
283
+ }
284
+ // Estimate size (would need actual file sizes in production)
285
+ totalSize += 50000; // Rough estimate
286
+ }
287
+ return {
288
+ totalInvoices: this.metadataCache.size,
289
+ inboundCount,
290
+ outboundCount,
291
+ totalSize,
292
+ duplicatesDetected: 0, // Would track this in production
293
+ lastUpdate: new Date()
294
+ };
295
+ }
296
+ /**
297
+ * Create EN16931 compliance report
298
+ */
299
+ async createComplianceReport() {
300
+ const report = {
301
+ timestamp: new Date().toISOString(),
302
+ totalInvoices: this.metadataCache.size,
303
+ validInvoices: 0,
304
+ invalidInvoices: 0,
305
+ warnings: 0,
306
+ byFormat: {},
307
+ byDirection: {
308
+ inbound: 0,
309
+ outbound: 0
310
+ },
311
+ validationErrors: [],
312
+ complianceLevel: 'EN16931',
313
+ validatorVersion: '5.1.4'
314
+ };
315
+ for (const metadata of this.metadataCache.values()) {
316
+ if (metadata.validationResult.isValid) {
317
+ report.validInvoices++;
318
+ }
319
+ else {
320
+ report.invalidInvoices++;
321
+ }
322
+ report.warnings += metadata.validationResult.warnings;
323
+ if (metadata.direction === 'inbound') {
324
+ report.byDirection.inbound++;
325
+ }
326
+ else {
327
+ report.byDirection.outbound++;
328
+ }
329
+ }
330
+ const reportPath = path.join(this.exportPath, 'data', 'validation', 'en16931_compliance.json');
331
+ await plugins.smartfile.memory.toFs(JSON.stringify(report, null, 2), reportPath);
332
+ }
333
+ /**
334
+ * Load registry from disk
335
+ */
336
+ async loadRegistry() {
337
+ try {
338
+ if (await plugins.smartfile.fs.fileExists(this.registryPath)) {
339
+ const content = await plugins.smartfile.fs.toStringSync(this.registryPath);
340
+ const lines = content.split('\n').filter(line => line.trim());
341
+ for (const line of lines) {
342
+ try {
343
+ const entry = JSON.parse(line);
344
+ this.setCacheEntry(entry.hash, entry.metadata);
345
+ }
346
+ catch (e) {
347
+ this.logger.log('warn', `Invalid registry entry: ${line}`);
348
+ }
349
+ }
350
+ this.logger.log('info', `Loaded ${this.metadataCache.size} invoices from registry`);
351
+ }
352
+ }
353
+ catch (error) {
354
+ this.logger.log('error', `Failed to load registry: ${error}`);
355
+ }
356
+ }
357
+ /**
358
+ * Update registry with new entry
359
+ */
360
+ async updateRegistry(invoiceId, contentHash, metadata) {
361
+ try {
362
+ const entry = {
363
+ id: invoiceId,
364
+ hash: contentHash,
365
+ metadata
366
+ };
367
+ // Append to NDJSON file
368
+ const line = JSON.stringify(entry) + '\n';
369
+ await plugins.smartfile.fs.ensureDir(path.dirname(this.registryPath));
370
+ // Use native fs for atomic append (better performance and concurrency safety)
371
+ const fs = await import('fs/promises');
372
+ await fs.appendFile(this.registryPath, line, 'utf8');
373
+ }
374
+ catch (error) {
375
+ this.logger.log('error', `Failed to update registry: ${error}`);
376
+ }
377
+ }
378
+ /**
379
+ * Find invoice file by hash and extension
380
+ */
381
+ async findInvoiceFile(contentHash, extension) {
382
+ const dirs = [
383
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'inbound'),
384
+ path.join(this.exportPath, 'data', 'documents', 'invoices', 'outbound')
385
+ ];
386
+ for (const dir of dirs) {
387
+ const files = await plugins.smartfile.fs.listFileTree(dir, '**/*' + extension);
388
+ for (const file of files) {
389
+ if (file.includes(contentHash.substring(0, 8))) {
390
+ return path.join(dir, file);
391
+ }
392
+ }
393
+ }
394
+ return null;
395
+ }
396
+ /**
397
+ * Calculate SHA-256 hash
398
+ */
399
+ async calculateHash(data) {
400
+ if (typeof data === 'string') {
401
+ return await plugins.smarthash.sha256FromString(data);
402
+ }
403
+ else {
404
+ return await plugins.smarthash.sha256FromBuffer(data);
405
+ }
406
+ }
407
+ /**
408
+ * Check if metadata matches filter
409
+ */
410
+ matchesFilter(metadata, filter) {
411
+ if (filter.direction && metadata.direction !== filter.direction) {
412
+ return false;
413
+ }
414
+ if (filter.dateFrom && new Date(metadata.issueDate) < filter.dateFrom) {
415
+ return false;
416
+ }
417
+ if (filter.dateTo && new Date(metadata.issueDate) > filter.dateTo) {
418
+ return false;
419
+ }
420
+ if (filter.minAmount && metadata.totalAmount < filter.minAmount) {
421
+ return false;
422
+ }
423
+ if (filter.maxAmount && metadata.totalAmount > filter.maxAmount) {
424
+ return false;
425
+ }
426
+ if (filter.invoiceNumber && !metadata.invoiceNumber.includes(filter.invoiceNumber)) {
427
+ return false;
428
+ }
429
+ if (filter.supplierId && !metadata.supplierName.includes(filter.supplierId)) {
430
+ return false;
431
+ }
432
+ if (filter.customerId && !metadata.customerName.includes(filter.customerId)) {
433
+ return false;
434
+ }
435
+ return true;
436
+ }
437
+ /**
438
+ * Count errors in validation result
439
+ */
440
+ countErrors(validationResult) {
441
+ if (!validationResult)
442
+ return 0;
443
+ return (validationResult.syntax.errors.length +
444
+ validationResult.semantic.errors.length +
445
+ validationResult.businessRules.errors.length +
446
+ (validationResult.countrySpecific?.errors.length || 0));
447
+ }
448
+ /**
449
+ * Count warnings in validation result
450
+ */
451
+ countWarnings(validationResult) {
452
+ if (!validationResult)
453
+ return 0;
454
+ return (validationResult.syntax.warnings.length +
455
+ validationResult.semantic.warnings.length +
456
+ validationResult.businessRules.warnings.length +
457
+ (validationResult.countrySpecific?.warnings.length || 0));
458
+ }
459
+ /**
460
+ * Clean up old invoices (for testing only)
461
+ */
462
+ async cleanup(olderThanDays = 365) {
463
+ let removed = 0;
464
+ const cutoffDate = new Date();
465
+ cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);
466
+ for (const [hash, metadata] of this.metadataCache.entries()) {
467
+ if (new Date(metadata.issueDate) < cutoffDate) {
468
+ this.metadataCache.delete(hash);
469
+ removed++;
470
+ }
471
+ }
472
+ this.logger.log('info', `Removed ${removed} old invoices from cache`);
473
+ return removed;
474
+ }
475
+ /**
476
+ * Set cache entry with LRU eviction
477
+ */
478
+ setCacheEntry(key, value) {
479
+ // Remove from access order if already exists
480
+ const existingIndex = this.cacheAccessOrder.indexOf(key);
481
+ if (existingIndex > -1) {
482
+ this.cacheAccessOrder.splice(existingIndex, 1);
483
+ }
484
+ // Add to end (most recently used)
485
+ this.cacheAccessOrder.push(key);
486
+ this.metadataCache.set(key, value);
487
+ // Evict oldest if cache is too large
488
+ while (this.metadataCache.size > this.MAX_CACHE_SIZE) {
489
+ const oldestKey = this.cacheAccessOrder.shift();
490
+ if (oldestKey) {
491
+ this.metadataCache.delete(oldestKey);
492
+ this.logger.log('debug', `Evicted invoice from cache: ${oldestKey}`);
493
+ }
494
+ }
495
+ }
496
+ /**
497
+ * Get cache entry and update access order
498
+ */
499
+ getCacheEntry(key) {
500
+ const value = this.metadataCache.get(key);
501
+ if (value) {
502
+ // Move to end (most recently used)
503
+ const index = this.cacheAccessOrder.indexOf(key);
504
+ if (index > -1) {
505
+ this.cacheAccessOrder.splice(index, 1);
506
+ }
507
+ this.cacheAccessOrder.push(key);
508
+ }
509
+ return value;
510
+ }
511
+ /**
512
+ * Update metadata in storage and cache
513
+ */
514
+ async updateMetadata(contentHash, updates) {
515
+ const metadata = this.getCacheEntry(contentHash);
516
+ if (!metadata) {
517
+ this.logger.log('warn', `Cannot update metadata - invoice not found: ${contentHash}`);
518
+ return;
519
+ }
520
+ // Update metadata
521
+ const updatedMetadata = { ...metadata, ...updates };
522
+ this.setCacheEntry(contentHash, updatedMetadata);
523
+ // Persist to disk
524
+ const metadataPath = path.join(this.exportPath, 'data', 'documents', 'invoices', metadata.direction, 'metadata', `${contentHash}.json`);
525
+ await plugins.smartfile.memory.toFs(JSON.stringify(updatedMetadata, null, 2), metadataPath);
526
+ this.logger.log('info', `Updated metadata for invoice: ${contentHash}`);
527
+ }
528
+ }
529
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmludm9pY2Uuc3RvcmFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3Nrci5pbnZvaWNlLnN0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUF1RDdCOzs7R0FHRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBUXpCLFlBQVksVUFBa0I7UUFIYixtQkFBYyxHQUFHLEtBQUssQ0FBQyxDQUFDLG1DQUFtQztRQUNwRSxxQkFBZ0IsR0FBYSxFQUFFLENBQUMsQ0FBQyxzQ0FBc0M7UUF5RDlELGlCQUFZLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxXQUFXO1FBdEQzRCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoRCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFDOUYsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNLLGVBQWU7UUFDckIsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDbEQscUNBQXFDO1lBQ3JDLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGNBQWMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsNEJBQTRCO1lBQzFHLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FB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
@@ -0,0 +1,65 @@
1
+ export interface ISigningOptions {
2
+ certificatePem?: string;
3
+ privateKeyPem?: string;
4
+ privateKeyPassphrase?: string;
5
+ timestampServerUrl?: string;
6
+ includeTimestamp?: boolean;
7
+ }
8
+ export interface ISignatureResult {
9
+ signature: string;
10
+ signatureFormat: 'CAdES-B' | 'CAdES-T' | 'CAdES-LT';
11
+ signingTime: string;
12
+ certificateChain?: string[];
13
+ timestampToken?: string;
14
+ timestampTime?: string;
15
+ }
16
+ export interface ITimestampResponse {
17
+ token: string;
18
+ time: string;
19
+ serverUrl: string;
20
+ hashAlgorithm: string;
21
+ }
22
+ export declare class SecurityManager {
23
+ private options;
24
+ private logger;
25
+ constructor(options?: ISigningOptions);
26
+ /**
27
+ * Creates a CAdES-B (Basic) signature for data
28
+ */
29
+ createCadesSignature(data: Buffer | string, certificatePem?: string, privateKeyPem?: string): Promise<ISignatureResult>;
30
+ /**
31
+ * Requests an RFC 3161 timestamp from a TSA
32
+ */
33
+ requestTimestamp(dataHash: string | Buffer): Promise<ITimestampResponse>;
34
+ /**
35
+ * Creates a timestamp request (simplified version)
36
+ */
37
+ private createTimestampRequest;
38
+ /**
39
+ * Sends timestamp request to TSA server
40
+ */
41
+ private sendTimestampRequest;
42
+ /**
43
+ * Verifies a CAdES signature
44
+ */
45
+ verifyCadesSignature(data: Buffer | string, signature: string, certificatePem?: string): Promise<boolean>;
46
+ /**
47
+ * Generates a self-signed certificate for testing
48
+ */
49
+ generateSelfSignedCertificate(commonName?: string, validDays?: number): Promise<{
50
+ certificate: string;
51
+ privateKey: string;
52
+ }>;
53
+ /**
54
+ * Creates a detached signature file
55
+ */
56
+ createDetachedSignature(dataPath: string, outputPath: string): Promise<void>;
57
+ /**
58
+ * Verifies a detached signature file
59
+ */
60
+ verifyDetachedSignature(dataPath: string, signaturePath: string): Promise<boolean>;
61
+ /**
62
+ * Adds Long-Term Validation (LTV) information
63
+ */
64
+ addLtvInformation(signature: ISignatureResult, ocspResponse?: Buffer, crlData?: Buffer): Promise<ISignatureResult>;
65
+ }