appwrite-cli 8.2.0 → 8.2.2

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.
@@ -41,7 +41,7 @@ jobs:
41
41
  npm publish
42
42
  fi
43
43
  env:
44
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
44
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN_NO_ORG }}
45
45
  - uses: fnkr/github-action-ghr@v1
46
46
  env:
47
47
  GHR_PATH: build/
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Change Log
2
2
 
3
+ ## 8.2.2
4
+
5
+ * Fix object comparison logic when pushing settings
6
+ * Type generation fixes:
7
+ * Dart: Fixed import casing to snake_case, removed `extends Document` and hardcoded attributes, removed unnecessary imports
8
+ * Java: Fixed indentation to 4 spaces, updated imports to `java.util.Objects`, fixed enum casing in strict mode as per [Oracle official docs](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)
9
+ * Javascript: Updated optional values formatting from `|null` to `| null`
10
+ * Kotlin: Fixed indentation to 4 spaces per [Kotlinlang official docs](https://kotlinlang.org/docs/coding-conventions.html#indentation)
11
+ * PHP: Fixed indentation to 4 spaces per [PHP Fig official docs](https://www.php-fig.org/psr/psr-2/)
12
+ * Swift: Fixed indentation to 4 spaces, improved `decodeIfPresent` usage for optionals, added missing `public` to `init` method
13
+ * Typescript: Fixed indentation to 4 spaces per [Typescript coding guidelines](https://github.com/microsoft/TypeScript/wiki/Coding-guidelines)
14
+
15
+ ## 8.2.1
16
+
17
+ * Added `--with-variables` option to the Sites command for adding/updating environment variables
18
+ * Fixed Functions environment variables not being pushed with `--with-variables`
19
+ * Removed `awaitPools` when wiping old variables
20
+
21
+ > **Note:** Storing environment variables in the `vars` attribute of `appwrite.json` is now deprecated due to security risks. Variables are now synced directly from the `.env` file in the root directory of the function’s or site’s folder.
22
+
3
23
  ## 8.2.0
4
24
 
5
25
  * Add `encrypt` attribute support
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.2.0
32
+ 8.2.2
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.2.0
63
+ 8.2.2
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.2.0/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.2.0/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.2.2/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.2.2/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.2.0"
100
+ GITHUB_LATEST_VERSION="8.2.2"
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.2.0',
20
- 'user-agent' : `AppwriteCLI/8.2.0 (${os.type()} ${os.version()}; ${os.arch()})`,
19
+ 'x-sdk-version': '8.2.2',
20
+ 'user-agent' : `AppwriteCLI/8.2.2 (${os.type()} ${os.version()}; ${os.arch()})`,
21
21
  'X-Appwrite-Response-Format' : '1.7.0',
22
22
  };
23
23
  }
@@ -1,3 +1,6 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { parse: parseDotenv } = require('dotenv');
1
4
  const chalk = require('chalk');
2
5
  const inquirer = require("inquirer");
3
6
  const JSONbig = require("json-bigint")({ storeAsString: false });
@@ -12,7 +15,7 @@ const { proxyCreateFunctionRule, proxyCreateSiteRule, proxyListRules } = require
12
15
  const { consoleVariables } = require('./console');
13
16
  const { sdkForConsole } = require('../sdks')
14
17
  const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsGetDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } = require('./functions');
15
- const { sitesGet, sitesCreate, sitesUpdate, sitesCreateDeployment, sitesGetDeployment, sitesCreateVariable } = require('./sites');
18
+ const { sitesGet, sitesCreate, sitesUpdate, sitesCreateDeployment, sitesGetDeployment, sitesCreateVariable, sitesListVariables, sitesDeleteVariable } = require('./sites');
16
19
  const {
17
20
  databasesGet,
18
21
  databasesCreate,
@@ -149,37 +152,6 @@ const awaitPools = {
149
152
  iteration + 1
150
153
  );
151
154
  },
