appwrite-cli 0.18.1 → 0.18.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # Appwrite Command Line SDK
2
2
 
3
3
  ![License](https://img.shields.io/github/license/appwrite/sdk-for-cli.svg?style=flat-square)
4
- ![Version](https://img.shields.io/badge/api%20version-0.15.1-blue.svg?style=flat-square)
4
+ ![Version](https://img.shields.io/badge/api%20version-0.15.0-blue.svg?style=flat-square)
5
5
  [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator)
6
6
  [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
7
7
  [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)
@@ -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
- 0.18.1
32
+ 0.18.2
33
33
  ```
34
34
 
35
35
  ### Install using prebuilt binaries
@@ -58,7 +58,7 @@ $ iwr -useb https://appwrite.io/cli/install.ps1 | iex
58
58
  Once the installation completes, you can verify your install using
59
59
  ```
60
60
  $ appwrite -v
61
- 0.18.1
61
+ 0.18.2
62
62
  ```
63
63
 
64
64
  ## Getting Started
@@ -94,6 +94,12 @@ You can also fetch all the collections in your current project using
94
94
  appwrite init collection
95
95
  ```
96
96
 
97
+ The CLI also comes with a convenient `--all` flag to perform both these steps at once.
98
+
99
+ ```sh
100
+ appwrite init --all
101
+ ```
102
+
97
103
  * ### Creating and deploying cloud functions
98
104
 
99
105
  The CLI makes it extremely easy to create and deploy Appwrite's cloud functions. Initialise your new function using
@@ -139,6 +145,12 @@ Similarly, you can deploy all your collections to your Appwrite server using
139
145
  appwrite deploy collections
140
146
  ```
141
147
 
148
+ The `deploy` command also comes with a convenient `--all` flag to deploy all your functions and collections at once.
149
+
150
+ ```sh
151
+ appwrite deploy --all
152
+ ```
153
+
142
154
  > ### Note
143
155
  > By default, requests to domains with self signed SSL certificates (or no certificates) are disabled. If you trust the domain, you can bypass the certificate validation using
144
156
  ```sh
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/0.18.1/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.1/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.2/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.2/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="0.18.1"
100
+ GITHUB_LATEST_VERSION="0.18.2"
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
@@ -12,8 +12,8 @@ class Client {
12
12
  this.endpoint = 'https://HOSTNAME/v1';
13
13
  this.headers = {
14
14
  'content-type': '',
15
- 'x-sdk-version': 'appwrite:cli:0.18.1',
16
- 'User-Agent' : `AppwriteCLI/0.18.1 (${os.type()} ${os.version()}; ${os.arch()})`,
15
+ 'x-sdk-version': 'appwrite:cli:0.18.2',
16
+ 'User-Agent' : `AppwriteCLI/0.18.2 (${os.type()} ${os.version()}; ${os.arch()})`,
17
17
  'X-Appwrite-Response-Format' : '0.15.0',
18
18
  };
19
19
  }
@@ -784,7 +784,7 @@ account
784
784
 
785
785
  account
786
786
  .command(`updatePhone`)
787
- .description(`Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST /account/verification/phone](/docs/client/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.`)
787
+ .description(`Update currently logged in user account phone number. After changing phone number, the user confirmation status will get reset. A new confirmation SMS is not sent automatically however you can use the phone confirmation endpoint again to send the confirmation SMS.`)
788
788
  .requiredOption(`--number <number>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`)
789
789
  .requiredOption(`--password <password>`, `User password. Must be at least 8 chars.`)
790
790
  .action(actionRunner(accountUpdatePhone))
@@ -856,7 +856,7 @@ account
856
856
  account
857
857
  .command(`createOAuth2Session`)
858
858
  .description(`Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. If there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.. `)
859
- .requiredOption(`--provider <provider>`, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, autodesk, bitbucket, bitly, box, dailymotion, discord, dropbox, facebook, github, gitlab, google, linkedin, microsoft, notion, okta, paypal, paypalSandbox, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.`)
859
+ .requiredOption(`--provider <provider>`, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, bitbucket, bitly, box, dailymotion, discord, dropbox, facebook, github, gitlab, google, linkedin, microsoft, notion, okta, paypal, paypalSandbox, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.`)
860
860
  .option(`--success <success>`, `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`)
861
861
  .option(`--failure <failure>`, `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`)
862
862
  .option(`--scopes <scopes...>`, `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`)
@@ -864,14 +864,14 @@ account
864
864
 
865
865
  account
866
866
  .command(`createPhoneSession`)
867
- .description(`Sends the user an SMS with a secret key for creating a session. Use the returned user ID and secret and submit a request to the [PUT /account/sessions/phone](/docs/client/account#accountUpdatePhoneSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.`)
867
+ .description(`Sends the user a SMS with a secret key for creating a session. Use the returned user ID and the secret to submit a request to the [PUT /account/sessions/phone](/docs/client/account#accountUpdatePhoneSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.`)
868
868
  .requiredOption(`--userId <userId>`, `Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`)
869
869
  .requiredOption(`--number <number>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`)
870
870
  .action(actionRunner(accountCreatePhoneSession))
871
871
 
872
872
  account
873
873
  .command(`updatePhoneSession`)
874
- .description(`Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](/docs/client/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.`)
874
+ .description(`Use this endpoint to complete creating the session with the Magic URL. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST /account/sessions/magic-url](/docs/client/account#accountCreateMagicURLSession) endpoint. Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.`)
875
875
  .requiredOption(`--userId <userId>`, `User ID.`)
876
876
  .requiredOption(`--secret <secret>`, `Valid verification token.`)
877
877
  .action(actionRunner(accountUpdatePhoneSession))
@@ -914,7 +914,7 @@ account
914
914
 
915
915
  account
916
916
  .command(`createPhoneVerification`)
917
- .description(`Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](/docs/client/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](/docs/client/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.`)
917
+ .description(`Use this endpoint to send a verification message to your user's phone number to confirm they are the valid owners of that address. The provided secret should allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](/docs/client/account#accountUpdatePhoneVerification). The verification link sent to the user's phone number is valid for 15 minutes.`)
918
918
  .action(actionRunner(accountCreatePhoneVerification))
919
919
 
920
920
  account
@@ -6,37 +6,34 @@ const { questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollect
6
6
  const { actionRunner, success, log, error, commandDescriptions } = require("../parser");
7
7
  const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsUpdateDeployment } = require('./functions');
8
8
  const {
9
- databasesGet,
10
- databasesCreate,
11
- databasesCreateBooleanAttribute,
12
- databasesGetCollection,
13
- databasesCreateCollection,
14
- databasesCreateStringAttribute,
15
- databasesCreateIntegerAttribute,
16
- databasesCreateFloatAttribute,
17
- databasesCreateEmailAttribute,
18
- databasesCreateIndex,
19
- databasesCreateUrlAttribute,
20
- databasesCreateIpAttribute,
21
- databasesCreateEnumAttribute,
22
- databasesDeleteAttribute,
23
- databasesListAttributes,
24
- databasesListIndexes,
25
- databasesDeleteIndex
26
- } = require("./databases");
9
+ databaseCreateBooleanAttribute,
10
+ databaseGetCollection,
11
+ databaseCreateCollection,
12
+ databaseCreateStringAttribute,
13
+ databaseCreateIntegerAttribute,
14
+ databaseCreateFloatAttribute,
15
+ databaseCreateEmailAttribute,
16
+ databaseCreateIndex,
17
+ databaseCreateUrlAttribute,
18
+ databaseCreateIpAttribute,
19
+ databaseCreateEnumAttribute,
20
+ databaseDeleteAttribute,
21
+ databaseListAttributes,
22
+ databaseListIndexes,
23
+ databaseDeleteIndex
24
+ } = require("./database");
27
25
 
28
26
  const POOL_DEBOUNCE = 2000; // in milliseconds
29
27
  const POOL_MAX_DEBOUNCES = 30;
30
28
 
31
29
  const awaitPools = {
32
- wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
30
+ wipeAttributes: async (collectionId, iteration = 1) => {
33
31
  if (iteration > POOL_MAX_DEBOUNCES) {
34
32
  return false;
35
33
  }
36
34
 
37
35
  // TODO: Pagination?
38
- const { attributes: remoteAttributes } = await databasesListAttributes({
39
- databaseId,
36
+ const { attributes: remoteAttributes } = await databaseListAttributes({
40
37
  collectionId,
41
38
  limit: 100,
42
39
  parseOutput: false
@@ -47,16 +44,15 @@ const awaitPools = {
47
44
  }
48
45
 
49
46
  await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
50
- return await awaitPools.wipeAttributes(databaseId, collectionId, iteration + 1);
47
+ return await awaitPools.wipeAttributes(collectionId, iteration + 1);
51
48
  },
52
- wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
49
+ wipeIndexes: async (collectionId, iteration = 1) => {
53
50
  if (iteration > POOL_MAX_DEBOUNCES) {
54
51
  return false;
55
52
  }
56
53
 
57
54
  // TODO: Pagination?
58
- const { indexes: remoteIndexes } = await databasesListIndexes({
59
- databaseId,
55
+ const { indexes: remoteIndexes } = await databaseListIndexes({
60
56
  collectionId,
61
57
  limit: 100,
62
58
  parseOutput: false
@@ -67,16 +63,15 @@ const awaitPools = {
67
63
  }
68
64
 
69
65
  await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
70
- return await awaitPools.wipeIndexes(databaseId, collectionId, iteration + 1);
66
+ return await awaitPools.wipeIndexes(collectionId, iteration + 1);
71
67
  },
72
- expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
68
+ expectAttributes: async (collectionId, attributeKeys, iteration = 1) => {
73
69
  if (iteration > POOL_MAX_DEBOUNCES) {
74
70
  return false;
75
71
  }
76
72
 
77
73
  // TODO: Pagination?
78
- const { attributes: remoteAttributes } = await databasesListAttributes({
79
- databaseId,
74
+ const { attributes: remoteAttributes } = await databaseListAttributes({
80
75
  collectionId,
81
76
  limit: 100,
82
77
  parseOutput: false
@@ -99,16 +94,15 @@ const awaitPools = {
99
94
  }
100
95
 
101
96
  await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
102
- return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
97
+ return await awaitPools.expectAttributes(collectionId, attributeKeys, iteration + 1);
103
98
  },
104
- expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
99
+ expectIndexes: async (collectionId, indexKeys, iteration = 1) => {
105
100
  if (iteration > POOL_MAX_DEBOUNCES) {
106
101
  return false;
107
102
  }
108
103
 
109
104
  // TODO: Pagination?
110
- const { indexes: remoteIndexes } = await databasesListIndexes({
111
- databaseId,
105
+ const { indexes: remoteIndexes } = await databaseListIndexes({
112
106
  collectionId,
113
107
  limit: 100,
114
108
  parseOutput: false
@@ -131,49 +125,32 @@ const awaitPools = {
131
125
  }
132
126
 
133
127
  await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
134
- return await awaitPools.expectIndexes(databaseId, collectionId, indexKeys, iteration + 1);
128
+ return await awaitPools.expectIndexes(collectionId, indexKeys, iteration + 1);
135
129
  },
136
130
  }
137
131
 
138
132
  const deploy = new Command("deploy")
139
133
  .description(commandDescriptions['deploy'])
140
- .action(actionRunner(async (_options, command) => {
141
- command.help()
142
- }));
143
-
144
- const deployFunction = async ({ functionId, all } = {}) => {
145
- let response = {};
146
-
147
- const functionIds = [];
148
-
149
- if(functionId) {
150
- functionIds.push(functionId);
151
- } else if(all) {
152
- const functions = localConfig.getFunctions();
153
- if (functions.length === 0) {
154
- throw new Error("No functions found in the current directory.");
134
+ .option("--all", "Flag to deploy collections and functions")
135
+ .action(actionRunner(async ({ all }, command) => {
136
+ if (all == undefined) {
137
+ command.help()
155
138
  }
156
- functionIds.push(...functions.map((func, idx) => {
157
- return func.$id;
158
- }));
159
- }
160
139
 
161
- if(functionIds.length <= 0) {
162
- const answers = await inquirer.prompt(questionsDeployFunctions);
163
- functionIds.push(...answers.functions);
164
- }
140
+ try {
141
+ await deployFunction();
142
+ } catch (e) {
143
+ error(e.message);
144
+ }
145
+ await deployCollection()
146
+ }));
165
147
 
166
- let functions = functionIds.map((id) => {
167
- const functions = localConfig.getFunctions();
168
- const func = functions.find((f) => f.$id === id);
148
+ const deployFunction = async () => {
149
+ let response = {};
169
150
 
170
- if(!func) {
171
- throw new Error("Function '" + id + "' not found.")
172
- }
151
+ let answers = await inquirer.prompt(questionsDeployFunctions)
152
+ let functions = answers.functions.map((func) => JSONbig.parse(func))
173
153
 
174
- return func;
175
- });
176
-
177
154
  for (let func of functions) {
178
155
  log(`Deploying function ${func.name} ( ${func['$id']} )`)
179
156
 
@@ -253,13 +230,12 @@ const deployFunction = async ({ functionId, all } = {}) => {
253
230
  }
254
231
  }
255
232
 
256
- const createAttribute = async (databaseId, collectionId, attribute) => {
233
+ const createAttribute = async (collectionId, attribute) => {
257
234
  switch (attribute.type) {
258
235
  case 'string':
259
236
  switch (attribute.format) {
260
237
  case 'email':
261
- return await databasesCreateEmailAttribute({
262
- databaseId,
238
+ return await databaseCreateEmailAttribute({
263
239
  collectionId,
264
240
  key: attribute.key,
265
241
  required: attribute.required,
@@ -268,8 +244,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
268
244
  parseOutput: false
269
245
  })
270
246
  case 'url':
271
- return await databasesCreateUrlAttribute({
272
- databaseId,
247
+ return await databaseCreateUrlAttribute({
273
248
  collectionId,
274
249
  key: attribute.key,
275
250
  required: attribute.required,
@@ -278,8 +253,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
278
253
  parseOutput: false
279
254
  })
280
255
  case 'ip':
281
- return await databasesCreateIpAttribute({
282
- databaseId,
256
+ return await databaseCreateIpAttribute({
283
257
  collectionId,
284
258
  key: attribute.key,
285
259
  required: attribute.required,
@@ -288,8 +262,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
288
262
  parseOutput: false
289
263
  })
290
264
  case 'enum':
291
- return await databasesCreateEnumAttribute({
292
- databaseId,
265
+ return await databaseCreateEnumAttribute({
293
266
  collectionId,
294
267
  key: attribute.key,
295
268
  elements: attribute.elements,
@@ -299,8 +272,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
299
272
  parseOutput: false
300
273
  })
301
274
  default:
302
- return await databasesCreateStringAttribute({
303
- databaseId,
275
+ return await databaseCreateStringAttribute({
304
276
  collectionId,
305
277
  key: attribute.key,
306
278
  size: attribute.size,
@@ -312,8 +284,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
312
284
 
313
285
  }
314
286
  case 'integer':
315
- return await databasesCreateIntegerAttribute({
316
- databaseId,
287
+ return await databaseCreateIntegerAttribute({
317
288
  collectionId,
318
289
  key: attribute.key,
319
290
  required: attribute.required,
@@ -324,8 +295,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
324
295
  parseOutput: false
325
296
  })
326
297
  case 'double':
327
- return databasesCreateFloatAttribute({
328
- databaseId,
298
+ return databaseCreateFloatAttribute({
329
299
  collectionId,
330
300
  key: attribute.key,
331
301
  required: attribute.required,
@@ -336,9 +306,7 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
336
306
  parseOutput: false
337
307
  })
338
308
  case 'boolean':
339
- return databasesCreateBooleanAttribute({
340
- databaseId,
341
- databaseId,
309
+ return databaseCreateBooleanAttribute({
342
310
  collectionId,
343
311
  key: attribute.key,
344
312
  required: attribute.required,
@@ -349,55 +317,15 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
349
317
  }
350
318
  }
351
319
 
352
- const deployCollection = async ({ all } = {}) => {
320
+ const deployCollection = async () => {
353
321
  let response = {};
354
-
355
- let collectionIds = [];
356
- const configCollections = localConfig.getCollections();
357
-
358
- if(all) {
359
- if (configCollections.length === 0) {
360
- throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
361
- }
362
- collectionIds.push(...configCollections.map((c) => c.$id));
363
- }
364
-
365
- if(collectionIds.length <= 0) {
366
- let answers = await inquirer.prompt(questionsDeployCollections[0])
367
- collectionIds.push(...answers.collections);
368
- }
369
-
370
- let collections = [];
371
-
372
- for(const collectionId of collectionIds) {
373
- const idCollections = configCollections.filter((c) => c.$id === collectionId);
374
- collections.push(...idCollections);
375
- }
322
+ let answers = await inquirer.prompt(questionsDeployCollections[0])
323
+ let collections = answers.collections.map((collection) => JSONbig.parse(collection));
376
324
 
377
325
  for (let collection of collections) {
378
326
  log(`Deploying collection ${collection.name} ( ${collection['$id']} )`)
379
-
380
- let databaseId;
381
-
382
- try {
383
- const database = await databasesGet({
384
- databaseId: collection.databaseId,
385
- parseOutput: false,
386
- });
387
- databaseId = database.$id;
388
- } catch(err) {
389
- log(`Database ${collection.databaseId} not found. Creating it now...`);
390
- const database = await databasesCreate({
391
- databaseId: collection.databaseId,
392
- name: collection.databaseId,
393
- parseOutput: false,
394
- });
395
- databaseId = database.$id;
396
- }
397
-
398
327
  try {
399
- response = await databasesGetCollection({
400
- databaseId,
328
+ response = await databaseGetCollection({
401
329
  collectionId: collection['$id'],
402
330
  parseOutput: false,
403
331
  })
@@ -412,55 +340,51 @@ const deployCollection = async ({ all } = {}) => {
412
340
  log(`Updating attributes ... `);
413
341
 
414
342
  // TODO: Pagination?
415
- const { indexes: remoteIndexes } = await databasesListIndexes({
416
- databaseId,
343
+ const { indexes: remoteIndexes } = await databaseListIndexes({
417
344
  collectionId: collection['$id'],
418
345
  limit: 100,
419
346
  parseOutput: false
420
347
  });
421
348
 
422
349
  await Promise.all(remoteIndexes.map(async index => {
423
- await databasesDeleteIndex({
424
- databaseId,
350
+ await databaseDeleteIndex({
425
351
  collectionId: collection['$id'],
426
352
  key: index.key,
427
353
  parseOutput: false
428
354
  });
429
355
  }));
430
356
 
431
- const deleteIndexesPoolStatus = await awaitPools.wipeIndexes(databaseId, collection['$id']);
357
+ const deleteIndexesPoolStatus = await awaitPools.wipeIndexes(collection['$id']);
432
358
  if (!deleteIndexesPoolStatus) {
433
359
  throw new Error("Index deletion did not finish for too long.");
434
360
  }
435
361
 
436
362
  // TODO: Pagination?
437
- const { attributes: remoteAttributes } = await databasesListAttributes({
438
- databaseId,
363
+ const { attributes: remoteAttributes } = await databaseListAttributes({
439
364
  collectionId: collection['$id'],
440
365
  limit: 100,
441
366
  parseOutput: false
442
367
  });
443
368
 
444
369
  await Promise.all(remoteAttributes.map(async attribute => {
445
- await databasesDeleteAttribute({
446
- databaseId,
370
+ await databaseDeleteAttribute({
447
371
  collectionId: collection['$id'],
448
372
  key: attribute.key,
449
373
  parseOutput: false
450
374
  });
451
375
  }));
452
376
 
453
- const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(databaseId, collection['$id']);
377
+ const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(collection['$id']);
454
378
  if (!deleteAttributesPoolStatus) {
455
379
  throw new Error("Attribute deletion did not finish for too long.");
456
380
  }
457
381
 
458
382
  await Promise.all(collection.attributes.map(async attribute => {
459
- await createAttribute(databaseId, collection['$id'], attribute);
383
+ await createAttribute(collection['$id'], attribute);
460
384
  }));
461
385
 
462
386
  const attributeKeys = collection.attributes.map(attribute => attribute.key);
463
- const createPoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
387
+ const createPoolStatus = await awaitPools.expectAttributes(collection['$id'], attributeKeys);
464
388
  if (!createPoolStatus) {
465
389
  throw new Error("Attribute creation did not finish for too long.");
466
390
  }
@@ -469,8 +393,7 @@ const deployCollection = async ({ all } = {}) => {
469
393
 
470
394
  log(`Creating indexes ...`)
471
395
  await Promise.all(collection.indexes.map(async index => {
472
- await databasesCreateIndex({
473
- databaseId,
396
+ await databaseCreateIndex({
474
397
  collectionId: collection['$id'],
475
398
  key: index.key,
476
399
  type: index.type,
@@ -481,7 +404,7 @@ const deployCollection = async ({ all } = {}) => {
481
404
  }));
482
405
 
483
406
  const indexKeys = collection.indexes.map(attribute => attribute.key);
484
- const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
407
+ const indexPoolStatus = await awaitPools.expectIndexes(collection['$id'], indexKeys);
485
408
  if (!indexPoolStatus) {
486
409
  throw new Error("Index creation did not finish for too long.");
487
410
  }
@@ -490,8 +413,7 @@ const deployCollection = async ({ all } = {}) => {
490
413
  } catch (e) {
491
414
  if (e.code == 404) {
492
415
  log(`Collection ${collection.name} does not exist in the project. Creating ... `);
493
- response = await databasesCreateCollection({
494
- databaseId,
416
+ response = await databaseCreateCollection({
495
417
  collectionId: collection['$id'],
496
418
  name: collection.name,
497
419
  permission: collection.permission,
@@ -502,11 +424,11 @@ const deployCollection = async ({ all } = {}) => {
502
424
 
503
425
  log(`Creating attributes ... `);
504
426
  await Promise.all(collection.attributes.map(async attribute => {
505
- await createAttribute(databaseId, collection['$id'], attribute);
427
+ await createAttribute(collection['$id'], attribute);
506
428
  }));
507
429
 
508
430
  const attributeKeys = collection.attributes.map(attribute => attribute.key);
509
- const attributePoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
431
+ const attributePoolStatus = await awaitPools.expectAttributes(collection['$id'], attributeKeys);
510
432
  if (!attributePoolStatus) {
511
433
  throw new Error("Attribute creation did not finish for too long.");
512
434
  }
@@ -515,8 +437,7 @@ const deployCollection = async ({ all } = {}) => {
515
437
 
516
438
  log(`Creating indexes ...`);
517
439
  await Promise.all(collection.indexes.map(async index => {
518
- await databasesCreateIndex({
519
- databaseId,
440
+ await databaseCreateIndex({
520
441
  collectionId: collection['$id'],
521
442
  key: index.key,
522
443
  type: index.type,
@@ -527,7 +448,7 @@ const deployCollection = async ({ all } = {}) => {
527
448
  }));
528
449
 
529
450
  const indexKeys = collection.indexes.map(attribute => attribute.key);
530
- const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
451
+ const indexPoolStatus = await awaitPools.expectIndexes(collection['$id'], indexKeys);
531
452
  if (!indexPoolStatus) {
532
453
  throw new Error("Index creation did not finish for too long.");
533
454
  }
@@ -545,14 +466,11 @@ const deployCollection = async ({ all } = {}) => {
545
466
  deploy
546
467
  .command("function")
547
468
  .description("Deploy functions in the current directory.")
548
- .option(`--functionId <functionId>`, `Function ID`)
549
- .option(`--all`, `Flag to deploy all functions`)
550
469
  .action(actionRunner(deployFunction));
551
470
 
552
471
  deploy
553
472
  .command("collection")
554
473
  .description("Deploy collections in the current project.")
555
- .option(`--all`, `Flag to deploy all functions`)
556
474
  .action(actionRunner(deployCollection));
557
475
 
558
476
  module.exports = {
@@ -5,7 +5,7 @@ const { sdkForConsole } = require("../sdks");
5
5
  const { globalConfig, localConfig } = require("../config");
6
6
  const { actionRunner, success, parseBool, commandDescriptions, log, parse } = require("../parser");
7
7
  const { questionsLogin } = require("../questions");
8
- const { accountCreateEmailSession, accountDeleteSession } = require("./account");
8
+ const { accountCreateSession, accountDeleteSession } = require("./account");
9
9
 
10
10
  const login = new Command("login")
11
11
  .description(commandDescriptions['login'])
@@ -14,7 +14,7 @@ const login = new Command("login")
14
14
 
15
15
  let client = await sdkForConsole(false);
16
16
 
17
- await accountCreateEmailSession({
17
+ await accountCreateSession({
18
18
  email: answers.email,
19
19
  password: answers.password,
20
20
  parseOutput: false,
@@ -6,16 +6,22 @@ const inquirer = require("inquirer");
6
6
  const { teamsCreate } = require("./teams");
7
7
  const { projectsCreate } = require("./projects");
8
8
  const { functionsCreate } = require("./functions");
9
- const { databasesListCollections, databasesList } = require("./databases");
9
+ const { databaseListCollections } = require("./database");
10
10
  const { sdkForConsole } = require("../sdks");
11
11
  const { localConfig } = require("../config");
12
- const { questionsInitProject, questionsInitFunction, questionsInitCollection } = require("../questions");
12
+ const { questionsInitProject, questionsInitFunction } = require("../questions");
13
13
  const { success, log, actionRunner, commandDescriptions } = require("../parser");
14
14
 
15
15
  const init = new Command("init")
16
16
  .description(commandDescriptions['init'])
17
- .action(actionRunner(async (_options, command) => {
18
- command.help();
17
+ .option("--all", "Flag to initialize projects and collection")
18
+ .action(actionRunner(async ({ all }, command) => {
19
+ if (all == undefined) {
20
+ command.help()
21
+ }
22
+
23
+ await initProject();
24
+ await initCollection()
19
25
  }));
20
26
 
21
27
  const initProject = async () => {
@@ -34,7 +40,7 @@ const initProject = async () => {
34
40
 
35
41
  let teamId = response['$id'];
36
42
  response = await projectsCreate({
37
- projectId: answers.id,
43
+ projectId: 'unique()',
38
44
  name: answers.project,
39
45
  teamId,
40
46
  parseOutput: false
@@ -48,7 +54,6 @@ const initProject = async () => {
48
54
  }
49
55
 
50
56
  const initFunction = async () => {
51
- // TODO: Add CI/CD support (ID, name, runtime)
52
57
  let answers = await inquirer.prompt(questionsInitFunction)
53
58
 
54
59
  if (fs.existsSync(path.join(process.cwd(), 'functions', answers.name))) {
@@ -60,7 +65,7 @@ const initFunction = async () => {
60
65
  }
61
66
 
62
67
  let response = await functionsCreate({
63
- functionId: answers.id,
68
+ functionId: 'unique()',
64
69
  name: answers.name,
65
70
  runtime: answers.runtime.id,
66
71
  parseOutput: false
@@ -105,41 +110,20 @@ const initFunction = async () => {
105
110
  success();
106
111
  }
107
112
 
108
- const initCollection = async ({ all, databaseId } = {}) => {
109
- const databaseIds = [];
110
-
111
- if(databaseId) {
112
- databaseIds.push(databaseId);
113
- } else if(all) {
114
- let allDatabases = await databasesList({
115
- parseOutput: false
116
- })
117
-
118
- databaseIds.push(...allDatabases.databases.map((d) => d.$id));
119
- }
120
-
121
- if(databaseIds.length <= 0) {
122
- let answers = await inquirer.prompt(questionsInitCollection)
123
- if (!answers.databases) process.exit(1)
124
- databaseIds.push(...answers.databases);
125
- }
126
-
127
- for(const databaseId of databaseIds) {
128
- // TODO: Pagination?
129
- let response = await databasesListCollections({
130
- databaseId,
131
- limit: 100,
132
- parseOutput: false
133
- })
113
+ const initCollection = async () => {
114
+ // TODO: Pagination?
115
+ let response = await databaseListCollections({
116
+ limit: 100,
117
+ parseOutput: false
118
+ })
134
119
 
135
- let collections = response.collections;
136
- log(`Found ${collections.length} collections`);
120
+ let collections = response.collections;
121
+ log(`Found ${collections.length} collections`);
137
122
 
138
- collections.forEach(async collection => {
139
- log(`Fetching ${collection.name} ...`);
140
- localConfig.addCollection(collection);
141
- });
142
- }
123
+ collections.forEach(async collection => {
124
+ log(`Fetching ${collection.name} ...`);
125
+ localConfig.addCollection(collection);
126
+ });
143
127
 
144
128
  success();
145
129
  }
@@ -157,8 +141,6 @@ init
157
141
  init
158
142
  .command("collection")
159
143
  .description("Initialise your Appwrite collections")
160
- .option(`--databaseId <databaseId>`, `Database ID`)
161
- .option(`--all`, `Flag to initialize all databases`)
162
144
  .action(actionRunner(initCollection))
163
145
 
164
146
  module.exports = {
package/lib/parser.js CHANGED
@@ -150,7 +150,7 @@ const logo = "\n _ _ _ ___ __ _____
150
150
  const commandDescriptions = {
151
151
  "account": `The account command allows you to authenticate and manage a user account.`,
152
152
  "avatars": `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`,
153
- "databases": `The databases command allows you to create structured collections of documents, query and filter lists of documents.`,
153
+ "database": `The database command allows you to create structured collections of documents, query and filter lists of documents.`,
154
154
  "deploy": `The deploy command provides a convenient wrapper for deploying your functions and collections.`,
155
155
  "functions": `The functions command allows you view, create and manage your Cloud Functions.`,
156
156
  "health": `The health command allows you to both validate and monitor your Appwrite server's health.`,
package/lib/questions.js CHANGED
@@ -1,7 +1,6 @@
1
1
  const { localConfig } = require('./config');
2
2
  const { projectsList } = require('./commands/projects');
3
3
  const { functionsListRuntimes } = require('./commands/functions');
4
- const { databasesList } = require('./commands/databases');
5
4
  const JSONbig = require("json-bigint")({ storeAsString: false });
6
5
 
7
6
  const getIgnores = (runtime) => {
@@ -109,15 +108,6 @@ const questionsInitProject = [
109
108
  return answers.start == "new";
110
109
  },
111
110
  },
112
- {
113
- type: "input",
114
- name: "id",
115
- message: "What ID would you like to have for your project?",
116
- default: "myAwesomeProject",
117
- when(answers) {
118
- return answers.start == "new";
119
- },
120
- },
121
111
  {
122
112
  type: "list",
123
113
  name: "project",
@@ -156,12 +146,6 @@ const questionsInitFunction = [
156
146
  message: "What would you like to name your function?",
157
147
  default: "My Awesome Function"
158
148
  },
159
- {
160
- type: "input",
161
- name: "id",
162
- message: "What ID would you like to have for your function?",
163
- default: "myAwesomeFunction"
164
- },
165
149
  {
166
150
  type: "list",
167
151
  name: "runtime",
@@ -182,31 +166,6 @@ const questionsInitFunction = [
182
166
  }
183
167
  ];
184
168
 
185
- const questionsInitCollection = [
186
- {
187
- type: "checkbox",
188
- name: "databases",
189
- message: "From which database would you like to init collections?",
190
- choices: async () => {
191
- let response = await databasesList({
192
- parseOutput: false
193
- })
194
- let databases = response["databases"]
195
-
196
- if(databases.length <= 0) {
197
- throw new Error("No databases found. Please create one in project console.")
198
- }
199
- let choices = databases.map((database, idx) => {
200
- return {
201
- name: `${database.name} (${database.$id})`,
202
- value: database.$id
203
- }
204
- })
205
- return choices;
206
- }
207
- }
208
- ];
209
-
210
169
  const questionsLogin = [
211
170
  {
212
171
  type: "input",
@@ -245,8 +204,8 @@ const questionsDeployFunctions = [
245
204
  }
246
205
  let choices = functions.map((func, idx) => {
247
206
  return {
248
- name: `${func.name} (${func.$id})`,
249
- value: func.$id
207
+ name: `${func.name} (${func['$id']})`,
208
+ value: JSONbig.stringify(func)
250
209
  }
251
210
  })
252
211
  return choices;
@@ -267,7 +226,7 @@ const questionsDeployCollections = [
267
226
  let choices = collections.map((collection, idx) => {
268
227
  return {
269
228
  name: `${collection.name} (${collection['$id']})`,
270
- value: collection.$id
229
+ value: JSONbig.stringify(collection)
271
230
  }
272
231
  })
273
232
  return choices;
@@ -299,7 +258,6 @@ module.exports = {
299
258
  questionsInitProject,
300
259
  questionsLogin,
301
260
  questionsInitFunction,
302
- questionsInitCollection,
303
261
  questionsDeployFunctions,
304
262
  questionsDeployCollections,
305
263
  questionsGetEntrypoint
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "appwrite-cli",
3
3
  "homepage": "https://appwrite.io/support",
4
4
  "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
5
- "version": "0.18.1",
5
+ "version": "0.18.2",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "index.js",
8
8
  "bin": {