envapt 7.0.3 → 8.0.0-next.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.
Files changed (298) hide show
  1. package/CHANGELOG.md +32 -101
  2. package/README.md +5 -5
  3. package/dist/node/converters/BuiltInConverters.cjs +1 -1
  4. package/dist/node/converters/BuiltInConverters.cjs.map +1 -1
  5. package/dist/node/converters/BuiltInConverters.mjs +1 -1
  6. package/dist/node/converters/BuiltInConverters.mjs.map +1 -1
  7. package/dist/node/converters/Converters.cjs.map +1 -1
  8. package/dist/node/converters/Converters.mjs.map +1 -1
  9. package/dist/node/converters/ValueConverter.cjs +1 -1
  10. package/dist/node/converters/ValueConverter.cjs.map +1 -1
  11. package/dist/node/converters/ValueConverter.mjs +1 -1
  12. package/dist/node/converters/ValueConverter.mjs.map +1 -1
  13. package/dist/node/core/AdvancedMethods.cjs +1 -1
  14. package/dist/node/core/AdvancedMethods.cjs.map +1 -1
  15. package/dist/node/core/AdvancedMethods.mjs +1 -1
  16. package/dist/node/core/AdvancedMethods.mjs.map +1 -1
  17. package/dist/node/core/EnvapterBase.cjs +1 -1
  18. package/dist/node/core/EnvapterBase.cjs.map +1 -1
  19. package/dist/node/core/EnvapterBase.mjs +1 -1
  20. package/dist/node/core/EnvapterBase.mjs.map +1 -1
  21. package/dist/node/core/Environment.cjs +2 -0
  22. package/dist/node/core/Environment.cjs.map +1 -0
  23. package/dist/node/core/Environment.mjs +2 -0
  24. package/dist/node/core/Environment.mjs.map +1 -0
  25. package/dist/node/core/EnvironmentMethods.cjs +1 -1
  26. package/dist/node/core/EnvironmentMethods.cjs.map +1 -1
  27. package/dist/node/core/EnvironmentMethods.mjs +1 -1
  28. package/dist/node/core/EnvironmentMethods.mjs.map +1 -1
  29. package/dist/node/core/PrimitiveMethods.cjs +1 -1
  30. package/dist/node/core/PrimitiveMethods.cjs.map +1 -1
  31. package/dist/node/core/PrimitiveMethods.mjs +1 -1
  32. package/dist/node/core/PrimitiveMethods.mjs.map +1 -1
  33. package/dist/node/core/engine.cjs +2 -0
  34. package/dist/node/core/engine.cjs.map +1 -0
  35. package/dist/node/core/engine.mjs +2 -0
  36. package/dist/node/core/engine.mjs.map +1 -0
  37. package/dist/node/core/paths.cjs +2 -0
  38. package/dist/node/core/paths.cjs.map +1 -0
  39. package/dist/node/core/paths.mjs +2 -0
  40. package/dist/node/core/paths.mjs.map +1 -0
  41. package/dist/node/core/state.cjs +2 -0
  42. package/dist/node/core/state.cjs.map +1 -0
  43. package/dist/node/core/state.mjs +2 -0
  44. package/dist/node/core/state.mjs.map +1 -0
  45. package/dist/node/decorators/resolveDecoratorValue.cjs +1 -1
  46. package/dist/node/decorators/resolveDecoratorValue.cjs.map +1 -1
  47. package/dist/node/decorators/resolveDecoratorValue.mjs +1 -1
  48. package/dist/node/decorators/resolveDecoratorValue.mjs.map +1 -1
  49. package/dist/node/engine/Envapter.cjs +1 -1
  50. package/dist/node/engine/Envapter.cjs.map +1 -1
  51. package/dist/node/engine/Envapter.mjs +1 -1
  52. package/dist/node/engine/Envapter.mjs.map +1 -1
  53. package/dist/node/engine/NodeEnvapter.cjs +1 -1
  54. package/dist/node/engine/NodeEnvapter.cjs.map +1 -1
  55. package/dist/node/engine/NodeEnvapter.mjs +1 -1
  56. package/dist/node/engine/NodeEnvapter.mjs.map +1 -1
  57. package/dist/node/engine/TemplateResolver.cjs +1 -1
  58. package/dist/node/engine/TemplateResolver.cjs.map +1 -1
  59. package/dist/node/engine/TemplateResolver.mjs +1 -1
  60. package/dist/node/engine/TemplateResolver.mjs.map +1 -1
  61. package/dist/node/engine/Validators.cjs +1 -1
  62. package/dist/node/engine/Validators.cjs.map +1 -1
  63. package/dist/node/engine/Validators.mjs +1 -1
  64. package/dist/node/engine/Validators.mjs.map +1 -1
  65. package/dist/node/index.cjs +1 -1
  66. package/dist/node/index.mjs +1 -1
  67. package/dist/node/infra/Error.cjs +1 -1
  68. package/dist/node/infra/Error.cjs.map +1 -1
  69. package/dist/node/infra/Error.mjs +1 -1
  70. package/dist/node/infra/Error.mjs.map +1 -1
  71. package/dist/node/infra/recase.cjs +2 -0
  72. package/dist/node/infra/recase.cjs.map +1 -0
  73. package/dist/node/infra/recase.mjs +2 -0
  74. package/dist/node/infra/recase.mjs.map +1 -0
  75. package/dist/node/infra/runtime.cjs.map +1 -1
  76. package/dist/node/infra/runtime.mjs.map +1 -1
  77. package/dist/node/sources/{NodeEnvSource.cjs → FileSource.cjs} +2 -2
  78. package/dist/node/sources/FileSource.cjs.map +1 -0
  79. package/dist/node/sources/{NodeEnvSource.mjs → FileSource.mjs} +2 -2
  80. package/dist/node/sources/FileSource.mjs.map +1 -0
  81. package/dist/node/sources/{ManualEnvSource.cjs → PortableSource.cjs} +2 -2
  82. package/dist/node/sources/PortableSource.cjs.map +1 -0
  83. package/dist/{browser/sources/ManualEnvSource.mjs → node/sources/PortableSource.mjs} +2 -2
  84. package/dist/node/sources/PortableSource.mjs.map +1 -0
  85. package/dist/node/sources/{UnboundEnvSource.cjs → UnboundSource.cjs} +2 -2
  86. package/dist/node/sources/UnboundSource.cjs.map +1 -0
  87. package/dist/{browser/sources/UnboundEnvSource.mjs → node/sources/UnboundSource.mjs} +2 -2
  88. package/dist/node/sources/UnboundSource.mjs.map +1 -0
  89. package/dist/node/sources/coerce.cjs.map +1 -1
  90. package/dist/node/sources/coerce.mjs.map +1 -1
  91. package/dist/node/sources/merge.cjs +2 -0
  92. package/dist/node/sources/merge.cjs.map +1 -0
  93. package/dist/node/sources/merge.mjs +2 -0
  94. package/dist/node/sources/merge.mjs.map +1 -0
  95. package/dist/portable/converters/BuiltInConverters.mjs +2 -0
  96. package/dist/portable/converters/BuiltInConverters.mjs.map +1 -0
  97. package/dist/portable/converters/Converters.mjs.map +1 -0
  98. package/dist/portable/converters/ValueConverter.mjs +2 -0
  99. package/dist/portable/converters/ValueConverter.mjs.map +1 -0
  100. package/dist/portable/core/AdvancedMethods.mjs +2 -0
  101. package/dist/portable/core/AdvancedMethods.mjs.map +1 -0
  102. package/dist/portable/core/EnvapterBase.mjs +2 -0
  103. package/dist/portable/core/EnvapterBase.mjs.map +1 -0
  104. package/dist/portable/core/Environment.mjs +2 -0
  105. package/dist/portable/core/Environment.mjs.map +1 -0
  106. package/dist/portable/core/EnvironmentMethods.mjs +2 -0
  107. package/dist/portable/core/EnvironmentMethods.mjs.map +1 -0
  108. package/dist/portable/core/PrimitiveMethods.mjs +2 -0
  109. package/dist/portable/core/PrimitiveMethods.mjs.map +1 -0
  110. package/dist/portable/core/engine.mjs +2 -0
  111. package/dist/portable/core/engine.mjs.map +1 -0
  112. package/dist/portable/core/paths.mjs +2 -0
  113. package/dist/portable/core/paths.mjs.map +1 -0
  114. package/dist/portable/core/state.mjs +2 -0
  115. package/dist/portable/core/state.mjs.map +1 -0
  116. package/dist/portable/decorators/resolveDecoratorValue.mjs +2 -0
  117. package/dist/portable/decorators/resolveDecoratorValue.mjs.map +1 -0
  118. package/dist/portable/engine/Envapter.mjs +2 -0
  119. package/dist/portable/engine/Envapter.mjs.map +1 -0
  120. package/dist/portable/engine/PortableEnvapter.mjs +2 -0
  121. package/dist/portable/engine/PortableEnvapter.mjs.map +1 -0
  122. package/dist/portable/engine/TemplateResolver.mjs +2 -0
  123. package/dist/portable/engine/TemplateResolver.mjs.map +1 -0
  124. package/dist/portable/engine/Validators.mjs +2 -0
  125. package/dist/portable/engine/Validators.mjs.map +1 -0
  126. package/dist/portable/engine/fileApiStub.mjs +2 -0
  127. package/dist/portable/engine/fileApiStub.mjs.map +1 -0
  128. package/dist/portable/index.mjs +1 -0
  129. package/dist/{browser → portable}/infra/Error.mjs +1 -1
  130. package/dist/{browser → portable}/infra/Error.mjs.map +1 -1
  131. package/dist/portable/infra/recase.mjs +2 -0
  132. package/dist/portable/infra/recase.mjs.map +1 -0
  133. package/dist/portable/infra/runtime.mjs.map +1 -0
  134. package/dist/{browser/sources/WorkerEnvSource.mjs → portable/sources/PortableSource.mjs} +2 -2
  135. package/dist/portable/sources/PortableSource.mjs.map +1 -0
  136. package/dist/{node/sources/UnboundEnvSource.mjs → portable/sources/UnboundSource.mjs} +2 -2
  137. package/dist/portable/sources/UnboundSource.mjs.map +1 -0
  138. package/dist/portable/sources/coerce.mjs.map +1 -0
  139. package/dist/portable/sources/merge.mjs +2 -0
  140. package/dist/portable/sources/merge.mjs.map +1 -0
  141. package/dist/types/converters/Converters.d.mts +1 -15
  142. package/dist/types/core/AdvancedMethods.d.mts +31 -19
  143. package/dist/types/core/EnvapterBase.d.mts +16 -30
  144. package/dist/types/core/Environment.d.mts +25 -0
  145. package/dist/types/core/EnvironmentMethods.d.mts +2 -67
  146. package/dist/types/core/PrimitiveMethods.d.mts +2 -10
  147. package/dist/types/engine/Envapter.d.mts +2 -3
  148. package/dist/types/engine/NodeEnvapter.d.mts +4 -7
  149. package/dist/types/engine/PortableEnvapter.d.mts +17 -5
  150. package/dist/types/index.d.mts +10 -13
  151. package/dist/types/index.portable.d.mts +9 -12
  152. package/dist/types/infra/Error.d.mts +3 -1
  153. package/dist/types/infra/StandardSchema.d.mts +1 -12
  154. package/dist/types/sources/{NodeEnvSource.d.mts → FileSource.d.mts} +5 -5
  155. package/dist/types/sources/PortableSource.d.mts +24 -0
  156. package/dist/types/sources/merge.d.mts +13 -0
  157. package/dist/types/types/Casing.d.mts +8 -0
  158. package/dist/types/types/Conversion.d.mts +9 -66
  159. package/dist/types/types/Decorator.d.mts +0 -14
  160. package/dist/types/types/Env.d.mts +1 -10
  161. package/dist/types/types/Options.d.mts +9 -2
  162. package/dist/types/types/Schema.d.mts +1 -13
  163. package/dist/types/types/Source.d.mts +8 -28
  164. package/package.json +62 -19
  165. package/aliases/browser.d.mts +0 -7
  166. package/aliases/browser.mjs +0 -4
  167. package/aliases/workerd.d.mts +0 -7
  168. package/aliases/workerd.mjs +0 -4
  169. package/dist/browser/converters/BuiltInConverters.mjs +0 -2
  170. package/dist/browser/converters/BuiltInConverters.mjs.map +0 -1
  171. package/dist/browser/converters/Converters.mjs.map +0 -1
  172. package/dist/browser/converters/ValueConverter.mjs +0 -2
  173. package/dist/browser/converters/ValueConverter.mjs.map +0 -1
  174. package/dist/browser/core/AdvancedMethods.mjs +0 -2
  175. package/dist/browser/core/AdvancedMethods.mjs.map +0 -1
  176. package/dist/browser/core/EnvapterBase.mjs +0 -2
  177. package/dist/browser/core/EnvapterBase.mjs.map +0 -1
  178. package/dist/browser/core/EnvironmentMethods.mjs +0 -2
  179. package/dist/browser/core/EnvironmentMethods.mjs.map +0 -1
  180. package/dist/browser/core/PrimitiveMethods.mjs +0 -2
  181. package/dist/browser/core/PrimitiveMethods.mjs.map +0 -1
  182. package/dist/browser/decorators/resolveDecoratorValue.mjs +0 -2
  183. package/dist/browser/decorators/resolveDecoratorValue.mjs.map +0 -1
  184. package/dist/browser/engine/Envapter.mjs +0 -2
  185. package/dist/browser/engine/Envapter.mjs.map +0 -1
  186. package/dist/browser/engine/PortableEnvapter.mjs +0 -2
  187. package/dist/browser/engine/PortableEnvapter.mjs.map +0 -1
  188. package/dist/browser/engine/TemplateResolver.mjs +0 -2
  189. package/dist/browser/engine/TemplateResolver.mjs.map +0 -1
  190. package/dist/browser/engine/Validators.mjs +0 -2
  191. package/dist/browser/engine/Validators.mjs.map +0 -1
  192. package/dist/browser/engine/installFileApiStubs.mjs +0 -2
  193. package/dist/browser/engine/installFileApiStubs.mjs.map +0 -1
  194. package/dist/browser/index.mjs +0 -1
  195. package/dist/browser/infra/runtime.mjs.map +0 -1
  196. package/dist/browser/sources/ManualEnvSource.mjs.map +0 -1
  197. package/dist/browser/sources/UnboundEnvSource.mjs.map +0 -1
  198. package/dist/browser/sources/WorkerEnvSource.mjs.map +0 -1
  199. package/dist/browser/sources/coerce.mjs.map +0 -1
  200. package/dist/node/sources/ManualEnvSource.cjs.map +0 -1
  201. package/dist/node/sources/ManualEnvSource.mjs +0 -2
  202. package/dist/node/sources/ManualEnvSource.mjs.map +0 -1
  203. package/dist/node/sources/NodeEnvSource.cjs.map +0 -1
  204. package/dist/node/sources/NodeEnvSource.mjs.map +0 -1
  205. package/dist/node/sources/UnboundEnvSource.cjs.map +0 -1
  206. package/dist/node/sources/UnboundEnvSource.mjs.map +0 -1
  207. package/dist/node/sources/WorkerEnvSource.cjs +0 -2
  208. package/dist/node/sources/WorkerEnvSource.cjs.map +0 -1
  209. package/dist/node/sources/WorkerEnvSource.mjs +0 -2
  210. package/dist/node/sources/WorkerEnvSource.mjs.map +0 -1
  211. package/dist/types/converters/ValueConverter.d.mts +0 -25
  212. package/dist/types/engine/TemplateResolver.d.mts +0 -17
  213. package/dist/types/sources/ManualEnvSource.d.mts +0 -22
  214. package/dist/types/sources/WorkerEnvSource.d.mts +0 -22
  215. package/dist/workerd/converters/BuiltInConverters.mjs +0 -2
  216. package/dist/workerd/converters/BuiltInConverters.mjs.map +0 -1
  217. package/dist/workerd/converters/Converters.mjs +0 -2
  218. package/dist/workerd/converters/Converters.mjs.map +0 -1
  219. package/dist/workerd/converters/ListOfBuiltInConverters.mjs +0 -2
  220. package/dist/workerd/converters/ListOfBuiltInConverters.mjs.map +0 -1
  221. package/dist/workerd/converters/ValueConverter.mjs +0 -2
  222. package/dist/workerd/converters/ValueConverter.mjs.map +0 -1
  223. package/dist/workerd/core/AdvancedMethods.mjs +0 -2
  224. package/dist/workerd/core/AdvancedMethods.mjs.map +0 -1
  225. package/dist/workerd/core/EnvapterBase.mjs +0 -2
  226. package/dist/workerd/core/EnvapterBase.mjs.map +0 -1
  227. package/dist/workerd/core/EnvironmentMethods.mjs +0 -2
  228. package/dist/workerd/core/EnvironmentMethods.mjs.map +0 -1
  229. package/dist/workerd/core/PrimitiveMethods.mjs +0 -2
  230. package/dist/workerd/core/PrimitiveMethods.mjs.map +0 -1
  231. package/dist/workerd/decorators/legacy/Envapt.mjs +0 -2
  232. package/dist/workerd/decorators/legacy/Envapt.mjs.map +0 -1
  233. package/dist/workerd/decorators/legacy/SugarDecorators.mjs +0 -2
  234. package/dist/workerd/decorators/legacy/SugarDecorators.mjs.map +0 -1
  235. package/dist/workerd/decorators/legacy/createPropertyDecorator.mjs +0 -2
  236. package/dist/workerd/decorators/legacy/createPropertyDecorator.mjs.map +0 -1
  237. package/dist/workerd/decorators/modern/Envapt.mjs +0 -2
  238. package/dist/workerd/decorators/modern/Envapt.mjs.map +0 -1
  239. package/dist/workerd/decorators/modern/SugarDecorators.mjs +0 -2
  240. package/dist/workerd/decorators/modern/SugarDecorators.mjs.map +0 -1
  241. package/dist/workerd/decorators/modern/createAccessorDecorator.mjs +0 -2
  242. package/dist/workerd/decorators/modern/createAccessorDecorator.mjs.map +0 -1
  243. package/dist/workerd/decorators/parseEnvaptOptions.mjs +0 -2
  244. package/dist/workerd/decorators/parseEnvaptOptions.mjs.map +0 -1
  245. package/dist/workerd/decorators/resolveDecoratorValue.mjs +0 -2
  246. package/dist/workerd/decorators/resolveDecoratorValue.mjs.map +0 -1
  247. package/dist/workerd/engine/Envapter.mjs +0 -2
  248. package/dist/workerd/engine/Envapter.mjs.map +0 -1
  249. package/dist/workerd/engine/PortableEnvapter.mjs +0 -2
  250. package/dist/workerd/engine/PortableEnvapter.mjs.map +0 -1
  251. package/dist/workerd/engine/TemplateResolver.mjs +0 -2
  252. package/dist/workerd/engine/TemplateResolver.mjs.map +0 -1
  253. package/dist/workerd/engine/Validators.mjs +0 -2
  254. package/dist/workerd/engine/Validators.mjs.map +0 -1
  255. package/dist/workerd/engine/installFileApiStubs.mjs +0 -2
  256. package/dist/workerd/engine/installFileApiStubs.mjs.map +0 -1
  257. package/dist/workerd/index.mjs +0 -1
  258. package/dist/workerd/infra/Debug.mjs +0 -2
  259. package/dist/workerd/infra/Debug.mjs.map +0 -1
  260. package/dist/workerd/infra/Dotenv.mjs +0 -3
  261. package/dist/workerd/infra/Dotenv.mjs.map +0 -1
  262. package/dist/workerd/infra/Error.mjs +0 -2
  263. package/dist/workerd/infra/Error.mjs.map +0 -1
  264. package/dist/workerd/infra/runtime.mjs +0 -2
  265. package/dist/workerd/infra/runtime.mjs.map +0 -1
  266. package/dist/workerd/legacy.mjs +0 -1
  267. package/dist/workerd/sources/ManualEnvSource.mjs +0 -2
  268. package/dist/workerd/sources/ManualEnvSource.mjs.map +0 -1
  269. package/dist/workerd/sources/UnboundEnvSource.mjs +0 -2
  270. package/dist/workerd/sources/UnboundEnvSource.mjs.map +0 -1
  271. package/dist/workerd/sources/WorkerEnvSource.mjs +0 -2
  272. package/dist/workerd/sources/WorkerEnvSource.mjs.map +0 -1
  273. package/dist/workerd/sources/coerce.mjs +0 -2
  274. package/dist/workerd/sources/coerce.mjs.map +0 -1
  275. /package/dist/{browser → portable}/converters/Converters.mjs +0 -0
  276. /package/dist/{browser → portable}/converters/ListOfBuiltInConverters.mjs +0 -0
  277. /package/dist/{browser → portable}/converters/ListOfBuiltInConverters.mjs.map +0 -0
  278. /package/dist/{browser → portable}/decorators/legacy/Envapt.mjs +0 -0
  279. /package/dist/{browser → portable}/decorators/legacy/Envapt.mjs.map +0 -0
  280. /package/dist/{browser → portable}/decorators/legacy/SugarDecorators.mjs +0 -0
  281. /package/dist/{browser → portable}/decorators/legacy/SugarDecorators.mjs.map +0 -0
  282. /package/dist/{browser → portable}/decorators/legacy/createPropertyDecorator.mjs +0 -0
  283. /package/dist/{browser → portable}/decorators/legacy/createPropertyDecorator.mjs.map +0 -0
  284. /package/dist/{browser → portable}/decorators/modern/Envapt.mjs +0 -0
  285. /package/dist/{browser → portable}/decorators/modern/Envapt.mjs.map +0 -0
  286. /package/dist/{browser → portable}/decorators/modern/SugarDecorators.mjs +0 -0
  287. /package/dist/{browser → portable}/decorators/modern/SugarDecorators.mjs.map +0 -0
  288. /package/dist/{browser → portable}/decorators/modern/createAccessorDecorator.mjs +0 -0
  289. /package/dist/{browser → portable}/decorators/modern/createAccessorDecorator.mjs.map +0 -0
  290. /package/dist/{browser → portable}/decorators/parseEnvaptOptions.mjs +0 -0
  291. /package/dist/{browser → portable}/decorators/parseEnvaptOptions.mjs.map +0 -0
  292. /package/dist/{browser → portable}/infra/Debug.mjs +0 -0
  293. /package/dist/{browser → portable}/infra/Debug.mjs.map +0 -0
  294. /package/dist/{browser → portable}/infra/Dotenv.mjs +0 -0
  295. /package/dist/{browser → portable}/infra/Dotenv.mjs.map +0 -0
  296. /package/dist/{browser → portable}/infra/runtime.mjs +0 -0
  297. /package/dist/{browser → portable}/legacy.mjs +0 -0
  298. /package/dist/{browser → portable}/sources/coerce.mjs +0 -0
