diff --git a/README.md b/README.md index 88bc04f..bedc527 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ yarn starship port-pids # test yarn starship:test -# watch +# watch yarn starship:watch ``` @@ -219,7 +219,7 @@ client.undeploy(); client.teardown(); ``` -## StarshipJS Usage +## StarshipJS Usage [`StarshipJS`](https://github.com/cosmology-tech/StarshipJS/tree/main/js/starshipjs) is a utility library that provides helpers to leverage [Starship](https://github.com/cosmology-tech/starship)'s internal chain registry, emulating the style of code used in projects like [cosmos-kit](https://github.com/cosmology-tech/cosmos-kit). @@ -234,16 +234,42 @@ import { join } from 'path'; // Path to your YAML configuration file const configFile = join(__dirname, 'your-config.yaml'); -// Set the configuration file in StarshipJS -ConfigContext.setConfigFile(configFile); +// using init for init the config and a default connected registry fetcher. +await ConfigContext.init(configFile); + ``` ### Registry +Using init for init the config and pass an optional customized registry fetcher. + +```js +import { useRegistry, ConfigContext } from 'starshipjs'; +import { join } from 'path'; + +// Path to your YAML configuration file +const configFile = join(__dirname, 'your-config.yaml'); + +const fetcher = new ChainRegistryFetcher({ + // your own options +}); + +await ConfigContext.init(configFile, fetcher); +``` + +Or use `useRegistry` to get a registry fetcher. + + ```js import { useRegistry, ConfigContext } from 'starshipjs'; +import { join } from 'path'; + +// Path to your YAML configuration file +const configFile = join(__dirname, 'your-config.yaml'); + +const fetcher = await useRegistry(configFile); -ConfigContext.setRegistry(await useRegistry(Config.configFile)); +await ConfigContext.init(configFile, fetcher); ``` ## Chain Info diff --git a/js/starshipjs/README.md b/js/starshipjs/README.md index c283a17..dbd421f 100644 --- a/js/starshipjs/README.md +++ b/js/starshipjs/README.md @@ -53,7 +53,7 @@ yarn starship deploy yarn starship start-ports ``` -## Using the Client +## Using the Client StarshipJS is a utility library that provides helpers to leverage [Starship](https://github.com/cosmology-tech/starship)'s internal chain registry, emulating the style of code used in projects like [cosmos-kit](https://github.com/cosmology-tech/cosmos-kit). @@ -68,16 +68,42 @@ import { join } from 'path'; // Path to your YAML configuration file const configFile = join(__dirname, 'your-config.yaml'); -// Set the configuration file in StarshipJS -ConfigContext.setConfigFile(configFile); +// using init for init the config and a default connected registry fetcher. +await ConfigContext.init(configFile); + ``` ### Registry +Using init for init the config and pass an optional customized registry fetcher. + ```js import { useRegistry, ConfigContext } from 'starshipjs'; +import { join } from 'path'; + +// Path to your YAML configuration file +const configFile = join(__dirname, 'your-config.yaml'); + +const fetcher = new ChainRegistryFetcher({ + // your own options +}); + +await ConfigContext.init(configFile, fetcher); +``` + +Or use `useRegistry` to get a registry fetcher. + + +```js +import { useRegistry, ConfigContext } from 'starshipjs'; +import { join } from 'path'; + +// Path to your YAML configuration file +const configFile = join(__dirname, 'your-config.yaml'); + +const fetcher = await useRegistry(configFile); -ConfigContext.setRegistry(await useRegistry(Config.configFile)); +await ConfigContext.init(configFile, fetcher); ``` ## Chain Info diff --git a/js/starshipjs/__tests__/config.test.ts b/js/starshipjs/__tests__/config.test.ts new file mode 100644 index 0000000..5508c22 --- /dev/null +++ b/js/starshipjs/__tests__/config.test.ts @@ -0,0 +1,25 @@ +import path from "path"; + +import { Config, ConfigContext } from "../src/config"; +import { ChainRegistryFetcher } from "@chain-registry/client"; + +// it's more recommended to use ConfigContext.init to set the config file and registry. +it("1. throws without init;\n 2. init the setup and gets config;\n 3. throws when double init;\n", async () => { + expect(() => ConfigContext.registry).toThrow(); + expect(() => ConfigContext.configFile).toThrow(); + + const file = path.join(__dirname, "../../../__fixtures__", "config.yaml"); + + // for unit test, only setup a chain registry fetcher without fetching. + await Config.init(file, new ChainRegistryFetcher()); + + const registry = ConfigContext.registry; + const configFile = ConfigContext.configFile; + + expect(registry).toBeInstanceOf(ChainRegistryFetcher); + expect(configFile).toBe(file); + + expect( + async () => await ConfigContext.init(file, new ChainRegistryFetcher()) + ).rejects.toThrow(); +}); diff --git a/js/starshipjs/__tests__/first.test.ts b/js/starshipjs/__tests__/first.test.ts deleted file mode 100644 index 2d48e8d..0000000 --- a/js/starshipjs/__tests__/first.test.ts +++ /dev/null @@ -1,3 +0,0 @@ -it('works', () => { - console.log('hello test world!'); -}) \ No newline at end of file diff --git a/js/starshipjs/__tests__/legacy.test.ts b/js/starshipjs/__tests__/legacy.test.ts new file mode 100644 index 0000000..e2eafee --- /dev/null +++ b/js/starshipjs/__tests__/legacy.test.ts @@ -0,0 +1,29 @@ +import path from "path"; + +import { Config, ConfigContext } from "../src/config"; +import { ChainRegistryFetcher } from "@chain-registry/client"; + +// people can still use legacy ConfigContext to set the config file and registry. +it("1. throws without init;\n 2. throws only init partially;\n 3. init the setup and gets config;\n 4. throws when double init;\n", async () => { + expect(() => ConfigContext.registry).toThrow(); + expect(() => ConfigContext.configFile).toThrow(); + + const file = path.join(__dirname, "../../../__fixtures__", "config.yaml"); + + ConfigContext.setConfigFile(file); + + expect(() => ConfigContext.registry).toThrow(); + expect(() => ConfigContext.configFile).toThrow(); + + ConfigContext.setRegistry(new ChainRegistryFetcher()); + + const registry = ConfigContext.registry; + const configFile = ConfigContext.configFile; + + expect(registry).toBeInstanceOf(ChainRegistryFetcher); + expect(configFile).toBe(file); + + expect( + async () => await ConfigContext.init(file, new ChainRegistryFetcher()) + ).rejects.toThrow(); +}); diff --git a/js/starshipjs/src/config.ts b/js/starshipjs/src/config.ts index 74870ce..6406a9c 100644 --- a/js/starshipjs/src/config.ts +++ b/js/starshipjs/src/config.ts @@ -1,25 +1,91 @@ -import { ChainRegistryFetcher } from '@chain-registry/client'; +import { ChainRegistryFetcher } from "@chain-registry/client"; + +import { useRegistry } from "./hooks"; + export class Config { - private static instance: Config; + // keep instantiation private to enforce singletone + private constructor() {} public registry?: ChainRegistryFetcher; public configFile?: string; + private isConfigInitialized = false; + private isRegistryInitialized = false; - // keep instantiation private to enforce singletone - private constructor() {} + private static instance: Config; + + setConfigFile(configFile: string) { + this.configFile = configFile; + this.isConfigInitialized = true; + } + + setRegistry(registry: ChainRegistryFetcher) { + this.registry = registry; + this.isRegistryInitialized = true; + } + + private get isInitialized() { + return this.isConfigInitialized && this.isRegistryInitialized; + } + + // init config with a config file and an optional registry fetcher + // if no registry fetcher is provided, it will use the default registry fetcher + // by enforcing the use of the init method, we can ensure that the config is initialized + public static async init( + configFile: string, + registryFetcher?: ChainRegistryFetcher + ) { + if (Config.instance && Config.instance.isInitialized) { + throw new Error("Config is already initialized."); + } + + const fetcher = registryFetcher ?? (await useRegistry(configFile)); + + Config.instance = new Config(); + Config.instance.setConfigFile(configFile); + Config.instance.setRegistry(fetcher); + } public static getInstance(): Config { + if (!Config.instance || !Config.instance.isInitialized) { + throw new Error("Config's not initialized."); + } + + return Config.instance; + } + + /** + * set the config file path + * @param configFile + * @depracated it's not recommended to set the configFile directly. Use init instead. + */ + public static setConfigFile(configFile: string) { if (!Config.instance) { Config.instance = new Config(); } - return Config.instance; + + Config.instance.setConfigFile(configFile); } - setConfigFile(configFile: string) { - this.configFile = configFile; + /** + * set the chain registry fetcher + * @param registry + * @depracated it's not recommended to set the registry directly. Use init instead. + */ + public static setRegistry(registry: ChainRegistryFetcher) { + if (!Config.instance) { + Config.instance = new Config(); + } + + Config.instance.setRegistry(registry); } - setRegistry(registry: ChainRegistryFetcher) { - this.registry = registry; + public static get configFile() { + // use getInstance to ensure that the config is initialized. + return Config.getInstance().configFile; + } + + public static get registry() { + // use getInstance to ensure that the config is initialized. + return Config.getInstance().registry; } } @@ -27,7 +93,7 @@ export interface ChainConfig { registry: { ports: { rest: number; - } + }; }; chains: Array<{ name: string; @@ -42,4 +108,4 @@ export interface ChainConfig { }>; } -export const ConfigContext = Config.getInstance(); \ No newline at end of file +export const ConfigContext = Config;