import dotenv from "dotenv"; import type { Secrets } from "./secrets.js"; export interface AppConfig { NODE_ENV: "development" | "production" | "test" | "staging"; PORT: number; SUPABASE_URL: string; SUPABASE_SERVICE_ROLE_KEY: string; SUPABASE_CONNECTION_STRING: string; SUPABASE_CA_CERT: string; STREAM_CHAT_API_KEY: string; STREAM_CHAT_API_SECRET: string; STRIPE_SECRET_KEY: string; STRIPE_WEBHOOK_SECRET: string; STRIPE_SOLO_PRICE_ID: string; STRIPE_TEAM_MONTHLY_PRICE_ID: string; STRIPE_FOUNDER_PRICE_ID: string; EMAIL_USER: string; EMAIL_CLIENT_ID: string; EMAIL_CLIENT_SECRET: string; EMAIL_REFRESH_TOKEN: string; XTABLO_URL: string; R2_ACCOUNT_ID: string; R2_ACCESS_KEY_ID: string; R2_SECRET_ACCESS_KEY: string; LOG_LEVEL: "debug" | "info" | "warn" | "error"; TASKS_SECRET: string; /** * Test user */ TEST_USER_DATA: { id: string; email: string; user_metadata: Record; app_metadata: Record; aud: string; created_at: string; }; } function validateEnvVar(name: string, value: string | undefined): string { if (!value) { throw new Error(`Missing required environment variable: ${name}`); } return value; } export function createConfig(secrets?: Secrets): AppConfig { const NODE_ENV = (process.env.NODE_ENV || "development") as | "development" | "production" | "staging" | "test"; dotenv.config({ path: `.env.${NODE_ENV}` }); // In test mode, use environment variables directly instead of secrets const isTestMode = NODE_ENV === "test"; const isStagingMode = NODE_ENV === "staging"; const getStreamChatApiSecret = (isStagingMode: boolean) => isStagingMode ? secrets!.streamChatApiSecretStaging : secrets!.streamChatApiSecret; const getStripeSecretKey = (isStagingMode: boolean) => isStagingMode ? secrets!.stripeSecretKeyStaging : secrets!.stripeSecretKey; const getStripeWebhookSecret = (isStagingMode: boolean) => isStagingMode ? secrets!.stripeWebhookSecretStaging : secrets!.stripeWebhookSecret; const getStripeSecretKeyFromEnv = () => process.env.STRIPE_SECRET_KEY; const getStripeWebhookSecretFromEnv = () => process.env.STRIPE_WEBHOOK_SECRET; // Base configuration const baseConfig: AppConfig = { NODE_ENV, PORT: parseInt(process.env.PORT || "8080", 10), SUPABASE_URL: validateEnvVar("SUPABASE_URL", process.env.SUPABASE_URL), SUPABASE_SERVICE_ROLE_KEY: isTestMode ? validateEnvVar("SUPABASE_SERVICE_ROLE_KEY", process.env.SUPABASE_SERVICE_ROLE_KEY) : secrets!.supabaseServiceRoleKey, SUPABASE_CONNECTION_STRING: isTestMode ? validateEnvVar("SUPABASE_CONNECTION_STRING", process.env.SUPABASE_CONNECTION_STRING) : secrets!.supabaseConnectionString, SUPABASE_CA_CERT: isTestMode ? validateEnvVar("SUPABASE_CA_CERT", process.env.SUPABASE_CA_CERT) : secrets!.supabaseCaCert, STREAM_CHAT_API_KEY: validateEnvVar("STREAM_CHAT_API_KEY", process.env.STREAM_CHAT_API_KEY), // Env dependent STREAM_CHAT_API_SECRET: isTestMode ? validateEnvVar("STREAM_CHAT_API_SECRET", process.env.STREAM_CHAT_API_SECRET) : getStreamChatApiSecret(isStagingMode), STRIPE_SECRET_KEY: isTestMode ? validateEnvVar("STRIPE_SECRET_KEY", process.env.STRIPE_SECRET_KEY) : getStripeSecretKeyFromEnv() || getStripeSecretKey(isStagingMode), STRIPE_WEBHOOK_SECRET: isTestMode ? validateEnvVar("STRIPE_WEBHOOK_SECRET", process.env.STRIPE_WEBHOOK_SECRET) : getStripeWebhookSecretFromEnv() || getStripeWebhookSecret(isStagingMode), STRIPE_SOLO_PRICE_ID: validateEnvVar( "STRIPE_SOLO_PRICE_ID", process.env.STRIPE_SOLO_PRICE_ID ), STRIPE_TEAM_MONTHLY_PRICE_ID: validateEnvVar( "STRIPE_TEAM_MONTHLY_PRICE_ID", process.env.STRIPE_TEAM_MONTHLY_PRICE_ID ), STRIPE_FOUNDER_PRICE_ID: validateEnvVar( "STRIPE_FOUNDER_PRICE_ID", process.env.STRIPE_FOUNDER_PRICE_ID ), EMAIL_USER: validateEnvVar("EMAIL_USER", process.env.EMAIL_USER), EMAIL_CLIENT_ID: validateEnvVar("EMAIL_CLIENT_ID", process.env.EMAIL_CLIENT_ID), EMAIL_CLIENT_SECRET: isTestMode ? validateEnvVar("EMAIL_CLIENT_SECRET", process.env.EMAIL_CLIENT_SECRET) : secrets!.emailClientSecret, EMAIL_REFRESH_TOKEN: isTestMode ? validateEnvVar("EMAIL_REFRESH_TOKEN", process.env.EMAIL_REFRESH_TOKEN) : secrets!.emailRefreshToken, XTABLO_URL: process.env.XTABLO_URL || "https://app.xtablo.com", R2_ACCOUNT_ID: validateEnvVar("R2_ACCOUNT_ID", process.env.R2_ACCOUNT_ID), R2_ACCESS_KEY_ID: isTestMode ? validateEnvVar("R2_ACCESS_KEY_ID", process.env.R2_ACCESS_KEY_ID) : secrets!.r2AccessKeyId, R2_SECRET_ACCESS_KEY: isTestMode ? validateEnvVar("R2_SECRET_ACCESS_KEY", process.env.R2_SECRET_ACCESS_KEY) : secrets!.r2SecretAccessKey, TASKS_SECRET: process.env.TASKS_SECRET || "", LOG_LEVEL: "info", TEST_USER_DATA: { id: "test", email: "test@test.com", user_metadata: {}, app_metadata: {}, aud: "test", created_at: new Date("2025-01-01").toISOString(), }, }; // Environment-specific configurations if (NODE_ENV === "development") { baseConfig.LOG_LEVEL = "debug"; } else if (NODE_ENV === "production") { baseConfig.LOG_LEVEL = "info"; } console.log("✓ Configuration loaded successfully"); return baseConfig; } // Helper functions for common environment checks // export const isDevelopment = () => config.NODE_ENV === "development"; // export const isProduction = () => config.NODE_ENV === "production";