@0xobelisk/sui-cli 1.2.0-pre.15 → 1.2.0-pre.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xobelisk/sui-cli",
3
- "version": "1.2.0-pre.15",
3
+ "version": "1.2.0-pre.16",
4
4
  "description": "Tookit for interacting with move eps framework",
5
5
  "keywords": [
6
6
  "sui",
@@ -50,8 +50,8 @@
50
50
  "yargs": "^17.7.1",
51
51
  "zod": "^3.22.3",
52
52
  "zod-validation-error": "^1.3.0",
53
- "@0xobelisk/sui-client": "1.2.0-pre.15",
54
- "@0xobelisk/sui-common": "1.2.0-pre.15"
53
+ "@0xobelisk/sui-client": "1.2.0-pre.16",
54
+ "@0xobelisk/sui-common": "1.2.0-pre.16"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/ejs": "^3.1.1",
@@ -15,6 +15,7 @@ import query from './query';
15
15
  import call from './call';
16
16
  import watch from './watch';
17
17
  import wait from './wait';
18
+ import switchEnv from './switchEnv';
18
19
 
19
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
20
21
  export const commands: CommandModule<any, any>[] = [
@@ -32,5 +33,6 @@ export const commands: CommandModule<any, any>[] = [
32
33
  checkBalance,
33
34
  configStore,
34
35
  watch,
35
- wait
36
+ wait,
37
+ switchEnv
36
38
  ];
@@ -0,0 +1,24 @@
1
+ import type { CommandModule, ArgumentsCamelCase } from 'yargs';
2
+ import { switchEnv } from '../utils';
3
+
4
+ type Options = {
5
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
6
+ };
7
+
8
+ const commandModule: CommandModule<Options, Options> = {
9
+ command: 'switch-env',
10
+ describe: 'Switch environment',
11
+ builder(yargs) {
12
+ return yargs.option('network', {
13
+ type: 'string',
14
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet'] as const,
15
+ default: 'localnet',
16
+ desc: 'Switch to node network (mainnet/testnet/devnet/localnet)'
17
+ }) as any;
18
+ },
19
+ async handler(argv: ArgumentsCamelCase<Options>) {
20
+ await switchEnv(argv.network as 'mainnet' | 'testnet' | 'devnet' | 'localnet');
21
+ }
22
+ };
23
+
24
+ export default commandModule;
@@ -207,32 +207,147 @@ export async function updateDubheDependency(
207
207
  fs.writeFileSync(filePath, updatedContent, 'utf-8');
208
208
  console.log(`Updated Dubhe dependency in ${filePath} for ${network}.`);
209
209
  }
210
+
211
+ async function checkRpcAvailability(rpcUrl: string): Promise<boolean> {
212
+ try {
213
+ const response = await fetch(rpcUrl, {
214
+ method: 'POST',
215
+ headers: {
216
+ 'Content-Type': 'application/json'
217
+ },
218
+ body: JSON.stringify({
219
+ jsonrpc: '2.0',
220
+ id: 1,
221
+ method: 'sui_getLatestCheckpointSequenceNumber',
222
+ params: []
223
+ })
224
+ });
225
+
226
+ if (!response.ok) {
227
+ return false;
228
+ }
229
+
230
+ const data = await response.json();
231
+ return !data.error;
232
+ } catch (error) {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ export async function addEnv(
238
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
239
+ ): Promise<void> {
240
+ const rpcMap = {
241
+ localnet: 'http://127.0.0.1:9000',
242
+ devnet: 'https://fullnode.devnet.sui.io:443/',
243
+ testnet: 'https://fullnode.testnet.sui.io:443/',
244
+ mainnet: 'https://fullnode.mainnet.sui.io:443/'
245
+ };
246
+
247
+ const rpcUrl = rpcMap[network];
248
+
249
+ // Check RPC availability first
250
+ const isRpcAvailable = await checkRpcAvailability(rpcUrl);
251
+ if (!isRpcAvailable) {
252
+ throw new Error(
253
+ `RPC endpoint ${rpcUrl} is not available. Please check your network connection or try again later.`
254
+ );
255
+ }
256
+
257
+ return new Promise<void>((resolve, reject) => {
258
+ let errorOutput = '';
259
+ let stdoutOutput = '';
260
+
261
+ const suiProcess = spawn(
262
+ 'sui',
263
+ ['client', 'new-env', '--alias', network, '--rpc', rpcMap[network]],
264
+ {
265
+ env: { ...process.env },
266
+ stdio: 'pipe'
267
+ }
268
+ );
269
+
270
+ // Capture standard output
271
+ suiProcess.stdout.on('data', (data) => {
272
+ stdoutOutput += data.toString();
273
+ });
274
+
275
+ // Capture error output
276
+ suiProcess.stderr.on('data', (data) => {
277
+ errorOutput += data.toString();
278
+ });
279
+
280
+ // Handle process errors (e.g., command not found)
281
+ suiProcess.on('error', (error) => {
282
+ console.error(chalk.red(`\n❌ Failed to execute sui command: ${error.message}`));
283
+ reject(new Error(`Failed to execute sui command: ${error.message}`));
284
+ });
285
+
286
+ // Handle process exit
287
+ suiProcess.on('exit', (code) => {
288
+ // Check if "already exists" message is present
289
+ if (errorOutput.includes('already exists') || stdoutOutput.includes('already exists')) {
290
+ console.log(chalk.yellow(`Environment ${network} already exists, proceeding...`));
291
+ resolve();
292
+ return;
293
+ }
294
+
295
+ if (code === 0) {
296
+ console.log(chalk.green(`Successfully added environment ${network}`));
297
+ resolve();
298
+ } else {
299
+ const finalError = errorOutput || stdoutOutput || `Process exited with code ${code}`;
300
+ console.error(chalk.red(`\n❌ Failed to add environment ${network}`));
301
+ console.error(chalk.red(` └─ ${finalError.trim()}`));
302
+ reject(new Error(finalError));
303
+ }
304
+ });
305
+ });
306
+ }
307
+
210
308
  export async function switchEnv(network: 'mainnet' | 'testnet' | 'devnet' | 'localnet') {
211
309
  try {
310
+ // First, try to add the environment
311
+ await addEnv(network);
312
+
313
+ // Then switch to the specified environment
212
314
  return new Promise<void>((resolve, reject) => {
315
+ let errorOutput = '';
316
+ let stdoutOutput = '';
317
+
213
318
  const suiProcess = spawn('sui', ['client', 'switch', '--env', network], {
214
319
  env: { ...process.env },
215
320
  stdio: 'pipe'
216
321
  });
217
322
 
323
+ suiProcess.stdout.on('data', (data) => {
324
+ stdoutOutput += data.toString();
325
+ });
326
+
327
+ suiProcess.stderr.on('data', (data) => {
328
+ errorOutput += data.toString();
329
+ });
330
+
218
331
  suiProcess.on('error', (error) => {
219
- console.error(chalk.red('\n❌ Failed to Switch Env'));
220
- console.error(chalk.red(` Error: ${error.message}`));
221
- reject(error); // Reject promise on error
332
+ console.error(chalk.red(`\n❌ Failed to execute sui command: ${error.message}`));
333
+ reject(new Error(`Failed to execute sui command: ${error.message}`));
222
334
  });
223
335
 
224
336
  suiProcess.on('exit', (code) => {
225
- if (code !== 0) {
226
- console.error(chalk.red(`\n❌ Process exited with code: ${code}`));
227
- reject(new Error(`Process exited with code: ${code}`));
337
+ if (code === 0) {
338
+ console.log(chalk.green(`Successfully switched to environment ${network}`));
339
+ resolve();
228
340
  } else {
229
- resolve(); // Resolve promise on successful exit
341
+ const finalError = errorOutput || stdoutOutput || `Process exited with code ${code}`;
342
+ console.error(chalk.red(`\n❌ Failed to switch to environment ${network}`));
343
+ console.error(chalk.red(` └─ ${finalError.trim()}`));
344
+ reject(new Error(finalError));
230
345
  }
231
346
  });
232
347
  });
233
348
  } catch (error) {
234
- console.error(chalk.red('\n❌ Failed to Switch Env'));
235
- console.error(chalk.red(` └─ Error: ${error}`));
349
+ // Re-throw the error for the caller to handle
350
+ throw error;
236
351
  }
237
352
  }
238
353