@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
package/README.md CHANGED
@@ -1,174 +1,222 @@
1
1
  # @jmlq/logger-plugin-fs
2
2
 
3
- Datasource de `sistema de archivos` para [`@jmlq/logger`](https://www.npmjs.com/package/@jmlq/logger).
4
- Escribe cada evento de log como **línea** (JSONL por defecto) y soporta `rotación por día` o por `tamaño`, manejo de `backpressure/drain`, `flush()` y `dispose()`.
5
-
6
- ---
3
+ Plugin de **sistema de archivos** para [`@jmlq/logger`](https://www.npmjs.com/package/@jmlq/logger). Permite persistir logs en archivos con soporte para rotación automática, manejo de backpressure y configuración flexible de formato y estructura de archivos.
7
4
 
8
5
  ## 📦 Instalación
9
6
 
10
7
  ```bash
11
- # Con npm
12
- npm i @jmlq/logger @jmlq/logger-plugin-fs
13
-
14
- ```
15
-
16
- Este plugin **depende** de [`@jmlq/logger`](https://www.npmjs.com/package/@jmlq/logger). Asegúrate de instalar ambos paquetes.
17
-
18
- ---
19
-
20
- ## 🧩 Configuración
21
-
22
- ### 🔐 Variables de Entorno (.env)
23
-
24
- ```ini
25
- # Ruta base (carpeta) para los archivos de log
26
- LOGGER_FS_PATH=./logs
27
-
28
- # Patrón (opcional). Si omites, usa "app-{yyyy}{MM}{dd}.log"
29
- LOGGER_FS_PATTERN=app-{yyyy}{MM}{dd}.log
30
-
31
- # Rotación: "day" | "size" | "none"
32
- LOGGER_FS_ROTATION=day
33
- LOGGER_FS_MAX_SIZE_MB=50
34
-
35
- # Logger core
36
- LOGGER_LEVEL=info # trace|debug|info|warn|error|fatal
37
-
8
+ npm install @jmlq/logger @jmlq/logger-plugin-fs
38
9
  ```
39
10
 
40
- ---
11
+ > **Nota:** Este plugin requiere [`@jmlq/logger`](https://www.npmjs.com/package/@jmlq/logger) como dependencia principal.
41
12
 
42
- ### 🚀 Uso del paquete
13
+ ## 🚀 Uso rápido
43
14
 
44
- ```tsx
45
- import { createLogger, LogLevel } from "@jmlq/logger";
15
+ ```typescript
16
+ import { LoggerFactory } from "@jmlq/logger";
46
17
  import { createFsDatasource } from "@jmlq/logger-plugin-fs";
47
18
 
48
- const ds = createFsDatasource({
49
- basePath: "./logs", // Carpeta destino
50
- mkdir: true, // Crea carpeta si no existe
51
- fileNamePattern: "app-{yyyy}{MM}{dd}.log", // Rotación diaria por fecha (UTC)
52
- // Alternativa por tamaño:
53
- // rotation: { by: "size", maxSizeMB: 50 }
19
+ // Crear datasource de filesystem
20
+ const fsDatasource = createFsDatasource({
21
+ basePath: "./logs",
22
+ fileNamePattern: "app-{yyyy}{MM}{dd}.log",
54
23
  rotation: { by: "day" },
55
- // Serializador opcional (por defecto JSON.stringify)
56
- // serializer: { serialize: (log) => formatMyLine(log) },
57
- onRotate: (oldP, newP) => console.log("[fs] rotated:", oldP, "->", newP),
58
- onError: (e) => console.error("[fs] error:", e),
59
24
  });
60
25
 
61
- const logger = createLogger(ds, { minLevel: LogLevel.INFO });
26
+ // Crear logger usando la factory
27
+ const logger = LoggerFactory.create([fsDatasource]);
62
28
 
63
- logger.info("Servidor iniciado", { pid: process.pid });
29
+ // Usar el logger
30
+ logger.info("Aplicación iniciada", { timestamp: new Date(), pid: process.pid });
31
+ logger.error("Error de conexión", { service: "database", retries: 3 });
64
32
 
65
33
  // Cierre elegante
66
34
  process.on("SIGTERM", async () => {
67
- await logger.flush?.();
68
- await logger.dispose?.();
35
+ await logger.flush();
36
+ await logger.dispose();
69
37
  process.exit(0);
70
38
  });
71
39
  ```
72
40
 
73
- También:
41
+ ## ⚙️ Configuración del datasource
74
42
 
75
- ```ts
76
- import { createLogger, LogLevel } from "@jmlq/logger";
77
- import {
78
- createFsDatasource,
79
- RotationPolicy,
80
- FileNamePattern,
81
- } from "@jmlq/logger-plugin-fs";
43
+ El datasource de filesystem acepta las siguientes opciones de configuración:
82
44
 
83
- // Validación/invariantes tempranas con VO (throws si es inválido)
84
- const pt = new FileNamePattern("app-{yyyy}{MM}{dd}.log");
85
- const rt = new RotationPolicy("size", 50 /* maxSizeMB */);
45
+ ### Opciones principales
86
46
 
87
- const ds = createFsDatasource({
88
- basePath: "./logs",
89
- mkdir: true,
90
- // La factory acepta primitives; usamos los VO arriba solo para validar/centrar la decisión
91
- fileNamePattern: pt.pattern,
92
- rotation: { by: rt.by, maxSizeMB: rotation.maxSizeMB },
93
- });
47
+ | Opción | Tipo | Descripción | Por defecto |
48
+ | ----------------- | ---------------- | ------------------------------------------------------ | --------------------------- |
49
+ | `basePath` | `string` | Directorio base donde se guardarán los archivos de log | `"./logs"` |
50
+ | `fileNamePattern` | `string` | Patrón para nombrar archivos con tokens de fecha | `"app-{yyyy}{MM}{dd}.log"` |
51
+ | `rotation` | `RotationConfig` | Configuración de política de rotación | `{ by: "day" }` |
52
+ | `mkdir` | `boolean` | Crear directorio base si no existe | `true` |
53
+ | `serializer` | `LogSerializer` | Serializador personalizado para el formato de líneas | Serializer JSON por defecto |
54
+
55
+ ### Configuración de rotación
94
56
 
95
- const logger = createLogger(ds, { minLevel: LogLevel.INFO });
57
+ ```typescript
58
+ interface RotationConfig {
59
+ by: "none" | "day" | "size";
60
+ maxSizeMB?: number; // Para rotación por tamaño
61
+ maxFiles?: number; // Límite de archivos rotados
62
+ }
96
63
  ```
97
64
 
98
- #### ⚙️ Opciones soportadas
65
+ ### Patrones de nombre de archivo
99
66
 
100
- > - `basePath: string` carpeta donde se guardan los logs.
101
- > - `mkdir?: boolean` – crea la carpeta si no existe.
102
- > - `fileNamePattern?: string` – tokens {yyyy}{MM}{dd} (formateados en UTC).
103
- > > - Ejemplos: `"app-{yyyy}{MM}{dd}.log"`, `"service.log"`.
104
- > - `rotation?: { by: "none" | "day" | "size"; maxSizeMB?: number; maxFiles?: number }`
105
- > > - `day` → rota al cambiar la fecha (UTC).
106
- > > - `size` → rota al alcanzar `maxSizeMB` (genera app.1.log, app.2.log, …).
107
- > - `serializer?: { serialize(entry: unknown): string }` – una línea sin `\n`.
108
- > - `onRotate?: (oldPath, newPath) => void | Promise<void>`
109
- > - `onError?: (err) => void | Promise<void>`
67
+ Utiliza tokens que se reemplazan con valores de fecha (UTC):
110
68
 
111
- ---
69
+ - `{yyyy}` - Año completo (ej: 2024)
70
+ - `{MM}` - Mes con ceros (ej: 01, 12)
71
+ - `{dd}` - Día con ceros (ej: 01, 31)
112
72
 
113
- ### 🗂️ Formato de archivo
73
+ **Ejemplos:**
114
74
 
115
- > - **Una línea por evento** (JSONL por defecto).
116
- > - El `serializer` determina el formato de cada línea (sin salto).
117
- > - El plugin agrega `"\n"` y maneja `backpressure`/`drain` del stream.
75
+ - `"app-{yyyy}{MM}{dd}.log"` `app-20241201.log`
76
+ - `"service-{yyyy}-{MM}-{dd}.log"` `service-2024-12-01.log`
77
+ - `"application.log"` `application.log` (sin rotación por fecha)
118
78
 
119
- ---
79
+ ## 🔁 Políticas de rotación
120
80
 
121
- ### 🔁 Rotación
81
+ ### Rotación por fecha
122
82
 
123
- **Por día **(`rotation: { by: "day" }`)
83
+ Crea un archivo nuevo cada día basado en fecha UTC:
124
84
 
125
- > - El archivo activo se calcula con `fileNamePattern` usando la `fecha UTC actual`.
126
- > - Si al persistir cambia el día → `cierra` el stream anterior, abre uno nuevo y dispara `onRotate(old, new)`.
85
+ ```typescript
86
+ import { createFsDatasource } from "@jmlq/logger-plugin-fs";
127
87
 
128
- **Por tamaño** (`rotation: { by: "size", maxSizeMB }`)
88
+ const datasource = createFsDatasource({
89
+ basePath: "./logs",
90
+ fileNamePattern: "app-{yyyy}{MM}{dd}.log",
91
+ rotation: { by: "day" },
92
+ onRotate: (oldPath, newPath) => {
93
+ console.log(
94
+ `Log rotado: ${oldPath.absolutePath} → ${newPath.absolutePath}`
95
+ );
96
+ },
97
+ });
98
+ ```
129
99
 
130
- > - Comprueba el tamaño del archivo activo. Si `>= maxSizeMB` → rota a `app.1.log`, `app.2.log`, … (buscando el siguiente índice libre).
100
+ ### Rotación por tamaño
131
101
 
132
- ---
102
+ Rota cuando el archivo alcanza el tamaño máximo especificado:
133
103
 
134
- ### 🧯 Backpressure & drain (cómo evita perder logs)
104
+ ```typescript
105
+ const datasource = createFsDatasource({
106
+ basePath: "./logs",
107
+ fileNamePattern: "app.log",
108
+ rotation: {
109
+ by: "size",
110
+ maxSizeMB: 50, // Rota al alcanzar 50MB
111
+ maxFiles: 10, // Mantiene máximo 10 archivos rotados
112
+ },
113
+ onRotate: (oldPath, newPath) => {
114
+ console.log(
115
+ `Archivo rotado por tamaño: ${oldPath.absolutePath} → ${newPath.absolutePath}`
116
+ );
117
+ },
118
+ });
119
+ ```
135
120
 
136
- Node.js devuelve `false` en `stream.write()` cuando el **buffer interno está lleno** (backpressure).
137
- El plugin:
121
+ ### Sin rotación
138
122
 
139
- 1. Serializa el log + `"\n"`.
140
- 2. Llama `write(...)`.
141
- 3. Si devuelve `false`, **espera el evento** `drain` antes de continuar.
142
- 4. `flush()` espera a que se libere el buffer si `writableNeedDrain` es `true`.
143
- 5. `dispose()` cierra el stream actual drenando el buffer pendiente.
123
+ Mantiene un único archivo que crece indefinidamente:
144
124
 
145
- ---
125
+ ```typescript
126
+ const datasource = createFsDatasource({
127
+ basePath: "./logs",
128
+ fileNamePattern: "application.log",
129
+ rotation: { by: "none" },
130
+ });
131
+ ```
146
132
 
147
- ### 🌐 Zona horaria
133
+ ## 🧩 Ejemplo completo
148
134
 
149
- > - El formateo `{yyyy}{MM}{dd}` del patrón se realiza en **UTC** para evitar desfases por huso horario (máquinas/CI distintas).
150
- > - Si necesitas otro criterio (p.ej., “día de Guayaquil”), puedes:
151
- > > - Ajustar el **IClock** para proveer el “ahora” en otro huso y/o
152
- > > - Reemplazar el util de formateo si deseas `{…}` en local time.
135
+ ```typescript
136
+ import { createFsDatasource } from "@jmlq/logger-plugin-fs";
137
+ import { LogLevel } from "@jmlq/logger";
153
138
 
154
- ---
139
+ const datasource = createFsDatasource({
140
+ basePath: "./logs",
141
+ fileNamePattern: "app-{yyyy}-{MM}-{dd}.log",
142
+ rotation: { by: "day" },
143
+ mkdir: true,
144
+ serializer: {
145
+ serialize(log: any) {
146
+ return JSON.stringify(log, null, 2);
147
+ },
148
+ },
149
+ onRotate: (oldPath, newPath) => {
150
+ console.log(`Rotación: ${oldPath.absolutePath} → ${newPath.absolutePath}`);
151
+ },
152
+ onError: (err) => {
153
+ console.error("Error en datasource:", err.message);
154
+ },
155
+ });
155
156
 
156
- ## FAQ
157
+ // Guardar logs
158
+ await datasource.save({
159
+ level: LogLevel.INFO,
160
+ message: "Servidor iniciado correctamente",
161
+ timestamp: Date.now(),
162
+ });
157
163
 
158
- **¿Puedo usar mi propio serializador?**
159
- Sí. Pasa serializer: { serialize: (log) => "mi-línea" }. Debe devolver una sola línea sin `\n`.
164
+ await datasource.save({
165
+ level: LogLevel.DEBUG,
166
+ message: "Conectando a base de datos...",
167
+ timestamp: Date.now(),
168
+ });
160
169
 
161
- **¿Qué pasa si el proceso se detiene en medio de un write?**
162
- Usamos los mecanismos de `Writable` (buffer + `drain`) y exponemos `flush()`/`dispose()` para el cierre. Llama a ambos en shutdown.
170
+ // Cierre
171
+ await datasource.flush();
172
+ await datasource.dispose();
173
+ ```
163
174
 
164
- **¿Puedo rotar por hora?**
165
- No out-of-the-box. Puedes implementar un **FileNamePattern** por hora (ej. `app-{yyyy}{MM}{dd}-{HH}.log`) + un `RotateIfNeededUseCase` extendido.
175
+ ## 🧪 Testing
166
176
 
167
- ---
177
+ ```typescript
178
+ import { createFsDatasource } from "@jmlq/logger-plugin-fs";
179
+ import * as fs from "fs";
180
+ import * as path from "path";
181
+
182
+ describe("FileSystem Datasource", () => {
183
+ const testLogsPath = "./test-logs";
184
+
185
+ beforeEach(() => {
186
+ if (fs.existsSync(testLogsPath)) {
187
+ fs.rmSync(testLogsPath, { recursive: true });
188
+ }
189
+ });
190
+
191
+ test("debe crear archivo de log", async () => {
192
+ const datasource = createFsDatasource({
193
+ basePath: testLogsPath,
194
+ fileNamePattern: "test.log",
195
+ rotation: { by: "none" },
196
+ });
197
+
198
+ await datasource.save({
199
+ level: "info",
200
+ message: "Test message",
201
+ timestamp: new Date(),
202
+ });
203
+
204
+ await datasource.flush();
205
+
206
+ const logFile = path.join(testLogsPath, "test.log");
207
+ expect(fs.existsSync(logFile)).toBe(true);
208
+
209
+ const content = fs.readFileSync(logFile, "utf8");
210
+ expect(content).toContain("Test message");
211
+ });
212
+ });
213
+ ```
168
214
 
169
- #### [LEER MAS...](./ARQUITECTURA.md)
215
+ ## 📄 Más Información
170
216
 
171
- ---
217
+ - **[Arquitectura Detallada](./architecture.md)** - Documentación técnica completa
218
+ - **[Guía de Instalación](./install.md)** - Configuración paso a paso
219
+ - **[Ejemplos](./examples/)** - Códigos de ejemplo funcionales
172
220
 
173
221
  ## 📄 Licencia
174
222