Files
dashcaddy/dashcaddy-api/src/config/site.js
T
Hermes 283121edba Merge krystie-improvements into main
Resolves 24 conflicts between Hermes (DC-008/009/010 + response-helper
envelope standardization) and Krystie (DC-005 src/ refactor path fixes,
DC-006 TOTP integration, DC-007 new test suites, cloud backup
destinations).

Conflict resolutions:
- src/utils/logging.js:    took ours (consumers depend on logError/
                            safeErrorMessage/createLogger exports)
- src/config/site.js:      merged (her factored validateAndLogConfig +
                            applyConfigFields helpers)
- src/context/dns.js:      took hers (admin/readonly role iteration for
                            write operations)
- src/utilities/backup-
  manager.js:              took hers (Dropbox/WebDAV/SFTP cloud feature)
- status/dist/*, status/
  sw.js:                   took hers (minified bundles + newer SW cache)

Additional fix (post-merge regression):
- src/monitoring/health-checker.js: fixed DC-005 path miss —
  'require(./platform-paths)' → 'require(../../platform-paths)'

Test status: 921/922 passing. One known failure in logging.test.js
(async file-handle timing) tracked as follow-up.
2026-06-25 16:43:10 -07:00

93 lines
2.9 KiB
JavaScript

/**
* 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('../utilities/config-schema');
const { CADDY } = require('../utilities/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 applyConfigFields(raw) {
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;
}
function validateAndLogConfig(raw, log) {
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);
}
}
}
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) {
validateAndLogConfig(raw, log);
applyConfigFields(raw);
}
} 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
};