@super-protocol/sp-cli 0.0.9 → 0.0.10-beta
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 +191 -163
- package/dist/commands/account/base.d.ts +3 -4
- package/dist/commands/account/base.js +8 -6
- package/dist/commands/account/forget.js +3 -3
- package/dist/commands/account/get-sppi.js +7 -11
- package/dist/commands/account/info.d.ts +1 -13
- package/dist/commands/account/info.js +20 -40
- package/dist/commands/account/list.js +6 -6
- package/dist/commands/account/login.d.ts +6 -5
- package/dist/commands/account/login.js +96 -145
- package/dist/commands/account/switch.js +2 -2
- package/dist/commands/assets/base.d.ts +39 -0
- package/dist/commands/assets/base.js +217 -0
- package/dist/commands/assets/create.d.ts +41 -0
- package/dist/commands/assets/create.js +277 -0
- package/dist/commands/assets/delete.d.ts +14 -0
- package/dist/commands/assets/delete.js +69 -0
- package/dist/commands/assets/get.d.ts +14 -0
- package/dist/commands/assets/get.js +79 -0
- package/dist/commands/assets/list.d.ts +7 -0
- package/dist/commands/assets/list.js +33 -0
- package/dist/commands/assets/update.d.ts +44 -0
- package/dist/commands/assets/update.js +321 -0
- package/dist/commands/base.d.ts +1 -0
- package/dist/commands/base.js +5 -0
- package/dist/config/config.schema.d.ts +2 -11
- package/dist/config/config.schema.js +2 -7
- package/dist/constants.d.ts +3 -3
- package/dist/constants.js +3 -3
- package/dist/errors.d.ts +0 -2
- package/dist/errors.js +0 -2
- package/dist/hooks/prerun/auth.js +3 -8
- package/dist/interfaces/config-manager.interface.d.ts +3 -1
- package/dist/lib/container.d.ts +4 -12
- package/dist/lib/container.js +28 -113
- package/dist/lib/swarm-client/fetch-api.d.ts +7 -0
- package/dist/lib/swarm-client/fetch-api.js +41 -0
- package/dist/lib/swarm-client/fetch-timeout.client.d.ts +1 -0
- package/dist/lib/swarm-client/fetch-timeout.client.js +32 -0
- package/dist/lib/swarm-client/index.d.ts +6 -0
- package/dist/lib/swarm-client/index.js +31 -0
- package/dist/lib/swarm-client/middlewares/authorization.middleware.d.ts +2 -0
- package/dist/lib/swarm-client/middlewares/authorization.middleware.js +12 -0
- package/dist/lib/swarm-client/middlewares/index.d.ts +6 -0
- package/dist/lib/swarm-client/middlewares/index.js +5 -0
- package/dist/lib/swarm-client/middlewares/logger.middleware.d.ts +2 -0
- package/dist/lib/swarm-client/middlewares/logger.middleware.js +30 -0
- package/dist/lib/swarm-client/middlewares/request-id.middleware.d.ts +2 -0
- package/dist/lib/swarm-client/middlewares/request-id.middleware.js +13 -0
- package/dist/lib/swarm-client/types.d.ts +23 -0
- package/dist/lib/swarm-client/types.js +1 -0
- package/dist/managers/account-manager.d.ts +1 -0
- package/dist/managers/account-manager.js +13 -18
- package/dist/managers/config-file-manager.d.ts +22 -9
- package/dist/managers/config-file-manager.js +247 -122
- package/dist/managers/config-manager.d.ts +6 -6
- package/dist/managers/config-manager.js +8 -8
- package/dist/services/account.service.d.ts +42 -0
- package/dist/services/account.service.js +140 -0
- package/dist/services/asset.service.d.ts +35 -0
- package/dist/services/asset.service.js +120 -0
- package/dist/services/auth.service.d.ts +4 -6
- package/dist/services/auth.service.js +108 -118
- package/dist/utils/helper.js +2 -2
- package/oclif.manifest.json +462 -212
- package/package.json +7 -8
- package/dist/commands/files/download.d.ts +0 -15
- package/dist/commands/files/download.js +0 -63
- package/dist/commands/files/upload.d.ts +0 -18
- package/dist/commands/files/upload.js +0 -83
- package/dist/commands/storage/base.d.ts +0 -13
- package/dist/commands/storage/base.js +0 -125
- package/dist/commands/storage/create.d.ts +0 -11
- package/dist/commands/storage/create.js +0 -53
- package/dist/commands/storage/select.d.ts +0 -9
- package/dist/commands/storage/select.js +0 -38
- package/dist/commands/storage/show.d.ts +0 -17
- package/dist/commands/storage/show.js +0 -34
- package/dist/commands/storage/update.d.ts +0 -14
- package/dist/commands/storage/update.js +0 -204
- package/dist/commands/workflows/extend-lease.d.ts +0 -17
- package/dist/commands/workflows/extend-lease.js +0 -102
- package/dist/hooks/finally/shutdown-blockchain.d.ts +0 -3
- package/dist/hooks/finally/shutdown-blockchain.js +0 -8
- package/dist/middlewares/auth-middleware.d.ts +0 -9
- package/dist/middlewares/auth-middleware.js +0 -91
- package/dist/middlewares/cookies-middleware.d.ts +0 -8
- package/dist/middlewares/cookies-middleware.js +0 -80
- package/dist/services/storage.service.d.ts +0 -73
- package/dist/services/storage.service.js +0 -378
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { formatEther } from 'viem';
|
|
1
|
+
//import { formatEther } from 'viem';
|
|
2
2
|
import { BaseAccountCommand } from './base.js';
|
|
3
3
|
export default class AccountGetSppi extends BaseAccountCommand {
|
|
4
4
|
static description = 'Get SPPI (Super Protocol incentive tokens) ';
|
|
5
5
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
6
6
|
async run() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
const tokens = formatEther(BigInt(data.amount || '0'));
|
|
14
|
-
this.log('Tokens replenished');
|
|
15
|
-
this.log(`Current balance: ${tokens} SPPI`);
|
|
16
|
-
return { tokens };
|
|
7
|
+
this.error('Not implemented yet');
|
|
8
|
+
// await this.initAccountContext();
|
|
9
|
+
// const tokens = formatEther(BigInt('0'));
|
|
10
|
+
// this.log('Tokens replenished');
|
|
11
|
+
// this.log(`Current balance: ${tokens} SPPI`);
|
|
12
|
+
// return { tokens };
|
|
17
13
|
}
|
|
18
14
|
}
|
|
@@ -6,20 +6,8 @@ export declare class InfoCommand extends BaseAccountCommand<typeof InfoCommand>
|
|
|
6
6
|
};
|
|
7
7
|
init(): Promise<void>;
|
|
8
8
|
run(): Promise<{
|
|
9
|
-
address: string;
|
|
9
|
+
address: string | undefined;
|
|
10
10
|
balance: string;
|
|
11
|
-
storage: {
|
|
12
|
-
bucket: string;
|
|
13
|
-
createdAt: string;
|
|
14
|
-
id: string;
|
|
15
|
-
isCentralized: boolean;
|
|
16
|
-
prefix: string;
|
|
17
|
-
s3Credentials?: import("@super-protocol/provider-client").components["schemas"]["S3CredentialsResponseDto"];
|
|
18
|
-
storageType: import("@super-protocol/provider-client").components["schemas"]["StorageType"];
|
|
19
|
-
storjCredentials?: import("@super-protocol/provider-client").components["schemas"]["StorJCredentialsResponseDto"];
|
|
20
|
-
updatedAt: string;
|
|
21
|
-
userId: string;
|
|
22
|
-
};
|
|
23
11
|
wallet: string;
|
|
24
12
|
}>;
|
|
25
13
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import { formatEther } from 'viem';
|
|
3
|
-
import {
|
|
4
|
-
import { StorageService } from '../../services/storage.service.js';
|
|
3
|
+
import { SWARM_URL } from '../../constants.js';
|
|
5
4
|
import { BaseAccountCommand } from './base.js';
|
|
6
5
|
export class InfoCommand extends BaseAccountCommand {
|
|
7
6
|
static description = 'Information about current authorized user';
|
|
@@ -17,54 +16,36 @@ export class InfoCommand extends BaseAccountCommand {
|
|
|
17
16
|
}
|
|
18
17
|
async run() {
|
|
19
18
|
const { flags } = await this.parse(InfoCommand);
|
|
20
|
-
const {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
const { accountManager, configFileManager } = this.container;
|
|
20
|
+
const current = configFileManager.getCurrentConfigFile();
|
|
21
|
+
let address;
|
|
22
|
+
try {
|
|
23
|
+
address = accountManager.getAddress();
|
|
25
24
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.error('Failed to retrieve wallet information');
|
|
32
|
-
}
|
|
33
|
-
const storage = await storageService.getCurrentStorage();
|
|
34
|
-
const balance = formatEther(BigInt(wallet?.teeBalance || '0'));
|
|
35
|
-
this.log(`Login: ${data.address}`);
|
|
36
|
-
this.log(`Super Wallet: ${data.internalAddress}`);
|
|
25
|
+
catch { }
|
|
26
|
+
const walletAddress = 'N/A';
|
|
27
|
+
const balance = formatEther(0n);
|
|
28
|
+
this.log(`Login: ${address || 'N/A'}`);
|
|
29
|
+
this.log(`Super Wallet: ${walletAddress}`);
|
|
37
30
|
this.log(`Balance: ${balance} SPPI`);
|
|
38
|
-
if (storage.isCentralized) {
|
|
39
|
-
this.log('Storage: Super cloud');
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
this.log('Active storage:');
|
|
43
|
-
this.log(` bucket: ${storage.bucket}`);
|
|
44
|
-
if (storage.prefix) {
|
|
45
|
-
this.log(` prefix: ${storage.prefix}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
31
|
if (flags.detail) {
|
|
49
|
-
const { configFileManager } = this.container;
|
|
50
|
-
const current = configFileManager.getCurrentConfigFile();
|
|
51
32
|
const configDir = configFileManager.getConfigDir();
|
|
52
33
|
this.log('\n-----------------(DETAILS)-----------------------');
|
|
53
34
|
if (current) {
|
|
54
|
-
const configs = configFileManager.getConfigsWithNames();
|
|
35
|
+
const configs = await configFileManager.getConfigsWithNames();
|
|
55
36
|
const currentConfig = configs.find((c) => c.file === current);
|
|
56
37
|
const displayName = currentConfig?.name || current;
|
|
57
|
-
const configData = configFileManager.getConfigData(current);
|
|
38
|
+
const configData = await configFileManager.getConfigData(current);
|
|
58
39
|
this.log(`Current account: ${displayName}`);
|
|
59
40
|
this.log(`Configuration file: ${current}`);
|
|
60
41
|
this.log(`Configuration directory: ${configDir}`);
|
|
61
42
|
if (configData) {
|
|
62
43
|
this.log('\nAccount details:');
|
|
63
|
-
if (configData.
|
|
64
|
-
this.log(`
|
|
44
|
+
if (configData.swarmUrl) {
|
|
45
|
+
this.log(` Swarm URL: ${configData.swarmUrl}`);
|
|
65
46
|
}
|
|
66
47
|
else {
|
|
67
|
-
this.log(`
|
|
48
|
+
this.log(` Swarm URL: ${SWARM_URL} (using default)`);
|
|
68
49
|
}
|
|
69
50
|
if (configData.auth?.accessKey) {
|
|
70
51
|
this.log(' Authorization: Configured');
|
|
@@ -72,8 +53,8 @@ export class InfoCommand extends BaseAccountCommand {
|
|
|
72
53
|
else {
|
|
73
54
|
this.log(' Authorization: Unauthorized');
|
|
74
55
|
}
|
|
75
|
-
if (
|
|
76
|
-
this.log(` Account: ${
|
|
56
|
+
if (address) {
|
|
57
|
+
this.log(` Account: ${address}`);
|
|
77
58
|
}
|
|
78
59
|
else {
|
|
79
60
|
this.log(' Account: Not configured');
|
|
@@ -87,10 +68,9 @@ export class InfoCommand extends BaseAccountCommand {
|
|
|
87
68
|
}
|
|
88
69
|
}
|
|
89
70
|
return {
|
|
90
|
-
address
|
|
71
|
+
address,
|
|
91
72
|
balance,
|
|
92
|
-
|
|
93
|
-
wallet: data.internalAddress,
|
|
73
|
+
wallet: walletAddress,
|
|
94
74
|
};
|
|
95
75
|
}
|
|
96
76
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { printTable } from 'console-table-printer';
|
|
2
|
-
import {
|
|
2
|
+
import { SWARM_URL } from '../../constants.js';
|
|
3
3
|
import { BaseCommand } from '../base.js';
|
|
4
4
|
export default class AccountListCommand extends BaseCommand {
|
|
5
5
|
static authenticate = false;
|
|
@@ -13,23 +13,23 @@ export default class AccountListCommand extends BaseCommand {
|
|
|
13
13
|
await this.container.initConfigManager().build();
|
|
14
14
|
}
|
|
15
15
|
async run() {
|
|
16
|
-
const configs = this.configFileManager.getConfigsWithNames();
|
|
16
|
+
const configs = await this.configFileManager.getConfigsWithNames();
|
|
17
17
|
const current = this.configFileManager.getCurrentConfigFile();
|
|
18
18
|
if (configs.length === 0) {
|
|
19
19
|
this.log('No Accounts found');
|
|
20
|
-
this.log('Create a new account with: sp account login --privateKey "<PRIVATE_KEY>" --url "<
|
|
20
|
+
this.log('Create a new account with: sp account login --privateKey "<PRIVATE_KEY>" --url "<SWARM_URL>" --name "Account Name"');
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
const rows = [];
|
|
24
24
|
for (const config of configs) {
|
|
25
25
|
const marker = config.file === current ? '* ' : ' ';
|
|
26
|
-
const configData = this.configFileManager.getConfigData(config.file);
|
|
26
|
+
const configData = await this.configFileManager.getConfigData(config.file);
|
|
27
27
|
const row = {
|
|
28
28
|
account: configData?.account?.address ?? '[not found in config file]',
|
|
29
29
|
current: marker,
|
|
30
30
|
file: config.file,
|
|
31
31
|
name: config.name,
|
|
32
|
-
url: configData?.
|
|
32
|
+
url: configData?.swarmUrl ?? SWARM_URL,
|
|
33
33
|
};
|
|
34
34
|
rows.push(row);
|
|
35
35
|
}
|
|
@@ -38,7 +38,7 @@ export default class AccountListCommand extends BaseCommand {
|
|
|
38
38
|
{ name: 'current', title: 'Current' },
|
|
39
39
|
{ name: 'name', title: 'Config name' },
|
|
40
40
|
{ name: 'account', title: 'Account' },
|
|
41
|
-
{ name: 'url', title: '
|
|
41
|
+
{ name: 'url', title: 'Swarm Url' },
|
|
42
42
|
{ name: 'file', title: 'Configuration File' },
|
|
43
43
|
],
|
|
44
44
|
title: 'Available Accounts',
|
|
@@ -2,6 +2,7 @@ import { BaseAccountCommand } from './base.js';
|
|
|
2
2
|
export default class AccountLoginCommand extends BaseAccountCommand<typeof AccountLoginCommand> {
|
|
3
3
|
static aliases: string[];
|
|
4
4
|
static authenticate: boolean;
|
|
5
|
+
static summary: string;
|
|
5
6
|
static description: string;
|
|
6
7
|
static examples: string[];
|
|
7
8
|
static flags: {
|
|
@@ -9,9 +10,10 @@ export default class AccountLoginCommand extends BaseAccountCommand<typeof Accou
|
|
|
9
10
|
privateKey: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
path: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
authUrl: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
14
|
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
15
|
};
|
|
14
|
-
private
|
|
16
|
+
private accountService;
|
|
15
17
|
private shouldSkipLogin;
|
|
16
18
|
private inputPrompt;
|
|
17
19
|
private checkStorage;
|
|
@@ -26,14 +28,13 @@ export default class AccountLoginCommand extends BaseAccountCommand<typeof Accou
|
|
|
26
28
|
private askName;
|
|
27
29
|
private confirmPrompt;
|
|
28
30
|
private createAccountFromKey;
|
|
29
|
-
private createConfigIfMissing;
|
|
30
31
|
private updateConfigDisplayName;
|
|
31
|
-
private
|
|
32
|
+
private setCurrentAndAuth;
|
|
33
|
+
private applySelectionWithDisplayName;
|
|
34
|
+
private selectMatchedConfig;
|
|
32
35
|
private getPrivateKeyOrGenerate;
|
|
33
36
|
private resolveByName;
|
|
34
|
-
private assertConfigHasAccount;
|
|
35
37
|
private loadConfigFromPath;
|
|
36
|
-
private resolveConfigFileName;
|
|
37
38
|
private resolveByPath;
|
|
38
39
|
private resolveByPrivateKey;
|
|
39
40
|
private resolveConfiguration;
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
1
|
import { Flags } from '@oclif/core';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { PROVIDER_URL } from '../../constants.js';
|
|
2
|
+
import { generatePrivateKey } from 'viem/accounts';
|
|
3
|
+
import { SWARM_URL } from '../../constants.js';
|
|
4
|
+
import { AccountService } from '../../services/account.service.js';
|
|
8
5
|
import { AuthService } from '../../services/auth.service.js';
|
|
9
|
-
import {
|
|
10
|
-
import { getConfigName, getConfigNameFromCredentials, preparePath, readJsonFile, } from '../../utils/helper.js';
|
|
6
|
+
import { getConfigName, preparePath } from '../../utils/helper.js';
|
|
11
7
|
import { promptService } from '../../utils/prompt.service.js';
|
|
12
8
|
import { BaseAccountCommand } from './base.js';
|
|
13
9
|
export default class AccountLoginCommand extends BaseAccountCommand {
|
|
14
10
|
static aliases = ['login'];
|
|
15
11
|
static authenticate = false;
|
|
12
|
+
static summary = 'Login and account creation for SuperProtocol';
|
|
16
13
|
static description = 'Login to SuperProtocol (sign up or sign in).';
|
|
17
14
|
static examples = [
|
|
18
15
|
`<%= config.bin %> <%= command.id %>
|
|
@@ -29,7 +26,11 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
29
26
|
description: 'Path to account(configuration) file to import',
|
|
30
27
|
}),
|
|
31
28
|
url: Flags.string({
|
|
32
|
-
description: '
|
|
29
|
+
description: 'Swarm Api URL',
|
|
30
|
+
hidden: true,
|
|
31
|
+
}),
|
|
32
|
+
authUrl: Flags.string({
|
|
33
|
+
description: 'Auth URL',
|
|
33
34
|
hidden: true,
|
|
34
35
|
}),
|
|
35
36
|
yes: Flags.boolean({
|
|
@@ -38,49 +39,40 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
38
39
|
description: 'Skip questions (generate keys when needed).',
|
|
39
40
|
}),
|
|
40
41
|
};
|
|
41
|
-
|
|
42
|
+
accountService;
|
|
42
43
|
shouldSkipLogin = false;
|
|
43
44
|
async inputPrompt(options) {
|
|
44
45
|
return promptService.text(options);
|
|
45
46
|
}
|
|
46
47
|
async checkStorage() {
|
|
47
|
-
|
|
48
|
-
.initProviderClient({ enableAuth: true, enableCookies: true, rebuild: true })
|
|
49
|
-
.build();
|
|
50
|
-
const { providerClient } = this.container;
|
|
51
|
-
const storageService = new StorageService(providerClient, this.logger);
|
|
52
|
-
if (!(await storageService.hasStorage())) {
|
|
53
|
-
this.logger.info('Requesting default storage');
|
|
54
|
-
const { id, isCentralized, storageType } = await storageService.getCentralizedStorage();
|
|
55
|
-
this.logger.info({ id, isCentralized, storageType }, 'Requested new storage');
|
|
56
|
-
await storageService.saveStorage(id);
|
|
57
|
-
}
|
|
48
|
+
this.logger.info('Storage initialization skipped (mock)');
|
|
58
49
|
}
|
|
59
50
|
async init() {
|
|
60
51
|
await super.init();
|
|
61
52
|
await this.container.initConfigFileManager().build();
|
|
62
|
-
this.
|
|
53
|
+
this.accountService = new AccountService(this.container.configFileManager);
|
|
63
54
|
await this.resolveConfiguration();
|
|
64
55
|
if (this.shouldSkipLogin) {
|
|
65
56
|
return;
|
|
66
57
|
}
|
|
67
58
|
await this.initAccountContext({
|
|
68
59
|
assumeYes: this.flags.yes,
|
|
69
|
-
enableAuth: false,
|
|
70
|
-
enableCookies: true,
|
|
71
60
|
});
|
|
72
61
|
}
|
|
73
62
|
async run() {
|
|
74
63
|
if (this.shouldSkipLogin) {
|
|
75
64
|
return { account: undefined, success: false };
|
|
76
65
|
}
|
|
77
|
-
const { accountManager, configManager
|
|
78
|
-
const authService = new AuthService(accountManager, configManager,
|
|
66
|
+
const { accountManager, configManager } = this.container;
|
|
67
|
+
const authService = new AuthService(accountManager, configManager, this.logger);
|
|
79
68
|
try {
|
|
80
69
|
await authService.auth({ force: true });
|
|
81
70
|
}
|
|
82
71
|
catch (error) {
|
|
83
|
-
|
|
72
|
+
if (error instanceof Error) {
|
|
73
|
+
this.error(error, { exit: 1 });
|
|
74
|
+
}
|
|
75
|
+
this.error(String(error), { exit: 1 });
|
|
84
76
|
}
|
|
85
77
|
try {
|
|
86
78
|
await this.checkStorage();
|
|
@@ -106,52 +98,48 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
106
98
|
}
|
|
107
99
|
createAccountFromKey(privateKey) {
|
|
108
100
|
try {
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
address: account.address,
|
|
112
|
-
privateKey: privateKey,
|
|
113
|
-
};
|
|
101
|
+
return this.accountService.createAccountFromKey(privateKey);
|
|
114
102
|
}
|
|
115
103
|
catch (error) {
|
|
116
|
-
|
|
117
|
-
this.error(
|
|
104
|
+
const message = error instanceof Error && error.message ? error.message : 'Invalid private key provided.';
|
|
105
|
+
this.logger.error({ err: error }, message);
|
|
106
|
+
this.error(message);
|
|
118
107
|
}
|
|
119
108
|
}
|
|
120
|
-
async createConfigIfMissing(configFile, displayName, providerUrl, account) {
|
|
121
|
-
const configPath = path.join(this.configFileManager.getConfigDir(), configFile);
|
|
122
|
-
if (existsSync(configPath)) {
|
|
123
|
-
await this.configFileManager.updateConfigName(configFile, displayName);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
await this.configFileManager.createConfig(configFile, displayName, providerUrl, account);
|
|
127
|
-
this.log(`Created account: ${displayName}`);
|
|
128
|
-
}
|
|
129
109
|
async updateConfigDisplayName(configFile, displayName) {
|
|
130
|
-
|
|
131
|
-
|
|
110
|
+
const result = await this.accountService.updateConfigDisplayName(configFile, displayName);
|
|
111
|
+
if (result.status === 'skipped') {
|
|
112
|
+
return configFile;
|
|
132
113
|
}
|
|
133
|
-
|
|
134
|
-
if (updated) {
|
|
114
|
+
if (result.status === 'updated') {
|
|
135
115
|
this.log(`Updated account name to "${displayName}"`);
|
|
136
|
-
return;
|
|
137
116
|
}
|
|
138
|
-
|
|
117
|
+
else {
|
|
118
|
+
this.log(`Account name: "${displayName}"`);
|
|
119
|
+
}
|
|
120
|
+
return result.configFile;
|
|
139
121
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
122
|
+
async setCurrentAndAuth(configFile, authUrl) {
|
|
123
|
+
await this.accountService.setCurrentConfig(configFile);
|
|
124
|
+
await this.accountService.updateConfigAuthUrl(configFile, authUrl);
|
|
125
|
+
}
|
|
126
|
+
async applySelectionWithDisplayName(configFile, displayName, authUrl) {
|
|
127
|
+
const updatedFile = await this.updateConfigDisplayName(configFile, displayName);
|
|
128
|
+
await this.setCurrentAndAuth(updatedFile, authUrl);
|
|
129
|
+
return updatedFile;
|
|
130
|
+
}
|
|
131
|
+
async selectMatchedConfig(matches) {
|
|
132
|
+
if (matches.length === 1) {
|
|
133
|
+
return matches[0].file;
|
|
134
|
+
}
|
|
135
|
+
if (this.flags.yes) {
|
|
136
|
+
this.log(`Too many matched accounts: ${matches.map((conf) => conf.name).join(',')} Selected first: ${matches[0].name}`);
|
|
137
|
+
return matches[0].file;
|
|
153
138
|
}
|
|
154
|
-
return
|
|
139
|
+
return this.selectPrompt({
|
|
140
|
+
message: 'Multiple accounts found for this private key. Select one:',
|
|
141
|
+
options: matches.map((match) => ({ label: match.name, value: match.file })),
|
|
142
|
+
});
|
|
155
143
|
}
|
|
156
144
|
async getPrivateKeyOrGenerate() {
|
|
157
145
|
const generatedKey = generatePrivateKey();
|
|
@@ -166,12 +154,12 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
166
154
|
const trimmed = value.trim();
|
|
167
155
|
return trimmed || generatedKey;
|
|
168
156
|
}
|
|
169
|
-
async resolveByName(name, privateKey,
|
|
170
|
-
const configs = this.
|
|
157
|
+
async resolveByName(name, privateKey, swarmUrl, authUrl) {
|
|
158
|
+
const configs = await this.accountService.getConfigsWithNames();
|
|
171
159
|
const normalized = name.toLowerCase();
|
|
172
160
|
const existingByName = configs.find((config) => config.name.toLowerCase() === normalized || config.file.toLowerCase() === normalized);
|
|
173
161
|
if (existingByName) {
|
|
174
|
-
await this.
|
|
162
|
+
await this.setCurrentAndAuth(existingByName.file, authUrl);
|
|
175
163
|
return;
|
|
176
164
|
}
|
|
177
165
|
let shouldCreate = true;
|
|
@@ -184,8 +172,11 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
184
172
|
}
|
|
185
173
|
const resolvedKey = privateKey ?? (await this.getPrivateKeyOrGenerate());
|
|
186
174
|
const account = this.createAccountFromKey(resolvedKey);
|
|
187
|
-
const configFile =
|
|
188
|
-
await this.createConfigIfMissing(configFile, name,
|
|
175
|
+
const configFile = getConfigName(name);
|
|
176
|
+
const { created, configFile: createdFile } = await this.accountService.createConfigIfMissing(configFile, name, swarmUrl, account, authUrl);
|
|
177
|
+
if (created) {
|
|
178
|
+
this.log(`Created account: ${name}`);
|
|
179
|
+
}
|
|
189
180
|
let shouldSwitch = true;
|
|
190
181
|
if (!this.flags.yes) {
|
|
191
182
|
shouldSwitch = await this.confirmPrompt(`Switch to account "${name}" now?`, true);
|
|
@@ -194,104 +185,57 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
194
185
|
this.shouldSkipLogin = true;
|
|
195
186
|
return;
|
|
196
187
|
}
|
|
197
|
-
await this.
|
|
198
|
-
}
|
|
199
|
-
assertConfigHasAccount(config) {
|
|
200
|
-
if (!config.account?.privateKey) {
|
|
201
|
-
throw new Error('Account private key is required for import.');
|
|
202
|
-
}
|
|
188
|
+
await this.setCurrentAndAuth(createdFile, authUrl);
|
|
203
189
|
}
|
|
204
190
|
async loadConfigFromPath(configPath) {
|
|
205
191
|
try {
|
|
206
|
-
|
|
207
|
-
if (!Value.Check(cliConfigSchema, config)) {
|
|
208
|
-
throw new Error("Account doesn't match required schema");
|
|
209
|
-
}
|
|
210
|
-
this.assertConfigHasAccount(config);
|
|
211
|
-
return config;
|
|
192
|
+
return await this.accountService.loadConfigFromPath(configPath);
|
|
212
193
|
}
|
|
213
194
|
catch (error) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
resolveConfigFileName(configPath, config, name) {
|
|
218
|
-
if (name) {
|
|
219
|
-
return getConfigName(name);
|
|
220
|
-
}
|
|
221
|
-
if (config.name) {
|
|
222
|
-
return getConfigName(config.name);
|
|
195
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
196
|
+
this.error(`Invalid account file: ${message}`, { exit: 1 });
|
|
223
197
|
}
|
|
224
|
-
const baseName = path.basename(configPath, path.extname(configPath));
|
|
225
|
-
return getConfigName(baseName);
|
|
226
198
|
}
|
|
227
|
-
async resolveByPath(rawPath, name) {
|
|
199
|
+
async resolveByPath(rawPath, name, authUrl) {
|
|
228
200
|
const sourcePath = preparePath(rawPath);
|
|
229
201
|
const config = await this.loadConfigFromPath(sourcePath);
|
|
230
|
-
const targetFile = this.resolveConfigFileName(sourcePath, config, name);
|
|
231
|
-
const targetPath = path.join(this.configFileManager.getConfigDir(), targetFile);
|
|
202
|
+
const targetFile = this.accountService.resolveConfigFileName(sourcePath, config, name);
|
|
232
203
|
const desiredName = name?.trim();
|
|
233
204
|
const privateKey = config.account.privateKey;
|
|
234
|
-
const
|
|
235
|
-
const matches = this.findConfigsByPrivateKey(privateKey,
|
|
205
|
+
const swarmUrl = (config.swarmUrl ?? SWARM_URL).trim();
|
|
206
|
+
const matches = await this.accountService.findConfigsByPrivateKey(privateKey, swarmUrl, true);
|
|
236
207
|
if (matches.length > 0) {
|
|
237
|
-
|
|
238
|
-
if (matches.length > 1) {
|
|
239
|
-
if (this.flags.yes) {
|
|
240
|
-
this.log(`Too many matched accounts: ${matches.map((conf) => conf.name).join(',')} Selected first: ${matches[0].name}`);
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
selectedFile = await this.selectPrompt({
|
|
244
|
-
message: 'Multiple accounts found for this private key. Select one:',
|
|
245
|
-
options: matches.map((match) => ({ label: match.name, value: match.file })),
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
208
|
+
const selectedFile = await this.selectMatchedConfig(matches);
|
|
249
209
|
this.log('Account already exists. Nothing to import.');
|
|
250
|
-
await this.
|
|
251
|
-
await this.configFileManager.setCurrentConfig(selectedFile);
|
|
210
|
+
await this.applySelectionWithDisplayName(selectedFile, desiredName, authUrl);
|
|
252
211
|
return;
|
|
253
212
|
}
|
|
254
|
-
if (
|
|
255
|
-
const existingConfig = this.
|
|
213
|
+
if (await this.accountService.configExists(targetFile)) {
|
|
214
|
+
const existingConfig = await this.accountService.getConfigData(targetFile);
|
|
256
215
|
const existingKey = existingConfig?.account?.privateKey?.trim().toLowerCase();
|
|
257
|
-
const existingUrl = (existingConfig?.
|
|
216
|
+
const existingUrl = (existingConfig?.swarmUrl ?? SWARM_URL).trim();
|
|
258
217
|
const importedKey = privateKey.trim().toLowerCase();
|
|
259
|
-
if (!existingKey || existingKey !== importedKey || existingUrl !==
|
|
218
|
+
if (!existingKey || existingKey !== importedKey || existingUrl !== swarmUrl) {
|
|
260
219
|
this.error(`Account file "${targetFile}" already exists with different credentials. Use a different name or remove the existing file before importing.`, { exit: 1 });
|
|
261
220
|
}
|
|
262
221
|
this.log(`Account already exists. Switching to ${name || targetFile}`);
|
|
263
|
-
await this.
|
|
222
|
+
await this.setCurrentAndAuth(targetFile, authUrl);
|
|
264
223
|
return;
|
|
265
224
|
}
|
|
266
225
|
try {
|
|
267
|
-
const importedFile = await this.
|
|
268
|
-
await this.
|
|
226
|
+
const importedFile = await this.accountService.importConfig(sourcePath, name);
|
|
227
|
+
await this.setCurrentAndAuth(importedFile, authUrl);
|
|
269
228
|
}
|
|
270
229
|
catch (error) {
|
|
271
230
|
this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
|
|
272
231
|
}
|
|
273
232
|
}
|
|
274
|
-
async resolveByPrivateKey(privateKey,
|
|
275
|
-
const matches = this.findConfigsByPrivateKey(privateKey,
|
|
233
|
+
async resolveByPrivateKey(privateKey, swarmUrl, matchSwarmUrl, name, authUrl) {
|
|
234
|
+
const matches = await this.accountService.findConfigsByPrivateKey(privateKey, swarmUrl, matchSwarmUrl);
|
|
276
235
|
const desiredName = name?.trim();
|
|
277
|
-
if (matches.length
|
|
278
|
-
await this.
|
|
279
|
-
await this.
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
if (matches.length > 1) {
|
|
283
|
-
if (this.flags.yes) {
|
|
284
|
-
this.log(`Too many matched accounts: ${matches.map((conf) => conf.name).join(',')} Selected first: ${matches[0].name}`);
|
|
285
|
-
await this.updateConfigDisplayName(matches[0].file, desiredName);
|
|
286
|
-
await this.configFileManager.setCurrentConfig(matches[0].file);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
const selected = await this.selectPrompt({
|
|
290
|
-
message: 'Multiple accounts found for this private key. Select one:',
|
|
291
|
-
options: matches.map((match) => ({ label: match.name, value: match.file })),
|
|
292
|
-
});
|
|
293
|
-
await this.updateConfigDisplayName(selected, desiredName);
|
|
294
|
-
await this.configFileManager.setCurrentConfig(selected);
|
|
236
|
+
if (matches.length > 0) {
|
|
237
|
+
const selectedFile = await this.selectMatchedConfig(matches);
|
|
238
|
+
await this.applySelectionWithDisplayName(selectedFile, desiredName, authUrl);
|
|
295
239
|
return;
|
|
296
240
|
}
|
|
297
241
|
let shouldCreate = true;
|
|
@@ -305,8 +249,11 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
305
249
|
const account = this.createAccountFromKey(privateKey);
|
|
306
250
|
const suggestedName = desiredName || account.address;
|
|
307
251
|
const displayName = this.flags.yes ? suggestedName : await this.askName(suggestedName);
|
|
308
|
-
const configFile =
|
|
309
|
-
await this.createConfigIfMissing(configFile, displayName,
|
|
252
|
+
const configFile = getConfigName(displayName);
|
|
253
|
+
const { created, configFile: createdFile } = await this.accountService.createConfigIfMissing(configFile, displayName, swarmUrl, account, authUrl);
|
|
254
|
+
if (created) {
|
|
255
|
+
this.log(`Created account: ${displayName}`);
|
|
256
|
+
}
|
|
310
257
|
let shouldSwitch = true;
|
|
311
258
|
if (!this.flags.yes) {
|
|
312
259
|
shouldSwitch = await this.confirmPrompt(`Switch to account "${displayName}" now?`, true);
|
|
@@ -315,7 +262,7 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
315
262
|
this.shouldSkipLogin = true;
|
|
316
263
|
return;
|
|
317
264
|
}
|
|
318
|
-
await this.
|
|
265
|
+
await this.setCurrentAndAuth(createdFile, authUrl);
|
|
319
266
|
}
|
|
320
267
|
async resolveConfiguration() {
|
|
321
268
|
const name = this.flags.name?.trim();
|
|
@@ -326,19 +273,23 @@ export default class AccountLoginCommand extends BaseAccountCommand {
|
|
|
326
273
|
const privateKey = this.flags.privateKey?.trim();
|
|
327
274
|
const url = this.flags.url?.trim();
|
|
328
275
|
if (url !== undefined && !url) {
|
|
329
|
-
this.error('
|
|
276
|
+
this.error('Swarm URL cannot be empty.', { exit: 1 });
|
|
277
|
+
}
|
|
278
|
+
const authUrl = this.flags.authUrl?.trim();
|
|
279
|
+
if (authUrl !== undefined && !authUrl) {
|
|
280
|
+
this.error('Auth URL cannot be empty.', { exit: 1 });
|
|
330
281
|
}
|
|
331
|
-
const
|
|
282
|
+
const swarmUrl = (url || SWARM_URL).trim();
|
|
332
283
|
if (configPath) {
|
|
333
|
-
await this.resolveByPath(configPath, name);
|
|
284
|
+
await this.resolveByPath(configPath, name, authUrl);
|
|
334
285
|
return;
|
|
335
286
|
}
|
|
336
287
|
if (privateKey) {
|
|
337
|
-
await this.resolveByPrivateKey(privateKey,
|
|
288
|
+
await this.resolveByPrivateKey(privateKey, swarmUrl, Boolean(url), name, authUrl);
|
|
338
289
|
return;
|
|
339
290
|
}
|
|
340
291
|
if (name) {
|
|
341
|
-
await this.resolveByName(name, privateKey,
|
|
292
|
+
await this.resolveByName(name, privateKey, swarmUrl, authUrl);
|
|
342
293
|
return;
|
|
343
294
|
}
|
|
344
295
|
}
|
|
@@ -20,7 +20,7 @@ export default class AccountSwitchCommand extends BaseAccountCommand {
|
|
|
20
20
|
}
|
|
21
21
|
async run() {
|
|
22
22
|
const { name } = this.flags;
|
|
23
|
-
const configs = this.configFileManager.getConfigsWithNames();
|
|
23
|
+
const configs = await this.configFileManager.getConfigsWithNames();
|
|
24
24
|
const currentConfig = this.configFileManager.getCurrentConfigFile();
|
|
25
25
|
if (configs.length === 0) {
|
|
26
26
|
this.log('No accounts found');
|
|
@@ -30,7 +30,7 @@ export default class AccountSwitchCommand extends BaseAccountCommand {
|
|
|
30
30
|
let selected;
|
|
31
31
|
if (name) {
|
|
32
32
|
try {
|
|
33
|
-
const config = this.configFileManager.getConfigWithName(name);
|
|
33
|
+
const config = await this.configFileManager.getConfigWithName(name);
|
|
34
34
|
selected = config.file;
|
|
35
35
|
}
|
|
36
36
|
catch {
|