Skip to content

Commit 59a0d36

Browse files
committed
Merge remote-tracking branch 'origin/feat-cli-g2' into feat-cli-local-development
2 parents 7b0f655 + 2014675 commit 59a0d36

File tree

16 files changed

+347
-292
lines changed

16 files changed

+347
-292
lines changed

src/SDK/Language/CLI.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ public function getFunctions(): array
362362
{
363363
return [
364364
/** Return true if the entered service->method is enabled for a console preview link */
365-
new TwigFunction('methodHaveConsolePreview', fn($method, $service) => preg_match('/^([Gg]et|[Ll]ist)/', $method)
365+
new TwigFunction('hasConsolePreview', fn($method, $service) => preg_match('/^([Gg]et|[Ll]ist)/', $method)
366366
&& !in_array(strtolower($method), $this->consoleIgnoreFunctions)
367367
&& !in_array($service, $this->consoleIgnoreServices)),
368368
];

templates/cli/base/requests/api.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
fs.writeFileSync(destination, response);
1818
{%~ endif %}
1919
if (parseOutput) {
20-
{%~ if methodHaveConsolePreview(method.name,service.name) %}
20+
{%~ if hasConsolePreview(method.name,service.name) %}
2121
if(console) {
22-
showConsoleLink('{{service.name}}', '{{ method.name }}',open
22+
showConsoleLink('{{service.name}}', '{{ method.name }}'
2323
{%- for parameter in method.parameters.path -%}{%- set param = (parameter.name | caseCamel | escapeKeyword) -%}{%- if param ends with 'Id' -%}, {{ param }} {%- endif -%}{%- endfor -%}
2424
);
2525
} else {

templates/cli/index.js.twig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ const chalk = require("chalk");
1010
const { version } = require("./package.json");
1111
const { commandDescriptions, cliConfig } = require("./lib/parser");
1212
const { client } = require("./lib/commands/generic");
13+
const inquirer = require("inquirer");
1314
{% if sdk.test != "true" %}
14-
const { login, logout, whoami, migrate } = require("./lib/commands/generic");
15+
const { login, logout, whoami } = require("./lib/commands/generic");
1516
const { init } = require("./lib/commands/init");
1617
const { pull } = require("./lib/commands/pull");
1718
const { run } = require("./lib/commands/run");
@@ -23,6 +24,8 @@ const { migrate } = require("./lib/commands/generic");
2324
const { {{ service.name | caseLower }} } = require("./lib/commands/{{ service.name | caseLower }}");
2425
{% endfor %}
2526

27+
inquirer.registerPrompt('search-list', require('inquirer-search-list'));
28+
2629
program
2730
.description(commandDescriptions['main'])
2831
.configureHelp({
@@ -36,7 +39,7 @@ program
3639
.option("-f,--force", "Flag to confirm all warnings")
3740
.option("-a,--all", "Flag to push all resources")
3841
.option("--id [id...]", "Flag to pass list of ids for a giving action")
39-
.option("--report", "Enable reporting when cli is crashing")
42+
.option("--report", "Enable reporting in case of CLI errors")
4043
.on("option:json", () => {
4144
cliConfig.json = true;
4245
})

templates/cli/lib/client.js.twig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ const { fetch, FormData, Agent } = require("undici");
44
const JSONbig = require("json-bigint")({ storeAsString: false });
55
const {{spec.title | caseUcfirst}}Exception = require("./exception.js");
66
const { globalConfig } = require("./config.js");
7+
const chalk = require("chalk");
78

89
class Client {
910
CHUNK_SIZE = 5*1024*1024; // 5MB
10-
11+
1112
constructor() {
1213
this.endpoint = '{{spec.endpoint}}';
1314
this.headers = {
@@ -144,6 +145,14 @@ class Client {
144145
} catch (error) {
145146
throw new {{spec.title | caseUcfirst}}Exception(text, response.status, "", text);
146147
}
148+
149+
if (path !== '/account' && json.code === 401 && json.type === 'user_more_factors_required') {
150+
console.log(`${chalk.cyan.bold("ℹ Info")} ${chalk.cyan("Unusable account found, removing...")}`);
151+
152+
const current = globalConfig.getCurrentSession();
153+
globalConfig.setCurrentSession('');
154+
globalConfig.removeSession(current);
155+
}
147156
throw new {{spec.title | caseUcfirst}}Exception(json.message, json.code, json.type, json);
148157
}
149158

templates/cli/lib/commands/command.js.twig

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({
7070
{%- if 'multipart/form-data' in method.consumes -%},onProgress = () => {}{%- endif -%}
7171

7272
{%- if method.type == 'location' -%}, destination{%- endif -%}
73-
{% if methodHaveConsolePreview(method.name,service.name) %}, console, open{%- endif -%}
73+
{% if hasConsolePreview(method.name,service.name) %}, console{%- endif -%}
7474
}) => {
7575
{%~ endblock %}
7676
let client = !sdk ? await {% if service.name == "projects" %}sdkForConsole(){% else %}sdkForProject(){% endif %} :
@@ -95,9 +95,8 @@ const {{ service.name | caseLower }}{{ method.name | caseUcfirst }} = async ({
9595
{% if method.type == 'location' %}
9696
.requiredOption(`--destination <path>`, `output file path.`)
9797
{% endif %}
98-
{% if methodHaveConsolePreview(method.name,service.name) %}
98+
{% if hasConsolePreview(method.name,service.name) %}
9999
.option(`--console`, `Get the resource console url`)
100-
.option(`--open`, `Use with '--console' to open the using default browser`)
101100
{% endif %}
102101
{% endautoescape %}
103102
.action(actionRunner({{ service.name | caseLower }}{{ method.name | caseUcfirst }}))

templates/cli/lib/commands/generic.js.twig

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,39 @@
11
const inquirer = require("inquirer");
22
const { Command } = require("commander");
33
const Client = require("../client");
4-
const { sdkForConsole, questionGetEndpoint } = require("../sdks");
4+
const { sdkForConsole } = require("../sdks");
55
const { globalConfig, localConfig } = require("../config");
66
const { actionRunner, success, parseBool, commandDescriptions, error, parse, log, drawTable } = require("../parser");
77
const ID = require("../id");
88
{% if sdk.test != "true" %}
9-
const { questionsLogin, questionLoginWithEndpoint, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
10-
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
9+
const { questionsLogin, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
10+
const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
1111

1212
const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1';
1313

14-
const loginCommand = async ({ selfHosted, email, password, endpoint, mfa, code }) => {
15-
const oldCurrent = globalConfig.getCurrentLogin();
16-
let answers = {};
17-
let configEndpoint = DEFAULT_ENDPOINT;
18-
19-
if (selfHosted) {
20-
answers = endpoint && email && password ? { endpoint, email, password } : await inquirer.prompt(questionLoginWithEndpoint);
21-
configEndpoint = answers.endpoint;
22-
} else {
23-
answers = email && password ? { email, password } : await inquirer.prompt(questionsLogin);
24-
}
14+
const loginCommand = async ({ email, password, endpoint, mfa, code }) => {
15+
const oldCurrent = globalConfig.getCurrentSession();
16+
let configEndpoint = endpoint ?? DEFAULT_ENDPOINT;
2517

18+
const answers = email && password ? { email, password } : await inquirer.prompt(questionsLogin);
2619

2720
if (answers.method === 'select') {
2821
const accountId = answers.accountId;
2922

30-
if (!globalConfig.getLoginIds().includes(accountId)) {
31-
throw Error('Login ID not found');
23+
if (!globalConfig.getSessionIds().includes(accountId)) {
24+
throw Error('Session ID not found');
3225
}
3326

34-
globalConfig.setCurrentLogin(accountId);
27+
globalConfig.setCurrentSession(accountId);
3528
success(`Current account is ${accountId}`);
3629

3730
return;
3831
}
3932

4033
const id = ID.unique();
4134

42-
globalConfig.addLogin(id, {});
43-
globalConfig.setCurrentLogin(id);
35+
globalConfig.addSession(id, {});
36+
globalConfig.setCurrentSession(id);
4437
globalConfig.setEndpoint(configEndpoint);
4538
globalConfig.setEmail(answers.email);
4639

@@ -86,8 +79,8 @@ const loginCommand = async ({ selfHosted, email, password, endpoint, mfa, code }
8679
parseOutput: false
8780
});
8881
} else {
89-
globalConfig.removeLogin(id);
90-
globalConfig.setCurrentLogin(oldCurrent);
82+
globalConfig.removeSession(id);
83+
globalConfig.setCurrentSession(oldCurrent);
9184
throw error;
9285
}
9386
}
@@ -123,7 +116,8 @@ const whoami = new Command("whoami")
123116
'ID': account.$id,
124117
'Name': account.name,
125118
'Email': account.email,
126-
'MFA enabled': account.mfa ? 'Yes' : 'No'
119+
'MFA enabled': account.mfa ? 'Yes' : 'No',
120+
'Endpoint': globalConfig.getEndpoint()
127121
}
128122
];
129123
if (json) {
@@ -137,7 +131,6 @@ const whoami = new Command("whoami")
137131

138132
const login = new Command("login")
139133
.description(commandDescriptions['login'])
140-
.option(`-sh, --self-hosted`, `Flag for enabling custom endpoint for self hosted instances`)
141134
.option(`--email [email]`, `User email`)
142135
.option(`--password [password]`, `User password`)
143136
.option(`--endpoint [endpoint]`, `Appwrite endpoint for self hosted instances`)
@@ -148,7 +141,7 @@ const login = new Command("login")
148141
})
149142
.action(actionRunner(loginCommand));
150143

151-
const singleLogout = async (accountId) => {
144+
const deleteSession = async (accountId) => {
152145
try {
153146
let client = await sdkForConsole();
154147

@@ -158,11 +151,11 @@ const singleLogout = async (accountId) => {
158151
sdk: client
159152
})
160153

161-
globalConfig.removeLogin(accountId);
154+
globalConfig.removeSession(accountId);
162155
} catch (e) {
163156
error('Unable to log out, removing locally saved session information')
164157
}
165-
globalConfig.removeLogin(accountId);
158+
globalConfig.removeSession(accountId);
166159
}
167160

168161
const logout = new Command("logout")
@@ -171,14 +164,14 @@ const logout = new Command("logout")
171164
helpWidth: process.stdout.columns || 80
172165
})
173166
.action(actionRunner(async () => {
174-
const logins = globalConfig.getLogins();
175-
const current = globalConfig.getCurrentLogin();
167+
const sessions = globalConfig.getSessions();
168+
const current = globalConfig.getCurrentSession();
176169

177170
if (current === '') {
178171
return;
179172
}
180-
if (logins.length === 1) {
181-
await singleLogout(current);
173+
if (sessions.length === 1) {
174+
await deleteSession(current);
182175
success();
183176

184177
return;
@@ -188,16 +181,16 @@ const logout = new Command("logout")
188181

189182
if (answers.accounts) {
190183
for (let accountId of answers.accounts) {
191-
globalConfig.setCurrentLogin(accountId);
192-
await singleLogout(accountId);
184+
globalConfig.setCurrentSession(accountId);
185+
await deleteSession(accountId);
193186
}
194187
}
195188

196-
const leftLogins = globalConfig.getLogins();
189+
const remainingSessions = globalConfig.getSessions();
197190

198-
if (leftLogins.length > 0 && leftLogins.filter(login => login.id === current).length !== 1) {
199-
const accountId = leftLogins[0].id;
200-
globalConfig.setCurrentLogin(accountId);
191+
if (remainingSessions .length > 0 && remainingSessions .filter(session => session.id === current).length !== 1) {
192+
const accountId = remainingSessions [0].id;
193+
globalConfig.setCurrentSession(accountId);
201194

202195
success(`Current account is ${accountId}`);
203196
}
@@ -250,8 +243,8 @@ const client = new Command("client")
250243
if (!response.version) {
251244
throw new Error();
252245
}
253-
globalConfig.setCurrentLogin(id);
254-
globalConfig.addLogin(id, {});
246+
globalConfig.setCurrentSession(id);
247+
globalConfig.addSession(id, {});
255248
globalConfig.setEndpoint(endpoint);
256249
} catch (_) {
257250
throw new Error("Invalid endpoint or your Appwrite server is not running as expected.");
@@ -271,11 +264,11 @@ const client = new Command("client")
271264
}
272265

273266
if (reset !== undefined) {
274-
const logins = globalConfig.getLogins();
267+
const sessions = globalConfig.getSessions();
275268

276-
for (let accountId of logins.map(login => login.id)) {
277-
globalConfig.setCurrentLogin(accountId);
278-
await singleLogout(accountId);
269+
for (let accountId of sessions.map(session => session.id)) {
270+
globalConfig.setCurrentSession(accountId);
271+
await deleteSession(accountId);
279272
}
280273
}
281274

@@ -297,8 +290,8 @@ const migrate = async () => {
297290
email: 'legacy'
298291
};
299292

300-
globalConfig.addLogin(id, data);
301-
globalConfig.setCurrentLogin(id);
293+
globalConfig.addSession(id, data);
294+
globalConfig.setCurrentSession(id);
302295
globalConfig.delete('endpoint');
303296
globalConfig.delete('cookie');
304297

0 commit comments

Comments
 (0)