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
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
const Tail = require('tail').Tail;
|
|
2
|
+
const EventEmitter = require('node:events');
|
|
3
|
+
const ignore = require("ignore");
|
|
4
|
+
const tar = require("tar");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const ID = require("../id");
|
|
7
|
+
const childProcess = require('child_process');
|
|
8
|
+
const chokidar = require('chokidar');
|
|
9
|
+
const inquirer = require("inquirer");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const { Command } = require("commander");
|
|
12
|
+
const { localConfig, globalConfig } = require("../config");
|
|
13
|
+
const { paginate } = require('../paginate');
|
|
14
|
+
const { functionsListVariables } = require('./functions');
|
|
15
|
+
const { usersGet, usersCreateJWT } = require('./users');
|
|
16
|
+
const { projectsCreateJWT } = require('./projects');
|
|
17
|
+
const { questionsRunFunctions } = require("../questions");
|
|
18
|
+
const { actionRunner, success, log, error, commandDescriptions, drawTable } = require("../parser");
|
|
19
|
+
const { systemHasCommand, isPortTaken, getAllFiles } = require('../utils');
|
|
20
|
+
const { openRuntimesVersion, runtimeNames, systemTools, JwtManager, Queue } = require('../emulation/utils');
|
|
21
|
+
const { dockerStop, dockerCleanup, dockerStart, dockerBuild, dockerPull, dockerStopActive } = require('../emulation/docker');
|
|
22
|
+
|
|
23
|
+
const runFunction = async ({ port, functionId, noVariables, noReload, userId } = {}) => {
|
|
24
|
+
// Selection
|
|
25
|
+
if(!functionId) {
|
|
26
|
+
const answers = await inquirer.prompt(questionsRunFunctions[0]);
|
|
27
|
+
functionId = answers.function;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const functions = localConfig.getFunctions();
|
|
31
|
+
const func = functions.find((f) => f.$id === functionId);
|
|
32
|
+
if (!func) {
|
|
33
|
+
throw new Error("Function '" + functionId + "' not found.")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const runtimeName = func.runtime.split("-").slice(0, -1).join("-");
|
|
37
|
+
const tool = systemTools[runtimeName];
|
|
38
|
+
|
|
39
|
+
// Configuration: Port
|
|
40
|
+
if(port) {
|
|
41
|
+
port = +port;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if(isNaN(port)) {
|
|
45
|
+
port = null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if(port) {
|
|
49
|
+
const taken = await isPortTaken(port);
|
|
50
|
+
|
|
51
|
+
if(taken) {
|
|
52
|
+
error(`Port ${port} is already in use by another process.`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if(!port) {
|
|
58
|
+
let portFound = false;
|
|
59
|
+
port = 3000;
|
|
60
|
+
while(port < 3100) {
|
|
61
|
+
const taken = await isPortTaken(port);
|
|
62
|
+
if(!taken) {
|
|
63
|
+
portFound = true;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
port++;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if(!portFound) {
|
|
71
|
+
error('Could not find an available port. Please select a port with `appwrite run --port YOUR_PORT` command.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Configuration: Engine
|
|
77
|
+
if(!systemHasCommand('docker')) {
|
|
78
|
+
return error("Docker Engine is required for local development. Please install Docker using: https://docs.docker.com/engine/install/");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Settings
|
|
82
|
+
const settings = {
|
|
83
|
+
runtime: func.runtime,
|
|
84
|
+
entrypoint: func.entrypoint,
|
|
85
|
+
path: func.path,
|
|
86
|
+
commands: func.commands,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
log("Local function configuration:");
|
|
90
|
+
drawTable([settings]);
|
|
91
|
+
log('If you wish to change your local settings, update the appwrite.json file and rerun the `appwrite run` command.');
|
|
92
|
+
|
|
93
|
+
await dockerCleanup();
|
|
94
|
+
|
|
95
|
+
process.on('SIGINT', async () => {
|
|
96
|
+
log('Cleaning up ...');
|
|
97
|
+
await dockerCleanup();
|
|
98
|
+
success();
|
|
99
|
+
process.exit();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const logsPath = path.join(process.cwd(), func.path, '.appwrite/logs.txt');
|
|
103
|
+
const errorsPath = path.join(process.cwd(), func.path, '.appwrite/errors.txt');
|
|
104
|
+
|
|
105
|
+
if(!fs.existsSync(path.dirname(logsPath))) {
|
|
106
|
+
fs.mkdirSync(path.dirname(logsPath), { recursive: true });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!fs.existsSync(logsPath)) {
|
|
110
|
+
fs.writeFileSync(logsPath, '');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!fs.existsSync(errorsPath)) {
|
|
114
|
+
fs.writeFileSync(errorsPath, '');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const variables = {};
|
|
118
|
+
if(!noVariables) {
|
|
119
|
+
if (globalConfig.getEndpoint() === '' || globalConfig.getCookie() === '') {
|
|
120
|
+
error("No user is signed in. To sign in, run: appwrite login. Function will run locally, but will not have your function's environment variables set.");
|
|
121
|
+
} else {
|
|
122
|
+
try {
|
|
123
|
+
const { variables: remoteVariables } = await paginate(functionsListVariables, {
|
|
124
|
+
functionId: func['$id'],
|
|
125
|
+
parseOutput: false
|
|
126
|
+
}, 100, 'variables');
|
|
127
|
+
|
|
128
|
+
remoteVariables.forEach((v) => {
|
|
129
|
+
variables[v.key] = v.value;
|
|
130
|
+
});
|
|
131
|
+
} catch(err) {
|
|
132
|
+
log("Could not fetch remote variables: " + err.message);
|
|
133
|
+
log("Function will run locally, but will not have your function's environment variables set.");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
variables['APPWRITE_FUNCTION_API_ENDPOINT'] = globalConfig.getFrom('endpoint');
|
|
139
|
+
variables['APPWRITE_FUNCTION_ID'] = func.$id;
|
|
140
|
+
variables['APPWRITE_FUNCTION_NAME'] = func.name;
|
|
141
|
+
variables['APPWRITE_FUNCTION_DEPLOYMENT'] = ''; // TODO: Implement when relevant
|
|
142
|
+
variables['APPWRITE_FUNCTION_PROJECT_ID'] = localConfig.getProject().projectId;
|
|
143
|
+
variables['APPWRITE_FUNCTION_RUNTIME_NAME'] = runtimeNames[runtimeName] ?? '';
|
|
144
|
+
variables['APPWRITE_FUNCTION_RUNTIME_VERSION'] = func.runtime;
|
|
145
|
+
|
|
146
|
+
await JwtManager.setup(userId);
|
|
147
|
+
|
|
148
|
+
const headers = {};
|
|
149
|
+
headers['x-appwrite-key'] = JwtManager.functionJwt ?? '';
|
|
150
|
+
headers['x-appwrite-trigger'] = 'http';
|
|
151
|
+
headers['x-appwrite-event'] = '';
|
|
152
|
+
headers['x-appwrite-user-id'] = userId ?? '';
|
|
153
|
+
headers['x-appwrite-user-jwt'] = JwtManager.userJwt ?? '';
|
|
154
|
+
variables['OPEN_RUNTIMES_HEADERS'] = JSON.stringify(headers);
|
|
155
|
+
|
|
156
|
+
await dockerPull(func);
|
|
157
|
+
await dockerBuild(func, variables);
|
|
158
|
+
await dockerStart(func, variables, port);
|
|
159
|
+
|
|
160
|
+
new Tail(logsPath).on("line", function(data) {
|
|
161
|
+
console.log(data);
|
|
162
|
+
});
|
|
163
|
+
new Tail(errorsPath).on("line", function(data) {
|
|
164
|
+
console.log(data);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if(!noReload) {
|
|
168
|
+
chokidar.watch('.', {
|
|
169
|
+
cwd: path.join(process.cwd(), func.path),
|
|
170
|
+
ignoreInitial: true,
|
|
171
|
+
ignored: [ ...(func.ignore ?? []), 'code.tar.gz', '.appwrite', '.appwrite/', '.appwrite/*', '.appwrite/**', '.appwrite/*.*', '.appwrite/**/*.*' ]
|
|
172
|
+
}).on('all', async (_event, filePath) => {
|
|
173
|
+
Queue.push(filePath);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
Queue.events.on('reload', async ({ files }) => {
|
|
178
|
+
Queue.lock();
|
|
179
|
+
|
|
180
|
+
log('Live-reloading due to file changes: ');
|
|
181
|
+
for(const file of files) {
|
|
182
|
+
log(`- ${file}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
log('Stopping the function ...');
|
|
187
|
+
|
|
188
|
+
await dockerStopActive();
|
|
189
|
+
|
|
190
|
+
const dependencyFile = files.find((filePath) => tool.dependencyFiles.includes(filePath));
|
|
191
|
+
if(tool.isCompiled || dependencyFile) {
|
|
192
|
+
log(`Rebuilding the function due to cange in ${dependencyFile} ...`);
|
|
193
|
+
await dockerBuild(func, variables);
|
|
194
|
+
await dockerStart(func, variables, port);
|
|
195
|
+
} else {
|
|
196
|
+
log('Hot-swapping function files ...');
|
|
197
|
+
|
|
198
|
+
const functionPath = path.join(process.cwd(), func.path);
|
|
199
|
+
const hotSwapPath = path.join(functionPath, '.appwrite/hot-swap');
|
|
200
|
+
const buildPath = path.join(functionPath, '.appwrite/build.tar.gz');
|
|
201
|
+
|
|
202
|
+
// Prepare temp folder
|
|
203
|
+
if (!fs.existsSync(hotSwapPath)) {
|
|
204
|
+
fs.mkdirSync(hotSwapPath, { recursive: true });
|
|
205
|
+
} else {
|
|
206
|
+
fs.rmSync(hotSwapPath, { recursive: true, force: true });
|
|
207
|
+
fs.mkdirSync(hotSwapPath, { recursive: true });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
await tar
|
|
211
|
+
.extract({
|
|
212
|
+
gzip: true,
|
|
213
|
+
sync: true,
|
|
214
|
+
cwd: hotSwapPath,
|
|
215
|
+
file: buildPath
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const ignorer = ignore();
|
|
219
|
+
ignorer.add('.appwrite');
|
|
220
|
+
if (func.ignore) {
|
|
221
|
+
ignorer.add(func.ignore);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const filesToCopy = getAllFiles(functionPath).map((file) => path.relative(functionPath, file)).filter((file) => !ignorer.ignores(file));
|
|
225
|
+
for(const f of filesToCopy) {
|
|
226
|
+
const filePath = path.join(hotSwapPath, f);
|
|
227
|
+
if (fs.existsSync(filePath)) {
|
|
228
|
+
fs.rmSync(filePath, { force: true });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const fileDir = path.dirname(filePath);
|
|
232
|
+
if (!fs.existsSync(fileDir)) {
|
|
233
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const sourcePath = path.join(functionPath, f);
|
|
237
|
+
fs.copyFileSync(sourcePath, filePath);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
await tar
|
|
241
|
+
.create({
|
|
242
|
+
gzip: true,
|
|
243
|
+
sync: true,
|
|
244
|
+
cwd: hotSwapPath,
|
|
245
|
+
file: buildPath
|
|
246
|
+
}, ['.']);
|
|
247
|
+
|
|
248
|
+
fs.rmSync(hotSwapPath, { recursive: true, force: true });
|
|
249
|
+
|
|
250
|
+
await dockerStart(func, variables, port);
|
|
251
|
+
}
|
|
252
|
+
} catch(err) {
|
|
253
|
+
console.error(err);
|
|
254
|
+
} finally {
|
|
255
|
+
Queue.unlock();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const run = new Command("run")
|
|
261
|
+
.description(commandDescriptions['run'])
|
|
262
|
+
.configureHelp({
|
|
263
|
+
helpWidth: process.stdout.columns || 80
|
|
264
|
+
})
|
|
265
|
+
.action(actionRunner(async (_options, command) => {
|
|
266
|
+
command.help();
|
|
267
|
+
}));
|
|
268
|
+
|
|
269
|
+
run
|
|
270
|
+
.command("function")
|
|
271
|
+
.alias("functions")
|
|
272
|
+
.description("Run functions in the current directory.")
|
|
273
|
+
.option(`--functionId <functionId>`, `Function ID`)
|
|
274
|
+
.option(`--port <port>`, `Local port`)
|
|
275
|
+
.option(`--userId <userId>`, `ID of user to impersonate`)
|
|
276
|
+
.option(`--noVariables`, `Prevent pulling variables from function settings`)
|
|
277
|
+
.option(`--noReload`, `Prevent live reloading of server when changes are made to function files`)
|
|
278
|
+
.action(actionRunner(runFunction));
|
|
279
|
+
|
|
280
|
+
module.exports = {
|
|
281
|
+
run
|
|
282
|
+
}
|