@mks2508/better-logger 4.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CHANGELOG.json +67 -1
  2. package/package.json +28 -3
  3. package/packages/core/package.json +1 -1
  4. package/packages/exports/package.json +2 -2
  5. package/packages/styling/package.json +2 -2
  6. package/playground/demo-all.ts +95 -0
  7. package/playground/demo-box.ts +85 -0
  8. package/playground/demo-levels.ts +56 -0
  9. package/playground/demo-real-world.ts +98 -0
  10. package/playground/demo-spinner.ts +77 -0
  11. package/playground/demo-steps.ts +72 -0
  12. package/playground/demo-table.ts +83 -0
  13. package/src/Logger.ts +213 -8
  14. package/src/ScopedLogger.ts +43 -1
  15. package/src/cli-module.ts +21 -0
  16. package/src/cli-primitives/box.ts +86 -0
  17. package/src/cli-primitives/cli-table.ts +62 -0
  18. package/src/cli-primitives/divider.ts +17 -0
  19. package/src/cli-primitives/header.ts +18 -0
  20. package/src/cli-primitives/index.ts +13 -0
  21. package/src/cli-primitives/server-fallback.ts +54 -0
  22. package/src/cli-primitives/spinner.ts +133 -0
  23. package/src/cli-primitives/step.ts +22 -0
  24. package/src/constants.ts +14 -2
  25. package/src/index.ts +18 -1
  26. package/src/terminal/formatter.ts +16 -10
  27. package/src/types/core.ts +53 -0
  28. package/src/types/index.ts +4 -0
  29. package/vite.config.ts +33 -0
  30. package/bun.lock +0 -333
  31. package/dist/Logger.d.ts +0 -863
  32. package/dist/Logger.d.ts.map +0 -1
  33. package/dist/ScopedLogger.d.ts +0 -57
  34. package/dist/ScopedLogger.d.ts.map +0 -1
  35. package/dist/chunks/Logger-D-gmmgR2.js +0 -4458
  36. package/dist/chunks/Logger-D-gmmgR2.js.map +0 -1
  37. package/dist/chunks/Logger-D7cfaz15.js +0 -2
  38. package/dist/chunks/Logger-D7cfaz15.js.map +0 -1
  39. package/dist/chunks/RemoteLogHandler-CjWpWZGl.js +0 -33
  40. package/dist/chunks/RemoteLogHandler-CjWpWZGl.js.map +0 -1
  41. package/dist/chunks/RemoteLogHandler-ymkQ97xl.js +0 -2
  42. package/dist/chunks/RemoteLogHandler-ymkQ97xl.js.map +0 -1
  43. package/dist/chunks/environment-COWvu6Wz.js +0 -1577
  44. package/dist/chunks/environment-COWvu6Wz.js.map +0 -1
  45. package/dist/chunks/environment-C_8J-zQ_.js +0 -4
  46. package/dist/chunks/environment-C_8J-zQ_.js.map +0 -1
  47. package/dist/chunks/formatting-CYjT9yhO.js +0 -380
  48. package/dist/chunks/formatting-CYjT9yhO.js.map +0 -1
  49. package/dist/chunks/formatting-Cg5YhB9Y.js +0 -2
  50. package/dist/chunks/formatting-Cg5YhB9Y.js.map +0 -1
  51. package/dist/cli/CommandProcessor.d.ts +0 -100
  52. package/dist/cli/CommandProcessor.d.ts.map +0 -1
  53. package/dist/cli/commands/ConfigCommand.d.ts +0 -14
  54. package/dist/cli/commands/ConfigCommand.d.ts.map +0 -1
  55. package/dist/cli/commands/ExportCommand.d.ts +0 -48
  56. package/dist/cli/commands/ExportCommand.d.ts.map +0 -1
  57. package/dist/cli/commands/HistoryCommand.d.ts +0 -47
  58. package/dist/cli/commands/HistoryCommand.d.ts.map +0 -1
  59. package/dist/cli/commands/StatusCommand.d.ts +0 -30
  60. package/dist/cli/commands/StatusCommand.d.ts.map +0 -1
  61. package/dist/cli/commands/ThemeCommand.d.ts +0 -30
  62. package/dist/cli/commands/ThemeCommand.d.ts.map +0 -1
  63. package/dist/cli/help.d.ts +0 -12
  64. package/dist/cli/help.d.ts.map +0 -1
  65. package/dist/cli/index.d.ts +0 -15
  66. package/dist/cli/index.d.ts.map +0 -1
  67. package/dist/constants.d.ts +0 -227
  68. package/dist/constants.d.ts.map +0 -1
  69. package/dist/core.cjs +0 -2
  70. package/dist/core.cjs.map +0 -1
  71. package/dist/core.d.ts +0 -127
  72. package/dist/core.d.ts.map +0 -1
  73. package/dist/core.js +0 -291
  74. package/dist/core.js.map +0 -1
  75. package/dist/example.d.ts +0 -18
  76. package/dist/example.d.ts.map +0 -1
  77. package/dist/exports-module.d.ts +0 -196
  78. package/dist/exports-module.d.ts.map +0 -1
  79. package/dist/exports.cjs +0 -2
  80. package/dist/exports.cjs.map +0 -1
  81. package/dist/exports.js +0 -238
  82. package/dist/exports.js.map +0 -1
  83. package/dist/handlers/AnalyticsLogHandler.d.ts +0 -8
  84. package/dist/handlers/AnalyticsLogHandler.d.ts.map +0 -1
  85. package/dist/handlers/ExportLogHandler.d.ts +0 -100
  86. package/dist/handlers/ExportLogHandler.d.ts.map +0 -1
  87. package/dist/handlers/FileLogHandler.d.ts +0 -33
  88. package/dist/handlers/FileLogHandler.d.ts.map +0 -1
  89. package/dist/handlers/RemoteLogHandler.d.ts +0 -11
  90. package/dist/handlers/RemoteLogHandler.d.ts.map +0 -1
  91. package/dist/handlers/index.d.ts +0 -8
  92. package/dist/handlers/index.d.ts.map +0 -1
  93. package/dist/hooks/HookManager.d.ts +0 -21
  94. package/dist/hooks/HookManager.d.ts.map +0 -1
  95. package/dist/hooks/index.d.ts +0 -2
  96. package/dist/hooks/index.d.ts.map +0 -1
  97. package/dist/index.cjs +0 -2
  98. package/dist/index.cjs.map +0 -1
  99. package/dist/index.d.ts +0 -153
  100. package/dist/index.d.ts.map +0 -1
  101. package/dist/index.js +0 -609
  102. package/dist/index.js.map +0 -1
  103. package/dist/main.d.ts +0 -2
  104. package/dist/main.d.ts.map +0 -1
  105. package/dist/serializers/SerializerRegistry.d.ts +0 -16
  106. package/dist/serializers/SerializerRegistry.d.ts.map +0 -1
  107. package/dist/serializers/index.d.ts +0 -2
  108. package/dist/serializers/index.d.ts.map +0 -1
  109. package/dist/styling/LogStyleBuilder.d.ts +0 -146
  110. package/dist/styling/LogStyleBuilder.d.ts.map +0 -1
  111. package/dist/styling/SemanticStyles.d.ts +0 -178
  112. package/dist/styling/SemanticStyles.d.ts.map +0 -1
  113. package/dist/styling/SmartPresets.d.ts +0 -22
  114. package/dist/styling/SmartPresets.d.ts.map +0 -1
  115. package/dist/styling/StyleBuilder.d.ts +0 -140
  116. package/dist/styling/StyleBuilder.d.ts.map +0 -1
  117. package/dist/styling/StyleCache.d.ts +0 -42
  118. package/dist/styling/StyleCache.d.ts.map +0 -1
  119. package/dist/styling/banners.d.ts +0 -42
  120. package/dist/styling/banners.d.ts.map +0 -1
  121. package/dist/styling/index.d.ts +0 -10
  122. package/dist/styling/index.d.ts.map +0 -1
  123. package/dist/styling/themes.d.ts +0 -7
  124. package/dist/styling/themes.d.ts.map +0 -1
  125. package/dist/styling-module.d.ts +0 -178
  126. package/dist/styling-module.d.ts.map +0 -1
  127. package/dist/styling.cjs +0 -2
  128. package/dist/styling.cjs.map +0 -1
  129. package/dist/styling.js +0 -146
  130. package/dist/styling.js.map +0 -1
  131. package/dist/terminal/color-converter.d.ts +0 -73
  132. package/dist/terminal/color-converter.d.ts.map +0 -1
  133. package/dist/terminal/formatter.d.ts +0 -20
  134. package/dist/terminal/formatter.d.ts.map +0 -1
  135. package/dist/terminal/terminal-renderer.d.ts +0 -77
  136. package/dist/terminal/terminal-renderer.d.ts.map +0 -1
  137. package/dist/transports/ConsoleTransport.d.ts +0 -9
  138. package/dist/transports/ConsoleTransport.d.ts.map +0 -1
  139. package/dist/transports/FileTransport.d.ts +0 -15
  140. package/dist/transports/FileTransport.d.ts.map +0 -1
  141. package/dist/transports/HttpTransport.d.ts +0 -16
  142. package/dist/transports/HttpTransport.d.ts.map +0 -1
  143. package/dist/transports/TransportManager.d.ts +0 -14
  144. package/dist/transports/TransportManager.d.ts.map +0 -1
  145. package/dist/transports/index.d.ts +0 -5
  146. package/dist/transports/index.d.ts.map +0 -1
  147. package/dist/types/core.d.ts +0 -333
  148. package/dist/types/core.d.ts.map +0 -1
  149. package/dist/types/handlers.d.ts +0 -85
  150. package/dist/types/handlers.d.ts.map +0 -1
  151. package/dist/types/hooks.d.ts +0 -36
  152. package/dist/types/hooks.d.ts.map +0 -1
  153. package/dist/types/index.d.ts +0 -11
  154. package/dist/types/index.d.ts.map +0 -1
  155. package/dist/types/serializers.d.ts +0 -25
  156. package/dist/types/serializers.d.ts.map +0 -1
  157. package/dist/types/transports.d.ts +0 -47
  158. package/dist/types/transports.d.ts.map +0 -1
  159. package/dist/utils/adapter.d.ts +0 -48
  160. package/dist/utils/adapter.d.ts.map +0 -1
  161. package/dist/utils/ansi-colors.d.ts +0 -156
  162. package/dist/utils/ansi-colors.d.ts.map +0 -1
  163. package/dist/utils/environment-detector.d.ts +0 -45
  164. package/dist/utils/environment-detector.d.ts.map +0 -1
  165. package/dist/utils/environment.d.ts +0 -47
  166. package/dist/utils/environment.d.ts.map +0 -1
  167. package/dist/utils/formatting.d.ts +0 -58
  168. package/dist/utils/formatting.d.ts.map +0 -1
  169. package/dist/utils/index.d.ts +0 -8
  170. package/dist/utils/index.d.ts.map +0 -1
  171. package/dist/utils/opentui-detection.d.ts +0 -34
  172. package/dist/utils/opentui-detection.d.ts.map +0 -1
  173. package/dist/utils/output.d.ts +0 -46
  174. package/dist/utils/output.d.ts.map +0 -1
  175. package/dist/utils/stackTrace.d.ts +0 -6
  176. package/dist/utils/stackTrace.d.ts.map +0 -1
  177. package/dist/utils/timestamps.d.ts +0 -20
  178. package/dist/utils/timestamps.d.ts.map +0 -1
  179. package/dist/vite.svg +0 -1
  180. package/dist/writers/BufferWriter.d.ts +0 -96
  181. package/dist/writers/BufferWriter.d.ts.map +0 -1
  182. package/dist/writers/index.d.ts +0 -6
  183. package/dist/writers/index.d.ts.map +0 -1
