@jmlq/logger-plugin-fs 0.1.0-alpha.7 → 0.1.0-alpha.9
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.
- package/README.md +6 -0
- package/dist/application/dto/index.d.ts +1 -3
- package/dist/application/dto/index.js +1 -3
- package/dist/application/dto/rotate-if-needed.request.d.ts +10 -0
- package/dist/application/factory/create-fs-datasource.factory.d.ts +14 -1
- package/dist/application/factory/create-fs-datasource.factory.js +45 -20
- package/dist/application/use-cases/append-log.use-case.d.ts +26 -8
- package/dist/application/use-cases/append-log.use-case.js +25 -12
- package/dist/application/use-cases/ensure-directory.use-case.d.ts +50 -3
- package/dist/application/use-cases/ensure-directory.use-case.js +44 -7
- package/dist/application/use-cases/find-logs-use-case.d.ts +17 -0
- package/dist/application/use-cases/find-logs-use-case.js +64 -0
- package/dist/application/use-cases/index.d.ts +1 -0
- package/dist/application/use-cases/index.js +1 -0
- package/dist/application/use-cases/persist-log.use-case.d.ts +86 -9
- package/dist/application/use-cases/persist-log.use-case.js +73 -15
- package/dist/application/use-cases/rotate-if-needed.use-case.d.ts +49 -11
- package/dist/application/use-cases/rotate-if-needed.use-case.js +41 -8
- package/dist/domain/model/index.d.ts +1 -0
- package/dist/{infrastructure/filesystem/value-objects → domain/model}/index.js +1 -1
- package/dist/domain/model/log-entry.model.d.ts +8 -0
- package/dist/domain/ports/file/file-path.port.d.ts +38 -0
- package/dist/domain/ports/file/file-rotator.port.d.ts +42 -0
- package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.d.ts +1 -0
- package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.js +1 -0
- package/dist/domain/ports/file/log-stream-writer.port.d.ts +70 -0
- package/dist/domain/ports/{fs-provider.port.d.ts → filesystem-provider.port.d.ts} +1 -1
- package/dist/domain/ports/index.d.ts +5 -4
- package/dist/domain/ports/index.js +5 -4
- package/dist/domain/ports/logs/find/index.d.ts +2 -0
- package/dist/domain/ports/logs/find/index.js +18 -0
- package/dist/domain/ports/logs/find/log-file-line-reader.port.d.ts +3 -0
- package/dist/domain/ports/logs/find/log-file-numerator.port.d.ts +3 -0
- package/dist/domain/ports/logs/index.d.ts +2 -0
- package/dist/domain/ports/logs/index.js +18 -0
- package/dist/domain/ports/logs/log-datasource.port.d.ts +10 -0
- package/dist/domain/ports/{clock.port.d.ts → system-clock.port.d.ts} +1 -1
- package/dist/domain/ports/system-clock.port.js +2 -0
- package/dist/domain/request/index.d.ts +2 -0
- package/dist/domain/request/index.js +18 -0
- package/dist/domain/request/log-filter.request.d.ts +9 -0
- package/dist/domain/request/log-filter.request.js +2 -0
- package/dist/domain/request/save-log.request.d.ts +7 -0
- package/dist/domain/request/save-log.request.js +2 -0
- package/dist/domain/response/index.d.ts +1 -0
- package/dist/{application/services → domain/response}/index.js +1 -1
- package/dist/domain/response/log.response.d.ts +8 -0
- package/dist/domain/response/log.response.js +2 -0
- package/dist/domain/types/fs-rotation-by.type.d.ts +8 -0
- package/dist/domain/types/fs-rotation-by.type.js +2 -0
- package/dist/domain/types/index.d.ts +1 -0
- package/dist/domain/types/index.js +17 -0
- package/dist/domain/value-objects/file-name-pattern.vo.d.ts +36 -0
- package/dist/domain/value-objects/file-name-pattern.vo.js +53 -0
- package/dist/domain/value-objects/file-path.vo.d.ts +73 -9
- package/dist/domain/value-objects/file-path.vo.js +54 -13
- package/dist/domain/value-objects/file-rotation-policy.vo.d.ts +51 -0
- package/dist/domain/value-objects/file-rotation-policy.vo.js +76 -0
- package/dist/domain/value-objects/file-size.vo.d.ts +61 -0
- package/dist/domain/value-objects/file-size.vo.js +57 -0
- package/dist/domain/value-objects/index.d.ts +3 -0
- package/dist/domain/value-objects/index.js +3 -0
- package/dist/domain/value-objects/log-level.vo.d.ts +8 -0
- package/dist/domain/value-objects/log-level.vo.js +13 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +5 -11
- package/dist/infrastructure/adapters/file-rotator.adapter.d.ts +67 -8
- package/dist/infrastructure/adapters/file-rotator.adapter.js +133 -67
- package/dist/infrastructure/adapters/fileSystem-datasource.adapter.d.ts +26 -0
- package/dist/infrastructure/adapters/fileSystem-datasource.adapter.js +45 -0
- package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.d.ts +6 -0
- package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.js +54 -0
- package/dist/infrastructure/adapters/filesystem-log-file-line-reader.adapter.d.ts +4 -0
- package/dist/infrastructure/adapters/{fs-provider.adapter.js → filesystem-log-file-line-reader.adapter.js} +13 -37
- package/dist/infrastructure/adapters/filesystem-provider.adapter.d.ts +122 -0
- package/dist/infrastructure/adapters/filesystem-provider.adapter.js +182 -0
- package/dist/infrastructure/adapters/index.d.ts +7 -4
- package/dist/infrastructure/adapters/index.js +7 -4
- package/dist/infrastructure/adapters/log-stream-writer.adapter.d.ts +80 -0
- package/dist/infrastructure/adapters/log-stream-writer.adapter.js +163 -0
- package/dist/infrastructure/adapters/system-clock.adapter.d.ts +25 -0
- package/dist/infrastructure/adapters/system-clock.adapter.js +30 -0
- package/dist/infrastructure/adapters/system-file-path.adapter.d.ts +47 -0
- package/dist/infrastructure/adapters/system-file-path.adapter.js +141 -0
- package/dist/infrastructure/errors/file-operation.error.d.ts +28 -0
- package/dist/infrastructure/errors/file-operation.error.js +54 -0
- package/dist/infrastructure/errors/index.d.ts +1 -0
- package/dist/{shared → infrastructure}/errors/index.js +0 -2
- package/dist/infrastructure/errors/types/file-operation-error-options.type.d.ts +8 -0
- package/dist/infrastructure/errors/types/file-operation-error-options.type.js +2 -0
- package/dist/infrastructure/errors/types/file-operation.type.d.ts +1 -0
- package/dist/infrastructure/errors/types/file-operation.type.js +2 -0
- package/dist/infrastructure/errors/types/fs-error-scope.type.d.ts +1 -0
- package/dist/infrastructure/errors/types/fs-error-scope.type.js +2 -0
- package/dist/infrastructure/errors/types/index.d.ts +3 -0
- package/dist/infrastructure/errors/types/index.js +19 -0
- package/dist/infrastructure/filesystem/index.d.ts +0 -3
- package/dist/infrastructure/filesystem/index.js +0 -3
- package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.d.ts +2 -6
- package/dist/infrastructure/filesystem/types/filesystem-rotation.type.d.ts +2 -9
- package/dist/infrastructure/filesystem/types/index.d.ts +0 -1
- package/dist/infrastructure/filesystem/types/index.js +0 -1
- package/install.md +1 -1
- package/package.json +4 -6
- package/dist/application/dto/rotation-check.dto.d.ts +0 -5
- package/dist/application/dto/save-log.dto.d.ts +0 -4
- package/dist/application/dto/write-operation.dto.d.ts +0 -5
- package/dist/application/services/fs-datasource.service.d.ts +0 -11
- package/dist/application/services/fs-datasource.service.js +0 -19
- package/dist/application/services/index.d.ts +0 -1
- package/dist/domain/ports/file-path-adapter.port.d.ts +0 -33
- package/dist/domain/ports/stream-writer.port.d.ts +0 -42
- package/dist/infrastructure/adapters/fs-provider.adapter.d.ts +0 -17
- package/dist/infrastructure/adapters/fs-writer.adapter.d.ts +0 -13
- package/dist/infrastructure/adapters/fs-writer.adapter.js +0 -71
- package/dist/infrastructure/adapters/node-clock.adapter.d.ts +0 -4
- package/dist/infrastructure/adapters/node-clock.adapter.js +0 -9
- package/dist/infrastructure/adapters/node-file-path.adapter.d.ts +0 -16
- package/dist/infrastructure/adapters/node-file-path.adapter.js +0 -117
- package/dist/infrastructure/filesystem/polices/index.d.ts +0 -1
- package/dist/infrastructure/filesystem/polices/index.js +0 -5
- package/dist/infrastructure/filesystem/polices/rotation-policy.d.ts +0 -29
- package/dist/infrastructure/filesystem/polices/rotation-policy.js +0 -55
- package/dist/infrastructure/filesystem/ports/file-rotator.port.d.ts +0 -32
- package/dist/infrastructure/filesystem/types/filesystem-serializer.type.d.ts +0 -10
- package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.d.ts +0 -22
- package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.js +0 -37
- package/dist/infrastructure/filesystem/value-objects/index.d.ts +0 -1
- package/dist/shared/errors/file-operation.error.d.ts +0 -12
- package/dist/shared/errors/file-operation.error.js +0 -32
- package/dist/shared/errors/fs-plugin.error.d.ts +0 -4
- package/dist/shared/errors/fs-plugin.error.js +0 -11
- package/dist/shared/errors/index.d.ts +0 -3
- package/dist/shared/errors/rotation.error.d.ts +0 -10
- package/dist/shared/errors/rotation.error.js +0 -25
- /package/dist/application/dto/{rotation-check.dto.js → rotate-if-needed.request.js} +0 -0
- /package/dist/{application/dto/save-log.dto.js → domain/model/log-entry.model.js} +0 -0
- /package/dist/{application/dto/write-operation.dto.js → domain/ports/file/file-path.port.js} +0 -0
- /package/dist/{infrastructure/filesystem/ports → domain/ports/file}/file-rotator.port.js +0 -0
- /package/dist/domain/ports/{clock.port.js → file/log-stream-writer.port.js} +0 -0
- /package/dist/domain/ports/{file-path-adapter.port.js → filesystem-provider.port.js} +0 -0
- /package/dist/domain/ports/{fs-provider.port.js → logs/find/log-file-line-reader.port.js} +0 -0
- /package/dist/domain/ports/{stream-writer.port.js → logs/find/log-file-numerator.port.js} +0 -0
- /package/dist/{infrastructure/filesystem/types/filesystem-serializer.type.js → domain/ports/logs/log-datasource.port.js} +0 -0
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ Plugin de **sistema de archivos** para [`@jmlq/logger`](https://www.npmjs.com/pa
|
|
|
8
8
|
npm install @jmlq/logger @jmlq/logger-plugin-fs
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
### Dependencias
|
|
12
|
+
|
|
13
|
+
El plugin requiere como peer dependency:
|
|
14
|
+
|
|
15
|
+
- `@jmlq/logger` >= 0.1.0-alpha.12
|
|
16
|
+
|
|
11
17
|
> **Nota:** Este plugin requiere [`@jmlq/logger`](https://www.npmjs.com/package/@jmlq/logger) como dependencia principal.
|
|
12
18
|
|
|
13
19
|
## 🚀 Uso rápido
|
|
@@ -14,6 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
18
|
-
__exportStar(require("./save-log.dto"), exports);
|
|
19
|
-
__exportStar(require("./write-operation.dto"), exports);
|
|
17
|
+
__exportStar(require("./rotate-if-needed.request"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileRotationPolicy } from "../../domain/value-objects";
|
|
2
|
+
/**
|
|
3
|
+
* DTO de entrada para el caso de uso RotateIfNeeded.
|
|
4
|
+
* - currentDate: fecha/hora actual (inyectada desde un clock para tests deterministas)
|
|
5
|
+
* - rotationPolicy: política de rotación (VO de dominio)
|
|
6
|
+
*/
|
|
7
|
+
export interface RotateIfNeededRequest {
|
|
8
|
+
currentDate: Date;
|
|
9
|
+
rotationPolicy: FileRotationPolicy;
|
|
10
|
+
}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
import { ILogDatasource } from "@jmlq/logger";
|
|
2
1
|
import { IFilesystemDatasourceOptions } from "../../infrastructure/filesystem";
|
|
2
|
+
import { ILogDatasource } from "../../domain/ports";
|
|
3
|
+
/**
|
|
4
|
+
* createFsDatasource
|
|
5
|
+
* -----------------------------------------------------------------------------
|
|
6
|
+
* Composition Root del plugin FS.
|
|
7
|
+
*
|
|
8
|
+
* Responsabilidad:
|
|
9
|
+
* - Construir el grafo de dependencias (VOs, adapters, use-cases)
|
|
10
|
+
* - Exponer un ILogDatasource compatible con @jmlq/logger
|
|
11
|
+
*
|
|
12
|
+
* Clean Architecture:
|
|
13
|
+
* - Vive en infraestructura porque integra con el core externo (@jmlq/logger)
|
|
14
|
+
* - Application/domain permanecen sin dependencias externas.
|
|
15
|
+
*/
|
|
3
16
|
export declare function createFsDatasource(options: IFilesystemDatasourceOptions): ILogDatasource;
|
|
@@ -1,26 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import type { ILogDatasource } from "@jmlq/logger";
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.createFsDatasource = createFsDatasource;
|
|
4
5
|
const adapters_1 = require("../../infrastructure/adapters");
|
|
5
|
-
const use_cases_1 = require("
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const use_cases_1 = require("../../application/use-cases");
|
|
7
|
+
const value_objects_1 = require("../../domain/value-objects");
|
|
8
|
+
/**
|
|
9
|
+
* createFsDatasource
|
|
10
|
+
* -----------------------------------------------------------------------------
|
|
11
|
+
* Composition Root del plugin FS.
|
|
12
|
+
*
|
|
13
|
+
* Responsabilidad:
|
|
14
|
+
* - Construir el grafo de dependencias (VOs, adapters, use-cases)
|
|
15
|
+
* - Exponer un ILogDatasource compatible con @jmlq/logger
|
|
16
|
+
*
|
|
17
|
+
* Clean Architecture:
|
|
18
|
+
* - Vive en infraestructura porque integra con el core externo (@jmlq/logger)
|
|
19
|
+
* - Application/domain permanecen sin dependencias externas.
|
|
20
|
+
*/
|
|
8
21
|
function createFsDatasource(options) {
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// 1) Value Objects (dominio)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
const fileNamePattern = new value_objects_1.FileNamePattern(options.fileNamePattern || "app-{yyyy}{MM}{dd}.log");
|
|
26
|
+
const rotationPolicy = new value_objects_1.FileRotationPolicy(options.rotation?.by || "day", options.rotation?.maxSizeMB, options.rotation?.maxFiles);
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// 2) Adapters (infraestructura)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
const clock = new adapters_1.SystemClockAdapter();
|
|
31
|
+
const filePath = new adapters_1.SystemFilePathAdapter();
|
|
32
|
+
const fsProvider = new adapters_1.FileSystemProviderAdapter();
|
|
33
|
+
const writer = new adapters_1.LogStreamWriterAdapter();
|
|
34
|
+
const fileRotator = new adapters_1.FileRotatorAdapter(fsProvider, filePath, fileNamePattern, options.basePath);
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// 3) Use-cases (application)
|
|
37
|
+
// Nota: no se "exponen" fuera; PersistLog orquesta todo.
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
const ensureDirectoryUseCase = new use_cases_1.EnsureDirectoryUseCase(fsProvider, options.basePath, options.mkdir);
|
|
40
|
+
const appendLogUseCase = new use_cases_1.AppendLogUseCase(writer);
|
|
41
|
+
const rotateIfNeededUseCase = new use_cases_1.RotateIfNeededUseCase(fileRotator, writer, options.onRotate);
|
|
42
|
+
const persistLogUseCase = new use_cases_1.PersistLogUseCase(clock, fileRotator, writer, rotationPolicy, rotateIfNeededUseCase, appendLogUseCase, ensureDirectoryUseCase, options.onError);
|
|
43
|
+
// 3.x) FindLogs use-case + IO
|
|
44
|
+
const fileEnumerator = new adapters_1.FileSystemLogFileEnumeratorAdapter(options.basePath);
|
|
45
|
+
const lineReader = new adapters_1.FileSystemLogFileLineReaderAdapter();
|
|
46
|
+
const findLogsUseCase = new use_cases_1.FindLogsUseCase({ fileEnumerator, lineReader });
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// 4) Adapter que expone el contrato del core (@jmlq/logger)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
return new adapters_1.FsDatasourceAdapter(persistLogUseCase, writer, findLogsUseCase);
|
|
26
51
|
}
|
|
@@ -1,12 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { SaveLogRequest } from "../../domain/request";
|
|
2
|
+
import { ILogStreamWriterPort } from "../../domain/ports";
|
|
3
|
+
/**
|
|
4
|
+
* Contrato del caso de uso: permite ejecutar la operación "append log".
|
|
5
|
+
* Útil si quieres mockearlo en tests o exponerlo vía facade.
|
|
6
|
+
*/
|
|
4
7
|
export interface IAppendLogUseCase {
|
|
5
|
-
execute(dto:
|
|
8
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
6
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* AppendLogUseCase
|
|
12
|
+
* -----------------------------------------------------------------------------
|
|
13
|
+
* Caso de uso de Application que:
|
|
14
|
+
* - toma un log (request model),
|
|
15
|
+
* - lo serializa (serializer opcional o JSON por defecto),
|
|
16
|
+
* - asegura salto de línea,
|
|
17
|
+
* - lo escribe a través de un port (writer por stream).
|
|
18
|
+
*
|
|
19
|
+
* Clean Architecture:
|
|
20
|
+
* - depende de puertos del dominio (ILogStreamWriterPort)
|
|
21
|
+
* - NO depende de infraestructura directamente.
|
|
22
|
+
*/
|
|
7
23
|
export declare class AppendLogUseCase implements IAppendLogUseCase {
|
|
8
|
-
private readonly
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
private readonly logStreamWriter;
|
|
25
|
+
constructor(logStreamWriter: ILogStreamWriterPort);
|
|
26
|
+
/**
|
|
27
|
+
* Ejecuta el caso de uso "append log".
|
|
28
|
+
*/
|
|
29
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
12
30
|
}
|
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AppendLogUseCase = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* AppendLogUseCase
|
|
6
|
+
* -----------------------------------------------------------------------------
|
|
7
|
+
* Caso de uso de Application que:
|
|
8
|
+
* - toma un log (request model),
|
|
9
|
+
* - lo serializa (serializer opcional o JSON por defecto),
|
|
10
|
+
* - asegura salto de línea,
|
|
11
|
+
* - lo escribe a través de un port (writer por stream).
|
|
12
|
+
*
|
|
13
|
+
* Clean Architecture:
|
|
14
|
+
* - depende de puertos del dominio (ILogStreamWriterPort)
|
|
15
|
+
* - NO depende de infraestructura directamente.
|
|
16
|
+
*/
|
|
4
17
|
class AppendLogUseCase {
|
|
5
|
-
constructor(
|
|
6
|
-
|
|
7
|
-
|
|
18
|
+
constructor(
|
|
19
|
+
// Outbound port hacia infraestructura (writer de stream)
|
|
20
|
+
logStreamWriter) {
|
|
21
|
+
this.logStreamWriter = logStreamWriter;
|
|
8
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Ejecuta el caso de uso "append log".
|
|
25
|
+
*/
|
|
9
26
|
async execute(dto) {
|
|
10
27
|
const { log } = dto;
|
|
28
|
+
// 1) Serializar el log
|
|
11
29
|
let serializedData;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
// Serialización por defecto
|
|
17
|
-
serializedData = JSON.stringify(log);
|
|
18
|
-
}
|
|
19
|
-
// Agregar salto de línea si no lo tiene
|
|
30
|
+
serializedData = JSON.stringify(log);
|
|
31
|
+
// 2) Asegurar salto de línea para escritura line-by-line
|
|
20
32
|
if (!serializedData.endsWith("\n")) {
|
|
21
33
|
serializedData += "\n";
|
|
22
34
|
}
|
|
23
|
-
|
|
35
|
+
// 3) Escribir al stream mediante el port (IO en infraestructura)
|
|
36
|
+
await this.logStreamWriter.write(serializedData);
|
|
24
37
|
}
|
|
25
38
|
}
|
|
26
39
|
exports.AppendLogUseCase = AppendLogUseCase;
|
|
@@ -1,11 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IFileSystemProviderPort } from "../../domain/ports";
|
|
2
|
+
/**
|
|
3
|
+
* Contrato del caso de uso: asegura la existencia del directorio base.
|
|
4
|
+
*/
|
|
2
5
|
export interface IEnsureDirectoryUseCase {
|
|
3
6
|
execute(): Promise<void>;
|
|
4
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* EnsureDirectoryUseCase
|
|
10
|
+
* -----------------------------------------------------------------------------
|
|
11
|
+
* Caso de uso de Application que garantiza que exista un directorio.
|
|
12
|
+
*
|
|
13
|
+
* Clean Architecture:
|
|
14
|
+
* - Depende de un port de dominio (IFileSystemProviderPort) para IO.
|
|
15
|
+
* - No depende de infraestructura directamente.
|
|
16
|
+
*
|
|
17
|
+
* Comportamiento:
|
|
18
|
+
* - Si createIfNotExists es false, no hace nada (no side-effects).
|
|
19
|
+
* - Si el directorio no existe, lo crea (recursive).
|
|
20
|
+
*/
|
|
5
21
|
export declare class EnsureDirectoryUseCase implements IEnsureDirectoryUseCase {
|
|
6
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Port de filesystem
|
|
24
|
+
*/
|
|
25
|
+
private readonly fileSystemProvider;
|
|
26
|
+
/**
|
|
27
|
+
* Ruta del directorio base a asegurar.
|
|
28
|
+
* Nota: aquí se usa string; idealmente podría ser un VO (FilePath/DirectoryPath)
|
|
29
|
+
* si tu dominio ya lo maneja.
|
|
30
|
+
*/
|
|
7
31
|
private readonly basePath;
|
|
32
|
+
/**
|
|
33
|
+
* Flag de configuración: si es false, el caso de uso es no-op.
|
|
34
|
+
*/
|
|
8
35
|
private readonly createIfNotExists;
|
|
9
|
-
constructor(
|
|
36
|
+
constructor(
|
|
37
|
+
/**
|
|
38
|
+
* Port de filesystem
|
|
39
|
+
*/
|
|
40
|
+
fileSystemProvider: IFileSystemProviderPort,
|
|
41
|
+
/**
|
|
42
|
+
* Ruta del directorio base a asegurar.
|
|
43
|
+
* Nota: aquí se usa string; idealmente podría ser un VO (FilePath/DirectoryPath)
|
|
44
|
+
* si tu dominio ya lo maneja.
|
|
45
|
+
*/
|
|
46
|
+
basePath: string,
|
|
47
|
+
/**
|
|
48
|
+
* Flag de configuración: si es false, el caso de uso es no-op.
|
|
49
|
+
*/
|
|
50
|
+
createIfNotExists?: boolean);
|
|
51
|
+
/**
|
|
52
|
+
* Ejecuta la operación:
|
|
53
|
+
* - verifica existencia
|
|
54
|
+
* - crea el directorio si no existe
|
|
55
|
+
* - encapsula errores en un error de dominio
|
|
56
|
+
*/
|
|
10
57
|
execute(): Promise<void>;
|
|
11
58
|
}
|
|
@@ -1,26 +1,63 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EnsureDirectoryUseCase = void 0;
|
|
4
|
-
const errors_1 = require("../../
|
|
4
|
+
const errors_1 = require("../../infrastructure/errors");
|
|
5
|
+
/**
|
|
6
|
+
* EnsureDirectoryUseCase
|
|
7
|
+
* -----------------------------------------------------------------------------
|
|
8
|
+
* Caso de uso de Application que garantiza que exista un directorio.
|
|
9
|
+
*
|
|
10
|
+
* Clean Architecture:
|
|
11
|
+
* - Depende de un port de dominio (IFileSystemProviderPort) para IO.
|
|
12
|
+
* - No depende de infraestructura directamente.
|
|
13
|
+
*
|
|
14
|
+
* Comportamiento:
|
|
15
|
+
* - Si createIfNotExists es false, no hace nada (no side-effects).
|
|
16
|
+
* - Si el directorio no existe, lo crea (recursive).
|
|
17
|
+
*/
|
|
5
18
|
class EnsureDirectoryUseCase {
|
|
6
|
-
constructor(
|
|
7
|
-
|
|
19
|
+
constructor(
|
|
20
|
+
/**
|
|
21
|
+
* Port de filesystem
|
|
22
|
+
*/
|
|
23
|
+
fileSystemProvider,
|
|
24
|
+
/**
|
|
25
|
+
* Ruta del directorio base a asegurar.
|
|
26
|
+
* Nota: aquí se usa string; idealmente podría ser un VO (FilePath/DirectoryPath)
|
|
27
|
+
* si tu dominio ya lo maneja.
|
|
28
|
+
*/
|
|
29
|
+
basePath,
|
|
30
|
+
/**
|
|
31
|
+
* Flag de configuración: si es false, el caso de uso es no-op.
|
|
32
|
+
*/
|
|
33
|
+
createIfNotExists = true) {
|
|
34
|
+
this.fileSystemProvider = fileSystemProvider;
|
|
8
35
|
this.basePath = basePath;
|
|
9
36
|
this.createIfNotExists = createIfNotExists;
|
|
10
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Ejecuta la operación:
|
|
40
|
+
* - verifica existencia
|
|
41
|
+
* - crea el directorio si no existe
|
|
42
|
+
* - encapsula errores en un error de dominio
|
|
43
|
+
*/
|
|
11
44
|
async execute() {
|
|
45
|
+
// Si la config indica no crear, salimos sin hacer nada.
|
|
12
46
|
if (!this.createIfNotExists) {
|
|
13
47
|
return;
|
|
14
48
|
}
|
|
15
49
|
try {
|
|
16
|
-
// El basePath ES el directorio que queremos
|
|
17
|
-
const exists = await this.
|
|
50
|
+
// El basePath ES el directorio que queremos asegurar.
|
|
51
|
+
const exists = await this.fileSystemProvider.exists(this.basePath);
|
|
18
52
|
if (!exists) {
|
|
19
|
-
await this.
|
|
53
|
+
await this.fileSystemProvider.mkdir(this.basePath, {
|
|
54
|
+
recursive: true,
|
|
55
|
+
});
|
|
20
56
|
}
|
|
21
57
|
}
|
|
22
58
|
catch (error) {
|
|
23
|
-
|
|
59
|
+
// Error de dominio (no infraestructura) para mantener la dirección de dependencias.
|
|
60
|
+
throw errors_1.FileOperationError.create("mkdir", this.basePath, error);
|
|
24
61
|
}
|
|
25
62
|
}
|
|
26
63
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LogFilterRequest } from "../../domain/request";
|
|
2
|
+
import { ILogFileEnumeratorPort, ILogFileLineReaderPort } from "../../domain/ports";
|
|
3
|
+
import { ILogResponse } from "../../domain/response";
|
|
4
|
+
export interface IFindLogsUseCase {
|
|
5
|
+
execute(filter?: LogFilterRequest): Promise<ILogResponse[]>;
|
|
6
|
+
}
|
|
7
|
+
export declare class FindLogsUseCase implements IFindLogsUseCase {
|
|
8
|
+
private readonly deps;
|
|
9
|
+
constructor(deps: {
|
|
10
|
+
fileEnumerator: ILogFileEnumeratorPort;
|
|
11
|
+
lineReader: ILogFileLineReaderPort;
|
|
12
|
+
});
|
|
13
|
+
execute(filter?: LogFilterRequest): Promise<ILogResponse[]>;
|
|
14
|
+
private matchesFilter;
|
|
15
|
+
private applyPagination;
|
|
16
|
+
private messageToText;
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FindLogsUseCase = void 0;
|
|
4
|
+
class FindLogsUseCase {
|
|
5
|
+
constructor(deps) {
|
|
6
|
+
this.deps = deps;
|
|
7
|
+
}
|
|
8
|
+
async execute(filter) {
|
|
9
|
+
// if (!this.ds.find) return [];
|
|
10
|
+
const files = await this.deps.fileEnumerator.listLogFiles();
|
|
11
|
+
const records = [];
|
|
12
|
+
for (const file of files) {
|
|
13
|
+
for await (const line of this.deps.lineReader.readLines(file)) {
|
|
14
|
+
if (!line.trim())
|
|
15
|
+
continue;
|
|
16
|
+
let record;
|
|
17
|
+
try {
|
|
18
|
+
record = JSON.parse(line);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
continue; // línea corrupta → la ignoras
|
|
22
|
+
}
|
|
23
|
+
if (!this.matchesFilter(record, filter))
|
|
24
|
+
continue;
|
|
25
|
+
records.push(record);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return this.applyPagination(records, filter);
|
|
29
|
+
}
|
|
30
|
+
matchesFilter(r, f) {
|
|
31
|
+
if (f?.levelMin != null && r.level < f.levelMin)
|
|
32
|
+
return false;
|
|
33
|
+
if (f?.since != null && r.timestamp < f.since)
|
|
34
|
+
return false;
|
|
35
|
+
if (f?.until != null && r.timestamp > f.until)
|
|
36
|
+
return false;
|
|
37
|
+
if (f?.query?.trim()) {
|
|
38
|
+
const q = f.query.trim().toLowerCase();
|
|
39
|
+
const msgText = this.messageToText(r.message).toLowerCase();
|
|
40
|
+
if (!msgText.includes(q))
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
applyPagination(records, f) {
|
|
46
|
+
const ordered = records.slice().sort((a, b) => a.timestamp - b.timestamp);
|
|
47
|
+
const limit = typeof f?.limit === "number" ? f.limit : ordered.length;
|
|
48
|
+
const page = typeof f?.offset === "number" ? f.offset : 0;
|
|
49
|
+
const slice = ordered.slice(page * limit, page * limit + limit);
|
|
50
|
+
return slice.reverse();
|
|
51
|
+
}
|
|
52
|
+
messageToText(message) {
|
|
53
|
+
if (typeof message === "string")
|
|
54
|
+
return message;
|
|
55
|
+
// message es objeto: lo convertimos a string para búsqueda simple
|
|
56
|
+
try {
|
|
57
|
+
return JSON.stringify(message);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return "";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.FindLogsUseCase = FindLogsUseCase;
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./append-log.use-case"), exports);
|
|
|
18
18
|
__exportStar(require("./ensure-directory.use-case"), exports);
|
|
19
19
|
__exportStar(require("./persist-log.use-case"), exports);
|
|
20
20
|
__exportStar(require("./rotate-if-needed.use-case"), exports);
|
|
21
|
+
__exportStar(require("./find-logs-use-case"), exports);
|
|
@@ -1,19 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ISystemClockPort, ILogStreamWriterPort, IFileRotatorPort } from "../../domain/ports";
|
|
2
|
+
import { SaveLogRequest } from "../../domain/request";
|
|
3
3
|
import { IAppendLogUseCase, IEnsureDirectoryUseCase, IRotateIfNeededUseCase } from ".";
|
|
4
|
-
import {
|
|
4
|
+
import { FileRotationPolicy } from "../../domain/value-objects";
|
|
5
|
+
/**
|
|
6
|
+
* Contrato del caso de uso principal para persistir logs.
|
|
7
|
+
*/
|
|
5
8
|
export interface IPersistLogUseCase {
|
|
6
|
-
execute(dto:
|
|
9
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
7
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* PersistLogUseCase
|
|
13
|
+
* -----------------------------------------------------------------------------
|
|
14
|
+
* Caso de uso de Application que orquesta el flujo completo:
|
|
15
|
+
* - asegura el directorio base
|
|
16
|
+
* - decide si rota según política y fecha actual
|
|
17
|
+
* - garantiza que el stream está abierto en el archivo correcto
|
|
18
|
+
* - escribe el log (append)
|
|
19
|
+
*
|
|
20
|
+
* Nota (Clean Architecture):
|
|
21
|
+
* - No hace IO directamente: todo IO va por ports/use-cases delegados.
|
|
22
|
+
* - Centraliza la secuencia y manejo de errores del flujo.
|
|
23
|
+
*/
|
|
8
24
|
export declare class PersistLogUseCase implements IPersistLogUseCase {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Port para obtener la hora actual
|
|
27
|
+
*/
|
|
28
|
+
private readonly systemClock;
|
|
29
|
+
/**
|
|
30
|
+
* Port relacionado con rotación/naming (según diseño actual).
|
|
31
|
+
* Idealmente: la parte de naming debería estar separada en un "namer".
|
|
32
|
+
*/
|
|
33
|
+
private readonly fileRotator;
|
|
34
|
+
/**
|
|
35
|
+
* Writer por stream
|
|
36
|
+
*/
|
|
37
|
+
private readonly streamWriter;
|
|
38
|
+
/**
|
|
39
|
+
* Política de rotación (VO de dominio).
|
|
40
|
+
*/
|
|
12
41
|
private readonly rotationPolicy;
|
|
42
|
+
/**
|
|
43
|
+
* Use-case que ejecuta rotación si corresponde
|
|
44
|
+
*/
|
|
13
45
|
private readonly rotateIfNeededUseCase;
|
|
46
|
+
/**
|
|
47
|
+
* Use-case que serializa y escribe el log al stream.
|
|
48
|
+
*/
|
|
14
49
|
private readonly appendLogUseCase;
|
|
50
|
+
/**
|
|
51
|
+
* Use-case que asegura que el directorio base exista.
|
|
52
|
+
*/
|
|
15
53
|
private readonly ensureDirectoryUseCase;
|
|
54
|
+
/**
|
|
55
|
+
* Hook opcional para reportar/registrar errores antes de relanzarlos.
|
|
56
|
+
*/
|
|
16
57
|
private readonly onError?;
|
|
17
|
-
constructor(
|
|
18
|
-
|
|
58
|
+
constructor(
|
|
59
|
+
/**
|
|
60
|
+
* Port para obtener la hora actual
|
|
61
|
+
*/
|
|
62
|
+
systemClock: ISystemClockPort,
|
|
63
|
+
/**
|
|
64
|
+
* Port relacionado con rotación/naming (según diseño actual).
|
|
65
|
+
* Idealmente: la parte de naming debería estar separada en un "namer".
|
|
66
|
+
*/
|
|
67
|
+
fileRotator: IFileRotatorPort,
|
|
68
|
+
/**
|
|
69
|
+
* Writer por stream
|
|
70
|
+
*/
|
|
71
|
+
streamWriter: ILogStreamWriterPort,
|
|
72
|
+
/**
|
|
73
|
+
* Política de rotación (VO de dominio).
|
|
74
|
+
*/
|
|
75
|
+
rotationPolicy: FileRotationPolicy,
|
|
76
|
+
/**
|
|
77
|
+
* Use-case que ejecuta rotación si corresponde
|
|
78
|
+
*/
|
|
79
|
+
rotateIfNeededUseCase: IRotateIfNeededUseCase,
|
|
80
|
+
/**
|
|
81
|
+
* Use-case que serializa y escribe el log al stream.
|
|
82
|
+
*/
|
|
83
|
+
appendLogUseCase: IAppendLogUseCase,
|
|
84
|
+
/**
|
|
85
|
+
* Use-case que asegura que el directorio base exista.
|
|
86
|
+
*/
|
|
87
|
+
ensureDirectoryUseCase: IEnsureDirectoryUseCase,
|
|
88
|
+
/**
|
|
89
|
+
* Hook opcional para reportar/registrar errores antes de relanzarlos.
|
|
90
|
+
*/
|
|
91
|
+
onError?: ((error: Error) => void | Promise<void>) | undefined);
|
|
92
|
+
/**
|
|
93
|
+
* Ejecuta el flujo principal de persistencia del log.
|
|
94
|
+
*/
|
|
95
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
19
96
|
}
|