appwrite-cli 16.0.0 → 17.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +4 -4
  3. package/cli.ts +6 -0
  4. package/dist/bundle-win-arm64.mjs +1355 -773
  5. package/dist/cli.cjs +1327 -745
  6. package/dist/index.cjs +466 -572
  7. package/dist/index.js +494 -600
  8. package/dist/lib/commands/push.d.ts.map +1 -1
  9. package/dist/lib/commands/run.d.ts.map +1 -1
  10. package/dist/lib/commands/services/organizations.d.ts +3 -0
  11. package/dist/lib/commands/services/organizations.d.ts.map +1 -0
  12. package/dist/lib/commands/services/teams.d.ts.map +1 -1
  13. package/dist/lib/constants.d.ts +1 -1
  14. package/dist/lib/emulation/utils.d.ts.map +1 -1
  15. package/dist/lib/parser.d.ts.map +1 -1
  16. package/dist/lib/questions.d.ts.map +1 -1
  17. package/dist/lib/types.d.ts +1 -0
  18. package/dist/lib/types.d.ts.map +1 -1
  19. package/docs/examples/organizations/add-credit.md +5 -0
  20. package/docs/examples/organizations/cancel-downgrade.md +4 -0
  21. package/docs/examples/organizations/create-downgrade-feedback.md +8 -0
  22. package/docs/examples/organizations/create-invoice-payment.md +6 -0
  23. package/docs/examples/organizations/create-key.md +6 -0
  24. package/docs/examples/organizations/create.md +6 -0
  25. package/docs/examples/organizations/delete-backup-payment-method.md +4 -0
  26. package/docs/examples/organizations/delete-default-payment-method.md +4 -0
  27. package/docs/examples/organizations/delete-key.md +5 -0
  28. package/docs/examples/organizations/delete.md +4 -0
  29. package/docs/examples/organizations/estimation-create-organization.md +4 -0
  30. package/docs/examples/organizations/estimation-delete-organization.md +4 -0
  31. package/docs/examples/organizations/estimation-update-plan.md +5 -0
  32. package/docs/examples/organizations/get-aggregation.md +5 -0
  33. package/docs/examples/organizations/get-available-credits.md +4 -0
  34. package/docs/examples/organizations/get-credit.md +5 -0
  35. package/docs/examples/organizations/get-invoice-download.md +5 -0
  36. package/docs/examples/organizations/get-invoice-view.md +5 -0
  37. package/docs/examples/organizations/get-invoice.md +5 -0
  38. package/docs/examples/organizations/get-key.md +5 -0
  39. package/docs/examples/organizations/get-plan.md +4 -0
  40. package/docs/examples/organizations/get-scopes.md +4 -0
  41. package/docs/examples/organizations/get-usage.md +4 -0
  42. package/docs/examples/organizations/list-aggregations.md +4 -0
  43. package/docs/examples/organizations/list-credits.md +4 -0
  44. package/docs/examples/organizations/list-keys.md +4 -0
  45. package/docs/examples/organizations/list-regions.md +4 -0
  46. package/docs/examples/organizations/list.md +3 -0
  47. package/docs/examples/organizations/set-backup-payment-method.md +5 -0
  48. package/docs/examples/organizations/set-billing-address.md +5 -0
  49. package/docs/examples/organizations/set-billing-email.md +5 -0
  50. package/docs/examples/organizations/set-billing-tax-id.md +5 -0
  51. package/docs/examples/organizations/set-default-payment-method.md +5 -0
  52. package/docs/examples/organizations/update-budget.md +5 -0
  53. package/docs/examples/organizations/update-key.md +7 -0
  54. package/docs/examples/organizations/update-plan.md +5 -0
  55. package/docs/examples/organizations/validate-invoice.md +5 -0
  56. package/docs/examples/organizations/validate-payment.md +4 -0
  57. package/docs/examples/project/create-variable.md +1 -0
  58. package/docs/examples/project/update-variable.md +1 -2
  59. package/docs/examples/users/update-impersonator.md +5 -0
  60. package/install.ps1 +2 -2
  61. package/install.sh +1 -1
  62. package/lib/commands/push.ts +6 -24
  63. package/lib/commands/run.ts +5 -7
  64. package/lib/commands/services/account.ts +0 -169
  65. package/lib/commands/services/health.ts +0 -68
  66. package/lib/commands/services/migrations.ts +2 -2
  67. package/lib/commands/services/organizations.ts +517 -0
  68. package/lib/commands/services/project.ts +21 -12
  69. package/lib/commands/services/projects.ts +2 -14
  70. package/lib/commands/services/proxy.ts +2 -2
  71. package/lib/commands/services/teams.ts +10 -1
  72. package/lib/commands/services/users.ts +14 -1
  73. package/lib/commands/services/vcs.ts +2 -2
  74. package/lib/constants.ts +1 -1
  75. package/lib/emulation/utils.ts +3 -2
  76. package/lib/parser.ts +149 -27
  77. package/lib/questions.ts +15 -9
  78. package/lib/sdks.ts +1 -0
  79. package/lib/types.ts +1 -0
  80. package/package.json +1 -1
  81. package/scoop/appwrite.config.json +3 -3
