ultraenv 1.0.1 → 1.0.2

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 (71) hide show
  1. package/README.md +67 -1857
  2. package/dist/{chunk-GC7RXHLA.js → chunk-2MBSLURI.js} +16 -17
  3. package/dist/{chunk-IGFVP24Q.js → chunk-3AF476D7.js} +1 -1
  4. package/dist/{chunk-N5PAV4NM.js → chunk-5WUBB633.js} +17 -26
  5. package/dist/{chunk-2USZPWLZ.js → chunk-6NFA23AY.js} +28 -39
  6. package/dist/{chunk-AWN6ADV7.js → chunk-6X3BUE5S.js} +45 -54
  7. package/dist/{chunk-NBOABPHM.js → chunk-72UKVOO5.js} +24 -40
  8. package/dist/{chunk-JB7RKV3C.js → chunk-7AHG2IP4.js} +1 -7
  9. package/dist/{chunk-6KS56D6E.js → chunk-7VJ7LK2M.js} +1 -1
  10. package/dist/{chunk-CIFMBJ4H.js → chunk-BNUHE2ZI.js} +57 -21
  11. package/dist/{chunk-HFXQGJY3.js → chunk-CVJPO3QY.js} +13 -27
  12. package/dist/{chunk-IKPTKALB.js → chunk-F7YSINGU.js} +1 -3
  13. package/dist/{chunk-3VYXPTYV.js → chunk-FSKVYBEP.js} +1 -1
  14. package/dist/{chunk-4XUYMRK5.js → chunk-GJC64ZG7.js} +4 -3
  15. package/dist/{chunk-YMMP4VQL.js → chunk-H3QEGEZ6.js} +1 -1
  16. package/dist/{chunk-CHVO6NWI.js → chunk-LFIKYFPS.js} +2 -2
  17. package/dist/{chunk-3UV2QNJL.js → chunk-LJSCUOD4.js} +19 -21
  18. package/dist/{chunk-YVWLXFUT.js → chunk-LQZK6BBQ.js} +2 -2
  19. package/dist/{chunk-5G2DU52U.js → chunk-N7GOHQBF.js} +7 -1
  20. package/dist/{chunk-MSXMESFP.js → chunk-OBLMAUCF.js} +8 -14
  21. package/dist/{chunk-UEWYFN6A.js → chunk-RJTUAMK3.js} +16 -29
  22. package/dist/{chunk-MNVFG7H4.js → chunk-XPZC32UY.js} +16 -25
  23. package/dist/{chunk-WMHN5RW2.js → chunk-YLGJQOMM.js} +3 -9
  24. package/dist/{ci-check-sync-VBMSVWIV.js → ci-check-sync-UO5PARKO.js} +4 -4
  25. package/dist/{ci-scan-24MT5XGS.js → ci-scan-5D7QBN5X.js} +2 -5
  26. package/dist/{ci-setup-C2NKEFRD.js → ci-setup-J34DS6KD.js} +2 -2
  27. package/dist/{ci-validate-7AW24LSQ.js → ci-validate-LWP5NBDN.js} +4 -4
  28. package/dist/cli/index.cjs +470 -390
  29. package/dist/cli/index.js +130 -55
  30. package/dist/comparator-AIRTWBOL.js +13 -0
  31. package/dist/{config-O5YRQP5Z.js → config-67GDO3CW.js} +3 -3
  32. package/dist/{debug-PTPXAF3K.js → debug-6VCX3QSP.js} +6 -6
  33. package/dist/{declaration-LEME4AFZ.js → declaration-YGOVZOXG.js} +3 -3
  34. package/dist/{doctor-FZAUPKHS.js → doctor-FF7QOTP2.js} +7 -5
  35. package/dist/{envs-compare-5K3HESX5.js → envs-compare-P7GPKGQX.js} +4 -4
  36. package/dist/{envs-create-2XXHXMGA.js → envs-create-ISG4SECU.js} +4 -4
  37. package/dist/{envs-list-NQM5252B.js → envs-list-PUW67HOC.js} +5 -5
  38. package/dist/{envs-switch-6L2AQYID.js → envs-switch-P4YDJ6LG.js} +4 -4
  39. package/dist/{envs-validate-FL73Q76T.js → envs-validate-VNKBKYO3.js} +6 -9
  40. package/dist/{fs-VH7ATUS3.js → fs-7HKOZY5K.js} +2 -2
  41. package/dist/{generator-LFZBMZZS.js → generator-O23ATCIY.js} +4 -4
  42. package/dist/{help-3XJBXEHE.js → help-THFLI6YT.js} +108 -26
  43. package/dist/index.cjs +295 -381
  44. package/dist/index.d.cts +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +81 -100
  47. package/dist/{init-Y7JQ2KYJ.js → init-KBLVTHQW.js} +15 -11
  48. package/dist/{install-hook-SKXIV6NV.js → install-hook-42F22BLY.js} +2 -2
  49. package/dist/{json-schema-I26YNQBH.js → json-schema-YULPWDKA.js} +3 -3
  50. package/dist/{key-manager-O3G55WPU.js → key-manager-WDWPX3IQ.js} +3 -3
  51. package/dist/middleware/express.cjs +1 -3
  52. package/dist/middleware/express.js +1 -1
  53. package/dist/middleware/fastify.cjs +1 -7
  54. package/dist/middleware/fastify.js +1 -1
  55. package/dist/{module-IDIZPP4M.js → module-FGH2V6N2.js} +3 -3
  56. package/dist/{protect-NCWPM6VC.js → protect-A4G7LQFJ.js} +26 -24
  57. package/dist/{scan-TRLY36TT.js → scan-4BXGHR33.js} +1 -1
  58. package/dist/schema/index.cjs +57 -21
  59. package/dist/schema/index.js +1 -1
  60. package/dist/{sync-TMHMTLH2.js → sync-MYLMDDY6.js} +23 -14
  61. package/dist/{typegen-SQOSXBWM.js → typegen-GLBRHWSK.js} +17 -23
  62. package/dist/{validate-IOAM5HWS.js → validate-J73ETKXD.js} +5 -5
  63. package/dist/{vault-decrypt-U6HJZNBV.js → vault-decrypt-V3GY5HES.js} +7 -7
  64. package/dist/{vault-diff-B3ZOQTWI.js → vault-diff-QVE6S6KP.js} +5 -5
  65. package/dist/{vault-encrypt-GUSLCSKS.js → vault-encrypt-WUBY3OVF.js} +7 -7
  66. package/dist/{vault-init-GUBOTOUL.js → vault-init-EWSAED44.js} +5 -5
  67. package/dist/{vault-rekey-DAHT7JCN.js → vault-rekey-VODMGCNA.js} +7 -7
  68. package/dist/{vault-status-GDLRU2OK.js → vault-status-YXDK6O7X.js} +4 -4
  69. package/dist/{vault-verify-CD76FJSF.js → vault-verify-SSXGTVBK.js} +7 -7
  70. package/package.json +1 -1
  71. package/dist/comparator-RDKX3OI7.js +0 -13
