UNPKG

@hyperlane-xyz/registry

Version:

A collection of configs, artifacts, and schemas for Hyperlane

159 lines (158 loc) 4.89 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', '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()}`); } async addWarpRoute(config, options) { await this.fetchJson('/warp-route', { method: 'POST', body: JSON.stringify({ config, options }), }); } getWarpDeployConfig(routeId) { return this.fetchJson(`/warp-route/deploy/${routeId}`); } getWarpDeployConfigs(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/deploy?${queryParams.toString()}`); } async addWarpRouteConfig(config, options) { await this.fetchJson('/warp-route/deploy', { method: 'POST', body: JSON.stringify({ config, options }), }); } 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(); } }