envapt 2.1.1 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -32
- package/dist/index.cjs +32 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.mjs +32 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
A TypeScript environment configuration library that eliminates the boilerplate of transforming parsed <code>.env</code><br/>
|
|
7
|
-
Get environment variables with correct runtime typing and fallbacks, template support, and automatic, built-in, & custom transformations.<br/>
|
|
6
|
+
A JavaScript/TypeScript environment configuration library that eliminates the boilerplate of transforming parsed <code>.env</code><br/>
|
|
7
|
+
Get environment variables with correct runtime typing and fallbacks, template support, and automatic, built-in, & custom transformations, and tagged template resolver.<br/>
|
|
8
8
|
<strong>No more <code>process.env.PORT || '3000'</code> everywhere!</strong>
|
|
9
9
|
</p>
|
|
10
10
|
<div align="center">
|
|
@@ -27,12 +27,13 @@
|
|
|
27
27
|
|
|
28
28
|
- 🔧 **Automatic Type Detection** - Runtime types inferred from fallback values
|
|
29
29
|
- 🔗 **Template Variables** - `${VAR}` syntax with circular reference protection
|
|
30
|
-
- 🎯 **Class Properties** - Functional and Decorator-based configuration for class members
|
|
30
|
+
- 🎯 **Class Properties** - Functional and Decorator-based configuration for class members _(Decorators: TypeScript only)_
|
|
31
31
|
- 🏷️ **Built-in & Custom Converters** - Ready-to-use converters for common patterns + custom transformations
|
|
32
|
+
- 🔖 **Tagged Template Resolver** - Tagged template literals with environment variable resolution
|
|
32
33
|
- 🌍 **Environment Detection** - Built-in development/staging/production handling
|
|
33
|
-
- 📂 **Multiple .env Files** - Load from multiple sources
|
|
34
34
|
- 💪 **Edge Case Handling** - Robust validation and parsing for all scenarios
|
|
35
|
-
- 🛡️ **Type Safety** - Full TypeScript support with proper type inference
|
|
35
|
+
- 🛡️ **Type Safety** - Full TypeScript support with proper type inference _(TypeScript optional)_
|
|
36
|
+
- 📂 **Multiple .env Files** - Load from multiple sources
|
|
36
37
|
- ⚡ **Lightweight** - Minimal overhead with [`dotenv`](https://www.npmjs.com/package/dotenv) bundled
|
|
37
38
|
|
|
38
39
|
---
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
- [Custom Converters](#custom-converters)
|
|
60
61
|
- [Handling Missing Values](#handling-missing-values)
|
|
61
62
|
- [Functional API](#functional-api)
|
|
63
|
+
- [Tagged Template Resolver](#tagged-template-resolver)
|
|
62
64
|
- [Converter Type Quick Reference](#converter-type-quick-reference)
|
|
63
65
|
|
|
64
66
|
### 🌍 Environment & Templates
|
|
@@ -79,7 +81,8 @@
|
|
|
79
81
|
### 🚀 Examples
|
|
80
82
|
|
|
81
83
|
- [Advanced Examples](#advanced-examples)
|
|
82
|
-
- [
|
|
84
|
+
- [JavaScript](#javascript)
|
|
85
|
+
- [TypeScript](#typescript)
|
|
83
86
|
|
|
84
87
|
---
|
|
85
88
|
|
|
@@ -90,16 +93,16 @@
|
|
|
90
93
|
- **Node.js**: `>=22.0.0`
|
|
91
94
|
_Recommended for full ESM and `nodenext` support_
|
|
92
95
|
|
|
93
|
-
- **TypeScript**: `>=5.8`
|
|
94
|
-
|
|
95
96
|
#### 📦 Runtime Dependency
|
|
96
97
|
|
|
97
98
|
- **dotenv**: _(bundled at runtime)_
|
|
98
99
|
|
|
99
|
-
#### 🛠️ TypeScript
|
|
100
|
+
#### 🛠️ TypeScript Users Only
|
|
101
|
+
|
|
102
|
+
- **TypeScript**: `>=5.8` _(Only required for decorator API)_
|
|
100
103
|
|
|
101
104
|
```jsonc
|
|
102
|
-
// tsconfig.json (required settings)
|
|
105
|
+
// tsconfig.json (required settings for decorators)
|
|
103
106
|
{
|
|
104
107
|
"experimentalDecorators": true,
|
|
105
108
|
"module": "esnext", // or "nodenext"
|
|
@@ -109,6 +112,9 @@
|
|
|
109
112
|
}
|
|
110
113
|
```
|
|
111
114
|
|
|
115
|
+
> [!NOTE]
|
|
116
|
+
> **JavaScript users** can use all features except the `@Envapt` decorator API. The [Functional API](#functional-api), [Tagged Template Resolver](#tagged-template-resolver), and all converters work perfectly in plain JavaScript.
|
|
117
|
+
|
|
112
118
|
## Quick Start
|
|
113
119
|
|
|
114
120
|
### Installation
|
|
@@ -132,7 +138,29 @@ MAX_CONNECTIONS=100
|
|
|
132
138
|
ALLOWED_ORIGINS=https://app.com,https://admin.com
|
|
133
139
|
```
|
|
134
140
|
|
|
135
|
-
|
|
141
|
+
**JavaScript Example (Functional API):**
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import { Envapter, Converters } from 'envapt';
|
|
145
|
+
|
|
146
|
+
// Basic usage
|
|
147
|
+
const port = Envapter.getNumber('APP_PORT', 3000);
|
|
148
|
+
const url = Envapter.get('APP_URL', 'http://localhost:3000');
|
|
149
|
+
const isProduction = Envapter.isProduction;
|
|
150
|
+
|
|
151
|
+
console.log(`Server running on port ${port}`); // 8443
|
|
152
|
+
console.log(`URL: ${url}`); // "http://localhost:8443"
|
|
153
|
+
|
|
154
|
+
// Advanced converters
|
|
155
|
+
const corsOrigins = Envapter.getUsing('ALLOWED_ORIGINS', Converters.Array, []);
|
|
156
|
+
const dbConfig = Envapter.getUsing('DATABASE_CONFIG', Converters.Json, {});
|
|
157
|
+
|
|
158
|
+
// Tagged template literals
|
|
159
|
+
const message = Envapter.resolve`Server ${'APP_URL'} is ready!`;
|
|
160
|
+
console.log(message); // "Server http://localhost:8443 is ready!"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**TypeScript Example (Decorator API):**
|
|
136
164
|
|
|
137
165
|
```ts
|
|
138
166
|
import { Envapt, Envapter, Converters } from 'envapt';
|
|
@@ -171,30 +199,23 @@ class DatabaseService {
|
|
|
171
199
|
|
|
172
200
|
// Usage
|
|
173
201
|
console.log(AppConfig.port); // 8443 (number)
|
|
174
|
-
console.log(AppConfig.url.href); // "http://localhost:8443"
|
|
202
|
+
console.log(AppConfig.url.href); // "http://localhost:8443"
|
|
175
203
|
|
|
176
204
|
const dbService = new DatabaseService();
|
|
177
205
|
await dbService.connect();
|
|
178
206
|
```
|
|
179
207
|
|
|
180
|
-
Or use functionally:
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
import { Envapter } from 'envapt';
|
|
184
|
-
|
|
185
|
-
const port = Envapter.getNumber('APP_PORT', 3000);
|
|
186
|
-
const url = Envapter.get('APP_URL', 'http://localhost:3000');
|
|
187
|
-
const isProduction = Envapter.getBoolean('IS_PRODUCTION', false);
|
|
188
|
-
```
|
|
189
|
-
|
|
190
208
|
## API Reference
|
|
191
209
|
|
|
192
210
|
### Decorator API
|
|
193
211
|
|
|
212
|
+
> [!IMPORTANT]
|
|
213
|
+
> **TypeScript Only**: The `@Envapt` decorator API requires TypeScript with `experimentalDecorators: true`. JavaScript users should use the [Functional API](#functional-api) instead.
|
|
214
|
+
|
|
194
215
|
The `@Envapt` decorator can be used on both **static** and **instance** class properties:
|
|
195
216
|
|
|
196
|
-
- **Static properties**:
|
|
197
|
-
- **Instance properties**:
|
|
217
|
+
- **Static properties**: Can use for global configuration that's shared across your entire application (e.g., app port, global features, environment settings)
|
|
218
|
+
- **Instance properties**: Can use for service-specific configuration that may vary per service or when you want the configuration tied to a specific class instance (e.g., database connections, service endpoints, per-service settings)
|
|
198
219
|
|
|
199
220
|
**Important**: Instance properties must be declared with `declare` keyword or `!` assertion since they're populated by the decorator rather than set in a constructor.
|
|
200
221
|
|
|
@@ -471,9 +492,9 @@ class Config extends Envapter {
|
|
|
471
492
|
|
|
472
493
|
### Functional API
|
|
473
494
|
|
|
474
|
-
For functional-style environment variable on primitive types:
|
|
495
|
+
For functional-style environment variable access on primitive types:
|
|
475
496
|
|
|
476
|
-
```
|
|
497
|
+
```js
|
|
477
498
|
import { Envapter, Converters } from 'envapt';
|
|
478
499
|
|
|
479
500
|
// Basic type-specific getters
|
|
@@ -496,12 +517,14 @@ const processed = envapter.getUsing('DATA', Converters.Array);
|
|
|
496
517
|
|
|
497
518
|
For functional-style environment variable access with converters:
|
|
498
519
|
|
|
499
|
-
```
|
|
520
|
+
```js
|
|
500
521
|
import { Envapter, Converters } from 'envapt';
|
|
501
522
|
|
|
502
523
|
// Use built-in converters directly
|
|
503
524
|
const config = Envapter.getUsing('API_CONFIG', Converters.Json, { default: 'value' });
|
|
504
525
|
const urls = Envapter.getUsing('SERVICE_URLS', { delimiter: '|', type: Converters.Url });
|
|
526
|
+
|
|
527
|
+
// TypeScript: Use type override for better type inference
|
|
505
528
|
const typedConfig = Envapter.getUsing<{ host: string; port: number; ssl: boolean }>('DATABASE_CONFIG', Converters.Json);
|
|
506
529
|
// typedConfig is now typed as { host: string; port: number; ssl: boolean } instead of JsonValue | undefined
|
|
507
530
|
|
|
@@ -557,6 +580,50 @@ const result = envapter.getUsing('DATABASE_CONFIG', Converters.Json);
|
|
|
557
580
|
> [!TIP]
|
|
558
581
|
> **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
582
|
|
|
583
|
+
### Tagged Template Resolver
|
|
584
|
+
|
|
585
|
+
Envapt provides a convenient tagged template literal syntax for resolving environment variables directly in template strings:
|
|
586
|
+
|
|
587
|
+
```js
|
|
588
|
+
import { Envapter } from 'envapt';
|
|
589
|
+
|
|
590
|
+
// Given these environment variables:
|
|
591
|
+
// API_HOST=api.example.com
|
|
592
|
+
// API_PORT=8080
|
|
593
|
+
// API_URL=https://${API_HOST}:${API_PORT}
|
|
594
|
+
// SERVICE_NAME=UserService
|
|
595
|
+
|
|
596
|
+
// Use tagged template literals for string interpolation
|
|
597
|
+
const endpoint = Envapter.resolve`Connecting to ${'SERVICE_NAME'} at ${'API_URL'}`;
|
|
598
|
+
// Returns: "Connecting to UserService at https://api.example.com:8080"
|
|
599
|
+
|
|
600
|
+
const logMessage = Envapter.resolve`Starting ${'SERVICE_NAME'} on port ${'API_PORT'}`;
|
|
601
|
+
// Returns: "Starting UserService on port 8080"
|
|
602
|
+
|
|
603
|
+
// Works with instance methods too
|
|
604
|
+
const envapter = new Envapter();
|
|
605
|
+
const status = envapter.resolve`${'SERVICE_NAME'} is running`;
|
|
606
|
+
// Returns: "UserService is running"
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Works seamlessly with template variables in your `.env` file:
|
|
610
|
+
|
|
611
|
+
```env
|
|
612
|
+
# Your .env file
|
|
613
|
+
API_HOST=api.example.com
|
|
614
|
+
API_PORT=8080
|
|
615
|
+
API_URL=https://${API_HOST}:${API_PORT} # Template resolved first
|
|
616
|
+
SERVICE_NAME=UserService
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
```ts
|
|
620
|
+
const message = Envapter.resolve`Service ${'SERVICE_NAME'} endpoint: ${'API_URL'}`;
|
|
621
|
+
// Returns: "Service UserService endpoint: https://api.example.com:8080"
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
> [!NOTE]
|
|
625
|
+
> Tagged template literals work with any environment variables, including those that use `${VAR}` template syntax in your `.env` file. The template resolution happens first, then the tagged template interpolation.
|
|
626
|
+
|
|
560
627
|
## Environment Detection
|
|
561
628
|
|
|
562
629
|
Envapt automatically detects your environment from these variables (in order):
|
|
@@ -569,7 +636,7 @@ Supported values: `development`, `staging`, `production` (case-sensitive)
|
|
|
569
636
|
|
|
570
637
|
### Environment Management
|
|
571
638
|
|
|
572
|
-
```
|
|
639
|
+
```js
|
|
573
640
|
import { Envapter, EnvaptEnvironment } from 'envapt';
|
|
574
641
|
|
|
575
642
|
// Check current environment
|
|
@@ -587,7 +654,7 @@ Envapter.environment = 'staging'; // string also works
|
|
|
587
654
|
|
|
588
655
|
### Multiple .env Files
|
|
589
656
|
|
|
590
|
-
```
|
|
657
|
+
```js
|
|
591
658
|
import { resolve } from 'node:path';
|
|
592
659
|
import { Envapter } from 'envapt';
|
|
593
660
|
|
|
@@ -604,7 +671,7 @@ Envapter.envPaths = resolve(__dirname, '.env.production');
|
|
|
604
671
|
|
|
605
672
|
Envapt allows you to customize dotenv behavior by setting configuration options:
|
|
606
673
|
|
|
607
|
-
```
|
|
674
|
+
```js
|
|
608
675
|
import { Envapter } from 'envapt';
|
|
609
676
|
|
|
610
677
|
// Set dotenv configuration options
|
|
@@ -650,7 +717,7 @@ Circular references are detected and preserved as-is rather than causing infinit
|
|
|
650
717
|
|
|
651
718
|
Envapt provides detailed error codes for better debugging and error handling:
|
|
652
719
|
|
|
653
|
-
```
|
|
720
|
+
```js
|
|
654
721
|
import { EnvaptError, EnvaptErrorCodes } from 'envapt';
|
|
655
722
|
|
|
656
723
|
try {
|
|
@@ -708,7 +775,46 @@ try {
|
|
|
708
775
|
|
|
709
776
|
## Advanced Examples
|
|
710
777
|
|
|
711
|
-
###
|
|
778
|
+
### JavaScript
|
|
779
|
+
|
|
780
|
+
```js
|
|
781
|
+
import { Envapter, Converters } from 'envapt';
|
|
782
|
+
|
|
783
|
+
// Global configuration
|
|
784
|
+
const config = {
|
|
785
|
+
port: Envapter.getNumber('PORT', 3000),
|
|
786
|
+
requestTimeout: Envapter.getUsing('REQUEST_TIMEOUT', Converters.Time, 10000), // "5s" -> 5000ms
|
|
787
|
+
featureFlags: Envapter.getWith(
|
|
788
|
+
'FEATURE_FLAGS',
|
|
789
|
+
(raw, fallback) => {
|
|
790
|
+
if (!raw) return fallback;
|
|
791
|
+
return new Set(raw.split(',').map((s) => s.trim()));
|
|
792
|
+
},
|
|
793
|
+
new Set(['basic'])
|
|
794
|
+
)
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
// Service configuration
|
|
798
|
+
class DatabaseService {
|
|
799
|
+
constructor() {
|
|
800
|
+
this.databaseUrl = Envapter.get('DB_URL', 'sqlite://memory');
|
|
801
|
+
this.cacheTtl = Envapter.getUsing('CACHE_TTL', Converters.Time, 3600000); // "1h" -> 3600000ms
|
|
802
|
+
this.redisUrls = Envapter.getWith(
|
|
803
|
+
'REDIS_URLS',
|
|
804
|
+
(raw, fallback) => (raw ? raw.split(',').map((s) => new URL(s)) : fallback),
|
|
805
|
+
[new URL('redis://localhost:6379')]
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
async initialize() {
|
|
810
|
+
console.log(`App running on port ${config.port}`);
|
|
811
|
+
console.log(`Database: ${this.databaseUrl}`);
|
|
812
|
+
console.log(`Cache TTL: ${this.cacheTtl}ms`);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### TypeScript
|
|
712
818
|
|
|
713
819
|
```ts
|
|
714
820
|
import { Envapt, Envapter, Converters } from 'envapt';
|
package/dist/index.cjs
CHANGED
|
@@ -788,17 +788,46 @@ var AdvancedMethods = class _AdvancedMethods extends PrimitiveMethods {
|
|
|
788
788
|
};
|
|
789
789
|
|
|
790
790
|
// src/Envapter.ts
|
|
791
|
-
var Envapter = class extends AdvancedMethods {
|
|
791
|
+
var Envapter = class _Envapter extends AdvancedMethods {
|
|
792
792
|
static {
|
|
793
793
|
__name(this, "Envapter");
|
|
794
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* Tagged template literal for resolving environment variables in template strings.
|
|
797
|
+
*
|
|
798
|
+
* @example
|
|
799
|
+
* ```ts
|
|
800
|
+
* // Given API_HOST=api.example.com and API_PORT=8080 in environment
|
|
801
|
+
* const endpoint = Envapter.resolve`Connecting to ${'API_HOST'}:${'API_PORT'}`;
|
|
802
|
+
* // Returns: "Connecting to api.example.com:8080"
|
|
803
|
+
*
|
|
804
|
+
* // Works with template variables in .env too:
|
|
805
|
+
* // API_URL=https://${API_HOST}:${API_PORT}
|
|
806
|
+
* const message = Envapter.resolve`Service endpoint: ${'API_URL'}`;
|
|
807
|
+
* // Returns: "Service endpoint: https://api.example.com:8080"
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
static resolve(strings, ...keys) {
|
|
811
|
+
return strings.reduce((result, string, i) => {
|
|
812
|
+
const envKey = keys[i];
|
|
813
|
+
const envValue = envKey ? super.get(envKey, "") : "";
|
|
814
|
+
return result + string + envValue;
|
|
815
|
+
}, "");
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* @see {@link Envapter.resolve}
|
|
819
|
+
*/
|
|
820
|
+
resolve(strings, ...keys) {
|
|
821
|
+
return _Envapter.resolve(strings, ...keys);
|
|
822
|
+
}
|
|
795
823
|
};
|
|
796
824
|
|
|
797
825
|
// src/Envapt.ts
|
|
798
826
|
function createPropertyDecorator(key, fallback, converter, hasFallback) {
|
|
799
827
|
return function(target, prop) {
|
|
800
828
|
const propKey = String(prop);
|
|
801
|
-
const
|
|
829
|
+
const className = typeof target === "function" ? target.name : target.constructor.name;
|
|
830
|
+
const cacheKey = `${className}.${propKey}`;
|
|
802
831
|
Object.defineProperty(target, propKey, {
|
|
803
832
|
get: /* @__PURE__ */ __name(function() {
|
|
804
833
|
let value = EnvaptCache.get(cacheKey);
|
|
@@ -853,6 +882,7 @@ var Converters = /* @__PURE__ */ ((Converters2) => {
|
|
|
853
882
|
|
|
854
883
|
exports.Converters = Converters;
|
|
855
884
|
exports.Envapt = Envapt;
|
|
885
|
+
exports.EnvaptError = EnvaptError;
|
|
856
886
|
exports.EnvaptErrorCodes = EnvaptErrorCodes;
|
|
857
887
|
exports.Envapter = Envapter;
|
|
858
888
|
exports.Environment = Environment;
|