import { cfg } from "./cfg"; type ServerTapPlayer = { uuid: string; displayName: string; address: string; port: number; exhaustion: number; exp: number; whitelisted: boolean; banned: boolean; op: boolean; }; type ServerTapResponse = { success: boolean; data?: T; error?: string; }; class ServerTapClient { private baseUrl: string; private apiKey: string; constructor() { this.baseUrl = cfg.serverTap.url || ""; this.apiKey = cfg.serverTap.key || ""; } private async makeRequest( endpoint: string, options: RequestInit = {} ): Promise> { if (!this.baseUrl || !this.apiKey) { return { success: false, error: "ServerTap is not configured", }; } try { const url = `${this.baseUrl}${endpoint}`; console.log(`ServerTap API Request: ${options.method || 'GET'} ${url}`); console.log(`Headers:`, { "Content-Type": "application/json", "Accept": "application/json", key: this.apiKey ? "***" : "MISSING", ...options.headers, }); const response = await fetch(url, { headers: { "Content-Type": "application/json", "Accept": "application/json", key: this.apiKey, ...options.headers, }, ...options, }); console.log(`ServerTap API Response: ${response.status} ${response.statusText}`); if (!response.ok) { const errorText = await response.text(); console.error(`ServerTap API Error Response: ${errorText}`); return { success: false, error: `HTTP ${response.status}: ${response.statusText} - ${errorText}`, }; } const data = await response.json(); return { success: true, data, }; } catch (error) { console.error(`ServerTap API Error:`, error); console.error(`Base URL: ${this.baseUrl}`); console.error(`API Key configured: ${!!this.apiKey}`); return { success: false, error: error instanceof Error ? error.message : "Unknown error", }; } } async addToWhitelist(playerName: string, playerUuid?: string, isBedrock?: boolean): Promise> { let uuid = playerUuid; // For Bedrock players, convert XUID to Java UUID format if no UUID provided if (isBedrock && !uuid) { // Remove dot prefix and convert XUID to Java UUID format const xuid = playerName.replace('.', ''); uuid = `00000000-0000-0000-0000-${xuid.padStart(12, '0')}`; } else if (!uuid) { // For Java players without UUID, leave empty as shown in curl example uuid = ''; } const body = new URLSearchParams({ uuid: uuid, name: playerName, }); return this.makeRequest(`/v1/server/whitelist`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: body.toString(), }); } async removeFromWhitelist(playerName: string): Promise> { return this.makeRequest(`/v1/whitelist/remove/${encodeURIComponent(playerName)}`, { method: "POST", }); } async getWhitelist(): Promise> { return this.makeRequest("/v1/whitelist"); } async addOp(playerName: string): Promise> { return this.makeRequest(`/v1/ops/add/${encodeURIComponent(playerName)}`, { method: "POST", }); } async removeOp(playerName: string): Promise> { return this.makeRequest(`/v1/ops/remove/${encodeURIComponent(playerName)}`, { method: "POST", }); } async getOps(): Promise> { return this.makeRequest("/v1/ops"); } async getPlayers(): Promise> { return this.makeRequest("/v1/players"); } async getServerInfo(): Promise> { return this.makeRequest("/v1/server"); } } export const servertap = new ServerTapClient();