appwrite-cli 0.18.2 → 0.18.5
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/README.md +3 -15
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.js +2 -2
- package/lib/commands/account.js +5 -5
- package/lib/commands/deploy.js +153 -71
- package/lib/commands/generic.js +2 -2
- package/lib/commands/init.js +99 -39
- package/lib/parser.js +1 -1
- package/lib/questions.js +45 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Appwrite Command Line SDK
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
[](https://travis-ci.com/appwrite/sdk-generator)
|
|
6
6
|
[](https://twitter.com/appwrite)
|
|
7
7
|
[](https://appwrite.io/discord)
|
|
@@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using
|
|
|
29
29
|
|
|
30
30
|
```sh
|
|
31
31
|
$ appwrite -v
|
|
32
|
-
0.18.
|
|
32
|
+
0.18.5
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
### Install using prebuilt binaries
|
|
@@ -58,7 +58,7 @@ $ iwr -useb https://appwrite.io/cli/install.ps1 | iex
|
|
|
58
58
|
Once the installation completes, you can verify your install using
|
|
59
59
|
```
|
|
60
60
|
$ appwrite -v
|
|
61
|
-
0.18.
|
|
61
|
+
0.18.5
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## Getting Started
|
|
@@ -94,12 +94,6 @@ You can also fetch all the collections in your current project using
|
|
|
94
94
|
appwrite init collection
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
The CLI also comes with a convenient `--all` flag to perform both these steps at once.
|
|
98
|
-
|
|
99
|
-
```sh
|
|
100
|
-
appwrite init --all
|
|
101
|
-
```
|
|
102
|
-
|
|
103
97
|
* ### Creating and deploying cloud functions
|
|
104
98
|
|
|
105
99
|
The CLI makes it extremely easy to create and deploy Appwrite's cloud functions. Initialise your new function using
|
|
@@ -145,12 +139,6 @@ Similarly, you can deploy all your collections to your Appwrite server using
|
|
|
145
139
|
appwrite deploy collections
|
|
146
140
|
```
|
|
147
141
|
|
|
148
|
-
The `deploy` command also comes with a convenient `--all` flag to deploy all your functions and collections at once.
|
|
149
|
-
|
|
150
|
-
```sh
|
|
151
|
-
appwrite deploy --all
|
|
152
|
-
```
|
|
153
|
-
|
|
154
142
|
> ### Note
|
|
155
143
|
> By default, requests to domains with self signed SSL certificates (or no certificates) are disabled. If you trust the domain, you can bypass the certificate validation using
|
|
156
144
|
```sh
|
package/install.ps1
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
# You can use "View source" of this page to see the full script.
|
|
14
14
|
|
|
15
15
|
# REPO
|
|
16
|
-
$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.
|
|
17
|
-
$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.
|
|
16
|
+
$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.5/appwrite-cli-win-x64.exe"
|
|
17
|
+
$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/0.18.5/appwrite-cli-win-arm64.exe"
|
|
18
18
|
|
|
19
19
|
$APPWRITE_BINARY_NAME = "appwrite.exe"
|
|
20
20
|
|
package/install.sh
CHANGED
|
@@ -97,7 +97,7 @@ printSuccess() {
|
|
|
97
97
|
downloadBinary() {
|
|
98
98
|
echo "[2/4] Downloading executable for $OS ($ARCH) ..."
|
|
99
99
|
|
|
100
|
-
GITHUB_LATEST_VERSION="0.18.
|
|
100
|
+
GITHUB_LATEST_VERSION="0.18.5"
|
|
101
101
|
GITHUB_FILE="appwrite-cli-${OS}-${ARCH}"
|
|
102
102
|
GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE"
|
|
103
103
|
|
package/lib/client.js
CHANGED
|
@@ -12,8 +12,8 @@ class Client {
|
|
|
12
12
|
this.endpoint = 'https://HOSTNAME/v1';
|
|
13
13
|
this.headers = {
|
|
14
14
|
'content-type': '',
|
|
15
|
-
'x-sdk-version': 'appwrite:cli:0.18.
|
|
16
|
-
'User-Agent' : `AppwriteCLI/0.18.
|
|
15
|
+
'x-sdk-version': 'appwrite:cli:0.18.5',
|
|
16
|
+
'User-Agent' : `AppwriteCLI/0.18.5 (${os.type()} ${os.version()}; ${os.arch()})`,
|
|
17
17
|
'X-Appwrite-Response-Format' : '0.15.0',
|
|
18
18
|
};
|
|
19
19
|
}
|
package/lib/commands/account.js
CHANGED
|
@@ -784,7 +784,7 @@ account
|
|
|
784
784
|
|
|
785
785
|
account
|
|
786
786
|
.command(`updatePhone`)
|
|
787
|
-
.description(`Update currently logged in user
|
|
787
|
+
.description(`Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST /account/verification/phone](/docs/client/account#accountCreatePhoneVerification) endpoint to send a confirmation SMS.`)
|
|
788
788
|
.requiredOption(`--number <number>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`)
|
|
789
789
|
.requiredOption(`--password <password>`, `User password. Must be at least 8 chars.`)
|
|
790
790
|
.action(actionRunner(accountUpdatePhone))
|
|
@@ -856,7 +856,7 @@ account
|
|
|
856
856
|
account
|
|
857
857
|
.command(`createOAuth2Session`)
|
|
858
858
|
.description(`Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. If there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user.. `)
|
|
859
|
-
.requiredOption(`--provider <provider>`, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, bitbucket, bitly, box, dailymotion, discord, dropbox, facebook, github, gitlab, google, linkedin, microsoft, notion, okta, paypal, paypalSandbox, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.`)
|
|
859
|
+
.requiredOption(`--provider <provider>`, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, autodesk, bitbucket, bitly, box, dailymotion, discord, dropbox, facebook, github, gitlab, google, linkedin, microsoft, notion, okta, paypal, paypalSandbox, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoom.`)
|
|
860
860
|
.option(`--success <success>`, `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`)
|
|
861
861
|
.option(`--failure <failure>`, `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`)
|
|
862
862
|
.option(`--scopes <scopes...>`, `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`)
|
|
@@ -864,14 +864,14 @@ account
|
|
|
864
864
|
|
|
865
865
|
account
|
|
866
866
|
.command(`createPhoneSession`)
|
|
867
|
-
.description(`Sends the user
|
|
867
|
+
.description(`Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [PUT /account/sessions/phone](/docs/client/account#accountUpdatePhoneSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes.`)
|
|
868
868
|
.requiredOption(`--userId <userId>`, `Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`)
|
|
869
869
|
.requiredOption(`--number <number>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`)
|
|
870
870
|
.action(actionRunner(accountCreatePhoneSession))
|
|
871
871
|
|
|
872
872
|
account
|
|
873
873
|
.command(`updatePhoneSession`)
|
|
874
|
-
.description(`Use this endpoint to complete creating
|
|
874
|
+
.description(`Use this endpoint to complete creating a session with SMS. Use the **userId** from the [createPhoneSession](/docs/client/account#accountCreatePhoneSession) endpoint and the **secret** received via SMS to successfully update and confirm the phone session.`)
|
|
875
875
|
.requiredOption(`--userId <userId>`, `User ID.`)
|
|
876
876
|
.requiredOption(`--secret <secret>`, `Valid verification token.`)
|
|
877
877
|
.action(actionRunner(accountUpdatePhoneSession))
|
|
@@ -914,7 +914,7 @@ account
|
|
|
914
914
|
|
|
915
915
|
account
|
|
916
916
|
.command(`createPhoneVerification`)
|
|
917
|
-
.description(`Use this endpoint to send a verification
|
|
917
|
+
.description(`Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](/docs/client/account#accountUpdatePhone) endpoint. Learn more about how to [complete the verification process](/docs/client/account#accountUpdatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.`)
|
|
918
918
|
.action(actionRunner(accountCreatePhoneVerification))
|
|
919
919
|
|
|
920
920
|
account
|
package/lib/commands/deploy.js
CHANGED
|
@@ -6,34 +6,37 @@ const { questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollect
|
|
|
6
6
|
const { actionRunner, success, log, error, commandDescriptions } = require("../parser");
|
|
7
7
|
const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsUpdateDeployment } = require('./functions');
|
|
8
8
|
const {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
databasesGet,
|
|
10
|
+
databasesCreate,
|
|
11
|
+
databasesCreateBooleanAttribute,
|
|
12
|
+
databasesGetCollection,
|
|
13
|
+
databasesCreateCollection,
|
|
14
|
+
databasesCreateStringAttribute,
|
|
15
|
+
databasesCreateIntegerAttribute,
|
|
16
|
+
databasesCreateFloatAttribute,
|
|
17
|
+
databasesCreateEmailAttribute,
|
|
18
|
+
databasesCreateIndex,
|
|
19
|
+
databasesCreateUrlAttribute,
|
|
20
|
+
databasesCreateIpAttribute,
|
|
21
|
+
databasesCreateEnumAttribute,
|
|
22
|
+
databasesDeleteAttribute,
|
|
23
|
+
databasesListAttributes,
|
|
24
|
+
databasesListIndexes,
|
|
25
|
+
databasesDeleteIndex
|
|
26
|
+
} = require("./databases");
|
|
25
27
|
|
|
26
28
|
const POOL_DEBOUNCE = 2000; // in milliseconds
|
|
27
29
|
const POOL_MAX_DEBOUNCES = 30;
|
|
28
30
|
|
|
29
31
|
const awaitPools = {
|
|
30
|
-
wipeAttributes: async (collectionId, iteration = 1) => {
|
|
32
|
+
wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
|
|
31
33
|
if (iteration > POOL_MAX_DEBOUNCES) {
|
|
32
34
|
return false;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
// TODO: Pagination?
|
|
36
|
-
const { attributes: remoteAttributes } = await
|
|
38
|
+
const { attributes: remoteAttributes } = await databasesListAttributes({
|
|
39
|
+
databaseId,
|
|
37
40
|
collectionId,
|
|
38
41
|
limit: 100,
|
|
39
42
|
parseOutput: false
|
|
@@ -44,15 +47,16 @@ const awaitPools = {
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
47
|
-
return await awaitPools.wipeAttributes(collectionId, iteration + 1);
|
|
50
|
+
return await awaitPools.wipeAttributes(databaseId, collectionId, iteration + 1);
|
|
48
51
|
},
|
|
49
|
-
wipeIndexes: async (collectionId, iteration = 1) => {
|
|
52
|
+
wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
|
|
50
53
|
if (iteration > POOL_MAX_DEBOUNCES) {
|
|
51
54
|
return false;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
// TODO: Pagination?
|
|
55
|
-
const { indexes: remoteIndexes } = await
|
|
58
|
+
const { indexes: remoteIndexes } = await databasesListIndexes({
|
|
59
|
+
databaseId,
|
|
56
60
|
collectionId,
|
|
57
61
|
limit: 100,
|
|
58
62
|
parseOutput: false
|
|
@@ -63,15 +67,16 @@ const awaitPools = {
|
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
66
|
-
return await awaitPools.wipeIndexes(collectionId, iteration + 1);
|
|
70
|
+
return await awaitPools.wipeIndexes(databaseId, collectionId, iteration + 1);
|
|
67
71
|
},
|
|
68
|
-
expectAttributes: async (collectionId, attributeKeys, iteration = 1) => {
|
|
72
|
+
expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
|
|
69
73
|
if (iteration > POOL_MAX_DEBOUNCES) {
|
|
70
74
|
return false;
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
// TODO: Pagination?
|
|
74
|
-
const { attributes: remoteAttributes } = await
|
|
78
|
+
const { attributes: remoteAttributes } = await databasesListAttributes({
|
|
79
|
+
databaseId,
|
|
75
80
|
collectionId,
|
|
76
81
|
limit: 100,
|
|
77
82
|
parseOutput: false
|
|
@@ -94,15 +99,16 @@ const awaitPools = {
|
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
97
|
-
return await awaitPools.expectAttributes(collectionId, attributeKeys, iteration + 1);
|
|
102
|
+
return await awaitPools.expectAttributes(databaseId, collectionId, attributeKeys, iteration + 1);
|
|
98
103
|
},
|
|
99
|
-
expectIndexes: async (collectionId, indexKeys, iteration = 1) => {
|
|
104
|
+
expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
|
|
100
105
|
if (iteration > POOL_MAX_DEBOUNCES) {
|
|
101
106
|
return false;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
// TODO: Pagination?
|
|
105
|
-
const { indexes: remoteIndexes } = await
|
|
110
|
+
const { indexes: remoteIndexes } = await databasesListIndexes({
|
|
111
|
+
databaseId,
|
|
106
112
|
collectionId,
|
|
107
113
|
limit: 100,
|
|
108
114
|
parseOutput: false
|
|
@@ -125,32 +131,49 @@ const awaitPools = {
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
128
|
-
return await awaitPools.expectIndexes(collectionId, indexKeys, iteration + 1);
|
|
134
|
+
return await awaitPools.expectIndexes(databaseId, collectionId, indexKeys, iteration + 1);
|
|
129
135
|
},
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
const deploy = new Command("deploy")
|
|
133
139
|
.description(commandDescriptions['deploy'])
|
|
134
|
-
.
|
|
135
|
-
|
|
136
|
-
if (all == undefined) {
|
|
137
|
-
command.help()
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
await deployFunction();
|
|
142
|
-
} catch (e) {
|
|
143
|
-
error(e.message);
|
|
144
|
-
}
|
|
145
|
-
await deployCollection()
|
|
140
|
+
.action(actionRunner(async (_options, command) => {
|
|
141
|
+
command.help()
|
|
146
142
|
}));
|
|
147
143
|
|
|
148
|
-
const deployFunction = async () => {
|
|
144
|
+
const deployFunction = async ({ functionId, all } = {}) => {
|
|
149
145
|
let response = {};
|
|
150
146
|
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
const functionIds = [];
|
|
148
|
+
|
|
149
|
+
if(functionId) {
|
|
150
|
+
functionIds.push(functionId);
|
|
151
|
+
} else if(all) {
|
|
152
|
+
const functions = localConfig.getFunctions();
|
|
153
|
+
if (functions.length === 0) {
|
|
154
|
+
throw new Error("No functions found in the current directory.");
|
|
155
|
+
}
|
|
156
|
+
functionIds.push(...functions.map((func, idx) => {
|
|
157
|
+
return func.$id;
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
153
160
|
|
|
161
|
+
if(functionIds.length <= 0) {
|
|
162
|
+
const answers = await inquirer.prompt(questionsDeployFunctions);
|
|
163
|
+
functionIds.push(...answers.functions);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let functions = functionIds.map((id) => {
|
|
167
|
+
const functions = localConfig.getFunctions();
|
|
168
|
+
const func = functions.find((f) => f.$id === id);
|
|
169
|
+
|
|
170
|
+
if(!func) {
|
|
171
|
+
throw new Error("Function '" + id + "' not found.")
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return func;
|
|
175
|
+
});
|
|
176
|
+
|
|
154
177
|
for (let func of functions) {
|
|
155
178
|
log(`Deploying function ${func.name} ( ${func['$id']} )`)
|
|
156
179
|
|
|
@@ -230,12 +253,13 @@ const deployFunction = async () => {
|
|
|
230
253
|
}
|
|
231
254
|
}
|
|
232
255
|
|
|
233
|
-
const createAttribute = async (collectionId, attribute) => {
|
|
256
|
+
const createAttribute = async (databaseId, collectionId, attribute) => {
|
|
234
257
|
switch (attribute.type) {
|
|
235
258
|
case 'string':
|
|
236
259
|
switch (attribute.format) {
|
|
237
260
|
case 'email':
|
|
238
|
-
return await
|
|
261
|
+
return await databasesCreateEmailAttribute({
|
|
262
|
+
databaseId,
|
|
239
263
|
collectionId,
|
|
240
264
|
key: attribute.key,
|
|
241
265
|
required: attribute.required,
|
|
@@ -244,7 +268,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
244
268
|
parseOutput: false
|
|
245
269
|
})
|
|
246
270
|
case 'url':
|
|
247
|
-
return await
|
|
271
|
+
return await databasesCreateUrlAttribute({
|
|
272
|
+
databaseId,
|
|
248
273
|
collectionId,
|
|
249
274
|
key: attribute.key,
|
|
250
275
|
required: attribute.required,
|
|
@@ -253,7 +278,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
253
278
|
parseOutput: false
|
|
254
279
|
})
|
|
255
280
|
case 'ip':
|
|
256
|
-
return await
|
|
281
|
+
return await databasesCreateIpAttribute({
|
|
282
|
+
databaseId,
|
|
257
283
|
collectionId,
|
|
258
284
|
key: attribute.key,
|
|
259
285
|
required: attribute.required,
|
|
@@ -262,7 +288,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
262
288
|
parseOutput: false
|
|
263
289
|
})
|
|
264
290
|
case 'enum':
|
|
265
|
-
return await
|
|
291
|
+
return await databasesCreateEnumAttribute({
|
|
292
|
+
databaseId,
|
|
266
293
|
collectionId,
|
|
267
294
|
key: attribute.key,
|
|
268
295
|
elements: attribute.elements,
|
|
@@ -272,7 +299,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
272
299
|
parseOutput: false
|
|
273
300
|
})
|
|
274
301
|
default:
|
|
275
|
-
return await
|
|
302
|
+
return await databasesCreateStringAttribute({
|
|
303
|
+
databaseId,
|
|
276
304
|
collectionId,
|
|
277
305
|
key: attribute.key,
|
|
278
306
|
size: attribute.size,
|
|
@@ -284,7 +312,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
284
312
|
|
|
285
313
|
}
|
|
286
314
|
case 'integer':
|
|
287
|
-
return await
|
|
315
|
+
return await databasesCreateIntegerAttribute({
|
|
316
|
+
databaseId,
|
|
288
317
|
collectionId,
|
|
289
318
|
key: attribute.key,
|
|
290
319
|
required: attribute.required,
|
|
@@ -295,7 +324,8 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
295
324
|
parseOutput: false
|
|
296
325
|
})
|
|
297
326
|
case 'double':
|
|
298
|
-
return
|
|
327
|
+
return databasesCreateFloatAttribute({
|
|
328
|
+
databaseId,
|
|
299
329
|
collectionId,
|
|
300
330
|
key: attribute.key,
|
|
301
331
|
required: attribute.required,
|
|
@@ -306,7 +336,9 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
306
336
|
parseOutput: false
|
|
307
337
|
})
|
|
308
338
|
case 'boolean':
|
|
309
|
-
return
|
|
339
|
+
return databasesCreateBooleanAttribute({
|
|
340
|
+
databaseId,
|
|
341
|
+
databaseId,
|
|
310
342
|
collectionId,
|
|
311
343
|
key: attribute.key,
|
|
312
344
|
required: attribute.required,
|
|
@@ -317,15 +349,55 @@ const createAttribute = async (collectionId, attribute) => {
|
|
|
317
349
|
}
|
|
318
350
|
}
|
|
319
351
|
|
|
320
|
-
const deployCollection = async () => {
|
|
352
|
+
const deployCollection = async ({ all } = {}) => {
|
|
321
353
|
let response = {};
|
|
322
|
-
|
|
323
|
-
let
|
|
354
|
+
|
|
355
|
+
let collectionIds = [];
|
|
356
|
+
const configCollections = localConfig.getCollections();
|
|
357
|
+
|
|
358
|
+
if(all) {
|
|
359
|
+
if (configCollections.length === 0) {
|
|
360
|
+
throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
|
|
361
|
+
}
|
|
362
|
+
collectionIds.push(...configCollections.map((c) => c.$id));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if(collectionIds.length <= 0) {
|
|
366
|
+
let answers = await inquirer.prompt(questionsDeployCollections[0])
|
|
367
|
+
collectionIds.push(...answers.collections);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let collections = [];
|
|
371
|
+
|
|
372
|
+
for(const collectionId of collectionIds) {
|
|
373
|
+
const idCollections = configCollections.filter((c) => c.$id === collectionId);
|
|
374
|
+
collections.push(...idCollections);
|
|
375
|
+
}
|
|
324
376
|
|
|
325
377
|
for (let collection of collections) {
|
|
326
378
|
log(`Deploying collection ${collection.name} ( ${collection['$id']} )`)
|
|
379
|
+
|
|
380
|
+
let databaseId;
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
const database = await databasesGet({
|
|
384
|
+
databaseId: collection.databaseId,
|
|
385
|
+
parseOutput: false,
|
|
386
|
+
});
|
|
387
|
+
databaseId = database.$id;
|
|
388
|
+
} catch(err) {
|
|
389
|
+
log(`Database ${collection.databaseId} not found. Creating it now...`);
|
|
390
|
+
const database = await databasesCreate({
|
|
391
|
+
databaseId: collection.databaseId,
|
|
392
|
+
name: collection.databaseId,
|
|
393
|
+
parseOutput: false,
|
|
394
|
+
});
|
|
395
|
+
databaseId = database.$id;
|
|
396
|
+
}
|
|
397
|
+
|
|
327
398
|
try {
|
|
328
|
-
response = await
|
|
399
|
+
response = await databasesGetCollection({
|
|
400
|
+
databaseId,
|
|
329
401
|
collectionId: collection['$id'],
|
|
330
402
|
parseOutput: false,
|
|
331
403
|
})
|
|
@@ -340,51 +412,55 @@ const deployCollection = async () => {
|
|
|
340
412
|
log(`Updating attributes ... `);
|
|
341
413
|
|
|
342
414
|
// TODO: Pagination?
|
|
343
|
-
const { indexes: remoteIndexes } = await
|
|
415
|
+
const { indexes: remoteIndexes } = await databasesListIndexes({
|
|
416
|
+
databaseId,
|
|
344
417
|
collectionId: collection['$id'],
|
|
345
418
|
limit: 100,
|
|
346
419
|
parseOutput: false
|
|
347
420
|
});
|
|
348
421
|
|
|
349
422
|
await Promise.all(remoteIndexes.map(async index => {
|
|
350
|
-
await
|
|
423
|
+
await databasesDeleteIndex({
|
|
424
|
+
databaseId,
|
|
351
425
|
collectionId: collection['$id'],
|
|
352
426
|
key: index.key,
|
|
353
427
|
parseOutput: false
|
|
354
428
|
});
|
|
355
429
|
}));
|
|
356
430
|
|
|
357
|
-
const deleteIndexesPoolStatus = await awaitPools.wipeIndexes(collection['$id']);
|
|
431
|
+
const deleteIndexesPoolStatus = await awaitPools.wipeIndexes(databaseId, collection['$id']);
|
|
358
432
|
if (!deleteIndexesPoolStatus) {
|
|
359
433
|
throw new Error("Index deletion did not finish for too long.");
|
|
360
434
|
}
|
|
361
435
|
|
|
362
436
|
// TODO: Pagination?
|
|
363
|
-
const { attributes: remoteAttributes } = await
|
|
437
|
+
const { attributes: remoteAttributes } = await databasesListAttributes({
|
|
438
|
+
databaseId,
|
|
364
439
|
collectionId: collection['$id'],
|
|
365
440
|
limit: 100,
|
|
366
441
|
parseOutput: false
|
|
367
442
|
});
|
|
368
443
|
|
|
369
444
|
await Promise.all(remoteAttributes.map(async attribute => {
|
|
370
|
-
await
|
|
445
|
+
await databasesDeleteAttribute({
|
|
446
|
+
databaseId,
|
|
371
447
|
collectionId: collection['$id'],
|
|
372
448
|
key: attribute.key,
|
|
373
449
|
parseOutput: false
|
|
374
450
|
});
|
|
375
451
|
}));
|
|
376
452
|
|
|
377
|
-
const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(collection['$id']);
|
|
453
|
+
const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(databaseId, collection['$id']);
|
|
378
454
|
if (!deleteAttributesPoolStatus) {
|
|
379
455
|
throw new Error("Attribute deletion did not finish for too long.");
|
|
380
456
|
}
|
|
381
457
|
|
|
382
458
|
await Promise.all(collection.attributes.map(async attribute => {
|
|
383
|
-
await createAttribute(collection['$id'], attribute);
|
|
459
|
+
await createAttribute(databaseId, collection['$id'], attribute);
|
|
384
460
|
}));
|
|
385
461
|
|
|
386
462
|
const attributeKeys = collection.attributes.map(attribute => attribute.key);
|
|
387
|
-
const createPoolStatus = await awaitPools.expectAttributes(collection['$id'], attributeKeys);
|
|
463
|
+
const createPoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
|
|
388
464
|
if (!createPoolStatus) {
|
|
389
465
|
throw new Error("Attribute creation did not finish for too long.");
|
|
390
466
|
}
|
|
@@ -393,7 +469,8 @@ const deployCollection = async () => {
|
|
|
393
469
|
|
|
394
470
|
log(`Creating indexes ...`)
|
|
395
471
|
await Promise.all(collection.indexes.map(async index => {
|
|
396
|
-
await
|
|
472
|
+
await databasesCreateIndex({
|
|
473
|
+
databaseId,
|
|
397
474
|
collectionId: collection['$id'],
|
|
398
475
|
key: index.key,
|
|
399
476
|
type: index.type,
|
|
@@ -404,7 +481,7 @@ const deployCollection = async () => {
|
|
|
404
481
|
}));
|
|
405
482
|
|
|
406
483
|
const indexKeys = collection.indexes.map(attribute => attribute.key);
|
|
407
|
-
const indexPoolStatus = await awaitPools.expectIndexes(collection['$id'], indexKeys);
|
|
484
|
+
const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
|
|
408
485
|
if (!indexPoolStatus) {
|
|
409
486
|
throw new Error("Index creation did not finish for too long.");
|
|
410
487
|
}
|
|
@@ -413,7 +490,8 @@ const deployCollection = async () => {
|
|
|
413
490
|
} catch (e) {
|
|
414
491
|
if (e.code == 404) {
|
|
415
492
|
log(`Collection ${collection.name} does not exist in the project. Creating ... `);
|
|
416
|
-
response = await
|
|
493
|
+
response = await databasesCreateCollection({
|
|
494
|
+
databaseId,
|
|
417
495
|
collectionId: collection['$id'],
|
|
418
496
|
name: collection.name,
|
|
419
497
|
permission: collection.permission,
|
|
@@ -424,11 +502,11 @@ const deployCollection = async () => {
|
|
|
424
502
|
|
|
425
503
|
log(`Creating attributes ... `);
|
|
426
504
|
await Promise.all(collection.attributes.map(async attribute => {
|
|
427
|
-
await createAttribute(collection['$id'], attribute);
|
|
505
|
+
await createAttribute(databaseId, collection['$id'], attribute);
|
|
428
506
|
}));
|
|
429
507
|
|
|
430
508
|
const attributeKeys = collection.attributes.map(attribute => attribute.key);
|
|
431
|
-
const attributePoolStatus = await awaitPools.expectAttributes(collection['$id'], attributeKeys);
|
|
509
|
+
const attributePoolStatus = await awaitPools.expectAttributes(databaseId, collection['$id'], attributeKeys);
|
|
432
510
|
if (!attributePoolStatus) {
|
|
433
511
|
throw new Error("Attribute creation did not finish for too long.");
|
|
434
512
|
}
|
|
@@ -437,7 +515,8 @@ const deployCollection = async () => {
|
|
|
437
515
|
|
|
438
516
|
log(`Creating indexes ...`);
|
|
439
517
|
await Promise.all(collection.indexes.map(async index => {
|
|
440
|
-
await
|
|
518
|
+
await databasesCreateIndex({
|
|
519
|
+
databaseId,
|
|
441
520
|
collectionId: collection['$id'],
|
|
442
521
|
key: index.key,
|
|
443
522
|
type: index.type,
|
|
@@ -448,7 +527,7 @@ const deployCollection = async () => {
|
|
|
448
527
|
}));
|
|
449
528
|
|
|
450
529
|
const indexKeys = collection.indexes.map(attribute => attribute.key);
|
|
451
|
-
const indexPoolStatus = await awaitPools.expectIndexes(collection['$id'], indexKeys);
|
|
530
|
+
const indexPoolStatus = await awaitPools.expectIndexes(databaseId, collection['$id'], indexKeys);
|
|
452
531
|
if (!indexPoolStatus) {
|
|
453
532
|
throw new Error("Index creation did not finish for too long.");
|
|
454
533
|
}
|
|
@@ -466,11 +545,14 @@ const deployCollection = async () => {
|
|
|
466
545
|
deploy
|
|
467
546
|
.command("function")
|
|
468
547
|
.description("Deploy functions in the current directory.")
|
|
548
|
+
.option(`--functionId <functionId>`, `Function ID`)
|
|
549
|
+
.option(`--all`, `Flag to deploy all functions`)
|
|
469
550
|
.action(actionRunner(deployFunction));
|
|
470
551
|
|
|
471
552
|
deploy
|
|
472
553
|
.command("collection")
|
|
473
554
|
.description("Deploy collections in the current project.")
|
|
555
|
+
.option(`--all`, `Flag to deploy all functions`)
|
|
474
556
|
.action(actionRunner(deployCollection));
|
|
475
557
|
|
|
476
558
|
module.exports = {
|
package/lib/commands/generic.js
CHANGED
|
@@ -5,7 +5,7 @@ const { sdkForConsole } = require("../sdks");
|
|
|
5
5
|
const { globalConfig, localConfig } = require("../config");
|
|
6
6
|
const { actionRunner, success, parseBool, commandDescriptions, log, parse } = require("../parser");
|
|
7
7
|
const { questionsLogin } = require("../questions");
|
|
8
|
-
const {
|
|
8
|
+
const { accountCreateEmailSession, accountDeleteSession } = require("./account");
|
|
9
9
|
|
|
10
10
|
const login = new Command("login")
|
|
11
11
|
.description(commandDescriptions['login'])
|
|
@@ -14,7 +14,7 @@ const login = new Command("login")
|
|
|
14
14
|
|
|
15
15
|
let client = await sdkForConsole(false);
|
|
16
16
|
|
|
17
|
-
await
|
|
17
|
+
await accountCreateEmailSession({
|
|
18
18
|
email: answers.email,
|
|
19
19
|
password: answers.password,
|
|
20
20
|
parseOutput: false,
|
package/lib/commands/init.js
CHANGED
|
@@ -6,22 +6,16 @@ const inquirer = require("inquirer");
|
|
|
6
6
|
const { teamsCreate } = require("./teams");
|
|
7
7
|
const { projectsCreate } = require("./projects");
|
|
8
8
|
const { functionsCreate } = require("./functions");
|
|
9
|
-
const {
|
|
9
|
+
const { databasesListCollections, databasesList } = require("./databases");
|
|
10
10
|
const { sdkForConsole } = require("../sdks");
|
|
11
11
|
const { localConfig } = require("../config");
|
|
12
|
-
const { questionsInitProject, questionsInitFunction } = require("../questions");
|
|
12
|
+
const { questionsInitProject, questionsInitFunction, questionsInitCollection } = require("../questions");
|
|
13
13
|
const { success, log, actionRunner, commandDescriptions } = require("../parser");
|
|
14
14
|
|
|
15
15
|
const init = new Command("init")
|
|
16
16
|
.description(commandDescriptions['init'])
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
if (all == undefined) {
|
|
20
|
-
command.help()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
await initProject();
|
|
24
|
-
await initCollection()
|
|
17
|
+
.action(actionRunner(async (_options, command) => {
|
|
18
|
+
command.help();
|
|
25
19
|
}));
|
|
26
20
|
|
|
27
21
|
const initProject = async () => {
|
|
@@ -40,7 +34,7 @@ const initProject = async () => {
|
|
|
40
34
|
|
|
41
35
|
let teamId = response['$id'];
|
|
42
36
|
response = await projectsCreate({
|
|
43
|
-
projectId:
|
|
37
|
+
projectId: answers.id,
|
|
44
38
|
name: answers.project,
|
|
45
39
|
teamId,
|
|
46
40
|
parseOutput: false
|
|
@@ -54,9 +48,19 @@ const initProject = async () => {
|
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
const initFunction = async () => {
|
|
51
|
+
// TODO: Add CI/CD support (ID, name, runtime)
|
|
57
52
|
let answers = await inquirer.prompt(questionsInitFunction)
|
|
53
|
+
let functionFolder = path.join(process.cwd(), 'functions');
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(functionFolder)) {
|
|
56
|
+
fs.mkdirSync(functionFolder, {
|
|
57
|
+
recursive: true
|
|
58
|
+
});
|
|
59
|
+
}
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
const functionDir = path.join(functionFolder, answers.name);
|
|
62
|
+
|
|
63
|
+
if (fs.existsSync(functionDir)) {
|
|
60
64
|
throw new Error(`( ${answers.name} ) already exists in the current directory. Please choose another name.`);
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -65,26 +69,59 @@ const initFunction = async () => {
|
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
let response = await functionsCreate({
|
|
68
|
-
functionId:
|
|
72
|
+
functionId: answers.id,
|
|
69
73
|
name: answers.name,
|
|
70
74
|
runtime: answers.runtime.id,
|
|
71
75
|
parseOutput: false
|
|
72
76
|
})
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
fs.mkdirSync(functionDir, "777");
|
|
79
|
+
|
|
80
|
+
let gitInitCommands = "git clone --depth 1 --sparse https://github.com/appwrite/functions-starter ."; // depth prevents fetching older commits reducing the amount fetched
|
|
81
|
+
|
|
82
|
+
let gitPullCommands = `git sparse-checkout add ${answers.runtime.id}`;
|
|
83
|
+
|
|
84
|
+
/* Force use CMD as powershell does not support && */
|
|
85
|
+
if (process.platform == 'win32') {
|
|
86
|
+
gitInitCommands = 'cmd /c "' + gitInitCommands + '"';
|
|
87
|
+
gitPullCommands = 'cmd /c "' + gitPullCommands + '"';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Execute the child process but do not print any std output */
|
|
91
|
+
try {
|
|
92
|
+
childProcess.execSync(gitInitCommands, { stdio: 'pipe', cwd: functionDir });
|
|
93
|
+
childProcess.execSync(gitPullCommands, { stdio: 'pipe', cwd: functionDir });
|
|
94
|
+
} catch (error) {
|
|
95
|
+
/* Specialised errors with recommended actions to take */
|
|
96
|
+
if (error.message.includes('error: unknown option')) {
|
|
97
|
+
throw new Error(`${error.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`)
|
|
98
|
+
} else if (error.message.includes('is not recognized as an internal or external command,') || error.message.includes('command not found')) {
|
|
99
|
+
throw new Error(`${error.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`)
|
|
100
|
+
} else {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fs.rmSync(path.join(functionDir, ".git"), { recursive: true });
|
|
106
|
+
const copyRecursiveSync = (src, dest) => {
|
|
107
|
+
let exists = fs.existsSync(src);
|
|
108
|
+
let stats = exists && fs.statSync(src);
|
|
109
|
+
let isDirectory = exists && stats.isDirectory();
|
|
110
|
+
if (isDirectory) {
|
|
111
|
+
if (!fs.existsSync(dest)) {
|
|
112
|
+
fs.mkdirSync(dest);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fs.readdirSync(src).forEach(function(childItemName) {
|
|
116
|
+
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
fs.copyFileSync(src, dest);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
copyRecursiveSync(path.join(functionDir, answers.runtime.id), functionDir);
|
|
123
|
+
|
|
124
|
+
fs.rmSync(`${functionDir}/${answers.runtime.id}`, { recursive: true, force: true });
|
|
88
125
|
|
|
89
126
|
const readmePath = path.join(process.cwd(), 'functions', answers.name, 'README.md');
|
|
90
127
|
const readmeFile = fs.readFileSync(readmePath).toString();
|
|
@@ -110,20 +147,41 @@ const initFunction = async () => {
|
|
|
110
147
|
success();
|
|
111
148
|
}
|
|
112
149
|
|
|
113
|
-
const initCollection = async () => {
|
|
114
|
-
|
|
115
|
-
let response = await databaseListCollections({
|
|
116
|
-
limit: 100,
|
|
117
|
-
parseOutput: false
|
|
118
|
-
})
|
|
150
|
+
const initCollection = async ({ all, databaseId } = {}) => {
|
|
151
|
+
const databaseIds = [];
|
|
119
152
|
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
if(databaseId) {
|
|
154
|
+
databaseIds.push(databaseId);
|
|
155
|
+
} else if(all) {
|
|
156
|
+
let allDatabases = await databasesList({
|
|
157
|
+
parseOutput: false
|
|
158
|
+
})
|
|
122
159
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
160
|
+
databaseIds.push(...allDatabases.databases.map((d) => d.$id));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if(databaseIds.length <= 0) {
|
|
164
|
+
let answers = await inquirer.prompt(questionsInitCollection)
|
|
165
|
+
if (!answers.databases) process.exit(1)
|
|
166
|
+
databaseIds.push(...answers.databases);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for(const databaseId of databaseIds) {
|
|
170
|
+
// TODO: Pagination?
|
|
171
|
+
let response = await databasesListCollections({
|
|
172
|
+
databaseId,
|
|
173
|
+
limit: 100,
|
|
174
|
+
parseOutput: false
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
let collections = response.collections;
|
|
178
|
+
log(`Found ${collections.length} collections`);
|
|
179
|
+
|
|
180
|
+
collections.forEach(async collection => {
|
|
181
|
+
log(`Fetching ${collection.name} ...`);
|
|
182
|
+
localConfig.addCollection(collection);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
127
185
|
|
|
128
186
|
success();
|
|
129
187
|
}
|
|
@@ -141,6 +199,8 @@ init
|
|
|
141
199
|
init
|
|
142
200
|
.command("collection")
|
|
143
201
|
.description("Initialise your Appwrite collections")
|
|
202
|
+
.option(`--databaseId <databaseId>`, `Database ID`)
|
|
203
|
+
.option(`--all`, `Flag to initialize all databases`)
|
|
144
204
|
.action(actionRunner(initCollection))
|
|
145
205
|
|
|
146
206
|
module.exports = {
|
package/lib/parser.js
CHANGED
|
@@ -150,7 +150,7 @@ const logo = "\n _ _ _ ___ __ _____
|
|
|
150
150
|
const commandDescriptions = {
|
|
151
151
|
"account": `The account command allows you to authenticate and manage a user account.`,
|
|
152
152
|
"avatars": `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`,
|
|
153
|
-
"
|
|
153
|
+
"databases": `The databases command allows you to create structured collections of documents, query and filter lists of documents.`,
|
|
154
154
|
"deploy": `The deploy command provides a convenient wrapper for deploying your functions and collections.`,
|
|
155
155
|
"functions": `The functions command allows you view, create and manage your Cloud Functions.`,
|
|
156
156
|
"health": `The health command allows you to both validate and monitor your Appwrite server's health.`,
|
package/lib/questions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { localConfig } = require('./config');
|
|
2
2
|
const { projectsList } = require('./commands/projects');
|
|
3
3
|
const { functionsListRuntimes } = require('./commands/functions');
|
|
4
|
+
const { databasesList } = require('./commands/databases');
|
|
4
5
|
const JSONbig = require("json-bigint")({ storeAsString: false });
|
|
5
6
|
|
|
6
7
|
const getIgnores = (runtime) => {
|
|
@@ -108,6 +109,15 @@ const questionsInitProject = [
|
|
|
108
109
|
return answers.start == "new";
|
|
109
110
|
},
|
|
110
111
|
},
|
|
112
|
+
{
|
|
113
|
+
type: "input",
|
|
114
|
+
name: "id",
|
|
115
|
+
message: "What ID would you like to have for your project?",
|
|
116
|
+
default: "myAwesomeProject",
|
|
117
|
+
when(answers) {
|
|
118
|
+
return answers.start == "new";
|
|
119
|
+
},
|
|
120
|
+
},
|
|
111
121
|
{
|
|
112
122
|
type: "list",
|
|
113
123
|
name: "project",
|
|
@@ -146,6 +156,12 @@ const questionsInitFunction = [
|
|
|
146
156
|
message: "What would you like to name your function?",
|
|
147
157
|
default: "My Awesome Function"
|
|
148
158
|
},
|
|
159
|
+
{
|
|
160
|
+
type: "input",
|
|
161
|
+
name: "id",
|
|
162
|
+
message: "What ID would you like to have for your function?",
|
|
163
|
+
default: "myAwesomeFunction"
|
|
164
|
+
},
|
|
149
165
|
{
|
|
150
166
|
type: "list",
|
|
151
167
|
name: "runtime",
|
|
@@ -166,6 +182,31 @@ const questionsInitFunction = [
|
|
|
166
182
|
}
|
|
167
183
|
];
|
|
168
184
|
|
|
185
|
+
const questionsInitCollection = [
|
|
186
|
+
{
|
|
187
|
+
type: "checkbox",
|
|
188
|
+
name: "databases",
|
|
189
|
+
message: "From which database would you like to init collections?",
|
|
190
|
+
choices: async () => {
|
|
191
|
+
let response = await databasesList({
|
|
192
|
+
parseOutput: false
|
|
193
|
+
})
|
|
194
|
+
let databases = response["databases"]
|
|
195
|
+
|
|
196
|
+
if(databases.length <= 0) {
|
|
197
|
+
throw new Error("No databases found. Please create one in project console.")
|
|
198
|
+
}
|
|
199
|
+
let choices = databases.map((database, idx) => {
|
|
200
|
+
return {
|
|
201
|
+
name: `${database.name} (${database.$id})`,
|
|
202
|
+
value: database.$id
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
return choices;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
];
|
|
209
|
+
|
|
169
210
|
const questionsLogin = [
|
|
170
211
|
{
|
|
171
212
|
type: "input",
|
|
@@ -204,8 +245,8 @@ const questionsDeployFunctions = [
|
|
|
204
245
|
}
|
|
205
246
|
let choices = functions.map((func, idx) => {
|
|
206
247
|
return {
|
|
207
|
-
name: `${func.name} (${func
|
|
208
|
-
value:
|
|
248
|
+
name: `${func.name} (${func.$id})`,
|
|
249
|
+
value: func.$id
|
|
209
250
|
}
|
|
210
251
|
})
|
|
211
252
|
return choices;
|
|
@@ -226,7 +267,7 @@ const questionsDeployCollections = [
|
|
|
226
267
|
let choices = collections.map((collection, idx) => {
|
|
227
268
|
return {
|
|
228
269
|
name: `${collection.name} (${collection['$id']})`,
|
|
229
|
-
value:
|
|
270
|
+
value: collection.$id
|
|
230
271
|
}
|
|
231
272
|
})
|
|
232
273
|
return choices;
|
|
@@ -258,6 +299,7 @@ module.exports = {
|
|
|
258
299
|
questionsInitProject,
|
|
259
300
|
questionsLogin,
|
|
260
301
|
questionsInitFunction,
|
|
302
|
+
questionsInitCollection,
|
|
261
303
|
questionsDeployFunctions,
|
|
262
304
|
questionsDeployCollections,
|
|
263
305
|
questionsGetEntrypoint
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "appwrite-cli",
|
|
3
3
|
"homepage": "https://appwrite.io/support",
|
|
4
4
|
"description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
|
|
5
|
-
"version": "0.18.
|
|
5
|
+
"version": "0.18.5",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"bin": {
|