@meadown/logger 1.3.1 → 1.5.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Dewan Mobashirul
3
+ Copyright (c) 2026 meadown
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -32,13 +32,14 @@ customLog.error("Something went wrong")
32
32
  You'll see something like:
33
33
 
34
34
  ```text
35
- [INFO] 2026-05-30T10:00:00.000Z (server.ts:42)
36
- Auth user logged in
35
+ [INFO] 05-30 04:00:00 PM (server.ts:42)
36
+ └── Auth user logged in
37
37
  ```
38
38
 
39
- The first line carries the level tag — `[INFO]`, `[WARN]`, or `[ERROR]` — the
40
- timestamp, and the source location. Your message sits on the line below, indented so
41
- it's easy to scan down a busy terminal.
39
+ The first line carries the level tag — `[INFO]`, `[WARN]`, or `[ERROR]` — a short
40
+ local timestamp (month-day and 12-hour time), and the source location. Your message
41
+ hangs off a `└──` branch on the line below (colored to match the level), so it's easy
42
+ to scan down a busy terminal.
42
43
 
43
44
  ### One thing if you re-export it
44
45
 
@@ -58,8 +59,8 @@ export const customLog = (...args) => log(...args)
58
59
  ## Color-coded levels
59
60
 
60
61
  The level tag is colored so you can spot what matters at a glance — `[INFO]` in
61
- cyan, `[WARN]` in yellow, `[ERROR]` in red. The timestamp and location stay plain so
62
- the color draws your eye straight to the level.
62
+ cyan, `[WARN]` in yellow, `[ERROR]` in red. The `(file:line)` location is dimmed to
63
+ light gray so it stays out of the way, and the timestamp is left plain.
63
64
 
64
65
  Colors appear automatically when you're in a terminal. When output is piped to a
65
66
  file or another program, the tag prints as plain `[INFO]` text — no stray color
@@ -77,6 +78,22 @@ terminal, and when it's piped to a file or another program they quietly drop to
77
78
  plain `(server.ts:42)` text — so your log files never get cluttered with escape
78
79
  codes.
79
80
 
81
+ ## Trimming long messages
82
+
83
+ By default you see everything you log, however long. But if a big object or a
84
+ chatty multi-line message is drowning out your terminal, you can cap how many
85
+ lines each message shows:
86
+
87
+ ```ts
88
+ import customLog from "@meadown/logger"
89
+
90
+ customLog.maxLines = 5 // show the first 5 lines, then "... N more lines"
91
+ customLog.maxLines = 0 // back to the default — show everything
92
+ ```
93
+
94
+ It only trims the _message_, never the tag, timestamp, or location, and the setting
95
+ applies to `customLog`, `.error`, and `.warn` alike.
96
+
80
97
  ## What about production?
81
98
 
82
99
  Here's the nice part: you don't have to do anything. Logs show up while you're
@@ -93,4 +110,4 @@ quietly step aside.
93
110
 
94
111
  ## License
95
112
 
96
- MIT © Dewan Mobashirul
113
+ MIT © meadown
@@ -3,15 +3,12 @@ export interface LogFN {
3
3
  (...args: unknown[]): void;
4
4
  error(...args: unknown[]): void;
5
5
  warn(...args: unknown[]): void;
6
+ /**
7
+ * How many lines of a multi-line message to show before collapsing the rest
8
+ * into a `… N more lines` summary. `0` (the default) shows everything.
9
+ */
10
+ maxLines: number;
6
11
  }
7
- /**
8
- * Logs to the console, but only outside production. Each line is prefixed with
9
- * a level tag, an ISO timestamp, and a clickable link to the file and line it
10
- * was called from; all arguments are then printed as-is.
11
- * @example
12
- * customLog("Auth", "user logged in")
13
- * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
14
- */
15
12
  declare const customLog: LogFN;
16
13
  export { customLog };
17
14
  export default customLog;
package/dist/cjs/index.js CHANGED
@@ -10,15 +10,26 @@ exports.customLog = void 0;
10
10
  const index_js_1 = require("./utils/index.js");
