/** * Site configuration management * Loads and validates site-wide settings from config.json */ const fs = require('fs'); const { validateConfig } = require('../../config-schema'); const { CADDY } = require('../../constants'); /** * Site configuration state * Modified by loadSiteConfig() */ const siteConfig = { tld: '.home', caName: '', dnsServerIp: '', dnsServerPort: CADDY.DEFAULT_DNS_PORT, dashboardHost: '', timezone: 'UTC', dnsServers: {}, configurationType: 'homelab', domain: '', routingMode: 'subdomain', }; /** * Load site configuration from config.json * @param {string} configFilePath - Path to config.json * @param {object} log - Logger instance (optional, may not be available at startup) */ function loadSiteConfig(configFilePath, log) { try { if (fs.existsSync(configFilePath)) { const raw = JSON.parse(fs.readFileSync(configFilePath, 'utf8')); // 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); } } // Apply config values 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'; } } catch (e) { if (log && log.error) { log.error('config', 'Failed to load site config', { error: e.message }); } else { console.error('[ERROR] Failed to load site config:', e.message); } } } /** * Build a domain from subdomain + configured TLD or public domain * @param {string} subdomain - Service subdomain (e.g., 'sonarr') * @returns {string} Full domain (e.g., 'sonarr.home' or 'sonarr.example.com') */ function buildDomain(subdomain) { if (siteConfig.configurationType === 'public' && siteConfig.domain) { return `${subdomain}.${siteConfig.domain}`; } return `${subdomain}${siteConfig.tld}`; } /** * Build full service URL (protocol + host + path) for a given subdomain * Subdirectory mode: https://example.com/sonarr * Subdomain mode: https://sonarr.example.com * @param {string} subdomain - Service subdomain * @returns {string} Full service URL */ function buildServiceUrl(subdomain) { if (siteConfig.routingMode === 'subdirectory' && siteConfig.domain) { return `https://${siteConfig.domain}/${subdomain}`; } return `https://${buildDomain(subdomain)}`; } module.exports = { siteConfig, loadSiteConfig, buildDomain, buildServiceUrl, };