const DEFAULT_KEY_CACHE = { ttlMs: 30 * 60 * 1000, max: 10_000 }; const config = { debug: false, dashboard: { core: {}, audit: {}, keyCache: { ...DEFAULT_KEY_CACHE } }, }; export async function loadConfig() { if (process.env.DEBUG) config.debug = process.env.DEBUG; if (process.env.POSTGRES_URL) config.postgresUrl = process.env.POSTGRES_URL; if (process.env.PUBLIC_CORE_URL) config.publicCoreUrl = process.env.PUBLIC_CORE_URL; if (process.env.PUBLIC_ARCHIVE_URL) config.publicArchiveUrl = process.env.PUBLIC_ARCHIVE_URL; if (process.env.PUBLIC_CALLBACK_URL) config.publicCallbackUrl = process.env.PUBLIC_CALLBACK_URL; if (process.env.SECURE_SECRET) config.secureSecret = process.env.SECURE_SECRET; if (process.env.DEFAULT_FEDID_URL) config.defaultFedidUrl = process.env.DEFAULT_FEDID_URL; if (process.env.AUTH_MODULES) { config.authModules = {}; const authModules = process.env.AUTH_MODULES.split(',').map(a => a.trim()); for (const type of authModules) { const authModulePath = `../modules/auth/${type}.js`; const { getModuleConfig } = await import(authModulePath); config.authModules[type] = getModuleConfig(); } } config.appModules = {}; let appModules = [ 'core', 'archive', ]; if (process.env.APP_MODULES) { appModules = process.env.APP_MODULES.split(',').map(a => a.trim()); } for (const type of appModules) { const appModulePath = `../modules/app/${type}.js`; const { getModuleConfig } = await import(appModulePath); config.appModules[type] = getModuleConfig(); } if (process.env.PDP_TYPE) config.pdpType = process.env.PDP_TYPE; if (process.env.PDP_URL) config.pdpUrl = process.env.PDP_URL; if (process.env.INSTANT_QUEUE) config.instantQueue = process.env.INSTANT_QUEUE; // Remote agreement-markdown caching: exponential backoff for failed fetches // so an invalid URL isn't retried on every referencing create. Defaults: // 1 minute → 1 day, factor 2, give up after 10 attempts. All overridable. config.agreementCache = { startingDelayMs: Number(process.env.AGREEMENT_CACHE_STARTING_DELAY_MS) || 60_000, maxDelayMs: Number(process.env.AGREEMENT_CACHE_MAX_DELAY_MS) || 86_400_000, maxRetries: Number(process.env.AGREEMENT_CACHE_MAX_RETRIES) || 10, factor: Number(process.env.AGREEMENT_CACHE_BACKOFF_FACTOR) || 2, }; // Optional federation: source dashboard core/audit data from remote servers // (via their /api/v1/data/dashboard/* API + an API key) instead of locally. // Unset => serve from the local DB (the single-operator default). const keyCacheTtl = Number(process.env.DASHBOARD_KEY_CACHE_TTL_MS); const keyCacheMax = Number(process.env.DASHBOARD_KEY_CACHE_MAX); config.dashboard = { core: { url: process.env.DASHBOARD_CORE_URL || null, key: process.env.DASHBOARD_CORE_KEY || null }, audit: { url: process.env.DASHBOARD_AUDIT_URL || null, key: process.env.DASHBOARD_AUDIT_KEY || null }, keyCache: { ttlMs: Number.isFinite(keyCacheTtl) ? keyCacheTtl : DEFAULT_KEY_CACHE.ttlMs, max: Number.isFinite(keyCacheMax) && keyCacheMax > 0 ? keyCacheMax : DEFAULT_KEY_CACHE.max, }, }; } export function getConfig() { return config; }