envapt 1.1.0 → 2.0.0

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