@vite-env/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pyyupsk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,12 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./dts-DT7HjKrz.cjs");
3
+ let jiti = require("jiti");
4
+ //#region src/config.ts
5
+ async function loadEnvConfig(configPath) {
6
+ const mod = await (0, jiti.createJiti)(configPath).import(configPath);
7
+ return mod.default ?? mod;
8
+ }
9
+ //#endregion
10
+ exports.loadEnvConfig = loadEnvConfig;
11
+
12
+ //# sourceMappingURL=config.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.cjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { EnvDefinition } from './types'\nimport { createJiti } from 'jiti'\n\nexport async function loadEnvConfig(configPath: string): Promise<EnvDefinition> {\n const jiti = createJiti(configPath)\n const mod = await jiti.import(configPath) as any\n return (mod.default ?? mod) as EnvDefinition\n}\n"],"mappings":";;;;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAAM,OAAA,GAAA,KAAA,YADY,WAAW,CACZ,OAAO,WAAW;AACzC,QAAQ,IAAI,WAAW"}
@@ -0,0 +1,7 @@
1
+ import { t as EnvDefinition } from "./types-BmEBJZdy.cjs";
2
+
3
+ //#region src/config.d.ts
4
+ declare function loadEnvConfig(configPath: string): Promise<EnvDefinition>;
5
+ //#endregion
6
+ export { loadEnvConfig };
7
+ //# sourceMappingURL=config.d.cts.map
@@ -0,0 +1,7 @@
1
+ import { t as EnvDefinition } from "./types-CLfG9amO.mjs";
2
+
3
+ //#region src/config.d.ts
4
+ declare function loadEnvConfig(configPath: string): Promise<EnvDefinition>;
5
+ //#endregion
6
+ export { loadEnvConfig };
7
+ //# sourceMappingURL=config.d.mts.map
@@ -0,0 +1,10 @@
1
+ import { createJiti } from "jiti";
2
+ //#region src/config.ts
3
+ async function loadEnvConfig(configPath) {
4
+ const mod = await createJiti(configPath).import(configPath);
5
+ return mod.default ?? mod;
6
+ }
7
+ //#endregion
8
+ export { loadEnvConfig };
9
+
10
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { EnvDefinition } from './types'\nimport { createJiti } from 'jiti'\n\nexport async function loadEnvConfig(configPath: string): Promise<EnvDefinition> {\n const jiti = createJiti(configPath)\n const mod = await jiti.import(configPath) as any\n return (mod.default ?? mod) as EnvDefinition\n}\n"],"mappings":";;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAAM,MADC,WAAW,WAAW,CACZ,OAAO,WAAW;AACzC,QAAQ,IAAI,WAAW"}
@@ -0,0 +1,99 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ let zod = require("zod");
24
+ let node_path = require("node:path");
25
+ node_path = __toESM(node_path);
26
+ let node_fs_promises = require("node:fs/promises");
27
+ node_fs_promises = __toESM(node_fs_promises);
28
+ //#region src/dts.ts
29
+ /**
30
+ * Writes vite-env.d.ts to project root.
31
+ * Declares virtual:env/client and virtual:env/server module types.
32
+ * Users never need to manually augment ImportMetaEnv again.
33
+ */
34
+ async function generateDts(def, root) {
35
+ const clientKeys = {
36
+ ...def.client,
37
+ ...def.shared
38
+ };
39
+ const serverKeys = {
40
+ ...def.server,
41
+ ...def.client,
42
+ ...def.shared
43
+ };
44
+ const dts = `// Auto-generated by @vite-env/core
45
+ // Do not edit manually — re-generated on every dev server start and build
46
+
47
+ declare module 'virtual:env/client' {
48
+ const env: {
49
+ ${zodShapeToTsFields(clientKeys)}
50
+ }
51
+ export { env }
52
+ export default env
53
+ }
54
+
55
+ declare module 'virtual:env/server' {
56
+ const env: {
57
+ ${zodShapeToTsFields(serverKeys)}
58
+ }
59
+ export { env }
60
+ export default env
61
+ }
62
+ `;
63
+ await node_fs_promises.default.writeFile(node_path.default.join(root, "vite-env.d.ts"), dts, "utf-8");
64
+ }
65
+ function zodShapeToTsFields(shape) {
66
+ return Object.entries(shape).map(([key, schema]) => {
67
+ const s = schema;
68
+ const tsType = zodToTs(s);
69
+ return ` readonly ${key}${isOptional(s) ? "?" : ""}: ${tsType}`;
70
+ }).join("\n");
71
+ }
72
+ function zodToTs(schema) {
73
+ if (schema instanceof zod.z.ZodOptional) return zodToTs(schema.unwrap());
74
+ if (schema instanceof zod.z.ZodDefault) return zodToTs(schema.def.innerType);
75
+ if (schema instanceof zod.z.ZodString) return "string";
76
+ if (schema instanceof zod.z.ZodNumber) return "number";
77
+ if (schema instanceof zod.z.ZodBoolean) return "boolean";
78
+ if (schema instanceof zod.z.ZodEnum) return schema.options.map((o) => `'${o}'`).join(" | ");
79
+ if (schema instanceof zod.z.ZodPipe) return zodToTs(schema.def.out);
80
+ return "string";
81
+ }
82
+ function isOptional(schema) {
83
+ return schema instanceof zod.z.ZodOptional || schema instanceof zod.z.ZodDefault;
84
+ }
85
+ //#endregion
86
+ Object.defineProperty(exports, "__toESM", {
87
+ enumerable: true,
88
+ get: function() {
89
+ return __toESM;
90
+ }
91
+ });
92
+ Object.defineProperty(exports, "generateDts", {
93
+ enumerable: true,
94
+ get: function() {
95
+ return generateDts;
96
+ }
97
+ });
98
+
99
+ //# sourceMappingURL=dts-DT7HjKrz.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dts-DT7HjKrz.cjs","names":["fs","path","z"],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition } from './types'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { z } from 'zod'\n\n/**\n * Writes vite-env.d.ts to project root.\n * Declares virtual:env/client and virtual:env/server module types.\n * Users never need to manually augment ImportMetaEnv again.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = {\n ...def.client,\n ...def.shared,\n }\n const serverKeys = {\n ...def.server,\n ...def.client,\n ...def.shared,\n }\n\n const clientFields = zodShapeToTsFields(clientKeys)\n const serverFields = zodShapeToTsFields(serverKeys)\n\n const dts = `// Auto-generated by @vite-env/core\n// Do not edit manually — re-generated on every dev server start and build\n\ndeclare module 'virtual:env/client' {\n const env: {\n${clientFields}\n }\n export { env }\n export default env\n}\n\ndeclare module 'virtual:env/server' {\n const env: {\n${serverFields}\n }\n export { env }\n export default env\n}\n`\n\n await fs.writeFile(path.join(root, 'vite-env.d.ts'), dts, 'utf-8')\n}\n\nfunction zodShapeToTsFields(shape: z.ZodRawShape): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n // Zod v4: ZodRawShape values are $ZodType, cast to ZodTypeAny for instanceof checks\n const s = schema as unknown as z.ZodTypeAny\n const tsType = zodToTs(s)\n const optional = isOptional(s)\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(schema: z.ZodTypeAny): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(schema.unwrap() as unknown as z.ZodTypeAny)\n if (schema instanceof z.ZodDefault)\n return zodToTs(schema.def.innerType as unknown as z.ZodTypeAny)\n if (schema instanceof z.ZodString)\n return 'string'\n if (schema instanceof z.ZodNumber)\n return 'number'\n if (schema instanceof z.ZodBoolean)\n return 'boolean'\n if (schema instanceof z.ZodEnum)\n return (schema.options as string[]).map(o => `'${o}'`).join(' | ')\n if (schema instanceof z.ZodPipe)\n return zodToTs(schema.def.out as unknown as z.ZodTypeAny)\n return 'string'\n}\n\nfunction isOptional(schema: z.ZodTypeAny): boolean {\n return schema instanceof z.ZodOptional || schema instanceof z.ZodDefault\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,aAAa;EACjB,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CACD,MAAM,aAAa;EACjB,GAAG,IAAI;EACP,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAKD,MAAM,MAAM;;;;;EAHS,mBAAmB,WAAW,CAQtC;;;;;;;;EAPQ,mBAAmB,WAAW,CAetC;;;;;;AAOb,OAAMA,iBAAAA,QAAG,UAAUC,UAAAA,QAAK,KAAK,MAAM,gBAAgB,EAAE,KAAK,QAAQ;;AAGpE,SAAS,mBAAmB,OAA8B;AACxD,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EAEtB,MAAM,IAAI;EACV,MAAM,SAAS,QAAQ,EAAE;AAEzB,SAAO,gBAAgB,MADN,WAAW,EAAE,GACU,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,QAA8B;AAC7C,KAAI,kBAAkBC,IAAAA,EAAE,YACtB,QAAO,QAAQ,OAAO,QAAQ,CAA4B;AAC5D,KAAI,kBAAkBA,IAAAA,EAAE,WACtB,QAAO,QAAQ,OAAO,IAAI,UAAqC;AACjE,KAAI,kBAAkBA,IAAAA,EAAE,UACtB,QAAO;AACT,KAAI,kBAAkBA,IAAAA,EAAE,UACtB,QAAO;AACT,KAAI,kBAAkBA,IAAAA,EAAE,WACtB,QAAO;AACT,KAAI,kBAAkBA,IAAAA,EAAE,QACtB,QAAQ,OAAO,QAAqB,KAAI,MAAK,IAAI,EAAE,GAAG,CAAC,KAAK,MAAM;AACpE,KAAI,kBAAkBA,IAAAA,EAAE,QACtB,QAAO,QAAQ,OAAO,IAAI,IAA+B;AAC3D,QAAO;;AAGT,SAAS,WAAW,QAA+B;AACjD,QAAO,kBAAkBA,IAAAA,EAAE,eAAe,kBAAkBA,IAAAA,EAAE"}
package/dist/dts.cjs ADDED
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_dts = require("./dts-DT7HjKrz.cjs");
3
+ exports.generateDts = require_dts.generateDts;
package/dist/dts.d.cts ADDED
@@ -0,0 +1,12 @@
1
+ import { t as EnvDefinition } from "./types-BmEBJZdy.cjs";
2
+
3
+ //#region src/dts.d.ts
4
+ /**
5
+ * Writes vite-env.d.ts to project root.
6
+ * Declares virtual:env/client and virtual:env/server module types.
7
+ * Users never need to manually augment ImportMetaEnv again.
8
+ */
9
+ declare function generateDts(def: EnvDefinition, root: string): Promise<void>;
10
+ //#endregion
11
+ export { generateDts };
12
+ //# sourceMappingURL=dts.d.cts.map
package/dist/dts.d.mts ADDED
@@ -0,0 +1,12 @@
1
+ import { t as EnvDefinition } from "./types-CLfG9amO.mjs";
2
+
3
+ //#region src/dts.d.ts
4
+ /**
5
+ * Writes vite-env.d.ts to project root.
6
+ * Declares virtual:env/client and virtual:env/server module types.
7
+ * Users never need to manually augment ImportMetaEnv again.
8
+ */
9
+ declare function generateDts(def: EnvDefinition, root: string): Promise<void>;
10
+ //#endregion
11
+ export { generateDts };
12
+ //# sourceMappingURL=dts.d.mts.map
package/dist/dts.mjs ADDED
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ import path from "node:path";
3
+ import fs from "node:fs/promises";
4
+ //#region src/dts.ts
5
+ /**
6
+ * Writes vite-env.d.ts to project root.
7
+ * Declares virtual:env/client and virtual:env/server module types.
8
+ * Users never need to manually augment ImportMetaEnv again.
9
+ */
10
+ async function generateDts(def, root) {
11
+ const clientKeys = {
12
+ ...def.client,
13
+ ...def.shared
14
+ };
15
+ const serverKeys = {
16
+ ...def.server,
17
+ ...def.client,
18
+ ...def.shared
19
+ };
20
+ const dts = `// Auto-generated by @vite-env/core
21
+ // Do not edit manually — re-generated on every dev server start and build
22
+
23
+ declare module 'virtual:env/client' {
24
+ const env: {
25
+ ${zodShapeToTsFields(clientKeys)}
26
+ }
27
+ export { env }
28
+ export default env
29
+ }
30
+
31
+ declare module 'virtual:env/server' {
32
+ const env: {
33
+ ${zodShapeToTsFields(serverKeys)}
34
+ }
35
+ export { env }
36
+ export default env
37
+ }
38
+ `;
39
+ await fs.writeFile(path.join(root, "vite-env.d.ts"), dts, "utf-8");
40
+ }
41
+ function zodShapeToTsFields(shape) {
42
+ return Object.entries(shape).map(([key, schema]) => {
43
+ const s = schema;
44
+ const tsType = zodToTs(s);
45
+ return ` readonly ${key}${isOptional(s) ? "?" : ""}: ${tsType}`;
46
+ }).join("\n");
47
+ }
48
+ function zodToTs(schema) {
49
+ if (schema instanceof z.ZodOptional) return zodToTs(schema.unwrap());
50
+ if (schema instanceof z.ZodDefault) return zodToTs(schema.def.innerType);
51
+ if (schema instanceof z.ZodString) return "string";
52
+ if (schema instanceof z.ZodNumber) return "number";
53
+ if (schema instanceof z.ZodBoolean) return "boolean";
54
+ if (schema instanceof z.ZodEnum) return schema.options.map((o) => `'${o}'`).join(" | ");
55
+ if (schema instanceof z.ZodPipe) return zodToTs(schema.def.out);
56
+ return "string";
57
+ }
58
+ function isOptional(schema) {
59
+ return schema instanceof z.ZodOptional || schema instanceof z.ZodDefault;
60
+ }
61
+ //#endregion
62
+ export { generateDts };
63
+
64
+ //# sourceMappingURL=dts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dts.mjs","names":[],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition } from './types'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { z } from 'zod'\n\n/**\n * Writes vite-env.d.ts to project root.\n * Declares virtual:env/client and virtual:env/server module types.\n * Users never need to manually augment ImportMetaEnv again.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = {\n ...def.client,\n ...def.shared,\n }\n const serverKeys = {\n ...def.server,\n ...def.client,\n ...def.shared,\n }\n\n const clientFields = zodShapeToTsFields(clientKeys)\n const serverFields = zodShapeToTsFields(serverKeys)\n\n const dts = `// Auto-generated by @vite-env/core\n// Do not edit manually — re-generated on every dev server start and build\n\ndeclare module 'virtual:env/client' {\n const env: {\n${clientFields}\n }\n export { env }\n export default env\n}\n\ndeclare module 'virtual:env/server' {\n const env: {\n${serverFields}\n }\n export { env }\n export default env\n}\n`\n\n await fs.writeFile(path.join(root, 'vite-env.d.ts'), dts, 'utf-8')\n}\n\nfunction zodShapeToTsFields(shape: z.ZodRawShape): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n // Zod v4: ZodRawShape values are $ZodType, cast to ZodTypeAny for instanceof checks\n const s = schema as unknown as z.ZodTypeAny\n const tsType = zodToTs(s)\n const optional = isOptional(s)\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(schema: z.ZodTypeAny): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(schema.unwrap() as unknown as z.ZodTypeAny)\n if (schema instanceof z.ZodDefault)\n return zodToTs(schema.def.innerType as unknown as z.ZodTypeAny)\n if (schema instanceof z.ZodString)\n return 'string'\n if (schema instanceof z.ZodNumber)\n return 'number'\n if (schema instanceof z.ZodBoolean)\n return 'boolean'\n if (schema instanceof z.ZodEnum)\n return (schema.options as string[]).map(o => `'${o}'`).join(' | ')\n if (schema instanceof z.ZodPipe)\n return zodToTs(schema.def.out as unknown as z.ZodTypeAny)\n return 'string'\n}\n\nfunction isOptional(schema: z.ZodTypeAny): boolean {\n return schema instanceof z.ZodOptional || schema instanceof z.ZodDefault\n}\n"],"mappings":";;;;;;;;;AAWA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,aAAa;EACjB,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CACD,MAAM,aAAa;EACjB,GAAG,IAAI;EACP,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAKD,MAAM,MAAM;;;;;EAHS,mBAAmB,WAAW,CAQtC;;;;;;;;EAPQ,mBAAmB,WAAW,CAetC;;;;;;AAOb,OAAM,GAAG,UAAU,KAAK,KAAK,MAAM,gBAAgB,EAAE,KAAK,QAAQ;;AAGpE,SAAS,mBAAmB,OAA8B;AACxD,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EAEtB,MAAM,IAAI;EACV,MAAM,SAAS,QAAQ,EAAE;AAEzB,SAAO,gBAAgB,MADN,WAAW,EAAE,GACU,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,QAA8B;AAC7C,KAAI,kBAAkB,EAAE,YACtB,QAAO,QAAQ,OAAO,QAAQ,CAA4B;AAC5D,KAAI,kBAAkB,EAAE,WACtB,QAAO,QAAQ,OAAO,IAAI,UAAqC;AACjE,KAAI,kBAAkB,EAAE,UACtB,QAAO;AACT,KAAI,kBAAkB,EAAE,UACtB,QAAO;AACT,KAAI,kBAAkB,EAAE,WACtB,QAAO;AACT,KAAI,kBAAkB,EAAE,QACtB,QAAQ,OAAO,QAAqB,KAAI,MAAK,IAAI,EAAE,GAAG,CAAC,KAAK,MAAM;AACpE,KAAI,kBAAkB,EAAE,QACtB,QAAO,QAAQ,OAAO,IAAI,IAA+B;AAC3D,QAAO;;AAGT,SAAS,WAAW,QAA+B;AACjD,QAAO,kBAAkB,EAAE,eAAe,kBAAkB,EAAE"}
@@ -0,0 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/format.ts
3
+ function formatZodError(issues) {
4
+ return issues.map((issue) => {
5
+ return ` \x1B[31m✗\x1B[0m ${(issue.path.length > 0 ? issue.path.join(".") : "(root)").padEnd(28)} ${issue.message}`;
6
+ }).join("\n");
7
+ }
8
+ //#endregion
9
+ exports.formatZodError = formatZodError;
10
+
11
+ //# sourceMappingURL=format.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.cjs","names":[],"sources":["../src/format.ts"],"sourcesContent":["import type { core } from 'zod'\n\nexport function formatZodError(issues: core.$ZodIssue[]): string {\n return issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : '(root)'\n return ` \\x1B[31m✗\\x1B[0m ${path.padEnd(28)} ${issue.message}`\n })\n .join('\\n')\n}\n"],"mappings":";;AAEA,SAAgB,eAAe,QAAkC;AAC/D,QAAO,OACJ,KAAK,UAAU;AAEd,SAAO,uBADM,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,UAC1B,OAAO,GAAG,CAAC,GAAG,MAAM;GACtD,CACD,KAAK,KAAK"}
@@ -0,0 +1,7 @@
1
+ import { core } from "zod";
2
+
3
+ //#region src/format.d.ts
4
+ declare function formatZodError(issues: core.$ZodIssue[]): string;
5
+ //#endregion
6
+ export { formatZodError };
7
+ //# sourceMappingURL=format.d.cts.map
@@ -0,0 +1,7 @@
1
+ import { core } from "zod";
2
+
3
+ //#region src/format.d.ts
4
+ declare function formatZodError(issues: core.$ZodIssue[]): string;
5
+ //#endregion
6
+ export { formatZodError };
7
+ //# sourceMappingURL=format.d.mts.map
@@ -0,0 +1,10 @@
1
+ //#region src/format.ts
2
+ function formatZodError(issues) {
3
+ return issues.map((issue) => {
4
+ return ` \x1B[31m✗\x1B[0m ${(issue.path.length > 0 ? issue.path.join(".") : "(root)").padEnd(28)} ${issue.message}`;
5
+ }).join("\n");
6
+ }
7
+ //#endregion
8
+ export { formatZodError };
9
+
10
+ //# sourceMappingURL=format.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.mjs","names":[],"sources":["../src/format.ts"],"sourcesContent":["import type { core } from 'zod'\n\nexport function formatZodError(issues: core.$ZodIssue[]): string {\n return issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : '(root)'\n return ` \\x1B[31m✗\\x1B[0m ${path.padEnd(28)} ${issue.message}`\n })\n .join('\\n')\n}\n"],"mappings":";AAEA,SAAgB,eAAe,QAAkC;AAC/D,QAAO,OACJ,KAAK,UAAU;AAEd,SAAO,uBADM,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,UAC1B,OAAO,GAAG,CAAC,GAAG,MAAM;GACtD,CACD,KAAK,KAAK"}
package/dist/index.cjs ADDED
@@ -0,0 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./dts-DT7HjKrz.cjs");
3
+ const require_schema = require("./schema.cjs");
4
+ let zod = require("zod");
5
+ exports.defineEnv = require_schema.defineEnv;
6
+ Object.defineProperty(exports, "z", {
7
+ enumerable: true,
8
+ get: function() {
9
+ return zod.z;
10
+ }
11
+ });
@@ -0,0 +1,4 @@
1
+ import { n as InferClientEnv, r as InferServerEnv, t as EnvDefinition } from "./types-BmEBJZdy.cjs";
2
+ import { defineEnv } from "./schema.cjs";
3
+ import { z } from "zod";
4
+ export { type EnvDefinition, type InferClientEnv, type InferServerEnv, defineEnv, z };
@@ -0,0 +1,4 @@
1
+ import { n as InferClientEnv, r as InferServerEnv, t as EnvDefinition } from "./types-CLfG9amO.mjs";
2
+ import { defineEnv } from "./schema.mjs";
3
+ import { z } from "zod";
4
+ export { type EnvDefinition, type InferClientEnv, type InferServerEnv, defineEnv, z };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { defineEnv } from "./schema.mjs";
2
+ import { z } from "zod";
3
+ export { defineEnv, z };
package/dist/leak.cjs ADDED
@@ -0,0 +1,25 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/leak.ts
3
+ /**
4
+ * Scans all client-destined chunks for literal values of server-only vars.
5
+ * Fires in generateBundle() — Rolldown sequential hook, safe.
6
+ *
7
+ * Strategy: for each server-only key, check if its actual runtime value
8
+ * appears as a literal string in any output chunk's source code.
9
+ * Short/common values (< 8 chars) are skipped to avoid false positives.
10
+ */
11
+ function detectServerLeak(def, data, bundle) {
12
+ const serverKeys = new Set(Object.keys(def.server ?? {}));
13
+ const serverSecrets = Object.entries(data).filter((entry) => serverKeys.has(entry[0]) && typeof entry[1] === "string" && entry[1].length >= 8);
14
+ const chunks = Object.entries(bundle).filter(([, chunk]) => chunk.type === "chunk" && !!chunk.code);
15
+ const leaks = [];
16
+ for (const [key, value] of serverSecrets) for (const [chunkName, chunk] of chunks) if (chunk.code.includes(value)) leaks.push({
17
+ key,
18
+ chunk: chunkName
19
+ });
20
+ return leaks;
21
+ }
22
+ //#endregion
23
+ exports.detectServerLeak = detectServerLeak;
24
+
25
+ //# sourceMappingURL=leak.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leak.cjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { EnvDefinition } from './types'\n\ninterface LeakReport {\n key: string\n chunk: string\n}\n\n/**\n * Scans all client-destined chunks for literal values of server-only vars.\n * Fires in generateBundle() — Rolldown sequential hook, safe.\n *\n * Strategy: for each server-only key, check if its actual runtime value\n * appears as a literal string in any output chunk's source code.\n * Short/common values (< 8 chars) are skipped to avoid false positives.\n */\nexport function detectServerLeak(\n def: EnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const serverSecrets = Object.entries(data).filter(\n (entry): entry is [string, string] =>\n serverKeys.has(entry[0])\n && typeof entry[1] === 'string'\n && entry[1].length >= 8,\n )\n\n const chunks = Object.entries(bundle).filter(\n ([, chunk]) => chunk.type === 'chunk' && !!chunk.code,\n )\n\n const leaks: LeakReport[] = []\n for (const [key, value] of serverSecrets) {\n for (const [chunkName, chunk] of chunks) {\n if (chunk.code!.includes(value)) {\n leaks.push({ key, chunk: chunkName })\n }\n }\n }\n\n return leaks\n}\n"],"mappings":";;;;;;;;;;AAeA,SAAgB,iBACd,KACA,MACA,QACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,gBAAgB,OAAO,QAAQ,KAAK,CAAC,QACxC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,UAAU,EACzB;CAED,MAAM,SAAS,OAAO,QAAQ,OAAO,CAAC,QACnC,GAAG,WAAW,MAAM,SAAS,WAAW,CAAC,CAAC,MAAM,KAClD;CAED,MAAM,QAAsB,EAAE;AAC9B,MAAK,MAAM,CAAC,KAAK,UAAU,cACzB,MAAK,MAAM,CAAC,WAAW,UAAU,OAC/B,KAAI,MAAM,KAAM,SAAS,MAAM,CAC7B,OAAM,KAAK;EAAE;EAAK,OAAO;EAAW,CAAC;AAK3C,QAAO"}
@@ -0,0 +1,22 @@
1
+ import { t as EnvDefinition } from "./types-BmEBJZdy.cjs";
2
+
3
+ //#region src/leak.d.ts
4
+ interface LeakReport {
5
+ key: string;
6
+ chunk: string;
7
+ }
8
+ /**
9
+ * Scans all client-destined chunks for literal values of server-only vars.
10
+ * Fires in generateBundle() — Rolldown sequential hook, safe.
11
+ *
12
+ * Strategy: for each server-only key, check if its actual runtime value
13
+ * appears as a literal string in any output chunk's source code.
14
+ * Short/common values (< 8 chars) are skipped to avoid false positives.
15
+ */
16
+ declare function detectServerLeak(def: EnvDefinition, data: Record<string, unknown>, bundle: Record<string, {
17
+ type: string;
18
+ code?: string;
19
+ }>): LeakReport[];
20
+ //#endregion
21
+ export { detectServerLeak };
22
+ //# sourceMappingURL=leak.d.cts.map
@@ -0,0 +1,22 @@
1
+ import { t as EnvDefinition } from "./types-CLfG9amO.mjs";
2
+
3
+ //#region src/leak.d.ts
4
+ interface LeakReport {
5
+ key: string;
6
+ chunk: string;
7
+ }
8
+ /**
9
+ * Scans all client-destined chunks for literal values of server-only vars.
10
+ * Fires in generateBundle() — Rolldown sequential hook, safe.
11
+ *
12
+ * Strategy: for each server-only key, check if its actual runtime value
13
+ * appears as a literal string in any output chunk's source code.
14
+ * Short/common values (< 8 chars) are skipped to avoid false positives.
15
+ */
16
+ declare function detectServerLeak(def: EnvDefinition, data: Record<string, unknown>, bundle: Record<string, {
17
+ type: string;
18
+ code?: string;
19
+ }>): LeakReport[];
20
+ //#endregion
21
+ export { detectServerLeak };
22
+ //# sourceMappingURL=leak.d.mts.map
package/dist/leak.mjs ADDED
@@ -0,0 +1,24 @@
1
+ //#region src/leak.ts
2
+ /**
3
+ * Scans all client-destined chunks for literal values of server-only vars.
4
+ * Fires in generateBundle() — Rolldown sequential hook, safe.
5
+ *
6
+ * Strategy: for each server-only key, check if its actual runtime value
7
+ * appears as a literal string in any output chunk's source code.
8
+ * Short/common values (< 8 chars) are skipped to avoid false positives.
9
+ */
10
+ function detectServerLeak(def, data, bundle) {
11
+ const serverKeys = new Set(Object.keys(def.server ?? {}));
12
+ const serverSecrets = Object.entries(data).filter((entry) => serverKeys.has(entry[0]) && typeof entry[1] === "string" && entry[1].length >= 8);
13
+ const chunks = Object.entries(bundle).filter(([, chunk]) => chunk.type === "chunk" && !!chunk.code);
14
+ const leaks = [];
15
+ for (const [key, value] of serverSecrets) for (const [chunkName, chunk] of chunks) if (chunk.code.includes(value)) leaks.push({
16
+ key,
17
+ chunk: chunkName
18
+ });
19
+ return leaks;
20
+ }
21
+ //#endregion
22
+ export { detectServerLeak };
23
+
24
+ //# sourceMappingURL=leak.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leak.mjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { EnvDefinition } from './types'\n\ninterface LeakReport {\n key: string\n chunk: string\n}\n\n/**\n * Scans all client-destined chunks for literal values of server-only vars.\n * Fires in generateBundle() — Rolldown sequential hook, safe.\n *\n * Strategy: for each server-only key, check if its actual runtime value\n * appears as a literal string in any output chunk's source code.\n * Short/common values (< 8 chars) are skipped to avoid false positives.\n */\nexport function detectServerLeak(\n def: EnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const serverSecrets = Object.entries(data).filter(\n (entry): entry is [string, string] =>\n serverKeys.has(entry[0])\n && typeof entry[1] === 'string'\n && entry[1].length >= 8,\n )\n\n const chunks = Object.entries(bundle).filter(\n ([, chunk]) => chunk.type === 'chunk' && !!chunk.code,\n )\n\n const leaks: LeakReport[] = []\n for (const [key, value] of serverSecrets) {\n for (const [chunkName, chunk] of chunks) {\n if (chunk.code!.includes(value)) {\n leaks.push({ key, chunk: chunkName })\n }\n }\n }\n\n return leaks\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,iBACd,KACA,MACA,QACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,gBAAgB,OAAO,QAAQ,KAAK,CAAC,QACxC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,UAAU,EACzB;CAED,MAAM,SAAS,OAAO,QAAQ,OAAO,CAAC,QACnC,GAAG,WAAW,MAAM,SAAS,WAAW,CAAC,CAAC,MAAM,KAClD;CAED,MAAM,QAAsB,EAAE;AAC9B,MAAK,MAAM,CAAC,KAAK,UAAU,cACzB,MAAK,MAAM,CAAC,WAAW,UAAU,OAC/B,KAAI,MAAM,KAAM,SAAS,MAAM,CAC7B,OAAM,KAAK;EAAE;EAAK,OAAO;EAAW,CAAC;AAK3C,QAAO"}
@@ -0,0 +1,130 @@
1
+ const require_dts = require("./dts-DT7HjKrz.cjs");
2
+ const require_schema = require("./schema.cjs");
3
+ const require_config = require("./config.cjs");
4
+ const require_format = require("./format.cjs");
5
+ const require_leak = require("./leak.cjs");
6
+ let node_path = require("node:path");
7
+ node_path = require_dts.__toESM(node_path);
8
+ let node_process = require("node:process");
9
+ node_process = require_dts.__toESM(node_process);
10
+ let vite = require("vite");
11
+ //#region src/sources.ts
12
+ /**
13
+ * Merge priority (highest → lowest):
14
+ * 1. process.env (CI pipeline secrets win)
15
+ * 2. .env.[mode].local
16
+ * 3. .env.[mode]
17
+ * 4. .env.local
18
+ * 5. .env
19
+ *
20
+ * Prefix '' = load everything, schema decides what's valid.
21
+ */
22
+ async function loadEnvSources(config) {
23
+ return {
24
+ ...(0, vite.loadEnv)(config.mode, config.envDir || config.root, ""),
25
+ ...filterStrings(node_process.default.env)
26
+ };
27
+ }
28
+ function filterStrings(env) {
29
+ return Object.fromEntries(Object.entries(env).filter((entry) => typeof entry[1] === "string"));
30
+ }
31
+ //#endregion
32
+ //#region src/virtual.ts
33
+ function buildClientModule(def, data) {
34
+ const clientKeys = new Set([...Object.keys(def.client ?? {}), ...Object.keys(def.shared ?? {})]);
35
+ const clientData = Object.fromEntries(Object.entries(data).filter(([k]) => clientKeys.has(k)));
36
+ return {
37
+ moduleType: "js",
38
+ code: `// Auto-generated by @vite-env/core — do not edit
39
+ export const env = Object.freeze(${JSON.stringify(clientData, null, 2)});
40
+ export default env;`
41
+ };
42
+ }
43
+ function buildServerModule(_def, data) {
44
+ return {
45
+ moduleType: "js",
46
+ code: `// Auto-generated by @vite-env/core — do not edit
47
+ export const env = Object.freeze(${JSON.stringify(data, null, 2)});
48
+ export default env;`
49
+ };
50
+ }
51
+ //#endregion
52
+ //#region src/plugin.ts
53
+ function ViteEnv(options = {}) {
54
+ let resolvedConfig;
55
+ let envDefinition;
56
+ let lastValidated = {};
57
+ return {
58
+ name: "vite-env",
59
+ enforce: "pre",
60
+ async configResolved(config) {
61
+ resolvedConfig = config;
62
+ const configPath = node_path.default.resolve(config.root, options.configFile ?? "env.ts");
63
+ try {
64
+ envDefinition = await require_config.loadEnvConfig(configPath);
65
+ } catch (e) {
66
+ throw new Error(`[vite-env] Could not load env definition file at: ${configPath}\n Create an env.ts file and export default defineEnv({ ... })`, { cause: e });
67
+ }
68
+ },
69
+ async buildStart() {
70
+ const rawEnv = await loadEnvSources(resolvedConfig);
71
+ const result = require_schema.validateEnv(envDefinition, rawEnv);
72
+ if (!result.success) {
73
+ const formatted = require_format.formatZodError(result.errors);
74
+ throw new Error(`[vite-env] Environment validation failed:\n\n${formatted}`);
75
+ }
76
+ lastValidated = result.data;
77
+ await require_dts.generateDts(envDefinition, resolvedConfig.root);
78
+ const count = Object.keys(result.data ?? {}).length;
79
+ resolvedConfig.logger.info(` \x1B[32m✓\x1B[0m \x1B[36m[vite-env]\x1B[0m ${count} variables validated`);
80
+ },
81
+ resolveId(id) {
82
+ if (id === "virtual:env/client") return "\0virtual:env/client";
83
+ if (id === "virtual:env/server") return "\0virtual:env/server";
84
+ },
85
+ load(id) {
86
+ if (id === "\0virtual:env/client") return buildClientModule(envDefinition, lastValidated);
87
+ if (id === "\0virtual:env/server") return buildServerModule(envDefinition, lastValidated);
88
+ },
89
+ async generateBundle(_options, bundle) {
90
+ if (resolvedConfig.build.ssr) return;
91
+ const rawEnv = await loadEnvSources(resolvedConfig);
92
+ const result = require_schema.validateEnv(envDefinition, rawEnv);
93
+ if (!result.success) {
94
+ const formatted = require_format.formatZodError(result.errors);
95
+ throw new Error(`[vite-env] Env validation failed at bundle emit:\n\n${formatted}`);
96
+ }
97
+ const leaks = require_leak.detectServerLeak(envDefinition, result.data || {}, bundle);
98
+ if (leaks.length > 0) throw new Error(`[vite-env] Server environment variables detected in client bundle!\n\n${leaks.map((l) => ` ✗ ${l.key} found in ${l.chunk}`).join("\n")}\n\n These variables are marked as server-only and must never reach the browser.`);
99
+ },
100
+ configureServer(server) {
101
+ const envDir = resolvedConfig.envDir || resolvedConfig.root;
102
+ server.watcher.add(node_path.default.join(envDir, ".env*"));
103
+ let debounceTimer;
104
+ server.watcher.on("change", async (file) => {
105
+ if (!node_path.default.basename(file).startsWith(".env")) return;
106
+ clearTimeout(debounceTimer);
107
+ debounceTimer = setTimeout(async () => {
108
+ const rawEnv = await loadEnvSources(resolvedConfig);
109
+ const result = require_schema.validateEnv(envDefinition, rawEnv);
110
+ if (!result.success) {
111
+ const formatted = require_format.formatZodError(result.errors);
112
+ resolvedConfig.logger.warn(`\n \x1B[33m⚠\x1B[0m \x1B[36m[vite-env]\x1B[0m Env revalidation failed:\n${formatted}`);
113
+ return;
114
+ }
115
+ lastValidated = result.data;
116
+ const clientMod = server.moduleGraph.getModuleById("\0virtual:env/client");
117
+ if (clientMod) {
118
+ server.moduleGraph.invalidateModule(clientMod);
119
+ server.hot.send({ type: "full-reload" });
120
+ resolvedConfig.logger.info(` \x1B[32m✓\x1B[0m \x1B[36m[vite-env]\x1B[0m Env revalidated`);
121
+ }
122
+ }, 150);
123
+ });
124
+ }
125
+ };
126
+ }
127
+ //#endregion
128
+ module.exports = ViteEnv;
129
+
130
+ //# sourceMappingURL=plugin.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs","names":["process","path","loadEnvConfig","validateEnv","formatZodError","generateDts","detectServerLeak"],"sources":["../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["// @env node\nimport type { ResolvedConfig } from 'vite'\nimport process from 'node:process'\nimport { loadEnv } from 'vite'\n\n/**\n * Merge priority (highest → lowest):\n * 1. process.env (CI pipeline secrets win)\n * 2. .env.[mode].local\n * 3. .env.[mode]\n * 4. .env.local\n * 5. .env\n *\n * Prefix '' = load everything, schema decides what's valid.\n */\nexport async function loadEnvSources(\n config: ResolvedConfig,\n): Promise<Record<string, string>> {\n const fileEnv = loadEnv(\n config.mode,\n config.envDir || config.root,\n '', // no prefix filter — schema is the filter\n )\n\n return {\n ...fileEnv,\n ...filterStrings(process.env),\n }\n}\n\nfunction filterStrings(env: NodeJS.ProcessEnv): Record<string, string> {\n return Object.fromEntries(\n Object.entries(env).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n )\n}\n","import type { EnvDefinition } from './types'\n\nexport function buildClientModule(\n def: EnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set([\n ...Object.keys(def.client ?? {}),\n ...Object.keys(def.shared ?? {}),\n ])\n\n const clientData = Object.fromEntries(\n Object.entries(data).filter(([k]) => clientKeys.has(k)),\n )\n\n return {\n moduleType: 'js', // Required: Vite 8 / Rolldown explicit moduleType\n code: `// Auto-generated by @vite-env/core — do not edit\nexport const env = Object.freeze(${JSON.stringify(clientData, null, 2)});\nexport default env;`,\n }\n}\n\nexport function buildServerModule(\n _def: EnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — do not edit\nexport const env = Object.freeze(${JSON.stringify(data, null, 2)});\nexport default env;`,\n }\n}\n","// @env node\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { EnvDefinition } from './types'\nimport path from 'node:path'\nimport { loadEnvConfig } from './config'\nimport { generateDts } from './dts'\nimport { formatZodError } from './format'\nimport { detectServerLeak } from './leak'\nimport { validateEnv } from './schema'\nimport { loadEnvSources } from './sources'\nimport { buildClientModule, buildServerModule } from './virtual'\n\nexport interface ViteEnvOptions {\n /**\n * Path to env definition file.\n * @default './env.ts' (resolved from project root)\n */\n configFile?: string\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: EnvDefinition\n let lastValidated: Record<string, unknown> = {}\n\n return {\n name: 'vite-env',\n enforce: 'pre',\n\n async configResolved(config) {\n resolvedConfig = config\n\n const configPath = path.resolve(\n config.root,\n options.configFile ?? 'env.ts',\n )\n\n try {\n envDefinition = await loadEnvConfig(configPath)\n }\n catch (e) {\n throw new Error(\n `[vite-env] Could not load env definition file at: ${configPath}\\n`\n + ` Create an env.ts file and export default defineEnv({ ... })`,\n { cause: e },\n )\n }\n },\n\n async buildStart() {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${formatted}`,\n )\n }\n\n lastValidated = result.data!\n\n await generateDts(envDefinition, resolvedConfig.root)\n\n const count = Object.keys(result.data ?? {}).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(id) {\n if (id === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (id === 'virtual:env/server')\n return '\\0virtual:env/server'\n },\n\n load(id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server')\n return buildServerModule(envDefinition, lastValidated)\n },\n\n async generateBundle(_options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n throw new Error(\n `[vite-env] Env validation failed at bundle emit:\\n\\n${formatted}`,\n )\n }\n\n const leaks = detectServerLeak(\n envDefinition,\n result.data || {},\n bundle as Record<string, { type: string, code?: string }>,\n )\n\n if (leaks.length > 0) {\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n }\\n\\n These variables are marked as server-only and must never reach the browser.`,\n )\n }\n },\n\n configureServer(server) {\n const envDir = resolvedConfig.envDir || resolvedConfig.root\n server.watcher.add(path.join(envDir, '.env*'))\n\n let debounceTimer: ReturnType<typeof setTimeout>\n\n server.watcher.on('change', async (file) => {\n if (!path.basename(file).startsWith('.env'))\n return\n\n clearTimeout(debounceTimer)\n debounceTimer = setTimeout(async () => {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${formatted}`,\n )\n return\n }\n\n lastValidated = result.data!\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n if (clientMod) {\n server.moduleGraph.invalidateModule(clientMod)\n server.hot.send({ type: 'full-reload' })\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidated`,\n )\n }\n }, 150) // 150ms debounce\n })\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/plugin.d.ts
4
+ interface ViteEnvOptions {
5
+ /**
6
+ * Path to env definition file.
7
+ * @default './env.ts' (resolved from project root)
8
+ */
9
+ configFile?: string;
10
+ }
11
+ declare function ViteEnv(options?: ViteEnvOptions): Plugin;
12
+ //#endregion
13
+ export { ViteEnvOptions, ViteEnv as default };
14
+ //# sourceMappingURL=plugin.d.cts.map
@@ -0,0 +1,14 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/plugin.d.ts
4
+ interface ViteEnvOptions {
5
+ /**
6
+ * Path to env definition file.
7
+ * @default './env.ts' (resolved from project root)
8
+ */
9
+ configFile?: string;
10
+ }
11
+ declare function ViteEnv(options?: ViteEnvOptions): Plugin;
12
+ //#endregion
13
+ export { ViteEnvOptions, ViteEnv as default };
14
+ //# sourceMappingURL=plugin.d.mts.map
@@ -0,0 +1,128 @@
1
+ import { validateEnv } from "./schema.mjs";
2
+ import { loadEnvConfig } from "./config.mjs";
3
+ import { generateDts } from "./dts.mjs";
4
+ import { formatZodError } from "./format.mjs";
5
+ import { detectServerLeak } from "./leak.mjs";
6
+ import path from "node:path";
7
+ import process from "node:process";
8
+ import { loadEnv } from "vite";
9
+ //#region src/sources.ts
10
+ /**
11
+ * Merge priority (highest → lowest):
12
+ * 1. process.env (CI pipeline secrets win)
13
+ * 2. .env.[mode].local
14
+ * 3. .env.[mode]
15
+ * 4. .env.local
16
+ * 5. .env
17
+ *
18
+ * Prefix '' = load everything, schema decides what's valid.
19
+ */
20
+ async function loadEnvSources(config) {
21
+ return {
22
+ ...loadEnv(config.mode, config.envDir || config.root, ""),
23
+ ...filterStrings(process.env)
24
+ };
25
+ }
26
+ function filterStrings(env) {
27
+ return Object.fromEntries(Object.entries(env).filter((entry) => typeof entry[1] === "string"));
28
+ }
29
+ //#endregion
30
+ //#region src/virtual.ts
31
+ function buildClientModule(def, data) {
32
+ const clientKeys = new Set([...Object.keys(def.client ?? {}), ...Object.keys(def.shared ?? {})]);
33
+ const clientData = Object.fromEntries(Object.entries(data).filter(([k]) => clientKeys.has(k)));
34
+ return {
35
+ moduleType: "js",
36
+ code: `// Auto-generated by @vite-env/core — do not edit
37
+ export const env = Object.freeze(${JSON.stringify(clientData, null, 2)});
38
+ export default env;`
39
+ };
40
+ }
41
+ function buildServerModule(_def, data) {
42
+ return {
43
+ moduleType: "js",
44
+ code: `// Auto-generated by @vite-env/core — do not edit
45
+ export const env = Object.freeze(${JSON.stringify(data, null, 2)});
46
+ export default env;`
47
+ };
48
+ }
49
+ //#endregion
50
+ //#region src/plugin.ts
51
+ function ViteEnv(options = {}) {
52
+ let resolvedConfig;
53
+ let envDefinition;
54
+ let lastValidated = {};
55
+ return {
56
+ name: "vite-env",
57
+ enforce: "pre",
58
+ async configResolved(config) {
59
+ resolvedConfig = config;
60
+ const configPath = path.resolve(config.root, options.configFile ?? "env.ts");
61
+ try {
62
+ envDefinition = await loadEnvConfig(configPath);
63
+ } catch (e) {
64
+ throw new Error(`[vite-env] Could not load env definition file at: ${configPath}\n Create an env.ts file and export default defineEnv({ ... })`, { cause: e });
65
+ }
66
+ },
67
+ async buildStart() {
68
+ const rawEnv = await loadEnvSources(resolvedConfig);
69
+ const result = validateEnv(envDefinition, rawEnv);
70
+ if (!result.success) {
71
+ const formatted = formatZodError(result.errors);
72
+ throw new Error(`[vite-env] Environment validation failed:\n\n${formatted}`);
73
+ }
74
+ lastValidated = result.data;
75
+ await generateDts(envDefinition, resolvedConfig.root);
76
+ const count = Object.keys(result.data ?? {}).length;
77
+ resolvedConfig.logger.info(` \x1B[32m✓\x1B[0m \x1B[36m[vite-env]\x1B[0m ${count} variables validated`);
78
+ },
79
+ resolveId(id) {
80
+ if (id === "virtual:env/client") return "\0virtual:env/client";
81
+ if (id === "virtual:env/server") return "\0virtual:env/server";
82
+ },
83
+ load(id) {
84
+ if (id === "\0virtual:env/client") return buildClientModule(envDefinition, lastValidated);
85
+ if (id === "\0virtual:env/server") return buildServerModule(envDefinition, lastValidated);
86
+ },
87
+ async generateBundle(_options, bundle) {
88
+ if (resolvedConfig.build.ssr) return;
89
+ const rawEnv = await loadEnvSources(resolvedConfig);
90
+ const result = validateEnv(envDefinition, rawEnv);
91
+ if (!result.success) {
92
+ const formatted = formatZodError(result.errors);
93
+ throw new Error(`[vite-env] Env validation failed at bundle emit:\n\n${formatted}`);
94
+ }
95
+ const leaks = detectServerLeak(envDefinition, result.data || {}, bundle);
96
+ if (leaks.length > 0) throw new Error(`[vite-env] Server environment variables detected in client bundle!\n\n${leaks.map((l) => ` ✗ ${l.key} found in ${l.chunk}`).join("\n")}\n\n These variables are marked as server-only and must never reach the browser.`);
97
+ },
98
+ configureServer(server) {
99
+ const envDir = resolvedConfig.envDir || resolvedConfig.root;
100
+ server.watcher.add(path.join(envDir, ".env*"));
101
+ let debounceTimer;
102
+ server.watcher.on("change", async (file) => {
103
+ if (!path.basename(file).startsWith(".env")) return;
104
+ clearTimeout(debounceTimer);
105
+ debounceTimer = setTimeout(async () => {
106
+ const rawEnv = await loadEnvSources(resolvedConfig);
107
+ const result = validateEnv(envDefinition, rawEnv);
108
+ if (!result.success) {
109
+ const formatted = formatZodError(result.errors);
110
+ resolvedConfig.logger.warn(`\n \x1B[33m⚠\x1B[0m \x1B[36m[vite-env]\x1B[0m Env revalidation failed:\n${formatted}`);
111
+ return;
112
+ }
113
+ lastValidated = result.data;
114
+ const clientMod = server.moduleGraph.getModuleById("\0virtual:env/client");
115
+ if (clientMod) {
116
+ server.moduleGraph.invalidateModule(clientMod);
117
+ server.hot.send({ type: "full-reload" });
118
+ resolvedConfig.logger.info(` \x1B[32m✓\x1B[0m \x1B[36m[vite-env]\x1B[0m Env revalidated`);
119
+ }
120
+ }, 150);
121
+ });
122
+ }
123
+ };
124
+ }
125
+ //#endregion
126
+ export { ViteEnv as default };
127
+
128
+ //# sourceMappingURL=plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["// @env node\nimport type { ResolvedConfig } from 'vite'\nimport process from 'node:process'\nimport { loadEnv } from 'vite'\n\n/**\n * Merge priority (highest → lowest):\n * 1. process.env (CI pipeline secrets win)\n * 2. .env.[mode].local\n * 3. .env.[mode]\n * 4. .env.local\n * 5. .env\n *\n * Prefix '' = load everything, schema decides what's valid.\n */\nexport async function loadEnvSources(\n config: ResolvedConfig,\n): Promise<Record<string, string>> {\n const fileEnv = loadEnv(\n config.mode,\n config.envDir || config.root,\n '', // no prefix filter — schema is the filter\n )\n\n return {\n ...fileEnv,\n ...filterStrings(process.env),\n }\n}\n\nfunction filterStrings(env: NodeJS.ProcessEnv): Record<string, string> {\n return Object.fromEntries(\n Object.entries(env).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n )\n}\n","import type { EnvDefinition } from './types'\n\nexport function buildClientModule(\n def: EnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set([\n ...Object.keys(def.client ?? {}),\n ...Object.keys(def.shared ?? {}),\n ])\n\n const clientData = Object.fromEntries(\n Object.entries(data).filter(([k]) => clientKeys.has(k)),\n )\n\n return {\n moduleType: 'js', // Required: Vite 8 / Rolldown explicit moduleType\n code: `// Auto-generated by @vite-env/core — do not edit\nexport const env = Object.freeze(${JSON.stringify(clientData, null, 2)});\nexport default env;`,\n }\n}\n\nexport function buildServerModule(\n _def: EnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — do not edit\nexport const env = Object.freeze(${JSON.stringify(data, null, 2)});\nexport default env;`,\n }\n}\n","// @env node\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { EnvDefinition } from './types'\nimport path from 'node:path'\nimport { loadEnvConfig } from './config'\nimport { generateDts } from './dts'\nimport { formatZodError } from './format'\nimport { detectServerLeak } from './leak'\nimport { validateEnv } from './schema'\nimport { loadEnvSources } from './sources'\nimport { buildClientModule, buildServerModule } from './virtual'\n\nexport interface ViteEnvOptions {\n /**\n * Path to env definition file.\n * @default './env.ts' (resolved from project root)\n */\n configFile?: string\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: EnvDefinition\n let lastValidated: Record<string, unknown> = {}\n\n return {\n name: 'vite-env',\n enforce: 'pre',\n\n async configResolved(config) {\n resolvedConfig = config\n\n const configPath = path.resolve(\n config.root,\n options.configFile ?? 'env.ts',\n )\n\n try {\n envDefinition = await loadEnvConfig(configPath)\n }\n catch (e) {\n throw new Error(\n `[vite-env] Could not load env definition file at: ${configPath}\\n`\n + ` Create an env.ts file and export default defineEnv({ ... })`,\n { cause: e },\n )\n }\n },\n\n async buildStart() {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${formatted}`,\n )\n }\n\n lastValidated = result.data!\n\n await generateDts(envDefinition, resolvedConfig.root)\n\n const count = Object.keys(result.data ?? {}).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(id) {\n if (id === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (id === 'virtual:env/server')\n return '\\0virtual:env/server'\n },\n\n load(id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server')\n return buildServerModule(envDefinition, lastValidated)\n },\n\n async generateBundle(_options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n throw new Error(\n `[vite-env] Env validation failed at bundle emit:\\n\\n${formatted}`,\n )\n }\n\n const leaks = detectServerLeak(\n envDefinition,\n result.data || {},\n bundle as Record<string, { type: string, code?: string }>,\n )\n\n if (leaks.length > 0) {\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n }\\n\\n These variables are marked as server-only and must never reach the browser.`,\n )\n }\n },\n\n configureServer(server) {\n const envDir = resolvedConfig.envDir || resolvedConfig.root\n server.watcher.add(path.join(envDir, '.env*'))\n\n let debounceTimer: ReturnType<typeof setTimeout>\n\n server.watcher.on('change', async (file) => {\n if (!path.basename(file).startsWith('.env'))\n return\n\n clearTimeout(debounceTimer)\n debounceTimer = setTimeout(async () => {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = validateEnv(envDefinition, rawEnv)\n\n if (!result.success) {\n const formatted = formatZodError(result.errors)\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${formatted}`,\n )\n return\n }\n\n lastValidated = result.data!\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n if (clientMod) {\n server.moduleGraph.invalidateModule(clientMod)\n server.hot.send({ type: 'full-reload' })\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidated`,\n )\n }\n }, 150) // 150ms debounce\n })\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./dts-DT7HjKrz.cjs");
3
+ let zod = require("zod");
4
+ //#region src/schema.ts
5
+ function defineEnv(definition) {
6
+ if (definition.client) {
7
+ for (const key of Object.keys(definition.client)) if (!key.startsWith("VITE_")) throw new Error(`[vite-env] Client env var "${key}" must be prefixed with VITE_.\n Rename it to "VITE_${key}" or move it to "server" if it's secret.`);
8
+ }
9
+ return definition;
10
+ }
11
+ function validateEnv(def, rawEnv) {
12
+ const combinedShape = {
13
+ ...def.server,
14
+ ...def.client,
15
+ ...def.shared
16
+ };
17
+ const result = zod.z.object(combinedShape).safeParse(rawEnv);
18
+ if (result.success) return {
19
+ success: true,
20
+ data: result.data,
21
+ errors: []
22
+ };
23
+ return {
24
+ success: false,
25
+ data: null,
26
+ errors: result.error.issues
27
+ };
28
+ }
29
+ //#endregion
30
+ exports.defineEnv = defineEnv;
31
+ exports.validateEnv = validateEnv;
32
+
33
+ //# sourceMappingURL=schema.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.cjs","names":["z"],"sources":["../src/schema.ts"],"sourcesContent":["import type { EnvDefinition, ValidationResult } from './types'\nimport { z } from 'zod'\n\nexport function defineEnv(definition: EnvDefinition): EnvDefinition {\n if (definition.client) {\n for (const key of Object.keys(definition.client)) {\n if (!key.startsWith('VITE_')) {\n throw new Error(\n `[vite-env] Client env var \"${key}\" must be prefixed with VITE_.\\n`\n + ` Rename it to \"VITE_${key}\" or move it to \"server\" if it's secret.`,\n )\n }\n }\n }\n return definition\n}\n\nexport function validateEnv(\n def: EnvDefinition,\n rawEnv: Record<string, string>,\n): ValidationResult {\n const combinedShape = {\n ...def.server,\n ...def.client,\n ...def.shared,\n }\n\n const schema = z.object(combinedShape)\n const result = schema.safeParse(rawEnv)\n\n if (result.success) {\n return { success: true, data: result.data, errors: [] }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;;;AAGA,SAAgB,UAAU,YAA0C;AAClE,KAAI,WAAW;OACR,MAAM,OAAO,OAAO,KAAK,WAAW,OAAO,CAC9C,KAAI,CAAC,IAAI,WAAW,QAAQ,CAC1B,OAAM,IAAI,MACR,8BAA8B,IAAI,uDACR,IAAI,0CAC/B;;AAIP,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,GAAG,IAAI;EACP,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAGD,MAAM,SADSA,IAAAA,EAAE,OAAO,cAAc,CAChB,UAAU,OAAO;AAEvC,KAAI,OAAO,QACT,QAAO;EAAE,SAAS;EAAM,MAAM,OAAO;EAAM,QAAQ,EAAE;EAAE;AAGzD,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
@@ -0,0 +1,8 @@
1
+ import { i as ValidationResult, t as EnvDefinition } from "./types-BmEBJZdy.cjs";
2
+
3
+ //#region src/schema.d.ts
4
+ declare function defineEnv(definition: EnvDefinition): EnvDefinition;
5
+ declare function validateEnv(def: EnvDefinition, rawEnv: Record<string, string>): ValidationResult;
6
+ //#endregion
7
+ export { defineEnv, validateEnv };
8
+ //# sourceMappingURL=schema.d.cts.map
@@ -0,0 +1,8 @@
1
+ import { i as ValidationResult, t as EnvDefinition } from "./types-CLfG9amO.mjs";
2
+
3
+ //#region src/schema.d.ts
4
+ declare function defineEnv(definition: EnvDefinition): EnvDefinition;
5
+ declare function validateEnv(def: EnvDefinition, rawEnv: Record<string, string>): ValidationResult;
6
+ //#endregion
7
+ export { defineEnv, validateEnv };
8
+ //# sourceMappingURL=schema.d.mts.map
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ //#region src/schema.ts
3
+ function defineEnv(definition) {
4
+ if (definition.client) {
5
+ for (const key of Object.keys(definition.client)) if (!key.startsWith("VITE_")) throw new Error(`[vite-env] Client env var "${key}" must be prefixed with VITE_.\n Rename it to "VITE_${key}" or move it to "server" if it's secret.`);
6
+ }
7
+ return definition;
8
+ }
9
+ function validateEnv(def, rawEnv) {
10
+ const combinedShape = {
11
+ ...def.server,
12
+ ...def.client,
13
+ ...def.shared
14
+ };
15
+ const result = z.object(combinedShape).safeParse(rawEnv);
16
+ if (result.success) return {
17
+ success: true,
18
+ data: result.data,
19
+ errors: []
20
+ };
21
+ return {
22
+ success: false,
23
+ data: null,
24
+ errors: result.error.issues
25
+ };
26
+ }
27
+ //#endregion
28
+ export { defineEnv, validateEnv };
29
+
30
+ //# sourceMappingURL=schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.mjs","names":[],"sources":["../src/schema.ts"],"sourcesContent":["import type { EnvDefinition, ValidationResult } from './types'\nimport { z } from 'zod'\n\nexport function defineEnv(definition: EnvDefinition): EnvDefinition {\n if (definition.client) {\n for (const key of Object.keys(definition.client)) {\n if (!key.startsWith('VITE_')) {\n throw new Error(\n `[vite-env] Client env var \"${key}\" must be prefixed with VITE_.\\n`\n + ` Rename it to \"VITE_${key}\" or move it to \"server\" if it's secret.`,\n )\n }\n }\n }\n return definition\n}\n\nexport function validateEnv(\n def: EnvDefinition,\n rawEnv: Record<string, string>,\n): ValidationResult {\n const combinedShape = {\n ...def.server,\n ...def.client,\n ...def.shared,\n }\n\n const schema = z.object(combinedShape)\n const result = schema.safeParse(rawEnv)\n\n if (result.success) {\n return { success: true, data: result.data, errors: [] }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;AAGA,SAAgB,UAAU,YAA0C;AAClE,KAAI,WAAW;OACR,MAAM,OAAO,OAAO,KAAK,WAAW,OAAO,CAC9C,KAAI,CAAC,IAAI,WAAW,QAAQ,CAC1B,OAAM,IAAI,MACR,8BAA8B,IAAI,uDACR,IAAI,0CAC/B;;AAIP,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,GAAG,IAAI;EACP,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAGD,MAAM,SADS,EAAE,OAAO,cAAc,CAChB,UAAU,OAAO;AAEvC,KAAI,OAAO,QACT,QAAO;EAAE,SAAS;EAAM,MAAM,OAAO;EAAM,QAAQ,EAAE;EAAE;AAGzD,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/types.d.ts
4
+ interface EnvDefinition {
5
+ server?: z.ZodRawShape;
6
+ client?: z.ZodRawShape;
7
+ shared?: z.ZodRawShape;
8
+ }
9
+ interface ValidationResult {
10
+ success: boolean;
11
+ data: Record<string, unknown> | null;
12
+ errors: z.core.$ZodIssue[];
13
+ }
14
+ type InferClientEnv<T extends EnvDefinition> = z.infer<z.ZodObject<NonNullable<T['client']> & NonNullable<T['shared']>>>;
15
+ type InferServerEnv<T extends EnvDefinition> = z.infer<z.ZodObject<NonNullable<T['server']> & NonNullable<T['client']> & NonNullable<T['shared']>>>;
16
+ //#endregion
17
+ export { ValidationResult as i, InferClientEnv as n, InferServerEnv as r, EnvDefinition as t };
18
+ //# sourceMappingURL=types-BmEBJZdy.d.cts.map
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/types.d.ts
4
+ interface EnvDefinition {
5
+ server?: z.ZodRawShape;
6
+ client?: z.ZodRawShape;
7
+ shared?: z.ZodRawShape;
8
+ }
9
+ interface ValidationResult {
10
+ success: boolean;
11
+ data: Record<string, unknown> | null;
12
+ errors: z.core.$ZodIssue[];
13
+ }
14
+ type InferClientEnv<T extends EnvDefinition> = z.infer<z.ZodObject<NonNullable<T['client']> & NonNullable<T['shared']>>>;
15
+ type InferServerEnv<T extends EnvDefinition> = z.infer<z.ZodObject<NonNullable<T['server']> & NonNullable<T['client']> & NonNullable<T['shared']>>>;
16
+ //#endregion
17
+ export { ValidationResult as i, InferClientEnv as n, InferServerEnv as r, EnvDefinition as t };
18
+ //# sourceMappingURL=types-CLfG9amO.d.mts.map
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@vite-env/core",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "The env.ts layer for Vite — define once, validate everywhere, import with types",
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.mts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "./config": {
19
+ "import": {
20
+ "types": "./dist/config.d.mts",
21
+ "default": "./dist/config.mjs"
22
+ },
23
+ "require": {
24
+ "types": "./dist/config.d.cts",
25
+ "default": "./dist/config.cjs"
26
+ }
27
+ },
28
+ "./dts": {
29
+ "import": {
30
+ "types": "./dist/dts.d.mts",
31
+ "default": "./dist/dts.mjs"
32
+ },
33
+ "require": {
34
+ "types": "./dist/dts.d.cts",
35
+ "default": "./dist/dts.cjs"
36
+ }
37
+ },
38
+ "./format": {
39
+ "import": {
40
+ "types": "./dist/format.d.mts",
41
+ "default": "./dist/format.mjs"
42
+ },
43
+ "require": {
44
+ "types": "./dist/format.d.cts",
45
+ "default": "./dist/format.cjs"
46
+ }
47
+ },
48
+ "./leak": {
49
+ "import": {
50
+ "types": "./dist/leak.d.mts",
51
+ "default": "./dist/leak.mjs"
52
+ },
53
+ "require": {
54
+ "types": "./dist/leak.d.cts",
55
+ "default": "./dist/leak.cjs"
56
+ }
57
+ },
58
+ "./plugin": {
59
+ "import": {
60
+ "types": "./dist/plugin.d.mts",
61
+ "default": "./dist/plugin.mjs"
62
+ },
63
+ "require": {
64
+ "types": "./dist/plugin.d.cts",
65
+ "default": "./dist/plugin.cjs"
66
+ }
67
+ },
68
+ "./schema": {
69
+ "import": {
70
+ "types": "./dist/schema.d.mts",
71
+ "default": "./dist/schema.mjs"
72
+ },
73
+ "require": {
74
+ "types": "./dist/schema.d.cts",
75
+ "default": "./dist/schema.cjs"
76
+ }
77
+ },
78
+ "./package.json": "./package.json"
79
+ },
80
+ "main": "./dist/index.cjs",
81
+ "module": "./dist/index.mjs",
82
+ "types": "./dist/index.d.cts",
83
+ "files": [
84
+ "dist"
85
+ ],
86
+ "engines": {
87
+ "node": ">=20.19.0"
88
+ },
89
+ "peerDependencies": {
90
+ "vite": ">=8.0.0",
91
+ "zod": "^4.0.0"
92
+ },
93
+ "dependencies": {
94
+ "jiti": "^2.6.1"
95
+ },
96
+ "devDependencies": {
97
+ "@types/node": "^25.5.2",
98
+ "@vitest/coverage-v8": "^4.1.2",
99
+ "tsdown": "^0.21.7",
100
+ "typescript": "^6.0.2",
101
+ "vite": "^8.0.3",
102
+ "vitest": "^4.1.2",
103
+ "zod": "^4.3.6"
104
+ },
105
+ "scripts": {
106
+ "build": "tsdown",
107
+ "dev": "tsdown --watch",
108
+ "test": "vitest run",
109
+ "typecheck": "tsc --noEmit"
110
+ }
111
+ }