import type { BaseConfigType } from "@erp/core/api"; import type { ILogger } from "@repo/rdx-logger"; import dotenv from "dotenv"; import { formatZodErrors } from "./env-error"; import { EnvSchema } from "./env-schema"; import { loadCompanyCertificates } from "./load-company-certificates"; import { logConfigSummary } from "./log-config"; dotenv.config(); let _config: ConfigType | null = null; export type ConfigType = BaseConfigType & { env: string; server: { port: number; apiBasePath: string; frontendUrl: string; trustProxy: number; timezone: string; }; database: { dialect: "mysql" | "postgres" | "sqlite" | "mariadb" | "mssql" | "db2" | "snowflake" | "oracle"; host: string; port: number; name: string; user: string; password: string; logging: boolean; ssl: boolean; syncMode: string; }; auth: { jwt: { secret: string; accessExpiration: string; refreshExpiration: string; }; }; paths: { templates: string; documents: string; signedDocuments: string; fastReportBin: string; }; signingService: { url: string; method: string; timeoutMs: number; maxRetries: number; }; certificates?: Record; flags: { isProd: boolean; isDev: boolean; isTest: boolean; }; }; export const initConfig = (logger: ILogger): ConfigType => { if (_config) { return _config; } const parsed = EnvSchema.safeParse(process.env); if (!parsed.success) { const errors = formatZodErrors(parsed.error); logger.error("Invalid environment configuration", { errorCount: errors.length, errors, }); throw new Error("Invalid environment configuration"); } const env = parsed.data; const certificates = loadCompanyCertificates(env.COMPANY_CERTIFICATES_PATH, logger); _config = { env: env.NODE_ENV, server: { port: env.PORT, apiBasePath: env.API_BASE_PATH, frontendUrl: env.FRONTEND_URL, trustProxy: env.TRUST_PROXY, timezone: env.TIMEZONE, }, database: { dialect: env.DB_DIALECT, host: env.DB_HOST, port: env.DB_PORT, name: env.DB_NAME, user: env.DB_USER, password: env.DB_PASS, logging: env.DB_LOGGING, ssl: env.DB_SSL, syncMode: env.DB_SYNC_MODE, }, auth: { jwt: { secret: env.JWT_SECRET, accessExpiration: env.JWT_ACCESS_EXPIRATION, refreshExpiration: env.JWT_REFRESH_EXPIRATION, }, }, paths: { templates: env.TEMPLATES_PATH, documents: env.DOCUMENTS_PATH, signedDocuments: env.SIGNED_DOCUMENTS_PATH, fastReportBin: env.FASTREPORT_BIN, }, signingService: { url: env.SIGNING_SERVICE_URL, method: env.SIGNING_SERVICE_METHOD, timeoutMs: env.SIGNING_SERVICE_TIMEOUT_MS, maxRetries: env.SIGNING_SERVICE_MAX_RETRIES, }, certificates, flags: { isProd: env.NODE_ENV === "production", isDev: env.NODE_ENV === "development", isTest: env.NODE_ENV === "test", }, }; logConfigSummary(_config, logger); return _config; }; export const Config = (): ConfigType => { if (!_config) { throw new Error("Config not initialized. Call initConfig(logger) during bootstrap."); } return _config; };