@geekmidas/envkit 0.3.0 → 0.5.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 (54) hide show
  1. package/dist/{EnvironmentBuilder-DHfDXJUm.d.mts → EnvironmentBuilder-jF-b7WQg.d.mts} +1 -1
  2. package/dist/{EnvironmentBuilder-DHfDXJUm.d.mts.map → EnvironmentBuilder-jF-b7WQg.d.mts.map} +1 -1
  3. package/dist/EnvironmentBuilder.d.mts +1 -1
  4. package/dist/{EnvironmentParser-c06agx31.mjs → EnvironmentParser-CBLsPUyQ.mjs} +7 -2
  5. package/dist/EnvironmentParser-CBLsPUyQ.mjs.map +1 -0
  6. package/dist/{EnvironmentParser-CY8TosTN.d.mts → EnvironmentParser-CkLfmn4Y.d.mts} +1 -1
  7. package/dist/{EnvironmentParser-CY8TosTN.d.mts.map → EnvironmentParser-CkLfmn4Y.d.mts.map} +1 -1
  8. package/dist/{EnvironmentParser-Bt246UeP.cjs → EnvironmentParser-DlWHnhDY.cjs} +7 -2
  9. package/dist/EnvironmentParser-DlWHnhDY.cjs.map +1 -0
  10. package/dist/EnvironmentParser-DtOL86NU.d.cts.map +1 -1
  11. package/dist/EnvironmentParser.cjs +2 -1
  12. package/dist/EnvironmentParser.d.mts +1 -1
  13. package/dist/EnvironmentParser.mjs +2 -1
  14. package/dist/SnifferEnvironmentParser.cjs +2 -1
  15. package/dist/SnifferEnvironmentParser.cjs.map +1 -1
  16. package/dist/SnifferEnvironmentParser.d.mts +1 -1
  17. package/dist/SnifferEnvironmentParser.mjs +2 -1
  18. package/dist/SnifferEnvironmentParser.mjs.map +1 -1
  19. package/dist/{SstEnvironmentBuilder-CjURMGjW.d.mts → SstEnvironmentBuilder-BZngSQKQ.d.mts} +2 -2
  20. package/dist/{SstEnvironmentBuilder-CjURMGjW.d.mts.map → SstEnvironmentBuilder-BZngSQKQ.d.mts.map} +1 -1
  21. package/dist/{SstEnvironmentBuilder-BEBFSUYr.mjs → SstEnvironmentBuilder-DVB7cJq4.mjs} +1 -1
  22. package/dist/{SstEnvironmentBuilder-BEBFSUYr.mjs.map → SstEnvironmentBuilder-DVB7cJq4.mjs.map} +1 -1
  23. package/dist/{SstEnvironmentBuilder-wFnN2M5O.cjs → SstEnvironmentBuilder-jsnqgtcW.cjs} +1 -1
  24. package/dist/{SstEnvironmentBuilder-wFnN2M5O.cjs.map → SstEnvironmentBuilder-jsnqgtcW.cjs.map} +1 -1
  25. package/dist/SstEnvironmentBuilder.cjs +1 -1
  26. package/dist/SstEnvironmentBuilder.d.mts +2 -2
  27. package/dist/SstEnvironmentBuilder.mjs +1 -1
  28. package/dist/formatter-Cox0NGxT.d.mts +51 -0
  29. package/dist/formatter-Cox0NGxT.d.mts.map +1 -0
  30. package/dist/formatter-D85aIkpd.d.cts +51 -0
  31. package/dist/formatter-D85aIkpd.d.cts.map +1 -0
  32. package/dist/formatter-fz8V7x6i.mjs +113 -0
  33. package/dist/formatter-fz8V7x6i.mjs.map +1 -0
  34. package/dist/formatter-w8Tsccw4.cjs +125 -0
  35. package/dist/formatter-w8Tsccw4.cjs.map +1 -0
  36. package/dist/formatter.cjs +4 -0
  37. package/dist/formatter.d.cts +2 -0
  38. package/dist/formatter.d.mts +2 -0
  39. package/dist/formatter.mjs +3 -0
  40. package/dist/index.cjs +5 -2
  41. package/dist/index.d.cts +2 -1
  42. package/dist/index.d.mts +4 -3
  43. package/dist/index.mjs +3 -2
  44. package/dist/sst.cjs +1 -1
  45. package/dist/sst.d.mts +2 -2
  46. package/dist/sst.mjs +1 -1
  47. package/package.json +1 -1
  48. package/src/EnvironmentParser.ts +7 -2
  49. package/src/__tests__/formatter.spec.ts +250 -0
  50. package/src/formatter.ts +147 -0
  51. package/src/index.ts +5 -0
  52. package/tsconfig.tsbuildinfo +1 -0
  53. package/dist/EnvironmentParser-Bt246UeP.cjs.map +0 -1
  54. package/dist/EnvironmentParser-c06agx31.mjs.map +0 -1
