fnos-cli 0.2.1 → 0.3.0
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/CHANGELOG.md +116 -0
- package/README.md +70 -268
- package/bin/fnos +5 -1
- package/docs/commands.md +775 -0
- package/package.json +1 -1
- package/src/commands/auth.js +42 -55
- package/src/commands/catalog/applications.js +30 -0
- package/src/commands/catalog/identity-security.js +52 -0
- package/src/commands/catalog/index.js +21 -0
- package/src/commands/catalog/monitoring.js +40 -0
- package/src/commands/catalog/network-sharing.js +81 -0
- package/src/commands/catalog/storage.js +107 -0
- package/src/commands/catalog/system.js +51 -0
- package/src/commands/index.js +18 -139
- package/src/commands/options.js +128 -0
- package/src/commands/runner.js +37 -0
- package/src/index.js +41 -51
- package/src/utils/auth-helper.js +13 -6
- package/src/utils/client.js +135 -113
- package/src/utils/errors.js +11 -0
- package/src/utils/logger.js +25 -1
- package/src/utils/settings.js +33 -72
- package/src/constants.js +0 -69
package/src/commands/index.js
CHANGED
|
@@ -1,144 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Create combined command name (e.g., "resmon.cpu")
|
|
19
|
-
const fullCommandName = `${commandName}.${subCommandName}`;
|
|
20
|
-
|
|
21
|
-
// Create command
|
|
22
|
-
const cmd = program.command(fullCommandName)
|
|
23
|
-
.description(commandConfig.description);
|
|
24
|
-
|
|
25
|
-
// Add authentication parameters
|
|
26
|
-
cmd.option('-e, --endpoint <endpoint>', 'Server endpoint (e.g., nas-9.timandes.net:5666)');
|
|
27
|
-
cmd.option('-u, --username <username>', 'Username');
|
|
28
|
-
cmd.option('-p, --password <password>', 'Password');
|
|
29
|
-
|
|
30
|
-
// Add parameters
|
|
31
|
-
if (commandConfig.params) {
|
|
32
|
-
commandConfig.params.forEach(param => {
|
|
33
|
-
const optionName = `--${param}`;
|
|
34
|
-
const description = `${param} parameter`;
|
|
35
|
-
if (param === 'disk' || param === 'path' || param === 'ifName' || param === 'files') {
|
|
36
|
-
cmd.requiredOption(optionName + ' <value>', `${description} (required)`);
|
|
37
|
-
} else {
|
|
38
|
-
cmd.option(optionName + ' <value>', description);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Add action handler
|
|
44
|
-
cmd.action(async (options) => {
|
|
45
|
-
try {
|
|
46
|
-
// Get global options from root command
|
|
47
|
-
const globalOptions = program.opts();
|
|
48
|
-
|
|
49
|
-
// Validate required parameters
|
|
50
|
-
if (commandConfig.params) {
|
|
51
|
-
const requiredParams = ['disk', 'path', 'ifName', 'files'];
|
|
52
|
-
for (const param of requiredParams) {
|
|
53
|
-
if (commandConfig.params.includes(param) && !options[param]) {
|
|
54
|
-
console.error(`Error: --${param} is required for this command.`);
|
|
55
|
-
process.exit(4);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Resolve credentials (command line or settings file)
|
|
61
|
-
let credentials;
|
|
62
|
-
try {
|
|
63
|
-
credentials = resolveCredentials(options, program);
|
|
64
|
-
} catch (error) {
|
|
65
|
-
if (error.message === 'PARTIAL_CREDENTIALS') {
|
|
66
|
-
// Display friendly error message
|
|
67
|
-
console.error('Error: When using -e/--endpoint, you must also provide -u/--username and -p/--password.');
|
|
68
|
-
console.error('Usage: fnos %s -e <endpoint> -u <username> -p <password>', fullCommandName);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Create client with resolved credentials
|
|
75
|
-
const client = await createClient({
|
|
76
|
-
credentials,
|
|
77
|
-
timeout: 60
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Get SDK instance
|
|
81
|
-
const sdkInstance = getSDKInstance(client, config.className);
|
|
82
|
-
|
|
83
|
-
// Prepare method arguments
|
|
84
|
-
const args = [];
|
|
85
|
-
const timeoutFirstClasses = ['ResourceMonitor', 'User', 'SystemInfo', 'SAC'];
|
|
86
|
-
|
|
87
|
-
if (commandConfig.params) {
|
|
88
|
-
commandConfig.params.forEach(param => {
|
|
89
|
-
if (options[param] !== undefined) {
|
|
90
|
-
let value = options[param];
|
|
91
|
-
// Handle comma-separated lists
|
|
92
|
-
if (param === 'files' || param === 'items') {
|
|
93
|
-
if (typeof value === 'string') {
|
|
94
|
-
value = value.split(',').map(s => s.trim());
|
|
95
|
-
} else if (!Array.isArray(value)) {
|
|
96
|
-
value = [value];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Handle boolean parameters
|
|
100
|
-
if (param === 'noHotSpare' || param === 'moveToTrashbin') {
|
|
101
|
-
value = value === 'false' ? false : value;
|
|
102
|
-
}
|
|
103
|
-
// Handle numeric parameters
|
|
104
|
-
if (param === 'type') {
|
|
105
|
-
value = parseInt(value, 10);
|
|
106
|
-
}
|
|
107
|
-
args.push(value);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Add timeout based on class pattern
|
|
113
|
-
if (timeoutFirstClasses.includes(config.className)) {
|
|
114
|
-
// Timeout first pattern: (timeout, params...)
|
|
115
|
-
args.unshift(10000);
|
|
116
|
-
} else {
|
|
117
|
-
// Timeout last pattern: (params..., timeout)
|
|
118
|
-
args.push(10000);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Execute method
|
|
122
|
-
logger.info(`Executing ${config.className}.${commandConfig.method}...`);
|
|
123
|
-
const result = await sdkInstance[commandConfig.method](...args);
|
|
124
|
-
|
|
125
|
-
// Format output
|
|
126
|
-
console.log(formatOutput(result, globalOptions.raw));
|
|
127
|
-
|
|
128
|
-
// Close connection
|
|
129
|
-
client.close();
|
|
130
|
-
process.exit(0);
|
|
131
|
-
} catch (error) {
|
|
132
|
-
logger.error(`Command failed: ${error.message}`);
|
|
133
|
-
const globalOptions = program.opts();
|
|
134
|
-
if (globalOptions.debug || globalOptions.silly) {
|
|
135
|
-
console.error(error);
|
|
136
|
-
}
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
1
|
+
const { COMMAND_CATALOG } = require('./catalog');
|
|
2
|
+
const { registerAuthenticationOptions, registerBusinessOptions } = require('./options');
|
|
3
|
+
const { runCommand } = require('./runner');
|
|
4
|
+
|
|
5
|
+
function registerCommands(program, dependencies = {}) {
|
|
6
|
+
for (const [domainName, domain] of Object.entries(COMMAND_CATALOG)) {
|
|
7
|
+
for (const [commandName, definition] of Object.entries(domain.commands)) {
|
|
8
|
+
const command = program.command(`${domainName}.${commandName}`).description(definition.description);
|
|
9
|
+
registerAuthenticationOptions(command);
|
|
10
|
+
registerBusinessOptions(command, definition.options);
|
|
11
|
+
command.action(async (options) => {
|
|
12
|
+
process.exitCode = await runCommand({
|
|
13
|
+
domain,
|
|
14
|
+
definition,
|
|
15
|
+
options,
|
|
16
|
+
globalOptions: program.opts()
|
|
17
|
+
}, dependencies);
|
|
139
18
|
});
|
|
140
19
|
}
|
|
141
20
|
}
|
|
142
21
|
}
|
|
143
22
|
|
|
144
|
-
module.exports = { registerCommands };
|
|
23
|
+
module.exports = { registerCommands };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const { Option } = require('commander');
|
|
2
|
+
|
|
3
|
+
class CommandParameterError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'CommandParameterError';
|
|
7
|
+
this.exitCode = 4;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function cloneDefault(value) {
|
|
12
|
+
if (Array.isArray(value)) return value.map((item) => cloneDefault(item));
|
|
13
|
+
if (value && typeof value === 'object') return { ...value };
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseBoolean(name, value) {
|
|
18
|
+
if (typeof value === 'boolean') return value;
|
|
19
|
+
if (typeof value === 'string' && value.toLowerCase() === 'true') return true;
|
|
20
|
+
if (typeof value === 'string' && value.toLowerCase() === 'false') return false;
|
|
21
|
+
throw new CommandParameterError(`--${name} must be true or false.`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parseInteger(definition, value) {
|
|
25
|
+
if (typeof value === 'string' && !/^-?\d+$/.test(value.trim())) {
|
|
26
|
+
throw new CommandParameterError(`--${definition.name} must be a decimal integer.`);
|
|
27
|
+
}
|
|
28
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
29
|
+
if (!Number.isInteger(parsed)) throw new CommandParameterError(`--${definition.name} must be an integer.`);
|
|
30
|
+
if (definition.min !== undefined && parsed < definition.min) {
|
|
31
|
+
throw new CommandParameterError(`--${definition.name} must be at least ${definition.min}.`);
|
|
32
|
+
}
|
|
33
|
+
if (definition.max !== undefined && parsed > definition.max) {
|
|
34
|
+
throw new CommandParameterError(`--${definition.name} must be at most ${definition.max}.`);
|
|
35
|
+
}
|
|
36
|
+
if (definition.allowedValues && !definition.allowedValues.includes(parsed)) {
|
|
37
|
+
throw new CommandParameterError(`--${definition.name} must be one of: ${definition.allowedValues.join(', ')}.`);
|
|
38
|
+
}
|
|
39
|
+
return parsed;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseJson(name, value) {
|
|
43
|
+
if (value && typeof value === 'object') return value;
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(value);
|
|
46
|
+
} catch {
|
|
47
|
+
throw new CommandParameterError(`--${name} must be valid JSON.`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseValue(definition, value) {
|
|
52
|
+
if (definition.type === 'boolean') return parseBoolean(definition.name, value);
|
|
53
|
+
if (definition.type === 'integer') return parseInteger(definition, value);
|
|
54
|
+
if (definition.type === 'csv') {
|
|
55
|
+
const values = Array.isArray(value) ? value : String(value).split(',').map((item) => item.trim()).filter(Boolean);
|
|
56
|
+
if (values.length === 0) throw new CommandParameterError(`--${definition.name} must contain at least one value.`);
|
|
57
|
+
return values;
|
|
58
|
+
}
|
|
59
|
+
if (definition.type === 'json') {
|
|
60
|
+
const parsed = parseJson(definition.name, value);
|
|
61
|
+
if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {
|
|
62
|
+
throw new CommandParameterError(`--${definition.name} must be a JSON object.`);
|
|
63
|
+
}
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
if (definition.type === 'json-record-array') {
|
|
67
|
+
const parsed = parseJson(definition.name, value);
|
|
68
|
+
if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some((item) => !item || Array.isArray(item) || typeof item !== 'object')) {
|
|
69
|
+
throw new CommandParameterError(`--${definition.name} must be a non-empty JSON object array.`);
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
const parsed = String(value);
|
|
74
|
+
if (!parsed.trim()) throw new CommandParameterError(`--${definition.name} must not be empty.`);
|
|
75
|
+
return parsed;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function optionReadNames(definition) {
|
|
79
|
+
if (definition.readNames) return definition.readNames;
|
|
80
|
+
return [new Option(definition.flag).attributeName()];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function readRawValue(definition, options) {
|
|
84
|
+
for (const name of optionReadNames(definition)) {
|
|
85
|
+
if (options[name] !== undefined) return options[name];
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function buildMethodArguments(definition, options, timeout = 10000) {
|
|
91
|
+
const values = definition.options.map((option) => {
|
|
92
|
+
const raw = readRawValue(option, options);
|
|
93
|
+
if (raw === undefined) {
|
|
94
|
+
if (option.required) throw new CommandParameterError(`--${option.name} is required.`);
|
|
95
|
+
return cloneDefault(option.defaultValue);
|
|
96
|
+
}
|
|
97
|
+
return parseValue(option, raw);
|
|
98
|
+
});
|
|
99
|
+
return definition.timeoutPosition === 'first' ? [timeout, ...values] : [...values, timeout];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function registerBusinessOptions(command, definitions) {
|
|
103
|
+
for (const definition of definitions) {
|
|
104
|
+
command.addOption(new Option(definition.flag, definition.description));
|
|
105
|
+
for (const legacyFlag of definition.legacyFlags || []) {
|
|
106
|
+
command.addOption(new Option(legacyFlag, `${definition.description} (legacy spelling)`).hideHelp());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return command;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function registerAuthenticationOptions(command, requiredCredentials = false) {
|
|
113
|
+
const add = requiredCredentials ? 'requiredOption' : 'option';
|
|
114
|
+
command[add]('-e, --endpoint <endpoint>', 'Server endpoint, including optional ws:// or wss:// prefix');
|
|
115
|
+
command[add]('-u, --username <username>', 'Username');
|
|
116
|
+
command[add]('-p, --password <password>', 'Password');
|
|
117
|
+
command.option('--twofa-code <code>', 'Six-digit two-factor code');
|
|
118
|
+
command.option('--trust-device', 'Trust this device after two-factor login');
|
|
119
|
+
command.option('--verify-ssl', 'Verify the WSS server certificate');
|
|
120
|
+
return command;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
CommandParameterError,
|
|
125
|
+
buildMethodArguments,
|
|
126
|
+
registerAuthenticationOptions,
|
|
127
|
+
registerBusinessOptions
|
|
128
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { buildMethodArguments } = require('./options');
|
|
2
|
+
const clientUtils = require('../utils/client');
|
|
3
|
+
const { formatOutput } = require('../utils/formatter');
|
|
4
|
+
const { resolveCredentials } = require('../utils/auth-helper');
|
|
5
|
+
const { errorMessage } = require('../utils/errors');
|
|
6
|
+
|
|
7
|
+
async function runCommand(context, dependencies = {}) {
|
|
8
|
+
const createClient = dependencies.createClient || clientUtils.createClient;
|
|
9
|
+
const getSDKInstance = dependencies.getSDKInstance || clientUtils.getSDKInstance;
|
|
10
|
+
const resolve = dependencies.resolveCredentials || resolveCredentials;
|
|
11
|
+
const stdout = dependencies.stdout || console.log;
|
|
12
|
+
const stderr = dependencies.stderr || console.error;
|
|
13
|
+
let client;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const args = buildMethodArguments(context.definition, context.options, 10000);
|
|
17
|
+
const credentials = resolve(context.options);
|
|
18
|
+
client = await createClient({
|
|
19
|
+
credentials,
|
|
20
|
+
timeout: 60,
|
|
21
|
+
twofaCode: context.options.twofaCode,
|
|
22
|
+
trustDevice: context.options.trustDevice,
|
|
23
|
+
verifySsl: context.options.verifySsl
|
|
24
|
+
});
|
|
25
|
+
const instance = getSDKInstance(client, context.domain.className);
|
|
26
|
+
const result = await instance[context.definition.method](...args);
|
|
27
|
+
stdout(formatOutput(result, context.globalOptions.raw));
|
|
28
|
+
return 0;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
stderr(`Error: ${errorMessage(error)}`);
|
|
31
|
+
return error.exitCode || 1;
|
|
32
|
+
} finally {
|
|
33
|
+
if (client) client.close();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { errorMessage, runCommand };
|
package/src/index.js
CHANGED
|
@@ -1,57 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* fnos-cli - CLI client for 飞牛 fnOS system
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
3
|
const { Command } = require('commander');
|
|
8
4
|
const { registerLoginCommand, registerLogoutCommand } = require('./commands/auth');
|
|
9
5
|
const { registerCommands } = require('./commands');
|
|
10
6
|
const { setLogLevel } = require('./utils/logger');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
program
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
program
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
program.parse(process.argv);
|
|
53
|
-
|
|
54
|
-
// Show help if no command provided
|
|
55
|
-
if (!process.argv.slice(2).length) {
|
|
56
|
-
program.outputHelp();
|
|
57
|
-
}
|
|
7
|
+
const { errorMessage } = require('./utils/errors');
|
|
8
|
+
const { version } = require('../package.json');
|
|
9
|
+
|
|
10
|
+
function createProgram(dependencies = {}) {
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program.name('fnos').description('CLI client for 飞牛 fnOS system').version(version);
|
|
13
|
+
program
|
|
14
|
+
.option('--raw', 'Output raw JSON response')
|
|
15
|
+
.option('-v, --verbose', 'Verbose output (info level)')
|
|
16
|
+
.option('-vv, --debug', 'Debug output (debug level)')
|
|
17
|
+
.option('-vvv, --silly', 'Silly output (silly level)');
|
|
18
|
+
registerLoginCommand(program, dependencies);
|
|
19
|
+
registerLogoutCommand(program, dependencies);
|
|
20
|
+
registerCommands(program, dependencies);
|
|
21
|
+
program.hook('preAction', (thisCommand) => {
|
|
22
|
+
const options = thisCommand.opts();
|
|
23
|
+
const verboseLevel = options.silly ? 3 : options.debug ? 2 : options.verbose ? 1 : 0;
|
|
24
|
+
setLogLevel(verboseLevel);
|
|
25
|
+
process.env.LOG_LEVEL = ['error', 'info', 'debug', 'silly'][verboseLevel];
|
|
26
|
+
});
|
|
27
|
+
return program;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function main(argv = process.argv, dependencies = {}) {
|
|
31
|
+
const program = createProgram(dependencies);
|
|
32
|
+
if (argv.slice(2).length === 0) {
|
|
33
|
+
program.outputHelp();
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
await program.parseAsync(argv);
|
|
37
|
+
return process.exitCode || 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (require.main === module) {
|
|
41
|
+
main().catch((error) => {
|
|
42
|
+
console.error(`Error: ${errorMessage(error)}`);
|
|
43
|
+
process.exitCode = error.exitCode || 1;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { createProgram, main };
|
package/src/utils/auth-helper.js
CHANGED
|
@@ -15,6 +15,13 @@ function hasPartialCredentials(options) {
|
|
|
15
15
|
return provided.length > 0 && provided.length < 3;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function credentialError(message) {
|
|
19
|
+
const error = new Error(message);
|
|
20
|
+
error.name = 'AuthenticationError';
|
|
21
|
+
error.exitCode = 3;
|
|
22
|
+
return error;
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
/**
|
|
19
26
|
* Validate command line credentials completeness
|
|
20
27
|
* @param {Object} options - Command line options
|
|
@@ -23,10 +30,10 @@ function hasPartialCredentials(options) {
|
|
|
23
30
|
*/
|
|
24
31
|
function validateCommandLineCredentials(options) {
|
|
25
32
|
if (hasPartialCredentials(options)) {
|
|
26
|
-
throw
|
|
33
|
+
throw credentialError('PARTIAL_CREDENTIALS');
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
const hasCredentials = options.endpoint && options.username && options.password;
|
|
36
|
+
const hasCredentials = Boolean(options.endpoint && options.username && options.password);
|
|
30
37
|
return { isValid: true, hasCredentials };
|
|
31
38
|
}
|
|
32
39
|
|
|
@@ -36,7 +43,7 @@ function validateCommandLineCredentials(options) {
|
|
|
36
43
|
* @returns {Object} - Credentials object
|
|
37
44
|
* @throws {Error} - If no valid credentials are found or partial credentials are provided
|
|
38
45
|
*/
|
|
39
|
-
function resolveCredentials(options) {
|
|
46
|
+
function resolveCredentials(options, settingsStore = settings) {
|
|
40
47
|
const validation = validateCommandLineCredentials(options);
|
|
41
48
|
|
|
42
49
|
if (validation.hasCredentials) {
|
|
@@ -50,9 +57,9 @@ function resolveCredentials(options) {
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
// Read from settings file
|
|
53
|
-
const credentials =
|
|
60
|
+
const credentials = settingsStore.getCredentials();
|
|
54
61
|
if (!credentials || !credentials.endpoint || !credentials.username || !credentials.password) {
|
|
55
|
-
throw
|
|
62
|
+
throw credentialError('No valid credentials found. Please use "fnos login" or provide -e/-u/-p options.');
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
return {
|
|
@@ -65,4 +72,4 @@ module.exports = {
|
|
|
65
72
|
hasPartialCredentials,
|
|
66
73
|
validateCommandLineCredentials,
|
|
67
74
|
resolveCredentials
|
|
68
|
-
};
|
|
75
|
+
};
|