@crimsonsunset/jsg-logger 1.7.0 → 1.7.4

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.
package/index.d.ts ADDED
@@ -0,0 +1,192 @@
1
+ /**
2
+ * TypeScript definitions for @crimsonsunset/jsg-logger
3
+ */
4
+
5
+ export interface LoggerInstance {
6
+ info: (message: string, data?: any) => void;
7
+ debug: (message: string, data?: any) => void;
8
+ warn: (message: string, data?: any) => void;
9
+ error: (message: string, data?: any) => void;
10
+ fatal: (message: string, data?: any) => void;
11
+ trace: (message: string, data?: any) => void;
12
+ [key: string]: any;
13
+ }
14
+
15
+ export interface LoggerComponents {
16
+ /**
17
+ * Component loggers - factory functions that ALWAYS return LoggerInstance
18
+ * Components return no-op logger if not initialized or unavailable
19
+ * Safe to call without null checks: components.reactComponents?.().info(...)
20
+ */
21
+ reactComponents?: () => LoggerInstance;
22
+ astroComponents?: () => LoggerInstance;
23
+ astroBuild?: () => LoggerInstance;
24
+ astroIntegration?: () => LoggerInstance;
25
+ contentProcessing?: () => LoggerInstance;
26
+ textUtils?: () => LoggerInstance;
27
+ dateUtils?: () => LoggerInstance;
28
+ pages?: () => LoggerInstance;
29
+ config?: () => LoggerInstance;
30
+ seo?: () => LoggerInstance;
31
+ performance?: () => LoggerInstance;
32
+ devServer?: () => LoggerInstance;
33
+ webComponents?: () => LoggerInstance;
34
+ core?: () => LoggerInstance;
35
+ api?: () => LoggerInstance;
36
+ ui?: () => LoggerInstance;
37
+ database?: () => LoggerInstance;
38
+ test?: () => LoggerInstance;
39
+ preact?: () => LoggerInstance;
40
+ auth?: () => LoggerInstance;
41
+ analytics?: () => LoggerInstance;
42
+ websocket?: () => LoggerInstance;
43
+ notification?: () => LoggerInstance;
44
+ router?: () => LoggerInstance;
45
+ cache?: () => LoggerInstance;
46
+ /**
47
+ * Dynamic component access - always returns a logger factory
48
+ * The factory function always returns LoggerInstance (no-op if unavailable)
49
+ */
50
+ [key: string]: (() => LoggerInstance) | undefined;
51
+ }
52
+
53
+ export interface JSGLoggerConfig {
54
+ configPath?: string;
55
+ config?: Record<string, any>;
56
+ devtools?: {
57
+ enabled?: boolean;
58
+ };
59
+ [key: string]: any;
60
+ }
61
+
62
+ export interface LoggerControls {
63
+ setLevel?: (component: string, level: string) => void;
64
+ getLevel?: (component: string) => string | undefined;
65
+ listComponents?: () => string[];
66
+ enableDebugMode?: () => void;
67
+ enableTraceMode?: () => void;
68
+ addFileOverride?: (filePath: string, overrideConfig: Record<string, any>) => void;
69
+ removeFileOverride?: (filePath: string) => void;
70
+ listFileOverrides?: () => string[];
71
+ setTimestampMode?: (mode: string) => void;
72
+ getTimestampMode?: () => string;
73
+ getTimestampModes?: () => string[];
74
+ setDisplayOption?: (option: string, enabled: boolean) => void;
75
+ getDisplayConfig?: () => Record<string, boolean>;
76
+ toggleDisplayOption?: (option: string) => void;
77
+ getStats?: () => any;
78
+ subscribe?: (callback: Function) => void;
79
+ clearLogs?: () => void;
80
+ getConfigSummary?: () => any;
81
+ setComponentLevel?: (component: string, level: string) => void;
82
+ getComponentLevel?: (component: string) => string | undefined;
83
+ enableDevPanel?: () => Promise<any>;
84
+ disableDevPanel?: () => boolean;
85
+ refresh?: () => void;
86
+ reset?: () => void;
87
+ [key: string]: any;
88
+ }
89
+
90
+ export interface LoggerConfig {
91
+ environment?: string;
92
+ components?: Record<string, any>;
93
+ summary?: any;
94
+ }
95
+
96
+ export interface LoggerInstanceType {
97
+ /**
98
+ * Direct access to component loggers
99
+ */
100
+ [componentName: string]: LoggerInstance | any;
101
+
102
+ /**
103
+ * Auto-discovery convenience getters (factory functions)
104
+ */
105
+ components?: LoggerComponents;
106
+
107
+ /**
108
+ * Get a specific component logger - always returns a logger instance
109
+ * Returns no-op logger if component unavailable or logger not initialized
110
+ * Always available - never undefined
111
+ */
112
+ getComponent: (componentName: string) => LoggerInstance;
113
+
114
+ /**
115
+ * Create a logger for a specific component
116
+ */
117
+ createLogger?: (componentName: string) => LoggerInstance;
118
+
119
+ /**
120
+ * Configuration and debugging info
121
+ */
122
+ config?: LoggerConfig;
123
+
124
+ /**
125
+ * Configuration manager instance
126
+ */
127
+ configManager?: any;
128
+
129
+ /**
130
+ * Log store instance
131
+ */
132
+ logStore?: any;
133
+
134
+ /**
135
+ * Enhanced runtime controls
136
+ */
137
+ controls?: LoggerControls;
138
+
139
+ /**
140
+ * Get singleton instance (async)
141
+ */
142
+ getInstance?: (config?: JSGLoggerConfig) => Promise<LoggerInstanceType> | LoggerInstanceType;
143
+
144
+ /**
145
+ * Get singleton instance (sync)
146
+ */
147
+ getInstanceSync?: (config?: JSGLoggerConfig) => LoggerInstanceType;
148
+
149
+ /**
150
+ * Static performance logging utility
151
+ */
152
+ logPerformance?: (label: string, startTime: number, component?: string) => Promise<number>;
153
+ }
154
+
155
+ export interface JSGLogger {
156
+ /**
157
+ * Get singleton instance with auto-initialization
158
+ * @param config - Initialization options (only used on first call)
159
+ * @returns Enhanced logger exports with controls API
160
+ *
161
+ * Note: Returns Promise if initialization is needed, sync value if already initialized.
162
+ * Use `await` to handle both cases safely.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * const logger = await JSGLogger.getInstance({ configPath: 'logger-config.json' });
167
+ * logger.components?.reactComponents?.().info('Hello');
168
+ * ```
169
+ */
170
+ getInstance(config?: JSGLoggerConfig): Promise<LoggerInstanceType> | LoggerInstanceType;
171
+
172
+ /**
173
+ * Get singleton instance synchronously (for environments without async support)
174
+ * @param config - Initialization options (only used on first call)
175
+ * @returns Enhanced logger exports with controls API
176
+ */
177
+ getInstanceSync(config?: JSGLoggerConfig): LoggerInstanceType;
178
+
179
+ /**
180
+ * Static performance logging utility
181
+ * @param label - Performance label
182
+ * @param startTime - Start time from performance.now()
183
+ * @param component - Optional component name (defaults to 'performance')
184
+ * @returns Duration in milliseconds
185
+ */
186
+ logPerformance(label: string, startTime: number, component?: string): Promise<number>;
187
+ }
188
+
189
+ declare const JSGLogger: JSGLogger;
190
+ export default JSGLogger;
191
+ export { JSGLogger };
192
+
package/index.js CHANGED
@@ -12,6 +12,7 @@ import {createBrowserFormatter} from './formatters/browser-formatter.js';
12
12
  import {createCLIFormatter} from './formatters/cli-formatter.js';
