appwrite-utils-cli 0.10.62 → 0.10.64
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 +2 -0
- package/dist/functions/deployments.js +21 -5
- package/dist/functions/methods.d.ts +4 -4
- package/dist/functions/methods.js +10 -5
- package/dist/interactiveCLI.js +76 -50
- package/package.json +2 -2
- package/src/functions/deployments.ts +28 -52
- package/src/functions/methods.ts +53 -102
- package/src/interactiveCLI.ts +103 -71
package/README.md
CHANGED
@@ -147,6 +147,8 @@ This updated CLI ensures that developers have robust tools at their fingertips t
|
|
147
147
|
|
148
148
|
## Changelog
|
149
149
|
|
150
|
+
- 0.10.64: Fixed `Deploy Function(s)` not ignoring things properly
|
151
|
+
- 0.10.63: My `collectLocalFunctions` function was failing to add the `scopes` and a few others to the function, accidentally, fixed now
|
150
152
|
- 0.10.62: Made `Deploy Function(s)` also update the functions, as not all things (timeout, specification, etc.) are updated via deploy
|
151
153
|
- 0.10.61: Fixed ignore haha, also added `ignore` to the `Functions` config, to specify what to ignore when creating the `.tar.gz` file
|
152
154
|
- 0.10.051: Added `node_modules` and a few others to the ignore
|
@@ -33,6 +33,15 @@ export const deployFunction = async (client, functionId, codePath, activate = tr
|
|
33
33
|
// Convert ignored patterns to lowercase for case-insensitive comparison
|
34
34
|
const ignoredLower = ignored.map((pattern) => pattern.toLowerCase());
|
35
35
|
const tarPath = join(process.cwd(), `function-${functionId}.tar.gz`);
|
36
|
+
// Verify codePath exists and is a directory
|
37
|
+
if (!fs.existsSync(codePath)) {
|
38
|
+
throw new Error(`Function directory not found at ${codePath}`);
|
39
|
+
}
|
40
|
+
const stats = await fs.promises.stat(codePath);
|
41
|
+
if (!stats.isDirectory()) {
|
42
|
+
throw new Error(`${codePath} is not a directory`);
|
43
|
+
}
|
44
|
+
console.log(chalk.blue(`Creating tarball from ${codePath}`));
|
36
45
|
const progressBar = new cliProgress.SingleBar({
|
37
46
|
format: "Uploading |" +
|
38
47
|
chalk.cyan("{bar}") +
|
@@ -47,10 +56,17 @@ export const deployFunction = async (client, functionId, codePath, activate = tr
|
|
47
56
|
cwd: codePath,
|
48
57
|
filter: (path, stat) => {
|
49
58
|
const relativePath = relative(codePath, join(codePath, path)).toLowerCase();
|
50
|
-
|
51
|
-
|
59
|
+
// Skip if path matches any ignored pattern
|
60
|
+
if (ignoredLower.some((pattern) => relativePath.startsWith(pattern) ||
|
61
|
+
relativePath.includes(`/${pattern}`) ||
|
62
|
+
relativePath.includes(`\\${pattern}`))) {
|
63
|
+
console.log(chalk.gray(`Ignoring ${path}`));
|
64
|
+
return false;
|
65
|
+
}
|
66
|
+
return true;
|
52
67
|
},
|
53
|
-
}, ["."]
|
68
|
+
}, ["."] // This now only includes contents of codePath since we set cwd to codePath
|
69
|
+
);
|
54
70
|
const fileBuffer = await fs.promises.readFile(tarPath);
|
55
71
|
const fileObject = InputFile.fromBuffer(new Uint8Array(fileBuffer), `function-${functionId}.tar.gz`);
|
56
72
|
try {
|
@@ -127,11 +143,11 @@ export const deployLocalFunction = async (client, functionName, functionConfig,
|
|
127
143
|
}
|
128
144
|
// Only create function if it doesn't exist
|
129
145
|
if (!functionExists) {
|
130
|
-
await createFunction(client, functionConfig
|
146
|
+
await createFunction(client, functionConfig);
|
131
147
|
}
|
132
148
|
else {
|
133
149
|
console.log(chalk.blue("Updating function..."));
|
134
|
-
await updateFunction(client, functionConfig
|
150
|
+
await updateFunction(client, functionConfig);
|
135
151
|
}
|
136
152
|
const deployPath = functionConfig.deployDir
|
137
153
|
? join(resolvedPath, functionConfig.deployDir)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Client
|
2
|
-
import { type Specification } from "appwrite-utils";
|
1
|
+
import { Client } from "node-appwrite";
|
2
|
+
import { type AppwriteFunction, type Specification } from "appwrite-utils";
|
3
3
|
export declare const listFunctions: (client: Client, queries?: string[], search?: string) => Promise<import("node-appwrite").Models.FunctionList>;
|
4
4
|
export declare const getFunction: (client: Client, functionId: string) => Promise<import("node-appwrite").Models.Function>;
|
5
5
|
export declare const downloadLatestFunctionDeployment: (client: Client, functionId: string, basePath?: string) => Promise<{
|
@@ -8,8 +8,8 @@ export declare const downloadLatestFunctionDeployment: (client: Client, function
|
|
8
8
|
deployment: import("node-appwrite").Models.Deployment;
|
9
9
|
}>;
|
10
10
|
export declare const deleteFunction: (client: Client, functionId: string) => Promise<{}>;
|
11
|
-
export declare const createFunction: (client: Client,
|
11
|
+
export declare const createFunction: (client: Client, functionConfig: AppwriteFunction) => Promise<import("node-appwrite").Models.Function>;
|
12
12
|
export declare const updateFunctionSpecifications: (client: Client, functionId: string, specification: Specification) => Promise<import("node-appwrite").Models.Function | undefined>;
|
13
13
|
export declare const listSpecifications: (client: Client) => Promise<import("node-appwrite").Models.SpecificationList>;
|
14
|
-
export declare const updateFunction: (client: Client,
|
14
|
+
export declare const updateFunction: (client: Client, functionConfig: AppwriteFunction) => Promise<import("node-appwrite").Models.Function>;
|
15
15
|
export declare const createFunctionTemplate: (templateType: "typescript-node" | "poetry" | "count-docs-in-collection", functionName: string, basePath?: string) => Promise<string>;
|
@@ -55,9 +55,9 @@ export const deleteFunction = async (client, functionId) => {
|
|
55
55
|
const functionResponse = await functions.delete(functionId);
|
56
56
|
return functionResponse;
|
57
57
|
};
|
58
|
-
export const createFunction = async (client,
|
58
|
+
export const createFunction = async (client, functionConfig) => {
|
59
59
|
const functions = new Functions(client);
|
60
|
-
const functionResponse = await functions.create(
|
60
|
+
const functionResponse = await functions.create(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, functionConfig.events, functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory, functionConfig.templateRepository, functionConfig.templateOwner, functionConfig.templateRootDirectory, functionConfig.templateVersion, functionConfig.specification);
|
61
61
|
return functionResponse;
|
62
62
|
};
|
63
63
|
export const updateFunctionSpecifications = async (client, functionId, specification) => {
|
@@ -69,7 +69,12 @@ export const updateFunctionSpecifications = async (client, functionId, specifica
|
|
69
69
|
}
|
70
70
|
const functionFound = curFunction.functions[0];
|
71
71
|
try {
|
72
|
-
const functionResponse = await updateFunction(client,
|
72
|
+
const functionResponse = await updateFunction(client, {
|
73
|
+
...functionFound,
|
74
|
+
runtime: functionFound.runtime,
|
75
|
+
scopes: functionFound.scopes,
|
76
|
+
specification: specification,
|
77
|
+
});
|
73
78
|
return functionResponse;
|
74
79
|
}
|
75
80
|
catch (error) {
|
@@ -88,9 +93,9 @@ export const listSpecifications = async (client) => {
|
|
88
93
|
const specifications = await functions.listSpecifications();
|
89
94
|
return specifications;
|
90
95
|
};
|
91
|
-
export const updateFunction = async (client,
|
96
|
+
export const updateFunction = async (client, functionConfig) => {
|
92
97
|
const functions = new Functions(client);
|
93
|
-
const functionResponse = await functions.update(
|
98
|
+
const functionResponse = await functions.update(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, functionConfig.events, functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory, functionConfig.specification);
|
94
99
|
return functionResponse;
|
95
100
|
};
|
96
101
|
export const createFunctionTemplate = async (templateType, functionName, basePath = "./functions") => {
|
package/dist/interactiveCLI.js
CHANGED
@@ -291,17 +291,14 @@ export class InteractiveCLI {
|
|
291
291
|
this.controller.config.functions.push(functionConfig);
|
292
292
|
console.log(chalk.green("✨ Function created successfully!"));
|
293
293
|
}
|
294
|
-
async findFunctionInSubdirectories(
|
294
|
+
async findFunctionInSubdirectories(basePaths, functionName) {
|
295
295
|
// Common locations to check first
|
296
|
-
const commonPaths = [
|
297
|
-
join(
|
298
|
-
join(
|
299
|
-
join(basePath,
|
300
|
-
join(basePath, functionName),
|
301
|
-
|
302
|
-
join(basePath, functionName.toLowerCase().replace(/\s+/g, "")), // appwriteFolder/functionName.toLowerCase().replace(/\s+/g, "")
|
303
|
-
join(process.cwd(), functionName.toLowerCase()), // ./functionName.toLowerCase()
|
304
|
-
];
|
296
|
+
const commonPaths = basePaths.flatMap((basePath) => [
|
297
|
+
join(basePath, "functions", functionName),
|
298
|
+
join(basePath, functionName),
|
299
|
+
join(basePath, functionName.toLowerCase()),
|
300
|
+
join(basePath, functionName.toLowerCase().replace(/\s+/g, "")),
|
301
|
+
]);
|
305
302
|
// Create different variations of the function name for comparison
|
306
303
|
const functionNameVariations = new Set([
|
307
304
|
functionName.toLowerCase(),
|
@@ -324,7 +321,7 @@ export class InteractiveCLI {
|
|
324
321
|
}
|
325
322
|
// If not found in common locations, do recursive search
|
326
323
|
console.log(chalk.yellow("Function not found in common locations, searching subdirectories..."));
|
327
|
-
const queue = [
|
324
|
+
const queue = [...basePaths];
|
328
325
|
const searched = new Set();
|
329
326
|
while (queue.length > 0) {
|
330
327
|
const currentPath = queue.shift();
|
@@ -383,55 +380,77 @@ export class InteractiveCLI {
|
|
383
380
|
if (!this.controller.config.functions) {
|
384
381
|
this.controller.config.functions = [];
|
385
382
|
}
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
383
|
+
const functionNameLower = functionConfig.name
|
384
|
+
.toLowerCase()
|
385
|
+
.replace(/\s+/g, "-");
|
386
|
+
// Check locations in priority order:
|
387
|
+
const priorityLocations = [
|
388
|
+
// 1. Config dirPath if specified
|
389
|
+
functionConfig.dirPath,
|
390
|
+
// 2. Appwrite config folder/functions/name
|
391
|
+
join(this.controller.getAppwriteFolderPath(), "functions", functionNameLower),
|
392
|
+
// 3. Current working directory/functions/name
|
393
|
+
join(process.cwd(), "functions", functionNameLower),
|
394
|
+
// 4. Current working directory/name
|
395
|
+
join(process.cwd(), functionNameLower),
|
396
|
+
].filter((val) => val !== undefined); // Remove undefined entries (in case dirPath is undefined)
|
397
|
+
let functionPath = null;
|
398
|
+
// Check each priority location
|
399
|
+
for (const location of priorityLocations) {
|
400
|
+
if (fs.existsSync(location)) {
|
401
|
+
console.log(chalk.green(`Found function at: ${location}`));
|
402
|
+
functionPath = location;
|
403
|
+
break;
|
393
404
|
}
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
405
|
+
}
|
406
|
+
// If not found in priority locations, do a broader search
|
407
|
+
if (!functionPath) {
|
408
|
+
console.log(chalk.yellow(`Function not found in primary locations, searching subdirectories...`));
|
409
|
+
// Search in both appwrite config directory and current working directory
|
410
|
+
functionPath = await this.findFunctionInSubdirectories([this.controller.getAppwriteFolderPath(), process.cwd()], functionNameLower);
|
411
|
+
}
|
412
|
+
if (!functionPath) {
|
413
|
+
const { shouldDownload } = await inquirer.prompt([
|
414
|
+
{
|
415
|
+
type: "confirm",
|
416
|
+
name: "shouldDownload",
|
417
|
+
message: "Function not found locally. Would you like to download the latest deployment?",
|
418
|
+
default: false,
|
419
|
+
},
|
420
|
+
]);
|
421
|
+
if (shouldDownload) {
|
422
|
+
try {
|
423
|
+
console.log(chalk.blue("Downloading latest deployment..."));
|
424
|
+
const { path: downloadedPath, function: remoteFunction } = await downloadLatestFunctionDeployment(this.controller.appwriteServer, functionConfig.$id, join(this.controller.getAppwriteFolderPath(), "functions"));
|
425
|
+
console.log(chalk.green(`✨ Function downloaded to ${downloadedPath}`));
|
426
|
+
functionPath = downloadedPath;
|
427
|
+
functionConfig.dirPath = downloadedPath;
|
428
|
+
const existingIndex = this.controller.config.functions.findIndex((f) => f?.$id === remoteFunction.$id);
|
429
|
+
if (existingIndex >= 0) {
|
430
|
+
this.controller.config.functions[existingIndex].dirPath =
|
431
|
+
downloadedPath;
|
421
432
|
}
|
433
|
+
await this.controller.reloadConfig();
|
422
434
|
}
|
423
|
-
|
424
|
-
console.
|
435
|
+
catch (error) {
|
436
|
+
console.error(chalk.red("Failed to download function deployment:"), error);
|
425
437
|
return;
|
426
438
|
}
|
427
439
|
}
|
440
|
+
else {
|
441
|
+
console.log(chalk.red(`Function ${functionConfig.name} not found locally. Cannot deploy.`));
|
442
|
+
return;
|
443
|
+
}
|
428
444
|
}
|
429
445
|
if (!this.controller.appwriteServer) {
|
430
446
|
console.log(chalk.red("Appwrite server not initialized"));
|
431
447
|
return;
|
432
448
|
}
|
433
449
|
try {
|
434
|
-
await deployLocalFunction(this.controller.appwriteServer, functionConfig.name,
|
450
|
+
await deployLocalFunction(this.controller.appwriteServer, functionConfig.name, {
|
451
|
+
...functionConfig,
|
452
|
+
dirPath: functionPath,
|
453
|
+
});
|
435
454
|
console.log(chalk.green("✨ Function deployed successfully!"));
|
436
455
|
}
|
437
456
|
catch (error) {
|
@@ -499,7 +518,14 @@ export class InteractiveCLI {
|
|
499
518
|
logging: f.logging !== false,
|
500
519
|
entrypoint: f.entrypoint || "src/index.ts",
|
501
520
|
commands: f.commands || "npm install",
|
521
|
+
scopes: f.scopes || [], // Add scopes
|
502
522
|
path: f.dirPath || `functions/${f.name}`,
|
523
|
+
dirPath: f.dirPath, // Preserve original dirPath
|
524
|
+
installationId: f.installationId || "",
|
525
|
+
providerRepositoryId: f.providerRepositoryId || "",
|
526
|
+
providerBranch: f.providerBranch || "",
|
527
|
+
providerSilentMode: f.providerSilentMode || false,
|
528
|
+
providerRootDirectory: f.providerRootDirectory || "",
|
503
529
|
...(f.specification ? { specification: f.specification } : {}),
|
504
530
|
...(f.predeployCommands
|
505
531
|
? { predeployCommands: f.predeployCommands }
|
@@ -808,7 +834,7 @@ export class InteractiveCLI {
|
|
808
834
|
let functionPath = join(this.controller.getAppwriteFolderPath(), "functions", func.name);
|
809
835
|
if (!fs.existsSync(functionPath)) {
|
810
836
|
console.log(chalk.yellow(`Function not found in primary location, searching subdirectories...`));
|
811
|
-
const foundPath = await this.findFunctionInSubdirectories(this.controller.getAppwriteFolderPath(), func.name);
|
837
|
+
const foundPath = await this.findFunctionInSubdirectories([this.controller.getAppwriteFolderPath(), process.cwd()], func.name);
|
812
838
|
if (foundPath) {
|
813
839
|
console.log(chalk.green(`Found function at: ${foundPath}`));
|
814
840
|
functionPath = foundPath;
|
@@ -876,7 +902,7 @@ export class InteractiveCLI {
|
|
876
902
|
// Similar check for local-only functions
|
877
903
|
let functionPath = join(this.controller.getAppwriteFolderPath(), "functions", func.name);
|
878
904
|
if (!fs.existsSync(functionPath)) {
|
879
|
-
const foundPath = await this.findFunctionInSubdirectories(this.controller.getAppwriteFolderPath(), func.name);
|
905
|
+
const foundPath = await this.findFunctionInSubdirectories([this.controller.getAppwriteFolderPath(), process.cwd()], func.name);
|
880
906
|
if (foundPath) {
|
881
907
|
functionPath = foundPath;
|
882
908
|
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "appwrite-utils-cli",
|
3
3
|
"description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
|
4
|
-
"version": "0.10.
|
4
|
+
"version": "0.10.64",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -31,7 +31,7 @@
|
|
31
31
|
},
|
32
32
|
"dependencies": {
|
33
33
|
"@types/inquirer": "^9.0.7",
|
34
|
-
"appwrite-utils": "^0.3.
|
34
|
+
"appwrite-utils": "^0.3.99",
|
35
35
|
"chalk": "^5.3.0",
|
36
36
|
"cli-progress": "^3.12.0",
|
37
37
|
"commander": "^12.1.0",
|
@@ -57,6 +57,18 @@ export const deployFunction = async (
|
|
57
57
|
|
58
58
|
const tarPath = join(process.cwd(), `function-${functionId}.tar.gz`);
|
59
59
|
|
60
|
+
// Verify codePath exists and is a directory
|
61
|
+
if (!fs.existsSync(codePath)) {
|
62
|
+
throw new Error(`Function directory not found at ${codePath}`);
|
63
|
+
}
|
64
|
+
|
65
|
+
const stats = await fs.promises.stat(codePath);
|
66
|
+
if (!stats.isDirectory()) {
|
67
|
+
throw new Error(`${codePath} is not a directory`);
|
68
|
+
}
|
69
|
+
|
70
|
+
console.log(chalk.blue(`Creating tarball from ${codePath}`));
|
71
|
+
|
60
72
|
const progressBar = new cliProgress.SingleBar({
|
61
73
|
format:
|
62
74
|
"Uploading |" +
|
@@ -77,14 +89,22 @@ export const deployFunction = async (
|
|
77
89
|
codePath,
|
78
90
|
join(codePath, path)
|
79
91
|
).toLowerCase();
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
92
|
+
// Skip if path matches any ignored pattern
|
93
|
+
if (
|
94
|
+
ignoredLower.some(
|
95
|
+
(pattern) =>
|
96
|
+
relativePath.startsWith(pattern) ||
|
97
|
+
relativePath.includes(`/${pattern}`) ||
|
98
|
+
relativePath.includes(`\\${pattern}`)
|
99
|
+
)
|
100
|
+
) {
|
101
|
+
console.log(chalk.gray(`Ignoring ${path}`));
|
102
|
+
return false;
|
103
|
+
}
|
104
|
+
return true;
|
85
105
|
},
|
86
106
|
},
|
87
|
-
["."]
|
107
|
+
["."] // This now only includes contents of codePath since we set cwd to codePath
|
88
108
|
);
|
89
109
|
|
90
110
|
const fileBuffer = await fs.promises.readFile(tarPath);
|
@@ -194,54 +214,10 @@ export const deployLocalFunction = async (
|
|
194
214
|
|
195
215
|
// Only create function if it doesn't exist
|
196
216
|
if (!functionExists) {
|
197
|
-
await createFunction(
|
198
|
-
client,
|
199
|
-
functionConfig.$id,
|
200
|
-
functionConfig.name,
|
201
|
-
functionConfig.runtime as Runtime,
|
202
|
-
functionConfig.execute,
|
203
|
-
functionConfig.events,
|
204
|
-
functionConfig.schedule,
|
205
|
-
functionConfig.timeout,
|
206
|
-
functionConfig.enabled,
|
207
|
-
functionConfig.logging,
|
208
|
-
functionConfig.entrypoint,
|
209
|
-
functionConfig.commands,
|
210
|
-
functionConfig.scopes,
|
211
|
-
functionConfig.installationId,
|
212
|
-
functionConfig.providerRepositoryId,
|
213
|
-
functionConfig.providerBranch,
|
214
|
-
functionConfig.providerSilentMode,
|
215
|
-
functionConfig.providerRootDirectory,
|
216
|
-
functionConfig.templateRepository,
|
217
|
-
functionConfig.templateOwner,
|
218
|
-
functionConfig.templateRootDirectory,
|
219
|
-
functionConfig.templateVersion,
|
220
|
-
functionConfig.specification
|
221
|
-
);
|
217
|
+
await createFunction(client, functionConfig);
|
222
218
|
} else {
|
223
219
|
console.log(chalk.blue("Updating function..."));
|
224
|
-
await updateFunction(
|
225
|
-
client,
|
226
|
-
functionConfig.$id,
|
227
|
-
functionConfig.name,
|
228
|
-
functionConfig.runtime as Runtime,
|
229
|
-
functionConfig.execute,
|
230
|
-
functionConfig.events,
|
231
|
-
functionConfig.schedule,
|
232
|
-
functionConfig.timeout,
|
233
|
-
functionConfig.enabled,
|
234
|
-
functionConfig.logging,
|
235
|
-
functionConfig.entrypoint,
|
236
|
-
functionConfig.commands,
|
237
|
-
functionConfig.scopes,
|
238
|
-
functionConfig.installationId,
|
239
|
-
functionConfig.providerRepositoryId,
|
240
|
-
functionConfig.providerBranch,
|
241
|
-
functionConfig.providerSilentMode,
|
242
|
-
functionConfig.providerRootDirectory,
|
243
|
-
functionConfig.specification
|
244
|
-
);
|
220
|
+
await updateFunction(client, functionConfig);
|
245
221
|
}
|
246
222
|
|
247
223
|
const deployPath = functionConfig.deployDir
|
package/src/functions/methods.ts
CHANGED
@@ -7,7 +7,11 @@ import {
|
|
7
7
|
} from "node-appwrite";
|
8
8
|
import { join } from "node:path";
|
9
9
|
import fs from "node:fs";
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
type AppwriteFunction,
|
12
|
+
type FunctionScope,
|
13
|
+
type Specification,
|
14
|
+
} from "appwrite-utils";
|
11
15
|
import chalk from "chalk";
|
12
16
|
import { extract as extractTar } from "tar";
|
13
17
|
|
@@ -87,53 +91,32 @@ export const deleteFunction = async (client: Client, functionId: string) => {
|
|
87
91
|
|
88
92
|
export const createFunction = async (
|
89
93
|
client: Client,
|
90
|
-
|
91
|
-
name: string,
|
92
|
-
runtime: Runtime,
|
93
|
-
execute?: string[],
|
94
|
-
events?: string[],
|
95
|
-
schedule?: string,
|
96
|
-
timeout?: number,
|
97
|
-
enabled?: boolean,
|
98
|
-
logging?: boolean,
|
99
|
-
entrypoint?: string,
|
100
|
-
commands?: string,
|
101
|
-
scopes?: string[],
|
102
|
-
installationId?: string,
|
103
|
-
providerRepositoryId?: string,
|
104
|
-
providerBranch?: string,
|
105
|
-
providerSilentMode?: boolean,
|
106
|
-
providerRootDirectory?: string,
|
107
|
-
templateRepository?: string,
|
108
|
-
templateOwner?: string,
|
109
|
-
templateRootDirectory?: string,
|
110
|
-
templateVersion?: string,
|
111
|
-
specification?: string
|
94
|
+
functionConfig: AppwriteFunction
|
112
95
|
) => {
|
113
96
|
const functions = new Functions(client);
|
114
97
|
const functionResponse = await functions.create(
|
115
|
-
|
116
|
-
name,
|
117
|
-
runtime,
|
118
|
-
execute,
|
119
|
-
events,
|
120
|
-
schedule,
|
121
|
-
timeout,
|
122
|
-
enabled,
|
123
|
-
logging,
|
124
|
-
entrypoint,
|
125
|
-
commands,
|
126
|
-
scopes,
|
127
|
-
installationId,
|
128
|
-
providerRepositoryId,
|
129
|
-
providerBranch,
|
130
|
-
providerSilentMode,
|
131
|
-
providerRootDirectory,
|
132
|
-
templateRepository,
|
133
|
-
templateOwner,
|
134
|
-
templateRootDirectory,
|
135
|
-
templateVersion,
|
136
|
-
specification
|
98
|
+
functionConfig.$id,
|
99
|
+
functionConfig.name,
|
100
|
+
functionConfig.runtime as Runtime,
|
101
|
+
functionConfig.execute,
|
102
|
+
functionConfig.events,
|
103
|
+
functionConfig.schedule,
|
104
|
+
functionConfig.timeout,
|
105
|
+
functionConfig.enabled,
|
106
|
+
functionConfig.logging,
|
107
|
+
functionConfig.entrypoint,
|
108
|
+
functionConfig.commands,
|
109
|
+
functionConfig.scopes,
|
110
|
+
functionConfig.installationId,
|
111
|
+
functionConfig.providerRepositoryId,
|
112
|
+
functionConfig.providerBranch,
|
113
|
+
functionConfig.providerSilentMode,
|
114
|
+
functionConfig.providerRootDirectory,
|
115
|
+
functionConfig.templateRepository,
|
116
|
+
functionConfig.templateOwner,
|
117
|
+
functionConfig.templateRootDirectory,
|
118
|
+
functionConfig.templateVersion,
|
119
|
+
functionConfig.specification
|
137
120
|
);
|
138
121
|
return functionResponse;
|
139
122
|
};
|
@@ -151,27 +134,12 @@ export const updateFunctionSpecifications = async (
|
|
151
134
|
}
|
152
135
|
const functionFound = curFunction.functions[0];
|
153
136
|
try {
|
154
|
-
const functionResponse = await updateFunction(
|
155
|
-
|
156
|
-
|
157
|
-
functionFound.
|
158
|
-
|
159
|
-
|
160
|
-
functionFound.events,
|
161
|
-
functionFound.schedule,
|
162
|
-
functionFound.timeout,
|
163
|
-
functionFound.enabled,
|
164
|
-
functionFound.logging,
|
165
|
-
functionFound.entrypoint,
|
166
|
-
functionFound.commands,
|
167
|
-
functionFound.scopes,
|
168
|
-
functionFound.installationId,
|
169
|
-
functionFound.providerRepositoryId,
|
170
|
-
functionFound.providerBranch,
|
171
|
-
functionFound.providerSilentMode,
|
172
|
-
functionFound.providerRootDirectory,
|
173
|
-
specification
|
174
|
-
);
|
137
|
+
const functionResponse = await updateFunction(client, {
|
138
|
+
...functionFound,
|
139
|
+
runtime: functionFound.runtime as Runtime,
|
140
|
+
scopes: functionFound.scopes as FunctionScope[],
|
141
|
+
specification: specification,
|
142
|
+
});
|
175
143
|
return functionResponse;
|
176
144
|
} catch (error) {
|
177
145
|
if (
|
@@ -198,45 +166,28 @@ export const listSpecifications = async (client: Client) => {
|
|
198
166
|
|
199
167
|
export const updateFunction = async (
|
200
168
|
client: Client,
|
201
|
-
|
202
|
-
name: string,
|
203
|
-
runtime?: Runtime,
|
204
|
-
execute?: string[],
|
205
|
-
events?: string[],
|
206
|
-
schedule?: string,
|
207
|
-
timeout?: number,
|
208
|
-
enabled?: boolean,
|
209
|
-
logging?: boolean,
|
210
|
-
entrypoint?: string,
|
211
|
-
commands?: string,
|
212
|
-
scopes?: string[],
|
213
|
-
installationId?: string,
|
214
|
-
providerRepositoryId?: string,
|
215
|
-
providerBranch?: string,
|
216
|
-
providerSilentMode?: boolean,
|
217
|
-
providerRootDirectory?: string,
|
218
|
-
specification?: Specification
|
169
|
+
functionConfig: AppwriteFunction
|
219
170
|
) => {
|
220
171
|
const functions = new Functions(client);
|
221
172
|
const functionResponse = await functions.update(
|
222
|
-
|
223
|
-
name,
|
224
|
-
runtime,
|
225
|
-
execute,
|
226
|
-
events,
|
227
|
-
schedule,
|
228
|
-
timeout,
|
229
|
-
enabled,
|
230
|
-
logging,
|
231
|
-
entrypoint,
|
232
|
-
commands,
|
233
|
-
scopes,
|
234
|
-
installationId,
|
235
|
-
providerRepositoryId,
|
236
|
-
providerBranch,
|
237
|
-
providerSilentMode,
|
238
|
-
providerRootDirectory,
|
239
|
-
specification
|
173
|
+
functionConfig.$id,
|
174
|
+
functionConfig.name,
|
175
|
+
functionConfig.runtime as Runtime,
|
176
|
+
functionConfig.execute,
|
177
|
+
functionConfig.events,
|
178
|
+
functionConfig.schedule,
|
179
|
+
functionConfig.timeout,
|
180
|
+
functionConfig.enabled,
|
181
|
+
functionConfig.logging,
|
182
|
+
functionConfig.entrypoint,
|
183
|
+
functionConfig.commands,
|
184
|
+
functionConfig.scopes,
|
185
|
+
functionConfig.installationId,
|
186
|
+
functionConfig.providerRepositoryId,
|
187
|
+
functionConfig.providerBranch,
|
188
|
+
functionConfig.providerSilentMode,
|
189
|
+
functionConfig.providerRootDirectory,
|
190
|
+
functionConfig.specification
|
240
191
|
);
|
241
192
|
return functionResponse;
|
242
193
|
};
|
package/src/interactiveCLI.ts
CHANGED
@@ -389,19 +389,16 @@ export class InteractiveCLI {
|
|
389
389
|
}
|
390
390
|
|
391
391
|
private async findFunctionInSubdirectories(
|
392
|
-
|
392
|
+
basePaths: string[],
|
393
393
|
functionName: string
|
394
394
|
): Promise<string | null> {
|
395
395
|
// Common locations to check first
|
396
|
-
const commonPaths = [
|
397
|
-
join(
|
398
|
-
join(
|
399
|
-
join(basePath,
|
400
|
-
join(basePath, functionName),
|
401
|
-
|
402
|
-
join(basePath, functionName.toLowerCase().replace(/\s+/g, "")), // appwriteFolder/functionName.toLowerCase().replace(/\s+/g, "")
|
403
|
-
join(process.cwd(), functionName.toLowerCase()), // ./functionName.toLowerCase()
|
404
|
-
];
|
396
|
+
const commonPaths = basePaths.flatMap((basePath) => [
|
397
|
+
join(basePath, "functions", functionName),
|
398
|
+
join(basePath, functionName),
|
399
|
+
join(basePath, functionName.toLowerCase()),
|
400
|
+
join(basePath, functionName.toLowerCase().replace(/\s+/g, "")),
|
401
|
+
]);
|
405
402
|
|
406
403
|
// Create different variations of the function name for comparison
|
407
404
|
const functionNameVariations = new Set([
|
@@ -433,7 +430,7 @@ export class InteractiveCLI {
|
|
433
430
|
)
|
434
431
|
);
|
435
432
|
|
436
|
-
const queue = [
|
433
|
+
const queue = [...basePaths];
|
437
434
|
const searched = new Set<string>();
|
438
435
|
|
439
436
|
while (queue.length > 0) {
|
@@ -515,78 +512,103 @@ export class InteractiveCLI {
|
|
515
512
|
this.controller.config.functions = [];
|
516
513
|
}
|
517
514
|
|
518
|
-
|
519
|
-
|
520
|
-
"
|
521
|
-
|
522
|
-
|
515
|
+
const functionNameLower = functionConfig.name
|
516
|
+
.toLowerCase()
|
517
|
+
.replace(/\s+/g, "-");
|
518
|
+
|
519
|
+
// Check locations in priority order:
|
520
|
+
const priorityLocations = [
|
521
|
+
// 1. Config dirPath if specified
|
522
|
+
functionConfig.dirPath,
|
523
|
+
// 2. Appwrite config folder/functions/name
|
524
|
+
join(
|
525
|
+
this.controller.getAppwriteFolderPath(),
|
526
|
+
"functions",
|
527
|
+
functionNameLower
|
528
|
+
),
|
529
|
+
// 3. Current working directory/functions/name
|
530
|
+
join(process.cwd(), "functions", functionNameLower),
|
531
|
+
// 4. Current working directory/name
|
532
|
+
join(process.cwd(), functionNameLower),
|
533
|
+
].filter((val): val is string => val !== undefined); // Remove undefined entries (in case dirPath is undefined)
|
534
|
+
|
535
|
+
let functionPath: string | null = null;
|
536
|
+
|
537
|
+
// Check each priority location
|
538
|
+
for (const location of priorityLocations) {
|
539
|
+
if (fs.existsSync(location)) {
|
540
|
+
console.log(chalk.green(`Found function at: ${location}`));
|
541
|
+
functionPath = location;
|
542
|
+
break;
|
543
|
+
}
|
544
|
+
}
|
523
545
|
|
524
|
-
|
546
|
+
// If not found in priority locations, do a broader search
|
547
|
+
if (!functionPath) {
|
525
548
|
console.log(
|
526
549
|
chalk.yellow(
|
527
|
-
`Function not found in primary
|
550
|
+
`Function not found in primary locations, searching subdirectories...`
|
528
551
|
)
|
529
552
|
);
|
530
|
-
|
531
|
-
|
532
|
-
|
553
|
+
|
554
|
+
// Search in both appwrite config directory and current working directory
|
555
|
+
functionPath = await this.findFunctionInSubdirectories(
|
556
|
+
[this.controller.getAppwriteFolderPath(), process.cwd()],
|
557
|
+
functionNameLower
|
533
558
|
);
|
559
|
+
}
|
534
560
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
default: false,
|
546
|
-
},
|
547
|
-
]);
|
561
|
+
if (!functionPath) {
|
562
|
+
const { shouldDownload } = await inquirer.prompt([
|
563
|
+
{
|
564
|
+
type: "confirm",
|
565
|
+
name: "shouldDownload",
|
566
|
+
message:
|
567
|
+
"Function not found locally. Would you like to download the latest deployment?",
|
568
|
+
default: false,
|
569
|
+
},
|
570
|
+
]);
|
548
571
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
);
|
558
|
-
console.log(
|
559
|
-
chalk.green(`✨ Function downloaded to ${downloadedPath}`)
|
572
|
+
if (shouldDownload) {
|
573
|
+
try {
|
574
|
+
console.log(chalk.blue("Downloading latest deployment..."));
|
575
|
+
const { path: downloadedPath, function: remoteFunction } =
|
576
|
+
await downloadLatestFunctionDeployment(
|
577
|
+
this.controller.appwriteServer!,
|
578
|
+
functionConfig.$id,
|
579
|
+
join(this.controller.getAppwriteFolderPath(), "functions")
|
560
580
|
);
|
581
|
+
console.log(
|
582
|
+
chalk.green(`✨ Function downloaded to ${downloadedPath}`)
|
583
|
+
);
|
561
584
|
|
562
|
-
|
563
|
-
|
564
|
-
);
|
585
|
+
functionPath = downloadedPath;
|
586
|
+
functionConfig.dirPath = downloadedPath;
|
565
587
|
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
functionConfig.dirPath = downloadedPath;
|
574
|
-
functionPath = downloadedPath;
|
575
|
-
} catch (error) {
|
576
|
-
console.error(
|
577
|
-
chalk.red("Failed to download function deployment:"),
|
578
|
-
error
|
579
|
-
);
|
580
|
-
return;
|
588
|
+
const existingIndex = this.controller.config.functions.findIndex(
|
589
|
+
(f) => f?.$id === remoteFunction.$id
|
590
|
+
);
|
591
|
+
|
592
|
+
if (existingIndex >= 0) {
|
593
|
+
this.controller.config.functions[existingIndex].dirPath =
|
594
|
+
downloadedPath;
|
581
595
|
}
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
)
|
596
|
+
|
597
|
+
await this.controller.reloadConfig();
|
598
|
+
} catch (error) {
|
599
|
+
console.error(
|
600
|
+
chalk.red("Failed to download function deployment:"),
|
601
|
+
error
|
587
602
|
);
|
588
603
|
return;
|
589
604
|
}
|
605
|
+
} else {
|
606
|
+
console.log(
|
607
|
+
chalk.red(
|
608
|
+
`Function ${functionConfig.name} not found locally. Cannot deploy.`
|
609
|
+
)
|
610
|
+
);
|
611
|
+
return;
|
590
612
|
}
|
591
613
|
}
|
592
614
|
|
@@ -599,7 +621,10 @@ export class InteractiveCLI {
|
|
599
621
|
await deployLocalFunction(
|
600
622
|
this.controller.appwriteServer,
|
601
623
|
functionConfig.name,
|
602
|
-
|
624
|
+
{
|
625
|
+
...functionConfig,
|
626
|
+
dirPath: functionPath,
|
627
|
+
}
|
603
628
|
);
|
604
629
|
console.log(chalk.green("✨ Function deployed successfully!"));
|
605
630
|
} catch (error) {
|
@@ -691,7 +716,14 @@ export class InteractiveCLI {
|
|
691
716
|
logging: f.logging !== false,
|
692
717
|
entrypoint: f.entrypoint || "src/index.ts",
|
693
718
|
commands: f.commands || "npm install",
|
719
|
+
scopes: f.scopes || [], // Add scopes
|
694
720
|
path: f.dirPath || `functions/${f.name}`,
|
721
|
+
dirPath: f.dirPath, // Preserve original dirPath
|
722
|
+
installationId: f.installationId || "",
|
723
|
+
providerRepositoryId: f.providerRepositoryId || "",
|
724
|
+
providerBranch: f.providerBranch || "",
|
725
|
+
providerSilentMode: f.providerSilentMode || false,
|
726
|
+
providerRootDirectory: f.providerRootDirectory || "",
|
695
727
|
...(f.specification ? { specification: f.specification } : {}),
|
696
728
|
...(f.predeployCommands
|
697
729
|
? { predeployCommands: f.predeployCommands }
|
@@ -1119,7 +1151,7 @@ export class InteractiveCLI {
|
|
1119
1151
|
)
|
1120
1152
|
);
|
1121
1153
|
const foundPath = await this.findFunctionInSubdirectories(
|
1122
|
-
this.controller!.getAppwriteFolderPath(),
|
1154
|
+
[this.controller!.getAppwriteFolderPath(), process.cwd()],
|
1123
1155
|
func.name
|
1124
1156
|
);
|
1125
1157
|
|
@@ -1210,7 +1242,7 @@ export class InteractiveCLI {
|
|
1210
1242
|
|
1211
1243
|
if (!fs.existsSync(functionPath)) {
|
1212
1244
|
const foundPath = await this.findFunctionInSubdirectories(
|
1213
|
-
this.controller!.getAppwriteFolderPath(),
|
1245
|
+
[this.controller!.getAppwriteFolderPath(), process.cwd()],
|
1214
1246
|
func.name
|
1215
1247
|
);
|
1216
1248
|
|