envapt 1.1.0 โ†’ 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,67 +1,127 @@
1
- # Envapt - The apt way to handle env
2
-
3
- A powerful TypeScript-first environment configuration library that provides type detection, template variable resolution, and decorator-based class property configuration by extending dotenv.
4
-
5
- ## Features
6
-
7
- - ๐Ÿ”ง **Automatic Type Detection** - Types inferred from fallback values
1
+ <p align="center">
2
+ <img src="assets/banner.png" alt="Envapt โ€“ The apt way to handle environment variables" width="100%" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ A TypeScript environment configuration library that eliminates the boilerplate of parsing <code>.env</code> files.<br/>
7
+ Get environment variables with correct runtime typing and fallbacks, template support, and automatic, built-in, & custom transformations.<br/>
8
+ <strong>No more <code>process.env.PORT || '3000'</code> everywhere!</strong>
9
+ </p>
10
+ <div align="center">
11
+ <img alt="Build" src="https://img.shields.io/github/actions/workflow/status/materwelonDhruv/envapt/publish.yaml?branch=main&label=build&style=flat&logo=github&color=3fb950"></a>
12
+ <a href="https://codecov.io/github/materwelonDhruv/envapt"><img src="https://codecov.io/github/materwelonDhruv/envapt/branch/main/graph/badge.svg?token=IQ4GC645LO"/></a>
13
+ <a href="https://www.npmjs.com/package/envapt"><img alt="npm version" src="https://img.shields.io/npm/v/envapt?style=flat&color=cb3838&logo=npm"></a>
14
+ <a href="LICENSE"><img alt="License" src="https://img.shields.io/npm/l/envapt?style=flat&color=e97826&logo=apache"></a>
15
+ <a href="https://www.typescriptlang.org/"><img alt="Types" src="https://img.shields.io/badge/types-TypeScript-3178c6?style=flat&logo=typescript&logoColor=white"></a>
16
+ <a href="https://nodejs.org/api/esm.html"><img alt="ESM" src="https://img.shields.io/badge/ESM-Supported-ffca28?style=flat"></a>
17
+ <a href="https://nodejs.org/api/modules.html"><img alt="CJS" src="https://img.shields.io/badge/CJS-Supported-ff6b35?style=flat"></a>
18
+ <a href="https://nodejs.org/"><img alt="Node" src="https://img.shields.io/badge/node-%3E=22.0.0-339933?style=flat&logo=node.js&logoColor=white"></a>
19
+ <a href="https://bundlephobia.com/package/envapt"><img alt="Bundle Size" src="https://img.shields.io/bundlephobia/minzip/envapt?style=flat&color=success"></a>
20
+ <a href="https://www.npmjs.com/package/envapt"><img alt="Downloads" src="https://img.shields.io/npm/dm/envapt?style=flat&color=blue"></a>
21
+ <a href="https://github.com/materwelondhruv/envapt"><img alt="GitHub Stars" src="https://img.shields.io/github/stars/materwelondhruv/envapt?style=flat&color=yellow"></a>
22
+ </div>
23
+
24
+ ---
25
+
26
+ ## โœจ Features
27
+
28
+ - ๐Ÿ”ง **Automatic Type Detection** - Runtime types inferred from fallback values
8
29
  - ๐Ÿ”— **Template Variables** - `${VAR}` syntax with circular reference protection
9
- - ๐ŸŽฏ **Class Properties** - Decorator-based configuration for class members
30
+ - ๐ŸŽฏ **Class Properties** - Functional and Decorator-based configuration for class members
10
31
  - ๐Ÿท๏ธ **Built-in & Custom Converters** - Ready-to-use converters for common patterns + custom transformations
11
32
  - ๐ŸŒ **Environment Detection** - Built-in development/staging/production handling
12
33
  - ๐Ÿ“‚ **Multiple .env Files** - Load from multiple sources
13
- - ๐Ÿ’ช **Edge Case Handling** - Robust parsing for all scenarios
34
+ - ๐Ÿ’ช **Edge Case Handling** - Robust validation and parsing for all scenarios
14
35
  - ๐Ÿ›ก๏ธ **Type Safety** - Full TypeScript support with proper type inference
