@mirta/env-loader 0.0.1 → 0.4.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.
- package/LICENSE +24 -0
- package/README.md +289 -28
- package/README.ru.md +300 -0
- package/dist/index.d.mts +186 -0
- package/dist/index.mjs +195 -0
- package/package.json +53 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
package/README.md
CHANGED
|
@@ -1,45 +1,306 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@mirta/env-loader`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/wb-mirta/core/blob/latest/packages/mirta-env-loader/README.md)
|
|
4
|
+
[](https://github.com/wb-mirta/core/blob/latest/packages/mirta-env-loader/README.ru.md)
|
|
5
|
+
[](https://npmjs.com/package/@mirta/env-loader)
|
|
6
|
+
[](https://npmjs.com/package/@mirta/env-loader)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
> Internal environment variable loader based on `@dotenvx/dotenvx`, used by Mirta tools.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
`@mirta/env-loader` provides a unified way to load and filter environment variables within the Mirta framework.
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Supports:
|
|
13
|
+
- `.env` files with modes (`development`, `test`, `production`) and `.local` variants
|
|
14
|
+
- Environment variables from the OS and CLI overrides
|
|
15
|
+
- Prefix-based filtering (`MIRTA_`, `APP_`)
|
|
16
|
+
- `.env` file encryption via `@dotenvx/dotenvx`
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@mirta/env-loader`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
18
|
+
Used in `@mirta/rollup`, `@mirta/testing`, and other internal tools.
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
**Not intended for execution in the Duktape environment on Wiren Board controllers.**
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 📦 Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Not required directly — used internally by Mirta
|
|
28
|
+
pnpm add -D @mirta/env-loader
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
⚠️ This package is part of Mirta's internal infrastructure. It is usually not used directly.
|
|
32
|
+
|
|
33
|
+
## 🚀 Quick Start
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { loadEnv, loadEnvReplacements } from '@mirta/env-loader'
|
|
37
|
+
|
|
38
|
+
// Load environment variables
|
|
39
|
+
const env = loadEnv({ mode: 'development' })
|
|
40
|
+
|
|
41
|
+
// For code replacement (e.g., with @rollup/plugin-replace)
|
|
42
|
+
const replacements = loadEnvReplacements({ mode: 'production' })
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🧰 API
|
|
46
|
+
|
|
47
|
+
### `loadEnv(options?: EnvLoaderOptions): Record<string, string>`
|
|
48
|
+
|
|
49
|
+
Synchronously loads and filters environment variables.
|
|
50
|
+
|
|
51
|
+
#### Parameters
|
|
52
|
+
|
|
53
|
+
| Field | Type | Description |
|
|
54
|
+
|------|-----|----------|
|
|
55
|
+
| `mode` | `string` | Environment mode. Defaults to `process.env.NODE_ENV` |
|
|
56
|
+
| `prefix` | `string \| string[]` | Prefixes for filtering. Default: `['MIRTA_', 'APP_']` |
|
|
57
|
+
| `cwd` | `string` | Current working directory. Defaults to `process.cwd()` |
|
|
58
|
+
| `rootDir` | `string` | Root directory of the project (e.g., in a monorepo).<br/>If specified and differs from `cwd`, files are also searched in the root |
|
|
59
|
+
| `envFile` | `string \| string[]` | Base `.env` file name. Default: `.env` |
|
|
60
|
+
| `keepNodeEnv` | `boolean` | Whether to include `NODE_ENV`. Default: `true`.<br/>If `false`, it is removed from the returned object.<br/>⚠️ Note: does not affect the global `process.env.NODE_ENV` value |
|
|
61
|
+
| `dotenv` | `DotenvOptions` | Additional `@dotenvx/dotenvx` settings, see below |
|
|
62
|
+
|
|
63
|
+
#### ⚠️ **Security: `prefix` cannot be fully disabled**
|
|
64
|
+
|
|
65
|
+
The `prefix` option **cannot be disabled** (e.g., via `prefix: false`, `prefix: ''`, `prefix: []`, or `prefix: ['']`) to prevent **automatic secret leakage**.
|
|
66
|
+
|
|
67
|
+
Even when loading variables, filtering remains active, and default prefixes (`MIRTA_`, `APP_`) are applied.
|
|
68
|
+
|
|
69
|
+
If you need to load variables with other prefixes, explicitly specify them:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
loadEnv({
|
|
73
|
+
prefix: ['MIRTA_', 'APP_', 'CUSTOM_', 'SECRET_'] // ← explicit allowance
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
This ensures that **only expected variables** are included in the result and — when using `loadEnvReplacements` — in the client-side code.
|
|
77
|
+
|
|
78
|
+
#### ⚙️ Dotenv Options
|
|
79
|
+
|
|
80
|
+
Type: `DotenvOptions` — passed directly to `@dotenvx/dotenvx`, but with limitations.
|
|
81
|
+
|
|
82
|
+
`@mirta/env-loader` controls key aspects of loading, so some options are overridden or ignored to ensure predictable behavior.
|
|
19
83
|
|
|
20
|
-
|
|
84
|
+
✅ **Supported and safe options**
|
|
21
85
|
|
|
22
|
-
|
|
86
|
+
| Option | Description |
|
|
87
|
+
|--------|-------------|
|
|
88
|
+
| `overload` | If `true`, later files overwrite variables from earlier ones. Default: `false` (earlier files have higher priority) |
|
|
89
|
+
| `encoding` | Encoding of `.env` files. Default: `'utf8'` |
|
|
90
|
+
| `strict` | If `true`, throws an error on parsing failures. Default: `false` |
|
|
91
|
+
| `debug` | Enables debug output. Useful for diagnostics. Default: `false` |
|
|
92
|
+
| `verbose` | Increases log verbosity |
|
|
93
|
+
| `quiet` | Suppresses console output (including errors) |
|
|
94
|
+
| `envKeysFile` | Path to `.env.keys` — useful in monorepos |
|
|
95
|
+
| `logLevel` | Log level: `'error'`, `'warn'`, `'info'`, etc. Partially overridden — see below |
|
|
23
96
|
|
|
24
|
-
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
97
|
+
❌ **Ignored or overridden options**
|
|
28
98
|
|
|
29
|
-
|
|
99
|
+
| Option | What happens | Reason |
|
|
100
|
+
|--------|--------------|--------|
|
|
101
|
+
| `path` | Ignored | File order and list are determined by `@mirta/env-loader` |
|
|
102
|
+
| `processEnv` | Overridden | To avoid polluting `process.env` and to apply filtering |
|
|
103
|
+
| `convention` | Ignored | To prevent conflicts with built-in priority logic |
|
|
104
|
+
| `logLevel` | Default is `'warn'`, but can be overridden | To avoid suppressing important warnings (e.g., missing `.env.keys`) |
|
|
105
|
+
| `ignore` | `'MISSING_ENV_FILE'` is enforced | `.env` files are optional — missing files are not an error |
|
|
30
106
|
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- Exists only for administrative purposes
|
|
107
|
+
📌 **Recommendations**
|
|
108
|
+
- Use `overload`, `debug`, `encoding` — they work as expected.
|
|
109
|
+
- Do not rely on `convention` or `path` — they are disabled.
|
|
110
|
+
- To change load order, configure `envFile`, `mode`, and `.env` file structure.
|
|
36
111
|
|
|
37
|
-
|
|
112
|
+
Example
|
|
38
113
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
114
|
+
```ts
|
|
115
|
+
const env = loadEnv({
|
|
116
|
+
mode: 'production',
|
|
117
|
+
dotenv: {
|
|
118
|
+
overload: true, // ✅ allowed: reverses file processing priority
|
|
119
|
+
debug: true, // ✅ allowed: console output
|
|
120
|
+
encoding: 'utf16', // ✅ rare, but possible
|
|
121
|
+
// convention: 'nextjs' // ❌ ignored
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### File Loading Order
|
|
127
|
+
|
|
128
|
+
Files are processed in descending order of priority:
|
|
129
|
+
|
|
130
|
+
1. **First — all `.env` files in `cwd`** (current directory):
|
|
131
|
+
- `.env.${mode}.local`
|
|
132
|
+
- `.env.${mode}`
|
|
133
|
+
- `.env.local`
|
|
134
|
+
- `.env`
|
|
135
|
+
2. **Then — all `.env` files in `rootDir`** (project root), in the same order.
|
|
136
|
+
|
|
137
|
+
#### ⚠️ Local package settings take precedence over root ones
|
|
138
|
+
|
|
139
|
+
For example:
|
|
140
|
+
- A project is built in `development` mode,
|
|
141
|
+
- The package file `packages/my-app/.env` contains `PORT=3000`
|
|
142
|
+
- The project's root file `.env.development` contains `PORT=4000`
|
|
143
|
+
|
|
144
|
+
In this case, `PORT=3000` will be used,<br/>
|
|
145
|
+
because the local context is considered more specific.
|
|
146
|
+
|
|
147
|
+
#### ⚠️ Behavior on key collision depends on `dotenv.overload`
|
|
148
|
+
|
|
149
|
+
- `dotenv.overload`: `false` (default)
|
|
150
|
+
|
|
151
|
+
Variables from earlier files are not overwritten by later ones.<br/>
|
|
152
|
+
→ The earlier a file appears in the list, the higher its priority.
|
|
153
|
+
|
|
154
|
+
- `dotenv.overload`: `true`
|
|
155
|
+
|
|
156
|
+
Later files overwrite earlier ones.<br/>
|
|
157
|
+
→ The later a file appears in the list, the higher its priority.
|
|
158
|
+
|
|
159
|
+
By default, `overload`: `false` is used, so .env.${mode}.local has the highest priority.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### `loadEnvReplacements(options?: EnvLoaderOptions): Record<string, string>`
|
|
164
|
+
|
|
165
|
+
Returns an object like:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
{
|
|
169
|
+
'process.env.APP_PORT': '"3000"',
|
|
170
|
+
'import.meta.env.APP_PORT': '"3000"'
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Suitable for integration with `@rollup/plugin-replace`.
|
|
42
175
|
|
|
43
176
|
---
|
|
44
177
|
|
|
45
|
-
|
|
178
|
+
### DEFAULT_ENV_PREFIXES
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
['MIRTA_', 'APP_']
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Default list of prefixes for variable filtering.
|
|
185
|
+
Can be overridden via `options.prefix`.
|
|
186
|
+
|
|
187
|
+
## 🛡️ Security and Configuration Best Practices
|
|
188
|
+
|
|
189
|
+
### ❌ Do not use system environment variables directly
|
|
190
|
+
|
|
191
|
+
Directly loading system environment variables — such as `PATH`, `HOME`, `USER`, `NODE_VERSION` — is **not recommended**, even if they are available in the environment.
|
|
192
|
+
|
|
193
|
+
👉 Why:
|
|
194
|
+
- **Breaks portability**: behavior will differ across machines.
|
|
195
|
+
- **Security risk**: sensitive data may accidentally leak into the build.
|
|
196
|
+
- **Non-deterministic behavior**: application behavior depends on the environment, not configuration.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### ✅ Option 1: Explicit override in `.env`
|
|
201
|
+
|
|
202
|
+
If you truly need a system environment variable, **explicitly declare it in your `.env` file**:
|
|
203
|
+
|
|
204
|
+
```env
|
|
205
|
+
# .env
|
|
206
|
+
MIRTA_PATH=${PATH}
|
|
207
|
+
MIRTA_HOME=${HOME}
|
|
208
|
+
APP_NODE_VERSION=${NODE_VERSION}
|
|
209
|
+
```
|
|
210
|
+
👉 This way:
|
|
211
|
+
- You **control** which variables enter the application,
|
|
212
|
+
- You **document** the intent explicitly,
|
|
213
|
+
- You can **override** the value per environment.
|
|
214
|
+
|
|
215
|
+
⚠️ Important: `@mirta/env-loader` does not expose variables outside allowed prefixes — even if `${PATH}` is used in `.env`, the `PATH` variable itself will not be included unless it starts with `MIRTA_` or `APP_`.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### ✅ Option 2: Explicit configuration (recommended)
|
|
220
|
+
|
|
221
|
+
Better yet — **avoid relying on system variables altogether**, and define paths and settings explicitly:
|
|
222
|
+
|
|
223
|
+
```env
|
|
224
|
+
# .env
|
|
225
|
+
MIRTA_BINARY_PATH=/usr/local/bin/custom-tool
|
|
226
|
+
APP_CONFIG_DIR=/etc/myapp
|
|
227
|
+
APP_CACHE_DIR=./temp/cache
|
|
228
|
+
```
|
|
229
|
+
👉 Benefits:
|
|
230
|
+
|
|
231
|
+
**Portability**: the app behaves consistently across environments,
|
|
232
|
+
**Readability**: all settings are visible in `.env`,
|
|
233
|
+
**Security**: no surprises from the environment,
|
|
234
|
+
**Testability**: easy to emulate different setups.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
🧩 Example of a secure .env
|
|
239
|
+
|
|
240
|
+
```env
|
|
241
|
+
# Environment mode
|
|
242
|
+
NODE_ENV=development
|
|
243
|
+
|
|
244
|
+
# Binaries and paths
|
|
245
|
+
MIRTA_BINARY_PATH=/opt/tools/cli
|
|
246
|
+
MIRTA_CONFIG_ROOT=./config
|
|
247
|
+
|
|
248
|
+
# Application settings
|
|
249
|
+
APP_PORT=3000
|
|
250
|
+
APP_API_KEY=dev-key-7x29qn
|
|
251
|
+
APP_FEATURE_TOGGLES=auth,logging,metrics
|
|
252
|
+
|
|
253
|
+
# Logging
|
|
254
|
+
MIRTA_LOG_LEVEL=debug
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
📌 Summary
|
|
260
|
+
- ❌ **Do not rely** on system environment variables directly.
|
|
261
|
+
- ✅ **Explicitly** declare everything you need in .env.
|
|
262
|
+
- ✅ **Use clear, fixed values**.
|
|
263
|
+
|
|
264
|
+
This way, you build a **predictable, secure, and portable** application.
|
|
265
|
+
|
|
266
|
+
## 🔐 Working with Encrypted Variables
|
|
267
|
+
|
|
268
|
+
`@mirta/env-loader` uses `@dotenvx/dotenvx` to load and decrypt `.env` files.
|
|
269
|
+
|
|
270
|
+
> ⚠️ **Deprecated: `DOTENV_KEY` and `.env.vault`**
|
|
271
|
+
>
|
|
272
|
+
> The legacy encryption flow using `DOTENV_KEY` and `.env.vault` is **deprecated**.
|
|
273
|
+
> While still supported for backward compatibility, it is no longer recommended.
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
✅ **Current mechanism: Key-pair encryption**
|
|
277
|
+
|
|
278
|
+
`dotenvx` now uses public-key cryptography:
|
|
279
|
+
- **`DOTENV_PUBLIC_KEY`** — used to **encrypt** `.env` files.
|
|
280
|
+
- **`DOTENV_PRIVATE_KEY`** — used to **decrypt** them at runtime.
|
|
281
|
+
|
|
282
|
+
When enabled:
|
|
283
|
+
- Your `.env` files are **fully encrypted on disk**.
|
|
284
|
+
- Only the public key is needed for encryption (safe to commit).
|
|
285
|
+
- The private key is required for decryption (kept secret in CI/CD or local env).
|
|
286
|
+
|
|
287
|
+
🔍 How it works:
|
|
288
|
+
- `@dotenvx/dotenvx` performs all cryptographic operations using the key pair.
|
|
289
|
+
- `@mirta/env-loader` receives **already decrypted values** — it does not handle keys or crypto directly.
|
|
290
|
+
|
|
291
|
+
👉 We recommend migrating to the new key-pair system.
|
|
292
|
+
|
|
293
|
+
For setup, see: [dotenvx — Encryption Guide](https://github.com/dotenvx/dotenvx#encryption)
|
|
294
|
+
|
|
295
|
+
## ✅ Testing
|
|
296
|
+
|
|
297
|
+
The package is covered with unit tests (Vitest):
|
|
298
|
+
- Loading `.env` files in the correct order
|
|
299
|
+
- Prefix filtering
|
|
300
|
+
- `rootDir` support
|
|
301
|
+
- Integration with `DOTENV_KEY` (via mocks)
|
|
302
|
+
- Cross-platform compatibility
|
|
303
|
+
|
|
304
|
+
## ⚠️ Limitations
|
|
305
|
+
|
|
306
|
+
**Works only in Node.js** (not in Duktape).
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# `@mirta/env-loader`
|
|
2
|
+
|
|
3
|
+
[](https://github.com/wb-mirta/core/blob/latest/packages/mirta-env-loader/README.md)
|
|
4
|
+
[](https://github.com/wb-mirta/core/blob/latest/packages/mirta-env-loader/README.ru.md)
|
|
5
|
+
[](https://npmjs.com/package/@mirta/env-loader)
|
|
6
|
+
[](https://npmjs.com/package/@mirta/env-loader)
|
|
7
|
+
|
|
8
|
+
> Внутренний загрузчик переменных окружения на базе `@dotenvx/dotenvx`, используемый инструментами Mirta.
|
|
9
|
+
|
|
10
|
+
`@mirta/env-loader` обеспечивает единый способ загрузки и фильтрации переменных окружения в рамках фреймворка Mirta.
|
|
11
|
+
|
|
12
|
+
Поддерживает:
|
|
13
|
+
- `.env`-файлы с режимами (`development`, `test`, `production`) и `.local`-файлами
|
|
14
|
+
- Переменные из операционной системы и CLI-переопределения
|
|
15
|
+
- Фильтрацию по префиксам (`MIRTA_`, `APP_`)
|
|
16
|
+
- Шифрование `.env`-файлов через `@dotenvx/dotenvx`
|
|
17
|
+
|
|
18
|
+
Используется в `@mirta/rollup`, `@mirta/testing` и других внутренних инструментах.
|
|
19
|
+
|
|
20
|
+
**Не предназначен для выполнения в среде Duktape на контроллерах Wiren Board.**
|
|
21
|
+
|
|
22
|
+
## 📦 Установка
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Не требуется напрямую — используется внутри Mirta
|
|
26
|
+
pnpm add -D @mirta/env-loader
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
⚠️ Этот пакет — часть внутренней инфраструктуры фреймворка Mirta. Обычно он не используется напрямую.
|
|
30
|
+
|
|
31
|
+
## 🚀 Быстрый старт
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { loadEnv, loadEnvReplacements } from '@mirta/env-loader'
|
|
35
|
+
|
|
36
|
+
// Загрузка переменных окружения
|
|
37
|
+
const env = loadEnv({ mode: 'development' })
|
|
38
|
+
|
|
39
|
+
// Для подстановки в код (например, @rollup/plugin-replace)
|
|
40
|
+
const replacements = loadEnvReplacements({ mode: 'production' })
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 🧰 API
|
|
44
|
+
|
|
45
|
+
### `loadEnv(options?: EnvLoaderOptions): Record<string, string>`
|
|
46
|
+
Синхронно загружает и фильтрует переменные окружения.
|
|
47
|
+
|
|
48
|
+
#### Параметры
|
|
49
|
+
|
|
50
|
+
| Поле | Тип | Описание |
|
|
51
|
+
|------|-----|----------|
|
|
52
|
+
| `mode` | `string` | Режим окружения. По умолчанию — `process.env.NODE_ENV` |
|
|
53
|
+
| `prefix` | `string \| string[]` | Префиксы для фильтрации. По умолчанию — `['MIRTA_', 'APP_']` |
|
|
54
|
+
| `cwd` | `string` | Текущая рабочая директория. По умолчанию — `process.cwd()` |
|
|
55
|
+
| `rootDir` | `string` | Корневая директория проекта (например, в монорепозитории).<br/>Если значение указано и отличается от `cwd`, файлы ищутся также и в корне |
|
|
56
|
+
| `envFile` | `string \| string[]` | Базовое имя `.env`-файла. По умолчанию — `.env` |
|
|
57
|
+
| `keepNodeEnv` | `boolean` | Сохранять ли `NODE_ENV`. По умолчанию — `true`, при `false` удаляется из возвращаемого объекта.<br/>⚠️ Примечание: не влияет на глобальное значение `process.env.NODE_ENV` |
|
|
58
|
+
| `dotenv` | `DotenvOptions` | Дополнительные настройки `@dotenvx/dotenvx`, см. ниже |
|
|
59
|
+
|
|
60
|
+
#### ⚠️ **Безопасность: `prefix` нельзя отключить полностью**
|
|
61
|
+
|
|
62
|
+
Параметр `prefix` **не может быть отключён** (например, через `prefix: false`, `prefix: ''`, `prefix: []` или `prefix: ['']`), чтобы предотвратить **автоматическую утечку секретов**.
|
|
63
|
+
|
|
64
|
+
Даже при загрузке всех переменных, фильтрация остаётся включённой, и применяются префиксы по умолчанию (`MIRTA_`, `APP_`).
|
|
65
|
+
|
|
66
|
+
Если вам нужно загрузить переменные с другими префиксами — явно укажите их:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
loadEnv({
|
|
70
|
+
prefix: ['MIRTA_', 'APP_', 'CUSTOM_', 'SECRET_'] // ← явное разрешение
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
Это гарантирует, что **только ожидаемые переменные** попадут в результат и, при использовании `loadEnvReplacements`, — в клиентский код.
|
|
74
|
+
|
|
75
|
+
#### ⚙️ **Опции dotenv****
|
|
76
|
+
|
|
77
|
+
Тип: `DotenvOptions` — передаётся напрямую в `@dotenvx/dotenvx`, но с ограничениями.
|
|
78
|
+
|
|
79
|
+
`@mirta/env-loader` контролирует ключевые аспекты загрузки, поэтому некоторые опции переопределяются или игнорируются, чтобы гарантировать предсказуемое поведение.
|
|
80
|
+
|
|
81
|
+
✅ **Поддерживаемые и безопасные опции**
|
|
82
|
+
|
|
83
|
+
| Опция | Описание |
|
|
84
|
+
|------|---------|
|
|
85
|
+
| `overload` | Если `true` — последующие файлы перезаписывают переменные из предыдущих. По умолчанию `false` (приоритет у первых файлов) |
|
|
86
|
+
| `encoding` | Кодировка `.env`-файлов. По умолчанию `'utf8'` |
|
|
87
|
+
| `strict` | Если `true` — выбрасывает ошибку при сбоях парсинга. По умолчанию `false` |
|
|
88
|
+
| `debug` | Включает отладочный вывод. Полезно для диагностики. По умолчанию `false` |
|
|
89
|
+
| `verbose` | Увеличивает детализацию логов |
|
|
90
|
+
| `quiet` | Подавляет вывод в консоль (включая ошибки) |
|
|
91
|
+
| `envKeysFile` | Путь к `.env.keys` — полезно в монорепозиториях |
|
|
92
|
+
| `logLevel` | Уровень логирования: `'error'`, `'warn'`, `'info'` и т.д. Частично переопределён — см. ниже |
|
|
93
|
+
|
|
94
|
+
❌ **Опции, которые игнорируются или переопределяются**
|
|
95
|
+
|
|
96
|
+
| Опция | Что происходит | Причина |
|
|
97
|
+
|------|----------------|--------|
|
|
98
|
+
| `path` | Игнорируется | Порядок и список файлов задаётся `@mirta/env-loader` |
|
|
99
|
+
| `processEnv` | Игнорируется | Внутренний объект, чтобы не загрязнять `process.env` и применить фильтрацию |
|
|
100
|
+
| `convention` | Игнорируется | Чтобы избежать конфликта с собственной логикой приоритетов |
|
|
101
|
+
| `logLevel` | По умолчанию `'warn'`, но может быть переопределён | Чтобы не подавлять важные предупреждения, например, о пропущенных `.env.keys` |
|
|
102
|
+
| `ignore` | Принудительно включает `'MISSING_ENV_FILE'` | `.env`-файлы не обязательны — отсутствие не является ошибкой |
|
|
103
|
+
|
|
104
|
+
📌 **Рекомендации**
|
|
105
|
+
|
|
106
|
+
- Используйте `overload`, `debug`, `encoding` — они работают как ожидается,
|
|
107
|
+
- Не полагайтесь на `convention` или `path` — они отключены,
|
|
108
|
+
- Если вы хотите изменить порядок загрузки — настройте envFile, mode и структуру `.env`-файлов.
|
|
109
|
+
|
|
110
|
+
Пример
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const env = loadEnv({
|
|
114
|
+
mode: 'production',
|
|
115
|
+
dotenv: {
|
|
116
|
+
overload: true, // ✅ разрешено: инвертирует приоритет обработки файлов
|
|
117
|
+
debug: true, // ✅ разрешено: вывод в консоль
|
|
118
|
+
encoding: 'utf16', // ✅ редко, но возможно
|
|
119
|
+
// convention: 'nextjs' // ❌ проигнорировано
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Порядок загрузки файлов
|
|
125
|
+
|
|
126
|
+
Файлы обрабатываются в порядке убывания приоритета:
|
|
127
|
+
|
|
128
|
+
1. **Сначала — все `.env`-файлы в `cwd`** (текущей директории):
|
|
129
|
+
- `.env.${mode}.local`
|
|
130
|
+
- `.env.${mode}`
|
|
131
|
+
- `.env.local`
|
|
132
|
+
- `.env`
|
|
133
|
+
|
|
134
|
+
2. **Затем — все `.env`-файлы в `rootDir`** (корне проекта), в том же порядке.
|
|
135
|
+
|
|
136
|
+
#### ⚠️ **Локальные настройки пакета имеют приоритет над корневыми**
|
|
137
|
+
|
|
138
|
+
Предположим, что:
|
|
139
|
+
- некий разрабатываемый проект собирается в режиме `development`,
|
|
140
|
+
- файл пакета `packages/my-app/.env` содержит `PORT=3000`,
|
|
141
|
+
- корневой файл проекта `.env.development` содержит `PORT=4000`.
|
|
142
|
+
|
|
143
|
+
В этом случае будет использовано значение `PORT=3000`,<br/>
|
|
144
|
+
потому что локальный контекст считается более специфичным.
|
|
145
|
+
|
|
146
|
+
#### ⚠️ **Поведение при совпадении ключей зависит от значения `dotenv.overload`**
|
|
147
|
+
|
|
148
|
+
- **`dotenv.overload`: `false`** (по умолчанию)
|
|
149
|
+
|
|
150
|
+
Переменные из **первых** файлов **не перезаписываются** последующими.<br/>
|
|
151
|
+
→ Чем **раньше** файл в списке — тем **выше** его приоритет.
|
|
152
|
+
|
|
153
|
+
- **`dotenv.overload`: `true`**
|
|
154
|
+
|
|
155
|
+
Последующие файлы **перезаписывают** предыдущие.<br/>
|
|
156
|
+
→ Чем **позже** файл в списке — тем **выше** его приоритет.
|
|
157
|
+
|
|
158
|
+
По умолчанию используется `overload`: `false`, поэтому `.env.${mode}.local` имеет наивысший приоритет.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `loadEnvReplacements(options?: EnvLoaderOptions): Record<string, string>`
|
|
163
|
+
|
|
164
|
+
Возвращает объект вида:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
{
|
|
168
|
+
'process.env.APP_PORT': '"3000"',
|
|
169
|
+
'import.meta.env.APP_PORT': '"3000"'
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
Подходит для интеграции с `@rollup/plugin-replace`
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### `DEFAULT_ENV_PREFIXES`
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
['MIRTA_', 'APP_']
|
|
180
|
+
```
|
|
181
|
+
Список префиксов по умолчанию для фильтрации переменных.
|
|
182
|
+
Можно переопределить через `options.prefix`.
|
|
183
|
+
|
|
184
|
+
## 🛡️ Рекомендации по безопасности и проектированию
|
|
185
|
+
|
|
186
|
+
### ❌ Не используйте системные переменные напрямую
|
|
187
|
+
|
|
188
|
+
Прямая загрузка системных переменных окружения — таких как `PATH`, `HOME`, `USER`, `NODE_VERSION`, **не рекомендуется**. Даже если они доступны в среде выполнения.
|
|
189
|
+
|
|
190
|
+
👉 Почему:
|
|
191
|
+
- Это **нарушает переносимость**: поведение будет отличаться на разных машинах.
|
|
192
|
+
- Это **риск безопасности**: в сборку может случайно попасть приватная информация.
|
|
193
|
+
- Это **нарушает детерминированность**: поведение приложения зависит от окружения, а не от конфигурации.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### ✅ Вариант 1: Явное переопределение в `.env`
|
|
198
|
+
|
|
199
|
+
Если вам действительно нужно значение системной переменной — **явно объявите его в `.env`-файле**:
|
|
200
|
+
|
|
201
|
+
```env
|
|
202
|
+
# .env
|
|
203
|
+
MIRTA_PATH=`${PATH}`
|
|
204
|
+
MIRTA_HOME=`${HOME}`
|
|
205
|
+
APP_NODE_VERSION=`${NODE_VERSION}`
|
|
206
|
+
```
|
|
207
|
+
👉 Так:
|
|
208
|
+
- Вы **контролируете**, какие переменные попадают в приложение,
|
|
209
|
+
- Вы **логируете** это намерение явно,
|
|
210
|
+
- Вы можете **переопределить** значение для конкретного окружения.
|
|
211
|
+
|
|
212
|
+
⚠️ Важно: `@mirta/env-loader` не раскрывает переменные вне указанных префиксов — даже если `${PATH}` используется в `.env`, сам `PATH` не попадёт в результат, если не начинается с `MIRTA_` или `APP_`.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### ✅ Вариант 2: Явная конфигурация (рекомендуется)
|
|
217
|
+
|
|
218
|
+
Лучше — вообще не полагаться на системные переменные, а задавать пути и настройки явно:
|
|
219
|
+
|
|
220
|
+
```env
|
|
221
|
+
# .env
|
|
222
|
+
MIRTA_BINARY_PATH=/usr/local/bin/custom-tool
|
|
223
|
+
APP_CONFIG_DIR=/etc/myapp
|
|
224
|
+
APP_CACHE_DIR=./temp/cache
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
👉 Преимущества:
|
|
228
|
+
- **Переносимость**: приложение работает одинаково на всех машинах,
|
|
229
|
+
- **Читаемость**: все настройки видны в `.env`,
|
|
230
|
+
- **Безопасность**: никаких сюрпризов из окружения,
|
|
231
|
+
- **Тестируемость**: легко эмулировать разные окружения.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
🧩 Пример безопасного `.env`
|
|
236
|
+
|
|
237
|
+
```env
|
|
238
|
+
# Режим окружения
|
|
239
|
+
NODE_ENV=development
|
|
240
|
+
|
|
241
|
+
# Пути и бинарники
|
|
242
|
+
MIRTA_BINARY_PATH=/opt/tools/cli
|
|
243
|
+
MIRTA_CONFIG_ROOT=./config
|
|
244
|
+
|
|
245
|
+
# Пользовательские настройки
|
|
246
|
+
APP_PORT=3000
|
|
247
|
+
APP_API_KEY=dev-key-7x29qn
|
|
248
|
+
APP_FEATURE_TOGGLES=auth,logging,metrics
|
|
249
|
+
|
|
250
|
+
# Логирование
|
|
251
|
+
MIRTA_LOG_LEVEL=debug
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
📌 Итог
|
|
255
|
+
- ❌ **Не полагайтесь** на системные переменные напрямую.
|
|
256
|
+
- ✅ **Явно объявляйте** всё, что нужно, в .env.
|
|
257
|
+
- ✅ **Используйте понятные, зафиксированные значения**.
|
|
258
|
+
|
|
259
|
+
Так вы строите **предсказуемое, безопасное и переносимое** приложение.
|
|
260
|
+
|
|
261
|
+
## 🔐 Работа с зашифрованными переменными
|
|
262
|
+
|
|
263
|
+
`@mirta/env-loader` использует `@dotenvx/dotenvx` для загрузки и расшифровки `.env`-файлов.
|
|
264
|
+
|
|
265
|
+
> ⚠️ **Устарело: `DOTENV_KEY` и `.env.vault`**
|
|
266
|
+
>
|
|
267
|
+
> Старый механизм шифрования через `DOTENV_KEY` и `.env.vault` **устарел**.
|
|
268
|
+
> Поддерживается только для обратной совместимости. Не рекомендуется к использованию.
|
|
269
|
+
|
|
270
|
+
✅ **Новый механизм: шифрование с парой ключей**
|
|
271
|
+
|
|
272
|
+
`dotenvx` теперь использует асимметричное шифрование:
|
|
273
|
+
- **`DOTENV_PUBLIC_KEY`** — для **шифрования** `.env`-файлов.
|
|
274
|
+
- **`DOTENV_PRIVATE_KEY`** — для **расшифровки** в рантайме.
|
|
275
|
+
|
|
276
|
+
При использовании:
|
|
277
|
+
- `.env`-файлы **полностью зашифрованы на диске**.
|
|
278
|
+
- Публичный ключ можно фиксировать в репозитории.
|
|
279
|
+
- Приватный ключ остаётся в CI/CD или локальном окружении.
|
|
280
|
+
|
|
281
|
+
🔍 Как это работает:
|
|
282
|
+
- `@dotenvx/dotenvx` выполняет все криптографические операции.
|
|
283
|
+
- `@mirta/env-loader` получает **уже расшифрованные значения** — не работает с ключами напрямую.
|
|
284
|
+
|
|
285
|
+
👉 Рекомендуется перейти на новую систему.
|
|
286
|
+
Подробнее: [dotenvx — Encryption Guide](https://github.com/dotenvx/dotenvx#encryption)
|
|
287
|
+
|
|
288
|
+
## ✅ Тестирование
|
|
289
|
+
|
|
290
|
+
Пакет покрыт юнит-тестами (Vitest):
|
|
291
|
+
|
|
292
|
+
- Загрузка `.env`-файлов в правильном порядке
|
|
293
|
+
- Фильтрация по префиксам
|
|
294
|
+
- Поддержка `rootDir`
|
|
295
|
+
- Интеграция с `DOTENV_KEY` (через моки)
|
|
296
|
+
- Кроссплатформенность
|
|
297
|
+
|
|
298
|
+
## ⚠️ Ограничения
|
|
299
|
+
|
|
300
|
+
**Работает только в Node.js** (не в Duktape).<br/>
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Набор префиксов для переменных окружения, которые будут загружены в проект.
|
|
3
|
+
*
|
|
4
|
+
* @description
|
|
5
|
+
* Константа используется для фильтрации переменных окружения по их префиксам:
|
|
6
|
+
* - `MIRTA_` — системные настройки фреймворка (например, логирование, таймауты).
|
|
7
|
+
* - `APP_` — пользовательские сценарии и параметры автоматизаций (например, расписания, пороговые значения).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```env
|
|
11
|
+
* # Пример переменной окружения, которая будет учтена
|
|
12
|
+
* MIRTA_LOG_LEVEL=debug
|
|
13
|
+
* APP_LIVING_ROOM_LIGHTS_SCHEDULE='18:00-22:00'
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* @remarks
|
|
17
|
+
* Эта константа предназначена для использования в конфигурации `loadEnv`, где указывается фильтр для загрузки `.env`-файлов.
|
|
18
|
+
* Может быть переопределена через пользовательскую конфигурацию, если требуется изменить список допустимых префиксов.
|
|
19
|
+
*
|
|
20
|
+
* @since 0.4.0
|
|
21
|
+
*
|
|
22
|
+
**/
|
|
23
|
+
declare const DEFAULT_ENV_PREFIXES: readonly ["MIRTA_", "APP_"];
|
|
24
|
+
/**
|
|
25
|
+
* Интерфейс для настройки параметров `dotenvx`.
|
|
26
|
+
*
|
|
27
|
+
* @since 0.4.0
|
|
28
|
+
*
|
|
29
|
+
**/
|
|
30
|
+
interface DotenvOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Кодировка файла `.env`, по умолчанию `'utf-8'`
|
|
33
|
+
*
|
|
34
|
+
**/
|
|
35
|
+
encoding?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Перезаписывает любые существующие переменные окружения значениями из файла `.env`
|
|
38
|
+
*
|
|
39
|
+
* @default false
|
|
40
|
+
*
|
|
41
|
+
**/
|
|
42
|
+
overload?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Выбрасывает ошибку сразу при её возникновении — например, при отсутствии файла `.env`.
|
|
45
|
+
*
|
|
46
|
+
* @default false
|
|
47
|
+
*
|
|
48
|
+
**/
|
|
49
|
+
strict?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Подавляет конкретные ошибки, например `MISSING_ENV_FILE`.
|
|
52
|
+
*
|
|
53
|
+
* Ключи ошибок можно найти в [исходном коде](https://github.com/dotenvx/dotenvx/blob/main/src/lib/helpers/errors.js) библиотеки `dotenvx`.
|
|
54
|
+
*
|
|
55
|
+
**/
|
|
56
|
+
ignore?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Путь к файлу с приватными ключами `.env.keys`, полезно для монорепозиториев.
|
|
59
|
+
*
|
|
60
|
+
**/
|
|
61
|
+
envKeysFile?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Включает логирование для диагностики причин, почему определённые ключи или значения не устанавливаются.
|
|
64
|
+
*
|
|
65
|
+
* @default false
|
|
66
|
+
*
|
|
67
|
+
**/
|
|
68
|
+
debug?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Увеличивает уровень детализации логов.
|
|
71
|
+
*
|
|
72
|
+
* @default false
|
|
73
|
+
*
|
|
74
|
+
**/
|
|
75
|
+
verbose?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Подавляет все сообщения в консоль, даже ошибки.
|
|
78
|
+
*
|
|
79
|
+
* @default false
|
|
80
|
+
*
|
|
81
|
+
**/
|
|
82
|
+
quiet?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Уровень логирования. Определяет, какие сообщения будут выводиться в консоль.
|
|
85
|
+
*
|
|
86
|
+
**/
|
|
87
|
+
logLevel?: 'error' | 'warn' | 'success' | 'successv' | 'info' | 'help' | 'verbose' | 'debug';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Позволяет настроить поведение загрузки и фильтрации переменных окружения.
|
|
91
|
+
*
|
|
92
|
+
* @since 0.4.0
|
|
93
|
+
*
|
|
94
|
+
**/
|
|
95
|
+
interface EnvLoaderOptions {
|
|
96
|
+
/**
|
|
97
|
+
* Режим окружения (например, `'development'`, `'production'`, `'test'`).
|
|
98
|
+
*
|
|
99
|
+
* По умолчанию используется значение из `process.env.NODE_ENV`.
|
|
100
|
+
*
|
|
101
|
+
**/
|
|
102
|
+
mode?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Префиксы для фильтрации переменных окружения.
|
|
105
|
+
*
|
|
106
|
+
* Если не указано, используется значение по умолчанию из {@link DEFAULT_ENV_PREFIXES}..
|
|
107
|
+
*
|
|
108
|
+
* @remarks
|
|
109
|
+
* Полностью отключить фильтрацию нельзя — это мера защиты от утечки секретов
|
|
110
|
+
* (например, `DB_PASSWORD`, `API_KEY`) в клиентский код.
|
|
111
|
+
*
|
|
112
|
+
* Чтобы использовать другие префиксы, перечислите их явно.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // Фильтрация по одному префиксу
|
|
116
|
+
* prefix: 'APP_'
|
|
117
|
+
* // → включаются только переменные, начинающиеся с `APP_`
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Фильтрация по нескольким префиксам
|
|
121
|
+
* prefix: ['MIRTA_', 'CUSTOM_']
|
|
122
|
+
* // → включаются переменные с `MIRTA_` или `CUSTOM_`
|
|
123
|
+
*
|
|
124
|
+
**/
|
|
125
|
+
prefix?: string | string[];
|
|
126
|
+
/**
|
|
127
|
+
* Текущая рабочая директория для обнаружения и загрузки файлов `.env`.
|
|
128
|
+
*
|
|
129
|
+
**/
|
|
130
|
+
cwd?: string;
|
|
131
|
+
/**
|
|
132
|
+
* Корневая директория проекта.
|
|
133
|
+
*
|
|
134
|
+
* Используется для обнаружения и загрузки общих `.env`-файлов.
|
|
135
|
+
* Если не указана или совпадает с `cwd`, поиск в корне не выполняется.
|
|
136
|
+
*
|
|
137
|
+
**/
|
|
138
|
+
rootDir?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Префикс файла с переменными окружения, по умолчанию `'.env'`.
|
|
141
|
+
*
|
|
142
|
+
**/
|
|
143
|
+
envFile?: string | string[];
|
|
144
|
+
/**
|
|
145
|
+
* Определяет, нужно ли включать переменную `NODE_ENV` в результат.
|
|
146
|
+
*
|
|
147
|
+
* @default true
|
|
148
|
+
*
|
|
149
|
+
* @remarks
|
|
150
|
+
*
|
|
151
|
+
* Используется для изоляции тестовой среды или предотвращения
|
|
152
|
+
* утечки режима выполнения в клиентский код.
|
|
153
|
+
*
|
|
154
|
+
**/
|
|
155
|
+
keepNodeEnv?: boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Дополнительные параметры библиотеки `dotenvx`.
|
|
158
|
+
*
|
|
159
|
+
**/
|
|
160
|
+
dotenv?: DotenvOptions;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Загружает и фильтрует переменные окружения из dotenv-файлов.
|
|
164
|
+
* @param options Опции загрузки и фильтрации переменных окружения (см. {@link EnvLoaderOptions}).
|
|
165
|
+
* @returns Набор переменных окружения.
|
|
166
|
+
*
|
|
167
|
+
* @since 0.4.0
|
|
168
|
+
*
|
|
169
|
+
**/
|
|
170
|
+
declare function loadEnv(options?: EnvLoaderOptions): Record<string, string>;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Загружает и фильтрует переменные окружения из dotenv-файлов.
|
|
174
|
+
* Используется совместно с `@rollup/plugin-replace` для замены значений в коде.
|
|
175
|
+
*
|
|
176
|
+
* @param options Опции загрузки и фильтрации переменных окружения (см. {@link EnvLoaderOptions}).
|
|
177
|
+
* @returns Объект с ключами вида `process.env.KEY` и `import.meta.env.KEY`, где `KEY` — имя переменной окружения.
|
|
178
|
+
*
|
|
179
|
+
*
|
|
180
|
+
* @since 0.4.0
|
|
181
|
+
*
|
|
182
|
+
**/
|
|
183
|
+
declare function loadEnvReplacements(options?: EnvLoaderOptions): Record<string, string>;
|
|
184
|
+
|
|
185
|
+
export { DEFAULT_ENV_PREFIXES, loadEnv, loadEnvReplacements };
|
|
186
|
+
export type { EnvLoaderOptions };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import nodePath from 'node:path';
|
|
2
|
+
import dotenvx from '@dotenvx/dotenvx';
|
|
3
|
+
import { ensureCompactArray, ensureArray } from '@mirta/basics/array';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Набор префиксов для переменных окружения, которые будут загружены в проект.
|
|
8
|
+
*
|
|
9
|
+
* @description
|
|
10
|
+
* Константа используется для фильтрации переменных окружения по их префиксам:
|
|
11
|
+
* - `MIRTA_` — системные настройки фреймворка (например, логирование, таймауты).
|
|
12
|
+
* - `APP_` — пользовательские сценарии и параметры автоматизаций (например, расписания, пороговые значения).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```env
|
|
16
|
+
* # Пример переменной окружения, которая будет учтена
|
|
17
|
+
* MIRTA_LOG_LEVEL=debug
|
|
18
|
+
* APP_LIVING_ROOM_LIGHTS_SCHEDULE='18:00-22:00'
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* @remarks
|
|
22
|
+
* Эта константа предназначена для использования в конфигурации `loadEnv`, где указывается фильтр для загрузки `.env`-файлов.
|
|
23
|
+
* Может быть переопределена через пользовательскую конфигурацию, если требуется изменить список допустимых префиксов.
|
|
24
|
+
*
|
|
25
|
+
* @since 0.4.0
|
|
26
|
+
*
|
|
27
|
+
**/
|
|
28
|
+
const DEFAULT_ENV_PREFIXES = ['MIRTA_', 'APP_'];
|
|
29
|
+
/**
|
|
30
|
+
* Возвращает возможные имена .env-файлов в зависимости от режима окружения.
|
|
31
|
+
*
|
|
32
|
+
* @param mode - Название текущего режима (например, `'development'`, `'production'`, `'test'`).
|
|
33
|
+
* Если значение не определено, возвращается только базовый файл.
|
|
34
|
+
* @param envFile - Базовое имя файла, которое будет дополнено (по умолчанию `.env`).
|
|
35
|
+
* @returns Массив строк с путями к файлам окружения, отсортированный в порядке убывания приоритета загрузки.
|
|
36
|
+
*
|
|
37
|
+
* @since 0.4.0
|
|
38
|
+
*
|
|
39
|
+
**/
|
|
40
|
+
function getEnvFileVariantsByMode(mode, envFile) {
|
|
41
|
+
if (mode === 'test' && envFile.endsWith('.local'))
|
|
42
|
+
return [];
|
|
43
|
+
const envFiles = [];
|
|
44
|
+
if (mode) {
|
|
45
|
+
// 1. Формируем файлы с суффиксом .local для конкретного окружения (кроме test)
|
|
46
|
+
if (mode !== 'test')
|
|
47
|
+
envFiles.push(`${envFile}.${mode}.local`);
|
|
48
|
+
// 2. Формируем файл для конкретного окружения без .local
|
|
49
|
+
envFiles.push(`${envFile}.${mode}`);
|
|
50
|
+
}
|
|
51
|
+
// 3. Формируем глобальный .local-файл (кроме test)
|
|
52
|
+
if (mode !== 'test')
|
|
53
|
+
envFiles.push(`${envFile}.local`);
|
|
54
|
+
// 4. Базовый файл
|
|
55
|
+
envFiles.push(envFile);
|
|
56
|
+
// Собираем список и убираем пустые элементы
|
|
57
|
+
return envFiles;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Формирует список существующих файлов окружения для загрузки на основе режима, текущей и корневой директорий.
|
|
61
|
+
*
|
|
62
|
+
* @param options - Опции разрешения путей: `mode` (env mode), `cwd` (текущая рабочая директория), `rootDir` (опциональная корневая директория для общих .env), `envFile` (имя или список базовых файлов, по умолчанию `.env`), `quiet` (подавлять предупреждения о дубликатах)
|
|
63
|
+
* @returns Массив абсолютных путей к существующим файлам окружения, в порядке поиска (сначала по `cwd`, затем по `rootDir` при наличии)
|
|
64
|
+
*
|
|
65
|
+
* @since 0.4.0
|
|
66
|
+
*/
|
|
67
|
+
function resolveEnvFiles(options) {
|
|
68
|
+
const { mode, cwd, rootDir, envFile = '.env', quiet } = options;
|
|
69
|
+
// Сначала — все файлы из cwd
|
|
70
|
+
const lookupDirs = [cwd];
|
|
71
|
+
// Потом — все файлы из rootDir, если директория указана
|
|
72
|
+
if (rootDir && rootDir !== cwd)
|
|
73
|
+
lookupDirs.push(rootDir);
|
|
74
|
+
// Преобразует envFile в массив уникальных значений:
|
|
75
|
+
// удаляет дубликаты с помощью `Set`.
|
|
76
|
+
//
|
|
77
|
+
const envFiles = [
|
|
78
|
+
...new Set(ensureArray(envFile)),
|
|
79
|
+
];
|
|
80
|
+
const envFilesVariants = new Set();
|
|
81
|
+
for (const file of envFiles) {
|
|
82
|
+
for (const variant of getEnvFileVariantsByMode(mode, file)) {
|
|
83
|
+
if (envFilesVariants.has(variant) && !quiet) {
|
|
84
|
+
console.warn(`[@mirta/env-loader] Redundant env file entry detected: "${file}" may be unnecessary, as it generates a file already covered by another entry.`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
envFilesVariants.add(variant);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const result = [];
|
|
91
|
+
// Перечисляем директории, в которых нужно выполнить поиск.
|
|
92
|
+
for (const dir of lookupDirs) {
|
|
93
|
+
// Перемножаем на варианты .env-файлов (обычно это все вариации `.env`)
|
|
94
|
+
for (const file of envFilesVariants) {
|
|
95
|
+
const path = nodePath.join(dir, file).replaceAll('\\', '/');
|
|
96
|
+
// Самостоятельно отсеиваем несуществующие файлы,
|
|
97
|
+
// чтобы предотвратить падение производительности.
|
|
98
|
+
//
|
|
99
|
+
if (existsSync(path))
|
|
100
|
+
result.push(path);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Отбирает из заданного набора только допустимые переменные окружения и возвращает их в детерминированном порядке.
|
|
107
|
+
*
|
|
108
|
+
* Фильтрация пропускает только пары, у которых есть определённое строковое значение; ключы, совпадающие с любым из указанных префиксов, и (опционально) `NODE_ENV` включаются в результат.
|
|
109
|
+
*
|
|
110
|
+
* @param env - Объект переменных окружения, значения могут быть `undefined`; только пары с определёнными строковыми значениями рассматриваются.
|
|
111
|
+
* @param prefixes - Список префиксов; ключ включается, если начинается с любого из этих префиксов.
|
|
112
|
+
* @param keepNodeEnv - Если `true`, ключ `NODE_ENV` будет включён в результат независимо от префиксов.
|
|
113
|
+
* @returns Объект с отфильтрованными парами ключ/значение; ключи отсортированы лексикографически с учётом числовых частей.
|
|
114
|
+
*
|
|
115
|
+
* @since 0.4.0
|
|
116
|
+
*/
|
|
117
|
+
function filterEnvKeys(env, prefixes, keepNodeEnv) {
|
|
118
|
+
// Типовой гвард для проверки ключа и значения.
|
|
119
|
+
const isValidEntry = (entry) => {
|
|
120
|
+
const [key, value] = entry;
|
|
121
|
+
if (value === undefined)
|
|
122
|
+
return false;
|
|
123
|
+
if (key === 'NODE_ENV')
|
|
124
|
+
return keepNodeEnv;
|
|
125
|
+
return prefixes.some(prefix => key.startsWith(prefix));
|
|
126
|
+
};
|
|
127
|
+
// Фильтрация и сортировка пар "ключ-значение", гарантирует
|
|
128
|
+
// детерминированный порядок ключей.
|
|
129
|
+
//
|
|
130
|
+
const filteredEntries = Object.entries(env)
|
|
131
|
+
.filter(isValidEntry)
|
|
132
|
+
.sort(([keyA], [keyB]) => keyA.localeCompare(keyB, 'en-US', {
|
|
133
|
+
sensitivity: 'base', // Игнорирует регистр и диакритики
|
|
134
|
+
numeric: true, // Числа в строках сравниваются как числа
|
|
135
|
+
}));
|
|
136
|
+
// Преобразует массив `[ключ, значение]` обратно в объект.
|
|
137
|
+
// Гарантирует детерминированный порядок ключей.
|
|
138
|
+
//
|
|
139
|
+
return Object.fromEntries(filteredEntries);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Загружает и фильтрует переменные окружения из dotenv-файлов.
|
|
143
|
+
* @param options Опции загрузки и фильтрации переменных окружения (см. {@link EnvLoaderOptions}).
|
|
144
|
+
* @returns Набор переменных окружения.
|
|
145
|
+
*
|
|
146
|
+
* @since 0.4.0
|
|
147
|
+
*
|
|
148
|
+
**/
|
|
149
|
+
function loadEnv(options = {}) {
|
|
150
|
+
const { mode = process.env.NODE_ENV, prefix = [...DEFAULT_ENV_PREFIXES], cwd = process.cwd(), rootDir, envFile = '.env', keepNodeEnv = true, dotenv, } = options;
|
|
151
|
+
// Хранилище для загруженных переменных окружения.
|
|
152
|
+
let processEnv = { ...process.env };
|
|
153
|
+
const files = resolveEnvFiles({ cwd, rootDir, mode, envFile, quiet: dotenv?.quiet });
|
|
154
|
+
if (files.length > 0)
|
|
155
|
+
dotenvx.config({
|
|
156
|
+
// Переопределяемые параметры конфигурации:
|
|
157
|
+
logLevel: 'warn',
|
|
158
|
+
ignore: [
|
|
159
|
+
'MISSING_ENV_FILE',
|
|
160
|
+
],
|
|
161
|
+
// Пользовательская конфигурация.
|
|
162
|
+
...dotenv,
|
|
163
|
+
// Параметры, которые переопределить нельзя:
|
|
164
|
+
path: files,
|
|
165
|
+
processEnv,
|
|
166
|
+
convention: undefined,
|
|
167
|
+
});
|
|
168
|
+
// Фильтрация переменных по заданным префиксам.
|
|
169
|
+
processEnv = filterEnvKeys(processEnv, ensureCompactArray(prefix), keepNodeEnv);
|
|
170
|
+
return processEnv;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Загружает и фильтрует переменные окружения из dotenv-файлов.
|
|
175
|
+
* Используется совместно с `@rollup/plugin-replace` для замены значений в коде.
|
|
176
|
+
*
|
|
177
|
+
* @param options Опции загрузки и фильтрации переменных окружения (см. {@link EnvLoaderOptions}).
|
|
178
|
+
* @returns Объект с ключами вида `process.env.KEY` и `import.meta.env.KEY`, где `KEY` — имя переменной окружения.
|
|
179
|
+
*
|
|
180
|
+
*
|
|
181
|
+
* @since 0.4.0
|
|
182
|
+
*
|
|
183
|
+
**/
|
|
184
|
+
function loadEnvReplacements(options = {}) {
|
|
185
|
+
const env = loadEnv(options);
|
|
186
|
+
const result = {};
|
|
187
|
+
for (const [key, rawValue] of Object.entries(env)) {
|
|
188
|
+
const value = JSON.stringify(rawValue);
|
|
189
|
+
result[`process.env.${key}`] = value;
|
|
190
|
+
result[`import.meta.env.${key}`] = value;
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export { DEFAULT_ENV_PREFIXES, loadEnv, loadEnvReplacements };
|
package/package.json
CHANGED
|
@@ -1,10 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirta/env-loader",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"description": "Internal dotenvx-based environment loader, used by Mirta Framework",
|
|
5
6
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
"mirta",
|
|
8
|
+
"env",
|
|
9
|
+
"environment",
|
|
10
|
+
"loader",
|
|
11
|
+
"dotenv",
|
|
12
|
+
"dotenvx",
|
|
13
|
+
"nodejs",
|
|
14
|
+
"utility",
|
|
15
|
+
"tooling"
|
|
16
|
+
],
|
|
17
|
+
"license": "Unlicense",
|
|
18
|
+
"homepage": "https://github.com/wb-mirta/core#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/wb-mirta/core/issues"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/wb-mirta/core.git",
|
|
25
|
+
"directory": "packages/mirta-env-loader"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"types": "./dist/index.d.mts",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"import": {
|
|
37
|
+
"types": "./dist/index.d.mts",
|
|
38
|
+
"default": "./dist/index.mjs"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"imports": {
|
|
43
|
+
"#src": "./src/index.js",
|
|
44
|
+
"#src/*": "./src/*.js"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@dotenvx/dotenvx": "^1.51.1",
|
|
48
|
+
"@mirta/basics": "0.4.1"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=24.12.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build:mono": "rollup -c node:@mirta/rollup/config-package"
|
|
55
|
+
}
|
|
56
|
+
}
|