@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.
Files changed (144) hide show
  1. package/README.md +6 -0
  2. package/dist/application/dto/index.d.ts +1 -3
  3. package/dist/application/dto/index.js +1 -3
  4. package/dist/application/dto/rotate-if-needed.request.d.ts +10 -0
  5. package/dist/application/factory/create-fs-datasource.factory.d.ts +14 -1
  6. package/dist/application/factory/create-fs-datasource.factory.js +45 -20
  7. package/dist/application/use-cases/append-log.use-case.d.ts +26 -8
  8. package/dist/application/use-cases/append-log.use-case.js +25 -12
  9. package/dist/application/use-cases/ensure-directory.use-case.d.ts +50 -3
  10. package/dist/application/use-cases/ensure-directory.use-case.js +44 -7
  11. package/dist/application/use-cases/find-logs-use-case.d.ts +17 -0
  12. package/dist/application/use-cases/find-logs-use-case.js +64 -0
  13. package/dist/application/use-cases/index.d.ts +1 -0
  14. package/dist/application/use-cases/index.js +1 -0
  15. package/dist/application/use-cases/persist-log.use-case.d.ts +86 -9
  16. package/dist/application/use-cases/persist-log.use-case.js +73 -15
  17. package/dist/application/use-cases/rotate-if-needed.use-case.d.ts +49 -11
  18. package/dist/application/use-cases/rotate-if-needed.use-case.js +41 -8
  19. package/dist/domain/model/index.d.ts +1 -0
  20. package/dist/{infrastructure/filesystem/value-objects → domain/model}/index.js +1 -1
  21. package/dist/domain/model/log-entry.model.d.ts +8 -0
  22. package/dist/domain/ports/file/file-path.port.d.ts +38 -0
  23. package/dist/domain/ports/file/file-rotator.port.d.ts +42 -0
  24. package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.d.ts +1 -0
  25. package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.js +1 -0
  26. package/dist/domain/ports/file/log-stream-writer.port.d.ts +70 -0
  27. package/dist/domain/ports/{fs-provider.port.d.ts → filesystem-provider.port.d.ts} +1 -1
  28. package/dist/domain/ports/index.d.ts +5 -4
  29. package/dist/domain/ports/index.js +5 -4
  30. package/dist/domain/ports/logs/find/index.d.ts +2 -0
  31. package/dist/domain/ports/logs/find/index.js +18 -0
  32. package/dist/domain/ports/logs/find/log-file-line-reader.port.d.ts +3 -0
  33. package/dist/domain/ports/logs/find/log-file-numerator.port.d.ts +3 -0
  34. package/dist/domain/ports/logs/index.d.ts +2 -0
  35. package/dist/domain/ports/logs/index.js +18 -0
  36. package/dist/domain/ports/logs/log-datasource.port.d.ts +10 -0
  37. package/dist/domain/ports/{clock.port.d.ts → system-clock.port.d.ts} +1 -1
  38. package/dist/domain/ports/system-clock.port.js +2 -0
  39. package/dist/domain/request/index.d.ts +2 -0
  40. package/dist/domain/request/index.js +18 -0
  41. package/dist/domain/request/log-filter.request.d.ts +9 -0
  42. package/dist/domain/request/log-filter.request.js +2 -0
  43. package/dist/domain/request/save-log.request.d.ts +7 -0
  44. package/dist/domain/request/save-log.request.js +2 -0
  45. package/dist/domain/response/index.d.ts +1 -0
  46. package/dist/{application/services → domain/response}/index.js +1 -1
  47. package/dist/domain/response/log.response.d.ts +8 -0
  48. package/dist/domain/response/log.response.js +2 -0
  49. package/dist/domain/types/fs-rotation-by.type.d.ts +8 -0
  50. package/dist/domain/types/fs-rotation-by.type.js +2 -0
  51. package/dist/domain/types/index.d.ts +1 -0
  52. package/dist/domain/types/index.js +17 -0
  53. package/dist/domain/value-objects/file-name-pattern.vo.d.ts +36 -0
  54. package/dist/domain/value-objects/file-name-pattern.vo.js +53 -0
  55. package/dist/domain/value-objects/file-path.vo.d.ts +73 -9
  56. package/dist/domain/value-objects/file-path.vo.js +54 -13
  57. package/dist/domain/value-objects/file-rotation-policy.vo.d.ts +51 -0
  58. package/dist/domain/value-objects/file-rotation-policy.vo.js +76 -0
  59. package/dist/domain/value-objects/file-size.vo.d.ts +61 -0
  60. package/dist/domain/value-objects/file-size.vo.js +57 -0
  61. package/dist/domain/value-objects/index.d.ts +3 -0
  62. package/dist/domain/value-objects/index.js +3 -0
  63. package/dist/domain/value-objects/log-level.vo.d.ts +8 -0
  64. package/dist/domain/value-objects/log-level.vo.js +13 -0
  65. package/dist/index.d.ts +3 -4
  66. package/dist/index.js +5 -11
  67. package/dist/infrastructure/adapters/file-rotator.adapter.d.ts +67 -8
  68. package/dist/infrastructure/adapters/file-rotator.adapter.js +133 -67
  69. package/dist/infrastructure/adapters/fileSystem-datasource.adapter.d.ts +26 -0
  70. package/dist/infrastructure/adapters/fileSystem-datasource.adapter.js +45 -0
  71. package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.d.ts +6 -0
  72. package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.js +54 -0
  73. package/dist/infrastructure/adapters/filesystem-log-file-line-reader.adapter.d.ts +4 -0
  74. package/dist/infrastructure/adapters/{fs-provider.adapter.js → filesystem-log-file-line-reader.adapter.js} +13 -37
  75. package/dist/infrastructure/adapters/filesystem-provider.adapter.d.ts +122 -0
  76. package/dist/infrastructure/adapters/filesystem-provider.adapter.js +182 -0
  77. package/dist/infrastructure/adapters/index.d.ts +7 -4
  78. package/dist/infrastructure/adapters/index.js +7 -4
  79. package/dist/infrastructure/adapters/log-stream-writer.adapter.d.ts +80 -0
  80. package/dist/infrastructure/adapters/log-stream-writer.adapter.js +163 -0
  81. package/dist/infrastructure/adapters/system-clock.adapter.d.ts +25 -0
  82. package/dist/infrastructure/adapters/system-clock.adapter.js +30 -0
  83. package/dist/infrastructure/adapters/system-file-path.adapter.d.ts +47 -0
  84. package/dist/infrastructure/adapters/system-file-path.adapter.js +141 -0
  85. package/dist/infrastructure/errors/file-operation.error.d.ts +28 -0
  86. package/dist/infrastructure/errors/file-operation.error.js +54 -0
  87. package/dist/infrastructure/errors/index.d.ts +1 -0
  88. package/dist/{shared → infrastructure}/errors/index.js +0 -2
  89. package/dist/infrastructure/errors/types/file-operation-error-options.type.d.ts +8 -0
  90. package/dist/infrastructure/errors/types/file-operation-error-options.type.js +2 -0
  91. package/dist/infrastructure/errors/types/file-operation.type.d.ts +1 -0
  92. package/dist/infrastructure/errors/types/file-operation.type.js +2 -0
  93. package/dist/infrastructure/errors/types/fs-error-scope.type.d.ts +1 -0
  94. package/dist/infrastructure/errors/types/fs-error-scope.type.js +2 -0
  95. package/dist/infrastructure/errors/types/index.d.ts +3 -0
  96. package/dist/infrastructure/errors/types/index.js +19 -0
  97. package/dist/infrastructure/filesystem/index.d.ts +0 -3
  98. package/dist/infrastructure/filesystem/index.js +0 -3
  99. package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.d.ts +2 -6
  100. package/dist/infrastructure/filesystem/types/filesystem-rotation.type.d.ts +2 -9
  101. package/dist/infrastructure/filesystem/types/index.d.ts +0 -1
  102. package/dist/infrastructure/filesystem/types/index.js +0 -1
  103. package/install.md +1 -1
  104. package/package.json +4 -6
  105. package/dist/application/dto/rotation-check.dto.d.ts +0 -5
  106. package/dist/application/dto/save-log.dto.d.ts +0 -4
  107. package/dist/application/dto/write-operation.dto.d.ts +0 -5
  108. package/dist/application/services/fs-datasource.service.d.ts +0 -11
  109. package/dist/application/services/fs-datasource.service.js +0 -19
  110. package/dist/application/services/index.d.ts +0 -1
  111. package/dist/domain/ports/file-path-adapter.port.d.ts +0 -33
  112. package/dist/domain/ports/stream-writer.port.d.ts +0 -42
  113. package/dist/infrastructure/adapters/fs-provider.adapter.d.ts +0 -17
  114. package/dist/infrastructure/adapters/fs-writer.adapter.d.ts +0 -13
  115. package/dist/infrastructure/adapters/fs-writer.adapter.js +0 -71
  116. package/dist/infrastructure/adapters/node-clock.adapter.d.ts +0 -4
  117. package/dist/infrastructure/adapters/node-clock.adapter.js +0 -9
  118. package/dist/infrastructure/adapters/node-file-path.adapter.d.ts +0 -16
  119. package/dist/infrastructure/adapters/node-file-path.adapter.js +0 -117
  120. package/dist/infrastructure/filesystem/polices/index.d.ts +0 -1
  121. package/dist/infrastructure/filesystem/polices/index.js +0 -5
  122. package/dist/infrastructure/filesystem/polices/rotation-policy.d.ts +0 -29
  123. package/dist/infrastructure/filesystem/polices/rotation-policy.js +0 -55
  124. package/dist/infrastructure/filesystem/ports/file-rotator.port.d.ts +0 -32
  125. package/dist/infrastructure/filesystem/types/filesystem-serializer.type.d.ts +0 -10
  126. package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.d.ts +0 -22
  127. package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.js +0 -37
  128. package/dist/infrastructure/filesystem/value-objects/index.d.ts +0 -1
  129. package/dist/shared/errors/file-operation.error.d.ts +0 -12
  130. package/dist/shared/errors/file-operation.error.js +0 -32
  131. package/dist/shared/errors/fs-plugin.error.d.ts +0 -4
  132. package/dist/shared/errors/fs-plugin.error.js +0 -11
  133. package/dist/shared/errors/index.d.ts +0 -3
  134. package/dist/shared/errors/rotation.error.d.ts +0 -10
  135. package/dist/shared/errors/rotation.error.js +0 -25
  136. /package/dist/application/dto/{rotation-check.dto.js → rotate-if-needed.request.js} +0 -0
  137. /package/dist/{application/dto/save-log.dto.js → domain/model/log-entry.model.js} +0 -0
  138. /package/dist/{application/dto/write-operation.dto.js → domain/ports/file/file-path.port.js} +0 -0
  139. /package/dist/{infrastructure/filesystem/ports → domain/ports/file}/file-rotator.port.js +0 -0
  140. /package/dist/domain/ports/{clock.port.js → file/log-stream-writer.port.js} +0 -0
  141. /package/dist/domain/ports/{file-path-adapter.port.js → filesystem-provider.port.js} +0 -0
  142. /package/dist/domain/ports/{fs-provider.port.js → logs/find/log-file-line-reader.port.js} +0 -0
  143. /package/dist/domain/ports/{stream-writer.port.js → logs/find/log-file-numerator.port.js} +0 -0
  144. /package/dist/{infrastructure/filesystem/types/filesystem-serializer.type.js → domain/ports/logs/log-datasource.port.js} +0 -0