@@ -0,0 +1,113 @@
1
+ import { z } from "zod/v4";
2
+
3
+ //#region src/formatter.ts
4
+ /**
5
+ * ANSI color codes for terminal output.
6
+ */
7
+ const colors = {
8
+ reset: "\x1B[0m",
9
+ red: "\x1B[31m",
10
+ yellow: "\x1B[33m",
11
+ cyan: "\x1B[36m",
12
+ dim: "\x1B[2m",
13
+ bold: "\x1B[1m"
14
+ };
15
+ /**
16
+ * Formats a ZodError into a user-friendly string for development.
17
+ *
18
+ * @param error - The ZodError to format
19
+ * @param options - Formatting options
20
+ * @returns Formatted error message
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * try {
25
+ * config.parse();
26
+ * } catch (error) {
27
+ * if (error instanceof ZodError) {
28
+ * console.error(formatParseError(error));
29
+ * }
30
+ * }
31
+ * ```
32
+ *
33
+ * Output:
34
+ * ```
35
+ * Environment Configuration Failed
36
+ *
37
+ * Missing Variables:
38
+ * DATABASE_URL - Required
39
+ * JWT_SECRET - Required
40
+ *
41
+ * Invalid Values:
42
+ * NODE_ENV = "invalid"
43
+ * Expected: "development" | "staging" | "production"
44
+ * ```
45
+ */
46
+ function formatParseError(error, options = {}) {
47
+ const useColors = options.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);
48
+ const c = useColors ? colors : {
49
+ reset: "",
50
+ red: "",
51
+ yellow: "",
52
+ cyan: "",
53
+ dim: "",
54
+ bold: ""
55
+ };
56
+ const missingVars = [];
57
+ const invalidVars = [];
58
+ for (const issue of error.issues) {
59
+ let envName = "";
60
+ if (issue.path.length > 0) envName = String(issue.path[0]);
61
+ else {
62
+ const match = issue.message.match(/Environment variable "([^"]+)"/);
63
+ if (match?.[1]) envName = match[1];
64
+ }
65
+ const received = "received" in issue ? issue.received : void 0;
66
+ const isMissing = issue.code === "invalid_type" && (received === "undefined" || received === "null");
67
+ if (isMissing) missingVars.push({
68
+ name: envName || "Unknown",
69
+ message: cleanMessage(issue.message)
70
+ });
71
+ else invalidVars.push({
72
+ name: envName || "Unknown",
73
+ value: received,
74
+ message: cleanMessage(issue.message)
75
+ });
76
+ }
77
+ const lines = [];
78
+ lines.push("");
79
+ lines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);
80
+ lines.push("");
81
+ if (missingVars.length > 0) {
82
+ lines.push(`${c.yellow}Missing Variables:${c.reset}`);
83
+ for (const v of missingVars) lines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);
84
+ lines.push("");
85
+ }
86
+ if (invalidVars.length > 0) {
87
+ lines.push(`${c.yellow}Invalid Values:${c.reset}`);
88
+ for (const v of invalidVars) {
89
+ const valueStr = v.value !== void 0 ? ` = ${JSON.stringify(v.value)}` : "";
90
+ lines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);
91
+ lines.push(` ${c.dim}${v.message}${c.reset}`);
92
+ }
93
+ lines.push("");
94
+ }
95
+ return lines.join("\n");
96
+ }
97
+ /**
98
+ * Cleans up a Zod error message by removing redundant prefixes.
99
+ */
100
+ function cleanMessage(message) {
101
+ return message.replace(/^Environment variable "[^"]+": /, "");
102
+ }
103
+ /**
104
+ * Checks if the current environment is development.
105
+ */
106
+ function isDevelopment() {
107
+ const nodeEnv = process.env.NODE_ENV?.toLowerCase();
108
+ return nodeEnv == null || nodeEnv === "development" || nodeEnv === "dev";
109
+ }
110
+
111
+ //#endregion
112
+ export { formatParseError, isDevelopment };
113
+ //# sourceMappingURL=formatter-fz8V7x6i.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter-fz8V7x6i.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"],"sources":["../src/formatter.ts"],"sourcesContent":["import { 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\tenvName = String(issue.path[0]);\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(\n\t\t`${c.red}${c.bold}Environment Configuration Failed${c.reset}`,\n\t);\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"],"mappings":";;;;;;AAaA,MAAM,SAAS;CACd,OAAO;CACP,KAAK;CACL,QAAQ;CACR,MAAM;CACN,KAAK;CACL,MAAM;AACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCD,SAAgB,iBACfA,OACAC,UAAyB,CAAE,GAClB;CACT,MAAM,YACL,QAAQ,WAAW,QAAQ,QAAQ,SAAS,QAAQ,IAAI,YAAY;CAErE,MAAM,IAAI,YACP,SACA;EAAE,OAAO;EAAI,KAAK;EAAI,QAAQ;EAAI,MAAM;EAAI,KAAK;EAAI,MAAM;CAAI;CAElE,MAAMC,cAAwD,CAAE;CAChE,MAAMC,cACL,CAAE;AAEH,MAAK,MAAM,SAAS,MAAM,QAAQ;EAEjC,IAAI,UAAU;AACd,MAAI,MAAM,KAAK,SAAS,EACvB,WAAU,OAAO,MAAM,KAAK,GAAG;OACzB;GAEN,MAAM,QAAQ,MAAM,QAAQ,MAAM,iCAAiC;AACnE,OAAI,QAAQ,GACX,WAAU,MAAM;EAEjB;EAID,MAAM,WAAW,cAAc,QAAQ,MAAM;EAC7C,MAAM,YACL,MAAM,SAAS,mBACd,aAAa,eAAe,aAAa;AAE3C,MAAI,UACH,aAAY,KAAK;GAChB,MAAM,WAAW;GACjB,SAAS,aAAa,MAAM,QAAQ;EACpC,EAAC;MAEF,aAAY,KAAK;GAChB,MAAM,WAAW;GACjB,OAAO;GACP,SAAS,aAAa,MAAM,QAAQ;EACpC,EAAC;CAEH;CAED,MAAMC,QAAkB,CAAE;AAE1B,OAAM,KAAK,GAAG;AACd,OAAM,MACJ,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,kCAAkC,EAAE,MAAM,EAC5D;AACD,OAAM,KAAK,GAAG;AAEd,KAAI,YAAY,SAAS,GAAG;AAC3B,QAAM,MAAM,EAAE,EAAE,OAAO,oBAAoB,EAAE,MAAM,EAAE;AACrD,OAAK,MAAM,KAAK,YACf,OAAM,MAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,YAAY,EAAE,MAAM,EAAE;AAE1E,QAAM,KAAK,GAAG;CACd;AAED,KAAI,YAAY,SAAS,GAAG;AAC3B,QAAM,MAAM,EAAE,EAAE,OAAO,iBAAiB,EAAE,MAAM,EAAE;AAClD,OAAK,MAAM,KAAK,aAAa;GAC5B,MAAM,WACL,EAAE,oBAAuB,KAAK,KAAK,UAAU,EAAE,MAAM,CAAC,IAAI;AAC3D,SAAM,MAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;AACvD,SAAM,MAAM,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE;EAChD;AACD,QAAM,KAAK,GAAG;CACd;AAED,QAAO,MAAM,KAAK,KAAK;AACvB;;;;AAKD,SAAS,aAAaC,SAAyB;AAE9C,QAAO,QAAQ,QAAQ,mCAAmC,GAAG;AAC7D;;;;AAKD,SAAgB,gBAAyB;CACxC,MAAM,UAAU,QAAQ,IAAI,UAAU,aAAa;AACnD,QAAO,WAAW,QAAQ,YAAY,iBAAiB,YAAY;AACnE"}
@@ -0,0 +1,125 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const zod_v4 = require_chunk.__toESM(require("zod/v4"));
3
+
4
+ //#region src/formatter.ts
5
+ /**
6
+ * ANSI color codes for terminal output.
7
+ */
8
+ const colors = {
9
+ reset: "\x1B[0m",
10
+ red: "\x1B[31m",
11
+ yellow: "\x1B[33m",
12
+ cyan: "\x1B[36m",
13
+ dim: "\x1B[2m",
14
+ bold: "\x1B[1m"
15
+ };
16
+ /**
17
+ * Formats a ZodError into a user-friendly string for development.
18
+ *
19
+ * @param error - The ZodError to format
20
+ * @param options - Formatting options
21
+ * @returns Formatted error message
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * try {
26
+ * config.parse();
27
+ * } catch (error) {
28
+ * if (error instanceof ZodError) {
29
+ * console.error(formatParseError(error));
30
+ * }
31
+ * }
32
+ * ```
33
+ *
34
+ * Output:
35
+ * ```
36
+ * Environment Configuration Failed
37
+ *
38
+ * Missing Variables:
39
+ * DATABASE_URL - Required
40
+ * JWT_SECRET - Required
41
+ *
42
+ * Invalid Values:
43
+ * NODE_ENV = "invalid"
44
+ * Expected: "development" | "staging" | "production"
45
+ * ```
46
+ */
47
+ function formatParseError(error, options = {}) {
48
+ const useColors = options.colors ?? (process.stdout?.isTTY && process.env.NO_COLOR == null);
49
+ const c = useColors ? colors : {
50
+ reset: "",
51
+ red: "",
52
+ yellow: "",
53
+ cyan: "",
54
+ dim: "",
55
+ bold: ""
56
+ };
57
+ const missingVars = [];
58
+ const invalidVars = [];
59
+ for (const issue of error.issues) {
60
+ let envName = "";
61
+ if (issue.path.length > 0) envName = String(issue.path[0]);
62
+ else {
63
+ const match = issue.message.match(/Environment variable "([^"]+)"/);
64
+ if (match?.[1]) envName = match[1];
65
+ }
66
+ const received = "received" in issue ? issue.received : void 0;
67
+ const isMissing = issue.code === "invalid_type" && (received === "undefined" || received === "null");
68
+ if (isMissing) missingVars.push({
69
+ name: envName || "Unknown",
70
+ message: cleanMessage(issue.message)
71
+ });
72
+ else invalidVars.push({
73
+ name: envName || "Unknown",
74
+ value: received,
75
+ message: cleanMessage(issue.message)
76
+ });
77
+ }
78
+ const lines = [];
79
+ lines.push("");
80
+ lines.push(`${c.red}${c.bold}Environment Configuration Failed${c.reset}`);
81
+ lines.push("");
82
+ if (missingVars.length > 0) {
83
+ lines.push(`${c.yellow}Missing Variables:${c.reset}`);
84
+ for (const v of missingVars) lines.push(` ${c.cyan}${v.name}${c.reset} ${c.dim}- Required${c.reset}`);
85
+ lines.push("");
86
+ }
87
+ if (invalidVars.length > 0) {
88
+ lines.push(`${c.yellow}Invalid Values:${c.reset}`);
89
+ for (const v of invalidVars) {
90
+ const valueStr = v.value !== void 0 ? ` = ${JSON.stringify(v.value)}` : "";
91
+ lines.push(` ${c.cyan}${v.name}${c.reset}${valueStr}`);
92
+ lines.push(` ${c.dim}${v.message}${c.reset}`);
93
+ }
94
+ lines.push("");
95
+ }
96
+ return lines.join("\n");
97
+ }
98
+ /**
99
+ * Cleans up a Zod error message by removing redundant prefixes.
100
+ */
101
+ function cleanMessage(message) {
102
+ return message.replace(/^Environment variable "[^"]+": /, "");
103
+ }
104
+ /**
105
+ * Checks if the current environment is development.
106
+ */
107
+ function isDevelopment() {
108
+ const nodeEnv = process.env.NODE_ENV?.toLowerCase();
109
+ return nodeEnv == null || nodeEnv === "development" || nodeEnv === "dev";
110
+ }
111
+
112
+ //#endregion
113
+ Object.defineProperty(exports, 'formatParseError', {
114
+ enumerable: true,
115
+ get: function () {
116
+ return formatParseError;
117
+ }
118
+ });
119
+ Object.defineProperty(exports, 'isDevelopment', {
120
+ enumerable: true,
121
+ get: function () {
122
+ return isDevelopment;
123
+ }
124
+ });
125
+ //# sourceMappingURL=formatter-w8Tsccw4.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter-w8Tsccw4.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"],"sources":["../src/formatter.ts"],"sourcesContent":["import { 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\tenvName = String(issue.path[0]);\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(\n\t\t`${c.red}${c.bold}Environment Configuration Failed${c.reset}`,\n\t);\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"],"mappings":";;;;;;;AAaA,MAAM,SAAS;CACd,OAAO;CACP,KAAK;CACL,QAAQ;CACR,MAAM;CACN,KAAK;CACL,MAAM;AACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCD,SAAgB,iBACfA,OACAC,UAAyB,CAAE,GAClB;CACT,MAAM,YACL,QAAQ,WAAW,QAAQ,QAAQ,SAAS,QAAQ,IAAI,YAAY;CAErE,MAAM,IAAI,YACP,SACA;EAAE,OAAO;EAAI,KAAK;EAAI,QAAQ;EAAI,MAAM;EAAI,KAAK;EAAI,MAAM;CAAI;CAElE,MAAMC,cAAwD,CAAE;CAChE,MAAMC,cACL,CAAE;AAEH,MAAK,MAAM,SAAS,MAAM,QAAQ;EAEjC,IAAI,UAAU;AACd,MAAI,MAAM,KAAK,SAAS,EACvB,WAAU,OAAO,MAAM,KAAK,GAAG;OACzB;GAEN,MAAM,QAAQ,MAAM,QAAQ,MAAM,iCAAiC;AACnE,OAAI,QAAQ,GACX,WAAU,MAAM;EAEjB;EAID,MAAM,WAAW,cAAc,QAAQ,MAAM;EAC7C,MAAM,YACL,MAAM,SAAS,mBACd,aAAa,eAAe,aAAa;AAE3C,MAAI,UACH,aAAY,KAAK;GAChB,MAAM,WAAW;GACjB,SAAS,aAAa,MAAM,QAAQ;EACpC,EAAC;MAEF,aAAY,KAAK;GAChB,MAAM,WAAW;GACjB,OAAO;GACP,SAAS,aAAa,MAAM,QAAQ;EACpC,EAAC;CAEH;CAED,MAAMC,QAAkB,CAAE;AAE1B,OAAM,KAAK,GAAG;AACd,OAAM,MACJ,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,kCAAkC,EAAE,MAAM,EAC5D;AACD,OAAM,KAAK,GAAG;AAEd,KAAI,YAAY,SAAS,GAAG;AAC3B,QAAM,MAAM,EAAE,EAAE,OAAO,oBAAoB,EAAE,MAAM,EAAE;AACrD,OAAK,MAAM,KAAK,YACf,OAAM,MAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,YAAY,EAAE,MAAM,EAAE;AAE1E,QAAM,KAAK,GAAG;CACd;AAED,KAAI,YAAY,SAAS,GAAG;AAC3B,QAAM,MAAM,EAAE,EAAE,OAAO,iBAAiB,EAAE,MAAM,EAAE;AAClD,OAAK,MAAM,KAAK,aAAa;GAC5B,MAAM,WACL,EAAE,oBAAuB,KAAK,KAAK,UAAU,EAAE,MAAM,CAAC,IAAI;AAC3D,SAAM,MAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE;AACvD,SAAM,MAAM,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE;EAChD;AACD,QAAM,KAAK,GAAG;CACd;AAED,QAAO,MAAM,KAAK,KAAK;AACvB;;;;AAKD,SAAS,aAAaC,SAAyB;AAE9C,QAAO,QAAQ,QAAQ,mCAAmC,GAAG;AAC7D;;;;AAKD,SAAgB,gBAAyB;CACxC,MAAM,UAAU,QAAQ,IAAI,UAAU,aAAa;AACnD,QAAO,WAAW,QAAQ,YAAY,iBAAiB,YAAY;AACnE"}
@@ -0,0 +1,4 @@
1
+ const require_formatter = require('./formatter-w8Tsccw4.cjs');
2
+
3
+ exports.formatParseError = require_formatter.formatParseError;
4
+ exports.isDevelopment = require_formatter.isDevelopment;
@@ -0,0 +1,2 @@
1
+ import { FormatOptions, formatParseError, isDevelopment } from "./formatter-D85aIkpd.cjs";
2
+ export { FormatOptions, formatParseError, isDevelopment };
@@ -0,0 +1,2 @@
1
+ import { FormatOptions, formatParseError, isDevelopment } from "./formatter-Cox0NGxT.mjs";
2
+ export { FormatOptions, formatParseError, isDevelopment };
@@ -0,0 +1,3 @@
1
+ import { formatParseError, isDevelopment } from "./formatter-fz8V7x6i.mjs";
2
+
3
+ export { formatParseError, isDevelopment };
package/dist/index.cjs CHANGED
@@ -1,7 +1,10 @@
1
1
  const require_EnvironmentBuilder = require('./EnvironmentBuilder-Djr1VsWM.cjs');
