@achs/env 4.12.3 → 5.0.0-alpha.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +580 -830
  3. package/arguments.d.ts +14 -14
  4. package/arguments.d.ts.map +1 -1
  5. package/arguments.js +135 -131
  6. package/arguments.js.map +1 -1
  7. package/assets/logo-achs.svg +16 -0
  8. package/assets/logo.svg +46 -0
  9. package/commands/env.command.d.ts +8 -2
  10. package/commands/env.command.d.ts.map +1 -1
  11. package/commands/env.command.js +55 -82
  12. package/commands/env.command.js.map +1 -1
  13. package/commands/export.command.d.ts +8 -2
  14. package/commands/export.command.d.ts.map +1 -1
  15. package/commands/export.command.js +53 -62
  16. package/commands/export.command.js.map +1 -1
  17. package/commands/index.d.ts +5 -5
  18. package/commands/index.d.ts.map +1 -1
  19. package/commands/index.js +5 -14
  20. package/commands/pull.command.d.ts +6 -1
  21. package/commands/pull.command.d.ts.map +1 -1
  22. package/commands/pull.command.js +20 -37
  23. package/commands/pull.command.js.map +1 -1
  24. package/commands/push.command.d.ts +6 -1
  25. package/commands/push.command.d.ts.map +1 -1
  26. package/commands/push.command.js +20 -36
  27. package/commands/push.command.js.map +1 -1
  28. package/commands/schema.command.d.ts +6 -1
  29. package/commands/schema.command.d.ts.map +1 -1
  30. package/commands/schema.command.js +16 -17
  31. package/commands/schema.command.js.map +1 -1
  32. package/exec.d.ts +7 -1
  33. package/exec.d.ts.map +1 -1
  34. package/exec.js +84 -160
  35. package/exec.js.map +1 -1
  36. package/index.d.ts +3 -3
  37. package/index.d.ts.map +1 -1
  38. package/index.js +3 -20
  39. package/interfaces/index.d.ts +1 -1
  40. package/interfaces/index.d.ts.map +1 -1
  41. package/interfaces/loader.interface.d.ts +29 -3
  42. package/interfaces/loader.interface.d.ts.map +1 -1
  43. package/main.d.ts +0 -1
  44. package/main.js +7 -26
  45. package/main.js.map +1 -1
  46. package/package.json +55 -34
  47. package/providers/app-settings.provider.d.ts +5 -2
  48. package/providers/app-settings.provider.d.ts.map +1 -1
  49. package/providers/app-settings.provider.js +36 -49
  50. package/providers/app-settings.provider.js.map +1 -1
  51. package/providers/azure-key-vault.provider.d.ts +12 -8
  52. package/providers/azure-key-vault.provider.d.ts.map +1 -1
  53. package/providers/azure-key-vault.provider.js +138 -169
  54. package/providers/azure-key-vault.provider.js.map +1 -1
  55. package/providers/index.d.ts +2 -2
  56. package/providers/index.d.ts.map +1 -1
  57. package/providers/index.js +18 -28
  58. package/providers/index.js.map +1 -1
  59. package/providers/local.provider.d.ts +5 -2
  60. package/providers/local.provider.d.ts.map +1 -1
  61. package/providers/local.provider.js +27 -40
  62. package/providers/local.provider.js.map +1 -1
  63. package/providers/package-json.provider.d.ts +5 -2
  64. package/providers/package-json.provider.d.ts.map +1 -1
  65. package/providers/package-json.provider.js +26 -28
  66. package/providers/package-json.provider.js.map +1 -1
  67. package/utils/argv.util.d.ts +10 -0
  68. package/utils/argv.util.d.ts.map +1 -0
  69. package/utils/argv.util.js +24 -0
  70. package/utils/argv.util.js.map +1 -0
  71. package/utils/command.util.d.ts +70 -3
  72. package/utils/command.util.d.ts.map +1 -1
  73. package/utils/command.util.js +60 -140
  74. package/utils/command.util.js.map +1 -1
  75. package/utils/index.d.ts +7 -6
  76. package/utils/index.d.ts.map +1 -1
  77. package/utils/index.js +8 -23
  78. package/utils/interpolate.util.d.ts +29 -1
  79. package/utils/interpolate.util.d.ts.map +1 -1
  80. package/utils/interpolate.util.js +12 -30
  81. package/utils/interpolate.util.js.map +1 -1
  82. package/utils/json.util.d.ts +41 -3
  83. package/utils/json.util.d.ts.map +1 -1
  84. package/utils/json.util.js +24 -42
  85. package/utils/json.util.js.map +1 -1
  86. package/utils/logger.d.ts +21 -2
  87. package/utils/logger.d.ts.map +1 -1
  88. package/utils/logger.js +31 -17
  89. package/utils/logger.js.map +1 -1
  90. package/utils/normalize.util.d.ts +24 -2
  91. package/utils/normalize.util.d.ts.map +1 -1
  92. package/utils/normalize.util.js +35 -56
  93. package/utils/normalize.util.js.map +1 -1
  94. package/utils/schema.util.d.ts +59 -0
  95. package/utils/schema.util.d.ts.map +1 -1
  96. package/utils/schema.util.js +62 -97
  97. package/utils/schema.util.js.map +1 -1
  98. package/commands/index.js.map +0 -1
  99. package/index.js.map +0 -1
  100. package/interfaces/index.js +0 -18
  101. package/interfaces/index.js.map +0 -1
  102. package/interfaces/loader.interface.js +0 -3
  103. package/interfaces/loader.interface.js.map +0 -1
  104. package/tsconfig.build.tsbuildinfo +0 -1
  105. package/utils/index.js.map +0 -1
