#!/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_PRIVATE_KEY: (env) => env.JWT_PRIVATE_KEY, JWT_PUBLIC_KEY: (env) => env.JWT_PUBLIC_KEY, 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, OLLAMA_URL: (env) => env.OLLAMA_URL || 'http://localhost:11434', 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'}`, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CHAT || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, MIDDLEWARE_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MANACORE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MANADECK || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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 || '', PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PICTURE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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', PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_NUTRIPHI || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_ZITARE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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_PUBLIC_KEY: (env) => env.JWT_PUBLIC_KEY, 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PRESI || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // SkillTree Backend (NestJS) { path: 'apps/skilltree/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.SKILLTREE_BACKEND_PORT || '3024', DATABASE_URL: (env) => env.SKILLTREE_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_PUBLIC_KEY: (env) => env.JWT_PUBLIC_KEY, CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // SkillTree Web (SvelteKit) { path: 'apps/skilltree/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.SKILLTREE_BACKEND_PORT || '3024'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_SKILLTREE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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'}`, }, }, // Context Backend (NestJS) { path: 'apps/context/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CONTEXT_BACKEND_PORT || '3020', DATABASE_URL: (env) => env.CONTEXT_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', AZURE_OPENAI_API_KEY: (env) => env.CONTEXT_AZURE_OPENAI_API_KEY || '', AZURE_OPENAI_ENDPOINT: (env) => env.CONTEXT_AZURE_OPENAI_ENDPOINT || '', GOOGLE_API_KEY: (env) => env.CONTEXT_GOOGLE_API_KEY || '', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Context Web (SvelteKit) { path: 'apps/context/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CONTEXT_BACKEND_PORT || '3020'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // 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', // Speech-to-Text Service PUBLIC_STT_URL: (env) => env.STT_URL || 'http://localhost:3020', PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CALENDAR || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CONTACTS || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_STORAGE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CLOCK || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_TODO || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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, }, }, // CityCorners Backend (NestJS) { path: 'apps/citycorners/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.CITYCORNERS_BACKEND_PORT || '3025', DATABASE_URL: (env) => env.CITYCORNERS_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, }, }, // CityCorners Web (SvelteKit) { path: 'apps/citycorners/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.CITYCORNERS_BACKEND_PORT || '3025'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // 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'}`, }, }, // Traces Backend (NestJS) { path: 'apps/traces/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.TRACES_BACKEND_PORT || '3026', DATABASE_URL: (env) => env.TRACES_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, MANA_LLM_URL: (env) => env.MANA_LLM_URL || 'http://localhost:3025', MANA_SEARCH_URL: (env) => env.MANA_SEARCH_URL || 'http://localhost:3021', MANA_CORE_SERVICE_KEY: (env) => env.MANA_CORE_SERVICE_KEY || '', APP_ID: () => 'traces', DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Traces Mobile (Expo) { path: 'apps/traces/apps/mobile/.env', vars: { EXPO_PUBLIC_TRACES_BACKEND_URL: (env) => `http://localhost:${env.TRACES_BACKEND_PORT || '3026'}`, EXPO_PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // Photos Web (SvelteKit) { path: 'apps/photos/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.PHOTOS_BACKEND_PORT || '3039'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PHOTOS || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // Planta Web (SvelteKit) { path: 'apps/planta/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.PLANTA_BACKEND_PORT || '3022'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PLANTA || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // Questions Web (SvelteKit) { path: 'apps/questions/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.QUESTIONS_BACKEND_PORT || '3011'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_QUESTIONS || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // Mukke Backend (NestJS) { path: 'apps/mukke/apps/backend/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.MUKKE_BACKEND_PORT || '3010', DATABASE_URL: (env) => env.MUKKE_DATABASE_URL, MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, 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: () => 'mukke-storage', DEV_BYPASS_AUTH: () => 'true', DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000', CORS_ORIGINS: (env) => env.CORS_ORIGINS, }, }, // Mukke Web (SvelteKit) { path: 'apps/mukke/apps/web/.env', vars: { PUBLIC_BACKEND_URL: (env) => `http://localhost:${env.MUKKE_BACKEND_PORT || '3010'}`, PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MUKKE || '', PUBLIC_GLITCHTIP_DSN: (env) => env.PUBLIC_GLITCHTIP_DSN || '', }, }, // LLM Playground (SvelteKit) { path: 'services/llm-playground/.env', vars: { PUBLIC_MANA_LLM_URL: (env) => env.MANA_LLM_URL || 'http://localhost:3025', PUBLIC_MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL || 'http://localhost:3001', }, }, // Zitare Telegram Bot { path: 'services/telegram-zitare-bot/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.ZITARE_BOT_PORT || '3303', TELEGRAM_BOT_TOKEN: (env) => env.ZITARE_BOT_TELEGRAM_TOKEN, DATABASE_URL: (env) => env.ZITARE_BOT_DATABASE_URL, }, }, // Todo Telegram Bot { path: 'services/telegram-todo-bot/.env', vars: { NODE_ENV: () => 'development', PORT: (env) => env.TODO_BOT_PORT || '3304', TELEGRAM_BOT_TOKEN: (env) => env.TODO_BOT_TELEGRAM_TOKEN, DATABASE_URL: (env) => env.TODO_BOT_DATABASE_URL, TODO_API_URL: (env) => env.TODO_BOT_API_URL || 'http://localhost:3018', MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL, }, }, // ========================================================== // Landing Pages (Astro) - Umami Website IDs // ========================================================== // Chat Landing { path: 'apps/chat/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CHAT_LANDING || '', }, }, // ManaCore Landing { path: 'apps/manacore/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MANACORE_LANDING || '', }, }, // ManaDeck Landing { path: 'apps/manadeck/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MANADECK_LANDING || '', }, }, // Calendar Landing { path: 'apps/calendar/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CALENDAR_LANDING || '', }, }, // Clock Landing { path: 'apps/clock/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_CLOCK_LANDING || '', }, }, // Picture Landing { path: 'apps/picture/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PICTURE_LANDING || '', }, }, // Todo Landing { path: 'apps/todo/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_TODO_LANDING || '', }, }, // NutriPhi Landing { path: 'apps/nutriphi/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_NUTRIPHI_LANDING || '', }, }, // Presi Landing { path: 'apps/presi/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_PRESI_LANDING || '', }, }, // Mukke Landing { path: 'apps/mukke/apps/landing/.env', vars: { PUBLIC_UMAMI_WEBSITE_ID: (env) => env.UMAMI_WEBSITE_ID_MUKKE_LANDING || '', }, }, ]; 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();