2
- const require_EnvironmentParser = require('./EnvironmentParser-Bt246UeP.cjs');
2
+ const require_formatter = require('./formatter-w8Tsccw4.cjs');
3
+ const require_EnvironmentParser = require('./EnvironmentParser-DlWHnhDY.cjs');
3
4
 
4
5
  exports.ConfigParser = require_EnvironmentParser.ConfigParser;
5
6
  exports.EnvironmentBuilder = require_EnvironmentBuilder.EnvironmentBuilder;
6
7
  exports.EnvironmentParser = require_EnvironmentParser.EnvironmentParser;
7
- exports.environmentCase = require_EnvironmentBuilder.environmentCase;
8
+ exports.environmentCase = require_EnvironmentBuilder.environmentCase;
9
+ exports.formatParseError = require_formatter.formatParseError;
10
+ exports.isDevelopment = require_formatter.isDevelopment;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase } from "./EnvironmentBuilder-Xuf2Dd9u.cjs";
2
2
  import { ConfigParser, EnvironmentParser } from "./EnvironmentParser-DtOL86NU.cjs";
3
- export { ConfigParser, EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentParser, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase };
3
+ import { FormatOptions, formatParseError, isDevelopment } from "./formatter-D85aIkpd.cjs";
4
+ export { ConfigParser, EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentParser, EnvironmentResolver, FormatOptions, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase, formatParseError, isDevelopment };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
- import { EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase } from "./EnvironmentBuilder-DHfDXJUm.mjs";
2
- import { ConfigParser, EnvironmentParser } from "./EnvironmentParser-CY8TosTN.mjs";
3
- export { ConfigParser, EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentParser, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase };
1
+ import { EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentResolver, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase } from "./EnvironmentBuilder-jF-b7WQg.mjs";
2
+ import { ConfigParser, EnvironmentParser } from "./EnvironmentParser-CkLfmn4Y.mjs";
3
+ import { FormatOptions, formatParseError, isDevelopment } from "./formatter-Cox0NGxT.mjs";
4
+ export { ConfigParser, EnvRecord, EnvValue, EnvironmentBuilder, EnvironmentBuilderOptions, EnvironmentParser, EnvironmentResolver, FormatOptions, InputValue, Resolvers, TypedInputValue, TypedResolvers, environmentCase, formatParseError, isDevelopment };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { EnvironmentBuilder, environmentCase } from "./EnvironmentBuilder-BSuHZm0y.mjs";
2
- import { ConfigParser, EnvironmentParser } from "./EnvironmentParser-c06agx31.mjs";
2
+ import { formatParseError, isDevelopment } from "./formatter-fz8V7x6i.mjs";
3
+ import { ConfigParser, EnvironmentParser } from "./EnvironmentParser-CBLsPUyQ.mjs";
3
4
 
