import "../src/plugins/dotenv.js"; import { z } from "zod"; // Функция для обязательных строковых переменных const requiredString = (envVar: string, defaultValue?: string) => { return z.preprocess( (val) => { if (typeof val !== "string" || val.trim() === "") { if (defaultValue !== undefined) return defaultValue; return z.NEVER; } return val.trim(); }, z .string() .min( 1, `${envVar} не определен. Пожалуйста, задайте переменную в файле ${process.env.NODE_ENV === "production" ? ".env" : ".dev.env"} или переменных окружения.`, ), ); }; // Функция для обязательных числовых переменных const requiredNumber = (envVar: string, defaultValue?: number) => { return z.preprocess( (val) => { if (val === undefined || val === null || val === "") { if (defaultValue !== undefined) return defaultValue; return z.NEVER; } // Если значение передано не строкой и не числом — ошибка if (typeof val !== "string" && typeof val !== "number") { return z.NEVER; } const parsed = Number(val); if (!isFinite(parsed)) { return z.NEVER; } return parsed; }, z.number().min(1, `${envVar} должен быть числом. Например: 5432.`), ); }; // Описание схемы переменных окружения const ConfigSchema = z.object({ PORT: requiredNumber("PORT", 3000), LOGS_LEVEL: z .enum(["error", "warn", "info", "verbose", "debug", "silly"]) .default("info"), API_URL: requiredString("API_URL"), // DB DB_USER: requiredString("DB_USER"), DB_HOST: requiredString("DB_HOST"), DB_PORT: requiredNumber("DB_PORT"), DB_NAME: requiredString("DB_NAME"), DB_PASS: requiredString("DB_PASS"), // MAIL SMTP_HOST: requiredString("SMTP_HOST"), SMTP_PORT: requiredNumber("SMTP_PORT"), SMTP_USER: requiredString("SMTP_USER"), SMTP_PASS: requiredString("SMTP_PASS"), // AUTH JWT_ACCESS_SECRET: requiredString("JWT_ACCESS_SECRET"), JWT_REFRESH_SECRET: requiredString("JWT_REFRESH_SECRET"), PASSWORD_MAX_TRIES: requiredNumber("PASSWORD_MAX_TRIES", 5), ACCESS_TOKEN_LIFETIME_MINS: requiredNumber("ACCESS_TOKEN_LIFETIME_MINS", 15), REFRESH_TOKEN_LIFETIME_DAYS: requiredNumber("REFRESH_TOKEN_LIFETIME_DAYS", 7), // CONFIRM PINS CONFIRM_PIN_LIFETIME_MINS: requiredNumber("CONFIRM_PIN_LIFETIME_MINS", 10), CONFIRM_PIN_MAX_TRIES: requiredNumber("CONFIRM_PIN_MAX_TRIES", 3), }); // Проверяем валидность конфигурации const result = ConfigSchema.safeParse(process.env); if (!result.success) { console.error( "❌ Невалидные переменные окружения:\n", JSON.stringify(result.error.format(), null, 2), ); process.exit(1); } export const config = result.data; // Экспорт типа конфигурации export type Config = z.infer; // Логируем успешную валидацию без чувствительных данных const safeConfig = { ...config, DB_PASS: "********", SMTP_PASS: "********", JWT_ACCESS_SECRET: "********", JWT_REFRESH_SECRET: "********", }; console.debug("✅ Валидация env прошла успешно:", safeConfig);