@xyo-network/xl1-cli-lib 1.20.5 → 1.20.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/node/commands/api/apiCommand.d.ts +5 -0
  2. package/dist/node/commands/api/apiCommand.d.ts.map +1 -0
  3. package/dist/node/commands/api/index.d.ts +2 -0
  4. package/dist/node/commands/api/index.d.ts.map +1 -0
  5. package/dist/node/commands/bridge/bridgeCommand.d.ts +5 -0
  6. package/dist/node/commands/bridge/bridgeCommand.d.ts.map +1 -0
  7. package/dist/node/commands/bridge/index.d.ts +1 -0
  8. package/dist/node/commands/bridge/index.d.ts.map +1 -1
  9. package/dist/node/commands/index.d.ts +6 -0
  10. package/dist/node/commands/index.d.ts.map +1 -1
  11. package/dist/node/commands/mempool/index.d.ts +2 -0
  12. package/dist/node/commands/mempool/index.d.ts.map +1 -0
  13. package/dist/node/commands/mempool/mempoolCommand.d.ts +5 -0
  14. package/dist/node/commands/mempool/mempoolCommand.d.ts.map +1 -0
  15. package/dist/node/commands/producer/index.d.ts +2 -0
  16. package/dist/node/commands/producer/index.d.ts.map +1 -0
  17. package/dist/node/commands/producer/producerCommand.d.ts +5 -0
  18. package/dist/node/commands/producer/producerCommand.d.ts.map +1 -0
  19. package/dist/node/commands/rewardRedemption/index.d.ts +1 -0
  20. package/dist/node/commands/rewardRedemption/index.d.ts.map +1 -1
  21. package/dist/node/commands/rewardRedemption/rewardRedemptionCommand.d.ts +5 -0
  22. package/dist/node/commands/rewardRedemption/rewardRedemptionCommand.d.ts.map +1 -0
  23. package/dist/node/commands/start/index.d.ts +2 -0
  24. package/dist/node/commands/start/index.d.ts.map +1 -0
  25. package/dist/node/commands/start/startCommand.d.ts +5 -0
  26. package/dist/node/commands/start/startCommand.d.ts.map +1 -0
  27. package/dist/node/commands/types.d.ts +8 -0
  28. package/dist/node/commands/types.d.ts.map +1 -0
  29. package/dist/node/commands/withDeprecationWarning.d.ts +3 -0
  30. package/dist/node/commands/withDeprecationWarning.d.ts.map +1 -0
  31. package/dist/node/configMiddleware.d.ts +3 -0
  32. package/dist/node/configMiddleware.d.ts.map +1 -0
  33. package/dist/node/index.d.ts +1 -0
  34. package/dist/node/index.d.ts.map +1 -1
  35. package/dist/node/index.mjs +351 -176
  36. package/dist/node/index.mjs.map +1 -1
  37. package/dist/node/runCLI.d.ts.map +1 -1
  38. package/dist/node/xl1.mjs +350 -176
  39. package/dist/node/xl1.mjs.map +1 -1
  40. package/package.json +16 -27
  41. package/src/commands/api/apiCommand.ts +39 -0
  42. package/src/commands/api/index.ts +1 -0
  43. package/src/commands/bridge/bridgeCommand.ts +19 -0
  44. package/src/commands/bridge/index.ts +1 -0
  45. package/src/commands/index.ts +6 -0
  46. package/src/commands/mempool/index.ts +1 -0
  47. package/src/commands/mempool/mempoolCommand.ts +19 -0
  48. package/src/commands/producer/index.ts +1 -0
  49. package/src/commands/producer/producerCommand.ts +19 -0
  50. package/src/commands/rewardRedemption/index.ts +1 -0
  51. package/src/commands/rewardRedemption/rewardRedemptionCommand.ts +19 -0
  52. package/src/commands/start/index.ts +1 -0
  53. package/src/commands/start/startCommand.ts +127 -0
  54. package/src/commands/types.ts +9 -0
  55. package/src/commands/withDeprecationWarning.ts +17 -0
  56. package/src/configMiddleware.ts +55 -0
  57. package/src/index.ts +1 -0
  58. package/src/runCLI.ts +31 -142
