@crimsonsunset/jsg-logger 1.0.9 → 1.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.
@@ -14,9 +14,9 @@
14
14
 
15
15
  ---
16
16
 
17
- **Date:** August 6, 2025
18
- **Session Goal:** 🎯 **COMPLETE** - Logger extraction, NPM publication, and documentation structure
19
- **Next Session Goal:** 🎨 **DevTools Panel Implementation** - Browser-based log filtering interface (optional enhancement)
17
+ **Date:** August 21, 2025
18
+ **Session Goal:** 🚀 **API Enhancement - Phase 8** - Eliminate boilerplate code for projects using JSG Logger
19
+ **Status:** 🔄 **IN PROGRESS** - Core enhancements implemented, testing & publishing remain
20
20
 
21
21
  ## 🎉 MAJOR ACCOMPLISHMENTS THIS SESSION
22
22
 
@@ -61,21 +61,35 @@
61
61
  - **Clean Integration** - DeskThing-Apps migration successful
62
62
  - **Documentation Complete** - All standard files in place
63
63
 
64
- ## 📋 CURRENT PRIORITIES
65
-
66
- ### **No Immediate Tasks**
67
- - **Logger is feature complete** - Core functionality fully implemented
68
- - **Documentation structure complete** - All standard files added
69
- - **NPM package stable** - Version 1.0.6 published and working
70
-
71
- ### **Optional Future Enhancements** (Low Priority)
72
- - [ ] **DevTools Panel** - Browser-based log filtering interface
73
- - Runtime-injected widget with Preact
74
- - Collapsible sidebar from left side
75
- - Controls console filtering without displaying logs
76
- - IndexedDB persistence for panel state
64
+ ## 📋 CURRENT PRIORITIES - PHASE 8 API ENHANCEMENT
65
+
66
+ ### **🎯 Primary Goal: Eliminate Project Boilerplate** 🔄 IN PROGRESS
67
+ **Problem**: Projects need ~220 lines of boilerplate code to use JSG Logger effectively
68
+ **Solution**: Build essential patterns directly into the JSG Logger package
69
+
70
+ ### **✅ COMPLETED THIS SESSION:**
71
+ - [x] **Static Singleton Pattern** - `CACPLogger.getInstance()` methods
72
+ - [x] **Auto-Discovery Getters** - Both camelCase and kebab-case component access
73
+ - [x] **Non-Destructive Error Handling** - Missing components log but don't break
74
+ - [x] **Static Performance Logging** - `CACPLogger.logPerformance()` utility
75
+ - [x] **Enhanced Export Structure** - Components and getComponent available
76
+
77
+ ### **🔄 REMAINING TASKS:**
78
+ - [ ] **Complete Export Structure** - Ensure static methods accessible
79
+ - [ ] **Version Bump** - Update to 1.1.0 (minor for new features)
80
+ - [ ] **NPM Publish** - Deploy enhanced package
81
+ - [ ] **Test Integration** - Validate simplified project usage
82
+ - [ ] **Update README** - Document new API patterns
83
+
84
+ ### **📊 Expected Impact:**
85
+ - **Project boilerplate**: 220 lines → 15 lines (93% reduction)
86
+ - **Initialization**: Complex setup → Single `getInstance()` call
87
+ - **Component access**: Manual mapping → Auto-discovery with both naming conventions
88
+ - **Performance logging**: Custom utilities → Built-in static method
89
+
90
+ ### **🚀 Next Steps After Completion:**
91
+ - [ ] **DevTools Panel** - Browser-based log filtering interface (Phase 6)
77
92
  - [ ] **Performance Monitoring** - Track logging overhead metrics
78
- - [ ] **Export Utilities** - Save logs to file formats
79
93
  - [ ] **Framework Integration Guides** - React, Vue, Svelte examples
80
94
 
81
95
  ## 🔧 Technical Notes
package/docs/roadmap.md CHANGED
@@ -390,10 +390,156 @@ Console filtering updates
390
390
 
391
391
  ## 🎯 Next Steps
