@super-protocol/sp-cli 0.0.6 → 0.0.7

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 (83) hide show
  1. package/README.md +97 -229
  2. package/dist/commands/account/base.d.ts +20 -0
  3. package/dist/commands/account/base.js +49 -0
  4. package/dist/commands/{config/delete.d.ts → account/forget.d.ts} +5 -2
  5. package/dist/commands/{config/delete.js → account/forget.js} +12 -5
  6. package/dist/commands/account/get-sppi.d.ts +2 -2
  7. package/dist/commands/account/get-sppi.js +8 -13
  8. package/dist/commands/account/info.d.ts +5 -2
  9. package/dist/commands/account/info.js +53 -3
  10. package/dist/commands/account/list.d.ts +9 -0
  11. package/dist/commands/{config → account}/list.js +16 -9
  12. package/dist/commands/account/login.d.ts +35 -0
  13. package/dist/commands/account/login.js +254 -0
  14. package/dist/commands/account/switch.d.ts +12 -0
  15. package/dist/commands/account/switch.js +40 -0
  16. package/dist/commands/base.d.ts +4 -3
  17. package/dist/commands/base.js +3 -1
  18. package/dist/commands/files/download.js +13 -5
  19. package/dist/commands/files/upload.js +11 -7
  20. package/dist/commands/storage/base.d.ts +2 -2
  21. package/dist/commands/storage/create.js +1 -1
  22. package/dist/commands/storage/select.js +3 -5
  23. package/dist/commands/storage/show.js +2 -4
  24. package/dist/commands/storage/update.js +31 -14
  25. package/dist/commands/workflows/extend-lease.d.ts +1 -1
  26. package/dist/commands/workflows/extend-lease.js +19 -10
  27. package/dist/config/config-file.schema.d.ts +1 -2
  28. package/dist/config/config-file.schema.js +0 -1
  29. package/dist/config/config.schema.d.ts +1 -1
  30. package/dist/errors.d.ts +2 -0
  31. package/dist/errors.js +2 -0
  32. package/dist/hooks/finally/shutdown-blockchain.d.ts +1 -1
  33. package/dist/hooks/finally/shutdown-blockchain.js +1 -1
  34. package/dist/hooks/finally/unlock-config.d.ts +3 -0
  35. package/dist/hooks/finally/unlock-config.js +5 -0
  36. package/dist/hooks/init/init-container.d.ts +1 -1
  37. package/dist/hooks/init/init-container.js +2 -3
  38. package/dist/hooks/init/lock-config.d.ts +3 -0
  39. package/dist/hooks/init/lock-config.js +19 -0
  40. package/dist/hooks/prerun/auth.d.ts +3 -0
  41. package/dist/hooks/prerun/auth.js +70 -0
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.js +1 -1
  44. package/dist/interfaces/account-manager.interface.d.ts +1 -1
  45. package/dist/interfaces/config-manager.interface.d.ts +2 -2
  46. package/dist/lib/cli-instance-lock.d.ts +2 -0
  47. package/dist/lib/cli-instance-lock.js +37 -0
  48. package/dist/lib/container.d.ts +6 -4
  49. package/dist/lib/container.js +108 -38
  50. package/dist/logger.d.ts +1 -1
  51. package/dist/logger.js +4 -1
  52. package/dist/managers/account-manager.d.ts +7 -8
  53. package/dist/managers/account-manager.js +20 -45
  54. package/dist/managers/config-file-manager.d.ts +6 -7
  55. package/dist/managers/config-file-manager.js +35 -32
  56. package/dist/managers/config-manager.d.ts +5 -5
  57. package/dist/managers/config-manager.js +5 -2
  58. package/dist/middlewares/auth-middleware.d.ts +1 -1
  59. package/dist/services/auth.service.d.ts +10 -15
  60. package/dist/services/auth.service.js +71 -5
  61. package/dist/services/storage.service.d.ts +3 -3
  62. package/dist/services/storage.service.js +46 -19
  63. package/dist/utils/helper.d.ts +1 -0
  64. package/dist/utils/helper.js +15 -1
  65. package/oclif.manifest.json +258 -399
  66. package/package.json +17 -24
  67. package/dist/commands/auth/login.d.ts +0 -12
  68. package/dist/commands/auth/login.js +0 -50
  69. package/dist/commands/auth/me.d.ts +0 -5
  70. package/dist/commands/auth/me.js +0 -16
  71. package/dist/commands/config/add.d.ts +0 -13
  72. package/dist/commands/config/add.js +0 -73
  73. package/dist/commands/config/base.d.ts +0 -16
  74. package/dist/commands/config/base.js +0 -78
  75. package/dist/commands/config/create.d.ts +0 -11
  76. package/dist/commands/config/create.js +0 -41
  77. package/dist/commands/config/index.d.ts +0 -6
  78. package/dist/commands/config/index.js +0 -22
  79. package/dist/commands/config/list.d.ts +0 -6
  80. package/dist/commands/config/show.d.ts +0 -6
  81. package/dist/commands/config/show.js +0 -10
  82. package/dist/commands/config/use.d.ts +0 -6
  83. package/dist/commands/config/use.js +0 -27