package/README.md CHANGED
@@ -103,1953 +103,163 @@ Create an `env.ts` file:
103
103
  import { defineEnv, t } from 'ultraenv';
104
104
 
105
105
  const env = defineEnv({
106
- // Required string with URL validation
107
106
  DATABASE_URL: t.string().format('url').required(),
108
-
109
- // Number with port validation and a default
110
107
  PORT: t.number().port().default(3000),
111
-
112
- // Enum with literal union types
113
108
  NODE_ENV: t.enum(['development', 'staging', 'production'] as const).required(),
114
-
115
- // Boolean with default
116
109
  DEBUG: t.boolean().default(false),
117
-
118
- // Optional email
119
110
  ADMIN_EMAIL: t.email().optional(),
120
-
121
- // Array with custom separator
122
111
  ALLOWED_ORIGINS: t.array().separator(';').default(['http://localhost:3000']),
123
-
124
- // Duration string
125
112
  CACHE_TTL: t.duration().default('1h'),
126
-
127
- // Bytes string
128
113
  MAX_UPLOAD_SIZE: t.bytes().default('10MB'),
129
114
  });
130
115
 
131
116
  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
117
  ```
143
118
 
144
119
  ### Step 3 — Use your typed env everywhere
145
120
 
146
121
  ```typescript
