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
This commit is contained in:
Claude
2026-04-08 05:44:00 +00:00
parent e59ee04b03
commit 567164ef7d
2 changed files with 181 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
# Servers API - Cloudflare Worker
**Purpose:** Proxies Pterodactyl Panel API to provide live server status for firefrostgaming.com
**Deployed URL:** https://servers-api.firefrostgaming.workers.dev
**Created:** April 3, 2026 by Chronicler #56 (The Velocity)
**Retrieved from Cloudflare:** April 8, 2026 by Chronicler #68
---
## What It Does
1. Receives request from website (firefrostgaming.com or pages.dev preview)
2. Fetches server list from Pterodactyl Panel API
3. Fetches live resource stats for each server
4. Returns JSON with server name, status (Online/Offline), player count, description
5. Caches response for 60 seconds
---
## Environment Variables
Configure these in Cloudflare Workers dashboard:
| Variable | Description |
|----------|-------------|
| `PANEL_URL` | Pterodactyl panel URL (https://panel.firefrostgaming.com) |
| `CLIENT_API_KEY` | Pterodactyl client API key for webuser_api account |
---
## CORS Configuration
Allowed origins:
- `https://firefrostgaming.com`
- `https://firefrost-website.pages.dev`
---
## Response Format
```json
{
"servers": [
{
"id": "abc123",
"name": "All The Mods 10",
"status": "Online",
"players": 3,
"description": "ATM10 modpack server"
}
]
}
```
---
## Deployment
This Worker is deployed via Cloudflare dashboard. To update:
1. Edit code in Cloudflare Workers dashboard, OR
2. Use Wrangler CLI: `wrangler deploy`
**Note:** This file is the source of truth. If editing in dashboard, sync changes back here.
---
## History
| Date | Change | By |
|------|--------|-----|
| 2026-04-03 | Initial creation | Chronicler #56 (The Velocity) |
| 2026-04-08 | Added to git (was dashboard-only) | Chronicler #68 |
---
**Fire + Frost + Foundation = Where Love Builds Legacy** 💙🔥❄️

View File

@@ -0,0 +1,103 @@
/**
* 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
}
});
}
}
}