// Centralized env loader with required-value enforcement. // Loaded once at startup; throws if anything mandatory is missing. import { z } from 'zod'; const envSchema = z.object({ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), PORT: z.coerce.number().int().positive().default(3010), DATABASE_URL: z.string().url(), REDIS_URL: z.string().url(), SESSION_SECRET: z.string().min(32, 'SESSION_SECRET must be at least 32 chars'), COOKIE_DOMAIN: z.string().default(''), UPLOAD_DIR: z.string().default('./uploads'), CORS_ORIGINS: z.string().default('http://localhost:3009'), LOG_LEVEL: z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']).default('info'), // OAuth — optional; providers without credentials are simply not offered. OAUTH_CALLBACK_BASE: z.string().default(''), GOOGLE_CLIENT_ID: z.string().default(''), GOOGLE_CLIENT_SECRET: z.string().default(''), GITHUB_CLIENT_ID: z.string().default(''), GITHUB_CLIENT_SECRET: z.string().default(''), SMTP_HOST: z.string().default(''), SMTP_PORT: z.coerce.number().int().positive().default(587), SMTP_USER: z.string().default(''), SMTP_PASS: z.string().default(''), SMTP_FROM: z.string().default('no-reply@teknav.ir'), SMS_PROVIDER: z.string().default(''), SMS_API_KEY: z.string().default(''), SMS_SENDER: z.string().default(''), }); const parsed = envSchema.safeParse(process.env); if (!parsed.success) { console.error('Invalid environment variables:'); console.error(parsed.error.flatten().fieldErrors); process.exit(1); } export const config = { ...parsed.data, corsOrigins: parsed.data.CORS_ORIGINS.split(',').map((s) => s.trim()).filter(Boolean), isProd: parsed.data.NODE_ENV === 'production', };