@mks2508/better-logger 2.1.0 → 3.1.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 (111) hide show
  1. package/.claude/settings.local.json +8 -1
  2. package/CHANGELOG.json +168 -1
  3. package/CHANGELOG.md +127 -0
  4. package/CLAUDE.md +14 -1
  5. package/README.md +111 -20
  6. package/dist/Logger.d.ts +217 -70
  7. package/dist/Logger.d.ts.map +1 -1
  8. package/dist/ScopedLogger.d.ts +23 -276
  9. package/dist/ScopedLogger.d.ts.map +1 -1
  10. package/dist/chunks/Logger-BV0v1AyC.js +2 -0
  11. package/dist/chunks/Logger-BV0v1AyC.js.map +1 -0
  12. package/dist/chunks/{Logger-B7L-ujY4.js → Logger-C086w3EM.js} +868 -102
  13. package/dist/chunks/Logger-C086w3EM.js.map +1 -0
  14. package/dist/chunks/environment-C_8J-zQ_.js +4 -0
  15. package/dist/chunks/environment-C_8J-zQ_.js.map +1 -0
  16. package/dist/chunks/{environment-TI2ByCPT.js → environment-DXHouGD4.js} +468 -100
  17. package/dist/chunks/environment-DXHouGD4.js.map +1 -0
  18. package/dist/chunks/{formatting-CuNUqGks.js → formatting-BNnVUPcw.js} +2 -2
  19. package/dist/chunks/{formatting-CuNUqGks.js.map → formatting-BNnVUPcw.js.map} +1 -1
  20. package/dist/chunks/{formatting-Blwy-f0W.js → formatting-Cg5YhB9Y.js} +2 -2
  21. package/dist/chunks/{formatting-Blwy-f0W.js.map → formatting-Cg5YhB9Y.js.map} +1 -1
  22. package/dist/core.cjs +1 -1
  23. package/dist/core.js +2 -2
  24. package/dist/exports-module.d.ts +1 -1
  25. package/dist/exports-module.d.ts.map +1 -1
  26. package/dist/exports.cjs +1 -1
  27. package/dist/exports.js +2 -2
  28. package/dist/hooks/HookManager.d.ts +21 -0
  29. package/dist/hooks/HookManager.d.ts.map +1 -0
  30. package/dist/hooks/index.d.ts +2 -0
  31. package/dist/hooks/index.d.ts.map +1 -0
  32. package/dist/index.cjs +1 -1
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.ts +30 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +433 -20
  37. package/dist/index.js.map +1 -1
  38. package/dist/serializers/SerializerRegistry.d.ts +16 -0
  39. package/dist/serializers/SerializerRegistry.d.ts.map +1 -0
  40. package/dist/serializers/index.d.ts +2 -0
  41. package/dist/serializers/index.d.ts.map +1 -0
  42. package/dist/styling/StyleCache.d.ts +42 -0
  43. package/dist/styling/StyleCache.d.ts.map +1 -0
  44. package/dist/styling-module.d.ts +1 -1
  45. package/dist/styling-module.d.ts.map +1 -1
  46. package/dist/styling.cjs +1 -1
  47. package/dist/styling.js +3 -3
  48. package/dist/terminal/color-converter.d.ts +73 -0
  49. package/dist/terminal/color-converter.d.ts.map +1 -0
  50. package/dist/terminal/formatter.d.ts +20 -0
  51. package/dist/terminal/formatter.d.ts.map +1 -0
  52. package/dist/terminal/terminal-renderer.d.ts +20 -6
  53. package/dist/terminal/terminal-renderer.d.ts.map +1 -1
  54. package/dist/transports/ConsoleTransport.d.ts +9 -0
  55. package/dist/transports/ConsoleTransport.d.ts.map +1 -0
  56. package/dist/transports/FileTransport.d.ts +15 -0
  57. package/dist/transports/FileTransport.d.ts.map +1 -0
  58. package/dist/transports/HttpTransport.d.ts +16 -0
  59. package/dist/transports/HttpTransport.d.ts.map +1 -0
  60. package/dist/transports/TransportManager.d.ts +14 -0
  61. package/dist/transports/TransportManager.d.ts.map +1 -0
  62. package/dist/transports/index.d.ts +5 -0
  63. package/dist/transports/index.d.ts.map +1 -0
  64. package/dist/types/core.d.ts +55 -0
  65. package/dist/types/core.d.ts.map +1 -1
  66. package/dist/types/hooks.d.ts +36 -0
  67. package/dist/types/hooks.d.ts.map +1 -0
  68. package/dist/types/index.d.ts +5 -1
  69. package/dist/types/index.d.ts.map +1 -1
  70. package/dist/types/serializers.d.ts +25 -0
  71. package/dist/types/serializers.d.ts.map +1 -0
  72. package/dist/types/transports.d.ts +47 -0
  73. package/dist/types/transports.d.ts.map +1 -0
  74. package/dist/utils/environment-detector.d.ts +10 -0
  75. package/dist/utils/environment-detector.d.ts.map +1 -1
  76. package/docs/API.md +227 -0
  77. package/package.json +1 -1
  78. package/packages/core/package.json +1 -1
  79. package/packages/styling/package.json +2 -2
  80. package/src/Logger.ts +403 -114
  81. package/src/ScopedLogger.ts +78 -318
  82. package/src/hooks/HookManager.ts +177 -0
  83. package/src/hooks/index.ts +1 -0
  84. package/src/index.ts +133 -3
  85. package/src/serializers/SerializerRegistry.ts +173 -0
  86. package/src/serializers/index.ts +1 -0
  87. package/src/styling/StyleCache.ts +131 -0
  88. package/src/terminal/color-converter.ts +315 -0
  89. package/src/terminal/formatter.ts +236 -0
  90. package/src/terminal/terminal-renderer.ts +74 -79
  91. package/src/transports/ConsoleTransport.ts +28 -0
  92. package/src/transports/FileTransport.ts +53 -0
  93. package/src/transports/HttpTransport.ts +56 -0
  94. package/src/transports/TransportManager.ts +130 -0
  95. package/src/transports/index.ts +4 -0
  96. package/src/types/core.ts +68 -0
  97. package/src/types/hooks.ts +45 -0
  98. package/src/types/index.ts +44 -1
  99. package/src/types/serializers.ts +30 -0
  100. package/src/types/transports.ts +52 -0
  101. package/src/utils/environment-detector.ts +23 -1
  102. package/dist/chunks/Logger-B7L-ujY4.js.map +0 -1
  103. package/dist/chunks/Logger-DzU_c5sX.js +0 -2
  104. package/dist/chunks/Logger-DzU_c5sX.js.map +0 -1
  105. package/dist/chunks/ScopedLogger-BY3-E8Ov.js +0 -2
  106. package/dist/chunks/ScopedLogger-BY3-E8Ov.js.map +0 -1
  107. package/dist/chunks/ScopedLogger-D-RbiFZn.js +0 -361
  108. package/dist/chunks/ScopedLogger-D-RbiFZn.js.map +0 -1
  109. package/dist/chunks/environment-Ba5kShbx.js +0 -4
  110. package/dist/chunks/environment-Ba5kShbx.js.map +0 -1
  111. package/dist/chunks/environment-TI2ByCPT.js.map +0 -1
