@jmlq/logger 0.1.0-alpha.3 → 0.1.0-alpha.5

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 (50) hide show
  1. package/README.md +40 -40
  2. package/dist/application/use-cases/flush-buffers.d.ts +6 -0
  3. package/dist/application/use-cases/flush-buffers.js +13 -0
  4. package/dist/application/use-cases/get-logs.d.ts +7 -0
  5. package/dist/application/use-cases/get-logs.js +24 -0
  6. package/dist/application/use-cases/index.d.ts +3 -0
  7. package/dist/application/use-cases/index.js +19 -0
  8. package/dist/application/use-cases/save-log.d.ts +13 -0
  9. package/dist/application/use-cases/save-log.js +30 -0
  10. package/dist/domain/contracts/index.d.ts +3 -0
  11. package/dist/domain/contracts/index.js +19 -0
  12. package/dist/domain/contracts/log.datasource.d.ts +8 -0
  13. package/dist/{config/interfaces/index.js → domain/contracts/log.datasource.js} +0 -1
  14. package/dist/domain/contracts/logger.d.ts +19 -0
  15. package/dist/domain/contracts/logger.js +2 -0
  16. package/dist/domain/contracts/pii.d.ts +5 -0
  17. package/dist/domain/contracts/pii.js +2 -0
  18. package/dist/domain/services/pii-redactor.d.ts +7 -24
  19. package/dist/domain/services/pii-redactor.js +55 -117
  20. package/dist/domain/types/index.d.ts +1 -0
  21. package/dist/{presentation → domain/types}/index.js +1 -1
  22. package/dist/domain/types/log.types.d.ts +28 -0
  23. package/dist/domain/types/log.types.js +2 -0
  24. package/dist/domain/value-objects/index.d.ts +1 -0
  25. package/dist/domain/{index.js → value-objects/index.js} +1 -1
  26. package/dist/domain/value-objects/log-level.d.ts +9 -0
  27. package/dist/domain/value-objects/log-level.js +37 -0
  28. package/dist/index.d.ts +5 -4
  29. package/dist/index.js +8 -18
  30. package/dist/infrastructure/adapters/composite.datasource.d.ts +11 -0
  31. package/dist/infrastructure/adapters/composite.datasource.js +46 -0
  32. package/dist/infrastructure/adapters/index.d.ts +1 -0
  33. package/dist/{config → infrastructure/adapters}/index.js +1 -2
  34. package/dist/presentation/factory/create-logger.d.ts +2 -0
  35. package/dist/presentation/factory/create-logger.js +29 -0
  36. package/dist/presentation/factory/index.d.ts +1 -2
  37. package/dist/presentation/factory/index.js +15 -72
  38. package/package.json +14 -2
  39. package/dist/Composite/index.d.ts +0 -9
  40. package/dist/Composite/index.js +0 -54
  41. package/dist/Factory/index.d.ts +0 -5
  42. package/dist/Factory/index.js +0 -23
  43. package/dist/config/index.d.ts +0 -2
  44. package/dist/config/interfaces/index.d.ts +0 -67
  45. package/dist/config/types/index.d.ts +0 -10
  46. package/dist/config/types/index.js +0 -13
  47. package/dist/domain/index.d.ts +0 -1
  48. package/dist/interfaces/index.d.ts +0 -35
  49. package/dist/interfaces/index.js +0 -13
  50. package/dist/presentation/index.d.ts +0 -1
package/README.md CHANGED
@@ -14,7 +14,15 @@ npm i @jmlq/logger
14
14
  # Instalar plugins opcionales según el backend de persistencia
15
15
  npm i @jmlq/logger-plugin-fs
16
16
  npm i @jmlq/logger-plugin-mongo
17
- npm i @jmlq/logger-plugin-postgres
17
+ npm i @jmlq/logger-plugin-postgresql
18
+
19
+ ```
20
+
21
+ Si usas Mongo o Postgres en tu app cliente, instala además:
22
+
23
+ ```bash
24
+ npm i mongodb@^6.19.0
25
+ npm i pg@^8.16.3
18
26
 
19
27
  ```
20
28
 
@@ -22,39 +30,44 @@ npm i @jmlq/logger-plugin-postgres
22
30
 
23
31
  > - [`@jmlq/logger-plugin-fs`](https://www.npmjs.com/package/@jmlq/logger-plugin-fs)
24
32
  > - [`@jmlq/logger-plugin-mongo`](https://www.npmjs.com/package/@jmlq/logger-plugin-mongo)
25
- > - [`@jmlq/logger-plugin-postgres`](https://www.npmjs.com/package/@jmlq/logger-plugin-postgres)
33
+ > - [`@jmlq/logger-plugin-postgresql`](https://www.npmjs.com/package/@jmlq/logger-plugin-postgresql)
26
34
 
27
35
  ---
28
36
 
29
37
  ## 🧱 Estructura del paquete
30
38
 
31
- ```txt
32
- src/
33
- composite/
34
- index.ts # Implementa CompositeDatasource para fan-out de logs a múltiples destinos
35
- config/
36
- interfaces/
37
- index.ts # Define contratos/puertos (ILogDatasource, ILogRepository)
38
- types/
39
- index.ts # Tipos y utilidades comunes (filtros de logs, opciones de logger, etc.)
40
- domain/
41
- services/
42
- index.ts # Servicio PiiRedactor: enmascara datos sensibles
43
- presentation/
44
- factory/
45
- index.ts # Factory createLogger: construye la API final del logger
46
- index.ts # Punto de entrada que re-exporta contratos, utilidades y createLogger
39
+ ### 📝 Resumen rápido
47
40
 
