/** * Site configuration loader * Loads and manages site-wide settings from config.json * * Includes automatic migration from older config versions (see migrations.js). * Users never see the migration — it runs silently on startup, writes the * updated config back, and the rest of the app only ever sees the current * schema. */ const { validateConfig } = require('../../config-schema'); const { CADDY } = require('../../constants'); const { loadAndMigrate, CURRENT_VERSION } = require('./migrations'); const siteConfig = { tld: '.home', caName: '', dnsServerIp: '', dnsServerPort: CADDY.DEFAULT_DNS_PORT, dashboardHost: '', timezone: 'UTC', dnsServers: {}, configurationType: 'homelab', domain: '', routingMode: 'subdomain' }; function loadSiteConfig(CONFIG_FILE, log) { try { // Run migrations first — this handles config.json files from older // versions of DashCaddy and writes the migrated version back to disk. const raw = loadAndMigrate(CONFIG_FILE, log); if (raw && Object.keys(raw).length > 0) { // Validate config and log any issues const { valid, errors: configErrors, warnings: configWarnings } = validateConfig(raw); if (log && log.warn) { if (!valid) { log.warn('config', 'Config validation errors', { errors: configErrors }); } for (const w of configWarnings) { log.warn('config', w); } } siteConfig.tld = raw.tld || '.home'; if (!siteConfig.tld.startsWith('.')) siteConfig.tld = '.' + siteConfig.tld; siteConfig.caName = raw.caName || ''; siteConfig.dnsServerIp = (raw.dns && raw.dns.ip) || ''; siteConfig.dnsServerPort = (raw.dns && raw.dns.port) || CADDY.DEFAULT_DNS_PORT; siteConfig.dashboardHost = raw.dashboardHost || `status${siteConfig.tld}`; siteConfig.timezone = raw.timezone || 'UTC'; siteConfig.dnsServers = raw.dnsServers || {}; siteConfig.configurationType = raw.configurationType || 'homelab'; siteConfig.domain = raw.domain || ''; siteConfig.routingMode = raw.routingMode || 'subdomain'; siteConfig.pylon = raw.pylon || null; } } catch (e) { if (log && log.error) { log.error('config', 'Failed to load site config', { error: e.message }); } } } /** Build a domain from subdomain + configured TLD or public domain */ function buildDomain(subdomain) { if (siteConfig.configurationType === 'public' && siteConfig.domain) { return `${subdomain}.${siteConfig.domain}`; } return `${subdomain}${siteConfig.tld}`; } /** Build full service URL (protocol + host + path) */ function buildServiceUrl(subdomain) { if (siteConfig.routingMode === 'subdirectory' && siteConfig.domain) { return `https://${siteConfig.domain}/${subdomain}`; } return `https://${buildDomain(subdomain)}`; } module.exports = { siteConfig, loadSiteConfig, buildDomain, buildServiceUrl, CURRENT_VERSION };