package/src/index.ts CHANGED
@@ -98,7 +98,12 @@ export const groupEnd = () => getLogger().groupEnd();
98
98
  export const time = (label: string) => getLogger().time(label);
99
99
  export const timeEnd = (label: string) => getLogger().timeEnd(label);
100
100
  export const setGlobalPrefix = (prefix: string) => getLogger().setGlobalPrefix(prefix);
101
- export const scope = (prefix: string) => getLogger().scope(prefix);
101
+ export const scope = (name: string) => getLogger().scope(name);
102
+ export const component = (name: string) => getLogger().component(name);
103
+ export const api = (name: string) => getLogger().api(name);
104
+ export const badges = (badgeList: string[]) => getLogger().badges(badgeList);
105
+ export const badge = (badgeName: string) => getLogger().badge(badgeName);
106
+ export const clearBadges = () => getLogger().clearBadges();
102
107
  export const setVerbosity = (level: Verbosity) => getLogger().setVerbosity(level);
103
108
  export const addHandler = (handler: ILogHandler) => getLogger().addHandler(handler);
104
109
  export const setTheme = (theme: ThemeVariant) => getLogger().setTheme(theme);
@@ -122,7 +127,31 @@ export type {
122
127
  LogMetadata,
123
128
  StackInfo,
124
129
  TimerEntry,
125
- OutputFormat
130
+ TimerResult,
131
+ OutputFormat,
132
+ IScopedLogger,
133
+ IAPILogger,
134
+ IComponentLogger,
135
+ Bindings,
136
+ SerializerFn,
137
+ SerializerContext,
138
+ SerializerConfig,
139
+ ISerializerRegistry,
140
+ HookLogEntry,
141
+ HookEvent,
142
+ HookCallback,
143
+ MiddlewareFn,
144
+ IHookManager,
145
+ TransportRecord,
146
+ TransportOptions,
147
+ TransportTarget,
148
+ ITransport,
149
+ StyleCacheConfig,
150
+ BadgeStyle,
151
+ TimestampFormat,
152
+ ColumnAlign,
153
+ ColumnConfig,
154
+ LogOptions,
126
155
  } from './types/index.js';
