@adriangalilea/utils 2.29.0 → 2.31.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 +33 -17
- package/dist/bot/create.js +2 -2
- package/dist/bot/create.js.map +1 -1
- package/dist/bot/menu.d.ts +39 -0
- package/dist/bot/menu.d.ts.map +1 -1
- package/dist/bot/menu.js +43 -2
- package/dist/bot/menu.js.map +1 -1
- package/dist/bot/payments/handlers.js +4 -4
- package/dist/bot/payments/handlers.js.map +1 -1
- package/dist/bot/payments/invoice.js +3 -3
- package/dist/bot/payments/invoice.js.map +1 -1
- package/dist/bot/payments/refund.js +4 -4
- package/dist/bot/payments/refund.js.map +1 -1
- package/dist/bot/payments/waiver.js +2 -2
- package/dist/bot/payments/waiver.js.map +1 -1
- package/dist/bot/profile.js +2 -2
- package/dist/bot/profile.js.map +1 -1
- package/dist/bot/storage-d1.js +2 -2
- package/dist/bot/storage-d1.js.map +1 -1
- package/dist/bot/storage.js +2 -2
- package/dist/bot/storage.js.map +1 -1
- package/dist/bot/worker.js +3 -3
- package/dist/bot/worker.js.map +1 -1
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +3 -3
- package/dist/cli/live.d.ts.map +1 -1
- package/dist/cli/live.js +1 -2
- package/dist/cli/live.js.map +1 -1
- package/dist/cli/text.d.ts +7 -0
- package/dist/cli/text.d.ts.map +1 -1
- package/dist/cli/text.js +21 -2
- package/dist/cli/text.js.map +1 -1
- package/dist/universal/log.d.ts +104 -99
- package/dist/universal/log.d.ts.map +1 -1
- package/dist/universal/log.js +263 -274
- package/dist/universal/log.js.map +1 -1
- package/package.json +2 -1
package/dist/universal/log.js
CHANGED
|
@@ -1,306 +1,295 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Provides colored output with Unicode symbols for different log levels
|
|
2
|
+
* Terminal-first logger with two renderings and one automatic decision.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* No per-scope level control (can't silence 'bor' but keep 'bdns' verbose).
|
|
8
|
-
* - No withTag/child pattern — consumer can't control library log levels.
|
|
4
|
+
* Two knobs, never confusing: format = how lines render, time = whether
|
|
5
|
+
* lines carry time. Each defaults sensibly and independently.
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* Format — LOG_FORMAT=human|record, or setLogFormat(). Default by TTY
|
|
8
|
+
* detection on the sink: a TTY gets human (symbols, color, a line meant
|
|
9
|
+
* for eyes), anything else gets record (level words, plain text, a line
|
|
10
|
+
* meant for a file read later). Detection happens on the stream actually
|
|
11
|
+
* written to (stderr), never a sibling stream.
|
|
15
12
|
*
|
|
16
|
-
*
|
|
13
|
+
* Time — LOG_TIME=1|0, or setLogTime(). Default: on in Node record mode,
|
|
14
|
+
* off everywhere else (human eyes don't need stamps; browser and Worker
|
|
15
|
+
* consoles stamp lines themselves). Record time opens the line with UTC
|
|
16
|
+
* RFC3339; human time prefixes a dim local HH:MM:SS (a human knows
|
|
17
|
+
* today's date).
|
|
18
|
+
*
|
|
19
|
+
* The record line with time on, identical across go-utils and py-utils by
|
|
20
|
+
* design:
|
|
21
|
+
* 2026-08-07T12:34:56Z WARN [scope] message
|
|
22
|
+
* UTC RFC3339 seconds precision · level word padded to 5 · scope brackets
|
|
23
|
+
* only when scoped · no color, no symbols. Grep WARN, not ⚠.
|
|
24
|
+
*
|
|
25
|
+
* Sinks
|
|
26
|
+
* Node/Bun/Deno: every level writes to stderr through console.error, so
|
|
27
|
+
* stdout stays clean for data and cli/live's console routing keeps log
|
|
28
|
+
* lines above an active region.
|
|
29
|
+
* Browser: level-mapped console methods (debug/info/warn/error), human.
|
|
30
|
+
* Workers: level-mapped console methods, record.
|
|
31
|
+
*
|
|
32
|
+
* Levels vs verbs
|
|
33
|
+
* Levels filter: silent < error < warn < info < debug < trace. An unknown
|
|
34
|
+
* LOG_LEVEL is a misconfiguration and throws Panic.
|
|
35
|
+
* Verbs express outcome and are renderings, never levels:
|
|
36
|
+
* error ⨯ fail ⨯ (error) · warn ⚠ (warn) · info · success ✓ · wait ○ ·
|
|
37
|
+
* ready ▶ · step • (info) · debug ◦ (debug) · trace » (trace).
|
|
38
|
+
* In record mode a verb renders as its level word.
|
|
39
|
+
*
|
|
40
|
+
* Scopes
|
|
41
|
+
* log.scope('api') returns a child whose lines carry [api]; scopes nest
|
|
42
|
+
* and join: log.scope('api').scope('auth') → [api auth]. A scoped logger
|
|
43
|
+
* resolves its threshold from {SCOPE}_LOG_LEVEL (upper-cased, joined and
|
|
44
|
+
* sanitized to A-Z0-9_: API_AUTH_LOG_LEVEL, then API_LOG_LEVEL), falling
|
|
45
|
+
* back to setLogLevel(), then LOG_LEVEL, then info — read live, so one
|
|
46
|
+
* subsystem can be silenced or opened up without touching code.
|
|
47
|
+
*
|
|
48
|
+
* Config is env plus three runtime setters — setLogLevel(), setLogFormat(),
|
|
49
|
+
* setLogTime(). No handlers, no formatters, no init. NO_COLOR /
|
|
50
|
+
* FORCE_COLOR override color within human mode. Unknown values of any
|
|
51
|
+
* knob throw Panic. All internal memory is bounded.
|
|
52
|
+
*
|
|
53
|
+
* Siblings: go-utils and py-utils implement the same doctrine in their own
|
|
54
|
+
* idioms; the record line format is identical by design.
|
|
17
55
|
*/
|
|
56
|
+
import { panic } from "../offensive.js";
|
|
18
57
|
import { runtime } from "../runtime.js";
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
import { BOLD, DIM, fg, RESET } from "./ansi.js";
|
|
59
|
+
const sink = runtime.isNode || runtime.isBun || runtime.isDeno
|
|
60
|
+
? "node"
|
|
61
|
+
: runtime.isBrowser
|
|
62
|
+
? "browser"
|
|
63
|
+
: "worker";
|
|
64
|
+
let formatOverride;
|
|
65
|
+
/** Force human or record rendering at runtime. Wins over LOG_FORMAT and auto-detection. */
|
|
66
|
+
export function setLogFormat(format) {
|
|
67
|
+
if (format !== "human" && format !== "record")
|
|
68
|
+
panic("unknown log format:", format, "(want human|record)");
|
|
69
|
+
formatOverride = format;
|
|
70
|
+
}
|
|
71
|
+
function currentFormat() {
|
|
72
|
+
if (formatOverride)
|
|
73
|
+
return formatOverride;
|
|
74
|
+
const env = runtime.env("LOG_FORMAT");
|
|
75
|
+
if (env === "human" || env === "record")
|
|
76
|
+
return env;
|
|
77
|
+
if (env !== undefined)
|
|
78
|
+
panic("unknown LOG_FORMAT:", env, "(want human|record)");
|
|
79
|
+
if (sink === "node")
|
|
80
|
+
return runtime.stderr.isTTY ? "human" : "record";
|
|
81
|
+
return sink === "browser" ? "human" : "record";
|
|
82
|
+
}
|
|
83
|
+
// --- time ----------------------------------------------------------------
|
|
84
|
+
let timeOverride;
|
|
85
|
+
/** Force time prefixes on or off at runtime. Wins over LOG_TIME and the defaults. */
|
|
86
|
+
export function setLogTime(on) {
|
|
87
|
+
timeOverride = on;
|
|
88
|
+
}
|
|
89
|
+
// Default: on only for Node record mode. Human lines are for eyes; browser
|
|
90
|
+
// and Worker consoles stamp every line themselves.
|
|
91
|
+
function timeEnabled(format) {
|
|
92
|
+
if (timeOverride !== undefined)
|
|
93
|
+
return timeOverride;
|
|
94
|
+
const env = runtime.env("LOG_TIME");
|
|
95
|
+
if (env === "1")
|
|
96
|
+
return true;
|
|
97
|
+
if (env === "0")
|
|
98
|
+
return false;
|
|
99
|
+
if (env !== undefined)
|
|
100
|
+
panic("unknown LOG_TIME:", env, "(want 1|0)");
|
|
101
|
+
return format === "record" && sink === "node";
|
|
102
|
+
}
|
|
103
|
+
function colorEnabled() {
|
|
104
|
+
if (currentFormat() === "record")
|
|
105
|
+
return false;
|
|
49
106
|
if (runtime.env("NO_COLOR"))
|
|
50
107
|
return false;
|
|
51
108
|
if (runtime.env("FORCE_COLOR"))
|
|
52
109
|
return true;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export const yellow = formatter(ANSI.yellow);
|
|
68
|
-
export const blue = formatter(ANSI.blue);
|
|
69
|
-
export const magenta = formatter(ANSI.magenta);
|
|
70
|
-
export const cyan = formatter(ANSI.cyan);
|
|
71
|
-
export const white = formatter(ANSI.white);
|
|
72
|
-
export const gray = formatter(ANSI.gray);
|
|
73
|
-
export const purple = formatter(ANSI.purple);
|
|
74
|
-
// Background colors
|
|
75
|
-
export const bgRed = formatter(ANSI.bgRed);
|
|
76
|
-
export const bgGreen = formatter(ANSI.bgGreen);
|
|
77
|
-
export const bgYellow = formatter(ANSI.bgYellow);
|
|
78
|
-
export const bgBlue = formatter(ANSI.bgBlue);
|
|
79
|
-
export const bgMagenta = formatter(ANSI.bgMagenta);
|
|
80
|
-
export const bgCyan = formatter(ANSI.bgCyan);
|
|
81
|
-
export const bgWhite = formatter(ANSI.bgWhite);
|
|
82
|
-
// Prefix symbols matching Next.js style
|
|
83
|
-
const prefixes = {
|
|
84
|
-
wait: white(bold("○")),
|
|
85
|
-
error: red(bold("⨯")),
|
|
86
|
-
warn: yellow(bold("⚠")),
|
|
87
|
-
ready: "▶",
|
|
88
|
-
info: white(bold(" ")),
|
|
89
|
-
success: green(bold("✓")),
|
|
90
|
-
event: green(bold("✓")),
|
|
91
|
-
trace: magenta(bold("»")),
|
|
92
|
-
};
|
|
93
|
-
// Log level priority (lower number = higher priority)
|
|
94
|
-
const LOG_LEVELS = {
|
|
95
|
-
error: 0,
|
|
96
|
-
warn: 1,
|
|
97
|
-
info: 2,
|
|
98
|
-
ready: 2,
|
|
99
|
-
success: 2,
|
|
100
|
-
event: 2,
|
|
101
|
-
wait: 3,
|
|
102
|
-
trace: 4,
|
|
110
|
+
if (sink === "browser")
|
|
111
|
+
return true;
|
|
112
|
+
if (sink === "worker")
|
|
113
|
+
return false;
|
|
114
|
+
return runtime.stderr.isTTY && runtime.env("TERM") !== "dumb";
|
|
115
|
+
}
|
|
116
|
+
// --- levels --------------------------------------------------------------
|
|
117
|
+
const LEVELS = {
|
|
118
|
+
silent: 0,
|
|
119
|
+
error: 1,
|
|
120
|
+
warn: 2,
|
|
121
|
+
info: 3,
|
|
122
|
+
debug: 4,
|
|
123
|
+
trace: 5,
|
|
103
124
|
};
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return LOG_LEVELS.warn;
|
|
110
|
-
case "info":
|
|
111
|
-
return LOG_LEVELS.info;
|
|
112
|
-
case "debug":
|
|
113
|
-
case "trace":
|
|
114
|
-
return LOG_LEVELS.trace;
|
|
115
|
-
default:
|
|
116
|
-
return LOG_LEVELS.info;
|
|
117
|
-
}
|
|
125
|
+
function parseLevel(raw) {
|
|
126
|
+
const n = LEVELS[raw.toLowerCase()];
|
|
127
|
+
if (n === undefined)
|
|
128
|
+
panic("unknown log level:", raw, "(want silent|error|warn|info|debug|trace)");
|
|
129
|
+
return n;
|
|
118
130
|
}
|
|
119
|
-
let
|
|
120
|
-
/** Set the global log level at runtime.
|
|
131
|
+
let levelOverride;
|
|
132
|
+
/** Set the global log level at runtime. Wins over LOG_LEVEL; per-scope env vars still win over this. */
|
|
121
133
|
export function setLogLevel(level) {
|
|
122
|
-
|
|
134
|
+
levelOverride = parseLevel(level);
|
|
123
135
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
this.cache.delete(key);
|
|
136
|
-
this.cache.set(key, item);
|
|
137
|
-
}
|
|
138
|
-
return item;
|
|
139
|
-
}
|
|
140
|
-
set(key, value) {
|
|
141
|
-
if (this.cache.has(key)) {
|
|
142
|
-
this.cache.delete(key);
|
|
143
|
-
}
|
|
144
|
-
this.cache.set(key, value);
|
|
145
|
-
if (this.cache.size > this.maxSize) {
|
|
146
|
-
// Remove least recently used (first item)
|
|
147
|
-
const firstKey = this.cache.keys().next().value;
|
|
148
|
-
if (firstKey !== undefined) {
|
|
149
|
-
this.cache.delete(firstKey);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
has(key) {
|
|
154
|
-
return this.cache.has(key);
|
|
136
|
+
const envKey = (scopes) => `${scopes
|
|
137
|
+
.map((s) => s.toUpperCase().replace(/[^A-Z0-9]+/g, "_"))
|
|
138
|
+
.join("_")}_LOG_LEVEL`;
|
|
139
|
+
// Most specific scope wins: [api auth] reads API_AUTH_LOG_LEVEL, then
|
|
140
|
+
// API_LOG_LEVEL, then the runtime override, then LOG_LEVEL. Read live on
|
|
141
|
+
// every line so a level flip needs no restart hook.
|
|
142
|
+
function threshold(scopes) {
|
|
143
|
+
for (let i = scopes.length; i > 0; i--) {
|
|
144
|
+
const raw = runtime.env(envKey(scopes.slice(0, i)));
|
|
145
|
+
if (raw !== undefined)
|
|
146
|
+
return parseLevel(raw);
|
|
155
147
|
}
|
|
148
|
+
if (levelOverride !== undefined)
|
|
149
|
+
return levelOverride;
|
|
150
|
+
const raw = runtime.env("LOG_LEVEL");
|
|
151
|
+
return raw === undefined ? LEVELS.info : parseLevel(raw);
|
|
156
152
|
}
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
const VERBS = {
|
|
154
|
+
error: { level: "error", symbol: "⨯", style: BOLD + fg(1), indent: "" },
|
|
155
|
+
fail: { level: "error", symbol: "⨯", style: BOLD + fg(1), indent: "" },
|
|
156
|
+
warn: { level: "warn", symbol: "⚠", style: BOLD + fg(3), indent: "" },
|
|
157
|
+
info: { level: "info", symbol: " ", style: "", indent: "" },
|
|
158
|
+
success: { level: "info", symbol: "✓", style: BOLD + fg(2), indent: "" },
|
|
159
|
+
wait: { level: "info", symbol: "○", style: BOLD + fg(7), indent: "" },
|
|
160
|
+
ready: { level: "info", symbol: "▶", style: BOLD + fg(2), indent: "" },
|
|
161
|
+
step: { level: "info", symbol: "•", style: DIM, indent: " " },
|
|
162
|
+
debug: { level: "debug", symbol: "◦", style: fg(8), indent: "" },
|
|
163
|
+
trace: { level: "trace", symbol: "»", style: BOLD + fg(5), indent: "" },
|
|
164
|
+
};
|
|
165
|
+
const LEVEL_WORD = {
|
|
166
|
+
error: "ERROR",
|
|
167
|
+
warn: "WARN ",
|
|
168
|
+
info: "INFO ",
|
|
169
|
+
debug: "DEBUG",
|
|
170
|
+
trace: "TRACE",
|
|
171
|
+
};
|
|
172
|
+
// --- rendering -----------------------------------------------------------
|
|
173
|
+
const rfc3339 = () => `${new Date().toISOString().slice(0, 19)}Z`;
|
|
174
|
+
const clockTime = () => new Date().toTimeString().slice(0, 8);
|
|
175
|
+
function stringify(m) {
|
|
176
|
+
if (typeof m === "string")
|
|
177
|
+
return m;
|
|
178
|
+
if (m instanceof Error)
|
|
179
|
+
return m.stack ?? String(m);
|
|
180
|
+
try {
|
|
181
|
+
return JSON.stringify(m) ?? String(m);
|
|
164
182
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
messages.length === 1) {
|
|
168
|
-
messages.shift();
|
|
183
|
+
catch {
|
|
184
|
+
return String(m);
|
|
169
185
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
186
|
+
}
|
|
187
|
+
const CONSOLE_METHOD = {
|
|
188
|
+
error: "error",
|
|
189
|
+
warn: "warn",
|
|
190
|
+
info: "info",
|
|
191
|
+
debug: "debug",
|
|
192
|
+
trace: "debug",
|
|
193
|
+
};
|
|
194
|
+
function emit(scopes, verb, messages) {
|
|
195
|
+
const v = VERBS[verb];
|
|
196
|
+
if (LEVELS[v.level] > threshold(scopes))
|
|
197
|
+
return;
|
|
198
|
+
// Node funnels every level through console.error: stderr is the log sink
|
|
199
|
+
// and cli/live patches console methods to reroute lines above an active
|
|
200
|
+
// region. Browser/worker use level-mapped methods so platform consoles
|
|
201
|
+
// classify lines correctly.
|
|
202
|
+
const method = sink === "node" ? "error" : CONSOLE_METHOD[v.level];
|
|
203
|
+
const format = currentFormat();
|
|
204
|
+
if (format === "record") {
|
|
205
|
+
const stamp = timeEnabled(format) ? `${rfc3339()} ` : "";
|
|
206
|
+
const scope = scopes.length > 0 ? `[${scopes.join(" ")}] ` : "";
|
|
207
|
+
console[method](`${stamp}${LEVEL_WORD[v.level]} ${scope}${messages.map(stringify).join(" ")}`);
|
|
176
208
|
return;
|
|
177
209
|
}
|
|
178
|
-
|
|
210
|
+
const color = colorEnabled();
|
|
211
|
+
const dimmed = (s) => (color ? `${DIM}${s}${RESET}` : s);
|
|
212
|
+
const stamp = timeEnabled(format) ? `${dimmed(clockTime())} ` : "";
|
|
213
|
+
const symbol = color ? `${v.style}${v.symbol}${RESET}` : v.symbol;
|
|
214
|
+
const scope = scopes.length > 0 ? `${dimmed(`[${scopes.join(" ")}]`)} ` : "";
|
|
215
|
+
const prefix = `${stamp}${v.indent} ${symbol} ${scope}`;
|
|
216
|
+
// A single string collapses into one line; anything richer is handed to
|
|
217
|
+
// console so devtools/util.inspect keep live object rendering.
|
|
179
218
|
if (messages.length === 1 && typeof messages[0] === "string") {
|
|
180
|
-
console[
|
|
219
|
+
console[method](`${prefix}${messages[0]}`);
|
|
181
220
|
}
|
|
182
221
|
else {
|
|
183
|
-
console[
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// Bootstrap function for startup messages (no prefix, just indentation)
|
|
187
|
-
export function bootstrap(...messages) {
|
|
188
|
-
console.log(` ${messages.join(" ")}`);
|
|
189
|
-
}
|
|
190
|
-
// Main logging functions
|
|
191
|
-
export function wait(...messages) {
|
|
192
|
-
prefixedLog("wait", ...messages);
|
|
193
|
-
}
|
|
194
|
-
export function error(...messages) {
|
|
195
|
-
prefixedLog("error", ...messages);
|
|
196
|
-
}
|
|
197
|
-
export function warn(...messages) {
|
|
198
|
-
prefixedLog("warn", ...messages);
|
|
199
|
-
}
|
|
200
|
-
export function ready(...messages) {
|
|
201
|
-
prefixedLog("ready", ...messages);
|
|
202
|
-
}
|
|
203
|
-
export function info(...messages) {
|
|
204
|
-
prefixedLog("info", ...messages);
|
|
205
|
-
}
|
|
206
|
-
export function success(...messages) {
|
|
207
|
-
prefixedLog("success", ...messages);
|
|
208
|
-
}
|
|
209
|
-
export function event(...messages) {
|
|
210
|
-
prefixedLog("event", ...messages);
|
|
211
|
-
}
|
|
212
|
-
export function trace(...messages) {
|
|
213
|
-
prefixedLog("trace", ...messages);
|
|
214
|
-
}
|
|
215
|
-
// Special warn-once function
|
|
216
|
-
export function warnOnce(...messages) {
|
|
217
|
-
const key = messages.join(" ");
|
|
218
|
-
if (!warnOnceCache.has(key)) {
|
|
219
|
-
warnOnceCache.set(key, true);
|
|
220
|
-
warn(...messages);
|
|
222
|
+
console[method](prefix.trimEnd(), ...messages);
|
|
221
223
|
}
|
|
222
224
|
}
|
|
223
|
-
//
|
|
225
|
+
// --- bounded state (daemons run for months) ------------------------------
|
|
226
|
+
const BOUND = 1024;
|
|
227
|
+
const warned = new Set();
|
|
224
228
|
const timers = new Map();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
export function timeEnd(label) {
|
|
229
|
-
const start = timers.get(label);
|
|
230
|
-
if (start === undefined) {
|
|
231
|
-
warn(`Timer '${label}' does not exist`);
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
const duration = Date.now() - start;
|
|
235
|
-
timers.delete(label);
|
|
236
|
-
const formatted = duration > 10000
|
|
237
|
-
? `${Math.round(duration / 100) / 10}s`
|
|
238
|
-
: `${Math.round(duration)}ms`;
|
|
239
|
-
trace(`${label}: ${formatted}`);
|
|
240
|
-
}
|
|
241
|
-
// Utility function to create a prefixed logger instance
|
|
242
|
-
export function createLogger(prefix) {
|
|
229
|
+
function makeLogger(scopes) {
|
|
230
|
+
const verb = (v) => (...messages) => emit(scopes, v, messages);
|
|
243
231
|
return {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
warn: (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
232
|
+
error: verb("error"),
|
|
233
|
+
fail: verb("fail"),
|
|
234
|
+
warn: verb("warn"),
|
|
235
|
+
info: verb("info"),
|
|
236
|
+
success: verb("success"),
|
|
237
|
+
wait: verb("wait"),
|
|
238
|
+
ready: verb("ready"),
|
|
239
|
+
step: verb("step"),
|
|
240
|
+
debug: verb("debug"),
|
|
241
|
+
trace: verb("trace"),
|
|
242
|
+
warnOnce(...messages) {
|
|
243
|
+
const key = scopes.join(" ") + messages.map(stringify).join(" ");
|
|
244
|
+
if (warned.has(key))
|
|
245
|
+
return;
|
|
246
|
+
if (warned.size >= BOUND)
|
|
247
|
+
warned.clear();
|
|
248
|
+
warned.add(key);
|
|
249
|
+
emit(scopes, "warn", messages);
|
|
250
|
+
},
|
|
251
|
+
time(label) {
|
|
252
|
+
if (timers.size >= BOUND)
|
|
253
|
+
timers.clear();
|
|
254
|
+
timers.set(`${scopes.join(" ")}:${label}`, Date.now());
|
|
255
|
+
},
|
|
256
|
+
timeEnd(label) {
|
|
257
|
+
const key = `${scopes.join(" ")}:${label}`;
|
|
258
|
+
const start = timers.get(key);
|
|
259
|
+
if (start === undefined) {
|
|
260
|
+
emit(scopes, "warn", [`Timer '${label}' does not exist`]);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
timers.delete(key);
|
|
264
|
+
const ms = Date.now() - start;
|
|
265
|
+
const pretty = ms > 10_000 ? `${Math.round(ms / 100) / 10}s` : `${Math.round(ms)}ms`;
|
|
266
|
+
emit(scopes, "trace", [`${label}: ${pretty}`]);
|
|
267
|
+
},
|
|
268
|
+
scope(name) {
|
|
269
|
+
return makeLogger([...scopes, name]);
|
|
270
|
+
},
|
|
255
271
|
};
|
|
256
272
|
}
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
273
|
+
const root = makeLogger([]);
|
|
274
|
+
export const error = root.error;
|
|
275
|
+
export const fail = root.fail;
|
|
276
|
+
export const warn = root.warn;
|
|
277
|
+
export const warnOnce = root.warnOnce;
|
|
278
|
+
export const info = root.info;
|
|
279
|
+
export const success = root.success;
|
|
280
|
+
export const wait = root.wait;
|
|
281
|
+
export const ready = root.ready;
|
|
282
|
+
export const step = root.step;
|
|
283
|
+
export const debug = root.debug;
|
|
284
|
+
export const trace = root.trace;
|
|
285
|
+
export const time = root.time;
|
|
286
|
+
export const timeEnd = root.timeEnd;
|
|
287
|
+
export const scope = root.scope;
|
|
288
|
+
/** The root logger plus its runtime knobs, for namespace-style consumers. */
|
|
289
|
+
export const log = {
|
|
290
|
+
...root,
|
|
272
291
|
setLogLevel,
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
bold,
|
|
276
|
-
dim,
|
|
277
|
-
red,
|
|
278
|
-
green,
|
|
279
|
-
yellow,
|
|
280
|
-
blue,
|
|
281
|
-
magenta,
|
|
282
|
-
cyan,
|
|
283
|
-
white,
|
|
284
|
-
gray,
|
|
285
|
-
purple,
|
|
286
|
-
bgRed,
|
|
287
|
-
bgGreen,
|
|
288
|
-
bgYellow,
|
|
289
|
-
bgBlue,
|
|
290
|
-
bgMagenta,
|
|
291
|
-
bgCyan,
|
|
292
|
-
bgWhite,
|
|
293
|
-
},
|
|
292
|
+
setLogFormat,
|
|
293
|
+
setLogTime,
|
|
294
294
|
};
|
|
295
|
-
export { log };
|
|
296
|
-
// Example usage helper
|
|
297
|
-
export function logAppStartup(options) {
|
|
298
|
-
const { name, version, port, host = "localhost", environment } = options;
|
|
299
|
-
bootstrap(bold(purple(`▶ ${name} ${version}`)));
|
|
300
|
-
bootstrap(`- Local: http://${host}:${port}`);
|
|
301
|
-
if (environment) {
|
|
302
|
-
bootstrap(`- Environment: ${environment}`);
|
|
303
|
-
}
|
|
304
|
-
info("");
|
|
305
|
-
}
|
|
306
295
|
//# sourceMappingURL=log.js.map
|