@catbee/utils 0.0.4 → 0.0.6

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.
Files changed (213) hide show
  1. package/LICENSE +21 -201
  2. package/README.md +911 -242
  3. package/build/esm/config.d.ts +108 -8
  4. package/build/esm/config.js +122 -6
  5. package/build/esm/config.js.map +1 -1
  6. package/build/esm/index.d.ts +6 -0
  7. package/build/esm/index.js +29 -0
  8. package/build/esm/index.js.map +1 -1
  9. package/build/esm/servers/server.builder.d.ts +625 -0
  10. package/build/esm/servers/server.builder.js +722 -0
  11. package/build/esm/servers/server.builder.js.map +1 -0
  12. package/build/esm/servers/server.d.ts +256 -0
  13. package/build/esm/servers/server.js +1211 -0
  14. package/build/esm/servers/server.js.map +1 -0
  15. package/build/esm/types/api-response.d.ts +5 -7
  16. package/build/esm/types/api-response.js +23 -0
  17. package/build/esm/types/api-response.js.map +1 -1
  18. package/build/esm/types/index.d.ts +125 -0
  19. package/build/esm/types/index.js +25 -0
  20. package/build/esm/types/index.js.map +1 -0
  21. package/build/esm/types/server.d.ts +285 -0
  22. package/build/esm/types/server.js +25 -0
  23. package/build/esm/types/server.js.map +1 -0
  24. package/build/esm/utils/array.utils.js +23 -0
  25. package/build/esm/utils/array.utils.js.map +1 -1
  26. package/build/esm/utils/async.utils.js +23 -0
  27. package/build/esm/utils/async.utils.js.map +1 -1
  28. package/build/esm/utils/cache.utils.js +39 -16
  29. package/build/esm/utils/cache.utils.js.map +1 -1
  30. package/build/esm/utils/context-store.utils.d.ts +1 -1
  31. package/build/esm/utils/context-store.utils.js +24 -1
  32. package/build/esm/utils/context-store.utils.js.map +1 -1
  33. package/build/esm/utils/crypto.utils.js +26 -2
  34. package/build/esm/utils/crypto.utils.js.map +1 -1
  35. package/build/esm/utils/decorators.utils.d.ts +291 -0
  36. package/build/esm/utils/decorators.utils.js +395 -41
  37. package/build/esm/utils/decorators.utils.js.map +1 -1
  38. package/build/esm/utils/dir.utils.js +23 -0
  39. package/build/esm/utils/dir.utils.js.map +1 -1
  40. package/build/esm/utils/env.utils.d.ts +186 -23
  41. package/build/esm/utils/env.utils.js +517 -91
  42. package/build/esm/utils/env.utils.js.map +1 -1
  43. package/build/esm/utils/exception.utils.js +31 -8
  44. package/build/esm/utils/exception.utils.js.map +1 -1
  45. package/build/esm/utils/fs.utils.js +23 -0
  46. package/build/esm/utils/fs.utils.js.map +1 -1
  47. package/build/esm/utils/http-status-codes.js +23 -0
  48. package/build/esm/utils/http-status-codes.js.map +1 -1
  49. package/build/esm/utils/id.utils.js +23 -0
  50. package/build/esm/utils/id.utils.js.map +1 -1
  51. package/build/esm/utils/logger.utils.d.ts +118 -0
  52. package/build/esm/utils/logger.utils.js +251 -15
  53. package/build/esm/utils/logger.utils.js.map +1 -1
  54. package/build/esm/utils/middleware.utils.d.ts +29 -7
  55. package/build/esm/utils/middleware.utils.js +81 -55
  56. package/build/esm/utils/middleware.utils.js.map +1 -1
  57. package/build/esm/utils/obj.utils.d.ts +10 -3
  58. package/build/esm/utils/obj.utils.js +225 -15
  59. package/build/esm/utils/obj.utils.js.map +1 -1
  60. package/build/esm/utils/request.utils.d.ts +77 -0
  61. package/build/esm/utils/request.utils.js +196 -0
  62. package/build/esm/utils/request.utils.js.map +1 -0
  63. package/build/esm/utils/response.utils.d.ts +15 -1
  64. package/build/esm/utils/response.utils.js +55 -4
  65. package/build/esm/utils/response.utils.js.map +1 -1
  66. package/build/esm/utils/string.utils.js +23 -0
  67. package/build/esm/utils/string.utils.js.map +1 -1
  68. package/build/esm/utils/url.utils.js +23 -0
  69. package/build/esm/utils/url.utils.js.map +1 -1
  70. package/build/esm/utils/validate.utils.d.ts +7 -0
  71. package/build/esm/utils/validate.utils.js +35 -2
  72. package/build/esm/utils/validate.utils.js.map +1 -1
  73. package/build/esnext/config.d.ts +108 -8
  74. package/build/esnext/config.js +122 -6
  75. package/build/esnext/config.js.map +1 -1
  76. package/build/esnext/index.d.ts +6 -0
  77. package/build/esnext/index.js +29 -0
  78. package/build/esnext/index.js.map +1 -1
  79. package/build/esnext/servers/server.builder.d.ts +625 -0
  80. package/build/esnext/servers/server.builder.js +677 -0
  81. package/build/esnext/servers/server.builder.js.map +1 -0
  82. package/build/esnext/servers/server.d.ts +256 -0
  83. package/build/esnext/servers/server.js +918 -0
  84. package/build/esnext/servers/server.js.map +1 -0
  85. package/build/esnext/types/api-response.d.ts +5 -7
  86. package/build/esnext/types/api-response.js +23 -0
  87. package/build/esnext/types/api-response.js.map +1 -1
  88. package/build/esnext/types/index.d.ts +125 -0
  89. package/build/esnext/types/index.js +25 -0
  90. package/build/esnext/types/index.js.map +1 -0
  91. package/build/esnext/types/server.d.ts +285 -0
  92. package/build/esnext/types/server.js +25 -0
  93. package/build/esnext/types/server.js.map +1 -0
  94. package/build/esnext/utils/array.utils.js +23 -0
  95. package/build/esnext/utils/array.utils.js.map +1 -1
  96. package/build/esnext/utils/async.utils.js +23 -0
  97. package/build/esnext/utils/async.utils.js.map +1 -1
  98. package/build/esnext/utils/cache.utils.js +39 -16
  99. package/build/esnext/utils/cache.utils.js.map +1 -1
  100. package/build/esnext/utils/context-store.utils.d.ts +1 -1
  101. package/build/esnext/utils/context-store.utils.js +24 -1
  102. package/build/esnext/utils/context-store.utils.js.map +1 -1
  103. package/build/esnext/utils/crypto.utils.js +26 -2
  104. package/build/esnext/utils/crypto.utils.js.map +1 -1
  105. package/build/esnext/utils/decorators.utils.d.ts +291 -0
  106. package/build/esnext/utils/decorators.utils.js +371 -22
  107. package/build/esnext/utils/decorators.utils.js.map +1 -1
  108. package/build/esnext/utils/dir.utils.js +23 -0
  109. package/build/esnext/utils/dir.utils.js.map +1 -1
  110. package/build/esnext/utils/env.utils.d.ts +186 -23
  111. package/build/esnext/utils/env.utils.js +468 -77
  112. package/build/esnext/utils/env.utils.js.map +1 -1
  113. package/build/esnext/utils/exception.utils.js +30 -7
  114. package/build/esnext/utils/exception.utils.js.map +1 -1
  115. package/build/esnext/utils/fs.utils.js +23 -0
  116. package/build/esnext/utils/fs.utils.js.map +1 -1
  117. package/build/esnext/utils/http-status-codes.js +23 -0
  118. package/build/esnext/utils/http-status-codes.js.map +1 -1
  119. package/build/esnext/utils/id.utils.js +23 -0
  120. package/build/esnext/utils/id.utils.js.map +1 -1
  121. package/build/esnext/utils/logger.utils.d.ts +118 -0
  122. package/build/esnext/utils/logger.utils.js +222 -15
  123. package/build/esnext/utils/logger.utils.js.map +1 -1
  124. package/build/esnext/utils/middleware.utils.d.ts +29 -7
  125. package/build/esnext/utils/middleware.utils.js +77 -55
  126. package/build/esnext/utils/middleware.utils.js.map +1 -1
  127. package/build/esnext/utils/obj.utils.d.ts +10 -3
  128. package/build/esnext/utils/obj.utils.js +176 -12
  129. package/build/esnext/utils/obj.utils.js.map +1 -1
  130. package/build/esnext/utils/request.utils.d.ts +77 -0
  131. package/build/esnext/utils/request.utils.js +168 -0
  132. package/build/esnext/utils/request.utils.js.map +1 -0
  133. package/build/esnext/utils/response.utils.d.ts +15 -1
  134. package/build/esnext/utils/response.utils.js +55 -4
  135. package/build/esnext/utils/response.utils.js.map +1 -1
  136. package/build/esnext/utils/string.utils.js +23 -0
  137. package/build/esnext/utils/string.utils.js.map +1 -1
  138. package/build/esnext/utils/url.utils.js +23 -0
  139. package/build/esnext/utils/url.utils.js.map +1 -1
  140. package/build/esnext/utils/validate.utils.d.ts +7 -0
  141. package/build/esnext/utils/validate.utils.js +33 -0
  142. package/build/esnext/utils/validate.utils.js.map +1 -1
  143. package/build/src/config.d.ts +108 -8
  144. package/build/src/config.js +125 -7
  145. package/build/src/config.js.map +1 -1
  146. package/build/src/index.d.ts +6 -0
  147. package/build/src/index.js +32 -0
  148. package/build/src/index.js.map +1 -1
  149. package/build/src/servers/server.builder.d.ts +625 -0
  150. package/build/src/servers/server.builder.js +681 -0
  151. package/build/src/servers/server.builder.js.map +1 -0
  152. package/build/src/servers/server.d.ts +256 -0
  153. package/build/src/servers/server.js +958 -0
  154. package/build/src/servers/server.js.map +1 -0
  155. package/build/src/types/api-response.d.ts +5 -7
  156. package/build/src/types/api-response.js +23 -0
  157. package/build/src/types/api-response.js.map +1 -1
  158. package/build/src/types/index.d.ts +125 -0
  159. package/build/src/types/index.js +26 -0
  160. package/build/src/types/index.js.map +1 -0
  161. package/build/src/types/server.d.ts +285 -0
  162. package/build/src/types/server.js +26 -0
  163. package/build/src/types/server.js.map +1 -0
  164. package/build/src/utils/array.utils.js +23 -0
  165. package/build/src/utils/array.utils.js.map +1 -1
  166. package/build/src/utils/async.utils.js +23 -0
  167. package/build/src/utils/async.utils.js.map +1 -1
  168. package/build/src/utils/cache.utils.js +38 -15
  169. package/build/src/utils/cache.utils.js.map +1 -1
  170. package/build/src/utils/context-store.utils.d.ts +1 -1
  171. package/build/src/utils/context-store.utils.js +24 -1
  172. package/build/src/utils/context-store.utils.js.map +1 -1
  173. package/build/src/utils/crypto.utils.js +25 -1
  174. package/build/src/utils/crypto.utils.js.map +1 -1
  175. package/build/src/utils/decorators.utils.d.ts +291 -0
  176. package/build/src/utils/decorators.utils.js +373 -22
  177. package/build/src/utils/decorators.utils.js.map +1 -1
  178. package/build/src/utils/dir.utils.js +23 -0
  179. package/build/src/utils/dir.utils.js.map +1 -1
  180. package/build/src/utils/env.utils.d.ts +186 -23
  181. package/build/src/utils/env.utils.js +467 -76
  182. package/build/src/utils/env.utils.js.map +1 -1
  183. package/build/src/utils/exception.utils.js +30 -7
  184. package/build/src/utils/exception.utils.js.map +1 -1
  185. package/build/src/utils/fs.utils.js +23 -0
  186. package/build/src/utils/fs.utils.js.map +1 -1
  187. package/build/src/utils/http-status-codes.js +23 -0
  188. package/build/src/utils/http-status-codes.js.map +1 -1
  189. package/build/src/utils/id.utils.js +23 -0
  190. package/build/src/utils/id.utils.js.map +1 -1
  191. package/build/src/utils/logger.utils.d.ts +118 -0
  192. package/build/src/utils/logger.utils.js +228 -15
  193. package/build/src/utils/logger.utils.js.map +1 -1
  194. package/build/src/utils/middleware.utils.d.ts +29 -7
  195. package/build/src/utils/middleware.utils.js +76 -54
  196. package/build/src/utils/middleware.utils.js.map +1 -1
  197. package/build/src/utils/obj.utils.d.ts +10 -3
  198. package/build/src/utils/obj.utils.js +177 -12
  199. package/build/src/utils/obj.utils.js.map +1 -1
  200. package/build/src/utils/request.utils.d.ts +77 -0
  201. package/build/src/utils/request.utils.js +175 -0
  202. package/build/src/utils/request.utils.js.map +1 -0
  203. package/build/src/utils/response.utils.d.ts +15 -1
  204. package/build/src/utils/response.utils.js +56 -4
  205. package/build/src/utils/response.utils.js.map +1 -1
  206. package/build/src/utils/string.utils.js +23 -0
  207. package/build/src/utils/string.utils.js.map +1 -1
  208. package/build/src/utils/url.utils.js +23 -0
  209. package/build/src/utils/url.utils.js.map +1 -1
  210. package/build/src/utils/validate.utils.d.ts +7 -0
  211. package/build/src/utils/validate.utils.js +36 -2
  212. package/build/src/utils/validate.utils.js.map +1 -1
  213. package/package.json +40 -9
