import { config as loadEnv } from 'dotenv' loadEnv() function optional(name: string): string | undefined { const value = process.env[name]?.trim() return value ? value : undefined } function optionalNumber(name: string): number | undefined { const raw = optional(name) if (raw === undefined) return undefined const value = Number(raw) if (!Number.isFinite(value)) throw new Error(`${name} must be a number, got "${raw}"`) return value } /** * amoCRM settings. Deliberately not throwing when they are missing: the site * must still boot and serve pages without a CRM connection — only the lead * endpoint degrades, and it says so explicitly. */ export interface AmoConfig { baseUrl: string token: string pipelineId: number responsibleUserId?: number tags: string[] } export function readAmoConfig(): AmoConfig | null { const subdomain = optional('AMO_SUBDOMAIN') const token = optional('AMO_LONG_LIVED_TOKEN') if (!subdomain || !token) return null // Accepts "exotherapy", "exotherapy.amocrm.ru", or a full URL (an explicit // scheme is kept as-is, which is what local mocks and self-hosted setups need). const host = subdomain.replace(/\/+$/, '') const baseUrl = /^https?:\/\//.test(host) ? host : `https://${host.includes('.') ? host : `${host}.${optional('AMO_DOMAIN') ?? 'amocrm.ru'}`}` return { baseUrl, token, pipelineId: optionalNumber('AMO_PIPELINE_ID') ?? 10980758, responsibleUserId: optionalNumber('AMO_RESPONSIBLE_USER_ID'), tags: (optional('AMO_LEAD_TAGS') ?? '') .split(',') .map((t) => t.trim()) .filter(Boolean), } } export const serverConfig = { port: optionalNumber('PORT') ?? 3000, isProduction: process.env.NODE_ENV === 'production', }