appwrite-cli 8.0.2 → 8.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # Change Log
2
+
3
+ ## 8.1.0
4
+
5
+ * Add multi-region support to `init` command
6
+ * Update `init` command to clear previous configuration in `appwrite.json`
7
+ * Update localConfig to store multi-region endpoint
8
+ * Fix throw error when creating unknown attribute instead of timing out
9
+ * Fix equal comparison of large numbers and BigNumber instances using proper equality checks
10
+ * Fix duplication of reasons when comparing localConfig with remoteConfig
11
+ * Fix `firstOrNull()` to `firstOrNull` in types generation for dart
12
+ * Refactor to use `isCloud()` method consistently
13
+
14
+ ## 8.0.2
15
+
16
+ * Add Type generation fixes:
17
+ * Properly handle enum attributes in dart, java and kotlin
18
+ * Fix initialisation of null attributes in dart's fromMap method
19
+ * Fix relationships and enums in swift
20
+
21
+ ## 8.0.1
22
+
23
+ * Add `resourceId` and `resourceType` attributes to `createRedirectRule`
24
+ * Add `providerReference` to vcs command for getting repository contents
25
+ * Add warning comment to `bulk updateDocuments` method
26
+ * Fix type generation for enums in Typescript and PHP language
27
+
28
+ ## 8.0.0
29
+
30
+ * Add `types` command to generate language specific typings for collections. Currently supports - `php`, `swift`, `dart`, `js`, `ts`, `kotlin` and `java`
31
+ * Update bulk operation docs to include experiment feature warnings
32
+ * Remove assistant service and commands
33
+
34
+ ## 7.0.0
35
+
36
+ * Add `sites` command
37
+ * Add `tokens` command
38
+ * Add `devKeys` support to `projects` command
39
+ * Add `init site`, `pull site` and `push site` commands
40
+ * Add bulk operation methods like `createDocuments`, `deleteDocuments` etc.
41
+ * Add new upsert methods: `upsertDocument` and `upsertDocuments`
42
+ * Update GET requests to not include content-type header
43
+
44
+ ## 6.2.3
45
+
46
+ * Fix hot swapping error in `python-ml` function
47
+
48
+ ## 6.2.2
49
+
50
+ * Fix GitHub builds by adding `qemu-system` package
51
+ * Fix attribute creation timed out
52
+
53
+ ## 6.2.1
54
+
55
+ * Add `listOrganizations` method to `organizations` service and fix init project command
56
+
57
+ ## 6.2.0
58
+
59
+ * Add specifications support to CLI
60
+ * Update package version
61
+ * 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.0
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.0
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.0/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.1.0/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.0"
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.0',
20
+ 'user-agent' : `AppwriteCLI/8.1.0 (${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 };
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.0';
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",
@@ -78,7 +78,7 @@ class <%= toPascalCase(collection.name) %> {
78
78
  (map['<%= attribute.key %>'] as List<dynamic>?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% if (!attribute.required) { %> ?? []<% } -%>
79
79
  <% } else { -%>
80
80
  <% if (!attribute.required) { -%>
81
- map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull() : null<% } else { -%>
81
+ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull : null<% } else { -%>
82
82
  <%- toPascalCase(attribute.key) %>.values.firstWhere((e) => e.name == map['<%= attribute.key %>'])<% } -%>
83
83
  <% } -%>
84
84
  <% } else { -%>
package/lib/utils.js CHANGED
@@ -274,10 +274,17 @@ function getUsersPath(action, ids) {
274
274
  return path;
275
275
  }
276
276
 
277
+ function isCloud() {
278
+ const endpoint = globalConfig.getEndpoint() || "https://cloud.appwrite.io/v1";
279
+ const hostname = new URL(endpoint).hostname;
280
+ return hostname.endsWith('appwrite.io');
281
+ }
282
+
277
283
  module.exports = {
278
284
  getAllFiles,
279
285
  isPortTaken,
280
286
  systemHasCommand,
281
287
  checkDeployConditions,
282
- showConsoleLink
288
+ showConsoleLink,
289
+ isCloud
283
290
  };
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.0",
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.0",
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.0/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.0/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",