@@ -0,0 +1,55 @@
1
+ import { createDeepMerge } from '@xylabs/sdk-js'
2
+ import { tryParseConfig } from '@xyo-network/chain-orchestration'
3
+ import type { Config } from '@xyo-network/xl1-sdk'
4
+ import {
5
+ ConfigZod, isZodError, resolveConfig,
6
+ } from '@xyo-network/xl1-sdk'
7
+
8
+ const deepMerge = createDeepMerge({ arrayStrategy: 'concat' })
9
+
10
+ export async function configMiddleware(argv: Record<string, unknown>, setConfiguration: (config: Config) => void): Promise<void> {
11
+ try {
12
+ // Parse the various config sources
13
+ const configPath = argv.config as string | undefined
14
+ const parsedConfigFile = await tryParseConfig({ configPath }) // Config file
15
+ const parsedConfigArgs = ConfigZod.safeParse(argv).data ?? {} // Command-line arguments & ENV VARs
16
+ const parseResult = ConfigZod.safeParse(deepMerge(parsedConfigFile, parsedConfigArgs))
17
+ if (!parseResult.success) {
18
+ throw parseResult.error
19
+ }
20
+ // Deep merge with precedence
21
+ // TODO: Would like precedence to be defaults < file < ENV < CLI Args
22
+ // but there is currently no way to determine which are defaults vs
23
+ // user-supplied CLI Args since we set the CLI args to the defaults
24
+ // and receive a flattened object. We might need to manually invoke
25
+ // the parser without the defaults to achieve this.
26
+ // const mergedConfig = deepMerge(parsedConfigArgs, parsedConfigFile)
27
+ const mergedConfig = parseResult.data
28
+ const validatedMergedConfigResult = ConfigZod.safeParse(mergedConfig)
29
+ if (!validatedMergedConfigResult.success) {
30
+ throw validatedMergedConfigResult.error
31
+ }
32
+ const resolvedConfig = resolveConfig(validatedMergedConfigResult.data)
33
+ // Validate the merged configuration
34
+ const validatedConfigResult = ConfigZod.safeParse(resolvedConfig)
35
+ if (!validatedConfigResult.success) {
36
+ throw validatedConfigResult.error
37
+ }
38
+ setConfiguration(validatedConfigResult.data)
39
+
40
+ // Check if user wants to dump config and exit
41
+ if (argv['dump-config']) {
42
+ console.log(JSON.stringify(validatedConfigResult.data, null, 2))
43
+ // eslint-disable-next-line unicorn/no-process-exit
44
+ process.exit(0)
45
+ }
46
+ } catch (err) {
47
+ if (isZodError(err)) {
48
+ console.error(`Zod error: ${err.message}`)
49
+ } else {
50
+ console.error(`Error parsing configuration: ${err}`)
51
+ }
52
+ console.error(`Stack: ${err instanceof Error ? err.stack : 'N/A'}`)
53
+ throw new Error('Invalid configuration')
54
+ }
55
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './configMiddleware.ts'
1
2
  export * from './initLogger.ts'
2
3
  export * from './runCLI.ts'
3
4
  export * from './start.ts'
package/src/runCLI.ts CHANGED
@@ -1,28 +1,26 @@
1
- import { createDeepMerge, isDefined } from '@xylabs/sdk-js'
2
- import { getApiActor, runApi } from '@xyo-network/chain-api'
3
- import { getMempoolActor, runMempool } from '@xyo-network/chain-mempool'
1
+ import { isDefined } from '@xylabs/sdk-js'
4
2
  import {
5
- ApiConfigZod, BridgeConfigZod, contextFromConfigWithoutLocator, locatorsFromConfig, MempoolConfigZod, Orchestrator, ProducerConfigZod,
6
- RewardRedemptionConfigZod, tryParseConfig,
7
- ValidatorConfigZod,
3
+ contextFromConfigWithoutLocator, locatorsFromConfig, Orchestrator,
8
4
  } from '@xyo-network/chain-orchestration'
9
- import { runProducer } from '@xyo-network/chain-producer'
10
5
  import type { ActorConfig, Config } from '@xyo-network/xl1-sdk'
11
- import {
12
- ActorConfigZod, ConfigZod, isZodError,
13
- resolveConfig,
14
- } from '@xyo-network/xl1-sdk'
6
+ import { ActorConfigZod, ConfigZod } from '@xyo-network/xl1-sdk'
15
7
  import type { Argv } from 'yargs'
16
8
  import yargs from 'yargs'
17
9
  import { hideBin } from 'yargs/helpers'
18
10
 
19
11
  import {
20
- getValidatorActor, runBridge, runRewardRedemptionApi,
12
+ apiCommand,
13
+ bridgeCommand,
14
+ mempoolCommand,
15
+ producerCommand,
16
+ rewardRedemptionCommand,
17
+ startCommand,
18
+ withDeprecationWarning,
21
19
  } from './commands/index.ts'
20
+ import { configMiddleware } from './configMiddleware.ts'
22
21
  import { XL1LogoColorizedAscii } from './images.ts'
23
22
  import { initLogger } from './initLogger.ts'
24
23
  import { optionsFromGlobalZodRegistry } from './optionsFromGlobalZodRegistry.ts'
25
- import { waitForHostPort } from './waitForHostPort.ts'
26
24
 
27
25
  /** Version string injected by Rollup at build time. */
28
26
  declare const __VERSION__: string
@@ -36,23 +34,23 @@ let configuration: Config
36
34
 
37
35
  const version = isDefined(__VERSION__) ? __VERSION__ : 'unknown'
38
36
 
39
- const deepMerge = createDeepMerge({ arrayStrategy: 'concat' })
37
+ function getConfiguration(): Config {
38
+ return configuration
39
+ }
40
40
 
41
41
  async function getLocatorsFromConfig(actors: string[], configuration: Config) {
42
42
  const actorConfigs: ActorConfig[] = []
43
43
  for (const actorName of actors) {
44
- const rawConfig = configuration.actors.find(actor => actor.name === actorName) ?? { name: actorName }
45
- const actorConfig = ActorConfigZod.loose().parse(rawConfig)
46
- actorConfigs.push(actorConfig)
44
+ const existingConfig = configuration.actors.find(actor => actor.name === actorName)
45
+ if (existingConfig) {
46
+ actorConfigs.push(existingConfig)
47
+ } else {
48
+ const actorConfig = ActorConfigZod.loose().parse({ name: actorName })
49
+ actorConfigs.push(actorConfig)
50
+ }
47
51
  }
48
52
 
49
- // merge the configs, but merge the actors list, don't concat it
50
- const config = ConfigZod.parse(deepMerge(configuration, { actors: actorConfigs }))
51
- const actorList = [...new Set([...config.actors.map(actor => actor.name), ...actorConfigs.map(actor => actor.name)])]
52
- config.actors = actorList.map(actorName => ActorConfigZod.loose().parse(deepMerge(
53
- (config.actors.find(actor => actor.name === actorName) ?? {}),
54
- (actorConfigs.find(actor => actor.name === actorName) ?? {}),
55
- )))
53
+ const config = ConfigZod.parse({ ...configuration, actors: actorConfigs })
56
54
 
57
55
  const logger = initLogger(configuration)
58
56
  const orchestrator = await Orchestrator.create({ logger })
@@ -95,127 +93,18 @@ $0 <command> [options]`)
95
93
  .env('XL1')
96
94
  .scriptName('xl1')
97
95
  .middleware(async (argv) => {
98
- try {
99
- // Parse the various config sources
100
- const configPath = argv.config as string | undefined
101
- const parsedConfigFile = await tryParseConfig({ configPath }) // Config file
102
- const parsedConfigArgs = ConfigZod.safeParse(argv).data ?? {} // Command-line arguments & ENV VARs
103
- const parseResult = ConfigZod.safeParse(deepMerge(parsedConfigFile, parsedConfigArgs))
104
- if (!parseResult.success) {
105
- throw parseResult.error
106
- }
107
- // Deep merge with precedence
108
- // TODO: Would like precedence to be defaults < file < ENV < CLI Args
109
- // but there is currently no way to determine which are defaults vs
110
- // user-supplied CLI Args since we set the CLI args to the defaults
111
- // and receive a flattened object. We might need to manually invoke
112
- // the parser without the defaults to achieve this.
113
- // const mergedConfig = deepMerge(parsedConfigArgs, parsedConfigFile)
114
- const mergedConfig = parseResult.data
115
- const validatedMergedConfigResult = ConfigZod.safeParse(mergedConfig)
116
- if (!validatedMergedConfigResult.success) {
117
- throw validatedMergedConfigResult.error
118
- }
119
- const resolvedConfig = resolveConfig(validatedMergedConfigResult.data)
120
- // Validate the merged configuration
121
- const validatedConfigResult = ConfigZod.safeParse(resolvedConfig)
122
- if (!validatedConfigResult.success) {
123
- throw validatedConfigResult.error
124
- }
125
- configuration = validatedConfigResult.data
126
-
127
- // Check if user wants to dump config and exit
128
- if (argv['dump-config']) {
129
- console.log(JSON.stringify(configuration, null, 2))
130
- // eslint-disable-next-line unicorn/no-process-exit
131
- process.exit(0)
132
- }
133
- } catch (err) {
134
- if (isZodError(err)) {
135
- console.error(`Zod error: ${err.message}`)
136
- } else {
137
- console.error(`Error parsing configuration: ${err}`)
138
- }
139
- console.error(`Stack: ${err instanceof Error ? err.stack : 'N/A'}`)
140
- throw new Error('Invalid configuration')
141
- }
96
+ await configMiddleware(argv, (config) => {
97
+ configuration = config
98
+ })
142
99
  })
143
100
  .options(optionsFromGlobalZodRegistry())
144
- // .commandDir('./command/commands', opts) // Not yet supported for ESM
145
101
  .wrap(y.terminalWidth())
146
- .command('api', 'Run a XL1 API Node', (yargs) => {
147
- return yargs
148
- .command('$0', 'Run a XL1 API Node', () => {}, async () => {
149
- const { locators, orchestrator } = await getLocatorsFromConfig(['api', 'mempool', 'validator'], configuration)
150
- const actors = await Promise.all([getApiActor(
151
- ApiConfigZod.parse(locators['api'].context.config),
152
- locators['api'],
153
- ), getMempoolActor(
154
- MempoolConfigZod.parse(locators['mempool'].context.config),
155
- locators['mempool'],
156
- ), getValidatorActor(
157
- ValidatorConfigZod.parse(locators['validator'].context.config),
158
- locators['validator'],
159
- )])
160
-
161
- for (const actor of actors) {
162
- await orchestrator.registerActor(actor)
163
- }
164
-
165
- await orchestrator.start()
166
- })
167
- })
168
- .command('bridge', 'Run a XL1 Bridge Node', (yargs) => {
169
- return yargs
170
- .command('$0', 'Run a XL1 Bridge Node', () => {}, async () => {
171
- const { locators, orchestrator } = await getLocatorsFromConfig(['bridge'], configuration)
172
- await runBridge(BridgeConfigZod.parse(locators['bridge'].context.config), orchestrator, locators['bridge'])
173
- })
174
- })
175
- .command('mempool', 'Run a XL1 Mempool Node', (yargs) => {
176
- return yargs
177
- .command('$0', 'Run a XL1 Mempool Node', () => {}, async () => {
178
- const { locators, orchestrator } = await getLocatorsFromConfig(['mempool'], configuration)
179
- await runMempool(MempoolConfigZod.parse(locators['mempool'].context.config), orchestrator, locators['mempool'])
180
- })
181
- })
182
- .command('producer', 'Run a XL1 Producer Node', (yargs) => {
183
- return yargs
184
- .command('$0', 'Run a XL1 Producer Node', () => {}, async () => {
185
- const { locators, orchestrator } = await getLocatorsFromConfig(['producer'], configuration)
186
- await runProducer(ProducerConfigZod.parse(locators['producer'].context.config), orchestrator, locators['producer'])
187
- })
188
- })
189
- .command('reward-redemption-api', 'Run a XL1 Rewards Redemption API Node', (yargs) => {
190
- return yargs
191
- .command('$0', 'Run a XL1 Rewards Redemption API Node', () => {}, async () => {
192
- const { locators, orchestrator } = await getLocatorsFromConfig(['rewardRedemption'], configuration)
193
- await runRewardRedemptionApi(RewardRedemptionConfigZod.parse(locators['rewardRedemption'].context.config), orchestrator, locators['rewardRedemption'])
194
- })
195
- })
196
- .command('$0', 'Run a full XL1 Node', () => {}, async () => {
197
- const actors = ['producer', 'api']
198
- const mempoolEnabled = configuration.actors.find(actor => actor.name === 'mempool')?.enabled
199
- if (mempoolEnabled) {
200
- actors.push('mempool')
201
- }
202
- const { locators, orchestrator } = await getLocatorsFromConfig(['api', 'producer'], configuration)
203
- if (mempoolEnabled) {
204
- const mempoolConfig = MempoolConfigZod.parse(locators['mempool'].context.config)
205
- // Start Mempool but do not block
206
- await runMempool(mempoolConfig, orchestrator, locators['mempool'])
207
- // Wait for Mempool to be ready
208
- await waitForHostPort(mempoolConfig.host, mempoolConfig.port)
209
- }
210
- // Start API but do not block
211
- const apiConfig = ApiConfigZod.parse(locators['api'].context.config)
212
- await runApi(apiConfig, orchestrator, locators['api'])
213
- // Wait for API to be ready
214
- await waitForHostPort(apiConfig.host, apiConfig.port)
215
- // Start Producer and block on it
216
- const producerConfig = ProducerConfigZod.parse(locators['producer'].context.config)
217
- await runProducer(producerConfig, orchestrator, locators['producer'])
218
- })
102
+ .command(withDeprecationWarning(apiCommand(getConfiguration, getLocatorsFromConfig)))
103
+ .command(withDeprecationWarning(bridgeCommand(getConfiguration, getLocatorsFromConfig)))
104
+ .command(withDeprecationWarning(mempoolCommand(getConfiguration, getLocatorsFromConfig)))
105
+ .command(withDeprecationWarning(producerCommand(getConfiguration, getLocatorsFromConfig)))
106
+ .command(withDeprecationWarning(rewardRedemptionCommand(getConfiguration, getLocatorsFromConfig)))
107
+ .command(startCommand(getConfiguration, getLocatorsFromConfig))
219
108
  .options({
220
109
  'config': {
221
110
  type: 'string',