@@ -29,7 +29,7 @@ export const users = new Command("users")
29
29
  users
30
30
  .command(`list`)
31
31
  .description(`Get a list of all the project's users. You can use the query params to filter your results.`)
32
- .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels`)
32
+ .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels, impersonator`)
33
33
  .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`)
34
34
  .option(
35
35
  `--total [value]`,
@@ -241,6 +241,19 @@ users
241
241
  ),
242
242
  );
243
243
 
244
+ users
245
+ .command(`update-impersonator`)
246
+ .description(`Enable or disable whether a user can impersonate other users. When impersonation headers are used, the request runs as the target user for API behavior, while internal audit logs still attribute the action to the original impersonator and store the impersonated target details only in internal audit payload data.
247
+ `)
248
+ .requiredOption(`--user-id <user-id>`, `User ID.`)
249
+ .requiredOption(`--impersonator <impersonator>`, `Whether the user can impersonate other users. When true, the user can browse project users to choose a target and can pass impersonation headers to act as that user. Internal audit logs still attribute impersonated actions to the original impersonator and store the target user details only in internal audit payload data.`, parseBool)
250
+ .action(
251
+ actionRunner(
252
+ async ({ userId, impersonator }) =>
253
+ parse(await (await getUsersClient()).updateImpersonator(userId, impersonator)),
254
+ ),
255
+ );
256
+
244
257
  users
245
258
  .command(`create-jwt`)
246
259
  .description(`Use this endpoint to create a JSON Web Token for user by its unique ID. You can use the resulting JWT to authenticate on behalf of the user. The JWT secret will become invalid if the session it uses gets deleted.`)
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import { sdkForProject } from "../../sdks.js";
2
+ import { sdkForConsole } from "../../sdks.js";
3
3
  import {
4
4
  actionRunner,
5
5
  commandDescriptions,
@@ -14,7 +14,7 @@ let vcsClient: Vcs | null = null;
14
14
 
15
15
  const getVcsClient = async (): Promise<Vcs> => {
16
16
  if (!vcsClient) {
17
- const sdkClient = await sdkForProject();
17
+ const sdkClient = await sdkForConsole();
18
18
  vcsClient = new Vcs(sdkClient);
19
19
  }
20
20
  return vcsClient;
package/lib/constants.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // SDK
2
2
  export const SDK_TITLE = 'Appwrite';
3
3
  export const SDK_TITLE_LOWER = 'appwrite';
4
- export const SDK_VERSION = '16.0.0';
4
+ export const SDK_VERSION = '17.1.0';
5
5
  export const SDK_NAME = 'Command Line';
6
6
  export const SDK_PLATFORM = 'console';
7
7
  export const SDK_LANGUAGE = 'cli';
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import { localConfig } from "../config.js";
3
3
  import { log } from "../parser.js";
4
- import { sdkForConsole } from "../sdks.js";
4
+ import { sdkForConsole, sdkForProject } from "../sdks.js";
5
5
  import { Projects, Scopes, Users } from "@appwrite.io/console";
6
6
 
7
7
  export const openRuntimesVersion = "v4";
@@ -108,7 +108,6 @@ export const JwtManager = {
108
108
  projectScopes: Scopes[] = [],
109
109
  ): Promise<void> {
110
110
  const consoleClient = await sdkForConsole();
111
- const usersClient = new Users(consoleClient);
112
111
  const projectsClient = new Projects(consoleClient);
113
112
 
114
113
  if (this.timerWarn) {
@@ -139,6 +138,8 @@ export const JwtManager = {
139
138
  ); // 60 mins
140
139
 
141
140
  if (userId) {
141
+ const projectClient = await sdkForProject();
142
+ const usersClient = new Users(projectClient);
142
143
  await usersClient.get({
143
144
  userId,
144
145
  });
package/lib/parser.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // @ts-expect-error BigInt toJSON polyfill for JSON.stringify support
2
+ BigInt.prototype.toJSON = function () { return this.toString(); };
3
+
1
4
  import chalk from "chalk";
2
5
  import { InvalidArgumentError } from "commander";
3
6
  import Table from "cli-table3";
@@ -18,6 +21,7 @@ import {
18
21
  const cliConfig: CliConfig = {
19
22
  verbose: false,
20
23
  json: false,
24
+ raw: false,
21
25
  force: false,
22
26
  all: false,
23
27
  ids: [],
@@ -54,36 +58,118 @@ const extractReportCommandArgs = (value: unknown): string[] => {
54
58
  return reportData.data.args;
55
59
  };
56
60
 
61
+ const filterObject = (obj: JsonObject): JsonObject => {
62
+ const result: JsonObject = {};
63
+ for (const key of Object.keys(obj)) {
64
+ const value = obj[key];
65
+ if (typeof value === "function") continue;
66
+ if (value == null) continue;
67
+ if (value?.constructor?.name === "BigNumber") {
68
+ result[key] = String(value);
69
+ continue;
70
+ }
71
+ if (typeof value === "object") continue;
72
+ if (typeof value === "string" && value.trim() === "") continue;
73
+ result[key] = value;
74
+ }
75
+ return result;
76
+ };
77
+
78
+ const filterData = (data: JsonObject): JsonObject => {
79
+ const result: JsonObject = {};
80
+ for (const key of Object.keys(data)) {
81
+ const value = data[key];
82
+ if (typeof value === "function") continue;
83
+ if (value == null) continue;
84
+ if (value?.constructor?.name === "BigNumber") {
85
+ result[key] = String(value);
86
+ continue;
87
+ }
88
+ if (Array.isArray(value)) {
89
+ result[key] = value.map((item) => {
90
+ if (item?.constructor?.name === "BigNumber") return String(item);
91
+ return item && typeof item === "object" && !Array.isArray(item)
92
+ ? filterObject(item as JsonObject)
93
+ : item;
94
+ });
95
+ } else if (typeof value === "object") {
96
+ continue;
97
+ } else if (typeof value === "string" && value.trim() === "") {
98
+ continue;
99
+ } else {
100
+ result[key] = value;
101
+ }
102
+ }
103
+ return result;
104
+ };
105
+
57
106
  export const parse = (data: JsonObject): void => {
58
- if (cliConfig.json) {
107
+ if (cliConfig.raw) {
59
108
  drawJSON(data);
60
109
  return;
61
110
  }
62
111
 
63
- for (const key in data) {
64
- if (data[key] === null) {
112
+ if (cliConfig.json) {
113
+ drawJSON(filterData(data));
114
+ return;
115
+ }
116
+
117
+ const keys = Object.keys(data).filter((k) => typeof data[k] !== "function");
118
+ let printedScalar = false;
119
+
120
+ for (const key of keys) {
121
+ const value = data[key];
122
+ if (value === null) {
65
123
  console.log(`${chalk.yellow.bold(key)} : null`);
66
- } else if (Array.isArray(data[key])) {
124
+ printedScalar = true;
125
+ } else if (Array.isArray(value)) {
126
+ if (printedScalar) console.log("");
67
127
  console.log(`${chalk.yellow.bold.underline(key)}`);
68
- if (typeof data[key][0] === "object") {
69
- drawTable(data[key]);
128
+ if (typeof value[0] === "object") {
129
+ drawTable(value);
70
130
  } else {
71
- drawJSON(data[key]);
131
+ drawJSON(value);
72
132
  }
73
- } else if (typeof data[key] === "object") {
74
- if (data[key]?.constructor?.name === "BigNumber") {
75
- console.log(`${chalk.yellow.bold(key)} : ${data[key]}`);
133
+ printedScalar = false;
134
+ } else if (typeof value === "object") {
135
+ if (printedScalar) console.log("");
136
+ if (value?.constructor?.name === "BigNumber") {
137
+ console.log(`${chalk.yellow.bold(key)} : ${value}`);
138
+ printedScalar = true;
76
139
  } else {
77
140
  console.log(`${chalk.yellow.bold.underline(key)}`);
78
- const tableRow = toJsonObject(data[key]) ?? {};
141
+ const tableRow = toJsonObject(value) ?? {};
79
142
  drawTable([tableRow]);
143
+ printedScalar = false;
80
144
  }
81
145
  } else {
82
- console.log(`${chalk.yellow.bold(key)} : ${data[key]}`);
146
+ console.log(`${chalk.yellow.bold(key)} : ${value}`);
147
+ printedScalar = true;
83
148
  }
84
149
  }
85
150
  };
86
151
 
152
+ const MAX_COL_WIDTH = 40;
153
+
154
+ const formatCellValue = (value: unknown): string => {
155
+ if (value == null) return "-";
156
+ if (Array.isArray(value)) {
157
+ if (value.length === 0) return "[]";
158
+ return `[${value.length} items]`;
159
+ }
160
+ if (typeof value === "object") {
161
+ if (value?.constructor?.name === "BigNumber") return String(value);
162
+ const keys = Object.keys(value as Record<string, unknown>);
163
+ if (keys.length === 0) return "{}";
164
+ return `{${keys.length} keys}`;
165
+ }
166
+ const str = String(value);
167
+ if (str.length > MAX_COL_WIDTH) {
168
+ return str.slice(0, MAX_COL_WIDTH - 1) + "…";
169
+ }
170
+ return str;
171
+ };
172
+
87
173
  export const drawTable = (data: Array<JsonObject | null | undefined>): void => {
88
174
  if (data.length == 0) {
89
175
  console.log("[]");
@@ -95,23 +181,67 @@ export const drawTable = (data: Array<JsonObject | null | undefined>): void => {
95
181
  // Create an object with all the keys in it
96
182
  const obj = rows.reduce((res, item) => ({ ...res, ...item }), {});
97
183
  // Get those keys as an array
98
- const keys = Object.keys(obj);
99
- if (keys.length === 0) {
184
+ const allKeys = Object.keys(obj);
185
+ if (allKeys.length === 0) {
100
186
  drawJSON(data);
101
187
  return;
102
188
  }
189
+
190
+ // If too many columns, show condensed key-value output with only scalar, non-empty fields
191
+ const maxColumns = 6;
192
+ if (allKeys.length > maxColumns) {
193
+ // Collect visible entries per row to compute alignment
194
+ const rowEntries = rows.map((row) => {
195
+ const entries: Array<[string, string]> = [];
196
+ for (const key of Object.keys(row)) {
197
+ const value = row[key];
198
+ if (typeof value === "function") continue;
199
+ if (value == null) continue;
200
+ if (value?.constructor?.name === "BigNumber") {
201
+ entries.push([key, String(value)]);
202
+ continue;
203
+ }
204
+ if (typeof value === "object") continue;
205
+ if (typeof value === "string" && value.trim() === "") continue;
206
+ entries.push([key, String(value)]);
207
+ }
208
+ return entries;
209
+ });
210
+
211
+ const flatEntries = rowEntries.flat();
212
+ if (flatEntries.length === 0) {
213
+ drawJSON(data);
214
+ return;
215
+ }
216
+
217
+ const maxKeyLen = Math.max(...flatEntries.map(([key]) => key.length));
218
+
219
+ const separatorLen = Math.min(maxKeyLen + 2 + MAX_COL_WIDTH, process.stdout.columns || 80);
220
+
221
+ rowEntries.forEach((entries, idx) => {
222
+ if (idx > 0) console.log(chalk.cyan("─".repeat(separatorLen)));
223
+ for (const [key, value] of entries) {
224
+ const paddedKey = key.padEnd(maxKeyLen);
225
+ console.log(`${chalk.yellow.bold(paddedKey)} ${value}`);
226
+ }
227
+ });
228
+ return;
229
+ }
230
+
231
+ const columns = allKeys;
232
+
103
233
  // Create an object with all keys set to the default value ''
104
- const def = keys.reduce((result: Record<string, string>, key) => {
234
+ const def = allKeys.reduce((result: Record<string, string>, key) => {
105
235
  result[key] = "-";
106
236
  return result;
107
237
  }, {});
108
238
  // Use object destructuring to replace all default values with the ones we have
109
239
  const normalizedData = rows.map((item) => ({ ...def, ...item }));
110
240
 
111
- const columns = Object.keys(normalizedData[0]);
112
-
113
241
  const table = new Table({
114
242
  head: columns.map((c) => chalk.cyan.italic.bold(c)),
243
+ colWidths: columns.map(() => null) as (number | null)[],
244
+ wordWrap: false,
115
245
  chars: {
116
246
  top: " ",
117
247
  "top-mid": " ",
@@ -134,15 +264,7 @@ export const drawTable = (data: Array<JsonObject | null | undefined>): void => {
134
264
  normalizedData.forEach((row) => {
135
265
  const rowValues: string[] = [];
136
266
  for (const key of columns) {
137
- if (row[key] == null) {
138
- rowValues.push("-");
139
- } else if (Array.isArray(row[key])) {
140
- rowValues.push(JSON.stringify(row[key]));
141
- } else if (typeof row[key] === "object") {
142
- rowValues.push(JSON.stringify(row[key]));
143
- } else {
144
- rowValues.push(String(row[key]));
145
- }
267
+ rowValues.push(formatCellValue(row[key]));
146
268
  }
147
269
  table.push(rowValues);
148
270
  });
@@ -291,7 +413,7 @@ export const commandDescriptions: Record<string, string> = {
291
413
  locale: `The locale command allows you to customize your app based on your users' location.`,
