@warlock.js/logger 4.0.174 → 4.1.1

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 (135) hide show
  1. package/README.md +145 -422
  2. package/cjs/index.cjs +1003 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/channels/console-log.d.mts +40 -0
  5. package/esm/channels/console-log.d.mts.map +1 -0
  6. package/esm/channels/console-log.mjs +51 -0
  7. package/esm/channels/console-log.mjs.map +1 -0
  8. package/esm/channels/file-log.d.mts +194 -0
  9. package/esm/channels/file-log.d.mts.map +1 -0
  10. package/esm/channels/file-log.mjs +267 -0
  11. package/esm/channels/file-log.mjs.map +1 -0
  12. package/esm/channels/index.mjs +5 -0
  13. package/esm/channels/json-file-log.d.mts +33 -0
  14. package/esm/channels/json-file-log.d.mts.map +1 -0
  15. package/esm/channels/json-file-log.mjs +137 -0
  16. package/esm/channels/json-file-log.mjs.map +1 -0
  17. package/esm/index.d.mts +11 -0
  18. package/esm/index.mjs +13 -0
  19. package/esm/log-channel.d.mts +78 -0
  20. package/esm/log-channel.d.mts.map +1 -0
  21. package/esm/log-channel.mjs +75 -0
  22. package/esm/log-channel.mjs.map +1 -0
  23. package/esm/logger.d.mts +184 -0
  24. package/esm/logger.d.mts.map +1 -0
  25. package/esm/logger.mjs +282 -0
  26. package/esm/logger.mjs.map +1 -0
  27. package/esm/redact/redact.d.mts +25 -0
  28. package/esm/redact/redact.d.mts.map +1 -0
  29. package/esm/redact/redact.mjs +109 -0
  30. package/esm/redact/redact.mjs.map +1 -0
  31. package/esm/types.d.mts +129 -0
  32. package/esm/types.d.mts.map +1 -0
  33. package/esm/utils/capture-unhandled-errors.d.mts +16 -0
  34. package/esm/utils/capture-unhandled-errors.d.mts.map +1 -0
  35. package/esm/utils/capture-unhandled-errors.mjs +26 -0
  36. package/esm/utils/capture-unhandled-errors.mjs.map +1 -0
  37. package/esm/utils/clear-message.d.mts +8 -0
  38. package/esm/utils/clear-message.d.mts.map +1 -0
  39. package/esm/utils/clear-message.mjs +12 -0
  40. package/esm/utils/clear-message.mjs.map +1 -0
  41. package/esm/utils/index.mjs +5 -0
  42. package/esm/utils/safe-json-stringify.d.mts +14 -0
  43. package/esm/utils/safe-json-stringify.d.mts.map +1 -0
  44. package/esm/utils/safe-json-stringify.mjs +35 -0
  45. package/esm/utils/safe-json-stringify.mjs.map +1 -0
  46. package/llms-full.txt +1296 -0
  47. package/llms.txt +19 -0
  48. package/package.json +39 -39
  49. package/skills/capture-unhandled-errors/SKILL.md +103 -0
  50. package/skills/configure-logger/SKILL.md +105 -0
  51. package/skills/filter-log-entries/SKILL.md +120 -0
  52. package/skills/flush-logs-on-shutdown/SKILL.md +91 -0
  53. package/skills/logger-basics/SKILL.md +85 -0
  54. package/skills/overview/SKILL.md +86 -0
  55. package/skills/pick-log-channel/SKILL.md +139 -0
  56. package/skills/redact-sensitive-log-fields/SKILL.md +122 -0
  57. package/skills/test-logging-code/SKILL.md +169 -0
  58. package/skills/use-log-helpers/SKILL.md +66 -0
  59. package/skills/write-custom-log-channel/SKILL.md +160 -0
  60. package/cjs/channels/console-log.d.ts +0 -17
  61. package/cjs/channels/console-log.d.ts.map +0 -1
  62. package/cjs/channels/console-log.js +0 -47
  63. package/cjs/channels/console-log.js.map +0 -1
  64. package/cjs/channels/file-log.d.ts +0 -171
  65. package/cjs/channels/file-log.d.ts.map +0 -1
  66. package/cjs/channels/file-log.js +0 -293
  67. package/cjs/channels/file-log.js.map +0 -1
  68. package/cjs/channels/index.d.ts +0 -4
  69. package/cjs/channels/index.d.ts.map +0 -1
  70. package/cjs/channels/json-file-log.d.ts +0 -33
  71. package/cjs/channels/json-file-log.d.ts.map +0 -1
  72. package/cjs/channels/json-file-log.js +0 -164
  73. package/cjs/channels/json-file-log.js.map +0 -1
  74. package/cjs/index.d.ts +0 -6
  75. package/cjs/index.d.ts.map +0 -1
  76. package/cjs/index.js +0 -1
  77. package/cjs/index.js.map +0 -1
  78. package/cjs/log-channel.d.ts +0 -67
  79. package/cjs/log-channel.d.ts.map +0 -1
  80. package/cjs/log-channel.js +0 -88
  81. package/cjs/log-channel.js.map +0 -1
  82. package/cjs/logger.d.ts +0 -62
  83. package/cjs/logger.d.ts.map +0 -1
  84. package/cjs/logger.js +0 -124
  85. package/cjs/logger.js.map +0 -1
  86. package/cjs/types.d.ts +0 -104
  87. package/cjs/types.d.ts.map +0 -1
  88. package/cjs/utils/capture-unhandled-errors.d.ts +0 -2
  89. package/cjs/utils/capture-unhandled-errors.d.ts.map +0 -1
  90. package/cjs/utils/capture-unhandled-errors.js +0 -12
  91. package/cjs/utils/capture-unhandled-errors.js.map +0 -1
  92. package/cjs/utils/clear-message.d.ts +0 -5
  93. package/cjs/utils/clear-message.d.ts.map +0 -1
  94. package/cjs/utils/clear-message.js +0 -9
  95. package/cjs/utils/clear-message.js.map +0 -1
  96. package/cjs/utils/index.d.ts +0 -3
  97. package/cjs/utils/index.d.ts.map +0 -1
  98. package/esm/channels/console-log.d.ts +0 -17
  99. package/esm/channels/console-log.d.ts.map +0 -1
  100. package/esm/channels/console-log.js +0 -47
  101. package/esm/channels/console-log.js.map +0 -1
  102. package/esm/channels/file-log.d.ts +0 -171
  103. package/esm/channels/file-log.d.ts.map +0 -1
  104. package/esm/channels/file-log.js +0 -293
  105. package/esm/channels/file-log.js.map +0 -1
  106. package/esm/channels/index.d.ts +0 -4
  107. package/esm/channels/index.d.ts.map +0 -1
  108. package/esm/channels/json-file-log.d.ts +0 -33
  109. package/esm/channels/json-file-log.d.ts.map +0 -1
  110. package/esm/channels/json-file-log.js +0 -164
  111. package/esm/channels/json-file-log.js.map +0 -1
  112. package/esm/index.d.ts +0 -6
  113. package/esm/index.d.ts.map +0 -1
  114. package/esm/index.js +0 -1
  115. package/esm/index.js.map +0 -1
  116. package/esm/log-channel.d.ts +0 -67
  117. package/esm/log-channel.d.ts.map +0 -1
  118. package/esm/log-channel.js +0 -88
  119. package/esm/log-channel.js.map +0 -1
  120. package/esm/logger.d.ts +0 -62
  121. package/esm/logger.d.ts.map +0 -1
  122. package/esm/logger.js +0 -124
  123. package/esm/logger.js.map +0 -1
  124. package/esm/types.d.ts +0 -104
  125. package/esm/types.d.ts.map +0 -1
  126. package/esm/utils/capture-unhandled-errors.d.ts +0 -2
  127. package/esm/utils/capture-unhandled-errors.d.ts.map +0 -1
  128. package/esm/utils/capture-unhandled-errors.js +0 -12
  129. package/esm/utils/capture-unhandled-errors.js.map +0 -1
  130. package/esm/utils/clear-message.d.ts +0 -5
  131. package/esm/utils/clear-message.d.ts.map +0 -1
  132. package/esm/utils/clear-message.js +0 -9
  133. package/esm/utils/clear-message.js.map +0 -1
  134. package/esm/utils/index.d.ts +0 -3
  135. package/esm/utils/index.d.ts.map +0 -1
