appwrite-cli 8.0.2 → 8.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,70 @@
1
+ # Change Log
2
+
3
+ ## 8.1.1
4
+
5
+ * Fix circular dependency issue due to usage of `success` method in `utils.js` file from `parser.js` file
6
+ * Type generation fixes:
7
+ * Add ability to generate types directly to a specific file by passing a file path to `appwrite types output_path`, instead of just a directory
8
+ * Fix non-required attributes to not be null if default value is provided
9
+ * Fix `Models` import error
10
+ * Improve formatting and add auto-generated comments
11
+
12
+ ## 8.1.0
13
+
14
+ * Add multi-region support to `init` command
15
+ * Update `init` command to clear previous configuration in `appwrite.json`
16
+ * Update localConfig to store multi-region endpoint
17
+ * Fix throw error when creating unknown attribute instead of timing out
18
+ * Fix equal comparison of large numbers and BigNumber instances using proper equality checks
19
+ * Fix duplication of reasons when comparing localConfig with remoteConfig
20
+ * Fix `firstOrNull()` to `firstOrNull` in types generation for dart
21
+ * Refactor to use `isCloud()` method consistently
22
+
23
+ ## 8.0.2
24
+
25
+ * Add Type generation fixes:
26
+ * Properly handle enum attributes in dart, java and kotlin
27
+ * Fix initialisation of null attributes in dart's fromMap method
28
+ * Fix relationships and enums in swift
29
+
30
+ ## 8.0.1
31
+
32
+ * Add `resourceId` and `resourceType` attributes to `createRedirectRule`
33
+ * Add `providerReference` to vcs command for getting repository contents
34
+ * Add warning comment to `bulk updateDocuments` method
35
+ * Fix type generation for enums in Typescript and PHP language
36
+
37
+ ## 8.0.0
38
+
39
+ * Add `types` command to generate language specific typings for collections. Currently supports - `php`, `swift`, `dart`, `js`, `ts`, `kotlin` and `java`
40
+ * Update bulk operation docs to include experiment feature warnings
41
+ * Remove assistant service and commands
42
+
43
+ ## 7.0.0
44
+
45
+ * Add `sites` command
46
+ * Add `tokens` command
47
+ * Add `devKeys` support to `projects` command
48
+ * Add `init site`, `pull site` and `push site` commands
49
+ * Add bulk operation methods like `createDocuments`, `deleteDocuments` etc.
50
+ * Add new upsert methods: `upsertDocument` and `upsertDocuments`
51
+ * Update GET requests to not include content-type header
52
+
53
+ ## 6.2.3
54
+
55
+ * Fix hot swapping error in `python-ml` function
56
+
57
+ ## 6.2.2
58
+
59
+ * Fix GitHub builds by adding `qemu-system` package
60
+ * Fix attribute creation timed out
61
+
62
+ ## 6.2.1
63
+
64
+ * Add `listOrganizations` method to `organizations` service and fix init project command
65
+
66
+ ## 6.2.0
67
+
68
+ * Add specifications support to CLI
69
+ * Update package version
70
+ * Fix: Missed specifications param when updating a function
package/README.md CHANGED
@@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using
29
29
 
30
30
  ```sh
31
31
  $ appwrite -v
32
- 8.0.2
32
+ 8.1.1
33
33
  ```
34
34
 
35
35
  ### Install using prebuilt binaries
@@ -60,7 +60,7 @@ $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/sc
60
60
  Once the installation completes, you can verify your install using
61
61
  ```
62
62
  $ appwrite -v
63
- 8.0.2
63
+ 8.1.1
64
64
  ```
65
65
 
66
66
  ## Getting Started
package/install.ps1 CHANGED
@@ -13,8 +13,8 @@
13
13
  # You can use "View source" of this page to see the full script.
14
14
 
15
15
  # REPO
16
- $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.2/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.2/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.1.1/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.1.1/appwrite-cli-win-arm64.exe"
18
18
 
