export const API_BASE_URL = 'https://minecraft.api.popa-popa.ru'; export interface Player { uuid: string; username: string; skin_url: string; cloak_url: string; coins: number; is_active: boolean; created_at: string; } export interface CoinsResponse { username: string; coins: number; total_time_played: { seconds: number; formatted: string; }; } export interface Cape { cape_id: string; cape_name: string; cape_description: string; image_url: string; purchased_at: string; is_active: boolean; } export type CapesResponse = Cape[]; export interface StoreCape { id: string; name: string; description: string; price: number; image_url: string; } export type StoreCapesResponse = StoreCape[]; export interface ApiError { message: string; details?: string; } export interface Server { id: string; name: string; ip: string; port: number; description: string; online_players: number; max_players: number; last_activity: string; } export interface ActiveServersResponse { servers: Server[]; } export interface OnlinePlayersResponse { server: { id: string; name: string; }; online_players: { // Это массив объектов, а не один объект username: string; uuid: string; online_since: string; }[]; // Добавьте [] здесь чтобы указать, что это массив count: number; } export interface MarketplaceResponse { items: [ { _id: string; id: string; material: string; amount: number; price: number; seller_name: string; server_ip: string; display_name: string | null; lore: string | null; enchants: string | null; item_data: { slot: number; material: string; amount: number; }; created_at: string; }, ]; total: number; page: number; pages: number; } export interface MarketplaceItemResponse { _id: string; id: string; material: string; amount: number; price: number; seller_name: string; server_ip: string; display_name: string | null; lore: string | null; enchants: string | null; item_data: { slot: number; material: string; amount: number; }; created_at: string; } export interface SellItemResponse { message: string; } export interface BuyItemResponse { message: string; } export interface PlayerInventoryResponse { status: string; request_id: string; } export interface PlayerInventory { status: string; result: { player_name: string; server_ip: string; inventory_data: PlayerInventoryItem[]; }; } export interface PlayerInventoryItem { slot: number; material: string; amount: number; enchants: { [key: string]: number; }; } export interface MarketplaceOperation { id: string; type: 'sell' | 'buy'; player_name: string; slot_index?: number; amount?: number; price: number; server_ip: string; status: 'pending' | 'completed' | 'failed'; item_id?: string; error?: string; created_at: string; item_data?: any; } export interface OperationsResponse { operations: MarketplaceOperation[]; } export interface RegisterUserResponse { status: string; uuid: string; } export interface GenerateVerificationCodeResponse { status: string; code: string; } export interface VerificationStatusResponse { is_verified: boolean; } export interface NewsItem { id: string; title: string; markdown: string; preview?: string; tags?: string[]; is_published?: boolean; created_at: string; updated_at: string; } export interface CreateNewsPayload { title: string; preview?: string; markdown: string; is_published: boolean; } export interface MeResponse { username: string; uuid: string; is_admin: boolean; } // ===== КЕЙСЫ ===== export interface CaseItemMeta { display_name?: string | null; lore?: string[] | null; } export interface CaseItem { id: string; name?: string; material: string; amount: number; weight?: number; meta?: CaseItemMeta; } export interface Case { id: string; name: string; description?: string; price: number; image_url?: string; server_ids?: string[]; items_count?: number; items?: CaseItem[]; } export interface OpenCaseResponse { status: string; message: string; operation_id: string; balance: number; reward: CaseItem; } // ===== КЕЙСЫ ===== export async function fetchCases(): Promise { const response = await fetch(`${API_BASE_URL}/cases`); if (!response.ok) { throw new Error('Не удалось получить список кейсов'); } return await response.json(); } // Если у тебя есть отдельный эндпоинт деталей кейса, можно использовать это: export async function fetchCase(case_id: string): Promise { const response = await fetch(`${API_BASE_URL}/cases/${case_id}`); if (!response.ok) { throw new Error('Не удалось получить информацию о кейсе'); } return await response.json(); } export async function openCase( case_id: string, username: string, server_id: string, ): Promise { // Формируем URL с query-параметрами, как любит текущий бэкенд const url = new URL(`${API_BASE_URL}/cases/${case_id}/open`); url.searchParams.append('username', username); url.searchParams.append('server_id', server_id); const response = await fetch(url.toString(), { method: 'POST', }); if (!response.ok) { let msg = 'Не удалось открыть кейс'; try { const errorData = await response.json(); if (errorData.message) { msg = errorData.message; } else if (Array.isArray(errorData.detail)) { msg = errorData.detail.map((d: any) => d.msg).join(', '); } else if (typeof errorData.detail === 'string') { msg = errorData.detail; } } catch { // если бэкенд вернул не-JSON, оставляем дефолтное сообщение } throw new Error(msg); } return await response.json(); } export async function fetchMe(): Promise { const { accessToken, clientToken } = getAuthTokens(); if (!accessToken || !clientToken) { throw new Error('Нет токенов авторизации'); } const params = new URLSearchParams({ accessToken, clientToken, }); const response = await fetch(`${API_BASE_URL}/auth/me?${params.toString()}`); if (!response.ok) { throw new Error('Не удалось получить данные пользователя'); } return await response.json(); } export async function createNews(payload: CreateNewsPayload) { const { accessToken, clientToken } = getAuthTokens(); // ← используем launcher_config if (!accessToken || !clientToken) { throw new Error('Необходимо войти в лаунчер, чтобы публиковать новости'); } const formData = new FormData(); formData.append('accessToken', accessToken); formData.append('clientToken', clientToken); formData.append('title', payload.title); formData.append('markdown', payload.markdown); formData.append('preview', payload.preview || ''); formData.append('is_published', String(payload.is_published)); const response = await fetch(`${API_BASE_URL}/news`, { method: 'POST', body: formData, }); if (!response.ok) { const text = await response.text(); throw new Error(text || 'Ошибка при создании новости'); } return await response.json(); } export async function deleteNews(id: string): Promise { const { accessToken, clientToken } = getAuthTokens(); if (!accessToken || !clientToken) { throw new Error('Необходимо войти в лаунчер'); } const params = new URLSearchParams({ accessToken, clientToken, }); const response = await fetch( `${API_BASE_URL}/news/${id}?${params.toString()}`, { method: 'DELETE', }, ); if (!response.ok) { const text = await response.text(); throw new Error(text || 'Не удалось удалить новость'); } } export async function fetchNews(): Promise { const response = await fetch(`${API_BASE_URL}/news`); if (!response.ok) { throw new Error('Не удалось получить новости'); } return await response.json(); } export async function getVerificationStatus( username: string, ): Promise { const response = await fetch( `${API_BASE_URL}/auth/verification_status/${username}`, ); if (!response.ok) { throw new Error('Не удалось получить статус верификации'); } return await response.json(); } export async function generateVerificationCode( username: string, ): Promise { const response = await fetch( `${API_BASE_URL}/auth/generate_code?username=${username}`, { method: 'POST', }, ); if (!response.ok) { throw new Error('Не удалось сгенерировать код верификации'); } return await response.json(); } export async function registerUser( username: string, password: string, ): Promise { const response = await fetch(`${API_BASE_URL}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, password, }), }); if (!response.ok) { throw new Error('Не удалось зарегистрировать пользователя'); } return await response.json(); } export async function getPlayerInventory( request_id: string, ): Promise { const response = await fetch( `${API_BASE_URL}/api/server/inventory/${request_id}`, ); if (!response.ok) { throw new Error('Не удалось получить инвентарь игрока'); } return await response.json(); } export async function RequestPlayerInventory( server_ip: string, player_name: string, ): Promise { const response = await fetch(`${API_BASE_URL}/api/server/inventory`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ server_ip: server_ip, player_name: player_name, }), }); if (!response.ok) { throw new Error('Не удалось получить инвентарь игрока'); } return await response.json(); } export async function buyItem( buyer_username: string, item_id: string, ): Promise<{ status: string; operation_id: string; message: string }> { const response = await fetch( `${API_BASE_URL}/api/marketplace/items/buy/${item_id}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: buyer_username, }), }, ); if (!response.ok) { const errorData = await response.json(); throw new Error( errorData.message || errorData.detail || 'Не удалось купить предмет', ); } return await response.json(); } export async function confirmMarketplaceOperation( operation_id: string, status: string = 'success', error?: string, ): Promise<{ status: string }> { const response = await fetch( `${API_BASE_URL}/api/marketplace/operations/confirm`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ operation_id, status, error, }), }, ); if (!response.ok) { throw new Error('Не удалось подтвердить операцию'); } return await response.json(); } export async function submitItemDetails( operation_id: string, item_data: any, ): Promise<{ status: string }> { const response = await fetch( `${API_BASE_URL}/api/marketplace/items/details`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ operation_id, item_data, }), }, ); if (!response.ok) { throw new Error('Не удалось отправить данные предмета'); } return await response.json(); } export async function sellItem( username: string, slot_index: number, amount: number, price: number, server_ip: string, ): Promise<{ status: string; operation_id: string }> { const response = await fetch(`${API_BASE_URL}/api/marketplace/items/sell`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, slot_index, amount, price, server_ip, }), }); if (!response.ok) { const errorData = await response.json(); throw new Error( errorData.message || errorData.detail || 'Не удалось выставить предмет на продажу', ); } return await response.json(); } export async function fetchMarketplaceItem( item_id: string, ): Promise { const response = await fetch( `${API_BASE_URL}/api/marketplace/items/${item_id}`, ); if (!response.ok) { throw new Error('Не удалось получить рынок'); } return await response.json(); } export async function fetchMarketplace( server_ip: string, page: number, limit: number, ): Promise { // Создаем URL с параметрами запроса const url = new URL(`${API_BASE_URL}/api/marketplace/items`); url.searchParams.append('server_ip', server_ip); url.searchParams.append('page', page.toString()); url.searchParams.append('limit', limit.toString()); const response = await fetch(url.toString()); if (!response.ok) { throw new Error('Не удалось получить предметы рынка'); } return await response.json(); } // Исправьте тип возвращаемого значения export async function fetchActiveServers(): Promise { const response = await fetch(`${API_BASE_URL}/api/pranks/servers`); if (!response.ok) { throw new Error('Не удалось получить активные сервера'); } return await response.json(); } export async function fetchOnlinePlayers( server_id: string, ): Promise { const response = await fetch( `${API_BASE_URL}/api/pranks/servers/${server_id}/players`, ); if (!response.ok) { throw new Error('Не удалось получить онлайн игроков'); } return await response.json(); } // Получение информации о игроке export async function fetchPlayer(uuid: string): Promise { try { const response = await fetch(`${API_BASE_URL}/users/${uuid}`); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Ошибка получения данных игрока'); } return await response.json(); } catch (error) { console.error('API ошибка:', error); throw error; } } export async function fetchCoins(username: string): Promise { try { const response = await fetch(`${API_BASE_URL}/users/${username}/coins`); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Ошибка получения данных игрока'); } return await response.json(); } catch (error) { console.error('API ошибка:', error); throw error; } } export async function fetchCapes(username: string): Promise { try { const response = await fetch( `${API_BASE_URL}/store/user/${username}/capes`, ); if (!response.ok) { return []; // Если плащи не найдены, возвращаем пустой массив } return await response.json(); } catch (error) { console.error('API ошибка:', error); return []; // В случае ошибки возвращаем пустой массив } } export async function purchaseCape( username: string, cape_id: string, ): Promise { // Создаем URL с query-параметрами const url = new URL(`${API_BASE_URL}/store/purchase/cape`); url.searchParams.append('username', username); url.searchParams.append('cape_id', cape_id); const response = await fetch(url.toString(), { method: 'POST', headers: { 'Content-Type': 'application/json', }, // Не нужно отправлять тело запроса // body: JSON.stringify({ // username: username, // cape_id: cape_id, // }), }); if (!response.ok) { const errorData = await response.json(); throw new Error( errorData.message || errorData.detail?.toString() || 'Не удалось купить плащ', ); } } export async function fetchCapesStore(): Promise { try { const response = await fetch(`${API_BASE_URL}/store/capes`); if (!response.ok) { return []; } return await response.json(); } catch (error) { console.error('API ошибка:', error); return []; } } export async function activateCape( username: string, cape_id: string, ): Promise { const response = await fetch( `${API_BASE_URL}/store/user/${username}/capes/activate/${cape_id}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ cape_id: cape_id, }), }, ); if (!response.ok) { throw new Error('Не удалось активировать плащ'); } } export async function deactivateCape( username: string, cape_id: string, ): Promise { const response = await fetch( `${API_BASE_URL}/store/user/${username}/capes/deactivate/${cape_id}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ cape_id: cape_id, }), }, ); if (!response.ok) { throw new Error('Не удалось деактивировать плащ'); } } // Загрузка скина export async function uploadSkin( username: string, skinFile: File, skinModel: string, ): Promise { const savedConfig = localStorage.getItem('launcher_config'); let accessToken = ''; let clientToken = ''; if (savedConfig) { const config = JSON.parse(savedConfig); accessToken = config.accessToken || ''; clientToken = config.clientToken || ''; } const formData = new FormData(); formData.append('skin_file', skinFile); formData.append('skin_model', skinModel); formData.append('accessToken', accessToken); formData.append('clientToken', clientToken); const response = await fetch(`${API_BASE_URL}/user/${username}/skin`, { method: 'POST', body: formData, }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Не удалось загрузить скин'); } } // Получение токенов из локального хранилища export function getAuthTokens(): { accessToken: string; clientToken: string } { const savedConfig = localStorage.getItem('launcher_config'); let accessToken = ''; let clientToken = ''; if (savedConfig) { const config = JSON.parse(savedConfig); accessToken = config.accessToken || ''; clientToken = config.clientToken || ''; } return { accessToken, clientToken }; } // Загрузка плаща export async function uploadCape( username: string, capeFile: File, ): Promise { const { accessToken, clientToken } = getAuthTokens(); const formData = new FormData(); formData.append('cape_file', capeFile); formData.append('accessToken', accessToken); formData.append('clientToken', clientToken); const response = await fetch(`${API_BASE_URL}/user/${username}/cape`, { method: 'POST', body: formData, }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Не удалось загрузить плащ'); } }