package/dist/index.js CHANGED
@@ -1,18 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RotationPolicy = exports.FileNamePattern = exports.RotationError = exports.FileOperationError = exports.FsPluginError = exports.createFsDatasource = exports.FileSize = exports.FilePath = void 0;
3
+ exports.createFsDatasource = exports.FileNamePattern = exports.FileRotationPolicy = exports.FileSize = exports.FilePath = void 0;
4
4
  // Value Objects
5
5
  var value_objects_1 = require("./domain/value-objects");
6
6
  Object.defineProperty(exports, "FilePath", { enumerable: true, get: function () { return value_objects_1.FilePath; } });
7
7
  Object.defineProperty(exports, "FileSize", { enumerable: true, get: function () { return value_objects_1.FileSize; } });
8
+ Object.defineProperty(exports, "FileRotationPolicy", { enumerable: true, get: function () { return value_objects_1.FileRotationPolicy; } });
9
+ Object.defineProperty(exports, "FileNamePattern", { enumerable: true, get: function () { return value_objects_1.FileNamePattern; } });
8
10
  // Factory
9
- var factory_1 = require("./application/factory");
10
- Object.defineProperty(exports, "createFsDatasource", { enumerable: true, get: function () { return factory_1.createFsDatasource; } });
11
- // Errors
12
- var errors_1 = require("./shared/errors");
13
- Object.defineProperty(exports, "FsPluginError", { enumerable: true, get: function () { return errors_1.FsPluginError; } });
14
- Object.defineProperty(exports, "FileOperationError", { enumerable: true, get: function () { return errors_1.FileOperationError; } });
15
- Object.defineProperty(exports, "RotationError", { enumerable: true, get: function () { return errors_1.RotationError; } });
16
- var filesystem_1 = require("./infrastructure/filesystem");
17
- Object.defineProperty(exports, "FileNamePattern", { enumerable: true, get: function () { return filesystem_1.FileNamePattern; } });
18
- Object.defineProperty(exports, "RotationPolicy", { enumerable: true, get: function () { return filesystem_1.RotationPolicy; } });
11
+ var create_fs_datasource_factory_1 = require("./application/factory/create-fs-datasource.factory");
12
+ Object.defineProperty(exports, "createFsDatasource", { enumerable: true, get: function () { return create_fs_datasource_factory_1.createFsDatasource; } });
@@ -1,20 +1,79 @@
1
- import { IFsProviderPort, IFilePathAdapterPort } from "../../domain/ports";
2
- import { FileSize, FilePath } from "../../domain/value-objects";
3
- import { FileNamePattern, IFileRotatorPort, RotationPolicy } from "../filesystem";
1
+ import { IFileSystemProviderPort, IFilePathPort, IFileRotatorPort } from "../../domain/ports";
2
+ import { FileSize, FilePath, FileRotationPolicy, FileNamePattern } from "../../domain/value-objects";
3
+ /**
4
+ * Adapter de infraestructura que implementa IFileRotatorPort.
5
+ *
6
+ * Responsabilidad:
7
+ * - Calcular el path esperado del archivo de log en base a una fecha y un FileNamePattern.
8
+ * - Leer metadata real del filesystem (tamaño / listado de archivos).
9
+ * - Decidir si debe rotar (por día o por tamaño) apoyándose en la política del dominio.
10
+ *
11
+ * Nota:
12
+ * - Este adapter mantiene estado mínimo (`currentFilePath`) porque el Port lo requiere.
13
+ * Aun así, evitamos mutaciones ocultas: solo se actualiza desde getExpectedPathForDate().
14
+ */
4
15
  export declare class FileRotatorAdapter implements IFileRotatorPort {
5
16
  private readonly fsProvider;
6
17
  private readonly filePathAdapter;
7
18
  private readonly fileNamePattern;
8
19
  private readonly basePath;
9
20
  private currentFilePath;
10
- constructor(fsProvider: IFsProviderPort, filePathAdapter: IFilePathAdapterPort, fileNamePattern: FileNamePattern, basePath: string);
21
+ private readonly baseDir;
22
+ private static readonly TOKEN_REGEX;
23
+ constructor(fsProvider: IFileSystemProviderPort, filePathAdapter: IFilePathPort, fileNamePattern: FileNamePattern, basePath: string);
24
+ /**
25
+ * Devuelve el último archivo considerado “actual” por el rotator.
26
+ * Puede ser null si aún no se ha calculado/solicitado un path.
27
+ */
11
28
  getCurrentPath(): FilePath | null;
29
+ /**
30
+ * Calcula el path esperado para una fecha y lo “marca” como archivo actual.
31
+ * OJO: este es el único método que muta currentFilePath a propósito.
32
+ */
12
33
  getExpectedPathForDate(date: Date): FilePath;
13
- private buildPathForDate;
34
+ /**
35
+ * Calcula el FilePath esperado para una fecha usando el patrón.
36
+ * Método “puro”: NO muta estado.
37
+ */
38
+ private computePathForDate;
39
+ /**
40
+ * Reemplaza tokens de fecha dentro del patrón (ej. {yyyy}{MM}{dd}) por valores reales.
41
+ */
42
+ private applyDateTokens;
43
+ /**
44
+ * Obtiene el tamaño del archivo (stat) y lo devuelve como FileSize (VO).
45
+ *
46
+ * Decisión de diseño:
47
+ * - Si stat falla (archivo no existe, permisos, etc.), devolvemos tamaño 0.
48
+ * - Esto evita que el flujo de rotación “reviente” por un fallo de I/O puntual.
49
+ * - Si quieres hacer esto más estricto, aquí podrías lanzar un FileOperationError("read"/"stat", ...).
50
+ */
14
51
  getFileSize(filePath: FilePath): Promise<FileSize>;
15
- getFileSizeBytes(path: string): Promise<number>;
16
- getNextRotationIndex(baseFilePath: FilePath): Promise<number>;
17
- shouldRotate(policy: RotationPolicy, currentDate: Date): Promise<boolean>;
52
+ /**
53
+ * Decide si debe rotar basándose en la política del dominio y el estado actual.
54
+ *
55
+ * Nota:
56
+ * - Para rotación por día: comparamos el path actual vs el esperado para la fecha actual.
57
+ * - Para rotación por tamaño: consultamos el tamaño real y delegamos la regla al VO.
58
+ */
59
+ shouldRotate(policy: FileRotationPolicy, currentDate: Date): Promise<boolean>;
60
+ /**
61
+ * Rotación por día:
62
+ * - Si no hay currentFilePath, se considera que “debe rotar/crear” para inicializar.
63
+ * - Si el nombre esperado para la fecha actual difiere del actual, debe rotar.
64
+ *
65
+ * Importante:
66
+ * - Este método NO muta currentFilePath (solo calcula).
67
+ */
18
68
  private shouldRotateByDay;
69
+ /**
70
+ * Rotación por tamaño:
71
+ * - Si no hay currentFilePath, no rotamos (no hay “archivo actual” que evaluar).
72
+ * - Si no hay maxSize en la policy, no rotamos.
73
+ * - Si se puede medir tamaño, delegamos al VO para la regla (>= maxSize).
74
+ */
19
75
  private shouldRotateBySize;
20
76
  }
