@meadown/logger 1.0.1 → 1.2.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 (41) hide show
  1. package/README.md +24 -8
  2. package/dist/cjs/config.d.ts +6 -0
  3. package/dist/cjs/config.js +19 -0
  4. package/dist/cjs/index.d.ts +17 -0
  5. package/dist/cjs/index.js +24 -0
  6. package/dist/cjs/package.json +3 -0
  7. package/dist/cjs/utils/createLog.d.ts +10 -0
  8. package/dist/cjs/utils/createLog.js +46 -0
  9. package/dist/cjs/utils/getCaller.d.ts +16 -0
  10. package/dist/cjs/utils/getCaller.js +37 -0
  11. package/dist/cjs/utils/getTimeStamp.d.ts +2 -0
  12. package/dist/cjs/utils/getTimeStamp.js +13 -0
  13. package/dist/cjs/utils/index.d.ts +4 -0
  14. package/dist/cjs/utils/index.js +22 -0
  15. package/dist/cjs/utils/link.d.ts +17 -0
  16. package/dist/cjs/utils/link.js +63 -0
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +4 -18
  20. package/dist/index.js.map +1 -1
  21. package/dist/utils/createLog.d.ts +11 -0
  22. package/dist/utils/createLog.d.ts.map +1 -0
  23. package/dist/utils/createLog.js +41 -0
  24. package/dist/utils/createLog.js.map +1 -0
  25. package/dist/utils/getCaller.d.ts +17 -0
  26. package/dist/utils/getCaller.d.ts.map +1 -0
  27. package/dist/utils/getCaller.js +35 -0
  28. package/dist/utils/getCaller.js.map +1 -0
  29. package/dist/utils/index.d.ts +3 -1
  30. package/dist/utils/index.d.ts.map +1 -1
  31. package/dist/utils/index.js +3 -1
  32. package/dist/utils/index.js.map +1 -1
  33. package/dist/utils/link.d.ts +18 -0
  34. package/dist/utils/link.d.ts.map +1 -0
  35. package/dist/utils/link.js +59 -0
  36. package/dist/utils/link.js.map +1 -0
  37. package/package.json +13 -7
  38. package/dist/utils/getFileName.d.ts +0 -6
  39. package/dist/utils/getFileName.d.ts.map +0 -1
  40. package/dist/utils/getFileName.js +0 -17
  41. package/dist/utils/getFileName.js.map +0 -1
package/README.md CHANGED
@@ -5,8 +5,9 @@ remember _which file_ a message came from — and worse, forgetting to pull thos
5
5
  out before shipping. So I made this.
6
6
 
7
7
  It's basically `console.log` with the rough edges sanded off: every message gets a
8
- label, a timestamp, and the file and line it came from. And it stays quiet in
9
- production, so you can leave your logs where they are and not worry about them.
8
+ level tag, a timestamp, and a **clickable link** to the exact file and line it came
9
+ from. And it stays quiet in production, so you can leave your logs where they are and
10
+ not worry about them.
10
11
 
11
12
  No dependencies. No config. Import it and you're done.
12
13
 
@@ -22,7 +23,7 @@ npm install @meadown/logger
22
23
  import customLog from "@meadown/logger"
23
24
 
24
25
  customLog("Hello world")
25
- customLog("Auth", "user logged in") // first word can be a label, if you want one
26
+ customLog("Auth", "user logged in") // every argument is printed as-is, like console.log
26
27
 
27
28
  customLog.warn("This is deprecated")
28
29
  customLog.error("Something went wrong")
@@ -31,13 +32,28 @@ customLog.error("Something went wrong")
31
32
  You'll see something like:
32
33
 
33
34
  ```text
34
- [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
35
- [WARN] 2026-05-30T10:00:00.000Z (server.ts:51) This is deprecated
36
- [ERROR] 2026-05-30T10:00:00.000Z (server.ts:60) Something went wrong
35
+ [INFO] 2026-05-30T10:00:00.000Z (server.ts:42)
36
+ Auth user logged in
37
37
  ```
38
38
 
