appwrite-cli 1.1.1 → 2.0.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.
Files changed (60) hide show
  1. package/Formula/appwrite.rb +1 -1
  2. package/LICENSE.md +2 -2
  3. package/README.md +4 -4
  4. package/docs/examples/account/create-phone-session.md +1 -1
  5. package/docs/examples/account/create.md +1 -1
  6. package/docs/examples/account/update-password.md +1 -1
  7. package/docs/examples/account/update-phone.md +1 -1
  8. package/docs/examples/console/variables.md +1 -0
  9. package/docs/examples/databases/create-relationship-attribute.md +9 -0
  10. package/docs/examples/databases/get-document.md +2 -1
  11. package/docs/examples/databases/update-boolean-attribute.md +6 -0
  12. package/docs/examples/databases/update-datetime-attribute.md +6 -0
  13. package/docs/examples/databases/update-email-attribute.md +6 -0
  14. package/docs/examples/databases/update-enum-attribute.md +7 -0
  15. package/docs/examples/databases/update-float-attribute.md +8 -0
  16. package/docs/examples/databases/update-integer-attribute.md +8 -0
  17. package/docs/examples/databases/update-ip-attribute.md +6 -0
  18. package/docs/examples/databases/update-relationship-attribute.md +5 -0
  19. package/docs/examples/databases/update-string-attribute.md +6 -0
  20. package/docs/examples/databases/update-url-attribute.md +6 -0
  21. package/docs/examples/functions/{retry-build.md → create-build.md} +1 -1
  22. package/docs/examples/functions/create.md +1 -1
  23. package/docs/examples/functions/update.md +1 -1
  24. package/docs/examples/graphql/mutation.md +2 -0
  25. package/docs/examples/graphql/query.md +2 -0
  26. package/docs/examples/projects/create.md +1 -0
  27. package/docs/examples/projects/update-auth-duration.md +3 -0
  28. package/docs/examples/projects/update-auth-password-dictionary.md +3 -0
  29. package/docs/examples/projects/update-auth-password-history.md +3 -0
  30. package/docs/examples/projects/update-auth-sessions-limit.md +3 -0
  31. package/docs/examples/projects/update-o-auth2.md +1 -0
  32. package/docs/examples/teams/create-membership.md +3 -1
  33. package/docs/examples/teams/get-prefs.md +2 -0
  34. package/docs/examples/teams/{update.md → update-name.md} +1 -1
  35. package/docs/examples/teams/update-prefs.md +3 -0
  36. package/docs/examples/users/update-password.md +1 -1
  37. package/docs/examples/users/update-phone.md +1 -1
  38. package/index.js +16 -1
  39. package/install.ps1 +2 -2
  40. package/install.sh +1 -1
  41. package/lib/client.js +7 -7
  42. package/lib/commands/account.js +46 -11
  43. package/lib/commands/avatars.js +3 -1
  44. package/lib/commands/console.js +44 -0
  45. package/lib/commands/databases.js +735 -109
  46. package/lib/commands/deploy.js +350 -141
  47. package/lib/commands/functions.js +44 -16
  48. package/lib/commands/generic.js +15 -3
  49. package/lib/commands/graphql.js +85 -0
  50. package/lib/commands/health.js +3 -1
  51. package/lib/commands/init.js +224 -162
  52. package/lib/commands/locale.js +3 -1
  53. package/lib/commands/projects.js +223 -9
  54. package/lib/commands/storage.js +43 -13
  55. package/lib/commands/teams.js +107 -19
  56. package/lib/commands/users.js +62 -11
  57. package/lib/config.js +122 -5
  58. package/lib/parser.js +7 -2
  59. package/lib/questions.js +311 -257
  60. package/package.json +1 -1
@@ -2,12 +2,13 @@ const inquirer = require("inquirer");
2
2
  const JSONbig = require("json-bigint")({ storeAsString: false });
3
3
  const { Command } = require("commander");
4
4
  const { localConfig } = require("../config");
5
- const { questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollections, questionsConfirmDeployCollections } = require("../questions");
5
+ const { questionsDeployBuckets, questionsDeployTeams, questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollections, questionsConfirmDeployCollections } = require("../questions");
6
6
  const { actionRunner, success, log, error, commandDescriptions } = require("../parser");
7
7
  const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsUpdateDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } = require('./functions');
