appwrite-cli 5.0.3 → 6.0.0-rc.1

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 (54) hide show
  1. package/README.md +4 -4
  2. package/docs/examples/functions/create-build.md +1 -1
  3. package/docs/examples/functions/create-execution.md +1 -0
  4. package/docs/examples/functions/create.md +1 -0
  5. package/docs/examples/functions/delete-execution.md +3 -0
  6. package/docs/examples/functions/update-deployment-build.md +3 -0
  7. package/docs/examples/functions/update.md +1 -0
  8. package/docs/examples/messaging/update-email.md +1 -0
  9. package/docs/examples/projects/create-j-w-t.md +4 -0
  10. package/docs/examples/projects/update-mock-numbers.md +3 -0
  11. package/docs/examples/projects/update-session-alerts.md +3 -0
  12. package/docs/examples/users/create-j-w-t.md +4 -0
  13. package/docs/examples/vcs/get-repository-contents.md +4 -0
  14. package/index.js +34 -7
  15. package/install.ps1 +3 -3
  16. package/install.sh +2 -2
  17. package/lib/client.js +19 -5
  18. package/lib/commands/account.js +307 -153
  19. package/lib/commands/assistant.js +8 -5
  20. package/lib/commands/avatars.js +116 -60
  21. package/lib/commands/console.js +8 -5
  22. package/lib/commands/databases.js +353 -164
  23. package/lib/commands/functions.js +310 -100
  24. package/lib/commands/generic.js +206 -54
  25. package/lib/commands/graphql.js +14 -8
  26. package/lib/commands/health.js +140 -71
  27. package/lib/commands/init.js +250 -155
  28. package/lib/commands/locale.js +50 -26
  29. package/lib/commands/messaging.js +363 -179
  30. package/lib/commands/migrations.js +98 -50
  31. package/lib/commands/project.js +38 -20
  32. package/lib/commands/projects.js +449 -144
  33. package/lib/commands/proxy.js +32 -17
  34. package/lib/commands/pull.js +231 -0
  35. package/lib/commands/push.js +1518 -0
  36. package/lib/commands/run.js +282 -0
  37. package/lib/commands/storage.js +160 -76
  38. package/lib/commands/teams.js +102 -50
  39. package/lib/commands/users.js +325 -135
  40. package/lib/commands/vcs.js +102 -29
  41. package/lib/config.js +190 -18
  42. package/lib/emulation/docker.js +187 -0
  43. package/lib/emulation/utils.js +177 -0
  44. package/lib/id.js +30 -0
  45. package/lib/paginate.js +1 -2
  46. package/lib/parser.js +69 -12
  47. package/lib/questions.js +462 -84
  48. package/lib/sdks.js +1 -1
  49. package/lib/spinner.js +103 -0
  50. package/lib/utils.js +248 -3
  51. package/lib/validations.js +17 -0
  52. package/package.json +6 -2
  53. package/scoop/appwrite.json +3 -3
  54. package/lib/commands/deploy.js +0 -941
