UNPKG

@artinet/sdk

Version:
182 lines 7.14 kB
/** * HTTP JSON-RPC client utilities. * Handles the common pattern of sending JSON-RPC requests and processing responses. */ import { v4 as uuidv4 } from "uuid"; import { SystemError, INTERNAL_ERROR, PARSE_ERROR, } from "../../utils/common/errors.js"; import { parseResponse } from "./parser.js"; import { logError, logWarn } from "../../utils/logging/log.js"; /** * Creates a JSON-RPC request body with the specified method and parameters. *, ErrorCodeParseError * @param method The JSON-RPC method name * @param params The parameters for the method * @param requestId Optional request ID (generates a UUID v4 if not provided) * @returns A properly formatted JSON-RPC request object */ export function createJsonRpcRequest(method, params, requestId = uuidv4()) { return { jsonrpc: "2.0", id: requestId, method, params, }; } /** * Sends a JSON-RPC request to the specified endpoint. * * @param baseUrl The API endpoint URL * @param method The JSON-RPC method name * @param params The parameters for the method * @param headers Custom headers to include in the request * @param acceptHeader The desired Accept header ('application/json' or 'text/event-stream') * @returns A Promise resolving to the fetch Response object * @throws RpcError if there's a network error */ export async function sendJsonRpcRequest(baseUrl, method, params, headers = {}, acceptHeader = "application/json") { const requestBody = createJsonRpcRequest(method, params); try { return await fetch(baseUrl, { method: "POST", headers: { "Content-Type": "application/json", Accept: acceptHeader, ...headers, }, body: JSON.stringify(requestBody), }); } catch (networkError) { logError("SendJsonRpcRequest", "Network error during RPC call:", networkError); // Wrap network errors into a standard error format throw INTERNAL_ERROR(networkError); } } /** * Sends a GET request to the specified endpoint. * This is used for non-JSON-RPC calls like agent card retrieval. * * @param url The endpoint URL * @param headers Custom headers to include in the request * @returns A Promise resolving to the fetch Response object * @throws RpcError if there's a network error */ export async function sendGetRequest(url, headers = {}) { try { return await fetch(url, { method: "GET", headers: { Accept: "application/json", ...headers, }, }); } catch (networkError) { logError("SendGetRequest", "Network error during GET request:", networkError); throw INTERNAL_ERROR(networkError); } } /** * Processes a standard JSON-RPC response (non-streaming). * Parses the response, validates it, and returns the result payload. * * @param response The fetch Response object * @param expectedMethod Optional method name for logging purposes * @returns A promise resolving to the result payload * @throws RpcError if there's an error in the response */ export async function handleJsonRpcResponse(response, expectedMethod) { let responseBody = null; try { responseBody = await response.text(); if (!response.ok) { try { // Try to parse error as JSON-RPC parseResponse(responseBody); // If we get here, it means there was no error in the response // But the HTTP status was not OK, so we throw a generic error } catch (parseError) { logWarn("handleJsonRpcResponse", "Error parsing JSON-RPC response:", parseError); } // Throw a generic HTTP error if we couldn't extract an RPC error throw new Error(`HTTP error ${response.status}: ${response.statusText}${responseBody ? ` - ${responseBody}` : ""}`); } // Parse and validate the response // If it has an error, parseResponse will throw // If it doesn't have a result, parseResponse will also throw const jsonResponse = parseResponse(responseBody); // At this point, we know we have a valid result // NonNullable is used in the return type to ensure TypeScript knows this return jsonResponse.result; } catch (error) { logError("handleJsonRpcResponse", `Error processing response [${expectedMethod}]:`, error); // Re-throw RpcError instances directly, wrap others if (error instanceof SystemError) { throw error; } else { throw INTERNAL_ERROR(error); } } } /** * Processes a JSON response from a regular GET request. * Handles error checking and returns the parsed JSON. * * @param response The fetch Response object * @param endpoint Optional endpoint description for logging purposes * @returns A promise resolving to the parsed JSON * @throws RpcError if there's a response error */ export async function handleJsonResponse(response, endpoint) { let responseBody = null; try { responseBody = await response.text(); if (!response.ok) { throw new Error(`HTTP error ${response.status}: ${response.statusText}${responseBody ? ` - ${responseBody}` : ""}`); } return JSON.parse(responseBody); } catch (error) { logError("handleJsonResponse", `Error processing response for ${endpoint || "unknown endpoint"}:`, error); if (error instanceof SystemError) { throw error; } else { throw PARSE_ERROR(error); } } } /** * Sends a JSON-RPC request and processes the response in a single operation. * This combines sendJsonRpcRequest and handleJsonRpcResponse into one call. * * @param baseUrl The API endpoint URL * @param method The JSON-RPC method name * @param params The parameters for the method * @param headers Custom headers to include in the request * @param acceptHeader The desired Accept header ('application/json' or 'text/event-stream') * @returns A Promise resolving to the result payload * @throws RpcError if there's a network error or error in the response */ export async function executeJsonRpcRequest(baseUrl, method, params, headers = {}, acceptHeader = "application/json") { const response = await sendJsonRpcRequest(baseUrl, method, params, headers, acceptHeader); return handleJsonRpcResponse(response, method); } /** * Sends a GET request and processes the JSON response. * Helper for non-RPC REST endpoints. * * @param url The endpoint URL * @param headers Custom headers to include in the request * @param endpoint Optional endpoint description for logging * @returns A Promise resolving to the parsed JSON * @throws RpcError if there's a network error or error in the response */ export async function executeGetRequest(url, headers = {}, endpoint) { const response = await sendGetRequest(url, headers); return handleJsonResponse(response, endpoint); } //# sourceMappingURL=rpc-client.js.map