devink 1.0.6 → 2.0.1
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 +242 -37
- package/dist/index.d.mts +97 -52
- package/dist/index.d.ts +97 -52
- package/dist/index.js +1 -4
- package/dist/index.mjs +1 -4
- package/package.json +23 -12
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://npmjs.org/package/devink)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
|
|
12
|
-
`devink` is a zero-dependency **Node.js logger** designed for developers who need high performance, beautiful **CLI output**, and structured **JSON logging**.
|
|
12
|
+
`devink` is a zero-dependency **Node.js logger** designed for developers who need high performance, beautiful **CLI output**, and structured **JSON logging**. Child loggers, HTTP middleware, file transport with rotation, log sampling, field redaction, pretty error formatting — all built in with full **TypeScript** support and **zero external dependencies**.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -17,20 +17,28 @@
|
|
|
17
17
|
<img src="https://raw.githubusercontent.com/harrymate22/devink/main/media/demo.png" alt="devink demo" width="600" />
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
- **Zero Dependencies
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- **Zero Dependencies** — Ultra-fast, nothing in `node_modules` except your own code.
|
|
23
|
+
- **Child Loggers** — Scoped, namespaced loggers with inherited configuration.
|
|
24
|
+
- **HTTP Middleware** — Framework-agnostic request logging for Express, Fastify, Hono, and more.
|
|
25
|
+
- **File Transport with Rotation** — Built-in async file transport with size-based rotation and retention.
|
|
26
|
+
- **Log Grouping** — Visual grouping for multi-step operations with indented output.
|
|
27
|
+
- **Performance Timers** — Measure execution time with `logger.time()` / `logger.timeEnd()`.
|
|
28
|
+
- **Log Sampling / Rate Limiting** — Only log a fraction of high-frequency events in production.
|
|
29
|
+
- **Sensitive Field Redaction** — Automatically mask passwords, tokens, and secrets from log output.
|
|
30
|
+
- **Pretty Error Formatting** — Colored stack traces with highlighted source locations.
|
|
31
|
+
- **Full ANSI & 256/RGB Color Support** — Beautiful themes for the terminal.
|
|
32
|
+
- **Structured JSON Logging** — One-line switch to JSON for Datadog, ELK, and more.
|
|
33
|
+
- **Log Levels & Priority Filtering** — Granular control via `trace`, `debug`, `info`, `warn`, `error`, and `fatal`.
|
|
34
|
+
- **Custom Transports** — Route logs to files, external APIs, or custom formatting engines.
|
|
35
|
+
- **Terminal Capability Detection** — Auto-detects `TTY`, `FORCE_COLOR`, `NO_COLOR`, and `CI` environments.
|
|
36
|
+
- **Boxed Output** — Unicode-boxed messages for critical startup and alert information.
|
|
37
|
+
- **TypeScript Native** — Built with TypeScript, full type definitions included.
|
|
30
38
|
|
|
31
39
|
---
|
|
32
40
|
|
|
33
|
-
##
|
|
41
|
+
## Installation
|
|
34
42
|
|
|
35
43
|
```bash
|
|
36
44
|
npm install devink
|
|
@@ -46,11 +54,9 @@ pnpm add devink
|
|
|
46
54
|
|
|
47
55
|
---
|
|
48
56
|
|
|
49
|
-
##
|
|
50
|
-
|
|
51
|
-
### Basic CLI Logger
|
|
57
|
+
## Quick Start
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
### Basic Logger
|
|
54
60
|
|
|
55
61
|
```ts
|
|
56
62
|
import { createLogger } from 'devink';
|
|
@@ -71,18 +77,198 @@ logger.error(new Error('Connection timeout'));
|
|
|
71
77
|
Perfect for production environments where log aggregation is crucial:
|
|
72
78
|
|
|
73
79
|
```ts
|
|
74
|
-
import { createLogger } from 'devink';
|
|
75
|
-
|
|
76
80
|
const logger = createLogger({
|
|
77
81
|
mode: 'json',
|
|
78
82
|
level: 'trace',
|
|
79
83
|
});
|
|
80
84
|
|
|
81
85
|
logger.info('Processing payment', { userId: 123, amount: 49.99 });
|
|
82
|
-
//
|
|
86
|
+
// {"level":"info","time":"2026-03-03T00:00:00.000Z","message":["Processing payment",{"userId":123,"amount":49.99}]}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Child Loggers / Namespaced Logging
|
|
92
|
+
|
|
93
|
+
Create scoped loggers that inherit the parent configuration and prepend a namespace to every log line:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { createLogger } from 'devink';
|
|
97
|
+
|
|
98
|
+
const logger = createLogger({ timestamps: true });
|
|
99
|
+
|
|
100
|
+
const dbLogger = logger.child({ namespace: 'db' });
|
|
101
|
+
const authLogger = logger.child({ namespace: 'auth' });
|
|
102
|
+
|
|
103
|
+
dbLogger.info('Query executed in 12ms');
|
|
104
|
+
// [14:30:00] [db] ℹ info Query executed in 12ms
|
|
105
|
+
|
|
106
|
+
authLogger.warn('Token expires in 5 minutes');
|
|
107
|
+
// [14:30:00] [auth] ⚠ warn Token expires in 5 minutes
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Child loggers can also carry default metadata:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const requestLogger = logger.child({ namespace: 'api', requestId: 'abc-123' });
|
|
114
|
+
requestLogger.info('Request received');
|
|
115
|
+
// In JSON mode: {"level":"info","namespace":"api","requestId":"abc-123","message":"Request received"}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## HTTP Request Middleware
|
|
121
|
+
|
|
122
|
+
Framework-agnostic middleware that auto-logs every HTTP request with method, path, status code, and response time:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { createLogger, httpMiddleware } from 'devink';
|
|
126
|
+
import express from 'express';
|
|
127
|
+
|
|
128
|
+
const logger = createLogger({ timestamps: true });
|
|
129
|
+
const app = express();
|
|
130
|
+
|
|
131
|
+
app.use(httpMiddleware(logger));
|
|
132
|
+
|
|
133
|
+
// Every request automatically logged:
|
|
134
|
+
// [14:30:05] ℹ info GET /api/users 200 12ms
|
|
135
|
+
// [14:30:06] ⚠ warn POST /api/login 401 8ms
|
|
136
|
+
// [14:30:07] ✖ error GET /api/crash 500 3ms
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Works with **Express**, **Fastify**, **Hono**, **Koa**, and any framework using the standard `(req, res, next)` pattern.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Log Grouping
|
|
144
|
+
|
|
145
|
+
Visually group related log lines for multi-step operations:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const logger = createLogger({ timestamps: true });
|
|
149
|
+
|
|
150
|
+
logger.group('Database Migration');
|
|
151
|
+
logger.info('Running migration 001_create_users...');
|
|
152
|
+
logger.info('Running migration 002_add_indexes...');
|
|
153
|
+
logger.success('All migrations complete');
|
|
154
|
+
logger.groupEnd();
|
|
155
|
+
|
|
156
|
+
logger.info('Server ready');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Output:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
[14:30:00] ▸ Database Migration
|
|
163
|
+
[14:30:00] ℹ info Running migration 001_create_users...
|
|
164
|
+
[14:30:01] ℹ info Running migration 002_add_indexes...
|
|
165
|
+
[14:30:01] ✔ success All migrations complete
|
|
166
|
+
[14:30:01] ℹ info Server ready
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Performance Timers
|
|
172
|
+
|
|
173
|
+
Measure execution time for any operation directly from the logger:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
const logger = createLogger();
|
|
177
|
+
|
|
178
|
+
logger.time('database-query');
|
|
179
|
+
await db.query('SELECT * FROM users');
|
|
180
|
+
logger.timeEnd('database-query');
|
|
181
|
+
// ℹ info database-query: 243ms
|
|
182
|
+
|
|
183
|
+
logger.time('api-call');
|
|
184
|
+
await fetch('https://api.example.com/data');
|
|
185
|
+
logger.timeEnd('api-call');
|
|
186
|
+
// ℹ info api-call: 891ms
|
|
83
187
|
```
|
|
84
188
|
|
|
85
|
-
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Log Sampling
|
|
192
|
+
|
|
193
|
+
In high-throughput production environments, log only a fraction of repetitive events:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const logger = createLogger({
|
|
197
|
+
sampling: {
|
|
198
|
+
'db.query': 0.1, // log 10% of database queries
|
|
199
|
+
'cache.hit': 0.01, // log 1% of cache hits
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Only ~10% of these calls will actually produce output
|
|
204
|
+
logger.info('Query executed', { table: 'users' });
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## File Transport
|
|
210
|
+
|
|
211
|
+
Built-in file transport with async writes and automatic log rotation:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { createLogger, FileTransport } from 'devink';
|
|
215
|
+
|
|
216
|
+
const logger = createLogger({
|
|
217
|
+
transports: [
|
|
218
|
+
new FileTransport({
|
|
219
|
+
path: './logs/app.log',
|
|
220
|
+
maxSize: '10mb',
|
|
221
|
+
maxFiles: 5,
|
|
222
|
+
rotate: true,
|
|
223
|
+
}),
|
|
224
|
+
],
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
logger.info('This goes to a file with automatic rotation');
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
When `app.log` exceeds 10 MB, it rotates to `app.log.1`, `app.log.2`, etc., keeping at most 5 rotated files.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Field Redaction
|
|
235
|
+
|
|
236
|
+
Automatically mask sensitive data before it reaches any transport:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const logger = createLogger({
|
|
240
|
+
redact: ['password', 'token', 'authorization', 'ssn'],
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
logger.info('User login', { user: 'harry', password: 's3cret!', token: 'eyJhbG...' });
|
|
244
|
+
// ℹ info User login { user: 'harry', password: '[REDACTED]', token: '[REDACTED]' }
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Redaction works recursively on nested objects and in both text and JSON modes.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Error Formatting
|
|
252
|
+
|
|
253
|
+
When you pass an `Error` object, devink renders a beautiful, colored stack trace instead of a raw dump:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
const logger = createLogger();
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
throw new Error('Database connection failed');
|
|
260
|
+
} catch (err) {
|
|
261
|
+
logger.error('Fatal error during startup', err);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
- Error name and message in **bold red**
|
|
266
|
+
- Your source files highlighted with **colored file paths and line numbers**
|
|
267
|
+
- `node_modules` and Node.js internal frames **dimmed** so your code stands out
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Boxed Output
|
|
86
272
|
|
|
87
273
|
Make important startup messages or critical alerts pop in the console:
|
|
88
274
|
|
|
@@ -97,18 +283,21 @@ logger.box(
|
|
|
97
283
|
|
|
98
284
|
---
|
|
99
285
|
|
|
100
|
-
##
|
|
286
|
+
## Configuration
|
|
101
287
|
|
|
102
288
|
The `createLogger` function accepts an optional `LoggerOptions` object:
|
|
103
289
|
|
|
104
|
-
| Property | Type
|
|
105
|
-
| ------------ |
|
|
106
|
-
| `level` | `LogLevelName`
|
|
107
|
-
| `mode` | `'text' \| 'json'`
|
|
108
|
-
| `colors` | `boolean`
|
|
109
|
-
| `timestamps` | `boolean`
|
|
110
|
-
| `theme` | `Partial<Theme>`
|
|
111
|
-
| `transports` | `Transport[]`
|
|
290
|
+
| Property | Type | Default | Description |
|
|
291
|
+
| ------------ | ------------------------ | -------------------- | ---------------------------------------------------------------------------- |
|
|
292
|
+
| `level` | `LogLevelName` | `'trace'` | Minimum log level (`trace` < `debug` < `info` < `warn` < `error` < `fatal`). |
|
|
293
|
+
| `mode` | `'text' \| 'json'` | `'text'` | Output mode. Text for the console, JSON for log aggregators. |
|
|
294
|
+
| `colors` | `boolean` | `true` | ANSI colors. Automatically disabled if the terminal doesn't support it. |
|
|
295
|
+
| `timestamps` | `boolean` | `false` | Prepend a timestamp (`[HH:MM:SS]`) to text outputs. |
|
|
296
|
+
| `theme` | `Partial<Theme>` | `modernTheme` | Customize prefix icons and color functions for each log level. |
|
|
297
|
+
| `transports` | `Transport[]` | `[ConsoleTransport]` | Target output destinations (console, file, external APIs). |
|
|
298
|
+
| `namespace` | `string` | `''` | Namespace prefix prepended to all log lines. |
|
|
299
|
+
| `redact` | `string[]` | `[]` | Field names to mask with `[REDACTED]` in log output. |
|
|
300
|
+
| `sampling` | `Record<string, number>` | `{}` | Sampling rates (0–1) for rate-limiting high-frequency log events. |
|
|
112
301
|
|
|
113
302
|
### Theme Presets
|
|
114
303
|
|
|
@@ -128,28 +317,28 @@ const logger = createLogger({
|
|
|
128
317
|
|
|
129
318
|
### Custom Transports
|
|
130
319
|
|
|
131
|
-
|
|
320
|
+
Route logs anywhere by implementing the `Transport` interface:
|
|
132
321
|
|
|
133
322
|
```ts
|
|
134
323
|
import { createLogger, Transport, TransportContext } from 'devink';
|
|
135
324
|
import fs from 'node:fs';
|
|
136
325
|
|
|
137
|
-
class
|
|
326
|
+
class CustomTransport implements Transport {
|
|
138
327
|
write(ctx: TransportContext) {
|
|
139
|
-
fs.appendFileSync('
|
|
328
|
+
fs.appendFileSync('custom.log', ctx.raw + '\n');
|
|
140
329
|
}
|
|
141
330
|
}
|
|
142
331
|
|
|
143
332
|
const logger = createLogger({
|
|
144
|
-
transports: [new
|
|
333
|
+
transports: [new CustomTransport()],
|
|
145
334
|
});
|
|
146
335
|
```
|
|
147
336
|
|
|
148
337
|
---
|
|
149
338
|
|
|
150
|
-
##
|
|
339
|
+
## ANSI Utilities
|
|
151
340
|
|
|
152
|
-
|
|
341
|
+
Build your own CLI tools with devink's high-performance, zero-dependency ANSI utilities:
|
|
153
342
|
|
|
154
343
|
```ts
|
|
155
344
|
import { ansi } from 'devink';
|
|
@@ -157,11 +346,27 @@ import { ansi } from 'devink';
|
|
|
157
346
|
console.log(ansi.rgb(255, 100, 50, 'True RGB text!'));
|
|
158
347
|
console.log(ansi.hex('#34d399', 'Hex coded text!'));
|
|
159
348
|
console.log(ansi.color256(128, '256 color terminal support!'));
|
|
160
|
-
console.log(ansi.
|
|
349
|
+
console.log(ansi.bold(ansi.cyan('Bold and cyan!')));
|
|
161
350
|
```
|
|
162
351
|
|
|
163
352
|
---
|
|
164
353
|
|
|
165
|
-
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Roadmap
|
|
357
|
+
|
|
358
|
+
These features are planned for upcoming releases:
|
|
359
|
+
|
|
360
|
+
- 🌐 **Browser Support** — Universal logger that works in both Node.js and browser DevTools.
|
|
361
|
+
- 🔗 **OpenTelemetry Integration** — Automatic `traceId` and `spanId` injection.
|
|
362
|
+
- 📡 **Log Aggregator Presets** — One-line setup for Datadog, Loki, and Elasticsearch.
|
|
363
|
+
- 🖥️ **Interactive CLI Mode** — Live log panel with filtering for development.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
Built with ❤️ by **[Harry Mate](https://github.com/harrymate22)**.
|
|
368
|
+
🌟 If you find this library helpful, consider dropping a **Star** on GitHub and **[following me (@harrymate22)](https://github.com/harrymate22)** for more open-source tools!
|
|
369
|
+
|
|
370
|
+
## License
|
|
166
371
|
|
|
167
372
|
MIT © [harrymate22](https://github.com/harrymate22)
|
package/dist/index.d.mts
CHANGED
|
@@ -33,6 +33,8 @@ interface TransportContext {
|
|
|
33
33
|
formatted: string;
|
|
34
34
|
raw: string;
|
|
35
35
|
timestamp: string;
|
|
36
|
+
namespace?: string;
|
|
37
|
+
meta?: Record<string, unknown>;
|
|
36
38
|
}
|
|
37
39
|
interface Transport {
|
|
38
40
|
write(ctx: TransportContext): void;
|
|
@@ -44,69 +46,87 @@ interface LoggerOptions {
|
|
|
44
46
|
level?: LogLevelName;
|
|
45
47
|
mode?: 'text' | 'json';
|
|
46
48
|
transports?: Transport[];
|
|
49
|
+
sampling?: Record<string, number>;
|
|
50
|
+
redact?: string[];
|
|
51
|
+
namespace?: string;
|
|
47
52
|
}
|
|
48
53
|
declare class ConsoleTransport implements Transport {
|
|
49
54
|
write(ctx: TransportContext): void;
|
|
50
55
|
}
|
|
51
56
|
declare class Logger {
|
|
52
|
-
private
|
|
53
|
-
private
|
|
54
|
-
private
|
|
55
|
-
private
|
|
56
|
-
private
|
|
57
|
-
private
|
|
58
|
-
private
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
private
|
|
62
|
-
private
|
|
63
|
-
private
|
|
64
|
-
private
|
|
57
|
+
private t;
|
|
58
|
+
private ts;
|
|
59
|
+
private c;
|
|
60
|
+
private lv;
|
|
61
|
+
private m;
|
|
62
|
+
private tr;
|
|
63
|
+
private tc;
|
|
64
|
+
private sp;
|
|
65
|
+
private rk;
|
|
66
|
+
private ns;
|
|
67
|
+
private gd;
|
|
68
|
+
private tm;
|
|
69
|
+
private sc;
|
|
70
|
+
private dm;
|
|
71
|
+
constructor(opts?: LoggerOptions, meta?: Record<string, unknown>);
|
|
72
|
+
child(bindings: {
|
|
73
|
+
namespace?: string;
|
|
74
|
+
[k: string]: unknown;
|
|
75
|
+
}): Logger;
|
|
76
|
+
group(label: string): void;
|
|
77
|
+
groupEnd(): void;
|
|
78
|
+
time(label: string): void;
|
|
79
|
+
timeEnd(label: string): void;
|
|
80
|
+
private getTs;
|
|
81
|
+
private nsPrefix;
|
|
82
|
+
private hlJson;
|
|
83
|
+
private fmtErr;
|
|
84
|
+
private fmtMsg;
|
|
65
85
|
private emit;
|
|
66
86
|
private dispatch;
|
|
67
|
-
success(...
|
|
68
|
-
error(...
|
|
69
|
-
warn(...
|
|
70
|
-
info(...
|
|
71
|
-
trace(...
|
|
72
|
-
debug(...
|
|
73
|
-
fatal(...
|
|
87
|
+
success(...msg: unknown[]): void;
|
|
88
|
+
error(...msg: unknown[]): void;
|
|
89
|
+
warn(...msg: unknown[]): void;
|
|
90
|
+
info(...msg: unknown[]): void;
|
|
91
|
+
trace(...msg: unknown[]): void;
|
|
92
|
+
debug(...msg: unknown[]): void;
|
|
93
|
+
fatal(...msg: unknown[]): void;
|
|
74
94
|
box(title: string, message: string): void;
|
|
75
95
|
}
|
|
76
|
-
declare const createLogger: (
|
|
96
|
+
declare const createLogger: (opts?: LoggerOptions) => Logger;
|
|
77
97
|
|
|
78
98
|
declare const isColorSupported: string | boolean;
|
|
79
99
|
declare const format: (code: number, text: string) => string;
|
|
80
|
-
declare const reset: (
|
|
81
|
-
declare const black: (
|
|
82
|
-
declare const red: (
|
|
83
|
-
declare const green: (
|
|
84
|
-
declare const yellow: (
|
|
85
|
-
declare const blue: (
|
|
86
|
-
declare const magenta: (
|
|
87
|
-
declare const cyan: (
|
|
88
|
-
declare const white: (
|
|
89
|
-
declare const gray: (
|
|
90
|
-
declare const bgBlack: (
|
|
91
|
-
declare const bgRed: (
|
|
92
|
-
declare const bgGreen: (
|
|
93
|
-
declare const bgYellow: (
|
|
94
|
-
declare const bgBlue: (
|
|
95
|
-
declare const bgMagenta: (
|
|
96
|
-
declare const bgCyan: (
|
|
97
|
-
declare const bgWhite: (
|
|
98
|
-
declare const bold: (
|
|
99
|
-
declare const dim: (
|
|
100
|
-
declare const italic: (
|
|
101
|
-
declare const underline: (
|
|
102
|
-
declare const inverse: (
|
|
103
|
-
declare const rgb: (r: number, g: number, b: number,
|
|
104
|
-
declare const bgRgb: (r: number, g: number, b: number,
|
|
105
|
-
declare const hex: (
|
|
106
|
-
declare const bgHex: (
|
|
107
|
-
declare const color256: (
|
|
108
|
-
declare const bgColor256: (
|
|
109
|
-
declare const stripAnsi: (
|
|
100
|
+
declare const reset: (t: string) => string;
|
|
101
|
+
declare const black: (t: string) => string;
|
|
102
|
+
declare const red: (t: string) => string;
|
|
103
|
+
declare const green: (t: string) => string;
|
|
104
|
+
declare const yellow: (t: string) => string;
|
|
105
|
+
declare const blue: (t: string) => string;
|
|
106
|
+
declare const magenta: (t: string) => string;
|
|
107
|
+
declare const cyan: (t: string) => string;
|
|
108
|
+
declare const white: (t: string) => string;
|
|
109
|
+
declare const gray: (t: string) => string;
|
|
110
|
+
declare const bgBlack: (t: string) => string;
|
|
111
|
+
declare const bgRed: (t: string) => string;
|
|
112
|
+
declare const bgGreen: (t: string) => string;
|
|
113
|
+
declare const bgYellow: (t: string) => string;
|
|
114
|
+
declare const bgBlue: (t: string) => string;
|
|
115
|
+
declare const bgMagenta: (t: string) => string;
|
|
116
|
+
declare const bgCyan: (t: string) => string;
|
|
117
|
+
declare const bgWhite: (t: string) => string;
|
|
118
|
+
declare const bold: (t: string) => string;
|
|
119
|
+
declare const dim: (t: string) => string;
|
|
120
|
+
declare const italic: (t: string) => string;
|
|
121
|
+
declare const underline: (t: string) => string;
|
|
122
|
+
declare const inverse: (t: string) => string;
|
|
123
|
+
declare const rgb: (r: number, g: number, b: number, t: string) => string;
|
|
124
|
+
declare const bgRgb: (r: number, g: number, b: number, t: string) => string;
|
|
125
|
+
declare const hex: (h: string, t: string) => string;
|
|
126
|
+
declare const bgHex: (h: string, t: string) => string;
|
|
127
|
+
declare const color256: (c: number, t: string) => string;
|
|
128
|
+
declare const bgColor256: (c: number, t: string) => string;
|
|
129
|
+
declare const stripAnsi: (t: string) => string;
|
|
110
130
|
|
|
111
131
|
declare const ansi_bgBlack: typeof bgBlack;
|
|
112
132
|
declare const ansi_bgBlue: typeof bgBlue;
|
|
@@ -144,4 +164,29 @@ declare namespace ansi {
|
|
|
144
164
|
export { ansi_bgBlack as bgBlack, ansi_bgBlue as bgBlue, ansi_bgColor256 as bgColor256, ansi_bgCyan as bgCyan, ansi_bgGreen as bgGreen, ansi_bgHex as bgHex, ansi_bgMagenta as bgMagenta, ansi_bgRed as bgRed, ansi_bgRgb as bgRgb, ansi_bgWhite as bgWhite, ansi_bgYellow as bgYellow, ansi_black as black, ansi_blue as blue, ansi_bold as bold, ansi_color256 as color256, ansi_cyan as cyan, ansi_dim as dim, ansi_format as format, ansi_gray as gray, ansi_green as green, ansi_hex as hex, ansi_inverse as inverse, ansi_isColorSupported as isColorSupported, ansi_italic as italic, ansi_magenta as magenta, ansi_red as red, ansi_reset as reset, ansi_rgb as rgb, ansi_stripAnsi as stripAnsi, ansi_underline as underline, ansi_white as white, ansi_yellow as yellow };
|
|
145
165
|
}
|
|
146
166
|
|
|
147
|
-
|
|
167
|
+
interface FileTransportOptions {
|
|
168
|
+
path: string;
|
|
169
|
+
maxSize?: string | number;
|
|
170
|
+
maxFiles?: number;
|
|
171
|
+
rotate?: boolean;
|
|
172
|
+
}
|
|
173
|
+
declare class FileTransport implements Transport {
|
|
174
|
+
private fp;
|
|
175
|
+
private ms;
|
|
176
|
+
private mf;
|
|
177
|
+
private rot;
|
|
178
|
+
private sz;
|
|
179
|
+
private q;
|
|
180
|
+
private init;
|
|
181
|
+
constructor(opts: FileTransportOptions);
|
|
182
|
+
write(ctx: TransportContext): void;
|
|
183
|
+
private flush;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface HttpMiddlewareOptions {
|
|
187
|
+
warnAbove?: number;
|
|
188
|
+
errorAbove?: number;
|
|
189
|
+
}
|
|
190
|
+
declare function httpMiddleware(logger: Logger, opts?: HttpMiddlewareOptions): (req: Record<string, unknown>, res: Record<string, unknown>, next: (err?: unknown) => void) => void;
|
|
191
|
+
|
|
192
|
+
export { ConsoleTransport, FileTransport, type FileTransportOptions, type HttpMiddlewareOptions, LogLevel, type LogLevelName, Logger, type LoggerOptions, type Theme, type Transport, type TransportContext, ansi, classicTheme, createLogger, defaultTheme, httpMiddleware, minimalTheme, modernTheme };
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ interface TransportContext {
|
|
|
33
33
|
formatted: string;
|
|
34
34
|
raw: string;
|
|
35
35
|
timestamp: string;
|
|
36
|
+
namespace?: string;
|
|
37
|
+
meta?: Record<string, unknown>;
|
|
36
38
|
}
|
|
37
39
|
interface Transport {
|
|
38
40
|
write(ctx: TransportContext): void;
|
|
@@ -44,69 +46,87 @@ interface LoggerOptions {
|
|
|
44
46
|
level?: LogLevelName;
|
|
45
47
|
mode?: 'text' | 'json';
|
|
46
48
|
transports?: Transport[];
|
|
49
|
+
sampling?: Record<string, number>;
|
|
50
|
+
redact?: string[];
|
|
51
|
+
namespace?: string;
|
|
47
52
|
}
|
|
48
53
|
declare class ConsoleTransport implements Transport {
|
|
49
54
|
write(ctx: TransportContext): void;
|
|
50
55
|
}
|
|
51
56
|
declare class Logger {
|
|
52
|
-
private
|
|
53
|
-
private
|
|
54
|
-
private
|
|
55
|
-
private
|
|
56
|
-
private
|
|
57
|
-
private
|
|
58
|
-
private
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
private
|
|
62
|
-
private
|
|
63
|
-
private
|
|
64
|
-
private
|
|
57
|
+
private t;
|
|
58
|
+
private ts;
|
|
59
|
+
private c;
|
|
60
|
+
private lv;
|
|
61
|
+
private m;
|
|
62
|
+
private tr;
|
|
63
|
+
private tc;
|
|
64
|
+
private sp;
|
|
65
|
+
private rk;
|
|
66
|
+
private ns;
|
|
67
|
+
private gd;
|
|
68
|
+
private tm;
|
|
69
|
+
private sc;
|
|
70
|
+
private dm;
|
|
71
|
+
constructor(opts?: LoggerOptions, meta?: Record<string, unknown>);
|
|
72
|
+
child(bindings: {
|
|
73
|
+
namespace?: string;
|
|
74
|
+
[k: string]: unknown;
|
|
75
|
+
}): Logger;
|
|
76
|
+
group(label: string): void;
|
|
77
|
+
groupEnd(): void;
|
|
78
|
+
time(label: string): void;
|
|
79
|
+
timeEnd(label: string): void;
|
|
80
|
+
private getTs;
|
|
81
|
+
private nsPrefix;
|
|
82
|
+
private hlJson;
|
|
83
|
+
private fmtErr;
|
|
84
|
+
private fmtMsg;
|
|
65
85
|
private emit;
|
|
66
86
|
private dispatch;
|
|
67
|
-
success(...
|
|
68
|
-
error(...
|
|
69
|
-
warn(...
|
|
70
|
-
info(...
|
|
71
|
-
trace(...
|
|
72
|
-
debug(...
|
|
73
|
-
fatal(...
|
|
87
|
+
success(...msg: unknown[]): void;
|
|
88
|
+
error(...msg: unknown[]): void;
|
|
89
|
+
warn(...msg: unknown[]): void;
|
|
90
|
+
info(...msg: unknown[]): void;
|
|
91
|
+
trace(...msg: unknown[]): void;
|
|
92
|
+
debug(...msg: unknown[]): void;
|
|
93
|
+
fatal(...msg: unknown[]): void;
|
|
74
94
|
box(title: string, message: string): void;
|
|
75
95
|
}
|
|
76
|
-
declare const createLogger: (
|
|
96
|
+
declare const createLogger: (opts?: LoggerOptions) => Logger;
|
|
77
97
|
|
|
78
98
|
declare const isColorSupported: string | boolean;
|
|
79
99
|
declare const format: (code: number, text: string) => string;
|
|
80
|
-
declare const reset: (
|
|
81
|
-
declare const black: (
|
|
82
|
-
declare const red: (
|
|
83
|
-
declare const green: (
|
|
84
|
-
declare const yellow: (
|
|
85
|
-
declare const blue: (
|
|
86
|
-
declare const magenta: (
|
|
87
|
-
declare const cyan: (
|
|
88
|
-
declare const white: (
|
|
89
|
-
declare const gray: (
|
|
90
|
-
declare const bgBlack: (
|
|
91
|
-
declare const bgRed: (
|
|
92
|
-
declare const bgGreen: (
|
|
93
|
-
declare const bgYellow: (
|
|
94
|
-
declare const bgBlue: (
|
|
95
|
-
declare const bgMagenta: (
|
|
96
|
-
declare const bgCyan: (
|
|
97
|
-
declare const bgWhite: (
|
|
98
|
-
declare const bold: (
|
|
99
|
-
declare const dim: (
|
|
100
|
-
declare const italic: (
|
|
101
|
-
declare const underline: (
|
|
102
|
-
declare const inverse: (
|
|
103
|
-
declare const rgb: (r: number, g: number, b: number,
|
|
104
|
-
declare const bgRgb: (r: number, g: number, b: number,
|
|
105
|
-
declare const hex: (
|
|
106
|
-
declare const bgHex: (
|
|
107
|
-
declare const color256: (
|
|
108
|
-
declare const bgColor256: (
|
|
109
|
-
declare const stripAnsi: (
|
|
100
|
+
declare const reset: (t: string) => string;
|
|
101
|
+
declare const black: (t: string) => string;
|
|
102
|
+
declare const red: (t: string) => string;
|
|
103
|
+
declare const green: (t: string) => string;
|
|
104
|
+
declare const yellow: (t: string) => string;
|
|
105
|
+
declare const blue: (t: string) => string;
|
|
106
|
+
declare const magenta: (t: string) => string;
|
|
107
|
+
declare const cyan: (t: string) => string;
|
|
108
|
+
declare const white: (t: string) => string;
|
|
109
|
+
declare const gray: (t: string) => string;
|
|
110
|
+
declare const bgBlack: (t: string) => string;
|
|
111
|
+
declare const bgRed: (t: string) => string;
|
|
112
|
+
declare const bgGreen: (t: string) => string;
|
|
113
|
+
declare const bgYellow: (t: string) => string;
|
|
114
|
+
declare const bgBlue: (t: string) => string;
|
|
115
|
+
declare const bgMagenta: (t: string) => string;
|
|
116
|
+
declare const bgCyan: (t: string) => string;
|
|
117
|
+
declare const bgWhite: (t: string) => string;
|
|
118
|
+
declare const bold: (t: string) => string;
|
|
119
|
+
declare const dim: (t: string) => string;
|
|
120
|
+
declare const italic: (t: string) => string;
|
|
121
|
+
declare const underline: (t: string) => string;
|
|
122
|
+
declare const inverse: (t: string) => string;
|
|
123
|
+
declare const rgb: (r: number, g: number, b: number, t: string) => string;
|
|
124
|
+
declare const bgRgb: (r: number, g: number, b: number, t: string) => string;
|
|
125
|
+
declare const hex: (h: string, t: string) => string;
|
|
126
|
+
declare const bgHex: (h: string, t: string) => string;
|
|
127
|
+
declare const color256: (c: number, t: string) => string;
|
|
128
|
+
declare const bgColor256: (c: number, t: string) => string;
|
|
129
|
+
declare const stripAnsi: (t: string) => string;
|
|
110
130
|
|
|
111
131
|
declare const ansi_bgBlack: typeof bgBlack;
|
|
112
132
|
declare const ansi_bgBlue: typeof bgBlue;
|
|
@@ -144,4 +164,29 @@ declare namespace ansi {
|
|
|
144
164
|
export { ansi_bgBlack as bgBlack, ansi_bgBlue as bgBlue, ansi_bgColor256 as bgColor256, ansi_bgCyan as bgCyan, ansi_bgGreen as bgGreen, ansi_bgHex as bgHex, ansi_bgMagenta as bgMagenta, ansi_bgRed as bgRed, ansi_bgRgb as bgRgb, ansi_bgWhite as bgWhite, ansi_bgYellow as bgYellow, ansi_black as black, ansi_blue as blue, ansi_bold as bold, ansi_color256 as color256, ansi_cyan as cyan, ansi_dim as dim, ansi_format as format, ansi_gray as gray, ansi_green as green, ansi_hex as hex, ansi_inverse as inverse, ansi_isColorSupported as isColorSupported, ansi_italic as italic, ansi_magenta as magenta, ansi_red as red, ansi_reset as reset, ansi_rgb as rgb, ansi_stripAnsi as stripAnsi, ansi_underline as underline, ansi_white as white, ansi_yellow as yellow };
|
|
145
165
|
}
|
|
146
166
|
|
|
147
|
-
|
|
167
|
+
interface FileTransportOptions {
|
|
168
|
+
path: string;
|
|
169
|
+
maxSize?: string | number;
|
|
170
|
+
maxFiles?: number;
|
|
171
|
+
rotate?: boolean;
|
|
172
|
+
}
|
|
173
|
+
declare class FileTransport implements Transport {
|
|
174
|
+
private fp;
|
|
175
|
+
private ms;
|
|
176
|
+
private mf;
|
|
177
|
+
private rot;
|
|
178
|
+
private sz;
|
|
179
|
+
private q;
|
|
180
|
+
private init;
|
|
181
|
+
constructor(opts: FileTransportOptions);
|
|
182
|
+
write(ctx: TransportContext): void;
|
|
183
|
+
private flush;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface HttpMiddlewareOptions {
|
|
187
|
+
warnAbove?: number;
|
|
188
|
+
errorAbove?: number;
|
|
189
|
+
}
|
|
190
|
+
declare function httpMiddleware(logger: Logger, opts?: HttpMiddlewareOptions): (req: Record<string, unknown>, res: Record<string, unknown>, next: (err?: unknown) => void) => void;
|
|
191
|
+
|
|
192
|
+
export { ConsoleTransport, FileTransport, type FileTransportOptions, type HttpMiddlewareOptions, LogLevel, type LogLevelName, Logger, type LoggerOptions, type Theme, type Transport, type TransportContext, ansi, classicTheme, createLogger, defaultTheme, httpMiddleware, minimalTheme, modernTheme };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
|
|
2
|
-
`+this.highlightJson(this.safeStringify(e,2))}catch{return "[Unserializable]"}}).join(" ")}emit(r,e,o,g){let a=y[r];if(!this.shouldLog(a))return;let f=this.getTimestamp(),m,n;if(this.mode==="json"){let c={level:r,time:f.iso,message:g.length===1?g[0]:g};m=n=this.safeStringify(c);}else {let c=this.formatMessage(g);m=`${f.formatted}${e} ${o(c)}`,n=u(m),this.colors||(m=n);}this.dispatch(r,a,g,m,n,f.iso);}dispatch(r,e,o,g,a,f){let m={level:r,levelValue:e,message:o,formatted:g,raw:a,timestamp:f};for(let n=0;n<this.transports.length;n++)this.transports[n]?.write(m);}success(...r){this.emit("success",this.theme.prefix.success,this.theme.success,r);}error(...r){this.emit("error",this.theme.prefix.error,this.theme.error,r);}warn(...r){this.emit("warn",this.theme.prefix.warn,this.theme.warn,r);}info(...r){this.emit("info",this.theme.prefix.info,this.theme.info,r);}trace(...r){this.emit("trace",b("\u{1F50D}"),b,r);}debug(...r){this.emit("debug",s("#94a3b8","\u{1F41B}"),e=>s("#94a3b8",e),r);}fatal(...r){this.emit("fatal",s("#be123c","\u{1F480}"),e=>s("#be123c",e),r);}box(r,e){let o=30;if(!this.shouldLog(o))return;let g=e.split(`
|
|
3
|
-
`),a=Math.max(r.length,...g.map(l=>u(l).length))+4,f=`\u250C\u2500 ${r} ${"\u2500".repeat(a-r.length-3)}\u2510`,m=`\u2514${"\u2500".repeat(a)}\u2518`,n=g.map(l=>{let E=a-u(l).length-2;return `\u2502 ${l}${" ".repeat(Math.max(0,E))} \u2502`}),c=[f,...n,m].join(`
|
|
4
|
-
`),O=u(c);if(this.mode==="json"){let l=this.getTimestamp();c=O=this.safeStringify({level:"info",time:l.iso,title:r,message:e}),this.dispatch("info",o,[e],c,O,l.iso);return}this.colors&&(c=s("#38bdf8",c));let j=this.getTimestamp();this.dispatch("info",o,[e],c,O,j.iso);}},st=t=>new k(t);exports.ConsoleTransport=C;exports.LogLevel=y;exports.Logger=k;exports.ansi=I;exports.classicTheme=et;exports.createLogger=st;exports.defaultTheme=$;exports.minimalTheme=rt;exports.modernTheme=N;
|
|
1
|
+
"use strict";var t=require("fs/promises"),e=require("fs"),s=require("path"),r=Object.defineProperty,i={};((t,e)=>{for(var s in e)r(t,s,{get:e[s],enumerable:!0})})(i,{bgBlack:()=>w,bgBlue:()=>k,bgColor256:()=>N,bgCyan:()=>j,bgGreen:()=>v,bgHex:()=>I,bgMagenta:()=>O,bgRed:()=>x,bgRgb:()=>L,bgWhite:()=>C,bgYellow:()=>y,black:()=>f,blue:()=>u,bold:()=>E,color256:()=>F,cyan:()=>b,dim:()=>T,format:()=>c,gray:()=>$,green:()=>m,hex:()=>A,inverse:()=>M,isColorSupported:()=>o,italic:()=>S,magenta:()=>d,red:()=>l,reset:()=>h,rgb:()=>R,stripAnsi:()=>q,underline:()=>z,white:()=>g,yellow:()=>p});var n=process.env,o=!n.NO_COLOR&&(n.FORCE_COLOR||process.stdout&&process.stdout.isTTY||"xterm-256color"===n.TERM||"true"===n.CI),a=(t,e)=>o?`[${t}m${e}[0m`:e,c=a,h=t=>a(0,t),f=t=>a(30,t),l=t=>a(31,t),m=t=>a(32,t),p=t=>a(33,t),u=t=>a(34,t),d=t=>a(35,t),b=t=>a(36,t),g=t=>a(37,t),$=t=>a(90,t),w=t=>a(40,t),x=t=>a(41,t),v=t=>a(42,t),y=t=>a(43,t),k=t=>a(44,t),O=t=>a(45,t),j=t=>a(46,t),C=t=>a(47,t),E=t=>a(1,t),T=t=>a(2,t),S=t=>a(3,t),z=t=>a(4,t),M=t=>a(7,t),R=(t,e,s,r)=>o?`[38;2;${t};${e};${s}m${r}[0m`:r,L=(t,e,s,r)=>o?`[48;2;${t};${e};${s}m${r}[0m`:r,A=(t,e)=>{if(!o)return e;const s=t.replace("#","");return 6===s.length?R(parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),e):e},I=(t,e)=>{if(!o)return e;const s=t.replace("#","");return 6===s.length?L(parseInt(s.slice(0,2),16),parseInt(s.slice(2,4),16),parseInt(s.slice(4,6),16),e):e},F=(t,e)=>o?`[38;5;${t}m${e}[0m`:e,N=(t,e)=>o?`[48;5;${t}m${e}[0m`:e,q=t=>t.replace(/\x1b\[[0-9;]*m/g,""),P={success:t=>A("#10b981",t),error:t=>A("#f43f5e",t),warn:t=>A("#f59e0b",t),info:t=>A("#38bdf8",t),prefix:{success:A("#10b981","✔")+" "+A("#34d399",T("success")),error:A("#f43f5e","✖")+" "+A("#fb7185",T("error")),warn:A("#f59e0b","⚠")+" "+A("#fbbf24",T("warn")),info:A("#38bdf8","ℹ")+" "+A("#7dd3fc",T("info"))}},W={success:t=>t,error:t=>t,warn:t=>t,info:t=>t,prefix:{success:A("#10b981","✔"),error:A("#f43f5e","✖"),warn:A("#f59e0b","⚠"),info:A("#38bdf8","ℹ")}},B={success:t=>m(t),error:t=>l(t),warn:t=>p(t),info:t=>b(t),prefix:{success:m("SUCCESS"),error:l("ERROR"),warn:p("WARN"),info:b("INFO")}},U=P,D=(t=>(t[t.trace=10]="trace",t[t.debug=20]="debug",t[t.info=30]="info",t[t.success=35]="success",t[t.warn=40]="warn",t[t.error=50]="error",t[t.fatal=60]="fatal",t[t.none=100]="none",t))(D||{}),J=class{write(t){(t.levelValue>=50?console.error:console.log)(t.formatted)}},_={iso:"",formatted:""},V=new Set;function Y(t,e){V.clear();const s=JSON.stringify(t,(t,e)=>{if("object"==typeof e&&null!==e){if(V.has(e))return"[Circular]";V.add(e)}return e},e);return V.clear(),s}function G(t,e){if("object"!=typeof t||null===t||t instanceof Error)return t;if(Array.isArray(t))return t.map(t=>G(t,e));const s={};for(const[r,i]of Object.entries(t))s[r]=e.has(r.toLowerCase())?"[REDACTED]":"object"!=typeof i||null===i||i instanceof Error?i:G(i,e);return s}var H=class t{t;ts;c;lv;m;tr;tc={t:"",s:""};sp;rk;ns;gd=0;tm=new Map;sc=new Map;dm;constructor(t={},e={}){this.t={...U,...t.theme,prefix:{...U.prefix,...t.theme?.prefix}},this.ts=t.timestamps??!1,this.c=t.colors??Boolean(o),this.lv=D[t.level??"trace"],this.m=t.mode??"text",this.tr=t.transports??[new J],this.sp=t.sampling??{},this.rk=new Set((t.redact??[]).map(t=>t.toLowerCase())),this.ns=t.namespace??"",this.dm=e}child(e){const{namespace:s,...r}=e;return new t({theme:this.t,timestamps:this.ts,colors:this.c,level:Object.keys(D).find(t=>D[t]===this.lv),mode:this.m,transports:this.tr,sampling:this.sp,redact:Array.from(this.rk),namespace:s?this.ns?`${this.ns}:${s}`:s:this.ns},{...this.dm,...r})}group(t){if(30<this.lv)return;const e=this.getTs(),s=this.nsPrefix(),r=" ".repeat(this.gd);if("json"===this.m){const s=Y({level:"info",type:"groupStart",label:t,time:e.iso});this.dispatch("info",30,[t],s,s,e.iso)}else{const i=`${e.formatted}${s}${r}${this.c?E(b(`▸ ${t}`)):`▸ ${t}`}`;this.dispatch("info",30,[t],i,q(i),e.iso)}this.gd++}groupEnd(){this.gd>0&&this.gd--}time(t){this.tm.set(t,performance.now())}timeEnd(t){const e=this.tm.get(t);if(void 0===e)return;this.tm.delete(t);const s=performance.now()-e;this.info(`${t}: ${s<1?s.toFixed(3):Math.round(s)}ms`)}getTs(){if(!this.ts)return _;const t=(new Date).toISOString(),e=t.slice(11,19);if(this.tc.t===e)return{iso:t,formatted:this.tc.s};const s=$(`[${e}] `);return this.tc={t:e,s:s},{iso:t,formatted:s}}nsPrefix(){return this.ns?this.c?A("#a78bfa",`[${this.ns}] `):`[${this.ns}] `:""}hlJson(t){return!this.c||t.length>5e3?t:t.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,t=>'"'===t[0]?t.endsWith(":")?A("#9ca3af",t.slice(0,-1))+":":A("#34d399",t):A("true"===t||"false"===t?"#c084fc":"null"===t?"#f87171":"#fbbf24",t))}fmtErr(t){const e=t.stack||t.message;return this.c?e.split("\n").map((t,e)=>{if(0===e)return E(l(t));const s=t.match(/^(\s+at\s+)(.+?)(\s+\()?(.+?):(\d+):(\d+)\)?$/);return s?s[4].includes("node_modules")||s[4].startsWith("node:")?T(t):`${T(s[1])}${p(s[2])}${T(s[3]||" ")}${b(s[4])}:${A("#fbbf24",s[5])}:${T(s[6])}${s[3]?T(")"):""}`:t.match(/^\s+at\s+/)?T(t):l(t)}).join("\n"):e}fmtMsg(t){return t.map(t=>{if("string"==typeof t)return t;if(t instanceof Error)return"\n"+this.fmtErr(t);try{return"\n"+this.hlJson(Y(this.rk.size?G(t,this.rk):t,2))}catch{return"[Unserializable]"}}).join(" ")}emit(t,e,s,r){const i=D[t];if(i<this.lv)return;const n=this.getTs(),o=this.nsPrefix(),a=" ".repeat(this.gd);let c,h;if("json"===this.m){const e=r.map(t=>"object"!=typeof t||null===t||t instanceof Error||!this.rk.size?t:G(t,this.rk)),s={level:t,time:n.iso,message:1===e.length?e[0]:e};this.ns&&(s.namespace=this.ns),Object.keys(this.dm).length&&Object.assign(s,this.dm),c=h=Y(s)}else c=`${n.formatted}${o}${a}${e} ${s(this.fmtMsg(r))}`,h=q(c),this.c||(c=h);this.dispatch(t,i,r,c,h,n.iso)}dispatch(t,e,s,r,i,n){const o={level:t,levelValue:e,message:s,formatted:r,raw:i,timestamp:n,namespace:this.ns||void 0,meta:Object.keys(this.dm).length?this.dm:void 0};for(let t=0;t<this.tr.length;t++)this.tr[t]?.write(o)}success(...t){this.emit("success",this.t.prefix.success,this.t.success,t)}error(...t){this.emit("error",this.t.prefix.error,this.t.error,t)}warn(...t){this.emit("warn",this.t.prefix.warn,this.t.warn,t)}info(...t){this.emit("info",this.t.prefix.info,this.t.info,t)}trace(...t){this.emit("trace",$("🔍"),$,t)}debug(...t){this.emit("debug",A("#94a3b8","🐛"),t=>A("#94a3b8",t),t)}fatal(...t){this.emit("fatal",A("#be123c","💀"),t=>A("#be123c",t),t)}box(t,e){if(30<this.lv)return;const s=e.split("\n"),r=Math.max(t.length,...s.map(t=>q(t).length))+4,i=`┌─ ${t} ${"─".repeat(r-t.length-3)}┐`,n=`└${"─".repeat(r)}┘`;let o=[i,...s.map(t=>`│ ${t}${" ".repeat(Math.max(0,r-q(t).length-2))} │`),n].join("\n");const a=q(o),c=this.getTs();if("json"===this.m){const s=Y({level:"info",time:c.iso,title:t,message:e});return void this.dispatch("info",30,[e],s,s,c.iso)}this.c&&(o=A("#38bdf8",o)),this.dispatch("info",30,[e],o,a,c.iso)}},K={b:1,kb:1024,mb:1048576,gb:1073741824};exports.ConsoleTransport=J,exports.FileTransport=class{fp;ms;mf;rot;sz=0;q=Promise.resolve();init=!1;constructor(t){this.fp=t.path,this.ms=function(t){if("number"==typeof t)return t;const e=t.trim().toLowerCase().match(/^([\d.]+)\s*(b|kb|mb|gb)?$/);return e?Math.floor(parseFloat(e[1])*K[e[2]||"b"]):10485760}(t.maxSize??"10mb"),this.mf=t.maxFiles??5,this.rot=t.rotate??!0;const r=s.dirname(this.fp);e.existsSync(r)||e.mkdirSync(r,{recursive:!0})}write(t){const e=t.raw+"\n";this.q=this.q.then(()=>this.flush(e))}async flush(e){if(!this.init){try{this.sz=(await t.stat(this.fp)).size}catch{this.sz=0}this.init=!0}const s=Buffer.byteLength(e,"utf8");if(this.rot&&this.sz+s>this.ms){for(let e=this.mf-1;e>=1;e--)try{await t.rename(1===e?this.fp:`${this.fp}.${e-1}`,`${this.fp}.${e}`)}catch{}try{await t.unlink(this.fp)}catch{}this.sz=0}await t.appendFile(this.fp,e,"utf8"),this.sz+=s}},exports.LogLevel=D,exports.Logger=H,exports.ansi=i,exports.classicTheme=B,exports.createLogger=t=>new H(t),exports.defaultTheme=U,exports.httpMiddleware=function(t,e={}){const s=e.warnAbove??400,r=e.errorAbove??500;return(e,i,n)=>{const o=performance.now(),a=e.method??"UNKNOWN",c=e.originalUrl??e.url??"/",h=()=>{const e=Math.round(performance.now()-o),n=i.statusCode??0,h=`${a} ${c} ${n} ${e}ms`;n>=r?t.error(h):n>=s?t.warn(h):t.info(h)},f=i.on,l=i.once;"function"==typeof f?f.call(i,"finish",h):"function"==typeof l&&l.call(i,"close",h),n()}},exports.minimalTheme=W,exports.modernTheme=P;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
`+this.highlightJson(this.safeStringify(e,2))}catch{return "[Unserializable]"}}).join(" ")}emit(r,e,o,g){let a=y[r];if(!this.shouldLog(a))return;let f=this.getTimestamp(),m,n;if(this.mode==="json"){let c={level:r,time:f.iso,message:g.length===1?g[0]:g};m=n=this.safeStringify(c);}else {let c=this.formatMessage(g);m=`${f.formatted}${e} ${o(c)}`,n=u(m),this.colors||(m=n);}this.dispatch(r,a,g,m,n,f.iso);}dispatch(r,e,o,g,a,f){let m={level:r,levelValue:e,message:o,formatted:g,raw:a,timestamp:f};for(let n=0;n<this.transports.length;n++)this.transports[n]?.write(m);}success(...r){this.emit("success",this.theme.prefix.success,this.theme.success,r);}error(...r){this.emit("error",this.theme.prefix.error,this.theme.error,r);}warn(...r){this.emit("warn",this.theme.prefix.warn,this.theme.warn,r);}info(...r){this.emit("info",this.theme.prefix.info,this.theme.info,r);}trace(...r){this.emit("trace",b("\u{1F50D}"),b,r);}debug(...r){this.emit("debug",s("#94a3b8","\u{1F41B}"),e=>s("#94a3b8",e),r);}fatal(...r){this.emit("fatal",s("#be123c","\u{1F480}"),e=>s("#be123c",e),r);}box(r,e){let o=30;if(!this.shouldLog(o))return;let g=e.split(`
|
|
3
|
-
`),a=Math.max(r.length,...g.map(l=>u(l).length))+4,f=`\u250C\u2500 ${r} ${"\u2500".repeat(a-r.length-3)}\u2510`,m=`\u2514${"\u2500".repeat(a)}\u2518`,n=g.map(l=>{let E=a-u(l).length-2;return `\u2502 ${l}${" ".repeat(Math.max(0,E))} \u2502`}),c=[f,...n,m].join(`
|
|
4
|
-
`),O=u(c);if(this.mode==="json"){let l=this.getTimestamp();c=O=this.safeStringify({level:"info",time:l.iso,title:r,message:e}),this.dispatch("info",o,[e],c,O,l.iso);return}this.colors&&(c=s("#38bdf8",c));let j=this.getTimestamp();this.dispatch("info",o,[e],c,O,j.iso);}},st=t=>new k(t);export{C as ConsoleTransport,y as LogLevel,k as Logger,I as ansi,et as classicTheme,st as createLogger,$ as defaultTheme,rt as minimalTheme,N as modernTheme};
|
|
1
|
+
import{stat as t,rename as s,unlink as e,appendFile as r}from"fs/promises";import{existsSync as i,mkdirSync as n}from"fs";import{dirname as o}from"path";var a=Object.defineProperty,c={};((t,s)=>{for(var e in s)a(t,e,{get:s[e],enumerable:!0})})(c,{bgBlack:()=>O,bgBlue:()=>E,bgColor256:()=>U,bgCyan:()=>M,bgGreen:()=>k,bgHex:()=>W,bgMagenta:()=>z,bgRed:()=>j,bgRgb:()=>F,bgWhite:()=>R,bgYellow:()=>C,black:()=>u,blue:()=>$,bold:()=>S,color256:()=>B,cyan:()=>v,dim:()=>A,format:()=>m,gray:()=>x,green:()=>b,hex:()=>P,inverse:()=>N,isColorSupported:()=>f,italic:()=>I,magenta:()=>w,red:()=>d,reset:()=>p,rgb:()=>L,stripAnsi:()=>q,underline:()=>T,white:()=>y,yellow:()=>g});var h=process.env,f=!h.NO_COLOR&&(h.FORCE_COLOR||process.stdout&&process.stdout.isTTY||"xterm-256color"===h.TERM||"true"===h.CI),l=(t,s)=>f?`[${t}m${s}[0m`:s,m=l,p=t=>l(0,t),u=t=>l(30,t),d=t=>l(31,t),b=t=>l(32,t),g=t=>l(33,t),$=t=>l(34,t),w=t=>l(35,t),v=t=>l(36,t),y=t=>l(37,t),x=t=>l(90,t),O=t=>l(40,t),j=t=>l(41,t),k=t=>l(42,t),C=t=>l(43,t),E=t=>l(44,t),z=t=>l(45,t),M=t=>l(46,t),R=t=>l(47,t),S=t=>l(1,t),A=t=>l(2,t),I=t=>l(3,t),T=t=>l(4,t),N=t=>l(7,t),L=(t,s,e,r)=>f?`[38;2;${t};${s};${e}m${r}[0m`:r,F=(t,s,e,r)=>f?`[48;2;${t};${s};${e}m${r}[0m`:r,P=(t,s)=>{if(!f)return s;const e=t.replace("#","");return 6===e.length?L(parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16),s):s},W=(t,s)=>{if(!f)return s;const e=t.replace("#","");return 6===e.length?F(parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16),s):s},B=(t,s)=>f?`[38;5;${t}m${s}[0m`:s,U=(t,s)=>f?`[48;5;${t}m${s}[0m`:s,q=t=>t.replace(/\x1b\[[0-9;]*m/g,""),D={success:t=>P("#10b981",t),error:t=>P("#f43f5e",t),warn:t=>P("#f59e0b",t),info:t=>P("#38bdf8",t),prefix:{success:P("#10b981","✔")+" "+P("#34d399",A("success")),error:P("#f43f5e","✖")+" "+P("#fb7185",A("error")),warn:P("#f59e0b","⚠")+" "+P("#fbbf24",A("warn")),info:P("#38bdf8","ℹ")+" "+P("#7dd3fc",A("info"))}},J={success:t=>t,error:t=>t,warn:t=>t,info:t=>t,prefix:{success:P("#10b981","✔"),error:P("#f43f5e","✖"),warn:P("#f59e0b","⚠"),info:P("#38bdf8","ℹ")}},_={success:t=>b(t),error:t=>d(t),warn:t=>g(t),info:t=>v(t),prefix:{success:b("SUCCESS"),error:d("ERROR"),warn:g("WARN"),info:v("INFO")}},V=D,Y=(t=>(t[t.trace=10]="trace",t[t.debug=20]="debug",t[t.info=30]="info",t[t.success=35]="success",t[t.warn=40]="warn",t[t.error=50]="error",t[t.fatal=60]="fatal",t[t.none=100]="none",t))(Y||{}),G=class{write(t){(t.levelValue>=50?console.error:console.log)(t.formatted)}},H={iso:"",formatted:""},K=new Set;function Z(t,s){K.clear();const e=JSON.stringify(t,(t,s)=>{if("object"==typeof s&&null!==s){if(K.has(s))return"[Circular]";K.add(s)}return s},s);return K.clear(),e}function Q(t,s){if("object"!=typeof t||null===t||t instanceof Error)return t;if(Array.isArray(t))return t.map(t=>Q(t,s));const e={};for(const[r,i]of Object.entries(t))e[r]=s.has(r.toLowerCase())?"[REDACTED]":"object"!=typeof i||null===i||i instanceof Error?i:Q(i,s);return e}var X=class t{t;ts;c;lv;m;tr;tc={t:"",s:""};sp;rk;ns;gd=0;tm=new Map;sc=new Map;dm;constructor(t={},s={}){this.t={...V,...t.theme,prefix:{...V.prefix,...t.theme?.prefix}},this.ts=t.timestamps??!1,this.c=t.colors??Boolean(f),this.lv=Y[t.level??"trace"],this.m=t.mode??"text",this.tr=t.transports??[new G],this.sp=t.sampling??{},this.rk=new Set((t.redact??[]).map(t=>t.toLowerCase())),this.ns=t.namespace??"",this.dm=s}child(s){const{namespace:e,...r}=s;return new t({theme:this.t,timestamps:this.ts,colors:this.c,level:Object.keys(Y).find(t=>Y[t]===this.lv),mode:this.m,transports:this.tr,sampling:this.sp,redact:Array.from(this.rk),namespace:e?this.ns?`${this.ns}:${e}`:e:this.ns},{...this.dm,...r})}group(t){if(30<this.lv)return;const s=this.getTs(),e=this.nsPrefix(),r=" ".repeat(this.gd);if("json"===this.m){const e=Z({level:"info",type:"groupStart",label:t,time:s.iso});this.dispatch("info",30,[t],e,e,s.iso)}else{const i=`${s.formatted}${e}${r}${this.c?S(v(`▸ ${t}`)):`▸ ${t}`}`;this.dispatch("info",30,[t],i,q(i),s.iso)}this.gd++}groupEnd(){this.gd>0&&this.gd--}time(t){this.tm.set(t,performance.now())}timeEnd(t){const s=this.tm.get(t);if(void 0===s)return;this.tm.delete(t);const e=performance.now()-s;this.info(`${t}: ${e<1?e.toFixed(3):Math.round(e)}ms`)}getTs(){if(!this.ts)return H;const t=(new Date).toISOString(),s=t.slice(11,19);if(this.tc.t===s)return{iso:t,formatted:this.tc.s};const e=x(`[${s}] `);return this.tc={t:s,s:e},{iso:t,formatted:e}}nsPrefix(){return this.ns?this.c?P("#a78bfa",`[${this.ns}] `):`[${this.ns}] `:""}hlJson(t){return!this.c||t.length>5e3?t:t.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,t=>'"'===t[0]?t.endsWith(":")?P("#9ca3af",t.slice(0,-1))+":":P("#34d399",t):P("true"===t||"false"===t?"#c084fc":"null"===t?"#f87171":"#fbbf24",t))}fmtErr(t){const s=t.stack||t.message;return this.c?s.split("\n").map((t,s)=>{if(0===s)return S(d(t));const e=t.match(/^(\s+at\s+)(.+?)(\s+\()?(.+?):(\d+):(\d+)\)?$/);return e?e[4].includes("node_modules")||e[4].startsWith("node:")?A(t):`${A(e[1])}${g(e[2])}${A(e[3]||" ")}${v(e[4])}:${P("#fbbf24",e[5])}:${A(e[6])}${e[3]?A(")"):""}`:t.match(/^\s+at\s+/)?A(t):d(t)}).join("\n"):s}fmtMsg(t){return t.map(t=>{if("string"==typeof t)return t;if(t instanceof Error)return"\n"+this.fmtErr(t);try{return"\n"+this.hlJson(Z(this.rk.size?Q(t,this.rk):t,2))}catch{return"[Unserializable]"}}).join(" ")}emit(t,s,e,r){const i=Y[t];if(i<this.lv)return;const n=this.getTs(),o=this.nsPrefix(),a=" ".repeat(this.gd);let c,h;if("json"===this.m){const s=r.map(t=>"object"!=typeof t||null===t||t instanceof Error||!this.rk.size?t:Q(t,this.rk)),e={level:t,time:n.iso,message:1===s.length?s[0]:s};this.ns&&(e.namespace=this.ns),Object.keys(this.dm).length&&Object.assign(e,this.dm),c=h=Z(e)}else c=`${n.formatted}${o}${a}${s} ${e(this.fmtMsg(r))}`,h=q(c),this.c||(c=h);this.dispatch(t,i,r,c,h,n.iso)}dispatch(t,s,e,r,i,n){const o={level:t,levelValue:s,message:e,formatted:r,raw:i,timestamp:n,namespace:this.ns||void 0,meta:Object.keys(this.dm).length?this.dm:void 0};for(let t=0;t<this.tr.length;t++)this.tr[t]?.write(o)}success(...t){this.emit("success",this.t.prefix.success,this.t.success,t)}error(...t){this.emit("error",this.t.prefix.error,this.t.error,t)}warn(...t){this.emit("warn",this.t.prefix.warn,this.t.warn,t)}info(...t){this.emit("info",this.t.prefix.info,this.t.info,t)}trace(...t){this.emit("trace",x("🔍"),x,t)}debug(...t){this.emit("debug",P("#94a3b8","🐛"),t=>P("#94a3b8",t),t)}fatal(...t){this.emit("fatal",P("#be123c","💀"),t=>P("#be123c",t),t)}box(t,s){if(30<this.lv)return;const e=s.split("\n"),r=Math.max(t.length,...e.map(t=>q(t).length))+4,i=`┌─ ${t} ${"─".repeat(r-t.length-3)}┐`,n=`└${"─".repeat(r)}┘`;let o=[i,...e.map(t=>`│ ${t}${" ".repeat(Math.max(0,r-q(t).length-2))} │`),n].join("\n");const a=q(o),c=this.getTs();if("json"===this.m){const e=Z({level:"info",time:c.iso,title:t,message:s});return void this.dispatch("info",30,[s],e,e,c.iso)}this.c&&(o=P("#38bdf8",o)),this.dispatch("info",30,[s],o,a,c.iso)}},tt=t=>new X(t),st={b:1,kb:1024,mb:1048576,gb:1073741824},et=class{fp;ms;mf;rot;sz=0;q=Promise.resolve();init=!1;constructor(t){this.fp=t.path,this.ms=function(t){if("number"==typeof t)return t;const s=t.trim().toLowerCase().match(/^([\d.]+)\s*(b|kb|mb|gb)?$/);return s?Math.floor(parseFloat(s[1])*st[s[2]||"b"]):10485760}(t.maxSize??"10mb"),this.mf=t.maxFiles??5,this.rot=t.rotate??!0;const s=o(this.fp);i(s)||n(s,{recursive:!0})}write(t){const s=t.raw+"\n";this.q=this.q.then(()=>this.flush(s))}async flush(i){if(!this.init){try{this.sz=(await t(this.fp)).size}catch{this.sz=0}this.init=!0}const n=Buffer.byteLength(i,"utf8");if(this.rot&&this.sz+n>this.ms){for(let t=this.mf-1;t>=1;t--)try{await s(1===t?this.fp:`${this.fp}.${t-1}`,`${this.fp}.${t}`)}catch{}try{await e(this.fp)}catch{}this.sz=0}await r(this.fp,i,"utf8"),this.sz+=n}};function rt(t,s={}){const e=s.warnAbove??400,r=s.errorAbove??500;return(s,i,n)=>{const o=performance.now(),a=s.method??"UNKNOWN",c=s.originalUrl??s.url??"/",h=()=>{const s=Math.round(performance.now()-o),n=i.statusCode??0,h=`${a} ${c} ${n} ${s}ms`;n>=r?t.error(h):n>=e?t.warn(h):t.info(h)},f=i.on,l=i.once;"function"==typeof f?f.call(i,"finish",h):"function"==typeof l&&l.call(i,"close",h),n()}}export{G as ConsoleTransport,et as FileTransport,Y as LogLevel,X as Logger,c as ansi,_ as classicTheme,tt as createLogger,V as defaultTheme,rt as httpMiddleware,J as minimalTheme,D as modernTheme};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devink",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Fast, lightweight, professional logger
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Fast, lightweight, professional TypeScript logger with child loggers, HTTP middleware, file transport, log sampling, field redaction, and zero dependencies.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -30,16 +30,26 @@
|
|
|
30
30
|
"prepack": "npm run build"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
"logger",
|
|
34
|
+
"logging",
|
|
35
|
+
"node-logger",
|
|
36
|
+
"typescript-logger",
|
|
37
|
+
"terminal-logger",
|
|
38
|
+
"ansi-colors",
|
|
39
|
+
"cli-logger",
|
|
40
|
+
"console-logger",
|
|
41
|
+
"structured-logger",
|
|
42
|
+
"zero-dependency",
|
|
43
|
+
"child-logger",
|
|
44
|
+
"http-middleware",
|
|
45
|
+
"express-logger",
|
|
46
|
+
"file-transport",
|
|
47
|
+
"log-rotation",
|
|
48
|
+
"log-sampling",
|
|
49
|
+
"redact",
|
|
50
|
+
"json-logger",
|
|
51
|
+
"pino-alternative",
|
|
52
|
+
"winston-alternative"
|
|
43
53
|
],
|
|
44
54
|
"author": "harrymate22",
|
|
45
55
|
"license": "MIT",
|
|
@@ -54,6 +64,7 @@
|
|
|
54
64
|
"eslint-config-prettier": "^9.1.0",
|
|
55
65
|
"globals": "^15.0.0",
|
|
56
66
|
"prettier": "^3.0.0",
|
|
67
|
+
"terser": "^5.46.0",
|
|
57
68
|
"tsup": "^8.0.0",
|
|
58
69
|
"typescript": "^5.0.0",
|
|
59
70
|
"typescript-eslint": "^8.0.0",
|