36
+ - โšก **Lightweight** - Minimal overhead with [`dotenv`](https://www.npmjs.com/package/dotenv) bundled
15
37
 
16
- ## Table of Contents
38
+ ---
39
+
40
+ ## ๐Ÿ“š Table of Contents
41
+
42
+ ### โš™๏ธ Essentials
17
43
 
18
44
  - [Requirements](#requirements)
19
45
  - [Quick Start](#quick-start)
20
46
  - [Installation](#installation)
21
47
  - [Basic Usage](#basic-usage)
48
+
49
+ ### ๐Ÿงฌ API Reference
50
+
22
51
  - [API Reference](#api-reference)
23
52
  - [Decorator API](#decorator-api)
24
- - [Built-in Converters](#built-in-converters)
25
- - [Custom Array Converters](#custom-array-converters)
26
- - [Custom Converters](#custom-converters)
27
- - [Handling Missing Values](#handling-missing-values)
53
+ - [Modern Syntax (Recommended)](#modern-syntax-recommended)
54
+ - [Classic Syntax](#classic-syntax)
55
+ - [Automatic Runtime Type Detection](#automatic-runtime-type-detection)
56
+ - [Primitive Converters](#primitive-converters)
57
+ - [Built-in Converters](#built-in-converters)
58
+ - [Custom Array Converters](#custom-array-converters)
59
+ - [Custom Converters](#custom-converters)
60
+ - [Handling Missing Values](#handling-missing-values)
28
61
  - [Functional API](#functional-api)
62
+ - [Converter Type Quick Reference](#converter-type-quick-reference)
63
+
64
+ ### ๐ŸŒ Environment & Templates
65
+
29
66
  - [Environment Detection](#environment-detection)
67
+ - [Environment Management](#environment-management)
30
68
  - [Template Variables](#template-variables)
69
+ - [Circular Reference Protection](#circular-reference-protection)
70
+
71
+ ### ๐Ÿ›  Configuration & Errors
72
+
73
+ - [Configuration](#configuration)
74
+ - [Multiple .env Files](#multiple-env-files)
75
+ - [Dotenv Configuration](#dotenv-configuration)
76
+ - [Error Handling](#error-handling)
77
+ - [Error Code Reference](#error-code-reference)
78
+
79
+ ### ๐Ÿš€ Examples
80
+
31
81
  - [Advanced Examples](#advanced-examples)
82
+ - [Complex Configuration](#complex-configuration)
83
+
84
+ ---
32
85
 
33
86
  ## Requirements
34
87
 
35
- - **Node.js**: v22 or later (recommended for ESM and nodenext support)
36
- - **TypeScript**: v5.8 or later
37
- - **Dependencies**:
38
- - `dotenv` (runtime dependency | bundled)
39
- - **TypeScript Compiler Options**:
40
- - `experimentalDecorators: true`
41
- - `module: nodenext OR esnext`
42
- - `moduleResolution: nodenext OR bundler`
43
- - `target: ESnext`
44
- - `lib: ESNext`
45
- - **ESM Support**: Project uses ESM, so your environment and tooling should support ES modules.
88
+ #### ๐ŸŸข Runtime
46
89
 
47
- ## Quick Start
90
+ - **Node.js**: `>=22.0.0`
91
+ _Recommended for full ESM and `nodenext` support_
48
92
 
49
- ### Installation
93
+ - **TypeScript**: `>=5.8`
50
94
 
51
- ```bash
52
- # npm
53
- npm install envapt
95
+ #### ๐Ÿ“ฆ Runtime Dependency
54
96
 
55
- # pnpm
56
- pnpm add envapt
97
+ - **dotenv**: _(bundled at runtime)_
57
98
 
58
- # yarn
59
- yarn add envapt
99
+ #### ๐Ÿ› ๏ธ TypeScript Compiler Options
100
+
101
+ ```jsonc
102
+ // tsconfig.json (required settings)
103
+ {
104
+ "experimentalDecorators": true,
105
+ "module": "esnext", // or "nodenext"
106
+ "moduleResolution": "bundler", // or "nodenext"
107
+ "target": "ESNext",
108
+ "lib": ["ESNext"]
109
+ }
60
110
  ```
61
111
 
112
+ ## Quick Start
113
+
114
+ ### Installation
115
+
116
+ | Package Manager | Command |
117
+ | --------------- | -------------------- |
118
+ | **npm** | `npm install envapt` |
119
+ | **pnpm** | `pnpm add envapt` |
120
+ | **yarn** | `yarn add envapt` |
121
+
62
122
  ### Basic Usage
63
123
 
64
- Create a `.env` file:
124
+ **Step 1:** Create a `.env` file:
65
125
 
66
126
  ```env
67
127
  APP_PORT=8443
@@ -72,22 +132,22 @@ MAX_CONNECTIONS=100
72
132
  ALLOWED_ORIGINS=https://app.com,https://admin.com
73
133
  ```
74
134
 
75
- Use with decorators (recommended):
135
+ Use with decorators:
76
136
 
77
137
  ```ts
78
- import { Envapt, Envapter } from 'envapt';
138
+ import { Envapt, Envapter, Converters } from 'envapt';
79
139
 
80
140
  // Global app configuration (static properties)
81
141
  class AppConfig extends Envapter {
82
142
  @Envapt('APP_PORT', 3000)
83
143
  static readonly port: number;
84
144
 
85
- @Envapt('APP_URL', 'http://localhost:3000', 'url')
145
+ @Envapt('APP_URL', 'http://localhost:3000', Converters.Url)
86
146
  static readonly url: URL;
87
147
 
88
148
  @Envapt('ALLOWED_ORIGINS', {
89
149
  fallback: ['http://localhost:3000'],
90
- converter: 'array'
150
+ converter: Converters.Array
91
151
  })
92
152
  static readonly allowedOrigins: string[];
93
153
  }
@@ -97,10 +157,10 @@ class DatabaseService {
97
157
  @Envapt('DATABASE_URL', 'sqlite://memory')
98
158
  declare readonly databaseUrl: string;
99
159
 
100
- @Envapt('MAX_CONNECTIONS', { converter: 'number', fallback: 10 })
160
+ @Envapt('MAX_CONNECTIONS', { converter: Converters.Number, fallback: 10 })
101
161
  declare readonly maxConnections: number;
102
162
 
103
- @Envapt('REQUEST_TIMEOUT', { converter: 'time', fallback: 5000 })
163
+ @Envapt('REQUEST_TIMEOUT', { converter: Converters.Time, fallback: 5000 })
104
164
  declare readonly timeout: number; // Converts "5s" to 5000ms
105
165
 
106
166
  async connect() {
@@ -117,8 +177,7 @@ const dbService = new DatabaseService();
117
177
  await dbService.connect();
118
178
  ```
119
179
 
120
- Or use functionally:\
121
- <sub>Limited to primitives, String, Number, Boolean, Symbol, and BigInt. Does not support converters.</sub>
180
+ Or use functionally:
122
181
 
123
182
  ```ts
124
183
  import { Envapter } from 'envapt';
@@ -151,9 +210,9 @@ The `@Envapt` decorator can be used on both **static** and **instance** class pr
151
210
  @Envapt('ENV_VAR', fallback?, converter?)
152
211
  ```
153
212
 
154
- #### Automatic Type Detection
213
+ #### Automatic Runtime Type Detection
155
214
 
156
- Types are automatically inferred from fallback values. Use static properties for app-wide config and instance properties for service-specific config:
215
+ Types are automatically inferred from fallback values.
157
216
 
158
217
  ```ts
159
218
  class Config extends Envapter {
@@ -183,65 +242,144 @@ class Config extends Envapter {
183
242
  }
184
243
  ```
185
244
 
245
+ #### Primitive Converters
246
+
247
+ Envapt allows using the 5 "primitive" type-like converters. These **will** coerce values.
248
+
249
+ > [!NOTE]
250
+ > The runtime validator will ignore this usage, allowing type coercion for flexibility.
251
+
252
+ **Valid Primitive Types:** `String`, `Number`, `Boolean`, `Symbol`, and `BigInt`.
253
+
254
+ ```ts
255
+ class Config extends Envapter {
256
+ @Envapt('PORT_STRING', { fallback: 'hello-world', converter: String })
257
+ static readonly portAsString: string;
258
+
259
+ @Envapt('DEBUG_FLAG', { fallback: true, converter: Boolean })
260
+ static readonly debugMode: boolean;
261
+
262
+ @Envapt('USER_ID', { fallback: 12345, converter: Number })
263
+ static readonly userId: number;
264
+
265
+ @Envapt('MAX_SAFE_INT', { fallback: 9007199254740991n, converter: BigInt })
266
+ static readonly maxSafeInt: bigint;
267
+
268
+ @Envapt('APP_INSTANCE', { fallback: Symbol(main), converter: Symbol })
269
+ static readonly appInstance: symbol;
270
+
271
+ // Instance properties work the same way
272
+ @Envapt('CONNECTION_TIMEOUT', { fallback: 5000, converter: Number })
273
+ declare readonly timeout: number;
274
+
275
+ // Type coercion example
276
+ @Envapt('PERMISSIONS', { fallback: '72394823472342983', converter: BigInt })
277
+ declare readonly permissions: bigint; // Converts "72394823472342983" to BigInt
278
+ }
279
+ ```
280
+
281
+ **When to use primitive converters:**
282
+
283
+ - When you need explicit type coercion between incompatible types
284
+ - When working with external systems that provide values in unexpected formats
285
+
186
286
  #### Built-in Converters
187
287
 
188
288
  Envapt provides many built-in converters for common patterns:
189
289
 
290
+ > [!IMPORTANT]
291
+ > **Use the `Converters` enum** instead of string literals. They look better, and provide better type inference:
292
+ >
293
+ > ```ts
294
+ > import { Converters } from 'envapt';
295
+ > // โœ… Recommended: Use enum
296
+ > @Envapt('PORT', { converter: Converters.Number, fallback: 3000 })
297
+ >
298
+ > // โŒ Discouraged: String literals (still supported for compatibility)
299
+ > @Envapt('PORT', { converter: 'number', fallback: 3000 })
300
+ > ```
301
+
302
+ > [!IMPORTANT]
303
+ > Built-in converters enforce **strict type validation** between the converter and fallback types. The converter's expected return type must match the fallback's type.
304
+
190
305
  ```ts
191
306
  class Config extends Envapter {
192
307
  // Basic types
193
- @Envapt('APP_NAME', { converter: 'string', fallback: 'MyApp' })
308
+ @Envapt('APP_NAME', { converter: Converters.String, fallback: 'MyApp' })
194
309
  static readonly appName: string;
195
310
 
196
- @Envapt('PORT', { converter: 'number', fallback: 3000 })
311
+ @Envapt('PORT', { converter: Converters.Number, fallback: 3000 })
197
312
  static readonly port: number;
198
313
 
199
- @Envapt('PRODUCTION_MODE', { converter: 'boolean', fallback: false })
314
+ @Envapt('PRODUCTION_MODE', { converter: Converters.Boolean, fallback: false })
200
315
  static readonly productionMode: boolean;
201
316
 
202
317
  // Advanced types
203
- @Envapt('CORS_ORIGINS', { converter: 'array', fallback: [] })
318
+ @Envapt('CORS_ORIGINS', { converter: Converters.Array, fallback: [] })
204
319
  static readonly corsOrigins: string[];
205
320
 
206
- @Envapt('CONFIG_JSON', { converter: 'json', fallback: {} })
321
+ @Envapt('CONFIG_JSON', { converter: Converters.Json, fallback: {} })
207
322
  static readonly config: object;
208
323
 
209
- @Envapt('API_URL', { converter: 'url', fallback: new URL('http://localhost') })
324
+ @Envapt('API_URL', { converter: Converters.Url, fallback: new URL('http://localhost') })
210
325
  static readonly apiUrl: URL;
211
326
 
212
- @Envapt('TIMEOUT', { converter: 'time', fallback: 5000 })
327
+ @Envapt('TIMEOUT', { converter: Converters.Time, fallback: 5000 })
213
328
  static readonly timeout: number; // Converts "30s" to 30000ms
214
329
 
215
330
  // Instance properties work the same way
216
- @Envapt('CACHE_TTL', { converter: 'time', fallback: 3600000 })
331
+ @Envapt('CACHE_TTL', { converter: Converters.Time, fallback: 3600000 })
217
332
  declare readonly cacheTtl: number; // "1h" becomes 3600000ms
218
333
  }
219
334
  ```
220
335
 
336
+ > [!WARNING]
337
+ > These will throw runtime errors due to type mismatches:
338
+ >
339
+ > ```ts
340
+ > // โŒ String converter with number fallback
341
+ > @Envapt('VAR', { converter: Converters.String, fallback: 42 })
342
+ >
343
+ > // โŒ URL converter with string fallback
344
+ > @Envapt('VAR', { converter: Converters.Url, fallback: 'http://example.com' })
345
+ >
346
+ > // โœ… Use primitive constructors for type coercion instead
347
+ > @Envapt('VAR', { converter: String, fallback: 42 })
348
+ > ```
349
+
221
350
  **Available Built-in Converters:**
222
351
 
223
- - `'string'` - String values
224
- - `'number'` - Numeric values (integers and floats)
225
- - `'integer'` - Integer values only
226
- - `'float'` - Float values only
227
- - `'boolean'` - Boolean values (true/false, yes/no, on/off, 1/0)
228
- - `'bigint'` - BigInt values for large integers
229
- - `'symbol'` - Symbol values (creates symbols from string descriptions)
230
- - `'json'` - JSON objects/arrays (safe parsing with fallback)
231
- - `'array'` - Comma-separated string arrays
232
- - `'url'` - URL objects
233
- - `'regexp'` - Regular expressions (supports `/pattern/flags` syntax)
234
- - `'date'` - Date objects (supports ISO strings and timestamps)
235
- - `'time'` - Time values (converts "5s", "30m", "2h" to milliseconds)
352
+ | **Converter** | **Alias** | **Description** |
353
+ | -------------------- | ----------- | -------------------------------------------------------------------- |
354
+ | `Converters.String` | `'string'` | String values |
355
+ | `Converters.Number` | `'number'` | Numeric values (integers and floats) |
356
+ | `Converters.Integer` | `'integer'` | Integer values only |
357
+ | `Converters.Float` | `'float'` | Float values only |
358
+ | `Converters.Boolean` | `'boolean'` | Boolean values (`true`/`false`, `yes`/`no`, `on`/`off`, `1`/`0`) |
359
+ | `Converters.Bigint` | `'bigint'` | BigInt values for large integers |
360
+ | `Converters.Symbol` | `'symbol'` | Symbol values (creates symbols from string descriptions) |
361
+ | `Converters.Json` | `'json'` | JSON objects/arrays (safe parsing with fallback) |
362
+ | `Converters.Array` | `'array'` | Comma-separated string arrays |
363
+ | `Converters.Url` | `'url'` | URL objects |
364
+ | `Converters.Regexp` | `'regexp'` | Regular expressions (supports `/pattern/flags` syntax) |
365
+ | `Converters.Date` | `'date'` | Date objects (supports ISO strings and timestamps) |
366
+ | `Converters.Time` | `'time'` | Time values (e.g. `"5s"`, `"30m"`, `"2h"` converted to milliseconds) |
236
367
 
237
368
  #### Custom Array Converters
238
369
 
239
370
  For more control over array parsing:
240
371
 
372
+ > [!IMPORTANT]
373
+ > Array converters validate that:
374
+ >
375
+ > 1. **Fallback must be an array** (if provided)
376
+ > 2. **All fallback elements have consistent types** (no mixed types like `['string', 42, true]`)
377
+ > 3. **Array converter `type` matches fallback element types** (if `type` is specified)
378
+
241
379
  ```ts
242
380
  class Config extends Envapter {
243
381
  // Basic array (comma-separated strings)
244
- @Envapt('TAGS', { converter: 'array', fallback: [] })
382
+ @Envapt('TAGS', { converter: Converters.Array, fallback: [] })
245
383
  static readonly tags: string[];
246
384
 
247
385
  // Custom delimiter
@@ -249,7 +387,7 @@ class Config extends Envapter {
249
387
  declare readonly allowedMethods: string[];
250
388
 
251
389
  // Custom delimiter with type conversion
252
- @Envapt('RATE_LIMITS', { converter: { delimiter: ',', type: 'number' }, fallback: [100] })
390
+ @Envapt('RATE_LIMITS', { converter: { delimiter: ',', type: Converters.Number }, fallback: [100] })
253
391
  declare readonly rateLimits: number[];
254
392
 
255
393
  @Envapt('FEATURE_FLAGS', { converter: { delimiter: ';', type: 'boolean' }, fallback: [false] })
@@ -257,10 +395,24 @@ class Config extends Envapter {
257
395
  }
258
396
  ```
259
397
 
398
+ > [!WARNING]
399
+ > These will throw runtime validation errors:
400
+ >
401
+ > ```ts
402
+ > // โŒ Mixed types in fallback array
403
+ > @Envapt('MIXED', { converter: Converters.Array, fallback: ['string', 42, true] })
404
+ >
405
+ > // โŒ Array converter type doesn't match fallback elements
406
+ > @Envapt('NUMS', { converter: { delimiter: ',', type: Converters.Number }, fallback: ['not', 'numbers'] })
407
+ >
408
+ > // โŒ Non-array fallback with array converter
409
+ > @Envapt('INVALID', { converter: Converters.Array, fallback: 'not-an-array' })
410
+ > ```
411
+
260
412
  **ArrayConverter Interface:**
261
413
 
262
414
  - `delimiter: string` - The string used to split array elements
263
- - `type?: BuiltInConverter` - Optional type to convert each element to (excludes 'array', 'json', and 'regexp')
415
+ - `type?: BuiltInConverter` - Optional type to convert each element to (excludes `Converters.Array`, `Converters.Json`, and `Converters.Regexp`)
264
416
 
265
417
  #### Custom Converters
266
418
 
@@ -304,7 +456,7 @@ class Config extends Envapter {
304
456
  static readonly optionalFeature: string | undefined;
305
457
 
306
458
  // Returns null if not found (no fallback provided)
307
- @Envapt('MISSING_CONFIG', { converter: 'string' })
459
+ @Envapt('MISSING_CONFIG', { converter: Converters.String })
308
460
  static readonly missingConfig: string | null;
309
461
 
310
462
  // Uses fallback if not found
@@ -319,19 +471,92 @@ class Config extends Envapter {
319
471
 
320
472
  ### Functional API
321
473
 
474
+ For functional-style environment variable on primitive types:
475
+
322
476
  ```ts
323
- import { Envapter } from 'envapt';
477
+ import { Envapter, Converters } from 'envapt';
324
478
 
325
- // Type-specific getters
479
+ // Basic type-specific getters
326
480
  const str = Envapter.get('STRING_VAR', 'default');
327
481
  const num = Envapter.getNumber('NUMBER_VAR', 42);
328
482
  const bool = Envapter.getBoolean('BOOLEAN_VAR', false);
483
+ const bigint = Envapter.getBigInt('BIGINT_VAR', 100n);
484
+ const symbol = Envapter.getSymbol('SYMBOL_VAR', Symbol('default'));
329
485
 
330
- // Instance methods (same API)
486
+ // Advanced converter methods
487
+ const jsonData = Envapter.getUsing('CONFIG_JSON', Converters.Json);
488
+ const urlArray = Envapter.getUsing('API_URLS', { delimiter: ',', type: Converters.Url });
489
+ const customData = Envapter.getWith('RAW_DATA', (raw) => raw?.split('|').map((s) => s.trim()));
490
+
491
+ // Instance methods (same API available)
331
492
  const envapter = new Envapter();
332
493
  const value = envapter.get('VAR', 'default');
494
+ const processed = envapter.getUsing('DATA', Converters.Array);
333
495
  ```
334
496
 
497
+ For functional-style environment variable access with converters:
498
+
499
+ ```ts
500
+ import { Envapter, Converters } from 'envapt';
501
+
502
+ // Use built-in converters directly
503
+ const config = Envapter.getUsing('API_CONFIG', Converters.Json, { default: 'value' });
504
+ const urls = Envapter.getUsing('SERVICE_URLS', { delimiter: '|', type: Converters.Url });
505
+ const typedConfig = Envapter.getUsing<{ host: string; port: number; ssl: boolean }>('DATABASE_CONFIG', Converters.Json);
506
+ // typedConfig is now typed as { host: string; port: number; ssl: boolean } instead of JsonValue | undefined
507
+
508
+ // Use custom converter functions
509
+ const processedData = Envapter.getWith(
510
+ 'RAW_DATA',
511
+ (raw, fallback) => {
512
+ if (!raw) return fallback ?? [];
513
+ return raw.split(',').map((item) => ({ name: item.trim(), enabled: true }));
514
+ },
515
+ []
516
+ );
517
+
518
+ // Instance methods work the same way
519
+ const envapter = new Envapter();
520
+ const result = envapter.getUsing('DATABASE_CONFIG', Converters.Json);
521
+ ```
522
+
523
+ > [!TIP]
524
+ > **Type Override with `getUsing`**
525
+ >
526
+ > You can explicitly specify the return type for `getUsing` when TypeScript's inference isn't specific enough (especially useful with `Converters.Json`):
527
+ >
528
+ > ```ts
529
+ > // Default behavior
530
+ > const config = Envapter.getUsing('CONFIG', Converters.Json); // type: JsonValue | undefined (undefined because no fallback)
531
+ >
532
+ > // Override with specific interface
533
+ > interface DatabaseConfig {
534
+ > host: string;
535
+ > port: number;
536
+ > ssl: boolean;
537
+ > }
538
+ > const dbConfig = Envapter.getUsing<DatabaseConfig>('DB_CONFIG', Converters.Json);
539
+ > // dbConfig is now properly typed as DatabaseConfig
540
+ > ```
541
+ >
542
+ > _Make sure the fallback value matches the expected type, if you use a fallback. Otherwise you'll see a TypeScript error._\
543
+ > _This does NOT validate the type at runtime. You'll need to handle that yourself._
544
+
545
+ ### Converter Type Quick Reference
546
+
547
+ | **Use Case** | **Converter Type** | **Example** |
548
+ | ----------------------- | ------------------------- | --------------------------------------------------------- |
549
+ | **Type coercion** | Primitive constructors | `converter: String` |
550
+ | **Strict validation** | Built-in converters | `converter: Converters.String` |
551
+ | **Array parsing** | Built-in Array converters | `converter: { delimiter: ',', type?: Converters.String }` |
552
+ | **Complex transforms** | Custom function | `converter: (raw, fallback) => ...` |
553
+ | **Functional built-in** | `getUsing()` method | `Envapter.getUsing('VAR', Converters.Json)` |
554
+ | **Type override** | `getUsing<T>()` method | `Envapter.getUsing<MyType>('VAR', Converters.Json)` |
555
+ | **Functional custom** | `getWith()` method | `Envapter.getWith('VAR', (raw) => transform(raw))` |
556
+
557
+ > [!TIP]
558
+ > **Use the `Converters` enum**. They look better. Start with built-in converters, use primitive constructors when you need coercion, and custom converters for complex transforms.
559
+
335
560
  ## Environment Detection
336
561
 
337
562
  Envapt automatically detects your environment from these variables (in order):
@@ -348,7 +573,7 @@ Supported values: `development`, `staging`, `production` (case-sensitive)
348
573
  import { Envapter, EnvaptEnvironment } from 'envapt';
349
574
 
350
575
  // Check current environment
351
- console.log(Envapter.environment); // Environment.Development
576
+ console.log(Envapter.environment); // Environment.Development (default)
352
577
  console.log(Envapter.isProduction); // false
353
578
  console.log(Envapter.isDevelopment); // true
354
579
  console.log(Envapter.isStaging); // false
@@ -358,6 +583,8 @@ Envapter.environment = EnvaptEnvironment.Production;
358
583
  Envapter.environment = 'staging'; // string also works
359
584
  ```
360
585
 
586
+ ## Configuration
587
+
361
588
  ### Multiple .env Files
362
589
 
363
590
  ```ts
@@ -373,6 +600,29 @@ Envapter.envPaths = resolve(__dirname, '.env.production');
373
600
  // Or just don't set a path for it to default to .env at the root of your project
374
601
  ```
375
602
 
603
+ ### Dotenv Configuration
604
+
605
+ Envapt allows you to customize dotenv behavior by setting configuration options:
606
+
607
+ ```ts
608
+ import { Envapter } from 'envapt';
609
+
610
+ // Set dotenv configuration options
611
+ Envapter.dotenvConfig = {
612
+ encoding: 'latin1', // File encoding (default: 'utf8')
613
+ debug: true, // Enable debug logging
614
+ override: true, // Override existing environment variables
615
+ quiet: false, // Suppress non-error output (default: true)
616
+ DOTENV_KEY: 'key...' // Decryption key for .env.vault files
617
+ };
618
+
619
+ // Get current configuration
620
+ console.log(Envapter.dotenvConfig);
621
+ ```
622
+
623
+ > [!NOTE]
624
+ > The `path` and `processEnv` options are managed internally by Envapter and cannot be set via `dotenvConfig`.
625
+
376
626
  ## Template Variables
377
627
 
378
628
  Envapt supports variable interpolation with `${VARIABLE}` syntax:
@@ -396,19 +646,79 @@ CIRCULAR_B=${CIRCULAR_A}
396
646
 
397
647
  Circular references are detected and preserved as-is rather than causing infinite loops.
398
648
 
649
+ ## Error Handling
650
+
651
+ Envapt provides detailed error codes for better debugging and error handling:
652
+
653
+ ```ts
654
+ import { EnvaptError, EnvaptErrorCodes } from 'envapt';
655
+
656
+ try {
657
+ // This will throw an error for invalid configuration
658
+ Envapter.dotenvConfig = { path: '.env.custom' };
659
+ } catch (error) {
660
+ if (error instanceof EnvaptError) {
661
+ console.log('Error code:', error.code);
662
+ console.log('Error message:', error.message);
663
+
664
+ // Handle specific error types
665
+ switch (error.code) {
666
+ case EnvaptErrorCodes.InvalidUserDefinedConfig:
667
+ console.log('Invalid configuration provided');
668
+ break;
669
+ case EnvaptErrorCodes.EnvFileNotFound:
670
+ console.log('Environment file not found');
671
+ break;
672
+ default:
673
+ console.warn('Unhandled error code:', error.code);
674
+ break;
675
+ }
676
+ }
677
+ }
678
+ ```
679
+
680
+ ### Error Code Reference
681
+
682
+ #### ๐Ÿ”ง Fallback Errors (1xx)
683
+
684
+ | **Error Code** | **Description** |
685
+ | ---------------------------------------- | --------------------------------------------------------- |
686
+ | `InvalidFallback` (101) | Invalid fallback value provided |
687
+ | `InvalidFallbackType` (102) | Fallback value type doesn't match expected converter type |
688
+ | `ArrayFallbackElementTypeMismatch` (103) | Array fallback contains elements of wrong type |
689
+ | `FallbackConverterTypeMismatch` (104) | Fallback type doesn't match the specified converter |
690
+
691
+ #### ๐Ÿงช Converter Errors (2xx)
692
+
693
+ | **Error Code** | **Description** |
694
+ | --------------------------------- | ---------------------------------------------- |
695
+ | `InvalidArrayConverterType` (201) | Invalid array converter configuration provided |
696
+ | `InvalidBuiltInConverter` (202) | Invalid built-in converter specified |
697
+ | `InvalidCustomConverter` (203) | Custom converter function is invalid |
698
+ | `InvalidConverterType` (204) | Converter type is not recognized |
699
+ | `PrimitiveCoercionFailed` (205) | Primitive type coercion failed |
700
+
701
+ #### ๐Ÿ“‚ Environment File & Config Errors (3xx)
702
+
703
+ | **Error Code** | **Description** |
704
+ | -------------------------------- | ---------------------------------------------- |
705
+ | `MissingDelimiter` (301) | Delimiter is missing in array converter config |
706
+ | `InvalidUserDefinedConfig` (302) | Invalid user-defined configuration provided |
707
+ | `EnvFilesNotFound` (303) | Specified environment file doesn't exist |
708
+
399
709
  ## Advanced Examples
400
710
 
401
711
  ### Complex Configuration
402
712
 
403
713
  ```ts
404
- import { Envapt, Envapter } from 'envapt';
714
+ import { Envapt, Envapter, Converters } from 'envapt';
405
715
 
406
716
  class AppConfig extends Envapter {
407
717
  // Global settings (static)
408
718
  @Envapt('PORT', 3000)
409
719
  static readonly port: number;
410
720
 
411
- @Envapt('REQUEST_TIMEOUT', { converter: 'time', fallback: 10000 })
721
+ @Envapt('REQUEST_TIMEOUT', { converter: Converters.Time, fallback: 10000 })
412
722
  static readonly requestTimeout: number; // "5s" -> 5000ms (if env is set to "5s")
413
723
 
414
724
  @Envapt('FEATURE_FLAGS', {
@@ -424,7 +734,7 @@ class AppConfig extends Envapter {
424
734
  @Envapt('DB_URL', 'sqlite://memory')
425
735
  declare readonly databaseUrl: string;
426
736
 
427
- @Envapt('CACHE_TTL', { converter: 'time', fallback: 3600000 })
737
+ @Envapt('CACHE_TTL', { converter: Converters.Time, fallback: 3600000 })
428
738
  declare readonly cacheTtl: number; // "1h" -> 3600000ms
429
739
 
430
740
  @Envapt('REDIS_URLS', {
@@ -440,3 +750,20 @@ class AppConfig extends Envapter {
440
750
  }
441
751
  }
442
752
  ```
753
+
754
+ ---
755
+
756
+ <hr/>
757
+
758
+ <p align="center">
759
+ <a href="https://github.com/materwelondhruv/envapt">โญ๏ธ Star it on GitHub</a> โ€ข
760
+ <a href="https://github.com/materwelondhruv/envapt/issues">๐Ÿ› Report a bug</a> โ€ข
761
+ <a href="https://github.com/materwelondhruv/envapt/issues/new?labels=enhancement">๐Ÿ’ก Request a feature</a>
762
+ </p>
763
+
764
+ <p align="center">
765
+ <sub>
766
+ Built by <a href="https://github.com/materwelondhruv">@materwelonDhruv</a> โ€ข Licensed under
767
+ <a href="LICENSE">Apache 2.0</a>
768
+ </sub>
769
+ </p>