appwrite-cli 5.0.5 → 6.0.0-rc.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/README.md +4 -4
- package/docs/examples/functions/create-build.md +1 -1
- package/docs/examples/functions/create-execution.md +1 -0
- package/docs/examples/functions/create.md +1 -0
- package/docs/examples/functions/delete-execution.md +3 -0
- package/docs/examples/functions/update-deployment-build.md +3 -0
- package/docs/examples/functions/update.md +1 -0
- package/docs/examples/projects/create-j-w-t.md +4 -0
- package/docs/examples/projects/update-mock-numbers.md +3 -0
- package/docs/examples/projects/update-session-alerts.md +3 -0
- package/docs/examples/users/create-j-w-t.md +4 -0
- package/docs/examples/vcs/get-repository-contents.md +4 -0
- package/index.js +34 -7
- package/install.ps1 +3 -3
- package/install.sh +2 -2
- package/lib/client.js +17 -3
- package/lib/commands/account.js +306 -152
- package/lib/commands/assistant.js +8 -5
- package/lib/commands/avatars.js +114 -58
- package/lib/commands/console.js +8 -5
- package/lib/commands/databases.js +353 -164
- package/lib/commands/functions.js +310 -100
- package/lib/commands/generic.js +206 -54
- package/lib/commands/graphql.js +14 -8
- package/lib/commands/health.js +140 -71
- package/lib/commands/init.js +250 -155
- package/lib/commands/locale.js +50 -26
- package/lib/commands/messaging.js +334 -156
- package/lib/commands/migrations.js +98 -50
- package/lib/commands/project.js +38 -20
- package/lib/commands/projects.js +449 -144
- package/lib/commands/proxy.js +32 -17
- package/lib/commands/pull.js +231 -0
- package/lib/commands/push.js +1518 -0
- package/lib/commands/run.js +282 -0
- package/lib/commands/storage.js +160 -76
- package/lib/commands/teams.js +102 -50
- package/lib/commands/users.js +324 -134
- package/lib/commands/vcs.js +102 -29
- package/lib/config.js +190 -18
- package/lib/emulation/docker.js +187 -0
- package/lib/emulation/utils.js +177 -0
- package/lib/id.js +30 -0
- package/lib/paginate.js +1 -2
- package/lib/parser.js +69 -12
- package/lib/questions.js +452 -80
- package/lib/sdks.js +1 -1
- package/lib/spinner.js +103 -0
- package/lib/utils.js +242 -4
- package/lib/validations.js +17 -0
- package/package.json +6 -2
- package/scoop/appwrite.json +3 -3
- package/lib/commands/deploy.js +0 -940
package/lib/commands/deploy.js
DELETED
|
@@ -1,940 +0,0 @@
|
|
|
1
|
-
const inquirer = require("inquirer");
|
|
2
|
-
const JSONbig = require("json-bigint")({ storeAsString: false });
|
|
3
|
-
const { Command } = require("commander");
|
|
4
|
-
const { localConfig } = require("../config");
|
|
5
|
-
const { paginate } = require('../paginate');
|
|
6
|
-
const { questionsDeployBuckets, questionsDeployTeams, questionsDeployFunctions, questionsGetEntrypoint, questionsDeployCollections, questionsConfirmDeployCollections } = require("../questions");
|
|
7
|
-
const { actionRunner, success, log, error, commandDescriptions } = require("../parser");
|
|
8
|
-
const { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsUpdateDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } = require('./functions');
|
|
9
|
-
const {
|
|
10
|
-
databasesGet,
|
|
11
|
-
databasesCreate,
|
|
12
|
-
databasesUpdate,
|
|
13
|
-
databasesCreateBooleanAttribute,
|
|
14
|
-
databasesGetCollection,
|
|
15
|
-
databasesCreateCollection,
|
|
16
|
-
databasesCreateStringAttribute,
|
|
17
|
-
databasesCreateIntegerAttribute,
|
|
18
|
-
databasesCreateFloatAttribute,
|
|
19
|
-
databasesCreateEmailAttribute,
|
|
20
|
-
databasesCreateDatetimeAttribute,
|
|
21
|
-
databasesCreateIndex,
|
|
22
|
-
databasesCreateUrlAttribute,
|
|
23
|
-
databasesCreateIpAttribute,
|
|
24
|
-
databasesCreateEnumAttribute,
|
|
25
|
-
databasesCreateRelationshipAttribute,
|
|
26
|
-
databasesDeleteAttribute,
|
|
27
|
-
databasesListAttributes,
|
|
28
|
-
databasesListIndexes,
|
|
29
|
-
databasesDeleteIndex,
|
|
30
|
-
databasesUpdateCollection
|
|
31
|
-
} = require("./databases");
|
|
32
|
-
const {
|
|
33
|
-
storageGetBucket, storageUpdateBucket, storageCreateBucket
|
|
34
|
-
} = require("./storage");
|
|
35
|
-
const {
|
|
36
|
-
teamsGet,
|
|
37
|
-
teamsUpdateName,
|
|
38
|
-
teamsCreate
|
|
39
|
-
} = require("./teams");
|
|
40
|
-
const { checkDeployConditions } = require('../utils');
|
|
41
|
-
|
|
42
|
-
const STEP_SIZE = 100; // Resources
|
|
43
|
-
const POOL_DEBOUNCE = 2000; // Milliseconds
|
|
44
|
-
|
|
45
|
-
let poolMaxDebounces = 30;
|
|
46
|
-
|
|
47
|
-
const awaitPools = {
|
|
48
|
-
wipeAttributes: async (databaseId, collectionId, iteration = 1) => {
|
|
49
|
-
if (iteration > poolMaxDebounces) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const { total } = await databasesListAttributes({
|
|
54
|
-
databaseId,
|
|
55
|
-
collectionId,
|
|
56
|
-
queries: [JSON.stringify({ method: 'limit', values: [1] })],
|
|
57
|
-
parseOutput: false
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (total === 0) {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
65
|
-
if (steps > 1 && iteration === 1) {
|
|
66
|
-
poolMaxDebounces *= steps;
|
|
67
|
-
|
|
68
|
-
log('Found a large number of attributes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
72
|
-
|
|
73
|
-
return await awaitPools.wipeAttributes(
|
|
74
|
-
databaseId,
|
|
75
|
-
collectionId,
|
|
76
|
-
iteration + 1
|
|
77
|
-
);
|
|
78
|
-
},
|
|
79
|
-
wipeIndexes: async (databaseId, collectionId, iteration = 1) => {
|
|
80
|
-
if (iteration > poolMaxDebounces) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const { total } = await databasesListIndexes({
|
|
85
|
-
databaseId,
|
|
86
|
-
collectionId,
|
|
87
|
-
queries: [JSON.stringify({ method: 'limit', values: [1] })],
|
|
88
|
-
parseOutput: false
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
if (total === 0) {
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
96
|
-
if (steps > 1 && iteration === 1) {
|
|
97
|
-
poolMaxDebounces *= steps;
|
|
98
|
-
|
|
99
|
-
log('Found a large number of indexes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
103
|
-
|
|
104
|
-
return await awaitPools.wipeIndexes(
|
|
105
|
-
databaseId,
|
|
106
|
-
collectionId,
|
|
107
|
-
iteration + 1
|
|
108
|
-
);
|
|
109
|
-
},
|
|
110
|
-
wipeVariables: async (functionId, iteration = 1) => {
|
|
111
|
-
if (iteration > poolMaxDebounces) {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const { total } = await functionsListVariables({
|
|
116
|
-
functionId,
|
|
117
|
-
queries: ['limit(1)'],
|
|
118
|
-
parseOutput: false
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (total === 0) {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
let steps = Math.max(1, Math.ceil(total / STEP_SIZE));
|
|
126
|
-
if (steps > 1 && iteration === 1) {
|
|
127
|
-
poolMaxDebounces *= steps;
|
|
128
|
-
|
|
129
|
-
log('Found a large number of variables, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
133
|
-
|
|
134
|
-
return await awaitPools.wipeVariables(
|
|
135
|
-
functionId,
|
|
136
|
-
iteration + 1
|
|
137
|
-
);
|
|
138
|
-
},
|
|
139
|
-
expectAttributes: async (databaseId, collectionId, attributeKeys, iteration = 1) => {
|
|
140
|
-
if (iteration > poolMaxDebounces) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE));
|
|
145
|
-
if (steps > 1 && iteration === 1) {
|
|
146
|
-
poolMaxDebounces *= steps;
|
|
147
|
-
|
|
148
|
-
log('Creating a large number of attributes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const { attributes } = await paginate(databasesListAttributes, {
|
|
152
|
-
databaseId,
|
|
153
|
-
collectionId,
|
|
154
|
-
parseOutput: false
|
|
155
|
-
}, 100, 'attributes');
|
|
156
|
-
|
|
157
|
-
const ready = attributes
|
|
158
|
-
.filter(attribute => {
|
|
159
|
-
if (attributeKeys.includes(attribute.key)) {
|
|
160
|
-
if (['stuck', 'failed'].includes(attribute.status)) {
|
|
161
|
-
throw new Error(`Attribute '${attribute.key}' failed!`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return attribute.status === 'available';
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return false;
|
|
168
|
-
})
|
|
169
|
-
.map(attribute => attribute.key);
|
|
170
|
-
|
|
171
|
-
if (ready.length === attributeKeys.length) {
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
176
|
-
|
|
177
|
-
return await awaitPools.expectAttributes(
|
|
178
|
-
databaseId,
|
|
179
|
-
collectionId,
|
|
180
|
-
attributeKeys,
|
|
181
|
-
iteration + 1
|
|
182
|
-
);
|
|
183
|
-
},
|
|
184
|
-
expectIndexes: async (databaseId, collectionId, indexKeys, iteration = 1) => {
|
|
185
|
-
if (iteration > poolMaxDebounces) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE));
|
|
190
|
-
if (steps > 1 && iteration === 1) {
|
|
191
|
-
poolMaxDebounces *= steps;
|
|
192
|
-
|
|
193
|
-
log('Creating a large number of indexes, increasing timeout to ' + (poolMaxDebounces * POOL_DEBOUNCE / 1000 / 60) + ' minutes')
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const { indexes } = await paginate(databasesListIndexes, {
|
|
197
|
-
databaseId,
|
|
198
|
-
collectionId,
|
|
199
|
-
parseOutput: false
|
|
200
|
-
}, 100, 'indexes');
|
|
201
|
-
|
|
202
|
-
const ready = indexes
|
|
203
|
-
.filter((index) => {
|
|
204
|
-
if (indexKeys.includes(index.key)) {
|
|
205
|
-
if (['stuck', 'failed'].includes(index.status)) {
|
|
206
|
-
throw new Error(`Index '${index.key}' failed!`);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return index.status === 'available';
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return false;
|
|
213
|
-
})
|
|
214
|
-
.map(index => index.key);
|
|
215
|
-
|
|
216
|
-
if (ready.length >= indexKeys.length) {
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
await new Promise(resolve => setTimeout(resolve, POOL_DEBOUNCE));
|
|
221
|
-
|
|
222
|
-
return await awaitPools.expectIndexes(
|
|
223
|
-
databaseId,
|
|
224
|
-
collectionId,
|
|
225
|
-
indexKeys,
|
|
226
|
-
iteration + 1
|
|
227
|
-
);
|
|
228
|
-
},
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const deploy = new Command("deploy")
|
|
232
|
-
.description(commandDescriptions['deploy'])
|
|
233
|
-
.configureHelp({
|
|
234
|
-
helpWidth: process.stdout.columns || 80
|
|
235
|
-
})
|
|
236
|
-
.action(actionRunner(async (_options, command) => {
|
|
237
|
-
command.help()
|
|
238
|
-
}));
|
|
239
|
-
|
|
240
|
-
const deployFunction = async ({ functionId, all, yes } = {}) => {
|
|
241
|
-
let response = {};
|
|
242
|
-
|
|
243
|
-
const functionIds = [];
|
|
244
|
-
|
|
245
|
-
if (functionId) {
|
|
246
|
-
functionIds.push(functionId);
|
|
247
|
-
} else if (all) {
|
|
248
|
-
const functions = localConfig.getFunctions();
|
|
249
|
-
checkDeployConditions(localConfig);
|
|
250
|
-
if (functions.length === 0) {
|
|
251
|
-
throw new Error("No functions found in the current directory.");
|
|
252
|
-
}
|
|
253
|
-
functionIds.push(...functions.map((func, idx) => {
|
|
254
|
-
return func.$id;
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (functionIds.length <= 0) {
|
|
259
|
-
const answers = await inquirer.prompt(questionsDeployFunctions[0]);
|
|
260
|
-
functionIds.push(...answers.functions);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let functions = functionIds.map((id) => {
|
|
264
|
-
const functions = localConfig.getFunctions();
|
|
265
|
-
const func = functions.find((f) => f.$id === id);
|
|
266
|
-
|
|
267
|
-
if (!func) {
|
|
268
|
-
throw new Error("Function '" + id + "' not found.")
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return func;
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
for (let func of functions) {
|
|
275
|
-
log(`Deploying function ${func.name} ( ${func['$id']} )`)
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
response = await functionsGet({
|
|
279
|
-
functionId: func['$id'],
|
|
280
|
-
parseOutput: false,
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
if (response.runtime !== func.runtime) {
|
|
284
|
-
throw new Error(`Runtime missmatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.json`);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
response = await functionsUpdate({
|
|
288
|
-
functionId: func['$id'],
|
|
289
|
-
name: func.name,
|
|
290
|
-
execute: func.execute,
|
|
291
|
-
events: func.events,
|
|
292
|
-
schedule: func.schedule,
|
|
293
|
-
timeout: func.timeout,
|
|
294
|
-
enabled: func.enabled,
|
|
295
|
-
logging: func.logging,
|
|
296
|
-
entrypoint: func.entrypoint,
|
|
297
|
-
commands: func.commands,
|
|
298
|
-
vars: JSON.stringify(response.vars),
|
|
299
|
-
parseOutput: false
|
|
300
|
-
});
|
|
301
|
-
} catch (e) {
|
|
302
|
-
if (e.code == 404) {
|
|
303
|
-
log(`Function ${func.name} ( ${func['$id']} ) does not exist in the project. Creating ... `);
|
|
304
|
-
response = await functionsCreate({
|
|
305
|
-
functionId: func.$id || 'unique()',
|
|
306
|
-
name: func.name,
|
|
307
|
-
runtime: func.runtime,
|
|
308
|
-
execute: func.execute,
|
|
309
|
-
events: func.events,
|
|
310
|
-
schedule: func.schedule,
|
|
311
|
-
timeout: func.timeout,
|
|
312
|
-
enabled: func.enabled,
|
|
313
|
-
logging: func.logging,
|
|
314
|
-
entrypoint: func.entrypoint,
|
|
315
|
-
commands: func.commands,
|
|
316
|
-
vars: JSON.stringify(func.vars),
|
|
317
|
-
parseOutput: false
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
localConfig.updateFunction(func['$id'], {
|
|
321
|
-
"$id": response['$id'],
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
func["$id"] = response['$id'];
|
|
325
|
-
log(`Function ${func.name} created.`);
|
|
326
|
-
} else {
|
|
327
|
-
throw e;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (func.variables) {
|
|
332
|
-
// Delete existing variables
|
|
333
|
-
|
|
334
|
-
const { total } = await functionsListVariables({
|
|
335
|
-
functionId: func['$id'],
|
|
336
|
-
queries: [JSON.stringify({ method: 'limit', values: [1] })],
|
|
337
|
-
parseOutput: false
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
let deployVariables = yes;
|
|
341
|
-
|
|
342
|
-
if (total === 0) {
|
|
343
|
-
deployVariables = true;
|
|
344
|
-
} else if (total > 0 && !yes) {
|
|
345
|
-
const variableAnswers = await inquirer.prompt(questionsDeployFunctions[1])
|
|
346
|
-
deployVariables = variableAnswers.override.toLowerCase() === "yes";
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (!deployVariables) {
|
|
350
|
-
log(`Skipping variables for ${func.name} ( ${func['$id']} )`);
|
|
351
|
-
} else {
|
|
352
|
-
log(`Deploying variables for ${func.name} ( ${func['$id']} )`);
|
|
353
|
-
|
|
354
|
-
const { variables } = await paginate(functionsListVariables, {
|
|
355
|
-
functionId: func['$id'],
|
|
356
|
-
parseOutput: false
|
|
357
|
-
}, 100, 'variables');
|
|
358
|
-
|
|
359
|
-
await Promise.all(variables.map(async variable => {
|
|
360
|
-
await functionsDeleteVariable({
|
|
361
|
-
functionId: func['$id'],
|
|
362
|
-
variableId: variable['$id'],
|
|
363
|
-
parseOutput: false
|
|
364
|
-
});
|
|
365
|
-
}));
|
|
366
|
-
|
|
367
|
-
let result = await awaitPools.wipeVariables(func['$id']);
|
|
368
|
-
if (!result) {
|
|
369
|
-
throw new Error("Variable deletion timed out.");
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Deploy local variables
|
|
373
|
-
await Promise.all(Object.keys(func.variables).map(async localVariableKey => {
|
|
374
|
-
await functionsCreateVariable({
|
|
375
|
-
functionId: func['$id'],
|
|
376
|
-
key: localVariableKey,
|
|
377
|
-
value: func.variables[localVariableKey],
|
|
378
|
-
parseOutput: false
|
|
379
|
-
});
|
|
380
|
-
}));
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Create tag
|
|
385
|
-
if (!func.entrypoint) {
|
|
386
|
-
const answers = await inquirer.prompt(questionsGetEntrypoint)
|
|
387
|
-
func.entrypoint = answers.entrypoint;
|
|
388
|
-
localConfig.updateFunction(func['$id'], func);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
try {
|
|
392
|
-
response = await functionsCreateDeployment({
|
|
393
|
-
functionId: func['$id'],
|
|
394
|
-
entrypoint: func.entrypoint,
|
|
395
|
-
commands: func.commands,
|
|
396
|
-
code: func.path,
|
|
397
|
-
activate: true,
|
|
398
|
-
parseOutput: false
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
success(`Deployed ${func.name} ( ${func['$id']} )`);
|
|
402
|
-
|
|
403
|
-
} catch (e) {
|
|
404
|
-
switch (e.code) {
|
|
405
|
-
case 'ENOENT':
|
|
406
|
-
error(`Function ${func.name} ( ${func['$id']} ) not found in the current directory. Skipping ...`);
|
|
407
|
-
break;
|
|
408
|
-
default:
|
|
409
|
-
throw e;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
success(`Deployed ${functions.length} functions`);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const createAttribute = async (databaseId, collectionId, attribute) => {
|
|
418
|
-
switch (attribute.type) {
|
|
419
|
-
case 'string':
|
|
420
|
-
switch (attribute.format) {
|
|
421
|
-
case 'email':
|
|
422
|
-
return await databasesCreateEmailAttribute({
|
|
423
|
-
databaseId,
|
|
424
|
-
collectionId,
|
|
425
|
-
key: attribute.key,
|
|
426
|
-
required: attribute.required,
|
|
427
|
-
xdefault: attribute.default,
|
|
428
|
-
array: attribute.array,
|
|
429
|
-
parseOutput: false
|
|
430
|
-
})
|
|
431
|
-
case 'url':
|
|
432
|
-
return await databasesCreateUrlAttribute({
|
|
433
|
-
databaseId,
|
|
434
|
-
collectionId,
|
|
435
|
-
key: attribute.key,
|
|
436
|
-
required: attribute.required,
|
|
437
|
-
xdefault: attribute.default,
|
|
438
|
-
array: attribute.array,
|
|
439
|
-
parseOutput: false
|
|
440
|
-
})
|
|
441
|
-
case 'ip':
|
|
442
|
-
return await databasesCreateIpAttribute({
|
|
443
|
-
databaseId,
|
|
444
|
-
collectionId,
|
|
445
|
-
key: attribute.key,
|
|
446
|
-
required: attribute.required,
|
|
447
|
-
xdefault: attribute.default,
|
|
448
|
-
array: attribute.array,
|
|
449
|
-
parseOutput: false
|
|
450
|
-
})
|
|
451
|
-
case 'enum':
|
|
452
|
-
return await databasesCreateEnumAttribute({
|
|
453
|
-
databaseId,
|
|
454
|
-
collectionId,
|
|
455
|
-
key: attribute.key,
|
|
456
|
-
elements: attribute.elements,
|
|
457
|
-
required: attribute.required,
|
|
458
|
-
xdefault: attribute.default,
|
|
459
|
-
array: attribute.array,
|
|
460
|
-
parseOutput: false
|
|
461
|
-
})
|
|
462
|
-
default:
|
|
463
|
-
return await databasesCreateStringAttribute({
|
|
464
|
-
databaseId,
|
|
465
|
-
collectionId,
|
|
466
|
-
key: attribute.key,
|
|
467
|
-
size: attribute.size,
|
|
468
|
-
required: attribute.required,
|
|
469
|
-
xdefault: attribute.default,
|
|
470
|
-
array: attribute.array,
|
|
471
|
-
parseOutput: false
|
|
472
|
-
})
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
case 'integer':
|
|
476
|
-
return await databasesCreateIntegerAttribute({
|
|
477
|
-
databaseId,
|
|
478
|
-
collectionId,
|
|
479
|
-
key: attribute.key,
|
|
480
|
-
required: attribute.required,
|
|
481
|
-
min: attribute.min,
|
|
482
|
-
max: attribute.max,
|
|
483
|
-
xdefault: attribute.default,
|
|
484
|
-
array: attribute.array,
|
|
485
|
-
parseOutput: false
|
|
486
|
-
})
|
|
487
|
-
case 'double':
|
|
488
|
-
return databasesCreateFloatAttribute({
|
|
489
|
-
databaseId,
|
|
490
|
-
collectionId,
|
|
491
|
-
key: attribute.key,
|
|
492
|
-
required: attribute.required,
|
|
493
|
-
min: attribute.min,
|
|
494
|
-
max: attribute.max,
|
|
495
|
-
xdefault: attribute.default,
|
|
496
|
-
array: attribute.array,
|
|
497
|
-
parseOutput: false
|
|
498
|
-
})
|
|
499
|
-
case 'boolean':
|
|
500
|
-
return databasesCreateBooleanAttribute({
|
|
501
|
-
databaseId,
|
|
502
|
-
collectionId,
|
|
503
|
-
key: attribute.key,
|
|
504
|
-
required: attribute.required,
|
|
505
|
-
xdefault: attribute.default,
|
|
506
|
-
array: attribute.array,
|
|
507
|
-
parseOutput: false
|
|
508
|
-
})
|
|
509
|
-
case 'datetime':
|
|
510
|
-
return databasesCreateDatetimeAttribute({
|
|
511
|
-
databaseId,
|
|
512
|
-
collectionId,
|
|
513
|
-
key: attribute.key,
|
|
514
|
-
required: attribute.required,
|
|
515
|
-
xdefault: attribute.default,
|
|
516
|
-
array: attribute.array,
|
|
517
|
-
parseOutput: false
|
|
518
|
-
})
|
|
519
|
-
case 'relationship':
|
|
520
|
-
return databasesCreateRelationshipAttribute({
|
|
521
|
-
databaseId,
|
|
522
|
-
collectionId,
|
|
523
|
-
relatedCollectionId: attribute.relatedCollection,
|
|
524
|
-
type: attribute.relationType,
|
|
525
|
-
twoWay: attribute.twoWay,
|
|
526
|
-
key: attribute.key,
|
|
527
|
-
twoWayKey: attribute.twoWayKey,
|
|
528
|
-
onDelete: attribute.onDelete,
|
|
529
|
-
parseOutput: false
|
|
530
|
-
})
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const deployCollection = async ({ all, yes } = {}) => {
|
|
535
|
-
let response = {};
|
|
536
|
-
|
|
537
|
-
const collections = [];
|
|
538
|
-
|
|
539
|
-
if (all) {
|
|
540
|
-
checkDeployConditions(localConfig);
|
|
541
|
-
if (localConfig.getCollections().length === 0) {
|
|
542
|
-
throw new Error("No collections found in the current directory. Run `appwrite init collection` to fetch all your collections.");
|
|
543
|
-
}
|
|
544
|
-
collections.push(...localConfig.getCollections());
|
|
545
|
-
} else {
|
|
546
|
-
const answers = await inquirer.prompt(questionsDeployCollections[0])
|
|
547
|
-
const configCollections = new Map();
|
|
548
|
-
localConfig.getCollections().forEach((c) => {
|
|
549
|
-
configCollections.set(`${c['databaseId']}|${c['$id']}`, c);
|
|
550
|
-
});
|
|
551
|
-
answers.collections.forEach((a) => {
|
|
552
|
-
const collection = configCollections.get(a);
|
|
553
|
-
collections.push(collection);
|
|
554
|
-
})
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
for (let collection of collections) {
|
|
558
|
-
log(`Deploying collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} )`)
|
|
559
|
-
|
|
560
|
-
let databaseId;
|
|
561
|
-
|
|
562
|
-
const localDatabase = localConfig.getDatabase(collection.databaseId);
|
|
563
|
-
|
|
564
|
-
try {
|
|
565
|
-
const database = await databasesGet({
|
|
566
|
-
databaseId: collection.databaseId,
|
|
567
|
-
parseOutput: false,
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
databaseId = database.$id;
|
|
571
|
-
|
|
572
|
-
if (database.name !== (localDatabase.name ?? collection.databaseId)) {
|
|
573
|
-
await databasesUpdate({
|
|
574
|
-
databaseId: collection.databaseId,
|
|
575
|
-
name: localDatabase.name ?? collection.databaseId,
|
|
576
|
-
parseOutput: false
|
|
577
|
-
})
|
|
578
|
-
|
|
579
|
-
success(`Updated ${localDatabase.name} ( ${collection.databaseId} )`);
|
|
580
|
-
}
|
|
581
|
-
} catch (err) {
|
|
582
|
-
log(`Database ${collection.databaseId} not found. Creating it now...`);
|
|
583
|
-
|
|
584
|
-
const database = await databasesCreate({
|
|
585
|
-
databaseId: collection.databaseId,
|
|
586
|
-
name: localDatabase.name ?? collection.databaseId,
|
|
587
|
-
parseOutput: false,
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
databaseId = database.$id;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
try {
|
|
594
|
-
response = await databasesGetCollection({
|
|
595
|
-
databaseId,
|
|
596
|
-
collectionId: collection['$id'],
|
|
597
|
-
parseOutput: false,
|
|
598
|
-
})
|
|
599
|
-
|
|
600
|
-
log(`Collection ${collection.name} ( ${collection['$id']} ) already exists.`);
|
|
601
|
-
|
|
602
|
-
if (!yes) {
|
|
603
|
-
const answers = await inquirer.prompt(questionsDeployCollections[1])
|
|
604
|
-
if (answers.override.toLowerCase() !== "yes") {
|
|
605
|
-
log(`Received "${answers.override}". Skipping ${collection.name} ( ${collection['$id']} )`);
|
|
606
|
-
continue;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
log(`Deleting indexes and attributes ... `);
|
|
611
|
-
|
|
612
|
-
const { indexes } = await paginate(databasesListIndexes, {
|
|
613
|
-
databaseId,
|
|
614
|
-
collectionId: collection['$id'],
|
|
615
|
-
parseOutput: false
|
|
616
|
-
}, 100, 'indexes');
|
|
617
|
-
|
|
618
|
-
await Promise.all(indexes.map(async index => {
|
|
619
|
-
await databasesDeleteIndex({
|
|
620
|
-
databaseId,
|
|
621
|
-
collectionId: collection['$id'],
|
|
622
|
-
key: index.key,
|
|
623
|
-
parseOutput: false
|
|
624
|
-
});
|
|
625
|
-
}));
|
|
626
|
-
|
|
627
|
-
let result = await awaitPools.wipeIndexes(databaseId, collection['$id']);
|
|
628
|
-
if (!result) {
|
|
629
|
-
throw new Error("Index deletion timed out.");
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
const { attributes } = await paginate(databasesListAttributes, {
|
|
633
|
-
databaseId,
|
|
634
|
-
collectionId: collection['$id'],
|
|
635
|
-
parseOutput: false
|
|
636
|
-
}, 100, 'attributes');
|
|
637
|
-
|
|
638
|
-
await Promise.all(attributes.map(async attribute => {
|
|
639
|
-
await databasesDeleteAttribute({
|
|
640
|
-
databaseId,
|
|
641
|
-
collectionId: collection['$id'],
|
|
642
|
-
key: attribute.key,
|
|
643
|
-
parseOutput: false
|
|
644
|
-
});
|
|
645
|
-
}));
|
|
646
|
-
|
|
647
|
-
const deleteAttributesPoolStatus = await awaitPools.wipeAttributes(databaseId, collection['$id']);
|
|
648
|
-
if (!deleteAttributesPoolStatus) {
|
|
649
|
-
throw new Error("Attribute deletion timed out.");
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
await databasesUpdateCollection({
|
|
653
|
-
databaseId,
|
|
654
|
-
collectionId: collection['$id'],
|
|
655
|
-
name: collection.name,
|
|
656
|
-
documentSecurity: collection.documentSecurity,
|
|
657
|
-
permissions: collection['$permissions'],
|
|
658
|
-
enabled: collection.enabled,
|
|
659
|
-
parseOutput: false
|
|
660
|
-
})
|
|
661
|
-
} catch (e) {
|
|
662
|
-
if (e.code == 404) {
|
|
663
|
-
log(`Collection ${collection.name} does not exist in the project. Creating ... `);
|
|
664
|
-
response = await databasesCreateCollection({
|
|
665
|
-
databaseId,
|
|
666
|
-
collectionId: collection['$id'],
|
|
667
|
-
name: collection.name,
|
|
668
|
-
documentSecurity: collection.documentSecurity,
|
|
669
|
-
permissions: collection['$permissions'],
|
|
670
|
-
parseOutput: false
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
} else {
|
|
674
|
-
throw e;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
// Create all non-relationship attributes first
|
|
679
|
-
const attributes = collection.attributes.filter(attribute => attribute.type !== 'relationship');
|
|
680
|
-
|
|
681
|
-
await Promise.all(attributes.map(attribute => {
|
|
682
|
-
return createAttribute(databaseId, collection['$id'], attribute);
|
|
683
|
-
}));
|
|
684
|
-
|
|
685
|
-
let result = await awaitPools.expectAttributes(
|
|
686
|
-
databaseId,
|
|
687
|
-
collection['$id'],
|
|
688
|
-
attributes.map(attribute => attribute.key)
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
if (!result) {
|
|
692
|
-
throw new Error("Attribute creation timed out.");
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
success(`Created ${attributes.length} non-relationship attributes`);
|
|
696
|
-
|
|
697
|
-
log(`Creating indexes ...`)
|
|
698
|
-
|
|
699
|
-
await Promise.all(collection.indexes.map(async index => {
|
|
700
|
-
await databasesCreateIndex({
|
|
701
|
-
databaseId,
|
|
702
|
-
collectionId: collection['$id'],
|
|
703
|
-
key: index.key,
|
|
704
|
-
type: index.type,
|
|
705
|
-
attributes: index.attributes,
|
|
706
|
-
orders: index.orders,
|
|
707
|
-
parseOutput: false
|
|
708
|
-
});
|
|
709
|
-
}));
|
|
710
|
-
|
|
711
|
-
result = await awaitPools.expectIndexes(
|
|
712
|
-
databaseId,
|
|
713
|
-
collection['$id'],
|
|
714
|
-
collection.indexes.map(attribute => attribute.key)
|
|
715
|
-
);
|
|
716
|
-
|
|
717
|
-
if (!result) {
|
|
718
|
-
throw new Error("Index creation timed out.");
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
success(`Created ${collection.indexes.length} indexes`);
|
|
722
|
-
|
|
723
|
-
success(`Deployed ${collection.name} ( ${collection['$id']} )`);
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Create the relationship attributes
|
|
727
|
-
for (let collection of collections) {
|
|
728
|
-
const relationships = collection.attributes.filter(attribute =>
|
|
729
|
-
attribute.type === 'relationship' && attribute.side === 'parent'
|
|
730
|
-
);
|
|
731
|
-
|
|
732
|
-
if (relationships.length === 0) {
|
|
733
|
-
continue;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
log(`Deploying relationships for collection ${collection.name} ( ${collection['$id']} )`);
|
|
737
|
-
|
|
738
|
-
await Promise.all(relationships.map(attribute => {
|
|
739
|
-
return createAttribute(collection['databaseId'], collection['$id'], attribute);
|
|
740
|
-
}));
|
|
741
|
-
|
|
742
|
-
let result = await awaitPools.expectAttributes(
|
|
743
|
-
collection['databaseId'],
|
|
744
|
-
collection['$id'],
|
|
745
|
-
relationships.map(attribute => attribute.key)
|
|
746
|
-
);
|
|
747
|
-
|
|
748
|
-
if (!result) {
|
|
749
|
-
throw new Error("Attribute creation timed out.");
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
success(`Created ${relationships.length} relationship attributes`);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
const deployBucket = async ({ all, yes } = {}) => {
|
|
757
|
-
let response = {};
|
|
758
|
-
|
|
759
|
-
let bucketIds = [];
|
|
760
|
-
const configBuckets = localConfig.getBuckets();
|
|
761
|
-
|
|
762
|
-
if (all) {
|
|
763
|
-
checkDeployConditions(localConfig);
|
|
764
|
-
bucketIds.push(...configBuckets.map((b) => b.$id));
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (bucketIds.length === 0) {
|
|
768
|
-
const answers = await inquirer.prompt(questionsDeployBuckets[0])
|
|
769
|
-
bucketIds.push(...answers.buckets);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
let buckets = [];
|
|
773
|
-
|
|
774
|
-
for (const bucketId of bucketIds) {
|
|
775
|
-
const idBuckets = configBuckets.filter((b) => b.$id === bucketId);
|
|
776
|
-
buckets.push(...idBuckets);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
for (let bucket of buckets) {
|
|
780
|
-
log(`Deploying bucket ${bucket.name} ( ${bucket['$id']} )`)
|
|
781
|
-
|
|
782
|
-
try {
|
|
783
|
-
response = await storageGetBucket({
|
|
784
|
-
bucketId: bucket['$id'],
|
|
785
|
-
parseOutput: false,
|
|
786
|
-
})
|
|
787
|
-
log(`Bucket ${bucket.name} ( ${bucket['$id']} ) already exists.`);
|
|
788
|
-
|
|
789
|
-
if (!yes) {
|
|
790
|
-
const answers = await inquirer.prompt(questionsDeployBuckets[1])
|
|
791
|
-
if (answers.override.toLowerCase() !== "yes") {
|
|
792
|
-
log(`Received "${answers.override}". Skipping ${bucket.name} ( ${bucket['$id']} )`);
|
|
793
|
-
continue;
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
log(`Updating bucket ...`)
|
|
798
|
-
|
|
799
|
-
await storageUpdateBucket({
|
|
800
|
-
bucketId: bucket['$id'],
|
|
801
|
-
name: bucket.name,
|
|
802
|
-
permissions: bucket['$permissions'],
|
|
803
|
-
fileSecurity: bucket.fileSecurity,
|
|
804
|
-
enabled: bucket.enabled,
|
|
805
|
-
maximumFileSize: bucket.maximumFileSize,
|
|
806
|
-
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
807
|
-
compression: bucket.compression,
|
|
808
|
-
encryption: bucket.encryption,
|
|
809
|
-
antivirus: bucket.antivirus,
|
|
810
|
-
compression: bucket.compression,
|
|
811
|
-
parseOutput: false
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
|
|
815
|
-
} catch (e) {
|
|
816
|
-
if (e.code == 404) {
|
|
817
|
-
log(`Bucket ${bucket.name} does not exist in the project. Creating ... `);
|
|
818
|
-
|
|
819
|
-
response = await storageCreateBucket({
|
|
820
|
-
bucketId: bucket['$id'],
|
|
821
|
-
name: bucket.name,
|
|
822
|
-
permissions: bucket['$permissions'],
|
|
823
|
-
fileSecurity: bucket.fileSecurity,
|
|
824
|
-
enabled: bucket.enabled,
|
|
825
|
-
maximumFileSize: bucket.maximumFileSize,
|
|
826
|
-
allowedFileExtensions: bucket.allowedFileExtensions,
|
|
827
|
-
compression: bucket.compression,
|
|
828
|
-
encryption: bucket.encryption,
|
|
829
|
-
antivirus: bucket.antivirus,
|
|
830
|
-
parseOutput: false
|
|
831
|
-
})
|
|
832
|
-
|
|
833
|
-
success(`Deployed ${bucket.name} ( ${bucket['$id']} )`);
|
|
834
|
-
} else {
|
|
835
|
-
throw e;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
const deployTeam = async ({ all, yes } = {}) => {
|
|
842
|
-
let response = {};
|
|
843
|
-
|
|
844
|
-
let teamIds = [];
|
|
845
|
-
const configTeams = localConfig.getTeams();
|
|
846
|
-
|
|
847
|
-
if (all) {
|
|
848
|
-
checkDeployConditions(localConfig);
|
|
849
|
-
teamIds.push(...configTeams.map((t) => t.$id));
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
if (teamIds.length === 0) {
|
|
853
|
-
const answers = await inquirer.prompt(questionsDeployTeams[0])
|
|
854
|
-
teamIds.push(...answers.teams);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
let teams = [];
|
|
858
|
-
|
|
859
|
-
for (const teamId of teamIds) {
|
|
860
|
-
const idTeams = configTeams.filter((t) => t.$id === teamId);
|
|
861
|
-
teams.push(...idTeams);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
for (let team of teams) {
|
|
865
|
-
log(`Deploying team ${team.name} ( ${team['$id']} )`)
|
|
866
|
-
|
|
867
|
-
try {
|
|
868
|
-
response = await teamsGet({
|
|
869
|
-
teamId: team['$id'],
|
|
870
|
-
parseOutput: false,
|
|
871
|
-
})
|
|
872
|
-
log(`Team ${team.name} ( ${team['$id']} ) already exists.`);
|
|
873
|
-
|
|
874
|
-
if (!yes) {
|
|
875
|
-
const answers = await inquirer.prompt(questionsDeployTeams[1])
|
|
876
|
-
if (answers.override.toLowerCase() !== "yes") {
|
|
877
|
-
log(`Received "${answers.override}". Skipping ${team.name} ( ${team['$id']} )`);
|
|
878
|
-
continue;
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
log(`Updating team ...`)
|
|
883
|
-
|
|
884
|
-
await teamsUpdateName({
|
|
885
|
-
teamId: team['$id'],
|
|
886
|
-
name: team.name,
|
|
887
|
-
parseOutput: false
|
|
888
|
-
});
|
|
889
|
-
|
|
890
|
-
success(`Deployed ${team.name} ( ${team['$id']} )`);
|
|
891
|
-
} catch (e) {
|
|
892
|
-
if (e.code == 404) {
|
|
893
|
-
log(`Team ${team.name} does not exist in the project. Creating ... `);
|
|
894
|
-
|
|
895
|
-
response = await teamsCreate({
|
|
896
|
-
teamId: team['$id'],
|
|
897
|
-
name: team.name,
|
|
898
|
-
parseOutput: false
|
|
899
|
-
})
|
|
900
|
-
|
|
901
|
-
success(`Deployed ${team.name} ( ${team['$id']} )`);
|
|
902
|
-
} else {
|
|
903
|
-
throw e;
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
deploy
|
|
910
|
-
.command("function")
|
|
911
|
-
.description("Deploy functions in the current directory.")
|
|
912
|
-
.option(`--functionId <functionId>`, `Function ID`)
|
|
913
|
-
.option(`--all`, `Flag to deploy all functions`)
|
|
914
|
-
.option(`--yes`, `Flag to confirm all warnings`)
|
|
915
|
-
.action(actionRunner(deployFunction));
|
|
916
|
-
|
|
917
|
-
deploy
|
|
918
|
-
.command("collection")
|
|
919
|
-
.description("Deploy collections in the current project.")
|
|
920
|
-
.option(`--all`, `Flag to deploy all collections`)
|
|
921
|
-
.option(`--yes`, `Flag to confirm all warnings`)
|
|
922
|
-
.action(actionRunner(deployCollection));
|
|
923
|
-
|
|
924
|
-
deploy
|
|
925
|
-
.command("bucket")
|
|
926
|
-
.description("Deploy buckets in the current project.")
|
|
927
|
-
.option(`--all`, `Flag to deploy all buckets`)
|
|
928
|
-
.option(`--yes`, `Flag to confirm all warnings`)
|
|
929
|
-
.action(actionRunner(deployBucket));
|
|
930
|
-
|
|
931
|
-
deploy
|
|
932
|
-
.command("team")
|
|
933
|
-
.description("Deploy teams in the current project.")
|
|
934
|
-
.option(`--all`, `Flag to deploy all teams`)
|
|
935
|
-
.option(`--yes`, `Flag to confirm all warnings`)
|
|
936
|
-
.action(actionRunner(deployTeam));
|
|
937
|
-
|
|
938
|
-
module.exports = {
|
|
939
|
-
deploy
|
|
940
|
-
}
|