392
392
 
393
- ### **Immediate Priorities**
394
- - None - logger is feature complete and stable
393
+ ### **Phase 8: API Enhancement for Project Simplification** 🚀 IN PROGRESS
394
+ **Goal**: Eliminate boilerplate code that every project needs to implement when using JSG Logger
395
395
 
396
- ### **Optional Enhancements**
396
+ #### **Background - The Problem**
397
+ Projects using JSG Logger currently need to implement ~220 lines of boilerplate:
398
+ - Singleton/caching patterns
399
+ - Component logger getters with fallback handling
400
+ - Performance logging utilities
401
+ - Auto-discovery of available components
402
+ - Error handling when components don't exist
403
+
404
+ **This defeats the purpose of having a reusable logger package.**
405
+
406
+ #### **Solution - Built-in Enhancement Features**
407
+
408
+ **✅ Design Decisions Made:**
409
+ 1. **getInstance location**: Static on CACPLogger class
410
+ 2. **Auto-discovery naming**: Both camelCase and kebab-case support
411
+ 3. **Performance logging**: Static utility `JSGLogger.logPerformance(...)`
412
+ 4. **Error handling**: Non-destructive with helpful logging (no fallbacks)
413
+ 5. **Config auto-discovery**: Strict mode - only configured components work
414
+ 6. **Getter creation**: Eagerly during init (not lazy)
415
+
416
+ #### **🔧 Implementation Plan**
417
+
418
+ ##### **Enhancement 1: Static Singleton Pattern**
419
+ ```javascript
420
+ // Static method on CACPLogger class
421
+ const logger = CACPLogger.getInstance(config);
422
+ const logger2 = CACPLogger.getInstance(); // Same instance, no config needed
423
+ ```
424
+
425
+ **Implementation Location**: `index.js` CACPLogger class
426
+ - Add `static _instance = null`
427
+ - Add `static async getInstance(options = {})`
428
+ - Add `static getInstanceSync(options = {})` for sync environments
429
+
430
+ ##### **Enhancement 2: Auto-Discovery Component Getters**
431
+ ```javascript
432
+ // From config: { "components": { "astro-build": {}, "react-components": {} }}
433
+
434
+ // Both naming conventions work:
435
+ logger.components.astroBuild() // camelCase convenience
436
+ logger.components['astro-build']() // original kebab-case
437
+ logger.components.reactComponents() // camelCase
438
+ logger.components['react-components']() // kebab-case
439
+
440
+ // Plus explicit method
441
+ logger.getComponent('astro-build')
442
+ ```
443
+
444
+ **Implementation**:
445
+ - Add `this.components = {}` to constructor
446
+ - Add `_createAutoDiscoveryGetters()` method - called eagerly during init
447
+ - Create getters for both kebab-case and camelCase from config components
448
+ - Add to `getLoggerExports()` return object
449
+
450
+ ##### **Enhancement 3: Non-Destructive Component Access**
451
+ ```javascript
452
+ // If 'missing-component' not in config:
453
+ const missingLogger = logger.getComponent('missing-component');
454
+ // Logs: "Component 'missing-component' not found. Available: astro-build, react-components"
455
+ // Returns: Logger that outputs error context but doesn't break
456
+
457
+ missingLogger.info('test');
458
+ // Outputs: "[MISSING-COMPONENT] ⚠️ Component not configured - test"
459
+ ```
460
+
461
+ **Implementation**:
462
+ - Add `getComponent(componentName)` method
463
+ - Add `_createErrorLogger(componentName)` helper
464
+ - Error prefix: `[COMPONENT-NAME] ⚠️ Component not configured -`
465
+ - Strict mode: Only configured components, log missing ones
466
+
467
+ ##### **Enhancement 4: Static Performance Logging**
468
+ ```javascript
469
+ const startTime = performance.now();
470
+ // ... do work ...
471
+ JSGLogger.logPerformance('Page Generation', startTime, 'astro-build');
472
+ // Auto-thresholds: >1000ms = warn, >100ms = info, else = debug
473
+ ```
474
+
475
+ **Implementation**:
476
+ - Add `static async logPerformance(operation, startTime, component = 'performance')`
477
+ - Auto-getInstance() - no manual initialization required
478
+ - Built-in performance thresholds and formatting
479
+ - Fallback to console if logger fails
480
+
481
+ #### **🎯 Result - Dramatically Simplified Project Usage**
482
+
483
+ **Before Enhancement** (220+ lines of boilerplate):
484
+ ```typescript
485
+ // Complex singleton pattern, fallback handling, component getters, etc.
486
+ let loggerInstance: any = null;
487
+ // ... 200+ lines of infrastructure code ...
488
+ ```
489
+
490
+ **After Enhancement** (15-20 lines):
491
+ ```typescript
492
+ import JSGLogger from '@crimsonsunset/jsg-logger';
493
+
494
+ const logger = JSGLogger.getInstance({
495
+ configPath: './logger-config.json'
496
+ });
497
+
498
+ // Optional project-specific convenience exports
499
+ export const loggers = {
500
+ build: logger.components.astroBuild,
501
+ react: logger.components.reactComponents,
502
+ textUtils: logger.components.textUtils
503
+ };
504
+
505
+ export { logger, JSGLogger };
506
+ ```
507
+
508
+ #### **📋 Implementation Checklist**
509
+
510
+ **✅ COMPLETED:**
511
+ - [x] Added static `_instance` property and `getInstance()` methods
512
+ - [x] Added `_createAutoDiscoveryGetters()` calls to init/initSync
513
+ - [x] Implemented `_createAutoDiscoveryGetters()` with both naming conventions
514
+ - [x] Implemented `getComponent()` with non-destructive error handling
515
+ - [x] Implemented `_createErrorLogger()` with proper error messaging
516
+ - [x] Added static `logPerformance()` with auto-getInstance
517
+ - [x] Updated `getLoggerExports()` to include components and getComponent
518
+
519
+ **🔄 IN PROGRESS:**
520
+ - [ ] Complete export structure for static methods
521
+ - [ ] Version bump and publish to NPM
522
+ - [ ] Test new API with simplified project integration
523
+ - [ ] Update project files to use new simplified API
524
+
525
+ **📊 Expected Outcome:**
526
+ - **Project boilerplate reduced**: 220 lines → 15 lines (93% reduction)
527
+ - **API simplification**: Single `getInstance()` call vs complex initialization
528
+ - **Auto-discovery**: No manual component mapping required
529
+ - **Non-destructive errors**: Missing components log but don't break apps
530
+ - **Built-in utilities**: Performance logging included
531
+
532
+ #### **🚀 Next Implementation Steps**
533
+ 1. Complete JSG Logger package enhancements
534
+ 2. Bump version to 1.1.0 (minor version for new features)
535
+ 3. Publish updated package to NPM
536
+ 4. Update jsg-tech-check-site to use simplified API
537
+ 5. Test and validate 93% boilerplate reduction
538
+ 6. Document new API in README examples
539
+
540
+ ---
541
+
542
+ ### **Previous Optional Enhancements** (Lower Priority)
397
543
  - **DevTools Panel** - Browser interface for log filtering
