bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
113 lines (112 loc) • 4.95 kB
JavaScript
// useApiClient Hook - Type-safe API client using bmap-api-types
import { ApiError as BaseApiError } from "../../../lib/api-error.js";
// Re-export ApiError for backward compatibility
export { ApiError } from "../../../lib/api-error.js";
import { Timeframe, } from "bmap-api-types";
import { BMAP_API_URL } from "../constants.js";
// Generic API fetcher with proper error handling
async function fetchApi(endpoint, options) {
const response = await fetch(`${BMAP_API_URL}${endpoint}`, {
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
});
const data = await response.json();
// Check if it's an API wrapper response
if ("status" in data) {
const apiResponse = data;
if (apiResponse.status === "error") {
const errorResponse = apiResponse;
const message = errorResponse.error || "API request failed";
throw new BaseApiError("NETWORK_ERROR", message, errorResponse);
}
// Extract data from success response
return apiResponse.data;
}
// If not wrapped, check if it's an error
if (!response.ok) {
throw new BaseApiError("NETWORK_ERROR", response.statusText, {
status: response.status,
statusText: response.statusText,
});
}
return data;
}
// Type-safe API client
export const apiClient = {
// Posts endpoints
posts: {
search: (params) => fetchApi(`/social/post/search?q=${encodeURIComponent(params.q)}&limit=${params.limit}&offset=${params.offset}`),
byBapId: (params) => fetchApi(`/social/post/bap/${params.bapId}?page=${params.page}&limit=${params.limit}`),
byAddress: (params) => fetchApi(`/social/post/address/${params.address}?page=${params.page}&limit=${params.limit}`),
single: (txid) => fetchApi(`/social/post/${txid}`),
replies: (txid, page = 1, limit = 20) => fetchApi(`/social/post/${txid}/reply?page=${page}&limit=${limit}`),
trending: (timeframe = Timeframe.Day, limit = 20) => fetchApi(`/social/post/trending?timeframe=${timeframe}&limit=${limit}`),
},
// Generic transaction fetcher for any transaction type
transactions: {
single: (txid) => fetchApi(`/tx/${txid}`),
// Specific transaction type fetchers
follow: (txid) => fetchApi(`/social/follow/${txid}`),
unfollow: (txid) => fetchApi(`/social/unfollow/${txid}`),
},
// Messages endpoints
messages: {
direct: (params) => fetchApi(`/social/@/${params.bapId}/messages?page=${params.page}&limit=${params.limit}${params.targetBapId ? `&targetBapId=${params.targetBapId}` : ""}`),
channel: (channelId, page = 1, limit = 20) => fetchApi(`/social/channels/${channelId}/messages?page=${page}&limit=${limit}`),
},
// Likes endpoints
likes: {
forPost: (txid) => fetchApi(`/social/post/${txid}/like`),
byUser: (bapId, page = 1, limit = 20) => fetchApi(`/social/bap/${bapId}/like?page=${page}&limit=${limit}`),
},
// Identity endpoints
identity: {
search: (query, limit = 10) => fetchApi(`/social/identity/search?q=${encodeURIComponent(query)}&limit=${limit}`),
byBapId: (bapId) => fetchApi(`/social/identity/${bapId}`),
},
// Channels
channels: {
list: () => fetchApi("/social/channels"),
single: (channelId) => fetchApi(`/social/channel/${channelId}`),
},
// Friends
friends: {
byBapId: (bapId) => fetchApi(`/social/friend/${bapId}`),
// Friend request management (uses different base URL)
accept: async (bapId) => {
const response = await fetch(`${BMAP_API_URL}/social/friend/accept`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ bapId }),
});
if (!response.ok) {
throw new BaseApiError("NETWORK_ERROR", `Failed to accept friend request: ${response.statusText}`, {
status: response.status,
statusText: response.statusText,
});
}
return response.json();
},
reject: async (bapId) => {
const response = await fetch(`${BMAP_API_URL}/social/friend/reject`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ bapId }),
});
if (!response.ok) {
throw new BaseApiError("NETWORK_ERROR", `Failed to reject friend request: ${response.statusText}`, {
status: response.status,
statusText: response.statusText,
});
}
return response.json();
},
},
};
// Hook for easy access to the API client
export function useApiClient() {
return apiClient;
}