import { z } from "zod"; /** * Sunucu ortam değişkenleri şeması. * * Doğrulama tembel (lazy) yapılır: `next build` sırasında (ör. Docker build aşamasında) * sırlar henüz tanımlı olmadığı için modül yüklenirken değil, ilk `env()` çağrısında çalışır. * Sunucu ilk isteği işlerken eksik/hatalı bir değişken varsa açık bir hata ile durur. */ export const serverEnvSchema = z.object({ NODE_ENV: z.enum(["development", "test", "production"]).default("development"), MONGODB_URI: z .string() .min(1, "MONGODB_URI zorunlu") .refine((v) => v.startsWith("mongodb://") || v.startsWith("mongodb+srv://"), { message: "MONGODB_URI mongodb:// veya mongodb+srv:// ile başlamalı", }), BETTER_AUTH_SECRET: z.string().min(32, "BETTER_AUTH_SECRET en az 32 karakter olmalı"), BETTER_AUTH_URL: z.url("BETTER_AUTH_URL geçerli bir URL olmalı"), SEED_ADMIN_EMAIL: z.email().optional(), SEED_ADMIN_PASSWORD: z.string().min(8).optional(), /** Örnek (geliştirme) kullanıcılarının ortak şifresi; production'da kullanılmaz. */ SEED_USER_PASSWORD: z.string().min(8).optional(), UPLOAD_DIR: z.string().min(1).default("./uploads"), MAX_UPLOAD_MB: z.coerce.number().int().positive().max(100).default(10), APP_VERSION: z.string().optional(), APP_COMMIT: z.string().optional(), }); export type ServerEnv = z.infer; /** Boş string'leri tanımsız say (`.env` dosyalarında `KEY=""` yaygın). */ function normalize(source: Record) { return Object.fromEntries(Object.entries(source).map(([k, v]) => [k, v === "" ? undefined : v])); } export function parseServerEnv(source: Record): ServerEnv { const result = serverEnvSchema.safeParse(normalize(source)); if (!result.success) { const issues = result.error.issues .map((i) => ` - ${i.path.join(".") || "(kök)"}: ${i.message}`) .join("\n"); throw new Error(`Geçersiz ortam değişkenleri:\n${issues}`); } return result.data; } let cached: ServerEnv | undefined; /** Doğrulanmış sunucu ortam değişkenleri. Yalnızca sunucu kodunda kullan. */ export function env(): ServerEnv { cached ??= parseServerEnv(process.env); return cached; }