@geekmidas/envkit 1.0.3 → 1.0.5

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 (88) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{EnvironmentBuilder-BSuHZm0y.mjs → EnvironmentBuilder-CFen3oIg.mjs} +1 -1
  3. package/dist/{EnvironmentBuilder-BSuHZm0y.mjs.map → EnvironmentBuilder-CFen3oIg.mjs.map} +1 -1
  4. package/dist/{EnvironmentBuilder-Xuf2Dd9u.d.cts → EnvironmentBuilder-CNgcdzSR.d.cts} +1 -1
  5. package/dist/{EnvironmentBuilder-Xuf2Dd9u.d.cts.map → EnvironmentBuilder-CNgcdzSR.d.cts.map} +1 -1
  6. package/dist/{EnvironmentBuilder-Djr1VsWM.cjs → EnvironmentBuilder-DDgLJAAo.cjs} +1 -1
  7. package/dist/{EnvironmentBuilder-Djr1VsWM.cjs.map → EnvironmentBuilder-DDgLJAAo.cjs.map} +1 -1
  8. package/dist/{EnvironmentBuilder-jF-b7WQg.d.mts → EnvironmentBuilder-DHfDXJUm.d.mts} +1 -1
  9. package/dist/{EnvironmentBuilder-jF-b7WQg.d.mts.map → EnvironmentBuilder-DHfDXJUm.d.mts.map} +1 -1
  10. package/dist/{EnvironmentParser-DtOL86NU.d.cts → EnvironmentParser-BY1oCUsc.d.mts} +3 -3
  11. package/dist/EnvironmentParser-BY1oCUsc.d.mts.map +1 -0
  12. package/dist/{EnvironmentParser-DJdW7vOL.cjs → EnvironmentParser-Bzg5yXG2.cjs} +124 -4
  13. package/dist/EnvironmentParser-Bzg5yXG2.cjs.map +1 -0
  14. package/dist/{EnvironmentParser-CkLfmn4Y.d.mts → EnvironmentParser-DoooZm8n.d.cts} +3 -3
  15. package/dist/EnvironmentParser-DoooZm8n.d.cts.map +1 -0
  16. package/dist/{EnvironmentParser-zMblItla.mjs → EnvironmentParser-taAKfzT7.mjs} +112 -4
  17. package/dist/EnvironmentParser-taAKfzT7.mjs.map +1 -0
  18. package/dist/SnifferEnvironmentParser.cjs +19 -4
  19. package/dist/SnifferEnvironmentParser.cjs.map +1 -1
  20. package/dist/SnifferEnvironmentParser.d.cts +20 -3
  21. package/dist/SnifferEnvironmentParser.d.cts.map +1 -1
  22. package/dist/SnifferEnvironmentParser.d.mts +20 -3
  23. package/dist/SnifferEnvironmentParser.d.mts.map +1 -1
  24. package/dist/SnifferEnvironmentParser.mjs +19 -4
  25. package/dist/SnifferEnvironmentParser.mjs.map +1 -1
  26. package/dist/credentials.cjs +9 -3
  27. package/dist/credentials.cjs.map +1 -1
  28. package/dist/credentials.d.cts +7 -3
  29. package/dist/credentials.d.cts.map +1 -1
  30. package/dist/credentials.d.mts +7 -3
  31. package/dist/credentials.d.mts.map +1 -1
  32. package/dist/credentials.mjs +9 -3
  33. package/dist/credentials.mjs.map +1 -1
  34. package/dist/index.cjs +4 -5
  35. package/dist/index.d.cts +52 -4
  36. package/dist/index.d.cts.map +1 -0
  37. package/dist/index.d.mts +52 -4
  38. package/dist/index.d.mts.map +1 -0
  39. package/dist/index.mjs +2 -3
  40. package/dist/sst.cjs +114 -6
  41. package/dist/sst.cjs.map +1 -1
  42. package/dist/sst.d.cts +184 -3
  43. package/dist/sst.d.cts.map +1 -1
  44. package/dist/sst.d.mts +184 -3
  45. package/dist/sst.d.mts.map +1 -1
  46. package/dist/sst.mjs +110 -2
  47. package/dist/sst.mjs.map +1 -1
  48. package/package.json +4 -3
  49. package/src/SnifferEnvironmentParser.ts +31 -3
  50. package/src/__tests__/SnifferEnvironmentParser.spec.ts +158 -0
  51. package/src/credentials.ts +16 -3
  52. package/tsdown.config.ts +16 -1
  53. package/dist/EnvironmentBuilder.cjs +0 -4
  54. package/dist/EnvironmentBuilder.d.cts +0 -2
  55. package/dist/EnvironmentBuilder.d.mts +0 -2
  56. package/dist/EnvironmentBuilder.mjs +0 -3
  57. package/dist/EnvironmentParser-CkLfmn4Y.d.mts.map +0 -1
  58. package/dist/EnvironmentParser-DJdW7vOL.cjs.map +0 -1
  59. package/dist/EnvironmentParser-DtOL86NU.d.cts.map +0 -1
  60. package/dist/EnvironmentParser-zMblItla.mjs.map +0 -1
  61. package/dist/EnvironmentParser.cjs +0 -5
  62. package/dist/EnvironmentParser.d.cts +0 -2
  63. package/dist/EnvironmentParser.d.mts +0 -2
  64. package/dist/EnvironmentParser.mjs +0 -4
  65. package/dist/SstEnvironmentBuilder-BRAcRQp2.d.mts +0 -186
  66. package/dist/SstEnvironmentBuilder-BRAcRQp2.d.mts.map +0 -1
  67. package/dist/SstEnvironmentBuilder-D-NGrp7U.cjs +0 -130
  68. package/dist/SstEnvironmentBuilder-D-NGrp7U.cjs.map +0 -1
  69. package/dist/SstEnvironmentBuilder-DOu4dVPL.mjs +0 -113
  70. package/dist/SstEnvironmentBuilder-DOu4dVPL.mjs.map +0 -1
  71. package/dist/SstEnvironmentBuilder-Dc9nOuuK.d.cts +0 -186
  72. package/dist/SstEnvironmentBuilder-Dc9nOuuK.d.cts.map +0 -1
  73. package/dist/SstEnvironmentBuilder.cjs +0 -7
  74. package/dist/SstEnvironmentBuilder.d.cts +0 -3
  75. package/dist/SstEnvironmentBuilder.d.mts +0 -3
  76. package/dist/SstEnvironmentBuilder.mjs +0 -4
  77. package/dist/formatter-BRRrxQi3.mjs +0 -111
  78. package/dist/formatter-BRRrxQi3.mjs.map +0 -1
  79. package/dist/formatter-Cox0NGxT.d.mts +0 -51
  80. package/dist/formatter-Cox0NGxT.d.mts.map +0 -1
  81. package/dist/formatter-D85aIkpd.d.cts +0 -51
  82. package/dist/formatter-D85aIkpd.d.cts.map +0 -1
  83. package/dist/formatter-HxePpSy2.cjs +0 -123
  84. package/dist/formatter-HxePpSy2.cjs.map +0 -1
  85. package/dist/formatter.cjs +0 -4
  86. package/dist/formatter.d.cts +0 -2
  87. package/dist/formatter.d.mts +0 -2
  88. package/dist/formatter.mjs +0 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @geekmidas/envkit
2
2
 
