@calvear/env 3.0.1 โ 3.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.
- package/CHANGELOG.md +14 -0
- package/README.md +603 -515
- package/arguments.js +1 -1
- package/arguments.js.map +1 -1
- package/assets/logo.svg +30 -30
- package/commands/export.command.js +1 -1
- package/commands/export.command.js.map +1 -1
- package/commands/pull.command.js.map +1 -1
- package/commands/push.command.js.map +1 -1
- package/commands/schema.command.js.map +1 -1
- package/main.js.map +1 -1
- package/package.json +2 -1
- package/providers/index.js.map +1 -1
- package/providers/secrets.provider.js.map +1 -1
- package/schemas/settings.schema.json +2 -2
- package/utils/argv.util.js.map +1 -1
- package/utils/logger.d.ts.map +1 -1
- package/utils/logger.js +14 -9
- package/utils/logger.js.map +1 -1
- package/utils/normalize.util.d.ts +4 -0
- package/utils/normalize.util.d.ts.map +1 -1
- package/utils/normalize.util.js +1 -1
- package/utils/normalize.util.js.map +1 -1
- package/utils/schema.util.d.ts.map +1 -1
- package/utils/schema.util.js +2 -2
- package/utils/schema.util.js.map +1 -1
- package/utils/ui.d.ts.map +1 -1
- package/utils/ui.js +54 -31
- package/utils/ui.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,515 +1,603 @@
|
|
|
1
|
-
<div id="top" align="center">
|
|
2
|
-
<img alt="@calvear/env logo" src="assets/logo.svg" width="150" />
|
|
3
|
-
|
|
4
|
-
<h1 align="center"><b>env</b></h1>
|
|
5
|
-
<h4 align="center">Environment variables made easy โ load, validate, inject.</h4>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
<img src="https://img.shields.io/npm/v/@calvear/env?style=flat-square&color=2563eb&label=version" alt="version" />
|
|
9
|
-
|
|
10
|
-
<img src="https://img.shields.io/badge/module-ESM-f59e0b?style=flat-square" alt="esm" />
|
|
11
|
-
|
|
12
|
-
<img src="https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white" alt="typescript" />
|
|
13
|
-
|
|
14
|
-
<img src="https://img.shields.io/badge/node->=20-339933?style=flat-square&logo=node.js&logoColor=white" alt="node engine" />
|
|
15
|
-
|
|
16
|
-
<img src="https://img.shields.io/badge/coverage-100%25-22c55e?style=flat-square" alt="coverage" />
|
|
17
|
-
|
|
18
|
-
<img src="https://img.shields.io/npm/l/@calvear/env?style=flat-square&color=eab308" alt="license" />
|
|
19
|
-
</p>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<br />
|
|
23
|
-
|
|
24
|
-
<!-- ABOUT -->
|
|
25
|
-
|
|
26
|
-
## ๐ About
|
|
27
|
-
|
|
28
|
-
`@calvear/env` eases **environment variable handling** for NodeJS apps โ like
|
|
29
|
-
[env-cmd](https://www.npmjs.com/package/env-cmd) or
|
|
30
|
-
[dotenv](https://www.npmjs.com/package/dotenv), but with **powerful, extensible
|
|
31
|
-
features**: pluggable **providers** to `load`, `pull` and `push` variables from
|
|
32
|
-
different stores, **JSON Schema validation**, value **interpolation**, secret
|
|
33
|
-
**masking** and nested/shared keys.
|
|
34
|
-
|
|
35
|
-
### โจ Features
|
|
36
|
-
|
|
37
|
-
- ๐งฉ **Provider plugins** โ bundled `package-json`, `app-settings`, `secrets`
|
|
38
|
-
and `local` providers, plus your own (NPM package or local script).
|
|
39
|
-
- ๐ **Injection** โ load variables into `process.env` and run any command.
|
|
40
|
-
- โ
**JSON Schema** โ auto-generate and validate variables before injecting.
|
|
41
|
-
- ๐ช **Nested &
|
|
42
|
-
keys.
|
|
43
|
-
- ๐งต **Interpolation** โ reference other args/vars with `[[ ]]` delimiters.
|
|
44
|
-
- ๐ **Masking** โ hide
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
env
|
|
102
|
-
env
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
|
172
|
-
|
|
|
173
|
-
|
|
|
174
|
-
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
|
181
|
-
|
|
|
182
|
-
| `-
|
|
183
|
-
| `--
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
|
189
|
-
|
|
|
190
|
-
| `--
|
|
191
|
-
| `--
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
| Option
|
|
322
|
-
|
|
|
323
|
-
| `--
|
|
324
|
-
|
|
325
|
-
### `
|
|
326
|
-
|
|
327
|
-
Loads
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
| Option
|
|
331
|
-
|
|
|
332
|
-
| `--
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
],
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
1
|
+
<div id="top" align="center">
|
|
2
|
+
<img alt="@calvear/env logo" src="assets/logo.svg" width="150" />
|
|
3
|
+
|
|
4
|
+
<h1 align="center"><b>env</b></h1>
|
|
5
|
+
<h4 align="center">Environment variables made easy โ load, validate, inject.</h4>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="https://img.shields.io/npm/v/@calvear/env?style=flat-square&color=2563eb&label=version" alt="version" />
|
|
9
|
+
|
|
10
|
+
<img src="https://img.shields.io/badge/module-ESM-f59e0b?style=flat-square" alt="esm" />
|
|
11
|
+
|
|
12
|
+
<img src="https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white" alt="typescript" />
|
|
13
|
+
|
|
14
|
+
<img src="https://img.shields.io/badge/node->=20-339933?style=flat-square&logo=node.js&logoColor=white" alt="node engine" />
|
|
15
|
+
|
|
16
|
+
<img src="https://img.shields.io/badge/coverage-100%25-22c55e?style=flat-square" alt="coverage" />
|
|
17
|
+
|
|
18
|
+
<img src="https://img.shields.io/npm/l/@calvear/env?style=flat-square&color=eab308" alt="license" />
|
|
19
|
+
</p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<br />
|
|
23
|
+
|
|
24
|
+
<!-- ABOUT -->
|
|
25
|
+
|
|
26
|
+
## ๐ About
|
|
27
|
+
|
|
28
|
+
`@calvear/env` eases **environment variable handling** for NodeJS apps โ like
|
|
29
|
+
[env-cmd](https://www.npmjs.com/package/env-cmd) or
|
|
30
|
+
[dotenv](https://www.npmjs.com/package/dotenv), but with **powerful, extensible
|
|
31
|
+
features**: pluggable **providers** to `load`, `pull` and `push` variables from
|
|
32
|
+
different stores, **JSON Schema validation**, value **interpolation**, secret
|
|
33
|
+
**masking** and nested/shared keys.
|
|
34
|
+
|
|
35
|
+
### โจ Features
|
|
36
|
+
|
|
37
|
+
- ๐งฉ **Provider plugins** โ bundled `package-json`, `app-settings`, `secrets`
|
|
38
|
+
and `local` providers, plus your own (NPM package or local script).
|
|
39
|
+
- ๐ **Injection** โ load variables into `process.env` and run any command.
|
|
40
|
+
- โ
**JSON Schema** โ auto-generate and validate variables before injecting.
|
|
41
|
+
- ๐ช **Nested & global keys** โ `GROUP__VAR` flattening and `$`-prefixed global
|
|
42
|
+
keys (the `$` marker is stripped on injection).
|
|
43
|
+
- ๐งต **Interpolation** โ reference other args/vars with `[[ ]]` delimiters.
|
|
44
|
+
- ๐ **Masking** โ hide secrets in the debug output by key name, key regex, or
|
|
45
|
+
value content regex.
|
|
46
|
+
- ๐จ **Pretty output** โ colorized, sorted, masked debug render of the resolved
|
|
47
|
+
environment.
|
|
48
|
+
- ๐ค **Export** โ write the unified environment to a `.env` or JSON file.
|
|
49
|
+
|
|
50
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
51
|
+
|
|
52
|
+
<!-- REQUIREMENTS -->
|
|
53
|
+
|
|
54
|
+
## ๐ Requirements
|
|
55
|
+
|
|
56
|
+
[NodeJS](https://nodejs.org/) **20 or higher**.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
> node -v
|
|
60
|
+
v20.0.0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
64
|
+
|
|
65
|
+
<!-- ESM -->
|
|
66
|
+
|
|
67
|
+
## ๐ฆ ESM only
|
|
68
|
+
|
|
69
|
+
Since **v3** this package is **ESM-only** (`"type": "module"`). Consumers must
|
|
70
|
+
use ESM `import` syntax, and custom providers must be ESM modules that `export`
|
|
71
|
+
their provider object.
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
// โ
ESM
|
|
75
|
+
import { EnvProvider } from '@calvear/env';
|
|
76
|
+
|
|
77
|
+
// โ CommonJS require is not supported
|
|
78
|
+
// const { EnvProvider } = require('@calvear/env');
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
82
|
+
|
|
83
|
+
<!-- QUICK START -->
|
|
84
|
+
|
|
85
|
+
## โก๏ธ Quick start
|
|
86
|
+
|
|
87
|
+
Install the package:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
> npm install @calvear/env
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Run the binary directly:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
> npx env --help
|
|
97
|
+
|
|
98
|
+
Usage: env [command] [options..] [: subcmd [:]] [options..]
|
|
99
|
+
|
|
100
|
+
Commands:
|
|
101
|
+
env [options..] [: <subcmd> :]
|
|
102
|
+
env pull [options..]
|
|
103
|
+
env push [options..]
|
|
104
|
+
env schema [options..]
|
|
105
|
+
env export [options..]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Or wire it into your **npm scripts**:
|
|
109
|
+
|
|
110
|
+
```jsonc
|
|
111
|
+
{
|
|
112
|
+
"scripts": {
|
|
113
|
+
// inject "dev" variables (debug mode) and start the app
|
|
114
|
+
"start:dev": "env -e dev -m debug : node dist/main.js",
|
|
115
|
+
// inject "prod" variables for the build
|
|
116
|
+
"build:prod": "env -e prod -m build : tsc",
|
|
117
|
+
// regenerate the validation schema
|
|
118
|
+
"env:schema": "env schema -e dev",
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run it:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
> npm run start:dev
|
|
127
|
+
|
|
128
|
+
โก env v3.0.0 ยท ๐ dev ยท ๐งฉ debug
|
|
129
|
+
|
|
130
|
+
๐ฆ package-json 6 vars
|
|
131
|
+
๐๏ธ app-settings 5 vars
|
|
132
|
+
๐ secrets 1 secrets
|
|
133
|
+
๐ local 1 vars
|
|
134
|
+
|
|
135
|
+
environment (12 variables)
|
|
136
|
+
ENV = dev
|
|
137
|
+
NODE_ENV = development
|
|
138
|
+
SECRET = *****
|
|
139
|
+
VERSION = 3.0.0
|
|
140
|
+
...
|
|
141
|
+
|
|
142
|
+
โ 12 variables loaded in 142ms
|
|
143
|
+
|
|
144
|
+
โถ node dist/main.js
|
|
145
|
+
My environment loaded is: dev
|
|
146
|
+
โ finished in 168ms
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
> The resolved environment is only rendered at `--log debug`. Values are
|
|
150
|
+
> **sorted**, **secrets are masked**, and colored by type โ strings in gray,
|
|
151
|
+
> numbers in orange, booleans `true`/`false` in green/red.
|
|
152
|
+
|
|
153
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
154
|
+
|
|
155
|
+
<!-- COMMANDS AND OPTIONS -->
|
|
156
|
+
|
|
157
|
+
## โ๏ธ Commands & Options
|
|
158
|
+
|
|
159
|
+
> **Interpolation** โ any option value can reference other arguments using `[[`
|
|
160
|
+
> and `]]` delimiters. With `root: "config"`, the value `[[root]]/file.json`
|
|
161
|
+
> resolves to `config/file.json`; with `env: "dev"`,
|
|
162
|
+
> `[[root]]/config.[[env]].json` resolves to `config/config.dev.json`.
|
|
163
|
+
|
|
164
|
+
### Global options
|
|
165
|
+
|
|
166
|
+
| Option | Description | Type | Default |
|
|
167
|
+
| ---------------------------------- | ------------------------------------------------- | ---------- | ------- |
|
|
168
|
+
| `--help` | Show help | `boolean` | |
|
|
169
|
+
| `-e, --env` | Environment to load (i.e. `dev`, `prod`) | `string` | |
|
|
170
|
+
| `-m, --modes` | Execution modes (i.e. `debug`, `test`) | `string[]` | `[]` |
|
|
171
|
+
| `--nd, --nestingDelimiter` | Nesting-level delimiter for flatten | `string` | `__` |
|
|
172
|
+
| `--arrDesc, --arrayDescomposition` | Serialize (`false`) or break down (`true`) arrays | `boolean` | `false` |
|
|
173
|
+
| `-x, --expand` | Interpolate environment variables using itself | `boolean` | `false` |
|
|
174
|
+
| `--ci` | Continuous Integration mode (skips local files) | `boolean` | auto |
|
|
175
|
+
|
|
176
|
+
### Workspace options
|
|
177
|
+
|
|
178
|
+
| Option | Description | Type | Default |
|
|
179
|
+
| ---------------------- | --------------------------------- | -------- | --------------------------------- |
|
|
180
|
+
| `--root` | Base environment folder path | `string` | `env` |
|
|
181
|
+
| `-c, --configFile` | Config JSON file path | `string` | `[[root]]/settings/settings.json` |
|
|
182
|
+
| `-s, --schemaFile` | Environment schema JSON file path | `string` | `[[root]]/settings/schema.json` |
|
|
183
|
+
| `--pkg, --packageJson` | `package.json` path | `string` | _cwd_ |
|
|
184
|
+
|
|
185
|
+
### JSON Schema options
|
|
186
|
+
|
|
187
|
+
| Option | Description | Type | Default |
|
|
188
|
+
| ---------------------- | ---------------------------------------------- | ------------------ | ------- |
|
|
189
|
+
| `-r, --resolve` | Merge new schema or override it | `merge`/`override` | `merge` |
|
|
190
|
+
| `--null, --nullable` | Whether variables are nullable by default | `boolean` | `true` |
|
|
191
|
+
| `--df, --detectFormat` | Include string formats in the generated schema | `boolean` | `false` |
|
|
192
|
+
|
|
193
|
+
### Logger options
|
|
194
|
+
|
|
195
|
+
| Option | Description | Type | Default |
|
|
196
|
+
| ------------------------------ | ------------------------------------------------------ | --------------------------------------------- | ------- |
|
|
197
|
+
| `--log, --logLevel` | Log level | `silly`/`trace`/`debug`/`info`/`warn`/`error` | `info` |
|
|
198
|
+
| `--mvk, --logMaskValuesOfKeys` | Mask a value when its **key** matches (exact or regex) | `string[]` | `[]` |
|
|
199
|
+
| `--mrx, --logMaskAnyRegEx` | Mask **value content** matching a regex (every match) | `string[]` | `[]` |
|
|
200
|
+
|
|
201
|
+
See [๐ Masking secrets](#-masking-secrets) for the full masking semantics.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### `env`
|
|
206
|
+
|
|
207
|
+
Inject environment variables into `process.env` and execute a command (the
|
|
208
|
+
command goes after `:`).
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
env -e <env> [options..] [: <subcmd> :] [options..]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
> env -e dev -m test unit : npm test
|
|
216
|
+
> env -e dev -m debug : npm start : -c [[root]]/[[env]].env.json
|
|
217
|
+
> env -e prod -m build optimize : npm run build
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
| Option | Description | Type | Default |
|
|
221
|
+
| ------------------------------ | ------------------------------------------ | --------- | ------- |
|
|
222
|
+
| `--validate, --schemaValidate` | Validate variables against the JSON schema | `boolean` | `true` |
|
|
223
|
+
|
|
224
|
+
### `pull`
|
|
225
|
+
|
|
226
|
+
Pull environment variables from the providers' stores (for providers that
|
|
227
|
+
implement `pull`, i.e. custom remote providers).
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
env pull -e <env> [options..]
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| Option | Description | Type | Default |
|
|
234
|
+
| ----------------- | ------------------------- | --------- | ------- |
|
|
235
|
+
| `-o, --overwrite` | Overwrite local variables | `boolean` | `false` |
|
|
236
|
+
|
|
237
|
+
### `push`
|
|
238
|
+
|
|
239
|
+
Push environment variables to the providers' stores (for providers that
|
|
240
|
+
implement `push`).
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
env push -e <env> [options..]
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
| Option | Description | Type | Default |
|
|
247
|
+
| ------------- | ---------------------- | --------- | ------- |
|
|
248
|
+
| `-f, --force` | Force push for secrets | `boolean` | `false` |
|
|
249
|
+
|
|
250
|
+
### `schema`
|
|
251
|
+
|
|
252
|
+
Generate (or update) the validation schema from the providers' output.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
> env schema -e dev -m build
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### `export`
|
|
259
|
+
|
|
260
|
+
Export the unified environment to a file.
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
env export -e <env> -m <modes> [options..]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
| Option | Description | Type | Default |
|
|
267
|
+
| --------------- | --------------------- | --------------- | -------- |
|
|
268
|
+
| `-u, -p, --uri` | Output file path | `string` | `.env` |
|
|
269
|
+
| `-f, --format` | Output format | `dotenv`/`json` | `dotenv` |
|
|
270
|
+
| `-q, --quotes` | Wrap values in quotes | `boolean` | `false` |
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
> env export -e dev -m build -f json --uri [[env]].env.json
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
277
|
+
|
|
278
|
+
<!-- PROVIDERS -->
|
|
279
|
+
|
|
280
|
+
## ๐ก Providers
|
|
281
|
+
|
|
282
|
+
Providers are the core of this library. It ships with **four integrated
|
|
283
|
+
providers**, and you can add your own.
|
|
284
|
+
|
|
285
|
+
### `package-json`
|
|
286
|
+
|
|
287
|
+
Loads project info from your `package.json` (`version`, `project`, `name`,
|
|
288
|
+
`title`, `description`) into `ENV`, `VERSION`, `PROJECT`, `NAME`, `TITLE`,
|
|
289
|
+
`DESCRIPTION`.
|
|
290
|
+
|
|
291
|
+
| Option | Description | Type | Default |
|
|
292
|
+
| ------------------- | ------------------------------- | -------- | ------- |
|
|
293
|
+
| `--vp, --varPrefix` | Prefix for the loaded variables | `string` | `""` |
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# i.e. expose them as REACT_APP_* for CRA
|
|
297
|
+
> env -e dev -m build : react-scripts build : --vp REACT_APP_
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### `app-settings`
|
|
301
|
+
|
|
302
|
+
Non-secret loader for `appsettings.json`, organized by sections:
|
|
303
|
+
|
|
304
|
+
```jsonc
|
|
305
|
+
{
|
|
306
|
+
"|DEFAULT|": { "VAR1": "v1_default" },
|
|
307
|
+
"|MODE|": {
|
|
308
|
+
"build": { "NODE_ENV": "production" },
|
|
309
|
+
"debug": { "NODE_ENV": "development" },
|
|
310
|
+
},
|
|
311
|
+
"|ENV|": {
|
|
312
|
+
"dev": {
|
|
313
|
+
"C1": "V1",
|
|
314
|
+
"GROUP1": { "VAR2": "G1V2", "GROUP2": { "VAR1": "G1G2V1" } },
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
"|LOCAL|": { "dev": { "LOCAL_VAR": "only-local" } },
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
| Option | Description | Type | Default |
|
|
322
|
+
| ----------------- | ----------------------------- | -------- | --------------------------- |
|
|
323
|
+
| `--ef, --envFile` | Non-secret settings file path | `string` | `[[root]]/appsettings.json` |
|
|
324
|
+
|
|
325
|
+
### `secrets`
|
|
326
|
+
|
|
327
|
+
Loads secret variables from a per-environment JSON file
|
|
328
|
+
(`[[root]]/[[env]].env.json`). Keep this file out of version control.
|
|
329
|
+
|
|
330
|
+
| Option | Description | Type | Default |
|
|
331
|
+
| --------------------- | -------------------------- | -------- | --------------------------- |
|
|
332
|
+
| `--sf, --secretsFile` | Secret variables file path | `string` | `[[root]]/[[env]].env.json` |
|
|
333
|
+
|
|
334
|
+
### `local`
|
|
335
|
+
|
|
336
|
+
Loads local-only variables (never loaded in `--ci`). The file is auto-created
|
|
337
|
+
if missing.
|
|
338
|
+
|
|
339
|
+
| Option | Description | Type | Default |
|
|
340
|
+
| ------------------- | ------------------------- | -------- | --------------------------------- |
|
|
341
|
+
| `--lf, --localFile` | Local variables file path | `string` | `[[root]]/[[env]].local.env.json` |
|
|
342
|
+
|
|
343
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
344
|
+
|
|
345
|
+
<!-- CUSTOM PROVIDERS -->
|
|
346
|
+
|
|
347
|
+
## โ๏ธ Creating custom providers
|
|
348
|
+
|
|
349
|
+
Create a provider in two ways:
|
|
350
|
+
|
|
351
|
+
- **Local script** โ a `.js` file that `export default`s your provider.
|
|
352
|
+
- **NPM package** โ a published module that `export default`s your provider.
|
|
353
|
+
|
|
354
|
+
Both are wired in the [config file](#-config) via the `providers` list. A custom
|
|
355
|
+
provider can also implement `pull`/`push` to fetch and publish variables from a
|
|
356
|
+
remote store (i.e. a vault, a secrets manager or an API).
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import type { CommandArguments, EnvProvider } from '@calvear/env';
|
|
360
|
+
import { logger, readJson, writeJson } from '@calvear/env/utils';
|
|
361
|
+
|
|
362
|
+
const KEY = 'my-unique-provider-key';
|
|
363
|
+
|
|
364
|
+
interface MyProviderArguments extends CommandArguments {
|
|
365
|
+
anyExtraOption: boolean;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const MyProvider: EnvProvider<MyProviderArguments> = {
|
|
369
|
+
// unique identifier
|
|
370
|
+
key: KEY,
|
|
371
|
+
|
|
372
|
+
// (optional) add custom options to the CLI via yargs
|
|
373
|
+
builder: (builder) => {
|
|
374
|
+
builder.options({
|
|
375
|
+
anyExtraOption: {
|
|
376
|
+
group: KEY,
|
|
377
|
+
alias: ['a', 'aeo'],
|
|
378
|
+
type: 'boolean',
|
|
379
|
+
default: false,
|
|
380
|
+
describe: 'Any option description',
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
// called on load โ may be sync or async, and may return a list to merge
|
|
386
|
+
load: ({ env }) => {
|
|
387
|
+
if (env === 'dev') return { NODE_ENV: 'development' };
|
|
388
|
+
|
|
389
|
+
return [{ NODE_ENV: 'production' }, { ANY_GROUP: { INNER_VAR: 12 } }];
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
// (optional) called on `env pull`
|
|
393
|
+
pull: (argv, config) => {
|
|
394
|
+
/* fetch variables into your local cache */
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
// (optional) called on `env push`
|
|
398
|
+
push: (argv, config) => {
|
|
399
|
+
/* publish/update your variables */
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
export default MyProvider;
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
407
|
+
|
|
408
|
+
<!-- CONFIG -->
|
|
409
|
+
|
|
410
|
+
## ๐ฅ Config
|
|
411
|
+
|
|
412
|
+
Any CLI argument can be set in your config file
|
|
413
|
+
(`[[root]]/settings/settings.json` by default), but it is mainly used to declare
|
|
414
|
+
**providers**:
|
|
415
|
+
|
|
416
|
+
```jsonc
|
|
417
|
+
{
|
|
418
|
+
"logLevel": "silly",
|
|
419
|
+
// mask secrets in the debug output (see the Masking section)
|
|
420
|
+
"logMaskValuesOfKeys": ["SECRET", "/token/i", "/api_key/i"],
|
|
421
|
+
"logMaskAnyRegEx": ["AKIA[0-9A-Z]{16}"],
|
|
422
|
+
"providers": [
|
|
423
|
+
{ "path": "package-json" },
|
|
424
|
+
{ "path": "app-settings" },
|
|
425
|
+
{ "path": "secrets" },
|
|
426
|
+
{ "path": "local" },
|
|
427
|
+
// custom NPM package
|
|
428
|
+
{ "path": "@my-scope/my-provider", "type": "module", "config": {} },
|
|
429
|
+
// custom local script
|
|
430
|
+
{ "path": "scripts/custom-loader.js", "type": "script" },
|
|
431
|
+
],
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
> **Provider order matters** โ providers are merged in declaration order, so
|
|
436
|
+
> later providers override earlier ones (`package-json` is the base, `local`
|
|
437
|
+
> wins).
|
|
438
|
+
|
|
439
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
440
|
+
|
|
441
|
+
<!-- SHARED / NESTED -->
|
|
442
|
+
|
|
443
|
+
## ๐ช Nested & global keys
|
|
444
|
+
|
|
445
|
+
Organize variables in nested objects. They are **flattened** into `process.env`
|
|
446
|
+
using the nesting delimiter (`__` by default):
|
|
447
|
+
|
|
448
|
+
```jsonc
|
|
449
|
+
{
|
|
450
|
+
"GROUP1": {
|
|
451
|
+
"VAR": "anyValue1",
|
|
452
|
+
"GROUP2": { "VAR": "anyValue2" },
|
|
453
|
+
},
|
|
454
|
+
"VAR3": "anyValue3",
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
process.env.GROUP1__VAR; // "anyValue1"
|
|
460
|
+
process.env.GROUP1__GROUP2__VAR; // "anyValue2"
|
|
461
|
+
process.env.VAR3; // "anyValue3"
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### `$` global marker
|
|
465
|
+
|
|
466
|
+
Prefix a key with `$` to mark it as **global/shared** โ relevant for the
|
|
467
|
+
`secrets` provider, which uses the marker to scope the secret across the project
|
|
468
|
+
rather than per-mode. The marker is **stripped on injection** at any nesting
|
|
469
|
+
depth, while the group prefix is **kept**:
|
|
470
|
+
|
|
471
|
+
```jsonc
|
|
472
|
+
{
|
|
473
|
+
"$TOKEN": "rootValue",
|
|
474
|
+
"GROUP1": {
|
|
475
|
+
"$SHARED": "groupValue",
|
|
476
|
+
"VAR": "anyValue",
|
|
477
|
+
},
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
// the `$` is removed; the nesting prefix is preserved
|
|
483
|
+
process.env.TOKEN; // "rootValue" (was $TOKEN)
|
|
484
|
+
process.env.GROUP1__SHARED; // "groupValue" (was GROUP1.$SHARED)
|
|
485
|
+
process.env.GROUP1__VAR; // "anyValue"
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
> The `$` is removed only from the **process environment** and from JSON Schema
|
|
489
|
+
> validation keys. It is **preserved** in the secrets file storage, so the
|
|
490
|
+
> `secrets` provider round-trips the global marker intact.
|
|
491
|
+
>
|
|
492
|
+
> Skip a key entirely (never injected) by prefixing it with `#`.
|
|
493
|
+
|
|
494
|
+
### Priority (lowest โ highest)
|
|
495
|
+
|
|
496
|
+
1. `package-json` info
|
|
497
|
+
2. `appsettings.json` (`app-settings`)
|
|
498
|
+
3. `<env>.env.json` (`secrets`)
|
|
499
|
+
4. `<env>.local.env.json` (`local`, skipped in `--ci`)
|
|
500
|
+
|
|
501
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
502
|
+
|
|
503
|
+
<!-- MASKING -->
|
|
504
|
+
|
|
505
|
+
## ๐ Masking secrets
|
|
506
|
+
|
|
507
|
+
When the resolved environment is rendered (at `--log debug`) and when objects
|
|
508
|
+
are logged, secrets are masked as `*****`. There are two complementary
|
|
509
|
+
mechanisms, configurable via CLI flags or the [config file](#-config):
|
|
510
|
+
|
|
511
|
+
### By key โ `logMaskValuesOfKeys` (`--mvk`)
|
|
512
|
+
|
|
513
|
+
Masks a variable's **whole value** when its **key** matches. Each entry is
|
|
514
|
+
either an **exact key name** (case-insensitive) or a `/source/flags` **regex**
|
|
515
|
+
matched against the key:
|
|
516
|
+
|
|
517
|
+
```jsonc
|
|
518
|
+
{
|
|
519
|
+
"logMaskValuesOfKeys": [
|
|
520
|
+
"PASSWORD", // exact key (case-insensitive)
|
|
521
|
+
"/token/i", // any key containing "token"
|
|
522
|
+
"/_secret$/i", // any key ending in "_secret"
|
|
523
|
+
],
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
# same, via CLI flag
|
|
529
|
+
> env -e dev --log debug --mvk PASSWORD "/token/i" : node app.js
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### By value content โ `logMaskAnyRegEx` (`--mrx`)
|
|
533
|
+
|
|
534
|
+
Masks **only the matching portion** of any string value, wherever it appears.
|
|
535
|
+
The global flag is always forced, so **every** occurrence is masked; use the
|
|
536
|
+
`/source/flags` form for extra flags such as `i`:
|
|
537
|
+
|
|
538
|
+
```jsonc
|
|
539
|
+
{
|
|
540
|
+
"logMaskAnyRegEx": [
|
|
541
|
+
"AKIA[0-9A-Z]{16}", // AWS access key ids
|
|
542
|
+
"/bearer .+/i", // bearer tokens (case-insensitive)
|
|
543
|
+
],
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
| Goal | Use |
|
|
548
|
+
| --------------------------------------------------- | --------------------- |
|
|
549
|
+
| Know the **key** of the secret | `logMaskValuesOfKeys` |
|
|
550
|
+
| Know the **shape** of the secret (token, key, RUTโฆ) | `logMaskAnyRegEx` |
|
|
551
|
+
|
|
552
|
+
> In JSON the backslash must be escaped: write `\\d` for `\d`. Neither mechanism
|
|
553
|
+
> masks the variable **name** โ keys are always shown. Masking only affects the
|
|
554
|
+
> output; the real (unmasked) values are still injected into `process.env`.
|
|
555
|
+
|
|
556
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
557
|
+
|
|
558
|
+
<!-- SCRIPTS -->
|
|
559
|
+
|
|
560
|
+
## ๐งฐ Development scripts
|
|
561
|
+
|
|
562
|
+
| Script | Description |
|
|
563
|
+
| -------------------- | ------------------------------------------------- |
|
|
564
|
+
| `pnpm build` | Build the library (Vite, ESM) into `dist/` |
|
|
565
|
+
| `pnpm test` | Run unit tests (Vitest) |
|
|
566
|
+
| `pnpm test:cov` | Run unit tests with coverage (100% threshold) |
|
|
567
|
+
| `pnpm test:int` | Run integration tests against the built binary |
|
|
568
|
+
| `pnpm typecheck` | Type-check with `tsc --noEmit` |
|
|
569
|
+
| `pnpm lint` | Lint with ESLint (flat config) |
|
|
570
|
+
| `pnpm format` | Format with Prettier |
|
|
571
|
+
| `pnpm run pub` | Gate + build + publish to npm (`latest`) |
|
|
572
|
+
| `pnpm run pub:alpha` | Gate + build + publish a prerelease (`alpha` tag) |
|
|
573
|
+
|
|
574
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
575
|
+
|
|
576
|
+
<!-- BUILT WITH -->
|
|
577
|
+
|
|
578
|
+
## ๐ ๏ธ Built with
|
|
579
|
+
|
|
580
|
+
- [yargs](http://yargs.js.org/) โ CLI argument parsing
|
|
581
|
+
- [ajv](https://ajv.js.org/) + [to-json-schema](https://www.npmjs.com/package/to-json-schema) โ JSON Schema
|
|
582
|
+
- [tslog](https://tslog.js.org/#/) โ logging
|
|
583
|
+
- [picocolors](https://github.com/alexeyraspopov/picocolors) โ terminal colors
|
|
584
|
+
- [subslate](https://github.com/josh-hemphill/subslate) โ interpolation
|
|
585
|
+
- [merge-deep](https://github.com/jonschlinkert/merge-deep) โ deep merge
|
|
586
|
+
- [Vite](https://vite.dev/) โ build ยท [Vitest](https://vitest.dev/) โ testing
|
|
587
|
+
|
|
588
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
589
|
+
|
|
590
|
+
<!-- LICENSE -->
|
|
591
|
+
|
|
592
|
+
## ๐ License
|
|
593
|
+
|
|
594
|
+
This project is licensed under the **MIT License** โ see [LICENSE.md](LICENSE.md)
|
|
595
|
+
for details.
|
|
596
|
+
|
|
597
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
<p align="center">
|
|
602
|
+
โจ with โค๏ธ by <a href="https://github.com/calvear93">Alvear Candia, Cristopher Alejandro</a>
|
|
603
|
+
</p>
|