soluser 1.0.1 → 1.0.5

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/README.md CHANGED
@@ -1,27 +1,37 @@
1
1
  # soluser
2
- # 新建账号
2
+ ## 安装
3
3
  ```shell
4
+ npm install -g soluser@latest
5
+ ```
6
+ ## 新建账号
7
+ ```shell
8
+ $ soluser new charlie
4
9
  $ soluser new alice --word-length 12
5
10
  $ soluser new bob --word-length 24 --no-bip39-passphrase
6
- $ soluser new charlie
7
11
  ```
8
12
 
9
- # 切换账号
13
+ ## 切换账号
10
14
  ```shell
11
- $ soluser switch --address alice
15
+ $ soluser switch bob
12
16
  ```
13
17
 
14
- # 列出账号
18
+ ## 列出账号
15
19
  ```shell
16
20
  $ soluser list
17
21
  ```
18
22
 
19
- # 删除账号
23
+ ## 删除账号
20
24
  ```shell
21
25
  $ soluser remove alice
22
26
  ```
23
27
 
24
- # 本地安装
28
+ ## 查看alias对应的地址
25
29
  ```shell
26
- npm link
30
+ $ soluser address alice
27
31
  ```
32
+
33
+ ## 查看alias对应的余额
34
+ ```shell
35
+ $ soluser balance alice
36
+ ```
37
+
package/bin/index.js CHANGED
@@ -6,6 +6,30 @@ const switchAccount = require('../src/commands/switch');
6
6
  const listAccounts = require('../src/commands/list');
7
7
  const removeAccount = require('../src/commands/remove');
8
8
 
9
+ // 导入地址查询命令
10
+ const showAddress = require('../src/commands/address');
11
+
12
+ // 定义地址查询命令
13
+ program
14
+ .command('address')
15
+ .description('Output the base58 address of a Solana account')
16
+ .argument('<alias>', 'Alias of the account to get address') // 接收别名作为位置参数
17
+ .action((alias) => {
18
+ showAddress(alias);
19
+ });
20
+
21
+ // 导入余额查询命令
22
+ const checkBalance = require('../src/commands/balance');
23
+
24
+ // 定义余额查询命令
25
+ program
26
+ .command('balance')
27
+ .description('Check the SOL balance of a Solana account')
28
+ .argument('<alias>', 'Alias of the account to check balance') // 接收别名作为位置参数
29
+ .action((alias) => {
30
+ checkBalance(alias);
31
+ });
32
+
9
33
 
10
34
  // 定义新建账号命令
11
35
  // 定义新建账号命令(修改后)
@@ -14,27 +38,30 @@ program
14
38
  .description('Create a new Solana account')
15
39
  .argument('<alias>', 'Alias for the new account (must start with a letter, contain letters, digits, hyphens, or underscores)') // 新增位置参数
16
40
  .option('--word-length <number>', 'Number of words in seed phrase (12,15,18,21,24)', 12)
17
- .option('--no-bip39-passphrase', 'Do not prompt for BIP39 passphrase')
41
+ .option('--without-passphrase', 'Do not prompt for BIP39 passphrase',false)
18
42
  .action((alias, options) => { // 第一个参数为位置参数 alias,第二个为选项
43
+ // // 打印选项值验证(调试用)
44
+ // console.log('without-passphrase:', options.withoutPassphrase);
45
+ // console.log("type noPassphrase:", typeof(options.withoutPassphrase), "value:", options.withoutPassphrase)
46
+
19
47
  newAccount(
20
48
  alias, // 直接使用位置参数的 alias
21
49
  parseInt(options.wordLength, 10), //10进制解析
22
- options.noBip39Passphrase
50
+ options.withoutPassphrase
23
51
  );
24
52
  });
25
53
 
26
- // 定义切换账号命令
54
+
55
+ // 定义切换账号命令(修改后)
27
56
  program
28
57
  .command('switch')
29
58
  .description('Switch active Solana account')
