@super-protocol/sp-cli 0.0.2 → 0.0.3

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.
Files changed (59) hide show
  1. package/README.md +217 -263
  2. package/bin/dev.js +1 -1
  3. package/dist/commands/account/get-sppi.d.ts +8 -0
  4. package/dist/commands/account/get-sppi.js +23 -0
  5. package/dist/commands/account/info.d.ts +22 -0
  6. package/dist/commands/account/info.js +46 -0
  7. package/dist/commands/auth/login.d.ts +6 -11
  8. package/dist/commands/auth/login.js +28 -76
  9. package/dist/commands/base.d.ts +2 -4
  10. package/dist/commands/base.js +8 -10
  11. package/dist/commands/config/add.js +1 -12
  12. package/dist/commands/config/base.d.ts +5 -3
  13. package/dist/commands/config/base.js +30 -14
  14. package/dist/commands/config/create.js +1 -11
  15. package/dist/commands/config/list.js +20 -19
  16. package/dist/commands/config/use.js +5 -3
  17. package/dist/commands/files/download.d.ts +15 -0
  18. package/dist/commands/files/download.js +55 -0
  19. package/dist/commands/files/upload.d.ts +18 -0
  20. package/dist/commands/files/upload.js +79 -0
  21. package/dist/commands/storage/base.d.ts +13 -0
  22. package/dist/commands/storage/base.js +125 -0
  23. package/dist/commands/storage/create.d.ts +11 -0
  24. package/dist/commands/storage/create.js +53 -0
  25. package/dist/commands/storage/select.d.ts +9 -0
  26. package/dist/commands/storage/select.js +40 -0
  27. package/dist/commands/storage/show.d.ts +17 -0
  28. package/dist/commands/storage/show.js +36 -0
  29. package/dist/commands/storage/update.d.ts +14 -0
  30. package/dist/commands/storage/update.js +187 -0
  31. package/dist/commands/workflows/extend-lease.d.ts +17 -0
  32. package/dist/commands/workflows/extend-lease.js +94 -0
  33. package/dist/config/config-file.schema.d.ts +4 -4
  34. package/dist/config/config-file.schema.js +1 -1
  35. package/dist/config/config.schema.d.ts +25 -15
  36. package/dist/config/config.schema.js +7 -10
  37. package/dist/constants.d.ts +5 -0
  38. package/dist/constants.js +5 -0
  39. package/dist/errors.d.ts +2 -0
  40. package/dist/errors.js +2 -0
  41. package/dist/hooks/finally/shutdown-blockchain.d.ts +3 -0
  42. package/dist/hooks/finally/shutdown-blockchain.js +8 -0
  43. package/dist/lib/container.d.ts +7 -7
  44. package/dist/lib/container.js +48 -26
  45. package/dist/managers/account-manager.d.ts +1 -0
  46. package/dist/managers/account-manager.js +27 -13
  47. package/dist/managers/config-file-manager.d.ts +2 -2
  48. package/dist/managers/config-file-manager.js +29 -12
  49. package/dist/middlewares/auth-middleware.js +5 -1
  50. package/dist/services/auth.service.d.ts +24 -0
  51. package/dist/services/auth.service.js +93 -0
  52. package/dist/services/storage.service.d.ts +73 -0
  53. package/dist/services/storage.service.js +351 -0
  54. package/dist/utils/helper.d.ts +6 -0
  55. package/dist/utils/helper.js +23 -0
  56. package/dist/utils/progress.d.ts +8 -0
  57. package/dist/utils/progress.js +35 -0
  58. package/oclif.manifest.json +455 -179
  59. package/package.json +18 -8
package/bin/dev.js CHANGED
@@ -2,6 +2,6 @@
2
2
  import { execute } from '@oclif/core';
3
3
 
4
4
  await execute({
5
- development: true,
5
+ development: Boolean(process.env.SP_LOG_LEVEL),
6
6
  dir: import.meta.url,
7
7
  });
