@meadown/logger 1.8.10 → 1.9.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.
Files changed (142) hide show
  1. package/README.md +149 -51
  2. package/dist/cjs/{config.js → config/index.js} +1 -1
  3. package/dist/cjs/{constants.d.ts → const/index.d.ts} +0 -5
  4. package/dist/cjs/{constants.js → const/index.js} +2 -8
  5. package/dist/cjs/{caller → domain/caller}/getCaller.js +1 -1
  6. package/dist/cjs/{colors → domain/colors}/color.js +1 -1
  7. package/dist/cjs/{decorations → domain/decorations}/link.js +1 -1
  8. package/dist/cjs/{terminal → domain/terminal}/isTTY.js +1 -1
  9. package/dist/cjs/{time → domain/time}/getTimeStamp.js +1 -1
  10. package/dist/cjs/domain/write/helpers/buildContext.d.ts +16 -0
  11. package/dist/cjs/domain/write/helpers/buildContext.js +40 -0
  12. package/dist/cjs/{core/writeLog → domain/write/helpers}/formatLocation.js +3 -2
  13. package/dist/cjs/domain/write/helpers/index.d.ts +4 -0
  14. package/dist/cjs/domain/write/helpers/index.js +20 -0
  15. package/dist/cjs/{core/writeLog → domain/write/helpers}/renderMessage.js +6 -5
  16. package/dist/cjs/{core/writeLog → domain/write/helpers}/visibleLines.js +3 -3
  17. package/dist/cjs/domain/write/index.d.ts +2 -0
  18. package/dist/cjs/domain/write/index.js +14 -0
  19. package/dist/{core/writeLog/index.d.ts → cjs/domain/write/writeLog.d.ts} +2 -3
  20. package/dist/cjs/domain/write/writeLog.js +24 -0
  21. package/dist/cjs/features/logger/index.d.ts +1 -0
  22. package/dist/cjs/features/logger/index.js +21 -0
  23. package/dist/cjs/features/logger-error/index.d.ts +1 -0
  24. package/dist/cjs/features/logger-error/index.js +21 -0
  25. package/dist/cjs/features/logger-group/createGroup.d.ts +11 -0
  26. package/dist/cjs/features/logger-group/createGroup.js +21 -0
  27. package/dist/cjs/features/logger-group/index.d.ts +1 -0
  28. package/dist/cjs/features/logger-group/index.js +14 -0
  29. package/dist/cjs/features/logger-group/writeGroup.d.ts +8 -0
  30. package/dist/cjs/features/logger-group/writeGroup.js +20 -0
  31. package/dist/cjs/features/logger-max-lines/index.d.ts +1 -0
  32. package/dist/cjs/features/logger-max-lines/index.js +12 -0
  33. package/dist/cjs/features/logger-tap/createTap.d.ts +5 -0
  34. package/dist/cjs/features/logger-tap/createTap.js +33 -0
  35. package/dist/cjs/features/logger-tap/index.d.ts +1 -0
  36. package/dist/cjs/features/logger-tap/index.js +14 -0
  37. package/dist/cjs/features/logger-tap/tapAsync/helpers/buildBlock.d.ts +19 -0
  38. package/dist/cjs/features/logger-tap/tapAsync/helpers/buildBlock.js +56 -0
  39. package/dist/cjs/features/logger-tap/tapAsync/helpers/format.d.ts +4 -0
  40. package/dist/cjs/features/logger-tap/tapAsync/helpers/format.js +30 -0
  41. package/dist/cjs/features/logger-tap/tapAsync/helpers/index.d.ts +4 -0
  42. package/dist/cjs/features/logger-tap/tapAsync/helpers/index.js +20 -0
  43. package/dist/cjs/features/logger-tap/tapAsync/helpers/isThenable.d.ts +2 -0
  44. package/dist/cjs/features/logger-tap/tapAsync/helpers/isThenable.js +15 -0
  45. package/dist/cjs/features/logger-tap/tapAsync/helpers/response.d.ts +21 -0
  46. package/dist/cjs/features/logger-tap/tapAsync/helpers/response.js +62 -0
  47. package/dist/cjs/features/logger-tap/tapAsync/index.d.ts +2 -0
  48. package/dist/cjs/features/logger-tap/tapAsync/index.js +13 -0
  49. package/dist/cjs/{tap → features/logger-tap/tapAsync}/tapAsync.d.ts +1 -3
  50. package/dist/cjs/features/logger-tap/tapAsync/tapAsync.js +95 -0
  51. package/dist/cjs/features/logger-warn/index.d.ts +1 -0
  52. package/dist/cjs/features/logger-warn/index.js +21 -0
  53. package/dist/cjs/index.d.ts +63 -18
  54. package/dist/cjs/index.js +29 -15
  55. package/dist/cjs/types/index.d.ts +2 -0
  56. package/dist/cjs/types/index.js +8 -0
  57. package/dist/{config.js → config/index.js} +1 -1
  58. package/dist/{constants.d.ts → const/index.d.ts} +0 -5
  59. package/dist/{constants.js → const/index.js} +1 -7
  60. package/dist/{caller → domain/caller}/getCaller.js +1 -1
  61. package/dist/{colors → domain/colors}/color.js +1 -1
  62. package/dist/{decorations → domain/decorations}/link.js +1 -1
  63. package/dist/{terminal → domain/terminal}/isTTY.js +1 -1
  64. package/dist/{time → domain/time}/getTimeStamp.js +1 -1
  65. package/dist/domain/write/helpers/buildContext.d.ts +16 -0
  66. package/dist/domain/write/helpers/buildContext.js +33 -0
  67. package/dist/{core/writeLog → domain/write/helpers}/formatLocation.js +3 -2
  68. package/dist/domain/write/helpers/index.d.ts +4 -0
  69. package/dist/domain/write/helpers/index.js +10 -0
  70. package/dist/{core/writeLog → domain/write/helpers}/renderMessage.js +5 -4
  71. package/dist/{core/writeLog → domain/write/helpers}/visibleLines.js +2 -2
  72. package/dist/domain/write/index.d.ts +2 -0
  73. package/dist/domain/write/index.js +8 -0
  74. package/dist/{cjs/core/writeLog/index.d.ts → domain/write/writeLog.d.ts} +2 -3
  75. package/dist/domain/write/writeLog.js +21 -0
  76. package/dist/features/logger/index.d.ts +1 -0
  77. package/dist/features/logger/index.js +15 -0
  78. package/dist/features/logger-error/index.d.ts +1 -0
  79. package/dist/features/logger-error/index.js +15 -0
  80. package/dist/features/logger-group/createGroup.d.ts +11 -0
  81. package/dist/features/logger-group/createGroup.js +15 -0
  82. package/dist/features/logger-group/index.d.ts +1 -0
  83. package/dist/features/logger-group/index.js +7 -0
  84. package/dist/features/logger-group/writeGroup.d.ts +8 -0
  85. package/dist/features/logger-group/writeGroup.js +17 -0
  86. package/dist/features/logger-max-lines/index.d.ts +1 -0
  87. package/dist/features/logger-max-lines/index.js +7 -0
  88. package/dist/features/logger-tap/createTap.d.ts +5 -0
  89. package/dist/features/logger-tap/createTap.js +27 -0
  90. package/dist/features/logger-tap/index.d.ts +1 -0
  91. package/dist/features/logger-tap/index.js +7 -0
  92. package/dist/features/logger-tap/tapAsync/helpers/buildBlock.d.ts +19 -0
  93. package/dist/features/logger-tap/tapAsync/helpers/buildBlock.js +53 -0
  94. package/dist/features/logger-tap/tapAsync/helpers/format.d.ts +4 -0
  95. package/dist/features/logger-tap/tapAsync/helpers/format.js +26 -0
  96. package/dist/features/logger-tap/tapAsync/helpers/index.d.ts +4 -0
  97. package/dist/features/logger-tap/tapAsync/helpers/index.js +10 -0
  98. package/dist/features/logger-tap/tapAsync/helpers/isThenable.d.ts +2 -0
  99. package/dist/features/logger-tap/tapAsync/helpers/isThenable.js +12 -0
  100. package/dist/features/logger-tap/tapAsync/helpers/response.d.ts +21 -0
  101. package/dist/features/logger-tap/tapAsync/helpers/response.js +57 -0
  102. package/dist/features/logger-tap/tapAsync/index.d.ts +2 -0
  103. package/dist/features/logger-tap/tapAsync/index.js +8 -0
  104. package/dist/{tap → features/logger-tap/tapAsync}/tapAsync.d.ts +1 -3
  105. package/dist/features/logger-tap/tapAsync/tapAsync.js +92 -0
  106. package/dist/features/logger-warn/index.d.ts +1 -0
  107. package/dist/features/logger-warn/index.js +15 -0
  108. package/dist/index.d.ts +63 -18
  109. package/dist/index.js +29 -15
  110. package/dist/types/index.d.ts +2 -0
  111. package/dist/types/index.js +7 -0
  112. package/package.json +7 -4
  113. package/dist/cjs/core/createLog.d.ts +0 -8
  114. package/dist/cjs/core/createLog.js +0 -29
  115. package/dist/cjs/core/writeLog/index.js +0 -48
  116. package/dist/cjs/tap/createTap.d.ts +0 -18
  117. package/dist/cjs/tap/createTap.js +0 -51
  118. package/dist/cjs/tap/tapAsync.js +0 -192
  119. package/dist/core/createLog.d.ts +0 -8
  120. package/dist/core/createLog.js +0 -23
  121. package/dist/core/writeLog/index.js +0 -39
  122. package/dist/tap/createTap.d.ts +0 -18
  123. package/dist/tap/createTap.js +0 -45
  124. package/dist/tap/tapAsync.js +0 -188
  125. /package/dist/cjs/{config.d.ts → config/index.d.ts} +0 -0
  126. /package/dist/{caller → cjs/domain/caller}/getCaller.d.ts +0 -0
  127. /package/dist/cjs/{colors → domain/colors}/color.d.ts +0 -0
  128. /package/dist/cjs/{decorations → domain/decorations}/link.d.ts +0 -0
  129. /package/dist/cjs/{terminal → domain/terminal}/isTTY.d.ts +0 -0
  130. /package/dist/cjs/{time → domain/time}/getTimeStamp.d.ts +0 -0
  131. /package/dist/cjs/{core/writeLog → domain/write/helpers}/formatLocation.d.ts +0 -0
  132. /package/dist/cjs/{core/writeLog → domain/write/helpers}/renderMessage.d.ts +0 -0
  133. /package/dist/cjs/{core/writeLog → domain/write/helpers}/visibleLines.d.ts +0 -0
  134. /package/dist/{config.d.ts → config/index.d.ts} +0 -0
  135. /package/dist/{cjs → domain}/caller/getCaller.d.ts +0 -0
  136. /package/dist/{colors → domain/colors}/color.d.ts +0 -0
  137. /package/dist/{decorations → domain/decorations}/link.d.ts +0 -0
  138. /package/dist/{terminal → domain/terminal}/isTTY.d.ts +0 -0
  139. /package/dist/{time → domain/time}/getTimeStamp.d.ts +0 -0
  140. /package/dist/{core/writeLog → domain/write/helpers}/formatLocation.d.ts +0 -0
  141. /package/dist/{core/writeLog → domain/write/helpers}/renderMessage.d.ts +0 -0
  142. /package/dist/{core/writeLog → domain/write/helpers}/visibleLines.d.ts +0 -0
