UNPKG

@hyperlane-xyz/registry

Version:

A collection of configs, artifacts, and schemas for Hyperlane

150 lines (149 loc) 4.53 kB
import { RegistryType, } from './IRegistry.js'; export class HttpError extends Error { status; body; constructor(message, status, body = null) { super(message); this.name = 'HttpError'; this.status = status; this.body = body; } } export class HttpClientRegistry { baseUrl; type = RegistryType.Http; uri; unimplementedMethods = new Set([ 'getUri', 'getChainLogoUri', 'addChain', 'removeChain', 'addWarpRoute', 'getWarpDeployConfig', 'getWarpDeployConfigs', 'addWarpRouteConfig', 'merge', ]); constructor(baseUrl = 'http://localhost:3001') { this.baseUrl = baseUrl; this.uri = baseUrl; } getMetadata() { return this.fetchJson('/metadata'); } getAddresses() { return this.fetchJson('/addresses'); } getUri(_itemPath) { throw new Error('Method not implemented.'); } listRegistryContent() { return this.fetchJson('/list-registry-content'); } getChains() { return this.fetchJson('/chains'); } async getChainMetadata(chainName) { try { return await this.fetchJson(`/chain/${chainName}/metadata`); } catch (e) { if (e instanceof HttpError && e.status === 404) { return null; } throw e; } } async getChainAddresses(chainName) { try { return await this.fetchJson(`/chain/${chainName}/addresses`); } catch (e) { if (e instanceof HttpError && e.status === 404) { return null; } throw e; } } async updateChain(update) { await this.fetchJson(`/chain/${update.chainName}`, { method: 'POST', body: JSON.stringify({ metadata: update.metadata, addresses: update.addresses, }), headers: { 'Content-Type': 'application/json', }, }); } getChainLogoUri(_chainName) { throw new Error('Method not implemented.'); } addChain(_chain) { throw new Error('Method not implemented.'); } removeChain(_chain) { throw new Error('Method not implemented.'); } getWarpRoute(routeId) { return this.fetchJson(`/warp-route/core/${routeId}`); } getWarpRoutes(filter) { const queryParams = new URLSearchParams(); if (filter?.symbol) { queryParams.set('symbol', filter.symbol); } if (filter?.label) { queryParams.set('label', filter.label); } return this.fetchJson(`/warp-route/core?${queryParams.toString()}`); } addWarpRoute(_config) { throw new Error('Method not implemented.'); } getWarpDeployConfig(routeId) { return this.fetchJson(`/warp-route/deploy/${routeId}`); } getWarpDeployConfigs() { throw new Error('Method not implemented.'); } addWarpRouteConfig(_config, _options) { throw new Error('Method not implemented.'); } merge(_otherRegistry) { throw new Error('Method not implemented.'); } async fetchJson(endpoint, options = {}) { const requestOptions = { ...options }; // Only add JSON content-type header if there's a body if (options.body) { requestOptions.headers = { 'Content-Type': 'application/json', ...options.headers, }; } const response = await fetch(`${this.baseUrl}${endpoint}`, requestOptions); // Handle successful requests that have no content to parse. if (response.status === 204) { return null; } if (!response.ok) { let errorBody = null; let errorMessage = `HTTP Error: ${response.status} ${response.statusText}`; try { errorBody = await response.json(); // Use the server's detailed error message if available if (errorBody?.message) { errorMessage = errorBody.message; } } catch (e) { // Ignore if error body isn't valid JSON, use statusText instead. } // Throw the structured error throw new HttpError(errorMessage, response.status, errorBody); } return response.json(); } }