@super-protocol/sp-cli 0.0.6 → 0.0.8
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 +116 -234
- package/dist/commands/account/base.d.ts +19 -0
- package/dist/commands/account/base.js +42 -0
- package/dist/commands/account/forget.d.ts +14 -0
- package/dist/commands/account/forget.js +49 -0
- package/dist/commands/account/get-sppi.d.ts +2 -2
- package/dist/commands/account/get-sppi.js +8 -13
- package/dist/commands/account/info.d.ts +5 -2
- package/dist/commands/account/info.js +53 -3
- package/dist/commands/account/list.d.ts +9 -0
- package/dist/commands/{config → account}/list.js +16 -9
- package/dist/commands/account/login.d.ts +35 -0
- package/dist/commands/account/login.js +249 -0
- package/dist/commands/account/switch.d.ts +12 -0
- package/dist/commands/account/switch.js +40 -0
- package/dist/commands/base.d.ts +4 -3
- package/dist/commands/base.js +99 -13
- package/dist/commands/files/download.js +13 -5
- package/dist/commands/files/upload.js +11 -7
- package/dist/commands/storage/base.d.ts +2 -2
- package/dist/commands/storage/base.js +11 -11
- package/dist/commands/storage/create.js +1 -1
- package/dist/commands/storage/select.js +6 -8
- package/dist/commands/storage/show.js +2 -4
- package/dist/commands/storage/update.js +39 -22
- package/dist/commands/workflows/extend-lease.d.ts +1 -1
- package/dist/commands/workflows/extend-lease.js +21 -13
- package/dist/config/config-file.schema.d.ts +1 -2
- package/dist/config/config-file.schema.js +0 -1
- package/dist/config/config.schema.d.ts +1 -1
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/hooks/finally/shutdown-blockchain.d.ts +1 -1
- package/dist/hooks/finally/shutdown-blockchain.js +1 -1
- package/dist/hooks/finally/unlock-config.d.ts +3 -0
- package/dist/hooks/finally/unlock-config.js +5 -0
- package/dist/hooks/init/init-container.d.ts +1 -1
- package/dist/hooks/init/init-container.js +2 -3
- package/dist/hooks/init/lock-config.d.ts +3 -0
- package/dist/hooks/init/lock-config.js +19 -0
- package/dist/hooks/prerun/auth.d.ts +3 -0
- package/dist/hooks/prerun/auth.js +70 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interfaces/account-manager.interface.d.ts +1 -1
- package/dist/interfaces/config-manager.interface.d.ts +2 -2
- package/dist/lib/cli-instance-lock.d.ts +2 -0
- package/dist/lib/cli-instance-lock.js +37 -0
- package/dist/lib/container.d.ts +6 -4
- package/dist/lib/container.js +108 -38
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +4 -1
- package/dist/managers/account-manager.d.ts +7 -8
- package/dist/managers/account-manager.js +20 -45
- package/dist/managers/config-file-manager.d.ts +6 -7
- package/dist/managers/config-file-manager.js +35 -32
- package/dist/managers/config-manager.d.ts +5 -5
- package/dist/managers/config-manager.js +5 -2
- package/dist/middlewares/auth-middleware.d.ts +1 -1
- package/dist/services/auth.service.d.ts +10 -15
- package/dist/services/auth.service.js +71 -5
- package/dist/services/storage.service.d.ts +3 -3
- package/dist/services/storage.service.js +46 -19
- package/dist/utils/helper.d.ts +1 -0
- package/dist/utils/helper.js +15 -1
- package/dist/utils/prompt-flags.d.ts +20 -0
- package/dist/utils/prompt-flags.js +121 -0
- package/dist/utils/prompt.service.d.ts +16 -0
- package/dist/utils/prompt.service.js +75 -0
- package/dist/utils/tty.d.ts +1 -0
- package/dist/utils/tty.js +3 -0
- package/oclif.manifest.json +206 -242
- package/package.json +17 -24
- package/dist/commands/auth/login.d.ts +0 -12
- package/dist/commands/auth/login.js +0 -50
- package/dist/commands/auth/me.d.ts +0 -5
- package/dist/commands/auth/me.js +0 -16
- package/dist/commands/config/add.d.ts +0 -13
- package/dist/commands/config/add.js +0 -73
- package/dist/commands/config/base.d.ts +0 -16
- package/dist/commands/config/base.js +0 -78
- package/dist/commands/config/create.d.ts +0 -11
- package/dist/commands/config/create.js +0 -41
- package/dist/commands/config/delete.d.ts +0 -10
- package/dist/commands/config/delete.js +0 -25
- package/dist/commands/config/index.d.ts +0 -6
- package/dist/commands/config/index.js +0 -22
- package/dist/commands/config/list.d.ts +0 -6
- package/dist/commands/config/show.d.ts +0 -6
- package/dist/commands/config/show.js +0 -10
- package/dist/commands/config/use.d.ts +0 -6
- package/dist/commands/config/use.js +0 -27
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AppContainer } from '../../lib/container.js';
|
|
2
|
-
const hook = async
|
|
3
|
-
AppContainer
|
|
4
|
-
.initialize(process.cwd(), opts.config);
|
|
2
|
+
const hook = async (opts) => {
|
|
3
|
+
AppContainer.initialize(process.cwd(), opts.config);
|
|
5
4
|
};
|
|
6
5
|
export default hook;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { acquireCliInstanceLock } from '../../lib/cli-instance-lock.js';
|
|
4
|
+
import { ConfigFileManager } from '../../managers/config-file-manager.js';
|
|
5
|
+
const hook = async (opts) => {
|
|
6
|
+
const { context, config } = opts;
|
|
7
|
+
const lockFile = path.join(config.configDir, ConfigFileManager.CONFIG_FILE);
|
|
8
|
+
mkdirSync(config.configDir, { recursive: true });
|
|
9
|
+
try {
|
|
10
|
+
await acquireCliInstanceLock(lockFile);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (context) {
|
|
14
|
+
context.error(error, { exit: 1 });
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export default hook;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BaseCommand } from '../../commands/base.js';
|
|
2
|
+
import { AppContainer } from '../../lib/container.js';
|
|
3
|
+
import logger from '../../logger.js';
|
|
4
|
+
import { AuthService } from '../../services/auth.service.js';
|
|
5
|
+
const isBaseCommandClass = (commandClass) => commandClass.prototype instanceof BaseCommand;
|
|
6
|
+
const getConfigFlag = (commandClass, argv) => {
|
|
7
|
+
if (!isBaseCommandClass(commandClass)) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
//Fix Parser.parse throws error Nonexistent flag we dont have the way to ignore it
|
|
11
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
12
|
+
const token = argv[index];
|
|
13
|
+
if (!token) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (token === '--config') {
|
|
17
|
+
const value = argv[index + 1];
|
|
18
|
+
return value && !value.startsWith('-') ? value : undefined;
|
|
19
|
+
}
|
|
20
|
+
if (token.startsWith('--config=')) {
|
|
21
|
+
const value = token.slice('--config='.length);
|
|
22
|
+
return value || undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
};
|
|
27
|
+
const hook = async (opts) => {
|
|
28
|
+
const { Command, config, context } = opts;
|
|
29
|
+
const commandId = Command.id;
|
|
30
|
+
const CommandClass = Command;
|
|
31
|
+
if (CommandClass.authenticate === false) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const pinoLogger = logger.getPino();
|
|
35
|
+
pinoLogger.info('Prerun hook auth called');
|
|
36
|
+
try {
|
|
37
|
+
const configFile = getConfigFlag(CommandClass, opts.argv ?? []);
|
|
38
|
+
const container = configFile
|
|
39
|
+
? AppContainer.container.setupRuntimeConfig({ configFile })
|
|
40
|
+
: AppContainer.container;
|
|
41
|
+
await container
|
|
42
|
+
.initConfigFileManager()
|
|
43
|
+
.initConfigManager()
|
|
44
|
+
.initAccountManager()
|
|
45
|
+
.initProviderClient({ enableAuth: false, enableCookies: true })
|
|
46
|
+
.build();
|
|
47
|
+
const { configManager, accountManager, providerClient } = container;
|
|
48
|
+
const credentials = await configManager.get('auth');
|
|
49
|
+
if (!credentials?.accessKey) {
|
|
50
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
51
|
+
context.error('Authorization not found. Please run: sp account login', { exit: 1 });
|
|
52
|
+
}
|
|
53
|
+
const args = configFile ? ['--config', configFile] : [];
|
|
54
|
+
pinoLogger.info({ commandId }, 'Authorization not found, redirecting to account:login');
|
|
55
|
+
await config.runCommand('account:login', args);
|
|
56
|
+
}
|
|
57
|
+
const authService = new AuthService(accountManager, configManager, providerClient, pinoLogger);
|
|
58
|
+
await authService.auth();
|
|
59
|
+
pinoLogger.debug({ commandId }, 'Authentication successful');
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof Error && error.message.includes('not initialized')) {
|
|
63
|
+
pinoLogger.debug({ commandId, err: error }, 'Container not initialized, skipping auth');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
pinoLogger.error({ commandId, err: error }, 'Authentication failed in prerun hook');
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
export default hook;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Interfaces, run as oclifRun } from '@oclif/core';
|
|
1
|
+
import { type Interfaces, run as oclifRun } from '@oclif/core';
|
|
2
2
|
export declare const run: (argv: string[], loadOptions?: Interfaces.LoadOptions | URL) => ReturnType<typeof oclifRun>;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CliConfig } from '../config/config.schema.js';
|
|
2
|
-
import { IManager } from './manager.interface.js';
|
|
1
|
+
import type { CliConfig } from '../config/config.schema.js';
|
|
2
|
+
import type { IManager } from './manager.interface.js';
|
|
3
3
|
export interface IConfigManager extends IManager {
|
|
4
4
|
get<K extends keyof CliConfig, V extends CliConfig[K]>(key: K): Promise<undefined | V>;
|
|
5
5
|
load(): Promise<CliConfig>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { lock } from 'proper-lockfile';
|
|
2
|
+
let release;
|
|
3
|
+
let locked = false;
|
|
4
|
+
const isLockHeldError = (error) => Boolean(error &&
|
|
5
|
+
typeof error === 'object' &&
|
|
6
|
+
'code' in error &&
|
|
7
|
+
error.code === 'ELOCKED');
|
|
8
|
+
export const acquireCliInstanceLock = async (lockTarget) => {
|
|
9
|
+
if (locked) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
release = await lock(lockTarget, {
|
|
14
|
+
realpath: false,
|
|
15
|
+
retries: 0,
|
|
16
|
+
stale: 30_000,
|
|
17
|
+
});
|
|
18
|
+
locked = true;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (isLockHeldError(error)) {
|
|
22
|
+
const lockHeldError = Object.assign(new Error('Another instance of spcli is already running.'), { code: 'ELOCKED' });
|
|
23
|
+
throw lockHeldError;
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export const releaseCliInstanceLock = async () => {
|
|
29
|
+
if (!release) {
|
|
30
|
+
locked = false;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const currentRelease = release;
|
|
34
|
+
release = undefined;
|
|
35
|
+
locked = false;
|
|
36
|
+
await currentRelease();
|
|
37
|
+
};
|
package/dist/lib/container.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Config } from '@oclif/core';
|
|
2
|
-
import { ProviderClient } from '@super-protocol/provider-client';
|
|
1
|
+
import type { Config } from '@oclif/core';
|
|
2
|
+
import { type ProviderClient } from '@super-protocol/provider-client';
|
|
3
3
|
import { AccountManager, ConfigFileManager, ConfigManager } from '../managers/index.js';
|
|
4
4
|
interface RuntimeConfig {
|
|
5
5
|
configFile?: string;
|
|
@@ -12,9 +12,10 @@ export declare class AppContainer {
|
|
|
12
12
|
private _configFileManager?;
|
|
13
13
|
private _configManager?;
|
|
14
14
|
private _providerClient?;
|
|
15
|
-
private
|
|
15
|
+
private providerClientOptions?;
|
|
16
16
|
private readonly initQueue;
|
|
17
17
|
private logger;
|
|
18
|
+
private providerClientInitToken;
|
|
18
19
|
private runtimeConfigFile?;
|
|
19
20
|
private constructor();
|
|
20
21
|
static initialize(currentDir: string, config: Config): AppContainer;
|
|
@@ -28,12 +29,13 @@ export declare class AppContainer {
|
|
|
28
29
|
initBlockchainConnector(): this;
|
|
29
30
|
initConfigFileManager(rebuild?: boolean): this;
|
|
30
31
|
initConfigManager(rebuild?: boolean): this;
|
|
31
|
-
initProviderClient({ enableAuth, enableCookies, rebuild }?: {
|
|
32
|
+
initProviderClient({ enableAuth, enableCookies, rebuild, }?: {
|
|
32
33
|
enableAuth?: boolean;
|
|
33
34
|
enableCookies?: boolean;
|
|
34
35
|
rebuild?: boolean;
|
|
35
36
|
}): this;
|
|
36
37
|
setupRuntimeConfig(config: RuntimeConfig): this;
|
|
38
|
+
private getProviderClientForBootstrap;
|
|
37
39
|
private queueInit;
|
|
38
40
|
private waitFor;
|
|
39
41
|
}
|
package/dist/lib/container.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
86
|
-
const { data, error } = await
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
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 (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
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, [
|
|
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
|
-
|
|
17
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
64
|
-
this.privateKey = this.account.privateKey;
|
|
57
|
+
await this.loadAccount();
|
|
65
58
|
}
|
|
66
59
|
catch (error) {
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
if (!(error instanceof AccountNotFoundError)) {
|
|
61
|
+
this.logger.warn({ err: error }, 'Unexpected error loading account');
|
|
62
|
+
}
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
|
-
async
|
|
72
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
return account;
|
|
68
|
+
this.account = Value.Parse(accountSchema, account);
|
|
69
|
+
this.privateKey = this.account.privateKey;
|
|
93
70
|
}
|
|
94
71
|
catch (error) {
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
42
|
+
private removeConfig;
|
|
44
43
|
setCurrentConfig(configName: string): Promise<void>;
|
|
45
44
|
setRuntimeConfigFile(runtimeConfigFile?: string): void;
|
|
46
45
|
private ensureDirectories;
|