package/CHANGELOG.md CHANGED
@@ -1,84 +1,64 @@
1
1
  # envapt
2
2
 
3
- ## 7.0.3
4
-
5
- ### Patch Changes
6
-
7
- - deprecate the envapt/workerd and envapt/browser subpaths. both still work but now log a deprecation warning on import. import directly from `envapt` instead. removed in v8.
8
-
9
- ## 7.0.2
3
+ ## 8.0.0-next.0
10
4
 
11
- ### Patch Changes
5
+ ### Major Changes
12
6
 
13
- - 2cf58a0: fix malformed CJS output (tsdown shim banner leaked ESM syntax into every .cjs)
7
+ - f889a67: Add `getRequired(key, converter)` and `getRequiredAll(spec, casing?)` for typed required reads. `getRequired` takes the converter positionally, returns the non-undefined value, and throws `MissingEnvValue` on a missing or empty key. `getRequiredAll` reads a group in one call and returns a typed record, throwing once listing every missing key. Its spec values can be tokens, `array()` tokens, or custom parser functions, and an optional `casing` (`'camelCase'`, `'PascalCase'`, or `'kebab-case'`) renames the record keys.
14
8
 
15
- ## 7.0.2-next.0
9
+ **BREAKING:** the `{ required: true }` options-bag form of `getUsing` and `getWith` is removed, use `getRequired` instead. The `@Envapt` decorator's `{ required: true }` option is unchanged.
16
10
 
17
- ### Patch Changes
11
+ - 5e02661: Move the engine's mutable state and read cache into a module that the `exports` map does not include. They are no longer fields on the class and have no import path, so outside code cannot read or write them through an `as`-cast or a subclass. Drop the internal `TimeUnit` type and `isStrict()` method from the public exports.
12
+ - 651008e: **BREAKING:** Tighten the `Integer` and `Float` converters.
18
13
 
19
- - 5719aa6: fix malformed CJS output (tsdown shim banner leaked ESM syntax into every .cjs)
14
+ `Converters.Integer` parses with `Number` and requires `Number.isSafeInteger`, so trailing characters (`42abc`), non-integers (`3.9`), and values past 2^53 now fall back. `Converters.Float` parses with `Number`, so trailing characters (`3.14xyz`) now fall back. `Float` still accepts `Infinity`.
20
15
 
21
- ## 7.0.1
16
+ - d415d68: Trim internal-only types out of the public API surface, from 36 exported types down to 15. Gone are the source shape interfaces, the decorator return types, the schema brands, the converter/inference machinery, the `EnvKeyInput`/`ArrayOf`/`ArrayElement` helpers, and the redundant `InferSchemaInput`/`InferSchemaOutput` aliases. Type inference on the readers and decorators is unchanged, since these types are inferred at the call site or reproducible from the still-public `Source` and `StandardSchemaV1`. For a schema's output type, use your validator's own inference (`z.infer`, valibot's `InferOutput`, arktype's `.infer`) or `StandardSchemaV1.InferOutput`.
17
+ - d415d68: Collapse to one portable build and a single universal `envapt` import, and rename the source classes. Three breaking changes.
22
18
 
23
- ### Patch Changes
19
+ 1. The source classes drop the `Env` infix. `PortableSource` (was `ManualEnvSource` / `WorkerEnvSource`, which were the same class) is the one source for every runtime without a filesystem. `FileSource` (was `NodeEnvSource`) is the Node source. The `Source` type replaces `EnvSource`. The v7.1 deprecated aliases are removed.
20
+ 2. `Envapter.fileApiMode` defaults to `'warn'`. On the portable build the file-only config APIs (`envPaths`, `baseDir`, `envFileOptions`, `configureProfiles`, `resetProfiles`) now warn once and no-op by default. Set `Envapter.fileApiMode = 'throw'` to restore the previous throwing behavior. An unconfigured read still throws `NoSourceBound` on first access.
21
+ 3. The `envapt/workerd` and `envapt/browser` subpaths are removed. Import from `envapt` everywhere. The package exports route Workers, the browser, and the edge runtimes (workerd, edge-light, fastly, worker, browser, react-native) to the portable build, and Node, Bun, and Deno to the node build. The portable types now include the file APIs, so config shared between dev and deploy compiles on every runtime.
24
22
 
25
- - 8f4cac8: Fixed: `syncProcessEnv` and `import 'envapt/config'` now mirror template-resolved values to `process.env`, matching `Envapter.get`.
26
-
27
- Also, verbose debug logging reports the base directory in use now.
28
-
29
- - 8f4cac8: `Envapter.debug = 'warn'` now logs whenever a read hits a missing or empty variable, including reads with no fallback and reads through `getUsing`, `getWith`, and `parse`. Previously only a read that fell back to a provided default logged, so a bare `Envapter.get('MISSING')` was silent.
23
+ ### Minor Changes
30
24
 
31
- ## 7.0.1-next.0
25
+ - 5dea9fb: Add `merge`, a source combinator that layers several sources with last-wins precedence. It keeps the `.env` cascade and file APIs on one filesystem-backed member, and throws `InvalidMergedSource` with no members or more than one file-backed member.
32
26
 
33
27
  ### Patch Changes
34
28
 
35
- - 8f4cac8: Fixed: `syncProcessEnv` and `import 'envapt/config'` now mirror template-resolved values to `process.env`, matching `Envapter.get`.
29
+ - 5dea9fb: Fix the read cache rebuilding on every access when a bound source and the `.env` cascade resolve to no keys. It now builds once per `useSource`, matching a non-empty source.
30
+ - 48d4f02: Move the engine read-path into module functions under core/ so a consumer subclass can no longer reach or mutate the read cache. No public API change.
36
31
 
37
- Also, verbose debug logging reports the base directory in use now.
38
-
39
- - 8f4cac8: `Envapter.debug = 'warn'` now logs whenever a read hits a missing or empty variable, including reads with no fallback and reads through `getUsing`, `getWith`, and `parse`. Previously only a read that fell back to a provided default logged, so a bare `Envapter.get('MISSING')` was silent.
40
-
41
- ## 7.0.0
42
-
43
- ### Major Changes
44
-
45
- - da55055: **BREAKING:** This should have been done long ago, but all the legacy decorators (`@Envapt` and the sugar decorators) now correctly typecheck the field they are decorating. Say, for example you had `@EnvNum(PORT)` on a field, but the field was typed as `number`, you would now get an error that says `'{ '[envapt] field type must hold the converter output': number | null; }'` because without a fallback, the field would be assigned a `null` value if the environment variable is not set. And of course, this also means completely incorrectly typed fields will also not compile anymore. This was the intended behavior so it should be a minor, but because of how many of my own tests it broke, I'm releasing it as a major.
46
- - da55055: **BREAKING.** Modern (TC39 Stage 3) decorators are now the default.
47
-
48
- `@Envapt` and the sugar decorators (`@EnvNum`, `@EnvStr`, `@EnvBool`, `@EnvUrl`, `@EnvTime`) imported from `envapt` are now Stage 3 accessor decorators. Decorate with the `accessor` keyword, `static accessor port: number` for a static field and `accessor port!: number` for an instance field. They need no `experimentalDecorators` flag and work on any runtime, including Bun and Deno running `.ts` directly.
49
-
50
- The legacy (experimentalDecorators) decorators move to a subpath. Change `import { Envapt } from 'envapt'` to `import { Envapt } from 'envapt/legacy'` to keep the old `static readonly` / `declare readonly` form, which still requires `experimentalDecorators: true`. Everything else (`Envapter`, `Converters`, sources, and types) stays on `envapt`.
32
+ ## 7.1.0
51
33
 
52
34
  ### Minor Changes
53
35
 
54
- - da55055: **BREAKING:** Legacy decorated properties now throw a clear error when you assign to them. `@Envapt` and the sugar decorators (from `envapt/legacy`) install a setter that throws `EnvaptError` with code `InvalidUserDefinedConfig`, because the value resolves from the environment and is read-only. Before, the property had only a getter, so an assignment was a silent no-op in sloppy mode and a native `TypeError` in strict mode. The modern decorators on `envapt` behave the same way.
36
+ - Add `PortableSource` and the `Source` type, the v8 names for the no-filesystem source class and the general source type.
37
+ `PortableSource` replaces both `ManualEnvSource` and `WorkerEnvSource`, which are now deprecated subclasses of it, so migrate `new ManualEnvSource(obj)` and `new WorkerEnvSource(env)` to `new PortableSource(...)`. `Source` replaces the now-deprecated `EnvSource` type. `PortableSource`'s constructor accepts any `object`, so a Cloudflare `Env` binding (an interface with no index signature) can be passed directly without a cast. Every deprecated name still works and is removed or renamed in v8.
38
+
39
+ ## 7.0.3
55
40
 
56
41
  ### Patch Changes
57
42
 
58
- - 54c8ecc: Bump dev dependencies.
59
- - da55055: Fix decorator value caching so a resolved `undefined` (from `fallback: undefined` or a converter that returns `undefined`) is cached once instead of re-resolving on every property access. The modern accessor decorator now throws `EnvaptError` when the runtime's Stage 3 transform does not provide the accessor name, rather than collapsing every accessor to one cache key.
60
- - 0bbcc85: Editor auto-import now suggests each public name once instead of once per runtime build. The published type declarations are emitted as a single shared tree that the Node, Workers, and browser entry points all re-export, so `Envapt`, `Envapter`, the converters, and the rest resolve to one declaration. The Workers and browser entries still expose the portable `Envapter` without the file-only APIs. The package no longer ships the redundant per-runtime declaration trees, so the install is smaller.
61
- - 5384199: The `envapt/browser` and `envapt/workerd` builds are now side-effect-free, so a bundler can drop the parts of envapt a consumer never imports. Importing a single export such as `EnvaptError` or `Converters` from the portable builds now ships about 1.3 kB instead of about 22 kB. The filesystem-only APIs (`envPaths`, `baseDir`, `envFileOptions`, `configureProfiles`, `resetProfiles`) still throw `EnvaptError` on the browser and Workers builds, their stubs moved onto the portable `Envapter` class so they install only when that class is used.
43
+ - deprecate the envapt/workerd and envapt/browser subpaths. both still work but now log a deprecation warning on import. import directly from `envapt` instead. removed in v8.
62
44
 
63
- ## 7.0.0-next.3
45
+ ## 7.0.2
64
46
 
65
47
  ### Patch Changes
66
48
 
67
- - 54c8ecc: Bump dev dependencies.
49
+ - 2cf58a0: fix malformed CJS output (tsdown shim banner leaked ESM syntax into every .cjs)
68
50
 
69
- ## 7.0.0-next.2
51
+ ## 7.0.1
70
52
 
71
53
  ### Patch Changes
72
54
 
73
- - 5384199: The `envapt/browser` and `envapt/workerd` builds are now side-effect-free, so a bundler can drop the parts of envapt a consumer never imports. Importing a single export such as `EnvaptError` or `Converters` from the portable builds now ships about 1.3 kB instead of about 22 kB. The filesystem-only APIs (`envPaths`, `baseDir`, `envFileOptions`, `configureProfiles`, `resetProfiles`) still throw `EnvaptError` on the browser and Workers builds, their stubs moved onto the portable `Envapter` class so they install only when that class is used.
74
-
75
- ## 7.0.0-next.1
55
+ - 8f4cac8: Fixed: `syncProcessEnv` and `import 'envapt/config'` now mirror template-resolved values to `process.env`, matching `Envapter.get`.
76
56
 
77
- ### Patch Changes
57
+ Also, verbose debug logging reports the base directory in use now.
78
58
 
79
- - 0bbcc85: Editor auto-import now suggests each public name once instead of once per runtime build. The published type declarations are emitted as a single shared tree that the Node, Workers, and browser entry points all re-export, so `Envapt`, `Envapter`, the converters, and the rest resolve to one declaration. The Workers and browser entries still expose the portable `Envapter` without the file-only APIs. The package no longer ships the redundant per-runtime declaration trees, so the install is smaller.
59
+ - 8f4cac8: `Envapter.debug = 'warn'` now logs whenever a read hits a missing or empty variable, including reads with no fallback and reads through `getUsing`, `getWith`, and `parse`. Previously only a read that fell back to a provided default logged, so a bare `Envapter.get('MISSING')` was silent.
80
60
 
81
- ## 7.0.0-next.0
61
+ ## 7.0.0
82
62
 
83
63
  ### Major Changes
84
64
 
@@ -95,7 +75,10 @@
95
75
 
96
76
  ### Patch Changes
97
77
 
78
+ - 54c8ecc: Bump dev dependencies.
98
79
  - da55055: Fix decorator value caching so a resolved `undefined` (from `fallback: undefined` or a converter that returns `undefined`) is cached once instead of re-resolving on every property access. The modern accessor decorator now throws `EnvaptError` when the runtime's Stage 3 transform does not provide the accessor name, rather than collapsing every accessor to one cache key.
