/** * servers-api — Cloudflare Worker * * Proxies Pterodactyl client API for the firefrostgaming.com website. * Returns live server status + player counts. * * Deployed: April 3, 2026 * Location: Cloudflare Workers (servers-api) * Env vars: PANEL_URL, CLIENT_API_KEY * CORS: firefrostgaming.com, firefrost-website.pages.dev * Cache: 60 seconds * * NOT in any git repo until now — recovered by Chronicler #78 via Cloudflare MCP. */ export default { async fetch(request, env) { // Determine allowed origin const origin = request.headers.get('Origin'); const allowedOrigins = [ 'https://firefrostgaming.com', 'https://firefrost-website.pages.dev' ]; const allowedOrigin = allowedOrigins.includes(origin) ? origin : 'https://firefrostgaming.com'; // Handle CORS preflight if (request.method === 'OPTIONS') { return new Response(null, { headers: { 'Access-Control-Allow-Origin': allowedOrigin, 'Access-Control-Allow-Methods': 'GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' } }); } const PANEL_URL = env.PANEL_URL; const API_KEY = env.CLIENT_API_KEY; try { // Fetch server list const listResponse = await fetch(`${PANEL_URL}/api/client`, { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Accept': 'application/json' } }); const listData = await listResponse.json(); if (!listData.data) throw new Error("Failed to fetch server list"); // Fetch live stats for all servers const serverPromises = listData.data.map(async (server) => { const id = server.attributes.identifier; const statsResponse = await fetch(`${PANEL_URL}/api/client/servers/${id}/resources`, { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Accept': 'application/json' } }); const stats = await statsResponse.json(); const isRunning = stats.attributes?.current_state === 'running'; return { id: id, name: server.attributes.name, status: isRunning ? 'Online' : 'Offline', players: isRunning ? (stats.attributes?.resources?.players || 0) : 0, description: server.attributes.description }; }); const finalServers = await Promise.all(serverPromises); return new Response(JSON.stringify({ servers: finalServers }), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': allowedOrigin, 'Cache-Control': 'public, s-maxage=60, max-age=60' } }); } catch (error) { return new Response(JSON.stringify({ error: "Servers temporarily unreachable", servers: [] }), { status: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': allowedOrigin } }); } } }