3
+ ## 1.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - ✨ [`56e71bc`](https://github.com/geekmidas/toolbox/commit/56e71bcb57a5305270909f695a4539fa504a463b) Thanks [@geekmidas](https://github.com/geekmidas)! - Add optional params support and open api on build
8
+
9
+ ## 1.0.4
10
+
11
+ ### Patch Changes
12
+
13
+ - 🐛 [`a483d4c`](https://github.com/geekmidas/toolbox/commit/a483d4c193d27673ccad2aeed6f56b1c5708b5b4) Thanks [@geekmidas](https://github.com/geekmidas)! - Fix credentials injection to work with esm/cjs
14
+
3
15
  ## 1.0.3
4
16
 
5
17
  ### Patch Changes
@@ -78,4 +78,4 @@ var EnvironmentBuilder = class {
78
78
 
79
79
  //#endregion
80
80
  export { EnvironmentBuilder, environmentCase };
81
- //# sourceMappingURL=EnvironmentBuilder-BSuHZm0y.mjs.map
81
+ //# sourceMappingURL=EnvironmentBuilder-CFen3oIg.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentBuilder-BSuHZm0y.mjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,UAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
1
+ {"version":3,"file":"EnvironmentBuilder-CFen3oIg.mjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,UAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
@@ -128,4 +128,4 @@ declare class EnvironmentBuilder<TRecord extends Record<string, InputValue> = Re
128
128
  }
129
129
  //#endregion
130
130
  export { EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase };
131
- //# sourceMappingURL=EnvironmentBuilder-Xuf2Dd9u.d.cts.map
131
+ //# sourceMappingURL=EnvironmentBuilder-CNgcdzSR.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentBuilder-Xuf2Dd9u.d.cts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
1
+ {"version":3,"file":"EnvironmentBuilder-CNgcdzSR.d.cts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
@@ -90,4 +90,4 @@ Object.defineProperty(exports, 'environmentCase', {
90
90
  return environmentCase;
91
91
  }
92
92
  });
93
- //# sourceMappingURL=EnvironmentBuilder-Djr1VsWM.cjs.map
93
+ //# sourceMappingURL=EnvironmentBuilder-DDgLJAAo.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentBuilder-Djr1VsWM.cjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,8BAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
1
+ {"version":3,"file":"EnvironmentBuilder-DDgLJAAo.cjs","names":["name: string","record: TRecord","resolvers: TResolvers","options: EnvironmentBuilderOptions","env: EnvRecord"],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":["import snakecase from 'lodash.snakecase';\n\n/**\n * Converts a string to environment variable case format (UPPER_SNAKE_CASE).\n * Numbers following underscores are preserved without the underscore.\n *\n * @param name - The string to convert\n * @returns The converted string in environment variable format\n *\n * @example\n * environmentCase('myVariable') // 'MY_VARIABLE'\n * environmentCase('apiV2') // 'APIV2'\n */\nexport function environmentCase(name: string): string {\n\treturn snakecase(name)\n\t\t.toUpperCase()\n\t\t.replace(/_\\d+/g, (r) => {\n\t\t\treturn r.replace('_', '');\n\t\t});\n}\n\n/**\n * A record of environment variable names to their values.\n * Values can be primitives or nested records.\n */\nexport interface EnvRecord {\n\t[key: string]: EnvValue;\n}\n\n/**\n * Represents a value that can be stored in an environment record.\n * Can be a primitive value or a nested record of environment values.\n */\nexport type EnvValue = string | number | boolean | EnvRecord;\n\n/**\n * A resolver function that converts a typed value into environment variables.\n *\n * @template T - The type of value this resolver handles (without the `type` key)\n * @param key - The key name from the input record\n * @param value - The value to resolve (without the `type` key)\n * @returns A record of environment variable names to their values\n */\nexport type EnvironmentResolver<T = any> = (key: string, value: T) => EnvRecord;\n\n/**\n * A map of type discriminator strings to their resolver functions.\n */\nexport type Resolvers = Record<string, EnvironmentResolver<any>>;\n\n/**\n * Options for configuring the EnvironmentBuilder.\n */\nexport interface EnvironmentBuilderOptions {\n\t/**\n\t * Handler called when a value's type doesn't match any registered resolver.\n\t * Defaults to console.warn.\n\t */\n\tonUnmatchedValue?: (key: string, value: unknown) => void;\n}\n\n/**\n * Input value type - either a string or an object with a `type` discriminator.\n */\nexport type InputValue = string | { type: string; [key: string]: unknown };\n\n/**\n * Base type for typed input values with a specific type discriminator.\n */\nexport type TypedInputValue<TType extends string = string> = {\n\ttype: TType;\n\t[key: string]: unknown;\n};\n\n/**\n * Extracts the `type` string value from an input value.\n */\ntype ExtractType<T> = T extends { type: infer U extends string } ? U : never;\n\n/**\n * Removes the `type` key from an object type.\n */\ntype OmitType<T> = T extends { type: string } ? Omit<T, 'type'> : never;\n\n/**\n * Extracts all unique `type` values from a record (excluding plain strings).\n */\ntype AllTypeValues<TRecord extends Record<string, InputValue>> = {\n\t[K in keyof TRecord]: ExtractType<TRecord[K]>;\n}[keyof TRecord];\n\n/**\n * For a given type value, finds the corresponding value type (without `type` key).\n */\ntype ValueForType<\n\tTRecord extends Record<string, InputValue>,\n\tTType extends string,\n> = {\n\t[K in keyof TRecord]: TRecord[K] extends { type: TType }\n\t\t? OmitType<TRecord[K]>\n\t\t: never;\n}[keyof TRecord];\n\n/**\n * Generates typed resolvers based on the input record.\n * Keys are the `type` values, values are resolver functions receiving the value without `type`.\n */\nexport type TypedResolvers<TRecord extends Record<string, InputValue>> = {\n\t[TType in AllTypeValues<TRecord>]: EnvironmentResolver<\n\t\tValueForType<TRecord, TType>\n\t>;\n};\n\n/**\n * A generic, extensible class for building environment variables from\n * objects with type-discriminated values.\n *\n * @template TRecord - The input record type for type inference\n * @template TResolvers - The resolvers type (defaults to TypedResolvers<TRecord>)\n *\n * @example\n * ```typescript\n * const env = new EnvironmentBuilder(\n * {\n * apiKey: { type: 'secret', value: 'xyz' },\n * appName: 'my-app'\n * },\n * {\n * // `value` is typed as { value: string } (without `type`)\n * secret: (key, value) => ({ [key]: value.value }),\n * }\n * ).build();\n * // { API_KEY: 'xyz', APP_NAME: 'my-app' }\n * ```\n */\nexport class EnvironmentBuilder<\n\tTRecord extends Record<string, InputValue> = Record<string, InputValue>,\n\tTResolvers extends Resolvers = TypedResolvers<TRecord>,\n> {\n\tprivate readonly record: TRecord;\n\tprivate readonly resolvers: TResolvers;\n\tprivate readonly options: Required<EnvironmentBuilderOptions>;\n\n\tconstructor(\n\t\trecord: TRecord,\n\t\tresolvers: TResolvers,\n\t\toptions: EnvironmentBuilderOptions = {},\n\t) {\n\t\tthis.record = record;\n\t\tthis.resolvers = resolvers;\n\t\tthis.options = {\n\t\t\tonUnmatchedValue: options.onUnmatchedValue ?? ((_key, _value) => {}),\n\t\t};\n\t}\n\n\t/**\n\t * Build environment variables from the input record.\n\t *\n\t * - Plain string values are passed through with key transformation\n\t * - Object values with a `type` property are matched against resolvers\n\t * - Resolvers receive values without the `type` key\n\t * - Only root-level keys are transformed to UPPER_SNAKE_CASE\n\t *\n\t * @returns A record of environment variables\n\t */\n\tbuild(): EnvRecord {\n\t\tconst env: EnvRecord = {};\n\n\t\tfor (const [key, value] of Object.entries(this.record)) {\n\t\t\t// Handle plain string values\n\t\t\tif (typeof value === 'string') {\n\t\t\t\tenv[environmentCase(key)] = value;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Handle objects with type discriminator\n\t\t\tconst { type, ...rest } = value;\n\t\t\tconst resolver = this.resolvers[type];\n\t\t\tif (resolver) {\n\t\t\t\tconst resolved = resolver(key, rest);\n\t\t\t\t// Transform only root-level keys from resolver output\n\t\t\t\tfor (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {\n\t\t\t\t\tenv[environmentCase(resolvedKey)] = resolvedValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.options.onUnmatchedValue(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn env;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;AAaA,SAAgB,gBAAgBA,MAAsB;AACrD,QAAO,8BAAU,KAAK,CACpB,aAAa,CACb,QAAQ,SAAS,CAAC,MAAM;AACxB,SAAO,EAAE,QAAQ,KAAK,GAAG;CACzB,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;AAoHD,IAAa,qBAAb,MAGE;CACD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACCC,QACAC,WACAC,UAAqC,CAAE,GACtC;AACD,OAAK,SAAS;AACd,OAAK,YAAY;AACjB,OAAK,UAAU,EACd,kBAAkB,QAAQ,qBAAqB,CAAC,MAAM,WAAW,CAAE,GACnE;CACD;;;;;;;;;;;CAYD,QAAmB;EAClB,MAAMC,MAAiB,CAAE;AAEzB,OAAK,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,OAAO,EAAE;AAEvD,cAAW,UAAU,UAAU;AAC9B,QAAI,gBAAgB,IAAI,IAAI;AAC5B;GACA;GAGD,MAAM,EAAE,KAAM,GAAG,MAAM,GAAG;GAC1B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,UAAU;IACb,MAAM,WAAW,SAAS,KAAK,KAAK;AAEpC,SAAK,MAAM,CAAC,aAAa,cAAc,IAAI,OAAO,QAAQ,SAAS,CAClE,KAAI,gBAAgB,YAAY,IAAI;GAErC,MACA,MAAK,QAAQ,iBAAiB,KAAK,MAAM;EAE1C;AAED,SAAO;CACP;AACD"}
@@ -128,4 +128,4 @@ declare class EnvironmentBuilder<TRecord extends Record<string, InputValue> = Re
128
128
  }
129
129
  //#endregion
130
130
  export { EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase };
131
- //# sourceMappingURL=EnvironmentBuilder-jF-b7WQg.d.mts.map
131
+ //# sourceMappingURL=EnvironmentBuilder-DHfDXJUm.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentBuilder-jF-b7WQg.d.mts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
1
+ {"version":3,"file":"EnvironmentBuilder-DHfDXJUm.d.mts","names":[],"sources":["../src/EnvironmentBuilder.ts"],"sourcesContent":[],"mappings":";;AAaA;AAYA;AAQA;AAUA;;;;AAA+E;AAK/E;;AAAuC,iBAnCvB,eAAA,CAmCuB,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;AAAT;AAK9B;AAWA;AAKY,UA5CK,SAAA,CA4CU;EAQtB,CAAA,GAAA,EAAA,MAAA,CAAA,EAnDW,QAmDA;;;;AAAoD;AAAA;AAKvD,KAjDD,QAAA,GAiDC,MAAA,GAAA,MAAA,GAAA,OAAA,GAjDsC,SAiDtC;;;;AAAuC;AAAA;;;;AAMvC,KA7CD,mBA6CC,CAAA,IAAA,GAAA,CAAA,GAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EA7CmD,CA6CnD,EAAA,GA7CyD,SA6CzD;;;;AACL,KAzCI,SAAA,GAAY,MAyChB,CAAA,MAAA,EAzC+B,mBAyC/B,CAAA,GAAA,CAAA,CAAA;AAAO;AAAA;;AAMiB,UA1Cf,yBAAA,CA0Ce;EAAU;;;;EAGV,gBAAkB,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;;;;;AAGnC,KArCH,UAAA,GAqCG,MAAA,GAAA;EAMH,IAAA,EAAA,MAAA;EAAc,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;CAAA;;;;AAEX,KAxCH,eAwCG,CAAA,cAAA,MAAA,GAAA,MAAA,CAAA,GAAA;EAAO,IAAE,EAvCjB,KAuCiB;EAAK,CAAA,GAA3B,EAAA,MAAA,CAAA,EAAA,OAAA;CAAY;AADyC;AA2BvD;;KA1DK,WA2D2B,CAAA,CAAA,CAAA,GA3DV,CA2DU,SAAA;EAAU,IAAzB,EAAA,KAAA,WAAA,MAAA;CAAM,GA3D4C,CA2D5C,GAAsC,KAAA;;;;KAtDxD,QAuD2B,CAAA,CAAA,CAAA,GAvDb,CAuDa,SAAA;EAAc,IAOpC,EAAA,MAAA;CAAO,GA9D+B,IA+DnC,CA/DwC,CA+DxC,EAAA,MAAA,CAAA,GAAA,KAAA;;;AAoBM;KA9Ed,8BAA8B,eAAe,6BACrC,UAAU,YAAY,QAAQ,YACnC;;;;KAKH,6BACY,eAAe,mDAGnB,UAAU,QAAQ;QAAmB;IAC9C,SAAS,QAAQ,oBAEb;;;;;KAMI,+BAA+B,eAAe,2BAC/C,cAAc,WAAW,oBAClC,aAAa,SAAS;;;;;;;;;;;;;;;;;;;;;;;cA0BX,mCACI,eAAe,cAAc,eAAe,gCACzC,YAAY,eAAe;;;;sBAOrC,oBACG,sBACF;;;;;;;;;;;WAmBD"}
@@ -135,7 +135,7 @@ type EnvFetcher<TPath extends string = string> = (name: TPath) => typeof z;
135
135
  * @param get - The environment variable fetcher function
136
136
  * @returns The configuration object with Zod schemas
137
137
  */
138
- type EnvironmentBuilder<TResponse extends EmptyObject> = (get: EnvFetcher) => TResponse;
138
+
139
139
  /**
140
140
  * Type alias for a generic object with unknown values.
141
141
  * Used as a constraint for configuration objects.
@@ -143,5 +143,5 @@ type EnvironmentBuilder<TResponse extends EmptyObject> = (get: EnvFetcher) => TR
143
143
  type EmptyObject = Record<string | number | symbol, unknown>;
144
144
  //# sourceMappingURL=EnvironmentParser.d.ts.map
145
145
  //#endregion
146
- export { ConfigParser, EmptyObject, EnvFetcher, EnvironmentBuilder, EnvironmentParser, InferConfig };
147
- //# sourceMappingURL=EnvironmentParser-DtOL86NU.d.cts.map
146
+ export { ConfigParser, EmptyObject, EnvFetcher, EnvironmentParser, InferConfig };
147
+ //# sourceMappingURL=EnvironmentParser-BY1oCUsc.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvironmentParser-BY1oCUsc.d.mts","names":[],"sources":["../src/EnvironmentParser.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;;;;AAS4B,cATf,YASe,CAAA,kBATgB,WAShB,CAAA,CAAA;EAAG,iBAMT,MAAA;EAAS,iBAArB,OAAA;EAAW;AA2FrB;;;;;EAiJmC,WAClB,CAAA,MAAA,EApPU,SAoPV,EAAA,OAAA,CAAA,EAnPW,GAmPX,CAAA,MAAA,CAAA;EAAU;;;AACX;EA6BJ,KAAA,CAAA,CAAA,EA3QF,WA2Qa,CA3QD,SA2QC,CAAA;EAAA;;;;;;;;;;;;;;;;EAKjB,uBAAC,CAAA,CAAA,EAAA,MAAA,EAAA;AAAC;AAWR;;;;AAEa;AAkBb;;;;;;;;;;;;;;cApNa,4BAA4B;;;;;;;;;;;sBAWH;;;;;;;;;;;;;;;;;;;;;;;;yBAsId,4BACP,eAAe,UAC5B,aAAa;;;;;;;;;;;;;;;;;;;;;;KA6BL,sBAAsB,6BACrB,IAAI,EAAE,WAAW,CAAA,CAAE,YAC5B,CAAA,CAAE,MAAM,EAAE,MACV,EAAE,WAAW,0BACZ,YAAY,EAAE,MACd,EAAE;;;;;;;;;KAWK,mDACL,iBACK;;;;;;;;;;;;;;KAkBA,WAAA,GAAc"}
@@ -1,9 +1,117 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_formatter = require('./formatter-HxePpSy2.cjs');
2
+ const zod_v4 = require_chunk.__toESM(require("zod/v4"));
3
3
  const lodash_get = require_chunk.__toESM(require("lodash.get"));
4
4
  const lodash_set = require_chunk.__toESM(require("lodash.set"));
5
- const zod_v4 = require_chunk.__toESM(require("zod/v4"));
6
5
 
6
+ //#region src/formatter.ts
7
+ /**
8
+ * ANSI color codes for terminal output.
9
+ */
10
+ const colors = {
11
+ reset: "\x1B[0m",
12
+ red: "\x1B[31m",
13
+ yellow: "\x1B[33m",
14
+ cyan: "\x1B[36m",
15
+ dim: "\x1B[2m",
16
+ bold: "\x1B[1m"
17
+ };
18
+ /**
19
+ * Formats a ZodError into a user-friendly string for development.
20
+ *
21
+ * @param error - The ZodError to format
22
+ * @param options - Formatting options
23
+ * @returns Formatted error message
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * try {
28
+ * config.parse();
29
+ * } catch (error) {
30
+ * if (error instanceof ZodError) {
31
+ * console.error(formatParseError(error));
32
+ * }
33
+ * }
34
+ * ```
35
+ *
36
+ * Output:
37
+ * ```
38
+ * Environment Configuration Failed
39
+ *
40
+ * Missing Variables:
41
+ * DATABASE_URL - Required
42
+ * JWT_SECRET - Required
43
+ *
44
+ * Invalid Values:
45
+ * NODE_ENV = "invalid"
46
+ * Expected: "development" | "staging" | "production"
47
+ * ```
48
+ */
49
+ function formatParseError(error, options = {}) {
50
+ const useColors = options.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);
51
+ const c = useColors ? colors : {
52
+ reset: "",
53
+ red: "",
54
+ yellow: "",
55
+ cyan: "",
56
+ dim: "",
57
+ bold: ""
58
+ };
59
+ const missingVars = [];
60
+ const invalidVars = [];
61
+ for (const issue of error.issues) {
62
+ let envName = "";
63
+ if (issue.path.length > 0) envName = issue.path.map(String).join(".");
64
+ else {
65
+ const match = issue.message.match(/Environment variable "([^"]+)"/);
66
+ if (match?.[1]) envName = match[1];
67
+ }
68
+ const received = "received" in issue ? issue.received : void 0;
69
+ const isMissing = issue.code === "invalid_type" && (received === "undefined" || received === "null");
70
+ if (isMissing) missingVars.push({
71
+ name: envName || "Unknown",
72
+ message: cleanMessage(issue.message)
73
+ });
74
+ else invalidVars.push({
75
+ name: envName || "Unknown",
76
+ value: received,
77
+ message: cleanMessage(issue.message)
78
+ });
79
+ }
80
+ const lines = [];
81
+ lines.push("");
82
+ lines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);
83
+ lines.push("");
84
+ if (missingVars.length > 0) {
85
+ lines.push(`${c.yellow}Missing Variables:${c.reset}`);
86
+ for (const v of missingVars) lines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);
87
+ lines.push("");
88
+ }
89
+ if (invalidVars.length > 0) {
90
+ lines.push(`${c.yellow}Invalid Values:${c.reset}`);
91
+ for (const v of invalidVars) {
92
+ const valueStr = v.value !== void 0 ? ` = ${JSON.stringify(v.value)}` : "";
93
+ lines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);
94
+ lines.push(` ${c.dim}${v.message}${c.reset}`);
95
+ }
96
+ lines.push("");
97
+ }
98
+ return lines.join("\n");
99
+ }
100
+ /**
101
+ * Cleans up a Zod error message by removing redundant prefixes.
102
+ */
103
+ function cleanMessage(message) {
104
+ return message.replace(/^Environment variable "[^"]+": /, "");
105
+ }
106
+ /**
107
+ * Checks if the current environment is development.
108
+ */
109
+ function isDevelopment() {
110
+ const nodeEnv = process.env.NODE_ENV?.toLowerCase();
111
+ return nodeEnv == null || nodeEnv === "development" || nodeEnv === "dev";
112
+ }
113
+
114
+ //#endregion
7
115
  //#region src/EnvironmentParser.ts
