appwrite-cli 6.2.2 → 7.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 (111) hide show
  1. package/README.md +8 -7
  2. package/docs/examples/console/get-resource.md +3 -0
  3. package/docs/examples/databases/create-documents.md +4 -0
  4. package/docs/examples/databases/create-index.md +1 -0
  5. package/docs/examples/databases/delete-documents.md +4 -0
  6. package/docs/examples/databases/update-documents.md +5 -0
  7. package/docs/examples/databases/update-float-attribute.md +2 -2
  8. package/docs/examples/databases/update-integer-attribute.md +2 -2
  9. package/docs/examples/databases/upsert-document.md +6 -0
  10. package/docs/examples/databases/upsert-documents.md +4 -0
  11. package/docs/examples/functions/{create-build.md → create-duplicate-deployment.md} +1 -1
  12. package/docs/examples/functions/create-template-deployment.md +7 -0
  13. package/docs/examples/functions/create-variable.md +2 -1
  14. package/docs/examples/functions/create-vcs-deployment.md +5 -0
  15. package/docs/examples/functions/create.md +0 -4
  16. package/docs/examples/functions/get-deployment-download.md +2 -1
  17. package/docs/examples/functions/get-usage.md +1 -0
  18. package/docs/examples/functions/list-executions.md +0 -1
  19. package/docs/examples/functions/list-usage.md +2 -0
  20. package/docs/examples/functions/{update-deployment-build.md → update-deployment-status.md} +1 -1
  21. package/docs/examples/functions/{update-deployment.md → update-function-deployment.md} +1 -1
  22. package/docs/examples/functions/update-variable.md +1 -0
  23. package/docs/examples/health/get-queue-stats-resources.md +2 -0
  24. package/docs/examples/migrations/create-csv-migration.md +4 -0
  25. package/docs/examples/project/create-variable.md +2 -1
  26. package/docs/examples/project/update-variable.md +1 -0
  27. package/docs/examples/projects/create-dev-key.md +4 -0
  28. package/docs/examples/projects/delete-dev-key.md +3 -0
  29. package/docs/examples/projects/get-dev-key.md +3 -0
  30. package/docs/examples/projects/list-dev-keys.md +3 -0
  31. package/docs/examples/projects/update-dev-key.md +5 -0
  32. package/docs/examples/proxy/create-a-p-i-rule.md +2 -0
  33. package/docs/examples/proxy/create-function-rule.md +4 -0
  34. package/docs/examples/proxy/create-redirect-rule.md +4 -0
  35. package/docs/examples/proxy/create-site-rule.md +4 -0
  36. package/docs/examples/sites/create-deployment.md +7 -0
  37. package/docs/examples/sites/create-duplicate-deployment.md +3 -0
  38. package/docs/examples/sites/create-template-deployment.md +7 -0
  39. package/docs/examples/sites/create-variable.md +5 -0
  40. package/docs/examples/sites/create-vcs-deployment.md +5 -0
  41. package/docs/examples/sites/create.md +19 -0
  42. package/docs/examples/sites/delete-deployment.md +3 -0
  43. package/docs/examples/sites/delete-log.md +3 -0
  44. package/docs/examples/sites/delete-variable.md +3 -0
  45. package/docs/examples/sites/delete.md +2 -0
  46. package/docs/examples/sites/get-deployment-download.md +4 -0
  47. package/docs/examples/sites/get-deployment.md +3 -0
  48. package/docs/examples/sites/get-log.md +3 -0
  49. package/docs/examples/sites/get-template.md +2 -0
  50. package/docs/examples/sites/get-usage.md +3 -0
  51. package/docs/examples/sites/get-variable.md +3 -0
  52. package/docs/examples/sites/get.md +2 -0
  53. package/docs/examples/sites/list-deployments.md +4 -0
  54. package/docs/examples/sites/list-frameworks.md +1 -0
  55. package/docs/examples/sites/list-logs.md +3 -0
  56. package/docs/examples/sites/list-specifications.md +1 -0
  57. package/docs/examples/sites/list-templates.md +5 -0
  58. package/docs/examples/sites/list-usage.md +2 -0
  59. package/docs/examples/sites/list-variables.md +2 -0
  60. package/docs/examples/sites/list.md +3 -0
  61. package/docs/examples/sites/update-deployment-status.md +3 -0
  62. package/docs/examples/sites/update-site-deployment.md +3 -0
  63. package/docs/examples/sites/update-variable.md +6 -0
  64. package/docs/examples/sites/update.md +19 -0
  65. package/docs/examples/storage/get-file-download.md +2 -1
  66. package/docs/examples/storage/get-file-preview.md +1 -0
  67. package/docs/examples/storage/get-file-view.md +2 -1
  68. package/docs/examples/tokens/create-file-token.md +4 -0
  69. package/docs/examples/tokens/delete.md +2 -0
  70. package/docs/examples/tokens/get.md +2 -0
  71. package/docs/examples/tokens/list.md +4 -0
  72. package/docs/examples/tokens/update.md +3 -0
  73. package/docs/examples/users/list-memberships.md +3 -1
  74. package/docs/examples/vcs/create-repository-detection.md +1 -0
  75. package/docs/examples/vcs/list-repositories.md +1 -0
  76. package/index.js +4 -0
  77. package/install.ps1 +2 -2
  78. package/install.sh +1 -1
  79. package/lib/client.js +12 -5
  80. package/lib/commands/account.js +7 -17
  81. package/lib/commands/avatars.js +9 -16
  82. package/lib/commands/console.js +50 -1
  83. package/lib/commands/databases.js +294 -62
  84. package/lib/commands/functions.js +244 -146
  85. package/lib/commands/generic.js +1 -1
  86. package/lib/commands/health.js +15 -73
  87. package/lib/commands/init.js +191 -0
  88. package/lib/commands/locale.js +0 -8
  89. package/lib/commands/messaging.js +38 -51
  90. package/lib/commands/migrations.js +56 -11
  91. package/lib/commands/project.js +12 -5
  92. package/lib/commands/projects.js +246 -27
  93. package/lib/commands/proxy.js +160 -19
  94. package/lib/commands/pull.js +124 -1
  95. package/lib/commands/push.js +338 -5
  96. package/lib/commands/sites.js +1663 -0
  97. package/lib/commands/storage.js +28 -22
  98. package/lib/commands/teams.js +2 -8
  99. package/lib/commands/tokens.js +261 -0
  100. package/lib/commands/users.js +15 -17
  101. package/lib/commands/vcs.js +60 -53
  102. package/lib/config.js +50 -0
  103. package/lib/parser.js +2 -1
  104. package/lib/questions.js +110 -1
  105. package/lib/utils.js +7 -1
  106. package/package.json +1 -1
  107. package/scoop/appwrite.json +3 -3
  108. package/docs/examples/functions/get-function-usage.md +0 -3
  109. package/docs/examples/health/get-queue-usage-dump.md +0 -2
  110. package/docs/examples/health/get-queue.md +0 -1
  111. package/docs/examples/proxy/create-rule.md +0 -4