77
+ /**
78
+ * Escapa caracteres especiales para construir RegExp seguro desde strings (basename/ext).
79
+ */
@@ -2,38 +2,103 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FileRotatorAdapter = void 0;
4
4
  const value_objects_1 = require("../../domain/value-objects");
5
+ /**
6
+ * Adapter de infraestructura que implementa IFileRotatorPort.
7
+ *
8
+ * Responsabilidad:
9
+ * - Calcular el path esperado del archivo de log en base a una fecha y un FileNamePattern.
10
+ * - Leer metadata real del filesystem (tamaño / listado de archivos).
11
+ * - Decidir si debe rotar (por día o por tamaño) apoyándose en la política del dominio.
12
+ *
13
+ * Nota:
14
+ * - Este adapter mantiene estado mínimo (`currentFilePath`) porque el Port lo requiere.
15
+ * Aun así, evitamos mutaciones ocultas: solo se actualiza desde getExpectedPathForDate().
16
+ */
5
17
  class FileRotatorAdapter {
6
- constructor(fsProvider, filePathAdapter, fileNamePattern, basePath) {
18
+ constructor(
19
+ // Port de FS (stat, readdir, etc.)
20
+ fsProvider,
21
+ // Port de paths (normalización, join, resolve, etc.)
22
+ filePathAdapter,
23
+ // VO de dominio: patrón de nombre
24
+ fileNamePattern,
25
+ // Config cruda (normalmente string proveniente de env/config)
26
+ basePath) {
7
27
  this.fsProvider = fsProvider;
8
28
  this.filePathAdapter = filePathAdapter;
9
29
  this.fileNamePattern = fileNamePattern;
10
30
  this.basePath = basePath;
31
+ // Estado mínimo: “archivo actual” según el último cálculo/uso.
11
32
  this.currentFilePath = null;
33
+ // Resolver y normalizar basePath una sola vez.
34
+ this.baseDir = this.filePathAdapter.fromRaw(this.basePath);
12
35
  }
36
+ /**
37
+ * Devuelve el último archivo considerado “actual” por el rotator.
38
+ * Puede ser null si aún no se ha calculado/solicitado un path.
39
+ */
13
40
  getCurrentPath() {
14
41
  return this.currentFilePath;
15
42
  }
43
+ /**
44
+ * Calcula el path esperado para una fecha y lo “marca” como archivo actual.
45
+ * OJO: este es el único método que muta currentFilePath a propósito.
46
+ */
16
47
  getExpectedPathForDate(date) {
17
- const fullFilePath = this.buildPathForDate(date);
18
- this.currentFilePath = fullFilePath;
19
- return fullFilePath;
48
+ const expected = this.computePathForDate(date);
49
+ this.currentFilePath = expected;
50
+ return expected;
20
51
  }
21
- buildPathForDate(date) {
22
- const pattern = this.fileNamePattern.pattern;
23
- const replacements = {
24
- "{yyyy}": date.getFullYear().toString(),
25
- "{MM}": (date.getMonth() + 1).toString().padStart(2, "0"),
26
- "{dd}": date.getDate().toString().padStart(2, "0"),
27
- "{HH}": date.getHours().toString().padStart(2, "0"),
28
- "{mm}": date.getMinutes().toString().padStart(2, "0"),
29
- "{ss}": date.getSeconds().toString().padStart(2, "0"),
30
- };
31
- let fileName = pattern;
32
- for (const [token, value] of Object.entries(replacements)) {
33
- fileName = fileName.replace(new RegExp(token.replace(/[{}]/g, "\\$&"), "g"), value);
34
- }
35
- return this.filePathAdapter.join(this.filePathAdapter.fromRaw(this.basePath), fileName);
52
+ /**
53
+ * Calcula el FilePath esperado para una fecha usando el patrón.
54
+ * Método “puro”: NO muta estado.
55
+ */
56
+ computePathForDate(date) {
57
+ // 1) Aplicar reemplazo de tokens al patrón -> obtenemos el nombre del archivo.
58
+ const fileName = this.applyDateTokens(this.fileNamePattern.pattern, date);
59
+ // 2) Unir baseDir + fileName (sin re-resolver basePath en cada llamada).
60
+ return this.filePathAdapter.join(this.baseDir, fileName);
61
+ }
62
+ /**
63
+ * Reemplaza tokens de fecha dentro del patrón (ej. {yyyy}{MM}{dd}) por valores reales.
64
+ */
65
+ applyDateTokens(pattern, date) {
66
+ // Normalizamos valores una sola vez.
67
+ const yyyy = date.getFullYear().toString();
68
+ const MM = String(date.getMonth() + 1).padStart(2, "0");
69
+ const dd = String(date.getDate()).padStart(2, "0");
70
+ const HH = String(date.getHours()).padStart(2, "0");
71
+ const mm = String(date.getMinutes()).padStart(2, "0");
72
+ const ss = String(date.getSeconds()).padStart(2, "0");
73
+ // Reemplazamos usando regex global; más simple y eficiente que loop + new RegExp por token.
74
+ return pattern.replace(FileRotatorAdapter.TOKEN_REGEX, (_m, token) => {
75
+ switch (token) {
76
+ case "yyyy":
77
+ return yyyy;
78
+ case "MM":
79
+ return MM;
80
+ case "dd":
81
+ return dd;
82
+ case "HH":
83
+ return HH;
84
+ case "mm":
85
+ return mm;
86
+ case "ss":
87
+ return ss;
88
+ default:
89
+ // Defensive: no debería ocurrir por la regex.
90
+ return _m;
91
+ }
92
+ });
36
93
  }
94
+ /**
95
+ * Obtiene el tamaño del archivo (stat) y lo devuelve como FileSize (VO).
96
+ *
97
+ * Decisión de diseño:
98
+ * - Si stat falla (archivo no existe, permisos, etc.), devolvemos tamaño 0.
99
+ * - Esto evita que el flujo de rotación “reviente” por un fallo de I/O puntual.
100
+ * - Si quieres hacer esto más estricto, aquí podrías lanzar un FileOperationError("read"/"stat", ...).
101
+ */
37
102
  async getFileSize(filePath) {
38
103
  try {
39
104
  const stats = await this.fsProvider.stat(filePath.absolutePath);
@@ -43,63 +108,64 @@ class FileRotatorAdapter {
43
108
  return new value_objects_1.FileSize(0);
44
109
  }
45
110
  }
46
- // Método de compatibilidad - deprecado, usar getFileSize
47
- async getFileSizeBytes(path) {
48
- const filePath = this.filePathAdapter.fromRaw(path);
49
- const fileSize = await this.getFileSize(filePath);
50
- return fileSize.bytes;
51
- }
52
- async getNextRotationIndex(baseFilePath) {
53
- try {
54
- const files = await this.fsProvider.readdir(baseFilePath.directory);
55
- const pattern = new RegExp(`^${baseFilePath.basename}\\.(\\d+)${baseFilePath.extension.replace(".", "\\.")}$`);
56
- let maxIndex = 0;
57
- for (const file of files) {
58
- const match = file.match(pattern);
59
- if (match) {
60
- const index = parseInt(match[1], 10);
61
- if (index > maxIndex) {
62
- maxIndex = index;
63
- }
64
- }
65
- }
66
- return maxIndex + 1;
67
- }
68
- catch {
69
- return 1;
70
- }
71
- }
111
+ // ---------------------------------------------------------------------------
112
+ // Decisión de rotación
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * Decide si debe rotar basándose en la política del dominio y el estado actual.
116
+ *
117
+ * Nota:
118
+ * - Para rotación por día: comparamos el path actual vs el esperado para la fecha actual.
119
+ * - Para rotación por tamaño: consultamos el tamaño real y delegamos la regla al VO.
120
+ */
72
121
  async shouldRotate(policy, currentDate) {
73
- if (policy.by === "none") {
74
- return false;
75
- }
76
- if (policy.by === "day") {
77
- return this.shouldRotateByDay(currentDate);
78
- }
79
- if (policy.by === "size") {
80
- return this.shouldRotateBySize(policy);
122
+ switch (policy.by) {
123
+ case "none":
124
+ return false;
125
+ case "day":
126
+ return this.shouldRotateByDay(currentDate);
127
+ case "size":
128
+ return this.shouldRotateBySize(policy);
129
+ default:
130
+ // Defensive: si el tipo llegara corrupto por casting/JS.
131
+ return false;
81
132
  }
82
- return false;
83
133
  }
134
+ /**
135
+ * Rotación por día:
136
+ * - Si no hay currentFilePath, se considera que “debe rotar/crear” para inicializar.
137
+ * - Si el nombre esperado para la fecha actual difiere del actual, debe rotar.
138
+ *
139
+ * Importante:
140
+ * - Este método NO muta currentFilePath (solo calcula).
141
+ */
84
142
  shouldRotateByDay(currentDate) {
85
- if (!this.currentFilePath) {
86
- return true; // No hay archivo actual, necesitamos crear uno
87
- }
88
- // Ahora solo calculamos, NO mutamos currentFilePath
89
- const expectedPath = this.buildPathForDate(currentDate);
143
+ if (!this.currentFilePath)
144
+ return true;
145
+ const expectedPath = this.computePathForDate(currentDate);
90
146
  return !this.currentFilePath.equals(expectedPath);
91
147
  }
148
+ /**
149
+ * Rotación por tamaño:
150
+ * - Si no hay currentFilePath, no rotamos (no hay “archivo actual” que evaluar).
151
+ * - Si no hay maxSize en la policy, no rotamos.
152
+ * - Si se puede medir tamaño, delegamos al VO para la regla (>= maxSize).
153
+ */
92
154
  async shouldRotateBySize(policy) {
93
- if (!this.currentFilePath || !policy.maxSize) {
155
+ if (!this.currentFilePath)
94
156
  return false;
95
- }
96
- try {
97
- const currentFileSize = await this.getFileSize(this.currentFilePath);
98
- return policy.shouldRotateBySize(currentFileSize);
99
- }
100
- catch {
157
+ if (!policy.maxSize)
101
158
  return false;
102
- }
159
+ const currentFileSize = await this.getFileSize(this.currentFilePath);
160
+ return policy.shouldRotateBySize(currentFileSize);
103
161
  }
104
162
  }
105
163
  exports.FileRotatorAdapter = FileRotatorAdapter;
164
+ // Regex precalculada para encontrar tokens del tipo {yyyy}, {MM}, etc.
165
+ FileRotatorAdapter.TOKEN_REGEX = /\{(yyyy|MM|dd|HH|mm|ss)\}/g;
166
+ /**
167
+ * Escapa caracteres especiales para construir RegExp seguro desde strings (basename/ext).
168
+ */
169
+ // function escapeRegExp(input: string): string {
170
+ // return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
171
+ // }
@@ -0,0 +1,26 @@
1
+ import type { ILogDatasource, LogEntry as CoreLogEntry, LogSearchRequest, LogRecord } from "@jmlq/logger";
2
+ import type { FindLogsUseCase, IPersistLogUseCase } from "../../application/use-cases";
3
+ import type { ILogStreamWriterPort } from "../../domain/ports";
4
+ export declare class FsDatasourceAdapter implements ILogDatasource {
5
+ private readonly persistLogUseCase;
6
+ private readonly streamWriterPort;
7
+ private readonly findLogsUseCase?;
8
+ readonly name = "fs";
9
+ constructor(persistLogUseCase: IPersistLogUseCase, streamWriterPort: ILogStreamWriterPort, findLogsUseCase?: FindLogsUseCase | undefined);
10
+ /**
11
+ * Firma EXACTA requerida por @jmlq/logger:
12
+ * save(log: LogEntry): Promise<void>
13
+ */
14
+ save(log: CoreLogEntry): Promise<void>;
15
+ /**
16
+ * Firma típica de @jmlq/logger (si existe en tu interface):
17
+ * find?(filter?: LogFilterRequest): Promise<ILogResponse[]>
18
+ *
19
+ * Por ahora, dejamos una implementación mínima coherente:
20
+ * - Si aún no soportas lectura, devuelve [] (o lanza un error explícito).
21
+ * - Te recomiendo implementar find en serio (tail/list+parse) como acordamos.
22
+ */
23
+ find?(filter?: LogSearchRequest): Promise<LogRecord[]>;
24
+ flush(): Promise<void>;
25
+ dispose(): Promise<void>;
26
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FsDatasourceAdapter = void 0;
4
+ class FsDatasourceAdapter {
5
+ constructor(persistLogUseCase, streamWriterPort, findLogsUseCase) {
6
+ this.persistLogUseCase = persistLogUseCase;
7
+ this.streamWriterPort = streamWriterPort;
8
+ this.findLogsUseCase = findLogsUseCase;
9
+ this.name = "fs";
10
+ }
11
+ /**
12
+ * Firma EXACTA requerida por @jmlq/logger:
13
+ * save(log: LogEntry): Promise<void>
14
+ */
15
+ async save(log) {
16
+ const dto = {
17
+ log,
18
+ };
19
+ await this.persistLogUseCase.execute(dto);
20
+ }
21
+ /**
22
+ * Firma típica de @jmlq/logger (si existe en tu interface):
23
+ * find?(filter?: LogFilterRequest): Promise<ILogResponse[]>
24
+ *
25
+ * Por ahora, dejamos una implementación mínima coherente:
26
+ * - Si aún no soportas lectura, devuelve [] (o lanza un error explícito).
27
+ * - Te recomiendo implementar find en serio (tail/list+parse) como acordamos.
28
+ */
29
+ async find(filter) {
30
+ if (!this.findLogsUseCase)
31
+ return [];
32
+ // mapeo 1:1 (misma estructura)
33
+ const internalFilter = filter;
34
+ const internal = (await this.findLogsUseCase.execute(internalFilter));
35
+ // mapeo 1:1
36
+ return internal;
37
+ }
38
+ async flush() {
39
+ await this.streamWriterPort.flush();
40
+ }
41
+ async dispose() {
42
+ await this.streamWriterPort.close();
43
+ }
44
+ }
45
+ exports.FsDatasourceAdapter = FsDatasourceAdapter;
@@ -0,0 +1,6 @@
1
+ import { ILogFileEnumeratorPort } from "../../domain/ports";
2
+ export declare class FileSystemLogFileEnumeratorAdapter implements ILogFileEnumeratorPort {
3
+ private readonly basePath;
4
+ constructor(basePath: string);
5
+ listLogFiles(): Promise<string[]>;
6
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FileSystemLogFileEnumeratorAdapter = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ class FileSystemLogFileEnumeratorAdapter {
40
+ constructor(basePath) {
41
+ this.basePath = basePath;
42
+ }
43
+ async listLogFiles() {
44
+ const entries = await fs.promises.readdir(this.basePath, {
45
+ withFileTypes: true,
46
+ });
47
+ return (entries
48
+ .filter((e) => e.isFile() && e.name.endsWith(".log"))
49
+ .map((e) => path.join(this.basePath, e.name))
50
+ // opcional: ordenar por nombre para estabilidad
51
+ .sort());
52
+ }
53
+ }
54
+ exports.FileSystemLogFileEnumeratorAdapter = FileSystemLogFileEnumeratorAdapter;
@@ -0,0 +1,4 @@
1
+ import { ILogFileLineReaderPort } from "../../domain/ports";
2
+ export declare class FileSystemLogFileLineReaderAdapter implements ILogFileLineReaderPort {
3
+ readLines(filePath: string): AsyncIterable<string>;
4
+ }
@@ -33,45 +33,21 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.FsProviderAdapter = void 0;
37
- const fs = __importStar(require("fs/promises"));
38
- class FsProviderAdapter {
39
- async exists(path) {
36
+ exports.FileSystemLogFileLineReaderAdapter = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const readline = __importStar(require("readline"));
39
+ class FileSystemLogFileLineReaderAdapter {
40
+ async *readLines(filePath) {
41
+ const stream = fs.createReadStream(filePath, { encoding: "utf8" });
42
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
40
43
  try {
41
- await fs.access(path);
42
- return true;
44
+ for await (const line of rl)
45
+ yield line;
43
46
  }
44
- catch {
45
- return false;
47
+ finally {
48
+ rl.close();
49
+ stream.close();
46
50
  }
47
51
  }
48
- async mkdir(path, options) {
49
- await fs.mkdir(path, options);
50
- }
51
- async readFile(path) {
52
- return fs.readFile(path);
53
- }
54
- async writeFile(path, data) {
55
- await fs.writeFile(path, data);
56
- }
57
- async appendFile(path, data) {
58
- await fs.appendFile(path, data);
59
- }
60
- async stat(path) {
61
- const stats = await fs.stat(path);
62
- return {
63
- size: stats.size,
64
- mtime: stats.mtime,
65
- };
66
- }
67
- async readdir(path) {
68
- return fs.readdir(path);
69
- }
70
- async unlink(path) {
71
- await fs.unlink(path);
72
- }
73
- async rename(oldPath, newPath) {
74
- await fs.rename(oldPath, newPath);
75
- }
76
52
  }
77
- exports.FsProviderAdapter = FsProviderAdapter;
53
+ exports.FileSystemLogFileLineReaderAdapter = FileSystemLogFileLineReaderAdapter;