152
- wipeVariables: async (functionId, iteration = 1) => {
153
- if (iteration > pollMaxDebounces) {
154
- return false;
155
- }
156
-
157
- const { total } = await functionsListVariables({
158
- functionId,
159
- queries: ['limit(1)'],
160
- parseOutput: false
161
- });
162
-
163
- if (total === 0) {
164
- return true;
165
- }
166
-
167
- if (pollMaxDebounces === POLL_DEFAULT_VALUE) {
168
- let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
169
- if (steps > 1 && iteration === 1) {
170
- pollMaxDebounces *= steps;
171
-
172
- log('Found a large number of variables, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes')
173
- }
174
- }
175
-
176
- await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE));
177
-
178
- return await awaitPools.wipeVariables(
179
- functionId,
180
- iteration + 1
181
- );
182
- },
183
155
  deleteAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
184
156
  if (iteration > pollMaxDebounces) {
185
157
  return false;
@@ -445,8 +417,17 @@ const getObjectChanges = (remote, local, index, what) => {
445
417
 
446
418
  if (remote[index] && local[index]) {
447
419
  for (let [service, status] of Object.entries(remote[index])) {
448
- if (status !== local[index][service]) {
449
- changes.push({ group: what, setting: service, remote: chalk.red(status), local: chalk.green(local[index][service]) })
420
+ const localValue = local[index][service];
421
+ let valuesEqual = false;
422
+
423
+ if (Array.isArray(status) && Array.isArray(localValue)) {
424
+ valuesEqual = JSON.stringify(status) === JSON.stringify(localValue);
425
+ } else {
426
+ valuesEqual = status === localValue;
427
+ }
428
+
429
+ if (!valuesEqual) {
430
+ changes.push({ group: what, setting: service, remote: chalk.red(status), local: chalk.green(localValue) })
450
431
  }
451
432
  }
452
433
  }
@@ -1047,7 +1028,7 @@ const pushSettings = async () => {
1047
1028
  }
1048
1029
  }
1049
1030
 
1050
- const pushSite = async({ siteId, async, code } = { returnOnZero: false }) => {
1031
+ const pushSite = async({ siteId, async, code, withVariables } = { returnOnZero: false }) => {
1051
1032
  process.chdir(localConfig.configDirectoryPath)
1052
1033
 
1053
1034
  const siteIds = [];
@@ -1180,7 +1161,6 @@ const pushSite = async({ siteId, async, code } = { returnOnZero: false }) => {
1180
1161
  timeout: site.timeout,
1181
1162
  enabled: site.enabled,
1182
1163
  logging: site.logging,
1183
- vars: JSON.stringify(site.vars),
1184
1164
  parseOutput: false
1185
1165
  });
1186
1166
 
@@ -1213,16 +1193,43 @@ const pushSite = async({ siteId, async, code } = { returnOnZero: false }) => {
1213
1193
  }
1214
1194
  }
1215
1195
 
1216
- updaterRow.update({ status: 'Creating variables' }).replaceSpinner(SPINNER_ARC);
1196
+ if (withVariables) {
1197
+ updaterRow.update({ status: 'Creating variables' }).replaceSpinner(SPINNER_ARC);
1217
1198
 
1218
- await Promise.all((site['vars'] ?? []).map(async variable => {
1219
- await sitesCreateVariable({
1199
+ const { variables } = await paginate(sitesListVariables, {
1220
1200
  siteId: site['$id'],
1221
- key: variable['key'],
1222
- value: variable['value'],
1223
1201
  parseOutput: false
1224
- });
1225
- }));
1202
+ }, 100, 'variables');
1203
+
1204
+ await Promise.all(variables.map(async variable => {
1205
+ await sitesDeleteVariable({
1206
+ siteId: site['$id'],
1207
+ variableId: variable['$id'],
1208
+ parseOutput: false
1209
+ });
1210
+ }));
1211
+
1212
+ const envFileLocation = `${site['path']}/.env`;
1213
+ let envVariables = [];
1214
+ try {
1215
+ if (fs.existsSync(envFileLocation)) {
1216
+ const envObject = parseDotenv(fs.readFileSync(envFileLocation, 'utf8'));
1217
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1218
+ }
1219
+ } catch (error) {
1220
+ // Handle parsing errors gracefully
1221
+ envVariables = [];
1222
+ }
1223
+ await Promise.all(envVariables.map(async variable => {
1224
+ await sitesCreateVariable({
1225
+ siteId: site['$id'],
1226
+ key: variable.key,
1227
+ value: variable.value,
1228
+ parseOutput: false,
1229
+ secret: false
1230
+ });
1231
+ }));
1232
+ }
1226
1233
 
1227
1234
  if (code === false) {
1228
1235
  successfullyPushed++;
@@ -1475,7 +1482,6 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
1475
1482
  entrypoint: func.entrypoint,
1476
1483
  commands: func.commands,
1477
1484
  scopes: func.scopes,
1478
- vars: JSON.stringify(func.vars),
1479
1485
  parseOutput: false
1480
1486
  });
1481
1487
 
@@ -1524,19 +1530,25 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
1524
1530
  });
