UNPKG

bigblocks

Version:

Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React

15 lines 6.37 kB
{ "name": "social-hooks-useapiclient", "type": "registry:hook", "dependencies": [], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "components/social/hooks/useApiClient.ts", "type": "registry:hook", "content": "// useApiClient Hook - Type-safe API client using bmap-api-types\nimport { ApiError as BaseApiError } from \"../../../lib/api-error.js\";\n\n// Re-export ApiError for backward compatibility\nexport { ApiError } from \"../../../lib/api-error.js\";\nimport {\n\ttype ApiErrorResponse,\n\ttype ApiResponse,\n\ttype ApiSuccessResponse,\n\ttype BaseTransaction,\n\ttype ChannelInfo,\n\ttype DirectMessageParams,\n\ttype FollowTransaction,\n\ttype LikeInfo,\n\ttype LikesResponse,\n\ttype MessagesResponse,\n\ttype PostResponse,\n\ttype PostsParams,\n\ttype PostsResponse,\n\ttype SearchParams,\n\tTimeframe,\n\ttype UnfollowTransaction,\n} from \"bmap-api-types\";\nimport { BMAP_API_URL } from \"../constants.js\";\n\n// Generic API fetcher with proper error handling\nasync function fetchApi<T>(\n\tendpoint: string,\n\toptions?: RequestInit,\n): Promise<T> {\n\tconst response = await fetch(`${BMAP_API_URL}${endpoint}`, {\n\t\t...options,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...options?.headers,\n\t\t},\n\t});\n\n\tconst data = await response.json();\n\n\t// Check if it's an API wrapper response\n\tif (\"status\" in data) {\n\t\tconst apiResponse = data as ApiResponse<T>;\n\n\t\tif (apiResponse.status === \"error\") {\n\t\t\tconst errorResponse = apiResponse as ApiErrorResponse;\n\t\t\tconst message = errorResponse.error || \"API request failed\";\n\t\t\tthrow new BaseApiError(\"NETWORK_ERROR\", message, errorResponse);\n\t\t}\n\n\t\t// Extract data from success response\n\t\treturn (apiResponse as ApiSuccessResponse<T>).data;\n\t}\n\n\t// If not wrapped, check if it's an error\n\tif (!response.ok) {\n\t\tthrow new BaseApiError(\"NETWORK_ERROR\", response.statusText, {\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t});\n\t}\n\n\treturn data as T;\n}\n\n// Type-safe API client\nexport const apiClient = {\n\t// Posts endpoints\n\tposts: {\n\t\tsearch: (params: SearchParams) =>\n\t\t\tfetchApi<PostsResponse>(\n\t\t\t\t`/social/post/search?q=${encodeURIComponent(params.q)}&limit=${params.limit}&offset=${params.offset}`,\n\t\t\t),\n\n\t\tbyBapId: (params: PostsParams & { bapId: string }) =>\n\t\t\tfetchApi<PostsResponse>(\n\t\t\t\t`/social/post/bap/${params.bapId}?page=${params.page}&limit=${params.limit}`,\n\t\t\t),\n\n\t\tbyAddress: (params: PostsParams & { address: string }) =>\n\t\t\tfetchApi<PostsResponse>(\n\t\t\t\t`/social/post/address/${params.address}?page=${params.page}&limit=${params.limit}`,\n\t\t\t),\n\n\t\tsingle: (txid: string) => fetchApi<PostResponse>(`/social/post/${txid}`),\n\n\t\treplies: (txid: string, page = 1, limit = 20) =>\n\t\t\tfetchApi<PostsResponse>(\n\t\t\t\t`/social/post/${txid}/reply?page=${page}&limit=${limit}`,\n\t\t\t),\n\n\t\ttrending: (timeframe: Timeframe = Timeframe.Day, limit = 20) =>\n\t\t\tfetchApi<PostsResponse>(\n\t\t\t\t`/social/post/trending?timeframe=${timeframe}&limit=${limit}`,\n\t\t\t),\n\t},\n\n\t// Generic transaction fetcher for any transaction type\n\ttransactions: {\n\t\tsingle: (txid: string) => fetchApi<BaseTransaction>(`/tx/${txid}`),\n\n\t\t// Specific transaction type fetchers\n\t\tfollow: (txid: string) =>\n\t\t\tfetchApi<FollowTransaction>(`/social/follow/${txid}`),\n\n\t\tunfollow: (txid: string) =>\n\t\t\tfetchApi<UnfollowTransaction>(`/social/unfollow/${txid}`),\n\t},\n\n\t// Messages endpoints\n\tmessages: {\n\t\tdirect: (params: DirectMessageParams) =>\n\t\t\tfetchApi(\n\t\t\t\t`/social/@/${params.bapId}/messages?page=${params.page}&limit=${params.limit}${\n\t\t\t\t\tparams.targetBapId ? `&targetBapId=${params.targetBapId}` : \"\"\n\t\t\t\t}`,\n\t\t\t),\n\n\t\tchannel: (channelId: string, page = 1, limit = 20) =>\n\t\t\tfetchApi<MessagesResponse>(\n\t\t\t\t`/social/channels/${channelId}/messages?page=${page}&limit=${limit}`,\n\t\t\t),\n\t},\n\n\t// Likes endpoints\n\tlikes: {\n\t\tforPost: (txid: string) => fetchApi<LikeInfo>(`/social/post/${txid}/like`),\n\n\t\tbyUser: (bapId: string, page = 1, limit = 20) =>\n\t\t\tfetchApi<LikesResponse>(\n\t\t\t\t`/social/bap/${bapId}/like?page=${page}&limit=${limit}`,\n\t\t\t),\n\t},\n\n\t// Identity endpoints\n\tidentity: {\n\t\tsearch: (query: string, limit = 10) =>\n\t\t\tfetchApi(\n\t\t\t\t`/social/identity/search?q=${encodeURIComponent(query)}&limit=${limit}`,\n\t\t\t),\n\n\t\tbyBapId: (bapId: string) => fetchApi(`/social/identity/${bapId}`),\n\t},\n\n\t// Channels\n\tchannels: {\n\t\tlist: () => fetchApi<ChannelInfo[]>(\"/social/channels\"),\n\n\t\tsingle: (channelId: string) => fetchApi(`/social/channel/${channelId}`),\n\t},\n\n\t// Friends\n\tfriends: {\n\t\tbyBapId: (bapId: string) => fetchApi(`/social/friend/${bapId}`),\n\n\t\t// Friend request management (uses different base URL)\n\t\taccept: async (bapId: string) => {\n\t\t\tconst response = await fetch(`${BMAP_API_URL}/social/friend/accept`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ bapId }),\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new BaseApiError(\n\t\t\t\t\t\"NETWORK_ERROR\",\n\t\t\t\t\t`Failed to accept friend request: ${response.statusText}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn response.json();\n\t\t},\n\n\t\treject: async (bapId: string) => {\n\t\t\tconst response = await fetch(`${BMAP_API_URL}/social/friend/reject`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({ bapId }),\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new BaseApiError(\n\t\t\t\t\t\"NETWORK_ERROR\",\n\t\t\t\t\t`Failed to reject friend request: ${response.statusText}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn response.json();\n\t\t},\n\t},\n};\n\n// Hook for easy access to the API client\nexport function useApiClient() {\n\treturn apiClient;\n}\n", "target": "<%- config.aliases.hooks %>/useapiclient.ts" } ] }