@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,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 = '
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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, {
|
|
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, {
|
|
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
|
|
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
|
|
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, {
|
|
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 {
|
|
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;
|
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
1
|
+
import type { ProviderClient } from '@super-protocol/provider-client';
|
|
2
|
+
import type pino from 'pino';
|
|
3
|
+
import type { AccountManager } from '../managers/account-manager.js';
|
|
4
|
+
import type { ConfigManager } from '../managers/config-manager.js';
|
|
5
5
|
export declare class AuthError extends Error {
|
|
6
6
|
}
|
|
7
7
|
export declare class AuthService {
|
|
@@ -10,15 +10,10 @@ export declare class AuthService {
|
|
|
10
10
|
private readonly providerClient;
|
|
11
11
|
private readonly logger;
|
|
12
12
|
constructor(accountManager: AccountManager, configManager: ConfigManager, providerClient: ProviderClient, logger: pino.BaseLogger);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} | undefined;
|
|
20
|
-
user: {
|
|
21
|
-
nonce?: string;
|
|
22
|
-
} | undefined;
|
|
23
|
-
}>;
|
|
13
|
+
private hasValidRefreshCookie;
|
|
14
|
+
auth(options?: {
|
|
15
|
+
force?: boolean;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
private getTokens;
|
|
18
|
+
private getUserNonce;
|
|
24
19
|
}
|
|
@@ -1,5 +1,31 @@
|
|
|
1
|
+
import { decode } from 'jsonwebtoken';
|
|
2
|
+
import { CookieJar } from 'tough-cookie';
|
|
3
|
+
import { PROVIDER_URL } from '../constants.js';
|
|
1
4
|
export class AuthError extends Error {
|
|
2
5
|
}
|
|
6
|
+
function isAccessKeyExpired(accessKey) {
|
|
7
|
+
try {
|
|
8
|
+
const payload = decode(accessKey);
|
|
9
|
+
if (!payload || typeof payload.exp !== 'number') {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const now = Math.floor(Date.now() / 1000);
|
|
13
|
+
return now >= payload.exp;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function isCookieExpired(cookie) {
|
|
20
|
+
if (!cookie.expires || cookie.expires === 'Infinity') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const expiresAt = cookie.expires.getTime();
|
|
24
|
+
if (!Number.isFinite(expiresAt)) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return Date.now() >= expiresAt;
|
|
28
|
+
}
|
|
3
29
|
export class AuthService {
|
|
4
30
|
accountManager;
|
|
5
31
|
configManager;
|
|
@@ -11,7 +37,45 @@ export class AuthService {
|
|
|
11
37
|
this.providerClient = providerClient;
|
|
12
38
|
this.logger = logger;
|
|
13
39
|
}
|
|
14
|
-
async
|
|
40
|
+
async hasValidRefreshCookie(baseUrl) {
|
|
41
|
+
let stored;
|
|
42
|
+
try {
|
|
43
|
+
stored = await this.configManager.getCookies();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
this.logger.warn({ err: error }, 'Failed to read cookies from config');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (!stored || typeof stored !== 'object') {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const jar = CookieJar.fromJSON(stored);
|
|
54
|
+
const cookies = await jar.getCookies(baseUrl, { expire: false });
|
|
55
|
+
return cookies.some((cookie) => cookie.key.toLowerCase().includes('refresh') && cookie.value && !isCookieExpired(cookie));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logger.warn({ err: error }, 'Failed to parse cookies');
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async auth(options = {}) {
|
|
63
|
+
if (!options.force) {
|
|
64
|
+
const credentials = await this.configManager.getCredentials();
|
|
65
|
+
const accessKey = credentials?.accessKey;
|
|
66
|
+
if (accessKey && !isAccessKeyExpired(accessKey)) {
|
|
67
|
+
this.logger.debug('Access key is not expired, skipping authorization');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (accessKey) {
|
|
71
|
+
const providerUrl = (await this.configManager.get('providerUrl')) || PROVIDER_URL;
|
|
72
|
+
const hasRefreshCookie = await this.hasValidRefreshCookie(providerUrl);
|
|
73
|
+
if (hasRefreshCookie) {
|
|
74
|
+
this.logger.debug('Access key expired but refresh cookie exists, skipping authorization');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
15
79
|
const address = this.accountManager.getAddress();
|
|
16
80
|
const { error: nonceError, user } = await this.getUserNonce(address);
|
|
17
81
|
if (nonceError && nonceError.statusCode === 404) {
|
|
@@ -25,7 +89,7 @@ export class AuthService {
|
|
|
25
89
|
this.logger.debug({ signUpError }, 'Error signing up');
|
|
26
90
|
const { error: nonceError, user } = await this.getUserNonce(address);
|
|
27
91
|
this.logger.debug({ nonceError, user }, 'Requesting nonce again');
|
|
28
|
-
if (user
|
|
92
|
+
if (user?.nonce) {
|
|
29
93
|
await this.getTokens(user.nonce);
|
|
30
94
|
}
|
|
31
95
|
else {
|
|
@@ -45,7 +109,7 @@ export class AuthService {
|
|
|
45
109
|
await this.getTokens(nonce);
|
|
46
110
|
}
|
|
47
111
|
}
|
|
48
|
-
else if (user
|
|
112
|
+
else if (user?.nonce) {
|
|
49
113
|
this.logger.debug({ user }, 'Requesting for existed user');
|
|
50
114
|
await this.getTokens(user.nonce);
|
|
51
115
|
}
|
|
@@ -55,7 +119,7 @@ export class AuthService {
|
|
|
55
119
|
}
|
|
56
120
|
async getTokens(nonce) {
|
|
57
121
|
const signature = await this.accountManager.createSign(nonce);
|
|
58
|
-
const { data: tokenResponse, error
|
|
122
|
+
const { data: tokenResponse, error } = await this.providerClient.POST('/api/auth/token', {
|
|
59
123
|
body: {
|
|
60
124
|
address: this.accountManager.getAddress(),
|
|
61
125
|
provider: 'sp-cli',
|
|
@@ -71,7 +135,9 @@ export class AuthService {
|
|
|
71
135
|
this.logger.error({ response: tokenResponse }, 'Unexpected token response');
|
|
72
136
|
throw new AuthError('Provider returned an unexpected token response.');
|
|
73
137
|
}
|
|
74
|
-
await this.configManager.setCredentials({
|
|
138
|
+
await this.configManager.setCredentials({
|
|
139
|
+
accessKey: accessToken,
|
|
140
|
+
});
|
|
75
141
|
}
|
|
76
142
|
async getUserNonce(address) {
|
|
77
143
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { EncryptionWithIV, Resource, RuntimeInputInfo } from '@super-protocol/dto-js';
|
|
2
|
-
import { AddStorageDto, ProviderClient, StorageResponseDto, UpdateStorageDto } from '@super-protocol/provider-client';
|
|
3
|
-
import pino from 'pino';
|
|
1
|
+
import { type EncryptionWithIV, type Resource, type RuntimeInputInfo } from '@super-protocol/dto-js';
|
|
2
|
+
import { type AddStorageDto, type ProviderClient, type StorageResponseDto, type UpdateStorageDto } from '@super-protocol/provider-client';
|
|
3
|
+
import type pino from 'pino';
|
|
4
4
|
export declare class StorageError extends Error {
|
|
5
5
|
}
|
|
6
6
|
export declare class StoragesUndefinedError extends StorageError {
|
|
@@ -4,11 +4,11 @@ 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 * as fs from 'node:fs/promises';
|
|
8
|
+
import { basename, dirname } from 'node:path';
|
|
7
9
|
import { StorageResourceSchema, StorageType, } from '@super-protocol/dto-js';
|
|
8
10
|
import { ResourceType, } from '@super-protocol/provider-client';
|
|
9
11
|
import { download, upload } from '@super-protocol/sp-files-addon';
|
|
10
|
-
import * as fs from 'node:fs/promises';
|
|
11
|
-
import { basename, dirname } from 'node:path';
|
|
12
12
|
import { Value } from 'typebox/value';
|
|
13
13
|
import { Retryable } from 'typescript-retry-decorator';
|
|
14
14
|
import { S3_ENDPOINT } from '../constants.js';
|
|
@@ -24,7 +24,9 @@ export class StorageUpdateError extends StorageError {
|
|
|
24
24
|
}
|
|
25
25
|
export class StorageGetError extends StorageError {
|
|
26
26
|
}
|
|
27
|
-
export const generateExternalId = () => Array.from({ length: 16 })
|
|
27
|
+
export const generateExternalId = () => Array.from({ length: 16 })
|
|
28
|
+
.map(() => Math.floor(Math.random() * 16).toString(16))
|
|
29
|
+
.join('');
|
|
28
30
|
export class StorageService {
|
|
29
31
|
providerClient;
|
|
30
32
|
logger;
|
|
@@ -38,7 +40,7 @@ export class StorageService {
|
|
|
38
40
|
const { data, error } = await this.providerClient.POST('/api/storages', {
|
|
39
41
|
body: storage,
|
|
40
42
|
});
|
|
41
|
-
if (error
|
|
43
|
+
if (error?.message) {
|
|
42
44
|
this.logger.error({ err: error }, 'Failed to create storage');
|
|
43
45
|
throw new StorageCreateError(error.message);
|
|
44
46
|
}
|
|
@@ -51,12 +53,16 @@ export class StorageService {
|
|
|
51
53
|
}
|
|
52
54
|
catch (error) {
|
|
53
55
|
this.logger.error({ err: error }, 'Storage creation failed');
|
|
54
|
-
const error_ = error instanceof StorageError
|
|
56
|
+
const error_ = error instanceof StorageError
|
|
57
|
+
? error
|
|
58
|
+
: new ProviderClientError('Request failed please try again later');
|
|
55
59
|
throw error_;
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
async download(params, progressCb) {
|
|
59
|
-
const resourceFile = await readJsonFile({
|
|
63
|
+
const resourceFile = await readJsonFile({
|
|
64
|
+
path: params.resourcePath,
|
|
65
|
+
});
|
|
60
66
|
if (!Value.Check(StorageResourceSchema, resourceFile)) {
|
|
61
67
|
throw new StorageError('Invalid resource file format, please verify resource.json against the schema.');
|
|
62
68
|
}
|
|
@@ -90,7 +96,7 @@ export class StorageService {
|
|
|
90
96
|
async getCentralizedStorage() {
|
|
91
97
|
try {
|
|
92
98
|
const storages = await this.requestStorages();
|
|
93
|
-
const centralized = storages.find(storage => storage.isCentralized);
|
|
99
|
+
const centralized = storages.find((storage) => storage.isCentralized);
|
|
94
100
|
if (!centralized) {
|
|
95
101
|
const storage = await this.initCentralizedStorage();
|
|
96
102
|
return storage;
|
|
@@ -114,7 +120,7 @@ export class StorageService {
|
|
|
114
120
|
}
|
|
115
121
|
const { activeStorageId } = data || {};
|
|
116
122
|
const storages = await this.requestStorages();
|
|
117
|
-
const storage = storages.find(storage => storage.id === activeStorageId);
|
|
123
|
+
const storage = storages.find((storage) => storage.id === activeStorageId);
|
|
118
124
|
if (!storage) {
|
|
119
125
|
throw new StorageError('Selected storage not found please select storage first');
|
|
120
126
|
}
|
|
@@ -122,7 +128,9 @@ export class StorageService {
|
|
|
122
128
|
}
|
|
123
129
|
catch (error) {
|
|
124
130
|
this.logger.error({ err: error }, 'Failed to get current storage');
|
|
125
|
-
const error_ = error instanceof StorageError
|
|
131
|
+
const error_ = error instanceof StorageError
|
|
132
|
+
? error
|
|
133
|
+
: new ProviderClientError('Request failed please try again later');
|
|
126
134
|
throw error_;
|
|
127
135
|
}
|
|
128
136
|
}
|
|
@@ -146,7 +154,9 @@ export class StorageService {
|
|
|
146
154
|
}
|
|
147
155
|
catch (error) {
|
|
148
156
|
this.logger.error({ err: error }, 'Storage initialization failed');
|
|
149
|
-
const error_ = error instanceof StorageError
|
|
157
|
+
const error_ = error instanceof StorageError
|
|
158
|
+
? error
|
|
159
|
+
: new ProviderClientError('Request failed please try again later');
|
|
150
160
|
throw error_;
|
|
151
161
|
}
|
|
152
162
|
}
|
|
@@ -167,7 +177,9 @@ export class StorageService {
|
|
|
167
177
|
}
|
|
168
178
|
catch (error) {
|
|
169
179
|
this.logger.error({ err: error }, 'Storage initialization failed');
|
|
170
|
-
const error_ = error instanceof StorageError
|
|
180
|
+
const error_ = error instanceof StorageError
|
|
181
|
+
? error
|
|
182
|
+
: new ProviderClientError('Request failed please try again later');
|
|
171
183
|
throw error_;
|
|
172
184
|
}
|
|
173
185
|
}
|
|
@@ -190,7 +202,9 @@ export class StorageService {
|
|
|
190
202
|
}
|
|
191
203
|
catch (error) {
|
|
192
204
|
this.logger.error({ err: error }, 'Failed to request storages');
|
|
193
|
-
const error_ = error instanceof StorageError
|
|
205
|
+
const error_ = error instanceof StorageError
|
|
206
|
+
? error
|
|
207
|
+
: new ProviderClientError('Request failed please try again later');
|
|
194
208
|
throw error_;
|
|
195
209
|
}
|
|
196
210
|
}
|
|
@@ -219,7 +233,9 @@ export class StorageService {
|
|
|
219
233
|
}
|
|
220
234
|
catch (error) {
|
|
221
235
|
this.logger.error({ err: error }, 'Failed to save selected storage');
|
|
222
|
-
const error_ = error instanceof StorageError
|
|
236
|
+
const error_ = error instanceof StorageError
|
|
237
|
+
? error
|
|
238
|
+
: new ProviderClientError('Request failed please try again later');
|
|
223
239
|
throw error_;
|
|
224
240
|
}
|
|
225
241
|
}
|
|
@@ -243,13 +259,17 @@ export class StorageService {
|
|
|
243
259
|
}
|
|
244
260
|
catch (error) {
|
|
245
261
|
this.logger.error({ err: error, storageId: id }, 'Failed to update storage');
|
|
246
|
-
const error_ = error instanceof StorageError
|
|
262
|
+
const error_ = error instanceof StorageError
|
|
263
|
+
? error
|
|
264
|
+
: new ProviderClientError('Request failed please try again later');
|
|
247
265
|
throw error_;
|
|
248
266
|
}
|
|
249
267
|
}
|
|
250
268
|
async upload(params, progressCb) {
|
|
251
269
|
const storage = await this.getCurrentStorage();
|
|
252
|
-
const remotePath = params.remotePath
|
|
270
|
+
const remotePath = params.remotePath
|
|
271
|
+
? params.remotePath.replaceAll('..', '').replace(/^\/+/, '')
|
|
272
|
+
: generateExternalId();
|
|
253
273
|
const resourceFilePath = preparePath(params.outputPath ?? 'resource.json');
|
|
254
274
|
try {
|
|
255
275
|
await fs.stat(resourceFilePath);
|
|
@@ -262,7 +282,9 @@ export class StorageService {
|
|
|
262
282
|
}
|
|
263
283
|
let metadata = {};
|
|
264
284
|
if (params.metadataPath) {
|
|
265
|
-
metadata = await readJsonFile({
|
|
285
|
+
metadata = await readJsonFile({
|
|
286
|
+
path: preparePath(params.metadataPath),
|
|
287
|
+
});
|
|
266
288
|
}
|
|
267
289
|
const { readCredentials, writeCredentials } = this.getStorageCredentials(storage, remotePath);
|
|
268
290
|
const info = await fs.stat(params.localPath);
|
|
@@ -315,7 +337,8 @@ export class StorageService {
|
|
|
315
337
|
bucket: storage.bucket,
|
|
316
338
|
prefix: joinPaths(storage.prefix, remotePath),
|
|
317
339
|
token: readAccessToken,
|
|
318
|
-
},
|
|
340
|
+
},
|
|
341
|
+
writeCredentials: {
|
|
319
342
|
bucket: storage.bucket,
|
|
320
343
|
prefix: joinPaths(storage.prefix, remotePath),
|
|
321
344
|
token: writeAccessToken,
|
|
@@ -334,7 +357,8 @@ export class StorageService {
|
|
|
334
357
|
endpoint: S3_ENDPOINT,
|
|
335
358
|
prefix: joinPaths(storage.prefix, remotePath),
|
|
336
359
|
secretKey: readSecretAccessKey,
|
|
337
|
-
},
|
|
360
|
+
},
|
|
361
|
+
writeCredentials: {
|
|
338
362
|
accessKeyId: writeAccessKeyId,
|
|
339
363
|
bucket: storage.bucket,
|
|
340
364
|
endpoint: S3_ENDPOINT,
|
|
@@ -347,5 +371,8 @@ export class StorageService {
|
|
|
347
371
|
}
|
|
348
372
|
}
|
|
349
373
|
__decorate([
|
|
350
|
-
Retryable({
|
|
374
|
+
Retryable({
|
|
375
|
+
maxAttempts: 3,
|
|
376
|
+
value: [StoragesUndefinedError, StorageCreateError, ProviderClientError],
|
|
377
|
+
})
|
|
351
378
|
], StorageService.prototype, "getCentralizedStorage", null);
|
package/dist/utils/helper.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const getConfigName: (name: string) => string;
|
|
2
|
+
export declare const getConfigNameFromCredentials: (privateKey: string, url: string) => string;
|
|
2
3
|
export declare const preparePath: (rawPath: string) => string;
|
|
3
4
|
export declare const joinPaths: (...args: string[]) => string;
|
|
4
5
|
export type ReadJsonFileParams = {
|
package/dist/utils/helper.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { existsSync } from 'node:fs';
|
|
2
3
|
import * as fs from 'node:fs/promises';
|
|
3
4
|
import path from 'node:path';
|
|
4
|
-
export const getConfigName = (name) => name.toLowerCase().replaceAll(/[^a-z0-9]+/g, '-')
|
|
5
|
+
export const getConfigName = (name) => `${name.toLowerCase().replaceAll(/[^a-z0-9]+/g, '-')}.config.json`;
|
|
6
|
+
export const getConfigNameFromCredentials = (privateKey, url) => {
|
|
7
|
+
const normalizedKey = privateKey.trim();
|
|
8
|
+
const normalizedUrl = url.trim();
|
|
9
|
+
if (!normalizedKey || !normalizedUrl) {
|
|
10
|
+
throw new Error('Private key and URL must not be empty');
|
|
11
|
+
}
|
|
12
|
+
const hashBuilder = createHash('sha256');
|
|
13
|
+
hashBuilder.update(normalizedKey);
|
|
14
|
+
hashBuilder.update('|');
|
|
15
|
+
hashBuilder.update(normalizedUrl);
|
|
16
|
+
const hash = hashBuilder.digest('hex');
|
|
17
|
+
return `${hash}.config.json`;
|
|
18
|
+
};
|
|
5
19
|
export const preparePath = (rawPath) => {
|
|
6
20
|
if (path.isAbsolute(rawPath))
|
|
7
21
|
return rawPath;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Args, Flags } from '@oclif/core';
|
|
2
|
+
type FlagDefinition = ReturnType<typeof Flags.string> | ReturnType<typeof Flags.integer> | ReturnType<typeof Flags.boolean>;
|
|
3
|
+
type ArgDefinition = ReturnType<typeof Args.string> | ReturnType<typeof Args.integer> | ReturnType<typeof Args.boolean>;
|
|
4
|
+
export interface MissingFlag {
|
|
5
|
+
name: string;
|
|
6
|
+
definition: FlagDefinition;
|
|
7
|
+
type: 'string' | 'integer' | 'boolean';
|
|
8
|
+
}
|
|
9
|
+
export interface MissingArg {
|
|
10
|
+
name: string;
|
|
11
|
+
definition: ArgDefinition;
|
|
12
|
+
type: 'string' | 'integer' | 'boolean';
|
|
13
|
+
}
|
|
14
|
+
export declare const findMissingRequiredFlags: (flags: Record<string, unknown>, flagDefinitions: Record<string, FlagDefinition> | undefined) => Promise<MissingFlag[]>;
|
|
15
|
+
export declare const findMissingRequiredArgs: (args: Record<string, unknown>, argDefinitions: Record<string, ArgDefinition> | undefined) => Promise<MissingArg[]>;
|
|
16
|
+
export declare const promptForFlag: (missingFlag: MissingFlag) => Promise<string | number | boolean>;
|
|
17
|
+
export declare const promptForArg: (missingArg: MissingArg) => Promise<string | number | boolean>;
|
|
18
|
+
export declare const formatMissingFlagsError: (missingFlags: MissingFlag[]) => string;
|
|
19
|
+
export declare const formatMissingArgsError: (missingArgs: MissingArg[]) => string;
|
|
20
|
+
export {};
|