8
116
  /**
9
117
  * Parses and validates configuration objects against Zod schemas.
@@ -48,7 +156,7 @@ var ConfigParser = class {
48
156
  const parsedConfig = parseDeep(this.config);
49
157
  if (errors.length > 0) {
50
158
  const zodError = new zod_v4.z.ZodError(errors);
51
- if (require_formatter.isDevelopment()) console.error(require_formatter.formatParseError(zodError));
159
+ if (isDevelopment()) console.error(formatParseError(zodError));
52
160
  throw zodError;
53
161
  }
54
162
  return parsedConfig;
@@ -223,4 +331,16 @@ Object.defineProperty(exports, 'EnvironmentParser', {
223
331
  return EnvironmentParser;
224
332
  }
225
333
  });
226
- //# sourceMappingURL=EnvironmentParser-DJdW7vOL.cjs.map
334
+ Object.defineProperty(exports, 'formatParseError', {
335
+ enumerable: true,
336
+ get: function () {
337
+ return formatParseError;
338
+ }
339
+ });
340
+ Object.defineProperty(exports, 'isDevelopment', {
341
+ enumerable: true,
342
+ get: function () {
343
+ return isDevelopment;
344
+ }
345
+ });
346
+ //# sourceMappingURL=EnvironmentParser-Bzg5yXG2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvironmentParser-Bzg5yXG2.cjs","names":["error: z.ZodError","options: FormatOptions","missingVars: Array<{ name: string; message: string }>","invalidVars: Array<{ name: string; value: unknown; message: string }>","lines: string[]","message: string","config: TResponse","envVars: Set<string>","errors: z.core.$ZodIssue[]","config: T","path: string[]","result: EmptyObject","z","schema: z.ZodType","name: string","issue: z.core.$ZodIssue","builder: (get: EnvFetcher) => TReturn"],"sources":["../src/formatter.ts","../src/EnvironmentParser.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\n/**\n * Options for formatting parse errors.\n */\nexport interface FormatOptions {\n\t/** Whether to use colors in output. Defaults to auto-detect TTY. */\n\tcolors?: boolean;\n}\n\n/**\n * ANSI color codes for terminal output.\n */\nconst colors = {\n\treset: '\\x1b[0m',\n\tred: '\\x1b[31m',\n\tyellow: '\\x1b[33m',\n\tcyan: '\\x1b[36m',\n\tdim: '\\x1b[2m',\n\tbold: '\\x1b[1m',\n};\n\n/**\n * Formats a ZodError into a user-friendly string for development.\n *\n * @param error - The ZodError to format\n * @param options - Formatting options\n * @returns Formatted error message\n *\n * @example\n * ```typescript\n * try {\n * config.parse();\n * } catch (error) {\n * if (error instanceof ZodError) {\n * console.error(formatParseError(error));\n * }\n * }\n * ```\n *\n * Output:\n * ```\n * Environment Configuration Failed\n *\n * Missing Variables:\n * DATABASE_URL - Required\n * JWT_SECRET - Required\n *\n * Invalid Values:\n * NODE_ENV = \"invalid\"\n * Expected: \"development\" | \"staging\" | \"production\"\n * ```\n */\nexport function formatParseError(\n\terror: z.ZodError,\n\toptions: FormatOptions = {},\n): string {\n\tconst useColors =\n\t\toptions.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);\n\n\tconst c = useColors\n\t\t? colors\n\t\t: { reset: '', red: '', yellow: '', cyan: '', dim: '', bold: '' };\n\n\tconst missingVars: Array<{ name: string; message: string }> = [];\n\tconst invalidVars: Array<{ name: string; value: unknown; message: string }> =\n\t\t[];\n\n\tfor (const issue of error.issues) {\n\t\t// Extract environment variable name from path or message\n\t\tlet envName = '';\n\t\tif (issue.path.length > 0) {\n\t\t\t// Join the full path with '.' to show nested config keys and env var name\n\t\t\tenvName = issue.path.map(String).join('.');\n\t\t} else {\n\t\t\t// Try to extract from message like 'Environment variable \"NAME\": ...'\n\t\t\tconst match = issue.message.match(/Environment variable \"([^\"]+)\"/);\n\t\t\tif (match?.[1]) {\n\t\t\t\tenvName = match[1];\n\t\t\t}\n\t\t}\n\n\t\t// Determine if this is a missing or invalid value\n\t\t// Use type guard for received property\n\t\tconst received = 'received' in issue ? issue.received : undefined;\n\t\tconst isMissing =\n\t\t\tissue.code === 'invalid_type' &&\n\t\t\t(received === 'undefined' || received === 'null');\n\n\t\tif (isMissing) {\n\t\t\tmissingVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t} else {\n\t\t\tinvalidVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tvalue: received,\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst lines: string[] = [];\n\n\tlines.push('');\n\tlines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);\n\tlines.push('');\n\n\tif (missingVars.length > 0) {\n\t\tlines.push(`${c.yellow}Missing Variables:${c.reset}`);\n\t\tfor (const v of missingVars) {\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\tif (invalidVars.length > 0) {\n\t\tlines.push(`${c.yellow}Invalid Values:${c.reset}`);\n\t\tfor (const v of invalidVars) {\n\t\t\tconst valueStr =\n\t\t\t\tv.value !== undefined ? ` = ${JSON.stringify(v.value)}` : '';\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);\n\t\t\tlines.push(` ${c.dim}${v.message}${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Cleans up a Zod error message by removing redundant prefixes.\n */\nfunction cleanMessage(message: string): string {\n\t// Remove \"Environment variable \"NAME\": \" prefix if present\n\treturn message.replace(/^Environment variable \"[^\"]+\": /, '');\n}\n\n/**\n * Checks if the current environment is development.\n */\nexport function isDevelopment(): boolean {\n\tconst nodeEnv = process.env.NODE_ENV?.toLowerCase();\n\treturn nodeEnv == null || nodeEnv === 'development' || nodeEnv === 'dev';\n}\n","import get from 'lodash.get';\nimport set from 'lodash.set';\nimport { z } from 'zod/v4';\nimport { formatParseError, isDevelopment } from './formatter.js';\n\n/**\n * Parses and validates configuration objects against Zod schemas.\n * Handles nested configurations and aggregates validation errors.\n *\n * @template TResponse - The shape of the configuration object\n */\nexport class ConfigParser<TResponse extends EmptyObject> {\n\t/**\n\t * Creates a new ConfigParser instance.\n\t *\n\t * @param config - The configuration object to parse\n\t * @param envVars - Set of environment variable names that were accessed\n\t */\n\tconstructor(\n\t\tprivate readonly config: TResponse,\n\t\tprivate readonly envVars: Set<string> = new Set(),\n\t) {}\n\t/**\n\t * Parses the config object and validates it against the Zod schemas\n\t * @returns The parsed config object\n\t */\n\tparse(): InferConfig<TResponse> {\n\t\tconst errors: z.core.$ZodIssue[] = [];\n\n\t\tconst parseDeep = <T>(config: T, path: string[] = []) => {\n\t\t\tconst result: EmptyObject = {};\n\n\t\t\tif (config && typeof config !== 'object') {\n\t\t\t\treturn config;\n\t\t\t}\n\n\t\t\tfor (const key in config) {\n\t\t\t\tconst schema = config[key];\n\t\t\t\tconst currentPath = [...path, key];\n\n\t\t\t\tif (schema instanceof z.ZodType) {\n\t\t\t\t\tconst parsed = schema.safeParse(undefined);\n\t\t\t\t\tif (parsed.success) {\n\t\t\t\t\t\tset(result, key, parsed.data);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the schema is invalid, assign the error\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t...parsed.error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\tpath: [...currentPath, ...(issue.path as string[])],\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (schema) {\n\t\t\t\t\tset(result, key, parseDeep(schema as EmptyObject, currentPath));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\n\t\tconst parsedConfig = parseDeep(\n\t\t\tthis.config,\n\t\t) as unknown as InferConfig<TResponse>;\n\n\t\tif (errors.length > 0) {\n\t\t\tconst zodError = new z.ZodError(errors);\n\t\t\t// In development, log a formatted error message before throwing\n\t\t\tif (isDevelopment()) {\n\t\t\t\tconsole.error(formatParseError(zodError));\n\t\t\t}\n\t\t\tthrow zodError;\n\t\t}\n\n\t\treturn parsedConfig;\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed during config creation.\n\t * This is useful for deployment and configuration management to know which env vars are required.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = envParser.create((get) => ({\n\t * dbUrl: get('DATABASE_URL').string(),\n\t * port: get('PORT').number()\n\t * }));\n\t *\n\t * config.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.envVars).sort();\n\t}\n}\n\n/**\n * Parses environment variables with type-safe validation using Zod schemas.\n * Provides a fluent API for defining environment variable schemas with automatic\n * error context enrichment.\n *\n * @template T - The type of the configuration object (typically process.env)\n *\n * @example\n * ```typescript\n * const config = new EnvironmentParser(process.env)\n * .create((get) => ({\n * port: get('PORT').string().transform(Number).default(3000),\n * database: {\n * url: get('DATABASE_URL').string().url()\n * }\n * }))\n * .parse();\n * ```\n */\nexport class EnvironmentParser<T extends EmptyObject> {\n\t/**\n\t * Set to track which environment variable names have been accessed\n\t */\n\tprivate readonly accessedVars: Set<string> = new Set();\n\n\t/**\n\t * Creates a new EnvironmentParser instance.\n\t *\n\t * @param config - The configuration object to parse (typically process.env)\n\t */\n\tconstructor(private readonly config: T) {}\n\n\t/**\n\t * Wraps a Zod schema to intercept parse/safeParse calls and enrich error messages\n\t * with environment variable context.\n\t *\n\t * @param schema - The Zod schema to wrap\n\t * @param name - The environment variable name for error context\n\t * @returns A wrapped Zod schema with enhanced error reporting\n\t */\n\tprivate wrapSchema = (schema: z.ZodType, name: string): z.ZodType => {\n\t\t// Create a proxy that intercepts all method calls on the schema\n\t\treturn new Proxy(schema, {\n\t\t\tget: (target, prop) => {\n\t\t\t\tif (prop === 'parse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn target.parse(value);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\t\tconst modifiedIssues = error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\t\tthrow new z.ZodError(modifiedIssues);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (prop === 'safeParse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\tconst result = target.safeParse(value);\n\n\t\t\t\t\t\tif (!result.success) {\n\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\tconst modifiedIssues = result.error.issues.map(\n\t\t\t\t\t\t\t\t(issue: z.core.$ZodIssue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tsuccess: false as const,\n\t\t\t\t\t\t\t\terror: new z.ZodError(modifiedIssues),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// For any method that returns a new schema (like transform, optional, etc.),\n\t\t\t\t// wrap the result as well\n\t\t\t\tconst originalProp = target[prop as keyof typeof target];\n\t\t\t\tif (typeof originalProp === 'function') {\n\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\tconst result = originalProp.apply(target, args);\n\t\t\t\t\t\t// If the result is a ZodType, wrap it too\n\t\t\t\t\t\tif (result && typeof result === 'object' && 'parse' in result) {\n\t\t\t\t\t\t\treturn this.wrapSchema(result, name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn originalProp;\n\t\t\t},\n\t\t});\n\t};\n\n\t/**\n\t * Creates a proxied version of the Zod object that wraps all schema creators\n\t * to provide enhanced error messages with environment variable context.\n\t *\n\t * @param name - The environment variable name\n\t * @returns A proxied Zod object with wrapped schema creators\n\t */\n\tprivate getZodGetter = (name: string) => {\n\t\t// Track that this environment variable was accessed\n\t\tthis.accessedVars.add(name);\n\n\t\t// Return an object that has all Zod schemas but with our wrapper\n\t\treturn new Proxy(\n\t\t\t{ ...z },\n\t\t\t{\n\t\t\t\tget: (target, prop) => {\n\t\t\t\t\t// deno-lint-ignore ban-ts-comment\n\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\tconst value = target[prop];\n\n\t\t\t\t\tif (typeof value === 'function') {\n\t\t\t\t\t\t// Return a wrapper around each Zod schema creator\n\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\tconst schema = value(...args);\n\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Handle objects like z.coerce\n\t\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\t\treturn new Proxy(value, {\n\t\t\t\t\t\t\tget: (nestedTarget, nestedProp) => {\n\t\t\t\t\t\t\t\tconst nestedValue =\n\t\t\t\t\t\t\t\t\tnestedTarget[nestedProp as keyof typeof nestedTarget];\n\t\t\t\t\t\t\t\tif (typeof nestedValue === 'function') {\n\t\t\t\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\t\t\t\tconst schema = nestedValue(...args);\n\t\t\t\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn nestedValue;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn value;\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t};\n\n\t/**\n\t * Creates a new ConfigParser object that can be used to parse the config object\n\t *\n\t * @param builder - A function that takes a getter function and returns a config object\n\t * @returns A ConfigParser object that can be used to parse the config object\n\t */\n\tcreate<TReturn extends EmptyObject>(\n\t\tbuilder: (get: EnvFetcher) => TReturn,\n\t): ConfigParser<TReturn> {\n\t\tconst config = builder(this.getZodGetter);\n\t\treturn new ConfigParser(config, this.accessedVars);\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed via the getter.\n\t * This is useful for build-time analysis to determine which env vars a service needs.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const sniffer = new EnvironmentParser({});\n\t * service.register(sniffer);\n\t * const envVars = sniffer.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.accessedVars).sort();\n\t}\n}\n\n/**\n * Infers the TypeScript type of a configuration object based on its Zod schemas.\n * Recursively processes nested objects and extracts types from Zod schemas.\n *\n * @template T - The configuration object type\n */\nexport type InferConfig<T extends EmptyObject> = {\n\t[K in keyof T]: T[K] extends z.ZodSchema\n\t\t? z.infer<T[K]>\n\t\t: T[K] extends Record<string, unknown>\n\t\t\t? InferConfig<T[K]>\n\t\t\t: T[K];\n};\n\n/**\n * Function type for fetching environment variables with Zod validation.\n * Returns a Zod object scoped to a specific environment variable.\n *\n * @template TPath - The environment variable path type\n * @param name - The environment variable name\n * @returns A Zod object for defining the schema\n */\nexport type EnvFetcher<TPath extends string = string> = (\n\tname: TPath,\n) => typeof z;\n\n/**\n * Function type for building environment configuration objects.\n * Takes an EnvFetcher and returns a configuration object with Zod schemas.\n *\n * @template TResponse - The response configuration object type\n * @param get - The environment variable fetcher function\n * @returns The configuration object with Zod schemas\n */\nexport type EnvironmentBuilder<TResponse extends EmptyObject> = (\n\tget: EnvFetcher,\n) => TResponse;\n\n/**\n * Type alias for a generic object with unknown values.\n * Used as a constraint for configuration objects.\n */\nexport type EmptyObject = Record<string | number | symbol, unknown>;\n"],"mappings":"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"}
@@ -135,7 +135,7 @@ type EnvFetcher<TPath extends string = string> = (name: TPath) => typeof z;
135
135
  * @param get - The environment variable fetcher function
136
136
  * @returns The configuration object with Zod schemas
137
137
  */
138
- type EnvironmentBuilder<TResponse extends EmptyObject> = (get: EnvFetcher) => TResponse;
138
+
139
139
  /**
140
140
  * Type alias for a generic object with unknown values.
141
141
  * Used as a constraint for configuration objects.
@@ -143,5 +143,5 @@ type EnvironmentBuilder<TResponse extends EmptyObject> = (get: EnvFetcher) => TR
143
143
  type EmptyObject = Record<string | number | symbol, unknown>;
144
144
  //# sourceMappingURL=EnvironmentParser.d.ts.map
145
145
  //#endregion
146
- export { ConfigParser, EmptyObject, EnvFetcher, EnvironmentBuilder, EnvironmentParser, InferConfig };
147
- //# sourceMappingURL=EnvironmentParser-CkLfmn4Y.d.mts.map
146
+ export { ConfigParser, EmptyObject, EnvFetcher, EnvironmentParser, InferConfig };
147
+ //# sourceMappingURL=EnvironmentParser-DoooZm8n.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvironmentParser-DoooZm8n.d.cts","names":[],"sources":["../src/EnvironmentParser.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;;;;AAS4B,cATf,YASe,CAAA,kBATgB,WAShB,CAAA,CAAA;EAAG,iBAMT,MAAA;EAAS,iBAArB,OAAA;EAAW;AA2FrB;;;;;EAiJmC,WAClB,CAAA,MAAA,EApPU,SAoPV,EAAA,OAAA,CAAA,EAnPW,GAmPX,CAAA,MAAA,CAAA;EAAU;;;AACX;EA6BJ,KAAA,CAAA,CAAA,EA3QF,WA2Qa,CA3QD,SA2QC,CAAA;EAAA;;;;;;;;;;;;;;;;EAKjB,uBAAC,CAAA,CAAA,EAAA,MAAA,EAAA;AAAC;AAWR;;;;AAEa;AAkBb;;;;;;;;;;;;;;cApNa,4BAA4B;;;;;;;;;;;sBAWH;;;;;;;;;;;;;;;;;;;;;;;;yBAsId,4BACP,eAAe,UAC5B,aAAa;;;;;;;;;;;;;;;;;;;;;;KA6BL,sBAAsB,6BACrB,IAAI,EAAE,WAAW,CAAA,CAAE,YAC5B,CAAA,CAAE,MAAM,EAAE,MACV,EAAE,WAAW,0BACZ,YAAY,EAAE,MACd,EAAE;;;;;;;;;KAWK,mDACL,iBACK;;;;;;;;;;;;;;KAkBA,WAAA,GAAc"}
@@ -1,8 +1,116 @@
1
- import { formatParseError, isDevelopment } from "./formatter-BRRrxQi3.mjs";
1
+ import { z } from "zod/v4";
2
2
  import get from "lodash.get";
3
3
  import set from "lodash.set";
4
- import { z } from "zod/v4";
5
4
 
5
+ //#region src/formatter.ts
6
+ /**
7
+ * ANSI color codes for terminal output.
8
+ */
9
+ const colors = {
10
+ reset: "\x1B[0m",
11
+ red: "\x1B[31m",
12
+ yellow: "\x1B[33m",
13
+ cyan: "\x1B[36m",
14
+ dim: "\x1B[2m",
15
+ bold: "\x1B[1m"
16
+ };
17
+ /**
18
+ * Formats a ZodError into a user-friendly string for development.
19
+ *
20
+ * @param error - The ZodError to format
21
+ * @param options - Formatting options
22
+ * @returns Formatted error message
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * try {
27
+ * config.parse();
28
+ * } catch (error) {
29
+ * if (error instanceof ZodError) {
30
+ * console.error(formatParseError(error));
31
+ * }
32
+ * }
33
+ * ```
34
+ *
35
+ * Output:
36
+ * ```
37
+ * Environment Configuration Failed
38
+ *
39
+ * Missing Variables:
40
+ * DATABASE_URL - Required
41
+ * JWT_SECRET - Required
42
+ *
43
+ * Invalid Values:
44
+ * NODE_ENV = "invalid"
45
+ * Expected: "development" | "staging" | "production"
46
+ * ```
47
+ */
48
+ function formatParseError(error, options = {}) {
49
+ const useColors = options.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);
50
+ const c = useColors ? colors : {
51
+ reset: "",
52
+ red: "",
53
+ yellow: "",
54
+ cyan: "",
55
+ dim: "",
56
+ bold: ""
57
+ };
58
+ const missingVars = [];
59
+ const invalidVars = [];
60
+ for (const issue of error.issues) {
61
+ let envName = "";
62
+ if (issue.path.length > 0) envName = issue.path.map(String).join(".");
63
+ else {
64
+ const match = issue.message.match(/Environment variable "([^"]+)"/);
65
+ if (match?.[1]) envName = match[1];
66
+ }
67
+ const received = "received" in issue ? issue.received : void 0;
68
+ const isMissing = issue.code === "invalid_type" && (received === "undefined" || received === "null");
69
+ if (isMissing) missingVars.push({
70
+ name: envName || "Unknown",
71
+ message: cleanMessage(issue.message)
72
+ });
73
+ else invalidVars.push({
74
+ name: envName || "Unknown",
75
+ value: received,
76
+ message: cleanMessage(issue.message)
77
+ });
78
+ }
79
+ const lines = [];
80
+ lines.push("");
81
+ lines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);
82
+ lines.push("");
83
+ if (missingVars.length > 0) {
84
+ lines.push(`${c.yellow}Missing Variables:${c.reset}`);
85
+ for (const v of missingVars) lines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);
86
+ lines.push("");
87
+ }
88
+ if (invalidVars.length > 0) {
89
+ lines.push(`${c.yellow}Invalid Values:${c.reset}`);
90
+ for (const v of invalidVars) {
91
+ const valueStr = v.value !== void 0 ? ` = ${JSON.stringify(v.value)}` : "";
92
+ lines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);
93
+ lines.push(` ${c.dim}${v.message}${c.reset}`);
94
+ }
95
+ lines.push("");
96
+ }
97
+ return lines.join("\n");
98
+ }
99
+ /**
100
+ * Cleans up a Zod error message by removing redundant prefixes.
101
+ */
102
+ function cleanMessage(message) {
103
+ return message.replace(/^Environment variable "[^"]+": /, "");
104
+ }
105
+ /**
106
+ * Checks if the current environment is development.
107
+ */
108
+ function isDevelopment() {
109
+ const nodeEnv = process.env.NODE_ENV?.toLowerCase();
110
+ return nodeEnv == null || nodeEnv === "development" || nodeEnv === "dev";
111
+ }
112
+
113
+ //#endregion
6
114
  //#region src/EnvironmentParser.ts