@@ -1,4458 +0,0 @@
1
- import { C as getAdaptiveColor, F as ADAPTIVE_COLORS, b as StyleBuilder, j as getANSIForeground, A as ANSI, u as getTerminalWidth, G as BUFFER_LIMITS, H as generateLogId, I as parseTimeInput, J as formatDisplayTime, K as safeStringify, M as escapeHtml, N as EXPORT_FORMATS, D as DEFAULT_CONFIG$1, O as setupThemeChangeListener, o as getEnvironment, p as parseStackTrace, f as formatTimestamp$1, y as createStyledOutput, t as getColorCapability, S as StylePresets } from "./environment-COWvu6Wz.js";
2
- const DEFAULT_CONFIG = {
3
- maxDepth: 5,
4
- circular: "placeholder",
5
- preserveUndefined: false
6
- };
7
- class SerializerRegistry {
8
- serializers = /* @__PURE__ */ new Map();
9
- config;
10
- constructor(config = {}) {
11
- this.config = { ...DEFAULT_CONFIG, ...config };
12
- this.registerDefaults();
13
- }
14
- registerDefaults() {
15
- this.add(Error, (err) => ({
16
- name: err.name,
17
- message: err.message,
18
- stack: err.stack?.split("\n").slice(0, 10),
19
- ...err.cause ? { cause: this.serialize(err.cause) } : {}
20
- }), 100);
21
- this.add(Date, (date) => ({
22
- iso: date.toISOString(),
23
- timestamp: date.getTime()
24
- }), 90);
25
- this.add(RegExp, (regex) => ({
26
- pattern: regex.source,
27
- flags: regex.flags
28
- }), 90);
29
- this.add(Map, (map, ctx) => {
30
- const obj = {};
31
- map.forEach((value, key) => {
32
- const keyStr = typeof key === "object" ? JSON.stringify(key) : String(key);
33
- obj[keyStr] = this.serializeInternal(value, {
34
- ...ctx,
35
- depth: ctx.depth + 1,
36
- path: [...ctx.path, keyStr]
37
- });
38
- });
39
- return { __type: "Map", entries: obj };
40
- }, 80);
41
- this.add(Set, (set, ctx) => ({
42
- __type: "Set",
43
- values: Array.from(set).map(
44
- (v, i) => this.serializeInternal(v, {
45
- ...ctx,
46
- depth: ctx.depth + 1,
47
- path: [...ctx.path, `[${i}]`]
48
- })
49
- )
50
- }), 80);
51
- if (typeof Buffer !== "undefined") {
52
- this.add(Buffer, (buf) => ({
53
- __type: "Buffer",
54
- length: buf.length,
55
- preview: buf.slice(0, 50).toString("hex")
56
- }), 70);
57
- }
58
- }
59
- add(type, serializer, priority = 50) {
60
- this.serializers.set(type, { type, serializer, priority });
61
- }
62
- remove(type) {
63
- return this.serializers.delete(type);
64
- }
65
- has(type) {
66
- return this.serializers.has(type);
67
- }
68
- getAll() {
69
- return Array.from(this.serializers.values()).sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
70
- }
71
- findSerializer(value) {
72
- const sorted = this.getAll();
73
- for (const entry of sorted) {
74
- if (value instanceof entry.type) {
75
- return entry;
76
- }
77
- }
78
- return null;
79
- }
80
- serializeInternal(value, context) {
81
- if (value === null) return null;
82
- if (value === void 0) return this.config.preserveUndefined ? void 0 : "[undefined]";
83
- if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
84
- if (typeof value !== "object") return value;
85
- if (context.depth >= this.config.maxDepth) {
86
- return "[Max Depth]";
87
- }
88
- if (context.seen.has(value)) {
89
- switch (this.config.circular) {
90
- case "error":
91
- throw new Error(`Circular reference at ${context.path.join(".")}`);
92
- case "skip":
93
- return void 0;
94
- case "placeholder":
95
- default:
96
- return "[Circular]";
97
- }
98
- }
99
- context.seen.add(value);
100
- const serializer = this.findSerializer(value);
101
- if (serializer) {
102
- return serializer.serializer(value, context);
103
- }
104
- if (Array.isArray(value)) {
105
- return value.map(
106
- (item, i) => this.serializeInternal(item, {
107
- ...context,
108
- depth: context.depth + 1,
109
- path: [...context.path, `[${i}]`]
110
- })
111
- );
112
- }
113
- const result = {};
114
- for (const [key, val] of Object.entries(value)) {
115
- result[key] = this.serializeInternal(val, {
116
- ...context,
117
- depth: context.depth + 1,
118
- path: [...context.path, key]
119
- });
120
- }
121
- return result;
122
- }
123
- serialize(value, config) {
124
- const mergedConfig = { ...this.config, ...config };
125
- return this.serializeInternal(value, {
126
- depth: 0,
127
- maxDepth: mergedConfig.maxDepth,
128
- path: [],
129
- seen: /* @__PURE__ */ new WeakSet()
130
- });
131
- }
132
- }
133
- function generateId() {
134
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
135
- }
136
- class HookManager {
137
- hooks = /* @__PURE__ */ new Map();
138
- middlewares = [];
139
- constructor() {
140
- this.hooks.set("beforeLog", []);
141
- this.hooks.set("afterLog", []);
142
- this.hooks.set("onError", []);
143
- }
144
- on(event, callback, priority = 50) {
145
- const registration = {
146
- id: generateId(),
147
- event,
148
- callback,
149
- priority,
150
- once: false
151
- };
152
- const hooks = this.hooks.get(event);
153
- hooks.push(registration);
154
- hooks.sort((a, b) => b.priority - a.priority);
155
- return () => this.removeHook(event, registration.id);
156
- }
157
- once(event, callback, priority = 50) {
158
- const registration = {
159
- id: generateId(),
160
- event,
161
- callback,
162
- priority,
163
- once: true
164
- };
165
- const hooks = this.hooks.get(event);
166
- hooks.push(registration);
167
- hooks.sort((a, b) => b.priority - a.priority);
168
- return () => this.removeHook(event, registration.id);
169
- }
170
- off(event, callback) {
171
- const hooks = this.hooks.get(event);
172
- if (!hooks) return false;
173
- const index = hooks.findIndex((h) => h.callback === callback);
174
- if (index >= 0) {
175
- hooks.splice(index, 1);
176
- return true;
177
- }
178
- return false;
179
- }
180
- removeHook(event, id) {
181
- const hooks = this.hooks.get(event);
182
- if (hooks) {
183
- const index = hooks.findIndex((h) => h.id === id);
184
- if (index >= 0) {
185
- hooks.splice(index, 1);
186
- }
187
- }
188
- }
189
- use(middleware, priority = 50) {
190
- const registration = {
191
- id: generateId(),
192
- fn: middleware,
193
- priority
194
- };
195
- this.middlewares.push(registration);
196
- this.middlewares.sort((a, b) => b.priority - a.priority);
197
- return () => {
198
- const index = this.middlewares.findIndex((m) => m.id === registration.id);
199
- if (index >= 0) {
200
- this.middlewares.splice(index, 1);
201
- }
202
- };
203
- }
204
- async emit(event, entry) {
205
- const hooks = this.hooks.get(event) || [];
206
- let currentEntry = { ...entry };
207
- const toRemove = [];
208
- for (const hook of hooks) {
209
- try {
210
- const result = await hook.callback(currentEntry);
211
- if (result) {
212
- currentEntry = { ...currentEntry, ...result };
213
- }
214
- if (hook.once) {
215
- toRemove.push(hook.id);
216
- }
217
- } catch (error) {
218
- if (event !== "onError") {
219
- await this.emit("onError", {
220
- ...currentEntry,
221
- error,
222
- hookEvent: event
223
- });
224
- }
225
- }
226
- }
227
- toRemove.forEach((id) => this.removeHook(event, id));
228
- return currentEntry;
229
- }
230
- async process(entry) {
231
- let currentEntry = { ...entry };
232
- currentEntry = await this.emit("beforeLog", currentEntry);
233
- if (this.middlewares.length > 0) {
234
- let index = 0;
235
- const executeNext = async () => {
236
- if (index < this.middlewares.length) {
237
- const middleware = this.middlewares[index++];
238
- if (middleware) {
239
- await middleware.fn(currentEntry, executeNext);
240
- }
241
- }
242
- };
243
- await executeNext();
244
- }
245
- return currentEntry;
246
- }
247
- async afterProcess(entry) {
248
- await this.emit("afterLog", entry);
249
- }
250
- clear() {
251
- this.hooks.forEach((hooks) => hooks.length = 0);
252
- this.middlewares.length = 0;
253
- }
254
- getStats() {
255
- return {
256
- hooks: {
257
- beforeLog: this.hooks.get("beforeLog")?.length || 0,
258
- afterLog: this.hooks.get("afterLog")?.length || 0,
259
- onError: this.hooks.get("onError")?.length || 0
260
- },
261
- middlewares: this.middlewares.length
262
- };
263
- }
264
- }
265
- const LOG_LEVELS = {
266
- debug: 0,
267
- info: 1,
268
- warn: 2,
269
- error: 3,
270
- critical: 4
271
- };
272
- function generateTransportId() {
273
- return `transport-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
274
- }
275
- class TransportManager {
276
- transports = /* @__PURE__ */ new Map();
277
- defaultLevel = "info";
278
- constructor(defaultLevel) {
279
- if (defaultLevel) {
280
- this.defaultLevel = defaultLevel;
281
- }
282
- }
283
- add(target) {
284
- const id = generateTransportId();
285
- const level = target.level || this.defaultLevel;
286
- let transport;
287
- if (typeof target.target === "string") {
288
- throw new Error(`String transport targets not supported. Use inline transport object.`);
289
- } else {
290
- transport = target.target;
291
- }
292
- const entry = {
293
- id,
294
- transport,
295
- options: target.options || {},
296
- level,
297
- levelValue: LOG_LEVELS[level]
298
- };
299
- this.transports.set(id, entry);
300
- return id;
301
- }
302
- remove(id) {
303
- const entry = this.transports.get(id);
304
- if (entry) {
305
- entry.transport.close?.();
306
- return this.transports.delete(id);
307
- }
308
- return false;
309
- }
310
- async write(record) {
311
- const promises = [];
312
- for (const entry of this.transports.values()) {
313
- if (record.levelValue < entry.levelValue) {
314
- continue;
315
- }
316
- let transformedRecord = record;
317
- if (entry.options.transform) {
318
- const result2 = entry.options.transform(record);
319
- if (result2 === null) continue;
320
- transformedRecord = result2;
321
- }
322
- const result = entry.transport.write(transformedRecord);
323
- if (result instanceof Promise) {
324
- promises.push(result);
325
- }
326
- }
327
- await Promise.all(promises);
328
- }
329
- async flush() {
330
- const promises = [];
331
- for (const entry of this.transports.values()) {
332
- if (entry.transport.flush) {
333
- const result = entry.transport.flush();
334
- if (result instanceof Promise) {
335
- promises.push(result);
336
- }
337
- }
338
- }
339
- await Promise.all(promises);
340
- }
341
- async close() {
342
- await this.flush();
343
- const promises = [];
344
- for (const entry of this.transports.values()) {
345
- if (entry.transport.close) {
346
- const result = entry.transport.close();
347
- if (result instanceof Promise) {
348
- promises.push(result);
349
- }
350
- }
351
- }
352
- await Promise.all(promises);
353
- this.transports.clear();
354
- }
355
- get count() {
356
- return this.transports.size;
357
- }
358
- list() {
359
- return Array.from(this.transports.keys());
360
- }
361
- }
362
- const THEME_PRESETS = {
363
- default: {
364
- debug: {
365
- emoji: "🐞",
366
- label: "DEBUG",
367
- background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
368
- color: "#ffffff",
369
- border: "1px solid #667eea",
370
- shadow: "0 2px 4px rgba(102, 126, 234, 0.3)"
371
- },
372
- info: {
373
- emoji: "ℹ️",
374
- label: "INFO",
375
- background: "linear-gradient(135deg, #74b9ff 0%, #0984e3 100%)",
376
- color: "#ffffff",
377
- border: "1px solid #74b9ff",
378
- shadow: "0 2px 4px rgba(116, 185, 255, 0.3)"
379
- },
380
- warn: {
381
- emoji: "⚠️",
382
- label: "WARN",
383
- background: "linear-gradient(135deg, #fdcb6e 0%, #e17055 100%)",
384
- color: "#2d3436",
385
- border: "1px solid #fdcb6e",
386
- shadow: "0 2px 4px rgba(253, 203, 110, 0.3)"
387
- },
388
- error: {
389
- emoji: "❌",
390
- label: "ERROR",
391
- background: "linear-gradient(135deg, #e84393 0%, #d63031 100%)",
392
- color: "#ffffff",
393
- border: "1px solid #e84393",
394
- shadow: "0 2px 4px rgba(232, 67, 147, 0.3)"
395
- },
396
- success: {
397
- emoji: "✅",
398
- label: "SUCCESS",
399
- background: "linear-gradient(135deg, #00b894 0%, #00a085 100%)",
400
- color: "#ffffff",
401
- border: "1px solid #00b894",
402
- shadow: "0 2px 4px rgba(0, 184, 148, 0.3)"
403
- },
404
- critical: {
405
- emoji: "🔥",
406
- label: "CRITICAL",
407
- background: "linear-gradient(135deg, #ff3838 0%, #ff1744 100%)",
408
- color: "#ffffff",
409
- border: "2px solid #ff3838",
410
- shadow: "0 4px 8px rgba(255, 56, 56, 0.5)"
411
- }
412
- },
413
- dark: {
414
- debug: {
415
- emoji: "🌙",
416
- label: "DEBUG",
417
- background: "linear-gradient(135deg, #2d3748 0%, #4a5568 100%)",
418
- color: "#e2e8f0",
419
- border: "1px solid #4a5568",
420
- shadow: "0 2px 4px rgba(45, 55, 72, 0.8)"
421
- },
422
- info: {
423
- emoji: "💡",
424
- label: "INFO",
425
- background: "linear-gradient(135deg, #1a202c 0%, #2d3748 100%)",
426
- color: "#90cdf4",
427
- border: "1px solid #3182ce",
428
- shadow: "0 2px 4px rgba(26, 32, 44, 0.8)"
429
- },
430
- warn: {
431
- emoji: "⚡",
432
- label: "WARN",
433
- background: "linear-gradient(135deg, #744210 0%, #975a16 100%)",
434
- color: "#faf089",
435
- border: "1px solid #d69e2e",
436
- shadow: "0 2px 4px rgba(116, 66, 16, 0.8)"
437
- },
438
- error: {
439
- emoji: "💀",
440
- label: "ERROR",
441
- background: "linear-gradient(135deg, #742a2a 0%, #9b2c2c 100%)",
442
- color: "#feb2b2",
443
- border: "1px solid #e53e3e",
444
- shadow: "0 2px 4px rgba(116, 42, 42, 0.8)"
445
- },
446
- success: {
447
- emoji: "🎯",
448
- label: "SUCCESS",
449
- background: "linear-gradient(135deg, #276749 0%, #2f855a 100%)",
450
- color: "#9ae6b4",
451
- border: "1px solid #38a169",
452
- shadow: "0 2px 4px rgba(39, 103, 73, 0.8)"
453
- },
454
- critical: {
455
- emoji: "💥",
456
- label: "CRITICAL",
457
- background: "linear-gradient(135deg, #1a1a1a 0%, #ff0000 100%)",
458
- color: "#ffffff",
459
- border: "2px solid #ff0000",
460
- shadow: "0 4px 8px rgba(255, 0, 0, 0.9)"
461
- }
462
- },
463
- neon: {
464
- debug: {
465
- emoji: "⚡",
466
- label: "DEBUG",
467
- background: "linear-gradient(135deg, #0f3460 0%, #e94560 100%)",
468
- color: "#00ffff",
469
- border: "1px solid #00ffff",
470
- shadow: "0 0 10px rgba(0, 255, 255, 0.5)"
471
- },
472
- info: {
473
- emoji: "🔮",
474
- label: "INFO",
475
- background: "linear-gradient(135deg, #16213e 0%, #0f3460 100%)",
476
- color: "#00ff41",
477
- border: "1px solid #00ff41",
478
- shadow: "0 0 10px rgba(0, 255, 65, 0.5)"
479
- },
480
- warn: {
481
- emoji: "⚠️",
482
- label: "WARN",
483
- background: "linear-gradient(135deg, #533a03 0%, #e94560 100%)",
484
- color: "#ffff00",
485
- border: "1px solid #ffff00",
486
- shadow: "0 0 10px rgba(255, 255, 0, 0.5)"
487
- },
488
- error: {
489
- emoji: "💥",
490
- label: "ERROR",
491
- background: "linear-gradient(135deg, #5c0a0a 0%, #ff073a 100%)",
492
- color: "#ff073a",
493
- border: "1px solid #ff073a",
494
- shadow: "0 0 10px rgba(255, 7, 58, 0.8)"
495
- },
496
- success: {
497
- emoji: "✨",
498
- label: "SUCCESS",
499
- background: "linear-gradient(135deg, #0a5c0a 0%, #39ff14 100%)",
500
- color: "#39ff14",
501
- border: "1px solid #39ff14",
502
- shadow: "0 0 10px rgba(57, 255, 20, 0.8)"
503
- },
504
- critical: {
505
- emoji: "🌟",
506
- label: "CRITICAL",
507
- background: "linear-gradient(135deg, #000000 0%, #ff0080 100%)",
508
- color: "#ff0080",
509
- border: "2px solid #ff0080",
510
- shadow: "0 0 20px rgba(255, 0, 128, 1)"
511
- }
512
- },
513
- minimal: {
514
- debug: {
515
- emoji: "",
516
- label: "DEBUG",
517
- background: "#f7fafc",
518
- color: "#4a5568",
519
- border: "1px solid #e2e8f0",
520
- shadow: "none"
521
- },
522
- info: {
523
- emoji: "",
524
- label: "INFO",
525
- background: "#ebf8ff",
526
- color: "#2b6cb0",
527
- border: "1px solid #bee3f8",
528
- shadow: "none"
529
- },
530
- warn: {
531
- emoji: "",
532
- label: "WARN",
533
- background: "#fffbf0",
534
- color: "#c05621",
535
- border: "1px solid #fed7aa",
536
- shadow: "none"
537
- },
538
- error: {
539
- emoji: "",
540
- label: "ERROR",
541
- background: "#fef5f5",
542
- color: "#c53030",
543
- border: "1px solid #fca5a5",
544
- shadow: "none"
545
- },
546
- success: {
547
- emoji: "",
548
- label: "SUCCESS",
549
- background: "#f0fff4",
550
- color: "#2f855a",
551
- border: "1px solid #9ae6b4",
552
- shadow: "none"
553
- },
554
- critical: {
555
- emoji: "",
556
- label: "CRITICAL",
557
- background: "#fef5f5",
558
- color: "#e53e3e",
559
- border: "2px solid #f56565",
560
- shadow: "none"
561
- }
562
- },
563
- // Additional theme variants can be added here
564
- light: {
565
- debug: {
566
- emoji: "🔍",
567
- label: "DEBUG",
568
- background: "linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%)",
569
- color: "#1565c0",
570
- border: "1px solid #90caf9",
571
- shadow: "0 1px 3px rgba(33, 150, 243, 0.2)"
572
- },
573
- info: {
574
- emoji: "ℹ️",
575
- label: "INFO",
576
- background: "linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%)",
577
- color: "#7b1fa2",
578
- border: "1px solid #ce93d8",
579
- shadow: "0 1px 3px rgba(156, 39, 176, 0.2)"
580
- },
581
- warn: {
582
- emoji: "⚠️",
583
- label: "WARN",
584
- background: "linear-gradient(135deg, #fff8e1 0%, #ffecb3 100%)",
585
- color: "#f57c00",
586
- border: "1px solid #ffcc02",
587
- shadow: "0 1px 3px rgba(255, 152, 0, 0.2)"
588
- },
589
- error: {
590
- emoji: "❌",
591
- label: "ERROR",
592
- background: "linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%)",
593
- color: "#d32f2f",
594
- border: "1px solid #f44336",
595
- shadow: "0 1px 3px rgba(244, 67, 54, 0.2)"
596
- },
597
- success: {
598
- emoji: "✅",
599
- label: "SUCCESS",
600
- background: "linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%)",
601
- color: "#388e3c",
602
- border: "1px solid #4caf50",
603
- shadow: "0 1px 3px rgba(76, 175, 80, 0.2)"
604
- },
605
- critical: {
606
- emoji: "🚨",
607
- label: "CRITICAL",
608
- background: "linear-gradient(135deg, #fce4ec 0%, #f8bbd9 100%)",
609
- color: "#c2185b",
610
- border: "2px solid #e91e63",
611
- shadow: "0 2px 6px rgba(233, 30, 99, 0.3)"
612
- }
613
- },
614
- cyberpunk: {
615
- debug: {
616
- emoji: "🤖",
617
- label: "DEBUG",
618
- background: "linear-gradient(135deg, #0d1b2a 0%, #415a77 100%)",
619
- color: "#00d4aa",
620
- border: "1px solid #00d4aa",
621
- shadow: "0 0 15px rgba(0, 212, 170, 0.4)"
622
- },
623
- info: {
624
- emoji: "🔗",
625
- label: "INFO",
626
- background: "linear-gradient(135deg, #1b263b 0%, #0d1b2a 100%)",
627
- color: "#00b4d8",
628
- border: "1px solid #00b4d8",
629
- shadow: "0 0 15px rgba(0, 180, 216, 0.4)"
630
- },
631
- warn: {
632
- emoji: "⚡",
633
- label: "WARN",
634
- background: "linear-gradient(135deg, #f72585 0%, #b5179e 100%)",
635
- color: "#ffff3f",
636
- border: "1px solid #ffff3f",
637
- shadow: "0 0 15px rgba(255, 255, 63, 0.4)"
638
- },
639
- error: {
640
- emoji: "💀",
641
- label: "ERROR",
642
- background: "linear-gradient(135deg, #7209b7 0%, #480ca8 100%)",
643
- color: "#ff006e",
644
- border: "1px solid #ff006e",
645
- shadow: "0 0 15px rgba(255, 0, 110, 0.6)"
646
- },
647
- success: {
648
- emoji: "⚡",
649
- label: "SUCCESS",
650
- background: "linear-gradient(135deg, #003566 0%, #001d3d 100%)",
651
- color: "#00f5ff",
652
- border: "1px solid #00f5ff",
653
- shadow: "0 0 15px rgba(0, 245, 255, 0.4)"
654
- },
655
- critical: {
656
- emoji: "💥",
657
- label: "CRITICAL",
658
- background: "linear-gradient(135deg, #000000 0%, #ff0040 100%)",
659
- color: "#ff0040",
660
- border: "2px solid #ff0040",
661
- shadow: "0 0 25px rgba(255, 0, 64, 0.8)"
662
- }
663
- }
664
- };
665
- const BANNER_VARIANTS = {
666
- simple: {
667
- text: "🚀 ADVANCED LOGGER v2.0.0 - State-of-the-art Console Styling 🚀",
668
- style: "background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 20px; border-radius: 8px; font-weight: bold; font-size: 14px;"
669
- },
670
- ascii: {
671
- text: `
672
- ___ ____ _ __ ___ _ __ _____ _____ ____ __ ___ _____ _____ _____ ____
673
- / _ \\ / __ \\| | / / / _ \\ | \\ | |/ ____| ____| _ \\ | | / _ \\ / ____| ___| _ | _ \\
674
- / /_\\ \\ / / _\` | |/ / / /_\\ \\ | \\| | | | |__ | | | | | | / / \\ \\| | __| |_ | |_| | |_) |
675
- | _ || | (_| | < | _ | | . \` | | | __| | | | | | | | | | | | |_ | _| | /| _ <
676
- | | | |\\ \\__,_|_|\\_\\ | | | | | |\\ | |___| |____| |_| | | |__\\ \\_/ /| |__| | |___| |\\ \\| |_) |
677
- \\_| |_/ \\____/ \\_| |_/ |_| \\_|\\_____|______|____/ |_____/\\___/ \\_____|_____|_| \\_|____/
678
-
679
- Advanced Logger v2.0.0 - Console Excellence`,
680
- style: 'font-family: "Courier New", Consolas, Monaco, monospace; color: #667eea; font-size: 11px; line-height: 1.2;'
681
- },
682
- unicode: {
683
- text: `
684
- ╔══════════════════════════════════════════════════════════════════════════╗
685
- ║ 🚀 ADVANCED LOGGER v2.0.0 ║
686
- ║ State-of-the-art Console Styling ║
687
- ╚══════════════════════════════════════════════════════════════════════════╝`,
688
- style: 'font-family: "Courier New", Consolas, Monaco, monospace; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 8px; font-size: 12px; line-height: 1.3;'
689
- },
690
- svg: {
691
- text: " ",
692
- style: `
693
- background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 80'><defs><linearGradient id='grad' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:%23667eea'/><stop offset='100%' style='stop-color:%23764ba2'/></linearGradient></defs><rect width='100%' height='100%' fill='url(%23grad)' rx='8'/><text x='200' y='30' text-anchor='middle' fill='white' font-family='monospace' font-size='14' font-weight='bold'>🚀 ADVANCED LOGGER</text><text x='200' y='50' text-anchor='middle' fill='white' font-family='monospace' font-size='12'>State-of-the-art Console Styling</text><text x='200' y='65' text-anchor='middle' fill='white' font-family='monospace' font-size='10'>v2.0.0</text></svg>");
694
- background-repeat: no-repeat;
695
- background-size: 400px 80px;
696
- padding: 40px 200px;
697
- color: transparent;
698
- display: inline-block;
699
- border-radius: 8px;
700
- `
701
- },
702
- animated: {
703
- text: " 🚀 ADVANCED LOGGER v2.0.0 ",
704
- style: `
705
- background: linear-gradient(-45deg, #667eea, #764ba2, #667eea, #764ba2);
706
- background-size: 400% 400%;
707
- color: white;
708
- padding: 15px 25px;
709
- border-radius: 10px;
710
- font-weight: bold;
711
- font-size: 14px;
712
- font-family: monospace;
713
- animation: gradientShift 3s ease infinite;
714
- display: inline-block;
715
- `
716
- }
717
- };
718
- const THEME_BANNERS = {
719
- default: {
720
- simple: "🚀 ADVANCED LOGGER v2.0.0 - State-of-the-art Console Styling 🚀",
721
- style: "background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 20px; border-radius: 8px; font-weight: bold;"
722
- },
723
- dark: {
724
- simple: "🌙 ADVANCED LOGGER v2.0.0 - Dark Mode Console Excellence 🌙",
725
- style: "background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%); color: #e2e8f0; padding: 12px 20px; border-radius: 8px; font-weight: bold; border: 1px solid #4a5568;"
726
- },
727
- neon: {
728
- simple: "⚡ ADVANCED LOGGER v2.0.0 - Cyberpunk Console Experience ⚡",
729
- style: "background: linear-gradient(135deg, #0f3460 0%, #e94560 100%); color: #00ffff; padding: 12px 20px; border-radius: 8px; font-weight: bold; text-shadow: 0 0 10px #00ffff;"
730
- },
731
- minimal: {
732
- simple: "ADVANCED LOGGER v2.0.0 - Clean Console Styling",
733
- style: "background: #f7fafc; color: #2d3748; padding: 8px 16px; border: 1px solid #e2e8f0; border-radius: 4px; font-weight: 500;"
734
- },
735
- light: {
736
- simple: "☀️ ADVANCED LOGGER v2.0.0 - Bright Console Styling ☀️",
737
- style: "background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); color: #495057; padding: 12px 20px; border-radius: 8px; font-weight: bold; border: 1px solid #dee2e6;"
738
- },
739
- cyberpunk: {
740
- simple: "🤖 ADVANCED LOGGER v2.0.0 - Neural Console Interface 🤖",
741
- style: "background: linear-gradient(135deg, #0d1b2a 0%, #415a77 100%); color: #00d4aa; padding: 12px 20px; border-radius: 8px; font-weight: bold; text-shadow: 0 0 10px #00d4aa; border: 1px solid #00d4aa;"
742
- }
743
- };
744
- function detectBannerCapabilities() {
745
- const userAgent = navigator.userAgent;
746
- const isChrome = /Chrome/.test(userAgent);
747
- const isFirefox = /Firefox/.test(userAgent);
748
- const isSafari = /Safari/.test(userAgent) && !/Chrome/.test(userAgent);
749
- const supportsSVG = !!document.createElementNS && !!document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect;
750
- const supportsAnimations = typeof document !== "undefined" && "animationName" in document.createElement("div").style;
751
- if (supportsAnimations && isChrome) {
752
- return "animated";
753
- } else if (supportsSVG && (isChrome || isFirefox)) {
754
- return "svg";
755
- } else if (isChrome || isFirefox) {
756
- return "unicode";
757
- } else if (isSafari) {
758
- return "ascii";
759
- }
760
- return "simple";
761
- }
762
- function displayInitBanner(bannerType) {
763
- const selectedType = bannerType || detectBannerCapabilities();
764
- const banner = BANNER_VARIANTS[selectedType];
765
- if (selectedType === "animated") {
766
- const style = document.createElement("style");
767
- style.textContent = `
768
- @keyframes gradientShift {
769
- 0% { background-position: 0% 50%; }
770
- 50% { background-position: 100% 50%; }
771
- 100% { background-position: 0% 50%; }
772
- }
773
- `;
774
- document.head.appendChild(style);
775
- }
776
- console.log(`%c${banner.text}`, banner.style);
777
- const features = [
778
- "🎨 Advanced CSS Console Styling",
779
- "📍 Automatic Stack Trace Parsing",
780
- "🔧 Scoped Loggers & Prefixes",
781
- "⚡ Performance Timers",
782
- "🎯 Verbosity Filtering",
783
- "🔌 Extensible Handlers",
784
- "📱 Modern TypeScript Patterns",
785
- "📤 Export & Clipboard Support"
786
- ];
787
- console.group(`%c✨ Features`, "background: #f8f9fa; color: #495057; padding: 4px 8px; border-radius: 4px; font-weight: bold;");
788
- features.forEach((feature) => {
789
- console.log(`%c${feature}`, "color: #6c757d; font-size: 13px;");
790
- });
791
- console.groupEnd();
792
- console.log("");
793
- }
794
- class BaseStyler {
795
- builder;
796
- constructor(builder = new StyleBuilder()) {
797
- this.builder = builder;
798
- }
799
- /**
800
- * Primary brand color (typically blue)
801
- */
802
- primary() {
803
- return this.color("#007bff");
804
- }
805
- /**
806
- * Secondary color (typically gray)
807
- */
808
- secondary() {
809
- return this.color("#6c757d");
810
- }
811
- /**
812
- * Accent color for highlights
813
- */
814
- accent() {
815
- return this.color("#17a2b8");
816
- }
817
- /**
818
- * Muted/subtle color - automatically adaptive
819
- */
820
- muted() {
821
- const mutedColors = { light: "#6c757d", dark: "#a0aec0" };
822
- return this.color(getAdaptiveColor(mutedColors));
823
- }
824
- /**
825
- * Success color (green)
826
- */
827
- success() {
828
- return this.color("#28a745");
829
- }
830
- /**
831
- * Warning color (yellow/orange)
832
- */
833
- warning() {
834
- return this.color("#ffc107");
835
- }
836
- /**
837
- * Danger/error color (red)
838
- */
839
- danger() {
840
- return this.color("#dc3545");
841
- }
842
- /**
843
- * Monospace font family
844
- */
845
- mono() {
846
- this.builder.font('Monaco, Consolas, "Courier New", monospace');
847
- return this;
848
- }
849
- /**
850
- * System font family
851
- */
852
- system() {
853
- this.builder.font('system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif');
854
- return this;
855
- }
856
- /**
857
- * Readable font optimized for text
858
- */
859
- readable() {
860
- this.builder.font('Georgia, "Times New Roman", serif');
861
- return this;
862
- }
863
- /**
864
- * Compact spacing
865
- */
866
- compact() {
867
- this.builder.padding("1px 4px").margin("0 1px");
868
- return this;
869
- }
870
- /**
871
- * Spacious layout
872
- */
873
- spacious() {
874
- this.builder.padding("6px 12px").margin("2px 4px");
875
- return this;
876
- }
877
- /**
878
- * Inline display
879
- */
880
- inline() {
881
- this.builder.display("inline-block");
882
- return this;
883
- }
884
- /**
885
- * Glass morphism effect
886
- */
887
- glassmorphic() {
888
- this.builder.css("backdrop-filter", "blur(10px)").css("background", "rgba(255, 255, 255, 0.1)").border("1px solid rgba(255, 255, 255, 0.2)").rounded("8px");
889
- return this;
890
- }
891
- /**
892
- * Neon glow effect
893
- */
894
- neon() {
895
- const neonColor = "#00ffff";
896
- this.builder.color(neonColor).border(`1px solid ${neonColor}`).shadow(`0 0 10px ${neonColor}, 0 0 20px ${neonColor}`).css("text-shadow", `0 0 5px ${neonColor}`);
897
- return this;
898
- }
899
- /**
900
- * Gradient background
901
- */
902
- gradient(from = "#667eea", to = "#764ba2") {
903
- this.builder.bg(`linear-gradient(135deg, ${from} 0%, ${to} 100%)`);
904
- return this;
905
- }
906
- /**
907
- * Bold text
908
- */
909
- bold() {
910
- this.builder.bold();
911
- return this;
912
- }
913
- /**
914
- * Set color with automatic adaptation
915
- */
916
- color(color) {
917
- this.builder.color(color);
918
- return this;
919
- }
920
- /**
921
- * Build the final CSS string
922
- */
923
- build() {
924
- return this.builder.build();
925
- }
926
- }
927
- class TimestampStyler extends BaseStyler {
928
- /**
929
- * Default timestamp style - subtle and informative
930
- */
931
- default() {
932
- this.muted().mono();
933
- this.builder.size("11px");
934
- return this;
935
- }
936
- /**
937
- * Hide timestamp
938
- */
939
- hidden() {
940
- this.builder.display("none");
941
- return this;
942
- }
943
- /**
944
- * Minimal timestamp (just time, no date)
945
- */
946
- minimal() {
947
- this.muted().mono();
948
- this.builder.size("10px").opacity(0.7);
949
- return this;
950
- }
951
- /**
952
- * Set font size
953
- */
954
- size(size) {
955
- this.builder.size(size);
956
- return this;
957
- }
958
- }
959
- class LevelStyler extends BaseStyler {
960
- /**
961
- * Colorful gradient badge
962
- */
963
- badge() {
964
- this.builder.padding("2px 8px").rounded("4px").bold().color("#ffffff");
965
- return this;
966
- }
967
- /**
968
- * Glowing effect for dark themes
969
- */
970
- glowing() {
971
- return this.neon().badge();
972
- }
973
- /**
974
- * Minimal flat style
975
- */
976
- flat() {
977
- this.builder.padding("1px 6px").rounded("2px").border("1px solid currentColor").css("background", "transparent");
978
- return this;
979
- }
980
- /**
981
- * Uppercase text
982
- */
983
- uppercase() {
984
- this.builder.uppercase();
985
- return this;
986
- }
987
- }
988
- class PrefixStyler extends BaseStyler {
989
- /**
990
- * Dark theme prefix
991
- */
992
- dark() {
993
- const prefixColors = { light: "#2d3748", dark: "#4a5568" };
994
- const textColors = { light: "#e2e8f0", dark: "#f7fafc" };
995
- this.builder.bg(getAdaptiveColor(prefixColors)).color(getAdaptiveColor(textColors)).padding("2px 6px").rounded("3px").bold().mono().size("11px");
996
- return this;
997
- }
998
- /**
999
- * Light theme prefix
1000
- */
1001
- light() {
1002
- this.builder.bg("#f8f9fa").color("#495057").padding("2px 6px").rounded("3px").bold().mono().size("11px").border("1px solid #dee2e6");
1003
- return this;
1004
- }
1005
- /**
1006
- * Compact prefix
1007
- */
1008
- compact() {
1009
- this.builder.padding("1px 4px").size("10px").rounded("2px");
1010
- return this;
1011
- }
1012
- }
1013
- class MessageStyler extends BaseStyler {
1014
- /**
1015
- * Readable message text - automatically adaptive
1016
- */
1017
- readable() {
1018
- this.builder.color(getAdaptiveColor(ADAPTIVE_COLORS.messageText)).system().size("14px");
1019
- return this;
1020
- }
1021
- /**
1022
- * Code-style monospace text
1023
- */
1024
- code() {
1025
- this.builder.mono().size("13px").color(getAdaptiveColor(ADAPTIVE_COLORS.messageText)).bg("rgba(0, 0, 0, 0.05)").padding("1px 4px").rounded("3px");
1026
- return this;
1027
- }
1028
- /**
1029
- * Large, prominent text
1030
- */
1031
- large() {
1032
- this.builder.size("16px").color(getAdaptiveColor(ADAPTIVE_COLORS.messageText));
1033
- return this;
1034
- }
1035
- }
1036
- class LocationStyler extends BaseStyler {
1037
- /**
1038
- * Subtle location info - automatically adaptive
1039
- */
1040
- subtle() {
1041
- this.builder.color(getAdaptiveColor(ADAPTIVE_COLORS.location)).mono().size("11px").opacity(0.7);
1042
- return this;
1043
- }
1044
- /**
1045
- * Hide location info
1046
- */
1047
- hidden() {
1048
- this.builder.display("none");
1049
- return this;
1050
- }
1051
- /**
1052
- * Clickable style (for IDE integration)
1053
- */
1054
- clickable() {
1055
- this.subtle();
1056
- this.builder.css("text-decoration", "underline").cursor("pointer");
1057
- return this;
1058
- }
1059
- }
1060
- class LogStyleBuilder {
1061
- logStyles = {};
1062
- logger;
1063
- constructor(logger) {
1064
- this.logger = logger;
1065
- }
1066
- /**
1067
- * Configure timestamp styling
1068
- */
1069
- timestamp() {
1070
- return new TimestampStyleBuilderProxy(this);
1071
- }
1072
- /**
1073
- * Configure level badge styling
1074
- */
1075
- level() {
1076
- return new LevelStyleBuilderProxy(this);
1077
- }
1078
- /**
1079
- * Configure prefix styling
1080
- */
1081
- prefix() {
1082
- return new PrefixStyleBuilderProxy(this);
1083
- }
1084
- /**
1085
- * Configure message text styling
1086
- */
1087
- message() {
1088
- return new MessageStyleBuilderProxy(this);
1089
- }
1090
- /**
1091
- * Configure location info styling
1092
- */
1093
- location() {
1094
- return new LocationStyleBuilderProxy(this);
1095
- }
1096
- /**
1097
- * Use a predefined preset
1098
- */
1099
- usePreset(presetName) {
1100
- console.warn(`Preset '${presetName}' will be available in next implementation phase`);
1101
- return this;
1102
- }
1103
- /**
1104
- * Customize with partial configuration
1105
- */
1106
- customize(overrides) {
1107
- this.logStyles = { ...this.logStyles, ...overrides };
1108
- return this;
1109
- }
1110
- /**
1111
- * Set layout spacing
1112
- */
1113
- spacing(type) {
1114
- if (!this.logStyles.layout) {
1115
- this.logStyles.layout = { spacing: type };
1116
- } else {
1117
- this.logStyles.layout.spacing = type;
1118
- }
1119
- switch (type) {
1120
- case "compact":
1121
- this.logStyles.layout.innerPadding = "1px";
1122
- this.logStyles.layout.outerMargin = "0px";
1123
- break;
1124
- case "spacious":
1125
- this.logStyles.layout.innerPadding = "4px";
1126
- this.logStyles.layout.outerMargin = "2px";
1127
- break;
1128
- default:
1129
- this.logStyles.layout.innerPadding = "2px";
1130
- this.logStyles.layout.outerMargin = "1px";
1131
- }
1132
- return this;
1133
- }
1134
- /**
1135
- * Set backdrop filter for glassmorphism effects
1136
- */
1137
- backdrop(filter) {
1138
- this.logStyles.backdrop = filter;
1139
- return this;
1140
- }
1141
- /**
1142
- * Set overall transparency
1143
- */
1144
- transparency(value) {
1145
- this.logStyles.transparency = Math.max(0, Math.min(1, value));
1146
- return this;
1147
- }
1148
- /**
1149
- * Apply the configured styles to the logger
1150
- */
1151
- apply() {
1152
- this.logger._customLogStyles = this.logStyles;
1153
- console.log("Applied log styles:", this.logStyles);
1154
- }
1155
- /**
1156
- * Get current configuration (for debugging)
1157
- */
1158
- getConfig() {
1159
- return { ...this.logStyles };
1160
- }
1161
- /**
1162
- * Internal method to update part configuration
1163
- */
1164
- _updatePartConfig(part, styles) {
1165
- if (part === "layout" || part === "backdrop" || part === "transparency") {
1166
- return;
1167
- }
1168
- if (!this.logStyles[part]) {
1169
- this.logStyles[part] = {};
1170
- }
1171
- this.logStyles[part].style = styles;
1172
- }
1173
- }
1174
- class PartStyleBuilderProxy {
1175
- parentBuilder;
1176
- partName;
1177
- constructor(parentBuilder, partName) {
1178
- this.parentBuilder = parentBuilder;
1179
- this.partName = partName;
1180
- }
1181
- /**
1182
- * Return to the main builder for chaining other parts
1183
- */
1184
- and() {
1185
- return this.parentBuilder;
1186
- }
1187
- /**
1188
- * Apply styles and finish configuration
1189
- */
1190
- apply() {
1191
- this.parentBuilder.apply();
1192
- }
1193
- /**
1194
- * Helper to apply styles to the parent builder
1195
- */
1196
- applyStyles(styler) {
1197
- const styles = styler.build();
1198
- this.parentBuilder._updatePartConfig(this.partName, styles);
1199
- return this;
1200
- }
1201
- }
1202
- class TimestampStyleBuilderProxy extends PartStyleBuilderProxy {
1203
- constructor(parentBuilder) {
1204
- super(parentBuilder, "timestamp");
1205
- }
1206
- default() {
1207
- return this.applyStyles(new TimestampStyler().default());
1208
- }
1209
- hidden() {
1210
- return this.applyStyles(new TimestampStyler().hidden());
1211
- }
1212
- minimal() {
1213
- return this.applyStyles(new TimestampStyler().minimal());
1214
- }
1215
- muted() {
1216
- return this.applyStyles(new TimestampStyler().muted());
1217
- }
1218
- mono() {
1219
- return this.applyStyles(new TimestampStyler().mono());
1220
- }
1221
- compact() {
1222
- return this.applyStyles(new TimestampStyler().compact());
1223
- }
1224
- }
1225
- class LevelStyleBuilderProxy extends PartStyleBuilderProxy {
1226
- constructor(parentBuilder) {
1227
- super(parentBuilder, "level");
1228
- }
1229
- badge() {
1230
- return this.applyStyles(new LevelStyler().badge());
1231
- }
1232
- gradient(from, to) {
1233
- return this.applyStyles(new LevelStyler().gradient(from, to));
1234
- }
1235
- glowing() {
1236
- return this.applyStyles(new LevelStyler().glowing());
1237
- }
1238
- flat() {
1239
- return this.applyStyles(new LevelStyler().flat());
1240
- }
1241
- bold() {
1242
- return this.applyStyles(new LevelStyler().bold());
1243
- }
1244
- uppercase() {
1245
- return this.applyStyles(new LevelStyler().uppercase());
1246
- }
1247
- neon() {
1248
- return this.applyStyles(new LevelStyler().neon());
1249
- }
1250
- }
1251
- class PrefixStyleBuilderProxy extends PartStyleBuilderProxy {
1252
- constructor(parentBuilder) {
1253
- super(parentBuilder, "prefix");
1254
- }
1255
- dark() {
1256
- return this.applyStyles(new PrefixStyler().dark());
1257
- }
1258
- light() {
1259
- return this.applyStyles(new PrefixStyler().light());
1260
- }
1261
- compact() {
1262
- return this.applyStyles(new PrefixStyler().compact());
1263
- }
1264
- muted() {
1265
- return this.applyStyles(new PrefixStyler().muted());
1266
- }
1267
- mono() {
1268
- return this.applyStyles(new PrefixStyler().mono());
1269
- }
1270
- }
1271
- class MessageStyleBuilderProxy extends PartStyleBuilderProxy {
1272
- constructor(parentBuilder) {
1273
- super(parentBuilder, "message");
1274
- }
1275
- readable() {
1276
- return this.applyStyles(new MessageStyler().readable());
1277
- }
1278
- code() {
1279
- return this.applyStyles(new MessageStyler().code());
1280
- }
1281
- large() {
1282
- return this.applyStyles(new MessageStyler().large());
1283
- }
1284
- system() {
1285
- return this.applyStyles(new MessageStyler().system());
1286
- }
1287
- mono() {
1288
- return this.applyStyles(new MessageStyler().mono());
1289
- }
1290
- }
1291
- class LocationStyleBuilderProxy extends PartStyleBuilderProxy {
1292
- constructor(parentBuilder) {
1293
- super(parentBuilder, "location");
1294
- }
1295
- subtle() {
1296
- return this.applyStyles(new LocationStyler().subtle());
1297
- }
1298
- hidden() {
1299
- return this.applyStyles(new LocationStyler().hidden());
1300
- }
1301
- clickable() {
1302
- return this.applyStyles(new LocationStyler().clickable());
1303
- }
1304
- muted() {
1305
- return this.applyStyles(new LocationStyler().muted());
1306
- }
1307
- mono() {
1308
- return this.applyStyles(new LocationStyler().mono());
1309
- }
1310
- }
1311
- function createLogStyleBuilder(logger) {
1312
- return new LogStyleBuilder(logger);
1313
- }
1314
- const SMART_PRESETS = {
1315
- /**
1316
- * Default preset - works perfectly out-of-the-box
1317
- * Clean, readable, automatically adaptive to dark/light themes
1318
- */
1319
- default: {
1320
- layout: {
1321
- spacing: "normal",
1322
- innerPadding: "2px",
1323
- outerMargin: "1px"
1324
- },
1325
- timestamp: {
1326
- show: true,
1327
- color: "auto",
1328
- // Automatically adaptive
1329
- font: "Monaco, Consolas, monospace",
1330
- size: "11px"
1331
- },
1332
- level: {
1333
- show: true,
1334
- style: "badge",
1335
- uppercase: false,
1336
- padding: "2px 8px"
1337
- },
1338
- prefix: {
1339
- show: true,
1340
- style: "dark",
1341
- // Automatically adaptive
1342
- padding: "2px 6px"
1343
- },
1344
- message: {
1345
- show: true,
1346
- color: "auto",
1347
- // Automatically adaptive
1348
- font: "system-ui, -apple-system, sans-serif",
1349
- size: "14px"
1350
- },
1351
- location: {
1352
- show: true,
1353
- color: "auto",
1354
- // Automatically adaptive
1355
- font: "Monaco, Consolas, monospace",
1356
- size: "11px"
1357
- }
1358
- },
1359
- /**
1360
- * Cyberpunk preset - neon colors, glowing effects, dark theme
1361
- */
1362
- cyberpunk: {
1363
- layout: {
1364
- spacing: "compact",
1365
- innerPadding: "1px",
1366
- outerMargin: "0px"
1367
- },
1368
- timestamp: {
1369
- show: true,
1370
- color: "#00ffff",
1371
- font: "Monaco, Consolas, monospace",
1372
- size: "10px",
1373
- style: "neon"
1374
- },
1375
- level: {
1376
- show: true,
1377
- style: "glowing",
1378
- uppercase: true,
1379
- padding: "2px 8px"
1380
- },
1381
- prefix: {
1382
- show: true,
1383
- color: "#ff0080",
1384
- background: "rgba(255, 0, 128, 0.1)",
1385
- border: "1px solid #ff0080",
1386
- style: "neon"
1387
- },
1388
- message: {
1389
- show: true,
1390
- color: "#00ff41",
1391
- font: "Monaco, Consolas, monospace",
1392
- size: "13px"
1393
- },
1394
- location: {
1395
- show: false
1396
- // Hidden for cleaner look
1397
- },
1398
- backdrop: "blur(2px)",
1399
- transparency: 0.9
1400
- },
1401
- /**
1402
- * Glassmorphism preset - modern blur effects, transparency
1403
- */
1404
- glassmorphism: {
1405
- layout: {
1406
- spacing: "spacious",
1407
- innerPadding: "4px",
1408
- outerMargin: "2px"
1409
- },
1410
- timestamp: {
1411
- show: true,
1412
- color: "auto",
1413
- font: "system-ui, sans-serif",
1414
- size: "11px",
1415
- style: "glassmorphic"
1416
- },
1417
- level: {
1418
- show: true,
1419
- style: "glassmorphic",
1420
- uppercase: false,
1421
- padding: "4px 12px"
1422
- },
1423
- prefix: {
1424
- show: true,
1425
- style: "glassmorphic",
1426
- padding: "3px 8px"
1427
- },
1428
- message: {
1429
- show: true,
1430
- color: "auto",
1431
- font: "system-ui, sans-serif",
1432
- size: "14px"
1433
- },
1434
- location: {
1435
- show: true,
1436
- color: "auto",
1437
- font: "system-ui, sans-serif",
1438
- size: "11px",
1439
- style: "glassmorphic"
1440
- },
1441
- backdrop: "blur(10px)",
1442
- transparency: 0.8
1443
- },
1444
- /**
1445
- * Minimal preset - clean, no decorations, maximum readability
1446
- */
1447
- minimal: {
1448
- layout: {
1449
- spacing: "compact",
1450
- innerPadding: "0px",
1451
- outerMargin: "0px"
1452
- },
1453
- timestamp: {
1454
- show: false
1455
- // Hidden for minimal look
1456
- },
1457
- level: {
1458
- show: true,
1459
- style: "flat",
1460
- uppercase: true,
1461
- padding: "0px 4px",
1462
- border: "none",
1463
- background: "transparent"
1464
- },
1465
- prefix: {
1466
- show: true,
1467
- style: "flat",
1468
- padding: "0px 4px",
1469
- border: "none",
1470
- background: "transparent"
1471
- },
1472
- message: {
1473
- show: true,
1474
- color: "auto",
1475
- font: "system-ui, sans-serif",
1476
- size: "14px"
1477
- },
1478
- location: {
1479
- show: false
1480
- // Hidden for minimal look
1481
- }
1482
- },
1483
- /**
1484
- * Debug preset - monospace, detailed, compact for development
1485
- */
1486
- debug: {
1487
- layout: {
1488
- spacing: "compact",
1489
- innerPadding: "1px",
1490
- outerMargin: "0px"
1491
- },
1492
- timestamp: {
1493
- show: true,
1494
- color: "auto",
1495
- font: "Monaco, Consolas, monospace",
1496
- size: "10px"
1497
- },
1498
- level: {
1499
- show: true,
1500
- style: "compact",
1501
- uppercase: true,
1502
- padding: "1px 4px",
1503
- font: "Monaco, Consolas, monospace",
1504
- size: "10px"
1505
- },
1506
- prefix: {
1507
- show: true,
1508
- style: "compact",
1509
- padding: "1px 4px",
1510
- font: "Monaco, Consolas, monospace",
1511
- size: "10px"
1512
- },
1513
- message: {
1514
- show: true,
1515
- color: "auto",
1516
- font: "Monaco, Consolas, monospace",
1517
- size: "12px"
1518
- },
1519
- location: {
1520
- show: true,
1521
- color: "auto",
1522
- font: "Monaco, Consolas, monospace",
1523
- size: "10px",
1524
- style: "clickable"
1525
- }
1526
- },
1527
- /**
1528
- * Production preset - clean, essential info only
1529
- */
1530
- production: {
1531
- layout: {
1532
- spacing: "normal",
1533
- innerPadding: "2px",
1534
- outerMargin: "1px"
1535
- },
1536
- timestamp: {
1537
- show: true,
1538
- color: "auto",
1539
- font: "system-ui, sans-serif",
1540
- size: "11px"
1541
- },
1542
- level: {
1543
- show: true,
1544
- style: "badge",
1545
- uppercase: false,
1546
- padding: "2px 6px"
1547
- },
1548
- prefix: {
1549
- show: false
1550
- // Hidden in production
1551
- },
1552
- message: {
1553
- show: true,
1554
- color: "auto",
1555
- font: "system-ui, sans-serif",
1556
- size: "14px"
1557
- },
1558
- location: {
1559
- show: false
1560
- // Hidden in production
1561
- }
1562
- }
1563
- };
1564
- function getSmartPreset(name) {
1565
- return SMART_PRESETS[name] || null;
1566
- }
1567
- function getAvailablePresets() {
1568
- return Object.keys(SMART_PRESETS);
1569
- }
1570
- function hasPreset(name) {
1571
- return name in SMART_PRESETS;
1572
- }
1573
- function stripAnsi(str) {
1574
- return str.replace(/\x1b\[[0-9;]*m/g, "");
1575
- }
1576
- function getVisibleLength(str) {
1577
- return stripAnsi(str).length;
1578
- }
1579
- function padToWidth(str, width, align = "left") {
1580
- const visibleLen = getVisibleLength(str);
1581
- if (visibleLen >= width) return str;
1582
- const padding = width - visibleLen;
1583
- switch (align) {
1584
- case "right":
1585
- return " ".repeat(padding) + str;
1586
- case "center":
1587
- const leftPad = Math.floor(padding / 2);
1588
- const rightPad = padding - leftPad;
1589
- return " ".repeat(leftPad) + str + " ".repeat(rightPad);
1590
- case "left":
1591
- default:
1592
- return str + " ".repeat(padding);
1593
- }
1594
- }
1595
- function formatWithRightAlign(leftContent, rightContent, maxWidth) {
1596
- const width = maxWidth ?? getTerminalWidth();
1597
- const leftLen = getVisibleLength(leftContent);
1598
- const rightLen = getVisibleLength(rightContent);
1599
- const gap = width - leftLen - rightLen;
1600
- if (gap <= 1) {
1601
- return `${leftContent} ${rightContent}`;
1602
- }
1603
- return `${leftContent}${" ".repeat(gap)}${rightContent}`;
1604
- }
1605
- function formatColumns(columns, maxWidth, colorCapability = "full") {
1606
- const width = maxWidth ?? getTerminalWidth();
1607
- columns.length;
1608
- const columnsWithWidths = columns.map((col, idx) => {
1609
- if (col.width) return { ...col, calculatedWidth: col.width };
1610
- const remainingWidth = width - columns.filter((c, i) => i !== idx && c.width).reduce((sum, c) => sum + (c.width ?? 0), 0);
1611
- const autoColumns = columns.filter((c) => !c.width).length;
1612
- const calculatedWidth = Math.floor(remainingWidth / autoColumns);
1613
- return { ...col, calculatedWidth };
1614
- });
1615
- return columnsWithWidths.map((col) => {
1616
- let content = col.content;
1617
- if (col.color && colorCapability !== "none") {
1618
- const colorCode = getANSIForeground(col.color, colorCapability);
1619
- content = `${colorCode}${content}${ANSI.reset}`;
1620
- }
1621
- return padToWidth(content, col.calculatedWidth, col.align);
1622
- }).join("");
1623
- }
1624
- function formatKeyValue(obj, colorCapability = "full", options = {}) {
1625
- const {
1626
- separator = " ",
1627
- keyColor = "#888888",
1628
- valueColor = "#00ffff"
1629
- } = options;
1630
- const entries = Object.entries(obj);
1631
- if (entries.length === 0) return "";
1632
- const keyColorCode = colorCapability !== "none" ? getANSIForeground(keyColor, colorCapability) : "";
1633
- const valueColorCode = colorCapability !== "none" ? getANSIForeground(valueColor, colorCapability) : "";
1634
- const reset = colorCapability !== "none" ? ANSI.reset : "";
1635
- return entries.map(([key, value]) => {
1636
- const valueStr = typeof value === "object" ? JSON.stringify(value) : String(value);
1637
- return `${keyColorCode}${key}:${reset} ${valueColorCode}${valueStr}${reset}`;
1638
- }).join(separator);
1639
- }
1640
- function isKeyValueObject(obj) {
1641
- if (typeof obj !== "object" || obj === null) return false;
1642
- if (Array.isArray(obj)) return false;
1643
- const proto = Object.getPrototypeOf(obj);
1644
- if (proto !== Object.prototype && proto !== null) return false;
1645
- const values = Object.values(obj);
1646
- return values.every(
1647
- (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v === null
1648
- );
1649
- }
1650
- function formatBadge(badge, style = "brackets", colorCapability = "full", color) {
1651
- const colorCode = color && colorCapability !== "none" ? getANSIForeground(color, colorCapability) : "";
1652
- const reset = colorCapability !== "none" ? ANSI.reset : "";
1653
- const bgBlack = colorCapability !== "none" ? ANSI.bg.black : "";
1654
- const text = badge.toUpperCase();
1655
- switch (style) {
1656
- case "rounded":
1657
- return `${bgBlack}${colorCode}⟨${text}⟩${reset}`;
1658
- case "plain":
1659
- return `${colorCode}${text}${reset}`;
1660
- case "unicode":
1661
- return `${bgBlack}${colorCode}╭${text}╮${reset}`;
1662
- case "pill":
1663
- return `${bgBlack}${colorCode}⦗${text}⦘${reset}`;
1664
- case "brackets":
1665
- default:
1666
- return `${bgBlack}${colorCode}[${text}]${reset}`;
1667
- }
1668
- }
1669
- function formatTimestamp(date = /* @__PURE__ */ new Date(), format = "time") {
1670
- switch (format) {
1671
- case "iso":
1672
- return date.toISOString();
1673
- case "date":
1674
- return date.toISOString().split("T")[0] ?? "";
1675
- case "time":
1676
- return date.toTimeString().slice(0, 8);
1677
- case "timeMs":
1678
- return date.toTimeString().slice(0, 8) + "." + String(date.getMilliseconds()).padStart(3, "0");
1679
- case "relative":
1680
- return formatRelativeTime(date);
1681
- case "elapsed":
1682
- return formatElapsedTime(date);
1683
- case "custom":
1684
- default:
1685
- return date.toLocaleTimeString();
1686
- }
1687
- }
1688
- let startTime = null;
1689
- function formatRelativeTime(date) {
1690
- if (startTime === null) {
1691
- startTime = Date.now();
1692
- }
1693
- const diff = date.getTime() - startTime;
1694
- if (diff < 1e3) {
1695
- return `+${diff}ms`;
1696
- } else if (diff < 6e4) {
1697
- return `+${(diff / 1e3).toFixed(1)}s`;
1698
- } else {
1699
- const mins = Math.floor(diff / 6e4);
1700
- const secs = Math.floor(diff % 6e4 / 1e3);
1701
- return `+${mins}m${secs}s`;
1702
- }
1703
- }
1704
- function formatElapsedTime(date) {
1705
- if (startTime === null) {
1706
- startTime = Date.now();
1707
- }
1708
- const diff = date.getTime() - startTime;
1709
- const hours = Math.floor(diff / 36e5);
1710
- const mins = Math.floor(diff % 36e5 / 6e4);
1711
- const secs = Math.floor(diff % 6e4 / 1e3);
1712
- return `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
1713
- }
1714
- function resetStartTime() {
1715
- startTime = Date.now();
1716
- }
1717
- function applyLogOptions(message, options, colorCapability = "full") {
1718
- let result = message;
1719
- if (options.rightAlign) {
1720
- result = formatWithRightAlign(message, options.rightAlign);
1721
- }
1722
- return result;
1723
- }
1724
- class ScopedLogger {
1725
- parent;
1726
- scopeName;
1727
- badgeList = [];
1728
- contextStack = [];
1729
- _timers;
1730
- constructor(parent, scopeName) {
1731
- this.parent = parent;
1732
- this.scopeName = scopeName;
1733
- }
1734
- get timers() {
1735
- if (!this._timers) this._timers = /* @__PURE__ */ new Map();
1736
- return this._timers;
1737
- }
1738
- getBindings() {
1739
- return {
1740
- scope: this.getScopePrefix(),
1741
- badges: this.badgeList.length > 0 ? [...this.badgeList] : void 0
1742
- };
1743
- }
1744
- getScopePrefix() {
1745
- if (this.contextStack.length === 0) return this.scopeName;
1746
- return [this.scopeName, ...this.contextStack].join(":");
1747
- }
1748
- badges(badges) {
1749
- this.badgeList = [...badges];
1750
- return this;
1751
- }
1752
- badge(badge) {
1753
- if (!this.badgeList.includes(badge)) {
1754
- this.badgeList.push(badge);
1755
- }
1756
- return this;
1757
- }
1758
- clearBadges() {
1759
- this.badgeList = [];
1760
- return this;
1761
- }
1762
- style(presetName) {
1763
- this.parent.setTheme(presetName);
1764
- return this;
1765
- }
1766
- context(contextName) {
1767
- return new ContextLogger(this, contextName);
1768
- }
1769
- time(label) {
1770
- this.timers.set(label, {
1771
- label: `${this.scopeName}:${label}`,
1772
- startTime: performance.now()
1773
- });
1774
- }
1775
- timeEnd(label) {
1776
- const timer = this.timers.get(label);
1777
- if (!timer) {
1778
- this.warn(`Timer '${label}' not found`);
1779
- return void 0;
1780
- }
1781
- const elapsed = performance.now() - timer.startTime;
1782
- this.timers.delete(label);
1783
- this.success(`Timer: ${label} - ${elapsed.toFixed(2)}ms`);
1784
- return elapsed;
1785
- }
1786
- debug(...args) {
1787
- this.parent.logWithBindings(this.getBindings(), "debug", ...args);
1788
- }
1789
- info(...args) {
1790
- this.parent.logWithBindings(this.getBindings(), "info", ...args);
1791
- }
1792
- warn(...args) {
1793
- this.parent.logWithBindings(this.getBindings(), "warn", ...args);
1794
- }
1795
- error(...args) {
1796
- this.parent.logWithBindings(this.getBindings(), "error", ...args);
1797
- }
1798
- success(...args) {
1799
- const bindings = this.getBindings();
1800
- this.parent.logWithBindings(bindings, "info", ...args);
1801
- }
1802
- critical(...args) {
1803
- this.parent.logWithBindings(this.getBindings(), "critical", ...args);
1804
- }
1805
- trace(...args) {
1806
- this.parent.logWithBindings(this.getBindings(), "debug", ...args);
1807
- console.trace(`[${this.scopeName}]`);
1808
- }
1809
- _pushContext(context) {
1810
- this.contextStack.push(context);
1811
- }
1812
- _popContext() {
1813
- this.contextStack.pop();
1814
- }
1815
- }
1816
- class APILogger extends ScopedLogger {
1817
- constructor(parent, apiName) {
1818
- super(parent, `API:${apiName}`);
1819
- this.badge("API");
1820
- }
1821
- slow(message, duration) {
1822
- this.badge("SLOW");
1823
- const msg = duration ? `${message} (${duration}ms)` : message;
1824
- this.warn(msg);
1825
- }
1826
- rateLimit(message) {
1827
- this.badge("RATE_LIMIT");
1828
- this.warn(message);
1829
- }
1830
- auth(message) {
1831
- this.badge("AUTH");
1832
- this.error(message);
1833
- }
1834
- deprecated(message) {
1835
- this.badge("DEPRECATED");
1836
- this.warn(message);
1837
- }
1838
- }
1839
- class ComponentLogger extends ScopedLogger {
1840
- constructor(parent, componentName) {
1841
- super(parent, componentName);
1842
- this.badge("COMPONENT");
1843
- }
1844
- lifecycle(event, message) {
1845
- this.badge("LIFECYCLE");
1846
- const msg = message ? `${event}: ${message}` : event;
1847
- this.info(msg);
1848
- }
1849
- stateChange(from, to, data) {
1850
- this.badge("STATE");
1851
- const msg = `${from} → ${to}`;
1852
- if (data) {
1853
- this.info(msg, data);
1854
- } else {
1855
- this.info(msg);
1856
- }
1857
- }
1858
- propsChange(changes) {
1859
- this.badge("PROPS");
1860
- this.debug("Props changed:", changes);
1861
- }
1862
- }
1863
- class ContextLogger {
1864
- parentLogger;
1865
- contextName;
1866
- constructor(parentLogger, contextName) {
1867
- this.parentLogger = parentLogger;
1868
- this.contextName = contextName;
1869
- }
1870
- run(fn) {
1871
- this.parentLogger._pushContext(this.contextName);
1872
- try {
1873
- return fn();
1874
- } finally {
1875
- this.parentLogger._popContext();
1876
- }
1877
- }
1878
- async runAsync(fn) {
1879
- this.parentLogger._pushContext(this.contextName);
1880
- try {
1881
- return await fn();
1882
- } finally {
1883
- this.parentLogger._popContext();
1884
- }
1885
- }
1886
- start() {
1887
- this.parentLogger._pushContext(this.contextName);
1888
- }
1889
- end() {
1890
- this.parentLogger._popContext();
1891
- }
1892
- debug(...args) {
1893
- this.parentLogger.debug(...args);
1894
- }
1895
- info(...args) {
1896
- this.parentLogger.info(...args);
1897
- }
1898
- warn(...args) {
1899
- this.parentLogger.warn(...args);
1900
- }
1901
- error(...args) {
1902
- this.parentLogger.error(...args);
1903
- }
1904
- success(...args) {
1905
- this.parentLogger.success(...args);
1906
- }
1907
- critical(...args) {
1908
- this.parentLogger.critical(...args);
1909
- }
1910
- }
1911
- class ExportLogHandler {
1912
- buffer = [];
1913
- maxSize;
1914
- groupDepth = 0;
1915
- currentGroup;
1916
- constructor(maxSize = BUFFER_LIMITS.DEFAULT_SIZE) {
1917
- this.maxSize = Math.min(Math.max(maxSize, BUFFER_LIMITS.MIN_SIZE), BUFFER_LIMITS.MAX_SIZE);
1918
- }
1919
- /**
1920
- * Handle incoming log and store in buffer
1921
- */
1922
- handle(level, message, args, metadata) {
1923
- const entry = {
1924
- id: generateLogId(),
1925
- timestamp: metadata.timestamp,
1926
- level,
1927
- prefix: metadata.prefix,
1928
- message,
1929
- args,
1930
- location: metadata.stackInfo,
1931
- groupInfo: this.groupDepth > 0 ? {
1932
- depth: this.groupDepth,
1933
- groupName: this.currentGroup
1934
- } : void 0
1935
- };
1936
- this.buffer.push(entry);
1937
- if (this.buffer.length > this.maxSize) {
1938
- this.buffer.shift();
1939
- }
1940
- }
1941
- /**
1942
- * Set group tracking for nested logs
1943
- */
1944
- setGroupInfo(depth, groupName) {
1945
- this.groupDepth = depth;
1946
- this.currentGroup = groupName;
1947
- }
1948
- /**
1949
- * Get buffer statistics
1950
- */
1951
- getBufferStats() {
1952
- const levelCounts = this.buffer.reduce((acc, entry) => {
1953
- const currentCount = acc[entry.level] ? acc[entry.level] : 0;
1954
- acc[entry.level] = currentCount + 1;
1955
- return acc;
1956
- }, {});
1957
- let oldestLog;
1958
- let newestLog;
1959
- if (this.buffer.length > 0) {
1960
- const firstEntry = this.buffer[0];
1961
- const lastEntry = this.buffer[this.buffer.length - 1];
1962
- if (firstEntry && firstEntry.timestamp) {
1963
- oldestLog = new Date(firstEntry.timestamp);
1964
- }
1965
- if (lastEntry && lastEntry.timestamp) {
1966
- newestLog = new Date(lastEntry.timestamp);
1967
- }
1968
- }
1969
- return {
1970
- size: this.buffer.length,
1971
- maxSize: this.maxSize,
1972
- usage: this.buffer.length / this.maxSize * 100,
1973
- oldestLog,
1974
- newestLog,
1975
- levelCounts: {
1976
- debug: levelCounts.debug ? levelCounts.debug : 0,
1977
- info: levelCounts.info ? levelCounts.info : 0,
1978
- warn: levelCounts.warn ? levelCounts.warn : 0,
1979
- error: levelCounts.error ? levelCounts.error : 0,
1980
- critical: levelCounts.critical ? levelCounts.critical : 0
1981
- }
1982
- };
1983
- }
1984
- /**
1985
- * Clear the buffer
1986
- */
1987
- clearBuffer() {
1988
- this.buffer = [];
1989
- }
1990
- /**
1991
- * Set buffer size (with limits)
1992
- */
1993
- setBufferSize(size) {
1994
- this.maxSize = Math.min(Math.max(size, BUFFER_LIMITS.MIN_SIZE), BUFFER_LIMITS.MAX_SIZE);
1995
- if (this.buffer.length > this.maxSize) {
1996
- this.buffer = this.buffer.slice(-this.maxSize);
1997
- }
1998
- }
1999
- /**
2000
- * Filter logs based on criteria
2001
- */
2002
- filterLogs(filters = {}) {
2003
- let filtered = [...this.buffer];
2004
- if (filters.levels?.length) {
2005
- filtered = filtered.filter((entry) => filters.levels.includes(entry.level));
2006
- }
2007
- if (filters.prefixes?.length) {
2008
- filtered = filtered.filter(
2009
- (entry) => entry.prefix && filters.prefixes.includes(entry.prefix)
2010
- );
2011
- }
2012
- if (filters.excludePrefixes?.length) {
2013
- filtered = filtered.filter(
2014
- (entry) => !entry.prefix || !filters.excludePrefixes.includes(entry.prefix)
2015
- );
2016
- }
2017
- if (filters.since) {
2018
- const sinceDate = parseTimeInput(filters.since);
2019
- filtered = filtered.filter((entry) => new Date(entry.timestamp) >= sinceDate);
2020
- }
2021
- if (filters.until) {
2022
- const untilDate = parseTimeInput(filters.until);
2023
- filtered = filtered.filter((entry) => new Date(entry.timestamp) <= untilDate);
2024
- }
2025
- if (filters.withStackTrace) {
2026
- filtered = filtered.filter((entry) => entry.location);
2027
- }
2028
- if (filters.errorsOnly) {
2029
- filtered = filtered.filter((entry) => entry.level === "error" || entry.level === "critical");
2030
- }
2031
- if (filters.search) {
2032
- const searchTerm = filters.search.toLowerCase();
2033
- filtered = filtered.filter(
2034
- (entry) => entry.message.toLowerCase().includes(searchTerm) || entry.args.some(
2035
- (arg) => String(arg).toLowerCase().includes(searchTerm)
2036
- )
2037
- );
2038
- }
2039
- if (filters.last) {
2040
- filtered = filtered.slice(-filters.last);
2041
- }
2042
- if (filters.first) {
2043
- filtered = filtered.slice(0, filters.first);
2044
- }
2045
- return filtered;
2046
- }
2047
- /**
2048
- * Export logs in JSON format
2049
- */
2050
- exportJSON(logs, options) {
2051
- const data = logs.map((entry) => ({
2052
- timestamp: entry.timestamp,
2053
- level: entry.level,
2054
- prefix: entry.prefix,
2055
- message: entry.message,
2056
- ...options.minimal ? {} : {
2057
- args: entry.args.slice(1),
2058
- location: entry.location,
2059
- groupInfo: entry.groupInfo
2060
- }
2061
- }));
2062
- return options.compact ? JSON.stringify(data) : JSON.stringify(data, null, 2);
2063
- }
2064
- /**
2065
- * Export logs in CSV format
2066
- */
2067
- exportCSV(logs, options) {
2068
- const headers = options.minimal ? ["Timestamp", "Level", "Prefix", "Message"] : ["Timestamp", "Level", "Prefix", "Message", "File", "Line", "Args"];
2069
- const rows = logs.map((entry) => {
2070
- const baseRow = [
2071
- formatDisplayTime(new Date(entry.timestamp), "full"),
2072
- entry.level.toUpperCase(),
2073
- entry.prefix || "",
2074
- `"${entry.message.replace(/"/g, '""')}"`
2075
- ];
2076
- if (!options.minimal) {
2077
- baseRow.push(
2078
- entry.location?.file || "",
2079
- entry.location?.line?.toString() || "",
2080
- `"${safeStringify(entry.args.slice(1)).replace(/"/g, '""')}"`
2081
- );
2082
- }
2083
- return baseRow;
2084
- });
2085
- return [headers.join(","), ...rows.map((row) => row.join(","))].join("\n");
2086
- }
2087
- /**
2088
- * Export logs in Markdown format
2089
- */
2090
- exportMarkdown(logs, options) {
2091
- const now = /* @__PURE__ */ new Date();
2092
- let content = `# Log Export - ${formatDisplayTime(now, "full")}
2093
-
2094
- `;
2095
- if (!options.minimal) {
2096
- const summary = this.getBufferStats();
2097
- content += `## Summary
2098
- `;
2099
- content += `- **Total logs**: ${logs.length}
2100
- `;
2101
- content += `- **Errors**: ${summary.levelCounts.error + summary.levelCounts.critical}
2102
- `;
2103
- content += `- **Warnings**: ${summary.levelCounts.warn}
2104
-
2105
- `;
2106
- }
2107
- if (options.groupBy === "level") {
2108
- const grouped = logs.reduce((acc, entry) => {
2109
- const level = entry.level;
2110
- if (!acc[level]) {
2111
- acc[level] = [];
2112
- }
2113
- const levelArray = acc[level];
2114
- if (levelArray) {
2115
- levelArray.push(entry);
2116
- }
2117
- return acc;
2118
- }, {});
2119
- Object.entries(grouped).forEach(([level, entries]) => {
2120
- const emoji = this.getLevelEmoji(level);
2121
- content += `## ${emoji} ${level.toUpperCase()} (${entries.length})
2122
-
2123
- `;
2124
- entries.forEach((entry) => {
2125
- const time = formatDisplayTime(new Date(entry.timestamp), "time-only");
2126
- const location = entry.location ? ` (${entry.location.file}:${entry.location.line})` : "";
2127
- const prefix = entry.prefix ? ` **${entry.prefix}**:` : "";
2128
- content += `- \`${time}\`${prefix} ${entry.message}${location}
2129
- `;
2130
- });
2131
- content += "\n";
2132
- });
2133
- } else {
2134
- content += "## Logs\n\n";
2135
- logs.forEach((entry) => {
2136
- const time = formatDisplayTime(new Date(entry.timestamp), "time-only");
2137
- const emoji = this.getLevelEmoji(entry.level);
2138
- const location = entry.location ? ` (${entry.location.file}:${entry.location.line})` : "";
2139
- const prefix = entry.prefix ? ` **${entry.prefix}**:` : "";
2140
- content += `- \`${time}\` ${emoji}${prefix} ${entry.message}${location}
2141
- `;
2142
- });
2143
- }
2144
- return content;
2145
- }
2146
- /**
2147
- * Export logs in plain text format
2148
- */
2149
- exportPlain(logs, options) {
2150
- return logs.map((entry) => {
2151
- const time = formatDisplayTime(new Date(entry.timestamp), options.minimal ? "time-only" : "short");
2152
- const level = entry.level.toUpperCase().padEnd(8);
2153
- const prefix = entry.prefix ? `[${entry.prefix}] ` : "";
2154
- const location = !options.minimal && entry.location ? ` (${entry.location.file}:${entry.location.line})` : "";
2155
- return `${time} ${level} ${prefix}${entry.message}${location}`;
2156
- }).join("\n");
2157
- }
2158
- /**
2159
- * Export logs in HTML format
2160
- */
2161
- exportHTML(logs, _options) {
2162
- const title = `Log Export - ${formatDisplayTime(/* @__PURE__ */ new Date(), "full")}`;
2163
- let html = `<!DOCTYPE html>
2164
- <html lang="en">
2165
- <head>
2166
- <meta charset="UTF-8">
2167
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
2168
- <title>${title}</title>
2169
- <style>
2170
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 20px; line-height: 1.6; }
2171
- .header { border-bottom: 2px solid #ddd; padding-bottom: 20px; margin-bottom: 20px; }
2172
- .log-entry { margin: 5px 0; padding: 8px; border-radius: 4px; font-family: 'Monaco', 'Consolas', monospace; }
2173
- .timestamp { color: #666; font-size: 0.9em; }
2174
- .level { font-weight: bold; padding: 2px 6px; border-radius: 3px; margin: 0 8px; }
2175
- .prefix { background: #2d3748; color: #e2e8f0; padding: 2px 6px; border-radius: 3px; margin: 0 8px; }
2176
- .location { color: #718096; font-size: 0.9em; }
2177
- .debug { background: #f0f4ff; }
2178
- .info { background: #f0f9ff; }
2179
- .warn { background: #fffbeb; }
2180
- .error { background: #fef2f2; }
2181
- .critical { background: #fef2f2; border-left: 4px solid #dc2626; }
2182
- .level.debug { background: #667eea; color: white; }
2183
- .level.info { background: #74b9ff; color: white; }
2184
- .level.warn { background: #fdcb6e; color: #2d3436; }
2185
- .level.error { background: #e84393; color: white; }
2186
- .level.critical { background: #ff3838; color: white; }
2187
- </style>
2188
- </head>
2189
- <body>
2190
- <div class="header">
2191
- <h1>${title}</h1>
2192
- <p>Generated by Advanced Logger v2.0.0</p>
2193
- </div>
2194
- <div class="logs">`;
2195
- logs.forEach((entry) => {
2196
- const time = formatDisplayTime(new Date(entry.timestamp), "full");
2197
- const location = entry.location ? ` <span class="location">(${escapeHtml(entry.location.file)}:${entry.location.line})</span>` : "";
2198
- const prefix = entry.prefix ? ` <span class="prefix">${escapeHtml(entry.prefix)}</span>` : "";
2199
- html += `
2200
- <div class="log-entry ${entry.level}">
2201
- <span class="timestamp">${time}</span>
2202
- <span class="level ${entry.level}">${entry.level.toUpperCase()}</span>
2203
- ${prefix}
2204
- <span class="message">${escapeHtml(entry.message)}</span>
2205
- ${location}
2206
- </div>`;
2207
- });
2208
- html += `
2209
- </div>
2210
- </body>
2211
- </html>`;
2212
- return html;
2213
- }
2214
- /**
2215
- * Get emoji for log level
2216
- */
2217
- getLevelEmoji(level) {
2218
- const emojis = {
2219
- debug: "🐞",
2220
- info: "ℹ️",
2221
- warn: "⚠️",
2222
- error: "❌",
2223
- critical: "🔥"
2224
- };
2225
- return emojis[level] || "";
2226
- }
2227
- /**
2228
- * Main export function
2229
- */
2230
- export(format, filters = {}, options = {}) {
2231
- const filteredLogs = this.filterLogs(filters);
2232
- let data;
2233
- switch (format) {
2234
- case "json":
2235
- data = this.exportJSON(filteredLogs, options);
2236
- break;
2237
- case "csv":
2238
- data = this.exportCSV(filteredLogs, options);
2239
- break;
2240
- case "markdown":
2241
- data = this.exportMarkdown(filteredLogs, options);
2242
- break;
2243
- case "plain":
2244
- data = this.exportPlain(filteredLogs, options);
2245
- break;
2246
- case "html":
2247
- data = this.exportHTML(filteredLogs, options);
2248
- break;
2249
- default:
2250
- throw new Error(`Unsupported export format: ${format}`);
2251
- }
2252
- return {
2253
- format,
2254
- data,
2255
- metadata: {
2256
- totalLogs: this.buffer.length,
2257
- filteredLogs: filteredLogs.length,
2258
- exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
2259
- filters,
2260
- options
2261
- }
2262
- };
2263
- }
2264
- /**
2265
- * Copy to clipboard with fallback
2266
- */
2267
- async copyToClipboard(format, filters = {}, options = {}) {
2268
- const result = this.export(format, filters, options);
2269
- try {
2270
- if (navigator.clipboard && window.isSecureContext) {
2271
- await navigator.clipboard.writeText(result.data);
2272
- return true;
2273
- } else {
2274
- const textArea = document.createElement("textarea");
2275
- textArea.value = result.data;
2276
- textArea.style.position = "fixed";
2277
- textArea.style.opacity = "0";
2278
- document.body.appendChild(textArea);
2279
- textArea.focus();
2280
- textArea.select();
2281
- const success = document.execCommand("copy");
2282
- document.body.removeChild(textArea);
2283
- return success;
2284
- }
2285
- } catch (error) {
2286
- console.error("Failed to copy to clipboard:", error);
2287
- return false;
2288
- }
2289
- }
2290
- /**
2291
- * Get all logs (for debugging)
2292
- */
2293
- getAllLogs() {
2294
- return [...this.buffer];
2295
- }
2296
- /**
2297
- * Save export to file with download prompt
2298
- */
2299
- async saveToFile(format, filters = {}, options = {}) {
2300
- try {
2301
- const result = this.export(format, filters, options);
2302
- const blob = new Blob([result.data], {
2303
- type: this.getMimeType(format)
2304
- });
2305
- const url = URL.createObjectURL(blob);
2306
- const a = document.createElement("a");
2307
- const filename = this.generateFilename(format, filters);
2308
- a.href = url;
2309
- a.download = filename;
2310
- a.style.display = "none";
2311
- document.body.appendChild(a);
2312
- a.click();
2313
- document.body.removeChild(a);
2314
- URL.revokeObjectURL(url);
2315
- return true;
2316
- } catch (error) {
2317
- console.error("Failed to save file:", error);
2318
- return false;
2319
- }
2320
- }
2321
- /**
2322
- * Get MIME type for format
2323
- */
2324
- getMimeType(format) {
2325
- const mimeTypes = {
2326
- json: "application/json",
2327
- csv: "text/csv",
2328
- markdown: "text/markdown",
2329
- plain: "text/plain",
2330
- html: "text/html"
2331
- };
2332
- return mimeTypes[format] || "text/plain";
2333
- }
2334
- /**
2335
- * Generate filename with timestamp
2336
- */
2337
- generateFilename(format, filters) {
2338
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, -5);
2339
- const prefix = filters.prefixes?.length === 1 ? `_${filters.prefixes[0]}` : "";
2340
- const extension = format === "markdown" ? "md" : format;
2341
- return `logs${prefix}_${timestamp}.${extension}`;
2342
- }
2343
- /**
2344
- * Stream logs to external endpoint
2345
- */
2346
- async streamToEndpoint(endpoint, filters = {}, options = {}) {
2347
- try {
2348
- const logs = this.filterLogs(filters);
2349
- const batchSize = options.batchSize || 100;
2350
- const format = options.format || "json";
2351
- for (let i = 0; i < logs.length; i += batchSize) {
2352
- const batch = logs.slice(i, i + batchSize);
2353
- const result = this.export(format, {}, { compact: true });
2354
- const headers = {
2355
- "Content-Type": "application/json"
2356
- };
2357
- if (options.apiKey) {
2358
- headers["Authorization"] = `Bearer ${options.apiKey}`;
2359
- }
2360
- const response = await fetch(endpoint, {
2361
- method: "POST",
2362
- headers,
2363
- body: JSON.stringify({
2364
- logs: batch,
2365
- metadata: {
2366
- batchIndex: Math.floor(i / batchSize),
2367
- totalBatches: Math.ceil(logs.length / batchSize),
2368
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
2369
- }
2370
- })
2371
- });
2372
- if (!response.ok) {
2373
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2374
- }
2375
- }
2376
- return true;
2377
- } catch (error) {
2378
- console.error("Failed to stream logs:", error);
2379
- return false;
2380
- }
2381
- }
2382
- /**
2383
- * Create export with metadata enrichment
2384
- */
2385
- exportWithMetadata(format, filters = {}, options = {}) {
2386
- const baseResult = this.export(format, filters, options);
2387
- const bufferStats = this.getBufferStats();
2388
- return {
2389
- ...baseResult,
2390
- metadata: {
2391
- ...baseResult.metadata,
2392
- bufferStats,
2393
- performance: {
2394
- memoryUsage: this.estimateMemoryUsage(),
2395
- processingTime: Date.now()
2396
- },
2397
- system: {
2398
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "Node.js",
2399
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2400
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
2401
- }
2402
- }
2403
- };
2404
- }
2405
- /**
2406
- * Estimate memory usage of buffer
2407
- */
2408
- estimateMemoryUsage() {
2409
- const sampleEntry = this.buffer[0];
2410
- if (!sampleEntry) return 0;
2411
- const sampleSize = JSON.stringify(sampleEntry).length;
2412
- return sampleSize * this.buffer.length;
2413
- }
2414
- }
2415
- class CommandProcessor {
2416
- commands = /* @__PURE__ */ new Map();
2417
- aliases = /* @__PURE__ */ new Map();
2418
- plugins = /* @__PURE__ */ new Map();
2419
- history = [];
2420
- maxHistorySize = 100;
2421
- isInteractiveMode = false;
2422
- /**
2423
- * Register a command
2424
- */
2425
- registerCommand(command) {
2426
- this.commands.set(command.name, command);
2427
- if (command.aliases) {
2428
- for (const alias of command.aliases) {
2429
- this.aliases.set(alias, command.name);
2430
- }
2431
- }
2432
- }
2433
- /**
2434
- * Register a plugin
2435
- */
2436
- registerPlugin(plugin, logger) {
2437
- if (this.plugins.has(plugin.name)) {
2438
- throw new Error(`Plugin ${plugin.name} is already registered`);
2439
- }
2440
- this.plugins.set(plugin.name, plugin);
2441
- for (const command of plugin.commands) {
2442
- this.registerCommand(command);
2443
- }
2444
- if (plugin.initialize && logger) {
2445
- plugin.initialize(this, logger);
2446
- }
2447
- }
2448
- /**
2449
- * Unregister a plugin
2450
- */
2451
- unregisterPlugin(pluginName) {
2452
- const plugin = this.plugins.get(pluginName);
2453
- if (!plugin) return;
2454
- for (const command of plugin.commands) {
2455
- this.commands.delete(command.name);
2456
- if (command.aliases) {
2457
- for (const alias of command.aliases) {
2458
- this.aliases.delete(alias);
2459
- }
2460
- }
2461
- }
2462
- if (plugin.cleanup) {
2463
- plugin.cleanup();
2464
- }
2465
- this.plugins.delete(pluginName);
2466
- }
2467
- /**
2468
- * Get all registered commands
2469
- */
2470
- getCommands() {
2471
- return Array.from(this.commands.values());
2472
- }
2473
- /**
2474
- * Get a specific command
2475
- */
2476
- getCommand(name) {
2477
- let command = this.commands.get(name);
2478
- if (command) return command;
2479
- const aliasTarget = this.aliases.get(name);
2480
- if (aliasTarget) {
2481
- return this.commands.get(aliasTarget);
2482
- }
2483
- return void 0;
2484
- }
2485
- /**
2486
- * Get command history
2487
- */
2488
- getHistory() {
2489
- return [...this.history];
2490
- }
2491
- /**
2492
- * Clear command history
2493
- */
2494
- clearHistory() {
2495
- this.history = [];
2496
- }
2497
- /**
2498
- * Get registered plugins
2499
- */
2500
- getPlugins() {
2501
- return Array.from(this.plugins.values());
2502
- }
2503
- /**
2504
- * Enter interactive mode
2505
- */
2506
- enterInteractiveMode(logger) {
2507
- this.isInteractiveMode = true;
2508
- logger.info("🔧 Interactive CLI mode activated. Type /exit to quit, /help for commands.");
2509
- if (typeof window !== "undefined") {
2510
- this.setupBrowserInteractiveMode(logger);
2511
- }
2512
- }
2513
- /**
2514
- * Exit interactive mode
2515
- */
2516
- exitInteractiveMode() {
2517
- this.isInteractiveMode = false;
2518
- }
2519
- /**
2520
- * Setup browser interactive mode
2521
- */
2522
- setupBrowserInteractiveMode(logger) {
2523
- window.cli = (commandString) => {
2524
- return this.processCommand(`/${commandString}`, logger);
2525
- };
2526
- logger.info('💡 Use cli("command") to execute CLI commands in browser console.');
2527
- }
2528
- /**
2529
- * Process a CLI command
2530
- */
2531
- async processCommand(commandString, logger) {
2532
- if (!commandString.startsWith("/")) {
2533
- logger.error("Invalid command. Commands must start with /");
2534
- this.addToHistory(commandString, false);
2535
- return;
2536
- }
2537
- const parts = commandString.slice(1).split(" ");
2538
- const commandName = parts[0] || "";
2539
- const args = parts.slice(1).join(" ");
2540
- const command = this.getCommand(commandName);
2541
- if (!command) {
2542
- logger.error(`Unknown command: ${commandName}. Type /help for available commands.`);
2543
- const suggestions = this.getSuggestions(commandName);
2544
- if (suggestions.length > 0) {
2545
- logger.info(`📋 Did you mean: ${suggestions.slice(0, 3).join(", ")}?`);
2546
- }
2547
- this.addToHistory(commandString, false);
2548
- return;
2549
- }
2550
- try {
2551
- await command.execute(args || "", logger);
2552
- this.addToHistory(commandString, true);
2553
- } catch (error) {
2554
- logger.error(`Command '${commandName}' failed:`, error);
2555
- this.addToHistory(commandString, false);
2556
- }
2557
- }
2558
- /**
2559
- * Add command to history
2560
- */
2561
- addToHistory(command, success) {
2562
- this.history.unshift({
2563
- command,
2564
- timestamp: /* @__PURE__ */ new Date(),
2565
- success
2566
- });
2567
- if (this.history.length > this.maxHistorySize) {
2568
- this.history = this.history.slice(0, this.maxHistorySize);
2569
- }
2570
- }
2571
- /**
2572
- * Get command suggestions for partial matches
2573
- */
2574
- getSuggestions(partial) {
2575
- const commandNames = Array.from(this.commands.keys());
2576
- return commandNames.filter((name) => name.startsWith(partial));
2577
- }
2578
- }
2579
- class ConfigCommand {
2580
- name = "config";
2581
- description = "Show or update logger configuration";
2582
- usage = "/config [json|key=value,...]";
2583
- execute(args, logger) {
2584
- if (!args) {
2585
- this.showStatus(logger);
2586
- return;
2587
- }
2588
- try {
2589
- if (args.startsWith("{")) {
2590
- const config = JSON.parse(args);
2591
- this.applyConfig(config, logger);
2592
- } else {
2593
- const pairs = args.split(",").map((pair) => pair.trim().split("="));
2594
- const config = {};
2595
- pairs.forEach(([key, value]) => {
2596
- if (key && value) {
2597
- config[key.trim()] = value.trim().replace(/["']/g, "");
2598
- }
2599
- });
2600
- this.applyConfig(config, logger);
2601
- }
2602
- } catch (error) {
2603
- logger.error("Invalid config format. Use JSON or key=value pairs:", error);
2604
- logger.info('Examples: /config {"theme":"dark"} or /config theme=neon,verbosity=debug');
2605
- }
2606
- }
2607
- showStatus(logger) {
2608
- const statusData = {
2609
- theme: logger.getConfig().theme || "default",
2610
- verbosity: logger.getConfig().verbosity,
2611
- colors: logger.getConfig().enableColors,
2612
- timestamps: logger.getConfig().enableTimestamps,
2613
- stackTrace: logger.getConfig().enableStackTrace,
2614
- globalPrefix: logger.getConfig().globalPrefix || "none",
2615
- bannerType: logger.getConfig().bannerType || "simple",
2616
- handlers: logger.getHandlers().length
2617
- };
2618
- logger.group("⚙️ Logger Configuration");
2619
- logger.table(statusData);
2620
- logger.groupEnd();
2621
- }
2622
- applyConfig(config, logger) {
2623
- const validKeys = ["theme", "verbosity", "enableColors", "enableTimestamps", "enableStackTrace", "globalPrefix", "bannerType"];
2624
- const applied = [];
2625
- Object.entries(config).forEach(([key, value]) => {
2626
- if (validKeys.includes(key)) {
2627
- if (key === "theme" && typeof value === "string") {
2628
- logger.setTheme(value);
2629
- applied.push(`${key}=${value}`);
2630
- } else if (key === "bannerType" && typeof value === "string") {
2631
- logger.setBannerType(value);
2632
- applied.push(`${key}=${value}`);
2633
- } else if (key === "verbosity") {
2634
- logger.setVerbosity(value);
2635
- applied.push(`${key}=${value}`);
2636
- } else if (key === "globalPrefix") {
2637
- logger.setGlobalPrefix(value);
2638
- applied.push(`${key}=${value}`);
2639
- } else {
2640
- logger.updateConfig({ [key]: value });
2641
- applied.push(`${key}=${value}`);
2642
- }
2643
- } else {
2644
- logger.warn(`Invalid config key: ${key}`);
2645
- }
2646
- });
2647
- if (applied.length > 0) {
2648
- logger.success(`Configuration updated: ${applied.join(", ")}`);
2649
- }
2650
- }
2651
- }
2652
- class ThemesCommand {
2653
- name = "themes";
2654
- description = "Show available theme presets";
2655
- usage = "/themes";
2656
- execute(_args, logger) {
2657
- logger.group("🎨 Available Themes");
2658
- Object.keys(THEME_PRESETS).forEach((themeName) => {
2659
- const preview = THEME_PRESETS[themeName];
2660
- const previewStyle = new StyleBuilder().bg(preview.info.background).color(preview.info.color).padding("4px 8px").rounded("4px").border(preview.info.border).build();
2661
- console.log(`%c${themeName}`, previewStyle, `- ${themeName} theme preview`);
2662
- });
2663
- logger.groupEnd();
2664
- }
2665
- }
2666
- class BannersCommand {
2667
- name = "banners";
2668
- description = "Show available banner types";
2669
- usage = "/banners";
2670
- execute(_args, logger) {
2671
- logger.group("🖼️ Available Banner Types");
2672
- Object.keys(BANNER_VARIANTS).forEach((bannerName) => {
2673
- const banner = BANNER_VARIANTS[bannerName];
2674
- console.log(`%c${bannerName}`, "font-weight: bold; color: #667eea;");
2675
- console.log(`%cPreview:`, "color: #666; font-size: 12px;");
2676
- if (bannerName === "simple") {
2677
- console.log(`%c${banner.text}`, banner.style);
2678
- } else if (bannerName === "ascii") {
2679
- console.log(`%c${banner.text.split("\n").slice(1, 4).join("\n")}...`, "font-family: monospace; color: #667eea; font-size: 10px;");
2680
- } else if (bannerName === "unicode") {
2681
- console.log(`%c${banner.text}`, banner.style);
2682
- } else {
2683
- console.log(`%c${bannerName} banner`, "color: #666; font-style: italic;");
2684
- }
2685
- });
2686
- logger.groupEnd();
2687
- }
2688
- }
2689
- class BannerCommand {
2690
- name = "banner";
2691
- description = "Change or show current banner type";
2692
- usage = "/banner [type]";
2693
- execute(args, logger) {
2694
- if (!args) {
2695
- logger.showBanner();
2696
- return;
2697
- }
2698
- if (args in BANNER_VARIANTS) {
2699
- logger.setBannerType(args);
2700
- logger.showBanner();
2701
- } else {
2702
- logger.error(`Invalid banner type: ${args}. Available: ${Object.keys(BANNER_VARIANTS).join(", ")}`);
2703
- }
2704
- }
2705
- }
2706
- class StatusCommand {
2707
- name = "status";
2708
- description = "Show current logger status and configuration";
2709
- usage = "/status";
2710
- execute(_args, logger) {
2711
- const config = logger.getConfig();
2712
- const statusData = {
2713
- theme: config.theme ? config.theme : "default",
2714
- verbosity: config.verbosity,
2715
- colors: config.enableColors,
2716
- timestamps: config.enableTimestamps,
2717
- stackTrace: config.enableStackTrace,
2718
- globalPrefix: config.globalPrefix ? config.globalPrefix : "none",
2719
- bannerType: config.bannerType ? config.bannerType : "simple",
2720
- handlers: logger.getHandlers().length,
2721
- bufferSize: config.bufferSize ? config.bufferSize : 1e3
2722
- };
2723
- logger.group("⚙️ Logger Configuration");
2724
- logger.table(statusData);
2725
- logger.groupEnd();
2726
- const exportHandler = logger.getExportHandler();
2727
- if (exportHandler) {
2728
- const bufferStats = exportHandler.getBufferStats();
2729
- logger.group("📊 Buffer Statistics");
2730
- logger.table({
2731
- size: `${bufferStats.size}/${bufferStats.maxSize}`,
2732
- usage: `${bufferStats.usage.toFixed(1)}%`,
2733
- oldestLog: bufferStats.oldestLog ? bufferStats.oldestLog.toISOString() : "None",
2734
- newestLog: bufferStats.newestLog ? bufferStats.newestLog.toISOString() : "None",
2735
- errorCount: bufferStats.levelCounts.error + bufferStats.levelCounts.critical,
2736
- warningCount: bufferStats.levelCounts.warn
2737
- });
2738
- logger.groupEnd();
2739
- }
2740
- }
2741
- }
2742
- class ResetCommand {
2743
- name = "reset";
2744
- description = "Reset logger configuration to defaults";
2745
- usage = "/reset";
2746
- execute(_args, logger) {
2747
- logger.resetConfig();
2748
- }
2749
- }
2750
- class DemoCommand {
2751
- name = "demo";
2752
- description = "Show comprehensive feature demonstration";
2753
- usage = "/demo";
2754
- execute(_args, logger) {
2755
- logger.group("🎪 Advanced Logger Demo");
2756
- logger.debug("Debug message with detailed information");
2757
- logger.info("Informational message about system state");
2758
- logger.warn("Warning about deprecated feature");
2759
- logger.error("Error processing user request");
2760
- logger.success("Operation completed successfully");
2761
- logger.critical("Critical system failure detected");
2762
- logger.group("📊 Advanced Features Demo");
2763
- logger.table([
2764
- { feature: "Styled Console", status: "✅ Active", performance: "Excellent" },
2765
- { feature: "Theme System", status: "✅ Active", performance: "Great" },
2766
- { feature: "CLI Interface", status: "✅ Active", performance: "Good" },
2767
- { feature: "Export System", status: "✅ Active", performance: "Excellent" }
2768
- ]);
2769
- logger.time("demo-operation");
2770
- setTimeout(() => {
2771
- logger.timeEnd("demo-operation");
2772
- }, 100);
2773
- logger.logWithSVG("SVG Demo");
2774
- logger.logAnimated("🌟 Animated Logger Demo 🌟", 2);
2775
- logger.groupEnd();
2776
- logger.groupEnd();
2777
- logger.info("Demo completed! Check the console for styled output.");
2778
- }
2779
- }
2780
- function parseArguments(args) {
2781
- const filters = {};
2782
- const options = {};
2783
- let format;
2784
- if (!args.trim()) return { filters, options };
2785
- const argParts = args.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
2786
- for (let i = 0; i < argParts.length; i++) {
2787
- const arg = argParts[i];
2788
- if (!arg) {
2789
- continue;
2790
- }
2791
- if (i === 0 && !arg.startsWith("--") && arg in EXPORT_FORMATS) {
2792
- format = arg;
2793
- continue;
2794
- }
2795
- if (arg.startsWith("--")) {
2796
- const [flag, value] = arg.slice(2).split("=");
2797
- switch (flag) {
2798
- case "level":
2799
- case "levels":
2800
- if (value) {
2801
- filters.levels = value.split(",").map((l) => l.trim());
2802
- }
2803
- break;
2804
- case "since":
2805
- if (value) filters.since = value;
2806
- break;
2807
- case "until":
2808
- if (value) filters.until = value;
2809
- break;
2810
- case "prefix":
2811
- case "prefixes":
2812
- if (value) {
2813
- filters.prefixes = value.split(",").map((p) => p.trim());
2814
- }
2815
- break;
2816
- case "exclude-prefix":
2817
- case "exclude-prefixes":
2818
- if (value) {
2819
- filters.excludePrefixes = value.split(",").map((p) => p.trim());
2820
- }
2821
- break;
2822
- case "last":
2823
- if (value) filters.last = parseInt(value, 10);
2824
- break;
2825
- case "first":
2826
- if (value) filters.first = parseInt(value, 10);
2827
- break;
2828
- case "search":
2829
- if (value) filters.search = value.replace(/['"]/g, "");
2830
- break;
2831
- case "with-stack":
2832
- filters.withStackTrace = true;
2833
- break;
2834
- case "errors-only":
2835
- filters.errorsOnly = true;
2836
- break;
2837
- case "group-by":
2838
- if (value) {
2839
- filters.groupBy = value;
2840
- options.groupBy = value;
2841
- }
2842
- break;
2843
- case "minimal":
2844
- options.minimal = true;
2845
- break;
2846
- case "compact":
2847
- options.compact = true;
2848
- break;
2849
- case "styled":
2850
- options.styled = true;
2851
- break;
2852
- }
2853
- }
2854
- }
2855
- return { filters, options, format };
2856
- }
2857
- class ExportCommand {
2858
- name = "export";
2859
- description = "Export logs to various formats";
2860
- usage = "/export <format> [--filter=value] [--option]";
2861
- execute(args, logger) {
2862
- const exportHandler = logger.getExportHandler();
2863
- if (!exportHandler) {
2864
- logger.error("Export handler not available. Make sure ExportLogHandler is registered.");
2865
- return;
2866
- }
2867
- const { filters, options, format } = parseArguments(args);
2868
- if (!format) {
2869
- logger.error("Format required. Available formats: " + Object.keys(EXPORT_FORMATS).join(", "));
2870
- logger.info("Usage: /export <format> [--filter=value]");
2871
- logger.info("Example: /export json --level=error,warn --last=50");
2872
- return;
2873
- }
2874
- try {
2875
- const result = exportHandler.export(format, filters, options);
2876
- logger.success(`✅ Export completed: ${result.metadata.filteredLogs} logs exported in ${format} format`);
2877
- if (result.data.length < 1e3) {
2878
- logger.group(`📄 Preview (${format.toUpperCase()})`);
2879
- console.log(result.data);
2880
- logger.groupEnd();
2881
- } else {
2882
- logger.info(`📄 Export size: ${(result.data.length / 1024).toFixed(2)}KB`);
2883
- }
2884
- logger.table({
2885
- format: result.format,
2886
- totalLogs: result.metadata.totalLogs,
2887
- filtered: result.metadata.filteredLogs,
2888
- exported: result.metadata.exportedAt
2889
- });
2890
- } catch (error) {
2891
- logger.error("Export failed:", error);
2892
- }
2893
- }
2894
- }
2895
- class CopyCommand {
2896
- name = "copy";
2897
- description = "Copy logs to clipboard";
2898
- usage = "/copy <format> [--filter=value] [--option]";
2899
- async execute(args, logger) {
2900
- const exportHandler = logger.getExportHandler();
2901
- if (!exportHandler) {
2902
- logger.error("Export handler not available. Make sure ExportLogHandler is registered.");
2903
- return;
2904
- }
2905
- const { filters, options, format } = parseArguments(args);
2906
- if (!format) {
2907
- logger.error("Format required. Available formats: " + Object.keys(EXPORT_FORMATS).join(", "));
2908
- logger.info("Usage: /copy <format> [--filter=value]");
2909
- logger.info("Example: /copy plain --level=error --last=25");
2910
- return;
2911
- }
2912
- try {
2913
- const success = await exportHandler.copyToClipboard(format, filters, options);
2914
- if (success) {
2915
- const result = exportHandler.export(format, filters, options);
2916
- logger.success(`📋 Copied ${result.metadata.filteredLogs} logs to clipboard (${format} format)`);
2917
- } else {
2918
- logger.error("Failed to copy to clipboard. Browser may not support clipboard API.");
2919
- }
2920
- } catch (error) {
2921
- logger.error("Copy failed:", error);
2922
- }
2923
- }
2924
- }
2925
- class BufferSizeCommand {
2926
- name = "buffer-size";
2927
- description = "Set log buffer size";
2928
- usage = "/buffer-size <size>";
2929
- execute(args, logger) {
2930
- const exportHandler = logger.getExportHandler();
2931
- if (!exportHandler) {
2932
- logger.error("Export handler not available.");
2933
- return;
2934
- }
2935
- const size = parseInt(args.trim(), 10);
2936
- if (isNaN(size) || size <= 0) {
2937
- logger.error("Invalid buffer size. Must be a positive number.");
2938
- logger.info("Example: /buffer-size 2000");
2939
- return;
2940
- }
2941
- exportHandler.setBufferSize(size);
2942
- logger.success(`Buffer size set to ${size}`);
2943
- }
2944
- }
2945
- class ClearBufferCommand {
2946
- name = "clear-buffer";
2947
- description = "Clear the log buffer";
2948
- usage = "/clear-buffer";
2949
- execute(_args, logger) {
2950
- const exportHandler = logger.getExportHandler();
2951
- if (!exportHandler) {
2952
- logger.error("Export handler not available.");
2953
- return;
2954
- }
2955
- const stats = exportHandler.getBufferStats();
2956
- exportHandler.clearBuffer();
2957
- logger.success(`✅ Buffer cleared. Removed ${stats.size} log entries.`);
2958
- }
2959
- }
2960
- class BufferInfoCommand {
2961
- name = "buffer-info";
2962
- description = "Show buffer statistics and information";
2963
- usage = "/buffer-info";
2964
- execute(_args, logger) {
2965
- const exportHandler = logger.getExportHandler();
2966
- if (!exportHandler) {
2967
- logger.error("Export handler not available.");
2968
- return;
2969
- }
2970
- const stats = exportHandler.getBufferStats();
2971
- logger.group("📊 Buffer Information");
2972
- logger.table({
2973
- size: `${stats.size}/${stats.maxSize}`,
2974
- usage: `${stats.usage.toFixed(1)}%`,
2975
- oldestLog: stats.oldestLog?.toLocaleString() || "None",
2976
- newestLog: stats.newestLog?.toLocaleString() || "None"
2977
- });
2978
- logger.group("📈 Log Level Counts");
2979
- logger.table(stats.levelCounts);
2980
- logger.groupEnd();
2981
- logger.groupEnd();
2982
- }
2983
- }
2984
- class HelpCommand {
2985
- name = "help";
2986
- description = "Show CLI help and available commands";
2987
- usage = "/help [command]";
2988
- execute(_args, logger) {
2989
- const helpStyle = new StyleBuilder().bg("linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%)").color("#495057").padding("15px 20px").rounded("8px").border("1px solid #dee2e6").font("Monaco, Consolas, monospace").size("13px").build();
2990
- const helpText = `
2991
- ╭─────────────── ADVANCED LOGGER CLI COMMANDS ─────────────────╮
2992
- │ │
2993
- │ CONFIGURATION │
2994
- │ /config Show current configuration │
2995
- │ /config {json} Apply JSON configuration │
2996
- │ /config key=val Apply key-value configuration │
2997
- │ /themes Show available themes │
2998
- │ /banners Show available banner types │
2999
- │ /banner [type] Change/show banner type │
3000
- │ /status Show logger status & buffer stats │
3001
- │ /demo Show feature demonstration │
3002
- │ /reset Reset to default configuration │
3003
- │ │
3004
- │ EXPORT & CLIPBOARD │
3005
- │ /export <format> Export logs (json|csv|md|plain|html) │
3006
- │ /copy <format> Copy logs to clipboard │
3007
- │ /buffer-size N Set log buffer size │
3008
- │ /buffer-info Show buffer statistics │
3009
- │ /clear-buffer Clear stored logs │
3010
- │ │
3011
- │ EXPORT FILTERS (for export/copy commands) │
3012
- │ --level error,warn Filter by log levels │
3013
- │ --since 2h Logs from last 2 hours │
3014
- │ --until 1h Logs until 1 hour ago │
3015
- │ --prefix API,DB Filter by prefixes │
3016
- │ --exclude-prefix INT Exclude prefixes │
3017
- │ --last 50 Last 50 logs only │
3018
- │ --first 25 First 25 logs only │
3019
- │ --search "error" Search in log messages │
3020
- │ --with-stack Only logs with stack traces │
3021
- │ --errors-only Only error + critical logs │
3022
- │ --group-by level Group by level/prefix/hour │
3023
- │ │
3024
- │ EXPORT OPTIONS │
3025
- │ --minimal Minimal output format │
3026
- │ --compact Remove extra whitespace │
3027
- │ --styled Include styling (HTML format) │
3028
- │ │
3029
- ├──────────────────── CONFIGURATION OPTIONS ─────────────────┤
3030
- │ │
3031
- │ theme: default | dark | light | neon | minimal | cyberpunk│
3032
- │ bannerType: simple | ascii | unicode | svg | animated │
3033
- │ verbosity: debug | info | warn | error | critical | silent│
3034
- │ enableColors: true | false │
3035
- │ enableTimestamps: true | false │
3036
- │ enableStackTrace: true | false │
3037
- │ globalPrefix: "string" │
3038
- │ bufferSize: number (50-10000) │
3039
- │ │
3040
- ├──────────────────────── EXAMPLES ──────────────────────────┤
3041
- │ │
3042
- │ Basic Configuration: │
3043
- │ /config {"theme":"dark","verbosity":"debug"} │
3044
- │ /config theme=neon,bufferSize=2000 │
3045
- │ /banner animated Change to animated banner │
3046
- │ │
3047
- │ Export Examples: │
3048
- │ /export json --level=error,warn --last=25 │
3049
- │ /export csv --since=2h --prefix=API │
3050
- │ /export markdown --group-by=level --errors-only │
3051
- │ /export html --styled --since=1h │
3052
- │ │
3053
- │ Clipboard Examples: │
3054
- │ /copy plain --minimal --last=10 │
3055
- │ /copy json --search="authentication" --compact │
3056
- │ /copy csv --since=30m --exclude-prefix=DEBUG │
3057
- │ │
3058
- │ Buffer Management: │
3059
- │ /buffer-size 5000 Increase buffer to 5000 logs │
3060
- │ /buffer-info Show detailed buffer statistics │
3061
- │ /clear-buffer Clear all stored logs │
3062
- │ │
3063
- │ Time Formats: │
3064
- │ --since=2h 2 hours ago │
3065
- │ --since=30m 30 minutes ago │
3066
- │ --since=1d 1 day ago │
3067
- │ --since="2024-01-01T10:00:00Z" Specific ISO date │
3068
- │ │
3069
- ╰─────────────────────────────────────────────────────────────╯`;
3070
- console.log(`%c${helpText}`, helpStyle);
3071
- logger.group("💡 Quick Tips");
3072
- const tips = [
3073
- "Use /demo to see all logger features in action",
3074
- "Logs are automatically stored in a circular buffer for export",
3075
- "Export formats: JSON (structured), CSV (Excel), Markdown (readable), Plain (simple), HTML (styled)",
3076
- "Time filters support relative (2h, 30m) and absolute (ISO) formats",
3077
- 'Combine multiple filters: /export json --level=error --since=1h --search="auth"',
3078
- "Use /copy for quick clipboard access instead of /export"
3079
- ];
3080
- tips.forEach((tip) => {
3081
- logger.info(`• ${tip}`);
3082
- });
3083
- logger.groupEnd();
3084
- }
3085
- }
3086
- class HistoryCommand {
3087
- name = "history";
3088
- description = "Show command execution history";
3089
- usage = "/history [limit] - Show recent commands (default: 10)";
3090
- category = "system";
3091
- aliases = ["hist", "h"];
3092
- execute(args, logger) {
3093
- const processor = logger.cliProcessor;
3094
- if (!processor) {
3095
- logger.error("CLI processor not available");
3096
- return;
3097
- }
3098
- const limit = parseInt(args) || 10;
3099
- const history = processor.getHistory().slice(0, limit);
3100
- if (history.length === 0) {
3101
- logger.info("📝 No command history available");
3102
- return;
3103
- }
3104
- logger.info(`📋 Last ${history.length} commands:`);
3105
- history.forEach((entry, index) => {
3106
- const status = entry.success ? "✅" : "❌";
3107
- const time = entry.timestamp.toLocaleTimeString();
3108
- logger.info(`${status} [${time}] ${entry.command}`);
3109
- });
3110
- }
3111
- }
3112
- class ClearHistoryCommand {
3113
- name = "clearhistory";
3114
- description = "Clear command execution history";
3115
- usage = "/clearhistory - Remove all command history";
3116
- category = "system";
3117
- aliases = ["clrhist"];
3118
- execute(args, logger) {
3119
- const processor = logger.cliProcessor;
3120
- if (!processor) {
3121
- logger.error("CLI processor not available");
3122
- return;
3123
- }
3124
- processor.clearHistory();
3125
- logger.success("🗑️ Command history cleared");
3126
- }
3127
- }
3128
- class InteractiveCommand {
3129
- name = "interactive";
3130
- description = "Enter interactive CLI mode";
3131
- usage = "/interactive - Start interactive command mode";
3132
- category = "system";
3133
- aliases = ["i", "repl"];
3134
- execute(args, logger) {
3135
- const processor = logger.cliProcessor;
3136
- if (!processor) {
3137
- logger.error("CLI processor not available");
3138
- return;
3139
- }
3140
- processor.enterInteractiveMode(logger);
3141
- }
3142
- }
3143
- class PluginsCommand {
3144
- name = "plugins";
3145
- description = "List loaded CLI plugins";
3146
- usage = "/plugins - Show all registered plugins";
3147
- category = "system";
3148
- aliases = ["plug"];
3149
- execute(args, logger) {
3150
- const processor = logger.cliProcessor;
3151
- if (!processor) {
3152
- logger.error("CLI processor not available");
3153
- return;
3154
- }
3155
- const plugins = processor.getPlugins();
3156
- if (plugins.length === 0) {
3157
- logger.info("🔌 No plugins registered");
3158
- return;
3159
- }
3160
- logger.info(`🔌 Loaded plugins (${plugins.length}):`);
3161
- plugins.forEach((plugin) => {
3162
- logger.info(` 📦 ${plugin.name} v${plugin.version} - ${plugin.description}`);
3163
- logger.info(` Commands: ${plugin.commands.map((c) => c.name).join(", ")}`);
3164
- });
3165
- }
3166
- }
3167
- function createDefaultCLI() {
3168
- const processor = new CommandProcessor();
3169
- processor.registerCommand(new HelpCommand());
3170
- processor.registerCommand(new ConfigCommand());
3171
- processor.registerCommand(new ThemesCommand());
3172
- processor.registerCommand(new BannersCommand());
3173
- processor.registerCommand(new BannerCommand());
3174
- processor.registerCommand(new StatusCommand());
3175
- processor.registerCommand(new ResetCommand());
3176
- processor.registerCommand(new DemoCommand());
3177
- processor.registerCommand(new ExportCommand());
3178
- processor.registerCommand(new CopyCommand());
3179
- processor.registerCommand(new BufferSizeCommand());
3180
- processor.registerCommand(new ClearBufferCommand());
3181
- processor.registerCommand(new BufferInfoCommand());
3182
- processor.registerCommand(new HistoryCommand());
3183
- processor.registerCommand(new ClearHistoryCommand());
3184
- processor.registerCommand(new InteractiveCommand());
3185
- processor.registerCommand(new PluginsCommand());
3186
- return processor;
3187
- }
3188
- let LEVEL_STYLES = THEME_PRESETS.default;
3189
- class Logger {
3190
- config;
3191
- scopedPrefix;
3192
- handlers = [];
3193
- timers = /* @__PURE__ */ new Map();
3194
- groupDepth = 0;
3195
- exportHandler;
3196
- cliProcessor;
3197
- themeChangeListener;
3198
- badgeList = [];
3199
- displaySettings = {
3200
- showTimestamp: true,
3201
- showLocation: true,
3202
- showBadges: true
3203
- };
3204
- serializerRegistry;
3205
- hookManager;
3206
- transportManager;
3207
- /**
3208
- * Crea una nueva instancia del Logger
3209
- *
3210
- * @param {Partial<LoggerConfig>} config - Configuración opcional del logger
3211
- *
3212
- * @example
3213
- * // Logger con configuración personalizada
3214
- * const logger = new Logger({
3215
- * theme: 'neon',
3216
- * globalPrefix: 'MiApp',
3217
- * verbosity: 'debug',
3218
- * bufferSize: 1000
3219
- * });
3220
- */
3221
- constructor(config = {}) {
3222
- this.config = {
3223
- ...DEFAULT_CONFIG$1,
3224
- ...config
3225
- };
3226
- this.serializerRegistry = new SerializerRegistry();
3227
- this.hookManager = new HookManager();
3228
- if (this.config.bufferSize) {
3229
- this.exportHandler = new ExportLogHandler(this.config.bufferSize);
3230
- this.handlers.push(this.exportHandler);
3231
- }
3232
- this.cliProcessor = createDefaultCLI();
3233
- if (this.config.autoDetectTheme) {
3234
- this.setupAutoThemeDetection();
3235
- }
3236
- }
3237
- // ===== PRIVATE HELPER METHODS =====
3238
- /**
3239
- * Configura la detección automática de tema con listener de cambios
3240
- * @private
3241
- * @description Detecta automáticamente si el navegador está en modo claro u oscuro
3242
- */
3243
- setupAutoThemeDetection() {
3244
- if (this.themeChangeListener) {
3245
- this.themeChangeListener();
3246
- this.themeChangeListener = null;
3247
- }
3248
- this.themeChangeListener = setupThemeChangeListener((theme) => {
3249
- this.debug(`DevTools theme changed to: ${theme}`);
3250
- });
3251
- }
3252
- // ===== CONFIGURATION METHODS =====
3253
- /**
3254
- * Obtiene la configuración actual del logger
3255
- *
3256
- * @returns {LoggerConfig} Configuración completa actual
3257
- *
3258
- * @example
3259
- * const config = logger.getConfig();
3260
- * console.log('Verbosidad actual:', config.verbosity);
3261
- * console.log('Tema actual:', config.theme);
3262
- *
3263
- * @since 0.3.0
3264
- */
3265
- getConfig() {
3266
- return { ...this.config };
3267
- }
3268
- /**
3269
- * Actualiza la configuración del logger
3270
- *
3271
- * @param {Partial<LoggerConfig>} updates - Propiedades a actualizar
3272
- *
3273
- * @example
3274
- * logger.updateConfig({
3275
- * verbosity: 'debug',
3276
- * enableTimestamps: false,
3277
- * theme: 'cyberpunk'
3278
- * });
3279
- *
3280
- * @since 0.3.0
3281
- */
3282
- updateConfig(updates) {
3283
- const previousAutoDetect = this.config.autoDetectTheme;
3284
- this.config = { ...this.config, ...updates };
3285
- if (updates.autoDetectTheme !== void 0 && updates.autoDetectTheme !== previousAutoDetect) {
3286
- if (updates.autoDetectTheme) {
3287
- this.setupAutoThemeDetection();
3288
- } else if (this.themeChangeListener) {
3289
- this.themeChangeListener();
3290
- this.themeChangeListener = null;
3291
- }
3292
- }
3293
- }
3294
- /**
3295
- * Establece el prefijo global para todos los mensajes de log
3296
- *
3297
- * @param {string} prefix - Prefijo a usar
3298
- *
3299
- * @example
3300
- * logger.setGlobalPrefix('MiApp');
3301
- * logger.info('Iniciado'); // [MiApp] Iniciado
3302
- *
3303
- * @since 0.3.0
3304
- */
3305
- setGlobalPrefix(prefix) {
3306
- this.config.globalPrefix = prefix;
3307
- }
3308
- /**
3309
- * Establece el nivel de verbosidad para filtrar la salida de logs
3310
- *
3311
- * @param {Verbosity} level - Nivel mínimo a mostrar ('debug' | 'info' | 'warn' | 'error' | 'critical' | 'silent')
3312
- *
3313
- * @example
3314
- * logger.setVerbosity('warn'); // Solo muestra warn, error y critical
3315
- * logger.setVerbosity('debug'); // Muestra todos los niveles
3316
- * logger.setVerbosity('silent'); // No muestra nada
3317
- *
3318
- * @since 0.3.0
3319
- */
3320
- setVerbosity(level) {
3321
- this.config.verbosity = level;
3322
- }
3323
- /**
3324
- * Establece el tema del logger
3325
- *
3326
- * @param {ThemeVariant} theme - Tema a aplicar ('default' | 'dark' | 'light' | 'neon' | 'minimal' | 'cyberpunk')
3327
- *
3328
- * @example
3329
- * logger.setTheme('neon'); // Tema con colores neón
3330
- * logger.setTheme('minimal'); // Tema minimalista
3331
- * logger.setTheme('cyberpunk'); // Tema cyberpunk con efectos
3332
- *
3333
- * @since 0.3.0
3334
- */
3335
- setTheme(theme) {
3336
- if (hasPreset(theme)) {
3337
- this.preset(theme);
3338
- return;
3339
- }
3340
- if (theme in THEME_PRESETS) {
3341
- LEVEL_STYLES = THEME_PRESETS[theme];
3342
- this.config.theme = theme;
3343
- if (theme in THEME_BANNERS) {
3344
- const themeBanner = THEME_BANNERS[theme];
3345
- console.log(`%c${themeBanner.simple}`, themeBanner.style);
3346
- }
3347
- this.success(`Theme changed to: ${theme}`);
3348
- } else {
3349
- this.error(`Invalid theme: ${theme}. Available:`, [...getAvailablePresets(), ...Object.keys(THEME_PRESETS)]);
3350
- }
3351
- }
3352
- /**
3353
- * Establece el tipo de banner para mostrar en la inicialización
3354
- *
3355
- * @param {BannerType} bannerType - Tipo de banner ('simple' | 'ascii' | 'unicode' | 'svg' | 'animated')
3356
- *
3357
- * @example
3358
- * logger.setBannerType('ascii'); // Banner con arte ASCII
3359
- * logger.setBannerType('unicode'); // Banner con caracteres Unicode
3360
- * logger.setBannerType('animated'); // Banner con animación
3361
- *
3362
- * @since 0.3.0
3363
- */
3364
- setBannerType(bannerType) {
3365
- this.config.bannerType = bannerType;
3366
- this.success(`Banner type changed to: ${bannerType}`);
3367
- }
3368
- /**
3369
- * Reinicia el logger a la configuración por defecto
3370
- *
3371
- * @example
3372
- * logger.resetConfig();
3373
- * // Todo vuelve a la configuración inicial
3374
- *
3375
- * @since 0.3.0
3376
- */
3377
- resetConfig() {
3378
- if (this.themeChangeListener) {
3379
- this.themeChangeListener();
3380
- this.themeChangeListener = null;
3381
- }
3382
- this.config = { ...DEFAULT_CONFIG$1 };
3383
- LEVEL_STYLES = THEME_PRESETS.default;
3384
- if (this.config.autoDetectTheme) {
3385
- this.setupAutoThemeDetection();
3386
- }
3387
- this.success("Logger configuration reset to defaults");
3388
- }
3389
- /**
3390
- * Método de limpieza para eliminar listeners y liberar recursos
3391
- *
3392
- * @example
3393
- * // Antes de cerrar la aplicación
3394
- * logger.cleanup();
3395
- *
3396
- * @since 0.3.0
3397
- */
3398
- cleanup() {
3399
- if (this.themeChangeListener) {
3400
- this.themeChangeListener();
3401
- this.themeChangeListener = null;
3402
- }
3403
- this.transportManager?.close().catch(() => {
3404
- });
3405
- }
3406
- // ===== SIMPLIFIED API =====
3407
- /**
3408
- * Aplica un preset inteligente - funciona perfectamente sin configuración
3409
- *
3410
- * @param {string} name - Nombre del preset a aplicar
3411
- *
3412
- * @example
3413
- * // Presets disponibles
3414
- * logger.preset('default'); // Limpio y adaptativo
3415
- * logger.preset('cyberpunk'); // Colores neón, efectos brillantes
3416
- * logger.preset('glassmorphism'); // Efectos de blur modernos
3417
- * logger.preset('minimal'); // Minimalista y elegante
3418
- * logger.preset('debug'); // Modo desarrollo detallado
3419
- * logger.preset('production'); // Optimizado para producción
3420
- *
3421
- * @since 0.3.0
3422
- */
3423
- preset(name) {
3424
- if (!hasPreset(name)) {
3425
- this.error(`Unknown preset: ${name}. Available presets:`, getAvailablePresets());
3426
- return;
3427
- }
3428
- const presetConfig = getSmartPreset(name);
3429
- if (presetConfig) {
3430
- this.displaySettings.showTimestamp = presetConfig.timestamp?.show ?? true;
3431
- this.displaySettings.showLocation = presetConfig.location?.show ?? true;
3432
- this._activePreset = presetConfig;
3433
- this._activePresetName = name;
3434
- if (getEnvironment() === "browser") {
3435
- this.success(`Applied preset: ${name}`);
3436
- }
3437
- }
3438
- }
3439
- /**
3440
- * Lista todos los presets disponibles
3441
- *
3442
- * @returns {string[]} Array con nombres de presets disponibles
3443
- *
3444
- * @example
3445
- * const disponibles = logger.presets();
3446
- * console.log(disponibles); // ['default', 'cyberpunk', 'glassmorphism', ...]
3447
- *
3448
- * @since 0.3.0
3449
- */
3450
- presets() {
3451
- return getAvailablePresets();
3452
- }
3453
- // ===== TOGGLE METHODS =====
3454
- /**
3455
- * Oculta el timestamp en los logs
3456
- *
3457
- * @example
3458
- * logger.hideTimestamp();
3459
- * logger.info('Sin marca de tiempo'); // Sin timestamp visible
3460
- *
3461
- * @since 0.3.0
3462
- */
3463
- hideTimestamp() {
3464
- this.displaySettings.showTimestamp = false;
3465
- return this;
3466
- }
3467
- /**
3468
- * Muestra el timestamp en los logs
3469
- *
3470
- * @example
3471
- * logger.showTimestamp();
3472
- * logger.info('Con marca de tiempo'); // [2024-01-15 10:30:45] Con marca de tiempo
3473
- *
3474
- * @since 0.3.0
3475
- */
3476
- showTimestamp() {
3477
- this.displaySettings.showTimestamp = true;
3478
- return this;
3479
- }
3480
- /**
3481
- * Oculta la información de ubicación (archivo:línea) en los logs
3482
- *
3483
- * @example
3484
- * logger.hideLocation();
3485
- * logger.debug('Sin ubicación'); // Sin mostrar archivo:línea
3486
- *
3487
- * @since 0.3.0
3488
- */
3489
- hideLocation() {
3490
- this.displaySettings.showLocation = false;
3491
- return this;
3492
- }
3493
- /**
3494
- * Muestra la información de ubicación (archivo:línea) en los logs
3495
- *
3496
- * @example
3497
- * logger.showLocation();
3498
- * logger.debug('Con ubicación'); // app.js:42 Con ubicación
3499
- *
3500
- * @since 0.3.0
3501
- */
3502
- showLocation() {
3503
- this.displaySettings.showLocation = true;
3504
- return this;
3505
- }
3506
- /**
3507
- * Oculta los badges en los logs
3508
- *
3509
- * @example
3510
- * logger.hideBadges();
3511
- * const api = logger.api('REST');
3512
- * api.info('Sin badges'); // Sin mostrar [API] [REST]
3513
- *
3514
- * @since 0.3.0
3515
- */
3516
- hideBadges() {
3517
- this.displaySettings.showBadges = false;
3518
- return this;
3519
- }
3520
- /**
3521
- * Muestra los badges en los logs
3522
- *
3523
- * @example
3524
- * logger.showBadges();
3525
- * const api = logger.api('GraphQL');
3526
- * api.info('Con badges'); // [API] [GraphQL] Con badges
3527
- *
3528
- * @since 0.3.0
3529
- */
3530
- showBadges() {
3531
- this.displaySettings.showBadges = true;
3532
- return this;
3533
- }
3534
- /**
3535
- * Establece múltiples badges para los logs
3536
- *
3537
- * @param {string[]} badges - Array de badges a mostrar
3538
- * @returns {this} Logger instance para encadenamiento
3539
- *
3540
- * @example
3541
- * logger.badges(['v3', 'stable']).info('Release publicado');
3542
- * logger.badges(['API', 'v2']).warn('Endpoint deprecado');
3543
- *
3544
- * @since 3.0.0
3545
- */
3546
- badges(badges2) {
3547
- this.badgeList = [...badges2];
3548
- return this;
3549
- }
3550
- /**
3551
- * Añade un badge individual a la lista
3552
- *
3553
- * @param {string} badge - Badge a añadir
3554
- * @returns {this} Logger instance para encadenamiento
3555
- *
3556
- * @example
3557
- * logger.badge('DEBUG').badge('AUTH').info('Token validado');
3558
- *
3559
- * @since 3.0.0
3560
- */
3561
- badge(badge2) {
3562
- if (!this.badgeList.includes(badge2)) {
3563
- this.badgeList.push(badge2);
3564
- }
3565
- return this;
3566
- }
3567
- /**
3568
- * Limpia todos los badges activos
3569
- *
3570
- * @returns {this} Logger instance para encadenamiento
3571
- *
3572
- * @example
3573
- * logger.clearBadges().info('Sin badges');
3574
- *
3575
- * @since 3.0.0
3576
- */
3577
- clearBadges() {
3578
- this.badgeList = [];
3579
- return this;
3580
- }
3581
- // ===== SCOPED LOGGERS =====
3582
- component(name) {
3583
- return new ComponentLogger(this, name);
3584
- }
3585
- api(name) {
3586
- return new APILogger(this, name);
3587
- }
3588
- scope(name) {
3589
- return new ScopedLogger(this, name);
3590
- }
3591
- // ===== SIMPLE CUSTOMIZATION =====
3592
- /**
3593
- * Personalización simple con configuración mínima
3594
- *
3595
- * @param {Object} overrides - Opciones de personalización
3596
- * @param {Object} overrides.message - Configuración del mensaje
3597
- * @param {Object} overrides.timestamp - Configuración del timestamp
3598
- * @param {Object} overrides.location - Configuración de ubicación
3599
- * @param {Object} overrides.level - Configuración del nivel
3600
- * @param {Object} overrides.prefix - Configuración del prefijo
3601
- * @param {string} overrides.spacing - Espaciado: 'compact' | 'normal' | 'spacious'
3602
- *
3603
- * @example
3604
- * logger.customize({
3605
- * message: { color: '#00ff00', size: '16px' },
3606
- * timestamp: { show: false },
3607
- * spacing: 'compact'
3608
- * });
3609
- *
3610
- * @since 0.3.0
3611
- */
3612
- customize(overrides) {
3613
- if (overrides.timestamp?.show !== void 0) {
3614
- this.displaySettings.showTimestamp = overrides.timestamp.show;
3615
- }
3616
- if (overrides.location?.show !== void 0) {
3617
- this.displaySettings.showLocation = overrides.location.show;
3618
- }
3619
- if (overrides.prefix?.show !== void 0) ;
3620
- this._customization = overrides;
3621
- this.success("Customization applied");
3622
- }
3623
- /**
3624
- * Access advanced styling API (for power users)
3625
- */
3626
- styles() {
3627
- return createLogStyleBuilder(this);
3628
- }
3629
- // ===== HANDLER MANAGEMENT =====
3630
- /**
3631
- * Añade un handler personalizado para extender funcionalidad
3632
- *
3633
- * @param {ILogHandler} handler - Handler que implementa ILogHandler
3634
- *
3635
- * @example
3636
- * // Handler personalizado para enviar logs a servidor
3637
- * const remoteHandler = new RemoteLogHandler('https://api.ejemplo.com/logs');
3638
- * logger.addHandler(remoteHandler);
3639
- *
3640
- * @example
3641
- * // Handler para guardar en archivo
3642
- * const fileHandler = new FileLogHandler('./app.log');
3643
- * logger.addHandler(fileHandler);
3644
- *
3645
- * @since 0.3.0
3646
- */
3647
- addHandler(handler) {
3648
- this.handlers.push(handler);
3649
- }
3650
- /**
3651
- * Obtiene todos los handlers registrados
3652
- *
3653
- * @returns {ILogHandler[]} Array de handlers activos
3654
- * @since 0.3.0
3655
- */
3656
- getHandlers() {
3657
- return [...this.handlers];
3658
- }
3659
- /**
3660
- * Obtiene el handler de exportación si está disponible
3661
- *
3662
- * @returns {ExportLogHandler | undefined} Handler de exportación o undefined
3663
- * @since 0.3.0
3664
- */
3665
- getExportHandler() {
3666
- return this.exportHandler;
3667
- }
3668
- // ===== SERIALIZERS =====
3669
- /**
3670
- * Añade un serializador personalizado para un tipo específico
3671
- *
3672
- * @param type - Constructor del tipo a serializar
3673
- * @param serializer - Función de serialización
3674
- * @param priority - Prioridad (mayor = primero)
3675
- *
3676
- * @example
3677
- * logger.addSerializer(Error, (err) => ({
3678
- * name: err.name,
3679
- * message: err.message,
3680
- * stack: err.stack?.split('\n').slice(0, 5)
3681
- * }));
3682
- *
3683
- * @since 3.0.0
3684
- */
3685
- addSerializer(type, serializer, priority) {
3686
- this.serializerRegistry.add(type, serializer, priority);
3687
- }
3688
- /**
3689
- * Elimina un serializador registrado
3690
- *
3691
- * @param type - Constructor del tipo a remover
3692
- * @returns true si se eliminó
3693
- *
3694
- * @since 3.0.0
3695
- */
3696
- removeSerializer(type) {
3697
- return this.serializerRegistry.remove(type);
3698
- }
3699
- /**
3700
- * Obtiene el registry de serializadores
3701
- *
3702
- * @returns SerializerRegistry
3703
- * @since 3.0.0
3704
- */
3705
- getSerializerRegistry() {
3706
- return this.serializerRegistry;
3707
- }
3708
- // ===== HOOKS & MIDDLEWARE =====
3709
- /**
3710
- * Registra un hook para un evento
3711
- *
3712
- * @param event - Evento: 'beforeLog' | 'afterLog' | 'onError'
3713
- * @param callback - Función a ejecutar
3714
- * @param priority - Prioridad (mayor = primero)
3715
- * @returns Función para desregistrar
3716
- *
3717
- * @example
3718
- * const unsubscribe = logger.on('beforeLog', (entry) => {
3719
- * entry.correlationId = getCorrelationId();
3720
- * return entry;
3721
- * });
3722
- *
3723
- * @since 3.0.0
3724
- */
3725
- on(event, callback, priority) {
3726
- return this.hookManager.on(event, callback, priority);
3727
- }
3728
- /**
3729
- * Registra un hook que se ejecuta solo una vez
3730
- *
3731
- * @param event - Evento: 'beforeLog' | 'afterLog' | 'onError'
3732
- * @param callback - Función a ejecutar
3733
- * @param priority - Prioridad (mayor = primero)
3734
- * @returns Función para desregistrar
3735
- *
3736
- * @since 3.0.0
3737
- */
3738
- once(event, callback, priority) {
3739
- return this.hookManager.once(event, callback, priority);
3740
- }
3741
- /**
3742
- * Elimina un hook registrado
3743
- *
3744
- * @param event - Evento del hook
3745
- * @param callback - Callback a remover
3746
- * @returns true si se eliminó
3747
- *
3748
- * @since 3.0.0
3749
- */
3750
- off(event, callback) {
3751
- return this.hookManager.off(event, callback);
3752
- }
3753
- /**
3754
- * Añade un middleware al pipeline
3755
- *
3756
- * @param middleware - Función middleware
3757
- * @param priority - Prioridad (mayor = primero)
3758
- * @returns Función para desregistrar
3759
- *
3760
- * @example
3761
- * logger.use((entry, next) => {
3762
- * entry.requestId = asyncLocalStorage.getStore()?.requestId;
3763
- * next();
3764
- * });
3765
- *
3766
- * @since 3.0.0
3767
- */
3768
- use(middleware, priority) {
3769
- return this.hookManager.use(middleware, priority);
3770
- }
3771
- /**
3772
- * Obtiene el HookManager
3773
- *
3774
- * @returns HookManager
3775
- * @since 3.0.0
3776
- */
3777
- getHookManager() {
3778
- return this.hookManager;
3779
- }
3780
- // ===== TRANSPORTS =====
3781
- /**
3782
- * Añade un transport para envío de logs
3783
- *
3784
- * @param target - Configuración del transport
3785
- * @returns ID único del transport
3786
- *
3787
- * @example
3788
- * // File transport
3789
- * logger.addTransport({
3790
- * target: 'file',
3791
- * options: { destination: '/var/log/app.log' }
3792
- * });
3793
- *
3794
- * @example
3795
- * // HTTP transport con batching
3796
- * logger.addTransport({
3797
- * target: 'http',
3798
- * options: {
3799
- * url: 'https://logs.example.com',
3800
- * batchSize: 100,
3801
- * flushInterval: 5000
3802
- * },
3803
- * level: 'warn'
3804
- * });
3805
- *
3806
- * @since 3.0.0
3807
- */
3808
- addTransport(target) {
3809
- if (!this.transportManager) {
3810
- this.transportManager = new TransportManager();
3811
- }
3812
- return this.transportManager.add(target);
3813
- }
3814
- /**
3815
- * Elimina un transport
3816
- *
3817
- * @param id - ID del transport a remover
3818
- * @returns true si se eliminó
3819
- *
3820
- * @since 3.0.0
3821
- */
3822
- removeTransport(id) {
3823
- return this.transportManager?.remove(id) ?? false;
3824
- }
3825
- /**
3826
- * Fuerza el flush de todos los transports
3827
- *
3828
- * @returns Promise que resuelve cuando todos los buffers están vaciados
3829
- *
3830
- * @since 3.0.0
3831
- */
3832
- async flushTransports() {
3833
- await this.transportManager?.flush();
3834
- }
3835
- /**
3836
- * Cierra todos los transports
3837
- *
3838
- * @returns Promise que resuelve cuando todos están cerrados
3839
- *
3840
- * @since 3.0.0
3841
- */
3842
- async closeTransports() {
3843
- await this.transportManager?.close();
3844
- }
3845
- /**
3846
- * Obtiene el TransportManager
3847
- *
3848
- * @returns TransportManager o undefined si no hay transports
3849
- * @since 3.0.0
3850
- */
3851
- getTransportManager() {
3852
- return this.transportManager;
3853
- }
3854
- // ===== CORE LOGGING METHODS =====
3855
- /**
3856
- * Verifica si un nivel de log debe mostrarse según la verbosidad actual
3857
- * @private
3858
- * @param {LogLevel} level - Nivel de log a verificar
3859
- * @returns {boolean} True si debe mostrarse, false si no
3860
- */
3861
- shouldLog(level) {
3862
- if (this.config.verbosity === "silent") return false;
3863
- const levels = { debug: 0, info: 1, warn: 2, error: 3, critical: 4 };
3864
- return levels[level] >= levels[this.config.verbosity];
3865
- }
3866
- /**
3867
- * Obtiene el prefijo efectivo (global + scope)
3868
- * @private
3869
- * @returns {string | undefined} Prefijo combinado o undefined
3870
- */
3871
- getEffectivePrefix() {
3872
- const parts = [this.config.globalPrefix, this.scopedPrefix].filter(Boolean);
3873
- return parts.length > 0 ? parts.join(":") : void 0;
3874
- }
3875
- /**
3876
- * Método central de logging que maneja estilos y formato
3877
- * @protected
3878
- * @param {LogLevel} level - Nivel del log
3879
- * @param {...any} args - Argumentos a loggear
3880
- */
3881
- log(level, ...args) {
3882
- if (!this.shouldLog(level)) return;
3883
- const stackInfo = this.config.enableStackTrace ? parseStackTrace() : null;
3884
- const prefix = this.getEffectivePrefix();
3885
- const timestamp = formatTimestamp$1();
3886
- const serializedArgs = args.map((arg) => this.serializerRegistry.serialize(arg));
3887
- let message = serializedArgs.length > 0 ? String(serializedArgs[0]) : "";
3888
- if (this.badgeList.length > 0 && this.displaySettings.showBadges) {
3889
- const badgePrefix = this.badgeList.map((b) => `[${b}]`).join("");
3890
- message = badgePrefix + " " + message;
3891
- }
3892
- const additionalArgs = serializedArgs.slice(1);
3893
- let hookEntry = {
3894
- level,
3895
- message,
3896
- args: serializedArgs,
3897
- timestamp,
3898
- prefix,
3899
- stackInfo: stackInfo || void 0
3900
- };
3901
- this.hookManager.emit("beforeLog", hookEntry).then((processed) => {
3902
- message = processed.message;
3903
- }).catch(() => {
3904
- });
3905
- const [format, ...styles2] = createStyledOutput(
3906
- level,
3907
- LEVEL_STYLES,
3908
- prefix,
3909
- message,
3910
- this.displaySettings.showLocation ? stackInfo : null,
3911
- this.config.autoDetectTheme,
3912
- this._activePreset,
3913
- this._activePresetName
3914
- );
3915
- const groupIndent = " ".repeat(this.groupDepth);
3916
- const finalFormat = groupIndent + format;
3917
- this.writeOutput(finalFormat, level, styles2, additionalArgs);
3918
- if (this.exportHandler) {
3919
- this.exportHandler.setGroupInfo(this.groupDepth);
3920
- }
3921
- const metadata = {
3922
- timestamp,
3923
- level,
3924
- prefix,
3925
- stackInfo: stackInfo ? stackInfo : void 0
3926
- };
3927
- this.handlers.forEach((handler) => {
3928
- try {
3929
- handler.handle(level, message, serializedArgs, metadata);
3930
- } catch (error2) {
3931
- console.error("Log handler failed:", error2);
3932
- }
3933
- });
3934
- if (this.transportManager) {
3935
- const levelValues = {
3936
- debug: 0,
3937
- info: 1,
3938
- warn: 2,
3939
- error: 3,
3940
- critical: 4
3941
- };
3942
- const record = {
3943
- level,
3944
- levelValue: levelValues[level],
3945
- time: Date.now(),
3946
- msg: message,
3947
- prefix,
3948
- location: stackInfo ? {
3949
- file: stackInfo.file,
3950
- line: stackInfo.line,
3951
- column: stackInfo.column,
3952
- function: stackInfo.function
3953
- } : void 0
3954
- };
3955
- this.transportManager.write(record).catch(() => {
3956
- });
3957
- }
3958
- this.hookManager.emit("afterLog", hookEntry).catch(() => {
3959
- });
3960
- }
3961
- logWithBindings(bindings, level, ...args) {
3962
- if (!this.shouldLog(level)) return;
3963
- let prefix = "";
3964
- const colorCapability = getColorCapability();
3965
- if (bindings.badges?.length) {
3966
- prefix += bindings.badges.map((b) => formatBadge(b, "pill", colorCapability, "#00ff88")).join(" ") + " ";
3967
- }
3968
- if (bindings.scope) {
3969
- prefix += formatBadge(bindings.scope, "pill", colorCapability, "#00ffff") + " ";
3970
- }
3971
- if (prefix && args.length > 0) {
3972
- args[0] = prefix + String(args[0]);
3973
- }
3974
- this.log(level, ...args);
3975
- }
3976
- debug(...args) {
3977
- this.log("debug", ...args);
3978
- }
3979
- /**
3980
- * Registra mensajes informativos
3981
- *
3982
- * @param {...any} args - Mensajes y datos informativos
3983
- *
3984
- * @example
3985
- * logger.info('Servidor iniciado en puerto 3000');
3986
- * logger.info('Usuario conectado:', userId);
3987
- * logger.info('Procesando', totalItems, 'elementos');
3988
- *
3989
- * @since 0.3.0
3990
- */
3991
- info(...args) {
3992
- this.log("info", ...args);
3993
- }
3994
- /**
3995
- * Registra mensajes de advertencia
3996
- *
3997
- * @param {...any} args - Mensajes de advertencia
3998
- *
3999
- * @example
4000
- * logger.warn('Memoria al 85% de capacidad');
4001
- * logger.warn('API deprecada, usar v2');
4002
- * logger.warn('Reintentos agotados:', maxRetries);
4003
- *
4004
- * @since 0.3.0
4005
- */
4006
- warn(...args) {
4007
- this.log("warn", ...args);
4008
- }
4009
- /**
4010
- * Registra mensajes de error
4011
- *
4012
- * @param {...any} args - Mensajes de error y stack traces
4013
- *
4014
- * @example
4015
- * logger.error('Fallo en conexión a base de datos');
4016
- * logger.error('Error al procesar:', error.message, error.stack);
4017
- * logger.error('Código de error:', errorCode);
4018
- *
4019
- * @since 0.3.0
4020
- */
4021
- error(...args) {
4022
- this.log("error", ...args);
4023
- }
4024
- /**
4025
- * Registra mensajes de éxito (nivel info especial)
4026
- *
4027
- * @param {...any} args - Mensajes de operaciones exitosas
4028
- *
4029
- * @example
4030
- * logger.success('Base de datos conectada');
4031
- * logger.success('Usuario creado con ID:', userId);
4032
- * logger.success('✓ Tests pasados: 42/42');
4033
- *
4034
- * @since 0.3.0
4035
- */
4036
- success(...args) {
4037
- if (!this.shouldLog("info")) return;
4038
- const stackInfo = this.config.enableStackTrace ? parseStackTrace() : null;
4039
- const prefix = this.getEffectivePrefix();
4040
- const message = args.length > 0 ? String(args[0]) : "";
4041
- const additionalArgs = args.slice(1);
4042
- const [format, ...styles2] = createStyledOutput(
4043
- "info",
4044
- LEVEL_STYLES,
4045
- prefix,
4046
- message,
4047
- this.displaySettings.showLocation ? stackInfo : null,
4048
- this.config.autoDetectTheme,
4049
- this._activePreset,
4050
- this._activePresetName
4051
- );
4052
- const successStyle = LEVEL_STYLES.success;
4053
- let emoji = "✅";
4054
- let label = "SUCCESS";
4055
- if (successStyle) {
4056
- if (successStyle.emoji) {
4057
- emoji = successStyle.emoji;
4058
- }
4059
- if (successStyle.label) {
4060
- label = successStyle.label;
4061
- }
4062
- }
4063
- const successFormat = format.replace(/ℹ️ INFO/, `${emoji} ${label}`);
4064
- const groupIndent = " ".repeat(this.groupDepth);
4065
- const finalFormat = groupIndent + successFormat;
4066
- if (additionalArgs.length > 0) {
4067
- console.log(finalFormat, ...styles2, ...additionalArgs);
4068
- } else {
4069
- console.log(finalFormat, ...styles2);
4070
- }
4071
- const metadata = {
4072
- timestamp: formatTimestamp$1(),
4073
- level: "info",
4074
- prefix,
4075
- stackInfo: stackInfo ? stackInfo : void 0
4076
- };
4077
- this.handlers.forEach((handler) => {
4078
- try {
4079
- handler.handle("info", message, args, metadata);
4080
- } catch (error2) {
4081
- console.error("Log handler failed:", error2);
4082
- }
4083
- });
4084
- }
4085
- /**
4086
- * Registra información de trace (debugging detallado)
4087
- *
4088
- * @param {...any} args - Datos detallados para debugging
4089
- *
4090
- * @example
4091
- * logger.trace('Entrando en función processData');
4092
- * logger.trace('Stack completo:', new Error().stack);
4093
- *
4094
- * @since 0.3.0
4095
- */
4096
- trace(...args) {
4097
- this.log("debug", ...args);
4098
- if (this.shouldLog("debug")) {
4099
- console.trace(...args);
4100
- }
4101
- }
4102
- /**
4103
- * Registra errores críticos (prioridad más alta)
4104
- *
4105
- * @param {...any} args - Errores críticos del sistema
4106
- *
4107
- * @example
4108
- * logger.critical('Sistema caído - reinicio inmediato requerido');
4109
- * logger.critical('Pérdida de datos detectada');
4110
- * logger.critical('Brecha de seguridad:', securityError);
4111
- *
4112
- * @since 0.3.0
4113
- */
4114
- critical(...args) {
4115
- this.log("critical", ...args);
4116
- }
4117
- // ===== ADVANCED LOGGING FEATURES =====
4118
- /**
4119
- * Muestra datos en formato de tabla
4120
- *
4121
- * @param {any} data - Datos a mostrar (array de objetos o matriz)
4122
- * @param {string[]} columns - Columnas específicas a mostrar (opcional)
4123
- *
4124
- * @example
4125
- * const usuarios = [
4126
- * { id: 1, nombre: 'Juan', edad: 30 },
4127
- * { id: 2, nombre: 'María', edad: 25 }
4128
- * ];
4129
- * logger.table(usuarios);
4130
- * logger.table(usuarios, ['nombre', 'edad']); // Solo estas columnas
4131
- *
4132
- * @since 0.3.0
4133
- */
4134
- table(data, columns) {
4135
- if (!this.shouldLog("info")) return;
4136
- const prefix = this.getEffectivePrefix();
4137
- const tableStyle = StylePresets.accent().build();
4138
- const format = `%c📊 TABLE${prefix ? ` [${prefix}]` : ""}`;
4139
- console.log(format, tableStyle);
4140
- if (columns) {
4141
- console.table(data, columns);
4142
- } else {
4143
- console.table(data);
4144
- }
4145
- }
4146
- /**
4147
- * Inicia un grupo colapsable en la consola
4148
- *
4149
- * @param {string} label - Etiqueta del grupo
4150
- * @param {boolean} collapsed - Si el grupo inicia colapsado (default: false)
4151
- *
4152
- * @example
4153
- * logger.group('Procesando usuarios');
4154
- * logger.info('Usuario 1 procesado');
4155
- * logger.info('Usuario 2 procesado');
4156
- * logger.groupEnd();
4157
- *
4158
- * @example
4159
- * // Grupo colapsado por defecto
4160
- * logger.group('Detalles adicionales', true);
4161
- * logger.debug('Información detallada aquí');
4162
- * logger.groupEnd();
4163
- *
4164
- * @since 0.3.0
4165
- */
4166
- group(label, collapsed = false) {
4167
- const groupStyle = new StyleBuilder().bg("linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%)").color("#1565c0").border("1px solid #90caf9").padding("4px 12px").rounded("6px").bold().build();
4168
- const format = `%c📁 ${label}`;
4169
- if (collapsed) {
4170
- console.groupCollapsed(format, groupStyle);
4171
- } else {
4172
- console.group(format, groupStyle);
4173
- }
4174
- this.groupDepth++;
4175
- }
4176
- /**
4177
- * Finaliza el grupo actual de la consola
4178
- *
4179
- * @example
4180
- * logger.group('Operaciones');
4181
- * logger.info('Operación 1');
4182
- * logger.info('Operación 2');
4183
- * logger.groupEnd(); // Cierra el grupo
4184
- *
4185
- * @since 0.3.0
4186
- */
4187
- groupEnd() {
4188
- if (this.groupDepth > 0) {
4189
- console.groupEnd();
4190
- this.groupDepth--;
4191
- }
4192
- }
4193
- // ===== PERFORMANCE TIMING =====
4194
- /**
4195
- * Inicia un temporizador con la etiqueta dada
4196
- *
4197
- * @param {string} label - Etiqueta identificadora del temporizador
4198
- *
4199
- * @example
4200
- * logger.time('proceso-datos');
4201
- * // ... operación costosa ...
4202
- * logger.timeEnd('proceso-datos'); // ⏱️ Timer ended: proceso-datos - 1523.45ms
4203
- *
4204
- * @since 0.3.0
4205
- */
4206
- time(label) {
4207
- const timer = {
4208
- label,
4209
- startTime: performance.now()
4210
- };
4211
- this.timers.set(label, timer);
4212
- const timerStyle = StylePresets.warning().build();
4213
- console.log(`%c⏱️ Timer started: ${label}`, timerStyle);
4214
- }
4215
- /**
4216
- * Finaliza un temporizador y muestra el tiempo transcurrido
4217
- *
4218
- * @param {string} label - Etiqueta del temporizador a finalizar
4219
- *
4220
- * @example
4221
- * logger.time('consulta-db');
4222
- * await consultarBaseDatos();
4223
- * logger.timeEnd('consulta-db'); // ⏱️ Timer ended: consulta-db - 234.56ms
4224
- *
4225
- * @since 0.3.0
4226
- */
4227
- timeEnd(label) {
4228
- const timer = this.timers.get(label);
4229
- if (!timer) {
4230
- this.warn(`Timer '${label}' does not exist`);
4231
- return;
4232
- }
4233
- const elapsed = performance.now() - timer.startTime;
4234
- this.timers.delete(label);
4235
- const timerStyle = StylePresets.success().build();
4236
- console.log(`%c⏱️ Timer ended: ${label} - ${elapsed.toFixed(2)}ms`, timerStyle);
4237
- }
4238
- // ===== ADVANCED VISUAL FEATURES =====
4239
- /**
4240
- * Muestra un banner con el tipo especificado o configurado
4241
- *
4242
- * @param {BannerType} bannerType - Tipo de banner (opcional)
4243
- *
4244
- * @example
4245
- * logger.showBanner('ascii'); // Banner ASCII art
4246
- * logger.showBanner('unicode'); // Banner con caracteres Unicode
4247
- * logger.showBanner('svg'); // Banner con gráfico SVG
4248
- * logger.showBanner(); // Usa el tipo configurado
4249
- *
4250
- * @since 0.3.0
4251
- */
4252
- showBanner(bannerType) {
4253
- const effectiveBannerType = bannerType ? bannerType : this.config.bannerType;
4254
- displayInitBanner(effectiveBannerType);
4255
- }
4256
- /**
4257
- * Registra mensaje con imagen SVG de fondo
4258
- *
4259
- * @param {string} message - Mensaje a mostrar
4260
- * @param {string} svgContent - Contenido SVG personalizado (opcional)
4261
- * @param {StyleOptions} options - Opciones de estilo (ancho, alto, padding)
4262
- *
4263
- * @example
4264
- * // SVG automático con gradiente
4265
- * logger.logWithSVG('🎆 Bienvenido a Better Logger');
4266
- *
4267
- * @example
4268
- * // SVG personalizado
4269
- * const customSVG = '<svg>...</svg>';
4270
- * logger.logWithSVG('Logo', customSVG, { width: 400, height: 100 });
4271
- *
4272
- * @since 0.3.0
4273
- */
4274
- logWithSVG(message, svgContent, options = {}) {
4275
- const { width = 300, height = 60, padding = "30px 150px" } = options;
4276
- let svgDataUri = "";
4277
- if (svgContent) {
4278
- const encodedSVG = encodeURIComponent(svgContent);
4279
- svgDataUri = `data:image/svg+xml,${encodedSVG}`;
4280
- } else {
4281
- const defaultSVG = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${width} ${height}'><defs><linearGradient id='grad' x1='0%' y1='0%' x2='100%' y2='0%'><stop offset='0%' style='stop-color:%23667eea'/><stop offset='100%' style='stop-color:%23764ba2'/></linearGradient></defs><rect width='100%' height='100%' fill='url(%23grad)' rx='4'/><text x='${width / 2}' y='${height / 2 + 5}' text-anchor='middle' fill='white' font-family='monospace' font-size='14' font-weight='bold'>${message}</text></svg>`;
4282
- svgDataUri = `data:image/svg+xml,${encodeURIComponent(defaultSVG)}`;
4283
- }
4284
- const svgStyle = new StyleBuilder().bg(`url("${svgDataUri}") no-repeat center center`).padding(padding).color("transparent").rounded("4px").build();
4285
- console.log(`%c${message}`, svgStyle);
4286
- }
4287
- /**
4288
- * Registra mensaje con gradiente animado de fondo
4289
- *
4290
- * @param {string} message - Mensaje a animar
4291
- * @param {number} duration - Duración de la animación en segundos (default: 3)
4292
- *
4293
- * @example
4294
- * logger.logAnimated('🌈 Animación en progreso');
4295
- * logger.logAnimated('Cargando...', 5); // Animación de 5 segundos
4296
- *
4297
- * @since 0.3.0
4298
- */
4299
- logAnimated(message, duration = 3) {
4300
- if (!document.getElementById("logger-animations")) {
4301
- const style = document.createElement("style");
4302
- style.id = "logger-animations";
4303
- style.textContent = `
4304
- @keyframes loggerGradient {
4305
- 0% { background-position: 0% 50%; }
4306
- 50% { background-position: 100% 50%; }
4307
- 100% { background-position: 0% 50%; }
4308
- }
4309
- `;
4310
- document.head.appendChild(style);
4311
- }
4312
- const animatedStyle = new StyleBuilder().bg("linear-gradient(-45deg, #667eea, #764ba2, #667eea, #764ba2)").css("background-size", "400% 400%").color("#ffffff").padding("12px 20px").rounded("8px").bold().font("Monaco, Consolas, monospace").animation(`loggerGradient ${duration}s ease infinite`).display("inline-block").build();
4313
- console.log(`%c${message}`, animatedStyle);
4314
- }
4315
- /**
4316
- * Agrupa logs por una propiedad específica usando Object.groupBy (cuando esté disponible)
4317
- *
4318
- * @param {T[]} items - Array de elementos a agrupar
4319
- * @param {Function} groupBy - Función que retorna la clave de agrupación
4320
- *
4321
- * @example
4322
- * const ventas = [
4323
- * { producto: 'Laptop', categoria: 'Electrónica', precio: 1200 },
4324
- * { producto: 'Mouse', categoria: 'Electrónica', precio: 25 },
4325
- * { producto: 'Libro', categoria: 'Literatura', precio: 15 }
4326
- * ];
4327
- * logger.logGrouped(ventas, item => item.categoria);
4328
- *
4329
- * @since 0.3.0
4330
- */
4331
- logGrouped(items, groupBy) {
4332
- try {
4333
- let grouped;
4334
- if (Object.groupBy) {
4335
- grouped = Object.groupBy(items, groupBy);
4336
- } else {
4337
- grouped = items.reduce((acc, item) => {
4338
- const key = groupBy(item);
4339
- if (!acc[key]) {
4340
- acc[key] = [];
4341
- }
4342
- acc[key].push(item);
4343
- return acc;
4344
- }, {});
4345
- }
4346
- Object.entries(grouped).forEach(([group2, groupItems]) => {
4347
- this.group(`Group: ${group2}`);
4348
- this.table(groupItems);
4349
- this.groupEnd();
4350
- });
4351
- } catch {
4352
- this.info("Grouped data:", items);
4353
- }
4354
- }
4355
- // ===== OUTPUT WRITER SYSTEM =====
4356
- /**
4357
- * Writes formatted output to the configured destination.
4358
- * Respects outputMode configuration for console, silent, or custom output.
4359
- *
4360
- * @private
4361
- * @param {string} message - Formatted log message
4362
- * @param {LogLevel} level - Log level
4363
- * @param {string[]} styles - CSS styles for browser console
4364
- * @param {any[]} additionalArgs - Additional arguments to log
4365
- * @since 4.0.0
4366
- */
4367
- writeOutput(message, level, styles2, additionalArgs) {
4368
- const mode = this.config.outputMode ?? "console";
4369
- if (mode === "silent") {
4370
- return;
4371
- }
4372
- if (mode === "custom" && this.config.outputWriter) {
4373
- const fullMessage = additionalArgs.length > 0 ? `${message} ${additionalArgs.map((a) => String(a)).join(" ")}` : message;
4374
- this.config.outputWriter.write(fullMessage, level, styles2);
4375
- return;
4376
- }
4377
- if (additionalArgs.length > 0) {
4378
- console.log(message, ...styles2, ...additionalArgs);
4379
- } else {
4380
- console.log(message, ...styles2);
4381
- }
4382
- }
4383
- // ===== CLI SYSTEM =====
4384
- /**
4385
- * Procesador de comandos CLI para configuración y exportación del logger
4386
- *
4387
- * @param {string} command - Comando CLI a ejecutar
4388
- * @returns {Promise<void>}
4389
- *
4390
- * @example
4391
- * // Comandos disponibles
4392
- * await logger.cli('export json'); // Exporta logs en JSON
4393
- * await logger.cli('export csv'); // Exporta logs en CSV
4394
- * await logger.cli('theme list'); // Lista temas disponibles
4395
- * await logger.cli('theme set neon'); // Cambia al tema neon
4396
- * await logger.cli('config show'); // Muestra configuración actual
4397
- * await logger.cli('history clear'); // Limpia historial de logs
4398
- * await logger.cli('status'); // Muestra estado del logger
4399
- * await logger.cli('help'); // Muestra ayuda de comandos
4400
- *
4401
- * @since 0.3.0
4402
- */
4403
- async cli(command) {
4404
- if (!this.cliProcessor) {
4405
- this.error("CLI processor not initialized");
4406
- return;
4407
- }
4408
- await this.cliProcessor.processCommand(command, this);
4409
- }
4410
- }
4411
- let _defaultLogger = null;
4412
- function getDefaultLogger() {
4413
- if (!_defaultLogger) {
4414
- _defaultLogger = new Logger({
4415
- verbosity: "info",
4416
- enableColors: true,
4417
- enableTimestamps: true,
4418
- enableStackTrace: true,
4419
- bufferSize: 1e3
4420
- // Enable export functionality by default
4421
- });
4422
- try {
4423
- displayInitBanner();
4424
- } catch (error2) {
4425
- }
4426
- }
4427
- return _defaultLogger;
4428
- }
4429
- getDefaultLogger();
4430
- export {
4431
- APILogger as A,
4432
- BANNER_VARIANTS as B,
4433
- ComponentLogger as C,
4434
- ExportLogHandler as E,
4435
- HookManager as H,
4436
- Logger as L,
4437
- SerializerRegistry as S,
4438
- THEME_PRESETS as T,
4439
- THEME_BANNERS as a,
4440
- TransportManager as b,
4441
- ScopedLogger as c,
4442
- ContextLogger as d,
4443
- formatColumns as e,
4444
- formatWithRightAlign as f,
4445
- formatKeyValue as g,
4446
- formatBadge as h,
4447
- formatTimestamp as i,
4448
- formatRelativeTime as j,
4449
- formatElapsedTime as k,
4450
- isKeyValueObject as l,
4451
- getVisibleLength as m,
4452
- applyLogOptions as n,
4453
- displayInitBanner as o,
4454
- padToWidth as p,
4455
- resetStartTime as r,
4456
- stripAnsi as s
4457
- };
4458
- //# sourceMappingURL=Logger-D-gmmgR2.js.map