ultraenv 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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2058 -0
  3. package/bin/ultraenv.mjs +3 -0
  4. package/dist/chunk-2USZPWLZ.js +288 -0
  5. package/dist/chunk-3UV2QNJL.js +270 -0
  6. package/dist/chunk-3VYXPTYV.js +179 -0
  7. package/dist/chunk-4XUYMRK5.js +366 -0
  8. package/dist/chunk-5G2DU52U.js +189 -0
  9. package/dist/chunk-6KS56D6E.js +172 -0
  10. package/dist/chunk-AWN6ADV7.js +328 -0
  11. package/dist/chunk-CHVO6NWI.js +203 -0
  12. package/dist/chunk-CIFMBJ4H.js +3975 -0
  13. package/dist/chunk-GC7RXHLA.js +253 -0
  14. package/dist/chunk-HFXQGJY3.js +445 -0
  15. package/dist/chunk-IGFVP24Q.js +91 -0
  16. package/dist/chunk-IKPTKALB.js +78 -0
  17. package/dist/chunk-JB7RKV3C.js +66 -0
  18. package/dist/chunk-MNVFG7H4.js +611 -0
  19. package/dist/chunk-MSXMESFP.js +1910 -0
  20. package/dist/chunk-N5PAV4NM.js +127 -0
  21. package/dist/chunk-NBOABPHM.js +158 -0
  22. package/dist/chunk-OMAOROL4.js +49 -0
  23. package/dist/chunk-R7PZRSZ7.js +105 -0
  24. package/dist/chunk-TE7HPLA6.js +73 -0
  25. package/dist/chunk-TMT5KCO3.js +101 -0
  26. package/dist/chunk-UEWYFN6A.js +189 -0
  27. package/dist/chunk-WMHN5RW2.js +128 -0
  28. package/dist/chunk-XC65ORJ5.js +70 -0
  29. package/dist/chunk-YMMP4VQL.js +118 -0
  30. package/dist/chunk-YN2KGTCB.js +33 -0
  31. package/dist/chunk-YTICOB5M.js +65 -0
  32. package/dist/chunk-YVWLXFUT.js +107 -0
  33. package/dist/ci-check-sync-VBMSVWIV.js +48 -0
  34. package/dist/ci-scan-24MT5XGS.js +41 -0
  35. package/dist/ci-setup-C2NKEFRD.js +135 -0
  36. package/dist/ci-validate-7AW24LSQ.js +57 -0
  37. package/dist/cli/index.cjs +9217 -0
  38. package/dist/cli/index.d.cts +9 -0
  39. package/dist/cli/index.d.ts +9 -0
  40. package/dist/cli/index.js +339 -0
  41. package/dist/comparator-RDKX3OI7.js +13 -0
  42. package/dist/completion-MW35C2XO.js +168 -0
  43. package/dist/config-O5YRQP5Z.js +13 -0
  44. package/dist/debug-PTPXAF3K.js +131 -0
  45. package/dist/declaration-LEME4AFZ.js +10 -0
  46. package/dist/doctor-FZAUPKHS.js +129 -0
  47. package/dist/envs-compare-5K3HESX5.js +49 -0
  48. package/dist/envs-create-2XXHXMGA.js +58 -0
  49. package/dist/envs-list-NQM5252B.js +59 -0
  50. package/dist/envs-switch-6L2AQYID.js +50 -0
  51. package/dist/envs-validate-FL73Q76T.js +89 -0
  52. package/dist/fs-VH7ATUS3.js +31 -0
  53. package/dist/generator-LFZBMZZS.js +14 -0
  54. package/dist/git-BZS4DPAI.js +30 -0
  55. package/dist/help-3XJBXEHE.js +121 -0
  56. package/dist/index.cjs +12907 -0
  57. package/dist/index.d.cts +2562 -0
  58. package/dist/index.d.ts +2562 -0
  59. package/dist/index.js +3212 -0
  60. package/dist/init-Y7JQ2KYJ.js +146 -0
  61. package/dist/install-hook-SKXIV6NV.js +111 -0
  62. package/dist/json-schema-I26YNQBH.js +10 -0
  63. package/dist/key-manager-O3G55WPU.js +25 -0
  64. package/dist/middleware/express.cjs +103 -0
  65. package/dist/middleware/express.d.cts +115 -0
  66. package/dist/middleware/express.d.ts +115 -0
  67. package/dist/middleware/express.js +8 -0
  68. package/dist/middleware/fastify.cjs +91 -0
  69. package/dist/middleware/fastify.d.cts +111 -0
  70. package/dist/middleware/fastify.d.ts +111 -0
  71. package/dist/middleware/fastify.js +8 -0
  72. package/dist/module-IDIZPP4M.js +10 -0
  73. package/dist/protect-NCWPM6VC.js +161 -0
  74. package/dist/scan-TRLY36TT.js +58 -0
  75. package/dist/schema/index.cjs +4074 -0
  76. package/dist/schema/index.d.cts +1244 -0
  77. package/dist/schema/index.d.ts +1244 -0
  78. package/dist/schema/index.js +152 -0
  79. package/dist/sync-TMHMTLH2.js +186 -0
  80. package/dist/typegen-SQOSXBWM.js +80 -0
  81. package/dist/validate-IOAM5HWS.js +100 -0
  82. package/dist/vault-decrypt-U6HJZNBV.js +111 -0
  83. package/dist/vault-diff-B3ZOQTWI.js +132 -0
  84. package/dist/vault-encrypt-GUSLCSKS.js +112 -0
  85. package/dist/vault-init-GUBOTOUL.js +106 -0
  86. package/dist/vault-rekey-DAHT7JCN.js +132 -0
  87. package/dist/vault-status-GDLRU2OK.js +90 -0
  88. package/dist/vault-verify-CD76FJSF.js +102 -0
  89. package/package.json +106 -0