13
13
  import {createServerFormatter, getServerConfig} from './formatters/server-formatter.js';
14
14
  import {LogStore} from './stores/log-store.js';
15
+ import {metaLog, metaWarn, metaError} from './utils/meta-logger.js';
15
16
 
16
17
  // Check default config for devtools at module load time
17
18
  // This allows bundlers to tree-shake if disabled
@@ -23,19 +24,19 @@ const defaultDevtoolsEnabled = defaultConfig.devtools?.enabled ?? false;
23
24
  let devtoolsModule = null;
24
25
  let devtoolsModulePromise = null;
25
26
  if (defaultDevtoolsEnabled) {
26
- console.log('[JSG-LOGGER] DevTools module pre-loading started (default config enabled)');
27
+ metaLog('[JSG-LOGGER] DevTools module pre-loading started (default config enabled)');
27
28
  // Start loading immediately but don't await (non-blocking)
28
29
  // Bundlers can still analyze this static import for tree-shaking
29
30
  devtoolsModulePromise = import('./devtools/dist/panel-entry.js').then(module => {
30
31
  devtoolsModule = module;
31
- console.log('[JSG-LOGGER] DevTools module pre-loaded successfully');
32
+ metaLog('[JSG-LOGGER] DevTools module pre-loaded successfully');
32
33
  return module;
33
34
  }).catch(error => {
34
- console.error('[JSG-LOGGER] DevTools module pre-load failed:', error);
35
+ metaError('[JSG-LOGGER] DevTools module pre-load failed:', error);
35
36
  return null;
36
37
  });
37
38
  } else {
38
- console.log('[JSG-LOGGER] DevTools module NOT pre-loaded (default config disabled - will tree-shake)');
39
+ metaLog('[JSG-LOGGER] DevTools module NOT pre-loaded (default config disabled - will tree-shake)');
39
40
  }