1525
1531
  }));
1526
1532
 
1527
- let result = await awaitPools.wipeVariables(func['$id']);
1528
- if (!result) {
1529
- updaterRow.fail({ errorMessage: `Variable deletion timed out.` })
1530
- return;
1533
+ const envFileLocation = `${func['path']}/.env`;
1534
+ let envVariables = [];
1535
+ try {
1536
+ if (fs.existsSync(envFileLocation)) {
1537
+ const envObject = parseDotenv(fs.readFileSync(envFileLocation, 'utf8'));
1538
+ envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value }));
1539
+ }
1540
+ } catch (error) {
1541
+ // Handle parsing errors gracefully
1542
+ envVariables = [];
1531
1543
  }
1532
-
1533
- // Deploy local variables
1534
- await Promise.all((func['vars'] ?? []).map(async variable => {
1544
+ await Promise.all(envVariables.map(async variable => {
1535
1545
  await functionsCreateVariable({
1536
1546
  functionId: func['$id'],
1537
- key: variable['key'],
1538
- value: variable['value'],
1539
- parseOutput: false
1547
+ variableId: ID.unique(),
1548
+ key: variable.key,
1549
+ value: variable.value,
1550
+ parseOutput: false,
1551
+ secret: false
1540
1552
  });
1541
1553
  }));
1542
1554
  }
@@ -2065,6 +2077,7 @@ push
2065
2077
  .option(`-f, --site-id <site-id>`, `ID of site to run`)
2066
2078
  .option(`-A, --async`, `Don't wait for sites deployments status`)
2067
2079
  .option("--no-code", "Don't push the site's code")
2080
+ .option("--with-variables", `Push site variables.`)
2068
2081
  .action(actionRunner(pushSite));
2069
2082
 
2070
2083
  push
package/lib/parser.js CHANGED
@@ -122,7 +122,7 @@ const parseError = (err) => {
122
122
  } catch {
123
123
  }
124
124
 
125
- const version = '8.2.0';
125
+ const version = '8.2.2';
126
126
  const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
127
127
  const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`;
128
128
 
@@ -83,10 +83,9 @@ class Dart extends LanguageMeta {
83
83
  }
84
84
 
85
85
  getTemplate() {
86
- return `import 'package:${this.getPackageName()}/models.dart';
87
- <% for (const attribute of collection.attributes) { -%>
86
+ return `<% for (const attribute of collection.attributes) { -%>
88
87
  <% if (attribute.type === 'relationship') { -%>
89
- import '<%- attribute.relatedCollection.toLowerCase() %>.dart';
88
+ import '<%- toSnakeCase(attribute.relatedCollection) %>.dart';
90
89
 
91
90
  <% } -%>
92
91
  <% } -%>
@@ -103,19 +102,12 @@ enum <%- toPascalCase(attribute.key) %> {
103
102
 
104
103
  <% } -%>
105
104
  <% } -%>
106
- class <%= toPascalCase(collection.name) %> extends Document {
105
+ class <%= toPascalCase(collection.name) %> {
107
106
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
108
107
  <%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
109
108
  <% } -%>
110
109
 
111
110
  <%= toPascalCase(collection.name) %>({
112
- required super.$id,
113
- required super.$collectionId,
114
- required super.$databaseId,
115
- required super.$createdAt,
116
- required super.$updatedAt,
117
- required super.$permissions,
118
- required super.data,
119
111
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
120
112
  <% if (attribute.required) { %>required <% } %>this.<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (index < collection.attributes.length - 1) { %>,<% } %>
121
113
  <% } -%>
@@ -123,13 +115,6 @@ class <%= toPascalCase(collection.name) %> extends Document {
123
115
 
124
116
  factory <%= toPascalCase(collection.name) %>.fromMap(Map<String, dynamic> map) {
125
117
  return <%= toPascalCase(collection.name) %>(
126
- $id: map['\\$id'].toString(),
127
- $collectionId: map['\\$collectionId'].toString(),
128
- $databaseId: map['\\$databaseId'].toString(),
129
- $createdAt: map['\\$createdAt'].toString(),
130
- $updatedAt: map['\\$updatedAt'].toString(),
131
- $permissions: List<String>.from(map['\\$permissions'] ?? []),
132
- data: map,
133
118
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
134
119
  <%= strict ? toCamelCase(attribute.key) : attribute.key %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%>
135
120
  <% if (attribute.format === 'enum') { -%>
@@ -180,12 +165,6 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.relatedCollecti
180
165
 
181
166
  Map<String, dynamic> toMap() {
182
167
  return {
183
- "\\$id": $id,
184
- "\\$collectionId": $collectionId,
185
- "\\$databaseId": $databaseId,
186
- "\\$createdAt": $createdAt,
187
- "\\$updatedAt": $updatedAt,
188
- "\\$permissions": $permissions,
189
168
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
190
169
  "<%= attribute.key %>": <% if (attribute.type === 'relationship') { -%>
191
170
  <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%>
@@ -50,7 +50,7 @@ class Java extends LanguageMeta {
50
50
  * You can regenerate it by running \`appwrite types -l java ${this.getCurrentDirectory()}\`.
51
51
  */
52
52
 
53
- import java.util.*;
53
+ import java.util.Objects;
54
54
  <% for (const attribute of collection.attributes) { -%>
55
55
  <% if (attribute.type === 'relationship') { -%>
56
56
  import io.appwrite.models.<%- toPascalCase(attribute.relatedCollection) %>;
@@ -61,63 +61,63 @@ public class <%- toPascalCase(collection.name) %> {
61
61
  <% for (const attribute of collection.attributes) { -%>
62
62
  <% if (attribute.format === 'enum') { -%>
63
63
 
64
- public enum <%- toPascalCase(attribute.key) %> {
64
+ public enum <%- toPascalCase(attribute.key) %> {
65
65
  <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
66
- <%- strict ? toSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : ';' %>
66
+ <%- strict ? toUpperSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : ';' %>
67
67
  <% } -%>
68
- }
68
+ }
69
69
 
70
70
  <% } -%>
71
71
  <% } -%>
72
72
  <% for (const attribute of collection.attributes) { -%>
73
- private <%- getType(attribute) %> <%- strict ? toCamelCase(attribute.key) : attribute.key %>;
73
+ private <%- getType(attribute) %> <%- strict ? toCamelCase(attribute.key) : attribute.key %>;
74
74
  <% } -%>
75
75
 
76
- public <%- toPascalCase(collection.name) %>() {
77
- }
76
+ public <%- toPascalCase(collection.name) %>() {
77
+ }
78
78
 
79
- public <%- toPascalCase(collection.name) %>(
79
+ public <%- toPascalCase(collection.name) %>(
80
80
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
81
- <%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %><%- index < collection.attributes.length - 1 ? ',' : '' %>
81
+ <%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %><%- index < collection.attributes.length - 1 ? ',' : '' %>
82
82
  <% } -%>
83
- ) {
83
+ ) {
84
84
  <% for (const attribute of collection.attributes) { -%>
85
- this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
85
+ this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
86
86
  <% } -%>
87
- }
87
+ }
88
88
 
89
89
  <% for (const attribute of collection.attributes) { -%>
90
- public <%- getType(attribute) %> get<%- toPascalCase(attribute.key) %>() {
91
- return <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
92
- }
90
+ public <%- getType(attribute) %> get<%- toPascalCase(attribute.key) %>() {
91
+ return <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
92
+ }
93
93
 
94
- public void set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>) {
95
- this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
96
- }
94
+ public void set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>) {
95
+ this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
96
+ }
97
97
 
98
98
  <% } -%>
99
- @Override
100
- public boolean equals(Object obj) {
101
- if (this == obj) return true;
102
- if (obj == null || getClass() != obj.getClass()) return false;
103
- <%- toPascalCase(collection.name) %> that = (<%- toPascalCase(collection.name) %>) obj;
104
- return <% collection.attributes.forEach((attr, index) => { %>Objects.equals(<%= toCamelCase(attr.key) %>, that.<%= toCamelCase(attr.key) %>)<% if (index < collection.attributes.length - 1) { %> &&
99
+ @Override
100
+ public boolean equals(Object obj) {
101
+ if (this == obj) return true;
102
+ if (obj == null || getClass() != obj.getClass()) return false;
103
+ <%- toPascalCase(collection.name) %> that = (<%- toPascalCase(collection.name) %>) obj;
104
+ return <% collection.attributes.forEach((attr, index) => { %>Objects.equals(<%= toCamelCase(attr.key) %>, that.<%= toCamelCase(attr.key) %>)<% if (index < collection.attributes.length - 1) { %> &&
105
105
  <% } }); %>;
106
- }
106
+ }
107
107
 
108
- @Override
109
- public int hashCode() {
110
- return Objects.hash(<%= collection.attributes.map(attr => toCamelCase(attr.key)).join(', ') %>);
111
- }
108
+ @Override
109
+ public int hashCode() {
110
+ return Objects.hash(<%= collection.attributes.map(attr => toCamelCase(attr.key)).join(', ') %>);
111
+ }
112
112
 
113
- @Override
114
- public String toString() {
115
- return "<%- toPascalCase(collection.name) %>{" +
116
- <% for (const attribute of collection.attributes) { -%>
117
- "<%= strict ? toCamelCase(attribute.key) : attribute.key %>=" + <%= strict ? toCamelCase(attribute.key) : attribute.key %> +
113
+ @Override
114
+ public String toString() {
115
+ return "<%- toPascalCase(collection.name) %>{" +
116
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
117
+ "<%= strict ? toCamelCase(attribute.key) : attribute.key %>=" + <%= strict ? toCamelCase(attribute.key) : attribute.key %> +<% if (index < collection.attributes.length - 1) { %> ", " +<% } %>
118
118
  <% } -%>
119
- '}';
120
- }
119
+ '}';
120
+ }
121
121
  }
122
122
  `;
123
123
  }
@@ -41,7 +41,7 @@ class JavaScript extends LanguageMeta {
41
41
  type += "[]";
42
42
  }
43
43
  if (!attribute.required && attribute.default === null) {
44
- type += "|null";
44
+ type += " | null";
45
45
  }
46
46
  return type;
47
47
  }
@@ -63,7 +63,7 @@ import <%- toPascalCase(attribute.relatedCollection) %>
63
63
  <% if (attribute.format === 'enum') { -%>
64
64
  enum class <%- toPascalCase(attribute.key) %> {
65
65
  <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
66
- <%- strict ? toUpperSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : '' %>
66
+ <%- strict ? toUpperSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : '' %>
67
67
  <% } -%>
68
68
  }
69
69
 
@@ -71,7 +71,7 @@ enum class <%- toPascalCase(attribute.key) %> {
71
71
  <% } -%>
72
72
  data class <%- toPascalCase(collection.name) %>(
73
73
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
74
- val <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
74
+ val <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
75
75
  <% } -%>
76
76
  )`;
77
77
  }
@@ -62,7 +62,7 @@ use Appwrite\\Models\\<%- toPascalCase(attribute.relatedCollection) %>;
62
62
  <% if (attribute.format === 'enum') { -%>
63
63
  enum <%- toPascalCase(attribute.key) %>: string {
64
64
  <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
65
- case <%- strict ? toUpperSnakeCase(element) : element %> = '<%- element %>';
65
+ case <%- strict ? toUpperSnakeCase(element) : element %> = '<%- element %>';
66
66
  <% } -%>
67
67
  }
68
68
 
@@ -70,31 +70,31 @@ enum <%- toPascalCase(attribute.key) %>: string {
70
70
  <% } -%>
71
71
  class <%- toPascalCase(collection.name) %> {
72
72
  <% for (const attribute of collection.attributes ){ -%>
73
- private <%- getType(attribute) %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
73
+ private <%- getType(attribute) %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
74
74
  <% } -%>
75
75
 
76
- public function __construct(
76
+ public function __construct(
77
77
  <% for (const attribute of collection.attributes ){ -%>
78
78
  <% if (attribute.required) { -%>
79
- <%- getType(attribute).replace('|null', '') %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %><% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
79
+ <%- getType(attribute).replace('|null', '') %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %><% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
80
80
  <% } else { -%>
81
- ?<%- getType(attribute).replace('|null', '') %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %> = null<% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
81
+ ?<%- getType(attribute).replace('|null', '') %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %> = null<% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
82
82
  <% } -%>
83
83
  <% } -%>
84
- ) {
84
+ ) {
85
85
  <% for (const attribute of collection.attributes ){ -%>
86
- $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %> = $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
86
+ $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %> = $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
87
87
  <% } -%>
88
- }
88
+ }
89
89
 
90
90
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
91
- public function get<%- toPascalCase(attribute.key) %>(): <%- getType(attribute) %> {
92
- return $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %>;
93
- }
91
+ public function get<%- toPascalCase(attribute.key) %>(): <%- getType(attribute) %> {
92
+ return $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %>;
93
+ }
94
94
 
95
- public function set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %>): void {
96
- $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %> = $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
97
- }
95
+ public function set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> $<%- strict ? toCamelCase(attribute.key) : attribute.key %>): void {
96
+ $this-><%- strict ? toCamelCase(attribute.key) : attribute.key %> = $<%- strict ? toCamelCase(attribute.key) : attribute.key %>;
97
+ }
98
98
  <% if (index < collection.attributes.length - 1) { %>
99
99
  <% } -%>
100
100
  <% } -%>
@@ -55,7 +55,7 @@ class Swift extends LanguageMeta {
55
55
  <% if (attribute.format === 'enum') { -%>
56
56
  public enum <%- toPascalCase(attribute.key) %>: String, Codable, CaseIterable {
57
57
  <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
58
- case <%- strict ? toCamelCase(element) : element %> = "<%- element %>"
58
+ case <%- strict ? toCamelCase(element) : element %> = "<%- element %>"
59
59
  <% } -%>
60
60
  }
61
61
 
@@ -63,101 +63,101 @@ public enum <%- toPascalCase(attribute.key) %>: String, Codable, CaseIterable {
63
63
  <% } -%>
64
64
  public class <%- toPascalCase(collection.name) %>: Codable {
65
65
  <% for (const attribute of collection.attributes) { -%>
66
- public let <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %>
66
+ public let <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %>
67
67
  <% } %>
68
- enum CodingKeys: String, CodingKey {
68
+ enum CodingKeys: String, CodingKey {
69
69
  <% for (const attribute of collection.attributes) { -%>
70
- case <%- strict ? toCamelCase(attribute.key) : attribute.key %> = "<%- attribute.key %>"
70
+ case <%- strict ? toCamelCase(attribute.key) : attribute.key %> = "<%- attribute.key %>"
71
71
  <% } -%>
72
- }
72
+ }
73
73
 
74
- init(
74
+ public init(
75
75
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
76
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
76
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
77
77
  <% } -%>
78
- ) {
78
+ ) {
79
79
  <% for (const attribute of collection.attributes) { -%>
80
- self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = <%- strict ? toCamelCase(attribute.key) : attribute.key %>
80
+ self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = <%- strict ? toCamelCase(attribute.key) : attribute.key %>
81
81
  <% } -%>
82
- }
82
+ }
83
83
 
84
- public required init(from decoder: Decoder) throws {
85
- let container = try decoder.container(keyedBy: CodingKeys.self)
84
+ public required init(from decoder: Decoder) throws {
85
+ let container = try decoder.container(keyedBy: CodingKeys.self)
86
86
 
87
87
  <% for (const attribute of collection.attributes) { -%>
88
- <% if (attribute.required) { -%>
89
- self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = try container.decode(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
88
+ <% if (!(!attribute.required && attribute.default === null)) { -%>
89
+ self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = try container.decode(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
90
90
  <% } else { -%>
91
- self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = try container.decodeIfPresent(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
91
+ self.<%- strict ? toCamelCase(attribute.key) : attribute.key %> = try container.decodeIfPresent(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
92
92
  <% } -%>
93
93
  <% } -%>
94
- }
94
+ }
95
95
 
96
- public func encode(to encoder: Encoder) throws {
97
- var container = encoder.container(keyedBy: CodingKeys.self)
96
+ public func encode(to encoder: Encoder) throws {
97
+ var container = encoder.container(keyedBy: CodingKeys.self)
98
98
 
99
99
  <% for (const attribute of collection.attributes) { -%>
100
- <% if (attribute.required) { -%>
101
- try container.encode(<%- strict ? toCamelCase(attribute.key) : attribute.key %>, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
100
+ <% if (!(!attribute.required && attribute.default === null)) { -%>
101
+ try container.encode(<%- strict ? toCamelCase(attribute.key) : attribute.key %>, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
102
102
  <% } else { -%>
103
- try container.encodeIfPresent(<%- strict ? toCamelCase(attribute.key) : attribute.key %>, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
103
+ try container.encodeIfPresent(<%- strict ? toCamelCase(attribute.key) : attribute.key %>, forKey: .<%- strict ? toCamelCase(attribute.key) : attribute.key %>)
104
104
  <% } -%>
105
105
  <% } -%>
106
- }
106
+ }
107
107
 
108
- public func toMap() -> [String: Any] {
109
- return [
108
+ public func toMap() -> [String: Any] {
109
+ return [
110
110
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
111
111
  <% if (attribute.type === 'relationship') { -%>
112
- "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %> as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
112
+ "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %> as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
113
113
  <% } else if (attribute.array && attribute.type !== 'string' && attribute.type !== 'integer' && attribute.type !== 'float' && attribute.type !== 'boolean') { -%>
114
- "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %>?.map { $0.toMap() } as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
114
+ "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %>?.map { $0.toMap() } as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
115
115
  <% } else { -%>
116
- "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %> as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
116
+ "<%- attribute.key %>": <%- strict ? toCamelCase(attribute.key) : attribute.key %> as Any<% if (index < collection.attributes.length - 1) { %>,<% } %>
117
117
  <% } -%>
118
118
  <% } -%>
119
- ]
120
- }
119
+ ]
120
+ }
121
121
 
122
- public static func from(map: [String: Any]) -> <%- toPascalCase(collection.name) %> {
123
- return <%- toPascalCase(collection.name) %>(
122
+ public static func from(map: [String: Any]) -> <%- toPascalCase(collection.name) %> {
123
+ return <%- toPascalCase(collection.name) %>(
124
124
  <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
125
125
  <% if (attribute.type === 'relationship') { -%>
126
126
  <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%>
127
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [<%- toPascalCase(attribute.relatedCollection) %>]<% if (index < collection.attributes.length - 1) { %>,<% } %>
127
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [<%- toPascalCase(attribute.relatedCollection) %>]<% if (index < collection.attributes.length - 1) { %>,<% } %>
128
128
  <% } else { -%>
129
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> <%- toPascalCase(attribute.relatedCollection) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
129
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> <%- toPascalCase(attribute.relatedCollection) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
130
130
  <% } -%>
131
131
  <% } else if (attribute.array) { -%>
132
132
  <% if (attribute.type === 'string') { -%>
133
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [String]<% if (index < collection.attributes.length - 1) { %>,<% } %>
133
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [String]<% if (index < collection.attributes.length - 1) { %>,<% } %>
134
134
  <% } else if (attribute.type === 'integer') { -%>
135
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Int]<% if (index < collection.attributes.length - 1) { %>,<% } %>
135
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Int]<% if (index < collection.attributes.length - 1) { %>,<% } %>
136
136
  <% } else if (attribute.type === 'float') { -%>
137
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Double]<% if (index < collection.attributes.length - 1) { %>,<% } %>
137
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Double]<% if (index < collection.attributes.length - 1) { %>,<% } %>
138
138
  <% } else if (attribute.type === 'boolean') { -%>
139
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Bool]<% if (index < collection.attributes.length - 1) { %>,<% } %>
139
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Bool]<% if (index < collection.attributes.length - 1) { %>,<% } %>
140
140
  <% } else { -%>
141
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: (map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [[String: Any]])<% if (!attribute.required) { %>?<% } %>.map { <%- toPascalCase(attribute.type) %>.from(map: $0) }<% if (index < collection.attributes.length - 1) { %>,<% } %>
141
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: (map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [[String: Any]])<% if (!attribute.required) { %>?<% } %>.map { <%- toPascalCase(attribute.type) %>.from(map: $0) }<% if (index < collection.attributes.length - 1) { %>,<% } %>
142
142
  <% } -%>
143
143
  <% } else { -%>
144
144
  <% if ((attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') && attribute.format !== 'enum') { -%>
145
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> String<% if (index < collection.attributes.length - 1) { %>,<% } %>
145
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> String<% if (index < collection.attributes.length - 1) { %>,<% } %>
146
146
  <% } else if (attribute.type === 'string' && attribute.format === 'enum') { -%>
147
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- toPascalCase(attribute.key) %>(rawValue: map["<%- attribute.key %>"] as! String)!<% if (index < collection.attributes.length - 1) { %>,<% } %>
147
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- toPascalCase(attribute.key) %>(rawValue: map["<%- attribute.key %>"] as! String)!<% if (index < collection.attributes.length - 1) { %>,<% } %>
148
148
  <% } else if (attribute.type === 'integer') { -%>
149
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Int<% if (index < collection.attributes.length - 1) { %>,<% } %>
149
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Int<% if (index < collection.attributes.length - 1) { %>,<% } %>
150
150
  <% } else if (attribute.type === 'float') { -%>
151
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Double<% if (index < collection.attributes.length - 1) { %>,<% } %>
151
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Double<% if (index < collection.attributes.length - 1) { %>,<% } %>
152
152
  <% } else if (attribute.type === 'boolean') { -%>
153
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Bool<% if (index < collection.attributes.length - 1) { %>,<% } %>
153
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Bool<% if (index < collection.attributes.length - 1) { %>,<% } %>
154
154
  <% } else { -%>
155
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- toPascalCase(attribute.type) %>.from(map: map["<%- attribute.key %>"] as! [String: Any])<% if (index < collection.attributes.length - 1) { %>,<% } %>
155
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- toPascalCase(attribute.type) %>.from(map: map["<%- attribute.key %>"] as! [String: Any])<% if (index < collection.attributes.length - 1) { %>,<% } %>
156
156
  <% } -%>
157
157
  <% } -%>
158
158
  <% } -%>
159
- )
160
- }
159
+ )
160
+ }
161
161
  }`;
