Files
firefrost-services/cloudflare-workers/servers-api/index.js
Claude 567164ef7d Add servers-api Cloudflare Worker to version control
- Retrieved from Cloudflare dashboard via MCP connector
- Was 'dashboard only, not in any git repo' - gap now closed
- Original creation: April 3, 2026 by Chronicler #56 (The Velocity)
- Proxies Pterodactyl API for live server status on website

Chronicler #68
2026-04-08 05:44:00 +00:00

104 lines
3.0 KiB
JavaScript

/**
* Firefrost Gaming - Servers API Worker
*
* Cloudflare Worker that proxies Pterodactyl Panel API
* to provide live server status for the website.
*
* Deployed: https://servers-api.firefrostgaming.workers.dev
* Created: April 3, 2026 (Chronicler #56 - The Velocity)
*
* Environment Variables Required:
* PANEL_URL - Pterodactyl panel URL (https://panel.firefrostgaming.com)
* CLIENT_API_KEY - Pterodactyl client API key
*/
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
}
});
}
}
}