package/README.md ADDED
@@ -0,0 +1,2058 @@
1
+ <div align="center">
2
+
3
+ ```
4
+ โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
5
+ โ•‘ โ•‘
6
+ โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ•‘
7
+ โ•‘ โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ• โ•‘
8
+ โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ•‘
9
+ โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ•‘
10
+ โ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•— โ•‘
11
+ โ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ• โ•‘
12
+ โ•‘ โ•‘
13
+ โ•‘ The Ultimate Environment Variable Manager โ•‘
14
+ โ•‘ v1.0.0 โ•‘
15
+ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
16
+ ```
17
+
18
+ **Validate, Type, Encrypt, Sync, and Never Ship Broken Configs Again.**
19
+
20
+ [![npm version](https://img.shields.io/npm/v/ultraenv.svg?style=flat-square&color=0EA5E9)](https://www.npmjs.com/package/ultraenv)
21
+ [![License: MIT](https://img.shields.io/npm/l/ultraenv.svg?style=flat-square&color=22C55E)](https://github.com/Avinashvelu03/ultraenv/blob/main/LICENSE)
22
+ [![Node.js](https://img.shields.io/node/v/ultraenv.svg?style=flat-square&color=339933)](https://nodejs.org)
23
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-blue.svg?style=flat-square)](https://www.npmjs.com/package/ultraenv)
24
+ [![TypeScript](https://img.shields.io/badge/types-TypeScript-3178C6.svg?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
25
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg?style=flat-square)](https://github.com/Avinashvelu03/ultraenv/actions)
26
+
27
+ [Getting Started](#-quick-start) ยท [Schema Reference](#-schema-reference) ยท [CLI Reference](#-cli-command-reference) ยท [Vault Guide](#-encryption--vault) ยท [Docs](#documentation)
28
+
29
+ </div>
30
+
31
+ ---
32
+
33
+ ## ๐Ÿค” Why ultraenv?
34
+
35
+ Every project uses environment variables. Every project gets them wrong eventually.
36
+
37
+ - **Missing variables** crash production at 3 AM.
38
+ - **Wrong types** (`process.env.PORT` is always a string) cause silent bugs.
39
+ - **Leaked secrets** in `.env` files end up in git history forever.
40
+ - **Drifting `.env.example`** files lead to confusing onboarding for new developers.
41
+ - **No validation** means you find out about missing configs at runtime.
42
+
43
+ **ultraenv** solves all of these problems with a single, zero-dependency library that provides:
44
+
45
+ | Problem | ultraenv Solution |
46
+ |---|---|
47
+ | No type safety for `process.env` | Full TypeScript inference from schema |
48
+ | Secrets leaked in git | Built-in secret scanner with 55+ patterns |
49
+ | No `.env` validation | Schema engine with 30+ validators |
50
+ | Secrets in plain text | AES-256-GCM encrypted vault |
51
+ | `.env.example` out of sync | Auto-sync with watch mode |
52
+ | No multi-environment support | Multi-env management (dev, staging, prod) |
53
+ | Can't use in CI/CD | CI commands with SARIF output |
54
+ | Hard to migrate from dotenv | Drop-in replacement with `load()` |
55
+
56
+ ---
57
+
58
+ ## ๐Ÿ“Š Feature Comparison
59
+
60
+ | Feature | **ultraenv** | [dotenv](https://github.com/motdotla/dotenv) | [envalid](https://github.com/af/envalid) | [@t3-oss/env](https://github.com/t3-oss/env-core) |
61
+ |---|:---:|:---:|:---:|:---:|
62
+ | **Parse `.env` files** | โœ… | โœ… | โœ… | โœ… |
63
+ | **TypeScript inference** | โœ… Full | โŒ | โœ… Partial | โœ… Full |
64
+ | **Schema validators** | โœ… 30+ | โŒ | โœ… 8 | โœ… Via zod |
65
+ | **String validators** | โœ… 20+ | โŒ | โŒ | Via zod |
66
+ | **Secret scanning** | โœ… 55+ patterns | โŒ | โŒ | โŒ |
67
+ | **Encrypted vault** | โœ… AES-256-GCM | โŒ | โŒ | โŒ |
68
+ | **Key rotation** | โœ… | โŒ | โŒ | โŒ |
69
+ | **`.env.example` sync** | โœ… Watch mode | โŒ | โŒ | โŒ |
70
+ | **Type generation** | โœ… `.d.ts` / module / JSON Schema | โŒ | โŒ | โœ… |
71
+ | **Multi-environment** | โœ… 11 file variants | โŒ | โŒ | โŒ |
72
+ | **Framework presets** | โœ… 9 presets | โŒ | โŒ | โŒ |
73
+ | **CI/CD integration** | โœ… SARIF output | โŒ | โŒ | โŒ |
74
+ | **Variable interpolation** | โœ… `$VAR` / `${VAR}` | โœ… | โŒ | โŒ |
75
+ | **File cascade** | โœ… Priority-based | โŒ | โŒ | โŒ |
76
+ | **Hot reload watcher** | โœ… | โŒ | โŒ | โŒ |
77
+ | **Health check API** | โœ… | โŒ | โŒ | โŒ |
78
+ | **Express middleware** | โœ… | โŒ | โŒ | โŒ |
79
+ | **Fastify plugin** | โœ… | โŒ | โŒ | โŒ |
80
+ | **SARIF output** | โœ… | โŒ | โŒ | โŒ |
81
+ | **Git hook integration** | โœ… | โŒ | โŒ | โŒ |
82
+ | **dotenv-compatible API** | โœ… | โ€” | โŒ | โŒ |
83
+ | **Zero dependencies** | โœ… | โœ… | โŒ | โŒ |
84
+ | **Node.js** | โ‰ฅ 18 | โ‰ฅ 12 | โ‰ฅ 14 | โ‰ฅ 18 |
85
+
86
+ ---
87
+
88
+ ## ๐Ÿš€ Quick Start
89
+
90
+ Get started in three steps:
91
+
92
+ ### Step 1 โ€” Install
93
+
94
+ ```bash
95
+ npm install ultraenv
96
+ ```
97
+
98
+ ### Step 2 โ€” Define your schema
99
+
100
+ Create an `env.ts` file:
101
+
102
+ ```typescript
103
+ import { defineEnv, t } from 'ultraenv';
104
+
105
+ const env = defineEnv({
106
+ // Required string with URL validation
107
+ DATABASE_URL: t.string().format('url').required(),
108
+
109
+ // Number with port validation and a default
110
+ PORT: t.number().port().default(3000),
111
+
112
+ // Enum with literal union types
113
+ NODE_ENV: t.enum(['development', 'staging', 'production'] as const).required(),
114
+
115
+ // Boolean with default
116
+ DEBUG: t.boolean().default(false),
117
+
118
+ // Optional email
119
+ ADMIN_EMAIL: t.email().optional(),
120
+
121
+ // Array with custom separator
122
+ ALLOWED_ORIGINS: t.array().separator(';').default(['http://localhost:3000']),
123
+
124
+ // Duration string
125
+ CACHE_TTL: t.duration().default('1h'),
126
+
127
+ // Bytes string
128
+ MAX_UPLOAD_SIZE: t.bytes().default('10MB'),
129
+ });
130
+
131
+ export default env;
132
+
133
+ // TypeScript knows the exact types:
134
+ // env.DATABASE_URL โ†’ string
135
+ // env.PORT โ†’ number (not string!)
136
+ // env.NODE_ENV โ†’ 'development' | 'staging' | 'production'
137
+ // env.DEBUG โ†’ boolean
138
+ // env.ADMIN_EMAIL โ†’ string | undefined
139
+ // env.ALLOWED_ORIGINS โ†’ readonly string[]
140
+ // env.CACHE_TTL โ†’ string
141
+ // env.MAX_UPLOAD_SIZE โ†’ string
142
+ ```
143
+
144
+ ### Step 3 โ€” Use your typed env everywhere
145
+
146
+ ```typescript
147
+ // Any file in your project:
148
+ import env from './env';
149
+
150
+ // Fully typed โ€” no more `process.env.PORT as unknown as number`
151
+ const server = createServer({
152
+ port: env.PORT, // number
153
+ host: env.HOST, // string
154
+ databaseUrl: env.DATABASE_URL, // string (URL-validated)
155
+ });
156
+
157
+ if (env.NODE_ENV === 'development') {
158
+ // TypeScript knows the exact enum values!
159
+ console.log('Development mode:', env.DEBUG);
160
+ }
161
+ ```
162
+
163
+ That's it. Your environment is validated, typed, and safe.
164
+
165
+ ---
166
+
167
+ ## ๐Ÿ“ฆ Installation
168
+
169
+ ### npm
170
+
171
+ ```bash
172
+ npm install ultraenv
173
+ ```
174
+
175
+ ### pnpm
176
+
177
+ ```bash
178
+ pnpm add ultraenv
179
+ ```
180
+
181
+ ### yarn
182
+
183
+ ```bash
184
+ yarn add ultraenv
185
+ ```
186
+
187
+ ### bun
188
+
189
+ ```bash
190
+ bun add ultraenv
191
+ ```
192
+
193
+ ### Global CLI (optional)
194
+
195
+ ```bash
196
+ npm install -g ultraenv
197
+
198
+ # Then use the CLI anywhere
199
+ ultraenv init
200
+ ultraenv validate
201
+ ultraenv scan
202
+ ```
203
+
204
+ ### Verify Installation
205
+
206
+ ```bash
207
+ npx ultraenv --version
208
+ # โ†’ ultraenv v1.0.0
209
+ ```
210
+
211
+ ---
212
+
213
+ ## ๐Ÿ”ง CLI Command Reference
214
+
215
+ ultraenv ships with a powerful CLI for managing your environment files from the terminal.
216
+
217
+ ### Core Commands
218
+
219
+ | Command | Description |
220
+ |---|---|
221
+ | `ultraenv init` | Initialize project with config, `.env`, `.env.example`, and `.gitignore` |
222
+ | `ultraenv validate` | Load and validate environment variables |
223
+ | `ultraenv typegen` | Generate TypeScript types from schema |
224
+ | `ultraenv sync` | Sync `.env.example` with `.env` (check, generate, interactive, watch modes) |
225
+ | `ultraenv scan` | Scan codebase for leaked secrets |
226
+ | `ultraenv debug` | Show diagnostics and debugging info |
227
+ | `ultraenv protect` | Check and update `.gitignore` for secret protection |
228
+ | `ultraenv doctor` | Run self-checks and diagnose common issues |
229
+ | `ultraenv help` | Show help for any command |
230
+
231
+ ### Vault Commands
232
+
233
+ | Command | Description |
234
+ |---|---|
235
+ | `ultraenv vault init` | Initialize encrypted vault |
236
+ | `ultraenv vault encrypt` | Encrypt environment to vault |
237
+ | `ultraenv vault decrypt` | Decrypt environment from vault |
238
+ | `ultraenv vault rekey` | Rotate encryption keys |
239
+ | `ultraenv vault status` | Show vault status |
240
+ | `ultraenv vault diff` | Compare local env vs vault |
241
+ | `ultraenv vault verify` | Verify vault integrity |
242
+
243
+ ### Environment Commands
244
+
245
+ | Command | Description |
246
+ |---|---|
247
+ | `ultraenv envs list` | List all environments |
248
+ | `ultraenv envs compare` | Compare two environments |
249
+ | `ultraenv envs validate` | Validate all environments |
250
+ | `ultraenv envs create` | Create a new environment |
251
+ | `ultraenv envs switch` | Switch active environment |
252
+
253
+ ### CI Commands
254
+
255
+ | Command | Description |
256
+ |---|---|
257
+ | `ultraenv ci validate` | Validate environment in CI (strict mode) |
258
+ | `ultraenv ci check-sync` | Check `.env` โ†” `.env.example` sync |
259
+ | `ultraenv ci scan` | Scan for secrets (SARIF output) |
260
+ | `ultraenv ci setup` | Generate CI config files |
261
+
262
+ ### Utility Commands
263
+
264
+ | Command | Description |
265
+ |---|---|
266
+ | `ultraenv install-hook` | Install git pre-commit hook |
267
+ | `ultraenv completion` | Generate shell completions |
268
+
269
+ ### Global Flags
270
+
271
+ | Flag | Description |
272
+ |---|---|
273
+ | `--config <path>` | Path to config file |
274
+ | `--cwd <path>` | Working directory |
275
+ | `--format <fmt>` | Output format: `terminal`, `json`, `silent` |
276
+ | `--debug` | Enable debug output |
277
+ | `--no-color` | Disable color output |
278
+ | `-q`, `--quiet` | Suppress non-error output |
279
+ | `-v`, `--version` | Show version |
280
+ | `-h`, `--help` | Show help |
281
+
282
+ ### Examples
283
+
284
+ ```bash
285
+ # Initialize a new project
286
+ ultraenv init
287
+
288
+ # Validate current environment
289
+ ultraenv validate --format json
290
+
291
+ # Generate TypeScript types
292
+ ultraenv typegen --format declaration --out src/env.d.ts
293
+
294
+ # Scan for secrets (terminal output)
295
+ ultraenv scan --scope files
296
+
297
+ # Scan for secrets (SARIF for GitHub)
298
+ ultraenv scan --scope all --format sarif --output results.sarif
299
+
300
+ # Sync .env.example
301
+ ultraenv sync --mode generate
302
+ ultraenv sync --mode watch
303
+
304
+ # Vault operations
305
+ ultraenv vault init --env production
306
+ ultraenv vault encrypt --env production
307
+ ultraenv vault decrypt --env production
308
+
309
+ # Setup CI pipeline
310
+ ultraenv ci setup --platform github
311
+
312
+ # Install pre-commit hook
313
+ ultraenv install-hook
314
+ ```
315
+
316
+ ---
317
+
318
+ ## ๐Ÿ“ Schema Reference
319
+
320
+ The schema engine is the heart of ultraenv. It provides **30+ validators** and **10+ modifiers** for comprehensive environment variable validation with full TypeScript inference.
321
+
322
+ ### The `t` Factory
323
+
324
+ All schema builders are created via the `t` factory object:
325
+
326
+ ```typescript
327
+ import { defineEnv, t } from 'ultraenv';
328
+ ```
329
+
330
+ ---
331
+
332
+ ### Core Validators
333
+
334
+ #### `t.string()` โ€” String Validation
335
+
336
+ ```typescript
337
+ // Basic string
338
+ API_KEY: t.string().required(),
339
+
340
+ // With format validation
341
+ WEBSITE_URL: t.string().format('url').required(),
342
+ ADMIN_EMAIL: t.string().format('email').optional(),
343
+ APP_ID: t.string().format('uuid').required(),
344
+
345
+ // Length constraints
346
+ USERNAME: t.string().minLength(3).maxLength(50).required(),
347
+
348
+ // Regex pattern
349
+ SLUG: t.string().pattern(/^[a-z0-9-]+$/).required(),
350
+
351
+ // Enum shorthand
352
+ LOG_LEVEL: t.string().enum(['debug', 'info', 'warn', 'error'] as const).default('info'),
353
+
354
+ // Auto-trim whitespace
355
+ TRIMMED_VALUE: t.string().trim().required(),
356
+ ```
357
+
358
+ | Method | Parameter | Description |
359
+ |---|---|---|
360
+ | `.required()` | โ€” | Field must be set |
361
+ | `.optional()` | โ€” | Field may be undefined |
362
+ | `.default(value)` | `string` | Default when not set |
363
+ | `.description(desc)` | `string` | JSDoc description |
364
+ | `.minLength(n)` | `number` | Minimum string length |
365
+ | `.maxLength(n)` | `number` | Maximum string length |
366
+ | `.pattern(regex)` | `RegExp` | Must match regex |
367
+ | `.format(fmt)` | `string` | Predefined format shortcut |
368
+ | `.enum(values)` | `readonly string[]` | Allowed values |
369
+ | `.trim()` | `boolean?` | Trim whitespace |
370
+ | `.transform(fn)` | `(v) => v` | Transform after parse |
371
+ | `.validate(fn)` | `(v) => string \| void` | Custom validation |
372
+ | `.deprecated(msg)` | `string` | Deprecation warning |
373
+ | `.secret()` | โ€” | Mark as secret (masked in output) |
374
+ | `.alias(name)` | `string` | Alternative variable name |
375
+ ```
376
+
377
+ #### `t.number()` โ€” Number Validation
378
+
379
+ ```typescript
380
+ // Basic number (parses from string)
381
+ PORT: t.number().required(),
382
+
383
+ // Port validation (1-65535)
384
+ PORT: t.number().port().default(3000),
385
+
386
+ // Range constraints
387
+ MIN_AGE: t.number().min(0).max(150).required(),
388
+
389
+ // Integer constraint
390
+ PAGE_SIZE: t.number().integer().min(1).max(100).default(20),
391
+
392
+ // Positive / negative / non-negative
393
+ BALANCE: t.number().nonNegative().default(0),
394
+ DISCOUNT: t.number().negative().optional(),
395
+
396
+ // Finite check (no NaN or Infinity)
397
+ RATIO: t.number().finite().positive().required(),
398
+
399
+ // Custom parser
400
+ HEX_PORT: t.number().parse(v => parseInt(v, 16)).default(0x1F90),
401
+ ```
402
+
403
+ | Method | Parameter | Description |
404
+ |---|---|---|
405
+ | `.min(n)` | `number` | Minimum value |
406
+ | `.max(n)` | `number` | Maximum value |
407
+ | `.integer()` | โ€” | Must be integer |
408
+ | `.positive()` | โ€” | Must be > 0 |
409
+ | `.negative()` | โ€” | Must be < 0 |
410
+ | `.nonNegative()` | โ€” | Must be >= 0 |
411
+ | `.finite()` | โ€” | No NaN / Infinity |
412
+ | `.port()` | โ€” | Valid port (1โ€“65535) |
413
+ | `.parse(fn)` | `(raw) => number` | Custom parser |
414
+
415
+ ---
416
+
417
+ #### `t.boolean()` โ€” Boolean Validation
418
+
419
+ ```typescript
420
+ DEBUG: t.boolean().default(false),
421
+ ENABLE_CACHE: t.boolean().required(),
422
+
423
+ // Custom truthy/falsy values
424
+ FEATURE_FLAG: t.boolean()
425
+ .truthy(['on', 'enabled', '1', 'yes'])
426
+ .falsy(['off', 'disabled', '0', 'no'])
427
+ .default(false),
428
+ ```
429
+
430
+ Default truthy: `'true'`, `'1'`, `'yes'`, `'on'`, `'TRUE'`, `'True'`, `'YES'`, `'ON'`
431
+
432
+ Default falsy: `'false'`, `'0'`, `'no'`, `'off'`, `'FALSE'`, `'False'`, `'NO'`, `'OFF'`, `''`
433
+
434
+ ---
435
+
436
+ #### `t.enum()` โ€” Enum / Literal Union
437
+
438
+ ```typescript
439
+ // TypeScript literal union inference
440
+ NODE_ENV: t.enum(['development', 'staging', 'production'] as const).required(),
441
+ // Type: 'development' | 'staging' | 'production'
442
+
443
+ LOG_LEVEL: t.enum(['debug', 'info', 'warn', 'error', 'fatal'] as const)
444
+ .caseInsensitive()
445
+ .default('info'),
446
+
447
+ COLOR_SCHEME: t.enum(['light', 'dark', 'system'] as const).optional(),
448
+ ```
449
+
450
+ | Method | Parameter | Description |
451
+ |---|---|---|
452
+ | `.caseInsensitive()` | `boolean?` | Case-insensitive matching |
453
+
454
+ ---
455
+
456
+ ### Advanced Validators
457
+
458
+ #### `t.url()` โ€” URL Validation
459
+
460
+ ```typescript
461
+ PUBLIC_URL: t.url().required(),
462
+ API_ENDPOINT: t.url({ protocols: ['https'] }).required(),
463
+ REDIRECT_URL: t.url({ allowRelative: true }).optional(),
464
+ ```
465
+
466
+ Options: `protocols`, `allowRelative`, `allowQuery`, `requireTld`
467
+
468
+ ---
469
+
470
+ #### `t.email()` โ€” Email Validation
471
+
472
+ ```typescript
473
+ ADMIN_EMAIL: t.email().required(),
474
+ CONTACT: t.email({ allowDisplayName: true }).optional(),
475
+ ```
476
+
477
+ ---
478
+
479
+ #### `t.ip()` โ€” IP Address Validation
480
+
481
+ ```typescript
482
+ SERVER_IP: t.ip().required(), // IPv4 or IPv6
483
+ BIND_ADDRESS: t.ipv4().required(), // IPv4 only
484
+ LISTEN_IPV6: t.ipv6().optional(), // IPv6 only
485
+ ```
486
+
487
+ ---
488
+
489
+ #### `t.hostname()` โ€” Hostname Validation
490
+
491
+ ```typescript
492
+ SERVER_HOST: t.hostname().default('localhost'),
493
+ ALLOWED_HOST: t.hostname({ allowWildcard: true }).required(),
494
+ ```
495
+
496
+ ---
497
+
498
+ #### `t.port()` โ€” Port Validation
499
+
500
+ ```typescript
501
+ PORT: t.port().default(3000),
502
+ REDIS_PORT: t.port().default(6379),
503
+ ```
504
+
505
+ Validates 1โ€“65535 range.
506
+
507
+ ---
508
+
509
+ #### `t.uuid()` โ€” UUID Validation
510
+
511
+ ```typescript
512
+ REQUEST_ID: t.uuid().required(),
513
+ SESSION_ID: t.uuid({ version: 4 }).required(),
514
+ ```
515
+
516
+ Supports versions: 1, 3, 4, 5, or `null` for any.
517
+
518
+ ---
519
+
520
+ #### `t.array()` โ€” Array (Delimited String)
521
+
522
+ ```typescript
523
+ ALLOWED_ORIGINS: t.array().required(), // comma-separated
524
+ TAGS: t.array().separator(';').required(), // semicolon-separated
525
+ FEATURES: t.array().trimItems().filterEmpty().required(), // clean items
526
+ ROLES: t.array().minItems(1).maxItems(10).unique().required(),
527
+ ```
528
+
529
+ | Method | Parameter | Description |
530
+ |---|---|---|
531
+ | `.separator(sep)` | `string` | Split character (default: `,`) |
532
+ | `.trimItems()` | `boolean?` | Trim whitespace from items |
533
+ | `.filterEmpty()` | `boolean?` | Remove empty strings |
534
+ | `.minItems(n)` | `number` | Minimum items |
535
+ | `.maxItems(n)` | `number` | Maximum items |
536
+ | `.unique()` | โ€” | Deduplicate items |
537
+
538
+ ---
539
+
540
+ #### `t.json()` โ€” JSON Parsing
541
+
542
+ ```typescript
543
+ FEATURE_FLAGS: t.json().required(), // unknown
544
+ APP_CONFIG: t.json<{ theme: string; lang: string }>().required(),
545
+ MIDDLEWARE_CONFIG: t.json().reviver((key, value) => value).optional(),
546
+ ```
547
+
548
+ ---
549
+
550
+ #### `t.date()` โ€” Date Validation
551
+
552
+ ```typescript
553
+ START_DATE: t.date().required(),
554
+ EXPIRY: t.date().min(new Date('2024-01-01')).optional(),
555
+ CREATED: t.date().format('YYYY-MM-DD').required(),
556
+ ```
557
+
558
+ ---
559
+
560
+ #### `t.bigint()` โ€” BigInt Validation
561
+
562
+ ```typescript
563
+ MAX_SAFE_INTEGER: t.bigint().required(),
564
+ SATOSHIS: t.bigint().min(0n).parse(v => BigInt(v)).required(),
565
+ ```
566
+
567
+ ---
568
+
569
+ #### `t.regex()` โ€” Regex Validation
570
+
571
+ ```typescript
572
+ PATTERN: t.regex().required(),
573
+ ROUTE_MATCHER: t.regex({ flags: 'i' }).optional(),
574
+ ```
575
+
576
+ ---
577
+
578
+ ### String Format Validators
579
+
580
+ #### `t.hex()` โ€” Hexadecimal String
581
+
582
+ ```typescript
583
+ COLOR: t.hex().required(),
584
+ API_KEY_HEX: t.hex({ minLength: 32, maxLength: 64 }).required(),
585
+ ```
586
+
587
+ ---
588
+
589
+ #### `t.base64()` โ€” Base64 String
590
+
591
+ ```typescript
592
+ ENCODED_DATA: t.base64().required(),
593
+ CERT_B64: t.base64({ paddingRequired: true }).required(),
594
+ ```
595
+
596
+ ---
597
+
598
+ #### `t.semver()` โ€” Semantic Version
599
+
600
+ ```typescript
601
+ APP_VERSION: t.semver().required(),
602
+ MIN_VERSION: t.semver({ loose: true }).optional(),
603
+ ```
604
+
605
+ ---
606
+
607
+ #### `t.cron()` โ€” Cron Expression
608
+
609
+ ```typescript
610
+ SCHEDULE: t.cron().required(),
611
+ BACKUP_CRON: t.cron({ allowSeconds: true }).default('0 2 * * *'),
612
+ ```
613
+
614
+ ---
615
+
616
+ #### `t.duration()` โ€” Duration String
617
+
618
+ ```typescript
619
+ TIMEOUT: t.duration().default('30s'),
620
+ CACHE_TTL: t.duration().default('1h'),
621
+ LEASE_TIME: t.duration().default('24h'),
622
+ GRACE_PERIOD: t.duration().default('500ms'),
623
+ ```
624
+
625
+ Supported units: `ms`, `s`, `m`, `h`, `d`, `w`
626
+
627
+ ---
628
+
629
+ #### `t.bytes()` โ€” Bytes String
630
+
631
+ ```typescript
632
+ MAX_UPLOAD: t.bytes().default('10MB'),
633
+ MEMORY_LIMIT: t.bytes().default('512MB'),
634
+ DISK_QUOTA: t.bytes().default('1GB'),
635
+ ```
636
+
637
+ Supported units: `B`, `KB`, `MB`, `GB`, `TB`, `PB`
638
+
639
+ ---
640
+
641
+ #### `t.color()` โ€” Color String
642
+
643
+ ```typescript
644
+ BRAND_COLOR: t.color().required(),
645
+ ACCENT: t.color({ formats: ['hex', 'rgb'] }).default('#0ea5e9'),
646
+ ```
647
+
648
+ ---
649
+
650
+ #### `t.locale()` โ€” Locale Code
651
+
652
+ ```typescript
653
+ DEFAULT_LOCALE: t.locale().default('en-US'),
654
+ SUPPORTED_LOCALES: t.locale().required(),
655
+ ```
656
+
657
+ ---
658
+
659
+ #### `t.timezone()` โ€” IANA Timezone
660
+
661
+ ```typescript
662
+ TZ: t.timezone().default('UTC'),
663
+ USER_TIMEZONE: t.timezone().required(),
664
+ ```
665
+
666
+ Validates against the full IANA timezone database.
667
+
668
+ ---
669
+
670
+ #### `t.country()` โ€” ISO Country Code
671
+
672
+ ```typescript
673
+ COUNTRY: t.country().required(), // ISO 3166-1 alpha-2
674
+ REGION: t.country({ format: 'alpha-3' }).optional(), // ISO 3166-1 alpha-3
675
+ ```
676
+
677
+ ---
678
+
679
+ #### `t.currency()` โ€” ISO Currency Code
680
+
681
+ ```typescript
682
+ CURRENCY: t.currency().required(),
683
+ ```
684
+
685
+ ---
686
+
687
+ #### `t.path()` โ€” File System Path
688
+
689
+ ```typescript
690
+ CONFIG_PATH: t.path().required(),
691
+ OUTPUT_DIR: t.path({ mustExist: false }).optional(),
692
+ LOG_FILE: t.path({ mustExist: false, resolve: true }).default('/var/log/app.log'),
693
+ ```
694
+
695
+ ---
696
+
697
+ ### Schema Modifiers
698
+
699
+ All validators support these common modifiers:
700
+
701
+ #### `.required()` / `.optional()`
702
+
703
+ ```typescript
704
+ REQUIRED_VAR: t.string().required(), // throws if missing
705
+ OPTIONAL_VAR: t.string().optional(), // value is string | undefined
706
+ ```
707
+
708
+ #### `.default(value)`
709
+
710
+ ```typescript
711
+ PORT: t.number().default(3000),
712
+ HOST: t.string().default('localhost'),
713
+ ENABLED: t.boolean().default(false),
714
+ ```
715
+
716
+ #### `.description(desc)`
717
+
718
+ ```typescript
719
+ DATABASE_URL: t.string()
720
+ .format('url')
721
+ .description('Primary PostgreSQL connection string')
722
+ .required(),
723
+ ```
724
+
725
+ Generates JSDoc comments in type generation and descriptions in `.env.example`.
726
+
727
+ #### `.transform(fn)`
728
+
729
+ ```typescript
730
+ PORT: t.number()
731
+ .transform(v => Math.floor(v))
732
+ .default(3000),
733
+
734
+ URL: t.string()
735
+ .transform(v => v.replace(/\/$/, ''))
736
+ .required(),
737
+ ```
738
+
739
+ #### `.validate(fn)`
740
+
741
+ ```typescript
742
+ PASSWORD: t.string()
743
+ .minLength(12)
744
+ .validate(v => {
745
+ if (!/[A-Z]/.test(v)) return 'Must contain an uppercase letter';
746
+ if (!/[0-9]/.test(v)) return 'Must contain a number';
747
+ return undefined; // passes validation
748
+ })
749
+ .required(),
750
+ ```
751
+
752
+ #### `.deprecated(msg)`
753
+
754
+ ```typescript
755
+ OLD_API_KEY: t.string()
756
+ .deprecated('Use NEW_API_KEY instead โ€” will be removed in v2.0')
757
+ .optional(),
758
+ ```
759
+
760
+ #### `.secret()`
761
+
762
+ ```typescript
763
+ DATABASE_PASSWORD: t.string().secret().required(),
764
+ ```
765
+
766
+ Secret values are masked in logs, scan results, and CLI output.
767
+
768
+ #### `.alias(name)`
769
+
770
+ ```typescript
771
+ DB_URL: t.string()
772
+ .alias('DATABASE_URL')
773
+ .format('url')
774
+ .required(),
775
+ ```
776
+
777
+ Allows the variable to be referenced by an alternative name.
778
+
779
+ #### `.conditional(config)`
780
+
781
+ ```typescript
782
+ STRIPE_KEY: t.string()
783
+ .conditional({
784
+ check: (env) => env.PAYMENT_PROVIDER === 'stripe',
785
+ then: (schema) => schema.required(),
786
+ otherwise: (schema) => schema.optional(),
787
+ }),
788
+ ```
789
+
790
+ Apply different requirements based on other env values.
791
+
792
+ ---
793
+
794
+ ### Complete Schema Example
795
+
796
+ Here's a comprehensive real-world schema:
797
+
798
+ ```typescript
799
+ import { defineEnv, t } from 'ultraenv';
800
+
801
+ const env = defineEnv({
802
+ // โ”€โ”€ Application โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
803
+ NODE_ENV: t.enum(['development', 'staging', 'production'] as const)
804
+ .description('Application environment')
805
+ .default('development'),
806
+
807
+ APP_NAME: t.string()
808
+ .minLength(1)
809
+ .maxLength(100)
810
+ .description('Application name')
811
+ .required(),
812
+
813
+ APP_URL: t.url()
814
+ .description('Canonical application URL')
815
+ .required(),
816
+
817
+ // โ”€โ”€ Server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
818
+ PORT: t.number()
819
+ .port()
820
+ .description('Server listening port')
821
+ .default(3000),
822
+
823
+ HOST: t.string()
824
+ .hostname()
825
+ .description('Server bind address')
826
+ .default('localhost'),
827
+
828
+ // โ”€โ”€ Database โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
829
+ DATABASE_URL: t.string()
830
+ .format('url')
831
+ .description('PostgreSQL connection string')
832
+ .secret()
833
+ .required(),
834
+
835
+ DATABASE_POOL_SIZE: t.number()
836
+ .integer()
837
+ .min(1)
838
+ .max(100)
839
+ .default(10),
840
+
841
+ // โ”€โ”€ Authentication โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
842
+ JWT_SECRET: t.string()
843
+ .minLength(32)
844
+ .description('JWT signing secret')
845
+ .secret()
846
+ .required(),
847
+
848
+ JWT_EXPIRY: t.duration()
849
+ .description('JWT token expiry duration')
850
+ .default('15m'),
851
+
852
+ REFRESH_TOKEN_EXPIRY: t.duration()
853
+ .description('Refresh token expiry duration')
854
+ .default('7d'),
855
+
856
+ // โ”€โ”€ Redis โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
857
+ REDIS_URL: t.string()
858
+ .format('url')
859
+ .optional()
860
+ .description('Redis connection URL'),
861
+
862
+ REDIS_TTL: t.duration()
863
+ .default('1h')
864
+ .description('Default Redis key TTL'),
865
+
866
+ // โ”€โ”€ Email โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
867
+ SMTP_HOST: t.string()
868
+ .hostname()
869
+ .optional(),
870
+
871
+ SMTP_PORT: t.number()
872
+ .port()
873
+ .default(587),
874
+
875
+ SMTP_USER: t.email()
876
+ .optional(),
877
+
878
+ SMTP_PASSWORD: t.string()
879
+ .secret()
880
+ .optional(),
881
+
882
+ // โ”€โ”€ File Uploads โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
883
+ MAX_UPLOAD_SIZE: t.bytes()
884
+ .default('10MB')
885
+ .description('Maximum file upload size'),
886
+
887
+ UPLOAD_DIR: t.path({ mustExist: false })
888
+ .default('./uploads'),
889
+
890
+ // โ”€โ”€ External APIs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
891
+ STRIPE_SECRET_KEY: t.string()
892
+ .secret()
893
+ .optional()
894
+ .deprecated('Use STRIPE_API_KEY instead'),
895
+
896
+ STRIPE_API_KEY: t.string()
897
+ .secret()
898
+ .optional(),
899
+
900
+ STRIPE_WEBHOOK_SECRET: t.string()
901
+ .secret()
902
+ .optional(),
903
+
904
+ // โ”€โ”€ Internationalization โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
905
+ DEFAULT_LOCALE: t.locale()
906
+ .default('en-US'),
907
+
908
+ DEFAULT_TIMEZONE: t.timezone()
909
+ .default('UTC'),
910
+
911
+ // โ”€โ”€ Feature Flags โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
912
+ ENABLE_ANALYTICS: t.boolean()
913
+ .default(false),
914
+
915
+ ENABLE_RATE_LIMITING: t.boolean()
916
+ .default(true),
917
+
918
+ RATE_LIMIT_MAX: t.number()
919
+ .positive()
920
+ .default(100),
921
+
922
+ // โ”€โ”€ Logging โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
923
+ LOG_LEVEL: t.enum(['debug', 'info', 'warn', 'error', 'fatal'] as const)
924
+ .default('info'),
925
+
926
+ LOG_FORMAT: t.enum(['json', 'text', 'pretty'] as const)
927
+ .default('json'),
928
+
929
+ // โ”€โ”€ CORS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
930
+ ALLOWED_ORIGINS: t.array()
931
+ .separator(';')
932
+ .trimItems()
933
+ .default(['http://localhost:3000']),
934
+
935
+ // โ”€โ”€ Health & Monitoring โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
936
+ HEALTH_CHECK_PATH: t.string()
937
+ .default('/health'),
938
+
939
+ SENTRY_DSN: t.url({ allowRelative: false })
940
+ .optional(),
941
+
942
+ // โ”€โ”€ Cron Jobs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
943
+ CLEANUP_CRON: t.cron()
944
+ .default('0 3 * * *')
945
+ .description('Daily cleanup schedule (3 AM)'),
946
+ });
947
+
948
+ export default env;
949
+
950
+ // All values are fully typed:
951
+ // env.DATABASE_URL โ†’ string
952
+ // env.PORT โ†’ number
953
+ // env.NODE_ENV โ†’ 'development' | 'staging' | 'production'
954
+ // env.MAX_UPLOAD_SIZE โ†’ string
955
+ // env.JWT_EXPIRY โ†’ string
956
+ // env.ALLOWED_ORIGINS โ†’ readonly string[]
957
+ // env.STRIPE_API_KEY โ†’ string | undefined
958
+ ```
959
+
960
+ ---
961
+
962
+ ## ๐Ÿ” Encryption & Vault
963
+
964
+ ultraenv includes a built-in encrypted vault for securely managing secrets across environments.
965
+
966
+ ### Quick Setup
967
+
968
+ ```bash
969
+ # 1. Initialize the vault
970
+ ultraenv vault init --env production
971
+
972
+ # 2. Encrypt your environment
973
+ ultraenv vault encrypt --env production
974
+
975
+ # 3. Commit the vault (safe โ€” it's encrypted!)
976
+ git add .env.vault
977
+ git commit -m "Add encrypted production vault"
978
+
979
+ # 4. Team members decrypt with the key
980
+ ultraenv vault decrypt --env production
981
+ ```
982
+
983
+ ### Programmatic API
984
+
985
+ ```typescript
986
+ import {
987
+ encryptValue,
988
+ decryptValue,
989
+ isEncryptedValue,
990
+ generateMasterKey,
991
+ formatKey,
992
+ } from 'ultraenv';
993
+
994
+ // Generate a new master key
995
+ const key = generateMasterKey(); // Buffer (32 bytes)
996
+ const keyFormatted = formatKey(key); // "ultraenv_key_v1_..."
997
+
998
+ // Encrypt a single value
999
+ const encrypted = await encryptValue(
1000
+ 'my-super-secret-password',
1001
+ key,
1002
+ );
1003
+ // โ†’ "encrypted:v1:aes-256-gcm:...base64..."
1004
+
1005
+ // Check if a value is encrypted
1006
+ isEncryptedValue(encrypted); // true
1007
+
1008
+ // Decrypt
1009
+ const decrypted = await decryptValue(encrypted, key);
1010
+ // โ†’ "my-super-secret-password"
1011
+ ```
1012
+
1013
+ ### Vault Workflow
1014
+
1015
+ ```bash
1016
+ # Full workflow
1017
+ ultraenv vault init --env development
1018
+ ultraenv vault init --env staging
1019
+ ultraenv vault init --env production
1020
+
1021
+ ultraenv vault encrypt --env production
1022
+
1023
+ # Check status
1024
+ ultraenv vault status
1025
+
1026
+ # Compare local vs vault
1027
+ ultraenv vault diff
1028
+
1029
+ # Verify integrity
1030
+ ultraenv vault verify
1031
+
1032
+ # Rotate keys (re-encrypt with new key)
1033
+ ultraenv vault rekey --env production
1034
+ ```
1035
+
1036
+ ### Vault Files
1037
+
1038
+ | File | Description | Git |
1039
+ |---|---|---|
1040
+ | `.env.vault` | Encrypted secrets (safe to commit) | โœ… Commit |
1041
+ | `.env.keys` | Decryption keys (NEVER commit) | โŒ Gitignore |
1042
+
1043
+ ### Encryption Details
1044
+
1045
+ - **Algorithm**: AES-256-GCM (authenticated encryption)
1046
+ - **Key derivation**: HKDF with random salt
1047
+ - **IV**: 12-byte random nonce per value
1048
+ - **Auth tag**: 16-byte GCM authentication tag
1049
+ - **Key format**: `ultraenv_key_v1_<base64>` (32-byte / 256-bit key)
1050
+
1051
+ > ๐Ÿ“– See [docs/VAULT_GUIDE.md](docs/VAULT_GUIDE.md) for the complete vault documentation.
1052
+
1053
+ ---
1054
+
1055
+ ## ๐Ÿ” Secret Scanning
1056
+
1057
+ ultraenv includes a powerful secret scanner that detects **55+ patterns** for leaked credentials, API keys, tokens, and secrets in your codebase.
1058
+
1059
+ ### Quick Scan
1060
+
1061
+ ```bash
1062
+ # Scan current directory
1063
+ ultraenv scan
1064
+
1065
+ # Scan specific paths
1066
+ ultraenv scan src/ config/
1067
+
1068
+ # Scan git history (thorough)
1069
+ ultraenv scan --scope git-history
1070
+
1071
+ # Scan staged files (pre-commit)
1072
+ ultraenv scan --scope staged
1073
+
1074
+ # Scan diff against main
1075
+ ultraenv scan --scope diff --from main
1076
+
1077
+ # Scan everything
1078
+ ultraenv scan --scope all
1079
+ ```
1080
+
1081
+ ### Output Formats
1082
+
1083
+ ```bash
1084
+ # Terminal (default โ€” human-readable)
1085
+ ultraenv scan --format terminal
1086
+
1087
+ # JSON (for integrations)
1088
+ ultraenv scan --format json
1089
+
1090
+ # SARIF (for GitHub Code Scanning)
1091
+ ultraenv scan --format sarif --output results.sarif
1092
+ ```
1093
+
1094
+ ### Detected Secret Categories
1095
+
1096
+ | Category | Patterns | Examples |
1097
+ |---|---|---|
1098
+ | **AWS** | 4 | Access Key ID, Secret Key, Session Token, Account ID |
1099
+ | **GitHub** | 6 | PAT, OAuth Token, App Token, Refresh Token, Webhook Secret |
1100
+ | **Google** | 5 | API Key, OAuth Client ID/Secret, Firebase Key, Service Account |
1101
+ | **Stripe** | 3 | Secret Key, Publishable Key, Restricted Key |
1102
+ | **Slack** | 4 | Bot Token, User Token, App Token, Webhook URL |
1103
+ | **Private Keys** | 8 | RSA, EC, DSA, OpenSSH, PGP, PKCS#8, Encrypted, Certificate |
1104
+ | **Database** | 5 | MongoDB, PostgreSQL, MySQL, Redis, CouchDB URLs |
1105
+ | **Cloud** | 4 | Azure, DigitalOcean, Heroku, Cloudflare |
1106
+ | **Auth** | 4 | JWT, Base64 Creds, Auth0, Generic Secret |
1107
+ | **Messaging** | 2 | Telegram Bot, Discord Bot |
1108
+ | **Email** | 2 | SendGrid, Mailgun |
1109
+ | **DevOps** | 2 | PagerDuty, Datadog |
1110
+ | **Generic** | 5+ | API Key, Token, Password, High-Entropy Strings |
1111
+ | **.env** | 1 | Secret-like variable patterns |
1112
+
1113
+ ### Programmatic API
1114
+
1115
+ ```typescript
1116
+ import { scan, formatScanResult, addCustomPattern } from 'ultraenv';
1117
+
1118
+ // Add a custom pattern
1119
+ addCustomPattern({
1120
+ id: 'my-company-api-key',
1121
+ name: 'My Company API Key',
1122
+ pattern: /MCKEY_[A-Za-z0-9]{32}/g,
1123
+ confidence: 0.9,
1124
+ severity: 'critical',
1125
+ description: 'Company-specific API key',
1126
+ remediation: 'Rotate the key and store in a vault.',
1127
+ category: 'internal',
1128
+ });
1129
+
1130
+ // Run a scan
1131
+ const result = await scan({
1132
+ cwd: '/path/to/project',
1133
+ include: ['src/', 'config/'],
1134
+ exclude: ['**/*.test.ts', '**/node_modules/**'],
1135
+ scanGitHistory: false,
1136
+ });
1137
+
1138
+ if (result.found) {
1139
+ console.log(`Found ${result.secrets.length} potential secrets!`);
1140
+ for (const secret of result.secrets) {
1141
+ console.log(` ${secret.type} in ${secret.file}:${secret.line}`);
1142
+ console.log(` Confidence: ${(secret.confidence * 100).toFixed(0)}%`);
1143
+ console.log(` Remediation: ${secret.pattern.remediation}`);
1144
+ }
1145
+ }
1146
+ ```
1147
+
1148
+ ### Git Hook Integration
1149
+
1150
+ ```bash
1151
+ # Install pre-commit hook
1152
+ ultraenv install-hook
1153
+
1154
+ # This runs `ultraenv scan --scope staged` before every commit
1155
+ # Commits with detected secrets will be blocked
1156
+ ```
1157
+
1158
+ > ๐Ÿ“– See [docs/SECRET_SCANNING.md](docs/SECRET_SCANNING.md) for the complete scanning documentation.
1159
+
1160
+ ---
1161
+
1162
+ ## ๐Ÿ“ TypeScript Type Generation
1163
+
1164
+ ultraenv can automatically generate TypeScript type definitions from your schema.
1165
+
1166
+ ### Declaration File (`.d.ts`)
1167
+
1168
+ ```bash
1169
+ ultraenv typegen --format declaration --out src/env.d.ts
1170
+ ```
1171
+
1172
+ Generates:
1173
+
1174
+ ```typescript
1175
+ // Auto-generated by ultraenv โ€” DO NOT EDIT
1176
+ declare namespace NodeJS {
1177
+ interface ProcessEnv {
1178
+ /** Application environment */
1179
+ NODE_ENV: 'development' | 'staging' | 'production';
1180
+
1181
+ /** Primary PostgreSQL connection string */
1182
+ DATABASE_URL: string;
1183
+
1184
+ /** Server listening port */
1185
+ PORT: number;
1186
+
1187
+ /** Application URL */
1188
+ APP_URL: string;
1189
+
1190
+ /** JWT signing secret */
1191
+ JWT_SECRET: string;
1192
+
1193
+ /** Optional admin email */
1194
+ ADMIN_EMAIL?: string;
1195
+
1196
+ // ... all your env vars with types and JSDoc
1197
+ }
1198
+ }
1199
+ ```
1200
+
1201
+ ### TypeScript Module
1202
+
1203
+ ```bash
1204
+ ultraenv typegen --format module --out src/env.ts
1205
+ ```
1206
+
1207
+ Generates a typed module with runtime values:
1208
+
1209
+ ```typescript
1210
+ // Auto-generated by ultraenv โ€” DO NOT EDIT
1211
+ export interface Env {
1212
+ /** Application environment */
1213
+ readonly NODE_ENV: 'development' | 'staging' | 'production';
1214
+ /** Primary PostgreSQL connection string */
1215
+ readonly DATABASE_URL: string;
1216
+ // ...
1217
+ }
1218
+
1219
+ export const env: Env = {
1220
+ NODE_ENV: process.env.NODE_ENV as Env['NODE_ENV'],
1221
+ DATABASE_URL: process.env.DATABASE_URL as string,
1222
+ // ...
1223
+ };
1224
+
1225
+ export default env;
1226
+ ```
1227
+
1228
+ ### JSON Schema
1229
+
1230
+ ```bash
1231
+ ultraenv typegen --format json-schema --out env.schema.json
1232
+ ```
1233
+
1234
+ Generates a standard JSON Schema for tool integrations.
1235
+
1236
+ ### Watch Mode
1237
+
1238
+ ```bash
1239
+ ultraenv typegen --format declaration --out src/env.d.ts --watch
1240
+ ```
1241
+
1242
+ Automatically regenerates types when your `.env` or config changes.
1243
+
1244
+ ### Programmatic API
1245
+
1246
+ ```typescript
1247
+ import {
1248
+ generateDeclaration,
1249
+ generateModule,
1250
+ generateJsonSchema,
1251
+ } from 'ultraenv';
1252
+
1253
+ // Generate declaration content
1254
+ const dts = generateDeclaration(envVars, schema, {
1255
+ interfaceName: 'Env',
1256
+ jsdoc: true,
1257
+ indent: 4,
1258
+ });
1259
+
1260
+ // Generate module content
1261
+ const moduleContent = generateModule(schema, {
1262
+ interfaceName: 'Env',
1263
+ jsdoc: true,
1264
+ indent: 2,
1265
+ });
1266
+
1267
+ // Generate JSON Schema
1268
+ const jsonSchema = generateJsonSchema(schema, {
1269
+ includeDescriptions: true,
1270
+ indent: 2,
1271
+ });
1272
+ ```
1273
+
1274
+ > ๐Ÿ“– See [docs/TYPE_GENERATION.md](docs/TYPE_GENERATION.md) for the complete type generation documentation.
1275
+
1276
+ ---
1277
+
1278
+ ## ๐Ÿ”„ .env.example Sync
1279
+
1280
+ Never let your `.env.example` drift out of sync with your `.env` file again.
1281
+
1282
+ ### Check Sync
1283
+
1284
+ ```bash
1285
+ ultraenv sync --mode check
1286
+ ```
1287
+
1288
+ Output:
1289
+
1290
+ ```
1291
+ ๐Ÿ”„ .env Sync Check
1292
+
1293
+ โœ… 12 variables match
1294
+ โš ๏ธ 2 variables missing from .env.example:
1295
+ - STRIPE_API_KEY
1296
+ - REDIS_URL
1297
+ โ„น๏ธ 1 variable in .env.example but not in .env:
1298
+ - OLD_FEATURE_FLAG
1299
+
1300
+ ACTION NEEDED
1301
+ Your .env is out of sync with .env.example.
1302
+ Run "ultraenv sync --mode generate" to update .env.example
1303
+ ```
1304
+
1305
+ ### Generate
1306
+
1307
+ ```bash
1308
+ ultraenv sync --mode generate
1309
+ ```
1310
+
1311
+ Auto-generates `.env.example` with types, defaults, and descriptions.
1312
+
1313
+ ### Interactive Mode
1314
+
1315
+ ```bash
1316
+ ultraenv sync --mode interactive
1317
+ ```
1318
+
1319
+ Shows differences and lets you review before updating.
1320
+
1321
+ ### Watch Mode
1322
+
1323
+ ```bash
1324
+ ultraenv sync --mode watch
1325
+ ```
1326
+
1327
+ Watches `.env` for changes and auto-updates `.env.example`.
1328
+
1329
+ ---
1330
+
1331
+ ## ๐ŸŒ Multi-Environment Management
1332
+
1333
+ ultraenv supports **11 `.env` file variants** with proper priority cascading.
1334
+
1335
+ ### Supported Files (Lowest โ†’ Highest Priority)
1336
+
1337
+ | File | Use Case |
1338
+ |---|---|
1339
+ | `.env` | Default, shared across all environments |
1340
+ | `.env.local` | Local overrides (gitignored) |
1341
+ | `.env.development` | Development-specific |
1342
+ | `.env.development.local` | Local dev overrides (gitignored) |
1343
+ | `.env.test` | Test-specific |
1344
+ | `.env.test.local` | Local test overrides (gitignored) |
1345
+ | `.env.production` | Production-specific |
1346
+ | `.env.production.local` | Local prod overrides (gitignored) |
1347
+ | `.env.staging` | Staging-specific |
1348
+ | `.env.staging.local` | Local staging overrides (gitignored) |
1349
+ | `.env.ci` | CI/CD-specific |
1350
+
1351
+ ### Cascade Order
1352
+
1353
+ Variables are merged in priority order โ€” **higher-priority files override lower**:
1354
+
1355
+ ```
1356
+ .env โ†’ .env.local โ†’ .env.development โ†’ .env.development.local โ†’ .env.production โ†’ ...
1357
+ ```
1358
+
1359
+ ### CLI Commands
1360
+
1361
+ ```bash
1362
+ # List all environments
1363
+ ultraenv envs list
1364
+
1365
+ # Compare two environments
1366
+ ultraenv envs compare development production
1367
+
1368
+ # Validate all environments
1369
+ ultraenv envs validate
1370
+
1371
+ # Create a new environment
1372
+ ultraenv envs create staging
1373
+
1374
+ # Switch active environment
1375
+ ultraenv envs switch production
1376
+ ```
1377
+
1378
+ ---
1379
+
1380
+ ## ๐Ÿงฉ Framework Presets
1381
+
1382
+ ultraenv ships with **9 built-in framework presets** that provide ready-made schemas, file loading order, and framework-specific validation.
1383
+
1384
+ ### Available Presets
1385
+
1386
+ | Preset | ID | Tags |
1387
+ |---|---|---|
1388
+ | **Next.js** | `nextjs` | `framework`, `react`, `ssr`, `fullstack` |
1389
+ | **Vite** | `vite` | `framework`, `build-tool` |
1390
+ | **Nuxt** | `nuxt` | `framework`, `vue`, `ssr` |
1391
+ | **Remix** | `remix` | `framework`, `react`, `ssr` |
1392
+ | **SvelteKit** | `sveltekit` | `framework`, `svelte`, `ssr` |
1393
+ | **Express** | `express` | `backend`, `server` |
1394
+ | **Fastify** | `fastify` | `backend`, `server` |
1395
+ | **Docker** | `docker` | `container`, `devops` |
1396
+ | **AWS Lambda** | `aws-lambda` | `serverless`, `cloud` |
1397
+
1398
+ ### Using Presets
1399
+
1400
+ ```typescript
1401
+ import { defineEnv, t, getPreset } from 'ultraenv';
1402
+
1403
+ // Get the Next.js preset schema
1404
+ const nextjsPreset = getPreset('nextjs');
1405
+
1406
+ // Use it directly
1407
+ const env = defineEnv(nextjsPreset.schema);
1408
+
1409
+ // Or extend it with your own variables
1410
+ const env = defineEnv({
1411
+ ...nextjsPreset.schema,
1412
+
1413
+ // Your custom variables
1414
+ CUSTOM_FEATURE: t.boolean().default(false),
1415
+ ANALYTICS_KEY: t.string().secret().optional(),
1416
+ });
1417
+ ```
1418
+
1419
+ ### Next.js Preset Features
1420
+
1421
+ The Next.js preset includes:
1422
+
1423
+ - **Client/server variable separation** โ€” warns if secrets are in `NEXT_PUBLIC_*` vars
1424
+ - **Common Next.js variables** โ€” `DATABASE_URL`, `NEXTAUTH_SECRET`, `NEXT_TELEMETRY_DISABLED`, etc.
1425
+ - **Image optimization** โ€” `NEXT_PUBLIC_IMAGE_DOMAINS`, `NEXT_PUBLIC_IMAGE_REMOTE_PATTERNS`
1426
+ - **Proper file loading order** โ€” `.env`, `.env.local`, `.env.development`, `.env.production`
1427
+
1428
+ ### Client Leak Detection
1429
+
1430
+ ```typescript
1431
+ import { detectClientLeakCandidates } from 'ultraenv';
1432
+
1433
+ const warnings = detectClientLeakCandidates(process.env);
1434
+ // โ†’ ['NEXT_PUBLIC_SECRET_KEY: appears to be a secret exposed to the client bundle']
1435
+ ```
1436
+
1437
+ > ๐Ÿ“– See [docs/FRAMEWORK_PRESETS.md](docs/FRAMEWORK_PRESETS.md) for complete preset documentation.
1438
+
1439
+ ---
1440
+
1441
+ ## ๐Ÿ”„ CI/CD Integration
1442
+
1443
+ ### GitHub Actions Setup
1444
+
1445
+ ```bash
1446
+ ultraenv ci setup --platform github
1447
+ ```
1448
+
1449
+ Generates `.github/workflows/ultraenv.yml`:
1450
+
1451
+ ```yaml
1452
+ name: Ultraenv CI
1453
+
1454
+ on:
1455
+ push:
1456
+ branches: [main]
1457
+ pull_request:
1458
+ branches: [main]
1459
+
1460
+ jobs:
1461
+ validate:
1462
+ runs-on: ubuntu-latest
1463
+ steps:
1464
+ - uses: actions/checkout@v4
1465
+
1466
+ - name: Setup Node.js
1467
+ uses: actions/setup-node@v4
1468
+ with:
1469
+ node-version: '20'
1470
+
1471
+ - name: Install ultraenv
1472
+ run: npm install -g ultraenv
1473
+
1474
+ - name: Validate environment
1475
+ run: ultraenv ci validate --strict
1476
+
1477
+ - name: Check .env sync
1478
+ run: ultraenv ci check-sync
1479
+
1480
+ - name: Scan for secrets
1481
+ run: ultraenv ci scan --format sarif --output results.sarif
1482
+ continue-on-error: true
1483
+
1484
+ - name: Upload SARIF results
1485
+ if: always()
1486
+ uses: github/codeql-action/upload-sarif@v3
1487
+ with:
1488
+ sarif_file: results.sarif
1489
+ continue-on-error: true
1490
+ ```
1491
+
1492
+ ### GitLab CI Setup
1493
+
1494
+ ```bash
1495
+ ultraenv ci setup --platform gitlab
1496
+ ```
1497
+
1498
+ ### CI Commands
1499
+
1500
+ ```bash
1501
+ # Validate in strict mode (fails on warnings)
1502
+ ultraenv ci validate --strict
1503
+
1504
+ # Check .env โ†” .env.example sync
1505
+ ultraenv ci check-sync
1506
+
1507
+ # Scan for secrets with SARIF output
1508
+ ultraenv ci scan --format sarif --output results.sarif
1509
+ ```
1510
+
1511
+ ### GitHub Code Scanning Integration
1512
+
1513
+ The SARIF output integrates directly with [GitHub Code Scanning](https://docs.github.com/en/code-security/code-scanning):
1514
+
1515
+ ```yaml
1516
+ - name: Scan for secrets
1517
+ run: ultraenv ci scan --format sarif --output results.sarif
1518
+
1519
+ - name: Upload SARIF results
1520
+ uses: github/codeql-action/upload-sarif@v3
1521
+ with:
1522
+ sarif_file: results.sarif
1523
+ ```
1524
+
1525
+ > ๐Ÿ“– See [docs/CI_CD_INTEGRATION.md](docs/CI_CD_INTEGRATION.md) for the complete CI/CD documentation.
1526
+
1527
+ ---
1528
+
1529
+ ## ๐Ÿ“š Programmatic API Reference
1530
+
1531
+ ### Core Loading
1532
+
1533
+ ```typescript
1534
+ import { load, loadSync, loadWithResult } from 'ultraenv';
1535
+
1536
+ // Simple load (dotenv-compatible)
1537
+ load();
1538
+ // Reads .env, sets process.env
1539
+
1540
+ // With options
1541
+ load({
1542
+ envDir: './config',
1543
+ expandVariables: true,
1544
+ overrideProcessEnv: true,
1545
+ mergeStrategy: 'last-wins',
1546
+ });
1547
+
1548
+ // Full result
1549
+ const result = loadWithResult();
1550
+ result.env // Record<string, string>
1551
+ result.metadata // { totalVars, filesParsed, loadTimeMs, ... }
1552
+ result.parsed // ParsedEnvFile[]
1553
+ ```
1554
+
1555
+ ### Schema Validation
1556
+
1557
+ ```typescript
1558
+ import { defineEnv, tryDefineEnv, validate, t } from 'ultraenv';
1559
+
1560
+ // Strict: throws on validation failure
1561
+ const env = defineEnv({
1562
+ PORT: t.number().port().default(3000),
1563
+ NODE_ENV: t.enum(['development', 'production'] as const).required(),
1564
+ });
1565
+
1566
+ // Non-throwing variant
1567
+ const result = tryDefineEnv({
1568
+ PORT: t.number().port().default(3000),
1569
+ NODE_ENV: t.enum(['development', 'production'] as const).required(),
1570
+ });
1571
+
1572
+ if (result.valid) {
1573
+ console.log(result.values); // typed values
1574
+ } else {
1575
+ console.log(result.errors); // validation errors
1576
+ console.log(result.unknown); // unknown variables
1577
+ }
1578
+ ```
1579
+
1580
+ ### Watching for Changes
1581
+
1582
+ ```typescript
1583
+ import { createWatcher } from 'ultraenv';
1584
+
1585
+ const watcher = createWatcher({
1586
+ files: ['.env', '.env.local'],
1587
+ recursive: false,
1588
+ debounceMs: 100,
1589
+ initial: true,
1590
+ });
1591
+
1592
+ watcher.on('change', (event) => {
1593
+ console.log(`File ${event.path} was ${event.type}`);
1594
+ // Reload your environment here
1595
+ });
1596
+
1597
+ watcher.start();
1598
+
1599
+ // Later...
1600
+ watcher.stop();
1601
+ ```
1602
+
1603
+ ### Health Checks
1604
+
1605
+ ```typescript
1606
+ import {
1607
+ healthCheck,
1608
+ liveCheck,
1609
+ readinessCheck,
1610
+ } from 'ultraenv';
1611
+
1612
+ // Full health check (safe to expose via HTTP)
1613
+ const health = healthCheck();
1614
+ // โ†’ { status: 'ok', loaded: 42, valid: 42, environment: 'production', ... }
1615
+
1616
+ // Liveness probe (minimal)
1617
+ const live = liveCheck();
1618
+ // โ†’ { status: 'ok', timestamp: '...' }
1619
+
1620
+ // Readiness probe (checks specific vars)
1621
+ const ready = readinessCheck(['DATABASE_URL', 'REDIS_URL']);
1622
+ // โ†’ { status: 'ok', ready: true, missing: [], timestamp: '...' }
1623
+ ```
1624
+
1625
+ ### Express Middleware
1626
+
1627
+ ```typescript
1628
+ import express from 'express';
1629
+ import { ultraenvMiddleware, healthCheckRoute } from 'ultraenv';
1630
+
1631
+ const app = express();
1632
+
1633
+ // Load and validate env
1634
+ app.use(ultraenvMiddleware({
1635
+ schema: {
1636
+ PORT: { type: 'number', port: true, default: 3000 },
1637
+ },
1638
+ }));
1639
+
1640
+ // Health check endpoint
1641
+ app.get('/health', healthCheckRoute());
1642
+
1643
+ // readiness endpoint
1644
+ app.get('/ready', readinessCheck(['DATABASE_URL']));
1645
+ ```
1646
+
1647
+ ### Fastify Plugin
1648
+
1649
+ ```typescript
1650
+ import Fastify from 'fastify';
1651
+ import { createUltraenvPlugin } from 'ultraenv/fastify';
1652
+
1653
+ const app = Fastify();
1654
+
1655
+ app.register(createUltraenvPlugin({
1656
+ schema: {
1657
+ DATABASE_URL: { type: 'string', format: 'url' },
1658
+ },
1659
+ }));
1660
+ ```
1661
+
1662
+ ### Error Handling
1663
+
1664
+ ```typescript
1665
+ import {
1666
+ UltraenvError,
1667
+ ValidationError,
1668
+ ParseError,
1669
+ EncryptionError,
1670
+ VaultError,
1671
+ ScanError,
1672
+ ConfigError,
1673
+ isUltraenvError,
1674
+ } from 'ultraenv';
1675
+
1676
+ try {
1677
+ // ... ultraenv operations
1678
+ } catch (error) {
1679
+ if (isUltraenvError(error)) {
1680
+ console.log(error.code); // 'VALIDATION_ERROR'
1681
+ console.log(error.message); // Human-readable message
1682
+ console.log(error.hint); // Actionable fix suggestion
1683
+ }
1684
+ }
1685
+ ```
1686
+
1687
+ ### Vault API
1688
+
1689
+ ```typescript
1690
+ import {
1691
+ encryptEnvironment,
1692
+ decryptEnvironment,
1693
+ encryptValue,
1694
+ decryptValue,
1695
+ isEncryptedValue,
1696
+ generateMasterKey,
1697
+ deriveEnvironmentKey,
1698
+ formatKey,
1699
+ parseKey,
1700
+ generateKeysFile,
1701
+ parseKeysFile,
1702
+ rotateKey,
1703
+ } from 'ultraenv';
1704
+ ```
1705
+
1706
+ ### Scanner API
1707
+
1708
+ ```typescript
1709
+ import {
1710
+ scan,
1711
+ scanFiles,
1712
+ scanGitHistory,
1713
+ scanStagedFiles,
1714
+ scanDiff,
1715
+ matchPatterns,
1716
+ addCustomPattern,
1717
+ removeCustomPattern,
1718
+ resetPatterns,
1719
+ detectHighEntropyStrings,
1720
+ formatScanResult,
1721
+ } from 'ultraenv';
1722
+ ```
1723
+
1724
+ ### Sync API
1725
+
1726
+ ```typescript
1727
+ import {
1728
+ generateExampleFile,
1729
+ generateExampleContent,
1730
+ needsUpdate,
1731
+ compareSync,
1732
+ compareValues,
1733
+ createSyncWatcher,
1734
+ } from 'ultraenv';
1735
+ ```
1736
+
1737
+ ### Type Generation API
1738
+
1739
+ ```typescript
1740
+ import {
1741
+ generateDeclaration,
1742
+ generateModule,
1743
+ generateJsonSchema,
1744
+ createTypegenWatcher,
1745
+ } from 'ultraenv';
1746
+ ```
1747
+
1748
+ ### Environment Management API
1749
+
1750
+ ```typescript
1751
+ import {
1752
+ listEnvironments,
1753
+ validateAllEnvironments,
1754
+ switchEnvironment,
1755
+ getActiveEnvironment,
1756
+ discoverEnvironments,
1757
+ compareEnvironments,
1758
+ formatComparison,
1759
+ createEnvironment,
1760
+ removeEnvironment,
1761
+ duplicateEnvironment,
1762
+ } from 'ultraenv';
1763
+ ```
1764
+
1765
+ ### Parser API (Advanced)
1766
+
1767
+ ```typescript
1768
+ import {
1769
+ parseEnvFile,
1770
+ expandVariables,
1771
+ resolveCascade,
1772
+ mergeCascade,
1773
+ } from 'ultraenv';
1774
+
1775
+ // Parse raw .env content
1776
+ const parsed = parseEnvFile(content, filePath);
1777
+ // โ†’ { path, vars: [{ key, value, raw, source, lineNumber, comment }], exists }
1778
+
1779
+ // Expand variable references
1780
+ const expanded = expandVariables(env, env, { maxDepth: 10 });
1781
+ ```
1782
+
1783
+ > ๐Ÿ“– See [docs/API_REFERENCE.md](docs/API_REFERENCE.md) for the complete API documentation.
1784
+
1785
+ ---
1786
+
1787
+ ## ๐Ÿ”€ Migration from dotenv
1788
+
1789
+ ultraenv is a **drop-in replacement** for dotenv. Migration takes just minutes.
1790
+
1791
+ ### Before (dotenv)
1792
+
1793
+ ```typescript
1794
+ // Load .env
1795
+ import dotenv from 'dotenv';
1796
+ dotenv.config();
1797
+
1798
+ // Use env vars (always strings!)
1799
+ const port = parseInt(process.env.PORT || '3000', 10);
1800
+ const dbUrl = process.env.DATABASE_URL!;
1801
+ const debug = process.env.DEBUG === 'true';
1802
+ ```
1803
+
1804
+ ### After (ultraenv)
1805
+
1806
+ ```typescript
1807
+ // Option 1: Simple drop-in replacement
1808
+ import { load } from 'ultraenv';
1809
+ load(); // That's it!
1810
+
1811
+ // Option 2: Full type safety
1812
+ import { defineEnv, t } from 'ultraenv';
1813
+
1814
+ const env = defineEnv({
1815
+ PORT: t.number().port().default(3000),
1816
+ DATABASE_URL: t.string().format('url').required(),
1817
+ DEBUG: t.boolean().default(false),
1818
+ });
1819
+
1820
+ // Now everything is typed!
1821
+ const port = env.PORT; // number
1822
+ const dbUrl = env.DATABASE_URL; // string
1823
+ const debug = env.DEBUG; // boolean
1824
+ ```
1825
+
1826
+ ### Migration Checklist
1827
+
1828
+ - [ ] Replace `import dotenv from 'dotenv'` with `import { load } from 'ultraenv'`
1829
+ - [ ] Replace `dotenv.config()` with `load()`
1830
+ - [ ] (Optional) Add a schema with `defineEnv()` for type safety
1831
+ - [ ] (Optional) Replace all `process.env.X` references with typed `env.X`
1832
+ - [ ] (Optional) Run `ultraenv scan` to find leaked secrets
1833
+ - [ ] (Optional) Run `ultraenv sync` to generate `.env.example`
1834
+ - [ ] (Optional) Set up `ultraenv ci setup` for CI/CD
1835
+
1836
+ > ๐Ÿ“– See [docs/MIGRATION_FROM_DOTENV.md](docs/MIGRATION_FROM_DOTENV.md) for the complete migration guide.
1837
+
1838
+ ---
1839
+
1840
+ ## โš™๏ธ Configuration Reference
1841
+
1842
+ ### Config File Locations (searched in order)
1843
+
1844
+ 1. `.ultraenvrc.json`
1845
+ 2. `.ultraenvrc.yaml`
1846
+ 3. `.ultraenvrc.yml`
1847
+ 4. `ultraenv.config.js`
1848
+ 5. `ultraenv.config.cjs`
1849
+ 6. `"ultraenv"` key in `package.json`
1850
+
1851
+ ### Example Configuration
1852
+
1853
+ ```json
1854
+ {
1855
+ "envDir": ".",
1856
+ "files": [".env", ".env.local", ".env.production"],
1857
+ "encoding": "utf-8",
1858
+ "expandVariables": true,
1859
+ "overrideProcessEnv": false,
1860
+ "mergeStrategy": "last-wins",
1861
+ "prefixErrors": true,
1862
+ "silent": false,
1863
+ "outputFormat": "terminal",
1864
+ "debug": false,
1865
+ "maxValueLength": 1048576,
1866
+ "maxInterpolationDepth": 10,
1867
+ "schema": {
1868
+ "PORT": { "type": "number", "port": true, "default": 3000 },
1869
+ "DATABASE_URL": { "type": "string", "format": "url" }
1870
+ },
1871
+ "vault": {
1872
+ "vaultFile": ".env.vault",
1873
+ "keysFile": ".env.keys",
1874
+ "environment": "production",
1875
+ "autoGenerateKey": true
1876
+ },
1877
+ "scan": {
1878
+ "include": ["src/", "config/"],
1879
+ "exclude": ["**/*.test.ts", "node_modules/**"],
1880
+ "scanGitHistory": false,
1881
+ "maxFileSize": 1048576,
1882
+ "failFast": false
1883
+ }
1884
+ }
1885
+ ```
1886
+
1887
+ ### Configuration Options
1888
+
1889
+ | Option | Type | Default | Description |
1890
+ |---|---|---|---|
1891
+ | `envDir` | `string` | `'.'` | Directory containing `.env` files |
1892
+ | `files` | `string[]` | `[]` | Specific `.env` files to load |
1893
+ | `encoding` | `string` | `'utf-8'` | File encoding |
1894
+ | `expandVariables` | `boolean` | `true` | Expand `$VAR` references |
1895
+ | `overrideProcessEnv` | `boolean` | `false` | Override existing `process.env` values |
1896
+ | `mergeStrategy` | `string` | `'last-wins'` | Merge strategy: `first-wins`, `last-wins`, `error-on-conflict` |
1897
+ | `prefixErrors` | `boolean` | `true` | Prefix error messages with "ultraenv" |
1898
+ | `silent` | `boolean` | `false` | Suppress all output |
1899
+ | `outputFormat` | `string` | `'terminal'` | Output format: `terminal`, `json`, `silent` |
1900
+ | `debug` | `boolean` | `false` | Enable debug logging |
1901
+ | `maxValueLength` | `number` | `1048576` | Max value length in bytes (1 MB) |
1902
+ | `maxInterpolationDepth` | `number` | `10` | Max variable expansion depth |
1903
+
1904
+ ---
1905
+
1906
+ ## โ“ FAQ
1907
+
1908
+ ### General
1909
+
1910
+ **Q: Is ultraenv really zero dependencies?**
1911
+
1912
+ A: Yes! ultraenv has zero runtime dependencies. The entire library (parser, validator, scanner, vault, CLI, typegen) is built with Node.js built-in modules only. Dev dependencies (TypeScript, Vitest, ESLint, tsup) are only used during development.
1913
+
1914
+ **Q: Does it work with ESM and CommonJS?**
1915
+
1916
+ A: Yes! ultraenv ships dual CJS/ESM builds:
1917
+ - `import { load } from 'ultraenv'` (ESM)
1918
+ - `const { load } = require('ultraenv')` (CJS)
1919
+
1920
+ **Q: What Node.js versions are supported?**
1921
+
1922
+ A: Node.js >= 18.0.0. This aligns with the current Node.js LTS cycle.
1923
+
1924
+ ### Schema & Validation
1925
+
1926
+ **Q: Can I use zod schemas with ultraenv?**
1927
+
1928
+ A: ultraenv has its own schema engine that's purpose-built for env vars. It's lighter and has env-specific validators (port, URL, duration, bytes, etc.) that zod doesn't provide out of the box. However, you can convert between them if needed.
1929
+
1930
+ **Q: What happens when validation fails?**
1931
+
1932
+ A: `defineEnv()` throws a detailed error with all validation failures. Use `tryDefineEnv()` for a non-throwing variant that returns `{ valid, errors, warnings, values }`.
1933
+
1934
+ **Q: Can I validate without throwing?**
1935
+
1936
+ A: Yes! Use `tryDefineEnv()`:
1937
+
1938
+ ```typescript
1939
+ const result = tryDefineEnv(schema);
1940
+ if (!result.valid) {
1941
+ console.log(result.errors);
1942
+ }
1943
+ ```
1944
+
1945
+ **Q: How do default values work?**
1946
+
1947
+ A: If a variable is not set in the environment, the default value is used. If no default is set and the variable is not optional, validation fails.
1948
+
1949
+ ### Vault & Security
1950
+
1951
+ **Q: Is the vault safe to commit to git?**
1952
+
1953
+ A: Yes! The `.env.vault` file contains only AES-256-GCM encrypted data. Without the decryption key (stored in `.env.keys`, which is gitignored), the vault contents are unreadable.
1954
+
1955
+ **Q: What if I lose my encryption key?**
1956
+
1957
+ A: You cannot recover encrypted values without the key. This is by design. Use `ultraenv vault rekey` to rotate keys, and always store keys in a secure secrets manager (e.g., GitHub Secrets, AWS Secrets Manager, HashiCorp Vault).
1958
+
1959
+ **Q: How does key rotation work?**
1960
+
1961
+ A: `ultraenv vault rekey` generates a new key and re-encrypts all values in the vault. Update your `.env.keys` file and CI secrets with the new key.
1962
+
1963
+ ### Secret Scanning
1964
+
1965
+ **Q: How accurate is the secret scanner?**
1966
+
1967
+ A: The scanner uses a combination of regex pattern matching (55+ patterns) and Shannon entropy analysis. Each pattern has a confidence score. High-confidence patterns (>0.9) are very accurate; lower-confidence patterns may have false positives.
1968
+
1969
+ **Q: Can I add custom patterns?**
1970
+
1971
+ A: Yes! Use `addCustomPattern()`:
1972
+
1973
+ ```typescript
1974
+ import { addCustomPattern } from 'ultraenv';
1975
+ addCustomPattern({
1976
+ id: 'my-company-token',
1977
+ name: 'My Company Token',
1978
+ pattern: /MYCO_[A-Za-z0-9]{32}/g,
1979
+ confidence: 0.9,
1980
+ severity: 'critical',
1981
+ description: 'Company internal API token',
1982
+ remediation: 'Rotate and store in vault.',
1983
+ category: 'internal',
1984
+ });
1985
+ ```
1986
+
1987
+ **Q: Can I suppress false positives?**
1988
+
1989
+ A: Add a comment `// ultraenv-ignore` or `# ultraenv-ignore` on the line before or on the same line as the detected secret.
1990
+
1991
+ ### CI/CD
1992
+
1993
+ **Q: How do I use ultraenv in CI?**
1994
+
1995
+ A: Run `ultraenv ci setup --platform github` or `--platform gitlab` to generate CI config files. Or manually add the CI commands to your pipeline.
1996
+
1997
+ **Q: Does ultraenv scan integrate with GitHub Code Scanning?**
1998
+
1999
+ A: Yes! Use `ultraenv scan --format sarif --output results.sarif` and upload with the `github/codeql-action/upload-sarif` action.
2000
+
2001
+ ---
2002
+
2003
+ ## ๐Ÿค Contributing
2004
+
2005
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
2006
+
2007
+ ### Quick Start
2008
+
2009
+ 1. Fork the repository
2010
+ 2. Clone your fork: `git clone https://github.com/your-username/ultraenv.git`
2011
+ 3. Install dependencies: `npm install`
2012
+ 4. Build: `npm run build`
2013
+ 5. Run tests: `npm test`
2014
+ 6. Run linter: `npm run lint`
2015
+
2016
+ ### Development Scripts
2017
+
2018
+ | Script | Description |
2019
+ |---|---|
2020
+ | `npm run build` | Build the library |
2021
+ | `npm run dev` | Build in watch mode |
2022
+ | `npm test` | Run tests |
2023
+ | `npm run test:watch` | Run tests in watch mode |
2024
+ | `npm run test:coverage` | Run tests with coverage |
2025
+ | `npm run lint` | Run ESLint |
2026
+ | `npm run lint:fix` | Fix ESLint issues |
2027
+ | `npm run format` | Format with Prettier |
2028
+ | `npm run typecheck` | TypeScript type checking |
2029
+
2030
+ ---
2031
+
2032
+ ## ๐Ÿ“œ License
2033
+
2034
+ [MIT](LICENSE) ยฉ 2024 [Avinash Velu](https://github.com/Avinashvelu03)
2035
+
2036
+ ---
2037
+
2038
+ ## ๐Ÿ™ Acknowledgments
2039
+
2040
+ - [dotenv](https://github.com/motdotla/dotenv) โ€” Inspiration for the core `.env` parsing
2041
+ - [envalid](https://github.com/af/envalid) โ€” Inspiration for schema-based validation
2042
+ - [@t3-oss/env](https://github.com/t3-oss/env-core) โ€” Inspiration for TypeScript inference
2043
+ - [gitleaks](https://github.com/gitleaks/gitleaks) โ€” Inspiration for secret scanning patterns
2044
+ - [trufflehog](https://github.com/trufflesecurity/trufflehog) โ€” Inspiration for secret detection
2045
+
2046
+ ---
2047
+
2048
+ ## โญ Star History
2049
+
2050
+ If you find ultraenv useful, please consider giving it a star on [GitHub](https://github.com/Avinashvelu03/ultraenv). It helps the project grow and reach more developers!
2051
+
2052
+ <div align="center">
2053
+
2054
+ **Made with โค๏ธ by [Avinash Velu](https://github.com/Avinashvelu03)**
2055
+
2056
+ [Report Bug](https://github.com/Avinashvelu03/ultraenv/issues) ยท [Request Feature](https://github.com/Avinashvelu03/ultraenv/issues) ยท [Discussions](https://github.com/Avinashvelu03/ultraenv/discussions)
2057
+
2058
+ </div>