@mks2508/better-logger 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/.claude/settings.local.json +6 -1
  2. package/CHANGELOG.json +93 -1
  3. package/CHANGELOG.md +127 -0
  4. package/CLAUDE.md +14 -1
  5. package/README.md +111 -20
  6. package/bun.lock +333 -0
  7. package/dist/Logger.d.ts +851 -0
  8. package/dist/Logger.d.ts.map +1 -0
  9. package/dist/ScopedLogger.d.ts +57 -0
  10. package/dist/ScopedLogger.d.ts.map +1 -0
  11. package/dist/chunks/Logger-BCfx_yCK.js +2 -0
  12. package/dist/chunks/Logger-BCfx_yCK.js.map +1 -0
  13. package/dist/chunks/Logger-C126NTrD.js +4269 -0
  14. package/dist/chunks/Logger-C126NTrD.js.map +1 -0
  15. package/dist/chunks/RemoteLogHandler-CjWpWZGl.js +33 -0
  16. package/dist/chunks/RemoteLogHandler-CjWpWZGl.js.map +1 -0
  17. package/dist/chunks/RemoteLogHandler-ymkQ97xl.js +2 -0
  18. package/dist/chunks/RemoteLogHandler-ymkQ97xl.js.map +1 -0
  19. package/dist/chunks/environment-Ba5kShbx.js +4 -0
  20. package/dist/chunks/environment-Ba5kShbx.js.map +1 -0
  21. package/dist/chunks/environment-TI2ByCPT.js +1209 -0
  22. package/dist/chunks/environment-TI2ByCPT.js.map +1 -0
  23. package/dist/chunks/formatting-Blwy-f0W.js +2 -0
  24. package/dist/chunks/formatting-Blwy-f0W.js.map +1 -0
  25. package/dist/chunks/formatting-CuNUqGks.js +380 -0
  26. package/dist/chunks/formatting-CuNUqGks.js.map +1 -0
  27. package/dist/cli/CommandProcessor.d.ts +100 -0
  28. package/dist/cli/CommandProcessor.d.ts.map +1 -0
  29. package/dist/cli/commands/ConfigCommand.d.ts +14 -0
  30. package/dist/cli/commands/ConfigCommand.d.ts.map +1 -0
  31. package/dist/cli/commands/ExportCommand.d.ts +48 -0
  32. package/dist/cli/commands/ExportCommand.d.ts.map +1 -0
  33. package/dist/cli/commands/HistoryCommand.d.ts +47 -0
  34. package/dist/cli/commands/HistoryCommand.d.ts.map +1 -0
  35. package/dist/cli/commands/StatusCommand.d.ts +30 -0
  36. package/dist/cli/commands/StatusCommand.d.ts.map +1 -0
  37. package/dist/cli/commands/ThemeCommand.d.ts +30 -0
  38. package/dist/cli/commands/ThemeCommand.d.ts.map +1 -0
  39. package/dist/cli/help.d.ts +12 -0
  40. package/dist/cli/help.d.ts.map +1 -0
  41. package/dist/cli/index.d.ts +15 -0
  42. package/dist/cli/index.d.ts.map +1 -0
  43. package/dist/constants.d.ts +227 -0
  44. package/dist/constants.d.ts.map +1 -0
  45. package/dist/core.cjs +2 -0
  46. package/dist/core.cjs.map +1 -0
  47. package/dist/core.d.ts +127 -0
  48. package/dist/core.d.ts.map +1 -0
  49. package/dist/core.js +291 -0
  50. package/dist/core.js.map +1 -0
  51. package/dist/example.d.ts +18 -0
  52. package/dist/example.d.ts.map +1 -0
  53. package/dist/exports-module.d.ts +196 -0
  54. package/dist/exports-module.d.ts.map +1 -0
  55. package/dist/exports.cjs +2 -0
  56. package/dist/exports.cjs.map +1 -0
  57. package/dist/exports.js +238 -0
  58. package/dist/exports.js.map +1 -0
  59. package/dist/handlers/AnalyticsLogHandler.d.ts +8 -0
  60. package/dist/handlers/AnalyticsLogHandler.d.ts.map +1 -0
  61. package/dist/handlers/ExportLogHandler.d.ts +100 -0
  62. package/dist/handlers/ExportLogHandler.d.ts.map +1 -0
  63. package/dist/handlers/FileLogHandler.d.ts +33 -0
  64. package/dist/handlers/FileLogHandler.d.ts.map +1 -0
  65. package/dist/handlers/RemoteLogHandler.d.ts +11 -0
  66. package/dist/handlers/RemoteLogHandler.d.ts.map +1 -0
  67. package/dist/handlers/index.d.ts +8 -0
  68. package/dist/handlers/index.d.ts.map +1 -0
  69. package/dist/hooks/HookManager.d.ts +21 -0
  70. package/dist/hooks/HookManager.d.ts.map +1 -0
  71. package/dist/hooks/index.d.ts +2 -0
  72. package/dist/hooks/index.d.ts.map +1 -0
  73. package/dist/index.cjs +2 -0
  74. package/dist/index.cjs.map +1 -0
  75. package/dist/index.d.ts +144 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +478 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/main.d.ts +2 -0
  80. package/dist/main.d.ts.map +1 -0
  81. package/dist/serializers/SerializerRegistry.d.ts +16 -0
  82. package/dist/serializers/SerializerRegistry.d.ts.map +1 -0
  83. package/dist/serializers/index.d.ts +2 -0
  84. package/dist/serializers/index.d.ts.map +1 -0
  85. package/dist/styling/LogStyleBuilder.d.ts +146 -0
  86. package/dist/styling/LogStyleBuilder.d.ts.map +1 -0
  87. package/dist/styling/SemanticStyles.d.ts +178 -0
  88. package/dist/styling/SemanticStyles.d.ts.map +1 -0
  89. package/dist/styling/SmartPresets.d.ts +22 -0
  90. package/dist/styling/SmartPresets.d.ts.map +1 -0
  91. package/dist/styling/StyleBuilder.d.ts +140 -0
  92. package/dist/styling/StyleBuilder.d.ts.map +1 -0
  93. package/dist/styling/StyleCache.d.ts +42 -0
  94. package/dist/styling/StyleCache.d.ts.map +1 -0
  95. package/dist/styling/banners.d.ts +42 -0
  96. package/dist/styling/banners.d.ts.map +1 -0
  97. package/dist/styling/index.d.ts +10 -0
  98. package/dist/styling/index.d.ts.map +1 -0
  99. package/dist/styling/themes.d.ts +7 -0
  100. package/dist/styling/themes.d.ts.map +1 -0
  101. package/dist/styling-module.d.ts +178 -0
  102. package/dist/styling-module.d.ts.map +1 -0
  103. package/dist/styling.cjs +2 -0
  104. package/dist/styling.cjs.map +1 -0
  105. package/dist/styling.js +146 -0
  106. package/dist/styling.js.map +1 -0
  107. package/dist/terminal/terminal-renderer.d.ts +63 -0
  108. package/dist/terminal/terminal-renderer.d.ts.map +1 -0
  109. package/dist/transports/ConsoleTransport.d.ts +9 -0
  110. package/dist/transports/ConsoleTransport.d.ts.map +1 -0
  111. package/dist/transports/FileTransport.d.ts +15 -0
  112. package/dist/transports/FileTransport.d.ts.map +1 -0
  113. package/dist/transports/HttpTransport.d.ts +16 -0
  114. package/dist/transports/HttpTransport.d.ts.map +1 -0
  115. package/dist/transports/TransportManager.d.ts +14 -0
  116. package/dist/transports/TransportManager.d.ts.map +1 -0
  117. package/dist/transports/index.d.ts +5 -0
  118. package/dist/transports/index.d.ts.map +1 -0
  119. package/dist/types/core.d.ts +272 -0
  120. package/dist/types/core.d.ts.map +1 -0
  121. package/dist/types/handlers.d.ts +85 -0
  122. package/dist/types/handlers.d.ts.map +1 -0
  123. package/dist/types/hooks.d.ts +36 -0
  124. package/dist/types/hooks.d.ts.map +1 -0
  125. package/dist/types/index.d.ts +11 -0
  126. package/dist/types/index.d.ts.map +1 -0
  127. package/dist/types/serializers.d.ts +25 -0
  128. package/dist/types/serializers.d.ts.map +1 -0
  129. package/dist/types/transports.d.ts +47 -0
  130. package/dist/types/transports.d.ts.map +1 -0
  131. package/dist/utils/adapter.d.ts +48 -0
  132. package/dist/utils/adapter.d.ts.map +1 -0
  133. package/dist/utils/ansi-colors.d.ts +156 -0
  134. package/dist/utils/ansi-colors.d.ts.map +1 -0
  135. package/dist/utils/environment-detector.d.ts +35 -0
  136. package/dist/utils/environment-detector.d.ts.map +1 -0
  137. package/dist/utils/environment.d.ts +47 -0
  138. package/dist/utils/environment.d.ts.map +1 -0
  139. package/dist/utils/formatting.d.ts +58 -0
  140. package/dist/utils/formatting.d.ts.map +1 -0
  141. package/dist/utils/index.d.ts +8 -0
  142. package/dist/utils/index.d.ts.map +1 -0
  143. package/dist/utils/opentui-detection.d.ts +34 -0
  144. package/dist/utils/opentui-detection.d.ts.map +1 -0
  145. package/dist/utils/output.d.ts +46 -0
  146. package/dist/utils/output.d.ts.map +1 -0
  147. package/dist/utils/stackTrace.d.ts +6 -0
  148. package/dist/utils/stackTrace.d.ts.map +1 -0
  149. package/dist/utils/timestamps.d.ts +20 -0
  150. package/dist/utils/timestamps.d.ts.map +1 -0
  151. package/dist/vite.svg +1 -0
  152. package/docs/API.md +227 -0
  153. package/package.json +1 -1
  154. package/packages/core/package.json +1 -1
  155. package/src/Logger.ts +391 -102
  156. package/src/ScopedLogger.ts +78 -318
  157. package/src/hooks/HookManager.ts +177 -0
  158. package/src/hooks/index.ts +1 -0
  159. package/src/index.ts +77 -2
  160. package/src/serializers/SerializerRegistry.ts +173 -0
  161. package/src/serializers/index.ts +1 -0
  162. package/src/styling/StyleCache.ts +131 -0
  163. package/src/transports/ConsoleTransport.ts +28 -0
  164. package/src/transports/FileTransport.ts +53 -0
  165. package/src/transports/HttpTransport.ts +56 -0
  166. package/src/transports/TransportManager.ts +130 -0
  167. package/src/transports/index.ts +4 -0
  168. package/src/types/core.ts +46 -0
  169. package/src/types/hooks.ts +45 -0
  170. package/src/types/index.ts +39 -1
  171. package/src/types/serializers.ts +30 -0
  172. package/src/types/transports.ts +52 -0
