@fuel-infrastructure/fuel-hyperlane-registry
Version:
A collection of configs, artifacts, and schemas for Hyperlane
111 lines (110 loc) • 4.6 kB
JavaScript
import { objMerge } from '../utils.js';
import { RegistryType, } from './IRegistry.js';
/**
* A registry that accepts multiple sub-registries.
* Read methods are performed on all sub-registries and the results are merged.
* Write methods are performed on all sub-registries.
* Can be created manually or by calling `.merge()` on an existing registry.
*/
export class MergedRegistry {
type = RegistryType.Merged;
uri = '__merged_registry__';
registries;
logger;
constructor({ registries, logger }) {
if (!registries.length)
throw new Error('At least one registry URI is required');
this.registries = registries;
// @ts-ignore
this.logger = logger || console;
}
getUri() {
throw new Error('getUri method not applicable to MergedRegistry');
}
async listRegistryContent() {
const results = await this.multiRegistryRead((r) => r.listRegistryContent());
return results.reduce((acc, content) => objMerge(acc, content), {
chains: {},
deployments: {
warpRoutes: {},
warpDeployConfig: {}
},
});
}
async getChains() {
return Object.keys(await this.getMetadata());
}
async getMetadata() {
const results = await this.multiRegistryRead((r) => r.getMetadata());
return results.reduce((acc, content) => objMerge(acc, content), {});
}
async getChainMetadata(chainName) {
return (await this.getMetadata())[chainName] || null;
}
async getAddresses() {
const results = await this.multiRegistryRead((r) => r.getAddresses());
return results.reduce((acc, content) => objMerge(acc, content), {});
}
async getChainAddresses(chainName) {
return (await this.getAddresses())[chainName] || null;
}
async getChainLogoUri(chainName) {
const results = await this.multiRegistryRead((r) => r.getChainLogoUri(chainName));
return results.find((uri) => !!uri) || null;
}
async addChain(chain) {
return this.multiRegistryWrite(async (registry) => await registry.addChain(chain), `adding chain ${chain.chainName}`);
}
async updateChain(chain) {
return this.multiRegistryWrite(async (registry) => await registry.updateChain(chain), `updating chain ${chain.chainName}`);
}
async removeChain(chain) {
return this.multiRegistryWrite(async (registry) => await registry.removeChain(chain), `removing chain ${chain}`);
}
async getWarpRoute(id) {
const results = await this.multiRegistryRead((r) => r.getWarpRoute(id));
return results.find((r) => !!r) || null;
}
async getWarpDeployConfig(id) {
const results = await this.multiRegistryRead((r) => r.getWarpDeployConfig(id));
return results.find((r) => !!r) || null;
}
async getWarpRoutes(filter) {
const results = await this.multiRegistryRead((r) => r.getWarpRoutes(filter));
return results.reduce((acc, content) => objMerge(acc, content), {});
}
async getWarpDeployConfigs(filter) {
const results = await this.multiRegistryRead((r) => r.getWarpDeployConfigs(filter));
return results.reduce((acc, content) => objMerge(acc, content), {});
}
async addWarpRoute(config, options) {
return this.multiRegistryWrite(async (registry) => await registry.addWarpRoute(config, options), 'adding warp route');
}
multiRegistryRead(readFn) {
return Promise.all(this.registries.map(readFn));
}
async multiRegistryWrite(writeFn, logMsg) {
for (const registry of this.registries) {
// TODO remove this when GithubRegistry supports write methods
if (registry.type === RegistryType.Github) {
this.logger.warn(`Skipping ${logMsg} at ${registry.type} registry`);
continue;
}
try {
this.logger.info(`Now ${logMsg} at ${registry.type} registry at ${registry.uri}`);
await writeFn(registry);
this.logger.info(`Done ${logMsg} at ${registry.type} registry`);
}
catch (error) {
// To prevent loss of artifacts, MergedRegistry write methods are failure tolerant
this.logger.error(`Failure ${logMsg} at ${registry.type} registry`, error);
}
}
}
merge(otherRegistry) {
return new MergedRegistry({
registries: [...this.registries, otherRegistry],
logger: this.logger,
});
}
}