7
115
  /**
8
116
  * Parses and validates configuration objects against Zod schemas.
@@ -210,5 +318,5 @@ var EnvironmentParser = class {
210
318
  };
211
319
 
212
320
  //#endregion
213
- export { ConfigParser, EnvironmentParser };
214
- //# sourceMappingURL=EnvironmentParser-zMblItla.mjs.map
321
+ export { ConfigParser, EnvironmentParser, formatParseError, isDevelopment };
322
+ //# sourceMappingURL=EnvironmentParser-taAKfzT7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvironmentParser-taAKfzT7.mjs","names":["error: z.ZodError","options: FormatOptions","missingVars: Array<{ name: string; message: string }>","invalidVars: Array<{ name: string; value: unknown; message: string }>","lines: string[]","message: string","config: TResponse","envVars: Set<string>","errors: z.core.$ZodIssue[]","config: T","path: string[]","result: EmptyObject","schema: z.ZodType","name: string","issue: z.core.$ZodIssue","builder: (get: EnvFetcher) => TReturn"],"sources":["../src/formatter.ts","../src/EnvironmentParser.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\n/**\n * Options for formatting parse errors.\n */\nexport interface FormatOptions {\n\t/** Whether to use colors in output. Defaults to auto-detect TTY. */\n\tcolors?: boolean;\n}\n\n/**\n * ANSI color codes for terminal output.\n */\nconst colors = {\n\treset: '\\x1b[0m',\n\tred: '\\x1b[31m',\n\tyellow: '\\x1b[33m',\n\tcyan: '\\x1b[36m',\n\tdim: '\\x1b[2m',\n\tbold: '\\x1b[1m',\n};\n\n/**\n * Formats a ZodError into a user-friendly string for development.\n *\n * @param error - The ZodError to format\n * @param options - Formatting options\n * @returns Formatted error message\n *\n * @example\n * ```typescript\n * try {\n * config.parse();\n * } catch (error) {\n * if (error instanceof ZodError) {\n * console.error(formatParseError(error));\n * }\n * }\n * ```\n *\n * Output:\n * ```\n * Environment Configuration Failed\n *\n * Missing Variables:\n * DATABASE_URL - Required\n * JWT_SECRET - Required\n *\n * Invalid Values:\n * NODE_ENV = \"invalid\"\n * Expected: \"development\" | \"staging\" | \"production\"\n * ```\n */\nexport function formatParseError(\n\terror: z.ZodError,\n\toptions: FormatOptions = {},\n): string {\n\tconst useColors =\n\t\toptions.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);\n\n\tconst c = useColors\n\t\t? colors\n\t\t: { reset: '', red: '', yellow: '', cyan: '', dim: '', bold: '' };\n\n\tconst missingVars: Array<{ name: string; message: string }> = [];\n\tconst invalidVars: Array<{ name: string; value: unknown; message: string }> =\n\t\t[];\n\n\tfor (const issue of error.issues) {\n\t\t// Extract environment variable name from path or message\n\t\tlet envName = '';\n\t\tif (issue.path.length > 0) {\n\t\t\t// Join the full path with '.' to show nested config keys and env var name\n\t\t\tenvName = issue.path.map(String).join('.');\n\t\t} else {\n\t\t\t// Try to extract from message like 'Environment variable \"NAME\": ...'\n\t\t\tconst match = issue.message.match(/Environment variable \"([^\"]+)\"/);\n\t\t\tif (match?.[1]) {\n\t\t\t\tenvName = match[1];\n\t\t\t}\n\t\t}\n\n\t\t// Determine if this is a missing or invalid value\n\t\t// Use type guard for received property\n\t\tconst received = 'received' in issue ? issue.received : undefined;\n\t\tconst isMissing =\n\t\t\tissue.code === 'invalid_type' &&\n\t\t\t(received === 'undefined' || received === 'null');\n\n\t\tif (isMissing) {\n\t\t\tmissingVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t} else {\n\t\t\tinvalidVars.push({\n\t\t\t\tname: envName || 'Unknown',\n\t\t\t\tvalue: received,\n\t\t\t\tmessage: cleanMessage(issue.message),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst lines: string[] = [];\n\n\tlines.push('');\n\tlines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);\n\tlines.push('');\n\n\tif (missingVars.length > 0) {\n\t\tlines.push(`${c.yellow}Missing Variables:${c.reset}`);\n\t\tfor (const v of missingVars) {\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\tif (invalidVars.length > 0) {\n\t\tlines.push(`${c.yellow}Invalid Values:${c.reset}`);\n\t\tfor (const v of invalidVars) {\n\t\t\tconst valueStr =\n\t\t\t\tv.value !== undefined ? ` = ${JSON.stringify(v.value)}` : '';\n\t\t\tlines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);\n\t\t\tlines.push(` ${c.dim}${v.message}${c.reset}`);\n\t\t}\n\t\tlines.push('');\n\t}\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Cleans up a Zod error message by removing redundant prefixes.\n */\nfunction cleanMessage(message: string): string {\n\t// Remove \"Environment variable \"NAME\": \" prefix if present\n\treturn message.replace(/^Environment variable \"[^\"]+\": /, '');\n}\n\n/**\n * Checks if the current environment is development.\n */\nexport function isDevelopment(): boolean {\n\tconst nodeEnv = process.env.NODE_ENV?.toLowerCase();\n\treturn nodeEnv == null || nodeEnv === 'development' || nodeEnv === 'dev';\n}\n","import get from 'lodash.get';\nimport set from 'lodash.set';\nimport { z } from 'zod/v4';\nimport { formatParseError, isDevelopment } from './formatter.js';\n\n/**\n * Parses and validates configuration objects against Zod schemas.\n * Handles nested configurations and aggregates validation errors.\n *\n * @template TResponse - The shape of the configuration object\n */\nexport class ConfigParser<TResponse extends EmptyObject> {\n\t/**\n\t * Creates a new ConfigParser instance.\n\t *\n\t * @param config - The configuration object to parse\n\t * @param envVars - Set of environment variable names that were accessed\n\t */\n\tconstructor(\n\t\tprivate readonly config: TResponse,\n\t\tprivate readonly envVars: Set<string> = new Set(),\n\t) {}\n\t/**\n\t * Parses the config object and validates it against the Zod schemas\n\t * @returns The parsed config object\n\t */\n\tparse(): InferConfig<TResponse> {\n\t\tconst errors: z.core.$ZodIssue[] = [];\n\n\t\tconst parseDeep = <T>(config: T, path: string[] = []) => {\n\t\t\tconst result: EmptyObject = {};\n\n\t\t\tif (config && typeof config !== 'object') {\n\t\t\t\treturn config;\n\t\t\t}\n\n\t\t\tfor (const key in config) {\n\t\t\t\tconst schema = config[key];\n\t\t\t\tconst currentPath = [...path, key];\n\n\t\t\t\tif (schema instanceof z.ZodType) {\n\t\t\t\t\tconst parsed = schema.safeParse(undefined);\n\t\t\t\t\tif (parsed.success) {\n\t\t\t\t\t\tset(result, key, parsed.data);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the schema is invalid, assign the error\n\t\t\t\t\t\terrors.push(\n\t\t\t\t\t\t\t...parsed.error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\tpath: [...currentPath, ...(issue.path as string[])],\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else if (schema) {\n\t\t\t\t\tset(result, key, parseDeep(schema as EmptyObject, currentPath));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\n\t\tconst parsedConfig = parseDeep(\n\t\t\tthis.config,\n\t\t) as unknown as InferConfig<TResponse>;\n\n\t\tif (errors.length > 0) {\n\t\t\tconst zodError = new z.ZodError(errors);\n\t\t\t// In development, log a formatted error message before throwing\n\t\t\tif (isDevelopment()) {\n\t\t\t\tconsole.error(formatParseError(zodError));\n\t\t\t}\n\t\t\tthrow zodError;\n\t\t}\n\n\t\treturn parsedConfig;\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed during config creation.\n\t * This is useful for deployment and configuration management to know which env vars are required.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = envParser.create((get) => ({\n\t * dbUrl: get('DATABASE_URL').string(),\n\t * port: get('PORT').number()\n\t * }));\n\t *\n\t * config.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.envVars).sort();\n\t}\n}\n\n/**\n * Parses environment variables with type-safe validation using Zod schemas.\n * Provides a fluent API for defining environment variable schemas with automatic\n * error context enrichment.\n *\n * @template T - The type of the configuration object (typically process.env)\n *\n * @example\n * ```typescript\n * const config = new EnvironmentParser(process.env)\n * .create((get) => ({\n * port: get('PORT').string().transform(Number).default(3000),\n * database: {\n * url: get('DATABASE_URL').string().url()\n * }\n * }))\n * .parse();\n * ```\n */\nexport class EnvironmentParser<T extends EmptyObject> {\n\t/**\n\t * Set to track which environment variable names have been accessed\n\t */\n\tprivate readonly accessedVars: Set<string> = new Set();\n\n\t/**\n\t * Creates a new EnvironmentParser instance.\n\t *\n\t * @param config - The configuration object to parse (typically process.env)\n\t */\n\tconstructor(private readonly config: T) {}\n\n\t/**\n\t * Wraps a Zod schema to intercept parse/safeParse calls and enrich error messages\n\t * with environment variable context.\n\t *\n\t * @param schema - The Zod schema to wrap\n\t * @param name - The environment variable name for error context\n\t * @returns A wrapped Zod schema with enhanced error reporting\n\t */\n\tprivate wrapSchema = (schema: z.ZodType, name: string): z.ZodType => {\n\t\t// Create a proxy that intercepts all method calls on the schema\n\t\treturn new Proxy(schema, {\n\t\t\tget: (target, prop) => {\n\t\t\t\tif (prop === 'parse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn target.parse(value);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\t\tconst modifiedIssues = error.issues.map((issue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\t\tthrow new z.ZodError(modifiedIssues);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (prop === 'safeParse') {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst value = get(this.config, name);\n\t\t\t\t\t\tconst result = target.safeParse(value);\n\n\t\t\t\t\t\tif (!result.success) {\n\t\t\t\t\t\t\t// Modify the error to include the environment variable name\n\t\t\t\t\t\t\tconst modifiedIssues = result.error.issues.map(\n\t\t\t\t\t\t\t\t(issue: z.core.$ZodIssue) => ({\n\t\t\t\t\t\t\t\t\t...issue,\n\t\t\t\t\t\t\t\t\tmessage: `Environment variable \"${name}\": ${issue.message}`,\n\t\t\t\t\t\t\t\t\tpath: [name, ...issue.path],\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tsuccess: false as const,\n\t\t\t\t\t\t\t\terror: new z.ZodError(modifiedIssues),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// For any method that returns a new schema (like transform, optional, etc.),\n\t\t\t\t// wrap the result as well\n\t\t\t\tconst originalProp = target[prop as keyof typeof target];\n\t\t\t\tif (typeof originalProp === 'function') {\n\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\tconst result = originalProp.apply(target, args);\n\t\t\t\t\t\t// If the result is a ZodType, wrap it too\n\t\t\t\t\t\tif (result && typeof result === 'object' && 'parse' in result) {\n\t\t\t\t\t\t\treturn this.wrapSchema(result, name);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn originalProp;\n\t\t\t},\n\t\t});\n\t};\n\n\t/**\n\t * Creates a proxied version of the Zod object that wraps all schema creators\n\t * to provide enhanced error messages with environment variable context.\n\t *\n\t * @param name - The environment variable name\n\t * @returns A proxied Zod object with wrapped schema creators\n\t */\n\tprivate getZodGetter = (name: string) => {\n\t\t// Track that this environment variable was accessed\n\t\tthis.accessedVars.add(name);\n\n\t\t// Return an object that has all Zod schemas but with our wrapper\n\t\treturn new Proxy(\n\t\t\t{ ...z },\n\t\t\t{\n\t\t\t\tget: (target, prop) => {\n\t\t\t\t\t// deno-lint-ignore ban-ts-comment\n\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\tconst value = target[prop];\n\n\t\t\t\t\tif (typeof value === 'function') {\n\t\t\t\t\t\t// Return a wrapper around each Zod schema creator\n\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\tconst schema = value(...args);\n\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Handle objects like z.coerce\n\t\t\t\t\tif (value && typeof value === 'object') {\n\t\t\t\t\t\treturn new Proxy(value, {\n\t\t\t\t\t\t\tget: (nestedTarget, nestedProp) => {\n\t\t\t\t\t\t\t\tconst nestedValue =\n\t\t\t\t\t\t\t\t\tnestedTarget[nestedProp as keyof typeof nestedTarget];\n\t\t\t\t\t\t\t\tif (typeof nestedValue === 'function') {\n\t\t\t\t\t\t\t\t\treturn (...args: any[]) => {\n\t\t\t\t\t\t\t\t\t\tconst schema = nestedValue(...args);\n\t\t\t\t\t\t\t\t\t\treturn this.wrapSchema(schema, name);\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn nestedValue;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn value;\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t};\n\n\t/**\n\t * Creates a new ConfigParser object that can be used to parse the config object\n\t *\n\t * @param builder - A function that takes a getter function and returns a config object\n\t * @returns A ConfigParser object that can be used to parse the config object\n\t */\n\tcreate<TReturn extends EmptyObject>(\n\t\tbuilder: (get: EnvFetcher) => TReturn,\n\t): ConfigParser<TReturn> {\n\t\tconst config = builder(this.getZodGetter);\n\t\treturn new ConfigParser(config, this.accessedVars);\n\t}\n\n\t/**\n\t * Returns an array of environment variable names that were accessed via the getter.\n\t * This is useful for build-time analysis to determine which env vars a service needs.\n\t *\n\t * @returns Array of environment variable names, sorted alphabetically\n\t *\n\t * @example\n\t * ```typescript\n\t * const sniffer = new EnvironmentParser({});\n\t * service.register(sniffer);\n\t * const envVars = sniffer.getEnvironmentVariables(); // ['DATABASE_URL', 'PORT']\n\t * ```\n\t */\n\tgetEnvironmentVariables(): string[] {\n\t\treturn Array.from(this.accessedVars).sort();\n\t}\n}\n\n/**\n * Infers the TypeScript type of a configuration object based on its Zod schemas.\n * Recursively processes nested objects and extracts types from Zod schemas.\n *\n * @template T - The configuration object type\n */\nexport type InferConfig<T extends EmptyObject> = {\n\t[K in keyof T]: T[K] extends z.ZodSchema\n\t\t? z.infer<T[K]>\n\t\t: T[K] extends Record<string, unknown>\n\t\t\t? InferConfig<T[K]>\n\t\t\t: T[K];\n};\n\n/**\n * Function type for fetching environment variables with Zod validation.\n * Returns a Zod object scoped to a specific environment variable.\n *\n * @template TPath - The environment variable path type\n * @param name - The environment variable name\n * @returns A Zod object for defining the schema\n */\nexport type EnvFetcher<TPath extends string = string> = (\n\tname: TPath,\n) => typeof z;\n\n/**\n * Function type for building environment configuration objects.\n * Takes an EnvFetcher and returns a configuration object with Zod schemas.\n *\n * @template TResponse - The response configuration object type\n * @param get - The environment variable fetcher function\n * @returns The configuration object with Zod schemas\n */\nexport type EnvironmentBuilder<TResponse extends EmptyObject> = (\n\tget: EnvFetcher,\n) => TResponse;\n\n/**\n * Type alias for a generic object with unknown values.\n * Used as a constraint for configuration objects.\n */\nexport type EmptyObject = Record<string | number | symbol, unknown>;\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- require('./formatter-HxePpSy2.cjs');
3
- const require_EnvironmentParser = require('./EnvironmentParser-DJdW7vOL.cjs');
2
+ const require_EnvironmentParser = require('./EnvironmentParser-Bzg5yXG2.cjs');
4
3
  const zod_v4 = require_chunk.__toESM(require("zod/v4"));
5
4
 
6
5
  //#region src/SnifferEnvironmentParser.ts
@@ -25,9 +24,11 @@ const zod_v4 = require_chunk.__toESM(require("zod/v4"));
25
24
  */
26
25
  var SnifferEnvironmentParser = class {
27
26
  accessedVars = /* @__PURE__ */ new Set();
27
+ optionalVars = /* @__PURE__ */ new Set();
28
28
  /**
29
29
  * Wraps a Zod schema to always return mock values.
30
30
  * This ensures .parse() and .safeParse() never fail.
31
+ * Also detects when .optional() or .default() is called to track optional vars.
31
32
  */
32
33
  wrapSchema = (schema, name) => {
33
34
  return new Proxy(schema, { get: (target, prop) => {
@@ -36,6 +37,7 @@ var SnifferEnvironmentParser = class {
36
37
  success: true,
37
38
  data: this.getMockValue(target)
38
39
  });
40
+ if (prop === "optional" || prop === "default") this.optionalVars.add(name);
39
41
  const originalProp = target[prop];
40
42
  if (typeof originalProp === "function") return (...args) => {
41
43
  const result = originalProp.apply(target, args);
@@ -93,9 +95,21 @@ var SnifferEnvironmentParser = class {
93
95
  }
94
96
  /**
95
97
  * Returns all environment variable names that were accessed.
98
+ *
99
+ * @param opts.markOptional - When true, optional variables (those accessed
100
+ * via `.optional()` or `.default()`) are suffixed with `?` (e.g. `PORT?`).
96
101
  */
97
- getEnvironmentVariables() {
98
- return Array.from(this.accessedVars).sort();
102
+ getEnvironmentVariables(opts) {
103
+ const vars = Array.from(this.accessedVars).sort();
104
+ if (!opts?.markOptional) return vars;
105
+ return vars.map((name) => this.optionalVars.has(name) ? `${name}?` : name);
106
+ }
107
+ /**
108
+ * Returns all environment variable names that were accessed via
109
+ * `.optional()` or `.default()` — i.e. variables that are not required.
110
+ */
111
+ getOptionalVariables() {
112
+ return Array.from(this.optionalVars).sort();
99
113
  }
100
114
  };
101
115
  /**
@@ -186,6 +200,7 @@ async function sniffWithFireAndForget(sniffer, operation, options = {}) {
186
200
  }
187
201
  return {
188
202
  envVars: sniffer.getEnvironmentVariables(),
203
+ optionalEnvVars: sniffer.getOptionalVariables(),
189
204
  error,
190
205
  unhandledRejections
191
206
  };