appwrite-cli 13.6.0 → 13.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +2 -2
  3. package/cli.ts +3 -3
  4. package/dist/bundle-win-arm64.mjs +336 -212
  5. package/dist/cli.cjs +336 -212
  6. package/dist/index.cjs +156 -104
  7. package/dist/index.js +156 -104
  8. package/dist/lib/commands/config-validations.d.ts +1 -1
  9. package/dist/lib/commands/config-validations.d.ts.map +1 -1
  10. package/dist/lib/commands/errors.d.ts +4 -4
  11. package/dist/lib/commands/errors.d.ts.map +1 -1
  12. package/dist/lib/commands/generate.d.ts.map +1 -1
  13. package/dist/lib/commands/generators/base.d.ts +5 -0
  14. package/dist/lib/commands/generators/base.d.ts.map +1 -1
  15. package/dist/lib/commands/generic.d.ts.map +1 -1
  16. package/dist/lib/commands/init.d.ts.map +1 -1
  17. package/dist/lib/commands/run.d.ts.map +1 -1
  18. package/dist/lib/commands/types.d.ts.map +1 -1
  19. package/dist/lib/commands/update.d.ts.map +1 -1
  20. package/dist/lib/commands/utils/change-approval.d.ts +3 -3
  21. package/dist/lib/commands/utils/change-approval.d.ts.map +1 -1
  22. package/dist/lib/commands/utils/database-sync.d.ts.map +1 -1
  23. package/dist/lib/commands/utils/deployment.d.ts +16 -4
  24. package/dist/lib/commands/utils/deployment.d.ts.map +1 -1
  25. package/dist/lib/commands/utils/pools.d.ts.map +1 -1
  26. package/dist/lib/constants.d.ts +1 -1
  27. package/dist/lib/emulation/docker.d.ts.map +1 -1
  28. package/dist/lib/json.d.ts +1 -1
  29. package/dist/lib/json.d.ts.map +1 -1
  30. package/dist/lib/paginate.d.ts +5 -6
  31. package/dist/lib/paginate.d.ts.map +1 -1
  32. package/dist/lib/parser.d.ts +5 -4
  33. package/dist/lib/parser.d.ts.map +1 -1
  34. package/dist/lib/spinner.d.ts +1 -1
  35. package/dist/lib/spinner.d.ts.map +1 -1
  36. package/dist/lib/utils.d.ts +6 -1
  37. package/dist/lib/utils.d.ts.map +1 -1
  38. package/dist/lib/validations.d.ts +1 -1
  39. package/dist/lib/validations.d.ts.map +1 -1
  40. package/eslint.config.js +45 -0
  41. package/install.ps1 +2 -2
  42. package/install.sh +1 -1
  43. package/lib/client.ts +3 -3
  44. package/lib/commands/config-validations.ts +1 -1
  45. package/lib/commands/config.ts +2 -2
  46. package/lib/commands/errors.ts +2 -2
  47. package/lib/commands/generate.ts +8 -6
  48. package/lib/commands/generators/base.ts +6 -0
  49. package/lib/commands/generators/typescript/databases.ts +9 -9
  50. package/lib/commands/generators/typescript/templates/databases.ts.hbs +16 -16
  51. package/lib/commands/generic.ts +21 -16
  52. package/lib/commands/init.ts +147 -61
  53. package/lib/commands/pull.ts +1 -1
  54. package/lib/commands/push.ts +19 -19
  55. package/lib/commands/run.ts +15 -9
  56. package/lib/commands/types.ts +18 -8
  57. package/lib/commands/update.ts +24 -16
  58. package/lib/commands/utils/attributes.ts +6 -6
  59. package/lib/commands/utils/change-approval.ts +26 -19
  60. package/lib/commands/utils/database-sync.ts +58 -18
  61. package/lib/commands/utils/deployment.ts +22 -5
  62. package/lib/commands/utils/pools.ts +11 -5
  63. package/lib/config.ts +1 -1
  64. package/lib/constants.ts +1 -1
  65. package/lib/emulation/docker.ts +5 -6
  66. package/lib/emulation/utils.ts +2 -2
  67. package/lib/json.ts +15 -7
  68. package/lib/paginate.ts +30 -20
  69. package/lib/parser.ts +46 -15
  70. package/lib/questions.ts +38 -38
  71. package/lib/spinner.ts +5 -1
  72. package/lib/utils.ts +15 -3
  73. package/lib/validations.ts +1 -1
  74. package/package.json +7 -1
  75. package/scoop/appwrite.config.json +3 -3
