@achs/env 5.0.0-alpha.0 → 5.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +580 -818
- package/assets/logo-achs.png +0 -0
- package/assets/logo.png +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,818 +1,580 @@
|
|
|
1
|
-
<div id="top" align="center">
|
|
2
|
-
<img
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
"path": "azure-key-vault",
|
|
582
|
-
"config": {
|
|
583
|
-
"dev": {
|
|
584
|
-
"vaultUrl": "https://kv-desa-ittec-sti.vault.azure.net"
|
|
585
|
-
},
|
|
586
|
-
"qa": {
|
|
587
|
-
"vaultUrl": "https://kv-qa-ittec-sti.vault.azure.net"
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
},
|
|
591
|
-
{
|
|
592
|
-
"path": "local"
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
// custom NPM package
|
|
596
|
-
"path": "@npm-package",
|
|
597
|
-
"type": "module",
|
|
598
|
-
"config": {
|
|
599
|
-
"any-config": "any value"
|
|
600
|
-
}
|
|
601
|
-
},
|
|
602
|
-
{
|
|
603
|
-
// custom script inside project
|
|
604
|
-
"path": "scripts/custom-loader.js",
|
|
605
|
-
"type": "script"
|
|
606
|
-
}
|
|
607
|
-
]
|
|
608
|
-
}
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
<!-- AZURE KEY VAULT -->
|
|
612
|
-
|
|
613
|
-
## 💽 **Azure Key Vault**
|
|
614
|
-
|
|
615
|
-
Allows you to store your secrets in Azure Key Vault.
|
|
616
|
-
|
|
617
|
-
#### 1.2. NPM Scripts
|
|
618
|
-
|
|
619
|
-
For load desired environment, add you npm script like **`env -e <env> -m <mode1[ mode2]> : <your-command>`**.
|
|
620
|
-
|
|
621
|
-
- **mode**: (build|debug|test) execution mode base variables.
|
|
622
|
-
- **env**: (dev|qa|stg|prod) environment variables.
|
|
623
|
-
|
|
624
|
-
_In example: `env -e dev -m debug : npm start`_
|
|
625
|
-
|
|
626
|
-
## 2. Structure
|
|
627
|
-
|
|
628
|
-
#### 2.1. Environments
|
|
629
|
-
|
|
630
|
-
Your `env/secrets` folder will contain files below:
|
|
631
|
-
|
|
632
|
-
- **dev.env.json**: development environment.
|
|
633
|
-
- **dev.local.env.json**: local development environment (takes precedence).
|
|
634
|
-
- **qa.env.json**: quality assurance environment.
|
|
635
|
-
- **qa.local.env.json**: local qa environment (takes precedence).
|
|
636
|
-
- **prod.env.json**: production environment.
|
|
637
|
-
- **prod.local.env.json**: local production environment (takes precedence).
|
|
638
|
-
|
|
639
|
-
_This folder should contains environment variables files for system environments._
|
|
640
|
-
|
|
641
|
-
#### 2.2. Keys (env/keys.json)
|
|
642
|
-
|
|
643
|
-
Your `keys.json` file should contains you Azure Key Vault SPN credentials per environment:
|
|
644
|
-
|
|
645
|
-
```json
|
|
646
|
-
{
|
|
647
|
-
"<env-name>": {
|
|
648
|
-
"vaultUrl": "<azure-key-vault-url>", // you can skip this var if present in config
|
|
649
|
-
"clientId": "<spn-client-id>",
|
|
650
|
-
"clientSecret": "<spn-secret-password>",
|
|
651
|
-
"tenantId": "<tenant-id>"
|
|
652
|
-
},
|
|
653
|
-
...
|
|
654
|
-
}
|
|
655
|
-
```
|
|
656
|
-
|
|
657
|
-
In example:
|
|
658
|
-
|
|
659
|
-
```json
|
|
660
|
-
{
|
|
661
|
-
"dev": {
|
|
662
|
-
"clientId": "f176a774-239e-4cd3-8551-88fd9fb9b441",
|
|
663
|
-
"clientSecret": "WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku",
|
|
664
|
-
"tenantId": "6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7"
|
|
665
|
-
},
|
|
666
|
-
"qa": {
|
|
667
|
-
"clientId": "5dcd9f45-7067-4387-94d8-e5e7066ba630",
|
|
668
|
-
"clientSecret": "60ec5e16430a46eba70dfea80d721b66",
|
|
669
|
-
"tenantId": "6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7"
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
```
|
|
673
|
-
|
|
674
|
-
Your secrets will be grouped, using your "name" and "project" variables from `package.json` file.
|
|
675
|
-
|
|
676
|
-
_This file allows to load environment files locally first run time._
|
|
677
|
-
|
|
678
|
-
## 3. Commands
|
|
679
|
-
|
|
680
|
-
You can use two command scripts for refresh your local env files
|
|
681
|
-
or publish/updates env files in the azure key vault from your local files.
|
|
682
|
-
|
|
683
|
-
- **Pulls Secrets File**: `env pull -e <env> [-o]`. (-o forces to replace your local file).
|
|
684
|
-
- **Pushes/Publishes Secrets File**: `env push -e <env>`.
|
|
685
|
-
|
|
686
|
-
#### 3.1. Environment Variables for Credentials
|
|
687
|
-
|
|
688
|
-
You can set your credentials variables from node environment variables.
|
|
689
|
-
|
|
690
|
-
In example:
|
|
691
|
-
|
|
692
|
-
```bash
|
|
693
|
-
user@machine:/mnt/c/Users/user$ AZURE_VAULT_URL=https://kv-desa-ittec-sti.vault.azure.net \
|
|
694
|
-
AZURE_CLIENT_ID=f176a774-239e-4cd3-8551-88fd9fb9b441 \
|
|
695
|
-
AZURE_CLIENT_SECRET=WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku \
|
|
696
|
-
AZURE_TENANT_ID=6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7 \
|
|
697
|
-
node_modules/.bin/env pull -e dev -o
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
or
|
|
701
|
-
|
|
702
|
-
```bash
|
|
703
|
-
user@machine:/mnt/c/Users/user$ npx pull -e dev -o \
|
|
704
|
-
--vaultUrl https://kv-desa-ittec-sti.vault.azure.net \
|
|
705
|
-
--spn f176a774-239e-4cd3-8551-88fd9fb9b441 \
|
|
706
|
-
--password WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku \
|
|
707
|
-
--tenant 6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
## 4. Schema
|
|
711
|
-
|
|
712
|
-
This lib uses JSON schema for validate and retrieve secrets from store.
|
|
713
|
-
|
|
714
|
-
For each property in the file, loader will retrieve the value from Azure Key
|
|
715
|
-
Vault.
|
|
716
|
-
|
|
717
|
-
When you push a new variable from any of your environment secrets
|
|
718
|
-
file, `env.schema.json` will be updated automatically.
|
|
719
|
-
|
|
720
|
-
If you want to ignore to load some variable without delete it, you can remove
|
|
721
|
-
the variable from `env.schema.json`.
|
|
722
|
-
|
|
723
|
-
## 5. Shared and Nested Keys
|
|
724
|
-
|
|
725
|
-
You can organize your keys in nested objects,
|
|
726
|
-
and declare project shared secrets (skips group
|
|
727
|
-
separation) prefixing with '\$' like:
|
|
728
|
-
|
|
729
|
-
```json
|
|
730
|
-
{
|
|
731
|
-
// .dev.env.json
|
|
732
|
-
"$SHARED": "sharedValue",
|
|
733
|
-
"GROUP1": {
|
|
734
|
-
"$SHARED": "sharedValue2",
|
|
735
|
-
"VAR": "anyValue1",
|
|
736
|
-
...
|
|
737
|
-
},
|
|
738
|
-
"GROUP2": {
|
|
739
|
-
"VAR": "anyValue2",
|
|
740
|
-
"SUBGROUP1": {
|
|
741
|
-
"VAR": "anyValue1",
|
|
742
|
-
...
|
|
743
|
-
},
|
|
744
|
-
...
|
|
745
|
-
},
|
|
746
|
-
"VAR3": "anyValue3",
|
|
747
|
-
...
|
|
748
|
-
}
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
So, in your application you can use the variables as shown below:
|
|
752
|
-
|
|
753
|
-
```javascript
|
|
754
|
-
const myVar1 = process.env.GROUP1__VAR;
|
|
755
|
-
const myVar2 = process.env.GROUP2__VAR;
|
|
756
|
-
const myVar2 = process.env.GROUP2__SUBGROUP1_VAR;
|
|
757
|
-
const myVar3 = process.env.VAR3;
|
|
758
|
-
// shared vars will load in every project
|
|
759
|
-
const mySharedVar1 = process.env.SHARED;
|
|
760
|
-
const mySharedNestedVar2 = process.env.GROUP1__SHARED;
|
|
761
|
-
```
|
|
762
|
-
|
|
763
|
-
## 6. Priority
|
|
764
|
-
|
|
765
|
-
### From lowest to highest.
|
|
766
|
-
|
|
767
|
-
- `(dev|qa|prod).env.json`
|
|
768
|
-
- `(dev|qa|prod).local.env.json` (takes precedence over previous)
|
|
769
|
-
|
|
770
|
-
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
771
|
-
|
|
772
|
-
<!-- LINTING -->
|
|
773
|
-
|
|
774
|
-
## 🧿 **Linting**
|
|
775
|
-
|
|
776
|
-
Project uses ESLint, for code formatting and code styling normalizing.
|
|
777
|
-
|
|
778
|
-
- **eslint**: linter integrated with TypeScript.
|
|
779
|
-
|
|
780
|
-
For correct interpretation of linters, is recommended to use [Visual Studio Code](https://code.visualstudio.com/) as IDE and install the plugins in .vscode folder at 'extensions.json', as well as use the config provided in 'settings.json'
|
|
781
|
-
|
|
782
|
-
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
783
|
-
|
|
784
|
-
<!-- CHANGELOG -->
|
|
785
|
-
|
|
786
|
-
## 📋 Changelog
|
|
787
|
-
|
|
788
|
-
For last changes see [CHANGELOG.md](CHANGELOG.md) file for details.
|
|
789
|
-
|
|
790
|
-
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
791
|
-
|
|
792
|
-
<!-- BUILT WITH -->
|
|
793
|
-
|
|
794
|
-
## 🛠️ Built with
|
|
795
|
-
|
|
796
|
-
- [yargs](http://yargs.js.org/)
|
|
797
|
-
- [tslog v4](https://tslog.js.org/#/)
|
|
798
|
-
- [subslate](https://github.com/josh-hemphill/subslate)
|
|
799
|
-
- [merge-deep](https://github.com/jonschlinkert/merge-deep)
|
|
800
|
-
- [ajv](https://ajv.js.org/)
|
|
801
|
-
- [to-json-schema](https://www.npmjs.com/package/to-json-schema)
|
|
802
|
-
- [Vite](https://vitejs.dev/) (build)
|
|
803
|
-
- [Vitest](https://vitest.dev/) (testing)
|
|
804
|
-
|
|
805
|
-
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
806
|
-
|
|
807
|
-
---
|
|
808
|
-
|
|
809
|
-
<br />
|
|
810
|
-
|
|
811
|
-
<p align="center">
|
|
812
|
-
<img
|
|
813
|
-
width="15%"
|
|
814
|
-
src="https://upload.wikimedia.org/wikipedia/commons/0/09/Logo_ACHS.svg"
|
|
815
|
-
/>
|
|
816
|
-
<h2 align="center">ASOCIACIÓN CHILENA DE SEGURIDAD</h2>
|
|
817
|
-
<h3 align="center">Tranformación Digital ▪ Equipo de Desarrollo</h3>
|
|
818
|
-
</p>
|
|
1
|
+
<div id="top" align="center">
|
|
2
|
+
<img alt="@achs/env logo" src="assets/logo.png" 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/@achs/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
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<br />
|
|
21
|
+
|
|
22
|
+
<!-- ABOUT -->
|
|
23
|
+
|
|
24
|
+
## 📖 About
|
|
25
|
+
|
|
26
|
+
`@achs/env` eases **environment variable handling** for NodeJS apps — like
|
|
27
|
+
[env-cmd](https://www.npmjs.com/package/env-cmd) or
|
|
28
|
+
[dotenv](https://www.npmjs.com/package/dotenv), but with **powerful, extensible
|
|
29
|
+
features**: pluggable **providers** to `load`, `pull` and `push` variables from
|
|
30
|
+
different stores, **JSON Schema validation**, value **interpolation**, secret
|
|
31
|
+
**masking** and nested/shared keys.
|
|
32
|
+
|
|
33
|
+
### ✨ Features
|
|
34
|
+
|
|
35
|
+
- 🧩 **Provider plugins** — bundled `package-json`, `app-settings`,
|
|
36
|
+
`azure-key-vault` and `local` providers, plus your own (NPM package or local
|
|
37
|
+
script).
|
|
38
|
+
- 💉 **Injection** — load variables into `process.env` and run any command.
|
|
39
|
+
- 🔐 **Azure Key Vault** — pull/push secrets per environment.
|
|
40
|
+
- ✅ **JSON Schema** — auto-generate and validate variables before injecting.
|
|
41
|
+
- 🪆 **Nested & shared keys** — `GROUP__VAR` flattening and `$`-prefixed shared
|
|
42
|
+
keys.
|
|
43
|
+
- 🧵 **Interpolation** — reference other args/vars with `[[ ]]` delimiters.
|
|
44
|
+
- 🙈 **Masking** — hide secret values in logs.
|
|
45
|
+
- 📤 **Export** — write the unified environment to a `.env` or JSON file.
|
|
46
|
+
|
|
47
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
48
|
+
|
|
49
|
+
<!-- REQUIREMENTS -->
|
|
50
|
+
|
|
51
|
+
## 📌 Requirements
|
|
52
|
+
|
|
53
|
+
[NodeJS](https://nodejs.org/) **20 or higher**.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
> node -v
|
|
57
|
+
v20.0.0
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
61
|
+
|
|
62
|
+
<!-- ESM -->
|
|
63
|
+
|
|
64
|
+
## 📦 ESM only
|
|
65
|
+
|
|
66
|
+
Since **v5** this package is **ESM-only** (`"type": "module"`). Consumers must
|
|
67
|
+
use ESM `import` syntax, and custom providers must be ESM modules that `export`
|
|
68
|
+
their provider object.
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// ✅ ESM
|
|
72
|
+
import { EnvProvider } from '@achs/env';
|
|
73
|
+
|
|
74
|
+
// ❌ CommonJS require is not supported
|
|
75
|
+
// const { EnvProvider } = require('@achs/env');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
79
|
+
|
|
80
|
+
<!-- QUICK START -->
|
|
81
|
+
|
|
82
|
+
## ⚡️ Quick start
|
|
83
|
+
|
|
84
|
+
Install the package:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
> npm install @achs/env
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Run the binary directly:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
> npx env --help
|
|
94
|
+
|
|
95
|
+
Usage: env [command] [options..] [: subcmd [:]] [options..]
|
|
96
|
+
|
|
97
|
+
Commands:
|
|
98
|
+
env [options..] [: <subcmd> :]
|
|
99
|
+
env pull [options..]
|
|
100
|
+
env push [options..]
|
|
101
|
+
env schema [options..]
|
|
102
|
+
env export [options..]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or wire it into your **npm scripts**:
|
|
106
|
+
|
|
107
|
+
```jsonc
|
|
108
|
+
{
|
|
109
|
+
"scripts": {
|
|
110
|
+
// inject "dev" variables (debug mode) and start the app
|
|
111
|
+
"start:dev": "env -e dev -m debug : node dist/main.js",
|
|
112
|
+
// inject "prod" variables for the build
|
|
113
|
+
"build:prod": "env -e prod -m build : tsc",
|
|
114
|
+
// regenerate the validation schema
|
|
115
|
+
"env:schema": "env schema -e dev",
|
|
116
|
+
// pull / push secrets for the "dev" environment
|
|
117
|
+
"env:pull:dev": "env pull -e dev",
|
|
118
|
+
"env:push:dev": "env push -e dev",
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run it:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
> npm run start:dev
|
|
127
|
+
|
|
128
|
+
13:31:59.865 INFO loading dev environment in debug mode
|
|
129
|
+
13:31:59.911 DEBUG using package-json provider
|
|
130
|
+
13:31:59.912 DEBUG using app-settings provider
|
|
131
|
+
13:31:59.914 DEBUG using azure-key-vault provider
|
|
132
|
+
13:32:00.109 DEBUG environment loaded:
|
|
133
|
+
{
|
|
134
|
+
NODE_ENV: 'development',
|
|
135
|
+
ENV: 'dev',
|
|
136
|
+
VERSION: '5.0.0',
|
|
137
|
+
NAME: '@my-app',
|
|
138
|
+
VAR1: true,
|
|
139
|
+
GROUP1__VAR1: 'G1V2',
|
|
140
|
+
ARR1: '1,val,true',
|
|
141
|
+
SECRET: '***'
|
|
142
|
+
}
|
|
143
|
+
13:32:00.116 INFO executing command > node dist/main.js
|
|
144
|
+
My environment loaded is: dev
|
|
145
|
+
13:32:00.232 INFO process finished successfully
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
149
|
+
|
|
150
|
+
<!-- COMMANDS AND OPTIONS -->
|
|
151
|
+
|
|
152
|
+
## ⚙️ Commands & Options
|
|
153
|
+
|
|
154
|
+
> **Interpolation** — any option value can reference other arguments using `[[`
|
|
155
|
+
> and `]]` delimiters. With `root: "config"`, the value `[[root]]/file.json`
|
|
156
|
+
> resolves to `config/file.json`; with `env: "dev"`,
|
|
157
|
+
> `[[root]]/config.[[env]].json` resolves to `config/config.dev.json`.
|
|
158
|
+
|
|
159
|
+
### Global options
|
|
160
|
+
|
|
161
|
+
| Option | Description | Type | Default |
|
|
162
|
+
| ---------------------------------- | ------------------------------------------------- | ---------- | ------- |
|
|
163
|
+
| `--help` | Show help | `boolean` | |
|
|
164
|
+
| `-e, --env` | Environment to load (i.e. `dev`, `prod`) | `string` | |
|
|
165
|
+
| `-m, --modes` | Execution modes (i.e. `debug`, `test`) | `string[]` | `[]` |
|
|
166
|
+
| `--nd, --nestingDelimiter` | Nesting-level delimiter for flatten | `string` | `__` |
|
|
167
|
+
| `--arrDesc, --arrayDescomposition` | Serialize (`false`) or break down (`true`) arrays | `boolean` | `false` |
|
|
168
|
+
| `-x, --expand` | Interpolate environment variables using itself | `boolean` | `false` |
|
|
169
|
+
| `--ci` | Continuous Integration mode (skips local files) | `boolean` | auto |
|
|
170
|
+
|
|
171
|
+
### Workspace options
|
|
172
|
+
|
|
173
|
+
| Option | Description | Type | Default |
|
|
174
|
+
| ---------------------- | --------------------------------- | -------- | --------------------------------- |
|
|
175
|
+
| `--root` | Base environment folder path | `string` | `env` |
|
|
176
|
+
| `-c, --configFile` | Config JSON file path | `string` | `[[root]]/settings/settings.json` |
|
|
177
|
+
| `-s, --schemaFile` | Environment schema JSON file path | `string` | `[[root]]/settings/schema.json` |
|
|
178
|
+
| `--pkg, --packageJson` | `package.json` path | `string` | _cwd_ |
|
|
179
|
+
|
|
180
|
+
### JSON Schema options
|
|
181
|
+
|
|
182
|
+
| Option | Description | Type | Default |
|
|
183
|
+
| ---------------------- | ---------------------------------------------- | ------------------ | ------- |
|
|
184
|
+
| `-r, --resolve` | Merge new schema or override it | `merge`/`override` | `merge` |
|
|
185
|
+
| `--null, --nullable` | Whether variables are nullable by default | `boolean` | `true` |
|
|
186
|
+
| `--df, --detectFormat` | Include string formats in the generated schema | `boolean` | `false` |
|
|
187
|
+
|
|
188
|
+
### Logger options
|
|
189
|
+
|
|
190
|
+
| Option | Description | Type | Default |
|
|
191
|
+
| ------------------------------ | -------------------------------------- | --------------------------------------------- | ------- |
|
|
192
|
+
| `--log, --logLevel` | Log level | `silly`/`trace`/`debug`/`info`/`warn`/`error` | `info` |
|
|
193
|
+
| `--mvk, --logMaskValuesOfKeys` | Mask values of the given keys in logs | `string[]` | `[]` |
|
|
194
|
+
| `--mrx, --logMaskAnyRegEx` | Mask values matching the given regexes | `string[]` | `[]` |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### `env`
|
|
199
|
+
|
|
200
|
+
Inject environment variables into `process.env` and execute a command (the
|
|
201
|
+
command goes after `:`).
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
env -e <env> [options..] [: <subcmd> :] [options..]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
> env -e dev -m test unit : npm test
|
|
209
|
+
> env -e dev -m debug : npm start : -c [[root]]/[[env]].env.json
|
|
210
|
+
> env -e prod -m build optimize : npm run build
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
| Option | Description | Type | Default |
|
|
214
|
+
| ------------------------------ | ------------------------------------------ | --------- | ------- |
|
|
215
|
+
| `--validate, --schemaValidate` | Validate variables against the JSON schema | `boolean` | `true` |
|
|
216
|
+
|
|
217
|
+
### `pull`
|
|
218
|
+
|
|
219
|
+
Pull environment variables from the providers' stores.
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
env pull -e <env> [options..]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
| Option | Description | Type | Default |
|
|
226
|
+
| ----------------- | ------------------------- | --------- | ------- |
|
|
227
|
+
| `-o, --overwrite` | Overwrite local variables | `boolean` | `false` |
|
|
228
|
+
|
|
229
|
+
### `push`
|
|
230
|
+
|
|
231
|
+
Push environment variables to the providers' stores.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
env push -e <env> [options..]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
| Option | Description | Type | Default |
|
|
238
|
+
| ------------- | ---------------------- | --------- | ------- |
|
|
239
|
+
| `-f, --force` | Force push for secrets | `boolean` | `false` |
|
|
240
|
+
|
|
241
|
+
### `schema`
|
|
242
|
+
|
|
243
|
+
Generate (or update) the validation schema from the providers' output.
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
> env schema -e dev -m build
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### `export`
|
|
250
|
+
|
|
251
|
+
Export the unified environment to a file.
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
env export -e <env> -m <modes> [options..]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Option | Description | Type | Default |
|
|
258
|
+
| --------------- | --------------------- | --------------- | -------- |
|
|
259
|
+
| `-u, -p, --uri` | Output file path | `string` | `.env` |
|
|
260
|
+
| `-f, --format` | Output format | `dotenv`/`json` | `dotenv` |
|
|
261
|
+
| `-q, --quotes` | Wrap values in quotes | `boolean` | `false` |
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
> env export -e dev -m build -f json --uri [[env]].env.json
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
268
|
+
|
|
269
|
+
<!-- PROVIDERS -->
|
|
270
|
+
|
|
271
|
+
## 📡 Providers
|
|
272
|
+
|
|
273
|
+
Providers are the core of this library. It ships with **four integrated
|
|
274
|
+
providers**, and you can add your own.
|
|
275
|
+
|
|
276
|
+
### `package-json`
|
|
277
|
+
|
|
278
|
+
Loads project info from your `package.json` (`version`, `project`, `name`,
|
|
279
|
+
`title`, `description`) into `ENV`, `VERSION`, `PROJECT`, `NAME`, `TITLE`,
|
|
280
|
+
`DESCRIPTION`.
|
|
281
|
+
|
|
282
|
+
| Option | Description | Type | Default |
|
|
283
|
+
| --------------------------- | ------------------------------- | -------- | ------- |
|
|
284
|
+
| `--vp, --packageInfoPrefix` | Prefix for the loaded variables | `string` | `""` |
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# i.e. expose them as REACT_APP_* for CRA
|
|
288
|
+
> env -e dev -m build : react-scripts build : --vp REACT_APP_
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `app-settings`
|
|
292
|
+
|
|
293
|
+
Non-secret loader for `appsettings.json`, organized by sections:
|
|
294
|
+
|
|
295
|
+
```jsonc
|
|
296
|
+
{
|
|
297
|
+
"|DEFAULT|": { "VAR1": "v1_default" },
|
|
298
|
+
"|MODE|": {
|
|
299
|
+
"build": { "NODE_ENV": "production" },
|
|
300
|
+
"debug": { "NODE_ENV": "development" },
|
|
301
|
+
},
|
|
302
|
+
"|ENV|": {
|
|
303
|
+
"dev": {
|
|
304
|
+
"C1": "V1",
|
|
305
|
+
"GROUP1": { "VAR2": "G1V2", "GROUP2": { "VAR1": "G1G2V1" } },
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
"|LOCAL|": { "dev": { "LOCAL_VAR": "only-local" } },
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
It also merges `appsettings.<env>.json`, `appsettings.<env>.local.json` (skipped
|
|
313
|
+
in `--ci`) and `appsettings.<mode>.json`.
|
|
314
|
+
|
|
315
|
+
| Option | Description | Type | Default |
|
|
316
|
+
| ----------------- | ----------------------------- | -------- | --------------------------- |
|
|
317
|
+
| `--ef, --envFile` | Non-secret settings file path | `string` | `[[root]]/appsettings.json` |
|
|
318
|
+
|
|
319
|
+
### `local`
|
|
320
|
+
|
|
321
|
+
Loads local-only variables (never loaded in `--ci`). The file is auto-created
|
|
322
|
+
if missing.
|
|
323
|
+
|
|
324
|
+
| Option | Description | Type | Default |
|
|
325
|
+
| ------------------- | ------------------------- | -------- | --------------------------------- |
|
|
326
|
+
| `--lf, --localFile` | Local variables file path | `string` | `[[root]]/[[env]].local.env.json` |
|
|
327
|
+
|
|
328
|
+
### `azure-key-vault`
|
|
329
|
+
|
|
330
|
+
Loads secrets from an Azure Key Vault store into `[[root]]/[[env]].env.json` per
|
|
331
|
+
environment (see the [Azure Key Vault](#-azure-key-vault) section below).
|
|
332
|
+
|
|
333
|
+
| Option | Description | Type | Default |
|
|
334
|
+
| ---------------------------------------- | --------------------------------- | ---------- | ---------------------------------------- |
|
|
335
|
+
| `--secretsFile` | Secret variables file path | `string` | `[[root]]/[[env]].env.json` |
|
|
336
|
+
| `-k, --keys, --keysFile` | SPN credentials file paths | `string[]` | `['[[root]]/keys.json', '../keys.json']` |
|
|
337
|
+
| `--url, --vaultUrl` | Azure Key Vault URL | `string` | |
|
|
338
|
+
| `--id, --clientId, --spn` | SPN Client ID | `string` | |
|
|
339
|
+
| `-p, --pass, --clientSecret, --password` | SPN Client Secret | `string` | |
|
|
340
|
+
| `-t, --tenant` | Azure Tenant ID | `string` | |
|
|
341
|
+
| `--mock` | Mock the Key Vault client (tests) | `boolean` | `false` |
|
|
342
|
+
| `--dns, --skipDnsCheck` | Skip the DNS reachability check | `boolean` | `false` |
|
|
343
|
+
|
|
344
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
345
|
+
|
|
346
|
+
<!-- CUSTOM PROVIDERS -->
|
|
347
|
+
|
|
348
|
+
## ✒️ Creating custom providers
|
|
349
|
+
|
|
350
|
+
Create a provider in two ways:
|
|
351
|
+
|
|
352
|
+
- **Local script** — a `.js` file that `export default`s your provider.
|
|
353
|
+
- **NPM package** — a published module that `export default`s your provider.
|
|
354
|
+
|
|
355
|
+
Both are wired in the [config file](#-config) via the `providers` list.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import type { CommandArguments, EnvProvider } from '@achs/env';
|
|
359
|
+
import { logger, readJson, writeJson } from '@achs/env/utils';
|
|
360
|
+
|
|
361
|
+
const KEY = 'my-unique-provider-key';
|
|
362
|
+
|
|
363
|
+
interface MyProviderArguments extends CommandArguments {
|
|
364
|
+
anyExtraOption: boolean;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const MyProvider: EnvProvider<MyProviderArguments> = {
|
|
368
|
+
// unique identifier
|
|
369
|
+
key: KEY,
|
|
370
|
+
|
|
371
|
+
// (optional) add custom options to the CLI via yargs
|
|
372
|
+
builder: (builder) => {
|
|
373
|
+
builder.options({
|
|
374
|
+
anyExtraOption: {
|
|
375
|
+
group: KEY,
|
|
376
|
+
alias: ['a', 'aeo'],
|
|
377
|
+
type: 'boolean',
|
|
378
|
+
default: false,
|
|
379
|
+
describe: 'Any option description',
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
// called on load — may be sync or async, and may return a list to merge
|
|
385
|
+
load: ({ env }) => {
|
|
386
|
+
if (env === 'dev') return { NODE_ENV: 'development' };
|
|
387
|
+
|
|
388
|
+
return [{ NODE_ENV: 'production' }, { ANY_GROUP: { INNER_VAR: 12 } }];
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
// (optional) called on `env pull`
|
|
392
|
+
pull: (argv, config) => {
|
|
393
|
+
/* fetch variables into your local cache */
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
// (optional) called on `env push`
|
|
397
|
+
push: (argv, config) => {
|
|
398
|
+
/* publish/update your variables */
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
export default MyProvider;
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
406
|
+
|
|
407
|
+
<!-- CONFIG -->
|
|
408
|
+
|
|
409
|
+
## 📥 Config
|
|
410
|
+
|
|
411
|
+
Any CLI argument can be set in your config file
|
|
412
|
+
(`[[root]]/settings/settings.json` by default), but it is mainly used to declare
|
|
413
|
+
**providers**:
|
|
414
|
+
|
|
415
|
+
```jsonc
|
|
416
|
+
{
|
|
417
|
+
"log": "silly",
|
|
418
|
+
// hide values of these keys in the logs
|
|
419
|
+
"logMaskValuesOfKeys": ["SECRET", "MY_API_KEY"],
|
|
420
|
+
"providers": [
|
|
421
|
+
{ "path": "package-json" },
|
|
422
|
+
{ "path": "app-settings" },
|
|
423
|
+
{
|
|
424
|
+
"path": "azure-key-vault",
|
|
425
|
+
"config": {
|
|
426
|
+
"dev": {
|
|
427
|
+
"vaultUrl": "https://kv-dev-myproject.vault.azure.net",
|
|
428
|
+
},
|
|
429
|
+
"qa": { "vaultUrl": "https://kv-qa-myproject.vault.azure.net" },
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
{ "path": "local" },
|
|
433
|
+
// custom NPM package
|
|
434
|
+
{ "path": "@my-scope/my-provider", "type": "module", "config": {} },
|
|
435
|
+
// custom local script
|
|
436
|
+
{ "path": "scripts/custom-loader.js", "type": "script" },
|
|
437
|
+
],
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
> **Provider order matters** — providers are merged in declaration order, so
|
|
442
|
+
> later providers override earlier ones (`package-json` is the base, `local`
|
|
443
|
+
> wins).
|
|
444
|
+
|
|
445
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
446
|
+
|
|
447
|
+
<!-- AZURE KEY VAULT -->
|
|
448
|
+
|
|
449
|
+
## 💽 Azure Key Vault
|
|
450
|
+
|
|
451
|
+
Store and retrieve your secrets from Azure Key Vault, grouped by your `name` and
|
|
452
|
+
`project` from `package.json`.
|
|
453
|
+
|
|
454
|
+
### Keys file (`env/keys.json`)
|
|
455
|
+
|
|
456
|
+
SPN credentials per environment, used to bootstrap the first pull:
|
|
457
|
+
|
|
458
|
+
```jsonc
|
|
459
|
+
{
|
|
460
|
+
"dev": {
|
|
461
|
+
"vaultUrl": "<azure-key-vault-url>", // optional if set in settings config
|
|
462
|
+
"clientId": "<spn-client-id>",
|
|
463
|
+
"clientSecret": "<spn-client-secret>",
|
|
464
|
+
"tenantId": "<tenant-id>",
|
|
465
|
+
},
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
> ⚠️ Keep `keys.json` and `*.env.json` out of version control — they hold
|
|
470
|
+
> secrets.
|
|
471
|
+
|
|
472
|
+
### Credentials via environment variables
|
|
473
|
+
|
|
474
|
+
Alternatively, provide credentials through env vars (they take precedence):
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
AZURE_VAULT_URL=<azure-key-vault-url> \
|
|
478
|
+
AZURE_CLIENT_ID=<spn-client-id> \
|
|
479
|
+
AZURE_CLIENT_SECRET=<spn-client-secret> \
|
|
480
|
+
AZURE_TENANT_ID=<tenant-id> \
|
|
481
|
+
npx env pull -e dev -o
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
or as CLI flags:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
npx env pull -e dev -o \
|
|
488
|
+
--vaultUrl <azure-key-vault-url> \
|
|
489
|
+
--spn <spn-client-id> \
|
|
490
|
+
--password <spn-client-secret> \
|
|
491
|
+
--tenant <tenant-id>
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Workflow
|
|
495
|
+
|
|
496
|
+
- **Pull** secrets to your local file: `env pull -e <env> [-o]` (`-o` overwrites).
|
|
497
|
+
- **Push** local secrets to the vault: `env push -e <env>`.
|
|
498
|
+
|
|
499
|
+
Pushing a new variable updates the schema automatically. To stop loading a
|
|
500
|
+
variable without deleting it from the vault, remove it from the schema file.
|
|
501
|
+
|
|
502
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
503
|
+
|
|
504
|
+
<!-- SHARED / NESTED -->
|
|
505
|
+
|
|
506
|
+
## 🪆 Shared & nested keys
|
|
507
|
+
|
|
508
|
+
Organize keys in nested objects. Declare **shared** keys (skipping group
|
|
509
|
+
separation) by prefixing them with `$`:
|
|
510
|
+
|
|
511
|
+
```jsonc
|
|
512
|
+
{
|
|
513
|
+
"$SHARED": "sharedValue",
|
|
514
|
+
"GROUP1": {
|
|
515
|
+
"$SHARED": "sharedValue2",
|
|
516
|
+
"VAR": "anyValue1",
|
|
517
|
+
},
|
|
518
|
+
"GROUP2": { "SUBGROUP1": { "VAR": "anyValue1" } },
|
|
519
|
+
"VAR3": "anyValue3",
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Consumed in your app as flattened keys (`__` separator by default):
|
|
524
|
+
|
|
525
|
+
```javascript
|
|
526
|
+
process.env.GROUP1__VAR; // "anyValue1"
|
|
527
|
+
process.env.GROUP2__SUBGROUP1__VAR; // "anyValue1"
|
|
528
|
+
process.env.VAR3; // "anyValue3"
|
|
529
|
+
// shared keys drop the `$` and the group prefix
|
|
530
|
+
process.env.SHARED; // "sharedValue"
|
|
531
|
+
process.env.GROUP1__SHARED; // "sharedValue2"
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Priority (lowest → highest)
|
|
535
|
+
|
|
536
|
+
1. `<env>.env.json`
|
|
537
|
+
2. `<env>.local.env.json` (overrides the above)
|
|
538
|
+
|
|
539
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
540
|
+
|
|
541
|
+
<!-- SCRIPTS -->
|
|
542
|
+
|
|
543
|
+
## 🧰 Development scripts
|
|
544
|
+
|
|
545
|
+
| Script | Description |
|
|
546
|
+
| -------------------- | ------------------------------------------------- |
|
|
547
|
+
| `pnpm build` | Build the library (Vite, ESM) into `dist/` |
|
|
548
|
+
| `pnpm test` | Run unit tests (Vitest) |
|
|
549
|
+
| `pnpm test:cov` | Run unit tests with coverage (100% threshold) |
|
|
550
|
+
| `pnpm test:int` | Run integration tests against the built binary |
|
|
551
|
+
| `pnpm typecheck` | Type-check with `tsc --noEmit` |
|
|
552
|
+
| `pnpm lint` | Lint with ESLint (flat config) |
|
|
553
|
+
| `pnpm format` | Format with Prettier |
|
|
554
|
+
| `pnpm run pub` | Gate + build + publish to npm (`latest`) |
|
|
555
|
+
| `pnpm run pub:alpha` | Gate + build + publish a prerelease (`alpha` tag) |
|
|
556
|
+
|
|
557
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
558
|
+
|
|
559
|
+
<!-- BUILT WITH -->
|
|
560
|
+
|
|
561
|
+
## 🛠️ Built with
|
|
562
|
+
|
|
563
|
+
- [yargs](http://yargs.js.org/) — CLI argument parsing
|
|
564
|
+
- [ajv](https://ajv.js.org/) + [to-json-schema](https://www.npmjs.com/package/to-json-schema) — JSON Schema
|
|
565
|
+
- [tslog](https://tslog.js.org/#/) — logging
|
|
566
|
+
- [subslate](https://github.com/josh-hemphill/subslate) — interpolation
|
|
567
|
+
- [merge-deep](https://github.com/jonschlinkert/merge-deep) — deep merge
|
|
568
|
+
- [Vite](https://vite.dev/) — build · [Vitest](https://vitest.dev/) — testing
|
|
569
|
+
|
|
570
|
+
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
<br />
|
|
575
|
+
|
|
576
|
+
<p align="center">
|
|
577
|
+
<img width="25%" src="./assets/logo-achs.png" alt="ACHS" />
|
|
578
|
+
<h3 align="center">ASOCIACIÓN CHILENA DE SEGURIDAD</h3>
|
|
579
|
+
<h4 align="center">Transformación Digital ▪ Equipo de Desarrollo</h4>
|
|
580
|
+
</p>
|