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.
Files changed (53) hide show
  1. package/README.md +4 -4
  2. package/docs/examples/functions/create-build.md +1 -1
  3. package/docs/examples/functions/create-execution.md +1 -0
  4. package/docs/examples/functions/create.md +1 -0
  5. package/docs/examples/functions/delete-execution.md +3 -0
  6. package/docs/examples/functions/update-deployment-build.md +3 -0
  7. package/docs/examples/functions/update.md +1 -0
  8. package/docs/examples/projects/create-j-w-t.md +4 -0
  9. package/docs/examples/projects/update-mock-numbers.md +3 -0
  10. package/docs/examples/projects/update-session-alerts.md +3 -0
  11. package/docs/examples/users/create-j-w-t.md +4 -0
  12. package/docs/examples/vcs/get-repository-contents.md +4 -0
  13. package/index.js +34 -7
  14. package/install.ps1 +3 -3
  15. package/install.sh +2 -2
  16. package/lib/client.js +17 -3
  17. package/lib/commands/account.js +306 -152
  18. package/lib/commands/assistant.js +8 -5
  19. package/lib/commands/avatars.js +114 -58
  20. package/lib/commands/console.js +8 -5
  21. package/lib/commands/databases.js +353 -164
  22. package/lib/commands/functions.js +310 -100
  23. package/lib/commands/generic.js +206 -54
  24. package/lib/commands/graphql.js +14 -8
  25. package/lib/commands/health.js +140 -71
  26. package/lib/commands/init.js +250 -155
  27. package/lib/commands/locale.js +50 -26
  28. package/lib/commands/messaging.js +334 -156
  29. package/lib/commands/migrations.js +98 -50
  30. package/lib/commands/project.js +38 -20
  31. package/lib/commands/projects.js +449 -144
  32. package/lib/commands/proxy.js +32 -17
  33. package/lib/commands/pull.js +231 -0
  34. package/lib/commands/push.js +1518 -0
  35. package/lib/commands/run.js +282 -0
  36. package/lib/commands/storage.js +160 -76
  37. package/lib/commands/teams.js +102 -50
  38. package/lib/commands/users.js +324 -134
  39. package/lib/commands/vcs.js +102 -29
  40. package/lib/config.js +190 -18
  41. package/lib/emulation/docker.js +187 -0
  42. package/lib/emulation/utils.js +177 -0
  43. package/lib/id.js +30 -0
  44. package/lib/paginate.js +1 -2
  45. package/lib/parser.js +69 -12
  46. package/lib/questions.js +452 -80
  47. package/lib/sdks.js +1 -1
  48. package/lib/spinner.js +103 -0
  49. package/lib/utils.js +242 -4
  50. package/lib/validations.js +17 -0
  51. package/package.json +6 -2
  52. package/scoop/appwrite.json +3 -3
  53. 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
+ }