@dotenvx/dotenvx 1.0.0 → 1.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 +15 -1
- package/README.md +215 -192
- package/package.json +2 -2
- package/src/lib/helpers/dotenvExpand.js +81 -0
- package/src/lib/helpers/parseDecryptEvalExpand.js +10 -9
- package/src/lib/main.d.ts +284 -0
- package/src/lib/main.js +67 -16
- package/src/lib/services/genexample.js +2 -0
- package/src/lib/services/get.js +1 -0
- package/src/lib/services/run.js +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.
|
|
5
|
+
## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.1.0...main)
|
|
6
|
+
|
|
7
|
+
## 1.1.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add TypeScript type definitions ([#272](https://github.com/dotenvx/dotenvx/pull/272))
|
|
12
|
+
|
|
13
|
+
## 1.0.1
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
* 🐞 Fix expansion when preset on `process.env` and/or with `--overload` ([#271](https://github.com/dotenvx/dotenvx/pull/271))
|
|
6
18
|
|
|
7
19
|
## 1.0.0
|
|
8
20
|
|
|
@@ -34,6 +46,8 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
34
46
|
|
|
35
47
|
This is a BIG release that sets the tone for `dotenvx`'s core offering and features while maintaining room for growth. Thank you everyone for your support and usage of `dotenvx` 🙏.
|
|
36
48
|
|
|
49
|
+
[blog post: "From dotenv to dotenvx: Next Generation Config Management"](https://dotenvx.com/blog/2024/06/24/dotenvx-next-generation-config-management.html)
|
|
50
|
+
|
|
37
51
|
## 0.45.0
|
|
38
52
|
|
|
39
53
|
### Changed
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
### Quickstart [](https://www.npmjs.com/package/@dotenvx/dotenvx) [](https://www.npmjs.com/package/@dotenvx/dotenvx)
|
|
12
|
+
### Quickstart [](https://www.npmjs.com/package/@dotenvx/dotenvx) [](https://github.com/dotenvx/dotenvx/tree/main/tests) [](https://www.npmjs.com/package/@dotenvx/dotenvx)
|
|
13
13
|
|
|
14
14
|
Install and use it in code just like `dotenv`.
|
|
15
15
|
|
|
@@ -233,6 +233,17 @@ More examples
|
|
|
233
233
|
Hello World
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
</details>
|
|
237
|
+
* <details><summary>Clojure 🌿</summary><br>
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
$ echo "HELLO=World" > .env
|
|
241
|
+
$ echo '(println "Hello" (System/getenv "HELLO"))' > index.clj
|
|
242
|
+
|
|
243
|
+
$ dotenvx run -- clojure -M index.clj
|
|
244
|
+
Hello World
|
|
245
|
+
```
|
|
246
|
+
|
|
236
247
|
</details>
|
|
237
248
|
* <details><summary>.NET 🔵</summary><br>
|
|
238
249
|
|
|
@@ -659,188 +670,10 @@ More examples
|
|
|
659
670
|
|
|
660
671
|
|
|
661
672
|
|
|
662
|
-
##
|
|
663
|
-
|
|
664
|
-
> Go deeper with [extensions](#extensions-), [advaned usage](#advanced-usage-), and [guides](#guides-).
|
|
665
|
-
|
|
666
|
-
### Extensions 🔌
|
|
667
|
-
|
|
668
|
-
* <details><summary>`ext ls`</summary><br>
|
|
669
|
-
|
|
670
|
-
Print all `.env` files in a tree structure.
|
|
671
|
-
|
|
672
|
-
```sh
|
|
673
|
-
$ touch .env
|
|
674
|
-
$ touch .env.production
|
|
675
|
-
$ mkdir -p apps/backend
|
|
676
|
-
$ touch apps/backend/.env
|
|
677
|
-
|
|
678
|
-
$ dotenvx ext ls
|
|
679
|
-
├─ .env.production
|
|
680
|
-
├─ .env
|
|
681
|
-
└─ apps
|
|
682
|
-
└─ backend
|
|
683
|
-
└─ .env
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
</details>
|
|
687
|
-
* <details><summary>`ext ls directory`</summary><br>
|
|
688
|
-
|
|
689
|
-
Print all `.env` files inside a specified path to a directory.
|
|
690
|
-
|
|
691
|
-
```sh
|
|
692
|
-
$ touch .env
|
|
693
|
-
$ touch .env.production
|
|
694
|
-
$ mkdir -p apps/backend
|
|
695
|
-
$ touch apps/backend/.env
|
|
696
|
-
|
|
697
|
-
$ dotenvx ext ls apps/backend
|
|
698
|
-
└─ .env
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
</details>
|
|
702
|
-
* <details><summary>`ext ls -f`</summary><br>
|
|
703
|
-
|
|
704
|
-
Glob `.env` filenames matching a wildcard.
|
|
705
|
-
|
|
706
|
-
```sh
|
|
707
|
-
$ touch .env
|
|
708
|
-
$ touch .env.production
|
|
709
|
-
$ mkdir -p apps/backend
|
|
710
|
-
$ touch apps/backend/.env
|
|
711
|
-
$ touch apps/backend/.env.prod
|
|
712
|
-
|
|
713
|
-
$ dotenvx ext ls -f **/.env.prod*
|
|
714
|
-
├─ .env.production
|
|
715
|
-
└─ apps
|
|
716
|
-
└─ backend
|
|
717
|
-
└─ .env.prod
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
</details>
|
|
721
|
-
* <details><summary>`ext genexample`</summary><br>
|
|
722
|
-
|
|
723
|
-
In one command, generate a `.env.example` file from your current `.env` file contents.
|
|
724
|
-
|
|
725
|
-
```sh
|
|
726
|
-
$ echo "HELLO=World" > .env
|
|
727
|
-
|
|
728
|
-
$ dotenvx ext genexample
|
|
729
|
-
✔ updated .env.example (1)
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
```ini
|
|
733
|
-
# .env.example
|
|
734
|
-
HELLO=""
|
|
735
|
-
```
|
|
736
|
-
|
|
737
|
-
</details>
|
|
738
|
-
* <details><summary>`ext genexample -f`</summary><br>
|
|
739
|
-
|
|
740
|
-
Pass multiple `.env` files to generate your `.env.example` file from the combination of their contents.
|
|
741
|
-
|
|
742
|
-
```sh
|
|
743
|
-
$ echo "HELLO=World" > .env
|
|
744
|
-
$ echo "DB_HOST=example.com" > .env.production
|
|
745
|
-
|
|
746
|
-
$ dotenvx ext genexample -f .env -f .env.production
|
|
747
|
-
✔ updated .env.example (2)
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
```ini
|
|
751
|
-
# .env.example
|
|
752
|
-
HELLO=""
|
|
753
|
-
DB_HOST=""
|
|
754
|
-
```
|
|
755
|
-
|
|
756
|
-
</details>
|
|
757
|
-
* <details><summary>`ext genexample directory`</summary><br>
|
|
758
|
-
|
|
759
|
-
Generate a `.env.example` file inside the specified directory. Useful for monorepos.
|
|
760
|
-
|
|
761
|
-
```sh
|
|
762
|
-
$ echo "HELLO=World" > .env
|
|
763
|
-
$ mkdir -p apps/backend
|
|
764
|
-
$ echo "HELLO=Backend" > apps/backend/.env
|
|
765
|
-
|
|
766
|
-
$ dotenvx ext genexample apps/backend
|
|
767
|
-
✔ updated .env.example (1)
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
```ini
|
|
771
|
-
# apps/backend/.env.example
|
|
772
|
-
HELLO=""
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
</details>
|
|
776
|
-
* <details><summary>`ext gitignore`</summary><br>
|
|
673
|
+
## Advanced
|
|
777
674
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
```sh
|
|
781
|
-
$ dotenvx ext gitignore
|
|
782
|
-
creating .gitignore
|
|
783
|
-
appending .env* to .gitignore
|
|
784
|
-
done
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
</details>
|
|
788
|
-
* <details><summary>`ext precommit`</summary><br>
|
|
789
|
-
|
|
790
|
-
Prevent `.env` files from being committed to code.
|
|
791
|
-
|
|
792
|
-
```sh
|
|
793
|
-
$ dotenvx ext precommit
|
|
794
|
-
[dotenvx][precommit] success
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
</details>
|
|
798
|
-
* <details><summary>`ext precommit --install`</summary><br>
|
|
799
|
-
|
|
800
|
-
Install a shell script to `.git/hooks/pre-commit` to prevent accidentally committing any `.env` files to source control.
|
|
801
|
-
|
|
802
|
-
```sh
|
|
803
|
-
$ dotenvx ext precommit --install
|
|
804
|
-
[dotenvx][precommit] dotenvx precommit installed [.git/hooks/pre-commit]
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
</details>
|
|
808
|
-
* <details><summary>`ext prebuild`</summary><br>
|
|
809
|
-
|
|
810
|
-
Prevent `.env` files from being built into your docker containers.
|
|
811
|
-
|
|
812
|
-
Add it to your `Dockerfile`.
|
|
813
|
-
|
|
814
|
-
```sh
|
|
815
|
-
RUN curl -fsS https://dotenvx.sh | sh
|
|
816
|
-
|
|
817
|
-
...
|
|
818
|
-
|
|
819
|
-
RUN dotenvx ext prebuild
|
|
820
|
-
CMD ["dotenvx", "run", "--", "node", "index.js"]
|
|
821
|
-
```
|
|
822
|
-
|
|
823
|
-
</details>
|
|
824
|
-
* <details><summary>`ext scan`</summary><br>
|
|
825
|
-
|
|
826
|
-
Use [gitleaks](https://gitleaks.io) under the hood to scan for possible secrets in your code.
|
|
827
|
-
|
|
828
|
-
```sh
|
|
829
|
-
$ dotenvx ext scan
|
|
830
|
-
|
|
831
|
-
○
|
|
832
|
-
│╲
|
|
833
|
-
│ ○
|
|
834
|
-
○ ░
|
|
835
|
-
░ gitleaks
|
|
836
|
-
|
|
837
|
-
100 commits scanned.
|
|
838
|
-
no leaks found
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
</details>
|
|
842
|
-
|
|
843
|
-
### Advanced usage 🎓
|
|
675
|
+
> Become a `dotenvx` power user.
|
|
676
|
+
>
|
|
844
677
|
|
|
845
678
|
* <details><summary>`run` - Variable Expansion</summary><br>
|
|
846
679
|
|
|
@@ -1355,18 +1188,208 @@ More examples
|
|
|
1355
1188
|
|
|
1356
1189
|
</details>
|
|
1357
1190
|
|
|
1358
|
-
###
|
|
1191
|
+
### Extensions 🔌
|
|
1192
|
+
|
|
1193
|
+
* <details><summary>`ext ls`</summary><br>
|
|
1194
|
+
|
|
1195
|
+
Print all `.env` files in a tree structure.
|
|
1196
|
+
|
|
1197
|
+
```sh
|
|
1198
|
+
$ touch .env
|
|
1199
|
+
$ touch .env.production
|
|
1200
|
+
$ mkdir -p apps/backend
|
|
1201
|
+
$ touch apps/backend/.env
|
|
1202
|
+
|
|
1203
|
+
$ dotenvx ext ls
|
|
1204
|
+
├─ .env.production
|
|
1205
|
+
├─ .env
|
|
1206
|
+
└─ apps
|
|
1207
|
+
└─ backend
|
|
1208
|
+
└─ .env
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
</details>
|
|
1212
|
+
* <details><summary>`ext ls directory`</summary><br>
|
|
1213
|
+
|
|
1214
|
+
Print all `.env` files inside a specified path to a directory.
|
|
1215
|
+
|
|
1216
|
+
```sh
|
|
1217
|
+
$ touch .env
|
|
1218
|
+
$ touch .env.production
|
|
1219
|
+
$ mkdir -p apps/backend
|
|
1220
|
+
$ touch apps/backend/.env
|
|
1359
1221
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1222
|
+
$ dotenvx ext ls apps/backend
|
|
1223
|
+
└─ .env
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
</details>
|
|
1227
|
+
* <details><summary>`ext ls -f`</summary><br>
|
|
1228
|
+
|
|
1229
|
+
Glob `.env` filenames matching a wildcard.
|
|
1230
|
+
|
|
1231
|
+
```sh
|
|
1232
|
+
$ touch .env
|
|
1233
|
+
$ touch .env.production
|
|
1234
|
+
$ mkdir -p apps/backend
|
|
1235
|
+
$ touch apps/backend/.env
|
|
1236
|
+
$ touch apps/backend/.env.prod
|
|
1237
|
+
|
|
1238
|
+
$ dotenvx ext ls -f **/.env.prod*
|
|
1239
|
+
├─ .env.production
|
|
1240
|
+
└─ apps
|
|
1241
|
+
└─ backend
|
|
1242
|
+
└─ .env.prod
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
</details>
|
|
1246
|
+
* <details><summary>`ext genexample`</summary><br>
|
|
1247
|
+
|
|
1248
|
+
In one command, generate a `.env.example` file from your current `.env` file contents.
|
|
1249
|
+
|
|
1250
|
+
```sh
|
|
1251
|
+
$ echo "HELLO=World" > .env
|
|
1252
|
+
|
|
1253
|
+
$ dotenvx ext genexample
|
|
1254
|
+
✔ updated .env.example (1)
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
```ini
|
|
1258
|
+
# .env.example
|
|
1259
|
+
HELLO=""
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
</details>
|
|
1263
|
+
* <details><summary>`ext genexample -f`</summary><br>
|
|
1264
|
+
|
|
1265
|
+
Pass multiple `.env` files to generate your `.env.example` file from the combination of their contents.
|
|
1266
|
+
|
|
1267
|
+
```sh
|
|
1268
|
+
$ echo "HELLO=World" > .env
|
|
1269
|
+
$ echo "DB_HOST=example.com" > .env.production
|
|
1270
|
+
|
|
1271
|
+
$ dotenvx ext genexample -f .env -f .env.production
|
|
1272
|
+
✔ updated .env.example (2)
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
```ini
|
|
1276
|
+
# .env.example
|
|
1277
|
+
HELLO=""
|
|
1278
|
+
DB_HOST=""
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
</details>
|
|
1282
|
+
* <details><summary>`ext genexample directory`</summary><br>
|
|
1283
|
+
|
|
1284
|
+
Generate a `.env.example` file inside the specified directory. Useful for monorepos.
|
|
1285
|
+
|
|
1286
|
+
```sh
|
|
1287
|
+
$ echo "HELLO=World" > .env
|
|
1288
|
+
$ mkdir -p apps/backend
|
|
1289
|
+
$ echo "HELLO=Backend" > apps/backend/.env
|
|
1290
|
+
|
|
1291
|
+
$ dotenvx ext genexample apps/backend
|
|
1292
|
+
✔ updated .env.example (1)
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
```ini
|
|
1296
|
+
# apps/backend/.env.example
|
|
1297
|
+
HELLO=""
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
</details>
|
|
1301
|
+
* <details><summary>`ext gitignore`</summary><br>
|
|
1302
|
+
|
|
1303
|
+
Gitignore your `.env` files.
|
|
1304
|
+
|
|
1305
|
+
```sh
|
|
1306
|
+
$ dotenvx ext gitignore
|
|
1307
|
+
creating .gitignore
|
|
1308
|
+
appending .env* to .gitignore
|
|
1309
|
+
done
|
|
1310
|
+
```
|
|
1311
|
+
|
|
1312
|
+
</details>
|
|
1313
|
+
* <details><summary>`ext precommit`</summary><br>
|
|
1314
|
+
|
|
1315
|
+
Prevent `.env` files from being committed to code.
|
|
1316
|
+
|
|
1317
|
+
```sh
|
|
1318
|
+
$ dotenvx ext precommit
|
|
1319
|
+
[dotenvx][precommit] success
|
|
1320
|
+
```
|
|
1321
|
+
|
|
1322
|
+
</details>
|
|
1323
|
+
* <details><summary>`ext precommit --install`</summary><br>
|
|
1324
|
+
|
|
1325
|
+
Install a shell script to `.git/hooks/pre-commit` to prevent accidentally committing any `.env` files to source control.
|
|
1326
|
+
|
|
1327
|
+
```sh
|
|
1328
|
+
$ dotenvx ext precommit --install
|
|
1329
|
+
[dotenvx][precommit] dotenvx precommit installed [.git/hooks/pre-commit]
|
|
1330
|
+
```
|
|
1331
|
+
|
|
1332
|
+
</details>
|
|
1333
|
+
* <details><summary>`ext prebuild`</summary><br>
|
|
1334
|
+
|
|
1335
|
+
Prevent `.env` files from being built into your docker containers.
|
|
1336
|
+
|
|
1337
|
+
Add it to your `Dockerfile`.
|
|
1338
|
+
|
|
1339
|
+
```sh
|
|
1340
|
+
RUN curl -fsS https://dotenvx.sh | sh
|
|
1341
|
+
|
|
1342
|
+
...
|
|
1343
|
+
|
|
1344
|
+
RUN dotenvx ext prebuild
|
|
1345
|
+
CMD ["dotenvx", "run", "--", "node", "index.js"]
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
</details>
|
|
1349
|
+
* <details><summary>`ext scan`</summary><br>
|
|
1350
|
+
|
|
1351
|
+
Use [gitleaks](https://gitleaks.io) under the hood to scan for possible secrets in your code.
|
|
1352
|
+
|
|
1353
|
+
```sh
|
|
1354
|
+
$ dotenvx ext scan
|
|
1355
|
+
|
|
1356
|
+
○
|
|
1357
|
+
│╲
|
|
1358
|
+
│ ○
|
|
1359
|
+
○ ░
|
|
1360
|
+
░ gitleaks
|
|
1361
|
+
|
|
1362
|
+
100 commits scanned.
|
|
1363
|
+
no leaks found
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
</details>
|
|
1367
|
+
|
|
1368
|
+
|
|
1369
1369
|
|
|
1370
|
+
## Guides
|
|
1371
|
+
|
|
1372
|
+
> Go deeper into using `dotenvx` with detailed framework and platform guides.
|
|
1373
|
+
>
|
|
1374
|
+
|
|
1375
|
+
* <a href="https://dotenvx.com/docs/platforms/digital-ocean">Digital Ocean <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/digitalocean.svg" alt="Digital Ocean Logo" width="20" height="20" style="fill:#0080FF;"></a>
|
|
1376
|
+
* <a href="https://dotenvx.com/docs/platforms/docker">Docker <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/docker.svg" alt="Docker Logo" width="20" height="20" style="fill:#2496ED;"></a>
|
|
1377
|
+
* <a href="https://dotenvx.com/docs/platforms/fly">Fly.io</a>
|
|
1378
|
+
* <a href="https://dotenvx.com/docs/cis/github-actions">GitHub Actions <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg" alt="GitHub Logo" width="20" height="20" style="fill:#181717;"></a>
|
|
1379
|
+
* <a href="https://dotenvx.com/docs/platforms/heroku">Heroku <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/heroku.svg" alt="Heroku Logo" width="20" height="20" style="fill:#430098;"></a>
|
|
1380
|
+
* <a href="https://dotenvx.com/docs/platforms/netlify">Netlify <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/netlify.svg" alt="Netlify Logo" width="20" height="20" style="fill:#00C7B7;"></a>
|
|
1381
|
+
* <a href="https://dotenvx.com/docs/package-managers/npm">NPM <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/npm.svg" alt="NPM Logo" width="20" height="20" style="fill:#CB3837;"></a>
|
|
1382
|
+
* <a href="https://dotenvx.com/docs/monorepos/nx">Nx <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/nx.svg" alt="Nx Logo" width="20" height="20" style="fill:#143055;"></a>
|
|
1383
|
+
* <a href="https://dotenvx.com/docs/platforms/render">Render <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/render.svg" alt="Render Logo" width="20" height="20" style="fill:#000000;"></a>
|
|
1384
|
+
* <a href="https://dotenvx.com/docs/platforms/railway">Railway <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/railway.svg" alt="Railway Logo" width="20" height="20" style="fill:#0B0D0E;"></a>
|
|
1385
|
+
* <a href="https://dotenvx.com/docs/monorepos/turborepo">Turborepo <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/turborepo.svg" alt="Turborepo Logo" width="20" height="20" style="fill:#EF4444;"></a>
|
|
1386
|
+
* <a href="https://dotenvx.com/docs/platforms/vercel">Vercel <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/vercel.svg" alt="Vercel Logo" width="20" height="20" style="fill:#000000;"></a>
|
|
1387
|
+
* [more](https://dotenvx.com/docs/guides)
|
|
1388
|
+
* <a href="https://dotenvx.com/docs/guides#node-js">Node.js <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/nodejs.svg" alt="Node.js Logo" width="20" height="20" style="fill:#5FA04E;"></a>
|
|
1389
|
+
* <a href="https://dotenvx.com/docs/guides#python">Python <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/python.svg" alt="Python Logo" width="20" height="20" style="fill:#3776AB;"></a>
|
|
1390
|
+
* <a href="https://dotenvx.com/docs/guides#php">PHP <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/php.svg" alt="PHP Logo" width="20" height="20" style="fill:#777BB4;"></a>
|
|
1391
|
+
* <a href="https://dotenvx.com/docs/guides#ruby">Ruby <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/ruby.svg" alt="Ruby Logo" width="20" height="20" style="fill:#CC342D;"></a>
|
|
1392
|
+
* <a href="https://dotenvx.com/docs/guides#rust">Rust <img src="https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/rust.svg" alt="Rust Logo" width="20" height="20" style="fill:#000000;"></a>
|
|
1370
1393
|
|
|
1371
1394
|
|
|
1372
1395
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.1.0",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
4
|
"description": "a better dotenv–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"CHANGELOG.md"
|
|
16
16
|
],
|
|
17
17
|
"main": "src/lib/main.js",
|
|
18
|
+
"types": "src/lib/main.d.ts",
|
|
18
19
|
"bin": {
|
|
19
20
|
"dotenvx": "./src/cli/dotenvx.js",
|
|
20
21
|
"git-dotenvx": "./src/cli/dotenvx.js"
|
|
@@ -36,7 +37,6 @@
|
|
|
36
37
|
"conf": "^10.2.0",
|
|
37
38
|
"diff": "^5.2.0",
|
|
38
39
|
"dotenv": "^16.4.5",
|
|
39
|
-
"dotenv-expand": "^11.0.6",
|
|
40
40
|
"eciesjs": "^0.4.6",
|
|
41
41
|
"execa": "^5.1.1",
|
|
42
42
|
"glob": "^10.3.10",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// * /
|
|
2
|
+
// * (\\)? # is it escaped with a backslash?
|
|
3
|
+
// * (\$) # literal $
|
|
4
|
+
// * (?!\() # shouldnt be followed by parenthesis
|
|
5
|
+
// * (\{?) # first brace wrap opening
|
|
6
|
+
// * ([\w.]+) # key
|
|
7
|
+
// * (?::-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))? # optional default nested 3 times
|
|
8
|
+
// * (\}?) # last brace warp closing
|
|
9
|
+
// * /xi
|
|
10
|
+
|
|
11
|
+
const DOTENV_SUBSTITUTION_REGEX = /(\\)?(\$)(?!\()(\{?)([\w.]+)(?::?-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))?(\}?)/gi
|
|
12
|
+
|
|
13
|
+
function _resolveEscapeSequences (value) {
|
|
14
|
+
return value.replace(/\\\$/g, '$')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function interpolate (value, lookups) {
|
|
18
|
+
return value.replace(DOTENV_SUBSTITUTION_REGEX, (match, escaped, dollarSign, openBrace, key, defaultValue, closeBrace) => {
|
|
19
|
+
if (escaped === '\\') {
|
|
20
|
+
return match.slice(1)
|
|
21
|
+
} else {
|
|
22
|
+
if (lookups[key]) {
|
|
23
|
+
// avoid recursion from EXPAND_SELF=$EXPAND_SELF
|
|
24
|
+
if (lookups[key] === value) {
|
|
25
|
+
return lookups[key]
|
|
26
|
+
} else {
|
|
27
|
+
return interpolate(lookups[key], lookups)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (defaultValue) {
|
|
32
|
+
if (defaultValue.startsWith('$')) {
|
|
33
|
+
return interpolate(defaultValue, lookups)
|
|
34
|
+
} else {
|
|
35
|
+
return defaultValue
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return ''
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function expand (options) {
|
|
45
|
+
let processEnv = process.env
|
|
46
|
+
if (options && options.processEnv != null) {
|
|
47
|
+
processEnv = options.processEnv
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const combined = { ...processEnv, ...options.parsed }
|
|
51
|
+
const combinedReversed = { ...options.parsed, ...processEnv }
|
|
52
|
+
|
|
53
|
+
for (const key in options.parsed) {
|
|
54
|
+
const value = options.parsed[key]
|
|
55
|
+
|
|
56
|
+
// interpolate using both file and processEnv (file interpolation wins. used for --overload later)
|
|
57
|
+
const fileValue = _resolveEscapeSequences(interpolate(value, combined))
|
|
58
|
+
options.parsed[key] = fileValue
|
|
59
|
+
|
|
60
|
+
if (fileValue === _resolveEscapeSequences(value)) {
|
|
61
|
+
continue // no change means no expansion, move on
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (processEnv[key]) {
|
|
65
|
+
continue // already has a value in process.env, move on
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// interpolate with processEnv only (used for default no overload)
|
|
69
|
+
const processEnvValue = interpolate(value, combinedReversed) // could be empty string ''
|
|
70
|
+
if (processEnvValue) {
|
|
71
|
+
processEnv[key] = _resolveEscapeSequences(processEnvValue) // set it
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
parsed: options.parsed,
|
|
77
|
+
processEnv
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports.expand = expand
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const dotenv = require('dotenv')
|
|
2
|
-
const dotenvExpand = require('dotenv-expand')
|
|
3
2
|
const dotenvEval = require('./dotenvEval')
|
|
3
|
+
const dotenvExpand = require('./dotenvExpand')
|
|
4
4
|
const decryptValue = require('./decryptValue')
|
|
5
5
|
|
|
6
|
-
function parseDecryptEvalExpand (src, privateKey = null) {
|
|
6
|
+
function parseDecryptEvalExpand (src, privateKey = null, processEnv = process.env) {
|
|
7
7
|
// parse
|
|
8
8
|
const parsed = dotenv.parse(src)
|
|
9
9
|
|
|
@@ -22,19 +22,20 @@ function parseDecryptEvalExpand (src, privateKey = null) {
|
|
|
22
22
|
}
|
|
23
23
|
const evaled = dotenvEval.eval(inputParsed).parsed
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// expanded
|
|
26
|
+
const inputEvaled = {
|
|
27
|
+
processEnv,
|
|
28
|
+
parsed: evaled
|
|
28
29
|
}
|
|
29
|
-
const expanded = dotenvExpand.expand(
|
|
30
|
+
const expanded = dotenvExpand.expand(inputEvaled)
|
|
30
31
|
|
|
31
|
-
//
|
|
32
|
+
// for logging only log the original keys existing in parsed. this feels unnecessarily complex - like dotenv-expand should support the ability to inject additional `process.env` or objects as it sees fit to the object it wants to expand
|
|
32
33
|
const result = {}
|
|
33
34
|
for (const key in parsed) {
|
|
34
|
-
result[key] = expanded[key]
|
|
35
|
+
result[key] = expanded.parsed[key]
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
return result
|
|
38
|
+
return { parsed: result, processEnv }
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
module.exports = parseDecryptEvalExpand
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import type { URL } from 'url';
|
|
2
|
+
import type { Change } from 'diff';
|
|
3
|
+
|
|
4
|
+
export interface DotenvParseOutput {
|
|
5
|
+
[name: string]: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Parses a string or buffer in the .env file format into an object.
|
|
10
|
+
*
|
|
11
|
+
* @see https://dotenvx.com/docs
|
|
12
|
+
* @param src - contents to be parsed. example: `'DB_HOST=localhost'`
|
|
13
|
+
* @returns an object with keys and values based on `src`. example: `{ DB_HOST : 'localhost' }`
|
|
14
|
+
*/
|
|
15
|
+
export function parse<T extends DotenvParseOutput = DotenvParseOutput>(
|
|
16
|
+
src: string | Buffer
|
|
17
|
+
): T;
|
|
18
|
+
|
|
19
|
+
export interface DotenvConfigOptions {
|
|
20
|
+
/** *
|
|
21
|
+
* Specify a custom path if your file containing environment variables is located elsewhere.
|
|
22
|
+
* Can also be an array of strings, specifying multiple paths.
|
|
23
|
+
*
|
|
24
|
+
* @default require('path').resolve(process.cwd(), '.env')
|
|
25
|
+
* @example require('@dotenvx/dotenvx').config({ path: '/custom/path/to/.env' })
|
|
26
|
+
* @example require('@dotenvx/dotenvx').config({ path: ['/path/to/first.env', '/path/to/second.env'] })
|
|
27
|
+
*/
|
|
28
|
+
path?: string | string[] | URL;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Specify the encoding of your file containing environment variables.
|
|
32
|
+
*
|
|
33
|
+
* @default 'utf8'
|
|
34
|
+
* @example require('@dotenvx/dotenvx').config({ encoding: 'latin1' })
|
|
35
|
+
*/
|
|
36
|
+
encoding?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Turn on logging to help debug why certain keys or values are not being set as you expect.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
* @example require('@dotenvx/dotenvx').config({ debug: process.env.DEBUG })
|
|
43
|
+
*/
|
|
44
|
+
debug?: boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Override any environment variables that have already been set on your machine with values from your .env file.
|
|
48
|
+
* @default false
|
|
49
|
+
* @example require('@dotenvx/dotenvx').config({ override: true })
|
|
50
|
+
* @alias overload
|
|
51
|
+
*/
|
|
52
|
+
override?: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @default false
|
|
56
|
+
* @alias override
|
|
57
|
+
*/
|
|
58
|
+
overload?: boolean;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Specify an object to write your secrets to. Defaults to process.env environment variables.
|
|
62
|
+
*
|
|
63
|
+
* @default process.env
|
|
64
|
+
* @example const processEnv = {}; require('@dotenvx/dotenvx').config({ processEnv: processEnv })
|
|
65
|
+
*/
|
|
66
|
+
processEnv?: DotenvPopulateInput;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Pass the DOTENV_KEY directly to config options. Defaults to looking for process.env.DOTENV_KEY environment variable. Note this only applies to decrypting .env.vault files. If passed as null or undefined, or not passed at all, dotenv falls back to its traditional job of parsing a .env file.
|
|
70
|
+
*
|
|
71
|
+
* @default undefined
|
|
72
|
+
* @example require('@dotenvx/dotenvx').config({ DOTENV_KEY: 'dotenv://:key_1234…@dotenvx.com/vault/.env.vault?environment=production' })
|
|
73
|
+
*/
|
|
74
|
+
DOTENV_KEY?: string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Do not warn for missing .env files
|
|
78
|
+
*/
|
|
79
|
+
convention?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface DotenvConfigOutput {
|
|
83
|
+
error?: Error;
|
|
84
|
+
parsed?: DotenvParseOutput;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface DotenvPopulateInput {
|
|
88
|
+
[name: string]: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Loads `.env` file contents into process.env by default. If `DOTENV_KEY` is present, it smartly attempts to load encrypted `.env.vault` file contents into process.env.
|
|
93
|
+
*
|
|
94
|
+
* @see https://dotenvx.com/docs
|
|
95
|
+
*
|
|
96
|
+
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true, override: false }`
|
|
97
|
+
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
|
98
|
+
*
|
|
99
|
+
*/
|
|
100
|
+
export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Loads `.env` file contents into process.env.
|
|
104
|
+
*
|
|
105
|
+
* @see https://dotenvx.com/docs
|
|
106
|
+
*
|
|
107
|
+
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true, override: false }`
|
|
108
|
+
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
|
109
|
+
*
|
|
110
|
+
*/
|
|
111
|
+
export function configDotenv(options?: DotenvConfigOptions): DotenvConfigOutput;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Decrypt ciphertext
|
|
115
|
+
*
|
|
116
|
+
* @see https://dotenvx.com/docs
|
|
117
|
+
*
|
|
118
|
+
* @param encrypted - the encrypted ciphertext string
|
|
119
|
+
* @param keyStr - the decryption key string
|
|
120
|
+
*/
|
|
121
|
+
export function decrypt(encrypted: string, keyStr: string): string;
|
|
122
|
+
|
|
123
|
+
export type EncryptRowOutput = {
|
|
124
|
+
keys: string[];
|
|
125
|
+
filepath: string;
|
|
126
|
+
envFilepath: string;
|
|
127
|
+
publicKey: string;
|
|
128
|
+
privateKey: string;
|
|
129
|
+
privateKeyName: string;
|
|
130
|
+
privateKeyAdded: boolean;
|
|
131
|
+
envSrc: string;
|
|
132
|
+
changed: boolean;
|
|
133
|
+
error?: Error;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type EncryptOutput = {
|
|
137
|
+
processedEnvFiles: EncryptRowOutput[];
|
|
138
|
+
changedFilepaths: string[];
|
|
139
|
+
unchangedFilepaths: string[];
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Encrypt plaintext
|
|
144
|
+
*
|
|
145
|
+
* @see https://dotenvx.com/docs
|
|
146
|
+
* @param envFile - path to the .env file
|
|
147
|
+
*/
|
|
148
|
+
export function encrypt(envFile: string): EncryptOutput;
|
|
149
|
+
|
|
150
|
+
export type VaultEncryptOutput = {
|
|
151
|
+
dotenvKeys: Record<string, string>;
|
|
152
|
+
dotenvKeysFile: string;
|
|
153
|
+
addedKeys: string[];
|
|
154
|
+
existingKeys: string[];
|
|
155
|
+
dotenvVaultFile: string;
|
|
156
|
+
addedVaults: string[];
|
|
157
|
+
existingVaults: string[];
|
|
158
|
+
addedDotenvFilenames: string[];
|
|
159
|
+
envFile: string | string[];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Encrypt plaintext
|
|
164
|
+
*
|
|
165
|
+
* @see https://dotenvx.com/docs
|
|
166
|
+
* @param directory - current working directory
|
|
167
|
+
* @param envFile - path to the .env file(s)
|
|
168
|
+
*/
|
|
169
|
+
export function vaultEncrypt(
|
|
170
|
+
directory: string,
|
|
171
|
+
envFile: string | string[]
|
|
172
|
+
): VaultEncryptOutput;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* List all env files in the current working directory
|
|
176
|
+
*
|
|
177
|
+
* @param directory - current working directory
|
|
178
|
+
* @param envFile - glob pattern to match env files
|
|
179
|
+
*/
|
|
180
|
+
export function ls(directory: string, envFile: string): string[];
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get the value of a key from the .env file
|
|
184
|
+
*
|
|
185
|
+
* @param [key] - the key to get the value of
|
|
186
|
+
* @param [envs] - the environment(s) to get the value from
|
|
187
|
+
* @param [overload] - whether to overload the value from the .env file
|
|
188
|
+
* @param [DOTENV_KEY] - the decryption key string
|
|
189
|
+
* @param [all] - whether to return all values
|
|
190
|
+
*/
|
|
191
|
+
export function get(
|
|
192
|
+
key?: string,
|
|
193
|
+
envs: string[] = [],
|
|
194
|
+
overload = false,
|
|
195
|
+
DOTENV_KEY = '',
|
|
196
|
+
all = false
|
|
197
|
+
): Record<string, string | undefined> | string | undefined;
|
|
198
|
+
|
|
199
|
+
export type SetOutput = {
|
|
200
|
+
key: string;
|
|
201
|
+
value: string;
|
|
202
|
+
filepath: string;
|
|
203
|
+
envFilepath: string;
|
|
204
|
+
envSrc: string;
|
|
205
|
+
changed: boolean;
|
|
206
|
+
encryptedValue?: string;
|
|
207
|
+
publicKey?: string;
|
|
208
|
+
privateKey?: string;
|
|
209
|
+
privateKeyAdded?: boolean;
|
|
210
|
+
privateKeyName?: string;
|
|
211
|
+
error?: Error;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set the value of a key in the .env file
|
|
216
|
+
*
|
|
217
|
+
* @param key - the key to set the value of
|
|
218
|
+
* @param value - the value to set
|
|
219
|
+
* @param envFile - the path to the .env file
|
|
220
|
+
* @param [encrypt] - whether to encrypt the value
|
|
221
|
+
*/
|
|
222
|
+
export function set(
|
|
223
|
+
key: string,
|
|
224
|
+
value: string,
|
|
225
|
+
envFile: string | string,
|
|
226
|
+
encrypt?: boolean
|
|
227
|
+
): EncryptOutput;
|
|
228
|
+
|
|
229
|
+
type StatusRow = {
|
|
230
|
+
filename: string;
|
|
231
|
+
filepath: string;
|
|
232
|
+
environment: string;
|
|
233
|
+
raw: string;
|
|
234
|
+
decrypted: any;
|
|
235
|
+
differences: Change[];
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export type StatusOutput = {
|
|
239
|
+
changes: StatusRow[];
|
|
240
|
+
nochanges: StatusRow[];
|
|
241
|
+
untracked: StatusRow[];
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check the differences between the .env file and the decrypted values
|
|
246
|
+
*
|
|
247
|
+
* @param directory - current working directory
|
|
248
|
+
*/
|
|
249
|
+
export function status(directory: string): StatusOutput;
|
|
250
|
+
|
|
251
|
+
export type GenExampleOutput = {
|
|
252
|
+
envExampleFile: string;
|
|
253
|
+
envFile: string | string[];
|
|
254
|
+
exampleFilepath: string;
|
|
255
|
+
addedKeys: string[];
|
|
256
|
+
injected: Record<string, string>;
|
|
257
|
+
preExisted: Record<string, string>;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Generate an example .env file
|
|
262
|
+
*
|
|
263
|
+
* @param directory - current working directory
|
|
264
|
+
* @param envFile - path to the .env file(s)
|
|
265
|
+
*/
|
|
266
|
+
export function genexample(
|
|
267
|
+
directory: string,
|
|
268
|
+
envFile: string
|
|
269
|
+
): GenExampleOutput;
|
|
270
|
+
|
|
271
|
+
export type Settings = {
|
|
272
|
+
DOTENVX_SETTINGS_FILEPATH: string;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
type KeyOfSettings = Extract<keyof Settings, string>;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get the dotenvx settings
|
|
279
|
+
*
|
|
280
|
+
* @param [key] - the key to get the value of
|
|
281
|
+
*/
|
|
282
|
+
export function settings(
|
|
283
|
+
key: KeyOfSettings | undefined | null = null
|
|
284
|
+
): Settings;
|
package/src/lib/main.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
const path = require('path')
|
|
2
3
|
const { logger } = require('./../shared/logger')
|
|
3
4
|
const dotenv = require('dotenv')
|
|
@@ -18,6 +19,8 @@ const dotenvOptionPaths = require('./helpers/dotenvOptionPaths')
|
|
|
18
19
|
const { setLogLevel } = require('../shared/logger')
|
|
19
20
|
|
|
20
21
|
// proxies to dotenv
|
|
22
|
+
|
|
23
|
+
/** @type {import('./main').config} */
|
|
21
24
|
const config = function (options = {}) {
|
|
22
25
|
// allow user to set processEnv to write to
|
|
23
26
|
let processEnv = process.env
|
|
@@ -44,29 +47,46 @@ const config = function (options = {}) {
|
|
|
44
47
|
for (const optionPath of optionPaths) {
|
|
45
48
|
// if DOTENV_KEY is set then assume we are checking envVaultFile
|
|
46
49
|
if (DOTENV_KEY) {
|
|
47
|
-
envs.push({
|
|
50
|
+
envs.push({
|
|
51
|
+
type: 'envVaultFile',
|
|
52
|
+
value: path.join(path.dirname(optionPath), '.env.vault')
|
|
53
|
+
})
|
|
48
54
|
} else {
|
|
49
55
|
envs.push({ type: 'envFile', value: optionPath })
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
|
|
53
|
-
const {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
const { processedEnvs, readableFilepaths, uniqueInjectedKeys } = new Run(
|
|
60
|
+
envs,
|
|
61
|
+
overload,
|
|
62
|
+
DOTENV_KEY,
|
|
63
|
+
processEnv
|
|
64
|
+
).run()
|
|
58
65
|
|
|
59
66
|
let lastError
|
|
67
|
+
/** @type {Record<string, string>} */
|
|
60
68
|
const parsedAll = {}
|
|
61
69
|
|
|
62
70
|
for (const processedEnv of processedEnvs) {
|
|
63
71
|
if (processedEnv.type === 'envVaultFile') {
|
|
64
|
-
logger.verbose(
|
|
65
|
-
|
|
72
|
+
logger.verbose(
|
|
73
|
+
`loading env from encrypted ${processedEnv.filepath} (${path.resolve(
|
|
74
|
+
processedEnv.filepath
|
|
75
|
+
)})`
|
|
76
|
+
)
|
|
77
|
+
logger.debug(
|
|
78
|
+
`decrypting encrypted env from ${
|
|
79
|
+
processedEnv.filepath
|
|
80
|
+
} (${path.resolve(processedEnv.filepath)})`
|
|
81
|
+
)
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
if (processedEnv.type === 'envFile') {
|
|
69
|
-
logger.verbose(
|
|
85
|
+
logger.verbose(
|
|
86
|
+
`loading env from ${processedEnv.filepath} (${path.resolve(
|
|
87
|
+
processedEnv.filepath
|
|
88
|
+
)})`
|
|
89
|
+
)
|
|
70
90
|
}
|
|
71
91
|
|
|
72
92
|
if (processedEnv.error) {
|
|
@@ -76,7 +96,9 @@ const config = function (options = {}) {
|
|
|
76
96
|
// do not warn for conventions (too noisy)
|
|
77
97
|
if (!options.convention) {
|
|
78
98
|
logger.warnv(processedEnv.error)
|
|
79
|
-
logger.help(
|
|
99
|
+
logger.help(
|
|
100
|
+
`? add one with [echo "HELLO=World" > ${processedEnv.filepath}] and re-run [dotenvx run -- yourcommand]`
|
|
101
|
+
)
|
|
80
102
|
}
|
|
81
103
|
} else {
|
|
82
104
|
logger.warnv(processedEnv.error)
|
|
@@ -99,8 +121,12 @@ const config = function (options = {}) {
|
|
|
99
121
|
// verbose/debug preExisted key/value
|
|
100
122
|
const preExisted = processedEnv.preExisted
|
|
101
123
|
for (const [key, value] of Object.entries(preExisted)) {
|
|
102
|
-
logger.verbose(
|
|
103
|
-
|
|
124
|
+
logger.verbose(
|
|
125
|
+
`${key} pre-exists (protip: use --overload to override)`
|
|
126
|
+
)
|
|
127
|
+
logger.debug(
|
|
128
|
+
`${key} pre-exists as ${value} (protip: use --overload to override)`
|
|
129
|
+
)
|
|
104
130
|
}
|
|
105
131
|
}
|
|
106
132
|
}
|
|
@@ -126,47 +152,66 @@ const config = function (options = {}) {
|
|
|
126
152
|
}
|
|
127
153
|
}
|
|
128
154
|
|
|
155
|
+
/** @type {import('./main').configDotenv} */
|
|
129
156
|
const configDotenv = function (options) {
|
|
130
157
|
return dotenv.configDotenv(options)
|
|
131
158
|
}
|
|
132
159
|
|
|
160
|
+
/** @type {import('./main').parse} */
|
|
133
161
|
const parse = function (src) {
|
|
134
162
|
return dotenv.parse(src)
|
|
135
163
|
}
|
|
136
164
|
|
|
165
|
+
/** @type {import('./main').vaultEncrypt} */
|
|
137
166
|
const vaultEncrypt = function (directory, envFile) {
|
|
138
167
|
return new VaultEncrypt(directory, envFile).run()
|
|
139
168
|
}
|
|
140
169
|
|
|
170
|
+
/** @type {import('./main').ls} */
|
|
141
171
|
const ls = function (directory, envFile) {
|
|
142
172
|
return new Ls(directory, envFile).run()
|
|
143
173
|
}
|
|
144
174
|
|
|
175
|
+
/** @type {import('./main').genexample} */
|
|
145
176
|
const genexample = function (directory, envFile) {
|
|
146
177
|
return new Genexample(directory, envFile).run()
|
|
147
178
|
}
|
|
148
179
|
|
|
149
|
-
|
|
180
|
+
/** @type {import('./main').get} */
|
|
181
|
+
const get = function (
|
|
182
|
+
key,
|
|
183
|
+
envs = [],
|
|
184
|
+
overload = false,
|
|
185
|
+
DOTENV_KEY = '',
|
|
186
|
+
all = false
|
|
187
|
+
) {
|
|
150
188
|
return new Get(key, envs, overload, DOTENV_KEY, all).run()
|
|
151
189
|
}
|
|
152
190
|
|
|
191
|
+
/** @type {import('./main').set} */
|
|
153
192
|
const set = function (key, value, envFile, encrypt) {
|
|
154
193
|
return new Sets(key, value, envFile, encrypt).run()
|
|
155
194
|
}
|
|
156
195
|
|
|
196
|
+
/** @type {import('./main').encrypt} */
|
|
157
197
|
const encrypt = function (envFile) {
|
|
158
198
|
return new Encrypt(envFile).run()
|
|
159
199
|
}
|
|
160
200
|
|
|
201
|
+
/** @type {import('./main').status} */
|
|
161
202
|
const status = function (directory) {
|
|
162
203
|
return new Status(directory).run()
|
|
163
204
|
}
|
|
164
205
|
|
|
206
|
+
/** @type {import('./main').settings} */
|
|
165
207
|
const settings = function (key = null) {
|
|
208
|
+
// @ts-ignore
|
|
166
209
|
return new Settings(key).run()
|
|
167
210
|
}
|
|
168
211
|
|
|
169
212
|
// misc/cleanup
|
|
213
|
+
|
|
214
|
+
/** @type {import('./main').decrypt} */
|
|
170
215
|
const decrypt = function (encrypted, keyStr) {
|
|
171
216
|
try {
|
|
172
217
|
return dotenv.decrypt(encrypted, keyStr)
|
|
@@ -174,9 +219,15 @@ const decrypt = function (encrypted, keyStr) {
|
|
|
174
219
|
switch (e.code) {
|
|
175
220
|
case 'DECRYPTION_FAILED':
|
|
176
221
|
// more helpful error when decryption fails
|
|
177
|
-
logger.error(
|
|
178
|
-
|
|
179
|
-
|
|
222
|
+
logger.error(
|
|
223
|
+
'[DECRYPTION_FAILED] Unable to decrypt .env.vault with DOTENV_KEY.'
|
|
224
|
+
)
|
|
225
|
+
logger.help(
|
|
226
|
+
'[DECRYPTION_FAILED] Run with debug flag [dotenvx run --debug -- yourcommand] or manually run [echo $DOTENV_KEY] to compare it to the one in .env.keys.'
|
|
227
|
+
)
|
|
228
|
+
logger.debug(
|
|
229
|
+
`[DECRYPTION_FAILED] DOTENV_KEY is ${process.env.DOTENV_KEY}`
|
|
230
|
+
)
|
|
180
231
|
process.exit(1)
|
|
181
232
|
break
|
|
182
233
|
default:
|
|
@@ -57,7 +57,9 @@ class Genexample {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
const currentEnvExample = dotenv.configDotenv({ path: exampleFilepath }).parsed
|
|
60
|
+
/** @type {Record<string, string>} */
|
|
60
61
|
const injected = {}
|
|
62
|
+
/** @type {Record<string, string>} */
|
|
61
63
|
const preExisted = {}
|
|
62
64
|
|
|
63
65
|
for (const key of [...keys]) {
|
package/src/lib/services/get.js
CHANGED
|
@@ -21,6 +21,7 @@ class Get {
|
|
|
21
21
|
|
|
22
22
|
// typical scenario - return only envs that were identified in the .env file
|
|
23
23
|
// iterate over all processedEnvs.parsed and grab from processEnv
|
|
24
|
+
/** @type {Record<string, string>} */
|
|
24
25
|
const result = {}
|
|
25
26
|
for (const processedEnv of processedEnvs) {
|
|
26
27
|
// parsed means we saw the key in a file or --env flag. this effectively filters out any preset machine envs - while still respecting complex evaluating, expansion, and overload. in other words, the value might be the machine value because the key was displayed in a .env file
|
package/src/lib/services/run.js
CHANGED
|
@@ -63,7 +63,8 @@ class Run {
|
|
|
63
63
|
row.string = env
|
|
64
64
|
|
|
65
65
|
try {
|
|
66
|
-
const parsed = parseDecryptEvalExpand(env)
|
|
66
|
+
const { parsed } = parseDecryptEvalExpand(env, null, this.processEnv)
|
|
67
|
+
|
|
67
68
|
row.parsed = parsed
|
|
68
69
|
this.readableStrings.add(env)
|
|
69
70
|
|
|
@@ -93,7 +94,7 @@ class Run {
|
|
|
93
94
|
|
|
94
95
|
// if DOTENV_PRIVATE_KEY_* already set in process.env then use it
|
|
95
96
|
const privateKey = smartDotenvPrivateKey(envFilepath)
|
|
96
|
-
const parsed = parseDecryptEvalExpand(src, privateKey)
|
|
97
|
+
const { parsed } = parseDecryptEvalExpand(src, privateKey, this.processEnv)
|
|
97
98
|
row.parsed = parsed
|
|
98
99
|
|
|
99
100
|
const { injected, preExisted } = this._inject(this.processEnv, parsed, this.overload)
|
|
@@ -162,7 +163,7 @@ class Run {
|
|
|
162
163
|
|
|
163
164
|
try {
|
|
164
165
|
// parse this. it's the equivalent of the .env file
|
|
165
|
-
const parsed = parseDecryptEvalExpand(decrypted)
|
|
166
|
+
const { parsed } = parseDecryptEvalExpand(decrypted, null, this.processEnv)
|
|
166
167
|
row.parsed = parsed
|
|
167
168
|
|
|
168
169
|
const { injected, preExisted } = this._inject(this.processEnv, parsed, this.overload)
|