30
- .option('--address <alias>', 'Alias of the account to switch to', '')
31
- .action((options) => {
32
- if (!options.address) {
33
- throw new Error('Alias is required (use --address <alias>)');
34
- }
35
- switchAccount(options.address);
59
+ .argument('<alias>', 'Alias of the account to switch to') // 新增位置参数
60
+ .action((alias) => { // 直接使用位置参数 alias
61
+ switchAccount(alias);
36
62
  });
37
63
 
64
+
38
65
  // 定义列出账号命令
39
66
  program
40
67
  .command('list')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soluser",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "A CLI tool to manage Solana accounts (new, switch, list)",
5
5
  "main": "bin/index.js",
6
6
  "bin": {
@@ -0,0 +1,22 @@
1
+ const { existsAccount, getKeyFilePath } = require('../utils/path');
2
+ const { getAddress } = require('../utils/solana');
3
+
4
+ function showAddress(alias) {
5
+ // 1. 检查账号是否存在
6
+ if (!existsAccount(alias)) {
7
+ console.error(`Error: Account "${alias}" does not exist.`);
8
+ console.error(` Use "soluser list" to view all available accounts.`);
9
+ process.exit(1);
10
+ }
11
+
12
+ // 2. 解析并输出 base58 地址
13
+ try {
14
+ const address = getAddress(alias); // 复用之前的 getAddress 函数(基于 solana-keygen)
15
+ console.log(address); // 直接输出地址(方便脚本调用)
16
+ } catch (err) {
17
+ console.error(`Error: Failed to parse address for "${alias}": ${err.message}`);
18
+ process.exit(1);
19
+ }
20
+ }
21
+
22
+ module.exports = showAddress;
@@ -0,0 +1,33 @@
1
+ const { existsAccount } = require('../utils/path');
2
+ const { getAddress, execCommand } = require('../utils/solana');
3
+
4
+ function checkBalance(alias) {
5
+ // 1. 检查账号是否存在
6
+ if (!existsAccount(alias)) {
7
+ console.error(`Error: Account "${alias}" does not exist.`);
8
+ console.error(` Use "soluser list" to view all available accounts.`);
9
+ process.exit(1);
10
+ }
11
+
12
+ // 2. 获取账号对应的公钥(address)
13
+ let address;
14
+ try {
15
+ address = getAddress(alias);
16
+ } catch (err) {
17
+ console.error(`Error: Failed to get address for "${alias}": ${err.message}`);
18
+ process.exit(1);
19
+ }
20
+
21
+ // 3. 调用 solana balance 命令查询余额
22
+ try {
23
+ // solana balance 命令会返回类似 "1.2345 SOL" 的结果
24
+ const balance = execCommand(`solana balance ${address}`);
25
+ console.log(`${alias}: ${balance}`); // 输出格式:别名 + 余额
26
+ } catch (err) {
27
+ console.error(`Error: Failed to check balance for "${alias}": ${err.message}`);
28
+ console.error(` Ensure Solana CLI is configured with a valid network (e.g., "solana config set --url https://api.devnet.solana.com")`);
29
+ process.exit(1);
30
+ }
31
+ }
32
+
33
+ module.exports = checkBalance;
@@ -26,7 +26,7 @@ function listAccounts() {
26
26
  // 3. 构建表格
27
27
  const table = new Table({
28
28
  head: ['alias', 'address', 'active'],
29
- colWidths: [15, 45, 8],
29
+ colWidths: [15, 50, 8],
30
30
  });
31
31
 
32
32
  // 4. 填充表格数据
@@ -34,7 +34,7 @@ function listAccounts() {
34
34
  const alias = path.basename(file, '.json');
35
35
  const address = getAddress(alias);
36
36
  const isActive = alias === activeAlias ? '*' : '';
37
- console.log("alias: ", alias, "address: ", address, "isActive: ", isActive,'activeAlias',activeAlias )
37
+ //console.log("alias: ", alias, "address: ", address, "isActive: ", isActive,'activeAlias',activeAlias )
38
38
  table.push([alias, address, isActive]);
39
39
  });
40
40
 
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
- const { KEYS_DIR, validateAlias, getKeyFilePath } = require('../utils/path');
2
+ const { KEYS_DIR, validateAlias, getKeyFilePath ,existsAccount} = require('../utils/path');
3
3
  const { execCommand } = require('../utils/solana');
4
+ const ThrowErorr = require('../utils/throw_error');
4
5
 
5
6
  function newAccount(alias, wordLength = 12, noPassphrase = false) {
6
7
  // 1. 确保密钥目录存在
@@ -10,21 +11,38 @@ function newAccount(alias, wordLength = 12, noPassphrase = false) {
10
11
 
11
12
  // 2. 验证参数
12
13
  validateAlias(alias);
14
+
15
+ // 3. 新增:检查账号是否已存在
16
+ if (existsAccount(alias)) {
17
+ console.error(`Error: Account "${alias}" already exists.`);
18
+ console.error(` Use "soluser list" to view existing accounts, or choose a different alias.`);
19
+ process.exit(1);
20
+ }
21
+
22
+
23
+ // 4. 验证助记词长度(已有逻辑)
13
24
  const validWordLengths = [12, 15, 18, 21, 24];
14
25
  if (!validWordLengths.includes(wordLength)) {
15
- throw new Error(`Word length must be one of: ${validWordLengths.join(', ')}`);
26
+ ThrowErorr(`Word length must be one of: ${validWordLengths.join(', ')}`);
16
27
  }
17
28
 
18
- // 3. 生成密钥对(调用 solana-keygen)
19
- const keyPath = getKeyFilePath(alias);
20
- let command = `solana-keygen new --word-count ${wordLength} --outfile ${keyPath}`;
21
- if (noPassphrase) {
22
- command += ' --no-bip39-passphrase';
23
- }
29
+
30
+
24
31
 
25
- console.log(`Generating key pair for ${alias}...`);
26
- execCommand(command);
27
- console.log(`Successfully created account: ${alias} (saved to ${keyPath})`);
32
+ // 5. 生成密钥对(已有逻辑)
33
+ try {
34
+ let command = `solana-keygen new --word-count ${wordLength} --outfile ${getKeyFilePath(alias)}`;
35
+
36
+ if (noPassphrase) {
37
+ command += ' --no-bip39-passphrase';
38
+ }
39
+ console.log(`Generating key pair for ${alias}...`);
40
+ execCommand(command);
41
+ console.log(`Successfully created account: ${alias} (saved to ${getKeyFilePath(alias)})`);
42
+ } catch (err) {
43
+ console.error(`Error: Failed to generate key pair: ${err.message}`);
44
+ process.exit(1);
45
+ }
28
46
  }
29
47
 
30
48
  module.exports = newAccount;
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const { validateAlias, getKeyFilePath } = require('../utils/path');
3
3
  const { getActiveKeyPath } = require('../utils/solana');
4
4
  const path = require('path');
5
-
5
+ const ThrowErorr = require('../utils/throw_error');
6
6
  function removeAccount(alias) {
7
7
  // 1. 验证别名格式
8
8
  validateAlias(alias);
@@ -10,7 +10,7 @@ function removeAccount(alias) {
10
10
  // 2. 检查密钥文件是否存在
11
11
  const keyPath = getKeyFilePath(alias);
12
12
  if (!fs.existsSync(keyPath)) {
13
- throw new Error(`Account "${alias}" not found. Use "soluser list" to check existing accounts.`);
13
+ ThrowErorr(`Account "${alias}" not found. Use "soluser list" to check existing accounts.`);
14
14
  }
15
15
 
16
16
  // 3. 检查是否为当前活跃账号
@@ -1,13 +1,13 @@
1
1
  const fs = require('fs');
2
2
  const { getKeyFilePath } = require('../utils/path');
3
3
  const { execCommand } = require('../utils/solana');
4
-
4
+ const ThrowErorr = require('../utils/throw_error');
5
5
  function switchAccount(alias) {
6
6
  const keyPath = getKeyFilePath(alias);
7
7
 
8
8
  // 验证密钥文件是否存在
9
9
  if (!fs.existsSync(keyPath)) {
10
- throw new Error(`Account ${alias} not found. Check alias or create it with "soluser new".`);
10
+ ThrowErorr(`Account ${alias} not found. Check alias or create it with "soluser new".`);
11
11
  }
12
12
 
13
13
  // 执行切换(调用 solana config set)
package/src/develop.md ADDED
@@ -0,0 +1,6 @@
1
+ # ai 生成提示符号
2
+ - 使用豆包生成, 再稍微调整
3
+ ## 本地安装
4
+ ```shell
5
+ npm link
6
+ ```
package/src/utils/path.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const os = require('os');
3
-
3
+ const ThrowErorr = require('../utils/throw_error');
4
4
  // 密钥存储目录:~/.config/solana/keys
5
5
  const KEYS_DIR = path.join(os.homedir(), '.config', 'solana', 'keys');
6
6
 
@@ -8,7 +8,7 @@ const KEYS_DIR = path.join(os.homedir(), '.config', 'solana', 'keys');
8
8
  function validateAlias(alias) {
9
9
  const regex = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
10
10
  if (!regex.test(alias)) {
11
- throw new Error('Alias must start with a letter and contain only letters, digits, hyphens, or underscores');
11
+ ThrowErorr('Alias must start with a letter and contain only letters, digits, hyphens, or underscores');
12
12
  }
13
13
  }
14
14
 
@@ -17,9 +17,19 @@ function getKeyFilePath(alias) {
17
17
  return path.join(KEYS_DIR, `${alias}.json`);
18
18
  }
19
19
 
20
+ // 检查账号是否存在(即密钥文件是否存在)
21
+ function existsAccount(alias) {
22
+ const keyPath = getKeyFilePath(alias);
23
+ return fs.existsSync(keyPath); // 返回布尔值:true=存在,false=不存在
24
+ }
25
+
26
+ // 记得在顶部导入 fs
27
+ const fs = require('fs');
28
+
20
29
  module.exports = {
21
30
  KEYS_DIR,
22
31
  validateAlias,
23
32
  getKeyFilePath,
33
+ existsAccount,
24
34
  };
25
35
 
@@ -1,12 +1,12 @@
1
1
  const { execSync } = require('child_process');
2
2
  const { getKeyFilePath } = require('./path');
3
-
3
+ const ThrowErorr = require('../utils/throw_error');
4
4
  // 执行 shell 命令并返回输出
5
5
  function execCommand(command) {
6
6
  try {
7
7
  return execSync(command, { encoding: 'utf8' }).trim();
8
8
  } catch (error) {
9
- throw new Error(`Command failed: ${command}\n${error.stderr}`);
9
+ ThrowErorr(`Command failed: ${command}\n${error.stderr}`);
10
10
  }
11
11
  }
12
12
 
@@ -21,7 +21,7 @@ function getActiveKeyPath() {
21
21
  const config = execCommand('solana config get keypair');
22
22
  // 从输出中提取路径(例如:"Keypair Path: /home/user/.config/solana/keys/alice.json")
23
23
  const match = config.match(/Key Path: (.*)/);
24
- console.log("config:",config,"config match :",match)
24
+ //console.log("config:",config,"config match :",match)
25
25
  return match ? match[1] : null;
26
26
  }
27
27
 
@@ -0,0 +1,12 @@
1
+
2
+ function ThrowError(msg){
3
+ var isDebug = false;
4
+ if(isDebug){
5
+ throw new Error(msg);
6
+ } else{
7
+ console.error(msg);
8
+ process.exit(-1);
9
+ }
10
+ }
11
+
12
+ module.exports = ThrowError