@warlock.js/logger 4.0.171 → 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,75 @@
1
+ //#region ../../@warlock.js/logger/src/log-channel.ts
2
+ var LogChannel = class {
3
+ /**
4
+ * Constructor
5
+ */
6
+ constructor(configurations) {
7
+ this.terminal = false;
8
+ this.defaultConfigurations = {};
9
+ this.channelConfigurations = {};
10
+ this.isInitialized = false;
11
+ if (configurations) this.setConfigurations(configurations);
12
+ setTimeout(async () => {
13
+ if (this.init) await this.init();
14
+ this.isInitialized = true;
15
+ }, 0);
16
+ }
17
+ /**
18
+ * Get config value
19
+ */
20
+ config(key) {
21
+ return this.channelConfigurations[key] ?? (this.defaultConfigurations ?? {})[key];
22
+ }
23
+ /**
24
+ * Set configurations
25
+ */
26
+ setConfigurations(configurations) {
27
+ this.channelConfigurations = {
28
+ ...this.channelConfigurations,
29
+ ...configurations
30
+ };
31
+ return this;
32
+ }
33
+ /**
34
+ * Determine if the message should be logged
35
+ */
36
+ shouldBeLogged(data) {
37
+ const allowedLevels = this.config("levels");
38
+ if (allowedLevels?.length && !allowedLevels.includes(data.type)) return false;
39
+ const filter = this.config("filter");
40
+ if (filter) return filter(data);
41
+ return true;
42
+ }
43
+ /**
44
+ * Read the channel's redact config (if any). Used by `Logger` to apply
45
+ * per-channel additive redaction on top of the logger-wide floor.
46
+ * Subclasses normally don't override this — set `redact` in your channel
47
+ * configuration instead.
48
+ */
49
+ getRedactConfig() {
50
+ return this.config("redact");
51
+ }
52
+ /**
53
+ * Get date and time formats
54
+ */
55
+ getDateAndTimeFormat() {
56
+ const dateFormat = this.config("dateFormat");
57
+ return {
58
+ date: dateFormat?.date ?? "DD-MM-YYYY",
59
+ time: dateFormat?.time ?? "HH:mm:ss"
60
+ };
61
+ }
62
+ /**
63
+ * get basic configurations with the given ones
64
+ */
65
+ withBasicConfigurations(configurations) {
66
+ return {
67
+ filter: () => true,
68
+ ...configurations
69
+ };
70
+ }
71
+ };
72
+
73
+ //#endregion
74
+ export { LogChannel };
75
+ //# sourceMappingURL=log-channel.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-channel.mjs","names":[],"sources":["../../../../../@warlock.js/logger/src/log-channel.ts"],"sourcesContent":["import type {\r\n BasicLogConfigurations,\r\n LogContract,\r\n LoggingData,\r\n RedactConfig,\r\n} from \"./types\";\r\n\r\nexport abstract class LogChannel<\r\n Options extends BasicLogConfigurations = BasicLogConfigurations,\r\n> implements LogContract\r\n{\r\n /**\r\n * Channel name\r\n */\r\n public name!: string;\r\n\r\n /**\r\n * Channel description\r\n */\r\n public description?: string;\r\n\r\n /**\r\n * Determine if channel is logging in terminal\r\n */\r\n public terminal = false;\r\n\r\n /**\r\n * Default Configurations\r\n */\r\n protected defaultConfigurations: Options = {} as Options;\r\n\r\n /**\r\n * Channel configurations\r\n */\r\n protected channelConfigurations: Options = {} as Options; //\r\n\r\n /**\r\n * Determine whether the channel is fully initialized\r\n */\r\n protected isInitialized = false;\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor(configurations?: Options) {\r\n if (configurations) {\r\n this.setConfigurations(configurations);\r\n }\r\n\r\n setTimeout(async () => {\r\n if (this.init) {\r\n await this.init();\r\n }\r\n\r\n this.isInitialized = true;\r\n }, 0);\r\n }\r\n\r\n /**\r\n * Initialize the channel\r\n */\r\n protected init?(): void | Promise<void>;\r\n\r\n /**\r\n * Get config value\r\n */\r\n protected config<K extends keyof Options>(key: K): Options[K] {\r\n return (\r\n this.channelConfigurations[key] ?? (this.defaultConfigurations ?? {})[key]\r\n );\r\n }\r\n\r\n /**\r\n * Set configurations\r\n */\r\n protected setConfigurations(configurations: Options) {\r\n this.channelConfigurations = {\r\n ...this.channelConfigurations,\r\n ...configurations,\r\n };\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Determine if the message should be logged\r\n */\r\n protected shouldBeLogged(data: LoggingData): boolean {\r\n // check for debug mode\r\n const allowedLevels = this.config(\"levels\");\r\n\r\n if (allowedLevels?.length && !allowedLevels.includes(data.type))\r\n return false;\r\n\r\n const filter = this.config(\"filter\");\r\n\r\n if (filter) {\r\n return filter(data);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Log the given message\r\n */\r\n public abstract log(data: LoggingData): void | Promise<void>;\r\n\r\n /**\r\n * Synchronously flush messages\r\n */\r\n public flushSync?(): void;\r\n\r\n /**\r\n * Read the channel's redact config (if any). Used by `Logger` to apply\r\n * per-channel additive redaction on top of the logger-wide floor.\r\n * Subclasses normally don't override this — set `redact` in your channel\r\n * configuration instead.\r\n */\r\n public getRedactConfig(): RedactConfig | undefined {\r\n return this.config(\"redact\" as keyof Options) as\r\n | RedactConfig\r\n | undefined;\r\n }\r\n\r\n /**\r\n * Get date and time formats\r\n */\r\n protected getDateAndTimeFormat() {\r\n const dateFormat = this.config(\"dateFormat\");\r\n const date = dateFormat?.date ?? \"DD-MM-YYYY\";\r\n const time = dateFormat?.time ?? \"HH:mm:ss\";\r\n\r\n return { date, time };\r\n }\r\n\r\n /**\r\n * get basic configurations with the given ones\r\n */\r\n protected withBasicConfigurations(configurations: Partial<Options>): Options {\r\n return {\r\n filter: () => true,\r\n ...configurations,\r\n } as any as Options;\r\n }\r\n}\r\n"],"mappings":";AAOA,IAAsB,aAAtB,MAGA;;;;CAkCE,AAAO,YAAY,gBAA0B;kBApB3B;+BAKyB,CAAC;+BAKD,CAAC;uBAKlB;EAMxB,IAAI,gBACF,KAAK,kBAAkB,cAAc;EAGvC,WAAW,YAAY;GACrB,IAAI,KAAK,MACP,MAAM,KAAK,KAAK;GAGlB,KAAK,gBAAgB;EACvB,GAAG,CAAC;CACN;;;;CAUA,AAAU,OAAgC,KAAoB;EAC5D,OACE,KAAK,sBAAsB,SAAS,KAAK,yBAAyB,CAAC,GAAG;CAE1E;;;;CAKA,AAAU,kBAAkB,gBAAyB;EACnD,KAAK,wBAAwB;GAC3B,GAAG,KAAK;GACR,GAAG;EACL;EAEA,OAAO;CACT;;;;CAKA,AAAU,eAAe,MAA4B;EAEnD,MAAM,gBAAgB,KAAK,OAAO,QAAQ;EAE1C,IAAI,eAAe,UAAU,CAAC,cAAc,SAAS,KAAK,IAAI,GAC5D,OAAO;EAET,MAAM,SAAS,KAAK,OAAO,QAAQ;EAEnC,IAAI,QACF,OAAO,OAAO,IAAI;EAGpB,OAAO;CACT;;;;;;;CAkBA,AAAO,kBAA4C;EACjD,OAAO,KAAK,OAAO,QAAyB;CAG9C;;;;CAKA,AAAU,uBAAuB;EAC/B,MAAM,aAAa,KAAK,OAAO,YAAY;EAI3C,OAAO;GAAE,MAHI,YAAY,QAAQ;GAGlB,MAFF,YAAY,QAAQ;EAEb;CACtB;;;;CAKA,AAAU,wBAAwB,gBAA2C;EAC3E,OAAO;GACL,cAAc;GACd,GAAG;EACL;CACF;AACF"}
@@ -0,0 +1,184 @@
1
+ import { AutoFlushEvent, BasicLogConfigurations, LogLevel, LoggingData, OmittedLoggingData, RedactConfig } from "./types.mjs";
2
+ import { LogChannel } from "./log-channel.mjs";
3
+
4
+ //#region ../../@warlock.js/logger/src/logger.d.ts
5
+ declare class Logger {
6
+ /**
7
+ * Current channel
8
+ */
9
+ channels: LogChannel[];
10
+ id: string;
11
+ /**
12
+ * Registered auto-flush handlers, keyed by event name. Stored so repeated
13
+ * calls to `enableAutoFlush` replace rather than stack, and so
14
+ * `disableAutoFlush` can remove them cleanly.
15
+ */
16
+ private autoFlushHandlers;
17
+ /**
18
+ * Logger-wide minimum severity. When set, entries below this level are
19
+ * dropped before any channel is invoked — cheaper than per-channel `levels`
20
+ * filters because the fan-out loop is skipped entirely. `undefined` means
21
+ * no minimum (every entry reaches every channel that accepts it).
22
+ */
23
+ private minLevel?;
24
+ /**
25
+ * Logger-wide redaction floor. Applied once before fan-out — every
26
+ * channel receives an entry with these paths already censored. Channel
27
+ * configs can extend the path list (additive); they cannot remove paths
28
+ * set here.
29
+ */
30
+ private redactConfig?;
31
+ /**
32
+ * Add a new channel
33
+ */
34
+ addChannel(channel: LogChannel): this;
35
+ /**
36
+ * Set base configurations
37
+ */
38
+ configure(config: {
39
+ channels?: LogChannel[];
40
+ autoFlushOn?: AutoFlushEvent[];
41
+ minLevel?: LogLevel;
42
+ redact?: RedactConfig;
43
+ }): this;
44
+ /**
45
+ * Set the logger-wide redaction floor. Applied to every entry before
46
+ * fan-out; channel configs add more paths on top, never fewer. Pass
47
+ * `undefined` to clear.
48
+ *
49
+ * @example
50
+ * log.setRedact({
51
+ * paths: ["context.password", "context.*.token"],
52
+ * censor: "[REDACTED]",
53
+ * });
54
+ */
55
+ setRedact(config: RedactConfig | undefined): this;
56
+ /**
57
+ * Read the active logger-wide redact config (or `undefined`).
58
+ */
59
+ getRedact(): RedactConfig | undefined;
60
+ /**
61
+ * Drop every entry whose severity is below `level` before fan-out. Cheaper
62
+ * than per-channel `levels` filters because the loop never runs and no
63
+ * channel receives the entry. Pass `undefined` to clear and accept all
64
+ * levels again.
65
+ *
66
+ * @example
67
+ * // production: silence debug noise everywhere at once
68
+ * logger.setMinLevel("info");
69
+ */
70
+ setMinLevel(level: LogLevel | undefined): this;
71
+ /**
72
+ * Read the active minimum severity (or `undefined` when none is set).
73
+ */
74
+ getMinLevel(): LogLevel | undefined;
75
+ /**
76
+ * Set channels
77
+ */
78
+ setChannels(channels: LogChannel[]): this;
79
+ /**
80
+ * Normalize log data to a single object
81
+ */
82
+ private normalizeLogData;
83
+ /**
84
+ * Make log
85
+ *
86
+ * Fans out a single log entry to every registered channel. Non-terminal
87
+ * channels receive a copy whose `message` has had ANSI color codes stripped
88
+ * — each channel sees its own shallow clone so one channel cannot observe
89
+ * another's mutations (e.g. a later terminal channel still sees the original
90
+ * colored message).
91
+ */
92
+ log(data: LoggingData): Promise<this>;
93
+ /**
94
+ * Make debug log
95
+ */
96
+ debug(dataOrModule: OmittedLoggingData | string, action?: string, message?: any, context?: Record<string, any>): Promise<this>;
97
+ /**
98
+ * Make info log
99
+ */
100
+ info(dataOrModule: OmittedLoggingData | string, action?: string, message?: any, context?: Record<string, any>): Promise<this>;
101
+ /**
102
+ * Make warn log
103
+ */
104
+ warn(dataOrModule: OmittedLoggingData | string, action?: string, message?: any, context?: Record<string, any>): Promise<this>;
105
+ /**
106
+ * Make error log
107
+ */
108
+ error(dataOrModule: OmittedLoggingData | string, action?: string, message?: any, context?: Record<string, any>): Promise<this>;
109
+ /**
110
+ * Make success log
111
+ */
112
+ success(dataOrModule: OmittedLoggingData | string, action?: string, message?: any, context?: Record<string, any>): Promise<this>;
113
+ /**
114
+ * Log an `error` entry when `condition` is falsy. No-op otherwise — the
115
+ * entry is never built and channels are not invoked, so this is genuinely
116
+ * free in the happy path. Mirrors the spirit of `console.assert` but routes
117
+ * through the logger pipeline so persistent channels capture failures.
118
+ *
119
+ * @example
120
+ * log.assert(user !== null, "auth", "session", "user vanished mid-flight", { sessionId });
121
+ */
122
+ assert(condition: unknown, module: string, action: string, message: any, context?: Record<string, any>): Promise<Logger> | Logger;
123
+ /**
124
+ * Start a duration timer. The returned function emits an `info` entry
125
+ * with `completed in <ms>ms` and a `durationMs` field in `context` when
126
+ * called. Pass an object to `end()` to merge extra fields into context.
127
+ *
128
+ * @example
129
+ * const end = log.timer("db", "users.findById");
130
+ * const user = await usersRepo.findById(id);
131
+ * end({ id, found: !!user });
132
+ */
133
+ timer(module: string, action: string): (extra?: Record<string, any>) => Promise<Logger>;
134
+ /**
135
+ * Get channel by name
136
+ */
137
+ channel(name: string): LogChannel<BasicLogConfigurations> | undefined;
138
+ /**
139
+ * Synchronously flush logs
140
+ */
141
+ flushSync(): void;
142
+ /**
143
+ * Register one process-level handler per event that calls `flushSync()`
144
+ * before the process terminates.
145
+ *
146
+ * For signal events (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGBREAK`, `SIGUSR2`)
147
+ * the handler flushes and then re-raises the signal so Node's default exit
148
+ * behavior runs. For `beforeExit`, the handler flushes in place — Node exits
149
+ * naturally afterwards.
150
+ *
151
+ * Idempotent: calling with the same events replaces the previous handlers.
152
+ * Call `disableAutoFlush()` to unregister.
153
+ *
154
+ * @example
155
+ * log.configure({
156
+ * channels: [new ConsoleLog(), new FileLog()],
157
+ * autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
158
+ * });
159
+ */
160
+ enableAutoFlush(events: AutoFlushEvent[]): this;
161
+ /**
162
+ * Remove every handler previously registered by `enableAutoFlush`.
163
+ * Safe to call when no handlers are registered.
164
+ */
165
+ disableAutoFlush(): this;
166
+ }
167
+ /**
168
+ * The package singleton. Use this for everyday logging — `log.info(...)`,
169
+ * `log.error(...)`, `log.configure(...)`. Custom logger instances can be
170
+ * created by instantiating `Logger` directly.
171
+ *
172
+ * The name is intentionally short: `log` reads naturally at the call site
173
+ * (`log.info("auth", "login", "ok")`) and matches the convention used in
174
+ * pino, bunyan, and most JS logging tutorials.
175
+ *
176
+ * Note that `log` is a `Logger` instance, **not** a function — the bare
177
+ * callable form was removed when the dual `log` / `logger` exports were
178
+ * collapsed into a single name. Use `log.info(...)` (or any other level
179
+ * shortcut) to emit entries.
180
+ */
181
+ declare const log: Logger;
182
+ //#endregion
183
+ export { Logger, log };
184
+ //# sourceMappingURL=logger.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.mts","names":[],"sources":["../../../../../@warlock.js/logger/src/logger.ts"],"mappings":";;;;cAmCa,MAAA;;AAAb;;EAIS,QAAA,EAAU,UAAA;EAEV,EAAA;EA4BoB;;;;;EAAA,QArBnB,iBAAA;EA0EY;;;;;;EAAA,QAlEZ,QAAA;EAkLI;;;;;;EAAA,QA1KJ,YAAA;EAoMuB;;;EA/LxB,UAAA,CAAW,OAAA,EAAS,UAAA;EAsNX;;;EA7MT,SAAA,CAAU,MAAA;IACf,QAAA,GAAW,UAAA;IACX,WAAA,GAAc,cAAA;IACd,QAAA,GAAW,QAAA;IACX,MAAA,GAAS,YAAA;EAAA;EAoPyB;;;;;;;;;;;EApN7B,SAAA,CAAU,MAAA,EAAQ,YAAA;EA7ClB;;;EAqDA,SAAA,CAAA,GAAa,YAAA;EA3ClB;;;;;;;;;;EAyDK,WAAA,CAAY,KAAA,EAAO,QAAA;EAtBT;;;EA8BV,WAAA,CAAA,GAAe,QAAA;EARI;;;EAenB,WAAA,CAAY,QAAA,EAAU,UAAA;EAAtB;;;EAAA,QASC,gBAAA;EAmCK;;;;;;;;;EAAA,GAAA,CAAI,IAAA,EAAM,WAAA,GAAW,OAAA;EAuChC;;;EAJK,KAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA,gBAAmB,OAAA;EAU7B;;;EADK,IAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA,gBAAmB,OAAA;EAA7B;;;EASK,IAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA,gBAAmB,OAAA;EAH7B;;;EAYK,KAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA,gBAAmB,OAAA;EAb7B;;;EAsBK,OAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA,gBAAmB,OAAA;EAhB7B;;;;;;;;;EAgCK,MAAA,CACL,SAAA,WACA,MAAA,UACA,MAAA,UACA,OAAA,OACA,OAAA,GAAU,MAAA,gBACT,OAAA,CAAQ,MAAA,IAAU,MAAA;EAvBnB;;;;;;;;;;EAsCK,KAAA,CACL,MAAA,UACA,MAAA,YACE,KAAA,GAAQ,MAAA,kBAAwB,OAAA,CAAQ,MAAA;EAlBzC;;;EAgCI,OAAA,CAAQ,IAAA,WAAY,UAAA,CAdgB,sBAAA;EAFzC;;;EAuBK,SAAA,CAAA;EArB6B;;;;;;;;;;;;AAwEb;AAyBzB;;;;AAA+B;EAlDtB,eAAA,CAAgB,MAAA,EAAQ,cAAA;;;;;EAyBxB,gBAAA,CAAA;AAAA;;;;;;;;;;;;;;;cAyBI,GAAA,EAAG,MAAe"}
package/esm/logger.mjs ADDED
@@ -0,0 +1,282 @@
1
+ import { applyRedact, mergeRedact } from "./redact/redact.mjs";
2
+ import { clearMessage } from "./utils/clear-message.mjs";
3
+ import { Random } from "@mongez/reinforcements";
4
+
5
+ //#region ../../@warlock.js/logger/src/logger.ts
6
+ const SIGNAL_EVENTS = new Set([
7
+ "SIGINT",
8
+ "SIGTERM",
9
+ "SIGHUP",
10
+ "SIGBREAK",
11
+ "SIGUSR2"
12
+ ]);
13
+ /**
14
+ * Severity ranks used by `setMinLevel`. Higher number = more severe. The
15
+ * ordering matches conventional log-level hierarchies: `debug` is noisiest
16
+ * and easiest to drop; `error` is the loudest and never dropped by the
17
+ * minimum-level filter. `success` sits beside `info` — it's an informational
18
+ * outcome, not a warning.
19
+ */
20
+ const LEVEL_RANK = {
21
+ debug: 0,
22
+ info: 1,
23
+ success: 1,
24
+ warn: 2,
25
+ error: 3
26
+ };
27
+ var Logger = class {
28
+ constructor() {
29
+ this.channels = [];
30
+ this.id = "logger-" + Random.string(32);
31
+ this.autoFlushHandlers = /* @__PURE__ */ new Map();
32
+ }
33
+ /**
34
+ * Add a new channel
35
+ */
36
+ addChannel(channel) {
37
+ this.channels.push(channel);
38
+ return this;
39
+ }
40
+ /**
41
+ * Set base configurations
42
+ */
43
+ configure(config) {
44
+ if (config.channels) this.channels = config.channels;
45
+ if (config.autoFlushOn) this.enableAutoFlush(config.autoFlushOn);
46
+ if (config.minLevel !== void 0) this.setMinLevel(config.minLevel);
47
+ if (config.redact !== void 0) this.setRedact(config.redact);
48
+ return this;
49
+ }
50
+ /**
51
+ * Set the logger-wide redaction floor. Applied to every entry before
52
+ * fan-out; channel configs add more paths on top, never fewer. Pass
53
+ * `undefined` to clear.
54
+ *
55
+ * @example
56
+ * log.setRedact({
57
+ * paths: ["context.password", "context.*.token"],
58
+ * censor: "[REDACTED]",
59
+ * });
60
+ */
61
+ setRedact(config) {
62
+ this.redactConfig = config;
63
+ return this;
64
+ }
65
+ /**
66
+ * Read the active logger-wide redact config (or `undefined`).
67
+ */
68
+ getRedact() {
69
+ return this.redactConfig;
70
+ }
71
+ /**
72
+ * Drop every entry whose severity is below `level` before fan-out. Cheaper
73
+ * than per-channel `levels` filters because the loop never runs and no
74
+ * channel receives the entry. Pass `undefined` to clear and accept all
75
+ * levels again.
76
+ *
77
+ * @example
78
+ * // production: silence debug noise everywhere at once
79
+ * logger.setMinLevel("info");
80
+ */
81
+ setMinLevel(level) {
82
+ this.minLevel = level;
83
+ return this;
84
+ }
85
+ /**
86
+ * Read the active minimum severity (or `undefined` when none is set).
87
+ */
88
+ getMinLevel() {
89
+ return this.minLevel;
90
+ }
91
+ /**
92
+ * Set channels
93
+ */
94
+ setChannels(channels) {
95
+ this.channels = channels;
96
+ return this;
97
+ }
98
+ /**
99
+ * Normalize log data to a single object
100
+ */
101
+ normalizeLogData(dataOrModule, action, message = "", level, context) {
102
+ if (typeof dataOrModule === "object") return {
103
+ type: level || dataOrModule.type || "info",
104
+ module: dataOrModule.module,
105
+ action: dataOrModule.action,
106
+ message: dataOrModule.message,
107
+ ...context ? { context } : dataOrModule.context ? { context: dataOrModule.context } : {}
108
+ };
109
+ return {
110
+ type: level || "info",
111
+ module: dataOrModule,
112
+ action,
113
+ message,
114
+ ...context ? { context } : {}
115
+ };
116
+ }
117
+ /**
118
+ * Make log
119
+ *
120
+ * Fans out a single log entry to every registered channel. Non-terminal
121
+ * channels receive a copy whose `message` has had ANSI color codes stripped
122
+ * — each channel sees its own shallow clone so one channel cannot observe
123
+ * another's mutations (e.g. a later terminal channel still sees the original
124
+ * colored message).
125
+ */
126
+ async log(data) {
127
+ if (this.minLevel && LEVEL_RANK[data.type] < LEVEL_RANK[this.minLevel]) return this;
128
+ const baseEntry = applyRedact(data, this.redactConfig);
129
+ for (const channel of this.channels) {
130
+ const channelRedact = channel.getRedactConfig?.();
131
+ const effectiveRedact = channelRedact ? mergeRedact(this.redactConfig, channelRedact) : void 0;
132
+ let payload = effectiveRedact ? applyRedact(data, effectiveRedact) : baseEntry;
133
+ if (channel.terminal === false) payload = {
134
+ ...payload,
135
+ message: clearMessage(payload.message)
136
+ };
137
+ channel.log(payload);
138
+ }
139
+ return this;
140
+ }
141
+ /**
142
+ * Make debug log
143
+ */
144
+ debug(dataOrModule, action, message = "", context) {
145
+ const data = this.normalizeLogData(dataOrModule, action, message, "debug", context);
146
+ return this.log(data);
147
+ }
148
+ /**
149
+ * Make info log
150
+ */
151
+ info(dataOrModule, action, message = "", context) {
152
+ const data = this.normalizeLogData(dataOrModule, action, message, "info", context);
153
+ return this.log(data);
154
+ }
155
+ /**
156
+ * Make warn log
157
+ */
158
+ warn(dataOrModule, action, message = "", context) {
159
+ const data = this.normalizeLogData(dataOrModule, action, message, "warn", context);
160
+ return this.log(data);
161
+ }
162
+ /**
163
+ * Make error log
164
+ */
165
+ error(dataOrModule, action, message = "", context) {
166
+ const data = this.normalizeLogData(dataOrModule, action, message, "error", context);
167
+ return this.log(data);
168
+ }
169
+ /**
170
+ * Make success log
171
+ */
172
+ success(dataOrModule, action, message = "", context) {
173
+ const data = this.normalizeLogData(dataOrModule, action, message, "success", context);
174
+ return this.log(data);
175
+ }
176
+ /**
177
+ * Log an `error` entry when `condition` is falsy. No-op otherwise — the
178
+ * entry is never built and channels are not invoked, so this is genuinely
179
+ * free in the happy path. Mirrors the spirit of `console.assert` but routes
180
+ * through the logger pipeline so persistent channels capture failures.
181
+ *
182
+ * @example
183
+ * log.assert(user !== null, "auth", "session", "user vanished mid-flight", { sessionId });
184
+ */
185
+ assert(condition, module, action, message, context) {
186
+ if (condition) return this;
187
+ return this.error(module, action, message, context);
188
+ }
189
+ /**
190
+ * Start a duration timer. The returned function emits an `info` entry
191
+ * with `completed in <ms>ms` and a `durationMs` field in `context` when
192
+ * called. Pass an object to `end()` to merge extra fields into context.
193
+ *
194
+ * @example
195
+ * const end = log.timer("db", "users.findById");
196
+ * const user = await usersRepo.findById(id);
197
+ * end({ id, found: !!user });
198
+ */
199
+ timer(module, action) {
200
+ const startedAt = Date.now();
201
+ return (extra) => {
202
+ const durationMs = Date.now() - startedAt;
203
+ return this.info(module, action, `completed in ${durationMs}ms`, {
204
+ durationMs,
205
+ ...extra ?? {}
206
+ });
207
+ };
208
+ }
209
+ /**
210
+ * Get channel by name
211
+ */
212
+ channel(name) {
213
+ return this.channels.find((channel) => channel.name === name);
214
+ }
215
+ /**
216
+ * Synchronously flush logs
217
+ */
218
+ flushSync() {
219
+ for (const channel of this.channels) if (channel.flushSync) channel.flushSync();
220
+ }
221
+ /**
222
+ * Register one process-level handler per event that calls `flushSync()`
223
+ * before the process terminates.
224
+ *
225
+ * For signal events (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGBREAK`, `SIGUSR2`)
226
+ * the handler flushes and then re-raises the signal so Node's default exit
227
+ * behavior runs. For `beforeExit`, the handler flushes in place — Node exits
228
+ * naturally afterwards.
229
+ *
230
+ * Idempotent: calling with the same events replaces the previous handlers.
231
+ * Call `disableAutoFlush()` to unregister.
232
+ *
233
+ * @example
234
+ * log.configure({
235
+ * channels: [new ConsoleLog(), new FileLog()],
236
+ * autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
237
+ * });
238
+ */
239
+ enableAutoFlush(events) {
240
+ this.disableAutoFlush();
241
+ for (const event of events) {
242
+ const handler = SIGNAL_EVENTS.has(event) ? () => {
243
+ this.flushSync();
244
+ process.off(event, handler);
245
+ process.kill(process.pid, event);
246
+ } : () => {
247
+ this.flushSync();
248
+ };
249
+ process.on(event, handler);
250
+ this.autoFlushHandlers.set(event, handler);
251
+ }
252
+ return this;
253
+ }
254
+ /**
255
+ * Remove every handler previously registered by `enableAutoFlush`.
256
+ * Safe to call when no handlers are registered.
257
+ */
258
+ disableAutoFlush() {
259
+ for (const [event, handler] of this.autoFlushHandlers) process.off(event, handler);
260
+ this.autoFlushHandlers.clear();
261
+ return this;
262
+ }
263
+ };
264
+ /**
265
+ * The package singleton. Use this for everyday logging — `log.info(...)`,
266
+ * `log.error(...)`, `log.configure(...)`. Custom logger instances can be
267
+ * created by instantiating `Logger` directly.
268
+ *
269
+ * The name is intentionally short: `log` reads naturally at the call site
270
+ * (`log.info("auth", "login", "ok")`) and matches the convention used in
271
+ * pino, bunyan, and most JS logging tutorials.
272
+ *
273
+ * Note that `log` is a `Logger` instance, **not** a function — the bare
274
+ * callable form was removed when the dual `log` / `logger` exports were
275
+ * collapsed into a single name. Use `log.info(...)` (or any other level
276
+ * shortcut) to emit entries.
277
+ */
278
+ const log = new Logger();
279
+
280
+ //#endregion
281
+ export { Logger, log };
282
+ //# sourceMappingURL=logger.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.mjs","names":[],"sources":["../../../../../@warlock.js/logger/src/logger.ts"],"sourcesContent":["import { Random } from \"@mongez/reinforcements\";\r\nimport type { LogChannel } from \"./log-channel\";\r\nimport { applyRedact, mergeRedact } from \"./redact\";\r\nimport type {\r\n AutoFlushEvent,\r\n LoggingData,\r\n LogLevel,\r\n OmittedLoggingData,\r\n RedactConfig,\r\n} from \"./types\";\r\nimport { clearMessage } from \"./utils/clear-message\";\r\n\r\nconst SIGNAL_EVENTS: ReadonlySet<AutoFlushEvent> = new Set([\r\n \"SIGINT\",\r\n \"SIGTERM\",\r\n \"SIGHUP\",\r\n \"SIGBREAK\",\r\n \"SIGUSR2\",\r\n]);\r\n\r\n/**\r\n * Severity ranks used by `setMinLevel`. Higher number = more severe. The\r\n * ordering matches conventional log-level hierarchies: `debug` is noisiest\r\n * and easiest to drop; `error` is the loudest and never dropped by the\r\n * minimum-level filter. `success` sits beside `info` — it's an informational\r\n * outcome, not a warning.\r\n */\r\nconst LEVEL_RANK: Record<LogLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n success: 1,\r\n warn: 2,\r\n error: 3,\r\n};\r\n\r\nexport class Logger {\r\n /**\r\n * Current channel\r\n */\r\n public channels: LogChannel[] = [];\r\n\r\n public id = \"logger-\" + Random.string(32);\r\n\r\n /**\r\n * Registered auto-flush handlers, keyed by event name. Stored so repeated\r\n * calls to `enableAutoFlush` replace rather than stack, and so\r\n * `disableAutoFlush` can remove them cleanly.\r\n */\r\n private autoFlushHandlers = new Map<AutoFlushEvent, () => void>();\r\n\r\n /**\r\n * Logger-wide minimum severity. When set, entries below this level are\r\n * dropped before any channel is invoked — cheaper than per-channel `levels`\r\n * filters because the fan-out loop is skipped entirely. `undefined` means\r\n * no minimum (every entry reaches every channel that accepts it).\r\n */\r\n private minLevel?: LogLevel;\r\n\r\n /**\r\n * Logger-wide redaction floor. Applied once before fan-out — every\r\n * channel receives an entry with these paths already censored. Channel\r\n * configs can extend the path list (additive); they cannot remove paths\r\n * set here.\r\n */\r\n private redactConfig?: RedactConfig;\r\n\r\n /**\r\n * Add a new channel\r\n */\r\n public addChannel(channel: LogChannel) {\r\n this.channels.push(channel);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Set base configurations\r\n */\r\n public configure(config: {\r\n channels?: LogChannel[];\r\n autoFlushOn?: AutoFlushEvent[];\r\n minLevel?: LogLevel;\r\n redact?: RedactConfig;\r\n }) {\r\n if (config.channels) {\r\n this.channels = config.channels;\r\n }\r\n\r\n if (config.autoFlushOn) {\r\n this.enableAutoFlush(config.autoFlushOn);\r\n }\r\n\r\n if (config.minLevel !== undefined) {\r\n this.setMinLevel(config.minLevel);\r\n }\r\n\r\n if (config.redact !== undefined) {\r\n this.setRedact(config.redact);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Set the logger-wide redaction floor. Applied to every entry before\r\n * fan-out; channel configs add more paths on top, never fewer. Pass\r\n * `undefined` to clear.\r\n *\r\n * @example\r\n * log.setRedact({\r\n * paths: [\"context.password\", \"context.*.token\"],\r\n * censor: \"[REDACTED]\",\r\n * });\r\n */\r\n public setRedact(config: RedactConfig | undefined): this {\r\n this.redactConfig = config;\r\n return this;\r\n }\r\n\r\n /**\r\n * Read the active logger-wide redact config (or `undefined`).\r\n */\r\n public getRedact(): RedactConfig | undefined {\r\n return this.redactConfig;\r\n }\r\n\r\n /**\r\n * Drop every entry whose severity is below `level` before fan-out. Cheaper\r\n * than per-channel `levels` filters because the loop never runs and no\r\n * channel receives the entry. Pass `undefined` to clear and accept all\r\n * levels again.\r\n *\r\n * @example\r\n * // production: silence debug noise everywhere at once\r\n * logger.setMinLevel(\"info\");\r\n */\r\n public setMinLevel(level: LogLevel | undefined): this {\r\n this.minLevel = level;\r\n return this;\r\n }\r\n\r\n /**\r\n * Read the active minimum severity (or `undefined` when none is set).\r\n */\r\n public getMinLevel(): LogLevel | undefined {\r\n return this.minLevel;\r\n }\r\n\r\n /**\r\n * Set channels\r\n */\r\n public setChannels(channels: LogChannel[]) {\r\n this.channels = channels;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Normalize log data to a single object\r\n */\r\n private normalizeLogData(\r\n dataOrModule: LoggingData | OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n level?: LogLevel,\r\n context?: Record<string, any>,\r\n ): LoggingData {\r\n if (typeof dataOrModule === \"object\") {\r\n // If level is provided, override type\r\n return {\r\n type: (level || (dataOrModule as any).type || \"info\") as LogLevel,\r\n module: dataOrModule.module,\r\n action: dataOrModule.action,\r\n message: dataOrModule.message,\r\n ...(context ? { context } : dataOrModule.context ? { context: dataOrModule.context } : {}),\r\n };\r\n }\r\n return {\r\n type: (level || \"info\") as LogLevel,\r\n module: dataOrModule,\r\n action: action as string,\r\n message,\r\n ...(context ? { context } : {}),\r\n };\r\n }\r\n\r\n /**\r\n * Make log\r\n *\r\n * Fans out a single log entry to every registered channel. Non-terminal\r\n * channels receive a copy whose `message` has had ANSI color codes stripped\r\n * — each channel sees its own shallow clone so one channel cannot observe\r\n * another's mutations (e.g. a later terminal channel still sees the original\r\n * colored message).\r\n */\r\n public async log(data: LoggingData) {\r\n if (this.minLevel && LEVEL_RANK[data.type] < LEVEL_RANK[this.minLevel]) {\r\n return this;\r\n }\r\n\r\n // Apply the logger-wide redact floor once. Every channel sees the\r\n // result; no channel can undo a logger-wide redaction (additive-only\r\n // semantics).\r\n const baseEntry = applyRedact(data, this.redactConfig);\r\n\r\n for (const channel of this.channels) {\r\n const channelRedact = channel.getRedactConfig?.();\r\n const effectiveRedact = channelRedact\r\n ? mergeRedact(this.redactConfig, channelRedact)\r\n : undefined;\r\n\r\n // When the channel adds paths, redact again from `data` rather than\r\n // from `baseEntry` so the merged config (which already contains the\r\n // logger-wide paths) does the full pass — avoids double-cloning the\r\n // already-redacted base.\r\n let payload = effectiveRedact ? applyRedact(data, effectiveRedact) : baseEntry;\r\n\r\n if (channel.terminal === false) {\r\n payload = { ...payload, message: clearMessage(payload.message) };\r\n }\r\n\r\n channel.log(payload);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Make debug log\r\n */\r\n public debug(\r\n dataOrModule: OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n context?: Record<string, any>,\r\n ) {\r\n const data = this.normalizeLogData(dataOrModule, action, message, \"debug\", context);\r\n return this.log(data);\r\n }\r\n\r\n /**\r\n * Make info log\r\n */\r\n public info(\r\n dataOrModule: OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n context?: Record<string, any>,\r\n ) {\r\n const data = this.normalizeLogData(dataOrModule, action, message, \"info\", context);\r\n return this.log(data);\r\n }\r\n\r\n /**\r\n * Make warn log\r\n */\r\n public warn(\r\n dataOrModule: OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n context?: Record<string, any>,\r\n ) {\r\n const data = this.normalizeLogData(dataOrModule, action, message, \"warn\", context);\r\n return this.log(data);\r\n }\r\n\r\n /**\r\n * Make error log\r\n */\r\n public error(\r\n dataOrModule: OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n context?: Record<string, any>,\r\n ) {\r\n const data = this.normalizeLogData(dataOrModule, action, message, \"error\", context);\r\n return this.log(data);\r\n }\r\n\r\n /**\r\n * Make success log\r\n */\r\n public success(\r\n dataOrModule: OmittedLoggingData | string,\r\n action?: string,\r\n message: any = \"\",\r\n context?: Record<string, any>,\r\n ) {\r\n const data = this.normalizeLogData(dataOrModule, action, message, \"success\", context);\r\n\r\n return this.log(data);\r\n }\r\n\r\n /**\r\n * Log an `error` entry when `condition` is falsy. No-op otherwise — the\r\n * entry is never built and channels are not invoked, so this is genuinely\r\n * free in the happy path. Mirrors the spirit of `console.assert` but routes\r\n * through the logger pipeline so persistent channels capture failures.\r\n *\r\n * @example\r\n * log.assert(user !== null, \"auth\", \"session\", \"user vanished mid-flight\", { sessionId });\r\n */\r\n public assert(\r\n condition: unknown,\r\n module: string,\r\n action: string,\r\n message: any,\r\n context?: Record<string, any>,\r\n ): Promise<Logger> | Logger {\r\n if (condition) return this;\r\n return this.error(module, action, message, context);\r\n }\r\n\r\n /**\r\n * Start a duration timer. The returned function emits an `info` entry\r\n * with `completed in <ms>ms` and a `durationMs` field in `context` when\r\n * called. Pass an object to `end()` to merge extra fields into context.\r\n *\r\n * @example\r\n * const end = log.timer(\"db\", \"users.findById\");\r\n * const user = await usersRepo.findById(id);\r\n * end({ id, found: !!user });\r\n */\r\n public timer(\r\n module: string,\r\n action: string,\r\n ): (extra?: Record<string, any>) => Promise<Logger> {\r\n const startedAt = Date.now();\r\n return (extra?: Record<string, any>) => {\r\n const durationMs = Date.now() - startedAt;\r\n return this.info(module, action, `completed in ${durationMs}ms`, {\r\n durationMs,\r\n ...(extra ?? {}),\r\n });\r\n };\r\n }\r\n\r\n /**\r\n * Get channel by name\r\n */\r\n public channel(name: string) {\r\n return this.channels.find((channel) => channel.name === name);\r\n }\r\n\r\n /**\r\n * Synchronously flush logs\r\n */\r\n public flushSync() {\r\n for (const channel of this.channels) {\r\n if (channel.flushSync) {\r\n channel.flushSync();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Register one process-level handler per event that calls `flushSync()`\r\n * before the process terminates.\r\n *\r\n * For signal events (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGBREAK`, `SIGUSR2`)\r\n * the handler flushes and then re-raises the signal so Node's default exit\r\n * behavior runs. For `beforeExit`, the handler flushes in place — Node exits\r\n * naturally afterwards.\r\n *\r\n * Idempotent: calling with the same events replaces the previous handlers.\r\n * Call `disableAutoFlush()` to unregister.\r\n *\r\n * @example\r\n * log.configure({\r\n * channels: [new ConsoleLog(), new FileLog()],\r\n * autoFlushOn: [\"SIGINT\", \"SIGTERM\", \"beforeExit\"],\r\n * });\r\n */\r\n public enableAutoFlush(events: AutoFlushEvent[]): this {\r\n this.disableAutoFlush();\r\n\r\n for (const event of events) {\r\n const handler = SIGNAL_EVENTS.has(event)\r\n ? () => {\r\n this.flushSync();\r\n process.off(event, handler);\r\n process.kill(process.pid, event as NodeJS.Signals);\r\n }\r\n : () => {\r\n this.flushSync();\r\n };\r\n\r\n process.on(event, handler);\r\n this.autoFlushHandlers.set(event, handler);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove every handler previously registered by `enableAutoFlush`.\r\n * Safe to call when no handlers are registered.\r\n */\r\n public disableAutoFlush(): this {\r\n for (const [event, handler] of this.autoFlushHandlers) {\r\n process.off(event, handler);\r\n }\r\n\r\n this.autoFlushHandlers.clear();\r\n\r\n return this;\r\n }\r\n}\r\n\r\n/**\r\n * The package singleton. Use this for everyday logging — `log.info(...)`,\r\n * `log.error(...)`, `log.configure(...)`. Custom logger instances can be\r\n * created by instantiating `Logger` directly.\r\n *\r\n * The name is intentionally short: `log` reads naturally at the call site\r\n * (`log.info(\"auth\", \"login\", \"ok\")`) and matches the convention used in\r\n * pino, bunyan, and most JS logging tutorials.\r\n *\r\n * Note that `log` is a `Logger` instance, **not** a function — the bare\r\n * callable form was removed when the dual `log` / `logger` exports were\r\n * collapsed into a single name. Use `log.info(...)` (or any other level\r\n * shortcut) to emit entries.\r\n */\r\nexport const log = new Logger();\r\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { LoggingData, RedactConfig } from "../types.mjs";
2
+
3
+ //#region ../../@warlock.js/logger/src/redact/redact.d.ts
4
+ /**
5
+ * Produce a new `LoggingData` with every path in `config.paths` replaced
6
+ * by `config.censor`. The original entry is never mutated — channels and
7
+ * other call sites can hold references to the input safely.
8
+ *
9
+ * No-op (returns the input by reference) when `config` is `undefined` or
10
+ * its `paths` array is empty, so the fast path stays fast.
11
+ */
12
+ declare function applyRedact(data: LoggingData, config: RedactConfig | undefined): LoggingData;
13
+ /**
14
+ * Combine two redact configs into one effective config. Used to merge a
15
+ * channel's additive paths on top of the logger-wide floor.
16
+ *
17
+ * - `paths` are concatenated; duplicates are kept (the matcher tolerates
18
+ * them, and de-duping cross-config would mask a developer typo).
19
+ * - `censor` from the channel wins; falls back to the logger's; falls back
20
+ * to the default `"[REDACTED]"`.
21
+ */
22
+ declare function mergeRedact(base: RedactConfig | undefined, extra: RedactConfig | undefined): RedactConfig | undefined;
23
+ //#endregion
24
+ export { applyRedact, mergeRedact };
25
+ //# sourceMappingURL=redact.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.mts","names":[],"sources":["../../../../../../@warlock.js/logger/src/redact/redact.ts"],"mappings":";;;;;AAyIA;;;;;;iBAAgB,WAAA,CACd,IAAA,EAAM,WAAA,EACN,MAAA,EAAQ,YAAA,eACP,WAAA;;;;;;;;AAAW;AA0Bd;iBAAgB,WAAA,CACd,IAAA,EAAM,YAAA,cACN,KAAA,EAAO,YAAA,eACN,YAAA"}