@vite-env/core 0.4.0 → 0.5.1

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/README.md CHANGED
@@ -6,8 +6,10 @@ The `env.ts` layer for Vite — define once, validate everywhere, import with ty
6
6
 
7
7
  - Typed virtual modules (`virtual:env/client`, `virtual:env/server`)
8
8
  - Server/client split with build-time leak detection
9
+ - Runtime access protection — warns or errors when `virtual:env/server` is imported from a client environment
9
10
  - Auto-coercion via Zod v4 (`z.stringbool()`, `z.coerce.number()`)
10
11
  - Standard Schema support — use Valibot, ArkType, or any compliant validator
12
+ - Platform presets — pre-built schemas for Vercel, Railway, and Netlify
11
13
  - Auto `.d.ts` generation
12
14
  - Vite 8 / Rolldown native
13
15
 
@@ -61,6 +63,22 @@ env.VITE_DARK_MODE // boolean
61
63
  env.VITE_NODE_ENV // 'development' | 'test' | 'production'
62
64
  ```
63
65
 
66
+ ### Platform presets
67
+
68
+ ```ts
69
+ import { defineEnv } from '@vite-env/core'
70
+ import { vercel } from '@vite-env/core/presets'
71
+ import { z } from 'zod'
72
+
73
+ export default defineEnv({
74
+ presets: [vercel],
75
+ server: { DATABASE_URL: z.url() },
76
+ client: { VITE_API_URL: z.url() },
77
+ })
78
+ ```
79
+
80
+ Available presets: `vercel`, `railway`, `netlify`.
81
+
64
82
  See the [full documentation](https://pyyupsk.github.io/vite-env/) for server/client split details, CLI tools, and more.
65
83
 
66
84
  ## License
@@ -1 +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: Record<string, unknown> = await jiti.import(configPath) as any\n const def: unknown = mod.default ?? mod\n\n if (!def || typeof def !== 'object') {\n throw new Error(\n `[vite-env] env config at ${configPath} must export an object (got ${typeof def}).\\n`\n + ` Use: export default defineEnv({ ... })`,\n )\n }\n\n return def as EnvDefinition\n}\n"],"mappings":";;;;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAA+B,OAAA,GAAA,KAAA,YADb,WAAW,CACa,OAAO,WAAW;CAClE,MAAM,MAAe,IAAI,WAAW;AAEpC,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,MACR,4BAA4B,WAAW,8BAA8B,OAAO,IAAI,8CAEjF;AAGH,QAAO"}
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<Record<string, unknown>>(configPath)\n const def: unknown = mod.default ?? mod\n\n if (!def || typeof def !== 'object') {\n throw new Error(\n `[vite-env] env config at ${configPath} must export an object (got ${typeof def}).\\n`\n + ` Use: export default defineEnv({ ... })`,\n )\n }\n\n return def as EnvDefinition\n}\n"],"mappings":";;;;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAAM,OAAA,GAAA,KAAA,YADY,WAAW,CACZ,OAAgC,WAAW;CAClE,MAAM,MAAe,IAAI,WAAW;AAEpC,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,MACR,4BAA4B,WAAW,8BAA8B,OAAO,IAAI,8CAEjF;AAGH,QAAO"}
package/dist/config.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as EnvDefinition } from "./types-1okexcwM.cjs";
1
+ import { n as EnvDefinition } from "./types-CpYkRwLM.cjs";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  declare function loadEnvConfig(configPath: string): Promise<EnvDefinition>;
package/dist/config.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as EnvDefinition } from "./types-DuWT_251.mjs";
1
+ import { n as EnvDefinition } from "./types--Km3TAdJ.mjs";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  declare function loadEnvConfig(configPath: string): Promise<EnvDefinition>;
@@ -1 +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: Record<string, unknown> = await jiti.import(configPath) as any\n const def: unknown = mod.default ?? mod\n\n if (!def || typeof def !== 'object') {\n throw new Error(\n `[vite-env] env config at ${configPath} must export an object (got ${typeof def}).\\n`\n + ` Use: export default defineEnv({ ... })`,\n )\n }\n\n return def as EnvDefinition\n}\n"],"mappings":";;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAA+B,MADxB,WAAW,WAAW,CACa,OAAO,WAAW;CAClE,MAAM,MAAe,IAAI,WAAW;AAEpC,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,MACR,4BAA4B,WAAW,8BAA8B,OAAO,IAAI,8CAEjF;AAGH,QAAO"}
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<Record<string, unknown>>(configPath)\n const def: unknown = mod.default ?? mod\n\n if (!def || typeof def !== 'object') {\n throw new Error(\n `[vite-env] env config at ${configPath} must export an object (got ${typeof def}).\\n`\n + ` Use: export default defineEnv({ ... })`,\n )\n }\n\n return def as EnvDefinition\n}\n"],"mappings":";;AAGA,eAAsB,cAAc,YAA4C;CAE9E,MAAM,MAAM,MADC,WAAW,WAAW,CACZ,OAAgC,WAAW;CAClE,MAAM,MAAe,IAAI,WAAW;AAEpC,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,MACR,4BAA4B,WAAW,8BAA8B,OAAO,IAAI,8CAEjF;AAGH,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"dts-BgHTl6hC.cjs","names":["path","fs"],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition, StandardEnvDefinition } from './types'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/**\n * Writes vite-env.d.ts for Zod definitions.\n * Uses instanceof checks to infer TypeScript types from Zod schemas.\n * Zod is loaded dynamically so this module can be imported without zod installed.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const { z } = await import('zod')\n\n const clientFields = zodShapeToTsFields(z, { ...def.client })\n const serverFields = zodShapeToTsFields(z, { ...def.server, ...def.client })\n\n await writeDts(root, clientFields, serverFields)\n}\n\n/**\n * Writes vite-env.d.ts for Standard Schema definitions.\n * All fields are typed as `string` — Standard Schema has no runtime type introspection.\n */\nexport async function generateStandardDts(\n def: StandardEnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = Object.keys(def.client ?? {})\n const serverKeys = [...Object.keys(def.server ?? {}), ...clientKeys]\n\n const clientFields = keysToTsFields(clientKeys)\n const serverFields = keysToTsFields(serverKeys)\n\n await writeDts(root, clientFields, serverFields, '(Standard Schema)')\n}\n\nasync function writeDts(\n root: string,\n clientFields: string,\n serverFields: string,\n tag = '',\n): Promise<void> {\n const header = tag\n ? `// Auto-generated by @vite-env/core ${tag}\\n// Do not edit manually — re-generated on every dev server start and build\\n// Tip: for richer types, use defineEnv() with Zod instead of defineStandardEnv()`\n : `// Auto-generated by @vite-env/core\\n// Do not edit manually — re-generated on every dev server start and build`\n\n const dts = `${header}\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 const filePath = path.join(root, 'vite-env.d.ts')\n try {\n await fs.writeFile(filePath, dts, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env.d.ts to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n\nfunction keysToTsFields(keys: string[]): string {\n return keys\n .map(key => ` readonly ${key}: string`)\n .join('\\n')\n}\n\nfunction zodShapeToTsFields(z: any, shape: Record<string, unknown>): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n const tsType = zodToTs(z, schema)\n const optional = schema instanceof z.ZodOptional\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(z: any, schema: any): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(z, schema.unwrap())\n if (schema instanceof z.ZodDefault)\n return zodToTs(z, schema.def.innerType)\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(z, schema.def.out)\n return 'string'\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,EAAE,MAAM,MAAM,OAAO;AAK3B,OAAM,SAAS,MAHM,mBAAmB,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,EACxC,mBAAmB,GAAG;EAAE,GAAG,IAAI;EAAQ,GAAG,IAAI;EAAQ,CAAC,CAE5B;;;;;;AAOlD,eAAsB,oBACpB,KACA,MACe;CACf,MAAM,aAAa,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC;CAChD,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,EAAE,GAAG,WAAW;AAKpE,OAAM,SAAS,MAHM,eAAe,WAAW,EAC1B,eAAe,WAAW,EAEE,oBAAoB;;AAGvE,eAAe,SACb,MACA,cACA,cACA,MAAM,IACS;CAKf,MAAM,MAAM,GAJG,MACX,uCAAuC,IAAI,mKAC3C,kHAEkB;;;;EAItB,aAAa;;;;;;;;EAQb,aAAa;;;;;;CAOb,MAAM,WAAWA,UAAAA,QAAK,KAAK,MAAM,gBAAgB;AACjD,KAAI;AACF,QAAMC,iBAAAA,QAAG,UAAU,UAAU,KAAK,QAAQ;UAErC,GAAG;AACR,QAAM,IAAI,MACR,+CAA+C,KAAK,4BACpD,EAAE,OAAO,GAAG,CACb;;;AAIL,SAAS,eAAe,MAAwB;AAC9C,QAAO,KACJ,KAAI,QAAO,gBAAgB,IAAI,UAAU,CACzC,KAAK,KAAK;;AAGf,SAAS,mBAAmB,GAAQ,OAAwC;AAC1E,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EACtB,MAAM,SAAS,QAAQ,GAAG,OAAO;AAEjC,SAAO,gBAAgB,MADN,kBAAkB,EAAE,cACG,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,GAAQ,QAAqB;AAC5C,KAAI,kBAAkB,EAAE,YACtB,QAAO,QAAQ,GAAG,OAAO,QAAQ,CAAC;AACpC,KAAI,kBAAkB,EAAE,WACtB,QAAO,QAAQ,GAAG,OAAO,IAAI,UAAU;AACzC,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,GAAG,OAAO,IAAI,IAAI;AACnC,QAAO"}
1
+ {"version":3,"file":"dts-BgHTl6hC.cjs","names":["path","fs"],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition, StandardEnvDefinition } from './types'\nimport type { z as ZodNs } from 'zod'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/**\n * Writes vite-env.d.ts for Zod definitions.\n * Uses instanceof checks to infer TypeScript types from Zod schemas.\n * Zod is loaded dynamically so this module can be imported without zod installed.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const { z } = await import('zod')\n\n const clientFields = zodShapeToTsFields(z, { ...def.client })\n const serverFields = zodShapeToTsFields(z, { ...def.server, ...def.client })\n\n await writeDts(root, clientFields, serverFields)\n}\n\n/**\n * Writes vite-env.d.ts for Standard Schema definitions.\n * All fields are typed as `string` — Standard Schema has no runtime type introspection.\n */\nexport async function generateStandardDts(\n def: StandardEnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = Object.keys(def.client ?? {})\n const serverKeys = [...Object.keys(def.server ?? {}), ...clientKeys]\n\n const clientFields = keysToTsFields(clientKeys)\n const serverFields = keysToTsFields(serverKeys)\n\n await writeDts(root, clientFields, serverFields, '(Standard Schema)')\n}\n\nasync function writeDts(\n root: string,\n clientFields: string,\n serverFields: string,\n tag = '',\n): Promise<void> {\n const header = tag\n ? `// Auto-generated by @vite-env/core ${tag}\\n// Do not edit manually — re-generated on every dev server start and build\\n// Tip: for richer types, use defineEnv() with Zod instead of defineStandardEnv()`\n : `// Auto-generated by @vite-env/core\\n// Do not edit manually — re-generated on every dev server start and build`\n\n const dts = `${header}\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 const filePath = path.join(root, 'vite-env.d.ts')\n try {\n await fs.writeFile(filePath, dts, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env.d.ts to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n\nfunction keysToTsFields(keys: string[]): string {\n return keys\n .map(key => ` readonly ${key}: string`)\n .join('\\n')\n}\n\nfunction zodShapeToTsFields(z: typeof ZodNs, shape: Record<string, unknown>): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n const tsType = zodToTs(z, schema)\n const optional = schema instanceof z.ZodOptional\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(z: typeof ZodNs, schema: unknown): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(z, schema.unwrap())\n if (schema instanceof z.ZodDefault)\n return zodToTs(z, schema.def.innerType)\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(z, schema.def.out)\n return 'string'\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,EAAE,MAAM,MAAM,OAAO;AAK3B,OAAM,SAAS,MAHM,mBAAmB,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,EACxC,mBAAmB,GAAG;EAAE,GAAG,IAAI;EAAQ,GAAG,IAAI;EAAQ,CAAC,CAE5B;;;;;;AAOlD,eAAsB,oBACpB,KACA,MACe;CACf,MAAM,aAAa,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC;CAChD,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,EAAE,GAAG,WAAW;AAKpE,OAAM,SAAS,MAHM,eAAe,WAAW,EAC1B,eAAe,WAAW,EAEE,oBAAoB;;AAGvE,eAAe,SACb,MACA,cACA,cACA,MAAM,IACS;CAKf,MAAM,MAAM,GAJG,MACX,uCAAuC,IAAI,mKAC3C,kHAEkB;;;;EAItB,aAAa;;;;;;;;EAQb,aAAa;;;;;;CAOb,MAAM,WAAWA,UAAAA,QAAK,KAAK,MAAM,gBAAgB;AACjD,KAAI;AACF,QAAMC,iBAAAA,QAAG,UAAU,UAAU,KAAK,QAAQ;UAErC,GAAG;AACR,QAAM,IAAI,MACR,+CAA+C,KAAK,4BACpD,EAAE,OAAO,GAAG,CACb;;;AAIL,SAAS,eAAe,MAAwB;AAC9C,QAAO,KACJ,KAAI,QAAO,gBAAgB,IAAI,UAAU,CACzC,KAAK,KAAK;;AAGf,SAAS,mBAAmB,GAAiB,OAAwC;AACnF,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EACtB,MAAM,SAAS,QAAQ,GAAG,OAAO;AAEjC,SAAO,gBAAgB,MADN,kBAAkB,EAAE,cACG,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,GAAiB,QAAyB;AACzD,KAAI,kBAAkB,EAAE,YACtB,QAAO,QAAQ,GAAG,OAAO,QAAQ,CAAC;AACpC,KAAI,kBAAkB,EAAE,WACtB,QAAO,QAAQ,GAAG,OAAO,IAAI,UAAU;AACzC,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,GAAG,OAAO,IAAI,IAAI;AACnC,QAAO"}
package/dist/dts.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, n as EnvDefinition } from "./types-1okexcwM.cjs";
1
+ import { n as EnvDefinition, o as StandardEnvDefinition } from "./types-CpYkRwLM.cjs";
2
2
 
3
3
  //#region src/dts.d.ts
4
4
  /**
package/dist/dts.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, n as EnvDefinition } from "./types-DuWT_251.mjs";
1
+ import { n as EnvDefinition, o as StandardEnvDefinition } from "./types--Km3TAdJ.mjs";
2
2
 
3
3
  //#region src/dts.d.ts
4
4
  /**
package/dist/dts.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dts.mjs","names":[],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition, StandardEnvDefinition } from './types'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/**\n * Writes vite-env.d.ts for Zod definitions.\n * Uses instanceof checks to infer TypeScript types from Zod schemas.\n * Zod is loaded dynamically so this module can be imported without zod installed.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const { z } = await import('zod')\n\n const clientFields = zodShapeToTsFields(z, { ...def.client })\n const serverFields = zodShapeToTsFields(z, { ...def.server, ...def.client })\n\n await writeDts(root, clientFields, serverFields)\n}\n\n/**\n * Writes vite-env.d.ts for Standard Schema definitions.\n * All fields are typed as `string` — Standard Schema has no runtime type introspection.\n */\nexport async function generateStandardDts(\n def: StandardEnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = Object.keys(def.client ?? {})\n const serverKeys = [...Object.keys(def.server ?? {}), ...clientKeys]\n\n const clientFields = keysToTsFields(clientKeys)\n const serverFields = keysToTsFields(serverKeys)\n\n await writeDts(root, clientFields, serverFields, '(Standard Schema)')\n}\n\nasync function writeDts(\n root: string,\n clientFields: string,\n serverFields: string,\n tag = '',\n): Promise<void> {\n const header = tag\n ? `// Auto-generated by @vite-env/core ${tag}\\n// Do not edit manually — re-generated on every dev server start and build\\n// Tip: for richer types, use defineEnv() with Zod instead of defineStandardEnv()`\n : `// Auto-generated by @vite-env/core\\n// Do not edit manually — re-generated on every dev server start and build`\n\n const dts = `${header}\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 const filePath = path.join(root, 'vite-env.d.ts')\n try {\n await fs.writeFile(filePath, dts, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env.d.ts to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n\nfunction keysToTsFields(keys: string[]): string {\n return keys\n .map(key => ` readonly ${key}: string`)\n .join('\\n')\n}\n\nfunction zodShapeToTsFields(z: any, shape: Record<string, unknown>): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n const tsType = zodToTs(z, schema)\n const optional = schema instanceof z.ZodOptional\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(z: any, schema: any): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(z, schema.unwrap())\n if (schema instanceof z.ZodDefault)\n return zodToTs(z, schema.def.innerType)\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(z, schema.def.out)\n return 'string'\n}\n"],"mappings":";;;;;;;;AAUA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,EAAE,MAAM,MAAM,OAAO;AAK3B,OAAM,SAAS,MAHM,mBAAmB,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,EACxC,mBAAmB,GAAG;EAAE,GAAG,IAAI;EAAQ,GAAG,IAAI;EAAQ,CAAC,CAE5B;;;;;;AAOlD,eAAsB,oBACpB,KACA,MACe;CACf,MAAM,aAAa,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC;CAChD,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,EAAE,GAAG,WAAW;AAKpE,OAAM,SAAS,MAHM,eAAe,WAAW,EAC1B,eAAe,WAAW,EAEE,oBAAoB;;AAGvE,eAAe,SACb,MACA,cACA,cACA,MAAM,IACS;CAKf,MAAM,MAAM,GAJG,MACX,uCAAuC,IAAI,mKAC3C,kHAEkB;;;;EAItB,aAAa;;;;;;;;EAQb,aAAa;;;;;;CAOb,MAAM,WAAW,KAAK,KAAK,MAAM,gBAAgB;AACjD,KAAI;AACF,QAAM,GAAG,UAAU,UAAU,KAAK,QAAQ;UAErC,GAAG;AACR,QAAM,IAAI,MACR,+CAA+C,KAAK,4BACpD,EAAE,OAAO,GAAG,CACb;;;AAIL,SAAS,eAAe,MAAwB;AAC9C,QAAO,KACJ,KAAI,QAAO,gBAAgB,IAAI,UAAU,CACzC,KAAK,KAAK;;AAGf,SAAS,mBAAmB,GAAQ,OAAwC;AAC1E,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EACtB,MAAM,SAAS,QAAQ,GAAG,OAAO;AAEjC,SAAO,gBAAgB,MADN,kBAAkB,EAAE,cACG,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,GAAQ,QAAqB;AAC5C,KAAI,kBAAkB,EAAE,YACtB,QAAO,QAAQ,GAAG,OAAO,QAAQ,CAAC;AACpC,KAAI,kBAAkB,EAAE,WACtB,QAAO,QAAQ,GAAG,OAAO,IAAI,UAAU;AACzC,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,GAAG,OAAO,IAAI,IAAI;AACnC,QAAO"}
1
+ {"version":3,"file":"dts.mjs","names":[],"sources":["../src/dts.ts"],"sourcesContent":["// @env node\nimport type { EnvDefinition, StandardEnvDefinition } from './types'\nimport type { z as ZodNs } from 'zod'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\n/**\n * Writes vite-env.d.ts for Zod definitions.\n * Uses instanceof checks to infer TypeScript types from Zod schemas.\n * Zod is loaded dynamically so this module can be imported without zod installed.\n */\nexport async function generateDts(\n def: EnvDefinition,\n root: string,\n): Promise<void> {\n const { z } = await import('zod')\n\n const clientFields = zodShapeToTsFields(z, { ...def.client })\n const serverFields = zodShapeToTsFields(z, { ...def.server, ...def.client })\n\n await writeDts(root, clientFields, serverFields)\n}\n\n/**\n * Writes vite-env.d.ts for Standard Schema definitions.\n * All fields are typed as `string` — Standard Schema has no runtime type introspection.\n */\nexport async function generateStandardDts(\n def: StandardEnvDefinition,\n root: string,\n): Promise<void> {\n const clientKeys = Object.keys(def.client ?? {})\n const serverKeys = [...Object.keys(def.server ?? {}), ...clientKeys]\n\n const clientFields = keysToTsFields(clientKeys)\n const serverFields = keysToTsFields(serverKeys)\n\n await writeDts(root, clientFields, serverFields, '(Standard Schema)')\n}\n\nasync function writeDts(\n root: string,\n clientFields: string,\n serverFields: string,\n tag = '',\n): Promise<void> {\n const header = tag\n ? `// Auto-generated by @vite-env/core ${tag}\\n// Do not edit manually — re-generated on every dev server start and build\\n// Tip: for richer types, use defineEnv() with Zod instead of defineStandardEnv()`\n : `// Auto-generated by @vite-env/core\\n// Do not edit manually — re-generated on every dev server start and build`\n\n const dts = `${header}\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 const filePath = path.join(root, 'vite-env.d.ts')\n try {\n await fs.writeFile(filePath, dts, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env.d.ts to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n\nfunction keysToTsFields(keys: string[]): string {\n return keys\n .map(key => ` readonly ${key}: string`)\n .join('\\n')\n}\n\nfunction zodShapeToTsFields(z: typeof ZodNs, shape: Record<string, unknown>): string {\n return Object.entries(shape)\n .map(([key, schema]) => {\n const tsType = zodToTs(z, schema)\n const optional = schema instanceof z.ZodOptional\n return ` readonly ${key}${optional ? '?' : ''}: ${tsType}`\n })\n .join('\\n')\n}\n\nfunction zodToTs(z: typeof ZodNs, schema: unknown): string {\n if (schema instanceof z.ZodOptional)\n return zodToTs(z, schema.unwrap())\n if (schema instanceof z.ZodDefault)\n return zodToTs(z, schema.def.innerType)\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(z, schema.def.out)\n return 'string'\n}\n"],"mappings":";;;;;;;;AAWA,eAAsB,YACpB,KACA,MACe;CACf,MAAM,EAAE,MAAM,MAAM,OAAO;AAK3B,OAAM,SAAS,MAHM,mBAAmB,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,EACxC,mBAAmB,GAAG;EAAE,GAAG,IAAI;EAAQ,GAAG,IAAI;EAAQ,CAAC,CAE5B;;;;;;AAOlD,eAAsB,oBACpB,KACA,MACe;CACf,MAAM,aAAa,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC;CAChD,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,EAAE,GAAG,WAAW;AAKpE,OAAM,SAAS,MAHM,eAAe,WAAW,EAC1B,eAAe,WAAW,EAEE,oBAAoB;;AAGvE,eAAe,SACb,MACA,cACA,cACA,MAAM,IACS;CAKf,MAAM,MAAM,GAJG,MACX,uCAAuC,IAAI,mKAC3C,kHAEkB;;;;EAItB,aAAa;;;;;;;;EAQb,aAAa;;;;;;CAOb,MAAM,WAAW,KAAK,KAAK,MAAM,gBAAgB;AACjD,KAAI;AACF,QAAM,GAAG,UAAU,UAAU,KAAK,QAAQ;UAErC,GAAG;AACR,QAAM,IAAI,MACR,+CAA+C,KAAK,4BACpD,EAAE,OAAO,GAAG,CACb;;;AAIL,SAAS,eAAe,MAAwB;AAC9C,QAAO,KACJ,KAAI,QAAO,gBAAgB,IAAI,UAAU,CACzC,KAAK,KAAK;;AAGf,SAAS,mBAAmB,GAAiB,OAAwC;AACnF,QAAO,OAAO,QAAQ,MAAM,CACzB,KAAK,CAAC,KAAK,YAAY;EACtB,MAAM,SAAS,QAAQ,GAAG,OAAO;AAEjC,SAAO,gBAAgB,MADN,kBAAkB,EAAE,cACG,MAAM,GAAG,IAAI;GACrD,CACD,KAAK,KAAK;;AAGf,SAAS,QAAQ,GAAiB,QAAyB;AACzD,KAAI,kBAAkB,EAAE,YACtB,QAAO,QAAQ,GAAG,OAAO,QAAQ,CAAC;AACpC,KAAI,kBAAkB,EAAE,WACtB,QAAO,QAAQ,GAAG,OAAO,IAAI,UAAU;AACzC,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,GAAG,OAAO,IAAI,IAAI;AACnC,QAAO"}
package/dist/format.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as StandardValidationIssue } from "./types-1okexcwM.cjs";
1
+ import { s as StandardValidationIssue } from "./types-CpYkRwLM.cjs";
2
2
  import { core } from "zod";
