@jmlq/logger 0.1.0-alpha.2 → 0.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +347 -0
- package/dist/application/use-cases/flush-buffers.d.ts +6 -0
- package/dist/application/use-cases/flush-buffers.js +13 -0
- package/dist/application/use-cases/get-logs.d.ts +7 -0
- package/dist/application/use-cases/get-logs.js +24 -0
- package/dist/application/use-cases/index.d.ts +3 -0
- package/dist/application/use-cases/index.js +19 -0
- package/dist/application/use-cases/save-log.d.ts +13 -0
- package/dist/application/use-cases/save-log.js +30 -0
- package/dist/domain/contracts/index.d.ts +3 -0
- package/dist/domain/contracts/index.js +19 -0
- package/dist/domain/contracts/log.datasource.d.ts +8 -0
- package/dist/{config/interfaces/index.js → domain/contracts/log.datasource.js} +0 -1
- package/dist/domain/contracts/logger.d.ts +19 -0
- package/dist/domain/contracts/logger.js +2 -0
- package/dist/domain/contracts/pii.d.ts +5 -0
- package/dist/domain/contracts/pii.js +2 -0
- package/dist/domain/services/pii-redactor.d.ts +7 -24
- package/dist/domain/services/pii-redactor.js +55 -117
- package/dist/domain/types/index.d.ts +1 -0
- package/dist/{presentation → domain/types}/index.js +1 -1
- package/dist/domain/types/log.types.d.ts +28 -0
- package/dist/domain/types/log.types.js +2 -0
- package/dist/domain/value-objects/index.d.ts +1 -0
- package/dist/domain/{index.js → value-objects/index.js} +1 -1
- package/dist/domain/value-objects/log-level.d.ts +9 -0
- package/dist/domain/value-objects/log-level.js +37 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +8 -18
- package/dist/infrastructure/adapters/composite.datasource.d.ts +11 -0
- package/dist/infrastructure/adapters/composite.datasource.js +46 -0
- package/dist/infrastructure/adapters/index.d.ts +1 -0
- package/dist/{config → infrastructure/adapters}/index.js +1 -2
- package/dist/presentation/factory/create-logger.d.ts +2 -0
- package/dist/presentation/factory/create-logger.js +29 -0
- package/dist/presentation/factory/index.d.ts +1 -2
- package/dist/presentation/factory/index.js +15 -72
- package/package.json +14 -2
- package/dist/Composite/index.d.ts +0 -9
- package/dist/Composite/index.js +0 -54
- package/dist/Factory/index.d.ts +0 -5
- package/dist/Factory/index.js +0 -23
- package/dist/config/index.d.ts +0 -2
- package/dist/config/interfaces/index.d.ts +0 -67
- package/dist/config/types/index.d.ts +0 -10
- package/dist/config/types/index.js +0 -13
- package/dist/domain/index.d.ts +0 -1
- package/dist/interfaces/index.d.ts +0 -35
- package/dist/interfaces/index.js +0 -13
- package/dist/presentation/index.d.ts +0 -1
|
@@ -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(
|
|
14
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
31
|
+
// Si es objeto/array → redacción profunda si corresponde
|
|
81
32
|
if (typeof value === "object") {
|
|
82
|
-
|
|
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
|
-
//
|
|
35
|
+
// Otros tipos (number, boolean, function) no se redactan
|
|
99
36
|
return value;
|
|
100
37
|
}
|
|
101
|
-
applyPatterns(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
114
|
-
}
|
|
115
|
-
isRedactedKey(key) {
|
|
116
|
-
return this.redactKeys.some((r) => typeof r === "string" ? r === key : r.test(key));
|
|
46
|
+
return out;
|
|
117
47
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
|
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("./
|
|
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 @@
|
|
|
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("./
|
|
17
|
+
__exportStar(require("./log-level"), exports);
|
|
@@ -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
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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("./
|
|
18
|
-
__exportStar(require("./types"), exports);
|
|
17
|
+
__exportStar(require("./composite.datasource"), exports);
|
|
@@ -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
|
-
|
|
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.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
"version": "0.1.0-alpha.4",
|
|
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
|
-
}
|
package/dist/Composite/index.js
DELETED
|
@@ -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;
|