@@ -0,0 +1,109 @@
1
+ //#region ../../@warlock.js/logger/src/redact/redact.ts
2
+ /**
3
+ * Deep-clone a value with structural fidelity for log entries — handles plain
4
+ * objects, arrays, `Date`, `Error`, and primitives. Anything else is copied
5
+ * by reference (we only redact paths through plain objects/arrays anyway,
6
+ * and rebuilding e.g. a `Buffer` would change semantics).
7
+ *
8
+ * Purpose-built rather than reaching for `structuredClone`: `Error` instances
9
+ * lose their `message`/`stack` under `structuredClone` in some Node versions,
10
+ * and the logger pipeline carries them often.
11
+ */
12
+ function cloneEntry(value, seen = /* @__PURE__ */ new WeakMap()) {
13
+ if (value === null || typeof value !== "object") return value;
14
+ if (seen.has(value)) return seen.get(value);
15
+ if (value instanceof Date) return new Date(value.getTime());
16
+ if (value instanceof Error) {
17
+ const copy = new value.constructor(value.message);
18
+ copy.stack = value.stack;
19
+ copy.name = value.name;
20
+ return copy;
21
+ }
22
+ if (Array.isArray(value)) {
23
+ const arr = [];
24
+ seen.set(value, arr);
25
+ for (const item of value) arr.push(cloneEntry(item, seen));
26
+ return arr;
27
+ }
28
+ const out = {};
29
+ seen.set(value, out);
30
+ for (const key of Object.keys(value)) out[key] = cloneEntry(value[key], seen);
31
+ return out;
32
+ }
33
+ /**
34
+ * Apply a single censor decision to a value. String censors are returned
35
+ * verbatim; function censors receive the original value plus the dotted
36
+ * path so callers can implement value-aware redaction (mask all but the
37
+ * last 4 chars, hash, etc.).
38
+ */
39
+ function applyCensor(value, censor, path) {
40
+ if (typeof censor === "function") return censor(value, path.join("."));
41
+ return censor;
42
+ }
43
+ /**
44
+ * Walk `target` following the remaining `segments` of a path pattern,
45
+ * replacing matched leaves via `censor`. Operates in place — the caller
46
+ * is responsible for cloning before calling.
47
+ *
48
+ * Wildcards:
49
+ * - `*` matches exactly one segment (any key on a plain object, any index
50
+ * on an array — stringified for the path that's passed to a function
51
+ * censor).
52
+ * - `**` matches zero or more segments greedily; the rest of the pattern
53
+ * is then attempted at the current level and at every descendant.
54
+ */
55
+ function redactAtPath(target, segments, censor, pathTrail) {
56
+ if (target === null || typeof target !== "object") return;
57
+ if (segments.length === 0) return;
58
+ const [head, ...rest] = segments;
59
+ if (head === "**") {
60
+ if (rest.length > 0) redactAtPath(target, rest, censor, pathTrail);
61
+ const keys = Array.isArray(target) ? target.map((_, index) => String(index)) : Object.keys(target);
62
+ for (const key of keys) redactAtPath(target[key], segments, censor, [...pathTrail, key]);
63
+ return;
64
+ }
65
+ const keysToVisit = head === "*" ? Array.isArray(target) ? target.map((_, index) => String(index)) : Object.keys(target) : Array.isArray(target) ? /^\d+$/.test(head) && Number(head) < target.length ? [head] : [] : Object.prototype.hasOwnProperty.call(target, head) ? [head] : [];
66
+ for (const key of keysToVisit) if (rest.length === 0) target[key] = applyCensor(target[key], censor, [...pathTrail, key]);
67
+ else redactAtPath(target[key], rest, censor, [...pathTrail, key]);
68
+ }
69
+ /**
70
+ * Produce a new `LoggingData` with every path in `config.paths` replaced
71
+ * by `config.censor`. The original entry is never mutated — channels and
72
+ * other call sites can hold references to the input safely.
73
+ *
74
+ * No-op (returns the input by reference) when `config` is `undefined` or
75
+ * its `paths` array is empty, so the fast path stays fast.
76
+ */
77
+ function applyRedact(data, config) {
78
+ if (!config || config.paths.length === 0) return data;
79
+ const censor = config.censor ?? "[REDACTED]";
80
+ const cloned = cloneEntry(data);
81
+ for (const pattern of config.paths) {
82
+ const segments = pattern.split(".").filter((segment) => segment.length > 0);
83
+ if (segments.length === 0) continue;
84
+ redactAtPath(cloned, segments, censor, []);
85
+ }
86
+ return cloned;
87
+ }
88
+ /**
89
+ * Combine two redact configs into one effective config. Used to merge a
90
+ * channel's additive paths on top of the logger-wide floor.
91
+ *
92
+ * - `paths` are concatenated; duplicates are kept (the matcher tolerates
93
+ * them, and de-duping cross-config would mask a developer typo).
94
+ * - `censor` from the channel wins; falls back to the logger's; falls back
95
+ * to the default `"[REDACTED]"`.
96
+ */
97
+ function mergeRedact(base, extra) {
98
+ if (!base && !extra) return void 0;
99
+ if (!base) return extra;
100
+ if (!extra) return base;
101
+ return {
102
+ paths: [...base.paths, ...extra.paths],
103
+ censor: extra.censor ?? base.censor
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ export { applyRedact, mergeRedact };
109
+ //# sourceMappingURL=redact.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.mjs","names":[],"sources":["../../../../../../@warlock.js/logger/src/redact/redact.ts"],"sourcesContent":["import type { LoggingData, RedactCensor, RedactConfig } from \"../types\";\n\n/**\n * Deep-clone a value with structural fidelity for log entries — handles plain\n * objects, arrays, `Date`, `Error`, and primitives. Anything else is copied\n * by reference (we only redact paths through plain objects/arrays anyway,\n * and rebuilding e.g. a `Buffer` would change semantics).\n *\n * Purpose-built rather than reaching for `structuredClone`: `Error` instances\n * lose their `message`/`stack` under `structuredClone` in some Node versions,\n * and the logger pipeline carries them often.\n */\nfunction cloneEntry<T>(value: T, seen = new WeakMap<object, any>()): T {\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n\n if (seen.has(value as unknown as object)) {\n return seen.get(value as unknown as object);\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime()) as unknown as T;\n }\n\n if (value instanceof Error) {\n const copy = new (value.constructor as ErrorConstructor)(value.message);\n copy.stack = value.stack;\n copy.name = value.name;\n return copy as unknown as T;\n }\n\n if (Array.isArray(value)) {\n const arr: any[] = [];\n seen.set(value as unknown as object, arr);\n for (const item of value) {\n arr.push(cloneEntry(item, seen));\n }\n return arr as unknown as T;\n }\n\n const out: Record<string, any> = {};\n seen.set(value as unknown as object, out);\n for (const key of Object.keys(value as Record<string, any>)) {\n out[key] = cloneEntry((value as Record<string, any>)[key], seen);\n }\n return out as unknown as T;\n}\n\n/**\n * Apply a single censor decision to a value. String censors are returned\n * verbatim; function censors receive the original value plus the dotted\n * path so callers can implement value-aware redaction (mask all but the\n * last 4 chars, hash, etc.).\n */\nfunction applyCensor(value: any, censor: RedactCensor, path: string[]): any {\n if (typeof censor === \"function\") {\n return censor(value, path.join(\".\"));\n }\n return censor;\n}\n\n/**\n * Walk `target` following the remaining `segments` of a path pattern,\n * replacing matched leaves via `censor`. Operates in place — the caller\n * is responsible for cloning before calling.\n *\n * Wildcards:\n * - `*` matches exactly one segment (any key on a plain object, any index\n * on an array — stringified for the path that's passed to a function\n * censor).\n * - `**` matches zero or more segments greedily; the rest of the pattern\n * is then attempted at the current level and at every descendant.\n */\nfunction redactAtPath(\n target: any,\n segments: string[],\n censor: RedactCensor,\n pathTrail: string[],\n): void {\n if (target === null || typeof target !== \"object\") {\n return;\n }\n\n if (segments.length === 0) {\n return;\n }\n\n const [head, ...rest] = segments;\n\n if (head === \"**\") {\n // Try matching `rest` at the current level (the zero-segment match\n // case), then recurse into every child carrying the `**` forward so\n // it keeps matching at deeper levels too.\n if (rest.length > 0) {\n redactAtPath(target, rest, censor, pathTrail);\n }\n const keys = Array.isArray(target)\n ? target.map((_, index) => String(index))\n : Object.keys(target);\n for (const key of keys) {\n redactAtPath(target[key], segments, censor, [...pathTrail, key]);\n }\n return;\n }\n\n const keysToVisit =\n head === \"*\"\n ? Array.isArray(target)\n ? target.map((_, index) => String(index))\n : Object.keys(target)\n : Array.isArray(target)\n ? // Numeric segment can index into an array.\n /^\\d+$/.test(head) && Number(head) < target.length\n ? [head]\n : []\n : Object.prototype.hasOwnProperty.call(target, head)\n ? [head]\n : [];\n\n for (const key of keysToVisit) {\n if (rest.length === 0) {\n target[key] = applyCensor(target[key], censor, [...pathTrail, key]);\n } else {\n redactAtPath(target[key], rest, censor, [...pathTrail, key]);\n }\n }\n}\n\n/**\n * Produce a new `LoggingData` with every path in `config.paths` replaced\n * by `config.censor`. The original entry is never mutated — channels and\n * other call sites can hold references to the input safely.\n *\n * No-op (returns the input by reference) when `config` is `undefined` or\n * its `paths` array is empty, so the fast path stays fast.\n */\nexport function applyRedact(\n data: LoggingData,\n config: RedactConfig | undefined,\n): LoggingData {\n if (!config || config.paths.length === 0) {\n return data;\n }\n\n const censor = config.censor ?? \"[REDACTED]\";\n const cloned = cloneEntry(data);\n\n for (const pattern of config.paths) {\n const segments = pattern.split(\".\").filter((segment) => segment.length > 0);\n if (segments.length === 0) continue;\n redactAtPath(cloned, segments, censor, []);\n }\n\n return cloned;\n}\n\n/**\n * Combine two redact configs into one effective config. Used to merge a\n * channel's additive paths on top of the logger-wide floor.\n *\n * - `paths` are concatenated; duplicates are kept (the matcher tolerates\n * them, and de-duping cross-config would mask a developer typo).\n * - `censor` from the channel wins; falls back to the logger's; falls back\n * to the default `\"[REDACTED]\"`.\n */\nexport function mergeRedact(\n base: RedactConfig | undefined,\n extra: RedactConfig | undefined,\n): RedactConfig | undefined {\n if (!base && !extra) return undefined;\n if (!base) return extra;\n if (!extra) return base;\n\n return {\n paths: [...base.paths, ...extra.paths],\n censor: extra.censor ?? base.censor,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ //#region ../../@warlock.js/logger/src/types.d.ts
2
+ type LogLevel = "debug" | "info" | "warn" | "error" | "success";
3
+ /**
4
+ * Process-level events that `Logger.enableAutoFlush()` can hook to drain
5
+ * buffered channels before the process terminates.
6
+ *
7
+ * - Signals (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGBREAK`, `SIGUSR2`) are flushed
8
+ * then re-raised so Node's default exit behavior runs.
9
+ * - `beforeExit` is flushed in place — Node exits on its own afterwards.
10
+ */
11
+ type AutoFlushEvent = "SIGINT" | "SIGTERM" | "SIGHUP" | "SIGBREAK" | "SIGUSR2" | "beforeExit";
12
+ type DebugMode = "daily" | "monthly" | "yearly" | "hourly";
13
+ /**
14
+ * Replacement value used by `RedactConfig`. Either a literal string
15
+ * (e.g. `"[REDACTED]"`) or a function that receives the original value plus
16
+ * the dotted path it sits at and returns whatever should replace it.
17
+ */
18
+ type RedactCensor = string | ((value: any, path: string) => any);
19
+ /**
20
+ * Strip sensitive fields from log entries before they reach a channel.
21
+ *
22
+ * Paths are dotted glob patterns evaluated against the `LoggingData` itself —
23
+ * use `context.password`, `message.token`, etc. Wildcards:
24
+ *
25
+ * - `*` — matches a single segment (any one key)
26
+ * - `**` — matches zero or more segments (any depth, any key)
27
+ *
28
+ * Configurable in two places:
29
+ *
30
+ * 1. **Logger-wide** via `Logger.configure({ redact })` — applied once before
31
+ * fan-out. This is the security floor; no channel can undo it.
32
+ * 2. **Per channel** via the channel's options. Channel paths are *additive*:
33
+ * they extend (never replace) the logger-wide list, so a channel can only
34
+ * redact more, never less.
35
+ *
36
+ * @example
37
+ * logger.configure({
38
+ * redact: {
39
+ * paths: ["context.password", "context.*.token", "context.headers.authorization"],
40
+ * censor: "[REDACTED]",
41
+ * },
42
+ * });
43
+ */
44
+ type RedactConfig = {
45
+ /**
46
+ * Glob path patterns to redact. Paths are evaluated against the full
47
+ * `LoggingData` object — so prefix with `context.` or `message.` to scope
48
+ * to either field.
49
+ */
50
+ paths: string[];
51
+ /**
52
+ * Replacement applied at each matched path.
53
+ *
54
+ * @default "[REDACTED]"
55
+ */
56
+ censor?: RedactCensor;
57
+ };
58
+ type BasicLogConfigurations = {
59
+ /**
60
+ * Set what level of logs should be logged
61
+ *
62
+ * @default all
63
+ */
64
+ levels?: LogLevel[];
65
+ /**
66
+ * Date and time format
67
+ */
68
+ dateFormat?: {
69
+ date?: string;
70
+ time?: string;
71
+ };
72
+ /**
73
+ * Advanced filter to determine if the message should be logged or not
74
+ */
75
+ filter?: (data: LoggingData) => boolean;
76
+ /**
77
+ * Add additional context to the log
78
+ */
79
+ context?: (data: LoggingData) => Promise<Record<string, any>>;
80
+ /**
81
+ * Channel-specific redaction. Additive on top of the logger-wide config —
82
+ * the channel's paths extend (never replace) the logger floor. The
83
+ * `censor` here, when omitted, falls back to the logger-wide censor.
84
+ */
85
+ redact?: RedactConfig;
86
+ };
87
+ type LogMessage = {
88
+ content: string;
89
+ level: LogLevel;
90
+ date: string;
91
+ module: string;
92
+ action: string;
93
+ stack?: string;
94
+ context?: Record<string, any>;
95
+ timestamp?: string;
96
+ };
97
+ interface LogContract {
98
+ /**
99
+ * Channel name
100
+ */
101
+ name: string;
102
+ /**
103
+ * Channel description
104
+ */
105
+ description?: string;
106
+ /**
107
+ * Determine if channel is logging in terminal
108
+ */
109
+ terminal?: boolean;
110
+ /**
111
+ * Log the given message
112
+ */
113
+ log(data: LoggingData): void | Promise<void>;
114
+ /**
115
+ * Synchronously flush logs
116
+ */
117
+ flushSync?(): void;
118
+ }
119
+ type LoggingData = {
120
+ type: "info" | "debug" | "warn" | "error" | "success";
121
+ module: string;
122
+ action: string;
123
+ message: any;
124
+ context?: Record<string, any>;
125
+ };
126
+ type OmittedLoggingData = Omit<LoggingData, "type">;
127
+ //#endregion
128
+ export { AutoFlushEvent, BasicLogConfigurations, DebugMode, LogContract, LogLevel, LogMessage, LoggingData, OmittedLoggingData, RedactCensor, RedactConfig };
129
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../@warlock.js/logger/src/types.ts"],"mappings":";KAAY,QAAA;AAAZ;;;;AAAoB;AAUpB;;;AAVA,KAUY,cAAA;AAAA,KAQA,SAAA;AAAZ;;;;AAAqB;AAArB,KAOY,YAAA,cAEN,KAAA,OAAY,IAAY;;;;AAAA;AA2B9B;;;;;;;;AAYuB;AAGvB;;;;;;;;;;;;KAfY,YAAA;EAyBV;;;;;EAnBA,KAAA;EA8BA;;;;;EAxBA,MAAA,GAAS,YAAY;AAAA;AAAA,KAGX,sBAAA;EA2BW;AAGvB;;;;EAxBE,MAAA,GAAS,QAAA;EA0BT;;;EAtBA,UAAA;IACE,IAAA;IACA,IAAA;EAAA;EAyBQ;;;EApBV,MAAA,IAAU,IAAA,EAAM,WAAA;EAwBD;;;EApBf,OAAA,IAAW,IAAA,EAAM,WAAA,KAAgB,OAAA,CAAQ,MAAA;EAwBzC;;;;;EAlBA,MAAA,GAAS,YAAA;AAAA;AAAA,KAGC,UAAA;EACV,OAAA;EACA,KAAA,EAAO,QAAA;EACP,IAAA;EACA,MAAA;EACA,MAAA;EACA,KAAA;EACA,OAAA,GAAU,MAAM;EAChB,SAAA;AAAA;AAAA,UAGe,WAAA;EAgCf;;;EA5BA,IAAA;EA+BU;;;EA1BV,WAAA;EA0B+C;;;EArB/C,QAAA;;;;EAKA,GAAA,CAAI,IAAA,EAAM,WAAA,UAAqB,OAAO;;;;EAKtC,SAAA;AAAA;AAAA,KAGU,WAAA;EACV,IAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA;EACA,OAAA,GAAU,MAAM;AAAA;AAAA,KAGN,kBAAA,GAAqB,IAAI,CAAC,WAAA"}
@@ -0,0 +1,16 @@
1
+ //#region ../../@warlock.js/logger/src/utils/capture-unhandled-errors.d.ts
2
+ /**
3
+ * Route Node's process-level failure events through the logger so they land in
4
+ * every configured channel with full stack context. Registers one listener for
5
+ * `unhandledRejection` and one for `uncaughtException`; call once at startup
6
+ * after channels are configured. Pair with `autoFlushOn: ["beforeExit"]` so the
7
+ * final entry survives the process exit that follows an uncaught exception.
8
+ *
9
+ * @example
10
+ * log.configure({ channels: [new ConsoleLog(), new FileLog()] });
11
+ * captureAnyUnhandledRejection();
12
+ */
13
+ declare function captureAnyUnhandledRejection(): void;
14
+ //#endregion
15
+ export { captureAnyUnhandledRejection };
16
+ //# sourceMappingURL=capture-unhandled-errors.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-unhandled-errors.d.mts","names":[],"sources":["../../../../../../@warlock.js/logger/src/utils/capture-unhandled-errors.ts"],"mappings":";;AAaA;;;;AAA4C;;;;;;iBAA5B,4BAAA,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { log } from "../logger.mjs";
2
+
3
+ //#region ../../@warlock.js/logger/src/utils/capture-unhandled-errors.ts
4
+ /**
5
+ * Route Node's process-level failure events through the logger so they land in
6
+ * every configured channel with full stack context. Registers one listener for
7
+ * `unhandledRejection` and one for `uncaughtException`; call once at startup
8
+ * after channels are configured. Pair with `autoFlushOn: ["beforeExit"]` so the
9
+ * final entry survives the process exit that follows an uncaught exception.
10
+ *
11
+ * @example
12
+ * log.configure({ channels: [new ConsoleLog(), new FileLog()] });
13
+ * captureAnyUnhandledRejection();
14
+ */
15
+ function captureAnyUnhandledRejection() {
16
+ process.on("unhandledRejection", (reason) => {
17
+ log.error("app", "unhandledRejection", reason);
18
+ });
19
+ process.on("uncaughtException", (error) => {
20
+ log.error("app", "uncaughtException", error);
21
+ });
22
+ }
23
+
24
+ //#endregion
25
+ export { captureAnyUnhandledRejection };
26
+ //# sourceMappingURL=capture-unhandled-errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-unhandled-errors.mjs","names":[],"sources":["../../../../../../@warlock.js/logger/src/utils/capture-unhandled-errors.ts"],"sourcesContent":["import { log } from \"../logger\";\r\n\r\n/**\r\n * Route Node's process-level failure events through the logger so they land in\r\n * every configured channel with full stack context. Registers one listener for\r\n * `unhandledRejection` and one for `uncaughtException`; call once at startup\r\n * after channels are configured. Pair with `autoFlushOn: [\"beforeExit\"]` so the\r\n * final entry survives the process exit that follows an uncaught exception.\r\n *\r\n * @example\r\n * log.configure({ channels: [new ConsoleLog(), new FileLog()] });\r\n * captureAnyUnhandledRejection();\r\n */\r\nexport function captureAnyUnhandledRejection() {\r\n process.on(\"unhandledRejection\", (reason: any) => {\r\n log.error(\"app\", \"unhandledRejection\", reason);\r\n });\r\n\r\n process.on(\"uncaughtException\", (error) => {\r\n log.error(\"app\", \"uncaughtException\", error);\r\n });\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,+BAA+B;CAC7C,QAAQ,GAAG,uBAAuB,WAAgB;EAChD,IAAI,MAAM,OAAO,sBAAsB,MAAM;CAC/C,CAAC;CAED,QAAQ,GAAG,sBAAsB,UAAU;EACzC,IAAI,MAAM,OAAO,qBAAqB,KAAK;CAC7C,CAAC;AACH"}
@@ -0,0 +1,8 @@
1
+ //#region ../../@warlock.js/logger/src/utils/clear-message.d.ts
2
+ /**
3
+ * Clear message from any terminal codes
4
+ */
5
+ declare function clearMessage(message: any): any;
6
+ //#endregion
7
+ export { clearMessage };
8
+ //# sourceMappingURL=clear-message.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear-message.d.mts","names":[],"sources":["../../../../../../@warlock.js/logger/src/utils/clear-message.ts"],"mappings":";;AAGA;;iBAAgB,YAAA,CAAa,OAAY"}
@@ -0,0 +1,12 @@
1
+ //#region ../../@warlock.js/logger/src/utils/clear-message.ts
2
+ /**
3
+ * Clear message from any terminal codes
4
+ */
5
+ function clearMessage(message) {
6
+ if (typeof message !== "string") return message;
7
+ return message.replace(/\u001b[^m]*?m/g, "");
8
+ }
9
+
10
+ //#endregion
11
+ export { clearMessage };
12
+ //# sourceMappingURL=clear-message.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear-message.mjs","names":[],"sources":["../../../../../../@warlock.js/logger/src/utils/clear-message.ts"],"sourcesContent":["/**\r\n * Clear message from any terminal codes\r\n */\r\nexport function clearMessage(message: any) {\r\n if (typeof message !== \"string\") return message;\r\n\r\n // eslint-disable-next-line no-control-regex\r\n return message.replace(/\\u001b[^m]*?m/g, \"\");\r\n}\r\n"],"mappings":";;;;AAGA,SAAgB,aAAa,SAAc;CACzC,IAAI,OAAO,YAAY,UAAU,OAAO;CAGxC,OAAO,QAAQ,QAAQ,kBAAkB,EAAE;AAC7C"}
@@ -0,0 +1,5 @@
1
+ import { safeJsonStringify } from "./safe-json-stringify.mjs";
2
+ import { clearMessage } from "./clear-message.mjs";
3
+ import { captureAnyUnhandledRejection } from "./capture-unhandled-errors.mjs";
4
+
5
+ export { };
@@ -0,0 +1,14 @@
1
+ //#region ../../@warlock.js/logger/src/utils/safe-json-stringify.d.ts
2
+ /**
3
+ * JSON-serialize log payloads safely. Circular refs, BigInt, and repeated
4
+ * non-tree references are handled by `safe-stable-stringify`; functions and
5
+ * symbols are dropped (standard JSON behavior); Errors are expanded via
6
+ * `errorReplacer`. Class instances serialize as their enumerable props.
7
+ *
8
+ * @example
9
+ * await fs.promises.writeFile(filePath, safeJsonStringify(payload, 2));
10
+ */
11
+ declare function safeJsonStringify(value: unknown, space?: number): string;
12
+ //#endregion
13
+ export { safeJsonStringify };
14
+ //# sourceMappingURL=safe-json-stringify.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-json-stringify.d.mts","names":[],"sources":["../../../../../../@warlock.js/logger/src/utils/safe-json-stringify.ts"],"mappings":";;AAyCA;;;;AAAgE;;;;iBAAhD,iBAAA,CAAkB,KAAA,WAAgB,KAAc"}
@@ -0,0 +1,35 @@
1
+ import { stringify } from "safe-stable-stringify";
2
+
3
+ //#region ../../@warlock.js/logger/src/utils/safe-json-stringify.ts
4
+ /**
5
+ * Replacer that surfaces Error data — `name`, `message`, and `stack` are
6
+ * non-enumerable on `Error`, so neither default JSON serialization nor an
7
+ * object spread captures them (both produce `{}`). They are copied explicitly;
8
+ * the trailing spread then captures any additional enumerable props the caller
9
+ * (or a subclass) attached, such as a `code` field.
10
+ */
11
+ function errorReplacer(_key, value) {
12
+ if (value instanceof Error) return {
13
+ ...value,
14
+ name: value.name,
15
+ message: value.message,
16
+ stack: value.stack
17
+ };
18
+ return value;
19
+ }
20
+ /**
21
+ * JSON-serialize log payloads safely. Circular refs, BigInt, and repeated
22
+ * non-tree references are handled by `safe-stable-stringify`; functions and
23
+ * symbols are dropped (standard JSON behavior); Errors are expanded via
24
+ * `errorReplacer`. Class instances serialize as their enumerable props.
25
+ *
26
+ * @example
27
+ * await fs.promises.writeFile(filePath, safeJsonStringify(payload, 2));
28
+ */
29
+ function safeJsonStringify(value, space) {
30
+ return stringify(value, errorReplacer, space) ?? "";
31
+ }
32
+
33
+ //#endregion
34
+ export { safeJsonStringify };
35
+ //# sourceMappingURL=safe-json-stringify.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-json-stringify.mjs","names":["safeStableStringify"],"sources":["../../../../../../@warlock.js/logger/src/utils/safe-json-stringify.ts"],"sourcesContent":["import { stringify as safeStableStringify } from \"safe-stable-stringify\";\n\n/**\n * Replacer that surfaces Error data — `name`, `message`, and `stack` are\n * non-enumerable on `Error`, so neither default JSON serialization nor an\n * object spread captures them (both produce `{}`). They are copied explicitly;\n * the trailing spread then captures any additional enumerable props the caller\n * (or a subclass) attached, such as a `code` field.\n */\nfunction errorReplacer<Value = unknown>(\n _key: string,\n value: Value,\n): Record<string, unknown> | Value {\n if (value instanceof Error) {\n // Spread first, then the explicit Error fields. `name`/`message`/`stack`\n // are non-enumerable on `Error`, so the spread never carries them — the\n // explicit assignments are what surface them. Placing the spread first\n // means those explicit keys legitimately take precedence over any\n // identically-named *enumerable* prop a subclass attached (resolving the\n // duplicate-key warning). Because `safe-stable-stringify` sorts keys, the\n // insertion order here does not affect the serialized bytes.\n return {\n ...value,\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n\n return value;\n}\n\n/**\n * JSON-serialize log payloads safely. Circular refs, BigInt, and repeated\n * non-tree references are handled by `safe-stable-stringify`; functions and\n * symbols are dropped (standard JSON behavior); Errors are expanded via\n * `errorReplacer`. Class instances serialize as their enumerable props.\n *\n * @example\n * await fs.promises.writeFile(filePath, safeJsonStringify(payload, 2));\n */\nexport function safeJsonStringify(value: unknown, space?: number): string {\n return safeStableStringify(value, errorReplacer, space) ?? \"\";\n}\n"],"mappings":";;;;;;;;;;AASA,SAAS,cACP,MACA,OACiC;CACjC,IAAI,iBAAiB,OAQnB,OAAO;EACL,GAAG;EACH,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,OAAO,MAAM;CACf;CAGF,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,kBAAkB,OAAgB,OAAwB;CACxE,OAAOA,UAAoB,OAAO,eAAe,KAAK,KAAK;AAC7D"}