@xyo-network/xl1-cli-lib 1.20.4 → 1.20.8

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 +354 -171
  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 +353 -171
  39. package/dist/node/xl1.mjs.map +1 -1
  40. package/package.json +15 -26
  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 +34 -137
@@ -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,16 +34,24 @@ 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
- const getLocatorsFromConfig = async (actors: string[], configuration: Config) => {
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
- const config = ConfigZod.parse(deepMerge(configuration, { actors: actorConfigs }))
52
+
53
+ const config = ConfigZod.parse({ ...configuration, actors: actorConfigs })
54
+
49
55
  const logger = initLogger(configuration)
50
56
  const orchestrator = await Orchestrator.create({ logger })
51
57
  const context = await contextFromConfigWithoutLocator(config, logger, 'xl1-cli', version)
@@ -87,127 +93,18 @@ $0 <command> [options]`)
87
93
  .env('XL1')
88
94
  .scriptName('xl1')
89
95
  .middleware(async (argv) => {
90
- try {
91
- // Parse the various config sources
92
- const configPath = argv.config as string | undefined
93
- const parsedConfigFile = await tryParseConfig({ configPath }) // Config file
94
- const parsedConfigArgs = ConfigZod.safeParse(argv).data ?? {} // Command-line arguments & ENV VARs
95
- const parseResult = ConfigZod.safeParse(deepMerge(parsedConfigFile, parsedConfigArgs))
96
- if (!parseResult.success) {
97
- throw parseResult.error
98
- }
99
- // Deep merge with precedence
100
- // TODO: Would like precedence to be defaults < file < ENV < CLI Args
101
- // but there is currently no way to determine which are defaults vs
102
- // user-supplied CLI Args since we set the CLI args to the defaults
103
- // and receive a flattened object. We might need to manually invoke
104
- // the parser without the defaults to achieve this.
105
- // const mergedConfig = deepMerge(parsedConfigArgs, parsedConfigFile)
106
- const mergedConfig = parseResult.data
107
- const validatedMergedConfigResult = ConfigZod.safeParse(mergedConfig)
108
- if (!validatedMergedConfigResult.success) {
109
- throw validatedMergedConfigResult.error
110
- }
111
- const resolvedConfig = resolveConfig(validatedMergedConfigResult.data)
112
- // Validate the merged configuration
113
- const validatedConfigResult = ConfigZod.safeParse(resolvedConfig)
114
- if (!validatedConfigResult.success) {
115
- throw validatedConfigResult.error
116
- }
117
- configuration = validatedConfigResult.data
118
-
119
- // Check if user wants to dump config and exit
120
- if (argv['dump-config']) {
121
- console.log(JSON.stringify(configuration, null, 2))
122
- // eslint-disable-next-line unicorn/no-process-exit
123
- process.exit(0)
124
- }
125
- } catch (err) {
126
- if (isZodError(err)) {
127
- console.error(`Zod error: ${err.message}`)
128
- } else {
129
- console.error(`Error parsing configuration: ${err}`)
130
- }
131
- console.error(`Stack: ${err instanceof Error ? err.stack : 'N/A'}`)
132
- throw new Error('Invalid configuration')
133
- }
96
+ await configMiddleware(argv, (config) => {
97
+ configuration = config
98
+ })
134
99
  })
135
100
  .options(optionsFromGlobalZodRegistry())
136
- // .commandDir('./command/commands', opts) // Not yet supported for ESM
137
101
  .wrap(y.terminalWidth())
138
- .command('api', 'Run a XL1 API Node', (yargs) => {
139
- return yargs
140
- .command('$0', 'Run a XL1 API Node', () => {}, async () => {
141
- const { locators, orchestrator } = await getLocatorsFromConfig(['api', 'mempool', 'validator'], configuration)
142
- const actors = await Promise.all([getApiActor(
143
- ApiConfigZod.parse(locators['api'].context.config),
144
- locators['api'],
145
- ), getMempoolActor(
146
- MempoolConfigZod.parse(locators['mempool'].context.config),
147
- locators['mempool'],
148
- ), getValidatorActor(
149
- ValidatorConfigZod.parse(locators['validator'].context.config),
150
- locators['validator'],
151
- )])
152
-
153
- for (const actor of actors) {
154
- await orchestrator.registerActor(actor)
155
- }
156
-
157
- await orchestrator.start()
158
- })
159
- })
160
- .command('bridge', 'Run a XL1 Bridge Node', (yargs) => {
161
- return yargs
162
- .command('$0', 'Run a XL1 Bridge Node', () => {}, async () => {
163
- const { locators, orchestrator } = await getLocatorsFromConfig(['bridge'], configuration)
164
- await runBridge(BridgeConfigZod.parse(locators['bridge'].context.config), orchestrator, locators['bridge'])
165
- })
166
- })
167
- .command('mempool', 'Run a XL1 Mempool Node', (yargs) => {
168
- return yargs
169
- .command('$0', 'Run a XL1 Mempool Node', () => {}, async () => {
170
- const { locators, orchestrator } = await getLocatorsFromConfig(['mempool'], configuration)
171
- await runMempool(MempoolConfigZod.parse(locators['mempool'].context.config), orchestrator, locators['mempool'])
172
- })
173
- })
174
- .command('producer', 'Run a XL1 Producer Node', (yargs) => {
175
- return yargs
176
- .command('$0', 'Run a XL1 Producer Node', () => {}, async () => {
177
- const { locators, orchestrator } = await getLocatorsFromConfig(['producer'], configuration)
178
- await runProducer(ProducerConfigZod.parse(locators['producer'].context.config), orchestrator, locators['producer'])
179
- })
180
- })
181
- .command('reward-redemption-api', 'Run a XL1 Rewards Redemption API Node', (yargs) => {
182
- return yargs
183
- .command('$0', 'Run a XL1 Rewards Redemption API Node', () => {}, async () => {
184
- const { locators, orchestrator } = await getLocatorsFromConfig(['rewardRedemption'], configuration)
185
- await runRewardRedemptionApi(RewardRedemptionConfigZod.parse(locators['rewardRedemption'].context.config), orchestrator, locators['rewardRedemption'])
186
- })
187
- })
188
- .command('$0', 'Run a full XL1 Node', () => {}, async () => {
189
- const actors = ['producer', 'api']
190
- const mempoolEnabled = configuration.actors.find(actor => actor.name === 'mempool')?.enabled
191
- if (mempoolEnabled) {
192
- actors.push('mempool')
193
- }
194
- const { locators, orchestrator } = await getLocatorsFromConfig(['api', 'producer'], configuration)
195
- if (mempoolEnabled) {
196
- const mempoolConfig = MempoolConfigZod.parse(locators['mempool'].context.config)
197
- // Start Mempool but do not block
198
- await runMempool(mempoolConfig, orchestrator, locators['mempool'])
199
- // Wait for Mempool to be ready
200
- await waitForHostPort(mempoolConfig.host, mempoolConfig.port)
201
- }
202
- // Start API but do not block
203
- const apiConfig = ApiConfigZod.parse(locators['api'].context.config)
204
- await runApi(apiConfig, orchestrator, locators['api'])
205
- // Wait for API to be ready
206
- await waitForHostPort(apiConfig.host, apiConfig.port)
207
- // Start Producer and block on it
208
- const producerConfig = ProducerConfigZod.parse(locators['producer'].context.config)
209
- await runProducer(producerConfig, orchestrator, locators['producer'])
210
- })
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))
211
108
  .options({
212
109
  'config': {
213
110
  type: 'string',