127
156
 
128
157
  // Styling utilities
@@ -141,6 +170,57 @@ export {
141
170
  AnalyticsLogHandler
142
171
  } from './handlers/index.js';
143
172
 
173
+ // Serializers
174
+ export { SerializerRegistry } from './serializers/index.js';
175
+
176
+ // Hooks & Middleware
177
+ export { HookManager } from './hooks/index.js';
178
+
179
+ // Transports
180
+ export {
181
+ TransportManager,
182
+ ConsoleTransport,
183
+ FileTransport,
184
+ HttpTransport
185
+ } from './transports/index.js';
186
+
187
+ // Style Cache
188
+ export { StyleCache, getStyleCache } from './styling/StyleCache.js';
189
+
190
+ // Enterprise feature function exports
191
+ import type { SerializerFn, HookEvent, HookCallback, MiddlewareFn, TransportTarget } from './types/index.js';
192
+ export const addSerializer = <T>(
193
+ type: new (...args: any[]) => T,
194
+ serializer: SerializerFn<T>,
195
+ priority?: number
196
+ ) => getLogger().addSerializer(type, serializer, priority);
197
+ export const removeSerializer = <T>(type: new (...args: any[]) => T) =>
198
+ getLogger().removeSerializer(type);
199
+ export const on = (event: HookEvent, callback: HookCallback, priority?: number) =>
200
+ getLogger().on(event, callback, priority);
201
+ export const once = (event: HookEvent, callback: HookCallback, priority?: number) =>
202
+ getLogger().once(event, callback, priority);
203
+ export const off = (event: HookEvent, callback: HookCallback) =>
204
+ getLogger().off(event, callback);
205
+ export const use = (middleware: MiddlewareFn, priority?: number) =>
206
+ getLogger().use(middleware, priority);
207
+ export const addTransport = (target: TransportTarget) =>
208
+ getLogger().addTransport(target);
209
+ export const removeTransport = (id: string) =>
210
+ getLogger().removeTransport(id);
211
+ export const flushTransports = () =>
212
+ getLogger().flushTransports();
213
+ export const closeTransports = () =>
214
+ getLogger().closeTransports();
215
+
216
+ // Scoped loggers
217
+ export {
218
+ ScopedLogger,
219
+ APILogger,
220
+ ComponentLogger,
221
+ ContextLogger
222
+ } from './ScopedLogger.js';
223
+
144
224
  // Constants
145
225
  export { DEFAULT_CONFIG } from './constants.js';
146
226
 
