@super-protocol/sp-cli 0.0.8 → 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.
Files changed (95) hide show
  1. package/README.md +200 -167
  2. package/dist/commands/account/base.d.ts +3 -4
  3. package/dist/commands/account/base.js +12 -9
  4. package/dist/commands/account/forget.d.ts +1 -1
  5. package/dist/commands/account/forget.js +66 -17
  6. package/dist/commands/account/get-sppi.js +7 -11
  7. package/dist/commands/account/info.d.ts +1 -13
  8. package/dist/commands/account/info.js +25 -45
  9. package/dist/commands/account/list.js +6 -6
  10. package/dist/commands/account/login.d.ts +10 -3
  11. package/dist/commands/account/login.js +143 -87
  12. package/dist/commands/account/switch.d.ts +3 -0
  13. package/dist/commands/account/switch.js +31 -11
  14. package/dist/commands/assets/base.d.ts +39 -0
  15. package/dist/commands/assets/base.js +217 -0
  16. package/dist/commands/assets/create.d.ts +41 -0
  17. package/dist/commands/assets/create.js +277 -0
  18. package/dist/commands/assets/delete.d.ts +14 -0
  19. package/dist/commands/assets/delete.js +69 -0
  20. package/dist/commands/assets/get.d.ts +14 -0
  21. package/dist/commands/assets/get.js +79 -0
  22. package/dist/commands/assets/list.d.ts +7 -0
  23. package/dist/commands/assets/list.js +33 -0
  24. package/dist/commands/assets/update.d.ts +44 -0
  25. package/dist/commands/assets/update.js +321 -0
  26. package/dist/commands/base.d.ts +1 -0
  27. package/dist/commands/base.js +6 -0
  28. package/dist/config/config.schema.d.ts +2 -11
  29. package/dist/config/config.schema.js +2 -7
  30. package/dist/constants.d.ts +3 -3
  31. package/dist/constants.js +3 -3
  32. package/dist/errors.d.ts +0 -2
  33. package/dist/errors.js +0 -2
  34. package/dist/hooks/prerun/auth.js +5 -9
  35. package/dist/interfaces/config-manager.interface.d.ts +3 -1
  36. package/dist/lib/container.d.ts +4 -12
  37. package/dist/lib/container.js +28 -113
  38. package/dist/lib/swarm-client/fetch-api.d.ts +7 -0
  39. package/dist/lib/swarm-client/fetch-api.js +41 -0
  40. package/dist/lib/swarm-client/fetch-timeout.client.d.ts +1 -0
  41. package/dist/lib/swarm-client/fetch-timeout.client.js +32 -0
  42. package/dist/lib/swarm-client/index.d.ts +6 -0
  43. package/dist/lib/swarm-client/index.js +31 -0
  44. package/dist/lib/swarm-client/middlewares/authorization.middleware.d.ts +2 -0
  45. package/dist/lib/swarm-client/middlewares/authorization.middleware.js +12 -0
  46. package/dist/lib/swarm-client/middlewares/index.d.ts +6 -0
  47. package/dist/lib/swarm-client/middlewares/index.js +5 -0
  48. package/dist/lib/swarm-client/middlewares/logger.middleware.d.ts +2 -0
  49. package/dist/lib/swarm-client/middlewares/logger.middleware.js +30 -0
  50. package/dist/lib/swarm-client/middlewares/request-id.middleware.d.ts +2 -0
  51. package/dist/lib/swarm-client/middlewares/request-id.middleware.js +13 -0
  52. package/dist/lib/swarm-client/types.d.ts +23 -0
  53. package/dist/lib/swarm-client/types.js +1 -0
  54. package/dist/managers/account-manager.d.ts +1 -0
  55. package/dist/managers/account-manager.js +13 -18
  56. package/dist/managers/config-file-manager.d.ts +24 -17
  57. package/dist/managers/config-file-manager.js +285 -161
  58. package/dist/managers/config-manager.d.ts +6 -6
  59. package/dist/managers/config-manager.js +8 -8
  60. package/dist/services/account.service.d.ts +42 -0
  61. package/dist/services/account.service.js +140 -0
  62. package/dist/services/asset.service.d.ts +35 -0
  63. package/dist/services/asset.service.js +120 -0
  64. package/dist/services/auth.service.d.ts +4 -6
  65. package/dist/services/auth.service.js +108 -118
  66. package/dist/utils/helper.js +2 -2
  67. package/dist/utils/progress.js +1 -0
  68. package/dist/utils/prompt.service.d.ts +8 -1
  69. package/dist/utils/prompt.service.js +33 -1
  70. package/oclif.manifest.json +479 -215
  71. package/package.json +7 -8
  72. package/dist/commands/files/download.d.ts +0 -15
  73. package/dist/commands/files/download.js +0 -63
  74. package/dist/commands/files/upload.d.ts +0 -18
  75. package/dist/commands/files/upload.js +0 -83
  76. package/dist/commands/storage/base.d.ts +0 -13
  77. package/dist/commands/storage/base.js +0 -125
  78. package/dist/commands/storage/create.d.ts +0 -11
  79. package/dist/commands/storage/create.js +0 -53
  80. package/dist/commands/storage/select.d.ts +0 -9
  81. package/dist/commands/storage/select.js +0 -38
  82. package/dist/commands/storage/show.d.ts +0 -17
  83. package/dist/commands/storage/show.js +0 -34
  84. package/dist/commands/storage/update.d.ts +0 -14
  85. package/dist/commands/storage/update.js +0 -204
  86. package/dist/commands/workflows/extend-lease.d.ts +0 -17
  87. package/dist/commands/workflows/extend-lease.js +0 -102
  88. package/dist/hooks/finally/shutdown-blockchain.d.ts +0 -3
  89. package/dist/hooks/finally/shutdown-blockchain.js +0 -8
  90. package/dist/middlewares/auth-middleware.d.ts +0 -9
  91. package/dist/middlewares/auth-middleware.js +0 -91
  92. package/dist/middlewares/cookies-middleware.d.ts +0 -8
  93. package/dist/middlewares/cookies-middleware.js +0 -80
  94. package/dist/services/storage.service.d.ts +0 -73
  95. package/dist/services/storage.service.js +0 -378