48
- ```
41
+ > - **`src/domain/`** — Reglas del negocio (sin dependencias de frameworks).
42
+ > > - **`value-objects/`**
43
+ > > > - `log-level.ts` — Define niveles (`TRACE…FATAL`) y `toLogLevel()` para convertir strings a nivel.
44
+ > > - **`types/`**
45
+ > > > - `log.types.ts` — Tipos puros del dominio: `ILog`, `IGetLogsFilter`, `PiiOptions`, etc.
46
+ > > - **`contracts/`**
47
+ > > > - `log.datasource.ts` — Puerto que debe implementar cualquier destino de logs (`save/find/flush/dispose`).
48
+ > > > - `logger.ts` — Contrato del logger público (`ILogger`, `ICreateLoggerOptions`).
49
+ > > > - `pii.ts` — Contrato del redactor de PII.
50
+ > > - **`services/`**
51
+ > > > - `pii-redactor.ts` — Enmascarado de datos sensibles (whitelist/blacklist, patrones, modo profundo).
52
+
53
+ > - **`src/application/`** — Orquestación de casos de uso (no depende de infraestructura).
54
+ > > - **`use-cases/`**
55
+ > > > - `save-log.ts` — Aplica `minLevel` + PII y delega a `datasource.save()`.
56
+ > > > - `get-logs.ts` — Recupera logs con filtros/paginación si el datasource lo soporta.
57
+ > > > - `flush-buffers.ts` — Ejecuta `flush()` en el datasource cuando exista.
58
+
59
+ > - **`src/infrastructure/`** — Adaptadores concretos (tecnología).
60
+ > > - **`adapters/`**
61
+ > > > - `composite.datasource.ts` — Fan-out: envía el log a varios datasources y no falla el todo si uno cae (avisa con `console.warn`).
49
62
 
50
- ## 📝 Resumen rápido
63
+ > - **`src/presentation/`** — API pública y fábricas (cara del paquete).
64
+ > > - **`factory/`**
65
+ > > > - `create-logger.ts` — Crea el logger listo para usar (`trace…fatal`, `flush`, `dispose`) conectando casos de uso + PII.
51
66
 
52
- > - **composite** Combinación de múltiples datasources para persistir en paralelo.
53
- > - **config/interfaces** Contratos base (ILogDatasource) que los plugins deben implementar.
54
- > - **config/types** → Tipos auxiliares (`LogLevel`, `GetLogsFilter`, etc.).
55
- > - **domain/services** → Lógica de dominio (PII redaction).
56
- > - **presentation/factory** → `createLogger`, expone la API (`trace`, `debug`, `info`, `warn`, `error`, `fatal`).
57
- > - **index.ts** → Punto de entrada limpio para el consumidor.
67
+ > - **`src/index.ts`** Barrel.
68
+ > > - Re-exporta lo público: `createLogger`, `LogLevel`, tipos/contratos y `CompositeDatasource`.
69
+
70
+ ### [LEER MAS](./ARQUITECTURA.md)
58
71
 
59
72
  ---
60
73
 
@@ -147,7 +160,7 @@ import {
147
160
  connectPostgres,
148
161
  ensurePostgresSchema,
149
162
  PostgresDatasource,
150
- } from "@jmlq/logger-plugin-postgres";
163
+ } from "@jmlq/logger-plugin-postgresql";
151
164
 
152
165
  // Configuración cargada desde variables de entorno (env-var + dotenv)
153
166
  import { envs } from "../plugins/envs.plugin";
@@ -280,19 +293,6 @@ async function main() {
280
293
  main();
281
294
  ```
282
295
 
283
- ### 📦 Dependencias adicionales en el cliente
284
-
285
- ```bash
286
- # Si se va a usar MongoDB
287
- npm i mongodb@^6.19.0
288
-
289
- # Si se va a usar PostgreSQL
290
- npm i pg@^8.16.3
291
-
292
- ```
293
-
294
- `mongodb` y `pg` son **peerDependencies**: `@jmlq/logger` no las instala por sí mismo para mantener el core desacoplado.
295
-
296
296
  ### 🔎 Notas importantes
297
297
 
298
298
  > - `loggerReady` es una Promise → debe resolverse con `await`.