@@ -1,9 +1,9 @@
1
+ import path from 'node:path';
1
2
  import { createProviderClient, loggerMiddleware, requestIdMiddleware, } from '@super-protocol/provider-client';
2
3
  import { BlockchainConnector } from '@super-protocol/sdk-js';
3
- import path from 'node:path';
4
4
  import { PROVIDER_URL } from '../constants.js';
5
5
  import logger from '../logger.js';
6
- import { AccountManager, ConfigFileManager, ConfigManager, } from '../managers/index.js';
6
+ import { AccountManager, ConfigFileManager, ConfigManager } from '../managers/index.js';
7
7
  import { createAuthMiddleware } from '../middlewares/auth-middleware.js';
8
8
  import { createCookieMiddleware } from '../middlewares/cookies-middleware.js';
9
9
  export class AppContainer {
@@ -14,9 +14,10 @@ export class AppContainer {
14
14
  _configFileManager;
15
15
  _configManager;
16
16
  _providerClient;
17
- initPromises = [];
17
+ providerClientOptions;
18
18
  initQueue = new Map();
19
19
  logger;
20
+ providerClientInitToken = 0;
20
21
  runtimeConfigFile;
21
22
  constructor(cwdDir, oclifConfig) {
22
23
  this.cwdDir = cwdDir;
@@ -60,16 +61,19 @@ export class AppContainer {
60
61
  return this._providerClient;
61
62
  }
62
63
  async build() {
63
- await Promise.all(this.initPromises);
64
+ await Promise.all(this.initQueue.values());
64
65
  return this;
65
66
  }
66
67
  initAccountManager(rebuild = true) {
67
68
  this.initConfigManager(rebuild);
68
69
  return this.queueInit('accountManager', async () => {
69
- await this.waitFor('configManager');
70
- if (this._accountManager) {
70
+ await this.waitFor('configManager', { required: true });
71
+ if (this._accountManager && !rebuild) {
71
72
  return;
72
73
  }
74
+ if (rebuild) {
75
+ this._accountManager = undefined;
76
+ }
73
77
  this.logger.info('Initializing account manager');
74
78
  const accountManager = new AccountManager(this.configManager, this.logger);
75
79
  await accountManager.init();
@@ -79,11 +83,11 @@ export class AppContainer {
79
83
  initBlockchainConnector() {
80
84
  this.initConfigManager();
81
85
  return this.queueInit('blockchainConnector', async () => {
82
- await this.waitFor('configManager');
86
+ await this.waitFor('configManager', { required: true });
83
87
  let blockchainConfig = await this.configManager.get('blockchain');
84
88
  if (!blockchainConfig) {
85
- await this.waitFor('providerClient');
86
- const { data, error } = await this.providerClient.GET('/api/config');
89
+ const client = await this.getProviderClientForBootstrap();
90
+ const { data, error } = await client.GET('/api/config');
87
91
  if (error || !data) {
88
92
  throw new Error('Could not get configuration from provider');
89
93
  }
@@ -99,9 +103,12 @@ export class AppContainer {
99
103
  }
100
104
  initConfigFileManager(rebuild = false) {
101
105
  return this.queueInit('configFileManager', async () => {
102
- if (this._configFileManager) {
106
+ if (this._configFileManager && !rebuild) {
103
107
  return;
104
108
  }
109
+ if (rebuild) {
110
+ this._configFileManager = undefined;
111
+ }
105
112
  const configFileManager = new ConfigFileManager(this.oclifConfig.configDir, this.logger, {
106
113
  runtimeConfigFile: this.runtimeConfigFile,
107
114
  });
@@ -112,10 +119,13 @@ export class AppContainer {
112
119
  initConfigManager(rebuild = false) {
113
120
  this.initConfigFileManager(rebuild);
114
121
  return this.queueInit('configManager', async () => {
115
- await this.waitFor('configFileManager');
116
- if (this._configManager) {
122
+ await this.waitFor('configFileManager', { required: true });
123
+ if (this._configManager && !rebuild) {
117
124
  return;
118
125
  }
126
+ if (rebuild) {
127
+ this._configManager = undefined;
128
+ }
119
129
  const configFilePath = await this.configFileManager.getCurrentConfigPath();
120
130
  if (!configFilePath) {
121
131
  throw new Error('Config file not found');
@@ -126,14 +136,30 @@ export class AppContainer {
126
136
  this._configManager = configManager;
127
137
  }, rebuild);
128
138
  }
129
- initProviderClient({ enableAuth = true, enableCookies = true, rebuild = false } = {}) {
139
+ initProviderClient({ enableAuth = true, enableCookies = true, rebuild = false, } = {}) {
130
140
  this.initConfigManager();
141
+ const options = { enableAuth, enableCookies };
142
+ const optionsChanged = this.providerClientOptions &&
143
+ (this.providerClientOptions.enableAuth !== options.enableAuth ||
144
+ this.providerClientOptions.enableCookies !== options.enableCookies);
145
+ if (optionsChanged) {
146
+ rebuild = true;
147
+ this.logger.debug({ newOptions: options, oldOptions: this.providerClientOptions }, 'Provider client options changed, rebuilding');
148
+ }
149
+ const shouldSchedule = rebuild || !this.initQueue.has('providerClient');
150
+ const initToken = shouldSchedule
151
+ ? ++this.providerClientInitToken
152
+ : this.providerClientInitToken;
131
153
  return this.queueInit('providerClient', async () => {
132
154
  if (this._providerClient && !rebuild) {
133
155
  return;
134
156
  }
135
- await this.waitFor('configManager');
136
- const providerUrl = await this.configManager.get('providerUrl') || PROVIDER_URL;
157
+ if (rebuild && this._providerClient) {
158
+ this.logger.debug('Clearing existing provider client for rebuild');
159
+ this._providerClient = undefined;
160
+ }
161
+ await this.waitFor('configManager', { required: true });
162
+ const providerUrl = (await this.configManager.get('providerUrl')) || PROVIDER_URL;
137
163
  this.logger.info('Initializing provider client');
138
164
  const providerClient = createProviderClient({
139
165
  baseUrl: providerUrl,
@@ -150,28 +176,28 @@ export class AppContainer {
150
176
  const authMiddleware = await createAuthMiddleware(this.configManager, providerClient, this.logger);
151
177
  providerClient.use(authMiddleware);
152
178
  }
153
- providerClient.use({
154
- onRequest: async ({ request }) => {
155
- const req = request.clone();
156
- const readBody = await req.body?.getReader().read();
157
- let body;
158
- if (readBody && readBody.value) {
159
- body = Buffer.from(readBody.value).toString('utf8');
160
- }
161
- this.logger.debug({
162
- body,
163
- token: req.headers.get('Authorization'),
164
- url: req.url,
165
- }, 'Requesting');
166
- },
167
- });
179
+ if (process.env.SP_CLI_DEBUG_REQUESTS === '1') {
180
+ providerClient.use({
181
+ onRequest: async ({ request }) => {
182
+ this.logger.debug({
183
+ hasAuthHeader: Boolean(request.headers.get('Authorization')),
184
+ hasBody: Boolean(request.body),
185
+ method: request.method,
186
+ url: request.url,
187
+ }, 'Requesting');
188
+ },
189
+ });
190
+ }
191
+ if (initToken !== this.providerClientInitToken) {
192
+ this.logger.debug({ initToken, providerClientInitToken: this.providerClientInitToken }, 'Skipping provider client assignment (superseded)');
193
+ return;
194
+ }
168
195
  this._providerClient = providerClient;
196
+ this.providerClientOptions = options;
169
197
  }, rebuild);
170
198
  }
171
199
  setupRuntimeConfig(config) {
172
- if (this.initQueue.size > 0) {
173
- throw new Error('Cannot change runtime config after initialization has started');
174
- }
200
+ const previousRuntimeConfigFile = this.runtimeConfigFile;
175
201
  if (config.configFile) {
176
202
  this.runtimeConfigFile = path.isAbsolute(config.configFile)
177
203
  ? config.configFile
@@ -180,18 +206,62 @@ export class AppContainer {
180
206
  else {
181
207
  this.runtimeConfigFile = undefined;
182
208
  }
209
+ const changed = previousRuntimeConfigFile !== this.runtimeConfigFile;
210
+ if (changed) {
211
+ this.logger.debug({ previousRuntimeConfigFile, runtimeConfigFile: this.runtimeConfigFile }, 'Runtime config changed; clearing dependent services');
212
+ this._configManager = undefined;
213
+ this._accountManager = undefined;
214
+ this._providerClient = undefined;
215
+ this.providerClientOptions = undefined;
216
+ this.initQueue.delete('configManager');
217
+ this.initQueue.delete('accountManager');
218
+ this.initQueue.delete('providerClient');
219
+ this.initQueue.delete('blockchainConnector');
220
+ this.initQueue.delete('configFileManager');
221
+ }
222
+ if (this._configFileManager) {
223
+ this._configFileManager.setRuntimeConfigFile(this.runtimeConfigFile);
224
+ }
183
225
  return this;
184
226
  }
227
+ async getProviderClientForBootstrap() {
228
+ if (this._providerClient) {
229
+ return this._providerClient;
230
+ }
231
+ const queued = this.initQueue.get('providerClient');
232
+ if (queued) {
233
+ await queued;
234
+ return this.providerClient;
235
+ }
236
+ await this.waitFor('configManager', { required: true });
237
+ const providerUrl = (await this.configManager.get('providerUrl')) || PROVIDER_URL;
238
+ this.logger.debug({ providerUrl }, 'Creating bootstrap provider client');
239
+ return createProviderClient({
240
+ baseUrl: providerUrl,
241
+ logger: this.logger,
242
+ middlewares: [requestIdMiddleware, loggerMiddleware],
243
+ });
244
+ }
185
245
  queueInit(name, task, force = false) {
186
- if (!this.initQueue.has(name) || force) {
187
- const promise = task();
188
- this.initQueue.set(name, promise);
189
- this.initPromises.push(promise);
246
+ if (force) {
247
+ this.initQueue.delete(name);
248
+ }
249
+ if (!this.initQueue.has(name)) {
250
+ const wrappedPromise = task().catch((error) => {
251
+ if (this.initQueue.get(name) === wrappedPromise) {
252
+ this.initQueue.delete(name);
253
+ }
254
+ throw error;
255
+ });
256
+ this.initQueue.set(name, wrappedPromise);
190
257
  }
191
258
  return this;
192
259
  }
193
- async waitFor(name) {
260
+ async waitFor(name, options = {}) {
194
261
  const promise = this.initQueue.get(name);
262
+ if (!promise && options.required) {
263
+ throw new Error(`Dependency "${name}" was not queued for initialization`);
264
+ }
195
265
  if (promise) {
196
266
  await promise;
197
267
  }
package/dist/logger.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Interfaces } from '@oclif/core';
1
+ import type { Interfaces } from '@oclif/core';
2
2
  import pino from 'pino';
3
3
  declare const _default: Interfaces.Logger & {
4
4
  getPino(): pino.Logger;
package/dist/logger.js CHANGED
@@ -43,7 +43,10 @@ class PinoLogger {
43
43
  this.forward('warn', formatter, args);
44
44
  }
45
45
  forward(level, formatter, args) {
46
- this.logger[level].apply(this.logger, [formatter, ...args]);
46
+ this.logger[level].apply(this.logger, [
47
+ formatter,
48
+ ...args,
49
+ ]);
47
50
  }
48
51
  }
49
52
  const logger = (namespace) => {
@@ -1,7 +1,7 @@
1
- import pino from 'pino';
2
- import { Account } from '../config/config.schema.js';
3
- import { IAccountManager } from '../interfaces/account-manager.interface.js';
4
- import { IConfigManager } from '../interfaces/config-manager.interface.js';
1
+ import type pino from 'pino';
2
+ import { type Account } from '../config/config.schema.js';
3
+ import type { IAccountManager } from '../interfaces/account-manager.interface.js';
4
+ import type { IConfigManager } from '../interfaces/config-manager.interface.js';
5
5
  export declare class AccountManager implements IAccountManager {
6
6
  private readonly configManager;
7
7
  private readonly logger;
@@ -12,9 +12,8 @@ export declare class AccountManager implements IAccountManager {
12
12
  createFromKey(privateKey: string): Promise<Account>;
13
13
  createSign(nonce: string): Promise<string>;
14
14
  getAddress(): string;
15
+ hasAccount(): Promise<boolean>;
15
16
  init(): Promise<void>;
16
- interactWithUser(): Promise<{
17
- address: string;
18
- privateKey: string;
19
- }>;
17
+ private loadAccount;
18
+ private save;
20
19
  }
@@ -1,16 +1,7 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { confirm, isCancel, password } from '@clack/prompts';
8
- import { ux } from '@oclif/core';
9
1
  import { Value } from 'typebox/value';
10
- import { Retryable } from 'typescript-retry-decorator';
11
2
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
12
3
  import { accountSchema } from '../config/config.schema.js';
13
- import { NotInitializedError } from '../errors.js';
4
+ import { AccountNotFoundError, NotInitializedError } from '../errors.js';
14
5
  export class AccountManager {
15
6
  configManager;
16
7
  logger;
@@ -27,7 +18,7 @@ export class AccountManager {
27
18
  address: account.address,
28
19
  privateKey: this.privateKey,
29
20
  };
30
- await this.configManager.set('account', this.account);
21
+ await this.save();
31
22
  this.logger.debug('Created new account');
32
23
  return this.account;
33
24
  }
@@ -38,7 +29,7 @@ export class AccountManager {
38
29
  address: account.address,
39
30
  privateKey: this.privateKey,
40
31
  };
41
- await this.configManager.set('account', this.account);
32
+ await this.save();
42
33
  this.logger.debug('Created new account from key');
43
34
  return this.account;
44
35
  }
@@ -57,48 +48,32 @@ export class AccountManager {
57
48
  }
58
49
  return this.account.address;
59
50
  }
60
- async init() {
51
+ async hasAccount() {
61
52
  const account = await this.configManager.get('account');
53
+ return Value.Check(accountSchema, account);
54
+ }
55
+ async init() {
62
56
  try {
63
- this.account = Value.Parse(accountSchema, account);
64
- this.privateKey = this.account.privateKey;
57
+ await this.loadAccount();
65
58
  }
66
59
  catch (error) {
67
- this.logger.warn({ err: error }, 'Incorrect config file');
68
- await this.interactWithUser();
60
+ if (!(error instanceof AccountNotFoundError)) {
61
+ this.logger.warn({ err: error }, 'Unexpected error loading account');
62
+ }
69
63
  }
70
64
  }
71
- async interactWithUser() {
72
- ux.warn("Account doesn't exist in current configuration");
73
- const ask = await confirm({
74
- message: 'Do you want to create a new account?',
75
- });
76
- if (isCancel(ask)) {
77
- ux.error('Operation cancelled.', { exit: 1 });
78
- }
79
- if (ask) {
80
- const account = await this.create();
81
- ux.stdout('Generated new keyPair for new account.');
82
- return account;
83
- }
84
- const privateKeyInput = await password({ message: 'Please input your privateKey for using in account' });
85
- if (isCancel(privateKeyInput)) {
86
- ux.error('Operation cancelled.', { exit: 1 });
87
- }
88
- const privateKey = privateKeyInput.trim();
65
+ async loadAccount() {
66
+ const account = await this.configManager.get('account');
89
67
  try {
90
- const account = await this.createFromKey(privateKey);
91
- ux.stdout('Your privateKey will be used in config. Keypair created');
92
- return account;
68
+ this.account = Value.Parse(accountSchema, account);
69
+ this.privateKey = this.account.privateKey;
93
70
  }
94
71
  catch (error) {
95
- ux.warn(error);
96
- ux.error('Invalid private key format. Please try again.');
72
+ this.logger.warn({ err: error }, 'Incorrect config file');
73
+ throw new AccountNotFoundError('Account not found in config file');
97
74
  }
98
75
  }
76
+ async save() {
77
+ await this.configManager.set('account', this.account);
78
+ }
99
79
  }
100
- __decorate([
101
- Retryable({
102
- maxAttempts: 3,
103
- })
104
- ], AccountManager.prototype, "interactWithUser", null);
@@ -1,8 +1,8 @@
1
1
  import { confirm, select } from '@clack/prompts';
2
2
  import { ux } from '@oclif/core';
3
- import pino from 'pino';
4
- import { CliConfig } from '../config/config.schema.js';
5
- import { IManager } from '../interfaces/manager.interface.js';
3
+ import type pino from 'pino';
4
+ import { type Account, type CliConfig } from '../config/config.schema.js';
5
+ import type { IManager } from '../interfaces/manager.interface.js';
6
6
  type ConfirmPrompt = typeof confirm;
7
7
  type SelectPrompt = typeof select;
8
8
  type UxLike = Pick<typeof ux, 'error' | 'stdout'>;
@@ -14,7 +14,7 @@ interface ConfigFileManagerOptions {
14
14
  }
15
15
  export declare class ConfigFileManager implements IManager {
16
16
  private readonly logger;
17
- private static readonly CONFIG_FILE;
17
+ static readonly CONFIG_FILE = "config.json";
18
18
  private static readonly CONFIGS_DIR;
19
19
  private readonly configDir;
20
20
  private readonly configFilePath;
@@ -25,8 +25,7 @@ export declare class ConfigFileManager implements IManager {
25
25
  private readonly selectPrompt;
26
26
  private readonly ux;
27
27
  constructor(configDir: string, logger: pino.BaseLogger, options?: ConfigFileManagerOptions);
28
- addConfig(configName: string): Promise<void>;
29
- createConfig(configFileName: string, name: string, url?: string): Promise<void>;
28
+ createConfig(configFileName: string, name: string, url?: string, account?: Account): Promise<void>;
30
29
  deleteConfig(configName: string): Promise<void>;
31
30
  deleteConfigByName(name?: string, force?: boolean): Promise<void>;
32
31
  getConfigData(configName: string): CliConfig | undefined;
@@ -40,7 +39,7 @@ export declare class ConfigFileManager implements IManager {
40
39
  getCurrentConfigPath(): Promise<string>;
41
40
  importConfig(sourcePath: string, targetName?: string): Promise<string>;
42
41
  init(): Promise<void>;
43
- removeConfig(configName: string): Promise<void>;
42
+ private removeConfig;
44
43
  setCurrentConfig(configName: string): Promise<void>;
45
44
  setRuntimeConfigFile(runtimeConfigFile?: string): void;
46
45
  private ensureDirectories;
@@ -1,7 +1,7 @@
1
- import { confirm, isCancel, select } from '@clack/prompts';
2
- import { ux } from '@oclif/core';
3
1
  import * as fs from 'node:fs';
4
2
  import path from 'node:path';
3
+ import { confirm, isCancel, select } from '@clack/prompts';
4
+ import { ux } from '@oclif/core';
5
5
  import { Value } from 'typebox/value';
6
6
  import { cliConfigSchema } from '../config/config.schema.js';
7
7
  import { DEFAULT_USER_CONFIG_FILE, DEFAULT_USER_CONFIG_NAME, DIR_ACCESS_PERMS, FILE_ACCESS_PERMS, } from '../constants.js';
@@ -9,11 +9,10 @@ import { getConfigName } from '../utils/helper.js';
9
9
  export class ConfigFileManager {
10
10
  logger;
11
11
  static CONFIG_FILE = 'config.json';
12
- static CONFIGS_DIR = 'configs';
12
+ static CONFIGS_DIR = 'accounts';
13
13
  configDir;
14
14
  configFilePath;
15
15
  configs = {
16
- configs: [],
17
16
  currentConfig: undefined,
18
17
  };
19
18
  configsDir;
@@ -31,13 +30,7 @@ export class ConfigFileManager {
31
30
  this.ux = options.ux ?? ux;
32
31
  this.runtimeConfigFile = options.runtimeConfigFile;
33
32
  }
34
- async addConfig(configName) {
35
- if (!this.configs.configs.includes(configName)) {
36
- this.configs.configs.push(configName);
37
- await this.save();
38
- }
39
- }
40
- async createConfig(configFileName, name, url) {
33
+ async createConfig(configFileName, name, url, account) {
41
34
  const configPath = path.join(this.configsDir, configFileName);
42
35
  if (fs.existsSync(configPath)) {
43
36
  throw new Error(`Configuration file already exists: ${configFileName}`);
@@ -46,12 +39,14 @@ export class ConfigFileManager {
46
39
  if (url) {
47
40
  config.providerUrl = url;
48
41
  }
42
+ if (account) {
43
+ config.account = account;
44
+ }
49
45
  fs.writeFileSync(configPath, JSON.stringify(config, undefined, 2), {
50
46
  encoding: 'utf8',
51
47
  flag: 'w',
52
48
  mode: FILE_ACCESS_PERMS,
53
49
  });
54
- await this.addConfig(configFileName);
55
50
  this.logger.info({ configFileName, name, url }, 'Created new configuration');
56
51
  }
57
52
  async deleteConfig(configName) {
@@ -71,7 +66,7 @@ export class ConfigFileManager {
71
66
  }
72
67
  let configToDelete;
73
68
  if (name) {
74
- const config = configs.find(c => c.name === name);
69
+ const config = configs.find((c) => c.name === name);
75
70
  if (!config) {
76
71
  this.ux.error(`Configuration not found: ${name}`);
77
72
  }
@@ -80,7 +75,7 @@ export class ConfigFileManager {
80
75
  else {
81
76
  const selection = await this.selectPrompt({
82
77
  message: 'Select configuration to delete:',
83
- options: configs.map(config => ({
78
+ options: configs.map((config) => ({
84
79
  label: config.name,
85
80
  value: config.file,
86
81
  })),
@@ -91,7 +86,7 @@ export class ConfigFileManager {
91
86
  }
92
87
  configToDelete = selection;
93
88
  }
94
- const configToDeleteData = configs.find(c => c.file === configToDelete);
89
+ const configToDeleteData = configs.find((c) => c.file === configToDelete);
95
90
  const displayName = configToDeleteData?.name || configToDelete;
96
91
  if (!force) {
97
92
  const confirmed = await this.confirmPrompt({
@@ -108,12 +103,12 @@ export class ConfigFileManager {
108
103
  this.ux.stdout(`Successfully deleted configuration: ${displayName}`);
109
104
  const newCurrent = this.getCurrentConfigFile();
110
105
  if (newCurrent) {
111
- const newCurrentConfig = configs.find(c => c.file === newCurrent);
106
+ const newCurrentConfig = configs.find((c) => c.file === newCurrent);
112
107
  this.ux.stdout(`Current configuration is now: ${newCurrentConfig?.name || newCurrent}`);
113
108
  }
114
109
  else {
115
110
  this.ux.stdout('No configurations remaining');
116
- this.ux.stdout('Create a new configuration with: sp config create --name "Config Name" or sp auth login');
111
+ this.ux.stdout('Create a new account with: sp account login --name "Account Name" or sp auth login');
117
112
  }
118
113
  }
119
114
  catch (error) {
@@ -138,10 +133,19 @@ export class ConfigFileManager {
138
133
  return this.configsDir;
139
134
  }
140
135
  getConfigs() {
141
- return [...this.configs.configs];
136
+ if (!fs.existsSync(this.configsDir)) {
137
+ return [];
138
+ }
139
+ return fs.readdirSync(this.configsDir).filter((file) => file.endsWith('.config.json'));
142
140
  }
143
141
  getConfigsWithNames() {
144
- return this.configs.configs.map(configFile => {
142
+ if (!fs.existsSync(this.configsDir)) {
143
+ return [];
144
+ }
145
+ const configFiles = fs
146
+ .readdirSync(this.configsDir)
147
+ .filter((file) => file.endsWith('.config.json'));
148
+ return configFiles.map((configFile) => {
145
149
  const configPath = path.join(this.configsDir, configFile);
146
150
  let name = configFile;
147
151
  try {
@@ -218,7 +222,6 @@ export class ConfigFileManager {
218
222
  }
219
223
  fs.copyFileSync(sourcePath, targetPath);
220
224
  fs.chmodSync(targetPath, FILE_ACCESS_PERMS);
221
- await this.addConfig(targetFileName);
222
225
  this.logger.info({ sourcePath, targetFileName }, 'Imported configuration');
223
226
  return targetFileName;
224
227
  }
@@ -231,12 +234,10 @@ export class ConfigFileManager {
231
234
  await this.load();
232
235
  }
233
236
  async removeConfig(configName) {
234
- const index = this.configs.configs.indexOf(configName);
235
- if (index !== -1) {
236
- this.configs.configs.splice(index, 1);
237
- if (this.configs.currentConfig === configName) {
238
- this.configs.currentConfig = this.configs.configs[0];
239
- }
237
+ if (this.configs.currentConfig === configName) {
238
+ const configs = this.getConfigs();
239
+ const remainingConfigs = configs.filter((c) => c !== configName);
240
+ this.configs.currentConfig = remainingConfigs.length > 0 ? remainingConfigs[0] : undefined;
240
241
  await this.save();
241
242
  }
242
243
  }
@@ -245,9 +246,6 @@ export class ConfigFileManager {
245
246
  if (!fs.existsSync(configPath)) {
246
247
  throw new Error(`Configuration file not found: ${configName}`);
247
248
  }
248
- if (!this.configs.configs.includes(configName)) {
249
- this.configs.configs.push(configName);
250
- }
251
249
  this.configs.currentConfig = configName;
252
250
  await this.save();
253
251
  }
@@ -256,10 +254,16 @@ export class ConfigFileManager {
256
254
  }
257
255
  ensureDirectories() {
258
256
  if (!fs.existsSync(this.configDir)) {
259
- fs.mkdirSync(this.configDir, { mode: DIR_ACCESS_PERMS, recursive: true });
257
+ fs.mkdirSync(this.configDir, {
258
+ mode: DIR_ACCESS_PERMS,
259
+ recursive: true,
260
+ });
260
261
  }
261
262
  if (!fs.existsSync(this.configsDir)) {
262
- fs.mkdirSync(this.configsDir, { mode: DIR_ACCESS_PERMS, recursive: true });
263
+ fs.mkdirSync(this.configsDir, {
264
+ mode: DIR_ACCESS_PERMS,
265
+ recursive: true,
266
+ });
263
267
  }
264
268
  }
265
269
  async load() {
@@ -277,7 +281,6 @@ export class ConfigFileManager {
277
281
  catch (error) {
278
282
  this.logger.error({ err: error }, 'Failed to load config manager file, using defaults');
279
283
  this.configs = {
280
- configs: [],
281
284
  currentConfig: undefined,
282
285
  };
283
286
  await this.save();
@@ -1,6 +1,6 @@
1
- import pino from 'pino';
2
- import { Auth, CliConfig } from '../config/config.schema.js';
3
- import { IConfigManager } from '../interfaces/config-manager.interface.js';
1
+ import type pino from 'pino';
2
+ import type { Auth, CliConfig } from '../config/config.schema.js';
3
+ import type { IConfigManager } from '../interfaces/config-manager.interface.js';
4
4
  export declare class ConfigManager implements IConfigManager {
5
5
  private readonly configFile;
6
6
  private readonly logger;
@@ -8,14 +8,14 @@ export declare class ConfigManager implements IConfigManager {
8
8
  private readonly configDir;
9
9
  constructor(configFile: string, logger: pino.BaseLogger);
10
10
  get<K extends keyof CliConfig, V extends CliConfig[K]>(key: K): Promise<undefined | V>;
11
- getConfig(): CliConfig;
11
+ private getConfig;
12
12
  getCookies(): Promise<unknown>;
13
13
  getCredentials(): Promise<{
14
14
  accessKey: string;
15
15
  } | undefined>;
16
16
  init(): Promise<void>;
17
17
  load(): Promise<CliConfig>;
18
- makeBackup(): void;
18
+ private makeBackup;
19
19
  save(): Promise<void>;
20
20
  set<K extends keyof CliConfig, V extends CliConfig[K]>(key: K, value: V): Promise<void>;
21
21
  setCookies(cookies: unknown): Promise<void>;
@@ -1,6 +1,6 @@
1
- import { ux } from '@oclif/core';
2
1
  import * as fs from 'node:fs';
3
2
  import path from 'node:path';
3
+ import { ux } from '@oclif/core';
4
4
  import { DIR_ACCESS_PERMS, FILE_ACCESS_PERMS } from '../constants.js';
5
5
  import { ConfigurationNotFoundError } from '../errors.js';
6
6
  export class ConfigManager {
@@ -62,7 +62,10 @@ export class ConfigManager {
62
62
  }
63
63
  }
64
64
  async save() {
65
- fs.mkdirSync(this.configDir, { mode: DIR_ACCESS_PERMS, recursive: true });
65
+ fs.mkdirSync(this.configDir, {
66
+ mode: DIR_ACCESS_PERMS,
67
+ recursive: true,
68
+ });
66
69
  this.logger.debug({ configFile: this.getConfigPath() }, 'Saving config file');
67
70
  fs.writeFileSync(this.getConfigPath(), JSON.stringify(this.config, undefined, ' '), {
68
71
  encoding: 'utf8',
@@ -1,6 +1,6 @@
1
1
  import type { MiddlewareFn, ProviderClient } from '@super-protocol/provider-client';
2
2
  import type pino from 'pino';
3
- import { type Auth } from '../config/config.schema.js';
3
+ import type { Auth } from '../config/config.schema.js';
4
4
  interface CredentialsStorage {
5
5
  getCredentials(): Promise<Auth | undefined>;
6
6
  setCredentials(auth: Auth): void;