3
3
 
4
4
  //#region src/guard.d.ts
package/dist/format.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { o as StandardValidationIssue } from "./types-DuWT_251.mjs";
1
+ import { s as StandardValidationIssue } from "./types--Km3TAdJ.mjs";
2
2
  import { core } from "zod";
3
3
 
4
4
  //#region src/guard.d.ts
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, i as InferServerEnv, n as EnvDefinition, r as InferClientEnv, t as AnyEnvDefinition } from "./types-1okexcwM.cjs";
1
+ import { a as InferServerEnv, i as InferClientEnv, n as EnvDefinition, o as StandardEnvDefinition, r as EnvPreset, t as AnyEnvDefinition } from "./types-CpYkRwLM.cjs";
2
2
  import { defineEnv } from "./schema.cjs";
3
3
  import { defineStandardEnv } from "./standard.cjs";
4
- export { type AnyEnvDefinition, type EnvDefinition, type InferClientEnv, type InferServerEnv, type StandardEnvDefinition, defineEnv, defineStandardEnv };
4
+ export { type AnyEnvDefinition, type EnvDefinition, type EnvPreset, type InferClientEnv, type InferServerEnv, type StandardEnvDefinition, defineEnv, defineStandardEnv };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, i as InferServerEnv, n as EnvDefinition, r as InferClientEnv, t as AnyEnvDefinition } from "./types-DuWT_251.mjs";
1
+ import { a as InferServerEnv, i as InferClientEnv, n as EnvDefinition, o as StandardEnvDefinition, r as EnvPreset, t as AnyEnvDefinition } from "./types--Km3TAdJ.mjs";
2
2
  import { defineEnv } from "./schema.mjs";
3
3
  import { defineStandardEnv } from "./standard.mjs";
4
- export { type AnyEnvDefinition, type EnvDefinition, type InferClientEnv, type InferServerEnv, type StandardEnvDefinition, defineEnv, defineStandardEnv };
4
+ export { type AnyEnvDefinition, type EnvDefinition, type EnvPreset, type InferClientEnv, type InferServerEnv, type StandardEnvDefinition, defineEnv, defineStandardEnv };
package/dist/leak.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"leak.cjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { AnyEnvDefinition } 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: AnyEnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n onSkipped?: (keys: string[]) => void,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const shortSecrets = 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 if (shortSecrets.length > 0 && onSkipped) {\n onSkipped(shortSecrets.map(([k]) => k))\n }\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,QACA,WACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,eAAe,OAAO,QAAQ,KAAK,CAAC,QACvC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,SAAS,EACxB;AAED,KAAI,aAAa,SAAS,KAAK,UAC7B,WAAU,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC;CAGzC,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"}
1
+ {"version":3,"file":"leak.cjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { AnyEnvDefinition } from './types'\n\ntype 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: AnyEnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n onSkipped?: (keys: string[]) => void,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const shortSecrets = 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 if (shortSecrets.length > 0 && onSkipped) {\n onSkipped(shortSecrets.map(([k]) => k))\n }\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,QACA,WACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,eAAe,OAAO,QAAQ,KAAK,CAAC,QACvC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,SAAS,EACxB;AAED,KAAI,aAAa,SAAS,KAAK,UAC7B,WAAU,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC;CAGzC,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"}
package/dist/leak.d.cts CHANGED
@@ -1,10 +1,10 @@
1
- import { t as AnyEnvDefinition } from "./types-1okexcwM.cjs";
1
+ import { t as AnyEnvDefinition } from "./types-CpYkRwLM.cjs";
2
2
 
3
3
  //#region src/leak.d.ts