39
- That `(server.ts:42)` bit is the part I missed most with plain `console.log` —
40
- no more hunting for where a message came from.
39
+ Each line is tagged by level `[INFO]`, `[WARN]`, or `[ERROR]` — followed by the
40
+ timestamp and the source location, with your arguments on the next line.
41
+
42
+ ## Click to jump to the source
43
+
44
+ That `(server.ts:42)` at the end of every log isn't just text — in terminals that
45
+ support it, it's a **clickable link** that opens the exact line that wrote the log.
46
+ No more hunting for where a message came from.
47
+
48
+ It works out of the box in editors and terminals like VS Code, iTerm2, WezTerm,
49
+ Kitty, and Windows Terminal. Anywhere else, it quietly falls back to plain
50
+ `(server.ts:42)` text — nothing to configure, never any garbled output.
51
+
52
+ If your terminal supports links but isn't auto-detected, you can force them on:
53
+
54
+ ```bash
55
+ FORCE_HYPERLINK=1 node app.js
56
+ ```
41
57
 
42
58
  ## What about production?
43
59
 
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Logging is enabled in every environment except production, read directly
3
+ * from `process.env.NODE_ENV`. No configuration — set `NODE_ENV=production`
4
+ * in your runtime to silence logs.
5
+ */
6
+ export declare function isLogAllowed(): boolean;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /*
3
+ * config.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isLogAllowed = isLogAllowed;
10
+ /**
11
+ * Logging is enabled in every environment except production, read directly
12
+ * from `process.env.NODE_ENV`. No configuration — set `NODE_ENV=production`
13
+ * in your runtime to silence logs.
14
+ */
15
+ function isLogAllowed() {
16
+ // Guard `process` so the logger doesn't throw in non-Node runtimes (browser,
17
+ // edge) where it may be undefined; default to logging when it's absent.
18
+ return typeof process === "undefined" || process.env.NODE_ENV !== "production";
19
+ }
@@ -0,0 +1,17 @@
1
+ /** The logger: a callable for info logs, plus `.error` and `.warn` variants. */
2
+ export interface LogFN {
3
+ (...args: unknown[]): void;
4
+ error(...args: unknown[]): void;
5
+ warn(...args: unknown[]): void;
6
+ }
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
+ declare const customLog: LogFN;
16
+ export { customLog };
17
+ export default customLog;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.customLog = void 0;
10
+ const index_js_1 = require("./utils/index.js");
11
+ /**
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.
15
+ * @example
16
+ * customLog("Auth", "user logged in")
17
+ * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
18
+ */
19
+ const customLog = Object.assign((0, index_js_1.createLog)("log", "[INFO]"), {
20
+ error: (0, index_js_1.createLog)("error", "[ERROR]"),
21
+ warn: (0, index_js_1.createLog)("warn", "[WARN]"),
22
+ });
23
+ exports.customLog = customLog;
24
+ exports.default = customLog;
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,10 @@
1
+ /** The console channels the logger writes to. */
2
+ export type LogChannel = "log" | "error" | "warn";
3
+ /**
4
+ * Builds a log function bound to a console channel and tag. The returned closure
5
+ * is what the caller invokes directly, so {@link getCaller} still resolves the
6
+ * caller's own frame (no extra stack frame is inserted). `console[channel]` is
7
+ * looked up at call time, so reassigning `console.log` (e.g. in tests) is
8
+ * respected. Logs only outside production — see {@link isLogAllowed}.
9
+ */
10
+ export default function createLog(channel: LogChannel, tag: string): (...args: unknown[]) => void;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /*
3
+ * createLog.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-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 = createLog;
13
+ const getCaller_js_1 = __importDefault(require("./getCaller.js"));
14
+ const getTimeStamp_js_1 = __importDefault(require("./getTimeStamp.js"));
15
+ const link_js_1 = require("./link.js");
16
+ const config_js_1 = require("../config.js");
17
+ /**
18
+ * Renders a caller as a `(file:line)` location. When the terminal supports
19
+ * OSC-8 hyperlinks, the location is a clickable link to the exact source line;
20
+ * otherwise it's plain text. Pure (no stack access), so it can be called from a
21
+ * helper without disturbing {@link getCaller}'s frame depth.
22
+ */
23
+ function formatLocation(caller, streamName) {
24
+ if (caller.file !== null &&
25
+ caller.line !== null &&
26
+ (0, link_js_1.supportsHyperlinks)(streamName))
27
+ return (0, link_js_1.hyperlink)(caller.label, (0, link_js_1.fileUrl)(caller.file, caller.line));
28
+ return caller.label;
29
+ }
30
+ /**
31
+ * Builds a log function bound to a console channel and tag. The returned closure
32
+ * is what the caller invokes directly, so {@link getCaller} still resolves the
33
+ * caller's own frame (no extra stack frame is inserted). `console[channel]` is
34
+ * looked up at call time, so reassigning `console.log` (e.g. in tests) is
35
+ * respected. Logs only outside production — see {@link isLogAllowed}.
36
+ */
37
+ function createLog(channel, tag) {
38
+ const streamName = channel === "log" ? "stdout" : "stderr";
39
+ return (...args) => {
40
+ if (!(0, config_js_1.isLogAllowed)())
41
+ return;
42
+ const caller = (0, getCaller_js_1.default)();
43
+ const location = formatLocation(caller, streamName);
44
+ console[channel](tag, (0, getTimeStamp_js_1.default)(), `(${location})`, `\n`, ...args, `\n`);
45
+ };
46
+ }
@@ -0,0 +1,16 @@
1
+ /** A resolved call site. `file`/`line` are `null` when they can't be determined. */
2
+ export interface Caller {
3
+ /** Short display location, e.g. `server.ts:42`, or `"unknown"`. */
4
+ label: string;
5
+ /** Absolute path (or `file://` URL) of the calling file, or `null`. */
6
+ file: string | null;
7
+ /** 1-based line number, or `null`. */
8
+ line: number | null;
9
+ }
10
+ /**
11
+ * Reads the call stack and returns the caller's location — both a short display
12
+ * label (`file:line`) and the absolute path/line needed to build a clickable
13
+ * link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
14
+ * (e.g. minified, eval, or native code).
15
+ */
16
+ export default function getCaller(): Caller;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /*
3
+ * getCaller.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.default = getCaller;
10
+ const UNKNOWN = { label: "unknown", file: null, line: null };
11
+ /** Matches a source file by extension: `.js/.jsx/.ts/.tsx` and `.cjs/.mjs/.cts/.mts`. */
12
+ const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
13
+ /**
14
+ * Reads the call stack and returns the caller's location — both a short display
15
+ * label (`file:line`) and the absolute path/line needed to build a clickable
16
+ * link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
17
+ * (e.g. minified, eval, or native code).
18
+ */
19
+ function getCaller() {
20
+ const stack = new Error().stack ?? "";
21
+ const frame = stack.split("\n")[3] ?? "";
22
+ // V8 frames look like `at fn (/path/file.js:10:5)` or `at /path/file.js:10:5`
23
+ // (and `file://…` for ESM). Prefer the parenthesised location when present.
24
+ const parens = frame.match(/\(([^)]+)\)\s*$/);
25
+ const inner = (parens?.[1] ?? frame.replace(/^\s*at\s+(?:async\s+)?/, "")).trim();
26
+ // Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
27
+ // path intact (e.g. Windows `C:\…` or `file://…`).
28
+ const match = inner.match(/^(.*):(\d+):\d+$/);
29
+ const file = match?.[1];
30
+ if (file === undefined)
31
+ return UNKNOWN;
32
+ const line = Number(match?.[2]);
33
+ const base = file.split(/[/\\]/).pop() ?? "";
34
+ if (!SOURCE_FILE.test(base))
35
+ return UNKNOWN;
36
+ return { label: `${base}:${line}`, file, line };
37
+ }
@@ -0,0 +1,2 @@
1
+ /** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
2
+ export default function getTimeStamp(): string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /*
3
+ * getTimeStamp.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
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();
13
+ }
@@ -0,0 +1,4 @@
1
+ export { default as createLog, type LogChannel } from "./createLog.js";
2
+ export { default as getCaller, type Caller } from "./getCaller.js";
3
+ export { default as getTimeStamp } from "./getTimeStamp.js";
4
+ export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-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.supportsHyperlinks = exports.hyperlink = exports.fileUrl = exports.getTimeStamp = exports.getCaller = exports.createLog = void 0;
13
+ var createLog_js_1 = require("./createLog.js");
14
+ Object.defineProperty(exports, "createLog", { enumerable: true, get: function () { return __importDefault(createLog_js_1).default; } });
15
+ var getCaller_js_1 = require("./getCaller.js");
16
+ Object.defineProperty(exports, "getCaller", { enumerable: true, get: function () { return __importDefault(getCaller_js_1).default; } });
17
+ var getTimeStamp_js_1 = require("./getTimeStamp.js");
18
+ Object.defineProperty(exports, "getTimeStamp", { enumerable: true, get: function () { return __importDefault(getTimeStamp_js_1).default; } });
19
+ var link_js_1 = require("./link.js");
20
+ Object.defineProperty(exports, "fileUrl", { enumerable: true, get: function () { return link_js_1.fileUrl; } });
21
+ Object.defineProperty(exports, "hyperlink", { enumerable: true, get: function () { return link_js_1.hyperlink; } });
22
+ Object.defineProperty(exports, "supportsHyperlinks", { enumerable: true, get: function () { return link_js_1.supportsHyperlinks; } });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Builds a `file://` URL with a trailing `:line` so terminals can jump to the
3
+ * exact line. Paths already in `file://` form are used as-is.
4
+ */
5
+ export declare function fileUrl(file: string, line: number): string;
6
+ /**
7
+ * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
8
+ * support OSC-8 render `text` as a clickable link; others simply show `text`.
9
+ */
10
+ export declare function hyperlink(text: string, url: string): string;
11
+ /**
12
+ * Conservative detection of OSC-8 hyperlink support for the given stream.
13
+ * Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
14
+ * and otherwise allow-lists terminals known to support hyperlinks. Unknown
15
+ * terminals get plain text so output is never garbled.
16
+ */
17
+ export declare function supportsHyperlinks(streamName: "stdout" | "stderr"): boolean;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /*
3
+ * link.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.fileUrl = fileUrl;
10
+ exports.hyperlink = hyperlink;
11
+ exports.supportsHyperlinks = supportsHyperlinks;
12
+ const node_url_1 = require("node:url");
13
+ /**
14
+ * Builds a `file://` URL with a trailing `:line` so terminals can jump to the
15
+ * exact line. Paths already in `file://` form are used as-is.
16
+ */
17
+ function fileUrl(file, line) {
18
+ const base = file.startsWith("file://") ? file : (0, node_url_1.pathToFileURL)(file).href;
19
+ return `${base}:${line}`;
20
+ }
21
+ /**
22
+ * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
23
+ * support OSC-8 render `text` as a clickable link; others simply show `text`.
24
+ */
25
+ function hyperlink(text, url) {
26
+ const OSC = "\x1b]8;;";
27
+ const BEL = "\x07";
28
+ return `${OSC}${url}${BEL}${text}${OSC}${BEL}`;
29
+ }
30
+ /**
31
+ * Conservative detection of OSC-8 hyperlink support for the given stream.
32
+ * Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
33
+ * and otherwise allow-lists terminals known to support hyperlinks. Unknown
34
+ * terminals get plain text so output is never garbled.
35
+ */
36
+ function supportsHyperlinks(streamName) {
37
+ if (typeof process === "undefined")
38
+ return false;
39
+ const env = process.env;
40
+ const force = env.FORCE_HYPERLINK;
41
+ if (force !== undefined && force !== "")
42
+ return force !== "0" && force.toLowerCase() !== "false";
43
+ const stream = streamName === "stdout" ? process.stdout : process.stderr;
44
+ if (!stream || !stream.isTTY)
45
+ return false;
46
+ if (env.TERM === "dumb")
47
+ return false;
48
+ if (env.CI !== undefined && env.CI !== "")
49
+ return false;
50
+ const program = env.TERM_PROGRAM;
51
+ if (program === "vscode" ||
52
+ program === "iTerm.app" ||
53
+ program === "Hyper" ||
54
+ program === "WezTerm")
55
+ return true;
56
+ if (env.WT_SESSION)
57
+ return true; // Windows Terminal
58
+ if (env.KITTY_WINDOW_ID)
59
+ return true;
60
+ if (env.VTE_VERSION !== undefined && Number(env.VTE_VERSION) >= 5000)
61
+ return true; // GNOME, etc.
62
+ return false;
63
+ }
package/dist/index.d.ts CHANGED
@@ -6,13 +6,13 @@ export interface LogFN {
6
6
  }
