const DEFAULT_DASHBOARD_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; const CACHE_TTL_MS = 5 * 60 * 1000; let dashboardCache = { html: '', timestamp: 0, }; function getDashboardUrl() { return process.env.DASHBOARD_TARGET_URL || DEFAULT_DASHBOARD_URL; } function response(statusCode, body, extraHeaders = {}) { return { statusCode, headers: { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'public, max-age=60, stale-while-revalidate=300', ...extraHeaders, }, body, }; } exports.handler = async () => { const now = Date.now(); if (dashboardCache.html && now - dashboardCache.timestamp < CACHE_TTL_MS) { return response(200, dashboardCache.html, { 'X-Cache': 'HIT' }); } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 12000); try { const dashboardResponse = await fetch(getDashboardUrl(), { signal: controller.signal, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36', }, }); if (!dashboardResponse.ok) { throw new Error(`HTTP_ERROR_${dashboardResponse.status}`); } const html = await dashboardResponse.text(); dashboardCache = { html, timestamp: Date.now() }; return response(200, html, { 'X-Cache': 'MISS' }); } catch (error) { if (dashboardCache.html) { return response(200, dashboardCache.html, { 'X-Cache': 'STALE' }); } return { statusCode: 502, headers: { 'Content-Type': 'text/plain; charset=utf-8', }, body: error && error.name === 'AbortError' ? 'DASHBOARD_FETCH_TIMEOUT' : 'DASHBOARD_FETCH_FAILED', }; } finally { clearTimeout(timeoutId); } };