147
- // Any file in your project:
148
122
  import env from './env';
149
123
 
150
- // Fully typed — no more `process.env.PORT as unknown as number`
151
124
  const server = createServer({
152
125
  port: env.PORT, // number
153
126
  host: env.HOST, // string
154
- databaseUrl: env.DATABASE_URL, // string (URL-validated)
127
+ databaseUrl: env.DATABASE_URL,
155
128
  });
156
-
157
- if (env.NODE_ENV === 'development') {
158
- // TypeScript knows the exact enum values!
159
- console.log('Development mode:', env.DEBUG);
160
- }
161
129
  ```
162
130
 
163
- That's it. Your environment is validated, typed, and safe.
164
-
165
131
  ---
166
132
 
167
133
  ## 📦 Installation
168
134
 
169
- ### npm
170
-
171
135
  ```bash
172
136
  npm install ultraenv
173
- ```
174
-
175
- ### pnpm
176
-
177
- ```bash
178
137
  pnpm add ultraenv
179
- ```
180
-
181
- ### yarn
182
-
183
- ```bash
184
138
  yarn add ultraenv
185
- ```
186
-
187
- ### bun
188
-
189
- ```bash
190
139
  bun add ultraenv
191
140
  ```
192
141
 
193
- ### Global CLI (optional)
142
+ ### Global CLI
194
143
 
195
144
  ```bash
196
145
  npm install -g ultraenv
197
-
198
- # Then use the CLI anywhere
199
146
  ultraenv init
200
147
  ultraenv validate
201
148
  ultraenv scan
202
149
  ```
203
150
 
204
- ### Verify Installation
205
-
206
- ```bash
207
- npx ultraenv --version
208
- # → ultraenv v1.0.0
209
- ```
210
-
211
151
  ---
212
152
 
213
153
  ## 🔧 CLI Command Reference
214
154
 
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
155
  | Command | Description |
265
156
  |---|---|
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
- ```
157
+ | `ultraenv init` | Initialize project |
158
+ | `ultraenv validate` | Validate environment variables |
159
+ | `ultraenv typegen` | Generate TypeScript types |
160
+ | `ultraenv sync` | Sync `.env.example` |
161
+ | `ultraenv scan` | Scan for leaked secrets |
162
+ | `ultraenv debug` | Show diagnostics |
163
+ | `ultraenv protect` | Check `.gitignore` protection |
164
+ | `ultraenv doctor` | Run self-checks |
165
+ | `ultraenv vault *` | Vault encrypt/decrypt/rekey |
166
+ | `ultraenv envs *` | Multi-environment management |
167
+ | `ultraenv ci *` | CI/CD integration commands |
315
168
 
316
169
  ---
317
170
 
318
171
  ## 📐 Schema Reference
319
172
 
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:
173
+ All schema builders via the `t` factory:
325
174
 
326
175
  ```typescript
327
176
  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
177
 
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'),
178
+ t.string().format('url').required()
179
+ t.number().port().default(3000)
180
+ t.boolean().default(false)
181
+ t.enum(['a', 'b'] as const).required()
182
+ t.url({ protocols: ['https'] }).required()
183
+ t.email().optional()
184
+ t.array().separator(';').trimItems().required()
185
+ t.json<{ theme: string }>().required()
186
+ t.duration().default('1h')
187
+ t.bytes().default('10MB')
188
+ t.path({ mustExist: false }).default('./uploads')
189
+ t.uuid({ version: 4 }).required()
190
+ t.ip().required()
191
+ t.cron().default('0 2 * * *')
635
192
  ```
636
193
 
637
- Supported units: `B`, `KB`, `MB`, `GB`, `TB`, `PB`
638
-
639
194
  ---
640
195
 
641
- #### `t.color()` Color String
196
+ ## 🔐 Encryption & Vault
642
197
 
643
- ```typescript
644
- BRAND_COLOR: t.color().required(),
645
- ACCENT: t.color({ formats: ['hex', 'rgb'] }).default('#0ea5e9'),
198
+ ```bash
199
+ ultraenv vault init --env production
200
+ ultraenv vault encrypt --env production
201
+ git add .env.vault # safe to commit!
202
+ ultraenv vault decrypt --env production
646
203
  ```
647
204
 
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
- ```
205
+ - **Algorithm**: AES-256-GCM
206
+ - `.env.vault` → commit ✅
207
+ - `.env.keys` gitignore
656
208
 
