Consolidate env at repo root
- Move all application env vars to repository-root .env (with .env.example as the committed template) and drop the per-app .env.example files. - Add @code/env subpaths (agent, convex) and consume validated exports everywhere instead of reading process.env directly. - Wire every dev/build/start script to load ../../.env via bun --env-file and point vite.config.ts envDir at the repo root.
This commit is contained in:
32
.env.example
Normal file
32
.env.example
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Shared application endpoints
|
||||||
|
CONVEX_DEPLOYMENT=dev:example-deployment
|
||||||
|
CONVEX_URL=https://example.convex.cloud
|
||||||
|
CONVEX_SITE_URL=https://example.convex.site
|
||||||
|
SITE_URL=http://localhost:5173
|
||||||
|
NATIVE_APP_URL=code://
|
||||||
|
|
||||||
|
# Browser and native public endpoints
|
||||||
|
VITE_CONVEX_URL=https://example.convex.cloud
|
||||||
|
VITE_CONVEX_SITE_URL=https://example.convex.site
|
||||||
|
EXPO_PUBLIC_CONVEX_URL=https://example.convex.cloud
|
||||||
|
EXPO_PUBLIC_CONVEX_SITE_URL=https://example.convex.site
|
||||||
|
|
||||||
|
# Daemon identity and control plane
|
||||||
|
DAEMON_ID=local-macbook
|
||||||
|
DAEMON_NAME=Local MacBook
|
||||||
|
DAEMON_VERSION=0.0.0
|
||||||
|
DAEMON_HEARTBEAT_MS=15000
|
||||||
|
DAEMON_COMMAND_LEASE_MS=60000
|
||||||
|
# RIVET_ENDPOINT=http://localhost:6420
|
||||||
|
|
||||||
|
# Flue persistence adapter
|
||||||
|
FLUE_DB_TOKEN=replace-with-a-long-random-token
|
||||||
|
|
||||||
|
# Agent model provider
|
||||||
|
AGENT_MODEL_PROVIDER=cheaptricks
|
||||||
|
AGENT_MODEL_NAME=minimax-m3
|
||||||
|
AGENT_MODEL_API=openai-completions
|
||||||
|
AGENT_MODEL_BASE_URL=https://ai.example.com/v1
|
||||||
|
AGENT_MODEL_API_KEY=replace-with-provider-api-key
|
||||||
|
AGENT_MODEL_CONTEXT_WINDOW=262000
|
||||||
|
AGENT_MODEL_MAX_TOKENS=131072
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,9 +11,10 @@ build
|
|||||||
# Generated files
|
# Generated files
|
||||||
apps/web/src/routeTree.gen.ts
|
apps/web/src/routeTree.gen.ts
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables live at the repository root
|
||||||
.env
|
.env
|
||||||
.env*.local
|
.env*.local
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
CONVEX_URL=https://example.convex.cloud
|
|
||||||
DAEMON_ID=local-macbook
|
|
||||||
DAEMON_NAME=Local MacBook
|
|
||||||
DAEMON_VERSION=0.0.0
|
|
||||||
DAEMON_HEARTBEAT_MS=15000
|
|
||||||
DAEMON_COMMAND_LEASE_MS=60000
|
|
||||||
# RIVET_ENDPOINT=http://localhost:6420
|
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"module": "src/index.ts",
|
"module": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --watch src/index.ts",
|
"dev": "bun --env-file=../../.env run --watch src/index.ts",
|
||||||
"build": "bun build src/index.ts --compile --outfile dist/code-daemon",
|
"build": "bun --env-file=../../.env build src/index.ts --compile --outfile dist/code-daemon",
|
||||||
"start": "./dist/code-daemon",
|
"start": "bun --env-file=../../.env ./dist/code-daemon",
|
||||||
"check-types": "tsc --noEmit"
|
"check-types": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"main": "expo-router/entry",
|
"main": "expo-router/entry",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start",
|
"start": "bun --env-file=../../.env expo start",
|
||||||
"dev": "expo start --clear",
|
"dev": "bun --env-file=../../.env expo start --clear",
|
||||||
"android": "expo run:android",
|
"android": "bun --env-file=../../.env expo run:android",
|
||||||
"ios": "expo run:ios",
|
"ios": "bun --env-file=../../.env expo run:ios",
|
||||||
"prebuild": "expo prebuild",
|
"prebuild": "bun --env-file=../../.env expo prebuild",
|
||||||
"web": "expo start --web"
|
"web": "bun --env-file=../../.env expo start --web"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@better-auth/expo": "catalog:",
|
"@better-auth/expo": "catalog:",
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
"@tanstack/react-form": "catalog:",
|
"@tanstack/react-form": "catalog:",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"expo": "~57.0.1",
|
"expo": "~57.0.1",
|
||||||
"expo-constants": "~57.0.2",
|
"expo-constants": "~57.0.2",
|
||||||
"expo-font": "~57.0.0",
|
"expo-font": "~57.0.0",
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
"@tanstack/react-form": "catalog:",
|
"@tanstack/react-form": "catalog:",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"isbot": "^5.1.44",
|
"isbot": "^5.1.44",
|
||||||
"lucide-react": "catalog:",
|
"lucide-react": "catalog:",
|
||||||
"next-themes": "catalog:",
|
"next-themes": "catalog:",
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
|
||||||
import { reactRouter } from "@react-router/dev/vite";
|
import { reactRouter } from "@react-router/dev/vite";
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import { defineConfig } from "vite-plus";
|
import { defineConfig } from "vite-plus";
|
||||||
import tsconfigPaths from "vite-tsconfig-paths";
|
import tsconfigPaths from "vite-tsconfig-paths";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
envDir: path.resolve(import.meta.dirname, "../.."),
|
||||||
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
|
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
|
||||||
});
|
});
|
||||||
|
|||||||
13
bun.lock
13
bun.lock
@@ -4,11 +4,6 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "code",
|
"name": "code",
|
||||||
"dependencies": {
|
|
||||||
"@code/env": "workspace:*",
|
|
||||||
"dotenv": "catalog:",
|
|
||||||
"zod": "catalog:",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@code/config": "workspace:*",
|
"@code/config": "workspace:*",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
@@ -67,7 +62,6 @@
|
|||||||
"@tanstack/react-form": "catalog:",
|
"@tanstack/react-form": "catalog:",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"expo": "~57.0.1",
|
"expo": "~57.0.1",
|
||||||
"expo-constants": "~57.0.2",
|
"expo-constants": "~57.0.2",
|
||||||
"expo-font": "~57.0.0",
|
"expo-font": "~57.0.0",
|
||||||
@@ -130,7 +124,6 @@
|
|||||||
"@tanstack/react-form": "catalog:",
|
"@tanstack/react-form": "catalog:",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"isbot": "^5.1.44",
|
"isbot": "^5.1.44",
|
||||||
"lucide-react": "catalog:",
|
"lucide-react": "catalog:",
|
||||||
"next-themes": "catalog:",
|
"next-themes": "catalog:",
|
||||||
@@ -158,7 +151,10 @@
|
|||||||
"name": "@code/agents",
|
"name": "@code/agents",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@code/env": "workspace:*",
|
||||||
"@flue/runtime": "latest",
|
"@flue/runtime": "latest",
|
||||||
|
"convex": "catalog:",
|
||||||
|
"hono": "^4.12.30",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@code/config": "workspace:*",
|
"@code/config": "workspace:*",
|
||||||
@@ -171,10 +167,10 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@better-auth/expo": "catalog:",
|
"@better-auth/expo": "catalog:",
|
||||||
|
"@code/env": "workspace:*",
|
||||||
"@convex-dev/better-auth": "catalog:",
|
"@convex-dev/better-auth": "catalog:",
|
||||||
"better-auth": "catalog:",
|
"better-auth": "catalog:",
|
||||||
"convex": "catalog:",
|
"convex": "catalog:",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -192,7 +188,6 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@t3-oss/env-core": "^0.13.11",
|
"@t3-oss/env-core": "^0.13.11",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"hooks:setup": "vp config",
|
"hooks:setup": "vp config",
|
||||||
"dev:native": "vp run --filter native dev",
|
"dev:native": "vp run --filter native dev",
|
||||||
"dev:web": "vp run --filter web dev",
|
"dev:web": "vp run --filter web dev",
|
||||||
|
"dev:agents": "vp run --filter @code/agents dev",
|
||||||
"dev:desktop": "vp run --filter desktop dev:hmr",
|
"dev:desktop": "vp run --filter desktop dev:hmr",
|
||||||
"build:desktop": "vp run --filter desktop build:stable",
|
"build:desktop": "vp run --filter desktop build:stable",
|
||||||
"build:desktop:canary": "vp run --filter desktop build:canary",
|
"build:desktop:canary": "vp run --filter desktop build:canary",
|
||||||
@@ -42,15 +43,12 @@
|
|||||||
"dev:setup": "vp run --filter @code/backend dev:setup",
|
"dev:setup": "vp run --filter @code/backend dev:setup",
|
||||||
"dev:daemon": "vp run --filter daemon dev",
|
"dev:daemon": "vp run --filter daemon dev",
|
||||||
"build:daemon": "vp run --filter daemon build",
|
"build:daemon": "vp run --filter daemon build",
|
||||||
|
"build:agents": "vp run --filter @code/agents build",
|
||||||
"docs:update": "bun run scripts/update-docs.ts",
|
"docs:update": "bun run scripts/update-docs.ts",
|
||||||
"subtree": "bun run scripts/subtree.ts",
|
"subtree": "bun run scripts/subtree.ts",
|
||||||
"fix": "ultracite fix"
|
"fix": "ultracite fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"@code/env": "workspace:*",
|
|
||||||
"dotenv": "catalog:",
|
|
||||||
"zod": "catalog:"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@code/config": "workspace:*",
|
"@code/config": "workspace:*",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
|||||||
7
packages/env/package.json
vendored
7
packages/env/package.json
vendored
@@ -4,13 +4,14 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./web": "./src/web.ts",
|
"./agent": "./src/agent.ts",
|
||||||
|
"./convex": "./src/convex.ts",
|
||||||
"./native": "./src/native.ts",
|
"./native": "./src/native.ts",
|
||||||
"./server": "./src/server.ts"
|
"./server": "./src/server.ts",
|
||||||
|
"./web": "./src/web.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@t3-oss/env-core": "^0.13.11",
|
"@t3-oss/env-core": "^0.13.11",
|
||||||
"dotenv": "catalog:",
|
|
||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
17
packages/env/src/agent.ts
vendored
Normal file
17
packages/env/src/agent.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const agentEnvSchema = z.object({
|
||||||
|
AGENT_MODEL_API: z.literal("openai-completions"),
|
||||||
|
AGENT_MODEL_API_KEY: z.string().min(1),
|
||||||
|
AGENT_MODEL_BASE_URL: z.url(),
|
||||||
|
AGENT_MODEL_CONTEXT_WINDOW: z.coerce.number().int().positive(),
|
||||||
|
AGENT_MODEL_MAX_TOKENS: z.coerce.number().int().positive(),
|
||||||
|
AGENT_MODEL_NAME: z.string().min(1),
|
||||||
|
AGENT_MODEL_PROVIDER: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AgentEnv = z.infer<typeof agentEnvSchema>;
|
||||||
|
|
||||||
|
export const parseAgentEnv = (
|
||||||
|
runtimeEnv: Record<string, string | undefined>
|
||||||
|
): AgentEnv => agentEnvSchema.parse(runtimeEnv);
|
||||||
13
packages/env/src/convex.ts
vendored
Normal file
13
packages/env/src/convex.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { createEnv } from "@t3-oss/env-core";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const env = createEnv({
|
||||||
|
emptyStringAsUndefined: true,
|
||||||
|
runtimeEnv: process.env,
|
||||||
|
server: {
|
||||||
|
CONVEX_SITE_URL: z.url(),
|
||||||
|
FLUE_DB_TOKEN: z.string().min(1),
|
||||||
|
NATIVE_APP_URL: z.string().min(1).default("code://"),
|
||||||
|
SITE_URL: z.url(),
|
||||||
|
},
|
||||||
|
});
|
||||||
1
packages/env/src/server.ts
vendored
1
packages/env/src/server.ts
vendored
@@ -14,6 +14,7 @@ export const env = createEnv({
|
|||||||
DAEMON_VERSION: z.string().default("0.0.0"),
|
DAEMON_VERSION: z.string().default("0.0.0"),
|
||||||
DAEMON_HEARTBEAT_MS: z.coerce.number().int().positive().default(15_000),
|
DAEMON_HEARTBEAT_MS: z.coerce.number().int().positive().default(15_000),
|
||||||
DAEMON_COMMAND_LEASE_MS: z.coerce.number().int().positive().default(60_000),
|
DAEMON_COMMAND_LEASE_MS: z.coerce.number().int().positive().default(60_000),
|
||||||
|
FLUE_DB_TOKEN: z.string().min(1),
|
||||||
RIVET_ENDPOINT: z.url().optional(),
|
RIVET_ENDPOINT: z.url().optional(),
|
||||||
},
|
},
|
||||||
runtimeEnv: process.env,
|
runtimeEnv: process.env,
|
||||||
|
|||||||
9
packages/env/src/vite-env.d.ts
vendored
Normal file
9
packages/env/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly [key: string]: string | number | boolean | undefined;
|
||||||
|
readonly VITE_CONVEX_SITE_URL: string;
|
||||||
|
readonly VITE_CONVEX_URL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
7
packages/env/src/web.ts
vendored
7
packages/env/src/web.ts
vendored
@@ -7,12 +7,11 @@ const convexUrlSchema = (exampleHost: string) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
clientPrefix: "VITE_",
|
|
||||||
client: {
|
client: {
|
||||||
VITE_CONVEX_URL: convexUrlSchema("example.convex.cloud"),
|
|
||||||
VITE_CONVEX_SITE_URL: convexUrlSchema("example.convex.site"),
|
VITE_CONVEX_SITE_URL: convexUrlSchema("example.convex.site"),
|
||||||
|
VITE_CONVEX_URL: convexUrlSchema("example.convex.cloud"),
|
||||||
},
|
},
|
||||||
runtimeEnv: (import.meta as any).env,
|
clientPrefix: "VITE_",
|
||||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
|
runtimeEnv: import.meta.env,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user