@pencroff-lab/kore 0.1.1 → 0.2.0

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.
@@ -0,0 +1,271 @@
1
+ /**
2
+ * @fileoverview Structured logging utility with transport DI and Err integration.
3
+ *
4
+ * This module provides a flexible, callable logger with a transport abstraction,
5
+ * built-in pretty console transport, and zero external runtime dependencies
6
+ * beyond `fast-safe-stringify`.
7
+ *
8
+ * ## Design Philosophy
9
+ *
10
+ * The logger is designed as a callable function with overloaded signatures.
11
+ * Transports are injectable, making the logger testable without streams or
12
+ * process-level side effects. The built-in pretty transport renders to stderr
13
+ * with ANSI colors and automatic Err formatting.
14
+ *
15
+ * ## Basic Usage
16
+ *
17
+ * @example Simple logging
18
+ * ```typescript
19
+ * import { log } from './utils/logger';
20
+ *
21
+ * log('Application started'); // INFO level by default
22
+ * log(log.WARN, 'Connection slow'); // Explicit level
23
+ * log(log.ERROR, 'Failed to save', { userId: '123' }); // With context
24
+ * ```
25
+ *
26
+ * @example Logging with Err instances
27
+ * ```typescript
28
+ * import { Err } from './types/err';
29
+ * import { log } from './utils/logger';
30
+ *
31
+ * const [data, err] = fetchData();
32
+ * if (err) {
33
+ * log(log.ERROR, 'Data fetch failed', err);
34
+ * return;
35
+ * }
36
+ * ```
37
+ *
38
+ * @example Child loggers with module context
39
+ * ```typescript
40
+ * const dbLogger = log.child('database', { version: '1.0' });
41
+ * dbLogger('Connected to postgres');
42
+ * // Output: [database] Connected to postgres
43
+ *
44
+ * const userLogger = dbLogger.child('users');
45
+ * userLogger('User created');
46
+ * // Output: [database] [users] User created
47
+ * ```
48
+ *
49
+ * @example Custom transport for testing
50
+ * ```typescript
51
+ * import { createLogger, lvl } from './utils/logger';
52
+ * import type { LogEntry, LogTransport } from './utils/logger';
53
+ *
54
+ * const entries: LogEntry[] = [];
55
+ * const spy: LogTransport = { write(e) { entries.push(e); } };
56
+ * const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
57
+ * ```
58
+ *
59
+ * ## Configuration
60
+ *
61
+ * The logger reads configuration from environment variables:
62
+ * - `LOG_LEVEL`: Minimum level to log (trace|debug|info|warn|error|fatal). Default: 'info'
63
+ *
64
+ * @module logger
65
+ */
66
+ import { Err } from "../types/err";
67
+ /**
68
+ * Log level constants for type-safe level specification.
69
+ *
70
+ * **Level Hierarchy** (lowest to highest):
71
+ * - `TRACE`: Detailed debugging information
72
+ * - `DEBUG`: Debugging information
73
+ * - `INFO`: General informational messages
74
+ * - `WARN`: Warning messages
75
+ * - `ERROR`: Error messages for failures
76
+ * - `FATAL`: Fatal errors causing termination
77
+ */
78
+ declare const lvl: {
79
+ readonly TRACE: "trace";
80
+ readonly DEBUG: "debug";
81
+ readonly INFO: "info";
82
+ readonly WARN: "warn";
83
+ readonly ERROR: "error";
84
+ readonly FATAL: "fatal";
85
+ };
86
+ /**
87
+ * Type representing valid log level values.
88
+ */
89
+ type LevelValue = (typeof lvl)[keyof typeof lvl];
90
+ /**
91
+ * A single structured log entry passed to transports.
92
+ */
93
+ interface LogEntry {
94
+ /** Log level */
95
+ level: LevelValue;
96
+ /** Unix timestamp in milliseconds (Date.now()) */
97
+ timestamp: number;
98
+ /** Log message */
99
+ message: string;
100
+ /** Merged bindings + call-site context */
101
+ context: Record<string, unknown>;
102
+ /** Module chain accumulated by child() calls */
103
+ modules: string[];
104
+ }
105
+ /**
106
+ * Transport interface — receives a `LogEntry` for each log call that passes
107
+ * the level filter. Implement this to integrate any logging backend.
108
+ *
109
+ * @example Pino transport
110
+ * ```typescript
111
+ * import pino from 'pino';
112
+ * import type { LogTransport, LogEntry } from '@pencroff-lab/kore';
113
+ *
114
+ * const pinoInstance = pino();
115
+ * const pinoTransport: LogTransport = {
116
+ * write(entry: LogEntry) {
117
+ * const prefix = entry.modules.map(m => `[${m}] `).join('');
118
+ * pinoInstance[entry.level](entry.context, prefix + entry.message);
119
+ * }
120
+ * };
121
+ * ```
122
+ */
123
+ interface LogTransport {
124
+ write(entry: LogEntry): void;
125
+ }
126
+ /**
127
+ * Options for the built-in pretty console transport.
128
+ */
129
+ interface PrettyOptions {
130
+ /** Output stream. Default: `process.stderr` */
131
+ output?: {
132
+ write(data: string): void;
133
+ };
134
+ /**
135
+ * Enable ANSI colors.
136
+ * - `'auto'` (default): enable when output is a TTY
137
+ * - `true`: always enable
138
+ * - `false`: always disable
139
+ */
140
+ colors?: boolean | "auto";
141
+ /** Override default level colors (ANSI escape sequences) */
142
+ levelColors?: Partial<Record<LevelValue, string>>;
143
+ /**
144
+ * Timestamp format.
145
+ * - `'short'` (default): `HH:MM:SS.mmm` local time
146
+ * - `'iso'`: ISO 8601 string
147
+ * - Custom function receiving `Date.now()` timestamp
148
+ */
149
+ timestamp?: "short" | "iso" | ((ts: number) => string);
150
+ }
151
+ /**
152
+ * Options for `createLogger`.
153
+ */
154
+ interface LoggerOptions {
155
+ /** Minimum log level. Default: from `LOG_LEVEL` env or `'info'` */
156
+ level?: LevelValue;
157
+ /** Transports to write entries to. Default: `[prettyTransport()]` */
158
+ transports?: LogTransport[];
159
+ }
160
+ /**
161
+ * Callable logger interface with overloaded signatures.
162
+ *
163
+ * The Logger is both a function (for logging) and an object (with level
164
+ * constants and the `child` method).
165
+ *
166
+ * ## Call Signatures
167
+ * 1. `log(message)` - Log at INFO level
168
+ * 2. `log(message, context)` - Log at INFO level with context object or Err
169
+ * 3. `log(message, detail)` - Log at INFO level with detail string
170
+ * 4. `log(level, message)` - Log at specific level
171
+ * 5. `log(level, message, context)` - Log at specific level with context
172
+ */
173
+ interface Logger {
174
+ /** Trace level constant */
175
+ readonly TRACE: "trace";
176
+ /** Debug level constant */
177
+ readonly DEBUG: "debug";
178
+ /** Info level constant */
179
+ readonly INFO: "info";
180
+ /** Warning level constant */
181
+ readonly WARN: "warn";
182
+ /** Error level constant */
183
+ readonly ERROR: "error";
184
+ /** Fatal level constant */
185
+ readonly FATAL: "fatal";
186
+ /** Log a message at INFO level. */
187
+ (message: string): void;
188
+ /** Log a message at INFO level with context. */
189
+ (message: string, context: object | Err): void;
190
+ /** Log a message at INFO level with detail string. */
191
+ (message: string, detail: string): void;
192
+ /** Log a message at a specific level. */
193
+ (level: LevelValue, message: string): void;
194
+ /** Log a message at a specific level with context. */
195
+ (level: LevelValue, message: string, context: object | Err): void;
196
+ /**
197
+ * Create a child logger with module-specific context.
198
+ *
199
+ * @param module - Module name added to the modules array
200
+ * @param bindings - Optional bindings merged into every log entry's context
201
+ * @returns New Logger instance
202
+ */
203
+ child(module: string, bindings?: object): Logger;
204
+ }
205
+ /**
206
+ * Create a built-in pretty console transport.
207
+ *
208
+ * Renders log entries to a human-readable format with optional ANSI colors.
209
+ *
210
+ * Output format:
211
+ * ```
212
+ * {dim timestamp} {colored TAG} {[mod] [mod]} {message} {dim context}
213
+ * ```
214
+ *
215
+ * Err instances in context are rendered via `Err.toString()` on their own
216
+ * indented line below the main line.
217
+ *
218
+ * @param options - Optional configuration
219
+ */
220
+ declare function prettyTransport(options?: PrettyOptions): LogTransport;
221
+ /**
222
+ * Create a logger instance with optional module name and configuration.
223
+ *
224
+ * @param module - Optional module name added as the first entry in `modules`
225
+ * @param options - Optional configuration
226
+ * @returns New Logger instance
227
+ *
228
+ * @example Basic usage
229
+ * ```typescript
230
+ * const logger = createLogger();
231
+ * logger('Application ready');
232
+ * ```
233
+ *
234
+ * @example Module-specific logger
235
+ * ```typescript
236
+ * const dbLogger = createLogger('database');
237
+ * dbLogger('Connected');
238
+ * ```
239
+ *
240
+ * @example Testing with spy transport
241
+ * ```typescript
242
+ * import type { LogEntry, LogTransport } from './utils/logger';
243
+ *
244
+ * const entries: LogEntry[] = [];
245
+ * const spy: LogTransport = { write(e) { entries.push(e); } };
246
+ * const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
247
+ * ```
248
+ */
249
+ declare function createLogger(module?: string, options?: LoggerOptions): Logger;
250
+ /**
251
+ * Default logger instance for application-wide logging.
252
+ *
253
+ * @example Basic usage
254
+ * ```typescript
255
+ * import { log } from './utils/logger';
256
+ *
257
+ * log('Application started');
258
+ * log(log.INFO, 'Server listening', { port: 3000 });
259
+ * log(log.ERROR, 'Startup failed', err);
260
+ * ```
261
+ *
262
+ * @example Module-specific logging via child
263
+ * ```typescript
264
+ * const dbLogger = log.child('database');
265
+ * dbLogger('Connection pool initialized');
266
+ * ```
267
+ */
268
+ export declare const log: Logger;
269
+ export { createLogger, prettyTransport, lvl };
270
+ export type { Logger, LevelValue, LogEntry, LogTransport, LoggerOptions, PrettyOptions, };
271
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,335 @@
1
+ /**
2
+ * @fileoverview Structured logging utility with transport DI and Err integration.
3
+ *
4
+ * This module provides a flexible, callable logger with a transport abstraction,
5
+ * built-in pretty console transport, and zero external runtime dependencies
6
+ * beyond `fast-safe-stringify`.
7
+ *
8
+ * ## Design Philosophy
9
+ *
10
+ * The logger is designed as a callable function with overloaded signatures.
11
+ * Transports are injectable, making the logger testable without streams or
12
+ * process-level side effects. The built-in pretty transport renders to stderr
13
+ * with ANSI colors and automatic Err formatting.
14
+ *
15
+ * ## Basic Usage
16
+ *
17
+ * @example Simple logging
18
+ * ```typescript
19
+ * import { log } from './utils/logger';
20
+ *
21
+ * log('Application started'); // INFO level by default
22
+ * log(log.WARN, 'Connection slow'); // Explicit level
23
+ * log(log.ERROR, 'Failed to save', { userId: '123' }); // With context
24
+ * ```
25
+ *
26
+ * @example Logging with Err instances
27
+ * ```typescript
28
+ * import { Err } from './types/err';
29
+ * import { log } from './utils/logger';
30
+ *
31
+ * const [data, err] = fetchData();
32
+ * if (err) {
33
+ * log(log.ERROR, 'Data fetch failed', err);
34
+ * return;
35
+ * }
36
+ * ```
37
+ *
38
+ * @example Child loggers with module context
39
+ * ```typescript
40
+ * const dbLogger = log.child('database', { version: '1.0' });
41
+ * dbLogger('Connected to postgres');
42
+ * // Output: [database] Connected to postgres
43
+ *
44
+ * const userLogger = dbLogger.child('users');
45
+ * userLogger('User created');
46
+ * // Output: [database] [users] User created
47
+ * ```
48
+ *
49
+ * @example Custom transport for testing
50
+ * ```typescript
51
+ * import { createLogger, lvl } from './utils/logger';
52
+ * import type { LogEntry, LogTransport } from './utils/logger';
53
+ *
54
+ * const entries: LogEntry[] = [];
55
+ * const spy: LogTransport = { write(e) { entries.push(e); } };
56
+ * const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
57
+ * ```
58
+ *
59
+ * ## Configuration
60
+ *
61
+ * The logger reads configuration from environment variables:
62
+ * - `LOG_LEVEL`: Minimum level to log (trace|debug|info|warn|error|fatal). Default: 'info'
63
+ *
64
+ * @module logger
65
+ */
66
+ import stringifySafe from "fast-safe-stringify";
67
+ import { Err } from "../types/err";
68
+ /**
69
+ * Log level constants for type-safe level specification.
70
+ *
71
+ * **Level Hierarchy** (lowest to highest):
72
+ * - `TRACE`: Detailed debugging information
73
+ * - `DEBUG`: Debugging information
74
+ * - `INFO`: General informational messages
75
+ * - `WARN`: Warning messages
76
+ * - `ERROR`: Error messages for failures
77
+ * - `FATAL`: Fatal errors causing termination
78
+ */
79
+ const lvl = {
80
+ TRACE: "trace",
81
+ DEBUG: "debug",
82
+ INFO: "info",
83
+ WARN: "warn",
84
+ ERROR: "error",
85
+ FATAL: "fatal",
86
+ };
87
+ // ─── Internal constants ───────────────────────────────────────────────────────
88
+ const levelSet = new Set(Object.values(lvl));
89
+ const LEVEL_NUMBERS = {
90
+ trace: 0,
91
+ debug: 1,
92
+ info: 2,
93
+ warn: 3,
94
+ error: 4,
95
+ fatal: 5,
96
+ };
97
+ const LEVEL_TAGS = {
98
+ trace: "TRC",
99
+ debug: "DBG",
100
+ info: "INF",
101
+ warn: "WRN",
102
+ error: "ERR",
103
+ fatal: "FTL",
104
+ };
105
+ const DEFAULT_LEVEL_COLORS = {
106
+ trace: "\x1b[2m",
107
+ debug: "\x1b[36m",
108
+ info: "\x1b[32m",
109
+ warn: "\x1b[38;5;208m",
110
+ error: "\x1b[31m",
111
+ fatal: "\x1b[1m\x1b[31m",
112
+ };
113
+ const RESET = "\x1b[0m";
114
+ const DIM = "\x1b[2m";
115
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
116
+ function isLevel(val) {
117
+ return (typeof val === "string" &&
118
+ levelSet.has(val.toLocaleLowerCase()));
119
+ }
120
+ function normalizeContext(ctx) {
121
+ if (Err.isErr(ctx))
122
+ return { err: ctx };
123
+ if (typeof ctx === "string")
124
+ return { detail: ctx };
125
+ if (typeof ctx === "object" && ctx !== null)
126
+ return ctx;
127
+ return {};
128
+ }
129
+ function resolveCall(...args) {
130
+ // 1 arg: [msg]
131
+ if (args.length === 1) {
132
+ return { level: lvl.INFO, message: String(args[0]), context: {} };
133
+ }
134
+ // 2 args
135
+ if (args.length === 2) {
136
+ const [first, second] = args;
137
+ if (isLevel(first)) {
138
+ return { level: first, message: String(second), context: {} };
139
+ }
140
+ return {
141
+ level: lvl.INFO,
142
+ message: String(first),
143
+ context: normalizeContext(second),
144
+ };
145
+ }
146
+ // 3+ args: [lvl, msg, ctx]
147
+ if (args.length >= 3) {
148
+ const [first, second, third] = args;
149
+ if (isLevel(first)) {
150
+ return {
151
+ level: first,
152
+ message: String(second),
153
+ context: normalizeContext(third),
154
+ };
155
+ }
156
+ }
157
+ // Fallback
158
+ return { level: lvl.INFO, message: String(args[0] ?? ""), context: {} };
159
+ }
160
+ function getLogLevel() {
161
+ const envLevel = process.env.LOG_LEVEL?.toLowerCase();
162
+ return isLevel(envLevel) ? envLevel : lvl.INFO;
163
+ }
164
+ // ─── Timestamp formatters ─────────────────────────────────────────────────────
165
+ function formatShortTimestamp(ts) {
166
+ const d = new Date(ts);
167
+ const hh = String(d.getHours()).padStart(2, "0");
168
+ const mm = String(d.getMinutes()).padStart(2, "0");
169
+ const ss = String(d.getSeconds()).padStart(2, "0");
170
+ const ms = String(d.getMilliseconds()).padStart(3, "0");
171
+ return `${hh}:${mm}:${ss}.${ms}`;
172
+ }
173
+ // ─── Pretty transport ─────────────────────────────────────────────────────────
174
+ /**
175
+ * Create a built-in pretty console transport.
176
+ *
177
+ * Renders log entries to a human-readable format with optional ANSI colors.
178
+ *
179
+ * Output format:
180
+ * ```
181
+ * {dim timestamp} {colored TAG} {[mod] [mod]} {message} {dim context}
182
+ * ```
183
+ *
184
+ * Err instances in context are rendered via `Err.toString()` on their own
185
+ * indented line below the main line.
186
+ *
187
+ * @param options - Optional configuration
188
+ */
189
+ function prettyTransport(options) {
190
+ const output = options?.output ?? process.stderr;
191
+ const colorsOpt = options?.colors ?? "auto";
192
+ const tsOpt = options?.timestamp ?? "short";
193
+ const levelColors = { ...DEFAULT_LEVEL_COLORS, ...options?.levelColors };
194
+ const isTTY = "isTTY" in output && output.isTTY === true;
195
+ const useColors = colorsOpt === "auto" ? isTTY : colorsOpt === true;
196
+ function formatTimestamp(ts) {
197
+ if (typeof tsOpt === "function")
198
+ return tsOpt(ts);
199
+ if (tsOpt === "iso")
200
+ return new Date(ts).toISOString();
201
+ return formatShortTimestamp(ts);
202
+ }
203
+ return {
204
+ write(entry) {
205
+ const ts = formatTimestamp(entry.timestamp);
206
+ const tag = LEVEL_TAGS[entry.level] ?? entry.level.toUpperCase();
207
+ const levelColor = levelColors[entry.level] ?? "";
208
+ // Module prefix
209
+ const modulePrefix = entry.modules.length > 0
210
+ ? `${entry.modules.map((m) => `[${m}]`).join(" ")} `
211
+ : "";
212
+ // Split err from rest of context
213
+ const { err: errVal, ...rest } = entry.context;
214
+ const hasErr = errVal !== undefined;
215
+ const hasRest = Object.keys(rest).length > 0;
216
+ let line;
217
+ if (useColors) {
218
+ const ctxStr = hasRest ? ` ${DIM}${stringifySafe(rest)}${RESET}` : "";
219
+ line = `${DIM}${ts}${RESET} ${levelColor}${tag}${RESET} ${modulePrefix}${entry.message}${ctxStr}`;
220
+ }
221
+ else {
222
+ const ctxStr = hasRest ? ` ${stringifySafe(rest)}` : "";
223
+ line = `${ts} ${tag} ${modulePrefix}${entry.message}${ctxStr}`;
224
+ }
225
+ if (hasErr) {
226
+ let errStr;
227
+ if (Err.isErr(errVal)) {
228
+ errStr = errVal.toString({ stack: 3, metadata: true });
229
+ }
230
+ else {
231
+ errStr = stringifySafe(errVal);
232
+ }
233
+ const indented = errStr
234
+ .split("\n")
235
+ .map((l) => ` ${l}`)
236
+ .join("\n");
237
+ line += `\n err: ${indented.trimStart()}`;
238
+ }
239
+ output.write(`${line}\n`);
240
+ },
241
+ };
242
+ }
243
+ // ─── Core logger builder ──────────────────────────────────────────────────────
244
+ function buildLogger(modules, bindings, level, transports) {
245
+ const configNum = LEVEL_NUMBERS[level];
246
+ const logFn = (...args) => {
247
+ const { level: callLevel, message, context } = resolveCall(...args);
248
+ if ((LEVEL_NUMBERS[callLevel] ?? 0) < configNum)
249
+ return;
250
+ const entry = {
251
+ level: callLevel,
252
+ timestamp: Date.now(),
253
+ message,
254
+ context: { ...bindings, ...context },
255
+ modules,
256
+ };
257
+ for (const transport of transports) {
258
+ transport.write(entry);
259
+ }
260
+ };
261
+ // Attach level constants
262
+ const keys = Object.keys(lvl);
263
+ for (const key of keys) {
264
+ Object.defineProperty(logFn, key, {
265
+ value: lvl[key],
266
+ writable: false,
267
+ enumerable: true,
268
+ });
269
+ }
270
+ // Attach child()
271
+ logFn.child = (name, childBindings) => {
272
+ const mergedBindings = {
273
+ ...bindings,
274
+ ...childBindings,
275
+ };
276
+ return buildLogger([...modules, name], mergedBindings, level, transports);
277
+ };
278
+ return logFn;
279
+ }
280
+ // ─── Public factory ───────────────────────────────────────────────────────────
281
+ /**
282
+ * Create a logger instance with optional module name and configuration.
283
+ *
284
+ * @param module - Optional module name added as the first entry in `modules`
285
+ * @param options - Optional configuration
286
+ * @returns New Logger instance
287
+ *
288
+ * @example Basic usage
289
+ * ```typescript
290
+ * const logger = createLogger();
291
+ * logger('Application ready');
292
+ * ```
293
+ *
294
+ * @example Module-specific logger
295
+ * ```typescript
296
+ * const dbLogger = createLogger('database');
297
+ * dbLogger('Connected');
298
+ * ```
299
+ *
300
+ * @example Testing with spy transport
301
+ * ```typescript
302
+ * import type { LogEntry, LogTransport } from './utils/logger';
303
+ *
304
+ * const entries: LogEntry[] = [];
305
+ * const spy: LogTransport = { write(e) { entries.push(e); } };
306
+ * const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
307
+ * ```
308
+ */
309
+ function createLogger(module, options) {
310
+ const level = options?.level ?? getLogLevel();
311
+ const transports = options?.transports ?? [prettyTransport()];
312
+ const modules = module ? [module] : [];
313
+ return buildLogger(modules, {}, level, transports);
314
+ }
315
+ /**
316
+ * Default logger instance for application-wide logging.
317
+ *
318
+ * @example Basic usage
319
+ * ```typescript
320
+ * import { log } from './utils/logger';
321
+ *
322
+ * log('Application started');
323
+ * log(log.INFO, 'Server listening', { port: 3000 });
324
+ * log(log.ERROR, 'Startup failed', err);
325
+ * ```
326
+ *
327
+ * @example Module-specific logging via child
328
+ * ```typescript
329
+ * const dbLogger = log.child('database');
330
+ * dbLogger('Connection pool initialized');
331
+ * ```
332
+ */
333
+ export const log = createLogger();
334
+ export { createLogger, prettyTransport, lvl };
335
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../../src/utils/logger.ts"],"names":[],"mappings":"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"}