@warlock.js/logger 5.31.0 → 5.32.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/CHANGELOG.md +6 -0
  2. package/cjs/index.cjs +4 -4
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/channels/console-log.d.mts +2 -4
  5. package/esm/channels/console-log.d.mts.map +1 -1
  6. package/esm/channels/file-log.d.mts +7 -8
  7. package/esm/channels/file-log.d.mts.map +1 -1
  8. package/esm/channels/file-log.mjs +2 -2
  9. package/esm/channels/file-log.mjs.map +1 -1
  10. package/esm/channels/file-name-pattern.d.mts +1 -2
  11. package/esm/channels/file-name-pattern.d.mts.map +1 -1
  12. package/esm/channels/index.mjs +1 -1
  13. package/esm/channels/json-file-log.d.mts +1 -3
  14. package/esm/channels/json-file-log.d.mts.map +1 -1
  15. package/esm/channels/sentry-log.d.mts +7 -8
  16. package/esm/channels/sentry-log.d.mts.map +1 -1
  17. package/esm/log-channel.d.mts +2 -4
  18. package/esm/log-channel.d.mts.map +1 -1
  19. package/esm/logger.d.mts +3 -5
  20. package/esm/logger.d.mts.map +1 -1
  21. package/esm/logger.mjs +1 -1
  22. package/esm/logger.mjs.map +1 -1
  23. package/esm/redact/default-keys.d.mts +3 -4
  24. package/esm/redact/default-keys.d.mts.map +1 -1
  25. package/esm/redact/escape-log-value.d.mts +2 -3
  26. package/esm/redact/escape-log-value.d.mts.map +1 -1
  27. package/esm/redact/index.mjs +1 -1
  28. package/esm/redact/mask-email.d.mts +3 -4
  29. package/esm/redact/mask-email.d.mts.map +1 -1
  30. package/esm/redact/redact.d.mts +3 -5
  31. package/esm/redact/redact.d.mts.map +1 -1
  32. package/esm/types.d.mts +11 -12
  33. package/esm/types.d.mts.map +1 -1
  34. package/esm/utils/capture-unhandled-errors.d.mts +2 -3
  35. package/esm/utils/capture-unhandled-errors.d.mts.map +1 -1
  36. package/esm/utils/clear-message.d.mts +1 -2
  37. package/esm/utils/clear-message.d.mts.map +1 -1
  38. package/esm/utils/index.mjs +1 -1
  39. package/esm/utils/safe-json-stringify.d.mts +1 -2
  40. package/esm/utils/safe-json-stringify.d.mts.map +1 -1
  41. package/package.json +2 -2
@@ -1,8 +1,7 @@
1
1
  import { BasicLogConfigurations, LoggingData } from "../types.mjs";
2
2
  import { LogChannel } from "../log-channel.mjs";
3
-
4
3
  //#region ../../packages/logger/src/channels/console-log.d.ts
