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.
- package/CHANGELOG.md +4 -0
- package/README.md +2 -2
- package/cli.ts +3 -3
- package/dist/bundle-win-arm64.mjs +336 -212
- package/dist/cli.cjs +336 -212
- package/dist/index.cjs +156 -104
- package/dist/index.js +156 -104
- package/dist/lib/commands/config-validations.d.ts +1 -1
- package/dist/lib/commands/config-validations.d.ts.map +1 -1
- package/dist/lib/commands/errors.d.ts +4 -4
- package/dist/lib/commands/errors.d.ts.map +1 -1
- package/dist/lib/commands/generate.d.ts.map +1 -1
- package/dist/lib/commands/generators/base.d.ts +5 -0
- package/dist/lib/commands/generators/base.d.ts.map +1 -1
- package/dist/lib/commands/generic.d.ts.map +1 -1
- package/dist/lib/commands/init.d.ts.map +1 -1
- package/dist/lib/commands/run.d.ts.map +1 -1
- package/dist/lib/commands/types.d.ts.map +1 -1
- package/dist/lib/commands/update.d.ts.map +1 -1
- package/dist/lib/commands/utils/change-approval.d.ts +3 -3
- package/dist/lib/commands/utils/change-approval.d.ts.map +1 -1
- package/dist/lib/commands/utils/database-sync.d.ts.map +1 -1
- package/dist/lib/commands/utils/deployment.d.ts +16 -4
- package/dist/lib/commands/utils/deployment.d.ts.map +1 -1
- package/dist/lib/commands/utils/pools.d.ts.map +1 -1
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/emulation/docker.d.ts.map +1 -1
- package/dist/lib/json.d.ts +1 -1
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/paginate.d.ts +5 -6
- package/dist/lib/paginate.d.ts.map +1 -1
- package/dist/lib/parser.d.ts +5 -4
- package/dist/lib/parser.d.ts.map +1 -1
- package/dist/lib/spinner.d.ts +1 -1
- package/dist/lib/spinner.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +6 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/validations.d.ts +1 -1
- package/dist/lib/validations.d.ts.map +1 -1
- package/eslint.config.js +45 -0
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.ts +3 -3
- package/lib/commands/config-validations.ts +1 -1
- package/lib/commands/config.ts +2 -2
- package/lib/commands/errors.ts +2 -2
- package/lib/commands/generate.ts +8 -6
- package/lib/commands/generators/base.ts +6 -0
- package/lib/commands/generators/typescript/databases.ts +9 -9
- package/lib/commands/generators/typescript/templates/databases.ts.hbs +16 -16
- package/lib/commands/generic.ts +21 -16
- package/lib/commands/init.ts +147 -61
- package/lib/commands/pull.ts +1 -1
- package/lib/commands/push.ts +19 -19
- package/lib/commands/run.ts +15 -9
- package/lib/commands/types.ts +18 -8
- package/lib/commands/update.ts +24 -16
- package/lib/commands/utils/attributes.ts +6 -6
- package/lib/commands/utils/change-approval.ts +26 -19
- package/lib/commands/utils/database-sync.ts +58 -18
- package/lib/commands/utils/deployment.ts +22 -5
- package/lib/commands/utils/pools.ts +11 -5
- package/lib/config.ts +1 -1
- package/lib/constants.ts +1 -1
- package/lib/emulation/docker.ts +5 -6
- package/lib/emulation/utils.ts +2 -2
- package/lib/json.ts +15 -7
- package/lib/paginate.ts +30 -20
- package/lib/parser.ts +46 -15
- package/lib/questions.ts +38 -38
- package/lib/spinner.ts +5 -1
- package/lib/utils.ts +15 -3
- package/lib/validations.ts +1 -1
- package/package.json +7 -1
- 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
|
|
11
|
-
notEqual: (field, value) => Query.notEqual(String(field), value as
|
|
12
|
-
lessThan: (field, value) => Query.lessThan(String(field), value as
|
|
13
|
-
lessThanEqual: (field, value) => Query.lessThanEqual(String(field), value as
|
|
14
|
-
greaterThan: (field, value) => Query.greaterThan(String(field), value as
|
|
15
|
-
greaterThanEqual: (field, value) => Query.greaterThanEqual(String(field), value as
|
|
16
|
-
contains: (field, value) => Query.contains(String(field), value as
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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?:
|
|
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
|
|
151
|
+
name: options?.name,
|
|
152
152
|
permissions: resolvePermissions(options?.permissions),
|
|
153
153
|
rowSecurity: options?.rowSecurity,
|
|
154
154
|
enabled: options?.enabled,
|
package/lib/commands/generic.ts
CHANGED
|
@@ -28,9 +28,14 @@ import ClientLegacy from "../client.js";
|
|
|
28
28
|
|
|
29
29
|
const DEFAULT_ENDPOINT = "https://cloud.appwrite.io/v1";
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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<
|
|
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
|
-
|
|
96
|
-
|
|
100
|
+
const client = await sdkForConsole();
|
|
101
|
+
const accountClient = new Account(client);
|
|
97
102
|
await accountClient.deleteSession(sessionId);
|
|
98
103
|
return true;
|
|
99
|
-
} catch (
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
305
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
533
|
+
const response = (await clientInstance.call(
|
|
529
534
|
"GET",
|
|
530
535
|
new URL(endpoint + "/health/version"),
|
|
531
536
|
)) as { version?: string };
|
package/lib/commands/init.ts
CHANGED
|
@@ -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,
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
141
|
+
const selectedProjectName =
|
|
102
142
|
projectName ?? (await inquirer.prompt([questionsInitProject[3]])).project;
|
|
103
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
answers
|
|
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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://${
|
|
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
|
-
|
|
153
|
-
|
|
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
|
|
439
|
+
} catch (err) {
|
|
355
440
|
/* Specialised errors with recommended actions to take */
|
|
356
|
-
|
|
441
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
442
|
+
if (errorMessage.includes("error: unknown option")) {
|
|
357
443
|
throw new Error(
|
|
358
|
-
`${
|
|
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
|
-
|
|
447
|
+
errorMessage.includes(
|
|
362
448
|
"is not recognized as an internal or external command,",
|
|
363
449
|
) ||
|
|
364
|
-
|
|
450
|
+
errorMessage.includes("command not found")
|
|
365
451
|
) {
|
|
366
452
|
throw new Error(
|
|
367
|
-
`${
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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}: ${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
641
|
+
} catch (err) {
|
|
555
642
|
/* Specialised errors with recommended actions to take */
|
|
556
|
-
|
|
643
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
644
|
+
if (errorMessage.includes("error: unknown option")) {
|
|
557
645
|
throw new Error(
|
|
558
|
-
`${
|
|
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
|
-
|
|
649
|
+
errorMessage.includes(
|
|
562
650
|
"is not recognized as an internal or external command,",
|
|
563
651
|
) ||
|
|
564
|
-
|
|
652
|
+
errorMessage.includes("command not found")
|
|
565
653
|
) {
|
|
566
654
|
throw new Error(
|
|
567
|
-
`${
|
|
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
|
-
|
|
594
|
-
|
|
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
|
|
691
|
+
if (value.includes(placeholder)) {
|
|
603
692
|
value = value.replace(placeholder, replacements[placeholder]);
|
|
604
693
|
}
|
|
605
694
|
}
|
|
606
695
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
value: value,
|
|
610
|
-
};
|
|
611
|
-
});
|
|
696
|
+
vars[variable.name] = value;
|
|
697
|
+
}
|
|
612
698
|
|
|
613
|
-
|
|
699
|
+
const data = {
|
|
614
700
|
$id: siteId,
|
|
615
701
|
name: answers.name,
|
|
616
702
|
framework: answers.framework.key,
|
package/lib/commands/pull.ts
CHANGED