@kikiutils/shared 18.3.0 → 20.0.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 (161) hide show
  1. package/README.md +0 -7
  2. package/dist/buffer.d.ts +0 -2
  3. package/dist/buffer.d.ts.map +1 -1
  4. package/dist/buffer.js +1 -2
  5. package/dist/classes/enhanced-date.d.ts +0 -2
  6. package/dist/classes/enhanced-date.d.ts.map +1 -1
  7. package/dist/classes/enhanced-date.js +1 -2
  8. package/dist/classes/path.d.ts +1 -3
  9. package/dist/classes/path.d.ts.map +1 -1
  10. package/dist/classes/path.js +1 -2
  11. package/dist/classes/precision-number.d.ts +0 -2
  12. package/dist/classes/precision-number.d.ts.map +1 -1
  13. package/dist/classes/precision-number.js +1 -2
  14. package/dist/clipboard.d.ts +0 -2
  15. package/dist/clipboard.d.ts.map +1 -1
  16. package/dist/clipboard.js +1 -2
  17. package/dist/crypto-hash.d.ts +0 -2
  18. package/dist/crypto-hash.d.ts.map +1 -1
  19. package/dist/crypto-hash.js +1 -2
  20. package/dist/datetime.d.ts +0 -2
  21. package/dist/datetime.d.ts.map +1 -1
  22. package/dist/datetime.js +1 -2
  23. package/dist/element-plus.d.ts +0 -2
  24. package/dist/element-plus.d.ts.map +1 -1
  25. package/dist/element-plus.js +1 -2
  26. package/dist/enum.d.ts +0 -2
  27. package/dist/enum.d.ts.map +1 -1
  28. package/dist/enum.js +1 -2
  29. package/dist/env.d.ts +0 -2
  30. package/dist/env.d.ts.map +1 -1
  31. package/dist/env.js +1 -2
  32. package/dist/event-awaiter.d.ts +0 -2
  33. package/dist/event-awaiter.d.ts.map +1 -1
  34. package/dist/event-awaiter.js +1 -2
  35. package/dist/file.d.ts +0 -2
  36. package/dist/file.d.ts.map +1 -1
  37. package/dist/file.js +1 -2
  38. package/dist/general.d.ts +0 -2
  39. package/dist/general.d.ts.map +1 -1
  40. package/dist/general.js +1 -2
  41. package/dist/hash.d.ts +0 -2
  42. package/dist/hash.d.ts.map +1 -1
  43. package/dist/hash.js +1 -2
  44. package/dist/logger/_internals/formatter.d.ts +13 -0
  45. package/dist/logger/_internals/formatter.d.ts.map +1 -0
  46. package/dist/logger/_internals/formatter.js +57 -0
  47. package/dist/logger/_internals/formatter.js.map +1 -0
  48. package/dist/logger/_internals/levels.d.ts +54 -0
  49. package/dist/logger/_internals/levels.d.ts.map +1 -0
  50. package/dist/logger/_internals/levels.js +59 -0
  51. package/dist/logger/_internals/levels.js.map +1 -0
  52. package/dist/logger/_internals/logger.d.ts +12 -0
  53. package/dist/logger/_internals/logger.d.ts.map +1 -0
  54. package/dist/logger/_internals/logger.js +147 -0
  55. package/dist/logger/_internals/logger.js.map +1 -0
  56. package/dist/logger/_internals/types.d.ts +12 -0
  57. package/dist/logger/_internals/types.d.ts.map +1 -0
  58. package/dist/logger/_internals/types.js +1 -0
  59. package/dist/logger/index.d.ts +10 -0
  60. package/dist/logger/index.d.ts.map +1 -0
  61. package/dist/logger/index.js +25 -0
  62. package/dist/logger/index.js.map +1 -0
  63. package/dist/logger/node/_internals/file-writer.d.ts +11 -0
  64. package/dist/logger/node/_internals/file-writer.d.ts.map +1 -0
  65. package/dist/logger/node/_internals/file-writer.js +188 -0
  66. package/dist/logger/node/_internals/file-writer.js.map +1 -0
  67. package/dist/logger/node/_internals/formatter.d.ts +4 -0
  68. package/dist/logger/node/_internals/formatter.d.ts.map +1 -0
  69. package/dist/logger/node/_internals/formatter.js +21 -0
  70. package/dist/logger/node/_internals/formatter.js.map +1 -0
  71. package/dist/logger/node/index.d.ts +10 -0
  72. package/dist/logger/node/index.d.ts.map +1 -0
  73. package/dist/logger/node/index.js +123 -0
  74. package/dist/logger/node/index.js.map +1 -0
  75. package/dist/logger/node/types.d.ts +43 -0
  76. package/dist/logger/node/types.d.ts.map +1 -0
  77. package/dist/logger/node/types.js +1 -0
  78. package/dist/logger/types.d.ts +50 -0
  79. package/dist/logger/types.d.ts.map +1 -0
  80. package/dist/logger/types.js +1 -0
  81. package/dist/math.d.ts +0 -2
  82. package/dist/math.d.ts.map +1 -1
  83. package/dist/math.js +1 -2
  84. package/dist/number.d.ts +0 -2
  85. package/dist/number.d.ts.map +1 -1
  86. package/dist/number.js +1 -2
  87. package/dist/random.d.ts +0 -2
  88. package/dist/random.d.ts.map +1 -1
  89. package/dist/random.js +1 -2
  90. package/dist/redis/script-runner.d.ts +0 -2
  91. package/dist/redis/script-runner.d.ts.map +1 -1
  92. package/dist/redis/script-runner.js +1 -2
  93. package/dist/storages/lru/keyed-store.d.ts +0 -2
  94. package/dist/storages/lru/keyed-store.d.ts.map +1 -1
  95. package/dist/storages/lru/keyed-store.js +1 -2
  96. package/dist/storages/redis/keyed-store.d.ts +4 -4
  97. package/dist/storages/redis/keyed-store.d.ts.map +1 -1
  98. package/dist/storages/redis/keyed-store.js +7 -4
  99. package/dist/storages/redis/keyed-store.js.map +1 -1
  100. package/dist/storages/redis/msgpack.d.ts +10 -3
  101. package/dist/storages/redis/msgpack.d.ts.map +1 -1
  102. package/dist/storages/redis/msgpack.js +18 -3
  103. package/dist/storages/redis/msgpack.js.map +1 -1
  104. package/dist/storages/redis/types.d.ts +30 -2
  105. package/dist/storages/redis/types.d.ts.map +1 -1
  106. package/dist/string.d.ts +0 -2
  107. package/dist/string.d.ts.map +1 -1
  108. package/dist/string.js +1 -2
  109. package/dist/time.d.ts +0 -2
  110. package/dist/time.d.ts.map +1 -1
  111. package/dist/time.js +1 -2
  112. package/dist/types/filtered-key-path.d.ts +0 -2
  113. package/dist/types/filtered-key-path.d.ts.map +1 -1
  114. package/dist/types/index.d.ts +0 -10
  115. package/dist/types/index.d.ts.map +1 -1
  116. package/dist/types/vue.d.ts +0 -2
  117. package/dist/types/vue.d.ts.map +1 -1
  118. package/dist/url.d.ts +0 -2
  119. package/dist/url.d.ts.map +1 -1
  120. package/dist/url.js +1 -2
  121. package/dist/vue.d.ts +0 -2
  122. package/dist/vue.d.ts.map +1 -1
  123. package/dist/vue.js +1 -2
  124. package/dist/web.d.ts +0 -2
  125. package/dist/web.d.ts.map +1 -1
  126. package/dist/web.js +1 -2
  127. package/package.json +73 -45
  128. package/src/logger/_internals/formatter.ts +80 -0
  129. package/src/logger/_internals/levels.ts +60 -0
  130. package/src/logger/_internals/logger.ts +224 -0
  131. package/src/logger/_internals/types.ts +12 -0
  132. package/src/logger/index.ts +34 -0
  133. package/src/logger/node/_internals/file-writer.ts +298 -0
  134. package/src/logger/node/_internals/formatter.ts +33 -0
  135. package/src/logger/node/index.ts +173 -0
  136. package/src/logger/node/types.ts +58 -0
  137. package/src/logger/types.ts +60 -0
  138. package/src/storages/redis/keyed-store.ts +6 -2
  139. package/src/storages/redis/msgpack.ts +17 -1
  140. package/src/storages/redis/types.ts +34 -0
  141. package/src/types/index.ts +0 -10
  142. package/dist/classes/ssh-client.d.ts +0 -40
  143. package/dist/classes/ssh-client.d.ts.map +0 -1
  144. package/dist/classes/ssh-client.js +0 -130
  145. package/dist/classes/ssh-client.js.map +0 -1
  146. package/dist/consola.d.ts +0 -24
  147. package/dist/consola.d.ts.map +0 -1
  148. package/dist/consola.js +0 -29
  149. package/dist/consola.js.map +0 -1
  150. package/dist/object.d.ts +0 -44
  151. package/dist/object.d.ts.map +0 -1
  152. package/dist/object.js +0 -59
  153. package/dist/object.js.map +0 -1
  154. package/dist/pino.d.ts +0 -25
  155. package/dist/pino.d.ts.map +0 -1
  156. package/dist/pino.js +0 -34
  157. package/dist/pino.js.map +0 -1
  158. package/src/classes/ssh-client.ts +0 -175
  159. package/src/consola.ts +0 -25
  160. package/src/object.ts +0 -78
  161. package/src/pino.ts +0 -33
