appwrite-cli 10.2.1 → 10.2.3

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 10.2.3
4
+
5
+ * Fix `init tables` command not working
6
+ * Improve tablesDB resource syncing during `push tables` command
7
+
8
+ ## 10.2.2
9
+
10
+ * Fix `logout` command showing duplicate sessions
11
+ * Fix `logout` command showing a blank email even when logged out
12
+ * Add syncing of `tablesDB` resource during `push tables` command
13
+
3
14
  ## 10.2.1
4
15
 
5
16
  * Add transaction support for Databases and TablesDB
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
- 10.2.1
32
+ 10.2.3
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
- 10.2.1
63
+ 10.2.3
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/10.2.1/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.3/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.3/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="10.2.1"
100
+ GITHUB_LATEST_VERSION="10.2.3"
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': '10.2.1',
20
- 'user-agent' : `AppwriteCLI/10.2.1 (${os.type()} ${os.version()}; ${os.arch()})`,
19
+ 'x-sdk-version': '10.2.3',
20
+ 'user-agent' : `AppwriteCLI/10.2.3 (${os.type()} ${os.version()}; ${os.arch()})`,
21
21
  'X-Appwrite-Response-Format' : '1.8.0',
22
22
  };
23
23
  }
@@ -171,12 +171,11 @@ const deleteSession = async (accountId) => {
171
171
  parseOutput: false,
172
172
  sdk: client
173
173
  })
174
-
175
- globalConfig.removeSession(accountId);
176
174
  } catch (e) {
177
175
  error('Unable to log out, removing locally saved session information')
176
+ } finally {
177
+ globalConfig.removeSession(accountId);
178
178
  }
179
- globalConfig.removeSession(accountId);
180
179
  }
181
180
 
182
181
  const logout = new Command("logout")
@@ -194,6 +193,7 @@ const logout = new Command("logout")
194
193
  }
195
194
  if (sessions.length === 1) {
196
195
  await deleteSession(current);
196
+ globalConfig.setCurrentSession('');
197
197
  success("Logging out");
198
198
 
199
199
  return;
@@ -215,6 +215,8 @@ const logout = new Command("logout")
215
215
  globalConfig.setCurrentSession(accountId);
216
216
 
217
217
  success(`Current account is ${accountId}`);
218
+ } else if (remainingSessions.length === 0) {
219
+ globalConfig.setCurrentSession('');
218
220
  }
219
221
 
220
222
  success("Logging out");