80
+ - 0bbcc85: Editor auto-import now suggests each public name once instead of once per runtime build. The published type declarations are emitted as a single shared tree that the Node, Workers, and browser entry points all re-export, so `Envapt`, `Envapter`, the converters, and the rest resolve to one declaration. The Workers and browser entries still expose the portable `Envapter` without the file-only APIs. The package no longer ships the redundant per-runtime declaration trees, so the install is smaller.
81
+ - 5384199: The `envapt/browser` and `envapt/workerd` builds are now side-effect-free, so a bundler can drop the parts of envapt a consumer never imports. Importing a single export such as `EnvaptError` or `Converters` from the portable builds now ships about 1.3 kB instead of about 22 kB. The filesystem-only APIs (`envPaths`, `baseDir`, `envFileOptions`, `configureProfiles`, `resetProfiles`) still throw `EnvaptError` on the browser and Workers builds, their stubs moved onto the portable `Envapter` class so they install only when that class is used.
99
82
 
100
83
  ## 6.0.2
101
84
 
@@ -160,58 +143,6 @@
160
143
 
161
144
  - b8e26dd: Move the build and lint toolchain to TypeScript 6.0. No public API or runtime change.
162
145
 
163
- ## 5.2.0-next.2
164
-
165
- ### Patch Changes
166
-
167
- - bad5f6b: update package.json desc and engines/os
168
-
169
- ## 5.2.0-next.1
170
-
171
- ### Patch Changes
172
-
173
- - b8e26dd: Move the build and lint toolchain to TypeScript 6.0. No public API or runtime change.
174
-
175
- ## 5.2.0-next.0
176
-
177
- ### Minor Changes
178
-
179
- - e506a6d: `Envapter` now detects the test environment and reads Vite's `MODE`.
180
- - `Environment.Test` and `Envapter.isTest` are added. `NODE_ENV=test` (and Vite's `MODE=test`) now resolve to `Environment.Test`, where they previously fell through to `Development`. As a result, `isDevelopment` is no longer `true` under a test runner that sets `NODE_ENV=test`.
181
- - `MODE` joins the detection chain, after `ENVIRONMENT`, `ENV`, and `NODE_ENV`. Vite-family browser builds expose `import.meta.env.MODE` but none of the others, so `new ManualEnvSource(import.meta.env)` now sets the environment from `MODE`.
182
- - Environment names match case-insensitively. Previously `staging` was matched case-sensitively, so `STAGING` or `Staging` fell through to `Development`; `production` was already case-insensitive.
183
- - When no environment key is set, or its value is unrecognized, detection defaults to `Development` and emits a debug warning (visible with `Envapter.debug = 'warn'`).
184
-
185
- - e506a6d: envapt now runs on the browser and Cloudflare Workers, not only Node. The engine reads variables through a pluggable `EnvSource` instead of reading `process.env` directly, so the same `Envapter` and `@Envapt` API works against an injected object or a Workers binding.
186
-
187
- `Envapter.useSource(source)` binds the source; the bound source then backs every read, the `.env` cascade, and `Envapter.syncProcessEnv`. Built-in sources, all exported from `envapt`:
188
- - `NodeEnvSource`: a `process.env` snapshot plus the `.env` cascade. Bound automatically on Node, Bun, and Deno, so you do not call `useSource` yourself.
189
- - `WorkerEnvSource`: reads a Cloudflare Workers `env` binding. Non-string bindings are JSON-stringified so the converters still apply.
190
- - `ManualEnvSource`: reads any object you pass in, snapshotted at construction, with non-string values JSON-stringified like `WorkerEnvSource`. Pass `import.meta.env` or a bundler-injected object directly on the browser, or a plain object in tests.
191
-
192
- ```ts
193
- import { Envapter, ManualEnvSource } from 'envapt';
194
-
195
- Envapter.useSource(new ManualEnvSource({ PORT: '3000', FLAG: 'true' }));
196
- Envapter.getNumber('PORT'); // 3000
197
- ```
198
-
199
- The core imports no `node:*` module: `node:fs`, `node:path`, `node:process`, and `node:url` are confined to `NodeEnvSource`. envapt ships a build per runtime, so a Workers or browser bundle pulls in no Node built-ins, and workerd needs no `nodejs_compat` flag. Bare `envapt` resolves the right build through the `exports` conditions, and the dedicated `envapt/workerd` and `envapt/browser` entries add the matching types, which omit the file-only APIs so a stray call is a compile error rather than a runtime `FileApiUnsupported`.
200
-
201
- Two new `EnvaptErrorCodes` replace silent no-ops with a thrown error:
202
- - `NoSourceBound` (307): thrown on the first read when no source is bound.
203
- - `FileApiUnsupported` (306): thrown when `envPaths`, `baseDir`, or `configureProfiles` is called on a source without a filesystem.
204
-
205
- `EnvSource` is a union of `BareEnvSource` (no filesystem) and `FileEnvSource` (which requires `readFile`, `resolvePath`, `normalizeBaseDir`, and `writeVars` together), so a custom source has either the full file API or none of it.
206
-
207
- On Node, the `.env` cascade now loads when envapt is first imported rather than on the first variable read.
208
-
209
- ### Patch Changes
210
-
211
- - e506a6d: `Converters.Time` string fallbacks now accept decimals, matching raw env values.
212
-
213
- A fallback like `'1.5h'` previously threw `MalformedTimeFallback` even though the `TimeFallback` type (`` `${number}${TimeUnit}` ``) accepts it at compile time. Raw env values already allowed decimals, so the restriction only applied to fallbacks, which was inconsistent. A string fallback still requires an explicit unit (a unitless number is a number fallback), but `'1.5h'` now resolves to `5400000`.
214
-
215
146
  ## 5.1.1
216
147
 
217
148
  ### Patch Changes
package/README.md CHANGED
@@ -42,7 +42,7 @@ const port = Envapter.getNumber('PORT', 3000); // number, not string | undefined
42
42
  - **Zero runtime dependencies.** The reader, converters, and built-in `.env` parser are self-contained,
43
43
  so nothing is added to your dependency tree.
44
44
  - **Runs on Node, Bun, Deno, Cloudflare Workers, and the browser.** Node `>=20`, Bun `>=1.3`, Deno
45
- `>=2.5` (ESM and CJS). The Workers and browser builds resolve through the package `exports`
45
+ `>=2.5` (ESM and CJS). The portable build resolves through the package `exports`
46
46
  conditions.
47
47
  - **`.env` loading built in on Node.** The default Node source adds a per-environment file cascade,
48
48
  `${VAR}` templates, and strict / required checks. Off Node there is no filesystem, so you bind
@@ -75,14 +75,14 @@ const port = Envapter.getNumber('PORT', 3000);
75
75
  const origins = Envapter.getUsing('ALLOWED_ORIGINS', Converters.array(), []);
76
76
  ```
77
77
 
78
- On Cloudflare Workers, `env` is importable at module scope, so bind it once in a config module; in the
79
- browser, seed a `ManualEnvSource` from the object your bundler injects.
78
+ On Cloudflare Workers, `env` is importable at module scope, so bind it once in a config module, and in
79
+ the browser seed a `PortableSource` from the object your bundler injects.
80
80
 
81
81
  ```ts
82
82
  import { env } from 'cloudflare:workers';
83
- import { Envapter, WorkerEnvSource } from 'envapt';
83
+ import { Envapter, PortableSource } from 'envapt';
84
84
 
85
- Envapter.useSource(new WorkerEnvSource(env));
85
+ Envapter.useSource(new PortableSource(env));
86
86
 
87
87
  export const apiToken = Envapter.get('API_TOKEN');
88
88
  ```
@@ -1,2 +1,2 @@
1
- const e=require("../infra/Error.cjs"),t=1e3,n=60*t,r=60*n,i=24*r,a={ms:1,s:t,m:n,h:r,d:i,w:7*i},o=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)?$`,`u`),s=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$`,`u`);function c(e,t=!1){let n=e.match(t?s:o);if(!n)return;let[,r,i]=n;if(!r)return;let c=Number.parseFloat(r);if(!Number.isNaN(c))return c*a[i??`ms`]}var l=class t{static string(e,t){return String(e)}static number(e,t){let n=Number(e);return Number.isNaN(n)?t:n}static boolean(e,t){let n=e.toLowerCase().trim();return[`1`,`yes`,`true`,`on`].includes(n)?!0:[`0`,`no`,`false`,`off`].includes(n)?!1:t}static bigint(e,t){try{return BigInt(e)}catch{return t}}static symbol(e,t){try{return e?Symbol.for(e):t}catch{return t}}static integer(e,t){let n=Number.parseInt(e,10);return Number.isNaN(n)?t:n}static float(e,t){let n=Number.parseFloat(e);return Number.isNaN(n)?t:n}static json(e,t){try{return JSON.parse(e)}catch{return t}}static url(e,t){try{return new URL(e)}catch{return t}}static regexp(e,t){try{let t=e.match(new RegExp(String.raw`^\/(.+)\/([gimsuvy]*)$`));return t?new RegExp(t[1],t[2]):new RegExp(e)}catch{return t}}static date(e,t){if(new RegExp(String.raw`^\d+$`).test(e)){let n=new Date(parseInt(e,10));return Number.isNaN(n.getTime())?t:n}if(!new RegExp(String.raw`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$`,`u`).test(e))return t;let n=new Date(e);return Number.isNaN(n.getTime())?t:n}static time(t,n){let r=c(t);if(r!==void 0)return r;if(typeof n==`number`)return n;if(typeof n==`string`){let t=c(n,!0);if(t===void 0)throw new e.EnvaptError(105,`Time-string fallback "${n}" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`);return t}}static processArrayConverter(n,r,i=!1){if(n.trim()===``)return[];let a=n.split(r.delimiter).map(e=>String(e).trim());if(i){let t=a.findIndex(e=>e===``);if(t!==-1)throw new e.EnvaptError(207,`Array element at index ${t} is empty or whitespace only (strict mode).`)}let o=a.filter(Boolean);if(!o.length)return[];let s=r.of;if(typeof s==`function`)return o.map((t,n)=>{let r=s(t);if(r===void 0)throw new e.EnvaptError(206,`Custom element converter returned undefined for item "${t}" at index ${n}.`);return r});let c=t.getConverter(s);return o.map((t,n)=>{let r=c(t,void 0);if(r===void 0)throw new e.EnvaptError(206,`Element "${t}" at index ${n} could not be converted to ${s}.`);return r})}static getConverter(e){return{string:t.string,number:t.number,boolean:t.boolean,integer:t.integer,bigint:t.bigint,symbol:t.symbol,float:t.float,json:t.json,url:t.url,regexp:t.regexp,date:t.date,time:t.time}[e]}};exports.BuiltInConverters=l;
1
+ const e=require("../infra/Error.cjs"),t=1e3,n=60*t,r=60*n,i=24*r,a={ms:1,s:t,m:n,h:r,d:i,w:7*i},o=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)?$`,`u`),s=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$`,`u`);function c(e,t=!1){let n=e.match(t?s:o);if(!n)return;let[,r,i]=n;if(!r)return;let c=Number.parseFloat(r);if(!Number.isNaN(c))return c*a[i??`ms`]}var l=class t{static string(e,t){return String(e)}static number(e,t){let n=Number(e);return Number.isNaN(n)?t:n}static boolean(e,t){let n=e.toLowerCase().trim();return[`1`,`yes`,`true`,`on`].includes(n)?!0:[`0`,`no`,`false`,`off`].includes(n)?!1:t}static bigint(e,t){try{return BigInt(e)}catch{return t}}static symbol(e,t){try{return e?Symbol.for(e):t}catch{return t}}static integer(e,t){let n=e.trim();if(n===``)return t;let r=Number(n);return Number.isSafeInteger(r)?r:t}static float(e,t){let n=e.trim();if(n===``)return t;let r=Number(n);return Number.isNaN(r)?t:r}static json(e,t){try{return JSON.parse(e)}catch{return t}}static url(e,t){try{return new URL(e)}catch{return t}}static regexp(e,t){try{let t=e.match(new RegExp(String.raw`^\/(.+)\/([gimsuvy]*)$`));return t?new RegExp(t[1],t[2]):new RegExp(e)}catch{return t}}static date(e,t){if(new RegExp(String.raw`^\d+$`).test(e)){let n=new Date(parseInt(e,10));return Number.isNaN(n.getTime())?t:n}if(!new RegExp(String.raw`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$`,`u`).test(e))return t;let n=new Date(e);return Number.isNaN(n.getTime())?t:n}static time(t,n){let r=c(t);if(r!==void 0)return r;if(typeof n==`number`)return n;if(typeof n==`string`){let t=c(n,!0);if(t===void 0)throw new e.EnvaptError(105,`Time-string fallback "${n}" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`);return t}}static processArrayConverter(n,r,i=!1){if(n.trim()===``)return[];let a=n.split(r.delimiter).map(e=>String(e).trim());if(i){let t=a.findIndex(e=>e===``);if(t!==-1)throw new e.EnvaptError(207,`Array element at index ${t} is empty or whitespace only (strict mode).`)}let o=a.filter(Boolean);if(!o.length)return[];let s=r.of;if(typeof s==`function`)return o.map((t,n)=>{let r=s(t);if(r===void 0)throw new e.EnvaptError(206,`Custom element converter returned undefined for item "${t}" at index ${n}.`);return r});let c=t.getConverter(s);return o.map((t,n)=>{let r=c(t,void 0);if(r===void 0)throw new e.EnvaptError(206,`Element "${t}" at index ${n} could not be converted to ${s}.`);return r})}static getConverter(e){return{string:t.string,number:t.number,boolean:t.boolean,integer:t.integer,bigint:t.bigint,symbol:t.symbol,float:t.float,json:t.json,url:t.url,regexp:t.regexp,date:t.date,time:t.time}[e]}};exports.BuiltInConverters=l;
2
2
  //# sourceMappingURL=BuiltInConverters.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BuiltInConverters.cjs","names":["EnvaptError","converter"],"sources":["../../../src/converters/BuiltInConverters.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf, CustomElementConverter } from './Converters';\nimport type {\n BuiltInConverter,\n BuiltInConverterFunction,\n JsonValue,\n MapOfConverterFunctions,\n TimeFallback,\n TimeUnit\n} from '../types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst HOURS_PER_DAY = 24;\nconst DAYS_PER_WEEK = 7;\nconst MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;\nconst MS_PER_HOUR = MINUTES_PER_HOUR * MS_PER_MINUTE;\nconst MS_PER_DAY = HOURS_PER_DAY * MS_PER_HOUR;\nconst MS_PER_WEEK = DAYS_PER_WEEK * MS_PER_DAY;\n\nconst TIME_UNIT_MS: Record<TimeUnit, number> = {\n ms: 1,\n s: MS_PER_SECOND,\n m: MS_PER_MINUTE,\n h: MS_PER_HOUR,\n d: MS_PER_DAY,\n w: MS_PER_WEEK\n};\n\nconst TIME_LOOSE_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)?$`, 'u');\nconst TIME_STRICT_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)$`, 'u');\n\n/**\n * Parse a time string (e.g. `\"30s\"`, `\"1.5h\"`) into milliseconds.\n *\n * @param input - The string to parse.\n * @param strict - When `true`, require an explicit unit (used for fallback strings).\n * When `false` (default), treat a missing unit as `ms` (used for raw env values). Both allow decimals.\n * @returns The duration in milliseconds, or `undefined` if the input does not match the expected format.\n * @internal\n */\nfunction parseTimeString(input: string, strict = false): number | undefined {\n const match = input.match(strict ? TIME_STRICT_RE : TIME_LOOSE_RE);\n if (!match) return undefined;\n\n const [, numStr, capturedUnit] = match;\n if (!numStr) return undefined;\n\n const value = Number.parseFloat(numStr);\n if (Number.isNaN(value)) return undefined;\n\n const unit = (capturedUnit ?? 'ms') as TimeUnit;\n return value * TIME_UNIT_MS[unit];\n}\n\n/**\n * Built-in converter implementations\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class -- dispatch-table helper, the documented exception to the no-static-class rule\nexport class BuiltInConverters {\n static string(raw: string, _fallback?: string): string | undefined {\n return String(raw);\n }\n\n static number(raw: string, fallback?: number): number | undefined {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static boolean(raw: string, fallback?: boolean): boolean | undefined {\n const lower = raw.toLowerCase().trim();\n\n const truthyValues = ['1', 'yes', 'true', 'on'];\n const falsyValues = ['0', 'no', 'false', 'off'];\n\n if (truthyValues.includes(lower)) return true;\n if (falsyValues.includes(lower)) return false;\n return fallback;\n }\n\n static bigint(raw: string, fallback?: bigint): bigint | undefined {\n try {\n return BigInt(raw);\n } catch {\n return fallback;\n }\n }\n\n static symbol(raw: string, fallback?: symbol): symbol | undefined {\n try {\n return raw ? Symbol.for(raw) : fallback;\n } catch {\n return fallback;\n }\n }\n\n static integer(raw: string, fallback?: number): number | undefined {\n const parsed = Number.parseInt(raw, 10);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static float(raw: string, fallback?: number): number | undefined {\n const parsed = Number.parseFloat(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static json(raw: string, fallback?: JsonValue): JsonValue | undefined {\n try {\n return JSON.parse(raw) as JsonValue;\n } catch {\n return fallback;\n }\n }\n\n static url(raw: string, fallback?: URL): URL | undefined {\n try {\n return new URL(raw);\n } catch {\n return fallback;\n }\n }\n\n static regexp(raw: string, fallback?: RegExp): RegExp | undefined {\n try {\n // Handle flags if provided in format: /pattern/flags\n const match = raw.match(new RegExp(String.raw`^\\/(.+)\\/([gimsuvy]*)$`));\n if (match) return new RegExp(match[1] as string, match[2]);\n\n return new RegExp(raw);\n } catch {\n return fallback;\n }\n }\n\n static date(raw: string, fallback?: Date): Date | undefined {\n // Try parsing as timestamp first (if it's all digits)\n if (new RegExp(String.raw`^\\d+$`).test(raw)) {\n const timestamp = parseInt(raw, 10);\n const parsed = new Date(timestamp);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n // Only accept ISO 8601 date strings (strict format)\n const isoRegex = new RegExp(String.raw`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$`, 'u');\n if (!isoRegex.test(raw)) return fallback;\n\n const parsed = new Date(raw);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n static time(raw: string, fallback?: TimeFallback): number | undefined {\n const parsedRaw = parseTimeString(raw);\n if (parsedRaw !== undefined) return parsedRaw;\n\n // Raw didn't parse so apply fallback\n if (typeof fallback === 'number') return fallback;\n if (typeof fallback === 'string') {\n // A string fallback must name a unit; a unitless number is expressed as a number fallback, not a string.\n const parsedFallback = parseTimeString(fallback, true);\n if (parsedFallback === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.MalformedTimeFallback,\n `Time-string fallback \"${fallback}\" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`\n );\n }\n return parsedFallback;\n }\n return undefined;\n }\n\n /**\n * Process the raw env value for an {@link ArrayOf} configuration.\n *\n * Behaviour:\n * - Splits on `config.delimiter`, trims each item, and filters out empty entries.\n * - With a scalar element token: runs each item through the matching built-in converter.\n * If any element returns `undefined`, throws `ArrayElementConversionFailed` with positional info.\n * - With a custom function element: runs each item through the function. Propagates user\n * exceptions; treats `undefined` returns as conversion failures (same throw as scalar path).\n * - Returns `[]` when the raw value is empty/whitespace.\n * - When `strict` is true, throws `EmptyArrayElement` on any empty/whitespace item instead\n * of silently filtering it out.\n */\n static processArrayConverter(raw: string, config: ArrayOf, strict = false): unknown[] {\n if (raw.trim() === '') return [];\n\n const trimmedItems = raw.split(config.delimiter).map((item) => String(item).trim());\n\n if (strict) {\n const emptyIdx = trimmedItems.findIndex((item) => item === '');\n if (emptyIdx !== -1) {\n throw new EnvaptError(\n EnvaptErrorCodes.EmptyArrayElement,\n `Array element at index ${emptyIdx} is empty or whitespace only (strict mode).`\n );\n }\n }\n\n const items = trimmedItems.filter(Boolean);\n\n if (!items.length) return [];\n\n const elementOf = config.of;\n\n if (typeof elementOf === 'function') {\n return items.map((item, index) => {\n const converter = elementOf as CustomElementConverter;\n const result = converter(item);\n if (result === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Custom element converter returned undefined for item \"${item}\" at index ${index}.`\n );\n }\n return result;\n });\n }\n\n const converter = BuiltInConverters.getConverter(elementOf);\n return items.map((item, index) => {\n const converted = converter(item, undefined);\n if (converted === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Element \"${item}\" at index ${index} could not be converted to ${elementOf}.`\n );\n }\n return converted;\n });\n }\n\n /**\n * Get the converter function for a built-in converter type\n */\n static getConverter<TFallback extends BuiltInConverter>(type: TFallback): BuiltInConverterFunction {\n const converters: MapOfConverterFunctions = {\n string: BuiltInConverters.string,\n number: BuiltInConverters.number,\n boolean: BuiltInConverters.boolean,\n integer: BuiltInConverters.integer,\n bigint: BuiltInConverters.bigint,\n symbol: BuiltInConverters.symbol,\n float: BuiltInConverters.float,\n json: BuiltInConverters.json,\n url: BuiltInConverters.url,\n regexp: BuiltInConverters.regexp,\n date: BuiltInConverters.date,\n time: BuiltInConverters.time\n } as const;\n\n return converters[type];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BuiltInConverters.cjs","names":["EnvaptError","converter"],"sources":["../../../src/converters/BuiltInConverters.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf, CustomElementConverter } from './Converters';\nimport type {\n BuiltInConverter,\n BuiltInConverterFunction,\n JsonValue,\n MapOfConverterFunctions,\n TimeFallback,\n TimeUnit\n} from '../types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst HOURS_PER_DAY = 24;\nconst DAYS_PER_WEEK = 7;\nconst MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;\nconst MS_PER_HOUR = MINUTES_PER_HOUR * MS_PER_MINUTE;\nconst MS_PER_DAY = HOURS_PER_DAY * MS_PER_HOUR;\nconst MS_PER_WEEK = DAYS_PER_WEEK * MS_PER_DAY;\n\nconst TIME_UNIT_MS: Record<TimeUnit, number> = {\n ms: 1,\n s: MS_PER_SECOND,\n m: MS_PER_MINUTE,\n h: MS_PER_HOUR,\n d: MS_PER_DAY,\n w: MS_PER_WEEK\n};\n\nconst TIME_LOOSE_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)?$`, 'u');\nconst TIME_STRICT_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)$`, 'u');\n\n/**\n * Parse a time string (e.g. `\"30s\"`, `\"1.5h\"`) into milliseconds.\n *\n * @param input - The string to parse.\n * @param strict - When `true`, require an explicit unit (used for fallback strings).\n * When `false` (default), treat a missing unit as `ms` (used for raw env values). Both allow decimals.\n * @returns The duration in milliseconds, or `undefined` if the input does not match the expected format.\n * @internal\n */\nfunction parseTimeString(input: string, strict = false): number | undefined {\n const match = input.match(strict ? TIME_STRICT_RE : TIME_LOOSE_RE);\n if (!match) return undefined;\n\n const [, numStr, capturedUnit] = match;\n if (!numStr) return undefined;\n\n const value = Number.parseFloat(numStr);\n if (Number.isNaN(value)) return undefined;\n\n const unit = (capturedUnit ?? 'ms') as TimeUnit;\n return value * TIME_UNIT_MS[unit];\n}\n\n/**\n * Built-in converter implementations\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class -- dispatch-table helper, the documented exception to the no-static-class rule\nexport class BuiltInConverters {\n static string(raw: string, _fallback?: string): string | undefined {\n return String(raw);\n }\n\n static number(raw: string, fallback?: number): number | undefined {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static boolean(raw: string, fallback?: boolean): boolean | undefined {\n const lower = raw.toLowerCase().trim();\n\n const truthyValues = ['1', 'yes', 'true', 'on'];\n const falsyValues = ['0', 'no', 'false', 'off'];\n\n if (truthyValues.includes(lower)) return true;\n if (falsyValues.includes(lower)) return false;\n return fallback;\n }\n\n static bigint(raw: string, fallback?: bigint): bigint | undefined {\n try {\n return BigInt(raw);\n } catch {\n return fallback;\n }\n }\n\n static symbol(raw: string, fallback?: symbol): symbol | undefined {\n try {\n return raw ? Symbol.for(raw) : fallback;\n } catch {\n return fallback;\n }\n }\n\n static integer(raw: string, fallback?: number): number | undefined {\n const trimmed = raw.trim();\n if (trimmed === '') return fallback;\n const parsed = Number(trimmed);\n // isSafeInteger also guards the 2^53 boundary, past which an integer value silently loses precision.\n return Number.isSafeInteger(parsed) ? parsed : fallback;\n }\n\n static float(raw: string, fallback?: number): number | undefined {\n const trimmed = raw.trim();\n if (trimmed === '') return fallback;\n const parsed = Number(trimmed);\n // isNaN keeps Infinity valid, matching the number converter.\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static json(raw: string, fallback?: JsonValue): JsonValue | undefined {\n try {\n return JSON.parse(raw) as JsonValue;\n } catch {\n return fallback;\n }\n }\n\n static url(raw: string, fallback?: URL): URL | undefined {\n try {\n return new URL(raw);\n } catch {\n return fallback;\n }\n }\n\n static regexp(raw: string, fallback?: RegExp): RegExp | undefined {\n try {\n // Handle flags if provided in format: /pattern/flags\n const match = raw.match(new RegExp(String.raw`^\\/(.+)\\/([gimsuvy]*)$`));\n if (match) return new RegExp(match[1] as string, match[2]);\n\n return new RegExp(raw);\n } catch {\n return fallback;\n }\n }\n\n static date(raw: string, fallback?: Date): Date | undefined {\n // Try parsing as timestamp first (if it's all digits)\n if (new RegExp(String.raw`^\\d+$`).test(raw)) {\n const timestamp = parseInt(raw, 10);\n const parsed = new Date(timestamp);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n // Only accept ISO 8601 date strings (strict format)\n const isoRegex = new RegExp(String.raw`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$`, 'u');\n if (!isoRegex.test(raw)) return fallback;\n\n const parsed = new Date(raw);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n static time(raw: string, fallback?: TimeFallback): number | undefined {\n const parsedRaw = parseTimeString(raw);\n if (parsedRaw !== undefined) return parsedRaw;\n\n // Raw didn't parse so apply fallback\n if (typeof fallback === 'number') return fallback;\n if (typeof fallback === 'string') {\n // A string fallback must name a unit; a unitless number is expressed as a number fallback, not a string.\n const parsedFallback = parseTimeString(fallback, true);\n if (parsedFallback === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.MalformedTimeFallback,\n `Time-string fallback \"${fallback}\" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`\n );\n }\n return parsedFallback;\n }\n return undefined;\n }\n\n /**\n * Process the raw env value for an {@link ArrayOf} configuration.\n *\n * Behaviour:\n * - Splits on `config.delimiter`, trims each item, and filters out empty entries.\n * - With a scalar element token: runs each item through the matching built-in converter.\n * If any element returns `undefined`, throws `ArrayElementConversionFailed` with positional info.\n * - With a custom function element: runs each item through the function. Propagates user\n * exceptions; treats `undefined` returns as conversion failures (same throw as scalar path).\n * - Returns `[]` when the raw value is empty/whitespace.\n * - When `strict` is true, throws `EmptyArrayElement` on any empty/whitespace item instead\n * of silently filtering it out.\n */\n static processArrayConverter(raw: string, config: ArrayOf, strict = false): unknown[] {\n if (raw.trim() === '') return [];\n\n const trimmedItems = raw.split(config.delimiter).map((item) => String(item).trim());\n\n if (strict) {\n const emptyIdx = trimmedItems.findIndex((item) => item === '');\n if (emptyIdx !== -1) {\n throw new EnvaptError(\n EnvaptErrorCodes.EmptyArrayElement,\n `Array element at index ${emptyIdx} is empty or whitespace only (strict mode).`\n );\n }\n }\n\n const items = trimmedItems.filter(Boolean);\n\n if (!items.length) return [];\n\n const elementOf = config.of;\n\n if (typeof elementOf === 'function') {\n return items.map((item, index) => {\n const converter = elementOf as CustomElementConverter;\n const result = converter(item);\n if (result === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Custom element converter returned undefined for item \"${item}\" at index ${index}.`\n );\n }\n return result;\n });\n }\n\n const converter = BuiltInConverters.getConverter(elementOf);\n return items.map((item, index) => {\n const converted = converter(item, undefined);\n if (converted === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Element \"${item}\" at index ${index} could not be converted to ${elementOf}.`\n );\n }\n return converted;\n });\n }\n\n /**\n * Get the converter function for a built-in converter type\n */\n static getConverter<TFallback extends BuiltInConverter>(type: TFallback): BuiltInConverterFunction {\n const converters: MapOfConverterFunctions = {\n string: BuiltInConverters.string,\n number: BuiltInConverters.number,\n boolean: BuiltInConverters.boolean,\n integer: BuiltInConverters.integer,\n bigint: BuiltInConverters.bigint,\n symbol: BuiltInConverters.symbol,\n float: BuiltInConverters.float,\n json: BuiltInConverters.json,\n url: BuiltInConverters.url,\n regexp: BuiltInConverters.regexp,\n date: BuiltInConverters.date,\n time: BuiltInConverters.time\n } as const;\n\n return converters[type];\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{EnvaptError as e}from"../infra/Error.mjs";const t=1e3,n=60*t,r=60*n,i=24*r,a={ms:1,s:t,m:n,h:r,d:i,w:7*i},o=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)?$`,`u`),s=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$`,`u`);function c(e,t=!1){let n=e.match(t?s:o);if(!n)return;let[,r,i]=n;if(!r)return;let c=Number.parseFloat(r);if(!Number.isNaN(c))return c*a[i??`ms`]}var l=class t{static string(e,t){return String(e)}static number(e,t){let n=Number(e);return Number.isNaN(n)?t:n}static boolean(e,t){let n=e.toLowerCase().trim();return[`1`,`yes`,`true`,`on`].includes(n)?!0:[`0`,`no`,`false`,`off`].includes(n)?!1:t}static bigint(e,t){try{return BigInt(e)}catch{return t}}static symbol(e,t){try{return e?Symbol.for(e):t}catch{return t}}static integer(e,t){let n=Number.parseInt(e,10);return Number.isNaN(n)?t:n}static float(e,t){let n=Number.parseFloat(e);return Number.isNaN(n)?t:n}static json(e,t){try{return JSON.parse(e)}catch{return t}}static url(e,t){try{return new URL(e)}catch{return t}}static regexp(e,t){try{let t=e.match(new RegExp(String.raw`^\/(.+)\/([gimsuvy]*)$`));return t?new RegExp(t[1],t[2]):new RegExp(e)}catch{return t}}static date(e,t){if(new RegExp(String.raw`^\d+$`).test(e)){let n=new Date(parseInt(e,10));return Number.isNaN(n.getTime())?t:n}if(!new RegExp(String.raw`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$`,`u`).test(e))return t;let n=new Date(e);return Number.isNaN(n.getTime())?t:n}static time(t,n){let r=c(t);if(r!==void 0)return r;if(typeof n==`number`)return n;if(typeof n==`string`){let t=c(n,!0);if(t===void 0)throw new e(105,`Time-string fallback "${n}" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`);return t}}static processArrayConverter(n,r,i=!1){if(n.trim()===``)return[];let a=n.split(r.delimiter).map(e=>String(e).trim());if(i){let t=a.findIndex(e=>e===``);if(t!==-1)throw new e(207,`Array element at index ${t} is empty or whitespace only (strict mode).`)}let o=a.filter(Boolean);if(!o.length)return[];let s=r.of;if(typeof s==`function`)return o.map((t,n)=>{let r=s(t);if(r===void 0)throw new e(206,`Custom element converter returned undefined for item "${t}" at index ${n}.`);return r});let c=t.getConverter(s);return o.map((t,n)=>{let r=c(t,void 0);if(r===void 0)throw new e(206,`Element "${t}" at index ${n} could not be converted to ${s}.`);return r})}static getConverter(e){return{string:t.string,number:t.number,boolean:t.boolean,integer:t.integer,bigint:t.bigint,symbol:t.symbol,float:t.float,json:t.json,url:t.url,regexp:t.regexp,date:t.date,time:t.time}[e]}};export{l as BuiltInConverters};
1
+ import{EnvaptError as e}from"../infra/Error.mjs";const t=1e3,n=60*t,r=60*n,i=24*r,a={ms:1,s:t,m:n,h:r,d:i,w:7*i},o=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)?$`,`u`),s=new RegExp(String.raw`^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$`,`u`);function c(e,t=!1){let n=e.match(t?s:o);if(!n)return;let[,r,i]=n;if(!r)return;let c=Number.parseFloat(r);if(!Number.isNaN(c))return c*a[i??`ms`]}var l=class t{static string(e,t){return String(e)}static number(e,t){let n=Number(e);return Number.isNaN(n)?t:n}static boolean(e,t){let n=e.toLowerCase().trim();return[`1`,`yes`,`true`,`on`].includes(n)?!0:[`0`,`no`,`false`,`off`].includes(n)?!1:t}static bigint(e,t){try{return BigInt(e)}catch{return t}}static symbol(e,t){try{return e?Symbol.for(e):t}catch{return t}}static integer(e,t){let n=e.trim();if(n===``)return t;let r=Number(n);return Number.isSafeInteger(r)?r:t}static float(e,t){let n=e.trim();if(n===``)return t;let r=Number(n);return Number.isNaN(r)?t:r}static json(e,t){try{return JSON.parse(e)}catch{return t}}static url(e,t){try{return new URL(e)}catch{return t}}static regexp(e,t){try{let t=e.match(new RegExp(String.raw`^\/(.+)\/([gimsuvy]*)$`));return t?new RegExp(t[1],t[2]):new RegExp(e)}catch{return t}}static date(e,t){if(new RegExp(String.raw`^\d+$`).test(e)){let n=new Date(parseInt(e,10));return Number.isNaN(n.getTime())?t:n}if(!new RegExp(String.raw`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$`,`u`).test(e))return t;let n=new Date(e);return Number.isNaN(n.getTime())?t:n}static time(t,n){let r=c(t);if(r!==void 0)return r;if(typeof n==`number`)return n;if(typeof n==`string`){let t=c(n,!0);if(t===void 0)throw new e(105,`Time-string fallback "${n}" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`);return t}}static processArrayConverter(n,r,i=!1){if(n.trim()===``)return[];let a=n.split(r.delimiter).map(e=>String(e).trim());if(i){let t=a.findIndex(e=>e===``);if(t!==-1)throw new e(207,`Array element at index ${t} is empty or whitespace only (strict mode).`)}let o=a.filter(Boolean);if(!o.length)return[];let s=r.of;if(typeof s==`function`)return o.map((t,n)=>{let r=s(t);if(r===void 0)throw new e(206,`Custom element converter returned undefined for item "${t}" at index ${n}.`);return r});let c=t.getConverter(s);return o.map((t,n)=>{let r=c(t,void 0);if(r===void 0)throw new e(206,`Element "${t}" at index ${n} could not be converted to ${s}.`);return r})}static getConverter(e){return{string:t.string,number:t.number,boolean:t.boolean,integer:t.integer,bigint:t.bigint,symbol:t.symbol,float:t.float,json:t.json,url:t.url,regexp:t.regexp,date:t.date,time:t.time}[e]}};export{l as BuiltInConverters};
2
2
  //# sourceMappingURL=BuiltInConverters.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BuiltInConverters.mjs","names":["converter"],"sources":["../../../src/converters/BuiltInConverters.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf, CustomElementConverter } from './Converters';\nimport type {\n BuiltInConverter,\n BuiltInConverterFunction,\n JsonValue,\n MapOfConverterFunctions,\n TimeFallback,\n TimeUnit\n} from '../types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst HOURS_PER_DAY = 24;\nconst DAYS_PER_WEEK = 7;\nconst MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;\nconst MS_PER_HOUR = MINUTES_PER_HOUR * MS_PER_MINUTE;\nconst MS_PER_DAY = HOURS_PER_DAY * MS_PER_HOUR;\nconst MS_PER_WEEK = DAYS_PER_WEEK * MS_PER_DAY;\n\nconst TIME_UNIT_MS: Record<TimeUnit, number> = {\n ms: 1,\n s: MS_PER_SECOND,\n m: MS_PER_MINUTE,\n h: MS_PER_HOUR,\n d: MS_PER_DAY,\n w: MS_PER_WEEK\n};\n\nconst TIME_LOOSE_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)?$`, 'u');\nconst TIME_STRICT_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)$`, 'u');\n\n/**\n * Parse a time string (e.g. `\"30s\"`, `\"1.5h\"`) into milliseconds.\n *\n * @param input - The string to parse.\n * @param strict - When `true`, require an explicit unit (used for fallback strings).\n * When `false` (default), treat a missing unit as `ms` (used for raw env values). Both allow decimals.\n * @returns The duration in milliseconds, or `undefined` if the input does not match the expected format.\n * @internal\n */\nfunction parseTimeString(input: string, strict = false): number | undefined {\n const match = input.match(strict ? TIME_STRICT_RE : TIME_LOOSE_RE);\n if (!match) return undefined;\n\n const [, numStr, capturedUnit] = match;\n if (!numStr) return undefined;\n\n const value = Number.parseFloat(numStr);\n if (Number.isNaN(value)) return undefined;\n\n const unit = (capturedUnit ?? 'ms') as TimeUnit;\n return value * TIME_UNIT_MS[unit];\n}\n\n/**\n * Built-in converter implementations\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class -- dispatch-table helper, the documented exception to the no-static-class rule\nexport class BuiltInConverters {\n static string(raw: string, _fallback?: string): string | undefined {\n return String(raw);\n }\n\n static number(raw: string, fallback?: number): number | undefined {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static boolean(raw: string, fallback?: boolean): boolean | undefined {\n const lower = raw.toLowerCase().trim();\n\n const truthyValues = ['1', 'yes', 'true', 'on'];\n const falsyValues = ['0', 'no', 'false', 'off'];\n\n if (truthyValues.includes(lower)) return true;\n if (falsyValues.includes(lower)) return false;\n return fallback;\n }\n\n static bigint(raw: string, fallback?: bigint): bigint | undefined {\n try {\n return BigInt(raw);\n } catch {\n return fallback;\n }\n }\n\n static symbol(raw: string, fallback?: symbol): symbol | undefined {\n try {\n return raw ? Symbol.for(raw) : fallback;\n } catch {\n return fallback;\n }\n }\n\n static integer(raw: string, fallback?: number): number | undefined {\n const parsed = Number.parseInt(raw, 10);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static float(raw: string, fallback?: number): number | undefined {\n const parsed = Number.parseFloat(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static json(raw: string, fallback?: JsonValue): JsonValue | undefined {\n try {\n return JSON.parse(raw) as JsonValue;\n } catch {\n return fallback;\n }\n }\n\n static url(raw: string, fallback?: URL): URL | undefined {\n try {\n return new URL(raw);\n } catch {\n return fallback;\n }\n }\n\n static regexp(raw: string, fallback?: RegExp): RegExp | undefined {\n try {\n // Handle flags if provided in format: /pattern/flags\n const match = raw.match(new RegExp(String.raw`^\\/(.+)\\/([gimsuvy]*)$`));\n if (match) return new RegExp(match[1] as string, match[2]);\n\n return new RegExp(raw);\n } catch {\n return fallback;\n }\n }\n\n static date(raw: string, fallback?: Date): Date | undefined {\n // Try parsing as timestamp first (if it's all digits)\n if (new RegExp(String.raw`^\\d+$`).test(raw)) {\n const timestamp = parseInt(raw, 10);\n const parsed = new Date(timestamp);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n // Only accept ISO 8601 date strings (strict format)\n const isoRegex = new RegExp(String.raw`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$`, 'u');\n if (!isoRegex.test(raw)) return fallback;\n\n const parsed = new Date(raw);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n static time(raw: string, fallback?: TimeFallback): number | undefined {\n const parsedRaw = parseTimeString(raw);\n if (parsedRaw !== undefined) return parsedRaw;\n\n // Raw didn't parse so apply fallback\n if (typeof fallback === 'number') return fallback;\n if (typeof fallback === 'string') {\n // A string fallback must name a unit; a unitless number is expressed as a number fallback, not a string.\n const parsedFallback = parseTimeString(fallback, true);\n if (parsedFallback === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.MalformedTimeFallback,\n `Time-string fallback \"${fallback}\" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`\n );\n }\n return parsedFallback;\n }\n return undefined;\n }\n\n /**\n * Process the raw env value for an {@link ArrayOf} configuration.\n *\n * Behaviour:\n * - Splits on `config.delimiter`, trims each item, and filters out empty entries.\n * - With a scalar element token: runs each item through the matching built-in converter.\n * If any element returns `undefined`, throws `ArrayElementConversionFailed` with positional info.\n * - With a custom function element: runs each item through the function. Propagates user\n * exceptions; treats `undefined` returns as conversion failures (same throw as scalar path).\n * - Returns `[]` when the raw value is empty/whitespace.\n * - When `strict` is true, throws `EmptyArrayElement` on any empty/whitespace item instead\n * of silently filtering it out.\n */\n static processArrayConverter(raw: string, config: ArrayOf, strict = false): unknown[] {\n if (raw.trim() === '') return [];\n\n const trimmedItems = raw.split(config.delimiter).map((item) => String(item).trim());\n\n if (strict) {\n const emptyIdx = trimmedItems.findIndex((item) => item === '');\n if (emptyIdx !== -1) {\n throw new EnvaptError(\n EnvaptErrorCodes.EmptyArrayElement,\n `Array element at index ${emptyIdx} is empty or whitespace only (strict mode).`\n );\n }\n }\n\n const items = trimmedItems.filter(Boolean);\n\n if (!items.length) return [];\n\n const elementOf = config.of;\n\n if (typeof elementOf === 'function') {\n return items.map((item, index) => {\n const converter = elementOf as CustomElementConverter;\n const result = converter(item);\n if (result === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Custom element converter returned undefined for item \"${item}\" at index ${index}.`\n );\n }\n return result;\n });\n }\n\n const converter = BuiltInConverters.getConverter(elementOf);\n return items.map((item, index) => {\n const converted = converter(item, undefined);\n if (converted === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Element \"${item}\" at index ${index} could not be converted to ${elementOf}.`\n );\n }\n return converted;\n });\n }\n\n /**\n * Get the converter function for a built-in converter type\n */\n static getConverter<TFallback extends BuiltInConverter>(type: TFallback): BuiltInConverterFunction {\n const converters: MapOfConverterFunctions = {\n string: BuiltInConverters.string,\n number: BuiltInConverters.number,\n boolean: BuiltInConverters.boolean,\n integer: BuiltInConverters.integer,\n bigint: BuiltInConverters.bigint,\n symbol: BuiltInConverters.symbol,\n float: BuiltInConverters.float,\n json: BuiltInConverters.json,\n url: BuiltInConverters.url,\n regexp: BuiltInConverters.regexp,\n date: BuiltInConverters.date,\n time: BuiltInConverters.time\n } as const;\n\n return converters[type];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BuiltInConverters.mjs","names":["converter"],"sources":["../../../src/converters/BuiltInConverters.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf, CustomElementConverter } from './Converters';\nimport type {\n BuiltInConverter,\n BuiltInConverterFunction,\n JsonValue,\n MapOfConverterFunctions,\n TimeFallback,\n TimeUnit\n} from '../types';\n\nconst MS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst HOURS_PER_DAY = 24;\nconst DAYS_PER_WEEK = 7;\nconst MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;\nconst MS_PER_HOUR = MINUTES_PER_HOUR * MS_PER_MINUTE;\nconst MS_PER_DAY = HOURS_PER_DAY * MS_PER_HOUR;\nconst MS_PER_WEEK = DAYS_PER_WEEK * MS_PER_DAY;\n\nconst TIME_UNIT_MS: Record<TimeUnit, number> = {\n ms: 1,\n s: MS_PER_SECOND,\n m: MS_PER_MINUTE,\n h: MS_PER_HOUR,\n d: MS_PER_DAY,\n w: MS_PER_WEEK\n};\n\nconst TIME_LOOSE_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)?$`, 'u');\nconst TIME_STRICT_RE = new RegExp(String.raw`^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)$`, 'u');\n\n/**\n * Parse a time string (e.g. `\"30s\"`, `\"1.5h\"`) into milliseconds.\n *\n * @param input - The string to parse.\n * @param strict - When `true`, require an explicit unit (used for fallback strings).\n * When `false` (default), treat a missing unit as `ms` (used for raw env values). Both allow decimals.\n * @returns The duration in milliseconds, or `undefined` if the input does not match the expected format.\n * @internal\n */\nfunction parseTimeString(input: string, strict = false): number | undefined {\n const match = input.match(strict ? TIME_STRICT_RE : TIME_LOOSE_RE);\n if (!match) return undefined;\n\n const [, numStr, capturedUnit] = match;\n if (!numStr) return undefined;\n\n const value = Number.parseFloat(numStr);\n if (Number.isNaN(value)) return undefined;\n\n const unit = (capturedUnit ?? 'ms') as TimeUnit;\n return value * TIME_UNIT_MS[unit];\n}\n\n/**\n * Built-in converter implementations\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class -- dispatch-table helper, the documented exception to the no-static-class rule\nexport class BuiltInConverters {\n static string(raw: string, _fallback?: string): string | undefined {\n return String(raw);\n }\n\n static number(raw: string, fallback?: number): number | undefined {\n const parsed = Number(raw);\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static boolean(raw: string, fallback?: boolean): boolean | undefined {\n const lower = raw.toLowerCase().trim();\n\n const truthyValues = ['1', 'yes', 'true', 'on'];\n const falsyValues = ['0', 'no', 'false', 'off'];\n\n if (truthyValues.includes(lower)) return true;\n if (falsyValues.includes(lower)) return false;\n return fallback;\n }\n\n static bigint(raw: string, fallback?: bigint): bigint | undefined {\n try {\n return BigInt(raw);\n } catch {\n return fallback;\n }\n }\n\n static symbol(raw: string, fallback?: symbol): symbol | undefined {\n try {\n return raw ? Symbol.for(raw) : fallback;\n } catch {\n return fallback;\n }\n }\n\n static integer(raw: string, fallback?: number): number | undefined {\n const trimmed = raw.trim();\n if (trimmed === '') return fallback;\n const parsed = Number(trimmed);\n // isSafeInteger also guards the 2^53 boundary, past which an integer value silently loses precision.\n return Number.isSafeInteger(parsed) ? parsed : fallback;\n }\n\n static float(raw: string, fallback?: number): number | undefined {\n const trimmed = raw.trim();\n if (trimmed === '') return fallback;\n const parsed = Number(trimmed);\n // isNaN keeps Infinity valid, matching the number converter.\n return Number.isNaN(parsed) ? fallback : parsed;\n }\n\n static json(raw: string, fallback?: JsonValue): JsonValue | undefined {\n try {\n return JSON.parse(raw) as JsonValue;\n } catch {\n return fallback;\n }\n }\n\n static url(raw: string, fallback?: URL): URL | undefined {\n try {\n return new URL(raw);\n } catch {\n return fallback;\n }\n }\n\n static regexp(raw: string, fallback?: RegExp): RegExp | undefined {\n try {\n // Handle flags if provided in format: /pattern/flags\n const match = raw.match(new RegExp(String.raw`^\\/(.+)\\/([gimsuvy]*)$`));\n if (match) return new RegExp(match[1] as string, match[2]);\n\n return new RegExp(raw);\n } catch {\n return fallback;\n }\n }\n\n static date(raw: string, fallback?: Date): Date | undefined {\n // Try parsing as timestamp first (if it's all digits)\n if (new RegExp(String.raw`^\\d+$`).test(raw)) {\n const timestamp = parseInt(raw, 10);\n const parsed = new Date(timestamp);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n // Only accept ISO 8601 date strings (strict format)\n const isoRegex = new RegExp(String.raw`^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$`, 'u');\n if (!isoRegex.test(raw)) return fallback;\n\n const parsed = new Date(raw);\n return Number.isNaN(parsed.getTime()) ? fallback : parsed;\n }\n\n static time(raw: string, fallback?: TimeFallback): number | undefined {\n const parsedRaw = parseTimeString(raw);\n if (parsedRaw !== undefined) return parsedRaw;\n\n // Raw didn't parse so apply fallback\n if (typeof fallback === 'number') return fallback;\n if (typeof fallback === 'string') {\n // A string fallback must name a unit; a unitless number is expressed as a number fallback, not a string.\n const parsedFallback = parseTimeString(fallback, true);\n if (parsedFallback === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.MalformedTimeFallback,\n `Time-string fallback \"${fallback}\" is not a valid format. Expected <number><unit> where unit is one of: ms, s, m, h, d, w.`\n );\n }\n return parsedFallback;\n }\n return undefined;\n }\n\n /**\n * Process the raw env value for an {@link ArrayOf} configuration.\n *\n * Behaviour:\n * - Splits on `config.delimiter`, trims each item, and filters out empty entries.\n * - With a scalar element token: runs each item through the matching built-in converter.\n * If any element returns `undefined`, throws `ArrayElementConversionFailed` with positional info.\n * - With a custom function element: runs each item through the function. Propagates user\n * exceptions; treats `undefined` returns as conversion failures (same throw as scalar path).\n * - Returns `[]` when the raw value is empty/whitespace.\n * - When `strict` is true, throws `EmptyArrayElement` on any empty/whitespace item instead\n * of silently filtering it out.\n */\n static processArrayConverter(raw: string, config: ArrayOf, strict = false): unknown[] {\n if (raw.trim() === '') return [];\n\n const trimmedItems = raw.split(config.delimiter).map((item) => String(item).trim());\n\n if (strict) {\n const emptyIdx = trimmedItems.findIndex((item) => item === '');\n if (emptyIdx !== -1) {\n throw new EnvaptError(\n EnvaptErrorCodes.EmptyArrayElement,\n `Array element at index ${emptyIdx} is empty or whitespace only (strict mode).`\n );\n }\n }\n\n const items = trimmedItems.filter(Boolean);\n\n if (!items.length) return [];\n\n const elementOf = config.of;\n\n if (typeof elementOf === 'function') {\n return items.map((item, index) => {\n const converter = elementOf as CustomElementConverter;\n const result = converter(item);\n if (result === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Custom element converter returned undefined for item \"${item}\" at index ${index}.`\n );\n }\n return result;\n });\n }\n\n const converter = BuiltInConverters.getConverter(elementOf);\n return items.map((item, index) => {\n const converted = converter(item, undefined);\n if (converted === undefined) {\n throw new EnvaptError(\n EnvaptErrorCodes.ArrayElementConversionFailed,\n `Element \"${item}\" at index ${index} could not be converted to ${elementOf}.`\n );\n }\n return converted;\n });\n }\n\n /**\n * Get the converter function for a built-in converter type\n */\n static getConverter<TFallback extends BuiltInConverter>(type: TFallback): BuiltInConverterFunction {\n const converters: MapOfConverterFunctions = {\n string: BuiltInConverters.string,\n number: BuiltInConverters.number,\n boolean: BuiltInConverters.boolean,\n integer: BuiltInConverters.integer,\n bigint: BuiltInConverters.bigint,\n symbol: BuiltInConverters.symbol,\n float: BuiltInConverters.float,\n json: BuiltInConverters.json,\n url: BuiltInConverters.url,\n regexp: BuiltInConverters.regexp,\n date: BuiltInConverters.date,\n time: BuiltInConverters.time\n } as const;\n\n return converters[type];\n }\n}\n"],"mappings":"iDAcA,MAAM,EAAgB,IAKhB,EAAgB,GAAqB,EACrC,EAAc,GAAmB,EACjC,EAAa,GAAgB,EAG7B,EAAyC,CAC3C,GAAI,EACJ,EAAG,EACH,EAAG,EACH,EAAG,EACH,EAAG,EACH,EARgB,EAAgB,CASpC,EAEM,EAAgB,IAAI,OAAO,OAAO,GAAG,mCAAoC,GAAG,EAC5E,EAAiB,IAAI,OAAO,OAAO,GAAG,kCAAmC,GAAG,EAWlF,SAAS,EAAgB,EAAe,EAAS,GAA2B,CACxE,IAAM,EAAQ,EAAM,MAAM,EAAS,EAAiB,CAAa,EACjE,GAAI,CAAC,EAAO,OAEZ,GAAM,EAAG,EAAQ,GAAgB,EACjC,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAQ,OAAO,WAAW,CAAM,EAClC,WAAO,MAAM,CAAK,EAGtB,OAAO,EAAQ,EADD,GAAgB,KAElC,CAOA,IAAa,EAAb,MAAa,CAAkB,CAC3B,OAAO,OAAO,EAAa,EAAwC,CAC/D,OAAO,OAAO,CAAG,CACrB,CAEA,OAAO,OAAO,EAAa,EAAuC,CAC9D,IAAM,EAAS,OAAO,CAAG,EACzB,OAAO,OAAO,MAAM,CAAM,EAAI,EAAW,CAC7C,CAEA,OAAO,QAAQ,EAAa,EAAyC,CACjE,IAAM,EAAQ,EAAI,YAAY,CAAC,CAAC,KAAK,EAOrC,MAFI,CAHkB,IAAK,MAAO,OAAQ,IAGtC,CAAA,CAAa,SAAS,CAAK,EAAU,GACrC,CAHiB,IAAK,KAAM,QAAS,KAGrC,CAAA,CAAY,SAAS,CAAK,EAAU,GACjC,CACX,CAEA,OAAO,OAAO,EAAa,EAAuC,CAC9D,GAAI,CACA,OAAO,OAAO,CAAG,CACrB,MAAQ,CACJ,OAAO,CACX,CACJ,CAEA,OAAO,OAAO,EAAa,EAAuC,CAC9D,GAAI,CACA,OAAO,EAAM,OAAO,IAAI,CAAG,EAAI,CACnC,MAAQ,CACJ,OAAO,CACX,CACJ,CAEA,OAAO,QAAQ,EAAa,EAAuC,CAC/D,IAAM,EAAU,EAAI,KAAK,EACzB,GAAI,IAAY,GAAI,OAAO,EAC3B,IAAM,EAAS,OAAO,CAAO,EAE7B,OAAO,OAAO,cAAc,CAAM,EAAI,EAAS,CACnD,CAEA,OAAO,MAAM,EAAa,EAAuC,CAC7D,IAAM,EAAU,EAAI,KAAK,EACzB,GAAI,IAAY,GAAI,OAAO,EAC3B,IAAM,EAAS,OAAO,CAAO,EAE7B,OAAO,OAAO,MAAM,CAAM,EAAI,EAAW,CAC7C,CAEA,OAAO,KAAK,EAAa,EAA6C,CAClE,GAAI,CACA,OAAO,KAAK,MAAM,CAAG,CACzB,MAAQ,CACJ,OAAO,CACX,CACJ,CAEA,OAAO,IAAI,EAAa,EAAiC,CACrD,GAAI,CACA,OAAO,IAAI,IAAI,CAAG,CACtB,MAAQ,CACJ,OAAO,CACX,CACJ,CAEA,OAAO,OAAO,EAAa,EAAuC,CAC9D,GAAI,CAEA,IAAM,EAAQ,EAAI,MAAM,IAAI,OAAO,OAAO,GAAG,wBAAwB,CAAC,EAGtE,OAFI,EAAc,IAAI,OAAO,EAAM,GAAc,EAAM,EAAE,EAElD,IAAI,OAAO,CAAG,CACzB,MAAQ,CACJ,OAAO,CACX,CACJ,CAEA,OAAO,KAAK,EAAa,EAAmC,CAExD,GAAI,IAAI,OAAO,OAAO,GAAG,OAAO,CAAC,CAAC,KAAK,CAAG,EAAG,CAEzC,IAAM,EAAS,IAAI,KADD,SAAS,EAAK,EACA,CAAC,EACjC,OAAO,OAAO,MAAM,EAAO,QAAQ,CAAC,EAAI,EAAW,CACvD,CAIA,GAAI,CAAC,IADgB,OAAO,OAAO,GAAG,mDAAoD,GAC9E,CAAC,CAAC,KAAK,CAAG,EAAG,OAAO,EAEhC,IAAM,EAAS,IAAI,KAAK,CAAG,EAC3B,OAAO,OAAO,MAAM,EAAO,QAAQ,CAAC,EAAI,EAAW,CACvD,CAEA,OAAO,KAAK,EAAa,EAA6C,CAClE,IAAM,EAAY,EAAgB,CAAG,EACrC,GAAI,IAAc,IAAA,GAAW,OAAO,EAGpC,GAAI,OAAO,GAAa,SAAU,OAAO,EACzC,GAAI,OAAO,GAAa,SAAU,CAE9B,IAAM,EAAiB,EAAgB,EAAU,EAAI,EACrD,GAAI,IAAmB,IAAA,GACnB,MAAM,IAAI,EAAA,IAEN,yBAAyB,EAAS,0FACtC,EAEJ,OAAO,CACX,CAEJ,CAeA,OAAO,sBAAsB,EAAa,EAAiB,EAAS,GAAkB,CAClF,GAAI,EAAI,KAAK,IAAM,GAAI,MAAO,CAAC,EAE/B,IAAM,EAAe,EAAI,MAAM,EAAO,SAAS,CAAC,CAAC,IAAK,GAAS,OAAO,CAAI,CAAC,CAAC,KAAK,CAAC,EAElF,GAAI,EAAQ,CACR,IAAM,EAAW,EAAa,UAAW,GAAS,IAAS,EAAE,EAC7D,GAAI,IAAa,GACb,MAAM,IAAI,EAAA,IAEN,0BAA0B,EAAS,4CACvC,CAER,CAEA,IAAM,EAAQ,EAAa,OAAO,OAAO,EAEzC,GAAI,CAAC,EAAM,OAAQ,MAAO,CAAC,EAE3B,IAAM,EAAY,EAAO,GAEzB,GAAI,OAAO,GAAc,WACrB,OAAO,EAAM,KAAK,EAAM,IAAU,CAE9B,IAAM,EAASA,EAAU,CAAI,EAC7B,GAAI,IAAW,IAAA,GACX,MAAM,IAAI,EAAA,IAEN,yDAAyD,EAAK,aAAa,EAAM,EACrF,EAEJ,OAAO,CACX,CAAC,EAGL,IAAM,EAAY,EAAkB,aAAa,CAAS,EAC1D,OAAO,EAAM,KAAK,EAAM,IAAU,CAC9B,IAAM,EAAY,EAAU,EAAM,IAAA,EAAS,EAC3C,GAAI,IAAc,IAAA,GACd,MAAM,IAAI,EAAA,IAEN,YAAY,EAAK,aAAa,EAAM,6BAA6B,EAAU,EAC/E,EAEJ,OAAO,CACX,CAAC,CACL,CAKA,OAAO,aAAiD,EAA2C,CAgB/F,MAAO,CAdH,OAAQ,EAAkB,OAC1B,OAAQ,EAAkB,OAC1B,QAAS,EAAkB,QAC3B,QAAS,EAAkB,QAC3B,OAAQ,EAAkB,OAC1B,OAAQ,EAAkB,OAC1B,MAAO,EAAkB,MACzB,KAAM,EAAkB,KACxB,IAAK,EAAkB,IACvB,OAAQ,EAAkB,OAC1B,KAAM,EAAkB,KACxB,KAAM,EAAkB,IAGZ,EAAE,EACtB,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"Converters.cjs","names":[],"sources":["../../../src/converters/Converters.ts"],"sourcesContent":["const SCALAR = {\n String: 'string',\n Number: 'number',\n Boolean: 'boolean',\n Bigint: 'bigint',\n Symbol: 'symbol',\n Integer: 'integer',\n Float: 'float',\n Json: 'json',\n Url: 'url',\n Regexp: 'regexp',\n Date: 'date',\n Time: 'time'\n} as const;\n\n/**\n * String tokens for every built-in scalar converter.\n * @public\n */\nexport type ConverterToken = (typeof SCALAR)[keyof typeof SCALAR];\n\n/**\n * Custom element converter for use inside {@link Converters.array}. Receives the trimmed,\n * non-empty raw string for one array slot and returns the parsed value.\n * @public\n */\nexport type CustomElementConverter<TReturn = unknown> = (raw: string) => TReturn;\n\n/**\n * Valid element converters for {@link Converters.array}: any scalar token except\n * `json` and `regexp` (those don't compose as array elements), or a custom function.\n * @public\n */\nexport type ArrayElement = Exclude<ConverterToken, 'json' | 'regexp'> | CustomElementConverter;\n\n/**\n * Phantom-branded token produced by {@link Converters.array}. The `T` type parameter carries\n * the element converter through any variable indirection so inference survives. The\n * `__envaptKind` discriminant is present at runtime for dispatch.\n * @public\n */\nexport interface ArrayOf<TElement extends ArrayElement = ArrayElement> {\n /** Runtime discriminant marking this token as an array converter. Don't use directly. */\n readonly __envaptKind: 'array';\n /** The element converter applied to each split slot. */\n readonly of: TElement;\n /** The string the raw value is split on. */\n readonly delimiter: string;\n}\n\n/**\n * Runtime type guard for tokens produced by {@link Converters.array}.\n * @internal\n */\nexport function isArrayOf(value: unknown): value is ArrayOf {\n return typeof value === 'object' && value !== null && '__envaptKind' in value && value.__envaptKind === 'array';\n}\n\ntype ArrayScalarElement = Exclude<ConverterToken, 'json' | 'regexp'>;\n\n// Overloads. The function-element overload must come first so it wins inference when `of`\n// is a function, otherwise TS picks the scalar branch and `raw` defaults to `any`.\nfunction buildArrayConverter<TReturn>(opts: {\n of: CustomElementConverter<TReturn>;\n delimiter?: string;\n}): ArrayOf<CustomElementConverter<TReturn>>;\nfunction buildArrayConverter<TToken extends ArrayScalarElement>(opts: {\n of: TToken;\n delimiter?: string;\n}): ArrayOf<TToken>;\nfunction buildArrayConverter(opts?: { delimiter?: string }): ArrayOf<'string'>;\nfunction buildArrayConverter(opts?: { of?: ArrayElement; delimiter?: string }): ArrayOf<ArrayElement> {\n return {\n __envaptKind: 'array',\n of: opts?.of ?? SCALAR.String,\n delimiter: opts?.delimiter ?? ','\n };\n}\n\n/**\n * Built-in converters for environment variables. Use the scalar tokens (e.g. `Converters.Number`)\n * for primitive types and the {@link Converters.array} builder for delimited lists.\n *\n * @example\n * ```ts\n * \\@Envapt('PORT', { converter: Converters.Number, fallback: 3000 })\n * static readonly port: number;\n *\n * \\@Envapt('TAGS', { converter: Converters.array({ of: Converters.String, delimiter: ' ' }) })\n * static readonly tags: string[];\n * ```\n *\n * @public\n */\nexport const Converters = {\n ...SCALAR,\n array: buildArrayConverter\n} as const;\n"],"mappings":"AAAA,MAAM,EAAS,CACX,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,MAAO,QACP,KAAM,OACN,IAAK,MACL,OAAQ,SACR,KAAM,OACN,KAAM,MACV,EAyCA,SAAgB,EAAU,EAAkC,CACxD,OAAO,OAAO,GAAU,YAAY,GAAkB,iBAAkB,GAAS,EAAM,eAAiB,OAC5G,CAeA,SAAS,EAAoB,EAAyE,CAClG,MAAO,CACH,aAAc,QACd,GAAI,GAAM,IAAM,EAAO,OACvB,UAAW,GAAM,WAAa,GAClC,CACJ,CAiBA,MAAa,EAAa,CACtB,GAAG,EACH,MAAO,CACX"}