4
- interface LeakReport {
4
+ type LeakReport = {
5
5
  key: string;
6
6
  chunk: string;
7
- }
7
+ };
8
8
  /**
9
9
  * Scans all client-destined chunks for literal values of server-only vars.
10
10
  * Fires in generateBundle() — Rolldown sequential hook, safe.
package/dist/leak.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import { t as AnyEnvDefinition } from "./types-DuWT_251.mjs";
1
+ import { t as AnyEnvDefinition } from "./types--Km3TAdJ.mjs";
2
2
 
3
3
  //#region src/leak.d.ts
4
- interface LeakReport {
4
+ type LeakReport = {
5
5
  key: string;
6
6
  chunk: string;
7
- }
7
+ };
8
8
  /**
9
9
  * Scans all client-destined chunks for literal values of server-only vars.
10
10
  * Fires in generateBundle() — Rolldown sequential hook, safe.
package/dist/leak.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"leak.mjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { AnyEnvDefinition } 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: AnyEnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n onSkipped?: (keys: string[]) => void,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const shortSecrets = 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 if (shortSecrets.length > 0 && onSkipped) {\n onSkipped(shortSecrets.map(([k]) => k))\n }\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,QACA,WACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,eAAe,OAAO,QAAQ,KAAK,CAAC,QACvC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,SAAS,EACxB;AAED,KAAI,aAAa,SAAS,KAAK,UAC7B,WAAU,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC;CAGzC,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"}
1
+ {"version":3,"file":"leak.mjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { AnyEnvDefinition } from './types'\n\ntype 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: AnyEnvDefinition,\n data: Record<string, unknown>,\n bundle: Record<string, { type: string, code?: string }>,\n onSkipped?: (keys: string[]) => void,\n): LeakReport[] {\n const serverKeys = new Set(Object.keys(def.server ?? {}))\n\n const shortSecrets = 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 if (shortSecrets.length > 0 && onSkipped) {\n onSkipped(shortSecrets.map(([k]) => k))\n }\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,QACA,WACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,eAAe,OAAO,QAAQ,KAAK,CAAC,QACvC,UACC,WAAW,IAAI,MAAM,GAAG,IACrB,OAAO,MAAM,OAAO,YACpB,MAAM,GAAG,SAAS,EACxB;AAED,KAAI,aAAa,SAAS,KAAK,UAC7B,WAAU,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC;CAGzC,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"}
package/dist/plugin.cjs CHANGED
@@ -202,6 +202,8 @@ function ViteEnv(options = {}) {
202
202
  },
203
203
  generateBundle(_options, bundle) {
204
204
  if (resolvedConfig.build.ssr) return;
205
+ const envName = this.environment?.name ?? "client";
206
+ if (serverEnvs.includes(envName)) return;
205
207
  const leaks = require_leak.detectServerLeak(envDefinition, lastValidated, bundle, (keys) => {
206
208
  resolvedConfig.logger.warn(` \x1B[33m⚠\x1B[0m \x1B[36m[vite-env]\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(", ")}`);
207
209
  });
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs","names":["formatGuardLogEntry","path","fs","process","isStandardEnvDefinition","validateStandardEnv","formatStandardSchemaError","path","loadEnvConfig","generateStandardDts","formatHardError","formatGuardWarning","detectServerLeak"],"sources":["../src/guard.ts","../src/log.ts","../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["export type GuardMode = 'error' | 'stub' | 'warn'\n\nexport type GuardResult\n = | { allowed: true }\n | { allowed: false, mode: GuardMode, envName: string, importer: string | undefined }\n\nexport type GuardFail = Extract<GuardResult, { allowed: false }>\n\n/**\n * Determines whether the given Vite environment is allowed to import virtual:env/server.\n * Returns a GuardResult discriminated union — allowed or fail with context.\n * When this.environment is undefined (should not occur with Vite ≥ 8), callers default\n * envName to 'client' — failing closed (restrictive) is safer than failing open.\n */\nexport function checkServerModuleAccess(\n envName: string,\n serverEnvironments: string[],\n mode: GuardMode,\n importer: string | undefined,\n): GuardResult {\n if (serverEnvironments.includes(envName))\n return { allowed: true }\n return { allowed: false, mode, envName, importer }\n}\n\n/**\n * Generates the stub virtual module returned when onClientAccessOfServerModule is 'stub'.\n * The stub throws at runtime if executed — its message reflects that this import was\n * expected to be unreachable and the assumption was wrong.\n */\nexport function buildServerStubModule(envName: string): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — server-only module stub\nthrow new Error(\n '[vite-env] virtual:env/server was imported in the \"${envName}\" environment. ' +\n 'This module is server-only and was replaced with a stub. ' +\n 'To allow this environment: add it to serverEnvironments. ' +\n 'To suppress this stub: ensure this import never executes in the \"${envName}\" environment.'\n);`,\n }\n}\n","// @env node\nimport type { GuardFail } from './guard'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { formatGuardLogEntry } from './format'\n\nconst LOG_HEADER = `# vite-env warnings — generated by @vite-env/core\n# These warnings will become hard errors in 1.0.0.\n# To enforce immediately: ViteEnv({ onClientAccessOfServerModule: 'error' })\n# To acknowledge and suppress: ViteEnv({ onClientAccessOfServerModule: 'stub' })\n# To allow specific environments: ViteEnv({ serverEnvironments: ['ssr', 'workerd'] })`\n\n/**\n * Writes accumulated GuardFail entries to vite-env-warnings.log in the project root.\n * Overwrites on each build — stale entries from previous builds must not persist.\n * Called only in 'warn' mode from buildEnd, after verifying the build succeeded.\n */\nexport async function writeWarningsLog(fails: GuardFail[], root: string): Promise<void> {\n const seen = new Set<string>()\n const unique = fails.filter((fail) => {\n const key = `${fail.envName}::${fail.importer ?? ''}`\n if (seen.has(key))\n return false\n seen.add(key)\n return true\n })\n const timestamp = new Date().toISOString()\n const entries = unique.map(fail => formatGuardLogEntry(fail, timestamp)).join('\\n\\n')\n const content = `${LOG_HEADER}\\n\\n${entries}\\n`\n const filePath = path.join(root, 'vite-env-warnings.log')\n try {\n await fs.writeFile(filePath, content, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env-warnings.log to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n","// @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 { AnyEnvDefinition } from './types'\n\nexport function buildClientModule(\n def: AnyEnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set(Object.keys(def.client ?? {}))\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: AnyEnvDefinition,\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, Rollup } from 'vite'\nimport type { GuardFail } from './guard'\nimport type { AnyEnvDefinition } from './types'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { loadEnvConfig } from './config'\nimport { generateStandardDts } from './dts'\nimport { formatGuardWarning, formatHardError, formatStandardSchemaError } from './format'\nimport { buildServerStubModule, checkServerModuleAccess } from './guard'\nimport { detectServerLeak } from './leak'\nimport { writeWarningsLog } from './log'\nimport { loadEnvSources } from './sources'\nimport { isStandardEnvDefinition, validateStandardEnv } from './standard'\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 /**\n * Vite 8 environment names that are allowed to import virtual:env/server.\n * Use this to allow edge runtimes (Cloudflare Workers → 'workerd', Deno Deploy → 'ssr').\n * @default ['ssr']\n */\n serverEnvironments?: string[]\n\n /**\n * Behavior when virtual:env/server is imported from a disallowed environment.\n *\n * - 'warn' — Deprecation warning printed to terminal + vite-env-warnings.log written.\n * Build succeeds but exits with code 1. Default in 0.x releases.\n * The default will change to 'error' in 1.0.0.\n *\n * - 'error' — Hard build error. No artifacts emitted.\n *\n * - 'stub' — Returns a module that throws at runtime if the import executes.\n * Use for testing environments (Vitest jsdom) or framework isomorphic files\n * where the import exists but the code path is never reached in a server context.\n *\n * @default 'warn'\n */\n onClientAccessOfServerModule?: 'error' | 'stub' | 'warn'\n}\n\n/**\n * Validates environment variables against the definition.\n * Routes to Zod or Standard Schema path based on definition type.\n * Zod modules are loaded dynamically to avoid requiring zod for Standard Schema users.\n */\nasync function validateAndFormat(\n def: AnyEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<{ data: Record<string, unknown> } | { error: string }> {\n if (isStandardEnvDefinition(def)) {\n const result = await validateStandardEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatStandardSchemaError(result.errors) }\n }\n return { data: result.data }\n }\n\n const { validateEnv } = await import('./schema')\n const { formatZodError } = await import('./format')\n const result = validateEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatZodError(result.errors) }\n }\n return { data: result.data }\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: AnyEnvDefinition\n let lastValidated: Record<string, unknown> = {}\n let serverModuleGuardFails: GuardFail[] = []\n let didSetExitCode = false\n\n const serverEnvs = options.serverEnvironments ?? ['ssr']\n const guardMode = options.onClientAccessOfServerModule ?? 'warn'\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 serverModuleGuardFails = []\n if (didSetExitCode) {\n process.exitCode = 0\n didSetExitCode = false\n }\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${result.error}`,\n )\n }\n\n lastValidated = result.data\n\n if (isStandardEnvDefinition(envDefinition)) {\n await generateStandardDts(envDefinition, resolvedConfig.root)\n }\n else {\n const { generateDts } = await import('./dts')\n await generateDts(envDefinition, resolvedConfig.root)\n }\n\n const count = Object.keys(lastValidated).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(this: Rollup.PluginContext, source, importer) {\n if (source === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (source === 'virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n const result = checkServerModuleAccess(envName, serverEnvs, guardMode, importer)\n if (!result.allowed)\n serverModuleGuardFails.push(result)\n return '\\0virtual:env/server'\n }\n },\n\n load(this: Rollup.PluginContext, id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n // Filter to fails from this environment only — other envs may have recorded fails for their own loads\n const envFails = serverModuleGuardFails.filter(f => f.envName === envName)\n if (envFails.length > 0) {\n // warn once per load cycle using the last recorded fail; unique importers are written to the log file\n const latest = envFails.at(-1)!\n if (latest.mode === 'error')\n throw new Error(formatHardError(latest))\n if (latest.mode === 'stub')\n return buildServerStubModule(envName)\n resolvedConfig.logger.warn(`\\n${formatGuardWarning(latest)}`)\n }\n return buildServerModule(envDefinition, lastValidated)\n }\n },\n\n async buildEnd(error) {\n if (error)\n return\n if (serverModuleGuardFails.length === 0)\n return\n if (guardMode !== 'warn')\n return\n await writeWarningsLog(serverModuleGuardFails, resolvedConfig.root)\n process.exitCode = 1\n didSetExitCode = true\n },\n\n generateBundle(_options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const leaks = detectServerLeak(\n envDefinition,\n lastValidated,\n bundle as Record<string, { type: string, code?: string }>,\n (keys) => {\n resolvedConfig.logger.warn(\n ` \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(', ')}`,\n )\n },\n )\n\n if (leaks.length > 0) {\n const details = leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${details}\\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 try {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${result.error}`,\n )\n return\n }\n\n lastValidated = result.data\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n const serverMod = server.moduleGraph.getModuleById('\\0virtual:env/server')\n if (clientMod)\n server.moduleGraph.invalidateModule(clientMod)\n if (serverMod)\n server.moduleGraph.invalidateModule(serverMod)\n if (clientMod || serverMod) {\n serverModuleGuardFails = []\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 }\n catch (e) {\n resolvedConfig.logger.error(\n `\\n \\x1B[31m✗\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Failed to reload env files: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }, 150)\n })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs","names":["formatGuardLogEntry","path","fs","process","isStandardEnvDefinition","validateStandardEnv","formatStandardSchemaError","path","loadEnvConfig","generateStandardDts","formatHardError","formatGuardWarning","detectServerLeak"],"sources":["../src/guard.ts","../src/log.ts","../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["export type GuardMode = 'error' | 'stub' | 'warn'\n\nexport type GuardResult\n = | { allowed: true }\n | { allowed: false, mode: GuardMode, envName: string, importer: string | undefined }\n\nexport type GuardFail = Extract<GuardResult, { allowed: false }>\n\n/**\n * Determines whether the given Vite environment is allowed to import virtual:env/server.\n * Returns a GuardResult discriminated union — allowed or fail with context.\n * When this.environment is undefined (should not occur with Vite ≥ 8), callers default\n * envName to 'client' — failing closed (restrictive) is safer than failing open.\n */\nexport function checkServerModuleAccess(\n envName: string,\n serverEnvironments: string[],\n mode: GuardMode,\n importer: string | undefined,\n): GuardResult {\n if (serverEnvironments.includes(envName))\n return { allowed: true }\n return { allowed: false, mode, envName, importer }\n}\n\n/**\n * Generates the stub virtual module returned when onClientAccessOfServerModule is 'stub'.\n * The stub throws at runtime if executed — its message reflects that this import was\n * expected to be unreachable and the assumption was wrong.\n */\nexport function buildServerStubModule(envName: string): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — server-only module stub\nthrow new Error(\n '[vite-env] virtual:env/server was imported in the \"${envName}\" environment. ' +\n 'This module is server-only and was replaced with a stub. ' +\n 'To allow this environment: add it to serverEnvironments. ' +\n 'To suppress this stub: ensure this import never executes in the \"${envName}\" environment.'\n);`,\n }\n}\n","// @env node\nimport type { GuardFail } from './guard'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { formatGuardLogEntry } from './format'\n\nconst LOG_HEADER = `# vite-env warnings — generated by @vite-env/core\n# These warnings will become hard errors in 1.0.0.\n# To enforce immediately: ViteEnv({ onClientAccessOfServerModule: 'error' })\n# To acknowledge and suppress: ViteEnv({ onClientAccessOfServerModule: 'stub' })\n# To allow specific environments: ViteEnv({ serverEnvironments: ['ssr', 'workerd'] })`\n\n/**\n * Writes accumulated GuardFail entries to vite-env-warnings.log in the project root.\n * Overwrites on each build — stale entries from previous builds must not persist.\n * Called only in 'warn' mode from buildEnd, after verifying the build succeeded.\n */\nexport async function writeWarningsLog(fails: GuardFail[], root: string): Promise<void> {\n const seen = new Set<string>()\n const unique = fails.filter((fail) => {\n const key = `${fail.envName}::${fail.importer ?? ''}`\n if (seen.has(key))\n return false\n seen.add(key)\n return true\n })\n const timestamp = new Date().toISOString()\n const entries = unique.map(fail => formatGuardLogEntry(fail, timestamp)).join('\\n\\n')\n const content = `${LOG_HEADER}\\n\\n${entries}\\n`\n const filePath = path.join(root, 'vite-env-warnings.log')\n try {\n await fs.writeFile(filePath, content, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env-warnings.log to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n","// @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 { AnyEnvDefinition } from './types'\n\nexport function buildClientModule(\n def: AnyEnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set(Object.keys(def.client ?? {}))\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: AnyEnvDefinition,\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, Rollup } from 'vite'\nimport type { GuardFail } from './guard'\nimport type { AnyEnvDefinition } from './types'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { loadEnvConfig } from './config'\nimport { generateStandardDts } from './dts'\nimport { formatGuardWarning, formatHardError, formatStandardSchemaError } from './format'\nimport { buildServerStubModule, checkServerModuleAccess } from './guard'\nimport { detectServerLeak } from './leak'\nimport { writeWarningsLog } from './log'\nimport { loadEnvSources } from './sources'\nimport { isStandardEnvDefinition, validateStandardEnv } from './standard'\nimport { buildClientModule, buildServerModule } from './virtual'\n\nexport type ViteEnvOptions = {\n /**\n * Path to env definition file.\n * @default './env.ts' (resolved from project root)\n */\n configFile?: string\n\n /**\n * Vite 8 environment names that are allowed to import virtual:env/server.\n * Use this to allow edge runtimes (Cloudflare Workers → 'workerd', Deno Deploy → 'ssr').\n * @default ['ssr']\n */\n serverEnvironments?: string[]\n\n /**\n * Behavior when virtual:env/server is imported from a disallowed environment.\n *\n * - 'warn' — Deprecation warning printed to terminal + vite-env-warnings.log written.\n * Build succeeds but exits with code 1. Default in 0.x releases.\n * The default will change to 'error' in 1.0.0.\n *\n * - 'error' — Hard build error. No artifacts emitted.\n *\n * - 'stub' — Returns a module that throws at runtime if the import executes.\n * Use for testing environments (Vitest jsdom) or framework isomorphic files\n * where the import exists but the code path is never reached in a server context.\n *\n * @default 'warn'\n */\n onClientAccessOfServerModule?: 'error' | 'stub' | 'warn'\n}\n\n/**\n * Validates environment variables against the definition.\n * Routes to Zod or Standard Schema path based on definition type.\n * Zod modules are loaded dynamically to avoid requiring zod for Standard Schema users.\n */\nasync function validateAndFormat(\n def: AnyEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<{ data: Record<string, unknown> } | { error: string }> {\n if (isStandardEnvDefinition(def)) {\n const result = await validateStandardEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatStandardSchemaError(result.errors) }\n }\n return { data: result.data }\n }\n\n const { validateEnv } = await import('./schema')\n const { formatZodError } = await import('./format')\n const result = validateEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatZodError(result.errors) }\n }\n return { data: result.data }\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: AnyEnvDefinition\n let lastValidated: Record<string, unknown> = {}\n let serverModuleGuardFails: GuardFail[] = []\n let didSetExitCode = false\n\n const serverEnvs = options.serverEnvironments ?? ['ssr']\n const guardMode = options.onClientAccessOfServerModule ?? 'warn'\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 serverModuleGuardFails = []\n if (didSetExitCode) {\n process.exitCode = 0\n didSetExitCode = false\n }\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${result.error}`,\n )\n }\n\n lastValidated = result.data\n\n if (isStandardEnvDefinition(envDefinition)) {\n await generateStandardDts(envDefinition, resolvedConfig.root)\n }\n else {\n const { generateDts } = await import('./dts')\n await generateDts(envDefinition, resolvedConfig.root)\n }\n\n const count = Object.keys(lastValidated).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(this: Rollup.PluginContext, source, importer) {\n if (source === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (source === 'virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n const result = checkServerModuleAccess(envName, serverEnvs, guardMode, importer)\n if (!result.allowed)\n serverModuleGuardFails.push(result)\n return '\\0virtual:env/server'\n }\n },\n\n load(this: Rollup.PluginContext, id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n // Filter to fails from this environment only — other envs may have recorded fails for their own loads\n const envFails = serverModuleGuardFails.filter(f => f.envName === envName)\n if (envFails.length > 0) {\n // warn once per load cycle using the last recorded fail; unique importers are written to the log file\n const latest = envFails.at(-1)!\n if (latest.mode === 'error')\n throw new Error(formatHardError(latest))\n if (latest.mode === 'stub')\n return buildServerStubModule(envName)\n resolvedConfig.logger.warn(`\\n${formatGuardWarning(latest)}`)\n }\n return buildServerModule(envDefinition, lastValidated)\n }\n },\n\n async buildEnd(error) {\n if (error)\n return\n if (serverModuleGuardFails.length === 0)\n return\n if (guardMode !== 'warn')\n return\n await writeWarningsLog(serverModuleGuardFails, resolvedConfig.root)\n process.exitCode = 1\n didSetExitCode = true\n },\n\n generateBundle(this: Rollup.PluginContext, _options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const envName = this.environment?.name ?? 'client'\n if (serverEnvs.includes(envName))\n return\n\n const leaks = detectServerLeak(\n envDefinition,\n lastValidated,\n bundle as Record<string, { type: string, code?: string }>,\n (keys) => {\n resolvedConfig.logger.warn(\n ` \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(', ')}`,\n )\n },\n )\n\n if (leaks.length > 0) {\n const details = leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${details}\\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 try {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${result.error}`,\n )\n return\n }\n\n lastValidated = result.data\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n const serverMod = server.moduleGraph.getModuleById('\\0virtual:env/server')\n if (clientMod)\n server.moduleGraph.invalidateModule(clientMod)\n if (serverMod)\n server.moduleGraph.invalidateModule(serverMod)\n if (clientMod || serverMod) {\n serverModuleGuardFails = []\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 }\n catch (e) {\n resolvedConfig.logger.error(\n `\\n \\x1B[31m✗\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Failed to reload env files: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }, 150)\n })\n },\n }\n}\n"],"mappings":"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"}
package/dist/plugin.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Plugin } from "vite";
2
2
 
3
3
  //#region src/plugin.d.ts
4
- interface ViteEnvOptions {
4
+ type ViteEnvOptions = {
5
5
  /**
6
6
  * Path to env definition file.
7
7
  * @default './env.ts' (resolved from project root)
@@ -29,7 +29,7 @@ interface ViteEnvOptions {
29
29
  * @default 'warn'
30
30
  */
31
31
  onClientAccessOfServerModule?: 'error' | 'stub' | 'warn';
32
- }
32
+ };
33
33
  declare function ViteEnv(options?: ViteEnvOptions): Plugin;
34
34
  //#endregion
35
35
  export { ViteEnvOptions, ViteEnv as default };
package/dist/plugin.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Plugin } from "vite";
2
2
 
3
3
  //#region src/plugin.d.ts