7
7
  /**
8
8
  * Logs to the console, but only outside production. Each line is prefixed with
9
- * an `[INFO]` tag, an ISO timestamp, and the file and line it was called from;
10
- * all arguments are then printed as-is. `.error` and `.warn` behave the same
11
- * with their own tags and console channels.
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.
12
11
  * @example
13
12
  * customLog("Auth", "user logged in")
14
13
  * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
15
14
  */
16
15
  declare const customLog: LogFN;
16
+ export { customLog };
17
17
  export default customLog;
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,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;AAmBD;;;;;;;;GAQG;AACH,QAAA,MAAM,SAAS,EAAE,KAGf,CAAA;AAEF,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;CAC/B;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,SAAS,EAAE,KAGf,CAAA;AAEF,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -4,26 +4,11 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
- import { getFileName, getTimeStamp } from "./utils/index.js";
8
- import { isLogAllowed } from "./config.js";
9
- /**
10
- * Builds a log function bound to a console channel and tag. The returned closure
11
- * is what the caller invokes directly, so {@link getFileName} still resolves the
12
- * caller's own frame (no extra stack frame is inserted). `console[channel]` is
13
- * looked up at call time, so reassigning `console.log` (e.g. in tests) is
14
- * respected. Logs only outside production — see {@link isLogAllowed}.
15
- */
16
- function createLog(channel, tag) {
17
- return (...args) => {
18
- if (isLogAllowed())
19
- console[channel](tag, getTimeStamp(), `(${getFileName()})`, ...args);
20
- };
21
- }
7
+ import { createLog } from "./utils/index.js";
22
8
  /**
23
9
  * Logs to the console, but only outside production. Each line is prefixed with
24
- * an `[INFO]` tag, an ISO timestamp, and the file and line it was called from;
25
- * all arguments are then printed as-is. `.error` and `.warn` behave the same
26
- * with their own tags and console channels.
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.
27
12
  * @example
28
13
  * customLog("Auth", "user logged in")
29
14
  * // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
@@ -32,5 +17,6 @@ const customLog = Object.assign(createLog("log", "[INFO]"), {
32
17
  error: createLog("error", "[ERROR]"),
33
18
  warn: createLog("warn", "[WARN]"),
34
19
  });
20
+ export { customLog };
35
21
  export default customLog;
36
22
  //# 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,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAS1C;;;;;;GAMG;AACH,SAAS,SAAS,CAChB,OAAiC,EACjC,GAAW;IAEX,OAAO,CAAC,GAAG,IAAe,EAAQ,EAAE;QAClC,IAAI,YAAY,EAAE;YAChB,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,IAAI,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IACxE,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;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,eAAe,SAAS,CAAA"}
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"}
@@ -0,0 +1,11 @@
1
+ /** The console channels the logger writes to. */
2
+ export type LogChannel = "log" | "error" | "warn";
3
+ /**
4
+ * Builds a log function bound to a console channel and tag. The returned closure
5
+ * is what the caller invokes directly, so {@link getCaller} still resolves the
6
+ * caller's own frame (no extra stack frame is inserted). `console[channel]` is
7
+ * looked up at call time, so reassigning `console.log` (e.g. in tests) is
8
+ * respected. Logs only outside production — see {@link isLogAllowed}.
9
+ */
10
+ export default function createLog(channel: LogChannel, tag: string): (...args: unknown[]) => void;
11
+ //# sourceMappingURL=createLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createLog.d.ts","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAYA,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAA;AAqBjD;;;;;;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,CAQ9B"}
@@ -0,0 +1,41 @@
1
+ /*
2
+ * createLog.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import getCaller from "./getCaller.js";
8
+ import getTimeStamp from "./getTimeStamp.js";
9
+ import { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
10
+ import { isLogAllowed } from "../config.js";
11
+ /**
12
+ * Renders a caller as a `(file:line)` location. When the terminal supports
13
+ * OSC-8 hyperlinks, the location is a clickable link to the exact source line;
14
+ * otherwise it's plain text. Pure (no stack access), so it can be called from a
15
+ * helper without disturbing {@link getCaller}'s frame depth.
16
+ */
17
+ function formatLocation(caller, streamName) {
18
+ if (caller.file !== null &&
19
+ caller.line !== null &&
20
+ supportsHyperlinks(streamName))
21
+ return hyperlink(caller.label, fileUrl(caller.file, caller.line));
22
+ return caller.label;
23
+ }
24
+ /**
25
+ * Builds a log function bound to a console channel and tag. The returned closure
26
+ * is what the caller invokes directly, so {@link getCaller} still resolves the
27
+ * caller's own frame (no extra stack frame is inserted). `console[channel]` is
28
+ * looked up at call time, so reassigning `console.log` (e.g. in tests) is
29
+ * respected. Logs only outside production — see {@link isLogAllowed}.
30
+ */
31
+ export default function createLog(channel, tag) {
32
+ const streamName = channel === "log" ? "stdout" : "stderr";
33
+ return (...args) => {
34
+ if (!isLogAllowed())
35
+ return;
36
+ const caller = getCaller();
37
+ const location = formatLocation(caller, streamName);
38
+ console[channel](tag, getTimeStamp(), `(${location})`, `\n`, ...args, `\n`);
39
+ };
40
+ }
41
+ //# sourceMappingURL=createLog.js.map
@@ -0,0 +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,YAAY,EAAE,MAAM,cAAc,CAAA;AAK3C;;;;;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,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACnE,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;QACnD,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,IAAI,QAAQ,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,CAAC,CAAA;IAC7E,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /** A resolved call site. `file`/`line` are `null` when they can't be determined. */
2
+ export interface Caller {
3
+ /** Short display location, e.g. `server.ts:42`, or `"unknown"`. */
4
+ label: string;
5
+ /** Absolute path (or `file://` URL) of the calling file, or `null`. */
6
+ file: string | null;
7
+ /** 1-based line number, or `null`. */
8
+ line: number | null;
9
+ }
10
+ /**
11
+ * Reads the call stack and returns the caller's location — both a short display
12
+ * label (`file:line`) and the absolute path/line needed to build a clickable
13
+ * link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
14
+ * (e.g. minified, eval, or native code).
15
+ */
16
+ export default function getCaller(): Caller;
17
+ //# sourceMappingURL=getCaller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCaller.d.ts","sourceRoot":"","sources":["../../src/utils/getCaller.ts"],"names":[],"mappings":"AAOA,oFAAoF;AACpF,MAAM,WAAW,MAAM;IACrB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,sCAAsC;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAOD;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,IAAI,MAAM,CAsB1C"}
@@ -0,0 +1,35 @@
1
+ /*
2
+ * getCaller.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ const UNKNOWN = { label: "unknown", file: null, line: null };
8
+ /** Matches a source file by extension: `.js/.jsx/.ts/.tsx` and `.cjs/.mjs/.cts/.mts`. */
9
+ const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
10
+ /**
11
+ * Reads the call stack and returns the caller's location — both a short display
12
+ * label (`file:line`) and the absolute path/line needed to build a clickable
13
+ * link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
14
+ * (e.g. minified, eval, or native code).
15
+ */
16
+ export default function getCaller() {
17
+ const stack = new Error().stack ?? "";
18
+ const frame = stack.split("\n")[3] ?? "";
19
+ // V8 frames look like `at fn (/path/file.js:10:5)` or `at /path/file.js:10:5`
20
+ // (and `file://…` for ESM). Prefer the parenthesised location when present.
21
+ const parens = frame.match(/\(([^)]+)\)\s*$/);
22
+ const inner = (parens?.[1] ?? frame.replace(/^\s*at\s+(?:async\s+)?/, "")).trim();
23
+ // Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
24
+ // path intact (e.g. Windows `C:\…` or `file://…`).
25
+ const match = inner.match(/^(.*):(\d+):\d+$/);
26
+ const file = match?.[1];
27
+ if (file === undefined)
28
+ return UNKNOWN;
29
+ const line = Number(match?.[2]);
30
+ const base = file.split(/[/\\]/).pop() ?? "";
31
+ if (!SOURCE_FILE.test(base))
32
+ return UNKNOWN;
33
+ return { label: `${base}:${line}`, file, line };
34
+ }
35
+ //# sourceMappingURL=getCaller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCaller.js","sourceRoot":"","sources":["../../src/utils/getCaller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,MAAM,OAAO,GAAW,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAEpE,yFAAyF;AACzF,MAAM,WAAW,GAAG,iBAAiB,CAAA;AAErC;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAA;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAExC,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC7C,MAAM,KAAK,GAAG,CACZ,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAC3D,CAAC,IAAI,EAAE,CAAA;IAER,8EAA8E;IAC9E,mDAAmD;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACvB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAA;IAEtC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;IAC5C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAA;IAE3C,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACjD,CAAC"}
@@ -1,3 +1,5 @@
1
- export { default as getFileName } from "./getFileName.js";
1
+ export { default as createLog, type LogChannel } from "./createLog.js";
2
+ export { default as getCaller, type Caller } from "./getCaller.js";
2
3
  export { default as getTimeStamp } from "./getTimeStamp.js";