@@ -0,0 +1,11 @@
1
+ import { type LogChannel } from "../../types/index.js";
2
+ export interface GroupOptions {
3
+ name: string;
4
+ type?: LogChannel;
5
+ logs: unknown[];
6
+ }
7
+ /** Type of `logger.group` — use this to annotate variables or parameters that accept it. */
8
+ export interface Group {
9
+ (opts: GroupOptions): void;
10
+ }
11
+ export default function group({ name, type, logs, }: GroupOptions): void;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /*
3
+ * createGroup.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = group;
13
+ const index_js_1 = require("../../config/index.js");
14
+ const getCaller_js_1 = __importDefault(require("../../domain/caller/getCaller.js"));
15
+ const writeGroup_js_1 = require("./writeGroup.js");
16
+ function group({ name, type = "log", logs, }) {
17
+ if (!(0, index_js_1.isLogAllowed)())
18
+ return;
19
+ const caller = (0, getCaller_js_1.default)();
20
+ (0, writeGroup_js_1.writeGroup)({ name, channel: type, logs, caller });
21
+ }
@@ -0,0 +1 @@
1
+ export { default, type Group, type GroupOptions } from "./createGroup.js";
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = void 0;
13
+ var createGroup_js_1 = require("./createGroup.js");
14
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(createGroup_js_1).default; } });
@@ -0,0 +1,8 @@
1
+ import { type LogChannel } from "../../types/index.js";
2
+ import { type Caller } from "../../domain/caller/getCaller.js";
3
+ export declare function writeGroup(opts: {
4
+ name: string;
5
+ channel: LogChannel;
6
+ logs: unknown[];
7
+ caller: Caller;
8
+ }): void;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*
3
+ * writeGroup.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.writeGroup = writeGroup;
10
+ const index_js_1 = require("../../domain/write/helpers/index.js");
11
+ function writeGroup(opts) {
12
+ const { name, channel, logs, caller } = opts;
13
+ const { useColor, paint, timeStamp, locOut, connector, connectorEnd, separator, } = (0, index_js_1.buildContext)(channel, caller);
14
+ const tagOut = paint(`[${name.toUpperCase()}]`, index_js_1.TAG_COLOR[channel]);
15
+ const itemLines = logs
16
+ .map((item) => `\n${connector} ${(0, index_js_1.renderMessage)([item], useColor)}`)
17
+ .join("");
18
+ const meta = `\n${connectorEnd} ${timeStamp} ${separator} ${locOut}`;
19
+ console[channel](`\n${tagOut} ${itemLines}${meta}`);
20
+ }
@@ -0,0 +1 @@
1
+ export { getVisibleLines, setVisibleLines } from "../../domain/write/index.js";
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.setVisibleLines = exports.getVisibleLines = void 0;
10
+ var index_js_1 = require("../../domain/write/index.js");
11
+ Object.defineProperty(exports, "getVisibleLines", { enumerable: true, get: function () { return index_js_1.getVisibleLines; } });
12
+ Object.defineProperty(exports, "setVisibleLines", { enumerable: true, get: function () { return index_js_1.setVisibleLines; } });
@@ -0,0 +1,5 @@
1
+ /** Type of `logger.tap` — use this to annotate variables or parameters that accept it. */
2
+ export interface Tap {
3
+ <T>(value: T, label?: string): T;
4
+ }
5
+ export default function tap<T>(value: T, label?: string): T;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /*
3
+ * createTap.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = tap;
13
+ const index_js_1 = require("../../config/index.js");
14
+ const getCaller_js_1 = __importDefault(require("../../domain/caller/getCaller.js"));
15
+ const writeLog_js_1 = require("../../domain/write/writeLog.js");
16
+ const index_js_2 = require("./tapAsync/index.js");
17
+ function tap(value, label) {
18
+ if (!(0, index_js_1.isLogAllowed)())
19
+ return value;
20
+ const caller = (0, getCaller_js_1.default)();
21
+ if ((0, index_js_2.isThenable)(value)) {
22
+ (0, index_js_2.tapAsync)(value, label, caller);
23
+ }
24
+ else {
25
+ (0, writeLog_js_1.writeLog)({
26
+ channel: "log",
27
+ tag: "[TAP]",
28
+ args: label === undefined ? [value] : [label, value],
29
+ caller,
30
+ });
31
+ }
32
+ return value;
33
+ }
@@ -0,0 +1 @@
1
+ export { default, type Tap } from "./createTap.js";
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = void 0;
13
+ var createTap_js_1 = require("./createTap.js");
14
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(createTap_js_1).default; } });
@@ -0,0 +1,19 @@
1
+ import { type ResponseLike } from "./response.js";
2
+ /**
3
+ * Renders the nested tree block:
4
+ *
5
+ * GET /users/1
6
+ * │
7
+ * │ response:
8
+ * │ ├── time: 65ms
9
+ * │ ├── status: 200 OK
10
+ * │ └── size: 848 B
11
+ * │
12
+ * │ body:
13
+ * │ ├── id: 1
14
+ * │ └── name: Leanne Graham
15
+ */
16
+ export declare function buildBlock(label: string | undefined, ms: number, res: ResponseLike, body: {
17
+ data: unknown;
18
+ size: string;
19
+ }, useColor: boolean): unknown[];
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /*
3
+ * buildBlock.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.buildBlock = buildBlock;
10
+ const node_util_1 = require("node:util");
11
+ const format_js_1 = require("./format.js");
12
+ const color_js_1 = require("../../../../domain/colors/color.js");
13
+ const response_js_1 = require("./response.js");
14
+ /**
15
+ * Renders the nested tree block:
16
+ *
17
+ * GET /users/1
18
+ * │
19
+ * │ response:
20
+ * │ ├── time: 65ms
21
+ * │ ├── status: 200 OK
22
+ * │ └── size: 848 B
23
+ * │
24
+ * │ body:
25
+ * │ ├── id: 1
26
+ * │ └── name: Leanne Graham
27
+ */
28
+ function buildBlock(label, ms, res, body, useColor) {
29
+ const paint = (s, c) => useColor ? (0, color_js_1.colorize)(s, c) : s;
30
+ const pipe = paint("│", "gray");
31
+ const branch = paint("├──", "gray");
32
+ const last = paint("└──", "gray");
33
+ const indent = `${pipe} `;
34
+ const timeLine = `${indent}${branch} time: ${(0, format_js_1.formatDuration)(ms, useColor)}`;
35
+ const statusLine = `${indent}${branch} status: ${(0, response_js_1.formatStatus)(res, useColor)}`;
36
+ const sizeLine = `${indent}${last} size: ${body.size}`;
37
+ const responseLines = [
38
+ `${pipe}`,
39
+ `${indent}response:`,
40
+ timeLine,
41
+ statusLine,
42
+ sizeLine,
43
+ ];
44
+ const head = label === undefined ? "" : `${label}\n`;
45
+ if (body.data === undefined) {
46
+ return [`${head}${responseLines.join("\n")}`];
47
+ }
48
+ const bodyText = (0, node_util_1.formatWithOptions)({ colors: useColor }, body.data);
49
+ const bodyLines = bodyText.split("\n");
50
+ const lastIdx = bodyLines.length - 1;
51
+ const bodyBlock = bodyLines
52
+ .map((line, i) => `${indent}${i === lastIdx ? last : branch} ${line}`)
53
+ .join("\n");
54
+ const full = [...responseLines, `${pipe}`, `${indent}body:`, bodyBlock].join("\n");
55
+ return [`${head}${full}`];
56
+ }
@@ -0,0 +1,4 @@
1
+ /** `65ms` (green) · `1.2s` (yellow) · `5.8s` (red). */
2
+ export declare function formatDuration(ms: number, useColor: boolean): string;
3
+ /** `848 B` / `1.84 KB` / `2.10 MB`. */
4
+ export declare function formatBytes(bytes: number): string;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /*
3
+ * format.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.formatDuration = formatDuration;
10
+ exports.formatBytes = formatBytes;
11
+ const color_js_1 = require("../../../../domain/colors/color.js");
12
+ /** `65ms` (green) · `1.2s` (yellow) · `5.8s` (red). */
13
+ function formatDuration(ms, useColor) {
14
+ const text = ms >= 1000 ? `${(ms / 1000).toFixed(2)}s` : `${ms}ms`;
15
+ if (!useColor)
16
+ return text;
17
+ if (ms >= 2000)
18
+ return (0, color_js_1.colorize)(text, "red");
19
+ if (ms >= 500)
20
+ return (0, color_js_1.colorize)(text, "yellow");
21
+ return (0, color_js_1.colorize)(text, "green");
22
+ }
23
+ /** `848 B` / `1.84 KB` / `2.10 MB`. */
24
+ function formatBytes(bytes) {
25
+ if (bytes < 1024)
26
+ return `${bytes} B`;
27
+ if (bytes < 1024 * 1024)
28
+ return `${(bytes / 1024).toFixed(2)} KB`;
29
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
30
+ }
@@ -0,0 +1,4 @@
1
+ export { readBody, isResponse, formatStatus, type ResponseLike, } from "./response.js";
2
+ export { buildBlock } from "./buildBlock.js";
3
+ export { isThenable } from "./isThenable.js";
4
+ export { formatDuration, formatBytes } from "./format.js";
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.formatBytes = exports.formatDuration = exports.isThenable = exports.buildBlock = exports.formatStatus = exports.isResponse = exports.readBody = void 0;
10
+ var response_js_1 = require("./response.js");
11
+ Object.defineProperty(exports, "readBody", { enumerable: true, get: function () { return response_js_1.readBody; } });
12
+ Object.defineProperty(exports, "isResponse", { enumerable: true, get: function () { return response_js_1.isResponse; } });
13
+ Object.defineProperty(exports, "formatStatus", { enumerable: true, get: function () { return response_js_1.formatStatus; } });
14
+ var buildBlock_js_1 = require("./buildBlock.js");
15
+ Object.defineProperty(exports, "buildBlock", { enumerable: true, get: function () { return buildBlock_js_1.buildBlock; } });
16
+ var isThenable_js_1 = require("./isThenable.js");
17
+ Object.defineProperty(exports, "isThenable", { enumerable: true, get: function () { return isThenable_js_1.isThenable; } });
18
+ var format_js_1 = require("./format.js");
19
+ Object.defineProperty(exports, "formatDuration", { enumerable: true, get: function () { return format_js_1.formatDuration; } });
20
+ Object.defineProperty(exports, "formatBytes", { enumerable: true, get: function () { return format_js_1.formatBytes; } });
@@ -0,0 +1,2 @@
1
+ /** Whether `value` is thenable (a promise we can await + time). */
2
+ export declare function isThenable(value: unknown): value is PromiseLike<unknown>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /*
3
+ * isThenable.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isThenable = isThenable;
10
+ /** Whether `value` is thenable (a promise we can await + time). */
11
+ function isThenable(value) {
12
+ return (typeof value === "object" &&
13
+ value !== null &&
14
+ typeof value.then === "function");
15
+ }
@@ -0,0 +1,21 @@
1
+ export type ResponseLike = {
2
+ status: number;
3
+ statusText?: unknown;
4
+ headers?: {
5
+ get?: (name: string) => string | null;
6
+ };
7
+ clone: () => ResponseLike;
8
+ text: () => Promise<string>;
9
+ };
10
+ /** Whether the resolved value is a fetch `Response` we can read. */
11
+ export declare function isResponse(value: unknown): value is ResponseLike;
12
+ export declare function formatStatus(res: ResponseLike, useColor: boolean): string;
13
+ /**
14
+ * Reads a (cloned) response body and returns both the parsed value and the
15
+ * actual byte size. Size is calculated from the body text — not `Content-Length`,
16
+ * which is absent on compressed responses — so size is always shown.
17
+ */
18
+ export declare function readBody(res: ResponseLike): Promise<{
19
+ data: unknown;
20
+ size: string;
21
+ }>;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /*
3
+ * response.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isResponse = isResponse;
10
+ exports.formatStatus = formatStatus;
11
+ exports.readBody = readBody;
12
+ const format_js_1 = require("./format.js");
13
+ const color_js_1 = require("../../../../domain/colors/color.js");
14
+ /** Whether the resolved value is a fetch `Response` we can read. */
15
+ function isResponse(value) {
16
+ const v = value;
17
+ return (typeof v?.status === "number" &&
18
+ typeof v.clone === "function" &&
19
+ typeof v.text === "function");
20
+ }
21
+ /**
22
+ * Status badge color:
23
+ * 2xx → green · 3xx → cyan · 4xx → yellow · 5xx → red
24
+ */
25
+ function statusColor(status) {
26
+ if (status >= 500)
27
+ return "red";
28
+ if (status >= 400)
29
+ return "yellow";
30
+ if (status >= 300)
31
+ return "cyan";
32
+ return "green";
33
+ }
34
+ function formatStatus(res, useColor) {
35
+ const text = typeof res.statusText === "string" && res.statusText
36
+ ? `${res.status} ${res.statusText}`
37
+ : `${res.status}`;
38
+ return useColor ? (0, color_js_1.colorize)(text, statusColor(res.status)) : text;
39
+ }
40
+ /**
41
+ * Reads a (cloned) response body and returns both the parsed value and the
42
+ * actual byte size. Size is calculated from the body text — not `Content-Length`,
43
+ * which is absent on compressed responses — so size is always shown.
44
+ */
45
+ async function readBody(res) {
46
+ try {
47
+ const text = await res.text();
48
+ const bytes = new TextEncoder().encode(text).length;
49
+ const size = (0, format_js_1.formatBytes)(bytes);
50
+ if (text === "")
51
+ return { data: undefined, size };
52
+ try {
53
+ return { data: JSON.parse(text), size };
54
+ }
55
+ catch {
56
+ return { data: text, size };
57
+ }
58
+ }
59
+ catch {
60
+ return { data: undefined, size: "unknown" };
61
+ }
62
+ }
@@ -0,0 +1,2 @@
1
+ export { tapAsync } from "./tapAsync.js";
2
+ export { isThenable } from "./helpers/index.js";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isThenable = exports.tapAsync = void 0;
10
+ var tapAsync_js_1 = require("./tapAsync.js");
11
+ Object.defineProperty(exports, "tapAsync", { enumerable: true, get: function () { return tapAsync_js_1.tapAsync; } });
12
+ var index_js_1 = require("./helpers/index.js");
13
+ Object.defineProperty(exports, "isThenable", { enumerable: true, get: function () { return index_js_1.isThenable; } });
@@ -1,6 +1,4 @@
1
- import { type Caller } from "../caller/getCaller.js";
2
- /** Whether `value` is thenable (a promise we can await + time). */
3
- export declare function isThenable(value: unknown): value is PromiseLike<unknown>;
1
+ import { type Caller } from "../../../domain/caller/getCaller.js";
4
2
  /**
5
3
  * The async tap. Fire-and-forget: returns `promise` immediately (unchanged),
6
4
  * and logs a rich block once it resolves. For a `Response`, reads the body from
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /*
3
+ * tapAsync.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.tapAsync = tapAsync;
10
+ const node_perf_hooks_1 = require("node:perf_hooks");
11
+ const index_js_1 = require("./helpers/index.js");
12
+ const isTTY_js_1 = require("../../../domain/terminal/isTTY.js");
13
+ const index_js_2 = require("../../../domain/write/index.js");
14
+ const index_js_3 = require("../../../config/index.js");
15
+ /**
16
+ * The async tap. Fire-and-forget: returns `promise` immediately (unchanged),
17
+ * and logs a rich block once it resolves. For a `Response`, reads the body from
18
+ * a clone so the caller's original stays consumable. A rejection logs an error
19
+ * to stderr. `caller` MUST be resolved by `tap` (the user-facing function) so
20
+ * the logged location points at the user's file.
21
+ */
22
+ function tapAsync(promise, label, caller) {
23
+ if (!(0, index_js_3.isLogAllowed)())
24
+ return;
25
+ const useColor = (0, isTTY_js_1.isTTY)("stdout");
26
+ const start = node_perf_hooks_1.performance.now();
27
+ void promise.then((resolved) => {
28
+ const ms = Math.round(node_perf_hooks_1.performance.now() - start);
29
+ if ((0, index_js_1.isResponse)(resolved)) {
30
+ let clone = null;
31
+ try {
32
+ clone = resolved.clone();
33
+ }
34
+ catch {
35
+ clone = null;
36
+ }
37
+ if (clone === null) {
38
+ (0, index_js_2.writeLog)({
39
+ channel: "log",
40
+ tag: "[TAP]",
41
+ args: (0, index_js_1.buildBlock)(label, ms, resolved, { data: undefined, size: "unknown" }, useColor),
42
+ caller,
43
+ });
44
+ return;
45
+ }
46
+ const cl = resolved.headers?.get?.("content-length");
47
+ const tooLarge = cl != null && cl !== "" && Number(cl) > 512 * 1024;
48
+ if (tooLarge) {
49
+ (0, index_js_2.writeLog)({
50
+ channel: "log",
51
+ tag: "[TAP]",
52
+ args: (0, index_js_1.buildBlock)(label, ms, resolved, {
53
+ data: "(body too large to display)",
54
+ size: (0, index_js_1.formatBytes)(Number(cl)),
55
+ }, useColor),
56
+ caller,
57
+ });
58
+ return;
59
+ }
60
+ void (0, index_js_1.readBody)(clone).then((body) => {
61
+ (0, index_js_2.writeLog)({
62
+ channel: "log",
63
+ tag: "[TAP]",
64
+ args: (0, index_js_1.buildBlock)(label, ms, resolved, body, useColor),
65
+ caller,
66
+ });
67
+ });
68
+ return;
69
+ }
70
+ // Non-Response promise — plain value with elapsed time.
71
+ const elapsed = (0, index_js_1.formatDuration)(ms, useColor);
72
+ (0, index_js_2.writeLog)({
73
+ channel: "log",
74
+ tag: "[TAP]",
75
+ args: label === undefined
76
+ ? [elapsed, resolved]
77
+ : [`${label} ${elapsed}`, resolved],
78
+ caller,
79
+ });
80
+ }, (err) => {
81
+ const ms = Math.round(node_perf_hooks_1.performance.now() - start);
82
+ const elapsed = (0, index_js_1.formatDuration)(ms, useColor);
83
+ (0, index_js_2.writeLog)({
84
+ channel: "error",
85
+ tag: "[ERROR]",
86
+ args: [
87
+ label === undefined
88
+ ? `rejected after ${elapsed}`
89
+ : `${label} rejected after ${elapsed}`,
90
+ err,
91
+ ],
92
+ caller,
93
+ });
94
+ });
95
+ }
@@ -0,0 +1 @@
1
+ export default function logWarn(...args: unknown[]): void;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = logWarn;
13
+ const index_js_1 = require("../../config/index.js");
14
+ const getCaller_js_1 = __importDefault(require("../../domain/caller/getCaller.js"));
15
+ const writeLog_js_1 = require("../../domain/write/writeLog.js");
16
+ function logWarn(...args) {
17
+ if (!(0, index_js_1.isLogAllowed)())
18
+ return;
19
+ const caller = (0, getCaller_js_1.default)();
20
+ (0, writeLog_js_1.writeLog)({ channel: "warn", tag: "[WARN]", args, caller });
21
+ }
@@ -1,32 +1,77 @@
1
- /** The logger: a callable for info logs, plus `.error`, `.warn`, and `.tap`. */
2
- export interface LogFN {
1
+ import { type Tap } from "./features/logger-tap/index.js";
2
+ import { type Group } from "./features/logger-group/index.js";
3
+ /** Type of the logger — use this to annotate variables or parameters that accept it. */
4
+ export interface Logger {
5
+ /** Log at info level — `stdout`, cyan `[INFO]` tag. */
3
6
  (...args: unknown[]): void;
7
+ /** Log at error level — `stderr`, red `[ERROR]` tag. */
4
8
  error(...args: unknown[]): void;
9
+ /** Log at warn level — `stderr`, yellow `[WARN]` tag. */
5
10
  warn(...args: unknown[]): void;
6
11
  /**
7
- * Logs `value` (optionally tagged with `label`) and returns it **unchanged**,
8
- * so it drops into any expression: `const u = logger.tap(getUser(), "user")`.
9
- * Pass a **promise** (e.g. a `fetch`) and you get the same promise back while
10
- * its elapsed time and the HTTP status if it's a `Response` — is logged in
11
- * the background. Silent in production; the value always flows through.
12
+ * Logs `value` with an optional `label` and gives it straight back unchanged
13
+ * so you can drop it into any expression without adding an extra line.
14
+ *
15
+ * **Sync value**logged immediately, returned as-is:
16
+ * ```ts
17
+ * const port = logger.tap(3000, "port") // logs it, port is still 3000
18
+ * const user = logger.tap(getUser(), "user") // logs the user object, returns it
19
+ * ```
20
+ *
21
+ * **Promise** — the same promise comes back; timing and HTTP status are logged
22
+ * in the background once it settles, without blocking your code:
23
+ * ```ts
24
+ * const res = await logger.tap(fetch(url), "GET /users") // logs status + ms
25
+ * const data = await logger.tap(loadConfig(), "config") // logs value + ms
26
+ * ```
27
+ *
28
+ * @param value Any value or promise — always returned as-is.
29
+ * @param label Optional label shown next to the value in the log line.
12
30
  */
13
- tap<T>(value: T, label?: string): T;
31
+ tap: Tap;
14
32
  /**
15
- * How many lines of a multi-line message to show before collapsing the rest
16
- * into a `… N more lines` summary. `0` (the default) shows everything.
33
+ * Log multiple related items as one block under a shared name and single
34
+ * timestamp. Each item in `logs` renders on its own `├──` branch — any value
35
+ * is accepted (string, object, function, Promise, …).
36
+ *
37
+ * `type` sets the channel and tag color: `"info"` (default), `"warn"`, `"error"`.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * logger.group({ name: "Server setup", logs: [`port: ${port}`, `env: ${env}`] })
42
+ * logger.group({ name: "Validation failed", type: "error", logs: ["email invalid"] })
43
+ * ```
44
+ */
45
+ group: Group;
46
+ /**
47
+ * How many lines to show before the rest collapses into a
48
+ * `… N more lines` summary. `0` (default) shows everything.
49
+ *
50
+ * @example
51
+ * logger.maxLines = 5
17
52
  */
18
53
  maxLines: number;
19
54
  }
20
55
  /**
21
- * Logs to the console, but only outside production. Each line is prefixed with
22
- * a level tag, a short local timestamp, and a clickable link to the file it was
23
- * called from; all arguments are then printed as-is.
24
- * @example
25
- * logger("Auth", "user logged in")
26
- * // [INFO] 05-30 04:00:00 PM (server.ts:42) Auth user logged in
56
+ * A logger built for development colored tags, a local timestamp, and a
57
+ * clickable `(file:line)` link on every line so you always know where a
58
+ * message came from. Works like `console.log`: pass anything and it prints.
59
+ *
60
+ * Logs only when `NODE_ENV !== "production"`.
61
+ *
27
62
  * @example
28
- * logger.maxLines = 5 // long messages collapse to 5 lines; 0 = show all
63
+ * ```ts
64
+ * logger("server started", { port: 3000 })
65
+ * logger.error("db failed", new Error("ECONNREFUSED"))
66
+ * logger.warn("disk above 80%")
67
+ * ```
68
+ *
69
+ * @example Tap — keep the value flowing, log it on the side
70
+ * ```ts
71
+ * const user = logger.tap(await getUser(id), "user")
72
+ * const res = await logger.tap(fetch(url), "GET /users")
73
+ * ```
29
74
  */
30
- declare const logger: LogFN;
75
+ declare const logger: Logger;
31
76
  export { logger };
32
77
  export default logger;