11
11
  /**
12
12
  * Logs to the console, but only outside production. Each line is prefixed with
13
- * a level tag, an ISO timestamp, and a clickable link to the file and line it
14
- * was called from; all arguments are then printed as-is.
13
+ * a level tag, a short local timestamp, and a clickable link to the file it was
14
+ * called from; all arguments are then printed as-is.
15
15
  * @example
16
16
  * customLog("Auth", "user logged in")
17
- * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
17
+ * // [INFO] 05-30 04:00:00 PM (server.ts:42) Auth user logged in
18
+ * @example
19
+ * customLog.maxLines = 5 // long messages collapse to 5 lines; 0 = show all
18
20
  */
19
- const customLog = Object.assign((0, index_js_1.createLog)("log", "[INFO]"), {
21
+ const logger = Object.assign((0, index_js_1.createLog)("log", "[INFO]"), {
20
22
  error: (0, index_js_1.createLog)("error", "[ERROR]"),
21
23
  warn: (0, index_js_1.createLog)("warn", "[WARN]"),
22
24
  });
25
+ // `maxLines` is a live getter/setter backed by the shared collapse setting, so
26
+ // setting it once affects info, error, and warn alike.
27
+ Object.defineProperty(logger, "maxLines", {
28
+ get: index_js_1.getVisibleLines,
29
+ set: index_js_1.setVisibleLines,
30
+ enumerable: true,
31
+ configurable: true,
32
+ });
33
+ const customLog = logger;
23
34
  exports.customLog = customLog;
24
35
  exports.default = customLog;
@@ -3,7 +3,9 @@ declare const CODES: {
3
3
  readonly red: 31;
4
4
  readonly yellow: 33;
5
5
  readonly cyan: 36;
6
- readonly dim: 2;
6
+ readonly gray: 90;
7
+ readonly teal: "38;5;30";
8
+ readonly dimTeal: "38;5;23";
7
9
  };
8
10
  /** The named colors/styles {@link colorize} understands. */
9
11
  export type Color = keyof typeof CODES;
@@ -13,7 +13,9 @@ const CODES = {
13
13
  red: 31,
14
14
  yellow: 33,
15
15
  cyan: 36,
16
- dim: 2,
16
+ gray: 90, // bright black — renders as light gray
17
+ teal: "38;5;30", // 256-color teal (#008787)
18
+ dimTeal: "38;5;23", // 256-color darker teal (#005f5f)
17
19
  };
18
20
  const RESET = "\x1b[0m";
19
21
  /**
@@ -1,5 +1,9 @@
1
1
  /** The console channels the logger writes to. */
2
2
  export type LogChannel = "log" | "error" | "warn";
3
+ /** How many lines a long message shows before collapsing (0 = all). */
4
+ export declare function getVisibleLines(): number;
5
+ /** Set how many lines a long message shows before collapsing (0 = all). */
6
+ export declare function setVisibleLines(value: number): void;
3
7
  /**
4
8
  * Builds a log function bound to a console channel and tag. The returned closure
5
9
  * is what the caller invokes directly, so {@link getCaller} still resolves the
@@ -9,7 +9,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getVisibleLines = getVisibleLines;
13
+ exports.setVisibleLines = setVisibleLines;
12
14
  exports.default = createLog;
15
+ const node_util_1 = require("node:util");
13
16
  const getCaller_js_1 = __importDefault(require("./getCaller.js"));
14
17
  const getTimeStamp_js_1 = __importDefault(require("./getTimeStamp.js"));
15
18
  const link_js_1 = require("./link.js");
@@ -21,11 +24,52 @@ const TAG_COLOR = {
21
24
  warn: "yellow",
22
25
  error: "red",
23
26
  };
27
+ /** Visible width of the `└── ` branch; message lines left-align under it. */
28
+ const MESSAGE_INDENT = " ";
29
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
30
+ let visibleLines = 0;
31
+ /** How many lines a long message shows before collapsing (0 = all). */
32
+ function getVisibleLines() {
33
+ return visibleLines;
34
+ }
35
+ /** Set how many lines a long message shows before collapsing (0 = all). */
36
+ function setVisibleLines(value) {
37
+ visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
38
+ }
39
+ /**
40
+ * Collapses a long multi-line message to {@link visibleLines} lines, replacing
41
+ * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
42
+ * (the default) nothing is collapsed — the full message is shown.
43
+ */
44
+ function collapse(text, useColor) {
45
+ if (visibleLines < 1)
46
+ return text;
47
+ const lines = text.split("\n");
48
+ if (lines.length <= visibleLines)
49
+ return text;
50
+ const hidden = lines.length - visibleLines;
51
+ const summary = `${MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
52
+ const visible = lines.slice(0, visibleLines);
53
+ visible.push(useColor ? (0, color_js_1.colorize)(summary, "gray") : summary);
54
+ return visible.join("\n");
55
+ }
56
+ /**
57
+ * Renders the args into a single message string exactly as console would —
58
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
59
+ * on a terminal — then hang-indents every continuation line so multi-line
60
+ * output (multi-line strings, pretty-printed objects, error stacks) all stays
61
+ * left-aligned under the `└── ` branch, and collapses very long output.
62
+ */
63
+ function renderMessage(args, useColor) {
64
+ const text = (0, node_util_1.formatWithOptions)({ colors: useColor }, ...args);
65
+ return collapse(text.replace(/\n/g, `\n${MESSAGE_INDENT}`), useColor);
66
+ }
24
67
  /**
25
68
  * Renders a caller as a `(file:line)` location. When the terminal supports
26
- * OSC-8 hyperlinks, the location is a clickable link to the exact source line;
27
- * otherwise it's plain text. Pure (no stack access), so it can be called from a
28
- * helper without disturbing {@link getCaller}'s frame depth.
69
+ * OSC-8 hyperlinks, the location is a clickable link to the source file while
70
+ * the line stays visible in the label; otherwise it's plain text. Pure (no
71
+ * stack access), so it can be called from a helper without disturbing
72
+ * {@link getCaller}'s frame depth.
29
73
  */
30
74
  function formatLocation(caller, streamName) {
31
75
  if (caller.file !== null &&
@@ -48,12 +92,25 @@ function createLog(channel, tag) {
48
92
  return;
49
93
  const caller = (0, getCaller_js_1.default)();
50
94
  const location = formatLocation(caller, streamName);
51
- // Color only the level tag, and only on a real terminal.
52
- const tagOut = (0, color_js_1.supportsColor)(streamName)
53
- ? (0, color_js_1.colorize)(tag, TAG_COLOR[channel])
54
- : tag;
55
- // `\n ` + console's own separator space => the message is indented 2 spaces
56
- // on its own line below the metadata.
57
- console[channel](tagOut, (0, getTimeStamp_js_1.default)(), `(${location})`, `\n `, ...args, `\n`);
95
+ // Colors (terminal only): tag by level, timestamp teal, location dim teal,
96
+ // branch and separator gray.
97
+ const useColor = (0, color_js_1.supportsColor)(streamName);
98
+ const tagOut = useColor ? (0, color_js_1.colorize)(tag, TAG_COLOR[channel]) : tag;
99
+ const timeStamp = useColor
100
+ ? (0, color_js_1.colorize)((0, getTimeStamp_js_1.default)(), "teal")
101
+ : (0, getTimeStamp_js_1.default)();
102
+ const locOut = useColor
103
+ ? (0, color_js_1.colorize)(`(${location})`, "dimTeal")
104
+ : `(${location})`;
105
+ const connector = useColor ? (0, color_js_1.colorize)("├──", "gray") : "└──";
106
+ const connectorBottom = useColor ? (0, color_js_1.colorize)("└──", "gray") : "└──";
107
+ const separator = useColor ? (0, color_js_1.colorize)("-", "gray") : "-";
108
+ // Layout: the tag, the message hanging off a `├──` branch, then the
109
+ // timestamp and location on a `└──` branch below.
110
+ const message = renderMessage(args, useColor);
111
+ const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
112
+ // Leading `\n` puts a blank line above each entry — in the same call and on
113
+ // the right stream (a separate `console.log` would always hit stdout).
114
+ console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
58
115
  };
59
116
  }
@@ -1,2 +1,6 @@
1
- /** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
2
- export default function getTimeStamp(): string;
1
+ /**
2
+ * Returns a short local timestamp: month-day plus 12-hour time, e.g.
3
+ * `05-30 04:00:00 PM`. The year and timezone are dropped to keep log lines
4
+ * compact; date and time are both local so they stay consistent.
5
+ */
6
+ export default function getTimeStamp(date?: Date): string;
@@ -7,7 +7,22 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.default = getTimeStamp;
10
- /** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
11
- function getTimeStamp() {
12
- return new Date().toISOString();
10
+ // Time-only 12-hour formatter (date is built separately, timezone is dropped).
11
+ const TIME_FORMATTER = new Intl.DateTimeFormat("en-US", {
12
+ hour: "2-digit",
13
+ minute: "2-digit",
14
+ second: "2-digit",
15
+ hour12: true,
16
+ });
17
+ function pad(value) {
18
+ return String(value).padStart(2, "0");
19
+ }
20
+ /**
21
+ * Returns a short local timestamp: month-day plus 12-hour time, e.g.
22
+ * `05-30 04:00:00 PM`. The year and timezone are dropped to keep log lines
23
+ * compact; date and time are both local so they stay consistent.
24
+ */
25
+ function getTimeStamp(date = new Date()) {
26
+ const datePart = `${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
27
+ return `${datePart} ${TIME_FORMATTER.format(date)}`;
13
28
  }
@@ -1,4 +1,4 @@
1
- export { default as createLog, type LogChannel } from "./createLog.js";
1
+ export { default as createLog, getVisibleLines, setVisibleLines, type LogChannel, } from "./createLog.js";
2
2
  export { default as getCaller, type Caller } from "./getCaller.js";
3
3
  export { default as getTimeStamp } from "./getTimeStamp.js";
4
4
  export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
@@ -9,9 +9,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.supportsColor = exports.colorize = exports.supportsHyperlinks = exports.hyperlink = exports.fileUrl = exports.getTimeStamp = exports.getCaller = exports.createLog = void 0;
12
+ exports.supportsColor = exports.colorize = exports.supportsHyperlinks = exports.hyperlink = exports.fileUrl = exports.getTimeStamp = exports.getCaller = exports.setVisibleLines = exports.getVisibleLines = exports.createLog = void 0;
13
13
  var createLog_js_1 = require("./createLog.js");
14
14
  Object.defineProperty(exports, "createLog", { enumerable: true, get: function () { return __importDefault(createLog_js_1).default; } });
15
+ Object.defineProperty(exports, "getVisibleLines", { enumerable: true, get: function () { return createLog_js_1.getVisibleLines; } });
16
+ Object.defineProperty(exports, "setVisibleLines", { enumerable: true, get: function () { return createLog_js_1.setVisibleLines; } });
15
17
  var getCaller_js_1 = require("./getCaller.js");
16
18
  Object.defineProperty(exports, "getCaller", { enumerable: true, get: function () { return __importDefault(getCaller_js_1).default; } });
17
19
  var getTimeStamp_js_1 = require("./getTimeStamp.js");
package/dist/index.d.ts CHANGED
@@ -3,15 +3,12 @@ export interface LogFN {
3
3
  (...args: unknown[]): void;
4
4
  error(...args: unknown[]): void;
5
5
  warn(...args: unknown[]): void;
6
+ /**
7
+ * How many lines of a multi-line message to show before collapsing the rest
8
+ * into a `… N more lines` summary. `0` (the default) shows everything.
9
+ */
10
+ maxLines: number;
6
11
  }
7
- /**
8
- * Logs to the console, but only outside production. Each line is prefixed with
9
- * a level tag, an ISO timestamp, and a clickable link to the file and line it
10
- * was called from; all arguments are then printed as-is.
11
- * @example
12
- * customLog("Auth", "user logged in")
13
- * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
14
- */
15
12
  declare const customLog: LogFN;
16
13
  export { customLog };
17
14
  export default customLog;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,gFAAgF;AAChF,MAAM,WAAW,KAAK;IACpB,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAC/B;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,SAAS,EAAE,KAGf,CAAA;AAEF,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,gFAAgF;AAChF,MAAM,WAAW,KAAK;IACpB,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC9B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;CACjB;AA0BD,QAAA,MAAM,SAAS,EAAa,KAAK,CAAA;AAEjC,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -4,19 +4,30 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
- import { createLog } from "./utils/index.js";
7
+ import { createLog, getVisibleLines, setVisibleLines } from "./utils/index.js";
8
8
  /**
9
9
  * Logs to the console, but only outside production. Each line is prefixed with
10
- * a level tag, an ISO timestamp, and a clickable link to the file and line it
11
- * was called from; all arguments are then printed as-is.
10
+ * a level tag, a short local timestamp, and a clickable link to the file it was
11
+ * called from; all arguments are then printed as-is.
12
12
  * @example
13
13
  * customLog("Auth", "user logged in")
14
- * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
14
+ * // [INFO] 05-30 04:00:00 PM (server.ts:42) Auth user logged in
15
+ * @example
16
+ * customLog.maxLines = 5 // long messages collapse to 5 lines; 0 = show all
15
17
  */
16
- const customLog = Object.assign(createLog("log", "[INFO]"), {
18
+ const logger = Object.assign(createLog("log", "[INFO]"), {
17
19
  error: createLog("error", "[ERROR]"),
18
20
  warn: createLog("warn", "[WARN]"),
19
21
  });
22
+ // `maxLines` is a live getter/setter backed by the shared collapse setting, so
23
+ // setting it once affects info, error, and warn alike.
24
+ Object.defineProperty(logger, "maxLines", {
25
+ get: getVisibleLines,
26
+ set: setVisibleLines,
27
+ enumerable: true,
28
+ configurable: true,
29
+ });
30
+ const customLog = logger;
20
31
  export { customLog };
21
32
  export default customLog;
22
33
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAS5C;;;;;;;GAOG;AACH,MAAM,SAAS,GAAU,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACjE,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;IACpC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC;CAClC,CAAC,CAAA;AAEF,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAc9E;;;;;;;;;GASG;AACH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACvD,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;IACpC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC;CAClC,CAAC,CAAA;AAEF,+EAA+E;AAC/E,uDAAuD;AACvD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE;IACxC,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,eAAe;IACpB,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,IAAI;CACnB,CAAC,CAAA;AAEF,MAAM,SAAS,GAAG,MAAe,CAAA;AAEjC,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
@@ -3,7 +3,9 @@ declare const CODES: {
3
3
  readonly red: 31;
4
4
  readonly yellow: 33;
5
5
  readonly cyan: 36;
6
- readonly dim: 2;
6
+ readonly gray: 90;
7
+ readonly teal: "38;5;30";
8
+ readonly dimTeal: "38;5;23";
7
9
  };
8
10
  /** The named colors/styles {@link colorize} understands. */
9
11
  export type Color = keyof typeof CODES;
@@ -1 +1 @@
1
- {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAOA,4DAA4D;AAC5D,QAAA,MAAM,KAAK;;;;;CAKD,CAAA;AAEV,4DAA4D;AAC5D,MAAM,MAAM,KAAK,GAAG,MAAM,OAAO,KAAK,CAAA;AAItC;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAItE"}
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAOA,4DAA4D;AAC5D,QAAA,MAAM,KAAK;;;;;;;CAOD,CAAA;AAEV,4DAA4D;AAC5D,MAAM,MAAM,KAAK,GAAG,MAAM,OAAO,KAAK,CAAA;AAItC;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAItE"}
@@ -9,7 +9,9 @@ const CODES = {
9
9
  red: 31,
10
10
  yellow: 33,
11
11
  cyan: 36,
12
- dim: 2,
12
+ gray: 90, // bright black — renders as light gray
13
+ teal: "38;5;30", // 256-color teal (#008787)
14
+ dimTeal: "38;5;23", // 256-color darker teal (#005f5f)
13
15
  };
14
16
  const RESET = "\x1b[0m";
15
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4DAA4D;AAC5D,MAAM,KAAK,GAAG;IACZ,GAAG,EAAE,EAAE;IACP,MAAM,EAAE,EAAE;IACV,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,CAAC;CACE,CAAA;AAKV,MAAM,KAAK,GAAG,SAAS,CAAA;AAEvB;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAY;IACjD,OAAO,QAAQ,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAA;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,UAA+B;IAC3D,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAChD,MAAM,MAAM,GAAG,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IACxE,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAC/B,CAAC"}
1
+ {"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4DAA4D;AAC5D,MAAM,KAAK,GAAG;IACZ,GAAG,EAAE,EAAE;IACP,MAAM,EAAE,EAAE;IACV,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE,EAAE,uCAAuC;IACjD,IAAI,EAAE,SAAS,EAAE,2BAA2B;IAC5C,OAAO,EAAE,SAAS,EAAE,kCAAkC;CAC9C,CAAA;AAKV,MAAM,KAAK,GAAG,SAAS,CAAA;AAEvB;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAY;IACjD,OAAO,QAAQ,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAA;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,UAA+B;IAC3D,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAChD,MAAM,MAAM,GAAG,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IACxE,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAC/B,CAAC"}
@@ -1,5 +1,9 @@
1
1
  /** The console channels the logger writes to. */
2
2
  export type LogChannel = "log" | "error" | "warn";
3
+ /** How many lines a long message shows before collapsing (0 = all). */
4
+ export declare function getVisibleLines(): number;
5
+ /** Set how many lines a long message shows before collapsing (0 = all). */
6
+ export declare function setVisibleLines(value: number): void;
3
7
  /**
4
8
  * Builds a log function bound to a console channel and tag. The returned closure
5
9
  * is what the caller invokes directly, so {@link getCaller} still resolves the
@@ -1 +1 @@
1
- {"version":3,"file":"createLog.d.ts","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAaA,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAA;AA4BjD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,GACV,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAgB9B"}
1
+ {"version":3,"file":"createLog.d.ts","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAeA,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAA;AAejD,uEAAuE;AACvE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEnD;AAkDD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,GACV,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CA8B9B"}
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
+ import { formatWithOptions } from "node:util";
7
8
  import getCaller from "./getCaller.js";
8
9
  import getTimeStamp from "./getTimeStamp.js";
9
10
  import { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
@@ -15,11 +16,52 @@ const TAG_COLOR = {
15
16
  warn: "yellow",
16
17
  error: "red",
17
18
  };
19
+ /** Visible width of the `└── ` branch; message lines left-align under it. */
20
+ const MESSAGE_INDENT = " ";
21
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
22
+ let visibleLines = 0;
23
+ /** How many lines a long message shows before collapsing (0 = all). */
24
+ export function getVisibleLines() {
25
+ return visibleLines;
26
+ }
27
+ /** Set how many lines a long message shows before collapsing (0 = all). */
28
+ export function setVisibleLines(value) {
29
+ visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
30
+ }
31
+ /**
32
+ * Collapses a long multi-line message to {@link visibleLines} lines, replacing
33
+ * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
34
+ * (the default) nothing is collapsed — the full message is shown.
35
+ */
36
+ function collapse(text, useColor) {
37
+ if (visibleLines < 1)
38
+ return text;
39
+ const lines = text.split("\n");
40
+ if (lines.length <= visibleLines)
41
+ return text;
42
+ const hidden = lines.length - visibleLines;
43
+ const summary = `${MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
44
+ const visible = lines.slice(0, visibleLines);
45
+ visible.push(useColor ? colorize(summary, "gray") : summary);
46
+ return visible.join("\n");
47
+ }
48
+ /**
49
+ * Renders the args into a single message string exactly as console would —
50
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
51
+ * on a terminal — then hang-indents every continuation line so multi-line
52
+ * output (multi-line strings, pretty-printed objects, error stacks) all stays
53
+ * left-aligned under the `└── ` branch, and collapses very long output.
54
+ */
55
+ function renderMessage(args, useColor) {
56
+ const text = formatWithOptions({ colors: useColor }, ...args);
57
+ return collapse(text.replace(/\n/g, `\n${MESSAGE_INDENT}`), useColor);
58
+ }
18
59
  /**
19
60
  * Renders a caller as a `(file:line)` location. When the terminal supports
20
- * OSC-8 hyperlinks, the location is a clickable link to the exact source line;
21
- * otherwise it's plain text. Pure (no stack access), so it can be called from a
22
- * helper without disturbing {@link getCaller}'s frame depth.
61
+ * OSC-8 hyperlinks, the location is a clickable link to the source file while
62
+ * the line stays visible in the label; otherwise it's plain text. Pure (no
63
+ * stack access), so it can be called from a helper without disturbing
64
+ * {@link getCaller}'s frame depth.
23
65
  */
24
66
  function formatLocation(caller, streamName) {
25
67
  if (caller.file !== null &&
@@ -42,13 +84,26 @@ export default function createLog(channel, tag) {
42
84
  return;
43
85
  const caller = getCaller();
44
86
  const location = formatLocation(caller, streamName);
45
- // Color only the level tag, and only on a real terminal.
46
- const tagOut = supportsColor(streamName)
47
- ? colorize(tag, TAG_COLOR[channel])
48
- : tag;
49
- // `\n ` + console's own separator space => the message is indented 2 spaces
50
- // on its own line below the metadata.
51
- console[channel](tagOut, getTimeStamp(), `(${location})`, `\n `, ...args, `\n`);
87
+ // Colors (terminal only): tag by level, timestamp teal, location dim teal,
88
+ // branch and separator gray.
89
+ const useColor = supportsColor(streamName);
90
+ const tagOut = useColor ? colorize(tag, TAG_COLOR[channel]) : tag;
91
+ const timeStamp = useColor
92
+ ? colorize(getTimeStamp(), "teal")
93
+ : getTimeStamp();
94
+ const locOut = useColor
95
+ ? colorize(`(${location})`, "dimTeal")
96
+ : `(${location})`;
97
+ const connector = useColor ? colorize("├──", "gray") : "└──";
98
+ const connectorBottom = useColor ? colorize("└──", "gray") : "└──";
99
+ const separator = useColor ? colorize("-", "gray") : "-";
100
+ // Layout: the tag, the message hanging off a `├──` branch, then the
101
+ // timestamp and location on a `└──` branch below.
102
+ const message = renderMessage(args, useColor);
103
+ const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
104
+ // Leading `\n` puts a blank line above each entry — in the same call and on
105
+ // the right stream (a separate `console.log` would always hit stdout).
106
+ console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
52
107
  };
53
108
  }
54
109
  //# sourceMappingURL=createLog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createLog.js","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,SAA0B,MAAM,gBAAgB,CAAA;AACvD,OAAO,YAAY,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAc,MAAM,YAAY,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAK3C,+EAA+E;AAC/E,MAAM,SAAS,GAA8B;IAC3C,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,KAAK;CACb,CAAA;AAED;;;;;GAKG;AACH,SAAS,cAAc,CACrB,MAAc,EACd,UAA+B;IAE/B,IACE,MAAM,CAAC,IAAI,KAAK,IAAI;QACpB,MAAM,CAAC,IAAI,KAAK,IAAI;QACpB,kBAAkB,CAAC,UAAU,CAAC;QAE9B,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,OAAmB,EACnB,GAAW;IAEX,MAAM,UAAU,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;IAC1D,OAAO,CAAC,GAAG,IAAe,EAAQ,EAAE;QAClC,IAAI,CAAC,YAAY,EAAE;YAAE,OAAM;QAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;QAC1B,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAEnD,yDAAyD;QACzD,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC;YACtC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC,CAAC,GAAG,CAAA;QAEP,4EAA4E;QAC5E,sCAAsC;QACtC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,IAAI,CAAC,CAAA;IACjF,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"createLog.js","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,7 @@
1
- /** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
2
- export default function getTimeStamp(): string;
1
+ /**
2
+ * Returns a short local timestamp: month-day plus 12-hour time, e.g.
3
+ * `05-30 04:00:00 PM`. The year and timezone are dropped to keep log lines
4
+ * compact; date and time are both local so they stay consistent.
5
+ */
6
+ export default function getTimeStamp(date?: Date): string;
3
7
  //# sourceMappingURL=getTimeStamp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getTimeStamp.d.ts","sourceRoot":"","sources":["../../src/utils/getTimeStamp.ts"],"names":[],"mappings":"AAOA,uFAAuF;AACvF,MAAM,CAAC,OAAO,UAAU,YAAY,IAAI,MAAM,CAE7C"}
1
+ {"version":3,"file":"getTimeStamp.d.ts","sourceRoot":"","sources":["../../src/utils/getTimeStamp.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,IAAI,OAAa,GAAG,MAAM,CAG9D"}
@@ -4,8 +4,23 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
- /** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
8
- export default function getTimeStamp() {
9
- return new Date().toISOString();
7
+ // Time-only 12-hour formatter (date is built separately, timezone is dropped).
8
+ const TIME_FORMATTER = new Intl.DateTimeFormat("en-US", {
9
+ hour: "2-digit",
10
+ minute: "2-digit",
11
+ second: "2-digit",
12
+ hour12: true,
13
+ });
14
+ function pad(value) {
15
+ return String(value).padStart(2, "0");
16
+ }
17
+ /**
18
+ * Returns a short local timestamp: month-day plus 12-hour time, e.g.
19
+ * `05-30 04:00:00 PM`. The year and timezone are dropped to keep log lines
20
+ * compact; date and time are both local so they stay consistent.
21
+ */
22
+ export default function getTimeStamp(date = new Date()) {
23
+ const datePart = `${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
24
+ return `${datePart} ${TIME_FORMATTER.format(date)}`;
10
25
  }
11
26
  //# sourceMappingURL=getTimeStamp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getTimeStamp.js","sourceRoot":"","sources":["../../src/utils/getTimeStamp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uFAAuF;AACvF,MAAM,CAAC,OAAO,UAAU,YAAY;IAClC,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;AACjC,CAAC"}
1
+ {"version":3,"file":"getTimeStamp.js","sourceRoot":"","sources":["../../src/utils/getTimeStamp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+EAA+E;AAC/E,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;IACtD,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,IAAI;CACb,CAAC,CAAA;AAEF,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,IAAI,GAAG,IAAI,IAAI,EAAE;IACpD,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAA;IACrE,OAAO,GAAG,QAAQ,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAA;AACrD,CAAC"}
@@ -1,4 +1,4 @@
1
- export { default as createLog, type LogChannel } from "./createLog.js";
1
+ export { default as createLog, getVisibleLines, setVisibleLines, type LogChannel, } from "./createLog.js";
2
2
  export { default as getCaller, type Caller } from "./getCaller.js";
3
3
  export { default as getTimeStamp } from "./getTimeStamp.js";
4
4
  export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,OAAO,IAAI,SAAS,EACpB,eAAe,EACf,eAAe,EACf,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAA"}
@@ -4,7 +4,7 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
- export { default as createLog } from "./createLog.js";
7
+ export { default as createLog, getVisibleLines, setVisibleLines, } from "./createLog.js";
8
8
  export { default as getCaller } from "./getCaller.js";
9
9
  export { default as getTimeStamp } from "./getTimeStamp.js";
10
10
  export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAmB,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAe,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAc,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,OAAO,IAAI,SAAS,EACpB,eAAe,EACf,eAAe,GAEhB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,OAAO,IAAI,SAAS,EAAe,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAc,MAAM,YAAY,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meadown/logger",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "A tiny, zero-dependency logger for Node.js and TypeScript that tags each line, timestamps it, shows the source file and line, and goes quiet in production.",
5
5
  "keywords": [
6
6
  "logger",
@@ -52,6 +52,7 @@
52
52
  "test": "tsc && node --test \"test/**/*.test.mjs\"",
53
53
  "lint": "eslint src",
54
54
  "lint:fix": "eslint src --fix",
55
+ "demo": "pnpm build && node examples/demo.mjs",
55
56
  "prepublishOnly": "pnpm run lint && pnpm test && pnpm run build",
56
57
  "prepare": "husky",
57
58
  "release": "semantic-release"