diff --git a/.vscode/launch.json b/.vscode/launch.json index b2693156..9a99b3c0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,5 @@ { - "version": "0.4.7", + "version": "0.4.8", "configurations": [ { "name": "WEB: Vite (Chrome)", diff --git a/apps/server/package.json b/apps/server/package.json index 7e73317d..2067ccc0 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -1,6 +1,6 @@ { "name": "@erp/factuges-server", - "version": "0.4.7", + "version": "0.4.8", "private": true, "scripts": { "build": "tsup src/index.ts --config tsup.config.ts", diff --git a/apps/web/package.json b/apps/web/package.json index 569ad801..f7895073 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,7 +1,7 @@ { "name": "@erp/factuges-web", "private": true, - "version": "0.4.7", + "version": "0.4.8", "type": "module", "scripts": { "dev": "vite --host --clearScreen false", diff --git a/modules/auth/package.json b/modules/auth/package.json index a464a3b5..7898f699 100644 --- a/modules/auth/package.json +++ b/modules/auth/package.json @@ -1,6 +1,6 @@ { "name": "@erp/auth", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/modules/core/package.json b/modules/core/package.json index f178a7a2..2bacc603 100644 --- a/modules/core/package.json +++ b/modules/core/package.json @@ -1,6 +1,6 @@ { "name": "@erp/core", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/modules/core/src/api/application/documents/services/document-storage-key-factory.ts b/modules/core/src/api/application/documents/services/document-storage-key-factory.ts index 641796bd..d2e21844 100644 --- a/modules/core/src/api/application/documents/services/document-storage-key-factory.ts +++ b/modules/core/src/api/application/documents/services/document-storage-key-factory.ts @@ -1,7 +1,13 @@ import { createHash } from "node:crypto"; export class DocumentStorageKeyFactory { - static fromMetadataRecord(metadata: Record): string { - return createHash("sha256").update(JSON.stringify(metadata)).digest("hex"); + static fromMetadataRecord(metadata: Record): { + paths: string[]; + storageKey: string; + } { + return { + paths: [String(metadata.companySlug), String(metadata.documentType)], + storageKey: createHash("sha256").update(JSON.stringify(metadata)).digest("hex"), + }; } } diff --git a/modules/core/src/api/application/documents/services/document-storage.interface.ts b/modules/core/src/api/application/documents/services/document-storage.interface.ts index 7bc18636..c8282dff 100644 --- a/modules/core/src/api/application/documents/services/document-storage.interface.ts +++ b/modules/core/src/api/application/documents/services/document-storage.interface.ts @@ -8,7 +8,7 @@ export interface IDocumentStorage { * - Best-effort * - Nunca lanza (errores se gestionan internamente) */ - existsKeyStorage(storageKey: string): Promise; + existsKeyStorage(storageKey: string, paths: string[]): Promise; /** * Recupera un documento guardado. @@ -17,7 +17,7 @@ export interface IDocumentStorage { * - Best-effort * - Nunca lanza (errores se gestionan internamente) */ - readDocument(storageKey: string): Promise; + readDocument(storageKey: string, paths: string[]): Promise; /** * Persiste un documento generado. diff --git a/modules/core/src/api/infrastructure/documents/storage/filesystem-signed-document-storage.ts b/modules/core/src/api/infrastructure/documents/storage/filesystem-signed-document-storage.ts index 4f72bc15..d36faf7b 100644 --- a/modules/core/src/api/infrastructure/documents/storage/filesystem-signed-document-storage.ts +++ b/modules/core/src/api/infrastructure/documents/storage/filesystem-signed-document-storage.ts @@ -1,6 +1,8 @@ import { mkdir, readFile, stat, writeFile } from "node:fs/promises"; import path from "node:path"; +import { buildSafePath } from "@repo/rdx-utils"; + import { DocumentStorageKeyFactory, type IDocument, @@ -15,11 +17,15 @@ import { * - No afecta al flujo del caso de uso */ export class FilesystemDocumentStorage implements IDocumentStorage { - public constructor(private readonly basePath: string) {} + public constructor(private readonly docRootPath: string) {} + + async existsKeyStorage(storageKey: string, paths: string[]): Promise { + // Ejemplo: .../signed-documents/770c138fc58548f72029c1ed4f3670e94be4cc7a0fab9f7f0b84d0aef77f43ae + // paths: => [".../signed-documents"], + // storageKey: => 770c138fc58548f72029c1ed4f3670e94be4cc7a0fab9f7f0b84d0aef77f43ae - async existsKeyStorage(storageKey: string): Promise { try { - const dir = this.resolveDirFromStorageKey(storageKey); + const dir = this.resolveDir(storageKey, paths); return (await stat(dir)).isDirectory(); } catch { // Consistente con saveDocument: best-effort @@ -27,12 +33,12 @@ export class FilesystemDocumentStorage implements IDocumentStorage { } } - async readDocument(storageKey: string) { + async readDocument(storageKey: string, paths: string[]) { try { - const dir = this.resolveDirFromStorageKey(storageKey); + const dir = this.resolveDir(storageKey, paths); const payload = await readFile(path.join(dir, "document.bin")); - const metaRaw = JSON.parse(await readFile(path.join(dir, "document.meta.json"), "utf-8")); + const metaRaw = await readFile(path.join(dir, "document.meta.json"), "utf-8"); const meta = JSON.parse(metaRaw) as { mimeType: string; @@ -78,15 +84,15 @@ export class FilesystemDocumentStorage implements IDocumentStorage { } private resolveDirFromMetadataRecord(metadataRecord: Record): string { - /** - * El storage NO decide claves semánticas. - * Se limita a generar un path técnico estable. - */ - const storageKey = DocumentStorageKeyFactory.fromMetadataRecord(metadataRecord); - return this.resolveDirFromStorageKey(storageKey); + const { paths, storageKey } = DocumentStorageKeyFactory.fromMetadataRecord(metadataRecord); + + return this.resolveDir(storageKey, paths); } - private resolveDirFromStorageKey(storageKey: string): string { - return path.join(this.basePath, storageKey); + private resolveDir(storageKey: string, paths: string[]): string { + return buildSafePath({ + basePath: this.docRootPath, + segments: [...paths, storageKey], + }); } } diff --git a/modules/customer-invoices/package.json b/modules/customer-invoices/package.json index 620c5707..e54305b5 100644 --- a/modules/customer-invoices/package.json +++ b/modules/customer-invoices/package.json @@ -1,6 +1,6 @@ { "name": "@erp/customer-invoices", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/modules/customer-invoices/src/api/infrastructure/documents/pre-processors/issued-invoice-signed-document-cache-pre-processor.ts b/modules/customer-invoices/src/api/infrastructure/documents/pre-processors/issued-invoice-signed-document-cache-pre-processor.ts index 5cd1b70e..633d71df 100644 --- a/modules/customer-invoices/src/api/infrastructure/documents/pre-processors/issued-invoice-signed-document-cache-pre-processor.ts +++ b/modules/customer-invoices/src/api/infrastructure/documents/pre-processors/issued-invoice-signed-document-cache-pre-processor.ts @@ -21,23 +21,25 @@ export class IssuedInvoiceSignedDocumentCachePreProcessor implements IDocumentPr async tryResolve(metadata: IDocumentMetadata): Promise { const metadataRecord = metadata as unknown as Record; try { - const storageKey = DocumentStorageKeyFactory.fromMetadataRecord(metadataRecord); + const { paths, storageKey } = DocumentStorageKeyFactory.fromMetadataRecord(metadataRecord); if (!storageKey) { return null; } - const exists = await this.docStorage.existsKeyStorage(storageKey); + const exists = await this.docStorage.existsKeyStorage(storageKey, paths); if (!exists) { return null; } - const document = await this.docStorage.readDocument(storageKey); + logger.info(`✅ Found Server cached document for key ${storageKey}`); + + const document = await this.docStorage.readDocument(storageKey, paths); if (!this.isValid(document)) { - logger.warn(`Storage key ${storageKey} not exists!`, { - lable: "IssuedInvoiceSignedDocumentCachePreProcessor", + logger.warn(`Corrupted or invalid cached document for key ${storageKey}`, { + label: "IssuedInvoiceSignedDocumentCachePreProcessor", }); return null; } diff --git a/modules/customers/package.json b/modules/customers/package.json index 8e72c523..c22f81b8 100644 --- a/modules/customers/package.json +++ b/modules/customers/package.json @@ -1,6 +1,6 @@ { "name": "@erp/customers", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/modules/doc-numbering/package.json b/modules/doc-numbering/package.json index 7514af6b..be3e618a 100644 --- a/modules/doc-numbering/package.json +++ b/modules/doc-numbering/package.json @@ -1,6 +1,6 @@ { "name": "@erp/doc-numbering", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/packages/rdx-criteria/package.json b/packages/rdx-criteria/package.json index 277e36fe..fc60b078 100644 --- a/packages/rdx-criteria/package.json +++ b/packages/rdx-criteria/package.json @@ -1,6 +1,6 @@ { "name": "@repo/rdx-criteria", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/packages/rdx-ddd/package.json b/packages/rdx-ddd/package.json index 1c09fa8b..50ed6a2d 100644 --- a/packages/rdx-ddd/package.json +++ b/packages/rdx-ddd/package.json @@ -1,6 +1,6 @@ { "name": "@repo/rdx-ddd", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/packages/rdx-logger/package.json b/packages/rdx-logger/package.json index d034ab8f..8df5484e 100644 --- a/packages/rdx-logger/package.json +++ b/packages/rdx-logger/package.json @@ -1,6 +1,6 @@ { "name": "@repo/rdx-logger", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/packages/rdx-utils/package.json b/packages/rdx-utils/package.json index 080a9e28..75485a5d 100644 --- a/packages/rdx-utils/package.json +++ b/packages/rdx-utils/package.json @@ -1,6 +1,6 @@ { "name": "@repo/rdx-utils", - "version": "0.4.7", + "version": "0.4.8", "private": true, "type": "module", "sideEffects": false, diff --git a/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/linux/FastReportCliGenerator b/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/linux/FastReportCliGenerator index cf2e2f66..c3b06f99 100755 Binary files a/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/linux/FastReportCliGenerator and b/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/linux/FastReportCliGenerator differ diff --git a/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/windows/FastReportCliGenerator.exe b/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/windows/FastReportCliGenerator.exe index d34d274a..929d5f85 100755 Binary files a/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/windows/FastReportCliGenerator.exe and b/tools/fastreportcli-net-core-skia/FastReportCliGenerator/publish/windows/FastReportCliGenerator.exe differ