@hyperlane-xyz/registry 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,9 @@ export declare abstract class BaseRegistry implements IRegistry {
9
9
  protected readonly logger: Logger;
10
10
  protected listContentCache?: RegistryContent;
11
11
  protected metadataCache?: ChainMap<ChainMetadata>;
12
+ protected isMetadataCacheFull: boolean;
12
13
  protected addressCache?: ChainMap<ChainAddresses>;
14
+ protected isAddressCacheFull: boolean;
13
15
  constructor({ uri, logger }: {
14
16
  uri: string;
15
17
  logger?: Logger;
@@ -25,6 +27,7 @@ export declare abstract class BaseRegistry implements IRegistry {
25
27
  abstract getChainMetadata(chainName: ChainName): MaybePromise<ChainMetadata | null>;
26
28
  abstract getAddresses(): MaybePromise<ChainMap<ChainAddresses>>;
27
29
  abstract getChainAddresses(chainName: ChainName): MaybePromise<ChainAddresses | null>;
30
+ getChainLogoUri(chainName: ChainName): Promise<string | null>;
28
31
  abstract addChain(chain: {
29
32
  chainName: ChainName;
30
33
  metadata?: ChainMetadata;
@@ -1,11 +1,13 @@
1
- export const CHAIN_FILE_REGEX = /chains\/([a-z0-9]+)\/([a-z]+)\.yaml/;
1
+ export const CHAIN_FILE_REGEX = /chains\/([a-z0-9]+)\/([a-z]+)\.(yaml|svg)/;
2
2
  export class BaseRegistry {
3
3
  uri;
4
4
  logger;
5
5
  // Caches
6
6
  listContentCache;
7
7
  metadataCache;
8
+ isMetadataCacheFull = false;
8
9
  addressCache;
10
+ isAddressCacheFull = false;
9
11
  constructor({ uri, logger }) {
10
12
  this.uri = uri;
11
13
  // @ts-ignore forcing in to avoid a @hyperlane-xyz/utils
@@ -30,4 +32,9 @@ export class BaseRegistry {
30
32
  const basePath = `deployments/warp_routes/${symbol}/${chains}`;
31
33
  return { configPath: `${basePath}-config.yaml`, addressesPath: `${basePath}-addresses.yaml` };
32
34
  }
35
+ async getChainLogoUri(chainName) {
36
+ const registryContent = await this.listRegistryContent();
37
+ const chain = registryContent.chains[chainName];
38
+ return chain?.logo ?? null;
39
+ }
33
40
  }
@@ -19,9 +19,9 @@ export declare class GithubRegistry extends BaseRegistry implements IRegistry {
19
19
  listRegistryContent(): Promise<RegistryContent>;
20
20
  getChains(): Promise<Array<ChainName>>;
21
21
  getMetadata(): Promise<ChainMap<ChainMetadata>>;
22
- getChainMetadata(chainName: ChainName): Promise<ChainMetadata>;
22
+ getChainMetadata(chainName: ChainName): Promise<ChainMetadata | null>;
23
23
  getAddresses(): Promise<ChainMap<ChainAddresses>>;
24
- getChainAddresses(chainName: ChainName): Promise<ChainAddresses>;
24
+ getChainAddresses(chainName: ChainName): Promise<ChainAddresses | null>;
25
25
  addChain(_chains: {
26
26
  chainName: ChainName;
27
27
  metadata?: ChainMetadata;
@@ -35,6 +35,7 @@ export declare class GithubRegistry extends BaseRegistry implements IRegistry {
35
35
  removeChain(_chains: ChainName): Promise<void>;
36
36
  addWarpRoute(_config: WarpCoreConfig): Promise<void>;
37
37
  protected getRawContentUrl(path: string): string;
38
- protected fetchChainFiles<T>(fileName: keyof ChainFiles): Promise<ChainMap<T>>;
38
+ protected fetchChainFiles<T>(fileName: keyof ChainFiles, chainNames?: ChainName[]): Promise<ChainMap<T>>;
39
+ protected fetchSingleChainFile<T>(fileName: keyof ChainFiles, chainName: ChainName): Promise<T | null>;
39
40
  protected fetch(url: string): Promise<Response>;
40
41
  }
@@ -1,6 +1,5 @@
1
1
  import { parse as yamlParse } from 'yaml';
2
2
  import { DEFAULT_GITHUB_REGISTRY, GITHUB_FETCH_CONCURRENCY_LIMIT } from '../consts.js';
3
- import { ChainAddressesSchema } from '../types.js';
4
3
  import { concurrentMap } from '../utils.js';
5
4
  import { BaseRegistry, CHAIN_FILE_REGEX } from './BaseRegistry.js';
6
5
  import { RegistryType, } from './IRegistry.js';
@@ -33,10 +32,10 @@ export class GithubRegistry extends BaseRegistry {
33
32
  const chains = {};
34
33
  for (const node of tree) {
35
34
  if (CHAIN_FILE_REGEX.test(node.path)) {
36
- const [_, chainName, fileName] = node.path.match(CHAIN_FILE_REGEX);
35
+ const [_, chainName, fileName, extension] = node.path.match(CHAIN_FILE_REGEX);
37
36
  chains[chainName] ??= {};
38
37
  // @ts-ignore allow dynamic key assignment
39
- chains[chainName][fileName] = this.getRawContentUrl(`${chainPath}/${chainName}/${fileName}.yaml`);
38
+ chains[chainName][fileName] = this.getRawContentUrl(`${chainPath}/${chainName}/${fileName}.${extension}`);
40
39
  }
41
40
  // TODO add handling for deployment artifact files here too
42
41
  }
@@ -47,32 +46,36 @@ export class GithubRegistry extends BaseRegistry {
47
46
  return Object.keys(repoContents.chains);
48
47
  }
49
48
  async getMetadata() {
50
- if (this.metadataCache)
49
+ if (this.metadataCache && this.isMetadataCacheFull)
51
50
  return this.metadataCache;
52
51
  const chainMetadata = await this.fetchChainFiles('metadata');
52
+ this.isMetadataCacheFull = true;
53
53
  return (this.metadataCache = chainMetadata);
54
54
  }
55
55
  async getChainMetadata(chainName) {
56
56
  if (this.metadataCache?.[chainName])
57
57
  return this.metadataCache[chainName];
58
- const url = this.getRawContentUrl(`${this.getChainsPath()}/${chainName}/metadata.yaml`);
59
- const response = await this.fetch(url);
60
- const data = await response.text();
61
- return yamlParse(data);
58
+ const data = await this.fetchSingleChainFile('metadata', chainName);
59
+ if (!data)
60
+ return null;
61
+ this.metadataCache = { ...this.metadataCache, [chainName]: data };
62
+ return data;
62
63
  }
63
64
  async getAddresses() {
64
- if (this.addressCache)
65
+ if (this.addressCache && this.isAddressCacheFull)
65
66
  return this.addressCache;
66
67
  const chainAddresses = await this.fetchChainFiles('addresses');
68
+ this.isAddressCacheFull = true;
67
69
  return (this.addressCache = chainAddresses);
68
70
  }
69
71
  async getChainAddresses(chainName) {
70
72
  if (this.addressCache?.[chainName])
71
73
  return this.addressCache[chainName];
72
- const url = this.getRawContentUrl(`${this.getChainsPath()}/${chainName}/addresses.yaml`);
73
- const response = await this.fetch(url);
74
- const data = await response.text();
75
- return ChainAddressesSchema.parse(yamlParse(data));
74
+ const data = await this.fetchSingleChainFile('addresses', chainName);
75
+ if (!data)
76
+ return null;
77
+ this.addressCache = { ...this.addressCache, [chainName]: data };
78
+ return data;
76
79
  }
77
80
  async addChain(_chains) {
78
81
  throw new Error('TODO: Implement');
@@ -89,9 +92,11 @@ export class GithubRegistry extends BaseRegistry {
89
92
  getRawContentUrl(path) {
90
93
  return `https://raw.githubusercontent.com/${this.repoOwner}/${this.repoName}/${this.branch}/${path}`;
91
94
  }
92
- async fetchChainFiles(fileName) {
95
+ // Fetches all files of a particular type in parallel
96
+ // Defaults to all known chains if chainNames is not provided
97
+ async fetchChainFiles(fileName, chainNames) {
93
98
  const repoContents = await this.listRegistryContent();
94
- const chainNames = Object.keys(repoContents.chains);
99
+ chainNames ||= Object.keys(repoContents.chains);
95
100
  const fileUrls = chainNames.reduce((acc, chainName) => {
96
101
  const fileUrl = repoContents.chains[chainName][fileName];
97
102
  if (fileUrl)
@@ -105,6 +110,10 @@ export class GithubRegistry extends BaseRegistry {
105
110
  });
106
111
  return Object.fromEntries(results);
107
112
  }
113
+ async fetchSingleChainFile(fileName, chainName) {
114
+ const results = await this.fetchChainFiles(fileName, [chainName]);
115
+ return results[chainName] ?? null;
116
+ }
108
117
  async fetch(url) {
109
118
  this.logger.debug(`Fetching from github: ${url}`);
110
119
  const response = await fetch(url);
@@ -3,6 +3,7 @@ import type { ChainAddresses, MaybePromise } from '../types.js';
3
3
  export interface ChainFiles {
4
4
  metadata?: string;
5
5
  addresses?: string;
6
+ logo?: string;
6
7
  }
7
8
  export interface RegistryContent {
8
9
  chains: ChainMap<ChainFiles>;
@@ -21,6 +22,7 @@ export interface IRegistry {
21
22
  getChainMetadata(chainName: ChainName): MaybePromise<ChainMetadata | null>;
22
23
  getAddresses(): MaybePromise<ChainMap<ChainAddresses>>;
23
24
  getChainAddresses(chainName: ChainName): MaybePromise<ChainAddresses | null>;
25
+ getChainLogoUri(chainName: ChainName): Promise<string | null>;
24
26
  addChain(chain: {
25
27
  chainName: ChainName;
26
28
  metadata?: ChainMetadata;
@@ -13,9 +13,9 @@ export declare class LocalRegistry extends BaseRegistry implements IRegistry {
13
13
  listRegistryContent(): RegistryContent;
14
14
  getChains(): Array<ChainName>;
15
15
  getMetadata(): ChainMap<ChainMetadata>;
16
- getChainMetadata(chainName: ChainName): ChainMetadata;
16
+ getChainMetadata(chainName: ChainName): ChainMetadata | null;
17
17
  getAddresses(): ChainMap<ChainAddresses>;
18
- getChainAddresses(chainName: ChainName): ChainAddresses;
18
+ getChainAddresses(chainName: ChainName): ChainAddresses | null;
19
19
  addChain(chain: {
20
20
  chainName: ChainName;
21
21
  metadata?: ChainMetadata;
@@ -47,9 +47,7 @@ export class LocalRegistry extends BaseRegistry {
47
47
  }
48
48
  getChainMetadata(chainName) {
49
49
  const metadata = this.getMetadata();
50
- if (!metadata[chainName])
51
- throw new Error(`Metadata not found in registry for chain: ${chainName}`);
52
- return metadata[chainName];
50
+ return metadata[chainName] ?? null;
53
51
  }
54
52
  getAddresses() {
55
53
  if (this.addressCache)
@@ -66,9 +64,7 @@ export class LocalRegistry extends BaseRegistry {
66
64
  }
67
65
  getChainAddresses(chainName) {
68
66
  const addresses = this.getAddresses();
69
- if (!addresses[chainName])
70
- throw new Error(`Addresses not found in registry for chain: ${chainName}`);
71
- return addresses[chainName];
67
+ return addresses[chainName] ?? null;
72
68
  }
73
69
  addChain(chain) {
74
70
  const currentChains = this.listRegistryContent().chains;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hyperlane-xyz/registry",
3
3
  "description": "A collection of configs, artifacts, and schemas for Hyperlane",
4
- "version": "1.1.1",
4
+ "version": "1.1.2",
5
5
  "dependencies": {
6
6
  "yaml": "^2",
7
7
  "zod": "^3.21.2"