@@ -1,5 +1,5 @@
1
1
  import { Client, TablesDB, ID, Query, type Models, Permission, Role } from '{{appwriteDep}}';
2
- import type { DatabaseHandle, DatabaseId, DatabaseTableMap, DatabaseTables, QueryBuilder, PermissionBuilder, RoleBuilder, RoleString } from './types{{importExt}}';
2
+ import type { DatabaseHandle, DatabaseId, DatabaseTableMap, DatabaseTables, QueryBuilder, QueryValue, PermissionBuilder, RoleBuilder, RoleString } from './types{{importExt}}';
3
3
  {{#if supportsServerSide}}
4
4
  import { PROJECT_ID, ENDPOINT, API_KEY } from './constants{{importExt}}';
5
5
  {{else}}
@@ -7,19 +7,19 @@ import { PROJECT_ID, ENDPOINT } from './constants{{importExt}}';
7
7
  {{/if}}
8
8
 
9
9
  const createQueryBuilder = <T>(): QueryBuilder<T> => ({
10
- equal: (field, value) => Query.equal(String(field), value as any),
11
- notEqual: (field, value) => Query.notEqual(String(field), value as any),
12
- lessThan: (field, value) => Query.lessThan(String(field), value as any),
13
- lessThanEqual: (field, value) => Query.lessThanEqual(String(field), value as any),
14
- greaterThan: (field, value) => Query.greaterThan(String(field), value as any),
15
- greaterThanEqual: (field, value) => Query.greaterThanEqual(String(field), value as any),
16
- contains: (field, value) => Query.contains(String(field), value as any),
10
+ equal: (field, value) => Query.equal(String(field), value as QueryValue),
11
+ notEqual: (field, value) => Query.notEqual(String(field), value as QueryValue),
12
+ lessThan: (field, value) => Query.lessThan(String(field), value as QueryValue),
13
+ lessThanEqual: (field, value) => Query.lessThanEqual(String(field), value as QueryValue),
14
+ greaterThan: (field, value) => Query.greaterThan(String(field), value as QueryValue),
15
+ greaterThanEqual: (field, value) => Query.greaterThanEqual(String(field), value as QueryValue),
16
+ contains: (field, value) => Query.contains(String(field), value as string | QueryValue[]),
17
17
  search: (field, value) => Query.search(String(field), value),
18
18
  isNull: (field) => Query.isNull(String(field)),
19
19
  isNotNull: (field) => Query.isNotNull(String(field)),
20
20
  startsWith: (field, value) => Query.startsWith(String(field), value),
21
21
  endsWith: (field, value) => Query.endsWith(String(field), value),
22
- between: (field, start, end) => Query.between(String(field), start as any, end as any),
22
+ between: (field, start, end) => Query.between(String(field), start as string | number, end as string | number),
23
23
  select: (fields) => Query.select(fields.map(String)),
24
24
  orderAsc: (field) => Query.orderAsc(String(field)),
25
25
  orderDesc: (field) => Query.orderDesc(String(field)),
@@ -62,12 +62,12 @@ function createTableApi<T extends Models.Row>(
62
62
  tableId: string,
63
63
  ) {
64
64
  return {
65
- create: (data: any, options?: { rowId?: string; permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>
65
+ create: (data: Omit<T, keyof Models.Row>, options?: { rowId?: string; permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>
66
66
  tablesDB.createRow<T>({
67
67
  databaseId,
68
68
  tableId,
69
69
  rowId: options?.rowId ?? ID.unique(),
70
- data,
70
+ data: data as T extends Models.DefaultRow ? Partial<Models.Row> & Record<string, unknown> : Partial<Models.Row> & Omit<T, keyof Models.Row>,
71
71
  permissions: resolvePermissions(options?.permissions),
72
72
  transactionId: options?.transactionId,
73
73
  }),
@@ -77,12 +77,12 @@ function createTableApi<T extends Models.Row>(
77
77
  tableId,
78
78
  rowId: id,
79
79
  }),
80
- update: (id: string, data: any, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>
80
+ update: (id: string, data: Partial<Omit<T, keyof Models.Row>>, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>
81
81
  tablesDB.updateRow<T>({
82
82
  databaseId,
83
83
  tableId,
84
84
  rowId: id,
85
- data,
85
+ data: data as T extends Models.DefaultRow ? Partial<Models.Row> & Record<string, unknown> : Partial<Models.Row> & Partial<Omit<T, keyof Models.Row>>,
86
86
  ...(options?.permissions ? { permissions: resolvePermissions(options.permissions) } : {}),
87
87
  transactionId: options?.transactionId,
88
88
  }),
@@ -94,7 +94,7 @@ function createTableApi<T extends Models.Row>(
94
94
  transactionId: options?.transactionId,
95
95
  });
96
96
  },
97
- list: (options?: { queries?: (q: any) => string[] }) =>
97
+ list: (options?: { queries?: (q: QueryBuilder<T>) => string[] }) =>
98
98
  tablesDB.listRows<T>({
99
99
  databaseId,
100
100
  tableId,
@@ -129,7 +129,7 @@ function createDatabaseHandle<D extends DatabaseId>(
129
129
  return tableApiCache.get(tableId) as DatabaseTableMap[D][T];
130
130
  },
131
131
  {{#if supportsServerSide}}
132
- create: (tableId: string, name: string, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; rowSecurity?: boolean; enabled?: boolean; columns?: any[]; indexes?: any[] }) =>
132
+ create: (tableId: string, name: string, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; rowSecurity?: boolean; enabled?: boolean; columns?: object[]; indexes?: object[] }) =>
133
133
  tablesDB.createTable({
134
134
  databaseId,
135
135
  tableId,
@@ -148,7 +148,7 @@ function createDatabaseHandle<D extends DatabaseId>(
148
148
  return tablesDB.updateTable({
149
149
  databaseId,
150
150
  tableId: resolvedTableId,
151
- name: options?.name ?? tableId, // TODO: remove this fallback once fixed in other SDKs
151
+ name: options?.name,
152
152
  permissions: resolvePermissions(options?.permissions),
153
153
  rowSecurity: options?.rowSecurity,
154
154
  enabled: options?.enabled,
@@ -28,9 +28,14 @@ import ClientLegacy from "../client.js";
28
28
 
29
29
  const DEFAULT_ENDPOINT = "https://cloud.appwrite.io/v1";
30
30
 
31
- const isMfaRequiredError = (err: any): boolean =>
32
- err?.type === "user_more_factors_required" ||
33
- err?.response === "user_more_factors_required";
31
+ interface AppwriteError {
32
+ type?: string;
33
+ response?: string;
34
+ }
35
+
36
+ const isMfaRequiredError = (err: unknown): err is AppwriteError =>
37
+ (err as AppwriteError)?.type === "user_more_factors_required" ||
38
+ (err as AppwriteError)?.response === "user_more_factors_required";
34
39
 
35
40
  const createLegacyConsoleClient = (endpoint: string): ClientLegacy => {
36
41
  const legacyClient = new ClientLegacy();
@@ -52,7 +57,7 @@ const completeMfaLogin = async ({
52
57
  legacyClient: ClientLegacy;
53
58
  mfa?: string;
54
59
  code?: string;
55
- }): Promise<any> => {
60
+ }): Promise<unknown> => {
56
61
  let accountClient = new Account(client);
57
62
 
58
63
  const savedCookie = globalConfig.getCookie();
@@ -92,11 +97,11 @@ const completeMfaLogin = async ({
92
97
 
93
98
  const deleteServerSession = async (sessionId: string): Promise<boolean> => {
94
99
  try {
95
- let client = await sdkForConsole();
96
- let accountClient = new Account(client);
100
+ const client = await sdkForConsole();
101
+ const accountClient = new Account(client);
97
102
  await accountClient.deleteSession(sessionId);
98
103
  return true;
99
- } catch (e) {
104
+ } catch (_e) {
100
105
  return false;
101
106
  }
102
107
  };
@@ -206,7 +211,7 @@ export const loginCommand = async ({
206
211
 
207
212
  try {
208
213
  await accountClient.get();
209
- } catch (err: any) {
214
+ } catch (err) {
210
215
  if (!isMfaRequiredError(err)) {
211
216
  throw err;
212
217
  }
@@ -234,7 +239,7 @@ export const loginCommand = async ({
234
239
  // Use legacy client for login to extract cookies from response
235
240
  const legacyClient = createLegacyConsoleClient(configEndpoint);
236
241
 
237
- let client = await sdkForConsole(false);
242
+ const client = await sdkForConsole(false);
238
243
  let accountClient = new Account(client);
239
244
 
240
245
  let account;
@@ -261,7 +266,7 @@ export const loginCommand = async ({
261
266
 
262
267
  accountClient = new Account(client);
263
268
  account = await accountClient.get();
264
- } catch (err: any) {
269
+ } catch (err) {
265
270
  if (isMfaRequiredError(err)) {
266
271
  account = await completeMfaLogin({
267
272
  client,
@@ -301,8 +306,8 @@ export const whoami = new Command("whoami")
301
306
  return;
302
307
  }
303
308
 
304
- let client = await sdkForConsole(false);
305
- let accountClient = new Account(client);
309
+ const client = await sdkForConsole(false);
310
+ const accountClient = new Account(client);
306
311
 
307
312
  let account;
308
313
 
@@ -501,7 +506,7 @@ export const client = new Command("client")
501
506
  : cookieValue || "********";
502
507
  maskedCookie = `${cookieName}=...${tail}`;
503
508
  }
504
- let config = {
509
+ const config = {
505
510
  endpoint: globalConfig.getEndpoint(),
506
511
  key: maskedKey,
507
512
  cookie: maskedCookie,
@@ -515,17 +520,17 @@ export const client = new Command("client")
515
520
  if (endpoint !== undefined) {
516
521
  try {
517
522
  const id = ID.unique();
518
- let url = new URL(endpoint);
523
+ const url = new URL(endpoint);
519
524
  if (url.protocol !== "http:" && url.protocol !== "https:") {
520
525
  throw new Error();
521
526
  }
522
527
 
523
- let clientInstance = new Client().setEndpoint(endpoint);
528
+ const clientInstance = new Client().setEndpoint(endpoint);
524
529
  clientInstance.setProject("console");
525
530
  if (selfSigned || globalConfig.getSelfSigned()) {
526
531
  clientInstance.setSelfSigned(true);
527
532
  }
528
- let response = (await clientInstance.call(
533
+ const response = (await clientInstance.call(
529
534
  "GET",
530
535
  new URL(endpoint + "/health/version"),
531
536
  )) as { version?: string };
@@ -31,11 +31,57 @@ import {
31
31
  } from "../parser.js";
32
32
  import { sdkForConsole } from "../sdks.js";
33
33
  import { isCloud } from "../utils.js";
34
- import { Account, UseCases } from "@appwrite.io/console";
34
+ import { Account, UseCases, AppwriteException } from "@appwrite.io/console";
35
35
  import { DEFAULT_ENDPOINT, EXECUTABLE_NAME } from "../constants.js";
36
36
 
37
+ type InitResourceAction = (_options?: unknown) => Promise<void>;
38
+ type ProjectsService = Awaited<ReturnType<typeof getProjectsService>>;
39
+ type ProjectCreateRegion = Parameters<ProjectsService["create"]>[3];
40
+
41
+ interface ExistingProjectSummary {
42
+ $id: string;
43
+ name?: string;
44
+ region?: string;
45
+ }
46
+
47
+ interface InitProjectAnswers {
48
+ start: "new" | "existing";
49
+ override?: boolean;
50
+ id?: string;
51
+ project: string | ExistingProjectSummary;
52
+ organization: string;
53
+ region?: ProjectCreateRegion;
54
+ }
55
+
56
+ interface InitProjectAutopullAnswer {
57
+ autopull?: boolean;
58
+ }
59
+
60
+ interface SiteTemplateFramework {
61
+ providerRootDirectory: string;
62
+ adapter?: string;
63
+ buildRuntime?: string;
64
+ installCommand?: string;
65
+ buildCommand?: string;
66
+ outputDirectory?: string;
67
+ fallbackFile?: string;
68
+ }
69
+
70
+ interface SiteTemplateVariable {
71
+ name: string;
72
+ value?: string;
73
+ }
74
+
75
+ interface SiteTemplateDetails {
76
+ providerOwner: string;
77
+ providerRepositoryId: string;
78
+ providerVersion: string;
79
+ frameworks: SiteTemplateFramework[];
80
+ variables?: SiteTemplateVariable[];
81
+ }
82
+
37
83
  const initResources = async (): Promise<void> => {
38
- const actions: Record<string, (options?: any) => Promise<void>> = {
84
+ const actions: Record<string, InitResourceAction> = {
39
85
  function: initFunction,
40
86
  site: initSite,
41
87
  table: initTable,
@@ -64,8 +110,6 @@ const initProject = async ({
64
110
  projectId,
65
111
  projectName,
66
112
  }: InitProjectOptions = {}): Promise<void> => {
67
- let response: any = {};
68
-
69
113
  try {
70
114
  if (globalConfig.getEndpoint() === "" || globalConfig.getCookie() === "") {
71
115
  throw new Error(
@@ -76,14 +120,14 @@ const initProject = async ({
76
120
  const accountClient = new Account(client);
77
121
 
78
122
  await accountClient.get();
79
- } catch (e) {
123
+ } catch (_e) {
80
124
  error(
81
125
  `Error Session not found. Please run '${EXECUTABLE_NAME} login' to create a session`,
82
126
  );
83
127
  process.exit(1);
84
128
  }
85
129
 
86
- let answers: any = {};
130
+ let answers: InitProjectAnswers;
87
131
 
88
132
  if (!organizationId && !projectId && !projectName) {
89
133
  answers = await inquirer.prompt(questionsInitProject);
@@ -91,26 +135,33 @@ const initProject = async ({
91
135
  process.exit(1);
92
136
  }
93
137
  } else {
94
- answers.start = "existing";
95
- answers.project = {};
96
- answers.organization = {};
97
-
98
- answers.organization =
138
+ const selectedOrganization =
99
139
  organizationId ??
100
140
  (await inquirer.prompt([questionsInitProject[2]])).organization;
101
- answers.project.name =
141
+ const selectedProjectName =
102
142
  projectName ?? (await inquirer.prompt([questionsInitProject[3]])).project;
103
- answers.project =
143
+ const selectedProjectId =
104
144
  projectId ?? (await inquirer.prompt([questionsInitProject[4]])).id;
105
145
 
146
+ answers = {
147
+ start: "existing",
148
+ project: selectedProjectId,
149
+ organization: selectedOrganization,
150
+ };
151
+
106
152
  try {
107
153
  const projectsService = await getProjectsService();
108
- await projectsService.get(projectId);
109
- } catch (e: any) {
110
- if (e.code === 404) {
111
- answers.start = "new";
112
- answers.id = answers.project;
113
- answers.project = answers.project.name;
154
+ const existingProject: ExistingProjectSummary =
155
+ await projectsService.get(selectedProjectId);
156
+ answers.project = existingProject;
157
+ } catch (e) {
158
+ if (e instanceof AppwriteException && e.code === 404) {
159
+ answers = {
160
+ start: "new",
161
+ id: selectedProjectId,
162
+ project: selectedProjectName,
163
+ organization: selectedOrganization,
164
+ };
114
165
  } else {
115
166
  throw e;
116
167
  }
@@ -121,10 +172,28 @@ const initProject = async ({
121
172
  const url = new URL(DEFAULT_ENDPOINT);
122
173
 
123
174
  if (answers.start === "new") {
175
+ let projectIdToCreate;
176
+ let projectNameToCreate;
177
+
178
+ switch (typeof answers.project) {
179
+ case "string":
180
+ projectIdToCreate = answers.id ?? answers.project;
181
+ projectNameToCreate = answers.project;
182
+ break;
183
+ case "object":
184
+ projectIdToCreate = answers.id ?? answers.project.$id;
185
+ projectNameToCreate = answers.project.name ?? answers.project.$id;
186
+ break;
187
+ default:
188
+ projectIdToCreate = answers.id;
189
+ projectNameToCreate = "";
190
+ break;
191
+ }
192
+
124
193
  const projectsService = await getProjectsService();
125
- response = await projectsService.create(
126
- answers.id,
127
- answers.project,
194
+ const response = await projectsService.create(
195
+ projectIdToCreate,
196
+ projectNameToCreate,
128
197
  answers.organization,
129
198
  answers.region,
130
199
  );
@@ -136,10 +205,25 @@ const initProject = async ({
136
205
  );
137
206
  }
138
207
  } else {
139
- localConfig.setProject(answers.project["$id"]);
140
- if (isCloud()) {
208
+ let selectedProject;
209
+
210
+ switch (typeof answers.project) {
211
+ case "string":
212
+ selectedProject = { $id: answers.project };
213
+ break;
214
+ case "object":
215
+ selectedProject = answers.project;
216
+ break;
217
+ default:
218
+ selectedProject = { $id: "" };
219
+ break;
220
+ }
221
+
222
+ localConfig.setProject(selectedProject.$id);
223
+
224
+ if (isCloud() && selectedProject.region) {
141
225
  localConfig.setEndpoint(
142
- `https://${answers.project["region"]}.${url.host}${url.pathname}`,
226
+ `https://${selectedProject.region}.${url.host}${url.pathname}`,
143
227
  );
144
228
  }
145
229
  }
@@ -149,8 +233,10 @@ const initProject = async ({
149
233
  );
150
234
 
151
235
  if (answers.start === "existing") {
152
- answers = await inquirer.prompt(questionsInitProjectAutopull);
153
- if (answers.autopull) {
236
+ const autopullAnswers: InitProjectAutopullAnswer = await inquirer.prompt(
237
+ questionsInitProjectAutopull,
238
+ );
239
+ if (autopullAnswers.autopull) {
154
240
  cliConfig.all = true;
155
241
  cliConfig.force = true;
156
242
  await pullResources({
@@ -322,7 +408,6 @@ const initFunction = async (): Promise<void> => {
322
408
  fs.mkdirSync(functionDir, { mode: 0o777 });
323
409
  fs.mkdirSync(templatesDir, { mode: 0o777 });
324
410
  const repo = "https://github.com/appwrite/templates";
325
- const api = `https://api.github.com/repos/appwrite/templates/contents/${answers.runtime.name}`;
326
411
  let selected: { template: string } = { template: "starter" };
327
412
 
328
413
  const sparse = (
@@ -351,20 +436,21 @@ const initFunction = async (): Promise<void> => {
351
436
  stdio: "pipe",
352
437
  cwd: templatesDir,
353
438
  });
354
- } catch (err: any) {
439
+ } catch (err) {
355
440
  /* Specialised errors with recommended actions to take */
356
- if (err.message.includes("error: unknown option")) {
441
+ const errorMessage = err instanceof Error ? err.message : String(err);
442
+ if (errorMessage.includes("error: unknown option")) {
357
443
  throw new Error(
358
- `${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`,
444
+ `${errorMessage} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`,
359
445
  );
360
446
  } else if (
361
- err.message.includes(
447
+ errorMessage.includes(
362
448
  "is not recognized as an internal or external command,",
363
449
  ) ||
364
- err.message.includes("command not found")
450
+ errorMessage.includes("command not found")
365
451
  ) {
366
452
  throw new Error(
367
- `${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`,
453
+ `${errorMessage} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`,
368
454
  );
369
455
  } else {
370
456
  throw err;
@@ -390,9 +476,9 @@ const initFunction = async (): Promise<void> => {
390
476
  }
391
477
 
392
478
  const copyRecursiveSync = (src: string, dest: string): void => {
393
- let exists = fs.existsSync(src);
394
- let stats = exists && fs.statSync(src);
395
- let isDirectory = exists && stats && stats.isDirectory();
479
+ const exists = fs.existsSync(src);
480
+ const stats = exists && fs.statSync(src);
481
+ const isDirectory = exists && stats && stats.isDirectory();
396
482
  if (isDirectory) {
397
483
  if (!fs.existsSync(dest)) {
398
484
  fs.mkdirSync(dest);
@@ -424,7 +510,7 @@ const initFunction = async (): Promise<void> => {
424
510
  newReadmeFile.splice(1, 2);
425
511
  fs.writeFileSync(readmePath, newReadmeFile.join("\n"));
426
512
 
427
- let data = {
513
+ const data = {
428
514
  $id: functionId,
429
515
  name: answers.name,
430
516
  runtime: answers.runtime.id,
@@ -472,7 +558,7 @@ const initSite = async (): Promise<void> => {
472
558
  );
473
559
  }
474
560
 
475
- let templateDetails: any;
561
+ let templateDetails: SiteTemplateDetails;
476
562
  try {
477
563
  const sitesService = await getSitesService();
478
564
  const response = await sitesService.listTemplates(
@@ -486,16 +572,17 @@ const initSite = async (): Promise<void> => {
486
572
  );
487
573
  }
488
574
  templateDetails = response.templates[0];
489
- } catch (err: any) {
575
+ } catch (err) {
576
+ const errorMessage = err instanceof Error ? err.message : String(err);
490
577
  throw new Error(
491
- `Failed to fetch template for framework ${answers.framework.key}: ${err.message}`,
578
+ `Failed to fetch template for framework ${answers.framework.key}: ${errorMessage}`,
492
579
  );
493
580
  }
494
581
 
495
582
  fs.mkdirSync(siteDir, { mode: 0o777 });
496
583
  fs.mkdirSync(templatesDir, { mode: 0o777 });
497
584
  const repo = `https://github.com/${templateDetails.providerOwner}/${templateDetails.providerRepositoryId}`;
498
- let selected = {
585
+ const selected = {
499
586
  template: templateDetails.frameworks[0].providerRootDirectory,
500
587
  };
501
588
 
@@ -526,12 +613,12 @@ const initSite = async (): Promise<void> => {
526
613
  git config remote.origin.tagopt --no-tags
527
614
  `.trim();
528
615
  }
529
- let windowsGitCloneCommands = `
616
+ const windowsGitCloneCommands = `
530
617
  $tag = (git ls-remote --tags origin "${templateDetails.providerVersion}" | Select-Object -Last 1) -replace '.*refs/tags/', ''
531
618
  git fetch --depth=1 origin "refs/tags/$tag"
532
619
  git checkout FETCH_HEAD
533
620
  `.trim();
534
- let unixGitCloneCommands = `
621
+ const unixGitCloneCommands = `
535
622
  git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
536
623
  git checkout FETCH_HEAD
537
624
  `.trim();
@@ -551,20 +638,21 @@ const initSite = async (): Promise<void> => {
551
638
  cwd: templatesDir,
552
639
  shell: usedShell,
553
640
  });
554
- } catch (err: any) {
641
+ } catch (err) {
555
642
  /* Specialised errors with recommended actions to take */
556
- if (err.message.includes("error: unknown option")) {
643
+ const errorMessage = err instanceof Error ? err.message : String(err);
644
+ if (errorMessage.includes("error: unknown option")) {
557
645
  throw new Error(
558
- `${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`,
646
+ `${errorMessage} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`,
559
647
  );
560
648
  } else if (
561
- err.message.includes(
649
+ errorMessage.includes(
562
650
  "is not recognized as an internal or external command,",
563
651
  ) ||
564
- err.message.includes("command not found")
652
+ errorMessage.includes("command not found")
565
653
  ) {
566
654
  throw new Error(
567
- `${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`,
655
+ `${errorMessage} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`,
568
656
  );
569
657
  } else {
570
658
  throw err;
@@ -590,27 +678,25 @@ const initSite = async (): Promise<void> => {
590
678
  newReadmeFile.splice(1, 2);
591
679
  fs.writeFileSync(readmePath, newReadmeFile.join("\n"));
592
680
 
593
- let vars = (templateDetails.variables ?? []).map((variable: any) => {
594
- let value = variable.value;
681
+ const vars: Record<string, string> = {};
682
+ for (const variable of templateDetails.variables ?? []) {
683
+ let value = variable.value ?? "";
595
684
  const replacements: Record<string, string> = {
596
685
  "{apiEndpoint}": globalConfig.getEndpoint(),
597
- "{projectId}": localConfig.getProject().projectId,
598
- "{projectName}": localConfig.getProject().projectName,
686
+ "{projectId}": localConfig.getProject().projectId ?? "",
687
+ "{projectName}": localConfig.getProject().projectName ?? "",
599
688
  };
600
689
 
601
690
  for (const placeholder in replacements) {
602
- if (value?.includes(placeholder)) {
691
+ if (value.includes(placeholder)) {
603
692
  value = value.replace(placeholder, replacements[placeholder]);
604
693
  }
605
694
  }
606
695
 
607
- return {
608
- key: variable.name,
609
- value: value,
610
- };
611
- });
696
+ vars[variable.name] = value;
697
+ }
612
698
 
613
- let data = {
699
+ const data = {
614
700
  $id: siteId,
615
701
  name: answers.name,
616
702
  framework: answers.framework.key,
@@ -719,7 +719,7 @@ export const pullResources = async ({
719
719
  }
720
720
 
721
721
  if (cliConfig.all) {
722
- for (let action of Object.values(actions)) {
722
+ for (const action of Object.values(actions)) {
723
723
  cliConfig.all = true;
724
724
  await action({ returnOnZero: true });
725
725
  }