@@ -1,344 +1,159 @@
1
- /**
2
- * @fileoverview ScopedLogger con badges y logging contextual
3
- * @version 0.3.0
4
- * @since 2024
5
- *
6
- * Proporciona loggers especializados con contexto, badges automáticos
7
- * y características avanzadas para componentes y APIs.
8
- */
9
-
10
1
  import { Logger } from './Logger.js';
11
- import type { LoggerConfig, LogLevel, Verbosity, BannerType, StyleOptions, ILogHandler } from './types/index.js';
12
-
13
- /**
14
- * Logger con scope mejorado con badges y API simplificada
15
- *
16
- * @class ScopedLogger
17
- * @extends Logger
18
- * @description Logger contextual que añade prefijos y badges automáticamente
19
- *
20
- * @example
21
- * const dbLogger = logger.scope('Database');
22
- * dbLogger.info('Conectando...'); // [Database] Conectando...
23
- *
24
- * // Con badges personalizados
25
- * dbLogger.badge('SLOW').warn('Query lenta detectada');
26
- * // [SLOW] [Database] Query lenta detectada
27
- *
28
- * @since 0.3.0
29
- */
30
- export class ScopedLogger extends Logger {
31
- private parentLogger: Logger;
32
- private scopeName: string;
2
+ import type { TimerEntry, Bindings } from './types/index.js';
3
+
4
+ export class ScopedLogger {
5
+ private readonly parent: Logger;
6
+ private readonly scopeName: string;
33
7
  private badgeList: string[] = [];
34
8
  private contextStack: string[] = [];
9
+ private _timers?: Map<string, TimerEntry>;
35
10
 
36
- constructor(parentLogger: Logger, scopeName: string, config?: Partial<LoggerConfig>) {
37
- // Initialize with parent's config plus any overrides
38
- super({ ...parentLogger.getConfig(), ...config });
39
- this.parentLogger = parentLogger;
11
+ constructor(parent: Logger, scopeName: string) {
12
+ this.parent = parent;
40
13
  this.scopeName = scopeName;
41
-
42
- // Inherit parent's handlers
43
- const parentHandlers = parentLogger.getHandlers();
44
- parentHandlers.forEach(handler => this.addHandler(handler));
45
- }
46
-
47
- /**
48
- * Añade múltiples badges a este logger con scope
49
- *
50
- * @param {string[]} badges - Array de badges a añadir
51
- * @returns {ScopedLogger} Esta instancia para encadenamiento
52
- *
53
- * @example
54
- * const api = logger.scope('API');
55
- * api.badges(['v2', 'beta', 'cached'])
56
- * .info('Respuesta desde caché');
57
- * // [v2] [beta] [cached] [API] Respuesta desde caché
58
- *
59
- * @since 0.3.0
60
- */
61
- badges(badges: string[]): ScopedLogger {
14
+ }
15
+
16
+ private get timers(): Map<string, TimerEntry> {
17
+ if (!this._timers) this._timers = new Map();
18
+ return this._timers;
19
+ }
20
+
21
+ private getBindings(): Bindings {
22
+ return {
23
+ scope: this.getScopePrefix(),
24
+ badges: this.badgeList.length > 0 ? [...this.badgeList] : undefined,
25
+ };
26
+ }
27
+
28
+ private getScopePrefix(): string {
29
+ if (this.contextStack.length === 0) return this.scopeName;
30
+ return [this.scopeName, ...this.contextStack].join(':');
31
+ }
32
+
33
+ badges(badges: string[]): this {
62
34
  this.badgeList = [...badges];
63
35
  return this;
64
36
  }
65
37
 
66
- /**
67
- * Añade un badge individual
68
- *
69
- * @param {string} badge - Badge a añadir
70
- * @returns {ScopedLogger} Esta instancia para encadenamiento
71
- *
72
- * @example
73
- * dbLogger.badge('SLOW').warn('Query tardó 3s');
74
- * // [SLOW] [Database] Query tardó 3s
75
- *
76
- * @since 0.3.0
77
- */
78
- badge(badge: string): ScopedLogger {
38
+ badge(badge: string): this {
79
39
  if (!this.badgeList.includes(badge)) {
80
40
  this.badgeList.push(badge);
81
41
  }
82
42
  return this;
83
43
  }
84
44
 
85
- /**
86
- * Elimina todos los badges
87
- *
88
- * @returns {ScopedLogger} Esta instancia para encadenamiento
89
- *
90
- * @example
91
- * api.clearBadges().info('Sin badges');
92
- * // [API] Sin badges
93
- *
94
- * @since 0.3.0
95
- */
96
- clearBadges(): ScopedLogger {
45
+ clearBadges(): this {
97
46
  this.badgeList = [];
98
47
  return this;
99
48
  }
100
49
 
101
- /**
102
- * Establece un preset de estilo para este logger con scope
103
- *
104
- * @param {string} presetName - Nombre del preset a aplicar
105
- * @returns {ScopedLogger} Esta instancia para encadenamiento
106
- *
107
- * @example
108
- * const errorLogger = logger.scope('ErrorHandler')
109
- * .style('cyberpunk');
110
- *
111
- * @since 0.3.0
112
- */
113
- style(presetName: string): ScopedLogger {
114
- this.setTheme(presetName as any); // Will be updated when we implement presets
50
+ style(presetName: string): this {
51
+ this.parent.setTheme(presetName as any);
115
52
  return this;
116
53
  }
117
54
 
118
- /**
119
- * Crea un contexto temporal que se limpia automáticamente
120
- *
121
- * @param {string} contextName - Nombre del contexto
122
- * @returns {ContextLogger} Logger con contexto temporal
123
- *
124
- * @example
125
- * const db = logger.scope('Database');
126
- *
127
- * // Contexto temporal para una operación
128
- * db.context('Migration').run(() => {
129
- * db.info('Iniciando migración');
130
- * db.success('Tablas creadas');
131
- * });
132
- * // Contexto automáticamente limpiado
133
- *
134
- * @since 0.3.0
135
- */
136
55
  context(contextName: string): ContextLogger {
137
56
  return new ContextLogger(this, contextName);
138
57
  }
139
58
 
140
- /**
141
- * Sobrescribe el logging principal para incluir badges
142
- * @protected
143
- * @param {LogLevel} level - Nivel del log
144
- * @param {...any} args - Argumentos del log
145
- */
146
- protected log(level: LogLevel, ...args: any[]): void {
147
- // Build the enhanced message with badges
148
- const badges = this.getBadgeString();
149
- const scopePrefix = this.getScopePrefix();
150
-
151
- let enhancedMessage = '';
152
- if (badges) enhancedMessage += badges + ' ';
153
- if (scopePrefix) enhancedMessage += `[${scopePrefix}] `;
154
-
155
- if (args.length > 0) {
156
- enhancedMessage += String(args[0]);
157
- // Replace the first argument with our enhanced message
158
- args[0] = enhancedMessage;
59
+ time(label: string): void {
60
+ this.timers.set(label, {
61
+ label: `${this.scopeName}:${label}`,
62
+ startTime: performance.now(),
63
+ });
64
+ }
65
+
66
+ timeEnd(label: string): number | undefined {
67
+ const timer = this.timers.get(label);
68
+ if (!timer) {
69
+ this.warn(`Timer '${label}' not found`);
70
+ return undefined;
159
71
  }
72
+ const elapsed = performance.now() - timer.startTime;
73
+ this.timers.delete(label);
74
+ this.success(`Timer: ${label} - ${elapsed.toFixed(2)}ms`);
75
+ return elapsed;
76
+ }
160
77
 
161
- // Call parent's log method
162
- super.log(level, ...args);
78
+ debug(...args: any[]): void {
79
+ this.parent.logWithBindings(this.getBindings(), 'debug', ...args);
163
80
  }
164
81
 
165
- /**
166
- * Obtiene la cadena de badges formateada
167
- * @private
168
- * @returns {string} Badges formateados como [BADGE1][BADGE2]
169
- */
170
- private getBadgeString(): string {
171
- if (this.badgeList.length === 0) return '';
172
- return this.badgeList.map(badge => `[${badge}]`).join('');
82
+ info(...args: any[]): void {
83
+ this.parent.logWithBindings(this.getBindings(), 'info', ...args);
173
84
  }
174
85
 
175
- /**
176
- * Obtiene el prefijo del scope (incluye stack de contexto)
177
- * @private
178
- * @returns {string} Prefijo completo con contextos
179
- */
180
- private getScopePrefix(): string {
181
- const parts = [this.scopeName, ...this.contextStack].filter(Boolean);
182
- return parts.join(':');
86
+ warn(...args: any[]): void {
87
+ this.parent.logWithBindings(this.getBindings(), 'warn', ...args);
88
+ }
89
+
90
+ error(...args: any[]): void {
91
+ this.parent.logWithBindings(this.getBindings(), 'error', ...args);
92
+ }
93
+
94
+ success(...args: any[]): void {
95
+ const bindings = this.getBindings();
96
+ this.parent.logWithBindings(bindings, 'info', ...args);
97
+ }
98
+
99
+ critical(...args: any[]): void {
100
+ this.parent.logWithBindings(this.getBindings(), 'critical', ...args);
101
+ }
102
+
103
+ trace(...args: any[]): void {
104
+ this.parent.logWithBindings(this.getBindings(), 'debug', ...args);
105
+ console.trace(`[${this.scopeName}]`);
183
106
  }
184
107
 
185
- /**
186
- * Método interno para añadir contexto
187
- * @internal
188
- */
189
108
  _pushContext(context: string): void {
190
109
  this.contextStack.push(context);
191
110
  }
192
111
 
193
- /**
194
- * Método interno para eliminar contexto
195
- * @internal
196
- */
197
112
  _popContext(): void {
198
113
  this.contextStack.pop();
199
114
  }
200
115
  }
201
116
 
202
- /**
203
- * Logger específico para APIs con badges comunes de API
204
- *
205
- * @class APILogger
206
- * @extends ScopedLogger
207
- * @description Logger especializado para endpoints y servicios API
208
- *
209
- * @example
210
- * const api = logger.api('REST');
211
- * api.info('GET /users');
212
- * // [API] [REST] GET /users
213
- *
214
- * api.slow('Query lenta', 3500);
215
- * // [API] [SLOW] [REST] Query lenta (3500ms)
216
- *
217
- * @since 0.3.0
218
- */
219
117
  export class APILogger extends ScopedLogger {
220
- constructor(parentLogger: Logger, apiName: string, config?: Partial<LoggerConfig>) {
221
- super(parentLogger, `API:${apiName}`, config);
118
+ constructor(parent: Logger, apiName: string) {
119
+ super(parent, `API:${apiName}`);
222
120
  this.badge('API');
223
121
  }
224
122
 
225
- /**
226
- * Registra operaciones lentas
227
- *
228
- * @param {string} message - Mensaje sobre la operación lenta
229
- * @param {number} duration - Duración en milisegundos (opcional)
230
- *
231
- * @example
232
- * api.slow('Query compleja', 5000);
233
- * api.slow('Procesamiento pesado');
234
- *
235
- * @since 0.3.0
236
- */
237
123
  slow(message: string, duration?: number): void {
238
124
  this.badge('SLOW');
239
125
  const msg = duration ? `${message} (${duration}ms)` : message;
240
126
  this.warn(msg);
241
127
  }
242
128
 
243
- /**
244
- * Registra límites de tasa alcanzados
245
- *
246
- * @param {string} message - Mensaje sobre el límite
247
- *
248
- * @example
249
- * api.rateLimit('Límite excedido: 100 req/min');
250
- *
251
- * @since 0.3.0
252
- */
253
129
  rateLimit(message: string): void {
254
130
  this.badge('RATE_LIMIT');
255
131
  this.warn(message);
256
132
  }
257
133
 
258
- /**
259
- * Registra problemas de autenticación
260
- *
261
- * @param {string} message - Mensaje de autenticación
262
- *
263
- * @example
264
- * api.auth('Token inválido o expirado');
265
- * api.auth('Credenciales incorrectas');
266
- *
267
- * @since 0.3.0
268
- */
269
134
  auth(message: string): void {
270
135
  this.badge('AUTH');
271
136
  this.error(message);
272
137
  }
273
138
 
274
- /**
275
- * Registra advertencias de deprecación
276
- *
277
- * @param {string} message - Mensaje de deprecación
278
- *
279
- * @example
280
- * api.deprecated('Este endpoint será eliminado en v2.0');
281
- * api.deprecated('Usar /v2/users en lugar de /users');
282
- *
283
- * @since 0.3.0
284
- */
285
139
  deprecated(message: string): void {
286
140
  this.badge('DEPRECATED');
287
141
  this.warn(message);
288
142
  }
289
143
  }
290
144
 
291
- /**
292
- * Logger específico para componentes de UI
293
- *
294
- * @class ComponentLogger
295
- * @extends ScopedLogger
296
- * @description Logger especializado para componentes con eventos de ciclo de vida
297
- *
298
- * @example
299
- * const authForm = logger.component('AuthForm');
300
- * authForm.lifecycle('mounted');
301
- * authForm.stateChange('idle', 'loading');
302
- *
303
- * @since 0.3.0
304
- */
305
145
  export class ComponentLogger extends ScopedLogger {
306
- constructor(parentLogger: Logger, componentName: string, config?: Partial<LoggerConfig>) {
307
- super(parentLogger, componentName, config);
146
+ constructor(parent: Logger, componentName: string) {
147
+ super(parent, componentName);
308
148
  this.badge('COMPONENT');
309
149
  }
310
150
 
311
- /**
312
- * Registra eventos del ciclo de vida del componente
313
- *
314
- * @param {string} event - Nombre del evento (mounted, unmounted, updated, etc)
315
- * @param {string} message - Mensaje adicional (opcional)
316
- *
317
- * @example
318
- * component.lifecycle('mounted', 'Componente listo');
319
- * component.lifecycle('beforeDestroy');
320
- *
321
- * @since 0.3.0
322
- */
323
151
  lifecycle(event: string, message?: string): void {
324
152
  this.badge('LIFECYCLE');
325
153
  const msg = message ? `${event}: ${message}` : event;
326
154
  this.info(msg);
327
155
  }
328
156
 
329
- /**
330
- * Registra cambios de estado
331
- *
332
- * @param {string} from - Estado anterior
333
- * @param {string} to - Estado nuevo
334
- * @param {any} data - Datos adicionales (opcional)
335
- *
336
- * @example
337
- * component.stateChange('idle', 'loading');
338
- * component.stateChange('loading', 'error', { code: 404 });
339
- *
340
- * @since 0.3.0
341
- */
342
157
  stateChange(from: string, to: string, data?: any): void {
343
158
  this.badge('STATE');
344
159
  const msg = `${from} → ${to}`;
@@ -349,42 +164,12 @@ export class ComponentLogger extends ScopedLogger {
349
164
  }
350
165
  }
351
166
 
352
- /**
353
- * Registra cambios en las propiedades
354
- *
355
- * @param {Record<string, any>} changes - Objeto con los cambios
356
- *
357
- * @example
358
- * component.propsChange({
359
- * user: newUser,
360
- * isActive: true
361
- * });
362
- *
363
- * @since 0.3.0
364
- */
365
167
  propsChange(changes: Record<string, any>): void {
366
168
  this.badge('PROPS');
367
169
  this.debug('Props changed:', changes);
368
170
  }
369
171
  }
370
172
 
371
- /**
372
- * Logger de contexto temporal que se limpia automáticamente
373
- *
374
- * @class ContextLogger
375
- * @description Proporciona un contexto temporal para operaciones agrupadas
376
- *
377
- * @example
378
- * const db = logger.scope('Database');
379
- *
380
- * // El contexto se limpia automáticamente al finalizar
381
- * db.context('Transaction').run(() => {
382
- * db.info('Iniciando transacción');
383
- * db.success('Transacción completada');
384
- * });
385
- *
386
- * @since 0.3.0
387
- */
388
173
  export class ContextLogger {
389
174
  private parentLogger: ScopedLogger;
390
175
  private contextName: string;
@@ -394,21 +179,6 @@ export class ContextLogger {
394
179
  this.contextName = contextName;
395
180
  }
396
181
 
397
- /**
398
- * Ejecuta una función con este contexto activo
399
- *
400
- * @template T - Tipo de retorno de la función
401
- * @param {Function} fn - Función a ejecutar
402
- * @returns {T} Resultado de la función
403
- *
404
- * @example
405
- * const result = logger.context('Process').run(() => {
406
- * logger.info('Procesando...');
407
- * return processData();
408
- * });
409
- *
410
- * @since 0.3.0
411
- */
412
182
  run<T>(fn: () => T): T {
413
183
  this.parentLogger._pushContext(this.contextName);
414
184
  try {
@@ -418,9 +188,6 @@ export class ContextLogger {
418
188
  }
419
189
  }
420
190
 
421
- /**
422
- * Run an async function with this context active
423
- */
424
191
  async runAsync<T>(fn: () => Promise<T>): Promise<T> {
425
192
  this.parentLogger._pushContext(this.contextName);
426
193
  try {
@@ -430,25 +197,18 @@ export class ContextLogger {
430
197
  }
431
198
  }
432
199
 
433
- /**
434
- * Start the context (manual mode)
435
- */
436
200
  start(): void {
437
201
  this.parentLogger._pushContext(this.contextName);
438
202
  }
439
203
 
440
- /**
441
- * End the context (manual mode)
442
- */
443
204
  end(): void {
444
205
  this.parentLogger._popContext();
445
206
  }
446
207
 
447
- // Delegate logging methods to parent with context
448
208
  debug(...args: any[]): void { this.parentLogger.debug(...args); }
449
209
  info(...args: any[]): void { this.parentLogger.info(...args); }
450
210
  warn(...args: any[]): void { this.parentLogger.warn(...args); }
451
211
  error(...args: any[]): void { this.parentLogger.error(...args); }
452
212
  success(...args: any[]): void { this.parentLogger.success(...args); }
453
213
  critical(...args: any[]): void { this.parentLogger.critical(...args); }
454
- }
214
+ }
@@ -0,0 +1,177 @@
1
+ import type {
2
+ HookLogEntry,
3
+ HookEvent,
4
+ HookCallback,
5
+ MiddlewareFn,
6
+ HookRegistration,
7
+ MiddlewareRegistration,
8
+ IHookManager
9
+ } from '../types/index.js';
10
+
11
+ function generateId(): string {
12
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
13
+ }
14
+
15
+ export class HookManager implements IHookManager {
16
+ private hooks: Map<HookEvent, HookRegistration[]> = new Map();
17
+ private middlewares: MiddlewareRegistration[] = [];
18
+
19
+ constructor() {
20
+ this.hooks.set('beforeLog', []);
21
+ this.hooks.set('afterLog', []);
22
+ this.hooks.set('onError', []);
23
+ }
24
+
25
+ on(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {
26
+ const registration: HookRegistration = {
27
+ id: generateId(),
28
+ event,
29
+ callback,
30
+ priority,
31
+ once: false
32
+ };
33
+
34
+ const hooks = this.hooks.get(event)!;
35
+ hooks.push(registration);
36
+ hooks.sort((a, b) => b.priority - a.priority);
37
+
38
+ return () => this.removeHook(event, registration.id);
39
+ }
40
+
41
+ once(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {
42
+ const registration: HookRegistration = {
43
+ id: generateId(),
44
+ event,
45
+ callback,
46
+ priority,
47
+ once: true
48
+ };
49
+
50
+ const hooks = this.hooks.get(event)!;
51
+ hooks.push(registration);
52
+ hooks.sort((a, b) => b.priority - a.priority);
53
+
54
+ return () => this.removeHook(event, registration.id);
55
+ }
56
+
57
+ off(event: HookEvent, callback: HookCallback): boolean {
58
+ const hooks = this.hooks.get(event);
59
+ if (!hooks) return false;
60
+
61
+ const index = hooks.findIndex(h => h.callback === callback);
62
+ if (index >= 0) {
63
+ hooks.splice(index, 1);
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+
69
+ private removeHook(event: HookEvent, id: string): void {
70
+ const hooks = this.hooks.get(event);
71
+ if (hooks) {
72
+ const index = hooks.findIndex(h => h.id === id);
73
+ if (index >= 0) {
74
+ hooks.splice(index, 1);
75
+ }
76
+ }
77
+ }
78
+
79
+ use(middleware: MiddlewareFn, priority: number = 50): () => void {
80
+ const registration: MiddlewareRegistration = {
81
+ id: generateId(),
82
+ fn: middleware,
83
+ priority
84
+ };
85
+
86
+ this.middlewares.push(registration);
87
+ this.middlewares.sort((a, b) => b.priority - a.priority);
88
+
89
+ return () => {
90
+ const index = this.middlewares.findIndex(m => m.id === registration.id);
91
+ if (index >= 0) {
92
+ this.middlewares.splice(index, 1);
93
+ }
94
+ };
95
+ }
96
+
97
+ async emit(event: HookEvent, entry: HookLogEntry): Promise<HookLogEntry> {
98
+ const hooks = this.hooks.get(event) || [];
99
+ let currentEntry = { ...entry };
100
+ const toRemove: string[] = [];
101
+
102
+ for (const hook of hooks) {
103
+ try {
104
+ const result = await hook.callback(currentEntry);
105
+ if (result) {
106
+ currentEntry = { ...currentEntry, ...result };
107
+ }
108
+ if (hook.once) {
109
+ toRemove.push(hook.id);
110
+ }
111
+ } catch (error) {
112
+ if (event !== 'onError') {
113
+ await this.emit('onError', {
114
+ ...currentEntry,
115
+ error,
116
+ hookEvent: event
117
+ } as HookLogEntry);
118
+ }
119
+ }
120
+ }
121
+
122
+ toRemove.forEach(id => this.removeHook(event, id));
123
+ return currentEntry;
124
+ }
125
+
126
+ async process(entry: HookLogEntry): Promise<HookLogEntry> {
127
+ let currentEntry = { ...entry };
128
+
129
+ currentEntry = await this.emit('beforeLog', currentEntry);
130
+
131
+ if (this.middlewares.length > 0) {
132
+ let index = 0;
133
+
134
+ const executeNext = async (): Promise<void> => {
135
+ if (index < this.middlewares.length) {
136
+ const middleware = this.middlewares[index++];
137
+ if (middleware) {
138
+ await middleware.fn(currentEntry, executeNext);
139
+ }
140
+ }
141
+ };
142
+
143
+ await executeNext();
144
+ }
145
+
146
+ return currentEntry;
147
+ }
148
+
149
+ async afterProcess(entry: HookLogEntry): Promise<void> {
150
+ await this.emit('afterLog', entry);
151
+ }
152
+
153
+ clear(): void {
154
+ this.hooks.forEach(hooks => hooks.length = 0);
155
+ this.middlewares.length = 0;
156
+ }
157
+
158
+ getStats(): { hooks: Record<HookEvent, number>; middlewares: number } {
159
+ return {
160
+ hooks: {
161
+ beforeLog: this.hooks.get('beforeLog')?.length || 0,
162
+ afterLog: this.hooks.get('afterLog')?.length || 0,
163
+ onError: this.hooks.get('onError')?.length || 0
164
+ },
165
+ middlewares: this.middlewares.length
166
+ };
167
+ }
168
+ }
169
+
170
+ let _defaultHookManager: HookManager | null = null;
171
+
172
+ export function getDefaultHookManager(): HookManager {
173
+ if (!_defaultHookManager) {
174
+ _defaultHookManager = new HookManager();
175
+ }
176
+ return _defaultHookManager;
177
+ }
@@ -0,0 +1 @@
1
+ export { HookManager, getDefaultHookManager } from './HookManager.js';