@super-protocol/sp-cli 0.0.2-alpha.1 → 0.0.2-beta.2
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 +144 -49
- package/dist/commands/account/info.d.ts +21 -0
- package/dist/commands/account/info.js +43 -0
- package/dist/commands/auth/login.d.ts +1 -10
- package/dist/commands/auth/login.js +23 -75
- package/dist/commands/base.d.ts +2 -4
- package/dist/commands/base.js +8 -10
- package/dist/commands/config/add.js +9 -5
- package/dist/commands/config/base.d.ts +4 -3
- package/dist/commands/config/base.js +12 -14
- package/dist/commands/config/create.js +4 -4
- package/dist/commands/config/list.js +2 -2
- package/dist/commands/config/use.js +5 -3
- package/dist/commands/storage/base.d.ts +8 -0
- package/dist/commands/storage/base.js +12 -0
- package/dist/commands/storage/create.d.ts +15 -0
- package/dist/commands/storage/create.js +169 -0
- package/dist/commands/storage/select.d.ts +9 -0
- package/dist/commands/storage/select.js +46 -0
- package/dist/commands/storage/update.d.ts +16 -0
- package/dist/commands/storage/update.js +244 -0
- package/dist/config/config.schema.d.ts +1 -0
- package/dist/config/config.schema.js +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/lib/container.d.ts +6 -7
- package/dist/lib/container.js +26 -26
- package/dist/managers/account-manager.js +12 -2
- package/dist/managers/config-file-manager.d.ts +1 -1
- package/dist/managers/config-file-manager.js +12 -7
- package/dist/middlewares/auth-middleware.js +5 -1
- package/dist/services/auth.service.d.ts +24 -0
- package/dist/services/auth.service.js +93 -0
- package/dist/services/storage.service.d.ts +47 -0
- package/dist/services/storage.service.js +179 -0
- package/oclif.manifest.json +217 -137
- package/package.json +9 -3
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { confirm, password, select, text, } from '@clack/prompts';
|
|
2
|
+
import { Flags } from '@oclif/core';
|
|
3
|
+
import { StorageType } from '@super-protocol/provider-client';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { StoragesEmptyError } from '../../services/storage.service.js';
|
|
7
|
+
import { BaseStorageCommand } from './base.js';
|
|
8
|
+
export default class StorageUpdate extends BaseStorageCommand {
|
|
9
|
+
static description = 'Update the configuration of an existing storage.';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> storage update --id=2de3e3a4-0000-1111-2222-333344445555 --fromFile ./storage-update.json',
|
|
12
|
+
'<%= config.bin %> storage update --id=2de3e3a4-0000-1111-2222-333344445555',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
fromFile: Flags.string({
|
|
16
|
+
char: 'f',
|
|
17
|
+
description: 'Path to a JSON file that contains UpdateStorageDto payload.',
|
|
18
|
+
}),
|
|
19
|
+
id: Flags.string({
|
|
20
|
+
char: 'i',
|
|
21
|
+
description: 'Storage ID to update',
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { flags } = await this.parse(StorageUpdate);
|
|
26
|
+
try {
|
|
27
|
+
const shouldRequestStorages = !flags.fromFile || !flags.id;
|
|
28
|
+
const storages = shouldRequestStorages ? await this.storageService.requestStorages() : undefined;
|
|
29
|
+
let storageId = flags.id;
|
|
30
|
+
if (!storageId) {
|
|
31
|
+
const options = (storages || []).filter(cp => !cp.isCentralized).map(storage => ({
|
|
32
|
+
label: `${storage.id} (${storage.storageType}) ${storage.bucket}/${storage.prefix} `,
|
|
33
|
+
value: storage.id,
|
|
34
|
+
}));
|
|
35
|
+
if (!options || options.length === 0) {
|
|
36
|
+
throw new StoragesEmptyError('No storages available to update');
|
|
37
|
+
}
|
|
38
|
+
storageId = this.ensurePromptValue(await select({
|
|
39
|
+
message: 'Select storage to update',
|
|
40
|
+
options,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
if (!storageId) {
|
|
44
|
+
this.error('Storage ID is required');
|
|
45
|
+
}
|
|
46
|
+
const storageToUpdate = storages?.find(storage => storage.id === storageId);
|
|
47
|
+
if (flags.id && storages && !storageToUpdate) {
|
|
48
|
+
this.error(`Storage with ID ${storageId} not found`);
|
|
49
|
+
}
|
|
50
|
+
const updatePayload = flags.fromFile
|
|
51
|
+
? await this.loadStorageFromFile(flags.fromFile)
|
|
52
|
+
: await this.promptStorageUpdate(storageToUpdate);
|
|
53
|
+
await this.storageService.updateStorage(storageId, updatePayload);
|
|
54
|
+
this.log(`Storage updated: ${storageId}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof StoragesEmptyError) {
|
|
58
|
+
this.error('No storages available. Run "sp storage create" first.');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
ensureNonEmptyString(value, fieldName) {
|
|
66
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
67
|
+
this.error(`${fieldName} must be a non-empty string`);
|
|
68
|
+
}
|
|
69
|
+
return value.trim();
|
|
70
|
+
}
|
|
71
|
+
ensureUpdatePayload(payload) {
|
|
72
|
+
if (!payload || typeof payload !== 'object') {
|
|
73
|
+
this.error('Storage update definition must be an object');
|
|
74
|
+
}
|
|
75
|
+
const updateFields = ['bucket', 'prefix', 'storageType', 's3Credentials', 'storjCredentials'];
|
|
76
|
+
const hasUpdates = updateFields.some(key => payload[key] !== undefined);
|
|
77
|
+
if (!hasUpdates) {
|
|
78
|
+
this.error('Update payload must include at least one property');
|
|
79
|
+
}
|
|
80
|
+
if (payload.storageType && !Object.values(StorageType).includes(payload.storageType)) {
|
|
81
|
+
this.error(`Unsupported storage type: ${payload.storageType}`);
|
|
82
|
+
}
|
|
83
|
+
if (payload.s3Credentials) {
|
|
84
|
+
const { readAccessKeyId, readSecretAccessKey, region, writeAccessKeyId, writeSecretAccessKey, } = payload.s3Credentials;
|
|
85
|
+
if (!readAccessKeyId || !readSecretAccessKey || !region || !writeAccessKeyId || !writeSecretAccessKey) {
|
|
86
|
+
this.error('S3 credentials must include readAccessKeyId, readSecretAccessKey, region, writeAccessKeyId and writeSecretAccessKey');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (payload.storjCredentials) {
|
|
90
|
+
const { readAccessToken, writeAccessToken } = payload.storjCredentials;
|
|
91
|
+
if (!readAccessToken || !writeAccessToken) {
|
|
92
|
+
this.error('StorJ credentials must include readAccessToken and writeAccessToken');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const sanitized = {};
|
|
96
|
+
if (payload.bucket !== undefined) {
|
|
97
|
+
sanitized.bucket = this.ensureNonEmptyString(payload.bucket, 'Bucket');
|
|
98
|
+
}
|
|
99
|
+
if (payload.prefix !== undefined) {
|
|
100
|
+
sanitized.prefix = this.ensureNonEmptyString(payload.prefix, 'Prefix');
|
|
101
|
+
}
|
|
102
|
+
if (payload.storageType) {
|
|
103
|
+
sanitized.storageType = payload.storageType;
|
|
104
|
+
}
|
|
105
|
+
if (payload.s3Credentials) {
|
|
106
|
+
sanitized.s3Credentials = {
|
|
107
|
+
readAccessKeyId: this.ensureNonEmptyString(payload.s3Credentials.readAccessKeyId, 'S3 credential "readAccessKeyId"'),
|
|
108
|
+
readSecretAccessKey: this.ensureNonEmptyString(payload.s3Credentials.readSecretAccessKey, 'S3 credential "readSecretAccessKey"'),
|
|
109
|
+
region: this.ensureNonEmptyString(payload.s3Credentials.region, 'S3 credential "region"'),
|
|
110
|
+
writeAccessKeyId: this.ensureNonEmptyString(payload.s3Credentials.writeAccessKeyId, 'S3 credential "writeAccessKeyId"'),
|
|
111
|
+
writeSecretAccessKey: this.ensureNonEmptyString(payload.s3Credentials.writeSecretAccessKey, 'S3 credential "writeSecretAccessKey"'),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (payload.storjCredentials) {
|
|
115
|
+
sanitized.storjCredentials = {
|
|
116
|
+
readAccessToken: this.ensureNonEmptyString(payload.storjCredentials.readAccessToken, 'StorJ credential "readAccessToken"'),
|
|
117
|
+
writeAccessToken: this.ensureNonEmptyString(payload.storjCredentials.writeAccessToken, 'StorJ credential "writeAccessToken"'),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return sanitized;
|
|
121
|
+
}
|
|
122
|
+
async loadStorageFromFile(filePath) {
|
|
123
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(this.currentDir, filePath);
|
|
124
|
+
try {
|
|
125
|
+
const fileContent = await fs.readFile(absolutePath, 'utf8');
|
|
126
|
+
const parsed = JSON.parse(fileContent);
|
|
127
|
+
return this.ensureUpdatePayload(parsed);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
this.error(`Failed to load storage update definition: ${error instanceof Error ? error.message : String(error)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async promptS3Credentials() {
|
|
134
|
+
const region = this.ensurePromptValue(await text({
|
|
135
|
+
message: 'AWS region',
|
|
136
|
+
validate(value) {
|
|
137
|
+
return value ? undefined : 'Region is required';
|
|
138
|
+
},
|
|
139
|
+
})).trim();
|
|
140
|
+
const readAccessKeyId = this.ensurePromptValue(await text({
|
|
141
|
+
message: 'Read access key ID',
|
|
142
|
+
validate(value) {
|
|
143
|
+
return value ? undefined : 'Read access key ID is required';
|
|
144
|
+
},
|
|
145
|
+
})).trim();
|
|
146
|
+
const readSecretAccessKey = this.ensurePromptValue(await password({
|
|
147
|
+
message: 'Read secret access key',
|
|
148
|
+
validate(value) {
|
|
149
|
+
return value ? undefined : 'Read secret access key is required';
|
|
150
|
+
},
|
|
151
|
+
})).trim();
|
|
152
|
+
const writeAccessKeyId = this.ensurePromptValue(await text({
|
|
153
|
+
message: 'Write access key ID',
|
|
154
|
+
validate(value) {
|
|
155
|
+
return value ? undefined : 'Write access key ID is required';
|
|
156
|
+
},
|
|
157
|
+
})).trim();
|
|
158
|
+
const writeSecretAccessKey = this.ensurePromptValue(await password({
|
|
159
|
+
message: 'Write secret access key',
|
|
160
|
+
validate(value) {
|
|
161
|
+
return value ? undefined : 'Write secret access key is required';
|
|
162
|
+
},
|
|
163
|
+
})).trim();
|
|
164
|
+
return {
|
|
165
|
+
readAccessKeyId,
|
|
166
|
+
readSecretAccessKey,
|
|
167
|
+
region,
|
|
168
|
+
writeAccessKeyId,
|
|
169
|
+
writeSecretAccessKey,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async promptStorageUpdate(existingStorage) {
|
|
173
|
+
const payload = {};
|
|
174
|
+
const bucket = this.ensurePromptValue(await text({
|
|
175
|
+
defaultValue: existingStorage?.bucket ?? '',
|
|
176
|
+
message: 'Bucket name (leave empty to keep current)',
|
|
177
|
+
})).trim();
|
|
178
|
+
if (bucket) {
|
|
179
|
+
payload.bucket = bucket;
|
|
180
|
+
}
|
|
181
|
+
const prefix = this.ensurePromptValue(await text({
|
|
182
|
+
defaultValue: existingStorage?.prefix ?? '',
|
|
183
|
+
message: 'Prefix (leave empty to keep current)',
|
|
184
|
+
})).trim();
|
|
185
|
+
if (prefix) {
|
|
186
|
+
payload.prefix = prefix;
|
|
187
|
+
}
|
|
188
|
+
let newStorageType;
|
|
189
|
+
const shouldChangeType = this.ensurePromptValue(await confirm({
|
|
190
|
+
initialValue: false,
|
|
191
|
+
message: existingStorage
|
|
192
|
+
? `Change storage type? (current: ${existingStorage.storageType})`
|
|
193
|
+
: 'Change storage type?',
|
|
194
|
+
}));
|
|
195
|
+
if (shouldChangeType) {
|
|
196
|
+
newStorageType = this.ensurePromptValue(await select({
|
|
197
|
+
message: 'Select new storage type',
|
|
198
|
+
options: [
|
|
199
|
+
{ label: 'Amazon S3', value: StorageType.S3 },
|
|
200
|
+
{ label: 'StorJ', value: StorageType.StorJ },
|
|
201
|
+
],
|
|
202
|
+
}));
|
|
203
|
+
payload.storageType = newStorageType;
|
|
204
|
+
}
|
|
205
|
+
const effectiveType = newStorageType ?? existingStorage?.storageType;
|
|
206
|
+
const credentialsRequired = Boolean(newStorageType);
|
|
207
|
+
if (effectiveType) {
|
|
208
|
+
const updateCredentials = credentialsRequired || this.ensurePromptValue(await confirm({
|
|
209
|
+
initialValue: false,
|
|
210
|
+
message: `Update ${effectiveType} credentials?`,
|
|
211
|
+
}));
|
|
212
|
+
if (updateCredentials) {
|
|
213
|
+
if (effectiveType === StorageType.S3) {
|
|
214
|
+
payload.s3Credentials = await this.promptS3Credentials();
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
payload.storjCredentials = await this.promptStorJCredentials();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (Object.keys(payload).length === 0) {
|
|
222
|
+
this.error('No changes provided');
|
|
223
|
+
}
|
|
224
|
+
return this.ensureUpdatePayload(payload);
|
|
225
|
+
}
|
|
226
|
+
async promptStorJCredentials() {
|
|
227
|
+
const readAccessToken = this.ensurePromptValue(await password({
|
|
228
|
+
message: 'Read access token',
|
|
229
|
+
validate(value) {
|
|
230
|
+
return value ? undefined : 'Read access token is required';
|
|
231
|
+
},
|
|
232
|
+
})).trim();
|
|
233
|
+
const writeAccessToken = this.ensurePromptValue(await password({
|
|
234
|
+
message: 'Write access token',
|
|
235
|
+
validate(value) {
|
|
236
|
+
return value ? undefined : 'Write access token is required';
|
|
237
|
+
},
|
|
238
|
+
})).trim();
|
|
239
|
+
return {
|
|
240
|
+
readAccessToken,
|
|
241
|
+
writeAccessToken,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -17,6 +17,7 @@ export declare const cliConfigSchema: import("@sinclair/typebox").TObject<{
|
|
|
17
17
|
cookies: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
|
|
18
18
|
name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
19
19
|
providerUrl: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
20
|
+
selectedStorage: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
20
21
|
}>;
|
|
21
22
|
export type CliConfig = Static<typeof cliConfigSchema>;
|
|
22
23
|
export type Account = Static<typeof accountSchema>;
|
|
@@ -21,4 +21,5 @@ export const cliConfigSchema = Type.Object({
|
|
|
21
21
|
cookies: Type.Optional(Type.Unknown()),
|
|
22
22
|
name: Type.Optional(Type.String()),
|
|
23
23
|
providerUrl: Type.Optional(Type.String({ format: 'url' })),
|
|
24
|
+
selectedStorage: Type.Optional(Type.String({ maxLength: 36, minLength: 36 })),
|
|
24
25
|
});
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/errors.d.ts
CHANGED
package/dist/errors.js
CHANGED
package/dist/lib/container.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { ProviderClient } from '@super-protocol/provider-client';
|
|
|
3
3
|
import { AccountManager, ConfigFileManager, ConfigManager } from '../managers/index.js';
|
|
4
4
|
interface RuntimeConfig {
|
|
5
5
|
configFile?: string;
|
|
6
|
-
url?: string;
|
|
7
6
|
}
|
|
8
7
|
export declare class AppContainer {
|
|
9
8
|
readonly cwdDir: string;
|
|
@@ -17,7 +16,6 @@ export declare class AppContainer {
|
|
|
17
16
|
private readonly initQueue;
|
|
18
17
|
private logger;
|
|
19
18
|
private runtimeConfigFile?;
|
|
20
|
-
private runtimeProviderUrl?;
|
|
21
19
|
private constructor();
|
|
22
20
|
static initialize(currentDir: string, config: Config): AppContainer;
|
|
23
21
|
get accountManager(): AccountManager;
|
|
@@ -25,13 +23,14 @@ export declare class AppContainer {
|
|
|
25
23
|
get configManager(): ConfigManager;
|
|
26
24
|
static get container(): AppContainer;
|
|
27
25
|
get providerClient(): ProviderClient;
|
|
28
|
-
build(): Promise<
|
|
29
|
-
initAccountManager(): this;
|
|
30
|
-
initConfigFileManager(): this;
|
|
31
|
-
initConfigManager(): this;
|
|
32
|
-
initProviderClient({ enableAuth, enableCookies }?: {
|
|
26
|
+
build(): Promise<this>;
|
|
27
|
+
initAccountManager(rebuild?: boolean): this;
|
|
28
|
+
initConfigFileManager(rebuild?: boolean): this;
|
|
29
|
+
initConfigManager(rebuild?: boolean): this;
|
|
30
|
+
initProviderClient({ enableAuth, enableCookies, rebuild }?: {
|
|
33
31
|
enableAuth?: boolean;
|
|
34
32
|
enableCookies?: boolean;
|
|
33
|
+
rebuild?: boolean;
|
|
35
34
|
}): this;
|
|
36
35
|
setupRuntimeConfig(config: RuntimeConfig): this;
|
|
37
36
|
private queueInit;
|
package/dist/lib/container.js
CHANGED
|
@@ -17,7 +17,6 @@ export class AppContainer {
|
|
|
17
17
|
initQueue = new Map();
|
|
18
18
|
logger;
|
|
19
19
|
runtimeConfigFile;
|
|
20
|
-
runtimeProviderUrl;
|
|
21
20
|
constructor(cwdDir, oclifConfig) {
|
|
22
21
|
this.cwdDir = cwdDir;
|
|
23
22
|
this.oclifConfig = oclifConfig;
|
|
@@ -61,9 +60,10 @@ export class AppContainer {
|
|
|
61
60
|
}
|
|
62
61
|
async build() {
|
|
63
62
|
await Promise.all(this.initPromises);
|
|
63
|
+
return this;
|
|
64
64
|
}
|
|
65
|
-
initAccountManager() {
|
|
66
|
-
this.initConfigManager();
|
|
65
|
+
initAccountManager(rebuild = true) {
|
|
66
|
+
this.initConfigManager(rebuild);
|
|
67
67
|
return this.queueInit('accountManager', async () => {
|
|
68
68
|
await this.waitFor('configManager');
|
|
69
69
|
if (this._accountManager) {
|
|
@@ -73,9 +73,9 @@ export class AppContainer {
|
|
|
73
73
|
const accountManager = new AccountManager(this.configManager, this.logger);
|
|
74
74
|
await accountManager.init();
|
|
75
75
|
this._accountManager = accountManager;
|
|
76
|
-
});
|
|
76
|
+
}, rebuild);
|
|
77
77
|
}
|
|
78
|
-
initConfigFileManager() {
|
|
78
|
+
initConfigFileManager(rebuild = false) {
|
|
79
79
|
return this.queueInit('configFileManager', async () => {
|
|
80
80
|
if (this._configFileManager) {
|
|
81
81
|
return;
|
|
@@ -85,10 +85,10 @@ export class AppContainer {
|
|
|
85
85
|
});
|
|
86
86
|
await configFileManager.init();
|
|
87
87
|
this._configFileManager = configFileManager;
|
|
88
|
-
});
|
|
88
|
+
}, rebuild);
|
|
89
89
|
}
|
|
90
|
-
initConfigManager() {
|
|
91
|
-
this.initConfigFileManager();
|
|
90
|
+
initConfigManager(rebuild = false) {
|
|
91
|
+
this.initConfigFileManager(rebuild);
|
|
92
92
|
return this.queueInit('configManager', async () => {
|
|
93
93
|
await this.waitFor('configFileManager');
|
|
94
94
|
if (this._configManager) {
|
|
@@ -102,22 +102,32 @@ export class AppContainer {
|
|
|
102
102
|
const configManager = new ConfigManager(configFilePath, this.logger);
|
|
103
103
|
await configManager.init();
|
|
104
104
|
this._configManager = configManager;
|
|
105
|
-
});
|
|
105
|
+
}, rebuild);
|
|
106
106
|
}
|
|
107
|
-
initProviderClient({ enableAuth = true, enableCookies = true } = {}) {
|
|
107
|
+
initProviderClient({ enableAuth = true, enableCookies = true, rebuild = false } = {}) {
|
|
108
108
|
this.initConfigManager();
|
|
109
109
|
return this.queueInit('providerClient', async () => {
|
|
110
|
-
if (this._providerClient) {
|
|
110
|
+
if (this._providerClient && !rebuild) {
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
await this.waitFor('configManager');
|
|
114
|
-
const providerUrl =
|
|
114
|
+
const providerUrl = await this.configManager.get('providerUrl') || PROVIDER_URL;
|
|
115
115
|
this.logger.info('Initializing provider client');
|
|
116
116
|
const providerClient = createProviderClient({
|
|
117
117
|
baseUrl: providerUrl,
|
|
118
118
|
logger: this.logger,
|
|
119
119
|
middlewares: [requestIdMiddleware, loggerMiddleware],
|
|
120
120
|
});
|
|
121
|
+
if (enableCookies) {
|
|
122
|
+
this.logger.info('Initializing cookie middleware');
|
|
123
|
+
const cookiesMiddleware = await createCookieMiddleware(this.configManager, this.logger, providerUrl);
|
|
124
|
+
providerClient.use(cookiesMiddleware);
|
|
125
|
+
}
|
|
126
|
+
if (enableAuth) {
|
|
127
|
+
this.logger.info('Initializing auth middleware');
|
|
128
|
+
const authMiddleware = await createAuthMiddleware(this.configManager, providerClient, this.logger);
|
|
129
|
+
providerClient.use(authMiddleware);
|
|
130
|
+
}
|
|
121
131
|
providerClient.use({
|
|
122
132
|
onRequest: async ({ request }) => {
|
|
123
133
|
const req = request.clone();
|
|
@@ -128,28 +138,18 @@ export class AppContainer {
|
|
|
128
138
|
}
|
|
129
139
|
this.logger.debug({
|
|
130
140
|
body,
|
|
141
|
+
token: req.headers.get('Authorization'),
|
|
131
142
|
url: req.url,
|
|
132
143
|
}, 'Requesting');
|
|
133
144
|
},
|
|
134
145
|
});
|
|
135
|
-
if (enableCookies) {
|
|
136
|
-
this.logger.info('Initializing cookie middleware');
|
|
137
|
-
const cookiesMiddleware = await createCookieMiddleware(this.configManager, this.logger, providerUrl);
|
|
138
|
-
providerClient.use(cookiesMiddleware);
|
|
139
|
-
}
|
|
140
|
-
if (enableAuth) {
|
|
141
|
-
this.logger.info('Initializing auth middleware');
|
|
142
|
-
const authMiddleware = await createAuthMiddleware(this.configManager, providerClient, this.logger);
|
|
143
|
-
providerClient.use(authMiddleware);
|
|
144
|
-
}
|
|
145
146
|
this._providerClient = providerClient;
|
|
146
|
-
});
|
|
147
|
+
}, rebuild);
|
|
147
148
|
}
|
|
148
149
|
setupRuntimeConfig(config) {
|
|
149
150
|
if (this.initQueue.size > 0) {
|
|
150
151
|
throw new Error('Cannot change runtime config after initialization has started');
|
|
151
152
|
}
|
|
152
|
-
this.runtimeProviderUrl = config.url;
|
|
153
153
|
if (config.configFile) {
|
|
154
154
|
this.runtimeConfigFile = path.isAbsolute(config.configFile)
|
|
155
155
|
? config.configFile
|
|
@@ -160,8 +160,8 @@ export class AppContainer {
|
|
|
160
160
|
}
|
|
161
161
|
return this;
|
|
162
162
|
}
|
|
163
|
-
queueInit(name, task) {
|
|
164
|
-
if (!this.initQueue.has(name)) {
|
|
163
|
+
queueInit(name, task, force = false) {
|
|
164
|
+
if (!this.initQueue.has(name) || force) {
|
|
165
165
|
const promise = task();
|
|
166
166
|
this.initQueue.set(name, promise);
|
|
167
167
|
this.initPromises.push(promise);
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { confirm, password } from '@
|
|
7
|
+
import { confirm, isCancel, password } from '@clack/prompts';
|
|
8
8
|
import { ux } from '@oclif/core';
|
|
9
9
|
import { Value } from '@sinclair/typebox/value';
|
|
10
10
|
import { Retryable } from 'typescript-retry-decorator';
|
|
@@ -69,6 +69,9 @@ export class AccountManager {
|
|
|
69
69
|
const ask = await confirm({
|
|
70
70
|
message: 'Do you want to create new one?',
|
|
71
71
|
});
|
|
72
|
+
if (isCancel(ask)) {
|
|
73
|
+
ux.error('Operation cancelled.', { exit: 1 });
|
|
74
|
+
}
|
|
72
75
|
if (ask) {
|
|
73
76
|
await this.promptAccount();
|
|
74
77
|
}
|
|
@@ -81,8 +84,15 @@ export class AccountManager {
|
|
|
81
84
|
const askPrivateKey = await confirm({
|
|
82
85
|
message: 'Do you want to input privateKey?',
|
|
83
86
|
});
|
|
87
|
+
if (isCancel(askPrivateKey)) {
|
|
88
|
+
ux.error('Operation cancelled.', { exit: 1 });
|
|
89
|
+
}
|
|
84
90
|
if (askPrivateKey) {
|
|
85
|
-
const
|
|
91
|
+
const privateKeyInput = await password({ message: 'Please input your privateKey for using in account' });
|
|
92
|
+
if (isCancel(privateKeyInput)) {
|
|
93
|
+
ux.error('Operation cancelled.', { exit: 1 });
|
|
94
|
+
}
|
|
95
|
+
const privateKey = privateKeyInput.trim();
|
|
86
96
|
try {
|
|
87
97
|
const account = await this.createFromKey(privateKey);
|
|
88
98
|
ux.stdout('Your privateKey will be used in config. Keypair created');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { confirm, select } from '@
|
|
1
|
+
import { confirm, isCancel, select } from '@clack/prompts';
|
|
2
2
|
import { ux } from '@oclif/core';
|
|
3
3
|
import { Value } from '@sinclair/typebox/value';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
@@ -78,22 +78,27 @@ export class ConfigFileManager {
|
|
|
78
78
|
configToDelete = config.file;
|
|
79
79
|
}
|
|
80
80
|
else {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const selection = await this.selectPrompt({
|
|
82
|
+
message: 'Select configuration to delete:',
|
|
83
|
+
options: configs.map(config => ({
|
|
84
|
+
label: config.name,
|
|
84
85
|
value: config.file,
|
|
85
86
|
})),
|
|
86
|
-
message: 'Select configuration to delete:',
|
|
87
87
|
});
|
|
88
|
+
if (isCancel(selection)) {
|
|
89
|
+
this.ux.stdout('Deletion cancelled');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
configToDelete = selection;
|
|
88
93
|
}
|
|
89
94
|
const configToDeleteData = configs.find(c => c.file === configToDelete);
|
|
90
95
|
const displayName = configToDeleteData?.name || configToDelete;
|
|
91
96
|
if (!force) {
|
|
92
97
|
const confirmed = await this.confirmPrompt({
|
|
93
|
-
|
|
98
|
+
initialValue: false,
|
|
94
99
|
message: `Are you sure you want to delete configuration "${displayName}"?`,
|
|
95
100
|
});
|
|
96
|
-
if (!confirmed) {
|
|
101
|
+
if (isCancel(confirmed) || !confirmed) {
|
|
97
102
|
this.ux.stdout('Deletion cancelled');
|
|
98
103
|
return;
|
|
99
104
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decode } from 'jsonwebtoken';
|
|
2
|
+
import { REFRESH_TOKEN_URI } from '../constants.js';
|
|
2
3
|
import { AuthorizationRequiredError } from '../errors.js';
|
|
3
4
|
function isAccessKeyExpired(accessKey) {
|
|
4
5
|
try {
|
|
@@ -23,7 +24,7 @@ export async function createAuthMiddleware(configManager, providerClient, logger
|
|
|
23
24
|
logger.info('Performed refresh token');
|
|
24
25
|
let refreshResult;
|
|
25
26
|
try {
|
|
26
|
-
refreshResult = await providerClient.POST(
|
|
27
|
+
refreshResult = await providerClient.POST(REFRESH_TOKEN_URI);
|
|
27
28
|
}
|
|
28
29
|
catch (error) {
|
|
29
30
|
logger.error({ err: error }, 'failure refresh token');
|
|
@@ -76,6 +77,9 @@ export async function createAuthMiddleware(configManager, providerClient, logger
|
|
|
76
77
|
}
|
|
77
78
|
const middleware = {
|
|
78
79
|
async onRequest({ request }) {
|
|
80
|
+
if (request.url.endsWith(REFRESH_TOKEN_URI)) {
|
|
81
|
+
return request;
|
|
82
|
+
}
|
|
79
83
|
const accessToken = await ensureAccessKey();
|
|
80
84
|
if (accessToken) {
|
|
81
85
|
request.headers.set('Authorization', `Bearer ${accessToken}`);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ProviderClient } from '@super-protocol/provider-client';
|
|
2
|
+
import pino from 'pino';
|
|
3
|
+
import { AccountManager } from '../managers/account-manager.js';
|
|
4
|
+
import { ConfigManager } from '../managers/config-manager.js';
|
|
5
|
+
export declare class AuthError extends Error {
|
|
6
|
+
}
|
|
7
|
+
export declare class AuthService {
|
|
8
|
+
private readonly accountManager;
|
|
9
|
+
private readonly configManager;
|
|
10
|
+
private readonly providerClient;
|
|
11
|
+
private readonly logger;
|
|
12
|
+
constructor(accountManager: AccountManager, configManager: ConfigManager, providerClient: ProviderClient, logger: pino.BaseLogger);
|
|
13
|
+
auth(): Promise<void>;
|
|
14
|
+
getTokens(nonce: string): Promise<void>;
|
|
15
|
+
getUserNonce(address: string): Promise<{
|
|
16
|
+
error: {
|
|
17
|
+
message: string;
|
|
18
|
+
statusCode: number;
|
|
19
|
+
} | undefined;
|
|
20
|
+
user: {
|
|
21
|
+
nonce?: string;
|
|
22
|
+
} | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
}
|