8
8
  const {
9
9
  databasesGet,
10
10
  databasesCreate,
11
+ databasesUpdate,
11
12
  databasesCreateBooleanAttribute,
12
13
  databasesGetCollection,
13
14
  databasesCreateCollection,
@@ -20,11 +21,21 @@ const {
20
21
  databasesCreateUrlAttribute,
21
22
  databasesCreateIpAttribute,
22
23
  databasesCreateEnumAttribute,
24
+ databasesCreateRelationshipAttribute,
23
25
  databasesDeleteAttribute,
24
26
  databasesListAttributes,
25
27
  databasesListIndexes,
26
- databasesDeleteIndex
28
+ databasesDeleteIndex,
29
+ databasesUpdateCollection
27
30
  } = require("./databases");
31
+ const {
32
+ storageGetBucket, storageUpdateBucket, storageCreateBucket
33
+ } = require("./storage");
34
+ const {
35
+ teamsGet,
36
+ teamsUpdate,
37
+ teamsCreate
38
+ } = require("./teams");
28
39
 
29
40
  const POOL_DEBOUNCE = 2000; // in milliseconds
30
41
  const POOL_MAX_DEBOUNCES = 30;
@@ -39,7 +50,7 @@ const awaitPools = {
39
50
  const { attributes: remoteAttributes } = await databasesListAttributes({
40
51
  databaseId,
41
52
  collectionId,
42
- queries: [ 'limit(100)' ],
53
+ queries: ['limit(100)'],
43
54
  parseOutput: false
44
55
  });
45
56
 
@@ -59,7 +70,7 @@ const awaitPools = {
59
70
  const { indexes: remoteIndexes } = await databasesListIndexes({
60
71
  databaseId,
61
72
  collectionId,
62
- queries: [ 'limit(100)' ],
73
+ queries: ['limit(100)'],
63
74
  parseOutput: false
64
75
  });
65
76
 
@@ -79,7 +90,7 @@ const awaitPools = {
79
90
  const { attributes: remoteAttributes } = await databasesListAttributes({
80
91
  databaseId,
81
92
  collectionId,
82
- queries: [ 'limit(100)' ],
93
+ queries: ['limit(100)'],
83
94
  parseOutput: false
84
95
  });
85
96
 
@@ -111,7 +122,7 @@ const awaitPools = {
111
122
  const { indexes: remoteIndexes } = await databasesListIndexes({
112
123
  databaseId,
113
124
  collectionId,
114
- queries: [ 'limit(100)' ],
125
+ queries: ['limit(100)'],
115
126
  parseOutput: false
116
127
  });
117
128
 
@@ -138,6 +149,9 @@ const awaitPools = {
138
149
 
139
150
  const deploy = new Command("deploy")
140
151
  .description(commandDescriptions['deploy'])
152
+ .configureHelp({
153
+ helpWidth: process.stdout.columns || 80
154
+ })
141
155
  .action(actionRunner(async (_options, command) => {
142
156
  command.help()
143
157
  }));
@@ -147,9 +161,9 @@ const deployFunction = async ({ functionId, all, yes } = {}) => {
147
161
 
148
162
  const functionIds = [];
149
163
 
150
- if(functionId) {
164
+ if (functionId) {
151
165
  functionIds.push(functionId);
152
- } else if(all) {
166
+ } else if (all) {
153
167
  const functions = localConfig.getFunctions();
154
168
  if (functions.length === 0) {
155
169
  throw new Error("No functions found in the current directory.");
@@ -159,22 +173,22 @@ const deployFunction = async ({ functionId, all, yes } = {}) => {
159
173
  }));
160
174
  }
161
175
 
162
- if(functionIds.length <= 0) {
176
+ if (functionIds.length <= 0) {
163
177
  const answers = await inquirer.prompt(questionsDeployFunctions[0]);
164
178
  functionIds.push(...answers.functions);
165
179
  }
166
180
 
167
181
  let functions = functionIds.map((id) => {
168
- const functions = localConfig.getFunctions();
169
- const func = functions.find((f) => f.$id === id);
182
+ const functions = localConfig.getFunctions();
183
+ const func = functions.find((f) => f.$id === id);
170
184
 
171
- if(!func) {
172
- throw new Error("Function '" + id + "' not found.")
173
- }
185
+ if (!func) {
186
+ throw new Error("Function '" + id + "' not found.")
187
+ }
174
188
 
175
- return func;
189
+ return func;
176
190
  });
177
-
191
+
178
192
  for (let func of functions) {
179
193
  log(`Deploying function ${func.name} ( ${func['$id']} )`)
180
194
 
@@ -184,50 +198,10 @@ const deployFunction = async ({ functionId, all, yes } = {}) => {
184
198
  parseOutput: false,
185
199
  });
186
200
 
187
- if(response.runtime !== func.runtime) {
201
+ if (response.runtime !== func.runtime) {
188
202
  throw new Error(`Runtime missmatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.json`);
189
203
  }
190
204
 
191
- if(func.variables) {
192
- // Delete existing variables
193
-
194
- // TODO: Pagination?
195
- const { variables: remoteVariables } = await functionsListVariables({
196
- functionId: func['$id'],
197
- queries: [ 'limit(100)' ],
198
- parseOutput: false
199
- });
200
-
201
- if(remoteVariables.length > 0) {
202
- if(!yes) {
203
- const variableAnswers = await inquirer.prompt(questionsDeployFunctions[1])
204
-
205
- if (variableAnswers.override !== "YES") {
206
- log(`Received "${variableAnswers.override}". Skipping ${func.name} ( ${func['$id']} )`);
207
- continue;
208
- }
209
- }
210
-
211
- await Promise.all(remoteVariables.map(async remoteVariable => {
212
- await functionsDeleteVariable({
213
- functionId: func['$id'],
214
- variableId: remoteVariable['$id'],
215
- parseOutput: false
216
- });
217
- }));
218
- }
219
-
220
- // Deploy local variables
221
- await Promise.all(Object.keys(func.variables).map(async localVariableKey => {
222
- await functionsCreateVariable({
223
- functionId: func['$id'],
224
- key: localVariableKey,
225
- value: func.variables[localVariableKey],
226
- parseOutput: false
227
- });
228
- }));
229
- }
230
-
231
205
  response = await functionsUpdate({
232
206
  functionId: func['$id'],
233
207
  name: func.name,
@@ -264,6 +238,49 @@ const deployFunction = async ({ functionId, all, yes } = {}) => {
264
238
  }
265
239
  }
266
240
 
241
+ if (func.variables) {
242
+ // Delete existing variables
243
+
244
+ // TODO: Pagination?
245
+ const { variables: remoteVariables } = await functionsListVariables({
246
+ functionId: func['$id'],
247
+ queries: ['limit(100)'],
248
+ parseOutput: false
249
+ });
250
+
251
+ let deployVariables = yes;
252
+ if (remoteVariables.length == 0) {
253
+ deployVariables = true;
254
+ } else if (remoteVariables.length > 0 && !yes) {
255
+ const variableAnswers = await inquirer.prompt(questionsDeployFunctions[1])
256
+ deployVariables = variableAnswers.override === "YES";
257
+ }
258
+
259
+ if (!deployVariables) {
260
+ log(`Skipping variables for ${func.name} ( ${func['$id']} )`);
261
+ } else {
262
+ log(`Deploying variables for ${func.name} ( ${func['$id']} )`);
263
+
264
+ await Promise.all(remoteVariables.map(async remoteVariable => {
265
+ await functionsDeleteVariable({
266
+ functionId: func['$id'],
267
+ variableId: remoteVariable['$id'],
268
+ parseOutput: false
269
+ });
270
+ }));
271
+
272
+ // Deploy local variables
273
+ await Promise.all(Object.keys(func.variables).map(async localVariableKey => {
274
+ await functionsCreateVariable({
275
+ functionId: func['$id'],
276
+ key: localVariableKey,
277
+ value: func.variables[localVariableKey],
278
+ parseOutput: false
279
+ });
280
+ }));
281
+ }
282
+ }
283
+
267
284
  // Create tag
268
285
  if (!func.entrypoint) {
269
286
  answers = await inquirer.prompt(questionsGetEntrypoint)
@@ -292,6 +309,8 @@ const deployFunction = async ({ functionId, all, yes } = {}) => {
292
309
  }
293
310
  }
294
311
  }
312
+
313
+ success(`Deployed ${functions.length} functions`);
295
314
  }
296
315
 
297
316
  const createAttribute = async (databaseId, collectionId, attribute) => {
@@ -396,50 +415,69 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
396
415
  array: attribute.array,
397
416
  parseOutput: false
398
417
  })
418
+ case 'relationship':
419
+ return databasesCreateRelationshipAttribute({
420
+ databaseId,
421
+ collectionId,
422
+ relatedCollectionId: attribute.relatedCollection,
423
+ type: attribute.relationType,
424
+ twoWay: attribute.twoWay,
425
+ key: attribute.key,
426
+ twoWayKey: attribute.twoWayKey,
427
+ onDelete: attribute.onDelete,
428
+ parseOutput: false
429
+ })
399
430
  }
400
431
  }
401
432
 
402
433
  const deployCollection = async ({ all, yes } = {}) => {
403
434
  let response = {};
404
435
 
405
- let collectionIds = [];
406
- const configCollections = localConfig.getCollections();
436
+ const collections = [];
407
437
 
408
- if(all) {
409
- if (configCollections.length === 0) {
438
+ if (all) {
439
+ if (localConfig.getCollections().length === 0) {
410
440
  throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
411
441
  }
412
- collectionIds.push(...configCollections.map((c) => c.$id));
413
- }
414
-
415
- if(collectionIds.length <= 0) {
416
- let answers = await inquirer.prompt(questionsDeployCollections[0])
417
- collectionIds.push(...answers.collections);
418
- }
419
-
420
- let collections = [];
421
-
422
- for(const collectionId of collectionIds) {
423
- const idCollections = configCollections.filter((c) => c.$id === collectionId);
424
- collections.push(...idCollections);
442
+ collections.push(...localConfig.getCollections());
443
+ } else {
444
+ const answers = await inquirer.prompt(questionsDeployCollections[0])
445
+ const configCollections = new Map();
446
+ localConfig.getCollections().forEach((c) => {
447
+ configCollections.set(`${c['databaseId']}|${c['$id']}`, c);
448
+ });
449
+ answers.collections.forEach((a) => {
450
+ const collection = configCollections.get(a);
451
+ collections.push(collection);
452
+ })
425
453
  }
426
454
 
427
455
  for (let collection of collections) {
428
- log(`Deploying collection ${collection.name} ( ${collection['$id']} )`)
456
+ log(`Deploying collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} )`)
429
457
 
430
458
  let databaseId;
431
459
 
460
+ const localDatabase = localConfig.getDatabase(collection.databaseId);
461
+
432
462
  try {
433
463
  const database = await databasesGet({
434
464
  databaseId: collection.databaseId,
435
465
  parseOutput: false,
436
466
  });
437
467
  databaseId = database.$id;
438
- } catch(err) {
468
+
469
+ await databasesUpdate({
470
+ databaseId: collection.databaseId,
471
+ name: localDatabase.name ?? collection.databaseId,
472
+ parseOutput: false
473
+ })
474
+
475
+ success(`Updated ${localDatabase.name} ( ${collection.databaseId} )`);
476
+ } catch (err) {
439
477
  log(`Database ${collection.databaseId} not found. Creating it now...`);
440
478
  const database = await databasesCreate({
441
479
  databaseId: collection.databaseId,
442
- name: collection.databaseId,
480
+ name: localDatabase.name ?? collection.databaseId,
443
481
  parseOutput: false,
444
482
  });
445
483
  databaseId = database.$id;
@@ -453,7 +491,7 @@ const deployCollection = async ({ all, yes } = {}) => {
453
491
  })
454
492
  log(`Collection ${collection.name} ( ${collection['$id']} ) already exists.`);
455
493
 
456
- if(!yes) {
494
+ if (!yes) {
457
495
  answers = await inquirer.prompt(questionsDeployCollections[1])
458
496
  if (answers.override !== "YES") {
459
497
  log(`Received "${answers.override}". Skipping ${collection.name} ( ${collection['$id']} )`);
@@ -461,13 +499,13 @@ const deployCollection = async ({ all, yes } = {}) => {
461
499
  }
462
500
  }
463
501
 
464
- log(`Updating attributes ... `);
502
+ log(`Deleting indexes and attributes ... `);
465
503
 
466
504
  // TODO: Pagination?
467
505
  const { indexes: remoteIndexes } = await databasesListIndexes({
468
506
  databaseId,
469
507
  collectionId: collection['$id'],
470
- queries: [ 'limit(100)' ],
508
+ queries: ['limit(100)'],
471
509
  parseOutput: false
472
510
  });
473
511
 
@@ -489,10 +527,10 @@ const deployCollection = async ({ all, yes } = {}) => {
489
527
  const { attributes: remoteAttributes } = await databasesListAttributes({
490
528
  databaseId,
491
529
  collectionId: collection['$id'],
492
- queries: [ 'limit(100)' ],
530
+ queries: ['limit(100)'],
493
531
  parseOutput: false
494
532
  });
495
-
533
+
496
534
  await Promise.all(remoteAttributes.map(async attribute => {
497
535
  await databasesDeleteAttribute({
498
536
  databaseId,
@@ -507,38 +545,15 @@ const deployCollection = async ({ all, yes } = {}) => {
507
545
  throw new Error("Attribute deletion did not finish for too long.");
508
546
  }
509
547
 
510
- await Promise.all(collection.attributes.map(async attribute => {
511
- await createAttribute(databaseId, collection['$id'], attribute);
512
- }));
513
-
514
- const attributeKeys = collection.attributes.map(attribute => attribute.key);
515
- const createPoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
516
- if (!createPoolStatus) {
517
- throw new Error("Attribute creation did not finish for too long.");
518
- }
519
-
520
- success(`Created ${collection.attributes.length} attributes`);
521
-
522
- log(`Creating indexes ...`)
523
- await Promise.all(collection.indexes.map(async index => {
524
- await databasesCreateIndex({
525
- databaseId,
526
- collectionId: collection['$id'],
527
- key: index.key,
528
- type: index.type,
529
- attributes: index.attributes,
530
- orders: index.orders,
531
- parseOutput: false
532
- });
533
- }));
534
-
535
- const indexKeys = collection.indexes.map(attribute => attribute.key);
536
- const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
537
- if (!indexPoolStatus) {
538
- throw new Error("Index creation did not finish for too long.");
539
- }
540
-
541
- success(`Created ${collection.indexes.length} indexes`);
548
+ await databasesUpdateCollection({
549
+ databaseId,
550
+ collectionId: collection['$id'],
551
+ name: collection.name,
552
+ documentSecurity: collection.documentSecurity,
553
+ permissions: collection['$permissions'],
554
+ enabled: collection.enabled,
555
+ parseOutput: false
556
+ })
542
557
  } catch (e) {
543
558
  if (e.code == 404) {
544
559
  log(`Collection ${collection.name} does not exist in the project. Creating ... `);
@@ -551,41 +566,221 @@ const deployCollection = async ({ all, yes } = {}) => {
551
566
  parseOutput: false
552
567
  })
553
568
 
554
- log(`Creating attributes ... `);
555
- await Promise.all(collection.attributes.map(async attribute => {
556
- await createAttribute(databaseId, collection['$id'], attribute);
557
- }));
569
+ } else {
570
+ throw e;
571
+ }
572
+ }
573
+
574
+ // Create all non-relationship attributes first
575
+ const nonRelationshipAttributes = collection.attributes.filter(attribute => attribute.type !== 'relationship');
576
+ await Promise.all(nonRelationshipAttributes.map(attribute => {
577
+ return createAttribute(databaseId, collection['$id'], attribute);
578
+ }));
579
+
580
+ const nonRelationshipAttributeKeys = nonRelationshipAttributes.map(attribute => attribute.key);
581
+ const createPoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], nonRelationshipAttributeKeys);
582
+ if (!createPoolStatus) {
583
+ throw new Error("Attribute creation did not finish for too long.");
584
+ }
585
+
586
+ success(`Created ${nonRelationshipAttributeKeys.length} non-relationship attributes`);
587
+
588
+ log(`Creating indexes ...`)
589
+ await Promise.all(collection.indexes.map(async index => {
590
+ await databasesCreateIndex({
591
+ databaseId,
592
+ collectionId: collection['$id'],
593
+ key: index.key,
594
+ type: index.type,
595
+ attributes: index.attributes,
596
+ orders: index.orders,
597
+ parseOutput: false
598
+ });
599
+ }));
600
+
601
+ const indexKeys = collection.indexes.map(attribute => attribute.key);
602
+ const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
603
+ if (!indexPoolStatus) {
604
+ throw new Error("Index creation did not finish for too long.");
605
+ }
606
+
607
+ success(`Created ${collection.indexes.length} indexes`);
608
+
609
+ success(`Deployed ${collection.name} ( ${collection['$id']} )`);
610
+ }
611
+
612
+ // Create the relationship attributes
613
+ for (let collection of collections) {
614
+ const relationshipAttributes = collection.attributes.filter(attribute => attribute.type === 'relationship' && attribute.side === 'parent');
615
+
616
+ if (relationshipAttributes.length === 0) continue;
617
+
618
+ log(`Deploying relationships for collection ${collection.name} ( ${collection['$id']} )`);
619
+
620
+ await Promise.all(relationshipAttributes.map(attribute => {
621
+ return createAttribute(collection['databaseId'], collection['$id'], attribute);
622
+ }));
623
+
624
+ const nonRelationshipAttributeKeys = relationshipAttributes.map(attribute => attribute.key);
625
+ const createPoolStatus = await awaitPools.expectAttributes(collection['databaseId'], collection['$id'], nonRelationshipAttributeKeys);
626
+ if (!createPoolStatus) {
627
+ throw new Error("Attribute creation did not finish for too long.");
628
+ }
629
+
630
+ success(`Created ${nonRelationshipAttributeKeys.length} relationship attributes`);
631
+ }
632
+ }
558
633
 
559
- const attributeKeys = collection.attributes.map(attribute => attribute.key);
560
- const attributePoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
561
- if (!attributePoolStatus) {
562
- throw new Error("Attribute creation did not finish for too long.");
634
+ const deployBucket = async ({ all, yes } = {}) => {
635
+ let response = {};
636
+
637
+ let bucketIds = [];
638
+ const configBuckets = localConfig.getBuckets();
639
+
640
+ if (all) {
641
+ if (configBuckets.length === 0) {
642
+ throw new Error("No buckets found in the current directory. Run `appwrite init bucket` to fetch all your buckets.");
643
+ }
644
+ bucketIds.push(...configBuckets.map((b) => b.$id));
645
+ }
646
+
647
+ if (bucketIds.length === 0) {
648
+ let answers = await inquirer.prompt(questionsDeployBuckets[0])
649
+ bucketIds.push(...answers.buckets);
650
+ }
651
+
652
+ let buckets = [];
653
+
654
+ for (const bucketId of bucketIds) {
655
+ const idBuckets = configBuckets.filter((b) => b.$id === bucketId);
656
+ buckets.push(...idBuckets);
657
+ }
658
+
659
+ for (let bucket of buckets) {
660
+ log(`Deploying bucket ${bucket.name} ( ${bucket['$id']} )`)
661
+
662
+ try {
663
+ response = await storageGetBucket({
664
+ bucketId: bucket['$id'],
665
+ parseOutput: false,
666
+ })
667
+ log(`Bucket ${bucket.name} ( ${bucket['$id']} ) already exists.`);
668
+
669
+ if (!yes) {
670
+ answers = await inquirer.prompt(questionsDeployBuckets[1])
671
+ if (answers.override !== "YES") {
672
+ log(`Received "${answers.override}". Skipping ${bucket.name} ( ${bucket['$id']} )`);
673
+ continue;
563
674
  }
675
+ }
564
676
 
565
- success(`Created ${collection.attributes.length} attributes`);
677
+ log(`Updating bucket ...`)
678
+
679
+ await storageUpdateBucket({
680
+ bucketId: bucket['$id'],
681
+ name: bucket.name,
682
+ permissions: bucket['$permissions'],
683
+ fileSecurity: bucket.fileSecurity,
684
+ enabled: bucket.enabled,
685
+ maximumFileSize: bucket.maximumFileSize,
686
+ allowedFileExtensions: bucket.allowedFileExtensions,
687
+ compression: bucket.compression,
688
+ encryption: bucket.encryption,
689
+ antivirus: bucket.antivirus,
690
+ compression: bucket.compression,
691
+ parseOutput: false
692
+ });
566
693
 
567
- log(`Creating indexes ...`);
568
- await Promise.all(collection.indexes.map(async index => {
569
- await databasesCreateIndex({
570
- databaseId,
571
- collectionId: collection['$id'],
572
- key: index.key,
573
- type: index.type,
574
- attributes: index.attributes,
575
- orders: index.orders,
576
- parseOutput: false
577
- });
578
- }));
694
+ success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
695
+ } catch (e) {
696
+ if (e.code == 404) {
697
+ log(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
698
+
699
+ response = await storageCreateBucket({
700
+ bucketId: bucket['$id'],
701
+ name: bucket.name,
702
+ permissions: bucket['$permissions'],
703
+ fileSecurity: bucket.fileSecurity,
704
+ enabled: bucket.enabled,
705
+ maximumFileSize: bucket.maximumFileSize,
706
+ allowedFileExtensions: bucket.allowedFileExtensions,
707
+ compression: bucket.compression,
708
+ encryption: bucket.encryption,
709
+ antivirus: bucket.antivirus,
710
+ parseOutput: false
711
+ })
712
+
713
+ success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
714
+ } else {
715
+ throw e;
716
+ }
717
+ }
718
+ }
719
+ }
720
+
721
+ const deployTeam = async ({ all, yes } = {}) => {
722
+ let response = {};
723
+
724
+ let teamIds = [];
725
+ const configTeams = localConfig.getTeams();
726
+
727
+ if (all) {
728
+ if (configTeams.length === 0) {
729
+ throw new Error("No teams found in the current directory. Run `appwrite init team` to fetch all your teams.");
730
+ }
731
+ teamIds.push(...configTeams.map((t) => t.$id));
732
+ }
733
+
734
+ if (teamIds.length === 0) {
735
+ let answers = await inquirer.prompt(questionsDeployTeams[0])
736
+ teamIds.push(...answers.teams);
737
+ }
738
+
739
+ let teams = [];
740
+
741
+ for (const teamId of teamIds) {
742
+ const idTeams = configTeams.filter((t) => t.$id === teamId);
743
+ teams.push(...idTeams);
744
+ }
579
745
 
580
- const indexKeys = collection.indexes.map(attribute => attribute.key);
581
- const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
582
- if (!indexPoolStatus) {
583
- throw new Error("Index creation did not finish for too long.");
746
+ for (let team of teams) {
747
+ log(`Deploying team ${team.name} ( ${team['$id']} )`)
748
+
749
+ try {
750
+ response = await teamsGet({
751
+ teamId: team['$id'],
752
+ parseOutput: false,
753
+ })
754
+ log(`Team ${team.name} ( ${team['$id']} ) already exists.`);
755
+
756
+ if (!yes) {
757
+ answers = await inquirer.prompt(questionsDeployTeams[1])
758
+ if (answers.override !== "YES") {
759
+ log(`Received "${answers.override}". Skipping ${team.name} ( ${team['$id']} )`);
760
+ continue;
584
761
  }
762
+ }
763
+
764
+ log(`Updating team ...`)
585
765
 
586
- success(`Created ${collection.indexes.length} indexes`);
766
+ await teamsUpdate({
767
+ teamId: team['$id'],
768
+ name: team.name,
769
+ parseOutput: false
770
+ });
587
771
 
588
- success(`Deployed ${collection.name} ( ${collection['$id']} )`);
772
+ success(`Deployed ${team.name} ( ${team['$id']} )`);
773
+ } catch (e) {
774
+ if (e.code == 404) {
775
+ log(`Team ${team.name} does not exist in the project. Creating ... `);
776
+
777
+ response = await teamsCreate({
778
+ teamId: team['$id'],
779
+ name: team.name,
780
+ parseOutput: false
781
+ })
782
+
783
+ success(`Deployed ${team.name} ( ${team['$id']} )`);
589
784
  } else {
590
785
  throw e;
591
786
  }
@@ -608,6 +803,20 @@ deploy
608
803
  .option(`--yes`, `Flag to confirm all warnings`)
609
804
  .action(actionRunner(deployCollection));
610
805
 
806
+ deploy
807
+ .command("bucket")
808
+ .description("Deploy buckets in the current project.")
809
+ .option(`--all`, `Flag to deploy all buckets`)
810
+ .option(`--yes`, `Flag to confirm all warnings`)
811
+ .action(actionRunner(deployBucket));
812
+
813
+ deploy
814
+ .command("team")
815
+ .description("Deploy teams in the current project.")
816
+ .option(`--all`, `Flag to deploy all teams`)
817
+ .option(`--yes`, `Flag to confirm all warnings`)
818
+ .action(actionRunner(deployTeam));
819
+
611
820
  module.exports = {
612
821
  deploy
613
822
  }