@@ -0,0 +1,54 @@
1
+ import { LoggerMethod } from "../types.js";
2
+ export declare const loggerMethods: {
3
+ readonly debug: {
4
+ readonly ansiColor: "36";
5
+ readonly consoleMethod: "debug";
6
+ readonly cssColor: "#0891b2";
7
+ readonly icon: "⚙";
8
+ readonly severity: 20;
9
+ };
10
+ readonly error: {
11
+ readonly ansiColor: "31";
12
+ readonly consoleMethod: "error";
13
+ readonly cssColor: "#dc2626";
14
+ readonly icon: "✖";
15
+ readonly severity: 50;
16
+ };
17
+ readonly fatal: {
18
+ readonly ansiColor: "31";
19
+ readonly consoleMethod: "error";
20
+ readonly cssColor: "#dc2626";
21
+ readonly icon: "✖";
22
+ readonly severity: 60;
23
+ };
24
+ readonly info: {
25
+ readonly ansiColor: "36";
26
+ readonly consoleMethod: "info";
27
+ readonly cssColor: "#0891b2";
28
+ readonly icon: "ℹ";
29
+ readonly severity: 30;
30
+ };
31
+ readonly success: {
32
+ readonly ansiColor: "32";
33
+ readonly consoleMethod: "info";
34
+ readonly cssColor: "#16a34a";
35
+ readonly icon: "✔";
36
+ readonly severity: 30;
37
+ };
38
+ readonly trace: {
39
+ readonly ansiColor: "90";
40
+ readonly consoleMethod: "debug";
41
+ readonly cssColor: "#808080";
42
+ readonly icon: "·";
43
+ readonly severity: 10;
44
+ };
45
+ readonly warn: {
46
+ readonly ansiColor: "33";
47
+ readonly consoleMethod: "warn";
48
+ readonly cssColor: "#ca8a04";
49
+ readonly icon: "⚠";
50
+ readonly severity: 40;
51
+ };
52
+ };
53
+ export declare function getLoggerStreamName(type: LoggerMethod): 'stderr' | 'stdout';
54
+ //# sourceMappingURL=levels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levels.d.ts","names":[],"sources":["../../../src/logger/_internals/levels.ts"],"mappings":";qBAGa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAqDG,oBAAoB,MAAM"}
@@ -0,0 +1,59 @@
1
+ // src/logger/_internals/levels.ts
2
+ const loggerMethods = {
3
+ debug: {
4
+ ansiColor: "36",
5
+ consoleMethod: "debug",
6
+ cssColor: "#0891b2",
7
+ icon: "⚙",
8
+ severity: 20
9
+ },
10
+ error: {
11
+ ansiColor: "31",
12
+ consoleMethod: "error",
13
+ cssColor: "#dc2626",
14
+ icon: "✖",
15
+ severity: 50
16
+ },
17
+ fatal: {
18
+ ansiColor: "31",
19
+ consoleMethod: "error",
20
+ cssColor: "#dc2626",
21
+ icon: "✖",
22
+ severity: 60
23
+ },
24
+ info: {
25
+ ansiColor: "36",
26
+ consoleMethod: "info",
27
+ cssColor: "#0891b2",
28
+ icon: "ℹ",
29
+ severity: 30
30
+ },
31
+ success: {
32
+ ansiColor: "32",
33
+ consoleMethod: "info",
34
+ cssColor: "#16a34a",
35
+ icon: "✔",
36
+ severity: 30
37
+ },
38
+ trace: {
39
+ ansiColor: "90",
40
+ consoleMethod: "debug",
41
+ cssColor: "#808080",
42
+ icon: "·",
43
+ severity: 10
44
+ },
45
+ warn: {
46
+ ansiColor: "33",
47
+ consoleMethod: "warn",
48
+ cssColor: "#ca8a04",
49
+ icon: "⚠",
50
+ severity: 40
51
+ }
52
+ };
53
+ function getLoggerStreamName(type) {
54
+ const method = loggerMethods[type].consoleMethod;
55
+ return method === "warn" || method === "error" ? "stderr" : "stdout";
56
+ }
57
+ export { getLoggerStreamName, loggerMethods };
58
+
59
+ //# sourceMappingURL=levels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levels.js","names":[],"sources":["../../../src/logger/_internals/levels.ts"],"sourcesContent":["import type { LoggerMethod } from '../types';\n\n// Constants/Variables\nexport const loggerMethods = {\n debug: {\n ansiColor: '36',\n consoleMethod: 'debug',\n cssColor: '#0891b2',\n icon: '⚙',\n severity: 20,\n },\n error: {\n ansiColor: '31',\n consoleMethod: 'error',\n cssColor: '#dc2626',\n icon: '✖',\n severity: 50,\n },\n fatal: {\n ansiColor: '31',\n consoleMethod: 'error',\n cssColor: '#dc2626',\n icon: '✖',\n severity: 60,\n },\n info: {\n ansiColor: '36',\n consoleMethod: 'info',\n cssColor: '#0891b2',\n icon: 'ℹ',\n severity: 30,\n },\n success: {\n ansiColor: '32',\n consoleMethod: 'info',\n cssColor: '#16a34a',\n icon: '✔',\n severity: 30,\n },\n trace: {\n ansiColor: '90',\n consoleMethod: 'debug',\n cssColor: '#808080',\n icon: '·',\n severity: 10,\n },\n warn: {\n ansiColor: '33',\n consoleMethod: 'warn',\n cssColor: '#ca8a04',\n icon: '⚠',\n severity: 40,\n },\n} as const;\n\n// Functions\nexport function getLoggerStreamName(type: LoggerMethod): 'stderr' | 'stdout' {\n const method = loggerMethods[type].consoleMethod;\n return method === 'warn' || method === 'error' ? 'stderr' : 'stdout';\n}\n"],"mappings":";AAGA,MAAa,gBAAgB;CACzB,OAAO;EACH,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,OAAO;EACH,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,OAAO;EACH,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,MAAM;EACF,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,SAAS;EACL,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,OAAO;EACH,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;CACA,MAAM;EACF,WAAW;EACX,eAAe;EACf,UAAU;EACV,MAAM;EACN,UAAU;CACd;AACJ;AAGA,SAAgB,oBAAoB,MAAyC;CACzE,MAAM,SAAS,cAAc,KAAK,CAAC;CACnC,OAAO,WAAW,UAAU,WAAW,UAAU,WAAW;AAChE"}
@@ -0,0 +1,12 @@
1
+ import { Logger, LoggerDiagnostic, LoggerOptions } from "../types.js";
2
+ import { LoggerRecord } from "./types.js";
3
+ interface LoggerHooks {
4
+ /** A non-throwing reporter created by createDiagnosticReporter. */
5
+ report: (event: LoggerDiagnostic) => void;
6
+ write: (record: LoggerRecord) => Promise<void> | void;
7
+ }
8
+ /** A non-recursive, rate-limited diagnostic boundary shared by server and browser adapters. */
9
+ export declare function createDiagnosticReporter(onError?: (event: Readonly<LoggerDiagnostic>) => void, fallback?: (message: string) => void): (event: LoggerDiagnostic) => void;
10
+ export declare function createLoggerCore(options: LoggerOptions, hooks: LoggerHooks): Readonly<Logger>;
11
+ export {};
12
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","names":[],"sources":["../../../src/logger/_internals/logger.ts"],"mappings":";;UAWU;;EAEN,SAAS,OAAO;EAChB,QAAQ,QAAQ,iBAAiB;;;wBAkBrB,yBACZ,WAAW,OAAO,SAAS,4BAC3B,YAAY,4BACZ,OAAO;wBAkEK,iBAAiB,SAAS,eAAe,OAAO,cAAc,SAAS"}
@@ -0,0 +1,147 @@
1
+ import { loggerMethods } from "./levels.js";
2
+ // src/logger/_internals/logger.ts
3
+ const booleanPresentationKeys = [
4
+ "console",
5
+ "icons",
6
+ "timestamp"
7
+ ];
8
+ const stringPresentationKeys = ["prefix", "suffix"];
9
+ /** A non-recursive, rate-limited diagnostic boundary shared by server and browser adapters. */
10
+ function createDiagnosticReporter(onError, fallback) {
11
+ let reporting = false;
12
+ let callbackPending = false;
13
+ const stateByType = /* @__PURE__ */ new Map();
14
+ return (event) => {
15
+ if (reporting) return;
16
+ try {
17
+ const now = Date.now();
18
+ const state = stateByType.get(event.type);
19
+ if (state && now - state.lastReportedAt < 1e3) {
20
+ state.suppressedCount++;
21
+ return;
22
+ }
23
+ reporting = true;
24
+ const suppressedCount = state?.suppressedCount ?? 0;
25
+ if (suppressedCount) event = {
26
+ ...event,
27
+ suppressedCount
28
+ };
29
+ stateByType.set(event.type, {
30
+ lastReportedAt: now,
31
+ suppressedCount: 0
32
+ });
33
+ try {
34
+ const summary = suppressedCount ? ` (${suppressedCount} similar diagnostics suppressed)` : "";
35
+ fallback?.(`[logger] ${event.message}${summary}\n`);
36
+ } catch {}
37
+ if (!callbackPending) try {
38
+ callbackPending = true;
39
+ const result = onError?.(Object.freeze({ ...event }));
40
+ if (result !== null && (typeof result === "object" || typeof result === "function")) Promise.resolve(result).then(() => {
41
+ callbackPending = false;
42
+ }, () => {
43
+ callbackPending = false;
44
+ });
45
+ else callbackPending = false;
46
+ } catch {
47
+ callbackPending = false;
48
+ }
49
+ } catch {} finally {
50
+ reporting = false;
51
+ }
52
+ };
53
+ }
54
+ function createLoggerCore(options, hooks) {
55
+ validateLevel(options.level);
56
+ validatePresentation(options);
57
+ if (options.onError !== void 0 && typeof options.onError !== "function") throw new TypeError("Logger onError must be a function");
58
+ const presentation = {
59
+ console: options.console ?? true,
60
+ icons: options.icons ?? true,
61
+ prefix: options.prefix ?? "",
62
+ suffix: options.suffix ?? "",
63
+ timestamp: options.timestamp ?? true
64
+ };
65
+ const { report } = hooks;
66
+ let override = options.level === "env" ? void 0 : options.level;
67
+ let previousEnvironment;
68
+ let currentLevel = override ?? "info";
69
+ let environmentRead = false;
70
+ function refreshLevel() {
71
+ if (override !== void 0) return;
72
+ const input = readEnvironmentLevel();
73
+ if (environmentRead && input === previousEnvironment) return;
74
+ environmentRead = true;
75
+ previousEnvironment = input;
76
+ const normalized = input?.trim().toLowerCase() || void 0;
77
+ currentLevel = isLevel(normalized) ? normalized : "info";
78
+ if (normalized !== void 0 && !isLevel(normalized)) report({
79
+ message: "Invalid LOG_LEVEL; using info",
80
+ type: "invalid-level"
81
+ });
82
+ }
83
+ const logger = {
84
+ configure(configuration) {
85
+ validatePresentation(configuration);
86
+ for (const name of booleanPresentationKeys) {
87
+ const value = configuration[name];
88
+ if (value !== void 0) presentation[name] = value;
89
+ }
90
+ for (const name of stringPresentationKeys) {
91
+ const value = configuration[name];
92
+ if (value !== void 0) presentation[name] = value;
93
+ }
94
+ },
95
+ isLevelEnabled(level) {
96
+ if (level !== "success" && !isLevel(level)) throw new TypeError("Invalid logger level");
97
+ refreshLevel();
98
+ return level !== "silent" && getLevelSeverity(level) >= getLevelSeverity(currentLevel);
99
+ },
100
+ setLevel(level) {
101
+ validateLevel(level);
102
+ if (level === void 0) throw new TypeError("Invalid logger level");
103
+ override = level === "env" ? void 0 : level;
104
+ environmentRead = false;
105
+ if (override !== void 0) currentLevel = override;
106
+ else refreshLevel();
107
+ }
108
+ };
109
+ for (const type of Object.keys(loggerMethods)) logger[type] = async (...args) => {
110
+ try {
111
+ refreshLevel();
112
+ if (loggerMethods[type].severity < getLevelSeverity(currentLevel)) return;
113
+ await hooks.write({
114
+ ...presentation,
115
+ args,
116
+ date: /* @__PURE__ */ new Date(),
117
+ type
118
+ });
119
+ } catch (error) {
120
+ report({
121
+ error,
122
+ message: "Logger output failed",
123
+ type: "format"
124
+ });
125
+ }
126
+ };
127
+ return Object.freeze(logger);
128
+ }
129
+ function getLevelSeverity(level) {
130
+ return level === "silent" ? Number.POSITIVE_INFINITY : loggerMethods[level].severity;
131
+ }
132
+ function isLevel(value) {
133
+ return typeof value === "string" && (value === "silent" || value !== "success" && Object.hasOwn(loggerMethods, value));
134
+ }
135
+ function readEnvironmentLevel() {
136
+ return globalThis.process?.env?.LOG_LEVEL;
137
+ }
138
+ function validateLevel(value) {
139
+ if (value !== void 0 && value !== "env" && !isLevel(value)) throw new TypeError("Invalid logger level");
140
+ }
141
+ function validatePresentation(options) {
142
+ for (const name of booleanPresentationKeys) if (options[name] !== void 0 && typeof options[name] !== "boolean") throw new TypeError(`Logger ${name} must be a boolean`);
143
+ for (const name of stringPresentationKeys) if (options[name] !== void 0 && typeof options[name] !== "string") throw new TypeError(`Logger ${name} must be a string`);
144
+ }
145
+ export { createDiagnosticReporter, createLoggerCore };
146
+
147
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../../src/logger/_internals/logger.ts"],"sourcesContent":["import type {\n Logger,\n LoggerDiagnostic,\n LoggerLevel,\n LoggerMethod,\n LoggerOptions,\n} from '../types';\n\nimport { loggerMethods } from './levels';\nimport type { LoggerRecord } from './types';\n\ninterface LoggerHooks {\n /** A non-throwing reporter created by createDiagnosticReporter. */\n report: (event: LoggerDiagnostic) => void;\n write: (record: LoggerRecord) => Promise<void> | void;\n}\n\n// Constants/Variables\nconst booleanPresentationKeys = [\n 'console',\n 'icons',\n 'timestamp',\n] as const;\n\nconst stringPresentationKeys = [\n 'prefix',\n 'suffix',\n] as const;\n\n// Functions\n\n/** A non-recursive, rate-limited diagnostic boundary shared by server and browser adapters. */\nexport function createDiagnosticReporter(\n onError?: (event: Readonly<LoggerDiagnostic>) => void,\n fallback?: (message: string) => void,\n): (event: LoggerDiagnostic) => void {\n let reporting = false;\n let callbackPending = false;\n const stateByType = new Map<LoggerDiagnostic['type'], { lastReportedAt: number; suppressedCount: number }>();\n\n return (event) => {\n if (reporting) return;\n try {\n const now = Date.now();\n const state = stateByType.get(event.type);\n if (state && now - state.lastReportedAt < 1000) {\n state.suppressedCount++;\n return;\n }\n\n reporting = true;\n const suppressedCount = state?.suppressedCount ?? 0;\n if (suppressedCount) {\n event = {\n ...event,\n suppressedCount,\n };\n }\n\n stateByType.set(\n event.type,\n {\n lastReportedAt: now,\n suppressedCount: 0,\n },\n );\n\n try {\n const summary = suppressedCount ? ` (${suppressedCount} similar diagnostics suppressed)` : '';\n fallback?.(`[logger] ${event.message}${summary}\\n`);\n } catch {\n // Diagnostics must never re-enter the normal logging pipeline.\n }\n\n if (!callbackPending) {\n try {\n callbackPending = true;\n const result: unknown = onError?.(Object.freeze({ ...event }));\n if (result !== null && (typeof result === 'object' || typeof result === 'function')) {\n void Promise.resolve(result).then(\n () => {\n callbackPending = false;\n },\n () => {\n callbackPending = false;\n },\n );\n } else {\n callbackPending = false;\n }\n } catch {\n callbackPending = false;\n // User diagnostic callbacks have the same non-throwing boundary.\n }\n }\n } catch { /* Diagnostics must never escape into the logging pipeline. */ } finally {\n reporting = false;\n }\n };\n}\n\nexport function createLoggerCore(options: LoggerOptions, hooks: LoggerHooks): Readonly<Logger> {\n validateLevel(options.level);\n validatePresentation(options);\n if (options.onError !== undefined && typeof options.onError !== 'function') {\n throw new TypeError('Logger onError must be a function');\n }\n\n const presentation = {\n console: options.console ?? true,\n icons: options.icons ?? true,\n prefix: options.prefix ?? '',\n suffix: options.suffix ?? '',\n timestamp: options.timestamp ?? true,\n };\n\n const { report } = hooks;\n\n let override = options.level === 'env' ? undefined : options.level;\n let previousEnvironment: string | undefined;\n let currentLevel: LoggerLevel = override ?? 'info';\n let environmentRead = false;\n\n function refreshLevel() {\n if (override !== undefined) return;\n const input = readEnvironmentLevel();\n if (environmentRead && input === previousEnvironment) return;\n environmentRead = true;\n previousEnvironment = input;\n const normalized = input?.trim().toLowerCase() || undefined;\n currentLevel = isLevel(normalized) ? normalized : 'info';\n if (normalized !== undefined && !isLevel(normalized)) {\n report({\n message: 'Invalid LOG_LEVEL; using info',\n type: 'invalid-level',\n });\n }\n }\n\n const logger = {\n configure(configuration) {\n validatePresentation(configuration);\n for (const name of booleanPresentationKeys) {\n const value = configuration[name];\n if (value !== undefined) presentation[name] = value;\n }\n\n for (const name of stringPresentationKeys) {\n const value = configuration[name];\n if (value !== undefined) presentation[name] = value;\n }\n },\n isLevelEnabled(level) {\n if (level !== 'success' && !isLevel(level)) throw new TypeError('Invalid logger level');\n refreshLevel();\n return level !== 'silent' && getLevelSeverity(level) >= getLevelSeverity(currentLevel);\n },\n setLevel(level) {\n validateLevel(level);\n if (level === undefined) throw new TypeError('Invalid logger level');\n override = level === 'env' ? undefined : level;\n environmentRead = false;\n if (override !== undefined) {\n currentLevel = override;\n } else {\n refreshLevel();\n }\n },\n } as Logger;\n\n for (const type of Object.keys(loggerMethods) as LoggerMethod[]) {\n logger[type] = async (...args: unknown[]) => {\n try {\n refreshLevel();\n if (loggerMethods[type].severity < getLevelSeverity(currentLevel)) return;\n await hooks.write({\n ...presentation,\n args,\n date: new Date(),\n type,\n });\n } catch (error) {\n report({\n error,\n message: 'Logger output failed',\n type: 'format',\n });\n }\n };\n }\n\n return Object.freeze(logger);\n}\n\nfunction getLevelSeverity(level: LoggerLevel | LoggerMethod): number {\n return level === 'silent' ? Number.POSITIVE_INFINITY : loggerMethods[level].severity;\n}\n\nfunction isLevel(value: unknown): value is LoggerLevel {\n return typeof value === 'string'\n && (value === 'silent' || (value !== 'success' && Object.hasOwn(loggerMethods, value)));\n}\n\nfunction readEnvironmentLevel(): string | undefined {\n return (globalThis as { process?: { env?: { LOG_LEVEL?: string } } }).process?.env?.LOG_LEVEL;\n}\n\nfunction validateLevel(value: unknown): asserts value is 'env' | LoggerLevel | undefined {\n if (value !== undefined && value !== 'env' && !isLevel(value)) throw new TypeError('Invalid logger level');\n}\n\nfunction validatePresentation(options: Pick<LoggerOptions, 'console' | 'icons' | 'prefix' | 'suffix' | 'timestamp'>) {\n for (const name of booleanPresentationKeys) {\n if (options[name] !== undefined && typeof options[name] !== 'boolean') {\n throw new TypeError(`Logger ${name} must be a boolean`);\n }\n }\n\n for (const name of stringPresentationKeys) {\n if (options[name] !== undefined && typeof options[name] !== 'string') {\n throw new TypeError(`Logger ${name} must be a string`);\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { LoggerMethod } from "../types.js";
2
+ export interface LoggerRecord {
3
+ args: readonly unknown[];
4
+ console: boolean;
5
+ date: Date;
6
+ icons: boolean;
7
+ prefix: string;
8
+ suffix: string;
9
+ timestamp: boolean;
10
+ type: LoggerMethod;
11
+ }
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/logger/_internals/types.ts"],"mappings":";iBAEiB;EACb;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA,MAAM"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { Logger, LoggerOptions } from "./types.js";
2
+ /**
3
+ * Creates an independent, browser-safe console logger.
4
+ *
5
+ * Log calls never throw or reject for recoverable output failures. Awaiting a call
6
+ * waits for the console invocation, not display or durable delivery. Unspecified
7
+ * levels follow LOG_LEVEL when a process environment is available, otherwise info.
8
+ */
9
+ export declare function createLogger(options?: LoggerOptions): Readonly<Logger>;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/logger/index.ts"],"mappings":";;;;;;;;wBAoBgB,aAAa,UAAS,gBAAqB,SAAS"}
@@ -0,0 +1,25 @@
1
+ import { loggerMethods } from "./_internals/levels.js";
2
+ import { formatLoggerConsoleArgs } from "./_internals/formatter.js";
3
+ import { createDiagnosticReporter, createLoggerCore } from "./_internals/logger.js";
4
+ // src/logger/index.ts
5
+ /**
6
+ * Creates an independent, browser-safe console logger.
7
+ *
8
+ * Log calls never throw or reject for recoverable output failures. Awaiting a call
9
+ * waits for the console invocation, not display or durable delivery. Unspecified
10
+ * levels follow LOG_LEVEL when a process environment is available, otherwise info.
11
+ */
12
+ function createLogger(options = {}) {
13
+ const target = globalThis.console;
14
+ const fallback = target?.error?.bind(target);
15
+ return createLoggerCore(options, {
16
+ report: createDiagnosticReporter(options.onError, (message) => fallback?.(message.trimEnd())),
17
+ write(record) {
18
+ if (!record.console) return;
19
+ target?.[loggerMethods[record.type].consoleMethod](...formatLoggerConsoleArgs(record));
20
+ }
21
+ });
22
+ }
23
+ export { createLogger };
24
+
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/logger/index.ts"],"sourcesContent":["import { formatLoggerConsoleArgs } from './_internals/formatter';\nimport { loggerMethods } from './_internals/levels';\nimport {\n createDiagnosticReporter,\n createLoggerCore,\n} from './_internals/logger';\nimport type {\n Logger,\n LoggerOptions,\n} from './types';\n\n// Functions\n\n/**\n * Creates an independent, browser-safe console logger.\n *\n * Log calls never throw or reject for recoverable output failures. Awaiting a call\n * waits for the console invocation, not display or durable delivery. Unspecified\n * levels follow LOG_LEVEL when a process environment is available, otherwise info.\n */\nexport function createLogger(options: LoggerOptions = {}): Readonly<Logger> {\n const target = globalThis.console;\n const fallback = target?.error?.bind(target);\n return createLoggerCore(\n options,\n {\n report: createDiagnosticReporter(options.onError, (message) => fallback?.(message.trimEnd())),\n write(record) {\n if (!record.console) return;\n target?.[loggerMethods[record.type].consoleMethod](...formatLoggerConsoleArgs(record));\n },\n },\n );\n}\n"],"mappings":";;;;;;;;;;;AAoBA,SAAgB,aAAa,UAAyB,CAAC,GAAqB;CACxE,MAAM,SAAS,WAAW;CAC1B,MAAM,WAAW,QAAQ,OAAO,KAAK,MAAM;CAC3C,OAAO,iBACH,SACA;EACI,QAAQ,yBAAyB,QAAQ,UAAU,YAAY,WAAW,QAAQ,QAAQ,CAAC,CAAC;EAC5F,MAAM,QAAQ;GACV,IAAI,CAAC,OAAO,SAAS;GACrB,SAAS,cAAc,OAAO,KAAK,CAAC,cAAc,CAAC,GAAG,wBAAwB,MAAM,CAAC;EACzF;CACJ,CACJ;AACJ"}
@@ -0,0 +1,11 @@
1
+ import { LoggerDiagnostic } from "../../types.js";
2
+ import { LoggerFileOptions, NodeLoggerStats } from "../types.js";
3
+ interface LoggerFileWriter {
4
+ close: () => Promise<void>;
5
+ getStats: () => Readonly<NodeLoggerStats>;
6
+ write: (text: string) => Promise<void>;
7
+ }
8
+ /** A bounded admission layer over the stream's own ordered write buffer; not a second FIFO. */
9
+ export declare function createFileWriter(options: LoggerFileOptions, report: (event: LoggerDiagnostic) => void): Promise<Readonly<LoggerFileWriter>>;
10
+ export {};
11
+ //# sourceMappingURL=file-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.d.ts","names":[],"sources":["../../../../src/logger/node/_internals/file-writer.ts"],"mappings":";;UAiBU;EACN,aAAa;EACb,gBAAgB,SAAS;EACzB,QAAQ,iBAAiB;;;wBASP,iBAClB,SAAS,mBACT,SAAS,OAAO,4BACjB,QAAQ,SAAS"}
@@ -0,0 +1,188 @@
1
+ import { Path } from "../../../classes/path.js";
2
+ import { Buffer } from "node:buffer";
3
+ import { mkdir } from "node:fs/promises";
4
+ import { basename, dirname } from "node:path";
5
+ import { createWriteStream } from "node:fs";
6
+ import { fileURLToPath } from "node:url";
7
+ // src/logger/node/_internals/file-writer.ts
8
+ const defaultMaxPendingBytes = 8388608;
9
+ /** A bounded admission layer over the stream's own ordered write buffer; not a second FIFO. */
10
+ async function createFileWriter(options, report) {
11
+ const { maxPendingBytes, path, rotate } = validateFileOptions(options);
12
+ const createRotatingStream = rotate ? (await import("rotating-file-stream")).createStream : void 0;
13
+ await mkdir(dirname(path), { recursive: true });
14
+ const stream = rotate && createRotatingStream ? createRotatingStream(basename(path), {
15
+ compress: rotate.compress === false ? false : "gzip",
16
+ ...rotate.interval === void 0 ? {} : { interval: rotate.interval === "hourly" ? "1h" : "1d" },
17
+ intervalBoundary: true,
18
+ intervalUTC: false,
19
+ maxFiles: rotate.keepFiles ?? 30,
20
+ ...rotate.maxTotalSize === void 0 ? {} : { maxSize: rotate.maxTotalSize },
21
+ path: dirname(path),
22
+ ...rotate.maxSize === void 0 ? {} : { size: rotate.maxSize }
23
+ }) : createWriteStream(path, { flags: "a" });
24
+ let pendingBytes = 0;
25
+ let droppedCount = 0;
26
+ let writeErrorCount = 0;
27
+ let failed = false;
28
+ let closing = false;
29
+ let closed = false;
30
+ let closePromise;
31
+ let initializing = true;
32
+ const unfinished = /* @__PURE__ */ new Set();
33
+ let rejectInitialization;
34
+ const settleAll = () => {
35
+ for (const settle of unfinished) settle();
36
+ };
37
+ const fail = (error) => {
38
+ rejectInitialization?.(error);
39
+ if (!failed) {
40
+ failed = true;
41
+ if (!initializing) {
42
+ writeErrorCount++;
43
+ report({
44
+ error,
45
+ message: "File output failed and has been disabled.",
46
+ type: "file"
47
+ });
48
+ }
49
+ }
50
+ settleAll();
51
+ if (!stream.destroyed) stream.destroy();
52
+ };
53
+ stream.on("error", fail);
54
+ stream.on("warning", (error) => {
55
+ writeErrorCount++;
56
+ report({
57
+ error,
58
+ message: "File rotation cleanup failed.",
59
+ type: "file"
60
+ });
61
+ });
62
+ stream.on("close", () => {
63
+ closed = true;
64
+ if (!closing && !failed) fail(/* @__PURE__ */ new Error("File stream closed unexpectedly."));
65
+ settleAll();
66
+ });
67
+ try {
68
+ await new Promise((resolveReady, rejectReady) => {
69
+ rejectInitialization = rejectReady;
70
+ stream.write(Buffer.alloc(0), (error) => {
71
+ if (error) rejectReady(error);
72
+ else resolveReady();
73
+ });
74
+ });
75
+ if (failed || closed) throw new Error("File output failed during initialization.");
76
+ } catch (error) {
77
+ if (!stream.destroyed) stream.destroy();
78
+ if (!closed) await new Promise((resolveClosed) => {
79
+ stream.once("close", resolveClosed);
80
+ });
81
+ throw error;
82
+ } finally {
83
+ rejectInitialization = void 0;
84
+ initializing = false;
85
+ }
86
+ return Object.freeze({
87
+ close() {
88
+ if (closePromise) return closePromise;
89
+ closing = true;
90
+ closePromise = new Promise((resolveClosed) => {
91
+ if (closed) {
92
+ resolveClosed();
93
+ return;
94
+ }
95
+ stream.once("close", resolveClosed);
96
+ try {
97
+ if (!stream.destroyed) stream.end();
98
+ } catch (error) {
99
+ fail(error);
100
+ }
101
+ });
102
+ return closePromise;
103
+ },
104
+ getStats: () => Object.freeze({
105
+ droppedCount,
106
+ pendingBytes,
107
+ writeErrorCount
108
+ }),
109
+ write(text) {
110
+ if (closing || closed || failed) {
111
+ report({
112
+ message: "File output is closed or unavailable.",
113
+ type: "closed"
114
+ });
115
+ return Promise.resolve();
116
+ }
117
+ const bytes = Buffer.byteLength(text);
118
+ if (bytes > maxPendingBytes - pendingBytes) {
119
+ droppedCount++;
120
+ report({
121
+ droppedCount,
122
+ message: "File output queue is full; the newest record was discarded.",
123
+ type: "overflow"
124
+ });
125
+ return Promise.resolve();
126
+ }
127
+ pendingBytes += bytes;
128
+ return new Promise((resolveWritten) => {
129
+ let settled = false;
130
+ const settle = () => {
131
+ if (settled) return;
132
+ settled = true;
133
+ pendingBytes -= bytes;
134
+ unfinished.delete(settle);
135
+ resolveWritten();
136
+ };
137
+ unfinished.add(settle);
138
+ try {
139
+ stream.write(text, (error) => {
140
+ if (error) fail(error);
141
+ settle();
142
+ });
143
+ } catch (error) {
144
+ fail(error);
145
+ }
146
+ });
147
+ }
148
+ });
149
+ }
150
+ /** Validate before mkdir, stream creation, or other filesystem side effects. */
151
+ function validateFileOptions(options) {
152
+ if (!options || typeof options !== "object" || !(typeof options.path === "string" || options.path instanceof Path || options.path instanceof URL || Buffer.isBuffer(options.path))) throw new TypeError("file.path must be a string, Buffer, file URL, or Path");
153
+ const path = options.path instanceof URL ? fileURLToPath(options.path) : options.path.toString();
154
+ if (Buffer.isBuffer(options.path) && !Buffer.from(path).equals(options.path)) throw new TypeError("file.path Buffer must contain valid UTF-8");
155
+ if (!path.trim() || path.includes("\0")) throw new TypeError("file.path must be a nonempty path without null bytes");
156
+ const maxPendingBytes = options.maxPendingBytes ?? defaultMaxPendingBytes;
157
+ if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) throw new RangeError("file.maxPendingBytes must be a positive safe integer");
158
+ const rotate = options.rotate;
159
+ if (rotate !== void 0 && rotate !== false) {
160
+ if (!rotate || typeof rotate !== "object") throw new TypeError("file.rotate must be false or an options object");
161
+ if (rotate.interval !== void 0 && rotate.interval !== "hourly" && rotate.interval !== "daily") throw new TypeError("file.rotate.interval must be hourly or daily");
162
+ if (rotate.interval === void 0 && rotate.maxSize === void 0) throw new TypeError("file.rotate requires interval or maxSize");
163
+ const keepFiles = rotate.keepFiles ?? 30;
164
+ if (!Number.isSafeInteger(keepFiles) || keepFiles <= 0) throw new RangeError("file.rotate.keepFiles must be a positive safe integer");
165
+ if (rotate.compress !== void 0 && typeof rotate.compress !== "boolean") throw new TypeError("file.rotate.compress must be a boolean");
166
+ validateSize(rotate.maxSize, "file.rotate.maxSize");
167
+ validateSize(rotate.maxTotalSize, "file.rotate.maxTotalSize");
168
+ }
169
+ return {
170
+ maxPendingBytes,
171
+ path: Path.resolve(path).value,
172
+ rotate
173
+ };
174
+ }
175
+ function validateSize(value, name) {
176
+ if (value === void 0) return;
177
+ if (typeof value !== "string" || !/^[1-9]\d*[BKMG]$/.test(value)) throw new TypeError(`${name} must be a positive integer followed by B, K, M, or G`);
178
+ const multiplier = {
179
+ B: 1,
180
+ G: 1024 ** 3,
181
+ K: 1024,
182
+ M: 1024 ** 2
183
+ }[value.at(-1)];
184
+ if (!Number.isSafeInteger(Number(value.slice(0, -1)) * multiplier)) throw new RangeError(`${name} exceeds the supported size range`);
185
+ }
186
+ export { createFileWriter };
187
+
188
+ //# sourceMappingURL=file-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.js","names":[],"sources":["../../../../src/logger/node/_internals/file-writer.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport { createWriteStream } from 'node:fs';\nimport { mkdir } from 'node:fs/promises';\nimport {\n basename,\n dirname,\n} from 'node:path';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\n\nimport { Path } from '../../../classes/path';\nimport type { LoggerDiagnostic } from '../../types';\nimport type {\n LoggerFileOptions,\n NodeLoggerStats,\n} from '../types';\n\ninterface LoggerFileWriter {\n close: () => Promise<void>;\n getStats: () => Readonly<NodeLoggerStats>;\n write: (text: string) => Promise<void>;\n}\n\n// Constants/Variables\nconst defaultMaxPendingBytes = 8 * 1024 * 1024;\n\n// Functions\n\n/** A bounded admission layer over the stream's own ordered write buffer; not a second FIFO. */\nexport async function createFileWriter(\n options: LoggerFileOptions,\n report: (event: LoggerDiagnostic) => void,\n): Promise<Readonly<LoggerFileWriter>> {\n const {\n maxPendingBytes,\n path,\n rotate,\n } = validateFileOptions(options);\n\n const createRotatingStream = rotate ? (await import('rotating-file-stream')).createStream : undefined;\n await mkdir(dirname(path), { recursive: true });\n const stream: Writable = rotate && createRotatingStream\n ? createRotatingStream(\n basename(path),\n {\n compress: rotate.compress === false ? false : 'gzip',\n ...rotate.interval === undefined ? {} : { interval: rotate.interval === 'hourly' ? '1h' : '1d' },\n intervalBoundary: true,\n intervalUTC: false,\n maxFiles: rotate.keepFiles ?? 30,\n ...rotate.maxTotalSize === undefined ? {} : { maxSize: rotate.maxTotalSize },\n path: dirname(path),\n ...rotate.maxSize === undefined ? {} : { size: rotate.maxSize },\n },\n )\n : createWriteStream(path, { flags: 'a' });\n\n let pendingBytes = 0;\n let droppedCount = 0;\n let writeErrorCount = 0;\n let failed = false;\n let closing = false;\n let closed = false;\n let closePromise: Promise<void> | undefined;\n let initializing = true;\n const unfinished = new Set<() => void>();\n let rejectInitialization: ((error: unknown) => void) | undefined;\n\n const settleAll = () => {\n for (const settle of unfinished) settle();\n };\n\n const fail = (error: unknown) => {\n rejectInitialization?.(error);\n if (!failed) {\n failed = true;\n if (!initializing) {\n writeErrorCount++;\n report({\n error,\n message: 'File output failed and has been disabled.',\n type: 'file',\n });\n }\n }\n\n settleAll();\n if (!stream.destroyed) stream.destroy();\n };\n\n stream.on('error', fail);\n stream.on(\n 'warning',\n (error: unknown) => {\n writeErrorCount++;\n report({\n error,\n message: 'File rotation cleanup failed.',\n type: 'file',\n });\n },\n );\n\n stream.on(\n 'close',\n () => {\n closed = true;\n if (!closing && !failed) fail(new Error('File stream closed unexpectedly.'));\n settleAll();\n },\n );\n\n // A write callback also waits for RFS's asynchronous initialization and initial rotation.\n try {\n await new Promise<void>((resolveReady, rejectReady) => {\n rejectInitialization = rejectReady;\n stream.write(\n Buffer.alloc(0),\n (error) => {\n if (error) rejectReady(error);\n else resolveReady();\n },\n );\n });\n\n if (failed || closed) throw new Error('File output failed during initialization.');\n } catch (error) {\n if (!stream.destroyed) stream.destroy();\n if (!closed) {\n await new Promise<void>((resolveClosed) => {\n stream.once('close', resolveClosed);\n });\n }\n\n throw error;\n } finally {\n rejectInitialization = undefined;\n initializing = false;\n }\n\n return Object.freeze({\n close() {\n if (closePromise) return closePromise;\n closing = true;\n closePromise = new Promise<void>((resolveClosed) => {\n if (closed) {\n resolveClosed();\n return;\n }\n\n stream.once('close', resolveClosed);\n try {\n if (!stream.destroyed) stream.end();\n } catch (error) {\n fail(error);\n }\n });\n\n return closePromise;\n },\n getStats: () => Object.freeze({\n droppedCount,\n pendingBytes,\n writeErrorCount,\n }),\n write(text: string) {\n if (closing || closed || failed) {\n report({\n message: 'File output is closed or unavailable.',\n type: 'closed',\n });\n\n return Promise.resolve();\n }\n\n const bytes = Buffer.byteLength(text);\n if (bytes > maxPendingBytes - pendingBytes) {\n droppedCount++;\n report({\n droppedCount,\n message: 'File output queue is full; the newest record was discarded.',\n type: 'overflow',\n });\n\n return Promise.resolve();\n }\n\n pendingBytes += bytes;\n return new Promise<void>((resolveWritten) => {\n let settled = false;\n const settle = () => {\n if (settled) return;\n settled = true;\n pendingBytes -= bytes;\n unfinished.delete(settle);\n resolveWritten();\n };\n\n unfinished.add(settle);\n try {\n stream.write(\n text,\n (error) => {\n if (error) fail(error);\n settle();\n },\n );\n } catch (error) {\n fail(error);\n }\n });\n },\n });\n}\n\n/** Validate before mkdir, stream creation, or other filesystem side effects. */\nfunction validateFileOptions(options: LoggerFileOptions) {\n if (\n !options\n || typeof options !== 'object'\n || !(\n typeof options.path === 'string'\n || options.path instanceof Path\n || options.path instanceof URL\n || Buffer.isBuffer(options.path)\n )\n ) {\n throw new TypeError('file.path must be a string, Buffer, file URL, or Path');\n }\n\n const path = options.path instanceof URL\n ? fileURLToPath(options.path)\n : options.path.toString();\n\n if (Buffer.isBuffer(options.path) && !Buffer.from(path).equals(options.path)) {\n throw new TypeError('file.path Buffer must contain valid UTF-8');\n }\n\n if (!path.trim() || path.includes('\\0')) {\n throw new TypeError('file.path must be a nonempty path without null bytes');\n }\n\n const maxPendingBytes = options.maxPendingBytes ?? defaultMaxPendingBytes;\n if (!Number.isSafeInteger(maxPendingBytes) || maxPendingBytes <= 0) {\n throw new RangeError('file.maxPendingBytes must be a positive safe integer');\n }\n\n const rotate = options.rotate;\n if (rotate !== undefined && rotate !== false) {\n if (!rotate || typeof rotate !== 'object') {\n throw new TypeError('file.rotate must be false or an options object');\n }\n\n if (rotate.interval !== undefined && rotate.interval !== 'hourly' && rotate.interval !== 'daily') {\n throw new TypeError('file.rotate.interval must be hourly or daily');\n }\n\n if (rotate.interval === undefined && rotate.maxSize === undefined) {\n throw new TypeError('file.rotate requires interval or maxSize');\n }\n\n const keepFiles = rotate.keepFiles ?? 30;\n if (!Number.isSafeInteger(keepFiles) || keepFiles <= 0) {\n throw new RangeError('file.rotate.keepFiles must be a positive safe integer');\n }\n\n if (rotate.compress !== undefined && typeof rotate.compress !== 'boolean') {\n throw new TypeError('file.rotate.compress must be a boolean');\n }\n\n validateSize(rotate.maxSize, 'file.rotate.maxSize');\n validateSize(rotate.maxTotalSize, 'file.rotate.maxTotalSize');\n }\n\n return {\n maxPendingBytes,\n path: Path.resolve(path).value,\n rotate,\n };\n}\n\nfunction validateSize(value: string | undefined, name: string) {\n if (value === undefined) return;\n if (typeof value !== 'string' || !/^[1-9]\\d*[BKMG]$/.test(value)) {\n throw new TypeError(`${name} must be a positive integer followed by B, K, M, or G`);\n }\n\n const multiplier = {\n B: 1,\n G: 1024 ** 3,\n K: 1024,\n M: 1024 ** 2,\n }[value.at(-1) as 'B' | 'G' | 'K' | 'M'];\n\n if (!Number.isSafeInteger(Number(value.slice(0, -1)) * multiplier)) {\n throw new RangeError(`${name} exceeds the supported size range`);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { LoggerRecord } from "../../_internals/types.js";
2
+ /** Preserve user ANSI for console output without invoking custom inspect callbacks/getters. */
3
+ export declare function formatNodeLoggerRecord(record: LoggerRecord, colors?: boolean): string;
4
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","names":[],"sources":["../../../../src/logger/node/_internals/formatter.ts"],"mappings":";;wBAQgB,uBAAuB,QAAQ,cAAc"}
@@ -0,0 +1,21 @@
1
+ import { formatLoggerParts } from "../../_internals/formatter.js";
2
+ import { inspect } from "node:util";
3
+ // src/logger/node/_internals/formatter.ts
4
+ /** Preserve user ANSI for console output without invoking custom inspect callbacks/getters. */
5
+ function formatNodeLoggerRecord(record, colors = false) {
6
+ const message = record.args.map((arg) => typeof arg === "string" ? arg : inspect(arg, {
7
+ colors: false,
8
+ customInspect: false,
9
+ depth: 6,
10
+ getters: false,
11
+ maxArrayLength: 100,
12
+ maxStringLength: 1e4
13
+ })).join(" ");
14
+ return formatLoggerParts({
15
+ ...record,
16
+ args: record.args.length ? [message] : []
17
+ }, colors).join(" ");
18
+ }
19
+ export { formatNodeLoggerRecord };
20
+
21
+ //# sourceMappingURL=formatter.js.map