appwrite-cli 6.0.0-rc.1 → 6.0.0-rc.3

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 CHANGED
@@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using
29
29
 
30
30
  ```sh
31
31
  $ appwrite -v
32
- 6.0.0-rc.1
32
+ 6.0.0-rc.3
33
33
  ```
34
34
 
35
35
  ### Install using prebuilt binaries
@@ -60,7 +60,7 @@ $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/sc
60
60
  Once the installation completes, you can verify your install using
61
61
  ```
62
62
  $ appwrite -v
63
- 6.0.0-rc.1
63
+ 6.0.0-rc.3
64
64
  ```
65
65
 
66
66
  ## Getting Started
package/index.js CHANGED
@@ -15,7 +15,7 @@ const { login, logout, whoami, migrate, register } = require("./lib/commands/gen
15
15
  const { init } = require("./lib/commands/init");
16
16
  const { pull } = require("./lib/commands/pull");
17
17
  const { run } = require("./lib/commands/run");
18
- const { push } = require("./lib/commands/push");
18
+ const { push, deploy } = require("./lib/commands/push");
19
19
  const { account } = require("./lib/commands/account");
20
20
  const { avatars } = require("./lib/commands/avatars");
21
21
  const { assistant } = require("./lib/commands/assistant");
@@ -77,6 +77,7 @@ program
77
77
  .addCommand(init)
78
78
  .addCommand(pull)
79
79
  .addCommand(push)
80
+ .addCommand(deploy)
80
81
  .addCommand(run)
81
82
  .addCommand(logout)
82
83
  .addCommand(account)
package/install.ps1 CHANGED
@@ -13,8 +13,8 @@
13
13
  # You can use "View source" of this page to see the full script.
14
14
 
15
15
  # REPO
16
- $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/6.0.0-rc.1/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/6.0.0-rc.1/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/6.0.0-rc.3/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/6.0.0-rc.3/appwrite-cli-win-arm64.exe"
18
18
 
19
19
  $APPWRITE_BINARY_NAME = "appwrite.exe"
20
20
 
package/install.sh CHANGED
@@ -97,7 +97,7 @@ printSuccess() {
97
97
  downloadBinary() {
98
98
  echo "[2/4] Downloading executable for $OS ($ARCH) ..."
99
99
 
100
- GITHUB_LATEST_VERSION="6.0.0-rc.1"
100
+ GITHUB_LATEST_VERSION="6.0.0-rc.3"
101
101
  GITHUB_FILE="appwrite-cli-${OS}-${ARCH}"
102
102
  GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE"
103
103
 
package/lib/client.js CHANGED
@@ -16,8 +16,8 @@ class Client {
16
16
  'x-sdk-name': 'Command Line',
17
17
  'x-sdk-platform': 'console',
18
18
  'x-sdk-language': 'cli',
19
- 'x-sdk-version': '6.0.0-rc.1',
20
- 'user-agent' : `AppwriteCLI/6.0.0-rc.1 (${os.type()} ${os.version()}; ${os.arch()})`,
19
+ 'x-sdk-version': '6.0.0-rc.3',
20
+ 'user-agent' : `AppwriteCLI/6.0.0-rc.3 (${os.type()} ${os.version()}; ${os.arch()})`,
21
21
  'X-Appwrite-Response-Format' : '1.5.0',
22
22
  };
23
23
  }
@@ -168,7 +168,7 @@ class Client {
168
168
 
169
169
  body = formData;
170
170
  } else {
171
- body = JSON.stringify(params);
171
+ body = JSONbig.stringify(params);
172
172
  }
173
173
 
174
174
  let response = undefined;
@@ -224,7 +224,7 @@ class Client {
224
224
  const text = await response.text();
225
225
  let json = undefined;
226
226
  try {
227
- json = JSON.parse(text);
227
+ json = JSONbig.parse(text);
228
228
  } catch (error) {
229
229
  return text;
230
230
  }
@@ -3,7 +3,7 @@ const { Command } = require("commander");
3
3
  const Client = require("../client");
4
4
  const { sdkForConsole } = require("../sdks");
5
5
  const { globalConfig, localConfig } = require("../config");
6
- const { actionRunner, success, parseBool, commandDescriptions, error, parse, log, drawTable, cliConfig } = require("../parser");
6
+ const { actionRunner, success, parseBool, commandDescriptions, error, parse, hint, log, drawTable, cliConfig } = require("../parser");
7
7
  const ID = require("../id");
8
8
  const { questionsLogin, questionsLogout, questionsListFactors, questionsMfaChallenge } = require("../questions");
9
9
  const { accountUpdateMfaChallenge, accountCreateMfaChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } = require("./account");
@@ -14,8 +14,20 @@ const loginCommand = async ({ email, password, endpoint, mfa, code }) => {
14
14
  const oldCurrent = globalConfig.getCurrentSession();
15
15
  let configEndpoint = endpoint ?? DEFAULT_ENDPOINT;
16
16
 
17
+ if(globalConfig.getCurrentSession() !== '') {
18
+ log('You are currently signed in as ' + globalConfig.getEmail());
19
+
20
+ if(globalConfig.getSessions().length === 1) {
21
+ hint('You can sign in and manage multiple accounts with Appwrite CLI');
22
+ }
23
+ }
24
+
17
25
  const answers = email && password ? { email, password } : await inquirer.prompt(questionsLogin);
18
26
 
27
+ if(!answers.method) {
28
+ answers.method = 'login';
29
+ }
30
+
19
31
  if (answers.method === 'select') {
20
32
  const accountId = answers.accountId;
21
33
 
@@ -87,15 +99,15 @@ const loginCommand = async ({ email, password, endpoint, mfa, code }) => {
87
99
  }
88
100
  }
89
101
 
90
- success("Signed in as user with ID: " + account.$id);
91
- log("Next you can create or link to your project using 'appwrite init project'");
102
+ success("Successfully signed in as " + account.email);
103
+ hint("Next you can create or link to your project using 'appwrite init project'");
92
104
  };
93
105
 
94
106
  const whoami = new Command("whoami")
95
107
  .description(commandDescriptions['whoami'])
96
108
  .action(actionRunner(async () => {
97
109
  if (globalConfig.getEndpoint() === '' || globalConfig.getCookie() === '') {
98
- error("No user is signed in. To sign in, run: appwrite login ");
110
+ error("No user is signed in. To sign in, run 'appwrite login'");
99
111
  return;
100
112
  }
101
113
 
@@ -109,7 +121,7 @@ const whoami = new Command("whoami")
109
121
  parseOutput: false
110
122
  });
111
123
  } catch (error) {
112
- error("No user is signed in. To sign in, run: appwrite login");
124
+ error("No user is signed in. To sign in, run 'appwrite login'");
113
125
  return;
114
126
  }
115
127
 
@@ -9,6 +9,7 @@ const { storageCreateBucket } = require("./storage");
9
9
  const { messagingCreateTopic } = require("./messaging");
10
10
  const { functionsCreate } = require("./functions");
11
11
  const { databasesCreateCollection } = require("./databases");
12
+ const { pullResources } = require("./pull");
12
13
  const ID = require("../id");
13
14
  const { localConfig, globalConfig } = require("../config");
14
15
  const {
@@ -18,10 +19,11 @@ const {
18
19
  questionsCreateMessagingTopic,
19
20
  questionsCreateCollection,
20
21
  questionsInitProject,
22
+ questionsInitProjectAutopull,
21
23
  questionsInitResources,
22
24
  questionsCreateTeam
23
25
  } = require("../questions");
24
- const { success, log, error, actionRunner, commandDescriptions } = require("../parser");
26
+ const { cliConfig, success, log, hint, error, actionRunner, commandDescriptions } = require("../parser");
25
27
  const { accountGet } = require("./account");
26
28
  const { sdkForConsole } = require("../sdks");
27
29
 
@@ -56,7 +58,7 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
56
58
  sdk: client
57
59
  });
58
60
  } catch (e) {
59
- error('Error Session not found. Please run `appwrite login` to create a session');
61
+ error("Error Session not found. Please run 'appwrite login' to create a session");
60
62
  process.exit(1);
61
63
  }
62
64
 
@@ -104,11 +106,17 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
104
106
 
105
107
  success(`Project successfully ${answers.start === 'existing' ? 'linked' : 'created'}. Details are now stored in appwrite.json file.`);
106
108
 
107
- log("Next you can use 'appwrite init' to create resources in your project, or use 'appwrite pull' and 'appwite push' to synchronize your project.")
108
-
109
109
  if(answers.start === 'existing') {
110
- log("Since you connected to an existing project, we highly recommend to run 'appwrite pull all' to synchronize all of your existing resources.");
110
+ answers = await inquirer.prompt(questionsInitProjectAutopull);
111
+ if(answers.autopull) {
112
+ cliConfig.all = true;
113
+ await pullResources();
114
+ } else {
115
+ log("You can run 'appwrite pull all' to synchronize all of your existing resources.");
116
+ }
111
117
  }
118
+
119
+ hint("Next you can use 'appwrite init' to create resources in your project, or use 'appwrite pull' and 'appwrite push' to synchronize your project.")
112
120
  }
