appwrite-cli 13.6.0 → 14.0.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.
- package/.github/workflows/ci.yml +66 -0
- package/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/cli.ts +3 -3
- package/dist/bundle-win-arm64.mjs +608 -310
- package/dist/cli.cjs +608 -310
- package/dist/index.cjs +354 -183
- package/dist/index.js +354 -183
- 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 +2 -0
- package/dist/lib/commands/generate.d.ts.map +1 -1
- package/dist/lib/commands/generators/base.d.ts +25 -2
- package/dist/lib/commands/generators/base.d.ts.map +1 -1
- package/dist/lib/commands/generators/index.d.ts +1 -1
- package/dist/lib/commands/generators/index.d.ts.map +1 -1
- package/dist/lib/commands/generators/typescript/databases.d.ts +2 -2
- package/dist/lib/commands/generators/typescript/databases.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/docs/examples/projects/update-status.md +5 -0
- package/docs/examples/sites/create-deployment.md +1 -2
- 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 +23 -8
- package/lib/commands/generators/base.ts +33 -2
- package/lib/commands/generators/index.ts +1 -0
- package/lib/commands/generators/typescript/databases.ts +31 -21
- 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/services/account.ts +1 -1
- package/lib/commands/services/databases.ts +20 -19
- package/lib/commands/services/health.ts +13 -0
- package/lib/commands/services/messaging.ts +1 -1
- package/lib/commands/services/projects.ts +25 -0
- package/lib/commands/services/sites.ts +8 -3
- package/lib/commands/services/tables-db.ts +3 -2
- package/lib/commands/services/teams.ts +2 -2
- 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 +8 -2
- package/scoop/appwrite.config.json +3 -3
|
@@ -314,7 +314,7 @@ databases
|
|
|
314
314
|
.description(`Create a boolean attribute.
|
|
315
315
|
`)
|
|
316
316
|
.requiredOption(`--database-id <database-id>`, `Database ID.`)
|
|
317
|
-
.requiredOption(`--collection-id <collection-id>`, `Collection ID. You can create a new
|
|
317
|
+
.requiredOption(`--collection-id <collection-id>`, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`)
|
|
318
318
|
.requiredOption(`--key <key>`, `Attribute Key.`)
|
|
319
319
|
.requiredOption(`--required <required>`, `Is attribute required?`, parseBool)
|
|
320
320
|
.option(
|
|
@@ -801,6 +801,22 @@ databases
|
|
|
801
801
|
),
|
|
802
802
|
);
|
|
803
803
|
|
|
804
|
+
databases
|
|
805
|
+
.command(`update-relationship-attribute`)
|
|
806
|
+
.description(`Update relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes).
|
|
807
|
+
`)
|
|
808
|
+
.requiredOption(`--database-id <database-id>`, `Database ID.`)
|
|
809
|
+
.requiredOption(`--collection-id <collection-id>`, `Collection ID.`)
|
|
810
|
+
.requiredOption(`--key <key>`, `Attribute Key.`)
|
|
811
|
+
.option(`--on-delete <on-delete>`, `Constraints option`)
|
|
812
|
+
.option(`--new-key <new-key>`, `New Attribute Key.`)
|
|
813
|
+
.action(
|
|
814
|
+
actionRunner(
|
|
815
|
+
async ({ databaseId, collectionId, key, onDelete, newKey }) =>
|
|
816
|
+
parse(await (await getDatabasesClient()).updateRelationshipAttribute(databaseId, collectionId, key, onDelete, newKey)),
|
|
817
|
+
),
|
|
818
|
+
);
|
|
819
|
+
|
|
804
820
|
databases
|
|
805
821
|
.command(`create-string-attribute`)
|
|
806
822
|
.description(`Create a string attribute.
|
|
@@ -1005,22 +1021,6 @@ databases
|
|
|
1005
1021
|
),
|
|
1006
1022
|
);
|
|
1007
1023
|
|
|
1008
|
-
databases
|
|
1009
|
-
.command(`update-relationship-attribute`)
|
|
1010
|
-
.description(`Update relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes).
|
|
1011
|
-
`)
|
|
1012
|
-
.requiredOption(`--database-id <database-id>`, `Database ID.`)
|
|
1013
|
-
.requiredOption(`--collection-id <collection-id>`, `Collection ID.`)
|
|
1014
|
-
.requiredOption(`--key <key>`, `Attribute Key.`)
|
|
1015
|
-
.option(`--on-delete <on-delete>`, `Constraints option`)
|
|
1016
|
-
.option(`--new-key <new-key>`, `New Attribute Key.`)
|
|
1017
|
-
.action(
|
|
1018
|
-
actionRunner(
|
|
1019
|
-
async ({ databaseId, collectionId, key, onDelete, newKey }) =>
|
|
1020
|
-
parse(await (await getDatabasesClient()).updateRelationshipAttribute(databaseId, collectionId, key, onDelete, newKey)),
|
|
1021
|
-
),
|
|
1022
|
-
);
|
|
1023
|
-
|
|
1024
1024
|
databases
|
|
1025
1025
|
.command(`list-documents`)
|
|
1026
1026
|
.description(`Get a list of all the user's documents in a given collection. You can use the query params to filter your results.`)
|
|
@@ -1034,10 +1034,11 @@ databases
|
|
|
1034
1034
|
(value: string | undefined) =>
|
|
1035
1035
|
value === undefined ? true : parseBool(value),
|
|
1036
1036
|
)
|
|
1037
|
+
.option(`--ttl <ttl>`, `TTL (seconds) for cached responses when caching is enabled for select queries. Must be between 0 and 86400 (24 hours).`, parseInteger)
|
|
1037
1038
|
.action(
|
|
1038
1039
|
actionRunner(
|
|
1039
|
-
async ({ databaseId, collectionId, queries, transactionId, total }) =>
|
|
1040
|
-
parse(await (await getDatabasesClient()).listDocuments(databaseId, collectionId, queries, transactionId, total)),
|
|
1040
|
+
async ({ databaseId, collectionId, queries, transactionId, total, ttl }) =>
|
|
1041
|
+
parse(await (await getDatabasesClient()).listDocuments(databaseId, collectionId, queries, transactionId, total, ttl)),
|
|
1041
1042
|
),
|
|
1042
1043
|
);
|
|
1043
1044
|
|
|
@@ -64,6 +64,19 @@ health
|
|
|
64
64
|
),
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
+
health
|
|
68
|
+
.command(`get-console-pausing`)
|
|
69
|
+
.description(`Get console pausing health status. Monitors projects approaching the pause threshold to detect potential issues with console access tracking.
|
|
70
|
+
`)
|
|
71
|
+
.option(`--threshold <threshold>`, `Percentage threshold of projects approaching pause. When hit (equal or higher), endpoint returns server error. Default value is 10.`, parseInteger)
|
|
72
|
+
.option(`--inactivity-days <inactivity-days>`, `Number of days of inactivity before a project is paused. Should match the plan's projectInactivityDays setting. Default value is 7.`, parseInteger)
|
|
73
|
+
.action(
|
|
74
|
+
actionRunner(
|
|
75
|
+
async ({ threshold, inactivityDays }) =>
|
|
76
|
+
parse(await (await getHealthClient()).getConsolePausing(threshold, inactivityDays)),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
|
|
67
80
|
health
|
|
68
81
|
.command(`get-db`)
|
|
69
82
|
.description(`Check the Appwrite database servers are up and connection is successful.`)
|
|
@@ -993,7 +993,7 @@ messaging
|
|
|
993
993
|
.command(`list-subscribers`)
|
|
994
994
|
.description(`Get a list of all subscribers from the current Appwrite project.`)
|
|
995
995
|
.requiredOption(`--topic-id <topic-id>`, `Topic ID. The topic ID subscribed to.`)
|
|
996
|
-
.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:
|
|
996
|
+
.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: targetId, topicId, userId, providerType`)
|
|
997
997
|
.option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`)
|
|
998
998
|
.option(
|
|
999
999
|
`--total [value]`,
|
|
@@ -270,6 +270,18 @@ projects
|
|
|
270
270
|
),
|
|
271
271
|
);
|
|
272
272
|
|
|
273
|
+
projects
|
|
274
|
+
.command(`update-console-access`)
|
|
275
|
+
.description(`Record console access to a project. This endpoint updates the last accessed timestamp for the project to track console activity.
|
|
276
|
+
`)
|
|
277
|
+
.requiredOption(`--project-id <project-id>`, `Project ID`)
|
|
278
|
+
.action(
|
|
279
|
+
actionRunner(
|
|
280
|
+
async ({ projectId }) =>
|
|
281
|
+
parse(await (await getProjectsClient()).updateConsoleAccess(projectId)),
|
|
282
|
+
),
|
|
283
|
+
);
|
|
284
|
+
|
|
273
285
|
projects
|
|
274
286
|
.command(`list-dev-keys`)
|
|
275
287
|
.description(`List all the project\'s dev keys. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development.'`)
|
|
@@ -639,6 +651,19 @@ projects
|
|
|
639
651
|
),
|
|
640
652
|
);
|
|
641
653
|
|
|
654
|
+
projects
|
|
655
|
+
.command(`update-status`)
|
|
656
|
+
.description(`Update the status of a project. Can be used to archive/restore projects, and to restore paused projects. When restoring a paused project, the console fingerprint header must be provided and the project must not be blocked for any reason other than inactivity.
|
|
657
|
+
`)
|
|
658
|
+
.requiredOption(`--project-id <project-id>`, `Project ID`)
|
|
659
|
+
.requiredOption(`--status <status>`, `New status for the project`)
|
|
660
|
+
.action(
|
|
661
|
+
actionRunner(
|
|
662
|
+
async ({ projectId, status }) =>
|
|
663
|
+
parse(await (await getProjectsClient()).updateStatus(projectId, status)),
|
|
664
|
+
),
|
|
665
|
+
);
|
|
666
|
+
|
|
642
667
|
projects
|
|
643
668
|
.command(`update-team`)
|
|
644
669
|
.description(`Update the team ID of a project allowing for it to be transferred to another team.`)
|
|
@@ -243,14 +243,19 @@ sites
|
|
|
243
243
|
.description(`Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.`)
|
|
244
244
|
.requiredOption(`--site-id <site-id>`, `Site ID.`)
|
|
245
245
|
.requiredOption(`--code <code>`, `Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.`)
|
|
246
|
-
.requiredOption(`--activate <activate>`, `Automatically activate the deployment when it is finished building.`, parseBool)
|
|
247
246
|
.option(`--install-command <install-command>`, `Install Commands.`)
|
|
248
247
|
.option(`--build-command <build-command>`, `Build Commands.`)
|
|
249
248
|
.option(`--output-directory <output-directory>`, `Output Directory.`)
|
|
249
|
+
.option(
|
|
250
|
+
`--activate [value]`,
|
|
251
|
+
`Automatically activate the deployment when it is finished building.`,
|
|
252
|
+
(value: string | undefined) =>
|
|
253
|
+
value === undefined ? true : parseBool(value),
|
|
254
|
+
)
|
|
250
255
|
.action(
|
|
251
256
|
actionRunner(
|
|
252
|
-
async ({ siteId, code,
|
|
253
|
-
parse(await (await getSitesClient()).createDeployment(siteId, code,
|
|
257
|
+
async ({ siteId, code, installCommand, buildCommand, outputDirectory, activate }) =>
|
|
258
|
+
parse(await (await getSitesClient()).createDeployment(siteId, code, installCommand, buildCommand, outputDirectory, activate)),
|
|
254
259
|
),
|
|
255
260
|
);
|
|
256
261
|
|
|
@@ -1109,10 +1109,11 @@ tablesDB
|
|
|
1109
1109
|
(value: string | undefined) =>
|
|
1110
1110
|
value === undefined ? true : parseBool(value),
|
|
1111
1111
|
)
|
|
1112
|
+
.option(`--ttl <ttl>`, `TTL (seconds) for cached responses when caching is enabled for select queries. Must be between 0 and 86400 (24 hours).`, parseInteger)
|
|
1112
1113
|
.action(
|
|
1113
1114
|
actionRunner(
|
|
1114
|
-
async ({ databaseId, tableId, queries, transactionId, total }) =>
|
|
1115
|
-
parse(await (await getTablesDBClient()).listRows(databaseId, tableId, queries, transactionId, total)),
|
|
1115
|
+
async ({ databaseId, tableId, queries, transactionId, total, ttl }) =>
|
|
1116
|
+
parse(await (await getTablesDBClient()).listRows(databaseId, tableId, queries, transactionId, total, ttl)),
|
|
1116
1117
|
),
|
|
1117
1118
|
);
|
|
1118
1119
|
|
|
@@ -139,7 +139,7 @@ Use the \`url\` parameter to redirect the user from the invitation email to your
|
|
|
139
139
|
Please note that to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console.
|
|
140
140
|
`)
|
|
141
141
|
.requiredOption(`--team-id <team-id>`, `Team ID.`)
|
|
142
|
-
.requiredOption(`--roles [roles...]`, `Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each
|
|
142
|
+
.requiredOption(`--roles [roles...]`, `Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long.`)
|
|
143
143
|
.option(`--email <email>`, `Email of the new team member.`)
|
|
144
144
|
.option(`--user-id <user-id>`, `ID of the user to be added to a team.`)
|
|
145
145
|
.option(`--phone <phone>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`)
|
|
@@ -170,7 +170,7 @@ teams
|
|
|
170
170
|
`)
|
|
171
171
|
.requiredOption(`--team-id <team-id>`, `Team ID.`)
|
|
172
172
|
.requiredOption(`--membership-id <membership-id>`, `Membership ID.`)
|
|
173
|
-
.requiredOption(`--roles [roles...]`, `An array of strings. Use this param to set the user's roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each
|
|
173
|
+
.requiredOption(`--roles [roles...]`, `An array of strings. Use this param to set the user's roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long.`)
|
|
174
174
|
.action(
|
|
175
175
|
actionRunner(
|
|
176
176
|
async ({ teamId, membershipId, roles }) =>
|
package/lib/commands/types.ts
CHANGED
|
@@ -83,6 +83,16 @@ interface TypesOptions {
|
|
|
83
83
|
strict: boolean;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
type TypeAttribute = Record<string, unknown> & {
|
|
87
|
+
relatedTable?: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
type TypeDataItem = Record<string, unknown> & {
|
|
91
|
+
name: string;
|
|
92
|
+
attributes?: TypeAttribute[];
|
|
93
|
+
columns?: TypeAttribute[];
|
|
94
|
+
};
|
|
95
|
+
|
|
86
96
|
const typesCommand = actionRunner(
|
|
87
97
|
async (rawOutputDirectory: string, { language, strict }: TypesOptions) => {
|
|
88
98
|
if (language === "auto") {
|
|
@@ -126,13 +136,11 @@ const typesCommand = actionRunner(
|
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
// Try tables first, fallback to collections
|
|
129
|
-
|
|
130
|
-
let collections:
|
|
131
|
-
let dataSource = "tables";
|
|
139
|
+
const tables = localConfig.getTables();
|
|
140
|
+
let collections: TypeDataItem[] = [];
|
|
132
141
|
|
|
133
142
|
if (tables.length === 0) {
|
|
134
143
|
collections = localConfig.getCollections();
|
|
135
|
-
dataSource = "collections";
|
|
136
144
|
|
|
137
145
|
if (collections.length === 0) {
|
|
138
146
|
const configFileName = path.basename(localConfig.path);
|
|
@@ -143,7 +151,8 @@ const typesCommand = actionRunner(
|
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
// Use tables if available, otherwise use collections
|
|
146
|
-
let dataItems:
|
|
154
|
+
let dataItems: TypeDataItem[] =
|
|
155
|
+
tables.length > 0 ? (tables as TypeDataItem[]) : collections;
|
|
147
156
|
const itemType = tables.length > 0 ? "tables" : "collections";
|
|
148
157
|
|
|
149
158
|
// Normalize tables data: rename 'columns' to 'attributes' for template compatibility
|
|
@@ -152,7 +161,7 @@ const typesCommand = actionRunner(
|
|
|
152
161
|
const { columns, ...rest } = table;
|
|
153
162
|
return {
|
|
154
163
|
...rest,
|
|
155
|
-
attributes: (columns || []).map((column:
|
|
164
|
+
attributes: (columns || []).map((column: TypeAttribute) => {
|
|
156
165
|
if (column.relatedTable) {
|
|
157
166
|
const { relatedTable, ...columnRest } = column;
|
|
158
167
|
return {
|
|
@@ -167,14 +176,15 @@ const typesCommand = actionRunner(
|
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
log(
|
|
170
|
-
`Found ${dataItems.length} ${itemType}: ${dataItems.map((c
|
|
179
|
+
`Found ${dataItems.length} ${itemType}: ${dataItems.map((c) => c.name).join(", ")}`,
|
|
171
180
|
);
|
|
172
181
|
|
|
173
182
|
// Use columns if available, otherwise use attributes
|
|
174
183
|
const resourceType = tables.length > 0 ? "columns" : "attributes";
|
|
175
184
|
|
|
176
185
|
const totalAttributes = dataItems.reduce(
|
|
177
|
-
(count: number, item:
|
|
186
|
+
(count: number, item: TypeDataItem) =>
|
|
187
|
+
count + (item.attributes || []).length,
|
|
178
188
|
0,
|
|
179
189
|
);
|
|
180
190
|
log(`Found ${totalAttributes} ${resourceType} across all ${itemType}`);
|
package/lib/commands/update.ts
CHANGED
|
@@ -3,7 +3,11 @@ import { Command } from "commander";
|
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import inquirer from "inquirer";
|
|
5
5
|
import { success, log, warn, error, hint, actionRunner } from "../parser.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getLatestVersion,
|
|
8
|
+
compareVersions,
|
|
9
|
+
getErrorMessage,
|
|
10
|
+
} from "../utils.js";
|
|
7
11
|
import {
|
|
8
12
|
GITHUB_RELEASES_URL,
|
|
9
13
|
NPM_PACKAGE_NAME,
|
|
@@ -12,6 +16,8 @@ import {
|
|
|
12
16
|
import packageJson from "../../package.json" with { type: "json" };
|
|
13
17
|
const { version } = packageJson;
|
|
14
18
|
|
|
19
|
+
type ExecCommandOptions = Exclude<Parameters<typeof spawn>[2], undefined>;
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Check if the CLI was installed via npm
|
|
17
23
|
*/
|
|
@@ -36,7 +42,7 @@ const isInstalledViaNpm = (): boolean => {
|
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
return false;
|
|
39
|
-
} catch (
|
|
45
|
+
} catch (_e) {
|
|
40
46
|
return false;
|
|
41
47
|
}
|
|
42
48
|
};
|
|
@@ -51,7 +57,7 @@ const isInstalledViaHomebrew = (): boolean => {
|
|
|
51
57
|
scriptPath.includes("/opt/homebrew/") ||
|
|
52
58
|
scriptPath.includes("/usr/local/Cellar/")
|
|
53
59
|
);
|
|
54
|
-
} catch (
|
|
60
|
+
} catch (_e) {
|
|
55
61
|
return false;
|
|
56
62
|
}
|
|
57
63
|
};
|
|
@@ -62,7 +68,7 @@ const isInstalledViaHomebrew = (): boolean => {
|
|
|
62
68
|
const execCommand = (
|
|
63
69
|
command: string,
|
|
64
70
|
args: string[] = [],
|
|
65
|
-
options:
|
|
71
|
+
options: ExecCommandOptions = {},
|
|
66
72
|
): Promise<void> => {
|
|
67
73
|
return new Promise((resolve, reject) => {
|
|
68
74
|
const child = spawn(command, args, {
|
|
@@ -94,17 +100,16 @@ const updateViaNpm = async (): Promise<void> => {
|
|
|
94
100
|
console.log("");
|
|
95
101
|
success("Updated to latest version via npm!");
|
|
96
102
|
hint("Run 'appwrite --version' to verify the new version.");
|
|
97
|
-
} catch (e:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
) {
|
|
103
|
+
} catch (e: unknown) {
|
|
104
|
+
const message = getErrorMessage(e);
|
|
105
|
+
|
|
106
|
+
if (message.includes("EEXIST") || message.includes("file already exists")) {
|
|
102
107
|
console.log("");
|
|
103
108
|
success("Latest version is already installed via npm!");
|
|
104
109
|
hint("The CLI is up to date. Run 'appwrite --version' to verify.");
|
|
105
110
|
} else {
|
|
106
111
|
console.log("");
|
|
107
|
-
error(`Failed to update via npm: ${
|
|
112
|
+
error(`Failed to update via npm: ${message}`);
|
|
108
113
|
hint(`Try running: npm install -g ${NPM_PACKAGE_NAME}@latest --force`);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
@@ -119,17 +124,19 @@ const updateViaHomebrew = async (): Promise<void> => {
|
|
|
119
124
|
console.log("");
|
|
120
125
|
success("Updated to latest version via Homebrew!");
|
|
121
126
|
hint("Run 'appwrite --version' to verify the new version.");
|
|
122
|
-
} catch (e:
|
|
127
|
+
} catch (e: unknown) {
|
|
128
|
+
const message = getErrorMessage(e);
|
|
129
|
+
|
|
123
130
|
if (
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
message.includes("already installed") ||
|
|
132
|
+
message.includes("up-to-date")
|
|
126
133
|
) {
|
|
127
134
|
console.log("");
|
|
128
135
|
success("Latest version is already installed via Homebrew!");
|
|
129
136
|
hint("The CLI is up to date. Run 'appwrite --version' to verify.");
|
|
130
137
|
} else {
|
|
131
138
|
console.log("");
|
|
132
|
-
error(`Failed to update via Homebrew: ${
|
|
139
|
+
error(`Failed to update via Homebrew: ${message}`);
|
|
133
140
|
hint("Try running: brew upgrade appwrite");
|
|
134
141
|
}
|
|
135
142
|
}
|
|
@@ -230,9 +237,10 @@ const updateCli = async ({ manual }: UpdateOptions = {}): Promise<void> => {
|
|
|
230
237
|
} else {
|
|
231
238
|
await chooseUpdateMethod(latestVersion);
|
|
232
239
|
}
|
|
233
|
-
} catch (e:
|
|
240
|
+
} catch (e: unknown) {
|
|
241
|
+
const message = getErrorMessage(e);
|
|
234
242
|
console.log("");
|
|
235
|
-
error(`Failed to check for updates: ${
|
|
243
|
+
error(`Failed to check for updates: ${message}`);
|
|
236
244
|
hint(`You can manually check for updates at: ${GITHUB_RELEASES_URL}`);
|
|
237
245
|
}
|
|
238
246
|
};
|
|
@@ -76,7 +76,7 @@ export class Attributes {
|
|
|
76
76
|
return answers.changes;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
const answers = await inquirer.prompt(questionPushChanges);
|
|
80
80
|
|
|
81
81
|
if (answers.changes !== "YES" && answers.changes !== "NO") {
|
|
82
82
|
answers.changes = await fixConfirmation();
|
|
@@ -148,9 +148,9 @@ export class Attributes {
|
|
|
148
148
|
const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection["$id"]})`;
|
|
149
149
|
const action = chalk.cyan(recreating ? "recreating" : "changing");
|
|
150
150
|
let reason = "";
|
|
151
|
-
|
|
151
|
+
const attribute = recreating ? remote : local;
|
|
152
152
|
|
|
153
|
-
for (
|
|
153
|
+
for (const key of Object.keys(remote)) {
|
|
154
154
|
if (!KeysAttributes.has(key)) {
|
|
155
155
|
continue;
|
|
156
156
|
}
|
|
@@ -737,7 +737,7 @@ export class Attributes {
|
|
|
737
737
|
log(`Creating indexes ...`);
|
|
738
738
|
|
|
739
739
|
const databasesService = await getDatabasesService(this.client);
|
|
740
|
-
for (
|
|
740
|
+
for (const index of indexes) {
|
|
741
741
|
await databasesService.createIndex({
|
|
742
742
|
databaseId: collection["databaseId"],
|
|
743
743
|
collectionId: collection["$id"],
|
|
@@ -769,7 +769,7 @@ export class Attributes {
|
|
|
769
769
|
): Promise<void> => {
|
|
770
770
|
log(`Creating attributes ...`);
|
|
771
771
|
|
|
772
|
-
for (
|
|
772
|
+
for (const attribute of attributes) {
|
|
773
773
|
if (attribute.side !== "child") {
|
|
774
774
|
await this.createAttribute(
|
|
775
775
|
collection["databaseId"],
|
|
@@ -803,7 +803,7 @@ export class Attributes {
|
|
|
803
803
|
): Promise<void> => {
|
|
804
804
|
log(`Creating columns ...`);
|
|
805
805
|
|
|
806
|
-
for (
|
|
806
|
+
for (const column of columns) {
|
|
807
807
|
if (column.side !== "child") {
|
|
808
808
|
await this.createAttribute(table["databaseId"], table["$id"], column);
|
|
809
809
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
|
+
import { AppwriteException } from "@appwrite.io/console";
|
|
3
4
|
import { cliConfig, success, warn, log, drawTable } from "../../parser.js";
|
|
4
5
|
import { whitelistKeys } from "../../config.js";
|
|
5
6
|
import {
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
/**
|
|
11
12
|
* Check if a value is considered empty
|
|
12
13
|
*/
|
|
13
|
-
export const isEmpty = (value:
|
|
14
|
+
export const isEmpty = (value: unknown): boolean =>
|
|
14
15
|
value === null ||
|
|
15
16
|
value === undefined ||
|
|
16
17
|
(typeof value === "string" && value.trim().length === 0) ||
|
|
@@ -33,7 +34,7 @@ export const getConfirmation = async (): Promise<boolean> => {
|
|
|
33
34
|
return answers.changes;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
const answers = await inquirer.prompt(questionPushChanges);
|
|
37
38
|
|
|
38
39
|
if (answers.changes !== "YES" && answers.changes !== "NO") {
|
|
39
40
|
answers.changes = await fixConfirmation();
|
|
@@ -57,9 +58,9 @@ interface ObjectChange {
|
|
|
57
58
|
local: string;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
type ComparableValue = boolean | number | string |
|
|
61
|
+
type ComparableValue = boolean | number | string | unknown[] | undefined;
|
|
61
62
|
|
|
62
|
-
export const getObjectChanges = <T extends Record<string,
|
|
63
|
+
export const getObjectChanges = <T extends Record<string, unknown>>(
|
|
63
64
|
remote: T,
|
|
64
65
|
local: T,
|
|
65
66
|
index: keyof T,
|
|
@@ -110,8 +111,10 @@ export const getObjectChanges = <T extends Record<string, any>>(
|
|
|
110
111
|
* Compares local resources with remote resources and prompts user for confirmation
|
|
111
112
|
*/
|
|
112
113
|
export const approveChanges = async (
|
|
113
|
-
resource:
|
|
114
|
-
resourceGetFunction:
|
|
114
|
+
resource: Array<Record<string, unknown>>,
|
|
115
|
+
resourceGetFunction: (
|
|
116
|
+
options: Record<string, unknown>,
|
|
117
|
+
) => Promise<Record<string, unknown>>,
|
|
115
118
|
keys: Set<string>,
|
|
116
119
|
resourceName: string,
|
|
117
120
|
resourcePlural: string,
|
|
@@ -120,12 +123,12 @@ export const approveChanges = async (
|
|
|
120
123
|
secondResourceName: string = "",
|
|
121
124
|
): Promise<boolean> => {
|
|
122
125
|
log("Checking for changes ...");
|
|
123
|
-
const changes:
|
|
126
|
+
const changes: Array<Record<string, unknown>> = [];
|
|
124
127
|
|
|
125
128
|
await Promise.all(
|
|
126
129
|
resource.map(async (localResource) => {
|
|
127
130
|
try {
|
|
128
|
-
const options: Record<string,
|
|
131
|
+
const options: Record<string, unknown> = {
|
|
129
132
|
[resourceName]: localResource["$id"],
|
|
130
133
|
};
|
|
131
134
|
|
|
@@ -135,7 +138,7 @@ export const approveChanges = async (
|
|
|
135
138
|
|
|
136
139
|
const remoteResource = await resourceGetFunction(options);
|
|
137
140
|
|
|
138
|
-
for (
|
|
141
|
+
for (const [key, value] of Object.entries(
|
|
139
142
|
whitelistKeys(remoteResource, keys),
|
|
140
143
|
)) {
|
|
141
144
|
if (skipKeys.includes(key)) {
|
|
@@ -146,28 +149,32 @@ export const approveChanges = async (
|
|
|
146
149
|
continue;
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
const localValue = localResource[key];
|
|
153
|
+
|
|
154
|
+
if (Array.isArray(value) && Array.isArray(localValue)) {
|
|
155
|
+
if (JSON.stringify(value) !== JSON.stringify(localValue)) {
|
|
151
156
|
changes.push({
|
|
152
157
|
id: localResource["$id"],
|
|
153
158
|
key,
|
|
154
159
|
remote: chalk.red((value as string[]).join("\n")),
|
|
155
|
-
local: chalk.green(
|
|
160
|
+
local: chalk.green(
|
|
161
|
+
localValue.map((entry) => String(entry)).join("\n"),
|
|
162
|
+
),
|
|
156
163
|
});
|
|
157
164
|
}
|
|
158
|
-
} else if (value !==
|
|
165
|
+
} else if (value !== localValue) {
|
|
159
166
|
changes.push({
|
|
160
167
|
id: localResource["$id"],
|
|
161
168
|
key,
|
|
162
|
-
remote: chalk.red(value),
|
|
163
|
-
local: chalk.green(
|
|
169
|
+
remote: chalk.red(String(value ?? "")),
|
|
170
|
+
local: chalk.green(String(localValue ?? "")),
|
|
164
171
|
});
|
|
165
172
|
}
|
|
166
173
|
}
|
|
167
|
-
} catch (e:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
} catch (e: unknown) {
|
|
175
|
+
const isNotFound =
|
|
176
|
+
e instanceof AppwriteException && Number(e.code) === 404;
|
|
177
|
+
if (!isNotFound) throw e;
|
|
171
178
|
}
|
|
172
179
|
}),
|
|
173
180
|
);
|