molex-env 0.2.5 → 0.3.1
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/README.md +157 -61
- package/package.json +1 -1
- package/src/lib/apply.js +22 -5
- package/src/lib/core.js +4 -3
- package/src/lib/watch.js +35 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
- **Type-safe parsing** - Automatic conversion of booleans, numbers, JSON, and dates
|
|
17
17
|
- **Strict validation** - Schema enforcement with required fields and type checking
|
|
18
18
|
- **Origin tracking** - Know exactly which file and line each value came from
|
|
19
|
+
- **Debug mode** - See which files override values during cascading
|
|
19
20
|
- **Immutable config** - Deep-freeze protection prevents accidental modifications
|
|
20
21
|
- **Live reload** - Watch mode automatically reloads on file changes
|
|
21
22
|
- **Deterministic merging** - Predictable cascading from base to profile files
|
|
@@ -125,8 +126,8 @@ OPTIONAL_KEY=
|
|
|
125
126
|
|
|
126
127
|
Files are loaded and merged in this order (later files override earlier ones):
|
|
127
128
|
|
|
128
|
-
1. `.menv` - Base configuration
|
|
129
|
-
2. `.menv.local` - Local overrides
|
|
129
|
+
1. `.menv` - Base configuration
|
|
130
|
+
2. `.menv.local` - Local overrides
|
|
130
131
|
3. `.menv.{profile}` - Profile-specific config (e.g., `.menv.prod`)
|
|
131
132
|
4. `.menv.{profile}.local` - Profile + local overrides (e.g., `.menv.prod.local`)
|
|
132
133
|
|
|
@@ -139,6 +140,18 @@ Files are loaded and merged in this order (later files override earlier ones):
|
|
|
139
140
|
Final result: PORT=9000, DEBUG=false
|
|
140
141
|
```
|
|
141
142
|
|
|
143
|
+
**Debug mode** - Use `debug: true` to see which files override values:
|
|
144
|
+
```javascript
|
|
145
|
+
load({ profile: 'prod', debug: true });
|
|
146
|
+
// Console output:
|
|
147
|
+
// [molex-env] Override: DEBUG
|
|
148
|
+
// Previous: .menv:2 = true
|
|
149
|
+
// New: .menv.local:1 = false
|
|
150
|
+
// [molex-env] Override: PORT
|
|
151
|
+
// Previous: .menv.local:3 = 3000
|
|
152
|
+
// New: .menv.prod:1 = 8080
|
|
153
|
+
```
|
|
154
|
+
|
|
142
155
|
## API Reference
|
|
143
156
|
|
|
144
157
|
### `load(options)` → `Object`
|
|
@@ -153,12 +166,13 @@ Load, merge, parse, and validate .menv files. This is the primary method you'll
|
|
|
153
166
|
| `profile` | `string` | `undefined` | Profile name for `.menv.{profile}` files |
|
|
154
167
|
| `files` | `Array<string>` | Auto-detected | Custom file list (absolute or relative to cwd) |
|
|
155
168
|
| `schema` | `Object` | `{}` | Schema definition for validation and typing |
|
|
156
|
-
| `strict` | `boolean` | `false` | Reject unknown keys, duplicates, and invalid lines |
|
|
169
|
+
| `strict` | `boolean` | `false` | Reject unknown keys, within-file duplicates, and invalid lines |
|
|
157
170
|
| `cast` | `boolean\|Object` | `true` | Enable/disable type casting (see Type Casting) |
|
|
158
171
|
| `exportEnv` | `boolean` | `false` | Write parsed values to `process.env` |
|
|
159
172
|
| `override` | `boolean` | `false` | Override existing `process.env` values |
|
|
160
173
|
| `attach` | `boolean` | `true` | Attach parsed values to `process.menv` |
|
|
161
174
|
| `freeze` | `boolean` | `true` | Deep-freeze the parsed config object |
|
|
175
|
+
| `debug` | `boolean` | `false` | Log file precedence overrides to console |
|
|
162
176
|
| `onWarning` | `Function` | `undefined` | Callback for non-strict warnings |
|
|
163
177
|
|
|
164
178
|
**Returns:**
|
|
@@ -213,10 +227,12 @@ Parse a string of .menv content without loading files. Useful for testing or pro
|
|
|
213
227
|
| Option | Type | Default | Description |
|
|
214
228
|
|--------|------|---------|-------------|
|
|
215
229
|
| `schema` | `Object` | `{}` | Schema definition for validation |
|
|
216
|
-
| `strict` | `boolean` | `false` | Enable strict validation |
|
|
230
|
+
| `strict` | `boolean` | `false` | Enable strict validation (rejects unknown keys, within-file duplicates, invalid lines) |
|
|
217
231
|
| `cast` | `boolean\|Object` | `true` | Enable/disable type casting |
|
|
218
232
|
| `freeze` | `boolean` | `true` | Deep-freeze the result |
|
|
219
233
|
|
|
234
|
+
> **Note:** The `parse()` function processes a single string, so the `debug` option for file precedence and cross-file features don't apply here.
|
|
235
|
+
|
|
220
236
|
**Returns:**
|
|
221
237
|
|
|
222
238
|
```javascript
|
|
@@ -261,23 +277,62 @@ Watch .menv files and reload automatically when they change. Perfect for develop
|
|
|
261
277
|
|
|
262
278
|
**Arguments:**
|
|
263
279
|
|
|
264
|
-
- `options` - Same options as `load()`
|
|
280
|
+
- `options` - Same options as `load()`, including `debug` for automatic change logging
|
|
265
281
|
- `onChange(error, result)` - Callback fired on file changes
|
|
266
282
|
|
|
267
|
-
**
|
|
283
|
+
**Automatic Change Detection:**
|
|
284
|
+
|
|
285
|
+
When `debug: true` is enabled, watch mode automatically logs what values changed on each reload:
|
|
268
286
|
|
|
269
287
|
```javascript
|
|
270
288
|
const { watch } = require('molex-env');
|
|
271
289
|
|
|
272
|
-
|
|
273
|
-
|
|
290
|
+
watch({
|
|
291
|
+
profile: 'dev',
|
|
292
|
+
debug: true, // Automatically logs changes
|
|
293
|
+
schema: {
|
|
294
|
+
PORT: 'number',
|
|
295
|
+
DEBUG: 'boolean',
|
|
296
|
+
SERVICE_URL: 'string'
|
|
297
|
+
}
|
|
298
|
+
}, (err, result) => {
|
|
299
|
+
if (err) {
|
|
300
|
+
console.error('Config reload failed:', err.message);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
console.log('✅ Config successfully reloaded');
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// When you edit .menv files, automatic output:
|
|
307
|
+
// [molex-env] Config reloaded - changes detected:
|
|
308
|
+
// PORT: 3000 → 8080
|
|
309
|
+
// SERVICE_URL: https://api.example.com → https://api.production.com
|
|
310
|
+
// ✅ Config successfully reloaded
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Manual Change Detection:**
|
|
314
|
+
|
|
315
|
+
Without `debug: true`, you can manually detect changes in your callback:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
let currentConfig;
|
|
319
|
+
|
|
320
|
+
watch({ profile: 'dev' }, (err, result) => {
|
|
274
321
|
if (err) {
|
|
275
322
|
console.error('Config reload failed:', err.message);
|
|
276
323
|
return;
|
|
277
324
|
}
|
|
278
325
|
|
|
279
|
-
|
|
280
|
-
|
|
326
|
+
if (!currentConfig) {
|
|
327
|
+
console.log('Initial config loaded');
|
|
328
|
+
} else {
|
|
329
|
+
// Manually check what changed
|
|
330
|
+
if (currentConfig.PORT !== result.parsed.PORT) {
|
|
331
|
+
console.log(`PORT changed: ${currentConfig.PORT} → ${result.parsed.PORT}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
currentConfig = result.parsed;
|
|
281
336
|
|
|
282
337
|
// Restart your server or update app state here
|
|
283
338
|
if (global.server) {
|
|
@@ -309,10 +364,17 @@ function startServer(config) {
|
|
|
309
364
|
const initial = require('molex-env').load({ profile: 'dev' });
|
|
310
365
|
server = startServer(initial.parsed);
|
|
311
366
|
|
|
312
|
-
// Watch for changes
|
|
313
|
-
watch({
|
|
367
|
+
// Watch for changes with automatic change logging
|
|
368
|
+
watch({
|
|
369
|
+
profile: 'dev',
|
|
370
|
+
debug: true,
|
|
371
|
+
schema: {
|
|
372
|
+
PORT: 'number',
|
|
373
|
+
DEBUG: 'boolean'
|
|
374
|
+
}
|
|
375
|
+
}, (err, result) => {
|
|
314
376
|
if (!err && result.parsed.PORT !== initial.parsed.PORT) {
|
|
315
|
-
console.log('Port changed, restarting...');
|
|
377
|
+
console.log('Port changed, restarting server...');
|
|
316
378
|
server.close(() => {
|
|
317
379
|
server = startServer(result.parsed);
|
|
318
380
|
});
|
|
@@ -452,9 +514,10 @@ Strict mode provides rigorous validation to catch configuration errors early.
|
|
|
452
514
|
|
|
453
515
|
When `strict: true`:
|
|
454
516
|
- ❌ **Unknown keys** - Keys not in schema are rejected
|
|
455
|
-
- ❌ **Duplicate keys** - Same key in
|
|
517
|
+
- ❌ **Duplicate keys** - Same key appearing twice **in the same file** throws error
|
|
518
|
+
- **Note:** File precedence still works - different files can define the same key
|
|
456
519
|
- ❌ **Invalid lines** - Malformed lines throw errors
|
|
457
|
-
-
|
|
520
|
+
- ✅ **Type validation** - When schema is present, type mismatches throw errors (enabled by default with schema)
|
|
458
521
|
|
|
459
522
|
**Example:**
|
|
460
523
|
|
|
@@ -473,28 +536,56 @@ load({
|
|
|
473
536
|
});
|
|
474
537
|
```
|
|
475
538
|
|
|
539
|
+
**Valid with strict mode (different files):**
|
|
540
|
+
```javascript
|
|
541
|
+
// .menv
|
|
542
|
+
PORT=3000
|
|
543
|
+
|
|
544
|
+
// .menv.prod
|
|
545
|
+
PORT=8080 // ✅ OK - overrides from different file
|
|
546
|
+
|
|
547
|
+
load({ profile: 'prod', strict: true });
|
|
548
|
+
// Result: PORT=8080
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Invalid with strict mode (same file):**
|
|
552
|
+
```javascript
|
|
553
|
+
// .menv
|
|
554
|
+
PORT=3000
|
|
555
|
+
PORT=8080 // ❌ ERROR - duplicate in same file
|
|
556
|
+
|
|
557
|
+
load({ strict: true }); // Throws error
|
|
558
|
+
```
|
|
559
|
+
|
|
476
560
|
### Non-Strict Mode (Default)
|
|
477
561
|
|
|
478
|
-
Without strict mode:
|
|
562
|
+
Without strict mode, the file precedence feature works as intended:
|
|
479
563
|
- ✅ Unknown keys are allowed and parsed
|
|
480
|
-
- ✅
|
|
564
|
+
- ✅ **Duplicate keys override** - Later files can override keys from earlier files
|
|
481
565
|
- ✅ Invalid lines are skipped
|
|
482
|
-
- ⚠️ Warnings can be logged via `onWarning` callback
|
|
566
|
+
- ⚠️ Warnings can be logged via `onWarning` callback for within-file duplicates
|
|
483
567
|
|
|
484
568
|
**Example with warning handler:**
|
|
485
569
|
|
|
486
570
|
```javascript
|
|
571
|
+
// .menv file with duplicate keys
|
|
572
|
+
// PORT=3000
|
|
573
|
+
// PORT=8080
|
|
574
|
+
|
|
487
575
|
load({
|
|
488
|
-
schema: { PORT: 'number' },
|
|
489
576
|
strict: false,
|
|
490
577
|
onWarning: (info) => {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
578
|
+
if (info.type === 'duplicate') {
|
|
579
|
+
console.warn(`Warning: Duplicate key '${info.key}' in ${info.file}:${info.line}`);
|
|
580
|
+
}
|
|
494
581
|
}
|
|
495
582
|
});
|
|
583
|
+
// Output: Warning: Duplicate key 'PORT' in .menv:2
|
|
584
|
+
// Result: PORT=8080 (last value wins)
|
|
496
585
|
```
|
|
497
586
|
|
|
587
|
+
**Tip:** Use `debug: true` to see cross-file overrides (file precedence), or `onWarning` to catch within-file duplicates.
|
|
588
|
+
|
|
498
589
|
---
|
|
499
590
|
|
|
500
591
|
## Origin Tracking
|
|
@@ -612,10 +703,9 @@ console.log(`PORT: ${process.menv.PORT}`);
|
|
|
612
703
|
```javascript
|
|
613
704
|
const { watch } = require('molex-env');
|
|
614
705
|
|
|
615
|
-
let currentConfig;
|
|
616
|
-
|
|
617
706
|
watch({
|
|
618
707
|
profile: 'dev',
|
|
708
|
+
debug: true, // Automatic change detection
|
|
619
709
|
schema: {
|
|
620
710
|
PORT: 'number',
|
|
621
711
|
DEBUG: 'boolean',
|
|
@@ -627,24 +717,15 @@ watch({
|
|
|
627
717
|
return;
|
|
628
718
|
}
|
|
629
719
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
console.log('Initial config loaded');
|
|
633
|
-
} else {
|
|
634
|
-
// Detect what changed
|
|
635
|
-
Object.keys(result.parsed).forEach(key => {
|
|
636
|
-
if (currentConfig[key] !== result.parsed[key]) {
|
|
637
|
-
changed.push(`${key}: ${currentConfig[key]} → ${result.parsed[key]}`);
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
if (changed.length > 0) {
|
|
642
|
-
console.log('Config updated:', changed.join(', '));
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
currentConfig = result.parsed;
|
|
720
|
+
console.log('Config reloaded and ready to use');
|
|
721
|
+
// result.parsed has the new values
|
|
647
722
|
});
|
|
723
|
+
|
|
724
|
+
console.log('Watching for changes...');
|
|
725
|
+
// Output on file change:
|
|
726
|
+
// [molex-env] Config reloaded - changes detected:
|
|
727
|
+
// DEBUG: false → true
|
|
728
|
+
// API_URL: https://api.example.com → https://api.dev.local
|
|
648
729
|
```
|
|
649
730
|
|
|
650
731
|
### Validation and Error Handling
|
|
@@ -685,34 +766,19 @@ try {
|
|
|
685
766
|
|
|
686
767
|
## Best Practices
|
|
687
768
|
|
|
688
|
-
### Git Configuration
|
|
689
|
-
|
|
690
|
-
Add to `.gitignore`:
|
|
691
|
-
```gitignore
|
|
692
|
-
# Keep base configs in git
|
|
693
|
-
# .menv
|
|
694
|
-
# .menv.dev
|
|
695
|
-
# .menv.prod
|
|
696
|
-
|
|
697
|
-
# Ignore local overrides (machine-specific, secrets)
|
|
698
|
-
.menv.local
|
|
699
|
-
.menv.*.local
|
|
700
|
-
```
|
|
701
|
-
|
|
702
769
|
### Environment Strategy
|
|
703
770
|
|
|
704
771
|
```
|
|
705
772
|
Development: .menv + .menv.local
|
|
706
773
|
Staging: .menv + .menv.staging
|
|
707
|
-
Production: .menv + .menv.prod + .menv.prod.local
|
|
774
|
+
Production: .menv + .menv.prod + .menv.prod.local
|
|
708
775
|
```
|
|
709
776
|
|
|
710
777
|
### Security Tips
|
|
711
778
|
|
|
712
|
-
- ✅ **DO** use
|
|
713
|
-
- ✅ **DO** use `
|
|
779
|
+
- ✅ **DO** use `strict: true` in production to catch unknown keys and configuration errors
|
|
780
|
+
- ✅ **DO** use `debug: true` during development to understand file precedence
|
|
714
781
|
- ✅ **DO** validate sensitive values (URLs, ports, etc.) after loading
|
|
715
|
-
- ❌ **DON'T** commit production secrets to git
|
|
716
782
|
- ❌ **DON'T** use `exportEnv: true` if you need immutable config
|
|
717
783
|
|
|
718
784
|
### Performance
|
|
@@ -748,11 +814,25 @@ The example demonstrates:
|
|
|
748
814
|
|
|
749
815
|
**Problem:** Getting errors about unknown keys when loading config.
|
|
750
816
|
|
|
751
|
-
**
|
|
817
|
+
**Cause:** You have a key in your `.menv` file that isn't defined in your schema, and `strict: true` is enabled.
|
|
818
|
+
|
|
819
|
+
**Solution:** Either add the key to your schema or disable strict mode:
|
|
752
820
|
```javascript
|
|
753
|
-
|
|
821
|
+
// Option 1: Add missing key to schema
|
|
822
|
+
load({
|
|
823
|
+
strict: true,
|
|
824
|
+
schema: {
|
|
825
|
+
PORT: 'number',
|
|
826
|
+
YOUR_MISSING_KEY: 'string' // Add this
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
// Option 2: Disable strict mode to allow unknown keys
|
|
831
|
+
load({ strict: false });
|
|
754
832
|
```
|
|
755
833
|
|
|
834
|
+
> **Note:** This is different from "required" - unknown keys exist in your file but not in schema. Required keys exist in schema but not in your file.
|
|
835
|
+
|
|
756
836
|
### Values are strings instead of typed
|
|
757
837
|
|
|
758
838
|
**Problem:** `PORT` is `"3000"` (string) instead of `3000` (number).
|
|
@@ -786,6 +866,22 @@ METADATA={"key":"value"}
|
|
|
786
866
|
START_DATE=2026-02-02
|
|
787
867
|
```
|
|
788
868
|
|
|
869
|
+
### Understanding which file sets a value
|
|
870
|
+
|
|
871
|
+
**Problem:** Not sure which file is providing a specific config value.
|
|
872
|
+
|
|
873
|
+
**Solution:** Use `debug: true` to see file precedence in action:
|
|
874
|
+
```javascript
|
|
875
|
+
load({ profile: 'prod', debug: true });
|
|
876
|
+
// Shows console output for each override
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Or check the `origins` object:
|
|
880
|
+
```javascript
|
|
881
|
+
const result = load({ profile: 'prod' });
|
|
882
|
+
console.log(result.origins.PORT); // { file: '.menv.prod', line: 1, raw: '8080' }
|
|
883
|
+
```
|
|
884
|
+
|
|
789
885
|
---
|
|
790
886
|
|
|
791
887
|
## License
|
package/package.json
CHANGED
package/src/lib/apply.js
CHANGED
|
@@ -5,15 +5,15 @@ const { coerceType, autoCast } = require('./cast');
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Apply a parsed entry to the state with schema/type checks.
|
|
8
|
-
* @param {{values: object, origins: object,
|
|
8
|
+
* @param {{values: object, origins: object, seenPerFile: Map<string, Set<string>>}} state
|
|
9
9
|
* @param {{key: string, raw: string, line: number}} entry
|
|
10
|
-
* @param {{schema: object|null, strict: boolean, cast: object, onWarning?: Function}} options
|
|
10
|
+
* @param {{schema: object|null, strict: boolean, cast: object, onWarning?: Function, debug?: boolean}} options
|
|
11
11
|
* @param {string} filePath
|
|
12
12
|
* @returns {void}
|
|
13
13
|
*/
|
|
14
14
|
function applyEntry(state, entry, options, filePath)
|
|
15
15
|
{
|
|
16
|
-
const { schema, strict, cast, onWarning } = options;
|
|
16
|
+
const { schema, strict, cast, onWarning, debug } = options;
|
|
17
17
|
const { key, raw, line } = entry;
|
|
18
18
|
|
|
19
19
|
if (schema && strict && !schema[key])
|
|
@@ -21,7 +21,15 @@ function applyEntry(state, entry, options, filePath)
|
|
|
21
21
|
throw unknownKeyError(key, filePath, line);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if
|
|
24
|
+
// Initialize per-file tracking if needed
|
|
25
|
+
if (!state.seenPerFile.has(filePath))
|
|
26
|
+
{
|
|
27
|
+
state.seenPerFile.set(filePath, new Set());
|
|
28
|
+
}
|
|
29
|
+
const fileKeys = state.seenPerFile.get(filePath);
|
|
30
|
+
|
|
31
|
+
// Check for duplicates ONLY within the same file
|
|
32
|
+
if (fileKeys.has(key))
|
|
25
33
|
{
|
|
26
34
|
if (strict)
|
|
27
35
|
{
|
|
@@ -38,6 +46,15 @@ function applyEntry(state, entry, options, filePath)
|
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
|
|
49
|
+
// Debug logging for file precedence
|
|
50
|
+
if (debug && state.values[key] !== undefined)
|
|
51
|
+
{
|
|
52
|
+
const prevOrigin = state.origins[key];
|
|
53
|
+
console.log(`[molex-env] Override: ${key}`);
|
|
54
|
+
console.log(` Previous: ${prevOrigin.file}:${prevOrigin.line} = ${prevOrigin.raw}`);
|
|
55
|
+
console.log(` New: ${filePath}:${line} = ${raw}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
const def = schema ? schema[key] : null;
|
|
42
59
|
let value;
|
|
43
60
|
if (def && def.type)
|
|
@@ -50,7 +67,7 @@ function applyEntry(state, entry, options, filePath)
|
|
|
50
67
|
|
|
51
68
|
state.values[key] = value;
|
|
52
69
|
state.origins[key] = { file: filePath, line, raw };
|
|
53
|
-
|
|
70
|
+
fileKeys.add(key);
|
|
54
71
|
}
|
|
55
72
|
|
|
56
73
|
module.exports = {
|
package/src/lib/core.js
CHANGED
|
@@ -11,14 +11,14 @@ const { deepFreeze } = require('./utils');
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Build a new parsing state container.
|
|
14
|
-
* @returns {{values: object, origins: object,
|
|
14
|
+
* @returns {{values: object, origins: object, seenPerFile: Map<string, Set<string>>}}
|
|
15
15
|
*/
|
|
16
16
|
function buildState()
|
|
17
17
|
{
|
|
18
18
|
return {
|
|
19
19
|
values: {},
|
|
20
20
|
origins: {},
|
|
21
|
-
|
|
21
|
+
seenPerFile: new Map()
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -79,7 +79,8 @@ function load(options = {})
|
|
|
79
79
|
schema: normalizedSchema,
|
|
80
80
|
strict,
|
|
81
81
|
cast,
|
|
82
|
-
onWarning: options.onWarning
|
|
82
|
+
onWarning: options.onWarning,
|
|
83
|
+
debug: options.debug
|
|
83
84
|
}, filePath);
|
|
84
85
|
}
|
|
85
86
|
readFiles.push(filePath);
|
package/src/lib/watch.js
CHANGED
|
@@ -27,6 +27,7 @@ function watch(options, onChange, load)
|
|
|
27
27
|
const basenames = new Set(files.map((file) => path.basename(file)));
|
|
28
28
|
const watchers = [];
|
|
29
29
|
let timer = null;
|
|
30
|
+
let previousConfig = null;
|
|
30
31
|
|
|
31
32
|
const trigger = () =>
|
|
32
33
|
{
|
|
@@ -35,7 +36,40 @@ function watch(options, onChange, load)
|
|
|
35
36
|
{
|
|
36
37
|
try
|
|
37
38
|
{
|
|
38
|
-
|
|
39
|
+
// Disable file precedence debug during reload to avoid conflicts with watch change detection
|
|
40
|
+
const reloadOptions = { ...options, debug: false };
|
|
41
|
+
const result = load(reloadOptions);
|
|
42
|
+
|
|
43
|
+
// Auto-detect changes if debug mode was enabled
|
|
44
|
+
if (options.debug && previousConfig)
|
|
45
|
+
{
|
|
46
|
+
const changes = [];
|
|
47
|
+
for (const key in result.parsed)
|
|
48
|
+
{
|
|
49
|
+
const oldValue = previousConfig[key];
|
|
50
|
+
const newValue = result.parsed[key];
|
|
51
|
+
|
|
52
|
+
// Compare values (handle dates and objects)
|
|
53
|
+
const oldStr = oldValue instanceof Date ? oldValue.toISOString() : JSON.stringify(oldValue);
|
|
54
|
+
const newStr = newValue instanceof Date ? newValue.toISOString() : JSON.stringify(newValue);
|
|
55
|
+
|
|
56
|
+
if (oldStr !== newStr)
|
|
57
|
+
{
|
|
58
|
+
changes.push({ key, old: oldValue, new: newValue });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (changes.length > 0)
|
|
63
|
+
{
|
|
64
|
+
console.log('[molex-env] Config reloaded - changes detected:');
|
|
65
|
+
changes.forEach(({ key, old, new: newVal }) =>
|
|
66
|
+
{
|
|
67
|
+
console.log(` ${key}: ${old} → ${newVal}`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
previousConfig = { ...result.parsed };
|
|
39
73
|
onChange(null, result);
|
|
40
74
|
} catch (err)
|
|
41
75
|
{
|