@meadown/logger 1.8.9 → 1.8.11
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/dist/cjs/core/createLog.js +2 -2
- package/dist/cjs/core/writeLog/helpers/formatLocation.d.ts +6 -0
- package/dist/cjs/core/writeLog/helpers/formatLocation.js +20 -0
- package/dist/cjs/core/writeLog/helpers/index.d.ts +3 -0
- package/dist/cjs/core/writeLog/helpers/index.js +17 -0
- package/dist/cjs/core/writeLog/helpers/renderMessage.d.ts +7 -0
- package/dist/cjs/core/writeLog/helpers/renderMessage.js +40 -0
- package/dist/cjs/core/writeLog/helpers/visibleLines.d.ts +6 -0
- package/dist/cjs/core/writeLog/helpers/visibleLines.js +22 -0
- package/dist/cjs/core/writeLog/index.d.ts +2 -0
- package/dist/cjs/core/writeLog/index.js +14 -0
- package/dist/cjs/core/{writeLog.d.ts → writeLog/writeLog.d.ts} +2 -6
- package/dist/cjs/core/writeLog/writeLog.js +43 -0
- package/dist/cjs/decorations/link.d.ts +2 -6
- package/dist/cjs/decorations/link.js +3 -8
- package/dist/cjs/index.d.ts +46 -17
- package/dist/cjs/index.js +20 -10
- package/dist/cjs/tap/createTap.js +6 -6
- package/dist/cjs/tap/tapAsync/helpers/buildBlock.d.ts +19 -0
- package/dist/cjs/tap/tapAsync/helpers/buildBlock.js +56 -0
- package/dist/cjs/tap/tapAsync/helpers/format.d.ts +4 -0
- package/dist/cjs/tap/tapAsync/helpers/format.js +30 -0
- package/dist/cjs/tap/tapAsync/helpers/index.d.ts +4 -0
- package/dist/cjs/tap/tapAsync/helpers/index.js +20 -0
- package/dist/cjs/tap/tapAsync/helpers/isThenable.d.ts +2 -0
- package/dist/cjs/tap/tapAsync/helpers/isThenable.js +15 -0
- package/dist/cjs/tap/tapAsync/helpers/response.d.ts +21 -0
- package/dist/cjs/tap/tapAsync/helpers/response.js +62 -0
- package/dist/cjs/tap/tapAsync/index.d.ts +2 -0
- package/dist/cjs/tap/tapAsync/index.js +13 -0
- package/dist/cjs/tap/{tapAsync.d.ts → tapAsync/tapAsync.d.ts} +1 -3
- package/dist/cjs/tap/tapAsync/tapAsync.js +92 -0
- package/dist/core/createLog.js +1 -1
- package/dist/core/writeLog/helpers/formatLocation.d.ts +6 -0
- package/dist/core/writeLog/helpers/formatLocation.js +17 -0
- package/dist/core/writeLog/helpers/index.d.ts +3 -0
- package/dist/core/writeLog/helpers/index.js +9 -0
- package/dist/core/writeLog/helpers/renderMessage.d.ts +7 -0
- package/dist/core/writeLog/helpers/renderMessage.js +37 -0
- package/dist/core/writeLog/helpers/visibleLines.d.ts +6 -0
- package/dist/core/writeLog/helpers/visibleLines.js +17 -0
- package/dist/core/writeLog/index.d.ts +2 -0
- package/dist/core/writeLog/index.js +8 -0
- package/dist/core/{writeLog.d.ts → writeLog/writeLog.d.ts} +2 -6
- package/dist/core/writeLog/writeLog.js +37 -0
- package/dist/decorations/link.d.ts +2 -6
- package/dist/decorations/link.js +3 -8
- package/dist/index.d.ts +46 -17
- package/dist/index.js +18 -8
- package/dist/tap/createTap.js +3 -3
- package/dist/tap/tapAsync/helpers/buildBlock.d.ts +19 -0
- package/dist/tap/tapAsync/helpers/buildBlock.js +53 -0
- package/dist/tap/tapAsync/helpers/format.d.ts +4 -0
- package/dist/tap/tapAsync/helpers/format.js +26 -0
- package/dist/tap/tapAsync/helpers/index.d.ts +4 -0
- package/dist/tap/tapAsync/helpers/index.js +10 -0
- package/dist/tap/tapAsync/helpers/isThenable.d.ts +2 -0
- package/dist/tap/tapAsync/helpers/isThenable.js +12 -0
- package/dist/tap/tapAsync/helpers/response.d.ts +21 -0
- package/dist/tap/tapAsync/helpers/response.js +57 -0
- package/dist/tap/tapAsync/index.d.ts +2 -0
- package/dist/tap/tapAsync/index.js +8 -0
- package/dist/tap/{tapAsync.d.ts → tapAsync/tapAsync.d.ts} +1 -3
- package/dist/tap/tapAsync/tapAsync.js +89 -0
- package/package.json +7 -4
- package/dist/cjs/core/writeLog.js +0 -92
- package/dist/cjs/tap/tapAsync.js +0 -192
- package/dist/core/writeLog.js +0 -84
- package/dist/tap/tapAsync.js +0 -188
package/dist/tap/tapAsync.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* tapAsync.ts
|
|
3
|
-
* Created by Dewan Mobashirul
|
|
4
|
-
* Copyright (c) 2026 dewan-meadown
|
|
5
|
-
* All rights reserved
|
|
6
|
-
*
|
|
7
|
-
* The async side of `tap`: times a promise and logs a rich response block when
|
|
8
|
-
* it resolves to a `Response` — status color, slow-request highlighting, size,
|
|
9
|
-
* and the actual body — all fire-and-forget so the caller never waits.
|
|
10
|
-
*/
|
|
11
|
-
import { performance } from "node:perf_hooks";
|
|
12
|
-
import { formatWithOptions } from "node:util";
|
|
13
|
-
import { writeLog } from "../core/writeLog.js";
|
|
14
|
-
import { colorize } from "../colors/color.js";
|
|
15
|
-
import { isTTY } from "../terminal/isTTY.js";
|
|
16
|
-
/** Whether `value` is thenable (a promise we can await + time). */
|
|
17
|
-
export function isThenable(value) {
|
|
18
|
-
return (typeof value === "object" &&
|
|
19
|
-
value !== null &&
|
|
20
|
-
typeof value.then === "function");
|
|
21
|
-
}
|
|
22
|
-
/** Whether the resolved value is a fetch `Response` we can read. */
|
|
23
|
-
function isResponse(value) {
|
|
24
|
-
const v = value;
|
|
25
|
-
return (typeof v?.status === "number" &&
|
|
26
|
-
typeof v.clone === "function" &&
|
|
27
|
-
typeof v.text === "function");
|
|
28
|
-
}
|
|
29
|
-
/** `65ms` (green) · `1.2s` (yellow) · `5.8s` (red). */
|
|
30
|
-
function formatDuration(ms, useColor) {
|
|
31
|
-
const text = ms >= 1000 ? `${(ms / 1000).toFixed(2)}s` : `${ms}ms`;
|
|
32
|
-
if (!useColor)
|
|
33
|
-
return text;
|
|
34
|
-
if (ms >= 2000)
|
|
35
|
-
return colorize(text, "red");
|
|
36
|
-
if (ms >= 500)
|
|
37
|
-
return colorize(text, "yellow");
|
|
38
|
-
return colorize(text, "green");
|
|
39
|
-
}
|
|
40
|
-
/** `848 B` / `1.84 KB` / `2.10 MB`. */
|
|
41
|
-
function formatBytes(bytes) {
|
|
42
|
-
if (bytes < 1024)
|
|
43
|
-
return `${bytes} B`;
|
|
44
|
-
if (bytes < 1024 * 1024)
|
|
45
|
-
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
46
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Status badge color:
|
|
50
|
-
* 2xx → green · 3xx → cyan · 4xx → yellow · 5xx → red
|
|
51
|
-
*/
|
|
52
|
-
function statusColor(status) {
|
|
53
|
-
if (status >= 500)
|
|
54
|
-
return "red";
|
|
55
|
-
if (status >= 400)
|
|
56
|
-
return "yellow";
|
|
57
|
-
if (status >= 300)
|
|
58
|
-
return "cyan";
|
|
59
|
-
return "green";
|
|
60
|
-
}
|
|
61
|
-
function formatStatus(res, useColor) {
|
|
62
|
-
const text = typeof res.statusText === "string" && res.statusText
|
|
63
|
-
? `${res.status} ${res.statusText}`
|
|
64
|
-
: `${res.status}`;
|
|
65
|
-
return useColor ? colorize(text, statusColor(res.status)) : text;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Reads a (cloned) response body and returns both the parsed value and the
|
|
69
|
-
* actual byte size. Size is calculated from the body text — not `Content-Length`,
|
|
70
|
-
* which is absent on compressed responses — so size is always shown.
|
|
71
|
-
*/
|
|
72
|
-
async function readBody(res) {
|
|
73
|
-
try {
|
|
74
|
-
const text = await res.text();
|
|
75
|
-
const bytes = new TextEncoder().encode(text).length;
|
|
76
|
-
const size = formatBytes(bytes);
|
|
77
|
-
if (text === "")
|
|
78
|
-
return { data: undefined, size };
|
|
79
|
-
try {
|
|
80
|
-
return { data: JSON.parse(text), size };
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return { data: text, size };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
return { data: undefined, size: "unknown" };
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Renders the nested tree block the user asked for:
|
|
92
|
-
*
|
|
93
|
-
* GET /users/1
|
|
94
|
-
* │
|
|
95
|
-
* │ response:
|
|
96
|
-
* │ ├── time: 65ms
|
|
97
|
-
* │ ├── status: 200 OK
|
|
98
|
-
* │ └── size: 848 B
|
|
99
|
-
* │
|
|
100
|
-
* │ body:
|
|
101
|
-
* │ ├── id: 1
|
|
102
|
-
* │ └── name: Leanne Graham
|
|
103
|
-
*/
|
|
104
|
-
function buildBlock(label, ms, res, body, useColor) {
|
|
105
|
-
const paint = (s, c) => useColor ? colorize(s, c) : s;
|
|
106
|
-
const pipe = paint("│", "gray");
|
|
107
|
-
const branch = paint("├──", "gray");
|
|
108
|
-
const last = paint("└──", "gray");
|
|
109
|
-
const indent = `${pipe} `;
|
|
110
|
-
const timeLine = `${indent}${branch} time: ${formatDuration(ms, useColor)}`;
|
|
111
|
-
const statusLine = `${indent}${branch} status: ${formatStatus(res, useColor)}`;
|
|
112
|
-
const sizeLine = `${indent}${last} size: ${body.size}`;
|
|
113
|
-
const responseLines = [`${pipe}`, `${indent}response:`, timeLine, statusLine, sizeLine];
|
|
114
|
-
const head = label === undefined ? "" : `${label}\n`;
|
|
115
|
-
if (body.data === undefined) {
|
|
116
|
-
return [`${head}${responseLines.join("\n")}`];
|
|
117
|
-
}
|
|
118
|
-
// Render the body using util.formatWithOptions so objects/arrays look like
|
|
119
|
-
// console.log output — colors, proper nesting, no JSON.stringify quirkiness.
|
|
120
|
-
const bodyText = formatWithOptions({ colors: useColor }, body.data);
|
|
121
|
-
const bodyLines = bodyText.split("\n");
|
|
122
|
-
const lastIdx = bodyLines.length - 1;
|
|
123
|
-
const bodyBlock = bodyLines
|
|
124
|
-
.map((line, i) => `${indent}${i === lastIdx ? last : branch} ${line}`)
|
|
125
|
-
.join("\n");
|
|
126
|
-
const full = [...responseLines, `${pipe}`, `${indent}body:`, bodyBlock].join("\n");
|
|
127
|
-
return [`${head}${full}`];
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* The async tap. Fire-and-forget: returns `promise` immediately (unchanged),
|
|
131
|
-
* and logs a rich block once it resolves. For a `Response`, reads the body from
|
|
132
|
-
* a clone so the caller's original stays consumable. A rejection logs an error
|
|
133
|
-
* to stderr. `caller` MUST be resolved by `tap` (the user-facing function) so
|
|
134
|
-
* the logged location points at the user's file.
|
|
135
|
-
*/
|
|
136
|
-
export function tapAsync(promise, label, caller) {
|
|
137
|
-
const useColor = isTTY("stdout");
|
|
138
|
-
const start = performance.now();
|
|
139
|
-
void promise.then((resolved) => {
|
|
140
|
-
const ms = Math.round(performance.now() - start);
|
|
141
|
-
if (isResponse(resolved)) {
|
|
142
|
-
let clone = null;
|
|
143
|
-
try {
|
|
144
|
-
clone = resolved.clone();
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
clone = null;
|
|
148
|
-
}
|
|
149
|
-
if (clone === null) {
|
|
150
|
-
writeLog({
|
|
151
|
-
channel: "log", tag: "[TAP]",
|
|
152
|
-
args: buildBlock(label, ms, resolved, { data: undefined, size: "unknown" }, useColor),
|
|
153
|
-
caller,
|
|
154
|
-
});
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
const cl = resolved.headers?.get?.("content-length");
|
|
158
|
-
const tooLarge = cl != null && cl !== "" && Number(cl) > 512 * 1024;
|
|
159
|
-
if (tooLarge) {
|
|
160
|
-
writeLog({
|
|
161
|
-
channel: "log", tag: "[TAP]",
|
|
162
|
-
args: buildBlock(label, ms, resolved, { data: "(body too large to display)", size: formatBytes(Number(cl)) }, useColor),
|
|
163
|
-
caller,
|
|
164
|
-
});
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
void readBody(clone).then((body) => {
|
|
168
|
-
writeLog({ channel: "log", tag: "[TAP]", args: buildBlock(label, ms, resolved, body, useColor), caller });
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
// Non-Response promise — plain value with elapsed time.
|
|
173
|
-
const elapsed = formatDuration(ms, useColor);
|
|
174
|
-
writeLog({
|
|
175
|
-
channel: "log", tag: "[TAP]",
|
|
176
|
-
args: label === undefined ? [elapsed, resolved] : [`${label} ${elapsed}`, resolved],
|
|
177
|
-
caller,
|
|
178
|
-
});
|
|
179
|
-
}, (err) => {
|
|
180
|
-
const ms = Math.round(performance.now() - start);
|
|
181
|
-
const elapsed = formatDuration(ms, useColor);
|
|
182
|
-
writeLog({
|
|
183
|
-
channel: "error", tag: "[TAP]",
|
|
184
|
-
args: [label === undefined ? `rejected after ${elapsed}` : `${label} rejected after ${elapsed}`, err],
|
|
185
|
-
caller,
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
}
|