@dotenvx/dotenvx 1.30.0 → 1.31.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 CHANGED
@@ -2,7 +2,20 @@
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.30.0...main)
5
+ [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.31.0...main)
6
+
7
+ ## [1.31.0](https://github.com/dotenvx/dotenvx/compare/v1.30.1...v1.31.0)
8
+
9
+ ### Added
10
+
11
+ * expose `main.set` function ([#492](https://github.com/dotenvx/dotenvx/pull/492))
12
+ * add missing types for `main.config` ([#491](https://github.com/dotenvx/dotenvx/pull/491))
13
+
14
+ ## [1.30.1](https://github.com/dotenvx/dotenvx/compare/v1.30.0...v1.30.1)
15
+
16
+ ### Added
17
+
18
+ * support complex command substitution combining variable expansion ([#490](https://github.com/dotenvx/dotenvx/pull/490))
6
19
 
7
20
  ## [1.30.0](https://github.com/dotenvx/dotenvx/compare/v1.29.0...v1.30.0)
8
21
 
@@ -10,7 +23,7 @@ All notable changes to this project will be documented in this file. See [standa
10
23
 
11
24
  * add `-fk` (`--env-keys-file`) flag to customize the path to your `.env.keys` file with `run, get, set, encrypt, decrypt, and keypair` 🎉 ([#486](https://github.com/dotenvx/dotenvx/pull/486))
12
25
 
13
- This is great for monorepos. Maintain one `.env.keys` file across multiple monorepos `.env*` files.
26
+ This is great for monorepos. Maintain one `.env.keys` file across all your apps.
14
27
 
15
28
  ```sh
16
29
  $ dotenvx encrypt -fk .env.keys -f apps/backend/.env
package/README.md CHANGED
@@ -2081,6 +2081,17 @@ More examples
2081
2081
  Hello World
2082
2082
  ```
2083
2083
  </details>
2084
+ * <details><summary>`set(KEY, value)`</summary><br>
2085
+
2086
+ Programatically set an environment variable.
2087
+
2088
+ ```js
2089
+ // index.js
2090
+ const dotenvx = require('@dotenvx/dotenvx')
2091
+ dotenvx.set('HELLO', 'World', { path: '.env' })
2092
+ ```
2093
+
2094
+ </details>
2084
2095
 
2085
2096
  &nbsp;
2086
2097
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.30.0",
2
+ "version": "1.31.0",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "a better dotenv–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -28,7 +28,6 @@
28
28
  "standard:fix": "standard --fix",
29
29
  "test": "tap run --allow-empty-coverage --disable-coverage --timeout=60000",
30
30
  "test-coverage": "tap run --show-full-coverage --timeout=60000",
31
- "test-single": "tap run --coverage-report=none tests/cli/actions/decrypt.test.js",
32
31
  "testshell": "bash shellspec",
33
32
  "prerelease": "npm test && npm run testshell",
34
33
  "release": "standard-version"
@@ -0,0 +1,33 @@
1
+ const path = require('path')
2
+
3
+ const conventions = require('./conventions')
4
+ const dotenvOptionPaths = require('./dotenvOptionPaths')
5
+ const DeprecationNotice = require('./deprecationNotice')
6
+
7
+ function buildEnvs (options, DOTENV_KEY = undefined) {
8
+ // build envs using user set option.path
9
+ const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
10
+
11
+ let envs = []
12
+ if (options.convention) { // handle shorthand conventions
13
+ envs = conventions(options.convention).concat(envs)
14
+ }
15
+
16
+ new DeprecationNotice({ DOTENV_KEY }).dotenvKey() // DEPRECATION NOTICE
17
+
18
+ for (const optionPath of optionPaths) {
19
+ // if DOTENV_KEY is set then assume we are checking envVaultFile
20
+ if (DOTENV_KEY) {
21
+ envs.push({
22
+ type: 'envVaultFile',
23
+ value: path.join(path.dirname(optionPath), '.env.vault')
24
+ })
25
+ } else {
26
+ envs.push({ type: 'envFile', value: optionPath })
27
+ }
28
+ }
29
+
30
+ return envs
31
+ }
32
+
33
+ module.exports = buildEnvs
@@ -136,10 +136,9 @@ class Parse {
136
136
  eval (value) {
137
137
  // Match everything between the outermost $() using a regex with non-capturing groups
138
138
  const matches = value.match(/\$\(([^)]+(?:\)[^(]*)*)\)/g) || []
139
-
140
- return matches.reduce(function (newValue, match) {
139
+ return matches.reduce((newValue, match) => {
141
140
  const command = match.slice(2, -1) // Extract command by removing $() wrapper
142
- const result = chomp(execSync(command).toString()) // execute command
141
+ const result = chomp(execSync(command, { env: { ...this.processEnv, ...this.runningParsed } }).toString()) // execute command (including runningParsed)
143
142
  return newValue.replace(match, result) // Replace match with result
144
143
  }, value)
145
144
  }
package/src/lib/main.d.ts CHANGED
@@ -41,7 +41,7 @@ export interface DotenvParseOutput {
41
41
  *
42
42
  * @see https://dotenvx.com/docs
43
43
  * @param src - contents to be parsed. example: `'DB_HOST=localhost'`
44
- * @param options - additional options. example: `{ prcoessEnv: {}, privateKey: '<privateKey>', overload: false }`
44
+ * @param options - additional options. example: `{ processEnv: {}, privateKey: '<privateKey>', overload: false }`
45
45
  * @returns an object with keys and values based on `src`. example: `{ DB_HOST : 'localhost' }`
46
46
  */
47
47
  export function parse<T extends DotenvParseOutput = DotenvParseOutput>(
@@ -82,6 +82,21 @@ export interface DotenvConfigOptions {
82
82
  */
83
83
  override?: boolean;
84
84
 
85
+ /**
86
+ * Throw immediately if an error is encountered - like a missing .env file.
87
+ * @default false
88
+ * @example require('@dotenvx/dotenvx').config({ strict: true })
89
+ */
90
+ strict?: boolean;
91
+
92
+ /**
93
+ * Suppress specific errors like MISSING_ENV_FILE. The error keys can be found
94
+ * in src/lib/helpers/errors.js
95
+ * @default []
96
+ * @example require('@dotenvx/dotenvx').config({ ignore: ['MISSING_ENV_FILE'] })
97
+ */
98
+ ignore?: string[];
99
+
85
100
  /**
86
101
  * Specify an object to write your secrets to. Defaults to process.env environment variables.
87
102
  *
@@ -90,6 +105,13 @@ export interface DotenvConfigOptions {
90
105
  */
91
106
  processEnv?: DotenvPopulateInput;
92
107
 
108
+ /**
109
+ * Customize the path to your .env.keys file. This is useful with monorepos.
110
+ * @default []
111
+ * @example require('@dotenvx/dotenvx').config({ envKeysFile: '../../.env.keys'} })
112
+ */
113
+ envKeysFile?: string;
114
+
93
115
  /**
94
116
  * 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.
95
117
  *
@@ -158,6 +180,59 @@ export interface DotenvPopulateInput {
158
180
  */
159
181
  export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
160
182
 
183
+ export interface SetOptions {
184
+ /**
185
+ * Specify a custom path if your file containing environment variables is located elsewhere.
186
+ * Can also be an array of strings, specifying multiple paths.
187
+ *
188
+ * @default require('path').resolve(process.cwd(), '.env')
189
+ * @example require('@dotenvx/dotenvx').set(key, value, { path: '/custom/path/to/.env' })
190
+ * @example require('@dotenvx/dotenvx').set(key, value, { path: ['/path/to/first.env', '/path/to/second.env'] })
191
+ */
192
+ path?: string | string[] | URL;
193
+
194
+ /**
195
+ * Customize the path to your .env.keys file. This is useful with monorepos.
196
+ * @default []
197
+ * @example require('@dotenvx/dotenvx').config(key, value, { envKeysFile: '../../.env.keys'} })
198
+ */
199
+ envKeysFile?: string;
200
+
201
+ /**
202
+ * Set a .env convention (available conventions: 'nextjs')
203
+ */
204
+ convention?: string;
205
+ }
206
+
207
+ export type SetOutput = {
208
+ key: string;
209
+ value: string;
210
+ filepath: string;
211
+ envFilepath: string;
212
+ envSrc: string;
213
+ changed: boolean;
214
+ encryptedValue?: string;
215
+ publicKey?: string;
216
+ privateKey?: string;
217
+ privateKeyAdded?: boolean;
218
+ privateKeyName?: string;
219
+ error?: Error;
220
+ };
221
+
222
+ /**
223
+ * Set a single environment variable.
224
+ *
225
+ * @see https://dotenvx.com/docs
226
+ * @param key - KEY
227
+ * @param value - value
228
+ * @param options - additional options. example: `{ encrypt: false }`
229
+ */
230
+ export function set(
231
+ key: string,
232
+ value: string,
233
+ options?: SetOptions
234
+ ): SetOutput;
235
+
161
236
  /**
162
237
  * List all env files in the current working directory
163
238
  *
package/src/lib/main.js CHANGED
@@ -8,14 +8,13 @@ const { getColor, bold } = require('./../shared/colors')
8
8
  // services
9
9
  const Ls = require('./services/ls')
10
10
  const Run = require('./services/run')
11
+ const Sets = require('./services/sets')
11
12
  const Keypair = require('./services/keypair')
12
13
  const Genexample = require('./services/genexample')
13
14
 
14
15
  // helpers
15
- const conventions = require('./helpers/conventions')
16
- const dotenvOptionPaths = require('./helpers/dotenvOptionPaths')
16
+ const buildEnvs = require('./helpers/buildEnvs')
17
17
  const Parse = require('./helpers/parse')
18
- const DeprecationNotice = require('./helpers/deprecationNotice')
19
18
 
20
19
  /** @type {import('./main').config} */
21
20
  const config = function (options = {}) {
@@ -45,30 +44,8 @@ const config = function (options = {}) {
45
44
 
46
45
  if (options) setLogLevel(options)
47
46
 
48
- // build envs using user set option.path
49
- const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
50
-
51
47
  try {
52
- let envs = []
53
- // handle shorthand conventions - like --convention=nextjs
54
- if (options.convention) {
55
- envs = conventions(options.convention).concat(envs)
56
- }
57
-
58
- new DeprecationNotice({ DOTENV_KEY }).dotenvKey() // DEPRECATION NOTICE
59
-
60
- for (const optionPath of optionPaths) {
61
- // if DOTENV_KEY is set then assume we are checking envVaultFile
62
- if (DOTENV_KEY) {
63
- envs.push({
64
- type: 'envVaultFile',
65
- value: path.join(path.dirname(optionPath), '.env.vault')
66
- })
67
- } else {
68
- envs.push({ type: 'envFile', value: optionPath })
69
- }
70
- }
71
-
48
+ const envs = buildEnvs(options, DOTENV_KEY)
72
49
  const {
73
50
  processedEnvs,
74
51
  readableFilepaths,
@@ -182,6 +159,25 @@ const parse = function (src, options = {}) {
182
159
  return parsed
183
160
  }
184
161
 
162
+ /* @type {import('./main').set} */
163
+ const set = function (key, value, options = {}) {
164
+ // encrypt
165
+ let encrypt = true
166
+ if (options.plain) {
167
+ encrypt = false
168
+ } else if (options.encrypt === false) {
169
+ encrypt = false
170
+ }
171
+
172
+ // envKeysFile
173
+ const envKeysFile = options.envKeysFile
174
+
175
+ // envs
176
+ const envs = buildEnvs(options)
177
+
178
+ return new Sets(key, value, envs, encrypt, envKeysFile).run()
179
+ }
180
+
185
181
  /** @type {import('./main').ls} */
186
182
  const ls = function (directory, envFile, excludeEnvFile) {
187
183
  return new Ls(directory, envFile, excludeEnvFile).run()
@@ -207,6 +203,7 @@ module.exports = {
207
203
  config,
208
204
  parse,
209
205
  // actions related
206
+ set,
210
207
  ls,
211
208
  keypair,
212
209
  genexample,