5
- type ConsoleLogConfig = BasicLogConfigurations & {
4
+ export type ConsoleLogConfig = BasicLogConfigurations & {
6
5
  /**
7
6
  * Render the log entry's `context` object on a second line after the main
8
7
  * message. When `false`, context is silently dropped (the historical
@@ -21,7 +20,7 @@ type ConsoleLogConfig = BasicLogConfigurations & {
21
20
  */
22
21
  contextDepth?: number;
23
22
  };
24
- declare class ConsoleLog extends LogChannel<ConsoleLogConfig> {
23
+ export declare class ConsoleLog extends LogChannel<ConsoleLogConfig> {
25
24
  /**
26
25
  * {@inheritdoc}
27
26
  */
@@ -36,5 +35,4 @@ declare class ConsoleLog extends LogChannel<ConsoleLogConfig> {
36
35
  log(data: LoggingData): void;
37
36
  }
38
37
  //#endregion
39
- export { ConsoleLog, ConsoleLogConfig };
40
38
  //# sourceMappingURL=console-log.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"console-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/console-log.ts"],"mappings":";;;;KAKY,gBAAA,GAAmB,sBAAsB;;AAArD;;;;;;;;EAUE,WAAA;EA6EW;;;;;;EAtEX,YAAA;AAAA;AAAA,cAsEW,UAAA,SAAmB,UAAA,CAAW,gBAAA;EAAA;;;EAIlC,IAAA;EAUU;;;EALV,QAAA;;;;EAKA,GAAA,CAAI,IAAA,EAAM,WAAA;AAAA"}
1
+ {"version":3,"file":"console-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/console-log.ts"],"mappings":";;;YAKY,mBAAmB;;;;;;;;;;EAU7B;;;;;;;EAOA;;qBAsEW,mBAAmB,WAAW;;;;EAIlC;;;;EAKA;;;;EAKA,IAAI,MAAM"}
@@ -1,14 +1,13 @@
1
1
  import { BasicLogConfigurations, LogContract, LogLevel, LogMessage, LoggingData } from "../types.mjs";
2
2
  import { LogChannel } from "../log-channel.mjs";
3
3
  import { FileNameOption } from "./file-name-pattern.mjs";
4
-
5
4
  //#region ../../packages/logger/src/channels/file-log.d.ts
6
5
  /** Default file name of a `daily` chunk: sortable ISO date. */
7
- declare const DAILY_FILE_NAME = "{YYYY}-{MM}-{DD}";
6
+ export declare const DAILY_FILE_NAME = "{YYYY}-{MM}-{DD}";
8
7
  /** Default file name of an `hourly` chunk: sortable ISO date and hour. */
9
- declare const HOURLY_FILE_NAME = "{YYYY}-{MM}-{DD}-{HH}";
8
+ export declare const HOURLY_FILE_NAME = "{YYYY}-{MM}-{DD}-{HH}";
10
9
  /** Default date part of a size-rotated file's name. */
11
- declare const ROTATE_FILE_NAME = "{YYYY}-{MM}-{DD}";
10
+ export declare const ROTATE_FILE_NAME = "{YYYY}-{MM}-{DD}";
12
11
  /**
13
12
  * Which old log files `FileLog` removes, on boot and whenever it starts a new
14
13
  * file (a size rotation or a dated name rolling over). Only files in the log
@@ -16,7 +15,7 @@ declare const ROTATE_FILE_NAME = "{YYYY}-{MM}-{DD}";
16
15
  * channel's file name pattern are considered; the file being written is
17
16
  * always kept.
18
17
  */
19
- type FileLogRetention = {
18
+ export type FileLogRetention = {
20
19
  /**
21
20
  * Keep at most this many matching files per directory, newest (by
22
21
  * modification time) first, counting the file being written.
@@ -33,7 +32,7 @@ type FileLogRetention = {
33
32
  */
34
33
  match?: RegExp;
35
34
  };
36
- type FileLogConfig = BasicLogConfigurations & {
35
+ export type FileLogConfig = BasicLogConfigurations & {
37
36
  storagePath?: string;
38
37
  /**
39
38
  * Base name, without extension: the file name of a `single` chunk and the
@@ -120,7 +119,7 @@ type FileLogConfig = BasicLogConfigurations & {
120
119
  time?: string;
121
120
  };
122
121
  };
123
- declare class FileLog extends LogChannel<FileLogConfig> implements LogContract {
122
+ export declare class FileLog extends LogChannel<FileLogConfig> implements LogContract {
124
123
  /**
125
124
  * {@inheritdoc}
126
125
  */
@@ -316,5 +315,5 @@ declare class FileLog extends LogChannel<FileLogConfig> implements LogContract {
316
315
  protected write(filePath: string, content: string): Promise<unknown>;
317
316
  }
318
317
  //#endregion
319
- export { DAILY_FILE_NAME, FileLog, FileLogConfig, FileLogRetention, HOURLY_FILE_NAME, ROTATE_FILE_NAME };
318
+ export type { FileNameOption };
320
319
  //# sourceMappingURL=file-log.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-log.ts"],"mappings":";;;;;;cAuBa,eAAA;;cAGA,gBAAA;;cAGA,gBAAA;AAHb;;;;AAA6B;AAG7B;;AAHA,KAcY,gBAAA;EAXiB;AAAA;AAW7B;;EAKE,QAAA;EAUc;;;EANd,UAAA;EAMQ;;AAAM;AAGhB;;EAHE,KAAA,GAAQ,MAAM;AAAA;AAAA,KAGJ,aAAA,GAAgB,sBAAA;EAC1B,WAAA;EAyDY;;;;;;EAlDZ,IAAA;EASA;;;;;;;;EAAA,QAAA,GAAW,cAAA;EAyCC;;;;;;;EAjCZ,KAAA;EA2DM;AAAA;AAIR;;;EAzDE,MAAA;EAkEoB;;;;;EA5DpB,SAAA;EA+H4C;;;;;;;;EAtH5C,cAAA,GAAiB,cAAA;EA4WwC;;;;;EAtWzD,WAAA;EAqiBuB;;;;;EA/hBvB,SAAA,GAAY,gBAAA;EA8Be;;;;;EAxB3B,kBAAA;EAwBgE;;;;;;;EAhBhE,OAAA;EAmCiC;;;;;EA7BjC,MAAA,GAAS,QAAA;EAiEC;;;EA7DV,UAAA;IACE,IAAA;IACA,IAAA;EAAA;AAAA;AAAA,cAIS,OAAA,SAAgB,UAAA,CAAW,aAAA,aAA0B,WAAA;EAqF7B;;;EAjF5B,IAAA;EAsG+C;;;EAAA,UAjG5C,QAAA,EAAU,UAAA;EA2KN;;;EAAA,UAtKJ,eAAA,EAAiB,MAAA,SAAe,UAAA;EAwM/B;;;EAAA,UAnMD,qBAAA,EAAuB,aAAA;EAmOjB;;;EAAA,UAhNN,aAAA;EA2OM;;;EAAA,UAtON,SAAA;EAuRA;;;;;EAAA,UAhRA,mBAAA,GAAsB,MAAA,CAAO,OAAA;EAmVvB;;;EAAA,UA9UN,YAAA;EAiVG;;;EAAA,UA5UH,YAAA;EAuYA;;;EAAA,UAlYA,OAAA,GAAU,OAAA;EA+aP;;;;EAAA,UAzaH,oBAAA;EA0bwB;;;EAAA,UArbxB,iBAAA,CAAkB,cAAA,EAAgB,aAAA;EAif9B;;;EAAA,UAxeE,kBAAA,CAAmB,QAAA,YAAwB,OAAA;EA2gBb;;;;EAAA,UAtf9B,aAAA,CAAc,QAAA,YAAwB,OAAA;EAoiBC;;AAAA;;;;;;EAAA,UAngB7C,gBAAA;;;;;;;;EAkBH,OAAA;;;;MAYI,QAAA;;;;gBAWG,kBAAA;;;;gBAOA,QAAA;;;;;gBAQA,eAAA,IAAmB,cAAA;;;;MAmBtB,QAAA;;;;MAWA,SAAA;;;;gBAOG,OAAA;;;;MAOH,WAAA;;;;YAOK,IAAA,IAAI,OAAA;;;;;;EAeb,KAAA,IAAS,OAAA;;;;;YAYA,UAAA,IAAc,OAAA;;;;YAuBd,UAAA,IAAc,OAAA;;;;;YA0BpB,gBAAA,CAAiB,SAAA,EAAW,gBAAA,GAAmB,MAAA;;;;YAqCzC,oBAAA,IAAwB,OAAA;;;;;YA8BxB,cAAA,CACd,SAAA,UACA,OAAA,EAAS,MAAA,EACT,SAAA,EAAW,gBAAA,EACX,UAAA,WACC,OAAA;;;;YAyDO,oBAAA,CAAqB,KAAA,WAAgB,MAAA;;;;EAYxC,SAAA;;;;;;;;;;EAiCM,KAAA,IAAS,OAAA;;;;EAiBT,GAAA,CAAI,IAAA,EAAM,WAAA,GAAW,OAAA;;;;YAyClB,8BAAA,IAA8B,OAAA;;;;YASpC,MAAA;;;;gBAUI,uBAAA;;;;YAOE,mBAAA,IAAmB,OAAA;;;;YA4BnB,0BAAA,IAA8B,OAAA;;;;YAgCpC,sBAAA;;;;YAcM,KAAA,CAAM,QAAA,UAAkB,OAAA,WAAe,OAAA;AAAA"}
1
+ {"version":3,"file":"file-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-log.ts"],"mappings":";;;;;qBAuBa;;qBAGA;;qBAGA;;;;;;;;YAWD;;;;;EAKV;;;;EAIA;;;;;;EAMA,QAAQ;;YAGE,gBAAgB;EAC1B;;;;;;;EAOA;;;;;;;;;EASA,WAAW;;;;;;;;EAQX;;;;;;EAMA;;;;;;EAMA;;;;;;;;;EASA,iBAAiB;;;;;;EAMjB;;;;;;EAMA,YAAY;;;;;;EAMZ;;;;;;;;EAQA;;;;;;EAMA,SAAS;;;;EAIT;IACE;IACA;;;qBAIS,gBAAgB,WAAW,0BAA0B;;;;EAIzD;;;;YAKG,UAAU;;;;YAKV,iBAAiB,eAAe;;;;YAKhC,uBAAuB;;;;YAmBvB;;;;YAKA;;;;;;YAOA,sBAAsB,OAAO;;;;YAK7B;;;;YAKA;;;;YAKA,UAAU;;;;;YAMV;;;;YAKA,kBAAkB,gBAAgB;;;;YAS5B,mBAAmB,oBAAwB;;;;;YAqB3C,cAAc,oBAAwB;;;;;;;;;YAiC5C;;;;;;;;EAkBH;;;;MAYI;;;;gBAWG;;;;gBAOA;;;;;gBAQA,mBAAmB;;;;MAmBtB;;;;MAWA;;;;gBAOG;;;;MAOH;;;;YAOK,QAAI;;;;;;EAeb,SAAS;;;;;YAYA,cAAc;;;;YAuBd,cAAc;;;;;YA0BpB,iBAAiB,WAAW,mBAAmB;;;;YAqCzC,wBAAwB;;;;;YA8BxB,eACd,mBACA,SAAS,QACT,WAAW,kBACX,qBACC;;;;YAyDO,qBAAqB,gBAAgB;;;;EAYxC;;;;;;;;;;EAiCM,SAAS;;;;EAiBT,IAAI,MAAM,cAAW;;;;YAyClB,kCAA8B;;;;YASpC;;;;gBAUI;;;;YAOE,uBAAmB;;;;YA4BnB,8BAA8B;;;;YAgCpC;;;;YAcM,MAAM,kBAAkB,kBAAe"}
@@ -13,7 +13,7 @@ const DAILY_FILE_NAME = "{YYYY}-{MM}-{DD}";
13
13
  const HOURLY_FILE_NAME = "{YYYY}-{MM}-{DD}-{HH}";
14
14
  /** Default date part of a size-rotated file's name. */
15
15
  const ROTATE_FILE_NAME = "{YYYY}-{MM}-{DD}";
16
- const DAY_MS = 1440 * 60 * 1e3;
16
+ const DAY_MS = 864e5;
17
17
  var FileLog = class extends LogChannel {
18
18
  constructor(..._args) {
19
19
  super(..._args);
@@ -28,7 +28,7 @@ var FileLog = class extends LogChannel {
28
28
  chunk: "single",
29
29
  maxMessagesToWrite: 100,
30
30
  filter: () => true,
31
- maxFileSize: 10 * 1024 * 1024,
31
+ maxFileSize: 10485760,
32
32
  rotateFileName: ROTATE_FILE_NAME,
33
33
  dateFormat: {
34
34
  date: "DD-MM-YYYY",
@@ -1 +1 @@
1
- {"version":3,"file":"file-log.mjs","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-log.ts"],"sourcesContent":["import { ensureDirectoryAsync } from \"@warlock.js/fs\";\nimport dayjs from \"dayjs\";\nimport fs from \"fs\";\nimport { EOL } from \"os\";\nimport path from \"path\";\nimport { LogChannel } from \"../log-channel\";\nimport type {\n BasicLogConfigurations,\n LogContract,\n LoggingData,\n LogLevel,\n LogMessage,\n} from \"../types\";\nimport {\n escapeRegExp,\n fileNamePatternSource,\n renderFileName,\n type FileNameOption,\n} from \"./file-name-pattern\";\n\nexport type { FileNameOption } from \"./file-name-pattern\";\n\n/** Default file name of a `daily` chunk: sortable ISO date. */\nexport const DAILY_FILE_NAME = \"{YYYY}-{MM}-{DD}\";\n\n/** Default file name of an `hourly` chunk: sortable ISO date and hour. */\nexport const HOURLY_FILE_NAME = \"{YYYY}-{MM}-{DD}-{HH}\";\n\n/** Default date part of a size-rotated file's name. */\nexport const ROTATE_FILE_NAME = \"{YYYY}-{MM}-{DD}\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Which old log files `FileLog` removes, on boot and whenever it starts a new\n * file (a size rotation or a dated name rolling over). Only files in the log\n * directory (each group directory with `groupBy`) whose names match the\n * channel's file name pattern are considered; the file being written is\n * always kept.\n */\nexport type FileLogRetention = {\n /**\n * Keep at most this many matching files per directory, newest (by\n * modification time) first, counting the file being written.\n */\n maxFiles?: number;\n /**\n * Remove matching files last modified more than this many days ago.\n */\n maxAgeDays?: number;\n /**\n * Which file names (with extension) belong to this channel. Defaults to one\n * derived from `fileName` and `rotateFileName`; required when `fileName` is\n * a function.\n */\n match?: RegExp;\n};\n\nexport type FileLogConfig = BasicLogConfigurations & {\n storagePath?: string;\n /**\n * Base name, without extension: the file name of a `single` chunk and the\n * `{name}` token of a `fileName` pattern.\n *\n * @default app\n */\n name?: string;\n /**\n * The file name, without extension: a pattern such as\n * `\"app-{YYYY}-{MM}-{DD}\"` (tokens `{YYYY}` `{MM}` `{DD}` `{HH}` `{mm}`\n * `{name}`, local time) or a function of the current date. Evaluated at\n * every write, so a dated name starts a new file when it changes.\n *\n * @default by chunk: `single` → name, `daily` → `{YYYY}-{MM}-{DD}`, `hourly` → `{YYYY}-{MM}-{DD}-{HH}`\n */\n fileName?: FileNameOption;\n /**\n * chunk mode: picks the default `fileName`.\n * `single` writes one file named `name`, `daily` one file per day\n * (`YYYY-MM-DD`), `hourly` one per hour (`YYYY-MM-DD-HH`). Size rotation\n * applies to each.\n * @default single\n */\n chunk?: \"single\" | \"daily\" | \"hourly\";\n /**\n * Whether to rotate the file\n *\n * @default true\n */\n rotate?: boolean;\n /**\n * File Extension\n *\n * @default log\n */\n extension?: string;\n /**\n * Middle part of a size-rotated file's name:\n * `<file name>-<rotateFileName>-<epoch ms>.<extension>`. Same forms as\n * `fileName` (a token pattern or a function of the rotation date); text\n * without tokens is used as is.\n *\n * @default {YYYY}-{MM}-{DD}\n */\n rotateFileName?: FileNameOption;\n /**\n * Max file size before rotating the file\n *\n * @default 10MB\n */\n maxFileSize?: number;\n /**\n * Remove old log files on boot and whenever a new file is started.\n *\n * @default none (nothing is removed)\n */\n retention?: FileLogRetention;\n /**\n * Set the max messages that needs to be added before writing to the file\n *\n * @default 100\n */\n maxMessagesToWrite?: number;\n /**\n * Group logs by\n * Please note that the order matters here\n * For example, if you set `groupBy: ['level', 'module']`, the logs will be added in level name first, then by module\n *\n * @default none\n */\n groupBy?: (\"level\" | \"module\" | \"action\")[];\n /**\n * Define what levels should be logged\n *\n * @default all\n */\n levels?: LogLevel[];\n /**\n * Date and time format\n */\n dateFormat?: {\n date?: string;\n time?: string;\n };\n};\n\nexport class FileLog extends LogChannel<FileLogConfig> implements LogContract {\n /**\n * {@inheritdoc}\n */\n public name = \"file\";\n\n /**\n * Messages buffer\n */\n protected messages: LogMessage[] = [];\n\n /**\n * Grouped messages\n */\n protected groupedMessages: Record<string, LogMessage[]> = {};\n\n /**\n * Default channel configurations\n */\n protected defaultConfigurations: FileLogConfig = {\n storagePath: process.cwd() + \"/storage/logs\",\n rotate: true,\n name: \"app\",\n extension: \"log\",\n chunk: \"single\",\n maxMessagesToWrite: 100,\n filter: () => true,\n maxFileSize: 10 * 1024 * 1024, // 10MB\n rotateFileName: ROTATE_FILE_NAME,\n dateFormat: {\n date: \"DD-MM-YYYY\",\n time: \"HH:mm:ss\",\n },\n };\n\n /**\n * Last write time\n */\n protected lastWriteTime = Date.now();\n\n /**\n * A flag to determine if the file is being written\n */\n protected isWriting = false;\n\n /**\n * Handle for the periodic flush interval. Stored so it can be cleared\n * in `dispose()` — long-lived processes that create channels dynamically\n * would otherwise leak one timer per channel.\n */\n protected flushIntervalHandle?: NodeJS.Timeout;\n\n /**\n * Set when a size rotation started a new file, so the next write prunes.\n */\n protected retentionDue = false;\n\n /**\n * File name of the last write, to notice a dated name rolling over.\n */\n protected lastFileName?: string;\n\n /**\n * The running (or last) prune, so prunes never overlap.\n */\n protected pruning?: Promise<void>;\n\n /**\n * Whether the \"function `fileName` needs `retention.match`\" error was\n * already reported.\n */\n protected missingMatchReported = false;\n\n /**\n * {@inheritdoc}\n */\n protected setConfigurations(configurations: FileLogConfig) {\n assertRetention(configurations.retention);\n\n return super.setConfigurations(configurations);\n }\n\n /**\n * Check file size for file rotation\n */\n protected async checkAndRotateFile(filePath = this.filePath) {\n if (!this.config(\"rotate\")) return;\n\n try {\n const stats = await fs.promises.stat(filePath);\n if (stats.size >= this.config(\"maxFileSize\")!) {\n await this.rotateLogFile(filePath);\n }\n } catch (error: any) {\n // ENOENT is expected when the file hasn't been created yet — there is\n // nothing to rotate, so stay silent. Surface anything else.\n if (error.code !== \"ENOENT\") {\n console.error(\"Error checking log file:\", error);\n }\n }\n }\n\n /**\n * Rotate the given log file (the active one by default) aside as\n * `<file name>-<rotateFileName>-<epoch ms>.<extension>` in its directory.\n */\n protected async rotateLogFile(filePath = this.filePath) {\n const now = new Date();\n const extension = this.extension;\n const baseName = path.basename(filePath, `.${extension}`);\n const rotateName = renderFileName(\n this.config(\"rotateFileName\") ?? ROTATE_FILE_NAME,\n now,\n this.baseName,\n );\n\n const rotatedFilePath = path.join(\n path.dirname(filePath),\n `${baseName}-${rotateName}-${now.getTime()}.${extension}`,\n );\n\n await fs.promises.rename(filePath, rotatedFilePath).then(\n () => {\n this.retentionDue = true;\n },\n (error) => {\n console.error(\"Error rotating file:\", error);\n },\n );\n }\n\n /**\n * Flush messages\n *\n * Starts a periodic re-check so low-traffic channels don't sit on buffered\n * entries indefinitely. The handle is stored on the instance so `dispose()`\n * can stop it — without this, every channel leaks a timer for the lifetime\n * of the process.\n */\n protected initMessageFlush() {\n this.flushIntervalHandle = setInterval(() => {\n if (\n this.messages.length > 0 &&\n (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5000)\n ) {\n this.writeMessagesToFile();\n }\n }, 5000);\n }\n\n /**\n * Stop the background flush interval and drain any buffered entries.\n *\n * Call this when discarding a channel (e.g. reconfiguring the logger at\n * runtime) so the 5-second timer doesn't keep the event loop alive. Safe to\n * call more than once.\n */\n public dispose(): void {\n if (this.flushIntervalHandle) {\n clearInterval(this.flushIntervalHandle);\n this.flushIntervalHandle = undefined;\n }\n\n this.flushSync();\n }\n\n /**\n * Get file path\n */\n public get filePath() {\n const fileName = this.fileName;\n\n const extension = this.extension;\n\n return path.join(this.storagePath, `${fileName}.${extension}`);\n }\n\n /**\n * Get max messages\n */\n protected get maxMessagesToWrite(): number {\n return this.config(\"maxMessagesToWrite\")!;\n }\n\n /**\n * The configured `name` option.\n */\n protected get baseName(): string {\n return this.config(\"name\") ?? \"app\";\n }\n\n /**\n * The `fileName` option, or the chunk's default. `undefined` means the\n * plain `name` of a `single` chunk, used as is (braces included).\n */\n protected get fileNamePattern(): FileNameOption | undefined {\n const configured = this.config(\"fileName\");\n\n if (configured !== undefined) return configured;\n\n switch (this.config(\"chunk\")) {\n case \"daily\":\n return DAILY_FILE_NAME;\n case \"hourly\":\n return HOURLY_FILE_NAME;\n case \"single\":\n default:\n return undefined;\n }\n }\n\n /**\n * Current file name, without extension\n */\n public get fileName(): string {\n const pattern = this.fileNamePattern;\n\n return pattern === undefined\n ? this.baseName\n : renderFileName(pattern, new Date(), this.baseName);\n }\n\n /**\n * Get file extension\n */\n public get extension(): string {\n return this.config(\"extension\")!;\n }\n\n /**\n * Get content\n */\n protected get content() {\n return this.messages.map((message) => message.content).join(EOL) + EOL;\n }\n\n /**\n * Get storage path\n */\n public get storagePath(): string {\n return this.config(\"storagePath\")!;\n }\n\n /**\n * {@inheritdoc}\n */\n protected async init() {\n const logsDirectory = this.storagePath;\n\n await ensureDirectoryAsync(logsDirectory);\n\n this.initMessageFlush();\n\n await this.prune();\n }\n\n /**\n * Remove old log files as configured by `retention`. Runs on boot and\n * whenever a new file is started; call it yourself to prune on demand.\n * Never rejects: failures go to the channel error handler.\n */\n public prune(): Promise<void> {\n const run = (this.pruning ?? Promise.resolve()).then(() => this.pruneFiles());\n\n this.pruning = run;\n\n return run;\n }\n\n /**\n * Prune once a write started a new file: after a size rotation, or when a\n * dated file name rolled over. Never throws.\n */\n protected async afterWrite(): Promise<void> {\n let fileName: string;\n\n try {\n fileName = this.fileName;\n } catch {\n return;\n }\n\n const rolledOver = this.lastFileName !== undefined && this.lastFileName !== fileName;\n\n this.lastFileName = fileName;\n\n if (!rolledOver && !this.retentionDue) return;\n\n this.retentionDue = false;\n\n await this.prune();\n }\n\n /**\n * Apply `retention` to every directory this channel writes to.\n */\n protected async pruneFiles(): Promise<void> {\n const retention = this.config(\"retention\");\n\n if (!retention || (retention.maxFiles === undefined && retention.maxAgeDays === undefined)) {\n return;\n }\n\n try {\n const matcher = this.retentionMatcher(retention);\n\n if (!matcher) return;\n\n const activeFile = `${this.fileName}.${this.extension}`;\n\n for (const directory of await this.retentionDirectories()) {\n await this.pruneDirectory(directory, matcher, retention, activeFile);\n }\n } catch (error) {\n this.reportRetentionError(error, this.storagePath);\n }\n }\n\n /**\n * The expression a file name must match to be pruned, or `undefined` when\n * none can be derived (a function `fileName` without `retention.match`).\n */\n protected retentionMatcher(retention: FileLogRetention): RegExp | undefined {\n if (retention.match) {\n // Drop `g`/`y`: their `lastIndex` would make `test()` stateful.\n return new RegExp(retention.match.source, retention.match.flags.replace(/[gy]/g, \"\"));\n }\n\n const pattern = this.fileNamePattern;\n\n if (typeof pattern === \"function\") {\n if (!this.missingMatchReported) {\n this.missingMatchReported = true;\n this.reportRetentionError(\n new Error(\n \"FileLog retention needs `retention.match` when `fileName` is a function; no files were pruned\",\n ),\n this.storagePath,\n );\n }\n\n return undefined;\n }\n\n const name = this.baseName;\n const fileSource =\n pattern === undefined ? escapeRegExp(name) : fileNamePatternSource(pattern, name);\n const rotateName = this.config(\"rotateFileName\") ?? ROTATE_FILE_NAME;\n const rotateSource =\n typeof rotateName === \"function\" ? \".+\" : fileNamePatternSource(rotateName, name);\n\n return new RegExp(\n `^${fileSource}(?:-${rotateSource}-\\\\d{13,})?\\\\.${escapeRegExp(this.extension)}$`,\n );\n }\n\n /**\n * The log directory, or each group directory when `groupBy` is set.\n */\n protected async retentionDirectories(): Promise<string[]> {\n let directories = [this.storagePath];\n const depth = this.config(\"groupBy\")?.length ?? 0;\n\n for (let level = 0; level < depth; level++) {\n const next: string[] = [];\n\n for (const directory of directories) {\n const entries = await fs.promises\n .readdir(directory, { withFileTypes: true })\n .catch((error: NodeJS.ErrnoException) => {\n if (error.code !== \"ENOENT\") this.reportRetentionError(error, directory);\n return [];\n });\n\n for (const entry of entries) {\n if (entry.isDirectory()) next.push(path.join(directory, entry.name));\n }\n }\n\n directories = next;\n }\n\n return directories;\n }\n\n /**\n * Remove the matching files of one directory that `retention` no longer\n * keeps. Each failure is reported and the rest still run.\n */\n protected async pruneDirectory(\n directory: string,\n matcher: RegExp,\n retention: FileLogRetention,\n activeFile: string,\n ): Promise<void> {\n let names: string[];\n\n try {\n names = await fs.promises.readdir(directory);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, directory);\n }\n return;\n }\n\n const candidates: Array<{ filePath: string; name: string; modifiedAt: number }> = [];\n\n for (const name of names) {\n if (name === activeFile || !matcher.test(name)) continue;\n\n const filePath = path.join(directory, name);\n\n try {\n const stats = await fs.promises.stat(filePath);\n\n if (stats.isFile()) candidates.push({ filePath, name, modifiedAt: stats.mtimeMs });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, filePath);\n }\n }\n }\n\n // Newest first; the name breaks ties so the order is stable.\n candidates.sort((a, b) => b.modifiedAt - a.modifiedAt || (a.name < b.name ? 1 : -1));\n\n // The file being written counts toward `maxFiles` and is never removed.\n const keep =\n retention.maxFiles === undefined\n ? Infinity\n : retention.maxFiles - (names.includes(activeFile) ? 1 : 0);\n const oldestKept =\n retention.maxAgeDays === undefined ? -Infinity : Date.now() - retention.maxAgeDays * DAY_MS;\n\n for (const [index, candidate] of candidates.entries()) {\n if (index < keep && candidate.modifiedAt >= oldestKept) continue;\n\n try {\n await fs.promises.unlink(candidate.filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, candidate.filePath);\n }\n }\n }\n }\n\n /**\n * Send a retention failure to the channel error handler.\n */\n protected reportRetentionError(error: unknown, target: string): void {\n this.reportError(error, {\n type: \"error\",\n module: \"logger\",\n action: \"retention\",\n message: `Log retention failed for ${target}`,\n });\n }\n\n /**\n * Synchronously flush messages\n */\n public flushSync(): void {\n if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) return;\n\n if (this.messagedShouldBeGrouped) {\n this.prepareGroupedMessages();\n // `Object.entries` rather than `for...in` + index: under\n // `noUncheckedIndexedAccess` an index read is `LogMessage[] | undefined`\n // even when the key came from the object itself, and entries hands over\n // the value already narrowed. Same iteration, no assertion.\n for (const [key, groupMessages] of Object.entries(this.groupedMessages)) {\n const directoryPath = path.join(this.storagePath, key);\n fs.mkdirSync(directoryPath, { recursive: true });\n const filePath = path.join(directoryPath, `${this.fileName}.${this.extension}`);\n const content = groupMessages.map((message) => message.content).join(EOL) + EOL;\n fs.appendFileSync(filePath, content);\n }\n } else {\n fs.mkdirSync(this.storagePath, { recursive: true });\n fs.appendFileSync(this.filePath, this.content);\n }\n\n this.onSave();\n }\n\n /**\n * Asynchronously drain buffered entries to disk.\n *\n * The async analogue of {@link flushSync}: it reuses the same async writer\n * as the background interval, so a caller on a graceful-shutdown path can\n * `await channel.flush()` (or `await log.flush()`) and rely on the buffer\n * being on disk once it resolves. `JSONFileLog` inherits this unchanged —\n * its overridden `writeMessagesToFile` performs the JSON merge.\n */\n public async flush(): Promise<void> {\n if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) {\n return;\n }\n\n // Clear the in-flight lock so a deliberate drain is never short-circuited\n // by a half-finished background write, then await the async writer to\n // completion — unlike the fire-and-forget interval, callers depend on the\n // buffer reaching disk before this resolves.\n this.isWriting = false;\n\n await this.writeMessagesToFile();\n }\n\n /**\n * {@inheritdoc}\n */\n public async log(data: LoggingData) {\n const { module, action, message, type: level, context } = data;\n\n if (!this.shouldBeLogged(data)) return;\n\n const { date: dateFormat, time } = this.getDateAndTimeFormat();\n\n const date = dayjs().format(dateFormat + \" \" + time);\n\n let content = `[${date}] [${level}] [${module}][${action}]: `;\n\n let stack: string | undefined;\n\n // check if message is an instance of Error\n if (message instanceof Error) {\n // in that case we need to store the error message and stack trace\n content += message.message + EOL;\n content += `[trace]` + EOL;\n content += message.stack;\n stack = message.stack;\n } else {\n content += message;\n }\n\n this.messages.push({\n content,\n level,\n date,\n module,\n action,\n stack,\n context,\n timestamp: new Date().toISOString(),\n });\n\n await this.checkIfMessagesShouldBeWritten(); // Immediate check on buffer size\n }\n\n /**\n * Check if messages should be written\n */\n protected async checkIfMessagesShouldBeWritten() {\n if (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5000) {\n await this.writeMessagesToFile();\n }\n }\n\n /**\n * Should be called after messages are saved\n */\n protected onSave() {\n this.messages = [];\n this.groupedMessages = {};\n this.isWriting = false;\n this.lastWriteTime = Date.now();\n }\n\n /**\n * Check if messages should be grouped\n */\n protected get messagedShouldBeGrouped(): boolean {\n return Number(this.config(\"groupBy\")?.length) > 0;\n }\n\n /**\n * Write messages to the file\n */\n protected async writeMessagesToFile() {\n if (this.messages.length === 0 || this.isWriting || !this.isInitialized) return;\n\n this.isWriting = true;\n\n if (this.messagedShouldBeGrouped) {\n return await this.writeGroupedMessagesToFile();\n }\n\n try {\n const filePath = this.filePath;\n\n await this.checkAndRotateFile(filePath); // Ensure we check file size before writing\n await this.write(filePath, this.content);\n this.onSave();\n } catch (error) {\n console.error(\"Failed to write log:\", error);\n // Implement fallback logic here\n this.isWriting = false;\n return;\n }\n\n await this.afterWrite();\n }\n\n /**\n * Write grouped messages to the file\n */\n protected async writeGroupedMessagesToFile(): Promise<void> {\n // first step, is to group the messages\n this.prepareGroupedMessages();\n\n // now each key in the grouped messages, represents the directory path that should extend the storage path\n for (const [key, groupMessages] of Object.entries(this.groupedMessages)) {\n const directoryPath = path.join(this.storagePath, key);\n\n try {\n await ensureDirectoryAsync(directoryPath);\n\n const filePath = path.join(directoryPath, `${this.fileName}.${this.extension}`);\n\n await this.checkAndRotateFile(filePath); // Ensure we check file size before writing\n\n const content = groupMessages.map((message) => message.content).join(EOL) + EOL;\n\n await this.write(filePath, content);\n } catch (error) {\n console.error(\"Failed to write log:\", error);\n }\n }\n\n this.onSave();\n this.isWriting = false;\n\n await this.afterWrite();\n }\n\n /**\n * Prepare grouped messages\n */\n protected prepareGroupedMessages(): void {\n this.messages.forEach((message) => {\n const key = this.config(\"groupBy\")!\n .map((groupKey) => encodeURIComponent(message[groupKey]))\n .join(\"/\");\n\n this.groupedMessages[key] = this.groupedMessages[key] || [];\n this.groupedMessages[key].push(message);\n });\n }\n\n /**\n * Start writing to the file\n */\n protected async write(filePath: string, content: string) {\n return new Promise((resolve, reject) => {\n const writer = fs.createWriteStream(filePath, { flags: \"a\" });\n\n writer.write(content, (error) => {\n writer.end();\n if (error) {\n reject(error);\n } else {\n resolve(true);\n }\n });\n });\n }\n}\n\n/**\n * Reject a `retention` that could never keep or remove anything sensibly.\n */\nfunction assertRetention(retention: FileLogRetention | undefined): void {\n if (!retention) return;\n\n const { maxFiles, maxAgeDays, match } = retention;\n\n if (maxFiles !== undefined && (!Number.isInteger(maxFiles) || maxFiles < 1)) {\n throw new TypeError(\"FileLog retention.maxFiles must be a positive integer\");\n }\n\n if (maxAgeDays !== undefined && (!Number.isFinite(maxAgeDays) || maxAgeDays <= 0)) {\n throw new TypeError(\"FileLog retention.maxAgeDays must be a positive number\");\n }\n\n if (match !== undefined && !(match instanceof RegExp)) {\n throw new TypeError(\"FileLog retention.match must be a RegExp\");\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"file-log.mjs","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-log.ts"],"sourcesContent":["import { ensureDirectoryAsync } from \"@warlock.js/fs\";\nimport dayjs from \"dayjs\";\nimport fs from \"fs\";\nimport { EOL } from \"os\";\nimport path from \"path\";\nimport { LogChannel } from \"../log-channel\";\nimport type {\n BasicLogConfigurations,\n LogContract,\n LoggingData,\n LogLevel,\n LogMessage,\n} from \"../types\";\nimport {\n escapeRegExp,\n fileNamePatternSource,\n renderFileName,\n type FileNameOption,\n} from \"./file-name-pattern\";\n\nexport type { FileNameOption } from \"./file-name-pattern\";\n\n/** Default file name of a `daily` chunk: sortable ISO date. */\nexport const DAILY_FILE_NAME = \"{YYYY}-{MM}-{DD}\";\n\n/** Default file name of an `hourly` chunk: sortable ISO date and hour. */\nexport const HOURLY_FILE_NAME = \"{YYYY}-{MM}-{DD}-{HH}\";\n\n/** Default date part of a size-rotated file's name. */\nexport const ROTATE_FILE_NAME = \"{YYYY}-{MM}-{DD}\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Which old log files `FileLog` removes, on boot and whenever it starts a new\n * file (a size rotation or a dated name rolling over). Only files in the log\n * directory (each group directory with `groupBy`) whose names match the\n * channel's file name pattern are considered; the file being written is\n * always kept.\n */\nexport type FileLogRetention = {\n /**\n * Keep at most this many matching files per directory, newest (by\n * modification time) first, counting the file being written.\n */\n maxFiles?: number;\n /**\n * Remove matching files last modified more than this many days ago.\n */\n maxAgeDays?: number;\n /**\n * Which file names (with extension) belong to this channel. Defaults to one\n * derived from `fileName` and `rotateFileName`; required when `fileName` is\n * a function.\n */\n match?: RegExp;\n};\n\nexport type FileLogConfig = BasicLogConfigurations & {\n storagePath?: string;\n /**\n * Base name, without extension: the file name of a `single` chunk and the\n * `{name}` token of a `fileName` pattern.\n *\n * @default app\n */\n name?: string;\n /**\n * The file name, without extension: a pattern such as\n * `\"app-{YYYY}-{MM}-{DD}\"` (tokens `{YYYY}` `{MM}` `{DD}` `{HH}` `{mm}`\n * `{name}`, local time) or a function of the current date. Evaluated at\n * every write, so a dated name starts a new file when it changes.\n *\n * @default by chunk: `single` → name, `daily` → `{YYYY}-{MM}-{DD}`, `hourly` → `{YYYY}-{MM}-{DD}-{HH}`\n */\n fileName?: FileNameOption;\n /**\n * chunk mode: picks the default `fileName`.\n * `single` writes one file named `name`, `daily` one file per day\n * (`YYYY-MM-DD`), `hourly` one per hour (`YYYY-MM-DD-HH`). Size rotation\n * applies to each.\n * @default single\n */\n chunk?: \"single\" | \"daily\" | \"hourly\";\n /**\n * Whether to rotate the file\n *\n * @default true\n */\n rotate?: boolean;\n /**\n * File Extension\n *\n * @default log\n */\n extension?: string;\n /**\n * Middle part of a size-rotated file's name:\n * `<file name>-<rotateFileName>-<epoch ms>.<extension>`. Same forms as\n * `fileName` (a token pattern or a function of the rotation date); text\n * without tokens is used as is.\n *\n * @default {YYYY}-{MM}-{DD}\n */\n rotateFileName?: FileNameOption;\n /**\n * Max file size before rotating the file\n *\n * @default 10MB\n */\n maxFileSize?: number;\n /**\n * Remove old log files on boot and whenever a new file is started.\n *\n * @default none (nothing is removed)\n */\n retention?: FileLogRetention;\n /**\n * Set the max messages that needs to be added before writing to the file\n *\n * @default 100\n */\n maxMessagesToWrite?: number;\n /**\n * Group logs by\n * Please note that the order matters here\n * For example, if you set `groupBy: ['level', 'module']`, the logs will be added in level name first, then by module\n *\n * @default none\n */\n groupBy?: (\"level\" | \"module\" | \"action\")[];\n /**\n * Define what levels should be logged\n *\n * @default all\n */\n levels?: LogLevel[];\n /**\n * Date and time format\n */\n dateFormat?: {\n date?: string;\n time?: string;\n };\n};\n\nexport class FileLog extends LogChannel<FileLogConfig> implements LogContract {\n /**\n * {@inheritdoc}\n */\n public name = \"file\";\n\n /**\n * Messages buffer\n */\n protected messages: LogMessage[] = [];\n\n /**\n * Grouped messages\n */\n protected groupedMessages: Record<string, LogMessage[]> = {};\n\n /**\n * Default channel configurations\n */\n protected defaultConfigurations: FileLogConfig = {\n storagePath: process.cwd() + \"/storage/logs\",\n rotate: true,\n name: \"app\",\n extension: \"log\",\n chunk: \"single\",\n maxMessagesToWrite: 100,\n filter: () => true,\n maxFileSize: 10 * 1024 * 1024, // 10MB\n rotateFileName: ROTATE_FILE_NAME,\n dateFormat: {\n date: \"DD-MM-YYYY\",\n time: \"HH:mm:ss\",\n },\n };\n\n /**\n * Last write time\n */\n protected lastWriteTime = Date.now();\n\n /**\n * A flag to determine if the file is being written\n */\n protected isWriting = false;\n\n /**\n * Handle for the periodic flush interval. Stored so it can be cleared\n * in `dispose()` — long-lived processes that create channels dynamically\n * would otherwise leak one timer per channel.\n */\n protected flushIntervalHandle?: NodeJS.Timeout;\n\n /**\n * Set when a size rotation started a new file, so the next write prunes.\n */\n protected retentionDue = false;\n\n /**\n * File name of the last write, to notice a dated name rolling over.\n */\n protected lastFileName?: string;\n\n /**\n * The running (or last) prune, so prunes never overlap.\n */\n protected pruning?: Promise<void>;\n\n /**\n * Whether the \"function `fileName` needs `retention.match`\" error was\n * already reported.\n */\n protected missingMatchReported = false;\n\n /**\n * {@inheritdoc}\n */\n protected setConfigurations(configurations: FileLogConfig) {\n assertRetention(configurations.retention);\n\n return super.setConfigurations(configurations);\n }\n\n /**\n * Check file size for file rotation\n */\n protected async checkAndRotateFile(filePath = this.filePath) {\n if (!this.config(\"rotate\")) return;\n\n try {\n const stats = await fs.promises.stat(filePath);\n if (stats.size >= this.config(\"maxFileSize\")!) {\n await this.rotateLogFile(filePath);\n }\n } catch (error: any) {\n // ENOENT is expected when the file hasn't been created yet — there is\n // nothing to rotate, so stay silent. Surface anything else.\n if (error.code !== \"ENOENT\") {\n console.error(\"Error checking log file:\", error);\n }\n }\n }\n\n /**\n * Rotate the given log file (the active one by default) aside as\n * `<file name>-<rotateFileName>-<epoch ms>.<extension>` in its directory.\n */\n protected async rotateLogFile(filePath = this.filePath) {\n const now = new Date();\n const extension = this.extension;\n const baseName = path.basename(filePath, `.${extension}`);\n const rotateName = renderFileName(\n this.config(\"rotateFileName\") ?? ROTATE_FILE_NAME,\n now,\n this.baseName,\n );\n\n const rotatedFilePath = path.join(\n path.dirname(filePath),\n `${baseName}-${rotateName}-${now.getTime()}.${extension}`,\n );\n\n await fs.promises.rename(filePath, rotatedFilePath).then(\n () => {\n this.retentionDue = true;\n },\n (error) => {\n console.error(\"Error rotating file:\", error);\n },\n );\n }\n\n /**\n * Flush messages\n *\n * Starts a periodic re-check so low-traffic channels don't sit on buffered\n * entries indefinitely. The handle is stored on the instance so `dispose()`\n * can stop it — without this, every channel leaks a timer for the lifetime\n * of the process.\n */\n protected initMessageFlush() {\n this.flushIntervalHandle = setInterval(() => {\n if (\n this.messages.length > 0 &&\n (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5000)\n ) {\n this.writeMessagesToFile();\n }\n }, 5000);\n }\n\n /**\n * Stop the background flush interval and drain any buffered entries.\n *\n * Call this when discarding a channel (e.g. reconfiguring the logger at\n * runtime) so the 5-second timer doesn't keep the event loop alive. Safe to\n * call more than once.\n */\n public dispose(): void {\n if (this.flushIntervalHandle) {\n clearInterval(this.flushIntervalHandle);\n this.flushIntervalHandle = undefined;\n }\n\n this.flushSync();\n }\n\n /**\n * Get file path\n */\n public get filePath() {\n const fileName = this.fileName;\n\n const extension = this.extension;\n\n return path.join(this.storagePath, `${fileName}.${extension}`);\n }\n\n /**\n * Get max messages\n */\n protected get maxMessagesToWrite(): number {\n return this.config(\"maxMessagesToWrite\")!;\n }\n\n /**\n * The configured `name` option.\n */\n protected get baseName(): string {\n return this.config(\"name\") ?? \"app\";\n }\n\n /**\n * The `fileName` option, or the chunk's default. `undefined` means the\n * plain `name` of a `single` chunk, used as is (braces included).\n */\n protected get fileNamePattern(): FileNameOption | undefined {\n const configured = this.config(\"fileName\");\n\n if (configured !== undefined) return configured;\n\n switch (this.config(\"chunk\")) {\n case \"daily\":\n return DAILY_FILE_NAME;\n case \"hourly\":\n return HOURLY_FILE_NAME;\n case \"single\":\n default:\n return undefined;\n }\n }\n\n /**\n * Current file name, without extension\n */\n public get fileName(): string {\n const pattern = this.fileNamePattern;\n\n return pattern === undefined\n ? this.baseName\n : renderFileName(pattern, new Date(), this.baseName);\n }\n\n /**\n * Get file extension\n */\n public get extension(): string {\n return this.config(\"extension\")!;\n }\n\n /**\n * Get content\n */\n protected get content() {\n return this.messages.map((message) => message.content).join(EOL) + EOL;\n }\n\n /**\n * Get storage path\n */\n public get storagePath(): string {\n return this.config(\"storagePath\")!;\n }\n\n /**\n * {@inheritdoc}\n */\n protected async init() {\n const logsDirectory = this.storagePath;\n\n await ensureDirectoryAsync(logsDirectory);\n\n this.initMessageFlush();\n\n await this.prune();\n }\n\n /**\n * Remove old log files as configured by `retention`. Runs on boot and\n * whenever a new file is started; call it yourself to prune on demand.\n * Never rejects: failures go to the channel error handler.\n */\n public prune(): Promise<void> {\n const run = (this.pruning ?? Promise.resolve()).then(() => this.pruneFiles());\n\n this.pruning = run;\n\n return run;\n }\n\n /**\n * Prune once a write started a new file: after a size rotation, or when a\n * dated file name rolled over. Never throws.\n */\n protected async afterWrite(): Promise<void> {\n let fileName: string;\n\n try {\n fileName = this.fileName;\n } catch {\n return;\n }\n\n const rolledOver = this.lastFileName !== undefined && this.lastFileName !== fileName;\n\n this.lastFileName = fileName;\n\n if (!rolledOver && !this.retentionDue) return;\n\n this.retentionDue = false;\n\n await this.prune();\n }\n\n /**\n * Apply `retention` to every directory this channel writes to.\n */\n protected async pruneFiles(): Promise<void> {\n const retention = this.config(\"retention\");\n\n if (!retention || (retention.maxFiles === undefined && retention.maxAgeDays === undefined)) {\n return;\n }\n\n try {\n const matcher = this.retentionMatcher(retention);\n\n if (!matcher) return;\n\n const activeFile = `${this.fileName}.${this.extension}`;\n\n for (const directory of await this.retentionDirectories()) {\n await this.pruneDirectory(directory, matcher, retention, activeFile);\n }\n } catch (error) {\n this.reportRetentionError(error, this.storagePath);\n }\n }\n\n /**\n * The expression a file name must match to be pruned, or `undefined` when\n * none can be derived (a function `fileName` without `retention.match`).\n */\n protected retentionMatcher(retention: FileLogRetention): RegExp | undefined {\n if (retention.match) {\n // Drop `g`/`y`: their `lastIndex` would make `test()` stateful.\n return new RegExp(retention.match.source, retention.match.flags.replace(/[gy]/g, \"\"));\n }\n\n const pattern = this.fileNamePattern;\n\n if (typeof pattern === \"function\") {\n if (!this.missingMatchReported) {\n this.missingMatchReported = true;\n this.reportRetentionError(\n new Error(\n \"FileLog retention needs `retention.match` when `fileName` is a function; no files were pruned\",\n ),\n this.storagePath,\n );\n }\n\n return undefined;\n }\n\n const name = this.baseName;\n const fileSource =\n pattern === undefined ? escapeRegExp(name) : fileNamePatternSource(pattern, name);\n const rotateName = this.config(\"rotateFileName\") ?? ROTATE_FILE_NAME;\n const rotateSource =\n typeof rotateName === \"function\" ? \".+\" : fileNamePatternSource(rotateName, name);\n\n return new RegExp(\n `^${fileSource}(?:-${rotateSource}-\\\\d{13,})?\\\\.${escapeRegExp(this.extension)}$`,\n );\n }\n\n /**\n * The log directory, or each group directory when `groupBy` is set.\n */\n protected async retentionDirectories(): Promise<string[]> {\n let directories = [this.storagePath];\n const depth = this.config(\"groupBy\")?.length ?? 0;\n\n for (let level = 0; level < depth; level++) {\n const next: string[] = [];\n\n for (const directory of directories) {\n const entries = await fs.promises\n .readdir(directory, { withFileTypes: true })\n .catch((error: NodeJS.ErrnoException) => {\n if (error.code !== \"ENOENT\") this.reportRetentionError(error, directory);\n return [];\n });\n\n for (const entry of entries) {\n if (entry.isDirectory()) next.push(path.join(directory, entry.name));\n }\n }\n\n directories = next;\n }\n\n return directories;\n }\n\n /**\n * Remove the matching files of one directory that `retention` no longer\n * keeps. Each failure is reported and the rest still run.\n */\n protected async pruneDirectory(\n directory: string,\n matcher: RegExp,\n retention: FileLogRetention,\n activeFile: string,\n ): Promise<void> {\n let names: string[];\n\n try {\n names = await fs.promises.readdir(directory);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, directory);\n }\n return;\n }\n\n const candidates: Array<{ filePath: string; name: string; modifiedAt: number }> = [];\n\n for (const name of names) {\n if (name === activeFile || !matcher.test(name)) continue;\n\n const filePath = path.join(directory, name);\n\n try {\n const stats = await fs.promises.stat(filePath);\n\n if (stats.isFile()) candidates.push({ filePath, name, modifiedAt: stats.mtimeMs });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, filePath);\n }\n }\n }\n\n // Newest first; the name breaks ties so the order is stable.\n candidates.sort((a, b) => b.modifiedAt - a.modifiedAt || (a.name < b.name ? 1 : -1));\n\n // The file being written counts toward `maxFiles` and is never removed.\n const keep =\n retention.maxFiles === undefined\n ? Infinity\n : retention.maxFiles - (names.includes(activeFile) ? 1 : 0);\n const oldestKept =\n retention.maxAgeDays === undefined ? -Infinity : Date.now() - retention.maxAgeDays * DAY_MS;\n\n for (const [index, candidate] of candidates.entries()) {\n if (index < keep && candidate.modifiedAt >= oldestKept) continue;\n\n try {\n await fs.promises.unlink(candidate.filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n this.reportRetentionError(error, candidate.filePath);\n }\n }\n }\n }\n\n /**\n * Send a retention failure to the channel error handler.\n */\n protected reportRetentionError(error: unknown, target: string): void {\n this.reportError(error, {\n type: \"error\",\n module: \"logger\",\n action: \"retention\",\n message: `Log retention failed for ${target}`,\n });\n }\n\n /**\n * Synchronously flush messages\n */\n public flushSync(): void {\n if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) return;\n\n if (this.messagedShouldBeGrouped) {\n this.prepareGroupedMessages();\n // `Object.entries` rather than `for...in` + index: under\n // `noUncheckedIndexedAccess` an index read is `LogMessage[] | undefined`\n // even when the key came from the object itself, and entries hands over\n // the value already narrowed. Same iteration, no assertion.\n for (const [key, groupMessages] of Object.entries(this.groupedMessages)) {\n const directoryPath = path.join(this.storagePath, key);\n fs.mkdirSync(directoryPath, { recursive: true });\n const filePath = path.join(directoryPath, `${this.fileName}.${this.extension}`);\n const content = groupMessages.map((message) => message.content).join(EOL) + EOL;\n fs.appendFileSync(filePath, content);\n }\n } else {\n fs.mkdirSync(this.storagePath, { recursive: true });\n fs.appendFileSync(this.filePath, this.content);\n }\n\n this.onSave();\n }\n\n /**\n * Asynchronously drain buffered entries to disk.\n *\n * The async analogue of {@link flushSync}: it reuses the same async writer\n * as the background interval, so a caller on a graceful-shutdown path can\n * `await channel.flush()` (or `await log.flush()`) and rely on the buffer\n * being on disk once it resolves. `JSONFileLog` inherits this unchanged —\n * its overridden `writeMessagesToFile` performs the JSON merge.\n */\n public async flush(): Promise<void> {\n if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) {\n return;\n }\n\n // Clear the in-flight lock so a deliberate drain is never short-circuited\n // by a half-finished background write, then await the async writer to\n // completion — unlike the fire-and-forget interval, callers depend on the\n // buffer reaching disk before this resolves.\n this.isWriting = false;\n\n await this.writeMessagesToFile();\n }\n\n /**\n * {@inheritdoc}\n */\n public async log(data: LoggingData) {\n const { module, action, message, type: level, context } = data;\n\n if (!this.shouldBeLogged(data)) return;\n\n const { date: dateFormat, time } = this.getDateAndTimeFormat();\n\n const date = dayjs().format(dateFormat + \" \" + time);\n\n let content = `[${date}] [${level}] [${module}][${action}]: `;\n\n let stack: string | undefined;\n\n // check if message is an instance of Error\n if (message instanceof Error) {\n // in that case we need to store the error message and stack trace\n content += message.message + EOL;\n content += `[trace]` + EOL;\n content += message.stack;\n stack = message.stack;\n } else {\n content += message;\n }\n\n this.messages.push({\n content,\n level,\n date,\n module,\n action,\n stack,\n context,\n timestamp: new Date().toISOString(),\n });\n\n await this.checkIfMessagesShouldBeWritten(); // Immediate check on buffer size\n }\n\n /**\n * Check if messages should be written\n */\n protected async checkIfMessagesShouldBeWritten() {\n if (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5000) {\n await this.writeMessagesToFile();\n }\n }\n\n /**\n * Should be called after messages are saved\n */\n protected onSave() {\n this.messages = [];\n this.groupedMessages = {};\n this.isWriting = false;\n this.lastWriteTime = Date.now();\n }\n\n /**\n * Check if messages should be grouped\n */\n protected get messagedShouldBeGrouped(): boolean {\n return Number(this.config(\"groupBy\")?.length) > 0;\n }\n\n /**\n * Write messages to the file\n */\n protected async writeMessagesToFile() {\n if (this.messages.length === 0 || this.isWriting || !this.isInitialized) return;\n\n this.isWriting = true;\n\n if (this.messagedShouldBeGrouped) {\n return await this.writeGroupedMessagesToFile();\n }\n\n try {\n const filePath = this.filePath;\n\n await this.checkAndRotateFile(filePath); // Ensure we check file size before writing\n await this.write(filePath, this.content);\n this.onSave();\n } catch (error) {\n console.error(\"Failed to write log:\", error);\n // Implement fallback logic here\n this.isWriting = false;\n return;\n }\n\n await this.afterWrite();\n }\n\n /**\n * Write grouped messages to the file\n */\n protected async writeGroupedMessagesToFile(): Promise<void> {\n // first step, is to group the messages\n this.prepareGroupedMessages();\n\n // now each key in the grouped messages, represents the directory path that should extend the storage path\n for (const [key, groupMessages] of Object.entries(this.groupedMessages)) {\n const directoryPath = path.join(this.storagePath, key);\n\n try {\n await ensureDirectoryAsync(directoryPath);\n\n const filePath = path.join(directoryPath, `${this.fileName}.${this.extension}`);\n\n await this.checkAndRotateFile(filePath); // Ensure we check file size before writing\n\n const content = groupMessages.map((message) => message.content).join(EOL) + EOL;\n\n await this.write(filePath, content);\n } catch (error) {\n console.error(\"Failed to write log:\", error);\n }\n }\n\n this.onSave();\n this.isWriting = false;\n\n await this.afterWrite();\n }\n\n /**\n * Prepare grouped messages\n */\n protected prepareGroupedMessages(): void {\n this.messages.forEach((message) => {\n const key = this.config(\"groupBy\")!\n .map((groupKey) => encodeURIComponent(message[groupKey]))\n .join(\"/\");\n\n this.groupedMessages[key] = this.groupedMessages[key] || [];\n this.groupedMessages[key].push(message);\n });\n }\n\n /**\n * Start writing to the file\n */\n protected async write(filePath: string, content: string) {\n return new Promise((resolve, reject) => {\n const writer = fs.createWriteStream(filePath, { flags: \"a\" });\n\n writer.write(content, (error) => {\n writer.end();\n if (error) {\n reject(error);\n } else {\n resolve(true);\n }\n });\n });\n }\n}\n\n/**\n * Reject a `retention` that could never keep or remove anything sensibly.\n */\nfunction assertRetention(retention: FileLogRetention | undefined): void {\n if (!retention) return;\n\n const { maxFiles, maxAgeDays, match } = retention;\n\n if (maxFiles !== undefined && (!Number.isInteger(maxFiles) || maxFiles < 1)) {\n throw new TypeError(\"FileLog retention.maxFiles must be a positive integer\");\n }\n\n if (maxAgeDays !== undefined && (!Number.isFinite(maxAgeDays) || maxAgeDays <= 0)) {\n throw new TypeError(\"FileLog retention.maxAgeDays must be a positive number\");\n }\n\n if (match !== undefined && !(match instanceof RegExp)) {\n throw new TypeError(\"FileLog retention.match must be a RegExp\");\n }\n}\n"],"mappings":"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"}
@@ -10,7 +10,6 @@
10
10
  * @example "app-{YYYY}-{MM}-{DD}" // → "app-2026-10-17"
11
11
  * @example (date) => `audit-${date.getFullYear()}` // → "audit-2026"
12
12
  */
13
- type FileNameOption = string | ((date: Date) => string);
13
+ export type FileNameOption = string | ((date: Date) => string);
14
14
  //#endregion
15
- export { FileNameOption };
16
15
  //# sourceMappingURL=file-name-pattern.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-name-pattern.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-name-pattern.ts"],"mappings":";;AAWA;;;;AAAkD;;;;;;KAAtC,cAAA,cAA4B,IAAU,EAAJ,IAAI"}
1
+ {"version":3,"file":"file-name-pattern.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/file-name-pattern.ts"],"mappings":";;;;;;;;;;;;YAWY,4BAA4B,MAAM"}
@@ -3,4 +3,4 @@ import { DAILY_FILE_NAME, FileLog, HOURLY_FILE_NAME, ROTATE_FILE_NAME } from "./
3
3
  import { JSONFileLog } from "./json-file-log.mjs";
4
4
  import { SentryLog } from "./sentry-log.mjs";
5
5
 
6
- export { };
6
+ export { ConsoleLog, DAILY_FILE_NAME, FileLog, HOURLY_FILE_NAME, JSONFileLog, ROTATE_FILE_NAME, SentryLog };
@@ -1,8 +1,7 @@
1
1
  import { LogContract, LoggingData } from "../types.mjs";
2
2
  import { FileLog } from "./file-log.mjs";
3
-
4
3
  //#region ../../packages/logger/src/channels/json-file-log.d.ts
5
- declare class JSONFileLog extends FileLog implements LogContract {
4
+ export declare class JSONFileLog extends FileLog implements LogContract {
6
5
  /**
7
6
  * {@inheritdoc}
8
7
  */
@@ -29,5 +28,4 @@ declare class JSONFileLog extends FileLog implements LogContract {
29
28
  protected writeGroupedMessagesToFile(): Promise<void>;
30
29
  }
31
30
  //#endregion
32
- export { JSONFileLog };
33
31
  //# sourceMappingURL=json-file-log.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-file-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/json-file-log.ts"],"mappings":";;;;cAQa,WAAA,SAAoB,OAAA,YAAmB,WAAA;;AAApD;;EAIS,IAAA;EA4DgB;;;EAAA,IAvDZ,SAAA;EAToB;;;EAgBxB,SAAA;EAhBwB;;;EAgElB,GAAA,CAAI,IAAA,EAAM,WAAA,GAAW,OAAA;EAhD3B;;;EAAA,UAiFS,mBAAA,IAAuB,OAAA;EAjCL;;;EAAA,UAsFlB,0BAAA,IAA8B,OAAA;AAAA"}
1
+ {"version":3,"file":"json-file-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/json-file-log.ts"],"mappings":";;;qBAQa,oBAAoB,mBAAmB;;;;EAI3C;;;;MAKI;;;;EAOJ;;;;EAgDM,IAAI,MAAM,cAAW;;;;YAiClB,uBAAuB;;;;YAqDvB,8BAA8B"}
@@ -1,6 +1,5 @@
1
1
  import { BasicLogConfigurations, LogLevel, LoggingData } from "../types.mjs";
2
2
  import { LogChannel } from "../log-channel.mjs";
3
-
4
3
  //#region ../../packages/logger/src/channels/sentry-log.d.ts
5
4
  /**
6
5
  * Sentry severity levels — the `@sentry/node` `SeverityLevel` union.
@@ -9,7 +8,7 @@ type SentrySeverityLevel = "fatal" | "error" | "warning" | "log" | "info" | "deb
9
8
  /**
10
9
  * The Sentry `Scope` surface used while building a single event.
11
10
  */
12
- interface SentryScopeLike {
11
+ export interface SentryScopeLike {
13
12
  setLevel(level: SentrySeverityLevel): void;
14
13
  setTags(tags: Record<string, string>): void;
15
14
  setContext(name: string, context: Record<string, unknown> | null): void;
@@ -17,7 +16,7 @@ interface SentryScopeLike {
17
16
  /**
18
17
  * A Sentry breadcrumb, as passed to `addBreadcrumb`.
19
18
  */
20
- type SentryBreadcrumb = {
19
+ export type SentryBreadcrumb = {
21
20
  category?: string;
22
21
  message?: string;
23
22
  level?: SentrySeverityLevel;
@@ -28,7 +27,7 @@ type SentryBreadcrumb = {
28
27
  * namespace satisfies this shape, so an app can pass it straight through as
29
28
  * `client`; a test (or a custom forwarder) can supply a compatible stand-in.
30
29
  */
31
- interface SentryForwarder {
30
+ export interface SentryForwarder {
32
31
  captureException(exception: unknown): string;
33
32
  captureMessage(message: string, level?: SentrySeverityLevel): string;
34
33
  addBreadcrumb(breadcrumb: SentryBreadcrumb): void;
@@ -40,14 +39,14 @@ interface SentryForwarder {
40
39
  * fields; the index signature keeps any other SDK option valid without coupling
41
40
  * to the SDK's types.
42
41
  */
43
- type SentryInitOptions = {
42
+ export type SentryInitOptions = {
44
43
  dsn?: string;
45
44
  environment?: string;
46
45
  release?: string;
47
46
  sampleRate?: number;
48
47
  [key: string]: unknown;
49
48
  };
50
- type SentryLogConfig = BasicLogConfigurations & {
49
+ export type SentryLogConfig = BasicLogConfigurations & {
51
50
  /**
52
51
  * Reuse an already-initialized Sentry instance — typically the `@sentry/node`
53
52
  * namespace from an app that already calls `Sentry.init(...)`. When set, the
@@ -99,7 +98,7 @@ type SentryLogConfig = BasicLogConfigurations & {
99
98
  * // New app — let the channel initialize Sentry
100
99
  * log.addChannel(new SentryLog({ options: { dsn: process.env.SENTRY_DSN } }));
101
100
  */
102
- declare class SentryLog extends LogChannel<SentryLogConfig> {
101
+ export declare class SentryLog extends LogChannel<SentryLogConfig> {
103
102
  /**
104
103
  * {@inheritdoc}
105
104
  */
@@ -178,5 +177,5 @@ declare class SentryLog extends LogChannel<SentryLogConfig> {
178
177
  private reportMissingSdk;
179
178
  }
180
179
  //#endregion
181
- export { SentryBreadcrumb, SentryForwarder, SentryInitOptions, SentryLog, SentryLogConfig, SentryScopeLike };
180
+ export {};
182
181
  //# sourceMappingURL=sentry-log.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentry-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/sentry-log.ts"],"mappings":";;;;;;AAC8E;KAgBzE,mBAAA;;;AAAmB;UAKP,eAAA;EACf,QAAA,CAAS,KAAA,EAAO,mBAAA;EAChB,OAAA,CAAQ,IAAA,EAAM,MAAA;EACd,UAAA,CAAW,IAAA,UAAc,OAAA,EAAS,MAAA;AAAA;;;;KAMxB,gBAAA;EACV,QAAA;EACA,OAAA;EACA,KAAA,GAAQ,mBAAA;EACR,IAAA,GAAO,MAAM;AAAA;;;;;;UAQE,eAAA;EACf,gBAAA,CAAiB,SAAA;EACjB,cAAA,CAAe,OAAA,UAAiB,KAAA,GAAQ,mBAAA;EACxC,aAAA,CAAc,UAAA,EAAY,gBAAA;EAC1B,SAAA,CAAU,QAAA,GAAW,KAAA,EAAO,eAAA;EAC5B,KAAA,CAAM,OAAA,YAAmB,OAAA;AAAA;;;;;;KAQf,iBAAA;EACV,GAAA;EACA,WAAA;EACA,OAAA;EACA,UAAA;EAAA,CACC,GAAA;AAAA;AAAA,KAyDS,eAAA,GAAkB,sBAAA;EAtEI;;;;;EA4EhC,MAAA,GAAS,eAAA;EA/E+B;;;;;EAqFxC,OAAA,GAAU,iBAAA;EAnFkB;;;;;;;EA2F5B,WAAA,GAAc,QAAA;EAlFJ;;;;;EAwFV,YAAA;AAAA;;;;AAnFY;AAyDd;;;;;;;;;;;;;;;;;;AA0Bc;AA2Bd;cAAa,SAAA,SAAkB,UAAA,CAAW,eAAA;;;;EAIjC,IAAA;EAqDiB;;;EAhDjB,WAAA;EATsB;;;EAAA,UAenB,qBAAA,EAAuB,eAAA;EAfO;;;;;EAAA,QAyBhC,MAAA;EAMA;;;;EAAA,QAAA,aAAA;EA0BgB;;;;;;;cAjBL,cAAA,GAAiB,eAAA;EAmH5B;;;;;AAiEgB;;EAjEhB,UAlGQ,IAAA,IAAQ,OAAA;;;;EA2BX,GAAA,CAAI,IAAA,EAAM,WAAA,GAAc,OAAA;;;;;EAiDxB,KAAA,IAAS,OAAA;;;;UAWd,YAAA;;;;;;;;UAWA,YAAA;;;;;UAiCA,aAAA;;;;;UAeA,MAAA;;;;;;UAiBA,gBAAA;AAAA"}
1
+ {"version":3,"file":"sentry-log.d.mts","names":[],"sources":["../../../../../../../../packages/logger/src/channels/sentry-log.ts"],"mappings":";;;;;;KAiBK;;;;iBAKY;EACf,SAAS,OAAO;EAChB,QAAQ,MAAM;EACd,WAAW,cAAc,SAAS;;;;;YAMxB;EACV;EACA;EACA,QAAQ;EACR,OAAO;;;;;;;iBAQQ;EACf,iBAAiB;EACjB,eAAe,iBAAiB,QAAQ;EACxC,cAAc,YAAY;EAC1B,UAAU,WAAW,OAAO;EAC5B,MAAM,mBAAmB;;;;;;;YAQf;EACV;EACA;EACA;EACA;GACC;;YAyDS,kBAAkB;;;;;;EAM5B,SAAS;;;;;;EAMT,UAAU;;;;;;;;EAQV,cAAc;;;;;;EAMd;;;;;;;;;;;;;;;;;;;;;;;;;;qBA2BW,kBAAkB,WAAW;;;;EAIjC;;;;EAKA;;;;YAMG,uBAAuB;;;;;;UAUzB;;;;;UAMA;;;;;;;;EASR,YAAmB,iBAAiB;;;;;;;;YAiBpB,QAAQ;;;;EA2BX,IAAI,MAAM,cAAc;;;;;EAiDxB,SAAS;;;;UAWd;;;;;;;;UAWA;;;;;UAiCA;;;;;UAeA;;;;;;UAiBA"}
@@ -1,13 +1,12 @@
1
1
  import { BasicLogConfigurations, LogContract, LoggingData, RedactConfig } from "./types.mjs";
2
-
3
2
  //#region ../../packages/logger/src/log-channel.d.ts
4
3
  /**
5
4
  * Receives a failure the channel hits outside a `log()` call (for example
6
5
  * `FileLog` retention). The logger installs one that forwards to its
7
6
  * `onChannelError` handler.
8
7
  */
9
- type ChannelErrorReporter = (error: unknown, entry: LoggingData) => void;
10
- declare abstract class LogChannel<Options extends BasicLogConfigurations = BasicLogConfigurations> implements LogContract {
8
+ export type ChannelErrorReporter = (error: unknown, entry: LoggingData) => void;
9
+ export declare abstract class LogChannel<Options extends BasicLogConfigurations = BasicLogConfigurations> implements LogContract {
11
10
  /**
12
11
  * Channel name
13
12
  */
@@ -104,5 +103,4 @@ declare abstract class LogChannel<Options extends BasicLogConfigurations = Basic
104
103
  protected withBasicConfigurations(configurations: Partial<Options>): Options;
105
104
  }
106
105
  //#endregion
107
- export { ChannelErrorReporter, LogChannel };
108
106
  //# sourceMappingURL=log-channel.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"log-channel.d.mts","names":[],"sources":["../../../../../../../packages/logger/src/log-channel.ts"],"mappings":";;;;;AAOA;;;KAAY,oBAAA,IAAwB,KAAA,WAAgB,KAAA,EAAO,WAAW;AAAA,uBAEhD,UAAA,iBACJ,sBAAA,GAAyB,sBAAA,aAC9B,WAAA;EAJ8C;;;EAQlD,IAAA;EANa;;;EAWb,WAAA;EAVkC;;;EAelC,QAAA;EA0B6B;;;EAAA,UArB1B,qBAAA,EAAuB,OAAA;EAsEA;;;EAAA,UAjEvB,qBAAA,EAAuB,OAAA;EAwEW;;;EAAA,UAnElC,aAAA;EA+Gc;;;;EAAA,UAzGd,aAAA,GAAgB,oBAAA;EAnCf;;;cAwCQ,cAAA,GAAiB,OAAA;EAzCpB;;;;;EA4DT,gBAAA,CAAiB,QAAA,EAAU,oBAAA;EAxCxB;;;;EAAA,UAgDA,WAAA,CAAY,KAAA,WAAgB,KAAA,EAAO,WAAA;EAhCnC;;;EAAA,UAiDA,IAAA,YAAgB,OAAA;EA5CP;;;EAAA,UAiDT,MAAA,iBAAuB,OAAA,EAAS,GAAA,EAAK,CAAA,GAAI,OAAA,CAAQ,CAAA;EAtBjD;;;EAAA,UA6BA,iBAAA,CAAkB,cAAA,EAAgB,OAAA;EAZlC;;;EAAA,UAwBA,cAAA,CAAe,IAAA,EAAM,WAAA;EAnBE;;;EAAA,SAqCjB,GAAA,CAAI,IAAA,EAAM,WAAA,UAAqB,OAAA;EArCY;;;EA0CpD,SAAA;EAvBG;;;;;;;EAgCH,KAAA,YAAiB,OAAA;EAAjB;;;;;;EAQA,eAAA,IAAmB,YAAA;EAkBhB;;;EAAA,UAXA,oBAAA;;;;;;;YAWA,uBAAA,CAAwB,cAAA,EAAgB,OAAA,CAAQ,OAAA,IAAW,OAAA;AAAA"}
1
+ {"version":3,"file":"log-channel.d.mts","names":[],"sources":["../../../../../../../packages/logger/src/log-channel.ts"],"mappings":";;;;;;;YAOY,wBAAwB,gBAAgB,OAAO;8BAErC,WACpB,gBAAgB,yBAAyB,mCAC9B;;;;EAIJ;;;;EAKA;;;;EAKA;;;;YAKG,uBAAuB;;;;YAKvB,uBAAuB;;;;YAKvB;;;;;YAMA,gBAAgB;;;;EAK1B,YAAmB,iBAAiB;;;;;;EAmB7B,iBAAiB,UAAU;;;;;YAQxB,YAAY,gBAAgB,OAAO;;;;YAiBnC,gBAAgB;;;;YAKhB,OAAO,gBAAgB,SAAS,KAAK,IAAI,QAAQ;;;;YAOjD,kBAAkB,gBAAgB;;;;YAYlC,eAAe,MAAM;;;;WAkBf,IAAI,MAAM,qBAAqB;;;;EAKxC;;;;;;;;EASA,iBAAiB;;;;;;;EAQjB,mBAAmB;;;;YAOhB;;;;;;;YAWA,wBAAwB,gBAAgB,QAAQ,WAAW"}
package/esm/logger.d.mts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { AutoFlushEvent, BasicLogConfigurations, ChannelErrorHandler, LogLevel, LoggingData, OmittedLoggingData, RedactConfig } from "./types.mjs";
2
2
  import { LogChannel } from "./log-channel.mjs";
3
-
4
3
  //#region ../../packages/logger/src/logger.d.ts
5
- declare class Logger {
4
+ export declare class Logger {
6
5
  /**
7
6
  * Current channel
8
7
  */
@@ -254,7 +253,7 @@ declare class Logger {
254
253
  * Default `timeout` of {@link Logger.flush}: long enough for a healthy network
255
254
  * channel, short enough that a hung one cannot eat a shutdown budget.
256
255
  */
257
- declare const DEFAULT_FLUSH_TIMEOUT_MS = 5000;
256
+ export declare const DEFAULT_FLUSH_TIMEOUT_MS = 5000;
258
257
  /**
259
258
  * The package singleton. Use this for everyday logging — `log.info(...)`,
260
259
  * `log.error(...)`, `log.configure(...)`. Custom logger instances can be
@@ -269,7 +268,6 @@ declare const DEFAULT_FLUSH_TIMEOUT_MS = 5000;
269
268
  * collapsed into a single name. Use `log.info(...)` (or any other level
270
269
  * shortcut) to emit entries.
271
270
  */
272
- declare const log: Logger;
271
+ export declare const log: Logger;
273
272
  //#endregion
274
- export { DEFAULT_FLUSH_TIMEOUT_MS, Logger, log };
275
273
  //# sourceMappingURL=logger.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.mts","names":[],"sources":["../../../../../../../packages/logger/src/logger.ts"],"mappings":";;;;cAsCa,MAAA;;AAAb;;EAIS,QAAA,EAAU,UAAA;EAEV,EAAA;EA0CoB;;;;;EAAA,QAnCnB,iBAAA;EAoFuB;;;;;;EAAA,QA5EvB,QAAA;EA2SQ;;;;;;EAAA,QAnSR,YAAA;EA6UI;;;;;;EAAA,QArUJ,iBAAA;EA2YqD;;;;EAAA,QArYrD,mBAAA;EAwhBqC;;;EAnhBtC,UAAA,CAAW,OAAA,EAAS,UAAA;EAnCnB;;;EA4CD,SAAA,CAAU,MAAA;IACf,QAAA,GAAW,UAAA;IACX,WAAA,GAAc,cAAA;IACd,QAAA,GAAW,QAAA;IACX,MAAA,GAAS,YAAA;IACT,cAAA,GAAiB,mBAAA;EAAA;EAJN;;;;;;;;;;EAuCN,cAAA,CAAe,OAAA,EAAS,mBAAA;EAAA;;;;;;;;;;;EAgBxB,SAAA,CAAU,MAAA,EAAQ,YAAA;EAqClB;;;EA7BA,SAAA,IAAa,YAAA;EAsDZ;;;;;;;;;;EAxCD,WAAA,CAAY,KAAA,EAAO,QAAA;EA4Ld;;;EApLL,WAAA,IAAe,QAAA;EA8LpB;;;EAvLK,WAAA,CAAY,QAAA,EAAU,UAAA;EA0L3B;;;;EAAA,QA5KM,aAAA;EAwLN;;;EAAA,QA7KM,gBAAA;EAwLQ;;;;;;;;;;;;;;EAhJT,GAAA,CAAI,IAAA,EAAM,WAAA;EAiLf;;;;;EAAA,QA/IM,OAAA;EAAA,QAqDA,kBAAA;EA+GN;;;EA9FK,KAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EA6FV;;;EApFK,IAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EAgG2C;;;EAvFhD,IAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EAiGe;;;EAxFpB,KAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EA8HkB;;;EArHvB,OAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EA4ML;;;;;AAyBgB;AAezB;;;EApOS,KAAA,CACL,YAAA,EAAc,kBAAA,WACd,MAAA,WACA,OAAA,QACA,OAAA,GAAU,MAAA;EAgOuB;AA8CrC;;;;AAA+B;;;;EA9PtB,MAAA,CACL,SAAA,WACA,MAAA,UACA,MAAA,UACA,OAAA,OACA,OAAA,GAAU,MAAA;;;;;;;;;;;EAgBL,KAAA,CAAM,MAAA,UAAgB,MAAA,YAAkB,KAAA,GAAQ,MAAA;;;;EAchD,OAAA,CAAQ,IAAA,WAAY,UAAA,CAdkC,sBAAA;;;;EAqBtD,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCM,KAAA,CAAM,OAAA;IAAW,OAAA;EAAA,IAA0B,OAAA;;;;;UA0D1C,YAAA;;;;;;;;;;;;;;;;;;;EAiCP,eAAA,CAAgB,MAAA,EAAQ,cAAA;;;;;EAyBxB,gBAAA;AAAA;;;;;cAeI,wBAAA;;;;;;;;;;;;;;;cA8CA,GAAA,EAAG,MAAe"}
1
+ {"version":3,"file":"logger.d.mts","names":["_$__types0.BasicLogConfigurations"],"sources":["../../../../../../../packages/logger/src/logger.ts"],"mappings":";;;qBAsCa;;;;EAIJ,UAAU;EAEV;;;;;;UAOC;;;;;;;UAQA;;;;;;;UAQA;;;;;;;UAQA;;;;;UAMA;;;;EAKD,WAAW,SAAS;;;;EASpB,UAAU;IACf,WAAW;IACX,cAAc;IACd,WAAW;IACX,SAAS;IACT,iBAAiB;;;;;;;;;;;;EAmCZ,eAAe,SAAS;;;;;;;;;;;;EAgBxB,UAAU,QAAQ;;;;EAQlB,aAAa;;;;;;;;;;;EAcb,YAAY,OAAO;;;;EAQnB,eAAe;;;;EAOf,YAAY,UAAU;;;;;UAcrB;;;;UAWA;;;;;;;;;;;;;;;EAwCD,IAAI,MAAM;;;;;;UAkCT;UAqDA;;;;EAiBD,MACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;EASL,KACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;EASL,KACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;EASL,MACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;EASL,QACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;;;;;;;EAgBL,MACL,cAAc,6BACd,iBACA,eACA,UAAU;;;;;;;;;;EAgBL,OACL,oBACA,gBACA,gBACA,cACA,UAAU;;;;;;;;;;;EAgBL,MAAM,gBAAgB,kBAAkB,QAAQ;;;;EAchD,QAAQ,eAAY,WAd4BA;;;;EAqBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCM,MAAM;IAAW;MAA0B;;;;;UA0D1C;;;;;;;;;;;;;;;;;;;EAiCP,gBAAgB,QAAQ;;;;;EAyBxB;;;;;;qBAeI;;;;;;;;;;;;;;;qBA8CA,KAAG"}
package/esm/logger.mjs CHANGED
@@ -4,7 +4,7 @@ import { clearMessage } from "./utils/clear-message.mjs";
4
4
  import { Random } from "@mongez/reinforcements";
5
5
 
6
6
  //#region ../../packages/logger/src/logger.ts
7
- const SIGNAL_EVENTS = new Set([
7
+ const SIGNAL_EVENTS = /* @__PURE__ */ new Set([
8
8
  "SIGINT",
9
9
  "SIGTERM",
10
10
  "SIGHUP",