From 771f61e59c1cf01d0fc133a98ad24571d7f17787 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 09:28:17 +0100 Subject: [PATCH 01/37] feat: refactor configs [JS-831] --- packages/cli-connector/package.json | 1 - packages/cli-connector/vite.config.ts | 2 + .../cli/package/src/commands/air/beautify.ts | 1 - .../cli/package/src/commands/aqua/imports.ts | 1 - .../cli/package/src/commands/default/env.ts | 11 +- .../cli/package/src/commands/default/peers.ts | 1 - .../cli/package/src/commands/dep/install.ts | 1 - .../cli/package/src/commands/dep/reset.ts | 1 - .../cli/package/src/commands/dep/uninstall.ts | 1 - packages/cli/package/src/commands/key/new.ts | 12 +- .../cli/package/src/commands/local/init.ts | 4 +- packages/cli/package/src/commands/local/up.ts | 21 +- .../cli/package/src/commands/provider/gen.ts | 2 +- .../cli/package/src/commands/provider/info.ts | 2 +- .../cli/package/src/commands/provider/init.ts | 10 +- .../package/src/commands/service/remove.ts | 1 - packages/cli/package/src/genConfigDocs.ts | 37 +- .../cli/package/src/lib/chain/chainConfig.ts | 6 +- .../cli/package/src/lib/chain/commitment.ts | 5 +- .../cli/package/src/lib/chain/conversions.ts | 1 - .../cli/package/src/lib/chain/offer/offer.ts | 10 +- .../src/lib/chain/offer/updateOffers.ts | 2 +- .../cli/package/src/lib/chain/providerInfo.ts | 2 +- .../cli/package/src/lib/configs/initConfig.ts | 21 +- .../package/src/lib/configs/initConfigNew.ts | 502 ++++ .../src/lib/configs/initConfigNewTypes.ts | 170 ++ .../src/lib/configs/project/dockerCompose.ts | 5 +- .../package/src/lib/configs/project/env.ts | 202 -- .../src/lib/configs/project/env/env.ts | 41 + .../{globalConfigs.ts => project/env/env0.ts} | 32 +- .../src/lib/configs/project/env/env1.ts | 97 + .../src/lib/configs/project/fluence.ts | 6 +- .../src/lib/configs/project/provider.ts | 2440 ----------------- .../lib/configs/project/provider/provider.ts | 563 ++++ .../lib/configs/project/provider/provider0.ts | 445 +++ .../lib/configs/project/provider/provider1.ts | 737 +++++ .../lib/configs/project/provider/provider2.ts | 131 + .../lib/configs/project/provider/provider3.ts | 611 +++++ .../lib/configs/project/providerArtifacts.ts | 366 --- .../providerArtifacts/providerArtifacts.ts | 52 + .../providerArtifacts/providerArtifacts0.ts | 52 + .../providerArtifacts/providerArtifacts1.ts | 80 + .../providerArtifacts/providerArtifacts2.ts | 105 + .../providerArtifacts/providerArtifacts3.ts | 75 + .../lib/configs/project/providerSecrets.ts | 156 -- .../providerSecrets/providerSecrets.ts | 59 + .../providerSecrets/providerSecrets0.ts | 65 + .../package/src/lib/configs/user/config.ts | 214 -- .../src/lib/configs/user/config/config.ts | 75 + .../src/lib/configs/user/config/config0.ts | 43 + .../src/lib/configs/user/config/config1.ts | 88 + packages/cli/package/src/lib/const.ts | 4 +- packages/cli/package/src/lib/countly.ts | 3 +- packages/cli/package/src/lib/dealClient.ts | 2 +- .../src/lib/generateUserProviderConfig.ts | 22 +- packages/cli/package/src/lib/init.ts | 12 +- packages/cli/package/src/lib/keyPairs.ts | 26 +- packages/cli/package/src/lib/lifeCycle.ts | 46 +- packages/cli/package/src/lib/multiaddres.ts | 5 +- .../src/lib/multiaddresWithoutLocal.ts | 2 +- packages/cli/package/src/lib/paths.ts | 10 + .../src/lib/resolveComputePeersByNames.ts | 2 +- .../cli/package/src/lib/resolveFluenceEnv.ts | 3 +- .../cli/package/test/tests/provider.test.ts | 18 +- yarn.lock | 8 - 65 files changed, 4168 insertions(+), 3563 deletions(-) create mode 100644 packages/cli/package/src/lib/configs/initConfigNew.ts create mode 100644 packages/cli/package/src/lib/configs/initConfigNewTypes.ts delete mode 100644 packages/cli/package/src/lib/configs/project/env.ts create mode 100644 packages/cli/package/src/lib/configs/project/env/env.ts rename packages/cli/package/src/lib/configs/{globalConfigs.ts => project/env/env0.ts} (53%) create mode 100644 packages/cli/package/src/lib/configs/project/env/env1.ts delete mode 100644 packages/cli/package/src/lib/configs/project/provider.ts create mode 100644 packages/cli/package/src/lib/configs/project/provider/provider.ts create mode 100644 packages/cli/package/src/lib/configs/project/provider/provider0.ts create mode 100644 packages/cli/package/src/lib/configs/project/provider/provider1.ts create mode 100644 packages/cli/package/src/lib/configs/project/provider/provider2.ts create mode 100644 packages/cli/package/src/lib/configs/project/provider/provider3.ts delete mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts0.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts1.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts2.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts3.ts delete mode 100644 packages/cli/package/src/lib/configs/project/providerSecrets.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets.ts create mode 100644 packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets0.ts delete mode 100644 packages/cli/package/src/lib/configs/user/config.ts create mode 100644 packages/cli/package/src/lib/configs/user/config/config.ts create mode 100644 packages/cli/package/src/lib/configs/user/config/config0.ts create mode 100644 packages/cli/package/src/lib/configs/user/config/config1.ts diff --git a/packages/cli-connector/package.json b/packages/cli-connector/package.json index 9b82903cc..e51ba5430 100644 --- a/packages/cli-connector/package.json +++ b/packages/cli-connector/package.json @@ -33,7 +33,6 @@ "@types/react-dom": "^18.3.0", "@vitejs/plugin-react-swc": "3.7.0", "eslint": "9.10.0", - "hotscript": "1.0.13", "npm-check-updates": "^17.1.1", "typescript": "5.6.2", "typescript-eslint": "8.5.0", diff --git a/packages/cli-connector/vite.config.ts b/packages/cli-connector/vite.config.ts index 6e4113dd9..d1095c7e2 100644 --- a/packages/cli-connector/vite.config.ts +++ b/packages/cli-connector/vite.config.ts @@ -20,4 +20,6 @@ import { defineConfig } from "vite"; export default defineConfig({ plugins: [react()], + // Disable chunk size warning cause this frontend is only used on local server + build: { chunkSizeWarningLimit: Infinity }, }); diff --git a/packages/cli/package/src/commands/air/beautify.ts b/packages/cli/package/src/commands/air/beautify.ts index abab4b7db..45d59a99d 100644 --- a/packages/cli/package/src/commands/air/beautify.ts +++ b/packages/cli/package/src/commands/air/beautify.ts @@ -29,7 +29,6 @@ export default class Beautify extends BaseCommand { static override aliases = ["air:b"]; static override description = "Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended to be read by mere mortals."; - static override flags = {}; static override args = { PATH: Args.string({ description: `Path to an AIR file. Must be relative to the current working directory or absolute`, diff --git a/packages/cli/package/src/commands/aqua/imports.ts b/packages/cli/package/src/commands/aqua/imports.ts index e4a558dfe..2d0289c6d 100644 --- a/packages/cli/package/src/commands/aqua/imports.ts +++ b/packages/cli/package/src/commands/aqua/imports.ts @@ -24,7 +24,6 @@ import { initCli } from "../../lib/lifeCycle.js"; export default class Json extends BaseCommand { static override description = "Returns a list of aqua imports that CLI produces"; - static override flags = {}; async run(): Promise { await initCli(this, await this.parse(Json)); diff --git a/packages/cli/package/src/commands/default/env.ts b/packages/cli/package/src/commands/default/env.ts index 6c873b6fb..422ee2134 100644 --- a/packages/cli/package/src/commands/default/env.ts +++ b/packages/cli/package/src/commands/default/env.ts @@ -19,8 +19,7 @@ import { color } from "@oclif/color"; import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; -import { setEnvConfig } from "../../lib/configs/globalConfigs.js"; -import { initNewEnvConfig } from "../../lib/configs/project/env.js"; +import { initNewEnvConfig } from "../../lib/configs/project/env/env.js"; import { initFluenceConfig } from "../../lib/configs/project/fluence.js"; import { ENV_ARG } from "../../lib/const.js"; import { ensureAquaFileWithWorkerInfo } from "../../lib/deployWorkers.js"; @@ -31,17 +30,15 @@ import { ensureValidFluenceEnv } from "../../lib/resolveFluenceEnv.js"; export default class Env extends BaseCommand { static override description = "Switch default Fluence Environment"; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; static override args = { ...ENV_ARG, }; async run(): Promise { const { args } = await initCli(this, await this.parse(Env)); - const newEnvConfig = await initNewEnvConfig(); - setEnvConfig(newEnvConfig); + const envConfig = await initNewEnvConfig(); const fluenceEnv = await ensureValidFluenceEnv(args.ENV); - newEnvConfig.fluenceEnv = fluenceEnv; - await newEnvConfig.$commit(); + envConfig.fluenceEnv = fluenceEnv; + await envConfig.$commit(); if ((await initFluenceConfig()) !== null) { await updateRelaysJSON(); diff --git a/packages/cli/package/src/commands/default/peers.ts b/packages/cli/package/src/commands/default/peers.ts index 07b97c760..77c83ef60 100644 --- a/packages/cli/package/src/commands/default/peers.ts +++ b/packages/cli/package/src/commands/default/peers.ts @@ -25,7 +25,6 @@ import { resolveDefaultRelays } from "../../lib/multiaddres.js"; export default class Peers extends BaseCommand { static override description = "Print default Fluence network peer addresses"; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; static override args = { ...ENV_ARG, }; diff --git a/packages/cli/package/src/commands/dep/install.ts b/packages/cli/package/src/commands/dep/install.ts index 595ee48e0..1501bd082 100644 --- a/packages/cli/package/src/commands/dep/install.ts +++ b/packages/cli/package/src/commands/dep/install.ts @@ -31,7 +31,6 @@ export default class Install extends BaseCommand { static override description = "Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)"; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; static override args = { [PACKAGE_NAME_AND_VERSION_ARG_NAME]: Args.string({ description: diff --git a/packages/cli/package/src/commands/dep/reset.ts b/packages/cli/package/src/commands/dep/reset.ts index 95a0af710..0208aad15 100644 --- a/packages/cli/package/src/commands/dep/reset.ts +++ b/packages/cli/package/src/commands/dep/reset.ts @@ -27,7 +27,6 @@ export default class Reset extends BaseCommand { static override description = "Reset all project dependencies to recommended versions"; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; async run(): Promise { await initCli(this, await this.parse(Reset)); const fluenceConfig = await ensureFluenceProject(); diff --git a/packages/cli/package/src/commands/dep/uninstall.ts b/packages/cli/package/src/commands/dep/uninstall.ts index 765b163c9..21d975d7b 100644 --- a/packages/cli/package/src/commands/dep/uninstall.ts +++ b/packages/cli/package/src/commands/dep/uninstall.ts @@ -28,7 +28,6 @@ export default class Install extends BaseCommand { static override description = "Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)"; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; static override args = { [PACKAGE_NAME]: Args.string({ description: `Aqua dependency name`, diff --git a/packages/cli/package/src/commands/key/new.ts b/packages/cli/package/src/commands/key/new.ts index 8c92944c1..3f2005b27 100644 --- a/packages/cli/package/src/commands/key/new.ts +++ b/packages/cli/package/src/commands/key/new.ts @@ -22,7 +22,10 @@ import { PROJECT_SECRETS_FULL_CONFIG_FILE_NAME, USER_SECRETS_CONFIG_FULL_FILE_NAME, } from "../../lib/const.js"; -import { createSecretKey } from "../../lib/keyPairs.js"; +import { + createSecretKey, + resolveUserOrProjectConfig, +} from "../../lib/keyPairs.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class New extends BaseCommand { @@ -46,6 +49,11 @@ export default class New extends BaseCommand { }; async run(): Promise { const { args, flags } = await initCli(this, await this.parse(New)); - await createSecretKey({ isUser: flags.user, name: args.name }); + + await createSecretKey({ + isUser: flags.user, + name: args.name, + userOrProjectConfig: await resolveUserOrProjectConfig(flags.user), + }); } } diff --git a/packages/cli/package/src/commands/local/init.ts b/packages/cli/package/src/commands/local/init.ts index c5f0c94a6..aca654a3c 100644 --- a/packages/cli/package/src/commands/local/init.ts +++ b/packages/cli/package/src/commands/local/init.ts @@ -25,7 +25,7 @@ import { initNewReadonlyDockerComposeConfig, initReadonlyDockerComposeConfig, } from "../../lib/configs/project/dockerCompose.js"; -import { initNewReadonlyProviderConfig } from "../../lib/configs/project/provider.js"; +import { initNewProviderConfig } from "../../lib/configs/project/provider/provider.js"; import { DOCKER_COMPOSE_FULL_FILE_NAME, PROVIDER_CONFIG_FULL_FILE_NAME, @@ -42,7 +42,7 @@ export default class Init extends BaseCommand { }; async run(): Promise { await initCli(this, await this.parse(Init)); - await initNewReadonlyProviderConfig(); + await initNewProviderConfig(); const existingDockerCompose = await initReadonlyDockerComposeConfig(); if (existingDockerCompose !== null) { diff --git a/packages/cli/package/src/commands/local/up.ts b/packages/cli/package/src/commands/local/up.ts index c7c9a8bcd..121241dd8 100644 --- a/packages/cli/package/src/commands/local/up.ts +++ b/packages/cli/package/src/commands/local/up.ts @@ -28,12 +28,11 @@ import { distributeToNox } from "../../lib/chain/distributeToNox.js"; import { createOffers } from "../../lib/chain/offer/offer.js"; import { registerProvider } from "../../lib/chain/providerInfo.js"; import { setChainFlags } from "../../lib/chainFlags.js"; -import { setEnvConfig } from "../../lib/configs/globalConfigs.js"; import { initNewReadonlyDockerComposeConfig, dockerComposeDirPath, } from "../../lib/configs/project/dockerCompose.js"; -import { initNewEnvConfig } from "../../lib/configs/project/env.js"; +import { initNewEnvConfig } from "../../lib/configs/project/env/env.js"; import { initFluenceConfig } from "../../lib/configs/project/fluence.js"; import { initNewWorkersConfig } from "../../lib/configs/project/workers.js"; import { @@ -50,7 +49,6 @@ import { } from "../../lib/const.js"; import { ensureAquaFileWithWorkerInfo } from "../../lib/deployWorkers.js"; import { dockerCompose } from "../../lib/dockerCompose.js"; -import { stringifyUnknown } from "../../lib/helpers/utils.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class Up extends BaseCommand { @@ -97,18 +95,9 @@ export default class Up extends BaseCommand { async run(): Promise { const env: FluenceEnv = "local"; - - try { - const envConfig = await initNewEnvConfig(env); - envConfig.fluenceEnv = env; - await envConfig.$commit(); - setEnvConfig(envConfig); - } catch (e) { - this.error( - `Make sure to init fluence project first. Error: ${stringifyUnknown(e)}`, - ); - } - + const envConfig = await initNewEnvConfig(env); + envConfig.fluenceEnv = env; + await envConfig.$commit(); const { flags } = await initCli(this, await this.parse(Up)); setChainFlags({ @@ -180,7 +169,7 @@ export default class Up extends BaseCommand { await distributeToNox({ ...flags, ...allOffers, amount: "10" }); await registerProvider(); await createOffers({ force: true, ...allOffers }); - await createCommitments({ ...flags, ...allOffers, env }); + await createCommitments({ ...flags, ...allOffers }); await depositCollateral(allOffers); } } diff --git a/packages/cli/package/src/commands/provider/gen.ts b/packages/cli/package/src/commands/provider/gen.ts index a63387185..d259b1fce 100644 --- a/packages/cli/package/src/commands/provider/gen.ts +++ b/packages/cli/package/src/commands/provider/gen.ts @@ -24,7 +24,7 @@ import { Flags } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { withdrawFromNox } from "../../lib/chain/distributeToNox.js"; import { commandObj } from "../../lib/commandObj.js"; -import { ensureComputerPeerConfigs } from "../../lib/configs/project/provider.js"; +import { ensureComputerPeerConfigs } from "../../lib/configs/project/provider/provider.js"; import { CHAIN_FLAGS, PROVIDER_CONFIG_FULL_FILE_NAME, diff --git a/packages/cli/package/src/commands/provider/info.ts b/packages/cli/package/src/commands/provider/info.ts index 1787c45da..b595ffc52 100644 --- a/packages/cli/package/src/commands/provider/info.ts +++ b/packages/cli/package/src/commands/provider/info.ts @@ -21,7 +21,7 @@ import { BaseCommand } from "../../baseCommand.js"; import { jsonStringify } from "../../common.js"; import { getProviderInfo } from "../../lib/chain/providerInfo.js"; import { commandObj } from "../../lib/commandObj.js"; -import { initNewProviderArtifactsConfig } from "../../lib/configs/project/providerArtifacts.js"; +import { initNewProviderArtifactsConfig } from "../../lib/configs/project/providerArtifacts/providerArtifacts.js"; import { NOX_NAMES_FLAG, CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/init.ts b/packages/cli/package/src/commands/provider/init.ts index ee69afc3b..1838f54d3 100644 --- a/packages/cli/package/src/commands/provider/init.ts +++ b/packages/cli/package/src/commands/provider/init.ts @@ -21,9 +21,9 @@ import { Flags } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; import { - initNewReadonlyProviderConfig, - initReadonlyProviderConfig, -} from "../../lib/configs/project/provider.js"; + initNewProviderConfig, + initProviderConfig, +} from "../../lib/configs/project/provider/provider.js"; import { CHAIN_FLAGS, NOXES_FLAG, @@ -45,7 +45,7 @@ export default class Init extends BaseCommand { async run(): Promise { const { flags } = await initCli(this, await this.parse(Init)); - let providerConfig = await initReadonlyProviderConfig(); + let providerConfig = await initProviderConfig(); if (providerConfig !== null) { return commandObj.error( @@ -55,7 +55,7 @@ export default class Init extends BaseCommand { ); } - providerConfig = await initNewReadonlyProviderConfig(flags); + providerConfig = await initNewProviderConfig(flags); commandObj.logToStderr( `Provider config is at ${color.yellow(providerConfig.$getPath())}`, diff --git a/packages/cli/package/src/commands/service/remove.ts b/packages/cli/package/src/commands/service/remove.ts index 0571a86e7..4e259a13b 100644 --- a/packages/cli/package/src/commands/service/remove.ts +++ b/packages/cli/package/src/commands/service/remove.ts @@ -39,7 +39,6 @@ const NAME_OR_PATH_OR_URL = "NAME | PATH | URL"; export default class Remove extends BaseCommand { static override description = `Remove service from ${FLUENCE_CONFIG_FULL_FILE_NAME} services property and from all of the workers`; static override examples = ["<%= config.bin %> <%= command.id %>"]; - static override flags = {}; static override args = { [NAME_OR_PATH_OR_URL]: Args.string({ description: `Service name from ${FLUENCE_CONFIG_FULL_FILE_NAME}, path to a service or url to .tar.gz archive`, diff --git a/packages/cli/package/src/genConfigDocs.ts b/packages/cli/package/src/genConfigDocs.ts index 43709ad5a..1458ae82a 100644 --- a/packages/cli/package/src/genConfigDocs.ts +++ b/packages/cli/package/src/genConfigDocs.ts @@ -20,24 +20,25 @@ import { writeFile, mkdir, readFile } from "node:fs/promises"; import { join } from "node:path"; import { jsonStringify } from "./common.js"; -import { dockerComposeSchema } from "./lib/configs/project/dockerCompose.js"; -import { envSchema } from "./lib/configs/project/env.js"; +import { getLatestConfigOptions } from "./lib/configs/initConfigNew.js"; +import { addTitleDescriptionAndVersionToSchemas } from "./lib/configs/initConfigNew.js"; +import { options as envOptions } from "./lib/configs/project/env/env.js"; import { fluenceSchema } from "./lib/configs/project/fluence.js"; import { moduleSchema } from "./lib/configs/project/module.js"; -import { providerSchema } from "./lib/configs/project/provider.js"; -import { providerArtifactsSchema } from "./lib/configs/project/providerArtifacts.js"; -import { providerSecretsSchema } from "./lib/configs/project/providerSecrets.js"; +import { options as providerOptions } from "./lib/configs/project/provider/provider.js"; +import { options as providerArtifactsOptions } from "./lib/configs/project/providerArtifacts/providerArtifacts.js"; +import { options as providerSecretsOptions } from "./lib/configs/project/providerSecrets/providerSecrets.js"; import { serviceSchema } from "./lib/configs/project/service.js"; import { spellSchema } from "./lib/configs/project/spell.js"; import { workersSchema } from "./lib/configs/project/workers.js"; -import { userConfigSchema } from "./lib/configs/user/config.js"; +import { options as userConfigOptions } from "./lib/configs/user/config/config.js"; import { FLUENCE_CONFIG_FILE_NAME, JSON_EXT, MODULE_CONFIG_FILE_NAME, SCHEMAS_DIR_NAME, SERVICE_CONFIG_FILE_NAME, - GLOBAL_CONFIG_FILE_NAME, + USER_CONFIG_FILE_NAME, WORKERS_CONFIG_FILE_NAME, SPELL_CONFIG_FILE_NAME, FS_OPTIONS, @@ -45,7 +46,6 @@ import { CLI_NAME_FULL, PROVIDER_CONFIG_FILE_NAME, ENV_CONFIG_FILE_NAME, - DOCKER_COMPOSE_FILE_NAME, PROVIDER_SECRETS_CONFIG_FILE_NAME, PROVIDER_ARTIFACTS_CONFIG_FILE_NAME, } from "./lib/const.js"; @@ -57,16 +57,25 @@ const DOCS_COMMANDS_PATH = join("docs", "commands", "README.md"); const configsInfo = Object.entries({ [FLUENCE_CONFIG_FILE_NAME]: fluenceSchema, - [PROVIDER_CONFIG_FILE_NAME]: providerSchema, - [PROVIDER_SECRETS_CONFIG_FILE_NAME]: providerSecretsSchema, + [PROVIDER_CONFIG_FILE_NAME]: getLatestConfigOptions( + await addTitleDescriptionAndVersionToSchemas(providerOptions), + ).schema, + [PROVIDER_SECRETS_CONFIG_FILE_NAME]: getLatestConfigOptions( + await addTitleDescriptionAndVersionToSchemas(providerSecretsOptions), + ).schema, [MODULE_CONFIG_FILE_NAME]: moduleSchema, [SERVICE_CONFIG_FILE_NAME]: serviceSchema, [SPELL_CONFIG_FILE_NAME]: spellSchema, [WORKERS_CONFIG_FILE_NAME]: workersSchema, - [GLOBAL_CONFIG_FILE_NAME]: userConfigSchema, - [ENV_CONFIG_FILE_NAME]: envSchema, - [DOCKER_COMPOSE_FILE_NAME]: dockerComposeSchema, - [PROVIDER_ARTIFACTS_CONFIG_FILE_NAME]: providerArtifactsSchema, + [USER_CONFIG_FILE_NAME]: getLatestConfigOptions( + await addTitleDescriptionAndVersionToSchemas(userConfigOptions), + ).schema, + [ENV_CONFIG_FILE_NAME]: getLatestConfigOptions( + await addTitleDescriptionAndVersionToSchemas(envOptions), + ).schema, + [PROVIDER_ARTIFACTS_CONFIG_FILE_NAME]: getLatestConfigOptions( + await addTitleDescriptionAndVersionToSchemas(providerArtifactsOptions), + ).schema, }).map(([filename, schema]) => { return { schemaPath: join(SCHEMAS_DIR_NAME, `${filename}.schema.${JSON_EXT}`), diff --git a/packages/cli/package/src/lib/chain/chainConfig.ts b/packages/cli/package/src/lib/chain/chainConfig.ts index 09ee84d7b..d38b3d66b 100644 --- a/packages/cli/package/src/lib/chain/chainConfig.ts +++ b/packages/cli/package/src/lib/chain/chainConfig.ts @@ -18,7 +18,7 @@ import capitalize from "lodash-es/capitalize.js"; import { commandObj } from "../commandObj.js"; -import { envConfig } from "../configs/globalConfigs.js"; +import { initEnvConfig } from "../configs/project/env/env.js"; import { dbg } from "../dbg.js"; import { ensureChainEnv } from "../ensureChainNetwork.js"; import { numToStr } from "../helpers/typesafeStringify.js"; @@ -31,6 +31,7 @@ export async function getChainId() { const chainEnv = await ensureChainEnv(); const { CHAIN_IDS } = await import("@fluencelabs/deal-ts-clients"); let chainId: number = CHAIN_IDS[chainEnv]; + const envConfig = await initEnvConfig(); if (envConfig?.chainId !== undefined) { commandObj.logToStderr( @@ -56,6 +57,7 @@ export async function getRpcUrl() { const chainEnv = await ensureChainEnv(); const { RPC_URLS } = await import("@fluencelabs/deal-ts-clients"); let rpcUrl: string = RPC_URLS[chainEnv]; + const envConfig = await initEnvConfig(); if (envConfig?.rpcUrl !== undefined) { commandObj.logToStderr( @@ -99,6 +101,7 @@ export async function getBlockScoutUrl() { const { BLOCK_SCOUT_URLS } = await import("@fluencelabs/deal-ts-clients"); let blockScoutUrl: string = BLOCK_SCOUT_URLS[chainEnv]; + const envConfig = await initEnvConfig(); if (envConfig?.blockScoutUrl !== undefined) { commandObj.logToStderr( @@ -132,6 +135,7 @@ export async function getSubgraphUrl() { const chainEnv = await ensureChainEnv(); const { SUBGRAPH_URLS } = await import("@fluencelabs/deal-ts-clients"); let subgraphUrl: string = SUBGRAPH_URLS[chainEnv]; + const envConfig = await initEnvConfig(); if (envConfig?.subgraphUrl !== undefined) { commandObj.logToStderr( diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index d2b132a99..02d4e39ea 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -24,7 +24,7 @@ import { yamlDiffPatch } from "yaml-diff-patch"; import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; -import { initReadonlyProviderConfig } from "../configs/project/provider.js"; +import { initProviderConfig } from "../configs/project/provider/provider.js"; import { CLI_NAME, NOX_NAMES_FLAG_NAME, @@ -190,7 +190,7 @@ export async function getCommitments( if ( flags[NOX_NAMES_FLAG_NAME] === undefined && - (await initReadonlyProviderConfig()) === null + (await initProviderConfig()) === null ) { return commaSepStrToArr( await input({ @@ -205,7 +205,6 @@ export async function getCommitments( } export async function createCommitments(flags: { - env: string | undefined; [NOX_NAMES_FLAG_NAME]?: string | undefined; [OFFER_FLAG_NAME]?: string | undefined; }) { diff --git a/packages/cli/package/src/lib/chain/conversions.ts b/packages/cli/package/src/lib/chain/conversions.ts index caf9b7867..cda3b9451 100644 --- a/packages/cli/package/src/lib/chain/conversions.ts +++ b/packages/cli/package/src/lib/chain/conversions.ts @@ -23,7 +23,6 @@ const BASE_58_PREFIX = "z"; export async function peerIdBase58ToUint8Array(peerIdBase58: string) { const [{ digest }, { base58btc }] = await Promise.all([ import("multiformats"), - import("multiformats/bases/base58"), ]); diff --git a/packages/cli/package/src/lib/chain/offer/offer.ts b/packages/cli/package/src/lib/chain/offer/offer.ts index 494227cc1..87a474f51 100644 --- a/packages/cli/package/src/lib/chain/offer/offer.ts +++ b/packages/cli/package/src/lib/chain/offer/offer.ts @@ -26,11 +26,11 @@ import { commandObj } from "../../commandObj.js"; import { ensureComputerPeerConfigs, ensureReadonlyProviderConfig, -} from "../../configs/project/provider.js"; +} from "../../configs/project/provider/provider.js"; import { initNewProviderArtifactsConfig, - initReadonlyProviderArtifactsConfig, -} from "../../configs/project/providerArtifacts.js"; + initProviderArtifactsConfig, +} from "../../configs/project/providerArtifacts/providerArtifacts.js"; import { ALL_FLAG_VALUE, CLI_NAME, @@ -658,7 +658,7 @@ export type EnsureOfferConfig = Awaited< async function ensureOfferConfigs() { const providerConfig = await ensureReadonlyProviderConfig(); - const providerArtifactsConfig = await initReadonlyProviderArtifactsConfig(); + const providerArtifactsConfig = await initProviderArtifactsConfig(); const { randomBytes } = await import("ethers"); const fluenceEnv = await ensureFluenceEnv(); @@ -754,7 +754,7 @@ export async function resolveCreatedOffers(flags: OfferArtifactsArgs) { }); } - const providerArtifactsConfig = await initReadonlyProviderArtifactsConfig(); + const providerArtifactsConfig = await initProviderArtifactsConfig(); if (providerArtifactsConfig === null) { return commandObj.error( diff --git a/packages/cli/package/src/lib/chain/offer/updateOffers.ts b/packages/cli/package/src/lib/chain/offer/updateOffers.ts index 2254047d8..f88c1b47e 100644 --- a/packages/cli/package/src/lib/chain/offer/updateOffers.ts +++ b/packages/cli/package/src/lib/chain/offer/updateOffers.ts @@ -20,7 +20,7 @@ import { color } from "@oclif/color"; import omit from "lodash-es/omit.js"; import { commandObj } from "../../commandObj.js"; -import { initNewProviderArtifactsConfig } from "../../configs/project/providerArtifacts.js"; +import { initNewProviderArtifactsConfig } from "../../configs/project/providerArtifacts/providerArtifacts.js"; import { CLI_NAME, PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, diff --git a/packages/cli/package/src/lib/chain/providerInfo.ts b/packages/cli/package/src/lib/chain/providerInfo.ts index 1dfa1ef5c..b5bd4c0fc 100644 --- a/packages/cli/package/src/lib/chain/providerInfo.ts +++ b/packages/cli/package/src/lib/chain/providerInfo.ts @@ -16,7 +16,7 @@ */ import { commandObj } from "../commandObj.js"; -import { ensureReadonlyProviderConfig } from "../configs/project/provider.js"; +import { ensureReadonlyProviderConfig } from "../configs/project/provider/provider.js"; import { CLI_NAME } from "../const.js"; import { getContracts, sign, getSignerAddress } from "../dealClient.js"; diff --git a/packages/cli/package/src/lib/configs/initConfig.ts b/packages/cli/package/src/lib/configs/initConfig.ts index f7b785f7b..2a38a1e62 100644 --- a/packages/cli/package/src/lib/configs/initConfig.ts +++ b/packages/cli/package/src/lib/configs/initConfig.ts @@ -38,8 +38,6 @@ import { removeProperties } from "../helpers/utils.js"; import type { ValidationResult } from "../helpers/validations.js"; import type { Mutable } from "../typeHelpers.js"; -import { userConfig } from "./globalConfigs.js"; - type EnsureSchemaArg = { name: string; configDirPath: string; @@ -205,7 +203,7 @@ export type Migrations = Array< (config: Config) => Config | Promise >; export type GetDefaultConfig = () => string | Promise; -type GetPath = () => string | Promise; +export type GetPath = () => string | Promise; export type ConfigValidateFunction = ( config: LatestConfig, @@ -398,16 +396,11 @@ export function getReadonlyConfigInitFunction< const defConf = await getDefaultConfig(); - configString = - // this is basically the only place where userConfig is undefined until it's initialized in initCli - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - (userConfig?.docsInConfigs ?? false) - ? `${schemaPathComment}\n\n${documentationLinkComment}\n${defConf}` - : yamlDiffPatch( - `${schemaPathComment}\n${description}\n\n${documentationLinkComment}\n`, - {}, - parse(defConf), - ); + configString = yamlDiffPatch( + `${schemaPathComment}\n${description}\n\n${documentationLinkComment}\n`, + {}, + parse(defConf), + ); await saveConfig(configPath, configString); } @@ -520,7 +513,7 @@ export function getReadonlyConfigInitFunction< const initializedConfigs = new Map>(); -function formatConfig(configString: string) { +export function formatConfig(configString: string) { const formattedConfig = configString .trim() .split("\n") diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts new file mode 100644 index 000000000..12489e683 --- /dev/null +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -0,0 +1,502 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import assert from "node:assert"; +import { readFile, mkdir, writeFile } from "node:fs/promises"; +import { basename, dirname, join, relative } from "node:path"; + +import { color } from "@oclif/color"; +import type { JSONSchemaType } from "ajv"; + +import { jsonStringify } from "../../common.js"; +import { validationErrorToString, getAjv } from "../ajvInstance.js"; +import { commandObj } from "../commandObj.js"; +import { + FS_OPTIONS, + YAML_EXT, + YML_EXT, + DOCKER_COMPOSE_FILE_NAME, + CLI_NAME_FULL, + SCHEMAS_DIR_NAME, +} from "../const.js"; +import { numToStr } from "../helpers/typesafeStringify.js"; +import { removeProperties } from "../helpers/utils.js"; + +import { formatConfig, type GetPath } from "./initConfig.js"; +import type { + InitializedConfig, + InitConfigOptions, + GetLatestConfig, + GetDefaultConfig, + OptionsTuple, + ConfigOptionsWithoutMigrate, + ConfigOptions, +} from "./initConfigNewTypes.js"; + +const initializedConfigs = new Map>(); + +export function getConfigInitFunction< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +>( + options: InitConfigOptions, + getDefaultConfig?: never, +): () => Promise +> | null>; +export function getConfigInitFunction< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +>( + options: InitConfigOptions, + getDefaultConfig: GetDefaultConfig< + GetLatestConfig + >, +): () => Promise< + InitializedConfig> +>; + +export function getConfigInitFunction< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +>( + { + options, + getSchemaDirPath, + getConfigPath, + description, + }: InitConfigOptions, + getDefaultConfig?: GetDefaultConfig< + GetLatestConfig + >, +): () => Promise +> | null> { + type LatestConfig = GetLatestConfig; + + return async () => { + const expectedConfigPath = await getConfigPath(); + + const previouslyInitializedConfig = + initializedConfigs.get(expectedConfigPath); + + if (previouslyInitializedConfig !== undefined) { + // It's safe to assert here because we can be sure that previouslyInitializedConfig has the same type + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return previouslyInitializedConfig as InitializedConfig; + } + + if ( + !expectedConfigPath.endsWith(YAML_EXT) && + !expectedConfigPath.endsWith(YML_EXT) + ) { + commandObj.error( + `Invalid config path ${color.yellow( + expectedConfigPath, + )}. Config path must end with ${color.yellow(YAML_EXT)} or ${color.yellow( + YML_EXT, + )}`, + ); + } + + await addTitleDescriptionAndVersionToSchemas({ + options, + description, + getConfigPath, + }); + + const getLatestConfigRes = await getLatestConfig({ + options, + expectedConfigPath, + getDefaultConfig, + getSchemaDirPath, + }); + + if (getLatestConfigRes === null) { + return null; + } + + const { yamlDiffPatch } = await import("yaml-diff-patch"); + + const { + latestConfig, + latestConfigString, + actualConfigPath, + validateLatestConfig, + } = getLatestConfigRes; + + let prevConfigString = latestConfigString; + let prevConfig = latestConfig; + + const initializedConfig: InitializedConfig = { + ...latestConfig, + $getPath(): string { + return actualConfigPath; + }, + async $commit(): Promise { + const config = removeProperties(this, ([, v]) => { + return typeof v === "function"; + }); + + prevConfigString = await saveConfig( + actualConfigPath, + yamlDiffPatch(prevConfigString, prevConfig, config), + prevConfigString, + ); + + prevConfig = await validateLatestConfig(config); + }, + }; + + initializedConfigs.set(expectedConfigPath, initializedConfig); + return initializedConfig; + }; +} + +export async function addTitleDescriptionAndVersionToSchemas< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +>({ + options, + description, + getConfigPath, +}: InitConfigOptions) { + const expectedConfigPath = await getConfigPath(); + const title = `${getConfigName(expectedConfigPath)}.${YAML_EXT}`; + + options.forEach(({ schema }, version) => { + schema.title = title; + schema.description = description; + schema.properties.version = { type: "integer", const: version }; + + if (schema.required?.includes("version") !== true) { + schema.required = [...(schema.required ?? []), "version"]; + } + }); + + return options; +} + +export function getLatestConfigOptions< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +>(arr: OptionsTuple) { + // The latest config is always the last one in the array + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return arr[arr.length - 1] as unknown as ConfigOptionsWithoutMigrate< + GetLatestConfig + >; +} + +function getConfigValidator({ + actualConfigPath, + configOptions: { schema, validate }, +}: { + actualConfigPath: string; + configOptions: ConfigOptionsWithoutMigrate; +}) { + return async function validateConfig(config: unknown): Promise { + const validateConfigSchema = getAjv().compile(schema); + + if (!validateConfigSchema(config)) { + return commandObj.error( + `Invalid config at ${color.yellow( + actualConfigPath, + )}. ${await validationErrorToString(validateConfigSchema.errors)}`, + ); + } + + const validity = + validate === undefined ? true : await validate(config, actualConfigPath); + + if (typeof validity === "string") { + return commandObj.error( + `Invalid config at ${color.yellow(actualConfigPath)}. Errors:\n${validity}`, + ); + } + + return config; + }; +} + +async function getLatestConfig({ + options, + expectedConfigPath, + getDefaultConfig, + getSchemaDirPath, +}: { + options: OptionsTuple; + expectedConfigPath: string; + getDefaultConfig: + | GetDefaultConfig> + | undefined; + getSchemaDirPath: GetPath | undefined; +}): Promise<{ + latestConfig: GetLatestConfig; + latestConfigString: string; + actualConfigPath: string; + validateLatestConfig: ReturnType< + typeof getConfigValidator< + GetLatestConfig + > + >; +} | null> { + type LatestConfig = GetLatestConfig; + + const [{ parse }, { yamlDiffPatch }] = await Promise.all([ + import("yaml"), + import("yaml-diff-patch"), + ]); + + const configName = getConfigName(expectedConfigPath); + let configString: string; + let actualConfigPath = expectedConfigPath; + + try { + // try reading config file + // if it fails, try replacing .yaml with .yml or vice versa and read again + // this way we can support both .yaml and .yml extensions interchangeably + try { + configString = await readFile(actualConfigPath, FS_OPTIONS); + } catch { + const endsWithYaml = actualConfigPath.endsWith(YAML_EXT); + + // try reading again by replacing .yaml with .yml or vice versa + const newConfigPath = `${actualConfigPath.slice( + 0, + -(endsWithYaml ? YAML_EXT : YML_EXT).length, + )}${endsWithYaml ? YML_EXT : YAML_EXT}`; + + configString = await readFile(newConfigPath, FS_OPTIONS); + actualConfigPath = newConfigPath; + } + } catch { + if (getDefaultConfig === undefined) { + return null; + } + + const latestConfigOptions = getLatestConfigOptions(options); + const { description } = latestConfigOptions.schema; + + assert( + description !== undefined, + `Unreachable. addVersionTitleAndDescriptionToConfigOptions function must ensure that description is defined`, + ); + + configString = yamlDiffPatch( + `# ${description}\n\n`, + {}, + { + ...(configName === DOCKER_COMPOSE_FILE_NAME + ? {} + : { version: options.length - 1 }), + ...(await getDefaultConfig()), + }, + ); + } + + const currentConfigUnknown: unknown = parse(configString); + + if (configName === DOCKER_COMPOSE_FILE_NAME) { + await saveConfig(actualConfigPath, configString); + + return { + // CLI will not validate docker-compose at all to not cause additional problems for the users + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + latestConfig: currentConfigUnknown as LatestConfig, + latestConfigString: configString, + actualConfigPath, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + validateLatestConfig: (() => { + return Promise.resolve(currentConfigUnknown); + }) as ReturnType>, + }; + } + + if ( + typeof currentConfigUnknown !== "object" || + currentConfigUnknown === null + ) { + return commandObj.error( + `Invalid config at ${color.yellow(actualConfigPath)}. Expected to be an object`, + ); + } + + let currentConfig = currentConfigUnknown; + let prevConfig = currentConfig; + + if (!validateConfigHasVersion(currentConfig)) { + return commandObj.error( + `Invalid config at ${color.yellow( + actualConfigPath, + )}. Expected to have an integer ${color.yellow("version")} property`, + ); + } + + const { version: initialVersion } = currentConfig; + const configDirName = dirname(actualConfigPath); + + const schemaDir = join( + getSchemaDirPath === undefined ? configDirName : await getSchemaDirPath(), + SCHEMAS_DIR_NAME, + ); + + await mkdir(schemaDir, { recursive: true }); + const schemaPath = join(schemaDir, `${getConfigName(actualConfigPath)}.json`); + const schemaPathComment = `${SCHEMA_PATH_COMMENT_START}${relative(configDirName, schemaPath)}`; + + let currentConfigString = configString.startsWith(SCHEMA_PATH_COMMENT_START) + ? [schemaPathComment, ...configString.split("\n").slice(1)].join("\n") + : `${schemaPathComment}\n${configString}`; + + let validateCurrentConfig: undefined | ((config: object) => Promise) = + undefined; + + // the exact type of configs is irrelevant further + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const relevantOptions = options.slice(initialVersion) as ConfigOptions< + object, + object + >[]; + + if (relevantOptions.length === 0) { + return commandObj.error( + `Invalid config at ${color.yellow( + actualConfigPath, + )}. Unknown ${color.yellow(`version: ${numToStr(initialVersion)}`)}. Consider updating ${CLI_NAME_FULL} to the latest version`, + ); + } + + for (const [indexString, configOptions] of Object.entries(relevantOptions)) { + const index = Number(indexString); + + // No need to migrate for the current config version + if (index !== 0) { + prevConfig = currentConfig; + const migrated = await configOptions.migrate(prevConfig); + currentConfig = { ...migrated, version: initialVersion + index }; + } + + await updateSchema(configOptions, schemaPath); + + currentConfigString = await saveConfig( + actualConfigPath, + yamlDiffPatch(currentConfigString, prevConfig, currentConfig), + index === 0 ? configString : currentConfigString, + ); + + validateCurrentConfig = getConfigValidator({ + configOptions, + actualConfigPath, + }); + + currentConfig = await validateCurrentConfig(currentConfig); + } + + return { + actualConfigPath, + latestConfigString: currentConfigString, + // The latest config here and below is ensured by the fact that by this point we have already migrated the config to the latest version + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + latestConfig: currentConfig as LatestConfig, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + validateLatestConfig: validateCurrentConfig as ReturnType< + typeof getConfigValidator + >, + }; +} + +const objWithVersionSchema: JSONSchemaType<{ version: number }> = { + type: "object", + properties: { version: { type: "integer" } }, + required: ["version"], +}; + +const validateConfigHasVersion = getAjv().compile(objWithVersionSchema); +const SCHEMA_PATH_COMMENT_START = "# yaml-language-server: $schema="; + +async function updateSchema( + configOptions: ConfigOptionsWithoutMigrate, + schemaPath: string, +) { + const schemaString = `${jsonStringify(configOptions.schema)}\n`; + + try { + const actualSchemaString = await readFile(schemaPath, FS_OPTIONS); + assert(actualSchemaString === schemaString); + } catch { + await writeFile(schemaPath, schemaString, FS_OPTIONS); + } +} + +async function saveConfig( + configPath: string, + configString: string, + prevConfigString?: string, +): Promise { + if (prevConfigString === configString) { + return configString; + } + + const newConfigString = formatConfig(configString); + await writeFile(configPath, newConfigString, FS_OPTIONS); + return newConfigString; +} + +function getConfigName(configPath: string) { + return basename(configPath).replace(/\.(yml|yaml)$/, ""); +} diff --git a/packages/cli/package/src/lib/configs/initConfigNewTypes.ts b/packages/cli/package/src/lib/configs/initConfigNewTypes.ts new file mode 100644 index 000000000..32c5a0149 --- /dev/null +++ b/packages/cli/package/src/lib/configs/initConfigNewTypes.ts @@ -0,0 +1,170 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import type { ValidationResult } from "../helpers/validations.js"; + +import type { GetPath } from "./initConfig.js"; + +export type InitializedConfig = LatestConfig & { + $getPath(): string; + $commit(): Promise; +}; + +export type GetDefaultConfig = () => + | LatestConfig + | Promise; + +export type ConfigOptionsWithoutMigrate = { + schema: JSONSchemaType & { + title?: string; + description?: string; + properties: { version?: unknown }; + required?: string[]; + }; + validate?: ( + config: Config, + configPath: string, + ) => ValidationResult | Promise; +}; + +export type ConfigOptions = PrevConfig extends undefined + ? ConfigOptionsWithoutMigrate + : ConfigOptionsWithoutMigrate & { + migrate: (prevConfig: PrevConfig) => Config | Promise; + }; + +export type GetLatestConfig = + C9 extends undefined + ? C8 extends undefined + ? C7 extends undefined + ? C6 extends undefined + ? C5 extends undefined + ? C4 extends undefined + ? C3 extends undefined + ? C2 extends undefined + ? C1 extends undefined + ? C0 + : C1 + : C2 + : C3 + : C4 + : C5 + : C6 + : C7 + : C8 + : C9; + +export type OptionsTuple = + C9 extends undefined + ? C8 extends undefined + ? C7 extends undefined + ? C6 extends undefined + ? C5 extends undefined + ? C4 extends undefined + ? C3 extends undefined + ? C2 extends undefined + ? C1 extends undefined + ? [ConfigOptions] + : [ConfigOptions, ConfigOptions] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ] + : [ + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ConfigOptions, + ]; + +export type InitConfigOptions< + C0, + C1 = undefined, + C2 = undefined, + C3 = undefined, + C4 = undefined, + C5 = undefined, + C6 = undefined, + C7 = undefined, + C8 = undefined, + C9 = undefined, +> = { + description: string; + options: OptionsTuple; + getConfigPath: GetPath; + getSchemaDirPath?: GetPath; +}; diff --git a/packages/cli/package/src/lib/configs/project/dockerCompose.ts b/packages/cli/package/src/lib/configs/project/dockerCompose.ts index 32a3e312b..3ed894c6c 100644 --- a/packages/cli/package/src/lib/configs/project/dockerCompose.ts +++ b/packages/cli/package/src/lib/configs/project/dockerCompose.ts @@ -52,7 +52,10 @@ import { } from "../initConfig.js"; import schema from "./compose.schema.json" with { type: "json" }; -import { ensureComputerPeerConfigs, getConfigTomlName } from "./provider.js"; +import { + ensureComputerPeerConfigs, + getConfigTomlName, +} from "./provider/provider.js"; type Service = { image?: string; diff --git a/packages/cli/package/src/lib/configs/project/env.ts b/packages/cli/package/src/lib/configs/project/env.ts deleted file mode 100644 index de12dbbac..000000000 --- a/packages/cli/package/src/lib/configs/project/env.ts +++ /dev/null @@ -1,202 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import type { Deployment } from "@fluencelabs/deal-ts-clients"; -import type { JSONSchemaType } from "ajv"; - -import { CHAIN_ENV, DEFAULT_PUBLIC_FLUENCE_ENV } from "../../../common.js"; -import { ajv, validationErrorToString } from "../../ajvInstance.js"; -import { - ENV_CONFIG_FILE_NAME, - ENV_CONFIG_FULL_FILE_NAME, - FLUENCE_ENVS_OLD, - fluenceOldEnvToNewEnv, - TOP_LEVEL_SCHEMA_ID, - type FluenceEnv, - type FluenceEnvOld, -} from "../../const.js"; -import { numToStr } from "../../helpers/typesafeStringify.js"; -import { getFluenceDir } from "../../paths.js"; -import { - getConfigInitFunction, - getReadonlyConfigInitFunction, - type GetDefaultConfig, - type InitConfigOptions, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, -} from "../initConfig.js"; - -type ConfigV0 = { - fluenceEnv?: FluenceEnvOld; - version: 0; -}; - -const configSchemaV0Obj = { - type: "object", - properties: { - fluenceEnv: { - title: "Fluence environment", - description: `Fluence environment to connect to`, - type: "string", - enum: [...FLUENCE_ENVS_OLD], - nullable: true, - }, - version: { type: "integer", const: 0 }, - }, - required: ["version"], - additionalProperties: false, -} as const satisfies JSONSchemaType; - -const configSchemaV0: JSONSchemaType = configSchemaV0Obj; - -type ConfigV1 = { - fluenceEnv?: FluenceEnv; - relays?: Array; - subgraphUrl?: string; - rpcUrl?: string; - blockScoutUrl?: string; - chainId?: number; - deployment?: Partial; - version: 1; -}; - -const configSchemaV1Obj = { - type: "object", - properties: { - fluenceEnv: { - title: "Fluence environment", - description: `Fluence environment to connect to`, - type: "string", - enum: [...CHAIN_ENV], - nullable: true, - }, - relays: { - type: "array", - description: `List of custom relay multiaddresses to use when connecting to Fluence network`, - items: { type: "string" }, - minItems: 1, - nullable: true, - }, - subgraphUrl: { - type: "string", - description: `Subgraph URL to use`, - format: "uri", - nullable: true, - }, - rpcUrl: { - type: "string", - description: `RPC URL to use`, - format: "uri", - nullable: true, - }, - blockScoutUrl: { - type: "string", - description: `BlockScout URL to use`, - format: "uri", - nullable: true, - }, - chainId: { - type: "number", - description: `Chain ID to use`, - nullable: true, - }, - deployment: { - type: "object", - description: `Deployed contract address overrides`, - nullable: true, - required: [], - additionalProperties: false, - properties: { - usdc: { type: "string", nullable: true }, - multicall3: { type: "string", nullable: true }, - diamond: { type: "string", nullable: true }, - }, - }, - version: { type: "integer", const: 1 }, - }, - required: ["version"], - additionalProperties: false, -} as const satisfies JSONSchemaType; - -const latestSchemaObj = { - $id: `${TOP_LEVEL_SCHEMA_ID}/${ENV_CONFIG_FULL_FILE_NAME}`, - title: ENV_CONFIG_FULL_FILE_NAME, - description: `Defines user project preferences`, - ...configSchemaV1Obj, -}; - -const latestSchema: JSONSchemaType = latestSchemaObj; - -const validateConfigSchemaV0 = ajv.compile(configSchemaV0); - -const getDefault = (fluenceEnv: FluenceEnv | undefined): GetDefaultConfig => { - return () => { - return `# Defines project preferences -# config version -version: ${numToStr(latestSchemaObj.properties.version.const)} - -# Fluence environment to connect to -${fluenceEnv === undefined ? `# fluenceEnv: ${DEFAULT_PUBLIC_FLUENCE_ENV}` : `fluenceEnv: "${fluenceEnv}"`} -`; - }; -}; - -const migrations: Migrations = [ - async (config: Config): Promise => { - if (!validateConfigSchemaV0(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const { fluenceEnv } = config; - - return { - version: 1, - ...(fluenceEnv === undefined - ? {} - : { fluenceEnv: fluenceOldEnvToNewEnv(fluenceEnv) }), - }; - }, -]; - -type Config = ConfigV0 | ConfigV1; -type LatestConfig = ConfigV1; -export type EnvConfig = InitializedConfig; -export type EnvConfigReadonly = InitializedReadonlyConfig; - -const initConfigOptions: InitConfigOptions = { - allSchemas: [configSchemaV0, latestSchema], - latestSchema, - migrations, - name: ENV_CONFIG_FILE_NAME, - getConfigOrConfigDirPath: getFluenceDir, -}; - -export const initNewEnvConfig = (fluenceEnv?: FluenceEnv) => { - return getConfigInitFunction(initConfigOptions, getDefault(fluenceEnv))(); -}; - -export const initEnvConfig = getConfigInitFunction(initConfigOptions); - -export const initReadonlyEnvConfig = - getReadonlyConfigInitFunction(initConfigOptions); - -export const envSchema: JSONSchemaType = latestSchema; diff --git a/packages/cli/package/src/lib/configs/project/env/env.ts b/packages/cli/package/src/lib/configs/project/env/env.ts new file mode 100644 index 000000000..574b50a1b --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/env/env.ts @@ -0,0 +1,41 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { DEFAULT_PUBLIC_FLUENCE_ENV } from "../../../../common.js"; +import { type FluenceEnv } from "../../../const.js"; +import { getEnvConfigPath } from "../../../paths.js"; +import { getConfigInitFunction } from "../../initConfigNew.js"; +import { type InitConfigOptions } from "../../initConfigNewTypes.js"; + +import configOptions0, { type Config as Config0 } from "./env0.js"; +import configOptions1, { type Config as Config1 } from "./env1.js"; + +export const options: InitConfigOptions = { + description: "Defines project user's preferences", + options: [configOptions0, configOptions1], + getConfigPath: getEnvConfigPath, +}; + +export function initNewEnvConfig( + fluenceEnv: FluenceEnv = DEFAULT_PUBLIC_FLUENCE_ENV, +) { + return getConfigInitFunction(options, () => { + return { fluenceEnv }; + })(); +} + +export const initEnvConfig = getConfigInitFunction(options); diff --git a/packages/cli/package/src/lib/configs/globalConfigs.ts b/packages/cli/package/src/lib/configs/project/env/env0.ts similarity index 53% rename from packages/cli/package/src/lib/configs/globalConfigs.ts rename to packages/cli/package/src/lib/configs/project/env/env0.ts index 645fbd250..6034c37b7 100644 --- a/packages/cli/package/src/lib/configs/globalConfigs.ts +++ b/packages/cli/package/src/lib/configs/project/env/env0.ts @@ -15,17 +15,25 @@ * along with this program. If not, see . */ -import type { EnvConfig } from "./project/env.js"; -import type { UserConfig } from "./user/config.js"; +import { FLUENCE_ENVS_OLD, type FluenceEnvOld } from "../../../const.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; -export let userConfig: UserConfig; +export type Config = { + fluenceEnv?: FluenceEnvOld; +}; -export function setUserConfig(newUserConfig: UserConfig) { - userConfig = newUserConfig; -} - -export let envConfig: EnvConfig | null = null; - -export function setEnvConfig(newEnvConfig: EnvConfig) { - envConfig = newEnvConfig; -} +export default { + schema: { + type: "object", + properties: { + fluenceEnv: { + title: "Fluence environment", + description: "Fluence environment to connect to", + type: "string", + enum: [...FLUENCE_ENVS_OLD], + nullable: true, + }, + }, + additionalProperties: false, + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/env/env1.ts b/packages/cli/package/src/lib/configs/project/env/env1.ts new file mode 100644 index 000000000..4157901f3 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/env/env1.ts @@ -0,0 +1,97 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { Deployment } from "@fluencelabs/deal-ts-clients"; + +import { CHAIN_ENV } from "../../../../common.js"; +import { type FluenceEnv, fluenceOldEnvToNewEnv } from "../../../const.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import type { Config as PrevConfig } from "./env0.js"; + +export type Config = { + fluenceEnv?: FluenceEnv; + relays?: Array; + subgraphUrl?: string; + rpcUrl?: string; + blockScoutUrl?: string; + chainId?: number; + deployment?: Partial; +}; + +export default { + schema: { + type: "object", + properties: { + fluenceEnv: { + title: "Fluence environment", + description: `Fluence environment to connect to`, + type: "string", + enum: [...CHAIN_ENV], + nullable: true, + }, + relays: { + type: "array", + description: `List of custom relay multiaddresses to use when connecting to Fluence network`, + items: { type: "string" }, + minItems: 1, + nullable: true, + }, + subgraphUrl: { + type: "string", + description: `Subgraph URL to use`, + format: "uri", + nullable: true, + }, + rpcUrl: { + type: "string", + description: `RPC URL to use`, + format: "uri", + nullable: true, + }, + blockScoutUrl: { + type: "string", + description: `BlockScout URL to use`, + format: "uri", + nullable: true, + }, + chainId: { + type: "number", + description: `Chain ID to use`, + nullable: true, + }, + deployment: { + type: "object", + description: `Deployed contract address overrides`, + nullable: true, + required: [], + additionalProperties: false, + properties: { + usdc: { type: "string", nullable: true }, + multicall3: { type: "string", nullable: true }, + diamond: { type: "string", nullable: true }, + }, + }, + }, + additionalProperties: false, + }, + migrate({ fluenceEnv }) { + return fluenceEnv === undefined + ? {} + : { fluenceEnv: fluenceOldEnvToNewEnv(fluenceEnv) }; + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/fluence.ts b/packages/cli/package/src/lib/configs/project/fluence.ts index 81fb1d69c..2a5e4eabc 100644 --- a/packages/cli/package/src/lib/configs/project/fluence.ts +++ b/packages/cli/package/src/lib/configs/project/fluence.ts @@ -50,7 +50,7 @@ import { FLUENCE_CONFIG_FILE_NAME, FLUENCE_CONFIG_FULL_FILE_NAME, type FluenceEnv, - GLOBAL_CONFIG_FULL_FILE_NAME, + USER_CONFIG_FULL_FILE_NAME, IPFS_ADDR_PROPERTY, LOCAL_IPFS_ADDRESS, MARINE_BUILD_ARGS_FLAG_NAME, @@ -85,7 +85,7 @@ import { type Migrations, } from "../initConfig.js"; -import { initNewEnvConfig } from "./env.js"; +import { initNewEnvConfig } from "./env/env.js"; import { type OverridableModuleProperties, overridableModuleProperties, @@ -521,7 +521,7 @@ const configSchemaV2Obj = { AQUA_DIR_NAME, )} dir, npm dependencies from ${FLUENCE_CONFIG_FULL_FILE_NAME}, npm dependencies from user's ${join( DOT_FLUENCE_DIR_NAME, - GLOBAL_CONFIG_FULL_FILE_NAME, + USER_CONFIG_FULL_FILE_NAME, )}, npm dependencies recommended by fluence`, items: { type: "string" }, nullable: true, diff --git a/packages/cli/package/src/lib/configs/project/provider.ts b/packages/cli/package/src/lib/configs/project/provider.ts deleted file mode 100644 index 179afe9db..000000000 --- a/packages/cli/package/src/lib/configs/project/provider.ts +++ /dev/null @@ -1,2440 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { writeFile } from "fs/promises"; -import { join } from "path"; - -import { type JsonMap, parse } from "@iarna/toml"; -import { color } from "@oclif/color"; -import type { JSONSchemaType } from "ajv"; -import { isUndefined, mapValues, omitBy } from "lodash-es"; -import cloneDeep from "lodash-es/cloneDeep.js"; -import isEmpty from "lodash-es/isEmpty.js"; -import kebabCase from "lodash-es/kebabCase.js"; -import mapKeys from "lodash-es/mapKeys.js"; -import mergeWith from "lodash-es/mergeWith.js"; -import snakeCase from "lodash-es/snakeCase.js"; -import times from "lodash-es/times.js"; - -import { - jsonStringify, - CHAIN_RPC_PORT, - type ChainENV, -} from "../../../common.js"; -import { versions } from "../../../versions.js"; -import { ajv, validationErrorToString } from "../../ajvInstance.js"; -import { getChainId } from "../../chain/chainConfig.js"; -import { - ccDurationValidator, - validateAddress, - validateProtocolVersion, -} from "../../chain/chainValidators.js"; -import { commandObj, isInteractive } from "../../commandObj.js"; -import { - COMPUTE_UNIT_MEMORY_STR, - DEFAULT_OFFER_NAME, - PROVIDER_CONFIG_FILE_NAME, - TOP_LEVEL_SCHEMA_ID, - PROVIDER_CONFIG_FULL_FILE_NAME, - DEFAULT_AQUAVM_POOL_SIZE, - FS_OPTIONS, - HTTP_PORT_START, - TCP_PORT_START, - WEB_SOCKET_PORT_START, - LOCAL_IPFS_ADDRESS, - TOML_EXT, - IPFS_CONTAINER_NAME, - IPFS_PORT, - defaultNumberProperties, - DEFAULT_CC_DURATION, - DEFAULT_CC_STAKER_REWARD, - DURATION_EXAMPLE, - DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, - WS_CHAIN_URLS, - PT_SYMBOL, - DEFAULT_CURL_EFFECTOR_CID, - CHAIN_RPC_CONTAINER_NAME, - CLI_NAME, - DEFAULT_NUMBER_OF_LOCAL_NET_NOXES, - DEFAULT_VM_EFFECTOR_CID, -} from "../../const.js"; -import { resolveDeployment } from "../../dealClient.js"; -import { ensureChainEnv } from "../../ensureChainNetwork.js"; -import { type ProviderConfigArgs } from "../../generateUserProviderConfig.js"; -import { getPeerIdFromSecretKey } from "../../helpers/getPeerIdFromSecretKey.js"; -import { boolToStr, numToStr } from "../../helpers/typesafeStringify.js"; -import { splitErrorsAndResults } from "../../helpers/utils.js"; -import { - type ValidationResult, - validateCIDs, -} from "../../helpers/validations.js"; -import { validateBatchAsync } from "../../helpers/validations.js"; -import { genSecretKeyOrReturnExisting } from "../../keyPairs.js"; -import { resolveRelaysWithoutLocal } from "../../multiaddresWithoutLocal.js"; -import { - ensureFluenceConfigsDir, - getProviderConfigPath, - getFluenceDir, - ensureFluenceSecretsFilePath, - ensureFluenceCCPConfigsDir, -} from "../../paths.js"; -import { input, list } from "../../prompt.js"; -import { envConfig, setEnvConfig } from "../globalConfigs.js"; -import { - getReadonlyConfigInitFunction, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, - type ConfigValidateFunction, - getConfigInitFunction, -} from "../initConfig.js"; - -import { initNewEnvConfig } from "./env.js"; -import { initNewProviderSecretsConfig } from "./providerSecrets.js"; - -type CapacityCommitmentV0 = { - duration: string; - rewardDelegationRate: number; - delegator?: string; -}; - -const capacityCommitmentSchemaV0 = { - type: "object", - description: "Defines a capacity commitment", - required: ["duration", "rewardDelegationRate"], - additionalProperties: false, - properties: { - duration: { - type: "string", - default: DEFAULT_CC_DURATION, - description: `Duration of the commitment ${DURATION_EXAMPLE}`, - }, - delegator: { - type: "string", - description: "Delegator address", - nullable: true, - }, - rewardDelegationRate: { - type: "number", - minimum: 0, - maximum: 100, - description: "Reward delegation rate in percent", - default: DEFAULT_CC_STAKER_REWARD, - }, - }, -} as const satisfies JSONSchemaType; - -type CapacityCommitmentV1 = Omit< - CapacityCommitmentV0, - "rewardDelegationRate" -> & { - stakerReward: number; -}; - -const capacityCommitmentSchemaV1 = { - type: "object", - description: "Defines a capacity commitment", - required: ["duration", "stakerReward"], - additionalProperties: false, - properties: { - duration: { - type: "string", - default: DEFAULT_CC_DURATION, - description: `Duration of the commitment ${DURATION_EXAMPLE}`, - }, - delegator: { - type: "string", - description: "Delegator address", - nullable: true, - }, - stakerReward: { - type: "number", - minimum: 0, - maximum: 100, - description: "Staker reward in percent", - default: DEFAULT_CC_STAKER_REWARD, - }, - }, -} as const satisfies JSONSchemaType; - -export type OfferV0 = { - minPricePerWorkerEpoch: string; - computePeers: Array; - effectors?: Array; - minProtocolVersion?: number; - maxProtocolVersion?: number; -}; - -type Effector = { - wasmCID: string; - allowedBinaries?: Record; -}; - -type NoxConfigYAMLV0 = { - tcpPort?: number; - websocketPort?: number; - httpPort?: number; - aquavmPoolSize?: number; - systemServices?: { - enable?: Array; - aquaIpfs?: { - externalApiMultiaddr?: string; - localApiMultiaddr?: string; - ipfsBinaryPath?: string; - }; - decider?: { - deciderPeriodSec?: number; - workerPeriodSec?: number; - workerIpfsMultiaddr?: string; - networkApiEndpoint?: string; - networkId?: number; - startBlock?: string; - matcherAddress?: string; - walletKey?: string; - }; - }; - effectors?: Record; - rawConfig?: string; - chainConfig?: { - httpEndpoint?: string; - coreContractAddress?: string; - ccContractAddress?: string; - marketContractAddress?: string; - networkId?: number; - walletKey?: string; - }; -}; - -const NOX_IPFS_MULTIADDR = `/dns4/${IPFS_CONTAINER_NAME}/tcp/${IPFS_PORT}`; - -const effectorSchema = { - type: "object", - description: "Effector configuration", - additionalProperties: false, - properties: { - wasmCID: { - type: "string", - description: `Wasm CID of the effector`, - }, - allowedBinaries: { - type: "object", - description: `Allowed binaries`, - additionalProperties: { type: "string" }, - properties: { - curl: { type: "string" }, - }, - required: [], - nullable: true, - }, - }, - required: ["wasmCID"], -} as const satisfies JSONSchemaType; - -const noxConfigYAMLSchemaV0 = { - type: "object", - description: - "Configuration to pass to the nox compute peer. Config.toml files are generated from this config", - properties: { - tcpPort: { - nullable: true, - type: "integer", - description: `Both host and container TCP port to use. Default: for each nox a unique port is assigned starting from ${numToStr( - TCP_PORT_START, - )}`, - }, - websocketPort: { - nullable: true, - type: "integer", - description: `Both host and container WebSocket port to use. Default: for each nox a unique port is assigned starting from ${numToStr( - WEB_SOCKET_PORT_START, - )}`, - }, - httpPort: { - nullable: true, - type: "integer", - description: `Both host and container HTTP port to use. Default: for each nox a unique port is assigned starting from ${numToStr( - HTTP_PORT_START, - )}`, - }, - aquavmPoolSize: { - nullable: true, - type: "integer", - description: `Number of aquavm instances to run. Default: ${numToStr( - DEFAULT_AQUAVM_POOL_SIZE, - )}`, - }, - systemServices: { - nullable: true, - type: "object", - description: - "System services to run by default. aquaIpfs and decider are enabled by default", - additionalProperties: false, - properties: { - enable: { - nullable: true, - type: "array", - items: { type: "string" }, - description: `List of system services to enable`, - }, - aquaIpfs: { - type: "object", - description: "Aqua IPFS service configuration", - additionalProperties: false, - nullable: true, - properties: { - externalApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of external IPFS API`, - }, - localApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of local IPFS API`, - }, - ipfsBinaryPath: { - nullable: true, - type: "string", - description: `Path to the IPFS binary`, - }, - }, - required: [], - }, - decider: { - type: "object", - description: "Decider service configuration", - additionalProperties: false, - nullable: true, - properties: { - deciderPeriodSec: { - nullable: true, - type: "integer", - description: `Decider period in seconds`, - }, - workerPeriodSec: { - nullable: true, - type: "integer", - description: `Worker period in seconds`, - }, - workerIpfsMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of worker IPFS node`, - }, - networkApiEndpoint: { - nullable: true, - type: "string", - description: `Network API endpoint`, - }, - networkId: { - nullable: true, - type: "integer", - description: `Network ID`, - }, - startBlock: { - nullable: true, - type: "string", - description: `Start block`, - }, - matcherAddress: { - nullable: true, - type: "string", - description: `Matcher address`, - }, - walletKey: { - nullable: true, - type: "string", - description: `Wallet key`, - }, - }, - required: [], - }, - }, - required: [], - }, - effectors: { - nullable: true, - type: "object", - description: "Effectors to allow on the nox", - additionalProperties: effectorSchema, - properties: { - effectorName: effectorSchema, - }, - required: [], - }, - chainConfig: { - nullable: true, - type: "object", - description: "Chain config", - additionalProperties: false, - properties: { - httpEndpoint: { - nullable: true, - type: "string", - description: `HTTP endpoint of the chain. Same as decider`, - }, - coreContractAddress: { - nullable: true, - type: "string", - description: `Core contract address`, - }, - ccContractAddress: { - nullable: true, - type: "string", - description: `Capacity commitment contract address`, - }, - marketContractAddress: { - nullable: true, - type: "string", - description: `Market contract address`, - }, - networkId: { - nullable: true, - type: "integer", - description: `Network ID`, - }, - walletKey: { - nullable: true, - type: "string", - description: `Wallet key`, - }, - }, - required: [], - }, - rawConfig: { - nullable: true, - type: "string", - description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, - }, - }, - required: [], - nullable: true, - additionalProperties: false, -} as const satisfies JSONSchemaType; - -type NoxConfigYAMLV1 = Omit & { - chain?: Omit< - NonNullable, - | "coreContractAddress" - | "ccContractAddress" - | "marketContractAddress" - | "walletKey" - > & { - wsEndpoint?: string; - dealSyncStartBlock?: string; - marketContract?: string; - ccContract?: string; - coreContract?: string; - diamondContract?: string; - walletPrivateKey?: string; - defaultBaseFee?: number; - defaultPriorityFee?: number; - }; - ccp?: { - ccpEndpoint?: string; - proofPollPeriod?: string; - }; - ipfs?: { - externalApiMultiaddr?: string; - localApiMultiaddr?: string; - ipfsBinaryPath?: string; - }; - cpusRange?: string; - systemCpuCount?: number; - listenIp?: string; - externalMultiaddresses?: Array; - metrics?: { - enabled?: boolean; - timerResolution?: string; - tokioMetricsEnabled?: boolean; - tokioDetailedMetricsEnabled?: boolean; - }; - bootstrapNodes?: Array; - vm?: { - libvirtUri?: string; - allowGpu?: boolean; - network: { - bridgeName?: string; - publicIp: string; - vmIp?: string; - portRange?: { - start?: number; - end?: number; - }; - hostSshPort?: number; - vmSshPort?: number; - }; - }; -}; - -const DEFAULT_TIMER_RESOLUTION = "1 minute"; -const DEFAULT_PROOF_POLL_PERIOD = "60 seconds"; -const DEFAULT_IPFS_BINARY_PATH = "/usr/bin/ipfs"; - -const noxConfigYAMLSchemaV1 = { - type: "object", - description: - "Configuration to pass to the nox compute peer. Config.toml files are generated from this config", - properties: { - tcpPort: { - nullable: true, - type: "integer", - description: `Both host and container TCP port to use. Default: ${numToStr( - TCP_PORT_START, - )} (on local network ports will be generated by default)`, - }, - websocketPort: { - nullable: true, - type: "integer", - description: `Both host and container WebSocket port to use. Default: ${numToStr( - WEB_SOCKET_PORT_START, - )} (on local network ports will be generated by default)`, - }, - httpPort: { - nullable: true, - type: "integer", - description: `Both host and container HTTP port to use. Default: ${numToStr( - HTTP_PORT_START, - )} (on local network ports will be generated by default)`, - }, - aquavmPoolSize: { - nullable: true, - type: "integer", - description: `Number of aquavm instances to run. Default: ${numToStr( - DEFAULT_AQUAVM_POOL_SIZE, - )}`, - }, - systemServices: { - nullable: true, - type: "object", - description: - "System services to run by default. aquaIpfs and decider are enabled by default", - additionalProperties: false, - properties: { - enable: { - nullable: true, - type: "array", - items: { type: "string" }, - description: `List of system services to enable`, - }, - aquaIpfs: { - type: "object", - description: "Aqua IPFS service configuration", - additionalProperties: false, - nullable: true, - properties: { - externalApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of external IPFS API`, - }, - localApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of local IPFS API`, - }, - ipfsBinaryPath: { - nullable: true, - type: "string", - description: `Path to the IPFS binary. Default: ${DEFAULT_IPFS_BINARY_PATH}`, - }, - }, - required: [], - }, - decider: { - type: "object", - description: "Decider service configuration", - additionalProperties: false, - nullable: true, - properties: { - deciderPeriodSec: { - nullable: true, - type: "integer", - description: `Decider period in seconds`, - }, - workerPeriodSec: { - nullable: true, - type: "integer", - description: `Worker period in seconds`, - }, - workerIpfsMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of worker IPFS node`, - }, - networkApiEndpoint: { - nullable: true, - type: "string", - description: `Network API endpoint (deprecated)`, - }, - networkId: { - nullable: true, - type: "integer", - description: `Network ID (deprecated)`, - }, - startBlock: { - nullable: true, - type: "string", - description: `Start block (deprecated)`, - }, - matcherAddress: { - nullable: true, - type: "string", - description: `Matcher address (deprecated)`, - }, - walletKey: { - nullable: true, - type: "string", - description: `Wallet key (deprecated)`, - }, - }, - required: [], - }, - }, - required: [], - }, - effectors: { - nullable: true, - type: "object", - description: "Effectors to allow on the nox", - additionalProperties: effectorSchema, - properties: { - effectorName: effectorSchema, - }, - required: [], - }, - chain: { - nullable: true, - type: "object", - description: "Chain config", - additionalProperties: false, - properties: { - dealSyncStartBlock: { - nullable: true, - type: "string", - description: `Start block (deprecated)`, - }, - wsEndpoint: { - nullable: true, - type: "string", - description: `WebSocket endpoint of the chain`, - }, - httpEndpoint: { - nullable: true, - type: "string", - description: `HTTP endpoint of the chain`, - }, - coreContract: { - nullable: true, - type: "string", - description: `Core contract address (deprecated)`, - }, - ccContract: { - nullable: true, - type: "string", - description: `Capacity commitment contract address (deprecated)`, - }, - marketContract: { - nullable: true, - type: "string", - description: `Market contract address (deprecated)`, - }, - diamondContract: { - nullable: true, - type: "string", - description: `Diamond contract address`, - }, - networkId: { - nullable: true, - type: "integer", - description: `Network ID`, - }, - walletPrivateKey: { - nullable: true, - type: "string", - description: `Nox wallet private key. Is generated by default`, - }, - defaultBaseFee: { - nullable: true, - type: "number", - description: `Default base fee`, - }, - defaultPriorityFee: { - nullable: true, - type: "number", - description: `Default priority fee`, - }, - }, - required: [], - }, - ccp: { - nullable: true, - type: "object", - description: "For advanced users. CCP config", - additionalProperties: false, - properties: { - ccpEndpoint: { - nullable: true, - type: "string", - description: `CCP endpoint. Default comes from top-level ccp config: http://{ccp.rpcEndpoint.host}:{ccp.rpcEndpoint.port}`, - }, - proofPollPeriod: { - nullable: true, - type: "string", - description: `Proof poll period. Default: ${DEFAULT_PROOF_POLL_PERIOD}`, - default: DEFAULT_PROOF_POLL_PERIOD, - }, - }, - required: [], - }, - ipfs: { - nullable: true, - type: "object", - description: "IPFS config", - additionalProperties: false, - properties: { - externalApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of external IPFS API`, - }, - localApiMultiaddr: { - nullable: true, - type: "string", - description: `Multiaddress of local IPFS API`, - }, - ipfsBinaryPath: { - nullable: true, - type: "string", - description: `Path to the IPFS binary. Default: ${DEFAULT_IPFS_BINARY_PATH}`, - }, - }, - required: [], - }, - cpusRange: { - nullable: true, - type: "string", - description: `Range of CPU cores to use. Default: 1-32`, - }, - systemCpuCount: { - nullable: true, - type: "integer", - minimum: 1, - description: `Number of CPU cores to allocate for the Nox itself. Default: 1`, - }, - listenIp: { - nullable: true, - type: "string", - format: "ipv4", - description: `IP to listen on`, - }, - externalMultiaddresses: { - nullable: true, - type: "array", - items: { type: "string" }, - description: `List of external multiaddresses`, - }, - metrics: { - nullable: true, - type: "object", - description: "Metrics configuration", - additionalProperties: false, - properties: { - enabled: { - nullable: true, - type: "boolean", - description: `Metrics enabled. Default: true`, - default: true, - }, - timerResolution: { - nullable: true, - type: "string", - description: `Timer resolution. Default: ${DEFAULT_TIMER_RESOLUTION}`, - default: DEFAULT_TIMER_RESOLUTION, - }, - tokioMetricsEnabled: { - nullable: true, - type: "boolean", - description: `Tokio metrics enabled. Default: true`, - default: true, - }, - tokioDetailedMetricsEnabled: { - nullable: true, - type: "boolean", - description: `Tokio detailed metrics enabled`, - }, - }, - required: [], - }, - bootstrapNodes: { - nullable: true, - type: "array", - items: { type: "string" }, - description: `List of bootstrap nodes. Default: all addresses for the selected env`, - }, - rawConfig: { - nullable: true, - type: "string", - description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, - }, - vm: { - type: "object", - description: "VM Configuration", - additionalProperties: false, - nullable: true, - required: ["network"], - properties: { - libvirtUri: { - nullable: true, - type: "string", - description: `QEMU Socket`, - }, - allowGpu: { - nullable: true, - type: "boolean", - description: `Whether to add info about GPUs to VM's XML`, - }, - network: { - type: "object", - description: "VM Network Configuration", - additionalProperties: false, - nullable: false, - required: ["publicIp"], - properties: { - bridgeName: { - nullable: true, - type: "string", - description: `Name of the network bridge device`, - }, - publicIp: { - nullable: false, - type: "string", - format: "ipv4", - description: `Public IP address to assign the VM. Must be publicly accessible.`, - }, - vmIp: { - nullable: true, - type: "string", - format: "ipv4", - description: `Internal IP address to assign the VM`, - }, - portRange: { - type: "object", - description: "iptables-mapped port range from Host to VM", - additionalProperties: false, - nullable: true, - required: [], - properties: { - start: { - nullable: true, - type: "integer", - description: `Start of the iptables-mapped port range from Host to VM`, - }, - end: { - nullable: true, - type: "integer", - description: `End of the iptables-mapped port range from Host to VM`, - }, - }, - }, - hostSshPort: { - nullable: true, - type: "integer", - description: `Host SSH port, default is 922`, - }, - vmSshPort: { - nullable: true, - type: "integer", - description: `VM SSH port, default is 22`, - }, - }, - }, - }, - }, - }, - required: [], - nullable: true, - additionalProperties: false, -} as const satisfies JSONSchemaType; - -type CCPConfigYAMLV1 = { - rpcEndpoint?: { - host?: string; - port?: number; - utilityThreadIds?: Array; - }; - prometheusEndpoint?: { - host?: string; - port?: number; - }; - logs?: { - reportHashrate?: boolean; - logLevel?: string; - }; - state?: { - path?: string; - }; - rawConfig?: string; -}; - -const DEFAULT_RPC_ENDPOINT_HOST = "0.0.0.0"; -const DEFAULT_RPC_ENDPOINT_PORT = 9389; -const DEFAULT_PROMETHEUS_ENDPOINT_HOST = "0.0.0.0"; -const DEFAULT_PROMETHEUS_ENDPOINT_PORT = 9384; -const DEFAULT_REPORT_HASHRATE = false; -const DEFAULT_LOG_LEVEL = "debug"; -const DEFAULT_STATE_PATH = "./state"; -const DEFAULT_UTILITY_THREAD_IDS = [1]; - -const ccpConfigYAMLSchemaV1 = { - type: "object", - description: "Configuration to pass to the Capacity Commitment Prover", - properties: { - rpcEndpoint: { - type: "object", - description: "RPC endpoint configuration", - additionalProperties: false, - nullable: true, - properties: { - host: { - nullable: true, - type: "string", - description: `RPC host. Default: ${DEFAULT_RPC_ENDPOINT_HOST}`, - default: DEFAULT_RPC_ENDPOINT_HOST, - }, - port: { - nullable: true, - type: "integer", - description: `RPC port. Default: ${numToStr( - DEFAULT_RPC_ENDPOINT_PORT, - )}`, - default: DEFAULT_RPC_ENDPOINT_PORT, - }, - utilityThreadIds: { - nullable: true, - type: "array", - items: { type: "integer" }, - description: `Utility thread IDs`, - }, - }, - required: [], - }, - prometheusEndpoint: { - type: "object", - description: "Prometheus endpoint configuration", - additionalProperties: false, - nullable: true, - properties: { - host: { - nullable: true, - type: "string", - description: `Prometheus host. Default: ${DEFAULT_PROMETHEUS_ENDPOINT_HOST}`, - default: DEFAULT_PROMETHEUS_ENDPOINT_HOST, - }, - port: { - nullable: true, - type: "integer", - description: `Prometheus port. Default: ${numToStr( - DEFAULT_PROMETHEUS_ENDPOINT_PORT, - )}`, - default: DEFAULT_PROMETHEUS_ENDPOINT_PORT, - }, - }, - required: [], - }, - logs: { - type: "object", - description: "Logs configuration", - additionalProperties: false, - nullable: true, - properties: { - reportHashrate: { - nullable: true, - type: "boolean", - description: `Report hashrate. Default: ${boolToStr( - DEFAULT_REPORT_HASHRATE, - )}`, - default: DEFAULT_REPORT_HASHRATE, - }, - logLevel: { - nullable: true, - type: "string", - description: `Log level. Default: ${DEFAULT_LOG_LEVEL}`, - default: DEFAULT_LOG_LEVEL, - }, - }, - required: [], - }, - state: { - type: "object", - description: "State configuration", - additionalProperties: false, - nullable: true, - properties: { - path: { - nullable: true, - type: "string", - description: `Path to the state file. Default: ${DEFAULT_STATE_PATH}`, - default: DEFAULT_STATE_PATH, - }, - }, - }, - rawConfig: { - nullable: true, - type: "string", - description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, - }, - }, - required: [], - nullable: true, - additionalProperties: false, -} as const satisfies JSONSchemaType; - -type ComputePeerV0 = { - computeUnits: number; - nox?: NoxConfigYAMLV0; -}; - -type ConfigV0 = { - providerName: string; - offers: Record; - computePeers: Record; - capacityCommitments: Record; - nox?: NoxConfigYAMLV0; - version: 0; -}; - -const offerSchemaV0 = { - type: "object", - description: "Defines a provider offer", - additionalProperties: false, - properties: { - minPricePerWorkerEpoch: { - type: "string", - description: `Minimum price per worker epoch in ${PT_SYMBOL}`, - }, - computePeers: { - description: "Number of Compute Units for this Compute Peer", - type: "array", - items: { type: "string" }, - uniqueItems: true, - }, - effectors: { type: "array", items: { type: "string" }, nullable: true }, - minProtocolVersion: { - type: "integer", - description: `Min protocol version. Must be less then or equal to maxProtocolVersion. Default: ${numToStr( - versions.protocolVersion, - )}`, - nullable: true, - default: versions.protocolVersion, - minimum: 1, - }, - maxProtocolVersion: { - type: "integer", - description: `Max protocol version. Must be more then or equal to minProtocolVersion. Default: ${numToStr( - versions.protocolVersion, - )}`, - nullable: true, - default: versions.protocolVersion, - minimum: 1, - }, - }, - required: ["minPricePerWorkerEpoch", "computePeers"], -} as const satisfies JSONSchemaType; - -const computePeerSchemaV0 = { - type: "object", - description: "Defines a compute peer", - additionalProperties: false, - properties: { - computeUnits: { - type: "integer", - description: `How many compute units should nox have. Default: ${numToStr( - DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, - )} (each compute unit requires ${COMPUTE_UNIT_MEMORY_STR} of RAM)`, - }, - nox: noxConfigYAMLSchemaV0, - }, - required: ["computeUnits"], -} as const satisfies JSONSchemaType; - -const configSchemaV0Obj = { - type: "object", - additionalProperties: false, - properties: { - providerName: { - description: "Provider name. Must not be empty", - type: "string", - minLength: 1, - }, - offers: { - description: "A map with offer names as keys and offers as values", - type: "object", - additionalProperties: offerSchemaV0, - properties: { - Offer: offerSchemaV0, - }, - required: [], - }, - computePeers: { - description: - "A map with compute peer names as keys and compute peers as values", - type: "object", - additionalProperties: computePeerSchemaV0, - properties: { - ComputePeer: computePeerSchemaV0, - }, - required: [], - }, - nox: noxConfigYAMLSchemaV0, - capacityCommitments: { - description: - "A map with nox names as keys and capacity commitments as values", - type: "object", - additionalProperties: capacityCommitmentSchemaV0, - properties: { - noxName: capacityCommitmentSchemaV0, - }, - required: [], - }, - version: { type: "integer", const: 0, description: "Config version" }, - }, - required: [ - "version", - "computePeers", - "offers", - "providerName", - "capacityCommitments", - ], -} as const satisfies JSONSchemaType; - -const configSchemaV0: JSONSchemaType = configSchemaV0Obj; - -type ComputePeerV1 = Omit & { - nox?: NoxConfigYAMLV1; - ccp?: CCPConfigYAMLV1; -}; - -const computePeerSchemaV1 = { - type: "object", - description: "Defines a compute peer", - additionalProperties: false, - properties: { - computeUnits: { - type: "integer", - description: `How many compute units should nox have. Default: ${numToStr( - DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, - )} (each compute unit requires ${COMPUTE_UNIT_MEMORY_STR} of RAM)`, - }, - nox: noxConfigYAMLSchemaV1, - ccp: ccpConfigYAMLSchemaV1, - }, - required: ["computeUnits"], -} as const satisfies JSONSchemaType; - -type ConfigV1 = Omit & { - version: 1; - nox?: NoxConfigYAMLV1; - computePeers: Record; - ccp?: CCPConfigYAMLV1; -}; - -const configSchemaV1Obj = { - type: "object", - additionalProperties: false, - properties: { - providerName: { - description: "Provider name. Must not be empty", - type: "string", - minLength: 1, - }, - offers: { - description: "A map with offer names as keys and offers as values", - type: "object", - additionalProperties: offerSchemaV0, - properties: { - Offer: offerSchemaV0, - }, - required: [], - }, - computePeers: { - description: - "A map with compute peer names as keys and compute peers as values", - type: "object", - additionalProperties: computePeerSchemaV1, - properties: { - ComputePeer: computePeerSchemaV1, - }, - required: [], - }, - nox: noxConfigYAMLSchemaV1, - ccp: ccpConfigYAMLSchemaV1, - capacityCommitments: { - description: - "A map with nox names as keys and capacity commitments as values", - type: "object", - additionalProperties: capacityCommitmentSchemaV0, - properties: { - noxName: capacityCommitmentSchemaV0, - }, - required: [], - }, - version: { type: "integer", const: 1, description: "Config version" }, - }, - required: [ - "version", - "computePeers", - "offers", - "providerName", - "capacityCommitments", - ], -} as const satisfies JSONSchemaType; - -const configSchemaV1: JSONSchemaType = configSchemaV1Obj; - -export type OfferV1 = Omit & { - minPricePerCuPerEpoch: string; -}; - -type ConfigV2 = Omit & { - version: 2; - offers: Record; -}; - -const offerSchemaV1 = { - type: "object", - description: "Defines a provider offer", - additionalProperties: false, - properties: { - minPricePerCuPerEpoch: { - type: "string", - description: `Minimum price per compute unit per epoch in ${PT_SYMBOL}`, - }, - computePeers: { - description: "Number of Compute Units for this Compute Peer", - type: "array", - items: { type: "string" }, - uniqueItems: true, - }, - effectors: { type: "array", items: { type: "string" }, nullable: true }, - minProtocolVersion: { - type: "integer", - description: `Min protocol version. Must be less then or equal to maxProtocolVersion. Default: ${numToStr( - versions.protocolVersion, - )}`, - nullable: true, - default: versions.protocolVersion, - minimum: 1, - }, - maxProtocolVersion: { - type: "integer", - description: `Max protocol version. Must be more then or equal to minProtocolVersion. Default: ${numToStr( - versions.protocolVersion, - )}`, - nullable: true, - default: versions.protocolVersion, - minimum: 1, - }, - }, - required: ["minPricePerCuPerEpoch", "computePeers"], -} as const satisfies JSONSchemaType; - -const configSchemaV2Obj = { - type: "object", - additionalProperties: false, - properties: { - providerName: { - description: "Provider name. Must not be empty", - type: "string", - minLength: 1, - }, - offers: { - description: "A map with offer names as keys and offers as values", - type: "object", - additionalProperties: offerSchemaV1, - properties: { - Offer: offerSchemaV1, - }, - required: [], - }, - computePeers: { - description: - "A map with compute peer names as keys and compute peers as values", - type: "object", - additionalProperties: computePeerSchemaV1, - properties: { - ComputePeer: computePeerSchemaV1, - }, - required: [], - }, - nox: noxConfigYAMLSchemaV1, - ccp: ccpConfigYAMLSchemaV1, - capacityCommitments: { - description: - "A map with nox names as keys and capacity commitments as values", - type: "object", - additionalProperties: capacityCommitmentSchemaV0, - properties: { - noxName: capacityCommitmentSchemaV0, - }, - required: [], - }, - version: { type: "integer", const: 2, description: "Config version" }, - }, - required: [ - "version", - "computePeers", - "offers", - "providerName", - "capacityCommitments", - ], -} as const satisfies JSONSchemaType; - -const configSchemaV2: JSONSchemaType = configSchemaV2Obj; - -type ConfigV3 = Omit & { - version: 3; - capacityCommitments: Record; -}; - -const configSchemaV3Obj = { - ...configSchemaV2Obj, - properties: { - ...configSchemaV2Obj.properties, - version: { type: "integer", const: 3, description: "Config version" }, - capacityCommitments: { - ...configSchemaV2Obj.properties.capacityCommitments, - additionalProperties: capacityCommitmentSchemaV1, - properties: { - noxName: capacityCommitmentSchemaV1, - }, - }, - }, -} as const satisfies JSONSchemaType; - -const configSchemaV3: JSONSchemaType = configSchemaV3Obj; - -const latestConfigSchemaObj = - configSchemaV3Obj satisfies JSONSchemaType; - -const latestConfigSchema: JSONSchemaType = { - $id: `${TOP_LEVEL_SCHEMA_ID}/${PROVIDER_CONFIG_FULL_FILE_NAME}`, - title: PROVIDER_CONFIG_FULL_FILE_NAME, - description: `Defines config used for provider set up`, - ...latestConfigSchemaObj, -}; - -const ipValidator = ajv.compile({ - type: "string", - format: "ipv4", -}); - -function validateIp(value: string) { - return ipValidator(value) ? true : "Must be a valid IPv4 address"; -} - -function getDefault(args: ProviderConfigArgs) { - return async () => { - const { yamlDiffPatch } = await import("yaml-diff-patch"); - const chainEnv = await ensureChainEnv(); - setEnvConfig(await initNewEnvConfig(chainEnv)); - const isLocal = chainEnv === "local"; - const hasVM = !isLocal && args["no-vm"] !== true; - - const userProvidedConfig: UserProvidedConfig = { - providerName: "defaultProvider", - nox: { - effectors: { - curl: { - wasmCID: DEFAULT_CURL_EFFECTOR_CID, - allowedBinaries: { curl: "/usr/bin/curl" }, - }, - ...(hasVM ? { vm: { wasmCID: DEFAULT_VM_EFFECTOR_CID } } : {}), - }, - }, - computePeers: {}, - offers: {}, - capacityCommitments: {}, - }; - - const numberOfNoxes = - args.noxes ?? - (isInteractive && !isLocal - ? Number( - await input({ - message: `Enter number of compute peers you want to set up`, - validate(value) { - return Number.isInteger(Number(value)) && Number(value) > 0 - ? true - : "Must be a positive integer"; - }, - }), - ) - : DEFAULT_NUMBER_OF_LOCAL_NET_NOXES); - - const computePeerEntries: [string, LatestComputePeer][] = []; - - for (const i of times(numberOfNoxes)) { - const peerConfig = hasVM - ? { - nox: { - vm: { - network: { - publicIp: isInteractive - ? await input({ - message: `Enter public IP address for nox-${numToStr(i)}`, - validate: validateIp, - }) - : "", - }, - }, - }, - } - : {}; - - computePeerEntries.push([ - `nox-${numToStr(i)}`, - { - computeUnits: DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, - ...peerConfig, - }, - ] as const); - } - - userProvidedConfig.computePeers = Object.fromEntries(computePeerEntries); - - userProvidedConfig.capacityCommitments = Object.fromEntries( - Object.keys(userProvidedConfig.computePeers).map((noxName) => { - return [ - noxName, - { - duration: DEFAULT_CC_DURATION, - stakerReward: DEFAULT_CC_STAKER_REWARD, - }, - ] as const; - }), - ); - - userProvidedConfig.offers = { - [DEFAULT_OFFER_NAME]: { - ...defaultNumberProperties, - computePeers: Object.keys(userProvidedConfig.computePeers), - effectors: [ - DEFAULT_CURL_EFFECTOR_CID, - ...(hasVM ? [DEFAULT_VM_EFFECTOR_CID] : []), - ], - }, - }; - - return `# Defines Provider configuration -# You can use \`fluence provider init\` command to generate this config template - -# config version -version: ${numToStr(latestConfigSchemaObj.properties.version.const)} - -${yamlDiffPatch("", {}, userProvidedConfig)} - `; - }; -} - -const validateConfigSchemaV0 = ajv.compile(configSchemaV0); -const validateConfigSchemaV1 = ajv.compile(configSchemaV1); -const validateConfigSchemaV2 = ajv.compile(configSchemaV2); - -const migrations: Migrations = [ - async (config: Config): Promise => { - if (!validateConfigSchemaV0(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const { nox, computePeers, ...restConfig } = config; - - const newConfig: Omit = { - ...restConfig, - version: 1, - }; - - if (nox !== undefined) { - newConfig.nox = migrateNoxConfigYAMLV0ToV1(nox); - } - - return { - ...newConfig, - computePeers: migrateComputePeersV0ToV1(computePeers), - }; - }, - async (config: Config): Promise => { - if (!validateConfigSchemaV1(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const { offers, ...restConfig } = config; - - return { - ...restConfig, - version: 2, - offers: mapValues(offers, ({ minPricePerWorkerEpoch, ...restConfig }) => { - return { - ...restConfig, - minPricePerCuPerEpoch: minPricePerWorkerEpoch, - }; - }), - }; - }, - async (config: Config): Promise => { - if (!validateConfigSchemaV2(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - return { - ...config, - version: 3, - capacityCommitments: mapValues( - config.capacityCommitments, - ({ rewardDelegationRate: stakerReward, ...cc }) => { - return { ...cc, stakerReward }; - }, - ), - }; - }, -]; - -function migrateComputePeersV0ToV1( - computePeers: ConfigV0["computePeers"], -): ConfigV1["computePeers"] { - return mapValues(computePeers, ({ nox, ...computePeer }) => { - if (nox === undefined) { - return computePeer; - } - - return { - ...computePeer, - nox: migrateNoxConfigYAMLV0ToV1(nox), - }; - }); -} - -function migrateNoxConfigYAMLV0ToV1(nox: NoxConfigYAMLV0) { - const { chainConfig, ...restNox } = nox; - - if (chainConfig !== undefined) { - return { - ...restNox, - chain: migrateChainConfigV0ToV1(chainConfig), - }; - } - - return restNox; -} - -function migrateChainConfigV0ToV1( - chainConfig: NonNullable, -) { - const { walletKey, ...restChainConfig } = chainConfig; - - return omitBy( - { - ...restChainConfig, - walletPrivateKey: walletKey, - }, - isUndefined, - ); -} - -type LatestComputePeer = ComputePeerV1; -type Config = ConfigV0 | ConfigV1 | ConfigV2 | ConfigV3; -type LatestConfig = ConfigV3; -type LatestCCPConfigYAML = CCPConfigYAMLV1; -type LatestNoxConfigYAML = NoxConfigYAMLV1; -export type ProviderConfig = InitializedConfig; -export type ProviderConfigReadonly = InitializedReadonlyConfig; - -const validate: ConfigValidateFunction = async (config) => { - return validateBatchAsync( - validateCIDs( - Object.entries(config.offers).flatMap(([name, { effectors }]) => { - return (effectors ?? []).map((cid) => { - return { - cid, - location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > offers > ${name} > effectors`, - }; - }); - }), - ), - validateCIDs( - Object.entries(config.nox?.effectors ?? {}).map( - ([effectorName, { wasmCID: cid }]) => { - return { - cid, - location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > nox > effectors > ${effectorName} > wasmCID`, - }; - }, - ), - ), - validateCIDs( - Object.entries(config.computePeers).flatMap( - ([computePeerName, { nox }]) => { - return Object.entries(nox?.effectors ?? {}).map( - ([effectorName, { wasmCID: cid }]) => { - return { - cid, - location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > computePeers > ${computePeerName} > nox > effectors > ${effectorName} > wasmCID`, - }; - }, - ); - }, - ), - ), - validateEffectors(config), - validateCC(config), - validateMissingComputePeers(config), - validateNoDuplicateNoxNamesInOffers(config), - validateProtocolVersions(config), - ); -}; - -async function validateProtocolVersions(providerConfig: LatestConfig) { - const errors = ( - await Promise.all( - Object.entries(providerConfig.offers).flatMap( - ([ - offer, - { - maxProtocolVersion = versions.protocolVersion, - minProtocolVersion = versions.protocolVersion, - }, - ]) => { - return [ - Promise.resolve({ - offer, - property: "minProtocolVersion or maxProtocolVersion", - validity: - minProtocolVersion > maxProtocolVersion - ? `minProtocolVersion must be less than or equal to maxProtocolVersion. Got: minProtocolVersion=${color.yellow( - minProtocolVersion, - )} maxProtocolVersion=${color.yellow(maxProtocolVersion)}` - : true, - }), - ...( - [ - ["minProtocolVersion", minProtocolVersion], - ["maxProtocolVersion", maxProtocolVersion], - ] as const - ).map(async ([property, v]) => { - return { - offer, - property, - validity: await validateProtocolVersion(v), - }; - }), - ]; - }, - ), - ) - ).filter((a): a is typeof a & { validity: string } => { - return a.validity !== true; - }); - - if (errors.length > 0) { - return errors - .map(({ offer, property, validity }) => { - return `Offer ${color.yellow(offer)} has invalid ${color.yellow( - property, - )} property: ${validity}`; - }) - .join("\n"); - } - - return true; -} - -export async function validateEffectors( - providerConfig: LatestConfig, -): Promise { - const errors = ( - await Promise.all( - Object.entries(providerConfig.offers).flatMap( - ([offerName, { effectors = [], computePeers: computePeerNames }]) => { - const offerEffectorsString = jsonStringify([...effectors].sort()); - - return computePeerNames.map(async (computePeerName) => { - const computePeer = providerConfig.computePeers[computePeerName]; - - if (computePeer === undefined) { - return true; - } - - const noxConfig = await resolveNoxConfigYAML( - providerConfig.nox, - computePeer.nox, - ); - - const computePeerEffectors = [ - ...Object.values(noxConfig.effectors ?? {}).map(({ wasmCID }) => { - return wasmCID; - }), - ].sort(); - - const hasDefaultVmEffector = computePeerEffectors.includes( - DEFAULT_VM_EFFECTOR_CID, - ); - - if ( - noxConfig.vm?.network.publicIp !== undefined && - !hasDefaultVmEffector - ) { - return `Compute peer ${color.yellow( - computePeerName, - )} has a defined publicIp property:\n\nvm:\n network:\n publicIp: ${noxConfig.vm.network.publicIp}\n\nso it is expected to also have a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}`; - } - - if ( - noxConfig.vm?.network.publicIp === undefined && - hasDefaultVmEffector - ) { - return `Compute peer ${color.yellow( - computePeerName, - )} has a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}\n\nso it is expected to also have a defined publicIp property:\n\nvm:\n network:\n publicIp: `; - } - - const computePeerEffectorsString = - jsonStringify(computePeerEffectors); - - if (computePeerEffectorsString !== offerEffectorsString) { - return `Offer ${color.yellow( - offerName, - )} contains computePeer ${color.yellow( - computePeerName, - )}, that has effectors ${color.yellow( - computePeerEffectorsString, - )} which doesn't match effectors that are specified in the offer ${color.yellow( - offerEffectorsString, - )}`; - } - - return true; - }); - }, - ), - ) - ).filter((result): result is string => { - return typeof result === "string"; - }); - - return errors.length > 0 ? errors.join("\n\n") : true; -} - -function validateNoDuplicateNoxNamesInOffers( - config: LatestConfig, -): ValidationResult { - const noxNamesInOffers: Record = {}; - - Object.entries(config.offers).forEach(([offerName, { computePeers }]) => { - computePeers.forEach((noxName) => { - const arr = noxNamesInOffers[noxName]; - - if (arr === undefined) { - noxNamesInOffers[noxName] = [offerName]; - } else { - arr.push(offerName); - } - }); - }); - - const duplicateNoxNames = Object.entries(noxNamesInOffers).filter( - ([, offerNames]) => { - return offerNames.length > 1; - }, - ); - - if (duplicateNoxNames.length > 0) { - return duplicateNoxNames - .map(([noxName, offerNames]) => { - return `Nox ${color.yellow( - noxName, - )} is present in multiple offers: ${color.yellow( - offerNames.join(", "), - )}`; - }) - .join("\n"); - } - - return true; -} - -async function validateCC(config: LatestConfig): Promise { - const validateCCDuration = await ccDurationValidator(); - - const capacityCommitmentErrors = ( - await Promise.all( - Object.entries(config.capacityCommitments).map(async ([name, cc]) => { - const errors = [ - cc.delegator === undefined - ? true - : await validateAddress(cc.delegator), - validateCCDuration(cc.duration), - ].filter((e) => { - return e !== true; - }); - - return errors.length === 0 - ? true - : `Invalid capacity commitment for ${color.yellow( - name, - )}:\n${errors.join("\n")}`; - }), - ) - ).filter((e) => { - return e !== true; - }); - - if (capacityCommitmentErrors.length > 0) { - return capacityCommitmentErrors.join("\n\n"); - } - - return true; -} - -function validateMissingComputePeers(config: LatestConfig): ValidationResult { - const missingComputePeerNamesInOffer: Array<{ - offerName: string; - missingComputePeerNames: Array; - }> = []; - - if (isEmpty(config.computePeers)) { - return `There should be at least one computePeer defined in the config`; - } - - const offers = Object.entries(config.offers); - - if (offers.length === 0) { - return `There should be at least one offer defined in the config`; - } - - // Checking that all computePeers referenced in offers are defined - for (const [offerName, { computePeers }] of offers) { - const missingComputePeerNames = computePeers.filter((cp) => { - return !(cp in config.computePeers); - }); - - if (missingComputePeerNames.length > 0) { - missingComputePeerNamesInOffer.push({ - offerName, - missingComputePeerNames, - }); - } - } - - if (missingComputePeerNamesInOffer.length > 0) { - return missingComputePeerNamesInOffer - .map(({ offerName, missingComputePeerNames }) => { - return `Offer ${color.yellow( - offerName, - )} has computePeers missing from the config's top level computePeers property: ${color.yellow( - missingComputePeerNames.join(", "), - )}`; - }) - .join("\n"); - } - - return true; -} - -const initConfigOptions = { - allSchemas: [configSchemaV0, configSchemaV1, configSchemaV2, configSchemaV3], - latestSchema: latestConfigSchema, - migrations, - name: PROVIDER_CONFIG_FILE_NAME, - getConfigOrConfigDirPath: () => { - return getProviderConfigPath(); - }, - getSchemaDirPath: getFluenceDir, - validate, -}; - -export type UserProvidedConfig = Omit; - -export async function initNewReadonlyProviderConfig( - args: ProviderConfigArgs = {}, -) { - return getReadonlyConfigInitFunction(initConfigOptions, getDefault(args))(); -} - -export function initReadonlyProviderConfig() { - return getReadonlyConfigInitFunction(initConfigOptions)(); -} - -export async function ensureReadonlyProviderConfig() { - const providerConfig = await initReadonlyProviderConfig(); - - if (providerConfig === null) { - commandObj.error( - `Please init ${PROVIDER_CONFIG_FULL_FILE_NAME} using '${CLI_NAME} provider init' in order to continue`, - ); - } - - return providerConfig; -} - -export async function initProviderConfigWithPath(path: string) { - return getConfigInitFunction({ - ...initConfigOptions, - getConfigOrConfigDirPath: () => { - return path; - }, - })(); -} - -export const providerSchema: JSONSchemaType = latestConfigSchema; - -function mergeConfigYAML(a: T, b: Record) { - return mergeWith(cloneDeep(a), b, (objValue, srcValue) => { - if (Array.isArray(objValue) && Array.isArray(srcValue)) { - return srcValue; - } - - return undefined; - }); -} - -function mergeConfigYAMLWithRawConfig< - T extends { rawConfig?: string | undefined } & Record, ->(a: T, b: T) { - const { rawConfig: rawConfigB, ...configB } = b; - let config = mergeConfigYAML(a, configB); - - const parsedRawConfigB = - rawConfigB === undefined ? undefined : parse(rawConfigB); - - if (parsedRawConfigB !== undefined) { - config = mergeConfigYAML(config, parsedRawConfigB); - } - - return config; -} - -async function resolveNoxConfigYAML( - globalNoxConfig: LatestNoxConfigYAML | undefined = {}, - computePeerNoxConfig: LatestNoxConfigYAML | undefined = {}, - { i = 0, signingWallet = "" }: { i?: number; signingWallet?: string } = {}, -) { - const env = await ensureChainEnv(); - const isLocal = env === "local"; - - let config = mergeConfigYAMLWithRawConfig( - await getDefaultNoxConfigYAML(), - globalNoxConfig, - ); - - config = mergeConfigYAMLWithRawConfig(config, computePeerNoxConfig); - - /* eslint-disable @typescript-eslint/consistent-type-assertions */ - - const tcpPort = - (config["tcp_port"] as number | undefined) ?? - config.tcpPort ?? - (isLocal ? TCP_PORT_START - i : TCP_PORT_START); - - const websocketPort = - (config["websocket_port"] as number | undefined) ?? - config.websocketPort ?? - (isLocal ? WEB_SOCKET_PORT_START - i : WEB_SOCKET_PORT_START); - - const httpPort = - (config["http_port"] as number | undefined) ?? - config.httpPort ?? - (isLocal ? HTTP_PORT_START - i : HTTP_PORT_START); - - const walletPrivateKey = - // @ts-expect-error we allow user to put anything in raw config - (config["chain_config"]?.["wallet_key"] as string | undefined) ?? - config.chain?.walletPrivateKey ?? - signingWallet; - - /* eslint-enable @typescript-eslint/consistent-type-assertions */ - - if (config.chain?.walletPrivateKey === undefined) { - config.chain = { ...config.chain, walletPrivateKey }; - } - - let ipfs: undefined | LatestNoxConfigYAML["ipfs"]; - // eslint-disable-next-line prefer-const - ({ ipfs, ...config } = config); - - config.systemServices = { - ...config.systemServices, - aquaIpfs: { - ...config.systemServices?.aquaIpfs, - externalApiMultiaddr: - config.systemServices?.aquaIpfs?.externalApiMultiaddr ?? - ipfs?.externalApiMultiaddr ?? - EXTERNAL_API_MULTIADDRS[env], - localApiMultiaddr: - config.systemServices?.aquaIpfs?.localApiMultiaddr ?? - ipfs?.localApiMultiaddr ?? - LOCAL_API_MULTIADDRS[env], - ipfsBinaryPath: - config.systemServices?.aquaIpfs?.ipfsBinaryPath ?? - ipfs?.ipfsBinaryPath ?? - DEFAULT_IPFS_BINARY_PATH, - }, - }; - - return { ...config, tcpPort, websocketPort, httpPort }; -} - -function resolveCCPConfigYAML( - globalCCPConfig: LatestCCPConfigYAML | undefined = {}, - computePeerCCPConfig: LatestCCPConfigYAML | undefined = {}, -) { - const config = mergeConfigYAMLWithRawConfig( - getDefaultCCPConfigYAML(), - globalCCPConfig, - ); - - return mergeConfigYAMLWithRawConfig(config, computePeerCCPConfig); -} - -function getObjByKey(obj: Record, key: string): object { - if (!(key in obj)) { - return {}; - } - - const value = obj[key]; - return typeof value === "object" && value !== null ? value : {}; -} - -function noxConfigYAMLToConfigToml( - { - chain: { diamondContract, walletPrivateKey, ...chain } = {}, - ccp, - listenIp, - metrics, - effectors, - ...config - }: LatestNoxConfigYAML, - ccpConfig: LatestCCPConfigYAML, - env: ChainENV, -) { - const chainConfig = { - httpEndpoint: chain.httpEndpoint, - diamondContractAddress: diamondContract, - networkId: chain.networkId, - walletKey: walletPrivateKey, - defaultBaseFee: chain.defaultBaseFee, - defaultPriorityFee: chain.defaultPriorityFee, - ...getObjByKey(config, "chain_config"), - }; - - // Would be too hard to properly type this - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return camelCaseKeysToSnakeCase({ - ...config, - ...(listenIp === undefined - ? {} - : { - listenConfig: { - listenIp, - ...getObjByKey(config, "listen_config"), - }, - }), - chainConfig, - ...(env === "local" - ? {} - : { - chainListenerConfig: { - wsEndpoint: chain.wsEndpoint, - ccpEndpoint: - ccp?.ccpEndpoint ?? - `http://${ - ccpConfig.rpcEndpoint?.host ?? DEFAULT_RPC_ENDPOINT_HOST - }:${numToStr( - ccpConfig.rpcEndpoint?.port ?? DEFAULT_RPC_ENDPOINT_PORT, - )}`, - proofPollPeriod: ccp?.proofPollPeriod, - ...getObjByKey(config, "chain_listener_config"), - }, - }), - tokioMetricsEnabled: metrics?.tokioMetricsEnabled, - tokioDetailedMetricsEnabled: metrics?.tokioDetailedMetricsEnabled, - metricsEnabled: metrics?.enabled, - metricsTimerResolution: metrics?.timerResolution, - ...(effectors === undefined - ? {} - : { - effectors: Object.fromEntries( - Object.entries(effectors).map( - ([name, { wasmCID, allowedBinaries }]) => { - return [ - name, - { wasmCID, allowedBinaries: allowedBinaries ?? {} }, - ] as const; - }, - ), - ), - }), - }) as JsonMap; -} - -function ccpConfigYAMLToConfigToml(config: LatestCCPConfigYAML) { - // Would be too hard to properly type this - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return camelCaseKeysToKebabCase(config) as JsonMap; -} - -function camelCaseToDifferentCase(caseFn: (str: string) => string) { - const camelCaseToDifferentCaseImpl = (val: unknown): unknown => { - if (typeof val === "object" && val !== null) { - if (Array.isArray(val)) { - return val.map(camelCaseToDifferentCaseImpl); - } - - const objWithSnakeCaseKeys = mapKeys(val, (_, key) => { - return caseFn(key); - }); - - return Object.fromEntries( - Object.entries(objWithSnakeCaseKeys).map(([key, value]) => { - return [key, camelCaseToDifferentCaseImpl(value)]; - }), - ); - } - - return val; - }; - - return camelCaseToDifferentCaseImpl; -} - -function camelCaseKeysToSnakeCase(val: unknown): unknown { - return camelCaseToDifferentCase(snakeCase)(val); -} - -function camelCaseKeysToKebabCase(val: unknown): unknown { - return camelCaseToDifferentCase(kebabCase)(val); -} - -const EXTERNAL_API_MULTIADDRS: Record = { - mainnet: "/dns4/ipfs.kras.fluence.dev/tcp/5020", - testnet: "/dns4/ipfs.dar.fluence.dev/tcp/5020", - stage: "/dns4/ipfs.fluence.dev/tcp/5001", - local: LOCAL_IPFS_ADDRESS, -}; - -const LOCAL_API_MULTIADDRS: Record = { - ...EXTERNAL_API_MULTIADDRS, - local: NOX_IPFS_MULTIADDR, -}; - -async function getDefaultNoxConfigYAML(): Promise { - const env = await ensureChainEnv(); - const networkId = await getChainId(); - const { RPC_URLS } = await import("@fluencelabs/deal-ts-clients"); - - const CHAIN_URLS_FOR_CONTAINERS = { - ...RPC_URLS, - local: `http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, - }; - - return { - aquavmPoolSize: DEFAULT_AQUAVM_POOL_SIZE, - ipfs: { - externalApiMultiaddr: EXTERNAL_API_MULTIADDRS[env], - localApiMultiaddr: LOCAL_API_MULTIADDRS[env], - ipfsBinaryPath: DEFAULT_IPFS_BINARY_PATH, - }, - systemServices: { - enable: ["aqua-ipfs", "decider"], - decider: { - deciderPeriodSec: 30, - workerIpfsMultiaddr: - env === "local" - ? NOX_IPFS_MULTIADDR - : "/dns4/ipfs.fluence.dev/tcp/5001", - }, - }, - chain: { - httpEndpoint: - envConfig?.rpcUrl === undefined - ? CHAIN_URLS_FOR_CONTAINERS[env] - : envConfig.rpcUrl, - wsEndpoint: WS_CHAIN_URLS[env], - diamondContract: (await resolveDeployment()).diamond, - networkId, - defaultPriorityFee: 0, - }, - ccp: { - proofPollPeriod: DEFAULT_PROOF_POLL_PERIOD, - }, - ...(env === "local" - ? {} - : { bootstrapNodes: await resolveRelaysWithoutLocal(env) }), - metrics: { - enabled: true, - timerResolution: DEFAULT_TIMER_RESOLUTION, - tokioMetricsEnabled: true, - }, - }; -} - -function getDefaultCCPConfigYAML(): LatestCCPConfigYAML { - return { - rpcEndpoint: { - host: DEFAULT_RPC_ENDPOINT_HOST, - port: DEFAULT_RPC_ENDPOINT_PORT, - utilityThreadIds: DEFAULT_UTILITY_THREAD_IDS, - }, - prometheusEndpoint: { - host: DEFAULT_PROMETHEUS_ENDPOINT_HOST, - port: DEFAULT_PROMETHEUS_ENDPOINT_PORT, - }, - logs: { - reportHashrate: DEFAULT_REPORT_HASHRATE, - logLevel: DEFAULT_LOG_LEVEL, - }, - }; -} - -export function getConfigTomlName(noxName: string) { - return `${noxName}_Config.${TOML_EXT}`; -} - -export function getCCPConfigTomlName(noxName: string) { - return `${noxName}_Config.${TOML_EXT}`; -} - -export function promptForOfferName(offers: ProviderConfigReadonly["offers"]) { - return list({ - message: "Select offer", - options: Object.keys(offers), - oneChoiceMessage(choice) { - return `Select offer ${color.yellow(choice)}`; - }, - onNoChoices() { - commandObj.error("No offers found"); - }, - }); -} - -export type EnsureComputerPeerConfig = Awaited< - ReturnType ->[number]; - -export async function ensureComputerPeerConfigs(computePeerNames?: string[]) { - const { Wallet } = await import("ethers"); - const providerConfig = await ensureReadonlyProviderConfig(); - - const providerSecretsConfig = - await initNewProviderSecretsConfig(providerConfig); - - const [computePeersWithoutKeys, computePeersWithKeys] = splitErrorsAndResults( - Object.entries(providerConfig.computePeers) - .filter(([name]) => { - return ( - computePeerNames === undefined || computePeerNames.includes(name) - ); - }) - .map(([computePeerName, computePeer]) => { - return { - computePeerName, - computePeer, - secretKey: providerSecretsConfig.noxes[computePeerName]?.networkKey, - signingWallet: - providerSecretsConfig.noxes[computePeerName]?.signingWallet, - }; - }), - ({ secretKey, signingWallet, computePeerName, computePeer }) => { - if (secretKey === undefined || signingWallet === undefined) { - return { - error: { computePeerName, computePeer }, - }; - } - - return { - result: { secretKey, signingWallet, computePeerName, computePeer }, - }; - }, - ); - - if (computePeersWithoutKeys.length > 0) { - commandObj.warn( - `Missing keys for the following compute peers in noxes property at ${providerSecretsConfig.$getPath()}:\n${computePeersWithoutKeys - .map(({ computePeerName }) => { - return computePeerName; - }) - .join(", ")}\nGenerating new ones...`, - ); - - const computePeersWithGeneratedKeys = await Promise.all( - computePeersWithoutKeys.map(async ({ computePeer, computePeerName }) => { - return { - secretKey: (await genSecretKeyOrReturnExisting(computePeerName)) - .secretKey, - computePeerName, - computePeer, - signingWallet: Wallet.createRandom().privateKey, - }; - }), - ); - - providerSecretsConfig.noxes = { - ...providerSecretsConfig.noxes, - ...Object.fromEntries( - computePeersWithGeneratedKeys.map( - ({ computePeerName, secretKey, signingWallet }) => { - return [ - computePeerName, - { networkKey: secretKey, signingWallet }, - ] as const; - }, - ), - ), - }; - - await providerSecretsConfig.$commit(); - computePeersWithKeys.push(...computePeersWithGeneratedKeys); - } - - const [noCCError, computePeersWithCC] = splitErrorsAndResults( - computePeersWithKeys, - (c) => { - const capacityCommitment = - providerConfig.capacityCommitments[c.computePeerName]; - - if (capacityCommitment === undefined) { - return { - error: c.computePeerName, - }; - } - - return { result: { ...c, capacityCommitment } }; - }, - ); - - if (noCCError.length > 0) { - commandObj.error( - `Missing capacity commitment for compute peers at ${providerConfig.$getPath()}:\n\n${noCCError - .map((n) => { - return `capacityCommitments.${n}`; - }) - .join("\n")}`, - ); - } - - const { stringify } = await import("@iarna/toml"); - const configsDir = await ensureFluenceConfigsDir(); - const ccpConfigsDir = await ensureFluenceCCPConfigsDir(); - const env = await ensureChainEnv(); - - if (env === "local") { - const cpWithoutGeneratedPorts = computePeersWithCC.slice( - WEB_SOCKET_PORT_START - TCP_PORT_START, - ); - - if ( - cpWithoutGeneratedPorts.length > 0 && - !cpWithoutGeneratedPorts.every(({ computePeer: { nox } }) => { - return ( - nox?.httpPort !== undefined && - nox.tcpPort !== undefined && - nox.websocketPort !== undefined - ); - }) - ) { - commandObj.error( - `Please define httpPort, tcpPort and websocketPort for compute peers ${cpWithoutGeneratedPorts - .map(({ computePeerName }) => { - return computePeerName; - }) - .join(", ")} in ${providerConfig.$getPath()}`, - ); - } - } - - return Promise.all( - computePeersWithCC.map( - async ( - { - computePeerName, - computePeer, - secretKey, - signingWallet, - capacityCommitment, - }, - i, - ) => { - await writeFile( - await ensureFluenceSecretsFilePath(computePeerName), - secretKey, - FS_OPTIONS, - ); - - const overridenCCPConfig = resolveCCPConfigYAML( - providerConfig.ccp, - computePeer.ccp, - ); - - await writeFile( - join(ccpConfigsDir, getCCPConfigTomlName(computePeerName)), - stringify(ccpConfigYAMLToConfigToml(overridenCCPConfig)), - FS_OPTIONS, - ); - - const overriddenNoxConfig = await resolveNoxConfigYAML( - providerConfig.nox, - computePeer.nox, - { i, signingWallet }, - ); - - await writeFile( - join(configsDir, getConfigTomlName(computePeerName)), - stringify( - noxConfigYAMLToConfigToml( - overriddenNoxConfig, - overridenCCPConfig, - env, - ), - ), - FS_OPTIONS, - ); - - return { - name: computePeerName, - overriddenNoxConfig, - secretKey, - peerId: await getPeerIdFromSecretKey(secretKey), - computeUnits: computePeer.computeUnits, - walletKey: signingWallet, - walletAddress: await new Wallet(signingWallet).getAddress(), - capacityCommitment, - }; - }, - ), - ); -} diff --git a/packages/cli/package/src/lib/configs/project/provider/provider.ts b/packages/cli/package/src/lib/configs/project/provider/provider.ts new file mode 100644 index 000000000..d7ab49f2c --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/provider/provider.ts @@ -0,0 +1,563 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { writeFile } from "fs/promises"; +import { join } from "path"; + +import { type JsonMap } from "@iarna/toml"; +import kebabCase from "lodash-es/kebabCase.js"; +import mapKeys from "lodash-es/mapKeys.js"; +import snakeCase from "lodash-es/snakeCase.js"; +import times from "lodash-es/times.js"; + +import { type ChainENV } from "../../../../common.js"; +import { ajv } from "../../../ajvInstance.js"; +import { commandObj, isInteractive } from "../../../commandObj.js"; +import { + DEFAULT_OFFER_NAME, + PROVIDER_CONFIG_FULL_FILE_NAME, + FS_OPTIONS, + TCP_PORT_START, + WEB_SOCKET_PORT_START, + TOML_EXT, + defaultNumberProperties, + DEFAULT_CC_DURATION, + DEFAULT_CC_STAKER_REWARD, + DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + DEFAULT_CURL_EFFECTOR_CID, + CLI_NAME, + DEFAULT_NUMBER_OF_LOCAL_NET_NOXES, + DEFAULT_VM_EFFECTOR_CID, +} from "../../../const.js"; +import { ensureChainEnv } from "../../../ensureChainNetwork.js"; +import { type ProviderConfigArgs } from "../../../generateUserProviderConfig.js"; +import { getPeerIdFromSecretKey } from "../../../helpers/getPeerIdFromSecretKey.js"; +import { numToStr } from "../../../helpers/typesafeStringify.js"; +import { splitErrorsAndResults } from "../../../helpers/utils.js"; +import { genSecretKeyOrReturnExisting } from "../../../keyPairs.js"; +import { + ensureFluenceConfigsDir, + getProviderConfigPath, + getFluenceDir, + ensureFluenceSecretsFilePath, + ensureFluenceCCPConfigsDir, +} from "../../../paths.js"; +import { input } from "../../../prompt.js"; +import { getConfigInitFunction } from "../../initConfigNew.js"; +import { type InitConfigOptions } from "../../initConfigNewTypes.js"; +import { initNewEnvConfig } from "../env/env.js"; +import { initNewProviderSecretsConfig } from "../providerSecrets/providerSecrets.js"; + +import configOptions0, { type Config as Config0 } from "./provider0.js"; +import configOptions1, { + DEFAULT_LOG_LEVEL, + DEFAULT_PROMETHEUS_ENDPOINT_HOST, + DEFAULT_PROMETHEUS_ENDPOINT_PORT, + DEFAULT_REPORT_HASHRATE, + DEFAULT_RPC_ENDPOINT_HOST, + DEFAULT_RPC_ENDPOINT_PORT, + type CCPConfigYAML, + type ComputePeer, + type Config as Config1, + type NoxConfigYAML, +} from "./provider1.js"; +import configOptions2, { type Config as Config2 } from "./provider2.js"; +import configOptions3, { + mergeConfigYAMLWithRawConfig, + resolveNoxConfigYAML, + type Config as Config3, +} from "./provider3.js"; + +export const options: InitConfigOptions = { + description: "Defines config used for provider set up", + options: [configOptions0, configOptions1, configOptions2, configOptions3], + getConfigPath: getProviderConfigPath, + getSchemaDirPath: getFluenceDir, +}; + +export type ProviderConfig = Awaited>; + +const ipValidator = ajv.compile({ + type: "string", + format: "ipv4", +}); + +function validateIp(value: string) { + return ipValidator(value) ? true : "Must be a valid IPv4 address"; +} + +function getDefault(args: ProviderConfigArgs) { + return async () => { + const chainEnv = await ensureChainEnv(); + await initNewEnvConfig(chainEnv); + const isLocal = chainEnv === "local"; + const hasVM = !isLocal && args["no-vm"] !== true; + + const numberOfNoxes = + args.noxes ?? + (isInteractive && !isLocal + ? Number( + await input({ + message: `Enter number of compute peers you want to set up`, + validate(value) { + return Number.isInteger(Number(value)) && Number(value) > 0 + ? true + : "Must be a positive integer"; + }, + }), + ) + : DEFAULT_NUMBER_OF_LOCAL_NET_NOXES); + + const computePeerEntries: [string, ComputePeer][] = []; + + for (const i of times(numberOfNoxes)) { + const peerConfig = hasVM + ? { + nox: { + vm: { + network: { + publicIp: isInteractive + ? await input({ + message: `Enter public IP address for nox-${numToStr(i)}`, + validate: validateIp, + }) + : "", + }, + }, + }, + } + : {}; + + computePeerEntries.push([ + `nox-${numToStr(i)}`, + { + computeUnits: DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + ...peerConfig, + }, + ] as const); + } + + const computePeers = Object.fromEntries(computePeerEntries); + + return { + providerName: "defaultProvider", + nox: { + effectors: { + curl: { + wasmCID: DEFAULT_CURL_EFFECTOR_CID, + allowedBinaries: { curl: "/usr/bin/curl" }, + }, + ...(hasVM ? { vm: { wasmCID: DEFAULT_VM_EFFECTOR_CID } } : {}), + }, + }, + computePeers, + offers: { + [DEFAULT_OFFER_NAME]: { + ...defaultNumberProperties, + computePeers: Object.keys(computePeers), + effectors: [ + DEFAULT_CURL_EFFECTOR_CID, + ...(hasVM ? [DEFAULT_VM_EFFECTOR_CID] : []), + ], + }, + }, + capacityCommitments: Object.fromEntries( + Object.keys(computePeers).map((noxName) => { + return [ + noxName, + { + duration: DEFAULT_CC_DURATION, + stakerReward: DEFAULT_CC_STAKER_REWARD, + }, + ] as const; + }), + ), + }; + }; +} + +export function initNewProviderConfig(args: ProviderConfigArgs = {}) { + return getConfigInitFunction(options, getDefault(args))(); +} + +export const initProviderConfig = getConfigInitFunction(options); + +export async function ensureReadonlyProviderConfig() { + const providerConfig = await initProviderConfig(); + + if (providerConfig === null) { + commandObj.error( + `Please init ${PROVIDER_CONFIG_FULL_FILE_NAME} using '${CLI_NAME} provider init' in order to continue`, + ); + } + + return providerConfig; +} + +function resolveCCPConfigYAML( + globalCCPConfig: CCPConfigYAML | undefined = {}, + computePeerCCPConfig: CCPConfigYAML | undefined = {}, +) { + const config = mergeConfigYAMLWithRawConfig( + getDefaultCCPConfigYAML(), + globalCCPConfig, + ); + + return mergeConfigYAMLWithRawConfig(config, computePeerCCPConfig); +} + +function getObjByKey(obj: Record, key: string): object { + if (!(key in obj)) { + return {}; + } + + const value = obj[key]; + return typeof value === "object" && value !== null ? value : {}; +} + +function noxConfigYAMLToConfigToml( + { + chain: { diamondContract, walletPrivateKey, ...chain } = {}, + ccp, + listenIp, + metrics, + effectors, + ...config + }: NoxConfigYAML, + ccpConfig: CCPConfigYAML, + env: ChainENV, +) { + const chainConfig = { + httpEndpoint: chain.httpEndpoint, + diamondContractAddress: diamondContract, + networkId: chain.networkId, + walletKey: walletPrivateKey, + defaultBaseFee: chain.defaultBaseFee, + defaultPriorityFee: chain.defaultPriorityFee, + ...getObjByKey(config, "chain_config"), + }; + + // Would be too hard to properly type this + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return camelCaseKeysToSnakeCase({ + ...config, + ...(listenIp === undefined + ? {} + : { + listenConfig: { + listenIp, + ...getObjByKey(config, "listen_config"), + }, + }), + chainConfig, + ...(env === "local" + ? {} + : { + chainListenerConfig: { + wsEndpoint: chain.wsEndpoint, + ccpEndpoint: + ccp?.ccpEndpoint ?? + `http://${ + ccpConfig.rpcEndpoint?.host ?? DEFAULT_RPC_ENDPOINT_HOST + }:${numToStr( + ccpConfig.rpcEndpoint?.port ?? DEFAULT_RPC_ENDPOINT_PORT, + )}`, + proofPollPeriod: ccp?.proofPollPeriod, + ...getObjByKey(config, "chain_listener_config"), + }, + }), + tokioMetricsEnabled: metrics?.tokioMetricsEnabled, + tokioDetailedMetricsEnabled: metrics?.tokioDetailedMetricsEnabled, + metricsEnabled: metrics?.enabled, + metricsTimerResolution: metrics?.timerResolution, + ...(effectors === undefined + ? {} + : { + effectors: Object.fromEntries( + Object.entries(effectors).map( + ([name, { wasmCID, allowedBinaries }]) => { + return [ + name, + { wasmCID, allowedBinaries: allowedBinaries ?? {} }, + ] as const; + }, + ), + ), + }), + }) as JsonMap; +} + +function ccpConfigYAMLToConfigToml(config: CCPConfigYAML) { + // Would be too hard to properly type this + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return camelCaseKeysToKebabCase(config) as JsonMap; +} + +function camelCaseToDifferentCase(caseFn: (str: string) => string) { + const camelCaseToDifferentCaseImpl = (val: unknown): unknown => { + if (typeof val === "object" && val !== null) { + if (Array.isArray(val)) { + return val.map(camelCaseToDifferentCaseImpl); + } + + const objWithSnakeCaseKeys = mapKeys(val, (_, key) => { + return caseFn(key); + }); + + return Object.fromEntries( + Object.entries(objWithSnakeCaseKeys).map(([key, value]) => { + return [key, camelCaseToDifferentCaseImpl(value)]; + }), + ); + } + + return val; + }; + + return camelCaseToDifferentCaseImpl; +} + +function camelCaseKeysToSnakeCase(val: unknown): unknown { + return camelCaseToDifferentCase(snakeCase)(val); +} + +function camelCaseKeysToKebabCase(val: unknown): unknown { + return camelCaseToDifferentCase(kebabCase)(val); +} + +function getDefaultCCPConfigYAML(): CCPConfigYAML { + return { + rpcEndpoint: { + host: DEFAULT_RPC_ENDPOINT_HOST, + port: DEFAULT_RPC_ENDPOINT_PORT, + utilityThreadIds: [1], + }, + prometheusEndpoint: { + host: DEFAULT_PROMETHEUS_ENDPOINT_HOST, + port: DEFAULT_PROMETHEUS_ENDPOINT_PORT, + }, + logs: { + reportHashrate: DEFAULT_REPORT_HASHRATE, + logLevel: DEFAULT_LOG_LEVEL, + }, + }; +} + +export function getConfigTomlName(noxName: string) { + return `${noxName}_Config.${TOML_EXT}`; +} + +function getCCPConfigTomlName(noxName: string) { + return `${noxName}_Config.${TOML_EXT}`; +} + +export type EnsureComputerPeerConfig = Awaited< + ReturnType +>[number]; + +export async function ensureComputerPeerConfigs(computePeerNames?: string[]) { + const { Wallet } = await import("ethers"); + const providerConfig = await ensureReadonlyProviderConfig(); + + const providerSecretsConfig = + await initNewProviderSecretsConfig(providerConfig); + + const [computePeersWithoutKeys, computePeersWithKeys] = splitErrorsAndResults( + Object.entries(providerConfig.computePeers) + .filter(([name]) => { + return ( + computePeerNames === undefined || computePeerNames.includes(name) + ); + }) + .map(([computePeerName, computePeer]) => { + return { + computePeerName, + computePeer, + secretKey: providerSecretsConfig.noxes[computePeerName]?.networkKey, + signingWallet: + providerSecretsConfig.noxes[computePeerName]?.signingWallet, + }; + }), + ({ secretKey, signingWallet, computePeerName, computePeer }) => { + if (secretKey === undefined || signingWallet === undefined) { + return { + error: { computePeerName, computePeer }, + }; + } + + return { + result: { secretKey, signingWallet, computePeerName, computePeer }, + }; + }, + ); + + if (computePeersWithoutKeys.length > 0) { + commandObj.warn( + `Missing keys for the following compute peers in noxes property at ${providerSecretsConfig.$getPath()}:\n${computePeersWithoutKeys + .map(({ computePeerName }) => { + return computePeerName; + }) + .join(", ")}\nGenerating new ones...`, + ); + + const computePeersWithGeneratedKeys = await Promise.all( + computePeersWithoutKeys.map(async ({ computePeer, computePeerName }) => { + return { + secretKey: (await genSecretKeyOrReturnExisting(computePeerName)) + .secretKey, + computePeerName, + computePeer, + signingWallet: Wallet.createRandom().privateKey, + }; + }), + ); + + providerSecretsConfig.noxes = { + ...providerSecretsConfig.noxes, + ...Object.fromEntries( + computePeersWithGeneratedKeys.map( + ({ computePeerName, secretKey, signingWallet }) => { + return [ + computePeerName, + { networkKey: secretKey, signingWallet }, + ] as const; + }, + ), + ), + }; + + await providerSecretsConfig.$commit(); + computePeersWithKeys.push(...computePeersWithGeneratedKeys); + } + + const [noCCError, computePeersWithCC] = splitErrorsAndResults( + computePeersWithKeys, + (c) => { + const capacityCommitment = + providerConfig.capacityCommitments[c.computePeerName]; + + if (capacityCommitment === undefined) { + return { + error: c.computePeerName, + }; + } + + return { result: { ...c, capacityCommitment } }; + }, + ); + + if (noCCError.length > 0) { + commandObj.error( + `Missing capacity commitment for compute peers at ${providerConfig.$getPath()}:\n\n${noCCError + .map((n) => { + return `capacityCommitments.${n}`; + }) + .join("\n")}`, + ); + } + + const { stringify } = await import("@iarna/toml"); + const configsDir = await ensureFluenceConfigsDir(); + const ccpConfigsDir = await ensureFluenceCCPConfigsDir(); + const env = await ensureChainEnv(); + + if (env === "local") { + const cpWithoutGeneratedPorts = computePeersWithCC.slice( + WEB_SOCKET_PORT_START - TCP_PORT_START, + ); + + if ( + cpWithoutGeneratedPorts.length > 0 && + !cpWithoutGeneratedPorts.every(({ computePeer: { nox } }) => { + return ( + nox?.httpPort !== undefined && + nox.tcpPort !== undefined && + nox.websocketPort !== undefined + ); + }) + ) { + commandObj.error( + `Please define httpPort, tcpPort and websocketPort for compute peers ${cpWithoutGeneratedPorts + .map(({ computePeerName }) => { + return computePeerName; + }) + .join(", ")} in ${providerConfig.$getPath()}`, + ); + } + } + + return Promise.all( + computePeersWithCC.map( + async ( + { + computePeerName, + computePeer, + secretKey, + signingWallet, + capacityCommitment, + }, + i, + ) => { + await writeFile( + await ensureFluenceSecretsFilePath(computePeerName), + secretKey, + FS_OPTIONS, + ); + + const overridenCCPConfig = resolveCCPConfigYAML( + providerConfig.ccp, + computePeer.ccp, + ); + + await writeFile( + join(ccpConfigsDir, getCCPConfigTomlName(computePeerName)), + stringify(ccpConfigYAMLToConfigToml(overridenCCPConfig)), + FS_OPTIONS, + ); + + const overriddenNoxConfig = await resolveNoxConfigYAML( + providerConfig.nox, + computePeer.nox, + { i, signingWallet }, + ); + + await writeFile( + join(configsDir, getConfigTomlName(computePeerName)), + stringify( + noxConfigYAMLToConfigToml( + overriddenNoxConfig, + overridenCCPConfig, + env, + ), + ), + FS_OPTIONS, + ); + + return { + name: computePeerName, + overriddenNoxConfig, + secretKey, + peerId: await getPeerIdFromSecretKey(secretKey), + computeUnits: computePeer.computeUnits, + walletKey: signingWallet, + walletAddress: await new Wallet(signingWallet).getAddress(), + capacityCommitment, + }; + }, + ), + ); +} diff --git a/packages/cli/package/src/lib/configs/project/provider/provider0.ts b/packages/cli/package/src/lib/configs/project/provider/provider0.ts new file mode 100644 index 000000000..6e814ce9b --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/provider/provider0.ts @@ -0,0 +1,445 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import { versions } from "../../../../versions.js"; +import { + COMPUTE_UNIT_MEMORY_STR, + DEFAULT_AQUAVM_POOL_SIZE, + HTTP_PORT_START, + TCP_PORT_START, + WEB_SOCKET_PORT_START, + DEFAULT_CC_DURATION, + DEFAULT_CC_STAKER_REWARD, + DURATION_EXAMPLE, + DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + PT_SYMBOL, +} from "../../../const.js"; +import { numToStr } from "../../../helpers/typesafeStringify.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +type CapacityCommitment = { + duration: string; + rewardDelegationRate: number; + delegator?: string; +}; + +const capacityCommitmentSchema = { + type: "object", + description: "Defines a capacity commitment", + required: ["duration", "rewardDelegationRate"], + additionalProperties: false, + properties: { + duration: { + type: "string", + default: DEFAULT_CC_DURATION, + description: `Duration of the commitment ${DURATION_EXAMPLE}`, + }, + delegator: { + type: "string", + description: "Delegator address", + nullable: true, + }, + rewardDelegationRate: { + type: "number", + minimum: 0, + maximum: 100, + description: "Reward delegation rate in percent", + default: DEFAULT_CC_STAKER_REWARD, + }, + }, +} as const satisfies JSONSchemaType; + +export type CapacityCommitments = Record; + +export const capacityCommitmentsSchema = { + description: + "A map with nox names as keys and capacity commitments as values", + type: "object", + additionalProperties: capacityCommitmentSchema, + properties: { noxName: capacityCommitmentSchema }, + required: [], +} as const satisfies JSONSchemaType; + +export type Effector = { + wasmCID: string; + allowedBinaries?: Record; +}; + +export const effectorSchema = { + type: "object", + description: "Effector configuration", + additionalProperties: false, + properties: { + wasmCID: { + type: "string", + description: `Wasm CID of the effector`, + }, + allowedBinaries: { + type: "object", + description: `Allowed binaries`, + additionalProperties: { type: "string" }, + properties: { + curl: { type: "string" }, + }, + required: [], + nullable: true, + }, + }, + required: ["wasmCID"], +} as const satisfies JSONSchemaType; + +export type ChainConfig = { + httpEndpoint?: string; + coreContractAddress?: string; + ccContractAddress?: string; + marketContractAddress?: string; + networkId?: number; + walletKey?: string; +}; + +const chainConfigSchema = { + nullable: true, + type: "object", + description: "Chain config", + additionalProperties: false, + properties: { + httpEndpoint: { + nullable: true, + type: "string", + description: `HTTP endpoint of the chain. Same as decider`, + }, + coreContractAddress: { + nullable: true, + type: "string", + description: `Core contract address`, + }, + ccContractAddress: { + nullable: true, + type: "string", + description: `Capacity commitment contract address`, + }, + marketContractAddress: { + nullable: true, + type: "string", + description: `Market contract address`, + }, + networkId: { + nullable: true, + type: "integer", + description: `Network ID`, + }, + walletKey: { + nullable: true, + type: "string", + description: `Wallet key`, + }, + }, + required: [], +} as const satisfies JSONSchemaType; + +export type NoxConfigYAML = { + tcpPort?: number; + websocketPort?: number; + httpPort?: number; + aquavmPoolSize?: number; + systemServices?: { + enable?: Array; + aquaIpfs?: { + externalApiMultiaddr?: string; + localApiMultiaddr?: string; + ipfsBinaryPath?: string; + }; + decider?: { + deciderPeriodSec?: number; + workerPeriodSec?: number; + workerIpfsMultiaddr?: string; + networkApiEndpoint?: string; + networkId?: number; + startBlock?: string; + matcherAddress?: string; + walletKey?: string; + }; + }; + effectors?: Record; + rawConfig?: string; + chainConfig?: ChainConfig; +}; + +const noxConfigYAMLSchema = { + type: "object", + description: + "Configuration to pass to the nox compute peer. Config.toml files are generated from this config", + properties: { + tcpPort: { + nullable: true, + type: "integer", + description: `Both host and container TCP port to use. Default: for each nox a unique port is assigned starting from ${numToStr( + TCP_PORT_START, + )}`, + }, + websocketPort: { + nullable: true, + type: "integer", + description: `Both host and container WebSocket port to use. Default: for each nox a unique port is assigned starting from ${numToStr( + WEB_SOCKET_PORT_START, + )}`, + }, + httpPort: { + nullable: true, + type: "integer", + description: `Both host and container HTTP port to use. Default: for each nox a unique port is assigned starting from ${numToStr( + HTTP_PORT_START, + )}`, + }, + aquavmPoolSize: { + nullable: true, + type: "integer", + description: `Number of aquavm instances to run. Default: ${numToStr( + DEFAULT_AQUAVM_POOL_SIZE, + )}`, + }, + systemServices: { + nullable: true, + type: "object", + description: + "System services to run by default. aquaIpfs and decider are enabled by default", + additionalProperties: false, + properties: { + enable: { + nullable: true, + type: "array", + items: { type: "string" }, + description: `List of system services to enable`, + }, + aquaIpfs: { + type: "object", + description: "Aqua IPFS service configuration", + additionalProperties: false, + nullable: true, + properties: { + externalApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of external IPFS API`, + }, + localApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of local IPFS API`, + }, + ipfsBinaryPath: { + nullable: true, + type: "string", + description: `Path to the IPFS binary`, + }, + }, + required: [], + }, + decider: { + type: "object", + description: "Decider service configuration", + additionalProperties: false, + nullable: true, + properties: { + deciderPeriodSec: { + nullable: true, + type: "integer", + description: `Decider period in seconds`, + }, + workerPeriodSec: { + nullable: true, + type: "integer", + description: `Worker period in seconds`, + }, + workerIpfsMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of worker IPFS node`, + }, + networkApiEndpoint: { + nullable: true, + type: "string", + description: `Network API endpoint`, + }, + networkId: { + nullable: true, + type: "integer", + description: `Network ID`, + }, + startBlock: { + nullable: true, + type: "string", + description: `Start block`, + }, + matcherAddress: { + nullable: true, + type: "string", + description: `Matcher address`, + }, + walletKey: { + nullable: true, + type: "string", + description: `Wallet key`, + }, + }, + required: [], + }, + }, + required: [], + }, + effectors: { + nullable: true, + type: "object", + description: "Effectors to allow on the nox", + additionalProperties: effectorSchema, + properties: { + effectorName: effectorSchema, + }, + required: [], + }, + chainConfig: chainConfigSchema, + rawConfig: { + nullable: true, + type: "string", + description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, + }, + }, + required: [], + nullable: true, + additionalProperties: false, +} as const satisfies JSONSchemaType; + +type Offer = { + minPricePerWorkerEpoch: string; + computePeers: Array; + effectors?: Array; + minProtocolVersion?: number; + maxProtocolVersion?: number; +}; + +const offerSchema = { + type: "object", + description: "Defines a provider offer", + additionalProperties: false, + properties: { + minPricePerWorkerEpoch: { + type: "string", + description: `Minimum price per worker epoch in ${PT_SYMBOL}`, + }, + computePeers: { + description: "Number of Compute Units for this Compute Peer", + type: "array", + items: { type: "string" }, + uniqueItems: true, + }, + effectors: { type: "array", items: { type: "string" }, nullable: true }, + minProtocolVersion: { + type: "integer", + description: `Min protocol version. Must be less then or equal to maxProtocolVersion. Default: ${numToStr( + versions.protocolVersion, + )}`, + nullable: true, + default: versions.protocolVersion, + minimum: 1, + }, + maxProtocolVersion: { + type: "integer", + description: `Max protocol version. Must be more then or equal to minProtocolVersion. Default: ${numToStr( + versions.protocolVersion, + )}`, + nullable: true, + default: versions.protocolVersion, + minimum: 1, + }, + }, + required: ["minPricePerWorkerEpoch", "computePeers"], +} as const satisfies JSONSchemaType; + +export type Offers = Record; + +export const offersSchema = { + description: "A map with offer names as keys and offers as values", + type: "object", + additionalProperties: offerSchema, + properties: { Offer: offerSchema }, + required: [], +} as const satisfies JSONSchemaType; + +type ComputePeer = { + computeUnits: number; + nox?: NoxConfigYAML; +}; + +const computePeerSchema = { + type: "object", + description: "Defines a compute peer", + additionalProperties: false, + properties: { + computeUnits: { + type: "integer", + description: `How many compute units should nox have. Default: ${numToStr( + DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + )} (each compute unit requires ${COMPUTE_UNIT_MEMORY_STR} of RAM)`, + }, + nox: noxConfigYAMLSchema, + }, + required: ["computeUnits"], +} as const satisfies JSONSchemaType; + +export type ComputePeers = Record; + +const computePeersSchema = { + description: + "A map with compute peer names as keys and compute peers as values", + type: "object", + additionalProperties: computePeerSchema, + properties: { + ComputePeer: computePeerSchema, + }, + required: [], +} as const satisfies JSONSchemaType; + +export const providerNameSchema = { + description: "Provider name. Must not be empty", + type: "string", + minLength: 1, +} as const satisfies JSONSchemaType; + +export type Config = { + providerName: string; + offers: Offers; + computePeers: ComputePeers; + capacityCommitments: CapacityCommitments; + nox?: NoxConfigYAML; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + providerName: providerNameSchema, + offers: offersSchema, + computePeers: computePeersSchema, + nox: noxConfigYAMLSchema, + capacityCommitments: capacityCommitmentsSchema, + }, + required: ["computePeers", "offers", "providerName", "capacityCommitments"], + }, +} satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/provider/provider1.ts b/packages/cli/package/src/lib/configs/project/provider/provider1.ts new file mode 100644 index 000000000..0cf56f245 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/provider/provider1.ts @@ -0,0 +1,737 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; +import { isUndefined, mapValues, omitBy } from "lodash-es"; + +import { + COMPUTE_UNIT_MEMORY_STR, + DEFAULT_AQUAVM_POOL_SIZE, + HTTP_PORT_START, + TCP_PORT_START, + WEB_SOCKET_PORT_START, + DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, +} from "../../../const.js"; +import { boolToStr, numToStr } from "../../../helpers/typesafeStringify.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import { + type Config as PrevConfig, + providerNameSchema, + type Effector, + effectorSchema, + type CapacityCommitments, + capacityCommitmentsSchema, + type Offers, + offersSchema, + type NoxConfigYAML as PrevNoxConfigYAML, + type ChainConfig as PrevChainConfig, + type ComputePeers as PrevComputePeers, +} from "./provider0.js"; + +export type NoxConfigYAML = { + tcpPort?: number; + websocketPort?: number; + httpPort?: number; + aquavmPoolSize?: number; + systemServices?: { + enable?: Array; + aquaIpfs?: { + externalApiMultiaddr?: string; + localApiMultiaddr?: string; + ipfsBinaryPath?: string; + }; + decider?: { + deciderPeriodSec?: number; + workerPeriodSec?: number; + workerIpfsMultiaddr?: string; + networkApiEndpoint?: string; + networkId?: number; + startBlock?: string; + matcherAddress?: string; + walletKey?: string; + }; + }; + effectors?: Record; + rawConfig?: string; + chain?: { + httpEndpoint?: string; + networkId?: number; + wsEndpoint?: string; + dealSyncStartBlock?: string; + marketContract?: string; + ccContract?: string; + coreContract?: string; + diamondContract?: string; + walletPrivateKey?: string; + defaultBaseFee?: number; + defaultPriorityFee?: number; + }; + ccp?: { + ccpEndpoint?: string; + proofPollPeriod?: string; + }; + ipfs?: { + externalApiMultiaddr?: string; + localApiMultiaddr?: string; + ipfsBinaryPath?: string; + }; + cpusRange?: string; + systemCpuCount?: number; + listenIp?: string; + externalMultiaddresses?: Array; + metrics?: { + enabled?: boolean; + timerResolution?: string; + tokioMetricsEnabled?: boolean; + tokioDetailedMetricsEnabled?: boolean; + }; + bootstrapNodes?: Array; + vm?: { + libvirtUri?: string; + allowGpu?: boolean; + network: { + bridgeName?: string; + publicIp: string; + vmIp?: string; + portRange?: { + start?: number; + end?: number; + }; + hostSshPort?: number; + vmSshPort?: number; + }; + }; +}; + +export const DEFAULT_TIMER_RESOLUTION = "1 minute"; +export const DEFAULT_PROOF_POLL_PERIOD = "60 seconds"; +export const DEFAULT_IPFS_BINARY_PATH = "/usr/bin/ipfs"; + +export const noxConfigYAMLSchema = { + type: "object", + description: + "Configuration to pass to the nox compute peer. Config.toml files are generated from this config", + properties: { + tcpPort: { + nullable: true, + type: "integer", + description: `Both host and container TCP port to use. Default: ${numToStr( + TCP_PORT_START, + )} (on local network ports will be generated by default)`, + }, + websocketPort: { + nullable: true, + type: "integer", + description: `Both host and container WebSocket port to use. Default: ${numToStr( + WEB_SOCKET_PORT_START, + )} (on local network ports will be generated by default)`, + }, + httpPort: { + nullable: true, + type: "integer", + description: `Both host and container HTTP port to use. Default: ${numToStr( + HTTP_PORT_START, + )} (on local network ports will be generated by default)`, + }, + aquavmPoolSize: { + nullable: true, + type: "integer", + description: `Number of aquavm instances to run. Default: ${numToStr( + DEFAULT_AQUAVM_POOL_SIZE, + )}`, + }, + systemServices: { + nullable: true, + type: "object", + description: + "System services to run by default. aquaIpfs and decider are enabled by default", + additionalProperties: false, + properties: { + enable: { + nullable: true, + type: "array", + items: { type: "string" }, + description: `List of system services to enable`, + }, + aquaIpfs: { + type: "object", + description: "Aqua IPFS service configuration", + additionalProperties: false, + nullable: true, + properties: { + externalApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of external IPFS API`, + }, + localApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of local IPFS API`, + }, + ipfsBinaryPath: { + nullable: true, + type: "string", + description: `Path to the IPFS binary. Default: ${DEFAULT_IPFS_BINARY_PATH}`, + }, + }, + required: [], + }, + decider: { + type: "object", + description: "Decider service configuration", + additionalProperties: false, + nullable: true, + properties: { + deciderPeriodSec: { + nullable: true, + type: "integer", + description: `Decider period in seconds`, + }, + workerPeriodSec: { + nullable: true, + type: "integer", + description: `Worker period in seconds`, + }, + workerIpfsMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of worker IPFS node`, + }, + networkApiEndpoint: { + nullable: true, + type: "string", + description: `Network API endpoint (deprecated)`, + }, + networkId: { + nullable: true, + type: "integer", + description: `Network ID (deprecated)`, + }, + startBlock: { + nullable: true, + type: "string", + description: `Start block (deprecated)`, + }, + matcherAddress: { + nullable: true, + type: "string", + description: `Matcher address (deprecated)`, + }, + walletKey: { + nullable: true, + type: "string", + description: `Wallet key (deprecated)`, + }, + }, + required: [], + }, + }, + required: [], + }, + effectors: { + nullable: true, + type: "object", + description: "Effectors to allow on the nox", + additionalProperties: effectorSchema, + properties: { + effectorName: effectorSchema, + }, + required: [], + }, + chain: { + nullable: true, + type: "object", + description: "Chain config", + additionalProperties: false, + properties: { + dealSyncStartBlock: { + nullable: true, + type: "string", + description: `Start block (deprecated)`, + }, + wsEndpoint: { + nullable: true, + type: "string", + description: `WebSocket endpoint of the chain`, + }, + httpEndpoint: { + nullable: true, + type: "string", + description: `HTTP endpoint of the chain`, + }, + coreContract: { + nullable: true, + type: "string", + description: `Core contract address (deprecated)`, + }, + ccContract: { + nullable: true, + type: "string", + description: `Capacity commitment contract address (deprecated)`, + }, + marketContract: { + nullable: true, + type: "string", + description: `Market contract address (deprecated)`, + }, + diamondContract: { + nullable: true, + type: "string", + description: `Diamond contract address`, + }, + networkId: { + nullable: true, + type: "integer", + description: `Network ID`, + }, + walletPrivateKey: { + nullable: true, + type: "string", + description: `Nox wallet private key. Is generated by default`, + }, + defaultBaseFee: { + nullable: true, + type: "number", + description: `Default base fee`, + }, + defaultPriorityFee: { + nullable: true, + type: "number", + description: `Default priority fee`, + }, + }, + required: [], + }, + ccp: { + nullable: true, + type: "object", + description: "For advanced users. CCP config", + additionalProperties: false, + properties: { + ccpEndpoint: { + nullable: true, + type: "string", + description: `CCP endpoint. Default comes from top-level ccp config: http://{ccp.rpcEndpoint.host}:{ccp.rpcEndpoint.port}`, + }, + proofPollPeriod: { + nullable: true, + type: "string", + description: `Proof poll period. Default: ${DEFAULT_PROOF_POLL_PERIOD}`, + default: DEFAULT_PROOF_POLL_PERIOD, + }, + }, + required: [], + }, + ipfs: { + nullable: true, + type: "object", + description: "IPFS config", + additionalProperties: false, + properties: { + externalApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of external IPFS API`, + }, + localApiMultiaddr: { + nullable: true, + type: "string", + description: `Multiaddress of local IPFS API`, + }, + ipfsBinaryPath: { + nullable: true, + type: "string", + description: `Path to the IPFS binary. Default: ${DEFAULT_IPFS_BINARY_PATH}`, + }, + }, + required: [], + }, + cpusRange: { + nullable: true, + type: "string", + description: `Range of CPU cores to use. Default: 1-32`, + }, + systemCpuCount: { + nullable: true, + type: "integer", + minimum: 1, + description: `Number of CPU cores to allocate for the Nox itself. Default: 1`, + }, + listenIp: { + nullable: true, + type: "string", + format: "ipv4", + description: `IP to listen on`, + }, + externalMultiaddresses: { + nullable: true, + type: "array", + items: { type: "string" }, + description: `List of external multiaddresses`, + }, + metrics: { + nullable: true, + type: "object", + description: "Metrics configuration", + additionalProperties: false, + properties: { + enabled: { + nullable: true, + type: "boolean", + description: `Metrics enabled. Default: true`, + default: true, + }, + timerResolution: { + nullable: true, + type: "string", + description: `Timer resolution. Default: ${DEFAULT_TIMER_RESOLUTION}`, + default: DEFAULT_TIMER_RESOLUTION, + }, + tokioMetricsEnabled: { + nullable: true, + type: "boolean", + description: `Tokio metrics enabled. Default: true`, + default: true, + }, + tokioDetailedMetricsEnabled: { + nullable: true, + type: "boolean", + description: `Tokio detailed metrics enabled`, + }, + }, + required: [], + }, + bootstrapNodes: { + nullable: true, + type: "array", + items: { type: "string" }, + description: `List of bootstrap nodes. Default: all addresses for the selected env`, + }, + rawConfig: { + nullable: true, + type: "string", + description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, + }, + vm: { + type: "object", + description: "VM Configuration", + additionalProperties: false, + nullable: true, + required: ["network"], + properties: { + libvirtUri: { + nullable: true, + type: "string", + description: `QEMU Socket`, + }, + allowGpu: { + nullable: true, + type: "boolean", + description: `Whether to add info about GPUs to VM's XML`, + }, + network: { + type: "object", + description: "VM Network Configuration", + additionalProperties: false, + nullable: false, + required: ["publicIp"], + properties: { + bridgeName: { + nullable: true, + type: "string", + description: `Name of the network bridge device`, + }, + publicIp: { + nullable: false, + type: "string", + format: "ipv4", + description: `Public IP address to assign the VM. Must be publicly accessible.`, + }, + vmIp: { + nullable: true, + type: "string", + format: "ipv4", + description: `Internal IP address to assign the VM`, + }, + portRange: { + type: "object", + description: "iptables-mapped port range from Host to VM", + additionalProperties: false, + nullable: true, + required: [], + properties: { + start: { + nullable: true, + type: "integer", + description: `Start of the iptables-mapped port range from Host to VM`, + }, + end: { + nullable: true, + type: "integer", + description: `End of the iptables-mapped port range from Host to VM`, + }, + }, + }, + hostSshPort: { + nullable: true, + type: "integer", + description: `Host SSH port, default is 922`, + }, + vmSshPort: { + nullable: true, + type: "integer", + description: `VM SSH port, default is 22`, + }, + }, + }, + }, + }, + }, + required: [], + nullable: true, + additionalProperties: false, +} as const satisfies JSONSchemaType; + +export type CCPConfigYAML = { + rpcEndpoint?: { + host?: string; + port?: number; + utilityThreadIds?: Array; + }; + prometheusEndpoint?: { + host?: string; + port?: number; + }; + logs?: { + reportHashrate?: boolean; + logLevel?: string; + }; + state?: { + path?: string; + }; + rawConfig?: string; +}; + +export const DEFAULT_RPC_ENDPOINT_HOST = "0.0.0.0"; +export const DEFAULT_RPC_ENDPOINT_PORT = 9389; +export const DEFAULT_PROMETHEUS_ENDPOINT_HOST = "0.0.0.0"; +export const DEFAULT_PROMETHEUS_ENDPOINT_PORT = 9384; +export const DEFAULT_REPORT_HASHRATE = false; +export const DEFAULT_LOG_LEVEL = "debug"; +const DEFAULT_STATE_PATH = "./state"; + +export const ccpConfigYAMLSchema = { + type: "object", + description: "Configuration to pass to the Capacity Commitment Prover", + properties: { + rpcEndpoint: { + type: "object", + description: "RPC endpoint configuration", + additionalProperties: false, + nullable: true, + properties: { + host: { + nullable: true, + type: "string", + description: `RPC host. Default: ${DEFAULT_RPC_ENDPOINT_HOST}`, + default: DEFAULT_RPC_ENDPOINT_HOST, + }, + port: { + nullable: true, + type: "integer", + description: `RPC port. Default: ${numToStr( + DEFAULT_RPC_ENDPOINT_PORT, + )}`, + default: DEFAULT_RPC_ENDPOINT_PORT, + }, + utilityThreadIds: { + nullable: true, + type: "array", + items: { type: "integer" }, + description: `Utility thread IDs`, + }, + }, + required: [], + }, + prometheusEndpoint: { + type: "object", + description: "Prometheus endpoint configuration", + additionalProperties: false, + nullable: true, + properties: { + host: { + nullable: true, + type: "string", + description: `Prometheus host. Default: ${DEFAULT_PROMETHEUS_ENDPOINT_HOST}`, + default: DEFAULT_PROMETHEUS_ENDPOINT_HOST, + }, + port: { + nullable: true, + type: "integer", + description: `Prometheus port. Default: ${numToStr( + DEFAULT_PROMETHEUS_ENDPOINT_PORT, + )}`, + default: DEFAULT_PROMETHEUS_ENDPOINT_PORT, + }, + }, + required: [], + }, + logs: { + type: "object", + description: "Logs configuration", + additionalProperties: false, + nullable: true, + properties: { + reportHashrate: { + nullable: true, + type: "boolean", + description: `Report hashrate. Default: ${boolToStr( + DEFAULT_REPORT_HASHRATE, + )}`, + default: DEFAULT_REPORT_HASHRATE, + }, + logLevel: { + nullable: true, + type: "string", + description: `Log level. Default: ${DEFAULT_LOG_LEVEL}`, + default: DEFAULT_LOG_LEVEL, + }, + }, + required: [], + }, + state: { + type: "object", + description: "State configuration", + additionalProperties: false, + nullable: true, + properties: { + path: { + nullable: true, + type: "string", + description: `Path to the state file. Default: ${DEFAULT_STATE_PATH}`, + default: DEFAULT_STATE_PATH, + }, + }, + }, + rawConfig: { + nullable: true, + type: "string", + description: `Raw TOML config string to parse and merge with the rest of the config. Has the highest priority`, + }, + }, + required: [], + nullable: true, + additionalProperties: false, +} as const satisfies JSONSchemaType; + +export type ComputePeer = { + computeUnits: number; + nox?: NoxConfigYAML; + ccp?: CCPConfigYAML; +}; + +const computePeerSchema = { + type: "object", + description: "Defines a compute peer", + additionalProperties: false, + properties: { + computeUnits: { + type: "integer", + description: `How many compute units should nox have. Default: ${numToStr( + DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + )} (each compute unit requires ${COMPUTE_UNIT_MEMORY_STR} of RAM)`, + }, + nox: noxConfigYAMLSchema, + ccp: ccpConfigYAMLSchema, + }, + required: ["computeUnits"], +} as const satisfies JSONSchemaType; + +export type ComputePeers = Record; + +export const computePeersSchema = { + description: + "A map with compute peer names as keys and compute peers as values", + type: "object", + additionalProperties: computePeerSchema, + properties: { + ComputePeer: computePeerSchema, + }, + required: [], +} as const satisfies JSONSchemaType; + +export type Config = { + providerName: string; + offers: Offers; + capacityCommitments: CapacityCommitments; + nox?: NoxConfigYAML; + computePeers: ComputePeers; + ccp?: CCPConfigYAML; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + providerName: providerNameSchema, + offers: offersSchema, + capacityCommitments: capacityCommitmentsSchema, + computePeers: computePeersSchema, + nox: noxConfigYAMLSchema, + ccp: ccpConfigYAMLSchema, + }, + required: ["computePeers", "offers", "providerName", "capacityCommitments"], + }, + migrate({ nox, computePeers, ...restConfig }) { + const newConfig: Omit = restConfig; + + if (nox !== undefined) { + newConfig.nox = migrateNoxConfigYAML(nox); + } + + return { ...newConfig, computePeers: migrateComputePeers(computePeers) }; + }, +} satisfies ConfigOptions; + +function migrateComputePeers( + computePeers: PrevComputePeers, +): Config["computePeers"] { + return mapValues(computePeers, ({ nox, ...computePeer }) => { + return nox === undefined + ? computePeer + : { ...computePeer, nox: migrateNoxConfigYAML(nox) }; + }); +} + +function migrateNoxConfigYAML({ chainConfig, ...restNox }: PrevNoxConfigYAML) { + return chainConfig === undefined + ? restNox + : { ...restNox, chain: migrateChainConfig(chainConfig) }; +} + +function migrateChainConfig({ + walletKey, + ...restChainConfig +}: PrevChainConfig) { + return omitBy( + { ...restChainConfig, walletPrivateKey: walletKey }, + isUndefined, + ); +} diff --git a/packages/cli/package/src/lib/configs/project/provider/provider2.ts b/packages/cli/package/src/lib/configs/project/provider/provider2.ts new file mode 100644 index 000000000..7503c9eb9 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/provider/provider2.ts @@ -0,0 +1,131 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; +import { mapValues } from "lodash-es"; + +import { versions } from "../../../../versions.js"; +import { PT_SYMBOL } from "../../../const.js"; +import { numToStr } from "../../../helpers/typesafeStringify.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import { + type CapacityCommitments, + capacityCommitmentsSchema, + providerNameSchema, +} from "./provider0.js"; +import { + ccpConfigYAMLSchema, + computePeersSchema, + noxConfigYAMLSchema, + type CCPConfigYAML, + type ComputePeers, + type NoxConfigYAML, + type Config as PrevConfig, +} from "./provider1.js"; + +export type Offer = { + minPricePerCuPerEpoch: string; + computePeers: Array; + effectors?: Array; + minProtocolVersion?: number; + maxProtocolVersion?: number; +}; + +const offerSchema = { + type: "object", + description: "Defines a provider offer", + additionalProperties: false, + properties: { + minPricePerCuPerEpoch: { + type: "string", + description: `Minimum price per compute unit per epoch in ${PT_SYMBOL}`, + }, + computePeers: { + description: "Number of Compute Units for this Compute Peer", + type: "array", + items: { type: "string" }, + uniqueItems: true, + }, + effectors: { type: "array", items: { type: "string" }, nullable: true }, + minProtocolVersion: { + type: "integer", + description: `Min protocol version. Must be less then or equal to maxProtocolVersion. Default: ${numToStr( + versions.protocolVersion, + )}`, + nullable: true, + default: versions.protocolVersion, + minimum: 1, + }, + maxProtocolVersion: { + type: "integer", + description: `Max protocol version. Must be more then or equal to minProtocolVersion. Default: ${numToStr( + versions.protocolVersion, + )}`, + nullable: true, + default: versions.protocolVersion, + minimum: 1, + }, + }, + required: ["minPricePerCuPerEpoch", "computePeers"], +} as const satisfies JSONSchemaType; + +export type Offers = Record; + +export const offersSchema = { + description: "A map with offer names as keys and offers as values", + type: "object", + additionalProperties: offerSchema, + properties: { Offer: offerSchema }, + required: [], +} as const satisfies JSONSchemaType; + +export type Config = { + providerName: string; + capacityCommitments: CapacityCommitments; + nox?: NoxConfigYAML; + computePeers: ComputePeers; + ccp?: CCPConfigYAML; + offers: Offers; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + providerName: providerNameSchema, + computePeers: computePeersSchema, + nox: noxConfigYAMLSchema, + ccp: ccpConfigYAMLSchema, + capacityCommitments: capacityCommitmentsSchema, + offers: offersSchema, + }, + required: ["computePeers", "offers", "providerName", "capacityCommitments"], + }, + migrate({ offers, ...restConfig }) { + return { + ...restConfig, + offers: mapValues(offers, ({ minPricePerWorkerEpoch, ...restConfig }) => { + return { + ...restConfig, + minPricePerCuPerEpoch: minPricePerWorkerEpoch, + }; + }), + }; + }, +} satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/provider/provider3.ts b/packages/cli/package/src/lib/configs/project/provider/provider3.ts new file mode 100644 index 000000000..344322f84 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/provider/provider3.ts @@ -0,0 +1,611 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { parse } from "@iarna/toml"; +import { color } from "@oclif/color"; +import type { JSONSchemaType } from "ajv"; +import cloneDeep from "lodash-es/cloneDeep.js"; +import isEmpty from "lodash-es/isEmpty.js"; +import mapValues from "lodash-es/mapValues.js"; +import mergeWith from "lodash-es/mergeWith.js"; + +import { + jsonStringify, + CHAIN_RPC_PORT, + type ChainENV, +} from "../../../../common.js"; +import { versions } from "../../../../versions.js"; +import { getChainId } from "../../../chain/chainConfig.js"; +import { + ccDurationValidator, + validateAddress, + validateProtocolVersion, +} from "../../../chain/chainValidators.js"; +import { + PROVIDER_CONFIG_FULL_FILE_NAME, + DEFAULT_AQUAVM_POOL_SIZE, + HTTP_PORT_START, + TCP_PORT_START, + WEB_SOCKET_PORT_START, + LOCAL_IPFS_ADDRESS, + DEFAULT_CC_DURATION, + DEFAULT_CC_STAKER_REWARD, + DURATION_EXAMPLE, + WS_CHAIN_URLS, + CHAIN_RPC_CONTAINER_NAME, + DEFAULT_VM_EFFECTOR_CID, + IPFS_CONTAINER_NAME, + IPFS_PORT, +} from "../../../const.js"; +import { resolveDeployment } from "../../../dealClient.js"; +import { ensureChainEnv } from "../../../ensureChainNetwork.js"; +import { + type ValidationResult, + validateCIDs, +} from "../../../helpers/validations.js"; +import { validateBatchAsync } from "../../../helpers/validations.js"; +import { resolveRelaysWithoutLocal } from "../../../multiaddresWithoutLocal.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; +import { initEnvConfig } from "../env/env.js"; + +import { providerNameSchema } from "./provider0.js"; +import { + ccpConfigYAMLSchema, + computePeersSchema, + DEFAULT_IPFS_BINARY_PATH, + DEFAULT_PROOF_POLL_PERIOD, + DEFAULT_TIMER_RESOLUTION, + noxConfigYAMLSchema, + type CCPConfigYAML, + type ComputePeers, + type NoxConfigYAML, +} from "./provider1.js"; +import { + offersSchema, + type Offers, + type Config as PrevConfig, +} from "./provider2.js"; + +type CapacityCommitment = { + duration: string; + stakerReward: number; + delegator?: string; +}; + +const capacityCommitmentSchema = { + type: "object", + description: "Defines a capacity commitment", + required: ["duration", "stakerReward"], + additionalProperties: false, + properties: { + duration: { + type: "string", + default: DEFAULT_CC_DURATION, + description: `Duration of the commitment ${DURATION_EXAMPLE}`, + }, + delegator: { + type: "string", + description: "Delegator address", + nullable: true, + }, + stakerReward: { + type: "number", + minimum: 0, + maximum: 100, + description: "Staker reward in percent", + default: DEFAULT_CC_STAKER_REWARD, + }, + }, +} as const satisfies JSONSchemaType; + +type CapacityCommitments = Record; + +const capacityCommitmentsSchema = { + type: "object", + description: "Capacity commitments", + additionalProperties: capacityCommitmentSchema, + properties: { + commitmentName: capacityCommitmentSchema, + }, + required: [], +} as const satisfies JSONSchemaType; + +export type Config = { + providerName: string; + capacityCommitments: CapacityCommitments; + nox?: NoxConfigYAML; + computePeers: ComputePeers; + ccp?: CCPConfigYAML; + offers: Offers; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + providerName: providerNameSchema, + computePeers: computePeersSchema, + nox: noxConfigYAMLSchema, + ccp: ccpConfigYAMLSchema, + capacityCommitments: capacityCommitmentsSchema, + offers: offersSchema, + }, + required: ["computePeers", "offers", "providerName", "capacityCommitments"], + }, + migrate(config) { + return { + ...config, + capacityCommitments: mapValues( + config.capacityCommitments, + ({ rewardDelegationRate: stakerReward, ...cc }) => { + return { ...cc, stakerReward }; + }, + ), + }; + }, + validate(config) { + return validateBatchAsync( + validateCIDs( + Object.entries(config.offers).flatMap(([name, { effectors }]) => { + return (effectors ?? []).map((cid) => { + return { + cid, + location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > offers > ${name} > effectors`, + }; + }); + }), + ), + validateCIDs( + Object.entries(config.nox?.effectors ?? {}).map( + ([effectorName, { wasmCID: cid }]) => { + return { + cid, + location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > nox > effectors > ${effectorName} > wasmCID`, + }; + }, + ), + ), + validateCIDs( + Object.entries(config.computePeers).flatMap( + ([computePeerName, { nox }]) => { + return Object.entries(nox?.effectors ?? {}).map( + ([effectorName, { wasmCID: cid }]) => { + return { + cid, + location: `${PROVIDER_CONFIG_FULL_FILE_NAME} > computePeers > ${computePeerName} > nox > effectors > ${effectorName} > wasmCID`, + }; + }, + ); + }, + ), + ), + validateEffectors(config), + validateCC(config), + validateMissingComputePeers(config), + validateNoDuplicateNoxNamesInOffers(config), + validateProtocolVersions(config), + ); + }, +} satisfies ConfigOptions; + +async function validateProtocolVersions(providerConfig: Config) { + const errors = ( + await Promise.all( + Object.entries(providerConfig.offers).flatMap( + ([ + offer, + { + maxProtocolVersion = versions.protocolVersion, + minProtocolVersion = versions.protocolVersion, + }, + ]) => { + return [ + Promise.resolve({ + offer, + property: "minProtocolVersion or maxProtocolVersion", + validity: + minProtocolVersion > maxProtocolVersion + ? `minProtocolVersion must be less than or equal to maxProtocolVersion. Got: minProtocolVersion=${color.yellow( + minProtocolVersion, + )} maxProtocolVersion=${color.yellow(maxProtocolVersion)}` + : true, + }), + ...( + [ + ["minProtocolVersion", minProtocolVersion], + ["maxProtocolVersion", maxProtocolVersion], + ] as const + ).map(async ([property, v]) => { + return { + offer, + property, + validity: await validateProtocolVersion(v), + }; + }), + ]; + }, + ), + ) + ).filter((a): a is typeof a & { validity: string } => { + return a.validity !== true; + }); + + if (errors.length > 0) { + return errors + .map(({ offer, property, validity }) => { + return `Offer ${color.yellow(offer)} has invalid ${color.yellow( + property, + )} property: ${validity}`; + }) + .join("\n"); + } + + return true; +} + +export async function validateEffectors( + providerConfig: Config, +): Promise { + const errors = ( + await Promise.all( + Object.entries(providerConfig.offers).flatMap( + ([offerName, { effectors = [], computePeers: computePeerNames }]) => { + const offerEffectorsString = jsonStringify([...effectors].sort()); + + return computePeerNames.map(async (computePeerName) => { + const computePeer = providerConfig.computePeers[computePeerName]; + + if (computePeer === undefined) { + return true; + } + + const noxConfig = await resolveNoxConfigYAML( + providerConfig.nox, + computePeer.nox, + ); + + const computePeerEffectors = [ + ...Object.values(noxConfig.effectors ?? {}).map(({ wasmCID }) => { + return wasmCID; + }), + ].sort(); + + const hasDefaultVmEffector = computePeerEffectors.includes( + DEFAULT_VM_EFFECTOR_CID, + ); + + if ( + noxConfig.vm?.network.publicIp !== undefined && + !hasDefaultVmEffector + ) { + return `Compute peer ${color.yellow( + computePeerName, + )} has a defined publicIp property:\n\nvm:\n network:\n publicIp: ${noxConfig.vm.network.publicIp}\n\nso it is expected to also have a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}`; + } + + if ( + noxConfig.vm?.network.publicIp === undefined && + hasDefaultVmEffector + ) { + return `Compute peer ${color.yellow( + computePeerName, + )} has a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}\n\nso it is expected to also have a defined publicIp property:\n\nvm:\n network:\n publicIp: `; + } + + const computePeerEffectorsString = + jsonStringify(computePeerEffectors); + + if (computePeerEffectorsString !== offerEffectorsString) { + return `Offer ${color.yellow( + offerName, + )} contains computePeer ${color.yellow( + computePeerName, + )}, that has effectors ${color.yellow( + computePeerEffectorsString, + )} which doesn't match effectors that are specified in the offer ${color.yellow( + offerEffectorsString, + )}`; + } + + return true; + }); + }, + ), + ) + ).filter((result): result is string => { + return typeof result === "string"; + }); + + return errors.length > 0 ? errors.join("\n\n") : true; +} + +function validateNoDuplicateNoxNamesInOffers(config: Config): ValidationResult { + const noxNamesInOffers: Record = {}; + + Object.entries(config.offers).forEach(([offerName, { computePeers }]) => { + computePeers.forEach((noxName) => { + const arr = noxNamesInOffers[noxName]; + + if (arr === undefined) { + noxNamesInOffers[noxName] = [offerName]; + } else { + arr.push(offerName); + } + }); + }); + + const duplicateNoxNames = Object.entries(noxNamesInOffers).filter( + ([, offerNames]) => { + return offerNames.length > 1; + }, + ); + + if (duplicateNoxNames.length > 0) { + return duplicateNoxNames + .map(([noxName, offerNames]) => { + return `Nox ${color.yellow( + noxName, + )} is present in multiple offers: ${color.yellow( + offerNames.join(", "), + )}`; + }) + .join("\n"); + } + + return true; +} + +async function validateCC(config: Config): Promise { + const validateCCDuration = await ccDurationValidator(); + + const capacityCommitmentErrors = ( + await Promise.all( + Object.entries(config.capacityCommitments).map(async ([name, cc]) => { + const errors = [ + cc.delegator === undefined + ? true + : await validateAddress(cc.delegator), + validateCCDuration(cc.duration), + ].filter((e) => { + return e !== true; + }); + + return errors.length === 0 + ? true + : `Invalid capacity commitment for ${color.yellow( + name, + )}:\n${errors.join("\n")}`; + }), + ) + ).filter((e) => { + return e !== true; + }); + + if (capacityCommitmentErrors.length > 0) { + return capacityCommitmentErrors.join("\n\n"); + } + + return true; +} + +function validateMissingComputePeers(config: Config): ValidationResult { + const missingComputePeerNamesInOffer: Array<{ + offerName: string; + missingComputePeerNames: Array; + }> = []; + + if (isEmpty(config.computePeers)) { + return `There should be at least one computePeer defined in the config`; + } + + const offers = Object.entries(config.offers); + + if (offers.length === 0) { + return `There should be at least one offer defined in the config`; + } + + // Checking that all computePeers referenced in offers are defined + for (const [offerName, { computePeers }] of offers) { + const missingComputePeerNames = computePeers.filter((cp) => { + return !(cp in config.computePeers); + }); + + if (missingComputePeerNames.length > 0) { + missingComputePeerNamesInOffer.push({ + offerName, + missingComputePeerNames, + }); + } + } + + if (missingComputePeerNamesInOffer.length > 0) { + return missingComputePeerNamesInOffer + .map(({ offerName, missingComputePeerNames }) => { + return `Offer ${color.yellow( + offerName, + )} has computePeers missing from the config's top level computePeers property: ${color.yellow( + missingComputePeerNames.join(", "), + )}`; + }) + .join("\n"); + } + + return true; +} + +function mergeConfigYAML(a: T, b: Record) { + return mergeWith(cloneDeep(a), b, (objValue, srcValue) => { + if (Array.isArray(objValue) && Array.isArray(srcValue)) { + return srcValue; + } + + return undefined; + }); +} + +export function mergeConfigYAMLWithRawConfig< + T extends { rawConfig?: string | undefined } & Record, +>(a: T, b: T) { + const { rawConfig: rawConfigB, ...configB } = b; + let config = mergeConfigYAML(a, configB); + + const parsedRawConfigB = + rawConfigB === undefined ? undefined : parse(rawConfigB); + + if (parsedRawConfigB !== undefined) { + config = mergeConfigYAML(config, parsedRawConfigB); + } + + return config; +} + +export async function resolveNoxConfigYAML( + globalNoxConfig: NoxConfigYAML | undefined = {}, + computePeerNoxConfig: NoxConfigYAML | undefined = {}, + { i = 0, signingWallet = "" }: { i?: number; signingWallet?: string } = {}, +) { + const env = await ensureChainEnv(); + const isLocal = env === "local"; + + let config = mergeConfigYAMLWithRawConfig( + await getDefaultNoxConfigYAML(), + globalNoxConfig, + ); + + config = mergeConfigYAMLWithRawConfig(config, computePeerNoxConfig); + + /* eslint-disable @typescript-eslint/consistent-type-assertions */ + + const tcpPort = + (config["tcp_port"] as number | undefined) ?? + config.tcpPort ?? + (isLocal ? TCP_PORT_START - i : TCP_PORT_START); + + const websocketPort = + (config["websocket_port"] as number | undefined) ?? + config.websocketPort ?? + (isLocal ? WEB_SOCKET_PORT_START - i : WEB_SOCKET_PORT_START); + + const httpPort = + (config["http_port"] as number | undefined) ?? + config.httpPort ?? + (isLocal ? HTTP_PORT_START - i : HTTP_PORT_START); + + const walletPrivateKey = + // @ts-expect-error we allow user to put anything in raw config + (config["chain_config"]?.["wallet_key"] as string | undefined) ?? + config.chain?.walletPrivateKey ?? + signingWallet; + + /* eslint-enable @typescript-eslint/consistent-type-assertions */ + + if (config.chain?.walletPrivateKey === undefined) { + config.chain = { ...config.chain, walletPrivateKey }; + } + + let ipfs: undefined | NoxConfigYAML["ipfs"]; + // eslint-disable-next-line prefer-const + ({ ipfs, ...config } = config); + + config.systemServices = { + ...config.systemServices, + aquaIpfs: { + ...config.systemServices?.aquaIpfs, + externalApiMultiaddr: + config.systemServices?.aquaIpfs?.externalApiMultiaddr ?? + ipfs?.externalApiMultiaddr ?? + EXTERNAL_API_MULTIADDRS[env], + localApiMultiaddr: + config.systemServices?.aquaIpfs?.localApiMultiaddr ?? + ipfs?.localApiMultiaddr ?? + LOCAL_API_MULTIADDRS[env], + ipfsBinaryPath: + config.systemServices?.aquaIpfs?.ipfsBinaryPath ?? + ipfs?.ipfsBinaryPath ?? + DEFAULT_IPFS_BINARY_PATH, + }, + }; + + return { ...config, tcpPort, websocketPort, httpPort }; +} + +const EXTERNAL_API_MULTIADDRS: Record = { + mainnet: "/dns4/ipfs.kras.fluence.dev/tcp/5020", + testnet: "/dns4/ipfs.dar.fluence.dev/tcp/5020", + stage: "/dns4/ipfs.fluence.dev/tcp/5001", + local: LOCAL_IPFS_ADDRESS, +}; + +export const NOX_IPFS_MULTIADDR = `/dns4/${IPFS_CONTAINER_NAME}/tcp/${IPFS_PORT}`; + +const LOCAL_API_MULTIADDRS: Record = { + ...EXTERNAL_API_MULTIADDRS, + local: NOX_IPFS_MULTIADDR, +}; + +export async function getDefaultNoxConfigYAML(): Promise { + const env = await ensureChainEnv(); + const networkId = await getChainId(); + const { RPC_URLS } = await import("@fluencelabs/deal-ts-clients"); + const envConfig = await initEnvConfig(); + + const CHAIN_URLS_FOR_CONTAINERS = { + ...RPC_URLS, + local: `http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, + }; + + return { + aquavmPoolSize: DEFAULT_AQUAVM_POOL_SIZE, + ipfs: { + externalApiMultiaddr: EXTERNAL_API_MULTIADDRS[env], + localApiMultiaddr: LOCAL_API_MULTIADDRS[env], + ipfsBinaryPath: DEFAULT_IPFS_BINARY_PATH, + }, + systemServices: { + enable: ["aqua-ipfs", "decider"], + decider: { + deciderPeriodSec: 30, + workerIpfsMultiaddr: + env === "local" + ? NOX_IPFS_MULTIADDR + : "/dns4/ipfs.fluence.dev/tcp/5001", + }, + }, + chain: { + httpEndpoint: + envConfig?.rpcUrl === undefined + ? CHAIN_URLS_FOR_CONTAINERS[env] + : envConfig.rpcUrl, + wsEndpoint: WS_CHAIN_URLS[env], + diamondContract: (await resolveDeployment()).diamond, + networkId, + defaultPriorityFee: 0, + }, + ccp: { + proofPollPeriod: DEFAULT_PROOF_POLL_PERIOD, + }, + ...(env === "local" + ? {} + : { bootstrapNodes: await resolveRelaysWithoutLocal(env) }), + metrics: { + enabled: true, + timerResolution: DEFAULT_TIMER_RESOLUTION, + tokioMetricsEnabled: true, + }, + }; +} diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts.ts deleted file mode 100644 index 4f49081a6..000000000 --- a/packages/cli/package/src/lib/configs/project/providerArtifacts.ts +++ /dev/null @@ -1,366 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { join } from "path"; - -import type { JSONSchemaType } from "ajv"; - -import { ajv, validationErrorToString } from "../../ajvInstance.js"; -import { - TOP_LEVEL_SCHEMA_ID, - PROVIDER_ARTIFACTS_CONFIG_FILE_NAME, - PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, - type FluenceEnvOld, - isFluenceEnvOld, - type FluenceEnv, - fluenceOldEnvToNewEnv, -} from "../../const.js"; -import { numToStr } from "../../helpers/typesafeStringify.js"; -import { - ensureProviderArtifactsConfigPath, - getFluenceDir, -} from "../../paths.js"; -import { input } from "../../prompt.js"; -import { fluenceEnvOldPrompt } from "../../resolveFluenceEnv.js"; -import { - getConfigInitFunction, - getReadonlyConfigInitFunction, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, - type InitConfigOptions, -} from "../initConfig.js"; - -type OfferConfigV0 = { - id: string; -}; - -type ConfigV0 = { - version: 0; - offers: Record; -}; - -const offerConfigV1 = { - type: "object", - additionalProperties: false, - description: "Created offer info", - properties: { - id: { type: "string", description: "Offer id" }, - }, - required: ["id"], -} as const satisfies JSONSchemaType; - -const configSchemaV0: JSONSchemaType = { - description: `Defines artifacts created by the provider`, - type: "object", - additionalProperties: false, - properties: { - version: { type: "integer", const: 0, description: "Config version" }, - offers: { - type: "object", - description: "Created offers", - additionalProperties: offerConfigV1, - properties: { - noxName: offerConfigV1, - }, - required: [], - }, - }, - required: ["version", "offers"], -}; - -type ConfigV1 = { - version: 1; - offers: Partial>>; -}; - -const offersConfigV1 = { - type: "object", - description: "Created offers", - additionalProperties: offerConfigV1, - properties: { - noxName: offerConfigV1, - }, - required: [], - nullable: true, -} as const satisfies JSONSchemaType>; - -const configSchemaV1: JSONSchemaType = { - type: "object", - additionalProperties: false, - properties: { - version: { type: "integer", const: 1, description: "Config version" }, - offers: { - type: "object", - description: "Created offers", - additionalProperties: false, - properties: { - dar: offersConfigV1, - custom: offersConfigV1, - kras: offersConfigV1, - local: offersConfigV1, - stage: offersConfigV1, - }, - required: [], - }, - }, - required: ["version", "offers"], -}; - -type OfferConfigV2 = { - id: string; - providerAddress: string; -}; - -type ConfigV2 = { - version: 2; - offers: Partial>>; -}; - -const offerConfigV2 = { - type: "object", - additionalProperties: false, - properties: { - id: { type: "string", description: "Offer id" }, - providerAddress: { - type: "string", - description: "Provider address", - }, - }, - required: ["id", "providerAddress"], -} as const satisfies JSONSchemaType; - -const offersConfigV2 = { - type: "object", - description: "Created offers", - additionalProperties: offerConfigV2, - properties: { - noxName: offerConfigV2, - }, - required: [], - nullable: true, -} as const satisfies JSONSchemaType>; - -const configSchemaV2: JSONSchemaType = { - description: `Defines artifacts created by the provider`, - type: "object", - additionalProperties: false, - properties: { - version: { type: "integer", const: 2, description: "Config version" }, - offers: { - type: "object", - description: "Created offers", - additionalProperties: false, - properties: { - dar: offersConfigV2, - custom: offersConfigV2, - kras: offersConfigV2, - local: offersConfigV2, - stage: offersConfigV2, - }, - required: [], - }, - }, - required: ["version", "offers"], -}; - -type ConfigV3 = { - version: 3; - offers: Partial>>; -}; - -const configSchemaV3 = { - description: `Defines artifacts created by the provider`, - type: "object", - additionalProperties: false, - properties: { - version: { type: "integer", const: 3, description: "Config version" }, - offers: { - type: "object", - description: "Created offers", - additionalProperties: false, - properties: { - testnet: offersConfigV2, - custom: offersConfigV2, - mainnet: offersConfigV2, - local: offersConfigV2, - stage: offersConfigV2, - }, - required: [], - }, - }, - required: ["version", "offers"], -} as const satisfies JSONSchemaType; - -const latestSchemaObj = { - $id: `${TOP_LEVEL_SCHEMA_ID}/${PROVIDER_ARTIFACTS_CONFIG_FILE_NAME}`, - title: PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, - ...configSchemaV3, -} as const satisfies JSONSchemaType; - -const latestSchema: JSONSchemaType = latestSchemaObj; - -const validateConfigSchemaV0 = ajv.compile(configSchemaV0); -const validateConfigSchemaV1 = ajv.compile(configSchemaV1); -const validateConfigSchemaV2 = ajv.compile(configSchemaV2); - -const migrations: Migrations = [ - async (config: Config): Promise => { - if (!validateConfigSchemaV0(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const configPath = join( - getFluenceDir(), - PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, - ); - - const offers: ConfigV1["offers"] = {}; - - for (const [offerName, offer] of Object.entries(config.offers)) { - const env = await fluenceEnvOldPrompt( - `Select the environment that you used for creating offer ${offerName} with offerId: ${offer.id} at ${configPath}`, - ); - - const dealsForEnv = offers[env] ?? {}; - dealsForEnv[offerName] = offer; - offers[env] = dealsForEnv; - } - - return { version: 1, offers }; - }, - async (config: Config): Promise => { - if (!validateConfigSchemaV1(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const configPath = join( - getFluenceDir(), - PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, - ); - - const newConfig: ConfigV2 = { - version: 2, - offers: {}, - }; - - for (const [env, configPerEnv] of Object.entries(config.offers)) { - if (!isFluenceEnvOld(env)) { - throw new Error( - `Unreachable. Migration error. Unknown env ${env} in ${PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME}`, - ); - } - - const newConfigPerEnv: Record = {}; - - for (const [offerName, offer] of Object.entries(configPerEnv)) { - const providerAddress = await input({ - message: `Enter provider address that was used when creating offer ${offerName} with offerId: ${offer.id} at ${configPath}`, - }); - - newConfigPerEnv[offerName] = { ...offer, providerAddress }; - } - - newConfig.offers[env] = newConfigPerEnv; - } - - return newConfig; - }, - async (config: Config): Promise => { - if (!validateConfigSchemaV2(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const newConfig: ConfigV3 = { - version: 3, - offers: {}, - }; - - for (const [env, configPerEnv] of Object.entries(config.offers)) { - if (Object.keys(configPerEnv).length === 0) { - continue; - } - - if (!isFluenceEnvOld(env)) { - throw new Error( - `Unreachable. Migration error. Unknown env ${env} in ${PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME}`, - ); - } - - newConfig.offers[fluenceOldEnvToNewEnv(env)] = configPerEnv; - } - - return newConfig; - }, -]; - -type Config = ConfigV0 | ConfigV1 | ConfigV2 | ConfigV3; -type LatestConfig = ConfigV3; -export type ProviderArtifactsConfig = InitializedConfig; -export type ProviderArtifactsConfigReadonly = - InitializedReadonlyConfig; - -function getInitConfigOptions(): InitConfigOptions { - return { - allSchemas: [configSchemaV0, configSchemaV1, configSchemaV2, latestSchema], - latestSchema, - migrations, - name: PROVIDER_ARTIFACTS_CONFIG_FILE_NAME, - getConfigOrConfigDirPath: () => { - return ensureProviderArtifactsConfigPath(); - }, - getSchemaDirPath: getFluenceDir, - }; -} - -export function initReadonlyProviderArtifactsConfig() { - return getReadonlyConfigInitFunction(getInitConfigOptions())(); -} - -export async function initNewReadonlyProviderArtifactsConfig() { - return getReadonlyConfigInitFunction(getInitConfigOptions(), () => { - return getDefault(); - })(); -} - -export async function initNewProviderArtifactsConfig() { - return getConfigInitFunction(getInitConfigOptions(), () => { - return getDefault(); - })(); -} - -function getDefault() { - return ` -version: ${numToStr(latestSchemaObj.properties.version.const)} -offers: {} -`; -} - -export const providerArtifactsSchema: JSONSchemaType = - latestSchema; diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts.ts new file mode 100644 index 000000000..55b9e68e4 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts.ts @@ -0,0 +1,52 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { + ensureProviderArtifactsConfigPath, + getFluenceDir, +} from "../../../paths.js"; +import { getConfigInitFunction } from "../../initConfigNew.js"; +import { type InitConfigOptions } from "../../initConfigNewTypes.js"; + +import configOptions0, { + type Config as Config0, +} from "./providerArtifacts0.js"; +import configOptions1, { + type Config as Config1, +} from "./providerArtifacts1.js"; +import configOptions2, { + type Config as Config2, +} from "./providerArtifacts2.js"; +import configOptions3, { + type Config as Config3, +} from "./providerArtifacts3.js"; + +export const options: InitConfigOptions = { + description: "Defines artifacts created by the provider", + options: [configOptions0, configOptions1, configOptions2, configOptions3], + getConfigPath: ensureProviderArtifactsConfigPath, + getSchemaDirPath: getFluenceDir, +}; + +export const initNewProviderArtifactsConfig = getConfigInitFunction( + options, + () => { + return { offers: {} }; + }, +); + +export const initProviderArtifactsConfig = getConfigInitFunction(options); diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts0.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts0.ts new file mode 100644 index 000000000..12fd59b60 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts0.ts @@ -0,0 +1,52 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +export type OfferConfig = { id: string }; + +export const offerConfig = { + type: "object", + additionalProperties: false, + description: "Created offer info", + properties: { id: { type: "string", description: "Offer id" } }, + required: ["id"], +} as const satisfies JSONSchemaType; + +type Offers = Record; +export type Config = { offers: Offers }; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + offers: { + type: "object", + description: "Created offers", + additionalProperties: offerConfig, + properties: { + noxName: offerConfig, + }, + required: [], + }, + }, + required: ["offers"], + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts1.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts1.ts new file mode 100644 index 000000000..c10261c5a --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts1.ts @@ -0,0 +1,80 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import type { FluenceEnvOld } from "../../../const.js"; +import { fluenceEnvOldPrompt } from "../../../resolveFluenceEnv.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import { + type Config as PrevConfig, + type OfferConfig, + offerConfig, +} from "./providerArtifacts0.js"; + +type OffersConfig = Record; + +const offersConfig = { + type: "object", + description: "Created offers", + additionalProperties: offerConfig, + properties: { noxName: offerConfig }, + required: [], + nullable: true, +} as const satisfies JSONSchemaType; + +type Offers = Partial>; +export type Config = { offers: Offers }; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + offers: { + type: "object", + description: "Created offers", + additionalProperties: false, + properties: { + dar: offersConfig, + custom: offersConfig, + kras: offersConfig, + local: offersConfig, + stage: offersConfig, + }, + required: [], + }, + }, + required: ["offers"], + }, + async migrate(config) { + const offers: Offers = {}; + + for (const [offerName, offer] of Object.entries(config.offers)) { + const env = await fluenceEnvOldPrompt( + `Select the environment that you previously used for creating offer ${offerName} with offerId: ${offer.id}`, + ); + + const dealsForEnv = offers[env] ?? {}; + dealsForEnv[offerName] = offer; + offers[env] = dealsForEnv; + } + + return { offers }; + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts2.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts2.ts new file mode 100644 index 000000000..0938332f6 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts2.ts @@ -0,0 +1,105 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import { + isFluenceEnvOld, + PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, + type FluenceEnvOld, +} from "../../../const.js"; +import { input } from "../../../prompt.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import type { Config as PrevConfig } from "./providerArtifacts1.js"; + +type OfferConfig = { id: string; providerAddress: string }; + +const offerConfig = { + type: "object", + additionalProperties: false, + properties: { + id: { type: "string", description: "Offer id" }, + providerAddress: { + type: "string", + description: "Provider address", + }, + }, + required: ["id", "providerAddress"], +} as const satisfies JSONSchemaType; + +export type OffersConfig = Record; + +export const offersConfig = { + type: "object", + description: "Created offers", + additionalProperties: offerConfig, + properties: { noxName: offerConfig }, + required: [], + nullable: true, +} as const satisfies JSONSchemaType; + +type Offers = Partial>; +export type Config = { offers: Offers }; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + offers: { + type: "object", + description: "Created offers", + additionalProperties: false, + properties: { + dar: offersConfig, + custom: offersConfig, + kras: offersConfig, + local: offersConfig, + stage: offersConfig, + }, + required: [], + }, + }, + required: ["offers"], + }, + async migrate(config) { + const newConfig: Config = { offers: {} }; + + for (const [env, configPerEnv] of Object.entries(config.offers)) { + if (!isFluenceEnvOld(env)) { + throw new Error( + `Unreachable. Migration error. Unknown env ${env} in ${PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME}`, + ); + } + + const newConfigPerEnv: OffersConfig = {}; + + for (const [offerName, offer] of Object.entries(configPerEnv)) { + const providerAddress = await input({ + message: `Enter provider wallet address that you previously used when creating offer ${offerName} with offerId: ${offer.id}`, + }); + + newConfigPerEnv[offerName] = { ...offer, providerAddress }; + } + + newConfig.offers[env] = newConfigPerEnv; + } + + return newConfig; + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts3.ts b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts3.ts new file mode 100644 index 000000000..04fe912d0 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerArtifacts/providerArtifacts3.ts @@ -0,0 +1,75 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { + fluenceOldEnvToNewEnv, + isFluenceEnvOld, + PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, + type FluenceEnv, +} from "../../../const.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +import { + offersConfig, + type OffersConfig, + type Config as PrevConfig, +} from "./providerArtifacts2.js"; + +type Offers = Partial>; +export type Config = { offers: Offers }; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + offers: { + type: "object", + description: "Created offers", + additionalProperties: false, + properties: { + testnet: offersConfig, + custom: offersConfig, + mainnet: offersConfig, + local: offersConfig, + stage: offersConfig, + }, + required: [], + }, + }, + required: ["offers"], + }, + migrate(config) { + const newConfig: Config = { offers: {} }; + + for (const [env, configPerEnv] of Object.entries(config.offers)) { + if (Object.keys(configPerEnv).length === 0) { + continue; + } + + if (!isFluenceEnvOld(env)) { + throw new Error( + `Unreachable. Migration error. Unknown env ${env} in ${PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME}`, + ); + } + + newConfig.offers[fluenceOldEnvToNewEnv(env)] = configPerEnv; + } + + return newConfig; + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/project/providerSecrets.ts b/packages/cli/package/src/lib/configs/project/providerSecrets.ts deleted file mode 100644 index ba5b19ab1..000000000 --- a/packages/cli/package/src/lib/configs/project/providerSecrets.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import type { JSONSchemaType } from "ajv"; -import { yamlDiffPatch } from "yaml-diff-patch"; - -import { - TOP_LEVEL_SCHEMA_ID, - PROVIDER_SECRETS_CONFIG_FULL_FILE_NAME, - PROVIDER_SECRETS_CONFIG_FILE_NAME, -} from "../../const.js"; -import { genSecretKeyOrReturnExisting } from "../../keyPairs.js"; -import { ensureProviderSecretsConfigPath, getFluenceDir } from "../../paths.js"; -import { - getConfigInitFunction, - getReadonlyConfigInitFunction, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, - type InitConfigOptions, -} from "../initConfig.js"; - -import type { ProviderConfigReadonly } from "./provider.js"; - -type SecretsConfig = { - networkKey: string; - signingWallet: string; -}; - -type ConfigV0 = { - version: 0; - noxes: Record; -}; - -const secretesConfig = { - type: "object", - additionalProperties: false, - description: - "Secret keys for noxes. You can put it near provider config and populate it in CI", - properties: { - networkKey: { - type: "string", - description: "Network key for the nox", - }, - signingWallet: { - type: "string", - format: "hex", - description: "Signing wallet for built-in decider system service in nox", - }, - }, - required: ["networkKey", "signingWallet"], -} as const satisfies JSONSchemaType; - -const configSchemaV0 = { - $id: `${TOP_LEVEL_SCHEMA_ID}/${PROVIDER_SECRETS_CONFIG_FULL_FILE_NAME}`, - title: PROVIDER_SECRETS_CONFIG_FULL_FILE_NAME, - description: `Defines secrets config used for provider set up`, - type: "object", - additionalProperties: false, - properties: { - version: { type: "integer", const: 0, description: "Config version" }, - noxes: { - type: "object", - description: "Secret keys for noxes by name", - additionalProperties: secretesConfig, - properties: { - noxName: secretesConfig, - }, - required: [], - }, - }, - required: ["version", "noxes"], -} as const satisfies JSONSchemaType; - -const latestSchema = configSchemaV0 satisfies JSONSchemaType; - -const migrations: Migrations = []; - -type Config = ConfigV0; -type LatestConfig = ConfigV0; -export type ProviderSecretesConfig = InitializedConfig; -export type ProviderSecretesConfigReadonly = - InitializedReadonlyConfig; - -function getInitConfigOptions(): InitConfigOptions { - return { - allSchemas: [configSchemaV0], - latestSchema, - migrations, - name: PROVIDER_SECRETS_CONFIG_FILE_NAME, - getConfigOrConfigDirPath: () => { - return ensureProviderSecretsConfigPath(); - }, - getSchemaDirPath: getFluenceDir, - }; -} - -export function initReadonlyProviderSecretsConfig() { - return getReadonlyConfigInitFunction(getInitConfigOptions())(); -} - -export async function initNewReadonlyProviderSecretsConfig( - providerConfig: ProviderConfigReadonly, -) { - return getReadonlyConfigInitFunction(getInitConfigOptions(), () => { - return getDefault(providerConfig); - })(); -} - -export async function initNewProviderSecretsConfig( - providerConfig: ProviderConfigReadonly, -) { - return getConfigInitFunction(getInitConfigOptions(), () => { - return getDefault(providerConfig); - })(); -} - -async function getDefault(providerConfig: ProviderConfigReadonly) { - const { Wallet } = await import("ethers"); - - const noxes: Record = Object.fromEntries( - await Promise.all( - Object.keys(providerConfig.computePeers).map(async (name) => { - return [ - name, - { - networkKey: (await genSecretKeyOrReturnExisting(name)).secretKey, - signingWallet: Wallet.createRandom().privateKey, - }, - ] as const; - }), - ), - ); - - return yamlDiffPatch( - "", - {}, - { version: latestSchema.properties.version.const, noxes }, - ); -} - -export const providerSecretsSchema: JSONSchemaType = latestSchema; diff --git a/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets.ts b/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets.ts new file mode 100644 index 000000000..f032bcb50 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets.ts @@ -0,0 +1,59 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { genSecretKeyOrReturnExisting } from "../../../keyPairs.js"; +import { + ensureProviderSecretsConfigPath, + getFluenceDir, +} from "../../../paths.js"; +import { getConfigInitFunction } from "../../initConfigNew.js"; +import { type InitConfigOptions } from "../../initConfigNewTypes.js"; +import type { ProviderConfig } from "../provider/provider.js"; + +import configOptions0, { type Config as Config0 } from "./providerSecrets0.js"; + +export const options: InitConfigOptions = { + description: "Defines secrets config used for provider set up", + options: [configOptions0], + getConfigPath: ensureProviderSecretsConfigPath, + getSchemaDirPath: getFluenceDir, +}; + +export async function initNewProviderSecretsConfig( + providerConfig: ProviderConfig, +) { + return getConfigInitFunction(options, async () => { + const { Wallet } = await import("ethers"); + + return { + noxes: Object.fromEntries( + await Promise.all( + Object.keys(providerConfig.computePeers).map(async (name) => { + return [ + name, + { + networkKey: (await genSecretKeyOrReturnExisting(name)) + .secretKey, + signingWallet: Wallet.createRandom().privateKey, + }, + ] as const; + }), + ), + ), + }; + })(); +} diff --git a/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets0.ts b/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets0.ts new file mode 100644 index 000000000..15b37f671 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/providerSecrets/providerSecrets0.ts @@ -0,0 +1,65 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import type { JSONSchemaType } from "ajv"; + +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +type SecretsConfig = { + networkKey: string; + signingWallet: string; +}; + +const secretesConfig = { + type: "object", + additionalProperties: false, + description: + "Secret keys for noxes. You can put it near provider config and populate it in CI", + properties: { + networkKey: { + type: "string", + description: "Network key for the nox", + }, + signingWallet: { + type: "string", + format: "hex", + description: "Signing wallet for built-in decider system service in nox", + }, + }, + required: ["networkKey", "signingWallet"], +} as const satisfies JSONSchemaType; + +export type Config = { + noxes: Record; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + noxes: { + type: "object", + description: "Secret keys for noxes by name", + additionalProperties: secretesConfig, + properties: { noxName: secretesConfig }, + required: [], + }, + }, + required: ["noxes"], + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/user/config.ts b/packages/cli/package/src/lib/configs/user/config.ts deleted file mode 100644 index b2224f28f..000000000 --- a/packages/cli/package/src/lib/configs/user/config.ts +++ /dev/null @@ -1,214 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { rm } from "fs/promises"; - -import type { JSONSchemaType } from "ajv"; - -import { ajv, validationErrorToString } from "../../ajvInstance.js"; -import { - GLOBAL_CONFIG_FILE_NAME, - GLOBAL_CONFIG_FULL_FILE_NAME, - TOP_LEVEL_SCHEMA_ID, - CLI_NAME_FULL, - AUTO_GENERATED, -} from "../../const.js"; -import { - createSecretKey, - genSecretKeyString, - getUserSecretKey, - writeSecretKey, -} from "../../keyPairs.js"; -import { ensureUserFluenceDir } from "../../paths.js"; -import { setUserConfig } from "../globalConfigs.js"; -import { - getConfigInitFunction, - getReadonlyConfigInitFunction, - type InitConfigOptions, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, -} from "../initConfig.js"; - -import { initReadonlyUserSecretsConfig } from "./userSecrets.js"; - -const CHECK_FOR_UPDATES_DISABLED = "disabled"; - -type ConfigV0 = { - version: 0; - countlyConsent: boolean; - docsInConfigs?: boolean; - lastCheckForUpdates?: string; -}; - -const configSchemaV0Obj = { - type: "object", - additionalProperties: false, - properties: { - countlyConsent: { - type: "boolean", - description: "Weather you consent to send usage data to Countly", - }, - lastCheckForUpdates: { - type: "string", - description: `DEPRECATED. It's currently advised to install CLI without using npm (See README.md: https://github.com/fluencelabs/cli?tab=readme-ov-file#installation-and-usage). Last time when ${CLI_NAME_FULL} checked for updates. Updates are checked daily unless this field is set to '${CHECK_FOR_UPDATES_DISABLED}'`, - nullable: true, - }, - docsInConfigs: { - type: "boolean", - description: - "Whether to include commented-out documented config examples in the configs generated with the CLI", - nullable: true, - }, - version: { type: "integer", const: 0 }, - }, - required: ["version", "countlyConsent"], -} as const; - -const configSchemaV0: JSONSchemaType = configSchemaV0Obj; - -type ConfigV1 = Omit & { - version: 1; - defaultSecretKeyName: string; -}; - -const configSchemaV1Obj = { - ...configSchemaV0Obj, - $id: `${TOP_LEVEL_SCHEMA_ID}/${GLOBAL_CONFIG_FULL_FILE_NAME}`, - title: GLOBAL_CONFIG_FULL_FILE_NAME, - description: `Defines global config for ${CLI_NAME_FULL}`, - properties: { - ...configSchemaV0Obj.properties, - version: { type: "integer", const: 1 }, - defaultSecretKeyName: { - type: "string", - description: - "Secret key with this name will be used by default by js-client inside CLI to run Aqua code", - }, - }, - required: [...configSchemaV0Obj.required, "defaultSecretKeyName"], -} as const; - -const configSchemaV1: JSONSchemaType = configSchemaV1Obj; - -function getDefault() { - return `# Defines global config for Fluence CLI - -# config version -version: 1 - -# Weather you consent to send usage data to Countly -countlyConsent: false - -# Whether to include commented-out documented config examples in the configs generated with the CLI -docsInConfigs: false - -# Secret key with this name will be used by default by js-client inside CLI to run Aqua code -defaultSecretKeyName: ${AUTO_GENERATED} - -# # Last time when CLI checked for updates. -# # Updates are checked daily unless this field is set to 'disabled' -# lastCheckForUpdates: 2023-07-07T09:31:00.961Z -`; -} - -const validateConfigSchemaV0 = ajv.compile(configSchemaV0); - -const migrations: Migrations = [ - async (config: Config): Promise => { - if (!validateConfigSchemaV0(config)) { - throw new Error( - `Migration error. Errors: ${await validationErrorToString( - validateConfigSchemaV0.errors, - )}`, - ); - } - - const userSecretsConfig = await initReadonlyUserSecretsConfig(); - - await Promise.all( - (userSecretsConfig?.keyPairs ?? []).map(({ name, secretKey }) => { - return writeSecretKey({ - name, - secretKey, - isUser: true, - }); - }), - ); - - if (userSecretsConfig !== null) { - await rm(userSecretsConfig.$getPath()); - } - - const { defaultKeyPairName } = userSecretsConfig ?? {}; - - if (defaultKeyPairName === undefined) { - await writeSecretKey({ - name: AUTO_GENERATED, - secretKey: await genSecretKeyString(), - isUser: true, - }); - } - - return { - ...config, - version: 1, - defaultSecretKeyName: defaultKeyPairName ?? AUTO_GENERATED, - }; - }, -]; - -type Config = ConfigV0 | ConfigV1; -type LatestConfig = ConfigV1; -export type UserConfig = InitializedConfig; -export type UserConfigReadonly = InitializedReadonlyConfig; - -const initConfigOptions: InitConfigOptions = { - allSchemas: [configSchemaV0, configSchemaV1], - latestSchema: configSchemaV1, - migrations, - name: GLOBAL_CONFIG_FILE_NAME, - getConfigOrConfigDirPath: ensureUserFluenceDir, -}; - -export const initUserConfig = getConfigInitFunction(initConfigOptions); - -export async function initNewUserConfig() { - const userConfig = await getConfigInitFunction( - initConfigOptions, - getDefault, - )(); - - setUserConfig(userConfig); - - const userSecretKey = await getUserSecretKey(AUTO_GENERATED); - - if (userSecretKey === undefined) { - await createSecretKey({ - name: AUTO_GENERATED, - isUser: true, - askToSetKeyAsDefaultInteractively: false, - }); - } - - return userConfig; -} - -export const initReadonlyUserConfig = - getReadonlyConfigInitFunction(initConfigOptions); - -export const userConfigSchema: JSONSchemaType = configSchemaV1; diff --git a/packages/cli/package/src/lib/configs/user/config/config.ts b/packages/cli/package/src/lib/configs/user/config/config.ts new file mode 100644 index 000000000..5dd87ce93 --- /dev/null +++ b/packages/cli/package/src/lib/configs/user/config/config.ts @@ -0,0 +1,75 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { color } from "@oclif/color"; + +import { commandObj, isInteractive } from "../../../commandObj.js"; +import { CLI_NAME_FULL, AUTO_GENERATED } from "../../../const.js"; +import { createSecretKey, getUserSecretKey } from "../../../keyPairs.js"; +import { getUserConfigPath } from "../../../paths.js"; +import { confirm } from "../../../prompt.js"; +import { getConfigInitFunction } from "../../initConfigNew.js"; +import { type InitConfigOptions } from "../../initConfigNewTypes.js"; + +import configOptions0, { type Config as Config0 } from "./config0.js"; +import configOptions1, { type Config as Config1 } from "./config1.js"; + +const getConfigPath = getUserConfigPath; + +export const options: InitConfigOptions = { + description: `Defines global config for ${CLI_NAME_FULL}`, + options: [configOptions0, configOptions1], + getConfigPath, +}; + +export async function initNewUserConfig() { + const userConfig = await getConfigInitFunction(options, async () => { + let countlyConsent = false; + + if ( + isInteractive && + (await confirm({ + message: `Help me improve ${CLI_NAME_FULL} by sending anonymous usage data. I don't collect IDs, names, or other personal data.\n${color.gray( + "Metrics will help the developers know which features are useful so they can prioritize what to work on next. Fluence Labs hosts a Countly instance to record anonymous usage data.", + )}\nOK?`, + })) + ) { + countlyConsent = true; + + commandObj.logToStderr( + `If you change your mind later, modify "countlyConsent" property in ${await getConfigPath()}`, + ); + } + + return { countlyConsent, defaultSecretKeyName: AUTO_GENERATED }; + })(); + + const userSecretKey = await getUserSecretKey(AUTO_GENERATED); + + if (userSecretKey === undefined) { + await createSecretKey({ + name: AUTO_GENERATED, + isUser: true, + askToSetKeyAsDefaultInteractively: false, + userOrProjectConfig: userConfig, + }); + } + + return userConfig; +} + +export type UserConfig = Awaited>; diff --git a/packages/cli/package/src/lib/configs/user/config/config0.ts b/packages/cli/package/src/lib/configs/user/config/config0.ts new file mode 100644 index 000000000..e9124f5f6 --- /dev/null +++ b/packages/cli/package/src/lib/configs/user/config/config0.ts @@ -0,0 +1,43 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { CLI_NAME_FULL } from "../../../const.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; + +export type Config = { + countlyConsent: boolean; + lastCheckForUpdates?: string; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + countlyConsent: { + type: "boolean", + description: "Weather you consent to send usage data to Countly", + }, + lastCheckForUpdates: { + type: "string", + description: `DEPRECATED. It's currently advised to install CLI without using npm (See README.md: https://github.com/fluencelabs/cli?tab=readme-ov-file#installation-and-usage). Last time when ${CLI_NAME_FULL} checked for updates. Updates are checked daily unless this field is set to 'disabled'`, + nullable: true, + }, + }, + required: ["countlyConsent"], + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/configs/user/config/config1.ts b/packages/cli/package/src/lib/configs/user/config/config1.ts new file mode 100644 index 000000000..2ef6029d1 --- /dev/null +++ b/packages/cli/package/src/lib/configs/user/config/config1.ts @@ -0,0 +1,88 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { rm } from "fs/promises"; + +import { commandObj } from "../../../commandObj.js"; +import { AUTO_GENERATED } from "../../../const.js"; +import { genSecretKeyString, writeSecretKey } from "../../../keyPairs.js"; +import type { ConfigOptions } from "../../initConfigNewTypes.js"; +import { initReadonlyUserSecretsConfig } from "../userSecrets.js"; + +import type { Config as PrevConfig } from "./config0.js"; + +export type Config = { + countlyConsent: boolean; + defaultSecretKeyName: string; +}; + +export default { + schema: { + type: "object", + additionalProperties: false, + properties: { + countlyConsent: { + type: "boolean", + description: "Weather you consent to send usage data to Countly", + }, + defaultSecretKeyName: { + type: "string", + description: + "Secret key with this name will be used by default by js-client inside CLI to run Aqua code", + }, + }, + required: ["countlyConsent", "defaultSecretKeyName"], + }, + async migrate({ lastCheckForUpdates, ...config }) { + if (lastCheckForUpdates !== undefined) { + commandObj.log( + `Use of 'lastCheckForUpdates' field is deprecated. It's currently advised to install CLI without using npm`, + ); + } + + const userSecretsConfig = await initReadonlyUserSecretsConfig(); + + await Promise.all( + (userSecretsConfig?.keyPairs ?? []).map(({ name, secretKey }) => { + return writeSecretKey({ + name, + secretKey, + isUser: true, + }); + }), + ); + + if (userSecretsConfig !== null) { + await rm(userSecretsConfig.$getPath()); + } + + const { defaultKeyPairName } = userSecretsConfig ?? {}; + + if (defaultKeyPairName === undefined) { + await writeSecretKey({ + name: AUTO_GENERATED, + secretKey: await genSecretKeyString(), + isUser: true, + }); + } + + return { + ...config, + defaultSecretKeyName: defaultKeyPairName ?? AUTO_GENERATED, + }; + }, +} as const satisfies ConfigOptions; diff --git a/packages/cli/package/src/lib/const.ts b/packages/cli/package/src/lib/const.ts index 32256b40a..a89516a13 100644 --- a/packages/cli/package/src/lib/const.ts +++ b/packages/cli/package/src/lib/const.ts @@ -193,7 +193,7 @@ export const PROVIDER_ARTIFACTS_CONFIG_FILE_NAME = `provider-artifacts`; export const WORKERS_CONFIG_FILE_NAME = `workers`; export const PROJECT_SECRETS_CONFIG_FILE_NAME = `project-secrets`; export const USER_SECRETS_CONFIG_FILE_NAME = `user-secrets`; -export const GLOBAL_CONFIG_FILE_NAME = `config`; +export const USER_CONFIG_FILE_NAME = `config`; export const MODULE_CONFIG_FILE_NAME = `module`; export const SERVICE_CONFIG_FILE_NAME = `service`; export const SPELL_CONFIG_FILE_NAME = `spell`; @@ -207,7 +207,7 @@ export const PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME = `${PROVIDER_ARTIFACTS_CO export const WORKERS_CONFIG_FULL_FILE_NAME = `${WORKERS_CONFIG_FILE_NAME}.${YAML_EXT}`; export const PROJECT_SECRETS_FULL_CONFIG_FILE_NAME = `${PROJECT_SECRETS_CONFIG_FILE_NAME}.${YAML_EXT}`; export const USER_SECRETS_CONFIG_FULL_FILE_NAME = `${USER_SECRETS_CONFIG_FILE_NAME}.${YAML_EXT}`; -export const GLOBAL_CONFIG_FULL_FILE_NAME = `${GLOBAL_CONFIG_FILE_NAME}.${YAML_EXT}`; +export const USER_CONFIG_FULL_FILE_NAME = `${USER_CONFIG_FILE_NAME}.${YAML_EXT}`; export const MODULE_CONFIG_FULL_FILE_NAME = `${MODULE_CONFIG_FILE_NAME}.${YAML_EXT}`; export const SERVICE_CONFIG_FULL_FILE_NAME = `${SERVICE_CONFIG_FILE_NAME}.${YAML_EXT}`; export const SPELL_CONFIG_FULL_FILE_NAME = `${SPELL_CONFIG_FILE_NAME}.${YAML_EXT}`; diff --git a/packages/cli/package/src/lib/countly.ts b/packages/cli/package/src/lib/countly.ts index 7430e8b56..04fbaa812 100644 --- a/packages/cli/package/src/lib/countly.ts +++ b/packages/cli/package/src/lib/countly.ts @@ -21,8 +21,8 @@ import { } from "../errorInterceptor.js"; import { commandObj } from "./commandObj.js"; -import { userConfig } from "./configs/globalConfigs.js"; import type { FluenceConfig } from "./configs/project/fluence.js"; +import { initNewUserConfig } from "./configs/user/config/config.js"; import { IS_DEVELOPMENT } from "./const.js"; import { ensureDir, getUserCountlyDir } from "./paths.js"; @@ -34,6 +34,7 @@ export async function initCountly({ maybeFluenceConfig, }: InitCountlyArgs): Promise { const userCountlyDir = await getUserCountlyDir(); + const userConfig = await initNewUserConfig(); if (!IS_DEVELOPMENT && userConfig.countlyConsent) { const Countly = (await import("countly-sdk-nodejs")).default; diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index f98a8f1b1..0eacaf9e9 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -54,7 +54,7 @@ import { } from "./chain/chainConfig.js"; import { chainFlags } from "./chainFlags.js"; import { commandObj, isInteractive } from "./commandObj.js"; -import { initEnvConfig } from "./configs/project/env.js"; +import { initEnvConfig } from "./configs/project/env/env.js"; import { CLI_NAME_FULL, PRIV_KEY_FLAG_NAME } from "./const.js"; import { dbg } from "./dbg.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; diff --git a/packages/cli/package/src/lib/generateUserProviderConfig.ts b/packages/cli/package/src/lib/generateUserProviderConfig.ts index 4be21efb2..2bb4b18d1 100644 --- a/packages/cli/package/src/lib/generateUserProviderConfig.ts +++ b/packages/cli/package/src/lib/generateUserProviderConfig.ts @@ -23,10 +23,8 @@ import { validateAddress, } from "./chain/chainValidators.js"; import { isInteractive } from "./commandObj.js"; -import type { - UserProvidedConfig, - OfferV1, -} from "./configs/project/provider.js"; +import type { ProviderConfig } from "./configs/project/provider/provider.js"; +import type { Offer } from "./configs/project/provider/provider2.js"; import { defaultNumberProperties, type CurrencyProperty, @@ -44,7 +42,7 @@ import { import { checkboxes, confirm, input } from "./prompt.js"; async function promptToSetNumberProperty( - offer: OfferV1, + offer: Offer, property: CurrencyProperty, ) { const propertyStr = await input({ @@ -64,7 +62,7 @@ export type ProviderConfigArgs = { export async function addComputePeers( numberOfNoxes: number | undefined, - userProvidedConfig: UserProvidedConfig, + providerConfig: ProviderConfig, ) { let computePeersCounter = 0; let isAddingMoreComputePeers = true; @@ -112,13 +110,13 @@ export async function addComputePeers( validate: validatePercent, }); - userProvidedConfig.capacityCommitments[name] = { + providerConfig.capacityCommitments[name] = { duration: capacityCommitmentDuration, delegator: capacityCommitmentDelegator, stakerReward: Number(capacityCommitmentStakerReward), }; - userProvidedConfig.computePeers[name] = { + providerConfig.computePeers[name] = { computeUnits: Number(computeUnitsString), }; @@ -139,7 +137,7 @@ export async function addComputePeers( } while (isAddingMoreComputePeers); } -export async function addOffers(userProvidedConfig: UserProvidedConfig) { +export async function addOffers(providerConfig: ProviderConfig) { let isAddingMoreOffers = true; let offersCounter = 0; @@ -156,7 +154,7 @@ export async function addOffers(userProvidedConfig: UserProvidedConfig) { offersCounter = offersCounter + 1; } - const computePeerOptions = Object.keys(userProvidedConfig.computePeers); + const computePeerOptions = Object.keys(providerConfig.computePeers); const computePeers = isInteractive ? await checkboxes({ @@ -186,7 +184,7 @@ export async function addOffers(userProvidedConfig: UserProvidedConfig) { const effectors = effectorsString === "" ? [] : commaSepStrToArr(effectorsString); - const offer: OfferV1 = { + const offer: Offer = { ...defaultNumberProperties, computePeers, ...(effectors.length > 0 ? { effectors } : {}), @@ -196,7 +194,7 @@ export async function addOffers(userProvidedConfig: UserProvidedConfig) { await promptToSetNumberProperty(offer, numberProperty); } - userProvidedConfig.offers[name] = offer; + providerConfig.offers[name] = offer; isAddingMoreOffers = await confirm({ message: "Do you want to add more offers", diff --git a/packages/cli/package/src/lib/init.ts b/packages/cli/package/src/lib/init.ts index ed8635a96..0d14b4d03 100644 --- a/packages/cli/package/src/lib/init.ts +++ b/packages/cli/package/src/lib/init.ts @@ -70,12 +70,11 @@ import CLIPackageJSON from "../versions/cli.package.json" with { type: "json" }; import { addService } from "./addService.js"; import { compileToFiles } from "./aqua.js"; import { commandObj, isInteractive } from "./commandObj.js"; -import { envConfig, setEnvConfig } from "./configs/globalConfigs.js"; -import { initNewEnvConfig } from "./configs/project/env.js"; +import { initNewEnvConfig, initEnvConfig } from "./configs/project/env/env.js"; import { ensureComputerPeerConfigs, - initNewReadonlyProviderConfig, -} from "./configs/project/provider.js"; + initNewProviderConfig, +} from "./configs/project/provider/provider.js"; import { initNewReadonlyServiceConfig } from "./configs/project/service.js"; import { COMPILE_AQUA_PROPERTY_NAME, @@ -167,16 +166,17 @@ export async function init(options: InitArg = {}): Promise { const fluenceConfig = await initNewFluenceConfig(); await copyDefaultDependencies(); const fluenceEnv = await ensureFluenceEnv(); + const envConfig = await initEnvConfig(); if (envConfig === null) { - setEnvConfig(await initNewEnvConfig(fluenceEnv)); + await initNewEnvConfig(fluenceEnv); } else { envConfig.fluenceEnv = fluenceEnv; await envConfig.$commit(); } if (fluenceEnv === "local") { - await initNewReadonlyProviderConfig(options); + await initNewProviderConfig(options); await ensureComputerPeerConfigs(); } diff --git a/packages/cli/package/src/lib/keyPairs.ts b/packages/cli/package/src/lib/keyPairs.ts index 31454757c..25664658f 100644 --- a/packages/cli/package/src/lib/keyPairs.ts +++ b/packages/cli/package/src/lib/keyPairs.ts @@ -21,13 +21,15 @@ import { join, parse, relative } from "node:path"; import { color } from "@oclif/color"; import { commandObj, isInteractive } from "./commandObj.js"; -import { userConfig } from "./configs/globalConfigs.js"; import { initFluenceConfig, initReadonlyFluenceConfig, type FluenceConfig, } from "./configs/project/fluence.js"; -import type { UserConfig } from "./configs/user/config.js"; +import { + initNewUserConfig, + type UserConfig, +} from "./configs/user/config/config.js"; import { FS_OPTIONS } from "./const.js"; import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; import { bufferToBase64 } from "./helpers/typesafeStringify.js"; @@ -46,15 +48,15 @@ type UpdateSecretKeyArg = { isUser: boolean; }; -async function resolveUserOrProjectConfig( +export async function resolveUserOrProjectConfig( isUser: boolean, ): Promise { - const fluenceConfig = await initFluenceConfig(); - if (isUser) { - return userConfig; + return initNewUserConfig(); } + const fluenceConfig = await initFluenceConfig(); + if (fluenceConfig !== null) { return fluenceConfig; } @@ -80,10 +82,12 @@ export async function writeSecretKey({ export async function createSecretKey({ name, isUser, + userOrProjectConfig, askToSetKeyAsDefaultInteractively = true, -}: UpdateSecretKeyArg & { askToSetKeyAsDefaultInteractively?: boolean }) { - const userOrProjectConfig = await resolveUserOrProjectConfig(isUser); - +}: UpdateSecretKeyArg & { + askToSetKeyAsDefaultInteractively?: boolean; + userOrProjectConfig: UserConfig | FluenceConfig; +}) { const secretsPath = await getSecretsPathForWriting(isUser); const secrets = await getSecretKeys(isUser); @@ -307,7 +311,9 @@ export async function getUserSecretKey( secretKeyName: string | undefined, ): Promise { const userSecrets = await getUserSecretKeys(); - return userSecrets[secretKeyName ?? userConfig.defaultSecretKeyName]; + return userSecrets[ + secretKeyName ?? (await initNewUserConfig()).defaultSecretKeyName + ]; } export async function getProjectSecretKey( diff --git a/packages/cli/package/src/lib/lifeCycle.ts b/packages/cli/package/src/lib/lifeCycle.ts index 801bb9b9f..225a98efb 100644 --- a/packages/cli/package/src/lib/lifeCycle.ts +++ b/packages/cli/package/src/lib/lifeCycle.ts @@ -22,14 +22,12 @@ import { color } from "@oclif/color"; import { setChainFlags } from "./chainFlags.js"; import { commandObj, - isInteractive, setCommandObjAndIsInteractive, type CommandObj, } from "./commandObj.js"; -import { setEnvConfig, setUserConfig } from "./configs/globalConfigs.js"; -import { initEnvConfig, initNewEnvConfig } from "./configs/project/env.js"; +import { initNewEnvConfig } from "./configs/project/env/env.js"; import { initFluenceConfig } from "./configs/project/fluence.js"; -import { initNewUserConfig, initUserConfig } from "./configs/user/config.js"; +import { initNewUserConfig } from "./configs/user/config/config.js"; import { NODE_JS_MAJOR_VERSION, CLI_NAME_FULL, @@ -50,35 +48,9 @@ import { setProjectRootDir, getProviderConfigPath, } from "./paths.js"; -import { confirm } from "./prompt.js"; const NODE_JS_MAJOR_VERSION_STR = numToStr(NODE_JS_MAJOR_VERSION); -const ensureUserConfig = async (): Promise => { - const maybeUserConfig = await initUserConfig(); - const isGeneratingNewUserConfig = maybeUserConfig === null; - const userConfig = maybeUserConfig ?? (await initNewUserConfig()); - - if ( - isGeneratingNewUserConfig && - isInteractive && - (await confirm({ - message: `Help me improve ${CLI_NAME_FULL} by sending anonymous usage data. I don't collect IDs, names, or other personal data.\n${color.gray( - "Metrics will help the developers know which features are useful so they can prioritize what to work on next. Fluence Labs hosts a Countly instance to record anonymous usage data.", - )}\nOK?`, - })) - ) { - userConfig.countlyConsent = true; - await userConfig.$commit(); - - commandObj.logToStderr( - `If you change your mind later, modify "countlyConsent" property in ${userConfig.$getPath()}`, - ); - } - - setUserConfig(userConfig); -}; - export async function initCli< T extends { args: unknown; @@ -115,22 +87,16 @@ export async function initCli< ); } - await ensureUserConfig(); + await initNewUserConfig(); if (requiresFluenceProject) { - setEnvConfig(await initNewEnvConfig()); + await initNewEnvConfig(); } else { try { // ensure env config also when provider.yaml exists await access(getProviderConfigPath()); - setEnvConfig(await initNewEnvConfig()); - } catch { - const envConfig = await initEnvConfig(); - - if (envConfig !== null) { - setEnvConfig(envConfig); - } - } + await initNewEnvConfig(); + } catch {} } setChainFlags({ diff --git a/packages/cli/package/src/lib/multiaddres.ts b/packages/cli/package/src/lib/multiaddres.ts index 7c3d54ff7..ae919c04b 100644 --- a/packages/cli/package/src/lib/multiaddres.ts +++ b/packages/cli/package/src/lib/multiaddres.ts @@ -26,9 +26,9 @@ import sample from "lodash-es/sample.js"; import { CHAIN_ENV, jsonStringify } from "../common.js"; import { commandObj } from "./commandObj.js"; -import { envConfig } from "./configs/globalConfigs.js"; +import { initEnvConfig } from "./configs/project/env/env.js"; import { initFluenceConfig } from "./configs/project/fluence.js"; -import { ensureComputerPeerConfigs } from "./configs/project/provider.js"; +import { ensureComputerPeerConfigs } from "./configs/project/provider/provider.js"; import type { FluenceEnv } from "./const.js"; import { numToStr } from "./helpers/typesafeStringify.js"; import { splitErrorsAndResults } from "./helpers/utils.js"; @@ -192,6 +192,7 @@ export async function resolvePeerId(peerIdOrNamedNode: string) { export async function updateRelaysJSON() { const fluenceConfig = await initFluenceConfig(); + const envConfig = await initEnvConfig(); if ( fluenceConfig?.relaysPath === undefined || diff --git a/packages/cli/package/src/lib/multiaddresWithoutLocal.ts b/packages/cli/package/src/lib/multiaddresWithoutLocal.ts index 41ddee3a6..e2fcae904 100644 --- a/packages/cli/package/src/lib/multiaddresWithoutLocal.ts +++ b/packages/cli/package/src/lib/multiaddresWithoutLocal.ts @@ -27,7 +27,7 @@ import { color } from "@oclif/color"; import { type PublicFluenceEnv } from "../common.js"; import { commandObj } from "./commandObj.js"; -import { initEnvConfig } from "./configs/project/env.js"; +import { initEnvConfig } from "./configs/project/env/env.js"; import type { FluenceEnv } from "./const.js"; export function getPeerId(addr: string): string { diff --git a/packages/cli/package/src/lib/paths.ts b/packages/cli/package/src/lib/paths.ts index 559aac5c1..36f86d5f9 100644 --- a/packages/cli/package/src/lib/paths.ts +++ b/packages/cli/package/src/lib/paths.ts @@ -61,6 +61,8 @@ import { CCP_CONFIGS_DIR_NAME, SERVICE_CONFIGS_DIR_NAME, BACKUPS_DIR_NAME, + ENV_CONFIG_FULL_FILE_NAME, + USER_CONFIG_FULL_FILE_NAME, } from "./const.js"; import { recursivelyFindFile } from "./helpers/recursivelyFindFile.js"; import { stringifyUnknown } from "./helpers/utils.js"; @@ -96,6 +98,10 @@ export const ensureUserFluenceDir = (): Promise => { return ensureDir(join(homedir(), DOT_FLUENCE_DIR_NAME)); }; +export async function getUserConfigPath(): Promise { + return join(await ensureUserFluenceDir(), USER_CONFIG_FULL_FILE_NAME); +} + export const getUserCountlyDir = async (): Promise => { return join(await ensureUserFluenceDir(), COUNTLY_DIR_NAME, COUNTLY_DIR_NAME); }; @@ -205,6 +211,10 @@ export const getFluenceDir = (cwd?: string): string => { return join(cwd ?? projectRootDir, DOT_FLUENCE_DIR_NAME); }; +export function getEnvConfigPath(): string { + return join(getFluenceDir(), ENV_CONFIG_FULL_FILE_NAME); +} + const ensureFluenceDir = async (): Promise => { return ensureDir(getFluenceDir()); }; diff --git a/packages/cli/package/src/lib/resolveComputePeersByNames.ts b/packages/cli/package/src/lib/resolveComputePeersByNames.ts index f1fe80784..75e3a8779 100644 --- a/packages/cli/package/src/lib/resolveComputePeersByNames.ts +++ b/packages/cli/package/src/lib/resolveComputePeersByNames.ts @@ -23,7 +23,7 @@ import { ensureComputerPeerConfigs, ensureReadonlyProviderConfig, type EnsureComputerPeerConfig, -} from "./configs/project/provider.js"; +} from "./configs/project/provider/provider.js"; import { NOX_NAMES_FLAG_NAME, ALL_FLAG_VALUE, diff --git a/packages/cli/package/src/lib/resolveFluenceEnv.ts b/packages/cli/package/src/lib/resolveFluenceEnv.ts index d67bf47bb..7104d2cb8 100644 --- a/packages/cli/package/src/lib/resolveFluenceEnv.ts +++ b/packages/cli/package/src/lib/resolveFluenceEnv.ts @@ -21,7 +21,7 @@ import { CHAIN_ENV, DEFAULT_PUBLIC_FLUENCE_ENV } from "../common.js"; import { chainFlags } from "./chainFlags.js"; import { commandObj } from "./commandObj.js"; -import { envConfig } from "./configs/globalConfigs.js"; +import { initEnvConfig } from "./configs/project/env/env.js"; import { ENV_FLAG_NAME, FLUENCE_ENVS_OLD, @@ -41,6 +41,7 @@ export async function ensureFluenceEnv(): Promise { } const fluenceEnvFromFlags = await ensureValidFluenceEnvFlag(chainFlags.env); + const envConfig = await initEnvConfig(); const fluenceEnv = fluenceEnvFromFlags ?? envConfig?.fluenceEnv; if (fluenceEnv !== undefined) { diff --git a/packages/cli/package/test/tests/provider.test.ts b/packages/cli/package/test/tests/provider.test.ts index e3735415e..55b8e0dd5 100644 --- a/packages/cli/package/test/tests/provider.test.ts +++ b/packages/cli/package/test/tests/provider.test.ts @@ -21,8 +21,13 @@ import { join } from "node:path"; import { describe } from "vitest"; import { LOCAL_NET_DEFAULT_ACCOUNTS } from "../../src/common.js"; -import { initProviderConfigWithPath } from "../../src/lib/configs/project/provider.js"; -import { OFFER_FLAG_NAME, PRIV_KEY_FLAG_NAME } from "../../src/lib/const.js"; +import { getConfigInitFunction } from "../../src/lib/configs/initConfigNew.js"; +import { options as providerConfigOptions } from "../../src/lib/configs/project/provider/provider.js"; +import { + OFFER_FLAG_NAME, + PRIV_KEY_FLAG_NAME, + PROVIDER_CONFIG_FULL_FILE_NAME, +} from "../../src/lib/const.js"; import { numToStr } from "../../src/lib/helpers/typesafeStringify.js"; import { stringifyUnknown } from "../../src/lib/helpers/utils.js"; import { fluence } from "../helpers/commonWithSetupTests.js"; @@ -34,6 +39,15 @@ const PRIV_KEY_1 = { [PRIV_KEY_FLAG_NAME]: LOCAL_NET_DEFAULT_ACCOUNTS[1].privateKey, }; +async function initProviderConfigWithPath(path: string) { + return getConfigInitFunction({ + ...providerConfigOptions, + getConfigPath() { + return join(path, PROVIDER_CONFIG_FULL_FILE_NAME); + }, + })(); +} + describe("provider tests", () => { wrappedTest( "should be able to register and update provider with a new name", diff --git a/yarn.lock b/yarn.lock index 371276064..82ebd1d5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1006,7 +1006,6 @@ __metadata: "@vitejs/plugin-react-swc": "npm:3.7.0" buffer: "npm:^6.0.3" eslint: "npm:9.10.0" - hotscript: "npm:1.0.13" npm-check-updates: "npm:^17.1.1" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" @@ -4668,13 +4667,6 @@ __metadata: languageName: node linkType: hard -"hotscript@npm:1.0.13": - version: 1.0.13 - resolution: "hotscript@npm:1.0.13" - checksum: 10c0/423ea2aa437befeeffc32ea5a364b0d833f442fecdd7531c6fe8dc3df092c58d31145f757ad505ec7629ce4bb0eb8ff58889c8a58fe36312f975ff682f5cd422 - languageName: node - linkType: hard - "http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" From 38455bc14c42f6cb6879c6e2a0b453eb23c441aa Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 10:46:35 +0100 Subject: [PATCH 02/37] fix circular dependency --- .../cli/package/src/commands/key/default.ts | 2 +- packages/cli/package/src/commands/key/new.ts | 6 +- .../cli/package/src/commands/key/remove.ts | 2 +- packages/cli/package/src/lib/commandObj.ts | 1 + .../src/lib/configs/user/config/config.ts | 16 +- packages/cli/package/src/lib/jsClient.ts | 3 +- packages/cli/package/src/lib/keyPairs.ts | 272 +---------------- packages/cli/package/src/lib/secretKeys.ts | 286 ++++++++++++++++++ 8 files changed, 310 insertions(+), 278 deletions(-) create mode 100644 packages/cli/package/src/lib/secretKeys.ts diff --git a/packages/cli/package/src/commands/key/default.ts b/packages/cli/package/src/commands/key/default.ts index 333cc1da4..df67b20f7 100644 --- a/packages/cli/package/src/commands/key/default.ts +++ b/packages/cli/package/src/commands/key/default.ts @@ -18,8 +18,8 @@ import { Args, Flags } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; -import { setDefaultSecretKey } from "../../lib/keyPairs.js"; import { initCli } from "../../lib/lifeCycle.js"; +import { setDefaultSecretKey } from "../../lib/secretKeys.js"; export default class Default extends BaseCommand { static override description = "Set default key-pair for user or project"; diff --git a/packages/cli/package/src/commands/key/new.ts b/packages/cli/package/src/commands/key/new.ts index 3f2005b27..bcfb67ed7 100644 --- a/packages/cli/package/src/commands/key/new.ts +++ b/packages/cli/package/src/commands/key/new.ts @@ -22,11 +22,9 @@ import { PROJECT_SECRETS_FULL_CONFIG_FILE_NAME, USER_SECRETS_CONFIG_FULL_FILE_NAME, } from "../../lib/const.js"; -import { - createSecretKey, - resolveUserOrProjectConfig, -} from "../../lib/keyPairs.js"; +import { createSecretKey } from "../../lib/keyPairs.js"; import { initCli } from "../../lib/lifeCycle.js"; +import { resolveUserOrProjectConfig } from "../../lib/secretKeys.js"; export default class New extends BaseCommand { static override description = `Generate key-pair and store it in ${USER_SECRETS_CONFIG_FULL_FILE_NAME} or ${PROJECT_SECRETS_FULL_CONFIG_FILE_NAME}`; diff --git a/packages/cli/package/src/commands/key/remove.ts b/packages/cli/package/src/commands/key/remove.ts index 5e2dbd245..16a156711 100644 --- a/packages/cli/package/src/commands/key/remove.ts +++ b/packages/cli/package/src/commands/key/remove.ts @@ -22,8 +22,8 @@ import { PROJECT_SECRETS_FULL_CONFIG_FILE_NAME, USER_SECRETS_CONFIG_FULL_FILE_NAME, } from "../../lib/const.js"; -import { removeSecretKey } from "../../lib/keyPairs.js"; import { initCli } from "../../lib/lifeCycle.js"; +import { removeSecretKey } from "../../lib/secretKeys.js"; export default class Remove extends BaseCommand { static override description = `Remove key-pair from ${USER_SECRETS_CONFIG_FULL_FILE_NAME} or ${PROJECT_SECRETS_FULL_CONFIG_FILE_NAME}`; diff --git a/packages/cli/package/src/lib/commandObj.ts b/packages/cli/package/src/lib/commandObj.ts index 881138853..d4ef98e28 100644 --- a/packages/cli/package/src/lib/commandObj.ts +++ b/packages/cli/package/src/lib/commandObj.ts @@ -33,6 +33,7 @@ export let commandObj: CommandObj = error(msg: string): never { throw new CLIError(msg); }, + config: {}, } as CommandObj; export let isInteractive: boolean; diff --git a/packages/cli/package/src/lib/configs/user/config/config.ts b/packages/cli/package/src/lib/configs/user/config/config.ts index 5dd87ce93..8a95e60f2 100644 --- a/packages/cli/package/src/lib/configs/user/config/config.ts +++ b/packages/cli/package/src/lib/configs/user/config/config.ts @@ -19,7 +19,7 @@ import { color } from "@oclif/color"; import { commandObj, isInteractive } from "../../../commandObj.js"; import { CLI_NAME_FULL, AUTO_GENERATED } from "../../../const.js"; -import { createSecretKey, getUserSecretKey } from "../../../keyPairs.js"; +import { createSecretKey, getUserSecretKeys } from "../../../keyPairs.js"; import { getUserConfigPath } from "../../../paths.js"; import { confirm } from "../../../prompt.js"; import { getConfigInitFunction } from "../../initConfigNew.js"; @@ -28,12 +28,10 @@ import { type InitConfigOptions } from "../../initConfigNewTypes.js"; import configOptions0, { type Config as Config0 } from "./config0.js"; import configOptions1, { type Config as Config1 } from "./config1.js"; -const getConfigPath = getUserConfigPath; - export const options: InitConfigOptions = { description: `Defines global config for ${CLI_NAME_FULL}`, options: [configOptions0, configOptions1], - getConfigPath, + getConfigPath: getUserConfigPath, }; export async function initNewUserConfig() { @@ -51,7 +49,7 @@ export async function initNewUserConfig() { countlyConsent = true; commandObj.logToStderr( - `If you change your mind later, modify "countlyConsent" property in ${await getConfigPath()}`, + `If you change your mind later, modify "countlyConsent" property in ${await options.getConfigPath()}`, ); } @@ -73,3 +71,11 @@ export async function initNewUserConfig() { } export type UserConfig = Awaited>; + +export async function getUserSecretKey( + secretKeyName: string | undefined, +): Promise { + return (await getUserSecretKeys())[ + secretKeyName ?? (await initNewUserConfig()).defaultSecretKeyName + ]; +} diff --git a/packages/cli/package/src/lib/jsClient.ts b/packages/cli/package/src/lib/jsClient.ts index fe63370e4..a2430219f 100644 --- a/packages/cli/package/src/lib/jsClient.ts +++ b/packages/cli/package/src/lib/jsClient.ts @@ -20,8 +20,9 @@ import { color } from "@oclif/color"; import { commandObj } from "./commandObj.js"; import { type FluenceClientFlags } from "./const.js"; import { stringifyUnknown } from "./helpers/utils.js"; -import { base64ToUint8Array, getExistingSecretKey } from "./keyPairs.js"; +import { base64ToUint8Array } from "./keyPairs.js"; import { resolveRelay } from "./multiaddres.js"; +import { getExistingSecretKey } from "./secretKeys.js"; export const initFluenceClient = async ({ relay: relayFromFlags, diff --git a/packages/cli/package/src/lib/keyPairs.ts b/packages/cli/package/src/lib/keyPairs.ts index 25664658f..d0f87aba2 100644 --- a/packages/cli/package/src/lib/keyPairs.ts +++ b/packages/cli/package/src/lib/keyPairs.ts @@ -15,55 +15,32 @@ * along with this program. If not, see . */ -import { access, readFile, readdir, rm, writeFile } from "node:fs/promises"; +import { access, readFile, readdir, writeFile } from "node:fs/promises"; import { join, parse, relative } from "node:path"; import { color } from "@oclif/color"; import { commandObj, isInteractive } from "./commandObj.js"; import { - initFluenceConfig, initReadonlyFluenceConfig, type FluenceConfig, } from "./configs/project/fluence.js"; -import { - initNewUserConfig, - type UserConfig, -} from "./configs/user/config/config.js"; +import type { UserConfig } from "./configs/user/config/config.js"; import { FS_OPTIONS } from "./const.js"; -import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; import { bufferToBase64 } from "./helpers/typesafeStringify.js"; import { - ensureUserFluenceSecretsDir, - getFluenceSecretsDir, getSecretsPathForWriting, getSecretsPathForReading, ensureFluenceSecretsFilePath, getFluenceDir, } from "./paths.js"; -import { list, type Choices, input, confirm } from "./prompt.js"; +import { input, confirm } from "./prompt.js"; -type UpdateSecretKeyArg = { +export type UpdateSecretKeyArg = { name: string | undefined; isUser: boolean; }; -export async function resolveUserOrProjectConfig( - isUser: boolean, -): Promise { - if (isUser) { - return initNewUserConfig(); - } - - const fluenceConfig = await initFluenceConfig(); - - if (fluenceConfig !== null) { - return fluenceConfig; - } - - return ensureFluenceProject(); -} - type WriteSecretKeyArg = { name: string; isUser: boolean; @@ -151,171 +128,6 @@ export async function createSecretKey({ ); } -export async function removeSecretKey({ name, isUser }: UpdateSecretKeyArg) { - const userOrProjectConfig = await resolveUserOrProjectConfig(isUser); - - const secretsPath = isUser - ? await ensureUserFluenceSecretsDir() - : getFluenceSecretsDir(); - - const secrets = await getSecretKeys(isUser); - - if (isUser && Object.keys(secrets).length === 1) { - commandObj.error( - `There is only one secret key in ${secretsPath} and it can't be removed, because having at least one user's secret key is required.`, - ); - } - - function validate(name: string) { - if (!(name in secrets)) { - return `Secret key ${color.yellow( - name, - )} doesn't exists at ${secretsPath}`; - } - - return true; - } - - function promptSecretKeyName() { - return list({ - message: "Select secret key name to remove", - options: Object.keys(secrets), - oneChoiceMessage(choice) { - return `Do you want to remove ${color.yellow(choice)}`; - }, - onNoChoices() { - return commandObj.error( - `There are no secret keys to remove at ${secretsPath}`, - ); - }, - }); - } - - let secretKeyNameToUse = name ?? (await promptSecretKeyName()); - const keyNameValidity = validate(secretKeyNameToUse); - - if (keyNameValidity !== true) { - if (!isInteractive) { - commandObj.error(keyNameValidity); - } - - commandObj.warn(keyNameValidity); - secretKeyNameToUse = await promptSecretKeyName(); - } - - await rm(join(secretsPath, `${secretKeyNameToUse}.txt`)); - - commandObj.logToStderr( - `Secret key with name ${color.yellow( - secretKeyNameToUse, - )} successfully removed from ${secretsPath}`, - ); - - if (userOrProjectConfig.defaultSecretKeyName !== secretKeyNameToUse) { - return; - } - - if (!isUser) { - delete userOrProjectConfig.defaultSecretKeyName; - await userOrProjectConfig.$commit(); - } - - if (!isInteractive) { - if (isUser) { - commandObj.warn( - `Please set another default secret key manually at ${userOrProjectConfig.$getPath()}`, - ); - } - - return; - } - - const options = Object.keys(secrets).filter((key) => { - return key !== secretKeyNameToUse; - }); - - const needToSelectNewDefault = - isUser || - (options.length > 0 && - (await confirm({ - message: `Do you want to set another secret key as default at ${userOrProjectConfig.$getPath()}`, - }))); - - if (!needToSelectNewDefault) { - return; - } - - await setDefaultSecretKey({ isUser, name }); -} - -export async function setDefaultSecretKey({ - name, - isUser, -}: UpdateSecretKeyArg) { - const userOrProjectConfig = await resolveUserOrProjectConfig(isUser); - - const secretsPath = isUser - ? getFluenceSecretsDir() - : await ensureUserFluenceSecretsDir(); - - const secrets = await getSecretKeys(isUser); - - function validate(name: string) { - if (!(name in secrets)) { - return `Secret key ${color.yellow( - name, - )} doesn't exists at ${secretsPath}`; - } - - return true; - } - - function promptSecretKeyName() { - return list({ - message: "Select new default secret key", - options: Object.keys(secrets), - oneChoiceMessage(choice) { - return `Do you want to set ${color.yellow(choice)} as default`; - }, - onNoChoices() { - return commandObj.error( - `There are no secret keys to set as default at ${secretsPath}`, - ); - }, - }); - } - - let secretKeyNameToUse = name ?? (await promptSecretKeyName()); - const keyNameValidity = validate(secretKeyNameToUse); - - if (keyNameValidity !== true) { - if (!isInteractive) { - commandObj.error(keyNameValidity); - } - - commandObj.warn(keyNameValidity); - secretKeyNameToUse = await promptSecretKeyName(); - } - - userOrProjectConfig.defaultSecretKeyName = secretKeyNameToUse; - await userOrProjectConfig.$commit(); - - commandObj.logToStderr( - `Secret key with name ${color.yellow( - secretKeyNameToUse, - )} successfully set as default at ${userOrProjectConfig.$getPath()}`, - ); -} - -export async function getUserSecretKey( - secretKeyName: string | undefined, -): Promise { - const userSecrets = await getUserSecretKeys(); - return userSecrets[ - secretKeyName ?? (await initNewUserConfig()).defaultSecretKeyName - ]; -} - export async function getProjectSecretKey( secretKeyName: string | undefined, ): Promise { @@ -332,83 +144,11 @@ export async function getProjectSecretKey( return secretKeys[secretKeyNameToUse]; } -export async function getExistingSecretKey( - secretKeyName: string | undefined, -): Promise { - const projectSecretKey = await getProjectSecretKey(secretKeyName); - - if (projectSecretKey !== undefined) { - return projectSecretKey; - } - - const userSecretKey = await getUserSecretKey(secretKeyName); - - if (userSecretKey !== undefined) { - return userSecretKey; - } - - const noUserKeyPairMessage = `Secret key ${color.yellow( - secretKeyName, - )} not found`; - - if (!isInteractive) { - return commandObj.error(noUserKeyPairMessage); - } - - commandObj.warn(noUserKeyPairMessage); - - const options: Choices<{ key: string }> = []; - const projectSecretKeys = await getProjectSecretKeys(); - - const projectKeyPairOptions = Object.entries(projectSecretKeys).map( - ([name, key]) => { - return { value: { key }, name }; - }, - ); - - if (projectKeyPairOptions.length > 0) { - const inquirer = (await import("inquirer")).default; - - options.push( - new inquirer.Separator("Project secret keys:"), - ...projectKeyPairOptions, - ); - } - - const userSecrets = await getUserSecretKeys(); - - const userKeyPairOptions = Object.entries(userSecrets).map(([name, key]) => { - return { value: { key }, name }; - }); - - const inquirer = (await import("inquirer")).default; - - options.push( - new inquirer.Separator("User secret keys:"), - ...userKeyPairOptions, - ); - - const { key } = await list<{ key: string }, never>({ - message: "Select existing secret key name", - options, - oneChoiceMessage: (name): string => { - return `Do you want to use ${color.yellow(name)}`; - }, - onNoChoices: (): never => { - return commandObj.error( - "There are no other secret keys. You need a secret key to continue", - ); - }, - }); - - return key; -} - -async function getUserSecretKeys() { +export async function getUserSecretKeys() { return getSecretKeys(true); } -async function getProjectSecretKeys() { +export async function getProjectSecretKeys() { return getSecretKeys(false); } diff --git a/packages/cli/package/src/lib/secretKeys.ts b/packages/cli/package/src/lib/secretKeys.ts new file mode 100644 index 000000000..8df58f5e2 --- /dev/null +++ b/packages/cli/package/src/lib/secretKeys.ts @@ -0,0 +1,286 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { rm } from "fs/promises"; +import { join } from "path/posix"; + +import { color } from "@oclif/color"; + +import { commandObj, isInteractive } from "./commandObj.js"; +import { + type FluenceConfig, + initFluenceConfig, +} from "./configs/project/fluence.js"; +import { + type UserConfig, + getUserSecretKey, + initNewUserConfig, +} from "./configs/user/config/config.js"; +import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; +import { + getUserSecretKeys, + type UpdateSecretKeyArg, + getSecretKeys, + getProjectSecretKey, + getProjectSecretKeys, +} from "./keyPairs.js"; +import { ensureUserFluenceSecretsDir, getFluenceSecretsDir } from "./paths.js"; +import { list, confirm, type Choices } from "./prompt.js"; + +export async function resolveUserOrProjectConfig( + isUser: boolean, +): Promise { + if (isUser) { + return initNewUserConfig(); + } + + const fluenceConfig = await initFluenceConfig(); + + if (fluenceConfig !== null) { + return fluenceConfig; + } + + return ensureFluenceProject(); +} + +export async function removeSecretKey({ name, isUser }: UpdateSecretKeyArg) { + const userOrProjectConfig = await resolveUserOrProjectConfig(isUser); + + const secretsPath = isUser + ? await ensureUserFluenceSecretsDir() + : getFluenceSecretsDir(); + + const secrets = await getSecretKeys(isUser); + + if (isUser && Object.keys(secrets).length === 1) { + commandObj.error( + `There is only one secret key in ${secretsPath} and it can't be removed, because having at least one user's secret key is required.`, + ); + } + + function validate(name: string) { + if (!(name in secrets)) { + return `Secret key ${color.yellow( + name, + )} doesn't exists at ${secretsPath}`; + } + + return true; + } + + function promptSecretKeyName() { + return list({ + message: "Select secret key name to remove", + options: Object.keys(secrets), + oneChoiceMessage(choice) { + return `Do you want to remove ${color.yellow(choice)}`; + }, + onNoChoices() { + return commandObj.error( + `There are no secret keys to remove at ${secretsPath}`, + ); + }, + }); + } + + let secretKeyNameToUse = name ?? (await promptSecretKeyName()); + const keyNameValidity = validate(secretKeyNameToUse); + + if (keyNameValidity !== true) { + if (!isInteractive) { + commandObj.error(keyNameValidity); + } + + commandObj.warn(keyNameValidity); + secretKeyNameToUse = await promptSecretKeyName(); + } + + await rm(join(secretsPath, `${secretKeyNameToUse}.txt`)); + + commandObj.logToStderr( + `Secret key with name ${color.yellow( + secretKeyNameToUse, + )} successfully removed from ${secretsPath}`, + ); + + if (userOrProjectConfig.defaultSecretKeyName !== secretKeyNameToUse) { + return; + } + + if (!isUser) { + delete userOrProjectConfig.defaultSecretKeyName; + await userOrProjectConfig.$commit(); + } + + if (!isInteractive) { + if (isUser) { + commandObj.warn( + `Please set another default secret key manually at ${userOrProjectConfig.$getPath()}`, + ); + } + + return; + } + + const options = Object.keys(secrets).filter((key) => { + return key !== secretKeyNameToUse; + }); + + const needToSelectNewDefault = + isUser || + (options.length > 0 && + (await confirm({ + message: `Do you want to set another secret key as default at ${userOrProjectConfig.$getPath()}`, + }))); + + if (!needToSelectNewDefault) { + return; + } + + await setDefaultSecretKey({ isUser, name }); +} + +export async function setDefaultSecretKey({ + name, + isUser, +}: UpdateSecretKeyArg) { + const userOrProjectConfig = await resolveUserOrProjectConfig(isUser); + + const secretsPath = isUser + ? getFluenceSecretsDir() + : await ensureUserFluenceSecretsDir(); + + const secrets = await getSecretKeys(isUser); + + function validate(name: string) { + if (!(name in secrets)) { + return `Secret key ${color.yellow( + name, + )} doesn't exists at ${secretsPath}`; + } + + return true; + } + + function promptSecretKeyName() { + return list({ + message: "Select new default secret key", + options: Object.keys(secrets), + oneChoiceMessage(choice) { + return `Do you want to set ${color.yellow(choice)} as default`; + }, + onNoChoices() { + return commandObj.error( + `There are no secret keys to set as default at ${secretsPath}`, + ); + }, + }); + } + + let secretKeyNameToUse = name ?? (await promptSecretKeyName()); + const keyNameValidity = validate(secretKeyNameToUse); + + if (keyNameValidity !== true) { + if (!isInteractive) { + commandObj.error(keyNameValidity); + } + + commandObj.warn(keyNameValidity); + secretKeyNameToUse = await promptSecretKeyName(); + } + + userOrProjectConfig.defaultSecretKeyName = secretKeyNameToUse; + await userOrProjectConfig.$commit(); + + commandObj.logToStderr( + `Secret key with name ${color.yellow( + secretKeyNameToUse, + )} successfully set as default at ${userOrProjectConfig.$getPath()}`, + ); +} + +export async function getExistingSecretKey( + secretKeyName: string | undefined, +): Promise { + const projectSecretKey = await getProjectSecretKey(secretKeyName); + + if (projectSecretKey !== undefined) { + return projectSecretKey; + } + + const userSecretKey = await getUserSecretKey(secretKeyName); + + if (userSecretKey !== undefined) { + return userSecretKey; + } + + const noUserKeyPairMessage = `Secret key ${color.yellow( + secretKeyName, + )} not found`; + + if (!isInteractive) { + return commandObj.error(noUserKeyPairMessage); + } + + commandObj.warn(noUserKeyPairMessage); + + const options: Choices<{ key: string }> = []; + const projectSecretKeys = await getProjectSecretKeys(); + + const projectKeyPairOptions = Object.entries(projectSecretKeys).map( + ([name, key]) => { + return { value: { key }, name }; + }, + ); + + if (projectKeyPairOptions.length > 0) { + const inquirer = (await import("inquirer")).default; + + options.push( + new inquirer.Separator("Project secret keys:"), + ...projectKeyPairOptions, + ); + } + + const userSecrets = await getUserSecretKeys(); + + const userKeyPairOptions = Object.entries(userSecrets).map(([name, key]) => { + return { value: { key }, name }; + }); + + const inquirer = (await import("inquirer")).default; + + options.push( + new inquirer.Separator("User secret keys:"), + ...userKeyPairOptions, + ); + + const { key } = await list<{ key: string }, never>({ + message: "Select existing secret key name", + options, + oneChoiceMessage: (name): string => { + return `Do you want to use ${color.yellow(name)}`; + }, + onNoChoices: (): never => { + return commandObj.error( + "There are no other secret keys. You need a secret key to continue", + ); + }, + }); + + return key; +} From 7a610778786591ffe12e9710c66b3eb374a5c475 Mon Sep 17 00:00:00 2001 From: shamsartem Date: Wed, 30 Oct 2024 09:48:49 +0000 Subject: [PATCH 03/37] Apply automatic changes --- packages/cli/package/docs/configs/README.md | 6 +-- packages/cli/package/docs/configs/config.md | 12 +++--- .../package/docs/configs/docker-compose.md | 42 ------------------- packages/cli/package/docs/configs/env.md | 2 +- .../docs/configs/provider-artifacts.md | 2 +- .../package/docs/configs/provider-secrets.md | 2 +- packages/cli/package/docs/configs/provider.md | 14 +++---- 7 files changed, 16 insertions(+), 64 deletions(-) delete mode 100644 packages/cli/package/docs/configs/docker-compose.md diff --git a/packages/cli/package/docs/configs/README.md b/packages/cli/package/docs/configs/README.md index fc7c06008..9d0a035f9 100644 --- a/packages/cli/package/docs/configs/README.md +++ b/packages/cli/package/docs/configs/README.md @@ -34,11 +34,7 @@ Defines global config for Fluence CLI ## [env.yaml](./env.md) -Defines user project preferences - -## [docker-compose.yaml](./docker-compose.md) - -The Compose file is a YAML file defining a multi-containers based application. +Defines project user's preferences ## [provider-artifacts.yaml](./provider-artifacts.md) diff --git a/packages/cli/package/docs/configs/config.md b/packages/cli/package/docs/configs/config.md index 22cd2be61..1842511b8 100644 --- a/packages/cli/package/docs/configs/config.md +++ b/packages/cli/package/docs/configs/config.md @@ -4,11 +4,9 @@ Defines global config for Fluence CLI ## Properties -| Property | Type | Required | Description | -|------------------------|---------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `countlyConsent` | boolean | **Yes** | Weather you consent to send usage data to Countly | -| `defaultSecretKeyName` | string | **Yes** | Secret key with this name will be used by default by js-client inside CLI to run Aqua code | -| `version` | integer | **Yes** | | -| `docsInConfigs` | boolean | No | Whether to include commented-out documented config examples in the configs generated with the CLI | -| `lastCheckForUpdates` | string | No | DEPRECATED. It's currently advised to install CLI without using npm (See README.md: https://github.com/fluencelabs/cli?tab=readme-ov-file#installation-and-usage). Last time when Fluence CLI checked for updates. Updates are checked daily unless this field is set to 'disabled' | +| Property | Type | Required | Description | +|------------------------|---------|----------|--------------------------------------------------------------------------------------------| +| `countlyConsent` | boolean | **Yes** | Weather you consent to send usage data to Countly | +| `defaultSecretKeyName` | string | **Yes** | Secret key with this name will be used by default by js-client inside CLI to run Aqua code | +| `version` | integer | **Yes** | | diff --git a/packages/cli/package/docs/configs/docker-compose.md b/packages/cli/package/docs/configs/docker-compose.md deleted file mode 100644 index 7e58743cf..000000000 --- a/packages/cli/package/docs/configs/docker-compose.md +++ /dev/null @@ -1,42 +0,0 @@ -# Compose Specification - -The Compose file is a YAML file defining a multi-containers based application. - -## Properties - -| Property | Type | Required | Description | -|------------|---------------------|----------|---------------------------------------------------------------------| -| `configs` | [object](#configs) | No | | -| `include` | | No | compose sub-projects to be included. | -| `name` | string | No | define the Compose project name, until user defines one explicitly. | -| `networks` | [object](#networks) | No | | -| `secrets` | [object](#secrets) | No | | -| `services` | [object](#services) | No | | -| `version` | string | No | declared for backward compatibility, ignored. | -| `volumes` | [object](#volumes) | No | | - -## configs - -| Property | Type | Required | Description | -|----------|------|----------|-------------| - -## networks - -| Property | Type | Required | Description | -|----------|------|----------|-------------| - -## secrets - -| Property | Type | Required | Description | -|----------|------|----------|-------------| - -## services - -| Property | Type | Required | Description | -|----------|------|----------|-------------| - -## volumes - -| Property | Type | Required | Description | -|----------|------|----------|-------------| - diff --git a/packages/cli/package/docs/configs/env.md b/packages/cli/package/docs/configs/env.md index 2335d30e7..fa736b0fc 100644 --- a/packages/cli/package/docs/configs/env.md +++ b/packages/cli/package/docs/configs/env.md @@ -1,6 +1,6 @@ # env.yaml -Defines user project preferences +Defines project user's preferences ## Properties diff --git a/packages/cli/package/docs/configs/provider-artifacts.md b/packages/cli/package/docs/configs/provider-artifacts.md index 9e0caf48f..2beffd5fd 100644 --- a/packages/cli/package/docs/configs/provider-artifacts.md +++ b/packages/cli/package/docs/configs/provider-artifacts.md @@ -7,7 +7,7 @@ Defines artifacts created by the provider | Property | Type | Required | Description | |-----------|-------------------|----------|----------------| | `offers` | [object](#offers) | **Yes** | Created offers | -| `version` | integer | **Yes** | Config version | +| `version` | integer | **Yes** | | ## offers diff --git a/packages/cli/package/docs/configs/provider-secrets.md b/packages/cli/package/docs/configs/provider-secrets.md index b8039f152..df071329f 100644 --- a/packages/cli/package/docs/configs/provider-secrets.md +++ b/packages/cli/package/docs/configs/provider-secrets.md @@ -7,7 +7,7 @@ Defines secrets config used for provider set up | Property | Type | Required | Description | |-----------|------------------|----------|-------------------------------| | `noxes` | [object](#noxes) | **Yes** | Secret keys for noxes by name | -| `version` | integer | **Yes** | Config version | +| `version` | integer | **Yes** | | ## noxes diff --git a/packages/cli/package/docs/configs/provider.md b/packages/cli/package/docs/configs/provider.md index 5e450a093..a4127d9f5 100644 --- a/packages/cli/package/docs/configs/provider.md +++ b/packages/cli/package/docs/configs/provider.md @@ -6,25 +6,25 @@ Defines config used for provider set up | Property | Type | Required | Description | |-----------------------|--------------------------------|----------|-------------------------------------------------------------------------------------------------| -| `capacityCommitments` | [object](#capacitycommitments) | **Yes** | A map with nox names as keys and capacity commitments as values | +| `capacityCommitments` | [object](#capacitycommitments) | **Yes** | Capacity commitments | | `computePeers` | [object](#computepeers) | **Yes** | A map with compute peer names as keys and compute peers as values | | `offers` | [object](#offers) | **Yes** | A map with offer names as keys and offers as values | | `providerName` | string | **Yes** | Provider name. Must not be empty | -| `version` | integer | **Yes** | Config version | +| `version` | integer | **Yes** | | | `ccp` | [object](#ccp) | No | Configuration to pass to the Capacity Commitment Prover | | `nox` | [object](#nox) | No | Configuration to pass to the nox compute peer. Config.toml files are generated from this config | ## capacityCommitments -A map with nox names as keys and capacity commitments as values +Capacity commitments ### Properties -| Property | Type | Required | Description | -|-----------|--------------------|----------|-------------------------------| -| `noxName` | [object](#noxname) | No | Defines a capacity commitment | +| Property | Type | Required | Description | +|------------------|---------------------------|----------|-------------------------------| +| `commitmentName` | [object](#commitmentname) | No | Defines a capacity commitment | -### noxName +### commitmentName Defines a capacity commitment From 2fdc97712a18caeea2c19d0cbbc82fa638a2619c Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 11:09:34 +0100 Subject: [PATCH 04/37] fix --- packages/cli/package/src/lib/configs/initConfigNew.ts | 7 ++++++- .../package/src/lib/configs/project/provider/provider3.ts | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index 12489e683..432f8a5c8 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -213,7 +213,12 @@ export async function addTitleDescriptionAndVersionToSchemas< options.forEach(({ schema }, version) => { schema.title = title; schema.description = description; - schema.properties.version = { type: "integer", const: version }; + + schema.properties.version = { + type: "integer", + const: version, + description: "Config version", + }; if (schema.required?.includes("version") !== true) { schema.required = [...(schema.required ?? []), "version"]; diff --git a/packages/cli/package/src/lib/configs/project/provider/provider3.ts b/packages/cli/package/src/lib/configs/project/provider/provider3.ts index 344322f84..b1efca147 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider3.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider3.ts @@ -116,10 +116,11 @@ type CapacityCommitments = Record; const capacityCommitmentsSchema = { type: "object", - description: "Capacity commitments", + description: + "A map with nox names as keys and capacity commitments as values", additionalProperties: capacityCommitmentSchema, properties: { - commitmentName: capacityCommitmentSchema, + noxName: capacityCommitmentSchema, }, required: [], } as const satisfies JSONSchemaType; From 7991aeb81a336fd27461e2c3c2c66bb81c6a5d9f Mon Sep 17 00:00:00 2001 From: shamsartem Date: Wed, 30 Oct 2024 10:11:32 +0000 Subject: [PATCH 05/37] Apply automatic changes --- packages/cli/package/docs/configs/config.md | 2 +- packages/cli/package/docs/configs/env.md | 2 +- .../cli/package/docs/configs/provider-artifacts.md | 2 +- .../cli/package/docs/configs/provider-secrets.md | 2 +- packages/cli/package/docs/configs/provider.md | 14 +++++++------- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/cli/package/docs/configs/config.md b/packages/cli/package/docs/configs/config.md index 1842511b8..48988998b 100644 --- a/packages/cli/package/docs/configs/config.md +++ b/packages/cli/package/docs/configs/config.md @@ -8,5 +8,5 @@ Defines global config for Fluence CLI |------------------------|---------|----------|--------------------------------------------------------------------------------------------| | `countlyConsent` | boolean | **Yes** | Weather you consent to send usage data to Countly | | `defaultSecretKeyName` | string | **Yes** | Secret key with this name will be used by default by js-client inside CLI to run Aqua code | -| `version` | integer | **Yes** | | +| `version` | integer | **Yes** | Config version | diff --git a/packages/cli/package/docs/configs/env.md b/packages/cli/package/docs/configs/env.md index fa736b0fc..05ae067ab 100644 --- a/packages/cli/package/docs/configs/env.md +++ b/packages/cli/package/docs/configs/env.md @@ -6,7 +6,7 @@ Defines project user's preferences | Property | Type | Required | Description | |-----------------|-----------------------|----------|------------------------------------------------------------------------------------------------| -| `version` | integer | **Yes** | | +| `version` | integer | **Yes** | Config version | | `blockScoutUrl` | string | No | BlockScout URL to use | | `chainId` | number | No | Chain ID to use | | `deployment` | [object](#deployment) | No | Deployed contract address overrides | diff --git a/packages/cli/package/docs/configs/provider-artifacts.md b/packages/cli/package/docs/configs/provider-artifacts.md index 2beffd5fd..9e0caf48f 100644 --- a/packages/cli/package/docs/configs/provider-artifacts.md +++ b/packages/cli/package/docs/configs/provider-artifacts.md @@ -7,7 +7,7 @@ Defines artifacts created by the provider | Property | Type | Required | Description | |-----------|-------------------|----------|----------------| | `offers` | [object](#offers) | **Yes** | Created offers | -| `version` | integer | **Yes** | | +| `version` | integer | **Yes** | Config version | ## offers diff --git a/packages/cli/package/docs/configs/provider-secrets.md b/packages/cli/package/docs/configs/provider-secrets.md index df071329f..b8039f152 100644 --- a/packages/cli/package/docs/configs/provider-secrets.md +++ b/packages/cli/package/docs/configs/provider-secrets.md @@ -7,7 +7,7 @@ Defines secrets config used for provider set up | Property | Type | Required | Description | |-----------|------------------|----------|-------------------------------| | `noxes` | [object](#noxes) | **Yes** | Secret keys for noxes by name | -| `version` | integer | **Yes** | | +| `version` | integer | **Yes** | Config version | ## noxes diff --git a/packages/cli/package/docs/configs/provider.md b/packages/cli/package/docs/configs/provider.md index a4127d9f5..5e450a093 100644 --- a/packages/cli/package/docs/configs/provider.md +++ b/packages/cli/package/docs/configs/provider.md @@ -6,25 +6,25 @@ Defines config used for provider set up | Property | Type | Required | Description | |-----------------------|--------------------------------|----------|-------------------------------------------------------------------------------------------------| -| `capacityCommitments` | [object](#capacitycommitments) | **Yes** | Capacity commitments | +| `capacityCommitments` | [object](#capacitycommitments) | **Yes** | A map with nox names as keys and capacity commitments as values | | `computePeers` | [object](#computepeers) | **Yes** | A map with compute peer names as keys and compute peers as values | | `offers` | [object](#offers) | **Yes** | A map with offer names as keys and offers as values | | `providerName` | string | **Yes** | Provider name. Must not be empty | -| `version` | integer | **Yes** | | +| `version` | integer | **Yes** | Config version | | `ccp` | [object](#ccp) | No | Configuration to pass to the Capacity Commitment Prover | | `nox` | [object](#nox) | No | Configuration to pass to the nox compute peer. Config.toml files are generated from this config | ## capacityCommitments -Capacity commitments +A map with nox names as keys and capacity commitments as values ### Properties -| Property | Type | Required | Description | -|------------------|---------------------------|----------|-------------------------------| -| `commitmentName` | [object](#commitmentname) | No | Defines a capacity commitment | +| Property | Type | Required | Description | +|-----------|--------------------|----------|-------------------------------| +| `noxName` | [object](#noxname) | No | Defines a capacity commitment | -### commitmentName +### noxName Defines a capacity commitment From 3dc1d8d8dd7ea1533ddb3bd615c44b8edc649e25 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 11:56:07 +0100 Subject: [PATCH 06/37] simplify --- packages/cli/package/src/genConfigDocs.ts | 34 ++++--- .../package/src/lib/configs/initConfigNew.ts | 21 +---- .../src/lib/configs/initConfigNewTypes.ts | 92 +++---------------- 3 files changed, 36 insertions(+), 111 deletions(-) diff --git a/packages/cli/package/src/genConfigDocs.ts b/packages/cli/package/src/genConfigDocs.ts index 1458ae82a..4dd9d3997 100644 --- a/packages/cli/package/src/genConfigDocs.ts +++ b/packages/cli/package/src/genConfigDocs.ts @@ -20,7 +20,6 @@ import { writeFile, mkdir, readFile } from "node:fs/promises"; import { join } from "node:path"; import { jsonStringify } from "./common.js"; -import { getLatestConfigOptions } from "./lib/configs/initConfigNew.js"; import { addTitleDescriptionAndVersionToSchemas } from "./lib/configs/initConfigNew.js"; import { options as envOptions } from "./lib/configs/project/env/env.js"; import { fluenceSchema } from "./lib/configs/project/fluence.js"; @@ -55,27 +54,40 @@ import CLIPackageJSON from "./versions/cli.package.json"; const DOCS_CONFIGS_DIR_PATH = join("docs", "configs"); const DOCS_COMMANDS_PATH = join("docs", "commands", "README.md"); +function getLatestConfigOptionsSchema< + T extends { schema: { description?: string } }, +>(arr: T[]) { + const latestOptions = arr[arr.length - 1]; + + assert( + latestOptions !== undefined, + "Unreachable. There is always at least one element in the array", + ); + + return latestOptions.schema; +} + const configsInfo = Object.entries({ [FLUENCE_CONFIG_FILE_NAME]: fluenceSchema, - [PROVIDER_CONFIG_FILE_NAME]: getLatestConfigOptions( + [PROVIDER_CONFIG_FILE_NAME]: getLatestConfigOptionsSchema( await addTitleDescriptionAndVersionToSchemas(providerOptions), - ).schema, - [PROVIDER_SECRETS_CONFIG_FILE_NAME]: getLatestConfigOptions( + ), + [PROVIDER_SECRETS_CONFIG_FILE_NAME]: getLatestConfigOptionsSchema( await addTitleDescriptionAndVersionToSchemas(providerSecretsOptions), - ).schema, + ), [MODULE_CONFIG_FILE_NAME]: moduleSchema, [SERVICE_CONFIG_FILE_NAME]: serviceSchema, [SPELL_CONFIG_FILE_NAME]: spellSchema, [WORKERS_CONFIG_FILE_NAME]: workersSchema, - [USER_CONFIG_FILE_NAME]: getLatestConfigOptions( + [USER_CONFIG_FILE_NAME]: getLatestConfigOptionsSchema( await addTitleDescriptionAndVersionToSchemas(userConfigOptions), - ).schema, - [ENV_CONFIG_FILE_NAME]: getLatestConfigOptions( + ), + [ENV_CONFIG_FILE_NAME]: getLatestConfigOptionsSchema( await addTitleDescriptionAndVersionToSchemas(envOptions), - ).schema, - [PROVIDER_ARTIFACTS_CONFIG_FILE_NAME]: getLatestConfigOptions( + ), + [PROVIDER_ARTIFACTS_CONFIG_FILE_NAME]: getLatestConfigOptionsSchema( await addTitleDescriptionAndVersionToSchemas(providerArtifactsOptions), - ).schema, + ), }).map(([filename, schema]) => { return { schemaPath: join(SCHEMAS_DIR_NAME, `${filename}.schema.${JSON_EXT}`), diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index 432f8a5c8..f12eb0810 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -228,25 +228,6 @@ export async function addTitleDescriptionAndVersionToSchemas< return options; } -export function getLatestConfigOptions< - C0, - C1 = undefined, - C2 = undefined, - C3 = undefined, - C4 = undefined, - C5 = undefined, - C6 = undefined, - C7 = undefined, - C8 = undefined, - C9 = undefined, ->(arr: OptionsTuple) { - // The latest config is always the last one in the array - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return arr[arr.length - 1] as unknown as ConfigOptionsWithoutMigrate< - GetLatestConfig - >; -} - function getConfigValidator({ actualConfigPath, configOptions: { schema, validate }, @@ -334,7 +315,7 @@ async function getLatestConfig({ return null; } - const latestConfigOptions = getLatestConfigOptions(options); + const latestConfigOptions = options[options.length - 1]; const { description } = latestConfigOptions.schema; assert( diff --git a/packages/cli/package/src/lib/configs/initConfigNewTypes.ts b/packages/cli/package/src/lib/configs/initConfigNewTypes.ts index 32c5a0149..5ee39c773 100644 --- a/packages/cli/package/src/lib/configs/initConfigNewTypes.ts +++ b/packages/cli/package/src/lib/configs/initConfigNewTypes.ts @@ -70,86 +70,18 @@ export type GetLatestConfig = : C8 : C9; -export type OptionsTuple = - C9 extends undefined - ? C8 extends undefined - ? C7 extends undefined - ? C6 extends undefined - ? C5 extends undefined - ? C4 extends undefined - ? C3 extends undefined - ? C2 extends undefined - ? C1 extends undefined - ? [ConfigOptions] - : [ConfigOptions, ConfigOptions] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ] - : [ - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ConfigOptions, - ]; +export type OptionsTuple = [ + ConfigOptions, + ...(C1 extends undefined ? [] : ConfigOptions[]), + ...(C2 extends undefined ? [] : ConfigOptions[]), + ...(C3 extends undefined ? [] : ConfigOptions[]), + ...(C4 extends undefined ? [] : ConfigOptions[]), + ...(C5 extends undefined ? [] : ConfigOptions[]), + ...(C6 extends undefined ? [] : ConfigOptions[]), + ...(C7 extends undefined ? [] : ConfigOptions[]), + ...(C8 extends undefined ? [] : ConfigOptions[]), + ...(C9 extends undefined ? [] : ConfigOptions[]), +]; export type InitConfigOptions< C0, From 0ebac893d158a10faa42bde04ad3c8d4782454f5 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 12:31:02 +0100 Subject: [PATCH 07/37] import only what's needed from lodash --- .../cli/package/src/lib/configs/project/provider/provider1.ts | 4 +++- .../cli/package/src/lib/configs/project/provider/provider2.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/package/src/lib/configs/project/provider/provider1.ts b/packages/cli/package/src/lib/configs/project/provider/provider1.ts index 0cf56f245..ab9086e65 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider1.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider1.ts @@ -16,7 +16,9 @@ */ import type { JSONSchemaType } from "ajv"; -import { isUndefined, mapValues, omitBy } from "lodash-es"; +import isUndefined from "lodash-es/isUndefined.js"; +import mapValues from "lodash-es/mapValues.js"; +import omitBy from "lodash-es/omitBy.js"; import { COMPUTE_UNIT_MEMORY_STR, diff --git a/packages/cli/package/src/lib/configs/project/provider/provider2.ts b/packages/cli/package/src/lib/configs/project/provider/provider2.ts index 7503c9eb9..75c25db1d 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider2.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider2.ts @@ -16,7 +16,7 @@ */ import type { JSONSchemaType } from "ajv"; -import { mapValues } from "lodash-es"; +import mapValues from "lodash-es/mapValues.js"; import { versions } from "../../../../versions.js"; import { PT_SYMBOL } from "../../../const.js"; From 75601cf508cfdf69f3f4d9c71ab86b122d209b3e Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 17:45:35 +0100 Subject: [PATCH 08/37] fix? --- packages/cli/package/src/commands/local/down.ts | 5 ----- packages/cli/package/src/lib/configs/initConfigNew.ts | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/cli/package/src/commands/local/down.ts b/packages/cli/package/src/commands/local/down.ts index a2f1de681..b1e8ceb2b 100644 --- a/packages/cli/package/src/commands/local/down.ts +++ b/packages/cli/package/src/commands/local/down.ts @@ -25,7 +25,6 @@ import { } from "../../lib/const.js"; import { dockerCompose } from "../../lib/dockerCompose.js"; import { initCli } from "../../lib/lifeCycle.js"; -import { input } from "../../lib/prompt.js"; export default class Down extends BaseCommand { static override description = `Stop and remove currently running ${DOCKER_COMPOSE_FULL_FILE_NAME} using docker compose`; @@ -43,10 +42,6 @@ export default class Down extends BaseCommand { const { flags } = await initCli(this, await this.parse(Down)); const dockerComposeConfig = await initNewReadonlyDockerComposeConfig(); - await input({ - message: `Stopping and removing ${DOCKER_COMPOSE_FULL_FILE_NAME} using docker compose. Are you sure?`, - }); - await dockerCompose({ args: [ "down", diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index f12eb0810..ceb86a685 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -164,7 +164,6 @@ export function getConfigInitFunction< } = getLatestConfigRes; let prevConfigString = latestConfigString; - let prevConfig = latestConfig; const initializedConfig: InitializedConfig = { ...latestConfig, @@ -178,11 +177,11 @@ export function getConfigInitFunction< prevConfigString = await saveConfig( actualConfigPath, - yamlDiffPatch(prevConfigString, prevConfig, config), + yamlDiffPatch(prevConfigString, {}, config), prevConfigString, ); - prevConfig = await validateLatestConfig(config); + await validateLatestConfig(config); }, }; From 5504ab58b2205df45607ad1b1f6ed9db870f318c Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 30 Oct 2024 17:46:51 +0100 Subject: [PATCH 09/37] just in case --- packages/cli/package/src/lib/configs/initConfigNew.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index ceb86a685..210b94527 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -420,7 +420,7 @@ async function getLatestConfig({ currentConfigString = await saveConfig( actualConfigPath, - yamlDiffPatch(currentConfigString, prevConfig, currentConfig), + yamlDiffPatch(currentConfigString, {}, currentConfig), index === 0 ? configString : currentConfigString, ); From da98076c36ed722108983b46d2c40a05b86ed906 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Thu, 31 Oct 2024 16:36:17 +0100 Subject: [PATCH 10/37] make all aliases hidden from top-level of help --- .../cli/package/src/commands/air/beautify.ts | 6 +-- packages/cli/package/src/commands/aqua/yml.ts | 6 +-- .../package/src/commands/deal/workers-add.ts | 5 ++- .../src/commands/deal/workers-remove.ts | 5 ++- .../src/commands/delegator/collateral-add.ts | 5 ++- .../commands/delegator/collateral-withdraw.ts | 5 ++- .../src/commands/delegator/reward-withdraw.ts | 5 ++- .../cli/package/src/commands/dep/install.ts | 6 +-- .../cli/package/src/commands/dep/reset.ts | 6 +-- .../cli/package/src/commands/dep/uninstall.ts | 6 +-- .../cli/package/src/commands/dep/versions.ts | 6 +-- .../src/commands/provider/cc-activate.ts | 5 ++- .../provider/cc-collateral-withdraw.ts | 43 ------------------- .../src/commands/provider/cc-create.ts | 5 ++- .../src/commands/provider/cc-finish.ts | 8 +++- .../package/src/commands/provider/cc-info.ts | 5 ++- .../src/commands/provider/cc-remove.ts | 6 +-- .../commands/provider/cc-rewards-withdraw.ts | 5 ++- .../src/commands/provider/deal-exit.ts | 5 ++- .../src/commands/provider/deal-list.ts | 5 ++- .../commands/provider/deal-rewards-info.ts | 5 ++- .../provider/deal-rewards-withdraw.ts | 5 ++- .../cli/package/src/commands/provider/info.ts | 5 ++- .../src/commands/provider/offer-create.ts | 6 +-- .../src/commands/provider/offer-info.ts | 5 ++- .../src/commands/provider/offer-remove.ts | 5 ++- .../src/commands/provider/offer-update.ts | 5 ++- .../package/src/commands/provider/register.ts | 5 ++- .../commands/provider/tokens-distribute.ts | 5 ++- .../src/commands/provider/tokens-withdraw.ts | 5 ++- .../package/src/commands/provider/update.ts | 5 ++- .../package/src/lib/helpers/aliasesText.ts | 30 +++++++++++++ 32 files changed, 123 insertions(+), 111 deletions(-) delete mode 100644 packages/cli/package/src/commands/provider/cc-collateral-withdraw.ts create mode 100644 packages/cli/package/src/lib/helpers/aliasesText.ts diff --git a/packages/cli/package/src/commands/air/beautify.ts b/packages/cli/package/src/commands/air/beautify.ts index 45d59a99d..7e405b67e 100644 --- a/packages/cli/package/src/commands/air/beautify.ts +++ b/packages/cli/package/src/commands/air/beautify.ts @@ -22,13 +22,13 @@ import { Args } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; import { FS_OPTIONS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; import { input } from "../../lib/prompt.js"; export default class Beautify extends BaseCommand { - static override aliases = ["air:b"]; - static override description = - "Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended to be read by mere mortals."; + static override hiddenAliases = ["air:b"]; + static override description = `Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended to be read by mere mortals${aliasesText.apply(this)}`; static override args = { PATH: Args.string({ description: `Path to an AIR file. Must be relative to the current working directory or absolute`, diff --git a/packages/cli/package/src/commands/aqua/yml.ts b/packages/cli/package/src/commands/aqua/yml.ts index bf4591dd1..7fbea52b8 100644 --- a/packages/cli/package/src/commands/aqua/yml.ts +++ b/packages/cli/package/src/commands/aqua/yml.ts @@ -19,13 +19,13 @@ import { Args } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { CUSTOM_TYPES_FLAG, USE_F64_FLAG } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { fileToAqua } from "../../lib/helpers/jsToAqua.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class Yaml extends BaseCommand { - static override aliases = ["aqua:yaml"]; - static override description = - "Infers aqua types for an arbitrary yaml file, generates valid aqua code with a function call that returns an aqua object literal with the same structure as the yaml file. For valid generation please refer to aqua documentation https://fluence.dev/docs/aqua-book/language/ to learn about what kind of structures are valid in aqua language and what they translate into"; + static override hiddenAliases = ["aqua:yaml"]; + static override description = `Infers aqua types for an arbitrary yaml file, generates valid aqua code with a function call that returns an aqua object literal with the same structure as the yaml file. For valid generation please refer to aqua documentation https://fluence.dev/docs/aqua-book/language/ to learn about what kind of structures are valid in aqua language and what they translate into${aliasesText.apply(this)}`; static override flags = { ...USE_F64_FLAG, ...CUSTOM_TYPES_FLAG, diff --git a/packages/cli/package/src/commands/deal/workers-add.ts b/packages/cli/package/src/commands/deal/workers-add.ts index f457bba12..532dd690c 100644 --- a/packages/cli/package/src/commands/deal/workers-add.ts +++ b/packages/cli/package/src/commands/deal/workers-add.ts @@ -22,11 +22,12 @@ import { DEPLOYMENT_NAMES_ARG, } from "../../lib/const.js"; import { match, getDeals } from "../../lib/deal.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class Match extends BaseCommand { - static override aliases = ["deal:wa"]; - static override description = "Add missing workers to the deal"; + static override hiddenAliases = ["deal:wa"]; + static override description = `Add missing workers to the deal${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...DEAL_IDS_FLAG, diff --git a/packages/cli/package/src/commands/deal/workers-remove.ts b/packages/cli/package/src/commands/deal/workers-remove.ts index 339fe9884..c94c366d1 100644 --- a/packages/cli/package/src/commands/deal/workers-remove.ts +++ b/packages/cli/package/src/commands/deal/workers-remove.ts @@ -27,13 +27,14 @@ import { } from "../../lib/const.js"; import { getDeal } from "../../lib/deal.js"; import { sign, getContracts } from "../../lib/dealClient.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { commaSepStrToArr } from "../../lib/helpers/utils.js"; import { initCli } from "../../lib/lifeCycle.js"; import { input } from "../../lib/prompt.js"; export default class WorkersRemove extends BaseCommand { - static override aliases = ["deal:wr"]; - static override description = "Remove unit from the deal"; + static override hiddenAliases = ["deal:wr"]; + static override description = `Remove unit from the deal${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, "deal-id": Flags.string({ diff --git a/packages/cli/package/src/commands/delegator/collateral-add.ts b/packages/cli/package/src/commands/delegator/collateral-add.ts index 20f87eb4d..c95151c19 100644 --- a/packages/cli/package/src/commands/delegator/collateral-add.ts +++ b/packages/cli/package/src/commands/delegator/collateral-add.ts @@ -20,11 +20,12 @@ import { Args } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { depositCollateral } from "../../lib/chain/depositCollateral.js"; import { CC_IDS_FLAG_NAME, CHAIN_FLAGS, FLT_SYMBOL } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CollateralAdd extends BaseCommand { - static override aliases = ["delegator:ca"]; - static override description = `Add ${FLT_SYMBOL} collateral to capacity commitment`; + static override hiddenAliases = ["delegator:ca"]; + static override description = `Add ${FLT_SYMBOL} collateral to capacity commitment${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/commands/delegator/collateral-withdraw.ts b/packages/cli/package/src/commands/delegator/collateral-withdraw.ts index 51751bbaf..b65dad9dc 100644 --- a/packages/cli/package/src/commands/delegator/collateral-withdraw.ts +++ b/packages/cli/package/src/commands/delegator/collateral-withdraw.ts @@ -25,13 +25,14 @@ import { FINISH_COMMITMENT_FLAG_NAME, FLT_SYMBOL, } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CollateralWithdraw extends BaseCommand< typeof CollateralWithdraw > { - static override aliases = ["delegator:cw"]; - static override description = `Withdraw ${FLT_SYMBOL} collateral from capacity commitment`; + static override hiddenAliases = ["delegator:cw"]; + static override description = `Withdraw ${FLT_SYMBOL} collateral from capacity commitment${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, [FINISH_COMMITMENT_FLAG_NAME]: Flags.boolean({ diff --git a/packages/cli/package/src/commands/delegator/reward-withdraw.ts b/packages/cli/package/src/commands/delegator/reward-withdraw.ts index e581dfa1c..dad0747f6 100644 --- a/packages/cli/package/src/commands/delegator/reward-withdraw.ts +++ b/packages/cli/package/src/commands/delegator/reward-withdraw.ts @@ -20,11 +20,12 @@ import { Args } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { collateralRewardWithdraw } from "../../lib/chain/commitment.js"; import { CC_IDS_FLAG_NAME, CHAIN_FLAGS, FLT_SYMBOL } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class RewardWithdraw extends BaseCommand { - static override aliases = ["delegator:rw"]; - static override description = `Withdraw ${FLT_SYMBOL} rewards from capacity commitment`; + static override hiddenAliases = ["delegator:rw"]; + static override description = `Withdraw ${FLT_SYMBOL} rewards from capacity commitment${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/commands/dep/install.ts b/packages/cli/package/src/commands/dep/install.ts index 1501bd082..c25ed59ea 100644 --- a/packages/cli/package/src/commands/dep/install.ts +++ b/packages/cli/package/src/commands/dep/install.ts @@ -21,15 +21,15 @@ import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; import { initFluenceConfig } from "../../lib/configs/project/fluence.js"; import { PACKAGE_NAME_AND_VERSION_ARG_NAME } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { startSpinner, stopSpinner } from "../../lib/helpers/spinner.js"; import { initCli } from "../../lib/lifeCycle.js"; import { npmInstall, npmInstallAll } from "../../lib/npm.js"; import { ensureMarineAndMreplDependencies } from "../../lib/rust.js"; export default class Install extends BaseCommand { - static override aliases = ["dep:i"]; - static override description = - "Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)"; + static override hiddenAliases = ["dep:i"]; + static override description = `Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)${aliasesText.apply(this)}`; static override examples = ["<%= config.bin %> <%= command.id %>"]; static override args = { [PACKAGE_NAME_AND_VERSION_ARG_NAME]: Args.string({ diff --git a/packages/cli/package/src/commands/dep/reset.ts b/packages/cli/package/src/commands/dep/reset.ts index 0208aad15..3dc2aa6bc 100644 --- a/packages/cli/package/src/commands/dep/reset.ts +++ b/packages/cli/package/src/commands/dep/reset.ts @@ -17,15 +17,15 @@ import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { ensureFluenceProject } from "../../lib/helpers/ensureFluenceProject.js"; import { initCli } from "../../lib/lifeCycle.js"; import { npmInstallAll } from "../../lib/npm.js"; import { versions } from "../../versions.js"; export default class Reset extends BaseCommand { - static override aliases = ["dep:r"]; - static override description = - "Reset all project dependencies to recommended versions"; + static override hiddenAliases = ["dep:r"]; + static override description = `Reset all project dependencies to recommended versions${aliasesText.apply(this)}`; static override examples = ["<%= config.bin %> <%= command.id %>"]; async run(): Promise { await initCli(this, await this.parse(Reset)); diff --git a/packages/cli/package/src/commands/dep/uninstall.ts b/packages/cli/package/src/commands/dep/uninstall.ts index 21d975d7b..d13a2259c 100644 --- a/packages/cli/package/src/commands/dep/uninstall.ts +++ b/packages/cli/package/src/commands/dep/uninstall.ts @@ -20,13 +20,13 @@ import { Args } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; import { PACKAGE_NAME } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; import { npmUninstall } from "../../lib/npm.js"; export default class Install extends BaseCommand { - static override aliases = ["dep:un"]; - static override description = - "Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)"; + static override hiddenAliases = ["dep:un"]; + static override description = `Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies)${aliasesText.apply(this)}`; static override examples = ["<%= config.bin %> <%= command.id %>"]; static override args = { [PACKAGE_NAME]: Args.string({ diff --git a/packages/cli/package/src/commands/dep/versions.ts b/packages/cli/package/src/commands/dep/versions.ts index f1e842b32..c33b6dc6b 100644 --- a/packages/cli/package/src/commands/dep/versions.ts +++ b/packages/cli/package/src/commands/dep/versions.ts @@ -23,6 +23,7 @@ import { jsonStringify } from "../../common.js"; import { commandObj } from "../../lib/commandObj.js"; import { initFluenceConfig } from "../../lib/configs/project/fluence.js"; import { CLI_NAME_FULL, JSON_FLAG } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; import { getRustToolchainToUse, @@ -33,9 +34,8 @@ import JSClientPackageJSON from "../../versions/js-client.package.json" with { t import { versions } from "../../versions.js"; export default class Versions extends BaseCommand { - static override aliases = ["dep:v"]; - static override description = - "Get versions of all cli dependencies, including aqua, marine, mrepl and internal"; + static override hiddenAliases = ["dep:v"]; + static override description = `Get versions of all cli dependencies, including aqua, marine, mrepl and internal${aliasesText.apply(this)}`; static override examples = ["<%= config.bin %> <%= command.id %>"]; static override flags = { default: Flags.boolean({ diff --git a/packages/cli/package/src/commands/provider/cc-activate.ts b/packages/cli/package/src/commands/provider/cc-activate.ts index 8fcbf0aae..be793ce58 100644 --- a/packages/cli/package/src/commands/provider/cc-activate.ts +++ b/packages/cli/package/src/commands/provider/cc-activate.ts @@ -18,11 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { depositCollateral } from "../../lib/chain/depositCollateral.js"; import { CC_FLAGS, CHAIN_FLAGS, FLT_SYMBOL } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class AddCollateral extends BaseCommand { - static override description = `Add ${FLT_SYMBOL} collateral to capacity commitment to activate it`; - static override aliases = ["provider:ca"]; + static override hiddenAliases = ["provider:ca"]; + static override description = `Add ${FLT_SYMBOL} collateral to capacity commitment to activate it${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...CC_FLAGS, diff --git a/packages/cli/package/src/commands/provider/cc-collateral-withdraw.ts b/packages/cli/package/src/commands/provider/cc-collateral-withdraw.ts deleted file mode 100644 index 0b72b14aa..000000000 --- a/packages/cli/package/src/commands/provider/cc-collateral-withdraw.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { BaseCommand } from "../../baseCommand.js"; -import { collateralWithdraw } from "../../lib/chain/commitment.js"; -import { CHAIN_FLAGS, FLT_SYMBOL, CC_FLAGS } from "../../lib/const.js"; -import { initCli } from "../../lib/lifeCycle.js"; - -// Deprecated alias for provider cc-finish -export default class CCCollateralWithdraw extends BaseCommand< - typeof CCCollateralWithdraw -> { - static override hidden = true; - static override aliases = ["provider:ccw"]; - static override description = `Move resources from deals, withdraw ${FLT_SYMBOL} collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments`; - static override flags = { - ...CC_FLAGS, - ...CHAIN_FLAGS, - }; - - async run(): Promise { - const { flags } = await initCli( - this, - await this.parse(CCCollateralWithdraw), - ); - - await collateralWithdraw(flags); - } -} diff --git a/packages/cli/package/src/commands/provider/cc-create.ts b/packages/cli/package/src/commands/provider/cc-create.ts index 8d709145c..14ee6a693 100644 --- a/packages/cli/package/src/commands/provider/cc-create.ts +++ b/packages/cli/package/src/commands/provider/cc-create.ts @@ -18,13 +18,14 @@ import { BaseCommand } from "../../baseCommand.js"; import { createCommitments } from "../../lib/chain/commitment.js"; import { NOX_NAMES_FLAG, CHAIN_FLAGS, OFFER_FLAG } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CreateCommitment extends BaseCommand< typeof CreateCommitment > { - static override aliases = ["provider:cc"]; - static override description = "Create Capacity commitment"; + static override hiddenAliases = ["provider:cc"]; + static override description = `Create Capacity commitment${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...NOX_NAMES_FLAG, diff --git a/packages/cli/package/src/commands/provider/cc-finish.ts b/packages/cli/package/src/commands/provider/cc-finish.ts index de86bae5a..7301123b4 100644 --- a/packages/cli/package/src/commands/provider/cc-finish.ts +++ b/packages/cli/package/src/commands/provider/cc-finish.ts @@ -18,11 +18,15 @@ import { BaseCommand } from "../../baseCommand.js"; import { collateralWithdraw } from "../../lib/chain/commitment.js"; import { CHAIN_FLAGS, FLT_SYMBOL, CC_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CCFinish extends BaseCommand { - static override aliases = ["provider:ccf"]; - static override description = `Move resources from deals, withdraw ${FLT_SYMBOL} collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments`; + static override hiddenAliases = [ + "provider:ccf", + "provider:cc-collateral-withdraw", + ]; + static override description = `Move resources from deals, withdraw ${FLT_SYMBOL} collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments${aliasesText.apply(this)}`; static override flags = { ...CC_FLAGS, ...CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/cc-info.ts b/packages/cli/package/src/commands/provider/cc-info.ts index 76cd3863d..52f3e002d 100644 --- a/packages/cli/package/src/commands/provider/cc-info.ts +++ b/packages/cli/package/src/commands/provider/cc-info.ts @@ -21,11 +21,12 @@ import { printCommitmentsInfoJSON, } from "../../lib/chain/commitment.js"; import { CHAIN_FLAGS, CC_FLAGS, JSON_FLAG } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CCInfo extends BaseCommand { - static override aliases = ["provider:ci"]; - static override description = "Get info about capacity commitments"; + static override hiddenAliases = ["provider:ci"]; + static override description = `Get info about capacity commitments${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...CC_FLAGS, diff --git a/packages/cli/package/src/commands/provider/cc-remove.ts b/packages/cli/package/src/commands/provider/cc-remove.ts index 3502ce5b6..dc8eac895 100644 --- a/packages/cli/package/src/commands/provider/cc-remove.ts +++ b/packages/cli/package/src/commands/provider/cc-remove.ts @@ -18,14 +18,14 @@ import { BaseCommand } from "../../baseCommand.js"; import { removeCommitments } from "../../lib/chain/commitment.js"; import { CC_FLAGS, CHAIN_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class RemoveCommitment extends BaseCommand< typeof RemoveCommitment > { - static override aliases = ["provider:cr"]; - static override description = - "Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral"; + static override hiddenAliases = ["provider:cr"]; + static override description = `Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...CC_FLAGS, diff --git a/packages/cli/package/src/commands/provider/cc-rewards-withdraw.ts b/packages/cli/package/src/commands/provider/cc-rewards-withdraw.ts index c0685ac17..9f1d35bc5 100644 --- a/packages/cli/package/src/commands/provider/cc-rewards-withdraw.ts +++ b/packages/cli/package/src/commands/provider/cc-rewards-withdraw.ts @@ -18,13 +18,14 @@ import { BaseCommand } from "../../baseCommand.js"; import { collateralRewardWithdraw } from "../../lib/chain/commitment.js"; import { CHAIN_FLAGS, FLT_SYMBOL, CC_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CCRewardsWithdraw extends BaseCommand< typeof CCRewardsWithdraw > { - static override aliases = ["provider:crw"]; - static override description = `Withdraw ${FLT_SYMBOL} rewards from capacity commitments`; + static override hiddenAliases = ["provider:crw"]; + static override description = `Withdraw ${FLT_SYMBOL} rewards from capacity commitments${aliasesText.apply(this)}`; static override flags = { ...CC_FLAGS, ...CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/deal-exit.ts b/packages/cli/package/src/commands/provider/deal-exit.ts index 7eeb47518..2f100ff52 100644 --- a/packages/cli/package/src/commands/provider/deal-exit.ts +++ b/packages/cli/package/src/commands/provider/deal-exit.ts @@ -30,13 +30,14 @@ import { populateTx, signBatch, } from "../../lib/dealClient.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { commaSepStrToArr } from "../../lib/helpers/utils.js"; import { initCli } from "../../lib/lifeCycle.js"; import { input } from "../../lib/prompt.js"; export default class DealExit extends BaseCommand { - static override aliases = ["provider:de"]; - static override description = "Exit from deal"; + static override hiddenAliases = ["provider:de"]; + static override description = `Exit from deal${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...DEAL_IDS_FLAG, diff --git a/packages/cli/package/src/commands/provider/deal-list.ts b/packages/cli/package/src/commands/provider/deal-list.ts index a2ac65f44..559e194e1 100644 --- a/packages/cli/package/src/commands/provider/deal-list.ts +++ b/packages/cli/package/src/commands/provider/deal-list.ts @@ -19,11 +19,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { getProviderDeals } from "../../lib/chain/deals.js"; import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class DealsList extends BaseCommand { - static override aliases = ["provider:dl"]; - static override description = "List all deals"; + static override hiddenAliases = ["provider:dl"]; + static override description = `List all deals${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/commands/provider/deal-rewards-info.ts b/packages/cli/package/src/commands/provider/deal-rewards-info.ts index b0b24c1a0..03773f09c 100644 --- a/packages/cli/package/src/commands/provider/deal-rewards-info.ts +++ b/packages/cli/package/src/commands/provider/deal-rewards-info.ts @@ -23,14 +23,15 @@ import { ptFormatWithSymbol } from "../../lib/chain/currencies.js"; import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS } from "../../lib/const.js"; import { getReadonlyContracts } from "../../lib/dealClient.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; import { input } from "../../lib/prompt.js"; export default class DealRewardsInfo extends BaseCommand< typeof DealRewardsInfo > { - static override aliases = ["provider:dri"]; - static override description = "Deal rewards info"; + static override hiddenAliases = ["provider:dri"]; + static override description = `Deal rewards info${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts b/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts index abd580652..30b4b1c7d 100644 --- a/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts +++ b/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts @@ -26,6 +26,7 @@ import { PT_SYMBOL, } from "../../lib/const.js"; import { getContracts, getEventValue, sign } from "../../lib/dealClient.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { commaSepStrToArr } from "../../lib/helpers/utils.js"; import { initCli } from "../../lib/lifeCycle.js"; import { input } from "../../lib/prompt.js"; @@ -35,8 +36,8 @@ const REWARD_WITHDRAWN_EVENT = "RewardWithdrawn"; export default class DealRewardsWithdraw extends BaseCommand< typeof DealRewardsWithdraw > { - static override aliases = ["provider:drw"]; - static override description = `Withdraw ${PT_SYMBOL} rewards from deals`; + static override hiddenAliases = ["provider:drw"]; + static override description = `Withdraw ${PT_SYMBOL} rewards from deals${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...DEAL_IDS_FLAG, diff --git a/packages/cli/package/src/commands/provider/info.ts b/packages/cli/package/src/commands/provider/info.ts index b595ffc52..0fc12102d 100644 --- a/packages/cli/package/src/commands/provider/info.ts +++ b/packages/cli/package/src/commands/provider/info.ts @@ -30,13 +30,14 @@ import { ADDRESS_FLAG_NAME, PRIV_KEY_FLAG_NAME, } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; import { resolveComputePeersByNames } from "../../lib/resolveComputePeersByNames.js"; import { ensureFluenceEnv } from "../../lib/resolveFluenceEnv.js"; export default class Info extends BaseCommand { - static override aliases = ["provider:i"]; - static override description = "Print nox signing wallets and peer ids"; + static override hiddenAliases = ["provider:i"]; + static override description = `Print nox signing wallets and peer ids${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...NOX_NAMES_FLAG, diff --git a/packages/cli/package/src/commands/provider/offer-create.ts b/packages/cli/package/src/commands/provider/offer-create.ts index bb2d337e7..d4e3f28ef 100644 --- a/packages/cli/package/src/commands/provider/offer-create.ts +++ b/packages/cli/package/src/commands/provider/offer-create.ts @@ -18,12 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { createOffers } from "../../lib/chain/offer/offer.js"; import { OFFER_FLAG, CHAIN_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class CreateOffer extends BaseCommand { - static override aliases = ["provider:oc"]; - static override description = - "Create offers. You have to be registered as a provider to do that"; + static override hiddenAliases = ["provider:oc"]; + static override description = `Create offers. You have to be registered as a provider to do that${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...OFFER_FLAG, diff --git a/packages/cli/package/src/commands/provider/offer-info.ts b/packages/cli/package/src/commands/provider/offer-info.ts index 8cde74ca6..62294b318 100644 --- a/packages/cli/package/src/commands/provider/offer-info.ts +++ b/packages/cli/package/src/commands/provider/offer-info.ts @@ -23,11 +23,12 @@ import { } from "../../lib/chain/offer/offer.js"; import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS, OFFER_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class OfferInfo extends BaseCommand { - static override aliases = ["provider:oi"]; - static override description = "Get info about offers"; + static override hiddenAliases = ["provider:oi"]; + static override description = `Get info about offers${aliasesText.apply(this)}`; static override flags = { ...OFFER_FLAGS, ...CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/offer-remove.ts b/packages/cli/package/src/commands/provider/offer-remove.ts index ebc03eb4a..9838c7d8d 100644 --- a/packages/cli/package/src/commands/provider/offer-remove.ts +++ b/packages/cli/package/src/commands/provider/offer-remove.ts @@ -18,11 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { removeOffers } from "../../lib/chain/offer/updateOffers.js"; import { CHAIN_FLAGS, OFFER_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class OfferRemove extends BaseCommand { - static override aliases = ["provider:or"]; - static override description = "Remove offers"; + static override hiddenAliases = ["provider:or"]; + static override description = `Remove offers${aliasesText.apply(this)}`; static override flags = { ...OFFER_FLAGS, ...CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/offer-update.ts b/packages/cli/package/src/commands/provider/offer-update.ts index f36eba314..80b73887d 100644 --- a/packages/cli/package/src/commands/provider/offer-update.ts +++ b/packages/cli/package/src/commands/provider/offer-update.ts @@ -18,11 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { updateOffers } from "../../lib/chain/offer/updateOffers.js"; import { CHAIN_FLAGS, OFFER_FLAG } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class OfferUpdate extends BaseCommand { - static override aliases = ["provider:ou"]; - static override description = "Update offers"; + static override hiddenAliases = ["provider:ou"]; + static override description = `Update offers${aliasesText.apply(this)}`; static override flags = { ...OFFER_FLAG, ...CHAIN_FLAGS, diff --git a/packages/cli/package/src/commands/provider/register.ts b/packages/cli/package/src/commands/provider/register.ts index 426ca7f41..534b892ce 100644 --- a/packages/cli/package/src/commands/provider/register.ts +++ b/packages/cli/package/src/commands/provider/register.ts @@ -18,11 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { registerProvider } from "../../lib/chain/providerInfo.js"; import { CHAIN_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class Register extends BaseCommand { - static override aliases = ["provider:r"]; - static override description = "Register as a provider"; + static override hiddenAliases = ["provider:r"]; + static override description = `Register as a provider${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/commands/provider/tokens-distribute.ts b/packages/cli/package/src/commands/provider/tokens-distribute.ts index f74c6fea0..98dd1edc8 100644 --- a/packages/cli/package/src/commands/provider/tokens-distribute.ts +++ b/packages/cli/package/src/commands/provider/tokens-distribute.ts @@ -25,13 +25,14 @@ import { NOX_NAMES_FLAG, OFFER_FLAG, } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class TokensDistribute extends BaseCommand< typeof TokensDistribute > { - static override aliases = ["provider:td"]; - static override description = `Distribute ${FLT_SYMBOL} tokens to noxes`; + static override hiddenAliases = ["provider:td"]; + static override description = `Distribute ${FLT_SYMBOL} tokens to noxes${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...NOX_NAMES_FLAG, diff --git a/packages/cli/package/src/commands/provider/tokens-withdraw.ts b/packages/cli/package/src/commands/provider/tokens-withdraw.ts index 9a96f257d..ba50dcf8b 100644 --- a/packages/cli/package/src/commands/provider/tokens-withdraw.ts +++ b/packages/cli/package/src/commands/provider/tokens-withdraw.ts @@ -25,13 +25,14 @@ import { MAX_TOKEN_AMOUNT_KEYWORD, NOX_NAMES_FLAG, } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; const AMOUNT_FLAG_NAME = "amount"; export default class TokensWithdraw extends BaseCommand { - static override aliases = ["provider:tw"]; - static override description = `Withdraw ${FLT_SYMBOL} tokens from noxes`; + static override hiddenAliases = ["provider:tw"]; + static override description = `Withdraw ${FLT_SYMBOL} tokens from noxes${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, ...NOX_NAMES_FLAG, diff --git a/packages/cli/package/src/commands/provider/update.ts b/packages/cli/package/src/commands/provider/update.ts index 0cab65edd..a79de501e 100644 --- a/packages/cli/package/src/commands/provider/update.ts +++ b/packages/cli/package/src/commands/provider/update.ts @@ -18,11 +18,12 @@ import { BaseCommand } from "../../baseCommand.js"; import { updateProvider } from "../../lib/chain/providerInfo.js"; import { CHAIN_FLAGS } from "../../lib/const.js"; +import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class Update extends BaseCommand { - static override aliases = ["provider:u"]; - static override description = "Update provider info"; + static override hiddenAliases = ["provider:u"]; + static override description = `Update provider info${aliasesText.apply(this)}`; static override flags = { ...CHAIN_FLAGS, }; diff --git a/packages/cli/package/src/lib/helpers/aliasesText.ts b/packages/cli/package/src/lib/helpers/aliasesText.ts new file mode 100644 index 000000000..ea7bcdd43 --- /dev/null +++ b/packages/cli/package/src/lib/helpers/aliasesText.ts @@ -0,0 +1,30 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { CLI_NAME } from "../const.js"; + +export function aliasesText(this: { hiddenAliases: string[] }) { + if (this.hiddenAliases.length === 0) { + return ""; + } + + return `. Alias${this.hiddenAliases.length === 1 ? "" : "es"}: ${this.hiddenAliases + .map((alias) => { + return `${CLI_NAME} ${alias.split(":").join(" ")}`; + }) + .join(", ")}`; +} From 2d4acd2b873900763ed368f96834b304a1c0d379 Mon Sep 17 00:00:00 2001 From: shamsartem Date: Thu, 31 Oct 2024 15:38:28 +0000 Subject: [PATCH 11/37] Apply automatic changes --- packages/cli/package/docs/commands/README.md | 213 ++++++------------- 1 file changed, 63 insertions(+), 150 deletions(-) diff --git a/packages/cli/package/docs/commands/README.md b/packages/cli/package/docs/commands/README.md index c0d34de1e..63c631493 100644 --- a/packages/cli/package/docs/commands/README.md +++ b/packages/cli/package/docs/commands/README.md @@ -74,7 +74,7 @@ ## `fluence air beautify [PATH]` -Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended to be read by mere mortals. +Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended to be read by mere mortals. Alias: fluence air b ``` USAGE @@ -88,10 +88,7 @@ FLAGS DESCRIPTION Prints AIR script in human-readable Python-like representation. This representation cannot be executed and is intended - to be read by mere mortals. - -ALIASES - $ fluence air b + to be read by mere mortals. Alias: fluence air b ``` _See code: [src/commands/air/beautify.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/air/beautify.ts)_ @@ -183,7 +180,7 @@ _See code: [src/commands/aqua/json.ts](https://github.com/fluencelabs/cli/blob/f ## `fluence aqua yml [INPUT] [OUTPUT]` -Infers aqua types for an arbitrary yaml file, generates valid aqua code with a function call that returns an aqua object literal with the same structure as the yaml file. For valid generation please refer to aqua documentation https://fluence.dev/docs/aqua-book/language/ to learn about what kind of structures are valid in aqua language and what they translate into +Infers aqua types for an arbitrary yaml file, generates valid aqua code with a function call that returns an aqua object literal with the same structure as the yaml file. For valid generation please refer to aqua documentation https://fluence.dev/docs/aqua-book/language/ to learn about what kind of structures are valid in aqua language and what they translate into. Alias: fluence aqua yaml ``` USAGE @@ -204,10 +201,7 @@ DESCRIPTION Infers aqua types for an arbitrary yaml file, generates valid aqua code with a function call that returns an aqua object literal with the same structure as the yaml file. For valid generation please refer to aqua documentation https://fluence.dev/docs/aqua-book/language/ to learn about what kind of structures are valid in aqua language and - what they translate into - -ALIASES - $ fluence aqua yaml + what they translate into. Alias: fluence aqua yaml ``` _See code: [src/commands/aqua/yml.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/aqua/yml.ts)_ @@ -504,7 +498,7 @@ _See code: [src/commands/deal/withdraw.ts](https://github.com/fluencelabs/cli/bl ## `fluence deal workers-add [DEPLOYMENT-NAMES]` -Add missing workers to the deal +Add missing workers to the deal. Alias: fluence deal wa ``` USAGE @@ -524,17 +518,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Add missing workers to the deal - -ALIASES - $ fluence deal wa + Add missing workers to the deal. Alias: fluence deal wa ``` _See code: [src/commands/deal/workers-add.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/deal/workers-add.ts)_ ## `fluence deal workers-remove [WORKER-IDS]` -Remove unit from the deal +Remove unit from the deal. Alias: fluence deal wr ``` USAGE @@ -555,10 +546,7 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Remove unit from the deal - -ALIASES - $ fluence deal wr + Remove unit from the deal. Alias: fluence deal wr ``` _See code: [src/commands/deal/workers-remove.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/deal/workers-remove.ts)_ @@ -611,7 +599,7 @@ _See code: [src/commands/default/peers.ts](https://github.com/fluencelabs/cli/bl ## `fluence delegator collateral-add [IDS]` -Add FLT collateral to capacity commitment +Add FLT collateral to capacity commitment. Alias: fluence delegator ca ``` USAGE @@ -630,17 +618,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Add FLT collateral to capacity commitment - -ALIASES - $ fluence delegator ca + Add FLT collateral to capacity commitment. Alias: fluence delegator ca ``` _See code: [src/commands/delegator/collateral-add.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/delegator/collateral-add.ts)_ ## `fluence delegator collateral-withdraw [IDS]` -Withdraw FLT collateral from capacity commitment +Withdraw FLT collateral from capacity commitment. Alias: fluence delegator cw ``` USAGE @@ -660,17 +645,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw FLT collateral from capacity commitment - -ALIASES - $ fluence delegator cw + Withdraw FLT collateral from capacity commitment. Alias: fluence delegator cw ``` _See code: [src/commands/delegator/collateral-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/delegator/collateral-withdraw.ts)_ ## `fluence delegator reward-withdraw [IDS]` -Withdraw FLT rewards from capacity commitment +Withdraw FLT rewards from capacity commitment. Alias: fluence delegator rw ``` USAGE @@ -689,17 +671,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw FLT rewards from capacity commitment - -ALIASES - $ fluence delegator rw + Withdraw FLT rewards from capacity commitment. Alias: fluence delegator rw ``` _See code: [src/commands/delegator/reward-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/delegator/reward-withdraw.ts)_ ## `fluence dep install [PACKAGE-NAME | PACKAGE-NAME@VERSION]` -Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies) +Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies). Alias: fluence dep i ``` USAGE @@ -714,10 +693,8 @@ FLAGS --no-input Don't interactively ask for any input from the user DESCRIPTION - Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies) - -ALIASES - $ fluence dep i + Install aqua project dependencies (currently npm is used under the hood for managing aqua dependencies). Alias: + fluence dep i EXAMPLES $ fluence dep install @@ -727,7 +704,7 @@ _See code: [src/commands/dep/install.ts](https://github.com/fluencelabs/cli/blob ## `fluence dep reset` -Reset all project dependencies to recommended versions +Reset all project dependencies to recommended versions. Alias: fluence dep r ``` USAGE @@ -737,10 +714,7 @@ FLAGS --no-input Don't interactively ask for any input from the user DESCRIPTION - Reset all project dependencies to recommended versions - -ALIASES - $ fluence dep r + Reset all project dependencies to recommended versions. Alias: fluence dep r EXAMPLES $ fluence dep reset @@ -750,7 +724,7 @@ _See code: [src/commands/dep/reset.ts](https://github.com/fluencelabs/cli/blob/f ## `fluence dep uninstall PACKAGE-NAME` -Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies) +Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies). Alias: fluence dep un ``` USAGE @@ -763,10 +737,8 @@ FLAGS --no-input Don't interactively ask for any input from the user DESCRIPTION - Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies) - -ALIASES - $ fluence dep un + Uninstall aqua project dependencies (currently npm is used under the hood for managing aqua dependencies). Alias: + fluence dep un EXAMPLES $ fluence dep uninstall @@ -776,7 +748,7 @@ _See code: [src/commands/dep/uninstall.ts](https://github.com/fluencelabs/cli/bl ## `fluence dep versions` -Get versions of all cli dependencies, including aqua, marine, mrepl and internal +Get versions of all cli dependencies, including aqua, marine, mrepl and internal. Alias: fluence dep v ``` USAGE @@ -789,10 +761,7 @@ FLAGS --no-input Don't interactively ask for any input from the user DESCRIPTION - Get versions of all cli dependencies, including aqua, marine, mrepl and internal - -ALIASES - $ fluence dep v + Get versions of all cli dependencies, including aqua, marine, mrepl and internal. Alias: fluence dep v EXAMPLES $ fluence dep versions @@ -1215,7 +1184,7 @@ _See code: [src/commands/module/remove.ts](https://github.com/fluencelabs/cli/bl ## `fluence provider cc-activate` -Add FLT collateral to capacity commitment to activate it +Add FLT collateral to capacity commitment to activate it. Alias: fluence provider ca ``` USAGE @@ -1236,17 +1205,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Add FLT collateral to capacity commitment to activate it - -ALIASES - $ fluence provider ca + Add FLT collateral to capacity commitment to activate it. Alias: fluence provider ca ``` _See code: [src/commands/provider/cc-activate.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-activate.ts)_ ## `fluence provider cc-create` -Create Capacity commitment +Create Capacity commitment. Alias: fluence provider cc ``` USAGE @@ -1266,17 +1232,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Create Capacity commitment - -ALIASES - $ fluence provider cc + Create Capacity commitment. Alias: fluence provider cc ``` _See code: [src/commands/provider/cc-create.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-create.ts)_ ## `fluence provider cc-finish` -Move resources from deals, withdraw FLT collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments +Move resources from deals, withdraw FLT collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments. Aliases: fluence provider ccf, fluence provider cc-collateral-withdraw ``` USAGE @@ -1298,17 +1261,14 @@ FLAGS DESCRIPTION Move resources from deals, withdraw FLT collateral from capacity commitments, remove compute units from capacity - commitments and finish capacity commitments - -ALIASES - $ fluence provider ccf + commitments and finish capacity commitments. Aliases: fluence provider ccf, fluence provider cc-collateral-withdraw ``` _See code: [src/commands/provider/cc-finish.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-finish.ts)_ ## `fluence provider cc-info` -Get info about capacity commitments +Get info about capacity commitments. Alias: fluence provider ci ``` USAGE @@ -1330,17 +1290,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Get info about capacity commitments - -ALIASES - $ fluence provider ci + Get info about capacity commitments. Alias: fluence provider ci ``` _See code: [src/commands/provider/cc-info.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-info.ts)_ ## `fluence provider cc-remove` -Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral +Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral. Alias: fluence provider cr ``` USAGE @@ -1361,17 +1318,15 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral - -ALIASES - $ fluence provider cr + Remove Capacity commitment. You can remove it only BEFORE you activated it by depositing collateral. Alias: fluence + provider cr ``` _See code: [src/commands/provider/cc-remove.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-remove.ts)_ ## `fluence provider cc-rewards-withdraw` -Withdraw FLT rewards from capacity commitments +Withdraw FLT rewards from capacity commitments. Alias: fluence provider crw ``` USAGE @@ -1392,17 +1347,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw FLT rewards from capacity commitments - -ALIASES - $ fluence provider crw + Withdraw FLT rewards from capacity commitments. Alias: fluence provider crw ``` _See code: [src/commands/provider/cc-rewards-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/cc-rewards-withdraw.ts)_ ## `fluence provider deal-exit` -Exit from deal +Exit from deal. Alias: fluence provider de ``` USAGE @@ -1420,17 +1372,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Exit from deal - -ALIASES - $ fluence provider de + Exit from deal. Alias: fluence provider de ``` _See code: [src/commands/provider/deal-exit.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/deal-exit.ts)_ ## `fluence provider deal-list` -List all deals +List all deals. Alias: fluence provider dl ``` USAGE @@ -1445,17 +1394,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - List all deals - -ALIASES - $ fluence provider dl + List all deals. Alias: fluence provider dl ``` _See code: [src/commands/provider/deal-list.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/deal-list.ts)_ ## `fluence provider deal-rewards-info [DEAL-ADDRESS] [ON-CHAIN-WORKER-ID]` -Deal rewards info +Deal rewards info. Alias: fluence provider dri ``` USAGE @@ -1475,17 +1421,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Deal rewards info - -ALIASES - $ fluence provider dri + Deal rewards info. Alias: fluence provider dri ``` _See code: [src/commands/provider/deal-rewards-info.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/deal-rewards-info.ts)_ ## `fluence provider deal-rewards-withdraw` -Withdraw USDC rewards from deals +Withdraw USDC rewards from deals. Alias: fluence provider drw ``` USAGE @@ -1502,10 +1445,7 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw USDC rewards from deals - -ALIASES - $ fluence provider drw + Withdraw USDC rewards from deals. Alias: fluence provider drw ``` _See code: [src/commands/provider/deal-rewards-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/deal-rewards-withdraw.ts)_ @@ -1543,7 +1483,7 @@ _See code: [src/commands/provider/gen.ts](https://github.com/fluencelabs/cli/blo ## `fluence provider info` -Print nox signing wallets and peer ids +Print nox signing wallets and peer ids. Alias: fluence provider i ``` USAGE @@ -1563,10 +1503,7 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Print nox signing wallets and peer ids - -ALIASES - $ fluence provider i + Print nox signing wallets and peer ids. Alias: fluence provider i ``` _See code: [src/commands/provider/info.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/info.ts)_ @@ -1598,7 +1535,7 @@ _See code: [src/commands/provider/init.ts](https://github.com/fluencelabs/cli/bl ## `fluence provider offer-create` -Create offers. You have to be registered as a provider to do that +Create offers. You have to be registered as a provider to do that. Alias: fluence provider oc ``` USAGE @@ -1616,17 +1553,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Create offers. You have to be registered as a provider to do that - -ALIASES - $ fluence provider oc + Create offers. You have to be registered as a provider to do that. Alias: fluence provider oc ``` _See code: [src/commands/provider/offer-create.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/offer-create.ts)_ ## `fluence provider offer-info` -Get info about offers +Get info about offers. Alias: fluence provider oi ``` USAGE @@ -1646,17 +1580,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Get info about offers - -ALIASES - $ fluence provider oi + Get info about offers. Alias: fluence provider oi ``` _See code: [src/commands/provider/offer-info.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/offer-info.ts)_ ## `fluence provider offer-remove` -Remove offers +Remove offers. Alias: fluence provider or ``` USAGE @@ -1676,17 +1607,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Remove offers - -ALIASES - $ fluence provider or + Remove offers. Alias: fluence provider or ``` _See code: [src/commands/provider/offer-remove.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/offer-remove.ts)_ ## `fluence provider offer-update` -Update offers +Update offers. Alias: fluence provider ou ``` USAGE @@ -1704,17 +1632,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Update offers - -ALIASES - $ fluence provider ou + Update offers. Alias: fluence provider ou ``` _See code: [src/commands/provider/offer-update.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/offer-update.ts)_ ## `fluence provider register` -Register as a provider +Register as a provider. Alias: fluence provider r ``` USAGE @@ -1729,17 +1654,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Register as a provider - -ALIASES - $ fluence provider r + Register as a provider. Alias: fluence provider r ``` _See code: [src/commands/provider/register.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/register.ts)_ ## `fluence provider tokens-distribute` -Distribute FLT tokens to noxes +Distribute FLT tokens to noxes. Alias: fluence provider td ``` USAGE @@ -1760,17 +1682,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Distribute FLT tokens to noxes - -ALIASES - $ fluence provider td + Distribute FLT tokens to noxes. Alias: fluence provider td ``` _See code: [src/commands/provider/tokens-distribute.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/tokens-distribute.ts)_ ## `fluence provider tokens-withdraw` -Withdraw FLT tokens from noxes +Withdraw FLT tokens from noxes. Alias: fluence provider tw ``` USAGE @@ -1790,17 +1709,14 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw FLT tokens from noxes - -ALIASES - $ fluence provider tw + Withdraw FLT tokens from noxes. Alias: fluence provider tw ``` _See code: [src/commands/provider/tokens-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/tokens-withdraw.ts)_ ## `fluence provider update` -Update provider info +Update provider info. Alias: fluence provider u ``` USAGE @@ -1815,10 +1731,7 @@ FLAGS by default when CLI is used in non-interactive mode DESCRIPTION - Update provider info - -ALIASES - $ fluence provider u + Update provider info. Alias: fluence provider u ``` _See code: [src/commands/provider/update.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.22.0/src/commands/provider/update.ts)_ From 41bcde0efb3e7233064ad71895a3628d73233f56 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Fri, 1 Nov 2024 16:14:06 +0100 Subject: [PATCH 12/37] stop managing ocker compose config completely --- .../cli/package/src/commands/local/down.ts | 14 +- .../cli/package/src/commands/local/init.ts | 19 +- .../cli/package/src/commands/local/logs.ts | 12 +- packages/cli/package/src/commands/local/ps.ts | 12 +- packages/cli/package/src/commands/local/up.ts | 36 +- .../package/src/lib/configs/initConfigNew.ts | 25 +- .../lib/configs/project/compose.schema.json | 943 ------------------ .../src/lib/configs/project/dockerCompose.ts | 76 +- packages/cli/package/src/lib/paths.ts | 5 + 9 files changed, 64 insertions(+), 1078 deletions(-) delete mode 100644 packages/cli/package/src/lib/configs/project/compose.schema.json diff --git a/packages/cli/package/src/commands/local/down.ts b/packages/cli/package/src/commands/local/down.ts index b1e8ceb2b..675dfcdfb 100644 --- a/packages/cli/package/src/commands/local/down.ts +++ b/packages/cli/package/src/commands/local/down.ts @@ -15,10 +15,12 @@ * along with this program. If not, see . */ +import { dirname } from "path"; + import { Flags } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; -import { initNewReadonlyDockerComposeConfig } from "../../lib/configs/project/dockerCompose.js"; +import { ensureDockerComposeConfig } from "../../lib/configs/project/dockerCompose.js"; import { DOCKER_COMPOSE_FULL_FILE_NAME, DOCKER_COMPOSE_FLAGS, @@ -40,20 +42,16 @@ export default class Down extends BaseCommand { }; async run(): Promise { const { flags } = await initCli(this, await this.parse(Down)); - const dockerComposeConfig = await initNewReadonlyDockerComposeConfig(); + const dockerComposeConfigPath = await ensureDockerComposeConfig(); await dockerCompose({ args: [ "down", ...(flags.flags === undefined ? [] : flags.flags.split(" ")), ], - flags: { - v: flags.volumes, - }, + flags: { v: flags.volumes }, printOutput: true, - options: { - cwd: dockerComposeConfig.$getDirPath(), - }, + options: { cwd: dirname(dockerComposeConfigPath) }, }); } } diff --git a/packages/cli/package/src/commands/local/init.ts b/packages/cli/package/src/commands/local/init.ts index aca654a3c..1d63ccfc3 100644 --- a/packages/cli/package/src/commands/local/init.ts +++ b/packages/cli/package/src/commands/local/init.ts @@ -22,8 +22,8 @@ import { color } from "@oclif/color"; import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; import { - initNewReadonlyDockerComposeConfig, - initReadonlyDockerComposeConfig, + ensureDockerComposeConfig, + checkDockerComposeConfigExists, } from "../../lib/configs/project/dockerCompose.js"; import { initNewProviderConfig } from "../../lib/configs/project/provider/provider.js"; import { @@ -43,27 +43,26 @@ export default class Init extends BaseCommand { async run(): Promise { await initCli(this, await this.parse(Init)); await initNewProviderConfig(); - const existingDockerCompose = await initReadonlyDockerComposeConfig(); + const existingDockerComposePath = await checkDockerComposeConfigExists(); - if (existingDockerCompose !== null) { + if (existingDockerComposePath !== null) { const isOverwriting = await confirm({ message: `Do you want to replace existing ${color.yellow( - existingDockerCompose.$getPath(), + existingDockerComposePath, )}`, default: false, }); if (!isOverwriting) { commandObj.error( - `The config already exists at ${existingDockerCompose.$getPath()}. Aborting.`, + `The config already exists at ${existingDockerComposePath}. Aborting.`, ); } - await rm(existingDockerCompose.$getPath()); + await rm(existingDockerComposePath); } - const dockerCompose = await initNewReadonlyDockerComposeConfig(); - - commandObj.logToStderr(`Created new config at ${dockerCompose.$getPath()}`); + const dockerComposePath = await ensureDockerComposeConfig(); + commandObj.logToStderr(`Created new config at ${dockerComposePath}`); } } diff --git a/packages/cli/package/src/commands/local/logs.ts b/packages/cli/package/src/commands/local/logs.ts index 6a735b68e..4f2a0572f 100644 --- a/packages/cli/package/src/commands/local/logs.ts +++ b/packages/cli/package/src/commands/local/logs.ts @@ -15,9 +15,11 @@ * along with this program. If not, see . */ +import { dirname } from "path"; + import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; -import { initReadonlyDockerComposeConfig } from "../../lib/configs/project/dockerCompose.js"; +import { checkDockerComposeConfigExists } from "../../lib/configs/project/dockerCompose.js"; import { DOCKER_COMPOSE_FULL_FILE_NAME, DOCKER_COMPOSE_FLAGS, @@ -33,9 +35,9 @@ export default class Logs extends BaseCommand { }; async run(): Promise { const { flags } = await initCli(this, await this.parse(Logs)); - const dockerComposeConfig = await initReadonlyDockerComposeConfig(); + const dockerComposeConfigPath = await checkDockerComposeConfigExists(); - if (dockerComposeConfig === null) { + if (dockerComposeConfigPath === null) { commandObj.error( `Cannot find ${DOCKER_COMPOSE_FULL_FILE_NAME}. Aborting.`, ); @@ -46,9 +48,7 @@ export default class Logs extends BaseCommand { "logs", ...(flags.flags === undefined ? [] : flags.flags.split(" ")), ], - options: { - cwd: dockerComposeConfig.$getDirPath(), - }, + options: { cwd: dirname(dockerComposeConfigPath) }, }); commandObj.log(logs); diff --git a/packages/cli/package/src/commands/local/ps.ts b/packages/cli/package/src/commands/local/ps.ts index 09601b3a6..a7830eb74 100644 --- a/packages/cli/package/src/commands/local/ps.ts +++ b/packages/cli/package/src/commands/local/ps.ts @@ -15,9 +15,11 @@ * along with this program. If not, see . */ +import { dirname } from "path"; + import { BaseCommand } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; -import { initReadonlyDockerComposeConfig } from "../../lib/configs/project/dockerCompose.js"; +import { checkDockerComposeConfigExists } from "../../lib/configs/project/dockerCompose.js"; import { DOCKER_COMPOSE_FULL_FILE_NAME, DOCKER_COMPOSE_FLAGS, @@ -33,9 +35,9 @@ export default class PS extends BaseCommand { }; async run(): Promise { const { flags } = await initCli(this, await this.parse(PS)); - const dockerComposeConfig = await initReadonlyDockerComposeConfig(); + const dockerComposeConfigPath = await checkDockerComposeConfigExists(); - if (dockerComposeConfig === null) { + if (dockerComposeConfigPath === null) { commandObj.error( `Cannot find ${DOCKER_COMPOSE_FULL_FILE_NAME}. Aborting.`, ); @@ -46,9 +48,7 @@ export default class PS extends BaseCommand { "ps", ...(flags.flags === undefined ? [] : flags.flags.split(" ")), ], - options: { - cwd: dockerComposeConfig.$getDirPath(), - }, + options: { cwd: dirname(dockerComposeConfigPath) }, }); commandObj.log(psResult); diff --git a/packages/cli/package/src/commands/local/up.ts b/packages/cli/package/src/commands/local/up.ts index 121241dd8..b13a53c68 100644 --- a/packages/cli/package/src/commands/local/up.ts +++ b/packages/cli/package/src/commands/local/up.ts @@ -16,7 +16,7 @@ */ import { rm } from "node:fs/promises"; -import { join } from "node:path"; +import { dirname } from "node:path"; import { Flags } from "@oclif/core"; @@ -28,17 +28,13 @@ import { distributeToNox } from "../../lib/chain/distributeToNox.js"; import { createOffers } from "../../lib/chain/offer/offer.js"; import { registerProvider } from "../../lib/chain/providerInfo.js"; import { setChainFlags } from "../../lib/chainFlags.js"; -import { - initNewReadonlyDockerComposeConfig, - dockerComposeDirPath, -} from "../../lib/configs/project/dockerCompose.js"; +import { ensureDockerComposeConfig } from "../../lib/configs/project/dockerCompose.js"; import { initNewEnvConfig } from "../../lib/configs/project/env/env.js"; import { initFluenceConfig } from "../../lib/configs/project/fluence.js"; import { initNewWorkersConfig } from "../../lib/configs/project/workers.js"; import { DOCKER_COMPOSE_FLAGS, OFFER_FLAG_NAME, - PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, ALL_FLAG_VALUE, DOCKER_COMPOSE_FULL_FILE_NAME, NOXES_FLAG, @@ -50,6 +46,10 @@ import { import { ensureAquaFileWithWorkerInfo } from "../../lib/deployWorkers.js"; import { dockerCompose } from "../../lib/dockerCompose.js"; import { initCli } from "../../lib/lifeCycle.js"; +import { + ensureDockerComposeConfigPath, + ensureProviderArtifactsConfigPath, +} from "../../lib/paths.js"; export default class Up extends BaseCommand { static override description = `Run ${DOCKER_COMPOSE_FULL_FILE_NAME} using docker compose and set up provider using all the offers from the 'offers' section in ${PROVIDER_CONFIG_FULL_FILE_NAME} config using default wallet key ${LOCAL_NET_DEFAULT_WALLET_KEY}`; @@ -105,29 +105,25 @@ export default class Up extends BaseCommand { [PRIV_KEY_FLAG_NAME]: LOCAL_NET_DEFAULT_WALLET_KEY, }); - if (!flags["no-reset"]) { - const dirPath = dockerComposeDirPath(); - await initNewReadonlyDockerComposeConfig(); + const dockerComposeConfigPath = await ensureDockerComposeConfigPath(); + const dockerComposeDir = dirname(dockerComposeConfigPath); + if (!flags["no-reset"]) { try { await dockerCompose({ args: ["down"], - flags: { - v: true, - }, + flags: { v: true }, printOutput: true, - options: { - cwd: dirPath, - }, + options: { cwd: dockerComposeDir }, }); } catch {} try { - await rm(join(dirPath, DOCKER_COMPOSE_FULL_FILE_NAME)); + await rm(dockerComposeConfigPath); } catch {} try { - await rm(join(dirPath, PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME)); + await rm(await ensureProviderArtifactsConfigPath()); } catch {} const workersConfig = await initNewWorkersConfig(); @@ -142,7 +138,7 @@ export default class Up extends BaseCommand { } } - const dockerComposeConfig = await initNewReadonlyDockerComposeConfig(); + await ensureDockerComposeConfig(); await dockerCompose({ args: [ @@ -156,9 +152,7 @@ export default class Up extends BaseCommand { wait: !flags["no-wait"], }, printOutput: true, - options: { - cwd: dockerComposeConfig.$getDirPath(), - }, + options: { cwd: dockerComposeDir }, }); if (flags["no-set-up"]) { diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index 210b94527..976d3b707 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -29,7 +29,6 @@ import { FS_OPTIONS, YAML_EXT, YML_EXT, - DOCKER_COMPOSE_FILE_NAME, CLI_NAME_FULL, SCHEMAS_DIR_NAME, } from "../const.js"; @@ -287,7 +286,6 @@ async function getLatestConfig({ import("yaml-diff-patch"), ]); - const configName = getConfigName(expectedConfigPath); let configString: string; let actualConfigPath = expectedConfigPath; @@ -325,33 +323,12 @@ async function getLatestConfig({ configString = yamlDiffPatch( `# ${description}\n\n`, {}, - { - ...(configName === DOCKER_COMPOSE_FILE_NAME - ? {} - : { version: options.length - 1 }), - ...(await getDefaultConfig()), - }, + { version: options.length - 1, ...(await getDefaultConfig()) }, ); } const currentConfigUnknown: unknown = parse(configString); - if (configName === DOCKER_COMPOSE_FILE_NAME) { - await saveConfig(actualConfigPath, configString); - - return { - // CLI will not validate docker-compose at all to not cause additional problems for the users - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - latestConfig: currentConfigUnknown as LatestConfig, - latestConfigString: configString, - actualConfigPath, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - validateLatestConfig: (() => { - return Promise.resolve(currentConfigUnknown); - }) as ReturnType>, - }; - } - if ( typeof currentConfigUnknown !== "object" || currentConfigUnknown === null diff --git a/packages/cli/package/src/lib/configs/project/compose.schema.json b/packages/cli/package/src/lib/configs/project/compose.schema.json deleted file mode 100644 index 9d79267b0..000000000 --- a/packages/cli/package/src/lib/configs/project/compose.schema.json +++ /dev/null @@ -1,943 +0,0 @@ -{ - "$id": "compose_spec.json", - "type": "object", - "title": "Compose Specification", - "description": "The Compose file is a YAML file defining a multi-containers based application.", - - "properties": { - "version": { - "type": "string", - "description": "declared for backward compatibility, ignored." - }, - - "name": { - "type": "string", - "pattern": "^[a-z0-9][a-z0-9_-]*$", - "description": "define the Compose project name, until user defines one explicitly." - }, - - "include": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/include" - }, - "description": "compose sub-projects to be included." - }, - - "services": { - "$id": "#/properties/services", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "$ref": "#/definitions/service" - } - }, - "additionalProperties": false - }, - - "networks": { - "$id": "#/properties/networks", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "$ref": "#/definitions/network" - } - } - }, - - "volumes": { - "$id": "#/properties/volumes", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "$ref": "#/definitions/volume" - } - }, - "additionalProperties": false - }, - - "secrets": { - "$id": "#/properties/secrets", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "$ref": "#/definitions/secret" - } - }, - "additionalProperties": false - }, - - "configs": { - "$id": "#/properties/configs", - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "$ref": "#/definitions/config" - } - }, - "additionalProperties": false - } - }, - - "patternProperties": { "^x-": {} }, - "additionalProperties": false, - - "definitions": { - "service": { - "$id": "#/definitions/service", - "type": "object", - - "properties": { - "develop": { "$ref": "#/definitions/development" }, - "deploy": { "$ref": "#/definitions/deployment" }, - "annotations": { "$ref": "#/definitions/list_or_dict" }, - "attach": { "type": "boolean" }, - "build": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "context": { "type": "string" }, - "dockerfile": { "type": "string" }, - "dockerfile_inline": { "type": "string" }, - "args": { "$ref": "#/definitions/list_or_dict" }, - "ssh": { "$ref": "#/definitions/list_or_dict" }, - "labels": { "$ref": "#/definitions/list_or_dict" }, - "cache_from": { - "type": "array", - "items": { "type": "string" } - }, - "cache_to": { "type": "array", "items": { "type": "string" } }, - "no_cache": { "type": "boolean" }, - "additional_contexts": { "$ref": "#/definitions/list_or_dict" }, - "network": { "type": "string" }, - "pull": { "type": "boolean" }, - "target": { "type": "string" }, - "shm_size": { "type": ["integer", "string"] }, - "extra_hosts": { "$ref": "#/definitions/list_or_dict" }, - "isolation": { "type": "string" }, - "privileged": { "type": "boolean" }, - "secrets": { "$ref": "#/definitions/service_config_or_secret" }, - "tags": { "type": "array", "items": { "type": "string" } }, - "ulimits": { "$ref": "#/definitions/ulimits" }, - "platforms": { "type": "array", "items": { "type": "string" } } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - ] - }, - "blkio_config": { - "type": "object", - "properties": { - "device_read_bps": { - "type": "array", - "items": { "$ref": "#/definitions/blkio_limit" } - }, - "device_read_iops": { - "type": "array", - "items": { "$ref": "#/definitions/blkio_limit" } - }, - "device_write_bps": { - "type": "array", - "items": { "$ref": "#/definitions/blkio_limit" } - }, - "device_write_iops": { - "type": "array", - "items": { "$ref": "#/definitions/blkio_limit" } - }, - "weight": { "type": "integer" }, - "weight_device": { - "type": "array", - "items": { "$ref": "#/definitions/blkio_weight" } - } - }, - "additionalProperties": false - }, - "cap_add": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "cap_drop": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "cgroup": { "type": "string", "enum": ["host", "private"] }, - "cgroup_parent": { "type": "string" }, - "command": { "$ref": "#/definitions/command" }, - "configs": { "$ref": "#/definitions/service_config_or_secret" }, - "container_name": { "type": "string" }, - "cpu_count": { "type": "integer", "minimum": 0 }, - "cpu_percent": { "type": "integer", "minimum": 0, "maximum": 100 }, - "cpu_shares": { "type": ["number", "string"] }, - "cpu_quota": { "type": ["number", "string"] }, - "cpu_period": { "type": ["number", "string"] }, - "cpu_rt_period": { "type": ["number", "string"] }, - "cpu_rt_runtime": { "type": ["number", "string"] }, - "cpus": { "type": ["number", "string"] }, - "cpuset": { "type": "string" }, - "credential_spec": { - "type": "object", - "properties": { - "config": { "type": "string" }, - "file": { "type": "string" }, - "registry": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "depends_on": { - "oneOf": [ - { "$ref": "#/definitions/list_of_strings" }, - { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "type": "object", - "additionalProperties": false, - "properties": { - "restart": { "type": "boolean" }, - "required": { - "type": "boolean", - "default": true - }, - "condition": { - "type": "string", - "enum": [ - "service_started", - "service_healthy", - "service_completed_successfully" - ] - } - }, - "required": ["condition"] - } - } - } - ] - }, - "device_cgroup_rules": { "$ref": "#/definitions/list_of_strings" }, - "devices": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "dns": { "$ref": "#/definitions/string_or_list" }, - "dns_opt": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "dns_search": { "$ref": "#/definitions/string_or_list" }, - "domainname": { "type": "string" }, - "entrypoint": { "$ref": "#/definitions/command" }, - "env_file": { "$ref": "#/definitions/env_file" }, - "environment": { "$ref": "#/definitions/list_or_dict" }, - - "expose": { - "type": "array", - "items": { - "type": ["string", "number"] - }, - "uniqueItems": true - }, - "extends": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - - "properties": { - "service": { "type": "string" }, - "file": { "type": "string" } - }, - "required": ["service"], - "additionalProperties": false - } - ] - }, - "external_links": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "extra_hosts": { "$ref": "#/definitions/list_or_dict" }, - "group_add": { - "type": "array", - "items": { - "type": ["string", "number"] - }, - "uniqueItems": true - }, - "healthcheck": { "$ref": "#/definitions/healthcheck" }, - "hostname": { "type": "string" }, - "image": { "type": "string" }, - "init": { "type": "boolean" }, - "ipc": { "type": "string" }, - "isolation": { "type": "string" }, - "labels": { "$ref": "#/definitions/list_or_dict" }, - "links": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "logging": { - "type": "object", - - "properties": { - "driver": { "type": "string" }, - "options": { - "type": "object", - "patternProperties": { - "^.+$": { "type": ["string", "number", "null"] } - } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "mac_address": { "type": "string" }, - "mem_limit": { "type": ["number", "string"] }, - "mem_reservation": { "type": ["string", "integer"] }, - "mem_swappiness": { "type": "integer" }, - "memswap_limit": { "type": ["number", "string"] }, - "network_mode": { "type": "string" }, - "networks": { - "oneOf": [ - { "$ref": "#/definitions/list_of_strings" }, - { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9._-]+$": { - "oneOf": [ - { - "type": "object", - "properties": { - "aliases": { "$ref": "#/definitions/list_of_strings" }, - "ipv4_address": { "type": "string" }, - "ipv6_address": { "type": "string" }, - "link_local_ips": { - "$ref": "#/definitions/list_of_strings" - }, - "mac_address": { "type": "string" }, - "priority": { "type": "number" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - { "type": "null" } - ] - } - }, - "additionalProperties": false - } - ] - }, - "oom_kill_disable": { "type": "boolean" }, - "oom_score_adj": { - "type": "integer", - "minimum": -1000, - "maximum": 1000 - }, - "pid": { "type": ["string", "null"] }, - "pids_limit": { "type": ["number", "string"] }, - "platform": { "type": "string" }, - "ports": { - "type": "array", - "items": { - "oneOf": [ - { "type": "number" }, - { "type": "string" }, - { - "type": "object", - "properties": { - "name": { "type": "string" }, - "mode": { "type": "string" }, - "host_ip": { "type": "string" }, - "target": { "type": "integer" }, - "published": { "type": ["string", "integer"] }, - "protocol": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - ] - }, - "uniqueItems": true - }, - "privileged": { "type": "boolean" }, - "profiles": { "$ref": "#/definitions/list_of_strings" }, - "pull_policy": { - "type": "string", - "enum": ["always", "never", "if_not_present", "build", "missing"] - }, - "read_only": { "type": "boolean" }, - "restart": { "type": "string" }, - "runtime": { - "type": "string" - }, - "scale": { - "type": "integer" - }, - "security_opt": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "shm_size": { "type": ["number", "string"] }, - "secrets": { "$ref": "#/definitions/service_config_or_secret" }, - "sysctls": { "$ref": "#/definitions/list_or_dict" }, - "stdin_open": { "type": "boolean" }, - "stop_grace_period": { "type": "string" }, - "stop_signal": { "type": "string" }, - "storage_opt": { "type": "object" }, - "tmpfs": { "$ref": "#/definitions/string_or_list" }, - "tty": { "type": "boolean" }, - "ulimits": { "$ref": "#/definitions/ulimits" }, - "user": { "type": "string" }, - "uts": { "type": "string" }, - "userns_mode": { "type": "string" }, - "volumes": { - "type": "array", - "items": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "required": ["type"], - "properties": { - "type": { "type": "string" }, - "source": { "type": "string" }, - "target": { "type": "string" }, - "read_only": { "type": "boolean" }, - "consistency": { "type": "string" }, - "bind": { - "type": "object", - "properties": { - "propagation": { "type": "string" }, - "create_host_path": { "type": "boolean" }, - "selinux": { "type": "string", "enum": ["z", "Z"] } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "volume": { - "type": "object", - "properties": { - "nocopy": { "type": "boolean" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "tmpfs": { - "type": "object", - "properties": { - "size": { - "oneOf": [ - { "type": "integer", "minimum": 0 }, - { "type": "string" } - ] - }, - "mode": { "type": "number" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - ] - }, - "uniqueItems": true - }, - "volumes_from": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - "working_dir": { "type": "string" } - }, - "patternProperties": { "^x-": {} }, - "additionalProperties": false - }, - - "healthcheck": { - "$id": "#/definitions/healthcheck", - "type": "object", - "properties": { - "disable": { "type": "boolean" }, - "interval": { "type": "string" }, - "retries": { "type": "number" }, - "test": { - "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "timeout": { "type": "string" }, - "start_period": { "type": "string" }, - "start_interval": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "development": { - "$id": "#/definitions/development", - "type": ["object", "null"], - "properties": { - "watch": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ignore": { "type": "array", "items": { "type": "string" } }, - "path": { "type": "string" }, - "action": { - "type": "string", - "enum": ["rebuild", "sync", "sync+restart"] - }, - "target": { "type": "string" } - }, - "required": ["path", "action"], - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - } - } - }, - "deployment": { - "$id": "#/definitions/deployment", - "type": ["object", "null"], - "properties": { - "mode": { "type": "string" }, - "endpoint_mode": { "type": "string" }, - "replicas": { "type": "integer" }, - "labels": { "$ref": "#/definitions/list_or_dict" }, - "rollback_config": { - "type": "object", - "properties": { - "parallelism": { "type": "integer" }, - "delay": { "type": "string" }, - "failure_action": { "type": "string" }, - "monitor": { "type": "string" }, - "max_failure_ratio": { "type": "number" }, - "order": { "type": "string", "enum": ["start-first", "stop-first"] } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "update_config": { - "type": "object", - "properties": { - "parallelism": { "type": "integer" }, - "delay": { "type": "string" }, - "failure_action": { "type": "string" }, - "monitor": { "type": "string" }, - "max_failure_ratio": { "type": "number" }, - "order": { "type": "string", "enum": ["start-first", "stop-first"] } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "resources": { - "type": "object", - "properties": { - "limits": { - "type": "object", - "properties": { - "cpus": { "type": ["number", "string"] }, - "memory": { "type": "string" }, - "pids": { "type": "integer" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "reservations": { - "type": "object", - "properties": { - "cpus": { "type": ["number", "string"] }, - "memory": { "type": "string" }, - "generic_resources": { - "$ref": "#/definitions/generic_resources" - }, - "devices": { "$ref": "#/definitions/devices" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "restart_policy": { - "type": "object", - "properties": { - "condition": { "type": "string" }, - "delay": { "type": "string" }, - "max_attempts": { "type": "integer" }, - "window": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "placement": { - "type": "object", - "properties": { - "constraints": { "type": "array", "items": { "type": "string" } }, - "preferences": { - "type": "array", - "items": { - "type": "object", - "properties": { - "spread": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "max_replicas_per_node": { "type": "integer" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - - "generic_resources": { - "$id": "#/definitions/generic_resources", - "type": "array", - "items": { - "type": "object", - "properties": { - "discrete_resource_spec": { - "type": "object", - "properties": { - "kind": { "type": "string" }, - "value": { "type": "number" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - - "devices": { - "$id": "#/definitions/devices", - "type": "array", - "items": { - "type": "object", - "properties": { - "capabilities": { "$ref": "#/definitions/list_of_strings" }, - "count": { "type": ["string", "integer"] }, - "device_ids": { "$ref": "#/definitions/list_of_strings" }, - "driver": { "type": "string" }, - "options": { "$ref": "#/definitions/list_or_dict" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - - "include": { - "$id": "#/definitions/include", - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "path": { "$ref": "#/definitions/string_or_list" }, - "env_file": { "$ref": "#/definitions/string_or_list" }, - "project_directory": { "type": "string" } - }, - "additionalProperties": false - } - ] - }, - - "network": { - "$id": "#/definitions/network", - "type": ["object", "null"], - "properties": { - "name": { "type": "string" }, - "driver": { "type": "string" }, - "driver_opts": { - "type": "object", - "patternProperties": { - "^.+$": { "type": ["string", "number"] } - } - }, - "ipam": { - "type": "object", - "properties": { - "driver": { "type": "string" }, - "config": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnet": { "type": "string" }, - "ip_range": { "type": "string" }, - "gateway": { "type": "string" }, - "aux_addresses": { - "type": "object", - "additionalProperties": false, - "patternProperties": { "^.+$": { "type": "string" } } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - }, - "options": { - "type": "object", - "additionalProperties": false, - "patternProperties": { "^.+$": { "type": "string" } } - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "external": { - "type": ["boolean", "object"], - "properties": { - "name": { - "deprecated": true, - "type": "string" - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "internal": { "type": "boolean" }, - "enable_ipv6": { "type": "boolean" }, - "attachable": { "type": "boolean" }, - "labels": { "$ref": "#/definitions/list_or_dict" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - - "volume": { - "$id": "#/definitions/volume", - "type": ["object", "null"], - "properties": { - "name": { "type": "string" }, - "driver": { "type": "string" }, - "driver_opts": { - "type": "object", - "patternProperties": { - "^.+$": { "type": ["string", "number"] } - } - }, - "external": { - "type": ["boolean", "object"], - "properties": { - "name": { - "deprecated": true, - "type": "string" - } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - "labels": { "$ref": "#/definitions/list_or_dict" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - - "secret": { - "$id": "#/definitions/secret", - "type": "object", - "properties": { - "name": { "type": "string" }, - "environment": { "type": "string" }, - "file": { "type": "string" }, - "external": { - "type": ["boolean", "object"], - "properties": { - "name": { "type": "string" } - } - }, - "labels": { "$ref": "#/definitions/list_or_dict" }, - "driver": { "type": "string" }, - "driver_opts": { - "type": "object", - "patternProperties": { - "^.+$": { "type": ["string", "number"] } - } - }, - "template_driver": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - - "config": { - "$id": "#/definitions/config", - "type": "object", - "properties": { - "name": { "type": "string" }, - "content": { "type": "string" }, - "environment": { "type": "string" }, - "file": { "type": "string" }, - "external": { - "type": ["boolean", "object"], - "properties": { - "name": { - "deprecated": true, - "type": "string" - } - } - }, - "labels": { "$ref": "#/definitions/list_or_dict" }, - "template_driver": { "type": "string" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - }, - - "command": { - "oneOf": [ - { "type": "null" }, - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - - "env_file": { - "oneOf": [ - { "type": "string" }, - { - "type": "array", - "items": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "path": { - "type": "string" - }, - "required": { - "type": "boolean", - "default": true - } - }, - "required": ["path"] - } - ] - } - } - ] - }, - - "string_or_list": { - "oneOf": [ - { "type": "string" }, - { "$ref": "#/definitions/list_of_strings" } - ] - }, - - "list_of_strings": { - "type": "array", - "items": { "type": "string" }, - "uniqueItems": true - }, - - "list_or_dict": { - "oneOf": [ - { - "type": "object", - "patternProperties": { - ".+": { - "type": ["string", "number", "boolean", "null"] - } - }, - "additionalProperties": false - }, - { "type": "array", "items": { "type": "string" }, "uniqueItems": true } - ] - }, - - "blkio_limit": { - "type": "object", - "properties": { - "path": { "type": "string" }, - "rate": { "type": ["integer", "string"] } - }, - "additionalProperties": false - }, - "blkio_weight": { - "type": "object", - "properties": { - "path": { "type": "string" }, - "weight": { "type": "integer" } - }, - "additionalProperties": false - }, - "service_config_or_secret": { - "type": "array", - "items": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "source": { "type": "string" }, - "target": { "type": "string" }, - "uid": { "type": "string" }, - "gid": { "type": "string" }, - "mode": { "type": "number" } - }, - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - ] - } - }, - "ulimits": { - "type": "object", - "patternProperties": { - "^[a-z]+$": { - "oneOf": [ - { "type": "integer" }, - { - "type": "object", - "properties": { - "hard": { "type": "integer" }, - "soft": { "type": "integer" } - }, - "required": ["soft", "hard"], - "additionalProperties": false, - "patternProperties": { "^x-": {} } - } - ] - } - } - }, - "constraints": { - "service": { - "$id": "#/definitions/constraints/service", - "anyOf": [{ "required": ["build"] }, { "required": ["image"] }], - "properties": { - "build": { - "required": ["context"] - } - } - } - } - } -} diff --git a/packages/cli/package/src/lib/configs/project/dockerCompose.ts b/packages/cli/package/src/lib/configs/project/dockerCompose.ts index 3ed894c6c..580f521f8 100644 --- a/packages/cli/package/src/lib/configs/project/dockerCompose.ts +++ b/packages/cli/package/src/lib/configs/project/dockerCompose.ts @@ -16,9 +16,9 @@ */ import assert from "assert"; +import { writeFile } from "fs/promises"; import { join, relative } from "path"; -import type { JSONSchemaType } from "ajv"; import { yamlDiffPatch } from "yaml-diff-patch"; import { CHAIN_RPC_PORT } from "../../../common.js"; @@ -27,7 +27,6 @@ import { CHAIN_DEPLOY_SCRIPT_NAME, CHAIN_RPC_CONTAINER_NAME, CONFIGS_DIR_NAME, - DOCKER_COMPOSE_FILE_NAME, GRAPH_NODE_CONTAINER_NAME, GRAPH_NODE_PORT, HTTP_PORT_START, @@ -40,18 +39,11 @@ import { WEB_SOCKET_PORT_START, } from "../../const.js"; import { numToStr } from "../../helpers/typesafeStringify.js"; +import { pathExists } from "../../helpers/utils.js"; import { genSecretKeyOrReturnExisting } from "../../keyPairs.js"; import { ensureFluenceConfigsDir, getFluenceDir } from "../../paths.js"; -import { - getConfigInitFunction, - type GetDefaultConfig, - getReadonlyConfigInitFunction, - type InitializedConfig, - type InitializedReadonlyConfig, - type Migrations, -} from "../initConfig.js"; +import { ensureDockerComposeConfigPath } from "../../paths.js"; -import schema from "./compose.schema.json" with { type: "json" }; import { ensureComputerPeerConfigs, getConfigTomlName, @@ -70,16 +62,12 @@ type Service = { }; type ConfigV0 = { - version: "3"; services: Record; volumes?: Record; include?: string[]; secrets?: Record; }; -// @ts-expect-error - this schema is from official github and it's valid -const configSchemaV0: JSONSchemaType = schema; - type GenNoxImageArgs = { name: string; tcpPort: number; @@ -150,7 +138,7 @@ function genNox({ ]; } -async function genDockerCompose(): Promise { +async function genDefaultDockerCompose(): Promise { const configsDir = await ensureFluenceConfigsDir(); const fluenceDir = getFluenceDir(); const computePeers = await ensureComputerPeerConfigs(); @@ -185,7 +173,6 @@ async function genDockerCompose(): Promise { } = bootstrap; return { - version: "3", volumes: { "chain-rpc": null, [IPFS_CONTAINER_NAME]: null, @@ -323,51 +310,20 @@ async function genDockerCompose(): Promise { }; } -async function genDefaultDockerCompose(): Promise { - const def = await genDockerCompose(); +export async function ensureDockerComposeConfig() { + const configPath = await ensureDockerComposeConfigPath(); - return () => { - return yamlDiffPatch("", {}, def); - }; -} + if (!(await pathExists(configPath))) { + await writeFile( + configPath, + yamlDiffPatch("", {}, await genDefaultDockerCompose()), + ); + } -const migrations: Migrations = []; - -type Config = ConfigV0; -type LatestConfig = ConfigV0; -export type DockerComposeConfig = InitializedConfig; -export type DockerComposeConfigReadonly = - InitializedReadonlyConfig; - -export function dockerComposeDirPath() { - return getFluenceDir(); + return configPath; } -const initConfigOptions = { - allSchemas: [configSchemaV0], - latestSchema: configSchemaV0, - migrations, - name: DOCKER_COMPOSE_FILE_NAME, - getConfigOrConfigDirPath: dockerComposeDirPath, -}; - -export async function initNewDockerComposeConfig() { - return getConfigInitFunction( - initConfigOptions, - await genDefaultDockerCompose(), - )(); -} - -export async function initNewReadonlyDockerComposeConfig() { - return getReadonlyConfigInitFunction( - initConfigOptions, - await genDefaultDockerCompose(), - )(); +export async function checkDockerComposeConfigExists() { + const configPath = await ensureDockerComposeConfigPath(); + return (await pathExists(configPath)) ? configPath : null; } - -export const initDockerComposeConfig = getConfigInitFunction(initConfigOptions); - -export const initReadonlyDockerComposeConfig = - getReadonlyConfigInitFunction(initConfigOptions); - -export const dockerComposeSchema: JSONSchemaType = configSchemaV0; diff --git a/packages/cli/package/src/lib/paths.ts b/packages/cli/package/src/lib/paths.ts index 36f86d5f9..f0f565ab1 100644 --- a/packages/cli/package/src/lib/paths.ts +++ b/packages/cli/package/src/lib/paths.ts @@ -63,6 +63,7 @@ import { BACKUPS_DIR_NAME, ENV_CONFIG_FULL_FILE_NAME, USER_CONFIG_FULL_FILE_NAME, + DOCKER_COMPOSE_FULL_FILE_NAME, } from "./const.js"; import { recursivelyFindFile } from "./helpers/recursivelyFindFile.js"; import { stringifyUnknown } from "./helpers/utils.js"; @@ -211,6 +212,10 @@ export const getFluenceDir = (cwd?: string): string => { return join(cwd ?? projectRootDir, DOT_FLUENCE_DIR_NAME); }; +export async function ensureDockerComposeConfigPath(): Promise { + return join(await ensureFluenceDir(), DOCKER_COMPOSE_FULL_FILE_NAME); +} + export function getEnvConfigPath(): string { return join(getFluenceDir(), ENV_CONFIG_FULL_FILE_NAME); } From d49a1f9d27533f39981714923e2f1484f7c0aabb Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:03:19 +0100 Subject: [PATCH 13/37] feat: use indexer directly --- package.json | 2 + packages/cli/package.json | 2 + packages/cli/package/.gitignore | 3 + packages/cli/package/.prettierignore | 1 + packages/cli/package/eslint.config.js | 3 +- packages/cli/package/package.json | 15 +- packages/cli/package/src/genGqlSchema.ts | 98 + packages/cli/package/src/lib/chain/deals.ts | 6 +- .../cli/package/src/lib/chain/offer/offer.ts | 111 +- .../lib/configs/project/chainContainers.ts | 153 + .../src/lib/configs/project/dockerCompose.ts | 139 +- .../lib/configs/project/provider/provider3.ts | 12 +- packages/cli/package/src/lib/const.ts | 14 +- packages/cli/package/src/lib/deal.ts | 2 +- packages/cli/package/src/lib/dealClient.ts | 15 +- packages/cli/package/src/lib/gql/gqlClient.ts | 64 + .../cli/package/src/lib/gql/gqlCodegen.ts | 65 + .../cli/package/src/lib/gql/schema.graphql | 65 + .../package/src/lib/helpers/setTryTimeout.ts | 92 + packages/cli/package/src/lib/helpers/utils.ts | 71 - .../cli/package/src/lib/localServices/ipfs.ts | 3 +- .../cli/package/src/lib/setupEnvironment.ts | 14 +- .../cli/package/test/helpers/sharedSteps.ts | 2 +- packages/cli/package/test/setup/localUp.ts | 2 +- packages/cli/package/tsconfig.json | 7 +- packages/cli/package/yarn.lock | 2803 ++++++++++++++++- packages/common/src/index.ts | 2 - turbo.json | 22 +- 28 files changed, 3379 insertions(+), 409 deletions(-) create mode 100644 packages/cli/package/src/genGqlSchema.ts create mode 100644 packages/cli/package/src/lib/configs/project/chainContainers.ts create mode 100644 packages/cli/package/src/lib/gql/gqlClient.ts create mode 100644 packages/cli/package/src/lib/gql/gqlCodegen.ts create mode 100644 packages/cli/package/src/lib/gql/schema.graphql create mode 100644 packages/cli/package/src/lib/helpers/setTryTimeout.ts diff --git a/package.json b/package.json index dc03a03b3..f73123c52 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "build": "turbo run build --cache-dir=.turbo", "install-yarn-dependencies": "turbo run install-yarn-dependencies --cache-dir=.turbo", "install-npm-dependencies": "turbo run install-npm-dependencies --cache-dir=.turbo", + "gen-gql-schema": "turbo run gen-gql-schema --cache-dir=.turbo", + "gql-codegen": "turbo run gql-codegen --cache-dir=.turbo", "pack-ci": "turbo run pack-ci --cache-dir=.turbo && node ./rename-packed.js", "pack-linux-x64": "turbo run pack-linux-x64 --cache-dir=.turbo && node ./rename-packed.js", "pack-darwin-x64": "turbo run pack-darwin-x64 --cache-dir=.turbo && node ./rename-packed.js", diff --git a/packages/cli/package.json b/packages/cli/package.json index 5187f0346..a3277568f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -8,6 +8,8 @@ "scripts": { "install-yarn-dependencies": "yarn ./package install", "install-npm-dependencies": "npm --prefix ./package/src/cli-aqua-dependencies install", + "gen-gql-schema": "yarn ./package gen-gql-schema", + "gql-codegen": "yarn ./package gql-codegen", "before-build": "yarn ./package before-build", "build": "yarn ./package build", "pack-ci": "yarn ./package pack-ci", diff --git a/packages/cli/package/.gitignore b/packages/cli/package/.gitignore index e29c25fe7..c783f0275 100644 --- a/packages/cli/package/.gitignore +++ b/packages/cli/package/.gitignore @@ -16,6 +16,7 @@ tmp /.f .env rust-toolchain.toml +docker-compose.yaml # recommended by Fluence .idea @@ -27,6 +28,8 @@ rust-toolchain.toml # ignore compiled files src/lib/compiled-aqua src/lib/compiled-aqua-with-tracing +src/lib/gql/gqlGenerated.ts +src/lib/gql/gqlSchema.json src/versions src/aqua-dependencies src/common.ts diff --git a/packages/cli/package/.prettierignore b/packages/cli/package/.prettierignore index db7019dd7..d7dcf17e0 100644 --- a/packages/cli/package/.prettierignore +++ b/packages/cli/package/.prettierignore @@ -4,5 +4,6 @@ node_modules tmp .fluence src/lib/compiled-aqua +gql.generated.ts CHANGELOG.md .github/workflows diff --git a/packages/cli/package/eslint.config.js b/packages/cli/package/eslint.config.js index c1337a81c..a3048777a 100644 --- a/packages/cli/package/eslint.config.js +++ b/packages/cli/package/eslint.config.js @@ -56,7 +56,7 @@ export default tseslint.config( "Please use type-safe to string converter (e.g. numToString)", }, { - selector: "Identifier[name='String']", + selector: "CallExpression[callee.name='String']", message: // cause when the variable changes type you will have no way to learn you possibly have to change it's string representation "Please use type-safe to string converter (e.g. numToString)", @@ -186,6 +186,7 @@ export default tseslint.config( "bin/dev.js", "resources/*", ".yarn/*", + "src/lib/gql/gql.generated.ts", ], }, ); diff --git a/packages/cli/package/package.json b/packages/cli/package/package.json index f9d7182cd..ce8dbd58a 100644 --- a/packages/cli/package/package.json +++ b/packages/cli/package/package.json @@ -29,6 +29,8 @@ "lint": "eslint .", "lint-fix": "eslint . --fix", "find-dead-code": "ts-prune", + "gen-gql-schema": "tsx ./src/genGqlSchema.ts", + "gql-codegen": "graphql-codegen --config ./src/lib/gql/gqlCodegen.ts", "postpack": "shx rm -f oclif.manifest.json", "vitest-provider": "vitest run provider.test.ts", "vitest-deal-deploy": "vitest run dealDeploy.test.ts", @@ -45,9 +47,9 @@ "upload-darwin-x64": "oclif upload tarballs -t \"darwin-x64\" --no-xz", "upload-darwin-arm64": "oclif upload tarballs -t \"darwin-arm64\" --no-xz", "upload-win32-x64": "oclif upload tarballs -t \"win32-x64\" --no-xz && oclif upload win --targets \"win32-x64\"", - "download-marine-and-mrepl": "node --import tsx --no-warnings ./test/setup/downloadMarineAndMrepl.ts", - "generate-templates": "node --import tsx --no-warnings ./test/setup/generateTemplates.ts", - "local-up": "node --import tsx --no-warnings ./test/setup/localUp.ts", + "download-marine-and-mrepl": "tsx ./test/setup/downloadMarineAndMrepl.ts", + "generate-templates": "tsx ./test/setup/generateTemplates.ts", + "local-up": "tsx ./test/setup/localUp.ts", "test": "yarn download-marine-and-mrepl && yarn generate-templates && yarn local-up && yarn vitest", "circular": "madge --circular ./dist --exclude cli-connector", "on-each-commit": "yarn lint-fix && yarn circular && cd docs/commands && oclif readme --no-aliases && yarn gen-config-docs", @@ -85,6 +87,9 @@ "ethers": "6.7.1", "express": "4.21.1", "filenamify": "6.0.0", + "graphql": "^16.9.0", + "graphql-request": "^7.1.2", + "graphql-tag": "^2.12.6", "inquirer": "9.2.20", "ipfs-http-client": "60.0.1", "lodash-es": "4.17.21", @@ -104,6 +109,10 @@ "devDependencies": { "@actions/core": "1.11.1", "@aws-sdk/lib-storage": "^3.501.0", + "@graphql-codegen/cli": "^5.0.3", + "@graphql-codegen/typescript": "^4.1.1", + "@graphql-codegen/typescript-graphql-request": "^6.2.0", + "@graphql-codegen/typescript-operations": "^4.3.1", "@tsconfig/node22": "^22.0.0", "@tsconfig/strictest": "^2.0.5", "@types/debug": "4.1.12", diff --git a/packages/cli/package/src/genGqlSchema.ts b/packages/cli/package/src/genGqlSchema.ts new file mode 100644 index 000000000..032247f68 --- /dev/null +++ b/packages/cli/package/src/genGqlSchema.ts @@ -0,0 +1,98 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { exec as callBackExec } from "node:child_process"; +import { writeFile } from "node:fs/promises"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; + +import { SUBGRAPH_URLS } from "@fluencelabs/deal-ts-clients"; + +import { chainContainers } from "./lib/configs/project/chainContainers.js"; +import { setTryTimeout } from "./lib/helpers/setTryTimeout.js"; +import { FLUENCE_ENV } from "./lib/setupEnvironment.js"; + +const exec = promisify(callBackExec); + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const root = resolve(__dirname, ".."); + +await writeFile( + join(root, "docker-compose.yaml"), + JSON.stringify(chainContainers, null, 2), + "utf-8", +); + +const env = process.env[FLUENCE_ENV]; + +if (env === "local") { + await exec(`cd ${root}`); + await exec("docker compose up -d"); +} + +const url = SUBGRAPH_URLS[env]; + +const res = await setTryTimeout( + `download graphql schema from ${url}`, + async () => { + const res = await fetch(url, { + credentials: "include", + headers: { + Accept: + "application/graphql-response+json, application/json, multipart/mixed", + "Accept-Language": "en-US,en;q=0.5", + "content-type": "application/json", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + Priority: "u=0", + }, + body: '{"query":"query IntrospectionQuery {\\n __schema {\\n description\\n queryType {\\n name\\n }\\n mutationType {\\n name\\n }\\n subscriptionType {\\n name\\n }\\n types {\\n ...FullType\\n }\\n directives {\\n name\\n description\\n locations\\n args {\\n ...InputValue\\n }\\n }\\n }\\n}\\n\\nfragment FullType on __Type {\\n kind\\n name\\n description\\n fields(includeDeprecated: true) {\\n name\\n description\\n args {\\n ...InputValue\\n }\\n type {\\n ...TypeRef\\n }\\n isDeprecated\\n deprecationReason\\n }\\n inputFields {\\n ...InputValue\\n }\\n interfaces {\\n ...TypeRef\\n }\\n enumValues(includeDeprecated: true) {\\n name\\n description\\n isDeprecated\\n deprecationReason\\n }\\n possibleTypes {\\n ...TypeRef\\n }\\n}\\n\\nfragment InputValue on __InputValue {\\n name\\n description\\n type {\\n ...TypeRef\\n }\\n defaultValue\\n}\\n\\nfragment TypeRef on __Type {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n}","operationName":"IntrospectionQuery","extensions":{}}', + method: "POST", + mode: "cors", + }); + + const json = await res.json(); + + if (typeof json !== "object" || json === null || !("data" in json)) { + throw new Error(`Invalid response: ${JSON.stringify(json, null, 2)}`); + } + + return json; + }, + (error) => { + return { error }; + }, + 120_000, + 3_000, +); + +if (env === "local") { + await exec("docker compose down -v"); +} + +if ("error" in res) { + throw res.error; +} + +await writeFile( + join(root, "src", "lib", "gql", "gqlSchema.json"), + JSON.stringify(res), + "utf-8", +); diff --git a/packages/cli/package/src/lib/chain/deals.ts b/packages/cli/package/src/lib/chain/deals.ts index 6670f7ca0..67a026af6 100644 --- a/packages/cli/package/src/lib/chain/deals.ts +++ b/packages/cli/package/src/lib/chain/deals.ts @@ -15,10 +15,10 @@ * along with this program. If not, see . */ -import { getDealCliClient, getSignerAddress } from "../dealClient.js"; +import { getSignerAddress } from "../dealClient.js"; +import { getDealsByProviderId } from "../gql/gqlClient.js"; export async function getProviderDeals() { - const dealCliClient = await getDealCliClient(); const signerAddress = await getSignerAddress(); - return dealCliClient.getDealsByProvider(signerAddress); + return getDealsByProviderId(signerAddress); } diff --git a/packages/cli/package/src/lib/chain/offer/offer.ts b/packages/cli/package/src/lib/chain/offer/offer.ts index 87a474f51..64c248c42 100644 --- a/packages/cli/package/src/lib/chain/offer/offer.ts +++ b/packages/cli/package/src/lib/chain/offer/offer.ts @@ -15,12 +15,10 @@ * along with this program. If not, see . */ -import type { OfferDetail } from "@fluencelabs/deal-ts-clients/dist/dealCliClient/types/schemes.js"; import { color } from "@oclif/color"; import times from "lodash-es/times.js"; import { yamlDiffPatch } from "yaml-diff-patch"; -import { jsonStringify } from "../../../common.js"; import { versions } from "../../../versions.js"; import { commandObj } from "../../commandObj.js"; import { @@ -38,29 +36,28 @@ import { OFFER_IDS_FLAG_NAME, PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME, } from "../../const.js"; -import { dbg } from "../../dbg.js"; import { getContracts, - getDealCliClient, getSignerAddress, guessTxSizeAndSign, getEventValue, } from "../../dealClient.js"; -import { startSpinner, stopSpinner } from "../../helpers/spinner.js"; +import { getOffers } from "../../gql/gqlClient.js"; import { numToStr } from "../../helpers/typesafeStringify.js"; import { commaSepStrToArr, - setTryTimeout, splitErrorsAndResults, stringifyUnknown, } from "../../helpers/utils.js"; +import { setTryTimeout } from "../../helpers/setTryTimeout.js"; import { checkboxes } from "../../prompt.js"; import { ensureFluenceEnv } from "../../resolveFluenceEnv.js"; import { getProtocolVersions } from "../chainValidators.js"; import { + cidHexStringToBase32, cidStringToCIDV1Struct, - peerIdHexStringToBase58String, peerIdBase58ToUint8Array, + peerIdHexStringToBase58String, } from "../conversions.js"; import { ptFormat, ptParse } from "../currencies.js"; import { assertProviderIsRegistered } from "../providerInfo.js"; @@ -461,10 +458,8 @@ async function formatOfferInfo( { "Provider ID": offerIndexerInfo.providerId, "Offer ID": offerIndexerInfo.id, - "Created At": new Date(offerIndexerInfo.createdAt * 1000).toISOString(), - "Last Updated At": new Date( - offerIndexerInfo.updatedAt * 1000, - ).toISOString(), + "Created At": offerIndexerInfo.createdAt, + "Last Updated At": offerIndexerInfo.updatedAt, "Price Per Epoch": await ptFormat(offerIndexerInfo.pricePerEpoch), Effectors: await Promise.all( offerIndexerInfo.effectors.map(({ cid }) => { @@ -832,44 +827,92 @@ export async function resolveCreatedOffers(flags: OfferArtifactsArgs) { export async function getOffersInfo( offers: T[], -): Promise<[T[], (T & { offerIndexerInfo: OfferDetail })[]]> { +): Promise< + [ + T[], + (T & { + offerIndexerInfo: Awaited>; + })[], + ] +> { if (offers.length === 0) { return [[], []]; } - const dealCliClient = await getDealCliClient(); - - const getOffersArg: Parameters[0] = { - ids: offers.map(({ offerId }) => { + const offersIndexerInfo = await getOffers( + offers.map(({ offerId }) => { return offerId; }), - }; - - dbg(`Running dealCliClient.getOffers with ${jsonStringify(getOffersArg)}`); - startSpinner("Fetching offers info from indexer"); - const offersIndexerInfo = await dealCliClient.getOffers(getOffersArg); - stopSpinner(); + ); const offersInfoMap = Object.fromEntries( - offersIndexerInfo.map((o) => { + offersIndexerInfo.offers.map((o) => { return [o.id, o] as const; }), ); - return splitErrorsAndResults(offers, (offer) => { + const [errors, results] = splitErrorsAndResults(offers, (offer) => { const offerIndexerInfo = offersInfoMap[offer.offerId]; - if (offerIndexerInfo === undefined) { + return offerIndexerInfo === undefined + ? { error: offer } + : { result: { offer, offerIndexerInfo } }; + }); + + return [ + errors, + await Promise.all( + results.map(async ({ offerIndexerInfo, offer }) => { + return { + ...offer, + offerIndexerInfo: await serializeOfferInfo(offerIndexerInfo), + }; + }), + ), + ] as const; +} + +type OfferIndexerInfo = Awaited>["offers"][number]; + +async function serializeOfferInfo(offerIndexerInfo: OfferIndexerInfo) { + const serializedPeers = + offerIndexerInfo.peers?.map((peer) => { return { - error: offer, + id: peer.id, + computeUnits: + peer.computeUnits?.map((computeUnit) => { + return { + id: computeUnit.id, + workerId: computeUnit.worker?.id, + }; + }) ?? [], }; - } + }) ?? []; + + return { + id: offerIndexerInfo.id, + createdAt: new Date( + Number(offerIndexerInfo.createdAt) * 1000, + ).toISOString(), + updatedAt: new Date( + Number(offerIndexerInfo.updatedAt) * 1000, + ).toISOString(), + pricePerEpoch: BigInt(offerIndexerInfo.pricePerEpoch), + paymentToken: { + address: offerIndexerInfo.paymentToken.id, + }, + totalComputeUnits: offerIndexerInfo.computeUnitsTotal, + freeComputeUnits: offerIndexerInfo.computeUnitsAvailable, + effectors: await serializeEffectors(offerIndexerInfo.effectors), + providerId: offerIndexerInfo.provider.id, + peers: serializedPeers, + }; +} - return { - result: { - ...offer, - offerIndexerInfo, - }, - }; - }); +async function serializeEffectors(effectors: OfferIndexerInfo["effectors"]) { + return Promise.all( + effectors?.map(async ({ effector: { id } }) => { + return { cid: await cidHexStringToBase32(id) }; + }) ?? [], + ); } diff --git a/packages/cli/package/src/lib/configs/project/chainContainers.ts b/packages/cli/package/src/lib/configs/project/chainContainers.ts new file mode 100644 index 000000000..c0d6a4384 --- /dev/null +++ b/packages/cli/package/src/lib/configs/project/chainContainers.ts @@ -0,0 +1,153 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { versions } from "../../../versions.js"; + +export type Service = { + image?: string; + ports?: string[]; + pull_policy?: string; + environment?: Record; + volumes?: string[]; + command?: string[]; + depends_on?: string[] | Record>; + secrets?: string[]; + healthcheck?: Record; +}; + +export type Config = { + services: Record; + volumes?: Record; + include?: string[]; + secrets?: Record; +}; + +export const CHAIN_DEPLOY_SCRIPT_NAME = "chain-deploy-script"; +export const CHAIN_RPC_CONTAINER_NAME = "chain-rpc"; +export const CHAIN_RPC_PORT = "8545"; +export const GRAPH_NODE_CONTAINER_NAME = "graph-node"; +export const GRAPH_NODE_PORT = "8020"; +export const IPFS_CONTAINER_NAME = "ipfs"; +export const IPFS_PORT = "5001"; +export const POSTGRES_CONTAINER_NAME = "postgres"; +export const SUBGRAPH_DEPLOY_SCRIPT_NAME = "subgraph-deploy-script"; + +export const chainContainers: Config = { + volumes: { + "chain-rpc": null, + [IPFS_CONTAINER_NAME]: null, + [POSTGRES_CONTAINER_NAME]: null, + }, + services: { + [IPFS_CONTAINER_NAME]: { + image: "ipfs/kubo:v0.27.0", + ports: [`${IPFS_PORT}:${IPFS_PORT}`, "4001:4001"], + environment: { + IPFS_PROFILE: "server", + }, + volumes: [`${IPFS_CONTAINER_NAME}:/data/ipfs`], + healthcheck: { + test: "ipfs id || exit 1", + interval: "8s", + timeout: "10s", + retries: 20, + }, + }, + [POSTGRES_CONTAINER_NAME]: { + image: "postgres:14", + ports: ["5432:5432"], + command: ["postgres", "-cshared_preload_libraries=pg_stat_statements"], + environment: { + POSTGRES_USER: "graph-node", + POSTGRES_PASSWORD: "let-me-in", + POSTGRES_DB: "graph-node", + PGDATA: "/var/lib/postgresql/data", + POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C", + }, + volumes: [`${POSTGRES_CONTAINER_NAME}:/var/lib/postgresql/data`], + }, + [CHAIN_RPC_CONTAINER_NAME]: { + image: versions[CHAIN_RPC_CONTAINER_NAME], + ports: [`${CHAIN_RPC_PORT}:${CHAIN_RPC_PORT}`], + volumes: [`chain-rpc:/data`], + environment: { + LOCAL_CHAIN_BLOCK_MINING_INTERVAL: 1, + }, + healthcheck: { + test: `curl -s -X POST 'http://localhost:${CHAIN_RPC_PORT}' -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "method":"eth_chainId", "params":[], "id":1}' | jq -e '.result != null'`, + interval: "8s", + timeout: "10s", + retries: 20, + }, + }, + [CHAIN_DEPLOY_SCRIPT_NAME]: { + image: versions[CHAIN_DEPLOY_SCRIPT_NAME], + environment: { + CHAIN_RPC_URL: `http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, + MAX_FAILED_RATIO: "9999", + IS_MOCKED_RANDOMX: "true", + MIN_DURATION: 0, + }, + depends_on: { + [CHAIN_RPC_CONTAINER_NAME]: { condition: "service_healthy" }, + }, + }, + [GRAPH_NODE_CONTAINER_NAME]: { + image: "fluencelabs/graph-node:v0.35.1", + ports: [ + "8000:8000", + "8001:8001", + `${GRAPH_NODE_PORT}:${GRAPH_NODE_PORT}`, + "8030:8030", + "8040:8040", + ], + depends_on: { + [IPFS_CONTAINER_NAME]: { condition: "service_healthy" }, + [CHAIN_RPC_CONTAINER_NAME]: { condition: "service_healthy" }, + [CHAIN_DEPLOY_SCRIPT_NAME]: { + condition: "service_completed_successfully", + }, + }, + environment: { + postgres_host: "postgres", + postgres_user: "graph-node", + postgres_pass: "let-me-in", + postgres_db: "graph-node", + ipfs: `${IPFS_CONTAINER_NAME}:${IPFS_PORT}`, + ethereum: `local:http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, + GRAPH_LOG: "info", + ETHEREUM_REORG_THRESHOLD: 1, + ETHEREUM_ANCESTOR_COUNT: 1, + }, + healthcheck: { + test: `timeout 10s bash -c ':> /dev/tcp/127.0.0.1/8000' || exit 1`, + interval: "40s", + timeout: "30s", + retries: 3, + start_period: "60s", + }, + }, + [SUBGRAPH_DEPLOY_SCRIPT_NAME]: { + image: versions[SUBGRAPH_DEPLOY_SCRIPT_NAME], + environment: { + GRAPHNODE_ADMIN_URL_LOCAL: `http://${GRAPH_NODE_CONTAINER_NAME}:${GRAPH_NODE_PORT}`, + IPFS_URL: `http://${IPFS_CONTAINER_NAME}:${IPFS_PORT}`, + }, + depends_on: [GRAPH_NODE_CONTAINER_NAME], + }, + }, +}; diff --git a/packages/cli/package/src/lib/configs/project/dockerCompose.ts b/packages/cli/package/src/lib/configs/project/dockerCompose.ts index 580f521f8..8ca368bba 100644 --- a/packages/cli/package/src/lib/configs/project/dockerCompose.ts +++ b/packages/cli/package/src/lib/configs/project/dockerCompose.ts @@ -21,20 +21,11 @@ import { join, relative } from "path"; import { yamlDiffPatch } from "yaml-diff-patch"; -import { CHAIN_RPC_PORT } from "../../../common.js"; import { versions } from "../../../versions.js"; import { - CHAIN_DEPLOY_SCRIPT_NAME, - CHAIN_RPC_CONTAINER_NAME, CONFIGS_DIR_NAME, - GRAPH_NODE_CONTAINER_NAME, - GRAPH_NODE_PORT, HTTP_PORT_START, - IPFS_CONTAINER_NAME, - IPFS_PORT, - POSTGRES_CONTAINER_NAME, PROVIDER_CONFIG_FULL_FILE_NAME, - SUBGRAPH_DEPLOY_SCRIPT_NAME, TCP_PORT_START, WEB_SOCKET_PORT_START, } from "../../const.js"; @@ -44,30 +35,19 @@ import { genSecretKeyOrReturnExisting } from "../../keyPairs.js"; import { ensureFluenceConfigsDir, getFluenceDir } from "../../paths.js"; import { ensureDockerComposeConfigPath } from "../../paths.js"; +import { CHAIN_RPC_CONTAINER_NAME } from "./chainContainers.js"; +import { IPFS_CONTAINER_NAME } from "./chainContainers.js"; +import { CHAIN_DEPLOY_SCRIPT_NAME } from "./chainContainers.js"; +import { + chainContainers, + type Config, + type Service, +} from "./chainContainers.js"; import { ensureComputerPeerConfigs, getConfigTomlName, } from "./provider/provider.js"; -type Service = { - image?: string; - ports?: string[]; - pull_policy?: string; - environment?: Record; - volumes?: string[]; - command?: string[]; - depends_on?: string[] | Record>; - secrets?: string[]; - healthcheck?: Record; -}; - -type ConfigV0 = { - services: Record; - volumes?: Record; - include?: string[]; - secrets?: Record; -}; - type GenNoxImageArgs = { name: string; tcpPort: number; @@ -138,7 +118,7 @@ function genNox({ ]; } -async function genDefaultDockerCompose(): Promise { +async function genDefaultDockerCompose(): Promise { const configsDir = await ensureFluenceConfigsDir(); const fluenceDir = getFluenceDir(); const computePeers = await ensureComputerPeerConfigs(); @@ -174,9 +154,7 @@ async function genDefaultDockerCompose(): Promise { return { volumes: { - "chain-rpc": null, - [IPFS_CONTAINER_NAME]: null, - [POSTGRES_CONTAINER_NAME]: null, + ...chainContainers.volumes, ...Object.fromEntries( peers.map(({ name }) => { return [name, null] as const; @@ -189,102 +167,7 @@ async function genDefaultDockerCompose(): Promise { }), ), services: { - [IPFS_CONTAINER_NAME]: { - image: "ipfs/kubo:v0.27.0", - ports: [`${IPFS_PORT}:${IPFS_PORT}`, "4001:4001"], - environment: { - IPFS_PROFILE: "server", - }, - volumes: [`${IPFS_CONTAINER_NAME}:/data/ipfs`], - healthcheck: { - test: "ipfs id || exit 1", - interval: "8s", - timeout: "10s", - retries: 20, - }, - }, - [POSTGRES_CONTAINER_NAME]: { - image: "postgres:14", - ports: ["5432:5432"], - command: ["postgres", "-cshared_preload_libraries=pg_stat_statements"], - environment: { - POSTGRES_USER: "graph-node", - POSTGRES_PASSWORD: "let-me-in", - POSTGRES_DB: "graph-node", - PGDATA: "/var/lib/postgresql/data", - POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C", - }, - volumes: [`${POSTGRES_CONTAINER_NAME}:/var/lib/postgresql/data`], - }, - [CHAIN_RPC_CONTAINER_NAME]: { - image: versions[CHAIN_RPC_CONTAINER_NAME], - ports: [`${CHAIN_RPC_PORT}:${CHAIN_RPC_PORT}`], - volumes: [`chain-rpc:/data`], - environment: { - LOCAL_CHAIN_BLOCK_MINING_INTERVAL: 1, - }, - healthcheck: { - test: `curl -s -X POST 'http://localhost:${CHAIN_RPC_PORT}' -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "method":"eth_chainId", "params":[], "id":1}' | jq -e '.result != null'`, - interval: "8s", - timeout: "10s", - retries: 20, - }, - }, - [CHAIN_DEPLOY_SCRIPT_NAME]: { - image: versions[CHAIN_DEPLOY_SCRIPT_NAME], - environment: { - CHAIN_RPC_URL: `http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, - MAX_FAILED_RATIO: "9999", - IS_MOCKED_RANDOMX: "true", - MIN_DURATION: 0, - }, - depends_on: { - [CHAIN_RPC_CONTAINER_NAME]: { condition: "service_healthy" }, - }, - }, - [GRAPH_NODE_CONTAINER_NAME]: { - image: "fluencelabs/graph-node:v0.35.1", - ports: [ - "8000:8000", - "8001:8001", - `${GRAPH_NODE_PORT}:${GRAPH_NODE_PORT}`, - "8030:8030", - "8040:8040", - ], - depends_on: { - [IPFS_CONTAINER_NAME]: { condition: "service_healthy" }, - [CHAIN_RPC_CONTAINER_NAME]: { condition: "service_healthy" }, - [CHAIN_DEPLOY_SCRIPT_NAME]: { - condition: "service_completed_successfully", - }, - }, - environment: { - postgres_host: "postgres", - postgres_user: "graph-node", - postgres_pass: "let-me-in", - postgres_db: "graph-node", - ipfs: `${IPFS_CONTAINER_NAME}:${IPFS_PORT}`, - ethereum: `local:http://${CHAIN_RPC_CONTAINER_NAME}:${CHAIN_RPC_PORT}`, - GRAPH_LOG: "info", - ETHEREUM_REORG_THRESHOLD: 1, - ETHEREUM_ANCESTOR_COUNT: 1, - }, - healthcheck: { - test: `timeout 10s bash -c ':> /dev/tcp/127.0.0.1/8000' || exit 1`, - interval: "40s", - timeout: "30s", - retries: 3, - start_period: "60s", - }, - }, - [SUBGRAPH_DEPLOY_SCRIPT_NAME]: { - image: versions[SUBGRAPH_DEPLOY_SCRIPT_NAME], - environment: { - GRAPHNODE_ADMIN_URL_LOCAL: `http://${GRAPH_NODE_CONTAINER_NAME}:${GRAPH_NODE_PORT}`, - IPFS_URL: `http://${IPFS_CONTAINER_NAME}:${IPFS_PORT}`, - }, - depends_on: [GRAPH_NODE_CONTAINER_NAME], - }, + ...chainContainers.services, ...Object.fromEntries([ genNox({ name: bootstrapName, diff --git a/packages/cli/package/src/lib/configs/project/provider/provider3.ts b/packages/cli/package/src/lib/configs/project/provider/provider3.ts index b1efca147..65af8333b 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider3.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider3.ts @@ -23,11 +23,10 @@ import isEmpty from "lodash-es/isEmpty.js"; import mapValues from "lodash-es/mapValues.js"; import mergeWith from "lodash-es/mergeWith.js"; -import { - jsonStringify, - CHAIN_RPC_PORT, - type ChainENV, -} from "../../../../common.js"; +import { jsonStringify, type ChainENV } from "../../../../common.js"; +import { CHAIN_RPC_PORT, IPFS_PORT } from "../chainContainers.js"; +import { IPFS_CONTAINER_NAME } from "../chainContainers.js"; +import { CHAIN_RPC_CONTAINER_NAME } from "../chainContainers.js"; import { versions } from "../../../../versions.js"; import { getChainId } from "../../../chain/chainConfig.js"; import { @@ -46,10 +45,7 @@ import { DEFAULT_CC_STAKER_REWARD, DURATION_EXAMPLE, WS_CHAIN_URLS, - CHAIN_RPC_CONTAINER_NAME, DEFAULT_VM_EFFECTOR_CID, - IPFS_CONTAINER_NAME, - IPFS_PORT, } from "../../../const.js"; import { resolveDeployment } from "../../../dealClient.js"; import { ensureChainEnv } from "../../../ensureChainNetwork.js"; diff --git a/packages/cli/package/src/lib/const.ts b/packages/cli/package/src/lib/const.ts index a89516a13..c0a9a8962 100644 --- a/packages/cli/package/src/lib/const.ts +++ b/packages/cli/package/src/lib/const.ts @@ -28,10 +28,14 @@ import { getIsUnion, CHAIN_ENV, type ChainENV, - CHAIN_RPC_PORT, LOCAL_NET_DEFAULT_WALLET_KEY, } from "../common.js"; +import { + CHAIN_RPC_CONTAINER_NAME, + CHAIN_RPC_PORT, + IPFS_PORT, +} from "./configs/project/chainContainers.js"; import { aquaComment } from "./helpers/utils.js"; export const CLI_NAME = "fluence"; @@ -128,15 +132,7 @@ export function fluenceOldEnvToNewEnv(env: FluenceEnvOld): FluenceEnv { )[env]; } -export const IPFS_CONTAINER_NAME = "ipfs"; -export const IPFS_PORT = "5001"; -export const GRAPH_NODE_CONTAINER_NAME = "graph-node"; -export const GRAPH_NODE_PORT = "8020"; -export const POSTGRES_CONTAINER_NAME = "postgres"; export const LOCAL_IPFS_ADDRESS = `/ip4/127.0.0.1/tcp/${IPFS_PORT}`; -export const CHAIN_RPC_CONTAINER_NAME = "chain-rpc"; -export const CHAIN_DEPLOY_SCRIPT_NAME = "chain-deploy-script"; -export const SUBGRAPH_DEPLOY_SCRIPT_NAME = "subgraph-deploy-script"; export const TCP_PORT_START = 977; export const WEB_SOCKET_PORT_START = 999; export const HTTP_PORT_START = 918; diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index 43993b53c..2b39dfbbd 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -47,10 +47,10 @@ import { ensureChainEnv } from "./ensureChainNetwork.js"; import { bigintToStr } from "./helpers/typesafeStringify.js"; import { commaSepStrToArr, - setTryTimeout, splitErrorsAndResults, stringifyUnknown, } from "./helpers/utils.js"; +import { setTryTimeout } from "./helpers/setTryTimeout.js"; import { checkboxes, input, list } from "./prompt.js"; import { ensureFluenceEnv } from "./resolveFluenceEnv.js"; diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index 0eacaf9e9..152cc305a 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -21,7 +21,6 @@ import type { Contracts, DealMatcherClient, DealExplorerClient, - DealCliClient, Deployment, } from "@fluencelabs/deal-ts-clients"; import type { @@ -58,7 +57,8 @@ import { initEnvConfig } from "./configs/project/env/env.js"; import { CLI_NAME_FULL, PRIV_KEY_FLAG_NAME } from "./const.js"; import { dbg } from "./dbg.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; -import { setTryTimeout, stringifyUnknown } from "./helpers/utils.js"; +import { setTryTimeout } from "./helpers/setTryTimeout.js"; +import { stringifyUnknown } from "./helpers/utils.js"; import { createTransaction, getAddressFromConnector } from "./server.js"; let provider: Provider | undefined = undefined; @@ -136,17 +136,6 @@ export async function getDealExplorerClient() { return dealExplorerClient; } -let dealCliClient: DealCliClient | undefined = undefined; - -export async function getDealCliClient() { - if (dealCliClient === undefined) { - const { DealCliClient } = await import("@fluencelabs/deal-ts-clients"); - dealCliClient = new DealCliClient(await getSubgraphUrl()); - } - - return dealCliClient; -} - let deployment: Promise | undefined = undefined; export async function resolveDeployment() { diff --git a/packages/cli/package/src/lib/gql/gqlClient.ts b/packages/cli/package/src/lib/gql/gqlClient.ts new file mode 100644 index 000000000..6f74a103f --- /dev/null +++ b/packages/cli/package/src/lib/gql/gqlClient.ts @@ -0,0 +1,64 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { GraphQLClient } from "graphql-request"; + +import { getSubgraphUrl } from "../chain/chainConfig.js"; + +import { getSdk as getGqlSdk, type Sdk } from "./gqlGenerated.js"; + +let sdk: Sdk | undefined = undefined; + +async function getSdk() { + if (sdk === undefined) { + sdk = getGqlSdk(new GraphQLClient(await getSubgraphUrl())); + } + + return sdk; +} + +const DEFAULT_PAGE_LIMIT = 1000; + +export async function getOffers(id_in: string[]) { + const sdk = await getSdk(); + + return sdk.OfferDetailsQuery({ + filters: { id_in }, + orderBy: "createdAt", + orderType: "desc", + }); +} + +export async function getDealsByProviderId(providerId: string) { + const sdk = await getSdk(); + + return ( + await sdk.DealsQuery({ + filters: { + joinedWorkers_: { + peer_: { provider_: { id: providerId.toLowerCase() } }, + }, + }, + offset: 0, + limit: DEFAULT_PAGE_LIMIT, + orderBy: "createdAt", + orderType: "desc", + }) + ).deals.map(({ id }) => { + return id; + }); +} diff --git a/packages/cli/package/src/lib/gql/gqlCodegen.ts b/packages/cli/package/src/lib/gql/gqlCodegen.ts new file mode 100644 index 000000000..4405207a2 --- /dev/null +++ b/packages/cli/package/src/lib/gql/gqlCodegen.ts @@ -0,0 +1,65 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import type { CodegenConfig } from "@graphql-codegen/cli"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export default { + schema: join(__dirname, "gqlSchema.json"), + documents: join(__dirname, "schema.graphql"), + generates: { + [join(__dirname, "gqlGenerated.ts")]: { + plugins: [ + "typescript", + "typescript-operations", + "typescript-graphql-request", + ], + config: { + /** + * Fail if there are unknown scalars (that are mapped to `any` type) + */ + strictScalars: true, + /** + * The Graph custom scalars + */ + scalars: { + BigInt: "string", + BigDecimal: "string", + Bytes: "string", + Int8: "number", + Timestamp: "number", + }, + /** + * This makes import look like `import { gql } from "graphql-tag"` + * and not `import gql from "graphql-tag"`, fixing "This expression is not callable" + */ + gqlImport: "graphql-tag#gql", + /** + * Import types with `import type { ... }` + */ + useTypeImports: true, + emitLegacyCommonJSImports: false, + enumsAsTypes: true, + }, + }, + }, +} satisfies CodegenConfig; diff --git a/packages/cli/package/src/lib/gql/schema.graphql b/packages/cli/package/src/lib/gql/schema.graphql new file mode 100644 index 000000000..dd9bd02fb --- /dev/null +++ b/packages/cli/package/src/lib/gql/schema.graphql @@ -0,0 +1,65 @@ +query DealsQuery( + $filters: Deal_filter + $offset: Int + $limit: Int + $orderBy: Deal_orderBy + $orderType: OrderDirection +) { + deals( + where: $filters + first: $limit + skip: $offset + orderBy: $orderBy + orderDirection: $orderType + ) { + id + } +} + +# Exclude deleted CUs. +# Exclude deleted Peers. + +query OfferDetailsQuery( + $filters: Offer_filter + $orderType: OrderDirection + $orderBy: Offer_orderBy +) { + offers( + where: { + and: [ + $filters + # Exclude deleted offers. + { deleted: false } + ] + } + orderBy: $orderBy + orderDirection: $orderType + ) { + id + createdAt + updatedAt + pricePerEpoch + paymentToken { + id + } + computeUnitsTotal + computeUnitsAvailable + effectors { + effector { + id + } + } + provider { + id + } + peers(where: { deleted: false }) { + id + computeUnits(where: { deleted: false }) { + id + worker { + id + } + } + } + } +} diff --git a/packages/cli/package/src/lib/helpers/setTryTimeout.ts b/packages/cli/package/src/lib/helpers/setTryTimeout.ts new file mode 100644 index 000000000..9525fbd72 --- /dev/null +++ b/packages/cli/package/src/lib/helpers/setTryTimeout.ts @@ -0,0 +1,92 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { color } from "@oclif/color"; + +import { commandObj } from "../commandObj.js"; +import { dbg } from "../dbg.js"; + +import { numToStr } from "./typesafeStringify.js"; +import { stringifyUnknown } from "./utils.js"; + +export async function setTryTimeout( + message: string, + callbackToTry: () => T | Promise, + errorHandler: (error: unknown) => U, + msToTryFor: number, + msBetweenTries = 1000, + failCondition?: (error: unknown) => boolean, +): Promise { + const yellowMessage = color.yellow(message); + let isTimeoutRunning = true; + + const timeout = setTimeout(() => { + isTimeoutRunning = false; + }, msToTryFor); + + let error: unknown; + let attemptCounter = 1; + let isTrying = true; + + while (isTrying) { + isTrying = isTimeoutRunning; + + try { + dbg(`Trying to ${yellowMessage}`); + const res = await callbackToTry(); + clearTimeout(timeout); + isTrying = false; + + if (attemptCounter > 1) { + commandObj.logToStderr( + `Succeeded to ${yellowMessage} after ${numToStr(attemptCounter)} attempts`, + ); + } + + return res; + } catch (e) { + if (failCondition !== undefined && failCondition(e)) { + clearTimeout(timeout); + return errorHandler(e); + } + + const errorString = stringifyUnknown(e); + const previousErrorString = stringifyUnknown(error); + + if (errorString === previousErrorString) { + commandObj.logToStderr( + `Attempt #${numToStr( + attemptCounter, + )} to ${yellowMessage} failed with the same error`, + ); + } else { + const retryMessage = isTrying ? ". Going to retry" : ""; + commandObj.logToStderr(`Failing to ${yellowMessage}${retryMessage}`); + dbg(`Reason: ${stringifyUnknown(e)}`); + } + + error = e; + attemptCounter++; + } + + await new Promise((resolve) => { + setTimeout(resolve, msBetweenTries); + }); + } + + return errorHandler(error); +} diff --git a/packages/cli/package/src/lib/helpers/utils.ts b/packages/cli/package/src/lib/helpers/utils.ts index 81c86ccd7..b0c5a1906 100644 --- a/packages/cli/package/src/lib/helpers/utils.ts +++ b/packages/cli/package/src/lib/helpers/utils.ts @@ -18,12 +18,9 @@ import { AssertionError } from "node:assert"; import { access } from "node:fs/promises"; -import { color } from "@oclif/color"; import { CLIError } from "@oclif/core/errors"; import { jsonStringify } from "../../common.js"; -import { commandObj } from "../commandObj.js"; -import { dbg } from "../dbg.js"; import { numToStr } from "./typesafeStringify.js"; @@ -174,74 +171,6 @@ export function splitErrorsAndResults( return [errors, results]; } -export async function setTryTimeout( - message: string, - callbackToTry: () => T | Promise, - errorHandler: (error: unknown) => U, - msToTryFor: number, - msBetweenTries = 1000, - failCondition?: (error: unknown) => boolean, -): Promise { - const yellowMessage = color.yellow(message); - let isTimeoutRunning = true; - - const timeout = setTimeout(() => { - isTimeoutRunning = false; - }, msToTryFor); - - let error: unknown; - let attemptCounter = 1; - let isTrying = true; - - while (isTrying) { - isTrying = isTimeoutRunning; - - try { - dbg(`Trying to ${yellowMessage}`); - const res = await callbackToTry(); - clearTimeout(timeout); - isTrying = false; - - if (attemptCounter > 1) { - commandObj.logToStderr( - `Succeeded to ${yellowMessage} after ${numToStr(attemptCounter)} attempts`, - ); - } - - return res; - } catch (e) { - if (failCondition !== undefined && failCondition(e)) { - clearTimeout(timeout); - return errorHandler(e); - } - - const errorString = stringifyUnknown(e); - const previousErrorString = stringifyUnknown(error); - - if (errorString === previousErrorString) { - commandObj.logToStderr( - `Attempt #${numToStr( - attemptCounter, - )} to ${yellowMessage} failed with the same error`, - ); - } else { - const retryMessage = isTrying ? ". Going to retry" : ""; - commandObj.logToStderr(`Failing to ${yellowMessage}${retryMessage}`); - dbg(`Reason: ${stringifyUnknown(e)}`); - } - - error = e; - attemptCounter++; - } - - await new Promise((resolve) => { - setTimeout(resolve, msBetweenTries); - }); - } - - return errorHandler(error); -} - export async function pathExists(path: string) { try { await access(path); diff --git a/packages/cli/package/src/lib/localServices/ipfs.ts b/packages/cli/package/src/lib/localServices/ipfs.ts index dc593cefa..b3a640ac6 100644 --- a/packages/cli/package/src/lib/localServices/ipfs.ts +++ b/packages/cli/package/src/lib/localServices/ipfs.ts @@ -23,7 +23,8 @@ import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { FS_OPTIONS } from "../const.js"; import { dbg } from "../dbg.js"; -import { setTryTimeout, stringifyUnknown } from "../helpers/utils.js"; +import { stringifyUnknown } from "../helpers/utils.js"; +import { setTryTimeout } from "../helpers/setTryTimeout.js"; // !IMPORTANT for some reason when in tsconfig.json "moduleResolution" is set to "nodenext" - "ipfs-http-client" types all become "any" // so when working with this module - remove "nodenext" from "moduleResolution" so you can make sure types are correct diff --git a/packages/cli/package/src/lib/setupEnvironment.ts b/packages/cli/package/src/lib/setupEnvironment.ts index ac406c051..2bb4818b6 100644 --- a/packages/cli/package/src/lib/setupEnvironment.ts +++ b/packages/cli/package/src/lib/setupEnvironment.ts @@ -17,10 +17,9 @@ import { isAbsolute } from "node:path"; +import { CONTRACTS_ENV } from "@fluencelabs/deal-ts-clients"; import dotenv from "dotenv"; -import { CHAIN_ENV, getIsUnion } from "../common.js"; - export const FLUENCE_ENV = "FLUENCE_ENV"; export const DEBUG_COUNTLY = "DEBUG_COUNTLY"; export const FLUENCE_USER_DIR = "FLUENCE_USER_DIR"; @@ -71,7 +70,16 @@ const isAbsolutePath = (v: unknown): v is string => { return typeof v === "string" && isAbsolute(v); }; -setEnvVariable(FLUENCE_ENV, getIsUnion(CHAIN_ENV), "local"); +setEnvVariable( + FLUENCE_ENV, + (val): val is (typeof CONTRACTS_ENV)[number] => { + return CONTRACTS_ENV.some((v) => { + return v === val; + }); + }, + "local", +); + setEnvVariable(DEBUG_COUNTLY, isTrueOrFalseString, "false"); setEnvVariable(CI, isTrueOrFalseString, "false"); setEnvVariable(FLUENCE_USER_DIR, isAbsolutePath); diff --git a/packages/cli/package/test/helpers/sharedSteps.ts b/packages/cli/package/test/helpers/sharedSteps.ts index caedaa076..ec23144e6 100644 --- a/packages/cli/package/test/helpers/sharedSteps.ts +++ b/packages/cli/package/test/helpers/sharedSteps.ts @@ -42,10 +42,10 @@ import { WORKER_SPELL, DEFAULT_NUMBER_OF_LOCAL_NET_NOXES, } from "../../src/lib/const.js"; +import { setTryTimeout } from "../../src/lib/helpers/setTryTimeout.js"; import { LOGS_GET_ERROR_START, LOGS_RESOLVE_SUBNET_ERROR_START, - setTryTimeout, stringifyUnknown, } from "../../src/lib/helpers/utils.js"; import { addrsToNodes } from "../../src/lib/multiaddresWithoutLocal.js"; diff --git a/packages/cli/package/test/setup/localUp.ts b/packages/cli/package/test/setup/localUp.ts index a44e5b7fc..69d89195a 100644 --- a/packages/cli/package/test/setup/localUp.ts +++ b/packages/cli/package/test/setup/localUp.ts @@ -22,7 +22,7 @@ import { pathToTheTemplateWhereLocalEnvironmentIsSpunUp } from "../helpers/paths if (fluenceEnv === "local") { await fluence({ args: ["local", "up"], - flags: { r: true, "no-set-up": true }, + flags: { "no-set-up": true }, cwd: pathToTheTemplateWhereLocalEnvironmentIsSpunUp, timeout: 1000 * 60 * 5, // 5 minutes }); diff --git a/packages/cli/package/tsconfig.json b/packages/cli/package/tsconfig.json index 9175bfff5..89322789f 100644 --- a/packages/cli/package/tsconfig.json +++ b/packages/cli/package/tsconfig.json @@ -10,6 +10,11 @@ "verbatimModuleSyntax": true }, "include": ["src/**/*"], - "files": ["src/environment.d.ts", "src/types.d.ts"], + "files": [ + "src/environment.d.ts", + "src/types.d.ts", + "./src/lib/helpers/setTryTimeout.ts", + "src/lib/configs/project/chainContainers.ts" + ], "types": ["node"] } diff --git a/packages/cli/package/yarn.lock b/packages/cli/package/yarn.lock index d4cec2be0..87dc6d791 100644 --- a/packages/cli/package/yarn.lock +++ b/packages/cli/package/yarn.lock @@ -58,6 +58,54 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.0": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed + languageName: node + linkType: hard + +"@ardatan/relay-compiler@npm:12.0.0": + version: 12.0.0 + resolution: "@ardatan/relay-compiler@npm:12.0.0" + dependencies: + "@babel/core": "npm:^7.14.0" + "@babel/generator": "npm:^7.14.0" + "@babel/parser": "npm:^7.14.0" + "@babel/runtime": "npm:^7.0.0" + "@babel/traverse": "npm:^7.14.0" + "@babel/types": "npm:^7.0.0" + babel-preset-fbjs: "npm:^3.4.0" + chalk: "npm:^4.0.0" + fb-watchman: "npm:^2.0.0" + fbjs: "npm:^3.0.0" + glob: "npm:^7.1.1" + immutable: "npm:~3.7.6" + invariant: "npm:^2.2.4" + nullthrows: "npm:^1.1.1" + relay-runtime: "npm:12.0.0" + signedsource: "npm:^1.0.0" + yargs: "npm:^15.3.1" + peerDependencies: + graphql: "*" + bin: + relay-compiler: bin/relay-compiler + checksum: 10c0/7207d65dd39d3a6202fcee81b03338409642a0ff4e7f799b4a074025429ce2b17b6c71c9579a6328b0f4548763ba4efbff0436cddbcad934af00cc4dbc7ac4e1 + languageName: node + linkType: hard + +"@ardatan/sync-fetch@npm:^0.0.1": + version: 0.0.1 + resolution: "@ardatan/sync-fetch@npm:0.0.1" + dependencies: + node-fetch: "npm:^2.6.1" + checksum: 10c0/cd69134005ef5ea570d55631c8be59b593e2dda2207f616d30618f948af6ee5d227b857aefd56c535e8f7f3ade47083e4e7795b5ee014a6732011c6e5f9eb08f + languageName: node + linkType: hard + "@aws-crypto/crc32@npm:5.2.0": version: 5.2.0 resolution: "@aws-crypto/crc32@npm:5.2.0" @@ -828,6 +876,181 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.25.9": + version: 7.26.2 + resolution: "@babel/compat-data@npm:7.26.2" + checksum: 10c0/c9b5f3724828d17f728a778f9d66c19b55c018d0d76de6d731178cca64f182c22b71400a73bf2b65dcc4fcfe52b630088a94d5902911b54206aa90e3ffe07d12 + languageName: node + linkType: hard + +"@babel/core@npm:^7.14.0, @babel/core@npm:^7.22.9": + version: 7.26.0 + resolution: "@babel/core@npm:7.26.0" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.26.0" + "@babel/generator": "npm:^7.26.0" + "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/helper-module-transforms": "npm:^7.26.0" + "@babel/helpers": "npm:^7.26.0" + "@babel/parser": "npm:^7.26.0" + "@babel/template": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/91de73a7ff5c4049fbc747930aa039300e4d2670c2a91f5aa622f1b4868600fc89b01b6278385fbcd46f9574186fa3d9b376a9e7538e50f8d118ec13cfbcb63e + languageName: node + linkType: hard + +"@babel/generator@npm:^7.14.0, @babel/generator@npm:^7.18.13, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0": + version: 7.26.2 + resolution: "@babel/generator@npm:7.26.2" + dependencies: + "@babel/parser": "npm:^7.26.2" + "@babel/types": "npm:^7.26.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10c0/167ebce8977142f5012fad6bd91da51ac52bcd752f2261a54b7ab605d928aebe57e21636cdd2a9c7757e552652c68d9fcb5d40b06fcb66e02d9ee7526e118a5c + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" + dependencies: + "@babel/types": "npm:^7.25.9" + checksum: 10c0/095b6ba50489d797733abebc4596a81918316a99e3632755c9f02508882912b00c2ae5e468532a25a5c2108d109ddbe9b7da78333ee7cc13817fc50c00cf06fe + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-compilation-targets@npm:7.25.9" + dependencies: + "@babel/compat-data": "npm:^7.25.9" + "@babel/helper-validator-option": "npm:^7.25.9" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/a6b26a1e4222e69ef8e62ee19374308f060b007828bc11c65025ecc9e814aba21ff2175d6d3f8bf53c863edd728ee8f94ba7870f8f90a37d39552ad9933a8aaa + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.18.6": + version: 7.25.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.25.9" + "@babel/helper-member-expression-to-functions": "npm:^7.25.9" + "@babel/helper-optimise-call-expression": "npm:^7.25.9" + "@babel/helper-replace-supers": "npm:^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/b2bdd39f38056a76b9ba00ec5b209dd84f5c5ebd998d0f4033cf0e73d5f2c357fbb49d1ce52db77a2709fb29ee22321f84a5734dc9914849bdfee9ad12ce8caf + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/e08c7616f111e1fb56f398365e78858e26e466d4ac46dff25921adc5ccae9b232f66e952a2f4162bbe336627ba336c7fd9eca4835b6548935973d3380d77eaff + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.25.9, @babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" + dependencies: + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/ee111b68a5933481d76633dad9cdab30c41df4479f0e5e1cc4756dc9447c1afd2c9473b5ba006362e35b17f4ebddd5fca090233bef8dfc84dca9d9127e56ec3a + languageName: node + linkType: hard + +"@babel/helper-optimise-call-expression@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" + dependencies: + "@babel/types": "npm:^7.25.9" + checksum: 10c0/90203e6607edeadd2a154940803fd616c0ed92c1013d6774c4b8eb491f1a5a3448b68faae6268141caa5c456e55e3ee49a4ed2bd7ddaf2365daea321c435914c + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.25.9 + resolution: "@babel/helper-plugin-utils@npm:7.25.9" + checksum: 10c0/483066a1ba36ff16c0116cd24f93de05de746a603a777cd695ac7a1b034928a65a4ecb35f255761ca56626435d7abdb73219eba196f9aa83b6c3c3169325599d + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-replace-supers@npm:7.25.9" + dependencies: + "@babel/helper-member-expression-to-functions": "npm:^7.25.9" + "@babel/helper-optimise-call-expression": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/0b40d7d2925bd3ba4223b3519e2e4d2456d471ad69aa458f1c1d1783c80b522c61f8237d3a52afc9e47c7174129bbba650df06393a6787d5722f2ec7f223c3f4 + languageName: node + linkType: hard + +"@babel/helper-simple-access@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-simple-access@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/3f1bcdb88ee3883ccf86959869a867f6bbf8c4737cd44fb9f799c38e54f67474590bc66802500ae9fe18161792875b2cfb7ec15673f48ed6c8663f6d09686ca8 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/09ace0c6156961624ac9524329ce7f45350bab94bbe24335cbe0da7dfaa1448e658771831983cb83fe91cf6635b15d0a3cab57c03b92657480bfb49fb56dd184 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-string-parser@npm:7.25.7" @@ -835,6 +1058,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" @@ -849,6 +1079,30 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 10c0/27fb195d14c7dcb07f14e58fe77c44eea19a6a40a74472ec05c441478fa0bb49fa1c32b2d64be7a38870ee48ef6601bdebe98d512f0253aea0b39756c4014f3e + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helpers@npm:7.26.0" + dependencies: + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.0" + checksum: 10c0/343333cced6946fe46617690a1d0789346960910225ce359021a88a60a65bc0d791f0c5d240c0ed46cf8cc63b5fd7df52734ff14e43b9c32feae2b61b1647097 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -861,6 +1115,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.14.0, @babel/parser@npm:^7.16.8, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/parser@npm:7.26.2" + dependencies: + "@babel/types": "npm:^7.26.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/751a743087b3a9172a7599f1421830d44c38f065ef781588d2bfb1c98f9b461719a226feb13c868d7a284783eee120c88ea522593118f2668f46ebfb1105c4d7 + languageName: node + linkType: hard + "@babel/parser@npm:^7.24.4, @babel/parser@npm:^7.25.3": version: 7.25.8 resolution: "@babel/parser@npm:7.25.8" @@ -872,6 +1137,371 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-class-properties@npm:^7.0.0": + version: 7.18.6 + resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/d5172ac6c9948cdfc387e94f3493ad86cb04035cf7433f86b5d358270b1b9752dc25e176db0c5d65892a246aca7bdb4636672e15626d7a7de4bc0bd0040168d9 + languageName: node + linkType: hard + +"@babel/plugin-proposal-object-rest-spread@npm:^7.0.0": + version: 7.20.7 + resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7" + dependencies: + "@babel/compat-data": "npm:^7.20.5" + "@babel/helper-compilation-targets": "npm:^7.20.7" + "@babel/helper-plugin-utils": "npm:^7.20.2" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-transform-parameters": "npm:^7.20.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b9818749bb49d8095df64c45db682448d04743d96722984cbfd375733b2585c26d807f84b4fdb28474f2d614be6a6ffe3d96ffb121840e9e5345b2ccc0438bd8 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.0.0": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.12.13" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/95168fa186416195280b1264fb18afcdcdcea780b3515537b766cb90de6ce042d42dd6a204a39002f794ae5845b02afb0fd4861a3308a861204a55e68310a120 + languageName: node + linkType: hard + +"@babel/plugin-syntax-flow@npm:^7.0.0, @babel/plugin-syntax-flow@npm:^7.25.9": + version: 7.26.0 + resolution: "@babel/plugin-syntax-flow@npm:7.26.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/3d5cc1627a67af8be9df8cfe246869f18e7e9e2592f4b6f1c4bcd9bbe4ad27102784a25b31ebdbed23499ecb6fc23aaf7891ccf5ac3f432fd26a27123d1e242b + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.20.0": + version: 7.26.0 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.26.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/525b174e60b210d96c1744c1575fc2ddedcc43a479cba64a5344cf77bd0541754fc58120b5a11ff832ba098437bb05aa80900d1f49bb3d888c5e349a4a3a356e + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-syntax-jsx@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/d56597aff4df39d3decda50193b6dfbe596ca53f437ff2934622ce19a743bf7f43492d3fb3308b0289f5cee2b825d99ceb56526a2b9e7b68bf04901546c5618c + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:^7.0.0, @babel/plugin-syntax-object-rest-spread@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/ee1eab52ea6437e3101a0a7018b0da698545230015fc8ab129d292980ec6dff94d265e9e90070e8ae5fed42f08f1622c14c94552c77bcac784b37f503a82ff26 + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/851fef9f58be60a80f46cc0ce1e46a6f7346a6f9d50fa9e0fa79d46ec205320069d0cc157db213e2bea88ef5b7d9bd7618bb83f0b1996a836e2426c3a3a1f622 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e92ba0e3d72c038513844d8fca1cc8437dcb35cd42778e97fd03cb8303380b201468611e7ecfdcae3de33473b2679fe2de1552c5f925d112c5693425cf851f10 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a76e30becb6c75b4d87a2cd53556fddb7c88ddd56bfadb965287fd944810ac159aa8eb5705366fc37336041f63154ed9fab3862fb10482a45bf5ede63fd55fda + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-classes@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.25.9" + "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-replace-supers": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + globals: "npm:^11.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/02742ea7cd25be286c982e672619effca528d7a931626a6f3d6cea11852951b7ee973276127eaf6418ac0e18c4d749a16b520709c707e86a67012bd23ff2927d + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-computed-properties@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/template": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/948c0ae3ce0ba2375241d122a9bc7cda4a7ac8110bd8a62cd804bc46a5fdb7a7a42c7799c4cd972e14e0a579d2bd0999b92e53177b73f240bb0d4b09972c758b + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-destructuring@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/7beec5fda665d108f69d5023aa7c298a1e566b973dd41290faa18aeea70f6f571295c1ece0a058f3ceb6c6c96de76de7cd34f5a227fbf09a1b8d8a735d28ca49 + languageName: node + linkType: hard + +"@babel/plugin-transform-flow-strip-types@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/plugin-syntax-flow": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/d4b79769a5b8bfc1a0766ed2158417e7efa53cdb5776161f641a642019c0822a1288f2ccd36c16a4bca77c64ccf1bab7e36aa1419adc417606acc6eddc126339 + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-for-of@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/bf11abc71934a1f369f39cd7a33cf3d4dc5673026a53f70b7c1238c4fcc44e68b3ca1bdbe3db2076f60defb6ffe117cbe10b90f3e1a613b551d88f7c4e693bbe + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-function-name@npm:7.25.9" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8e67fbd1dd367927b8b6afdf0a6e7cb3a3fd70766c52f700ca77428b6d536f6c9d7ec643e7762d64b23093233765c66bffa40e31aabe6492682879bcb45423e1 + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/00b14e9c14cf1e871c1f3781bf6334cac339c360404afd6aba63d2f6aca9270854d59a2b40abff1c4c90d4ffdca614440842d3043316c2f0ceb155fdf7726b3b + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/91d17b451bcc5ea9f1c6f8264144057ade3338d4b92c0b248366e4db3a7790a28fd59cc56ac433a9627a9087a17a5684e53f4995dd6ae92831cb72f1bd540b54 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.25.9" + dependencies: + "@babel/helper-module-transforms": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-simple-access": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/6ce771fb04d4810257fc8900374fece877dacaed74b05eaa16ad9224b390f43795c4d046cbe9ae304e1eb5aad035d37383895e3c64496d647c2128d183916e74 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-object-super@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-replace-supers": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/0348d00e76f1f15ada44481a76e8c923d24cba91f6e49ee9b30d6861eb75344e7f84d62a18df8a6f9e9a7eacf992f388174b7f9cc4ce48287bcefca268c07600 + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.0.0, @babel/plugin-transform-parameters@npm:^7.20.7": + version: 7.25.9 + resolution: "@babel/plugin-transform-parameters@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/aecb446754b9e09d6b6fa95fd09e7cf682f8aaeed1d972874ba24c0a30a7e803ad5f014bb1fffc7bfeed22f93c0d200947407894ea59bf7687816f2f464f8df3 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-property-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1639e35b2438ccf3107af760d34e6a8e4f9acdd3ae6186ae771a6e3029bd59dfe778e502d67090f1185ecda5c16addfed77561e39c518a3f51ff10d41790e106 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-display-name@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-display-name@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/63a0f962d64e71baf87c212755419e25c637d2d95ea6fdc067df26b91e606ae186442ae815b99a577eca9bf5404d9577ecad218a3cf42d0e9e286ca7b003a992 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-jsx@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.25.9" + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/plugin-syntax-jsx": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5c9947e8ed141f7606f54da3e05eea1074950c5b8354c39df69cb7f43cb5a83c6c9d7973b24bc3d89341c8611f8ad50830a98ab10d117d850e6bdd8febdce221 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/05a20d45f0fb62567644c507ccd4e379c1a74dacf887d2b2cac70247415e3f6d7d3bf4850c8b336053144715fedb6200fc38f7130c4b76c94eec9b9c0c2a8e9b + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-spread@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/996c8fed238efc30e0664f9f58bd7ec8c148f4659f84425f68923a094fe891245711d26eb10d1f815f50c124434e076e860dbe9662240844d1b77cd09907dcdf + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.0.0": + version: 7.25.9 + resolution: "@babel/plugin-transform-template-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5144da6036807bbd4e9d2a8b92ae67a759543929f34f4db9b463448a77298f4a40bf1e92e582db208fe08ee116224806a3bd0bed75d9da404fc2c0af9e6da540 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.0.0": + version: 7.26.0 + resolution: "@babel/runtime@npm:7.26.0" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10c0/12c01357e0345f89f4f7e8c0e81921f2a3e3e101f06e8eaa18a382b517376520cd2fa8c237726eb094dab25532855df28a7baaf1c26342b52782f6936b07c287 + languageName: node + linkType: hard + +"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/ebe677273f96a36c92cc15b7aa7b11cc8bc8a3bb7a01d55b2125baca8f19cae94ff3ce15f1b1880fb8437f3a690d9f89d4e91f16fc1dc4d3eb66226d128983ab + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.14.0, @babel/traverse@npm:^7.16.8, @babel/traverse@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/traverse@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/generator": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/e90be586a714da4adb80e6cb6a3c5cfcaa9b28148abdafb065e34cc109676fc3db22cf98cd2b2fff66ffb9b50c0ef882cab0f466b6844be0f6c637b82719bba1 + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.16.8, @babel/types@npm:^7.18.13, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/types@npm:7.26.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/b694f41ad1597127e16024d766c33a641508aad037abd08d0d1f73af753e1119fa03b4a107d04b5f92cc19c095a594660547ae9bead1db2299212d644b0a5cb8 + languageName: node + linkType: hard + "@babel/types@npm:^7.25.8": version: 7.25.8 resolution: "@babel/types@npm:7.25.8" @@ -1429,6 +2059,10 @@ __metadata: "@fluencelabs/fluence-network-environment": "npm:1.2.3" "@fluencelabs/js-client": "npm:0.9.0" "@fluencelabs/npm-aqua-compiler": "npm:0.0.3" + "@graphql-codegen/cli": "npm:^5.0.3" + "@graphql-codegen/typescript": "npm:^4.1.1" + "@graphql-codegen/typescript-graphql-request": "npm:^6.2.0" + "@graphql-codegen/typescript-operations": "npm:^4.3.1" "@iarna/toml": "npm:2.2.5" "@mswjs/interceptors": "npm:0.29.1" "@multiformats/multiaddr": "npm:12.2.1" @@ -1466,6 +2100,9 @@ __metadata: express: "npm:4.21.1" filenamify: "npm:6.0.0" globby: "npm:14" + graphql: "npm:^16.9.0" + graphql-request: "npm:^7.1.2" + graphql-tag: "npm:^2.12.6" inquirer: "npm:9.2.20" ipfs-http-client: "npm:60.0.1" lodash-es: "npm:4.17.21" @@ -1498,136 +2135,832 @@ __metadata: languageName: unknown linkType: soft -"@fluencelabs/deal-ts-clients@npm:0.22.1": - version: 0.22.1 - resolution: "@fluencelabs/deal-ts-clients@npm:0.22.1" +"@fluencelabs/deal-ts-clients@npm:0.22.1": + version: 0.22.1 + resolution: "@fluencelabs/deal-ts-clients@npm:0.22.1" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.2.0" + debug: "npm:^4.3.4" + dotenv: "npm:^16.3.1" + ethers: "npm:6.7.1" + graphql: "npm:^16.8.1" + graphql-request: "npm:^6.1.0" + graphql-scalars: "npm:^1.22.4" + graphql-tag: "npm:^2.12.6" + ipfs-http-client: "npm:^60.0.1" + multiformats: "npm:^13.0.1" + checksum: 10c0/10009e68a5d2441bfa749cb00c2944bd705dd7b1ff755e12649a50f8e408ad9f984ffbc17b54006d5c92cef4f90d0aa0eac126bb621c28cf06b1342124242b5a + languageName: node + linkType: hard + +"@fluencelabs/fluence-network-environment@npm:1.2.3": + version: 1.2.3 + resolution: "@fluencelabs/fluence-network-environment@npm:1.2.3" + checksum: 10c0/5ae802a4cf2e5f2656527f2fc57b6c45bbdc106a64a7a4cebf7b15eed390d0e57f487cde73e57676686ac98775a7d94a6280436cc457a675fc3d746580ff84ea + languageName: node + linkType: hard + +"@fluencelabs/interfaces@npm:0.12.0": + version: 0.12.0 + resolution: "@fluencelabs/interfaces@npm:0.12.0" + checksum: 10c0/f9daf04484d34c7dd3fd6e6385baedbbabd0883164307afa43d9c20479d74965bb0857967e86797b5a4ef02b0aec244ab6191feb0b4268dfb687532b98667ed1 + languageName: node + linkType: hard + +"@fluencelabs/js-client-isomorphic@npm:0.6.0": + version: 0.6.0 + resolution: "@fluencelabs/js-client-isomorphic@npm:0.6.0" + dependencies: + "@fluencelabs/avm": "npm:0.62.0" + "@fluencelabs/marine-js": "npm:0.13.0" + "@fluencelabs/marine-worker": "npm:0.6.0" + "@fluencelabs/threads": "npm:^2.0.0" + checksum: 10c0/d644e9116da0d715ec4673e5b908d84ea448665718e428916c75514e9a114f026fc59b4a09c197b65f20abd09e01786e5bc4cf6ad71f67583cfca98ab2e9a0f9 + languageName: node + linkType: hard + +"@fluencelabs/js-client@npm:0.9.0": + version: 0.9.0 + resolution: "@fluencelabs/js-client@npm:0.9.0" + dependencies: + "@chainsafe/libp2p-noise": "npm:14.0.0" + "@chainsafe/libp2p-yamux": "npm:6.0.1" + "@fluencelabs/avm": "npm:0.62.0" + "@fluencelabs/interfaces": "npm:0.12.0" + "@fluencelabs/js-client-isomorphic": "npm:0.6.0" + "@fluencelabs/marine-worker": "npm:0.6.0" + "@fluencelabs/threads": "npm:^2.0.0" + "@libp2p/crypto": "npm:4.0.1" + "@libp2p/identify": "npm:1.0.11" + "@libp2p/interface": "npm:1.1.2" + "@libp2p/peer-id": "npm:4.0.5" + "@libp2p/peer-id-factory": "npm:4.0.5" + "@libp2p/ping": "npm:1.0.10" + "@libp2p/utils": "npm:5.2.2" + "@libp2p/websockets": "npm:8.0.12" + "@multiformats/multiaddr": "npm:12.1.12" + bs58: "npm:5.0.0" + debug: "npm:4.3.4" + int64-buffer: "npm:1.0.1" + it-length-prefixed: "npm:9.0.3" + it-map: "npm:3.0.5" + it-pipe: "npm:3.0.1" + js-base64: "npm:3.7.5" + libp2p: "npm:1.2.0" + multiformats: "npm:11.0.1" + rxjs: "npm:7.5.5" + uint8arrays: "npm:4.0.3" + uuid: "npm:8.3.2" + zod: "npm:3.22.4" + checksum: 10c0/e238b5682e8017e100527d2d9c8182212319d1ecbb90483934602470c2aa1b45a3a5e2650dfd281a47f1aab3f3eb27d6f6564c9f8f3bf87e7d7e50956146a6e2 + languageName: node + linkType: hard + +"@fluencelabs/marine-js@npm:0.13.0": + version: 0.13.0 + resolution: "@fluencelabs/marine-js@npm:0.13.0" + dependencies: + "@wasmer/wasi": "npm:0.12.0" + "@wasmer/wasmfs": "npm:0.12.0" + default-import: "npm:1.1.5" + checksum: 10c0/c8a36875bfbd890eb8afab61bbce8bc98f32b6bbe4bc58c23e402996491499cdac77ef757959191d5148aef1a200196b29a7a42de805aa6dc8418c638a620717 + languageName: node + linkType: hard + +"@fluencelabs/marine-worker@npm:0.6.0": + version: 0.6.0 + resolution: "@fluencelabs/marine-worker@npm:0.6.0" + dependencies: + "@fluencelabs/marine-js": "npm:0.13.0" + "@fluencelabs/threads": "npm:^2.0.0" + observable-fns: "npm:0.6.1" + checksum: 10c0/c91c282caf829613437384d9ac6df26283b73f6af1a810a6c4b77603ed659f9187576928b9ce67a6c99ff20ab353b6ce5ac56fa4fc38dbc50adee37a60961aa4 + languageName: node + linkType: hard + +"@fluencelabs/npm-aqua-compiler@npm:0.0.3": + version: 0.0.3 + resolution: "@fluencelabs/npm-aqua-compiler@npm:0.0.3" + dependencies: + "@npmcli/arborist": "npm:^7.2.1" + treeverse: "npm:3.0.0" + checksum: 10c0/0f11c4c68d2a58ae3d6f45be073a53d4dd3e278dbdabfa80204cb24bb5eb2d33b5cea71ee79e78b6e3f3eadf8e8c47d384ef76babbd3876a233d19cfa9a2ba2a + languageName: node + linkType: hard + +"@fluencelabs/threads@npm:^2.0.0": + version: 2.0.0 + resolution: "@fluencelabs/threads@npm:2.0.0" + dependencies: + callsites: "npm:^3.1.0" + debug: "npm:^4.2.0" + is-observable: "npm:^2.1.0" + observable-fns: "npm:^0.6.1" + tiny-worker: "npm:>= 2" + dependenciesMeta: + tiny-worker: + optional: true + checksum: 10c0/1a7f73048f3f69da328386bbc3727b480f77907e779796d7485d172c35f484f4daa7592df4701ab8dd3142a34f4ea39d2495da48d9deabf830e32cfb846e7d64 + languageName: node + linkType: hard + +"@graphql-codegen/add@npm:^5.0.3": + version: 5.0.3 + resolution: "@graphql-codegen/add@npm:5.0.3" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.0.3" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/2ddb8b57a0b445f109b1d8e5611e838ff590dc3c6c210ba1c31e3967e6a58097bceaef79b501eace700cd6210dca0d1ef3d28519ed7b5a4f3ce6cfc8f1508c90 + languageName: node + linkType: hard + +"@graphql-codegen/cli@npm:^5.0.3": + version: 5.0.3 + resolution: "@graphql-codegen/cli@npm:5.0.3" + dependencies: + "@babel/generator": "npm:^7.18.13" + "@babel/template": "npm:^7.18.10" + "@babel/types": "npm:^7.18.13" + "@graphql-codegen/client-preset": "npm:^4.4.0" + "@graphql-codegen/core": "npm:^4.0.2" + "@graphql-codegen/plugin-helpers": "npm:^5.0.3" + "@graphql-tools/apollo-engine-loader": "npm:^8.0.0" + "@graphql-tools/code-file-loader": "npm:^8.0.0" + "@graphql-tools/git-loader": "npm:^8.0.0" + "@graphql-tools/github-loader": "npm:^8.0.0" + "@graphql-tools/graphql-file-loader": "npm:^8.0.0" + "@graphql-tools/json-file-loader": "npm:^8.0.0" + "@graphql-tools/load": "npm:^8.0.0" + "@graphql-tools/prisma-loader": "npm:^8.0.0" + "@graphql-tools/url-loader": "npm:^8.0.0" + "@graphql-tools/utils": "npm:^10.0.0" + "@whatwg-node/fetch": "npm:^0.9.20" + chalk: "npm:^4.1.0" + cosmiconfig: "npm:^8.1.3" + debounce: "npm:^1.2.0" + detect-indent: "npm:^6.0.0" + graphql-config: "npm:^5.1.1" + inquirer: "npm:^8.0.0" + is-glob: "npm:^4.0.1" + jiti: "npm:^1.17.1" + json-to-pretty-yaml: "npm:^1.2.2" + listr2: "npm:^4.0.5" + log-symbols: "npm:^4.0.0" + micromatch: "npm:^4.0.5" + shell-quote: "npm:^1.7.3" + string-env-interpolation: "npm:^1.0.1" + ts-log: "npm:^2.2.3" + tslib: "npm:^2.4.0" + yaml: "npm:^2.3.1" + yargs: "npm:^17.0.0" + peerDependencies: + "@parcel/watcher": ^2.1.0 + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + "@parcel/watcher": + optional: true + bin: + gql-gen: cjs/bin.js + graphql-code-generator: cjs/bin.js + graphql-codegen: cjs/bin.js + graphql-codegen-esm: esm/bin.js + checksum: 10c0/fb08da11c9fc276bfb90a949438defede799e456d07e09b4bf44adfb140694902116c046da5935750730cb9f4a3d1cca67c98a1eaa1919e1b3a9dafb6590304a + languageName: node + linkType: hard + +"@graphql-codegen/client-preset@npm:^4.4.0": + version: 4.5.0 + resolution: "@graphql-codegen/client-preset@npm:4.5.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.20.2" + "@babel/template": "npm:^7.20.7" + "@graphql-codegen/add": "npm:^5.0.3" + "@graphql-codegen/gql-tag-operations": "npm:4.0.11" + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-codegen/typed-document-node": "npm:^5.0.11" + "@graphql-codegen/typescript": "npm:^4.1.1" + "@graphql-codegen/typescript-operations": "npm:^4.3.1" + "@graphql-codegen/visitor-plugin-common": "npm:^5.5.0" + "@graphql-tools/documents": "npm:^1.0.0" + "@graphql-tools/utils": "npm:^10.0.0" + "@graphql-typed-document-node/core": "npm:3.2.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/4fce2af23b4c3f36e334d96406ed490d6f87b92942bd9b782c8da3d8b8f67dbaed288cc2a19aba03a6e2f4b9a6595321d0428b70a7013261380472bc3f4e6a43 + languageName: node + linkType: hard + +"@graphql-codegen/core@npm:^4.0.2": + version: 4.0.2 + resolution: "@graphql-codegen/core@npm:4.0.2" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.0.3" + "@graphql-tools/schema": "npm:^10.0.0" + "@graphql-tools/utils": "npm:^10.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/8387a91dd852e8c45e76843453fc50dba4e63079f1ecfe2242f3c49561d229d55d1083905f46049ddd7f9f94b8e55a96e6deeac8a0c1db34a7312f5f216ca229 + languageName: node + linkType: hard + +"@graphql-codegen/gql-tag-operations@npm:4.0.11": + version: 4.0.11 + resolution: "@graphql-codegen/gql-tag-operations@npm:4.0.11" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-codegen/visitor-plugin-common": "npm:5.5.0" + "@graphql-tools/utils": "npm:^10.0.0" + auto-bind: "npm:~4.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/f13e78c1641f085645c88058df23ece3994fe6492eed1217d64b36090f90bf50e797dab1ba7b91a25f2040a50346adcbbf6b33d9f514259b53506bb1efdc1eef + languageName: node + linkType: hard + +"@graphql-codegen/plugin-helpers@npm:^2.7.2": + version: 2.7.2 + resolution: "@graphql-codegen/plugin-helpers@npm:2.7.2" + dependencies: + "@graphql-tools/utils": "npm:^8.8.0" + change-case-all: "npm:1.0.14" + common-tags: "npm:1.8.2" + import-from: "npm:4.0.0" + lodash: "npm:~4.17.0" + tslib: "npm:~2.4.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/b4abce50a751d938a48b2b7ff57aa1671df1ae9d54196ccd60237077aef2e2b528b45244cb786d1b2eeb1f464c48eb7626553fdc5cf3a9013455ed27ef3ef7d2 + languageName: node + linkType: hard + +"@graphql-codegen/plugin-helpers@npm:^3.0.0": + version: 3.1.2 + resolution: "@graphql-codegen/plugin-helpers@npm:3.1.2" + dependencies: + "@graphql-tools/utils": "npm:^9.0.0" + change-case-all: "npm:1.0.15" + common-tags: "npm:1.8.2" + import-from: "npm:4.0.0" + lodash: "npm:~4.17.0" + tslib: "npm:~2.4.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/fbe326270aef17792b326ad8d8ae3e82acf1b60f3137a4d99eb605c0c8d709830537fec112705484b5fd2c9ee1d0588fbf4269f31c9a5852567c5d4c0c7057b7 + languageName: node + linkType: hard + +"@graphql-codegen/plugin-helpers@npm:^5.0.3, @graphql-codegen/plugin-helpers@npm:^5.1.0": + version: 5.1.0 + resolution: "@graphql-codegen/plugin-helpers@npm:5.1.0" + dependencies: + "@graphql-tools/utils": "npm:^10.0.0" + change-case-all: "npm:1.0.15" + common-tags: "npm:1.8.2" + import-from: "npm:4.0.0" + lodash: "npm:~4.17.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/9fe308f1db889bc2783cf2c2d95446c56f8c38332da1c126e3320d02d33c79c6f249e14770590bacaadc908daa75bf60afbd464fcd256bf8e1809e7d25b77ac1 + languageName: node + linkType: hard + +"@graphql-codegen/schema-ast@npm:^4.0.2": + version: 4.1.0 + resolution: "@graphql-codegen/schema-ast@npm:4.1.0" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.0.3" + "@graphql-tools/utils": "npm:^10.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/ff7ab73f46f1ae4882eda0af8c3f78d37e904108aba37d52288028ee34e9bc56236b6a032a1e2fe1283030ba5f6a5f75224285af12b3f56a76e90843e1eff0e0 + languageName: node + linkType: hard + +"@graphql-codegen/typed-document-node@npm:^5.0.11": + version: 5.0.11 + resolution: "@graphql-codegen/typed-document-node@npm:5.0.11" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-codegen/visitor-plugin-common": "npm:5.5.0" + auto-bind: "npm:~4.0.0" + change-case-all: "npm:1.0.15" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/fa3f47fd7f04f6273121b0befa3577475bddde41532c067417342b85c7c86e073729bdff9b5b29603a6fc35165e61daa42361067c4e50d0b1d6ef6311ebbc91d + languageName: node + linkType: hard + +"@graphql-codegen/typescript-graphql-request@npm:^6.2.0": + version: 6.2.0 + resolution: "@graphql-codegen/typescript-graphql-request@npm:6.2.0" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^3.0.0" + "@graphql-codegen/visitor-plugin-common": "npm:2.13.1" + auto-bind: "npm:~4.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + graphql-request: ^6.0.0 + graphql-tag: ^2.0.0 + checksum: 10c0/f25b59346684c2a072f9dfa10b7593b0614fb10b3b503b78cb4ea7ab40103f28a626ed43025a8dfdc6265f53f01fa53d59553c7b0073a097522a934ea178575c + languageName: node + linkType: hard + +"@graphql-codegen/typescript-operations@npm:^4.3.1": + version: 4.3.1 + resolution: "@graphql-codegen/typescript-operations@npm:4.3.1" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-codegen/typescript": "npm:^4.1.1" + "@graphql-codegen/visitor-plugin-common": "npm:5.5.0" + auto-bind: "npm:~4.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/74ed1dfaae19bbb6611981352f81bca2244cbfeed71b0c1627e0321bcb8467e71d61b7f54a17606e8d696a223d556226ad27ecb23937da2b1c4b98bee329f2d3 + languageName: node + linkType: hard + +"@graphql-codegen/typescript@npm:^4.1.1": + version: 4.1.1 + resolution: "@graphql-codegen/typescript@npm:4.1.1" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-codegen/schema-ast": "npm:^4.0.2" + "@graphql-codegen/visitor-plugin-common": "npm:5.5.0" + auto-bind: "npm:~4.0.0" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/728a76058737ec321951df536ddbd1891745c700117392b95b563cba9c9608c9c8002348b6279391fa533d176669ac2898a5cd2ec683c21e9a0461957fd00efd + languageName: node + linkType: hard + +"@graphql-codegen/visitor-plugin-common@npm:2.13.1": + version: 2.13.1 + resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.1" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^2.7.2" + "@graphql-tools/optimize": "npm:^1.3.0" + "@graphql-tools/relay-operation-optimizer": "npm:^6.5.0" + "@graphql-tools/utils": "npm:^8.8.0" + auto-bind: "npm:~4.0.0" + change-case-all: "npm:1.0.14" + dependency-graph: "npm:^0.11.0" + graphql-tag: "npm:^2.11.0" + parse-filepath: "npm:^1.0.2" + tslib: "npm:~2.4.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/9dfc4893599721eba988103d4456345f915cab75c9a754e78a21bd7d05c49b00a01f38ffb70355d758626da0396ae3bb6d44fc98d5c8f9f36a1b122aea0063c4 + languageName: node + linkType: hard + +"@graphql-codegen/visitor-plugin-common@npm:5.5.0, @graphql-codegen/visitor-plugin-common@npm:^5.5.0": + version: 5.5.0 + resolution: "@graphql-codegen/visitor-plugin-common@npm:5.5.0" + dependencies: + "@graphql-codegen/plugin-helpers": "npm:^5.1.0" + "@graphql-tools/optimize": "npm:^2.0.0" + "@graphql-tools/relay-operation-optimizer": "npm:^7.0.0" + "@graphql-tools/utils": "npm:^10.0.0" + auto-bind: "npm:~4.0.0" + change-case-all: "npm:1.0.15" + dependency-graph: "npm:^0.11.0" + graphql-tag: "npm:^2.11.0" + parse-filepath: "npm:^1.0.2" + tslib: "npm:~2.6.0" + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + checksum: 10c0/b272bd5d70337d0d309954c24286117ee3437d57487cbb305a98396608eae39da0d1dd33e125e7471bc3cd69b8ca5c59d574003fa66540aebdf77011de943b86 + languageName: node + linkType: hard + +"@graphql-tools/apollo-engine-loader@npm:^8.0.0": + version: 8.0.2 + resolution: "@graphql-tools/apollo-engine-loader@npm:8.0.2" + dependencies: + "@ardatan/sync-fetch": "npm:^0.0.1" + "@graphql-tools/utils": "npm:^10.5.5" + "@whatwg-node/fetch": "npm:^0.9.0" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/c8d7974e9af625a38491fe705c275b94604c108cc15e021615dea48e921782fd6a4a8f63fa6e0d79c181bc8b293a951a91d54ff04cde8f178c84a69d630a326f + languageName: node + linkType: hard + +"@graphql-tools/batch-execute@npm:^9.0.5": + version: 9.0.5 + resolution: "@graphql-tools/batch-execute@npm:9.0.5" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + dataloader: "npm:^2.2.2" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/df2760b21e9baf6fade8507fb7a19877f71bb250079b23c8c763cb3422d62a498e8c525130d7e856878a03cc2530b7b4debcb398fd9a566e3b5765f880a52cf3 + languageName: node + linkType: hard + +"@graphql-tools/code-file-loader@npm:^8.0.0": + version: 8.1.4 + resolution: "@graphql-tools/code-file-loader@npm:8.1.4" + dependencies: + "@graphql-tools/graphql-tag-pluck": "npm:8.3.3" + "@graphql-tools/utils": "npm:^10.5.5" + globby: "npm:^11.0.3" + tslib: "npm:^2.4.0" + unixify: "npm:^1.0.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/01be2381bbbdcd869d6d26de76d70b8fccc382101f991b3d295e49fd5cf6659752dbf558d57372e9e755b79a5db059c884d3a4767e33121e22593f0b6951e823 + languageName: node + linkType: hard + +"@graphql-tools/delegate@npm:^10.1.1": + version: 10.1.1 + resolution: "@graphql-tools/delegate@npm:10.1.1" + dependencies: + "@graphql-tools/batch-execute": "npm:^9.0.5" + "@graphql-tools/executor": "npm:^1.3.2" + "@graphql-tools/schema": "npm:^10.0.7" + "@graphql-tools/utils": "npm:^10.5.5" + "@repeaterjs/repeater": "npm:^3.0.6" + dataloader: "npm:^2.2.2" + dset: "npm:^3.1.2" + tslib: "npm:^2.5.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/98ad9219ba84f7914133f711a1cfcb692bd13b6e3feebaa1c71b4b861b4f6ea6f8d235710468ec5b8cdf8c2c5a649c95912e8080dca1e0c26d77ded50328f76f + languageName: node + linkType: hard + +"@graphql-tools/documents@npm:^1.0.0": + version: 1.0.1 + resolution: "@graphql-tools/documents@npm:1.0.1" + dependencies: + lodash.sortby: "npm:^4.7.0" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/df24738f8ffd844a4727884f7825d7009456d7dcb24fa91169efdc061bb72a29527abeb2e23ccf9effed195104485fa286919c33452d8744cb659ad721f17586 + languageName: node + linkType: hard + +"@graphql-tools/executor-graphql-ws@npm:^1.3.1": + version: 1.3.1 + resolution: "@graphql-tools/executor-graphql-ws@npm:1.3.1" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + "@types/ws": "npm:^8.0.0" + graphql-ws: "npm:^5.14.0" + isomorphic-ws: "npm:^5.0.0" + tslib: "npm:^2.4.0" + ws: "npm:^8.17.1" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/58a4828ee0f74eed2b0dd89c16fc08750cfd5fd8ff65df238e32038fc823a57d1e914bb6ed0c4ca1d11b1c96f2548ee6978f92f2458e52ee8c8b650795cfef93 + languageName: node + linkType: hard + +"@graphql-tools/executor-http@npm:^1.1.7": + version: 1.1.7 + resolution: "@graphql-tools/executor-http@npm:1.1.7" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + "@repeaterjs/repeater": "npm:^3.0.4" + "@whatwg-node/fetch": "npm:^0.9.0" + extract-files: "npm:^11.0.0" + meros: "npm:^1.2.1" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/3110bcafc7ce7132f6508c47722f901eacac01077618317a2e7532e5a0557ab1e9060e18949f60637b896b1d5b1396e7bb0a7d44c6090ed05455c73ee544aacd + languageName: node + linkType: hard + +"@graphql-tools/executor-legacy-ws@npm:^1.1.1": + version: 1.1.1 + resolution: "@graphql-tools/executor-legacy-ws@npm:1.1.1" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + "@types/ws": "npm:^8.0.0" + isomorphic-ws: "npm:^5.0.0" + tslib: "npm:^2.4.0" + ws: "npm:^8.17.1" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/872fe2a418790b4f8c74a02b2cb58fef56a2b9f69cf4935bdd57a645274473acc7567664e1f0eb857ffa6753ad11537884e58be4a82d6f704b3a1763fdd4256a + languageName: node + linkType: hard + +"@graphql-tools/executor@npm:^1.3.2": + version: 1.3.2 + resolution: "@graphql-tools/executor@npm:1.3.2" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + "@graphql-typed-document-node/core": "npm:3.2.0" + "@repeaterjs/repeater": "npm:^3.0.4" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/232eadfbca6693ddcac8367a6ed1884a18dcfd1b40385e49a98a1a2ef5abd5289b7dca15f6bc7522e402d2b917026a81507324dfee425ef8b90be261932d25e2 + languageName: node + linkType: hard + +"@graphql-tools/git-loader@npm:^8.0.0": + version: 8.0.8 + resolution: "@graphql-tools/git-loader@npm:8.0.8" + dependencies: + "@graphql-tools/graphql-tag-pluck": "npm:8.3.3" + "@graphql-tools/utils": "npm:^10.5.5" + is-glob: "npm:4.0.3" + micromatch: "npm:^4.0.8" + tslib: "npm:^2.4.0" + unixify: "npm:^1.0.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/9f83afcd857ece89a06ec317f9de4452f1a07c97b424d5a6bbf691110070585f4b88ae702e4669d0d819cf461e6cba18681649b76ad7cc1914791bf5b2f754ac + languageName: node + linkType: hard + +"@graphql-tools/github-loader@npm:^8.0.0": + version: 8.0.2 + resolution: "@graphql-tools/github-loader@npm:8.0.2" + dependencies: + "@ardatan/sync-fetch": "npm:^0.0.1" + "@graphql-tools/executor-http": "npm:^1.1.7" + "@graphql-tools/graphql-tag-pluck": "npm:^8.3.3" + "@graphql-tools/utils": "npm:^10.5.5" + "@whatwg-node/fetch": "npm:^0.9.0" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/ef300716307005e3fa9c64bd6c6a26446e6f87da8a7d4e4ee2afd065f3dc469e670a4cc83093a55bb6a39fa0f5639f535dc22fa433a0ec4b8755df7dca6e022f + languageName: node + linkType: hard + +"@graphql-tools/graphql-file-loader@npm:^8.0.0": + version: 8.0.2 + resolution: "@graphql-tools/graphql-file-loader@npm:8.0.2" + dependencies: + "@graphql-tools/import": "npm:7.0.2" + "@graphql-tools/utils": "npm:^10.5.5" + globby: "npm:^11.0.3" + tslib: "npm:^2.4.0" + unixify: "npm:^1.0.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/75094d0d7b803c384a2c69e223c8b2668c4bbbf68e2339b4b7ea6a2d1f045f4ac939b5a897d42ea4d351b42fc3f5123bbd83cf870fee0a3f834a24e739f2103e + languageName: node + linkType: hard + +"@graphql-tools/graphql-tag-pluck@npm:8.3.3, @graphql-tools/graphql-tag-pluck@npm:^8.3.3": + version: 8.3.3 + resolution: "@graphql-tools/graphql-tag-pluck@npm:8.3.3" + dependencies: + "@babel/core": "npm:^7.22.9" + "@babel/parser": "npm:^7.16.8" + "@babel/plugin-syntax-import-assertions": "npm:^7.20.0" + "@babel/traverse": "npm:^7.16.8" + "@babel/types": "npm:^7.16.8" + "@graphql-tools/utils": "npm:^10.5.5" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/197094895ee350d5c2ebd9088396653a56d3d058f0f4b554aef01611d774473a3998083c43f01d9b2a419f91d71a3b80ab937b3d20797bc971317b99ce7ca0b5 + languageName: node + linkType: hard + +"@graphql-tools/import@npm:7.0.2": + version: 7.0.2 + resolution: "@graphql-tools/import@npm:7.0.2" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + resolve-from: "npm:5.0.0" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/68a633c0244544e532656dd95805872f0308d2f05b45b3080ab7c5ad88e0b39d38ce573cef3102bca4b8dcdfef9a9fdb1e7ccb5cafa071c8d9cd56a304b09015 + languageName: node + linkType: hard + +"@graphql-tools/json-file-loader@npm:^8.0.0": + version: 8.0.2 + resolution: "@graphql-tools/json-file-loader@npm:8.0.2" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + globby: "npm:^11.0.3" + tslib: "npm:^2.4.0" + unixify: "npm:^1.0.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/e4f5920160d30690b0fb5e9298be3c1e31e07ccb3f08cde40683039a9b30c03f37049e9e07b2e00f1290a38c115d35eb898a554df628424d5a3deeaaf1f60938 + languageName: node + linkType: hard + +"@graphql-tools/load@npm:^8.0.0": + version: 8.0.3 + resolution: "@graphql-tools/load@npm:8.0.3" + dependencies: + "@graphql-tools/schema": "npm:^10.0.7" + "@graphql-tools/utils": "npm:^10.5.5" + p-limit: "npm:3.1.0" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/f2646ececf1231799933aaf24708249ffc1821921e998d3c085fbc487d659dbde10aba37237912c59d4233af7f204fc614e7cbbed17ab517923d100dabd51a7e + languageName: node + linkType: hard + +"@graphql-tools/merge@npm:^9.0.0, @graphql-tools/merge@npm:^9.0.8": + version: 9.0.8 + resolution: "@graphql-tools/merge@npm:9.0.8" + dependencies: + "@graphql-tools/utils": "npm:^10.5.5" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/1916146ce0e6e19b2250de8f6ad18f1c88f017315ba505ea2bc1607504ee8de7cd2930460b560796895bd76c85bba5639cf43fc7d86e02b68fcef0e1168bf151 + languageName: node + linkType: hard + +"@graphql-tools/optimize@npm:^1.3.0": + version: 1.4.0 + resolution: "@graphql-tools/optimize@npm:1.4.0" dependencies: - "@graphql-typed-document-node/core": "npm:^3.2.0" - debug: "npm:^4.3.4" - dotenv: "npm:^16.3.1" - ethers: "npm:6.7.1" - graphql: "npm:^16.8.1" - graphql-request: "npm:^6.1.0" - graphql-scalars: "npm:^1.22.4" - graphql-tag: "npm:^2.12.6" - ipfs-http-client: "npm:^60.0.1" - multiformats: "npm:^13.0.1" - checksum: 10c0/10009e68a5d2441bfa749cb00c2944bd705dd7b1ff755e12649a50f8e408ad9f984ffbc17b54006d5c92cef4f90d0aa0eac126bb621c28cf06b1342124242b5a + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/10be773b0082fe54b9505469a89925f1a5e33f866453b88cd411261951e8718f8720451e07c56cbfb762970b56b9b45c7c748d62afcdcf9414ec64533e94e543 languageName: node linkType: hard -"@fluencelabs/fluence-network-environment@npm:1.2.3": - version: 1.2.3 - resolution: "@fluencelabs/fluence-network-environment@npm:1.2.3" - checksum: 10c0/5ae802a4cf2e5f2656527f2fc57b6c45bbdc106a64a7a4cebf7b15eed390d0e57f487cde73e57676686ac98775a7d94a6280436cc457a675fc3d746580ff84ea +"@graphql-tools/optimize@npm:^2.0.0": + version: 2.0.0 + resolution: "@graphql-tools/optimize@npm:2.0.0" + dependencies: + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/db4ac0a2b0c89126ee7746e5615ae003d8665b684b17fb35956a7633fefb0e329a047f32a975cfbdf83f0f5ac4ae09fe469834fd71fdd49d8ed932fda79012fd languageName: node linkType: hard -"@fluencelabs/interfaces@npm:0.12.0": - version: 0.12.0 - resolution: "@fluencelabs/interfaces@npm:0.12.0" - checksum: 10c0/f9daf04484d34c7dd3fd6e6385baedbbabd0883164307afa43d9c20479d74965bb0857967e86797b5a4ef02b0aec244ab6191feb0b4268dfb687532b98667ed1 +"@graphql-tools/prisma-loader@npm:^8.0.0": + version: 8.0.15 + resolution: "@graphql-tools/prisma-loader@npm:8.0.15" + dependencies: + "@graphql-tools/url-loader": "npm:^8.0.13" + "@graphql-tools/utils": "npm:^10.5.5" + "@types/js-yaml": "npm:^4.0.0" + "@whatwg-node/fetch": "npm:^0.9.0" + chalk: "npm:^4.1.0" + debug: "npm:^4.3.1" + dotenv: "npm:^16.0.0" + graphql-request: "npm:^6.0.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.0" + jose: "npm:^5.0.0" + js-yaml: "npm:^4.0.0" + lodash: "npm:^4.17.20" + scuid: "npm:^1.1.0" + tslib: "npm:^2.4.0" + yaml-ast-parser: "npm:^0.0.43" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/fc98651360be6d4d1b7eb8dd33da540a081e8f8fe63676b45f137ae985513fb67f2dcf960c08e6b09f207d4f89fc0bf10b75d22ef48f8667190c08972c5442e1 languageName: node linkType: hard -"@fluencelabs/js-client-isomorphic@npm:0.6.0": - version: 0.6.0 - resolution: "@fluencelabs/js-client-isomorphic@npm:0.6.0" +"@graphql-tools/relay-operation-optimizer@npm:^6.5.0": + version: 6.5.18 + resolution: "@graphql-tools/relay-operation-optimizer@npm:6.5.18" dependencies: - "@fluencelabs/avm": "npm:0.62.0" - "@fluencelabs/marine-js": "npm:0.13.0" - "@fluencelabs/marine-worker": "npm:0.6.0" - "@fluencelabs/threads": "npm:^2.0.0" - checksum: 10c0/d644e9116da0d715ec4673e5b908d84ea448665718e428916c75514e9a114f026fc59b4a09c197b65f20abd09e01786e5bc4cf6ad71f67583cfca98ab2e9a0f9 + "@ardatan/relay-compiler": "npm:12.0.0" + "@graphql-tools/utils": "npm:^9.2.1" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/9d74d65da8bf474e256ff0cfb77afb442a968451ded6a92b8348d8ac1bca3b2c13a578ab29ac869d10d53e0101219fe8283d485fff920aa7abcc68fcbbdd9a36 languageName: node linkType: hard -"@fluencelabs/js-client@npm:0.9.0": - version: 0.9.0 - resolution: "@fluencelabs/js-client@npm:0.9.0" +"@graphql-tools/relay-operation-optimizer@npm:^7.0.0": + version: 7.0.2 + resolution: "@graphql-tools/relay-operation-optimizer@npm:7.0.2" dependencies: - "@chainsafe/libp2p-noise": "npm:14.0.0" - "@chainsafe/libp2p-yamux": "npm:6.0.1" - "@fluencelabs/avm": "npm:0.62.0" - "@fluencelabs/interfaces": "npm:0.12.0" - "@fluencelabs/js-client-isomorphic": "npm:0.6.0" - "@fluencelabs/marine-worker": "npm:0.6.0" - "@fluencelabs/threads": "npm:^2.0.0" - "@libp2p/crypto": "npm:4.0.1" - "@libp2p/identify": "npm:1.0.11" - "@libp2p/interface": "npm:1.1.2" - "@libp2p/peer-id": "npm:4.0.5" - "@libp2p/peer-id-factory": "npm:4.0.5" - "@libp2p/ping": "npm:1.0.10" - "@libp2p/utils": "npm:5.2.2" - "@libp2p/websockets": "npm:8.0.12" - "@multiformats/multiaddr": "npm:12.1.12" - bs58: "npm:5.0.0" - debug: "npm:4.3.4" - int64-buffer: "npm:1.0.1" - it-length-prefixed: "npm:9.0.3" - it-map: "npm:3.0.5" - it-pipe: "npm:3.0.1" - js-base64: "npm:3.7.5" - libp2p: "npm:1.2.0" - multiformats: "npm:11.0.1" - rxjs: "npm:7.5.5" - uint8arrays: "npm:4.0.3" - uuid: "npm:8.3.2" - zod: "npm:3.22.4" - checksum: 10c0/e238b5682e8017e100527d2d9c8182212319d1ecbb90483934602470c2aa1b45a3a5e2650dfd281a47f1aab3f3eb27d6f6564c9f8f3bf87e7d7e50956146a6e2 + "@ardatan/relay-compiler": "npm:12.0.0" + "@graphql-tools/utils": "npm:^10.5.5" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/aac020333f2c9ed7e6fcbaac58712961384afcc68c8d1db825daa0feb3b7175004f1d013668bb0db742e9a9df74441c17a4efdfb389a5613e3e5496a8e00c35e languageName: node linkType: hard -"@fluencelabs/marine-js@npm:0.13.0": - version: 0.13.0 - resolution: "@fluencelabs/marine-js@npm:0.13.0" +"@graphql-tools/schema@npm:^10.0.0, @graphql-tools/schema@npm:^10.0.7": + version: 10.0.7 + resolution: "@graphql-tools/schema@npm:10.0.7" dependencies: - "@wasmer/wasi": "npm:0.12.0" - "@wasmer/wasmfs": "npm:0.12.0" - default-import: "npm:1.1.5" - checksum: 10c0/c8a36875bfbd890eb8afab61bbce8bc98f32b6bbe4bc58c23e402996491499cdac77ef757959191d5148aef1a200196b29a7a42de805aa6dc8418c638a620717 + "@graphql-tools/merge": "npm:^9.0.8" + "@graphql-tools/utils": "npm:^10.5.5" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/0906045ae2488ba11c9b372a7df7157aa12c510e877a13ca02b048f2d4275f363b4265cbc3edb181a8410c7af2c953f2cf70b1138499e89200fe54a6077c149f languageName: node linkType: hard -"@fluencelabs/marine-worker@npm:0.6.0": - version: 0.6.0 - resolution: "@fluencelabs/marine-worker@npm:0.6.0" +"@graphql-tools/url-loader@npm:^8.0.0, @graphql-tools/url-loader@npm:^8.0.13": + version: 8.0.13 + resolution: "@graphql-tools/url-loader@npm:8.0.13" dependencies: - "@fluencelabs/marine-js": "npm:0.13.0" - "@fluencelabs/threads": "npm:^2.0.0" - observable-fns: "npm:0.6.1" - checksum: 10c0/c91c282caf829613437384d9ac6df26283b73f6af1a810a6c4b77603ed659f9187576928b9ce67a6c99ff20ab353b6ce5ac56fa4fc38dbc50adee37a60961aa4 + "@ardatan/sync-fetch": "npm:^0.0.1" + "@graphql-tools/executor-graphql-ws": "npm:^1.3.1" + "@graphql-tools/executor-http": "npm:^1.1.7" + "@graphql-tools/executor-legacy-ws": "npm:^1.1.1" + "@graphql-tools/utils": "npm:^10.5.5" + "@graphql-tools/wrap": "npm:^10.0.15" + "@types/ws": "npm:^8.0.0" + "@whatwg-node/fetch": "npm:^0.9.0" + isomorphic-ws: "npm:^5.0.0" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.11" + ws: "npm:^8.17.1" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/79fa0c1940a9761e15ea9197cdc9364cb556d01de21f3528af0f273c83cb3776bb3cbf3ca9b686357357326fdf55530d104c986760bfe5ac2c6f291906c19571 languageName: node linkType: hard -"@fluencelabs/npm-aqua-compiler@npm:0.0.3": - version: 0.0.3 - resolution: "@fluencelabs/npm-aqua-compiler@npm:0.0.3" +"@graphql-tools/utils@npm:^10.0.0, @graphql-tools/utils@npm:^10.5.5": + version: 10.5.5 + resolution: "@graphql-tools/utils@npm:10.5.5" dependencies: - "@npmcli/arborist": "npm:^7.2.1" - treeverse: "npm:3.0.0" - checksum: 10c0/0f11c4c68d2a58ae3d6f45be073a53d4dd3e278dbdabfa80204cb24bb5eb2d33b5cea71ee79e78b6e3f3eadf8e8c47d384ef76babbd3876a233d19cfa9a2ba2a + "@graphql-typed-document-node/core": "npm:^3.1.1" + cross-inspect: "npm:1.0.1" + dset: "npm:^3.1.2" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/826f853dd51681165513e92e2d1c85f605bcc42fb2383db2c9645f82821f07866a65e4b2a293c5e4717b38f74c6f4d798500c61b5a68e4cb7dd707189b18cdb6 languageName: node linkType: hard -"@fluencelabs/threads@npm:^2.0.0": - version: 2.0.0 - resolution: "@fluencelabs/threads@npm:2.0.0" +"@graphql-tools/utils@npm:^8.8.0": + version: 8.13.1 + resolution: "@graphql-tools/utils@npm:8.13.1" dependencies: - callsites: "npm:^3.1.0" - debug: "npm:^4.2.0" - is-observable: "npm:^2.1.0" - observable-fns: "npm:^0.6.1" - tiny-worker: "npm:>= 2" - dependenciesMeta: - tiny-worker: - optional: true - checksum: 10c0/1a7f73048f3f69da328386bbc3727b480f77907e779796d7485d172c35f484f4daa7592df4701ab8dd3142a34f4ea39d2495da48d9deabf830e32cfb846e7d64 + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/f9bab1370aa91e706abec4c8ea980e15293cb78bd4effba53ad2365dc39d81148db7667b3ef89b35f0a0b0ad58081ffdac4264b7125c69fa8393590ae5025745 + languageName: node + linkType: hard + +"@graphql-tools/utils@npm:^9.0.0, @graphql-tools/utils@npm:^9.2.1": + version: 9.2.1 + resolution: "@graphql-tools/utils@npm:9.2.1" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.1.1" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/37a7bd7e14d28ff1bacc007dca84bc6cef2d7d7af9a547b5dbe52fcd134afddd6d4a7b2148cfbaff5ddba91a868453d597da77bd0457fb0be15928f916901606 + languageName: node + linkType: hard + +"@graphql-tools/wrap@npm:^10.0.15": + version: 10.0.15 + resolution: "@graphql-tools/wrap@npm:10.0.15" + dependencies: + "@graphql-tools/delegate": "npm:^10.1.1" + "@graphql-tools/schema": "npm:^10.0.7" + "@graphql-tools/utils": "npm:^10.5.5" + tslib: "npm:^2.4.0" + value-or-promise: "npm:^1.0.12" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/d478ea6a2967c14772bbe9fe7521e32bc2d6d21d2d26f5fcd89850b54a71054e342f89c99ea8d4207b6aa36eb77240073f52da03812b40117773a65fa11e93cc languageName: node linkType: hard -"@graphql-typed-document-node/core@npm:^3.2.0": +"@graphql-typed-document-node/core@npm:3.2.0, @graphql-typed-document-node/core@npm:^3.1.1, @graphql-typed-document-node/core@npm:^3.2.0": version: 3.2.0 resolution: "@graphql-typed-document-node/core@npm:3.2.0" peerDependencies: @@ -1818,13 +3151,55 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/1be4fd4a6b0f41337c4f5fdf4afc3bd19e39c3691924817108b82ffcb9c9e609c273f936932b9fba4b3a298ce2eb06d9bff4eb1cc3bd81c4f4ee1b4917e25feb + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.0 resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 + languageName: node + linkType: hard + +"@kamilkisiela/fast-url-parser@npm:^1.1.4": + version: 1.1.4 + resolution: "@kamilkisiela/fast-url-parser@npm:1.1.4" + checksum: 10c0/2c85202cb4924720ac812c8bc06967fd5df4db759a68aa3acc2962b8cf9e2b3bc131de863f00473c0b0602df13891b35140f667a87eea04c9b897b6c1ae89c4a + languageName: node + linkType: hard + "@leichtgewicht/ip-codec@npm:^2.0.1": version: 2.0.5 resolution: "@leichtgewicht/ip-codec@npm:2.0.5" @@ -3100,6 +4475,13 @@ __metadata: languageName: node linkType: hard +"@repeaterjs/repeater@npm:^3.0.4, @repeaterjs/repeater@npm:^3.0.6": + version: 3.0.6 + resolution: "@repeaterjs/repeater@npm:3.0.6" + checksum: 10c0/c3915e2603927c7d6a9eb09673bc28fc49ab3a86947ec191a74663b33deebee2fcc4b03c31cc663ff27bd6db9e6c9487639b6935e265d601ce71b8c497f5f4a8 + languageName: node + linkType: hard + "@rollup/rollup-android-arm-eabi@npm:4.18.0": version: 4.18.0 resolution: "@rollup/rollup-android-arm-eabi@npm:4.18.0" @@ -4164,6 +5546,13 @@ __metadata: languageName: node linkType: hard +"@types/js-yaml@npm:^4.0.0": + version: 4.0.9 + resolution: "@types/js-yaml@npm:4.0.9" + checksum: 10c0/24de857aa8d61526bbfbbaa383aa538283ad17363fcd5bb5148e2c7f604547db36646440e739d78241ed008702a8920665d1add5618687b6743858fae00da211 + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.15": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" @@ -4380,6 +5769,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.0.0": + version: 8.5.13 + resolution: "@types/ws@npm:8.5.13" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/a5430aa479bde588e69cb9175518d72f9338b6999e3b2ae16fc03d3bdcff8347e486dc031e4ed14601260463c07e1f9a0d7511dfc653712b047c439c680b0b34 + languageName: node + linkType: hard + "@types/ws@npm:^8.2.2, @types/ws@npm:^8.5.4": version: 8.5.10 resolution: "@types/ws@npm:8.5.10" @@ -4703,6 +6101,28 @@ __metadata: languageName: node linkType: hard +"@whatwg-node/fetch@npm:^0.9.0, @whatwg-node/fetch@npm:^0.9.20": + version: 0.9.22 + resolution: "@whatwg-node/fetch@npm:0.9.22" + dependencies: + "@whatwg-node/node-fetch": "npm:^0.5.27" + urlpattern-polyfill: "npm:^10.0.0" + checksum: 10c0/67a8668b2dd491b24a20a03ba23b6463481e209b16e2ffc9444ed9f52fb82de744a6076278499cea60737985204fca44f68dccea7e2af1a5fb68c2721e3bb1a6 + languageName: node + linkType: hard + +"@whatwg-node/node-fetch@npm:^0.5.27": + version: 0.5.27 + resolution: "@whatwg-node/node-fetch@npm:0.5.27" + dependencies: + "@kamilkisiela/fast-url-parser": "npm:^1.1.4" + busboy: "npm:^1.6.0" + fast-querystring: "npm:^1.1.1" + tslib: "npm:^2.6.3" + checksum: 10c0/1cd036e1ef36bfc71436a3e7438b180b94c33d7958c02e33540c35d37db19fb598f2ab09f0aef538a3bbc771c32d34c5728a596ffabf8be7961435a80fcb8f62 + languageName: node + linkType: hard + "abbrev@npm:^2.0.0": version: 2.0.0 resolution: "abbrev@npm:2.0.0" @@ -4818,7 +6238,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.3.2": +"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.0, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -5030,6 +6450,13 @@ __metadata: languageName: node linkType: hard +"asap@npm:~2.0.3": + version: 2.0.6 + resolution: "asap@npm:2.0.6" + checksum: 10c0/c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d + languageName: node + linkType: hard + "asn1js@npm:^3.0.5": version: 3.0.5 resolution: "asn1js@npm:3.0.5" @@ -5064,6 +6491,13 @@ __metadata: languageName: node linkType: hard +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 10c0/f63d439cc383db1b9c5c6080d1e240bd14dae745f15d11ec5da863e182bbeca70df6c8191cffef5deba0b566ef98834610a68be79ac6379c95eeb26e1b310e25 + languageName: node + linkType: hard + "async-retry@npm:^1.3.3": version: 1.3.3 resolution: "async-retry@npm:1.3.3" @@ -5087,6 +6521,13 @@ __metadata: languageName: node linkType: hard +"auto-bind@npm:~4.0.0": + version: 4.0.0 + resolution: "auto-bind@npm:4.0.0" + checksum: 10c0/12f70745d081ba990dca028ecfa70de25d4baa9a8b74a5bef3ab293da56cba32ff8276c3ff8e5fe6d9f370547bf3fa71486befbfefe272af7e722c21d0c25530 + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -5096,6 +6537,50 @@ __metadata: languageName: node linkType: hard +"babel-plugin-syntax-trailing-function-commas@npm:^7.0.0-beta.0": + version: 7.0.0-beta.0 + resolution: "babel-plugin-syntax-trailing-function-commas@npm:7.0.0-beta.0" + checksum: 10c0/67e3d6a706637097526b2d3046d3124d3efd3aac28b47af940c2f8df01b8d7ffeb4cdf5648f3b5eac3f098f5b61c4845e306f34301c869e5e14db6ae8b77f699 + languageName: node + linkType: hard + +"babel-preset-fbjs@npm:^3.4.0": + version: 3.4.0 + resolution: "babel-preset-fbjs@npm:3.4.0" + dependencies: + "@babel/plugin-proposal-class-properties": "npm:^7.0.0" + "@babel/plugin-proposal-object-rest-spread": "npm:^7.0.0" + "@babel/plugin-syntax-class-properties": "npm:^7.0.0" + "@babel/plugin-syntax-flow": "npm:^7.0.0" + "@babel/plugin-syntax-jsx": "npm:^7.0.0" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.0.0" + "@babel/plugin-transform-arrow-functions": "npm:^7.0.0" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.0.0" + "@babel/plugin-transform-block-scoping": "npm:^7.0.0" + "@babel/plugin-transform-classes": "npm:^7.0.0" + "@babel/plugin-transform-computed-properties": "npm:^7.0.0" + "@babel/plugin-transform-destructuring": "npm:^7.0.0" + "@babel/plugin-transform-flow-strip-types": "npm:^7.0.0" + "@babel/plugin-transform-for-of": "npm:^7.0.0" + "@babel/plugin-transform-function-name": "npm:^7.0.0" + "@babel/plugin-transform-literals": "npm:^7.0.0" + "@babel/plugin-transform-member-expression-literals": "npm:^7.0.0" + "@babel/plugin-transform-modules-commonjs": "npm:^7.0.0" + "@babel/plugin-transform-object-super": "npm:^7.0.0" + "@babel/plugin-transform-parameters": "npm:^7.0.0" + "@babel/plugin-transform-property-literals": "npm:^7.0.0" + "@babel/plugin-transform-react-display-name": "npm:^7.0.0" + "@babel/plugin-transform-react-jsx": "npm:^7.0.0" + "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0" + "@babel/plugin-transform-spread": "npm:^7.0.0" + "@babel/plugin-transform-template-literals": "npm:^7.0.0" + babel-plugin-syntax-trailing-function-commas: "npm:^7.0.0-beta.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/2be440c0fd7d1df247417be35644cb89f40a300e7fcdc44878b737ec49b04380eff422e4ebdc7bb5efd5ecfef45b634fc5fe11c3a409a50c9084e81083037902 + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -5252,6 +6737,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0": + version: 4.24.2 + resolution: "browserslist@npm:4.24.2" + dependencies: + caniuse-lite: "npm:^1.0.30001669" + electron-to-chromium: "npm:^1.5.41" + node-releases: "npm:^2.0.18" + update-browserslist-db: "npm:^1.1.1" + bin: + browserslist: cli.js + checksum: 10c0/d747c9fb65ed7b4f1abcae4959405707ed9a7b835639f8a9ba0da2911995a6ab9b0648fd05baf2a4d4e3cf7f9fdbad56d3753f91881e365992c1d49c8d88ff7a + languageName: node + linkType: hard + "bs58@npm:5.0.0": version: 5.0.0 resolution: "bs58@npm:5.0.0" @@ -5261,6 +6760,15 @@ __metadata: languageName: node linkType: hard +"bser@npm:2.1.1": + version: 2.1.1 + resolution: "bser@npm:2.1.1" + dependencies: + node-int64: "npm:^0.4.0" + checksum: 10c0/24d8dfb7b6d457d73f32744e678a60cc553e4ec0e9e1a01cf614b44d85c3c87e188d3cc78ef0442ce5032ee6818de20a0162ba1074725c0d08908f62ea979227 + languageName: node + linkType: hard + "buffer-es6@npm:^4.9.3": version: 4.9.3 resolution: "buffer-es6@npm:4.9.3" @@ -5298,6 +6806,15 @@ __metadata: languageName: node linkType: hard +"busboy@npm:^1.6.0": + version: 1.6.0 + resolution: "busboy@npm:1.6.0" + dependencies: + streamsearch: "npm:^1.1.0" + checksum: 10c0/fa7e836a2b82699b6e074393428b91ae579d4f9e21f5ac468e1b459a244341d722d2d22d10920cdd849743dbece6dca11d72de939fb75a7448825cf2babfba1f + languageName: node + linkType: hard + "bytes@npm:3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -5404,6 +6921,20 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:^5.0.0": + version: 5.3.1 + resolution: "camelcase@npm:5.3.1" + checksum: 10c0/92ff9b443bfe8abb15f2b1513ca182d16126359ad4f955ebc83dc4ddcc4ef3fdd2c078bc223f2673dc223488e75c99b16cc4d056624374b799e6a1555cf61b23 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001669": + version: 1.0.30001677 + resolution: "caniuse-lite@npm:1.0.30001677" + checksum: 10c0/22b4aa738b213b5d0bc820c26ba23fa265ca90a5c59776e1a686b9ab6fff9120d0825fd920c0a601a4b65056ef40d01548405feb95c8dd6083255f50c71a0864 + languageName: node + linkType: hard + "capital-case@npm:^1.0.4": version: 1.0.4 resolution: "capital-case@npm:1.0.4" @@ -5465,7 +6996,43 @@ __metadata: languageName: node linkType: hard -"change-case@npm:^4": +"change-case-all@npm:1.0.14": + version: 1.0.14 + resolution: "change-case-all@npm:1.0.14" + dependencies: + change-case: "npm:^4.1.2" + is-lower-case: "npm:^2.0.2" + is-upper-case: "npm:^2.0.2" + lower-case: "npm:^2.0.2" + lower-case-first: "npm:^2.0.2" + sponge-case: "npm:^1.0.1" + swap-case: "npm:^2.0.2" + title-case: "npm:^3.0.3" + upper-case: "npm:^2.0.2" + upper-case-first: "npm:^2.0.2" + checksum: 10c0/c2d5fda011b2430f9e503afdca5d8ed48b0e8ee96e38f5530193f8a503317c4a82e6b721c5ea8ef852a2534bdd3d1af25d76e0604b820cd3bc136cf9c179803e + languageName: node + linkType: hard + +"change-case-all@npm:1.0.15": + version: 1.0.15 + resolution: "change-case-all@npm:1.0.15" + dependencies: + change-case: "npm:^4.1.2" + is-lower-case: "npm:^2.0.2" + is-upper-case: "npm:^2.0.2" + lower-case: "npm:^2.0.2" + lower-case-first: "npm:^2.0.2" + sponge-case: "npm:^1.0.1" + swap-case: "npm:^2.0.2" + title-case: "npm:^3.0.3" + upper-case: "npm:^2.0.2" + upper-case-first: "npm:^2.0.2" + checksum: 10c0/0de81690de866aa8c477f8b5b08c6f9dbce4a078cffa5f014858f49fda548a9a6524b61f62f2940acce9f1fdcfeef3a7124090684e86e731f55d26c22713e2d7 + languageName: node + linkType: hard + +"change-case@npm:^4, change-case@npm:^4.1.2": version: 4.1.2 resolution: "change-case@npm:4.1.2" dependencies: @@ -5610,6 +7177,16 @@ __metadata: languageName: node linkType: hard +"cli-truncate@npm:^2.1.0": + version: 2.1.0 + resolution: "cli-truncate@npm:2.1.0" + dependencies: + slice-ansi: "npm:^3.0.0" + string-width: "npm:^4.2.0" + checksum: 10c0/dfaa3df675bcef7a3254773de768712b590250420345a4c7ac151f041a4bacb4c25864b1377bee54a39b5925a030c00eabf014e312e3a4ac130952ed3b3879e9 + languageName: node + linkType: hard + "cli-truncate@npm:^4.0.0": version: 4.0.0 resolution: "cli-truncate@npm:4.0.0" @@ -5620,6 +7197,13 @@ __metadata: languageName: node linkType: hard +"cli-width@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-width@npm:3.0.0" + checksum: 10c0/125a62810e59a2564268c80fdff56c23159a7690c003e34aeb2e68497dccff26911998ff49c33916fcfdf71e824322cc3953e3f7b48b27267c7a062c81348a9a + languageName: node + linkType: hard + "cli-width@npm:^4.1.0": version: 4.1.0 resolution: "cli-width@npm:4.1.0" @@ -5627,6 +7211,28 @@ __metadata: languageName: node linkType: hard +"cliui@npm:^6.0.0": + version: 6.0.0 + resolution: "cliui@npm:6.0.0" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.0" + wrap-ansi: "npm:^6.2.0" + checksum: 10c0/35229b1bb48647e882104cac374c9a18e34bbf0bace0e2cf03000326b6ca3050d6b59545d91e17bfe3705f4a0e2988787aa5cde6331bf5cbbf0164732cef6492 + languageName: node + linkType: hard + +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 + languageName: node + linkType: hard + "clone@npm:^1.0.2": version: 1.0.4 resolution: "clone@npm:1.0.4" @@ -5696,6 +7302,13 @@ __metadata: languageName: node linkType: hard +"colorette@npm:^2.0.16": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 + languageName: node + linkType: hard + "commander@npm:^12.0.0, commander@npm:^12.1.0": version: 12.1.0 resolution: "commander@npm:12.1.0" @@ -5724,6 +7337,13 @@ __metadata: languageName: node linkType: hard +"common-tags@npm:1.8.2": + version: 1.8.2 + resolution: "common-tags@npm:1.8.2" + checksum: 10c0/23efe47ff0a1a7c91489271b3a1e1d2a171c12ec7f9b35b29b2fce51270124aff0ec890087e2bc2182c1cb746e232ab7561aaafe05f1e7452aea733d2bfe3f63 + languageName: node + linkType: hard + "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" @@ -5775,6 +7395,13 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + "convert-to-spaces@npm:^2.0.1": version: 2.0.1 resolution: "convert-to-spaces@npm:2.0.1" @@ -5809,6 +7436,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.1.0, cosmiconfig@npm:^8.1.3": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a + languageName: node + linkType: hard + "cosmiconfig@npm:^9.0.0": version: 9.0.0 resolution: "cosmiconfig@npm:9.0.0" @@ -5842,6 +7486,15 @@ __metadata: languageName: node linkType: hard +"cross-inspect@npm:1.0.1": + version: 1.0.1 + resolution: "cross-inspect@npm:1.0.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/2493ee47a801b46ede1c42ca6242b8d2059f7319b5baf23887bbaf46a6ea8e536d2e271d0990176c05092f67b32d084ffd8c93e7c1227eff4a06cceadb49af47 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -5919,6 +7572,13 @@ __metadata: languageName: node linkType: hard +"dataloader@npm:^2.2.2": + version: 2.2.2 + resolution: "dataloader@npm:2.2.2" + checksum: 10c0/125ec69f821478cf7c6b4360095db6cab939fe57876a0d2060c428091a8deee7152345189923b71a6afa694aaec463779f34b585317164016fd6f54f52cd94ba + languageName: node + linkType: hard + "datastore-core@npm:^9.0.1": version: 9.2.9 resolution: "datastore-core@npm:9.2.9" @@ -5939,6 +7599,13 @@ __metadata: languageName: node linkType: hard +"debounce@npm:^1.2.0": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 10c0/6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500 + languageName: node + linkType: hard + "debug@npm:2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -5972,7 +7639,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4.3.7, debug@npm:^4.3.6, debug@npm:^4.3.7": +"debug@npm:4.3.7, debug@npm:^4.1.0, debug@npm:^4.3.6, debug@npm:^4.3.7": version: 4.3.7 resolution: "debug@npm:4.3.7" dependencies: @@ -5993,6 +7660,13 @@ __metadata: languageName: node linkType: hard +"decamelize@npm:^1.2.0": + version: 1.2.0 + resolution: "decamelize@npm:1.2.0" + checksum: 10c0/85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2 + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -6093,6 +7767,13 @@ __metadata: languageName: node linkType: hard +"dependency-graph@npm:^0.11.0": + version: 0.11.0 + resolution: "dependency-graph@npm:0.11.0" + checksum: 10c0/9e6968d1534fdb502f7f3a25a3819b499f9d60f8389193950ed0b4d1618f1341b36b5d039f2cee256cfe10c9e8198ace16b271e370df06a93fac206e81602e7c + languageName: node + linkType: hard + "dependency-tree@npm:^11.0.0": version: 11.0.1 resolution: "dependency-tree@npm:11.0.1" @@ -6114,6 +7795,13 @@ __metadata: languageName: node linkType: hard +"detect-indent@npm:^6.0.0": + version: 6.1.0 + resolution: "detect-indent@npm:6.1.0" + checksum: 10c0/dd83cdeda9af219cf77f5e9a0dc31d828c045337386cfb55ce04fad94ba872ee7957336834154f7647b89b899c3c7acc977c57a79b7c776b506240993f97acc7 + languageName: node + linkType: hard + "detect-indent@npm:^7.0.1": version: 7.0.1 resolution: "detect-indent@npm:7.0.1" @@ -6295,13 +7983,20 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:16.4.5, dotenv@npm:^16.3.1": +"dotenv@npm:16.4.5, dotenv@npm:^16.0.0, dotenv@npm:^16.3.1": version: 16.4.5 resolution: "dotenv@npm:16.4.5" checksum: 10c0/48d92870076832af0418b13acd6e5a5a3e83bb00df690d9812e94b24aff62b88ade955ac99a05501305b8dc8f1b0ee7638b18493deb6fe93d680e5220936292f languageName: node linkType: hard +"dset@npm:^3.1.2": + version: 3.1.4 + resolution: "dset@npm:3.1.4" + checksum: 10c0/b67bbd28dd8a539e90c15ffb61100eb64ef995c5270a124d4f99bbb53f4d82f55a051b731ba81f3215dd9dce2b4c8d69927dc20b3be1c5fc88bab159467aa438 + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -6336,6 +8031,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.41": + version: 1.5.50 + resolution: "electron-to-chromium@npm:1.5.50" + checksum: 10c0/8b77b18ae833bfe2173e346ac33b8d66b5b5acf0cf5de65df9799f4d482334c938aa0950e4d01391d5fab8994f46c0e9059f4517843e7b8d861f9b0c49eb4c5d + languageName: node + linkType: hard + "emoji-regex@npm:^10.3.0": version: 10.4.0 resolution: "emoji-regex@npm:10.4.0" @@ -6716,6 +8418,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.1.1, escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + "escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -7111,7 +8820,7 @@ __metadata: languageName: node linkType: hard -"external-editor@npm:^3.1.0": +"external-editor@npm:^3.0.3, external-editor@npm:^3.1.0": version: 3.1.0 resolution: "external-editor@npm:3.1.0" dependencies: @@ -7122,6 +8831,20 @@ __metadata: languageName: node linkType: hard +"extract-files@npm:^11.0.0": + version: 11.0.0 + resolution: "extract-files@npm:11.0.0" + checksum: 10c0/7ac1cd693d081099d7c29f2b36aad199f92c5ea234c2016eb37ba213dddaefe74d54566f0675de5917d35cf98670183c2c9a0d96094727eb2c6dae02be7fc308 + languageName: node + linkType: hard + +"fast-decode-uri-component@npm:^1.0.1": + version: 1.0.1 + resolution: "fast-decode-uri-component@npm:1.0.1" + checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -7186,6 +8909,15 @@ __metadata: languageName: node linkType: hard +"fast-querystring@npm:^1.1.1": + version: 1.1.2 + resolution: "fast-querystring@npm:1.1.2" + dependencies: + fast-decode-uri-component: "npm:^1.0.1" + checksum: 10c0/e8223273a9b199722f760f5a047a77ad049a14bd444b821502cb8218f5925e3a5fffb56b64389bca73ab2ac6f1aa7aebbe4e203e5f6e53ff5978de97c0fde4e3 + languageName: node + linkType: hard + "fast-uri@npm:^3.0.1": version: 3.0.1 resolution: "fast-uri@npm:3.0.1" @@ -7220,6 +8952,46 @@ __metadata: languageName: node linkType: hard +"fb-watchman@npm:^2.0.0": + version: 2.0.2 + resolution: "fb-watchman@npm:2.0.2" + dependencies: + bser: "npm:2.1.1" + checksum: 10c0/feae89ac148adb8f6ae8ccd87632e62b13563e6fb114cacb5265c51f585b17e2e268084519fb2edd133872f1d47a18e6bfd7e5e08625c0d41b93149694187581 + languageName: node + linkType: hard + +"fbjs-css-vars@npm:^1.0.0": + version: 1.0.2 + resolution: "fbjs-css-vars@npm:1.0.2" + checksum: 10c0/dfb64116b125a64abecca9e31477b5edb9a2332c5ffe74326fe36e0a72eef7fc8a49b86adf36c2c293078d79f4524f35e80f5e62546395f53fb7c9e69821f54f + languageName: node + linkType: hard + +"fbjs@npm:^3.0.0": + version: 3.0.5 + resolution: "fbjs@npm:3.0.5" + dependencies: + cross-fetch: "npm:^3.1.5" + fbjs-css-vars: "npm:^1.0.0" + loose-envify: "npm:^1.0.0" + object-assign: "npm:^4.1.0" + promise: "npm:^7.1.1" + setimmediate: "npm:^1.0.5" + ua-parser-js: "npm:^1.0.35" + checksum: 10c0/66d0a2fc9a774f9066e35ac2ac4bf1245931d27f3ac287c7d47e6aa1fc152b243c2109743eb8f65341e025621fb51a12038fadb9fd8fda2e3ddae04ebab06f91 + languageName: node + linkType: hard + +"figures@npm:^3.0.0": + version: 3.2.0 + resolution: "figures@npm:3.2.0" + dependencies: + escape-string-regexp: "npm:^1.0.5" + checksum: 10c0/9c421646ede432829a50bc4e55c7a4eb4bcb7cc07b5bab2f471ef1ab9a344595bbebb6c5c21470093fbb730cd81bbca119624c40473a125293f656f49cb47629 + languageName: node + linkType: hard + "file-entry-cache@npm:^8.0.0": version: 8.0.0 resolution: "file-entry-cache@npm:8.0.0" @@ -7306,6 +9078,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^4.1.0": + version: 4.1.0 + resolution: "find-up@npm:4.1.0" + dependencies: + locate-path: "npm:^5.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/0406ee89ebeefa2d507feb07ec366bebd8a6167ae74aa4e34fb4c4abd06cf782a3ce26ae4194d70706f72182841733f00551c209fe575cb00bd92104056e78c1 + languageName: node + linkType: hard + "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -7488,6 +9270,13 @@ __metadata: languageName: node linkType: hard +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + "get-amd-module-type@npm:^6.0.0": version: 6.0.0 resolution: "get-amd-module-type@npm:6.0.0" @@ -7498,6 +9287,13 @@ __metadata: languageName: node linkType: hard +"get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde + languageName: node + linkType: hard + "get-east-asian-width@npm:^1.0.0": version: 1.3.0 resolution: "get-east-asian-width@npm:1.3.0" @@ -7655,7 +9451,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.2.3": +"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.2.3": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -7669,6 +9465,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 + languageName: node + linkType: hard + "globals@npm:^14.0.0": version: 14.0.0 resolution: "globals@npm:14.0.0" @@ -7700,7 +9503,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.1.0": +"globby@npm:^11.0.3, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -7787,7 +9590,32 @@ __metadata: languageName: node linkType: hard -"graphql-request@npm:^6.1.0": +"graphql-config@npm:^5.1.1": + version: 5.1.3 + resolution: "graphql-config@npm:5.1.3" + dependencies: + "@graphql-tools/graphql-file-loader": "npm:^8.0.0" + "@graphql-tools/json-file-loader": "npm:^8.0.0" + "@graphql-tools/load": "npm:^8.0.0" + "@graphql-tools/merge": "npm:^9.0.0" + "@graphql-tools/url-loader": "npm:^8.0.0" + "@graphql-tools/utils": "npm:^10.0.0" + cosmiconfig: "npm:^8.1.0" + jiti: "npm:^2.0.0" + minimatch: "npm:^9.0.5" + string-env-interpolation: "npm:^1.0.1" + tslib: "npm:^2.4.0" + peerDependencies: + cosmiconfig-toml-loader: ^1.0.0 + graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + cosmiconfig-toml-loader: + optional: true + checksum: 10c0/e1a1a665c35a6c01c7922f532aad098c2bea67354e33fbf78d631079fd51fd18fa32e0571dc098c50d22d554c43085afec8b634b29f788f140d17d2bde12c9a6 + languageName: node + linkType: hard + +"graphql-request@npm:^6.0.0, graphql-request@npm:^6.1.0": version: 6.1.0 resolution: "graphql-request@npm:6.1.0" dependencies: @@ -7799,6 +9627,17 @@ __metadata: languageName: node linkType: hard +"graphql-request@npm:^7.1.2": + version: 7.1.2 + resolution: "graphql-request@npm:7.1.2" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.2.0" + peerDependencies: + graphql: 14 - 16 + checksum: 10c0/d87ae2a5603bf5e69a91ff9e2b7a3902ed285d6ea470daf7df37cfa48e71a674a8b026f3fe76881a450484b52e90eff43f950faa6851cd6c79bd5b4ab9d19451 + languageName: node + linkType: hard + "graphql-scalars@npm:^1.22.4": version: 1.23.0 resolution: "graphql-scalars@npm:1.23.0" @@ -7810,7 +9649,7 @@ __metadata: languageName: node linkType: hard -"graphql-tag@npm:^2.12.6": +"graphql-tag@npm:^2.11.0, graphql-tag@npm:^2.12.6": version: 2.12.6 resolution: "graphql-tag@npm:2.12.6" dependencies: @@ -7821,6 +9660,15 @@ __metadata: languageName: node linkType: hard +"graphql-ws@npm:^5.14.0": + version: 5.16.0 + resolution: "graphql-ws@npm:5.16.0" + peerDependencies: + graphql: ">=0.11 <=16" + checksum: 10c0/5e538c3460ca997a1634bd0f64236d8d7aa6ac75c58aba549b49953faf0dd2497f4fa43eedb0bc82cfff50426c7ce47682a670d2571fd7f3af5dcf00911c9e1b + languageName: node + linkType: hard + "graphql@npm:^16.8.1": version: 16.8.1 resolution: "graphql@npm:16.8.1" @@ -7828,6 +9676,13 @@ __metadata: languageName: node linkType: hard +"graphql@npm:^16.9.0": + version: 16.9.0 + resolution: "graphql@npm:16.9.0" + checksum: 10c0/a8850f077ff767377237d1f8b1da2ec70aeb7623cdf1dfc9e1c7ae93accc0c8149c85abe68923be9871a2934b1bce5a2496f846d4d56e1cfb03eaaa7ddba9b6a + languageName: node + linkType: hard + "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" @@ -7979,23 +9834,23 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1": - version: 7.0.4 - resolution: "https-proxy-agent@npm:7.0.4" +"https-proxy-agent@npm:^7.0.0, https-proxy-agent@npm:^7.0.3, https-proxy-agent@npm:^7.0.5": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" dependencies: agent-base: "npm:^7.0.2" debug: "npm:4" - checksum: 10c0/bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b + checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.3, https-proxy-agent@npm:^7.0.5": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" +"https-proxy-agent@npm:^7.0.1": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" dependencies: agent-base: "npm:^7.0.2" debug: "npm:4" - checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c + checksum: 10c0/bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b languageName: node linkType: hard @@ -8049,6 +9904,13 @@ __metadata: languageName: node linkType: hard +"immutable@npm:~3.7.6": + version: 3.7.6 + resolution: "immutable@npm:3.7.6" + checksum: 10c0/efe2bbb2620aa897afbb79545b9eda4dd3dc072e05ae7004895a7efb43187e4265612a88f8723f391eb1c87c46c52fd11e2d1968e42404450c63e49558d7ca4e + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" @@ -8059,6 +9921,13 @@ __metadata: languageName: node linkType: hard +"import-from@npm:4.0.0": + version: 4.0.0 + resolution: "import-from@npm:4.0.0" + checksum: 10c0/7fd98650d555e418c18341fef49ae11afc833f5ae70b7043e99684187cba6ac6b52e4118a491bd9f856045495bef5bdda7321095e65bcb2ef70ce2adf9f0d8d1 + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -8190,6 +10059,29 @@ __metadata: languageName: node linkType: hard +"inquirer@npm:^8.0.0": + version: 8.2.6 + resolution: "inquirer@npm:8.2.6" + dependencies: + ansi-escapes: "npm:^4.2.1" + chalk: "npm:^4.1.1" + cli-cursor: "npm:^3.1.0" + cli-width: "npm:^3.0.0" + external-editor: "npm:^3.0.3" + figures: "npm:^3.0.0" + lodash: "npm:^4.17.21" + mute-stream: "npm:0.0.8" + ora: "npm:^5.4.1" + run-async: "npm:^2.4.0" + rxjs: "npm:^7.5.5" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + through: "npm:^2.3.6" + wrap-ansi: "npm:^6.0.1" + checksum: 10c0/eb5724de1778265323f3a68c80acfa899378cb43c24cdcb58661386500e5696b6b0b6c700e046b7aa767fe7b4823c6f04e6ddc268173e3f84116112529016296 + languageName: node + linkType: hard + "int64-buffer@npm:1.0.1": version: 1.0.1 resolution: "int64-buffer@npm:1.0.1" @@ -8257,6 +10149,15 @@ __metadata: languageName: node linkType: hard +"invariant@npm:^2.2.4": + version: 2.2.4 + resolution: "invariant@npm:2.2.4" + dependencies: + loose-envify: "npm:^1.0.0" + checksum: 10c0/5af133a917c0bcf65e84e7f23e779e7abc1cd49cb7fdc62d00d1de74b0d8c1b5ee74ac7766099fb3be1b05b26dfc67bab76a17030d2fe7ea2eef867434362dfc + languageName: node + linkType: hard + "ip-address@npm:^9.0.5": version: 9.0.5 resolution: "ip-address@npm:9.0.5" @@ -8395,6 +10296,16 @@ __metadata: languageName: node linkType: hard +"is-absolute@npm:^1.0.0": + version: 1.0.0 + resolution: "is-absolute@npm:1.0.0" + dependencies: + is-relative: "npm:^1.0.0" + is-windows: "npm:^1.0.1" + checksum: 10c0/422302ce879d4f3ca6848499b6f3ddcc8fd2dc9f3e9cad3f6bcedff58cdfbbbd7f4c28600fffa7c59a858f1b15c27fb6cfe1d5275e58a36d2bf098a44ef5abc4 + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" @@ -8538,7 +10449,7 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": +"is-glob@npm:4.0.3, is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: @@ -8588,6 +10499,15 @@ __metadata: languageName: node linkType: hard +"is-lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "is-lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/c045e6a52dcc7c3857e2f8c850ded604cdc5269ff94625b03881cefc73bfc02f5099a1bc9bafa67793656711a40d4ab3e26e285a848e728506df20ead0ce8e2f + languageName: node + linkType: hard + "is-negative-zero@npm:^2.0.3": version: 2.0.3 resolution: "is-negative-zero@npm:2.0.3" @@ -8663,6 +10583,15 @@ __metadata: languageName: node linkType: hard +"is-relative@npm:^1.0.0": + version: 1.0.0 + resolution: "is-relative@npm:1.0.0" + dependencies: + is-unc-path: "npm:^1.0.0" + checksum: 10c0/61157c4be8594dd25ac6f0ef29b1218c36667259ea26698367a4d9f39ff9018368bc365c490b3c79be92dfb1e389e43c4b865c95709e7b3bc72c5932f751fb60 + languageName: node + linkType: hard + "is-retry-allowed@npm:^1.1.0": version: 1.2.0 resolution: "is-retry-allowed@npm:1.2.0" @@ -8713,6 +10642,15 @@ __metadata: languageName: node linkType: hard +"is-unc-path@npm:^1.0.0": + version: 1.0.0 + resolution: "is-unc-path@npm:1.0.0" + dependencies: + unc-path-regex: "npm:^0.1.2" + checksum: 10c0/ac1b78f9b748196e3be3d0e722cd4b0f98639247a130a8f2473a58b29baf63fdb1b1c5a12c830660c5ee6ef0279c5418ca8e346f98cbe1a29e433d7ae531d42e + languageName: node + linkType: hard + "is-unicode-supported@npm:^0.1.0": version: 0.1.0 resolution: "is-unicode-supported@npm:0.1.0" @@ -8720,6 +10658,15 @@ __metadata: languageName: node linkType: hard +"is-upper-case@npm:^2.0.2": + version: 2.0.2 + resolution: "is-upper-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/2236f416484a2643d55a07cc95443cecf96cbc5fb0de7f24c506a8bc5cc4c4de885ab56c5ec946eadd95b3b7960bff7ed51cc88511fa8e8a9d92f2f8969622d9 + languageName: node + linkType: hard + "is-url-superb@npm:^4.0.0": version: 4.0.0 resolution: "is-url-superb@npm:4.0.0" @@ -8743,6 +10690,13 @@ __metadata: languageName: node linkType: hard +"is-windows@npm:^1.0.1": + version: 1.0.2 + resolution: "is-windows@npm:1.0.2" + checksum: 10c0/b32f418ab3385604a66f1b7a3ce39d25e8881dee0bd30816dc8344ef6ff9df473a732bcc1ec4e84fe99b2f229ae474f7133e8e93f9241686cfcf7eebe53ba7a5 + languageName: node + linkType: hard + "is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" @@ -8796,6 +10750,15 @@ __metadata: languageName: node linkType: hard +"isomorphic-ws@npm:^5.0.0": + version: 5.0.0 + resolution: "isomorphic-ws@npm:5.0.0" + peerDependencies: + ws: "*" + checksum: 10c0/a058ac8b5e6efe9e46252cb0bc67fd325005d7216451d1a51238bc62d7da8486f828ef017df54ddf742e0fffcbe4b1bcc2a66cc115b027ed0180334cd18df252 + languageName: node + linkType: hard + "it-all@npm:^1.0.4": version: 1.0.6 resolution: "it-all@npm:1.0.6" @@ -9126,6 +11089,31 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^1.17.1": + version: 1.21.6 + resolution: "jiti@npm:1.21.6" + bin: + jiti: bin/jiti.js + checksum: 10c0/05b9ed58cd30d0c3ccd3c98209339e74f50abd9a17e716f65db46b6a35812103f6bde6e134be7124d01745586bca8cc5dae1d0d952267c3ebe55171949c32e56 + languageName: node + linkType: hard + +"jiti@npm:^2.0.0": + version: 2.4.0 + resolution: "jiti@npm:2.4.0" + bin: + jiti: lib/jiti-cli.mjs + checksum: 10c0/f97365a83169e0544b0a6e7f415f1ee69ca9c0bdd55e336035490b4b7a6ff99b63b9df89c70babfc49e924247dfbdc730f9eb0c5ed4771d3db989ac70e49bf18 + languageName: node + linkType: hard + +"jose@npm:^5.0.0": + version: 5.9.6 + resolution: "jose@npm:5.9.6" + checksum: 10c0/d6bcd8c7d655b5cda8e182952a76f0c093347f5476d74795405bb91563f7ab676f61540310dd4b1531c60d685335ceb600571a409551d2cbd2ab3e9f9fbf1e4d + languageName: node + linkType: hard + "js-base64@npm:3.7.5": version: 3.7.5 resolution: "js-base64@npm:3.7.5" @@ -9140,7 +11128,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^4.1.0": +"js-yaml@npm:^4.0.0, js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" dependencies: @@ -9158,6 +11146,15 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.0.2 + resolution: "jsesc@npm:3.0.2" + bin: + jsesc: bin/jsesc + checksum: 10c0/ef22148f9e793180b14d8a145ee6f9f60f301abf443288117b4b6c53d0ecd58354898dc506ccbb553a5f7827965cd38bc5fb726575aae93c5e8915e2de8290e1 + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -9221,6 +11218,16 @@ __metadata: languageName: node linkType: hard +"json-to-pretty-yaml@npm:^1.2.2": + version: 1.2.2 + resolution: "json-to-pretty-yaml@npm:1.2.2" + dependencies: + remedial: "npm:^1.0.7" + remove-trailing-spaces: "npm:^1.0.6" + checksum: 10c0/d28891860a7ae034873ac8ec5f69f5493106afed9a86295f1642a40b27a48df717c63966439a1dec5b8a4b30e99b86cd1b4ca7d979bb8048ffd7f7c67bfd88a3 + languageName: node + linkType: hard + "json5@npm:^1.0.2": version: 1.0.2 resolution: "json5@npm:1.0.2" @@ -9232,7 +11239,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.3, json5@npm:^2.2.2": +"json5@npm:^2.1.3, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -9481,6 +11488,36 @@ __metadata: languageName: node linkType: hard +"listr2@npm:^4.0.5": + version: 4.0.5 + resolution: "listr2@npm:4.0.5" + dependencies: + cli-truncate: "npm:^2.1.0" + colorette: "npm:^2.0.16" + log-update: "npm:^4.0.0" + p-map: "npm:^4.0.0" + rfdc: "npm:^1.3.0" + rxjs: "npm:^7.5.5" + through: "npm:^2.3.8" + wrap-ansi: "npm:^7.0.0" + peerDependencies: + enquirer: ">= 2.3.0 < 3" + peerDependenciesMeta: + enquirer: + optional: true + checksum: 10c0/0e64dc5e66fbd4361f6b35c49489ed842a1d7de30cf2b5c06bf4569669449288698b8ea93f7842aaf3c510963a1e554bca31376b9054d1521445d1ce4c917ea1 + languageName: node + linkType: hard + +"locate-path@npm:^5.0.0": + version: 5.0.0 + resolution: "locate-path@npm:5.0.0" + dependencies: + p-locate: "npm:^4.1.0" + checksum: 10c0/33a1c5247e87e022f9713e6213a744557a3e9ec32c5d0b5efb10aa3a38177615bf90221a5592674857039c1a0fd2063b82f285702d37b792d973e9e72ace6c59 + languageName: node + linkType: hard + "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" @@ -9504,14 +11541,21 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.21": +"lodash.sortby@npm:^4.7.0": + version: 4.7.0 + resolution: "lodash.sortby@npm:4.7.0" + checksum: 10c0/fc48fb54ff7669f33bb32997cab9460757ee99fafaf72400b261c3e10fde21538e47d8cfcbe6a25a31bcb5b7b727c27d52626386fc2de24eb059a6d64a89cdf5 + languageName: node + linkType: hard + +"lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:~4.17.0": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c languageName: node linkType: hard -"log-symbols@npm:^4.1.0": +"log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" dependencies: @@ -9521,6 +11565,18 @@ __metadata: languageName: node linkType: hard +"log-update@npm:^4.0.0": + version: 4.0.0 + resolution: "log-update@npm:4.0.0" + dependencies: + ansi-escapes: "npm:^4.3.0" + cli-cursor: "npm:^3.1.0" + slice-ansi: "npm:^4.0.0" + wrap-ansi: "npm:^6.2.0" + checksum: 10c0/18b299e230432a156f2535660776406d15ba8bb7817dd3eaadd58004b363756d4ecaabcd658f9949f90b62ea7d3354423be3fdeb7a201ab951ec0e8d6139af86 + languageName: node + linkType: hard + "lokijs@npm:1.5.12": version: 1.5.12 resolution: "lokijs@npm:1.5.12" @@ -9535,7 +11591,7 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.1.0": +"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" dependencies: @@ -9553,6 +11609,15 @@ __metadata: languageName: node linkType: hard +"lower-case-first@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case-first@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/22253389fa0693ec1ba09b9394be3a8228304bf21d074703db2eef97c16cda9c66462d88f9b91d4ad0186493d23cad99c63d38ebc13f9a808bc83aad539ff404 + languageName: node + linkType: hard + "lower-case@npm:^2.0.2": version: 2.0.2 resolution: "lower-case@npm:2.0.2" @@ -9576,6 +11641,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + "lru-cache@npm:^7.14.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" @@ -9658,6 +11732,13 @@ __metadata: languageName: node linkType: hard +"map-cache@npm:^0.2.0": + version: 0.2.2 + resolution: "map-cache@npm:0.2.2" + checksum: 10c0/05e3eb005c1b80b9f949ca007687640e8c5d0fc88dc45c3c3ab4902a3bec79d66a58f3e3b04d6985d90cd267c629c7b46c977e9c34433e8c11ecfcbb9f0fa290 + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -9698,6 +11779,18 @@ __metadata: languageName: node linkType: hard +"meros@npm:^1.2.1": + version: 1.3.0 + resolution: "meros@npm:1.3.0" + peerDependencies: + "@types/node": ">=13" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10c0/2cf9a31228ae6441428a750b67beafec062cc0d693942045336dbe6bfb44507e0ca42854a46f483ebd97e4d78cbc31322b3b85f9648b60fa7a4b28fc0f858f51 + languageName: node + linkType: hard + "methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" @@ -9715,6 +11808,16 @@ __metadata: languageName: node linkType: hard +"micromatch@npm:^4.0.5, micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -10086,6 +12189,13 @@ __metadata: languageName: node linkType: hard +"mute-stream@npm:0.0.8": + version: 0.0.8 + resolution: "mute-stream@npm:0.0.8" + checksum: 10c0/18d06d92e5d6d45e2b63c0e1b8f25376af71748ac36f53c059baa8b76ffac31c5ab225480494e7d35d30215ecdb18fed26ec23cafcd2f7733f2f14406bcd19e2 + languageName: node + linkType: hard + "mute-stream@npm:1.0.0, mute-stream@npm:^1.0.0": version: 1.0.0 resolution: "mute-stream@npm:1.0.0" @@ -10174,7 +12284,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.8": +"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.8": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -10235,6 +12345,20 @@ __metadata: languageName: node linkType: hard +"node-int64@npm:^0.4.0": + version: 0.4.0 + resolution: "node-int64@npm:0.4.0" + checksum: 10c0/a6a4d8369e2f2720e9c645255ffde909c0fbd41c92ea92a5607fc17055955daac99c1ff589d421eee12a0d24e99f7bfc2aabfeb1a4c14742f6c099a51863f31a + languageName: node + linkType: hard + +"node-releases@npm:^2.0.18": + version: 2.0.18 + resolution: "node-releases@npm:2.0.18" + checksum: 10c0/786ac9db9d7226339e1dc84bbb42007cb054a346bd9257e6aa154d294f01bc6a6cddb1348fa099f079be6580acbb470e3c048effd5f719325abd0179e566fd27 + languageName: node + linkType: hard + "node-source-walk@npm:^7.0.0": version: 7.0.0 resolution: "node-source-walk@npm:7.0.0" @@ -10309,6 +12433,15 @@ __metadata: languageName: node linkType: hard +"normalize-path@npm:^2.1.1": + version: 2.1.1 + resolution: "normalize-path@npm:2.1.1" + dependencies: + remove-trailing-separator: "npm:^1.0.1" + checksum: 10c0/db814326ff88057437233361b4c7e9cac7b54815b051b57f2d341ce89b1d8ec8cbd43e7fa95d7652b3b69ea8fcc294b89b8530d556a84d1bdace94229e1e9a8b + languageName: node + linkType: hard + "normalize-url@npm:^8.0.0": version: 8.0.1 resolution: "normalize-url@npm:8.0.1" @@ -10577,6 +12710,20 @@ __metadata: languageName: node linkType: hard +"nullthrows@npm:^1.1.1": + version: 1.1.1 + resolution: "nullthrows@npm:1.1.1" + checksum: 10c0/56f34bd7c3dcb3bd23481a277fa22918120459d3e9d95ca72976c72e9cac33a97483f0b95fc420e2eb546b9fe6db398273aba9a938650cdb8c98ee8f159dcb30 + languageName: node + linkType: hard + +"object-assign@npm:^4.1.0": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + languageName: node + linkType: hard + "object-hash@npm:^3.0.0": version: 3.0.0 resolution: "object-hash@npm:3.0.0" @@ -10879,7 +13026,7 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^3.0.2": +"p-limit@npm:3.1.0, p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: @@ -10888,6 +13035,24 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^2.2.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: "npm:^2.0.0" + checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 + languageName: node + linkType: hard + +"p-locate@npm:^4.1.0": + version: 4.1.0 + resolution: "p-locate@npm:4.1.0" + dependencies: + p-limit: "npm:^2.2.0" + checksum: 10c0/1b476ad69ad7f6059744f343b26d51ce091508935c1dbb80c4e0a2f397ffce0ca3a1f9f5cd3c7ce19d7929a09719d5c65fe70d8ee289c3f267cd36f2881813e9 + languageName: node + linkType: hard + "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" @@ -10930,6 +13095,13 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f + languageName: node + linkType: hard + "pac-proxy-agent@npm:^7.0.1": version: 7.0.2 resolution: "pac-proxy-agent@npm:7.0.2" @@ -11083,6 +13255,17 @@ __metadata: languageName: node linkType: hard +"parse-filepath@npm:^1.0.2": + version: 1.0.2 + resolution: "parse-filepath@npm:1.0.2" + dependencies: + is-absolute: "npm:^1.0.0" + map-cache: "npm:^0.2.0" + path-root: "npm:^0.1.1" + checksum: 10c0/37bbd225fa864257246777efbdf72a9305c4ae12110bf467d11994e93f8be60dd309dcef68124a2c78c5d3b4e64e1c36fcc2560e2ea93fd97767831e7a446805 + languageName: node + linkType: hard + "parse-json@npm:^4.0.0": version: 4.0.0 resolution: "parse-json@npm:4.0.0" @@ -11181,6 +13364,22 @@ __metadata: languageName: node linkType: hard +"path-root-regex@npm:^0.1.0": + version: 0.1.2 + resolution: "path-root-regex@npm:0.1.2" + checksum: 10c0/27651a234f280c70d982dd25c35550f74a4284cde6b97237aab618cb4b5745682d18cdde1160617bb4a4b6b8aec4fbc911c4a2ad80d01fa4c7ee74dae7af2337 + languageName: node + linkType: hard + +"path-root@npm:^0.1.1": + version: 0.1.1 + resolution: "path-root@npm:0.1.1" + dependencies: + path-root-regex: "npm:^0.1.0" + checksum: 10c0/aed5cd290df84c46c7730f6a363e95e47a23929b51ab068a3818d69900da3e89dc154cdfd0c45c57b2e02f40c094351bc862db70c2cb00b7e6bd47039a227813 + languageName: node + linkType: hard + "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" @@ -11449,6 +13648,15 @@ __metadata: languageName: node linkType: hard +"promise@npm:^7.1.1": + version: 7.3.1 + resolution: "promise@npm:7.3.1" + dependencies: + asap: "npm:~2.0.3" + checksum: 10c0/742e5c0cc646af1f0746963b8776299701ad561ce2c70b49365d62c8db8ea3681b0a1bf0d4e2fe07910bf72f02d39e51e8e73dc8d7503c3501206ac908be107f + languageName: node + linkType: hard + "promzard@npm:^2.0.0": version: 2.0.0 resolution: "promzard@npm:2.0.0" @@ -11788,6 +13996,13 @@ __metadata: languageName: node linkType: hard +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" @@ -11827,6 +14042,45 @@ __metadata: languageName: node linkType: hard +"relay-runtime@npm:12.0.0": + version: 12.0.0 + resolution: "relay-runtime@npm:12.0.0" + dependencies: + "@babel/runtime": "npm:^7.0.0" + fbjs: "npm:^3.0.0" + invariant: "npm:^2.2.4" + checksum: 10c0/f5d29b5c2f3c8a3438d43dcbc3022bd454c4ecbd4f0b10616df08bedc62d8aaa84f155f23e374053cf9f4a8238b93804e37a5b37ed9dc7ad01436d62d1b01d53 + languageName: node + linkType: hard + +"remedial@npm:^1.0.7": + version: 1.0.8 + resolution: "remedial@npm:1.0.8" + checksum: 10c0/ca1e22d2958e3f0f2fdb5f1c23fecadab5d83a0b1e291c67474c806ce07801212f1d2006995bdcfb592803ead7666e2b1fbb9281b3f32d4a87ff2335b3777725 + languageName: node + linkType: hard + +"remove-trailing-separator@npm:^1.0.1": + version: 1.1.0 + resolution: "remove-trailing-separator@npm:1.1.0" + checksum: 10c0/3568f9f8f5af3737b4aee9e6e1e8ec4be65a92da9cb27f989e0893714d50aa95ed2ff02d40d1fa35e1b1a234dc9c2437050ef356704a3999feaca6667d9e9bfc + languageName: node + linkType: hard + +"remove-trailing-spaces@npm:^1.0.6": + version: 1.0.8 + resolution: "remove-trailing-spaces@npm:1.0.8" + checksum: 10c0/b9a4d74fd77e4a81b83cd19152abe1d658e5ecf13bc9b789c2699d7166d3879258a61625f8fc0274ef5719ab70e514ae86234fee481f6b41b50729949b837c1b + languageName: node + linkType: hard + +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 + languageName: node + linkType: hard + "require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" @@ -11834,6 +14088,13 @@ __metadata: languageName: node linkType: hard +"require-main-filename@npm:^2.0.0": + version: 2.0.0 + resolution: "require-main-filename@npm:2.0.0" + checksum: 10c0/db91467d9ead311b4111cbd73a4e67fa7820daed2989a32f7023785a2659008c6d119752d9c4ac011ae07e537eb86523adff99804c5fdb39cd3a017f9b401bb6 + languageName: node + linkType: hard + "requireindex@npm:^1.2.0": version: 1.2.0 resolution: "requireindex@npm:1.2.0" @@ -11875,6 +14136,13 @@ __metadata: languageName: node linkType: hard +"resolve-from@npm:5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 + languageName: node + linkType: hard + "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -11972,6 +14240,13 @@ __metadata: languageName: node linkType: hard +"rfdc@npm:^1.3.0": + version: 1.4.1 + resolution: "rfdc@npm:1.4.1" + checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7 + languageName: node + linkType: hard + "rimraf@npm:^5.0.5": version: 5.0.7 resolution: "rimraf@npm:5.0.7" @@ -12046,6 +14321,13 @@ __metadata: languageName: node linkType: hard +"run-async@npm:^2.4.0": + version: 2.4.1 + resolution: "run-async@npm:2.4.1" + checksum: 10c0/35a68c8f1d9664f6c7c2e153877ca1d6e4f886e5ca067c25cdd895a6891ff3a1466ee07c63d6a9be306e9619ff7d509494e6d9c129516a36b9fd82263d579ee1 + languageName: node + linkType: hard + "run-async@npm:^3.0.0": version: 3.0.0 resolution: "run-async@npm:3.0.0" @@ -12071,7 +14353,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.2.0, rxjs@npm:^7.8.1": +"rxjs@npm:^7.2.0, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" dependencies: @@ -12137,6 +14419,13 @@ __metadata: languageName: node linkType: hard +"scuid@npm:^1.1.0": + version: 1.1.0 + resolution: "scuid@npm:1.1.0" + checksum: 10c0/01c6bd2657ceaa148ead0c836df6251f561166142059261022a38dba429b30141e27ab3c0eca1012b88912f51a9e848e475fe1b6259ef1c61a0a7f6eb54fb261 + languageName: node + linkType: hard + "semver@npm:7.6.3, semver@npm:^7.6.3": version: 7.6.3 resolution: "semver@npm:7.6.3" @@ -12208,6 +14497,13 @@ __metadata: languageName: node linkType: hard +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 + languageName: node + linkType: hard + "set-function-length@npm:^1.2.1": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" @@ -12234,6 +14530,13 @@ __metadata: languageName: node linkType: hard +"setimmediate@npm:^1.0.5": + version: 1.0.5 + resolution: "setimmediate@npm:1.0.5" + checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 + languageName: node + linkType: hard + "setprototypeof@npm:1.2.0": version: 1.2.0 resolution: "setprototypeof@npm:1.2.0" @@ -12257,6 +14560,13 @@ __metadata: languageName: node linkType: hard +"shell-quote@npm:^1.7.3": + version: 1.8.1 + resolution: "shell-quote@npm:1.8.1" + checksum: 10c0/8cec6fd827bad74d0a49347057d40dfea1e01f12a6123bf82c4649f3ef152fc2bc6d6176e6376bffcd205d9d0ccb4f1f9acae889384d20baff92186f01ea455a + languageName: node + linkType: hard + "shelljs@npm:^0.8.5": version: 0.8.5 resolution: "shelljs@npm:0.8.5" @@ -12315,6 +14625,13 @@ __metadata: languageName: node linkType: hard +"signedsource@npm:^1.0.0": + version: 1.0.0 + resolution: "signedsource@npm:1.0.0" + checksum: 10c0/dbb4ade9c94888e83c16d23ef1a43195799de091d366d130be286415e8aeb97b3f25b14fd26fc5888e1335d703ad561374fddee32e43b7cea04751b93d178a47 + languageName: node + linkType: hard + "sigstore@npm:^2.2.0": version: 2.3.1 resolution: "sigstore@npm:2.3.1" @@ -12382,6 +14699,28 @@ __metadata: languageName: node linkType: hard +"slice-ansi@npm:^3.0.0": + version: 3.0.0 + resolution: "slice-ansi@npm:3.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + astral-regex: "npm:^2.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + checksum: 10c0/88083c9d0ca67d09f8b4c78f68833d69cabbb7236b74df5d741ad572bbf022deaf243fa54009cd434350622a1174ab267710fcc80a214ecc7689797fe00cb27c + languageName: node + linkType: hard + +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + astral-regex: "npm:^2.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + checksum: 10c0/6c25678db1270d4793e0327620f1e0f9f5bea4630123f51e9e399191bc52c87d6e6de53ed33538609e5eacbd1fab769fae00f3705d08d029f02102a540648918 + languageName: node + linkType: hard + "slice-ansi@npm:^5.0.0": version: 5.0.0 resolution: "slice-ansi@npm:5.0.0" @@ -12541,6 +14880,15 @@ __metadata: languageName: node linkType: hard +"sponge-case@npm:^1.0.1": + version: 1.0.1 + resolution: "sponge-case@npm:1.0.1" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/dbe42f300ae9f7fbd83c40f71c2a61ecf9c86b927b5668bae067d1e516e314671cc85166f87017e51b56938409b1fc042719eb46a6d5bb30cc1cf23252a82761 + languageName: node + linkType: hard + "sprintf-js@npm:^1.1.3": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -12624,6 +14972,13 @@ __metadata: languageName: node linkType: hard +"streamsearch@npm:^1.1.0": + version: 1.1.0 + resolution: "streamsearch@npm:1.1.0" + checksum: 10c0/fbd9aecc2621364384d157f7e59426f4bfd385e8b424b5aaa79c83a6f5a1c8fd2e4e3289e95de1eb3511cb96bb333d6281a9919fafce760e4edb35b2cd2facab + languageName: node + linkType: hard + "strict-event-emitter@npm:^0.5.1": version: 0.5.1 resolution: "strict-event-emitter@npm:0.5.1" @@ -12631,7 +14986,14 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.3": +"string-env-interpolation@npm:^1.0.1": + version: 1.0.1 + resolution: "string-env-interpolation@npm:1.0.1" + checksum: 10c0/410046e621e71678e71816377d799b40ba88d236708c0ad015114137fa3575f1b3cf14bfd63ec5eaa35ea43ac582308e60a8e1a3839a10f475b8db73470105bc + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -12816,6 +15178,15 @@ __metadata: languageName: node linkType: hard +"swap-case@npm:^2.0.2": + version: 2.0.2 + resolution: "swap-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/6a47c1926e06395ead750905e103be388aeec8c9697f20b14bc3e1e86fcb4fc78e5033197afe6cc8bbed80f0a4ee1f184b0fa22eec7f4a767bdfd278683d52eb + languageName: node + linkType: hard + "tapable@npm:^2.2.0": version: 2.2.1 resolution: "tapable@npm:2.2.1" @@ -12883,6 +15254,13 @@ __metadata: languageName: node linkType: hard +"through@npm:^2.3.6, through@npm:^2.3.8": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc + languageName: node + linkType: hard + "timeout-abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "timeout-abort-controller@npm:3.0.0" @@ -12950,6 +15328,15 @@ __metadata: languageName: node linkType: hard +"title-case@npm:^3.0.3": + version: 3.0.3 + resolution: "title-case@npm:3.0.3" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/face56f686060f777b43a180d371407124d201eb4238c19d9e97030fd54859696ca4e2ca499cc232f8700f24f2414cc08aab9fdf6d39acff055dd825a4d86d6a + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -13026,6 +15413,13 @@ __metadata: languageName: node linkType: hard +"ts-log@npm:^2.2.3": + version: 2.2.7 + resolution: "ts-log@npm:2.2.7" + checksum: 10c0/2c63a7ccdea6dad774f51ba031d9b8d7242833733a1122e20be7e2817556f8e5691bd589860940068073c3859f8cdd8b99e2f65934b95a3552e97a60066ea7f3 + languageName: node + linkType: hard + "ts-morph@npm:^13.0.1": version: 13.0.3 resolution: "ts-morph@npm:13.0.3" @@ -13113,13 +15507,27 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1": +"tslib@npm:^2, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1, tslib@npm:~2.6.0": version: 2.6.3 resolution: "tslib@npm:2.6.3" checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a languageName: node linkType: hard +"tslib@npm:^2.6.3": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + +"tslib@npm:~2.4.0": + version: 2.4.1 + resolution: "tslib@npm:2.4.1" + checksum: 10c0/9ac0e4fd1033861f0b4f0d848dc3009ebcc3aa4757a06e8602a2d8a7aed252810e3540e54e70709f06c0f95311faa8584f769bcbede48aff785eb7e4d399b9ec + languageName: node + linkType: hard + "tsx@npm:4.19.1": version: 4.19.1 resolution: "tsx@npm:4.19.1" @@ -13313,6 +15721,15 @@ __metadata: languageName: node linkType: hard +"ua-parser-js@npm:^1.0.35": + version: 1.0.39 + resolution: "ua-parser-js@npm:1.0.39" + bin: + ua-parser-js: script/cli.js + checksum: 10c0/c6452b0c683000f10975cb0a7e74cb1119ea95d4522ae85f396fa53b0b17884358a24ffdd86a66030c6b2981bdc502109a618c79fdaa217ee9032c9e46fcc78a + languageName: node + linkType: hard + "uint8-varint@npm:^2.0.1, uint8-varint@npm:^2.0.2, uint8-varint@npm:^2.0.4": version: 2.0.4 resolution: "uint8-varint@npm:2.0.4" @@ -13380,6 +15797,13 @@ __metadata: languageName: node linkType: hard +"unc-path-regex@npm:^0.1.2": + version: 0.1.2 + resolution: "unc-path-regex@npm:0.1.2" + checksum: 10c0/bf9c781c4e2f38e6613ea17a51072e4b416840fbe6eeb244597ce9b028fac2fb6cfd3dde1f14111b02c245e665dc461aab8168ecc30b14364d02caa37f812996 + languageName: node + linkType: hard + "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" @@ -13460,6 +15884,15 @@ __metadata: languageName: node linkType: hard +"unixify@npm:^1.0.0": + version: 1.0.0 + resolution: "unixify@npm:1.0.0" + dependencies: + normalize-path: "npm:^2.1.1" + checksum: 10c0/8b89100619ebde9f0ab4024a4d402316fb7b1d4853723410fc828944e8d3d01480f210cddf94d9a1699559f8180d861eb6323da8011b7bcc1bbaf6a11a5b1f1e + languageName: node + linkType: hard + "unpipe@npm:1.0.0, unpipe@npm:~1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0" @@ -13467,6 +15900,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.1": + version: 1.1.1 + resolution: "update-browserslist-db@npm:1.1.1" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.0" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/536a2979adda2b4be81b07e311bd2f3ad5e978690987956bc5f514130ad50cac87cd22c710b686d79731e00fbee8ef43efe5fcd72baa241045209195d43dcc80 + languageName: node + linkType: hard + "upper-case-first@npm:^2.0.2": version: 2.0.2 resolution: "upper-case-first@npm:2.0.2" @@ -13494,6 +15941,13 @@ __metadata: languageName: node linkType: hard +"urlpattern-polyfill@npm:^10.0.0": + version: 10.0.0 + resolution: "urlpattern-polyfill@npm:10.0.0" + checksum: 10c0/43593f2a89bd54f2d5b5105ef4896ac5c5db66aef723759fbd15cd5eb1ea6cdae9d112e257eda9bbc3fb0cd90be6ac6e9689abe4ca69caa33114f42a27363531 + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -13550,6 +16004,13 @@ __metadata: languageName: node linkType: hard +"value-or-promise@npm:^1.0.11, value-or-promise@npm:^1.0.12": + version: 1.0.12 + resolution: "value-or-promise@npm:1.0.12" + checksum: 10c0/b75657b74e4d17552bd88e0c2857020fbab34a4d091dc058db18c470e7da0336067e72c130b3358e3321ac0a6ff11c0b92b67a382318a3705ad5d57de7ff3262 + languageName: node + linkType: hard + "varint@npm:^6.0.0": version: 6.0.0 resolution: "varint@npm:6.0.0" @@ -13729,6 +16190,13 @@ __metadata: languageName: node linkType: hard +"which-module@npm:^2.0.0": + version: 2.0.1 + resolution: "which-module@npm:2.0.1" + checksum: 10c0/087038e7992649eaffa6c7a4f3158d5b53b14cf5b6c1f0e043dccfacb1ba179d12f17545d5b85ebd94a42ce280a6fe65d0cbcab70f4fc6daad1dfae85e0e6a3e + languageName: node + linkType: hard + "which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" @@ -13830,7 +16298,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^6.2.0": +"wrap-ansi@npm:^6.0.1, wrap-ansi@npm:^6.2.0": version: 6.2.0 resolution: "wrap-ansi@npm:6.2.0" dependencies: @@ -13920,7 +16388,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.15.0": +"ws@npm:^8.15.0, ws@npm:^8.17.1": version: 8.18.0 resolution: "ws@npm:8.18.0" peerDependencies: @@ -13942,6 +16410,27 @@ __metadata: languageName: node linkType: hard +"y18n@npm:^4.0.0": + version: 4.0.3 + resolution: "y18n@npm:4.0.3" + checksum: 10c0/308a2efd7cc296ab2c0f3b9284fd4827be01cfeb647b3ba18230e3a416eb1bc887ac050de9f8c4fd9e7856b2e8246e05d190b53c96c5ad8d8cb56dffb6f81024 + languageName: node + linkType: hard + +"y18n@npm:^5.0.5": + version: 5.0.8 + resolution: "y18n@npm:5.0.8" + checksum: 10c0/4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -13956,6 +16445,13 @@ __metadata: languageName: node linkType: hard +"yaml-ast-parser@npm:^0.0.43": + version: 0.0.43 + resolution: "yaml-ast-parser@npm:0.0.43" + checksum: 10c0/4d2f1e761067b2c6abdd882279a406f879258787af470a6d4a659cb79cb2ab056b870b25f1f80f46ed556e8b499d611d247806376f53edf3412f72c0a8ea2e98 + languageName: node + linkType: hard + "yaml-diff-patch@npm:2.0.0": version: 2.0.0 resolution: "yaml-diff-patch@npm:2.0.0" @@ -13971,7 +16467,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:2.6.0": +"yaml@npm:2.6.0, yaml@npm:^2.3.1": version: 2.6.0 resolution: "yaml@npm:2.6.0" bin: @@ -13996,6 +16492,57 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^18.1.2": + version: 18.1.3 + resolution: "yargs-parser@npm:18.1.3" + dependencies: + camelcase: "npm:^5.0.0" + decamelize: "npm:^1.2.0" + checksum: 10c0/25df918833592a83f52e7e4f91ba7d7bfaa2b891ebf7fe901923c2ee797534f23a176913ff6ff7ebbc1cc1725a044cc6a6539fed8bfd4e13b5b16376875f9499 + languageName: node + linkType: hard + +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 + languageName: node + linkType: hard + +"yargs@npm:^15.3.1": + version: 15.4.1 + resolution: "yargs@npm:15.4.1" + dependencies: + cliui: "npm:^6.0.0" + decamelize: "npm:^1.2.0" + find-up: "npm:^4.1.0" + get-caller-file: "npm:^2.0.1" + require-directory: "npm:^2.1.1" + require-main-filename: "npm:^2.0.0" + set-blocking: "npm:^2.0.0" + string-width: "npm:^4.2.0" + which-module: "npm:^2.0.0" + y18n: "npm:^4.0.0" + yargs-parser: "npm:^18.1.2" + checksum: 10c0/f1ca680c974333a5822732825cca7e95306c5a1e7750eb7b973ce6dc4f97a6b0a8837203c8b194f461969bfe1fb1176d1d423036635285f6010b392fa498ab2d + languageName: node + linkType: hard + +"yargs@npm:^17.0.0": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 8e444d897..7f2e6c7e0 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -18,8 +18,6 @@ import "@total-typescript/ts-reset"; import type { TransactionRequest } from "ethers"; -export const CHAIN_RPC_PORT = "8545"; - export const DEFAULT_PUBLIC_FLUENCE_ENV = "testnet"; export const PUBLIC_FLUENCE_ENV = [ DEFAULT_PUBLIC_FLUENCE_ENV, diff --git a/turbo.json b/turbo.json index fc743d34d..d8f2d70b9 100644 --- a/turbo.json +++ b/turbo.json @@ -16,6 +16,26 @@ ], "outputs": ["package/src/cli-aqua-dependencies/node_modules/**"] }, + "gen-gql-schema": { + "dependsOn": ["install-yarn-dependencies"], + "inputs": [ + "package/src/lib/configs/project/chainContainers.ts", + "package/src/genGqlSchema.ts", + "package/src/versions.ts", + "package/src/versions.json", + "package/src/lib/helpers/setTryTimeout.ts", + "package/src/lib/setupEnvironment.ts" + ], + "outputs": ["package/src/lib/gql/gqlSchema.json"] + }, + "gql-codegen": { + "dependsOn": ["gen-gql-schema"], + "inputs": [ + "package/src/lib/gql/gqlCodegen.ts", + "package/src/lib/gql/schema.graphql" + ], + "outputs": ["package/src/lib/gql/gqlGenerated.ts"] + }, "before-build": { "dependsOn": [ "install-yarn-dependencies", @@ -36,7 +56,7 @@ ] }, "build": { - "dependsOn": ["^build", "before-build"], + "dependsOn": ["^build", "before-build", "gql-codegen"], "outputs": ["dist/**", "package/dist/**"] }, "on-each-commit": { From 616479fdee793ff0be961c50807222ad6c015e01 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:08:52 +0100 Subject: [PATCH 14/37] fix --- .../cli/package/src/commands/deal/logs.ts | 6 +- .../cli/package/src/commands/provider/gen.ts | 3 +- .../cli/package/src/commands/workers/logs.ts | 3 +- .../package/src/lib/chain/chainValidators.ts | 2 +- .../cli/package/src/lib/chain/commitment.ts | 7 +- .../cli/package/src/lib/chain/offer/offer.ts | 2 +- .../package/src/lib/compileAquaAndWatch.ts | 7 +- packages/cli/package/src/lib/deal.ts | 7 +- packages/cli/package/src/lib/dealClient.ts | 2 +- packages/cli/package/src/lib/deploy.ts | 2 +- .../cli/package/src/lib/helpers/jsToAqua.ts | 2 +- .../package/src/lib/helpers/setTryTimeout.ts | 2 +- .../src/lib/helpers/stringifyUnknown.ts | 70 +++++++++++++++++++ packages/cli/package/src/lib/helpers/utils.ts | 54 -------------- .../package/src/lib/helpers/validations.ts | 3 +- packages/cli/package/src/lib/jsClient.ts | 2 +- .../cli/package/src/lib/localServices/ipfs.ts | 2 +- packages/cli/package/src/lib/npm.ts | 3 +- packages/cli/package/src/lib/paths.ts | 2 +- packages/cli/package/src/lib/rust.ts | 2 +- packages/cli/package/tsconfig.json | 7 +- 21 files changed, 97 insertions(+), 93 deletions(-) create mode 100644 packages/cli/package/src/lib/helpers/stringifyUnknown.ts diff --git a/packages/cli/package/src/commands/deal/logs.ts b/packages/cli/package/src/commands/deal/logs.ts index e957a9916..d322f9d26 100644 --- a/packages/cli/package/src/commands/deal/logs.ts +++ b/packages/cli/package/src/commands/deal/logs.ts @@ -37,10 +37,8 @@ import { formatAquaLogsHeader, formatAquaLogs, } from "../../lib/helpers/formatAquaLogs.js"; -import { - LOGS_RESOLVE_SUBNET_ERROR_START, - stringifyUnknown, -} from "../../lib/helpers/utils.js"; +import { LOGS_RESOLVE_SUBNET_ERROR_START } from "../../lib/helpers/utils.js"; +import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; import { disconnectFluenceClient, initFluenceClient, diff --git a/packages/cli/package/src/commands/provider/gen.ts b/packages/cli/package/src/commands/provider/gen.ts index d259b1fce..0ba4c4e83 100644 --- a/packages/cli/package/src/commands/provider/gen.ts +++ b/packages/cli/package/src/commands/provider/gen.ts @@ -36,7 +36,8 @@ import { MAX_TOKEN_AMOUNT_KEYWORD, CLI_NAME, } from "../../lib/const.js"; -import { pathExists, stringifyUnknown } from "../../lib/helpers/utils.js"; +import { pathExists } from "../../lib/helpers/utils.js"; +import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; import { initCli } from "../../lib/lifeCycle.js"; import { getFluenceSecretsDir, diff --git a/packages/cli/package/src/commands/workers/logs.ts b/packages/cli/package/src/commands/workers/logs.ts index 3c04a698b..c714e84dc 100644 --- a/packages/cli/package/src/commands/workers/logs.ts +++ b/packages/cli/package/src/commands/workers/logs.ts @@ -32,7 +32,8 @@ import { type FluenceEnv, } from "../../lib/const.js"; import { formatAquaLogs } from "../../lib/helpers/formatAquaLogs.js"; -import { stringifyUnknown, commaSepStrToArr } from "../../lib/helpers/utils.js"; +import { commaSepStrToArr } from "../../lib/helpers/utils.js"; +import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; import { disconnectFluenceClient, initFluenceClient, diff --git a/packages/cli/package/src/lib/chain/chainValidators.ts b/packages/cli/package/src/lib/chain/chainValidators.ts index b727b1b6e..7e71cd3fb 100644 --- a/packages/cli/package/src/lib/chain/chainValidators.ts +++ b/packages/cli/package/src/lib/chain/chainValidators.ts @@ -22,7 +22,7 @@ import { versions } from "../../versions.js"; import { getReadonlyContracts } from "../dealClient.js"; import { ensureChainEnv } from "../ensureChainNetwork.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; -import { stringifyUnknown } from "../helpers/utils.js"; +import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import type { ValidationResult } from "../helpers/validations.js"; export async function getMinCCDuration(): Promise { diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 02d4e39ea..545ae9f31 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -45,11 +45,8 @@ import { } from "../dealClient.js"; import { bigintSecondsToDate } from "../helpers/bigintOps.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; -import { - splitErrorsAndResults, - stringifyUnknown, - commaSepStrToArr, -} from "../helpers/utils.js"; +import { splitErrorsAndResults, commaSepStrToArr } from "../helpers/utils.js"; +import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { input } from "../prompt.js"; import { resolveComputePeersByNames, diff --git a/packages/cli/package/src/lib/chain/offer/offer.ts b/packages/cli/package/src/lib/chain/offer/offer.ts index 64c248c42..fe30687ee 100644 --- a/packages/cli/package/src/lib/chain/offer/offer.ts +++ b/packages/cli/package/src/lib/chain/offer/offer.ts @@ -47,8 +47,8 @@ import { numToStr } from "../../helpers/typesafeStringify.js"; import { commaSepStrToArr, splitErrorsAndResults, - stringifyUnknown, } from "../../helpers/utils.js"; +import { stringifyUnknown } from "../../helpers/stringifyUnknown.js"; import { setTryTimeout } from "../../helpers/setTryTimeout.js"; import { checkboxes } from "../../prompt.js"; import { ensureFluenceEnv } from "../../resolveFluenceEnv.js"; diff --git a/packages/cli/package/src/lib/compileAquaAndWatch.ts b/packages/cli/package/src/lib/compileAquaAndWatch.ts index 77d216103..95dd31e04 100644 --- a/packages/cli/package/src/lib/compileAquaAndWatch.ts +++ b/packages/cli/package/src/lib/compileAquaAndWatch.ts @@ -33,11 +33,8 @@ import { } from "./configs/project/fluence.js"; import { COMPILE_AQUA_PROPERTY_NAME } from "./const.js"; import { getAquaImports } from "./helpers/aquaImports.js"; -import { - commaSepStrToArr, - splitErrorsAndResults, - stringifyUnknown, -} from "./helpers/utils.js"; +import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { projectRootDir } from "./paths.js"; import type { Required } from "./typeHelpers.js"; diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index 2b39dfbbd..d17235346 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -45,11 +45,8 @@ import { } from "./dealClient.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; import { bigintToStr } from "./helpers/typesafeStringify.js"; -import { - commaSepStrToArr, - splitErrorsAndResults, - stringifyUnknown, -} from "./helpers/utils.js"; +import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { setTryTimeout } from "./helpers/setTryTimeout.js"; import { checkboxes, input, list } from "./prompt.js"; import { ensureFluenceEnv } from "./resolveFluenceEnv.js"; diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index 152cc305a..7cd9a48c2 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -58,7 +58,7 @@ import { CLI_NAME_FULL, PRIV_KEY_FLAG_NAME } from "./const.js"; import { dbg } from "./dbg.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; import { setTryTimeout } from "./helpers/setTryTimeout.js"; -import { stringifyUnknown } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { createTransaction, getAddressFromConnector } from "./server.js"; let provider: Provider | undefined = undefined; diff --git a/packages/cli/package/src/lib/deploy.ts b/packages/cli/package/src/lib/deploy.ts index 20455d067..34fc3e2c1 100644 --- a/packages/cli/package/src/lib/deploy.ts +++ b/packages/cli/package/src/lib/deploy.ts @@ -51,7 +51,7 @@ import { createAndMatchDealsForPeerIds } from "./deal.js"; import { getReadonlyContracts } from "./dealClient.js"; import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; import { numToStr } from "./helpers/typesafeStringify.js"; -import { stringifyUnknown } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { disconnectFluenceClient } from "./jsClient.js"; import { initCli } from "./lifeCycle.js"; import { getIpfsClient } from "./localServices/ipfs.js"; diff --git a/packages/cli/package/src/lib/helpers/jsToAqua.ts b/packages/cli/package/src/lib/helpers/jsToAqua.ts index 212417cc8..dc274439d 100644 --- a/packages/cli/package/src/lib/helpers/jsToAqua.ts +++ b/packages/cli/package/src/lib/helpers/jsToAqua.ts @@ -31,7 +31,7 @@ import { input } from "../prompt.js"; import { validateAquaTypeName, validateAquaName } from "./downloadFile.js"; import { boolToStr, numToStr } from "./typesafeStringify.js"; -import { stringifyUnknown } from "./utils.js"; +import { stringifyUnknown } from "./stringifyUnknown.js"; /** * In js object, json or yaml when you want to represent optional value and still generate a type for it you can use this syntax: diff --git a/packages/cli/package/src/lib/helpers/setTryTimeout.ts b/packages/cli/package/src/lib/helpers/setTryTimeout.ts index 9525fbd72..2fd22ae52 100644 --- a/packages/cli/package/src/lib/helpers/setTryTimeout.ts +++ b/packages/cli/package/src/lib/helpers/setTryTimeout.ts @@ -20,8 +20,8 @@ import { color } from "@oclif/color"; import { commandObj } from "../commandObj.js"; import { dbg } from "../dbg.js"; +import { stringifyUnknown } from "./stringifyUnknown.js"; import { numToStr } from "./typesafeStringify.js"; -import { stringifyUnknown } from "./utils.js"; export async function setTryTimeout( message: string, diff --git a/packages/cli/package/src/lib/helpers/stringifyUnknown.ts b/packages/cli/package/src/lib/helpers/stringifyUnknown.ts new file mode 100644 index 000000000..b18b6a64c --- /dev/null +++ b/packages/cli/package/src/lib/helpers/stringifyUnknown.ts @@ -0,0 +1,70 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { AssertionError } from "assert"; + +import { CLIError } from "@oclif/core/errors"; + +import { jsonStringify } from "../../common.js"; + +/** + * Used for error stringification cause one can throw anything in js (not only errors) + * also used for e.g. debug logs or "unreachable error" messages where we don't necessarily care much about the output as long as it's somewhat readable. + * it would be good to have two functions for this each with a more clear purpose for existence and used accordingly TODO: DXJ-763 + */ + +export function stringifyUnknown(unknown: unknown): string { + try { + if (typeof unknown === "string") { + return unknown; + } + + if (unknown instanceof CLIError || unknown instanceof AssertionError) { + // eslint-disable-next-line no-restricted-syntax + return String(unknown); + } + + if (unknown instanceof Error) { + const errorMessage = + typeof unknown.stack === "string" && + unknown.stack.includes(unknown.message) + ? unknown.stack + : `${unknown.message}${unknown.stack === undefined ? "" : `\n${unknown.stack}`}`; + + const otherErrorProperties = Object.getOwnPropertyNames(unknown).filter( + (p) => { + return p !== "message" && p !== "stack"; + }, + ); + + return `${errorMessage}${ + otherErrorProperties.length > 0 + ? `\n${JSON.stringify(unknown, otherErrorProperties, 2)}` + : "" + }`; + } + + if (unknown === undefined) { + return "undefined"; + } + + return jsonStringify(unknown); + } catch { + // eslint-disable-next-line no-restricted-syntax + return String(unknown); + } +} diff --git a/packages/cli/package/src/lib/helpers/utils.ts b/packages/cli/package/src/lib/helpers/utils.ts index b0c5a1906..aab6f6e2b 100644 --- a/packages/cli/package/src/lib/helpers/utils.ts +++ b/packages/cli/package/src/lib/helpers/utils.ts @@ -15,13 +15,8 @@ * along with this program. If not, see . */ -import { AssertionError } from "node:assert"; import { access } from "node:fs/promises"; -import { CLIError } from "@oclif/core/errors"; - -import { jsonStringify } from "../../common.js"; - import { numToStr } from "./typesafeStringify.js"; export function commaSepStrToArr(commaSepStr: string) { @@ -48,55 +43,6 @@ function comment(commentToken: string) { export const jsComment = comment("//"); export const aquaComment = comment("--"); -/** - * Used for error stringification cause one can throw anything in js (not only errors) - * also used for e.g. debug logs or "unreachable error" messages where we don't necessarily care much about the output as long as it's somewhat readable. - * it would be good to have two functions for this each with a more clear purpose for existence and used accordingly TODO: DXJ-763 - */ -export function stringifyUnknown(unknown: unknown): string { - try { - if (typeof unknown === "string") { - return unknown; - } - - if (unknown instanceof CLIError || unknown instanceof AssertionError) { - // eslint-disable-next-line no-restricted-syntax - return String(unknown); - } - - if (unknown instanceof Error) { - const errorMessage = - typeof unknown.stack === "string" && - unknown.stack.includes(unknown.message) - ? unknown.stack - : `${unknown.message}${ - unknown.stack === undefined ? "" : `\n${unknown.stack}` - }`; - - const otherErrorProperties = Object.getOwnPropertyNames(unknown).filter( - (p) => { - return p !== "message" && p !== "stack"; - }, - ); - - return `${errorMessage}${ - otherErrorProperties.length > 0 - ? `\n${JSON.stringify(unknown, otherErrorProperties, 2)}` - : "" - }`; - } - - if (unknown === undefined) { - return "undefined"; - } - - return jsonStringify(unknown); - } catch { - // eslint-disable-next-line no-restricted-syntax - return String(unknown); - } -} - function flagToArg( flagName: string, flagValue: string | number | boolean | undefined, diff --git a/packages/cli/package/src/lib/helpers/validations.ts b/packages/cli/package/src/lib/helpers/validations.ts index 39f71a801..fbbcf9d22 100644 --- a/packages/cli/package/src/lib/helpers/validations.ts +++ b/packages/cli/package/src/lib/helpers/validations.ts @@ -16,7 +16,8 @@ */ import { numToStr } from "./typesafeStringify.js"; -import { splitErrorsAndResults, stringifyUnknown } from "./utils.js"; +import { splitErrorsAndResults } from "./utils.js"; +import { stringifyUnknown } from "./stringifyUnknown.js"; export type ValidationResult = string | true; diff --git a/packages/cli/package/src/lib/jsClient.ts b/packages/cli/package/src/lib/jsClient.ts index a2430219f..e09e36ecf 100644 --- a/packages/cli/package/src/lib/jsClient.ts +++ b/packages/cli/package/src/lib/jsClient.ts @@ -19,7 +19,7 @@ import { color } from "@oclif/color"; import { commandObj } from "./commandObj.js"; import { type FluenceClientFlags } from "./const.js"; -import { stringifyUnknown } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { base64ToUint8Array } from "./keyPairs.js"; import { resolveRelay } from "./multiaddres.js"; import { getExistingSecretKey } from "./secretKeys.js"; diff --git a/packages/cli/package/src/lib/localServices/ipfs.ts b/packages/cli/package/src/lib/localServices/ipfs.ts index b3a640ac6..ed97f45fe 100644 --- a/packages/cli/package/src/lib/localServices/ipfs.ts +++ b/packages/cli/package/src/lib/localServices/ipfs.ts @@ -23,7 +23,7 @@ import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { FS_OPTIONS } from "../const.js"; import { dbg } from "../dbg.js"; -import { stringifyUnknown } from "../helpers/utils.js"; +import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { setTryTimeout } from "../helpers/setTryTimeout.js"; // !IMPORTANT for some reason when in tsconfig.json "moduleResolution" is set to "nodenext" - "ipfs-http-client" types all become "any" diff --git a/packages/cli/package/src/lib/npm.ts b/packages/cli/package/src/lib/npm.ts index c67f7270f..af3ceafda 100644 --- a/packages/cli/package/src/lib/npm.ts +++ b/packages/cli/package/src/lib/npm.ts @@ -31,7 +31,8 @@ import { AQUA_DEPENDENCIES_DIR_NAME, FS_OPTIONS } from "./const.js"; import { type ExecPromiseArg, execPromise } from "./execPromise.js"; import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; import { startSpinner, stopSpinner } from "./helpers/spinner.js"; -import { removeProperties, stringifyUnknown } from "./helpers/utils.js"; +import { removeProperties } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { getFluenceAquaDependenciesPackageJsonPath, ensureFluenceAquaDependenciesPath, diff --git a/packages/cli/package/src/lib/paths.ts b/packages/cli/package/src/lib/paths.ts index f0f565ab1..5682e818d 100644 --- a/packages/cli/package/src/lib/paths.ts +++ b/packages/cli/package/src/lib/paths.ts @@ -66,7 +66,7 @@ import { DOCKER_COMPOSE_FULL_FILE_NAME, } from "./const.js"; import { recursivelyFindFile } from "./helpers/recursivelyFindFile.js"; -import { stringifyUnknown } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { FLUENCE_USER_DIR } from "./setupEnvironment.js"; export const validatePath = async (path: string): Promise => { diff --git a/packages/cli/package/src/lib/rust.ts b/packages/cli/package/src/lib/rust.ts index fdb08afcb..ed5919584 100644 --- a/packages/cli/package/src/lib/rust.ts +++ b/packages/cli/package/src/lib/rust.ts @@ -38,7 +38,7 @@ import { findEntryInPATH, prependEntryToPATH } from "./env.js"; import { execPromise } from "./execPromise.js"; import { downloadFile } from "./helpers/downloadFile.js"; import { startSpinner, stopSpinner } from "./helpers/spinner.js"; -import { stringifyUnknown } from "./helpers/utils.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { projectRootDir, ensureUserFluenceCargoDir, diff --git a/packages/cli/package/tsconfig.json b/packages/cli/package/tsconfig.json index 89322789f..9175bfff5 100644 --- a/packages/cli/package/tsconfig.json +++ b/packages/cli/package/tsconfig.json @@ -10,11 +10,6 @@ "verbatimModuleSyntax": true }, "include": ["src/**/*"], - "files": [ - "src/environment.d.ts", - "src/types.d.ts", - "./src/lib/helpers/setTryTimeout.ts", - "src/lib/configs/project/chainContainers.ts" - ], + "files": ["src/environment.d.ts", "src/types.d.ts"], "types": ["node"] } From eb52c51514dc695943bdc13994c93826882a4560 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:13:56 +0100 Subject: [PATCH 15/37] don't require build for linting --- turbo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index d8f2d70b9..ef00eacfe 100644 --- a/turbo.json +++ b/turbo.json @@ -60,7 +60,7 @@ "outputs": ["dist/**", "package/dist/**"] }, "on-each-commit": { - "dependsOn": ["^build", "build"] + "dependsOn": ["^build", "before-build"] }, "pack-ci": { "dependsOn": ["build"], From 735d792dce2cb7a88d6cddec8a0d0ed83877eceb Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:17:13 +0100 Subject: [PATCH 16/37] remove irrelevant dependencies --- turbo.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/turbo.json b/turbo.json index ef00eacfe..d64bbfcb0 100644 --- a/turbo.json +++ b/turbo.json @@ -21,10 +21,7 @@ "inputs": [ "package/src/lib/configs/project/chainContainers.ts", "package/src/genGqlSchema.ts", - "package/src/versions.ts", - "package/src/versions.json", - "package/src/lib/helpers/setTryTimeout.ts", - "package/src/lib/setupEnvironment.ts" + "package/src/versions.json" ], "outputs": ["package/src/lib/gql/gqlSchema.json"] }, From be52e49143111cdd5f89c9a52176e26462bce547 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:23:03 +0100 Subject: [PATCH 17/37] add docker for on-each-commit --- .github/workflows/docs.yml | 32 ++++++++++++++++++++++++++++++++ turbo.json | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bac4fc330..f2d98809e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,6 +27,38 @@ jobs: with: token: ${{ secrets.FLUENCEBOT_RELEASE_PLEASE_PAT }} + - name: Import secrets + uses: hashicorp/vault-action@v3.0.0 + id: secrets + with: + url: https://vault.fluence.dev + path: jwt/github + role: ci + method: jwt + jwtGithubAudience: "https://github.com/fluencelabs" + jwtTtl: 300 + exportToken: false + secrets: | + kv/hub.docker.com/fluencebot username | DOCKER_HUB_USERNAME ; + kv/hub.docker.com/fluencebot password | DOCKER_HUB_PASSWORD ; + kv/docker-registry/basicauth/ci username | DOCKER_USERNAME ; + kv/docker-registry/basicauth/ci password | DOCKER_PASSWORD ; + kv/npm-registry/basicauth/ci token | NODE_AUTH_TOKEN; + kv/cargo-registry/users/ci token | CARGO_REGISTRIES_FLUENCE_TOKEN + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + + - name: Login to private docker registry + uses: docker/login-action@v3 + with: + registry: docker.fluence.dev + username: ${{ env.DOCKER_USERNAME }} + password: ${{ env.DOCKER_PASSWORD }} + - name: Setup node with self-hosted npm registry uses: actions/setup-node@v4 with: diff --git a/turbo.json b/turbo.json index d64bbfcb0..b9fdf8677 100644 --- a/turbo.json +++ b/turbo.json @@ -57,7 +57,7 @@ "outputs": ["dist/**", "package/dist/**"] }, "on-each-commit": { - "dependsOn": ["^build", "before-build"] + "dependsOn": ["^build", "build"] }, "pack-ci": { "dependsOn": ["build"], From 8856f00dd5a49a5d2ec05ece51bba7a20f29352f Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:31:20 +0100 Subject: [PATCH 18/37] add env --- .github/workflows/docs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f2d98809e..403f82aec 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,11 @@ concurrency: env: CI: true FORCE_COLOR: true + DEBUG: "fcli:*,deal-ts-clients:*" FLUENCE_USER_DIR: "${{ github.workspace }}/tmp/.fluence" + CARGO_REGISTRIES_FLUENCE_INDEX: "git://crates.fluence.dev/index" + NPM_CONFIG_REGISTRY: "https://npm.fluence.dev" + FLUENCE_LOG_DISPLAY_SPAN_LIST: true jobs: docs: From fba466292df200277dc84213107d354a3ff1e447 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:33:07 +0100 Subject: [PATCH 19/37] change runs-on --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 403f82aec..9e7f2c3bb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,7 +24,7 @@ jobs: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} name: Generate docs - runs-on: ubuntu-latest + runs-on: builder steps: - name: Checkout repository uses: actions/checkout@v4 From 5fdd23eb4854dd8d76455de42adfd86f670b3c8b Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:36:37 +0100 Subject: [PATCH 20/37] add permissions? --- .github/workflows/docs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9e7f2c3bb..a3b4f09a5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,6 +25,11 @@ jobs: TURBO_TEAM: ${{ vars.TURBO_TEAM }} name: Generate docs runs-on: builder + + permissions: + contents: write + id-token: write + steps: - name: Checkout repository uses: actions/checkout@v4 From 22f6adaeec586b2390f166ff70445524e8f2411b Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 16:44:20 +0100 Subject: [PATCH 21/37] fix and remove stuff from docs.yml --- .github/workflows/docs.yml | 43 +------------------ .../src/lib/helpers/stringifyUnknown.ts | 4 +- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a3b4f09a5..bac4fc330 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,11 +12,7 @@ concurrency: env: CI: true FORCE_COLOR: true - DEBUG: "fcli:*,deal-ts-clients:*" FLUENCE_USER_DIR: "${{ github.workspace }}/tmp/.fluence" - CARGO_REGISTRIES_FLUENCE_INDEX: "git://crates.fluence.dev/index" - NPM_CONFIG_REGISTRY: "https://npm.fluence.dev" - FLUENCE_LOG_DISPLAY_SPAN_LIST: true jobs: docs: @@ -24,50 +20,13 @@ jobs: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} name: Generate docs - runs-on: builder - - permissions: - contents: write - id-token: write - + runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: token: ${{ secrets.FLUENCEBOT_RELEASE_PLEASE_PAT }} - - name: Import secrets - uses: hashicorp/vault-action@v3.0.0 - id: secrets - with: - url: https://vault.fluence.dev - path: jwt/github - role: ci - method: jwt - jwtGithubAudience: "https://github.com/fluencelabs" - jwtTtl: 300 - exportToken: false - secrets: | - kv/hub.docker.com/fluencebot username | DOCKER_HUB_USERNAME ; - kv/hub.docker.com/fluencebot password | DOCKER_HUB_PASSWORD ; - kv/docker-registry/basicauth/ci username | DOCKER_USERNAME ; - kv/docker-registry/basicauth/ci password | DOCKER_PASSWORD ; - kv/npm-registry/basicauth/ci token | NODE_AUTH_TOKEN; - kv/cargo-registry/users/ci token | CARGO_REGISTRIES_FLUENCE_TOKEN - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} - - - name: Login to private docker registry - uses: docker/login-action@v3 - with: - registry: docker.fluence.dev - username: ${{ env.DOCKER_USERNAME }} - password: ${{ env.DOCKER_PASSWORD }} - - name: Setup node with self-hosted npm registry uses: actions/setup-node@v4 with: diff --git a/packages/cli/package/src/lib/helpers/stringifyUnknown.ts b/packages/cli/package/src/lib/helpers/stringifyUnknown.ts index b18b6a64c..a2b01bd09 100644 --- a/packages/cli/package/src/lib/helpers/stringifyUnknown.ts +++ b/packages/cli/package/src/lib/helpers/stringifyUnknown.ts @@ -19,8 +19,6 @@ import { AssertionError } from "assert"; import { CLIError } from "@oclif/core/errors"; -import { jsonStringify } from "../../common.js"; - /** * Used for error stringification cause one can throw anything in js (not only errors) * also used for e.g. debug logs or "unreachable error" messages where we don't necessarily care much about the output as long as it's somewhat readable. @@ -62,7 +60,7 @@ export function stringifyUnknown(unknown: unknown): string { return "undefined"; } - return jsonStringify(unknown); + return JSON.stringify(unknown, null, 2); } catch { // eslint-disable-next-line no-restricted-syntax return String(unknown); From c1530c891389b8ea61a778c58f3c61c6f1e21094 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 5 Nov 2024 17:01:49 +0100 Subject: [PATCH 22/37] fix --- packages/cli/package/eslint.config.js | 2 +- packages/cli/package/src/commands/deal/logs.ts | 2 +- packages/cli/package/src/commands/provider/gen.ts | 2 +- packages/cli/package/src/commands/workers/logs.ts | 2 +- packages/cli/package/src/lib/chain/chainValidators.ts | 2 +- packages/cli/package/src/lib/chain/commitment.ts | 2 +- packages/cli/package/src/lib/chain/offer/offer.ts | 4 ++-- packages/cli/package/src/lib/compileAquaAndWatch.ts | 2 +- .../package/src/lib/configs/project/provider/provider3.ts | 6 +++--- packages/cli/package/src/lib/deal.ts | 4 ++-- packages/cli/package/src/lib/deploy.ts | 2 +- packages/cli/package/src/lib/helpers/jsToAqua.ts | 2 +- packages/cli/package/src/lib/helpers/validations.ts | 2 +- packages/cli/package/src/lib/localServices/ipfs.ts | 2 +- packages/cli/package/src/lib/npm.ts | 2 +- packages/cli/package/test/helpers/sharedSteps.ts | 2 +- packages/cli/package/test/tests/provider.test.ts | 2 +- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/cli/package/eslint.config.js b/packages/cli/package/eslint.config.js index a3048777a..2b47a688e 100644 --- a/packages/cli/package/eslint.config.js +++ b/packages/cli/package/eslint.config.js @@ -186,7 +186,7 @@ export default tseslint.config( "bin/dev.js", "resources/*", ".yarn/*", - "src/lib/gql/gql.generated.ts", + "src/lib/gql/gqlGenerated.ts", ], }, ); diff --git a/packages/cli/package/src/commands/deal/logs.ts b/packages/cli/package/src/commands/deal/logs.ts index d322f9d26..52ae28b63 100644 --- a/packages/cli/package/src/commands/deal/logs.ts +++ b/packages/cli/package/src/commands/deal/logs.ts @@ -37,8 +37,8 @@ import { formatAquaLogsHeader, formatAquaLogs, } from "../../lib/helpers/formatAquaLogs.js"; -import { LOGS_RESOLVE_SUBNET_ERROR_START } from "../../lib/helpers/utils.js"; import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; +import { LOGS_RESOLVE_SUBNET_ERROR_START } from "../../lib/helpers/utils.js"; import { disconnectFluenceClient, initFluenceClient, diff --git a/packages/cli/package/src/commands/provider/gen.ts b/packages/cli/package/src/commands/provider/gen.ts index 0ba4c4e83..4b08949e4 100644 --- a/packages/cli/package/src/commands/provider/gen.ts +++ b/packages/cli/package/src/commands/provider/gen.ts @@ -36,8 +36,8 @@ import { MAX_TOKEN_AMOUNT_KEYWORD, CLI_NAME, } from "../../lib/const.js"; -import { pathExists } from "../../lib/helpers/utils.js"; import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; +import { pathExists } from "../../lib/helpers/utils.js"; import { initCli } from "../../lib/lifeCycle.js"; import { getFluenceSecretsDir, diff --git a/packages/cli/package/src/commands/workers/logs.ts b/packages/cli/package/src/commands/workers/logs.ts index c714e84dc..858a15b09 100644 --- a/packages/cli/package/src/commands/workers/logs.ts +++ b/packages/cli/package/src/commands/workers/logs.ts @@ -32,8 +32,8 @@ import { type FluenceEnv, } from "../../lib/const.js"; import { formatAquaLogs } from "../../lib/helpers/formatAquaLogs.js"; -import { commaSepStrToArr } from "../../lib/helpers/utils.js"; import { stringifyUnknown } from "../../lib/helpers/stringifyUnknown.js"; +import { commaSepStrToArr } from "../../lib/helpers/utils.js"; import { disconnectFluenceClient, initFluenceClient, diff --git a/packages/cli/package/src/lib/chain/chainValidators.ts b/packages/cli/package/src/lib/chain/chainValidators.ts index 7e71cd3fb..be6f325a9 100644 --- a/packages/cli/package/src/lib/chain/chainValidators.ts +++ b/packages/cli/package/src/lib/chain/chainValidators.ts @@ -21,8 +21,8 @@ import parseDuration from "parse-duration"; import { versions } from "../../versions.js"; import { getReadonlyContracts } from "../dealClient.js"; import { ensureChainEnv } from "../ensureChainNetwork.js"; -import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; +import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; import type { ValidationResult } from "../helpers/validations.js"; export async function getMinCCDuration(): Promise { diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 545ae9f31..06b0c6f64 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -44,9 +44,9 @@ import { getDealExplorerClient, } from "../dealClient.js"; import { bigintSecondsToDate } from "../helpers/bigintOps.js"; +import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; import { splitErrorsAndResults, commaSepStrToArr } from "../helpers/utils.js"; -import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { input } from "../prompt.js"; import { resolveComputePeersByNames, diff --git a/packages/cli/package/src/lib/chain/offer/offer.ts b/packages/cli/package/src/lib/chain/offer/offer.ts index fe30687ee..ef16fb1ae 100644 --- a/packages/cli/package/src/lib/chain/offer/offer.ts +++ b/packages/cli/package/src/lib/chain/offer/offer.ts @@ -43,13 +43,13 @@ import { getEventValue, } from "../../dealClient.js"; import { getOffers } from "../../gql/gqlClient.js"; +import { setTryTimeout } from "../../helpers/setTryTimeout.js"; +import { stringifyUnknown } from "../../helpers/stringifyUnknown.js"; import { numToStr } from "../../helpers/typesafeStringify.js"; import { commaSepStrToArr, splitErrorsAndResults, } from "../../helpers/utils.js"; -import { stringifyUnknown } from "../../helpers/stringifyUnknown.js"; -import { setTryTimeout } from "../../helpers/setTryTimeout.js"; import { checkboxes } from "../../prompt.js"; import { ensureFluenceEnv } from "../../resolveFluenceEnv.js"; import { getProtocolVersions } from "../chainValidators.js"; diff --git a/packages/cli/package/src/lib/compileAquaAndWatch.ts b/packages/cli/package/src/lib/compileAquaAndWatch.ts index 95dd31e04..ae15c69d4 100644 --- a/packages/cli/package/src/lib/compileAquaAndWatch.ts +++ b/packages/cli/package/src/lib/compileAquaAndWatch.ts @@ -33,8 +33,8 @@ import { } from "./configs/project/fluence.js"; import { COMPILE_AQUA_PROPERTY_NAME } from "./const.js"; import { getAquaImports } from "./helpers/aquaImports.js"; -import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; +import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; import { projectRootDir } from "./paths.js"; import type { Required } from "./typeHelpers.js"; diff --git a/packages/cli/package/src/lib/configs/project/provider/provider3.ts b/packages/cli/package/src/lib/configs/project/provider/provider3.ts index 65af8333b..aefcd02cd 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider3.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider3.ts @@ -24,9 +24,6 @@ import mapValues from "lodash-es/mapValues.js"; import mergeWith from "lodash-es/mergeWith.js"; import { jsonStringify, type ChainENV } from "../../../../common.js"; -import { CHAIN_RPC_PORT, IPFS_PORT } from "../chainContainers.js"; -import { IPFS_CONTAINER_NAME } from "../chainContainers.js"; -import { CHAIN_RPC_CONTAINER_NAME } from "../chainContainers.js"; import { versions } from "../../../../versions.js"; import { getChainId } from "../../../chain/chainConfig.js"; import { @@ -56,6 +53,9 @@ import { import { validateBatchAsync } from "../../../helpers/validations.js"; import { resolveRelaysWithoutLocal } from "../../../multiaddresWithoutLocal.js"; import type { ConfigOptions } from "../../initConfigNewTypes.js"; +import { CHAIN_RPC_CONTAINER_NAME } from "../chainContainers.js"; +import { IPFS_CONTAINER_NAME } from "../chainContainers.js"; +import { CHAIN_RPC_PORT, IPFS_PORT } from "../chainContainers.js"; import { initEnvConfig } from "../env/env.js"; import { providerNameSchema } from "./provider0.js"; diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index d17235346..420ba186d 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -44,10 +44,10 @@ import { batchRead, } from "./dealClient.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; +import { setTryTimeout } from "./helpers/setTryTimeout.js"; +import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; import { bigintToStr } from "./helpers/typesafeStringify.js"; import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; -import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; -import { setTryTimeout } from "./helpers/setTryTimeout.js"; import { checkboxes, input, list } from "./prompt.js"; import { ensureFluenceEnv } from "./resolveFluenceEnv.js"; diff --git a/packages/cli/package/src/lib/deploy.ts b/packages/cli/package/src/lib/deploy.ts index 34fc3e2c1..233aa5d7f 100644 --- a/packages/cli/package/src/lib/deploy.ts +++ b/packages/cli/package/src/lib/deploy.ts @@ -50,8 +50,8 @@ import { dealCreate, dealUpdate, match } from "./deal.js"; import { createAndMatchDealsForPeerIds } from "./deal.js"; import { getReadonlyContracts } from "./dealClient.js"; import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; -import { numToStr } from "./helpers/typesafeStringify.js"; import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; +import { numToStr } from "./helpers/typesafeStringify.js"; import { disconnectFluenceClient } from "./jsClient.js"; import { initCli } from "./lifeCycle.js"; import { getIpfsClient } from "./localServices/ipfs.js"; diff --git a/packages/cli/package/src/lib/helpers/jsToAqua.ts b/packages/cli/package/src/lib/helpers/jsToAqua.ts index dc274439d..afa7ecaa7 100644 --- a/packages/cli/package/src/lib/helpers/jsToAqua.ts +++ b/packages/cli/package/src/lib/helpers/jsToAqua.ts @@ -30,8 +30,8 @@ import { AQUA_EXT, FS_OPTIONS } from "../const.js"; import { input } from "../prompt.js"; import { validateAquaTypeName, validateAquaName } from "./downloadFile.js"; -import { boolToStr, numToStr } from "./typesafeStringify.js"; import { stringifyUnknown } from "./stringifyUnknown.js"; +import { boolToStr, numToStr } from "./typesafeStringify.js"; /** * In js object, json or yaml when you want to represent optional value and still generate a type for it you can use this syntax: diff --git a/packages/cli/package/src/lib/helpers/validations.ts b/packages/cli/package/src/lib/helpers/validations.ts index fbbcf9d22..7f698bb1a 100644 --- a/packages/cli/package/src/lib/helpers/validations.ts +++ b/packages/cli/package/src/lib/helpers/validations.ts @@ -15,9 +15,9 @@ * along with this program. If not, see . */ +import { stringifyUnknown } from "./stringifyUnknown.js"; import { numToStr } from "./typesafeStringify.js"; import { splitErrorsAndResults } from "./utils.js"; -import { stringifyUnknown } from "./stringifyUnknown.js"; export type ValidationResult = string | true; diff --git a/packages/cli/package/src/lib/localServices/ipfs.ts b/packages/cli/package/src/lib/localServices/ipfs.ts index ed97f45fe..a88b29ba6 100644 --- a/packages/cli/package/src/lib/localServices/ipfs.ts +++ b/packages/cli/package/src/lib/localServices/ipfs.ts @@ -23,8 +23,8 @@ import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { FS_OPTIONS } from "../const.js"; import { dbg } from "../dbg.js"; -import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { setTryTimeout } from "../helpers/setTryTimeout.js"; +import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; // !IMPORTANT for some reason when in tsconfig.json "moduleResolution" is set to "nodenext" - "ipfs-http-client" types all become "any" // so when working with this module - remove "nodenext" from "moduleResolution" so you can make sure types are correct diff --git a/packages/cli/package/src/lib/npm.ts b/packages/cli/package/src/lib/npm.ts index af3ceafda..84b062195 100644 --- a/packages/cli/package/src/lib/npm.ts +++ b/packages/cli/package/src/lib/npm.ts @@ -31,8 +31,8 @@ import { AQUA_DEPENDENCIES_DIR_NAME, FS_OPTIONS } from "./const.js"; import { type ExecPromiseArg, execPromise } from "./execPromise.js"; import { ensureFluenceProject } from "./helpers/ensureFluenceProject.js"; import { startSpinner, stopSpinner } from "./helpers/spinner.js"; -import { removeProperties } from "./helpers/utils.js"; import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; +import { removeProperties } from "./helpers/utils.js"; import { getFluenceAquaDependenciesPackageJsonPath, ensureFluenceAquaDependenciesPath, diff --git a/packages/cli/package/test/helpers/sharedSteps.ts b/packages/cli/package/test/helpers/sharedSteps.ts index ec23144e6..9b06f73cd 100644 --- a/packages/cli/package/test/helpers/sharedSteps.ts +++ b/packages/cli/package/test/helpers/sharedSteps.ts @@ -43,10 +43,10 @@ import { DEFAULT_NUMBER_OF_LOCAL_NET_NOXES, } from "../../src/lib/const.js"; import { setTryTimeout } from "../../src/lib/helpers/setTryTimeout.js"; +import { stringifyUnknown } from "../../src/lib/helpers/stringifyUnknown.js"; import { LOGS_GET_ERROR_START, LOGS_RESOLVE_SUBNET_ERROR_START, - stringifyUnknown, } from "../../src/lib/helpers/utils.js"; import { addrsToNodes } from "../../src/lib/multiaddresWithoutLocal.js"; import { getAquaMainPath } from "../../src/lib/paths.js"; diff --git a/packages/cli/package/test/tests/provider.test.ts b/packages/cli/package/test/tests/provider.test.ts index 55b8e0dd5..085b7ae41 100644 --- a/packages/cli/package/test/tests/provider.test.ts +++ b/packages/cli/package/test/tests/provider.test.ts @@ -28,8 +28,8 @@ import { PRIV_KEY_FLAG_NAME, PROVIDER_CONFIG_FULL_FILE_NAME, } from "../../src/lib/const.js"; +import { stringifyUnknown } from "../../src/lib/helpers/stringifyUnknown.js"; import { numToStr } from "../../src/lib/helpers/typesafeStringify.js"; -import { stringifyUnknown } from "../../src/lib/helpers/utils.js"; import { fluence } from "../helpers/commonWithSetupTests.js"; import { CC_DURATION_SECONDS } from "../helpers/constants.js"; import { initializeTemplate } from "../helpers/sharedSteps.js"; From ebfeec12b63a2eaf0ad92520e0906c329e0e09db Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 6 Nov 2024 10:39:46 +0100 Subject: [PATCH 23/37] add generated to prettierignore --- packages/cli/package/.prettierignore => .prettierignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename packages/cli/package/.prettierignore => .prettierignore (59%) diff --git a/packages/cli/package/.prettierignore b/.prettierignore similarity index 59% rename from packages/cli/package/.prettierignore rename to .prettierignore index d7dcf17e0..7b076479d 100644 --- a/packages/cli/package/.prettierignore +++ b/.prettierignore @@ -3,7 +3,8 @@ docs node_modules tmp .fluence -src/lib/compiled-aqua -gql.generated.ts +compiled-aqua +gqlSchema.json +gqlGenerated.ts CHANGELOG.md .github/workflows From a19187e6397bdb5ba37c1438d3884056e7fc5ad5 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 6 Nov 2024 10:47:55 +0100 Subject: [PATCH 24/37] add config promise to the Map right away to prevent possible problems when using Promise.all that inits and manipulates the same config --- .../package/src/lib/configs/initConfigNew.ts | 135 +++++++++--------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index 976d3b707..a67d1a0aa 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -46,7 +46,10 @@ import type { ConfigOptions, } from "./initConfigNewTypes.js"; -const initializedConfigs = new Map>(); +const initializedConfigs = new Map< + string, + Promise | null> +>(); export function getConfigInitFunction< C0, @@ -120,72 +123,76 @@ export function getConfigInitFunction< if (previouslyInitializedConfig !== undefined) { // It's safe to assert here because we can be sure that previouslyInitializedConfig has the same type // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return previouslyInitializedConfig as InitializedConfig; + return previouslyInitializedConfig as Promise | null>; } - if ( - !expectedConfigPath.endsWith(YAML_EXT) && - !expectedConfigPath.endsWith(YML_EXT) - ) { - commandObj.error( - `Invalid config path ${color.yellow( - expectedConfigPath, - )}. Config path must end with ${color.yellow(YAML_EXT)} or ${color.yellow( - YML_EXT, - )}`, - ); - } - - await addTitleDescriptionAndVersionToSchemas({ - options, - description, - getConfigPath, - }); - - const getLatestConfigRes = await getLatestConfig({ - options, - expectedConfigPath, - getDefaultConfig, - getSchemaDirPath, - }); - - if (getLatestConfigRes === null) { - return null; - } - - const { yamlDiffPatch } = await import("yaml-diff-patch"); - - const { - latestConfig, - latestConfigString, - actualConfigPath, - validateLatestConfig, - } = getLatestConfigRes; - - let prevConfigString = latestConfigString; - - const initializedConfig: InitializedConfig = { - ...latestConfig, - $getPath(): string { - return actualConfigPath; - }, - async $commit(): Promise { - const config = removeProperties(this, ([, v]) => { - return typeof v === "function"; - }); - - prevConfigString = await saveConfig( - actualConfigPath, - yamlDiffPatch(prevConfigString, {}, config), - prevConfigString, + const initializedConfigPromise = (async () => { + if ( + !expectedConfigPath.endsWith(YAML_EXT) && + !expectedConfigPath.endsWith(YML_EXT) + ) { + commandObj.error( + `Invalid config path ${color.yellow( + expectedConfigPath, + )}. Config path must end with ${color.yellow(YAML_EXT)} or ${color.yellow( + YML_EXT, + )}`, ); - - await validateLatestConfig(config); - }, - }; - - initializedConfigs.set(expectedConfigPath, initializedConfig); - return initializedConfig; + } + + await addTitleDescriptionAndVersionToSchemas({ + options, + description, + getConfigPath, + }); + + const getLatestConfigRes = await getLatestConfig({ + options, + expectedConfigPath, + getDefaultConfig, + getSchemaDirPath, + }); + + if (getLatestConfigRes === null) { + return null; + } + + const { yamlDiffPatch } = await import("yaml-diff-patch"); + + const { + latestConfig, + latestConfigString, + actualConfigPath, + validateLatestConfig, + } = getLatestConfigRes; + + let prevConfigString = latestConfigString; + + const initializedConfig: InitializedConfig = { + ...latestConfig, + $getPath(): string { + return actualConfigPath; + }, + async $commit(): Promise { + const config = removeProperties(this, ([, v]) => { + return typeof v === "function"; + }); + + prevConfigString = await saveConfig( + actualConfigPath, + yamlDiffPatch(prevConfigString, {}, config), + prevConfigString, + ); + + await validateLatestConfig(config); + }, + }; + + return initializedConfig; + })(); + + initializedConfigs.set(expectedConfigPath, initializedConfigPromise); + return initializedConfigPromise; }; } From 53a68b0df1a3f44b0a4e9eab62076f8d0ab49c75 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 6 Nov 2024 11:43:36 +0100 Subject: [PATCH 25/37] fix --- .../cli/package/src/lib/configs/initConfigNew.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/cli/package/src/lib/configs/initConfigNew.ts b/packages/cli/package/src/lib/configs/initConfigNew.ts index a67d1a0aa..6f70cff7b 100644 --- a/packages/cli/package/src/lib/configs/initConfigNew.ts +++ b/packages/cli/package/src/lib/configs/initConfigNew.ts @@ -118,12 +118,17 @@ export function getConfigInitFunction< const expectedConfigPath = await getConfigPath(); const previouslyInitializedConfig = - initializedConfigs.get(expectedConfigPath); - - if (previouslyInitializedConfig !== undefined) { + await initializedConfigs.get(expectedConfigPath); + + if ( + // return previously initialized config if it exists + previouslyInitializedConfig !== undefined && + // And don't return null if default config is provided, proceed with initialization + !(previouslyInitializedConfig === null && getDefaultConfig !== undefined) + ) { // It's safe to assert here because we can be sure that previouslyInitializedConfig has the same type // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - return previouslyInitializedConfig as Promise | null>; + return previouslyInitializedConfig as InitializedConfig | null; } const initializedConfigPromise = (async () => { From 278dcad60635258ec4fcd2b52f3f754695b922ae Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 10:50:44 +0100 Subject: [PATCH 26/37] remove rest of the clients --- .../src/commands/deal/workers-remove.ts | 11 +- .../package/src/commands/provider/cc-info.ts | 22 +- .../src/commands/provider/deal-exit.ts | 34 +- .../provider/deal-rewards-withdraw.ts | 12 +- .../cli/package/src/commands/spell/build.ts | 10 +- .../cli/package/src/commands/workers/logs.ts | 6 + .../package/src/commands/workers/remove.ts | 4 + .../cli/package/src/lib/chain/commitment.ts | 1244 ++++++++++------- .../cli/package/src/lib/chain/conversions.ts | 5 + packages/cli/package/src/lib/chain/deals.ts | 9 +- .../src/lib/chain/depositCollateral.ts | 47 +- .../cli/package/src/lib/chain/offer/offer.ts | 2 +- .../src/lib/chain/offer/updateOffers.ts | 18 +- .../lib/configs/project/provider/provider.ts | 14 +- packages/cli/package/src/lib/deal.ts | 521 ++++++- packages/cli/package/src/lib/dealClient.ts | 126 +- packages/cli/package/src/lib/gql/gql.ts | 94 ++ packages/cli/package/src/lib/gql/gqlClient.ts | 64 - .../cli/package/src/lib/gql/schema.graphql | 143 +- .../cli/package/src/lib/helpers/bigintOps.ts | 9 +- .../src/lib/helpers/typesafeStringify.ts | 4 + packages/cli/package/src/lib/helpers/utils.ts | 11 +- .../src/lib/resolveComputePeersByNames.ts | 77 +- packages/cli/package/src/lib/typeHelpers.ts | 7 + 24 files changed, 1731 insertions(+), 763 deletions(-) create mode 100644 packages/cli/package/src/lib/gql/gql.ts delete mode 100644 packages/cli/package/src/lib/gql/gqlClient.ts diff --git a/packages/cli/package/src/commands/deal/workers-remove.ts b/packages/cli/package/src/commands/deal/workers-remove.ts index c94c366d1..126d88c62 100644 --- a/packages/cli/package/src/commands/deal/workers-remove.ts +++ b/packages/cli/package/src/commands/deal/workers-remove.ts @@ -65,12 +65,19 @@ export default class WorkersRemove extends BaseCommand { args["WORKER-IDS"] ?? (await input({ message: "Enter comma-separated worker ids", - validate: (v: string) => { - return commaSepStrToArr(v).length > 0; + validate(v: string) { + return ( + commaSepStrToArr(v).length > 0 || + "Please provide at least one worker id" + ); }, })), ); + if (workerIds.length === 0) { + commandObj.error("No worker ids provided"); + } + for (const workerId of workerIds) { await sign({ title: `Remove worker ${workerId} from deal`, diff --git a/packages/cli/package/src/commands/provider/cc-info.ts b/packages/cli/package/src/commands/provider/cc-info.ts index 52f3e002d..01e9d3821 100644 --- a/packages/cli/package/src/commands/provider/cc-info.ts +++ b/packages/cli/package/src/commands/provider/cc-info.ts @@ -16,10 +16,12 @@ */ import { BaseCommand } from "../../baseCommand.js"; +import { jsonStringify } from "../../common.js"; import { - printCommitmentsInfo, - printCommitmentsInfoJSON, + getDetailedCommitmentsInfoGroupedByStatus, + stringifyDetailedCommitmentsInfo, } from "../../lib/chain/commitment.js"; +import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS, CC_FLAGS, JSON_FLAG } from "../../lib/const.js"; import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; @@ -36,10 +38,16 @@ export default class CCInfo extends BaseCommand { async run(): Promise { const { flags } = await initCli(this, await this.parse(CCInfo)); - if (flags.json) { - await printCommitmentsInfoJSON(flags); - } else { - await printCommitmentsInfo(flags); - } + const ccInfo = await getDetailedCommitmentsInfoGroupedByStatus(flags); + + commandObj.log( + flags.json + ? jsonStringify( + ccInfo.flatMap(({ CCs }) => { + return CCs; + }), + ) + : stringifyDetailedCommitmentsInfo(ccInfo), + ); } } diff --git a/packages/cli/package/src/commands/provider/deal-exit.ts b/packages/cli/package/src/commands/provider/deal-exit.ts index 2f100ff52..4cd620c1e 100644 --- a/packages/cli/package/src/commands/provider/deal-exit.ts +++ b/packages/cli/package/src/commands/provider/deal-exit.ts @@ -19,6 +19,7 @@ import { Flags } from "@oclif/core"; import { BaseCommand } from "../../baseCommand.js"; import { getProviderDeals } from "../../lib/chain/deals.js"; +import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS, DEAL_IDS_FLAG, @@ -59,9 +60,19 @@ export default class DealExit extends BaseCommand { flags[DEAL_IDS_FLAG_NAME] ?? (await input({ message: "Enter comma-separated deal ids", + validate(input: string) { + return ( + commaSepStrToArr(input).length > 0 || + "Please enter at least one deal id" + ); + }, })), ); + if (dealIds.length === 0) { + return commandObj.error("No deal ids provided"); + } + const workers = ( await Promise.all( dealIds.map(async (id) => { @@ -71,7 +82,19 @@ export default class DealExit extends BaseCommand { }); }), ) - ).flat(); + ) + .flat() + .filter(({ worker }) => { + return worker.provider.toLowerCase() === signerAddress; + }); + + const [firstWorker, ...restWorkers] = workers; + + if (firstWorker === undefined) { + return commandObj.error( + `No workers found for address ${signerAddress} and deal ids: ${dealIds.join(", ")}`, + ); + } await signBatch( `Remove the following workers from deals:\n\n${workers @@ -79,13 +102,12 @@ export default class DealExit extends BaseCommand { return onchainId; }) .join("\n")}`, - workers - .filter(({ worker }) => { - return worker.provider.toLowerCase() === signerAddress; - }) - .map(({ deal, worker: { onchainId } }) => { + [ + populateTx(firstWorker.deal.removeWorker, firstWorker.worker.onchainId), + ...restWorkers.map(({ deal, worker: { onchainId } }) => { return populateTx(deal.removeWorker, onchainId); }), + ], ); } } diff --git a/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts b/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts index 30b4b1c7d..c44b682f6 100644 --- a/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts +++ b/packages/cli/package/src/commands/provider/deal-rewards-withdraw.ts @@ -51,11 +51,19 @@ export default class DealRewardsWithdraw extends BaseCommand< const dealIds = commaSepStrToArr( flags[DEAL_IDS_FLAG_NAME] ?? - (await input({ message: "Enter comma-separated deal ids" })), + (await input({ + message: "Enter comma-separated deal ids", + validate(val: string) { + return ( + commaSepStrToArr(val).length > 0 || + "Please enter at least one deal id" + ); + }, + })), ); if (dealIds.length === 0) { - return commandObj.error("Got empty list of deal ids. Aborting"); + return commandObj.error("No deal ids provided"); } const { contracts } = await getContracts(); diff --git a/packages/cli/package/src/commands/spell/build.ts b/packages/cli/package/src/commands/spell/build.ts index faa8fcf58..0d5cd66db 100644 --- a/packages/cli/package/src/commands/spell/build.ts +++ b/packages/cli/package/src/commands/spell/build.ts @@ -46,10 +46,12 @@ export default class Build extends BaseCommand { args["SPELL-NAMES"] ?? Object.keys(fluenceConfig.spells ?? {}).join(","), ); - await compileSpells(flags.import, spellNames); + if (spellNames.length > 0) { + await compileSpells(flags.import, spellNames); - commandObj.log( - `Compiled ${color.yellow(spellNames.join(", "))} successfully`, - ); + commandObj.log( + `Compiled ${color.yellow(spellNames.join(", "))} successfully`, + ); + } } } diff --git a/packages/cli/package/src/commands/workers/logs.ts b/packages/cli/package/src/commands/workers/logs.ts index 858a15b09..7c953fdf1 100644 --- a/packages/cli/package/src/commands/workers/logs.ts +++ b/packages/cli/package/src/commands/workers/logs.ts @@ -162,6 +162,12 @@ const getLogsArg = async ({ ? workerNamesSet : commaSepStrToArr(maybeWorkerNamesString); + if (workersToGetLogsFor.length === 0) { + commandObj.error( + `No worker names provided. Please provide worker names to get logs for`, + ); + } + const workerNamesNotFoundInWorkersConfig = workersToGetLogsFor.filter( (workerName) => { return !workerNamesSet.includes(workerName); diff --git a/packages/cli/package/src/commands/workers/remove.ts b/packages/cli/package/src/commands/workers/remove.ts index 7dae1f69b..430063140 100644 --- a/packages/cli/package/src/commands/workers/remove.ts +++ b/packages/cli/package/src/commands/workers/remove.ts @@ -77,6 +77,10 @@ export default class Remove extends BaseCommand { ? Object.keys(deployedWorkersForEnv) : commaSepStrToArr(args["WORKER-NAMES"]); + if (workersToRemove.length === 0) { + return commandObj.error("No worker names provided"); + } + const deployedWorkersForEnvArr = Object.entries(deployedWorkersForEnv); const removeArg: RemoveArgWorkers = { diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 06b0c6f64..3b7b93d4a 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -15,14 +15,11 @@ * along with this program. If not, see . */ -import type { CommitmentStatus, ICapacity } from "@fluencelabs/deal-ts-clients"; +import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { color } from "@oclif/color"; -import isUndefined from "lodash-es/isUndefined.js"; -import omitBy from "lodash-es/omitBy.js"; import parse from "parse-duration"; import { yamlDiffPatch } from "yaml-diff-patch"; -import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { initProviderConfig } from "../configs/project/provider/provider.js"; import { @@ -34,15 +31,16 @@ import { } from "../const.js"; import { dbg } from "../dbg.js"; import { - batchRead, getContracts, getEventValues, signBatch, populateTx, - getReadonlyContracts, sign, - getDealExplorerClient, + multicallRead, + type MulticallReadItem, } from "../dealClient.js"; +import { ccIds, ccIdsAndStatuses, ccDetails } from "../gql/gql.js"; +import type { CapacityCommitmentStatus } from "../gql/gqlGenerated.js"; import { bigintSecondsToDate } from "../helpers/bigintOps.js"; import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; @@ -54,8 +52,9 @@ import { } from "../resolveComputePeersByNames.js"; import { - peerIdHexStringToBase58String, peerIdBase58ToUint8Array, + peerIdBase58ToHexString, + peerIdHexStringToBase58String, } from "./conversions.js"; import { fltFormatWithSymbol } from "./currencies.js"; @@ -65,94 +64,80 @@ export type ComputePeersWithCC = Awaited< ReturnType >; -export async function getComputePeersWithCC( - computePeers: ResolvedComputePeer[], -) { - const { readonlyContracts } = await getReadonlyContracts(); - - const commitmentCreatedEvents = Object.fromEntries( - await Promise.all( - ( - await readonlyContracts.diamond.queryFilter( - readonlyContracts.diamond.filters.CommitmentCreated, - ) - ).map(async (event) => { - return [ - await peerIdHexStringToBase58String(event.args.peerId), - event, - ] as const; - }), - ), - ); - - const { ZeroHash } = await import("ethers"); - - const computePeersWithChainInfo = ( - await Promise.all( - computePeers.map(async (computePeer) => { - const peerIdUint8Array = await peerIdBase58ToUint8Array( - computePeer.peerId, - ); +type CommitmentAndPeerId = { id: string; peer: { id: string } }; + +async function getComputePeersWithCC( + [firstComputePeer, ...restComputePeers]: [ + ResolvedComputePeer, + ...ResolvedComputePeer[], + ], + getCCByHexPeerId: ( + hexPeerIds: [string, ...string[]], + ) => Promise<{ capacityCommitments: T[] }>, +): Promise< + [ + { + name: string; + infoFromSubgraph: T; + }, + ...{ + name: string; + infoFromSubgraph: T; + }[], + ] +> { + const computePeersWithHexPeerIds = await Promise.all([ + (async () => { + return { + ...firstComputePeer, + hexPeerId: await peerIdBase58ToHexString(firstComputePeer.peerId), + }; + })(), + ...restComputePeers.map(async (computePeer) => { + return { + ...computePeer, + hexPeerId: await peerIdBase58ToHexString(computePeer.peerId), + }; + }), + ]); - const commitmentCreatedEvent = - commitmentCreatedEvents[computePeer.peerId]; + const [firstComputePeerWithHexPeerId, ...restComputePeersWithHexPeerIds] = + computePeersWithHexPeerIds; - const marketGetComputePeerRes = await (async () => { - try { - return await readonlyContracts.diamond.getComputePeer( - peerIdUint8Array, - ); - } catch { - return undefined; - } - })(); + const { capacityCommitments } = await getCCByHexPeerId([ + firstComputePeerWithHexPeerId.hexPeerId, + ...restComputePeersWithHexPeerIds.map(({ hexPeerId }) => { + return hexPeerId; + }), + ]); - return { - providerConfigComputePeer: computePeer, - ...(commitmentCreatedEvent === undefined - ? {} - : { - commitmentCreatedEvent, - }), - ...(marketGetComputePeerRes === undefined - ? {} - : { - marketGetComputePeerRes, - }), - }; - }), - ) - ).map((c) => { - const commitmentId = - c.commitmentCreatedEvent?.args.commitmentId ?? - c.marketGetComputePeerRes?.commitmentId; - - if (commitmentId === undefined || commitmentId === ZeroHash) { - return c; - } + const ccInfoByHexPeerId = capacityCommitments.reduce>( + (acc, cc) => { + acc[cc.peer.id] = cc; + return acc; + }, + {}, + ); - return { ...c, commitmentId }; - }); + const { ZeroHash } = await import("ethers"); - const [computePeersWithoutCCId, computePeersWithCCId] = splitErrorsAndResults( - computePeersWithChainInfo, - (computePeerWithChainInfo) => { - if ("commitmentId" in computePeerWithChainInfo) { - return { - result: computePeerWithChainInfo, - }; - } + const [computePeersWithoutCC, computePeersWithCC] = splitErrorsAndResults( + computePeersWithHexPeerIds, + ({ hexPeerId, name, peerId }) => { + const infoFromSubgraph = ccInfoByHexPeerId[hexPeerId]; - return { - error: computePeerWithChainInfo, - }; + return infoFromSubgraph === undefined || infoFromSubgraph.id === ZeroHash + ? { error: { name, peerId } } + : { + result: { name, infoFromSubgraph } satisfies CapacityCommitment, + }; }, ); - if (computePeersWithoutCCId.length > 0) { + if (computePeersWithoutCC.length > 0) { commandObj.warn( - `Some of the commitments are not found on chain for:\n${computePeersWithoutCCId - .map(({ providerConfigComputePeer: { name, peerId } }) => { + `Some of the commitments were not found for:\n${computePeersWithoutCC + .map(({ name, peerId }) => { return `Nox: ${name}, PeerId: ${peerId}`; }) .join( @@ -161,13 +146,56 @@ export async function getComputePeersWithCC( ); } - if (computePeersWithCCId.length === 0) { + const [firstComputePeerWithCC, ...restComputePeersWithCC] = + computePeersWithCC; + + if (firstComputePeerWithCC === undefined) { return commandObj.error( - "No compute peers with capacity commitments were found on chain.", + "No compute peers with capacity commitments were found", ); } - return computePeersWithCCId; + return [firstComputePeerWithCC, ...restComputePeersWithCC]; +} + +async function getCCs( + ccIds: [string, ...string[]], + getCCByCCIds: ( + ccIds: [string, ...string[]], + ) => Promise<{ capacityCommitments: T[] }>, +) { + const { capacityCommitments } = await getCCByCCIds(ccIds); + + const ccInfoByCCId = capacityCommitments.reduce>( + (acc, cc) => { + acc[cc.id] = cc; + return acc; + }, + {}, + ); + + const { ZeroHash } = await import("ethers"); + + const [ccIdsWithoutInfo, ccInfos] = splitErrorsAndResults(ccIds, (ccId) => { + const infoFromSubgraph = ccInfoByCCId[ccId]; + return infoFromSubgraph === undefined || infoFromSubgraph.id === ZeroHash + ? { error: ccId } + : { result: { infoFromSubgraph } satisfies CapacityCommitment }; + }); + + if (ccIdsWithoutInfo.length > 0) { + commandObj.warn( + `Some of the commitments were not found:\n${ccIdsWithoutInfo.join("\n")}`, + ); + } + + const [firstCCInfo, ...restCCInfos] = ccInfos; + + if (firstCCInfo === undefined) { + return commandObj.error("No commitments were found"); + } + + return [firstCCInfo, ...restCCInfos]; } export type CCFlags = { @@ -176,29 +204,77 @@ export type CCFlags = { [CC_IDS_FLAG_NAME]?: string | undefined; }; -export async function getCommitments( +export async function getCommitments< + T extends { id: string; peer: { id: string } }, +>( flags: CCFlags, -): Promise<{ commitmentId: string }[] | ComputePeersWithCC> { + { + getCCByCCId, + getCCByHexPeerId, + }: { + getCCByCCId: ( + ccIds: [string, ...string[]], + ) => Promise<{ capacityCommitments: T[] }>; + getCCByHexPeerId: ( + hexPeerIds: [string, ...string[]], + ) => Promise<{ capacityCommitments: T[] }>; + }, +): Promise<[CapacityCommitment, ...CapacityCommitment[]]> { if (flags[CC_IDS_FLAG_NAME] !== undefined) { - return commaSepStrToArr(flags[CC_IDS_FLAG_NAME]).map((commitmentId) => { - return { commitmentId }; - }); + const [firstCCId, ...restCCIds] = commaSepStrToArr(flags[CC_IDS_FLAG_NAME]); + + if (firstCCId === undefined) { + return commandObj.error("No commitment ids specified"); + } + + const [firstCC, ...restCCs] = await getCCs( + [firstCCId, ...restCCIds], + getCCByCCId, + ); + + if (firstCC === undefined) { + return commandObj.error("No commitment ids specified"); + } + + return [firstCC, ...restCCs]; } if ( flags[NOX_NAMES_FLAG_NAME] === undefined && (await initProviderConfig()) === null ) { - return commaSepStrToArr( + const [firstCCId, ...restCCIds] = commaSepStrToArr( await input({ message: "Enter comma-separated list of Capacity Commitment IDs", + validate(val: string) { + return ( + commaSepStrToArr(val).length > 0 || + "Please enter at least one commitment id" + ); + }, }), - ).map((commitmentId) => { - return { commitmentId }; - }); + ); + + if (firstCCId === undefined) { + return commandObj.error("No commitment ids provided"); + } + + const [firstCC, ...restCCs] = await getCCs( + [firstCCId, ...restCCIds], + getCCByCCId, + ); + + if (firstCC === undefined) { + return commandObj.error("No commitment ids specified"); + } + + return [firstCC, ...restCCs]; } - return getComputePeersWithCC(await resolveComputePeersByNames(flags)); + return getComputePeersWithCC( + await resolveComputePeersByNames(flags), + getCCByHexPeerId, + ); } export async function createCommitments(flags: { @@ -277,12 +353,20 @@ export async function createCommitments(flags: { if (createCommitmentsTxsErrors.length > 0) { return commandObj.error( - `Failed to create commitments for some of the compute peers:\n${createCommitmentsTxsErrors.join( + `Failed to populate transactions to create commitments for some of the compute peers:\n${createCommitmentsTxsErrors.join( "\n", )}`, ); } + const [firstCommitmentTx, ...restCommitmentTxs] = createCommitmentsTxs; + + if (firstCommitmentTx === undefined) { + throw new Error( + "Unreachable. First commitment tx can't be undefined cause it is checked in resolveComputePeersByNames", + ); + } + let createCommitmentsTxReceipts; try { @@ -292,7 +376,7 @@ export async function createCommitments(flags: { return `Nox: ${name}\nPeerId: ${peerId}`; }) .join("\n\n")}`, - createCommitmentsTxs, + [firstCommitmentTx, ...restCommitmentTxs], ); } catch (e) { const errorString = stringifyUnknown(e); @@ -310,12 +394,6 @@ export async function createCommitments(flags: { throw e; } - if (createCommitmentsTxReceipts === undefined) { - return commandObj.error( - "The are no compute peers to create commitments for", - ); - } - const commitmentIds = createCommitmentsTxReceipts.flatMap((txReceipt) => { return getEventValues({ txReceipt, @@ -338,7 +416,7 @@ export async function createCommitments(flags: { if (notStringCommitmentIds.length > 0) { return commandObj.error( - `Wasn't able to get id for some of the commitments. Got: ${notStringCommitmentIds.join( + `Wasn't able to get ids for some of the commitments. Got: ${notStringCommitmentIds.join( ", ", )}`, ); @@ -350,80 +428,71 @@ export async function createCommitments(flags: { )}`, ); - await printCommitmentsInfo({ - "nox-names": computePeers - .map(({ name }) => { - return name; - }) - .join(", "), - }); + commandObj.logToStderr( + stringifyDetailedCommitmentsInfo( + await getDetailedCommitmentsInfoGroupedByStatus({ + "nox-names": computePeers + .map(({ name }) => { + return name; + }) + .join(", "), + }), + ), + ); } export async function removeCommitments(flags: CCFlags) { - const commitments = await getCommitments(flags); - const { contracts } = await getContracts(); - - const [commitmentInfoErrors, commitmentInfo] = splitErrorsAndResults( - await Promise.all( - commitments.map(async (commitment) => { - try { - return { - result: { - commitment, - info: await contracts.diamond.getCommitment( - commitment.commitmentId, - ), - }, - }; - } catch (error) { - return { error: { commitment, error } }; - } - }), - ), - (res) => { - return res; + const [invalidCommitments, commitments] = splitErrorsAndResults( + await getCommitments(flags, ccIdsAndStatuses), + (cc) => { + return cc.infoFromSubgraph.status === "WaitDelegation" + ? { result: cc } + : { error: cc }; }, ); - if (commitmentInfoErrors.length > 0) { - commandObj.error( - `Wasn't able to get commitments from chain:\n${commitmentInfoErrors - .map(({ commitment, error }) => { - return `${stringifyBasicCommitmentInfo(commitment)}\n\n${color.red( - stringifyUnknown(error), - )}`; - }) - .join("\n\n")}`, + if (invalidCommitments.length > 0) { + commandObj.warn( + `You can remove commitments only if they have WaitDelegation status. Got:\n\n${( + await Promise.all( + invalidCommitments.map(async (cc) => { + return `${await stringifyBasicCommitmentInfo(cc)}Status: ${ccStatusToString( + cc.infoFromSubgraph.status, + )}`; + }), + ) + ).join("\n\n")}`, ); } - const { CommitmentStatus } = await import("@fluencelabs/deal-ts-clients"); + const [firstCommitment, ...restCommitments] = commitments; - const commitmentsWithInvalidStatus = commitmentInfo.filter(({ info }) => { - return Number(info.status) !== Number(CommitmentStatus.WaitDelegation); - }); - - if (commitmentsWithInvalidStatus.length > 0) { - commandObj.error( - `You can remove commitments only if they have WaitDelegation status. Got:\n\n${commitmentsWithInvalidStatus - .map(({ commitment, info }) => { - return `${stringifyBasicCommitmentInfo(commitment)}Status: ${ - CommitmentStatus[Number(info.status)] ?? "Unknown" - }`; - }) - .join("\n\n")}`, + if (firstCommitment === undefined) { + return commandObj.error( + "No commitments with 'WaitDelegation' status found", ); } + const { contracts } = await getContracts(); + await signBatch( `Remove the following commitments:\n\n${commitments .map((commitment) => { return stringifyBasicCommitmentInfo(commitment); }) .join("\n\n")}`, - commitments.map(({ commitmentId }) => { - return populateTx(contracts.diamond.removeCommitment, commitmentId); - }), + [ + populateTx( + contracts.diamond.removeCommitment, + firstCommitment.infoFromSubgraph.id, + ), + ...restCommitments.map(({ infoFromSubgraph }) => { + return populateTx( + contracts.diamond.removeCommitment, + infoFromSubgraph.id, + ); + }), + ], ); commandObj.logToStderr( @@ -441,25 +510,19 @@ export async function collateralWithdraw( }, ) { const { ZeroAddress } = await import("ethers"); - const { CommitmentStatus } = await import("@fluencelabs/deal-ts-clients"); const [invalidCommitments, commitments] = splitErrorsAndResults( - await getCommitmentsInfo(flags), + await getCommitmentsGroupedByStatus(flags, ccIdsAndStatuses), (c) => { - if ( - c.status === CommitmentStatus.Inactive || - c.status === CommitmentStatus.Failed - ) { - return { result: c }; - } - - return { error: c }; + return c.status === "Completed" || c.status === "Failed" + ? { result: c } + : { error: c }; }, ); if (invalidCommitments.length > 0) { commandObj.warn( - `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( + `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( invalidCommitments, )}`, ); @@ -476,28 +539,52 @@ export async function collateralWithdraw( for (const commitment of commitments.flatMap(({ ccInfos }) => { return ccInfos; })) { - const { commitmentId, noxName } = commitment; + const { + infoFromSubgraph: { id: commitmentId }, + name: noxName, + } = commitment; const [unitIds, isExitedStatuses] = await contracts.diamond.getUnitExitStatuses(commitmentId); - const units = await batchRead( - unitIds.map((unitId, i) => { - return async () => { - return { - unitId, - unitInfo: await contracts.diamond.getComputeUnit(unitId), - isExited: - isExitedStatuses[i] ?? - (() => { - throw new Error( - `Unreachable. No exit status returned from getUnitExitStatuses for unit ${unitId}`, - ); - })(), - }; + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const computeUnitInfos = (await multicallRead( + unitIds.map((unitId): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getComputeUnit", + [unitId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getComputeUnit", + returnData, + ); + }, }; }), - ); + )) as Awaited>[]; + + const units = unitIds.map((unitId, i) => { + return { + unitId, + unitInfo: + computeUnitInfos[i] ?? + (() => { + throw new Error( + `Unreachable. Unit ${unitId} not found after running getComputeUnit`, + ); + })(), + isExited: + isExitedStatuses[i] ?? + (() => { + throw new Error( + `Unreachable. No exit status returned from getUnitExitStatuses for unit ${unitId}`, + ); + })(), + }; + }); const unitsWithDeals = units.filter((unit) => { return unit.unitInfo.deal !== ZeroAddress; @@ -528,6 +615,9 @@ export async function collateralWithdraw( }); }); + const [firstMoveResourcesFromDealTx, ...restMoveResourcesFromDealTxs] = + moveResourcesFromDealTxs; + const dealsString = Array.from( new Set( unitsWithDeals.map(({ unitInfo }) => { @@ -536,28 +626,30 @@ export async function collateralWithdraw( ), ).join("\n"); - try { - await signBatch( - `Moving resources from the following deals:\n${dealsString}`, - moveResourcesFromDealTxs, - ); - } catch (e) { - commandObj.warn( - `Wasn't able to move resources from deals for ${stringifyBasicCommitmentInfo(commitment)}. Most likely the reason is you must wait until the provider exits from all the following deals:\n${dealsString}`, - ); + if (firstMoveResourcesFromDealTx !== undefined) { + try { + await signBatch( + `Moving resources from the following deals:\n${dealsString}`, + [firstMoveResourcesFromDealTx, ...restMoveResourcesFromDealTxs], + ); + } catch (e) { + commandObj.warn( + `Wasn't able to move resources from deals for ${await stringifyBasicCommitmentInfo(commitment)}. Most likely the reason is you must wait until the provider exits from all the following deals:\n${dealsString}`, + ); - dbg(stringifyUnknown(e)); - continue; + dbg(stringifyUnknown(e)); + continue; + } } await sign({ - title: `withdraw collateral from: ${commitment.commitmentId}`, + title: `withdraw collateral from: ${commitmentId}`, method: contracts.diamond.withdrawCollateral, args: [commitmentId], }); commandObj.logToStderr( - `Collateral withdrawn for:\n${stringifyBasicCommitmentInfo(commitment)}`, + `Collateral withdrawn for:\n${await stringifyBasicCommitmentInfo(commitment)}`, ); const shouldFinishCommitment = flags[FINISH_COMMITMENT_FLAG_NAME] ?? true; // for provider it's true by default @@ -566,373 +658,507 @@ export async function collateralWithdraw( continue; } + const [firstNotExitedUnit, ...restNotExitedUnits] = units.filter( + ({ isExited }) => { + return !isExited; + }, + ); + await signBatch( - `Remove compute units from capacity commitments and finish commitment ${noxName === undefined ? commitmentId : `for ${noxName} (${commitmentId})`} ${commitmentId}`, - [ - ...units - .filter(({ isExited }) => { - return !isExited; - }) - .map(({ unitId }) => { - return populateTx(contracts.diamond.removeCUFromCC, commitmentId, [ - unitId, - ]); - }), - populateTx(contracts.diamond.finishCommitment, commitmentId), - ], + `${firstNotExitedUnit === undefined ? "F" : "Remove compute units from capacity commitments and f"}inish commitment ${noxName === undefined ? commitmentId : `for ${noxName} (${commitmentId})`} ${commitmentId}`, + firstNotExitedUnit === undefined + ? [populateTx(contracts.diamond.finishCommitment, commitmentId)] + : [ + populateTx(contracts.diamond.removeCUFromCC, commitmentId, [ + firstNotExitedUnit.unitId, + ]), + ...restNotExitedUnits.map(({ unitId }) => { + return populateTx( + contracts.diamond.removeCUFromCC, + commitmentId, + [unitId], + ); + }), + populateTx(contracts.diamond.finishCommitment, commitmentId), + ], ); } } export async function collateralRewardWithdraw(flags: CCFlags) { - const commitments = await getCommitments(flags); + const commitments = await getCommitments(flags, ccIds); + const [firstCommitment, ...restCommitments] = commitments; const { contracts } = await getContracts(); - // TODO: add logs here await signBatch( `Withdraw rewards for commitments:\n\n${commitments - .map(({ commitmentId }) => { - return commitmentId; + .map(({ infoFromSubgraph: { id } }) => { + return id; }) .join("\n")}`, - commitments.map(({ commitmentId }) => { - return populateTx(contracts.diamond.withdrawReward, commitmentId); - }), + [ + populateTx( + contracts.diamond.withdrawReward, + firstCommitment.infoFromSubgraph.id, + ), + ...restCommitments.map(({ infoFromSubgraph: { id } }) => { + return populateTx(contracts.diamond.withdrawReward, id); + }), + ], ); } -export function stringifyBasicCommitmentInfo( - commitment: - | Awaited>[number] - | Awaited>[number]["ccInfos"][number], -) { - if ("providerConfigComputePeer" in commitment) { - return `${color.yellow( - `Nox: ${commitment.providerConfigComputePeer.name}`, - )}\n${yamlDiffPatch( - "", - {}, - { - PeerId: commitment.providerConfigComputePeer.peerId, - CommitmentId: commitment.commitmentId, - }, - )}`; - } +export async function stringifyBasicCommitmentInfo< + T extends CommitmentAndPeerId, +>({ name, infoFromSubgraph }: CapacityCommitment) { + const peerId = await peerIdHexStringToBase58String(infoFromSubgraph.peer.id); + const noxName = name === undefined ? "" : `Nox: ${name}\n`; + return `${color.yellow(`${noxName}PeerId: ${peerId}`)}\nCommitmentId: ${infoFromSubgraph.id}`; +} - if ("noxName" in commitment) { - return `${color.yellow(`Nox: ${commitment.noxName}`)}\n${yamlDiffPatch( - "", - {}, - { - PeerId: commitment.peerId, - CommitmentId: commitment.commitmentId, - }, - )}`; - } +type StatusCommitmentAndPeerId = CommitmentAndPeerId & { + status?: CapacityCommitmentStatus | null; +}; - return color.yellow(`CommitmentId: ${commitment.commitmentId}`); -} +type CapacityCommitment = { + infoFromSubgraph: T; + name?: string; +}; -export async function getCommitmentsInfo(flags: CCFlags) { - const { readonlyContracts } = await getReadonlyContracts(); - const { CommitmentStatus } = await import("@fluencelabs/deal-ts-clients"); +type CommitmentGroupedByStatus = { + status: ReturnType; + ccInfos: CapacityCommitment[]; +}[]; - const [ - commitments, - currentEpoch, - epochDuration, - initTimestamp, - maxFailedRatio, - ] = await Promise.all([ - getCommitments(flags), - readonlyContracts.diamond.currentEpoch(), - readonlyContracts.diamond.epochDuration(), - readonlyContracts.diamond.initTimestamp(), - readonlyContracts.diamond.maxFailedRatio(), - ]); +export async function getCommitmentsGroupedByStatus< + T extends StatusCommitmentAndPeerId, +>( + ...args: Parameters> +): Promise> { + return Array.from( + (await getCommitments(...args)) + .reduce[]>>( + (acc, v) => { + const status = ccStatusToString(v.infoFromSubgraph.status); + const infos = acc.get(status) ?? []; + infos.push(v); + acc.set(status, infos); + return acc; + }, + new Map(), + ) + .entries(), + ).map(([status, ccInfos]) => { + return { status, ccInfos }; + }); +} - const dealExplorerClient = await getDealExplorerClient(); - - const commitmentsInfo = await Promise.all( - commitments.map(async (c) => { - let commitment: Partial = - "commitmentCreatedEvent" in c - ? { - peerId: c.commitmentCreatedEvent.args.peerId, - rewardDelegatorRate: - c.commitmentCreatedEvent.args.rewardDelegationRate, - collateralPerUnit: - c.commitmentCreatedEvent.args.fltCollateralPerUnit, - delegator: c.commitmentCreatedEvent.args.delegator, - } - : {}; +function stakerRewardToString(stakerReward: bigint, precision: bigint) { + return `${numToStr( + (Number(stakerReward) * HUNDRED_PERCENT) / Number(precision), + )}%`; +} - try { - commitment = await readonlyContracts.diamond.getCommitment( - c.commitmentId, +function getRewardsMulticallReads( + commitmentId: string, + diamondContract: Contracts["diamond"], + diamondContractAddress: string, +): MulticallReadItem[] { + return [ + { + target: diamondContractAddress, + callData: diamondContract.interface.encodeFunctionData( + "unlockedRewards", + [commitmentId], + ), + decode(returnData) { + return diamondContract.interface.decodeFunctionResult( + "unlockedRewards", + returnData, ); - } catch (e) { - dbg( - `Failed to get commitment from chain ${c.commitmentId}. Error: ${stringifyUnknown(e)}`, + }, + }, + { + target: diamondContractAddress, + callData: diamondContract.interface.encodeFunctionData("totalRewards", [ + commitmentId, + ]), + decode(returnData) { + return diamondContract.interface.decodeFunctionResult( + "totalRewards", + returnData, ); - } - - const cuFailThreshold = - commitment.unitCount === undefined - ? undefined - : maxFailedRatio * commitment.unitCount; + }, + }, + ]; +} - let ccFromExplorer: Awaited< - ReturnType - > = null; +export async function getDetailedCommitmentsInfoGroupedByStatus( + flags: CCFlags, +) { + const ccGroupedByStatus = await getCommitmentsGroupedByStatus( + flags, + ccDetails, + ); - try { - ccFromExplorer = await dealExplorerClient.getCapacityCommitment( - c.commitmentId, - ); - } catch (e) { - dbg( - `Failed to get commitment ${c.commitmentId} from explorer. Error: ${stringifyUnknown( - e, - )}`, - ); - } + const { contracts } = await getContracts(); - const ccStartDate = - commitment.startEpoch === undefined - ? undefined - : bigintSecondsToDate( - initTimestamp + commitment.startEpoch * epochDuration, - ); + const allCCIds = ccGroupedByStatus.flatMap(({ ccInfos }) => { + return ccInfos.map(({ infoFromSubgraph: { id } }) => { + return id; + }); + }); - const ccEndDate = - commitment.endEpoch === undefined - ? undefined - : bigintSecondsToDate( - initTimestamp + commitment.endEpoch * epochDuration, - ); + const rewardsMulticallReads = allCCIds.flatMap((id) => { + return getRewardsMulticallReads( + id, + contracts.diamond, + contracts.deployment.diamond, + ); + }); - const status = Number(commitment.status); + const contractReadsPerCC = rewardsMulticallReads.length / allCCIds.length; + const [ + currentEpoch, + epochDuration, + initTimestamp, + maxFailedRatio, + precision, + ...rewards + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + ] = (await multicallRead([ + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("currentEpoch"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "currentEpoch", + returnData, + ); + }, + }, + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("epochDuration"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "epochDuration", + returnData, + ); + }, + }, + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("initTimestamp"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "initTimestamp", + returnData, + ); + }, + }, + { + target: contracts.deployment.diamond, + callData: + contracts.diamond.interface.encodeFunctionData("maxFailedRatio"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "maxFailedRatio", + returnData, + ); + }, + }, + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("precision"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "precision", + returnData, + ); + }, + }, + ...ccGroupedByStatus.flatMap(({ ccInfos }) => { + return ccInfos.flatMap(({ infoFromSubgraph: { id } }) => { + return getRewardsMulticallReads( + id, + contracts.diamond, + contracts.deployment.diamond, + ); + }); + }), + ])) as [ + Awaited>, + Awaited>, + Awaited>, + Awaited>, + Awaited>, + ...Awaited< + ReturnType< + | typeof contracts.diamond.unlockedRewards + | typeof contracts.diamond.totalRewards + > + >[], + ]; + + let rewardsCounter = -contractReadsPerCC; + + return Promise.all( + ccGroupedByStatus.map(async (groupedCCs) => { return { - ...("providerConfigComputePeer" in c - ? { - noxName: c.providerConfigComputePeer.name, - peerId: c.providerConfigComputePeer.peerId, - } - : {}), - ccFromExplorer, - commitmentId: c.commitmentId, - status: status in CommitmentStatus ? status : undefined, - currentEpoch: bigintToStr(currentEpoch), - startEpoch: optBigIntToStr(commitment.startEpoch), - startDate: ccStartDate, - endEpoch: optBigIntToStr(commitment.endEpoch), - endDate: ccEndDate, - stakerReward: await stakerRewardToString( - commitment.rewardDelegatorRate, + statusInfo: groupedCCs, + CCs: await Promise.all( + groupedCCs.ccInfos.map(async (cc) => { + rewardsCounter = rewardsCounter + contractReadsPerCC; + + return getDetailedCommitmentInfo({ + ...cc, + currentEpoch, + epochDuration, + initTimestamp, + maxFailedRatio, + precision, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + unlockedRewards: rewards[rewardsCounter] as Awaited< + ReturnType + >, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + totalRewards: rewards[rewardsCounter + 1] as Awaited< + ReturnType + >, + }); + }), ), - delegator: commitment.delegator, - totalCU: optBigIntToStr(commitment.unitCount), - failedEpoch: optBigIntToStr(commitment.failedEpoch), - totalCUFailCount: optBigIntToStr(commitment.totalFailCount), - cuFailThreshold: optBigIntToStr(cuFailThreshold), - collateralPerUnit: commitment.collateralPerUnit, - exitedUnitCount: optBigIntToStr(commitment.exitedUnitCount), }; }), ); - - // group commitments by status - return Array.from( - commitmentsInfo - .reduce< - Map - >((acc, v) => { - const infos = acc.get(v.status) ?? []; - infos.push(v); - - acc.set( - v.status !== undefined && v.status in CommitmentStatus - ? v.status - : undefined, - infos, - ); - - return acc; - }, new Map()) - .entries(), - ).map(([status, ccInfos]) => { - return { status, ccInfos }; - }); -} - -function optBigIntToStr(value: bigint | undefined) { - return value === undefined ? undefined : bigintToStr(value); } -async function stakerRewardToString(stakerReward: bigint | undefined) { - if (stakerReward === undefined) { - return undefined; - } - - const { readonlyContracts } = await getReadonlyContracts(); - const precision = await readonlyContracts.diamond.precision(); - return `${numToStr( - (Number(stakerReward) * HUNDRED_PERCENT) / Number(precision), - )}%`; -} - -export async function printCommitmentsInfo(flags: CCFlags) { - const ccInfos = await getCommitmentsInfo(flags); - - commandObj.logToStderr( - ( - await Promise.all( - ccInfos.map(async ({ status, ccInfos }) => { - return `${await getStatusHeading(status, ccInfos)}${( - await Promise.all( - ccInfos.map(async (ccInfo) => { - const noxName = - ccInfo.noxName === undefined - ? "" - : color.yellow(`Nox: ${ccInfo.noxName}\n`); - - return `${noxName}${await getCommitmentInfoString(ccInfo)}`; - }), - ) - ).join("\n\n")}`; - }), - ) - ).join("\n\n"), - ); +export function stringifyDetailedCommitmentsInfo( + detailedCommitmentsInfoGroupedByStatus: Awaited< + ReturnType + >, +) { + return detailedCommitmentsInfoGroupedByStatus + .map(({ statusInfo, CCs }) => { + return `${getStatusHeading(statusInfo)}${CCs.map((cc) => { + const noxNameString = + "noxName" in cc ? color.yellow(`Nox: ${cc.noxName}\n`) : ""; + + return `${noxNameString}${getDetailedCommitmentInfoString(cc)}`; + }).join("\n\n")}`; + }) + .join("\n\n"); } -async function getStatusHeading( - status: CommitmentStatus | undefined, - ccInfos: { noxName?: undefined | string; commitmentId: string }[], +function getStatusHeading( + cc: CommitmentGroupedByStatus[number], ) { return color.yellow( - `Status: ${await ccStatusToString(status)} (${ccInfos - .map(({ commitmentId, noxName }) => { - return noxName ?? commitmentId; + `Status: ${cc.status} (${cc.ccInfos + .map(({ infoFromSubgraph: { id }, name }) => { + return name ?? id; }) .join(",")})\n\n`, ); } -export async function printCommitmentsInfoJSON(flags: CCFlags) { - commandObj.log(jsonStringify(await getCommitmentsInfo(flags))); -} +type DetailedCCInfo = Awaited< + ReturnType< + typeof getCommitmentsGroupedByStatus< + Awaited< + ReturnType<(typeof ccDetails)["getCCByCCId"]> + >["capacityCommitments"][number] + > + > +>[number]["ccInfos"][number]; + +async function getDetailedCommitmentInfo({ + infoFromSubgraph: { + id: commitmentId, + status, + startEpoch, + endEpoch, + delegator, + computeUnitsCount, + totalFailCount, + collateralPerUnit, + exitedUnitCount, + rewardDelegatorRate, + ccRewardsWithdrawn, + dealStakerRewardsWithdrawn, + peer: { id: peerId }, + }, + name: noxName, + currentEpoch, + epochDuration, + initTimestamp, + maxFailedRatio, + precision, + totalRewards, + unlockedRewards, +}: DetailedCCInfo & { + currentEpoch: bigint; + epochDuration: bigint; + initTimestamp: bigint; + maxFailedRatio: bigint; + precision: bigint; + totalRewards: Rewards; + unlockedRewards: Rewards; +}) { + const rewardDelegatorRateBigInt = BigInt(rewardDelegatorRate); -async function getCommitmentInfoString( - ccInfo: Awaited< - ReturnType - >[number]["ccInfos"][number], -) { - const { ZeroAddress } = await import("ethers"); + const totalRewardsSplit = splitRewards( + totalRewards, + rewardDelegatorRateBigInt, + precision, + ); - const staker = - ccInfo.delegator ?? ccInfo.ccFromExplorer?.stakerAddress ?? undefined; + const unlockedRewardsSplit = splitRewards( + unlockedRewards, + rewardDelegatorRateBigInt, + precision, + ); - const startEndCurrentEpoch = - ccInfo.startEpoch === undefined || ccInfo.endEpoch === undefined - ? undefined - : [ccInfo.startEpoch, ccInfo.endEpoch, ccInfo.currentEpoch].join(" / "); + const withdrawnRewardsSplit = splitRewards( + { + ccRewards: BigInt(ccRewardsWithdrawn), + dealStakerRewards: BigInt(dealStakerRewardsWithdrawn), + }, + rewardDelegatorRateBigInt, + precision, + ); - const missedProofsThreshold = - ccInfo.totalCUFailCount === undefined || - ccInfo.cuFailThreshold === undefined - ? undefined - : [ccInfo.totalCUFailCount, ccInfo.cuFailThreshold].join(" / "); + return { + ...(noxName === undefined ? {} : { noxName }), + peerId: await peerIdHexStringToBase58String(peerId), + commitmentId, + status: ccStatusToString(status), + staker: + delegator?.id === (await import("ethers")).ZeroAddress + ? "Anyone can activate capacity commitment" + : (delegator?.id ?? "Unknown"), + stakerReward: stakerRewardToString(rewardDelegatorRateBigInt, precision), + startEpoch, + endEpoch, + currentEpoch: bigintToStr(currentEpoch), + startDate: bigintSecondsToDate( + initTimestamp + BigInt(startEpoch) * epochDuration, + ).toLocaleString(), + expirationDate: bigintSecondsToDate( + initTimestamp + BigInt(endEpoch) * epochDuration, + ).toLocaleString(), + totalCU: numToStr(computeUnitsCount), + missedProofs: numToStr(totalFailCount), + threshold: bigintToStr(maxFailedRatio * BigInt(computeUnitsCount)), + collateralPerUnit: await fltFormatWithSymbol(BigInt(collateralPerUnit)), + exitedUnitCount: numToStr(exitedUnitCount), + totalCCRewardsOverTime: await fltFormatWithSymbol( + BigInt(totalRewards.ccRewards) + BigInt(totalRewards.dealStakerRewards), + ), + providerRewardsInVesting: await fltFormatWithSymbol( + totalRewardsSplit.provider - unlockedRewardsSplit.provider, + ), + providerRewardsAvailable: await fltFormatWithSymbol( + unlockedRewardsSplit.provider, + ), + providerRewardsTotalClaimed: await fltFormatWithSymbol( + withdrawnRewardsSplit.provider, + ), + stakerRewardsInVesting: await fltFormatWithSymbol( + totalRewardsSplit.staker - unlockedRewardsSplit.staker, + ), + stakerRewardsAvailable: await fltFormatWithSymbol( + unlockedRewardsSplit.staker, + ), + stakerRewardsTotalClaimed: await fltFormatWithSymbol( + withdrawnRewardsSplit.staker, + ), + } satisfies Record; +} +function getDetailedCommitmentInfoString( + detailedCommitmentInfo: Awaited>, +) { return yamlDiffPatch( "", {}, - omitBy( - { - PeerId: ccInfo.peerId, - "Capacity commitment ID": ccInfo.commitmentId, - Status: await ccStatusToString(ccInfo.status), - Staker: - staker === ZeroAddress - ? "Anyone can activate capacity commitment" - : staker, - "Staker reward": - ccInfo.stakerReward === undefined ? undefined : ccInfo.stakerReward, - "Start / End / Current epoch": startEndCurrentEpoch, - "Start date": ccInfo.startDate?.toLocaleString(), - "Expiration date": ccInfo.endDate?.toLocaleString(), - "Total CU": ccInfo.totalCU, - "Missed proofs / Threshold": missedProofsThreshold, - "Collateral per unit": - ccInfo.collateralPerUnit === undefined - ? undefined - : await fltFormatWithSymbol(ccInfo.collateralPerUnit), - "Exited unit count": ccInfo.exitedUnitCount, - ...(ccInfo.ccFromExplorer === null - ? {} - : { - "Total CC rewards over time": await fltFormatWithSymbol( - ccInfo.ccFromExplorer.rewards.total, - ), - "In vesting / Available / Total claimed (Provider)": ( - await Promise.all( - [ - ccInfo.ccFromExplorer.rewards.provider.inVesting, - ccInfo.ccFromExplorer.rewards.provider.availableToClaim, - ccInfo.ccFromExplorer.rewards.provider.claimed, - ].map((val) => { - return fltFormatWithSymbol(val); - }), - ) - ).join(" / "), - "In vesting / Available / Total claimed (Staker)": ( - await Promise.all( - [ - ccInfo.ccFromExplorer.rewards.staker.inVesting, - ccInfo.ccFromExplorer.rewards.staker.availableToClaim, - ccInfo.ccFromExplorer.rewards.staker.claimed, - ].map((val) => { - return fltFormatWithSymbol(val); - }), - ) - ).join(" / "), - }), - } satisfies Record, - isUndefined, - ), + { + PeerId: detailedCommitmentInfo.peerId, + "Capacity commitment ID": detailedCommitmentInfo.commitmentId, + Status: detailedCommitmentInfo.status, + Staker: detailedCommitmentInfo.staker, + "Staker reward": detailedCommitmentInfo.stakerReward, + "Start / End / Current epoch": [ + detailedCommitmentInfo.startEpoch, + detailedCommitmentInfo.endEpoch, + detailedCommitmentInfo.currentEpoch, + ].join(" / "), + "Start date": detailedCommitmentInfo.startDate, + "Expiration date": detailedCommitmentInfo.expirationDate, + "Total CU": detailedCommitmentInfo.totalCU, + "Missed proofs / Threshold": [ + detailedCommitmentInfo.missedProofs, + detailedCommitmentInfo.threshold, + ].join(" / "), + "Collateral per unit": detailedCommitmentInfo.collateralPerUnit, + "Exited unit count": detailedCommitmentInfo.exitedUnitCount, + "Total CC rewards over time": + detailedCommitmentInfo.totalCCRewardsOverTime, + "In vesting / Available / Total claimed (Provider)": [ + detailedCommitmentInfo.providerRewardsInVesting, + detailedCommitmentInfo.providerRewardsAvailable, + detailedCommitmentInfo.providerRewardsTotalClaimed, + ].join(" / "), + "In vesting / Available / Total claimed (Staker)": [ + detailedCommitmentInfo.stakerRewardsInVesting, + detailedCommitmentInfo.stakerRewardsAvailable, + detailedCommitmentInfo.stakerRewardsTotalClaimed, + ].join(" / "), + }, ); } -async function ccStatusToString(status: number | undefined) { - const { CommitmentStatus } = await import("@fluencelabs/deal-ts-clients"); +type Rewards = { ccRewards: bigint; dealStakerRewards: bigint }; - if (status === undefined) { - return "Unknown"; - } +function splitRewards( + { ccRewards, dealStakerRewards }: Rewards, + stakerRate: bigint, + precision: bigint, +) { + const stakerCCReward = (ccRewards * stakerRate) / precision; + return { + provider: ccRewards - stakerCCReward, + staker: stakerCCReward + dealStakerRewards, + }; +} - const statusStr = CommitmentStatus[status]; +type CapacityCommitmentStatusString = + | "Unknown" + | Exclude + | "Completed"; - if (statusStr === undefined) { - return `Unknown (${numToStr(status)})`; +function ccStatusToString( + status: CapacityCommitmentStatus | null | undefined, +): CapacityCommitmentStatusString { + if (status === undefined || status === null) { + return "Unknown"; } - return statusStr === "Inactive" ? "Completed" : statusStr; + return status === "Inactive" ? "Completed" : status; } -export async function basicCCInfoAndStatusToString( - ccInfos: Awaited>, -) { - return ( - await Promise.all( - ccInfos.map(async ({ status, ccInfos }) => { - return `${await getStatusHeading(status, ccInfos)}${ccInfos - .map((ccInfo) => { - return stringifyBasicCommitmentInfo(ccInfo); - }) - .join("\n\n")} `; - }), - ) - ).join("\n\n"); +export function basicCCInfoAndStatusToString< + T extends StatusCommitmentAndPeerId, +>(ccsGroupedByStatus: CommitmentGroupedByStatus) { + return ccsGroupedByStatus + .map((cc) => { + return `${getStatusHeading(cc)}${cc.ccInfos + .map((ccInfo) => { + return stringifyBasicCommitmentInfo(ccInfo); + }) + .join("\n\n")} `; + }) + .join("\n\n"); } diff --git a/packages/cli/package/src/lib/chain/conversions.ts b/packages/cli/package/src/lib/chain/conversions.ts index cda3b9451..0b3b70f0f 100644 --- a/packages/cli/package/src/lib/chain/conversions.ts +++ b/packages/cli/package/src/lib/chain/conversions.ts @@ -31,6 +31,11 @@ export async function peerIdBase58ToUint8Array(peerIdBase58: string) { .bytes.subarray(PREFIX.length); } +export async function peerIdBase58ToHexString(peerIdBase58: string) { + const { hexlify } = await import("ethers"); + return hexlify(await peerIdBase58ToUint8Array(peerIdBase58)); +} + export async function peerIdHexStringToBase58String(peerIdHex: string) { const [{ base58btc }] = await Promise.all([ import("multiformats/bases/base58"), diff --git a/packages/cli/package/src/lib/chain/deals.ts b/packages/cli/package/src/lib/chain/deals.ts index 67a026af6..0a3251161 100644 --- a/packages/cli/package/src/lib/chain/deals.ts +++ b/packages/cli/package/src/lib/chain/deals.ts @@ -16,9 +16,12 @@ */ import { getSignerAddress } from "../dealClient.js"; -import { getDealsByProviderId } from "../gql/gqlClient.js"; +import { getDealIdsByProviderId } from "../gql/gql.js"; export async function getProviderDeals() { - const signerAddress = await getSignerAddress(); - return getDealsByProviderId(signerAddress); + return (await getDealIdsByProviderId(await getSignerAddress())).deals.map( + ({ id }) => { + return id; + }, + ); } diff --git a/packages/cli/package/src/lib/chain/depositCollateral.ts b/packages/cli/package/src/lib/chain/depositCollateral.ts index c3cd57798..de24b94bf 100644 --- a/packages/cli/package/src/lib/chain/depositCollateral.ts +++ b/packages/cli/package/src/lib/chain/depositCollateral.ts @@ -19,31 +19,30 @@ import { color } from "@oclif/color"; import { commandObj } from "../commandObj.js"; import { getContracts, getReadonlyContracts, sign } from "../dealClient.js"; +import { ccIdsAndStatuses } from "../gql/gql.js"; import { splitErrorsAndResults } from "../helpers/utils.js"; import { stringifyBasicCommitmentInfo, - getCommitmentsInfo, + getCommitmentsGroupedByStatus, basicCCInfoAndStatusToString, } from "./commitment.js"; import { type CCFlags } from "./commitment.js"; +import { peerIdHexStringToBase58String } from "./conversions.js"; import { fltFormatWithSymbol } from "./currencies.js"; export async function depositCollateral(flags: CCFlags) { - const { CommitmentStatus } = await import("@fluencelabs/deal-ts-clients"); - const [commitmentsWithInvalidStatus, commitmentsWithWaitDelegation] = - splitErrorsAndResults(await getCommitmentsInfo(flags), (c) => { - if (c.status === CommitmentStatus.WaitDelegation) { - return { result: c }; - } - - return { error: c }; - }); + splitErrorsAndResults( + await getCommitmentsGroupedByStatus(flags, ccIdsAndStatuses), + (c) => { + return c.status === "WaitDelegation" ? { result: c } : { error: c }; + }, + ); if (commitmentsWithInvalidStatus.length > 0) { commandObj.warn( - `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( + `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( commitmentsWithInvalidStatus, )}`, ); @@ -71,7 +70,7 @@ export async function depositCollateral(flags: CCFlags) { commitments.map(async (commitment) => { return { ...commitment, - collateral: await getCollateral(commitment.commitmentId), + collateral: await getCollateral(commitment.infoFromSubgraph.id), }; }), ); @@ -84,15 +83,23 @@ export async function depositCollateral(flags: CCFlags) { ); await sign({ - title: `Deposit ${await fltFormatWithSymbol(collateralToApproveCommitment)} collateral to the following capacity commitments:\n\n${commitments - .map(({ commitmentId, noxName, peerId }) => { - return [noxName, peerId, commitmentId].filter(Boolean).join("\n"); - }) - .join("\n\n")}`, + title: `Deposit ${await fltFormatWithSymbol(collateralToApproveCommitment)} collateral to the following capacity commitments:\n\n${( + await Promise.all( + commitments.map(async ({ infoFromSubgraph, name }) => { + return [ + name, + await peerIdHexStringToBase58String(infoFromSubgraph.peer.id), + infoFromSubgraph.id, + ] + .filter(Boolean) + .join("\n"); + }), + ) + ).join("\n\n")}`, method: contracts.diamond.depositCollateral, args: [ - commitments.map(({ commitmentId }) => { - return commitmentId; + commitments.map(({ infoFromSubgraph }) => { + return infoFromSubgraph.id; }), { value: collateralToApproveCommitment }, ], @@ -114,7 +121,7 @@ Deposited ${color.yellow( ${( await Promise.all( commitmentsWithCollateral.map(async (c) => { - return `Capacity commitment successfully activated!\n${stringifyBasicCommitmentInfo( + return `Capacity commitment successfully activated!\n${await stringifyBasicCommitmentInfo( c, )}\nCollateral: ${color.yellow(await fltFormatWithSymbol(c.collateral))}`; }), diff --git a/packages/cli/package/src/lib/chain/offer/offer.ts b/packages/cli/package/src/lib/chain/offer/offer.ts index ef16fb1ae..1c8dda5ab 100644 --- a/packages/cli/package/src/lib/chain/offer/offer.ts +++ b/packages/cli/package/src/lib/chain/offer/offer.ts @@ -42,7 +42,7 @@ import { guessTxSizeAndSign, getEventValue, } from "../../dealClient.js"; -import { getOffers } from "../../gql/gqlClient.js"; +import { getOffers } from "../../gql/gql.js"; import { setTryTimeout } from "../../helpers/setTryTimeout.js"; import { stringifyUnknown } from "../../helpers/stringifyUnknown.js"; import { numToStr } from "../../helpers/typesafeStringify.js"; diff --git a/packages/cli/package/src/lib/chain/offer/updateOffers.ts b/packages/cli/package/src/lib/chain/offer/updateOffers.ts index f88c1b47e..7244da3f2 100644 --- a/packages/cli/package/src/lib/chain/offer/updateOffers.ts +++ b/packages/cli/package/src/lib/chain/offer/updateOffers.ts @@ -15,7 +15,6 @@ * along with this program. If not, see . */ -import type { ComputeUnit } from "@fluencelabs/deal-ts-clients/dist/dealExplorerClient/types/schemes.js"; import { color } from "@oclif/color"; import omit from "lodash-es/omit.js"; @@ -46,7 +45,10 @@ import { } from "./offer.js"; type PeersOnChain = { - computeUnits: ComputeUnit[]; + computeUnits: { + id: string; + workerId: string | undefined; + }[]; peerIdBase58: string; hexPeerId: string; }[]; @@ -58,7 +60,7 @@ export async function updateOffers(flags: OffersArgs) { const offersFoundOnChain = await filterOffersFoundOnChain(offers); const populatedTxs = await populateUpdateOffersTxs(offersFoundOnChain); - const updateOffersTxs = [ + const [firstUpdateOffersTx, ...restUpdateOffersTxs] = [ populatedTxs.flatMap(({ removePeersFromOffersTxs }) => { return removePeersFromOffersTxs.map(({ tx }) => { return tx; @@ -71,7 +73,7 @@ export async function updateOffers(flags: OffersArgs) { }), ].flat(); - if (updateOffersTxs.length === 0) { + if (firstUpdateOffersTx === undefined) { commandObj.logToStderr("No changes found for selected offers"); return; } @@ -94,7 +96,7 @@ export async function updateOffers(flags: OffersArgs) { return `${offerName} (${offerId})`; }) .join("\n")}`, - updateOffersTxs, + [firstUpdateOffersTx, ...restUpdateOffersTxs], assertProviderIsRegistered, ); } @@ -104,7 +106,7 @@ export async function removeOffers(flags: OffersArgs) { const offersFoundOnChain = await filterOffersFoundOnChain(offers); const populatedTxs = await populateRemoveOffersTxs(offersFoundOnChain); - const removeOffersTxs = [ + const [firstRemoveOffersTx, ...restRemoveOffersTxs] = [ populatedTxs.flatMap(({ cuToRemoveTxs: txs }) => { return txs.map(({ tx }) => { return tx; @@ -120,7 +122,7 @@ export async function removeOffers(flags: OffersArgs) { }), ].flat(); - if (removeOffersTxs.length === 0) { + if (firstRemoveOffersTx === undefined) { commandObj.logToStderr("Nothing to remove for selected offers"); return; } @@ -143,7 +145,7 @@ export async function removeOffers(flags: OffersArgs) { return `${offerName} (${offerId})`; }) .join("\n")}`, - removeOffersTxs, + [firstRemoveOffersTx, ...restRemoveOffersTxs], assertProviderIsRegistered, ); diff --git a/packages/cli/package/src/lib/configs/project/provider/provider.ts b/packages/cli/package/src/lib/configs/project/provider/provider.ts index d7ab49f2c..7e575b991 100644 --- a/packages/cli/package/src/lib/configs/project/provider/provider.ts +++ b/packages/cli/package/src/lib/configs/project/provider/provider.ts @@ -393,15 +393,11 @@ export async function ensureComputerPeerConfigs(computePeerNames?: string[]) { }; }), ({ secretKey, signingWallet, computePeerName, computePeer }) => { - if (secretKey === undefined || signingWallet === undefined) { - return { - error: { computePeerName, computePeer }, - }; - } - - return { - result: { secretKey, signingWallet, computePeerName, computePeer }, - }; + return secretKey === undefined || signingWallet === undefined + ? { error: { computePeerName, computePeer } } + : { + result: { secretKey, signingWallet, computePeerName, computePeer }, + }; }, ); diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index 420ba186d..129790a85 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -17,7 +17,9 @@ import assert from "node:assert"; +import type { MarketFacet } from "@fluencelabs/deal-ts-clients"; import { color } from "@oclif/color"; +import type { Typed } from "ethers"; import { versions } from "../versions.js"; @@ -35,18 +37,28 @@ import { } from "./const.js"; import { dbg } from "./dbg.js"; import { + type MulticallReadItem, sign, getContracts, - getDealMatcherClient, getEventValue, getEventValues, getReadonlyContracts, - batchRead, + multicallRead, } from "./dealClient.js"; import { ensureChainEnv } from "./ensureChainNetwork.js"; +import { + DEFAULT_PAGE_LIMIT, + getDealForMatching, + getOffersForMatching, +} from "./gql/gql.js"; +import type { OffersForMatchingQueryVariables } from "./gql/gqlGenerated.js"; import { setTryTimeout } from "./helpers/setTryTimeout.js"; import { stringifyUnknown } from "./helpers/stringifyUnknown.js"; -import { bigintToStr } from "./helpers/typesafeStringify.js"; +import { + bigintToStr, + nullableToString, + numToStr, +} from "./helpers/typesafeStringify.js"; import { commaSepStrToArr, splitErrorsAndResults } from "./helpers/utils.js"; import { checkboxes, input, list } from "./prompt.js"; import { ensureFluenceEnv } from "./resolveFluenceEnv.js"; @@ -176,16 +188,54 @@ export async function createAndMatchDealsForPeerIds({ const peerIdUint8Array = await peerIdBase58ToUint8Array(peerId); const ccIds = await contracts.diamond.getComputeUnitIds(peerIdUint8Array); - const computeUnits = ( - await batchRead( - ccIds.map((unitId) => { - return async () => { - const { deal } = await contracts.diamond.getComputeUnit(unitId); - return { unitId, deal }; - }; - }), - ) - ) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const [{ offerId }, ...computeUnitInfos] = (await multicallRead([ + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getComputePeer", + [peerIdUint8Array], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getComputePeer", + returnData, + ); + }, + }, + ...ccIds.map((unitId): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getComputeUnit", + [unitId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getComputeUnit", + returnData, + ); + }, + }; + }), + ])) as [ + Awaited>, + ...Awaited>[], + ]; + + const computeUnits = ccIds + .map((unitId, i) => { + return { + unitId, + deal: + computeUnitInfos[i]?.deal ?? + (() => { + throw new Error( + `Unreachable. Couldn't get deal for compute unit ${unitId}`, + ); + })(), + }; + }) .filter(({ deal }) => { return deal === ZeroAddress; }) @@ -193,9 +243,6 @@ export async function createAndMatchDealsForPeerIds({ return unitId; }); - const { offerId } = - await contracts.diamond.getComputePeer(peerIdUint8Array); - return { computeUnits, offerId, peerId }; }), ); @@ -279,7 +326,6 @@ export async function dealUpdate({ dealAddress, appCID }: DealUpdateArg) { export async function match(dealAddress: string) { const { contracts } = await getContracts(); - const dealMatcherClient = await getDealMatcherClient(); dbg(`running getMatchedOffersByDealId with dealAddress: ${dealAddress}`); dbg( @@ -291,7 +337,7 @@ export async function match(dealAddress: string) { const matchedOffers = await setTryTimeout( "get matched offers by deal id", () => { - return dealMatcherClient.getMatchedOffersByDealId(dealAddress); + return getMatchedOffersByDealId(dealAddress); }, (err) => { commandObj.error( @@ -329,6 +375,445 @@ export async function match(dealAddress: string) { ); } +type MatchDealParm = Exclude< + Parameters[T], + Typed +>; + +type GetMatchedOffersOut = { + offers: MatchDealParm<1>; + computeUnits: MatchDealParm<2>; +} | null; + +async function getMatchedOffersByDealId(dealId: string) { + const { deal, _meta, graphNetworks } = await getDealForMatching(dealId); + + if (deal === null || deal === undefined) { + commandObj.error(`Deal not found. Searched for: ${dealId}`); + } + + const [graphNetwork] = graphNetworks; + + if (graphNetwork === undefined) { + throw new Error("graphNetworks array is empty"); + } + + if ( + graphNetwork.initTimestamp === null || + graphNetwork.initTimestamp === undefined + ) { + throw new Error( + `graphNetwork.initTimestamp is not a number. Got: ${nullableToString(graphNetwork.initTimestamp)}`, + ); + } + + if ( + graphNetwork.coreEpochDuration === null || + graphNetwork.coreEpochDuration === undefined + ) { + throw new Error( + `graphNetwork.coreEpochDuration is not a number. Got: ${nullableToString(graphNetwork.coreEpochDuration)}`, + ); + } + + if ( + graphNetwork.coreMinDealRematchingEpochs === null || + graphNetwork.coreMinDealRematchingEpochs === undefined + ) { + throw new Error( + `graphNetwork.coreMinDealRematchingEpochs is not a number. Got: ${nullableToString(graphNetwork.coreMinDealRematchingEpochs)}`, + ); + } + + if (_meta === null || _meta === undefined) { + throw new Error(`_meta is expected to be ${nullableToString(_meta)}`); + } + + if (_meta.block.timestamp === null || _meta.block.timestamp === undefined) { + throw new Error( + `_meta.block.timestamp is not a number. Got: ${nullableToString(_meta.block.timestamp)}`, + ); + } + + const { initTimestamp, coreEpochDuration, coreMinDealRematchingEpochs } = + graphNetwork; + + if (deal.effectors === null || deal.effectors === undefined) { + throw new Error( + `deal.effectors is ${nullableToString(deal.effectors)} for dealId: ${dealId}. Array is expected.`, + ); + } + + const alreadyMatchedCU = deal.joinedWorkers?.length ?? 0; + + if (alreadyMatchedCU % deal.cuCountPerWorker !== 0) { + throw new Error( + `Unreachable. Deal already has matched compute units, but the number of compute units is not a multiple of cuCountPerWorker. Already matched CU: ${numToStr(alreadyMatchedCU)}, cuCountPerWorker: ${numToStr(deal.cuCountPerWorker)}`, + ); + } + + const alreadyMatchedWorkers = alreadyMatchedCU / deal.cuCountPerWorker; + const targetWorkersToMatch = deal.targetWorkers - alreadyMatchedWorkers; + + if (targetWorkersToMatch < 0) { + throw new Error( + `Deal already has more workers matched than target. In theory this should never be the case. Already matched: ${numToStr(alreadyMatchedWorkers)}, target: ${numToStr(deal.targetWorkers * deal.cuCountPerWorker)}`, + ); + } + + if (targetWorkersToMatch === 0) { + throw new Error(`Deal already has target number of workers matched.`); + } + + const currentEpoch = calculateEpoch( + _meta.block.timestamp, + initTimestamp, + coreEpochDuration, + ); + + const matchedAtEpoch = + deal.matchedAt !== undefined + ? calculateEpoch(Number(deal.matchedAt), initTimestamp, coreEpochDuration) + : 0; + + const nextEpochToRematch = matchedAtEpoch + coreMinDealRematchingEpochs; + + if (currentEpoch <= nextEpochToRematch) { + throw new Error( + `Deal ${dealId} has been matched recently at: ${deal.matchedAt ?? "unknown"} (${numToStr(matchedAtEpoch)} epoch). Wait for ${numToStr(nextEpochToRematch)} epoch to rematch`, + ); + } + + const minWorkersToMatch = Math.max( + deal.minWorkers - alreadyMatchedWorkers, + 0, + ); + + const { whitelist: providersWhiteList, blacklist: providersBlackList } = + prepareDealProviderAccessLists( + deal.providersAccessType, + deal.providersAccessList, + ); + + // Request page as big as allowed (remember about indexer limit). + // Shortens the query response for that rule as additional query size optimization. + const offersPerPageLimit = Math.min(targetWorkersToMatch, DEFAULT_PAGE_LIMIT); + + // Request page of peers and CUs as big as allowed (remember about indexer limit). + const peersPerPageLimit = Math.min( + deal.maxWorkersPerProvider, + DEFAULT_PAGE_LIMIT, + ); + + const matchedOffers: NonNullable = { + offers: [], + computeUnits: [], + }; + + let workersMatched = 0; + + // Go through indexer pages until the end condition: one of {fulfilled | end of offers, and peers, and CUs.} + let lastPageReached = false; + let offersOffset = 0; + let peersOffset = 0; + let computeUnitsOffset = 0; + + while (!lastPageReached) { + const offers = await getMatchedOffersPage( + { + dealId, + pricePerCuPerEpoch: deal.pricePerCuPerEpoch, + cuCountPerWorker: deal.cuCountPerWorker, + effectors: deal.effectors.map(({ effector: { id } }) => { + return id; + }), + paymentToken: deal.paymentToken.id, + targetWorkersToMatch, + minWorkersToMatch, + maxWorkersPerProvider: deal.maxWorkersPerProvider, + currentEpoch, + providersWhiteList, + providersBlackList, + }, + offersPerPageLimit, + peersPerPageLimit, + offersOffset, + peersOffset, + computeUnitsOffset, + ); + + if (offers.length === 0) { + dbg("Got empty data from indexer, break search."); + break; + } + + // Analyze fetched data to understand if we need to fetch next page and what + // params {offset, ...} to use for the next page. + for (const { peers, id: offerId } of offers) { + // Check if peers are empty and need to fetch next offer page. + // It could happen because we have after fetch filter: not more than cuCountPerWorker per peer + // that filters + if (peers === null || peers === undefined || peers.length === 0) { + offersOffset = offersOffset + DEFAULT_PAGE_LIMIT; + peersOffset = 0; + computeUnitsOffset = 0; + break; + } + + const peersToReturn: NonNullable["computeUnits"][number] = + []; + + for (const { computeUnits } of peers) { + if (computeUnits === null || computeUnits === undefined) { + continue; + } + + if (computeUnits.length >= deal.cuCountPerWorker) { + workersMatched = workersMatched + 1; + + peersToReturn.push( + computeUnits.slice(0, deal.cuCountPerWorker).map((cu) => { + return cu.id; + }), + ); + } + + if (workersMatched === targetWorkersToMatch) { + matchedOffers.offers.push(offerId); + matchedOffers.computeUnits.push(peersToReturn); + return matchedOffers; + } + + if (computeUnits.length < DEFAULT_PAGE_LIMIT) { + if (peers.length < DEFAULT_PAGE_LIMIT) { + if (offers.length < DEFAULT_PAGE_LIMIT) { + lastPageReached = true; + } else { + offersOffset = offersOffset + DEFAULT_PAGE_LIMIT; + peersOffset = 0; + computeUnitsOffset = 0; + } + } else { + peersOffset = peersOffset + DEFAULT_PAGE_LIMIT; + computeUnitsOffset = 0; + } + } else { + computeUnitsOffset = computeUnitsOffset + DEFAULT_PAGE_LIMIT; + } + } + + matchedOffers.offers.push(offerId); + matchedOffers.computeUnits.push(peersToReturn); + } + } + + if (workersMatched < minWorkersToMatch) { + dbg("workersMatched < minWorkersToMatch"); + matchedOffers.offers = []; + matchedOffers.computeUnits = []; + } + + if ( + matchedOffers.offers.length === 0 || + matchedOffers.computeUnits.length === 0 + ) { + return null; + } + + return matchedOffers; +} + +function calculateEpoch( + timestamp: number, + epochControllerStorageInitTimestamp: number, + epochControllerStorageEpochDuration: number, +) { + dbg( + `timestamp: ${numToStr(timestamp)} epochControllerStorageInitTimestamp: ${numToStr(epochControllerStorageInitTimestamp)} epochControllerStorageEpochDuration: ${numToStr(epochControllerStorageEpochDuration)}`, + ); + + return Math.floor( + 1 + + (timestamp - epochControllerStorageInitTimestamp) / + epochControllerStorageEpochDuration, + ); +} + +function prepareDealProviderAccessLists( + providersAccessType: number, + providersAccessList: + | { + __typename?: "DealToProvidersAccess"; + provider: { __typename?: "Provider"; id: string }; + }[] + | null + | undefined, +): { whitelist: string[]; blacklist: string[] } { + const res: { whitelist: string[]; blacklist: string[] } = { + whitelist: [], + blacklist: [], + }; + + if ( + providersAccessType === 0 || + providersAccessList === null || + providersAccessList === undefined + ) { + // None + return res; + } + + const providersAccessListStrings = providersAccessList.map((providerObj) => { + return providerObj.provider.id; + }); + + if (providersAccessType === 1) { + // whitelist + res.whitelist = providersAccessListStrings; + } else if (providersAccessType === 2) { + // whitelist + res.blacklist = providersAccessListStrings; + } + + return res; +} + +type GetMatchedOffersIn = { + dealId: string; + pricePerCuPerEpoch: string; + cuCountPerWorker: number; + effectors: string[]; + paymentToken: string; + targetWorkersToMatch: number; + minWorkersToMatch: number; + maxWorkersPerProvider: number; + currentEpoch: number; + providersWhiteList: string[]; + providersBlackList: string[]; +}; + +// must match market.matchDeal logic +async function getMatchedOffersPage( + getMatchedOffersIn: GetMatchedOffersIn, + offersPerPageLimit: number, // Possibility to optimize query size. + peersPerPageLimit: number, // Possibility to control, e.g. maxWorkersPerProvider. + offersOffset: number, + peersOffset: number, + computeUnitsOffset: number, +) { + const currentEpochString = numToStr(getMatchedOffersIn.currentEpoch); + + const filters: NonNullable = { + // TODO: We do not need Offers with ALL peers already linked to the Deal (protocol restriction). + pricePerEpoch_lte: getMatchedOffersIn.pricePerCuPerEpoch, + paymentToken: getMatchedOffersIn.paymentToken.toLowerCase(), + // Check if any of compute units are available in the offer and do not even fetch unrelated offers. + computeUnitsAvailable_gt: 0, + + // Check if provider whitelisted/blacklisted below, and if CC Active below in case without whitelist below. + }; + + const peersFilter: NonNullable< + NonNullable["and"] + >[number] = { + deleted: false, + computeUnits_: { worker: null, deleted: false }, + // Check for CC Active status below and depends on provider whitelist filter. + }; + + // Some filters per peers, capacity commitments and compute units are copied + // and implemented with different fields for the same filtration - it is so + // because in subgraph it is impossible to filter on nested fields + // and we do not want to reduce fetched data size (e.g. do to fetch offers + // with no peers with our conditions) + const indexerGetOffersParams: OffersForMatchingQueryVariables = { + limit: offersPerPageLimit, + filters, + peersFilters: { + and: [ + peersFilter, + { + // We do not need peers that already linked to the Deal (protocol restriction). + or: [ + { joinedDeals_: { deal_not: getMatchedOffersIn.dealId } }, + { isAnyJoinedDeals: false }, + ], + }, + ], + }, + computeUnitsFilters: { worker: null, deleted: false }, + peersLimit: peersPerPageLimit, + // We do not need more than cuCountPerWorker per peer. Apply restriction to already fetched and filtered data. + computeUnitsLimit: getMatchedOffersIn.cuCountPerWorker, + offset: offersOffset, + peersOffset, + computeUnitsOffset, + }; + + if (getMatchedOffersIn.effectors.length > 0) { + filters.effectors_ = { effector_in: getMatchedOffersIn.effectors }; + } + + // Check for blacklisted Providers. + if (getMatchedOffersIn.providersBlackList.length > 0) { + filters.provider_ = { id_not_in: getMatchedOffersIn.providersBlackList }; + } + + // We require rather CU to be in Active CC (and not in blacklist if blacklist exists) + // or CU from Deal whitelist of Providers. + if (getMatchedOffersIn.providersWhiteList.length > 0) { + filters.provider_ = { id_in: getMatchedOffersIn.providersWhiteList }; + } else { + // No whitelist, thus, check for active cc status is required. + // For Peers. + filters.peers_ = { + deleted: false, + // Do not fetch peers with no any of compute units in "active" status at all. + // Check if CU status is Active - if it has current capacity commitment and + // cc.info.startEpoch <= currentEpoch_. + currentCapacityCommitment_not: null, + // Since it is not possible to filter by currentCapacityCommitment_.startEpoch_lt + // we use this help field. + currentCCCollateralDepositedAt_lte: currentEpochString, + currentCCEndEpoch_gt: currentEpochString, + currentCCNextCCFailedEpoch_gt: currentEpochString, + }; + + // For CUs. + // Check if CU status is Active - if it has current capacity commitment and + // cc.info.startEpoch <= currentEpoch_. + peersFilter.currentCapacityCommitment_not = null; + + peersFilter.currentCapacityCommitment_ = { + // Duplication as it is in DealExplorerClient: serializeCapacityCommitmentsFiltersToIndexer. + startEpoch_lte: currentEpochString, + endEpoch_gt: currentEpochString, + // On each submitProof indexer should save nextCCFailedEpoch, and + // in query we relay on that field to filter Failed CC. + nextCCFailedEpoch_gt: currentEpochString, + deleted: false, + // Wait delegation is duplicating startEpoch_lte check, though. + status_not_in: ["WaitDelegation", "Removed", "Failed"], + }; + } + + dbg( + `[getMatchedOffersPage] Requesting indexer for page with page params: ${JSON.stringify( + indexerGetOffersParams, + null, + 2, + )}...`, + ); + + const fetched = await getOffersForMatching(indexerGetOffersParams); + + dbg( + `[getMatchedOffersPage] Fetched data: ${JSON.stringify(fetched, null, 2)}`, + ); + + return fetched.offers; +} + export type DealNameAndId = { dealName: string; dealId: string; diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index 7cd9a48c2..54bc82042 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -17,12 +17,7 @@ import assert from "node:assert"; -import type { - Contracts, - DealMatcherClient, - DealExplorerClient, - Deployment, -} from "@fluencelabs/deal-ts-clients"; +import type { Contracts, Deployment } from "@fluencelabs/deal-ts-clients"; import type { TypedContractMethod, StateMutability, @@ -36,8 +31,9 @@ import type { Wallet, ContractTransaction, TransactionReceipt, + BytesLike, + Result, } from "ethers"; -import chunk from "lodash-es/chunk.js"; import stripAnsi from "strip-ansi"; import { @@ -45,12 +41,7 @@ import { LOCAL_NET_DEFAULT_WALLET_KEY, } from "../common.js"; -import { - getChainId, - getNetworkName, - getRpcUrl, - getSubgraphUrl, -} from "./chain/chainConfig.js"; +import { getChainId, getNetworkName, getRpcUrl } from "./chain/chainConfig.js"; import { chainFlags } from "./chainFlags.js"; import { commandObj, isInteractive } from "./commandObj.js"; import { initEnvConfig } from "./configs/project/env/env.js"; @@ -109,33 +100,6 @@ export async function getSignerAddress() { ).toLowerCase(); } -let dealMatcherClient: DealMatcherClient | undefined = undefined; - -export async function getDealMatcherClient() { - if (dealMatcherClient === undefined) { - const { DealMatcherClient } = await import("@fluencelabs/deal-ts-clients"); - dealMatcherClient = new DealMatcherClient(await getSubgraphUrl()); - } - - return dealMatcherClient; -} - -let dealExplorerClient: DealExplorerClient | undefined = undefined; - -export async function getDealExplorerClient() { - if (dealExplorerClient === undefined) { - const { DealExplorerClient } = await import("@fluencelabs/deal-ts-clients"); - const { readonlyContracts } = await getReadonlyContracts(); - - dealExplorerClient = await DealExplorerClient.create( - readonlyContracts, - await getSubgraphUrl(), - ); - } - - return dealExplorerClient; -} - let deployment: Promise | undefined = undefined; export async function resolveDeployment() { @@ -477,27 +441,30 @@ let batchTxMessage: string | undefined; export async function signBatch( title: string, - populatedTxsWithDebugInfo: Array>, + populatedTxsWithDebugInfo: [ + ReturnType, + ...ReturnType[], + ], validateAddress?: ValidateAddress, ) { - const populatedTxsWithDebugInfoResolved = await Promise.all( - populatedTxsWithDebugInfo.map(async ({ populate, debugInfo }) => { - return { - populated: await populate(), - debugInfo, - }; + const [ + { populate: firstPopulate, debugInfo: firstDebugInfo }, + ...restPopulatedTxsWithDebugInfo + ] = populatedTxsWithDebugInfo; + + const [ + { + populated: { to: firstAddr }, + }, + ...restPopulatedTxs + ] = await Promise.all([ + (async () => { + return { populated: await firstPopulate(), debugInfo: firstDebugInfo }; + })(), + ...restPopulatedTxsWithDebugInfo.map(async ({ populate, debugInfo }) => { + return { populated: await populate(), debugInfo }; }), - ); - - const [firstPopulatedTx, ...restPopulatedTxs] = - populatedTxsWithDebugInfoResolved; - - const firstAddr = firstPopulatedTx?.populated.to; - - if (firstAddr === undefined) { - // if populatedTxsPromises is an empty array - do nothing - return; - } + ]); if ( restPopulatedTxs.some(({ populated: { to } }) => { @@ -674,23 +641,36 @@ export function getEventValues>({ }); } -export async function batchRead(rpcReadCalls: Array<() => Promise>) { - let rpcResults: Array = []; - - for (const rpcReadCallBatch of chunk( - rpcReadCalls, - 20, // it's our guess on the max number of concurrent requests to RPC - )) { - rpcResults = rpcResults.concat( - await Promise.all( - rpcReadCallBatch.map((rpcReadCall) => { - return rpcReadCall(); - }), - ), +export type MulticallReadItem = { + callData: BytesLike; + decode: (returnData: string) => Result; + target: string; +}; + +/** + * There is no good way to type this function correctly, so you have to use type-assertions when using it + */ +export async function multicallRead( + multicallReadItems: MulticallReadItem[], +): Promise { + const { contracts } = await getContracts(); + + const results = await contracts.multicall3.aggregate3.staticCall( + multicallReadItems.map(({ callData, target }) => { + return { callData, target, allowFailure: false }; + }), + ); + + return multicallReadItems.map(({ decode }, i): unknown => { + const res = results[i]; + + assert( + res !== undefined, + "Unreachable. For each call we must have a result", ); - } - return rpcResults; + return res.success ? decode(res.returnData)[0] : null; + }); } export async function guessTxSizeAndSign< diff --git a/packages/cli/package/src/lib/gql/gql.ts b/packages/cli/package/src/lib/gql/gql.ts new file mode 100644 index 000000000..6291c53a6 --- /dev/null +++ b/packages/cli/package/src/lib/gql/gql.ts @@ -0,0 +1,94 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { GraphQLClient } from "graphql-request"; + +import { getSubgraphUrl } from "../chain/chainConfig.js"; + +import { + getSdk as getGqlSdk, + type OffersForMatchingQueryVariables, + type Sdk, +} from "./gqlGenerated.js"; + +let sdk: Promise | undefined = undefined; + +async function getSdk() { + if (sdk === undefined) { + sdk = (async () => { + return getGqlSdk(new GraphQLClient(await getSubgraphUrl())); + })(); + } + + return sdk; +} + +export const DEFAULT_PAGE_LIMIT = 1000; + +export async function getDealIdsByProviderId(providerId: string) { + return (await getSdk()).Deals({ + where: { + joinedWorkers_: { + peer_: { provider_: { id: providerId.toLowerCase() } }, + }, + }, + skip: 0, + first: DEFAULT_PAGE_LIMIT, + orderBy: "createdAt", + orderDirection: "desc", + }); +} + +export async function getDealForMatching(dealId: string) { + return (await getSdk()).DealForMatching({ id: dealId }); +} + +export async function getOffersForMatching( + variables: OffersForMatchingQueryVariables, +) { + return (await getSdk()).OffersForMatching(variables); +} + +export async function getOffers(id_in: string[]) { + return (await getSdk()).OfferDetails({ + where: { id_in }, + orderBy: "createdAt", + orderDirection: "desc", + }); +} + +function getCCQueries( + queryName: T, +): { + getCCByCCId(ccIds: string[]): ReturnType; + getCCByHexPeerId(hexPeerIds: string[]): ReturnType; +} { + return { + // @ts-expect-error Don't know how to satisfy the type system here + async getCCByCCId(ccIds: string[]) { + return (await getSdk())[queryName]({ where: { id_in: ccIds } }); + }, + // @ts-expect-error Don't know how to satisfy the type system here + async getCCByHexPeerId(hexPeerIds: string[]) { + return (await getSdk())[queryName]({ where: { peer_in: hexPeerIds } }); + }, + }; +} + +export const ccIds = getCCQueries("CCIds"); +export const ccIdsAndStatuses = getCCQueries("CCIdsAndStatuses"); +export const ccDetails = getCCQueries("CCDetails"); diff --git a/packages/cli/package/src/lib/gql/gqlClient.ts b/packages/cli/package/src/lib/gql/gqlClient.ts deleted file mode 100644 index 6f74a103f..000000000 --- a/packages/cli/package/src/lib/gql/gqlClient.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Fluence CLI - * Copyright (C) 2024 Fluence DAO - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import { GraphQLClient } from "graphql-request"; - -import { getSubgraphUrl } from "../chain/chainConfig.js"; - -import { getSdk as getGqlSdk, type Sdk } from "./gqlGenerated.js"; - -let sdk: Sdk | undefined = undefined; - -async function getSdk() { - if (sdk === undefined) { - sdk = getGqlSdk(new GraphQLClient(await getSubgraphUrl())); - } - - return sdk; -} - -const DEFAULT_PAGE_LIMIT = 1000; - -export async function getOffers(id_in: string[]) { - const sdk = await getSdk(); - - return sdk.OfferDetailsQuery({ - filters: { id_in }, - orderBy: "createdAt", - orderType: "desc", - }); -} - -export async function getDealsByProviderId(providerId: string) { - const sdk = await getSdk(); - - return ( - await sdk.DealsQuery({ - filters: { - joinedWorkers_: { - peer_: { provider_: { id: providerId.toLowerCase() } }, - }, - }, - offset: 0, - limit: DEFAULT_PAGE_LIMIT, - orderBy: "createdAt", - orderType: "desc", - }) - ).deals.map(({ id }) => { - return id; - }); -} diff --git a/packages/cli/package/src/lib/gql/schema.graphql b/packages/cli/package/src/lib/gql/schema.graphql index dd9bd02fb..b364f5e9b 100644 --- a/packages/cli/package/src/lib/gql/schema.graphql +++ b/packages/cli/package/src/lib/gql/schema.graphql @@ -1,39 +1,121 @@ -query DealsQuery( - $filters: Deal_filter +query Deals( + $where: Deal_filter + $skip: Int + $first: Int + $orderBy: Deal_orderBy + $orderDirection: OrderDirection +) { + deals( + where: $where + skip: $skip + first: $first + orderBy: $orderBy + orderDirection: $orderDirection + ) { + id + } +} + +query DealForMatching($id: ID!) { + deal(id: $id) { + maxWorkersPerProvider + minWorkers + pricePerCuPerEpoch + matchedAt + paymentToken { + id + } + targetWorkers + cuCountPerWorker + joinedWorkers { + computeUnits { + id + } + } + effectors { + effector { + id + } + } + providersAccessType + providersAccessList { + provider { + id + } + } + } + + _meta { + block { + timestamp + } + } + + graphNetworks(first: 1) { + coreEpochDuration + initTimestamp + coreMinDealRematchingEpochs + } +} + +query OffersForMatching( + $filters: Offer_filter + $peersFilters: Peer_filter + $computeUnitsFilters: ComputeUnit_filter + $peersLimit: Int + $computeUnitsLimit: Int $offset: Int + $peersOffset: Int + $computeUnitsOffset: Int $limit: Int - $orderBy: Deal_orderBy + $orderBy: Offer_orderBy $orderType: OrderDirection ) { - deals( - where: $filters + offers( + where: { + and: [ + $filters + # Exclude deleted offers. + { deleted: false } + ] + } first: $limit skip: $offset orderBy: $orderBy orderDirection: $orderType ) { id + peers(where: $peersFilters, first: $peersLimit, skip: $peersOffset) { + id + computeUnits( + where: $computeUnitsFilters + first: $computeUnitsLimit + skip: $computeUnitsOffset + ) { + id + } + } } } # Exclude deleted CUs. # Exclude deleted Peers. -query OfferDetailsQuery( - $filters: Offer_filter - $orderType: OrderDirection +query OfferDetails( + $where: Offer_filter + $orderDirection: OrderDirection $orderBy: Offer_orderBy ) { offers( where: { and: [ - $filters + $where # Exclude deleted offers. { deleted: false } ] } orderBy: $orderBy - orderDirection: $orderType + orderDirection: $orderDirection ) { id createdAt @@ -63,3 +145,44 @@ query OfferDetailsQuery( } } } + +query CCIds($where: CapacityCommitment_filter) { + capacityCommitments(where: $where) { + id + peer { + id + } + } +} + +query CCIdsAndStatuses($where: CapacityCommitment_filter) { + capacityCommitments(where: $where) { + id + status + peer { + id + } + } +} + +query CCDetails($where: CapacityCommitment_filter) { + capacityCommitments(where: $where) { + id + peer { + id + } + status + delegator { + id + } + rewardDelegatorRate + startEpoch + endEpoch + computeUnitsCount + totalFailCount + exitedUnitCount + collateralPerUnit + ccRewardsWithdrawn + dealStakerRewardsWithdrawn + } +} diff --git a/packages/cli/package/src/lib/helpers/bigintOps.ts b/packages/cli/package/src/lib/helpers/bigintOps.ts index 44b95911d..80b4afd4b 100644 --- a/packages/cli/package/src/lib/helpers/bigintOps.ts +++ b/packages/cli/package/src/lib/helpers/bigintOps.ts @@ -15,11 +15,6 @@ * along with this program. If not, see . */ -export function bigintSecondsToDate(bigSec: bigint): Date | undefined { - if (bigSec > Number.MAX_SAFE_INTEGER) { - return undefined; - } - - const sec = Number(bigSec * BigInt(1000)); - return new Date(sec); +export function bigintSecondsToDate(bigSec: bigint): Date { + return new Date(Number(bigSec * 1000n)); } diff --git a/packages/cli/package/src/lib/helpers/typesafeStringify.ts b/packages/cli/package/src/lib/helpers/typesafeStringify.ts index 220d41cb4..0ea70c82d 100644 --- a/packages/cli/package/src/lib/helpers/typesafeStringify.ts +++ b/packages/cli/package/src/lib/helpers/typesafeStringify.ts @@ -41,3 +41,7 @@ export function bufferToStr(buffer: Buffer): string { export function urlToStr(url: URL) { return url.toString(); } + +export function nullableToString(value: null | undefined): string { + return value === null ? "null" : "undefined"; +} diff --git a/packages/cli/package/src/lib/helpers/utils.ts b/packages/cli/package/src/lib/helpers/utils.ts index aab6f6e2b..28214a571 100644 --- a/packages/cli/package/src/lib/helpers/utils.ts +++ b/packages/cli/package/src/lib/helpers/utils.ts @@ -20,9 +20,14 @@ import { access } from "node:fs/promises"; import { numToStr } from "./typesafeStringify.js"; export function commaSepStrToArr(commaSepStr: string) { - return commaSepStr.split(",").map((s) => { - return s.trim(); - }); + return commaSepStr + .split(",") + .map((s) => { + return s.trim(); + }) + .filter((s) => { + return s !== ""; + }); } function comment(commentToken: string) { diff --git a/packages/cli/package/src/lib/resolveComputePeersByNames.ts b/packages/cli/package/src/lib/resolveComputePeersByNames.ts index 75e3a8779..36ce1c122 100644 --- a/packages/cli/package/src/lib/resolveComputePeersByNames.ts +++ b/packages/cli/package/src/lib/resolveComputePeersByNames.ts @@ -37,31 +37,56 @@ export async function resolveComputePeersByNames( [NOX_NAMES_FLAG_NAME]?: string | undefined; [OFFER_FLAG_NAME]?: string | undefined; } = {}, -) { +): Promise<[ResolvedComputePeer, ...ResolvedComputePeer[]]> { const computePeers = await ensureComputerPeerConfigs(); if (flags[NOX_NAMES_FLAG_NAME] === ALL_FLAG_VALUE) { - return computePeers; + const [firstComputePeer, ...restComputePeers] = computePeers; + + if (firstComputePeer === undefined) { + commandObj.error("No compute peers found"); + } + + return [firstComputePeer, ...restComputePeers]; } const providerConfig = await ensureReadonlyProviderConfig(); if (flags[OFFER_FLAG_NAME] !== undefined) { - const computerPeerNamesFromOffers = ( - await resolveOffersFromProviderConfig(flags) - ).flatMap(({ computePeersFromProviderConfig }) => { - return computePeersFromProviderConfig.map(({ name }) => { - return name; - }); - }); + const offers = await resolveOffersFromProviderConfig(flags); - return computePeers.filter(({ name }) => { - return computerPeerNamesFromOffers.includes(name); - }); + const computerPeerNamesFromOffers = offers.flatMap( + ({ computePeersFromProviderConfig }) => { + return computePeersFromProviderConfig.map(({ name }) => { + return name; + }); + }, + ); + + const [firstComputerPeer, ...restComputerPeers] = computePeers.filter( + ({ name }) => { + return computerPeerNamesFromOffers.includes(name); + }, + ); + + if (firstComputerPeer === undefined) { + commandObj.error( + `No compute peers found for offers: ${offers + .map(({ offerName }) => { + return offerName; + }) + .join(", ")}`, + ); + } + + return [firstComputerPeer, ...restComputerPeers]; } if (flags[NOX_NAMES_FLAG_NAME] === undefined) { - return checkboxes({ + const [firstComputePeer, ...restComputePeers] = await checkboxes< + EnsureComputerPeerConfig, + never + >({ message: `Select one or more nox names from ${providerConfig.$getPath()}`, options: computePeers.map((computePeer) => { return { @@ -88,6 +113,14 @@ export async function resolveComputePeersByNames( }, flagName: NOX_NAMES_FLAG_NAME, }); + + if (firstComputePeer === undefined) { + throw new Error( + "Unreachable. It's checked there are compute peers in checkboxes", + ); + } + + return [firstComputePeer, ...restComputePeers]; } const noxNames = commaSepStrToArr(flags[NOX_NAMES_FLAG_NAME]); @@ -117,11 +150,21 @@ export async function resolveComputePeersByNames( ); } - return computePeers.filter(({ name }) => { - return validNoxNames.includes(name); - }); + const [firstComputePeer, ...restComputePeers] = computePeers.filter( + ({ name }) => { + return validNoxNames.includes(name); + }, + ); + + if (firstComputePeer === undefined) { + commandObj.error( + `No compute peers found for nox names: ${validNoxNames.join(", ")}`, + ); + } + + return [firstComputePeer, ...restComputePeers]; } export type ResolvedComputePeer = Awaited< - ReturnType + Awaited> >[number]; diff --git a/packages/cli/package/src/lib/typeHelpers.ts b/packages/cli/package/src/lib/typeHelpers.ts index db46c900f..aef44bb65 100644 --- a/packages/cli/package/src/lib/typeHelpers.ts +++ b/packages/cli/package/src/lib/typeHelpers.ts @@ -49,6 +49,13 @@ export type OptionalFlags = Partial< Record> >; +/** + * Useful for debugging. Merges any compound type into a final flat object type + */ +export type Prettify = { + [K in keyof T]: T[K]; +} & {}; + export const isObject = ( unknown: unknown, ): unknown is Record => { From 65afa0fa6488469de8c162e950bff2c8f1e6276e Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 14:32:55 +0100 Subject: [PATCH 27/37] get cc statuses from RPC --- .../cli/package/src/lib/chain/commitment.ts | 143 ++++++++++++------ .../src/lib/chain/depositCollateral.ts | 6 +- packages/cli/package/src/lib/gql/gql.ts | 3 +- .../cli/package/src/lib/gql/schema.graphql | 11 -- 4 files changed, 100 insertions(+), 63 deletions(-) diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 3b7b93d4a..8b7b59d1b 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -39,7 +39,7 @@ import { multicallRead, type MulticallReadItem, } from "../dealClient.js"; -import { ccIds, ccIdsAndStatuses, ccDetails } from "../gql/gql.js"; +import { ccIds, ccDetails } from "../gql/gql.js"; import type { CapacityCommitmentStatus } from "../gql/gqlGenerated.js"; import { bigintSecondsToDate } from "../helpers/bigintOps.js"; import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; @@ -443,9 +443,13 @@ export async function createCommitments(flags: { export async function removeCommitments(flags: CCFlags) { const [invalidCommitments, commitments] = splitErrorsAndResults( - await getCommitments(flags, ccIdsAndStatuses), + (await getCommitmentsGroupedByStatus(flags, ccIds)).flatMap( + ({ ccInfos }) => { + return ccInfos; + }, + ), (cc) => { - return cc.infoFromSubgraph.status === "WaitDelegation" + return cc.infoFromSubgraph.statusFromRPC === "WaitDelegation" ? { result: cc } : { error: cc }; }, @@ -456,9 +460,7 @@ export async function removeCommitments(flags: CCFlags) { `You can remove commitments only if they have WaitDelegation status. Got:\n\n${( await Promise.all( invalidCommitments.map(async (cc) => { - return `${await stringifyBasicCommitmentInfo(cc)}Status: ${ccStatusToString( - cc.infoFromSubgraph.status, - )}`; + return `${await stringifyBasicCommitmentInfo(cc)}Status: ${cc.infoFromSubgraph.statusFromRPC}`; }), ) ).join("\n\n")}`, @@ -512,7 +514,7 @@ export async function collateralWithdraw( const { ZeroAddress } = await import("ethers"); const [invalidCommitments, commitments] = splitErrorsAndResults( - await getCommitmentsGroupedByStatus(flags, ccIdsAndStatuses), + await getCommitmentsGroupedByStatus(flags, ccIds), (c) => { return c.status === "Completed" || c.status === "Failed" ? { result: c } @@ -522,7 +524,7 @@ export async function collateralWithdraw( if (invalidCommitments.length > 0) { commandObj.warn( - `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( + `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( invalidCommitments, )}`, ); @@ -716,37 +718,75 @@ export async function stringifyBasicCommitmentInfo< return `${color.yellow(`${noxName}PeerId: ${peerId}`)}\nCommitmentId: ${infoFromSubgraph.id}`; } -type StatusCommitmentAndPeerId = CommitmentAndPeerId & { - status?: CapacityCommitmentStatus | null; -}; - type CapacityCommitment = { infoFromSubgraph: T; name?: string; }; -type CommitmentGroupedByStatus = { +type CommitmentGroupedByStatus = { status: ReturnType; ccInfos: CapacityCommitment[]; }[]; export async function getCommitmentsGroupedByStatus< - T extends StatusCommitmentAndPeerId, + T extends CommitmentAndPeerId, >( ...args: Parameters> -): Promise> { +): Promise< + CommitmentGroupedByStatus< + T & { statusFromRPC: CapacityCommitmentStatusString } + > +> { + const commitments = await getCommitments(...args); + const { contracts } = await getContracts(); + + const statuses = await multicallRead( + commitments.map(({ infoFromSubgraph: { id } }): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("getStatus", [ + id, + ]), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getStatus", + returnData, + ); + }, + }; + }), + ); + return Array.from( (await getCommitments(...args)) - .reduce[]>>( - (acc, v) => { - const status = ccStatusToString(v.infoFromSubgraph.status); - const infos = acc.get(status) ?? []; - infos.push(v); - acc.set(status, infos); - return acc; - }, - new Map(), - ) + .reduce< + Map< + CapacityCommitmentStatusString, + CapacityCommitment< + T & { statusFromRPC: CapacityCommitmentStatusString } + >[] + > + >((acc, v, i) => { + const statusFromRPC = ccStatusToString( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + statuses[i] as Awaited< + ReturnType + >, + ); + + const infos = acc.get(statusFromRPC) ?? []; + + infos.push({ + ...v, + infoFromSubgraph: { + ...v.infoFromSubgraph, + statusFromRPC, + }, + }); + + acc.set(statusFromRPC, infos); + return acc; + }, new Map()) .entries(), ).map(([status, ccInfos]) => { return { status, ccInfos }; @@ -952,7 +992,7 @@ export function stringifyDetailedCommitmentsInfo( .join("\n\n"); } -function getStatusHeading( +function getStatusHeading( cc: CommitmentGroupedByStatus[number], ) { return color.yellow( @@ -977,7 +1017,6 @@ type DetailedCCInfo = Awaited< async function getDetailedCommitmentInfo({ infoFromSubgraph: { id: commitmentId, - status, startEpoch, endEpoch, delegator, @@ -989,6 +1028,7 @@ async function getDetailedCommitmentInfo({ ccRewardsWithdrawn, dealStakerRewardsWithdrawn, peer: { id: peerId }, + statusFromRPC: status, }, name: noxName, currentEpoch, @@ -1034,7 +1074,7 @@ async function getDetailedCommitmentInfo({ ...(noxName === undefined ? {} : { noxName }), peerId: await peerIdHexStringToBase58String(peerId), commitmentId, - status: ccStatusToString(status), + status, staker: delegator?.id === (await import("ethers")).ZeroAddress ? "Anyone can activate capacity commitment" @@ -1139,26 +1179,35 @@ type CapacityCommitmentStatusString = | Exclude | "Completed"; -function ccStatusToString( - status: CapacityCommitmentStatus | null | undefined, -): CapacityCommitmentStatusString { - if (status === undefined || status === null) { - return "Unknown"; - } - - return status === "Inactive" ? "Completed" : status; +function ccStatusToString(status: bigint): CapacityCommitmentStatusString { + return ( + ( + [ + "Completed", + "Active", + "WaitDelegation", + "WaitStart", + "Failed", + "Removed", + ] as const + )[Number(status)] ?? "Unknown" + ); } -export function basicCCInfoAndStatusToString< - T extends StatusCommitmentAndPeerId, +export async function basicCCInfoAndStatusToString< + T extends CommitmentAndPeerId, >(ccsGroupedByStatus: CommitmentGroupedByStatus) { - return ccsGroupedByStatus - .map((cc) => { - return `${getStatusHeading(cc)}${cc.ccInfos - .map((ccInfo) => { - return stringifyBasicCommitmentInfo(ccInfo); - }) - .join("\n\n")} `; - }) - .join("\n\n"); + return ( + await Promise.all( + ccsGroupedByStatus.map(async (cc) => { + return `${getStatusHeading(cc)}${( + await Promise.all( + cc.ccInfos.map((ccInfo) => { + return stringifyBasicCommitmentInfo(ccInfo); + }), + ) + ).join("\n\n")} `; + }), + ) + ).join("\n\n"); } diff --git a/packages/cli/package/src/lib/chain/depositCollateral.ts b/packages/cli/package/src/lib/chain/depositCollateral.ts index de24b94bf..9f7acf077 100644 --- a/packages/cli/package/src/lib/chain/depositCollateral.ts +++ b/packages/cli/package/src/lib/chain/depositCollateral.ts @@ -19,7 +19,7 @@ import { color } from "@oclif/color"; import { commandObj } from "../commandObj.js"; import { getContracts, getReadonlyContracts, sign } from "../dealClient.js"; -import { ccIdsAndStatuses } from "../gql/gql.js"; +import { ccIds } from "../gql/gql.js"; import { splitErrorsAndResults } from "../helpers/utils.js"; import { @@ -34,7 +34,7 @@ import { fltFormatWithSymbol } from "./currencies.js"; export async function depositCollateral(flags: CCFlags) { const [commitmentsWithInvalidStatus, commitmentsWithWaitDelegation] = splitErrorsAndResults( - await getCommitmentsGroupedByStatus(flags, ccIdsAndStatuses), + await getCommitmentsGroupedByStatus(flags, ccIds), (c) => { return c.status === "WaitDelegation" ? { result: c } : { error: c }; }, @@ -42,7 +42,7 @@ export async function depositCollateral(flags: CCFlags) { if (commitmentsWithInvalidStatus.length > 0) { commandObj.warn( - `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( + `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( commitmentsWithInvalidStatus, )}`, ); diff --git a/packages/cli/package/src/lib/gql/gql.ts b/packages/cli/package/src/lib/gql/gql.ts index 6291c53a6..9c7d2cad9 100644 --- a/packages/cli/package/src/lib/gql/gql.ts +++ b/packages/cli/package/src/lib/gql/gql.ts @@ -71,7 +71,7 @@ export async function getOffers(id_in: string[]) { }); } -function getCCQueries( +function getCCQueries( queryName: T, ): { getCCByCCId(ccIds: string[]): ReturnType; @@ -90,5 +90,4 @@ function getCCQueries( } export const ccIds = getCCQueries("CCIds"); -export const ccIdsAndStatuses = getCCQueries("CCIdsAndStatuses"); export const ccDetails = getCCQueries("CCDetails"); diff --git a/packages/cli/package/src/lib/gql/schema.graphql b/packages/cli/package/src/lib/gql/schema.graphql index b364f5e9b..5af005212 100644 --- a/packages/cli/package/src/lib/gql/schema.graphql +++ b/packages/cli/package/src/lib/gql/schema.graphql @@ -155,23 +155,12 @@ query CCIds($where: CapacityCommitment_filter) { } } -query CCIdsAndStatuses($where: CapacityCommitment_filter) { - capacityCommitments(where: $where) { - id - status - peer { - id - } - } -} - query CCDetails($where: CapacityCommitment_filter) { capacityCommitments(where: $where) { id peer { id } - status delegator { id } From 9b0c2f7405466a5fabab66465129a566fedfc0b3 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 14:53:19 +0100 Subject: [PATCH 28/37] lowercase dealId --- packages/cli-connector/src/App.tsx | 2 - packages/cli/package/src/lib/deal.ts | 3 +- packages/common/package.json | 12 +--- yarn.lock | 92 ++-------------------------- 4 files changed, 11 insertions(+), 98 deletions(-) diff --git a/packages/cli-connector/src/App.tsx b/packages/cli-connector/src/App.tsx index 2bbaabc5b..33d2e4717 100644 --- a/packages/cli-connector/src/App.tsx +++ b/packages/cli-connector/src/App.tsx @@ -15,8 +15,6 @@ * along with this program. If not, see . */ -// In Firefox: client variable can be undefined - that's why we need to use optional chaining - import { ConnectButton } from "@rainbow-me/rainbowkit"; import { type CLIToConnectorFullMsg, diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index 129790a85..bc8b287ac 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -385,7 +385,8 @@ type GetMatchedOffersOut = { computeUnits: MatchDealParm<2>; } | null; -async function getMatchedOffersByDealId(dealId: string) { +async function getMatchedOffersByDealId(dealAddress: string) { + const dealId = dealAddress.toLowerCase(); const { deal, _meta, graphNetworks } = await getDealForMatching(dealId); if (deal === null || deal === undefined) { diff --git a/packages/common/package.json b/packages/common/package.json index c213f320f..9eba236b0 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -3,19 +3,14 @@ "license": "AGPL-3.0", "version": "0.0.0", "type": "module", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], "exports": { ".": { - "import": "./dist/index.js", - "types": "./dist/index.d.ts" + "types": "./src/index.ts", + "default": "./dist/index.js" } }, "scripts": { - "build": "shx rm -rf dist && tsc -b", + "build": "tsc", "lint-fix": "eslint . --fix", "on-each-commit": "yarn lint-fix" }, @@ -25,7 +20,6 @@ "eslint": "9.3.0", "ethers": "6.7.1", "react": "18.2.0", - "shx": "0.3.4", "typescript": "5.4.5", "typescript-eslint": "7.11.0" } diff --git a/yarn.lock b/yarn.lock index 82ebd1d5f..0f4b16fa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1036,7 +1036,6 @@ __metadata: eslint: "npm:9.3.0" ethers: "npm:6.7.1" react: "npm:18.2.0" - shx: "npm:0.3.4" typescript: "npm:5.4.5" typescript-eslint: "npm:7.11.0" languageName: unknown @@ -4347,13 +4346,6 @@ __metadata: languageName: node linkType: hard -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 - languageName: node - linkType: hard - "fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -4491,20 +4483,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe - languageName: node - linkType: hard - "globals@npm:15.1.0": version: 15.1.0 resolution: "globals@npm:15.1.0" @@ -4780,17 +4758,7 @@ __metadata: languageName: node linkType: hard -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": +"inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 @@ -4808,13 +4776,6 @@ __metadata: languageName: node linkType: hard -"interpret@npm:^1.0.0": - version: 1.4.0 - resolution: "interpret@npm:1.4.0" - checksum: 10c0/08c5ad30032edeec638485bc3f6db7d0094d9b3e85e0f950866600af3c52e9fd69715416d29564731c479d9f4d43ff3e4d302a178196bdc0e6837ec147640450 - languageName: node - linkType: hard - "invariant@npm:2.2.4, invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -5569,7 +5530,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:^3.0.5, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -5587,7 +5548,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.6": +"minimist@npm:^1.2.0, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 @@ -6038,7 +5999,7 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": +"once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -6149,13 +6110,6 @@ __metadata: languageName: node linkType: hard -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -6662,15 +6616,6 @@ __metadata: languageName: node linkType: hard -"rechoir@npm:^0.6.2": - version: 0.6.2 - resolution: "rechoir@npm:0.6.2" - dependencies: - resolve: "npm:^1.1.6" - checksum: 10c0/22c4bb32f4934a9468468b608417194f7e3ceba9a508512125b16082c64f161915a28467562368eeb15dc16058eb5b7c13a20b9eb29ff9927d1ebb3b5aa83e84 - languageName: node - linkType: hard - "reflect.getprototypeof@npm:^1.0.4": version: 1.0.6 resolution: "reflect.getprototypeof@npm:1.0.6" @@ -6733,7 +6678,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.22.4": +"resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -6759,7 +6704,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -7041,31 +6986,6 @@ __metadata: languageName: node linkType: hard -"shelljs@npm:^0.8.5": - version: 0.8.5 - resolution: "shelljs@npm:0.8.5" - dependencies: - glob: "npm:^7.0.0" - interpret: "npm:^1.0.0" - rechoir: "npm:^0.6.2" - bin: - shjs: bin/shjs - checksum: 10c0/feb25289a12e4bcd04c40ddfab51aff98a3729f5c2602d5b1a1b95f6819ec7804ac8147ebd8d9a85dfab69d501bcf92d7acef03247320f51c1552cec8d8e2382 - languageName: node - linkType: hard - -"shx@npm:0.3.4": - version: 0.3.4 - resolution: "shx@npm:0.3.4" - dependencies: - minimist: "npm:^1.2.3" - shelljs: "npm:^0.8.5" - bin: - shx: lib/cli.js - checksum: 10c0/83251fb09314682f5a192f0249a4be68c755933313a41b5152b11c19fc0a68311954d3ca971a0cbae05815786a893c59b82f356484d8eeb009c84f4066b3fa31 - languageName: node - linkType: hard - "side-channel@npm:^1.0.4, side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" From 43dc831c552bab848d4cab8af8efd1397cdeb76b Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 16:26:43 +0100 Subject: [PATCH 29/37] add debug log --- .../cli/package/src/lib/chain/commitment.ts | 21 ++++++++++++------- packages/cli/package/src/lib/dealClient.ts | 5 +++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 8b7b59d1b..f467508ab 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -20,6 +20,7 @@ import { color } from "@oclif/color"; import parse from "parse-duration"; import { yamlDiffPatch } from "yaml-diff-patch"; +import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { initProviderConfig } from "../configs/project/provider/provider.js"; import { @@ -724,7 +725,7 @@ type CapacityCommitment = { }; type CommitmentGroupedByStatus = { - status: ReturnType; + status: CapacityCommitmentStatusString; ccInfos: CapacityCommitment[]; }[]; @@ -757,6 +758,8 @@ export async function getCommitmentsGroupedByStatus< }), ); + dbg(`Statuses: ${jsonStringify(statuses)}`); + return Array.from( (await getCommitments(...args)) .reduce< @@ -767,13 +770,13 @@ export async function getCommitmentsGroupedByStatus< >[] > >((acc, v, i) => { - const statusFromRPC = ccStatusToString( - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - statuses[i] as Awaited< - ReturnType - >, - ); + if (typeof statuses[i] !== "bigint") { + throw new Error( + `Expected status from RPC to be a bigint, got ${stringifyUnknown(statuses[i])}`, + ); + } + const statusFromRPC = ccStatusToString(statuses[i]); const infos = acc.get(statusFromRPC) ?? []; infos.push({ @@ -1179,7 +1182,9 @@ type CapacityCommitmentStatusString = | Exclude | "Completed"; -function ccStatusToString(status: bigint): CapacityCommitmentStatusString { +function ccStatusToString( + status: Awaited>, +): CapacityCommitmentStatusString { return ( ( [ diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index 54bc82042..e639df104 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -38,6 +38,7 @@ import stripAnsi from "strip-ansi"; import { type TransactionPayload, + jsonStringify, LOCAL_NET_DEFAULT_WALLET_KEY, } from "../common.js"; @@ -521,7 +522,7 @@ function methodCallToString([method, ...args]: [ { name: string }, ...unknown[], ]) { - return `${method.name}(${stringifyUnknown(args).slice(1, -1)})`; + return `${method.name}(${jsonStringify(args).slice(1, -1)})`; } type Contract = { @@ -648,7 +649,7 @@ export type MulticallReadItem = { }; /** - * There is no good way to type this function correctly, so you have to use type-assertions when using it + * There is no good way to type this function correctly, so you have to use validation or type-assertions when using it */ export async function multicallRead( multicallReadItems: MulticallReadItem[], From 6f70f4dc55951ef08e4a970f3346eda32231cad4 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 16:41:49 +0100 Subject: [PATCH 30/37] try using batch read like before instead of multicall read --- .../cli/package/src/lib/chain/commitment.ts | 34 +++++++------------ packages/cli/package/src/lib/dealClient.ts | 20 +++++++++++ 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index f467508ab..eefd9a49d 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -15,12 +15,13 @@ * along with this program. If not, see . */ +import assert from "assert"; + import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { color } from "@oclif/color"; import parse from "parse-duration"; import { yamlDiffPatch } from "yaml-diff-patch"; -import { jsonStringify } from "../../common.js"; import { commandObj } from "../commandObj.js"; import { initProviderConfig } from "../configs/project/provider/provider.js"; import { @@ -39,6 +40,7 @@ import { sign, multicallRead, type MulticallReadItem, + batchRead, } from "../dealClient.js"; import { ccIds, ccDetails } from "../gql/gql.js"; import type { CapacityCommitmentStatus } from "../gql/gqlGenerated.js"; @@ -741,25 +743,14 @@ export async function getCommitmentsGroupedByStatus< const commitments = await getCommitments(...args); const { contracts } = await getContracts(); - const statuses = await multicallRead( - commitments.map(({ infoFromSubgraph: { id } }): MulticallReadItem => { - return { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData("getStatus", [ - id, - ]), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "getStatus", - returnData, - ); - }, + const rpcCCInfos = await batchRead( + commitments.map(({ infoFromSubgraph: { id } }) => { + return () => { + return contracts.diamond.getCommitment(id); }; }), ); - dbg(`Statuses: ${jsonStringify(statuses)}`); - return Array.from( (await getCommitments(...args)) .reduce< @@ -770,13 +761,12 @@ export async function getCommitmentsGroupedByStatus< >[] > >((acc, v, i) => { - if (typeof statuses[i] !== "bigint") { - throw new Error( - `Expected status from RPC to be a bigint, got ${stringifyUnknown(statuses[i])}`, - ); - } + assert( + rpcCCInfos[i] !== undefined, + "Unreachable. Expected getCommitment from RPC not to be undefined", + ); - const statusFromRPC = ccStatusToString(statuses[i]); + const statusFromRPC = ccStatusToString(rpcCCInfos[i].status); const infos = acc.get(statusFromRPC) ?? []; infos.push({ diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index e639df104..c2985b4d7 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -34,6 +34,7 @@ import type { BytesLike, Result, } from "ethers"; +import chunk from "lodash-es/chunk.js"; import stripAnsi from "strip-ansi"; import { @@ -674,6 +675,25 @@ export async function multicallRead( }); } +export async function batchRead(rpcReadCalls: Array<() => Promise>) { + let rpcResults: Array = []; + + for (const rpcReadCallBatch of chunk( + rpcReadCalls, + 20, // it's our guess on the max number of concurrent requests to RPC + )) { + rpcResults = rpcResults.concat( + await Promise.all( + rpcReadCallBatch.map((rpcReadCall) => { + return rpcReadCall(); + }), + ), + ); + } + + return rpcResults; +} + export async function guessTxSizeAndSign< T, A extends Array = Array, From a7ee43fc20ce7f37b01d20ea07ea4f42a3d9490c Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Tue, 12 Nov 2024 17:08:54 +0100 Subject: [PATCH 31/37] try adding timeout --- .../cli/package/src/lib/chain/commitment.ts | 31 ++++++++------ packages/cli/package/src/lib/dealClient.ts | 20 --------- .../cli/package/test/tests/provider.test.ts | 41 +++++++++++++++++++ 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index eefd9a49d..5d4efce22 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -15,8 +15,6 @@ * along with this program. If not, see . */ -import assert from "assert"; - import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { color } from "@oclif/color"; import parse from "parse-duration"; @@ -40,7 +38,6 @@ import { sign, multicallRead, type MulticallReadItem, - batchRead, } from "../dealClient.js"; import { ccIds, ccDetails } from "../gql/gql.js"; import type { CapacityCommitmentStatus } from "../gql/gqlGenerated.js"; @@ -743,10 +740,19 @@ export async function getCommitmentsGroupedByStatus< const commitments = await getCommitments(...args); const { contracts } = await getContracts(); - const rpcCCInfos = await batchRead( - commitments.map(({ infoFromSubgraph: { id } }) => { - return () => { - return contracts.diamond.getCommitment(id); + const statuses = await multicallRead( + commitments.map(({ infoFromSubgraph: { id } }): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("getStatus", [ + id, + ]), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getStatus", + returnData, + ); + }, }; }), ); @@ -761,12 +767,13 @@ export async function getCommitmentsGroupedByStatus< >[] > >((acc, v, i) => { - assert( - rpcCCInfos[i] !== undefined, - "Unreachable. Expected getCommitment from RPC not to be undefined", - ); + if (typeof statuses[i] !== "bigint") { + throw new Error( + `Expected status from RPC to be a bigint, got ${stringifyUnknown(statuses[i])}`, + ); + } - const statusFromRPC = ccStatusToString(rpcCCInfos[i].status); + const statusFromRPC = ccStatusToString(statuses[i]); const infos = acc.get(statusFromRPC) ?? []; infos.push({ diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index c2985b4d7..e639df104 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -34,7 +34,6 @@ import type { BytesLike, Result, } from "ethers"; -import chunk from "lodash-es/chunk.js"; import stripAnsi from "strip-ansi"; import { @@ -675,25 +674,6 @@ export async function multicallRead( }); } -export async function batchRead(rpcReadCalls: Array<() => Promise>) { - let rpcResults: Array = []; - - for (const rpcReadCallBatch of chunk( - rpcReadCalls, - 20, // it's our guess on the max number of concurrent requests to RPC - )) { - rpcResults = rpcResults.concat( - await Promise.all( - rpcReadCallBatch.map((rpcReadCall) => { - return rpcReadCall(); - }), - ), - ); - } - - return rpcResults; -} - export async function guessTxSizeAndSign< T, A extends Array = Array, diff --git a/packages/cli/package/test/tests/provider.test.ts b/packages/cli/package/test/tests/provider.test.ts index 085b7ae41..927be708c 100644 --- a/packages/cli/package/test/tests/provider.test.ts +++ b/packages/cli/package/test/tests/provider.test.ts @@ -28,6 +28,7 @@ import { PRIV_KEY_FLAG_NAME, PROVIDER_CONFIG_FULL_FILE_NAME, } from "../../src/lib/const.js"; +import { setTryTimeout } from "../../src/lib/helpers/setTryTimeout.js"; import { stringifyUnknown } from "../../src/lib/helpers/stringifyUnknown.js"; import { numToStr } from "../../src/lib/helpers/typesafeStringify.js"; import { fluence } from "../helpers/commonWithSetupTests.js"; @@ -194,6 +195,46 @@ describe("provider tests", () => { cwd, }); + await setTryTimeout( + "wait until all commitments get WaitDelegation status", + async () => { + const res = JSON.parse( + await fluence({ + args: ["provider", "cc-info"], + flags: { + [OFFER_FLAG_NAME]: NEW_OFFER_NAME, + json: true, + }, + cwd, + }), + ); + + if (!Array.isArray(res)) { + throw new Error("Expected an array of commitments"); + } + + const ccWithInvalidStatus = res.filter((el) => { + return ( + typeof el !== "object" || + el === null || + !("status" in el) || + el.status !== "WaitDelegation" + ); + }); + + if (ccWithInvalidStatus.length > 0) { + throw new Error( + `Some commitments are not in WaitDelegation status: ${JSON.stringify(ccWithInvalidStatus, null, 2)}`, + ); + } + }, + (e) => { + throw e; + }, + 60_000, + 5_000, + ); + await fluence({ args: ["provider", "cc-activate"], flags: { From 7f53ceedacaa74517d4eda43ffc754fcce8b47b8 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 13 Nov 2024 17:10:35 +0100 Subject: [PATCH 32/37] use on-chain info for cc, refactor and fix --- .../src/commands/provider/deal-exit.ts | 95 ++- .../src/commands/provider/deal-list.ts | 9 +- .../cli/package/src/lib/chain/commitment.ts | 804 +++++++++--------- packages/cli/package/src/lib/chain/deals.ts | 2 +- .../src/lib/chain/depositCollateral.ts | 73 +- packages/cli/package/src/lib/deal.ts | 14 +- packages/cli/package/src/lib/dealClient.ts | 4 +- packages/cli/package/src/lib/gql/gql.ts | 71 +- .../cli/package/src/lib/gql/schema.graphql | 57 +- .../cli/package/test/tests/provider.test.ts | 41 - 10 files changed, 557 insertions(+), 613 deletions(-) diff --git a/packages/cli/package/src/commands/provider/deal-exit.ts b/packages/cli/package/src/commands/provider/deal-exit.ts index 4cd620c1e..26411d7db 100644 --- a/packages/cli/package/src/commands/provider/deal-exit.ts +++ b/packages/cli/package/src/commands/provider/deal-exit.ts @@ -15,10 +15,11 @@ * along with this program. If not, see . */ -import { Flags } from "@oclif/core"; +import assert from "assert"; + +import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { BaseCommand } from "../../baseCommand.js"; -import { getProviderDeals } from "../../lib/chain/deals.js"; import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS, @@ -28,8 +29,10 @@ import { import { getContracts, getSignerAddress, + multicallRead, populateTx, signBatch, + type MulticallReadItem, } from "../../lib/dealClient.js"; import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { commaSepStrToArr } from "../../lib/helpers/utils.js"; @@ -42,11 +45,11 @@ export default class DealExit extends BaseCommand { static override flags = { ...CHAIN_FLAGS, ...DEAL_IDS_FLAG, - all: Flags.boolean({ - default: false, - description: - "To use all deal ids that indexer is aware of for your provider address", - }), + // all: Flags.boolean({ + // default: false, + // description: + // "To use all deal ids that indexer is aware of for your provider address", + // }), }; async run(): Promise { @@ -54,39 +57,61 @@ export default class DealExit extends BaseCommand { const { contracts } = await getContracts(); const signerAddress = await getSignerAddress(); - const dealIds = flags.all - ? await getProviderDeals() - : commaSepStrToArr( - flags[DEAL_IDS_FLAG_NAME] ?? - (await input({ - message: "Enter comma-separated deal ids", - validate(input: string) { - return ( - commaSepStrToArr(input).length > 0 || - "Please enter at least one deal id" - ); - }, - })), - ); + const dealIds = + // flags.all + // ? await getProviderDeals() + // : + commaSepStrToArr( + flags[DEAL_IDS_FLAG_NAME] ?? + (await input({ + message: "Enter comma-separated deal ids", + validate(input: string) { + return ( + commaSepStrToArr(input).length > 0 || + "Please enter at least one deal id" + ); + }, + })), + ); if (dealIds.length === 0) { return commandObj.error("No deal ids provided"); } - const workers = ( - await Promise.all( - dealIds.map(async (id) => { - const deal = contracts.getDeal(id); - return (await deal.getWorkers()).map((worker) => { - return { deal, worker }; - }); - }), - ) - ) - .flat() - .filter(({ worker }) => { - return worker.provider.toLowerCase() === signerAddress; - }); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const workersFromRPC = (await multicallRead( + dealIds.map((id): MulticallReadItem => { + const deal = contracts.getDeal(id); + return { + target: id, + callData: deal.interface.encodeFunctionData("getWorkers"), + decode(returnData) { + return deal.interface.decodeFunctionResult( + "getWorkers", + returnData, + ); + }, + }; + }), + )) as Awaited["getWorkers"]>>[]; + + const workers = dealIds.flatMap((id, i) => { + const deal = contracts.getDeal(id); + const workers = workersFromRPC[i]; + + assert( + workers !== undefined, + `Unreachable. Got nothing from RPC for deal id ${id}`, + ); + + return workers + .filter((worker) => { + return worker.provider.toLowerCase() === signerAddress; + }) + .map((worker) => { + return { worker, deal }; + }); + }); const [firstWorker, ...restWorkers] = workers; diff --git a/packages/cli/package/src/commands/provider/deal-list.ts b/packages/cli/package/src/commands/provider/deal-list.ts index 559e194e1..1532a41e7 100644 --- a/packages/cli/package/src/commands/provider/deal-list.ts +++ b/packages/cli/package/src/commands/provider/deal-list.ts @@ -16,8 +16,9 @@ */ import { BaseCommand } from "../../baseCommand.js"; -import { getProviderDeals } from "../../lib/chain/deals.js"; import { commandObj } from "../../lib/commandObj.js"; +// import { getProviderDeals } from "../../lib/chain/deals.js"; +// import { commandObj } from "../../lib/commandObj.js"; import { CHAIN_FLAGS } from "../../lib/const.js"; import { aliasesText } from "../../lib/helpers/aliasesText.js"; import { initCli } from "../../lib/lifeCycle.js"; @@ -31,6 +32,10 @@ export default class DealsList extends BaseCommand { async run(): Promise { await initCli(this, await this.parse(DealsList)); - commandObj.log((await getProviderDeals()).join("\n")); + + commandObj.error( + "This command is temporary not working. Please use explorer to see deals", + ); + // commandObj.log((await getProviderDeals()).join("\n")); } } diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 5d4efce22..5296aec9b 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +import assert from "assert"; + import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { color } from "@oclif/color"; import parse from "parse-duration"; @@ -39,8 +41,11 @@ import { multicallRead, type MulticallReadItem, } from "../dealClient.js"; -import { ccIds, ccDetails } from "../gql/gql.js"; -import type { CapacityCommitmentStatus } from "../gql/gqlGenerated.js"; +import { ccDetails } from "../gql/gql.js"; +import type { + CapacityCommitmentStatus, + CcDetailsQuery, +} from "../gql/gqlGenerated.js"; import { bigintSecondsToDate } from "../helpers/bigintOps.js"; import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; @@ -61,76 +66,55 @@ import { fltFormatWithSymbol } from "./currencies.js"; const HUNDRED_PERCENT = 100; export type ComputePeersWithCC = Awaited< - ReturnType + ReturnType >; -type CommitmentAndPeerId = { id: string; peer: { id: string } }; - -async function getComputePeersWithCC( - [firstComputePeer, ...restComputePeers]: [ - ResolvedComputePeer, - ...ResolvedComputePeer[], - ], - getCCByHexPeerId: ( - hexPeerIds: [string, ...string[]], - ) => Promise<{ capacityCommitments: T[] }>, -): Promise< - [ - { - name: string; - infoFromSubgraph: T; - }, - ...{ - name: string; - infoFromSubgraph: T; - }[], - ] -> { - const computePeersWithHexPeerIds = await Promise.all([ - (async () => { - return { - ...firstComputePeer, - hexPeerId: await peerIdBase58ToHexString(firstComputePeer.peerId), - }; - })(), - ...restComputePeers.map(async (computePeer) => { +async function getComputePeersWithCCIds( + computePeers: ResolvedComputePeer[], +): Promise<[Required, ...Required[]]> { + const computePeersWithHexPeerIds = await Promise.all( + computePeers.map(async (computePeer) => { return { ...computePeer, hexPeerId: await peerIdBase58ToHexString(computePeer.peerId), }; }), - ]); + ); - const [firstComputePeerWithHexPeerId, ...restComputePeersWithHexPeerIds] = - computePeersWithHexPeerIds; + const { contracts } = await getContracts(); - const { capacityCommitments } = await getCCByHexPeerId([ - firstComputePeerWithHexPeerId.hexPeerId, - ...restComputePeersWithHexPeerIds.map(({ hexPeerId }) => { - return hexPeerId; + const computePeersRPCInfo = await multicallRead( + computePeersWithHexPeerIds.map(({ hexPeerId }): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getComputePeer", + [hexPeerId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getComputePeer", + returnData, + ); + }, + }; }), - ]); - - const ccInfoByHexPeerId = capacityCommitments.reduce>( - (acc, cc) => { - acc[cc.peer.id] = cc; - return acc; - }, - {}, ); const { ZeroHash } = await import("ethers"); const [computePeersWithoutCC, computePeersWithCC] = splitErrorsAndResults( computePeersWithHexPeerIds, - ({ hexPeerId, name, peerId }) => { - const infoFromSubgraph = ccInfoByHexPeerId[hexPeerId]; - - return infoFromSubgraph === undefined || infoFromSubgraph.id === ZeroHash + ({ name, peerId }, i) => { + const { commitmentId: ccId } = + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (computePeersRPCInfo[i] as + | Awaited> + | undefined) ?? {}; + + return ccId === undefined || ccId === ZeroHash ? { error: { name, peerId } } - : { - result: { name, infoFromSubgraph } satisfies CapacityCommitment, - }; + : { result: { name, peerId, ccId } satisfies CapacityCommitment }; }, ); @@ -158,38 +142,56 @@ async function getComputePeersWithCC( return [firstComputePeerWithCC, ...restComputePeersWithCC]; } -async function getCCs( - ccIds: [string, ...string[]], - getCCByCCIds: ( - ccIds: [string, ...string[]], - ) => Promise<{ capacityCommitments: T[] }>, -) { - const { capacityCommitments } = await getCCByCCIds(ccIds); +async function getCCs( + ccIdsString: string, +): Promise<[CapacityCommitment, ...CapacityCommitment[]]> { + const ccIds = commaSepStrToArr(ccIdsString); + const { contracts } = await getContracts(); - const ccInfoByCCId = capacityCommitments.reduce>( - (acc, cc) => { - acc[cc.id] = cc; - return acc; - }, - {}, + const computePeers = await multicallRead( + ccIds.map((ccId): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getCommitment", + [ccId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getCommitment", + returnData, + ); + }, + }; + }), ); - const { ZeroHash } = await import("ethers"); - - const [ccIdsWithoutInfo, ccInfos] = splitErrorsAndResults(ccIds, (ccId) => { - const infoFromSubgraph = ccInfoByCCId[ccId]; - return infoFromSubgraph === undefined || infoFromSubgraph.id === ZeroHash - ? { error: ccId } - : { result: { infoFromSubgraph } satisfies CapacityCommitment }; - }); + const [ccIdsWithoutInfo, ccInfos] = splitErrorsAndResults( + ccIds, + (ccId, i) => { + const { peerId: peerIdHex } = + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (computePeers[i] as + | Awaited> + | undefined) ?? {}; + + return peerIdHex === undefined + ? { error: ccId } + : { result: { peerIdHex, ccId } }; + }, + ); if (ccIdsWithoutInfo.length > 0) { commandObj.warn( - `Some of the commitments were not found:\n${ccIdsWithoutInfo.join("\n")}`, + `Some of the commitments were not found on chain:\n${ccIdsWithoutInfo.join("\n")}`, ); } - const [firstCCInfo, ...restCCInfos] = ccInfos; + const [firstCCInfo, ...restCCInfos] = await Promise.all( + ccInfos.map(async ({ ccId, peerIdHex }) => { + return { ccId, peerId: await peerIdHexStringToBase58String(peerIdHex) }; + }), + ); if (firstCCInfo === undefined) { return commandObj.error("No commitments were found"); @@ -204,46 +206,18 @@ export type CCFlags = { [CC_IDS_FLAG_NAME]?: string | undefined; }; -export async function getCommitments< - T extends { id: string; peer: { id: string } }, ->( +export async function getCommitmentsIds( flags: CCFlags, - { - getCCByCCId, - getCCByHexPeerId, - }: { - getCCByCCId: ( - ccIds: [string, ...string[]], - ) => Promise<{ capacityCommitments: T[] }>; - getCCByHexPeerId: ( - hexPeerIds: [string, ...string[]], - ) => Promise<{ capacityCommitments: T[] }>; - }, -): Promise<[CapacityCommitment, ...CapacityCommitment[]]> { +): Promise<[CapacityCommitment, ...CapacityCommitment[]]> { if (flags[CC_IDS_FLAG_NAME] !== undefined) { - const [firstCCId, ...restCCIds] = commaSepStrToArr(flags[CC_IDS_FLAG_NAME]); - - if (firstCCId === undefined) { - return commandObj.error("No commitment ids specified"); - } - - const [firstCC, ...restCCs] = await getCCs( - [firstCCId, ...restCCIds], - getCCByCCId, - ); - - if (firstCC === undefined) { - return commandObj.error("No commitment ids specified"); - } - - return [firstCC, ...restCCs]; + return getCCs(flags[CC_IDS_FLAG_NAME]); } if ( flags[NOX_NAMES_FLAG_NAME] === undefined && (await initProviderConfig()) === null ) { - const [firstCCId, ...restCCIds] = commaSepStrToArr( + return getCCs( await input({ message: "Enter comma-separated list of Capacity Commitment IDs", validate(val: string) { @@ -254,27 +228,9 @@ export async function getCommitments< }, }), ); - - if (firstCCId === undefined) { - return commandObj.error("No commitment ids provided"); - } - - const [firstCC, ...restCCs] = await getCCs( - [firstCCId, ...restCCIds], - getCCByCCId, - ); - - if (firstCC === undefined) { - return commandObj.error("No commitment ids specified"); - } - - return [firstCC, ...restCCs]; } - return getComputePeersWithCC( - await resolveComputePeersByNames(flags), - getCCByHexPeerId, - ); + return getComputePeersWithCCIds(await resolveComputePeersByNames(flags)); } export async function createCommitments(flags: { @@ -406,11 +362,9 @@ export async function createCommitments(flags: { const [notStringCommitmentIds, stringCommitmentIds] = splitErrorsAndResults( commitmentIds, (id) => { - if (typeof id !== "string") { - return { error: stringifyUnknown(id) }; - } - - return { result: id }; + return typeof id === "string" + ? { result: id } + : { error: stringifyUnknown(id) }; }, ); @@ -442,34 +396,27 @@ export async function createCommitments(flags: { } export async function removeCommitments(flags: CCFlags) { - const [invalidCommitments, commitments] = splitErrorsAndResults( - (await getCommitmentsGroupedByStatus(flags, ccIds)).flatMap( - ({ ccInfos }) => { - return ccInfos; - }, - ), - (cc) => { - return cc.infoFromSubgraph.statusFromRPC === "WaitDelegation" - ? { result: cc } - : { error: cc }; - }, - ); + const [invalidCommitments, ccWithWaitDelegationStatusGroup] = + splitErrorsAndResults(await getCommitmentsGroupedByStatus(flags), (cc) => { + return cc.status === "WaitDelegation" ? { result: cc } : { error: cc }; + }); if (invalidCommitments.length > 0) { commandObj.warn( - `You can remove commitments only if they have WaitDelegation status. Got:\n\n${( - await Promise.all( - invalidCommitments.map(async (cc) => { - return `${await stringifyBasicCommitmentInfo(cc)}Status: ${cc.infoFromSubgraph.statusFromRPC}`; - }), - ) - ).join("\n\n")}`, + `You can remove commitments only if they have WaitDelegation status. Got:\n\n${basicCCInfoAndStatusToString(invalidCommitments)}`, ); } - const [firstCommitment, ...restCommitments] = commitments; + const CCsWithWaitDelegationStatus = ccWithWaitDelegationStatusGroup.flatMap( + ({ ccInfos }) => { + return ccInfos; + }, + ); - if (firstCommitment === undefined) { + const [firstCCWithWaitDelegationStatus, ...restCCsWithWaitDelegationStatus] = + CCsWithWaitDelegationStatus; + + if (firstCCWithWaitDelegationStatus === undefined) { return commandObj.error( "No commitments with 'WaitDelegation' status found", ); @@ -477,32 +424,27 @@ export async function removeCommitments(flags: CCFlags) { const { contracts } = await getContracts(); + const CCsWithWaitDelegationStatusString = CCsWithWaitDelegationStatus.map( + (commitment) => { + return stringifyBasicCommitmentInfo(commitment); + }, + ).join("\n\n"); + await signBatch( - `Remove the following commitments:\n\n${commitments - .map((commitment) => { - return stringifyBasicCommitmentInfo(commitment); - }) - .join("\n\n")}`, + `Remove the following commitments:\n\n${CCsWithWaitDelegationStatusString}`, [ populateTx( contracts.diamond.removeCommitment, - firstCommitment.infoFromSubgraph.id, + firstCCWithWaitDelegationStatus.ccId, ), - ...restCommitments.map(({ infoFromSubgraph }) => { - return populateTx( - contracts.diamond.removeCommitment, - infoFromSubgraph.id, - ); + ...restCCsWithWaitDelegationStatus.map(({ ccId }) => { + return populateTx(contracts.diamond.removeCommitment, ccId); }), ], ); commandObj.logToStderr( - `Removed commitments:\n\n${commitments - .map((commitment) => { - return stringifyBasicCommitmentInfo(commitment); - }) - .join("\n")}`, + `Removed commitments:\n\n${CCsWithWaitDelegationStatusString}`, ); } @@ -514,7 +456,7 @@ export async function collateralWithdraw( const { ZeroAddress } = await import("ethers"); const [invalidCommitments, commitments] = splitErrorsAndResults( - await getCommitmentsGroupedByStatus(flags, ccIds), + await getCommitmentsGroupedByStatus(flags), (c) => { return c.status === "Completed" || c.status === "Failed" ? { result: c } @@ -524,7 +466,7 @@ export async function collateralWithdraw( if (invalidCommitments.length > 0) { commandObj.warn( - `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( + `You can withdraw collateral only from commitments with "Inactive" or "Failed" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( invalidCommitments, )}`, ); @@ -541,13 +483,10 @@ export async function collateralWithdraw( for (const commitment of commitments.flatMap(({ ccInfos }) => { return ccInfos; })) { - const { - infoFromSubgraph: { id: commitmentId }, - name: noxName, - } = commitment; + const { ccId, name: noxName } = commitment; const [unitIds, isExitedStatuses] = - await contracts.diamond.getUnitExitStatuses(commitmentId); + await contracts.diamond.getUnitExitStatuses(ccId); // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const computeUnitInfos = (await multicallRead( @@ -566,7 +505,10 @@ export async function collateralWithdraw( }, }; }), - )) as Awaited>[]; + )) as ( + | Awaited> + | undefined + )[]; const units = unitIds.map((unitId, i) => { return { @@ -636,7 +578,7 @@ export async function collateralWithdraw( ); } catch (e) { commandObj.warn( - `Wasn't able to move resources from deals for ${await stringifyBasicCommitmentInfo(commitment)}. Most likely the reason is you must wait until the provider exits from all the following deals:\n${dealsString}`, + `Wasn't able to move resources from deals for ${stringifyBasicCommitmentInfo(commitment)}. Most likely the reason is you must wait until the provider exits from all the following deals:\n${dealsString}`, ); dbg(stringifyUnknown(e)); @@ -645,13 +587,13 @@ export async function collateralWithdraw( } await sign({ - title: `withdraw collateral from: ${commitmentId}`, + title: `withdraw collateral from: ${ccId}`, method: contracts.diamond.withdrawCollateral, - args: [commitmentId], + args: [ccId], }); commandObj.logToStderr( - `Collateral withdrawn for:\n${await stringifyBasicCommitmentInfo(commitment)}`, + `Collateral withdrawn for:\n${stringifyBasicCommitmentInfo(commitment)}`, ); const shouldFinishCommitment = flags[FINISH_COMMITMENT_FLAG_NAME] ?? true; // for provider it's true by default @@ -667,85 +609,76 @@ export async function collateralWithdraw( ); await signBatch( - `${firstNotExitedUnit === undefined ? "F" : "Remove compute units from capacity commitments and f"}inish commitment ${noxName === undefined ? commitmentId : `for ${noxName} (${commitmentId})`} ${commitmentId}`, + `${firstNotExitedUnit === undefined ? "F" : "Remove compute units from capacity commitments and f"}inish commitment ${noxName === undefined ? ccId : `for ${noxName} (${ccId})`} ${ccId}`, firstNotExitedUnit === undefined - ? [populateTx(contracts.diamond.finishCommitment, commitmentId)] + ? [populateTx(contracts.diamond.finishCommitment, ccId)] : [ - populateTx(contracts.diamond.removeCUFromCC, commitmentId, [ + populateTx(contracts.diamond.removeCUFromCC, ccId, [ firstNotExitedUnit.unitId, ]), ...restNotExitedUnits.map(({ unitId }) => { - return populateTx( - contracts.diamond.removeCUFromCC, - commitmentId, - [unitId], - ); + return populateTx(contracts.diamond.removeCUFromCC, ccId, [ + unitId, + ]); }), - populateTx(contracts.diamond.finishCommitment, commitmentId), + populateTx(contracts.diamond.finishCommitment, ccId), ], ); } } export async function collateralRewardWithdraw(flags: CCFlags) { - const commitments = await getCommitments(flags, ccIds); + const commitments = await getCommitmentsIds(flags); const [firstCommitment, ...restCommitments] = commitments; const { contracts } = await getContracts(); await signBatch( `Withdraw rewards for commitments:\n\n${commitments - .map(({ infoFromSubgraph: { id } }) => { - return id; + .map(({ ccId }) => { + return ccId; }) .join("\n")}`, [ - populateTx( - contracts.diamond.withdrawReward, - firstCommitment.infoFromSubgraph.id, - ), - ...restCommitments.map(({ infoFromSubgraph: { id } }) => { - return populateTx(contracts.diamond.withdrawReward, id); + populateTx(contracts.diamond.withdrawReward, firstCommitment.ccId), + ...restCommitments.map(({ ccId }) => { + return populateTx(contracts.diamond.withdrawReward, ccId); }), ], ); } -export async function stringifyBasicCommitmentInfo< - T extends CommitmentAndPeerId, ->({ name, infoFromSubgraph }: CapacityCommitment) { - const peerId = await peerIdHexStringToBase58String(infoFromSubgraph.peer.id); +export function stringifyBasicCommitmentInfo({ + name, + peerId, + ccId, +}: CapacityCommitment) { const noxName = name === undefined ? "" : `Nox: ${name}\n`; - return `${color.yellow(`${noxName}PeerId: ${peerId}`)}\nCommitmentId: ${infoFromSubgraph.id}`; + return `${color.yellow(`${noxName}PeerId: ${peerId}`)}\nCommitmentId: ${ccId}`; } -type CapacityCommitment = { - infoFromSubgraph: T; +type CapacityCommitment = { + ccId: string; + peerId: string; name?: string; }; -type CommitmentGroupedByStatus = { +type CommitmentGroupedByStatus = { status: CapacityCommitmentStatusString; - ccInfos: CapacityCommitment[]; + ccInfos: (CapacityCommitment & { status: CapacityCommitmentStatusString })[]; }[]; -export async function getCommitmentsGroupedByStatus< - T extends CommitmentAndPeerId, ->( - ...args: Parameters> -): Promise< - CommitmentGroupedByStatus< - T & { statusFromRPC: CapacityCommitmentStatusString } - > -> { - const commitments = await getCommitments(...args); +export async function getCommitmentsGroupedByStatus( + flags: CCFlags, +): Promise { + const commitments = await getCommitmentsIds(flags); const { contracts } = await getContracts(); const statuses = await multicallRead( - commitments.map(({ infoFromSubgraph: { id } }): MulticallReadItem => { + commitments.map(({ ccId }): MulticallReadItem => { return { target: contracts.deployment.diamond, callData: contracts.diamond.interface.encodeFunctionData("getStatus", [ - id, + ccId, ]), decode(returnData) { return contracts.diamond.interface.decodeFunctionResult( @@ -758,33 +691,24 @@ export async function getCommitmentsGroupedByStatus< ); return Array.from( - (await getCommitments(...args)) + commitments .reduce< Map< CapacityCommitmentStatusString, - CapacityCommitment< - T & { statusFromRPC: CapacityCommitmentStatusString } - >[] + (CapacityCommitment & { + status: CapacityCommitmentStatusString; + })[] > >((acc, v, i) => { - if (typeof statuses[i] !== "bigint") { - throw new Error( - `Expected status from RPC to be a bigint, got ${stringifyUnknown(statuses[i])}`, - ); - } - - const statusFromRPC = ccStatusToString(statuses[i]); - const infos = acc.get(statusFromRPC) ?? []; - - infos.push({ - ...v, - infoFromSubgraph: { - ...v.infoFromSubgraph, - statusFromRPC, - }, - }); + assert( + typeof statuses[i] === "bigint", + `Unreachable. Didn't get status for commitment ${v.ccId} from chain`, + ); - acc.set(statusFromRPC, infos); + const status = ccStatusToString(statuses[i]); + const infos = acc.get(status) ?? []; + infos.push({ ...v, status }); + acc.set(status, infos); return acc; }, new Map()) .entries(), @@ -830,22 +754,30 @@ function getRewardsMulticallReads( ); }, }, + { + target: diamondContractAddress, + callData: diamondContract.interface.encodeFunctionData("getCommitment", [ + commitmentId, + ]), + decode(returnData) { + return diamondContract.interface.decodeFunctionResult( + "getCommitment", + returnData, + ); + }, + }, ]; } export async function getDetailedCommitmentsInfoGroupedByStatus( flags: CCFlags, ) { - const ccGroupedByStatus = await getCommitmentsGroupedByStatus( - flags, - ccDetails, - ); - + const ccGroupedByStatus = await getCommitmentsGroupedByStatus(flags); const { contracts } = await getContracts(); const allCCIds = ccGroupedByStatus.flatMap(({ ccInfos }) => { - return ccInfos.map(({ infoFromSubgraph: { id } }) => { - return id; + return ccInfos.map(({ ccId }) => { + return ccId; }); }); @@ -860,89 +792,123 @@ export async function getDetailedCommitmentsInfoGroupedByStatus( const contractReadsPerCC = rewardsMulticallReads.length / allCCIds.length; const [ - currentEpoch, - epochDuration, - initTimestamp, - maxFailedRatio, - precision, - ...rewards + [ + currentEpoch, + epochDuration, + initTimestamp, + maxFailedRatio, + precision, + ...rewards + ], + ccInfosFromSubgraph, + ] = await Promise.all([ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - ] = (await multicallRead([ - { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData("currentEpoch"), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "currentEpoch", - returnData, - ); + multicallRead([ + { + target: contracts.deployment.diamond, + callData: + contracts.diamond.interface.encodeFunctionData("currentEpoch"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "currentEpoch", + returnData, + ); + }, }, - }, - { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData("epochDuration"), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "epochDuration", - returnData, - ); + { + target: contracts.deployment.diamond, + callData: + contracts.diamond.interface.encodeFunctionData("epochDuration"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "epochDuration", + returnData, + ); + }, }, - }, - { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData("initTimestamp"), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "initTimestamp", - returnData, - ); + { + target: contracts.deployment.diamond, + callData: + contracts.diamond.interface.encodeFunctionData("initTimestamp"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "initTimestamp", + returnData, + ); + }, }, - }, - { - target: contracts.deployment.diamond, - callData: - contracts.diamond.interface.encodeFunctionData("maxFailedRatio"), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "maxFailedRatio", - returnData, - ); + { + target: contracts.deployment.diamond, + callData: + contracts.diamond.interface.encodeFunctionData("maxFailedRatio"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "maxFailedRatio", + returnData, + ); + }, }, - }, - { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData("precision"), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( - "precision", - returnData, - ); + { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData("precision"), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "precision", + returnData, + ); + }, }, - }, - ...ccGroupedByStatus.flatMap(({ ccInfos }) => { - return ccInfos.flatMap(({ infoFromSubgraph: { id } }) => { - return getRewardsMulticallReads( - id, - contracts.diamond, - contracts.deployment.diamond, - ); - }); - }), - ])) as [ - Awaited>, - Awaited>, - Awaited>, - Awaited>, - Awaited>, - ...Awaited< - ReturnType< - | typeof contracts.diamond.unlockedRewards - | typeof contracts.diamond.totalRewards - > - >[], - ]; + ...ccGroupedByStatus.flatMap(({ ccInfos }) => { + return ccInfos.flatMap(({ ccId }) => { + return getRewardsMulticallReads( + ccId, + contracts.diamond, + contracts.deployment.diamond, + ); + }); + }), + ]) as Promise< + [ + Awaited> | undefined, + Awaited> | undefined, + Awaited> | undefined, + ( + | Awaited> + | undefined + ), + Awaited> | undefined, + ...( + | Awaited< + ReturnType< + | typeof contracts.diamond.unlockedRewards + | typeof contracts.diamond.totalRewards + | typeof contracts.diamond.getCommitment + > + > + | undefined + )[], + ] + >, + ccDetails(allCCIds), + ]); + + assert(currentEpoch !== undefined, "currentEpoch is undefined"); + assert(epochDuration !== undefined, "epochDuration is undefined"); + assert(initTimestamp !== undefined, "initTimestamp is undefined"); + assert(maxFailedRatio !== undefined, "maxFailedRatio is undefined"); + assert(precision !== undefined, "precision is undefined"); + + const commitmentsById = ccInfosFromSubgraph.capacityCommitments.reduce< + Record + >((acc, cc) => { + const ccIds = acc[cc.id] ?? []; + ccIds.push(cc); + acc[cc.id] = ccIds; + return acc; + }, {}); let rewardsCounter = -contractReadsPerCC; + let infoFromSubgraphCounter = -1; return Promise.all( ccGroupedByStatus.map(async (groupedCCs) => { @@ -951,22 +917,50 @@ export async function getDetailedCommitmentsInfoGroupedByStatus( CCs: await Promise.all( groupedCCs.ccInfos.map(async (cc) => { rewardsCounter = rewardsCounter + contractReadsPerCC; + infoFromSubgraphCounter = infoFromSubgraphCounter + 1; + const infoFromSubgraph = commitmentsById[cc.ccId]?.[0]; + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const unlockedRewards = rewards[rewardsCounter] as + | Awaited> + | undefined; + + assert( + unlockedRewards !== undefined, + "Unreachable. unlockedRewards must be defined", + ); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const totalRewards = rewards[rewardsCounter + 1] as + | Awaited> + | undefined; + + assert( + totalRewards !== undefined, + "Unreachable. totalRewards must be defined", + ); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const ccFromChain = rewards[rewardsCounter + 2] as + | Awaited> + | undefined; + + assert( + ccFromChain !== undefined, + "Unreachable. ccFromChain must be defined", + ); return getDetailedCommitmentInfo({ ...cc, + infoFromSubgraph, currentEpoch, epochDuration, initTimestamp, maxFailedRatio, precision, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - unlockedRewards: rewards[rewardsCounter] as Awaited< - ReturnType - >, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - totalRewards: rewards[rewardsCounter + 1] as Awaited< - ReturnType - >, + ccFromChain, + unlockedRewards, + totalRewards, }); }), ), @@ -992,44 +986,22 @@ export function stringifyDetailedCommitmentsInfo( .join("\n\n"); } -function getStatusHeading( - cc: CommitmentGroupedByStatus[number], -) { +function getStatusHeading(cc: CommitmentGroupedByStatus[number]) { return color.yellow( `Status: ${cc.status} (${cc.ccInfos - .map(({ infoFromSubgraph: { id }, name }) => { - return name ?? id; + .map(({ ccId, name }) => { + return name ?? ccId; }) .join(",")})\n\n`, ); } -type DetailedCCInfo = Awaited< - ReturnType< - typeof getCommitmentsGroupedByStatus< - Awaited< - ReturnType<(typeof ccDetails)["getCCByCCId"]> - >["capacityCommitments"][number] - > - > ->[number]["ccInfos"][number]; - async function getDetailedCommitmentInfo({ - infoFromSubgraph: { - id: commitmentId, - startEpoch, - endEpoch, - delegator, - computeUnitsCount, - totalFailCount, - collateralPerUnit, - exitedUnitCount, - rewardDelegatorRate, - ccRewardsWithdrawn, - dealStakerRewardsWithdrawn, - peer: { id: peerId }, - statusFromRPC: status, - }, + infoFromSubgraph: { ccRewardsWithdrawn, dealStakerRewardsWithdrawn } = {}, + ccFromChain, + status, + peerId, + ccId, name: noxName, currentEpoch, epochDuration, @@ -1038,7 +1010,9 @@ async function getDetailedCommitmentInfo({ precision, totalRewards, unlockedRewards, -}: DetailedCCInfo & { +}: Awaited< + ReturnType +>[number]["ccInfos"][number] & { currentEpoch: bigint; epochDuration: bigint; initTimestamp: bigint; @@ -1046,54 +1020,62 @@ async function getDetailedCommitmentInfo({ precision: bigint; totalRewards: Rewards; unlockedRewards: Rewards; + infoFromSubgraph: + | Partial + | undefined; + ccFromChain: Awaited>; }) { - const rewardDelegatorRateBigInt = BigInt(rewardDelegatorRate); - const totalRewardsSplit = splitRewards( totalRewards, - rewardDelegatorRateBigInt, + ccFromChain.rewardDelegatorRate, precision, ); const unlockedRewardsSplit = splitRewards( unlockedRewards, - rewardDelegatorRateBigInt, + ccFromChain.rewardDelegatorRate, precision, ); - const withdrawnRewardsSplit = splitRewards( - { - ccRewards: BigInt(ccRewardsWithdrawn), - dealStakerRewards: BigInt(dealStakerRewardsWithdrawn), - }, - rewardDelegatorRateBigInt, - precision, - ); + const withdrawnRewardsSplit = + ccRewardsWithdrawn !== undefined && dealStakerRewardsWithdrawn !== undefined + ? splitRewards( + { + ccRewards: BigInt(ccRewardsWithdrawn), + dealStakerRewards: BigInt(dealStakerRewardsWithdrawn), + }, + ccFromChain.rewardDelegatorRate, + precision, + ) + : undefined; return { ...(noxName === undefined ? {} : { noxName }), - peerId: await peerIdHexStringToBase58String(peerId), - commitmentId, + peerId, + commitmentId: ccId, status, staker: - delegator?.id === (await import("ethers")).ZeroAddress + ccFromChain.delegator === (await import("ethers")).ZeroAddress ? "Anyone can activate capacity commitment" - : (delegator?.id ?? "Unknown"), - stakerReward: stakerRewardToString(rewardDelegatorRateBigInt, precision), - startEpoch, - endEpoch, + : ccFromChain.delegator, + stakerReward: stakerRewardToString( + ccFromChain.rewardDelegatorRate, + precision, + ), + startEpoch: bigintToStr(ccFromChain.startEpoch), + endEpoch: bigintToStr(ccFromChain.endEpoch), currentEpoch: bigintToStr(currentEpoch), startDate: bigintSecondsToDate( - initTimestamp + BigInt(startEpoch) * epochDuration, + initTimestamp + ccFromChain.startEpoch * epochDuration, ).toLocaleString(), expirationDate: bigintSecondsToDate( - initTimestamp + BigInt(endEpoch) * epochDuration, + initTimestamp + ccFromChain.endEpoch * epochDuration, ).toLocaleString(), - totalCU: numToStr(computeUnitsCount), - missedProofs: numToStr(totalFailCount), - threshold: bigintToStr(maxFailedRatio * BigInt(computeUnitsCount)), - collateralPerUnit: await fltFormatWithSymbol(BigInt(collateralPerUnit)), - exitedUnitCount: numToStr(exitedUnitCount), + totalCU: bigintToStr(ccFromChain.unitCount), + missedProofs: bigintToStr(ccFromChain.totalFailCount), + threshold: bigintToStr(maxFailedRatio * ccFromChain.unitCount), + collateralPerUnit: await fltFormatWithSymbol(ccFromChain.collateralPerUnit), + exitedUnitCount: bigintToStr(ccFromChain.exitedUnitCount), totalCCRewardsOverTime: await fltFormatWithSymbol( BigInt(totalRewards.ccRewards) + BigInt(totalRewards.dealStakerRewards), ), @@ -1103,18 +1085,20 @@ async function getDetailedCommitmentInfo({ providerRewardsAvailable: await fltFormatWithSymbol( unlockedRewardsSplit.provider, ), - providerRewardsTotalClaimed: await fltFormatWithSymbol( - withdrawnRewardsSplit.provider, - ), + providerRewardsTotalClaimed: + withdrawnRewardsSplit === undefined + ? "Didn't get claimed rewards from indexer" + : await fltFormatWithSymbol(withdrawnRewardsSplit.provider), stakerRewardsInVesting: await fltFormatWithSymbol( totalRewardsSplit.staker - unlockedRewardsSplit.staker, ), stakerRewardsAvailable: await fltFormatWithSymbol( unlockedRewardsSplit.staker, ), - stakerRewardsTotalClaimed: await fltFormatWithSymbol( - withdrawnRewardsSplit.staker, - ), + stakerRewardsTotalClaimed: + withdrawnRewardsSplit === undefined + ? "Didn't get claimed rewards from indexer" + : await fltFormatWithSymbol(withdrawnRewardsSplit.staker), } satisfies Record; } @@ -1196,20 +1180,16 @@ function ccStatusToString( ); } -export async function basicCCInfoAndStatusToString< - T extends CommitmentAndPeerId, ->(ccsGroupedByStatus: CommitmentGroupedByStatus) { - return ( - await Promise.all( - ccsGroupedByStatus.map(async (cc) => { - return `${getStatusHeading(cc)}${( - await Promise.all( - cc.ccInfos.map((ccInfo) => { - return stringifyBasicCommitmentInfo(ccInfo); - }), - ) - ).join("\n\n")} `; - }), - ) - ).join("\n\n"); +export function basicCCInfoAndStatusToString( + ccsGroupedByStatus: CommitmentGroupedByStatus, +) { + return ccsGroupedByStatus + .map((cc) => { + return `${getStatusHeading(cc)}${cc.ccInfos + .map((ccInfo) => { + return stringifyBasicCommitmentInfo(ccInfo); + }) + .join("\n\n")} `; + }) + .join("\n\n"); } diff --git a/packages/cli/package/src/lib/chain/deals.ts b/packages/cli/package/src/lib/chain/deals.ts index 0a3251161..7d6dadf84 100644 --- a/packages/cli/package/src/lib/chain/deals.ts +++ b/packages/cli/package/src/lib/chain/deals.ts @@ -19,7 +19,7 @@ import { getSignerAddress } from "../dealClient.js"; import { getDealIdsByProviderId } from "../gql/gql.js"; export async function getProviderDeals() { - return (await getDealIdsByProviderId(await getSignerAddress())).deals.map( + return (await getDealIdsByProviderId(await getSignerAddress())).map( ({ id }) => { return id; }, diff --git a/packages/cli/package/src/lib/chain/depositCollateral.ts b/packages/cli/package/src/lib/chain/depositCollateral.ts index 9f7acf077..a3bafafab 100644 --- a/packages/cli/package/src/lib/chain/depositCollateral.ts +++ b/packages/cli/package/src/lib/chain/depositCollateral.ts @@ -15,11 +15,17 @@ * along with this program. If not, see . */ +import assert from "assert"; + import { color } from "@oclif/color"; import { commandObj } from "../commandObj.js"; -import { getContracts, getReadonlyContracts, sign } from "../dealClient.js"; -import { ccIds } from "../gql/gql.js"; +import { + getContracts, + multicallRead, + sign, + type MulticallReadItem, +} from "../dealClient.js"; import { splitErrorsAndResults } from "../helpers/utils.js"; import { @@ -33,16 +39,13 @@ import { fltFormatWithSymbol } from "./currencies.js"; export async function depositCollateral(flags: CCFlags) { const [commitmentsWithInvalidStatus, commitmentsWithWaitDelegation] = - splitErrorsAndResults( - await getCommitmentsGroupedByStatus(flags, ccIds), - (c) => { - return c.status === "WaitDelegation" ? { result: c } : { error: c }; - }, - ); + splitErrorsAndResults(await getCommitmentsGroupedByStatus(flags), (c) => { + return c.status === "WaitDelegation" ? { result: c } : { error: c }; + }); if (commitmentsWithInvalidStatus.length > 0) { commandObj.warn( - `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${await basicCCInfoAndStatusToString( + `It's only possible to deposit collateral to the capacity commitments in the "WaitDelegation" status. The following commitments have invalid status:\n\n${basicCCInfoAndStatusToString( commitmentsWithInvalidStatus, )}`, ); @@ -66,14 +69,33 @@ export async function depositCollateral(flags: CCFlags) { const { contracts } = await getContracts(); - const commitmentsWithCollateral = await Promise.all( - commitments.map(async (commitment) => { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const commitmentsFromChain = (await multicallRead( + commitments.map(({ ccId }): MulticallReadItem => { return { - ...commitment, - collateral: await getCollateral(commitment.infoFromSubgraph.id), + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( + "getCommitment", + [ccId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getCommitment", + returnData, + ); + }, }; }), - ); + )) as Array>>; + + const commitmentsWithCollateral = commitments.map((commitment, i) => { + const ccFromChain = commitmentsFromChain[i]; + assert(ccFromChain !== undefined, "ccFromChain is undefined"); + return { + ...commitment, + collateral: ccFromChain.collateralPerUnit * ccFromChain.unitCount, + }; + }); const collateralToApproveCommitment = commitmentsWithCollateral.reduce( (acc, c) => { @@ -85,12 +107,8 @@ export async function depositCollateral(flags: CCFlags) { await sign({ title: `Deposit ${await fltFormatWithSymbol(collateralToApproveCommitment)} collateral to the following capacity commitments:\n\n${( await Promise.all( - commitments.map(async ({ infoFromSubgraph, name }) => { - return [ - name, - await peerIdHexStringToBase58String(infoFromSubgraph.peer.id), - infoFromSubgraph.id, - ] + commitments.map(async ({ ccId, peerId, name }) => { + return [name, await peerIdHexStringToBase58String(peerId), ccId] .filter(Boolean) .join("\n"); }), @@ -98,8 +116,8 @@ export async function depositCollateral(flags: CCFlags) { ).join("\n\n")}`, method: contracts.diamond.depositCollateral, args: [ - commitments.map(({ infoFromSubgraph }) => { - return infoFromSubgraph.id; + commitments.map(({ ccId }) => { + return ccId; }), { value: collateralToApproveCommitment }, ], @@ -121,7 +139,7 @@ Deposited ${color.yellow( ${( await Promise.all( commitmentsWithCollateral.map(async (c) => { - return `Capacity commitment successfully activated!\n${await stringifyBasicCommitmentInfo( + return `Capacity commitment successfully activated!\n${stringifyBasicCommitmentInfo( c, )}\nCollateral: ${color.yellow(await fltFormatWithSymbol(c.collateral))}`; }), @@ -129,12 +147,3 @@ ${( ).join("\n\n")}`, ); } - -async function getCollateral(commitmentId: string) { - const { readonlyContracts } = await getReadonlyContracts(); - - const commitment = - await readonlyContracts.diamond.getCommitment(commitmentId); - - return commitment.collateralPerUnit * commitment.unitCount; -} diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index bc8b287ac..a87e0ba55 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -189,7 +189,7 @@ export async function createAndMatchDealsForPeerIds({ const ccIds = await contracts.diamond.getComputeUnitIds(peerIdUint8Array); // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const [{ offerId }, ...computeUnitInfos] = (await multicallRead([ + const [{ offerId } = {}, ...computeUnitInfos] = (await multicallRead([ { target: contracts.deployment.diamond, callData: contracts.diamond.interface.encodeFunctionData( @@ -219,10 +219,18 @@ export async function createAndMatchDealsForPeerIds({ }; }), ])) as [ - Awaited>, - ...Awaited>[], + ( + | Awaited> + | undefined + ), + ...( + | Awaited> + | undefined + )[], ]; + assert(offerId !== undefined, "wasn't able to find offerId"); + const computeUnits = ccIds .map((unitId, i) => { return { diff --git a/packages/cli/package/src/lib/dealClient.ts b/packages/cli/package/src/lib/dealClient.ts index e639df104..770c66f75 100644 --- a/packages/cli/package/src/lib/dealClient.ts +++ b/packages/cli/package/src/lib/dealClient.ts @@ -658,7 +658,7 @@ export async function multicallRead( const results = await contracts.multicall3.aggregate3.staticCall( multicallReadItems.map(({ callData, target }) => { - return { callData, target, allowFailure: false }; + return { callData, target, allowFailure: true }; }), ); @@ -670,7 +670,7 @@ export async function multicallRead( "Unreachable. For each call we must have a result", ); - return res.success ? decode(res.returnData)[0] : null; + return res.success ? decode(res.returnData)[0] : undefined; }); } diff --git a/packages/cli/package/src/lib/gql/gql.ts b/packages/cli/package/src/lib/gql/gql.ts index 9c7d2cad9..154e87d20 100644 --- a/packages/cli/package/src/lib/gql/gql.ts +++ b/packages/cli/package/src/lib/gql/gql.ts @@ -39,17 +39,41 @@ async function getSdk() { export const DEFAULT_PAGE_LIMIT = 1000; +async function getAllPages(getter: (skip: number) => Promise) { + let result: T[] = []; + let skip = 0; + let hasMore = true; + + while (hasMore) { + const res = await getter(skip); + result = result.concat(res); + + if (res.length === DEFAULT_PAGE_LIMIT) { + skip = skip + DEFAULT_PAGE_LIMIT; + } else { + hasMore = false; + } + } + + return result; +} + export async function getDealIdsByProviderId(providerId: string) { - return (await getSdk()).Deals({ - where: { - joinedWorkers_: { - peer_: { provider_: { id: providerId.toLowerCase() } }, - }, - }, - skip: 0, - first: DEFAULT_PAGE_LIMIT, - orderBy: "createdAt", - orderDirection: "desc", + const sdk = await getSdk(); + + return getAllPages(async (skip) => { + return ( + await sdk.Deals({ + where: { + joinedWorkers_: { + // TODO: must be just provider_: { id: providerId.toLowerCase() } + peer_: { provider_: { id: providerId.toLowerCase() } }, + }, + }, + skip, + first: DEFAULT_PAGE_LIMIT, + }) + ).deals; }); } @@ -64,30 +88,9 @@ export async function getOffersForMatching( } export async function getOffers(id_in: string[]) { - return (await getSdk()).OfferDetails({ - where: { id_in }, - orderBy: "createdAt", - orderDirection: "desc", - }); + return (await getSdk()).OfferDetails({ where: { id_in, deleted: false } }); } -function getCCQueries( - queryName: T, -): { - getCCByCCId(ccIds: string[]): ReturnType; - getCCByHexPeerId(hexPeerIds: string[]): ReturnType; -} { - return { - // @ts-expect-error Don't know how to satisfy the type system here - async getCCByCCId(ccIds: string[]) { - return (await getSdk())[queryName]({ where: { id_in: ccIds } }); - }, - // @ts-expect-error Don't know how to satisfy the type system here - async getCCByHexPeerId(hexPeerIds: string[]) { - return (await getSdk())[queryName]({ where: { peer_in: hexPeerIds } }); - }, - }; +export async function ccDetails(ccIds: string[]) { + return (await getSdk()).CCDetails({ where: { id_in: ccIds } }); } - -export const ccIds = getCCQueries("CCIds"); -export const ccDetails = getCCQueries("CCDetails"); diff --git a/packages/cli/package/src/lib/gql/schema.graphql b/packages/cli/package/src/lib/gql/schema.graphql index 5af005212..65efffbac 100644 --- a/packages/cli/package/src/lib/gql/schema.graphql +++ b/packages/cli/package/src/lib/gql/schema.graphql @@ -1,16 +1,10 @@ -query Deals( - $where: Deal_filter - $skip: Int - $first: Int - $orderBy: Deal_orderBy - $orderDirection: OrderDirection -) { +query Deals($where: Deal_filter, $skip: Int, $first: Int) { deals( where: $where skip: $skip first: $first - orderBy: $orderBy - orderDirection: $orderDirection + orderBy: createdAt + orderDirection: desc ) { id } @@ -98,25 +92,8 @@ query OffersForMatching( } } -# Exclude deleted CUs. -# Exclude deleted Peers. - -query OfferDetails( - $where: Offer_filter - $orderDirection: OrderDirection - $orderBy: Offer_orderBy -) { - offers( - where: { - and: [ - $where - # Exclude deleted offers. - { deleted: false } - ] - } - orderBy: $orderBy - orderDirection: $orderDirection - ) { +query OfferDetails($where: Offer_filter) { + offers(where: $where) { id createdAt updatedAt @@ -146,31 +123,9 @@ query OfferDetails( } } -query CCIds($where: CapacityCommitment_filter) { - capacityCommitments(where: $where) { - id - peer { - id - } - } -} - query CCDetails($where: CapacityCommitment_filter) { - capacityCommitments(where: $where) { + capacityCommitments(where: $where, orderBy: createdAt, orderDirection: desc) { id - peer { - id - } - delegator { - id - } - rewardDelegatorRate - startEpoch - endEpoch - computeUnitsCount - totalFailCount - exitedUnitCount - collateralPerUnit ccRewardsWithdrawn dealStakerRewardsWithdrawn } diff --git a/packages/cli/package/test/tests/provider.test.ts b/packages/cli/package/test/tests/provider.test.ts index 927be708c..085b7ae41 100644 --- a/packages/cli/package/test/tests/provider.test.ts +++ b/packages/cli/package/test/tests/provider.test.ts @@ -28,7 +28,6 @@ import { PRIV_KEY_FLAG_NAME, PROVIDER_CONFIG_FULL_FILE_NAME, } from "../../src/lib/const.js"; -import { setTryTimeout } from "../../src/lib/helpers/setTryTimeout.js"; import { stringifyUnknown } from "../../src/lib/helpers/stringifyUnknown.js"; import { numToStr } from "../../src/lib/helpers/typesafeStringify.js"; import { fluence } from "../helpers/commonWithSetupTests.js"; @@ -195,46 +194,6 @@ describe("provider tests", () => { cwd, }); - await setTryTimeout( - "wait until all commitments get WaitDelegation status", - async () => { - const res = JSON.parse( - await fluence({ - args: ["provider", "cc-info"], - flags: { - [OFFER_FLAG_NAME]: NEW_OFFER_NAME, - json: true, - }, - cwd, - }), - ); - - if (!Array.isArray(res)) { - throw new Error("Expected an array of commitments"); - } - - const ccWithInvalidStatus = res.filter((el) => { - return ( - typeof el !== "object" || - el === null || - !("status" in el) || - el.status !== "WaitDelegation" - ); - }); - - if (ccWithInvalidStatus.length > 0) { - throw new Error( - `Some commitments are not in WaitDelegation status: ${JSON.stringify(ccWithInvalidStatus, null, 2)}`, - ); - } - }, - (e) => { - throw e; - }, - 60_000, - 5_000, - ); - await fluence({ args: ["provider", "cc-activate"], flags: { From cafff89163c7b3fd2eab83f8e135388dd6810a19 Mon Sep 17 00:00:00 2001 From: shamsartem Date: Wed, 13 Nov 2024 16:12:46 +0000 Subject: [PATCH 33/37] Apply automatic changes --- packages/cli/package/docs/commands/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli/package/docs/commands/README.md b/packages/cli/package/docs/commands/README.md index 63c631493..c172cc9b5 100644 --- a/packages/cli/package/docs/commands/README.md +++ b/packages/cli/package/docs/commands/README.md @@ -1359,10 +1359,9 @@ Exit from deal. Alias: fluence provider de ``` USAGE $ fluence provider deal-exit [--no-input] [--env ] [--priv-key ] - [--deal-ids ] [--all] + [--deal-ids ] FLAGS - --all To use all deal ids that indexer is aware of for your provider address --deal-ids= Comma-separated deal ids --env= Fluence Environment to use when running the command --no-input Don't interactively ask for any input from the user From a194ec7b89059db1006f368098c17fb99cd37349 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 13 Nov 2024 18:33:22 +0100 Subject: [PATCH 34/37] take ccId from subgraph if cc from RPC is zeroHash (was removed) --- .../src/commands/provider/deal-exit.ts | 14 ++-- .../cli/package/src/lib/chain/commitment.ts | 72 +++++++++++-------- packages/cli/package/src/lib/gql/gql.ts | 8 ++- .../cli/package/src/lib/gql/schema.graphql | 17 ++++- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/packages/cli/package/src/commands/provider/deal-exit.ts b/packages/cli/package/src/commands/provider/deal-exit.ts index 26411d7db..c33c548b4 100644 --- a/packages/cli/package/src/commands/provider/deal-exit.ts +++ b/packages/cli/package/src/commands/provider/deal-exit.ts @@ -15,8 +15,6 @@ * along with this program. If not, see . */ -import assert from "assert"; - import type { Contracts } from "@fluencelabs/deal-ts-clients"; import { BaseCommand } from "../../baseCommand.js"; @@ -45,6 +43,7 @@ export default class DealExit extends BaseCommand { static override flags = { ...CHAIN_FLAGS, ...DEAL_IDS_FLAG, + // TODO: When we have a way to get all deal ids for a provider address // all: Flags.boolean({ // default: false, // description: @@ -99,10 +98,13 @@ export default class DealExit extends BaseCommand { const deal = contracts.getDeal(id); const workers = workersFromRPC[i]; - assert( - workers !== undefined, - `Unreachable. Got nothing from RPC for deal id ${id}`, - ); + if (workers === undefined) { + commandObj.warn( + `Was not able to get workers for deal ${id} from chain. Skipping...`, + ); + + return []; + } return workers .filter((worker) => { diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 5296aec9b..942dd00f0 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -41,7 +41,7 @@ import { multicallRead, type MulticallReadItem, } from "../dealClient.js"; -import { ccDetails } from "../gql/gql.js"; +import { getCCDetails, getCCIdsByHexPeerIds } from "../gql/gql.js"; import type { CapacityCommitmentStatus, CcDetailsQuery, @@ -83,21 +83,34 @@ async function getComputePeersWithCCIds( const { contracts } = await getContracts(); - const computePeersRPCInfo = await multicallRead( - computePeersWithHexPeerIds.map(({ hexPeerId }): MulticallReadItem => { - return { - target: contracts.deployment.diamond, - callData: contracts.diamond.interface.encodeFunctionData( - "getComputePeer", - [hexPeerId], - ), - decode(returnData) { - return contracts.diamond.interface.decodeFunctionResult( + const [computePeersRPCInfo, ccIdsByHexPeerIdsRes] = await Promise.all([ + multicallRead( + computePeersWithHexPeerIds.map(({ hexPeerId }): MulticallReadItem => { + return { + target: contracts.deployment.diamond, + callData: contracts.diamond.interface.encodeFunctionData( "getComputePeer", - returnData, - ); - }, - }; + [hexPeerId], + ), + decode(returnData) { + return contracts.diamond.interface.decodeFunctionResult( + "getComputePeer", + returnData, + ); + }, + }; + }), + ), + getCCIdsByHexPeerIds( + computePeersWithHexPeerIds.map(({ hexPeerId }) => { + return hexPeerId; + }), + ), + ]); + + const ccIdsByHexPeerIds = Object.fromEntries( + ccIdsByHexPeerIdsRes.capacityCommitments.map(({ peer, id }) => { + return [peer.id, id]; }), ); @@ -105,13 +118,19 @@ async function getComputePeersWithCCIds( const [computePeersWithoutCC, computePeersWithCC] = splitErrorsAndResults( computePeersWithHexPeerIds, - ({ name, peerId }, i) => { - const { commitmentId: ccId } = + ({ name, peerId, hexPeerId }, i) => { + const { commitmentId: ccIdFromRPC } = // eslint-disable-next-line @typescript-eslint/consistent-type-assertions (computePeersRPCInfo[i] as | Awaited> | undefined) ?? {}; + // if ccIdFromRPC is undefined or ZeroHash (in case CC was removed), then we try to get last ccId from subgraph + const ccId = + ccIdFromRPC === undefined || ccIdFromRPC === ZeroHash + ? ccIdsByHexPeerIds[hexPeerId] + : ccIdFromRPC; + return ccId === undefined || ccId === ZeroHash ? { error: { name, peerId } } : { result: { name, peerId, ccId } satisfies CapacityCommitment }; @@ -319,7 +338,7 @@ export async function createCommitments(flags: { if (firstCommitmentTx === undefined) { throw new Error( - "Unreachable. First commitment tx can't be undefined cause it is checked in resolveComputePeersByNames", + "Unreachable. First commitment tx can't be undefined cause it's checked in resolveComputePeersByNames that computePeers array is not empty", ); } @@ -889,7 +908,7 @@ export async function getDetailedCommitmentsInfoGroupedByStatus( )[], ] >, - ccDetails(allCCIds), + getCCDetails(allCCIds), ]); assert(currentEpoch !== undefined, "currentEpoch is undefined"); @@ -898,14 +917,11 @@ export async function getDetailedCommitmentsInfoGroupedByStatus( assert(maxFailedRatio !== undefined, "maxFailedRatio is undefined"); assert(precision !== undefined, "precision is undefined"); - const commitmentsById = ccInfosFromSubgraph.capacityCommitments.reduce< - Record - >((acc, cc) => { - const ccIds = acc[cc.id] ?? []; - ccIds.push(cc); - acc[cc.id] = ccIds; - return acc; - }, {}); + const commitmentsById = Object.fromEntries( + ccInfosFromSubgraph.capacityCommitments.map((cc) => { + return [cc.id, cc]; + }), + ); let rewardsCounter = -contractReadsPerCC; let infoFromSubgraphCounter = -1; @@ -918,7 +934,7 @@ export async function getDetailedCommitmentsInfoGroupedByStatus( groupedCCs.ccInfos.map(async (cc) => { rewardsCounter = rewardsCounter + contractReadsPerCC; infoFromSubgraphCounter = infoFromSubgraphCounter + 1; - const infoFromSubgraph = commitmentsById[cc.ccId]?.[0]; + const infoFromSubgraph = commitmentsById[cc.ccId]; // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const unlockedRewards = rewards[rewardsCounter] as diff --git a/packages/cli/package/src/lib/gql/gql.ts b/packages/cli/package/src/lib/gql/gql.ts index 154e87d20..a6c821db3 100644 --- a/packages/cli/package/src/lib/gql/gql.ts +++ b/packages/cli/package/src/lib/gql/gql.ts @@ -91,6 +91,12 @@ export async function getOffers(id_in: string[]) { return (await getSdk()).OfferDetails({ where: { id_in, deleted: false } }); } -export async function ccDetails(ccIds: string[]) { +export async function getCCIdsByHexPeerIds(hexPeerIds: string[]) { + return (await getSdk()).CCIdsByPeerIds({ + where: { peer_: { id_in: hexPeerIds } }, + }); +} + +export async function getCCDetails(ccIds: string[]) { return (await getSdk()).CCDetails({ where: { id_in: ccIds } }); } diff --git a/packages/cli/package/src/lib/gql/schema.graphql b/packages/cli/package/src/lib/gql/schema.graphql index 65efffbac..9b5bb07ad 100644 --- a/packages/cli/package/src/lib/gql/schema.graphql +++ b/packages/cli/package/src/lib/gql/schema.graphql @@ -123,8 +123,23 @@ query OfferDetails($where: Offer_filter) { } } +query CCIdsByPeerIds($where: CapacityCommitment_filter) { + capacityCommitments( + where: $where + orderBy: createdAt + # only get the last cc for each peer + orderDirection: desc + first: 1 + ) { + id + peer { + id + } + } +} + query CCDetails($where: CapacityCommitment_filter) { - capacityCommitments(where: $where, orderBy: createdAt, orderDirection: desc) { + capacityCommitments(where: $where) { id ccRewardsWithdrawn dealStakerRewardsWithdrawn From 9be7d30dd80ccb4eccacceed586fe5f1d8aa4853 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 13 Nov 2024 19:00:35 +0100 Subject: [PATCH 35/37] don't convert already converted peerId --- .../package/src/lib/chain/depositCollateral.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/cli/package/src/lib/chain/depositCollateral.ts b/packages/cli/package/src/lib/chain/depositCollateral.ts index a3bafafab..f60912110 100644 --- a/packages/cli/package/src/lib/chain/depositCollateral.ts +++ b/packages/cli/package/src/lib/chain/depositCollateral.ts @@ -34,7 +34,6 @@ import { basicCCInfoAndStatusToString, } from "./commitment.js"; import { type CCFlags } from "./commitment.js"; -import { peerIdHexStringToBase58String } from "./conversions.js"; import { fltFormatWithSymbol } from "./currencies.js"; export async function depositCollateral(flags: CCFlags) { @@ -105,15 +104,11 @@ export async function depositCollateral(flags: CCFlags) { ); await sign({ - title: `Deposit ${await fltFormatWithSymbol(collateralToApproveCommitment)} collateral to the following capacity commitments:\n\n${( - await Promise.all( - commitments.map(async ({ ccId, peerId, name }) => { - return [name, await peerIdHexStringToBase58String(peerId), ccId] - .filter(Boolean) - .join("\n"); - }), - ) - ).join("\n\n")}`, + title: `Deposit ${await fltFormatWithSymbol(collateralToApproveCommitment)} collateral to the following capacity commitments:\n\n${commitments + .map(({ ccId, peerId, name }) => { + return [name, peerId, ccId].filter(Boolean).join("\n"); + }) + .join("\n\n")}`, method: contracts.diamond.depositCollateral, args: [ commitments.map(({ ccId }) => { From 20cb1b5349ef5db8ae81786d8d7b43c71f85f3fe Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Mon, 18 Nov 2024 15:18:29 +0100 Subject: [PATCH 36/37] rename left-ower Fluence Labs --- .github/actions/replace-version/package.json | 2 +- README.md | 2 +- packages/cli/package/nsis/custom-installer.nsi | 2 +- packages/cli/package/package.json | 2 +- packages/cli/package/src/lib/configs/user/config/config.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/actions/replace-version/package.json b/.github/actions/replace-version/package.json index 61de3b090..dfb7ba4cc 100644 --- a/.github/actions/replace-version/package.json +++ b/.github/actions/replace-version/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "ncc build index.js" }, - "author": "Fluence Labs", + "author": "Cloudless Labs", "license": "AGPL-3.0", "dependencies": { "@actions/core": "^1.10.0" diff --git a/README.md b/README.md index f5eef9f09..fad47867f 100644 --- a/README.md +++ b/README.md @@ -92,5 +92,5 @@ you read and follow some basic [rules](./CONTRIBUTING.md). ## License -All software code is copyright (c) Fluence Labs, Inc. under the +All software code is copyright (c) Fluence DAO. under the [GNU Affero General Public License version 3](./LICENSE) license. diff --git a/packages/cli/package/nsis/custom-installer.nsi b/packages/cli/package/nsis/custom-installer.nsi index 53b8aabf9..d41838e97 100644 --- a/packages/cli/package/nsis/custom-installer.nsi +++ b/packages/cli/package/nsis/custom-installer.nsi @@ -22,7 +22,7 @@ Section "@fluencelabs/cli CLI ${VERSION}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\fluence" \ "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\fluence" \ - "Publisher" "Fluence Labs" + "Publisher" "Cloudless Labs" WriteRegExpandStr ${env_hkcu} "FLUENCE_OCLIF_CLIENT_HOME" "$INSTDIR\client" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 diff --git a/packages/cli/package/package.json b/packages/cli/package/package.json index ce8dbd58a..150438259 100644 --- a/packages/cli/package/package.json +++ b/packages/cli/package/package.json @@ -10,7 +10,7 @@ "bugs": "https://github.com/fluencelabs/cli/issues", "repository": "fluencelabs/cli", "license": "AGPL-3.0", - "author": "Fluence Labs", + "author": "Cloudless Labs", "type": "module", "exports": "./lib/index.js", "types": "dist/index.d.ts", diff --git a/packages/cli/package/src/lib/configs/user/config/config.ts b/packages/cli/package/src/lib/configs/user/config/config.ts index 8a95e60f2..6da4b30b2 100644 --- a/packages/cli/package/src/lib/configs/user/config/config.ts +++ b/packages/cli/package/src/lib/configs/user/config/config.ts @@ -42,7 +42,7 @@ export async function initNewUserConfig() { isInteractive && (await confirm({ message: `Help me improve ${CLI_NAME_FULL} by sending anonymous usage data. I don't collect IDs, names, or other personal data.\n${color.gray( - "Metrics will help the developers know which features are useful so they can prioritize what to work on next. Fluence Labs hosts a Countly instance to record anonymous usage data.", + "Metrics will help the developers know which features are useful so they can prioritize what to work on next. Cloudless Labs hosts a Countly instance to record anonymous usage data.", )}\nOK?`, })) ) { From c35463221fe5b13e9ad625931c787e4198ab0430 Mon Sep 17 00:00:00 2001 From: Artsiom Shamsutdzinau Date: Wed, 27 Nov 2024 17:37:56 +0100 Subject: [PATCH 37/37] improve startDate and expirationDate display --- .../cli/package/src/lib/chain/commitment.ts | 27 ++++++++++++++----- packages/cli/package/src/lib/deal.ts | 20 +++----------- .../cli/package/src/lib/helpers/bigintOps.ts | 4 +-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/packages/cli/package/src/lib/chain/commitment.ts b/packages/cli/package/src/lib/chain/commitment.ts index 942dd00f0..b2fb3908b 100644 --- a/packages/cli/package/src/lib/chain/commitment.ts +++ b/packages/cli/package/src/lib/chain/commitment.ts @@ -46,7 +46,7 @@ import type { CapacityCommitmentStatus, CcDetailsQuery, } from "../gql/gqlGenerated.js"; -import { bigintSecondsToDate } from "../helpers/bigintOps.js"; +import { secondsToDate } from "../helpers/bigintOps.js"; import { stringifyUnknown } from "../helpers/stringifyUnknown.js"; import { bigintToStr, numToStr } from "../helpers/typesafeStringify.js"; import { splitErrorsAndResults, commaSepStrToArr } from "../helpers/utils.js"; @@ -1041,6 +1041,23 @@ async function getDetailedCommitmentInfo({ | undefined; ccFromChain: Awaited>; }) { + const { calculateTimestamp } = await import( + "@fluencelabs/deal-ts-clients/dist/dealExplorerClient/utils.js" + ); + + function getStartOrExpirationDate(epoch: bigint) { + // if startEpoch is 0, then it's not yet started - no need to show anything + return ccFromChain.startEpoch === 0n + ? "-" + : secondsToDate( + calculateTimestamp( + Number(epoch), + Number(initTimestamp), + Number(epochDuration), + ), + ).toLocaleString(); + } + const totalRewardsSplit = splitRewards( totalRewards, ccFromChain.rewardDelegatorRate, @@ -1081,12 +1098,8 @@ async function getDetailedCommitmentInfo({ startEpoch: bigintToStr(ccFromChain.startEpoch), endEpoch: bigintToStr(ccFromChain.endEpoch), currentEpoch: bigintToStr(currentEpoch), - startDate: bigintSecondsToDate( - initTimestamp + ccFromChain.startEpoch * epochDuration, - ).toLocaleString(), - expirationDate: bigintSecondsToDate( - initTimestamp + ccFromChain.endEpoch * epochDuration, - ).toLocaleString(), + startDate: getStartOrExpirationDate(ccFromChain.startEpoch), + expirationDate: getStartOrExpirationDate(ccFromChain.endEpoch), totalCU: bigintToStr(ccFromChain.unitCount), missedProofs: bigintToStr(ccFromChain.totalFailCount), threshold: bigintToStr(maxFailedRatio * ccFromChain.unitCount), diff --git a/packages/cli/package/src/lib/deal.ts b/packages/cli/package/src/lib/deal.ts index a87e0ba55..98584bdb2 100644 --- a/packages/cli/package/src/lib/deal.ts +++ b/packages/cli/package/src/lib/deal.ts @@ -474,6 +474,10 @@ async function getMatchedOffersByDealId(dealAddress: string) { throw new Error(`Deal already has target number of workers matched.`); } + const { calculateEpoch } = await import( + "@fluencelabs/deal-ts-clients/dist/dealExplorerClient/utils.js" + ); + const currentEpoch = calculateEpoch( _meta.block.timestamp, initTimestamp, @@ -632,22 +636,6 @@ async function getMatchedOffersByDealId(dealAddress: string) { return matchedOffers; } -function calculateEpoch( - timestamp: number, - epochControllerStorageInitTimestamp: number, - epochControllerStorageEpochDuration: number, -) { - dbg( - `timestamp: ${numToStr(timestamp)} epochControllerStorageInitTimestamp: ${numToStr(epochControllerStorageInitTimestamp)} epochControllerStorageEpochDuration: ${numToStr(epochControllerStorageEpochDuration)}`, - ); - - return Math.floor( - 1 + - (timestamp - epochControllerStorageInitTimestamp) / - epochControllerStorageEpochDuration, - ); -} - function prepareDealProviderAccessLists( providersAccessType: number, providersAccessList: diff --git a/packages/cli/package/src/lib/helpers/bigintOps.ts b/packages/cli/package/src/lib/helpers/bigintOps.ts index 80b4afd4b..9b10b75ff 100644 --- a/packages/cli/package/src/lib/helpers/bigintOps.ts +++ b/packages/cli/package/src/lib/helpers/bigintOps.ts @@ -15,6 +15,6 @@ * along with this program. If not, see . */ -export function bigintSecondsToDate(bigSec: bigint): Date { - return new Date(Number(bigSec * 1000n)); +export function secondsToDate(bigSec: bigint | number): Date { + return new Date(Number(bigSec) * 1000); }