@@ -241,4 +321,54 @@ export const stylePresets = {
241
321
  warning: StylePresets.warning().build(),
242
322
  info: StylePresets.info().build(),
243
323
  accent: StylePresets.accent().build(),
244
- };
324
+ };
325
+
326
+ // Terminal formatting utilities
327
+ export {
328
+ formatWithRightAlign,
329
+ formatColumns,
330
+ formatKeyValue,
331
+ formatBadge,
332
+ formatTimestamp as formatTimestampExt,
333
+ formatRelativeTime,
334
+ formatElapsedTime,
335
+ resetStartTime,
336
+ isKeyValueObject,
337
+ stripAnsi,
338
+ getVisibleLength,
339
+ padToWidth,
340
+ applyLogOptions,
341
+ } from './terminal/formatter.js';
342
+
343
+ // Color converter utilities
344
+ export {
345
+ hexToRgb,
346
+ rgbToHex,
347
+ hexTo256,
348
+ colorToHex,
349
+ getANSIForeground,
350
+ getANSIBackground,
351
+ getANSI256Foreground,
352
+ getANSI256Background,
353
+ cssColorToANSI,
354
+ ANSI,
355
+ } from './terminal/color-converter.js';
356
+
357
+ export type { RGB, ColorCapability } from './terminal/color-converter.js';
358
+
359
+ // Terminal renderer
360
+ export { TerminalRenderer } from './terminal/terminal-renderer.js';
361
+ export type { ANSIStyle, ChalkLikeInterface } from './terminal/terminal-renderer.js';
362
+
363
+ // Environment detection
364
+ export {
365
+ getEnvironment,
366
+ isRunningInTerminal,
367
+ supportsANSI,
368
+ getColorCapability,
369
+ getTerminalWidth,
370
+ getTerminalHeight,
371
+ getEnvironmentInfo,
372
+ } from './utils/environment-detector.js';
373
+
374
+ export type { Environment } from './utils/environment-detector.js';
@@ -0,0 +1,173 @@
1
+ import type {
2
+ SerializerFn,
3
+ SerializerContext,
4
+ SerializerEntry,
5
+ SerializerConfig,
6
+ ISerializerRegistry
7
+ } from '../types/index.js';
8
+
9
+ const DEFAULT_CONFIG: Required<SerializerConfig> = {
10
+ maxDepth: 5,
11
+ circular: 'placeholder',
12
+ preserveUndefined: false
13
+ };
14
+
15
+ export class SerializerRegistry implements ISerializerRegistry {
16
+ private serializers: Map<Function, SerializerEntry> = new Map();
17
+ private config: Required<SerializerConfig>;
18
+
19
+ constructor(config: SerializerConfig = {}) {
20
+ this.config = { ...DEFAULT_CONFIG, ...config };
21
+ this.registerDefaults();
22
+ }
23
+
24
+ private registerDefaults(): void {
25
+ this.add(Error, (err: Error) => ({
26
+ name: err.name,
27
+ message: err.message,
28
+ stack: err.stack?.split('\n').slice(0, 10),
29
+ ...(err.cause ? { cause: this.serialize(err.cause) } : {})
30
+ }), 100);
31
+
32
+ this.add(Date, (date: Date) => ({
33
+ iso: date.toISOString(),
34
+ timestamp: date.getTime()
35
+ }), 90);
36
+
37
+ this.add(RegExp, (regex: RegExp) => ({
38
+ pattern: regex.source,
39
+ flags: regex.flags
40
+ }), 90);
41
+
42
+ this.add(Map, (map: Map<any, any>, ctx) => {
43
+ const obj: Record<string, any> = {};
44
+ map.forEach((value, key) => {
45
+ const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);
46
+ obj[keyStr] = this.serializeInternal(value, {
47
+ ...ctx,
48
+ depth: ctx.depth + 1,
49
+ path: [...ctx.path, keyStr]
50
+ });
51
+ });
52
+ return { __type: 'Map', entries: obj };
53
+ }, 80);
54
+
55
+ this.add(Set, (set: Set<any>, ctx) => ({
56
+ __type: 'Set',
57
+ values: Array.from(set).map((v, i) =>
58
+ this.serializeInternal(v, {
59
+ ...ctx,
60
+ depth: ctx.depth + 1,
61
+ path: [...ctx.path, `[${i}]`]
62
+ })
63
+ )
64
+ }), 80);
65
+
66
+ if (typeof Buffer !== 'undefined') {
67
+ this.add(Buffer as any, (buf: Buffer) => ({
68
+ __type: 'Buffer',
69
+ length: buf.length,
70
+ preview: buf.slice(0, 50).toString('hex')
71
+ }), 70);
72
+ }
73
+ }
74
+
75
+ add<T>(
76
+ type: new (...args: any[]) => T,
77
+ serializer: SerializerFn<T>,
78
+ priority: number = 50
79
+ ): void {
80
+ this.serializers.set(type, { type, serializer, priority });
81
+ }
82
+
83
+ remove<T>(type: new (...args: any[]) => T): boolean {
84
+ return this.serializers.delete(type);
85
+ }
86
+
87
+ has<T>(type: new (...args: any[]) => T): boolean {
88
+ return this.serializers.has(type);
89
+ }
90
+
91
+ getAll(): SerializerEntry[] {
92
+ return Array.from(this.serializers.values())
93
+ .sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
94
+ }
95
+
96
+ private findSerializer(value: any): SerializerEntry | null {
97
+ const sorted = this.getAll();
98
+ for (const entry of sorted) {
99
+ if (value instanceof entry.type) {
100
+ return entry;
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+
106
+ private serializeInternal(value: any, context: SerializerContext): any {
107
+ if (value === null) return null;
108
+ if (value === undefined) return this.config.preserveUndefined ? undefined : '[undefined]';
109
+ if (typeof value === 'function') return `[Function: ${value.name || 'anonymous'}]`;
110
+ if (typeof value !== 'object') return value;
111
+
112
+ if (context.depth >= this.config.maxDepth) {
113
+ return '[Max Depth]';
114
+ }
115
+
116
+ if (context.seen.has(value)) {
117
+ switch (this.config.circular) {
118
+ case 'error':
119
+ throw new Error(`Circular reference at ${context.path.join('.')}`);
120
+ case 'skip':
121
+ return undefined;
122
+ case 'placeholder':
123
+ default:
124
+ return '[Circular]';
125
+ }
126
+ }
127
+ context.seen.add(value);
128
+
129
+ const serializer = this.findSerializer(value);
130
+ if (serializer) {
131
+ return serializer.serializer(value, context);
132
+ }
133
+
134
+ if (Array.isArray(value)) {
135
+ return value.map((item, i) =>
136
+ this.serializeInternal(item, {
137
+ ...context,
138
+ depth: context.depth + 1,
139
+ path: [...context.path, `[${i}]`]
140
+ })
141
+ );
142
+ }
143
+
144
+ const result: Record<string, any> = {};
145
+ for (const [key, val] of Object.entries(value)) {
146
+ result[key] = this.serializeInternal(val, {
147
+ ...context,
148
+ depth: context.depth + 1,
149
+ path: [...context.path, key]
150
+ });
151
+ }
152
+ return result;
153
+ }
154
+
155
+ serialize(value: any, config?: SerializerConfig): any {
156
+ const mergedConfig = { ...this.config, ...config };
157
+ return this.serializeInternal(value, {
158
+ depth: 0,
159
+ maxDepth: mergedConfig.maxDepth,
160
+ path: [],
161
+ seen: new WeakSet()
162
+ });
163
+ }
164
+ }
165
+
166
+ let _defaultRegistry: SerializerRegistry | null = null;
167
+
168
+ export function getDefaultSerializerRegistry(): SerializerRegistry {
169
+ if (!_defaultRegistry) {
170
+ _defaultRegistry = new SerializerRegistry();
171
+ }
172
+ return _defaultRegistry;
173
+ }
@@ -0,0 +1 @@
1
+ export { SerializerRegistry, getDefaultSerializerRegistry } from './SerializerRegistry.js';
@@ -0,0 +1,131 @@
1
+ import type { LogLevel, DevToolsTheme } from '../types/core.js';
2
+
3
+ interface CacheKey {
4
+ level: LogLevel | 'success';
5
+ theme: DevToolsTheme;
6
+ presetName?: string;
7
+ hasPrefix: boolean;
8
+ hasLocation: boolean;
9
+ }
10
+
11
+ interface CacheEntry {
12
+ styles: string[];
13
+ format: string;
14
+ createdAt: number;
15
+ hits: number;
16
+ }
17
+
18
+ export interface StyleCacheConfig {
19
+ maxEntries?: number;
20
+ ttl?: number;
21
+ enabled?: boolean;
22
+ }
23
+
24
+ const DEFAULT_CONFIG: Required<StyleCacheConfig> = {
25
+ maxEntries: 100,
26
+ ttl: 5 * 60 * 1000,
27
+ enabled: true
28
+ };
29
+
30
+ export class StyleCache {
31
+ private cache: Map<string, CacheEntry> = new Map();
32
+ private config: Required<StyleCacheConfig>;
33
+ private hitCount = 0;
34
+ private missCount = 0;
35
+
36
+ constructor(config: StyleCacheConfig = {}) {
37
+ this.config = { ...DEFAULT_CONFIG, ...config };
38
+ }
39
+
40
+ private generateKey(key: CacheKey): string {
41
+ return `${key.level}:${key.theme}:${key.presetName || 'default'}:${key.hasPrefix}:${key.hasLocation}`;
42
+ }
43
+
44
+ get(key: CacheKey): CacheEntry | null {
45
+ if (!this.config.enabled) return null;
46
+
47
+ const cacheKey = this.generateKey(key);
48
+ const entry = this.cache.get(cacheKey);
49
+
50
+ if (!entry) {
51
+ this.missCount++;
52
+ return null;
53
+ }
54
+
55
+ if (Date.now() - entry.createdAt > this.config.ttl) {
56
+ this.cache.delete(cacheKey);
57
+ this.missCount++;
58
+ return null;
59
+ }
60
+
61
+ entry.hits++;
62
+ this.cache.delete(cacheKey);
63
+ this.cache.set(cacheKey, entry);
64
+ this.hitCount++;
65
+
66
+ return entry;
67
+ }
68
+
69
+ set(key: CacheKey, format: string, styles: string[]): void {
70
+ if (!this.config.enabled) return;
71
+
72
+ const cacheKey = this.generateKey(key);
73
+
74
+ if (this.cache.size >= this.config.maxEntries) {
75
+ const firstKey = this.cache.keys().next().value;
76
+ if (firstKey) {
77
+ this.cache.delete(firstKey);
78
+ }
79
+ }
80
+
81
+ this.cache.set(cacheKey, {
82
+ format,
83
+ styles: [...styles],
84
+ createdAt: Date.now(),
85
+ hits: 0
86
+ });
87
+ }
88
+
89
+ clear(): void {
90
+ this.cache.clear();
91
+ this.hitCount = 0;
92
+ this.missCount = 0;
93
+ }
94
+
95
+ getStats(): {
96
+ size: number;
97
+ maxSize: number;
98
+ hitRate: number;
99
+ hits: number;
100
+ misses: number;
101
+ } {
102
+ const total = this.hitCount + this.missCount;
103
+ return {
104
+ size: this.cache.size,
105
+ maxSize: this.config.maxEntries,
106
+ hitRate: total > 0 ? this.hitCount / total : 0,
107
+ hits: this.hitCount,
108
+ misses: this.missCount
109
+ };
110
+ }
111
+
112
+ setEnabled(enabled: boolean): void {
113
+ this.config.enabled = enabled;
114
+ if (!enabled) {
115
+ this.clear();
116
+ }
117
+ }
118
+
119
+ isEnabled(): boolean {
120
+ return this.config.enabled;
121
+ }
122
+ }
123
+
124
+ let _styleCache: StyleCache | null = null;
125
+
126
+ export function getStyleCache(): StyleCache {
127
+ if (!_styleCache) {
128
+ _styleCache = new StyleCache();
129
+ }
130
+ return _styleCache;
131
+ }