4
- interface ViteEnvOptions {
4
+ type ViteEnvOptions = {
5
5
  /**
6
6
  * Path to env definition file.
7
7
  * @default './env.ts' (resolved from project root)
@@ -29,7 +29,7 @@ interface ViteEnvOptions {
29
29
  * @default 'warn'
30
30
  */
31
31
  onClientAccessOfServerModule?: 'error' | 'stub' | 'warn';
32
- }
32
+ };
33
33
  declare function ViteEnv(options?: ViteEnvOptions): Plugin;
34
34
  //#endregion
35
35
  export { ViteEnvOptions, ViteEnv as default };
package/dist/plugin.mjs CHANGED
@@ -199,6 +199,8 @@ function ViteEnv(options = {}) {
199
199
  },
200
200
  generateBundle(_options, bundle) {
201
201
  if (resolvedConfig.build.ssr) return;
202
+ const envName = this.environment?.name ?? "client";
203
+ if (serverEnvs.includes(envName)) return;
202
204
  const leaks = detectServerLeak(envDefinition, lastValidated, bundle, (keys) => {
203
205
  resolvedConfig.logger.warn(` \x1B[33m⚠\x1B[0m \x1B[36m[vite-env]\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(", ")}`);
204
206
  });
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/guard.ts","../src/log.ts","../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["export type GuardMode = 'error' | 'stub' | 'warn'\n\nexport type GuardResult\n = | { allowed: true }\n | { allowed: false, mode: GuardMode, envName: string, importer: string | undefined }\n\nexport type GuardFail = Extract<GuardResult, { allowed: false }>\n\n/**\n * Determines whether the given Vite environment is allowed to import virtual:env/server.\n * Returns a GuardResult discriminated union — allowed or fail with context.\n * When this.environment is undefined (should not occur with Vite ≥ 8), callers default\n * envName to 'client' — failing closed (restrictive) is safer than failing open.\n */\nexport function checkServerModuleAccess(\n envName: string,\n serverEnvironments: string[],\n mode: GuardMode,\n importer: string | undefined,\n): GuardResult {\n if (serverEnvironments.includes(envName))\n return { allowed: true }\n return { allowed: false, mode, envName, importer }\n}\n\n/**\n * Generates the stub virtual module returned when onClientAccessOfServerModule is 'stub'.\n * The stub throws at runtime if executed — its message reflects that this import was\n * expected to be unreachable and the assumption was wrong.\n */\nexport function buildServerStubModule(envName: string): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — server-only module stub\nthrow new Error(\n '[vite-env] virtual:env/server was imported in the \"${envName}\" environment. ' +\n 'This module is server-only and was replaced with a stub. ' +\n 'To allow this environment: add it to serverEnvironments. ' +\n 'To suppress this stub: ensure this import never executes in the \"${envName}\" environment.'\n);`,\n }\n}\n","// @env node\nimport type { GuardFail } from './guard'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { formatGuardLogEntry } from './format'\n\nconst LOG_HEADER = `# vite-env warnings — generated by @vite-env/core\n# These warnings will become hard errors in 1.0.0.\n# To enforce immediately: ViteEnv({ onClientAccessOfServerModule: 'error' })\n# To acknowledge and suppress: ViteEnv({ onClientAccessOfServerModule: 'stub' })\n# To allow specific environments: ViteEnv({ serverEnvironments: ['ssr', 'workerd'] })`\n\n/**\n * Writes accumulated GuardFail entries to vite-env-warnings.log in the project root.\n * Overwrites on each build — stale entries from previous builds must not persist.\n * Called only in 'warn' mode from buildEnd, after verifying the build succeeded.\n */\nexport async function writeWarningsLog(fails: GuardFail[], root: string): Promise<void> {\n const seen = new Set<string>()\n const unique = fails.filter((fail) => {\n const key = `${fail.envName}::${fail.importer ?? ''}`\n if (seen.has(key))\n return false\n seen.add(key)\n return true\n })\n const timestamp = new Date().toISOString()\n const entries = unique.map(fail => formatGuardLogEntry(fail, timestamp)).join('\\n\\n')\n const content = `${LOG_HEADER}\\n\\n${entries}\\n`\n const filePath = path.join(root, 'vite-env-warnings.log')\n try {\n await fs.writeFile(filePath, content, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env-warnings.log to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n","// @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 { AnyEnvDefinition } from './types'\n\nexport function buildClientModule(\n def: AnyEnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set(Object.keys(def.client ?? {}))\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: AnyEnvDefinition,\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, Rollup } from 'vite'\nimport type { GuardFail } from './guard'\nimport type { AnyEnvDefinition } from './types'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { loadEnvConfig } from './config'\nimport { generateStandardDts } from './dts'\nimport { formatGuardWarning, formatHardError, formatStandardSchemaError } from './format'\nimport { buildServerStubModule, checkServerModuleAccess } from './guard'\nimport { detectServerLeak } from './leak'\nimport { writeWarningsLog } from './log'\nimport { loadEnvSources } from './sources'\nimport { isStandardEnvDefinition, validateStandardEnv } from './standard'\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 /**\n * Vite 8 environment names that are allowed to import virtual:env/server.\n * Use this to allow edge runtimes (Cloudflare Workers → 'workerd', Deno Deploy → 'ssr').\n * @default ['ssr']\n */\n serverEnvironments?: string[]\n\n /**\n * Behavior when virtual:env/server is imported from a disallowed environment.\n *\n * - 'warn' — Deprecation warning printed to terminal + vite-env-warnings.log written.\n * Build succeeds but exits with code 1. Default in 0.x releases.\n * The default will change to 'error' in 1.0.0.\n *\n * - 'error' — Hard build error. No artifacts emitted.\n *\n * - 'stub' — Returns a module that throws at runtime if the import executes.\n * Use for testing environments (Vitest jsdom) or framework isomorphic files\n * where the import exists but the code path is never reached in a server context.\n *\n * @default 'warn'\n */\n onClientAccessOfServerModule?: 'error' | 'stub' | 'warn'\n}\n\n/**\n * Validates environment variables against the definition.\n * Routes to Zod or Standard Schema path based on definition type.\n * Zod modules are loaded dynamically to avoid requiring zod for Standard Schema users.\n */\nasync function validateAndFormat(\n def: AnyEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<{ data: Record<string, unknown> } | { error: string }> {\n if (isStandardEnvDefinition(def)) {\n const result = await validateStandardEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatStandardSchemaError(result.errors) }\n }\n return { data: result.data }\n }\n\n const { validateEnv } = await import('./schema')\n const { formatZodError } = await import('./format')\n const result = validateEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatZodError(result.errors) }\n }\n return { data: result.data }\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: AnyEnvDefinition\n let lastValidated: Record<string, unknown> = {}\n let serverModuleGuardFails: GuardFail[] = []\n let didSetExitCode = false\n\n const serverEnvs = options.serverEnvironments ?? ['ssr']\n const guardMode = options.onClientAccessOfServerModule ?? 'warn'\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 serverModuleGuardFails = []\n if (didSetExitCode) {\n process.exitCode = 0\n didSetExitCode = false\n }\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${result.error}`,\n )\n }\n\n lastValidated = result.data\n\n if (isStandardEnvDefinition(envDefinition)) {\n await generateStandardDts(envDefinition, resolvedConfig.root)\n }\n else {\n const { generateDts } = await import('./dts')\n await generateDts(envDefinition, resolvedConfig.root)\n }\n\n const count = Object.keys(lastValidated).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(this: Rollup.PluginContext, source, importer) {\n if (source === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (source === 'virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n const result = checkServerModuleAccess(envName, serverEnvs, guardMode, importer)\n if (!result.allowed)\n serverModuleGuardFails.push(result)\n return '\\0virtual:env/server'\n }\n },\n\n load(this: Rollup.PluginContext, id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n // Filter to fails from this environment only — other envs may have recorded fails for their own loads\n const envFails = serverModuleGuardFails.filter(f => f.envName === envName)\n if (envFails.length > 0) {\n // warn once per load cycle using the last recorded fail; unique importers are written to the log file\n const latest = envFails.at(-1)!\n if (latest.mode === 'error')\n throw new Error(formatHardError(latest))\n if (latest.mode === 'stub')\n return buildServerStubModule(envName)\n resolvedConfig.logger.warn(`\\n${formatGuardWarning(latest)}`)\n }\n return buildServerModule(envDefinition, lastValidated)\n }\n },\n\n async buildEnd(error) {\n if (error)\n return\n if (serverModuleGuardFails.length === 0)\n return\n if (guardMode !== 'warn')\n return\n await writeWarningsLog(serverModuleGuardFails, resolvedConfig.root)\n process.exitCode = 1\n didSetExitCode = true\n },\n\n generateBundle(_options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const leaks = detectServerLeak(\n envDefinition,\n lastValidated,\n bundle as Record<string, { type: string, code?: string }>,\n (keys) => {\n resolvedConfig.logger.warn(\n ` \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(', ')}`,\n )\n },\n )\n\n if (leaks.length > 0) {\n const details = leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${details}\\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 try {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${result.error}`,\n )\n return\n }\n\n lastValidated = result.data\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n const serverMod = server.moduleGraph.getModuleById('\\0virtual:env/server')\n if (clientMod)\n server.moduleGraph.invalidateModule(clientMod)\n if (serverMod)\n server.moduleGraph.invalidateModule(serverMod)\n if (clientMod || serverMod) {\n serverModuleGuardFails = []\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 }\n catch (e) {\n resolvedConfig.logger.error(\n `\\n \\x1B[31m✗\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Failed to reload env files: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }, 150)\n })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/guard.ts","../src/log.ts","../src/sources.ts","../src/virtual.ts","../src/plugin.ts"],"sourcesContent":["export type GuardMode = 'error' | 'stub' | 'warn'\n\nexport type GuardResult\n = | { allowed: true }\n | { allowed: false, mode: GuardMode, envName: string, importer: string | undefined }\n\nexport type GuardFail = Extract<GuardResult, { allowed: false }>\n\n/**\n * Determines whether the given Vite environment is allowed to import virtual:env/server.\n * Returns a GuardResult discriminated union — allowed or fail with context.\n * When this.environment is undefined (should not occur with Vite ≥ 8), callers default\n * envName to 'client' — failing closed (restrictive) is safer than failing open.\n */\nexport function checkServerModuleAccess(\n envName: string,\n serverEnvironments: string[],\n mode: GuardMode,\n importer: string | undefined,\n): GuardResult {\n if (serverEnvironments.includes(envName))\n return { allowed: true }\n return { allowed: false, mode, envName, importer }\n}\n\n/**\n * Generates the stub virtual module returned when onClientAccessOfServerModule is 'stub'.\n * The stub throws at runtime if executed — its message reflects that this import was\n * expected to be unreachable and the assumption was wrong.\n */\nexport function buildServerStubModule(envName: string): { code: string, moduleType: 'js' } {\n return {\n moduleType: 'js',\n code: `// Auto-generated by @vite-env/core — server-only module stub\nthrow new Error(\n '[vite-env] virtual:env/server was imported in the \"${envName}\" environment. ' +\n 'This module is server-only and was replaced with a stub. ' +\n 'To allow this environment: add it to serverEnvironments. ' +\n 'To suppress this stub: ensure this import never executes in the \"${envName}\" environment.'\n);`,\n }\n}\n","// @env node\nimport type { GuardFail } from './guard'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { formatGuardLogEntry } from './format'\n\nconst LOG_HEADER = `# vite-env warnings — generated by @vite-env/core\n# These warnings will become hard errors in 1.0.0.\n# To enforce immediately: ViteEnv({ onClientAccessOfServerModule: 'error' })\n# To acknowledge and suppress: ViteEnv({ onClientAccessOfServerModule: 'stub' })\n# To allow specific environments: ViteEnv({ serverEnvironments: ['ssr', 'workerd'] })`\n\n/**\n * Writes accumulated GuardFail entries to vite-env-warnings.log in the project root.\n * Overwrites on each build — stale entries from previous builds must not persist.\n * Called only in 'warn' mode from buildEnd, after verifying the build succeeded.\n */\nexport async function writeWarningsLog(fails: GuardFail[], root: string): Promise<void> {\n const seen = new Set<string>()\n const unique = fails.filter((fail) => {\n const key = `${fail.envName}::${fail.importer ?? ''}`\n if (seen.has(key))\n return false\n seen.add(key)\n return true\n })\n const timestamp = new Date().toISOString()\n const entries = unique.map(fail => formatGuardLogEntry(fail, timestamp)).join('\\n\\n')\n const content = `${LOG_HEADER}\\n\\n${entries}\\n`\n const filePath = path.join(root, 'vite-env-warnings.log')\n try {\n await fs.writeFile(filePath, content, 'utf-8')\n }\n catch (e) {\n throw new Error(\n `[vite-env] Failed to write vite-env-warnings.log to ${root}. Check file permissions.`,\n { cause: e },\n )\n }\n}\n","// @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 { AnyEnvDefinition } from './types'\n\nexport function buildClientModule(\n def: AnyEnvDefinition,\n data: Record<string, unknown>,\n): { code: string, moduleType: 'js' } {\n const clientKeys = new Set(Object.keys(def.client ?? {}))\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: AnyEnvDefinition,\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, Rollup } from 'vite'\nimport type { GuardFail } from './guard'\nimport type { AnyEnvDefinition } from './types'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { loadEnvConfig } from './config'\nimport { generateStandardDts } from './dts'\nimport { formatGuardWarning, formatHardError, formatStandardSchemaError } from './format'\nimport { buildServerStubModule, checkServerModuleAccess } from './guard'\nimport { detectServerLeak } from './leak'\nimport { writeWarningsLog } from './log'\nimport { loadEnvSources } from './sources'\nimport { isStandardEnvDefinition, validateStandardEnv } from './standard'\nimport { buildClientModule, buildServerModule } from './virtual'\n\nexport type ViteEnvOptions = {\n /**\n * Path to env definition file.\n * @default './env.ts' (resolved from project root)\n */\n configFile?: string\n\n /**\n * Vite 8 environment names that are allowed to import virtual:env/server.\n * Use this to allow edge runtimes (Cloudflare Workers → 'workerd', Deno Deploy → 'ssr').\n * @default ['ssr']\n */\n serverEnvironments?: string[]\n\n /**\n * Behavior when virtual:env/server is imported from a disallowed environment.\n *\n * - 'warn' — Deprecation warning printed to terminal + vite-env-warnings.log written.\n * Build succeeds but exits with code 1. Default in 0.x releases.\n * The default will change to 'error' in 1.0.0.\n *\n * - 'error' — Hard build error. No artifacts emitted.\n *\n * - 'stub' — Returns a module that throws at runtime if the import executes.\n * Use for testing environments (Vitest jsdom) or framework isomorphic files\n * where the import exists but the code path is never reached in a server context.\n *\n * @default 'warn'\n */\n onClientAccessOfServerModule?: 'error' | 'stub' | 'warn'\n}\n\n/**\n * Validates environment variables against the definition.\n * Routes to Zod or Standard Schema path based on definition type.\n * Zod modules are loaded dynamically to avoid requiring zod for Standard Schema users.\n */\nasync function validateAndFormat(\n def: AnyEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<{ data: Record<string, unknown> } | { error: string }> {\n if (isStandardEnvDefinition(def)) {\n const result = await validateStandardEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatStandardSchemaError(result.errors) }\n }\n return { data: result.data }\n }\n\n const { validateEnv } = await import('./schema')\n const { formatZodError } = await import('./format')\n const result = validateEnv(def, rawEnv)\n if (!result.success) {\n return { error: formatZodError(result.errors) }\n }\n return { data: result.data }\n}\n\nexport default function ViteEnv(options: ViteEnvOptions = {}): Plugin {\n let resolvedConfig: ResolvedConfig\n let envDefinition: AnyEnvDefinition\n let lastValidated: Record<string, unknown> = {}\n let serverModuleGuardFails: GuardFail[] = []\n let didSetExitCode = false\n\n const serverEnvs = options.serverEnvironments ?? ['ssr']\n const guardMode = options.onClientAccessOfServerModule ?? 'warn'\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 serverModuleGuardFails = []\n if (didSetExitCode) {\n process.exitCode = 0\n didSetExitCode = false\n }\n\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n throw new Error(\n `[vite-env] Environment validation failed:\\n\\n${result.error}`,\n )\n }\n\n lastValidated = result.data\n\n if (isStandardEnvDefinition(envDefinition)) {\n await generateStandardDts(envDefinition, resolvedConfig.root)\n }\n else {\n const { generateDts } = await import('./dts')\n await generateDts(envDefinition, resolvedConfig.root)\n }\n\n const count = Object.keys(lastValidated).length\n resolvedConfig.logger.info(\n ` \\x1B[32m✓\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m ${count} variables validated`,\n )\n },\n\n resolveId(this: Rollup.PluginContext, source, importer) {\n if (source === 'virtual:env/client')\n return '\\0virtual:env/client'\n if (source === 'virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n const result = checkServerModuleAccess(envName, serverEnvs, guardMode, importer)\n if (!result.allowed)\n serverModuleGuardFails.push(result)\n return '\\0virtual:env/server'\n }\n },\n\n load(this: Rollup.PluginContext, id) {\n if (id === '\\0virtual:env/client')\n return buildClientModule(envDefinition, lastValidated)\n if (id === '\\0virtual:env/server') {\n const envName = this.environment?.name ?? 'client'\n // Filter to fails from this environment only — other envs may have recorded fails for their own loads\n const envFails = serverModuleGuardFails.filter(f => f.envName === envName)\n if (envFails.length > 0) {\n // warn once per load cycle using the last recorded fail; unique importers are written to the log file\n const latest = envFails.at(-1)!\n if (latest.mode === 'error')\n throw new Error(formatHardError(latest))\n if (latest.mode === 'stub')\n return buildServerStubModule(envName)\n resolvedConfig.logger.warn(`\\n${formatGuardWarning(latest)}`)\n }\n return buildServerModule(envDefinition, lastValidated)\n }\n },\n\n async buildEnd(error) {\n if (error)\n return\n if (serverModuleGuardFails.length === 0)\n return\n if (guardMode !== 'warn')\n return\n await writeWarningsLog(serverModuleGuardFails, resolvedConfig.root)\n process.exitCode = 1\n didSetExitCode = true\n },\n\n generateBundle(this: Rollup.PluginContext, _options, bundle) {\n if (resolvedConfig.build.ssr)\n return\n\n const envName = this.environment?.name ?? 'client'\n if (serverEnvs.includes(envName))\n return\n\n const leaks = detectServerLeak(\n envDefinition,\n lastValidated,\n bundle as Record<string, { type: string, code?: string }>,\n (keys) => {\n resolvedConfig.logger.warn(\n ` \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Leak detection skipped ${keys.length} server variable(s) with values shorter than 8 chars: ${keys.join(', ')}`,\n )\n },\n )\n\n if (leaks.length > 0) {\n const details = leaks.map(l => ` ✗ ${l.key} found in ${l.chunk}`).join('\\n')\n throw new Error(\n `[vite-env] Server environment variables detected in client bundle!\\n\\n${details}\\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 try {\n const rawEnv = await loadEnvSources(resolvedConfig)\n const result = await validateAndFormat(envDefinition, rawEnv)\n\n if ('error' in result) {\n resolvedConfig.logger.warn(\n `\\n \\x1B[33m⚠\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Env revalidation failed:\\n${result.error}`,\n )\n return\n }\n\n lastValidated = result.data\n\n const clientMod = server.moduleGraph.getModuleById('\\0virtual:env/client')\n const serverMod = server.moduleGraph.getModuleById('\\0virtual:env/server')\n if (clientMod)\n server.moduleGraph.invalidateModule(clientMod)\n if (serverMod)\n server.moduleGraph.invalidateModule(serverMod)\n if (clientMod || serverMod) {\n serverModuleGuardFails = []\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 }\n catch (e) {\n resolvedConfig.logger.error(\n `\\n \\x1B[31m✗\\x1B[0m \\x1B[36m[vite-env]\\x1B[0m Failed to reload env files: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }, 150)\n })\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("../dts-BgHTl6hC.cjs");
3
+ let zod = require("zod");
4
+ //#region src/presets/netlify.ts
5
+ const netlify = { server: {
6
+ NETLIFY: zod.z.enum(["true"]),
7
+ BUILD_ID: zod.z.string().min(1),
8
+ CONTEXT: zod.z.enum([
9
+ "production",
10
+ "deploy-preview",
11
+ "branch-deploy",
12
+ "dev"
13
+ ]),
14
+ DEPLOY_ID: zod.z.string().min(1),
15
+ DEPLOY_URL: zod.z.url(),
16
+ DEPLOY_PRIME_URL: zod.z.url(),
17
+ URL: zod.z.url(),
18
+ BRANCH: zod.z.string().min(1),
19
+ COMMIT_REF: zod.z.string().min(1),
20
+ PULL_REQUEST: zod.z.enum(["true"]).optional(),
21
+ REVIEW_ID: zod.z.string().optional(),
22
+ REPOSITORY_URL: zod.z.url().optional(),
23
+ INCOMING_HOOK_TITLE: zod.z.string().optional(),
24
+ INCOMING_HOOK_URL: zod.z.url().optional()
25
+ } };
26
+ //#endregion
27
+ //#region src/presets/railway.ts
28
+ const railway = { server: {
29
+ RAILWAY_ENVIRONMENT_ID: zod.z.string().min(1),
30
+ RAILWAY_ENVIRONMENT_NAME: zod.z.string().min(1),
31
+ RAILWAY_SERVICE_ID: zod.z.string().min(1),
32
+ RAILWAY_SERVICE_NAME: zod.z.string().min(1),
33
+ RAILWAY_PROJECT_ID: zod.z.string().min(1),
34
+ RAILWAY_PROJECT_NAME: zod.z.string().min(1),
35
+ RAILWAY_DEPLOYMENT_ID: zod.z.string().min(1),
36
+ RAILWAY_REPLICA_ID: zod.z.string().optional(),
37
+ RAILWAY_GIT_COMMIT_SHA: zod.z.string().optional(),
38
+ RAILWAY_GIT_BRANCH: zod.z.string().optional(),
39
+ RAILWAY_GIT_REPO_NAME: zod.z.string().optional(),
40
+ RAILWAY_GIT_REPO_OWNER: zod.z.string().optional(),
41
+ RAILWAY_PUBLIC_DOMAIN: zod.z.string().min(1).optional(),
42
+ RAILWAY_PRIVATE_DOMAIN: zod.z.string().min(1).optional(),
43
+ RAILWAY_TCP_PROXY_DOMAIN: zod.z.string().min(1).optional(),
44
+ RAILWAY_TCP_PROXY_PORT: zod.z.coerce.number().int().min(1).max(65535).optional()
45
+ } };
46
+ //#endregion
47
+ //#region src/presets/vercel.ts
48
+ const vercel = { server: {
49
+ VERCEL: zod.z.enum(["1"]),
50
+ VERCEL_ENV: zod.z.enum([
51
+ "production",
52
+ "preview",
53
+ "development"
54
+ ]),
55
+ VERCEL_URL: zod.z.string().min(1),
56
+ VERCEL_BRANCH_URL: zod.z.string().min(1).optional(),
57
+ VERCEL_PROJECT_PRODUCTION_URL: zod.z.string().min(1),
58
+ VERCEL_DEPLOYMENT_ID: zod.z.string().min(1),
59
+ VERCEL_REGION: zod.z.string().optional(),
60
+ VERCEL_GIT_PROVIDER: zod.z.string().optional(),
61
+ VERCEL_GIT_REPO_SLUG: zod.z.string().optional(),
62
+ VERCEL_GIT_REPO_OWNER: zod.z.string().optional(),
63
+ VERCEL_GIT_COMMIT_REF: zod.z.string().optional(),
64
+ VERCEL_GIT_COMMIT_SHA: zod.z.string().optional(),
65
+ VERCEL_GIT_COMMIT_MESSAGE: zod.z.string().optional(),
66
+ VERCEL_GIT_COMMIT_AUTHOR_LOGIN: zod.z.string().optional(),
67
+ VERCEL_GIT_PULL_REQUEST_ID: zod.z.string().optional(),
68
+ VERCEL_SKEW_PROTECTION_ENABLED: zod.z.enum(["1"]).optional()
69
+ } };
70
+ //#endregion
71
+ exports.netlify = netlify;
72
+ exports.railway = railway;
73
+ exports.vercel = vercel;
74
+
75
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["z","z","z"],"sources":["../../src/presets/netlify.ts","../../src/presets/railway.ts","../../src/presets/vercel.ts"],"sourcesContent":["import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const netlify = {\n server: {\n // Set to 'true' by Netlify to indicate a Netlify build (note: Vercel uses '1', not 'true')\n NETLIFY: z.enum(['true']),\n BUILD_ID: z.string().min(1),\n CONTEXT: z.enum(['production', 'deploy-preview', 'branch-deploy', 'dev']),\n DEPLOY_ID: z.string().min(1),\n // Full https:// URLs — z.url() is correct here unlike VERCEL_URL\n DEPLOY_URL: z.url(),\n DEPLOY_PRIME_URL: z.url(),\n URL: z.url(),\n BRANCH: z.string().min(1),\n COMMIT_REF: z.string().min(1),\n // Netlify sets this to 'true' on PR deploys; absent (not 'false') on non-PR builds\n PULL_REQUEST: z.enum(['true']).optional(),\n REVIEW_ID: z.string().optional(),\n REPOSITORY_URL: z.url().optional(),\n INCOMING_HOOK_TITLE: z.string().optional(),\n INCOMING_HOOK_URL: z.url().optional(),\n },\n} satisfies EnvPreset\n","import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const railway = {\n server: {\n RAILWAY_ENVIRONMENT_ID: z.string().min(1),\n RAILWAY_ENVIRONMENT_NAME: z.string().min(1),\n RAILWAY_SERVICE_ID: z.string().min(1),\n RAILWAY_SERVICE_NAME: z.string().min(1),\n RAILWAY_PROJECT_ID: z.string().min(1),\n RAILWAY_PROJECT_NAME: z.string().min(1),\n RAILWAY_DEPLOYMENT_ID: z.string().min(1),\n RAILWAY_REPLICA_ID: z.string().optional(),\n RAILWAY_GIT_COMMIT_SHA: z.string().optional(),\n RAILWAY_GIT_BRANCH: z.string().optional(),\n RAILWAY_GIT_REPO_NAME: z.string().optional(),\n RAILWAY_GIT_REPO_OWNER: z.string().optional(),\n RAILWAY_PUBLIC_DOMAIN: z.string().min(1).optional(),\n RAILWAY_PRIVATE_DOMAIN: z.string().min(1).optional(),\n RAILWAY_TCP_PROXY_DOMAIN: z.string().min(1).optional(),\n RAILWAY_TCP_PROXY_PORT: z.coerce.number().int().min(1).max(65535).optional(),\n // PORT excluded: generic name set by many tools independently; handle it in your own server config\n },\n} satisfies EnvPreset\n","import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const vercel = {\n server: {\n // Set to '1' by Vercel to indicate a Vercel environment\n VERCEL: z.enum(['1']),\n VERCEL_ENV: z.enum(['production', 'preview', 'development']),\n // Bare hostname (e.g. myapp-abc123.vercel.app) — no scheme, z.url() would reject it\n VERCEL_URL: z.string().min(1),\n VERCEL_BRANCH_URL: z.string().min(1).optional(),\n VERCEL_PROJECT_PRODUCTION_URL: z.string().min(1),\n VERCEL_DEPLOYMENT_ID: z.string().min(1),\n VERCEL_REGION: z.string().optional(),\n // z.string() not enum — Vercel may add providers (Azure DevOps, self-hosted GitLab) without notice\n VERCEL_GIT_PROVIDER: z.string().optional(),\n VERCEL_GIT_REPO_SLUG: z.string().optional(),\n VERCEL_GIT_REPO_OWNER: z.string().optional(),\n VERCEL_GIT_COMMIT_REF: z.string().optional(),\n VERCEL_GIT_COMMIT_SHA: z.string().optional(),\n VERCEL_GIT_COMMIT_MESSAGE: z.string().optional(),\n VERCEL_GIT_COMMIT_AUTHOR_LOGIN: z.string().optional(),\n VERCEL_GIT_PULL_REQUEST_ID: z.string().optional(),\n VERCEL_SKEW_PROTECTION_ENABLED: z.enum(['1']).optional(),\n },\n} satisfies EnvPreset\n"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/presets/netlify.d.ts
4
+ declare const netlify: {
5
+ server: {
6
+ NETLIFY: z.ZodEnum<{
7
+ true: "true";
8
+ }>;
9
+ BUILD_ID: z.ZodString;
10
+ CONTEXT: z.ZodEnum<{
11
+ production: "production";
12
+ "deploy-preview": "deploy-preview";
13
+ "branch-deploy": "branch-deploy";
14
+ dev: "dev";
15
+ }>;
16
+ DEPLOY_ID: z.ZodString;
17
+ DEPLOY_URL: z.ZodURL;
18
+ DEPLOY_PRIME_URL: z.ZodURL;
19
+ URL: z.ZodURL;
20
+ BRANCH: z.ZodString;
21
+ COMMIT_REF: z.ZodString;
22
+ PULL_REQUEST: z.ZodOptional<z.ZodEnum<{
23
+ true: "true";
24
+ }>>;
25
+ REVIEW_ID: z.ZodOptional<z.ZodString>;
26
+ REPOSITORY_URL: z.ZodOptional<z.ZodURL>;
27
+ INCOMING_HOOK_TITLE: z.ZodOptional<z.ZodString>;
28
+ INCOMING_HOOK_URL: z.ZodOptional<z.ZodURL>;
29
+ };
30
+ };
31
+ //#endregion
32
+ //#region src/presets/railway.d.ts
33
+ declare const railway: {
34
+ server: {
35
+ RAILWAY_ENVIRONMENT_ID: z.ZodString;
36
+ RAILWAY_ENVIRONMENT_NAME: z.ZodString;
37
+ RAILWAY_SERVICE_ID: z.ZodString;
38
+ RAILWAY_SERVICE_NAME: z.ZodString;
39
+ RAILWAY_PROJECT_ID: z.ZodString;
40
+ RAILWAY_PROJECT_NAME: z.ZodString;
41
+ RAILWAY_DEPLOYMENT_ID: z.ZodString;
42
+ RAILWAY_REPLICA_ID: z.ZodOptional<z.ZodString>;
43
+ RAILWAY_GIT_COMMIT_SHA: z.ZodOptional<z.ZodString>;
44
+ RAILWAY_GIT_BRANCH: z.ZodOptional<z.ZodString>;
45
+ RAILWAY_GIT_REPO_NAME: z.ZodOptional<z.ZodString>;
46
+ RAILWAY_GIT_REPO_OWNER: z.ZodOptional<z.ZodString>;
47
+ RAILWAY_PUBLIC_DOMAIN: z.ZodOptional<z.ZodString>;
48
+ RAILWAY_PRIVATE_DOMAIN: z.ZodOptional<z.ZodString>;
49
+ RAILWAY_TCP_PROXY_DOMAIN: z.ZodOptional<z.ZodString>;
50
+ RAILWAY_TCP_PROXY_PORT: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
51
+ };
52
+ };
53
+ //#endregion
54
+ //#region src/presets/vercel.d.ts
55
+ declare const vercel: {
56
+ server: {
57
+ VERCEL: z.ZodEnum<{
58
+ 1: "1";
59
+ }>;
60
+ VERCEL_ENV: z.ZodEnum<{
61
+ production: "production";
62
+ preview: "preview";
63
+ development: "development";
64
+ }>;
65
+ VERCEL_URL: z.ZodString;
66
+ VERCEL_BRANCH_URL: z.ZodOptional<z.ZodString>;
67
+ VERCEL_PROJECT_PRODUCTION_URL: z.ZodString;
68
+ VERCEL_DEPLOYMENT_ID: z.ZodString;
69
+ VERCEL_REGION: z.ZodOptional<z.ZodString>;
70
+ VERCEL_GIT_PROVIDER: z.ZodOptional<z.ZodString>;
71
+ VERCEL_GIT_REPO_SLUG: z.ZodOptional<z.ZodString>;
72
+ VERCEL_GIT_REPO_OWNER: z.ZodOptional<z.ZodString>;
73
+ VERCEL_GIT_COMMIT_REF: z.ZodOptional<z.ZodString>;
74
+ VERCEL_GIT_COMMIT_SHA: z.ZodOptional<z.ZodString>;
75
+ VERCEL_GIT_COMMIT_MESSAGE: z.ZodOptional<z.ZodString>;
76
+ VERCEL_GIT_COMMIT_AUTHOR_LOGIN: z.ZodOptional<z.ZodString>;
77
+ VERCEL_GIT_PULL_REQUEST_ID: z.ZodOptional<z.ZodString>;
78
+ VERCEL_SKEW_PROTECTION_ENABLED: z.ZodOptional<z.ZodEnum<{
79
+ 1: "1";
80
+ }>>;
81
+ };
82
+ };
83
+ //#endregion
84
+ export { netlify, railway, vercel };
85
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,85 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/presets/netlify.d.ts
4
+ declare const netlify: {
5
+ server: {
6
+ NETLIFY: z.ZodEnum<{
7
+ true: "true";
8
+ }>;
9
+ BUILD_ID: z.ZodString;
10
+ CONTEXT: z.ZodEnum<{
11
+ production: "production";
12
+ "deploy-preview": "deploy-preview";
13
+ "branch-deploy": "branch-deploy";
14
+ dev: "dev";
15
+ }>;
16
+ DEPLOY_ID: z.ZodString;
17
+ DEPLOY_URL: z.ZodURL;
18
+ DEPLOY_PRIME_URL: z.ZodURL;
19
+ URL: z.ZodURL;
20
+ BRANCH: z.ZodString;
21
+ COMMIT_REF: z.ZodString;
22
+ PULL_REQUEST: z.ZodOptional<z.ZodEnum<{
23
+ true: "true";
24
+ }>>;
25
+ REVIEW_ID: z.ZodOptional<z.ZodString>;
26
+ REPOSITORY_URL: z.ZodOptional<z.ZodURL>;
27
+ INCOMING_HOOK_TITLE: z.ZodOptional<z.ZodString>;
28
+ INCOMING_HOOK_URL: z.ZodOptional<z.ZodURL>;
29
+ };
30
+ };
31
+ //#endregion
32
+ //#region src/presets/railway.d.ts
33
+ declare const railway: {
34
+ server: {
35
+ RAILWAY_ENVIRONMENT_ID: z.ZodString;
36
+ RAILWAY_ENVIRONMENT_NAME: z.ZodString;
37
+ RAILWAY_SERVICE_ID: z.ZodString;
38
+ RAILWAY_SERVICE_NAME: z.ZodString;
39
+ RAILWAY_PROJECT_ID: z.ZodString;
40
+ RAILWAY_PROJECT_NAME: z.ZodString;
41
+ RAILWAY_DEPLOYMENT_ID: z.ZodString;
42
+ RAILWAY_REPLICA_ID: z.ZodOptional<z.ZodString>;
43
+ RAILWAY_GIT_COMMIT_SHA: z.ZodOptional<z.ZodString>;
44
+ RAILWAY_GIT_BRANCH: z.ZodOptional<z.ZodString>;
45
+ RAILWAY_GIT_REPO_NAME: z.ZodOptional<z.ZodString>;
46
+ RAILWAY_GIT_REPO_OWNER: z.ZodOptional<z.ZodString>;
47
+ RAILWAY_PUBLIC_DOMAIN: z.ZodOptional<z.ZodString>;
48
+ RAILWAY_PRIVATE_DOMAIN: z.ZodOptional<z.ZodString>;
49
+ RAILWAY_TCP_PROXY_DOMAIN: z.ZodOptional<z.ZodString>;
50
+ RAILWAY_TCP_PROXY_PORT: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
51
+ };
52
+ };
53
+ //#endregion
54
+ //#region src/presets/vercel.d.ts
55
+ declare const vercel: {
56
+ server: {
57
+ VERCEL: z.ZodEnum<{
58
+ 1: "1";
59
+ }>;
60
+ VERCEL_ENV: z.ZodEnum<{
61
+ production: "production";
62
+ preview: "preview";
63
+ development: "development";
64
+ }>;
65
+ VERCEL_URL: z.ZodString;
66
+ VERCEL_BRANCH_URL: z.ZodOptional<z.ZodString>;
67
+ VERCEL_PROJECT_PRODUCTION_URL: z.ZodString;
68
+ VERCEL_DEPLOYMENT_ID: z.ZodString;
69
+ VERCEL_REGION: z.ZodOptional<z.ZodString>;
70
+ VERCEL_GIT_PROVIDER: z.ZodOptional<z.ZodString>;
71
+ VERCEL_GIT_REPO_SLUG: z.ZodOptional<z.ZodString>;
72
+ VERCEL_GIT_REPO_OWNER: z.ZodOptional<z.ZodString>;
73
+ VERCEL_GIT_COMMIT_REF: z.ZodOptional<z.ZodString>;
74
+ VERCEL_GIT_COMMIT_SHA: z.ZodOptional<z.ZodString>;
75
+ VERCEL_GIT_COMMIT_MESSAGE: z.ZodOptional<z.ZodString>;
76
+ VERCEL_GIT_COMMIT_AUTHOR_LOGIN: z.ZodOptional<z.ZodString>;
77
+ VERCEL_GIT_PULL_REQUEST_ID: z.ZodOptional<z.ZodString>;
78
+ VERCEL_SKEW_PROTECTION_ENABLED: z.ZodOptional<z.ZodEnum<{
79
+ 1: "1";
80
+ }>>;
81
+ };
82
+ };
83
+ //#endregion
84
+ export { netlify, railway, vercel };
85
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+ //#region src/presets/netlify.ts
3
+ const netlify = { server: {
4
+ NETLIFY: z.enum(["true"]),
5
+ BUILD_ID: z.string().min(1),
6
+ CONTEXT: z.enum([
7
+ "production",
8
+ "deploy-preview",
9
+ "branch-deploy",
10
+ "dev"
11
+ ]),
12
+ DEPLOY_ID: z.string().min(1),
13
+ DEPLOY_URL: z.url(),
14
+ DEPLOY_PRIME_URL: z.url(),
15
+ URL: z.url(),
16
+ BRANCH: z.string().min(1),
17
+ COMMIT_REF: z.string().min(1),
18
+ PULL_REQUEST: z.enum(["true"]).optional(),
19
+ REVIEW_ID: z.string().optional(),
20
+ REPOSITORY_URL: z.url().optional(),
21
+ INCOMING_HOOK_TITLE: z.string().optional(),
22
+ INCOMING_HOOK_URL: z.url().optional()
23
+ } };
24
+ //#endregion
25
+ //#region src/presets/railway.ts
26
+ const railway = { server: {
27
+ RAILWAY_ENVIRONMENT_ID: z.string().min(1),
28
+ RAILWAY_ENVIRONMENT_NAME: z.string().min(1),
29
+ RAILWAY_SERVICE_ID: z.string().min(1),
30
+ RAILWAY_SERVICE_NAME: z.string().min(1),
31
+ RAILWAY_PROJECT_ID: z.string().min(1),
32
+ RAILWAY_PROJECT_NAME: z.string().min(1),
33
+ RAILWAY_DEPLOYMENT_ID: z.string().min(1),
34
+ RAILWAY_REPLICA_ID: z.string().optional(),
35
+ RAILWAY_GIT_COMMIT_SHA: z.string().optional(),
36
+ RAILWAY_GIT_BRANCH: z.string().optional(),
37
+ RAILWAY_GIT_REPO_NAME: z.string().optional(),
38
+ RAILWAY_GIT_REPO_OWNER: z.string().optional(),
39
+ RAILWAY_PUBLIC_DOMAIN: z.string().min(1).optional(),
40
+ RAILWAY_PRIVATE_DOMAIN: z.string().min(1).optional(),
41
+ RAILWAY_TCP_PROXY_DOMAIN: z.string().min(1).optional(),
42
+ RAILWAY_TCP_PROXY_PORT: z.coerce.number().int().min(1).max(65535).optional()
43
+ } };
44
+ //#endregion
45
+ //#region src/presets/vercel.ts
46
+ const vercel = { server: {
47
+ VERCEL: z.enum(["1"]),
48
+ VERCEL_ENV: z.enum([
49
+ "production",
50
+ "preview",
51
+ "development"
52
+ ]),
53
+ VERCEL_URL: z.string().min(1),
54
+ VERCEL_BRANCH_URL: z.string().min(1).optional(),
55
+ VERCEL_PROJECT_PRODUCTION_URL: z.string().min(1),
56
+ VERCEL_DEPLOYMENT_ID: z.string().min(1),
57
+ VERCEL_REGION: z.string().optional(),
58
+ VERCEL_GIT_PROVIDER: z.string().optional(),
59
+ VERCEL_GIT_REPO_SLUG: z.string().optional(),
60
+ VERCEL_GIT_REPO_OWNER: z.string().optional(),
61
+ VERCEL_GIT_COMMIT_REF: z.string().optional(),
62
+ VERCEL_GIT_COMMIT_SHA: z.string().optional(),
63
+ VERCEL_GIT_COMMIT_MESSAGE: z.string().optional(),
64
+ VERCEL_GIT_COMMIT_AUTHOR_LOGIN: z.string().optional(),
65
+ VERCEL_GIT_PULL_REQUEST_ID: z.string().optional(),
66
+ VERCEL_SKEW_PROTECTION_ENABLED: z.enum(["1"]).optional()
67
+ } };
68
+ //#endregion
69
+ export { netlify, railway, vercel };
70
+
71
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/presets/netlify.ts","../../src/presets/railway.ts","../../src/presets/vercel.ts"],"sourcesContent":["import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const netlify = {\n server: {\n // Set to 'true' by Netlify to indicate a Netlify build (note: Vercel uses '1', not 'true')\n NETLIFY: z.enum(['true']),\n BUILD_ID: z.string().min(1),\n CONTEXT: z.enum(['production', 'deploy-preview', 'branch-deploy', 'dev']),\n DEPLOY_ID: z.string().min(1),\n // Full https:// URLs — z.url() is correct here unlike VERCEL_URL\n DEPLOY_URL: z.url(),\n DEPLOY_PRIME_URL: z.url(),\n URL: z.url(),\n BRANCH: z.string().min(1),\n COMMIT_REF: z.string().min(1),\n // Netlify sets this to 'true' on PR deploys; absent (not 'false') on non-PR builds\n PULL_REQUEST: z.enum(['true']).optional(),\n REVIEW_ID: z.string().optional(),\n REPOSITORY_URL: z.url().optional(),\n INCOMING_HOOK_TITLE: z.string().optional(),\n INCOMING_HOOK_URL: z.url().optional(),\n },\n} satisfies EnvPreset\n","import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const railway = {\n server: {\n RAILWAY_ENVIRONMENT_ID: z.string().min(1),\n RAILWAY_ENVIRONMENT_NAME: z.string().min(1),\n RAILWAY_SERVICE_ID: z.string().min(1),\n RAILWAY_SERVICE_NAME: z.string().min(1),\n RAILWAY_PROJECT_ID: z.string().min(1),\n RAILWAY_PROJECT_NAME: z.string().min(1),\n RAILWAY_DEPLOYMENT_ID: z.string().min(1),\n RAILWAY_REPLICA_ID: z.string().optional(),\n RAILWAY_GIT_COMMIT_SHA: z.string().optional(),\n RAILWAY_GIT_BRANCH: z.string().optional(),\n RAILWAY_GIT_REPO_NAME: z.string().optional(),\n RAILWAY_GIT_REPO_OWNER: z.string().optional(),\n RAILWAY_PUBLIC_DOMAIN: z.string().min(1).optional(),\n RAILWAY_PRIVATE_DOMAIN: z.string().min(1).optional(),\n RAILWAY_TCP_PROXY_DOMAIN: z.string().min(1).optional(),\n RAILWAY_TCP_PROXY_PORT: z.coerce.number().int().min(1).max(65535).optional(),\n // PORT excluded: generic name set by many tools independently; handle it in your own server config\n },\n} satisfies EnvPreset\n","import type { EnvPreset } from '../types'\nimport { z } from 'zod'\n\nexport const vercel = {\n server: {\n // Set to '1' by Vercel to indicate a Vercel environment\n VERCEL: z.enum(['1']),\n VERCEL_ENV: z.enum(['production', 'preview', 'development']),\n // Bare hostname (e.g. myapp-abc123.vercel.app) — no scheme, z.url() would reject it\n VERCEL_URL: z.string().min(1),\n VERCEL_BRANCH_URL: z.string().min(1).optional(),\n VERCEL_PROJECT_PRODUCTION_URL: z.string().min(1),\n VERCEL_DEPLOYMENT_ID: z.string().min(1),\n VERCEL_REGION: z.string().optional(),\n // z.string() not enum — Vercel may add providers (Azure DevOps, self-hosted GitLab) without notice\n VERCEL_GIT_PROVIDER: z.string().optional(),\n VERCEL_GIT_REPO_SLUG: z.string().optional(),\n VERCEL_GIT_REPO_OWNER: z.string().optional(),\n VERCEL_GIT_COMMIT_REF: z.string().optional(),\n VERCEL_GIT_COMMIT_SHA: z.string().optional(),\n VERCEL_GIT_COMMIT_MESSAGE: z.string().optional(),\n VERCEL_GIT_COMMIT_AUTHOR_LOGIN: z.string().optional(),\n VERCEL_GIT_PULL_REQUEST_ID: z.string().optional(),\n VERCEL_SKEW_PROTECTION_ENABLED: z.enum(['1']).optional(),\n },\n} satisfies EnvPreset\n"],"mappings":";;AAGA,MAAa,UAAU,EACrB,QAAQ;CAEN,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC;CACzB,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC3B,SAAS,EAAE,KAAK;EAAC;EAAc;EAAkB;EAAiB;EAAM,CAAC;CACzE,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE;CAE5B,YAAY,EAAE,KAAK;CACnB,kBAAkB,EAAE,KAAK;CACzB,KAAK,EAAE,KAAK;CACZ,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE;CACzB,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE;CAE7B,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,UAAU;CACzC,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,gBAAgB,EAAE,KAAK,CAAC,UAAU;CAClC,qBAAqB,EAAE,QAAQ,CAAC,UAAU;CAC1C,mBAAmB,EAAE,KAAK,CAAC,UAAU;CACtC,EACF;;;ACpBD,MAAa,UAAU,EACrB,QAAQ;CACN,wBAAwB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACzC,0BAA0B,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC3C,oBAAoB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACrC,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvC,oBAAoB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACrC,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvC,uBAAuB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACxC,oBAAoB,EAAE,QAAQ,CAAC,UAAU;CACzC,wBAAwB,EAAE,QAAQ,CAAC,UAAU;CAC7C,oBAAoB,EAAE,QAAQ,CAAC,UAAU;CACzC,uBAAuB,EAAE,QAAQ,CAAC,UAAU;CAC5C,wBAAwB,EAAE,QAAQ,CAAC,UAAU;CAC7C,uBAAuB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CACnD,wBAAwB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CACpD,0BAA0B,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CACtD,wBAAwB,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU;CAE7E,EACF;;;ACpBD,MAAa,SAAS,EACpB,QAAQ;CAEN,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;CACrB,YAAY,EAAE,KAAK;EAAC;EAAc;EAAW;EAAc,CAAC;CAE5D,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC7B,mBAAmB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CAC/C,+BAA+B,EAAE,QAAQ,CAAC,IAAI,EAAE;CAChD,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvC,eAAe,EAAE,QAAQ,CAAC,UAAU;CAEpC,qBAAqB,EAAE,QAAQ,CAAC,UAAU;CAC1C,sBAAsB,EAAE,QAAQ,CAAC,UAAU;CAC3C,uBAAuB,EAAE,QAAQ,CAAC,UAAU;CAC5C,uBAAuB,EAAE,QAAQ,CAAC,UAAU;CAC5C,uBAAuB,EAAE,QAAQ,CAAC,UAAU;CAC5C,2BAA2B,EAAE,QAAQ,CAAC,UAAU;CAChD,gCAAgC,EAAE,QAAQ,CAAC,UAAU;CACrD,4BAA4B,EAAE,QAAQ,CAAC,UAAU;CACjD,gCAAgC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU;CACzD,EACF"}
package/dist/schema.cjs CHANGED
@@ -2,11 +2,32 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./dts-BgHTl6hC.cjs");
3
3
  let zod = require("zod");
4
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.`);
5
+ function warnSideConflicts(keys, seen, userKeys, side) {
6
+ for (const key of keys) {
7
+ const duplicate = seen.has(key);
8
+ if (duplicate) console.warn(`[vite-env] "${key}" is defined in multiple presets. The last preset wins.`);
9
+ seen.add(key);
10
+ if (!duplicate && userKeys.has(key)) console.warn(`[vite-env] "${key}" is defined in both a preset and your ${side} config. Your definition wins.`);
11
+ }
12
+ }
13
+ function warnConflicts(presets, userServerKeys, userClientKeys) {
14
+ const seenServerKeys = /* @__PURE__ */ new Set();
15
+ const seenClientKeys = /* @__PURE__ */ new Set();
16
+ for (const preset of presets) {
17
+ warnSideConflicts(Object.keys(preset.server ?? {}), seenServerKeys, userServerKeys, "server");
18
+ warnSideConflicts(Object.keys(preset.client ?? {}), seenClientKeys, userClientKeys, "client");
8
19
  }
9
- return definition;
20
+ }
21
+ function defineEnv(definition) {
22
+ const { presets = [], server, client, ...rest } = definition;
23
+ const mergedServer = Object.assign({}, ...presets.map((p) => p.server ?? {}), server);
24
+ const mergedClient = Object.assign({}, ...presets.map((p) => p.client ?? {}), client);
25
+ warnConflicts(presets, new Set(Object.keys(server ?? {})), new Set(Object.keys(client ?? {})));
26
+ for (const key of Object.keys(mergedClient)) 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.`);
27
+ const result = { ...rest };
28
+ if (Object.keys(mergedServer).length > 0 || server !== void 0) result.server = mergedServer;
29
+ if (Object.keys(mergedClient).length > 0 || client !== void 0) result.client = mergedClient;
30
+ return result;
10
31
  }
11
32
  function validateEnv(def, rawEnv) {
12
33
  const combinedShape = {
@@ -1 +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<T extends EnvDefinition>(definition: T): T {\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\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 }\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: [] as const }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;;;AAGA,SAAgB,UAAmC,YAAkB;AACnE,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;;AAKP,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,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;EAAW;AAGlE,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
1
+ {"version":3,"file":"schema.cjs","names":["z"],"sources":["../src/schema.ts"],"sourcesContent":["import type { EnvDefinition, EnvPreset, ValidationResult } from './types'\nimport { z } from 'zod'\n\ntype DefineEnvInput = {\n presets?: EnvPreset[]\n} & EnvDefinition\n\nfunction warnSideConflicts(\n keys: string[],\n seen: Set<string>,\n userKeys: Set<string>,\n side: 'server' | 'client',\n): void {\n for (const key of keys) {\n const duplicate = seen.has(key)\n if (duplicate)\n console.warn(`[vite-env] \"${key}\" is defined in multiple presets. The last preset wins.`)\n seen.add(key)\n if (!duplicate && userKeys.has(key))\n console.warn(`[vite-env] \"${key}\" is defined in both a preset and your ${side} config. Your definition wins.`)\n }\n}\n\nfunction warnConflicts(\n presets: EnvPreset[],\n userServerKeys: Set<string>,\n userClientKeys: Set<string>,\n): void {\n const seenServerKeys = new Set<string>()\n const seenClientKeys = new Set<string>()\n\n for (const preset of presets) {\n warnSideConflicts(Object.keys(preset.server ?? {}), seenServerKeys, userServerKeys, 'server')\n warnSideConflicts(Object.keys(preset.client ?? {}), seenClientKeys, userClientKeys, 'client')\n }\n}\n\nexport function defineEnv<T extends DefineEnvInput>(definition: T): Omit<T, 'presets'> & Pick<EnvDefinition, 'server' | 'client'> {\n const { presets = [], server, client, ...rest } = definition\n // ...rest intentionally forwarded — T may carry extra keys beyond EnvDefinition\n\n const mergedServer: z.ZodRawShape = Object.assign({}, ...presets.map(p => p.server ?? {}), server)\n const mergedClient: z.ZodRawShape = Object.assign({}, ...presets.map(p => p.client ?? {}), client)\n\n warnConflicts(\n presets,\n new Set(Object.keys(server ?? {})),\n new Set(Object.keys(client ?? {})),\n )\n\n for (const key of Object.keys(mergedClient)) {\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 const result: Record<string, unknown> = { ...rest }\n if (Object.keys(mergedServer).length > 0 || server !== undefined)\n result.server = mergedServer\n if (Object.keys(mergedClient).length > 0 || client !== undefined)\n result.client = mergedClient\n\n return result as Omit<T, 'presets'>\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 }\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: [] as const }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;;;AAOA,SAAS,kBACP,MACA,MACA,UACA,MACM;AACN,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,MAAI,UACF,SAAQ,KAAK,eAAe,IAAI,yDAAyD;AAC3F,OAAK,IAAI,IAAI;AACb,MAAI,CAAC,aAAa,SAAS,IAAI,IAAI,CACjC,SAAQ,KAAK,eAAe,IAAI,yCAAyC,KAAK,gCAAgC;;;AAIpH,SAAS,cACP,SACA,gBACA,gBACM;CACN,MAAM,iCAAiB,IAAI,KAAa;CACxC,MAAM,iCAAiB,IAAI,KAAa;AAExC,MAAK,MAAM,UAAU,SAAS;AAC5B,oBAAkB,OAAO,KAAK,OAAO,UAAU,EAAE,CAAC,EAAE,gBAAgB,gBAAgB,SAAS;AAC7F,oBAAkB,OAAO,KAAK,OAAO,UAAU,EAAE,CAAC,EAAE,gBAAgB,gBAAgB,SAAS;;;AAIjG,SAAgB,UAAoC,YAA8E;CAChI,MAAM,EAAE,UAAU,EAAE,EAAE,QAAQ,QAAQ,GAAG,SAAS;CAGlD,MAAM,eAA8B,OAAO,OAAO,EAAE,EAAE,GAAG,QAAQ,KAAI,MAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO;CAClG,MAAM,eAA8B,OAAO,OAAO,EAAE,EAAE,GAAG,QAAQ,KAAI,MAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO;AAElG,eACE,SACA,IAAI,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,EAClC,IAAI,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,CACnC;AAED,MAAK,MAAM,OAAO,OAAO,KAAK,aAAa,CACzC,KAAI,CAAC,IAAI,WAAW,QAAQ,CAC1B,OAAM,IAAI,MACR,8BAA8B,IAAI,uDACR,IAAI,0CAC/B;CAIL,MAAM,SAAkC,EAAE,GAAG,MAAM;AACnD,KAAI,OAAO,KAAK,aAAa,CAAC,SAAS,KAAK,WAAW,KAAA,EACrD,QAAO,SAAS;AAClB,KAAI,OAAO,KAAK,aAAa,CAAC,SAAS,KAAK,WAAW,KAAA,EACrD,QAAO,SAAS;AAElB,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,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;EAAW;AAGlE,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
package/dist/schema.d.cts CHANGED
@@ -1,7 +1,10 @@
1
- import { c as ValidationResult, n as EnvDefinition } from "./types-1okexcwM.cjs";
1
+ import { l as ValidationResult, n as EnvDefinition, r as EnvPreset } from "./types-CpYkRwLM.cjs";
2
2
 
3
3
  //#region src/schema.d.ts
4
- declare function defineEnv<T extends EnvDefinition>(definition: T): T;
4
+ type DefineEnvInput = {
5
+ presets?: EnvPreset[];
6
+ } & EnvDefinition;
7
+ declare function defineEnv<T extends DefineEnvInput>(definition: T): Omit<T, 'presets'> & Pick<EnvDefinition, 'server' | 'client'>;
5
8
  declare function validateEnv(def: EnvDefinition, rawEnv: Record<string, string>): ValidationResult;
6
9
  //#endregion
7
10
  export { defineEnv, validateEnv };
package/dist/schema.d.mts CHANGED
@@ -1,7 +1,10 @@
1
- import { c as ValidationResult, n as EnvDefinition } from "./types-DuWT_251.mjs";
1
+ import { l as ValidationResult, n as EnvDefinition, r as EnvPreset } from "./types--Km3TAdJ.mjs";
2
2
 
3
3
  //#region src/schema.d.ts
4
- declare function defineEnv<T extends EnvDefinition>(definition: T): T;
4
+ type DefineEnvInput = {
5
+ presets?: EnvPreset[];
6
+ } & EnvDefinition;
7
+ declare function defineEnv<T extends DefineEnvInput>(definition: T): Omit<T, 'presets'> & Pick<EnvDefinition, 'server' | 'client'>;
5
8
  declare function validateEnv(def: EnvDefinition, rawEnv: Record<string, string>): ValidationResult;
6
9
  //#endregion
7
10
  export { defineEnv, validateEnv };
package/dist/schema.mjs CHANGED
@@ -1,10 +1,31 @@
1
1
  import { z } from "zod";
2
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.`);
3
+ function warnSideConflicts(keys, seen, userKeys, side) {
4
+ for (const key of keys) {
5
+ const duplicate = seen.has(key);
6
+ if (duplicate) console.warn(`[vite-env] "${key}" is defined in multiple presets. The last preset wins.`);
7
+ seen.add(key);
8
+ if (!duplicate && userKeys.has(key)) console.warn(`[vite-env] "${key}" is defined in both a preset and your ${side} config. Your definition wins.`);
9
+ }
10
+ }
11
+ function warnConflicts(presets, userServerKeys, userClientKeys) {
12
+ const seenServerKeys = /* @__PURE__ */ new Set();
13
+ const seenClientKeys = /* @__PURE__ */ new Set();
14
+ for (const preset of presets) {
15
+ warnSideConflicts(Object.keys(preset.server ?? {}), seenServerKeys, userServerKeys, "server");
16
+ warnSideConflicts(Object.keys(preset.client ?? {}), seenClientKeys, userClientKeys, "client");
6
17
  }
7
- return definition;
18
+ }
19
+ function defineEnv(definition) {
20
+ const { presets = [], server, client, ...rest } = definition;
21
+ const mergedServer = Object.assign({}, ...presets.map((p) => p.server ?? {}), server);
22
+ const mergedClient = Object.assign({}, ...presets.map((p) => p.client ?? {}), client);
23
+ warnConflicts(presets, new Set(Object.keys(server ?? {})), new Set(Object.keys(client ?? {})));
24
+ for (const key of Object.keys(mergedClient)) 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.`);
25
+ const result = { ...rest };
26
+ if (Object.keys(mergedServer).length > 0 || server !== void 0) result.server = mergedServer;
27
+ if (Object.keys(mergedClient).length > 0 || client !== void 0) result.client = mergedClient;
28
+ return result;
8
29
  }
9
30
  function validateEnv(def, rawEnv) {
10
31
  const combinedShape = {
@@ -1 +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<T extends EnvDefinition>(definition: T): T {\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\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 }\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: [] as const }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;AAGA,SAAgB,UAAmC,YAAkB;AACnE,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;;AAKP,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,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;EAAW;AAGlE,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
1
+ {"version":3,"file":"schema.mjs","names":[],"sources":["../src/schema.ts"],"sourcesContent":["import type { EnvDefinition, EnvPreset, ValidationResult } from './types'\nimport { z } from 'zod'\n\ntype DefineEnvInput = {\n presets?: EnvPreset[]\n} & EnvDefinition\n\nfunction warnSideConflicts(\n keys: string[],\n seen: Set<string>,\n userKeys: Set<string>,\n side: 'server' | 'client',\n): void {\n for (const key of keys) {\n const duplicate = seen.has(key)\n if (duplicate)\n console.warn(`[vite-env] \"${key}\" is defined in multiple presets. The last preset wins.`)\n seen.add(key)\n if (!duplicate && userKeys.has(key))\n console.warn(`[vite-env] \"${key}\" is defined in both a preset and your ${side} config. Your definition wins.`)\n }\n}\n\nfunction warnConflicts(\n presets: EnvPreset[],\n userServerKeys: Set<string>,\n userClientKeys: Set<string>,\n): void {\n const seenServerKeys = new Set<string>()\n const seenClientKeys = new Set<string>()\n\n for (const preset of presets) {\n warnSideConflicts(Object.keys(preset.server ?? {}), seenServerKeys, userServerKeys, 'server')\n warnSideConflicts(Object.keys(preset.client ?? {}), seenClientKeys, userClientKeys, 'client')\n }\n}\n\nexport function defineEnv<T extends DefineEnvInput>(definition: T): Omit<T, 'presets'> & Pick<EnvDefinition, 'server' | 'client'> {\n const { presets = [], server, client, ...rest } = definition\n // ...rest intentionally forwarded — T may carry extra keys beyond EnvDefinition\n\n const mergedServer: z.ZodRawShape = Object.assign({}, ...presets.map(p => p.server ?? {}), server)\n const mergedClient: z.ZodRawShape = Object.assign({}, ...presets.map(p => p.client ?? {}), client)\n\n warnConflicts(\n presets,\n new Set(Object.keys(server ?? {})),\n new Set(Object.keys(client ?? {})),\n )\n\n for (const key of Object.keys(mergedClient)) {\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 const result: Record<string, unknown> = { ...rest }\n if (Object.keys(mergedServer).length > 0 || server !== undefined)\n result.server = mergedServer\n if (Object.keys(mergedClient).length > 0 || client !== undefined)\n result.client = mergedClient\n\n return result as Omit<T, 'presets'>\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 }\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: [] as const }\n }\n\n return {\n success: false,\n data: null,\n errors: result.error.issues,\n }\n}\n"],"mappings":";;AAOA,SAAS,kBACP,MACA,MACA,UACA,MACM;AACN,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,MAAI,UACF,SAAQ,KAAK,eAAe,IAAI,yDAAyD;AAC3F,OAAK,IAAI,IAAI;AACb,MAAI,CAAC,aAAa,SAAS,IAAI,IAAI,CACjC,SAAQ,KAAK,eAAe,IAAI,yCAAyC,KAAK,gCAAgC;;;AAIpH,SAAS,cACP,SACA,gBACA,gBACM;CACN,MAAM,iCAAiB,IAAI,KAAa;CACxC,MAAM,iCAAiB,IAAI,KAAa;AAExC,MAAK,MAAM,UAAU,SAAS;AAC5B,oBAAkB,OAAO,KAAK,OAAO,UAAU,EAAE,CAAC,EAAE,gBAAgB,gBAAgB,SAAS;AAC7F,oBAAkB,OAAO,KAAK,OAAO,UAAU,EAAE,CAAC,EAAE,gBAAgB,gBAAgB,SAAS;;;AAIjG,SAAgB,UAAoC,YAA8E;CAChI,MAAM,EAAE,UAAU,EAAE,EAAE,QAAQ,QAAQ,GAAG,SAAS;CAGlD,MAAM,eAA8B,OAAO,OAAO,EAAE,EAAE,GAAG,QAAQ,KAAI,MAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO;CAClG,MAAM,eAA8B,OAAO,OAAO,EAAE,EAAE,GAAG,QAAQ,KAAI,MAAK,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO;AAElG,eACE,SACA,IAAI,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,EAClC,IAAI,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC,CAAC,CACnC;AAED,MAAK,MAAM,OAAO,OAAO,KAAK,aAAa,CACzC,KAAI,CAAC,IAAI,WAAW,QAAQ,CAC1B,OAAM,IAAI,MACR,8BAA8B,IAAI,uDACR,IAAI,0CAC/B;CAIL,MAAM,SAAkC,EAAE,GAAG,MAAM;AACnD,KAAI,OAAO,KAAK,aAAa,CAAC,SAAS,KAAK,WAAW,KAAA,EACrD,QAAO,SAAS;AAClB,KAAI,OAAO,KAAK,aAAa,CAAC,SAAS,KAAK,WAAW,KAAA,EACrD,QAAO,SAAS;AAElB,QAAO;;AAGT,SAAgB,YACd,KACA,QACkB;CAClB,MAAM,gBAAgB;EACpB,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;EAAW;AAGlE,QAAO;EACL,SAAS;EACT,MAAM;EACN,QAAQ,OAAO,MAAM;EACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"standard.cjs","names":[],"sources":["../src/standard.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type { StandardEnvDefinition, StandardValidationIssue, StandardValidationResult } from './types'\n\nexport function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(\n definition: T,\n): T & { readonly _standard: true } {\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\n return { ...definition, _standard: true as const }\n}\n\nexport function isStandardEnvDefinition(\n def: unknown,\n): def is StandardEnvDefinition {\n return def != null && typeof def === 'object' && '_standard' in def && (def as any)._standard === true\n}\n\nexport async function validateStandardEnv(\n def: StandardEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<StandardValidationResult> {\n const combinedShape: Record<string, StandardSchemaV1> = {\n ...def.server,\n ...def.client,\n }\n\n const errors: StandardValidationIssue[] = []\n const data: Record<string, unknown> = {}\n\n for (const [key, schema] of Object.entries(combinedShape)) {\n const result = await schema['~standard'].validate(rawEnv[key])\n\n if ('issues' in result && result.issues) {\n for (const issue of result.issues) {\n errors.push({\n message: issue.message,\n path: [key, ...(issue.path ?? [])],\n })\n }\n }\n else {\n data[key] = (result as { value: unknown }).value\n }\n }\n\n if (errors.length > 0) {\n return { success: false, data: null, errors }\n }\n\n return { success: true, data, errors: [] as const }\n}\n"],"mappings":";;AAGA,SAAgB,kBACd,YACkC;AAClC,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;;AAKP,QAAO;EAAE,GAAG;EAAY,WAAW;EAAe;;AAGpD,SAAgB,wBACd,KAC8B;AAC9B,QAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,eAAe,OAAQ,IAAY,cAAc;;AAGpG,eAAsB,oBACpB,KACA,QACmC;CACnC,MAAM,gBAAkD;EACtD,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAED,MAAM,SAAoC,EAAE;CAC5C,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,cAAc,EAAE;EACzD,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,OAAO,KAAK;AAE9D,MAAI,YAAY,UAAU,OAAO,OAC/B,MAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,SAAS,MAAM;GACf,MAAM,CAAC,KAAK,GAAI,MAAM,QAAQ,EAAE,CAAE;GACnC,CAAC;MAIJ,MAAK,OAAQ,OAA8B;;AAI/C,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,SAAS;EAAO,MAAM;EAAM;EAAQ;AAG/C,QAAO;EAAE,SAAS;EAAM;EAAM,QAAQ,EAAE;EAAW"}
1
+ {"version":3,"file":"standard.cjs","names":[],"sources":["../src/standard.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type { StandardEnvDefinition, StandardValidationIssue, StandardValidationResult } from './types'\n\nexport function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(\n definition: T,\n): T & { readonly _standard: true } {\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\n return { ...definition, _standard: true as const }\n}\n\nexport function isStandardEnvDefinition(\n def: unknown,\n): def is StandardEnvDefinition {\n return def != null && typeof def === 'object' && '_standard' in def && (def as Record<string, unknown>)._standard === true\n}\n\nexport async function validateStandardEnv(\n def: StandardEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<StandardValidationResult> {\n const combinedShape: Record<string, StandardSchemaV1> = {\n ...def.server,\n ...def.client,\n }\n\n const errors: StandardValidationIssue[] = []\n const data: Record<string, unknown> = {}\n\n for (const [key, schema] of Object.entries(combinedShape)) {\n const result = await schema['~standard'].validate(rawEnv[key])\n\n if ('issues' in result && result.issues) {\n for (const issue of result.issues) {\n errors.push({\n message: issue.message,\n path: [key, ...(issue.path ?? [])],\n })\n }\n }\n else {\n data[key] = (result as { value: unknown }).value\n }\n }\n\n if (errors.length > 0) {\n return { success: false, data: null, errors }\n }\n\n return { success: true, data, errors: [] as const }\n}\n"],"mappings":";;AAGA,SAAgB,kBACd,YACkC;AAClC,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;;AAKP,QAAO;EAAE,GAAG;EAAY,WAAW;EAAe;;AAGpD,SAAgB,wBACd,KAC8B;AAC9B,QAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,eAAe,OAAQ,IAAgC,cAAc;;AAGxH,eAAsB,oBACpB,KACA,QACmC;CACnC,MAAM,gBAAkD;EACtD,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAED,MAAM,SAAoC,EAAE;CAC5C,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,cAAc,EAAE;EACzD,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,OAAO,KAAK;AAE9D,MAAI,YAAY,UAAU,OAAO,OAC/B,MAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,SAAS,MAAM;GACf,MAAM,CAAC,KAAK,GAAI,MAAM,QAAQ,EAAE,CAAE;GACnC,CAAC;MAIJ,MAAK,OAAQ,OAA8B;;AAI/C,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,SAAS;EAAO,MAAM;EAAM;EAAQ;AAG/C,QAAO;EAAE,SAAS;EAAM;EAAM,QAAQ,EAAE;EAAW"}
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, s as StandardValidationResult } from "./types-1okexcwM.cjs";
1
+ import { c as StandardValidationResult, o as StandardEnvDefinition } from "./types-CpYkRwLM.cjs";
2
2
 
3
3
  //#region src/standard.d.ts
4
4
  declare function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(definition: T): T & {
@@ -1,4 +1,4 @@
1
- import { a as StandardEnvDefinition, s as StandardValidationResult } from "./types-DuWT_251.mjs";
1
+ import { c as StandardValidationResult, o as StandardEnvDefinition } from "./types--Km3TAdJ.mjs";
2
2
 
3
3
  //#region src/standard.d.ts
4
4
  declare function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(definition: T): T & {
@@ -1 +1 @@
1
- {"version":3,"file":"standard.mjs","names":[],"sources":["../src/standard.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type { StandardEnvDefinition, StandardValidationIssue, StandardValidationResult } from './types'\n\nexport function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(\n definition: T,\n): T & { readonly _standard: true } {\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\n return { ...definition, _standard: true as const }\n}\n\nexport function isStandardEnvDefinition(\n def: unknown,\n): def is StandardEnvDefinition {\n return def != null && typeof def === 'object' && '_standard' in def && (def as any)._standard === true\n}\n\nexport async function validateStandardEnv(\n def: StandardEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<StandardValidationResult> {\n const combinedShape: Record<string, StandardSchemaV1> = {\n ...def.server,\n ...def.client,\n }\n\n const errors: StandardValidationIssue[] = []\n const data: Record<string, unknown> = {}\n\n for (const [key, schema] of Object.entries(combinedShape)) {\n const result = await schema['~standard'].validate(rawEnv[key])\n\n if ('issues' in result && result.issues) {\n for (const issue of result.issues) {\n errors.push({\n message: issue.message,\n path: [key, ...(issue.path ?? [])],\n })\n }\n }\n else {\n data[key] = (result as { value: unknown }).value\n }\n }\n\n if (errors.length > 0) {\n return { success: false, data: null, errors }\n }\n\n return { success: true, data, errors: [] as const }\n}\n"],"mappings":";AAGA,SAAgB,kBACd,YACkC;AAClC,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;;AAKP,QAAO;EAAE,GAAG;EAAY,WAAW;EAAe;;AAGpD,SAAgB,wBACd,KAC8B;AAC9B,QAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,eAAe,OAAQ,IAAY,cAAc;;AAGpG,eAAsB,oBACpB,KACA,QACmC;CACnC,MAAM,gBAAkD;EACtD,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAED,MAAM,SAAoC,EAAE;CAC5C,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,cAAc,EAAE;EACzD,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,OAAO,KAAK;AAE9D,MAAI,YAAY,UAAU,OAAO,OAC/B,MAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,SAAS,MAAM;GACf,MAAM,CAAC,KAAK,GAAI,MAAM,QAAQ,EAAE,CAAE;GACnC,CAAC;MAIJ,MAAK,OAAQ,OAA8B;;AAI/C,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,SAAS;EAAO,MAAM;EAAM;EAAQ;AAG/C,QAAO;EAAE,SAAS;EAAM;EAAM,QAAQ,EAAE;EAAW"}
1
+ {"version":3,"file":"standard.mjs","names":[],"sources":["../src/standard.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type { StandardEnvDefinition, StandardValidationIssue, StandardValidationResult } from './types'\n\nexport function defineStandardEnv<T extends Omit<StandardEnvDefinition, '_standard'>>(\n definition: T,\n): T & { readonly _standard: true } {\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\n return { ...definition, _standard: true as const }\n}\n\nexport function isStandardEnvDefinition(\n def: unknown,\n): def is StandardEnvDefinition {\n return def != null && typeof def === 'object' && '_standard' in def && (def as Record<string, unknown>)._standard === true\n}\n\nexport async function validateStandardEnv(\n def: StandardEnvDefinition,\n rawEnv: Record<string, string>,\n): Promise<StandardValidationResult> {\n const combinedShape: Record<string, StandardSchemaV1> = {\n ...def.server,\n ...def.client,\n }\n\n const errors: StandardValidationIssue[] = []\n const data: Record<string, unknown> = {}\n\n for (const [key, schema] of Object.entries(combinedShape)) {\n const result = await schema['~standard'].validate(rawEnv[key])\n\n if ('issues' in result && result.issues) {\n for (const issue of result.issues) {\n errors.push({\n message: issue.message,\n path: [key, ...(issue.path ?? [])],\n })\n }\n }\n else {\n data[key] = (result as { value: unknown }).value\n }\n }\n\n if (errors.length > 0) {\n return { success: false, data: null, errors }\n }\n\n return { success: true, data, errors: [] as const }\n}\n"],"mappings":";AAGA,SAAgB,kBACd,YACkC;AAClC,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;;AAKP,QAAO;EAAE,GAAG;EAAY,WAAW;EAAe;;AAGpD,SAAgB,wBACd,KAC8B;AAC9B,QAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,eAAe,OAAQ,IAAgC,cAAc;;AAGxH,eAAsB,oBACpB,KACA,QACmC;CACnC,MAAM,gBAAkD;EACtD,GAAG,IAAI;EACP,GAAG,IAAI;EACR;CAED,MAAM,SAAoC,EAAE;CAC5C,MAAM,OAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,cAAc,EAAE;EACzD,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,OAAO,KAAK;AAE9D,MAAI,YAAY,UAAU,OAAO,OAC/B,MAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,SAAS,MAAM;GACf,MAAM,CAAC,KAAK,GAAI,MAAM,QAAQ,EAAE,CAAE;GACnC,CAAC;MAIJ,MAAK,OAAQ,OAA8B;;AAI/C,KAAI,OAAO,SAAS,EAClB,QAAO;EAAE,SAAS;EAAO,MAAM;EAAM;EAAQ;AAG/C,QAAO;EAAE,SAAS;EAAM;EAAM,QAAQ,EAAE;EAAW"}
@@ -1,17 +1,20 @@
1
- import { StandardSchemaV1 } from "@standard-schema/spec";
2
1
  import { z } from "zod";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
3
 
4
4
  //#region src/types.d.ts
5
- interface EnvDefinition {
5
+ type EnvDefinition = {
6
6
  server?: z.ZodRawShape;
7
7
  client?: z.ZodRawShape;
8
- }
9
- interface StandardEnvDefinition {
8
+ };
9
+ type StandardEnvDefinition = {
10
10
  server?: Record<string, StandardSchemaV1>;
11
- client?: Record<string, StandardSchemaV1>;
12
- /** @internal */
11
+ client?: Record<string, StandardSchemaV1>; /** @internal */
13
12
  readonly _standard: true;
14
- }
13
+ };
14
+ type EnvPreset = {
15
+ server?: z.ZodRawShape;
16
+ client?: z.ZodRawShape;
17
+ };
15
18
  type AnyEnvDefinition = EnvDefinition | StandardEnvDefinition;
16
19
  type ValidationResult = {
17
20
  success: true;
@@ -22,10 +25,10 @@ type ValidationResult = {
22
25
  data: null;
23
26
  errors: z.core.$ZodIssue[];
24
27
  };
25
- interface StandardValidationIssue {
28
+ type StandardValidationIssue = {
26
29
  message: string;
27
- path: ReadonlyArray<PropertyKey | StandardSchemaV1.PathSegment>;
28
- }
30
+ path: readonly (PropertyKey | StandardSchemaV1.PathSegment)[];
31
+ };
29
32
  type StandardValidationResult = {
30
33
  success: true;
31
34
  data: Record<string, unknown>;
@@ -39,5 +42,5 @@ type OrEmptyShape<T> = T extends z.ZodRawShape ? T : Record<string, never>;
39
42
  type InferClientEnv<T extends EnvDefinition> = z.infer<z.ZodObject<OrEmptyShape<T['client']>>>;
40
43
  type InferServerEnv<T extends EnvDefinition> = z.infer<z.ZodObject<OrEmptyShape<T['server']> & OrEmptyShape<T['client']>>>;
41
44
  //#endregion
42
- export { StandardEnvDefinition as a, ValidationResult as c, InferServerEnv as i, EnvDefinition as n, StandardValidationIssue as o, InferClientEnv as r, StandardValidationResult as s, AnyEnvDefinition as t };
43
- //# sourceMappingURL=types-1okexcwM.d.cts.map
45
+ export { InferServerEnv as a, StandardValidationResult as c, InferClientEnv as i, ValidationResult as l, EnvDefinition as n, StandardEnvDefinition as o, EnvPreset as r, StandardValidationIssue as s, AnyEnvDefinition as t };
46
+ //# sourceMappingURL=types--Km3TAdJ.d.mts.map
@@ -1,17 +1,20 @@
1
- import { z } from "zod";
2
1
  import { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import { z } from "zod";
3
3
 
4
4
  //#region src/types.d.ts
5
- interface EnvDefinition {
5
+ type EnvDefinition = {
6
6
  server?: z.ZodRawShape;
7
7
  client?: z.ZodRawShape;
8
- }
9
- interface StandardEnvDefinition {
8
+ };
9
+ type StandardEnvDefinition = {
10
10
  server?: Record<string, StandardSchemaV1>;
11
- client?: Record<string, StandardSchemaV1>;
12
- /** @internal */
11
+ client?: Record<string, StandardSchemaV1>; /** @internal */
13
12
  readonly _standard: true;
14
- }
13
+ };
14
+ type EnvPreset = {
15
+ server?: z.ZodRawShape;
16
+ client?: z.ZodRawShape;
17
+ };
15
18
  type AnyEnvDefinition = EnvDefinition | StandardEnvDefinition;
16
19
  type ValidationResult = {
17
20
  success: true;
@@ -22,10 +25,10 @@ type ValidationResult = {
22
25
  data: null;
23
26
  errors: z.core.$ZodIssue[];
24
27
  };
25
- interface StandardValidationIssue {
28
+ type StandardValidationIssue = {
26
29
  message: string;
27
- path: ReadonlyArray<PropertyKey | StandardSchemaV1.PathSegment>;
28
- }
30
+ path: readonly (PropertyKey | StandardSchemaV1.PathSegment)[];
31
+ };
29
32
  type StandardValidationResult = {
30
33
  success: true;
31
34
  data: Record<string, unknown>;
@@ -39,5 +42,5 @@ type OrEmptyShape<T> = T extends z.ZodRawShape ? T : Record<string, never>;
39
42
  type InferClientEnv<T extends EnvDefinition> = z.infer<z.ZodObject<OrEmptyShape<T['client']>>>;
40
43
  type InferServerEnv<T extends EnvDefinition> = z.infer<z.ZodObject<OrEmptyShape<T['server']> & OrEmptyShape<T['client']>>>;
41
44
  //#endregion
42
- export { StandardEnvDefinition as a, ValidationResult as c, InferServerEnv as i, EnvDefinition as n, StandardValidationIssue as o, InferClientEnv as r, StandardValidationResult as s, AnyEnvDefinition as t };
43
- //# sourceMappingURL=types-DuWT_251.d.mts.map
45
+ export { InferServerEnv as a, StandardValidationResult as c, InferClientEnv as i, ValidationResult as l, EnvDefinition as n, StandardEnvDefinition as o, EnvPreset as r, StandardValidationIssue as s, AnyEnvDefinition as t };
46
+ //# sourceMappingURL=types-CpYkRwLM.d.cts.map
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://raw.githubusercontent.com/vitejs/vite-plugin-registry/refs/heads/main/data/schema/extended-package-json.schema.json",
3
3
  "name": "@vite-env/core",
4
4
  "type": "module",
5
- "version": "0.4.0",
5
+ "version": "0.5.1",
6
6
  "description": "The env.ts layer for Vite — define once, validate everywhere, import with types",
7
7
  "license": "MIT",
8
8
  "homepage": "https://github.com/pyyupsk/vite-env#readme",
@@ -104,6 +104,16 @@
104
104
  "default": "./dist/standard.cjs"
105
105
  }
106
106
  },
107
+ "./presets": {
108
+ "import": {
109
+ "types": "./dist/presets/index.d.mts",
110
+ "default": "./dist/presets/index.mjs"
111
+ },
112
+ "require": {
113
+ "types": "./dist/presets/index.d.cts",
114
+ "default": "./dist/presets/index.cjs"
115
+ }
116
+ },
107
117
  "./package.json": "./package.json"
108
118
  },
109
119
  "main": "./dist/index.cjs",
@@ -134,7 +144,7 @@
134
144
  "@vitest/coverage-v8": "^4.1.2",
135
145
  "tsdown": "^0.21.7",
136
146
  "typescript": "^6.0.2",
137
- "vite": "^8.0.3",
147
+ "vite": "^8.0.8",
138
148
  "vitest": "^4.1.2",
139
149
  "zod": "^4.3.6"
140
150
  },