#!/usr/bin/env node /** * Environment Variable Generator * * Reads from .env.development and generates app-specific .env files * with the appropriate prefixes for each platform. * * Usage: pnpm setup:env */ import { readFileSync, writeFileSync, existsSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT_DIR = join(__dirname, '..'); const ENV_FILE = join(ROOT_DIR, '.env.development'); // Parse a .env file into an object function parseEnvFile(content) { const env = {}; const lines = content.split('\n'); for (const line of lines) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const match = trimmed.match(/^([^=]+)=(.*)$/); if (match) { let [, key, value] = match; // Handle quoted values if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } env[key.trim()] = value; } } return env; } // Generate env file content function generateEnvContent(vars) { const lines = ['# Auto-generated by scripts/generate-env.mjs', '# Source: .env.development', '']; for (const [key, value] of Object.entries(vars)) { // Quote values that contain special characters or newlines const needsQuotes = value.includes('\n') || value.includes(' ') || value.includes('#'); const formattedValue = needsQuotes ? `"${value}"` : value; lines.push(`${key}=${formattedValue}`); } return lines.join('\n') + '\n'; } // App configurations - maps source variables to target variables const APP_CONFIGS = [ // Mana Core Auth Service { path: 'services/mana-core-auth/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MANA_CORE_AUTH_PORT || '3001', DATABASE_URL: (env) => env.MANA_CORE_AUTH_DATABASE_URL, REDIS_HOST: (env) => env.REDIS_HOST, REDIS_PORT: (env) => env.REDIS_PORT, REDIS_PASSWORD: (env) => env.REDIS_PASSWORD || '', // JWT keys managed by Better Auth (EdDSA) - stored in auth.jwks table JWT_ACCESS_TOKEN_EXPIRY: (env) => env.JWT_ACCESS_TOKEN_EXPIRY, JWT_REFRESH_TOKEN_EXPIRY: (env) => env.JWT_REFRESH_TOKEN_EXPIRY, JWT_ISSUER: (env) => env.JWT_ISSUER, JWT_AUDIENCE: (env) => env.JWT_AUDIENCE, STRIPE_SECRET_KEY: (env) => env.STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY: (env) => env.STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRET: (env) => env.STRIPE_WEBHOOK_SECRET, CORS_ORIGINS: (env) => env.CORS_ORIGINS, CREDITS_SIGNUP_BONUS: (env) => env.CREDITS_SIGNUP_BONUS, CREDITS_DAILY_FREE: (env) => env.CREDITS_DAILY_FREE, RATE_LIMIT_TTL: (env) => env.RATE_LIMIT_TTL, RATE_LIMIT_MAX: (env) => env.RATE_LIMIT_MAX, GOOGLE_GENAI_API_KEY: (env) => env.GOOGLE_GENAI_API_KEY, }, }, // Chat Backend { path: 'apps/chat/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CHAT_BACKEND_PORT || '3002', DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', OPENROUTER_API_KEY: (env) => env.OPENROUTER_API_KEY, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DATABASE_URL: (env) => env.CHAT_DATABASE_URL, }, }, // Chat Mobile (Expo) { path: 'apps/chat/apps/mobile/.env', vars: { EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, EXPO_PUBLIC_SUPABASE_URL: (env) => env.CHAT_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_ANON_KEY: (env) => env.CHAT_SUPABASE_ANON_KEY, EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CHAT_BACKEND_PORT || '3002'}`, }, }, // Chat Web (SvelteKit) { path: 'apps/chat/apps/web/.env', vars: { PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_SUPABASE_URL: (env) => env.CHAT_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.CHAT_SUPABASE_ANON_KEY, PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CHAT_BACKEND_PORT || '3002'}`, }, }, // Maerchenzauber Backend { path: 'apps/maerchenzauber/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MAERCHENZAUBER_BACKEND_PORT || '3003', MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, APP_ID: (env) => env.MAERCHENZAUBER_APP_ID, MAERCHENZAUBER_SUPABASE_URL: (env) => env.MAERCHENZAUBER_SUPABASE_URL, MAERCHENZAUBER_SUPABASE_ANON_KEY: (env) => env.MAERCHENZAUBER_SUPABASE_ANON_KEY, MAERCHENZAUBER_JWT_SECRET: (env) => env.MAERCHENZAUBER_JWT_SECRET, MAERCHENZAUBER_AZURE_OPENAI_KEY: (env) => env.MAERCHENZAUBER_AZURE_OPENAI_KEY, MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT: (env) => env.MAERCHENZAUBER_AZURE_OPENAI_ENDPOINT, MAERCHENZAUBER_REPLICATE_API_KEY: (env) => env.MAERCHENZAUBER_REPLICATE_API_KEY, CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Maerchenzauber Mobile { path: 'apps/maerchenzauber/apps/mobile/.env', vars: { EXPO_PUBLIC_STORYTELLER_BACKEND_URL: (env) => `http://localhost:${env.MAERCHENZAUBER_BACKEND_PORT || '3003'}`, EXPO_ROUTER_APP_ROOT: () => 'app', }, }, // Maerchenzauber Web { path: 'apps/maerchenzauber/apps/web/.env', vars: { PUBLIC_SUPABASE_URL: (env) => env.MAERCHENZAUBER_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.MAERCHENZAUBER_SUPABASE_ANON_KEY, PUBLIC_API_URL: (env) => `http://localhost:${env.MAERCHENZAUBER_BACKEND_PORT || '3003'}`, }, }, // Manacore Mobile { path: 'apps/manacore/apps/mobile/.env', vars: { EXPO_PUBLIC_SUPABASE_URL: (env) => env.MANACORE_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_ANON_KEY: (env) => env.MANACORE_SUPABASE_ANON_KEY, }, }, // Manacore Web { path: 'apps/manacore/apps/web/.env', vars: { PUBLIC_SUPABASE_URL: (env) => env.MANACORE_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.MANACORE_SUPABASE_ANON_KEY, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Memoro Mobile { path: 'apps/memoro/apps/mobile/.env', vars: { EXPO_PUBLIC_SUPABASE_URL: (env) => env.MEMORO_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_ANON_KEY: (env) => env.MEMORO_SUPABASE_ANON_KEY, EXPO_PUBLIC_MIDDLEWARE_API_URL: (env) => env.MEMORO_MIDDLEWARE_API_URL, EXPO_PUBLIC_APPID: (env) => env.MEMORO_APPID, }, }, // Memoro Web { path: 'apps/memoro/apps/web/.env', vars: { PUBLIC_SUPABASE_URL: (env) => env.MEMORO_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.MEMORO_SUPABASE_ANON_KEY, }, }, // Manadeck Backend { path: 'apps/manadeck/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MANADECK_BACKEND_PORT || '3004', DATABASE_URL: (env) => env.MANADECK_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, APP_ID: (env) => env.MANADECK_APP_ID, GOOGLE_GENAI_API_KEY: (env) => env.GOOGLE_GENAI_API_KEY, }, }, // Manadeck Web { path: 'apps/manadeck/apps/web/.env', vars: { PUBLIC_SUPABASE_URL: (env) => env.MANADECK_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.MANADECK_SUPABASE_ANON_KEY, PUBLIC_API_URL: (env) => `http://localhost:${env.MANADECK_BACKEND_PORT || '3004'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Picture Backend (NestJS) { path: 'apps/picture/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.PICTURE_BACKEND_PORT || '3006', BACKEND_URL: (env) => env.PICTURE_BACKEND_URL || 'http://localhost:3006', DATABASE_URL: (env) => env.PICTURE_DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/picture', MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', REPLICATE_API_TOKEN: (env) => env.PICTURE_REPLICATE_API_TOKEN, CORS_ORIGINS: (env) => env.CORS_ORIGINS, // Storage configuration - use shared MinIO for local dev STORAGE_MODE: (env) => env.PICTURE_STORAGE_MODE || 's3', LOCAL_STORAGE_PATH: (env) => env.PICTURE_LOCAL_STORAGE_PATH || './uploads', S3_ENDPOINT: (env) => env.S3_ENDPOINT || 'http://localhost:9000', S3_REGION: (env) => env.S3_REGION || 'us-east-1', S3_ACCESS_KEY: (env) => env.S3_ACCESS_KEY || 'minioadmin', S3_SECRET_KEY: (env) => env.S3_SECRET_KEY || 'minioadmin', S3_BUCKET: (env) => env.PICTURE_S3_BUCKET || 'picture-storage', STORAGE_PUBLIC_URL: (env) => env.PICTURE_STORAGE_PUBLIC_URL || 'http://localhost:9000/picture-storage', // Credit system (for staging) APP_ID: (env) => env.PICTURE_APP_ID || 'picture-app', MANA_CORE_SERVICE_KEY: (env) => env.PICTURE_MANA_CORE_SERVICE_KEY || '', }, }, // Picture Mobile (Expo) { path: 'apps/picture/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => env.PICTURE_BACKEND_URL || 'http://localhost:3003', EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Picture Web (SvelteKit) - No Supabase, uses Backend API { path: 'apps/picture/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => env.PICTURE_BACKEND_URL || 'http://localhost:3003', PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_GOOGLE_CLIENT_ID: (env) => env.PICTURE_GOOGLE_CLIENT_ID || '', PUBLIC_APPLE_CLIENT_ID: (env) => env.PICTURE_APPLE_CLIENT_ID || '', }, }, // Nutriphi Backend (NestJS) { path: 'apps/nutriphi/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.NUTRIPHI_BACKEND_PORT || '3002', DATABASE_URL: (env) => env.NUTRIPHI_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, GEMINI_API_KEY: (env) => env.NUTRIPHI_GEMINI_API_KEY, S3_ENDPOINT: (env) => env.NUTRIPHI_S3_ENDPOINT, S3_ACCESS_KEY_ID: (env) => env.NUTRIPHI_S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY: (env) => env.NUTRIPHI_S3_SECRET_ACCESS_KEY, S3_BUCKET_NAME: (env) => env.NUTRIPHI_S3_BUCKET_NAME, S3_REGION: (env) => env.NUTRIPHI_S3_REGION, S3_PUBLIC_URL: (env) => env.NUTRIPHI_S3_PUBLIC_URL, }, }, // Nutriphi Web (SvelteKit) { path: 'apps/nutriphi/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.NUTRIPHI_BACKEND_PORT || '3002'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_MIDDLEWARE_APP_ID: (env) => env.NUTRIPHI_APP_ID || 'nutriphi', }, }, // Zitare Backend (NestJS) { path: 'apps/zitare/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.ZITARE_BACKEND_PORT || '3007', DATABASE_URL: (env) => env.ZITARE_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Zitare Mobile (Expo) { path: 'apps/zitare/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.ZITARE_BACKEND_PORT || '3007'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Zitare Web (SvelteKit) { path: 'apps/zitare/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.ZITARE_BACKEND_PORT || '3007'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Presi Backend (NestJS) { path: 'apps/presi/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.PRESI_BACKEND_PORT || '3008', DATABASE_URL: (env) => env.PRESI_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', // JWT keys fetched via JWKS from MANA_CORE_AUTH_URL/api/v1/auth/jwks CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Presi Mobile (Expo) { path: 'apps/presi/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.PRESI_BACKEND_PORT || '3008'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Presi Web (SvelteKit) { path: 'apps/presi/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.PRESI_BACKEND_PORT || '3008'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Mana Games Backend (NestJS) { path: 'games/mana-games/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MANA_GAMES_BACKEND_PORT || '3011', // Google Gemini GOOGLE_GENAI_API_KEY: (env) => env.MANA_GAMES_GOOGLE_GENAI_API_KEY, // Anthropic Claude ANTHROPIC_API_KEY: (env) => env.MANA_GAMES_ANTHROPIC_API_KEY, // Azure OpenAI AZURE_OPENAI_ENDPOINT: (env) => env.MANA_GAMES_AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY: (env) => env.MANA_GAMES_AZURE_OPENAI_API_KEY, AZURE_OPENAI_DEPLOYMENT: (env) => env.MANA_GAMES_AZURE_OPENAI_DEPLOYMENT || 'gpt-4o', // GitHub GITHUB_TOKEN: (env) => env.MANA_GAMES_GITHUB_TOKEN, GITHUB_OWNER: (env) => env.MANA_GAMES_GITHUB_OWNER || 'tillschneider', GITHUB_REPO: (env) => env.MANA_GAMES_GITHUB_REPO || 'mana-games', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Mana Games Web (Astro) { path: 'games/mana-games/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.MANA_GAMES_BACKEND_PORT || '3011'}`, }, }, // Calendar Backend (NestJS) { path: 'apps/calendar/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CALENDAR_BACKEND_PORT || '3014', DATABASE_URL: (env) => env.CALENDAR_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Calendar Mobile (Expo) { path: 'apps/calendar/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CALENDAR_BACKEND_PORT || '3014'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Calendar Web (SvelteKit) { path: 'apps/calendar/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CALENDAR_BACKEND_PORT || '3014'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_TODO_BACKEND_URL: (env) => env.TODO_BACKEND_URL || `http://localhost:${env.TODO_BACKEND_PORT || '3018'}`, // Cross-app integration: Contacts service for birthdays PUBLIC_CONTACTS_API_URL: (env) => `http://localhost:${env.CONTACTS_BACKEND_PORT || '3015'}`, PUBLIC_CONTACTS_WEB_URL: () => 'http://localhost:5184', }, }, // Contacts Backend (NestJS) { path: 'apps/contacts/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CONTACTS_BACKEND_PORT || '3015', DATABASE_URL: (env) => env.CONTACTS_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', S3_ENDPOINT: (env) => env.S3_ENDPOINT, S3_REGION: (env) => env.S3_REGION, S3_ACCESS_KEY: (env) => env.S3_ACCESS_KEY, S3_SECRET_KEY: (env) => env.S3_SECRET_KEY, S3_BUCKET: (env) => env.CONTACTS_S3_BUCKET || 'contacts-photos', CORS_ORIGINS: (env) => env.CORS_ORIGINS, // Google OAuth for contacts import GOOGLE_CLIENT_ID: (env) => env.CONTACTS_GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: (env) => env.CONTACTS_GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI: (env) => env.CONTACTS_GOOGLE_REDIRECT_URI, }, }, // Contacts Mobile (Expo) { path: 'apps/contacts/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CONTACTS_BACKEND_PORT || '3015'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Contacts Web (SvelteKit) { path: 'apps/contacts/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CONTACTS_BACKEND_PORT || '3015'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Storage Backend (NestJS) { path: 'apps/storage/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.STORAGE_BACKEND_PORT || '3016', DATABASE_URL: (env) => env.STORAGE_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', S3_ENDPOINT: (env) => env.S3_ENDPOINT, S3_REGION: (env) => env.S3_REGION, S3_ACCESS_KEY: (env) => env.S3_ACCESS_KEY, S3_SECRET_KEY: (env) => env.S3_SECRET_KEY, STORAGE_S3_PUBLIC_URL: (env) => env.STORAGE_S3_PUBLIC_URL, STORAGE_MAX_FILE_SIZE: (env) => env.STORAGE_MAX_FILE_SIZE || '104857600', STORAGE_MAX_FILES_PER_UPLOAD: (env) => env.STORAGE_MAX_FILES_PER_UPLOAD || '10', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Storage Web (SvelteKit) { path: 'apps/storage/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.STORAGE_BACKEND_PORT || '3016'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Clock Backend (NestJS) { path: 'apps/clock/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CLOCK_BACKEND_PORT || '3017', DATABASE_URL: (env) => env.CLOCK_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Clock Web (SvelteKit) { path: 'apps/clock/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CLOCK_BACKEND_PORT || '3017'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Todo Backend (NestJS) { path: 'apps/todo/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.TODO_BACKEND_PORT || '3018', DATABASE_URL: (env) => env.TODO_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Todo Web (SvelteKit) { path: 'apps/todo/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.TODO_BACKEND_PORT || '3018'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Moodlit Backend (NestJS) { path: 'apps/moodlit/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MOODLIT_BACKEND_PORT || '3012', DATABASE_URL: (env) => env.MOODLIT_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Moodlit Mobile (Expo) { path: 'apps/moodlit/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.MOODLIT_BACKEND_PORT || '3012'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Moodlit Web (SvelteKit) { path: 'apps/moodlit/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.MOODLIT_BACKEND_PORT || '3012'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Finance Backend (NestJS) { path: 'apps/finance/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.FINANCE_BACKEND_PORT || '3019', DATABASE_URL: (env) => env.FINANCE_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Finance Mobile (Expo) { path: 'apps/finance/apps/mobile/.env', vars: { EXPO_PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.FINANCE_BACKEND_PORT || '3019'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Finance Web (SvelteKit) { path: 'apps/finance/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.FINANCE_BACKEND_PORT || '3019'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Worldream Web (SvelteKit) { path: 'games/worldream/apps/web/.env', vars: { PUBLIC_SUPABASE_URL: (env) => env.WORLDREAM_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY: (env) => env.WORLDREAM_SUPABASE_ANON_KEY, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, OPENAI_API_KEY: (env) => env.WORLDREAM_OPENAI_API_KEY, GEMINI_API_KEY: (env) => env.WORLDREAM_GEMINI_API_KEY, REPLICATE_API_TOKEN: (env) => env.WORLDREAM_REPLICATE_API_TOKEN, }, }, // TechBase Backend (NestJS) { path: 'apps/techbase/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.TECHBASE_BACKEND_PORT || '3021', DATABASE_URL: (env) => env.TECHBASE_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, CORS_ORIGINS: () => 'http://localhost:4321,http://localhost:5173', }, }, // TechBase Web (Astro) { path: 'apps/techbase/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.TECHBASE_BACKEND_PORT || '3021'}`, }, }, ]; function main() { console.log('Generating environment files from .env.development...\n'); // Check if source file exists if (!existsSync(ENV_FILE)) { console.error(`Error: ${ENV_FILE} not found.`); console.error('Please create .env.development from .env.development.example'); process.exit(1); } // Parse source env file const sourceContent = readFileSync(ENV_FILE, 'utf-8'); const sourceEnv = parseEnvFile(sourceContent); let generated = 0; let skipped = 0; for (const config of APP_CONFIGS) { const targetPath = join(ROOT_DIR, config.path); const targetDir = dirname(targetPath); // Check if target directory exists if (!existsSync(targetDir)) { console.log(` Skipping ${config.path} (directory not found)`); skipped++; continue; } // Generate variables const targetVars = {}; for (const [key, getter] of Object.entries(config.vars)) { const value = getter(sourceEnv); if (value !== undefined && value !== null) { targetVars[key] = value; } } // Write file const content = generateEnvContent(targetVars); writeFileSync(targetPath, content); console.log(` Generated ${config.path}`); generated++; } console.log(`\nDone! Generated ${generated} files, skipped ${skipped}.`); console.log('\nNote: Generated .env files are gitignored. Only .env.development is committed.'); } main();