envapt 1.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 ADDED
@@ -0,0 +1,625 @@
1
+ 'use strict';
2
+
3
+ var dotenv = require('dotenv');
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+
8
+ // 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
+ );
20
+ var EnvaptError = class _EnvaptError extends Error {
21
+ static {
22
+ __name(this, "EnvaptError");
23
+ }
24
+ code;
25
+ constructor(code, message) {
26
+ super(message);
27
+ this.name = `${ReversedEnvaptErrorCodes[code]} [${code}]`;
28
+ this.code = code;
29
+ Error.captureStackTrace(this, _EnvaptError);
30
+ }
31
+ };
32
+
33
+ // src/ListOfBuiltInConverters.ts
34
+ var ListOfBuiltInConverters = [
35
+ "string",
36
+ "number",
37
+ "boolean",
38
+ "bigint",
39
+ "symbol",
40
+ "integer",
41
+ "float",
42
+ "json",
43
+ "array",
44
+ "url",
45
+ "regexp",
46
+ "date",
47
+ "time"
48
+ ];
49
+
50
+ // src/Validators.ts
51
+ var Validator = class {
52
+ static {
53
+ __name(this, "Validator");
54
+ }
55
+ /**
56
+ * Check if a value is a built-in converter type
57
+ */
58
+ static isBuiltInConverter(value) {
59
+ if (typeof value === "string") return ListOfBuiltInConverters.includes(value);
60
+ return false;
61
+ }
62
+ /**
63
+ * Check if a value is an ArrayConverter configuration object
64
+ */
65
+ static isArrayConverter(value) {
66
+ return typeof value === "object" && value !== null && "delimiter" in value && typeof value.delimiter === "string";
67
+ }
68
+ /**
69
+ * Check if a value is a valid ArrayConverter type
70
+ */
71
+ static isValidArrayConverterType(value) {
72
+ if (typeof value !== "string") return false;
73
+ const invalidTypes = ["array", "json", "regexp"];
74
+ if (invalidTypes.includes(value)) return false;
75
+ const validTypes = ListOfBuiltInConverters.filter(
76
+ (type) => !invalidTypes.includes(type)
77
+ );
78
+ return validTypes.includes(value);
79
+ }
80
+ /**
81
+ * Check if a value is a valid custom converter function
82
+ */
83
+ static isValidConverterFunction(converter) {
84
+ return typeof converter === "function";
85
+ }
86
+ static customConvertor(converter) {
87
+ if (typeof converter !== "function") {
88
+ throw new EnvaptError(
89
+ EnvaptErrorCodes.InvalidCustomConverter,
90
+ `Custom converter must be a function, got ${typeof converter}.`
91
+ );
92
+ }
93
+ }
94
+ /**
95
+ * Validate ArrayConverter configuration with runtime checks
96
+ */
97
+ static arrayConverter(value) {
98
+ if (!this.isArrayConverter(value)) {
99
+ throw new EnvaptError(EnvaptErrorCodes.MissingDelimiter, "Must have delimiter property");
100
+ }
101
+ if (value.type !== void 0 && !this.isValidArrayConverterType(value.type)) {
102
+ throw new EnvaptError(
103
+ EnvaptErrorCodes.InvalidArrayConverterType,
104
+ `"${value.type}" is not a valid converter type`
105
+ );
106
+ }
107
+ }
108
+ /**
109
+ * Validate that a string is a valid built-in converter type
110
+ */
111
+ static builtInConverter(value) {
112
+ if (typeof value !== "string") {
113
+ throw new EnvaptError(EnvaptErrorCodes.InvalidConverterType, `Expected string, got ${typeof value}`);
114
+ }
115
+ if (!ListOfBuiltInConverters.includes(value)) {
116
+ throw new EnvaptError(
117
+ EnvaptErrorCodes.InvalidBuiltInConverter,
118
+ `"${value}" is not a valid converter type. Valid types are: ${ListOfBuiltInConverters.join(",")}`
119
+ );
120
+ }
121
+ }
122
+ };
123
+
124
+ // src/BuiltInConverters.ts
125
+ var BuiltInConverters = class _BuiltInConverters {
126
+ static {
127
+ __name(this, "BuiltInConverters");
128
+ }
129
+ static string(raw, fallback) {
130
+ return raw ?? fallback;
131
+ }
132
+ static number(raw, fallback) {
133
+ if (raw === void 0) return fallback;
134
+ const parsed = Number(raw);
135
+ return Number.isNaN(parsed) ? fallback : parsed;
136
+ }
137
+ static boolean(raw, fallback) {
138
+ if (raw === void 0) return fallback;
139
+ const lower = raw.toLowerCase().trim();
140
+ const truthyValues = ["1", "yes", "true", "on"];
141
+ const falsyValues = ["0", "no", "false", "off"];
142
+ if (truthyValues.includes(lower)) return true;
143
+ if (falsyValues.includes(lower)) return false;
144
+ return fallback;
145
+ }
146
+ static bigint(raw, fallback) {
147
+ if (raw === void 0) return fallback;
148
+ try {
149
+ return BigInt(raw);
150
+ } catch {
151
+ return fallback;
152
+ }
153
+ }
154
+ static symbol(raw, fallback) {
155
+ return raw ? Symbol(raw) : fallback;
156
+ }
157
+ static integer(raw, fallback) {
158
+ if (raw === void 0) return fallback;
159
+ const parsed = parseInt(raw, 10);
160
+ return Number.isNaN(parsed) ? fallback : parsed;
161
+ }
162
+ static float(raw, fallback) {
163
+ if (raw === void 0) return fallback;
164
+ const parsed = parseFloat(raw);
165
+ return Number.isNaN(parsed) ? fallback : parsed;
166
+ }
167
+ static json(raw, fallback) {
168
+ if (raw === void 0) return fallback;
169
+ try {
170
+ return JSON.parse(raw);
171
+ } catch {
172
+ return fallback;
173
+ }
174
+ }
175
+ static array(raw, fallback, delimiter = ",") {
176
+ if (raw === void 0) return fallback;
177
+ if (raw.trim() === "") return [];
178
+ return raw.split(delimiter).map((item) => item.trim()).filter((item) => item.length > 0);
179
+ }
180
+ static url(raw, fallback) {
181
+ if (raw === void 0) return fallback;
182
+ try {
183
+ return new URL(raw);
184
+ } catch {
185
+ return fallback;
186
+ }
187
+ }
188
+ static regexp(raw, fallback) {
189
+ if (raw === void 0) return fallback;
190
+ try {
191
+ const match = raw.match(/^\/(.+)\/([gimsuvy]*)$/);
192
+ if (match) return new RegExp(match[1], match[2]);
193
+ return new RegExp(raw);
194
+ } catch {
195
+ return fallback;
196
+ }
197
+ }
198
+ static date(raw, fallback) {
199
+ if (raw === void 0) return fallback;
200
+ if (/^\d+$/.test(raw)) {
201
+ const timestamp = parseInt(raw, 10);
202
+ const parsed2 = new Date(timestamp);
203
+ return Number.isNaN(parsed2.getTime()) ? fallback : parsed2;
204
+ }
205
+ const parsed = new Date(raw);
206
+ return Number.isNaN(parsed.getTime()) ? fallback : parsed;
207
+ }
208
+ static time(raw, fallback) {
209
+ if (raw === void 0) return fallback;
210
+ const match = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/u);
211
+ if (!match) return fallback;
212
+ const [, numStr, unit = "ms"] = match;
213
+ if (!numStr) return fallback;
214
+ const value = Number.parseFloat(numStr);
215
+ if (Number.isNaN(value)) return fallback;
216
+ const SECONDS_TO_MS = 1e3;
217
+ const SECONDS_PER_MINUTE = 60;
218
+ const MINUTES_PER_HOUR = 60;
219
+ const MINUTES_TO_MS = SECONDS_PER_MINUTE * SECONDS_TO_MS;
220
+ const HOURS_TO_MS = MINUTES_PER_HOUR * MINUTES_TO_MS;
221
+ if (unit === "ms") return value;
222
+ if (unit === "s") return value * SECONDS_TO_MS;
223
+ if (unit === "m") return value * MINUTES_TO_MS;
224
+ if (unit === "h") return value * HOURS_TO_MS;
225
+ return fallback;
226
+ }
227
+ /**
228
+ * Process array with custom converter config
229
+ */
230
+ 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
+ if (raw.trim() === "") return [];
239
+ 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);
242
+ return items.map((item) => {
243
+ const converted = converter(item, void 0);
244
+ return converted ?? item;
245
+ });
246
+ }
247
+ /**
248
+ * Get the converter function for a built-in converter type
249
+ */
250
+ static getConverter(type) {
251
+ const converters = {
252
+ string: _BuiltInConverters.string,
253
+ number: _BuiltInConverters.number,
254
+ boolean: _BuiltInConverters.boolean,
255
+ integer: _BuiltInConverters.integer,
256
+ bigint: _BuiltInConverters.bigint,
257
+ symbol: _BuiltInConverters.symbol,
258
+ float: _BuiltInConverters.float,
259
+ json: _BuiltInConverters.json,
260
+ array: _BuiltInConverters.array,
261
+ url: _BuiltInConverters.url,
262
+ regexp: _BuiltInConverters.regexp,
263
+ date: _BuiltInConverters.date,
264
+ time: _BuiltInConverters.time
265
+ };
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;
271
+ }
272
+ };
273
+
274
+ // src/Parser.ts
275
+ var Parser = class {
276
+ constructor(envService) {
277
+ this.envService = envService;
278
+ }
279
+ static {
280
+ __name(this, "Parser");
281
+ }
282
+ TEMPLATE_REGEX = /\${\w*}/g;
283
+ resolveTemplate(key, value, stack = /* @__PURE__ */ new Set()) {
284
+ if (stack.has(key)) return value;
285
+ stack.add(key);
286
+ const out = value.replace(this.TEMPLATE_REGEX, (template) => {
287
+ const variable = template.slice(2, -1);
288
+ if (!variable) return template;
289
+ if (stack.has(variable)) return template;
290
+ const raw = this.envService.getRaw(variable);
291
+ if (!raw || raw === "") return template;
292
+ const resolved = this.resolveTemplate(variable, raw, new Set(stack));
293
+ if (resolved.includes(`\${${key}}`)) return template;
294
+ if (resolved === raw && /\$\{[^}]*\}/.test(resolved)) return template;
295
+ return resolved;
296
+ });
297
+ stack.delete(key);
298
+ return out;
299
+ }
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";
307
+ 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);
312
+ }
313
+ 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;
320
+ }
321
+ Validator.customConvertor(resolvedConverter);
322
+ const raw = this.envService.get(key, void 0);
323
+ if (raw === void 0) return hasFallback ? fallback : null;
324
+ return resolvedConverter(raw, fallback);
325
+ }
326
+ resolveConverter(converter, fallback) {
327
+ if (converter) return converter;
328
+ const fallbackType = typeof fallback;
329
+ if (fallbackType === "number") return "number";
330
+ if (fallbackType === "boolean") return "boolean";
331
+ if (fallbackType === "bigint") return "bigint";
332
+ if (fallbackType === "symbol") return "symbol";
333
+ return "string";
334
+ }
335
+ };
336
+
337
+ // src/Envapter.ts
338
+ var EnvaptCache = /* @__PURE__ */ new Map();
339
+ var Environment = /* @__PURE__ */ ((Environment2) => {
340
+ Environment2[Environment2["Development"] = 0] = "Development";
341
+ Environment2[Environment2["Staging"] = 1] = "Staging";
342
+ Environment2[Environment2["Production"] = 2] = "Production";
343
+ return Environment2;
344
+ })(Environment || {});
345
+ var Envapter = class _Envapter {
346
+ static {
347
+ __name(this, "Envapter");
348
+ }
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
+ );
378
+ }
379
+ /**
380
+ * Get currently configured .env file paths
381
+ * @returns Array of file paths being loaded
382
+ */
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
+ }
396
+ }
397
+ return env;
398
+ }
399
+ /**
400
+ * 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
+ */
410
+ static set environment(env) {
411
+ this.internalEnvironment = this.determineEnvironment(env);
412
+ }
413
+ /**
414
+ * Get the current application environment
415
+ * @returns Current environment enum value
416
+ */
417
+ static get environment() {
418
+ return this.internalEnvironment;
419
+ }
420
+ /**
421
+ * Check if the current environment is production
422
+ * @returns true if environment is production
423
+ */
424
+ static get isProduction() {
425
+ return this.internalEnvironment === 2 /* Production */;
426
+ }
427
+ /**
428
+ * Check if the current environment is staging
429
+ * @returns true if environment is staging
430
+ */
431
+ static get isStaging() {
432
+ return this.internalEnvironment === 1 /* Staging */;
433
+ }
434
+ /**
435
+ * Check if the current environment is development
436
+ * @returns true if environment is development
437
+ */
438
+ static get isDevelopment() {
439
+ return this.internalEnvironment === 0 /* Development */;
440
+ }
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;
451
+ }
452
+ static _get(key, type = 0 /* String */, def) {
453
+ const rawVal = this.config.get(key);
454
+ if (!rawVal) return def;
455
+ 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
+ }
476
+ }
477
+ /**
478
+ * Get a string environment variable with optional fallback.
479
+ * 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
+ */
490
+ static get(key, def) {
491
+ return this._get(key, 0 /* String */, def);
492
+ }
493
+ /**
494
+ * Get a number environment variable with optional fallback.
495
+ * 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
+ */
506
+ static getNumber(key, def) {
507
+ return this._get(key, 1 /* Number */, def);
508
+ }
509
+ /**
510
+ * 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
+ * ```
521
+ */
522
+ static getBoolean(key, def) {
523
+ return this._get(key, 2 /* Boolean */, def);
524
+ }
525
+ /**
526
+ * Get a bigint environment variable with optional fallback.
527
+ * 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
+ */
538
+ static getBigInt(key, def) {
539
+ return this._get(key, 3 /* BigInt */, def);
540
+ }
541
+ /**
542
+ * Get a symbol environment variable with optional fallback.
543
+ * 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
+ */
554
+ static getSymbol(key, def) {
555
+ return this._get(key, 4 /* Symbol */, def);
556
+ }
557
+ get(key, def) {
558
+ return _Envapter._get(key, 0 /* String */, def);
559
+ }
560
+ getNumber(key, def) {
561
+ return _Envapter._get(key, 1 /* Number */, def);
562
+ }
563
+ getBoolean(key, def) {
564
+ return _Envapter._get(key, 2 /* Boolean */, def);
565
+ }
566
+ getBigInt(key, def) {
567
+ return _Envapter._get(key, 3 /* BigInt */, def);
568
+ }
569
+ getSymbol(key, def) {
570
+ return _Envapter._get(key, 4 /* Symbol */, def);
571
+ }
572
+ /**
573
+ * Get raw environment variable value without parsing or conversion.
574
+ *
575
+ * @internal
576
+ */
577
+ getRaw(key) {
578
+ return _Envapter.config.get(key);
579
+ }
580
+ };
581
+
582
+ // src/Envapt.ts
583
+ function createPropertyDecorator(key, fallback, converter, hasFallback = true) {
584
+ return function(target, prop) {
585
+ const propKey = String(prop);
586
+ const cacheKey = `${target.constructor.name}.${propKey}`;
587
+ Object.defineProperty(target, propKey, {
588
+ get: /* @__PURE__ */ __name(function() {
589
+ let value = EnvaptCache.get(cacheKey);
590
+ if (value === void 0) {
591
+ const parser = new Parser(new Envapter());
592
+ value = parser.convertValue(key, fallback, converter, hasFallback);
593
+ EnvaptCache.set(cacheKey, value);
594
+ }
595
+ return value;
596
+ }, "get"),
597
+ configurable: false,
598
+ enumerable: true
599
+ });
600
+ };
601
+ }
602
+ __name(createPropertyDecorator, "createPropertyDecorator");
603
+ function Envapt(key, fallbackOrOptions, converter) {
604
+ let fallback;
605
+ let actualConverter;
606
+ let hasFallback = true;
607
+ if (fallbackOrOptions && typeof fallbackOrOptions === "object" && ("fallback" in fallbackOrOptions || "converter" in fallbackOrOptions)) {
608
+ const options = fallbackOrOptions;
609
+ fallback = options.fallback;
610
+ actualConverter = options.converter;
611
+ hasFallback = "fallback" in options;
612
+ } else {
613
+ fallback = fallbackOrOptions;
614
+ actualConverter = converter;
615
+ hasFallback = arguments.length > 1;
616
+ }
617
+ return createPropertyDecorator(key, fallback, actualConverter, hasFallback);
618
+ }
619
+ __name(Envapt, "Envapt");
620
+
621
+ exports.Envapt = Envapt;
622
+ exports.Envapter = Envapter;
623
+ exports.Environment = Environment;
624
+ //# sourceMappingURL=index.js.map
625
+ //# sourceMappingURL=index.js.map