@@ -1,14 +1,26 @@
1
- var __values = (this && this.__values) || function(o) {
2
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
3
- if (m) return m.call(o);
4
- if (o && typeof o.length === "number") return {
5
- next: function () {
6
- if (o && i >= o.length) o = void 0;
7
- return { value: o && o[i++], done: !o };
8
- }
9
- };
10
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
11
- };
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
12
24
  var __read = (this && this.__read) || function (o, n) {
13
25
  var m = typeof Symbol === "function" && o[Symbol.iterator];
14
26
  if (!m) return o;
@@ -25,8 +37,28 @@ var __read = (this && this.__read) || function (o, n) {
25
37
  }
26
38
  return ar;
27
39
  };
40
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
41
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
42
+ if (ar || !(i in from)) {
43
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
44
+ ar[i] = from[i];
45
+ }
46
+ }
47
+ return to.concat(ar || Array.prototype.slice.call(from));
48
+ };
49
+ var __values = (this && this.__values) || function(o) {
50
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
+ if (m) return m.call(o);
52
+ if (o && typeof o.length === "number") return {
53
+ next: function () {
54
+ if (o && i >= o.length) o = void 0;
55
+ return { value: o && o[i++], done: !o };
56
+ }
57
+ };
58
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
+ };
28
60
  /* eslint-disable n/no-process-env */
