diff --git a/apps/app/package.json b/apps/app/package.json index 8e02d3e8..0e392126 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -41,6 +41,7 @@ "devDependencies": { "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/node": "24.10.1", "@types/react": "19.1.13", diff --git a/apps/app/src/shared/env.ts b/apps/app/src/shared/env.ts index 34f2df28..63a866c7 100644 --- a/apps/app/src/shared/env.ts +++ b/apps/app/src/shared/env.ts @@ -1,4 +1,4 @@ -import { createEnv } from "@init/env" +import { createEnv, getRuntimeEnv } from "@init/env" import { auth, db } from "@init/env/presets" import { REACT_PUBLIC_ENV_PREFIX } from "@init/utils/constants" import * as z from "@init/utils/schema" @@ -13,7 +13,7 @@ export default createEnv({ extends: [auth(), auth.providers.github(), auth.providers.google(), db()], // Load server environment variables (process.env) and client environment // variables (import.meta.env) - runtimeEnv: { ...import.meta.env, ...process.env }, + runtimeEnv: getRuntimeEnv(), server: {}, skipValidation: isCI, }) diff --git a/apps/app/vite.config.ts b/apps/app/vite.config.ts index 6f61a0fa..e280fa8f 100644 --- a/apps/app/vite.config.ts +++ b/apps/app/vite.config.ts @@ -2,31 +2,36 @@ import { I18N_COOKIE_NAME } from "@init/utils/constants" import { paraglideVitePlugin as paraglide } from "@inlang/paraglide-js" import tailwindcss from "@tailwindcss/vite" import { tanstackStart } from "@tanstack/react-start/plugin/vite" +import { ensureEnv } from "@tooling/env/vite" import react from "@vitejs/plugin-react" import { nitro } from "nitro/vite" import { defineConfig } from "vite" -export default defineConfig({ - envPrefix: ["PUBLIC_"], - plugins: [ - tailwindcss(), - tanstackStart(), - react({ - babel: { - plugins: [["babel-plugin-react-compiler", {}]], - }, - }), - paraglide({ - cookieName: I18N_COOKIE_NAME, - outdir: "./src/shared/internationalization", - project: "../../tooling/internationalization/project.inlang", - strategy: ["cookie", "baseLocale"], - }), - nitro({ - preset: "bun", - }), - ], - server: { - port: 3001, - }, +export default defineConfig(({ mode }) => { + void ensureEnv(mode) + + return { + envPrefix: ["PUBLIC_"], + plugins: [ + tailwindcss(), + tanstackStart(), + react({ + babel: { + plugins: [["babel-plugin-react-compiler", {}]], + }, + }), + paraglide({ + cookieName: I18N_COOKIE_NAME, + outdir: "./src/shared/internationalization", + project: "../../tooling/internationalization/project.inlang", + strategy: ["cookie", "baseLocale"], + }), + nitro({ + preset: "bun", + }), + ], + server: { + port: 3001, + }, + } }) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 4e17e6a9..18e01f4e 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -35,6 +35,7 @@ "@tanstack/devtools-vite": "0.4.1", "@tanstack/router-plugin": "1.149.0", "@tauri-apps/cli": "2.9.6", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", diff --git a/apps/desktop/src/shared/env.ts b/apps/desktop/src/shared/env.ts index 3818032d..aa000e48 100644 --- a/apps/desktop/src/shared/env.ts +++ b/apps/desktop/src/shared/env.ts @@ -1,4 +1,4 @@ -import { createEnv } from "@init/env" +import { createEnv, getRuntimeEnv } from "@init/env" import { tauri } from "@init/env/presets" import * as z from "@init/utils/schema" import { isCI } from "std-env" @@ -9,6 +9,6 @@ export default createEnv({ }, clientPrefix: "PUBLIC_", extends: [tauri()], - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), skipValidation: isCI, }) diff --git a/apps/desktop/vite.config.ts b/apps/desktop/vite.config.ts index 404f16de..fb0ea488 100644 --- a/apps/desktop/vite.config.ts +++ b/apps/desktop/vite.config.ts @@ -2,50 +2,54 @@ import { paraglideVitePlugin as paraglide } from "@inlang/paraglide-js" import tailwindcss from "@tailwindcss/vite" import { devtools } from "@tanstack/devtools-vite" import { tanstackRouter } from "@tanstack/router-plugin/vite" +import { ensureEnv } from "@tooling/env/vite" import react from "@vitejs/plugin-react" import { defineConfig } from "vite" -const host = process.env.TAURI_DEV_HOST +export default defineConfig(({ mode }) => { + void ensureEnv(mode) + const host = process.env.TAURI_DEV_HOST -export default defineConfig({ - build: { - minify: process.env.TAURI_ENV_DEBUG ? false : "esbuild", - sourcemap: !!process.env.TAURI_ENV_DEBUG, - target: process.env.TAURI_ENV_PLATFORM === "windows" ? "chrome105" : "safari13", - }, - clearScreen: false, - envPrefix: ["PUBLIC_", "TAURI_DEV_HOST"], - plugins: [ - devtools(), - tailwindcss(), - paraglide({ - outdir: "./src/shared/internationalization", - project: "../../tooling/internationalization/project.inlang", - strategy: ["baseLocale"], - }), - tanstackRouter({ - autoCodeSplitting: false, - target: "react", - }), - react({ - babel: { - plugins: [["babel-plugin-react-compiler", {}]], + return { + build: { + minify: process.env.TAURI_ENV_DEBUG ? false : "esbuild", + sourcemap: !!process.env.TAURI_ENV_DEBUG, + target: process.env.TAURI_ENV_PLATFORM === "windows" ? "chrome105" : "safari13", + }, + clearScreen: false, + envPrefix: ["PUBLIC_", "TAURI_DEV_HOST"], + plugins: [ + devtools(), + tailwindcss(), + paraglide({ + outdir: "./src/shared/internationalization", + project: "../../tooling/internationalization/project.inlang", + strategy: ["baseLocale"], + }), + tanstackRouter({ + autoCodeSplitting: false, + target: "react", + }), + react({ + babel: { + plugins: [["babel-plugin-react-compiler", {}]], + }, + }), + ], + server: { + hmr: host + ? { + host, + port: 4003, + protocol: "ws", + } + : undefined, + host: host ?? false, + port: 3003, + strictPort: true, + watch: { + ignored: ["**/src-tauri/**"], }, - }), - ], - server: { - hmr: host - ? { - host, - port: 4003, - protocol: "ws", - } - : undefined, - host: host ?? false, - port: 3003, - strictPort: true, - watch: { - ignored: ["**/src-tauri/**"], }, - }, + } }) diff --git a/apps/extension/package.json b/apps/extension/package.json index 5e369bc1..92a40a5b 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -37,6 +37,7 @@ "devDependencies": { "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/chrome": "0.1.33", "@types/react": "19.1.13", diff --git a/apps/extension/wxt.config.ts b/apps/extension/wxt.config.ts index 0f98f4a6..9b8922f3 100644 --- a/apps/extension/wxt.config.ts +++ b/apps/extension/wxt.config.ts @@ -1,5 +1,6 @@ import { paraglideVitePlugin as paraglide } from "@inlang/paraglide-js" import tailwindcss from "@tailwindcss/vite" +import { ensureEnv } from "@tooling/env/vite" import { defineConfig } from "wxt" // See https://wxt.dev/api/config.html @@ -13,14 +14,18 @@ export default defineConfig({ imports: false, modules: ["@wxt-dev/module-react", "@wxt-dev/auto-icons"], srcDir: "src", - vite: () => ({ - plugins: [ - tailwindcss(), - paraglide({ - outdir: "./src/shared/internationalization", - project: "../../tooling/internationalization/project.inlang", - strategy: ["baseLocale"], - }), - ], - }), + vite: ({ mode }) => { + void ensureEnv(mode) + + return { + plugins: [ + tailwindcss(), + paraglide({ + outdir: "./src/shared/internationalization", + project: "../../tooling/internationalization/project.inlang", + strategy: ["baseLocale"], + }), + ], + } + }, }) diff --git a/apps/web/astro.config.ts b/apps/web/astro.config.ts index 0f1ef092..4efcaf77 100644 --- a/apps/web/astro.config.ts +++ b/apps/web/astro.config.ts @@ -2,8 +2,11 @@ import mdx from "@astrojs/mdx" import react from "@astrojs/react" import { paraglideVitePlugin as paraglide } from "@inlang/paraglide-js" import tailwindcss from "@tailwindcss/vite" +import { ensureEnv } from "@tooling/env/vite" import { defineConfig } from "astro/config" +void ensureEnv(process.env.NODE_ENV ?? "development") + export default defineConfig({ server: { port: 3006, diff --git a/apps/web/package.json b/apps/web/package.json index 4bf43abf..97f9dd53 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -32,6 +32,7 @@ "@astrojs/ts-plugin": "1.10.6", "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", diff --git a/apps/web/src/shared/env.ts b/apps/web/src/shared/env.ts index 30d096d9..a499a0c5 100644 --- a/apps/web/src/shared/env.ts +++ b/apps/web/src/shared/env.ts @@ -1,4 +1,4 @@ -import { createEnv } from "@init/env" +import { createEnv, getRuntimeEnv } from "@init/env" import * as z from "@init/utils/schema" import { isCI } from "std-env" @@ -7,7 +7,7 @@ export default createEnv({ PUBLIC_API_URL: z.url(), }, clientPrefix: "PUBLIC_", - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), server: { TEST_VAR: z.string(), }, diff --git a/bun.lock b/bun.lock index bc002ae0..5d3c289a 100644 --- a/bun.lock +++ b/bun.lock @@ -83,6 +83,7 @@ "devDependencies": { "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/node": "24.10.1", "@types/react": "19.1.13", @@ -119,6 +120,7 @@ "@tanstack/devtools-vite": "0.4.1", "@tanstack/router-plugin": "1.149.0", "@tauri-apps/cli": "2.9.6", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", @@ -169,6 +171,7 @@ "devDependencies": { "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/chrome": "0.1.33", "@types/react": "19.1.13", @@ -260,6 +263,7 @@ "@astrojs/ts-plugin": "1.10.6", "@inlang/paraglide-js": "2.8.0", "@tailwindcss/vite": "4.1.18", + "@tooling/env": "workspace:*", "@tooling/tsconfig": "workspace:*", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", @@ -527,6 +531,16 @@ "typescript": "5.9.3", }, }, + "tooling/env": { + "name": "@tooling/env", + "dependencies": { + "jiti": "2.4.2", + "vite": "7.3.1", + }, + "devDependencies": { + "@tooling/tsconfig": "workspace:*", + }, + }, "tooling/internationalization": { "name": "@tooling/internationalization", "devDependencies": { @@ -2136,6 +2150,8 @@ "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="], + "@tooling/env": ["@tooling/env@workspace:tooling/env"], + "@tooling/internationalization": ["@tooling/internationalization@workspace:tooling/internationalization"], "@tooling/tsconfig": ["@tooling/tsconfig@workspace:tooling/tsconfig"], @@ -3462,7 +3478,7 @@ "jimp-compact": ["jimp-compact@0.16.1", "", {}, "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww=="], - "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], @@ -5300,6 +5316,8 @@ "@stripe/agent-toolkit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], @@ -5406,6 +5424,8 @@ "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "c12/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cheerio/htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], @@ -5554,6 +5574,8 @@ "jsondiffpatch/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "knip/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "knip/picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "langsmith/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], @@ -5622,6 +5644,8 @@ "nitro/h3": ["h3@2.0.1-rc.5", "", { "dependencies": { "rou3": "^0.7.9", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qkohAzCab0nLzXNm78tBjZDvtKMTmtygS8BJLT3VPczAQofdqlFXDPkXdLMJN4r05+xqneG8snZJ0HgkERCZTg=="], + "nitro/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "nitro/ofetch": ["ofetch@2.0.0-alpha.3", "", {}, "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA=="], "nitro/unstorage": ["unstorage@2.0.0-alpha.5", "", { "peerDependencies": { "@azure/app-configuration": "^1.9.0", "@azure/cosmos": "^4.7.0", "@azure/data-tables": "^13.3.1", "@azure/identity": "^4.13.0", "@azure/keyvault-secrets": "^4.10.0", "@azure/storage-blob": "^12.29.1", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.12.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.35.6", "@vercel/blob": ">=0.27.3", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4 || ^5", "db0": ">=0.3.4", "idb-keyval": "^6.2.2", "ioredis": "^5.8.2", "lru-cache": "^11.2.2", "mongodb": "^6 || ^7", "ofetch": "*", "uploadthing": "^7.7.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g=="], @@ -5692,8 +5716,6 @@ "react-email/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], - "react-email/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], - "react-email/nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], diff --git a/packages/env/src/index.ts b/packages/env/src/index.ts index 56725f96..5562a873 100644 --- a/packages/env/src/index.ts +++ b/packages/env/src/index.ts @@ -1 +1,2 @@ export { createEnv } from "@t3-oss/env-core" +export { getRuntimeEnv } from "./runtime" diff --git a/packages/env/src/presets.ts b/packages/env/src/presets.ts index 21c3a77d..a9c28664 100644 --- a/packages/env/src/presets.ts +++ b/packages/env/src/presets.ts @@ -2,6 +2,7 @@ import { EXPO_PUBLIC_ENV_PREFIX, REACT_PUBLIC_ENV_PREFIX } from "@init/utils/con import * as z from "@init/utils/schema" import { createEnv } from "@t3-oss/env-core" import { isCI } from "std-env" +import { getRuntimeEnv } from "./runtime" // Presets for system environment variables from popular services (Vercel, Neon, // Supabase, Render, etc.) @@ -66,7 +67,7 @@ export const convex = { PUBLIC_CONVEX_URL: z.url(), }, clientPrefix: REACT_PUBLIC_ENV_PREFIX, - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), skipValidation: isCI, }), } @@ -133,7 +134,7 @@ export const sentry = { PUBLIC_SENTRY_DSN: z.string(), }, clientPrefix: REACT_PUBLIC_ENV_PREFIX, - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), skipValidation: isCI, }), expo: () => @@ -218,7 +219,7 @@ export const posthog = { PUBLIC_POSTHOG_HOST: z.url(), }, clientPrefix: REACT_PUBLIC_ENV_PREFIX, - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), skipValidation: isCI, }), server: () => @@ -243,6 +244,6 @@ export const tauri = () => TAURI_ENV_TARGET_TRIPLE: z.string().optional(), }, clientPrefix: "TAURI_ENV_", - runtimeEnv: import.meta.env, + runtimeEnv: getRuntimeEnv(), skipValidation: isCI, }) diff --git a/packages/env/src/runtime.ts b/packages/env/src/runtime.ts new file mode 100644 index 00000000..e08202c4 --- /dev/null +++ b/packages/env/src/runtime.ts @@ -0,0 +1,7 @@ +export type RuntimeEnv = Record + +export function getRuntimeEnv(): RuntimeEnv { + const meta = import.meta.env ?? {} + const node = globalThis.process?.env ?? {} + return { ...meta, ...node } +} diff --git a/tooling/env/package.json b/tooling/env/package.json new file mode 100644 index 00000000..a82c3bc8 --- /dev/null +++ b/tooling/env/package.json @@ -0,0 +1,19 @@ +{ + "name": "@tooling/env", + "private": true, + "type": "module", + "exports": { + "./vite": "./src/vite.ts" + }, + "scripts": { + "clean": "git clean -xdf .cache .turbo dist node_modules", + "bump:deps": "bun update --interactive" + }, + "dependencies": { + "jiti": "2.4.2", + "vite": "7.3.1" + }, + "devDependencies": { + "@tooling/tsconfig": "workspace:*" + } +} diff --git a/tooling/env/src/vite.ts b/tooling/env/src/vite.ts new file mode 100644 index 00000000..62ffd5c4 --- /dev/null +++ b/tooling/env/src/vite.ts @@ -0,0 +1,18 @@ +import { resolve } from "node:path" +import { fileURLToPath } from "node:url" +import createJiti from "jiti" +import { loadEnv } from "vite" + +const jiti = createJiti(fileURLToPath(import.meta.url)) + +// Callers may choose to void this promise to keep configs synchronous. +export async function ensureEnv( + mode: string, + cwd = process.cwd(), + envPath = "./src/shared/env.ts" +) { + const env = loadEnv(mode, cwd, "") + Object.assign(process.env, env) + await jiti.import(resolve(cwd, envPath)) + return env +} diff --git a/tooling/env/tsconfig.json b/tooling/env/tsconfig.json new file mode 100644 index 00000000..95e8f3d5 --- /dev/null +++ b/tooling/env/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@tooling/tsconfig/internal-package.json", + "include": ["src"], + "exclude": ["node_modules"] +}