package/README.md CHANGED
@@ -1,830 +1,580 @@
1
- <div id="top" align="center">
2
- <img
3
- alt="logo"
4
- src="https://nodejs.org/static/images/logo.svg"
5
- width="256px"
6
- />
7
-
8
- </br>
9
-
10
- <h1 align="center"><b>env</b></h1>
11
- <h4 align="center">¡Environment variables made easy!</h4>
12
- </div>
13
-
14
- <br />
15
-
16
- <p align="center">
17
- <img
18
- src="https://img.shields.io/badge/version-1.0.0-blue?style=flat-square"
19
- alt="version"
20
- />
21
- &nbsp;
22
- <img
23
- src="https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white"
24
- alt="typescript"
25
- />
26
- &nbsp;
27
- <img
28
- src="https://img.shields.io/badge/nodejs-~14.0.0_||_^16.14.2-darkgreen?style=flat-square"
29
- alt="nodejs engine"
30
- />
31
- &nbsp;
32
- <img
33
- src="https://img.shields.io/badge/npm->=7.5.6-darkgreen?style=flat-square"
34
- alt="npm engine"
35
- />
36
- </p>
37
-
38
- <br />
39
-
40
- <!-- ABOUT THE PROJECT -->
41
-
42
- ## 📖 **About**
43
-
44
- Eases NodeJS <b>environment variable handling</b>, like [env-cmd](https://www.npmjs.com/package/env-cmd) or [dotenv](https://www.npmjs.com/package/dotenv), but with <b>powerfull features and extensibility</b> for adding custom providers (as plugins) for <u>load</u>, <u>pull</u> and <u>push</u> the variables from different stores.
45
-
46
- <p align="right">(<a href="#top">back to top</a>)</p>
47
-
48
- <!-- REQUIREMENTS -->
49
-
50
- ## 📌 **Requirements**
51
-
52
- First, [download](https://nodejs.org/) and install **NodeJS**. Version `16` or higher is required.
53
-
54
- Validate installed versions of node and npm with:
55
-
56
- ```bash
57
- > node -v
58
- v16.14.2
59
-
60
- > npm -v
61
- 8.3.0
62
- ```
63
-
64
- You can initialize a new npm project using:
65
-
66
- ```bash
67
- > npm init
68
- ```
69
-
70
- <p align="right">(<a href="#top">back to top</a>)</p>
71
-
72
- <!-- QUICK START -->
73
-
74
- ## ⚡️ **Quick start**
75
-
76
- > 🔔 Make sure that you have [NodeJS 14+](https://nodejs.org/) installed on your computer.
77
-
78
- - Installs the package:
79
-
80
- ```bash
81
- > npm install @achs/env
82
-
83
- added 1 packages, and audited 1 packages in 1s
84
-
85
- found 0 vulnerabilities
86
- > _
87
- ```
88
-
89
- - Executes binary directly:
90
-
91
- ```bash
92
- > node_modules/.bin/env --help
93
-
94
- Usage: env [command] [options..] [: subcmd [:]] [options..]
95
-
96
- Commands:
97
- env [options..] [: <subcmd> :]
98
- env pull [options..]
99
- env push [options..]
100
- env schema [options..]
101
- > _
102
- ```
103
-
104
- ```bash
105
- > npx env --help
106
-
107
- Usage: env [command] [options..] [: subcmd [:]] [options..]
108
-
109
- Commands:
110
- env [options..] [: <subcmd> :]
111
- env pull [options..]
112
- env push [options..]
113
- env schema [options..]
114
- > _
115
- ```
116
-
117
- - Or add desired commands in your **npm script** in `package.json`:
118
-
119
- ```javascript
120
- {
121
- ...,
122
- "scripts": {
123
- // starts project injecting "dev" environment variables and debug log level
124
- "start:dev": "env -e dev -m debug : node dist/main.js : --log debug",
125
- // starts project injecting "prod" environment variables
126
- "start:prod": "env -e prod -m debug : node dist/main.js",
127
- ...,
128
- // builds project injecting "prod" environment variables
129
- "build:prod": "env -e prod -m build : tsc",
130
- ...,
131
- "env:schema": "env schema -e dev --ci",
132
- // uploads environment "dev" variables
133
- "env:push:dev": "env push -e dev",
134
- // downloads environment "dev" variables
135
- "env:pull:dev": "env pull -e dev"
136
- },
137
- ...
138
- }
139
- ```
140
-
141
- - Execs your command:
142
-
143
- **file**: _dist/main.js_
144
-
145
- ```javascript
146
- console.log(`My environment loaded is: ${process.env.ENV}`);
147
- ```
148
-
149
- ```bash
150
- > npm run start:dev
151
-
152
- 13:31:59.865 INFO loading dev environment in debug mode
153
- 13:31:59.911 DEBUG using package-json provider
154
- 13:31:59.912 DEBUG using app-settings provider
155
- 13:31:59.914 DEBUG using secrets provider
156
- 13:32:00.109 DEBUG environment loaded:
157
- {
158
- NODE_ENV: 'development',
159
- ENV: 'dev',
160
- VERSION: '1.0.0',
161
- NAME: '@my-app',
162
- VAR1: true,
163
- VAR2: true,
164
- GROUP1__VAR1: 'G1V2',
165
- ARR1: '1,val,true',
166
- SECRET: '***'
167
- }
168
- 13:32:00.116 INFO executing command > node dist/main.js
169
- My environment loaded is: dev
170
- 13:32:00.232 INFO process finished successfully
171
- > _
172
- ```
173
-
174
- <p align="right">(<a href="#top">back to top</a>)</p>
175
-
176
- ## **Structure**
177
-
178
- ```bash
179
- ├── src/
180
- │   ├── commands/ # lib commands handlers
181
- │   │   ├── env.command.ts
182
- │   │   ├── export.command.ts
183
- │   │   ├── pull.command.ts
184
- │   │   ├── push.command.ts
185
- │   │   └── schema.command.ts
186
- │   ├── interfaces/ # provider interfaces
187
- │   ├── providers/ # integrated providers
188
- │   │   ├── package-json.provider.ts
189
- │   │   ├── app-settings.provider.ts
190
- │   │   ├── local.provider.ts
191
- │   │   └── azure-key-vault.provider.ts
192
- │   ├── utils/
193
- │   │   ├── command.util.ts
194
- │   │   ├── interpolate.util.ts
195
- │   │   ├── json.util.ts
196
- │   │   ├── normalize.util.ts
197
- │   │   ├── schema.util.ts
198
- │   │   └── logger.ts
199
- │   ├── arguments.ts # global arguments
200
- │   ├── exec.ts # initialization logic (load config, commands, etc.)
201
- │   └── main.ts
202
- ├── tests/ # integration tests
203
- ├── .eslintrc.json
204
- ├── jest.config.json
205
- ├── tsconfig.build.json
206
- └── tsconfig.json
207
- ```
208
-
209
- <p align="right">(<a href="#top">back to top</a>)</p>
210
-
211
- <!-- COMMANDS AND OPTIONS -->
212
-
213
- ## ⚙️ **Commands & Options**
214
-
215
- Options handling has the ability of **replace arguments itself**, using `[[` and `]]` as delimiters.
216
- So, in example for define your config file path, you must use your _root_ argument,
217
- supposing root has the value of "config", this definition _`[[root]]/any-config-file.json`_ will be
218
- _`config/any-config-file.json`_, or if your _env_ argument is "dev", this definition
219
- _`[[root]]/config-file.[[env]].json`_ will be _`config/config-file.dev.json`_.
220
-
221
- <div align="center">
222
- <span style="font-size:20px;font-weight:bold" align="center">Options</span>
223
- </div>
224
-
225
- ### Global options
226
-
227
- | Option | Description | Type | Default | Required? |
228
- | ---------------------------------- | ----------------------------------------------- | ---------- | ------- | --------- |
229
- | `--help` | Shows help | `boolean` | | No |
230
- | `--e, --env` | Environment for load | `string` | | Yes |
231
- | `-m, --modes` | Execution modes | `string[]` | `[]` | No |
232
- | `--nd, --nestingDelimiter` | Nesting level delimiter for flatten | `string` | `__` | No |
233
- | `--arrDesc, --arrayDescomposition` | Whether serialize or break down arrays | `boolean` | `false` | No |
234
- | `-x, --expand` | Interpolates environment variables using itself | `boolean` | `false` | No |
235
- | `-ci` | Continuous Integration mode | `boolean` | `false` | No |
236
-
237
- </br>
238
-
239
- ### Workspace options
240
-
241
- | Option | Description | Type | Default | Required? |
242
- | ------------------ | --------------------------------- | -------- | --------------------------------- | --------- |
243
- | `--root` | Default environment folder path | `string` | `env` | No |
244
- | `-c, --configFile` | Config JSON file path | `string` | `[[root]]/settings/settings.json` | No |
245
- | `-s, --schemaFile` | Environment Schema JSON file path | `string` | `[[root]]/settings/schema.json` | No |
246
-
247
- ### JSON Schema options
248
-
249
- | Option | Description | Type | Default | Required? |
250
- | ---------------------- | ---------------------------------------------------------- | ----------------- | ------- | --------- |
251
- | `-r, --resolve` | Whether merges new schema or override | `merge, override` | `merge` | No |
252
- | `--null, --nullable` | Whether variables are nullable by default | `boolean` | `true` | No |
253
- | `--df, --detectFormat` | Whether format of strings variables are included in schema | `boolean` | `true` | No |
254
-
255
- ### Logger options
256
-
257
- | Option | Description | Type | Default | Required? |
258
- | ------------------- | ----------- | ---------------------------------------- | ------- | --------- |
259
- | `--log, --logLevel` | Log level | `silly, trace, debug, info, warn, error` | `info` | No |
260
-
261
- <div align="center">
262
- <span style="font-size:20px;font-weight:bold" align="center">Commands</span>
263
- </div>
264
-
265
- - ## **`env`**
266
-
267
- Inject your environment variables into `process.env` and executes a command.
268
-
269
- ```bash
270
- env -e [env] [options..] [: subcmd [:]] [options..]
271
- ```
272
-
273
- Examples:
274
-
275
- ```bash
276
- > env -e dev -m test unit : npm test
277
- ```
278
-
279
- ```bash
280
- > env -e dev -m debug : npm start : -c [[root]]/[[env]].env.json
281
- ```
282
-
283
- ```bash
284
- > env -e prod -m build optimize : npm build
285
- ```
286
-
287
- - ## **`pull`**
288
-
289
- Pulls environment variables from providers stores.
290
-
291
- ```bash
292
- env pull -e [env] [options..]
293
- ```
294
-
295
- | Option | Description | Type | Default | Required? |
296
- | ----------------- | ------------------------- | --------- | ------- | --------- |
297
- | `-o, --overwrite` | Overwrite local variables | `boolean` | `false` | No |
298
-
299
- Examples:
300
-
301
- ```bash
302
- > env pull -e dev
303
- ```
304
-
305
- - ## **`push`**
306
-
307
- Pushes environment variables to providers stores.
308
-
309
- ```bash
310
- env push -e [env] [options..]
311
- ```
312
-
313
- | Option | Description | Type | Default | Required? |
314
- | ------------- | ------------------------------------ | --------- | ------- | --------- |
315
- | `-f, --force` | Force push for secrets (replace all) | `boolean` | `false` | No |
316
-
317
- Examples:
318
-
319
- ```bash
320
- > env push -e dev
321
- ```
322
-
323
- - ## **`schema`**
324
-
325
- Generates validation schema from providers output variables.
326
-
327
- ```bash
328
- env schema -e [env] -m [modes] [options..]
329
- ```
330
-
331
- Examples:
332
-
333
- ```bash
334
- > env schema -e dev -m build
335
- ```
336
-
337
- - ## **`export`**
338
-
339
- Export unified environment variables to a file from providers.
340
-
341
- ```bash
342
- env export -e [env] -m [modes] [options..]
343
- ```
344
-
345
- | Option | Description | Type | Default | Required? |
346
- | --------------- | ---------------------------------- | -------- | -------- | --------- |
347
- | `-u, -p, --uri` | Uri for export file with variables | `string` | `.env` | No |
348
- | `-f, --format` | Format for export variables | `string` | `dotenv` | No |
349
-
350
- Examples:
351
-
352
- ```bash
353
- > env export -e dev -m build -f json --uri [[env]].env.json
354
- ```
355
-
356
- <p align="right">(<a href="#top">back to top</a>)</p>
357
-
358
- <!-- PROVIDERS -->
359
-
360
- ## 📡 **Providers**
361
-
362
- Main feature of this library is using providers for get and set environment variables.
363
- So, you can define your own provider, but lib came with 3 integrated providers:
364
-
365
- - ## **`package-json`**
366
-
367
- Load some info from your project `package.json`.
368
-
369
- Info read is:
370
-
371
- ```json
372
- {
373
- "version": "1.0.0",
374
- "project": "project-name",
375
- "name": "@package-name",
376
- "title": "app-name",
377
- "description": "any description"
378
- }
379
- ```
380
-
381
- | Option | Description | Type | Default | Required? |
382
- | ------------------- | --------------------------- | -------- | ------- | --------- |
383
- | `--vp, --varPrefix` | Prefix for loaded variables | `string` | `""` | No |
384
-
385
- Examples:
386
-
387
- ```bash
388
- > env -e dev -m build : react-script build : --vp REACT_APP_
389
- ```
390
-
391
- </br>
392
-
393
- - ## **`app-settings`**
394
-
395
- Non secrets loader for `appsettings.json`.
396
-
397
- `appsettings.json` file has the format below:
398
-
399
- ```json
400
- {
401
- "|DEFAULT|": {},
402
- "|MODE|": {},
403
- "|ENV|": {}
404
- }
405
- ```
406
-
407
- In example:
408
-
409
- ```json
410
- {
411
- "|DEFAULT|": {
412
- "VAR1": "v1_default"
413
- },
414
- "|MODE|": {
415
- "build": {
416
- "NODE_ENV": "production"
417
- },
418
- "debug": {
419
- "NODE_ENV": "development"
420
- },
421
- "test": {
422
- "NODE_ENV": "test"
423
- }
424
- },
425
- "|ENV|": {
426
- "dev": {
427
- "C1": "V1",
428
- "C2": "V2",
429
- "C3": 3,
430
- "GROUP1": {
431
- "VAR1": null,
432
- "VAR2": "G1V2",
433
- "VAR3": true,
434
- "GROUP2": {
435
- "VAR1": "G1G2V1"
436
- }
437
- },
438
- "C4": "23"
439
- }
440
- }
441
- }
442
- ```
443
-
444
- | Option | Description | Type | Default | Required? |
445
- | ----------------------- | ------------------------------------ | -------- | --------------------------- | --------- |
446
- | `--ef, --envFile` | Environment variables file path | `string` | `[[root]]/appsettings.json` | No |
447
- | `--sp, --sectionPrefix` | Prefix for env and modes in env file | `string` | `::` | No |
448
-
449
- </br>
450
-
451
- - ## **`package-json`**
452
-
453
- Load some info from your project `package.json`.
454
-
455
- Info read is:
456
-
457
- ```json
458
- {
459
- "version": "1.0.0",
460
- "project": "project-name",
461
- "name": "@package-name",
462
- "title": "app-name",
463
- "description": "any description"
464
- }
465
- ```
466
-
467
- | Option | Description | Type | Default | Required? |
468
- | ------------------- | --------------------------- | -------- | ------- | --------- |
469
- | `--vp, --varPrefix` | Prefix for loaded variables | `string` | `""` | No |
470
-
471
- Examples:
472
-
473
- ```bash
474
- > env -e dev -m build : react-script build : --vp REACT_APP_
475
- ```
476
-
477
- - ## **`azure-key-vault`**
478
-
479
- Azure Key Vault provider, allows to load secrets from vault store to `env/secrets/[[env]].env.json` per environment.
480
- Also, handles `env/secrets/[[env]].local.env.json` for load local variables with precedence over base.
481
-
482
- | Option | Description | Type | Default | Required? |
483
- | --------------------------------------- | ---------------------------------------------- | ---------- | ----------------------------------------- | --------- |
484
- | `--secretFolder` | Secret variables folder path | `string` | `[[root]]/secrets` | No |
485
- | `--secretFile` | Secret variables file path | `string` | `[[secretFolder]]/[[env]].env.json` | No |
486
- | `--localSecretFile` | Local secret variables file path | `string` | `[[secretFolder]]/[[env]].local.env.json` | No |
487
- | `-k, --keys, --keysFile` | Azure Key Vault SPN credentials files paths | `string[]` | `['../keys.json', '[[root]]/keys.json']` | No |
488
- | `--url, --vaultUrl` | Azure Key Vault server URL | `string` | | Yes |
489
- | `--spn, --clientId, --id` | SPN Client ID | `string` | | Yes |
490
- | `-p --password, --pass, --clientSecret` | SPN Client Secret Password | `string` | | Yes |
491
- | `-t, --tenant` | Azure Tenant ID | `string` | | Yes |
492
- | `--mock` | Mocks Azure Key Vault client (testing purpose) | `string` | `false` | No |
493
-
494
- <p align="right">(<a href="#top">back to top</a>)</p>
495
-
496
- <!-- PROVIDERS -->
497
-
498
- ## ✒ **Creating Custom Providers**
499
-
500
- You can create your custom providers, in two ways:
501
-
502
- - **Local Script**: you must create a JavaScript file (.js), exporting by default your "provider" following standard interface exported by this lib.
503
- - **NPM Package**: you must create your custom NPM library and export by default your "provider" using standard interface exported by this lib.
504
-
505
- How to load your provider is shown in Config Section.
506
-
507
- In example, a provider exported by your NPM package written in TypeScript should be like:
508
-
509
- ```typescript
510
- import { CommandArguments, EnvProvider } from '@achs/env';
511
- import { logger, readJson, writeJson } from '@achs/env/utils';
512
-
513
- const KEY = 'my-unique-provider-key';
514
-
515
- interface MyProviderCommandArguments extends CommandArguments {
516
- anyExtraOption: boolean;
517
- }
518
-
519
- export const MyProvider: EnvProvider<MyProviderCommandArguments> = {
520
- // unique identifier for provider
521
- key: KEY,
522
-
523
- // (optional) allows to provider adds new arguments/options
524
- // to commands using yargs for builder
525
- builder: (builder) => {
526
- builder.options({
527
- anyExtraOption: {
528
- group: KEY,
529
- alias: ['a', 'aeo'],
530
- type: 'boolean',
531
- default: false,
532
- describe: 'Any option description',
533
- },
534
- });
535
- },
536
-
537
- // call on environment variables loading,
538
- // may be a Promise
539
- load: ({ env, modes, ...options }) => {
540
- if (env === 'dev')
541
- return {
542
- NODE_ENV: 'development',
543
- };
544
-
545
- // you can return a list of JSON environment variables for merge
546
- return [
547
- {
548
- NODE_ENV: 'production',
549
- },
550
- {
551
- ANY_VAR: 'ANY_VALUE',
552
- ANY_GROUP: {
553
- INNER_VAR: 12,
554
- },
555
- },
556
- ];
557
- },
558
-
559
- // (optional) call on pulling variables from provider store,
560
- // config may pass in your config file
561
- pull: ({ env, modes, ...options }, config) => {
562
- // anyway you want for pulling variables to cache
563
- },
564
-
565
- // (optional) call on pushing/updating variables to provider store,
566
- // config may pass in your config file
567
- push: ({ env, modes, ...options }, config) => {
568
- // anyway you should do for pushing or updating your variables
569
- },
570
- };
571
- ```
572
-
573
- <p align="right">(<a href="#top">back to top</a>)</p>
574
-
575
- <!-- CONFIG -->
576
-
577
- ## 📥 **Config**
578
-
579
- You can configure any config argument inside you config file, but commonly providers are designed for this purpose.
580
-
581
- ```javascript
582
- {
583
- "log": "silly",
584
- // will hide values of keys SECRET and MY_API_KEY in logging
585
- "logMaskValuesOfKeys": ["SECRET", "MY_API_KEY"],
586
- // integrated providers and custom providers together
587
- "providers": [
588
- {
589
- "path": "package-json"
590
- },
591
- {
592
- "path": "app-settings"
593
- },
594
- {
595
- "path": "azure-key-vault",
596
- "config": {
597
- "dev": {
598
- "vaultUrl": "https://kv-desa-ittec-sti.vault.azure.net"
599
- },
600
- "qa": {
601
- "vaultUrl": "https://kv-qa-ittec-sti.vault.azure.net"
602
- }
603
- }
604
- },
605
- {
606
- "path": "local"
607
- },
608
- {
609
- // custom NPM package
610
- "path": "@npm-package",
611
- "type": "module",
612
- "config": {
613
- "any-config": "any value"
614
- }
615
- },
616
- {
617
- // custom script inside project
618
- "path": "scripts/custom-loader.js",
619
- "type": "script"
620
- }
621
- ]
622
- }
623
- ```
624
-
625
- <!-- AZURE KEY VAULT -->
626
-
627
- ## 💽 **Azure Key Vault**
628
-
629
- Allows you to store your secrets in Azure Key Vault.
630
-
631
- #### 1.2. NPM Scripts
632
-
633
- For load desired environment, add you npm script like **`env -e <env> -m <mode1[ mode2]> : <your-command>`**.
634
-
635
- - **mode**: (build|debug|test) execution mode base variables.
636
- - **env**: (dev|qa|stg|prod) environment variables.
637
-
638
- _In example: `env -e dev -m debug : npm start`_
639
-
640
- ## 2. Structure
641
-
642
- #### 2.1. Environments
643
-
644
- Your `env/secrets` folder will contain files below:
645
-
646
- - **dev.env.json**: development environment.
647
- - **dev.local.env.json**: local development environment (takes precedence).
648
- - **qa.env.json**: quality assurance environment.
649
- - **qa.local.env.json**: local qa environment (takes precedence).
650
- - **prod.env.json**: production environment.
651
- - **prod.local.env.json**: local production environment (takes precedence).
652
-
653
- _This folder should contains environment variables files for system environments._
654
-
655
- #### 2.2. Keys (env/keys.json)
656
-
657
- Your `keys.json` file should contains you Azure Key Vault SPN credentials per environment:
658
-
659
- ```json
660
- {
661
- "<env-name>": {
662
- "vaultUrl": "<azure-key-vault-url>", // you can skip this var if present in config
663
- "clientId": "<spn-client-id>",
664
- "clientSecret": "<spn-secret-password>",
665
- "tenantId": "<tenant-id>"
666
- },
667
- ...
668
- }
669
- ```
670
-
671
- In example:
672
-
673
- ```json
674
- {
675
- "dev": {
676
- "clientId": "f176a774-239e-4cd3-8551-88fd9fb9b441",
677
- "clientSecret": "WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku",
678
- "tenantId": "6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7"
679
- },
680
- "qa": {
681
- "clientId": "5dcd9f45-7067-4387-94d8-e5e7066ba630",
682
- "clientSecret": "60ec5e16430a46eba70dfea80d721b66",
683
- "tenantId": "6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7"
684
- }
685
- }
686
- ```
687
-
688
- Your secrets will be grouped, using your "name" and "project" variables from `package.json` file.
689
-
690
- _This file allows to load environment files locally first run time._
691
-
692
- ## 3. Commands
693
-
694
- You can use two command scripts for refresh your local env files
695
- or publish/updates env files in the azure key vault from your local files.
696
-
697
- - **Pulls Secrets File**: `env pull -e <env> [-o]`. (-o forces to replace your local file).
698
- - **Pushes/Publishes Secrets File**: `env push -e <env>`.
699
-
700
- #### 3.1. Environment Variables for Credentials
701
-
702
- You can set your credentials variables from node environment variables.
703
-
704
- In example:
705
-
706
- ```bash
707
- user@machine:/mnt/c/Users/user$ AZURE_VAULT_URL=https://kv-desa-ittec-sti.vault.azure.net \
708
- AZURE_CLIENT_ID=f176a774-239e-4cd3-8551-88fd9fb9b441 \
709
- AZURE_CLIENT_SECRET=WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku \
710
- AZURE_TENANT_ID=6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7 \
711
- node_modules/.bin/env pull -e dev -o
712
- ```
713
-
714
- or
715
-
716
- ```bash
717
- user@machine:/mnt/c/Users/user$ npx pull -e dev -o \
718
- --vaultUrl https://kv-desa-ittec-sti.vault.azure.net \
719
- --spn f176a774-239e-4cd3-8551-88fd9fb9b441 \
720
- --password WyBwkmcL8rGQe9B2fvRLDrqDuannE4Ku \
721
- --tenant 6d4bbe0a-5654-4c69-a682-bf7dcdaed8e7
722
- ```
723
-
724
- ## 4. Schema
725
-
726
- This lib uses JSON schema for validate and retrieve secrets from store.
727
-
728
- For each property in the file, loader will retrieve the value from Azure Key
729
- Vault.
730
-
731
- When you push a new variable from any of your environment secrets
732
- file, `env.schema.json` will be updated automatically.
733
-
734
- If you want to ignore to load some variable without delete it, you can remove
735
- the variable from `env.schema.json`.
736
-
737
- ## 5. Shared and Nested Keys
738
-
739
- You can organize your keys in nested objects,
740
- and declare project shared secrets (skips group
741
- separation) prefixing with '\$' like:
742
-
743
- ```json
744
- {
745
- // .dev.env.json
746
- "$SHARED": "sharedValue",
747
- "GROUP1": {
748
- "$SHARED": "sharedValue2",
749
- "VAR": "anyValue1",
750
- ...
751
- },
752
- "GROUP2": {
753
- "VAR": "anyValue2",
754
- "SUBGROUP1": {
755
- "VAR": "anyValue1",
756
- ...
757
- },
758
- ...
759
- },
760
- "VAR3": "anyValue3",
761
- ...
762
- }
763
- ```
764
-
765
- So, in your application you can use the variables as shown below:
766
-
767
- ```javascript
768
- const myVar1 = process.env.GROUP1__VAR;
769
- const myVar2 = process.env.GROUP2__VAR;
770
- const myVar2 = process.env.GROUP2__SUBGROUP1_VAR;
771
- const myVar3 = process.env.VAR3;
772
- // shared vars will load in every project
773
- const mySharedVar1 = process.env.SHARED;
774
- const mySharedNestedVar2 = process.env.GROUP1__SHARED;
775
- ```
776
-
777
- ## 6. Priority
778
-
779
- ### From lowest to highest.
780
-
781
- - `(dev|qa|prod).env.json`
782
- - `(dev|qa|prod).local.env.json` (takes precedence over previous)
783
-
784
- <p align="right">(<a href="#top">back to top</a>)</p>
785
-
786
- <!-- LINTING -->
787
-
788
- ## 🧿 **Linting**
789
-
790
- Project uses ESLint, for code formatting and code styling normalizing.
791
-
792
- - **eslint**: linter integrated with TypeScript.
793
-
794
- 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'
795
-
796
- <p align="right">(<a href="#top">back to top</a>)</p>
797
-
798
- <!-- CHANGELOG -->
799
-
800
- ## 📋 Changelog
801
-
802
- For last changes see [CHANGELOG.md](CHANGELOG.md) file for details.
803
-
804
- <p align="right">(<a href="#top">back to top</a>)</p>
805
-
806
- <!-- BUILT WITH -->
807
-
808
- ## 🛠️ Built with
809
-
810
- - [yargs](http://yargs.js.org/)
811
- - [tslog](https://tslog.js.org/#/)
812
- - [subslate](https://github.com/josh-hemphill/subslate)
813
- - [merge-deep](https://github.com/jonschlinkert/merge-deep)
814
- - [ajv](https://ajv.js.org/)
815
- - [to-json-schema](https://www.npmjs.com/package/to-json-schema)
816
-
817
- <p align="right">(<a href="#top">back to top</a>)</p>
818
-
819
- ---
820
-
821
- <br />
822
-
823
- <p align="center">
824
- <img
825
- width="15%"
826
- src="https://upload.wikimedia.org/wikipedia/commons/0/09/Logo_ACHS.svg"
827
- />
828
- <h2 align="center">ASOCIACIÓN CHILENA DE SEGURIDAD</h2>
829
- <h3 align="center">Tranformación Digital ▪ Equipo de Desarrollo</h3>
830
- </p>
1
+ <div id="top" align="center">
2
+ <img alt="@achs/env logo" src="assets/logo.svg" width="160" />
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
+ &nbsp;
10
+ <img src="https://img.shields.io/badge/module-ESM-f59e0b?style=flat-square" alt="esm" />
11
+ &nbsp;
12
+ <img src="https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white" alt="typescript" />
13
+ &nbsp;
14
+ <img src="https://img.shields.io/badge/node->=20-339933?style=flat-square&logo=node.js&logoColor=white" alt="node engine" />
15
+ &nbsp;
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.svg" 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>