@@ -121,7 +121,7 @@ const whoami = new Command("whoami")
121
121
  sdk: client,
122
122
  parseOutput: false
123
123
  });
124
- } catch (error) {
124
+ } catch (_) {
125
125
  error("No user is signed in. To sign in, run 'appwrite login'");
126
126
  return;
127
127
  }
@@ -58,7 +58,6 @@ const healthGet = async ({parseOutput = true, overrideForCli = false, sdk = unde
58
58
  let response = undefined;
59
59
 
60
60
  response = await client.call('get', apiPath, {
61
- 'content-type': 'application/json',
62
61
  }, payload);
63
62
 
64
63
  if (parseOutput) {
@@ -88,7 +87,6 @@ const healthGetAntivirus = async ({parseOutput = true, overrideForCli = false, s
88
87
  let response = undefined;
89
88
 
90
89
  response = await client.call('get', apiPath, {
91
- 'content-type': 'application/json',
92
90
  }, payload);
93
91
 
94
92
  if (parseOutput) {
@@ -118,7 +116,6 @@ const healthGetCache = async ({parseOutput = true, overrideForCli = false, sdk =
118
116
  let response = undefined;
119
117
 
120
118
  response = await client.call('get', apiPath, {
121
- 'content-type': 'application/json',
122
119
  }, payload);
123
120
 
124
121
  if (parseOutput) {
@@ -152,7 +149,6 @@ const healthGetCertificate = async ({domain,parseOutput = true, overrideForCli =
152
149
  let response = undefined;
153
150
 
154
151
  response = await client.call('get', apiPath, {
155
- 'content-type': 'application/json',
156
152
  }, payload);
157
153
 
158
154
  if (parseOutput) {
@@ -182,7 +178,6 @@ const healthGetDB = async ({parseOutput = true, overrideForCli = false, sdk = un
182
178
  let response = undefined;
183
179
 
184
180
  response = await client.call('get', apiPath, {
185
- 'content-type': 'application/json',
186
181
  }, payload);
187
182
 
188
183
  if (parseOutput) {
@@ -212,37 +207,6 @@ const healthGetPubSub = async ({parseOutput = true, overrideForCli = false, sdk
212
207
  let response = undefined;
213
208
 
214
209
  response = await client.call('get', apiPath, {
215
- 'content-type': 'application/json',
216
- }, payload);
217
-
218
- if (parseOutput) {
219
- parse(response)
220
- }
221
-
222
- return response;
223
-
224
- }
225
-
226
- /**
227
- * @typedef {Object} HealthGetQueueRequestParams
228
- * @property {boolean} overrideForCli
229
- * @property {boolean} parseOutput
230
- * @property {libClient | undefined} sdk
231
- */
232
-
233
- /**
234
- * @param {HealthGetQueueRequestParams} params
235
- */
236
- const healthGetQueue = async ({parseOutput = true, overrideForCli = false, sdk = undefined}) => {
237
- let client = !sdk ? await sdkForProject() :
238
- sdk;
239
- let apiPath = '/health/queue';
240
- let payload = {};
241
-
242
- let response = undefined;
243
-
244
- response = await client.call('get', apiPath, {
245
- 'content-type': 'application/json',
246
210
  }, payload);
247
211
 
248
212
  if (parseOutput) {
@@ -276,7 +240,6 @@ const healthGetQueueBuilds = async ({threshold,parseOutput = true, overrideForCl
276
240
  let response = undefined;
277
241
 
278
242
  response = await client.call('get', apiPath, {
279
- 'content-type': 'application/json',
280
243
  }, payload);
281
244
 
282
245
  if (parseOutput) {
@@ -310,7 +273,6 @@ const healthGetQueueCertificates = async ({threshold,parseOutput = true, overrid
310
273
  let response = undefined;
311
274
 
312
275
  response = await client.call('get', apiPath, {
313
- 'content-type': 'application/json',
314
276
  }, payload);
315
277
 
316
278
  if (parseOutput) {
@@ -348,7 +310,6 @@ const healthGetQueueDatabases = async ({name,threshold,parseOutput = true, overr
348
310
  let response = undefined;
349
311
 
350
312
  response = await client.call('get', apiPath, {
351
- 'content-type': 'application/json',
352
313
  }, payload);
353
314
 
354
315
  if (parseOutput) {
@@ -382,7 +343,6 @@ const healthGetQueueDeletes = async ({threshold,parseOutput = true, overrideForC
382
343
  let response = undefined;
383
344
 
384
345
  response = await client.call('get', apiPath, {
385
- 'content-type': 'application/json',
386
346
  }, payload);
387
347
 
388
348
  if (parseOutput) {
@@ -417,7 +377,6 @@ const healthGetFailedJobs = async ({name,threshold,parseOutput = true, overrideF
417
377
  let response = undefined;
418
378
 
419
379
  response = await client.call('get', apiPath, {
420
- 'content-type': 'application/json',
421
380
  }, payload);
422
381
 
423
382
  if (parseOutput) {
@@ -451,7 +410,6 @@ const healthGetQueueFunctions = async ({threshold,parseOutput = true, overrideFo
451
410
  let response = undefined;
452
411
 
453
412
  response = await client.call('get', apiPath, {
454
- 'content-type': 'application/json',
455
413
  }, payload);
456
414
 
457
415
  if (parseOutput) {
@@ -485,7 +443,6 @@ const healthGetQueueLogs = async ({threshold,parseOutput = true, overrideForCli
485
443
  let response = undefined;
486
444
 
487
445
  response = await client.call('get', apiPath, {
488
- 'content-type': 'application/json',
489
446
  }, payload);
490
447
 
491
448
  if (parseOutput) {
@@ -519,7 +476,6 @@ const healthGetQueueMails = async ({threshold,parseOutput = true, overrideForCli
519
476
  let response = undefined;
520
477
 
521
478
  response = await client.call('get', apiPath, {
522
- 'content-type': 'application/json',
523
479
  }, payload);
524
480
 
525
481
  if (parseOutput) {
@@ -553,7 +509,6 @@ const healthGetQueueMessaging = async ({threshold,parseOutput = true, overrideFo
553
509
  let response = undefined;
554
510
 
555
511
  response = await client.call('get', apiPath, {
556
- 'content-type': 'application/json',
557
512
  }, payload);
558
513
 
559
514
  if (parseOutput) {
@@ -587,7 +542,6 @@ const healthGetQueueMigrations = async ({threshold,parseOutput = true, overrideF
587
542
  let response = undefined;
588
543
 
589
544
  response = await client.call('get', apiPath, {
590
- 'content-type': 'application/json',
591
545
  }, payload);
592
546
 
593
547
  if (parseOutput) {
@@ -599,7 +553,7 @@ const healthGetQueueMigrations = async ({threshold,parseOutput = true, overrideF
599
553
  }
600
554
 
601
555
  /**
602
- * @typedef {Object} HealthGetQueueUsageRequestParams
556
+ * @typedef {Object} HealthGetQueueStatsResourcesRequestParams
603
557
  * @property {number} threshold Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.
604
558
  * @property {boolean} overrideForCli
605
559
  * @property {boolean} parseOutput
@@ -607,12 +561,12 @@ const healthGetQueueMigrations = async ({threshold,parseOutput = true, overrideF
607
561
  */
608
562
 
609
563
  /**
610
- * @param {HealthGetQueueUsageRequestParams} params
564
+ * @param {HealthGetQueueStatsResourcesRequestParams} params
611
565
  */
612
- const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}) => {
566
+ const healthGetQueueStatsResources = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}) => {
613
567
  let client = !sdk ? await sdkForProject() :
614
568
  sdk;
615
- let apiPath = '/health/queue/usage';
569
+ let apiPath = '/health/queue/stats-resources';
616
570
  let payload = {};
617
571
  if (typeof threshold !== 'undefined') {
618
572
  payload['threshold'] = threshold;
@@ -621,7 +575,6 @@ const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli
621
575
  let response = undefined;
622
576
 
623
577
  response = await client.call('get', apiPath, {
624
- 'content-type': 'application/json',
625
578
  }, payload);
626
579
 
627
580
  if (parseOutput) {
@@ -633,7 +586,7 @@ const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli
633
586
  }
634
587
 
635
588
  /**
636
- * @typedef {Object} HealthGetQueueUsageDumpRequestParams
589
+ * @typedef {Object} HealthGetQueueUsageRequestParams
637
590
  * @property {number} threshold Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.
638
591
  * @property {boolean} overrideForCli
639
592
  * @property {boolean} parseOutput
@@ -641,12 +594,12 @@ const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli
641
594
  */
642
595
 
643
596
  /**
644
- * @param {HealthGetQueueUsageDumpRequestParams} params
597
+ * @param {HealthGetQueueUsageRequestParams} params
645
598
  */
646
- const healthGetQueueUsageDump = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}) => {
599
+ const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}) => {
647
600
  let client = !sdk ? await sdkForProject() :
648
601
  sdk;
649
- let apiPath = '/health/queue/usage-dump';
602
+ let apiPath = '/health/queue/stats-usage';
650
603
  let payload = {};
651
604
  if (typeof threshold !== 'undefined') {
652
605
  payload['threshold'] = threshold;
@@ -655,7 +608,6 @@ const healthGetQueueUsageDump = async ({threshold,parseOutput = true, overrideFo
655
608
  let response = undefined;
656
609
 
657
610
  response = await client.call('get', apiPath, {
658
- 'content-type': 'application/json',
659
611
  }, payload);
660
612
 
661
613
  if (parseOutput) {
@@ -689,7 +641,6 @@ const healthGetQueueWebhooks = async ({threshold,parseOutput = true, overrideFor
689
641
  let response = undefined;
690
642
 
691
643
  response = await client.call('get', apiPath, {
692
- 'content-type': 'application/json',
693
644
  }, payload);
694
645
 
695
646
  if (parseOutput) {
@@ -719,7 +670,6 @@ const healthGetStorage = async ({parseOutput = true, overrideForCli = false, sdk
719
670
  let response = undefined;
720
671
 
721
672
  response = await client.call('get', apiPath, {
722
- 'content-type': 'application/json',
723
673
  }, payload);
724
674
 
725
675
  if (parseOutput) {
@@ -749,7 +699,6 @@ const healthGetStorageLocal = async ({parseOutput = true, overrideForCli = false
749
699
  let response = undefined;
750
700
 
751
701
  response = await client.call('get', apiPath, {
752
- 'content-type': 'application/json',
753
702
  }, payload);
754
703
 
755
704
  if (parseOutput) {
@@ -779,7 +728,6 @@ const healthGetTime = async ({parseOutput = true, overrideForCli = false, sdk =
779
728
  let response = undefined;
780
729
 
781
730
  response = await client.call('get', apiPath, {
782
- 'content-type': 'application/json',
783
731
  }, payload);
784
732
 
785
733
  if (parseOutput) {
@@ -821,11 +769,6 @@ health
821
769
  .description(`Check the Appwrite pub-sub servers are up and connection is successful.`)
822
770
  .action(actionRunner(healthGetPubSub))
823
771
 
824
- health
825
- .command(`get-queue`)
826
- .description(`Check the Appwrite queue messaging servers are up and connection is successful.`)
827
- .action(actionRunner(healthGetQueue))
828
-
829
772
  health
830
773
  .command(`get-queue-builds`)
831
774
  .description(`Get the number of builds that are waiting to be processed in the Appwrite internal queue server.`)
@@ -889,16 +832,16 @@ health
889
832
  .action(actionRunner(healthGetQueueMigrations))
890
833
 
891
834
  health
892
- .command(`get-queue-usage`)
893
- .description(`Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.`)
835
+ .command(`get-queue-stats-resources`)
836
+ .description(`Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.`)
894
837
  .option(`--threshold <threshold>`, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger)
895
- .action(actionRunner(healthGetQueueUsage))
838
+ .action(actionRunner(healthGetQueueStatsResources))
896
839
 
897
840
  health
898
- .command(`get-queue-usage-dump`)
899
- .description(`Get the number of projects containing metrics that are waiting to be processed in the Appwrite internal queue server.`)
841
+ .command(`get-queue-usage`)
842
+ .description(`Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.`)
900
843
  .option(`--threshold <threshold>`, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger)
901
- .action(actionRunner(healthGetQueueUsageDump))
844
+ .action(actionRunner(healthGetQueueUsage))
902
845
 
903
846
  health
904
847
  .command(`get-queue-webhooks`)
@@ -929,7 +872,6 @@ module.exports = {
929
872
  healthGetCertificate,
930
873
  healthGetDB,
931
874
  healthGetPubSub,
932
- healthGetQueue,
933
875
  healthGetQueueBuilds,
934
876
  healthGetQueueCertificates,
935
877
  healthGetQueueDatabases,
@@ -940,8 +882,8 @@ module.exports = {
940
882
  healthGetQueueMails,
941
883
  healthGetQueueMessaging,
942
884
  healthGetQueueMigrations,
885
+ healthGetQueueStatsResources,
943
886
  healthGetQueueUsage,
944
- healthGetQueueUsageDump,
945
887
  healthGetQueueWebhooks,
946
888
  healthGetStorage,
947
889
  healthGetStorageLocal,
@@ -15,6 +15,7 @@ const { localConfig, globalConfig } = require("../config");
15
15
  const {
16
16
  questionsCreateFunction,
17
17
  questionsCreateFunctionSelectTemplate,
18
+ questionsCreateSite,
18
19
  questionsCreateBucket,
19
20
  questionsCreateMessagingTopic,
20
21
  questionsCreateCollection,
@@ -25,11 +26,13 @@ const {
25
26
  } = require("../questions");
26
27
  const { cliConfig, success, log, hint, error, actionRunner, commandDescriptions } = require("../parser");
27
28
  const { accountGet } = require("./account");
29
+ const { sitesListTemplates } = require("./sites");
28
30
  const { sdkForConsole } = require("../sdks");
29
31
 
30
32
  const initResources = async () => {
31
33
  const actions = {
32
34
  function: initFunction,
35
+ site: initSite,
33
36
  collection: initCollection,
34
37
  bucket: initBucket,
35
38
  team: initTeam,
@@ -318,6 +321,188 @@ const initFunction = async () => {
318
321
  log("Next you can use 'appwrite run function' to develop a function locally. To deploy the function, use 'appwrite push function'");
319
322
  }
320
323
 
324
+ const initSite = async () => {
325
+ process.chdir(localConfig.configDirectoryPath)
326
+
327
+ const answers = await inquirer.prompt(questionsCreateSite);
328
+ const siteFolder = path.join(process.cwd(), 'sites');
329
+
330
+ if (!fs.existsSync(siteFolder)) {
331
+ fs.mkdirSync(siteFolder, {
332
+ recursive: true
333
+ });
334
+ }
335
+
336
+ const siteId = answers.id === 'unique()' ? ID.unique() : answers.id;
337
+ const siteName = answers.name;
338
+ const siteDir = path.join(siteFolder, siteName);
339
+ const templatesDir = path.join(siteFolder, `${siteId}-templates`);
340
+
341
+ if (fs.existsSync(siteDir)) {
342
+ throw new Error(`( ${siteName} ) already exists in the current directory. Please choose another name.`);
343
+ }
344
+
345
+ let templateDetails;
346
+ try {
347
+ const response = await sitesListTemplates({
348
+ frameworks: [answers.framework.key],
349
+ useCases: ['starter'],
350
+ limit: 1,
351
+ parseOutput: false
352
+ });
353
+ if (response.total == 0) {
354
+ throw new Error(`No starter template found for framework ${answers.framework.key}`);
355
+ }
356
+ templateDetails = response.templates[0];
357
+ } catch (error) {
358
+ throw new Error(`Failed to fetch template for framework ${answers.framework.key}: ${error.message}`);
359
+ }
360
+
361
+ fs.mkdirSync(siteDir, "777");
362
+ fs.mkdirSync(templatesDir, "777");
363
+ const repo = `https://github.com/${templateDetails.providerOwner}/${templateDetails.providerRepositoryId}`;
364
+ let selected = { template: templateDetails.frameworks[0].providerRootDirectory };
365
+
366
+ let gitCloneCommands = '';
367
+
368
+ const sparse = selected.template.startsWith('./') ? selected.template.substring(2) : selected.template;
369
+
370
+ log('Fetching site code ...');
371
+
372
+ if(selected.template === './') {
373
+ gitCloneCommands = `
374
+ mkdir -p .
375
+ cd .
376
+ git init
377
+ git remote add origin ${repo}
378
+ git config --global init.defaultBranch main
379
+ git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
380
+ git checkout FETCH_HEAD
381
+ `.trim();
382
+ } else {
383
+ gitCloneCommands = `
384
+ mkdir -p .
385
+ cd .
386
+ git init
387
+ git remote add origin ${repo}
388
+ git config --global init.defaultBranch main
389
+ git config core.sparseCheckout true
390
+ echo "${sparse}" >> .git/info/sparse-checkout
391
+ git config --add remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
392
+ git config remote.origin.tagopt --no-tags
393
+ git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
394
+ git checkout FETCH_HEAD
395
+ `.trim();
396
+ }
397
+
398
+ /* Force use CMD as powershell does not support && */
399
+ if (process.platform === 'win32') {
400
+ gitCloneCommands = 'cmd /c "' + gitCloneCommands + '"';
401
+ }
402
+
403
+ /* Execute the child process but do not print any std output */
404
+ try {
405
+ childProcess.execSync(gitCloneCommands, { stdio: 'pipe', cwd: templatesDir });
406
+ } catch (error) {
407
+ /* Specialised errors with recommended actions to take */
408
+ if (error.message.includes('error: unknown option')) {
409
+ throw new Error(`${error.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`)
410
+ } else if (error.message.includes('is not recognized as an internal or external command,') || error.message.includes('command not found')) {
411
+ throw new Error(`${error.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`)
412
+ } else {
413
+ throw error;
414
+ }
415
+ }
416
+
417
+ fs.rmSync(path.join(templatesDir, ".git"), { recursive: true });
418
+
419
+ const copyRecursiveSync = (src, dest) => {
420
+ let exists = fs.existsSync(src);
421
+ let stats = exists && fs.statSync(src);
422
+ let isDirectory = exists && stats.isDirectory();
423
+ if (isDirectory) {
424
+ if (!fs.existsSync(dest)) {
425
+ fs.mkdirSync(dest);
426
+ }
427
+
428
+ fs.readdirSync(src).forEach(function (childItemName) {
429
+ copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
430
+ });
431
+ } else {
432
+ fs.copyFileSync(src, dest);
433
+ }
434
+ };
435
+ copyRecursiveSync(selected.template === './' ? templatesDir : path.join(templatesDir, selected.template), siteDir);
436
+
437
+ fs.rmSync(templatesDir, { recursive: true, force: true });
438
+
439
+ const readmePath = path.join(process.cwd(), 'sites', siteName, 'README.md');
440
+ const readmeFile = fs.readFileSync(readmePath).toString();
441
+ const newReadmeFile = readmeFile.split('\n');
442
+ newReadmeFile[0] = `# ${answers.key}`;
443
+ newReadmeFile.splice(1, 2);
444
+ fs.writeFileSync(readmePath, newReadmeFile.join('\n'));
445
+
446
+ let vars = (templateDetails.variables ?? []).map(variable => {
447
+ let value = variable.value;
448
+ const replacements = {
449
+ '{apiEndpoint}': globalConfig.getEndpoint(),
450
+ '{projectId}': localConfig.getProject().projectId,
451
+ '{projectName}': localConfig.getProject().projectName,
452
+ };
453
+
454
+ for (const placeholder in replacements) {
455
+ if (value?.includes(placeholder)) {
456
+ value = value.replace(placeholder, replacements[placeholder]);
457
+ }
458
+ }
459
+
460
+ return {
461
+ key: variable.name,
462
+ value: value
463
+ };
464
+ });
465
+
466
+ let data = {
467
+ $id: siteId,
468
+ name: answers.name,
469
+ framework: answers.framework.key,
470
+ adapter: templateDetails.frameworks[0].adapter || '',
471
+ buildRuntime: templateDetails.frameworks[0].buildRuntime || '',
472
+ installCommand: templateDetails.frameworks[0].installCommand || '',
473
+ buildCommand: templateDetails.frameworks[0].buildCommand || '',
474
+ outputDirectory: templateDetails.frameworks[0].outputDirectory || '',
475
+ fallbackFile: templateDetails.frameworks[0].fallbackFile || '',
476
+ specification: answers.specification,
477
+ enabled: true,
478
+ timeout: 30,
479
+ logging: true,
480
+ ignore: answers.framework.ignore || null,
481
+ path: `sites/${siteName}`,
482
+ vars: vars
483
+ };
484
+
485
+ if (!data.buildRuntime) {
486
+ log(`Build runtime for this framework not found. You will be asked to configure build runtime when you first push the site.`);
487
+ }
488
+
489
+ if (!data.installCommand) {
490
+ log(`Installation command for this framework not found. You will be asked to configure the install command when you first push the site.`);
491
+ }
492
+
493
+ if (!data.buildCommand) {
494
+ log(`Build command for this framework not found. You will be asked to configure the build command when you first push the site.`);
495
+ }
496
+
497
+ if (!data.outputDirectory) {
498
+ log(`Output directory for this framework not found. You will be asked to configure the output directory when you first push the site.`);
499
+ }
500
+
501
+ localConfig.addSite(data);
502
+ success("Initializing site");
503
+ log("Next you can use 'appwrite push site' to deploy the changes.");
504
+ };
505
+
321
506
  const init = new Command("init")
322
507
  .description(commandDescriptions['init'])
323
508
  .action(actionRunner(initResources));
@@ -336,6 +521,12 @@ init
336
521
  .description("Init a new Appwrite function")
337
522
  .action(actionRunner(initFunction));
338
523
 
524
+ init
525
+ .command("site")
526
+ .alias("sites")
527
+ .description("Init a new Appwrite site")
528
+ .action(actionRunner(initSite));
529
+
339
530
  init
340
531
  .command("bucket")
341
532
  .alias("buckets")
@@ -58,7 +58,6 @@ const localeGet = async ({parseOutput = true, overrideForCli = false, sdk = unde
58
58
  let response = undefined;
59
59
 
60
60
  response = await client.call('get', apiPath, {
61
- 'content-type': 'application/json',
62
61
  }, payload);
63
62
 
64
63
  if (parseOutput) {
@@ -88,7 +87,6 @@ const localeListCodes = async ({parseOutput = true, overrideForCli = false, sdk
88
87
  let response = undefined;
89
88
 
90
89
  response = await client.call('get', apiPath, {
91
- 'content-type': 'application/json',
92
90
  }, payload);
93
91
 
94
92
  if (parseOutput) {
@@ -118,7 +116,6 @@ const localeListContinents = async ({parseOutput = true, overrideForCli = false,
118
116
  let response = undefined;
119
117
 
120
118
  response = await client.call('get', apiPath, {
121
- 'content-type': 'application/json',
122
119
  }, payload);
123
120
 
124
121
  if (parseOutput) {
@@ -148,7 +145,6 @@ const localeListCountries = async ({parseOutput = true, overrideForCli = false,
148
145
  let response = undefined;
149
146
 
150
147
  response = await client.call('get', apiPath, {
151
- 'content-type': 'application/json',
152
148
  }, payload);
153
149
 
154
150
  if (parseOutput) {
@@ -178,7 +174,6 @@ const localeListCountriesEU = async ({parseOutput = true, overrideForCli = false
178
174
  let response = undefined;
179
175
 
180
176
  response = await client.call('get', apiPath, {
181
- 'content-type': 'application/json',
182
177
  }, payload);
183
178
 
184
179
  if (parseOutput) {
@@ -208,7 +203,6 @@ const localeListCountriesPhones = async ({parseOutput = true, overrideForCli = f
208
203
  let response = undefined;
209
204
 
210
205
  response = await client.call('get', apiPath, {
211
- 'content-type': 'application/json',
212
206
  }, payload);
213
207
 
214
208
  if (parseOutput) {
@@ -238,7 +232,6 @@ const localeListCurrencies = async ({parseOutput = true, overrideForCli = false,
238
232
  let response = undefined;
239
233
 
240
234
  response = await client.call('get', apiPath, {
241
- 'content-type': 'application/json',
242
235
  }, payload);
243
236
 
244
237
  if (parseOutput) {
@@ -268,7 +261,6 @@ const localeListLanguages = async ({parseOutput = true, overrideForCli = false,
268
261
  let response = undefined;
269
262
 
270
263
  response = await client.call('get', apiPath, {
271
- 'content-type': 'application/json',
272
264
  }, payload);
273
265
 
274
266
  if (parseOutput) {