dotenv-runtime 0.0.0-stage → 1.0.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 +36 -0
- package/LICENSE +23 -0
- package/README.md +1205 -2
- package/SECURITY.md +21 -0
- package/dist/cli.cjs +9 -0
- package/dist/config.cjs +3 -0
- package/dist/config.mjs +3 -0
- package/dist/decode.js +1 -0
- package/dist/index.cjs +7 -0
- package/dist/index.d.ts +165 -0
- package/dist/index.mjs +4 -0
- package/dist/stest.jpg +0 -0
- package/package.json +77 -4
package/README.md
CHANGED
|
@@ -1,3 +1,1206 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dotenv-runtime
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> A fast, validated, zero-dependency environment configuration toolkit for Node.js.
|
|
4
|
+
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](#)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
`dotenv-runtime` loads `.env` files into `process.env` or an isolated configuration object while adding the features production applications commonly need:
|
|
11
|
+
|
|
12
|
+
- Async configuration loading
|
|
13
|
+
- Variable expansion
|
|
14
|
+
- Required-variable checks
|
|
15
|
+
- Typed schema validation
|
|
16
|
+
- Type coercion
|
|
17
|
+
- Multiple `.env` files with deterministic precedence
|
|
18
|
+
- Parent-directory discovery
|
|
19
|
+
- Isolated configuration targets
|
|
20
|
+
- Structured errors and load metadata
|
|
21
|
+
- A production-oriented command runner
|
|
22
|
+
- CommonJS, ESM, and TypeScript support
|
|
23
|
+
|
|
24
|
+
The default behavior remains familiar to users of [`dotenv`](https://github.com/motdotla/dotenv). Extended functionality is explicit and opt-in.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Why dotenv-runtime?
|
|
29
|
+
|
|
30
|
+
Environment configuration usually starts simple:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
require('dotenv').config()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
But production applications often need more:
|
|
37
|
+
|
|
38
|
+
- Multiple environment files
|
|
39
|
+
- Validation before startup
|
|
40
|
+
- Required variables
|
|
41
|
+
- Typed values
|
|
42
|
+
- Variable references
|
|
43
|
+
- Async file loading
|
|
44
|
+
- Monorepo-friendly `.env` discovery
|
|
45
|
+
- Isolated configuration for tests
|
|
46
|
+
- Strict startup failures
|
|
47
|
+
- A CLI for launching commands
|
|
48
|
+
|
|
49
|
+
`dotenv-runtime` provides these capabilities without adding runtime dependencies.
|
|
50
|
+
|
|
51
|
+
### Highlights
|
|
52
|
+
|
|
53
|
+
| Feature | Supported |
|
|
54
|
+
| --- | :---: |
|
|
55
|
+
| Zero runtime dependencies | ✅ |
|
|
56
|
+
| CommonJS | ✅ |
|
|
57
|
+
| Native ESM | ✅ |
|
|
58
|
+
| TypeScript declarations | ✅ |
|
|
59
|
+
| Sync configuration | ✅ |
|
|
60
|
+
| Async configuration | ✅ |
|
|
61
|
+
| Variable expansion | ✅ |
|
|
62
|
+
| Required variables | ✅ |
|
|
63
|
+
| Schema validation | ✅ |
|
|
64
|
+
| Type coercion | ✅ |
|
|
65
|
+
| Multiple `.env` files | ✅ |
|
|
66
|
+
| Parent-directory discovery | ✅ |
|
|
67
|
+
| Isolated configuration targets | ✅ |
|
|
68
|
+
| Optimized parser | ✅ |
|
|
69
|
+
| CLI command runner | ✅ |
|
|
70
|
+
| Optional encrypted configuration | ✅ |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Requirements
|
|
75
|
+
|
|
76
|
+
- **Node.js 20 or later**
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Installation
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npm install dotenv-runtime
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
# Quick Start
|
|
89
|
+
|
|
90
|
+
Create a `.env` file:
|
|
91
|
+
|
|
92
|
+
```dotenv
|
|
93
|
+
APP_NAME=payments-api
|
|
94
|
+
PORT=3000
|
|
95
|
+
LOG_LEVEL=info
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Load it from your application:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
const dotenv = require('dotenv-runtime')
|
|
102
|
+
|
|
103
|
+
const result = dotenv.config()
|
|
104
|
+
|
|
105
|
+
if (result.error) {
|
|
106
|
+
throw result.error
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log(process.env.APP_NAME)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### ESM
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import dotenv, { config } from 'dotenv-runtime'
|
|
116
|
+
|
|
117
|
+
config()
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### ESM preload
|
|
121
|
+
|
|
122
|
+
If you want configuration loaded as a side effect:
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
import 'dotenv-runtime/config'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
# Production Configuration
|
|
131
|
+
|
|
132
|
+
For production applications, you can combine multiple features into a single configuration pipeline.
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
import { config } from 'dotenv-runtime'
|
|
136
|
+
|
|
137
|
+
const result = config({
|
|
138
|
+
path: [
|
|
139
|
+
'.env.production.local',
|
|
140
|
+
'.env.production'
|
|
141
|
+
],
|
|
142
|
+
|
|
143
|
+
expand: true,
|
|
144
|
+
|
|
145
|
+
required: [
|
|
146
|
+
'DATABASE_URL',
|
|
147
|
+
'PORT'
|
|
148
|
+
],
|
|
149
|
+
|
|
150
|
+
strict: true,
|
|
151
|
+
|
|
152
|
+
quiet: true,
|
|
153
|
+
|
|
154
|
+
schema: {
|
|
155
|
+
DATABASE_URL: 'url',
|
|
156
|
+
|
|
157
|
+
PORT: {
|
|
158
|
+
type: 'integer',
|
|
159
|
+
min: 1,
|
|
160
|
+
max: 65535,
|
|
161
|
+
required: true
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
LOG_LEVEL: {
|
|
165
|
+
type: 'string',
|
|
166
|
+
enum: [
|
|
167
|
+
'debug',
|
|
168
|
+
'info',
|
|
169
|
+
'warn',
|
|
170
|
+
'error'
|
|
171
|
+
],
|
|
172
|
+
default: 'info'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
const {
|
|
178
|
+
PORT,
|
|
179
|
+
LOG_LEVEL
|
|
180
|
+
} = result.validated
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Environment variables written to `process.env` remain strings.
|
|
184
|
+
|
|
185
|
+
Coerced and validated values are returned separately through:
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
result.validated
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
This lets you keep the familiar `.env` / `process.env` behavior while still working with properly typed configuration inside your application.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
# `.env` Syntax
|
|
196
|
+
|
|
197
|
+
`dotenv-runtime` supports the established `.env` syntax:
|
|
198
|
+
|
|
199
|
+
```dotenv
|
|
200
|
+
# Comments and blank lines are ignored.
|
|
201
|
+
|
|
202
|
+
PLAIN=value
|
|
203
|
+
|
|
204
|
+
EMPTY=
|
|
205
|
+
|
|
206
|
+
SINGLE_QUOTED='literal value'
|
|
207
|
+
|
|
208
|
+
DOUBLE_QUOTED="supports escaped\nnewlines"
|
|
209
|
+
|
|
210
|
+
BACKTICKED=`multiline-friendly value`
|
|
211
|
+
|
|
212
|
+
export EXPORTED=value
|
|
213
|
+
|
|
214
|
+
COLON: value
|
|
215
|
+
|
|
216
|
+
INLINE=value # comment
|
|
217
|
+
|
|
218
|
+
HASH="value#inside-quotes"
|
|
219
|
+
|
|
220
|
+
MULTILINE="first line
|
|
221
|
+
second line"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Keys may contain:
|
|
225
|
+
|
|
226
|
+
- Letters
|
|
227
|
+
- Numbers
|
|
228
|
+
- Underscores
|
|
229
|
+
- Periods
|
|
230
|
+
- Hyphens
|
|
231
|
+
|
|
232
|
+
Parsed values are strings.
|
|
233
|
+
|
|
234
|
+
Existing environment values are preserved unless:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
override: true
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
is enabled.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
# Core API
|
|
245
|
+
|
|
246
|
+
`dotenv-runtime` exports eight primary functions:
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
config()
|
|
250
|
+
configDotenv()
|
|
251
|
+
configAsync()
|
|
252
|
+
parse()
|
|
253
|
+
populate()
|
|
254
|
+
expand()
|
|
255
|
+
validate()
|
|
256
|
+
findUp()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## `config(options?)`
|
|
262
|
+
|
|
263
|
+
Loads the configured environment files synchronously.
|
|
264
|
+
|
|
265
|
+
The pipeline is:
|
|
266
|
+
|
|
267
|
+
```text
|
|
268
|
+
Load files
|
|
269
|
+
↓
|
|
270
|
+
Parse
|
|
271
|
+
↓
|
|
272
|
+
Expand references
|
|
273
|
+
↓
|
|
274
|
+
Check required values
|
|
275
|
+
↓
|
|
276
|
+
Validate schema
|
|
277
|
+
↓
|
|
278
|
+
Commit final values
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Example:
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
const dotenv = require('dotenv-runtime')
|
|
285
|
+
|
|
286
|
+
const result = dotenv.config({
|
|
287
|
+
path: '.env.local',
|
|
288
|
+
quiet: true
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Return value
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
interface DotenvConfigOutput<T> {
|
|
296
|
+
parsed: Record<string, string>
|
|
297
|
+
loaded: string[]
|
|
298
|
+
errors: Error[]
|
|
299
|
+
error?: Error
|
|
300
|
+
validated?: T
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Result fields
|
|
305
|
+
|
|
306
|
+
| Property | Description |
|
|
307
|
+
| --- | --- |
|
|
308
|
+
| `parsed` | Parsed configuration values |
|
|
309
|
+
| `loaded` | Absolute paths successfully loaded |
|
|
310
|
+
| `errors` | All load or processing errors in encounter order |
|
|
311
|
+
| `error` | Primary error for conventional single-error handling |
|
|
312
|
+
| `validated` | Typed configuration returned after schema validation |
|
|
313
|
+
|
|
314
|
+
`loaded` contains absolute paths for successfully read files.
|
|
315
|
+
|
|
316
|
+
`errors` contains every encountered load or processing error.
|
|
317
|
+
|
|
318
|
+
`error` provides the primary error for applications that only need conventional single-error handling.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Configuration Options
|
|
323
|
+
|
|
324
|
+
| Option | Type | Default | Description |
|
|
325
|
+
| --- | --- | --- | --- |
|
|
326
|
+
| `path` | `string \| URL \| Array<string \| URL>` | `<cwd>/.env` | File or ordered list of files to load |
|
|
327
|
+
| `cwd` | `string` | `process.cwd()` | Base directory for relative paths and discovery |
|
|
328
|
+
| `encoding` | `BufferEncoding` | `utf8` | File encoding |
|
|
329
|
+
| `processEnv` | `Record<string, string>` | `process.env` | Target object receiving configuration |
|
|
330
|
+
| `override` | `boolean` | `false` | Replace existing values and allow later files to win |
|
|
331
|
+
| `quiet` | `boolean` | `false` | Suppress the injection summary |
|
|
332
|
+
| `debug` | `boolean` | `false` | Print diagnostic information |
|
|
333
|
+
| `fast` | `boolean` | `false` | Use the optimized parser |
|
|
334
|
+
| `expand` | `boolean` | `false` | Expand variable references before validation |
|
|
335
|
+
| `required` | `string \| string[]` | — | Require non-empty final values |
|
|
336
|
+
| `allowEmpty` | `boolean` | `false` | Allow required values to be empty |
|
|
337
|
+
| `schema` | `DotenvSchema` | — | Validate and coerce configuration |
|
|
338
|
+
| `strict` | `boolean` | `false` | Throw instead of returning processing errors |
|
|
339
|
+
| `searchUp` | `boolean \| string` | `false` | Search ancestor directories for `.env` or a named file |
|
|
340
|
+
| `stopDir` | `string` | filesystem root | Stop upward discovery at this directory |
|
|
341
|
+
| `secure` | `boolean` | `false` | Delegate encrypted configuration to `@dotenvx/dotenvx` |
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
# Async Loading
|
|
346
|
+
|
|
347
|
+
## `configAsync(options?)`
|
|
348
|
+
|
|
349
|
+
`configAsync()` provides the same configuration pipeline as `config()` while using the promise-based filesystem API.
|
|
350
|
+
|
|
351
|
+
Multiple files can be read concurrently.
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
import { configAsync } from 'dotenv-runtime'
|
|
355
|
+
|
|
356
|
+
const result = await configAsync({
|
|
357
|
+
path: [
|
|
358
|
+
'.env.local',
|
|
359
|
+
'.env'
|
|
360
|
+
],
|
|
361
|
+
|
|
362
|
+
processEnv: {},
|
|
363
|
+
|
|
364
|
+
quiet: true
|
|
365
|
+
})
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Use `config()` when environment configuration is part of normal synchronous application bootstrap.
|
|
369
|
+
|
|
370
|
+
Use `configAsync()` when startup is already asynchronous, configuration files are stored on slower storage, several files need to be loaded, or you prefer promise-based initialization.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
# `configDotenv(options?)`
|
|
375
|
+
|
|
376
|
+
Runs the local environment-file loading pipeline directly.
|
|
377
|
+
|
|
378
|
+
`config()` normally delegates to `configDotenv()` unless secure mode is enabled.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
# Parsing
|
|
383
|
+
|
|
384
|
+
## `parse(source, options?)`
|
|
385
|
+
|
|
386
|
+
Parses a string or `Buffer` without:
|
|
387
|
+
|
|
388
|
+
- Reading files
|
|
389
|
+
- Mutating `process.env`
|
|
390
|
+
- Mutating another environment object
|
|
391
|
+
|
|
392
|
+
```js
|
|
393
|
+
import { parse } from 'dotenv-runtime'
|
|
394
|
+
|
|
395
|
+
const values = parse(
|
|
396
|
+
'HOST=localhost\nPORT=3000'
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
console.log(values)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Result:
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
{
|
|
406
|
+
HOST: 'localhost',
|
|
407
|
+
PORT: '3000'
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Optimized parser
|
|
412
|
+
|
|
413
|
+
The optimized scanner can be selected explicitly:
|
|
414
|
+
|
|
415
|
+
```js
|
|
416
|
+
const values = parse(source, {
|
|
417
|
+
fast: true
|
|
418
|
+
})
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The scanner supports:
|
|
422
|
+
|
|
423
|
+
- BOM-prefixed files
|
|
424
|
+
- Multiline quoted values
|
|
425
|
+
- Escaped quotes
|
|
426
|
+
- Escaped backslashes
|
|
427
|
+
- Comments
|
|
428
|
+
- `export` prefixes
|
|
429
|
+
- Ordered duplicate-key behavior
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
# Populating Configuration
|
|
434
|
+
|
|
435
|
+
## `populate(target, values, options?)`
|
|
436
|
+
|
|
437
|
+
Copies configuration values into a target object.
|
|
438
|
+
|
|
439
|
+
It returns only the values that were actually written.
|
|
440
|
+
|
|
441
|
+
```js
|
|
442
|
+
import { populate } from 'dotenv-runtime'
|
|
443
|
+
|
|
444
|
+
const target = {
|
|
445
|
+
PORT: '8080'
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const populated = populate(
|
|
449
|
+
target,
|
|
450
|
+
{
|
|
451
|
+
PORT: '3000',
|
|
452
|
+
HOST: 'localhost'
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
override: false
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
The result is:
|
|
461
|
+
|
|
462
|
+
```js
|
|
463
|
+
// target
|
|
464
|
+
{
|
|
465
|
+
PORT: '8080',
|
|
466
|
+
HOST: 'localhost'
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// populated
|
|
470
|
+
{
|
|
471
|
+
HOST: 'localhost'
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Existing properties are preserved by default, including properties whose value is `undefined`.
|
|
476
|
+
|
|
477
|
+
Special property names are assigned safely without modifying object prototypes.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
# Variable Expansion
|
|
482
|
+
|
|
483
|
+
## `expand(values, options?)`
|
|
484
|
+
|
|
485
|
+
Resolves variable references and returns a new object.
|
|
486
|
+
|
|
487
|
+
The input object is never mutated.
|
|
488
|
+
|
|
489
|
+
Variable expansion **never executes shell commands**.
|
|
490
|
+
|
|
491
|
+
Example:
|
|
492
|
+
|
|
493
|
+
```dotenv
|
|
494
|
+
HOST=localhost
|
|
495
|
+
PORT=3000
|
|
496
|
+
|
|
497
|
+
BASE_URL=http://${HOST}:${PORT}
|
|
498
|
+
|
|
499
|
+
OPTIONAL=${UNSET:-fallback}
|
|
500
|
+
|
|
501
|
+
LITERAL=\$HOST
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Supported expressions:
|
|
505
|
+
|
|
506
|
+
| Expression | Behavior |
|
|
507
|
+
| --- | --- |
|
|
508
|
+
| `$NAME` | Resolve `NAME` |
|
|
509
|
+
| `${NAME}` | Resolve `NAME` |
|
|
510
|
+
| `${NAME-default}` | Use `default` when `NAME` is unset |
|
|
511
|
+
| `${NAME:-default}` | Use `default` when `NAME` is unset or empty |
|
|
512
|
+
| `\$NAME` | Preserve `$NAME` literally |
|
|
513
|
+
|
|
514
|
+
### Precedence
|
|
515
|
+
|
|
516
|
+
Existing values in `processEnv` take precedence during expansion.
|
|
517
|
+
|
|
518
|
+
Use:
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
const expanded = expand(values, {
|
|
522
|
+
processEnv: process.env,
|
|
523
|
+
override: true
|
|
524
|
+
})
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
to prefer local values instead.
|
|
528
|
+
|
|
529
|
+
### Circular references
|
|
530
|
+
|
|
531
|
+
Circular references throw a:
|
|
532
|
+
|
|
533
|
+
```text
|
|
534
|
+
dotenv-runtime_EXPANSION_CYCLE
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
error.
|
|
538
|
+
|
|
539
|
+
The error identifies the variables involved without exposing their values.
|
|
540
|
+
|
|
541
|
+
Shell expressions such as:
|
|
542
|
+
|
|
543
|
+
```sh
|
|
544
|
+
$(command)
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
are not executed and remain untouched.
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
# Validation & Type Coercion
|
|
552
|
+
|
|
553
|
+
## `validate(values, schema)`
|
|
554
|
+
|
|
555
|
+
Validates configuration against a schema and returns a new object containing the declared fields.
|
|
556
|
+
|
|
557
|
+
Values can optionally be coerced into useful JavaScript types.
|
|
558
|
+
|
|
559
|
+
```js
|
|
560
|
+
import { validate } from 'dotenv-runtime'
|
|
561
|
+
|
|
562
|
+
const settings = validate(process.env, {
|
|
563
|
+
APP_ENV: {
|
|
564
|
+
type: 'string',
|
|
565
|
+
enum: [
|
|
566
|
+
'development',
|
|
567
|
+
'test',
|
|
568
|
+
'production'
|
|
569
|
+
],
|
|
570
|
+
required: true
|
|
571
|
+
},
|
|
572
|
+
|
|
573
|
+
PORT: {
|
|
574
|
+
type: 'integer',
|
|
575
|
+
min: 1,
|
|
576
|
+
max: 65535,
|
|
577
|
+
default: 3000
|
|
578
|
+
},
|
|
579
|
+
|
|
580
|
+
ENABLE_CACHE: 'boolean',
|
|
581
|
+
|
|
582
|
+
CACHE_OPTIONS: 'json',
|
|
583
|
+
|
|
584
|
+
PUBLIC_URL: 'url'
|
|
585
|
+
})
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
## Supported Types
|
|
589
|
+
|
|
590
|
+
| Type | Output | Accepted input |
|
|
591
|
+
| --- | --- | --- |
|
|
592
|
+
| `string` | `string` | Any defined value |
|
|
593
|
+
| `number` | `number` | Finite numeric value |
|
|
594
|
+
| `integer` | `number` | Safe integer |
|
|
595
|
+
| `boolean` | `boolean` | `true`, `false`, `1`, `0`, `yes`, `no`, `on`, `off` |
|
|
596
|
+
| `json` | JSON value | Valid JSON text or an existing value |
|
|
597
|
+
| `url` | `string` | URL accepted by the standard `URL` parser |
|
|
598
|
+
|
|
599
|
+
## Validation Rules
|
|
600
|
+
|
|
601
|
+
A schema descriptor can define:
|
|
602
|
+
|
|
603
|
+
```ts
|
|
604
|
+
interface DotenvValidationRule {
|
|
605
|
+
type?:
|
|
606
|
+
| 'string'
|
|
607
|
+
| 'number'
|
|
608
|
+
| 'integer'
|
|
609
|
+
| 'boolean'
|
|
610
|
+
| 'json'
|
|
611
|
+
| 'url'
|
|
612
|
+
|
|
613
|
+
required?: boolean
|
|
614
|
+
|
|
615
|
+
allowEmpty?: boolean
|
|
616
|
+
|
|
617
|
+
default?: unknown
|
|
618
|
+
|
|
619
|
+
enum?: readonly unknown[]
|
|
620
|
+
|
|
621
|
+
min?: number
|
|
622
|
+
|
|
623
|
+
max?: number
|
|
624
|
+
|
|
625
|
+
pattern?: RegExp | string
|
|
626
|
+
|
|
627
|
+
validate?:
|
|
628
|
+
(value: unknown) =>
|
|
629
|
+
boolean | string | void
|
|
630
|
+
|
|
631
|
+
transform?:
|
|
632
|
+
(value: unknown) => unknown
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Type shorthand
|
|
637
|
+
|
|
638
|
+
Instead of:
|
|
639
|
+
|
|
640
|
+
```js
|
|
641
|
+
PORT: {
|
|
642
|
+
type: 'integer'
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
you can use:
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
PORT: 'integer'
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
A type shorthand marks the field as required.
|
|
653
|
+
|
|
654
|
+
Descriptor rules are optional unless:
|
|
655
|
+
|
|
656
|
+
```js
|
|
657
|
+
required: true
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
is specified.
|
|
661
|
+
|
|
662
|
+
Validation failures are collected in:
|
|
663
|
+
|
|
664
|
+
```js
|
|
665
|
+
error.issues
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Built-in diagnostics identify configuration keys and validation rules without exposing configuration values.
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
# Multiple `.env` Files
|
|
673
|
+
|
|
674
|
+
Multiple files can be supplied in a deterministic order:
|
|
675
|
+
|
|
676
|
+
```js
|
|
677
|
+
dotenv.config({
|
|
678
|
+
path: [
|
|
679
|
+
'.env.local',
|
|
680
|
+
'.env'
|
|
681
|
+
]
|
|
682
|
+
})
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
Files are processed in exactly the order provided.
|
|
686
|
+
|
|
687
|
+
## Default behavior
|
|
688
|
+
|
|
689
|
+
Without `override`:
|
|
690
|
+
|
|
691
|
+
1. Existing target values are preserved.
|
|
692
|
+
2. The first file defining a key wins.
|
|
693
|
+
3. Later files only add keys that are still absent.
|
|
694
|
+
|
|
695
|
+
For example:
|
|
696
|
+
|
|
697
|
+
```text
|
|
698
|
+
.env.local
|
|
699
|
+
.env
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
means `.env.local` has priority over `.env`.
|
|
703
|
+
|
|
704
|
+
## With `override: true`
|
|
705
|
+
|
|
706
|
+
```js
|
|
707
|
+
dotenv.config({
|
|
708
|
+
path: [
|
|
709
|
+
'.env.local',
|
|
710
|
+
'.env'
|
|
711
|
+
],
|
|
712
|
+
override: true
|
|
713
|
+
})
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
The behavior becomes:
|
|
717
|
+
|
|
718
|
+
1. File values replace existing target values.
|
|
719
|
+
2. The last file defining a key wins.
|
|
720
|
+
|
|
721
|
+
## Atomic configuration
|
|
722
|
+
|
|
723
|
+
Required checks and schema validation run against the final candidate environment **before** parsed values are committed.
|
|
724
|
+
|
|
725
|
+
This means a failure in required-variable validation, variable expansion, or schema validation cannot partially update the target environment.
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
# Parent Directory Discovery
|
|
730
|
+
|
|
731
|
+
## `findUp(filename?, options?)`
|
|
732
|
+
|
|
733
|
+
Searches upward from a directory and returns the nearest matching file.
|
|
734
|
+
|
|
735
|
+
```js
|
|
736
|
+
import { findUp } from 'dotenv-runtime'
|
|
737
|
+
|
|
738
|
+
const envPath = findUp('.env', {
|
|
739
|
+
cwd: __dirname,
|
|
740
|
+
stopDir: '/workspace'
|
|
741
|
+
})
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
Returns an absolute path or `undefined` when no matching file is found.
|
|
745
|
+
|
|
746
|
+
### Configuration shortcut
|
|
747
|
+
|
|
748
|
+
```js
|
|
749
|
+
dotenv.config({
|
|
750
|
+
searchUp: true
|
|
751
|
+
})
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
searches for `.env`.
|
|
755
|
+
|
|
756
|
+
You can also specify a filename:
|
|
757
|
+
|
|
758
|
+
```js
|
|
759
|
+
dotenv.config({
|
|
760
|
+
searchUp: '.env.production'
|
|
761
|
+
})
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
This is especially useful for monorepos and applications nested inside workspace directories.
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
# Strict Error Handling
|
|
769
|
+
|
|
770
|
+
By default, errors are returned through the configuration result.
|
|
771
|
+
|
|
772
|
+
```js
|
|
773
|
+
const result = dotenv.config({
|
|
774
|
+
path: '.env.production'
|
|
775
|
+
})
|
|
776
|
+
|
|
777
|
+
if (result.error) {
|
|
778
|
+
console.error(result.error.message)
|
|
779
|
+
process.exit(1)
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
For applications that prefer exceptions, enable strict mode:
|
|
784
|
+
|
|
785
|
+
```js
|
|
786
|
+
dotenv.config({
|
|
787
|
+
path: '.env.production',
|
|
788
|
+
required: [
|
|
789
|
+
'DATABASE_URL'
|
|
790
|
+
],
|
|
791
|
+
strict: true
|
|
792
|
+
})
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
With `strict: true`, the primary configuration failure is thrown immediately.
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
# Isolated Configuration
|
|
800
|
+
|
|
801
|
+
You do not have to write configuration into `process.env`.
|
|
802
|
+
|
|
803
|
+
Pass your own target:
|
|
804
|
+
|
|
805
|
+
```js
|
|
806
|
+
const environment = {}
|
|
807
|
+
|
|
808
|
+
const result = dotenv.config({
|
|
809
|
+
path: '.env.test',
|
|
810
|
+
processEnv: environment,
|
|
811
|
+
quiet: true
|
|
812
|
+
})
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
This is useful for:
|
|
816
|
+
|
|
817
|
+
- Tests
|
|
818
|
+
- Build tools
|
|
819
|
+
- Multiple configuration contexts
|
|
820
|
+
- Libraries
|
|
821
|
+
- Sandboxed configuration
|
|
822
|
+
- Applications that should avoid global environment mutation
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
# Command-Line Interface
|
|
827
|
+
|
|
828
|
+
`dotenv-runtime` includes a command runner for launching processes with loaded environment variables.
|
|
829
|
+
|
|
830
|
+
## Basic usage
|
|
831
|
+
|
|
832
|
+
```sh
|
|
833
|
+
dotenv-runtime run -- node server.js
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
The `--` separator marks the beginning of the child process command.
|
|
837
|
+
|
|
838
|
+
## Multiple files
|
|
839
|
+
|
|
840
|
+
```sh
|
|
841
|
+
dotenv-runtime run \
|
|
842
|
+
-f .env.local \
|
|
843
|
+
-f .env \
|
|
844
|
+
-- node server.js
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
Files are processed in the specified order.
|
|
848
|
+
|
|
849
|
+
## Required variables
|
|
850
|
+
|
|
851
|
+
```sh
|
|
852
|
+
dotenv-runtime run \
|
|
853
|
+
--expand \
|
|
854
|
+
--required DATABASE_URL,PORT \
|
|
855
|
+
-- node server.js
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
## Search parent directories
|
|
859
|
+
|
|
860
|
+
```sh
|
|
861
|
+
dotenv-runtime run \
|
|
862
|
+
--search-up \
|
|
863
|
+
-- npm test
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
## CLI options
|
|
867
|
+
|
|
868
|
+
| Option | Description |
|
|
869
|
+
| --- | --- |
|
|
870
|
+
| `-f, --file <path>` | Load a file; repeatable |
|
|
871
|
+
| `--cwd <path>` | Resolve files from another directory |
|
|
872
|
+
| `--search-up[=<name>]` | Find `.env` or a named file in an ancestor directory |
|
|
873
|
+
| `--expand` | Expand variable references safely |
|
|
874
|
+
| `--required <names>` | Require comma-separated variables; repeatable |
|
|
875
|
+
| `--allow-empty` | Permit empty required values |
|
|
876
|
+
| `--override` | Replace existing environment values |
|
|
877
|
+
| `--strict` | Fail on load or validation errors |
|
|
878
|
+
| `--fast` | Use the optimized parser |
|
|
879
|
+
| `--secure` | Delegate encrypted loading to `@dotenvx/dotenvx` |
|
|
880
|
+
| `--debug` | Print diagnostics |
|
|
881
|
+
| `--quiet` | Suppress the injection summary |
|
|
882
|
+
| `-h, --help` | Show command help |
|
|
883
|
+
| `-v, --version` | Print the installed version |
|
|
884
|
+
|
|
885
|
+
The `--` separator is required.
|
|
886
|
+
|
|
887
|
+
The child process receives its arguments directly, and `dotenv-runtime` propagates the child's exit status.
|
|
888
|
+
|
|
889
|
+
---
|
|
890
|
+
|
|
891
|
+
# Environment-Based Configuration
|
|
892
|
+
|
|
893
|
+
Configuration defaults can also be provided through environment variables.
|
|
894
|
+
|
|
895
|
+
Two prefixes are supported:
|
|
896
|
+
|
|
897
|
+
```text
|
|
898
|
+
dotenv-runtime_CONFIG_
|
|
899
|
+
DOTENV_CONFIG_
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
The `dotenv-runtime_CONFIG_` prefix takes precedence when both are present.
|
|
903
|
+
|
|
904
|
+
Supported variables:
|
|
905
|
+
|
|
906
|
+
```text
|
|
907
|
+
PATH
|
|
908
|
+
ENCODING
|
|
909
|
+
CWD
|
|
910
|
+
QUIET
|
|
911
|
+
DEBUG
|
|
912
|
+
OVERRIDE
|
|
913
|
+
SECURE
|
|
914
|
+
FAST
|
|
915
|
+
EXPAND
|
|
916
|
+
STRICT
|
|
917
|
+
SEARCH_UP
|
|
918
|
+
ALLOW_EMPTY
|
|
919
|
+
REQUIRED
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
`REQUIRED` accepts a comma-separated list.
|
|
923
|
+
|
|
924
|
+
Example:
|
|
925
|
+
|
|
926
|
+
```sh
|
|
927
|
+
dotenv-runtime_CONFIG_PATH=.env.production \
|
|
928
|
+
dotenv-runtime_CONFIG_EXPAND=true \
|
|
929
|
+
dotenv-runtime_CONFIG_REQUIRED=DATABASE_URL,PORT \
|
|
930
|
+
node server.js
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
Explicit API options and CLI flags take precedence over environment-based defaults.
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
# Security
|
|
938
|
+
|
|
939
|
+
`dotenv-runtime` treats `.env` files as configuration data rather than executable input.
|
|
940
|
+
|
|
941
|
+
### Safety properties
|
|
942
|
+
|
|
943
|
+
- Variable expansion never executes commands.
|
|
944
|
+
- Built-in validation errors do not include configuration values.
|
|
945
|
+
- Required-variable and schema failures are atomic.
|
|
946
|
+
- Special property names cannot modify object prototypes.
|
|
947
|
+
- The core package performs no network operations.
|
|
948
|
+
- The core package has no runtime dependencies.
|
|
949
|
+
|
|
950
|
+
### Protect your `.env` files
|
|
951
|
+
|
|
952
|
+
`.env` files commonly contain credentials and other secrets.
|
|
953
|
+
|
|
954
|
+
Do not:
|
|
955
|
+
|
|
956
|
+
- Commit secrets to source control
|
|
957
|
+
- Log entire configuration objects
|
|
958
|
+
- Expose `.env` files publicly
|
|
959
|
+
- Share production environment files unnecessarily
|
|
960
|
+
|
|
961
|
+
Use restrictive file permissions and your deployment platform's secret-management facilities for production credentials.
|
|
962
|
+
|
|
963
|
+
## Encrypted Configuration
|
|
964
|
+
|
|
965
|
+
Encrypted configuration is optional.
|
|
966
|
+
|
|
967
|
+
Install `@dotenvx/dotenvx` separately:
|
|
968
|
+
|
|
969
|
+
```sh
|
|
970
|
+
npm install @dotenvx/dotenvx
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
Then enable secure mode:
|
|
974
|
+
|
|
975
|
+
```js
|
|
976
|
+
dotenv.config({
|
|
977
|
+
secure: true
|
|
978
|
+
})
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
The core package does not require the encrypted configuration dependency unless secure mode is used.
|
|
982
|
+
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
# TypeScript
|
|
986
|
+
|
|
987
|
+
TypeScript declarations are included with the package.
|
|
988
|
+
|
|
989
|
+
```ts
|
|
990
|
+
import { config } from 'dotenv-runtime'
|
|
991
|
+
|
|
992
|
+
interface Settings {
|
|
993
|
+
PORT: number
|
|
994
|
+
ENABLE_CACHE: boolean
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const result = config<Settings>({
|
|
998
|
+
schema: {
|
|
999
|
+
PORT: 'integer',
|
|
1000
|
+
ENABLE_CACHE: 'boolean'
|
|
1001
|
+
},
|
|
1002
|
+
|
|
1003
|
+
strict: true
|
|
1004
|
+
})
|
|
1005
|
+
|
|
1006
|
+
result.validated?.PORT.toFixed()
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
The generic type can describe the validated configuration returned by the loader.
|
|
1010
|
+
|
|
1011
|
+
Compatibility type aliases beginning with `Dotenv` are retained to make migration easier.
|
|
1012
|
+
|
|
1013
|
+
---
|
|
1014
|
+
|
|
1015
|
+
# CommonJS & ESM
|
|
1016
|
+
|
|
1017
|
+
`dotenv-runtime` provides both CommonJS and native ESM builds.
|
|
1018
|
+
|
|
1019
|
+
### CommonJS
|
|
1020
|
+
|
|
1021
|
+
```js
|
|
1022
|
+
const dotenv = require('dotenv-runtime')
|
|
1023
|
+
|
|
1024
|
+
dotenv.config()
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### ESM
|
|
1028
|
+
|
|
1029
|
+
```js
|
|
1030
|
+
import dotenv from 'dotenv-runtime'
|
|
1031
|
+
|
|
1032
|
+
dotenv.config()
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
### Named import
|
|
1036
|
+
|
|
1037
|
+
```js
|
|
1038
|
+
import { config } from 'dotenv-runtime'
|
|
1039
|
+
|
|
1040
|
+
config()
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
### ESM preload
|
|
1044
|
+
|
|
1045
|
+
```js
|
|
1046
|
+
import 'dotenv-runtime/config'
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
---
|
|
1050
|
+
|
|
1051
|
+
# Migrating from `dotenv`
|
|
1052
|
+
|
|
1053
|
+
For basic usage, migration is intentionally simple.
|
|
1054
|
+
|
|
1055
|
+
### Before
|
|
1056
|
+
|
|
1057
|
+
```js
|
|
1058
|
+
const dotenv = require('dotenv')
|
|
1059
|
+
|
|
1060
|
+
dotenv.config()
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
### After
|
|
1064
|
+
|
|
1065
|
+
```js
|
|
1066
|
+
const dotenv = require('dotenv-runtime')
|
|
1067
|
+
|
|
1068
|
+
dotenv.config()
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
### ESM preload
|
|
1072
|
+
|
|
1073
|
+
Before:
|
|
1074
|
+
|
|
1075
|
+
```js
|
|
1076
|
+
import 'dotenv/config'
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
After:
|
|
1080
|
+
|
|
1081
|
+
```js
|
|
1082
|
+
import 'dotenv-runtime/config'
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
The core defaults remain familiar:
|
|
1086
|
+
|
|
1087
|
+
- `.env` is loaded from the current working directory
|
|
1088
|
+
- Values are strings
|
|
1089
|
+
- Existing target keys are preserved
|
|
1090
|
+
- Multiple paths use first-file-wins behavior
|
|
1091
|
+
- `override: true` enables replacement
|
|
1092
|
+
|
|
1093
|
+
`dotenv-runtime` is an independent fork and is **not** the official `dotenv` distribution.
|
|
1094
|
+
|
|
1095
|
+
---
|
|
1096
|
+
|
|
1097
|
+
# Development
|
|
1098
|
+
|
|
1099
|
+
Install the locked development dependencies:
|
|
1100
|
+
|
|
1101
|
+
```sh
|
|
1102
|
+
npm ci
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
Run the complete verification pipeline:
|
|
1106
|
+
|
|
1107
|
+
```sh
|
|
1108
|
+
npm test
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
The test pipeline:
|
|
1112
|
+
|
|
1113
|
+
1. Builds every module format
|
|
1114
|
+
2. Checks JavaScript style
|
|
1115
|
+
3. Validates TypeScript declarations
|
|
1116
|
+
4. Runs unit and integration tests
|
|
1117
|
+
5. Runs CLI and parser tests
|
|
1118
|
+
6. Executes sample programs
|
|
1119
|
+
|
|
1120
|
+
## Run samples
|
|
1121
|
+
|
|
1122
|
+
```sh
|
|
1123
|
+
node samples/basic/test.js
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
```sh
|
|
1127
|
+
node samples/features/test.js
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
## Verify the package before publishing
|
|
1131
|
+
|
|
1132
|
+
```sh
|
|
1133
|
+
npm pack --dry-run
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
---
|
|
1137
|
+
|
|
1138
|
+
# Project Structure
|
|
1139
|
+
|
|
1140
|
+
```text
|
|
1141
|
+
.
|
|
1142
|
+
├── lib/ Runtime implementation and declarations
|
|
1143
|
+
├── scripts/ Reproducible build tooling
|
|
1144
|
+
├── tests/ Unit, integration, CLI, parser, and type tests
|
|
1145
|
+
├── samples/ Executable consumer-style examples
|
|
1146
|
+
└── dist/ Generated CommonJS, ESM, CLI,
|
|
1147
|
+
preload, and declaration files
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
---
|
|
1151
|
+
|
|
1152
|
+
# Design Principles
|
|
1153
|
+
|
|
1154
|
+
`dotenv-runtime` is built around a few simple principles.
|
|
1155
|
+
|
|
1156
|
+
### Familiar by default
|
|
1157
|
+
|
|
1158
|
+
Basic usage should feel immediately familiar to existing `dotenv` users.
|
|
1159
|
+
|
|
1160
|
+
### Explicit extensions
|
|
1161
|
+
|
|
1162
|
+
Advanced behavior is opt-in rather than silently changing traditional behavior.
|
|
1163
|
+
|
|
1164
|
+
### Deterministic configuration
|
|
1165
|
+
|
|
1166
|
+
Multiple files, overrides, expansion, and validation follow predictable rules.
|
|
1167
|
+
|
|
1168
|
+
### No unnecessary dependencies
|
|
1169
|
+
|
|
1170
|
+
The core runtime remains dependency-free.
|
|
1171
|
+
|
|
1172
|
+
### Safe configuration handling
|
|
1173
|
+
|
|
1174
|
+
Configuration values should be treated as data, not executable input.
|
|
1175
|
+
|
|
1176
|
+
### Atomic startup
|
|
1177
|
+
|
|
1178
|
+
Validation should happen before configuration is committed, preventing partially configured environments.
|
|
1179
|
+
|
|
1180
|
+
### Type-aware configuration
|
|
1181
|
+
|
|
1182
|
+
Environment variables begin as strings, but applications can explicitly validate and coerce them into useful types.
|
|
1183
|
+
|
|
1184
|
+
---
|
|
1185
|
+
|
|
1186
|
+
# Upstream Attribution
|
|
1187
|
+
|
|
1188
|
+
`dotenv-runtime` is derived from [`dotenv`](https://github.com/motdotla/dotenv) and retains its BSD 2-Clause licensing terms.
|
|
1189
|
+
|
|
1190
|
+
This fork adds independent:
|
|
1191
|
+
|
|
1192
|
+
- APIs
|
|
1193
|
+
- Packaging
|
|
1194
|
+
- Tests
|
|
1195
|
+
- Documentation
|
|
1196
|
+
- Build tooling
|
|
1197
|
+
- Configuration features
|
|
1198
|
+
- Release policy
|
|
1199
|
+
|
|
1200
|
+
---
|
|
1201
|
+
|
|
1202
|
+
# License
|
|
1203
|
+
|
|
1204
|
+
BSD 2-Clause.
|
|
1205
|
+
|
|
1206
|
+
See [`LICENSE`](LICENSE) for the complete license text.
|