@crimsonsunset/jsg-logger 1.1.1 โ†’ 1.1.2

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.
@@ -24,26 +24,18 @@ export class ConfigManager {
24
24
  let externalConfig = {};
25
25
 
26
26
  if (typeof configSource === 'string') {
27
- // Load from file path
28
- if (configSource.startsWith('./') || configSource.startsWith('../')) {
29
- // Relative path - attempt to load
30
- try {
31
- const response = await fetch(configSource);
32
- if (response.ok) {
33
- externalConfig = await response.json();
34
- this.loadedPaths.push(configSource);
35
- }
36
- } catch (error) {
37
- console.warn(`Failed to load config from ${configSource}:`, error.message);
38
- }
39
- }
27
+ // Load from file path - handle all path formats
28
+ externalConfig = await this._loadConfigFromPath(configSource);
40
29
  } else if (typeof configSource === 'object') {
41
30
  // Direct config object
42
31
  externalConfig = configSource;
43
32
  }
44
33
 
45
- // Merge configurations
46
- this.config = this.mergeConfigs(this.config, externalConfig);
34
+ // Normalize external config to match expected structure
35
+ const normalizedConfig = this._normalizeConfigStructure(externalConfig);
36
+
37
+ // Merge configurations - project configs override defaults
38
+ this.config = this.mergeConfigs(this.config, normalizedConfig);
47
39
 
48
40
  return this.config;
49
41
  } catch (error) {
@@ -52,6 +44,255 @@ export class ConfigManager {
52
44
  }
53
45
  }
54
46
 
