@getsoda/core 0.2.0 → 0.2.2
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 +23 -0
- package/dist/app/app.d.ts.map +1 -1
- package/dist/app/app.js +17 -0
- package/dist/app/app.js.map +1 -1
- package/dist/config/config.d.ts +57 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +72 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/module.d.ts +29 -0
- package/dist/config/module.d.ts.map +1 -0
- package/dist/config/module.js +28 -0
- package/dist/config/module.js.map +1 -0
- package/dist/di/container.d.ts +2 -0
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +9 -0
- package/dist/di/container.js.map +1 -1
- package/dist/http/decorators.d.ts +6 -1
- package/dist/http/decorators.d.ts.map +1 -1
- package/dist/http/decorators.js.map +1 -1
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js.map +1 -1
- package/dist/http/routes.d.ts +10 -1
- package/dist/http/routes.d.ts.map +1 -1
- package/dist/http/routes.js +4 -1
- package/dist/http/routes.js.map +1 -1
- package/dist/http/schema.d.ts +2 -0
- package/dist/http/schema.d.ts.map +1 -1
- package/dist/http/schema.js +2 -1
- package/dist/http/schema.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logger/console-logger.d.ts +12 -4
- package/dist/logger/console-logger.d.ts.map +1 -1
- package/dist/logger/console-logger.js +47 -17
- package/dist/logger/console-logger.js.map +1 -1
- package/package.json +1 -1
- package/src/app/app.ts +24 -1
- package/src/config/config.ts +88 -0
- package/src/config/index.ts +9 -0
- package/src/config/module.ts +40 -0
- package/src/di/container.ts +14 -0
- package/src/http/decorators.ts +9 -2
- package/src/http/index.ts +2 -1
- package/src/http/routes.ts +17 -2
- package/src/http/schema.ts +2 -1
- package/src/index.ts +1 -0
- package/src/logger/console-logger.ts +62 -18
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* Logger writing to stdout and stderr, readable for people or as JSON lines.
|
|
4
4
|
*
|
|
5
5
|
* ```
|
|
6
|
-
*
|
|
7
|
-
* {"time":"2026-11-
|
|
6
|
+
* [Soda] 41250 - 11/14/2026, 12:22:09 AM LOG [UsersService] User created {"id":7} +3ms
|
|
7
|
+
* {"time":"2026-11-13T21:22:09.120Z","level":"log","context":"UsersService","message":"User created","id":7}
|
|
8
8
|
* ```
|
|
9
9
|
*
|
|
10
|
-
* Like Nest's `ConsoleLogger`:
|
|
11
|
-
*
|
|
10
|
+
* Like Nest's `ConsoleLogger`: the same line layout, colored by level in a
|
|
11
|
+
* terminal, with the time since the previous line; a minimum level; a JSON
|
|
12
|
+
* mode for log collectors. `error` and `fatal` go to stderr, the rest to stdout.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import { Logger } from './logger.ts'
|
|
@@ -21,10 +22,42 @@ export interface ConsoleLoggerOptions {
|
|
|
21
22
|
readonly json?: boolean
|
|
22
23
|
/** Where lines go. Defaults to stderr for `error` and `fatal`, stdout otherwise. */
|
|
23
24
|
readonly output?: (line: string, level: LogLevel) => void
|
|
25
|
+
/**
|
|
26
|
+
* Colors by level. Defaults to on when writing to a terminal without
|
|
27
|
+
* `NO_COLOR`, off with a custom `output`.
|
|
28
|
+
*/
|
|
29
|
+
readonly colors?: boolean
|
|
30
|
+
/** Name starting each readable line. Defaults to `Soda`. */
|
|
31
|
+
readonly prefix?: string
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
const SEVERITY: Readonly<Record<LogLevel, number>> = { verbose: 0, debug: 1, log: 2, warn: 3, error: 4, fatal: 5 }
|
|
27
35
|
|
|
36
|
+
const color =
|
|
37
|
+
(code: string) =>
|
|
38
|
+
(text: string): string =>
|
|
39
|
+
`\u001B[${code}m${text}\u001B[0m`
|
|
40
|
+
|
|
41
|
+
const LEVEL_COLORS: Readonly<Record<LogLevel, (text: string) => string>> = {
|
|
42
|
+
verbose: color('96'),
|
|
43
|
+
debug: color('95'),
|
|
44
|
+
log: color('32'),
|
|
45
|
+
warn: color('33'),
|
|
46
|
+
error: color('31'),
|
|
47
|
+
fatal: color('1;31'),
|
|
48
|
+
}
|
|
49
|
+
const yellow = color('38;5;3')
|
|
50
|
+
const plain = (text: string): string => text
|
|
51
|
+
|
|
52
|
+
const dateTime = new Intl.DateTimeFormat(undefined, {
|
|
53
|
+
year: 'numeric',
|
|
54
|
+
month: '2-digit',
|
|
55
|
+
day: '2-digit',
|
|
56
|
+
hour: 'numeric',
|
|
57
|
+
minute: '2-digit',
|
|
58
|
+
second: '2-digit',
|
|
59
|
+
})
|
|
60
|
+
|
|
28
61
|
const writeToConsole = (line: string, level: LogLevel): void => {
|
|
29
62
|
const stream = level === 'error' || level === 'fatal' ? process.stderr : process.stdout
|
|
30
63
|
|
|
@@ -75,12 +108,18 @@ export class ConsoleLogger extends Logger {
|
|
|
75
108
|
readonly #minimum: number
|
|
76
109
|
readonly #json: boolean
|
|
77
110
|
readonly #output: (line: string, level: LogLevel) => void
|
|
111
|
+
readonly #colors: boolean
|
|
112
|
+
readonly #prefix: string
|
|
113
|
+
/** When the previous line was written, for the `+3ms` at the end of the next. */
|
|
114
|
+
#last: number | undefined
|
|
78
115
|
|
|
79
116
|
constructor(options: ConsoleLoggerOptions = {}) {
|
|
80
117
|
super()
|
|
81
118
|
this.#minimum = SEVERITY[options.level ?? 'log']
|
|
82
119
|
this.#json = options.json === true
|
|
83
120
|
this.#output = options.output ?? writeToConsole
|
|
121
|
+
this.#colors = options.colors ?? (options.output === undefined && process.stdout.isTTY === true && process.env.NO_COLOR === undefined)
|
|
122
|
+
this.#prefix = options.prefix ?? 'Soda'
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
write(entry: LogEntry): void {
|
|
@@ -88,29 +127,34 @@ export class ConsoleLogger extends Logger {
|
|
|
88
127
|
return
|
|
89
128
|
}
|
|
90
129
|
|
|
91
|
-
const
|
|
130
|
+
const now = Date.now()
|
|
92
131
|
|
|
93
|
-
this.#output(this.#json ? this.#formatJson(entry,
|
|
132
|
+
this.#output(this.#json ? this.#formatJson(entry, now) : this.#formatText(entry, now), entry.level)
|
|
133
|
+
this.#last = now
|
|
94
134
|
}
|
|
95
135
|
|
|
96
|
-
#formatJson(entry: LogEntry,
|
|
136
|
+
#formatJson(entry: LogEntry, now: number): string {
|
|
137
|
+
const time = new Date(now).toISOString()
|
|
138
|
+
|
|
97
139
|
// Fixed fields last: data cannot overwrite them.
|
|
98
140
|
return stringify({ ...entry.data, time, level: entry.level, context: entry.context, message: entry.message }, 'full')
|
|
99
141
|
}
|
|
100
142
|
|
|
101
|
-
#formatText(entry: LogEntry,
|
|
102
|
-
const
|
|
103
|
-
|
|
143
|
+
#formatText(entry: LogEntry, now: number): string {
|
|
144
|
+
const level = this.#colors ? LEVEL_COLORS[entry.level] : plain
|
|
145
|
+
const accent = this.#colors ? yellow : plain
|
|
146
|
+
const context = entry.context === undefined ? '' : accent(`[${entry.context}] `)
|
|
147
|
+
const since = this.#last === undefined ? '' : accent(` +${now - this.#last}ms`)
|
|
148
|
+
const data = entry.data === undefined ? '' : ` ${stringify(entry.data, 'brief')}`
|
|
149
|
+
const line =
|
|
150
|
+
`${level(`[${this.#prefix}] ${process.pid} - `)}${dateTime.format(now)} ${level(entry.level.toUpperCase().padStart(7))} ` +
|
|
151
|
+
`${context}${level(entry.message)}${data}${since}`
|
|
104
152
|
let stacks = ''
|
|
105
153
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
for (const value of Object.values(entry.data)) {
|
|
111
|
-
if (value instanceof Error && value.stack !== undefined) {
|
|
112
|
-
stacks += `\n${value.stack}`
|
|
113
|
-
}
|
|
154
|
+
// Stacks are read better on their own lines than inside the JSON.
|
|
155
|
+
for (const value of Object.values(entry.data ?? {})) {
|
|
156
|
+
if (value instanceof Error && value.stack !== undefined) {
|
|
157
|
+
stacks += `\n${value.stack}`
|
|
114
158
|
}
|
|
115
159
|
}
|
|
116
160
|
|