@jmlq/logger-plugin-fs 0.1.0-alpha.6 → 0.1.0-alpha.7

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 (120) hide show
  1. package/README.md +165 -117
  2. package/architecture.md +426 -0
  3. package/dist/application/dto/index.d.ts +2 -0
  4. package/dist/application/dto/index.js +2 -0
  5. package/dist/application/dto/rotation-check.dto.d.ts +5 -0
  6. package/dist/application/dto/save-log.dto.d.ts +3 -3
  7. package/dist/application/dto/write-operation.dto.d.ts +5 -0
  8. package/dist/application/factory/create-fs-datasource.factory.d.ts +3 -0
  9. package/dist/application/factory/create-fs-datasource.factory.js +26 -0
  10. package/dist/application/factory/index.d.ts +1 -0
  11. package/dist/{presentation → application}/factory/index.js +1 -1
  12. package/dist/application/services/fs-datasource.service.d.ts +7 -5
  13. package/dist/application/services/fs-datasource.service.js +6 -9
  14. package/dist/application/use-cases/append-log.use-case.d.ts +12 -0
  15. package/dist/application/use-cases/append-log.use-case.js +26 -0
  16. package/dist/application/use-cases/ensure-directory.use-case.d.ts +11 -0
  17. package/dist/application/use-cases/ensure-directory.use-case.js +27 -0
  18. package/dist/application/use-cases/index.d.ts +4 -3
  19. package/dist/application/use-cases/index.js +4 -3
  20. package/dist/application/use-cases/persist-log.use-case.d.ts +19 -0
  21. package/dist/application/use-cases/persist-log.use-case.js +47 -0
  22. package/dist/application/use-cases/rotate-if-needed.use-case.d.ts +17 -0
  23. package/dist/application/use-cases/rotate-if-needed.use-case.js +28 -0
  24. package/dist/domain/ports/clock.port.d.ts +8 -0
  25. package/dist/domain/ports/file-path-adapter.port.d.ts +33 -0
  26. package/dist/domain/ports/fs-provider.port.d.ts +61 -0
  27. package/dist/domain/ports/fs-provider.port.js +2 -0
  28. package/dist/domain/ports/index.d.ts +4 -0
  29. package/dist/domain/{contracts → ports}/index.js +3 -3
  30. package/dist/domain/ports/stream-writer.port.d.ts +42 -0
  31. package/dist/domain/ports/stream-writer.port.js +2 -0
  32. package/dist/domain/value-objects/file-path.vo.d.ts +27 -0
  33. package/dist/domain/value-objects/file-path.vo.js +59 -0
  34. package/dist/domain/value-objects/file-size.vo.d.ts +14 -0
  35. package/dist/domain/value-objects/file-size.vo.js +57 -0
  36. package/dist/domain/value-objects/index.d.ts +2 -2
  37. package/dist/domain/value-objects/index.js +2 -2
  38. package/dist/index.d.ts +4 -3
  39. package/dist/index.js +14 -5
  40. package/dist/infrastructure/adapters/file-rotator.adapter.d.ts +20 -0
  41. package/dist/infrastructure/adapters/file-rotator.adapter.js +105 -0
  42. package/dist/infrastructure/adapters/fs-provider.adapter.d.ts +17 -0
  43. package/dist/infrastructure/{fs/fs-provider.js → adapters/fs-provider.adapter.js} +41 -19
  44. package/dist/infrastructure/adapters/fs-writer.adapter.d.ts +13 -0
  45. package/dist/infrastructure/adapters/fs-writer.adapter.js +71 -0
  46. package/dist/infrastructure/{fs → adapters}/index.d.ts +2 -2
  47. package/dist/infrastructure/{fs → adapters}/index.js +2 -2
  48. package/dist/infrastructure/adapters/node-clock.adapter.d.ts +4 -0
  49. package/dist/infrastructure/{fs → adapters}/node-clock.adapter.js +0 -1
  50. package/dist/infrastructure/adapters/node-file-path.adapter.d.ts +16 -0
  51. package/dist/infrastructure/adapters/node-file-path.adapter.js +117 -0
  52. package/dist/infrastructure/filesystem/index.d.ts +4 -0
  53. package/dist/infrastructure/filesystem/index.js +20 -0
  54. package/dist/infrastructure/filesystem/polices/index.d.ts +1 -0
  55. package/dist/infrastructure/filesystem/polices/index.js +5 -0
  56. package/dist/infrastructure/filesystem/polices/rotation-policy.d.ts +29 -0
  57. package/dist/infrastructure/filesystem/polices/rotation-policy.js +55 -0
  58. package/dist/infrastructure/filesystem/ports/file-rotator.port.d.ts +32 -0
  59. package/dist/infrastructure/filesystem/ports/file-rotator.port.js +2 -0
  60. package/dist/infrastructure/filesystem/ports/index.d.ts +1 -0
  61. package/dist/{domain/types → infrastructure/filesystem/ports}/index.js +1 -1
  62. package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.d.ts +49 -0
  63. package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.js +2 -0
  64. package/dist/infrastructure/filesystem/types/filesystem-rotation.type.d.ts +19 -0
  65. package/dist/infrastructure/filesystem/types/filesystem-rotation.type.js +2 -0
  66. package/dist/infrastructure/filesystem/types/filesystem-serializer.type.d.ts +10 -0
  67. package/dist/infrastructure/filesystem/types/filesystem-serializer.type.js +2 -0
  68. package/dist/infrastructure/filesystem/types/index.d.ts +3 -0
  69. package/dist/infrastructure/filesystem/types/index.js +19 -0
  70. package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.d.ts +22 -0
  71. package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.js +37 -0
  72. package/dist/infrastructure/filesystem/value-objects/index.d.ts +1 -0
  73. package/dist/infrastructure/{datasources → filesystem/value-objects}/index.js +1 -1
  74. package/dist/shared/errors/file-operation.error.d.ts +12 -0
  75. package/dist/shared/errors/file-operation.error.js +32 -0
  76. package/dist/shared/errors/fs-plugin.error.d.ts +4 -0
  77. package/dist/shared/errors/fs-plugin.error.js +11 -0
  78. package/dist/shared/errors/index.d.ts +3 -0
  79. package/dist/shared/errors/index.js +19 -0
  80. package/dist/shared/errors/rotation.error.d.ts +10 -0
  81. package/dist/shared/errors/rotation.error.js +25 -0
  82. package/install.md +520 -0
  83. package/package.json +39 -22
  84. package/LICENSE +0 -21
  85. package/dist/application/use-cases/append-log.usecase.d.ts +0 -7
  86. package/dist/application/use-cases/append-log.usecase.js +0 -19
  87. package/dist/application/use-cases/persist-log.usecase.d.ts +0 -23
  88. package/dist/application/use-cases/persist-log.usecase.js +0 -74
  89. package/dist/application/use-cases/rotate-if-needed.usecase.d.ts +0 -10
  90. package/dist/application/use-cases/rotate-if-needed.usecase.js +0 -39
  91. package/dist/domain/contracts/clock.contract.d.ts +0 -3
  92. package/dist/domain/contracts/file-rotator.contract.d.ts +0 -7
  93. package/dist/domain/contracts/index.d.ts +0 -4
  94. package/dist/domain/contracts/serializer.contract.d.ts +0 -3
  95. package/dist/domain/contracts/stream-writer.port.d.ts +0 -6
  96. package/dist/domain/types/index.d.ts +0 -1
  97. package/dist/domain/types/options.type.d.ts +0 -11
  98. package/dist/domain/types/options.type.js +0 -5
  99. package/dist/domain/value-objects/file-name-pattern.vo.d.ts +0 -4
  100. package/dist/domain/value-objects/file-name-pattern.vo.js +0 -14
  101. package/dist/domain/value-objects/rotation-policy.vo.d.ts +0 -7
  102. package/dist/domain/value-objects/rotation-policy.vo.js +0 -20
  103. package/dist/infrastructure/datasources/fs.datasource.d.ts +0 -17
  104. package/dist/infrastructure/datasources/fs.datasource.js +0 -84
  105. package/dist/infrastructure/datasources/index.d.ts +0 -1
  106. package/dist/infrastructure/fs/file-rotator.adapter.d.ts +0 -22
  107. package/dist/infrastructure/fs/file-rotator.adapter.js +0 -51
  108. package/dist/infrastructure/fs/fs-provider.d.ts +0 -15
  109. package/dist/infrastructure/fs/fs-writer.adapter.d.ts +0 -10
  110. package/dist/infrastructure/fs/fs-writer.adapter.js +0 -26
  111. package/dist/infrastructure/fs/node-clock.adapter.d.ts +0 -4
  112. package/dist/infrastructure/fs/path-utils.d.ts +0 -6
  113. package/dist/infrastructure/fs/path-utils.js +0 -26
  114. package/dist/presentation/factory/create-fs-datasource.d.ts +0 -15
  115. package/dist/presentation/factory/create-fs-datasource.js +0 -39
  116. package/dist/presentation/factory/index.d.ts +0 -1
  117. /package/dist/{domain/contracts/clock.contract.js → application/dto/rotation-check.dto.js} +0 -0
  118. /package/dist/{domain/contracts/file-rotator.contract.js → application/dto/write-operation.dto.js} +0 -0
  119. /package/dist/domain/{contracts/serializer.contract.js → ports/clock.port.js} +0 -0
  120. /package/dist/domain/{contracts/stream-writer.port.js → ports/file-path-adapter.port.js} +0 -0
