import { config } from "./config.js"; import { ensureSetting, generateSecret, listSettings, removeSetting, setSetting, SettingKey, StoredSettings } from "./settingsStore.js"; export interface RuntimeSettings { paperlessBaseUrl: string | null; paperlessExternalUrl: string | null; appExternalUrl: string | null; appLocale: string; paperlessToken: string | null; schedulerIntervalMinutes: number; alertDaysBefore: number; mailServer: string | null; mailPort: number | null; mailUsername: string | null; mailPassword: string | null; mailUseTls: boolean; mailFrom: string | null; mailTo: string | null; ntfyServerUrl: string | null; ntfyTopic: string | null; ntfyToken: string | null; ntfyPriority: string | null; authUsername: string | null; authPassword: string | null; icalSecret: string | null; } const numericKeys = new Set(["schedulerIntervalMinutes", "alertDaysBefore", "mailPort"]); const booleanKeys = new Set(["mailUseTls"]); function coerceNumber(value: unknown, fallback: number): number { if (typeof value === "number" && Number.isFinite(value)) { return value; } if (typeof value === "string" && value.trim() !== "") { const parsed = Number(value); if (!Number.isNaN(parsed)) { return parsed; } } return fallback; } function coerceBoolean(value: unknown, fallback: boolean): boolean { if (typeof value === "boolean") { return value; } if (typeof value === "string") { return ["1", "true", "yes", "on"].includes(value.toLowerCase()); } return fallback; } function coerceString(value: unknown, fallback: string | null): string | null { if (typeof value === "string") { const trimmed = value.trim(); return trimmed.length === 0 ? null : trimmed; } return fallback; } function normalizeLocale(value: unknown, fallback: string): string { if (typeof value === "string") { const lower = value.toLowerCase(); if (lower.startsWith("de")) { return "de"; } if (lower.startsWith("en")) { return "en"; } } return fallback; } export function getRuntimeSettings(): RuntimeSettings { const stored = listSettings(); const schedulerIntervalMinutes = coerceNumber( stored.schedulerIntervalMinutes, config.schedulerIntervalMinutes ); const alertDaysBefore = coerceNumber(stored.alertDaysBefore, config.alertDaysBefore); const mailPort = stored.mailPort !== undefined ? coerceNumber(stored.mailPort, config.mailPort) : config.mailPort; return { paperlessBaseUrl: coerceString(stored.paperlessBaseUrl, config.paperlessBaseUrl ?? null), paperlessExternalUrl: coerceString(stored.paperlessExternalUrl, config.paperlessExternalUrl ?? null), appExternalUrl: coerceString(stored.appExternalUrl, config.appExternalUrl ?? null), appLocale: normalizeLocale(stored.appLocale, config.appLocale), paperlessToken: coerceString(stored.paperlessToken, config.paperlessToken ?? null), schedulerIntervalMinutes, alertDaysBefore, mailServer: coerceString(stored.mailServer, config.mailServer ?? null), mailPort, mailUsername: coerceString(stored.mailUsername, config.mailUsername ?? null), mailPassword: coerceString(stored.mailPassword, config.mailPassword ?? null), mailUseTls: stored.mailUseTls !== undefined ? coerceBoolean(stored.mailUseTls, config.mailUseTls) : config.mailUseTls, mailFrom: coerceString(stored.mailFrom, config.mailFrom ?? null), mailTo: coerceString(stored.mailTo, config.mailTo ?? null), ntfyServerUrl: coerceString(stored.ntfyServerUrl, config.ntfyServerUrl ?? null), ntfyTopic: coerceString(stored.ntfyTopic, config.ntfyTopic ?? null), ntfyToken: coerceString(stored.ntfyToken, config.ntfyToken ?? null), ntfyPriority: coerceString(stored.ntfyPriority, config.ntfyPriority ?? null), authUsername: coerceString(stored.authUsername, config.authUsername ?? null), authPassword: coerceString(stored.authPassword, config.authPassword ?? null), icalSecret: coerceString(stored.icalSecret, config.icalSecret ?? null) }; } export function updateRuntimeSettings(update: Partial): RuntimeSettings { const keys = Object.keys(update) as SettingKey[]; for (const key of keys) { let value = update[key as keyof RuntimeSettings]; if (value === undefined || value === null || value === "") { removeSetting(key); continue; } if (key === "appLocale") { value = normalizeLocale(value, config.appLocale); } if (numericKeys.has(key)) { const numericValue = coerceNumber(value, 0); setSetting(key, numericValue); } else if (booleanKeys.has(key)) { const boolValue = coerceBoolean(value, false); setSetting(key, boolValue); } else { setSetting(key, value); } } return getRuntimeSettings(); } export function ensureIcalSecret(): string { const value = ensureSetting("icalSecret", () => generateSecret(24)); return String(value); } export function regenerateIcalSecret(): string { const secret = generateSecret(24); setSetting("icalSecret", secret); return secret; } export function getStoredSettings(): StoredSettings { return listSettings(); }