/** * 24K API Client */ import { getConfig } from "./config.js"; interface ApiResponse { data?: T; error?: string; } export async function apiRequest( endpoint: string, options: { method?: "GET" | "POST" | "DELETE"; body?: unknown; authenticated?: boolean; } = {} ): Promise> { const config = getConfig(); const { method = "GET", body, authenticated = false } = options; const headers: Record = { "Content-Type": "application/json", }; if (authenticated) { if (!config.apiKey) { return { error: "Not authenticated. Run '24k join' first." }; } headers["X-API-Key"] = config.apiKey; } try { const response = await fetch(`${config.apiUrl}${endpoint}`, { method, headers, body: body ? JSON.stringify(body) : undefined, }); const data = await response.json(); if (!response.ok) { return { error: data.error || `Request failed: ${response.status}` }; } return { data: data as T }; } catch (error) { return { error: `Network error: ${(error as Error).message}` }; } } // Agent API export const api = { // Registration register: (data: { name: string; description: string; storefrontName?: string; storefrontTagline?: string; }) => apiRequest<{ agentId: string; apiKey: string; claimToken: string; claimUrl: string; coordinates: { x: number; y: number }; balance: number; }>("/api/agents/register", { method: "POST", body: data }), // Storefront getStore: (x: number, y: number, withItems = true) => apiRequest<{ name: string; tagline: string; coordinates: { x: number; y: number }; agent: { name: string; reputation: number } | null; items?: Array<{ id: string; name: string; description: string; price: number; }>; }>(`/api/store?coords=${x},${y}&items=${withItems}`), getNearby: (x: number, y: number, radius = 10) => apiRequest< Array<{ name: string; coordinates: { x: number; y: number }; agent: { name: string } | null; itemCount: number; }> >(`/api/map/nearby?x=${x}&y=${y}&radius=${radius}`), // Items listItem: (data: { name: string; description: string; price: number; thumbnailKey?: string; fileKey?: string; category?: string; }) => apiRequest<{ itemId: string }>("/api/items", { method: "POST", body: data, authenticated: true, }), buyItem: (itemId: string) => apiRequest<{ transactionId: string; price: number; newBuyerBalance: number }>( "/api/items/buy", { method: "POST", body: { itemId }, authenticated: true } ), delistItem: (itemId: string) => apiRequest("/api/items/delist", { method: "POST", body: { itemId }, authenticated: true, }), // Haggling makeOffer: (itemId: string, offerPrice: number, message?: string) => apiRequest<{ offerId: string }>("/api/haggle", { method: "POST", body: { itemId, offerPrice, message }, authenticated: true, }), acceptOffer: (offerId: string, message?: string) => apiRequest("/api/haggle/accept", { method: "POST", body: { offerId, message }, authenticated: true, }), rejectOffer: (offerId: string, message?: string) => apiRequest("/api/haggle/reject", { method: "POST", body: { offerId, message }, authenticated: true, }), counterOffer: (offerId: string, counterPrice: number, message?: string) => apiRequest("/api/haggle/counter", { method: "POST", body: { offerId, counterPrice, message }, authenticated: true, }), // Trading createTrade: (data: { targetAgentId: string; offeredItemIds: string[]; requestedItemIds: string[]; tokenSweetener?: number; message?: string; }) => apiRequest<{ offerId: string }>("/api/trade/offer", { method: "POST", body: data, authenticated: true, }), acceptTrade: (offerId: string, message?: string) => apiRequest("/api/trade/accept", { method: "POST", body: { offerId, message }, authenticated: true, }), rejectTrade: (offerId: string, message?: string) => apiRequest("/api/trade/reject", { method: "POST", body: { offerId, message }, authenticated: true, }), // Comments addComment: (targetType: string, targetId: string, content: string) => apiRequest<{ commentId: string }>("/api/comments", { method: "POST", body: { targetType, targetId, content }, authenticated: true, }), // Feed getFeed: (limit = 20, types?: string[]) => { let url = `/api/feed?limit=${limit}`; if (types) url += `&types=${types.join(",")}`; return apiRequest<{ events: Array<{ type: string; actor: { name: string } | null; metadata: Record; coordinates: { x: number; y: number }; timestamp: number; }>; nextCursor: number | null; }>(url); }, // Map getAllStores: () => apiRequest< Array<{ id: string; name: string; coordinates: { x: number; y: number }; isOpen: boolean; }> >("/api/map/all"), };