/* ========================= DNS CACHE (mit TTL) ========================= */ // ========================= // DNS CACHE (minimal + robust) // ========================= const DNS_CACHE_TTL = 300000 // 5 min für erfolgreiche Antworten const DNS_ERROR_TTL = 5000 // 5 sek für Fehler const dnsCache = {} const pending = {} function normalizeDomain(domain) { return domain.trim().toLowerCase() } async function getDNS(domain){ if(!domain) return [] const key = normalizeDomain(domain) const now = Date.now() const cached = dnsCache[key] // ✅ gültiger Cache if(cached && (now - cached.time < cached.ttl)){ return cached.ips } // ✅ laufende Anfrage wiederverwenden (dedupe) if(pending[key]){ return pending[key] } pending[key] = (async () => { try{ const res = await api( API + "/dns/" + encodeURIComponent(key), {}, { showError: false } ) const ips = res?.ips || [] dnsCache[key] = { ips, time: Date.now(), ttl: DNS_CACHE_TTL } return ips }catch(e){ // ❗ Fehler nur kurz cachen dnsCache[key] = { ips: [], time: Date.now(), ttl: DNS_ERROR_TTL } return [] }finally{ delete pending[key] } })() return pending[key] } function dnsStatusMarkup(expectedIp, ips){ if(!ips.length){ return ` Kein DNS ` } const matches = expectedIp && ips.includes(expectedIp) const badgeClass = matches ? "ok" : "warn" const label = matches ? "DNS OK" : "DNS Abweichung" return ` ${label} ${ips.join(", ")} ` } function chipMarkup(label, muted = false){ return `` } /* ========================= DOMAINS + SUBDOMAINS ========================= */ window.loadDomains = async function(){ const domains = await api(API + "/domains") const subs = await api(API + "/subdomains") window.domainList = domains const resources = window.resources || [] const table = document.getElementById("domains") table.innerHTML = "" for(const d of domains){ const tr = document.createElement("tr") const domainSubs = subs.filter(s => s.domain_id === d.id) const sublist = domainSubs.length ? `