@@ -19,6 +19,7 @@ const {
19
19
  questionsCreateBucket,
20
20
  questionsCreateMessagingTopic,
21
21
  questionsCreateCollection,
22
+ questionsCreateTable,
22
23
  questionsInitProject,
23
24
  questionsInitProjectAutopull,
24
25
  questionsInitResources,
@@ -34,10 +35,11 @@ const initResources = async () => {
34
35
  const actions = {
35
36
  function: initFunction,
36
37
  site: initSite,
37
- collection: initCollection,
38
+ table: initTable,
38
39
  bucket: initBucket,
39
40
  team: initTeam,
40
- message: initTopic
41
+ message: initTopic,
42
+ collection: initCollection
41
43
  }
42
44
 
43
45
  const answers = await inquirer.prompt(questionsInitResources[0]);
@@ -160,6 +162,40 @@ const initTeam = async () => {
160
162
  log("Next you can use 'appwrite push team' to deploy the changes.");
161
163
  };
162
164
 
165
+ const initTable = async () => {
166
+ const answers = await inquirer.prompt(questionsCreateTable)
167
+ const newDatabase = (answers.method ?? '').toLowerCase() !== 'existing';
168
+
169
+ if (!newDatabase) {
170
+ answers.databaseId = answers.database;
171
+ answers.databaseName = localConfig.getTablesDB(answers.database).name;
172
+ }
173
+
174
+ const databaseId = answers.databaseId === 'unique()' ? ID.unique() : answers.databaseId;
175
+
176
+ if (newDatabase || !localConfig.getTablesDB(answers.databaseId)) {
177
+ localConfig.addTablesDB({
178
+ $id: databaseId,
179
+ name: answers.databaseName,
180
+ enabled: true
181
+ });
182
+ }
183
+
184
+ localConfig.addTable({
185
+ $id: answers.id === 'unique()' ? ID.unique() : answers.id,
186
+ $permissions: [],
187
+ databaseId: databaseId,
188
+ name: answers.table,
189
+ enabled: true,
190
+ rowSecurity: answers.rowSecurity.toLowerCase() === 'yes',
191
+ columns: [],
192
+ indexes: [],
193
+ });
194
+
195
+ success("Initialing table");
196
+ log("Next you can use 'appwrite push table' to deploy the changes.");
197
+ };
198
+
163
199
  const initCollection = async () => {
164
200
  const answers = await inquirer.prompt(questionsCreateCollection)
165
201
  const newDatabase = (answers.method ?? '').toLowerCase() !== 'existing';
@@ -557,6 +593,12 @@ init
557
593
  .description("Init a new Appwrite collection")
558
594
  .action(actionRunner(initCollection));
559
595
 
596
+ init
597
+ .command("table")
598
+ .alias("tables")
599
+ .description("Init a new Appwrite table")
600
+ .action(actionRunner(initTable));
601
+
560
602
  init
561
603
  .command("topic")
562
604
  .alias("topics")
@@ -55,7 +55,10 @@ const {
55
55
  tablesDBUpdate,
56
56
  tablesDBCreateTable,
57
57
  tablesDBGetTable,
58
- tablesDBUpdateTable
58
+ tablesDBUpdateTable,
59
+ tablesDBList,
60
+ tablesDBDelete,
61
+ tablesDBListTables
59
62
  } = require("./tables-db");
60
63
  const {
61
64
  storageGetBucket, storageUpdateBucket, storageCreateBucket
@@ -834,14 +837,16 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection,
834
837
 
835
838
  if (!cliConfig.force) {
836
839
  if (deleting.length > 0 && !isIndex) {
837
- console.log(`${chalk.red('-------------------------------------------------------')}`);
840
+ console.log(`${chalk.red('------------------------------------------------------')}`);
838
841
  console.log(`${chalk.red('| WARNING: Attribute deletion may cause loss of data |')}`);
839
- console.log(`${chalk.red('-------------------------------------------------------')}`);
842
+ console.log(`${chalk.red('------------------------------------------------------')}`);
843
+ console.log();
840
844
  }
841
845
  if (conflicts.length > 0 && !isIndex) {
842
- console.log(`${chalk.red('---------------------------------------------------------')}`);
846
+ console.log(`${chalk.red('--------------------------------------------------------')}`);
843
847
  console.log(`${chalk.red('| WARNING: Attribute recreation may cause loss of data |')}`);
844
- console.log(`${chalk.red('---------------------------------------------------------')}`);
848
+ console.log(`${chalk.red('--------------------------------------------------------')}`);
849
+ console.log();
845
850
  }
846
851
 
847
852
  if ((await getConfirmation()) !== true) {
@@ -1700,6 +1705,158 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
1700
1705
  }
1701
1706
  }
1702
1707
 
1708
+ const checkAndApplyTablesDBChanges = async () => {
1709
+ log('Checking for tablesDB changes ...');
1710
+
1711
+ const localTablesDBs = localConfig.getTablesDBs();
1712
+ const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases');
1713
+
1714
+ if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
1715
+ return { applied: false, resyncNeeded: false };
1716
+ }
1717
+
1718
+ const changes = [];
1719
+ const toCreate = [];
1720
+ const toUpdate = [];
1721
+ const toDelete = [];
1722
+
1723
+ // Check for deletions - remote DBs that aren't in local config
1724
+ for (const remoteDB of remoteTablesDBs) {
1725
+ const localDB = localTablesDBs.find(db => db.$id === remoteDB.$id);
1726
+ if (!localDB) {
1727
+ toDelete.push(remoteDB);
1728
+ changes.push({
1729
+ id: remoteDB.$id,
1730
+ action: chalk.red('deleting'),
1731
+ key: 'Database',
1732
+ remote: remoteDB.name,
1733
+ local: '(deleted locally)'
1734
+ });
1735
+ }
1736
+ }
1737
+
1738
+ // Check for additions and updates
1739
+ for (const localDB of localTablesDBs) {
1740
+ const remoteDB = remoteTablesDBs.find(db => db.$id === localDB.$id);
1741
+
1742
+ if (!remoteDB) {
1743
+ toCreate.push(localDB);
1744
+ changes.push({
1745
+ id: localDB.$id,
1746
+ action: chalk.green('creating'),
1747
+ key: 'Database',
1748
+ remote: '(does not exist)',
1749
+ local: localDB.name
1750
+ });
1751
+ } else {
1752
+ let hasChanges = false;
1753
+
1754
+ if (remoteDB.name !== localDB.name) {
1755
+ hasChanges = true;
1756
+ changes.push({
1757
+ id: localDB.$id,
1758
+ action: chalk.yellow('updating'),
1759
+ key: 'Name',
1760
+ remote: remoteDB.name,
1761
+ local: localDB.name
1762
+ });
1763
+ }
1764
+
1765
+ if (remoteDB.enabled !== localDB.enabled) {
1766
+ hasChanges = true;
1767
+ changes.push({
1768
+ id: localDB.$id,
1769
+ action: chalk.yellow('updating'),
1770
+ key: 'Enabled',
1771
+ remote: remoteDB.enabled,
1772
+ local: localDB.enabled
1773
+ });
1774
+ }
1775
+
1776
+ if (hasChanges) {
1777
+ toUpdate.push(localDB);
1778
+ }
1779
+ }
1780
+ }
1781
+
1782
+ if (changes.length === 0) {
1783
+ console.log('No changes found in tablesDB resource');
1784
+ console.log();
1785
+ return { applied: false, resyncNeeded: false };
1786
+ }
1787
+
1788
+ log('Found changes in tablesDB resource:');
1789
+ drawTable(changes);
1790
+
1791
+ if (toDelete.length > 0) {
1792
+ console.log(`${chalk.red('------------------------------------------------------------------')}`);
1793
+ console.log(`${chalk.red('| WARNING: Database deletion will also delete all related tables |')}`);
1794
+ console.log(`${chalk.red('------------------------------------------------------------------')}`);
1795
+ console.log();
1796
+ }
1797
+
1798
+ if ((await getConfirmation()) !== true) {
1799
+ return { applied: false, resyncNeeded: false };
1800
+ }
1801
+
1802
+ // Apply deletions first
1803
+ let needsResync = false;
1804
+ for (const db of toDelete) {
1805
+ try {
1806
+ log(`Deleting database ${db.name} ( ${db.$id} ) ...`);
1807
+ await tablesDBDelete({
1808
+ databaseId: db.$id,
1809
+ parseOutput: false
1810
+ });
1811
+ success(`Deleted ${db.name} ( ${db.$id} )`);
1812
+ needsResync = true;
1813
+ } catch (e) {
1814
+ error(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`);
1815
+ throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`);
1816
+ }
1817
+ }
1818
+
1819
+ // Apply creations
1820
+ for (const db of toCreate) {
1821
+ try {
1822
+ log(`Creating database ${db.name} ( ${db.$id} ) ...`);
1823
+ await tablesDBCreate({
1824
+ databaseId: db.$id,
1825
+ name: db.name,
1826
+ enabled: db.enabled,
1827
+ parseOutput: false
1828
+ });
1829
+ success(`Created ${db.name} ( ${db.$id} )`);
1830
+ } catch (e) {
1831
+ error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
1832
+ throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
1833
+ }
1834
+ }
1835
+
1836
+ // Apply updates
1837
+ for (const db of toUpdate) {
1838
+ try {
1839
+ log(`Updating database ${db.name} ( ${db.$id} ) ...`);
1840
+ await tablesDBUpdate({
1841
+ databaseId: db.$id,
1842
+ name: db.name,
1843
+ enabled: db.enabled,
1844
+ parseOutput: false
1845
+ });
1846
+ success(`Updated ${db.name} ( ${db.$id} )`);
1847
+ } catch (e) {
1848
+ error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
1849
+ throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
1850
+ }
1851
+ }
1852
+
1853
+ if (toDelete.length === 0){
1854
+ console.log();
1855
+ }
1856
+
1857
+ return { applied: true, resyncNeeded: needsResync };
1858
+ };
1859
+
1703
1860
  const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
1704
1861
  const tables = [];
1705
1862
 
@@ -1707,6 +1864,26 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
1707
1864
  pollMaxDebounces = attempts;
1708
1865
  }
1709
1866
 
1867
+ const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges();
1868
+ if (resyncNeeded) {
1869
+ log('Resyncing configuration due to tablesDB deletions ...');
1870
+
1871
+ const remoteTablesDBs = (await paginate(tablesDBList, { parseOutput: false }, 100, 'databases')).databases;
1872
+ const localTablesDBs = localConfig.getTablesDBs();
1873
+
1874
+ const remoteDatabaseIds = new Set(remoteTablesDBs.map(db => db.$id));
1875
+ const localTables = localConfig.getTables();
1876
+ const validTables = localTables.filter(table => remoteDatabaseIds.has(table.databaseId));
1877
+
1878
+ localConfig.set('tables', validTables);
1879
+
1880
+ const validTablesDBs = localTablesDBs.filter(db => remoteDatabaseIds.has(db.$id));
1881
+ localConfig.set('tablesDB', validTablesDBs);
1882
+
1883
+ success('Configuration resynced successfully.');
1884
+ console.log();
1885
+ }
1886
+
1710
1887
  if (cliConfig.all) {
1711
1888
  checkDeployConditions(localConfig);
1712
1889
  tables.push(...localConfig.getTables());
@@ -1730,39 +1907,6 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
1730
1907
  return;
1731
1908
  }
1732
1909
 
1733
- const databases = Array.from(new Set(tables.map(table => table['databaseId'])));
1734
-
1735
- // Parallel tablesDB actions
1736
- await Promise.all(databases.map(async (databaseId) => {
1737
- const localDatabase = localConfig.getTablesDB(databaseId);
1738
-
1739
- try {
1740
- const database = await tablesDBGet({
1741
- databaseId: databaseId,
1742
- parseOutput: false,
1743
- });
1744
-
1745
- if (database.name !== (localDatabase.name ?? databaseId)) {
1746
- await tablesDBUpdate({
1747
- databaseId: databaseId,
1748
- name: localDatabase.name ?? databaseId,
1749
- parseOutput: false
1750
- })
1751
-
1752
- success(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
1753
- }
1754
- } catch (err) {
1755
- log(`Database ${databaseId} not found. Creating it now ...`);
1756
-
1757
- await tablesDBCreate({
1758
- databaseId: databaseId,
1759
- name: localDatabase.name ?? databaseId,
1760
- parseOutput: false,
1761
- });
1762
- }
1763
- }));
1764
-
1765
-
1766
1910
  if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) {
1767
1911
  return;
1768
1912
  }
package/lib/config.js CHANGED
@@ -681,15 +681,25 @@ class Global extends Config {
681
681
 
682
682
  getSessions() {
683
683
  const sessions = Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key))
684
+ const current = this.getCurrentSession();
684
685
 
685
- return sessions.map((session) => {
686
-
687
- return {
688
- id: session,
689
- endpoint: this.data[session][Global.PREFERENCE_ENDPOINT],
690
- email: this.data[session][Global.PREFERENCE_EMAIL]
686
+ const sessionMap = new Map();
687
+
688
+ sessions.forEach((sessionId) => {
689
+ const email = this.data[sessionId][Global.PREFERENCE_EMAIL];
690
+ const endpoint = this.data[sessionId][Global.PREFERENCE_ENDPOINT];
691
+ const key = `${email}|${endpoint}`;
692
+
693
+ if (sessionId === current || !sessionMap.has(key)) {
694
+ sessionMap.set(key, {
695
+ id: sessionId,
696
+ endpoint: this.data[sessionId][Global.PREFERENCE_ENDPOINT],
697
+ email: this.data[sessionId][Global.PREFERENCE_EMAIL]
698
+ });
691
699
  }
692
- })
700
+ });
701
+
702
+ return Array.from(sessionMap.values());
693
703
  }
694
704
 
695
705
  addSession(session, data) {
package/lib/parser.js CHANGED
@@ -122,7 +122,7 @@ const parseError = (err) => {
122
122
  } catch {
123
123
  }
124
124
 
125
- const version = '10.2.1';
125
+ const version = '10.2.3';
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
 
package/lib/questions.js CHANGED
@@ -496,7 +496,73 @@ const questionsCreateCollection = [
496
496
  {
497
497
  type: "list",
498
498
  name: "documentSecurity",
499
- message: "Enable Document-Security for configuring permissions for individual documents",
499
+ message: "Enable document security for configuring permissions for individual documents",
500
+ choices: ["No", "Yes"]
501
+ }
502
+ ];
503
+
504
+ const questionsCreateTable = [
505
+ {
506
+ type: "list",
507
+ name: "method",
508
+ message: "What database would you like to use for your table?",
509
+ choices: ["New", "Existing"],
510
+ when: async () => {
511
+ return localConfig.getTablesDBs().length !== 0;
512
+ }
513
+ },
514
+ {
515
+ type: "search-list",
516
+ name: "database",
517
+ message: "Choose the table database",
518
+ choices: async () => {
519
+ const databases = localConfig.getTablesDBs();
520
+
521
+ let choices = databases.map((database, idx) => {
522
+ return {
523
+ name: `${database.name} (${database.$id})`,
524
+ value: database.$id
525
+ }
526
+ })
527
+
528
+ if (choices.length === 0) {
529
+ throw new Error("No databases found. Please create one in project console.")
530
+ }
531
+
532
+ return choices;
533
+ },
534
+ when: (answers) => (answers.method ?? '').toLowerCase() === 'existing'
535
+ },
536
+ {
537
+ type: "input",
538
+ name: "databaseName",
539
+ message: "What would you like to name your database?",
540
+ default: "My Awesome Database",
541
+ when: (answers) => (answers.method ?? '').toLowerCase() !== 'existing'
542
+ },
543
+ {
544
+ type: "input",
545
+ name: "databaseId",
546
+ message: "What ID would you like to have for your database?",
547
+ default: "unique()",
548
+ when: (answers) => (answers.method ?? '').toLowerCase() !== 'existing'
549
+ },
550
+ {
551
+ type: "input",
552
+ name: "table",
553
+ message: "What would you like to name your table?",
554
+ default: "My Awesome Table"
555
+ },
556
+ {
557
+ type: "input",
558
+ name: "id",
559
+ message: "What ID would you like to have for your table?",
560
+ default: "unique()"
561
+ },
562
+ {
563
+ type: "list",
564
+ name: "rowSecurity",
565
+ message: "Enable row security for configuring permissions for individual rows",
500
566
  choices: ["No", "Yes"]
501
567
  }
502
568
  ];
@@ -1001,6 +1067,7 @@ module.exports = {
1001
1067
  questionsCreateFunctionSelectTemplate,
1002
1068
  questionsCreateBucket,
1003
1069
  questionsCreateCollection,
1070
+ questionsCreateTable,
1004
1071
  questionsCreateMessagingTopic,
1005
1072
  questionsPullFunctions,
1006
1073
  questionsPullFunctionsCode,
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": "10.2.1",
5
+ "version": "10.2.3",
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": "10.2.1",
3
+ "version": "10.2.3",
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/10.2.1/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.3/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/10.2.1/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.3/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",