@crimsonsunset/jsg-logger 1.4.0 → 1.6.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.
- package/CHANGELOG.md +127 -0
- package/README.md +130 -4
- package/config/config-manager.js +17 -1
- package/config/default-config.json +1 -2
- package/docs/next-session.md +52 -9
- package/formatters/cli-formatter.js +64 -42
- package/index.js +116 -18
- package/package.json +3 -5
- package/utils/environment-detector.js +33 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,133 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
### Fixed
|
|
17
17
|
- None
|
|
18
18
|
|
|
19
|
+
## [1.5.0] - 2025-10-25 🎯 **CRITICAL FIX: CLI Tool Support**
|
|
20
|
+
|
|
21
|
+
### 🚨 **Critical Fixes**
|
|
22
|
+
These fixes resolve major blockers for CLI tool usage reported in production.
|
|
23
|
+
|
|
24
|
+
#### **Fixed: CLI Formatter Context Data Display** (Critical)
|
|
25
|
+
- **Replaced pino-colada** with custom formatter that displays context data
|
|
26
|
+
- Context objects now render as indented tree format in terminal
|
|
27
|
+
- Example output:
|
|
28
|
+
```
|
|
29
|
+
21:32:11.6 ✨ [SYSTEM] ✓ macOS version compatible
|
|
30
|
+
├─ version: 14.2
|
|
31
|
+
├─ build: 23C64
|
|
32
|
+
└─ command: sw_vers
|
|
33
|
+
```
|
|
34
|
+
- **Problem solved**: Context data was being silently ignored by pino-colada
|
|
35
|
+
- **Impact**: Terminal applications now show full diagnostic information, not just messages
|
|
36
|
+
|
|
37
|
+
#### **Fixed: Environment Detection for CLI Tools** (Critical)
|
|
38
|
+
- **Enhanced `isCLI()` detection** - Now checks multiple signals:
|
|
39
|
+
- `process.stdout.isTTY` OR `process.stderr.isTTY` (not just stdout)
|
|
40
|
+
- `process.env.TERM` or `process.env.COLORTERM` environment variables
|
|
41
|
+
- Not running in CI/GitHub Actions context
|
|
42
|
+
- **Problem solved**: CLI tools were being detected as "server" mode → outputting JSON instead of pretty terminal formatting
|
|
43
|
+
- **Impact**: Terminal applications now properly display colored, formatted output instead of raw JSON blobs
|
|
44
|
+
|
|
45
|
+
#### **Added: Force Environment Override** (Critical)
|
|
46
|
+
- **New config option**: `forceEnvironment: 'cli' | 'browser' | 'server'`
|
|
47
|
+
- Allows explicit environment override when auto-detection fails
|
|
48
|
+
- Works in both inline config and `logger-config.json`
|
|
49
|
+
- **Use case**: Essential for CLI tools in non-TTY contexts (piped output, automation scripts, etc.)
|
|
50
|
+
|
|
51
|
+
#### **Added: Custom Component Name Support** (High Priority)
|
|
52
|
+
- **Auto-create loggers for ANY component name** - No longer restricted to `COMPONENT_SCHEME`
|
|
53
|
+
- Components not in config get auto-generated with sensible defaults:
|
|
54
|
+
- Default emoji: 📦
|
|
55
|
+
- Default color: #999999
|
|
56
|
+
- Uppercase display name
|
|
57
|
+
- Global level inheritance
|
|
58
|
+
- **Problem solved**: Custom components like 'system', 'installer', 'nvm' now work without pre-definition
|
|
59
|
+
- **Impact**: True zero-configuration for component names
|
|
60
|
+
|
|
61
|
+
### ✨ **API Enhancements**
|
|
62
|
+
|
|
63
|
+
#### **Updated: `getComponent()` Method**
|
|
64
|
+
- Now auto-creates loggers for undefined components instead of returning error loggers
|
|
65
|
+
- Adds new components to auto-discovery getters dynamically
|
|
66
|
+
- Seamless experience for custom component names
|
|
67
|
+
|
|
68
|
+
#### **Updated: `getComponentConfig()` Method**
|
|
69
|
+
- Added 3-tier priority system:
|
|
70
|
+
1. Config components (project-defined)
|
|
71
|
+
2. COMPONENT_SCHEME defaults (built-in)
|
|
72
|
+
3. Auto-generated (for custom components)
|
|
73
|
+
- Always returns valid config, never null/undefined
|
|
74
|
+
|
|
75
|
+
#### **Updated: `init()` and `initSync()` Methods**
|
|
76
|
+
- Now load config BEFORE environment detection
|
|
77
|
+
- Apply `forceEnvironment` config before determining environment
|
|
78
|
+
- `initSync()` properly handles inline config objects
|
|
79
|
+
|
|
80
|
+
### 📚 **Documentation**
|
|
81
|
+
- **Updated README** - New v1.5.0 Quick Start section highlighting CLI tool fixes
|
|
82
|
+
- **Added Force Environment docs** - When and how to override environment detection
|
|
83
|
+
- **Added Custom Components docs** - Examples of using arbitrary component names
|
|
84
|
+
- **Updated Environment Detection section** - Document enhanced CLI detection logic
|
|
85
|
+
|
|
86
|
+
### 🎯 **Real-World Impact**
|
|
87
|
+
**Before v1.5.0 (Broken for CLI tools):**
|
|
88
|
+
```javascript
|
|
89
|
+
const logger = JSGLogger.getInstanceSync({ components: { system: {...} } });
|
|
90
|
+
logger.getComponent('system').info('✓ macOS compatible', { version: '14.2', build: '23C64' });
|
|
91
|
+
// Output: {"level":30,"time":...,"msg":"✓ macOS compatible"} ❌ JSON blob
|
|
92
|
+
// Component 'system' not found error ❌
|
|
93
|
+
// Context data not visible ❌
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**After v1.5.0 (All Fixed!):**
|
|
97
|
+
```javascript
|
|
98
|
+
const logger = JSGLogger.getInstanceSync({
|
|
99
|
+
forceEnvironment: 'cli',
|
|
100
|
+
components: { system: { emoji: '⚙️' } }
|
|
101
|
+
});
|
|
102
|
+
logger.getComponent('system').info('✓ macOS compatible', { version: '14.2', build: '23C64' });
|
|
103
|
+
// Output:
|
|
104
|
+
// 21:32:11.6 ⚙️ [SYSTEM] ✓ macOS compatible ✅ Pretty formatted
|
|
105
|
+
// ├─ version: 14.2 ✅ Context data visible
|
|
106
|
+
// └─ build: 23C64 ✅ Tree formatting
|
|
107
|
+
// Custom component works ✅
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 🔧 **Technical Changes**
|
|
111
|
+
- **File**: `formatters/cli-formatter.js` ⭐ NEW FIX
|
|
112
|
+
- Removed pino-colada dependency (wasn't showing context data)
|
|
113
|
+
- Implemented custom formatter with context tree rendering
|
|
114
|
+
- Context data now displays with tree formatting (├─ and └─)
|
|
115
|
+
- Filters out pino internal fields (level, time, msg, pid, hostname, name, v, environment)
|
|
116
|
+
|
|
117
|
+
- **File**: `utils/environment-detector.js`
|
|
118
|
+
- Added `forceEnvironment()` function for manual override
|
|
119
|
+
- Enhanced `isCLI()` with multi-signal detection
|
|
120
|
+
- All detection functions now respect forced environment
|
|
121
|
+
|
|
122
|
+
- **File**: `config/config-manager.js`
|
|
123
|
+
- `getComponentConfig()` now has 3-tier fallback with auto-generation
|
|
124
|
+
|
|
125
|
+
- **File**: `index.js`
|
|
126
|
+
- Import `forceEnvironment` from environment detector
|
|
127
|
+
- Config loading moved BEFORE environment detection
|
|
128
|
+
- `getComponent()` auto-creates loggers instead of error loggers
|
|
129
|
+
- Added dynamic auto-discovery getter registration
|
|
130
|
+
|
|
131
|
+
- **File**: `package.json`
|
|
132
|
+
- Removed pino-colada from dependencies (no longer required)
|
|
133
|
+
|
|
134
|
+
### 📋 **Migration Guide**
|
|
135
|
+
**No breaking changes** - This is a backward-compatible enhancement.
|
|
136
|
+
|
|
137
|
+
**Recommended for CLI tools:**
|
|
138
|
+
```javascript
|
|
139
|
+
// Add this to your config for reliable terminal output
|
|
140
|
+
const logger = JSGLogger.getInstanceSync({
|
|
141
|
+
forceEnvironment: 'cli', // ← Add this line
|
|
142
|
+
// ... rest of your config
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
19
146
|
## [1.2.0] - 2025-08-21 🎯 **MAJOR: Fully Generic Logger**
|
|
20
147
|
|
|
21
148
|
### 🚀 **BREAKING CHANGES**
|
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ A sophisticated, fully generic logging system that automatically detects its env
|
|
|
11
11
|
- 🔧 **Auto-Discovery Components** - Both camelCase and kebab-case component access
|
|
12
12
|
- ⚡ **Built-in Performance Logging** - Static utilities with auto-getInstance
|
|
13
13
|
- 🛡️ **Non-Destructive Error Handling** - Missing components log but don't break apps
|
|
14
|
-
-
|
|
14
|
+
- 🎨 **Custom Component Names** - *New in v1.5.0!* Use ANY component name, auto-generated styling
|
|
15
|
+
- 🔧 **Force Environment Override** - *New in v1.5.0!* Override auto-detection for CLI tools
|
|
16
|
+
- 🧠 **Enhanced Environment Detection** - *New in v1.5.0!* Robust CLI detection with fallbacks
|
|
15
17
|
- 🎨 **Beautiful Visual Output** - Emoji, colors, and structured context display
|
|
16
18
|
- 📱 **Multi-Environment** - Browser console, terminal, and production JSON
|
|
17
19
|
- 🏪 **Log Store** - In-memory storage for debugging and popup interfaces
|
|
@@ -25,6 +27,41 @@ A sophisticated, fully generic logging system that automatically detects its env
|
|
|
25
27
|
|
|
26
28
|
## 🚀 Quick Start
|
|
27
29
|
|
|
30
|
+
### **v1.5.0: Custom Components & Force Environment - Perfect for CLI Tools!**
|
|
31
|
+
|
|
32
|
+
> **✨ New in v1.5.0:** Use ANY component name (not just pre-defined ones) and force CLI mode for terminal applications!
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
import JSGLogger from '@crimsonsunset/jsg-logger';
|
|
36
|
+
|
|
37
|
+
// ✨ NEW: Force environment for CLI tools (fixes terminal detection)
|
|
38
|
+
const logger = JSGLogger.getInstanceSync({
|
|
39
|
+
forceEnvironment: 'cli', // Forces pretty terminal output
|
|
40
|
+
globalLevel: 'info',
|
|
41
|
+
components: {
|
|
42
|
+
system: { emoji: '⚙️', level: 'info' }, // Custom component names!
|
|
43
|
+
installer: { emoji: '📦', level: 'info' }, // No need to pre-define
|
|
44
|
+
ssh: { emoji: '🔑', level: 'info' }, // Auto-generated styling
|
|
45
|
+
nvm: { emoji: '🟢', level: 'info' }
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// ✨ NEW: Custom components work immediately
|
|
50
|
+
const sysLog = logger.getComponent('system');
|
|
51
|
+
sysLog.info('✓ macOS version compatible', { version: '14.2', build: '23C64' });
|
|
52
|
+
// Output: Pretty formatted terminal output with colors AND context data!
|
|
53
|
+
// 21:32:11.6 ⚙️ [SYSTEM] ✓ macOS version compatible
|
|
54
|
+
// ├─ version: 14.2
|
|
55
|
+
// └─ build: 23C64
|
|
56
|
+
|
|
57
|
+
const installLog = logger.getComponent('installer');
|
|
58
|
+
installLog.info('✓ Applications installed', { installed: 25, duration: '5m' });
|
|
59
|
+
// 21:32:11.8 📦 [INSTALLER] ✓ Applications installed
|
|
60
|
+
// ├─ installed: 25
|
|
61
|
+
// └─ duration: 5m
|
|
62
|
+
// No more JSON blobs in terminal! 🎉
|
|
63
|
+
```
|
|
64
|
+
|
|
28
65
|
### **v1.2.0: Fully Generic Design - Works with Any Project!**
|
|
29
66
|
|
|
30
67
|
> **⚠️ Breaking Change:** v1.2.0 requires defining components in your logger-config.json. The logger is now 100% generic with no hardcoded assumptions.
|
|
@@ -47,7 +84,7 @@ const startTime = performance.now();
|
|
|
47
84
|
// ... do work ...
|
|
48
85
|
JSGLogger.logPerformance('Page Generation', startTime, 'api');
|
|
49
86
|
|
|
50
|
-
//
|
|
87
|
+
// ✨ NEW: Custom components auto-created on demand
|
|
51
88
|
const dynamicLogger = logger.getComponent('new-feature');
|
|
52
89
|
dynamicLogger.info('Auto-created component!'); // Works immediately
|
|
53
90
|
```
|
|
@@ -82,10 +119,68 @@ This allows surgical debugging - you can turn on trace logging for just one prob
|
|
|
82
119
|
|
|
83
120
|
## ⚙️ **Advanced Configuration**
|
|
84
121
|
|
|
122
|
+
### **Force Environment Override** ✨ *New in v1.5.0*
|
|
123
|
+
|
|
124
|
+
Perfect for CLI tools that get mis-detected as "server" mode:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// Inline config approach (recommended for CLI tools)
|
|
128
|
+
const logger = JSGLogger.getInstanceSync({
|
|
129
|
+
forceEnvironment: 'cli', // Options: 'browser', 'cli', 'server'
|
|
130
|
+
globalLevel: 'info',
|
|
131
|
+
components: {
|
|
132
|
+
system: { emoji: '⚙️', level: 'info' }
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or in `logger-config.json`:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"forceEnvironment": "cli",
|
|
142
|
+
"projectName": "My CLI Tool",
|
|
143
|
+
"globalLevel": "info",
|
|
144
|
+
"components": {
|
|
145
|
+
"system": { "emoji": "⚙️", "level": "info" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**When to use `forceEnvironment`:**
|
|
151
|
+
- CLI tools running in non-TTY contexts (CI, piped output, etc.)
|
|
152
|
+
- Override incorrect environment detection
|
|
153
|
+
- Testing different output formats
|
|
154
|
+
- Production deployments with specific requirements
|
|
155
|
+
|
|
156
|
+
### **Custom Component Names** ✨ *New in v1.5.0*
|
|
157
|
+
|
|
158
|
+
Use ANY component name - no need to pre-define in COMPONENT_SCHEME:
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
const logger = JSGLogger.getInstanceSync({
|
|
162
|
+
components: {
|
|
163
|
+
'my-custom-component': { emoji: '🎯', level: 'debug' },
|
|
164
|
+
'another-one': { emoji: '🚀', level: 'info' },
|
|
165
|
+
'system-checker': { emoji: '⚙️', level: 'trace' }
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// All these work immediately - auto-created with sensible defaults
|
|
170
|
+
const log1 = logger.getComponent('my-custom-component');
|
|
171
|
+
const log2 = logger.getComponent('another-one');
|
|
172
|
+
const log3 = logger.getComponent('system-checker');
|
|
173
|
+
|
|
174
|
+
// Even undefined components work (auto-generated with 📦 emoji)
|
|
175
|
+
const log4 = logger.getComponent('undefined-component');
|
|
176
|
+
log4.info('This works!'); // Uses auto-generated styling
|
|
177
|
+
```
|
|
178
|
+
|
|
85
179
|
### **Full Configuration Example**
|
|
86
180
|
|
|
87
181
|
```json
|
|
88
182
|
{
|
|
183
|
+
"forceEnvironment": "cli",
|
|
89
184
|
"projectName": "My Advanced Project",
|
|
90
185
|
"globalLevel": "info",
|
|
91
186
|
"timestampMode": "absolute",
|
|
@@ -255,6 +350,9 @@ logger.controls.addFileOverride('src/popup.js', {
|
|
|
255
350
|
```
|
|
256
351
|
|
|
257
352
|
### **Context Data**
|
|
353
|
+
|
|
354
|
+
✨ **New in v1.5.0:** Context data now displays in CLI/terminal mode with tree formatting!
|
|
355
|
+
|
|
258
356
|
```javascript
|
|
259
357
|
logger.api.error('Request failed', {
|
|
260
358
|
url: window.location.href,
|
|
@@ -267,7 +365,15 @@ logger.api.error('Request failed', {
|
|
|
267
365
|
userAgent: navigator.userAgent
|
|
268
366
|
});
|
|
269
367
|
|
|
270
|
-
//
|
|
368
|
+
// CLI/Terminal output (v1.5.0+):
|
|
369
|
+
// 22:15:30.1 🚨 [API] Request failed
|
|
370
|
+
// ├─ url: https://soundcloud.com/track/example
|
|
371
|
+
// ├─ selectors: {"title":".track-title","artist":".track-artist"}
|
|
372
|
+
// ├─ retryCount: 3
|
|
373
|
+
// ├─ lastError: Element not found
|
|
374
|
+
// └─ userAgent: Mozilla/5.0...
|
|
375
|
+
|
|
376
|
+
// Browser Console output:
|
|
271
377
|
// 22:15:30.123 🚨 [API] Request failed
|
|
272
378
|
// ├─ url: https://soundcloud.com/track/example
|
|
273
379
|
// ├─ selectors: {title: ".track-title", artist: ".track-artist"}
|
|
@@ -393,7 +499,7 @@ const stats = logger.controls.getStats();
|
|
|
393
499
|
npm install @crimsonsunset/jsg-logger
|
|
394
500
|
```
|
|
395
501
|
|
|
396
|
-
**Latest**: v1.
|
|
502
|
+
**Latest**: v1.5.0 includes critical CLI tool fixes and custom component support!
|
|
397
503
|
|
|
398
504
|
## 🎯 Environment Detection
|
|
399
505
|
|
|
@@ -403,6 +509,26 @@ The logger automatically detects its environment and uses optimal implementation
|
|
|
403
509
|
- **CLI**: Uses pino-colada for beautiful terminal output
|
|
404
510
|
- **Server**: Uses structured JSON for production logging
|
|
405
511
|
|
|
512
|
+
### **Enhanced CLI Detection** ✨ *Improved in v1.5.0*
|
|
513
|
+
|
|
514
|
+
The CLI detection now checks multiple signals:
|
|
515
|
+
1. **TTY Check**: `process.stdout.isTTY` or `process.stderr.isTTY`
|
|
516
|
+
2. **Terminal Environment**: `process.env.TERM` or `process.env.COLORTERM`
|
|
517
|
+
3. **Non-CI Context**: Not running in CI/GitHub Actions
|
|
518
|
+
|
|
519
|
+
This fixes detection issues in various terminal contexts where `isTTY` may be undefined.
|
|
520
|
+
|
|
521
|
+
### **Force Environment Override** ✨ *New in v1.5.0*
|
|
522
|
+
|
|
523
|
+
If auto-detection fails, you can force the environment:
|
|
524
|
+
|
|
525
|
+
```javascript
|
|
526
|
+
const logger = JSGLogger.getInstanceSync({
|
|
527
|
+
forceEnvironment: 'cli', // Override auto-detection
|
|
528
|
+
// ... rest of config
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
406
532
|
**Why Browser is Different:**
|
|
407
533
|
Our testing revealed that Pino's browser detection was interfering with custom formatters, especially in Chrome extensions. By creating a custom direct browser logger that bypasses Pino entirely, we achieved:
|
|
408
534
|
- Perfect emoji and color display
|
package/config/config-manager.js
CHANGED
|
@@ -406,7 +406,23 @@ export class ConfigManager {
|
|
|
406
406
|
* @returns {Object} Component configuration
|
|
407
407
|
*/
|
|
408
408
|
getComponentConfig(componentName, filePath = null) {
|
|
409
|
-
|
|
409
|
+
// Priority 1: Config components
|
|
410
|
+
let baseComponent = this.config.components?.[componentName];
|
|
411
|
+
|
|
412
|
+
// Priority 2: COMPONENT_SCHEME defaults
|
|
413
|
+
if (!baseComponent) {
|
|
414
|
+
baseComponent = COMPONENT_SCHEME[componentName];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Priority 3: Auto-generate for custom components
|
|
418
|
+
if (!baseComponent) {
|
|
419
|
+
baseComponent = {
|
|
420
|
+
emoji: '📦',
|
|
421
|
+
color: '#999999',
|
|
422
|
+
name: componentName.toUpperCase().replace(/-/g, '-'),
|
|
423
|
+
level: this.config.globalLevel || 'info'
|
|
424
|
+
};
|
|
425
|
+
}
|
|
410
426
|
|
|
411
427
|
// Check for file-specific overrides
|
|
412
428
|
const checkFile = filePath || this.currentFile;
|
package/docs/next-session.md
CHANGED
|
@@ -14,12 +14,44 @@
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
**Date:** October
|
|
18
|
-
**Session Goal:** 🎯 **
|
|
19
|
-
**Status:**
|
|
17
|
+
**Date:** October 25, 2025
|
|
18
|
+
**Session Goal:** 🎯 **Critical CLI Tool Fixes** - Resolve environment detection and custom component blockers
|
|
19
|
+
**Status:** ✅ **COMPLETE** - v1.5.0 shipped with all critical fixes
|
|
20
20
|
|
|
21
21
|
## 🎉 MAJOR ACCOMPLISHMENTS THIS SESSION
|
|
22
22
|
|
|
23
|
+
### ✅ Critical CLI Tool Fixes Complete (October 25, 2025) 🚨→✅
|
|
24
|
+
- **🎨 CLI Context Data Display Fixed** - Replaced pino-colada with custom formatter
|
|
25
|
+
- Context data now renders as indented tree in terminal
|
|
26
|
+
- Shows all diagnostic information, not just messages
|
|
27
|
+
- Example: version, build, command data visible with ├─ and └─ formatting
|
|
28
|
+
- **🔧 Environment Detection Fixed** - Enhanced `isCLI()` with multi-signal detection
|
|
29
|
+
- Now checks TTY, TERM env vars, and CI context
|
|
30
|
+
- CLI tools no longer mis-detected as "server" mode
|
|
31
|
+
- Fixes JSON output in terminal applications
|
|
32
|
+
- **✨ Force Environment Override** - New `forceEnvironment` config option
|
|
33
|
+
- Allows manual override of auto-detection
|
|
34
|
+
- Works in inline config and logger-config.json
|
|
35
|
+
- Essential for non-TTY contexts (piped output, automation)
|
|
36
|
+
- **🎯 Custom Component Names** - Any component name now works
|
|
37
|
+
- Auto-creation for undefined components
|
|
38
|
+
- Sensible default styling (📦 emoji, gray color)
|
|
39
|
+
- No longer restricted to COMPONENT_SCHEME
|
|
40
|
+
- **📦 Version Bump** - Published v1.5.0 with all fixes
|
|
41
|
+
- **🗑️ Dependency Cleanup** - Removed pino-colada (no longer needed)
|
|
42
|
+
- **📚 Comprehensive Documentation** - Updated README, CHANGELOG
|
|
43
|
+
- New Quick Start section for v1.5.0
|
|
44
|
+
- Detailed forceEnvironment examples
|
|
45
|
+
- Custom component usage patterns
|
|
46
|
+
- Context data rendering examples
|
|
47
|
+
|
|
48
|
+
### **Real-World Impact**
|
|
49
|
+
Fixed production blocker in macOS setup automation tool:
|
|
50
|
+
- **Before**: JSON blobs in 30-minute terminal script → unusable
|
|
51
|
+
- **After**: Pretty colored output with component organization → perfect UX
|
|
52
|
+
|
|
53
|
+
## 🎉 PREVIOUS SESSION ACCOMPLISHMENTS
|
|
54
|
+
|
|
23
55
|
### ✅ DevTools Integration Blocker RESOLVED (October 24, 2025)
|
|
24
56
|
- **🔧 Import Path Fixed** - Installed JSG Logger as local file dependency
|
|
25
57
|
- **📦 Dependencies Complete** - All parent dependencies installed (pino, pino-colada)
|
|
@@ -70,17 +102,28 @@
|
|
|
70
102
|
|
|
71
103
|
## 📋 IMMEDIATE PRIORITIES
|
|
72
104
|
|
|
73
|
-
###
|
|
105
|
+
### **🚀 Ready to Publish v1.5.0:**
|
|
106
|
+
- [x] **Environment Detection** - Enhanced CLI detection with multi-signal check
|
|
107
|
+
- [x] **Force Environment** - Config option to override auto-detection
|
|
108
|
+
- [x] **Custom Components** - Auto-create loggers for any component name
|
|
109
|
+
- [x] **Documentation** - README, CHANGELOG updated with v1.5.0 features
|
|
110
|
+
- [x] **Version Bump** - Package version updated to 1.5.0
|
|
111
|
+
- [ ] **Publish to NPM** - `npm run release:minor` when ready
|
|
112
|
+
|
|
113
|
+
### **🔧 DevTools Theme Fixes (Optional, Low Priority):**
|
|
74
114
|
- [ ] **Fix Text Components** - Pass theme data correctly to Evergreen UI Text components
|
|
75
115
|
- [ ] **Test Panel Interaction** - Click floating button and verify panel opens
|
|
76
116
|
- [ ] **Verify Filtering** - Test component toggles affect console output
|
|
77
117
|
- [ ] **Apply Custom Theme** - Implement devtools-theme.js once basic theme works
|
|
78
118
|
|
|
79
|
-
### **✅ COMPLETED:**
|
|
80
|
-
- [x] **
|
|
81
|
-
- [x] **
|
|
82
|
-
- [x] **
|
|
83
|
-
- [x] **
|
|
119
|
+
### **✅ COMPLETED THIS SESSION:**
|
|
120
|
+
- [x] **CLI Context Data Display** - Custom formatter with tree rendering
|
|
121
|
+
- [x] **Environment Detection Fixed** - Multi-signal CLI detection (TTY, TERM, CI check)
|
|
122
|
+
- [x] **forceEnvironment Config** - Override auto-detection via config
|
|
123
|
+
- [x] **Custom Component Names** - getComponent() auto-creates loggers
|
|
124
|
+
- [x] **Config Loading Order** - Load config BEFORE environment detection
|
|
125
|
+
- [x] **Dependency Cleanup** - Removed pino-colada from package
|
|
126
|
+
- [x] **Documentation Complete** - README, CHANGELOG, version bump
|
|
84
127
|
|
|
85
128
|
## 🔮 Future Possibilities (Phase 10)
|
|
86
129
|
|
|
@@ -1,56 +1,78 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI/Terminal Formatter for JSG Logger
|
|
3
|
-
*
|
|
3
|
+
* Custom formatter with context data display
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { COMPONENT_SCHEME, LEVEL_SCHEME } from '../config/component-schemes.js';
|
|
7
|
-
import pinoColada from 'pino-colada';
|
|
8
|
-
// Note: pino-pretty imported conditionally to avoid browser bundle issues
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
|
-
*
|
|
9
|
+
* Format a value for display in context tree
|
|
10
|
+
* @param {*} value - Value to format
|
|
11
|
+
* @returns {string} Formatted value
|
|
12
|
+
*/
|
|
13
|
+
const formatValue = (value) => {
|
|
14
|
+
if (value === null) return 'null';
|
|
15
|
+
if (value === undefined) return 'undefined';
|
|
16
|
+
if (typeof value === 'string') return value;
|
|
17
|
+
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
18
|
+
if (typeof value === 'object') {
|
|
19
|
+
// For objects/arrays, show compact JSON
|
|
20
|
+
try {
|
|
21
|
+
return JSON.stringify(value);
|
|
22
|
+
} catch {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return String(value);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create CLI formatter with context data support
|
|
12
31
|
* @returns {Object} Stream-like object for Pino
|
|
13
32
|
*/
|
|
14
33
|
export const createCLIFormatter = () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
return {
|
|
35
|
+
write: (chunk) => {
|
|
36
|
+
try {
|
|
37
|
+
const log = JSON.parse(chunk);
|
|
38
|
+
|
|
39
|
+
// Get component info
|
|
40
|
+
const component = COMPONENT_SCHEME[log.name] || COMPONENT_SCHEME['core'];
|
|
41
|
+
const componentName = component.name.toUpperCase().replace(/([a-z])([A-Z])/g, '$1-$2');
|
|
42
|
+
|
|
43
|
+
// Get level info
|
|
44
|
+
const level = LEVEL_SCHEME[log.level] || LEVEL_SCHEME[30];
|
|
45
|
+
|
|
46
|
+
// Format timestamp
|
|
47
|
+
const timestamp = new Date(log.time).toLocaleTimeString('en-US', {
|
|
48
|
+
hour12: false,
|
|
49
|
+
hour: '2-digit',
|
|
50
|
+
minute: '2-digit',
|
|
51
|
+
second: '2-digit',
|
|
52
|
+
fractionalSecondDigits: 1
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Format main message
|
|
56
|
+
const message = `${level.emoji} [${componentName}] ${log.msg || ''}`;
|
|
57
|
+
console.log(`${timestamp} ${message}`);
|
|
58
|
+
|
|
59
|
+
// Display context data (exclude pino internal fields)
|
|
60
|
+
const internalFields = ['level', 'time', 'msg', 'pid', 'hostname', 'name', 'v', 'environment'];
|
|
61
|
+
const contextKeys = Object.keys(log).filter(key => !internalFields.includes(key));
|
|
62
|
+
|
|
63
|
+
if (contextKeys.length > 0) {
|
|
64
|
+
contextKeys.forEach((key, index) => {
|
|
65
|
+
const isLast = index === contextKeys.length - 1;
|
|
66
|
+
const prefix = isLast ? ' └─' : ' ├─';
|
|
67
|
+
const value = formatValue(log[key]);
|
|
68
|
+
console.log(`${prefix} ${key}: ${value}`);
|
|
41
69
|
});
|
|
42
|
-
|
|
43
|
-
// Format message like pino-pretty messageFormat
|
|
44
|
-
const message = `${level.emoji} [${componentName}] ${log.msg || ''}`;
|
|
45
|
-
|
|
46
|
-
// Output with timestamp prefix
|
|
47
|
-
console.log(`${timestamp} ${message}`);
|
|
48
|
-
|
|
49
|
-
} catch (error) {
|
|
50
|
-
// Raw fallback
|
|
51
|
-
console.log(chunk);
|
|
52
70
|
}
|
|
71
|
+
|
|
72
|
+
} catch (error) {
|
|
73
|
+
// Raw fallback for malformed JSON
|
|
74
|
+
console.log(chunk);
|
|
53
75
|
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
56
78
|
};
|
package/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import pino from 'pino';
|
|
|
7
7
|
import {configManager} from './config/config-manager.js';
|
|
8
8
|
import {COMPONENT_SCHEME} from './config/component-schemes.js';
|
|
9
9
|
import defaultConfig from './config/default-config.json' with { type: 'json' };
|
|
10
|
-
import {getEnvironment, isBrowser, isCLI} from './utils/environment-detector.js';
|
|
10
|
+
import {getEnvironment, isBrowser, isCLI, forceEnvironment} from './utils/environment-detector.js';
|
|
11
11
|
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';
|
|
@@ -25,7 +25,7 @@ class JSGLogger {
|
|
|
25
25
|
constructor() {
|
|
26
26
|
this.loggers = {};
|
|
27
27
|
this.logStore = new LogStore();
|
|
28
|
-
this.environment =
|
|
28
|
+
this.environment = null; // Will be set after config loads
|
|
29
29
|
this.initialized = false;
|
|
30
30
|
this.components = {}; // Auto-discovery getters
|
|
31
31
|
}
|
|
@@ -49,10 +49,17 @@ class JSGLogger {
|
|
|
49
49
|
* @returns {Object} Enhanced logger exports with controls API
|
|
50
50
|
*/
|
|
51
51
|
static getInstanceSync(options = {}) {
|
|
52
|
+
const hasOptions = options && Object.keys(options).length > 0;
|
|
53
|
+
|
|
52
54
|
if (!JSGLogger._instance) {
|
|
55
|
+
// First time initialization
|
|
53
56
|
JSGLogger._instance = new JSGLogger();
|
|
54
57
|
JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
|
|
58
|
+
} else if (hasOptions) {
|
|
59
|
+
// Instance exists but new options provided - reinitialize
|
|
60
|
+
JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
|
|
55
61
|
}
|
|
62
|
+
|
|
56
63
|
return JSGLogger._enhancedLoggers;
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -63,11 +70,22 @@ class JSGLogger {
|
|
|
63
70
|
*/
|
|
64
71
|
async init(options = {}) {
|
|
65
72
|
try {
|
|
66
|
-
// Load configuration
|
|
73
|
+
// Load configuration FIRST (before environment detection)
|
|
67
74
|
if (options.configPath || options.config) {
|
|
68
75
|
await configManager.loadConfig(options.configPath || options.config);
|
|
76
|
+
} else if (options) {
|
|
77
|
+
// Support inline config passed as options
|
|
78
|
+
await configManager.loadConfig(options);
|
|
69
79
|
}
|
|
70
80
|
|
|
81
|
+
// Apply forceEnvironment if specified in config
|
|
82
|
+
if (configManager.config.forceEnvironment) {
|
|
83
|
+
forceEnvironment(configManager.config.forceEnvironment);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// NOW determine environment (after config is loaded and forceEnvironment is applied)
|
|
87
|
+
this.environment = getEnvironment();
|
|
88
|
+
|
|
71
89
|
// Create loggers for all available components
|
|
72
90
|
const components = configManager.getAvailableComponents();
|
|
73
91
|
|
|
@@ -107,15 +125,32 @@ class JSGLogger {
|
|
|
107
125
|
|
|
108
126
|
/**
|
|
109
127
|
* Initialize synchronously with default configuration
|
|
128
|
+
* @param {Object} options - Initialization options
|
|
110
129
|
* @returns {Object} Logger instance with all components
|
|
111
130
|
*/
|
|
112
|
-
initSync() {
|
|
131
|
+
initSync(options = {}) {
|
|
113
132
|
try {
|
|
133
|
+
// Load inline config if provided (sync loading for objects)
|
|
134
|
+
if (options && Object.keys(options).length > 0) {
|
|
135
|
+
// Merge inline config with existing config
|
|
136
|
+
configManager.config = configManager.mergeConfigs(configManager.config, options);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Apply forceEnvironment if specified in config
|
|
140
|
+
if (configManager.config.forceEnvironment) {
|
|
141
|
+
forceEnvironment(configManager.config.forceEnvironment);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// NOW determine environment (after config is loaded and forceEnvironment is applied)
|
|
145
|
+
this.environment = getEnvironment();
|
|
146
|
+
|
|
114
147
|
// Create loggers for all available components using default config
|
|
115
148
|
const components = configManager.getAvailableComponents();
|
|
116
149
|
|
|
117
150
|
components.forEach(componentName => {
|
|
118
|
-
|
|
151
|
+
// Use original createLogger to bypass utility method caching
|
|
152
|
+
const createFn = this._createLoggerOriginal || this.createLogger.bind(this);
|
|
153
|
+
this.loggers[componentName] = createFn(componentName);
|
|
119
154
|
});
|
|
120
155
|
|
|
121
156
|
// Create legacy compatibility aliases
|
|
@@ -181,7 +216,54 @@ class JSGLogger {
|
|
|
181
216
|
logger._componentName = component.name;
|
|
182
217
|
logger._effectiveLevel = configManager.getEffectiveLevel(componentName);
|
|
183
218
|
|
|
184
|
-
|
|
219
|
+
// Wrap pino logger to support (message, context) syntax
|
|
220
|
+
const wrappedLogger = this._wrapPinoLogger(logger);
|
|
221
|
+
|
|
222
|
+
return wrappedLogger;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Wrap Pino logger to support (message, context) syntax
|
|
227
|
+
* Transforms calls from logger.info('msg', {ctx}) to pino's logger.info({ctx}, 'msg')
|
|
228
|
+
* @param {Object} pinoLogger - Original pino logger instance
|
|
229
|
+
* @returns {Object} Wrapped logger with enhanced syntax
|
|
230
|
+
* @private
|
|
231
|
+
*/
|
|
232
|
+
_wrapPinoLogger(pinoLogger) {
|
|
233
|
+
const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
234
|
+
const wrapped = {};
|
|
235
|
+
|
|
236
|
+
levels.forEach(level => {
|
|
237
|
+
wrapped[level] = (first, ...args) => {
|
|
238
|
+
// Handle different argument patterns
|
|
239
|
+
if (typeof first === 'string') {
|
|
240
|
+
// Pattern: logger.info('message', {context})
|
|
241
|
+
const message = first;
|
|
242
|
+
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
|
|
243
|
+
// Has context object
|
|
244
|
+
pinoLogger[level](args[0], message);
|
|
245
|
+
} else {
|
|
246
|
+
// Just message
|
|
247
|
+
pinoLogger[level](message);
|
|
248
|
+
}
|
|
249
|
+
} else if (typeof first === 'object' && first !== null) {
|
|
250
|
+
// Pattern: logger.info({context}, 'message') - already pino format
|
|
251
|
+
pinoLogger[level](first, ...args);
|
|
252
|
+
} else {
|
|
253
|
+
// Fallback: just pass through
|
|
254
|
+
pinoLogger[level](first, ...args);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Copy over all other properties from original logger
|
|
260
|
+
Object.keys(pinoLogger).forEach(key => {
|
|
261
|
+
if (!wrapped[key]) {
|
|
262
|
+
wrapped[key] = pinoLogger[key];
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return wrapped;
|
|
185
267
|
}
|
|
186
268
|
|
|
187
269
|
/**
|
|
@@ -203,13 +285,19 @@ class JSGLogger {
|
|
|
203
285
|
* @private
|
|
204
286
|
*/
|
|
205
287
|
addUtilityMethods() {
|
|
206
|
-
//
|
|
288
|
+
// Store reference to original createLogger before overriding
|
|
289
|
+
const originalCreateLogger = this.createLogger.bind(this);
|
|
290
|
+
|
|
291
|
+
// Create logger on demand (reuses existing loggers)
|
|
207
292
|
this.createLogger = (componentName) => {
|
|
208
293
|
if (!this.loggers[componentName]) {
|
|
209
|
-
this.loggers[componentName] =
|
|
294
|
+
this.loggers[componentName] = originalCreateLogger(componentName);
|
|
210
295
|
}
|
|
211
296
|
return this.loggers[componentName];
|
|
212
297
|
};
|
|
298
|
+
|
|
299
|
+
// Store the original for internal use
|
|
300
|
+
this._createLoggerOriginal = originalCreateLogger;
|
|
213
301
|
}
|
|
214
302
|
|
|
215
303
|
/**
|
|
@@ -506,23 +594,33 @@ class JSGLogger {
|
|
|
506
594
|
}
|
|
507
595
|
|
|
508
596
|
/**
|
|
509
|
-
* Get a specific component logger with
|
|
597
|
+
* Get a specific component logger with auto-creation for custom components
|
|
510
598
|
* @param {string} componentName - Component name to retrieve
|
|
511
|
-
* @returns {Object} Logger instance
|
|
599
|
+
* @returns {Object} Logger instance (auto-created if needed)
|
|
512
600
|
*/
|
|
513
601
|
getComponent(componentName) {
|
|
602
|
+
// If logger doesn't exist, auto-create it for custom components
|
|
514
603
|
if (!this.loggers[componentName]) {
|
|
515
|
-
|
|
604
|
+
// Check if this is a configured component or custom component
|
|
605
|
+
const hasConfig = configManager.config.components?.[componentName];
|
|
606
|
+
const hasScheme = COMPONENT_SCHEME[componentName];
|
|
516
607
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.loggers.
|
|
520
|
-
|
|
521
|
-
|
|
608
|
+
if (!hasConfig && !hasScheme) {
|
|
609
|
+
// Custom component - log info and auto-create
|
|
610
|
+
if (this.loggers.core) {
|
|
611
|
+
this.loggers.core.debug(`Auto-creating custom component logger: ${componentName}`);
|
|
612
|
+
}
|
|
522
613
|
}
|
|
523
614
|
|
|
524
|
-
//
|
|
525
|
-
|
|
615
|
+
// Create the logger (getComponentConfig will auto-generate config for custom components)
|
|
616
|
+
this.loggers[componentName] = this.createLogger(componentName);
|
|
617
|
+
|
|
618
|
+
// Also add to auto-discovery getters
|
|
619
|
+
this.components[componentName] = () => this.getComponent(componentName);
|
|
620
|
+
const camelName = componentName.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
|
|
621
|
+
if (camelName !== componentName) {
|
|
622
|
+
this.components[camelName] = () => this.getComponent(componentName);
|
|
623
|
+
}
|
|
526
624
|
}
|
|
527
625
|
|
|
528
626
|
return this.loggers[componentName];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crimsonsunset/jsg-logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.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",
|
|
@@ -34,12 +34,8 @@
|
|
|
34
34
|
"preact": "^10.27.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"pino-colada": "^2.2.2",
|
|
38
37
|
"vite": "^5.1.3"
|
|
39
38
|
},
|
|
40
|
-
"peerDependencies": {
|
|
41
|
-
"pino-colada": "^2.2.2"
|
|
42
|
-
},
|
|
43
39
|
"files": [
|
|
44
40
|
"index.js",
|
|
45
41
|
"config/",
|
|
@@ -69,6 +65,8 @@
|
|
|
69
65
|
"./examples/*": "./examples/*"
|
|
70
66
|
},
|
|
71
67
|
"scripts": {
|
|
68
|
+
"test": "node tests/run-all.js",
|
|
69
|
+
"test:watch": "nodemon --watch . --ext js --exec 'npm test'",
|
|
72
70
|
"dev": "vite",
|
|
73
71
|
"dev:devtools": "vite",
|
|
74
72
|
"test:devtools": "vite",
|
|
@@ -3,20 +3,50 @@
|
|
|
3
3
|
* Smart detection of browser, CLI, and server environments
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
// Store forced environment override
|
|
7
|
+
let forcedEnvironment = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Force environment detection to a specific value
|
|
11
|
+
* @param {'browser'|'cli'|'server'|null} env - Environment to force, or null to reset
|
|
12
|
+
*/
|
|
13
|
+
export const forceEnvironment = (env) => {
|
|
14
|
+
if (env !== null && !['browser', 'cli', 'server'].includes(env)) {
|
|
15
|
+
console.warn(`[JSG-LOGGER] Invalid environment "${env}". Must be 'browser', 'cli', 'server', or null.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
forcedEnvironment = env;
|
|
19
|
+
};
|
|
20
|
+
|
|
6
21
|
/**
|
|
7
22
|
* Check if running in browser environment
|
|
8
23
|
* @returns {boolean}
|
|
9
24
|
*/
|
|
10
25
|
export const isBrowser = () => {
|
|
26
|
+
if (forcedEnvironment) return forcedEnvironment === 'browser';
|
|
11
27
|
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
12
28
|
};
|
|
13
29
|
|
|
14
30
|
/**
|
|
15
31
|
* Check if running in CLI/terminal environment
|
|
32
|
+
* Enhanced detection for various terminal contexts
|
|
16
33
|
* @returns {boolean}
|
|
17
34
|
*/
|
|
18
35
|
export const isCLI = () => {
|
|
19
|
-
return
|
|
36
|
+
if (forcedEnvironment) return forcedEnvironment === 'cli';
|
|
37
|
+
|
|
38
|
+
if (typeof process === 'undefined') return false;
|
|
39
|
+
|
|
40
|
+
// Check multiple signals for TTY/terminal environment
|
|
41
|
+
const hasTTY = process.stdout?.isTTY || process.stderr?.isTTY;
|
|
42
|
+
const hasTermEnv = process.env.TERM || process.env.COLORTERM;
|
|
43
|
+
const notCI = !process.env.CI && !process.env.GITHUB_ACTIONS;
|
|
44
|
+
|
|
45
|
+
// Consider it CLI if:
|
|
46
|
+
// 1. Has TTY (traditional check)
|
|
47
|
+
// 2. Has TERM/COLORTERM environment variables (terminal detected)
|
|
48
|
+
// 3. Not running in CI/automation environment
|
|
49
|
+
return hasTTY || (hasTermEnv && notCI);
|
|
20
50
|
};
|
|
21
51
|
|
|
22
52
|
/**
|
|
@@ -24,6 +54,7 @@ export const isCLI = () => {
|
|
|
24
54
|
* @returns {boolean}
|
|
25
55
|
*/
|
|
26
56
|
export const isServer = () => {
|
|
57
|
+
if (forcedEnvironment) return forcedEnvironment === 'server';
|
|
27
58
|
return !isBrowser() && !isCLI();
|
|
28
59
|
};
|
|
29
60
|
|
|
@@ -32,6 +63,7 @@ export const isServer = () => {
|
|
|
32
63
|
* @returns {'browser'|'cli'|'server'}
|
|
33
64
|
*/
|
|
34
65
|
export const getEnvironment = () => {
|
|
66
|
+
if (forcedEnvironment) return forcedEnvironment;
|
|
35
67
|
if (isBrowser()) return 'browser';
|
|
36
68
|
if (isCLI()) return 'cli';
|
|
37
69
|
return 'server';
|