@@ -0,0 +1,6 @@
1
+ import { ILogDatasource } from "../../domain/contracts";
2
+ export declare class FlushBuffers {
3
+ private readonly ds;
4
+ constructor(ds: ILogDatasource);
5
+ execute(): Promise<void>;
6
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlushBuffers = void 0;
4
+ class FlushBuffers {
5
+ constructor(ds) {
6
+ this.ds = ds;
7
+ }
8
+ async execute() {
9
+ // flush es opcional; si no está implementado, no hace nada
10
+ await this.ds.flush?.();
11
+ }
12
+ }
13
+ exports.FlushBuffers = FlushBuffers;
@@ -0,0 +1,7 @@
1
+ import { ILogDatasource } from "../../domain/contracts";
2
+ import { IGetLogsFilter, ILog } from "../../domain/types";
3
+ export declare class GetLogs {
4
+ private readonly ds;
5
+ constructor(ds: ILogDatasource);
6
+ execute(filter?: IGetLogsFilter): Promise<ILog[]>;
7
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetLogs = void 0;
4
+ class GetLogs {
5
+ constructor(ds) {
6
+ this.ds = ds;
7
+ }
8
+ async execute(filter) {
9
+ if (!this.ds.find)
10
+ return []; // si el datasource no lo soporta, retorna vacío
11
+ // Sanitiza límites (evita valores negativos o absurdos)
12
+ const safe = filter
13
+ ? {
14
+ ...filter,
15
+ limit: filter.limit && filter.limit > 0
16
+ ? Math.min(filter.limit, 5000)
17
+ : undefined,
18
+ offset: filter.offset && filter.offset >= 0 ? filter.offset : undefined,
19
+ }
20
+ : undefined;
21
+ return this.ds.find(safe);
22
+ }
23
+ }
24
+ exports.GetLogs = GetLogs;
@@ -0,0 +1,3 @@
1
+ export * from "./save-log";
2
+ export * from "./get-logs";
3
+ export * from "./flush-buffers";
@@ -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("./save-log"), exports);
18
+ __exportStar(require("./get-logs"), exports);
19
+ __exportStar(require("./flush-buffers"), exports);
@@ -0,0 +1,13 @@
1
+ import { ILogDatasource, IPiiRedactor } from "../../domain/contracts";
2
+ import { LogMessage } from "../../domain/types";
3
+ import { LogLevel } from "../../domain/value-objects";
4
+ export interface SaveLogDeps {
5
+ ds: ILogDatasource;
6
+ minLevel: LogLevel;
7
+ redactor: IPiiRedactor;
8
+ }
9
+ export declare class SaveLog {
10
+ private readonly deps;
11
+ constructor(deps: SaveLogDeps);
12
+ execute(level: LogLevel, message: LogMessage, meta?: unknown): Promise<void>;
13
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SaveLog = void 0;
4
+ // Normaliza el mensaje: si es función, la evalúa; si es objeto, se redacta; si es string, se redacta
5
+ function normalizeMessage(message, redactor) {
6
+ const resolved = typeof message === "function" ? message() : message; // eval laziness
7
+ return redactor.redact(resolved);
8
+ }
9
+ class SaveLog {
10
+ constructor(deps) {
11
+ this.deps = deps;
12
+ }
13
+ async execute(level, message, meta) {
14
+ // 1) Filtro por nivel (evita hacer trabajo innecesario)
15
+ if (level < this.deps.minLevel)
16
+ return; // no se loggea
17
+ // 2) Normalización + PII
18
+ const normalized = normalizeMessage(message, this.deps.redactor);
19
+ // 3) Construcción del evento
20
+ const log = {
21
+ level,
22
+ message: normalized,
23
+ meta: meta === undefined ? undefined : this.deps.redactor.redact(meta),
24
+ timestamp: Date.now(),
25
+ };
26
+ // 4) Persistencia (fan-out lo maneja el ds si es composite)
27
+ await this.deps.ds.save(log);
28
+ }
29
+ }
30
+ exports.SaveLog = SaveLog;
@@ -0,0 +1,3 @@
1
+ export * from "./log.datasource";
2
+ export * from "./logger";
3
+ export * from "./pii";
@@ -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("./log.datasource"), exports);
18
+ __exportStar(require("./logger"), exports);
19
+ __exportStar(require("./pii"), exports);
@@ -0,0 +1,8 @@
1
+ import { IGetLogsFilter, ILog } from "../types";
2
+ export interface ILogDatasource {
3
+ save(log: ILog): Promise<void>;
4
+ find?(filter?: IGetLogsFilter): Promise<ILog[]>;
5
+ flush?(): Promise<void>;
6
+ dispose?(): Promise<void>;
7
+ readonly name?: string;
8
+ }
@@ -1,3 +1,2 @@
1
1
  "use strict";
2
- // ---- Contratos ----
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ import { ILogDatasource } from ".";
2
+ import { PiiOptions } from "../types";
3
+ import { LogLevel } from "../value-objects";
4
+ export interface ICreateLoggerOptions {
5
+ minLevel?: LogLevel;
6
+ redactPII?: boolean;
7
+ pii?: PiiOptions;
8
+ }
9
+ export interface ILogger {
10
+ trace: (message: unknown, meta?: unknown) => void | Promise<void>;
11
+ debug: (message: unknown, meta?: unknown) => void | Promise<void>;
12
+ info: (message: unknown, meta?: unknown) => void | Promise<void>;
13
+ warn: (message: unknown, meta?: unknown) => void | Promise<void>;
14
+ error: (message: unknown, meta?: unknown) => void | Promise<void>;
15
+ fatal: (message: unknown, meta?: unknown) => void | Promise<void>;
16
+ flush?: () => Promise<void>;
17
+ dispose?: () => Promise<void>;
18
+ }
19
+ export type { ILogDatasource as LogDatasourcePort };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import { PiiOptions } from "../types";
2
+ export interface IPiiRedactor {
3
+ redact<T = unknown>(value: T): T;
4
+ updateOptions?(opts: PiiOptions): void;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,27 +1,10 @@
1
- /**
2
- * Domain Service: PiiRedactor
3
- *
4
- * Propósito:
5
- * - Redactar/anonimizar PII en strings, objetos y arrays (deep).
6
- * - Permitir que el cliente pase patrones adicionales/propios.
7
- * - Controlar redacción por nombre de clave (whitelist/blacklist).
8
- */
9
- import { IPiiPattern, IPiiRedactorOptions } from "../../config";
10
- export declare class PiiRedactor {
11
- private readonly enabled;
12
- private readonly patterns;
13
- private readonly redactKeys;
14
- private readonly preserveKeys;
15
- constructor(opts?: IPiiRedactorOptions);
16
- /** Patrones por defecto (seguros y genéricos). Ajusta según tu dominio/región si lo deseas. */
17
- static defaultPatterns(): IPiiPattern[];
18
- /** Punto de entrada público: redacción deep de cualquier estructura */
1
+ import { IPiiRedactor } from "../contracts";
2
+ import { PiiOptions } from "../types";
3
+ export declare class PiiRedactor implements IPiiRedactor {
4
+ private options;
5
+ constructor(options?: PiiOptions);
6
+ updateOptions(opts: PiiOptions): void;
19
7
  redact<T = unknown>(value: T): T;
20
- /** === Internos === */
21
- private redactValue;
22
8
  private applyPatterns;
23
- private isRedactedKey;
24
- private isPreservedKey;
25
- private keyRedactionReplacement;
26
- private clone;
9
+ private redactDeep;
27
10
  }
@@ -1,139 +1,77 @@
1
1
  "use strict";
2
- /**
3
- * Domain Service: PiiRedactor
4
- *
5
- * Propósito:
6
- * - Redactar/anonimizar PII en strings, objetos y arrays (deep).
7
- * - Permitir que el cliente pase patrones adicionales/propios.
8
- * - Controlar redacción por nombre de clave (whitelist/blacklist).
9
- */
10
2
  Object.defineProperty(exports, "__esModule", { value: true });
11
3
  exports.PiiRedactor = void 0;
4
+ // Utilidad local: crea RegExp segura desde {pattern, flags}
5
+ function toRegex(p) {
6
+ // new RegExp lanza si el patrón es inválido → try/catch para robustez
7
+ try {
8
+ return new RegExp(p.pattern, p.flags ?? "g");
9
+ }
10
+ catch {
11
+ return /$a/; /* patrón imposible */
12
+ }
13
+ }
12
14
  class PiiRedactor {
13
- constructor(opts = {}) {
14
- const { enabled = true, includeDefaultPatterns = true, patterns = [], redactKeys = [], preserveKeys = [], } = opts;
15
- this.enabled = enabled;
16
- this.patterns = includeDefaultPatterns
17
- ? [...PiiRedactor.defaultPatterns(), ...patterns]
18
- : [...patterns];
19
- this.redactKeys = redactKeys;
20
- this.preserveKeys = preserveKeys;
15
+ constructor(options = {}) {
16
+ this.options = options;
21
17
  }
22
- /** Patrones por defecto (seguros y genéricos). Ajusta según tu dominio/región si lo deseas. */
23
- static defaultPatterns() {
24
- return [
25
- // Tarjetas (13–19 dígitos con espacios o guiones) — patrón simple
26
- {
27
- name: "credit_card",
28
- regex: /\b(?:\d[ -]*?){13,19}\b/g,
29
- replacement: "[REDACTED_CARD]",
30
- },
31
- // Emails
32
- {
33
- name: "email",
34
- regex: /\b[\w._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
35
- replacement: "[REDACTED_EMAIL]",
36
- },
37
- // Teléfonos: 10+ dígitos (ajusta a tu región si hace falta)
38
- {
39
- name: "phone",
40
- regex: /\b\d{10,}\b/g,
41
- replacement: "[REDACTED_PHONE]",
42
- },
43
- // Documento genérico: ABC-123456… o similar
44
- {
45
- name: "document_id",
46
- regex: /\b[A-Z]{1,3}-?\d{6,10}\b/g,
47
- replacement: "[REDACTED_ID]",
48
- },
49
- // IPv4
50
- {
51
- name: "ipv4",
52
- regex: /\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.|$)){4}\b/g,
53
- replacement: "[REDACTED_IP]",
54
- },
55
- ];
18
+ updateOptions(opts) {
19
+ // merge superficial de opciones; no muta referencias externas
20
+ this.options = { ...this.options, ...opts };
56
21
  }
57
- /** Punto de entrada público: redacción deep de cualquier estructura */
58
22
  redact(value) {
59
- if (!this.enabled)
23
+ if (!this.options.enabled)
24
+ return value; // early exit si PII apagado
25
+ if (value == null)
60
26
  return value;
61
- return this.redactValue(value, []);
62
- }
63
- /** === Internos === */
64
- redactValue(value, keyPath) {
65
- // Strings → aplicar patrones
27
+ // Si es string → aplicar patrones
66
28
  if (typeof value === "string") {
67
- return this.applyPatterns(value, keyPath);
68
- }
69
- // Números / boolean / null / undefined → retornar tal cual
70
- if (typeof value === "number" ||
71
- typeof value === "boolean" ||
72
- value === null ||
73
- typeof value === "undefined") {
74
- return value;
75
- }
76
- // Arrays → deep
77
- if (Array.isArray(value)) {
78
- return value.map((v, i) => this.redactValue(v, [...keyPath, String(i)]));
29
+ return this.applyPatterns(value);
79
30
  }
80
- // Objetos deep + reglas por nombre de clave
31
+ // Si es objeto/array redacción profunda si corresponde
81
32
  if (typeof value === "object") {
82
- const src = value;
83
- const out = {};
84
- for (const [k, v] of Object.entries(src)) {
85
- const path = [...keyPath, k];
86
- if (this.isPreservedKey(k)) {
87
- out[k] = this.clone(v); // explícitamente preservado
88
- continue;
89
- }
90
- if (this.isRedactedKey(k)) {
91
- out[k] = this.keyRedactionReplacement(k, path);
92
- continue;
93
- }
94
- out[k] = this.redactValue(v, path);
95
- }
96
- return out;
33
+ return this.redactDeep(value);
97
34
  }
98
- // funciones, símbolos, etc.
35
+ // Otros tipos (number, boolean, function) no se redactan
99
36
  return value;
100
37
  }
101
- applyPatterns(text, keyPath) {
102
- let result = text;
103
- for (const p of this.patterns) {
104
- const replacement = p.replacement ?? "[REDACTED]";
105
- // Soporta función de reemplazo con contexto (ruta de claves)
106
- if (typeof replacement === "function") {
107
- result = result.replace(p.regex, (m) => replacement(m, keyPath));
108
- }
109
- else {
110
- result = result.replace(p.regex, replacement);
111
- }
38
+ applyPatterns(input) {
39
+ const patterns = this.options.patterns ?? [];
40
+ let out = input;
41
+ for (const p of patterns) {
42
+ const rx = toRegex(p);
43
+ // replace con patrón RegExp
44
+ out = out.replace(rx, p.replaceWith);
112
45
  }
113
- return result;
114
- }
115
- isRedactedKey(key) {
116
- return this.redactKeys.some((r) => typeof r === "string" ? r === key : r.test(key));
46
+ return out;
117
47
  }
118
- isPreservedKey(key) {
119
- return this.preserveKeys.some((r) => typeof r === "string" ? r === key : r.test(key));
120
- }
121
- keyRedactionReplacement(_key, _path) {
122
- return "[REDACTED]";
123
- }
124
- clone(v) {
125
- if (v && typeof v === "object") {
126
- try {
127
- return JSON.parse(JSON.stringify(v));
48
+ redactDeep(obj) {
49
+ // Evita mutar el objeto original copia superficial
50
+ const clone = Array.isArray(obj)
51
+ ? [...obj]
52
+ : { ...obj };
53
+ const { whitelistKeys = [], blacklistKeys = [], deep = true, } = this.options;
54
+ for (const key of Object.keys(clone)) {
55
+ const val = clone[key];
56
+ // Si está en whitelist, se respeta siempre
57
+ if (whitelistKeys.includes(key))
58
+ continue;
59
+ // Si está en blacklist y es string → reemplazar completamente
60
+ if (blacklistKeys.includes(key)) {
61
+ clone[key] = "[REDACTED]"; // fuerza redacción total de claves sensibles
62
+ continue;
63
+ }
64
+ // Para strings comunes → aplicar patrones
65
+ if (typeof val === "string") {
66
+ clone[key] = this.applyPatterns(val);
67
+ continue;
128
68
  }
129
- catch {
130
- // fallback shallow
131
- if (Array.isArray(v))
132
- return [...v];
133
- return { ...v };
69
+ // Para objetos/arrays y deep===true → recursión
70
+ if (deep && val && typeof val === "object") {
71
+ clone[key] = this.redactDeep(val);
134
72
  }
135
73
  }
136
- return v;
74
+ return clone;
137
75
  }
138
76
  }
139
77
  exports.PiiRedactor = PiiRedactor;
@@ -0,0 +1 @@
1
+ export * from "./log.types";
@@ -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("./factory"), exports);
17
+ __exportStar(require("./log.types"), exports);
@@ -0,0 +1,28 @@
1
+ import { LogLevel } from "../value-objects";
2
+ export type LogMessage = string | Record<string, unknown> | (() => string | Record<string, unknown>);
3
+ export interface ILog {
4
+ level: LogLevel;
5
+ message: string | Record<string, unknown>;
6
+ meta?: unknown;
7
+ timestamp: number;
8
+ }
9
+ export interface IGetLogsFilter {
10
+ levelMin?: LogLevel;
11
+ since?: number;
12
+ until?: number;
13
+ limit?: number;
14
+ offset?: number;
15
+ query?: string;
16
+ }
17
+ export interface PiiReplacement {
18
+ pattern: string;
19
+ flags?: string;
20
+ replaceWith: string;
21
+ }
22
+ export interface PiiOptions {
23
+ enabled?: boolean;
24
+ whitelistKeys?: string[];
25
+ blacklistKeys?: string[];
26
+ patterns?: PiiReplacement[];
27
+ deep?: boolean;
28
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export * from "./log-level";
@@ -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("./services"), exports);
17
+ __exportStar(require("./log-level"), exports);
@@ -0,0 +1,9 @@
1
+ export declare enum LogLevel {
2
+ TRACE = 10,
3
+ DEBUG = 20,
4
+ INFO = 30,
5
+ WARN = 40,
6
+ ERROR = 50,
7
+ FATAL = 60
8
+ }
9
+ export declare function toLogLevel(level: string | number | undefined, def?: LogLevel): LogLevel;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LogLevel = void 0;
4
+ exports.toLogLevel = toLogLevel;
5
+ var LogLevel;
6
+ (function (LogLevel) {
7
+ // Orden creciente permite comparar por severidad (trace < debug < ...)
8
+ LogLevel[LogLevel["TRACE"] = 10] = "TRACE";
9
+ LogLevel[LogLevel["DEBUG"] = 20] = "DEBUG";
10
+ LogLevel[LogLevel["INFO"] = 30] = "INFO";
11
+ LogLevel[LogLevel["WARN"] = 40] = "WARN";
12
+ LogLevel[LogLevel["ERROR"] = 50] = "ERROR";
13
+ LogLevel[LogLevel["FATAL"] = 60] = "FATAL";
14
+ })(LogLevel || (exports.LogLevel = LogLevel = {}));
15
+ // Convierte string a LogLevel con fallback seguro
16
+ function toLogLevel(level, def = LogLevel.INFO) {
17
+ if (typeof level === "number")
18
+ return (Object.values(LogLevel).includes(level) ? level : def);
19
+ if (!level)
20
+ return def;
21
+ switch (String(level).toLowerCase()) {
22
+ case "trace":
23
+ return LogLevel.TRACE;
24
+ case "debug":
25
+ return LogLevel.DEBUG;
26
+ case "info":
27
+ return LogLevel.INFO;
28
+ case "warn":
29
+ return LogLevel.WARN;
30
+ case "error":
31
+ return LogLevel.ERROR;
32
+ case "fatal":
33
+ return LogLevel.FATAL;
34
+ default:
35
+ return def; // evita lanzar excepción por valores inesperados
36
+ }
37
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export * from "./composite";
2
- export * from "./domain";
3
- export * from "./presentation";
4
- export * from "./config";
1
+ export { LogLevel, toLogLevel } from "./domain/value-objects";
2
+ export type { LogMessage, ILog, IGetLogsFilter, PiiOptions, PiiReplacement, } from "./domain/types";
3
+ export type { LogDatasourcePort, ILogger, ICreateLoggerOptions, ILogDatasource, } from "./domain/contracts";
4
+ export { createLogger } from "./presentation/factory";
5
+ export { CompositeDatasource } from "./infrastructure/adapters";
package/dist/index.js CHANGED
@@ -1,20 +1,10 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./composite"), exports);
18
- __exportStar(require("./domain"), exports);
19
- __exportStar(require("./presentation"), exports);
20
- __exportStar(require("./config"), exports);
3
+ exports.CompositeDatasource = exports.createLogger = exports.toLogLevel = exports.LogLevel = void 0;
4
+ var value_objects_1 = require("./domain/value-objects");
5
+ Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return value_objects_1.LogLevel; } });
6
+ Object.defineProperty(exports, "toLogLevel", { enumerable: true, get: function () { return value_objects_1.toLogLevel; } });
7
+ var factory_1 = require("./presentation/factory");
8
+ Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return factory_1.createLogger; } });
9
+ var adapters_1 = require("./infrastructure/adapters");
10
+ Object.defineProperty(exports, "CompositeDatasource", { enumerable: true, get: function () { return adapters_1.CompositeDatasource; } });
@@ -0,0 +1,11 @@
1
+ import { ILogDatasource } from "../../domain/contracts";
2
+ import { IGetLogsFilter, ILog } from "../../domain/types";
3
+ export declare class CompositeDatasource implements ILogDatasource {
4
+ private readonly targets;
5
+ readonly name = "composite";
6
+ constructor(targets: ILogDatasource[]);
7
+ save(log: ILog): Promise<void>;
8
+ find(filter?: IGetLogsFilter): Promise<ILog[]>;
9
+ flush(): Promise<void>;
10
+ dispose(): Promise<void>;
11
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompositeDatasource = void 0;
4
+ // CompositeDatasource: fan-out hacia múltiples datasources
5
+ class CompositeDatasource {
6
+ constructor(targets) {
7
+ this.targets = targets;
8
+ this.name = "composite";
9
+ // Filtro targets válidos (defensivo). Evita null/undefined
10
+ this.targets = (targets ?? []).filter(Boolean);
11
+ }
12
+ async save(log) {
13
+ // Ejecuta todos en paralelo y NO falla el todo si uno falla
14
+ const results = await Promise.allSettled(this.targets.map((ds) => ds.save(log)));
15
+ // Log de errores silencioso (el logger real no debe auto-dependerse)
16
+ for (let i = 0; i < results.length; i++) {
17
+ const r = results[i];
18
+ if (r.status === "rejected") {
19
+ // Preferible: exponer un hook externo; aquí solo console.warn por simplicidad
20
+ // eslint-disable-next-line no-console
21
+ console.warn(`[CompositeDatasource] save error in ds#${i} (${this.targets[i]?.name ?? "unknown"})`, r.reason);
22
+ }
23
+ }
24
+ }
25
+ async find(filter) {
26
+ // Si varios ds soportan find, se concatena y ordena por timestamp desc
27
+ const results = await Promise.allSettled(this.targets.map((ds) => ds.find?.(filter)));
28
+ const logs = [];
29
+ for (const r of results) {
30
+ if (r.status === "fulfilled" && Array.isArray(r.value))
31
+ logs.push(...r.value);
32
+ }
33
+ // Orden descendente por timestamp (más recientes primero)
34
+ logs.sort((a, b) => b.timestamp - a.timestamp);
35
+ return logs;
36
+ }
37
+ async flush() {
38
+ // Ejecuta flush donde esté disponible
39
+ await Promise.allSettled(this.targets.map((ds) => ds.flush?.()));
40
+ }
41
+ async dispose() {
42
+ // Libera recursos en todos los ds
43
+ await Promise.allSettled(this.targets.map((ds) => ds.dispose?.()));
44
+ }
45
+ }
46
+ exports.CompositeDatasource = CompositeDatasource;
@@ -0,0 +1 @@
1
+ export * from "./composite.datasource";
@@ -14,5 +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("./interfaces"), exports);
18
- __exportStar(require("./types"), exports);
17
+ __exportStar(require("./composite.datasource"), exports);
@@ -0,0 +1,2 @@
1
+ import { ICreateLoggerOptions, ILogDatasource, ILogger } from "../../domain/contracts";
2
+ export declare function createLogger(ds: ILogDatasource, opts?: ICreateLoggerOptions): ILogger;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLogger = createLogger;
4
+ const use_cases_1 = require("../../application/use-cases");
5
+ const services_1 = require("../../domain/services");
6
+ const value_objects_1 = require("../../domain/value-objects");
7
+ // Factoría de logger. Encapsula composición de casos de uso y servicios
8
+ function createLogger(ds, opts = {}) {
9
+ // Resolve minLevel con un default razonable (INFO)
10
+ const minLevel = opts.minLevel ?? value_objects_1.LogLevel.INFO;
11
+ // Mantén compatibilidad con redactPII
12
+ const piiEnabled = opts.pii?.enabled ?? opts.redactPII ?? false;
13
+ const redactor = new services_1.PiiRedactor({ enabled: piiEnabled, ...opts.pii });
14
+ const save = new use_cases_1.SaveLog({ ds, minLevel, redactor });
15
+ const flushUC = new use_cases_1.FlushBuffers(ds);
16
+ // Helper emisor; si en el futuro se necesita encolar, aquí es el lugar
17
+ const emit = (lvl, message, meta) => save.execute(lvl, message, meta);
18
+ return {
19
+ trace: (m, meta) => emit(value_objects_1.LogLevel.TRACE, m, meta),
20
+ debug: (m, meta) => emit(value_objects_1.LogLevel.DEBUG, m, meta),
21
+ info: (m, meta) => emit(value_objects_1.LogLevel.INFO, m, meta),
22
+ warn: (m, meta) => emit(value_objects_1.LogLevel.WARN, m, meta),
23
+ error: (m, meta) => emit(value_objects_1.LogLevel.ERROR, m, meta),
24
+ fatal: (m, meta) => emit(value_objects_1.LogLevel.FATAL, m, meta),
25
+ // Gestión de ciclo de vida → delega en caso de uso / puerto
26
+ flush: () => flushUC.execute(),
27
+ dispose: () => ds.dispose?.() ?? Promise.resolve(),
28
+ };
29
+ }
@@ -1,2 +1 @@
1
- import { ICreateLoggerOptions, ILogDatasource, ILogger } from "../..";
2
- export declare function createLogger(ds: ILogDatasource, opts?: ICreateLoggerOptions): ILogger;
1
+ export * from "./create-logger";
@@ -1,74 +1,17 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLogger = createLogger;
4
- const __1 = require("../..");
5
- /**
6
- * Normaliza cualquier LogMessage a string, aplicando PII (si procede) ANTES de serializar.
7
- */
8
- function normalizeLogMessage(value, redactEnabled, redactor) {
9
- const v = redactEnabled ? redactor.redact(value) : value;
10
- if (typeof v === "string")
11
- return v;
12
- // Si soportas Error en LogMessage, lo serializamos “bonito”
13
- if (v instanceof Error) {
14
- const err = v;
15
- const obj = {
16
- error: err.name || "Error",
17
- message: err.message,
18
- stack: err.stack,
19
- code: err.code,
20
- cause: err.cause,
21
- };
22
- try {
23
- return JSON.stringify(obj);
24
- }
25
- catch {
26
- return `${obj.error}: ${obj.message}`;
27
- }
28
- }
29
- // Objeto → JSON
30
- try {
31
- return JSON.stringify(v);
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]; } };
32
7
  }
33
- catch {
34
- // fallback ultra defensivo
35
- return String(v);
36
- }
37
- }
38
- function createLogger(ds, opts = {}) {
39
- const minLevel = opts.minLevel ?? __1.LogLevel.INFO;
40
- // Compatibilidad: redactPII (boolean) o pii.enabled
41
- const redactEnabled = (opts.redactPII ?? false) || (opts.pii?.enabled ?? false);
42
- // Inicializa redactor con opciones del cliente (incluye defaults por defecto)
43
- const redactor = new __1.PiiRedactor({
44
- enabled: redactEnabled,
45
- includeDefaultPatterns: opts.pii?.includeDefaultPatterns ?? true,
46
- patterns: opts.pii?.patterns,
47
- redactKeys: opts.pii?.redactKeys,
48
- preserveKeys: opts.pii?.preserveKeys,
49
- });
50
- const emit = async (level, message, meta) => {
51
- if (level < minLevel)
52
- return;
53
- const msgStr = normalizeLogMessage(message, redactEnabled, redactor);
54
- const metaVal = redactEnabled ? redactor.redact(meta) : meta;
55
- const payload = {
56
- level,
57
- timestamp: Date.now(),
58
- message: msgStr, // <- garantizamos string
59
- meta: metaVal,
60
- };
61
- await ds.save(payload);
62
- };
63
- const logger = {
64
- trace: (m, meta) => emit(__1.LogLevel.TRACE, m, meta),
65
- debug: (m, meta) => emit(__1.LogLevel.DEBUG, m, meta),
66
- info: (m, meta) => emit(__1.LogLevel.INFO, m, meta),
67
- warn: (m, meta) => emit(__1.LogLevel.WARN, m, meta),
68
- error: (m, meta) => emit(__1.LogLevel.ERROR, m, meta),
69
- fatal: (m, meta) => emit(__1.LogLevel.FATAL, m, meta),
70
- flush: () => ds.flush?.() ?? Promise.resolve(),
71
- dispose: () => ds.dispose?.() ?? Promise.resolve(),
72
- };
73
- return logger;
74
- }
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("./create-logger"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmlq/logger",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.5",
4
4
  "author": "MLahuasi",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,11 +9,23 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "build": "tsc -p tsconfig.json",
12
- "prepublishOnly": "npm run build"
12
+ "prepublishOnly": "npm run build",
13
+ "test": "jest --passWithNoTests",
14
+ "test:watch": "jest --watch",
15
+ "test:cov": "jest --coverage"
13
16
  },
14
17
  "devDependencies": {
18
+ "@swc/core": "^1.13.5",
19
+ "@swc/jest": "^0.2.39",
20
+ "@types/jest": "^30.0.0",
15
21
  "@types/node": "^24.3.0",
22
+ "jest": "^30.1.3",
16
23
  "tsx": "^4.20.5",
17
24
  "typescript": "^5.9.2"
25
+ },
26
+ "overrides": {
27
+ "test-exclude": "^7.0.1",
28
+ "glob": "^10.4.5",
29
+ "minimatch": "^9.0.5"
18
30
  }
19
31
  }