292
414
  sites: `The sites command allows you to view, create and manage your Appwrite Sites.`,
293
415
  storage: `The storage command allows you to manage your project files.`,
294
- teams: `The teams command allows you to group users of your project to enable them to share read and write access to your project resources.`,
416
+ teams: `The teams command allows you to group users of your project to enable them to share read and write access to your project resources. Requires a linked project. To manage console-level teams, use the 'organizations' command instead.`,
295
417
  update: `The update command allows you to update the ${SDK_TITLE} CLI to the latest version.`,
296
418
  users: `The users command allows you to manage your project users.`,
297
419
  projects: `The projects command allows you to manage your projects, add platforms, manage API keys, Dev Keys etc.`,
package/lib/questions.ts CHANGED
@@ -187,15 +187,19 @@ export const questionsInitProject: Question[] = [
187
187
  const client = await sdkForConsole(true);
188
188
  const { teams } = isCloud()
189
189
  ? await paginate(
190
- async (opts: { sdk?: Client } = {}) =>
191
- (await getOrganizationsService(opts.sdk)).list(),
190
+ async (args) =>
191
+ (await getOrganizationsService(args.sdk as Client)).list({
192
+ queries: args.queries as string[],
193
+ }),
192
194
  { sdk: client },
193
195
  100,
194
196
  "teams",
195
197
  )
196
198
  : await paginate(
197
- async (opts: { sdk?: Client } = {}) =>
198
- (await getTeamsService(opts.sdk)).list(),
199
+ async (args) =>
200
+ (await getTeamsService(args.sdk as Client)).list({
201
+ queries: args.queries as string[],
202
+ }),
199
203
  { parseOutput: false, sdk: client },
200
204
  100,
201
205
  "teams",
@@ -223,14 +227,14 @@ export const questionsInitProject: Question[] = [
223
227
  name: "project",
224
228
  message: "What would you like to name your project?",
225
229
  default: "My Awesome Project",
226
- when: (answer: Answers) => answer.start !== "existing",
230
+ when: (answer: Answers) => whenOverride(answer) && answer.start !== "existing",
227
231
  },
228
232
  {
229
233
  type: "input",
230
234
  name: "id",
231
235
  message: "What ID would you like to have for your project?",
232
236
  default: "unique()",
233
- when: (answer: Answers) => answer.start !== "existing",
237
+ when: (answer: Answers) => whenOverride(answer) && answer.start !== "existing",
234
238
  },
235
239
  {
236
240
  type: "search-list",
@@ -247,7 +251,7 @@ export const questionsInitProject: Question[] = [
247
251
  ];
248
252
 
249
253
  const { projects } = await paginate(
250
- async () => (await getProjectsService()).list(queries),
254
+ async (args) => (await getProjectsService()).list(args.queries as string[]),
251
255
  { parseOutput: false },
252
256
  100,
253
257
  "projects",
@@ -342,7 +346,8 @@ export const questionsPullFunctions: Question[] = [
342
346
  validate: (value: any) => validateRequired("function", value),
343
347
  choices: async () => {
344
348
  const { functions } = await paginate(
345
- async () => (await getFunctionsService()).list(),
349
+ async (args) =>
350
+ (await getFunctionsService()).list(args.queries as string[]),
346
351
  { parseOutput: false },
347
352
  100,
348
353
  "functions",
@@ -385,7 +390,8 @@ export const questionsPullSites: Question[] = [
385
390
  validate: (value: any) => validateRequired("site", value),
386
391
  choices: async () => {
387
392
  const { sites } = await paginate(
388
- async () => (await getSitesService()).list(),
393
+ async (args) =>
394
+ (await getSitesService()).list(args.queries as string[]),
389
395
  { parseOutput: false },
390
396
  100,
391
397
  "sites",
package/lib/sdks.ts CHANGED
@@ -88,3 +88,4 @@ export const sdkForProject = async (): Promise<Client> => {
88
88
  `Session not found. Please run \`${EXECUTABLE_NAME} login\` to create a session.`,
89
89
  );
90
90
  };
91
+
package/lib/types.ts CHANGED
@@ -52,6 +52,7 @@ export interface CommandDescription {
52
52
  export interface CliConfig {
53
53
  verbose: boolean;
54
54
  json: boolean;
55
+ raw: boolean;
55
56
  force: boolean;
56
57
  all: boolean;
57
58
  ids: string[];
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "homepage": "https://appwrite.io/support",
5
5
  "description": "Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API",
6
- "version": "16.0.0",
6
+ "version": "17.1.0",
7
7
  "license": "BSD-3-Clause",
8
8
  "main": "dist/index.cjs",
9
9
  "module": "dist/index.js",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json",
3
- "version": "16.0.0",
3
+ "version": "17.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/16.0.0/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/17.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/16.0.0/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/17.1.0/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",