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/dist/index.cjs CHANGED
@@ -1,22 +1,31 @@
1
1
  'use strict';
2
2
 
3
3
  var dotenv = require('dotenv');
4
+ var fs = require('fs');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
4
9
 
5
10
  var __defProp = Object.defineProperty;
6
11
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
12
 
8
13
  // src/Error.ts
9
- var EnvaptErrorCodes = {
10
- InvalidFallback: 617404,
11
- MissingDelimiter: 967308,
12
- InvalidArrayConverterType: 193159,
13
- InvalidBuiltInConverter: 337271,
14
- InvalidConverterType: 453217,
15
- InvalidCustomConverter: 789432
16
- };
17
- var ReversedEnvaptErrorCodes = Object.fromEntries(
18
- Object.entries(EnvaptErrorCodes).map(([key, value]) => [value, key])
19
- );
14
+ var EnvaptErrorCodes = /* @__PURE__ */ ((EnvaptErrorCodes2) => {
15
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidFallback"] = 101] = "InvalidFallback";
16
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidFallbackType"] = 102] = "InvalidFallbackType";
17
+ EnvaptErrorCodes2[EnvaptErrorCodes2["ArrayFallbackElementTypeMismatch"] = 103] = "ArrayFallbackElementTypeMismatch";
18
+ EnvaptErrorCodes2[EnvaptErrorCodes2["FallbackConverterTypeMismatch"] = 104] = "FallbackConverterTypeMismatch";
19
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidArrayConverterType"] = 201] = "InvalidArrayConverterType";
20
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidBuiltInConverter"] = 202] = "InvalidBuiltInConverter";
21
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidCustomConverter"] = 203] = "InvalidCustomConverter";
22
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidConverterType"] = 204] = "InvalidConverterType";
23
+ EnvaptErrorCodes2[EnvaptErrorCodes2["PrimitiveCoercionFailed"] = 205] = "PrimitiveCoercionFailed";
24
+ EnvaptErrorCodes2[EnvaptErrorCodes2["MissingDelimiter"] = 301] = "MissingDelimiter";
25
+ EnvaptErrorCodes2[EnvaptErrorCodes2["InvalidUserDefinedConfig"] = 302] = "InvalidUserDefinedConfig";
26
+ EnvaptErrorCodes2[EnvaptErrorCodes2["EnvFilesNotFound"] = 303] = "EnvFilesNotFound";
27
+ return EnvaptErrorCodes2;
28
+ })(EnvaptErrorCodes || {});
20
29
  var EnvaptError = class _EnvaptError extends Error {
21
30
  static {
22
31
  __name(this, "EnvaptError");
@@ -24,7 +33,7 @@ var EnvaptError = class _EnvaptError extends Error {
24
33
  code;
25
34
  constructor(code, message) {
26
35
  super(message);
27
- this.name = `${ReversedEnvaptErrorCodes[code]} [${code}]`;
36
+ this.name = `EnvaptError [${code}]`;
28
37
  this.code = code;
29
38
  Error.captureStackTrace(this, _EnvaptError);
30
39
  }
@@ -46,6 +55,28 @@ var ListOfBuiltInConverters = [
46
55
  "date",
47
56
  "time"
48
57
  ];
58
+ var BuiltInConverterTypeCheckers = {
59
+ string: /* @__PURE__ */ __name((value) => typeof value === "string", "string"),
60
+ number: /* @__PURE__ */ __name((value) => typeof value === "number", "number"),
61
+ boolean: /* @__PURE__ */ __name((value) => typeof value === "boolean", "boolean"),
62
+ bigint: /* @__PURE__ */ __name((value) => typeof value === "bigint", "bigint"),
63
+ symbol: /* @__PURE__ */ __name((value) => typeof value === "symbol", "symbol"),
64
+ integer: /* @__PURE__ */ __name((value) => typeof value === "number" && Number.isInteger(value), "integer"),
65
+ float: /* @__PURE__ */ __name((value) => typeof value === "number", "float"),
66
+ json: /* @__PURE__ */ __name((value) => {
67
+ try {
68
+ JSON.parse(JSON.stringify(value));
69
+ return true;
70
+ } catch {
71
+ return false;
72
+ }
73
+ }, "json"),
74
+ array: /* @__PURE__ */ __name((value) => Array.isArray(value), "array"),
75
+ url: /* @__PURE__ */ __name((value) => value instanceof URL, "url"),
76
+ regexp: /* @__PURE__ */ __name((value) => value instanceof RegExp, "regexp"),
77
+ date: /* @__PURE__ */ __name((value) => value instanceof Date, "date"),
78
+ time: /* @__PURE__ */ __name((value) => typeof value === "number", "time")
79
+ };
49
80
 
50
81
  // src/Validators.ts
51
82
  var Validator = class {
@@ -77,16 +108,10 @@ var Validator = class {
77
108
  );
78
109
  return validTypes.includes(value);
79
110
  }
80
- /**
81
- * Check if a value is a valid custom converter function
82
- */
83
- static isValidConverterFunction(converter) {
84
- return typeof converter === "function";
85
- }
86
111
  static customConvertor(converter) {
87
112
  if (typeof converter !== "function") {
88
113
  throw new EnvaptError(
89
- EnvaptErrorCodes.InvalidCustomConverter,
114
+ 203 /* InvalidCustomConverter */,
90
115
  `Custom converter must be a function, got ${typeof converter}.`
91
116
  );
92
117
  }
@@ -96,11 +121,11 @@ var Validator = class {
96
121
  */
97
122
  static arrayConverter(value) {
98
123
  if (!this.isArrayConverter(value)) {
99
- throw new EnvaptError(EnvaptErrorCodes.MissingDelimiter, "Must have delimiter property");
124
+ throw new EnvaptError(301 /* MissingDelimiter */, "Must have delimiter property");
100
125
  }
101
126
  if (value.type !== void 0 && !this.isValidArrayConverterType(value.type)) {
102
127
  throw new EnvaptError(
103
- EnvaptErrorCodes.InvalidArrayConverterType,
128
+ 201 /* InvalidArrayConverterType */,
104
129
  `"${value.type}" is not a valid converter type`
105
130
  );
106
131
  }
@@ -110,15 +135,201 @@ var Validator = class {
110
135
  */
111
136
  static builtInConverter(value) {
112
137
  if (typeof value !== "string") {
113
- throw new EnvaptError(EnvaptErrorCodes.InvalidConverterType, `Expected string, got ${typeof value}`);
138
+ throw new EnvaptError(204 /* InvalidConverterType */, `Expected string, got ${typeof value}`);
114
139
  }
115
140
  if (!ListOfBuiltInConverters.includes(value)) {
116
141
  throw new EnvaptError(
117
- EnvaptErrorCodes.InvalidBuiltInConverter,
142
+ 202 /* InvalidBuiltInConverter */,
118
143
  `"${value}" is not a valid converter type. Valid types are: ${ListOfBuiltInConverters.join(",")}`
119
144
  );
120
145
  }
121
146
  }
147
+ /**
148
+ * Validate that fallback type matches the converter's return type for built-in converters
149
+ */
150
+ static validateBuiltInConverterFallback(converter, fallback) {
151
+ const typeChecker = BuiltInConverterTypeCheckers[converter];
152
+ if (!typeChecker(fallback)) {
153
+ throw new EnvaptError(
154
+ 104 /* FallbackConverterTypeMismatch */,
155
+ `Fallback type does not match converter "${converter}". Expected ${converter} compatible type.`
156
+ );
157
+ }
158
+ }
159
+ /**
160
+ * Validate that all elements in an array fallback have consistent types
161
+ */
162
+ static validateArrayFallbackElementTypes(fallback) {
163
+ if (fallback.length === 0) return;
164
+ const firstElementType = typeof fallback[0];
165
+ const hasInconsistentTypes = fallback.some((element, index) => {
166
+ if (index === 0) return false;
167
+ return typeof element !== firstElementType;
168
+ });
169
+ if (hasInconsistentTypes) {
170
+ throw new EnvaptError(
171
+ 103 /* ArrayFallbackElementTypeMismatch */,
172
+ `All elements in array fallback must have the same type. Found mixed types.`
173
+ );
174
+ }
175
+ }
176
+ /**
177
+ * Validate that array converter type matches fallback element types
178
+ */
179
+ static validateArrayConverterElementTypeMatch(converterType, fallback) {
180
+ if (fallback.length === 0) return;
181
+ const firstElement = fallback[0];
182
+ const typeChecker = BuiltInConverterTypeCheckers[converterType];
183
+ if (!typeChecker(firstElement)) {
184
+ throw new EnvaptError(
185
+ 103 /* ArrayFallbackElementTypeMismatch */,
186
+ `Array converter type "${converterType}" does not match fallback element type. Expected ${converterType} compatible elements.`
187
+ );
188
+ }
189
+ }
190
+ /**
191
+ * Check if a value is a primitive constructor
192
+ */
193
+ static isPrimitiveConstructor(value) {
194
+ return value === String || value === Number || value === Boolean || value === BigInt || value === Symbol;
195
+ }
196
+ /**
197
+ * Safely coerce a fallback value using a primitive constructor
198
+ */
199
+ static coercePrimitiveFallback(converter, fallback) {
200
+ if (this.isCorrectPrimitiveType(converter, fallback)) return fallback;
201
+ return this.performPrimitiveCoercion(converter, fallback);
202
+ }
203
+ /**
204
+ * Check if fallback is already the correct primitive type
205
+ */
206
+ static isCorrectPrimitiveType(converter, fallback) {
207
+ if (converter === String && typeof fallback === "string") return true;
208
+ if (converter === Number && typeof fallback === "number") return true;
209
+ if (converter === Boolean && typeof fallback === "boolean") return true;
210
+ if (converter === BigInt && typeof fallback === "bigint") return true;
211
+ if (converter === Symbol && typeof fallback === "symbol") return true;
212
+ return false;
213
+ }
214
+ /**
215
+ * Perform the actual primitive coercion
216
+ */
217
+ static performPrimitiveCoercion(converter, fallback) {
218
+ try {
219
+ if (converter === String) return String(fallback);
220
+ if (converter === Number) return Number(fallback);
221
+ if (converter === Boolean) return Boolean(fallback);
222
+ if (converter === BigInt) return BigInt(fallback);
223
+ if (converter === Symbol) return Symbol(fallback);
224
+ } catch (error) {
225
+ throw new EnvaptError(
226
+ 205 /* PrimitiveCoercionFailed */,
227
+ `Failed to coerce fallback value using ${converter.name}: ${error.message}`
228
+ );
229
+ }
230
+ throw new EnvaptError(205 /* PrimitiveCoercionFailed */, `Unknown primitive converter: ${converter.name}`);
231
+ }
232
+ /**
233
+ * Make sure the user hasn't provided prohibited options in their dotenv config
234
+ */
235
+ static validateDotenvConfig(config2) {
236
+ if ("path" in config2 || "processEnv" in config2) {
237
+ throw new EnvaptError(
238
+ 302 /* InvalidUserDefinedConfig */,
239
+ 'Custom dotenvConfig should not include "path" or "processEnv" options. Those are managed by Envapter.'
240
+ );
241
+ }
242
+ const validKeys = /* @__PURE__ */ new Set(["encoding", "quiet", "debug", "override", "DOTENV_KEY"]);
243
+ const invalidKeys = Object.keys(config2).filter((key) => !validKeys.has(key));
244
+ if (invalidKeys.length > 0) {
245
+ throw new EnvaptError(
246
+ 302 /* InvalidUserDefinedConfig */,
247
+ `Invalid dotenvConfig options: ${invalidKeys.join(", ")}. Allowed options: ${Array.from(validKeys).join(", ")}`
248
+ );
249
+ }
250
+ return true;
251
+ }
252
+ /**
253
+ * Check if each provided path resolves to an env file by trying to access it
254
+ */
255
+ static validateEnvFilesExist(paths) {
256
+ const missing = paths.filter((p) => {
257
+ try {
258
+ fs__default.default.accessSync(p, fs__default.default.constants.F_OK);
259
+ return false;
260
+ } catch {
261
+ return true;
262
+ }
263
+ });
264
+ if (missing.length > 0) {
265
+ throw new EnvaptError(
266
+ 303 /* EnvFilesNotFound */,
267
+ `Environment file not found at path: ${missing.join(", ")}`
268
+ );
269
+ }
270
+ }
271
+ };
272
+
273
+ // src/core/EnvapterBase.ts
274
+ var EnvaptCache = /* @__PURE__ */ new Map();
275
+ var EnvapterBase = class _EnvapterBase {
276
+ static {
277
+ __name(this, "EnvapterBase");
278
+ }
279
+ static _envPaths = [".env"];
280
+ // default path
281
+ static _userDefinedDotenvConfig = { quiet: true };
282
+ /**
283
+ * Set custom .env file paths. Accepts either a single path or array of paths.
284
+ * Setting new paths clears the cache and reloads environment variables.
285
+ */
286
+ static set envPaths(paths) {
287
+ const newPaths = Array.isArray(paths) ? paths : [paths];
288
+ Validator.validateEnvFilesExist(newPaths);
289
+ this._envPaths = newPaths;
290
+ this.refreshCache();
291
+ }
292
+ /**
293
+ * Get currently configured .env file paths
294
+ */
295
+ static get envPaths() {
296
+ return this._envPaths;
297
+ }
298
+ /**
299
+ * Set custom dotenv configuration options.
300
+ */
301
+ static set dotenvConfig(config2) {
302
+ Validator.validateDotenvConfig(config2);
303
+ this._userDefinedDotenvConfig = config2;
304
+ this.refreshCache();
305
+ }
306
+ /**
307
+ * Get current dotenv configuration options
308
+ */
309
+ static get dotenvConfig() {
310
+ return this._userDefinedDotenvConfig;
311
+ }
312
+ static refreshCache() {
313
+ EnvaptCache.clear();
314
+ void this.config;
315
+ }
316
+ static get config() {
317
+ if (EnvaptCache.size === 0) {
318
+ const isolatedEnv = { ...process.env };
319
+ try {
320
+ dotenv.config({ path: this._envPaths, processEnv: isolatedEnv, ...this._userDefinedDotenvConfig });
321
+ } catch {
322
+ }
323
+ for (const [key, value] of Object.entries(isolatedEnv)) EnvaptCache.set(key, value);
324
+ }
325
+ return EnvaptCache;
326
+ }
327
+ /**
328
+ * Get raw environment variable value without parsing or conversion.
329
+ */
330
+ getRaw(key) {
331
+ return _EnvapterBase.config.get(key);
332
+ }
122
333
  };
123
334
 
124
335
  // src/BuiltInConverters.ts
@@ -127,15 +338,13 @@ var BuiltInConverters = class _BuiltInConverters {
127
338
  __name(this, "BuiltInConverters");
128
339
  }
129
340
  static string(raw, fallback) {
130
- return raw ?? fallback;
341
+ return String(raw) || fallback;
131
342
  }
132
343
  static number(raw, fallback) {
133
- if (raw === void 0) return fallback;
134
344
  const parsed = Number(raw);
135
345
  return Number.isNaN(parsed) ? fallback : parsed;
136
346
  }
137
347
  static boolean(raw, fallback) {
138
- if (raw === void 0) return fallback;
139
348
  const lower = raw.toLowerCase().trim();
140
349
  const truthyValues = ["1", "yes", "true", "on"];
141
350
  const falsyValues = ["0", "no", "false", "off"];
@@ -144,7 +353,6 @@ var BuiltInConverters = class _BuiltInConverters {
144
353
  return fallback;
145
354
  }
146
355
  static bigint(raw, fallback) {
147
- if (raw === void 0) return fallback;
148
356
  try {
149
357
  return BigInt(raw);
150
358
  } catch {
@@ -155,17 +363,14 @@ var BuiltInConverters = class _BuiltInConverters {
155
363
  return raw ? Symbol(raw) : fallback;
156
364
  }
157
365
  static integer(raw, fallback) {
158
- if (raw === void 0) return fallback;
159
366
  const parsed = parseInt(raw, 10);
160
367
  return Number.isNaN(parsed) ? fallback : parsed;
161
368
  }
162
369
  static float(raw, fallback) {
163
- if (raw === void 0) return fallback;
164
370
  const parsed = parseFloat(raw);
165
371
  return Number.isNaN(parsed) ? fallback : parsed;
166
372
  }
167
373
  static json(raw, fallback) {
168
- if (raw === void 0) return fallback;
169
374
  try {
170
375
  return JSON.parse(raw);
171
376
  } catch {
@@ -173,12 +378,11 @@ var BuiltInConverters = class _BuiltInConverters {
173
378
  }
174
379
  }
175
380
  static array(raw, fallback, delimiter = ",") {
176
- if (raw === void 0) return fallback;
177
381
  if (raw.trim() === "") return [];
178
- return raw.split(delimiter).map((item) => item.trim()).filter((item) => item.length > 0);
382
+ const arr = raw.split(delimiter).map((item) => item.trim()).filter(Boolean);
383
+ return arr.length ? arr : fallback;
179
384
  }
180
385
  static url(raw, fallback) {
181
- if (raw === void 0) return fallback;
182
386
  try {
183
387
  return new URL(raw);
184
388
  } catch {
@@ -186,7 +390,6 @@ var BuiltInConverters = class _BuiltInConverters {
186
390
  }
187
391
  }
188
392
  static regexp(raw, fallback) {
189
- if (raw === void 0) return fallback;
190
393
  try {
191
394
  const match = raw.match(/^\/(.+)\/([gimsuvy]*)$/);
192
395
  if (match) return new RegExp(match[1], match[2]);
@@ -196,7 +399,6 @@ var BuiltInConverters = class _BuiltInConverters {
196
399
  }
197
400
  }
198
401
  static date(raw, fallback) {
199
- if (raw === void 0) return fallback;
200
402
  if (/^\d+$/.test(raw)) {
201
403
  const timestamp = parseInt(raw, 10);
202
404
  const parsed2 = new Date(timestamp);
@@ -206,13 +408,13 @@ var BuiltInConverters = class _BuiltInConverters {
206
408
  return Number.isNaN(parsed.getTime()) ? fallback : parsed;
207
409
  }
208
410
  static time(raw, fallback) {
209
- if (raw === void 0) return fallback;
210
411
  const match = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/u);
211
412
  if (!match) return fallback;
212
- const [, numStr, unit = "ms"] = match;
413
+ const [, numStr, capturedUnit] = match;
213
414
  if (!numStr) return fallback;
214
415
  const value = Number.parseFloat(numStr);
215
416
  if (Number.isNaN(value)) return fallback;
417
+ const unit = capturedUnit ?? "ms";
216
418
  const SECONDS_TO_MS = 1e3;
217
419
  const SECONDS_PER_MINUTE = 60;
218
420
  const MINUTES_PER_HOUR = 60;
@@ -221,24 +423,18 @@ var BuiltInConverters = class _BuiltInConverters {
221
423
  if (unit === "ms") return value;
222
424
  if (unit === "s") return value * SECONDS_TO_MS;
223
425
  if (unit === "m") return value * MINUTES_TO_MS;
224
- if (unit === "h") return value * HOURS_TO_MS;
225
- return fallback;
426
+ return value * HOURS_TO_MS;
226
427
  }
227
428
  /**
228
429
  * Process array with custom converter config
229
430
  */
230
431
  static processArrayConverter(raw, fallback, config2) {
231
- if (raw === void 0) {
232
- if (Array.isArray(fallback)) return fallback;
233
- throw new EnvaptError(
234
- EnvaptErrorCodes.InvalidFallback,
235
- `ArrayConverter requires that the fallback be an array, got ${typeof fallback}`
236
- );
237
- }
238
432
  if (raw.trim() === "") return [];
239
433
  const items = raw.split(config2.delimiter).map((item) => String(item).trim()).filter(Boolean);
240
- if (!config2.type) return items;
241
- const converter = _BuiltInConverters.getConverter(config2.type);
434
+ if (!items.length) return fallback ? fallback : void 0;
435
+ const type = config2.type;
436
+ if (!type) return items;
437
+ const converter = _BuiltInConverters.getConverter(type);
242
438
  return items.map((item) => {
243
439
  const converted = converter(item, void 0);
244
440
  return converted ?? item;
@@ -263,11 +459,7 @@ var BuiltInConverters = class _BuiltInConverters {
263
459
  date: _BuiltInConverters.date,
264
460
  time: _BuiltInConverters.time
265
461
  };
266
- const converter = converters[type];
267
- if (!Validator.isValidConverterFunction(converter)) {
268
- throw new EnvaptError(EnvaptErrorCodes.InvalidBuiltInConverter, `Unknown built-in converter: ${type}`);
269
- }
270
- return converter;
462
+ return converters[type];
271
463
  }
272
464
  };
273
465
 
@@ -280,12 +472,14 @@ var Parser = class {
280
472
  __name(this, "Parser");
281
473
  }
282
474
  TEMPLATE_REGEX = /\${\w*}/g;
475
+ /**
476
+ * Resolve template variables in a string while handling circular references and missing variables
477
+ * @internal
478
+ */
283
479
  resolveTemplate(key, value, stack = /* @__PURE__ */ new Set()) {
284
- if (stack.has(key)) return value;
285
480
  stack.add(key);
286
481
  const out = value.replace(this.TEMPLATE_REGEX, (template) => {
287
482
  const variable = template.slice(2, -1);
288
- if (!variable) return template;
289
483
  if (stack.has(variable)) return template;
290
484
  const raw = this.envService.getRaw(variable);
291
485
  if (!raw || raw === "") return template;
@@ -297,27 +491,71 @@ var Parser = class {
297
491
  stack.delete(key);
298
492
  return out;
299
493
  }
300
- convertValue(key, fallback, converter, hasFallback = true) {
301
- let resolvedConverter = this.resolveConverter(converter, fallback);
302
- if (resolvedConverter === Number) resolvedConverter = "number";
303
- else if (resolvedConverter === Boolean) resolvedConverter = "boolean";
304
- else if (resolvedConverter === String) resolvedConverter = "string";
305
- else if (resolvedConverter === BigInt) resolvedConverter = "bigint";
306
- else if (resolvedConverter === Symbol) resolvedConverter = "symbol";
494
+ convertValue(key, fallback, converter, hasFallback) {
495
+ const resolvedConverter = this.resolveConverter(converter, fallback);
496
+ const processedFallback = this.processFallbackForConverter(resolvedConverter, fallback);
307
497
  if (Validator.isArrayConverter(resolvedConverter)) {
308
- Validator.arrayConverter(resolvedConverter);
309
- const parsed = this.envService.get(key, void 0);
310
- if (parsed === void 0) return hasFallback ? fallback : null;
311
- return BuiltInConverters.processArrayConverter(parsed, fallback, resolvedConverter);
498
+ return this.processArrayConverter(key, processedFallback, resolvedConverter, hasFallback);
499
+ }
500
+ if (Validator.isPrimitiveConstructor(resolvedConverter)) {
501
+ const stringConverter = this.convertPrimitiveToString(resolvedConverter);
502
+ return this.processBuiltInConverter(key, processedFallback, stringConverter, hasFallback, true);
312
503
  }
313
504
  if (Validator.isBuiltInConverter(resolvedConverter)) {
314
- Validator.builtInConverter(resolvedConverter);
315
- const parsed = this.envService.get(key, void 0);
316
- if (parsed === void 0) return hasFallback ? fallback : null;
317
- const converterFn = BuiltInConverters.getConverter(resolvedConverter);
318
- const result = converterFn(parsed, fallback);
319
- return result;
505
+ return this.processBuiltInConverter(key, processedFallback, resolvedConverter, hasFallback, false);
506
+ }
507
+ return this.processCustomConverter(key, processedFallback, resolvedConverter, hasFallback);
508
+ }
509
+ processFallbackForConverter(converter, fallback) {
510
+ if (Validator.isPrimitiveConstructor(converter) && fallback !== void 0) {
511
+ return Validator.coercePrimitiveFallback(converter, fallback);
512
+ }
513
+ return fallback;
514
+ }
515
+ convertPrimitiveToString(primitiveConstructor) {
516
+ if (primitiveConstructor === String) return "string";
517
+ if (primitiveConstructor === Number) return "number";
518
+ if (primitiveConstructor === Boolean) return "boolean";
519
+ if (primitiveConstructor === BigInt) return "bigint";
520
+ if (primitiveConstructor === Symbol) return "symbol";
521
+ throw new EnvaptError(204 /* InvalidConverterType */, `Unknown primitive constructor`);
522
+ }
523
+ processBuiltInConverter(key, fallback, resolvedConverter, hasFallback, wasOriginallyConstructor) {
524
+ Validator.builtInConverter(resolvedConverter);
525
+ if (hasFallback && fallback !== void 0 && !wasOriginallyConstructor) {
526
+ Validator.validateBuiltInConverterFallback(resolvedConverter, fallback);
527
+ if (resolvedConverter === "array" && Array.isArray(fallback)) {
528
+ Validator.validateArrayFallbackElementTypes(fallback);
529
+ }
320
530
  }
531
+ const parsed = this.envService.get(key, void 0);
532
+ if (parsed === void 0) return hasFallback ? fallback : null;
533
+ const converterFn = BuiltInConverters.getConverter(resolvedConverter);
534
+ const result = converterFn(parsed, fallback);
535
+ if (result === void 0 && !hasFallback) return null;
536
+ return result;
537
+ }
538
+ processArrayConverter(key, fallback, resolvedConverter, hasFallback) {
539
+ Validator.arrayConverter(resolvedConverter);
540
+ if (hasFallback && fallback !== void 0 && !Array.isArray(fallback)) {
541
+ throw new EnvaptError(
542
+ 101 /* InvalidFallback */,
543
+ `ArrayConverter requires that the fallback be an array, got ${typeof fallback}`
544
+ );
545
+ }
546
+ if (hasFallback && Array.isArray(fallback)) {
547
+ Validator.validateArrayFallbackElementTypes(fallback);
548
+ if (resolvedConverter.type) {
549
+ Validator.validateArrayConverterElementTypeMatch(resolvedConverter.type, fallback);
550
+ }
551
+ }
552
+ const parsed = this.envService.get(key, void 0);
553
+ if (parsed === void 0) return hasFallback ? fallback : null;
554
+ const result = BuiltInConverters.processArrayConverter(parsed, fallback, resolvedConverter);
555
+ if (result === void 0 && !hasFallback) return null;
556
+ return result;
557
+ }
558
+ processCustomConverter(key, fallback, resolvedConverter, hasFallback) {
321
559
  Validator.customConvertor(resolvedConverter);
322
560
  const raw = this.envService.get(key, void 0);
323
561
  if (raw === void 0) return hasFallback ? fallback : null;
@@ -334,253 +572,230 @@ var Parser = class {
334
572
  }
335
573
  };
336
574
 
337
- // src/Envapter.ts
338
- var EnvaptCache = /* @__PURE__ */ new Map();
575
+ // src/core/EnvironmentMethods.ts
339
576
  var Environment = /* @__PURE__ */ ((Environment2) => {
340
577
  Environment2[Environment2["Development"] = 0] = "Development";
341
578
  Environment2[Environment2["Staging"] = 1] = "Staging";
342
579
  Environment2[Environment2["Production"] = 2] = "Production";
343
580
  return Environment2;
344
581
  })(Environment || {});
345
- var Envapter = class _Envapter {
582
+ var EnvironmentMethods = class _EnvironmentMethods extends EnvapterBase {
346
583
  static {
347
- __name(this, "Envapter");
584
+ __name(this, "EnvironmentMethods");
348
585
  }
349
- static parser = new Parser(new _Envapter());
350
- static _envPaths = [".env"];
351
- // default path
352
- // Environment handling
353
- static internalEnvironment = this.determineEnvironment(
354
- this.get("ENVIRONMENT", this.get("ENV", this.get("NODE_ENV", "development")))
355
- );
356
- /**
357
- * Set custom .env file paths. Accepts either a single path or array of paths.
358
- * Setting new paths clears the cache and reloads environment variables.
359
- *
360
- * @param paths - Single file path or array of file paths to load
361
- *
362
- * @example
363
- * ```ts
364
- * // Single file
365
- * Envapter.envPaths = '.env.production';
366
- *
367
- * // Multiple files (loaded in order)
368
- * Envapter.envPaths = ['.env', '.env.local', '.env.production'];
369
- * ```
370
- */
371
- static set envPaths(paths) {
372
- this._envPaths = Array.isArray(paths) ? paths : [paths];
373
- EnvaptCache.clear();
374
- void this.config;
375
- this.internalEnvironment = this.determineEnvironment(
376
- this.get("ENVIRONMENT", this.get("ENV", this.get("NODE_ENV", "development")))
377
- );
586
+ static _environment;
587
+ static determineEnvironment(env) {
588
+ const environment = env ?? this.getRawValue("ENVIRONMENT", this.getRawValue("ENV", this.getRawValue("NODE_ENV", "development")));
589
+ if (typeof environment === "string") {
590
+ this._environment = environment.toLowerCase() === "production" ? 2 /* Production */ : environment === "staging" ? 1 /* Staging */ : 0 /* Development */;
591
+ } else {
592
+ this._environment = environment;
593
+ }
594
+ }
595
+ static getRawValue(key, fallback) {
596
+ return this.config.get(key) || fallback;
378
597
  }
379
598
  /**
380
- * Get currently configured .env file paths
381
- * @returns Array of file paths being loaded
599
+ * Get the current application environment
382
600
  */
383
- static get envPaths() {
384
- return this._envPaths;
385
- }
386
- static determineEnvironment(env) {
387
- if (typeof env === "string") {
388
- switch (env.toLowerCase()) {
389
- case "production":
390
- return 2 /* Production */;
391
- case "staging":
392
- return 1 /* Staging */;
393
- default:
394
- return 0 /* Development */;
395
- }
601
+ static get environment() {
602
+ if (this._environment === void 0) {
603
+ this.determineEnvironment();
396
604
  }
397
- return env;
605
+ return this._environment;
398
606
  }
399
607
  /**
400
608
  * Set the application environment. Accepts either Environment enum or string value.
401
- *
402
- * @param env - Environment value ('development', 'staging', 'production') or Environment enum
403
- *
404
- * @example
405
- * ```ts
406
- * Envapter.environment = Environment.Production;
407
- * Envapter.environment = 'staging';
408
- * ```
409
609
  */
410
610
  static set environment(env) {
411
- this.internalEnvironment = this.determineEnvironment(env);
611
+ this.determineEnvironment(env);
412
612
  }
413
613
  /**
414
- * Get the current application environment
415
- * @returns Current environment enum value
614
+ * @see {@link EnvironmentMethods.environment}
416
615
  */
417
- static get environment() {
418
- return this.internalEnvironment;
616
+ get environment() {
617
+ return _EnvironmentMethods.environment;
618
+ }
619
+ /**
620
+ * @see {@link EnvironmentMethods.environment}
621
+ */
622
+ set environment(env) {
623
+ _EnvironmentMethods.determineEnvironment(env);
419
624
  }
420
625
  /**
421
626
  * Check if the current environment is production
422
- * @returns true if environment is production
423
627
  */
424
628
  static get isProduction() {
425
- return this.internalEnvironment === 2 /* Production */;
629
+ return this.environment === 2 /* Production */;
630
+ }
631
+ /**
632
+ * @see {@link EnvironmentMethods.isProduction}
633
+ */
634
+ get isProduction() {
635
+ return _EnvironmentMethods.environment === 2 /* Production */;
426
636
  }
427
637
  /**
428
638
  * Check if the current environment is staging
429
- * @returns true if environment is staging
430
639
  */
431
640
  static get isStaging() {
432
- return this.internalEnvironment === 1 /* Staging */;
641
+ return this.environment === 1 /* Staging */;
642
+ }
643
+ /**
644
+ * @see {@link EnvironmentMethods.isStaging}
645
+ */
646
+ get isStaging() {
647
+ return _EnvironmentMethods.environment === 1 /* Staging */;
433
648
  }
434
649
  /**
435
650
  * Check if the current environment is development
436
- * @returns true if environment is development
437
651
  */
438
652
  static get isDevelopment() {
439
- return this.internalEnvironment === 0 /* Development */;
653
+ return this.environment === 0 /* Development */;
440
654
  }
441
- static get config() {
442
- if (EnvaptCache.size === 0) {
443
- const isolatedEnv = { ...process.env };
444
- try {
445
- dotenv.config({ path: this._envPaths, quiet: true, processEnv: isolatedEnv });
446
- } catch {
447
- }
448
- for (const [key, value] of Object.entries(isolatedEnv)) EnvaptCache.set(key, value);
449
- }
450
- return EnvaptCache;
655
+ /**
656
+ * @see {@link EnvironmentMethods.isDevelopment}
657
+ */
658
+ get isDevelopment() {
659
+ return _EnvironmentMethods.environment === 0 /* Development */;
660
+ }
661
+ static refreshCache() {
662
+ super.refreshCache();
663
+ this._environment = void 0;
664
+ }
665
+ };
666
+
667
+ // src/core/PrimitiveMethods.ts
668
+ var PrimitiveMethods = class _PrimitiveMethods extends EnvironmentMethods {
669
+ static {
670
+ __name(this, "PrimitiveMethods");
451
671
  }
452
- static _get(key, type = 0 /* String */, def) {
672
+ static parser = new Parser(new _PrimitiveMethods());
673
+ static _get(key, type, def) {
453
674
  const rawVal = this.config.get(key);
454
675
  if (!rawVal) return def;
455
676
  const parsed = this.parser.resolveTemplate(key, String(rawVal));
456
- switch (type) {
457
- case 0 /* String */: {
458
- return BuiltInConverters.string(parsed, def);
459
- }
460
- case 1 /* Number */: {
461
- return BuiltInConverters.number(parsed, def);
462
- }
463
- case 2 /* Boolean */: {
464
- return BuiltInConverters.boolean(parsed, def);
465
- }
466
- case 3 /* BigInt */: {
467
- return BuiltInConverters.bigint(parsed, def);
468
- }
469
- case 4 /* Symbol */: {
470
- return BuiltInConverters.symbol(parsed, def);
471
- }
472
- default: {
473
- return BuiltInConverters.string(parsed, def);
474
- }
475
- }
677
+ let result;
678
+ if (type === 1 /* Number */) result = BuiltInConverters.number(parsed, def);
679
+ else if (type === 2 /* Boolean */) result = BuiltInConverters.boolean(parsed, def);
680
+ else if (type === 3 /* BigInt */) result = BuiltInConverters.bigint(parsed, def);
681
+ else if (type === 4 /* Symbol */) result = BuiltInConverters.symbol(parsed, def);
682
+ else result = BuiltInConverters.string(parsed, def);
683
+ return result;
476
684
  }
477
685
  /**
478
686
  * Get a string environment variable with optional fallback.
479
687
  * Supports template variable resolution using ${VAR} syntax.
480
- *
481
- * @param key - Environment variable name
482
- * @param def - Default value if variable is not found
483
- * @returns The environment variable value or default
484
- *
485
- * @example
486
- * ```ts
487
- * const apiUrl = Envapter.get('API_URL', 'http://localhost:3000');
488
- * ```
489
688
  */
490
689
  static get(key, def) {
491
690
  return this._get(key, 0 /* String */, def);
492
691
  }
692
+ /**
693
+ * @see {@link PrimitiveMethods.get}
694
+ */
695
+ get(key, def) {
696
+ return _PrimitiveMethods._get(key, 0 /* String */, def);
697
+ }
493
698
  /**
494
699
  * Get a number environment variable with optional fallback.
495
700
  * Automatically converts string values to numbers.
496
- *
497
- * @param key - Environment variable name
498
- * @param def - Default value if variable is not found or cannot be converted
499
- * @returns The environment variable value as number or default
500
- *
501
- * @example
502
- * ```ts
503
- * const port = Envapter.getNumber('PORT', 3000);
504
- * ```
505
701
  */
506
702
  static getNumber(key, def) {
507
703
  return this._get(key, 1 /* Number */, def);
508
704
  }
705
+ /**
706
+ * @see {@link PrimitiveMethods.getNumber}
707
+ */
708
+ getNumber(key, def) {
709
+ return _PrimitiveMethods._get(key, 1 /* Number */, def);
710
+ }
509
711
  /**
510
712
  * Get a boolean environment variable with optional fallback.
511
- * Recognizes: `1`, `yes`, `true` as **true**; `0`, `no`, `false` as **false** (case-insensitive).
512
- *
513
- * @param key - Environment variable name
514
- * @param def - Default value if variable is not found or cannot be converted
515
- * @returns The environment variable value as boolean or default
516
- *
517
- * @example
518
- * ```ts
519
- * const isProduction = Envapter.getBoolean('IS_PRODUCTION', false);
520
- * ```
713
+ * Recognizes: `1`, `yes`, `true`, 'on' as **true**; `0`, `no`, `false`, 'off' as **false** (case-insensitive).
521
714
  */
522
715
  static getBoolean(key, def) {
523
716
  return this._get(key, 2 /* Boolean */, def);
524
717
  }
718
+ /**
719
+ * @see {@link PrimitiveMethods.getBoolean}
720
+ */
721
+ getBoolean(key, def) {
722
+ return _PrimitiveMethods._get(key, 2 /* Boolean */, def);
723
+ }
525
724
  /**
526
725
  * Get a bigint environment variable with optional fallback.
527
726
  * Automatically converts string values to bigint.
528
- *
529
- * @param key - Environment variable name
530
- * @param def - Default value if variable is not found or cannot be converted
531
- * @returns The environment variable value as bigint or default
532
- *
533
- * @example
534
- * ```ts
535
- * const largeNumber = Envapter.getBigInt('LARGE_NUMBER', 123456789012345678901234567890n);
536
- * ```
537
727
  */
538
728
  static getBigInt(key, def) {
539
729
  return this._get(key, 3 /* BigInt */, def);
540
730
  }
731
+ /**
732
+ * @see {@link PrimitiveMethods.getBigInt}
733
+ */
734
+ getBigInt(key, def) {
735
+ return _PrimitiveMethods._get(key, 3 /* BigInt */, def);
736
+ }
541
737
  /**
542
738
  * Get a symbol environment variable with optional fallback.
543
739
  * Creates a symbol from the string value.
544
- *
545
- * @param key - Environment variable name
546
- * @param def - Default value if variable is not found
547
- * @returns The environment variable value as symbol or default
548
- *
549
- * @example
550
- * ```ts
551
- * const uniqueKey = Envapter.getSymbol('UNIQUE_KEY', Symbol('default'));
552
- * ```
553
740
  */
554
741
  static getSymbol(key, def) {
555
742
  return this._get(key, 4 /* Symbol */, def);
556
743
  }
557
- get(key, def) {
558
- return _Envapter._get(key, 0 /* String */, def);
744
+ /**
745
+ * @see {@link PrimitiveMethods.getSymbol}
746
+ */
747
+ getSymbol(key, def) {
748
+ return _PrimitiveMethods._get(key, 4 /* Symbol */, def);
559
749
  }
560
- getNumber(key, def) {
561
- return _Envapter._get(key, 1 /* Number */, def);
750
+ };
751
+
752
+ // src/core/AdvancedMethods.ts
753
+ var AdvancedMethods = class _AdvancedMethods extends PrimitiveMethods {
754
+ static {
755
+ __name(this, "AdvancedMethods");
562
756
  }
563
- getBoolean(key, def) {
564
- return _Envapter._get(key, 2 /* Boolean */, def);
757
+ static getUsing(key, converter, fallback) {
758
+ const rawVal = this.config.get(key);
759
+ if (!rawVal) return fallback;
760
+ const hasFallback = fallback !== void 0;
761
+ const result = this.parser.convertValue(key, fallback, converter, hasFallback);
762
+ return result;
565
763
  }
566
- getBigInt(key, def) {
567
- return _Envapter._get(key, 3 /* BigInt */, def);
764
+ getUsing(key, converter, fallback) {
765
+ return _AdvancedMethods.getUsing(key, converter, fallback);
568
766
  }
569
- getSymbol(key, def) {
570
- return _Envapter._get(key, 4 /* Symbol */, def);
767
+ /**
768
+ * Get an environment variable using a custom converter function.
769
+ */
770
+ static getWith(key, converter, fallback) {
771
+ const rawVal = this.config.get(key);
772
+ if (!rawVal) return fallback;
773
+ const hasFallback = fallback !== void 0;
774
+ const result = this.parser.convertValue(
775
+ key,
776
+ fallback,
777
+ converter,
778
+ hasFallback
779
+ );
780
+ return result;
571
781
  }
572
782
  /**
573
- * Get raw environment variable value without parsing or conversion.
574
- *
575
- * @internal
783
+ * @see {@link AdvancedMethods.getWith}
576
784
  */
577
- getRaw(key) {
578
- return _Envapter.config.get(key);
785
+ getWith(key, converter, fallback) {
786
+ return _AdvancedMethods.getWith(key, converter, fallback);
787
+ }
788
+ };
789
+
790
+ // src/Envapter.ts
791
+ var Envapter = class extends AdvancedMethods {
792
+ static {
793
+ __name(this, "Envapter");
579
794
  }
580
795
  };
581
796
 
582
797
  // src/Envapt.ts
583
- function createPropertyDecorator(key, fallback, converter, hasFallback = true) {
798
+ function createPropertyDecorator(key, fallback, converter, hasFallback) {
584
799
  return function(target, prop) {
585
800
  const propKey = String(prop);
586
801
  const cacheKey = `${target.constructor.name}.${propKey}`;
@@ -618,7 +833,27 @@ function Envapt(key, fallbackOrOptions, converter) {
618
833
  }
619
834
  __name(Envapt, "Envapt");
620
835
 
836
+ // src/Converters.ts
837
+ var Converters = /* @__PURE__ */ ((Converters2) => {
838
+ Converters2["String"] = "string";
839
+ Converters2["Number"] = "number";
840
+ Converters2["Boolean"] = "boolean";
841
+ Converters2["Bigint"] = "bigint";
842
+ Converters2["Symbol"] = "symbol";
843
+ Converters2["Integer"] = "integer";
844
+ Converters2["Float"] = "float";
845
+ Converters2["Json"] = "json";
846
+ Converters2["Array"] = "array";
847
+ Converters2["Url"] = "url";
848
+ Converters2["Regexp"] = "regexp";
849
+ Converters2["Date"] = "date";
850
+ Converters2["Time"] = "time";
851
+ return Converters2;
852
+ })(Converters || {});
853
+
854
+ exports.Converters = Converters;
621
855
  exports.Envapt = Envapt;
856
+ exports.EnvaptErrorCodes = EnvaptErrorCodes;
622
857
  exports.Envapter = Envapter;
623
858
  exports.Environment = Environment;
624
859
  //# sourceMappingURL=index.cjs.map