@@ -1,16 +1,15 @@
1
- import { existsSync } from 'node:fs';
2
- import path from 'node:path';
3
1
  import { Flags } from '@oclif/core';
4
- import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
5
- 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';
6
5
  import { AuthService } from '../../services/auth.service.js';
7
- import { StorageService } from '../../services/storage.service.js';
8
- import { getConfigNameFromCredentials } from '../../utils/helper.js';
6
+ import { getConfigName, preparePath } from '../../utils/helper.js';
9
7
  import { promptService } from '../../utils/prompt.service.js';
10
8
  import { BaseAccountCommand } from './base.js';
11
9
  export default class AccountLoginCommand extends BaseAccountCommand {
12
10
  static aliases = ['login'];
13
11
  static authenticate = false;
12
+ static summary = 'Login and account creation for SuperProtocol';
14
13
  static description = 'Login to SuperProtocol (sign up or sign in).';
15
14
  static examples = [
16
15
  `<%= config.bin %> <%= command.id %>
@@ -23,8 +22,15 @@ export default class AccountLoginCommand extends BaseAccountCommand {
23
22
  privateKey: Flags.string({
24
23
  description: 'Account private key used for authentication',
25
24
  }),
25
+ path: Flags.string({
26
+ description: 'Path to account(configuration) file to import',
27
+ }),
26
28
  url: Flags.string({
27
- description: 'Provider base URL',
29
+ description: 'Swarm Api URL',
30
+ hidden: true,
31
+ }),
32
+ authUrl: Flags.string({
33
+ description: 'Auth URL',
28
34
  hidden: true,
29
35
  }),
30
36
  yes: Flags.boolean({
@@ -33,49 +39,40 @@ export default class AccountLoginCommand extends BaseAccountCommand {
33
39
  description: 'Skip questions (generate keys when needed).',
34
40
  }),
35
41
  };
36
- configFileManager;
42
+ accountService;
37
43
  shouldSkipLogin = false;
38
44
  async inputPrompt(options) {
39
45
  return promptService.text(options);
40
46
  }
41
47
  async checkStorage() {
42
- await this.container
43
- .initProviderClient({ enableAuth: true, enableCookies: true, rebuild: true })
44
- .build();
45
- const { providerClient } = this.container;
46
- const storageService = new StorageService(providerClient, this.logger);
47
- if (!(await storageService.hasStorage())) {
48
- this.logger.info('Requesting default storage');
49
- const { id, isCentralized, storageType } = await storageService.getCentralizedStorage();
50
- this.logger.info({ id, isCentralized, storageType }, 'Requested new storage');
51
- await storageService.saveStorage(id);
52
- }
48
+ this.logger.info('Storage initialization skipped (mock)');
53
49
  }
54
50
  async init() {
55
51
  await super.init();
56
52
  await this.container.initConfigFileManager().build();
57
- this.configFileManager = this.container.configFileManager;
53
+ this.accountService = new AccountService(this.container.configFileManager);
58
54
  await this.resolveConfiguration();
59
55
  if (this.shouldSkipLogin) {
60
56
  return;
61
57
  }
62
58
  await this.initAccountContext({
63
59
  assumeYes: this.flags.yes,
64
- enableAuth: false,
65
- enableCookies: true,
66
60
  });
67
61
  }
68
62
  async run() {
69
63
  if (this.shouldSkipLogin) {
70
64
  return { account: undefined, success: false };
71
65
  }
72
- const { accountManager, configManager, providerClient } = this.container;
73
- const authService = new AuthService(accountManager, configManager, providerClient, this.logger);
66
+ const { accountManager, configManager } = this.container;
67
+ const authService = new AuthService(accountManager, configManager, this.logger);
74
68
  try {
75
69
  await authService.auth({ force: true });
76
70
  }
77
71
  catch (error) {
78
- this.error(error, { exit: 1 });
72
+ if (error instanceof Error) {
73
+ this.error(error, { exit: 1 });
74
+ }
75
+ this.error(String(error), { exit: 1 });
79
76
  }
80
77
  try {
81
78
  await this.checkStorage();
@@ -90,7 +87,7 @@ export default class AccountLoginCommand extends BaseAccountCommand {
90
87
  }
91
88
  async askName(fallback) {
92
89
  const value = await this.inputPrompt({
93
- message: 'Configuration name:',
90
+ message: 'Account name:',
94
91
  placeholder: fallback,
95
92
  });
96
93
  const trimmed = value.trim();
@@ -101,40 +98,48 @@ export default class AccountLoginCommand extends BaseAccountCommand {
101
98
  }
102
99
  createAccountFromKey(privateKey) {
103
100
  try {
104
- const account = privateKeyToAccount(privateKey);
105
- return {
106
- address: account.address,
107
- privateKey: privateKey,
108
- };
101
+ return this.accountService.createAccountFromKey(privateKey);
109
102
  }
110
103
  catch (error) {
111
- this.logger.error({ err: error }, 'Invalid private key provided.');
112
- this.error('Invalid private key provided.');
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);
113
107
  }
114
108
  }
115
- async createConfigIfMissing(configFile, displayName, providerUrl, account) {
116
- const configPath = path.join(this.configFileManager.getConfigDir(), configFile);
117
- if (existsSync(configPath)) {
118
- return;
109
+ async updateConfigDisplayName(configFile, displayName) {
110
+ const result = await this.accountService.updateConfigDisplayName(configFile, displayName);
111
+ if (result.status === 'skipped') {
112
+ return configFile;
119
113
  }
120
- await this.configFileManager.createConfig(configFile, displayName, providerUrl, account);
121
- this.log(`Created configuration: ${displayName}`);
122
- }
123
- findConfigsByPrivateKey(privateKey, providerUrl, matchProviderUrl) {
124
- const normalizedKey = privateKey.trim().toLowerCase();
125
- const configs = this.configFileManager.getConfigsWithNames();
126
- const matches = [];
127
- for (const config of configs) {
128
- const configData = this.configFileManager.getConfigData(config.file);
129
- const storedKey = configData?.account?.privateKey?.toLowerCase();
130
- const storedUrl = (configData?.providerUrl ?? PROVIDER_URL).trim();
131
- const keyMatches = storedKey === normalizedKey;
132
- const urlMatches = !matchProviderUrl || storedUrl === providerUrl;
133
- if (keyMatches && urlMatches) {
134
- matches.push(config);
135
- }
114
+ if (result.status === 'updated') {
115
+ this.log(`Updated account name to "${displayName}"`);
116
+ }
117
+ else {
118
+ this.log(`Account name: "${displayName}"`);
136
119
  }
137
- return matches;
120
+ return result.configFile;
121
+ }
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;
138
+ }
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
+ });
138
143
  }
139
144
  async getPrivateKeyOrGenerate() {
140
145
  const generatedKey = generatePrivateKey();
@@ -149,17 +154,17 @@ export default class AccountLoginCommand extends BaseAccountCommand {
149
154
  const trimmed = value.trim();
150
155
  return trimmed || generatedKey;
151
156
  }
152
- async resolveByName(name, privateKey, providerUrl) {
153
- const configs = this.configFileManager.getConfigsWithNames();
157
+ async resolveByName(name, privateKey, swarmUrl, authUrl) {
158
+ const configs = await this.accountService.getConfigsWithNames();
154
159
  const normalized = name.toLowerCase();
155
160
  const existingByName = configs.find((config) => config.name.toLowerCase() === normalized || config.file.toLowerCase() === normalized);
156
161
  if (existingByName) {
157
- await this.configFileManager.setCurrentConfig(existingByName.file);
162
+ await this.setCurrentAndAuth(existingByName.file, authUrl);
158
163
  return;
159
164
  }
160
165
  let shouldCreate = true;
161
166
  if (!this.flags.yes) {
162
- shouldCreate = await this.confirmPrompt(`Configuration "${name}" not found. Create it?`, true);
167
+ shouldCreate = await this.confirmPrompt(`Account with "${name}" not found. Create it?`, true);
163
168
  }
164
169
  if (!shouldCreate) {
165
170
  this.shouldSkipLogin = true;
@@ -167,74 +172,125 @@ export default class AccountLoginCommand extends BaseAccountCommand {
167
172
  }
168
173
  const resolvedKey = privateKey ?? (await this.getPrivateKeyOrGenerate());
169
174
  const account = this.createAccountFromKey(resolvedKey);
170
- const configFile = getConfigNameFromCredentials(resolvedKey, providerUrl);
171
- await this.createConfigIfMissing(configFile, name, providerUrl, account);
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
+ }
172
180
  let shouldSwitch = true;
173
181
  if (!this.flags.yes) {
174
- shouldSwitch = await this.confirmPrompt(`Switch to configuration "${name}" now?`, true);
182
+ shouldSwitch = await this.confirmPrompt(`Switch to account "${name}" now?`, true);
175
183
  }
176
184
  if (!shouldSwitch) {
177
185
  this.shouldSkipLogin = true;
178
186
  return;
179
187
  }
180
- await this.configFileManager.setCurrentConfig(configFile);
188
+ await this.setCurrentAndAuth(createdFile, authUrl);
181
189
  }
182
- async resolveByPrivateKey(privateKey, providerUrl, matchProviderUrl) {
183
- const matches = this.findConfigsByPrivateKey(privateKey, providerUrl, matchProviderUrl);
184
- if (matches.length === 1) {
185
- await this.configFileManager.setCurrentConfig(matches[0].file);
190
+ async loadConfigFromPath(configPath) {
191
+ try {
192
+ return await this.accountService.loadConfigFromPath(configPath);
193
+ }
194
+ catch (error) {
195
+ const message = error instanceof Error ? error.message : String(error);
196
+ this.error(`Invalid account file: ${message}`, { exit: 1 });
197
+ }
198
+ }
199
+ async resolveByPath(rawPath, name, authUrl) {
200
+ const sourcePath = preparePath(rawPath);
201
+ const config = await this.loadConfigFromPath(sourcePath);
202
+ const targetFile = this.accountService.resolveConfigFileName(sourcePath, config, name);
203
+ const desiredName = name?.trim();
204
+ const privateKey = config.account.privateKey;
205
+ const swarmUrl = (config.swarmUrl ?? SWARM_URL).trim();
206
+ const matches = await this.accountService.findConfigsByPrivateKey(privateKey, swarmUrl, true);
207
+ if (matches.length > 0) {
208
+ const selectedFile = await this.selectMatchedConfig(matches);
209
+ this.log('Account already exists. Nothing to import.');
210
+ await this.applySelectionWithDisplayName(selectedFile, desiredName, authUrl);
186
211
  return;
187
212
  }
188
- if (matches.length > 1) {
189
- if (this.flags.yes) {
190
- this.log(`Too many matched configs: ${matches.map((conf) => conf.name).join(',')} Selected first: ${matches[0].name}`);
191
- await this.configFileManager.setCurrentConfig(matches[0].file);
192
- return;
213
+ if (await this.accountService.configExists(targetFile)) {
214
+ const existingConfig = await this.accountService.getConfigData(targetFile);
215
+ const existingKey = existingConfig?.account?.privateKey?.trim().toLowerCase();
216
+ const existingUrl = (existingConfig?.swarmUrl ?? SWARM_URL).trim();
217
+ const importedKey = privateKey.trim().toLowerCase();
218
+ if (!existingKey || existingKey !== importedKey || existingUrl !== swarmUrl) {
219
+ this.error(`Account file "${targetFile}" already exists with different credentials. Use a different name or remove the existing file before importing.`, { exit: 1 });
193
220
  }
194
- const selected = await this.selectPrompt({
195
- message: 'Multiple configurations found for this private key. Select one:',
196
- options: matches.map((match) => ({ label: match.name, value: match.file })),
197
- });
198
- await this.configFileManager.setCurrentConfig(selected);
221
+ this.log(`Account already exists. Switching to ${name || targetFile}`);
222
+ await this.setCurrentAndAuth(targetFile, authUrl);
223
+ return;
224
+ }
225
+ try {
226
+ const importedFile = await this.accountService.importConfig(sourcePath, name);
227
+ await this.setCurrentAndAuth(importedFile, authUrl);
228
+ }
229
+ catch (error) {
230
+ this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
231
+ }
232
+ }
233
+ async resolveByPrivateKey(privateKey, swarmUrl, matchSwarmUrl, name, authUrl) {
234
+ const matches = await this.accountService.findConfigsByPrivateKey(privateKey, swarmUrl, matchSwarmUrl);
235
+ const desiredName = name?.trim();
236
+ if (matches.length > 0) {
237
+ const selectedFile = await this.selectMatchedConfig(matches);
238
+ await this.applySelectionWithDisplayName(selectedFile, desiredName, authUrl);
199
239
  return;
200
240
  }
201
241
  let shouldCreate = true;
202
242
  if (!this.flags.yes) {
203
- shouldCreate = await this.confirmPrompt('No configuration found for this private key. Create a new one?', true);
243
+ shouldCreate = await this.confirmPrompt('No accounts found for this private key. Create a new one?', true);
204
244
  }
205
245
  if (!shouldCreate) {
206
246
  this.shouldSkipLogin = true;
207
247
  return;
208
248
  }
209
249
  const account = this.createAccountFromKey(privateKey);
210
- const suggestedName = this.flags.name?.trim() || account.address;
250
+ const suggestedName = desiredName || account.address;
211
251
  const displayName = this.flags.yes ? suggestedName : await this.askName(suggestedName);
212
- const configFile = getConfigNameFromCredentials(privateKey, providerUrl);
213
- await this.createConfigIfMissing(configFile, displayName, providerUrl, account);
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
+ }
214
257
  let shouldSwitch = true;
215
258
  if (!this.flags.yes) {
216
- shouldSwitch = await this.confirmPrompt(`Switch to configuration "${displayName}" now?`, true);
259
+ shouldSwitch = await this.confirmPrompt(`Switch to account "${displayName}" now?`, true);
217
260
  }
218
261
  if (!shouldSwitch) {
219
262
  this.shouldSkipLogin = true;
220
263
  return;
221
264
  }
222
- await this.configFileManager.setCurrentConfig(configFile);
265
+ await this.setCurrentAndAuth(createdFile, authUrl);
223
266
  }
224
267
  async resolveConfiguration() {
225
268
  const name = this.flags.name?.trim();
269
+ const configPath = this.flags.path?.trim();
270
+ if (configPath !== undefined && !configPath) {
271
+ this.error('Account path cannot be empty.', { exit: 1 });
272
+ }
226
273
  const privateKey = this.flags.privateKey?.trim();
227
274
  const url = this.flags.url?.trim();
228
275
  if (url !== undefined && !url) {
229
- this.error('Provider URL cannot be empty.', { exit: 1 });
276
+ this.error('Swarm URL cannot be empty.', { exit: 1 });
230
277
  }
231
- const providerUrl = (url || PROVIDER_URL).trim();
232
- if (name) {
233
- await this.resolveByName(name, privateKey, providerUrl);
278
+ const authUrl = this.flags.authUrl?.trim();
279
+ if (authUrl !== undefined && !authUrl) {
280
+ this.error('Auth URL cannot be empty.', { exit: 1 });
281
+ }
282
+ const swarmUrl = (url || SWARM_URL).trim();
283
+ if (configPath) {
284
+ await this.resolveByPath(configPath, name, authUrl);
234
285
  return;
235
286
  }
236
287
  if (privateKey) {
237
- await this.resolveByPrivateKey(privateKey, providerUrl, Boolean(url));
288
+ await this.resolveByPrivateKey(privateKey, swarmUrl, Boolean(url), name, authUrl);
289
+ return;
290
+ }
291
+ if (name) {
292
+ await this.resolveByName(name, privateKey, swarmUrl, authUrl);
293
+ return;
238
294
  }
239
295
  }
240
296
  static maskPrivateKey(privateKey) {
@@ -6,6 +6,9 @@ export default class AccountSwitchCommand extends BaseAccountCommand<typeof Acco
6
6
  static examples: string[];
7
7
  protected configFileManager: ConfigFileManager;
8
8
  protected configManager: ConfigManager;
9
+ static flags: {
10
+ name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
9
12
  init(): Promise<void>;
10
13
  run(): Promise<void>;
11
14
  private switchConfig;
@@ -1,3 +1,4 @@
1
+ import { Flags } from '@oclif/core';
1
2
  import { BaseAccountCommand } from './base.js';
2
3
  export default class AccountSwitchCommand extends BaseAccountCommand {
3
4
  static authenticate = false;
@@ -5,6 +6,12 @@ export default class AccountSwitchCommand extends BaseAccountCommand {
5
6
  static examples = ['<%= config.bin %> <%= command.id %>'];
6
7
  configFileManager;
7
8
  configManager;
9
+ static flags = {
10
+ name: Flags.string({
11
+ char: 'n',
12
+ description: 'Account name to switch',
13
+ }),
14
+ };
8
15
  async init() {
9
16
  await super.init();
10
17
  await this.container.initConfigFileManager().build();
@@ -12,28 +19,41 @@ export default class AccountSwitchCommand extends BaseAccountCommand {
12
19
  await this.container.initConfigManager().build();
13
20
  }
14
21
  async run() {
15
- const configs = this.configFileManager.getConfigsWithNames();
22
+ const { name } = this.flags;
23
+ const configs = await this.configFileManager.getConfigsWithNames();
16
24
  const currentConfig = this.configFileManager.getCurrentConfigFile();
17
25
  if (configs.length === 0) {
18
26
  this.log('No accounts found');
19
- this.log('Create a new account with: sp account login --privateKey "<PRIVATE_KEY>" --name "Account Name"');
27
+ this.log('Create a new account with: sp account login --privateKey "<PRIVATE_KEY>" --name "Account Name" or sp account login');
20
28
  return;
21
29
  }
22
- const selected = await this.selectPrompt({
23
- initialValue: currentConfig,
24
- message: 'Select an account:',
25
- options: configs.map((config) => ({
26
- label: config.name ?? config.file,
27
- value: config.file,
28
- })),
29
- });
30
+ let selected;
31
+ if (name) {
32
+ try {
33
+ const config = await this.configFileManager.getConfigWithName(name);
34
+ selected = config.file;
35
+ }
36
+ catch {
37
+ this.error(`Account with name ${name} not found`);
38
+ }
39
+ }
40
+ else {
41
+ selected = await this.selectPrompt({
42
+ initialValue: currentConfig,
43
+ message: 'Select an account:',
44
+ options: configs.map((config) => ({
45
+ label: config.name ?? config.file,
46
+ value: config.file,
47
+ })),
48
+ });
49
+ }
30
50
  const selectedConfig = configs.find((c) => c.file === selected);
31
51
  await this.switchConfig(selected, selectedConfig?.name || selected);
32
52
  }
33
53
  async switchConfig(configFile, displayName) {
34
54
  await this.configFileManager.setCurrentConfig(configFile);
35
55
  this.log(`Switched to account: ${displayName || configFile}`);
36
- await this.initAccountContext({ enableAuth: false, enableCookies: true, rebuild: true });
56
+ await this.container.initConfigManager(true).build();
37
57
  this.configFileManager = this.container.configFileManager;
38
58
  this.configManager = this.container.configManager;
39
59
  }
@@ -0,0 +1,39 @@
1
+ import type { Command } from '@oclif/core';
2
+ import { type AssetCredentials, AssetService, AssetType, SourceType } from '../../services/asset.service.js';
3
+ import { BaseCommand } from '../base.js';
4
+ export type AssetCredentialsFlags = {
5
+ storjBucket?: string;
6
+ storjPath?: string;
7
+ storjToken?: string;
8
+ s3Bucket?: string;
9
+ s3Path?: string;
10
+ s3AccessKey?: string;
11
+ s3SecretKey?: string;
12
+ s3Region?: string;
13
+ s3Endpoint?: string;
14
+ dockerImage?: string;
15
+ dockerRegistry?: string;
16
+ dockerUsername?: string;
17
+ dockerPassword?: string;
18
+ githubRepo?: string;
19
+ githubToken?: string;
20
+ githubBranch?: string;
21
+ gdocsDocumentId?: string;
22
+ gdocsApiKey?: string;
23
+ gdocsServiceAccountJson?: string;
24
+ };
25
+ export declare abstract class BaseAssetCommand<T extends typeof Command> extends BaseCommand<T> {
26
+ static summary: string;
27
+ protected assetService: AssetService;
28
+ protected currentDir: string;
29
+ init(): Promise<void>;
30
+ protected parseCredentialsInput(raw: string, fieldName: string): Record<string, unknown>;
31
+ protected promptCredentials<T extends SourceType>(sourceType: T): Promise<AssetCredentials>;
32
+ protected promptOptionalText(message: string, secret?: boolean): Promise<string | undefined>;
33
+ protected promptRequiredText(message: string): Promise<string>;
34
+ protected parseSizeInput(raw: string): number | undefined;
35
+ protected getAllowedSourceTypes(type: AssetType): readonly SourceType[];
36
+ protected assertSourceTypeAllowed(type: AssetType, sourceType: SourceType): void;
37
+ protected hasCredentialsFlags(flags: AssetCredentialsFlags): boolean;
38
+ protected buildCredentialsFromFlags(sourceType: SourceType, flags: AssetCredentialsFlags): AssetCredentials;
39
+ }