appwrite-utils-cli 0.10.62 → 0.10.63

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 CHANGED
@@ -147,6 +147,7 @@ This updated CLI ensures that developers have robust tools at their fingertips t
147
147
 
148
148
  ## Changelog
149
149
 
150
+ - 0.10.63: My `collectLocalFunctions` function was failing to add the `scopes` and a few others to the function, accidentally, fixed now
150
151
  - 0.10.62: Made `Deploy Function(s)` also update the functions, as not all things (timeout, specification, etc.) are updated via deploy
151
152
  - 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
153
  - 0.10.051: Added `node_modules` and a few others to the ignore
@@ -127,11 +127,11 @@ export const deployLocalFunction = async (client, functionName, functionConfig,
127
127
  }
128
128
  // Only create function if it doesn't exist
129
129
  if (!functionExists) {
130
- await createFunction(client, 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);
130
+ await createFunction(client, functionConfig);
131
131
  }
132
132
  else {
133
133
  console.log(chalk.blue("Updating function..."));
134
- await updateFunction(client, 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);
134
+ await updateFunction(client, functionConfig);
135
135
  }
136
136
  const deployPath = functionConfig.deployDir
137
137
  ? join(resolvedPath, functionConfig.deployDir)
@@ -1,5 +1,5 @@
1
- import { Client, Runtime } from "node-appwrite";
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, functionId: string, name: string, runtime: Runtime, execute?: string[], events?: string[], schedule?: string, timeout?: number, enabled?: boolean, logging?: boolean, entrypoint?: string, commands?: string, scopes?: string[], installationId?: string, providerRepositoryId?: string, providerBranch?: string, providerSilentMode?: boolean, providerRootDirectory?: string, templateRepository?: string, templateOwner?: string, templateRootDirectory?: string, templateVersion?: string, specification?: string) => Promise<import("node-appwrite").Models.Function>;
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, functionId: string, name: string, runtime?: Runtime, execute?: string[], events?: string[], schedule?: string, timeout?: number, enabled?: boolean, logging?: boolean, entrypoint?: string, commands?: string, scopes?: string[], installationId?: string, providerRepositoryId?: string, providerBranch?: string, providerSilentMode?: boolean, providerRootDirectory?: string, specification?: Specification) => Promise<import("node-appwrite").Models.Function>;
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, functionId, name, runtime, execute, events, schedule, timeout, enabled, logging, entrypoint, commands, scopes, installationId, providerRepositoryId, providerBranch, providerSilentMode, providerRootDirectory, templateRepository, templateOwner, templateRootDirectory, templateVersion, specification) => {
58
+ export const createFunction = async (client, functionConfig) => {
59
59
  const functions = new Functions(client);
60
- const functionResponse = await functions.create(functionId, name, runtime, execute, events, schedule, timeout, enabled, logging, entrypoint, commands, scopes, installationId, providerRepositoryId, providerBranch, providerSilentMode, providerRootDirectory, templateRepository, templateOwner, templateRootDirectory, templateVersion, specification);
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, functionId, functionFound.name, functionFound.runtime, functionFound.execute, functionFound.events, functionFound.schedule, functionFound.timeout, functionFound.enabled, functionFound.logging, functionFound.entrypoint, functionFound.commands, functionFound.scopes, functionFound.installationId, functionFound.providerRepositoryId, functionFound.providerBranch, functionFound.providerSilentMode, functionFound.providerRootDirectory, specification);
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, functionId, name, runtime, execute, events, schedule, timeout, enabled, logging, entrypoint, commands, scopes, installationId, providerRepositoryId, providerBranch, providerSilentMode, providerRootDirectory, specification) => {
96
+ export const updateFunction = async (client, functionConfig) => {
92
97
  const functions = new Functions(client);
93
- const functionResponse = await functions.update(functionId, name, runtime, execute, events, schedule, timeout, enabled, logging, entrypoint, commands, scopes, installationId, providerRepositoryId, providerBranch, providerSilentMode, providerRootDirectory, specification);
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") => {
@@ -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(basePath, functionName) {
294
+ async findFunctionInSubdirectories(basePaths, functionName) {
295
295
  // Common locations to check first
296
- const commonPaths = [
297
- join(process.cwd(), "functions", functionName), // ./functions/functionName
298
- join(process.cwd(), functionName), // ./functionName
299
- join(basePath, "functions", functionName), // appwriteFolder/functions/functionName
300
- join(basePath, functionName), // appwriteFolder/functionName
301
- join(basePath, functionName.toLowerCase()), // appwriteFolder/functionName.toLowerCase()
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 = [process.cwd(), basePath];
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
- let functionPath = join(this.controller.getAppwriteFolderPath(), "functions", functionConfig.name);
387
- if (!fs.existsSync(functionPath)) {
388
- console.log(chalk.yellow(`Function not found in primary location, searching subdirectories...`));
389
- const foundPath = await this.findFunctionInSubdirectories(this.controller.getAppwriteFolderPath(), functionConfig.name.toLowerCase());
390
- if (foundPath) {
391
- functionPath = foundPath;
392
- functionConfig.dirPath = foundPath;
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
- else {
395
- const { shouldDownload } = await inquirer.prompt([
396
- {
397
- type: "confirm",
398
- name: "shouldDownload",
399
- message: "Function not found locally. Would you like to download the latest deployment?",
400
- default: false,
401
- },
402
- ]);
403
- if (shouldDownload) {
404
- try {
405
- console.log(chalk.blue("Downloading latest deployment..."));
406
- const { path: downloadedPath, function: remoteFunction } = await downloadLatestFunctionDeployment(this.controller.appwriteServer, functionConfig.$id, join(this.controller.getAppwriteFolderPath(), "functions"));
407
- console.log(chalk.green(`✨ Function downloaded to ${downloadedPath}`));
408
- const existingIndex = this.controller.config.functions.findIndex((f) => f?.$id === remoteFunction.$id);
409
- if (existingIndex >= 0) {
410
- // Only update the dirPath if function exists
411
- this.controller.config.functions[existingIndex].dirPath =
412
- downloadedPath;
413
- }
414
- await this.controller.reloadConfig();
415
- functionConfig.dirPath = downloadedPath;
416
- functionPath = downloadedPath;
417
- }
418
- catch (error) {
419
- console.error(chalk.red("Failed to download function deployment:"), error);
420
- return;
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
- else {
424
- console.log(chalk.red(`Function ${functionConfig.name} not found locally. Cannot deploy.`));
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, functionConfig);
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.62",
4
+ "version": "0.10.63",
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.98",
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",
@@ -194,54 +194,10 @@ export const deployLocalFunction = async (
194
194
 
195
195
  // Only create function if it doesn't exist
196
196
  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
- );
197
+ await createFunction(client, functionConfig);
222
198
  } else {
223
199
  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
- );
200
+ await updateFunction(client, functionConfig);
245
201
  }
246
202
 
247
203
  const deployPath = functionConfig.deployDir
@@ -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 { type Specification } from "appwrite-utils";
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
- functionId: string,
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
- functionId,
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
- client,
156
- functionId,
157
- functionFound.name,
158
- functionFound.runtime as Runtime,
159
- functionFound.execute,
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
- functionId: string,
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
- functionId,
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
  };
@@ -389,19 +389,16 @@ export class InteractiveCLI {
389
389
  }
390
390
 
391
391
  private async findFunctionInSubdirectories(
392
- basePath: string,
392
+ basePaths: string[],
393
393
  functionName: string
394
394
  ): Promise<string | null> {
395
395
  // Common locations to check first
396
- const commonPaths = [
397
- join(process.cwd(), "functions", functionName), // ./functions/functionName
398
- join(process.cwd(), functionName), // ./functionName
399
- join(basePath, "functions", functionName), // appwriteFolder/functions/functionName
400
- join(basePath, functionName), // appwriteFolder/functionName
401
- join(basePath, functionName.toLowerCase()), // appwriteFolder/functionName.toLowerCase()
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 = [process.cwd(), basePath];
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
- let functionPath = join(
519
- this.controller.getAppwriteFolderPath(),
520
- "functions",
521
- functionConfig.name
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
- if (!fs.existsSync(functionPath)) {
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 location, searching subdirectories...`
550
+ `Function not found in primary locations, searching subdirectories...`
528
551
  )
529
552
  );
530
- const foundPath = await this.findFunctionInSubdirectories(
531
- this.controller.getAppwriteFolderPath(),
532
- functionConfig.name.toLowerCase()
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
- if (foundPath) {
536
- functionPath = foundPath;
537
- functionConfig.dirPath = foundPath;
538
- } else {
539
- const { shouldDownload } = await inquirer.prompt([
540
- {
541
- type: "confirm",
542
- name: "shouldDownload",
543
- message:
544
- "Function not found locally. Would you like to download the latest deployment?",
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
- if (shouldDownload) {
550
- try {
551
- console.log(chalk.blue("Downloading latest deployment..."));
552
- const { path: downloadedPath, function: remoteFunction } =
553
- await downloadLatestFunctionDeployment(
554
- this.controller.appwriteServer!,
555
- functionConfig.$id,
556
- join(this.controller.getAppwriteFolderPath(), "functions")
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
- const existingIndex = this.controller.config.functions.findIndex(
563
- (f) => f?.$id === remoteFunction.$id
564
- );
585
+ functionPath = downloadedPath;
586
+ functionConfig.dirPath = downloadedPath;
565
587
 
566
- if (existingIndex >= 0) {
567
- // Only update the dirPath if function exists
568
- this.controller.config.functions[existingIndex].dirPath =
569
- downloadedPath;
570
- }
571
-
572
- await this.controller.reloadConfig();
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
- } else {
583
- console.log(
584
- chalk.red(
585
- `Function ${functionConfig.name} not found locally. Cannot deploy.`
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
- functionConfig
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