4
- export { ConfigParser, EnvironmentBuilder, EnvironmentParser, environmentCase };
5
+ export { ConfigParser, EnvironmentBuilder, EnvironmentParser, environmentCase, formatParseError, isDevelopment };
package/dist/sst.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const require_EnvironmentBuilder = require('./EnvironmentBuilder-Djr1VsWM.cjs');
2
- const require_SstEnvironmentBuilder = require('./SstEnvironmentBuilder-wFnN2M5O.cjs');
2
+ const require_SstEnvironmentBuilder = require('./SstEnvironmentBuilder-jsnqgtcW.cjs');
3
3
 
4
4
  //#region src/sst.ts
5
5
  /**
package/dist/sst.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { EnvRecord, EnvValue, EnvironmentBuilderOptions, environmentCase } from "./EnvironmentBuilder-DHfDXJUm.mjs";
2
- import { ApiGatewayV2, Bucket, Function, Postgres, ResourceProcessor, ResourceType, Secret, SnsTopic, SstEnvironmentBuilder, SstResource, Vpc, sstResolvers } from "./SstEnvironmentBuilder-CjURMGjW.mjs";
1
+ import { EnvRecord, EnvValue, EnvironmentBuilderOptions, environmentCase } from "./EnvironmentBuilder-jF-b7WQg.mjs";
2
+ import { ApiGatewayV2, Bucket, Function, Postgres, ResourceProcessor, ResourceType, Secret, SnsTopic, SstEnvironmentBuilder, SstResource, Vpc, sstResolvers } from "./SstEnvironmentBuilder-BZngSQKQ.mjs";
3
3
 
4
4
  //#region src/sst.d.ts
5
5
 
package/dist/sst.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { environmentCase } from "./EnvironmentBuilder-BSuHZm0y.mjs";
2
- import { ResourceType, SstEnvironmentBuilder, sstResolvers } from "./SstEnvironmentBuilder-BEBFSUYr.mjs";
2
+ import { ResourceType, SstEnvironmentBuilder, sstResolvers } from "./SstEnvironmentBuilder-DVB7cJq4.mjs";
3
3
 
4
4
  //#region src/sst.ts
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/envkit",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,7 @@
1
1
  import get from 'lodash.get';
2
2
  import set from 'lodash.set';
3
3
  import { z } from 'zod/v4';
4
+ import { formatParseError, isDevelopment } from './formatter.js';
4
5
 
5
6
  /**
6
7
  * Parses and validates configuration objects against Zod schemas.
@@ -63,8 +64,12 @@ export class ConfigParser<TResponse extends EmptyObject> {
63
64
  ) as unknown as InferConfig<TResponse>;
64
65
 
65
66
  if (errors.length > 0) {
66
- // If there are errors, throw them
67
- throw new z.ZodError(errors);
67
+ const zodError = new z.ZodError(errors);
68
+ // In development, log a formatted error message before throwing
69
+ if (isDevelopment()) {
70
+ console.error(formatParseError(zodError));
71
+ }
72
+ throw zodError;
68
73
  }
69
74
 
70
75
  return parsedConfig;
@@ -0,0 +1,250 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { z } from 'zod/v4';
3
+ import { formatParseError, isDevelopment } from '../formatter';
4
+
5
+ // Helper to create test issues - casts through unknown because we're creating test fixtures
6
+ // that may include properties like 'received' which vary by issue type
7
+ function createIssue(issue: Record<string, unknown>): z.core.$ZodIssue {
8
+ return issue as unknown as z.core.$ZodIssue;
9
+ }
10
+
11
+ describe('formatParseError', () => {
12
+ it('should format missing variables', () => {
13
+ const error = new z.ZodError([
14
+ createIssue({
15
+ code: 'invalid_type',
16
+ expected: 'string',
17
+ received: 'undefined',
18
+ path: ['DATABASE_URL'],
19
+ message: 'Environment variable "DATABASE_URL": Required',
20
+ }),
21
+ createIssue({
22
+ code: 'invalid_type',
23
+ expected: 'string',
24
+ received: 'undefined',
25
+ path: ['JWT_SECRET'],
26
+ message: 'Environment variable "JWT_SECRET": Required',
27
+ }),
28
+ ]);
29
+
30
+ const formatted = formatParseError(error, { colors: false });
31
+
32
+ expect(formatted).toContain('Environment Configuration Failed');
33
+ expect(formatted).toContain('Missing Variables:');
34
+ expect(formatted).toContain('DATABASE_URL');
35
+ expect(formatted).toContain('JWT_SECRET');
36
+ expect(formatted).toContain('Required');
37
+ });
38
+
39
+ it('should format invalid values', () => {
40
+ const error = new z.ZodError([
41
+ createIssue({
42
+ code: 'invalid_value',
43
+ values: ['development', 'staging', 'production'],
44
+ received: 'invalid',
45
+ path: ['NODE_ENV'],
46
+ message:
47
+ 'Invalid enum value. Expected \'development\' | \'staging\' | \'production\', received \'invalid\'',
48
+ }),
49
+ ]);
50
+
51
+ const formatted = formatParseError(error, { colors: false });
52
+
53
+ expect(formatted).toContain('Environment Configuration Failed');
54
+ expect(formatted).toContain('Invalid Values:');
55
+ expect(formatted).toContain('NODE_ENV');
56
+ expect(formatted).toContain('invalid');
57
+ });
58
+
59
+ it('should handle mixed missing and invalid values', () => {
60
+ const error = new z.ZodError([
61
+ createIssue({
62
+ code: 'invalid_type',
63
+ expected: 'string',
64
+ received: 'undefined',
65
+ path: ['DATABASE_URL'],
66
+ message: 'Environment variable "DATABASE_URL": Required',
67
+ }),
68
+ createIssue({
69
+ code: 'invalid_type',
70
+ expected: 'number',
71
+ received: 'string',
72
+ path: ['PORT'],
73
+ message: 'Expected number, received string',
74
+ }),
75
+ ]);
76
+
77
+ const formatted = formatParseError(error, { colors: false });
78
+
79
+ expect(formatted).toContain('Missing Variables:');
80
+ expect(formatted).toContain('DATABASE_URL');
81
+ expect(formatted).toContain('Invalid Values:');
82
+ expect(formatted).toContain('PORT');
83
+ });
84
+
85
+ it('should clean message prefixes', () => {
86
+ const error = new z.ZodError([
87
+ createIssue({
88
+ code: 'invalid_type',
89
+ expected: 'number',
90
+ received: 'string',
91
+ path: ['PORT'],
92
+ message: 'Environment variable "PORT": Expected number, received string',
93
+ }),
94
+ ]);
95
+
96
+ const formatted = formatParseError(error, { colors: false });
97
+
98
+ // Should not duplicate "Environment variable" in output
99
+ expect(formatted).not.toContain(
100
+ 'Environment variable "PORT": Environment variable',
101
+ );
102
+ expect(formatted).toContain('Expected number, received string');
103
+ });
104
+
105
+ it('should extract env name from message when path is empty', () => {
106
+ const error = new z.ZodError([
107
+ createIssue({
108
+ code: 'invalid_type',
109
+ expected: 'string',
110
+ received: 'undefined',
111
+ path: [],
112
+ message: 'Environment variable "API_KEY": Required',
113
+ }),
114
+ ]);
115
+
116
+ const formatted = formatParseError(error, { colors: false });
117
+
118
+ expect(formatted).toContain('API_KEY');
119
+ });
120
+
121
+ it('should handle colors option false', () => {
122
+ const error = new z.ZodError([
123
+ createIssue({
124
+ code: 'invalid_type',
125
+ expected: 'string',
126
+ received: 'undefined',
127
+ path: ['TEST'],
128
+ message: 'Required',
129
+ }),
130
+ ]);
131
+
132
+ const formatted = formatParseError(error, { colors: false });
133
+
134
+ // Should not contain ANSI codes
135
+ expect(formatted).not.toContain('\x1b[');
136
+ });
137
+
138
+ it('should handle colors option true', () => {
139
+ const error = new z.ZodError([
140
+ createIssue({
141
+ code: 'invalid_type',
142
+ expected: 'string',
143
+ received: 'undefined',
144
+ path: ['TEST'],
145
+ message: 'Required',
146
+ }),
147
+ ]);
148
+
149
+ const formatted = formatParseError(error, { colors: true });
150
+
151
+ // Should contain ANSI codes
152
+ expect(formatted).toContain('\x1b[');
153
+ });
154
+ });
155
+
156
+ describe('isDevelopment', () => {
157
+ const originalEnv = process.env.NODE_ENV;
158
+
159
+ afterEach(() => {
160
+ if (originalEnv === undefined) {
161
+ delete process.env.NODE_ENV;
162
+ } else {
163
+ process.env.NODE_ENV = originalEnv;
164
+ }
165
+ });
166
+
167
+ it('should return true when NODE_ENV is undefined', () => {
168
+ delete process.env.NODE_ENV;
169
+ expect(isDevelopment()).toBe(true);
170
+ });
171
+
172
+ it('should return true when NODE_ENV is development', () => {
173
+ process.env.NODE_ENV = 'development';
174
+ expect(isDevelopment()).toBe(true);
175
+ });
176
+
177
+ it('should return true when NODE_ENV is dev', () => {
178
+ process.env.NODE_ENV = 'dev';
179
+ expect(isDevelopment()).toBe(true);
180
+ });
181
+
182
+ it('should return true when NODE_ENV is DEVELOPMENT (case insensitive)', () => {
183
+ process.env.NODE_ENV = 'DEVELOPMENT';
184
+ expect(isDevelopment()).toBe(true);
185
+ });
186
+
187
+ it('should return false when NODE_ENV is production', () => {
188
+ process.env.NODE_ENV = 'production';
189
+ expect(isDevelopment()).toBe(false);
190
+ });
191
+
192
+ it('should return false when NODE_ENV is staging', () => {
193
+ process.env.NODE_ENV = 'staging';
194
+ expect(isDevelopment()).toBe(false);
195
+ });
196
+
197
+ it('should return false when NODE_ENV is test', () => {
198
+ process.env.NODE_ENV = 'test';
199
+ expect(isDevelopment()).toBe(false);
200
+ });
201
+ });
202
+
203
+ describe('ConfigParser with dev formatting', () => {
204
+ const originalEnv = process.env.NODE_ENV;
205
+
206
+ beforeEach(() => {
207
+ vi.spyOn(console, 'error').mockImplementation(() => {});
208
+ });
209
+
210
+ afterEach(() => {
211
+ vi.restoreAllMocks();
212
+ if (originalEnv === undefined) {
213
+ delete process.env.NODE_ENV;
214
+ } else {
215
+ process.env.NODE_ENV = originalEnv;
216
+ }
217
+ });
218
+
219
+ it('should log formatted error in development mode', async () => {
220
+ process.env.NODE_ENV = 'development';
221
+
222
+ const { EnvironmentParser } = await import('../EnvironmentParser');
223
+ const parser = new EnvironmentParser({});
224
+ const config = parser.create((get) => ({
225
+ dbUrl: get('DATABASE_URL').string(),
226
+ }));
227
+
228
+ expect(() => config.parse()).toThrow();
229
+ expect(console.error).toHaveBeenCalled();
230
+
231
+ const errorOutput = (console.error as any).mock.calls[0][0];
232
+ expect(errorOutput).toContain('Environment Configuration Failed');
233
+ });
234
+
235
+ it('should not log formatted error in production mode', async () => {
236
+ process.env.NODE_ENV = 'production';
237
+
238
+ // Need to reimport to pick up the new NODE_ENV
239
+ vi.resetModules();
240
+ const { EnvironmentParser } = await import('../EnvironmentParser');
241
+
242
+ const parser = new EnvironmentParser({});
243
+ const config = parser.create((get) => ({
244
+ dbUrl: get('DATABASE_URL').string(),
245
+ }));
246
+
247
+ expect(() => config.parse()).toThrow();
248
+ expect(console.error).not.toHaveBeenCalled();
249
+ });
250
+ });