19
19
  $APPWRITE_BINARY_NAME = "appwrite.exe"
20
20
 
package/install.sh CHANGED
@@ -97,7 +97,7 @@ printSuccess() {
97
97
  downloadBinary() {
98
98
  echo "[2/4] Downloading executable for $OS ($ARCH) ..."
99
99
 
100
- GITHUB_LATEST_VERSION="8.0.2"
100
+ GITHUB_LATEST_VERSION="8.1.1"
101
101
  GITHUB_FILE="appwrite-cli-${OS}-${ARCH}"
102
102
  GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE"
103
103
 
package/lib/client.js CHANGED
@@ -16,8 +16,8 @@ class Client {
16
16
  'x-sdk-name': 'Command Line',
17
17
  'x-sdk-platform': 'console',
18
18
  'x-sdk-language': 'cli',
19
- 'x-sdk-version': '8.0.2',
20
- 'user-agent' : `AppwriteCLI/8.0.2 (${os.type()} ${os.version()}; ${os.arch()})`,
19
+ 'x-sdk-version': '8.1.1',
20
+ 'user-agent' : `AppwriteCLI/8.1.1 (${os.type()} ${os.version()}; ${os.arch()})`,
21
21
  'X-Appwrite-Response-Format' : '1.7.0',
22
22
  };
23
23
  }
@@ -28,6 +28,7 @@ const { cliConfig, success, log, hint, error, actionRunner, commandDescriptions
28
28
  const { accountGet } = require("./account");
29
29
  const { sitesListTemplates } = require("./sites");
30
30
  const { sdkForConsole } = require("../sdks");
31
+ const { isCloud } = require('../utils');
31
32
 
32
33
  const initResources = async () => {
33
34
  const actions = {
@@ -94,6 +95,9 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
94
95
  }
95
96
  }
96
97
 
98
+ localConfig.clear(); // Clear the config to avoid any conflicts
99
+ const url = new URL("https://cloud.appwrite.io/v1");
100
+
97
101
  if (answers.start === 'new') {
98
102
  response = await projectsCreate({
99
103
  projectId: answers.id,
@@ -103,8 +107,14 @@ const initProject = async ({ organizationId, projectId, projectName } = {}) => {
103
107
  })
104
108
 
105
109
  localConfig.setProject(response['$id']);
110
+ if (answers.region) {
111
+ localConfig.setEndpoint(`https://${answers.region}.${url.host}${url.pathname}`);
112
+ }
106
113
  } else {
107
- localConfig.setProject(answers.project);
114
+ localConfig.setProject(answers.project["$id"]);
115
+ if(isCloud()) {
116
+ localConfig.setEndpoint(`https://${answers.project["region"]}.${url.host}${url.pathname}`);
117
+ }
108
118
  }
109
119
 
110
120
  success(`Project successfully ${answers.start === 'existing' ? 'linked' : 'created'}. Details are now stored in appwrite.json file.`);
@@ -568,6 +568,8 @@ const createAttribute = (databaseId, collectionId, attribute) => {
568
568
  onDelete: attribute.onDelete,
569
569
  parseOutput: false
570
570
  })
571
+ default:
572
+ throw new Error(`Unsupported attribute type: ${attribute.type}`);
571
573
  }
572
574
  }
573
575
 
@@ -685,6 +687,8 @@ const updateAttribute = (databaseId, collectionId, attribute) => {
685
687
  onDelete: attribute.onDelete,
686
688
  parseOutput: false
687
689
  })
690
+ default:
691
+ throw new Error(`Unsupported attribute type: ${attribute.type}`);
688
692
  }
689
693
  }
690
694
  const deleteAttribute = async (collection, attribute, isIndex = false) => {
@@ -708,6 +712,33 @@ const deleteAttribute = async (collection, attribute, isIndex = false) => {
708
712
  });
709
713
  }
