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
package/lib/questions.js CHANGED
@@ -1,14 +1,22 @@
1
- const { localConfig } = require('./config');
1
+ const chalk = require("chalk");
2
+ const Client = require("./client");
3
+ const { localConfig, globalConfig } = require('./config');
2
4
  const { projectsList } = require('./commands/projects');
3
- const { functionsListRuntimes } = require('./commands/functions');
5
+ const { teamsList } = require('./commands/teams');
6
+ const { functionsListRuntimes, functionsList } = require('./commands/functions');
4
7
  const { accountListMfaFactors } = require("./commands/account");
5
8
  const { sdkForConsole } = require("./sdks");
6
-
9
+ const { validateRequired } = require("./validations");
10
+ const { paginate } = require('./paginate');
11
+ const { isPortTaken } = require('./utils');
7
12
  const { databasesList } = require('./commands/databases');
13
+ const { checkDeployConditions } = require('./utils');
8
14
  const JSONbig = require("json-bigint")({ storeAsString: false });
9
15
 
16
+ const whenOverride = (answers) => answers.override === undefined ? true : answers.override;
17
+
10
18
  const getIgnores = (runtime) => {
11
- const languge = runtime.split('-')[0];
19
+ const languge = runtime.split("-").slice(0, -1).join("-");
12
20
 
13
21
  switch (languge) {
14
22
  case 'cpp':
@@ -28,6 +36,7 @@ const getIgnores = (runtime) => {
28
36
  case 'php':
29
37
  return ['vendor'];
30
38
  case 'python':
39
+ case 'python-ml':
31
40
  return ['__pypackages__'];
32
41
  case 'ruby':
33
42
  return ['vendor'];
@@ -41,7 +50,7 @@ const getIgnores = (runtime) => {
41
50
  };
42
51
 
43
52
  const getEntrypoint = (runtime) => {
44
- const languge = runtime.split('-')[0];
53
+ const languge = runtime.split("-").slice(0, -1).join("-");
45
54
 
46
55
  switch (languge) {
47
56
  case 'dart':
@@ -55,6 +64,7 @@ const getEntrypoint = (runtime) => {
55
64
  case 'php':
56
65
  return 'src/index.php';
57
66
  case 'python':
67
+ case 'python-ml':
58
68
  return 'src/main.py';
59
69
  case 'ruby':
60
70
  return 'lib/main.rb';
@@ -76,7 +86,7 @@ const getEntrypoint = (runtime) => {
76
86
  };
77
87
 
78
88
  const getInstallCommand = (runtime) => {
79
- const languge = runtime.split('-')[0];
89
+ const languge = runtime.split("-").slice(0, -1).join("-");
80
90
 
81
91
  switch (languge) {
82
92
  case 'dart':
@@ -90,6 +100,7 @@ const getInstallCommand = (runtime) => {
90
100
  case 'php':
91
101
  return 'composer install';
92
102
  case 'python':
103
+ case 'python-ml':
93
104
  return 'pip install -r requirements.txt';
94
105
  case 'ruby':
95
106
  return 'bundle install';
@@ -112,7 +123,7 @@ const questionsInitProject = [
112
123
  type: "confirm",
113
124
  name: "override",
114
125
  message:
115
- `An Appwrite project ( ${localConfig.getProject()['projectName']} ) is already associated with the current directory. Would you like to override`,
126
+ `An Appwrite project ( ${localConfig.getProject()['projectId']} ) is already associated with the current directory. Would you like to override`,
116
127
  when() {
117
128
  return Object.keys(localConfig.getProject()).length !== 0;
118
129
  }
@@ -120,61 +131,72 @@ const questionsInitProject = [
120
131
  {
121
132
  type: "list",
122
133
  name: "start",
123
- when(answers) {
124
- if (answers.override == undefined) {
125
- return true
126
- }
127
- return answers.override;
128
- },
134
+ when: whenOverride,
129
135
  message: "How would you like to start?",
130
136
  choices: [
131
137
  {
132
- name: "Create a new Appwrite project",
133
- value: "new",
138
+ name: "Create new project",
139
+ value: "new"
134
140
  },
135
141
  {
136
- name: "Link this directory to an existing Appwrite project",
137
- value: "existing",
138
- },
139
- ],
142
+ name: "Link directory to an existing project",
143
+ value: "existing"
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ type: "search-list",
149
+ name: "organization",
150
+ message: "Choose your organization",
151
+ choices: async () => {
152
+ let client = await sdkForConsole(true);
153
+ const { teams } = await paginate(teamsList, { parseOutput: false, sdk: client }, 100, 'teams');
154
+
155
+ let choices = teams.map((team, idx) => {
156
+ return {
157
+ name: `${team.name} (${team['$id']})`,
158
+ value: team['$id']
159
+ }
160
+ })
161
+
162
+ if (choices.length == 0) {
163
+ throw new Error(`No organizations found. Please create a new organization at ${globalConfig.getEndpoint().replace('/v1', '/console/onboarding')}`)
164
+ }
165
+
166
+ return choices;
167
+ },
168
+ when: whenOverride
140
169
  },
141
170
  {
142
171
  type: "input",
143
172
  name: "project",
144
173
  message: "What would you like to name your project?",
145
174
  default: "My Awesome Project",
146
- when(answers) {
147
- return answers.start == "new";
148
- },
175
+ when: (answer) => answer.start !== 'existing'
149
176
  },
150
177
  {
151
178
  type: "input",
152
179
  name: "id",
153
180
  message: "What ID would you like to have for your project?",
154
181
  default: "unique()",
155
- when(answers) {
156
- return answers.start == "new";
157
- },
182
+ when: (answer) => answer.start !== 'existing'
158
183
  },
159
184
  {
160
- type: "list",
185
+ type: "search-list",
161
186
  name: "project",
162
187
  message: "Choose your Appwrite project.",
163
- when(answers) {
164
- return answers.start == "existing";
165
- },
166
- choices: async () => {
167
- let response = await projectsList({
168
- parseOutput: false
169
- })
170
- let projects = response["projects"]
171
- let choices = projects.map((project, idx) => {
188
+ choices: async (answers) => {
189
+ const queries = [
190
+ JSON.stringify({ method: 'equal', attribute: 'teamId', values: [answers.organization.id] }),
191
+ JSON.stringify({ method: 'orderDesc', attribute: 'Id' })
192
+ ]
193
+
194
+ const { projects } = await paginate(projectsList, { parseOutput: false, queries, }, 100, 'projects');
195
+
196
+ let choices = projects.map((project) => {
172
197
  return {
173
198
  name: `${project.name} (${project['$id']})`,
174
- value: {
175
- name: project.name,
176
- id: project['$id']
177
- }
199
+ value: project['$id']
178
200
  }
179
201
  })
180
202
 
@@ -183,11 +205,50 @@ const questionsInitProject = [
183
205
  }
184
206
 
185
207
  return choices;
208
+ },
209
+ when: (answer) => answer.start === 'existing'
210
+ }
211
+ ];
212
+ const questionsPullResources = [
213
+ {
214
+ type: "list",
215
+ name: "resource",
216
+ message: "Which resources would you like to pull?",
217
+ choices: [
218
+ { name: 'Project', value: 'project' },
219
+ { name: 'Functions', value: 'functions' },
220
+ { name: 'Collections', value: 'collections' },
221
+ { name: 'Buckets', value: 'buckets' },
222
+ { name: 'Teams', value: 'teams' },
223
+ { name: 'Topics', value: 'messages' }
224
+ ]
225
+ }
226
+ ]
227
+
228
+ const questionsPullFunctions = [
229
+ {
230
+ type: "checkbox",
231
+ name: "functions",
232
+ message: "Which functions would you like to pull?",
233
+ validate: (value) => validateRequired('function', value),
234
+ choices: async () => {
235
+ const { functions } = await paginate(functionsList, { parseOutput: false }, 100, 'functions');
236
+
237
+ if (functions.length === 0) {
238
+ throw "We couldn't find any functions in your Appwrite project";
239
+ }
240
+
241
+ return functions.map(func => {
242
+ return {
243
+ name: `${func.name} (${func.$id})`,
244
+ value: func
245
+ }
246
+ });
186
247
  }
187
248
  }
188
249
  ];
189
250
 
190
- const questionsInitFunction = [
251
+ const questionsCreateFunction = [
191
252
  {
192
253
  type: "input",
193
254
  name: "name",
@@ -209,14 +270,15 @@ const questionsInitFunction = [
209
270
  parseOutput: false
210
271
  })
211
272
  let runtimes = response["runtimes"]
212
- let choices = runtimes.map((runtime, idx) => {
273
+ let choices = runtimes.map((runtime, idx) => {
213
274
  return {
214
275
  name: `${runtime.name} (${runtime['$id']})`,
215
- value: {
216
- id: runtime['$id'],
217
- entrypoint: getEntrypoint(runtime['$id']),
276
+ value: {
277
+ id: runtime['$id'],
278
+ name: runtime['$id'].split('-')[0],
279
+ entrypoint: getEntrypoint(runtime['$id']),
218
280
  ignore: getIgnores(runtime['$id']),
219
- commands : getInstallCommand(runtime['$id'])
281
+ commands: getInstallCommand(runtime['$id'])
220
282
  },
221
283
  }
222
284
  })
@@ -225,11 +287,146 @@ const questionsInitFunction = [
225
287
  }
226
288
  ];
227
289
 
228
- const questionsInitCollection = [
290
+ const questionsCreateFunctionSelectTemplate = (templates) => {
291
+ return [
292
+ {
293
+ type: "search-list",
294
+ name: "template",
295
+ message: "What template would you like to use?",
296
+ choices: templates.map((template) => {
297
+ const name = `${template[0].toUpperCase()}${template.split('').slice(1).join('')}`.replace(/[-_]/g, ' ');
298
+
299
+ return { value: template, name }
300
+ })
301
+ }
302
+ ];
303
+ };
304
+
305
+
306
+
307
+ const questionsCreateBucket = [
308
+ {
309
+ type: "input",
310
+ name: "bucket",
311
+ message: "What would you like to name your bucket?",
312
+ default: "My Awesome Bucket"
313
+ },
314
+ {
315
+ type: "input",
316
+ name: "id",
317
+ message: "What ID would you like to have for your bucket?",
318
+ default: "unique()"
319
+ },
320
+ {
321
+ type: "list",
322
+ name: "fileSecurity",
323
+ message: "Enable File-Security configuring permissions for individual file",
324
+ choices: ["No", "Yes"]
325
+ }
326
+ ];
327
+
328
+ const questionsCreateTeam = [
329
+ {
330
+ type: "input",
331
+ name: "bucket",
332
+ message: "What would you like to name your team?",
333
+ default: "My Awesome Team"
334
+ },
335
+ {
336
+ type: "input",
337
+ name: "id",
338
+ message: "What ID would you like to have for your team?",
339
+ default: "unique()"
340
+ }
341
+ ];
342
+
343
+ const questionsCreateCollection = [
344
+ {
345
+ type: "list",
346
+ name: "method",
347
+ message: "What database would you like to use for your collection",
348
+ choices: ["New", "Existing"],
349
+ when: async () => {
350
+ return localConfig.getDatabases().length !== 0;
351
+ }
352
+ },
353
+ {
354
+ type: "search-list",
355
+ name: "database",
356
+ message: "Choose the collection database",
357
+ choices: async () => {
358
+ const databases = localConfig.getDatabases();
359
+
360
+ let choices = databases.map((database, idx) => {
361
+ return {
362
+ name: `${database.name} (${database.$id})`,
363
+ value: database.$id
364
+ }
365
+ })
366
+
367
+ if (choices.length === 0) {
368
+ throw new Error("No databases found. Please create one in project console.")
369
+ }
370
+
371
+ return choices;
372
+ },
373
+ when: (answers) => (answers.method ?? '').toLowerCase() === 'existing'
374
+ },
375
+ {
376
+ type: "input",
377
+ name: "databaseName",
378
+ message: "What would you like to name your database?",
379
+ default: "My Awesome Database",
380
+ when: (answers) => (answers.method ?? '').toLowerCase() !== 'existing'
381
+ },
382
+ {
383
+ type: "input",
384
+ name: "databaseId",
385
+ message: "What ID would you like to have for your database?",
386
+ default: "unique()",
387
+ when: (answers) => (answers.method ?? '').toLowerCase() !== 'existing'
388
+ },
389
+ {
390
+ type: "input",
391
+ name: "collection",
392
+ message: "What would you like to name your collection?",
393
+ default: "My Awesome Collection"
394
+ },
395
+ {
396
+ type: "input",
397
+ name: "id",
398
+ message: "What ID would you like to have for your collection?",
399
+ default: "unique()"
400
+ },
401
+ {
402
+ type: "list",
403
+ name: "documentSecurity",
404
+ message: "Enable Document-Security for configuring permissions for individual documents",
405
+ choices: ["No", "Yes"]
406
+ }
407
+ ];
408
+
409
+ const questionsCreateMessagingTopic = [
410
+ {
411
+ type: "input",
412
+ name: "topic",
413
+ message: "What would you like to name your messaging topic?",
414
+ default: "My Awesome Topic"
415
+ },
416
+ {
417
+ type: "input",
418
+ name: "id",
419
+ message: "What ID would you like to have for your messaging topic?",
420
+ default: "unique()"
421
+ }
422
+ ];
423
+
424
+ const questionsPullCollection = [
229
425
  {
230
426
  type: "checkbox",
231
427
  name: "databases",
232
- message: "From which database would you like to init collections?",
428
+ message: "From which database would you like to pull collections?",
429
+ validate: (value) => validateRequired('collection', value),
233
430
  choices: async () => {
234
431
  let response = await databasesList({
235
432
  parseOutput: false
@@ -251,6 +448,16 @@ const questionsInitCollection = [
251
448
  ];
252
449
 
253
450
  const questionsLogin = [
451
+ {
452
+ type: "list",
453
+ name: "method",
454
+ message: "You're already logged in, what you like to do?",
455
+ choices: [
456
+ { name: 'Login to a different account', value: 'login' },
457
+ { name: 'Change to a different existed account', value: 'select' }
458
+ ],
459
+ when: () => globalConfig.getCurrentSession() !== ''
460
+ },
254
461
  {
255
462
  type: "input",
256
463
  name: "email",
@@ -261,6 +468,7 @@ const questionsLogin = [
261
468
  }
262
469
  return true;
263
470
  },
471
+ when: (answers) => answers.method !== 'select'
264
472
  },
265
473
  {
266
474
  type: "password",
@@ -272,19 +480,132 @@ const questionsLogin = [
272
480
  return "Please enter your password";
273
481
  }
274
482
  return true;
275
- }
483
+ },
484
+ when: (answers) => answers.method !== 'select'
485
+ },
486
+ {
487
+ type: "search-list",
488
+ name: "accountId",
489
+ message: "Select an account to use",
490
+ choices() {
491
+ const sessions = globalConfig.getSessions();
492
+ const current = globalConfig.getCurrentSession();
493
+
494
+ const data = [];
495
+
496
+ const longestEmail = sessions.reduce((prev, current) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length;
497
+
498
+ sessions.forEach((session) => {
499
+ if (session.email) {
500
+ data.push({
501
+ current: current === session.id,
502
+ value: session.id,
503
+ name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold('current') : ' '.repeat(6)} ${session.endpoint}`,
504
+ });
505
+ }
506
+ })
507
+
508
+ return data.sort((a, b) => Number(b.current) - Number(a.current))
509
+ },
510
+ when: (answers) => answers.method === 'select'
276
511
  },
277
512
  ];
513
+ const questionGetEndpoint = [
514
+ {
515
+ type: "input",
516
+ name: "endpoint",
517
+ message: "Enter the endpoint of your Appwrite server",
518
+ default: "http://localhost/v1",
519
+ async validate(value) {
520
+ if (!value) {
521
+ return "Please enter a valid endpoint.";
522
+ }
523
+ let client = new Client().setEndpoint(value);
524
+ try {
525
+ let response = await client.call('get', '/health/version');
526
+ if (response.version) {
527
+ return true;
528
+ } else {
529
+ throw new Error();
530
+ }
531
+ } catch (error) {
532
+ return "Invalid endpoint or your Appwrite server is not running as expected.";
533
+ }
534
+ }
535
+ }
536
+ ];
537
+
538
+ const questionsLogout = [
539
+ {
540
+ type: "checkbox",
541
+ name: "accounts",
542
+ message: "Select accounts to logout from",
543
+ validate: (value) => validateRequired('account', value),
544
+ choices() {
545
+ const sessions = globalConfig.getSessions();
546
+ const current = globalConfig.getCurrentSession();
547
+
548
+ const data = [];
549
+
550
+ const longestEmail = sessions.reduce((prev, current) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length;
551
+
552
+ sessions.forEach((session) => {
553
+ if (session.email) {
554
+ data.push({
555
+ current: current === session.id,
556
+ value: session.id,
557
+ name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold('current') : ' '.repeat(6)} ${session.endpoint}`,
558
+ });
559
+ }
560
+ })
561
+
562
+ return data.sort((a, b) => Number(b.current) - Number(a.current))
563
+ }
564
+ }
565
+ ];
566
+
567
+ const questionsPushResources = [
568
+ {
569
+ type: "list",
570
+ name: "resource",
571
+ message: "Which resources would you like to push?",
572
+ choices: [
573
+ { name: 'Project', value: 'project' },
574
+ { name: 'Functions', value: 'functions' },
575
+ { name: 'Collections', value: 'collections' },
576
+ { name: 'Buckets', value: 'buckets' },
577
+ { name: 'Teams', value: 'teams' },
578
+ { name: 'Topics', value: 'messages' }
579
+ ]
580
+ }
581
+ ];
582
+
583
+ const questionsInitResources = [
584
+ {
585
+ type: "list",
586
+ name: "resource",
587
+ message: "Which resource would you create?",
588
+ choices: [
589
+ { name: 'Function', value: 'function' },
590
+ { name: 'Collection', value: 'collection' },
591
+ { name: 'Bucket', value: 'bucket' },
592
+ { name: 'Team', value: 'team' },
593
+ { name: 'Topic', value: 'message' }
594
+ ]
595
+ }
596
+ ];
278
597
 
279
- const questionsDeployFunctions = [
598
+ const questionsPushFunctions = [
280
599
  {
281
600
  type: "checkbox",
282
601
  name: "functions",
283
- message: "Which functions would you like to deploy?",
602
+ message: "Which functions would you like to push?",
603
+ validate: (value) => validateRequired('function', value),
284
604
  choices: () => {
285
605
  let functions = localConfig.getFunctions();
606
+ checkDeployConditions(localConfig)
286
607
  if (functions.length === 0) {
287
- throw new Error("No functions found in the current directory.");
608
+ throw new Error("No functions found in the current directory Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
288
609
  }
289
610
  let choices = functions.map((func, idx) => {
290
611
  return {
@@ -302,15 +623,18 @@ const questionsDeployFunctions = [
302
623
  },
303
624
  ]
304
625
 
305
- const questionsDeployCollections = [
626
+ const questionsPushCollections = [
306
627
  {
307
628
  type: "checkbox",
308
629
  name: "collections",
309
- message: "Which collections would you like to deploy?",
630
+ message: "Which collections would you like to push?",
631
+ validate: (value) => validateRequired('collection', value),
310
632
  choices: () => {
311
633
  let collections = localConfig.getCollections();
634
+ checkDeployConditions(localConfig)
635
+
312
636
  if (collections.length === 0) {
313
- throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
637
+ throw new Error("No collections found in the current directory. Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.");
314
638
  }
315
639
  return collections.map(collection => {
316
640
  return {
@@ -322,20 +646,22 @@ const questionsDeployCollections = [
322
646
  },
323
647
  {
324
648
  type: "input",
325
- name: "override",
326
- message: 'Are you sure you want to override this collection? This can lead to loss of data! Type "YES" to confirm.'
327
- },
649
+ name: "changes",
650
+ message: `Would you like to apply these changes? Type "YES" to confirm.`
651
+ }
328
652
  ]
329
653
 
330
- const questionsDeployBuckets = [
654
+ const questionsPushBuckets = [
331
655
  {
332
656
  type: "checkbox",
333
657
  name: "buckets",
334
- message: "Which buckets would you like to deploy?",
658
+ message: "Which buckets would you like to push?",
659
+ validate: (value) => validateRequired('bucket', value),
335
660
  choices: () => {
336
661
  let buckets = localConfig.getBuckets();
662
+ checkDeployConditions(localConfig)
337
663
  if (buckets.length === 0) {
338
- throw new Error("No buckets found in the current directory. Run `appwrite init bucket` to fetch all your buckets.");
664
+ throw new Error("No buckets found in the current directory. Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.");
339
665
  }
340
666
  return buckets.map(bucket => {
341
667
  return {
@@ -344,12 +670,32 @@ const questionsDeployBuckets = [
344
670
  }
345
671
  });
346
672
  }
673
+ }
674
+ ]
675
+
676
+ const questionsPushMessagingTopics = [
677
+ {
678
+ type: "checkbox",
679
+ name: "topics",
680
+ message: "Which messaging topic would you like to push?",
681
+ choices: () => {
682
+ let topics = localConfig.getMessagingTopics();
683
+ if (topics.length === 0) {
684
+ throw new Error("No topics found in the current directory. Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.");
685
+ }
686
+ return topics.map(topic => {
687
+ return {
688
+ name: `${topic.name} (${topic['$id']})`,
689
+ value: topic.$id
690
+ }
691
+ });
692
+ }
347
693
  },
348
694
  {
349
695
  type: "input",
350
696
  name: "override",
351
- message: 'Are you sure you want to override this bucket? This can lead to loss of data! Type "YES" to confirm.'
352
- },
697
+ message: 'Would you like to override existing topics? This can lead to loss of data! Type "YES" to confirm.'
698
+ }
353
699
  ]
354
700
 
355
701
  const questionsGetEntrypoint = [
@@ -367,15 +713,17 @@ const questionsGetEntrypoint = [
367
713
  },
368
714
  ]
369
715
 
370
- const questionsDeployTeams = [
716
+ const questionsPushTeams = [
371
717
  {
372
718
  type: "checkbox",
373
719
  name: "teams",
374
- message: "Which teams would you like to deploy?",
720
+ message: "Which teams would you like to push?",
721
+ validate: (value) => validateRequired('team', value),
375
722
  choices: () => {
376
723
  let teams = localConfig.getTeams();
724
+ checkDeployConditions(localConfig);
377
725
  if (teams.length === 0) {
378
- throw new Error("No teams found in the current directory. Run `appwrite init team` to fetch all your teams.");
726
+ throw new Error("No teams found in the current directory. Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.");
379
727
  }
380
728
  return teams.map(team => {
381
729
  return {
@@ -385,43 +733,38 @@ const questionsDeployTeams = [
385
733
  });
386
734
  }
387
735
  },
388
- {
389
- type: "input",
390
- name: "override",
391
- message: 'Are you sure you want to override this team? This can lead to loss of data! Type "YES" to confirm.'
392
- },
393
736
  ];
394
737
 
395
738
  const questionsListFactors = [
396
739
  {
397
740
  type: "list",
398
741
  name: "factor",
399
- message: "Your account is protected by multiple factors. Which factor would you like to use to authenticate?",
742
+ message: "Your account is protected by multi-factor authentication. Please choose one for verification.",
400
743
  choices: async () => {
401
744
  let client = await sdkForConsole(false);
402
745
  const factors = await accountListMfaFactors({
403
746
  sdk: client,
404
747
  parseOutput: false
405
748
  });
406
-
749
+
407
750
  const choices = [
408
751
  {
409
- name: `TOTP (Time-based One-time Password)`,
752
+ name: `Authenticator app (Get a code from a third-party authenticator app)`,
410
753
  value: 'totp'
411
754
  },
412
755
  {
413
- name: `E-mail`,
756
+ name: `Email (Get a security code at your Appwrite email address)`,
414
757
  value: 'email'
415
758
  },
416
759
  {
417
- name: `Phone (SMS)`,
760
+ name: `SMS (Get a security code on your Appwrite phone number)`,
418
761
  value: 'phone'
419
762
  },
420
763
  {
421
- name: `Recovery code`,
764
+ name: `Recovery code (Use one of your recovery codes for verification)`,
422
765
  value: 'recoveryCode'
423
766
  }
424
- ].filter((ch) => factors[ch.value] === true);
767
+ ].filter((ch) => factors[ch.value] === true);
425
768
 
426
769
  return choices;
427
770
  }
@@ -442,16 +785,51 @@ const questionsMfaChallenge = [
442
785
  }
443
786
  ];
444
787
 
788
+ const questionsRunFunctions = [
789
+ {
790
+ type: "list",
791
+ name: "function",
792
+ message: "Which function would you like to develop locally?",
793
+ validate: (value) => validateRequired('function', value),
794
+ choices: () => {
795
+ let functions = localConfig.getFunctions();
796
+ if (functions.length === 0) {
797
+ throw new Error("No functions found in the current directory. Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.");
798
+ }
799
+ let choices = functions.map((func, idx) => {
800
+ return {
801
+ name: `${func.name} (${func.$id})`,
802
+ value: func.$id
803
+ }
804
+ })
805
+ return choices;
806
+ }
807
+ }
808
+ ];
809
+
445
810
  module.exports = {
446
811
  questionsInitProject,
812
+ questionsCreateFunction,
813
+ questionsCreateFunctionSelectTemplate,
814
+ questionsCreateBucket,
815
+ questionsCreateCollection,
816
+ questionsCreateMessagingTopic,
817
+ questionsPullFunctions,
447
818
  questionsLogin,
448
- questionsInitFunction,
449
- questionsInitCollection,
450
- questionsDeployFunctions,
451
- questionsDeployCollections,
452
- questionsDeployBuckets,
453
- questionsDeployTeams,
819
+ questionsPullResources,
820
+ questionsLogout,
821
+ questionsPullCollection,
822
+ questionsPushResources,
823
+ questionsPushFunctions,
824
+ questionsPushCollections,
825
+ questionsPushBuckets,
826
+ questionsPushMessagingTopics,
827
+ questionsPushTeams,
454
828
  questionsGetEntrypoint,
455
829
  questionsListFactors,
456
- questionsMfaChallenge
830
+ questionsMfaChallenge,
831
+ questionsRunFunctions,
832
+ questionGetEndpoint,
833
+ questionsInitResources,
834
+ questionsCreateTeam
457
835
  };