@resq-sw/logger 0.1.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.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # @resq-sw/logger
2
+
3
+ > Structured logging with log levels, decorators, and singleton management for Node.js and Bun.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @resq-sw/logger
9
+ ```
10
+
11
+ Zero runtime dependencies.
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { Logger, LogLevel } from "@resq-sw/logger";
17
+
18
+ const log = Logger.getLogger("[MyService]");
19
+
20
+ log.info("Server started", { port: 3000 });
21
+ log.warn("Disk usage high", { percent: 92 });
22
+ log.error("Connection failed", new Error("timeout"), { host: "db" });
23
+ log.debug("Cache hit", { key: "user:123" });
24
+ ```
25
+
26
+ Output format: `YYYY-MM-DD HH:mm:ss.SSS LEVEL [context] message {data}`
27
+
28
+ ## API Reference
29
+
30
+ ### Logger Class
31
+
32
+ #### `Logger.getLogger(context, options?): Logger`
33
+
34
+ Returns a singleton Logger instance for the given context. Subsequent calls with the same context return the same instance.
35
+
36
+ #### `new Logger(context, options?)`
37
+
38
+ Creates a new Logger instance.
39
+
40
+ | Option | Type | Default | Description |
41
+ |--------|------|---------|-------------|
42
+ | `minLevel` | `LogLevel` | env-based | Minimum log level |
43
+ | `includeTimestamp` | `boolean` | -- | Include timestamps |
44
+ | `colorize` | `boolean` | -- | Colorize output |
45
+ | `logToFile` | `boolean` | -- | Write to file (server-side) |
46
+ | `filePath` | `string` | -- | Log file path |
47
+
48
+ **Level resolution priority**: `options.minLevel` > `LOG_LEVEL` env > `BUN_LOG_LEVEL` env > `LogLevel.ERROR` (production) / `LogLevel.ALL` (development).
49
+
50
+ #### `Logger.setGlobalLogLevel(level: LogLevel): void`
51
+
52
+ Sets the minimum log level for all existing logger instances.
53
+
54
+ ### Log Levels
55
+
56
+ ```ts
57
+ enum LogLevel {
58
+ NONE = 0, // No logging
59
+ ERROR = 1, // Errors only
60
+ WARN = 2, // Errors + warnings
61
+ INFO = 3, // + informational
62
+ DEBUG = 4, // + debug messages
63
+ TRACE = 5, // + trace messages
64
+ ALL = 6, // Everything
65
+ }
66
+ ```
67
+
68
+ ### Logging Methods
69
+
70
+ All methods accept an optional `data` parameter (`Record<string, unknown>`).
71
+
72
+ | Method | Min Level | Console Method | Description |
73
+ |--------|-----------|----------------|-------------|
74
+ | `info(message, data?)` | `INFO` | `console.info` | Informational messages |
75
+ | `error(message, error?, data?)` | `ERROR` | `console.error` | Errors (auto-serializes Error objects) |
76
+ | `warn(message, data?)` | `WARN` | `console.warn` | Warnings |
77
+ | `debug(message, data?)` | `DEBUG` | `console.debug` | Debug messages |
78
+ | `trace(message, data?)` | `TRACE` | `console.debug` | Trace messages (most verbose) |
79
+ | `action(message, data?)` | `INFO` | `console.info` | Server actions / user interactions |
80
+ | `success(message, data?)` | `INFO` | `console.info` | Success confirmations |
81
+
82
+ ### Grouping
83
+
84
+ ```ts
85
+ log.group("Request Processing");
86
+ log.info("Step 1");
87
+ log.info("Step 2");
88
+ log.groupEnd();
89
+ ```
90
+
91
+ ### Timing
92
+
93
+ #### `logger.time<T>(label, fn): Promise<T>`
94
+
95
+ Measures and logs execution time of a sync or async function.
96
+
97
+ ```ts
98
+ const result = await log.time("DB query", async () => {
99
+ return await db.query("SELECT * FROM users");
100
+ });
101
+ // Logs: "DB query completed" { duration: "12.34ms" }
102
+ ```
103
+
104
+ On error, logs the failure with duration and rethrows.
105
+
106
+ ## Decorators
107
+
108
+ ### `@Log(options?)`
109
+
110
+ Logs method entry and exit with optional argument and return value logging.
111
+
112
+ | Option | Type | Default | Description |
113
+ |--------|------|---------|-------------|
114
+ | `logArgs` | `boolean` | `true` | Log method arguments |
115
+ | `logResult` | `boolean` | `false` | Log return value |
116
+ | `message` | `string` | method name | Custom message prefix |
117
+ | `level` | `LogLevelString` | `"debug"` | Log level to use |
118
+
119
+ ```ts
120
+ class UserService {
121
+ @Log({ logArgs: true, logResult: true, level: "info" })
122
+ async getUser(id: string) { return { id, name: "John" }; }
123
+ }
124
+ ```
125
+
126
+ ### `@LogTiming(options?)`
127
+
128
+ Logs method execution time. Works with both sync and async methods.
129
+
130
+ | Option | Type | Default | Description |
131
+ |--------|------|---------|-------------|
132
+ | `label` | `string` | `ClassName.methodName` | Custom timing label |
133
+ | `threshold` | `number` | `0` | Only log if duration exceeds this (ms) |
134
+ | `level` | `LogLevelString` | `"info"` | Log level to use |
135
+
136
+ ```ts
137
+ class DataService {
138
+ @LogTiming({ threshold: 100 })
139
+ async fetchData() { /* only logged if > 100ms */ }
140
+ }
141
+ ```
142
+
143
+ ### `@LogError(options?)`
144
+
145
+ Wraps method in try/catch, logs errors with stack traces.
146
+
147
+ | Option | Type | Default | Description |
148
+ |--------|------|---------|-------------|
149
+ | `rethrow` | `boolean` | `true` | Rethrow after logging |
150
+ | `message` | `string` | `"<method> error"` | Custom error prefix |
151
+ | `includeStack` | `boolean` | `true` | Include stack trace in log |
152
+
153
+ ```ts
154
+ class Api {
155
+ @LogError({ rethrow: false, message: "API call failed" })
156
+ async callApi() { throw new Error("Network error"); }
157
+ // Error is logged but swallowed; method returns undefined
158
+ }
159
+ ```
160
+
161
+ ### `@LogClass(options?)`
162
+
163
+ Class decorator that applies logging to all methods on the prototype.
164
+
165
+ | Option | Type | Default | Description |
166
+ |--------|------|---------|-------------|
167
+ | `exclude` | `string[]` | `[]` | Method names to skip |
168
+ | `logCalls` | `boolean` | `true` | Log method entry/exit |
169
+ | `timing` | `boolean` | `false` | Log execution times |
170
+
171
+ ```ts
172
+ @LogClass({ exclude: ["internalHelper"], timing: true })
173
+ class MyService {
174
+ publicMethod() { /* logged with timing */ }
175
+ internalHelper() { /* not logged */ }
176
+ }
177
+ ```
178
+
179
+ ## Types
180
+
181
+ Exported types: `LogData`, `LoggerOptions`, `LogLevel`, `LogLevelString`, `ColorKey`, `LogEntry`, `LogTransport`, `LogMethodOptions`, `LogTimingOptions`, `LogErrorOptions`, `LogClassOptions`.
182
+
183
+ ## License
184
+
185
+ Apache-2.0
package/lib/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { ColorKey, LogData, LogLevel, Logger, LoggerOptions, logger } from "./logger.js";
2
+ import { LogClassOptions, LogEntry, LogErrorOptions, LogLevelString, LogMethodOptions, LogTimingOptions, LogTransport } from "./logger.types.js";
3
+ import { Log, LogClass, LogError, LogTiming } from "./logger.decorators.js";
4
+ export { ColorKey, Log, LogClass, type LogClassOptions, LogData, type LogEntry, LogError, type LogErrorOptions, LogLevel, type LogLevelString, type LogMethodOptions, LogTiming, type LogTimingOptions, type LogTransport, Logger, LoggerOptions, logger };
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { LogLevel, Logger, logger } from "./logger.js";
2
+ import { Log, LogClass, LogError, LogTiming } from "./logger.decorators.js";
3
+ export { Log, LogClass, LogError, LogLevel, LogTiming, Logger, logger };
@@ -0,0 +1,210 @@
1
+ //#region src/logger.d.ts
2
+ /**
3
+ * Copyright (c) 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * @fileoverview A comprehensive logging utility for both client and server environments.
19
+ * Provides structured logging with support for different log levels, colorization,
20
+ * and contextual information.
21
+ *
22
+ * This logger uses native console methods with structured formatting — no external
23
+ * dependencies are required. Log output follows the pattern:
24
+ * TIMESTAMP LEVEL [CONTEXT] message { data }
25
+ */
26
+ /**
27
+ * Enum representing different logging levels with their priority values.
28
+ * Higher values indicate more verbose logging.
29
+ * @enum {number}
30
+ */
31
+ declare enum LogLevel {
32
+ /** No logging */
33
+ NONE = 0,
34
+ /** Only error messages */
35
+ ERROR = 1,
36
+ /** Errors and warnings */
37
+ WARN = 2,
38
+ /** Errors, warnings, and informational messages */
39
+ INFO = 3,
40
+ /** Errors, warnings, info, and debug messages */
41
+ DEBUG = 4,
42
+ /** Errors, warnings, info, debug, and trace messages */
43
+ TRACE = 5,
44
+ /** All possible log messages */
45
+ ALL = 6
46
+ }
47
+ /**
48
+ * Available color keys for log formatting
49
+ * @typedef {'reset' | 'red' | 'yellow' | 'blue' | 'green' | 'gray' | 'bold' | 'magenta' | 'cyan' | 'white'} ColorKey
50
+ */
51
+ type ColorKey = 'reset' | 'red' | 'yellow' | 'blue' | 'green' | 'gray' | 'bold' | 'magenta' | 'cyan' | 'white';
52
+ /**
53
+ * Interface for structured data that can be attached to log messages
54
+ * @interface
55
+ */
56
+ interface LogData {
57
+ /**
58
+ * Any key-value pairs to include in the log
59
+ */
60
+ [key: string]: unknown;
61
+ }
62
+ /**
63
+ * Configuration options for the Logger
64
+ * @interface
65
+ */
66
+ interface LoggerOptions {
67
+ /**
68
+ * The minimum level of messages to log
69
+ */
70
+ minLevel?: LogLevel;
71
+ /**
72
+ * Whether to include timestamps in log messages
73
+ */
74
+ includeTimestamp?: boolean;
75
+ /**
76
+ * Whether to colorize log output
77
+ */
78
+ colorize?: boolean;
79
+ /**
80
+ * Whether to write logs to a file (server-side only)
81
+ */
82
+ logToFile?: boolean;
83
+ /**
84
+ * Path to the log file if logToFile is enabled
85
+ */
86
+ filePath?: string;
87
+ }
88
+ /**
89
+ * A versatile logging utility that works in both browser and Node.js environments.
90
+ * Supports multiple log levels, colorized output, and structured data logging.
91
+ */
92
+ declare class Logger {
93
+ /** The context/category name for this logger instance */
94
+ private readonly context;
95
+ /** The minimum log level that will be output */
96
+ private minLevel;
97
+ /**
98
+ * Parse log level from string or return default
99
+ */
100
+ private static parseLevel;
101
+ /** Registry of logger instances to implement the singleton pattern */
102
+ private static readonly instances;
103
+ /**
104
+ * Create a new Logger instance or return an existing one for the given context
105
+ * @param {string} context - The context name for this logger (e.g., component or service name)
106
+ * @param {LoggerOptions} [options={}] - Optional logger configuration
107
+ */
108
+ constructor(context: string, options?: LoggerOptions);
109
+ /**
110
+ * Get a logger instance for the given context.
111
+ * If a logger with this context already exists, returns the existing instance.
112
+ *
113
+ * @param {string} context - The context name
114
+ * @param {LoggerOptions} [options] - Optional logger configuration
115
+ * @returns {Logger} A logger instance for the specified context
116
+ */
117
+ static getLogger(context: string, options?: LoggerOptions): Logger;
118
+ /**
119
+ * Set global minimum log level for all logger instances
120
+ *
121
+ * @param {LogLevel} level - The minimum level to log across all loggers
122
+ */
123
+ static setGlobalLogLevel(level: LogLevel): void;
124
+ /**
125
+ * Format a timestamp for log output
126
+ */
127
+ private formatTimestamp;
128
+ /**
129
+ * Format structured log data into a readable suffix string.
130
+ * Returns empty string if data is null/empty.
131
+ */
132
+ private formatData;
133
+ /**
134
+ * Emit a log entry using the appropriate console method
135
+ */
136
+ private emit;
137
+ /**
138
+ * Log an informational message
139
+ *
140
+ * @param {string} message - The message to log
141
+ * @param {LogData} [data] - Optional data to include
142
+ */
143
+ info(message: string, data?: LogData): void;
144
+ /**
145
+ * Log an error message
146
+ *
147
+ * @param {string} message - The error message
148
+ * @param {Error|unknown} [error] - Optional Error object or unknown error
149
+ * @param {LogData} [data] - Optional additional data
150
+ */
151
+ error(message: string, error?: unknown, data?: LogData): void;
152
+ /**
153
+ * Log a warning message
154
+ *
155
+ * @param {string} message - The warning message
156
+ * @param {LogData} [data] - Optional data to include
157
+ */
158
+ warn(message: string, data?: LogData): void;
159
+ /**
160
+ * Log a debug message
161
+ *
162
+ * @param {string} message - The debug message
163
+ * @param {LogData} [data] - Optional data to include
164
+ */
165
+ debug(message: string, data?: LogData): void;
166
+ /**
167
+ * Log a trace message (most verbose level)
168
+ *
169
+ * @param {string} message - The trace message
170
+ * @param {LogData} [data] - Optional data to include
171
+ */
172
+ trace(message: string, data?: LogData): void;
173
+ /**
174
+ * Log an action message (for server actions or important user interactions)
175
+ *
176
+ * @param {string} message - The action message
177
+ * @param {LogData} [data] - Optional data to include
178
+ */
179
+ action(message: string, data?: LogData): void;
180
+ /**
181
+ * Log a success message
182
+ *
183
+ * @param {string} message - The success message
184
+ * @param {LogData} [data] - Optional data to include
185
+ */
186
+ success(message: string, data?: LogData): void;
187
+ /**
188
+ * Group related log messages (console.group wrapper)
189
+ *
190
+ * @param {string} label - The group label
191
+ */
192
+ group(label: string): void;
193
+ /**
194
+ * End a log group (console.groupEnd wrapper)
195
+ */
196
+ groupEnd(): void;
197
+ /**
198
+ * Log execution time of a function
199
+ *
200
+ * @template T - The return type of the function being timed
201
+ * @param {string} label - Description of the operation being timed
202
+ * @param {() => Promise<T> | T} fn - Function to execute and time
203
+ * @returns {Promise<T>} The result of the function execution
204
+ */
205
+ time<T>(label: string, fn: () => Promise<T> | T): Promise<T>;
206
+ }
207
+ declare const logger: Logger;
208
+ //#endregion
209
+ export { ColorKey, LogData, LogLevel, Logger, LoggerOptions, logger };
210
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","names":[],"sources":["../src/logger.ts"],"mappings":";;AA+BA;;;;;;;;;;;;;AAqBA;;;;;AAgBA;;;;;AAWA;;;;;AAAA,aAhDY,QAAA;EAyDV;EAvDA,IAAA;EAiEA;EA/DA,KAAA;EAoEQ;EAlER,IAAA;EAyEW;EAvEX,IAAA;EAuEiB;EArEjB,KAAA;EA2HmD;EAzHnD,KAAA;EAyIuC;EAvIvC,GAAA;AAAA;;;;;KAOU,QAAA;;;;;UAgBK,OAAA;EAgRgD;;;EAAA,CA5Q9D,GAAA;AAAA;;;;;UAOc,aAAA;EAqFD;;;EAjFd,QAAA,GAAW,QAAA;EAiFwD;;;EA5EnE,gBAAA;EAqGQ;;;EAhGR,QAAA;EA6IK;;;EAxIL,SAAA;EAoJM;;;EA/IN,QAAA;AAAA;;;;;cAOW,MAAA;EAsKmB;EAAA,iBApKb,OAAA;EA+KjB;EAAA,QA5KQ,QAAA;EA4KsB;;;EAAA,eAvKf,UAAA;EAkLgB;EAAA,wBAlKP,SAAA;EA6KxB;;;;;cAtKY,OAAA,UAAiB,OAAA,GAAS,aAAA;EAwLtC;;;;;;;;EAAA,OAnKc,SAAA,CAAU,OAAA,UAAiB,OAAA,GAAU,aAAA,GAAgB,MAAA;EAgLH;;;AAmBlE;;EAnBkE,OAhKlD,iBAAA,CAAkB,KAAA,EAAO,QAAA;EAmLtB;;;EAAA,QA1KT,eAAA;;;;;UAgBA,UAAA;;;;UAYA,IAAA;;;;;;;EAiBR,IAAA,CAAK,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;;;EAY7B,KAAA,CAAM,OAAA,UAAiB,KAAA,YAAiB,IAAA,GAAO,OAAA;;;;;;;EAmB/C,IAAA,CAAK,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;;EAW7B,KAAA,CAAM,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;;EAW9B,KAAA,CAAM,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;;EAW9B,MAAA,CAAO,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;;EAW/B,OAAA,CAAQ,OAAA,UAAiB,IAAA,GAAO,OAAA;;;;;;EAUhC,KAAA,CAAM,KAAA;;;;EAQN,QAAA,CAAA;;;;;;;;;EAaM,IAAA,GAAA,CAAQ,KAAA,UAAe,EAAA,QAAU,OAAA,CAAQ,CAAA,IAAK,CAAA,GAAI,OAAA,CAAQ,CAAA;AAAA;AAAA,cAmBrD,MAAA,EAAM,MAAA"}
@@ -0,0 +1,77 @@
1
+ import { LogClassOptions, LogErrorOptions, LogMethodOptions, LogTimingOptions } from "./logger.types.js";
2
+
3
+ //#region src/logger.decorators.d.ts
4
+ /**
5
+ * Decorator that logs method entry and exit.
6
+ * Can optionally log arguments and return values.
7
+ *
8
+ * @param {LogMethodOptions} [options={}] - Configuration options
9
+ * @returns {MethodDecorator} The decorator function
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * class UserService {
14
+ * @Log({ logArgs: true, logResult: true })
15
+ * async getUser(id: string) {
16
+ * return { id, name: 'John' };
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ declare function Log(options?: LogMethodOptions): MethodDecorator;
22
+ /**
23
+ * Decorator that logs method execution time.
24
+ * Useful for performance monitoring.
25
+ *
26
+ * @param {LogTimingOptions} [options={}] - Configuration options
27
+ * @returns {MethodDecorator} The decorator function
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * class DataService {
32
+ * @LogTiming({ threshold: 100 }) // Only log if execution > 100ms
33
+ * async fetchData() {
34
+ * // ... slow operation
35
+ * }
36
+ * }
37
+ * ```
38
+ */
39
+ declare function LogTiming(options?: LogTimingOptions): MethodDecorator;
40
+ /**
41
+ * Decorator that wraps method in try/catch and logs errors.
42
+ * Can optionally suppress the error or rethrow it.
43
+ *
44
+ * @param {LogErrorOptions} [options={}] - Configuration options
45
+ * @returns {MethodDecorator} The decorator function
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * class ApiService {
50
+ * @LogError({ rethrow: false, message: 'API call failed' })
51
+ * async callApi() {
52
+ * throw new Error('Network error');
53
+ * }
54
+ * }
55
+ * ```
56
+ */
57
+ declare function LogError(options?: LogErrorOptions): MethodDecorator;
58
+ /**
59
+ * Class decorator that applies logging to all methods of a class.
60
+ * Can be configured to exclude specific methods.
61
+ *
62
+ * @param {LogClassOptions} [options={}] - Configuration options
63
+ * @returns {ClassDecorator} The decorator function
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * @LogClass({ exclude: ['privateMethod'], timing: true })
68
+ * class MyService {
69
+ * publicMethod() { ... }
70
+ * privateMethod() { ... } // Won't be logged
71
+ * }
72
+ * ```
73
+ */
74
+ declare function LogClass(options?: LogClassOptions): <T extends new (...args: unknown[]) => object>(target: T) => T;
75
+ //#endregion
76
+ export { Log, LogClass, LogError, LogTiming };
77
+ //# sourceMappingURL=logger.decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.decorators.d.ts","names":[],"sources":["../src/logger.decorators.ts"],"mappings":";;;;;;;;AAqLA;;;;;;;;;AAgEA;;;iBAvMgB,GAAA,CAAI,OAAA,GAAS,gBAAA,GAAwB,eAAA;;;;;;;;;;;;;;;;;;iBA2ErC,SAAA,CAAU,OAAA,GAAS,gBAAA,GAAwB,eAAA;;;;;;;;;;;;;;;;;;iBA4D3C,QAAA,CAAS,OAAA,GAAS,eAAA,GAAuB,eAAA;;;;;;;;;;;;;;;;;iBAgEzC,QAAA,CACd,OAAA,GAAS,eAAA,sBACW,IAAA,wBAA4B,MAAA,EAAQ,CAAA,KAAM,CAAA"}
@@ -0,0 +1,208 @@
1
+ import { Logger } from "./logger.js";
2
+ //#region src/logger.decorators.ts
3
+ /**
4
+ * Copyright 2026 ResQ
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ /**
19
+ * @fileoverview TypeScript decorators for logging method calls, timing, and errors.
20
+ * These decorators integrate with the Logger class to provide declarative logging.
21
+ */
22
+ /**
23
+ * Decorator that logs method entry and exit.
24
+ * Can optionally log arguments and return values.
25
+ *
26
+ * @param {LogMethodOptions} [options={}] - Configuration options
27
+ * @returns {MethodDecorator} The decorator function
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * class UserService {
32
+ * @Log({ logArgs: true, logResult: true })
33
+ * async getUser(id: string) {
34
+ * return { id, name: 'John' };
35
+ * }
36
+ * }
37
+ * ```
38
+ */
39
+ function Log(options = {}) {
40
+ const { logArgs = true, logResult = false, message, level = "debug" } = options;
41
+ return (target, propertyKey, descriptor) => {
42
+ const originalMethod = descriptor.value;
43
+ const methodName = String(propertyKey);
44
+ const className = target.constructor.name;
45
+ descriptor.value = function(...args) {
46
+ const logger = Logger.getLogger(`[${className}]`);
47
+ const prefix = message || `${methodName}`;
48
+ if (logArgs && args.length > 0) logger[level](`${prefix} called`, { arguments: args });
49
+ else logger[level](`${prefix} called`);
50
+ const result = originalMethod.apply(this, args);
51
+ if (result instanceof Promise) return result.then((value) => {
52
+ if (logResult) logger[level](`${prefix} returned`, { result: value });
53
+ else logger[level](`${prefix} completed`);
54
+ return value;
55
+ }, (error) => {
56
+ logger.error(`${prefix} failed`, error);
57
+ throw error;
58
+ });
59
+ if (logResult) logger[level](`${prefix} returned`, { result });
60
+ else logger[level](`${prefix} completed`);
61
+ return result;
62
+ };
63
+ return descriptor;
64
+ };
65
+ }
66
+ /**
67
+ * Decorator that logs method execution time.
68
+ * Useful for performance monitoring.
69
+ *
70
+ * @param {LogTimingOptions} [options={}] - Configuration options
71
+ * @returns {MethodDecorator} The decorator function
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * class DataService {
76
+ * @LogTiming({ threshold: 100 }) // Only log if execution > 100ms
77
+ * async fetchData() {
78
+ * // ... slow operation
79
+ * }
80
+ * }
81
+ * ```
82
+ */
83
+ function LogTiming(options = {}) {
84
+ const { label, threshold = 0, level = "info" } = options;
85
+ return (target, propertyKey, descriptor) => {
86
+ const originalMethod = descriptor.value;
87
+ const methodName = String(propertyKey);
88
+ const className = target.constructor.name;
89
+ descriptor.value = function(...args) {
90
+ const logger = Logger.getLogger(`[${className}]`);
91
+ const timerLabel = label || `${className}.${methodName}`;
92
+ const startTime = performance.now();
93
+ const result = originalMethod.apply(this, args);
94
+ if (result instanceof Promise) return result.finally(() => {
95
+ const duration = performance.now() - startTime;
96
+ if (duration >= threshold) logger[level](`${timerLabel} completed in ${duration.toFixed(2)}ms`);
97
+ });
98
+ const duration = performance.now() - startTime;
99
+ if (duration >= threshold) logger[level](`${timerLabel} completed in ${duration.toFixed(2)}ms`);
100
+ return result;
101
+ };
102
+ return descriptor;
103
+ };
104
+ }
105
+ /**
106
+ * Decorator that wraps method in try/catch and logs errors.
107
+ * Can optionally suppress the error or rethrow it.
108
+ *
109
+ * @param {LogErrorOptions} [options={}] - Configuration options
110
+ * @returns {MethodDecorator} The decorator function
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * class ApiService {
115
+ * @LogError({ rethrow: false, message: 'API call failed' })
116
+ * async callApi() {
117
+ * throw new Error('Network error');
118
+ * }
119
+ * }
120
+ * ```
121
+ */
122
+ function LogError(options = {}) {
123
+ const { rethrow = true, message, includeStack = true } = options;
124
+ return (target, propertyKey, descriptor) => {
125
+ const originalMethod = descriptor.value;
126
+ const methodName = String(propertyKey);
127
+ const className = target.constructor.name;
128
+ descriptor.value = function(...args) {
129
+ const logger = Logger.getLogger(`[${className}]`);
130
+ const errorPrefix = message || `${methodName} error`;
131
+ try {
132
+ const result = originalMethod.apply(this, args);
133
+ if (result instanceof Promise) return result.catch((error) => {
134
+ const errorData = { method: methodName };
135
+ if (error instanceof Error && includeStack) errorData["stack"] = error.stack;
136
+ logger.error(errorPrefix, error, errorData);
137
+ if (rethrow) throw error;
138
+ });
139
+ return result;
140
+ } catch (error) {
141
+ const errorData = { method: methodName };
142
+ if (error instanceof Error && includeStack) errorData["stack"] = error.stack;
143
+ logger.error(errorPrefix, error, errorData);
144
+ if (rethrow) throw error;
145
+ return;
146
+ }
147
+ };
148
+ return descriptor;
149
+ };
150
+ }
151
+ /**
152
+ * Class decorator that applies logging to all methods of a class.
153
+ * Can be configured to exclude specific methods.
154
+ *
155
+ * @param {LogClassOptions} [options={}] - Configuration options
156
+ * @returns {ClassDecorator} The decorator function
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * @LogClass({ exclude: ['privateMethod'], timing: true })
161
+ * class MyService {
162
+ * publicMethod() { ... }
163
+ * privateMethod() { ... } // Won't be logged
164
+ * }
165
+ * ```
166
+ */
167
+ function LogClass(options = {}) {
168
+ const { exclude = [], logCalls = true, timing = false } = options;
169
+ return (target) => {
170
+ const className = target.name;
171
+ const prototype = target.prototype;
172
+ if (prototype) {
173
+ const methodNames = Object.getOwnPropertyNames(prototype).filter((name) => name !== "constructor" && typeof prototype[name] === "function" && !exclude.includes(name));
174
+ for (const methodName of methodNames) {
175
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName);
176
+ if (!descriptor) continue;
177
+ const originalMethod = descriptor.value;
178
+ descriptor.value = function(...args) {
179
+ const logger = Logger.getLogger(`[${className}]`);
180
+ const startTime = timing ? performance.now() : 0;
181
+ if (logCalls) logger.debug(`${methodName} called`, { arguments: args });
182
+ const result = originalMethod.apply(this, args);
183
+ if (result instanceof Promise) return result.then((value) => {
184
+ if (timing) {
185
+ const duration = performance.now() - startTime;
186
+ logger.debug(`${methodName} completed in ${duration.toFixed(2)}ms`);
187
+ } else if (logCalls) logger.debug(`${methodName} completed`);
188
+ return value;
189
+ }, (error) => {
190
+ logger.error(`${methodName} failed`, error);
191
+ throw error;
192
+ });
193
+ if (timing) {
194
+ const duration = performance.now() - startTime;
195
+ logger.debug(`${methodName} completed in ${duration.toFixed(2)}ms`);
196
+ } else if (logCalls) logger.debug(`${methodName} completed`);
197
+ return result;
198
+ };
199
+ Object.defineProperty(prototype, methodName, descriptor);
200
+ }
201
+ }
202
+ return target;
203
+ };
204
+ }
205
+ //#endregion
206
+ export { Log, LogClass, LogError, LogTiming };
207
+
208
+ //# sourceMappingURL=logger.decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.decorators.js","names":[],"sources":["../src/logger.decorators.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview TypeScript decorators for logging method calls, timing, and errors.\n * These decorators integrate with the Logger class to provide declarative logging.\n */\n\nimport { Logger } from './logger.js';\nimport type {\n LogClassOptions,\n LogErrorOptions,\n LogMethodOptions,\n LogTimingOptions,\n} from './logger.types.js';\n\n/**\n * Decorator that logs method entry and exit.\n * Can optionally log arguments and return values.\n *\n * @param {LogMethodOptions} [options={}] - Configuration options\n * @returns {MethodDecorator} The decorator function\n *\n * @example\n * ```typescript\n * class UserService {\n * @Log({ logArgs: true, logResult: true })\n * async getUser(id: string) {\n * return { id, name: 'John' };\n * }\n * }\n * ```\n */\nexport function Log(options: LogMethodOptions = {}): MethodDecorator {\n const { logArgs = true, logResult = false, message, level = 'debug' } = options;\n\n return (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ): PropertyDescriptor => {\n const originalMethod = descriptor.value;\n const methodName = String(propertyKey);\n const className = target.constructor.name;\n\n descriptor.value = function (...args: unknown[]) {\n const logger = Logger.getLogger(`[${className}]`);\n const prefix = message || `${methodName}`;\n\n // Log method entry\n if (logArgs && args.length > 0) {\n logger[level](`${prefix} called`, { arguments: args });\n } else {\n logger[level](`${prefix} called`);\n }\n\n // Execute the original method\n const result = originalMethod.apply(this, args);\n\n // Handle async methods\n if (result instanceof Promise) {\n return result.then(\n (value: unknown) => {\n if (logResult) {\n logger[level](`${prefix} returned`, { result: value });\n } else {\n logger[level](`${prefix} completed`);\n }\n return value;\n },\n (error: unknown) => {\n logger.error(`${prefix} failed`, error);\n throw error;\n },\n );\n }\n\n // Log sync method result\n if (logResult) {\n logger[level](`${prefix} returned`, { result });\n } else {\n logger[level](`${prefix} completed`);\n }\n\n return result;\n };\n\n return descriptor;\n };\n}\n\n/**\n * Decorator that logs method execution time.\n * Useful for performance monitoring.\n *\n * @param {LogTimingOptions} [options={}] - Configuration options\n * @returns {MethodDecorator} The decorator function\n *\n * @example\n * ```typescript\n * class DataService {\n * @LogTiming({ threshold: 100 }) // Only log if execution > 100ms\n * async fetchData() {\n * // ... slow operation\n * }\n * }\n * ```\n */\nexport function LogTiming(options: LogTimingOptions = {}): MethodDecorator {\n const { label, threshold = 0, level = 'info' } = options;\n\n return (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ): PropertyDescriptor => {\n const originalMethod = descriptor.value;\n const methodName = String(propertyKey);\n const className = target.constructor.name;\n\n descriptor.value = function (...args: unknown[]) {\n const logger = Logger.getLogger(`[${className}]`);\n const timerLabel = label || `${className}.${methodName}`;\n const startTime = performance.now();\n\n // Execute the original method\n const result = originalMethod.apply(this, args);\n\n // Handle async methods\n if (result instanceof Promise) {\n return result.finally(() => {\n const duration = performance.now() - startTime;\n if (duration >= threshold) {\n logger[level](`${timerLabel} completed in ${duration.toFixed(2)}ms`);\n }\n });\n }\n\n // Log sync method timing\n const duration = performance.now() - startTime;\n if (duration >= threshold) {\n logger[level](`${timerLabel} completed in ${duration.toFixed(2)}ms`);\n }\n\n return result;\n };\n\n return descriptor;\n };\n}\n\n/**\n * Decorator that wraps method in try/catch and logs errors.\n * Can optionally suppress the error or rethrow it.\n *\n * @param {LogErrorOptions} [options={}] - Configuration options\n * @returns {MethodDecorator} The decorator function\n *\n * @example\n * ```typescript\n * class ApiService {\n * @LogError({ rethrow: false, message: 'API call failed' })\n * async callApi() {\n * throw new Error('Network error');\n * }\n * }\n * ```\n */\nexport function LogError(options: LogErrorOptions = {}): MethodDecorator {\n const { rethrow = true, message, includeStack = true } = options;\n\n return (\n target: object,\n propertyKey: string | symbol,\n descriptor: PropertyDescriptor,\n ): PropertyDescriptor => {\n const originalMethod = descriptor.value;\n const methodName = String(propertyKey);\n const className = target.constructor.name;\n\n descriptor.value = function (...args: unknown[]) {\n const logger = Logger.getLogger(`[${className}]`);\n const errorPrefix = message || `${methodName} error`;\n\n try {\n const result = originalMethod.apply(this, args);\n\n // Handle async methods\n if (result instanceof Promise) {\n return result.catch((error: unknown) => {\n const errorData: Record<string, unknown> = { method: methodName };\n if (error instanceof Error && includeStack) {\n errorData['stack'] = error.stack;\n }\n logger.error(errorPrefix, error, errorData);\n if (rethrow) throw error;\n return undefined;\n });\n }\n\n return result;\n } catch (error) {\n const errorData: Record<string, unknown> = { method: methodName };\n if (error instanceof Error && includeStack) {\n errorData['stack'] = error.stack;\n }\n logger.error(errorPrefix, error, errorData);\n if (rethrow) throw error;\n return undefined;\n }\n };\n\n return descriptor;\n };\n}\n\n/**\n * Class decorator that applies logging to all methods of a class.\n * Can be configured to exclude specific methods.\n *\n * @param {LogClassOptions} [options={}] - Configuration options\n * @returns {ClassDecorator} The decorator function\n *\n * @example\n * ```typescript\n * @LogClass({ exclude: ['privateMethod'], timing: true })\n * class MyService {\n * publicMethod() { ... }\n * privateMethod() { ... } // Won't be logged\n * }\n * ```\n */\nexport function LogClass(\n options: LogClassOptions = {},\n): <T extends new (...args: unknown[]) => object>(target: T) => T {\n const { exclude = [], logCalls = true, timing = false } = options;\n\n return <T extends new (...args: unknown[]) => object>(target: T): T => {\n const className = target.name;\n const prototype = target.prototype;\n\n // Only apply decorators if prototype exists\n if (prototype) {\n // Get all method names from the prototype\n const methodNames = Object.getOwnPropertyNames(prototype).filter(\n (name) =>\n name !== 'constructor' &&\n typeof prototype[name] === 'function' &&\n !exclude.includes(name),\n );\n\n // Apply decorators to each method\n for (const methodName of methodNames) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName);\n if (!descriptor) continue;\n\n const originalMethod = descriptor.value;\n\n descriptor.value = function (...args: unknown[]) {\n const logger = Logger.getLogger(`[${className}]`);\n const startTime = timing ? performance.now() : 0;\n\n if (logCalls) {\n logger.debug(`${methodName} called`, { arguments: args });\n }\n\n const result = originalMethod.apply(this, args);\n\n if (result instanceof Promise) {\n return result.then(\n (value: unknown) => {\n if (timing) {\n const duration = performance.now() - startTime;\n logger.debug(`${methodName} completed in ${duration.toFixed(2)}ms`);\n } else if (logCalls) {\n logger.debug(`${methodName} completed`);\n }\n return value;\n },\n (error: unknown) => {\n logger.error(`${methodName} failed`, error);\n throw error;\n },\n );\n }\n\n if (timing) {\n const duration = performance.now() - startTime;\n logger.debug(`${methodName} completed in ${duration.toFixed(2)}ms`);\n } else if (logCalls) {\n logger.debug(`${methodName} completed`);\n }\n\n return result;\n };\n\n Object.defineProperty(prototype, methodName, descriptor);\n }\n }\n\n return target;\n };\n}\n"],"mappings":"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"}
package/lib/logger.js ADDED
@@ -0,0 +1,268 @@
1
+ //#region src/logger.ts
2
+ /**
3
+ * Copyright (c) 2026 ResQ
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * @fileoverview A comprehensive logging utility for both client and server environments.
19
+ * Provides structured logging with support for different log levels, colorization,
20
+ * and contextual information.
21
+ *
22
+ * This logger uses native console methods with structured formatting — no external
23
+ * dependencies are required. Log output follows the pattern:
24
+ * TIMESTAMP LEVEL [CONTEXT] message { data }
25
+ */
26
+ /**
27
+ * Enum representing different logging levels with their priority values.
28
+ * Higher values indicate more verbose logging.
29
+ * @enum {number}
30
+ */
31
+ let LogLevel = /* @__PURE__ */ function(LogLevel) {
32
+ /** No logging */
33
+ LogLevel[LogLevel["NONE"] = 0] = "NONE";
34
+ /** Only error messages */
35
+ LogLevel[LogLevel["ERROR"] = 1] = "ERROR";
36
+ /** Errors and warnings */
37
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
38
+ /** Errors, warnings, and informational messages */
39
+ LogLevel[LogLevel["INFO"] = 3] = "INFO";
40
+ /** Errors, warnings, info, and debug messages */
41
+ LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG";
42
+ /** Errors, warnings, info, debug, and trace messages */
43
+ LogLevel[LogLevel["TRACE"] = 5] = "TRACE";
44
+ /** All possible log messages */
45
+ LogLevel[LogLevel["ALL"] = 6] = "ALL";
46
+ return LogLevel;
47
+ }({});
48
+ /**
49
+ * A versatile logging utility that works in both browser and Node.js environments.
50
+ * Supports multiple log levels, colorized output, and structured data logging.
51
+ */
52
+ var Logger = class Logger {
53
+ /** The context/category name for this logger instance */
54
+ context;
55
+ /** The minimum log level that will be output */
56
+ minLevel;
57
+ /**
58
+ * Parse log level from string or return default
59
+ */
60
+ static parseLevel(level) {
61
+ if (!level) return void 0;
62
+ switch (level.toUpperCase()) {
63
+ case "NONE": return LogLevel.NONE;
64
+ case "ERROR": return LogLevel.ERROR;
65
+ case "WARN": return LogLevel.WARN;
66
+ case "INFO": return LogLevel.INFO;
67
+ case "DEBUG": return LogLevel.DEBUG;
68
+ case "TRACE": return LogLevel.TRACE;
69
+ case "ALL": return LogLevel.ALL;
70
+ default: return;
71
+ }
72
+ }
73
+ /** Registry of logger instances to implement the singleton pattern */
74
+ static instances = /* @__PURE__ */ new Map();
75
+ /**
76
+ * Create a new Logger instance or return an existing one for the given context
77
+ * @param {string} context - The context name for this logger (e.g., component or service name)
78
+ * @param {LoggerOptions} [options={}] - Optional logger configuration
79
+ */
80
+ constructor(context, options = {}) {
81
+ this.context = context;
82
+ const env = typeof process !== "undefined" ? process.env : {};
83
+ const envLevel = Logger.parseLevel(env["LOG_LEVEL"] || env["BUN_LOG_LEVEL"]);
84
+ this.minLevel = options.minLevel ?? envLevel ?? (env["NODE_ENV"] === "production" ? LogLevel.ERROR : LogLevel.ALL);
85
+ }
86
+ /**
87
+ * Get a logger instance for the given context.
88
+ * If a logger with this context already exists, returns the existing instance.
89
+ *
90
+ * @param {string} context - The context name
91
+ * @param {LoggerOptions} [options] - Optional logger configuration
92
+ * @returns {Logger} A logger instance for the specified context
93
+ */
94
+ static getLogger(context, options) {
95
+ let instance = Logger.instances.get(context);
96
+ if (!instance) {
97
+ instance = new Logger(context, options);
98
+ Logger.instances.set(context, instance);
99
+ }
100
+ return instance;
101
+ }
102
+ /**
103
+ * Set global minimum log level for all logger instances
104
+ *
105
+ * @param {LogLevel} level - The minimum level to log across all loggers
106
+ */
107
+ static setGlobalLogLevel(level) {
108
+ Logger.instances.forEach((logger) => {
109
+ logger.minLevel = level;
110
+ });
111
+ }
112
+ /**
113
+ * Format a timestamp for log output
114
+ */
115
+ formatTimestamp() {
116
+ const now = /* @__PURE__ */ new Date();
117
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}.${String(now.getMilliseconds()).padStart(3, "0")}`;
118
+ }
119
+ /**
120
+ * Format structured log data into a readable suffix string.
121
+ * Returns empty string if data is null/empty.
122
+ */
123
+ formatData(data) {
124
+ if (!data || Object.keys(data).length === 0) return "";
125
+ try {
126
+ return ` ${JSON.stringify(data)}`;
127
+ } catch {
128
+ return " [unserializable data]";
129
+ }
130
+ }
131
+ /**
132
+ * Emit a log entry using the appropriate console method
133
+ */
134
+ emit(consoleFn, level, message, data) {
135
+ const ts = this.formatTimestamp();
136
+ const suffix = this.formatData(data);
137
+ consoleFn(`${ts} ${level} [${this.context}] ${message}${suffix}`);
138
+ }
139
+ /**
140
+ * Log an informational message
141
+ *
142
+ * @param {string} message - The message to log
143
+ * @param {LogData} [data] - Optional data to include
144
+ */
145
+ info(message, data) {
146
+ if (this.minLevel < LogLevel.INFO) return;
147
+ this.emit(console.info, "INFO", message, data);
148
+ }
149
+ /**
150
+ * Log an error message
151
+ *
152
+ * @param {string} message - The error message
153
+ * @param {Error|unknown} [error] - Optional Error object or unknown error
154
+ * @param {LogData} [data] - Optional additional data
155
+ */
156
+ error(message, error, data) {
157
+ if (this.minLevel < LogLevel.ERROR) return;
158
+ let errorObj = error;
159
+ if (error instanceof Error) {
160
+ const errorMessage = error.message || ("cause" in error && error.cause instanceof Error ? error.cause.message : "");
161
+ errorObj = {
162
+ name: error.name,
163
+ message: errorMessage,
164
+ stack: error.stack
165
+ };
166
+ }
167
+ this.emit(console.error, "ERROR", message, {
168
+ ...data,
169
+ error: errorObj
170
+ });
171
+ }
172
+ /**
173
+ * Log a warning message
174
+ *
175
+ * @param {string} message - The warning message
176
+ * @param {LogData} [data] - Optional data to include
177
+ */
178
+ warn(message, data) {
179
+ if (this.minLevel < LogLevel.WARN) return;
180
+ this.emit(console.warn, "WARN", message, data);
181
+ }
182
+ /**
183
+ * Log a debug message
184
+ *
185
+ * @param {string} message - The debug message
186
+ * @param {LogData} [data] - Optional data to include
187
+ */
188
+ debug(message, data) {
189
+ if (this.minLevel < LogLevel.DEBUG) return;
190
+ this.emit(console.debug, "DEBUG", message, data);
191
+ }
192
+ /**
193
+ * Log a trace message (most verbose level)
194
+ *
195
+ * @param {string} message - The trace message
196
+ * @param {LogData} [data] - Optional data to include
197
+ */
198
+ trace(message, data) {
199
+ if (this.minLevel < LogLevel.TRACE) return;
200
+ this.emit(console.debug, "TRACE", message, data);
201
+ }
202
+ /**
203
+ * Log an action message (for server actions or important user interactions)
204
+ *
205
+ * @param {string} message - The action message
206
+ * @param {LogData} [data] - Optional data to include
207
+ */
208
+ action(message, data) {
209
+ if (this.minLevel < LogLevel.INFO) return;
210
+ this.emit(console.info, "ACTION", message, data);
211
+ }
212
+ /**
213
+ * Log a success message
214
+ *
215
+ * @param {string} message - The success message
216
+ * @param {LogData} [data] - Optional data to include
217
+ */
218
+ success(message, data) {
219
+ if (this.minLevel < LogLevel.INFO) return;
220
+ this.emit(console.info, "SUCCESS", message, data);
221
+ }
222
+ /**
223
+ * Group related log messages (console.group wrapper)
224
+ *
225
+ * @param {string} label - The group label
226
+ */
227
+ group(label) {
228
+ if (this.minLevel < LogLevel.INFO) return;
229
+ console.group(label);
230
+ }
231
+ /**
232
+ * End a log group (console.groupEnd wrapper)
233
+ */
234
+ groupEnd() {
235
+ if (this.minLevel < LogLevel.INFO) return;
236
+ console.groupEnd();
237
+ }
238
+ /**
239
+ * Log execution time of a function
240
+ *
241
+ * @template T - The return type of the function being timed
242
+ * @param {string} label - Description of the operation being timed
243
+ * @param {() => Promise<T> | T} fn - Function to execute and time
244
+ * @returns {Promise<T>} The result of the function execution
245
+ */
246
+ async time(label, fn) {
247
+ if (this.minLevel < LogLevel.DEBUG) return fn();
248
+ const startTime = performance.now();
249
+ try {
250
+ const result = await fn();
251
+ const duration = (performance.now() - startTime).toFixed(2);
252
+ this.info(`${label} completed`, { duration: `${duration}ms` });
253
+ return result;
254
+ } catch (error) {
255
+ const duration = (performance.now() - startTime).toFixed(2);
256
+ this.error(`${label} failed`, error, { duration: `${duration}ms` });
257
+ throw error;
258
+ }
259
+ }
260
+ };
261
+ const logger = new Logger("[LOGGER]", {
262
+ includeTimestamp: true,
263
+ colorize: true
264
+ });
265
+ //#endregion
266
+ export { LogLevel, Logger, logger };
267
+
268
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["/**\n * Copyright (c) 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview A comprehensive logging utility for both client and server environments.\n * Provides structured logging with support for different log levels, colorization,\n * and contextual information.\n *\n * This logger uses native console methods with structured formatting — no external\n * dependencies are required. Log output follows the pattern:\n * TIMESTAMP LEVEL [CONTEXT] message { data }\n */\n\n/**\n * Enum representing different logging levels with their priority values.\n * Higher values indicate more verbose logging.\n * @enum {number}\n */\nexport enum LogLevel {\n /** No logging */\n NONE = 0,\n /** Only error messages */\n ERROR = 1,\n /** Errors and warnings */\n WARN = 2,\n /** Errors, warnings, and informational messages */\n INFO = 3,\n /** Errors, warnings, info, and debug messages */\n DEBUG = 4,\n /** Errors, warnings, info, debug, and trace messages */\n TRACE = 5,\n /** All possible log messages */\n ALL = 6,\n}\n\n/**\n * Available color keys for log formatting\n * @typedef {'reset' | 'red' | 'yellow' | 'blue' | 'green' | 'gray' | 'bold' | 'magenta' | 'cyan' | 'white'} ColorKey\n */\nexport type ColorKey =\n | 'reset'\n | 'red'\n | 'yellow'\n | 'blue'\n | 'green'\n | 'gray'\n | 'bold'\n | 'magenta'\n | 'cyan'\n | 'white';\n\n/**\n * Interface for structured data that can be attached to log messages\n * @interface\n */\nexport interface LogData {\n /**\n * Any key-value pairs to include in the log\n */\n [key: string]: unknown;\n}\n\n/**\n * Configuration options for the Logger\n * @interface\n */\nexport interface LoggerOptions {\n /**\n * The minimum level of messages to log\n */\n minLevel?: LogLevel;\n\n /**\n * Whether to include timestamps in log messages\n */\n includeTimestamp?: boolean;\n\n /**\n * Whether to colorize log output\n */\n colorize?: boolean;\n\n /**\n * Whether to write logs to a file (server-side only)\n */\n logToFile?: boolean;\n\n /**\n * Path to the log file if logToFile is enabled\n */\n filePath?: string;\n}\n\n/**\n * A versatile logging utility that works in both browser and Node.js environments.\n * Supports multiple log levels, colorized output, and structured data logging.\n */\nexport class Logger {\n /** The context/category name for this logger instance */\n private readonly context: string;\n\n /** The minimum log level that will be output */\n private minLevel: LogLevel;\n\n /**\n * Parse log level from string or return default\n */\n private static parseLevel(level?: string): LogLevel | undefined {\n if (!level) return undefined;\n const upper = level.toUpperCase();\n switch (upper) {\n case 'NONE': return LogLevel.NONE;\n case 'ERROR': return LogLevel.ERROR;\n case 'WARN': return LogLevel.WARN;\n case 'INFO': return LogLevel.INFO;\n case 'DEBUG': return LogLevel.DEBUG;\n case 'TRACE': return LogLevel.TRACE;\n case 'ALL': return LogLevel.ALL;\n default: return undefined;\n }\n }\n\n /** Registry of logger instances to implement the singleton pattern */\n private static readonly instances: Map<string, Logger> = new Map();\n\n /**\n * Create a new Logger instance or return an existing one for the given context\n * @param {string} context - The context name for this logger (e.g., component or service name)\n * @param {LoggerOptions} [options={}] - Optional logger configuration\n */\n constructor(context: string, options: LoggerOptions = {}) {\n this.context = context;\n\n // Priority: options.minLevel > LOG_LEVEL env > BUN_LOG_LEVEL env > Default\n const env = typeof process !== 'undefined' ? process.env : {};\n const envLevel = Logger.parseLevel(env['LOG_LEVEL'] || env['BUN_LOG_LEVEL']);\n\n this.minLevel =\n options.minLevel ??\n envLevel ??\n (env['NODE_ENV'] === 'production' ? LogLevel.ERROR : LogLevel.ALL);\n }\n\n /**\n * Get a logger instance for the given context.\n * If a logger with this context already exists, returns the existing instance.\n *\n * @param {string} context - The context name\n * @param {LoggerOptions} [options] - Optional logger configuration\n * @returns {Logger} A logger instance for the specified context\n */\n public static getLogger(context: string, options?: LoggerOptions): Logger {\n let instance = Logger.instances.get(context);\n\n if (!instance) {\n instance = new Logger(context, options);\n Logger.instances.set(context, instance);\n }\n\n return instance;\n }\n\n /**\n * Set global minimum log level for all logger instances\n *\n * @param {LogLevel} level - The minimum level to log across all loggers\n */\n public static setGlobalLogLevel(level: LogLevel): void {\n Logger.instances.forEach((logger) => {\n logger.minLevel = level;\n });\n }\n\n /**\n * Format a timestamp for log output\n */\n private formatTimestamp(): string {\n const now = new Date();\n const y = now.getFullYear();\n const mo = String(now.getMonth() + 1).padStart(2, '0');\n const d = String(now.getDate()).padStart(2, '0');\n const h = String(now.getHours()).padStart(2, '0');\n const mi = String(now.getMinutes()).padStart(2, '0');\n const s = String(now.getSeconds()).padStart(2, '0');\n const ms = String(now.getMilliseconds()).padStart(3, '0');\n return `${y}-${mo}-${d} ${h}:${mi}:${s}.${ms}`;\n }\n\n /**\n * Format structured log data into a readable suffix string.\n * Returns empty string if data is null/empty.\n */\n private formatData(data?: Record<string, unknown>): string {\n if (!data || Object.keys(data).length === 0) return '';\n try {\n return ` ${JSON.stringify(data)}`;\n } catch {\n return ' [unserializable data]';\n }\n }\n\n /**\n * Emit a log entry using the appropriate console method\n */\n private emit(\n consoleFn: (...args: unknown[]) => void,\n level: string,\n message: string,\n data?: Record<string, unknown>,\n ): void {\n const ts = this.formatTimestamp();\n const suffix = this.formatData(data);\n consoleFn(`${ts} ${level} [${this.context}] ${message}${suffix}`);\n }\n\n /**\n * Log an informational message\n *\n * @param {string} message - The message to log\n * @param {LogData} [data] - Optional data to include\n */\n info(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.INFO) return;\n this.emit(console.info, 'INFO', message, data);\n }\n\n /**\n * Log an error message\n *\n * @param {string} message - The error message\n * @param {Error|unknown} [error] - Optional Error object or unknown error\n * @param {LogData} [data] - Optional additional data\n */\n error(message: string, error?: unknown, data?: LogData): void {\n if (this.minLevel < LogLevel.ERROR) return;\n\n let errorObj: unknown = error;\n if (error instanceof Error) {\n const errorMessage =\n error.message || ('cause' in error && error.cause instanceof Error ? error.cause.message : '');\n errorObj = { name: error.name, message: errorMessage, stack: error.stack };\n }\n\n this.emit(console.error, 'ERROR', message, { ...data, error: errorObj });\n }\n\n /**\n * Log a warning message\n *\n * @param {string} message - The warning message\n * @param {LogData} [data] - Optional data to include\n */\n warn(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.WARN) return;\n this.emit(console.warn, 'WARN', message, data);\n }\n\n /**\n * Log a debug message\n *\n * @param {string} message - The debug message\n * @param {LogData} [data] - Optional data to include\n */\n debug(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.DEBUG) return;\n this.emit(console.debug, 'DEBUG', message, data);\n }\n\n /**\n * Log a trace message (most verbose level)\n *\n * @param {string} message - The trace message\n * @param {LogData} [data] - Optional data to include\n */\n trace(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.TRACE) return;\n this.emit(console.debug, 'TRACE', message, data);\n }\n\n /**\n * Log an action message (for server actions or important user interactions)\n *\n * @param {string} message - The action message\n * @param {LogData} [data] - Optional data to include\n */\n action(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.INFO) return;\n this.emit(console.info, 'ACTION', message, data);\n }\n\n /**\n * Log a success message\n *\n * @param {string} message - The success message\n * @param {LogData} [data] - Optional data to include\n */\n success(message: string, data?: LogData): void {\n if (this.minLevel < LogLevel.INFO) return;\n this.emit(console.info, 'SUCCESS', message, data);\n }\n\n /**\n * Group related log messages (console.group wrapper)\n *\n * @param {string} label - The group label\n */\n group(label: string): void {\n if (this.minLevel < LogLevel.INFO) return;\n console.group(label);\n }\n\n /**\n * End a log group (console.groupEnd wrapper)\n */\n groupEnd(): void {\n if (this.minLevel < LogLevel.INFO) return;\n console.groupEnd();\n }\n\n /**\n * Log execution time of a function\n *\n * @template T - The return type of the function being timed\n * @param {string} label - Description of the operation being timed\n * @param {() => Promise<T> | T} fn - Function to execute and time\n * @returns {Promise<T>} The result of the function execution\n */\n async time<T>(label: string, fn: () => Promise<T> | T): Promise<T> {\n if (this.minLevel < LogLevel.DEBUG) return fn();\n\n const startTime = performance.now();\n try {\n const result = await fn();\n const endTime = performance.now();\n const duration = (endTime - startTime).toFixed(2);\n this.info(`${label} completed`, { duration: `${duration}ms` });\n return result;\n } catch (error) {\n const endTime = performance.now();\n const duration = (endTime - startTime).toFixed(2);\n this.error(`${label} failed`, error, { duration: `${duration}ms` });\n throw error;\n }\n }\n}\n\nexport const logger = new Logger('[LOGGER]', {\n includeTimestamp: true,\n colorize: true,\n});\n"],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import { LogLevel } from "./logger.js";
2
+
3
+ //#region src/logger.types.d.ts
4
+ /**
5
+ * Copyright 2026 ResQ
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ /**
20
+ * Interface for structured data that can be attached to log messages
21
+ * @interface
22
+ */
23
+ interface LogData {
24
+ /**
25
+ * Any key-value pairs to include in the log
26
+ */
27
+ [key: string]: unknown;
28
+ }
29
+ /**
30
+ * Configuration options for the Logger
31
+ * @interface
32
+ */
33
+ interface LoggerOptions {
34
+ /**
35
+ * The minimum level of messages to log
36
+ */
37
+ minLevel?: LogLevel;
38
+ /**
39
+ * Whether to include timestamps in log messages
40
+ */
41
+ includeTimestamp?: boolean;
42
+ /**
43
+ * Whether to colorize log output
44
+ */
45
+ colorize?: boolean;
46
+ /**
47
+ * Whether to write logs to a file (server-side only)
48
+ */
49
+ logToFile?: boolean;
50
+ /**
51
+ * Path to the log file if logToFile is enabled
52
+ */
53
+ filePath?: string;
54
+ }
55
+ /**
56
+ * Available color keys for log formatting
57
+ * @typedef ColorKey
58
+ */
59
+ type ColorKey = 'reset' | 'red' | 'yellow' | 'blue' | 'green' | 'gray' | 'bold' | 'magenta' | 'cyan' | 'white';
60
+ /**
61
+ * Log level strings for type safety
62
+ */
63
+ type LogLevelString = 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'action' | 'success';
64
+ /**
65
+ * Structured log entry for transport/storage
66
+ * @interface
67
+ */
68
+ interface LogEntry {
69
+ /** ISO timestamp of the log */
70
+ timestamp: string;
71
+ /** Log level */
72
+ level: LogLevelString;
73
+ /** Logger context/category */
74
+ context: string;
75
+ /** Log message */
76
+ message: string;
77
+ /** Optional structured data */
78
+ data?: LogData;
79
+ /** Environment (client/server) */
80
+ environment: 'client' | 'server';
81
+ }
82
+ /**
83
+ * Interface for custom log transports
84
+ * @interface
85
+ */
86
+ interface LogTransport {
87
+ /** Transport name for identification */
88
+ name: string;
89
+ /** Method to write a log entry */
90
+ write(entry: LogEntry): void | Promise<void>;
91
+ }
92
+ /**
93
+ * Options for the @Log decorator
94
+ * @interface
95
+ */
96
+ interface LogMethodOptions {
97
+ /** Whether to log method arguments (default: true) */
98
+ logArgs?: boolean;
99
+ /** Whether to log return value (default: false) */
100
+ logResult?: boolean;
101
+ /** Custom message prefix */
102
+ message?: string;
103
+ /** Log level to use (default: 'debug') */
104
+ level?: LogLevelString;
105
+ }
106
+ /**
107
+ * Options for the @LogTiming decorator
108
+ * @interface
109
+ */
110
+ interface LogTimingOptions {
111
+ /** Custom label for timing logs */
112
+ label?: string;
113
+ /** Threshold in ms - only log if execution exceeds this (default: 0) */
114
+ threshold?: number;
115
+ /** Log level to use (default: 'info') */
116
+ level?: LogLevelString;
117
+ }
118
+ /**
119
+ * Options for the @LogError decorator
120
+ * @interface
121
+ */
122
+ interface LogErrorOptions {
123
+ /** Whether to rethrow the error after logging (default: true) */
124
+ rethrow?: boolean;
125
+ /** Custom error message prefix */
126
+ message?: string;
127
+ /** Whether to log the stack trace (default: true) */
128
+ includeStack?: boolean;
129
+ }
130
+ /**
131
+ * Options for the @LogClass decorator
132
+ * @interface
133
+ */
134
+ interface LogClassOptions {
135
+ /** Methods to exclude from logging */
136
+ exclude?: string[];
137
+ /** Whether to log all method calls (default: true) */
138
+ logCalls?: boolean;
139
+ /** Whether to time all method calls (default: false) */
140
+ timing?: boolean;
141
+ }
142
+ //#endregion
143
+ export { ColorKey, LogClassOptions, LogData, LogEntry, LogErrorOptions, LogLevelString, LogMethodOptions, LogTimingOptions, LogTransport, LoggerOptions };
144
+ //# sourceMappingURL=logger.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.types.d.ts","names":[],"sources":["../src/logger.types.ts"],"mappings":";;;;;;AAoBA;;;;;AAWA;;;;;;;;;;;UAXiB,OAAA;EAsCL;;;EAAA,CAlCT,GAAA;AAAA;AAiDH;;;;AAAA,UA1CiB,aAAA;EAgDA;;;EA5Cf,QAAA,GAJ4B,QAAA;EAkD5B;;;EA1CA,gBAAA;EAgDA;;;EA5CA,QAAA;EAgDW;;AAOb;EAnDE,SAAA;;;;EAIA,QAAA;AAAA;;;;;KAOU,QAAA;;;;KAeA,cAAA;;;;;UAMK,QAAA;EAsCO;EApCtB,SAAA;EA2C+B;EAzC/B,KAAA,EAAO,cAAA;EA+Ce;EA7CtB,OAAA;EA2CA;EAzCA,OAAA;EA2CQ;EAzCR,IAAA,GAAO,OAAA;EAyCe;EAvCtB,WAAA;AAAA;;;;;UAOe,YAAA;EA6CH;EA3CZ,IAAA;EAkDe;EAhDf,KAAA,CAAM,KAAA,EAAO,QAAA,UAAkB,OAAA;AAAA;;;;;UAOhB,gBAAA;EA+CT;EA7CN,OAAA;;EAEA,SAAA;;EAEA,OAAA;;EAEA,KAAA,GAAQ,cAAA;AAAA;;;;;UAOO,gBAAA;;EAEf,KAAA;;EAEA,SAAA;;EAEA,KAAA,GAAQ,cAAA;AAAA;;;;;UAOO,eAAA;;EAEf,OAAA;;EAEA,OAAA;;EAEA,YAAA;AAAA;;;;;UAOe,eAAA;;EAEf,OAAA;;EAEA,QAAA;;EAEA,MAAA;AAAA"}
File without changes
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@resq-sw/logger",
3
+ "version": "0.1.0",
4
+ "description": "Structured logging with log levels for Node.js and Bun",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./lib/index.d.ts",
10
+ "import": "./lib/index.js",
11
+ "default": "./lib/index.js"
12
+ }
13
+ },
14
+ "main": "lib/index.js",
15
+ "types": "lib/index.d.ts",
16
+ "files": ["lib", "README.md"],
17
+ "scripts": {
18
+ "build": "tsdown",
19
+ "test": "vitest run"
20
+ },
21
+ "devDependencies": {
22
+ "tsdown": "^0.21.7",
23
+ "typescript": "5.9.3",
24
+ "vitest": "3.2.4"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "provenance": true,
29
+ "registry": "https://registry.npmjs.org/"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/resq-software/npm.git",
34
+ "directory": "packages/logger"
35
+ },
36
+ "keywords": ["logger", "logging", "structured-logging"],
37
+ "engines": {
38
+ "node": ">=20.19.0"
39
+ }
40
+ }