| |
| |
| |
| |
|
|
| import { z } from "zod"; |
|
|
| const envSchema = z.object({ |
| |
| DATABASE_URL: z.string().url("DATABASE_URL must be a valid URL"), |
|
|
| |
| NEXTAUTH_SECRET: z.string().min(32, "NEXTAUTH_SECRET must be at least 32 characters"), |
| NEXTAUTH_URL: z.string().url("NEXTAUTH_URL must be a valid URL"), |
|
|
| |
| GOOGLE_CLIENT_ID: z.string().optional(), |
| GOOGLE_CLIENT_SECRET: z.string().optional(), |
| GITHUB_ID: z.string().optional(), |
| GITHUB_SECRET: z.string().optional(), |
|
|
| |
| REDIS_URL: z.string().url("REDIS_URL must be a valid URL").optional(), |
|
|
| |
| SENDGRID_API_KEY: z.string().optional(), |
| OPENAI_API_KEY: z.string().optional(), |
| GOOGLE_API_KEY: z.string().optional(), |
|
|
| |
| NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(), |
| SENTRY_AUTH_TOKEN: z.string().optional(), |
|
|
| |
| NODE_ENV: z.enum(["development", "staging", "production"]).default("development"), |
| NEXT_PUBLIC_APP_URL: z.string().url(), |
|
|
| |
| ENABLE_ANALYTICS: z.string().transform((v) => v === "true").default("true"), |
| ENABLE_EMAIL_NOTIFICATIONS: z.string().transform((v) => v === "true").default("true"), |
| ENABLE_TWO_FACTOR: z.string().transform((v) => v === "true").default("false"), |
| }); |
|
|
| type Environment = z.infer<typeof envSchema>; |
|
|
| let validatedEnv: Environment | null = null; |
|
|
| |
| |
| |
| export function validateEnvironment(): Environment { |
| if (validatedEnv) { |
| return validatedEnv; |
| } |
|
|
| try { |
| validatedEnv = envSchema.parse(process.env); |
| console.info("✅ Environment variables validated successfully"); |
| return validatedEnv; |
| } catch (error) { |
| if (error instanceof z.ZodError) { |
| const missingVars = error.errors |
| .map((err) => `${err.path.join(".")}: ${err.message}`) |
| .join("\n"); |
|
|
| console.error("❌ Environment validation failed:"); |
| console.error(missingVars); |
|
|
| throw new Error("Invalid environment variables. Check logs for details."); |
| } |
| throw error; |
| } |
| } |
|
|
| |
| |
| |
| export function getEnv(): Environment { |
| if (!validatedEnv) { |
| validateEnvironment(); |
| } |
| return validatedEnv!; |
| } |
|
|
| |
| |
| |
| export function isProduction(): boolean { |
| return process.env.NODE_ENV === "production"; |
| } |
|
|
| |
| |
| |
| export function isDevelopment(): boolean { |
| return process.env.NODE_ENV === "development"; |
| } |
|
|
| |
| |
| |
| export function isFeatureEnabled(featureName: string): boolean { |
| const env = getEnv(); |
| const value = env[featureName as keyof Environment] as unknown; |
| |
| if (typeof window === "undefined") { |
| try { |
| validateEnvironment(); |
| } catch (error) { |
| |
| if (process.env.NODE_ENV === "production") { |
| throw error; |
| } |
| } |
| } |
| return value === true || value === "true"; |
| } |
|
|