Source Code
The important bits that make this thing work
Background Monitor
server.js// Background Worker Function async function performCheck() { const now = Date.now(); const timestamp = new Date(now).toISOString(); try { // Accept any response < 500 as "up" since Cloudflare bot detection // may return 403/challenge pages even when the site is operational const response = await axios.get(CHECK_URL, { timeout: 10000, validateStatus: (status) => status < 500 }); currentStatus = { status: 'up', timestamp, lastCheckAt: now }; console.log(`[${timestamp}] Check performed: UP`); } catch (error) { currentStatus = { status: 'down', timestamp, lastCheckAt: now }; console.log(`[${timestamp}] Check performed: DOWN`); } } // Start the background worker performCheck(); checkInterval = setInterval(performCheck, 30000);
The core monitoring logic. Polls downdetector.com every 30 seconds and caches the result. HTTP responses under 500 count as "up" because Cloudflare's bot detection returns 403s even when the site is operational.
Frontend Sync
index.html// Status checking - syncs with server's check time const CHECK_INTERVAL_MS = 30000; let lastServerCheck = null; function updateCountdown() { const countdownEl = document.getElementById('countdown'); if (!lastServerCheck) { countdownEl.textContent = 'Waiting...'; return; } const elapsed = Date.now() - lastServerCheck; const remaining = Math.max(0, Math.ceil( (CHECK_INTERVAL_MS - elapsed) / 1000 )); countdownEl.textContent = remaining === 0 ? 'Now...' : `${remaining}s`; } // Poll server every 5 seconds to stay in sync checkStatus(); setInterval(checkStatus, 5000); setInterval(updateCountdown, 1000);
The frontend polls the API every 5 seconds (lightweight) to get the server's last check timestamp. The countdown timer calculates time remaining based on when the server actually ran its check, keeping client and server in sync.