113
121
 
114
122
  const initBucket = async () => {
@@ -210,22 +218,24 @@ const initFunction = async () => {
210
218
  log(`Installation command for this runtime not found. You will be asked to configure the install command when you first push the function.`);
211
219
  }
212
220
 
213
-
214
221
  fs.mkdirSync(functionDir, "777");
215
222
  fs.mkdirSync(templatesDir, "777");
216
223
  const repo = "https://github.com/appwrite/templates";
217
224
  const api = `https://api.github.com/repos/appwrite/templates/contents/${answers.runtime.name}`
218
- const templates = ['starter'];
219
225
  let selected = undefined;
220
226
 
221
- try {
222
- const res = await fetch(api);
223
- templates.push(...(await res.json()).map((template) => template.name));
224
-
225
- selected = await inquirer.prompt(questionsCreateFunctionSelectTemplate(templates))
226
- } catch {
227
- // Not a problem will go with directory pulling
228
- log('Loading templates...');
227
+ if(answers.template === 'starter') {
228
+ selected = { template: 'starter' };
229
+ } else {
230
+ try {
231
+ const res = await fetch(api);
232
+ const templates = [];
233
+ templates.push(...(await res.json()).map((template) => template.name));
234
+ selected = await inquirer.prompt(questionsCreateFunctionSelectTemplate(templates));
235
+ } catch {
236
+ // Not a problem will go with directory pulling
237
+ log('Loading templates...');
238
+ }
229
239
  }
230
240
 
231
241
  const sparse = (selected ? `${answers.runtime.name}/${selected.template}` : answers.runtime.name).toLowerCase();
@@ -257,6 +267,7 @@ const initFunction = async () => {
257
267
 
258
268
  fs.rmSync(path.join(templatesDir, ".git"), { recursive: true });
259
269
  if (!selected) {
270
+ const templates = [];
260
271
  templates.push(...fs.readdirSync(runtimeDir, { withFileTypes: true })
261
272
  .filter(item => item.isDirectory() && item.name !== 'starter')
262
273
  .map(dirent => dirent.name));
@@ -1,4 +1,5 @@
1
1
  const fs = require("fs");
2
+ const chalk = require('chalk');
2
3
  const tar = require("tar");
3
4
  const { Command } = require("commander");
4
5
  const inquirer = require("inquirer");
@@ -10,12 +11,12 @@ const { databasesGet, databasesListCollections, databasesList } = require("./dat
10
11
  const { storageListBuckets } = require("./storage");
11
12
  const { localConfig } = require("../config");
12
13
  const { paginate } = require("../paginate");
13
- const { questionsPullCollection, questionsPullFunctions, questionsPullResources } = require("../questions");
14
- const { cliConfig, success, log, actionRunner, commandDescriptions } = require("../parser");
14
+ const { questionsPullCollection, questionsPullFunctions, questionsPullFunctionsCode, questionsPullResources } = require("../questions");
15
+ const { cliConfig, success, log, warn, actionRunner, commandDescriptions } = require("../parser");
15
16
 
16
17
  const pullResources = async () => {
17
18
  const actions = {
18
- project: pullProject,
19
+ settings: pullSettings,
19
20
  functions: pullFunctions,
20
21
  collections: pullCollection,
21
22
  buckets: pullBucket,
@@ -25,6 +26,7 @@ const pullResources = async () => {
25
26
 
26
27
  if (cliConfig.all) {
27
28
  for (let action of Object.values(actions)) {
29
+ cliConfig.all = true;
28
30
  await action();
29
31
  }
30
32
  } else {
@@ -37,75 +39,110 @@ const pullResources = async () => {
37
39
  }
38
40
  };
39
41
 
40
- const pullProject = async () => {
42
+ const pullSettings = async () => {
43
+ log("Pulling project settings ...");
44
+
41
45
  try {
42
46
  let response = await projectsGet({
43
47
  parseOutput: false,
44
48
  projectId: localConfig.getProject().projectId
45
-
46
- })
49
+ });
47
50
 
48
51
  localConfig.setProject(response.$id, response.name, response);
49
52
 
50
- success();
53
+ success(`Successfully pulled ${chalk.bold('all')} project settings.`);
51
54
  } catch (e) {
52
55
  throw e;
53
56
  }
54
57
  }
55
58
 
56
- const pullFunctions = async () => {
57
- const localFunctions = localConfig.getFunctions();
59
+ const pullFunctions = async ({ code }) => {
60
+ log("Fetching functions ...");
61
+ let total = 0;
62
+
63
+ const fetchResponse = await functionsList({
64
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
65
+ parseOutput: false
66
+ });
67
+ if (fetchResponse["functions"].length <= 0) {
68
+ log("No functions found.");
69
+ success(`Successfully pulled ${chalk.bold(total)} functions.`);
70
+ return;
71
+ }
58
72
 
59
73
  const functions = cliConfig.all
60
74
  ? (await paginate(functionsList, { parseOutput: false }, 100, 'functions')).functions
61
75
  : (await inquirer.prompt(questionsPullFunctions)).functions;
62
76
 
63
- log(`Pulling ${functions.length} functions`);
77
+ let allowCodePull = cliConfig.force === true ? true : null;
64
78
 
65
79
  for (let func of functions) {
66
- const functionExistLocally = localFunctions.find((localFunc) => localFunc['$id'] === func['$id']) !== undefined;
80
+ total++;
81
+ log(`Pulling function ${chalk.bold(func['name'])} ...`);
67
82
 
68
- if (functionExistLocally) {
69
- localConfig.updateFunction(func['$id'], func);
70
- } else {
71
- func['path'] = `functions/${func['$id']}`;
72
- localConfig.addFunction(func);
73
- localFunctions.push(func);
74
- }
75
-
76
- const localFunction = localFunctions.find((localFunc) => localFunc['$id'] === func['$id']);
83
+ const localFunction = localConfig.getFunction(func.$id);
77
84
 
78
- if (localFunction['deployment'] === '') {
79
- continue
85
+ func['path'] = localFunction['path'];
86
+ if(!localFunction['path']) {
87
+ func['path'] = `functions/${func.$id}`;
80
88
  }
81
89
 
82
- const compressedFileName = `${func['$id']}-${+new Date()}.tar.gz`
83
-
84
- await functionsDownloadDeployment({
85
- functionId: func['$id'],
86
- deploymentId: func['deployment'],
87
- destination: compressedFileName,
88
- overrideForCli: true,
89
- parseOutput: false
90
- })
90
+ localConfig.addFunction(func);
91
91
 
92
- if (!fs.existsSync(localFunction['path'])) {
93
- fs.mkdirSync(localFunction['path'], { recursive: true });
92
+ if (!fs.existsSync(func['path'])) {
93
+ fs.mkdirSync(func['path'], { recursive: true });
94
94
  }
95
-
96
- tar.extract({
97
- sync: true,
98
- cwd: localFunction['path'],
99
- file: compressedFileName,
100
- strict: false,
101
- });
102
-
103
- fs.rmSync(compressedFileName);
104
- success(`Pulled ${func['name']} code and settings`)
95
+
96
+ if(code === false) {
97
+ warn("Source code download skipped.");
98
+ } else if(!func['deployment']) {
99
+ warn("Source code download skipped because function doesn't have active deployment.");
100
+ } else {
101
+ if(allowCodePull === null) {
102
+ const codeAnswer = await inquirer.prompt(questionsPullFunctionsCode);
103
+ allowCodePull = codeAnswer.override;
104
+ }
105
+
106
+ if(allowCodePull) {
107
+ log("Pulling active deployment's code ...");
108
+
109
+ const compressedFileName = `${func['$id']}-${+new Date()}.tar.gz`
110
+ await functionsDownloadDeployment({
111
+ functionId: func['$id'],
112
+ deploymentId: func['deployment'],
113
+ destination: compressedFileName,
114
+ overrideForCli: true,
115
+ parseOutput: false
116
+ });
117
+
118
+ tar.extract({
119
+ sync: true,
120
+ cwd: func['path'],
121
+ file: compressedFileName,
122
+ strict: false,
123
+ });
124
+
125
+ fs.rmSync(compressedFileName);
126
+ }
105
127
  }
128
+
129
+ success(`Successfully pulled ${chalk.bold(total)} functions.`);
106
130
  }
107
131
 
108
132
  const pullCollection = async () => {
133
+ log("Fetching collections ...");
134
+ let total = 0;
135
+
136
+ const fetchResponse = await databasesList({
137
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
138
+ parseOutput: false
139
+ });
140
+ if (fetchResponse["databases"].length <= 0) {
141
+ log("No collections found.");
142
+ success(`Successfully pulled ${chalk.bold(total)} collections.`);
143
+ return;
144
+ }
145
+
109
146
  let databases = cliConfig.ids;
110
147
 
111
148
  if (databases.length === 0) {
@@ -122,61 +159,101 @@ const pullCollection = async () => {
122
159
  parseOutput: false
123
160
  });
124
161
 
162
+ total++;
163
+ log(`Pulling all collections from ${chalk.bold(database['name'])} database ...`);
164
+
125
165
  localConfig.addDatabase(database);
126
166
 
127
- const { collections, total } = await paginate(databasesListCollections, {
167
+ const { collections } = await paginate(databasesListCollections, {
128
168
  databaseId,
129
169
  parseOutput: false
130
170
  }, 100, 'collections');
131
171
 
132
- log(`Found ${total} collections`);
133
-
134
- collections.map(async collection => {
135
- log(`Fetching ${collection.name} ...`);
172
+ for(const collection of collections) {
136
173
  localConfig.addCollection({
137
174
  ...collection,
138
175
  '$createdAt': undefined,
139
176
  '$updatedAt': undefined
140
177
  });
141
- });
178
+ }
142
179
  }
143
180
 
144
- success();
181
+ success(`Successfully pulled ${chalk.bold(total)} collections.`);
145
182
  }
146
183
 
147
184
  const pullBucket = async () => {
148
- const { buckets } = await paginate(storageListBuckets, { parseOutput: false }, 100, 'buckets');
185
+ log("Fetching buckets ...");
186
+ let total = 0;
149
187
 
150
- log(`Found ${buckets.length} buckets`);
188
+ const fetchResponse = await storageListBuckets({
189
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
190
+ parseOutput: false
191
+ });
192
+ if (fetchResponse["buckets"].length <= 0) {
193
+ log("No buckets found.");
194
+ success(`Successfully pulled ${chalk.bold(total)} buckets.`);
195
+ return;
196
+ }
151
197
 
152
- buckets.forEach(bucket => localConfig.addBucket(bucket));
198
+ const { buckets } = await paginate(storageListBuckets, { parseOutput: false }, 100, 'buckets');
153
199
 
154
- success();
200
+ for(const bucket of buckets) {
201
+ total++;
202
+ log(`Pulling bucket ${chalk.bold(bucket['name'])} ...`);
203
+ localConfig.addBucket(bucket);
204
+ }
205
+
206
+ success(`Successfully pulled ${chalk.bold(total)} buckets.`);
155
207
  }
156
208
 
157
209
  const pullTeam = async () => {
158
- const { teams } = await paginate(teamsList, { parseOutput: false }, 100, 'teams');
210
+ log("Fetching teams ...");
211
+ let total = 0;
159
212
 
160
- log(`Found ${teams.length} teams`);
161
-
162
- teams.forEach(team => {
163
- const { total, $updatedAt, $createdAt, prefs, ...rest } = team;
164
- localConfig.addTeam(rest);
213
+ const fetchResponse = await teamsList({
214
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
215
+ parseOutput: false
165
216
  });
217
+ if (fetchResponse["teams"].length <= 0) {
218
+ log("No teams found.");
219
+ success(`Successfully pulled ${chalk.bold(total)} teams.`);
220
+ return;
221
+ }
166
222
 
167
- success();
223
+ const { teams } = await paginate(teamsList, { parseOutput: false }, 100, 'teams');
224
+
225
+ for(const team of teams) {
226
+ total++;
227
+ log(`Pulling team ${chalk.bold(team['name'])} ...`);
228
+ localConfig.addTeam(team);
229
+ }
230
+
231
+ success(`Successfully pulled ${chalk.bold(total)} teams.`);
168
232
  }
169
233
 
170
234
  const pullMessagingTopic = async () => {
171
- const { topics } = await paginate(messagingListTopics, { parseOutput: false }, 100, 'topics');
235
+ log("Fetching topics ...");
236
+ let total = 0;
172
237
 
173
- log(`Found ${topics.length} topics`);
238
+ const fetchResponse = await messagingListTopics({
239
+ queries: [JSON.stringify({ method: 'limit', values: [1] })],
240
+ parseOutput: false
241
+ });
242
+ if (fetchResponse["topics"].length <= 0) {
243
+ log("No topics found.");
244
+ success(`Successfully pulled ${chalk.bold(total)} topics.`);
245
+ return;
246
+ }
247
+
248
+ const { topics } = await paginate(messagingListTopics, { parseOutput: false }, 100, 'topics');
174
249
 
175
- topics.forEach(topic => {
250
+ for(const topic of topics) {
251
+ total++;
252
+ log(`Pulling topic ${chalk.bold(topic['name'])} ...`);
176
253
  localConfig.addMessagingTopic(topic);
177
- });
254
+ }
178
255
 
179
- success();
256
+ success(`Successfully pulled ${chalk.bold(total)} topics.`);
180
257
  }
181
258
 
182
259
  const pull = new Command("pull")
@@ -192,14 +269,15 @@ pull
192
269
  }));
193
270
 
194
271
  pull
195
- .command("project")
272
+ .command("settings")
196
273
  .description("Pull your Appwrite project name, services and auth settings")
197
- .action(actionRunner(pullProject));
274
+ .action(actionRunner(pullSettings));
198
275
 
199
276
  pull
200
277
  .command("function")
201
278
  .alias("functions")
202
279
  .description("Pulling your Appwrite cloud function")
280
+ .option("--no-code", "Don't pull the function's code")
203
281
  .action(actionRunner(pullFunctions))
204
282
 
205
283
  pull
@@ -228,4 +306,5 @@ pull
228
306
 
229
307
  module.exports = {
230
308
  pull,
309
+ pullResources
231
310
  };