47
+ /**
48
+ * Load configuration from a file path with environment detection
49
+ * @param {string} configPath - File path to load
50
+ * @returns {Promise<Object>} Configuration object
51
+ * @private
52
+ */
53
+ async _loadConfigFromPath(configPath) {
54
+ try {
55
+ // Normalize path - add ./ prefix if missing for relative paths
56
+ const normalizedPath = this._normalizePath(configPath);
57
+
58
+ // Try different loading strategies based on environment
59
+ let config = null;
60
+
61
+ // Strategy 1: Browser environment with fetch
62
+ if (typeof window !== 'undefined' && typeof fetch !== 'undefined') {
63
+ config = await this._loadConfigBrowser(normalizedPath);
64
+ }
65
+
66
+ // Strategy 2: Node.js environment with dynamic import
67
+ if (!config && typeof process !== 'undefined') {
68
+ config = await this._loadConfigNode(normalizedPath);
69
+ }
70
+
71
+ // Strategy 3: Fallback browser import (for bundlers like Vite)
72
+ if (!config && typeof window !== 'undefined') {
73
+ config = await this._loadConfigBrowserImport(normalizedPath);
74
+ }
75
+
76
+ if (config) {
77
+ this.loadedPaths.push(configPath);
78
+ console.log(`[JSG-LOGGER] Successfully loaded config from: ${configPath}`);
79
+ return config;
80
+ } else {
81
+ console.warn(`[JSG-LOGGER] Could not load config from: ${configPath} - using defaults`);
82
+ return {};
83
+ }
84
+ } catch (error) {
85
+ console.warn(`[JSG-LOGGER] Failed to load config from ${configPath}:`, error.message);
86
+ return {};
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Normalize file path for consistent handling
92
+ * @param {string} path - Original path
93
+ * @returns {string} Normalized path
94
+ * @private
95
+ */
96
+ _normalizePath(path) {
97
+ // Add ./ prefix for relative paths that don't have it
98
+ if (!path.startsWith('./') && !path.startsWith('../') && !path.startsWith('/')) {
99
+ return `./${path}`;
100
+ }
101
+ return path;
102
+ }
103
+
104
+ /**
105
+ * Load config in browser environment using fetch
106
+ * @param {string} path - File path
107
+ * @returns {Promise<Object|null>} Configuration object or null
108
+ * @private
109
+ */
110
+ async _loadConfigBrowser(path) {
111
+ try {
112
+ const response = await fetch(path);
113
+ if (response.ok) {
114
+ return await response.json();
115
+ }
116
+ return null;
117
+ } catch (error) {
118
+ return null;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Load config in Node.js environment
124
+ * @param {string} path - File path
125
+ * @returns {Promise<Object|null>} Configuration object or null
126
+ * @private
127
+ */
128
+ async _loadConfigNode(path) {
129
+ try {
130
+ // Try dynamic import first (works with ES modules)
131
+ const module = await import(path, { assert: { type: 'json' } });
132
+ return module.default || module;
133
+ } catch (error) {
134
+ try {
135
+ // Fallback to fs.readFile for broader compatibility
136
+ const fs = await import('fs/promises');
137
+ const fileContent = await fs.readFile(path, 'utf-8');
138
+ return JSON.parse(fileContent);
139
+ } catch (fsError) {
140
+ return null;
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Load config in browser using dynamic import (for bundlers)
147
+ * @param {string} path - File path
148
+ * @returns {Promise<Object|null>} Configuration object or null
149
+ * @private
150
+ */
151
+ async _loadConfigBrowserImport(path) {
152
+ try {
153
+ // Some bundlers can handle dynamic imports of JSON files
154
+ const module = await import(path);
155
+ return module.default || module;
156
+ } catch (error) {
157
+ return null;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Normalize config structure to handle different field naming conventions
163
+ * @param {Object} config - Raw configuration object
164
+ * @returns {Object} Normalized configuration
165
+ * @private
166
+ */
167
+ _normalizeConfigStructure(config) {
168
+ const normalized = {...config};
169
+
170
+ // Handle displayOptions -> display mapping
171
+ if (config.displayOptions && !config.display) {
172
+ normalized.display = this._mapDisplayOptions(config.displayOptions);
173
+ delete normalized.displayOptions;
174
+ }
175
+
176
+ // Handle environment-specific configurations
177
+ if (config.environments) {
178
+ // For now, just log that environment configs exist
179
+ // TODO: Implement environment-based config selection
180
+ console.log(`[JSG-LOGGER] Found environment configs for: ${Object.keys(config.environments).join(', ')}`);
181
+ }
182
+
183
+ // Normalize component configurations
184
+ if (config.components) {
185
+ normalized.components = this._normalizeComponents(config.components);
186
+ }
187
+
188
+ return normalized;
189
+ }
190
+
191
+ /**
192
+ * Map displayOptions to display format
193
+ * @param {Object} displayOptions - Original display options
194
+ * @returns {Object} Normalized display configuration
195
+ * @private
196
+ */
197
+ _mapDisplayOptions(displayOptions) {
198
+ return {
199
+ timestamp: displayOptions.showTimestamp ?? true,
200
+ emoji: true, // Always enabled for JSG Logger
201
+ component: displayOptions.showComponent ?? true,
202
+ level: displayOptions.showLevel ?? false,
203
+ message: true, // Always enabled
204
+ jsonPayload: true, // Default enabled
205
+ stackTrace: true, // Default enabled
206
+ environment: displayOptions.showEnvironment ?? false
207
+ };
208
+ }
209
+
210
+ /**
211
+ * Normalize component configurations
212
+ * @param {Object} components - Raw component config
213
+ * @returns {Object} Normalized component config
214
+ * @private
215
+ */
216
+ _normalizeComponents(components) {
217
+ const normalized = {};
218
+
219
+ for (const [name, config] of Object.entries(components)) {
220
+ normalized[name] = {
221
+ emoji: config.emoji || this._getDefaultEmoji(name),
222
+ color: config.color || this._getDefaultColor(name),
223
+ name: config.name || this._formatComponentName(name),
224
+ level: config.level || 'info',
225
+ enabled: config.enabled ?? true,
226
+ description: config.description // Preserve description for documentation
227
+ };
228
+ }
229
+
230
+ return normalized;
231
+ }
232
+
233
+ /**
234
+ * Get default emoji for component
235
+ * @param {string} componentName - Component name
236
+ * @returns {string} Default emoji
237
+ * @private
238
+ */
239
+ _getDefaultEmoji(componentName) {
240
+ const emojiMap = {
241
+ 'astro-build': '๐Ÿš€',
242
+ 'astro-integration': 'โš™๏ธ',
243
+ 'content-processing': '๐Ÿ“',
244
+ 'text-utils': '๐Ÿ“„',
245
+ 'date-utils': '๐Ÿ“…',
246
+ 'react-components': 'โš›๏ธ',
247
+ 'astro-components': '๐ŸŒŸ',
248
+ 'pages': '๐Ÿ“„',
249
+ 'config': 'โš™๏ธ',
250
+ 'seo': '๐Ÿ”',
251
+ 'performance': 'โšก',
252
+ 'dev-server': '๐Ÿ› ๏ธ'
253
+ };
254
+
255
+ return emojiMap[componentName] || '๐ŸŽฏ';
256
+ }
257
+
258
+ /**
259
+ * Get default color for component
260
+ * @param {string} componentName - Component name
261
+ * @returns {string} Default color
262
+ * @private
263
+ */
264
+ _getDefaultColor(componentName) {
265
+ const colorMap = {
266
+ 'astro-build': '#FF5D01',
267
+ 'astro-integration': '#4A90E2',
268
+ 'content-processing': '#00C896',
269
+ 'text-utils': '#9B59B6',
270
+ 'date-utils': '#3498DB',
271
+ 'react-components': '#61DAFB',
272
+ 'astro-components': '#FF5D01',
273
+ 'pages': '#2ECC71',
274
+ 'config': '#95A5A6',
275
+ 'seo': '#E74C3C',
276
+ 'performance': '#F39C12',
277
+ 'dev-server': '#8E44AD'
278
+ };
279
+
280
+ return colorMap[componentName] || '#4A90E2';
281
+ }
282
+
283
+ /**
284
+ * Format component name for display
285
+ * @param {string} componentName - Raw component name
286
+ * @returns {string} Formatted display name
287
+ * @private
288
+ */
289
+ _formatComponentName(componentName) {
290
+ return componentName
291
+ .split('-')
292
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
293
+ .join('');
294
+ }
295
+
55
296
  /**
56
297
  * Set current file context for override resolution
57
298
  * @param {string} filePath - Current file path being logged from
package/docs/roadmap.md CHANGED
@@ -21,9 +21,9 @@
21
21
 
22
22
  ## ๐ŸŽฏ Current Status
23
23
  **Last Updated:** August 21, 2025
24
- **Current Phase:** Phase 8 Complete - API Enhancement Success
25
- **Status:** โœ… **ENHANCED & SIMPLIFIED** - v1.1.0 eliminates project boilerplate with 82% reduction
26
- **Next Session Goal:** Phase 6 - DevTools Panel implementation (optional enhancement)
24
+ **Current Phase:** Phase 9 - Genericize Logger (Remove CACP Hardcoding)
25
+ **Status:** ๐Ÿš€ **IN PROGRESS** - Making JSG Logger truly generic by removing CACP-specific hardcoded components
26
+ **Current Issue:** Logger still loads CACP defaults instead of project-specific `logger-config.json` files
27
27
 
28
28
  ### Progress Overview
29
29
  - โœ… **COMPLETED:** Multi-environment logger with smart detection
@@ -339,6 +339,19 @@ Console filtering updates
339
339
 
340
340
  ## ๐Ÿ“ˆ Recent Progress
341
341
 
342
+ ### August 21, 2025 - Phase 9 Discovery: CACP Hardcoding Issues ๐Ÿ”
343
+ - ๐Ÿ› **Critical Discovery**: JSG Logger still deeply hardcoded for CACP use cases
344
+ - ๐Ÿ” **Issue Identified**: `logger-config.json` files being ignored, falling back to CACP defaults
345
+ - ๐Ÿ“‹ **Root Causes Documented**: 6 major areas requiring genericization
346
+ 1. `CACPLogger` class name and all references
347
+ 2. Default config with 10 hardcoded CACP components
348
+ 3. Component schemes duplication
349
+ 4. Hardcoded legacy aliases for CACP components
350
+ 5. Core component dependency on 'cacp' logger
351
+ 6. Config loading path resolution issues
352
+ - ๐ŸŽฏ **Phase 9 Planned**: Complete roadmap for making logger truly generic
353
+ - โœ… **Testing Successful**: JSG Logger v1.1.0 API features work, but components wrong
354
+
342
355
  ### August 21, 2025 - Phase 8 API Enhancement Complete โœ…
343
356
  - โœ… **JSG Logger v1.1.0** - Major API simplification enhancements shipped
344
357
  - โœ… **Static Singleton Pattern** - `CACPLogger.getInstance()` with auto-initialization
@@ -403,7 +416,7 @@ Console filtering updates
403
416
 
404
417
  ## ๐ŸŽฏ Next Steps
405
418
 
406
- ### **Phase 8: API Enhancement for Project Simplification** ๐Ÿš€ IN PROGRESS
419
+ ### **Phase 8: API Enhancement for Project Simplification** โœ… COMPLETED
407
420
  **Goal**: Eliminate boilerplate code that every project needs to implement when using JSG Logger
408
421
 
409
422
  #### **Background - The Problem**
@@ -553,6 +566,142 @@ export { logger, JSGLogger };
553
566
  5. Test and validate 93% boilerplate reduction
554
567
  6. Document new API in README examples
555
568
 
569
+ #### **๐ŸŽฏ Actual Impact Achieved**
570
+ - โœ… **82% Boilerplate Reduction**: 220 lines โ†’ 40 lines in jsg-tech-check-site
571
+ - โœ… **Version Published**: JSG Logger v1.1.0 live on NPM
572
+ - โœ… **All Features Working**: Singleton pattern, auto-discovery, performance logging, non-destructive errors
573
+ - โœ… **Build Integration**: Works in both Astro build-time and client-side contexts
574
+
575
+ ---
576
+
577
+ ### **Phase 9: Genericize Logger (Remove CACP Hardcoding)** ๐Ÿš€ IN PROGRESS
578
+ **Goal**: Make JSG Logger truly generic by removing all CACP-specific hardcoded components and references
579
+
580
+ #### **Background - The Problem**
581
+ During Phase 8 integration testing with jsg-tech-check-site, we discovered the logger is still deeply hardcoded for CACP (Chrome Audio Control Panel) use cases:
582
+
583
+ **Observable Issues:**
584
+ ```
585
+ [JSG-LOGGER] Component 'astro-build' not found. Available: cacp, soundcloud, youtube, site-detector, websocket, popup, background, priority-manager, settings, test, siteDetector, priorityManager
586
+ ```
587
+
588
+ Despite providing a proper `logger-config.json` with Astro-specific components, the logger falls back to CACP defaults instead of loading the project's configuration.
589
+
590
+ #### **Root Causes - What Makes It CACP-Specific**
591
+
592
+ ##### **1. Class Name & Core References**
593
+ - `CACPLogger` class name should be `JSGLogger` or `GenericLogger`
594
+ - All static method references (`CACPLogger.getInstance()`, etc.)
595
+ - Error messages mentioning "CACP Logger"
596
+ - `window.CACP_Logger` global should be `window.JSG_Logger`
597
+
598
+ ##### **2. Default Configuration Hardcoding**
599
+ **File:** `/config/default-config.json`
600
+ - **Hardcoded project name**: `"CACP Logger"`
601
+ - **10 CACP-specific components**:
602
+ - `cacp` (๐ŸŽฏ CACP-CORE) - should be generic `core`
603
+ - `soundcloud` (๐ŸŽต SoundCloud)
604
+ - `youtube` (๐Ÿ“น YouTube)
605
+ - `site-detector` (๐Ÿ” SiteDetector)
606
+ - `websocket` (๐ŸŒ WebSocket)
607
+ - `popup` (๐ŸŽ›๏ธ Popup)
608
+ - `background` (๐Ÿ”ง Background)
609
+ - `priority-manager` (โš–๏ธ PriorityManager)
610
+ - `settings` (โš™๏ธ Settings)
611
+ - `test` (๐Ÿงช Test)
612
+
613
+ ##### **3. Component Schemes Duplication**
614
+ **File:** `/config/component-schemes.js`
615
+ - Duplicates the same 10 hardcoded CACP components
616
+ - Should be empty/minimal by default for generic usage
617
+
618
+ ##### **4. Hardcoded Legacy Aliases**
619
+ ```javascript
620
+ // In createAliases() method:
621
+ this.loggers.siteDetector = this.loggers['site-detector'];
622
+ this.loggers.priorityManager = this.loggers['priority-manager'];
623
+ ```
624
+
625
+ ##### **5. Core Component Dependency**
626
+ ```javascript
627
+ // Initialization requires 'cacp' component:
628
+ if (this.loggers.cacp) {
629
+ this.loggers.cacp.info('CACP Logger initialized', {...});
630
+ }
631
+ ```
632
+
633
+ ##### **6. Config Loading Path Issue**
634
+ - **Critical**: The logger isn't loading our `logger-config.json` properly
635
+ - Falls back to default CACP config instead of using project-specific configurations
636
+ - **Why our Astro config is ignored**: Path resolution or config merging logic issues
637
+
638
+ #### **๐Ÿ”ง Implementation Plan**
639
+
640
+ ##### **Fix 1: Make Default Config Truly Generic**
641
+ **Target**: `/config/default-config.json`
642
+ ```json
643
+ {
644
+ "projectName": "JSG Logger",
645
+ "globalLevel": "info",
646
+ "components": {
647
+ "core": {
648
+ "emoji": "๐ŸŽฏ",
649
+ "color": "#4A90E2",
650
+ "name": "Logger-Core",
651
+ "level": "info"
652
+ }
653
+ }
654
+ }
655
+ ```
656
+
657
+ ##### **Fix 2: Rename Core Class**
658
+ **Target**: `/index.js`
659
+ - `CACPLogger` โ†’ `JSGLogger`
660
+ - Update all static method references
661
+ - Update error messages
662
+ - Update browser global: `window.CACP_Logger` โ†’ `window.JSG_Logger`
663
+
664
+ ##### **Fix 3: Fix Config Loading**
665
+ **Target**: Config manager and initialization
666
+ - Debug why `configPath: 'logger-config.json'` isn't loading properly
667
+ - Ensure project configs override defaults instead of falling back
668
+ - Fix path resolution for various environments (Node.js vs browser)
669
+
670
+ ##### **Fix 4: Remove CACP-Specific Logic**
671
+ **Target**: `/index.js` `createAliases()` method
672
+ - Remove hardcoded legacy aliases for `siteDetector`, `priorityManager`
673
+ - Make aliases configurable if needed, not hardcoded
674
+
675
+ ##### **Fix 5: Use Configurable Core Component**
676
+ **Target**: Initialization logging
677
+ - Replace `this.loggers.cacp.info()` with configurable core component
678
+ - Use `this.loggers.core` or first available component
679
+ - Graceful fallback if no components configured
680
+
681
+ ##### **Fix 6: Clean Component Schemes**
682
+ **Target**: `/config/component-schemes.js`
683
+ - Remove all CACP-specific hardcoded components
684
+ - Keep only minimal example or make it empty
685
+ - Let projects define their own components
686
+
687
+ #### **๐ŸŽฏ Success Criteria**
688
+ 1. โœ… **Generic by Default**: Fresh installations work without CACP references
689
+ 2. โœ… **Config Loading Works**: Project-specific `logger-config.json` files are properly loaded
690
+ 3. โœ… **No CACP Dependencies**: Logger works without any CACP-specific components
691
+ 4. โœ… **Clean API**: `JSGLogger.getInstance()` instead of `CACPLogger.getInstance()`
692
+ 5. โœ… **Test with Real Project**: jsg-tech-check-site loads Astro components correctly
693
+
694
+ #### **๐Ÿ“‹ Implementation Steps**
695
+ 1. **Debug config loading** - Fix why `logger-config.json` is ignored
696
+ 2. **Rename core class** - `CACPLogger` โ†’ `JSGLogger`
697
+ 3. **Replace default config** - Remove 10 CACP components, use minimal generic
698
+ 4. **Remove hardcoded aliases** - Make legacy aliases configurable
699
+ 5. **Fix core component** - Use configurable core for init logging
700
+ 6. **Update browser global** - `window.JSG_Logger`
701
+ 7. **Test with jsg-tech-check-site** - Verify Astro components load correctly
702
+ 8. **Version bump** - Patch or minor version for breaking changes
703
+ 9. **Publish updated package** - Deploy generic version to NPM
704
+
556
705
  ---
557
706
 
558
707
  ### **Previous Optional Enhancements** (Lower Priority)
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import { COMPONENT_SCHEME, LEVEL_SCHEME } from '../config/component-schemes.js';
7
+ import pinoColada from 'pino-colada';
8
+ import pinoPretty from 'pino-pretty';
7
9
 
8
10
  /**
9
11
  * Create CLI formatter using pino-colada or pino-pretty
@@ -11,13 +13,13 @@ import { COMPONENT_SCHEME, LEVEL_SCHEME } from '../config/component-schemes.js';
11
13
  */
12
14
  export const createCLIFormatter = () => {
13
15
  try {
14
- // Try to use pino-colada if available
15
- const pinoColada = require('pino-colada');
16
- return pinoColada();
16
+ // Try pino-colada first (best formatting)
17
+ const colada = pinoColada();
18
+ colada.pipe(process.stdout);
19
+ return colada;
17
20
  } catch (error) {
18
21
  // Fallback to pino-pretty if pino-colada not available
19
22
  try {
20
- const pinoPretty = require('pino-pretty');
21
23
  return pinoPretty({
22
24
  colorize: true,
23
25
  translateTime: 'HH:MM:ss.l',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
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",
@@ -30,7 +30,8 @@
30
30
  "pino": "^9.7.0"
31
31
  },
32
32
  "devDependencies": {
33
- "pino-colada": "^2.2.2"
33
+ "pino-colada": "^2.2.2",
34
+ "pino-pretty": "^13.1.1"
34
35
  },
35
36
  "peerDependencies": {
36
37
  "pino-colada": "^2.2.2"