@@ -33,23 +33,45 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.createFsProvider = createFsProvider;
37
- // Provider de fs compatible (tipos derivados para evitar errores por versión).
38
- const fs = __importStar(require("fs"));
39
- const fsp = __importStar(require("fs/promises"));
40
- function createFsProvider() {
41
- return {
42
- createWriteStream: (p, opts) => fs.createWriteStream(p, opts),
43
- mkdirSync: (p, opts) => fs.mkdirSync(p, { recursive: true, ...(opts ?? {}) }),
44
- exists: async (p) => await new Promise((r) => fs.access(p, (e) => r(!e))),
45
- statSafe: async (p) => {
46
- try {
47
- const s = await fsp.stat(p);
48
- return { size: s.size };
49
- }
50
- catch {
51
- return null;
52
- }
53
- },
54
- };
36
+ exports.FsProviderAdapter = void 0;
37
+ const fs = __importStar(require("fs/promises"));
38
+ class FsProviderAdapter {
39
+ async exists(path) {
40
+ try {
41
+ await fs.access(path);
42
+ return true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
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
+ }
55
76
  }
77
+ exports.FsProviderAdapter = FsProviderAdapter;
@@ -0,0 +1,13 @@
1
+ import { IStreamWriterPort } from "../../domain/ports";
2
+ import { FilePath } from "../../domain/value-objects";
3
+ export declare class FsWriterAdapter implements IStreamWriterPort {
4
+ private stream;
5
+ private currentPath;
6
+ write(data: string): Promise<boolean>;
7
+ open(path: FilePath): Promise<void>;
8
+ close(): Promise<void>;
9
+ end(): Promise<void>;
10
+ flush(): Promise<void>;
11
+ isOpen(): boolean;
12
+ getCurrentPath(): FilePath | null;
13
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FsWriterAdapter = void 0;
4
+ const fs_1 = require("fs");
5
+ const errors_1 = require("../../shared/errors");
6
+ class FsWriterAdapter {
7
+ constructor() {
8
+ this.stream = null;
9
+ this.currentPath = null;
10
+ }
11
+ async write(data) {
12
+ if (!this.stream) {
13
+ throw new errors_1.FsPluginError("Stream not opened");
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ const success = this.stream.write(data);
17
+ if (!success) {
18
+ this.stream.once("drain", () => resolve(true));
19
+ this.stream.once("error", reject);
20
+ }
21
+ else {
22
+ resolve(true);
23
+ }
24
+ });
25
+ }
26
+ async open(path) {
27
+ if (this.stream) {
28
+ await this.close();
29
+ }
30
+ const pathString = path.absolutePath;
31
+ this.stream = (0, fs_1.createWriteStream)(pathString, { flags: "a" });
32
+ this.currentPath = path;
33
+ return new Promise((resolve, reject) => {
34
+ this.stream.once("open", () => resolve());
35
+ this.stream.once("error", reject);
36
+ });
37
+ }
38
+ async close() {
39
+ if (!this.stream)
40
+ return;
41
+ return new Promise((resolve) => {
42
+ this.stream.end(() => {
43
+ this.stream = null;
44
+ this.currentPath = null;
45
+ resolve();
46
+ });
47
+ });
48
+ }
49
+ async end() {
50
+ return this.close();
51
+ }
52
+ async flush() {
53
+ if (!this.stream)
54
+ return;
55
+ return new Promise((resolve) => {
56
+ if (this.stream.writableNeedDrain) {
57
+ this.stream.once("drain", () => resolve());
58
+ }
59
+ else {
60
+ resolve();
61
+ }
62
+ });
63
+ }
64
+ isOpen() {
65
+ return this.stream !== null;
66
+ }
67
+ getCurrentPath() {
68
+ return this.currentPath;
69
+ }
70
+ }
71
+ exports.FsWriterAdapter = FsWriterAdapter;
@@ -1,5 +1,5 @@
1
1
  export * from "./file-rotator.adapter";
2
+ export * from "./fs-provider.adapter";
2
3
  export * from "./fs-writer.adapter";
3
- export * from "./fs-provider";
4
- export * from "./path-utils";
5
4
  export * from "./node-clock.adapter";
5
+ export * from "./node-file-path.adapter";
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./file-rotator.adapter"), exports);
18
+ __exportStar(require("./fs-provider.adapter"), exports);
18
19
  __exportStar(require("./fs-writer.adapter"), exports);
19
- __exportStar(require("./fs-provider"), exports);
20
- __exportStar(require("./path-utils"), exports);
21
20
  __exportStar(require("./node-clock.adapter"), exports);
21
+ __exportStar(require("./node-file-path.adapter"), exports);
@@ -0,0 +1,4 @@
1
+ import { IClockPort } from "../../domain/ports";
2
+ export declare class NodeClockAdapter implements IClockPort {
3
+ now(): Date;
4
+ }
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // Reloj real del sistema.
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.NodeClockAdapter = void 0;
5
4
  class NodeClockAdapter {
@@ -0,0 +1,16 @@
1
+ import { FilePath } from "../../domain/value-objects/file-path.vo";
2
+ import { IFilePathAdapterPort } from "../../domain/ports/file-path-adapter.port";
3
+ /**
4
+ * Adapter concreto basado en Node.js (`path`) que construye y transforma FilePath.
5
+ * Es infraestructura pura que implementa el port de dominio.
6
+ */
7
+ export declare class NodeFilePathAdapter implements IFilePathAdapterPort {
8
+ fromRaw(inputPath: string): FilePath;
9
+ fromBasename(directory: string, basename: string, extension: string): FilePath;
10
+ withExtension(filePath: FilePath, newExtension: string): FilePath;
11
+ withBasename(filePath: FilePath, newBasename: string): FilePath;
12
+ join(filePath: FilePath, ...segments: string[]): FilePath;
13
+ resolve(filePath: FilePath, ...segments: string[]): FilePath;
14
+ relativeTo(basePath: string, filePath: FilePath): string;
15
+ private buildFromAbsolute;
16
+ }
@@ -0,0 +1,117 @@
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.NodeFilePathAdapter = void 0;
37
+ const path = __importStar(require("path"));
38
+ const file_path_vo_1 = require("../../domain/value-objects/file-path.vo");
39
+ /**
40
+ * Adapter concreto basado en Node.js (`path`) que construye y transforma FilePath.
41
+ * Es infraestructura pura que implementa el port de dominio.
42
+ */
43
+ class NodeFilePathAdapter {
44
+ fromRaw(inputPath) {
45
+ if (!inputPath || typeof inputPath !== "string") {
46
+ throw new Error("NodeFilePathAdapter.fromRaw: inputPath must be a non-empty string");
47
+ }
48
+ const trimmed = inputPath.trim();
49
+ if (!trimmed) {
50
+ throw new Error("NodeFilePathAdapter.fromRaw: inputPath cannot be empty or whitespace");
51
+ }
52
+ const absolutePath = path.resolve(trimmed);
53
+ return this.buildFromAbsolute(absolutePath);
54
+ }
55
+ fromBasename(directory, basename, extension) {
56
+ if (!directory || !basename) {
57
+ throw new Error("NodeFilePathAdapter.fromBasename: directory and basename are required");
58
+ }
59
+ const ext = extension
60
+ ? extension.startsWith(".")
61
+ ? extension
62
+ : `.${extension}`
63
+ : "";
64
+ const fullPath = path.join(directory, basename + ext);
65
+ const absolutePath = path.resolve(fullPath);
66
+ return this.buildFromAbsolute(absolutePath);
67
+ }
68
+ withExtension(filePath, newExtension) {
69
+ const ext = newExtension.startsWith(".")
70
+ ? newExtension
71
+ : `.${newExtension}`;
72
+ const filename = filePath.basename + ext;
73
+ const absolutePath = path.join(filePath.directory, filename);
74
+ return this.buildFromAbsolute(absolutePath);
75
+ }
76
+ withBasename(filePath, newBasename) {
77
+ if (!newBasename || !newBasename.trim()) {
78
+ throw new Error("NodeFilePathAdapter.withBasename: newBasename must be a non-empty string");
79
+ }
80
+ const filename = newBasename + filePath.extension;
81
+ const absolutePath = path.join(filePath.directory, filename);
82
+ return this.buildFromAbsolute(absolutePath);
83
+ }
84
+ join(filePath, ...segments) {
85
+ const absolutePath = path.join(filePath.absolutePath, ...segments);
86
+ return this.buildFromAbsolute(absolutePath);
87
+ }
88
+ resolve(filePath, ...segments) {
89
+ const absolutePath = path.resolve(filePath.absolutePath, ...segments);
90
+ return this.buildFromAbsolute(absolutePath);
91
+ }
92
+ relativeTo(basePath, filePath) {
93
+ if (!basePath || !basePath.trim()) {
94
+ throw new Error("NodeFilePathAdapter.relativeTo: basePath must be a non-empty string");
95
+ }
96
+ return path.relative(path.resolve(basePath.trim()), filePath.absolutePath);
97
+ }
98
+ // ────────────────────────────────────────────
99
+ // Helper privado: construye IFilePathProps
100
+ // ────────────────────────────────────────────
101
+ buildFromAbsolute(absolutePath) {
102
+ const normalized = path.resolve(absolutePath);
103
+ const directory = path.dirname(normalized);
104
+ const filename = path.basename(normalized);
105
+ const extension = path.extname(normalized);
106
+ const basename = path.basename(normalized, extension);
107
+ const props = {
108
+ absolutePath: normalized,
109
+ directory,
110
+ filename,
111
+ extension,
112
+ basename,
113
+ };
114
+ return new file_path_vo_1.FilePath(props);
115
+ }
116
+ }
117
+ exports.NodeFilePathAdapter = NodeFilePathAdapter;
@@ -0,0 +1,4 @@
1
+ export * from "./polices";
2
+ export * from "./types";
3
+ export * from "./value-objects";
4
+ export * from "./ports";
@@ -0,0 +1,20 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./polices"), exports);
18
+ __exportStar(require("./types"), exports);
19
+ __exportStar(require("./value-objects"), exports);
20
+ __exportStar(require("./ports"), exports);
@@ -0,0 +1 @@
1
+ export { RotationPolicy } from "./rotation-policy";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RotationPolicy = void 0;
4
+ var rotation_policy_1 = require("./rotation-policy");
5
+ Object.defineProperty(exports, "RotationPolicy", { enumerable: true, get: function () { return rotation_policy_1.RotationPolicy; } });
@@ -0,0 +1,29 @@
1
+ import { FsRotationBy } from "..";
2
+ import { FileSize } from "../../../domain/value-objects/file-size.vo";
3
+ /**
4
+ * Es un Value Object de dominio que encapsula la política de rotación de logs
5
+ * by: cómo se rota → "none" | "day" | "size".
6
+ * maxSizeMB: umbral de tamaño (solo tiene sentido para "size").
7
+ * maxFiles: cuántos archivos rotados se mantienen (concepto típico en rotation).
8
+ */
9
+ export declare class RotationPolicy {
10
+ private readonly _by;
11
+ private readonly _maxSize?;
12
+ private readonly _maxFiles?;
13
+ constructor(by: FsRotationBy, maxSizeMB?: number, maxFiles?: number);
14
+ get by(): FsRotationBy;
15
+ get maxSizeMB(): number | undefined;
16
+ get maxSize(): FileSize | undefined;
17
+ get maxFiles(): number | undefined;
18
+ /**
19
+ * Lógica de negocio mejorada usando FileSize value object
20
+ * @param currentSize Tamaño actual del archivo como FileSize
21
+ * @returns true si debe rotar por tamaño
22
+ */
23
+ shouldRotateBySize(currentSize: FileSize): boolean;
24
+ /**
25
+ * Método de compatibilidad para tamaños en bytes
26
+ * Usar shouldRotateBySize(FileSize) en su lugar
27
+ */
28
+ shouldRotateBySizeBytes(currentSizeBytes: number): boolean;
29
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RotationPolicy = void 0;
4
+ const file_size_vo_1 = require("../../../domain/value-objects/file-size.vo");
5
+ /**
6
+ * Es un Value Object de dominio que encapsula la política de rotación de logs
7
+ * by: cómo se rota → "none" | "day" | "size".
8
+ * maxSizeMB: umbral de tamaño (solo tiene sentido para "size").
9
+ * maxFiles: cuántos archivos rotados se mantienen (concepto típico en rotation).
10
+ */
11
+ class RotationPolicy {
12
+ constructor(by, maxSizeMB, maxFiles) {
13
+ if (!["none", "day", "size"].includes(by)) {
14
+ throw new Error("RotationPolicy: invalid rotation strategy");
15
+ }
16
+ if (by === "size" && (maxSizeMB == null || maxSizeMB <= 0)) {
17
+ throw new Error("RotationPolicy: maxSizeMB must be positive for size rotation");
18
+ }
19
+ this._by = by;
20
+ this._maxSize = maxSizeMB ? file_size_vo_1.FileSize.fromMegabytes(maxSizeMB) : undefined;
21
+ this._maxFiles = maxFiles;
22
+ }
23
+ get by() {
24
+ return this._by;
25
+ }
26
+ get maxSizeMB() {
27
+ return this._maxSize?.megabytes;
28
+ }
29
+ get maxSize() {
30
+ return this._maxSize;
31
+ }
32
+ get maxFiles() {
33
+ return this._maxFiles;
34
+ }
35
+ /**
36
+ * Lógica de negocio mejorada usando FileSize value object
37
+ * @param currentSize Tamaño actual del archivo como FileSize
38
+ * @returns true si debe rotar por tamaño
39
+ */
40
+ shouldRotateBySize(currentSize) {
41
+ if (this._by !== "size" || !this._maxSize) {
42
+ return false;
43
+ }
44
+ return (currentSize.isGreaterThan(this._maxSize) ||
45
+ currentSize.equals(this._maxSize));
46
+ }
47
+ /**
48
+ * Método de compatibilidad para tamaños en bytes
49
+ * Usar shouldRotateBySize(FileSize) en su lugar
50
+ */
51
+ shouldRotateBySizeBytes(currentSizeBytes) {
52
+ return this.shouldRotateBySize(new file_size_vo_1.FileSize(currentSizeBytes));
53
+ }
54
+ }
55
+ exports.RotationPolicy = RotationPolicy;
@@ -0,0 +1,32 @@
1
+ import { FileSize, FilePath } from "../../../domain/value-objects";
2
+ import { RotationPolicy } from "../polices";
3
+ /**
4
+ * "Puente" entre dominio y filesystem
5
+ */
6
+ export interface IFileRotatorPort {
7
+ /**
8
+ * Saber qué archivo de log está activo ahora
9
+ */
10
+ getCurrentPath(): FilePath | null;
11
+ /**
12
+ * Calcular cómo se va a llamar el archivo según una fecha
13
+ * @param date Fecha para la que se quiere el path
14
+ */
15
+ getExpectedPathForDate(date: Date): FilePath;
16
+ /**
17
+ * Consultar metadata del archivo usando FileSize value object
18
+ * @param filePath Ruta del archivo como FilePath
19
+ */
20
+ getFileSize(filePath: FilePath): Promise<FileSize>;
21
+ /**
22
+ * Saber qué índice usar para el siguiente archivo rotado
23
+ * @param baseFilePath Ruta base del archivo como FilePath
24
+ */
25
+ getNextRotationIndex(baseFilePath: FilePath): Promise<number>;
26
+ /**
27
+ * Decidir si corresponde rotar de acuerdo a una RotationPolicy y la fecha actual
28
+ * @param policy Política de rotación
29
+ * @param currentDate Fecha actual
30
+ */
31
+ shouldRotate(policy: RotationPolicy, currentDate: Date): Promise<boolean>;
32
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export * from "./file-rotator.port";
@@ -14,4 +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("./options.type"), exports);
17
+ __exportStar(require("./file-rotator.port"), exports);
@@ -0,0 +1,49 @@
1
+ import { IFileRotationConfig, IFsSerializer } from "..";
2
+ import { FilePath } from "../../../domain/value-objects";
3
+ /**
4
+ * Opciones de configuración para la fuente de datos del sistema de archivos.
5
+ * Es el objeto de configuración para un datasource de logs basado en filesystem
6
+ */
7
+ export interface IFilesystemDatasourceOptions {
8
+ /**
9
+ * Directorio base donde se van a crear/leer los archivos de log.
10
+ */
11
+ basePath: string;
12
+ /**
13
+ * Indica si se deben crear los directorios padres si no existen
14
+ * Si es true, la implementación puede crear el basePath (con fs.mkdir({ recursive: true })) si no existe.
15
+ * Si es false o undefined, o no lo crea o depende de tu implementación.
16
+ */
17
+ mkdir?: boolean;
18
+ /**
19
+ * Patrón de nombre del archivo de log
20
+ */
21
+ fileNamePattern?: string;
22
+ /**
23
+ * Conecta con la política de rotación: "none" | "day" | "size", tamaño máximo, número de archivos, etc
24
+ */
25
+ rotation?: IFileRotationConfig;
26
+ /**
27
+ * Estrategia para serializar el log a string / buffer antes de escribir: JSON, texto plano, custom, etc
28
+ */
29
+ serializer?: IFsSerializer;
30
+ /**
31
+ * Hook que se dispara cuando se rota un archivo de log. Útil para:
32
+ * - Notificar a otro sistema.
33
+ * - Enviar el archivo rotado a S3.
34
+ * - Hacer limpieza adicional.
35
+ * @param oldPath Ruta del archivo de log antes de la rotación
36
+ * @param newPath Ruta del archivo de log después de la rotación
37
+ * @returns
38
+ */
39
+ onRotate?: (oldPath: FilePath, newPath: FilePath) => void | Promise<void>;
40
+ /**
41
+ * Hook centralizado para manejar errores del datasource:
42
+ * - Loggear en otro canal.
43
+ * - Enviar métricas / alertas.
44
+ * - Evitar que el logger “reviente” la app.
45
+ * @param error Error ocurrido en el datasource
46
+ * @returns
47
+ */
48
+ onError?: (error: Error) => void | Promise<void>;
49
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Es un tipo discriminado que define cómo se realizará la rotación de logs dentro del sistema.
3
+ * Los valores significan:
4
+ * "none" → Sin rotación. El archivo crece indefinidamente.
5
+ * "day" → Rotación diaria (por fecha).
6
+ * "size" → Rotación por tamaño (normalmente basado en maxSizeMB).
7
+ */
8
+ export type FsRotationBy = "none" | "day" | "size";
9
+ /**
10
+ * Representa la configuración que el sistema de log debe seguir para decidir cuándo rotar archivos.
11
+ * by: Estrategia principal de rotación: "none", "day", "size".
12
+ * maxSizeMB: Tamaño máximo del archivo antes de rotar (solo aplica si by === "size").
13
+ * maxFiles: Cuántos archivos rotados se mantienen. Ejemplo: si maxFiles = 5, se mantienen:
14
+ */
15
+ export interface IFileRotationConfig {
16
+ by: FsRotationBy;
17
+ maxSizeMB?: number;
18
+ maxFiles?: number;
19
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Es una estrategia de serialización usada por el datasource de filesystem para convertir cualquier entrada (entry: unknown) en una cadena (string) antes de escribirla en el archivo.
3
+ */
4
+ export interface IFsSerializer {
5
+ /**
6
+ * Serializa una entrada genérica a string
7
+ * @param entry Entrada a serializar
8
+ */
9
+ serialize(entry: unknown): string;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ export * from "./filesystem-datasource-options.type";
2
+ export * from "./filesystem-rotation.type";
3
+ export * from "./filesystem-serializer.type";
@@ -0,0 +1,19 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./filesystem-datasource-options.type"), exports);
18
+ __exportStar(require("./filesystem-rotation.type"), exports);
19
+ __exportStar(require("./filesystem-serializer.type"), exports);
@@ -0,0 +1,22 @@
1
+ /**
2
+ * representa el patrón de nombrado de archivos de log
3
+ */
4
+ export declare class FileNamePattern {
5
+ private readonly _pattern;
6
+ constructor(pattern: string);
7
+ /**
8
+ * Retorna el valor inmutable
9
+ */
10
+ get pattern(): string;
11
+ /**
12
+ * Indica si el patrón contiene tokens de fecha
13
+ * Útil para detectar si el nombre del archivo depende de fecha
14
+ * @returns true si el patrón contiene tokens de fecha, false en caso contrario
15
+ */
16
+ hasDateTokens(): boolean;
17
+ /**
18
+ * Devuelve todos los tokens encerrados en llaves presentes en el patrón
19
+ * @returns Array de tokens encontrados en el patrón
20
+ */
21
+ getTokens(): string[];
22
+ }