import { z } from 'zod'; /** * Helper to parse boolean from string */ const booleanString = z .string() .optional() .default('false') .transform((val) => val === 'true'); /** * Environment variables schema validation using Zod */ export const envSchema = z.object({ // Environment NODE_ENV: z .enum(['development', 'production', 'test']) .default('development'), PORT: z.coerce.number().default(3000), // Database DATABASE_URL: z.string().url(), // JWT JWT_SECRET: z.string().min(32), JWT_ACCESS_EXPIRATION: z.string().default('15m'), JWT_REFRESH_EXPIRATION: z.string().default('7d'), // Redis REDIS_HOST: z.string().default('localhost'), REDIS_PORT: z.coerce.number().default(6379), REDIS_PASSWORD: z.string().optional(), // i18n DEFAULT_LANGUAGE: z.string().default('en'), FALLBACK_LANGUAGE: z.string().default('en'), // Optional Features ENABLE_MAIL: booleanString, ENABLE_S3: booleanString, ENABLE_WEBSOCKET: booleanString, ENABLE_MULTI_TENANCY: booleanString, // Mail (Optional) MAIL_HOST: z.string().optional(), MAIL_PORT: z.coerce.number().optional(), MAIL_USER: z.string().optional(), MAIL_PASSWORD: z.string().optional(), MAIL_FROM: z.string().optional(), // S3 (Optional) S3_ENDPOINT: z.string().optional(), S3_ACCESS_KEY: z.string().optional(), S3_SECRET_KEY: z.string().optional(), S3_BUCKET: z.string().optional(), S3_REGION: z.string().optional(), // Throttle THROTTLE_TTL: z.coerce.number().default(60000), THROTTLE_LIMIT: z.coerce.number().default(100), }); export type EnvConfig = z.infer; /** * Validate environment variables */ export function validateEnv(config: Record): EnvConfig { const result = envSchema.safeParse(config); if (!result.success) { const errors = result.error.issues.map( (err) => `${err.path.join('.')}: ${err.message}`, ); throw new Error(`Environment validation failed:\n${errors.join('\n')}`); } return result.data; }