710
714
 
715
+ const isEqual = (a, b) => {
716
+ if (a === b) return true;
717
+
718
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
719
+ if (a.constructor && a.constructor.name === 'BigNumber' &&
720
+ b.constructor && b.constructor.name === 'BigNumber') {
721
+ return a.eq(b);
722
+ }
723
+
724
+ if (typeof a.equals === 'function') {
725
+ return a.equals(b);
726
+ }
727
+
728
+ if (typeof a.eq === 'function') {
729
+ return a.eq(b);
730
+ }
731
+ }
732
+
733
+ if (typeof a === 'number' && typeof b === 'number') {
734
+ if (isNaN(a) && isNaN(b)) return true;
735
+ if (!isFinite(a) && !isFinite(b)) return a === b;
736
+ return Math.abs(a - b) < Number.EPSILON;
737
+ }
738
+
739
+ return false;
740
+ };
741
+
711
742
  const compareAttribute = (remote, local, reason, key) => {
712
743
  if (isEmpty(remote) && isEmpty(local)) {
713
744
  return reason;
@@ -718,7 +749,7 @@ const compareAttribute = (remote, local, reason, key) => {
718
749
  const bol = reason === '' ? '' : '\n';
719
750
  reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
720
751
  }
721
- } else if (remote !== local) {
752
+ } else if (!isEqual(remote, local)) {
722
753
  const bol = reason === '' ? '' : '\n';
723
754
  reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`;
724
755
  }
@@ -733,16 +764,16 @@ const compareAttribute = (remote, local, reason, key) => {
733
764
  * @param remote
734
765
  * @param local
735
766
  * @param collection
736
- * @param recraeting when true will check only non-changeable keys
767
+ * @param recreating when true will check only non-changeable keys
737
768
  * @returns {undefined|{reason: string, action: *, attribute, key: string}}
738
769
  */
739
- const checkAttributeChanges = (remote, local, collection, recraeting = true) => {
770
+ const checkAttributeChanges = (remote, local, collection, recreating = true) => {
740
771
  if (local === undefined) {
741
772
  return undefined;
742
773
  }
743
774
 
744
775
  const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection['$id']})`;
745
- const action = chalk.cyan(recraeting ? 'recreating' : 'changing');
776
+ const action = chalk.cyan(recreating ? 'recreating' : 'changing');
746
777
  let reason = '';
747
778
  let attribute = remote;
748
779
 
@@ -752,17 +783,17 @@ const checkAttributeChanges = (remote, local, collection, recraeting = true) =>
752
783
  }
753
784
 
754
785
  if (changeableKeys.includes(key)) {
755
- if (!recraeting) {
756
- reason += compareAttribute(remote[key], local[key], reason, key)
786
+ if (!recreating) {
787
+ reason = compareAttribute(remote[key], local[key], reason, key)
757
788
  }
758
789
  continue;
759
790
  }
760
791
 
761
- if (!recraeting) {
792
+ if (!recreating) {
762
793
  continue;
763
794
  }
764
795
 
765
- reason += compareAttribute(remote[key], local[key], reason, key)
796
+ reason = compareAttribute(remote[key], local[key], reason, key)
766
797
  }
767
798
 
768
799
  return reason === '' ? undefined : { key: keyName, attribute, reason, action };
@@ -66,7 +66,22 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
66
66
 
67
67
  const meta = createLanguageMeta(language);
68
68
 
69
- const outputDirectory = path.resolve(rawOutputDirectory);
69
+ const rawOutputPath = rawOutputDirectory;
70
+ const outputExt = path.extname(rawOutputPath);
71
+ const isFileOutput = !!outputExt;
72
+ let outputDirectory = rawOutputPath;
73
+ let singleFileDestination = null;
74
+
75
+ if (isFileOutput) {
76
+ if (meta.isSingleFile()) {
77
+ // Use the file path directly for single file languages
78
+ outputDirectory = path.dirname(rawOutputPath);
79
+ singleFileDestination = rawOutputPath;
80
+ } else {
81
+ throw new Error(`Invalid output path: ${rawOutputPath}. Output path must be a directory for languages that generate multiple files.`);
82
+ }
83
+ }
84
+
70
85
  if (!fs.existsSync(outputDirectory)) {
71
86
  log(`Directory: ${outputDirectory} does not exist, creating...`);
72
87
  fs.mkdirSync(outputDirectory, { recursive: true });
@@ -95,7 +110,7 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
95
110
  getType: meta.getType
96
111
  });
97
112
 
98
- const destination = path.join(outputDirectory, meta.getFileName());
113
+ const destination = singleFileDestination || path.join(outputDirectory, meta.getFileName());
99
114
 
100
115
  fs.writeFileSync(destination, content);
101
116
  log(`Added types to ${destination}`);
package/lib/config.js CHANGED
@@ -150,6 +150,14 @@ class Local extends Config {
150
150
  return _path.dirname(this.path)
151
151
  }
152
152
 
153
+ getEndpoint() {
154
+ return this.get('endpoint') || '';
155
+ }
156
+
157
+ setEndpoint(endpoint) {
158
+ this.set('endpoint', endpoint);
159
+ }
160
+
153
161
  getSites() {
154
162
  if (!this.has("sites")) {
155
163
  return [];
package/lib/parser.js CHANGED
@@ -5,6 +5,7 @@ const { description } = require('../package.json');
5
5
  const { globalConfig } = require("./config.js");
6
6
  const os = require('os');
7
7
  const Client = require("./client");
8
+ const { isCloud } = require("./utils");
8
9
 
9
10
  const cliConfig = {
10
11
  verbose: false,
@@ -111,7 +112,6 @@ const parseError = (err) => {
111
112
  (async () => {
112
113
  let appwriteVersion = 'unknown';
113
114
  const endpoint = globalConfig.getEndpoint();
114
- const isCloud = endpoint.includes('cloud.appwrite.io') ? 'Yes' : 'No';
115
115
 
116
116
  try {
117
117
  const client = new Client().setEndpoint(endpoint);
@@ -120,9 +120,9 @@ const parseError = (err) => {
120
120
  } catch {
121
121
  }
122
122
 
123
- const version = '8.0.2';
123
+ const version = '8.1.1';
124
124
  const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
125
- const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud}`;
125
+ const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`;
126
126
 
127
127
  const stack = '```\n' + err.stack + '\n```';
128
128
 
package/lib/questions.js CHANGED
@@ -11,7 +11,7 @@ const { validateRequired } = require("./validations");
11
11
  const { paginate } = require('./paginate');
12
12
  const { isPortTaken } = require('./utils');
13
13
  const { databasesList } = require('./commands/databases');
14
- const { checkDeployConditions } = require('./utils');
14
+ const { checkDeployConditions, isCloud } = require('./utils');
15
15
  const JSONbig = require("json-bigint")({ storeAsString: false });
16
16
  const { sitesListFrameworks, sitesListSpecifications, sitesList } = require('./commands/sites');
17
17
 
@@ -154,8 +154,7 @@ const questionsInitProject = [
154
154
  message: "Choose your organization",
155
155
  choices: async () => {
156
156
  let client = await sdkForConsole(true);
157
- const hostname = new URL(client.endpoint).hostname;
158
- const { teams } = hostname.endsWith('appwrite.io')
157
+ const { teams } = isCloud()
159
158
  ? await paginate(organizationsList, { parseOutput: false, sdk: client }, 100, 'teams')
160
159
  : await paginate(teamsList, { parseOutput: false, sdk: client }, 100, 'teams');
161
160
 
@@ -203,17 +202,41 @@ const questionsInitProject = [
203
202
  let choices = projects.map((project) => {
204
203
  return {
205
204
  name: `${project.name} (${project['$id']})`,
206
- value: project['$id']
205
+ value: {
206
+ "$id": project['$id'],
207
+ "region": project.region || ''
208
+ }
207
209
  }
208
210
  })
209
211
 
210
- if (choices.length == 0) {
212
+ if (choices.length === 0) {
211
213
  throw new Error("No projects found. Please create a new project.")
212
214
  }
213
215
 
214
216
  return choices;
215
217
  },
216
218
  when: (answer) => answer.start === 'existing'
219
+ },
220
+ {
221
+ type: "list",
222
+ name: "region",
223
+ message: "Select your Appwrite Cloud region",
224
+ choices: async () => {
225
+ let client = await sdkForConsole(true);
226
+ let response = await client.call("GET", "/console/regions");
227
+ let regions = response.regions || [];
228
+ if (!regions.length) {
229
+ throw new Error("No regions found. Please check your network or Appwrite Cloud availability.");
230
+ }
231
+ return regions.filter(region => !region.disabled).map(region => ({
232
+ name: `${region.name} (${region.$id})`,
233
+ value: region.$id
234
+ }));
235
+ },
236
+ when: (answer) => {
237
+ if (answer.start === 'existing') return false;
238
+ return isCloud();
239
+ }
217
240
  }
218
241
  ];
219
242
  const questionsInitProjectAutopull = [
package/lib/sdks.js CHANGED
@@ -23,7 +23,7 @@ const sdkForConsole = async (requiresAuth = true) => {
23
23
 
24
24
  const sdkForProject = async () => {
25
25
  let client = new Client();
26
- let endpoint = globalConfig.getEndpoint();
26
+ let endpoint = localConfig.getEndpoint() || globalConfig.getEndpoint();
27
27
  let project = localConfig.getProject().projectId ? localConfig.getProject().projectId : globalConfig.getProject();
28
28
  let key = globalConfig.getKey();
29
29
  let cookie = globalConfig.getCookie()
@@ -1,7 +1,7 @@
1
1
  const AttributeType = {
2
2
  STRING: "string",
3
3
  INTEGER: "integer",
4
- FLOAT: "float",
4
+ FLOAT: "double",
5
5
  BOOLEAN: "boolean",
6
6
  DATETIME: "datetime",
7
7
  EMAIL: "email",
@@ -41,6 +41,10 @@ class Dart extends LanguageMeta {
41
41
  return type;
42
42
  }
43
43
 
44
+ getCurrentDirectory() {
45
+ return process.cwd();
46
+ }
47
+
44
48
  getTemplate() {
45
49
  return `<% for (const attribute of collection.attributes) { -%>
46
50
  <% if (attribute.type === 'relationship') { -%>
@@ -48,11 +52,16 @@ import '<%- attribute.relatedCollection.toLowerCase() %>.dart';
48
52
 
49
53
  <% } -%>
50
54
  <% } -%>
55
+ /**
56
+ * This file is auto-generated by the Appwrite CLI.
57
+ * You can regenerate it by running \`appwrite types -l dart ${this.getCurrentDirectory()}\`.
58
+ */
59
+
51
60
  <% for (const attribute of collection.attributes) { -%>
52
61
  <% if (attribute.format === 'enum') { -%>
53
62
  enum <%- toPascalCase(attribute.key) %> {
54
- <% for (const element of attribute.elements) { -%>
55
- <%- toSnakeCase(element) %>,
63
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
64
+ <%- toSnakeCase(element) %><% if (index < attribute.elements.length - 1) { %>,<% } %>
56
65
  <% } -%>
57
66
  }
58
67
 
@@ -65,7 +74,7 @@ class <%= toPascalCase(collection.name) %> {
65
74
 
66
75
  <%= toPascalCase(collection.name) %>({
67
76
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
68
- <% if (attribute.required) { %>required <% } %>this.<%= toCamelCase(attribute.key) %>,
77
+ <% if (attribute.required) { %>required <% } %>this.<%= toCamelCase(attribute.key) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
69
78
  <% } -%>
70
79
  });
71
80
 
@@ -78,7 +87,7 @@ class <%= toPascalCase(collection.name) %> {
78
87
  (map['<%= attribute.key %>'] as List<dynamic>?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% if (!attribute.required) { %> ?? []<% } -%>
79
88
  <% } else { -%>
80
89
  <% if (!attribute.required) { -%>
81
- map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull() : null<% } else { -%>
90
+ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull : null<% } else { -%>
82
91
  <%- toPascalCase(attribute.key) %>.values.firstWhere((e) => e.name == map['<%= attribute.key %>'])<% } -%>
83
92
  <% } -%>
84
93
  <% } else { -%>
@@ -114,7 +123,7 @@ map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%>
114
123
  map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.relatedCollection) %>.fromMap(map['<%= attribute.key %>']) : null<% } else { -%>
115
124
  <%- toPascalCase(attribute.relatedCollection) %>.fromMap(map['<%= attribute.key %>'])<% } -%>
116
125
  <% } -%>
117
- <% } -%>,
126
+ <% } -%><% if (index < collection.attributes.length - 1) { %>,<% } %>
118
127
  <% } -%>
119
128
  );
120
129
  }
@@ -136,7 +145,7 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.relatedCollecti
136
145
  <% } -%>
137
146
  <% } else { -%>
138
147
  <%= toCamelCase(attribute.key) -%>
139
- <% } -%>,
148
+ <% } -%><% if (index < collection.attributes.length - 1) { %>,<% } %>
140
149
  <% } -%>
141
150
  };
142
151
  }
@@ -38,9 +38,18 @@ class Java extends LanguageMeta {
38
38
  return type;
39
39
  }
40
40
 
41
+ getCurrentDirectory() {
42
+ return process.cwd();
43
+ }
44
+
41
45
  getTemplate() {
42
46
  return `package io.appwrite.models;
43
47
 
48
+ /**
49
+ * This file is auto-generated by the Appwrite CLI.
50
+ * You can regenerate it by running \`appwrite types -l java ${this.getCurrentDirectory()}\`.
51
+ */
52
+
44
53
  import java.util.*;
45
54
  <% for (const attribute of collection.attributes) { -%>
46
55
  <% if (attribute.type === 'relationship') { -%>
@@ -40,8 +40,8 @@ class JavaScript extends LanguageMeta {
40
40
  if (attribute.array) {
41
41
  type += "[]";
42
42
  }
43
- if (!attribute.required) {
44
- type += "|null|undefined";
43
+ if (!attribute.required && attribute.default === null) {
44
+ type += "|null";
45
45
  }
46
46
  return type;
47
47
  }
@@ -60,11 +60,19 @@ class JavaScript extends LanguageMeta {
60
60
  return "appwrite";
61
61
  }
62
62
 
63
+ getCurrentDirectory() {
64
+ return process.cwd();
65
+ }
66
+
63
67
  getTemplate() {
64
68
  return `/**
65
69
  * @typedef {import('${this._getAppwriteDependency()}').Models.Document} Document
66
70
  */
67
71
 
72
+ /**
73
+ * This file is auto-generated by the Appwrite CLI.
74
+ * You can regenerate it by running \`appwrite types -l js ${this.getCurrentDirectory()}\`.
75
+ */
68
76
  <% for (const collection of collections) { %>
69
77
  /**
70
78
  * @typedef {Object} <%- toPascalCase(collection.name) %>
@@ -72,7 +80,6 @@ class JavaScript extends LanguageMeta {
72
80
  * @property {<%- getType(attribute) %>} <%- toCamelCase(attribute.key) %>
73
81
  <% } -%>
74
82
  */
75
-
76
83
  <% } %>`;
77
84
  }
78
85
 
@@ -35,12 +35,16 @@ class Kotlin extends LanguageMeta {
35
35
  if (attribute.array) {
36
36
  type = "List<" + type + ">";
37
37
  }
38
- if (!attribute.required) {
38
+ if (!attribute.required && attribute.default === null) {
39
39
  type += "?";
40
40
  }
41
41
  return type;
42
42
  }
43
43
 
44
+ getCurrentDirectory() {
45
+ return process.cwd();
46
+ }
47
+
44
48
  getTemplate() {
45
49
  return `package io.appwrite.models
46
50
 
@@ -50,6 +54,11 @@ import <%- toPascalCase(attribute.relatedCollection) %>
50
54
 
51
55
  <% } -%>
52
56
  <% } -%>
57
+ /**
58
+ * This file is auto-generated by the Appwrite CLI.
59
+ * You can regenerate it by running \`appwrite types -l kotlin ${this.getCurrentDirectory()}\`.
60
+ */
61
+
53
62
  <% for (const attribute of collection.attributes) { -%>
54
63
  <% if (attribute.format === 'enum') { -%>
55
64
  enum class <%- toPascalCase(attribute.key) %> {
@@ -61,8 +70,8 @@ enum class <%- toPascalCase(attribute.key) %> {
61
70
  <% } -%>
62
71
  <% } -%>
63
72
  data class <%- toPascalCase(collection.name) %>(
64
- <% for (const attribute of collection.attributes) { -%>
65
- val <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %>,
73
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
74
+ val <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
66
75
  <% } -%>
67
76
  )`;
68
77
  }
@@ -35,16 +35,25 @@ class PHP extends LanguageMeta {
35
35
  default:
36
36
  throw new Error(`Unknown attribute type: ${attribute.type}`);
37
37
  }
38
- if (!attribute.required) {
38
+ if (!attribute.required && attribute.default === null) {
39
39
  type += "|null";
40
40
  }
41
41
  return type;
42
42
  }
43
43
 
44
+ getCurrentDirectory() {
45
+ return process.cwd();
46
+ }
47
+
44
48
  getTemplate() {
45
49
  return `<?php
46
50
  namespace Appwrite\\Models;
47
51
 
52
+ /**
53
+ * This file is auto-generated by the Appwrite CLI.
54
+ * You can regenerate it by running \`appwrite types -l php ${this.getCurrentDirectory()}\`.
55
+ */
56
+
48
57
  <% for (const attribute of collection.attributes) { -%>
49
58
  <% if (attribute.type === 'relationship' && !(attribute.relationType === 'manyToMany') && !(attribute.relationType === 'oneToMany' && attribute.side === 'parent')) { -%>
50
59
  use Appwrite\\Models\\<%- toPascalCase(attribute.relatedCollection) %>;
@@ -35,15 +35,22 @@ class Swift extends LanguageMeta {
35
35
  if (attribute.array) {
36
36
  type = "[" + type + "]";
37
37
  }
38
- if (!attribute.required) {
38
+ if (!attribute.required && attribute.default === null) {
39
39
  type += "?";
40
40
  }
41
41
  return type;
42
42
  }
43
43
 
44
+ getCurrentDirectory() {
45
+ return process.cwd();
46
+ }
47
+
44
48
  getTemplate() {
45
49
  return `import Foundation
46
50
 
51
+ /// This file is auto-generated by the Appwrite CLI.
52
+ /// You can regenerate it by running \`appwrite types -l swift ${this.getCurrentDirectory()}\`.
53
+
47
54
  <% for (const attribute of collection.attributes) { -%>
48
55
  <% if (attribute.format === 'enum') { -%>
49
56
  public enum <%- toPascalCase(attribute.key) %>: String, Codable, CaseIterable {
@@ -40,7 +40,7 @@ class TypeScript extends LanguageMeta {
40
40
  if (attribute.array) {
41
41
  type += "[]";
42
42
  }
43
- if (!attribute.required) {
43
+ if (!attribute.required && attribute.default === null) {
44
44
  type += " | null";
45
45
  }
46
46
  return type;
@@ -64,15 +64,25 @@ class TypeScript extends LanguageMeta {
64
64
  return "appwrite";
65
65
  }
66
66
 
67
+ getCurrentDirectory() {
68
+ return process.cwd();
69
+ }
70
+
67
71
  getTemplate() {
68
- return `import { Models } from '${this._getAppwriteDependency()}';
72
+ return `import { type Models } from '${this._getAppwriteDependency()}';
73
+
74
+ /**
75
+ * This file is auto-generated by the Appwrite CLI.
76
+ * You can regenerate it by running \`appwrite types -l ts ${this.getCurrentDirectory()}\`.
77
+ */
69
78
 
70
79
  <% for (const collection of collections) { -%>
71
80
  <% for (const attribute of collection.attributes) { -%>
72
81
  <% if (attribute.format === 'enum') { -%>
73
82
  export enum <%- toPascalCase(attribute.key) %> {
74
- <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
75
- <%- toUpperSnakeCase(element) %> = "<%- element %>",
83
+ <% const entries = Object.entries(attribute.elements); -%>
84
+ <% for (let i = 0; i < entries.length; i++) { -%>
85
+ <%- toUpperSnakeCase(entries[i][1]) %> = "<%- entries[i][1] %>"<% if (i !== entries.length - 1) { %>,<% } %>
76
86
  <% } -%>
77
87
  }
78
88
 
package/lib/utils.js CHANGED
@@ -2,8 +2,8 @@ const fs = require("fs");
2
2
  const path = require("path");
3
3
  const net = require("net");
4
4
  const childProcess = require('child_process');
5
+ const chalk = require('chalk');
5
6
  const { localConfig, globalConfig } = require("./config");
6
- const { success } = require('./parser')
7
7
 
8
8
  function getAllFiles(folder) {
9
9
  const files = [];
@@ -105,8 +105,7 @@ function showConsoleLink(serviceName, action, ...ids) {
105
105
  return;
106
106
  }
107
107
 
108
-
109
- success(url);
108
+ console.log(`${chalk.green.bold("✓ Success:")} ${chalk.green(url)}`);
110
109
  }
111
110
 
112
111
  function getAccountPath(action) {
@@ -274,10 +273,17 @@ function getUsersPath(action, ids) {
274
273
  return path;
275
274
  }
276
275
 
276
+ function isCloud() {
277
+ const endpoint = globalConfig.getEndpoint() || "https://cloud.appwrite.io/v1";
278
+ const hostname = new URL(endpoint).hostname;
279
+ return hostname.endsWith('appwrite.io');
280
+ }
281
+
277
282
  module.exports = {
278
283
  getAllFiles,
279
284
  isPortTaken,
280
285
  systemHasCommand,
281
286
  checkDeployConditions,
282
- showConsoleLink
287
+ showConsoleLink,
288
+ isCloud
283
289
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "appwrite-cli",
3
3
  "homepage": "https://appwrite.io/support",
4
4
  "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
5
- "version": "8.0.2",
5
+ "version": "8.1.1",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "index.js",
8
8
  "bin": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json",
3
- "version": "8.0.2",
3
+ "version": "8.1.1",
4
4
  "description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.",
5
5
  "homepage": "https://github.com/appwrite/sdk-for-cli",
6
6
  "license": "BSD-3-Clause",
7
7
  "architecture": {
8
8
  "64bit": {
9
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.2/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.1.1/appwrite-cli-win-x64.exe",
10
10
  "bin": [
11
11
  [
12
12
  "appwrite-cli-win-x64.exe",
@@ -15,7 +15,7 @@
15
15
  ]
16
16
  },
17
17
  "arm64": {
18
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.2/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.1.1/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",