657
209
  ---
658
210
 
659
- #### `t.timezone()` IANA Timezone
211
+ ## 🔍 Secret Scanning
660
212
 
661
- ```typescript
662
- TZ: t.timezone().default('UTC'),
663
- USER_TIMEZONE: t.timezone().required(),
213
+ ```bash
214
+ ultraenv scan # Scan files
215
+ ultraenv scan --scope git-history # Scan git history
216
+ ultraenv scan --format sarif --output results.sarif # GitHub Code Scanning
664
217
  ```
665
218
 
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
- ```
219
+ 55+ patterns: AWS, GitHub, Google, Stripe, Slack, private keys, DB URLs, and more.
676
220
 
677
221
  ---
678
222
 
679
- #### `t.currency()` — ISO Currency Code
223
+ ## 🤝 Contributing
680
224
 
681
- ```typescript
682
- CURRENCY: t.currency().required(),
225
+ ```bash
226
+ git clone https://github.com/Avinashvelu03/ultraenv.git
227
+ cd ultraenv && npm install
228
+ npm test
229
+ npm run build
683
230
  ```
684
231
 
685
232
  ---
686
233
 
687
- #### `t.path()` — File System Path
234
+ ## 📜 License
688
235
 
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
- ```
236
+ [MIT](LICENSE) © 2024 [Avinash Velu](https://github.com/Avinashvelu03)
694
237
 
695
238
  ---
696
239
 
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
- ```
240
+ ## 🔐 Support ultraenv
707
241
 
708
- #### `.default(value)`
242
+ <div align="center">
709
243
 
710
- ```typescript
711
- PORT: t.number().default(3000),
712
- HOST: t.string().default('localhost'),
713
- ENABLED: t.boolean().default(false),
714
244
  ```
715
-
716
- #### `.description(desc)`
717
-
718
- ```typescript
719
- DATABASE_URL: t.string()
720
- .format('url')
721
- .description('Primary PostgreSQL connection string')
722
- .required(),
245
+ ██████╗ ██████╗ ███╗ ██╗ █████╗ ████████╗███████╗
246
+ ██╔══██╗██╔═══██╗████╗ ██║██╔══██╗╚══██╔══╝██╔════╝
247
+ ██║ ██║██║ ██║██╔██╗ ██║███████║ ██║ █████╗
248
+ ██║ ██║██║ ██║██║╚██╗██║██╔══██║ ██║ ██╔══╝
249
+ ██████╔╝╚██████╔╝██║ ╚████║██║ ██║ ██║ ███████╗
250
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚══════╝
723
251
  ```
724
252
 
725
- Generates JSDoc comments in type generation and descriptions in `.env.example`.
253
+ > *ultraenv is solo-built and freely available to every developer on Earth.*
254
+ > *If it saved your secrets, saved your sanity, or caught a leak before prod — it earned your support.*
726
255
 
727
- #### `.transform(fn)`
728
-
729
- ```typescript
730
- PORT: t.number()
731
- .transform(v => Math.floor(v))
732
- .default(3000),
256
+ [![Ko-fi](https://img.shields.io/badge/☕_Ko--fi-Power_the_Vault-FF5E5B?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/avinashvelu)
257
+ [![GitHub Sponsors](https://img.shields.io/badge/💜_GitHub-Become_a_Sponsor-EA4AAA?style=for-the-badge&logo=github&logoColor=white)](https://github.com/sponsors/Avinashvelu03)
733
258
 
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">
259
+ **Zero-cost support:**
260
+ - [Star on GitHub](https://github.com/Avinashvelu03/ultraenv)
261
+ - 🐛 [Report a bug or request a feature](https://github.com/Avinashvelu03/ultraenv/issues)
262
+ - 📣 Share ultraenv with your team or in your community
2053
263
 
2054
264
  **Made with ❤️ by [Avinash Velu](https://github.com/Avinashvelu03)**
2055
265