40
41
 
41
42
  /**
@@ -113,7 +114,7 @@ class JSGLogger {
113
114
  */
114
115
  async init(options = {}) {
115
116
  try {
116
- console.log('[JSG-LOGGER] Initializing logger...', options.configPath ? `configPath: ${options.configPath}` : options.config ? 'inline config provided' : 'using defaults');
117
+ metaLog('[JSG-LOGGER] Initializing logger...', options.configPath ? `configPath: ${options.configPath}` : options.config ? 'inline config provided' : 'using defaults');
117
118
 
118
119
  // Load configuration FIRST (before environment detection)
119
120
  if (options.configPath || options.config) {
@@ -162,7 +163,12 @@ class JSGLogger {
162
163
 
163
164
  return this.getLoggerExports();
164
165
  } catch (error) {
165
- console.error('JSG Logger initialization failed:', error);
166
+ // Try to use actual logger if partially initialized, otherwise fallback to console
167
+ if (this.loggers?.core) {
168
+ this.loggers.core.error('JSG Logger initialization failed:', error);
169
+ } else {
170
+ console.error('JSG Logger initialization failed:', error);
171
+ }
166
172
  // Return minimal fallback logger
167
173
  return this.createFallbackLogger();
168
174
  }
@@ -232,7 +238,12 @@ class JSGLogger {
232
238
 
233
239
  return this.getLoggerExports();
234
240
  } catch (error) {
235
- console.error('JSG Logger sync initialization failed:', error);
241
+ // Try to use actual logger if partially initialized, otherwise fallback to console
242
+ if (this.loggers?.core) {
243
+ this.loggers.core.error('JSG Logger sync initialization failed:', error);
244
+ } else {
245
+ console.error('JSG Logger sync initialization failed:', error);
246
+ }
236
247
  // Return minimal fallback logger
237
248
  return this.createFallbackLogger();
238
249
  }
@@ -485,18 +496,22 @@ class JSGLogger {
485
496
 
486
497
  // DevTools panel controls
487
498
  enableDevPanel: async () => {
499
+ const devtoolsLogger = this.getComponent('devtools-ui');
500
+
488
501
  // Early config check - uses consumer's runtime config
489
502
  const runtimeDevtoolsEnabled = configManager.config.devtools?.enabled ?? false;
490
503
 
491
- console.log(`[JSG-LOGGER] enableDevPanel() called - runtime config: ${runtimeDevtoolsEnabled ? 'ENABLED' : 'DISABLED'}`);
504
+ devtoolsLogger.info('enableDevPanel() called', {
505
+ runtimeConfig: runtimeDevtoolsEnabled ? 'ENABLED' : 'DISABLED'
506
+ });
492
507
 
493
508
  if (!runtimeDevtoolsEnabled) {
494
- console.warn('[JSG-LOGGER] DevTools disabled via config. Set devtools.enabled: true to enable.');
509
+ devtoolsLogger.warn('DevTools disabled via config. Set devtools.enabled: true to enable.');
495
510
  return null;
496
511
  }
497
512
 
498
513
  if (typeof window === 'undefined') {
499
- console.warn('[JSG-LOGGER] DevTools panel only available in browser environments');
514
+ devtoolsLogger.warn('DevTools panel only available in browser environments');
500
515
  return null;
501
516
  }
502
517
 
@@ -505,44 +520,49 @@ class JSGLogger {
505
520
  if (!devtoolsModule) {
506
521
  // Check if we have a promise for pre-loading
507
522
  if (devtoolsModulePromise) {
508
- console.log('[JSG-LOGGER] Waiting for pre-loaded DevTools module...');
523
+ devtoolsLogger.info('Waiting for pre-loaded DevTools module...');
509
524
  // Wait for pre-load to complete
510
525
  devtoolsModule = await devtoolsModulePromise;
511
526
  } else {
512
527
  // Runtime config override: consumer enabled devtools but default was disabled
513
528
  // Load on demand via dynamic import
514
- console.log('[JSG-LOGGER] Loading DevTools module dynamically (runtime config override)...');
529
+ devtoolsLogger.info('Loading DevTools module dynamically (runtime config override)...');
515
530
  devtoolsModule = await import('./devtools/dist/panel-entry.js');
516
531
  }
517
532
  } else {
518
- console.log('[JSG-LOGGER] Using pre-loaded DevTools module');
533
+ devtoolsLogger.info('Using pre-loaded DevTools module');
519
534
  }
520
535
 
521
536
  if (!devtoolsModule || !devtoolsModule.initializePanel) {
522
537
  throw new Error('DevTools panel module missing initializePanel export');
523
538
  }
524
539
 
525
- console.log('[JSG-LOGGER] Initializing DevTools panel...');
540
+ devtoolsLogger.info('Initializing DevTools panel...');
526
541
  const panel = devtoolsModule.initializePanel();
527
- console.log('[JSG-LOGGER] DevTools panel initialized successfully');
542
+ devtoolsLogger.info('DevTools panel initialized successfully');
528
543
  return panel;
529
544
  } catch (error) {
530
- console.error('[JSG-LOGGER] Failed to load DevTools panel:', error);
531
- console.error('[JSG-LOGGER] If using npm link, ensure Vite config has: server.fs.allow: [\'..\']');
545
+ devtoolsLogger.error('Failed to load DevTools panel', { error: error.message, stack: error.stack });
546
+ devtoolsLogger.error('If using npm link, ensure Vite config has: server.fs.allow: [\'..\']');
532
547
  return null;
533
548
  }
534
549
  },
535
550
 
536
551
  disableDevPanel: () => {
552
+ const devtoolsLogger = this.getComponent('devtools-ui');
553
+
537
554
  if (typeof window !== 'undefined' && window.JSG_DevTools?.destroy) {
538
555
  window.JSG_DevTools.destroy();
539
- console.log('[JSG-LOGGER] DevTools panel disabled and destroyed');
556
+ devtoolsLogger.info('DevTools panel disabled and destroyed');
540
557
  return true;
541
558
  }
542
- console.warn('[JSG-LOGGER] DevTools panel not loaded or already destroyed');
559
+ devtoolsLogger.warn('DevTools panel not loaded or already destroyed');
543
560
  return false;
544
561
  },
545
562
 
563
+ // Project info
564
+ getProjectName: () => configManager.config.projectName || 'JSG Logger',
565
+
546
566
  // System controls
547
567
  refresh: () => this.refreshLoggers(),
548
568
  reset: () => {
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.7.0",
3
+ "version": "1.7.4",
4
4
  "type": "module",
5
5
  "description": "Multi-environment logger with smart detection, file-level overrides, and beautiful console formatting. Test it live: https://logger.joesangiorgio.com/",
6
6
  "main": "index.js",
7
+ "types": "./index.d.ts",
7
8
  "keywords": [
8
9
  "logging",
9
10
  "pino",
@@ -50,6 +51,7 @@
50
51
  },
51
52
  "files": [
52
53
  "index.js",
54
+ "index.d.ts",
53
55
  "config/",
54
56
  "formatters/",
55
57
  "stores/",
@@ -63,7 +65,11 @@
63
65
  "LICENSE"
64
66
  ],
65
67
  "exports": {
66
- ".": "./index.js",
68
+ ".": {
69
+ "import": "./index.js",
70
+ "require": "./index.js",
71
+ "types": "./index.d.ts"
72
+ },
67
73
  "./config": "./config/config-manager.js",
68
74
  "./config/manager": "./config/config-manager.js",
69
75
  "./config/schemes": "./config/component-schemes.js",
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Meta-Logger Utilities
3
+ * Handles logging about the logger itself BEFORE initialization (bootstrap logs only)
4
+ * Respects metaLogging config setting: true (show console logs), false (silent)
5
+ *
6
+ * IMPORTANT: Use meta-logger ONLY for pre-initialization logs. Once logger is initialized,
7
+ * use the actual logger with proper components for all logging.
8
+ */
9
+
10
+ import { configManager } from '../config/config-manager.js';
11
+
12
+ /**
13
+ * Meta log function - logs about the logger itself (BOOTSTRAP ONLY)
14
+ * @param {string} message - Log message
15
+ * @param {...any} args - Additional arguments
16
+ */
17
+ export const metaLog = (message, ...args) => {
18
+ try {
19
+ const metaLoggingConfig = configManager?.config?.metaLogging;
20
+
21
+ // If config not loaded yet or explicitly true, use console.log
22
+ if (metaLoggingConfig === undefined || metaLoggingConfig === true) {
23
+ console.log(message, ...args);
24
+ return;
25
+ }
26
+
27
+ // If explicitly false, stay silent
28
+ if (metaLoggingConfig === false) {
29
+ return;
30
+ }
31
+ } catch (error) {
32
+ // If anything fails, fall back to console.log
33
+ console.log(message, ...args);
34
+ }
35
+ };
36
+
37
+ /**
38
+ * Meta warn function - warnings about the logger itself (BOOTSTRAP ONLY)
39
+ * @param {string} message - Warning message
40
+ * @param {...any} args - Additional arguments
41
+ */
42
+ export const metaWarn = (message, ...args) => {
43
+ try {
44
+ const metaLoggingConfig = configManager?.config?.metaLogging;
45
+
46
+ if (metaLoggingConfig === undefined || metaLoggingConfig === true) {
47
+ console.warn(message, ...args);
48
+ return;
49
+ }
50
+
51
+ if (metaLoggingConfig === false) {
52
+ return;
53
+ }
54
+ } catch (error) {
55
+ console.warn(message, ...args);
56
+ }
57
+ };
58
+
59
+ /**
60
+ * Meta error function - errors about the logger itself (BOOTSTRAP ONLY)
61
+ * @param {string} message - Error message
62
+ * @param {...any} args - Additional arguments
63
+ */
64
+ export const metaError = (message, ...args) => {
65
+ try {
66
+ const metaLoggingConfig = configManager?.config?.metaLogging;
67
+
68
+ if (metaLoggingConfig === undefined || metaLoggingConfig === true) {
69
+ console.error(message, ...args);
70
+ return;
71
+ }
72
+
73
+ if (metaLoggingConfig === false) {
74
+ return;
75
+ }
76
+ } catch (error) {
77
+ console.error(message, ...args);
78
+ }
79
+ };
80
+