@@ -0,0 +1,8 @@
1
+ import { BaseCommand } from '../base.js';
2
+ export default class AccountGetSppi extends BaseCommand<typeof AccountGetSppi> {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<{
6
+ tokens: string;
7
+ }>;
8
+ }
@@ -0,0 +1,23 @@
1
+ import { formatEther } from 'viem';
2
+ import { BaseCommand } from '../base.js';
3
+ export default class AccountGetSppi extends BaseCommand {
4
+ static description = 'Get SPPI (Super Protocol incentive tokens) ';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %>',
7
+ ];
8
+ async run() {
9
+ const { providerClient } = await this.container
10
+ .initConfigFileManager()
11
+ .initConfigManager()
12
+ .initAccountManager()
13
+ .initProviderClient()
14
+ .build();
15
+ const { data, error } = await providerClient.POST('/api/faucet/request-tokens');
16
+ if (error) {
17
+ this.error(`Request tokens failed. Reason ${error.message}`);
18
+ }
19
+ const tokens = formatEther(BigInt(data.amount || '0'));
20
+ this.log(`Requested tokens: ${tokens} SPPI`);
21
+ return { tokens };
22
+ }
23
+ }
@@ -0,0 +1,22 @@
1
+ import { BaseCommand } from '../base.js';
2
+ export declare class InfoCommand extends BaseCommand<typeof InfoCommand> {
3
+ static description: string;
4
+ init(): Promise<void>;
5
+ run(): Promise<{
6
+ address: string;
7
+ balance: string;
8
+ storage: {
9
+ bucket: string;
10
+ createdAt: string;
11
+ id: string;
12
+ isCentralized: boolean;
13
+ prefix: string;
14
+ s3Credentials?: import("@super-protocol/provider-client").components["schemas"]["S3CredentialsResponseDto"];
15
+ storageType: import("@super-protocol/provider-client").components["schemas"]["StorageType"];
16
+ storjCredentials?: import("@super-protocol/provider-client").components["schemas"]["StorJCredentialsResponseDto"];
17
+ updatedAt: string;
18
+ userId: string;
19
+ };
20
+ wallet: string;
21
+ }>;
22
+ }
@@ -0,0 +1,46 @@
1
+ import { formatEther } from 'viem';
2
+ import { StorageService } from '../../services/storage.service.js';
3
+ import { BaseCommand } from '../base.js';
4
+ export class InfoCommand extends BaseCommand {
5
+ static description = 'Information about current authorized user';
6
+ async init() {
7
+ await super.init();
8
+ await this.container.initProviderClient().initAccountManager().initConfigManager().build();
9
+ }
10
+ async run() {
11
+ const { providerClient } = this.container;
12
+ const storageService = new StorageService(providerClient, this.logger);
13
+ const { data, error } = await providerClient.GET('/api/auth/me');
14
+ if (error) {
15
+ this.error(error.message);
16
+ }
17
+ if (!data) {
18
+ this.error('Failed to retrieve account information');
19
+ }
20
+ const { data: wallet } = await providerClient.GET('/api/users/me/wallet');
21
+ if (!wallet) {
22
+ this.error('Failed to retrieve wallet information');
23
+ }
24
+ const storage = await storageService.getCurrentStorage();
25
+ const balance = formatEther(BigInt(wallet?.teeBalance || '0'));
26
+ this.log(`Login: ${data.address}`);
27
+ this.log(`Super Wallet: ${data.internalAddress}`);
28
+ this.log(`Balance: ${balance} SPPI`);
29
+ if (storage.isCentralized) {
30
+ this.log('Storage: Super cloud');
31
+ }
32
+ else {
33
+ this.log('Active storage:');
34
+ this.log(` bucket: ${storage.bucket}`);
35
+ if (storage.prefix) {
36
+ this.log(` prefix: ${storage.prefix}`);
37
+ }
38
+ }
39
+ return {
40
+ address: data.address,
41
+ balance,
42
+ storage,
43
+ wallet: data.internalAddress,
44
+ };
45
+ }
46
+ }
@@ -1,17 +1,12 @@
1
1
  import { BaseCommand } from '../base.js';
