@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.
- package/dist/node/commands/api/apiCommand.d.ts +5 -0
- package/dist/node/commands/api/apiCommand.d.ts.map +1 -0
- package/dist/node/commands/api/index.d.ts +2 -0
- package/dist/node/commands/api/index.d.ts.map +1 -0
- package/dist/node/commands/bridge/bridgeCommand.d.ts +5 -0
- package/dist/node/commands/bridge/bridgeCommand.d.ts.map +1 -0
- package/dist/node/commands/bridge/index.d.ts +1 -0
- package/dist/node/commands/bridge/index.d.ts.map +1 -1
- package/dist/node/commands/index.d.ts +6 -0
- package/dist/node/commands/index.d.ts.map +1 -1
- package/dist/node/commands/mempool/index.d.ts +2 -0
- package/dist/node/commands/mempool/index.d.ts.map +1 -0
- package/dist/node/commands/mempool/mempoolCommand.d.ts +5 -0
- package/dist/node/commands/mempool/mempoolCommand.d.ts.map +1 -0
- package/dist/node/commands/producer/index.d.ts +2 -0
- package/dist/node/commands/producer/index.d.ts.map +1 -0
- package/dist/node/commands/producer/producerCommand.d.ts +5 -0
- package/dist/node/commands/producer/producerCommand.d.ts.map +1 -0
- package/dist/node/commands/rewardRedemption/index.d.ts +1 -0
- package/dist/node/commands/rewardRedemption/index.d.ts.map +1 -1
- package/dist/node/commands/rewardRedemption/rewardRedemptionCommand.d.ts +5 -0
- package/dist/node/commands/rewardRedemption/rewardRedemptionCommand.d.ts.map +1 -0
- package/dist/node/commands/start/index.d.ts +2 -0
- package/dist/node/commands/start/index.d.ts.map +1 -0
- package/dist/node/commands/start/startCommand.d.ts +5 -0
- package/dist/node/commands/start/startCommand.d.ts.map +1 -0
- package/dist/node/commands/types.d.ts +8 -0
- package/dist/node/commands/types.d.ts.map +1 -0
- package/dist/node/commands/withDeprecationWarning.d.ts +3 -0
- package/dist/node/commands/withDeprecationWarning.d.ts.map +1 -0
- package/dist/node/configMiddleware.d.ts +3 -0
- package/dist/node/configMiddleware.d.ts.map +1 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.mjs +354 -171
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/runCLI.d.ts.map +1 -1
- package/dist/node/xl1.mjs +353 -171
- package/dist/node/xl1.mjs.map +1 -1
- package/package.json +15 -26
- package/src/commands/api/apiCommand.ts +39 -0
- package/src/commands/api/index.ts +1 -0
- package/src/commands/bridge/bridgeCommand.ts +19 -0
- package/src/commands/bridge/index.ts +1 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/mempool/index.ts +1 -0
- package/src/commands/mempool/mempoolCommand.ts +19 -0
- package/src/commands/producer/index.ts +1 -0
- package/src/commands/producer/producerCommand.ts +19 -0
- package/src/commands/rewardRedemption/index.ts +1 -0
- package/src/commands/rewardRedemption/rewardRedemptionCommand.ts +19 -0
- package/src/commands/start/index.ts +1 -0
- package/src/commands/start/startCommand.ts +127 -0
- package/src/commands/types.ts +9 -0
- package/src/commands/withDeprecationWarning.ts +17 -0
- package/src/configMiddleware.ts +55 -0
- package/src/index.ts +1 -0
- 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
package/src/runCLI.ts
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
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
|
+
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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',
|