4
+ export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
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"}
@@ -4,6 +4,8 @@
4
4
  * Copyright (c) 2026 dewan-meadown
5
5
  * All rights reserved
6
6
  */
7
- export { default as getFileName } from "./getFileName.js";
7
+ export { default as createLog } from "./createLog.js";
8
+ export { default as getCaller } from "./getCaller.js";
8
9
  export { default as getTimeStamp } from "./getTimeStamp.js";
10
+ export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
9
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Builds a `file://` URL with a trailing `:line` so terminals can jump to the
3
+ * exact line. Paths already in `file://` form are used as-is.
4
+ */
5
+ export declare function fileUrl(file: string, line: number): string;
6
+ /**
7
+ * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
8
+ * support OSC-8 render `text` as a clickable link; others simply show `text`.
9
+ */
10
+ export declare function hyperlink(text: string, url: string): string;
11
+ /**
12
+ * Conservative detection of OSC-8 hyperlink support for the given stream.
13
+ * Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
14
+ * and otherwise allow-lists terminals known to support hyperlinks. Unknown
15
+ * terminals get plain text so output is never garbled.
16
+ */
17
+ export declare function supportsHyperlinks(streamName: "stdout" | "stderr"): boolean;
18
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/utils/link.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CA2B3E"}
@@ -0,0 +1,59 @@
1
+ /*
2
+ * link.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import { pathToFileURL } from "node:url";
8
+ /**
9
+ * Builds a `file://` URL with a trailing `:line` so terminals can jump to the
10
+ * exact line. Paths already in `file://` form are used as-is.
11
+ */
12
+ export function fileUrl(file, line) {
13
+ const base = file.startsWith("file://") ? file : pathToFileURL(file).href;
14
+ return `${base}:${line}`;
15
+ }
16
+ /**
17
+ * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
18
+ * support OSC-8 render `text` as a clickable link; others simply show `text`.
19
+ */
20
+ export function hyperlink(text, url) {
21
+ const OSC = "\x1b]8;;";
22
+ const BEL = "\x07";
23
+ return `${OSC}${url}${BEL}${text}${OSC}${BEL}`;
24
+ }
25
+ /**
26
+ * Conservative detection of OSC-8 hyperlink support for the given stream.
27
+ * Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
28
+ * and otherwise allow-lists terminals known to support hyperlinks. Unknown
29
+ * terminals get plain text so output is never garbled.
30
+ */
31
+ export function supportsHyperlinks(streamName) {
32
+ if (typeof process === "undefined")
33
+ return false;
34
+ const env = process.env;
35
+ const force = env.FORCE_HYPERLINK;
36
+ if (force !== undefined && force !== "")
37
+ return force !== "0" && force.toLowerCase() !== "false";
38
+ const stream = streamName === "stdout" ? process.stdout : process.stderr;
39
+ if (!stream || !stream.isTTY)
40
+ return false;
41
+ if (env.TERM === "dumb")
42
+ return false;
43
+ if (env.CI !== undefined && env.CI !== "")
44
+ return false;
45
+ const program = env.TERM_PROGRAM;
46
+ if (program === "vscode" ||
47
+ program === "iTerm.app" ||
48
+ program === "Hyper" ||
49
+ program === "WezTerm")
50
+ return true;
51
+ if (env.WT_SESSION)
52
+ return true; // Windows Terminal
53
+ if (env.KITTY_WINDOW_ID)
54
+ return true;
55
+ if (env.VTE_VERSION !== undefined && Number(env.VTE_VERSION) >= 5000)
56
+ return true; // GNOME, etc.
57
+ return false;
58
+ }
59
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/utils/link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAA;IACzE,OAAO,GAAG,IAAI,IAAI,IAAI,EAAE,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,GAAW;IACjD,MAAM,GAAG,GAAG,UAAU,CAAA;IACtB,MAAM,GAAG,GAAG,MAAM,CAAA;IAClB,OAAO,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,EAAE,CAAA;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B;IAChE,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,CAAA;IACjC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QACrC,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,CAAA;IAEzD,MAAM,MAAM,GAAG,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IACxE,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IAC1C,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAA;IACrC,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE;QAAE,OAAO,KAAK,CAAA;IAEvD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAA;IAChC,IACE,OAAO,KAAK,QAAQ;QACpB,OAAO,KAAK,WAAW;QACvB,OAAO,KAAK,OAAO;QACnB,OAAO,KAAK,SAAS;QAErB,OAAO,IAAI,CAAA;IACb,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA,CAAC,mBAAmB;IACnD,IAAI,GAAG,CAAC,eAAe;QAAE,OAAO,IAAI,CAAA;IACpC,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI;QAClE,OAAO,IAAI,CAAA,CAAC,cAAc;IAE5B,OAAO,KAAK,CAAA;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meadown/logger",
3
- "version": "1.0.1",
3
+ "version": "1.2.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",
@@ -23,13 +23,19 @@
23
23
  "license": "MIT",