@@ -1,9 +0,0 @@
1
- import { IGetLogsFilter, ILogDatasource, ILog } from "../config";
2
- export declare class CompositeDatasource implements ILogDatasource {
3
- private readonly datasources;
4
- constructor(datasources: ILogDatasource[]);
5
- save(log: ILog): Promise<void>;
6
- find(filter?: IGetLogsFilter): Promise<ILog[]>;
7
- flush(): Promise<void>;
8
- dispose(): Promise<void>;
9
- }
@@ -1,54 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CompositeDatasource = void 0;
4
- // ---- Composite fan-out ----
5
- class CompositeDatasource {
6
- constructor(datasources) {
7
- this.datasources = datasources;
8
- }
9
- async save(log) {
10
- const results = await Promise.allSettled(this.datasources.map((ds) => ds.save(log)));
11
- for (const r of results) {
12
- if (r.status === "rejected") {
13
- // Evita romper el flujo si un destino falla.
14
- // Aquí podrías enrutar a "dead-letter", métricas, etc.
15
- // eslint-disable-next-line no-console
16
- console.warn("[CompositeDatasource] save failed:", r.reason);
17
- }
18
- }
19
- }
20
- async find(filter = {}) {
21
- for (const ds of this.datasources) {
22
- if (typeof ds.find === "function") {
23
- try {
24
- return await ds.find(filter);
25
- }
26
- catch (e) {
27
- // eslint-disable-next-line no-console
28
- console.warn("[CompositeDatasource] find failed on a datasource:", e);
29
- // probar siguiente datasource
30
- }
31
- }
32
- }
33
- return [];
34
- }
35
- async flush() {
36
- const results = await Promise.allSettled(this.datasources.map((ds) => ds.flush?.() ?? Promise.resolve()));
37
- for (const r of results) {
38
- if (r.status === "rejected") {
39
- // eslint-disable-next-line no-console
40
- console.warn("[CompositeDatasource] flush failed:", r.reason);
41
- }
42
- }
43
- }
44
- async dispose() {
45
- const results = await Promise.allSettled(this.datasources.map((ds) => ds.dispose?.() ?? Promise.resolve()));
46
- for (const r of results) {
47
- if (r.status === "rejected") {
48
- // eslint-disable-next-line no-console
49
- console.warn("[CompositeDatasource] dispose failed:", r.reason);
50
- }
51
- }
52
- }
53
- }
54
- exports.CompositeDatasource = CompositeDatasource;
@@ -1,5 +0,0 @@
1
- import { ILogDatasource, Logger, LogLevel } from "..";
2
- export declare function createLogger(ds: ILogDatasource, opts: {
3
- minLevel: LogLevel;
4
- redactPII?: boolean;
5
- }): Logger;
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLogger = createLogger;
4
- const __1 = require("..");
5
- function createLogger(ds, opts) {
6
- const write = async (level, message, meta) => {
7
- if (level < opts.minLevel)
8
- return;
9
- // (Opcional) redactor PII aquí si opts.redactPII === true
10
- await ds.save({ level, message, meta, timestamp: Date.now() });
11
- };
12
- const logger = {
13
- trace: (m, meta) => write(__1.LogLevel.TRACE, m, meta),
14
- debug: (m, meta) => write(__1.LogLevel.DEBUG, m, meta),
15
- info: (m, meta) => write(__1.LogLevel.INFO, m, meta),
16
- warn: (m, meta) => write(__1.LogLevel.WARN, m, meta),
17
- error: (m, meta) => write(__1.LogLevel.ERROR, m, meta),
18
- fatal: (m, meta) => write(__1.LogLevel.FATAL, m, meta),
19
- flush: () => ds.flush?.() ?? Promise.resolve(),
20
- dispose: () => ds.dispose?.() ?? Promise.resolve(),
21
- };
22
- return logger;
23
- }
@@ -1,2 +0,0 @@
1
- export * from "./interfaces";
2
- export * from "./types";
@@ -1,67 +0,0 @@
1
- import { LogLevel, LogMessage, PiiReplacement } from "..";
2
- export interface ILog {
3
- level: LogLevel;
4
- message: string;
5
- meta?: unknown;
6
- timestamp: number;
7
- }
8
- export interface IGetLogsFilter {
9
- levelMin?: LogLevel;
10
- since?: number;
11
- until?: number;
12
- }
13
- export interface ILogDatasource {
14
- save(log: ILog): Promise<void>;
15
- find?(filter?: IGetLogsFilter): Promise<ILog[]>;
16
- flush?(): Promise<void>;
17
- dispose?(): Promise<void>;
18
- }
19
- export interface ILogger {
20
- trace: (msg: LogMessage, meta?: unknown) => Promise<void>;
21
- debug: (msg: LogMessage, meta?: unknown) => Promise<void>;
22
- info: (msg: LogMessage, meta?: unknown) => Promise<void>;
23
- warn: (msg: LogMessage, meta?: unknown) => Promise<void>;
24
- error: (msg: LogMessage, meta?: unknown) => Promise<void>;
25
- fatal: (msg: LogMessage, meta?: unknown) => Promise<void>;
26
- flush?: () => Promise<void>;
27
- dispose?: () => Promise<void>;
28
- }
29
- export interface IPiiPattern {
30
- /** (Opcional) Nombre del patrón para debug/telemetría */
31
- name?: string;
32
- /** Expresión regular a aplicar sobre strings */
33
- regex: RegExp;
34
- /** Reemplazo, por defecto "[REDACTED]" si no se provee */
35
- replacement?: PiiReplacement;
36
- }
37
- export interface IPiiRedactorOptions {
38
- /** Habilita/deshabilita redacción (permite control fino además del flag redactPII) */
39
- enabled?: boolean;
40
- /**
41
- * Incluye patrones default (true) y fusiona con los custom. Si false, usa solo los personalizados
42
- * por el cliente.
43
- */
44
- includeDefaultPatterns?: boolean;
45
- /** Patrones adicionales o propios del cliente */
46
- patterns?: IPiiPattern[];
47
- /**
48
- * Redactar por nombre de clave (deep). Cualquier key que haga match será redacatada
49
- * con "[REDACTED]". Acepta exacto o RegExp.
50
- */
51
- redactKeys?: Array<string | RegExp>;
52
- /**
53
- * Claves que NO se deben redactar aunque coincidan con patrones o redactKeys.
54
- * Prioridad: preserveKeys > redactKeys > patterns.
55
- */
56
- preserveKeys?: Array<string | RegExp>;
57
- }
58
- export interface ICreateLoggerOptions {
59
- minLevel?: LogLevel;
60
- /** compatibilidad con lo que ya tienes */
61
- redactPII?: boolean;
62
- /** NUEVO: bloque de configuración PII */
63
- pii?: IPiiRedactorOptions & {
64
- /** atajo para permitir que el cliente mande solo patterns sin escribir PiiRedactorOptions */
65
- patterns?: IPiiPattern[];
66
- };
67
- }
@@ -1,10 +0,0 @@
1
- export declare enum LogLevel {
2
- TRACE = 0,
3
- DEBUG = 1,
4
- INFO = 2,
5
- WARN = 3,
6
- ERROR = 4,
7
- FATAL = 5
8
- }
9
- export type PiiReplacement = string | ((match: string, keyPath: string[]) => string);
10
- export type LogMessage = string | Record<string, unknown> | Error;
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogLevel = void 0;
4
- // ---- Types ----
5
- var LogLevel;
6
- (function (LogLevel) {
7
- LogLevel[LogLevel["TRACE"] = 0] = "TRACE";
8
- LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
9
- LogLevel[LogLevel["INFO"] = 2] = "INFO";
10
- LogLevel[LogLevel["WARN"] = 3] = "WARN";
11
- LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
12
- LogLevel[LogLevel["FATAL"] = 5] = "FATAL";
13
- })(LogLevel || (exports.LogLevel = LogLevel = {}));
@@ -1 +0,0 @@
1
- export * from "./services";
@@ -1,35 +0,0 @@
1
- export declare enum LogLevel {
2
- TRACE = 0,
3
- DEBUG = 1,
4
- INFO = 2,
5
- WARN = 3,
6
- ERROR = 4,
7
- FATAL = 5
8
- }
9
- export interface Log {
10
- level: LogLevel;
11
- message: string;
12
- meta?: unknown;
13
- timestamp: number;
14
- }
15
- export interface GetLogsFilter {
16
- levelMin?: LogLevel;
17
- since?: number;
18
- until?: number;
19
- }
20
- export interface ILogDatasource {
21
- save(log: Log): Promise<void>;
22
- find?(filter?: GetLogsFilter): Promise<Log[]>;
23
- flush?(): Promise<void>;
24
- dispose?(): Promise<void>;
25
- }
26
- export interface Logger {
27
- trace: (msg: string, meta?: unknown) => Promise<void>;
28
- debug: (msg: string, meta?: unknown) => Promise<void>;
29
- info: (msg: string, meta?: unknown) => Promise<void>;
30
- warn: (msg: string, meta?: unknown) => Promise<void>;
31
- error: (msg: string, meta?: unknown) => Promise<void>;
32
- fatal: (msg: string, meta?: unknown) => Promise<void>;
33
- flush?: () => Promise<void>;
34
- dispose?: () => Promise<void>;
35
- }
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogLevel = void 0;
4
- // ---- Types & contratos ----
5
- var LogLevel;
6
- (function (LogLevel) {
7
- LogLevel[LogLevel["TRACE"] = 0] = "TRACE";
8
- LogLevel[LogLevel["DEBUG"] = 1] = "DEBUG";
9
- LogLevel[LogLevel["INFO"] = 2] = "INFO";
10
- LogLevel[LogLevel["WARN"] = 3] = "WARN";
11
- LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
12
- LogLevel[LogLevel["FATAL"] = 5] = "FATAL";
13
- })(LogLevel || (exports.LogLevel = LogLevel = {}));
@@ -1 +0,0 @@
1
- export * from "./factory";