@@ -1,941 +0,0 @@
1
- const inquirer = require("inquirer");
2
- const JSONbig = require("json-bigint")({ storeAsString: false });
3
- const { Command } = require("commander");
4
- const { localConfig } = require("../config");
5
- const { paginate } = require('../paginate');
6
- const { questionsDeployBuckets, questionsDeployTeams, questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollections, questionsConfirmDeployCollections } = require("../questions");
7
- const { actionRunner, success, log, error, commandDescriptions } = require("../parser");
8
- const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsUpdateDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } = require('./functions');
9
- const {
10
- databasesGet,
11
- databasesCreate,
12
- databasesUpdate,
13
- databasesCreateBooleanAttribute,
14
- databasesGetCollection,
15
- databasesCreateCollection,
16
- databasesCreateStringAttribute,
17
- databasesCreateIntegerAttribute,
18
- databasesCreateFloatAttribute,
19
- databasesCreateEmailAttribute,
20
- databasesCreateDatetimeAttribute,
21
- databasesCreateIndex,
22
- databasesCreateUrlAttribute,
23
- databasesCreateIpAttribute,
24
- databasesCreateEnumAttribute,
25
- databasesCreateRelationshipAttribute,
26
- databasesDeleteAttribute,
27
- databasesListAttributes,
28
- databasesListIndexes,
29
- databasesDeleteIndex,
30
- databasesUpdateCollection
31
- } = require("./databases");
32
- const {
33
- storageGetBucket, storageUpdateBucket, storageCreateBucket
34
- } = require("./storage");
35
- const {
36
- teamsGet,
37
- teamsUpdate,
38
- teamsCreate
39
- } = require("./teams");
40
-
41
- const STEP_SIZE = 100; // Resources
42
- const POOL_DEBOUNCE = 2000; // Milliseconds
43
-
44
- let poolMaxDebounces = 30;
45
-
46
- const awaitPools = {
47
- wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
48
- if (iteration > poolMaxDebounces) {
49
- return false;
50
- }
51
-
52
- const { total } = await databasesListAttributes({
53
- databaseId,
54
- collectionId,
55
- queries: [JSON.stringify({ method: 'limit', values: [1] })],
56
- parseOutput: false
57
- });
58
-
59
- if (total === 0) {
60
- return true;
61
- }
62
-
63
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
64
- if (steps > 1 && iteration === 1) {
65
- poolMaxDebounces *= steps;
66
-
67
- log('Found a large number of attributes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
68
- }
69
-
70
- await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
71
-
72
- return await awaitPools.wipeAttributes(
73
- databaseId,
74
- collectionId,
75
- iteration + 1
76
- );
77
- },
78
- wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
79
- if (iteration > poolMaxDebounces) {
80
- return false;
81
- }
82
-
83
- const { total } = await databasesListIndexes({
84
- databaseId,
85
- collectionId,
86
- queries: [JSON.stringify({ method: 'limit', values: [1] })],
87
- parseOutput: false
88
- });
89
-
90
- if (total === 0) {
91
- return true;
92
- }
93
-
94
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
95
- if (steps > 1 && iteration === 1) {
96
- poolMaxDebounces *= steps;
97
-
98
- log('Found a large number of indexes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
99
- }
100
-
101
- await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
102
-
103
- return await awaitPools.wipeIndexes(
104
- databaseId,
105
- collectionId,
106
- iteration + 1
107
- );
108
- },
109
- wipeVariables: async (functionId, iteration = 1) => {
110
- if (iteration > poolMaxDebounces) {
111
- return false;
112
- }
113
-
114
- const { total } = await functionsListVariables({
115
- functionId,
116
- queries: ['limit(1)'],
117
- parseOutput: false
118
- });
119
-
120
- if (total === 0) {
121
- return true;
122
- }
123
-
124
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
125
- if (steps > 1 && iteration === 1) {
126
- poolMaxDebounces *= steps;
127
-
128
- log('Found a large number of variables, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
129
- }
130
-
131
- await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
132
-
133
- return await awaitPools.wipeVariables(
134
- functionId,
135
- iteration + 1
136
- );
137
- },
138
- expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
139
- if (iteration > poolMaxDebounces) {
140
- return false;
141
- }
142
-
143
- let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
144
- if (steps > 1 && iteration === 1) {
145
- poolMaxDebounces *= steps;
146
-
147
- log('Creating a large number of attributes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
148
- }
149
-
150
- const { attributes } = await paginate(databasesListAttributes, {
151
- databaseId,
152
- collectionId,
153
- parseOutput: false
154
- }, 100, 'attributes');
155
-
156
- const ready = attributes
157
- .filter(attribute => {
158
- if (attributeKeys.includes(attribute.key)) {
159
- if (['stuck', 'failed'].includes(attribute.status)) {
160
- throw new Error(`Attribute '${attribute.key}' failed!`);
161
- }
162
-
163
- return attribute.status === 'available';
164
- }
165
-
166
- return false;
167
- })
168
- .map(attribute => attribute.key);
169
-
170
- if (ready.length === attributeKeys.length) {
171
- return true;
172
- }
173
-
174
- await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
175
-
176
- return await awaitPools.expectAttributes(
177
- databaseId,
178
- collectionId,
179
- attributeKeys,
180
- iteration + 1
181
- );
182
- },
183
- expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
184
- if (iteration > poolMaxDebounces) {
185
- return false;
186
- }
187
-
188
- let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE));
189
- if (steps > 1 && iteration === 1) {
190
- poolMaxDebounces *= steps;
191
-
192
- log('Creating a large number of indexes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
193
- }
194
-
195
- const { indexes } = await paginate(databasesListIndexes, {
196
- databaseId,
197
- collectionId,
198
- parseOutput: false
199
- }, 100, 'indexes');
200
-
201
- const ready = indexes
202
- .filter((index) => {
203
- if (indexKeys.includes(index.key)) {
204
- if (['stuck', 'failed'].includes(index.status)) {
205
- throw new Error(`Index '${index.key}' failed!`);
206
- }
207
-
208
- return index.status === 'available';
209
- }
210
-
211
- return false;
212
- })
213
- .map(index => index.key);
214
-
215
- if (ready.length >= indexKeys.length) {
216
- return true;
217
- }
218
-
219
- await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
220
-
221
- return await awaitPools.expectIndexes(
222
- databaseId,
223
- collectionId,
224
- indexKeys,
225
- iteration + 1
226
- );
227
- },
228
- }
229
-
230
- const deploy = new Command("deploy")
231
- .description(commandDescriptions['deploy'])
232
- .configureHelp({
233
- helpWidth: process.stdout.columns || 80
234
- })
235
- .action(actionRunner(async (_options, command) => {
236
- command.help()
237
- }));
238
-
239
- const deployFunction = async ({ functionId, all, yes } = {}) => {
240
- let response = {};
241
-
242
- const functionIds = [];
243
-
244
- if (functionId) {
245
- functionIds.push(functionId);
246
- } else if (all) {
247
- const functions = localConfig.getFunctions();
248
- if (functions.length === 0) {
249
- throw new Error("No functions found in the current directory.");
250
- }
251
- functionIds.push(...functions.map((func, idx) => {
252
- return func.$id;
253
- }));
254
- }
255
-
256
- if (functionIds.length <= 0) {
257
- const answers = await inquirer.prompt(questionsDeployFunctions[0]);
258
- functionIds.push(...answers.functions);
259
- }
260
-
261
- let functions = functionIds.map((id) => {
262
- const functions = localConfig.getFunctions();
263
- const func = functions.find((f) => f.$id === id);
264
-
265
- if (!func) {
266
- throw new Error("Function '" + id + "' not found.")
267
- }
268
-
269
- return func;
270
- });
271
-
272
- for (let func of functions) {
273
- log(`Deploying function ${func.name} ( ${func['$id']} )`)
274
-
275
- try {
276
- response = await functionsGet({
277
- functionId: func['$id'],
278
- parseOutput: false,
279
- });
280
-
281
- if (response.runtime !== func.runtime) {
282
- throw new Error(`Runtime missmatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.json`);
283
- }
284
-
285
- response = await functionsUpdate({
286
- functionId: func['$id'],
287
- name: func.name,
288
- execute: func.execute,
289
- events: func.events,
290
- schedule: func.schedule,
291
- timeout: func.timeout,
292
- enabled: func.enabled,
293
- logging: func.logging,
294
- entrypoint: func.entrypoint,
295
- commands: func.commands,
296
- vars: JSON.stringify(response.vars),
297
- parseOutput: false
298
- });
299
- } catch (e) {
300
- if (e.code == 404) {
301
- log(`Function ${func.name} ( ${func['$id']} ) does not exist in the project. Creating ... `);
302
- response = await functionsCreate({
303
- functionId: func.$id || 'unique()',
304
- name: func.name,
305
- runtime: func.runtime,
306
- execute: func.execute,
307
- events: func.events,
308
- schedule: func.schedule,
309
- timeout: func.timeout,
310
- enabled: func.enabled,
311
- logging: func.logging,
312
- entrypoint: func.entrypoint,
313
- commands: func.commands,
314
- vars: JSON.stringify(func.vars),
315
- parseOutput: false
316
- });
317
-
318
- localConfig.updateFunction(func['$id'], {
319
- "$id": response['$id'],
320
- });
321
-
322
- func["$id"] = response['$id'];
323
- log(`Function ${func.name} created.`);
324
- } else {
325
- throw e;
326
- }
327
- }
328
-
329
- if (func.variables) {
330
- // Delete existing variables
331
-
332
- const { total } = await functionsListVariables({
333
- functionId: func['$id'],
334
- queries: [JSON.stringify({ method: 'limit', values: [1] })],
335
- parseOutput: false
336
- });
337
-
338
- let deployVariables = yes;
339
-
340
- if (total === 0) {
341
- deployVariables = true;
342
- } else if (total > 0 && !yes) {
343
- const variableAnswers = await inquirer.prompt(questionsDeployFunctions[1])
344
- deployVariables = variableAnswers.override.toLowerCase() === "yes";
345
- }
346
-
347
- if (!deployVariables) {
348
- log(`Skipping variables for ${func.name} ( ${func['$id']} )`);
349
- } else {
350
- log(`Deploying variables for ${func.name} ( ${func['$id']} )`);
351
-
352
- const { variables } = await paginate(functionsListVariables, {
353
- functionId: func['$id'],
354
- parseOutput: false
355
- }, 100, 'variables');
356
-
357
- await Promise.all(variables.map(async variable => {
358
- await functionsDeleteVariable({
359
- functionId: func['$id'],
360
- variableId: variable['$id'],
361
- parseOutput: false
362
- });
363
- }));
364
-
365
- let result = await awaitPools.wipeVariables(func['$id']);
366
- if (!result) {
367
- throw new Error("Variable deletion timed out.");
368
- }
369
-
370
- // Deploy local variables
371
- await Promise.all(Object.keys(func.variables).map(async localVariableKey => {
372
- await functionsCreateVariable({
373
- functionId: func['$id'],
374
- key: localVariableKey,
375
- value: func.variables[localVariableKey],
376
- parseOutput: false
377
- });
378
- }));
379
- }
380
- }
381
-
382
- // Create tag
383
- if (!func.entrypoint) {
384
- const answers = await inquirer.prompt(questionsGetEntrypoint)
385
- func.entrypoint = answers.entrypoint;
386
- localConfig.updateFunction(func['$id'], func);
387
- }
388
-
389
- try {
390
- response = await functionsCreateDeployment({
391
- functionId: func['$id'],
392
- entrypoint: func.entrypoint,
393
- commands: func.commands,
394
- code: func.path,
395
- activate: true,
396
- parseOutput: false
397
- })
398
-
399
- success(`Deployed ${func.name} ( ${func['$id']} )`);
400
-
401
- } catch (e) {
402
- switch (e.code) {
403
- case 'ENOENT':
404
- error(`Function ${func.name} ( ${func['$id']} ) not found in the current directory. Skipping ...`);
405
- break;
406
- default:
407
- throw e;
408
- }
409
- }
410
- }
411
-
412
- success(`Deployed ${functions.length} functions`);
413
- }
414
-
415
- const createAttribute = async (databaseId, collectionId, attribute) => {
416
- switch (attribute.type) {
417
- case 'string':
418
- switch (attribute.format) {
419
- case 'email':
420
- return await databasesCreateEmailAttribute({
421
- databaseId,
422
- collectionId,
423
- key: attribute.key,
424
- required: attribute.required,
425
- xdefault: attribute.default,
426
- array: attribute.array,
427
- parseOutput: false
428
- })
429
- case 'url':
430
- return await databasesCreateUrlAttribute({
431
- databaseId,
432
- collectionId,
433
- key: attribute.key,
434
- required: attribute.required,
435
- xdefault: attribute.default,
436
- array: attribute.array,
437
- parseOutput: false
438
- })
439
- case 'ip':
440
- return await databasesCreateIpAttribute({
441
- databaseId,
442
- collectionId,
443
- key: attribute.key,
444
- required: attribute.required,
445
- xdefault: attribute.default,
446
- array: attribute.array,
447
- parseOutput: false
448
- })
449
- case 'enum':
450
- return await databasesCreateEnumAttribute({
451
- databaseId,
452
- collectionId,
453
- key: attribute.key,
454
- elements: attribute.elements,
455
- required: attribute.required,
456
- xdefault: attribute.default,
457
- array: attribute.array,
458
- parseOutput: false
459
- })
460
- default:
461
- return await databasesCreateStringAttribute({
462
- databaseId,
463
- collectionId,
464
- key: attribute.key,
465
- size: attribute.size,
466
- required: attribute.required,
467
- xdefault: attribute.default,
468
- array: attribute.array,
469
- parseOutput: false
470
- })
471
-
472
- }
473
- case 'integer':
474
- return await databasesCreateIntegerAttribute({
475
- databaseId,
476
- collectionId,
477
- key: attribute.key,
478
- required: attribute.required,
479
- min: attribute.min,
480
- max: attribute.max,
481
- xdefault: attribute.default,
482
- array: attribute.array,
483
- parseOutput: false
484
- })
485
- case 'double':
486
- return databasesCreateFloatAttribute({
487
- databaseId,
488
- collectionId,
489
- key: attribute.key,
490
- required: attribute.required,
491
- min: attribute.min,
492
- max: attribute.max,
493
- xdefault: attribute.default,
494
- array: attribute.array,
495
- parseOutput: false
496
- })
497
- case 'boolean':
498
- return databasesCreateBooleanAttribute({
499
- databaseId,
500
- collectionId,
501
- key: attribute.key,
502
- required: attribute.required,
503
- xdefault: attribute.default,
504
- array: attribute.array,
505
- parseOutput: false
506
- })
507
- case 'datetime':
508
- return databasesCreateDatetimeAttribute({
509
- databaseId,
510
- collectionId,
511
- key: attribute.key,
512
- required: attribute.required,
513
- xdefault: attribute.default,
514
- array: attribute.array,
515
- parseOutput: false
516
- })
517
- case 'relationship':
518
- return databasesCreateRelationshipAttribute({
519
- databaseId,
520
- collectionId,
521
- relatedCollectionId: attribute.relatedCollection,
522
- type: attribute.relationType,
523
- twoWay: attribute.twoWay,
524
- key: attribute.key,
525
- twoWayKey: attribute.twoWayKey,
526
- onDelete: attribute.onDelete,
527
- parseOutput: false
528
- })
529
- }
530
- }
531
-
532
- const deployCollection = async ({ all, yes } = {}) => {
533
- let response = {};
534
-
535
- const collections = [];
536
-
537
- if (all) {
538
- if (localConfig.getCollections().length === 0) {
539
- throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
540
- }
541
- collections.push(...localConfig.getCollections());
542
- } else {
543
- const answers = await inquirer.prompt(questionsDeployCollections[0])
544
- const configCollections = new Map();
545
- localConfig.getCollections().forEach((c) => {
546
- configCollections.set(`${c['databaseId']}|${c['$id']}`, c);
547
- });
548
- answers.collections.forEach((a) => {
549
- const collection = configCollections.get(a);
550
- collections.push(collection);
551
- })
552
- }
553
-
554
- for (let collection of collections) {
555
- log(`Deploying collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} )`)
556
-
557
- let databaseId;
558
-
559
- const localDatabase = localConfig.getDatabase(collection.databaseId);
560
-
561
- try {
562
- const database = await databasesGet({
563
- databaseId: collection.databaseId,
564
- parseOutput: false,
565
- });
566
-
567
- databaseId = database.$id;
568
-
569
- if (database.name !== (localDatabase.name ?? collection.databaseId)) {
570
- await databasesUpdate({
571
- databaseId: collection.databaseId,
572
- name: localDatabase.name ?? collection.databaseId,
573
- parseOutput: false
574
- })
575
-
576
- success(`Updated ${localDatabase.name} ( ${collection.databaseId} )`);
577
- }
578
- } catch (err) {
579
- log(`Database ${collection.databaseId} not found. Creating it now...`);
580
-
581
- const database = await databasesCreate({
582
- databaseId: collection.databaseId,
583
- name: localDatabase.name ?? collection.databaseId,
584
- parseOutput: false,
585
- });
586
-
587
- databaseId = database.$id;
588
- }
589
-
590
- try {
591
- response = await databasesGetCollection({
592
- databaseId,
593
- collectionId: collection['$id'],
594
- parseOutput: false,
595
- })
596
-
597
- log(`Collection ${collection.name} ( ${collection['$id']} ) already exists.`);
598
-
599
- if (!yes) {
600
- const answers = await inquirer.prompt(questionsDeployCollections[1])
601
- if (answers.override.toLowerCase() !== "yes") {
602
- log(`Received "${answers.override}". Skipping ${collection.name} ( ${collection['$id']} )`);
603
- continue;
604
- }
605
- }
606
-
607
- log(`Deleting indexes and attributes ... `);
608
-
609
- const { indexes } = await paginate(databasesListIndexes, {
610
- databaseId,
611
- collectionId: collection['$id'],
612
- parseOutput: false
613
- }, 100, 'indexes');
614
-
615
- await Promise.all(indexes.map(async index => {
616
- await databasesDeleteIndex({
617
- databaseId,
618
- collectionId: collection['$id'],
619
- key: index.key,
620
- parseOutput: false
621
- });
622
- }));
623
-
624
- let result = await awaitPools.wipeIndexes(databaseId, collection['$id']);
625
- if (!result) {
626
- throw new Error("Index deletion timed out.");
627
- }
628
-
629
- const { attributes } = await paginate(databasesListAttributes, {
630
- databaseId,
631
- collectionId: collection['$id'],
632
- parseOutput: false
633
- }, 100, 'attributes');
634
-
635
- await Promise.all(attributes.map(async attribute => {
636
- await databasesDeleteAttribute({
637
- databaseId,
638
- collectionId: collection['$id'],
639
- key: attribute.key,
640
- parseOutput: false
641
- });
642
- }));
643
-
644
- const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(databaseId, collection['$id']);
645
- if (!deleteAttributesPoolStatus) {
646
- throw new Error("Attribute deletion timed out.");
647
- }
648
-
649
- await databasesUpdateCollection({
650
- databaseId,
651
- collectionId: collection['$id'],
652
- name: collection.name,
653
- documentSecurity: collection.documentSecurity,
654
- permissions: collection['$permissions'],
655
- enabled: collection.enabled,
656
- parseOutput: false
657
- })
658
- } catch (e) {
659
- if (e.code == 404) {
660
- log(`Collection ${collection.name} does not exist in the project. Creating ... `);
661
- response = await databasesCreateCollection({
662
- databaseId,
663
- collectionId: collection['$id'],
664
- name: collection.name,
665
- documentSecurity: collection.documentSecurity,
666
- permissions: collection['$permissions'],
667
- parseOutput: false
668
- })
669
-
670
- } else {
671
- throw e;
672
- }
673
- }
674
-
675
- // Create all non-relationship attributes first
676
- const attributes = collection.attributes.filter(attribute => attribute.type !== 'relationship');
677
-
678
- await Promise.all(attributes.map(attribute => {
679
- return createAttribute(databaseId, collection['$id'], attribute);
680
- }));
681
-
682
- let result = await awaitPools.expectAttributes(
683
- databaseId,
684
- collection['$id'],
685
- attributes.map(attribute => attribute.key)
686
- );
687
-
688
- if (!result) {
689
- throw new Error("Attribute creation timed out.");
690
- }
691
-
692
- success(`Created ${attributes.length} non-relationship attributes`);
693
-
694
- log(`Creating indexes ...`)
695
-
696
- await Promise.all(collection.indexes.map(async index => {
697
- await databasesCreateIndex({
698
- databaseId,
699
- collectionId: collection['$id'],
700
- key: index.key,
701
- type: index.type,
702
- attributes: index.attributes,
703
- orders: index.orders,
704
- parseOutput: false
705
- });
706
- }));
707
-
708
- result = await awaitPools.expectIndexes(
709
- databaseId,
710
- collection['$id'],
711
- collection.indexes.map(attribute => attribute.key)
712
- );
713
-
714
- if (!result) {
715
- throw new Error("Index creation timed out.");
716
- }
717
-
718
- success(`Created ${collection.indexes.length} indexes`);
719
-
720
- success(`Deployed ${collection.name} ( ${collection['$id']} )`);
721
- }
722
-
723
- // Create the relationship attributes
724
- for (let collection of collections) {
725
- const relationships = collection.attributes.filter(attribute =>
726
- attribute.type === 'relationship' && attribute.side === 'parent'
727
- );
728
-
729
- if (relationships.length === 0) {
730
- continue;
731
- }
732
-
733
- log(`Deploying relationships for collection ${collection.name} ( ${collection['$id']} )`);
734
-
735
- await Promise.all(relationships.map(attribute => {
736
- return createAttribute(collection['databaseId'], collection['$id'], attribute);
737
- }));
738
-
739
- let result = await awaitPools.expectAttributes(
740
- collection['databaseId'],
741
- collection['$id'],
742
- relationships.map(attribute => attribute.key)
743
- );
744
-
745
- if (!result) {
746
- throw new Error("Attribute creation timed out.");
747
- }
748
-
749
- success(`Created ${relationships.length} relationship attributes`);
750
- }
751
- }
752
-
753
- const deployBucket = async ({ all, yes } = {}) => {
754
- let response = {};
755
-
756
- let bucketIds = [];
757
- const configBuckets = localConfig.getBuckets();
758
-
759
- if (all) {
760
- if (configBuckets.length === 0) {
761
- throw new Error("No buckets found in the current directory. Run `appwrite init bucket` to fetch all your buckets.");
762
- }
763
- bucketIds.push(...configBuckets.map((b) => b.$id));
764
- }
765
-
766
- if (bucketIds.length === 0) {
767
- const answers = await inquirer.prompt(questionsDeployBuckets[0])
768
- bucketIds.push(...answers.buckets);
769
- }
770
-
771
- let buckets = [];
772
-
773
- for (const bucketId of bucketIds) {
774
- const idBuckets = configBuckets.filter((b) => b.$id === bucketId);
775
- buckets.push(...idBuckets);
776
- }
777
-
778
- for (let bucket of buckets) {
779
- log(`Deploying bucket ${bucket.name} ( ${bucket['$id']} )`)
780
-
781
- try {
782
- response = await storageGetBucket({
783
- bucketId: bucket['$id'],
784
- parseOutput: false,
785
- })
786
- log(`Bucket ${bucket.name} ( ${bucket['$id']} ) already exists.`);
787
-
788
- if (!yes) {
789
- const answers = await inquirer.prompt(questionsDeployBuckets[1])
790
- if (answers.override.toLowerCase() !== "yes") {
791
- log(`Received "${answers.override}". Skipping ${bucket.name} ( ${bucket['$id']} )`);
792
- continue;
793
- }
794
- }
795
-
796
- log(`Updating bucket ...`)
797
-
798
- await storageUpdateBucket({
799
- bucketId: bucket['$id'],
800
- name: bucket.name,
801
- permissions: bucket['$permissions'],
802
- fileSecurity: bucket.fileSecurity,
803
- enabled: bucket.enabled,
804
- maximumFileSize: bucket.maximumFileSize,
805
- allowedFileExtensions: bucket.allowedFileExtensions,
806
- compression: bucket.compression,
807
- encryption: bucket.encryption,
808
- antivirus: bucket.antivirus,
809
- compression: bucket.compression,
810
- parseOutput: false
811
- });
812
-
813
- success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
814
- } catch (e) {
815
- if (e.code == 404) {
816
- log(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
817
-
818
- response = await storageCreateBucket({
819
- bucketId: bucket['$id'],
820
- name: bucket.name,
821
- permissions: bucket['$permissions'],
822
- fileSecurity: bucket.fileSecurity,
823
- enabled: bucket.enabled,
824
- maximumFileSize: bucket.maximumFileSize,
825
- allowedFileExtensions: bucket.allowedFileExtensions,
826
- compression: bucket.compression,
827
- encryption: bucket.encryption,
828
- antivirus: bucket.antivirus,
829
- parseOutput: false
830
- })
831
-
832
- success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
833
- } else {
834
- throw e;
835
- }
836
- }
837
- }
838
- }
839
-
840
- const deployTeam = async ({ all, yes } = {}) => {
841
- let response = {};
842
-
843
- let teamIds = [];
844
- const configTeams = localConfig.getTeams();
845
-
846
- if (all) {
847
- if (configTeams.length === 0) {
848
- throw new Error("No teams found in the current directory. Run `appwrite init team` to fetch all your teams.");
849
- }
850
- teamIds.push(...configTeams.map((t) => t.$id));
851
- }
852
-
853
- if (teamIds.length === 0) {
854
- const answers = await inquirer.prompt(questionsDeployTeams[0])
855
- teamIds.push(...answers.teams);
856
- }
857
-
858
- let teams = [];
859
-
860
- for (const teamId of teamIds) {
861
- const idTeams = configTeams.filter((t) => t.$id === teamId);
862
- teams.push(...idTeams);
863
- }
864
-
865
- for (let team of teams) {
866
- log(`Deploying team ${team.name} ( ${team['$id']} )`)
867
-
868
- try {
869
- response = await teamsGet({
870
- teamId: team['$id'],
871
- parseOutput: false,
872
- })
873
- log(`Team ${team.name} ( ${team['$id']} ) already exists.`);
874
-
875
- if (!yes) {
876
- const answers = await inquirer.prompt(questionsDeployTeams[1])
877
- if (answers.override.toLowerCase() !== "yes") {
878
- log(`Received "${answers.override}". Skipping ${team.name} ( ${team['$id']} )`);
879
- continue;
880
- }
881
- }
882
-
883
- log(`Updating team ...`)
884
-
885
- await teamsUpdate({
886
- teamId: team['$id'],
887
- name: team.name,
888
- parseOutput: false
889
- });
890
-
891
- success(`Deployed ${team.name} ( ${team['$id']} )`);
892
- } catch (e) {
893
- if (e.code == 404) {
894
- log(`Team ${team.name} does not exist in the project. Creating ... `);
895
-
896
- response = await teamsCreate({
897
- teamId: team['$id'],
898
- name: team.name,
899
- parseOutput: false
900
- })
901
-
902
- success(`Deployed ${team.name} ( ${team['$id']} )`);
903
- } else {
904
- throw e;
905
- }
906
- }
907
- }
908
- }
909
-
910
- deploy
911
- .command("function")
912
- .description("Deploy functions in the current directory.")
913
- .option(`--functionId <functionId>`, `Function ID`)
914
- .option(`--all`, `Flag to deploy all functions`)
915
- .option(`--yes`, `Flag to confirm all warnings`)
916
- .action(actionRunner(deployFunction));
917
-
918
- deploy
919
- .command("collection")
920
- .description("Deploy collections in the current project.")
921
- .option(`--all`, `Flag to deploy all collections`)
922
- .option(`--yes`, `Flag to confirm all warnings`)
923
- .action(actionRunner(deployCollection));
924
-
925
- deploy
926
- .command("bucket")
927
- .description("Deploy buckets in the current project.")
928
- .option(`--all`, `Flag to deploy all buckets`)
929
- .option(`--yes`, `Flag to confirm all warnings`)
930
- .action(actionRunner(deployBucket));
931
-
932
- deploy
933
- .command("team")
934
- .description("Deploy teams in the current project.")
935
- .option(`--all`, `Flag to deploy all teams`)
936
- .option(`--yes`, `Flag to confirm all warnings`)
937
- .action(actionRunner(deployTeam));
938
-
939
- module.exports = {
940
- deploy
941
- }