29
- import { existsSync } from 'fs';
61
+ import { existsSync, readFileSync } from 'fs';
30
62
  import { isAbsolute, resolve } from 'path';
31
63
  /**
32
64
  * Enum representing valid application environments.
@@ -59,7 +91,7 @@ var Env = /** @class */ (function () {
59
91
  * @returns {boolean} `true` if NODE_ENV is 'production', else `false`.
60
92
  */
61
93
  Env.isProd = function () {
62
- return Env.get('NODE_ENV') === Environment.PRODUCTION;
94
+ return Env.get('NODE_ENV', Environment.DEVELOPMENT) === Environment.PRODUCTION;
63
95
  };
64
96
  /**
65
97
  * Checks if the current NODE_ENV is 'testing'.
@@ -67,7 +99,7 @@ var Env = /** @class */ (function () {
67
99
  * @returns {boolean} `true` if NODE_ENV is 'testing', else `false`.
68
100
  */
69
101
  Env.isTest = function () {
70
- return Env.get('NODE_ENV') === Environment.TESTING;
102
+ return Env.get('NODE_ENV', Environment.DEVELOPMENT) === Environment.TESTING;
71
103
  };
72
104
  /**
73
105
  * Checks if the current NODE_ENV is 'staging'.
@@ -75,7 +107,7 @@ var Env = /** @class */ (function () {
75
107
  * @returns {boolean} `true` if NODE_ENV is 'staging', else `false`.
76
108
  */
77
109
  Env.isStaging = function () {
78
- return Env.get('NODE_ENV') === Environment.STAGING;
110
+ return Env.get('NODE_ENV', Environment.DEVELOPMENT) === Environment.STAGING;
79
111
  };
80
112
  /**
81
113
  * Sets an environment variable (only affects runtime memory).
@@ -84,7 +116,25 @@ var Env = /** @class */ (function () {
84
116
  * @param {string} value - The value to set.
85
117
  */
86
118
  Env.set = function (key, value) {
119
+ var e_1, _a;
87
120
  process.env[key] = value;
121
+ // Clear all cached values for this key with any prefix
122
+ this.cache.delete(key);
123
+ try {
124
+ for (var _b = __values(__spreadArray([], __read(this.cache.keys()), false)), _c = _b.next(); !_c.done; _c = _b.next()) {
125
+ var cacheKey = _c.value;
126
+ if (cacheKey.includes(":".concat(key))) {
127
+ this.cache.delete(cacheKey);
128
+ }
129
+ }
130
+ }
131
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
132
+ finally {
133
+ try {
134
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
135
+ }
136
+ finally { if (e_1) throw e_1.error; }
137
+ }
88
138
  };
89
139
  /**
90
140
  * Returns all environment variables as an object.
@@ -96,14 +146,28 @@ var Env = /** @class */ (function () {
96
146
  };
97
147
  /**
98
148
  * Retrieves a string environment variable with a fallback default.
149
+ * Supports variable expansion with ${VAR_NAME} syntax.
99
150
  *
100
151
  * @param {string} key - The environment variable key.
101
152
  * @param {string} [defaultValue] - Value to return if the key is missing.
102
- * @returns {string | undefined} The env value or the fallback.
153
+ * @returns {string} The env value or the fallback.
154
+ *
155
+ * @example
156
+ * // If DATABASE_URL is "postgres://localhost:5432/${DB_NAME}"
157
+ * // and DB_NAME is "myapp"
158
+ * const url = Env.get('DATABASE_URL', ''); // "postgres://localhost:5432/myapp"
103
159
  */
104
160
  Env.get = function (key, defaultValue) {
105
161
  var _a;
106
- return (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
162
+ var value = (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
163
+ // Expand ${VAR} references
164
+ if (value && value.includes('${')) {
165
+ value = value.replace(/\${([A-Za-z0-9_]+)}/g, function (_, varName) {
166
+ var _a;
167
+ return (_a = process.env[varName]) !== null && _a !== void 0 ? _a : '';
168
+ });
169
+ }
170
+ return value;
107
171
  };
108
172
  /**
109
173
  * Retrieves a string environment variable and throws if it's missing.
@@ -115,9 +179,29 @@ var Env = /** @class */ (function () {
115
179
  Env.getRequired = function (key) {
116
180
  var value = process.env[key];
117
181
  if (value === undefined) {
118
- throw new Error("Required env ".concat(key, " is missing"));
182
+ throw new Error("Required environment variable '".concat(key, "' is missing"));
119
183
  }
120
- return value;
184
+ return Env.get(key, ''); // Use get to handle variable expansion
185
+ };
186
+ /**
187
+ * Retrieves a value using a default generating function if the key doesn't exist.
188
+ * Useful for expensive default calculations.
189
+ *
190
+ * @param {string} key - The environment variable key.
191
+ * @param {() => string} defaultFn - Function that generates default value.
192
+ * @returns {string} The environment value or generated default.
193
+ *
194
+ * @example
195
+ * const hostname = Env.getWithDefault('HOSTNAME', () => {
196
+ * // Only called if HOSTNAME is not set
197
+ * return require('os').hostname();
198
+ * });
199
+ */
200
+ Env.getWithDefault = function (key, defaultFn) {
201
+ if (Env.has(key)) {
202
+ return Env.get(key, '');
203
+ }
204
+ return defaultFn();
121
205
  };
122
206
  /**
123
207
  * Retrieves an environment variable as a number, or returns a default.
@@ -128,12 +212,18 @@ var Env = /** @class */ (function () {
128
212
  * @throws {Error} If the value is not a valid number.
129
213
  */
130
214
  Env.getNumber = function (key, defaultValue) {
131
- var _a;
132
- var value = (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
215
+ if (this.cache.has("number:".concat(key))) {
216
+ return this.cache.get("number:".concat(key));
217
+ }
218
+ var value = process.env[key];
219
+ if (value === undefined) {
220
+ return defaultValue;
221
+ }
133
222
  var numberValue = Number(value);
134
223
  if (isNaN(numberValue)) {
135
- throw new Error("Env ".concat(key, " is not a number"));
224
+ throw new Error("Environment variable '".concat(key, "' is not a valid number, got: \"").concat(value, "\""));
136
225
  }
226
+ this.cache.set("number:".concat(key), numberValue);
137
227
  return numberValue;
138
228
  };
139
229
  /**
@@ -146,13 +236,38 @@ var Env = /** @class */ (function () {
146
236
  Env.getNumberRequired = function (key) {
147
237
  var value = process.env[key];
148
238
  if (value === undefined) {
149
- throw new Error("Required env ".concat(key, " is missing"));
239
+ throw new Error("Required environment variable '".concat(key, "' is missing"));
150
240
  }
151
- var numberValue = Number(value);
152
- if (isNaN(numberValue)) {
153
- throw new Error("Required env ".concat(key, " is not a number"));
241
+ return Env.getNumber(key, 0); // The default is ignored since we know the key exists
242
+ };
243
+ /**
244
+ * Retrieves an integer environment variable and validates it.
245
+ *
246
+ * @param {string} key - The environment variable key.
247
+ * @param {number} defaultValue - Fallback number if key is not present.
248
+ * @param {object} [options] - Validation options.
249
+ * @param {number} [options.min] - Minimum allowed value.
250
+ * @param {number} [options.max] - Maximum allowed value.
251
+ * @returns {number} The parsed integer.
252
+ *
253
+ * @example
254
+ * // Require PORT to be between 1000 and 9999
255
+ * const port = Env.getInteger('PORT', 3000, { min: 1000, max: 9999 });
256
+ */
257
+ Env.getInteger = function (key, defaultValue, options) {
258
+ if (options === void 0) { options = {}; }
259
+ var num = Env.getNumber(key, defaultValue);
260
+ var intValue = Math.floor(num);
261
+ if (intValue !== num) {
262
+ throw new Error("Environment variable '".concat(key, "' must be an integer, got: ").concat(num));
154
263
  }
155
- return numberValue;
264
+ if (options.min !== undefined && intValue < options.min) {
265
+ throw new Error("Environment variable '".concat(key, "' must be at least ").concat(options.min, ", got: ").concat(intValue));
266
+ }
267
+ if (options.max !== undefined && intValue > options.max) {
268
+ throw new Error("Environment variable '".concat(key, "' must be at most ").concat(options.max, ", got: ").concat(intValue));
269
+ }
270
+ return intValue;
156
271
  };
157
272
  /**
158
273
  * Retrieves an environment variable as a boolean.
@@ -162,16 +277,30 @@ var Env = /** @class */ (function () {
162
277
  * @param {boolean} [defaultValue=false] - Optional fallback value if key is missing.
163
278
  * @returns {boolean} Parsed boolean.
164
279
  * @throws {Error} If the value is not a recognized boolean string.
280
+ *
281
+ * @example
282
+ * // If DEBUG=yes
283
+ * const isDebug = Env.getBoolean('DEBUG', false); // true
165
284
  */
166
285
  Env.getBoolean = function (key, defaultValue) {
167
- var _a;
168
286
  if (defaultValue === void 0) { defaultValue = false; }
169
- var value = ((_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue).toString().toLowerCase();
170
- if (['true', '1', 'yes', 'on'].includes(value))
287
+ if (this.cache.has("bool:".concat(key))) {
288
+ return this.cache.get("bool:".concat(key));
289
+ }
290
+ var value = process.env[key];
291
+ if (value === undefined) {
292
+ return defaultValue;
293
+ }
294
+ var lowerValue = value.toLowerCase();
295
+ if (['true', '1', 'yes', 'on'].includes(lowerValue)) {
296
+ this.cache.set("bool:".concat(key), true);
171
297
  return true;
172
- if (['false', '0', 'no', 'off'].includes(value))
298
+ }
299
+ if (['false', '0', 'no', 'off'].includes(lowerValue)) {
300
+ this.cache.set("bool:".concat(key), false);
173
301
  return false;
174
- throw new Error("Env variable ".concat(key, " is not a boolean"));
302
+ }
303
+ throw new Error("Environment variable '".concat(key, "' is not a valid boolean, got: \"").concat(value, "\". Use true/false, yes/no, 1/0, or on/off."));
175
304
  };
176
305
  /**
177
306
  * Retrieves a required environment variable as a boolean.
@@ -183,9 +312,9 @@ var Env = /** @class */ (function () {
183
312
  Env.getBooleanRequired = function (key) {
184
313
  var value = process.env[key];
185
314
  if (value === undefined) {
186
- throw new Error("Required env ".concat(key, " is missing"));
315
+ throw new Error("Required environment variable '".concat(key, "' is missing"));
187
316
  }
188
- return this.getBoolean(key); // reuse logic
317
+ return Env.getBoolean(key);
189
318
  };
190
319
  /**
191
320
  * Parses a stringified JSON object from an environment variable.
@@ -195,18 +324,28 @@ var Env = /** @class */ (function () {
195
324
  * @param {T} defaultValue - Value to return if key is missing.
196
325
  * @returns {T} Parsed object or default.
197
326
  * @throws {Error} If the value is not valid JSON.
327
+ *
328
+ * @example
329
+ * // If CONFIG='{"debug":true,"api":{"url":"https://api.example.com"}}'
330
+ * const config = Env.getJSON('CONFIG', { debug: false });
331
+ * // { debug: true, api: { url: "https://api.example.com" }}
198
332
  */
199
333
  Env.getJSON = function (key, defaultValue) {
334
+ if (this.cache.has("json:".concat(key))) {
335
+ return this.cache.get("json:".concat(key));
336
+ }
200
337
  var v = process.env[key];
201
- if (v !== undefined) {
202
- try {
203
- return JSON.parse(v);
204
- }
205
- catch (_a) {
206
- throw new Error("Env variable ".concat(key, " is not a valid JSON string"));
207
- }
338
+ if (v === undefined) {
339
+ return defaultValue;
340
+ }
341
+ try {
342
+ var parsed = JSON.parse(v);
343
+ this.cache.set("json:".concat(key), parsed);
344
+ return parsed;
345
+ }
346
+ catch (error) {
347
+ throw new Error("Environment variable '".concat(key, "' is not valid JSON: ").concat(error.message));
208
348
  }
209
- return defaultValue;
210
349
  };
211
350
  /**
212
351
  * Parses a comma-separated string as an array.
@@ -215,19 +354,69 @@ var Env = /** @class */ (function () {
215
354
  * @param {string} key - The environment variable key.
216
355
  * @param {T[]} [defaultValue=[]] - Array to return if value is empty or missing.
217
356
  * @param {string} [splitter=','] - Delimiter to split on.
218
- * @returns {string[] | T[]} An array of strings.
357
+ * @param {(item: string) => T} [transform] - Optional function to transform each item.
358
+ * @returns {T[]} An array of items.
359
+ *
360
+ * @example
361
+ * // If ALLOWED_IPS=127.0.0.1,192.168.1.1,10.0.0.1
362
+ * const ips = Env.getArray('ALLOWED_IPS');
363
+ * // ["127.0.0.1", "192.168.1.1", "10.0.0.1"]
364
+ *
365
+ * // With transformation function
366
+ * const ports = Env.getArray('PORTS', [], ',', (p) => parseInt(p, 10));
219
367
  */
220
- Env.getArray = function (key, defaultValue, splitter) {
368
+ Env.getArray = function (key, defaultValue, splitter, transform) {
221
369
  if (defaultValue === void 0) { defaultValue = []; }
222
370
  if (splitter === void 0) { splitter = ','; }
371
+ var cacheKey = "array:".concat(key, ":").concat(splitter, ":").concat(transform ? 'transformed' : 'raw');
372
+ if (this.cache.has(cacheKey)) {
373
+ return this.cache.get(cacheKey);
374
+ }
223
375
  var value = process.env[key];
224
376
  if (!value || value.trim() === '') {
225
377
  return defaultValue;
226
378
  }
227
- return value
379
+ var items = value
228
380
  .split(splitter)
229
381
  .map(function (item) { return item.trim(); })
230
382
  .filter(function (item) { return item.length > 0; });
383
+ if (transform) {
384
+ try {
385
+ var result_1 = items.map(transform);
386
+ this.cache.set(cacheKey, result_1);
387
+ return result_1;
388
+ }
389
+ catch (error) {
390
+ throw new Error("Failed to transform items in '".concat(key, "': ").concat(error.message));
391
+ }
392
+ }
393
+ var result = items;
394
+ this.cache.set(cacheKey, result);
395
+ return result;
396
+ };
397
+ /**
398
+ * Parses a comma-separated list of numbers.
399
+ *
400
+ * @param {string} key - The environment variable key.
401
+ * @param {number[]} [defaultValue=[]] - Default value if not present.
402
+ * @param {string} [splitter=','] - Delimiter to split on.
403
+ * @returns {number[]} Array of parsed numbers.
404
+ *
405
+ * @example
406
+ * // If ALLOWED_PORTS=80,443,3000,8080
407
+ * const ports = Env.getNumberArray('ALLOWED_PORTS');
408
+ * // [80, 443, 3000, 8080]
409
+ */
410
+ Env.getNumberArray = function (key, defaultValue, splitter) {
411
+ if (defaultValue === void 0) { defaultValue = []; }
412
+ if (splitter === void 0) { splitter = ','; }
413
+ return Env.getArray(key, defaultValue, splitter, function (item) {
414
+ var num = Number(item);
415
+ if (isNaN(num)) {
416
+ throw new Error("Value \"".concat(item, "\" in array '").concat(key, "' is not a valid number"));
417
+ }
418
+ return num;
419
+ });
231
420
  };
232
421
  /**
233
422
  * Retrieves an enum-like environment variable value, validating against allowed values.
@@ -238,12 +427,38 @@ var Env = /** @class */ (function () {
238
427
  * @param {T} [defaultValue] - Optional fallback value.
239
428
  * @returns {T} The validated environment value.
240
429
  * @throws {Error} If missing or invalid.
430
+ *
431
+ * @example
432
+ * // If LOG_LEVEL=debug
433
+ * const level = Env.getEnum('LOG_LEVEL', ['debug', 'info', 'warn', 'error'] as const, 'info');
434
+ * // 'debug' (typed as 'debug' | 'info' | 'warn' | 'error')
241
435
  */
242
436
  Env.getEnum = function (key, allowedValues, defaultValue) {
243
- var _a;
244
- var value = (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
245
- if (!value || !allowedValues.includes(value)) {
246
- throw new Error("Env ".concat(key, " must be one of ").concat(allowedValues.join(', '), ". Received: ").concat(value));
437
+ var value = process.env[key];
438
+ if (!value) {
439
+ return defaultValue;
440
+ }
441
+ if (!allowedValues.includes(value)) {
442
+ throw new Error("Environment variable '".concat(key, "' must be one of: ").concat(allowedValues.join(', '), ". Received: \"").concat(value, "\""));
443
+ }
444
+ return value;
445
+ };
446
+ /**
447
+ * Retrieves an enum-like numeric environment variable.
448
+ *
449
+ * @param {string} key - The environment variable key.
450
+ * @param {number[]} allowedValues - Array of accepted values.
451
+ * @param {number} defaultValue - Default value if not present.
452
+ * @returns {number} The validated value.
453
+ *
454
+ * @example
455
+ * // If NODE_VERSION=16
456
+ * const version = Env.getNumberEnum('NODE_VERSION', [14, 16, 18], 16);
457
+ */
458
+ Env.getNumberEnum = function (key, allowedValues, defaultValue) {
459
+ var value = Env.getNumber(key, defaultValue);
460
+ if (!allowedValues.includes(value)) {
461
+ throw new Error("Environment variable '".concat(key, "' must be one of: ").concat(allowedValues.join(', '), ". Received: ").concat(value));
247
462
  }
248
463
  return value;
249
464
  };
@@ -252,42 +467,67 @@ var Env = /** @class */ (function () {
252
467
  *
253
468
  * @param {string} key - The environment variable key.
254
469
  * @param {string} [defaultValue] - Optional fallback value.
255
- * @param {object} [options] - Validation options.
256
- * @param {string[]} [options.protocols] - Allowed protocols.
257
- * @param {boolean} [options.requireTld=true] - Whether TLD is required.
470
+ * @param {UrlOptions} [options] - Validation options.
258
471
  * @returns {string} The validated URL.
259
472
  * @throws {Error} If URL is invalid.
473
+ *
474
+ * @example
475
+ * // Validate API URL requires HTTPS
476
+ * const apiUrl = Env.getUrl('API_URL', 'https://api.example.com', {
477
+ * protocols: ['https'],
478
+ * requireTld: true,
479
+ * allowIp: false
480
+ * });
260
481
  */
261
482
  Env.getUrl = function (key, defaultValue, options) {
262
483
  if (options === void 0) { options = {}; }
484
+ var cacheKey = "url:".concat(key, ":").concat(JSON.stringify(options));
485
+ if (this.cache.has(cacheKey)) {
486
+ return this.cache.get(cacheKey);
487
+ }
263
488
  var value = Env.get(key, defaultValue);
264
489
  if (!value) {
265
- throw new Error("Env ".concat(key, " is missing or empty"));
490
+ throw new Error("URL environment variable '".concat(key, "' is missing or empty"));
266
491
  }
267
492
  var url;
268
493
  try {
269
494
  url = new URL(value);
270
495
  }
271
496
  catch (_a) {
272
- throw new Error("Env ".concat(key, " is not a valid URL"));
497
+ throw new Error("Environment variable '".concat(key, "' is not a valid URL: \"").concat(value, "\""));
273
498
  }
499
+ // Validate protocol
274
500
  if (options.protocols && options.protocols.length > 0) {
275
501
  var protocol = url.protocol.replace(':', '');
276
502
  if (!options.protocols.includes(protocol)) {
277
- throw new Error("Env ".concat(key, " must use one of the protocols: ").concat(options.protocols.join(', ')));
503
+ throw new Error("Environment variable '".concat(key, "' must use one of the protocols: ").concat(options.protocols.join(', '), ". Got: ").concat(protocol));
278
504
  }
279
505
  }
506
+ // Validate hostname
507
+ var hostname = url.hostname;
508
+ var isIp = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(hostname);
509
+ var isLocalhost = hostname === 'localhost';
510
+ // Check if hostname is an IP address when not allowed
511
+ if (isIp && options.allowIp === false) {
512
+ throw new Error("Environment variable '".concat(key, "' cannot be an IP address: \"").concat(hostname, "\""));
513
+ }
514
+ // Check if hostname is localhost when not allowed
515
+ if (isLocalhost && options.allowLocalhost === false) {
516
+ throw new Error("Environment variable '".concat(key, "' cannot be localhost"));
517
+ }
518
+ // Check for TLD requirement - include localhost in check if requireTld is true and allowLocalhost is false
280
519
  if (options.requireTld === true) {
281
- // Check if hostname has a TLD (contains at least one dot and doesn't end with a dot)
282
- // localhost, 127.0.0.1, etc. don't have TLDs
283
- var hostname = url.hostname;
284
- if (!hostname.includes('.') ||
285
- hostname === 'localhost' ||
286
- /^[\d.]+$/.test(hostname) || // IP address
287
- hostname.endsWith('.')) {
288
- throw new Error("Env ".concat(key, " must have a valid host with TLD"));
520
+ if (isLocalhost && options.allowLocalhost !== false) {
521
+ // Localhost is allowed, so no TLD check needed for it
522
+ }
523
+ else if (isIp && options.allowIp !== false) {
524
+ // IP is allowed, so no TLD check needed for it
525
+ }
526
+ else if (!hostname.includes('.') || hostname.endsWith('.')) {
527
+ throw new Error("Environment variable '".concat(key, "' must have a valid host with TLD: \"").concat(hostname, "\""));
289
528
  }
290
529
  }
530
+ this.cache.set(cacheKey, value);
291
531
  return value;
292
532
  };
293
533
  /**
@@ -297,20 +537,27 @@ var Env = /** @class */ (function () {
297
537
  * @param {string} [defaultValue] - Optional fallback value.
298
538
  * @returns {string} The validated email address.
299
539
  * @throws {Error} If email is invalid.
540
+ *
541
+ * @example
542
+ * const supportEmail = Env.getEmail('SUPPORT_EMAIL', 'support@example.com');
300
543
  */
301
544
  Env.getEmail = function (key, defaultValue) {
545
+ if (this.cache.has("email:".concat(key))) {
546
+ return this.cache.get("email:".concat(key));
547
+ }
302
548
  var value = Env.get(key, defaultValue);
303
549
  if (!value) {
304
550
  if (defaultValue === undefined) {
305
- throw new Error("Email env ".concat(key, " is missing"));
551
+ throw new Error("Email environment variable '".concat(key, "' is missing"));
306
552
  }
307
553
  return defaultValue;
308
554
  }
309
- // Simple email validation regex
310
- var emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
555
+ // More comprehensive email validation regex
556
+ var emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
311
557
  if (!emailRegex.test(value)) {
312
- throw new Error("Env ".concat(key, " is not a valid email address"));
558
+ throw new Error("Environment variable '".concat(key, "' is not a valid email address: \"").concat(value, "\""));
313
559
  }
560
+ this.cache.set("email:".concat(key), value);
314
561
  return value;
315
562
  };
316
563
  /**
@@ -318,78 +565,143 @@ var Env = /** @class */ (function () {
318
565
  *
319
566
  * @param {string} key - The environment variable key.
320
567
  * @param {string} [defaultValue] - Optional fallback value.
321
- * @param {object} [options] - Validation options.
322
- * @param {boolean} [options.mustExist=false] - Whether path must exist.
323
- * @param {boolean} [options.makeAbsolute=true] - Convert relative paths to absolute.
568
+ * @param {PathOptions} [options] - Validation options.
324
569
  * @returns {string} The validated path.
325
570
  * @throws {Error} If path is invalid.
571
+ *
572
+ * @example
573
+ * // Require that the path exists and is a .json file
574
+ * const configPath = Env.getPath('CONFIG_PATH', './config.json', {
575
+ * mustExist: true,
576
+ * allowedExtensions: ['.json', '.yaml']
577
+ * });
326
578
  */
327
579
  Env.getPath = function (key, defaultValue, options) {
328
580
  if (options === void 0) { options = {}; }
581
+ var cacheKey = "path:".concat(key, ":").concat(JSON.stringify(options));
582
+ if (this.cache.has(cacheKey)) {
583
+ return this.cache.get(cacheKey);
584
+ }
329
585
  var value = Env.get(key, defaultValue);
330
586
  if (!value) {
331
587
  if (defaultValue === undefined) {
332
- throw new Error("Path env ".concat(key, " is missing"));
588
+ throw new Error("Path environment variable '".concat(key, "' is missing"));
333
589
  }
334
590
  return defaultValue;
335
591
  }
336
592
  var path = options.makeAbsolute !== false && !isAbsolute(value) ? resolve(process.cwd(), value) : value;
593
+ // Validate path exists if required
337
594
  if (options.mustExist && !existsSync(path)) {
338
- throw new Error("Path in env ".concat(key, " does not exist: ").concat(path));
595
+ throw new Error("Path in environment variable '".concat(key, "' does not exist: \"").concat(path, "\""));
596
+ }
597
+ // Validate file extension if specified
598
+ if (options.allowedExtensions && options.allowedExtensions.length > 0) {
599
+ var hasValidExtension = options.allowedExtensions.some(function (ext) { return path.toLowerCase().endsWith(ext.toLowerCase()); });
600
+ if (!hasValidExtension) {
601
+ throw new Error("Path in environment variable '".concat(key, "' must have one of these extensions: ").concat(options.allowedExtensions.join(', '), ". Got: \"").concat(path, "\""));
602
+ }
339
603
  }
604
+ this.cache.set(cacheKey, path);
340
605
  return path;
341
606
  };
342
607
  /**
343
608
  * Retrieves a port environment variable and validates it.
344
609
  *
345
610
  * @param {string} key - The environment variable key.
346
- * @param {number} [defaultValue=3000] - Optional fallback value.
611
+ * @param {number} [defaultValue] - Optional fallback value.
347
612
  * @returns {number} The validated port number.
348
613
  * @throws {Error} If port is invalid.
614
+ *
615
+ * @example
616
+ * const serverPort = Env.getPort('PORT', 3000);
349
617
  */
350
618
  Env.getPort = function (key, defaultValue) {
351
- if (defaultValue === void 0) { defaultValue = 3000; }
352
- var port = Env.getNumber(key, defaultValue);
353
- if (port < 0 || port > 65535) {
354
- throw new Error("Env ".concat(key, " must be a valid port number (0-65535)"));
619
+ try {
620
+ return Env.getInteger(key, defaultValue, { min: 0, max: 65535 });
621
+ }
622
+ catch (error) {
623
+ // Rewrite the error message to match the expected pattern
624
+ if (error.message.includes('must be at most 65535')) {
625
+ throw new Error("Environment variable '".concat(key, "' must be a valid port number (0-65535)"));
626
+ }
627
+ throw error;
628
+ }
629
+ };
630
+ /**
631
+ * Retrieves an ISO date string and converts it to a Date object.
632
+ *
633
+ * @param {string} key - The environment variable key.
634
+ * @param {string|Date} [defaultValue] - Optional fallback value.
635
+ * @returns {Date} The parsed Date object.
636
+ *
637
+ * @example
638
+ * // If EXPIRY_DATE=2023-12-31T23:59:59Z
639
+ * const expiryDate = Env.getDate('EXPIRY_DATE', new Date());
640
+ */
641
+ Env.getDate = function (key, defaultValue) {
642
+ if (defaultValue === void 0) { defaultValue = new Date(); }
643
+ var value = Env.get(key, defaultValue instanceof Date ? defaultValue.toISOString() : defaultValue);
644
+ if (!value) {
645
+ return defaultValue instanceof Date ? defaultValue : new Date();
646
+ }
647
+ var date = new Date(value);
648
+ if (isNaN(date.getTime())) {
649
+ throw new Error("Environment variable '".concat(key, "' is not a valid date: \"").concat(value, "\""));
355
650
  }
356
- return port;
651
+ return date;
357
652
  };
358
653
  /**
359
- * Retrieves a duration string and converts to milliseconds.
654
+ * Retrieves a duration string and converts it to milliseconds.
360
655
  * Supports formats like "1d", "2h", "30m", "45s", "100ms" or combinations like "1h30m".
361
656
  *
362
657
  * @param {string} key - The environment variable key.
363
658
  * @param {string|number} [defaultValue='0'] - Optional fallback value.
364
659
  * @returns {number} The duration in milliseconds.
365
660
  * @throws {Error} If duration format is invalid.
661
+ *
662
+ * @example
663
+ * // If CACHE_TTL=2h30m
664
+ * const cacheTtlMs = Env.getDuration('CACHE_TTL', '1h');
665
+ * // 9000000 (2.5 hours in milliseconds)
366
666
  */
367
667
  Env.getDuration = function (key, defaultValue) {
368
668
  if (defaultValue === void 0) { defaultValue = '0'; }
669
+ var cacheKey = "duration:".concat(key);
670
+ if (this.cache.has(cacheKey)) {
671
+ return this.cache.get(cacheKey);
672
+ }
369
673
  var value = Env.get(key, String(defaultValue));
370
674
  if (!value)
371
675
  return 0;
372
676
  // Handle plain number input (assume milliseconds)
373
677
  if (/^\d+$/.test(value)) {
374
- return parseInt(value, 10);
678
+ var ms_1 = parseInt(value, 10);
679
+ this.cache.set(cacheKey, ms_1);
680
+ return ms_1;
375
681
  }
376
- // Parse duration string like "1d2h30m15s"
377
- var durationRegex = /(\d+d)?(\d+h)?(\d+m)?(\d+s)?(\d+ms)?/;
682
+ // Enhanced duration parsing with more precise regex
683
+ var durationRegex = /^(?:(\d+)y)?(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?(?:(\d+)ms)?$/;
378
684
  var matches = value.match(durationRegex);
379
685
  if (!matches || matches[0] === '') {
380
- throw new Error("Env ".concat(key, " has invalid duration format. Use 1d, 2h, 30m, 45s, or 100ms."));
686
+ throw new Error("Environment variable '".concat(key, "' has invalid duration format: \"").concat(value, "\". ") +
687
+ "Use formats like 1y, 2w, 3d, 4h, 5m, 6s, or 7ms.");
381
688
  }
382
689
  var ms = 0;
383
690
  if (matches[1])
384
- ms += parseInt(matches[1], 10) * 86400000; // days
691
+ ms += parseInt(matches[1], 10) * 31536000000; // years (approximate)
385
692
  if (matches[2])
386
- ms += parseInt(matches[2], 10) * 3600000; // hours
693
+ ms += parseInt(matches[2], 10) * 604800000; // weeks
387
694
  if (matches[3])
388
- ms += parseInt(matches[3], 10) * 60000; // minutes
695
+ ms += parseInt(matches[3], 10) * 86400000; // days
389
696
  if (matches[4])
390
- ms += parseInt(matches[4], 10) * 1000; // seconds
697
+ ms += parseInt(matches[4], 10) * 3600000; // hours
391
698
  if (matches[5])
392
- ms += parseInt(matches[5], 10); // milliseconds
699
+ ms += parseInt(matches[5], 10) * 60000; // minutes
700
+ if (matches[6])
701
+ ms += parseInt(matches[6], 10) * 1000; // seconds
702
+ if (matches[7])
703
+ ms += parseInt(matches[7], 10); // milliseconds
704
+ this.cache.set(cacheKey, ms);
393
705
  return ms;
394
706
  };
395
707
  /**
@@ -397,9 +709,13 @@ var Env = /** @class */ (function () {
397
709
  *
398
710
  * @param {string[]} [sensitiveKeys=['password', 'secret', 'key', 'token', 'auth']] - Keys to mask.
399
711
  * @returns {Record<string, string>} Environment variables with sensitive values masked.
712
+ *
713
+ * @example
714
+ * console.log(Env.getSafeEnv(['password', 'secret', 'key']));
715
+ * // { DATABASE_URL: "postgres://...", API_KEY: "******", ... }
400
716
  */
401
717
  Env.getSafeEnv = function (sensitiveKeys) {
402
- var e_1, _a;
718
+ var e_2, _a;
403
719
  if (sensitiveKeys === void 0) { sensitiveKeys = ['password', 'secret', 'key', 'token', 'auth']; }
404
720
  var safeEnv = {};
405
721
  var _loop_1 = function (key, value) {
@@ -414,15 +730,98 @@ var Env = /** @class */ (function () {
414
730
  _loop_1(key, value);
415
731
  }
416
732
  }
417
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
733
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
418
734
  finally {
419
735
  try {
420
736
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
421
737
  }
422
- finally { if (e_1) throw e_1.error; }
738
+ finally { if (e_2) throw e_2.error; }
423
739
  }
424
740
  return safeEnv;
425
741
  };
742
+ /**
743
+ * Loads environment variables from a .env file.
744
+ * Does not override existing variables.
745
+ *
746
+ * @param {string} [path='.env'] - Path to the .env file.
747
+ * @returns {Record<string, string>} Loaded environment variables.
748
+ *
749
+ * @example
750
+ * // Load variables from .env.development
751
+ * Env.loadFromFile('.env.development');
752
+ */
753
+ Env.loadFromFile = function (path) {
754
+ if (path === void 0) { path = '.env'; }
755
+ if (!existsSync(path)) {
756
+ throw new Error("Environment file not found: \"".concat(path, "\""));
757
+ }
758
+ var content = readFileSync(path, 'utf8');
759
+ var variables = {};
760
+ var lines = content.split(/\r?\n/);
761
+ var i = 0;
762
+ while (i < lines.length) {
763
+ var line = lines[i].trim();
764
+ // Skip empty lines or comment-only lines
765
+ if (!line || line.startsWith('#')) {
766
+ i++;
767
+ continue;
768
+ }
769
+ var match = line.match(/^([^=]+)=(.*)$/);
770
+ if (!match) {
771
+ i++;
772
+ continue;
773
+ }
774
+ var key = match[1].trim();
775
+ var value = match[2].trim();
776
+ // Remove inline comment for unquoted values
777
+ if (!/^['"]/.test(value)) {
778
+ var hashIndex = value.indexOf(' #');
779
+ if (hashIndex !== -1) {
780
+ value = value.slice(0, hashIndex).trim();
781
+ }
782
+ }
783
+ // Handle quoted values
784
+ if ((value.startsWith('"') || value.startsWith("'")) && value.length > 1) {
785
+ var quote = value[0];
786
+ if (!value.endsWith(quote) || value.length === 1) {
787
+ // multiline quoted
788
+ var multilineValue = value.slice(1);
789
+ i++;
790
+ while (i < lines.length) {
791
+ var nextLine = lines[i];
792
+ if (nextLine.endsWith(quote)) {
793
+ multilineValue += '\n' + nextLine.slice(0, -1);
794
+ break;
795
+ }
796
+ else {
797
+ multilineValue += '\n' + nextLine;
798
+ }
799
+ i++;
800
+ }
801
+ value = multilineValue;
802
+ }
803
+ else {
804
+ // single-line quoted
805
+ value = value.slice(1, -1);
806
+ }
807
+ }
808
+ else {
809
+ // Handle unquoted multiline: continue collecting until next key=value or empty line
810
+ i++;
811
+ while (i < lines.length && !lines[i].includes('=') && lines[i].trim() !== '') {
812
+ value += '\n' + lines[i];
813
+ i++;
814
+ }
815
+ i--; // adjust for outer loop
816
+ }
817
+ if (!process.env[key]) {
818
+ process.env[key] = value;
819
+ variables[key] = value;
820
+ }
821
+ i++;
822
+ }
823
+ return variables;
824
+ };
426
825
  /**
427
826
  * Checks whether the specified environment variable exists.
428
827
  *
@@ -439,8 +838,35 @@ var Env = /** @class */ (function () {
439
838
  * @returns {void}
440
839
  */
441
840
  Env.delete = function (key) {
841
+ var e_3, _a;
442
842
  delete process.env[key];
843
+ this.cache.delete(key);
844
+ try {
845
+ // Also clear all cached variations of this key
846
+ for (var _b = __values(this.cache.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
847
+ var cacheKey = _c.value;
848
+ if (cacheKey.includes(":".concat(key))) {
849
+ this.cache.delete(cacheKey);
850
+ }
851
+ }
852
+ }
853
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
854
+ finally {
855
+ try {
856
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
857
+ }
858
+ finally { if (e_3) throw e_3.error; }
859
+ }
860
+ };
861
+ /**
862
+ * Clears the internal cache of parsed environment values.
863
+ * Useful for testing or when environment variables might change.
864
+ */
865
+ Env.clearCache = function () {
866
+ this.cache.clear();
443
867
  };
868
+ // Cache for parsed values to avoid repeated parsing of complex values
869
+ Env.cache = new Map();
444
870
  return Env;
445
871
  }());
446
872
  export { Env };