398
544
  - **Performance Monitoring** - Track logging overhead
399
545
  - **Framework Guides** - React, Vue, Svelte integration examples
package/index.js CHANGED
@@ -18,11 +18,41 @@ import {LogStore} from './stores/log-store.js';
18
18
  * Manages logger instances and provides the public API
19
19
  */
20
20
  class CACPLogger {
21
+ // Static singleton instance
22
+ static _instance = null;
23
+
21
24
  constructor() {
22
25
  this.loggers = {};
23
26
  this.logStore = new LogStore();
24
27
  this.environment = getEnvironment();
25
28
  this.initialized = false;
29
+ this.components = {}; // Auto-discovery getters
30
+ }
31
+
32
+ /**
33
+ * Get singleton instance with auto-initialization
34
+ * @param {Object} options - Initialization options (only used on first call)
35
+ * @returns {Promise<CACPLogger>} Singleton logger instance
36
+ */
37
+ static async getInstance(options = {}) {
38
+ if (!CACPLogger._instance) {
39
+ CACPLogger._instance = new CACPLogger();
40
+ await CACPLogger._instance.init(options);
41
+ }
42
+ return CACPLogger._instance;
43
+ }
44
+
45
+ /**
46
+ * Get singleton instance synchronously (for environments without async support)
47
+ * @param {Object} options - Initialization options (only used on first call)
48
+ * @returns {CACPLogger} Singleton logger instance
49
+ */
50
+ static getInstanceSync(options = {}) {
51
+ if (!CACPLogger._instance) {
52
+ CACPLogger._instance = new CACPLogger();
53
+ CACPLogger._instance.initSync(options);
54
+ }
55
+ return CACPLogger._instance;
26
56
  }
27
57
 
28
58
  /**
@@ -50,6 +80,9 @@ class CACPLogger {
50
80
  // Add utility methods
51
81
  this.addUtilityMethods();
52
82
 
83
+ // Create auto-discovery getters (eager)
84
+ this._createAutoDiscoveryGetters();
85
+
53
86
  this.initialized = true;
54
87
 
55
88
  // Log initialization success
@@ -90,6 +123,9 @@ class CACPLogger {
90
123
  // Add utility methods
91
124
  this.addUtilityMethods();
92
125
 
126
+ // Create auto-discovery getters (eager)
127
+ this._createAutoDiscoveryGetters();
128
+
93
129
  this.initialized = true;
94
130
 
95
131
  // Log initialization success
@@ -181,6 +217,12 @@ class CACPLogger {
181
217
  // All component loggers
182
218
  ...this.loggers,
183
219
 
220
+ // Auto-discovery convenience getters (kebab-case and camelCase)
221
+ components: this.components,
222
+
223
+ // Component getter with error handling
224
+ getComponent: (componentName) => this.getComponent(componentName),
225
+
184
226
  // Utility methods
185
227
  createLogger: (componentName) => {
186
228
  if (!this.loggers[componentName]) {
@@ -219,12 +261,18 @@ class CACPLogger {
219
261
  listComponents: () => Object.keys(this.loggers),
220
262
  enableDebugMode: () => {
221
263
  Object.keys(this.loggers).forEach(component => {
222
- this.controls.setLevel(component, 'debug');
264
+ if (this.loggers[component]) {
265
+ this.loggers[component].level = 'debug';
266
+ this.loggers[component]._effectiveLevel = 'debug';
267
+ }
223
268
  });
224
269
  },
225
270
  enableTraceMode: () => {
226
271
  Object.keys(this.loggers).forEach(component => {
227
- this.controls.setLevel(component, 'trace');
272
+ if (this.loggers[component]) {
273
+ this.loggers[component].level = 'trace';
274
+ this.loggers[component]._effectiveLevel = 'trace';
275
+ }
228
276
  });
229
277
  },
230
278
 
@@ -394,6 +442,99 @@ class CACPLogger {
394
442
  }
395
443
  };
396
444
  }
445
+
446
+ /**
447
+ * Create auto-discovery getters for easy component access
448
+ * Supports both kebab-case (original) and camelCase naming
449
+ * @private
450
+ */
451
+ _createAutoDiscoveryGetters() {
452
+ this.components = {};
453
+
454
+ Object.keys(this.loggers).forEach(name => {
455
+ // Original kebab-case name
456
+ this.components[name] = () => this.getComponent(name);
457
+
458
+ // camelCase convenience getter
459
+ const camelName = name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
460
+ if (camelName !== name) {
461
+ this.components[camelName] = () => this.getComponent(name);
462
+ }
463
+ });
464
+ }
465
+
466
+ /**
467
+ * Get a specific component logger with non-destructive error handling
468
+ * @param {string} componentName - Component name to retrieve
469
+ * @returns {Object} Logger instance or error-context logger
470
+ */
471
+ getComponent(componentName) {
472
+ if (!this.loggers[componentName]) {
473
+ const available = Object.keys(this.loggers).join(', ');
474
+
475
+ // Log the error using the config logger if available
476
+ if (this.loggers.config) {
477
+ this.loggers.config.warn(`Component '${componentName}' not found. Available: ${available}`);
478
+ } else {
479
+ console.warn(`[JSG-LOGGER] Component '${componentName}' not found. Available: ${available}`);
480
+ }
481
+
482
+ // Return non-destructive error logger
483
+ return this._createErrorLogger(componentName);
484
+ }
485
+
486
+ return this.loggers[componentName];
487
+ }
488
+
489
+ /**
490
+ * Create error-context logger that doesn't break the app
491
+ * @param {string} componentName - Name of the missing component
492
+ * @returns {Object} Logger with error context in all messages
493
+ * @private
494
+ */
495
+ _createErrorLogger(componentName) {
496
+ const prefix = `[${componentName.toUpperCase()}]`;
497
+ const errorMsg = '⚠️ Component not configured -';
498
+
499
+ return {
500
+ trace: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
501
+ debug: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
502
+ info: (msg, ...args) => console.info(`${prefix} ${errorMsg}`, msg, ...args),
503
+ warn: (msg, ...args) => console.warn(`${prefix} ${errorMsg}`, msg, ...args),
504
+ error: (msg, ...args) => console.error(`${prefix} ${errorMsg}`, msg, ...args),
505
+ fatal: (msg, ...args) => console.error(`${prefix} ${errorMsg}`, msg, ...args)
506
+ };
507
+ }
508
+
509
+ /**
510
+ * Static utility for performance logging with auto-getInstance
511
+ * @param {string} operation - Description of the operation being measured
512
+ * @param {number} startTime - Start time from performance.now()
513
+ * @param {string} component - Component name for logging (defaults to 'performance')
514
+ * @returns {number} Duration in milliseconds
515
+ */
516
+ static async logPerformance(operation, startTime, component = 'performance') {
517
+ try {
518
+ const instance = await CACPLogger.getInstance();
519
+ const logger = instance.getComponent(component);
520
+ const duration = performance.now() - startTime;
521
+
522
+ if (duration > 1000) {
523
+ logger.warn(`${operation} took ${duration.toFixed(2)}ms (slow)`);
524
+ } else if (duration > 100) {
525
+ logger.info(`${operation} took ${duration.toFixed(2)}ms`);
526
+ } else {
527
+ logger.debug(`${operation} took ${duration.toFixed(2)}ms (fast)`);
528
+ }
529
+
530
+ return duration;
531
+ } catch (error) {
532
+ // Fallback to console if logger fails
533
+ const duration = performance.now() - startTime;
534
+ console.log(`[${component.toUpperCase()}] ${operation} took ${duration.toFixed(2)}ms`);
535
+ return duration;
536
+ }
537
+ }
397
538
  }
398
539
 
399
540
  // Create singleton instance
@@ -408,6 +549,12 @@ if (isBrowser() && typeof window !== 'undefined') {
408
549
  window.CACP_Logger = enhancedLoggers.controls;
409
550
  }
410
551
 
411
- // Export both the initialized loggers and the init function for advanced usage
552
+ // Add static methods to the enhanced loggers for convenience
553
+ enhancedLoggers.getInstance = CACPLogger.getInstance;
554
+ enhancedLoggers.getInstanceSync = CACPLogger.getInstanceSync;
555
+ enhancedLoggers.logPerformance = CACPLogger.logPerformance;
556
+ enhancedLoggers.CACPLogger = CACPLogger;
557
+
558
+ // Export both the initialized loggers and the class for advanced usage
412
559
  export default enhancedLoggers;
413
560
  export {logger as CACPLogger};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "JSG Logger - Multi-environment logger with smart detection, file-level overrides, and beautiful console formatting",
6
6
  "main": "index.js",