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.