@sentio/cli 3.5.1-rc.2 → 3.6.0-rc.1
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/lib/index.js +38419 -11030
- package/package.json +1 -1
- package/src/commands/processor.ts +1 -1
- package/src/commands/stop-processor.ts +63 -0
- package/src/commands/upload.ts +196 -3
- package/src/index.ts +2 -0
- package/src/network.ts +407 -0
- package/src/uploader.ts +29 -22
package/package.json
CHANGED
|
@@ -337,7 +337,7 @@ async function runProcessorResume(processorId: string | undefined, options: Proc
|
|
|
337
337
|
})
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
async function runProcessorStop(processorId: string | undefined, options: ProcessorOptions & { yes?: boolean }) {
|
|
340
|
+
export async function runProcessorStop(processorId: string | undefined, options: ProcessorOptions & { yes?: boolean }) {
|
|
341
341
|
const resolvedProcessorId = await resolveAndConfirmProcessor('stop', processorId, options)
|
|
342
342
|
if (!resolvedProcessorId) return
|
|
343
343
|
const context = createApiContext(options)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Command } from '@commander-js/extra-typings'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { handleCommandError } from '../api.js'
|
|
4
|
+
import { confirm } from './upload.js'
|
|
5
|
+
import { runProcessorStop } from './processor.js'
|
|
6
|
+
import {
|
|
7
|
+
getSentioNetworkConfig,
|
|
8
|
+
resolveNetworkAddresses,
|
|
9
|
+
getWalletFromPrivateKey,
|
|
10
|
+
requirePrivateKey,
|
|
11
|
+
stopProcessorOnChain
|
|
12
|
+
} from '../network.js'
|
|
13
|
+
|
|
14
|
+
export function createStopProcessorCommand() {
|
|
15
|
+
return new Command('stop')
|
|
16
|
+
.description('Stop a processor. Uses Sentio Network contract when --sentio-network is specified.')
|
|
17
|
+
.argument('<processorId>', 'ID of the processor to stop')
|
|
18
|
+
.option('--sentio-network <network>', 'Stop via Sentio Network contract (only "testnet" supported)')
|
|
19
|
+
.option('--host <host>', 'Override Sentio host')
|
|
20
|
+
.option('--api-key <key>', 'Use an explicit API key instead of saved credentials')
|
|
21
|
+
.option('--token <token>', 'Use an explicit bearer token instead of saved credentials')
|
|
22
|
+
.option('--project <owner/slug>', 'Sentio project in <owner>/<slug> format')
|
|
23
|
+
.option('--owner <owner>', 'Sentio project owner')
|
|
24
|
+
.option('--name <name>', 'Sentio project name')
|
|
25
|
+
.option('-y, --yes', 'Bypass confirmation')
|
|
26
|
+
.showHelpAfterError()
|
|
27
|
+
.action(async (processorId, options) => {
|
|
28
|
+
try {
|
|
29
|
+
if (options.sentioNetwork) {
|
|
30
|
+
await runStopProcessorOnChain(processorId, options)
|
|
31
|
+
} else {
|
|
32
|
+
await runProcessorStop(processorId, options)
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
handleCommandError(error)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function runStopProcessorOnChain(processorId: string, options: { sentioNetwork?: string; yes?: boolean }) {
|
|
41
|
+
const network = options.sentioNetwork!
|
|
42
|
+
const networkConfig = getSentioNetworkConfig(network)
|
|
43
|
+
|
|
44
|
+
const privateKey = requirePrivateKey()
|
|
45
|
+
const wallet = getWalletFromPrivateKey(privateKey)
|
|
46
|
+
|
|
47
|
+
console.log(chalk.blue(`Wallet address: ${wallet.address}`))
|
|
48
|
+
console.log(chalk.blue('Resolving contract addresses from AddressBook...'))
|
|
49
|
+
const addresses = await resolveNetworkAddresses(networkConfig)
|
|
50
|
+
|
|
51
|
+
if (!options.yes) {
|
|
52
|
+
const confirmed = await confirm(`Stop processor "${processorId}" on Sentio Network ${network}?`)
|
|
53
|
+
if (!confirmed) {
|
|
54
|
+
console.log('Stop cancelled.')
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await stopProcessorOnChain(networkConfig, addresses, wallet, processorId)
|
|
60
|
+
|
|
61
|
+
console.log()
|
|
62
|
+
console.log(chalk.green(`Processor "${processorId}" stopped on Sentio Network ${network}.`))
|
|
63
|
+
}
|
package/src/commands/upload.ts
CHANGED
|
@@ -13,7 +13,22 @@ import readline from 'readline'
|
|
|
13
13
|
import JSZip from 'jszip'
|
|
14
14
|
import { UserInfo } from '../../../protos/lib/service/common/protos/common.js'
|
|
15
15
|
import { CommandOptionsType } from './types.js'
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
getSentioNetworkConfig,
|
|
18
|
+
resolveNetworkAddresses,
|
|
19
|
+
getWalletFromPrivateKey,
|
|
20
|
+
requirePrivateKey,
|
|
21
|
+
checkSTBalance,
|
|
22
|
+
checkBillingBalance,
|
|
23
|
+
uploadToIPFS,
|
|
24
|
+
createProcessorOnChain,
|
|
25
|
+
startProcessorOnChain,
|
|
26
|
+
stopProcessorOnChain,
|
|
27
|
+
confirmNoPlatformUpload,
|
|
28
|
+
getProcessorOnChain,
|
|
29
|
+
deleteProcessorOnChain
|
|
30
|
+
} from '../network.js'
|
|
31
|
+
import { Auth, DefaultBatchUploader, FileType, IPFSBatchUploader, WalrusBatchUploader } from '../uploader.js'
|
|
17
32
|
export { type Auth } from '../uploader.js'
|
|
18
33
|
|
|
19
34
|
function myParseInt(value: string, dummyPrevious: number): number {
|
|
@@ -56,16 +71,164 @@ export function createUploadCommand() {
|
|
|
56
71
|
'--required-chain-id <chain_id...>',
|
|
57
72
|
'(Optional) Specify chain IDs required for the Sentio network. This option is only available when --sentio-network is used. If omitted, all chain IDs from the project configuration (contracts or network overrides) will be used.'
|
|
58
73
|
)
|
|
74
|
+
.option(
|
|
75
|
+
'--no-platform',
|
|
76
|
+
'Upload processor directly to Sentio Network without platform support. Requires $PRIVATE_KEY env var. Only testnet is supported.'
|
|
77
|
+
)
|
|
78
|
+
.option(
|
|
79
|
+
'--ipfs-put-url <url>',
|
|
80
|
+
'IPFS upload endpoint (used with --no-platform)',
|
|
81
|
+
'https://api.sentio.xyz/v1/ipfs/add'
|
|
82
|
+
)
|
|
59
83
|
.action(async (options, command) => {
|
|
60
84
|
const processorConfig = loadProcessorConfig(options.path)
|
|
61
85
|
overrideConfigWithOptions(processorConfig, options)
|
|
62
86
|
if (options.path) {
|
|
63
87
|
process.chdir(options.path)
|
|
64
88
|
}
|
|
65
|
-
|
|
89
|
+
if (options.platform === false) {
|
|
90
|
+
await runNoPlatformUpload(processorConfig, options)
|
|
91
|
+
} else {
|
|
92
|
+
await runUploadInternal(processorConfig, options, command)
|
|
93
|
+
}
|
|
66
94
|
})
|
|
67
95
|
}
|
|
68
96
|
|
|
97
|
+
async function runNoPlatformUpload(
|
|
98
|
+
processorConfig: YamlProjectConfig,
|
|
99
|
+
options: CommandOptionsType<typeof createUploadCommand>
|
|
100
|
+
) {
|
|
101
|
+
// Determine network - default to testnet for --no-platform
|
|
102
|
+
const network = options.sentioNetwork || 'testnet'
|
|
103
|
+
const networkConfig = getSentioNetworkConfig(network)
|
|
104
|
+
|
|
105
|
+
// Step 1: Require PRIVATE_KEY
|
|
106
|
+
const privateKey = requirePrivateKey()
|
|
107
|
+
const wallet = getWalletFromPrivateKey(privateKey)
|
|
108
|
+
const walletAddress = wallet.address
|
|
109
|
+
|
|
110
|
+
// Step 2: Resolve contract addresses via AddressBook
|
|
111
|
+
console.log(chalk.blue('Resolving contract addresses from AddressBook...'))
|
|
112
|
+
const addresses = await resolveNetworkAddresses(networkConfig)
|
|
113
|
+
|
|
114
|
+
// Step 3: Check ST balance and Billing balance, then confirm
|
|
115
|
+
const [stBalance, billingBalance] = await Promise.all([
|
|
116
|
+
checkSTBalance(networkConfig, addresses, walletAddress),
|
|
117
|
+
checkBillingBalance(networkConfig, addresses, walletAddress)
|
|
118
|
+
])
|
|
119
|
+
const confirmed = await confirmNoPlatformUpload(walletAddress, stBalance, billingBalance, addresses, networkConfig)
|
|
120
|
+
if (!confirmed) {
|
|
121
|
+
console.log('Upload cancelled.')
|
|
122
|
+
process.exit(0)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Step 4: Build processor
|
|
126
|
+
if (!options.skipBuild) {
|
|
127
|
+
await buildProcessor(false, options)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const processorFile = path.join(process.cwd(), 'dist/lib.js')
|
|
131
|
+
if (!fs.existsSync(processorFile)) {
|
|
132
|
+
console.error(chalk.red('File not found:', processorFile, "- don't use --skip-build"))
|
|
133
|
+
process.exit(1)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const codeBuffer = fs.readFileSync(processorFile)
|
|
137
|
+
const stat = fs.statSync(processorFile)
|
|
138
|
+
console.log('Packed processor file size', Math.floor(stat.size / 1024) + 'K, last modified', stat.mtime)
|
|
139
|
+
|
|
140
|
+
// Step 5: Upload to IPFS
|
|
141
|
+
const ipfsPutUrl = options.ipfsPutUrl || 'https://api.sentio.xyz/v1/ipfs/add'
|
|
142
|
+
console.log(chalk.blue(`Uploading processor to IPFS (${ipfsPutUrl})...`))
|
|
143
|
+
const cid = await uploadToIPFS(codeBuffer, ipfsPutUrl)
|
|
144
|
+
console.log(chalk.green(`IPFS upload complete.`))
|
|
145
|
+
console.log('\t', chalk.blue('CID:'), cid)
|
|
146
|
+
|
|
147
|
+
// Step 6: Collect required chain IDs
|
|
148
|
+
let requiredChainIds = options.requiredChainId || processorConfig.requiredChainIds || []
|
|
149
|
+
if (requiredChainIds.length === 0) {
|
|
150
|
+
const chainIds = new Set<string>()
|
|
151
|
+
if (processorConfig.contracts) {
|
|
152
|
+
for (const contract of processorConfig.contracts) {
|
|
153
|
+
chainIds.add(String(contract.chain))
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (processorConfig.networkOverrides) {
|
|
157
|
+
for (const override of processorConfig.networkOverrides) {
|
|
158
|
+
chainIds.add(String(override.chain))
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
requiredChainIds = Array.from(chainIds)
|
|
162
|
+
}
|
|
163
|
+
if (requiredChainIds.length === 0) {
|
|
164
|
+
console.error(
|
|
165
|
+
chalk.red(
|
|
166
|
+
'Error: No chain IDs found. Specify --required-chain-id or define contracts/networkOverrides in sentio.yaml.'
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
process.exit(1)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Step 7: Derive processor ID from project name
|
|
173
|
+
let processorId = processorConfig.project.replace('/', '_')
|
|
174
|
+
const sdkVersion = getSdkVersion() || 'unknown'
|
|
175
|
+
|
|
176
|
+
// Step 7.5: Check if processor already exists on-chain
|
|
177
|
+
console.log(chalk.blue('Checking if processor already exists on-chain...'))
|
|
178
|
+
const existingProcessor = await getProcessorOnChain(networkConfig, addresses, processorId)
|
|
179
|
+
|
|
180
|
+
if (existingProcessor) {
|
|
181
|
+
const existingOwner = existingProcessor.owner.toLowerCase()
|
|
182
|
+
const currentWallet = wallet.address.toLowerCase()
|
|
183
|
+
|
|
184
|
+
if (existingOwner === currentWallet) {
|
|
185
|
+
// Same owner — prompt to replace
|
|
186
|
+
console.log(chalk.yellow(`Processor "${processorId}" already exists (owned by you).`))
|
|
187
|
+
const shouldReplace = await confirm(`Replace existing processor "${processorId}"?`)
|
|
188
|
+
if (!shouldReplace) {
|
|
189
|
+
console.log('Upload cancelled.')
|
|
190
|
+
process.exit(0)
|
|
191
|
+
}
|
|
192
|
+
// Stop and delete existing processor before re-creating
|
|
193
|
+
await stopProcessorOnChain(networkConfig, addresses, wallet, processorId)
|
|
194
|
+
await deleteProcessorOnChain(networkConfig, addresses, wallet, processorId)
|
|
195
|
+
} else {
|
|
196
|
+
// Different owner — prompt to rename
|
|
197
|
+
console.log(
|
|
198
|
+
chalk.yellow(
|
|
199
|
+
`Processor "${processorId}" already exists and is owned by ${existingProcessor.owner} (not your wallet ${wallet.address}).`
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
const randomSuffix = Math.random().toString(36).substring(2, 8)
|
|
203
|
+
const defaultNewId = `${processorId}-${randomSuffix}`
|
|
204
|
+
|
|
205
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
206
|
+
const newId: string = await new Promise((resolve) =>
|
|
207
|
+
rl.question(`Enter a new processor ID [${defaultNewId}]: `, (answer) => {
|
|
208
|
+
rl.close()
|
|
209
|
+
resolve(answer.trim() || defaultNewId)
|
|
210
|
+
})
|
|
211
|
+
)
|
|
212
|
+
processorId = newId
|
|
213
|
+
console.log(chalk.blue(`Using processor ID: ${processorId}`))
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Step 8: Create processor on-chain
|
|
218
|
+
await createProcessorOnChain(networkConfig, addresses, wallet, processorId, cid, requiredChainIds, sdkVersion)
|
|
219
|
+
|
|
220
|
+
// Step 9: Start processor on-chain
|
|
221
|
+
await startProcessorOnChain(networkConfig, addresses, wallet, processorId)
|
|
222
|
+
|
|
223
|
+
console.log()
|
|
224
|
+
console.log(chalk.green('=== Upload Complete ==='))
|
|
225
|
+
console.log('\t', chalk.blue('Processor ID:'), processorId)
|
|
226
|
+
console.log('\t', chalk.blue('IPFS CID:'), cid)
|
|
227
|
+
console.log('\t', chalk.blue('Network:'), network)
|
|
228
|
+
const codeHash = createHash('sha256').update(codeBuffer).digest('hex')
|
|
229
|
+
console.log('\t', chalk.blue('sha256:'), codeHash)
|
|
230
|
+
}
|
|
231
|
+
|
|
69
232
|
function parseCheckpoints(
|
|
70
233
|
checkpoints: string[] | undefined,
|
|
71
234
|
continueFrom: number | undefined,
|
|
@@ -322,6 +485,15 @@ async function checkOrCreateProject(options: YamlProjectConfig, auth: Auth) {
|
|
|
322
485
|
)
|
|
323
486
|
process.exit(1)
|
|
324
487
|
}
|
|
488
|
+
if (!options.sentioNetwork && project.sentioNetwork === true) {
|
|
489
|
+
console.error(
|
|
490
|
+
chalk.red(
|
|
491
|
+
`Project ${project?.slug} is a Sentio Network project. Please add the --sentio-network flag when uploading.\n` +
|
|
492
|
+
`Example: sentio upload --sentio-network testnet`
|
|
493
|
+
)
|
|
494
|
+
)
|
|
495
|
+
process.exit(1)
|
|
496
|
+
}
|
|
325
497
|
return project?.id
|
|
326
498
|
}
|
|
327
499
|
|
|
@@ -421,6 +593,26 @@ export async function uploadFile(
|
|
|
421
593
|
? new IPFSBatchUploader(config, auth)
|
|
422
594
|
: new DefaultBatchUploader(config, auth)
|
|
423
595
|
|
|
596
|
+
// Initialize upload and handle confirmation
|
|
597
|
+
const fileTypes: Record<string, number> = {
|
|
598
|
+
source: FileType.SOURCE,
|
|
599
|
+
code: FileType.PROCESSOR
|
|
600
|
+
}
|
|
601
|
+
const initResponse = await uploader.initUpload(fileTypes)
|
|
602
|
+
|
|
603
|
+
if (initResponse.warning) {
|
|
604
|
+
console.log(chalk.yellow(initResponse.warning))
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (initResponse.replacing_version && !config.silentOverwrite) {
|
|
608
|
+
const confirmed = await confirm(
|
|
609
|
+
`This will replace processor version ${initResponse.replacing_version}. Continue?`
|
|
610
|
+
)
|
|
611
|
+
if (!confirmed) {
|
|
612
|
+
process.exit(0)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
424
616
|
// Handle variables update if needed
|
|
425
617
|
if (config.variables && config.variables.length > 0) {
|
|
426
618
|
const ret = await updateVariables(projectId, config, auth)
|
|
@@ -439,7 +631,8 @@ export async function uploadFile(
|
|
|
439
631
|
config.debug || options.debug,
|
|
440
632
|
continueFrom,
|
|
441
633
|
config.networkOverrides,
|
|
442
|
-
rollbackMap
|
|
634
|
+
rollbackMap,
|
|
635
|
+
initResponse
|
|
443
636
|
)
|
|
444
637
|
|
|
445
638
|
console.log(chalk.green('Upload success: '))
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { createPriceCommand } from './commands/price.js'
|
|
|
19
19
|
import { createSimulationCommand } from './commands/simulation.js'
|
|
20
20
|
import { createEndpointCommand } from './commands/endpoint.js'
|
|
21
21
|
import { createDashboardCommand } from './commands/dashboard.js'
|
|
22
|
+
import { createStopProcessorCommand } from './commands/stop-processor.js'
|
|
22
23
|
import { enableApiDebug } from './api.js'
|
|
23
24
|
import { printVersions } from './utils.js'
|
|
24
25
|
|
|
@@ -52,5 +53,6 @@ program.addCommand(createPriceCommand())
|
|
|
52
53
|
program.addCommand(createSimulationCommand())
|
|
53
54
|
program.addCommand(createEndpointCommand())
|
|
54
55
|
program.addCommand(createDashboardCommand())
|
|
56
|
+
program.addCommand(createStopProcessorCommand())
|
|
55
57
|
|
|
56
58
|
program.parse()
|