2
2
  export default class SpLogin extends BaseCommand<typeof SpLogin> {
3
+ static aliases: string[];
3
4
  static description: string;
4
5
  static examples: string[];
5
- getTokens(nonce: string): Promise<void>;
6
- getUserNonce(address: string): Promise<{
7
- error: {
8
- message: string;
9
- statusCode: number;
10
- } | undefined;
11
- user: {
12
- nonce?: string;
13
- } | undefined;
14
- }>;
6
+ checkStorage(): Promise<void>;
15
7
  init(): Promise<void>;
16
- run(): Promise<void>;
8
+ run(): Promise<{
9
+ account: string;
10
+ success: boolean;
11
+ }>;
17
12
  }
@@ -1,49 +1,22 @@
1
- import { ux } from '@oclif/core';
1
+ import { AuthService } from '../../services/auth.service.js';
2
+ import { StorageService } from '../../services/storage.service.js';
2
3
  import { BaseCommand } from '../base.js';
3
4
  export default class SpLogin extends BaseCommand {
4
- static description = 'Authorization';
5
+ static aliases = ['login'];
6
+ static description = 'Login to SuperProtocol (sign up or sign in).';
5
7
  static examples = [
6
8
  `<%= config.bin %> <%= command.id %>
7
9
  `,
8
10
  ];
9
- async getTokens(nonce) {
10
- const { accountManager, configManager, providerClient } = this.container;
11
- const signature = await accountManager.createSign(nonce);
12
- const { data: tokenResponse, error, } = await providerClient.POST('/api/auth/token', {
13
- body: {
14
- address: accountManager.getAddress(),
15
- provider: 'sp-cli',
16
- signature,
17
- },
18
- });
19
- if (error) {
20
- this.logger.error({ err: error }, 'Token exchange failed');
21
- ux.error('Authorization failed please try again later.');
22
- }
23
- const { accessToken } = tokenResponse || {};
24
- if (!accessToken) {
25
- this.logger.error({ response: tokenResponse }, 'Unexpected token response');
26
- ux.error('Provider returned an unexpected token response.');
27
- }
28
- await configManager.setCredentials({ accessKey: accessToken });
29
- this.log('Authorization successful');
30
- }
31
- async getUserNonce(address) {
11
+ async checkStorage() {
12
+ await this.container.initProviderClient({ enableAuth: true, enableCookies: true, rebuild: true }).build();
32
13
  const { providerClient } = this.container;
33
- try {
34
- const { data, error } = await providerClient.GET('/api/users/nonce/{address}', {
35
- params: {
36
- path: {
37
- address,
38
- },
39
- },
40
- });
41
- this.logger.debug({ data, error }, 'Getting user nonce');
42
- return { error, user: data };
43
- }
44
- catch (error) {
45
- this.logger.error({ err: error }, 'Error request nonce');
46
- ux.error('Connection failure, please try again later');
14
+ const storageService = new StorageService(providerClient, this.logger);
15
+ if (!await storageService.hasStorage()) {
16
+ this.logger.info('Requesting default storage');
17
+ const { id, isCentralized, storageType } = await storageService.getCentralizedStorage();
18
+ this.logger.info({ id, isCentralized, storageType }, 'Requested new storage');
19
+ await storageService.saveStorage(id);
47
20
  }
48
21
  }
49
22
  async init() {
@@ -51,48 +24,27 @@ export default class SpLogin extends BaseCommand {
51
24
  await this.container
52
25
  .initConfigManager()
53
26
  .initAccountManager()
54
- .initProviderClient({ enableAuth: false })
27
+ .initProviderClient({ enableAuth: false, enableCookies: true })
55
28
  .build();
56
29
  }
57
30
  async run() {
58
- const { accountManager, providerClient } = this.container;
59
- const address = accountManager.getAddress();
60
- const { error: nonceError, user } = await this.getUserNonce(address);
61
- if (nonceError && nonceError.statusCode === 404) {
62
- this.logger.debug('Nonce error call sign up');
63
- const { data: nonceResponse, error: signUpError } = await providerClient.POST('/api/auth/sign-up', {
64
- body: {
65
- address,
66
- },
67
- });
68
- if (signUpError && signUpError.statusCode === 409) {
69
- this.logger.debug({ signUpError }, 'Error signing up');
70
- const { error: nonceError, user } = await this.getUserNonce(address);
71
- this.logger.debug({ nonceError, user }, 'Requesting nonce again');
72
- if (user && user.nonce)
73
- await this.getTokens(user.nonce);
74
- else
75
- ux.error('User exists but nonce is unavailable. Please try again or contact support.');
76
- }
77
- else if (signUpError) {
78
- this.logger.error({ signUpError }, 'Sign-up failed');
79
- ux.error('Sign-up failed. Please try again later.');
80
- }
81
- else {
82
- const nonce = nonceResponse?.nonce;
83
- if (!nonce) {
84
- this.logger.error({ response: nonceResponse }, 'Unexpected sign-up response');
85
- ux.error('Provider did not return a nonce.');
86
- }
87
- await this.getTokens(nonce);
88
- }
31
+ const { accountManager, configManager, providerClient } = this.container;
32
+ const authService = new AuthService(accountManager, configManager, providerClient, this.logger);
33
+ try {
34
+ await authService.auth();
35
+ }
36
+ catch (error) {
37
+ this.error(error, { exit: 1 });
89
38
  }
90
- else if (user && user.nonce) {
91
- this.logger.debug({ user }, 'Requesting for existed user');
92
- await this.getTokens(user.nonce);
39
+ try {
40
+ await this.checkStorage();
93
41
  }
94
- else {
95
- ux.error('Unable to retrieve authentication nonce. Please try again later or contact support if the issue persists.');
42
+ catch (error) {
43
+ this.logger.error({ err: error }, 'Storage initialization failed');
44
+ this.warn('Storage initialization failed. You can set up storage later using "sp storage create" or "sp storage select".');
96
45
  }
46
+ const account = accountManager.getAddress();
47
+ this.log(`Logged in with account ${account}`);
48
+ return { account, success: true };
97
49
  }
98
50
  }
@@ -4,15 +4,13 @@ import { AppContainer } from '../lib/container.js';
4
4
  export type CommandFlags<T extends typeof Command> = Interfaces.InferredFlags<T['flags'] & typeof BaseCommand['baseFlags']>;
5
5
  export type CommandArgs<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
6
6
  export declare abstract class BaseCommand<T extends typeof Command> extends Command {
7
- static baseFlags: {
8
- config: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
9
- url: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
10
- };
7
+ static baseFlags: typeof Command.baseFlags;
11
8
  static enableJsonFlag: boolean;
12
9
  protected args: CommandArgs<T>;
13
10
  protected container: AppContainer;
14
11
  protected flags: CommandFlags<T>;
15
12
  protected logger: pino.BaseLogger;
16
13
  constructor(argv: string[], config: Config);
14
+ protected ensurePromptValue<T>(value: symbol | T, errorMessage?: string): T;
17
15
  init(): Promise<void>;
18
16
  }
@@ -1,3 +1,4 @@
1
+ import { isCancel } from '@clack/prompts';
1
2
  import { Command, Flags, } from '@oclif/core';
2
3
  import { AppContainer } from '../lib/container.js';
3
4
  import logger from '../logger.js';
@@ -8,11 +9,6 @@ export class BaseCommand extends Command {
8
9
  required: false,
9
10
  summary: 'Specify config file.',
10
11
  }),
11
- url: Flags.string({
12
- helpGroup: 'GLOBAL',
13
- required: false,
14
- summary: 'Specify provider base URL.',
15
- }),
16
12
  };
17
13
  static enableJsonFlag = true;
18
14
  args;
@@ -23,14 +19,17 @@ export class BaseCommand extends Command {
23
19
  super(argv, config);
24
20
  this.logger = logger.getPino();
25
21
  }
22
+ ensurePromptValue(value, errorMessage = 'Operation cancelled.') {
23
+ if (isCancel(value)) {
24
+ this.error(errorMessage);
25
+ }
26
+ return value;
27
+ }
26
28
  async init() {
27
29
  await super.init();
28
30
  const { args, flags } = await this.parse({
29
31
  args: this.ctor.args,
30
- baseFlags: {
31
- ...BaseCommand.baseFlags,
32
- ...super.ctor.baseFlags,
33
- },
32
+ baseFlags: super.ctor.baseFlags,
34
33
  enableJsonFlag: this.ctor.enableJsonFlag,
35
34
  flags: this.ctor.flags,
36
35
  strict: this.ctor.strict,
@@ -39,7 +38,6 @@ export class BaseCommand extends Command {
39
38
  this.args = args;
40
39
  this.container = AppContainer.container.setupRuntimeConfig({
41
40
  configFile: flags.config,
42
- url: flags.url,
43
41
  });
44
42
  }
45
43
  }
@@ -48,7 +48,6 @@ export default class ConfigAdd extends BaseConfigCommand {
48
48
  if (!existsSync(testPath)) {
49
49
  return 'File does not exist';
50
50
  }
51
- return true;
52
51
  },
53
52
  });
54
53
  }
@@ -65,17 +64,7 @@ export default class ConfigAdd extends BaseConfigCommand {
65
64
  const displayName = importedConfig?.name || importedFileName;
66
65
  this.log(`Successfully imported configuration: ${displayName}`);
67
66
  this.log(`Configuration file: ${importedFileName}`);
68
- const shouldSwitch = this.flags.yes || await this.selectPrompt({
69
- choices: [
70
- { name: 'Yes', value: true },
71
- { name: 'No', value: false },
72
- ],
73
- message: 'Switch to this configuration now?',
74
- });
75
- if (shouldSwitch) {
76
- await this.configFileManager.setCurrentConfig(importedFileName);
77
- this.log(`Switched to configuration: ${displayName}`);
78
- }
67
+ await this.switchToNewConfig(importedFileName, displayName, this.flags.yes);
79
68
  }
80
69
  catch (error) {
81
70
  this.error(`Failed to import configuration: ${error instanceof Error ? error.message : String(error)}`);
@@ -1,14 +1,16 @@
1
1
  import type { Command } from '@oclif/core';
2
- import { input, select } from '@inquirer/prompts';
2
+ import { select, text } from '@clack/prompts';
3
3
  import type { ConfigFileManager } from '../../managers/config-file-manager.js';
4
4
  import { BaseCommand } from '../base.js';
5
- type InputOptions = Parameters<typeof input>[0];
5
+ type TextOptions = Parameters<typeof text>[0];
6
6
  type SelectOptions<T> = Parameters<typeof select<T>>[0];
7
7
  export declare abstract class BaseConfigCommand<T extends typeof Command> extends BaseCommand<T> {
8
+ static baseFlags: {};
8
9
  protected configFileManager: ConfigFileManager;
9
10
  protected displayCurrentConfig(): void;
10
11
  init(): Promise<void>;
11
- protected inputPrompt(options: InputOptions): Promise<string>;
12
+ protected inputPrompt(options: TextOptions): Promise<string>;
12
13
  protected selectPrompt<Value>(options: SelectOptions<Value>): Promise<Value>;
14
+ protected switchToNewConfig(configFile: string, displayName: string, yes: boolean): Promise<void>;
13
15
  }
14
16
  export {};
@@ -1,6 +1,8 @@
1
- import { input, select } from '@inquirer/prompts';
1
+ import { select, text } from '@clack/prompts';
2
+ import { PROVIDER_URL } from '../../constants.js';
2
3
  import { BaseCommand } from '../base.js';
3
4
  export class BaseConfigCommand extends BaseCommand {
5
+ static baseFlags = {};
4
6
  configFileManager;
5
7
  displayCurrentConfig() {
6
8
  const current = this.configFileManager.getCurrentConfigFile();
@@ -20,25 +22,19 @@ export class BaseConfigCommand extends BaseCommand {
20
22
  this.log(` Provider URL: ${configData.providerUrl}`);
21
23
  }
22
24
  else {
23
- this.log(' Provider URL: (using default)');
25
+ this.log(` Provider URL: ${PROVIDER_URL} (using default)`);
24
26
  }
25
27
  if (configData.auth?.accessKey) {
26
- this.log(' Authorization: Configured');
28
+ this.log(' Authorization: Configured');
27
29
  }
28
30
  else {
29
- this.log(' Authorization: ✗ Not configured');
31
+ this.log(' Authorization: Unauthorized');
30
32
  }
31
33
  if (configData.account?.address) {
32
- this.log(` Account: ${configData.account.address}`);
34
+ this.log(` Account: ${configData.account.address}`);
33
35
  }
34
36
  else {
35
- this.log(' Account: Not configured');
36
- }
37
- if (configData.cookies) {
38
- this.log(' Cookies: ✓ Stored');
39
- }
40
- else {
41
- this.log(' Cookies: ✗ None');
37
+ this.log(' Account: Not configured');
42
38
  }
43
39
  }
44
40
  }
@@ -54,9 +50,29 @@ export class BaseConfigCommand extends BaseCommand {
54
50
  this.configFileManager = this.container.configFileManager;
55
51
  }
56
52
  async inputPrompt(options) {
57
- return input(options);
53
+ const result = await text(options);
54
+ return this.ensurePromptValue(result);
58
55
  }
59
56
  async selectPrompt(options) {
60
- return select(options);
57
+ const result = await select(options);
58
+ return this.ensurePromptValue(result);
59
+ }
60
+ async switchToNewConfig(configFile, displayName, yes) {
61
+ const shouldSwitch = yes || await this.selectPrompt({
62
+ message: 'Switch to this configuration now?',
63
+ options: [
64
+ { label: 'Yes', value: true },
65
+ { label: 'No', value: false },
66
+ ],
67
+ });
68
+ if (shouldSwitch) {
69
+ await this.configFileManager.setCurrentConfig(configFile);
70
+ this.log(`Switched to configuration: ${displayName}`);
71
+ await this.container
72
+ .initConfigFileManager(true)
73
+ .initConfigManager(true)
74
+ .initAccountManager(true)
75
+ .build();
76
+ }
61
77
  }
62
78
  }
@@ -32,17 +32,7 @@ export default class ConfigCreate extends BaseConfigCommand {
32
32
  if (url) {
33
33
  this.log(`Provider URL: ${url}`);
34
34
  }
35
- const shouldSwitch = yes || await this.selectPrompt({
36
- choices: [
37
- { name: 'Yes', value: true },
38
- { name: 'No', value: false },
39
- ],
40
- message: 'Switch to this configuration now?',
41
- });
42
- if (shouldSwitch) {
43
- await this.configFileManager.setCurrentConfig(fileName);
44
- this.log(`Switched to configuration: ${name}`);
45
- }
35
+ await this.switchToNewConfig(fileName, name, yes);
46
36
  }
47
37
  catch (error) {
48
38
  this.error(`Failed to create configuration: ${error instanceof Error ? error.message : String(error)}`);
@@ -1,3 +1,5 @@
1
+ import { printTable } from 'console-table-printer';
2
+ import { PROVIDER_URL } from '../../constants.js';
1
3
  import { BaseConfigCommand } from './base.js';
2
4
  export default class ConfigList extends BaseConfigCommand {
3
5
  static description = 'List all configurations';
@@ -12,28 +14,27 @@ export default class ConfigList extends BaseConfigCommand {
12
14
  this.log('Create a new configuration with: sp config create --name "Config Name"');
13
15
  return;
14
16
  }
15
- this.log('Available configurations:\n');
17
+ const rows = [];
16
18
  for (const config of configs) {
17
19
  const marker = config.file === current ? '* ' : ' ';
18
20
  const configData = this.configFileManager.getConfigData(config.file);
19
- let statusInfo = '';
20
- if (configData) {
21
- const parts = [];
22
- if (configData.providerUrl) {
23
- parts.push(`URL: ${configData.providerUrl}`);
24
- }
25
- if (configData.auth) {
26
- parts.push('Auth: ✓');
27
- }
28
- if (configData.account) {
29
- parts.push('Account: ✓');
30
- }
31
- if (parts.length > 0) {
32
- statusInfo = ` | ${parts.join(', ')}`;
33
- }
34
- }
35
- this.log(`${marker}${config.name}${statusInfo}`);
36
- this.log(` File: ${config.file}`);
21
+ const row = {
22
+ account: configData?.account?.address ?? '[not found in config file]',
23
+ current: marker,
24
+ file: config.file,
25
+ name: config.name,
26
+ url: configData?.providerUrl ?? PROVIDER_URL,
27
+ };
28
+ rows.push(row);
37
29
  }
30
+ printTable(rows, {
31
+ columns: [
32
+ { name: 'current', title: 'Current' },
33
+ { name: 'name', title: 'Config name' },
34
+ { name: 'account', title: 'Account' },
35
+ { name: 'url', title: 'Provider Url' },
36
+ { name: 'file', title: 'Configuration File' },
37
+ ], title: 'Available configurations',
38
+ });
38
39
  }
39
40
  }
@@ -6,17 +6,19 @@ export default class ConfigUse extends BaseConfigCommand {
6
6
  ];
7
7
  async run() {
8
8
  const configs = this.configFileManager.getConfigsWithNames();
9
+ const currentConfig = this.configFileManager.getCurrentConfigFile();
9
10
  if (configs.length === 0) {
10
11
  this.log('No configurations found');
11
12
  this.log('Create a new configuration with: sp config create --name "Config Name"');
12
13
  return;
13
14
  }
14
15
  const selected = await this.selectPrompt({
15
- choices: configs.map(config => ({
16
- name: config.name ?? config.file,
16
+ initialValue: currentConfig,
17
+ message: 'Select a configuration:',
18
+ options: configs.map(config => ({
19
+ label: config.name ?? config.file,
17
20
  value: config.file,
18
21
  })),
19
- message: 'Select a configuration:',
20
22
  });
21
23
  await this.configFileManager.setCurrentConfig(selected);
22
24
  const selectedConfig = configs.find(c => c.file === selected);
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../base.js';
2
+ export default class FilesDownload extends BaseCommand<typeof FilesDownload> {
3
+ static args: {
4
+ resourceFile: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ localDirectory: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ 'maximum-concurrent': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ static help: string;
13
+ init(): Promise<void>;
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,55 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { StorageService } from '../../services/storage.service.js';
3
+ import { createProgressPrinter } from '../../utils/progress.js';
4
+ import { BaseCommand } from '../base.js';
5
+ export default class FilesDownload extends BaseCommand {
6
+ static args = {
7
+ resourceFile: Args.string({ description: 'Path to a resource file', required: true }),
8
+ // eslint-disable-next-line perfectionist/sort-objects
9
+ localDirectory: Args.string({ description: 'Path to save downloaded file', required: true }),
10
+ };
11
+ static description = 'Download file or directory described in resource file';
12
+ static examples = [
13
+ '<%= config.bin %> <%= command.id %> ./resource.json ./pathToDownload ',
14
+ ];
15
+ static flags = {
16
+ 'maximum-concurrent': Flags.integer({
17
+ default: 1, description: 'Maximum concurrent pieces to download at once per transfer', max: 1000, min: 1,
18
+ }),
19
+ };
20
+ static help = 'Download and decrypt a file from the remote storage to <localPath> using resource file <resourcePath>';
21
+ async init() {
22
+ await super.init();
23
+ await this.container.initProviderClient({ enableAuth: false }).initConfigManager().build();
24
+ }
25
+ async run() {
26
+ const { args, flags } = await this.parse(FilesDownload);
27
+ const { providerClient } = this.container;
28
+ const storageService = new StorageService(providerClient, this.logger);
29
+ const progress = createProgressPrinter({
30
+ action: 'Download',
31
+ start: 'Downloading: ',
32
+ });
33
+ try {
34
+ await storageService.download({
35
+ downloadPath: args.localDirectory,
36
+ maximumConcurrent: flags['maximum-concurrent'],
37
+ resourcePath: args.resourceFile,
38
+ }, ({ current, key, total }) => {
39
+ progress.advance(key, current / total * 100, `Downloading: ${key} [${current}/${total}]`);
40
+ });
41
+ }
42
+ catch (error) {
43
+ let reason = '';
44
+ this.logger.error({ err: error }, 'Error trying download');
45
+ if (error instanceof Error) {
46
+ reason = error.message;
47
+ }
48
+ this.error(`Download aborted. Reason: ${reason}`);
49
+ }
50
+ finally {
51
+ progress.finish();
52
+ }
53
+ this.log('Download successfully completed');
54
+ }
55
+ }
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../base.js';
2
+ export default class FilesUpload extends BaseCommand<typeof FilesUpload> {
3
+ static args: {
4
+ path: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ filename: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'maximum-concurrent': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
11
+ metadata: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'skip-encryption': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ sync: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ };
16
+ init(): Promise<void>;
17
+ run(): Promise<void>;
18
+ }