24
24
  "author": "Dewan Mobashirul",
25
25
  "type": "module",
26
- "main": "dist/index.js",
27
- "types": "dist/index.d.ts",
26
+ "main": "./dist/cjs/index.js",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
28
29
  "exports": {
29
30
  ".": {
30
- "types": "./dist/index.d.ts",
31
- "import": "./dist/index.js",
32
- "default": "./dist/index.js"
31
+ "import": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/cjs/index.d.ts",
37
+ "default": "./dist/cjs/index.js"
38
+ }
33
39
  }
34
40
  },
35
41
  "files": [
@@ -42,7 +48,7 @@
42
48
  "access": "public"
43
49
  },
44
50
  "scripts": {
45
- "build": "tsc",
51
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/write-cjs-pkg.mjs",
46
52
  "test": "tsc && node --test \"test/**/*.test.mjs\"",
47
53
  "lint": "eslint src",
48
54
  "lint:fix": "eslint src --fix",
@@ -1,6 +0,0 @@
1
- /**
2
- * Returns the caller's source location as `file.ext:line` by reading the call
3
- * stack, or `"unknown"` if it can't be determined (e.g. minified or eval code).
4
- */
5
- export default function getFileName(): string;
6
- //# sourceMappingURL=getFileName.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileName.d.ts","sourceRoot":"","sources":["../../src/utils/getFileName.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,IAAI,MAAM,CAK5C"}
@@ -1,17 +0,0 @@
1
- /*
2
- * getFileName.ts
3
- * Created by Dewan Mobashirul
4
- * Copyright (c) 2026 dewan-meadown
5
- * All rights reserved
6
- */
7
- /**
8
- * Returns the caller's source location as `file.ext:line` by reading the call
9
- * stack, or `"unknown"` if it can't be determined (e.g. minified or eval code).
10
- */
11
- export default function getFileName() {
12
- const stack = new Error().stack ?? "";
13
- const line = stack.split("\n")[3] ?? "";
14
- const match = line.match(/([^/\\]+\.[cm]?[jt]sx?):(\d+)/);
15
- return match ? match[0] : "unknown";
16
- }
17
- //# sourceMappingURL=getFileName.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getFileName.js","sourceRoot":"","sources":["../../src/utils/getFileName.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW;IACjC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAA;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAA;IACzD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACrC,CAAC"}