1
+ {"version":3,"file":"Converters.cjs","names":[],"sources":["../../../src/converters/Converters.ts"],"sourcesContent":["const SCALAR = {\n String: 'string',\n Number: 'number',\n Boolean: 'boolean',\n Bigint: 'bigint',\n Symbol: 'symbol',\n Integer: 'integer',\n Float: 'float',\n Json: 'json',\n Url: 'url',\n Regexp: 'regexp',\n Date: 'date',\n Time: 'time'\n} as const;\n\n/**\n * String tokens for every built-in scalar converter.\n * @public\n */\nexport type ConverterToken = (typeof SCALAR)[keyof typeof SCALAR];\n\n/**\n * Custom element converter for use inside {@link Converters.array}. Receives the trimmed,\n * non-empty raw string for one array slot and returns the parsed value.\n * @public\n */\nexport type CustomElementConverter<TReturn = unknown> = (raw: string) => TReturn;\n\n// array element converters, any scalar token except json/regexp (those don't compose) or a custom function\nexport type ArrayElement = Exclude<ConverterToken, 'json' | 'regexp'> | CustomElementConverter;\n\n// phantom-branded token from Converters.array. TElement carries the element converter through variable\n// indirection so inference survives. __envaptKind is the runtime dispatch discriminant.\nexport interface ArrayOf<TElement extends ArrayElement = ArrayElement> {\n readonly __envaptKind: 'array';\n readonly of: TElement;\n readonly delimiter: string;\n}\n\n/**\n * Runtime type guard for tokens produced by {@link Converters.array}.\n * @internal\n */\nexport function isArrayOf(value: unknown): value is ArrayOf {\n return typeof value === 'object' && value !== null && '__envaptKind' in value && value.__envaptKind === 'array';\n}\n\ntype ArrayScalarElement = Exclude<ConverterToken, 'json' | 'regexp'>;\n\n// Overloads. The function-element overload must come first so it wins inference when `of`\n// is a function, otherwise TS picks the scalar branch and `raw` defaults to `any`.\nfunction buildArrayConverter<TReturn>(opts: {\n of: CustomElementConverter<TReturn>;\n delimiter?: string;\n}): ArrayOf<CustomElementConverter<TReturn>>;\nfunction buildArrayConverter<TToken extends ArrayScalarElement>(opts: {\n of: TToken;\n delimiter?: string;\n}): ArrayOf<TToken>;\nfunction buildArrayConverter(opts?: { delimiter?: string }): ArrayOf<'string'>;\nfunction buildArrayConverter(opts?: { of?: ArrayElement; delimiter?: string }): ArrayOf<ArrayElement> {\n return {\n __envaptKind: 'array',\n of: opts?.of ?? SCALAR.String,\n delimiter: opts?.delimiter ?? ','\n };\n}\n\n/**\n * Built-in converters for environment variables. Use the scalar tokens (e.g. `Converters.Number`)\n * for primitive types and the {@link Converters.array} builder for delimited lists.\n *\n * @example\n * ```ts\n * \\@Envapt('PORT', { converter: Converters.Number, fallback: 3000 })\n * static readonly port: number;\n *\n * \\@Envapt('TAGS', { converter: Converters.array({ of: Converters.String, delimiter: ' ' }) })\n * static readonly tags: string[];\n * ```\n *\n * @public\n */\nexport const Converters = {\n ...SCALAR,\n array: buildArrayConverter\n} as const;\n"],"mappings":"AAAA,MAAM,EAAS,CACX,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,MAAO,QACP,KAAM,OACN,IAAK,MACL,OAAQ,SACR,KAAM,OACN,KAAM,MACV,EA8BA,SAAgB,EAAU,EAAkC,CACxD,OAAO,OAAO,GAAU,YAAY,GAAkB,iBAAkB,GAAS,EAAM,eAAiB,OAC5G,CAeA,SAAS,EAAoB,EAAyE,CAClG,MAAO,CACH,aAAc,QACd,GAAI,GAAM,IAAM,EAAO,OACvB,UAAW,GAAM,WAAa,GAClC,CACJ,CAiBA,MAAa,EAAa,CACtB,GAAG,EACH,MAAO,CACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"Converters.mjs","names":[],"sources":["../../../src/converters/Converters.ts"],"sourcesContent":["const SCALAR = {\n String: 'string',\n Number: 'number',\n Boolean: 'boolean',\n Bigint: 'bigint',\n Symbol: 'symbol',\n Integer: 'integer',\n Float: 'float',\n Json: 'json',\n Url: 'url',\n Regexp: 'regexp',\n Date: 'date',\n Time: 'time'\n} as const;\n\n/**\n * String tokens for every built-in scalar converter.\n * @public\n */\nexport type ConverterToken = (typeof SCALAR)[keyof typeof SCALAR];\n\n/**\n * Custom element converter for use inside {@link Converters.array}. Receives the trimmed,\n * non-empty raw string for one array slot and returns the parsed value.\n * @public\n */\nexport type CustomElementConverter<TReturn = unknown> = (raw: string) => TReturn;\n\n/**\n * Valid element converters for {@link Converters.array}: any scalar token except\n * `json` and `regexp` (those don't compose as array elements), or a custom function.\n * @public\n */\nexport type ArrayElement = Exclude<ConverterToken, 'json' | 'regexp'> | CustomElementConverter;\n\n/**\n * Phantom-branded token produced by {@link Converters.array}. The `T` type parameter carries\n * the element converter through any variable indirection so inference survives. The\n * `__envaptKind` discriminant is present at runtime for dispatch.\n * @public\n */\nexport interface ArrayOf<TElement extends ArrayElement = ArrayElement> {\n /** Runtime discriminant marking this token as an array converter. Don't use directly. */\n readonly __envaptKind: 'array';\n /** The element converter applied to each split slot. */\n readonly of: TElement;\n /** The string the raw value is split on. */\n readonly delimiter: string;\n}\n\n/**\n * Runtime type guard for tokens produced by {@link Converters.array}.\n * @internal\n */\nexport function isArrayOf(value: unknown): value is ArrayOf {\n return typeof value === 'object' && value !== null && '__envaptKind' in value && value.__envaptKind === 'array';\n}\n\ntype ArrayScalarElement = Exclude<ConverterToken, 'json' | 'regexp'>;\n\n// Overloads. The function-element overload must come first so it wins inference when `of`\n// is a function, otherwise TS picks the scalar branch and `raw` defaults to `any`.\nfunction buildArrayConverter<TReturn>(opts: {\n of: CustomElementConverter<TReturn>;\n delimiter?: string;\n}): ArrayOf<CustomElementConverter<TReturn>>;\nfunction buildArrayConverter<TToken extends ArrayScalarElement>(opts: {\n of: TToken;\n delimiter?: string;\n}): ArrayOf<TToken>;\nfunction buildArrayConverter(opts?: { delimiter?: string }): ArrayOf<'string'>;\nfunction buildArrayConverter(opts?: { of?: ArrayElement; delimiter?: string }): ArrayOf<ArrayElement> {\n return {\n __envaptKind: 'array',\n of: opts?.of ?? SCALAR.String,\n delimiter: opts?.delimiter ?? ','\n };\n}\n\n/**\n * Built-in converters for environment variables. Use the scalar tokens (e.g. `Converters.Number`)\n * for primitive types and the {@link Converters.array} builder for delimited lists.\n *\n * @example\n * ```ts\n * \\@Envapt('PORT', { converter: Converters.Number, fallback: 3000 })\n * static readonly port: number;\n *\n * \\@Envapt('TAGS', { converter: Converters.array({ of: Converters.String, delimiter: ' ' }) })\n * static readonly tags: string[];\n * ```\n *\n * @public\n */\nexport const Converters = {\n ...SCALAR,\n array: buildArrayConverter\n} as const;\n"],"mappings":"AAAA,MAAM,EAAS,CACX,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,MAAO,QACP,KAAM,OACN,IAAK,MACL,OAAQ,SACR,KAAM,OACN,KAAM,MACV,EAyCA,SAAgB,EAAU,EAAkC,CACxD,OAAO,OAAO,GAAU,YAAY,GAAkB,iBAAkB,GAAS,EAAM,eAAiB,OAC5G,CAeA,SAAS,EAAoB,EAAyE,CAClG,MAAO,CACH,aAAc,QACd,GAAI,GAAM,IAAM,EAAO,OACvB,UAAW,GAAM,WAAa,GAClC,CACJ,CAiBA,MAAa,EAAa,CACtB,GAAG,EACH,MAAO,CACX"}
1
+ {"version":3,"file":"Converters.mjs","names":[],"sources":["../../../src/converters/Converters.ts"],"sourcesContent":["const SCALAR = {\n String: 'string',\n Number: 'number',\n Boolean: 'boolean',\n Bigint: 'bigint',\n Symbol: 'symbol',\n Integer: 'integer',\n Float: 'float',\n Json: 'json',\n Url: 'url',\n Regexp: 'regexp',\n Date: 'date',\n Time: 'time'\n} as const;\n\n/**\n * String tokens for every built-in scalar converter.\n * @public\n */\nexport type ConverterToken = (typeof SCALAR)[keyof typeof SCALAR];\n\n/**\n * Custom element converter for use inside {@link Converters.array}. Receives the trimmed,\n * non-empty raw string for one array slot and returns the parsed value.\n * @public\n */\nexport type CustomElementConverter<TReturn = unknown> = (raw: string) => TReturn;\n\n// array element converters, any scalar token except json/regexp (those don't compose) or a custom function\nexport type ArrayElement = Exclude<ConverterToken, 'json' | 'regexp'> | CustomElementConverter;\n\n// phantom-branded token from Converters.array. TElement carries the element converter through variable\n// indirection so inference survives. __envaptKind is the runtime dispatch discriminant.\nexport interface ArrayOf<TElement extends ArrayElement = ArrayElement> {\n readonly __envaptKind: 'array';\n readonly of: TElement;\n readonly delimiter: string;\n}\n\n/**\n * Runtime type guard for tokens produced by {@link Converters.array}.\n * @internal\n */\nexport function isArrayOf(value: unknown): value is ArrayOf {\n return typeof value === 'object' && value !== null && '__envaptKind' in value && value.__envaptKind === 'array';\n}\n\ntype ArrayScalarElement = Exclude<ConverterToken, 'json' | 'regexp'>;\n\n// Overloads. The function-element overload must come first so it wins inference when `of`\n// is a function, otherwise TS picks the scalar branch and `raw` defaults to `any`.\nfunction buildArrayConverter<TReturn>(opts: {\n of: CustomElementConverter<TReturn>;\n delimiter?: string;\n}): ArrayOf<CustomElementConverter<TReturn>>;\nfunction buildArrayConverter<TToken extends ArrayScalarElement>(opts: {\n of: TToken;\n delimiter?: string;\n}): ArrayOf<TToken>;\nfunction buildArrayConverter(opts?: { delimiter?: string }): ArrayOf<'string'>;\nfunction buildArrayConverter(opts?: { of?: ArrayElement; delimiter?: string }): ArrayOf<ArrayElement> {\n return {\n __envaptKind: 'array',\n of: opts?.of ?? SCALAR.String,\n delimiter: opts?.delimiter ?? ','\n };\n}\n\n/**\n * Built-in converters for environment variables. Use the scalar tokens (e.g. `Converters.Number`)\n * for primitive types and the {@link Converters.array} builder for delimited lists.\n *\n * @example\n * ```ts\n * \\@Envapt('PORT', { converter: Converters.Number, fallback: 3000 })\n * static readonly port: number;\n *\n * \\@Envapt('TAGS', { converter: Converters.array({ of: Converters.String, delimiter: ' ' }) })\n * static readonly tags: string[];\n * ```\n *\n * @public\n */\nexport const Converters = {\n ...SCALAR,\n array: buildArrayConverter\n} as const;\n"],"mappings":"AAAA,MAAM,EAAS,CACX,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,OAAQ,SACR,OAAQ,SACR,QAAS,UACT,MAAO,QACP,KAAM,OACN,IAAK,MACL,OAAQ,SACR,KAAM,OACN,KAAM,MACV,EA8BA,SAAgB,EAAU,EAAkC,CACxD,OAAO,OAAO,GAAU,YAAY,GAAkB,iBAAkB,GAAS,EAAM,eAAiB,OAC5G,CAeA,SAAS,EAAoB,EAAyE,CAClG,MAAO,CACH,aAAc,QACd,GAAI,GAAM,IAAM,EAAO,OACvB,UAAW,GAAM,WAAa,GAClC,CACJ,CAiBA,MAAa,EAAa,CACtB,GAAG,EACH,MAAO,CACX"}
@@ -1,2 +1,2 @@
1
- const e=require("../infra/Error.cjs"),t=require("../engine/Validators.cjs"),n=require("./BuiltInConverters.cjs");function r(e){return Array.isArray(e)?`[${e.join(`, `)}]`:String(e)}var i=class{envService;constructor(e){this.envService=e}convertValue(e,n,r,i){let a=this.resolveConverter(r,n),o=this.processFallbackForConverter(a,n);if(t.Validator.isArrayConverter(a))return this.processArrayConverter(e,o,a,i);if(t.Validator.isPrimitiveConstructor(a)){let t=this.convertPrimitiveToString(a);return this.processBuiltInConverter(e,o,t,i,!0)}return t.Validator.isBuiltInConverter(a)?this.processBuiltInConverter(e,o,a,i,!1):this.processCustomConverter(e,o,a,i)}processFallbackForConverter(e,n){return t.Validator.isPrimitiveConstructor(e)&&n!==void 0?t.Validator.coercePrimitiveFallback(e,n):n}convertPrimitiveToString(t){if(t===String)return`string`;if(t===Number)return`number`;if(t===Boolean)return`boolean`;if(t===BigInt)return`bigint`;if(t===Symbol)return`symbol`;throw new e.EnvaptError(204,`Unknown primitive constructor`)}processBuiltInConverter(e,r,i,a,o){t.Validator.builtInConverter(i),a&&r!==void 0&&!o&&t.Validator.validateBuiltInConverterFallback(i,r);let s=this.envService.get(e,void 0);if(s===void 0)return a?i===`time`&&typeof r==`string`?n.BuiltInConverters.getConverter(i)(``,r):r:null;let c=n.BuiltInConverters.getConverter(i)(s,r);return c===void 0&&!a?null:c}processArrayConverter(r,i,a,o){if(t.Validator.arrayConverter(a),o&&i!==void 0&&!Array.isArray(i))throw new e.EnvaptError(101,`ArrayOf<...> requires that the fallback be an array, got ${typeof i}`);o&&Array.isArray(i)&&(t.Validator.validateArrayFallbackElementTypes(i),t.Validator.validateArrayConverterElementTypeMatch(a.of,i));let s=this.envService.get(r,void 0);if(s===void 0){if(!o)return null;if(a.of===`time`&&Array.isArray(i)&&i.every(e=>typeof e==`string`)){let e=n.BuiltInConverters.getConverter(`time`);return i.map(t=>e(``,t))}return i}return n.BuiltInConverters.processArrayConverter(s,a,this.envService.isStrict())}processCustomConverter(e,n,r,i){return t.Validator.customConvertor(r),r(this.envService.get(e,void 0),n)}resolveConverter(e,t){if(e)return e;let n=typeof t;return n===`number`?`number`:n===`boolean`?`boolean`:n===`bigint`?`bigint`:n===`symbol`?`symbol`:`string`}convertWithSchema(t,n,i,a){let o=this.envService.get(t,void 0);if(o===void 0){if(a)return i;throw new e.EnvaptError(305,`Required environment variable "${r(t)}" is missing or empty.`)}let s;try{s=n[`~standard`].validate(o)}catch(n){throw new e.EnvaptError(209,`Schema for "${r(t)}" threw during validation: ${n.message}`,{cause:n})}if(s instanceof Promise)throw new e.EnvaptError(302,`Schema for "${r(t)}" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`);if(s.issues!==void 0){let n=s.issues[0]?.message??`no issue message`;throw new e.EnvaptError(208,`Schema validation failed for "${r(t)}": ${n}`,{issues:s.issues})}return s.value}};exports.ValueConverter=i;
1
+ const e=require("../infra/Error.cjs"),t=require("./BuiltInConverters.cjs"),n=require("../core/state.cjs"),r=require("../engine/Validators.cjs");function i(e){return Array.isArray(e)?`[${e.join(`, `)}]`:String(e)}var a=class{envService;constructor(e){this.envService=e}convertValue(e,t,n,i){let a=this.resolveConverter(n,t),o=this.processFallbackForConverter(a,t);if(r.Validator.isArrayConverter(a))return this.processArrayConverter(e,o,a,i);if(r.Validator.isPrimitiveConstructor(a)){let t=this.convertPrimitiveToString(a);return this.processBuiltInConverter(e,o,t,i,!0)}return r.Validator.isBuiltInConverter(a)?this.processBuiltInConverter(e,o,a,i,!1):this.processCustomConverter(e,o,a,i)}processFallbackForConverter(e,t){return r.Validator.isPrimitiveConstructor(e)&&t!==void 0?r.Validator.coercePrimitiveFallback(e,t):t}convertPrimitiveToString(t){if(t===String)return`string`;if(t===Number)return`number`;if(t===Boolean)return`boolean`;if(t===BigInt)return`bigint`;if(t===Symbol)return`symbol`;throw new e.EnvaptError(204,`Unknown primitive constructor`)}processBuiltInConverter(e,n,i,a,o){r.Validator.builtInConverter(i),a&&n!==void 0&&!o&&r.Validator.validateBuiltInConverterFallback(i,n);let s=this.envService.get(e,void 0);if(s===void 0)return a?i===`time`&&typeof n==`string`?t.BuiltInConverters.getConverter(i)(``,n):n:null;let c=t.BuiltInConverters.getConverter(i)(s,n);return c===void 0&&!a?null:c}processArrayConverter(i,a,o,s){if(r.Validator.arrayConverter(o),s&&a!==void 0&&!Array.isArray(a))throw new e.EnvaptError(101,`ArrayOf<...> requires that the fallback be an array, got ${typeof a}`);s&&Array.isArray(a)&&(r.Validator.validateArrayFallbackElementTypes(a),r.Validator.validateArrayConverterElementTypeMatch(o.of,a));let c=this.envService.get(i,void 0);if(c===void 0){if(!s)return null;if(o.of===`time`&&Array.isArray(a)&&a.every(e=>typeof e==`string`)){let e=t.BuiltInConverters.getConverter(`time`);return a.map(t=>e(``,t))}return a}return t.BuiltInConverters.processArrayConverter(c,o,n.state.strict)}processCustomConverter(e,t,n,i){return r.Validator.customConvertor(n),n(this.envService.get(e,void 0),t)}resolveConverter(e,t){if(e)return e;let n=typeof t;return n===`number`?`number`:n===`boolean`?`boolean`:n===`bigint`?`bigint`:n===`symbol`?`symbol`:`string`}convertWithSchema(t,n,r,a){let o=this.envService.get(t,void 0);if(o===void 0){if(a)return r;throw new e.EnvaptError(305,`Required environment variable "${i(t)}" is missing or empty.`)}let s;try{s=n[`~standard`].validate(o)}catch(n){throw new e.EnvaptError(209,`Schema for "${i(t)}" threw during validation: ${n.message}`,{cause:n})}if(s instanceof Promise)throw new e.EnvaptError(302,`Schema for "${i(t)}" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`);if(s.issues!==void 0){let n=s.issues[0]?.message??`no issue message`;throw new e.EnvaptError(208,`Schema validation failed for "${i(t)}": ${n}`,{issues:s.issues})}return s.value}};exports.ValueConverter=a;
2
2
  //# sourceMappingURL=ValueConverter.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ValueConverter.cjs","names":["Validator","EnvaptError","BuiltInConverters"],"sources":["../../../src/converters/ValueConverter.ts"],"sourcesContent":["import { BuiltInConverters } from './BuiltInConverters';\nimport { Validator } from '../engine/Validators';\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf } from './Converters';\nimport type { StandardSchemaV1 } from '../infra/StandardSchema';\nimport type { BuiltInConverter, EnvKeyInput, EnvaptConverter, PrimitiveConstructor } from '../types';\nimport type { EnvapterService } from '../types/Env';\n\nfunction formatKeyForError(key: EnvKeyInput): string {\n return Array.isArray(key) ? `[${key.join(', ')}]` : String(key);\n}\n\n/**\n * Convert a resolved environment value to its declared type via built-in, primitive, array,\n * custom, or Standard Schema converters.\n * @internal\n */\nexport class ValueConverter {\n constructor(private readonly envService: EnvapterService) {}\n\n convertValue<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n converter: EnvaptConverter<TFallback> | undefined,\n hasFallback: boolean\n ): TFallback | null | undefined {\n const resolvedConverter = this.resolveConverter(converter, fallback);\n const processedFallback = this.processFallbackForConverter(resolvedConverter, fallback);\n\n if (Validator.isArrayConverter(resolvedConverter)) {\n return this.processArrayConverter(key, processedFallback, resolvedConverter, hasFallback);\n }\n\n if (Validator.isPrimitiveConstructor(resolvedConverter)) {\n const stringConverter = this.convertPrimitiveToString(resolvedConverter);\n return this.processBuiltInConverter(key, processedFallback, stringConverter, hasFallback, true);\n }\n\n if (Validator.isBuiltInConverter(resolvedConverter)) {\n return this.processBuiltInConverter(key, processedFallback, resolvedConverter, hasFallback, false);\n }\n\n return this.processCustomConverter(key, processedFallback, resolvedConverter, hasFallback);\n }\n\n private processFallbackForConverter<TFallback>(\n converter: EnvaptConverter<TFallback>,\n fallback: TFallback | undefined\n ): TFallback | undefined {\n if (Validator.isPrimitiveConstructor(converter) && fallback !== undefined) {\n return Validator.coercePrimitiveFallback<TFallback>(converter, fallback);\n }\n return fallback;\n }\n\n private convertPrimitiveToString(primitiveConstructor: PrimitiveConstructor): BuiltInConverter {\n if (primitiveConstructor === String) return 'string';\n if (primitiveConstructor === Number) return 'number';\n if (primitiveConstructor === Boolean) return 'boolean';\n if (primitiveConstructor === BigInt) return 'bigint';\n /* v8 ignore next -- @preserve */\n if (primitiveConstructor === Symbol) return 'symbol';\n\n /* v8 ignore next -- @preserve */\n throw new EnvaptError(EnvaptErrorCodes.InvalidConverterType, `Unknown primitive constructor`);\n }\n\n private processBuiltInConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: BuiltInConverter,\n hasFallback: boolean,\n wasOriginallyConstructor: boolean\n ): TFallback | null | undefined {\n Validator.builtInConverter(resolvedConverter);\n\n if (hasFallback && fallback !== undefined && !wasOriginallyConstructor) {\n Validator.validateBuiltInConverterFallback(resolvedConverter, fallback);\n }\n\n const parsed = this.envService.get(key, undefined);\n\n if (parsed === undefined) {\n if (!hasFallback) return null;\n // For converters with asymmetric fallback / return types — currently only `time`,\n // whose fallback may be a string while the return type is `number` — route the\n // fallback through the converter so it gets coerced to the return type.\n if (resolvedConverter === 'time' && typeof fallback === 'string') {\n const timeFn = BuiltInConverters.getConverter(resolvedConverter);\n return timeFn('', fallback) as TFallback;\n }\n return fallback;\n }\n\n const converterFn = BuiltInConverters.getConverter(resolvedConverter);\n const result = converterFn(parsed, fallback);\n\n if (result === undefined && !hasFallback) return null;\n\n return result as TFallback;\n }\n\n private processArrayConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: ArrayOf,\n hasFallback: boolean\n ): TFallback | null | undefined {\n Validator.arrayConverter(resolvedConverter);\n\n if (hasFallback && fallback !== undefined && !Array.isArray(fallback)) {\n throw new EnvaptError(\n EnvaptErrorCodes.InvalidFallback,\n `ArrayOf<...> requires that the fallback be an array, got ${typeof fallback}`\n );\n }\n\n if (hasFallback && Array.isArray(fallback)) {\n Validator.validateArrayFallbackElementTypes(fallback);\n Validator.validateArrayConverterElementTypeMatch(resolvedConverter.of, fallback);\n }\n\n const parsed = this.envService.get(key, undefined);\n\n if (parsed === undefined) {\n if (!hasFallback) return null;\n // When the array element is `time` and the fallback is a list of time-strings,\n // coerce each entry through the time converter so the returned array is\n // `number[]` matching the declared return type.\n if (\n resolvedConverter.of === 'time' &&\n Array.isArray(fallback) &&\n fallback.every((v) => typeof v === 'string')\n ) {\n const timeFn = BuiltInConverters.getConverter('time');\n return fallback.map((v) => timeFn('', v as string)) as TFallback;\n }\n return fallback;\n }\n\n const result = BuiltInConverters.processArrayConverter(parsed, resolvedConverter, this.envService.isStrict());\n return result as TFallback;\n }\n\n private processCustomConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: EnvaptConverter<TFallback>,\n _hasFallback: boolean // hasFallback is not needed because customConverter is called even if the raw value is undefined\n ): TFallback | null | undefined {\n Validator.customConvertor(resolvedConverter);\n\n const raw = this.envService.get(key, undefined);\n\n return resolvedConverter(raw, fallback);\n }\n\n private resolveConverter<TFallback>(\n converter: EnvaptConverter<TFallback> | undefined,\n fallback: TFallback | undefined\n ): EnvaptConverter<TFallback> {\n if (converter) return converter;\n\n const fallbackType = typeof fallback;\n if (fallbackType === 'number') return 'number';\n if (fallbackType === 'boolean') return 'boolean';\n if (fallbackType === 'bigint') return 'bigint';\n if (fallbackType === 'symbol') return 'symbol';\n return 'string';\n }\n\n // Single dispatch site for decorator + `Envapter.parse()` so error codes (208 / 209 / 305)\n // stay consistent. Missing+no-fallback throws here so callers don't duplicate the check.\n convertWithSchema(key: EnvKeyInput, schema: StandardSchemaV1, fallback: unknown, hasFallback: boolean): unknown {\n const raw = this.envService.get(key, undefined);\n\n if (raw === undefined) {\n if (hasFallback) return fallback;\n throw new EnvaptError(\n EnvaptErrorCodes.MissingEnvValue,\n `Required environment variable \"${formatKeyForError(key)}\" is missing or empty.`\n );\n }\n\n let outcome: StandardSchemaV1.Result<unknown> | Promise<StandardSchemaV1.Result<unknown>>;\n try {\n outcome = schema['~standard'].validate(raw);\n } catch (cause) {\n throw new EnvaptError(\n EnvaptErrorCodes.SchemaThrew,\n `Schema for \"${formatKeyForError(key)}\" threw during validation: ${(cause as Error).message}`,\n { cause }\n );\n }\n\n if (outcome instanceof Promise) {\n throw new EnvaptError(\n EnvaptErrorCodes.InvalidUserDefinedConfig,\n `Schema for \"${formatKeyForError(key)}\" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`\n );\n }\n\n if (outcome.issues !== undefined) {\n const first = outcome.issues[0];\n const firstMessage = first?.message ?? 'no issue message';\n throw new EnvaptError(\n EnvaptErrorCodes.SchemaValidationFailed,\n `Schema validation failed for \"${formatKeyForError(key)}\": ${firstMessage}`,\n { issues: outcome.issues }\n );\n }\n\n return outcome.value;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ValueConverter.cjs","names":["Validator","EnvaptError","BuiltInConverters","state"],"sources":["../../../src/converters/ValueConverter.ts"],"sourcesContent":["import { BuiltInConverters } from './BuiltInConverters';\nimport { state } from '../core/state';\nimport { Validator } from '../engine/Validators';\nimport { EnvaptError, EnvaptErrorCodes } from '../infra/Error';\n\nimport type { ArrayOf } from './Converters';\nimport type { StandardSchemaV1 } from '../infra/StandardSchema';\nimport type { BuiltInConverter, EnvKeyInput, EnvaptConverter, PrimitiveConstructor } from '../types';\nimport type { EnvapterService } from '../types/Env';\n\nfunction formatKeyForError(key: EnvKeyInput): string {\n return Array.isArray(key) ? `[${key.join(', ')}]` : String(key);\n}\n\n/**\n * Convert a resolved environment value to its declared type via built-in, primitive, array,\n * custom, or Standard Schema converters.\n * @internal\n */\nexport class ValueConverter {\n constructor(private readonly envService: EnvapterService) {}\n\n convertValue<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n converter: EnvaptConverter<TFallback> | undefined,\n hasFallback: boolean\n ): TFallback | null | undefined {\n const resolvedConverter = this.resolveConverter(converter, fallback);\n const processedFallback = this.processFallbackForConverter(resolvedConverter, fallback);\n\n if (Validator.isArrayConverter(resolvedConverter)) {\n return this.processArrayConverter(key, processedFallback, resolvedConverter, hasFallback);\n }\n\n if (Validator.isPrimitiveConstructor(resolvedConverter)) {\n const stringConverter = this.convertPrimitiveToString(resolvedConverter);\n return this.processBuiltInConverter(key, processedFallback, stringConverter, hasFallback, true);\n }\n\n if (Validator.isBuiltInConverter(resolvedConverter)) {\n return this.processBuiltInConverter(key, processedFallback, resolvedConverter, hasFallback, false);\n }\n\n return this.processCustomConverter(key, processedFallback, resolvedConverter, hasFallback);\n }\n\n private processFallbackForConverter<TFallback>(\n converter: EnvaptConverter<TFallback>,\n fallback: TFallback | undefined\n ): TFallback | undefined {\n if (Validator.isPrimitiveConstructor(converter) && fallback !== undefined) {\n return Validator.coercePrimitiveFallback<TFallback>(converter, fallback);\n }\n return fallback;\n }\n\n private convertPrimitiveToString(primitiveConstructor: PrimitiveConstructor): BuiltInConverter {\n if (primitiveConstructor === String) return 'string';\n if (primitiveConstructor === Number) return 'number';\n if (primitiveConstructor === Boolean) return 'boolean';\n if (primitiveConstructor === BigInt) return 'bigint';\n /* v8 ignore next -- @preserve */\n if (primitiveConstructor === Symbol) return 'symbol';\n\n /* v8 ignore next -- @preserve */\n throw new EnvaptError(EnvaptErrorCodes.InvalidConverterType, `Unknown primitive constructor`);\n }\n\n private processBuiltInConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: BuiltInConverter,\n hasFallback: boolean,\n wasOriginallyConstructor: boolean\n ): TFallback | null | undefined {\n Validator.builtInConverter(resolvedConverter);\n\n if (hasFallback && fallback !== undefined && !wasOriginallyConstructor) {\n Validator.validateBuiltInConverterFallback(resolvedConverter, fallback);\n }\n\n const parsed = this.envService.get(key, undefined);\n\n if (parsed === undefined) {\n if (!hasFallback) return null;\n // For converters with asymmetric fallback / return types — currently only `time`,\n // whose fallback may be a string while the return type is `number` — route the\n // fallback through the converter so it gets coerced to the return type.\n if (resolvedConverter === 'time' && typeof fallback === 'string') {\n const timeFn = BuiltInConverters.getConverter(resolvedConverter);\n return timeFn('', fallback) as TFallback;\n }\n return fallback;\n }\n\n const converterFn = BuiltInConverters.getConverter(resolvedConverter);\n const result = converterFn(parsed, fallback);\n\n if (result === undefined && !hasFallback) return null;\n\n return result as TFallback;\n }\n\n private processArrayConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: ArrayOf,\n hasFallback: boolean\n ): TFallback | null | undefined {\n Validator.arrayConverter(resolvedConverter);\n\n if (hasFallback && fallback !== undefined && !Array.isArray(fallback)) {\n throw new EnvaptError(\n EnvaptErrorCodes.InvalidFallback,\n `ArrayOf<...> requires that the fallback be an array, got ${typeof fallback}`\n );\n }\n\n if (hasFallback && Array.isArray(fallback)) {\n Validator.validateArrayFallbackElementTypes(fallback);\n Validator.validateArrayConverterElementTypeMatch(resolvedConverter.of, fallback);\n }\n\n const parsed = this.envService.get(key, undefined);\n\n if (parsed === undefined) {\n if (!hasFallback) return null;\n // When the array element is `time` and the fallback is a list of time-strings,\n // coerce each entry through the time converter so the returned array is\n // `number[]` matching the declared return type.\n if (\n resolvedConverter.of === 'time' &&\n Array.isArray(fallback) &&\n fallback.every((v) => typeof v === 'string')\n ) {\n const timeFn = BuiltInConverters.getConverter('time');\n return fallback.map((v) => timeFn('', v as string)) as TFallback;\n }\n return fallback;\n }\n\n const result = BuiltInConverters.processArrayConverter(parsed, resolvedConverter, state.strict);\n return result as TFallback;\n }\n\n private processCustomConverter<TFallback>(\n key: EnvKeyInput,\n fallback: TFallback | undefined,\n resolvedConverter: EnvaptConverter<TFallback>,\n _hasFallback: boolean // hasFallback is not needed because customConverter is called even if the raw value is undefined\n ): TFallback | null | undefined {\n Validator.customConvertor(resolvedConverter);\n\n const raw = this.envService.get(key, undefined);\n\n return resolvedConverter(raw, fallback);\n }\n\n private resolveConverter<TFallback>(\n converter: EnvaptConverter<TFallback> | undefined,\n fallback: TFallback | undefined\n ): EnvaptConverter<TFallback> {\n if (converter) return converter;\n\n const fallbackType = typeof fallback;\n if (fallbackType === 'number') return 'number';\n if (fallbackType === 'boolean') return 'boolean';\n if (fallbackType === 'bigint') return 'bigint';\n if (fallbackType === 'symbol') return 'symbol';\n return 'string';\n }\n\n // Single dispatch site for decorator + `Envapter.parse()` so error codes (208 / 209 / 305)\n // stay consistent. Missing+no-fallback throws here so callers don't duplicate the check.\n convertWithSchema(key: EnvKeyInput, schema: StandardSchemaV1, fallback: unknown, hasFallback: boolean): unknown {\n const raw = this.envService.get(key, undefined);\n\n if (raw === undefined) {\n if (hasFallback) return fallback;\n throw new EnvaptError(\n EnvaptErrorCodes.MissingEnvValue,\n `Required environment variable \"${formatKeyForError(key)}\" is missing or empty.`\n );\n }\n\n let outcome: StandardSchemaV1.Result<unknown> | Promise<StandardSchemaV1.Result<unknown>>;\n try {\n outcome = schema['~standard'].validate(raw);\n } catch (cause) {\n throw new EnvaptError(\n EnvaptErrorCodes.SchemaThrew,\n `Schema for \"${formatKeyForError(key)}\" threw during validation: ${(cause as Error).message}`,\n { cause }\n );\n }\n\n if (outcome instanceof Promise) {\n throw new EnvaptError(\n EnvaptErrorCodes.InvalidUserDefinedConfig,\n `Schema for \"${formatKeyForError(key)}\" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`\n );\n }\n\n if (outcome.issues !== undefined) {\n const first = outcome.issues[0];\n const firstMessage = first?.message ?? 'no issue message';\n throw new EnvaptError(\n EnvaptErrorCodes.SchemaValidationFailed,\n `Schema validation failed for \"${formatKeyForError(key)}\": ${firstMessage}`,\n { issues: outcome.issues }\n );\n }\n\n return outcome.value;\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{EnvaptError as e}from"../infra/Error.mjs";import{Validator as t}from"../engine/Validators.mjs";import{BuiltInConverters as n}from"./BuiltInConverters.mjs";function r(e){return Array.isArray(e)?`[${e.join(`, `)}]`:String(e)}var i=class{envService;constructor(e){this.envService=e}convertValue(e,n,r,i){let a=this.resolveConverter(r,n),o=this.processFallbackForConverter(a,n);if(t.isArrayConverter(a))return this.processArrayConverter(e,o,a,i);if(t.isPrimitiveConstructor(a)){let t=this.convertPrimitiveToString(a);return this.processBuiltInConverter(e,o,t,i,!0)}return t.isBuiltInConverter(a)?this.processBuiltInConverter(e,o,a,i,!1):this.processCustomConverter(e,o,a,i)}processFallbackForConverter(e,n){return t.isPrimitiveConstructor(e)&&n!==void 0?t.coercePrimitiveFallback(e,n):n}convertPrimitiveToString(t){if(t===String)return`string`;if(t===Number)return`number`;if(t===Boolean)return`boolean`;if(t===BigInt)return`bigint`;if(t===Symbol)return`symbol`;throw new e(204,`Unknown primitive constructor`)}processBuiltInConverter(e,r,i,a,o){t.builtInConverter(i),a&&r!==void 0&&!o&&t.validateBuiltInConverterFallback(i,r);let s=this.envService.get(e,void 0);if(s===void 0)return a?i===`time`&&typeof r==`string`?n.getConverter(i)(``,r):r:null;let c=n.getConverter(i)(s,r);return c===void 0&&!a?null:c}processArrayConverter(r,i,a,o){if(t.arrayConverter(a),o&&i!==void 0&&!Array.isArray(i))throw new e(101,`ArrayOf<...> requires that the fallback be an array, got ${typeof i}`);o&&Array.isArray(i)&&(t.validateArrayFallbackElementTypes(i),t.validateArrayConverterElementTypeMatch(a.of,i));let s=this.envService.get(r,void 0);if(s===void 0){if(!o)return null;if(a.of===`time`&&Array.isArray(i)&&i.every(e=>typeof e==`string`)){let e=n.getConverter(`time`);return i.map(t=>e(``,t))}return i}return n.processArrayConverter(s,a,this.envService.isStrict())}processCustomConverter(e,n,r,i){return t.customConvertor(r),r(this.envService.get(e,void 0),n)}resolveConverter(e,t){if(e)return e;let n=typeof t;return n===`number`?`number`:n===`boolean`?`boolean`:n===`bigint`?`bigint`:n===`symbol`?`symbol`:`string`}convertWithSchema(t,n,i,a){let o=this.envService.get(t,void 0);if(o===void 0){if(a)return i;throw new e(305,`Required environment variable "${r(t)}" is missing or empty.`)}let s;try{s=n[`~standard`].validate(o)}catch(n){throw new e(209,`Schema for "${r(t)}" threw during validation: ${n.message}`,{cause:n})}if(s instanceof Promise)throw new e(302,`Schema for "${r(t)}" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`);if(s.issues!==void 0){let n=s.issues[0]?.message??`no issue message`;throw new e(208,`Schema validation failed for "${r(t)}": ${n}`,{issues:s.issues})}return s.value}};export{i as ValueConverter};
1
+ import{EnvaptError as e}from"../infra/Error.mjs";import{BuiltInConverters as t}from"./BuiltInConverters.mjs";import{state as n}from"../core/state.mjs";import{Validator as r}from"../engine/Validators.mjs";function i(e){return Array.isArray(e)?`[${e.join(`, `)}]`:String(e)}var a=class{envService;constructor(e){this.envService=e}convertValue(e,t,n,i){let a=this.resolveConverter(n,t),o=this.processFallbackForConverter(a,t);if(r.isArrayConverter(a))return this.processArrayConverter(e,o,a,i);if(r.isPrimitiveConstructor(a)){let t=this.convertPrimitiveToString(a);return this.processBuiltInConverter(e,o,t,i,!0)}return r.isBuiltInConverter(a)?this.processBuiltInConverter(e,o,a,i,!1):this.processCustomConverter(e,o,a,i)}processFallbackForConverter(e,t){return r.isPrimitiveConstructor(e)&&t!==void 0?r.coercePrimitiveFallback(e,t):t}convertPrimitiveToString(t){if(t===String)return`string`;if(t===Number)return`number`;if(t===Boolean)return`boolean`;if(t===BigInt)return`bigint`;if(t===Symbol)return`symbol`;throw new e(204,`Unknown primitive constructor`)}processBuiltInConverter(e,n,i,a,o){r.builtInConverter(i),a&&n!==void 0&&!o&&r.validateBuiltInConverterFallback(i,n);let s=this.envService.get(e,void 0);if(s===void 0)return a?i===`time`&&typeof n==`string`?t.getConverter(i)(``,n):n:null;let c=t.getConverter(i)(s,n);return c===void 0&&!a?null:c}processArrayConverter(i,a,o,s){if(r.arrayConverter(o),s&&a!==void 0&&!Array.isArray(a))throw new e(101,`ArrayOf<...> requires that the fallback be an array, got ${typeof a}`);s&&Array.isArray(a)&&(r.validateArrayFallbackElementTypes(a),r.validateArrayConverterElementTypeMatch(o.of,a));let c=this.envService.get(i,void 0);if(c===void 0){if(!s)return null;if(o.of===`time`&&Array.isArray(a)&&a.every(e=>typeof e==`string`)){let e=t.getConverter(`time`);return a.map(t=>e(``,t))}return a}return t.processArrayConverter(c,o,n.strict)}processCustomConverter(e,t,n,i){return r.customConvertor(n),n(this.envService.get(e,void 0),t)}resolveConverter(e,t){if(e)return e;let n=typeof t;return n===`number`?`number`:n===`boolean`?`boolean`:n===`bigint`?`bigint`:n===`symbol`?`symbol`:`string`}convertWithSchema(t,n,r,a){let o=this.envService.get(t,void 0);if(o===void 0){if(a)return r;throw new e(305,`Required environment variable "${i(t)}" is missing or empty.`)}let s;try{s=n[`~standard`].validate(o)}catch(n){throw new e(209,`Schema for "${i(t)}" threw during validation: ${n.message}`,{cause:n})}if(s instanceof Promise)throw new e(302,`Schema for "${i(t)}" returned a Promise. envapt requires synchronous schemas; use a sync validator or perform async checks outside the env layer.`);if(s.issues!==void 0){let n=s.issues[0]?.message??`no issue message`;throw new e(208,`Schema validation failed for "${i(t)}": ${n}`,{issues:s.issues})}return s.value}};export{a as ValueConverter};
2
2
  //# sourceMappingURL=ValueConverter.mjs.map