162
162
  }
163
163
 
@@ -80,21 +80,21 @@ class TypeScript extends LanguageMeta {
80
80
  export enum <%- toPascalCase(attribute.key) %> {
81
81
  <% const entries = Object.entries(attribute.elements); -%>
82
82
  <% for (let i = 0; i < entries.length; i++) { -%>
83
- <%- toUpperSnakeCase(entries[i][1]) %> = "<%- entries[i][1] %>"<% if (i !== entries.length - 1) { %>,<% } %>
83
+ <%- toUpperSnakeCase(entries[i][1]) %> = "<%- entries[i][1] %>"<% if (i !== entries.length - 1) { %>,<% } %>
84
84
  <% } -%>
85
85
  }
86
86
 
87
87
  <% } -%>
88
88
  <% } -%>
89
89
  <% } -%>
90
- <% for (const collection of collections) { -%>
90
+ <% for (const [index, collection] of Object.entries(collections)) { -%>
91
91
  export type <%- toPascalCase(collection.name) %> = Models.Document & {
92
92
  <% for (const attribute of collection.attributes) { -%>
93
- <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %>;
93
+ <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %>;
94
94
  <% } -%>
95
- }
96
-
97
- <% } %>`;
95
+ }<% if (index < collections.length - 1) { %>
96
+ <% } %>
97
+ <% } -%>`;
98
98
  }
99
99
 
100
100
  getFileName(_) {
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.2.0",
5
+ "version": "8.2.2",
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.2.0",
3
+ "version": "8.2.2",
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.2.0/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.2.2/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.2.0/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.2.2/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",