appwrite-cli 13.2.1 → 13.3.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 +9 -0
- package/README.md +2 -2
- package/dist/bundle-win-arm64.mjs +311 -81
- package/dist/cli.cjs +311 -81
- package/dist/index.js +119 -18
- package/dist/lib/commands/config-validations.d.ts +1 -1
- package/dist/lib/commands/config.d.ts +24 -0
- package/dist/lib/commands/config.d.ts.map +1 -1
- package/dist/lib/commands/generate.d.ts.map +1 -1
- package/dist/lib/commands/generators/typescript/databases.d.ts.map +1 -1
- package/dist/lib/commands/generic.d.ts +2 -4
- package/dist/lib/commands/generic.d.ts.map +1 -1
- package/dist/lib/commands/utils/attributes.d.ts.map +1 -1
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/questions.d.ts +1 -0
- package/dist/lib/questions.d.ts.map +1 -1
- package/dist/lib/shared/typescript-type-utils.d.ts +5 -0
- package/dist/lib/shared/typescript-type-utils.d.ts.map +1 -1
- package/dist/lib/type-generation/attribute.d.ts +4 -0
- package/dist/lib/type-generation/attribute.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/csharp.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/dart.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/java.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/javascript.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/kotlin.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/php.d.ts.map +1 -1
- package/dist/lib/type-generation/languages/swift.d.ts.map +1 -1
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/commands/config-validations.ts +3 -3
- package/lib/commands/config.ts +10 -2
- package/lib/commands/generate.ts +4 -2
- package/lib/commands/generators/typescript/databases.ts +9 -5
- package/lib/commands/generators/typescript/templates/databases.ts.hbs +3 -3
- package/lib/commands/generators/typescript/templates/index.ts.hbs +2 -2
- package/lib/commands/generic.ts +211 -76
- package/lib/commands/push.ts +1 -1
- package/lib/commands/utils/attributes.ts +70 -0
- package/lib/config.ts +4 -4
- package/lib/constants.ts +1 -1
- package/lib/questions.ts +3 -1
- package/lib/shared/typescript-type-utils.ts +30 -0
- package/lib/type-generation/attribute.ts +4 -0
- package/lib/type-generation/languages/csharp.ts +6 -2
- package/lib/type-generation/languages/dart.ts +5 -1
- package/lib/type-generation/languages/java.ts +4 -0
- package/lib/type-generation/languages/javascript.ts +4 -0
- package/lib/type-generation/languages/kotlin.ts +4 -0
- package/lib/type-generation/languages/php.ts +4 -0
- package/lib/type-generation/languages/swift.ts +8 -4
- package/package.json +1 -1
- package/scoop/appwrite.config.json +3 -3
|
@@ -18,7 +18,7 @@ export const validateRequiredDefault = (data: {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Validates that string type attributes must have a size defined,
|
|
21
|
+
* Validates that string/varchar type attributes must have a size defined,
|
|
22
22
|
* unless they have a format (email, url, ip, enum) which defines the size
|
|
23
23
|
*/
|
|
24
24
|
export const validateStringSize = (data: {
|
|
@@ -26,8 +26,8 @@ export const validateStringSize = (data: {
|
|
|
26
26
|
size?: number | null;
|
|
27
27
|
format?: string | null;
|
|
28
28
|
}) => {
|
|
29
|
-
// Skip validation if not a string type
|
|
30
|
-
if (data.type !== "string") {
|
|
29
|
+
// Skip validation if not a string-like type that requires size
|
|
30
|
+
if (data.type !== "string" && data.type !== "varchar") {
|
|
31
31
|
return true;
|
|
32
32
|
}
|
|
33
33
|
|
package/lib/commands/config.ts
CHANGED
|
@@ -194,6 +194,10 @@ const AttributeSchema = z
|
|
|
194
194
|
key: z.string(),
|
|
195
195
|
type: z.enum([
|
|
196
196
|
"string",
|
|
197
|
+
"text",
|
|
198
|
+
"varchar",
|
|
199
|
+
"mediumtext",
|
|
200
|
+
"longtext",
|
|
197
201
|
"integer",
|
|
198
202
|
"double",
|
|
199
203
|
"boolean",
|
|
@@ -233,7 +237,7 @@ const AttributeSchema = z
|
|
|
233
237
|
path: ["default"],
|
|
234
238
|
})
|
|
235
239
|
.refine(validateStringSize, {
|
|
236
|
-
message: "When 'type' is 'string', 'size' must be defined",
|
|
240
|
+
message: "When 'type' is 'string' or 'varchar', 'size' must be defined",
|
|
237
241
|
path: ["size"],
|
|
238
242
|
});
|
|
239
243
|
|
|
@@ -270,6 +274,10 @@ const ColumnSchema = z
|
|
|
270
274
|
key: z.string(),
|
|
271
275
|
type: z.enum([
|
|
272
276
|
"string",
|
|
277
|
+
"text",
|
|
278
|
+
"varchar",
|
|
279
|
+
"mediumtext",
|
|
280
|
+
"longtext",
|
|
273
281
|
"integer",
|
|
274
282
|
"double",
|
|
275
283
|
"boolean",
|
|
@@ -310,7 +318,7 @@ const ColumnSchema = z
|
|
|
310
318
|
path: ["default"],
|
|
311
319
|
})
|
|
312
320
|
.refine(validateStringSize, {
|
|
313
|
-
message: "When 'type' is 'string', 'size' must be defined",
|
|
321
|
+
message: "When 'type' is 'string' or 'varchar', 'size' must be defined",
|
|
314
322
|
path: ["size"],
|
|
315
323
|
});
|
|
316
324
|
|
package/lib/commands/generate.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
EXECUTABLE_NAME,
|
|
18
18
|
DEFAULT_ENDPOINT,
|
|
19
19
|
} from "../constants.js";
|
|
20
|
+
import { detectImportExtension } from "../shared/typescript-type-utils.js";
|
|
20
21
|
|
|
21
22
|
type ServerSideOverride = "auto" | "true" | "false";
|
|
22
23
|
|
|
@@ -129,11 +130,12 @@ const generateAction = async (
|
|
|
129
130
|
const firstEntity = entities?.[0];
|
|
130
131
|
const dbId = firstEntity?.databaseId ?? "databaseId";
|
|
131
132
|
const tableName = firstEntity?.name ?? "tableName";
|
|
133
|
+
const importExt = detectImportExtension();
|
|
132
134
|
|
|
133
135
|
console.log("");
|
|
134
136
|
log(`Import the generated SDK in your project:`);
|
|
135
137
|
console.log(
|
|
136
|
-
` import { databases } from "./${outputDir}/${SDK_TITLE_LOWER}/index
|
|
138
|
+
` import { databases } from "./${outputDir}/${SDK_TITLE_LOWER}/index${importExt}";`,
|
|
137
139
|
);
|
|
138
140
|
console.log("");
|
|
139
141
|
log(`Configure your SDK constants:`);
|
|
@@ -176,7 +178,7 @@ export const generate = new Command("generate")
|
|
|
176
178
|
`
|
|
177
179
|
Example:
|
|
178
180
|
Import the generated SDK in your project:
|
|
179
|
-
import { databases } from "./generated/${SDK_TITLE_LOWER}/index
|
|
181
|
+
import { databases } from "./generated/${SDK_TITLE_LOWER}/index${detectImportExtension()}";
|
|
180
182
|
|
|
181
183
|
Configure your SDK constants:
|
|
182
184
|
set values in ./generated/${SDK_TITLE_LOWER}/constants.ts
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getTypeScriptType,
|
|
14
14
|
getAppwriteDependency,
|
|
15
15
|
supportsServerSideMethods,
|
|
16
|
+
detectImportExtension,
|
|
16
17
|
TypeAttribute,
|
|
17
18
|
TypeEntity,
|
|
18
19
|
} from "../../../shared/typescript-type-utils.js";
|
|
@@ -369,7 +370,7 @@ ${
|
|
|
369
370
|
}`;
|
|
370
371
|
}
|
|
371
372
|
|
|
372
|
-
private generateDatabasesFile(config: ConfigType): string {
|
|
373
|
+
private generateDatabasesFile(config: ConfigType, importExt: string): string {
|
|
373
374
|
const entities = config.tables?.length ? config.tables : config.collections;
|
|
374
375
|
|
|
375
376
|
if (!entities || entities.length === 0) {
|
|
@@ -386,6 +387,7 @@ ${
|
|
|
386
387
|
return databasesTemplate({
|
|
387
388
|
appwriteDep,
|
|
388
389
|
supportsServerSide,
|
|
390
|
+
importExt,
|
|
389
391
|
TABLE_ID_MAP: this.generateTableIdMap(entitiesByDb),
|
|
390
392
|
TABLES_WITH_RELATIONSHIPS:
|
|
391
393
|
this.generateTablesWithRelationships(entitiesByDb),
|
|
@@ -395,10 +397,11 @@ ${
|
|
|
395
397
|
});
|
|
396
398
|
}
|
|
397
399
|
|
|
398
|
-
private generateIndexFile(): string {
|
|
400
|
+
private generateIndexFile(importExt: string): string {
|
|
399
401
|
return indexTemplate({
|
|
400
402
|
sdkTitle: SDK_TITLE,
|
|
401
403
|
executableName: EXECUTABLE_NAME,
|
|
404
|
+
importExt,
|
|
402
405
|
});
|
|
403
406
|
}
|
|
404
407
|
|
|
@@ -422,6 +425,7 @@ ${
|
|
|
422
425
|
throw new Error("Project ID is required in configuration");
|
|
423
426
|
}
|
|
424
427
|
|
|
428
|
+
const importExt = detectImportExtension();
|
|
425
429
|
const files = new Map<string, string>();
|
|
426
430
|
|
|
427
431
|
const hasEntities =
|
|
@@ -440,14 +444,14 @@ ${
|
|
|
440
444
|
"types.ts",
|
|
441
445
|
"// No tables or collections found in configuration\n",
|
|
442
446
|
);
|
|
443
|
-
files.set("index.ts", this.generateIndexFile());
|
|
447
|
+
files.set("index.ts", this.generateIndexFile(importExt));
|
|
444
448
|
files.set("constants.ts", this.generateConstantsFile(config));
|
|
445
449
|
return { files };
|
|
446
450
|
}
|
|
447
451
|
|
|
448
452
|
files.set("types.ts", this.generateTypesFile(config));
|
|
449
|
-
files.set("databases.ts", this.generateDatabasesFile(config));
|
|
450
|
-
files.set("index.ts", this.generateIndexFile());
|
|
453
|
+
files.set("databases.ts", this.generateDatabasesFile(config, importExt));
|
|
454
|
+
files.set("index.ts", this.generateIndexFile(importExt));
|
|
451
455
|
files.set("constants.ts", this.generateConstantsFile(config));
|
|
452
456
|
|
|
453
457
|
return { files };
|
|
@@ -1,9 +1,9 @@
|
|
|
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
|
|
2
|
+
import type { DatabaseHandle, DatabaseId, DatabaseTableMap, DatabaseTables, QueryBuilder, PermissionBuilder, RoleBuilder, RoleString } from './types{{importExt}}';
|
|
3
3
|
{{#if supportsServerSide}}
|
|
4
|
-
import { PROJECT_ID, ENDPOINT, API_KEY } from './constants
|
|
4
|
+
import { PROJECT_ID, ENDPOINT, API_KEY } from './constants{{importExt}}';
|
|
5
5
|
{{else}}
|
|
6
|
-
import { PROJECT_ID, ENDPOINT } from './constants
|
|
6
|
+
import { PROJECT_ID, ENDPOINT } from './constants{{importExt}}';
|
|
7
7
|
{{/if}}
|
|
8
8
|
|
|
9
9
|
const createQueryBuilder = <T>(): QueryBuilder<T> => ({
|
package/lib/commands/generic.ts
CHANGED
|
@@ -28,13 +28,131 @@ import ClientLegacy from "../client.js";
|
|
|
28
28
|
|
|
29
29
|
const DEFAULT_ENDPOINT = "https://cloud.appwrite.io/v1";
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const isMfaRequiredError = (err: any): boolean =>
|
|
32
|
+
err?.type === "user_more_factors_required" ||
|
|
33
|
+
err?.response === "user_more_factors_required";
|
|
34
|
+
|
|
35
|
+
const createLegacyConsoleClient = (endpoint: string): ClientLegacy => {
|
|
36
|
+
const legacyClient = new ClientLegacy();
|
|
37
|
+
legacyClient.setEndpoint(endpoint);
|
|
38
|
+
legacyClient.setProject("console");
|
|
39
|
+
if (globalConfig.getSelfSigned()) {
|
|
40
|
+
legacyClient.setSelfSigned(true);
|
|
41
|
+
}
|
|
42
|
+
return legacyClient;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const completeMfaLogin = async ({
|
|
46
|
+
client,
|
|
47
|
+
legacyClient,
|
|
48
|
+
mfa,
|
|
49
|
+
code,
|
|
50
|
+
}: {
|
|
51
|
+
client: ConsoleClient;
|
|
52
|
+
legacyClient: ClientLegacy;
|
|
35
53
|
mfa?: string;
|
|
36
54
|
code?: string;
|
|
37
|
-
}
|
|
55
|
+
}): Promise<any> => {
|
|
56
|
+
let accountClient = new Account(client);
|
|
57
|
+
|
|
58
|
+
const savedCookie = globalConfig.getCookie();
|
|
59
|
+
if (savedCookie) {
|
|
60
|
+
legacyClient.setCookie(savedCookie);
|
|
61
|
+
client.setCookie(savedCookie);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { factor } = mfa
|
|
65
|
+
? { factor: mfa }
|
|
66
|
+
: await inquirer.prompt(questionsListFactors);
|
|
67
|
+
const challenge = await accountClient.createMfaChallenge(factor);
|
|
68
|
+
|
|
69
|
+
const { otp } = code
|
|
70
|
+
? { otp: code }
|
|
71
|
+
: await inquirer.prompt(questionsMFAChallenge);
|
|
72
|
+
await legacyClient.call(
|
|
73
|
+
"PUT",
|
|
74
|
+
"/account/mfa/challenges",
|
|
75
|
+
{
|
|
76
|
+
"content-type": "application/json",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
challengeId: challenge.$id,
|
|
80
|
+
otp,
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const updatedCookie = globalConfig.getCookie();
|
|
85
|
+
if (updatedCookie) {
|
|
86
|
+
client.setCookie(updatedCookie);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
accountClient = new Account(client);
|
|
90
|
+
return accountClient.get();
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const deleteServerSession = async (sessionId: string): Promise<boolean> => {
|
|
94
|
+
try {
|
|
95
|
+
let client = await sdkForConsole();
|
|
96
|
+
let accountClient = new Account(client);
|
|
97
|
+
await accountClient.deleteSession(sessionId);
|
|
98
|
+
return true;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const deleteLocalSession = (accountId: string): void => {
|
|
105
|
+
globalConfig.removeSession(accountId);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getSessionAccountKey = (sessionId: string): string | undefined => {
|
|
109
|
+
const session = globalConfig.get(sessionId) as
|
|
110
|
+
| { email?: string; endpoint?: string }
|
|
111
|
+
| undefined;
|
|
112
|
+
if (!session) return undefined;
|
|
113
|
+
return `${session.email ?? ""}|${session.endpoint ?? ""}`;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Given selected session IDs, determine which sessions should be logged out
|
|
118
|
+
* from the server (one per unique account) and which should be removed locally (all sessions for those accounts).
|
|
119
|
+
*
|
|
120
|
+
* @param selectedSessionIds Array of session IDs to process for logout.
|
|
121
|
+
* @returns Object containing `serverTargets` (sessions to logout from server)
|
|
122
|
+
* and `localTargets` (sessions to remove locally).
|
|
123
|
+
*/
|
|
124
|
+
const planSessionLogout = (
|
|
125
|
+
selectedSessionIds: string[],
|
|
126
|
+
): { serverTargets: string[]; localTargets: string[] } => {
|
|
127
|
+
// Map to group all session IDs by their unique account key (email+endpoint)
|
|
128
|
+
const sessionIdsByAccount = new Map<string, string[]>();
|
|
129
|
+
for (const sessionId of globalConfig.getSessionIds()) {
|
|
130
|
+
const key = getSessionAccountKey(sessionId);
|
|
131
|
+
if (!key) continue; // Skip sessions without proper account key
|
|
132
|
+
|
|
133
|
+
// For each account key, gather all associated session IDs
|
|
134
|
+
const ids = sessionIdsByAccount.get(key) ?? [];
|
|
135
|
+
ids.push(sessionId);
|
|
136
|
+
sessionIdsByAccount.set(key, ids);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Map to store one selected session ID per unique account for server logout
|
|
140
|
+
const selectedByAccount = new Map<string, string>();
|
|
141
|
+
for (const selectedSessionId of selectedSessionIds) {
|
|
142
|
+
const key = getSessionAccountKey(selectedSessionId);
|
|
143
|
+
if (!key || selectedByAccount.has(key)) continue; // Skip if key missing or already considered for this account
|
|
144
|
+
selectedByAccount.set(key, selectedSessionId);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Sessions to target for server logout: one per unique account
|
|
148
|
+
const serverTargets = Array.from(selectedByAccount.values());
|
|
149
|
+
// Sessions to remove locally: all sessions under selected accounts
|
|
150
|
+
const localTargets = Array.from(selectedByAccount.keys()).flatMap(
|
|
151
|
+
(accountKey) => sessionIdsByAccount.get(accountKey) ?? [],
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
return { serverTargets, localTargets };
|
|
155
|
+
};
|
|
38
156
|
|
|
39
157
|
export const loginCommand = async ({
|
|
40
158
|
email,
|
|
@@ -42,7 +160,13 @@ export const loginCommand = async ({
|
|
|
42
160
|
endpoint,
|
|
43
161
|
mfa,
|
|
44
162
|
code,
|
|
45
|
-
}:
|
|
163
|
+
}: {
|
|
164
|
+
email?: string;
|
|
165
|
+
password?: string;
|
|
166
|
+
endpoint?: string;
|
|
167
|
+
mfa?: string;
|
|
168
|
+
code?: string;
|
|
169
|
+
}): Promise<void> => {
|
|
46
170
|
const oldCurrent = globalConfig.getCurrentSession();
|
|
47
171
|
|
|
48
172
|
const configEndpoint =
|
|
@@ -73,7 +197,29 @@ export const loginCommand = async ({
|
|
|
73
197
|
}
|
|
74
198
|
|
|
75
199
|
globalConfig.setCurrentSession(accountId);
|
|
76
|
-
|
|
200
|
+
|
|
201
|
+
const client = await sdkForConsole(false);
|
|
202
|
+
const accountClient = new Account(client);
|
|
203
|
+
const legacyClient = createLegacyConsoleClient(
|
|
204
|
+
globalConfig.getEndpoint() || DEFAULT_ENDPOINT,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
await accountClient.get();
|
|
209
|
+
} catch (err: any) {
|
|
210
|
+
if (!isMfaRequiredError(err)) {
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await completeMfaLogin({
|
|
215
|
+
client,
|
|
216
|
+
legacyClient,
|
|
217
|
+
mfa,
|
|
218
|
+
code,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
success(`Switched to ${globalConfig.getEmail()}`);
|
|
77
223
|
|
|
78
224
|
return;
|
|
79
225
|
}
|
|
@@ -86,12 +232,7 @@ export const loginCommand = async ({
|
|
|
86
232
|
globalConfig.setEmail(answers.email);
|
|
87
233
|
|
|
88
234
|
// Use legacy client for login to extract cookies from response
|
|
89
|
-
const legacyClient =
|
|
90
|
-
legacyClient.setEndpoint(configEndpoint);
|
|
91
|
-
legacyClient.setProject("console");
|
|
92
|
-
if (globalConfig.getSelfSigned()) {
|
|
93
|
-
legacyClient.setSelfSigned(true);
|
|
94
|
-
}
|
|
235
|
+
const legacyClient = createLegacyConsoleClient(configEndpoint);
|
|
95
236
|
|
|
96
237
|
let client = await sdkForConsole(false);
|
|
97
238
|
let accountClient = new Account(client);
|
|
@@ -121,37 +262,13 @@ export const loginCommand = async ({
|
|
|
121
262
|
accountClient = new Account(client);
|
|
122
263
|
account = await accountClient.get();
|
|
123
264
|
} catch (err: any) {
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const challenge = await accountClient.createMfaChallenge(factor);
|
|
132
|
-
|
|
133
|
-
const { otp } = code
|
|
134
|
-
? { otp: code }
|
|
135
|
-
: await inquirer.prompt(questionsMFAChallenge);
|
|
136
|
-
await legacyClient.call(
|
|
137
|
-
"PUT",
|
|
138
|
-
"/account/mfa/challenges",
|
|
139
|
-
{
|
|
140
|
-
"content-type": "application/json",
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
challengeId: challenge.$id,
|
|
144
|
-
otp: otp,
|
|
145
|
-
},
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
const savedCookie = globalConfig.getCookie();
|
|
149
|
-
if (savedCookie) {
|
|
150
|
-
client.setCookie(savedCookie);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
accountClient = new Account(client);
|
|
154
|
-
account = await accountClient.get();
|
|
265
|
+
if (isMfaRequiredError(err)) {
|
|
266
|
+
account = await completeMfaLogin({
|
|
267
|
+
client,
|
|
268
|
+
legacyClient,
|
|
269
|
+
mfa,
|
|
270
|
+
code,
|
|
271
|
+
});
|
|
155
272
|
} else {
|
|
156
273
|
globalConfig.removeSession(id);
|
|
157
274
|
globalConfig.setCurrentSession(oldCurrent);
|
|
@@ -241,19 +358,6 @@ export const login = new Command("login")
|
|
|
241
358
|
})
|
|
242
359
|
.action(actionRunner(loginCommand));
|
|
243
360
|
|
|
244
|
-
const deleteSession = async (accountId: string): Promise<void> => {
|
|
245
|
-
try {
|
|
246
|
-
let client = await sdkForConsole();
|
|
247
|
-
let accountClient = new Account(client);
|
|
248
|
-
|
|
249
|
-
await accountClient.deleteSession("current");
|
|
250
|
-
} catch (e) {
|
|
251
|
-
error("Unable to log out, removing locally saved session information");
|
|
252
|
-
} finally {
|
|
253
|
-
globalConfig.removeSession(accountId);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
|
|
257
361
|
export const logout = new Command("logout")
|
|
258
362
|
.description(commandDescriptions["logout"])
|
|
259
363
|
.configureHelp({
|
|
@@ -263,44 +367,69 @@ export const logout = new Command("logout")
|
|
|
263
367
|
actionRunner(async () => {
|
|
264
368
|
const sessions = globalConfig.getSessions();
|
|
265
369
|
const current = globalConfig.getCurrentSession();
|
|
370
|
+
const originalCurrent = current;
|
|
266
371
|
|
|
267
372
|
if (current === "" || !sessions.length) {
|
|
268
373
|
log("No active sessions found.");
|
|
269
374
|
return;
|
|
270
375
|
}
|
|
271
376
|
if (sessions.length === 1) {
|
|
272
|
-
|
|
377
|
+
// Try to delete from server, then remove locally
|
|
378
|
+
const serverDeleted = await deleteServerSession(current);
|
|
379
|
+
// Remove all local sessions with the same email+endpoint
|
|
380
|
+
const allSessionIds = globalConfig.getSessionIds();
|
|
381
|
+
for (const sessId of allSessionIds) {
|
|
382
|
+
deleteLocalSession(sessId);
|
|
383
|
+
}
|
|
273
384
|
globalConfig.setCurrentSession("");
|
|
274
|
-
|
|
385
|
+
if (!serverDeleted) {
|
|
386
|
+
hint("Could not reach server, removed local session data");
|
|
387
|
+
}
|
|
388
|
+
success("Logged out successfully");
|
|
275
389
|
|
|
276
390
|
return;
|
|
277
391
|
}
|
|
278
392
|
|
|
279
393
|
const answers = await inquirer.prompt(questionsLogout);
|
|
280
394
|
|
|
281
|
-
if (answers.accounts) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
395
|
+
if (answers.accounts?.length) {
|
|
396
|
+
const { serverTargets, localTargets } = planSessionLogout(
|
|
397
|
+
answers.accounts as string[],
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
for (const sessionId of serverTargets) {
|
|
401
|
+
globalConfig.setCurrentSession(sessionId);
|
|
402
|
+
await deleteServerSession(sessionId);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
for (const sessionId of localTargets) {
|
|
406
|
+
deleteLocalSession(sessionId);
|
|
285
407
|
}
|
|
286
408
|
}
|
|
287
409
|
|
|
288
410
|
const remainingSessions = globalConfig.getSessions();
|
|
411
|
+
const hasCurrent = remainingSessions.some(
|
|
412
|
+
(session) => session.id === originalCurrent,
|
|
413
|
+
);
|
|
289
414
|
|
|
290
|
-
if (
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
globalConfig.setCurrentSession(
|
|
297
|
-
|
|
298
|
-
success(
|
|
415
|
+
if (remainingSessions.length > 0 && hasCurrent) {
|
|
416
|
+
globalConfig.setCurrentSession(originalCurrent);
|
|
417
|
+
} else if (remainingSessions.length > 0) {
|
|
418
|
+
const nextSession =
|
|
419
|
+
remainingSessions.find((session) => session.email) ??
|
|
420
|
+
remainingSessions[0];
|
|
421
|
+
globalConfig.setCurrentSession(nextSession.id);
|
|
422
|
+
|
|
423
|
+
success(
|
|
424
|
+
nextSession.email
|
|
425
|
+
? `Switched to ${nextSession.email}`
|
|
426
|
+
: `Switched to session at ${nextSession.endpoint}`,
|
|
427
|
+
);
|
|
299
428
|
} else if (remainingSessions.length === 0) {
|
|
300
429
|
globalConfig.setCurrentSession("");
|
|
301
430
|
}
|
|
302
431
|
|
|
303
|
-
success("
|
|
432
|
+
success("Logged out successfully");
|
|
304
433
|
}),
|
|
305
434
|
);
|
|
306
435
|
|
|
@@ -438,10 +567,16 @@ export const client = new Command("client")
|
|
|
438
567
|
if (reset !== undefined) {
|
|
439
568
|
const sessions = globalConfig.getSessions();
|
|
440
569
|
|
|
441
|
-
for (
|
|
442
|
-
globalConfig.setCurrentSession(
|
|
443
|
-
await
|
|
570
|
+
for (const sessionId of sessions.map((session) => session.id)) {
|
|
571
|
+
globalConfig.setCurrentSession(sessionId);
|
|
572
|
+
await deleteServerSession(sessionId);
|
|
444
573
|
}
|
|
574
|
+
|
|
575
|
+
for (const sessionId of globalConfig.getSessionIds()) {
|
|
576
|
+
deleteLocalSession(sessionId);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
globalConfig.setCurrentSession("");
|
|
445
580
|
}
|
|
446
581
|
|
|
447
582
|
if (!debug) {
|
package/lib/commands/push.ts
CHANGED
|
@@ -2324,7 +2324,7 @@ const pushCollection = async (): Promise<void> => {
|
|
|
2324
2324
|
const { successfullyPushed, errors } = result;
|
|
2325
2325
|
|
|
2326
2326
|
if (successfullyPushed === 0) {
|
|
2327
|
-
|
|
2327
|
+
warn("No collections were pushed.");
|
|
2328
2328
|
} else {
|
|
2329
2329
|
success(`Successfully pushed ${successfullyPushed} collections.`);
|
|
2330
2330
|
}
|
|
@@ -250,6 +250,43 @@ export class Attributes {
|
|
|
250
250
|
encrypt: attribute.encrypt,
|
|
251
251
|
});
|
|
252
252
|
}
|
|
253
|
+
case "varchar":
|
|
254
|
+
return databasesService.createVarcharAttribute({
|
|
255
|
+
databaseId,
|
|
256
|
+
collectionId,
|
|
257
|
+
key: attribute.key,
|
|
258
|
+
size: attribute.size,
|
|
259
|
+
required: attribute.required,
|
|
260
|
+
xdefault: attribute.default,
|
|
261
|
+
array: attribute.array,
|
|
262
|
+
});
|
|
263
|
+
case "text":
|
|
264
|
+
return databasesService.createTextAttribute({
|
|
265
|
+
databaseId,
|
|
266
|
+
collectionId,
|
|
267
|
+
key: attribute.key,
|
|
268
|
+
required: attribute.required,
|
|
269
|
+
xdefault: attribute.default,
|
|
270
|
+
array: attribute.array,
|
|
271
|
+
});
|
|
272
|
+
case "mediumtext":
|
|
273
|
+
return databasesService.createMediumtextAttribute({
|
|
274
|
+
databaseId,
|
|
275
|
+
collectionId,
|
|
276
|
+
key: attribute.key,
|
|
277
|
+
required: attribute.required,
|
|
278
|
+
xdefault: attribute.default,
|
|
279
|
+
array: attribute.array,
|
|
280
|
+
});
|
|
281
|
+
case "longtext":
|
|
282
|
+
return databasesService.createLongtextAttribute({
|
|
283
|
+
databaseId,
|
|
284
|
+
collectionId,
|
|
285
|
+
key: attribute.key,
|
|
286
|
+
required: attribute.required,
|
|
287
|
+
xdefault: attribute.default,
|
|
288
|
+
array: attribute.array,
|
|
289
|
+
});
|
|
253
290
|
case "integer":
|
|
254
291
|
return databasesService.createIntegerAttribute({
|
|
255
292
|
databaseId,
|
|
@@ -382,6 +419,39 @@ export class Attributes {
|
|
|
382
419
|
xdefault: attribute.default,
|
|
383
420
|
});
|
|
384
421
|
}
|
|
422
|
+
case "varchar":
|
|
423
|
+
return databasesService.updateVarcharAttribute({
|
|
424
|
+
databaseId,
|
|
425
|
+
collectionId,
|
|
426
|
+
key: attribute.key,
|
|
427
|
+
required: attribute.required,
|
|
428
|
+
xdefault: attribute.default,
|
|
429
|
+
size: attribute.size,
|
|
430
|
+
});
|
|
431
|
+
case "text":
|
|
432
|
+
return databasesService.updateTextAttribute({
|
|
433
|
+
databaseId,
|
|
434
|
+
collectionId,
|
|
435
|
+
key: attribute.key,
|
|
436
|
+
required: attribute.required,
|
|
437
|
+
xdefault: attribute.default,
|
|
438
|
+
});
|
|
439
|
+
case "mediumtext":
|
|
440
|
+
return databasesService.updateMediumtextAttribute({
|
|
441
|
+
databaseId,
|
|
442
|
+
collectionId,
|
|
443
|
+
key: attribute.key,
|
|
444
|
+
required: attribute.required,
|
|
445
|
+
xdefault: attribute.default,
|
|
446
|
+
});
|
|
447
|
+
case "longtext":
|
|
448
|
+
return databasesService.updateLongtextAttribute({
|
|
449
|
+
databaseId,
|
|
450
|
+
collectionId,
|
|
451
|
+
key: attribute.key,
|
|
452
|
+
required: attribute.required,
|
|
453
|
+
xdefault: attribute.default,
|
|
454
|
+
});
|
|
385
455
|
case "integer":
|
|
386
456
|
return databasesService.updateIntegerAttribute({
|
|
387
457
|
databaseId,
|
package/lib/config.ts
CHANGED
|
@@ -749,15 +749,15 @@ class Global extends Config<GlobalConfigData> {
|
|
|
749
749
|
|
|
750
750
|
sessions.forEach((sessionId) => {
|
|
751
751
|
const sessionData = (this.data as any)[sessionId];
|
|
752
|
-
const email = sessionData[Global.PREFERENCE_EMAIL];
|
|
753
|
-
const endpoint = sessionData[Global.PREFERENCE_ENDPOINT];
|
|
752
|
+
const email = sessionData[Global.PREFERENCE_EMAIL] ?? "";
|
|
753
|
+
const endpoint = sessionData[Global.PREFERENCE_ENDPOINT] ?? "";
|
|
754
754
|
const key = `${email}|${endpoint}`;
|
|
755
755
|
|
|
756
756
|
if (sessionId === current || !sessionMap.has(key)) {
|
|
757
757
|
sessionMap.set(key, {
|
|
758
758
|
id: sessionId,
|
|
759
|
-
endpoint
|
|
760
|
-
email
|
|
759
|
+
endpoint,
|
|
760
|
+
email,
|
|
761
761
|
});
|
|
762
762
|
}
|
|
763
763
|
});
|
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 = '13.
|
|
4
|
+
export const SDK_VERSION = '13.3.1';
|
|
5
5
|
export const SDK_NAME = 'Command Line';
|
|
6
6
|
export const SDK_PLATFORM = 'console';
|
|
7
7
|
export const SDK_LANGUAGE = 'cli';
|