@nexusts/logger 0.7.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,41 @@
1
+ # @nexusts/logger
2
+
3
+ > **NexusTS** — Bun-native fullstack framework
4
+
5
+ ## Description
6
+
7
+ Pino-backed structured logging.
8
+
9
+ Pretty-printed in dev, JSON in prod. Request-scoped via AsyncLocalStorage (every log line inside a request automatically includes the request id).
10
+
11
+ ## Install
12
+
13
+ This module is part of the NexusTS monorepo. Each module is published as its own npm package under the `@nexusts/` scope.
14
+
15
+ Most apps start with just the core:
16
+
17
+ ```bash
18
+ bun add @nexusts/core reflect-metadata zod hono
19
+ ```
20
+
21
+ Then add this module only if you need it:
22
+
23
+ ```bash
24
+ bun add @nexusts/logger
25
+ ```
26
+
27
+ ## Peer dependencies
28
+
29
+ None. This module is fully self-contained.
30
+
31
+ ## Usage
32
+
33
+ ```typescript
34
+ import { /* public API */ } from "@nexusts/logger";
35
+ ```
36
+
37
+ See the [user guide](../../docs/user-guide/logger.md) and the [example app](../../examples/) for a working demo.
38
+
39
+ ## License
40
+
41
+ MIT — see the root [LICENSE](../../LICENSE).
package/dist/index.js ADDED
@@ -0,0 +1,317 @@
1
+ // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
21
+ r = Reflect.decorate(decorators, target, key, desc);
22
+ else
23
+ for (var i = decorators.length - 1;i >= 0; i--)
24
+ if (d = decorators[i])
25
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
26
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
27
+ };
28
+ var __legacyDecorateParamTS = (index, decorator) => (target, key) => decorator(target, key, index);
29
+ var __legacyMetadataTS = (k, v) => {
30
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
31
+ return Reflect.metadata(k, v);
32
+ };
33
+ var __require = import.meta.require;
34
+ // packages/logger/src/logger.service.ts
35
+ import { AsyncLocalStorage } from "async_hooks";
36
+ import { Inject, Injectable } from "@nexusts/core/decorators/index.js";
37
+
38
+ // packages/logger/src/transports/index.ts
39
+ var pinoSingleton = null;
40
+ var prettySingleton = null;
41
+ async function loadPino(pretty, level, base) {
42
+ const pinoMod = await import("pino");
43
+ const pino = pinoMod.default ?? pinoMod;
44
+ if (pretty) {
45
+ if (prettySingleton)
46
+ return prettySingleton;
47
+ const opts = {
48
+ level,
49
+ base,
50
+ errorKey: "error",
51
+ translateTime: "HH:MM:ss.l",
52
+ ignore: "pid,hostname",
53
+ colorize: true
54
+ };
55
+ try {
56
+ const prettyMod = globalThis.require?.("pino-pretty");
57
+ if (prettyMod) {
58
+ prettySingleton = pino(opts);
59
+ return prettySingleton;
60
+ }
61
+ } catch {}
62
+ prettySingleton = pino({
63
+ level,
64
+ base,
65
+ timestamp: () => `,"time":"${new Date().toISOString()}"`
66
+ });
67
+ return prettySingleton;
68
+ }
69
+ if (pinoSingleton)
70
+ return pinoSingleton;
71
+ pinoSingleton = pino({
72
+ level,
73
+ base,
74
+ timestamp: () => `,"time":"${new Date().toISOString()}"`
75
+ });
76
+ return pinoSingleton;
77
+ }
78
+
79
+ class PinoTransport {
80
+ name = "pino";
81
+ isDefault = true;
82
+ #pino = null;
83
+ #ready;
84
+ constructor(level, base) {
85
+ this.#ready = loadPino(false, level, base).then((p) => {
86
+ this.#pino = p;
87
+ });
88
+ }
89
+ async ready() {
90
+ await this.#ready;
91
+ }
92
+ write(record) {
93
+ if (!this.#pino) {
94
+ console.log(JSON.stringify(record));
95
+ return;
96
+ }
97
+ const { level, time, msg, ...rest } = record;
98
+ const obj = { time, ...rest };
99
+ switch (level) {
100
+ case "trace":
101
+ this.#pino.trace(obj, msg);
102
+ break;
103
+ case "debug":
104
+ this.#pino.debug(obj, msg);
105
+ break;
106
+ case "info":
107
+ this.#pino.info(obj, msg);
108
+ break;
109
+ case "warn":
110
+ this.#pino.warn(obj, msg);
111
+ break;
112
+ case "error":
113
+ this.#pino.error(obj, msg);
114
+ break;
115
+ case "fatal":
116
+ this.#pino.fatal(obj, msg);
117
+ break;
118
+ }
119
+ }
120
+ }
121
+
122
+ class PrettyTransport {
123
+ name = "pretty";
124
+ isDefault = true;
125
+ #pino = null;
126
+ #ready;
127
+ constructor(level, base) {
128
+ this.#ready = loadPino(true, level, base).then((p) => {
129
+ this.#pino = p;
130
+ });
131
+ }
132
+ async ready() {
133
+ await this.#ready;
134
+ }
135
+ write(record) {
136
+ if (!this.#pino) {
137
+ console.log(`[${record.level}] ${record.msg}`, record);
138
+ return;
139
+ }
140
+ const { level, time, msg, ...rest } = record;
141
+ const obj = { time, ...rest };
142
+ switch (level) {
143
+ case "trace":
144
+ this.#pino.trace(obj, msg);
145
+ break;
146
+ case "debug":
147
+ this.#pino.debug(obj, msg);
148
+ break;
149
+ case "info":
150
+ this.#pino.info(obj, msg);
151
+ break;
152
+ case "warn":
153
+ this.#pino.warn(obj, msg);
154
+ break;
155
+ case "error":
156
+ this.#pino.error(obj, msg);
157
+ break;
158
+ case "fatal":
159
+ this.#pino.fatal(obj, msg);
160
+ break;
161
+ }
162
+ }
163
+ }
164
+
165
+ class NullTransport {
166
+ name = "null";
167
+ isDefault = false;
168
+ write(_record) {}
169
+ }
170
+
171
+ // packages/logger/src/logger.service.ts
172
+ var LEVEL_RANK = {
173
+ trace: 10,
174
+ debug: 20,
175
+ info: 30,
176
+ warn: 40,
177
+ error: 50,
178
+ fatal: 60
179
+ };
180
+
181
+ class Logger {
182
+ static TOKEN = Symbol.for("nexus:Logger");
183
+ transports;
184
+ silent;
185
+ base;
186
+ level;
187
+ als = new AsyncLocalStorage;
188
+ constructor(options = {}) {
189
+ this.silent = options.silent ?? false;
190
+ this.base = options.base ?? {};
191
+ this.level = options.level ?? (process.env["NODE_ENV"] === "production" ? "info" : "debug");
192
+ if (options.transports && options.transports.length > 0) {
193
+ this.transports = options.transports;
194
+ } else {
195
+ const pretty = options.pretty ?? process.env["NODE_ENV"] !== "production";
196
+ this.transports = [
197
+ pretty ? new PrettyTransport(this.level, this.base) : new PinoTransport(this.level, this.base)
198
+ ];
199
+ }
200
+ }
201
+ trace(arg1, arg2) {
202
+ this.emit("trace", arg1, arg2);
203
+ }
204
+ debug(arg1, arg2) {
205
+ this.emit("debug", arg1, arg2);
206
+ }
207
+ info(arg1, arg2) {
208
+ this.emit("info", arg1, arg2);
209
+ }
210
+ warn(arg1, arg2) {
211
+ this.emit("warn", arg1, arg2);
212
+ }
213
+ error(arg1, arg2) {
214
+ this.emit("error", arg1, arg2);
215
+ }
216
+ fatal(arg1, arg2) {
217
+ this.emit("fatal", arg1, arg2);
218
+ }
219
+ with(meta, fn) {
220
+ const prev = this.als.getStore() ?? {};
221
+ const next = { ...prev, ...meta };
222
+ return this.als.run(next, fn);
223
+ }
224
+ get context() {
225
+ return this.als.getStore() ?? {};
226
+ }
227
+ child(bindings) {
228
+ const child = Object.create(Logger.prototype);
229
+ child.transports = this.transports;
230
+ child.silent = this.silent;
231
+ child.base = { ...this.base, ...bindings };
232
+ child.level = this.level;
233
+ child.als = this.als;
234
+ return child;
235
+ }
236
+ async ready() {
237
+ for (const t of this.transports) {
238
+ const r = t.ready;
239
+ if (r)
240
+ await r.call(t);
241
+ }
242
+ }
243
+ emit(level, arg1, arg2) {
244
+ if (this.silent)
245
+ return;
246
+ if (LEVEL_RANK[level] < LEVEL_RANK[this.level])
247
+ return;
248
+ let meta = {};
249
+ let msg;
250
+ if (typeof arg1 === "string") {
251
+ msg = arg1;
252
+ } else {
253
+ meta = arg1;
254
+ msg = arg2 ?? "";
255
+ }
256
+ const ctx = this.als.getStore() ?? {};
257
+ const record = {
258
+ level,
259
+ time: Date.now(),
260
+ msg,
261
+ ...this.base,
262
+ ...meta,
263
+ ...ctx
264
+ };
265
+ for (const t of this.transports) {
266
+ try {
267
+ t.write(record);
268
+ } catch {}
269
+ }
270
+ }
271
+ }
272
+ Logger = __legacyDecorateClassTS([
273
+ Injectable(),
274
+ __legacyDecorateParamTS(0, Inject("LOGGER_OPTIONS")),
275
+ __legacyMetadataTS("design:paramtypes", [
276
+ typeof LoggerOptions === "undefined" ? Object : LoggerOptions
277
+ ])
278
+ ], Logger);
279
+ // packages/logger/src/logger.module.ts
280
+ import"reflect-metadata";
281
+ import { Module } from "@nexusts/core/decorators/module.js";
282
+ class LoggerModule {
283
+ static forRoot(options = {}) {
284
+ class ConfiguredLoggerModule {
285
+ }
286
+ ConfiguredLoggerModule = __legacyDecorateClassTS([
287
+ Module({
288
+ providers: [
289
+ Logger,
290
+ { provide: Logger.TOKEN, useExisting: Logger },
291
+ { provide: "LOGGER_OPTIONS", useValue: options }
292
+ ],
293
+ exports: [Logger, Logger.TOKEN]
294
+ })
295
+ ], ConfiguredLoggerModule);
296
+ Object.defineProperty(ConfiguredLoggerModule, "name", {
297
+ value: "ConfiguredLoggerModule"
298
+ });
299
+ return ConfiguredLoggerModule;
300
+ }
301
+ }
302
+ LoggerModule = __legacyDecorateClassTS([
303
+ Module({
304
+ providers: [Logger, { provide: Logger.TOKEN, useExisting: Logger }],
305
+ exports: [Logger, Logger.TOKEN]
306
+ })
307
+ ], LoggerModule);
308
+ export {
309
+ PrettyTransport,
310
+ PinoTransport,
311
+ NullTransport,
312
+ LoggerModule,
313
+ Logger
314
+ };
315
+
316
+ //# debugId=ED234D0B19040FE764756E2164756E21
317
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/logger.service.ts", "../src/transports/index.ts", "../src/logger.module.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * `Logger` — the user-facing logging interface.\n *\n * Logger is request-scoped via `AsyncLocalStorage`: any `logger.info(...)`\n * call inside a request automatically merges in fields set by\n * `logger.with({ requestId, userId, ... })`.\n *\n * Usage:\n * constructor(@Inject(Logger.TOKEN) private logger: Logger) {}\n *\n * this.logger.info({ userId: 'u-1' }, 'user signed in');\n * this.logger.error({ err }, 'failed to save');\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { Inject, Injectable } from \"@nexusts/core/decorators/index.js\";\nimport type {\n\tLogLevel,\n\tLogRecord,\n\tLogTransport,\n\tLoggerOptions,\n\tLogContext,\n} from \"./types.js\";\nimport { PinoTransport, PrettyTransport, NullTransport } from \"./transports/index.js\";\n\nconst LEVEL_RANK: Record<LogLevel, number> = {\n\ttrace: 10,\n\tdebug: 20,\n\tinfo: 30,\n\twarn: 40,\n\terror: 50,\n\tfatal: 60,\n};\n\n@Injectable()\nexport class Logger {\n\t/** DI token — use with `@Inject(Logger.TOKEN)`. */\n\tstatic readonly TOKEN = Symbol.for(\"nexus:Logger\");\n\n\ttransports: LogTransport[];\n\tsilent: boolean;\n\tbase: Record<string, unknown>;\n\tlevel: LogLevel;\n\tals = new AsyncLocalStorage<LogContext>();\n\n\tconstructor(@Inject(\"LOGGER_OPTIONS\") options: LoggerOptions = {}) {\n\t\tthis.silent = options.silent ?? false;\n\t\tthis.base = options.base ?? {};\n\t\tthis.level = options.level ?? (process.env[\"NODE_ENV\"] === \"production\" ? \"info\" : \"debug\");\n\t\tif (options.transports && options.transports.length > 0) {\n\t\t\tthis.transports = options.transports;\n\t\t} else {\n\t\t\tconst pretty = options.pretty ?? process.env[\"NODE_ENV\"] !== \"production\";\n\t\t\tthis.transports = [\n\t\t\t\tpretty\n\t\t\t\t\t? new PrettyTransport(this.level, this.base)\n\t\t\t\t\t: new PinoTransport(this.level, this.base),\n\t\t\t];\n\t\t}\n\t}\n\n\t// ===========================================================================\n\t// Level methods\n\t// ===========================================================================\n\n\ttrace(meta: Record<string, unknown>, msg: string): void;\n\ttrace(msg: string): void;\n\ttrace(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"trace\", arg1, arg2);\n\t}\n\n\tdebug(meta: Record<string, unknown>, msg: string): void;\n\tdebug(msg: string): void;\n\tdebug(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"debug\", arg1, arg2);\n\t}\n\n\tinfo(meta: Record<string, unknown>, msg: string): void;\n\tinfo(msg: string): void;\n\tinfo(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"info\", arg1, arg2);\n\t}\n\n\twarn(meta: Record<string, unknown>, msg: string): void;\n\twarn(msg: string): void;\n\twarn(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"warn\", arg1, arg2);\n\t}\n\n\terror(meta: Record<string, unknown>, msg: string): void;\n\terror(msg: string): void;\n\terror(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"error\", arg1, arg2);\n\t}\n\n\tfatal(meta: Record<string, unknown>, msg: string): void;\n\tfatal(msg: string): void;\n\tfatal(arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tthis.emit(\"fatal\", arg1, arg2);\n\t}\n\n\t// ===========================================================================\n\t// Context\n\t// ===========================================================================\n\n\t/**\n\t * Run `fn` inside a logger context — every log emitted during\n\t * `fn()` is tagged with `meta`.\n\t */\n\twith<T>(meta: LogContext, fn: () => T): T {\n\t\tconst prev = this.als.getStore() ?? {};\n\t\tconst next: LogContext = { ...prev, ...meta };\n\t\treturn this.als.run(next, fn);\n\t}\n\n\t/** Read the current request context (or empty object). */\n\tget context(): LogContext {\n\t\treturn this.als.getStore() ?? {};\n\t}\n\n\t// ===========================================================================\n\t// Child loggers\n\t// ===========================================================================\n\n\t/**\n\t * Derive a child logger that always merges `bindings` into every\n\t * record. Useful for service-scoped loggers.\n\t */\n\tchild(bindings: Record<string, unknown>): Logger {\n\t\tconst child = Object.create(Logger.prototype) as Logger;\n\t\tchild.transports = this.transports;\n\t\tchild.silent = this.silent;\n\t\tchild.base = { ...this.base, ...bindings };\n\t\tchild.level = this.level;\n\t\tchild.als = this.als;\n\t\treturn child;\n\t}\n\n\t// ===========================================================================\n\t// Lifecycle\n\t// ===========================================================================\n\n\t/** Wait for transports to finish loading (Pino is async). */\n\tasync ready(): Promise<void> {\n\t\tfor (const t of this.transports) {\n\t\t\tconst r = (t as { ready?: () => Promise<void> }).ready;\n\t\t\tif (r) await r.call(t);\n\t\t}\n\t}\n\n\t// ===========================================================================\n\t// Internal\n\t// ===========================================================================\n\n\tprivate emit(level: LogLevel, arg1: Record<string, unknown> | string, arg2?: string): void {\n\t\tif (this.silent) return;\n\t\tif (LEVEL_RANK[level] < LEVEL_RANK[this.level]) return;\n\n\t\tlet meta: Record<string, unknown> = {};\n\t\tlet msg: string;\n\t\tif (typeof arg1 === \"string\") {\n\t\t\tmsg = arg1;\n\t\t} else {\n\t\t\tmeta = arg1;\n\t\t\tmsg = arg2 ?? \"\";\n\t\t}\n\n\t\tconst ctx = this.als.getStore() ?? {};\n\t\tconst record: LogRecord = {\n\t\t\tlevel,\n\t\t\ttime: Date.now(),\n\t\t\tmsg,\n\t\t\t...this.base,\n\t\t\t...meta,\n\t\t\t...ctx,\n\t\t};\n\t\tfor (const t of this.transports) {\n\t\t\ttry {\n\t\t\t\tt.write(record);\n\t\t\t} catch {\n\t\t\t\t// never let a logging error crash the request\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Re-export NullTransport for tests.\nexport { NullTransport };",
6
+ "/**\n * Built-in transports.\n *\n * - **PinoTransport** — JSON output via `pino` (production).\n * - **PrettyTransport** — colorized via `pino-pretty` (development).\n *\n * Both wrap the pino API and feed records into the same write loop,\n * so switching is one config flag.\n */\n\nimport type { LogLevel, LogRecord, LogTransport } from \"../types.js\";\n\ninterface PinoLike {\n\tlevel: string;\n\tinfo: (obj: object, msg?: string) => void;\n\twarn: (obj: object, msg?: string) => void;\n\terror: (obj: object, msg?: string) => void;\n\tdebug: (obj: object, msg?: string) => void;\n\ttrace: (obj: object, msg?: string) => void;\n\tfatal: (obj: object, msg?: string) => void;\n\tflush?: () => void;\n}\n\nlet pinoSingleton: PinoLike | null = null;\nlet prettySingleton: PinoLike | null = null;\n\nasync function loadPino(\n\tpretty: boolean,\n\tlevel: LogLevel,\n\tbase?: Record<string, unknown>,\n): Promise<PinoLike> {\n\tconst pinoMod = await import(\"pino\");\n\tconst pino = pinoMod.default ?? pinoMod;\n\tif (pretty) {\n\t\tif (prettySingleton) return prettySingleton;\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tconst opts: any = {\n\t\t\tlevel,\n\t\t\tbase,\n\t\t\terrorKey: \"error\",\n\t\t\ttranslateTime: \"HH:MM:ss.l\",\n\t\t\tignore: \"pid,hostname\",\n\t\t\tcolorize: true,\n\t\t};\n\t\t// Try to use pino-pretty if installed.\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\t\tconst prettyMod = (\n\t\t\t\tglobalThis as { require?: (id: string) => unknown }\n\t\t\t).require?.(\"pino-pretty\") as ((opts: unknown) => unknown) | undefined;\n\t\t\tif (prettyMod) {\n\t\t\t\tprettySingleton = (pino as unknown as (opts: unknown) => PinoLike)(\n\t\t\t\t\topts,\n\t\t\t\t);\n\t\t\t\treturn prettySingleton;\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall through\n\t\t}\n\t\tprettySingleton = (pino as unknown as (opts: unknown) => PinoLike)({\n\t\t\tlevel,\n\t\t\tbase,\n\t\t\ttimestamp: () => `,\"time\":\"${new Date().toISOString()}\"`,\n\t\t});\n\t\treturn prettySingleton;\n\t}\n\tif (pinoSingleton) return pinoSingleton;\n\tpinoSingleton = (pino as unknown as (opts: unknown) => PinoLike)({\n\t\tlevel,\n\t\tbase,\n\t\ttimestamp: () => `,\"time\":\"${new Date().toISOString()}\"`,\n\t});\n\treturn pinoSingleton;\n}\n\n/** JSON transport via pino. */\nexport class PinoTransport implements LogTransport {\n\treadonly name = \"pino\";\n\treadonly isDefault = true;\n\t#pino: PinoLike | null = null;\n\t#ready: Promise<void>;\n\n\tconstructor(level: LogLevel, base?: Record<string, unknown>) {\n\t\tthis.#ready = loadPino(false, level, base).then((p) => {\n\t\t\tthis.#pino = p;\n\t\t});\n\t}\n\n\tasync ready(): Promise<void> {\n\t\tawait this.#ready;\n\t}\n\n\twrite(record: LogRecord): void {\n\t\tif (!this.#pino) {\n\t\t\t// Fall back to stdout until pino is loaded.\n\t\t\tconsole.log(JSON.stringify(record));\n\t\t\treturn;\n\t\t}\n\t\tconst { level, time, msg, ...rest } = record;\n\t\tconst obj = { time, ...rest };\n\t\tswitch (level) {\n\t\t\tcase \"trace\":\n\t\t\t\tthis.#pino.trace(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"debug\":\n\t\t\t\tthis.#pino.debug(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"info\":\n\t\t\t\tthis.#pino.info(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"warn\":\n\t\t\t\tthis.#pino.warn(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis.#pino.error(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"fatal\":\n\t\t\t\tthis.#pino.fatal(obj, msg);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/** Pretty-print transport via pino-pretty (development). */\nexport class PrettyTransport implements LogTransport {\n\treadonly name = \"pretty\";\n\treadonly isDefault = true;\n\t#pino: PinoLike | null = null;\n\t#ready: Promise<void>;\n\n\tconstructor(level: LogLevel, base?: Record<string, unknown>) {\n\t\tthis.#ready = loadPino(true, level, base).then((p) => {\n\t\t\tthis.#pino = p;\n\t\t});\n\t}\n\n\tasync ready(): Promise<void> {\n\t\tawait this.#ready;\n\t}\n\n\twrite(record: LogRecord): void {\n\t\tif (!this.#pino) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(`[${record.level}] ${record.msg}`, record);\n\t\t\treturn;\n\t\t}\n\t\tconst { level, time, msg, ...rest } = record;\n\t\tconst obj = { time, ...rest };\n\t\tswitch (level) {\n\t\t\tcase \"trace\":\n\t\t\t\tthis.#pino.trace(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"debug\":\n\t\t\t\tthis.#pino.debug(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"info\":\n\t\t\t\tthis.#pino.info(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"warn\":\n\t\t\t\tthis.#pino.warn(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis.#pino.error(obj, msg);\n\t\t\t\tbreak;\n\t\t\tcase \"fatal\":\n\t\t\t\tthis.#pino.fatal(obj, msg);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/** Null transport — drops everything. For tests. */\nexport class NullTransport implements LogTransport {\n\treadonly name = \"null\";\n\treadonly isDefault = false;\n\twrite(_record: LogRecord): void {\n\t\t// discard\n\t}\n}\n",
7
+ "/**\n * `LoggerModule` — drop-in module for structured logging.\n *\n * Usage:\n * @Module({\n * imports: [\n * LoggerModule.forRoot({\n * level: 'info', // 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'\n * pretty: process.env.NODE_ENV !== 'production',\n * base: { service: 'my-app' },\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * // any service\n * @Injectable()\n * class MyService {\n * constructor(@Inject(Logger.TOKEN) private logger: Logger) {}\n *\n * async handle() {\n * await this.logger.with({ requestId: 'r-1' }, async () => {\n * this.logger.info({ userId: 'u-1' }, 'processing');\n * });\n * }\n * }\n */\n\nimport \"reflect-metadata\";\nimport { Module } from \"@nexusts/core/decorators/module.js\";\nimport { Logger } from \"./logger.service.js\";\nimport type { LoggerOptions } from \"./types.js\";\n\n@Module({\n\tproviders: [Logger, { provide: Logger.TOKEN, useExisting: Logger }],\n\texports: [Logger, Logger.TOKEN],\n})\nexport class LoggerModule {\n\tstatic forRoot(options: LoggerOptions = {}) {\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tLogger,\n\t\t\t\t{ provide: Logger.TOKEN, useExisting: Logger },\n\t\t\t\t{ provide: \"LOGGER_OPTIONS\", useValue: options },\n\t\t\t],\n\t\t\texports: [Logger, Logger.TOKEN],\n\t\t})\n\t\tclass ConfiguredLoggerModule {}\n\n\t\tObject.defineProperty(ConfiguredLoggerModule, \"name\", {\n\t\t\tvalue: \"ConfiguredLoggerModule\",\n\t\t});\n\n\t\treturn ConfiguredLoggerModule;\n\t}\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "ED234D0B19040FE764756E2164756E21",
11
+ "names": []
12
+ }
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@nexusts/logger",
3
+ "version": "0.7.0",
4
+ "description": "Pino-backed structured logging",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "bun run ../../build.ts"
21
+ },
22
+ "keywords": [
23
+ "nexusts",
24
+ "framework",
25
+ "bun"
26
+ ],
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "@nexusts/core": "^0.7.0"
30
+ }
31
+ }