appwrite-utils-cli 1.5.2 → 1.6.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 (233) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +251 -29
  3. package/dist/adapters/AdapterFactory.d.ts +10 -3
  4. package/dist/adapters/AdapterFactory.js +213 -17
  5. package/dist/adapters/TablesDBAdapter.js +60 -17
  6. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  7. package/dist/backups/operations/bucketBackup.js +197 -0
  8. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  9. package/dist/backups/operations/collectionBackup.js +201 -0
  10. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  11. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  12. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  13. package/dist/backups/schemas/bucketManifest.js +33 -0
  14. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  15. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  16. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  17. package/dist/backups/tracking/centralizedTracking.js +274 -0
  18. package/dist/cli/commands/configCommands.d.ts +8 -0
  19. package/dist/cli/commands/configCommands.js +160 -0
  20. package/dist/cli/commands/databaseCommands.d.ts +13 -0
  21. package/dist/cli/commands/databaseCommands.js +479 -0
  22. package/dist/cli/commands/functionCommands.d.ts +7 -0
  23. package/dist/cli/commands/functionCommands.js +289 -0
  24. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  25. package/dist/cli/commands/schemaCommands.js +134 -0
  26. package/dist/cli/commands/transferCommands.d.ts +5 -0
  27. package/dist/cli/commands/transferCommands.js +384 -0
  28. package/dist/collections/attributes.d.ts +5 -4
  29. package/dist/collections/attributes.js +539 -246
  30. package/dist/collections/indexes.js +39 -37
  31. package/dist/collections/methods.d.ts +2 -16
  32. package/dist/collections/methods.js +90 -538
  33. package/dist/collections/transferOperations.d.ts +7 -0
  34. package/dist/collections/transferOperations.js +331 -0
  35. package/dist/collections/wipeOperations.d.ts +16 -0
  36. package/dist/collections/wipeOperations.js +328 -0
  37. package/dist/config/configMigration.d.ts +87 -0
  38. package/dist/config/configMigration.js +390 -0
  39. package/dist/config/configValidation.d.ts +66 -0
  40. package/dist/config/configValidation.js +358 -0
  41. package/dist/config/yamlConfig.d.ts +455 -1
  42. package/dist/config/yamlConfig.js +145 -52
  43. package/dist/databases/methods.js +3 -2
  44. package/dist/databases/setup.d.ts +1 -2
  45. package/dist/databases/setup.js +9 -87
  46. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  47. package/dist/examples/yamlTerminologyExample.js +269 -0
  48. package/dist/functions/deployments.js +11 -10
  49. package/dist/functions/methods.d.ts +1 -1
  50. package/dist/functions/methods.js +5 -4
  51. package/dist/init.js +9 -9
  52. package/dist/interactiveCLI.d.ts +8 -17
  53. package/dist/interactiveCLI.js +209 -1172
  54. package/dist/main.js +364 -21
  55. package/dist/migrations/afterImportActions.js +22 -30
  56. package/dist/migrations/appwriteToX.js +71 -25
  57. package/dist/migrations/dataLoader.js +35 -26
  58. package/dist/migrations/importController.js +29 -30
  59. package/dist/migrations/relationships.js +13 -12
  60. package/dist/migrations/services/ImportOrchestrator.js +16 -19
  61. package/dist/migrations/transfer.js +46 -46
  62. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
  63. package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
  64. package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
  65. package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
  66. package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
  67. package/dist/migrations/yaml/generateImportSchemas.js +736 -7
  68. package/dist/schemas/authUser.d.ts +1 -1
  69. package/dist/setupController.js +3 -2
  70. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  71. package/dist/shared/backupMetadataSchema.js +38 -0
  72. package/dist/shared/backupTracking.d.ts +18 -0
  73. package/dist/shared/backupTracking.js +176 -0
  74. package/dist/shared/confirmationDialogs.js +15 -15
  75. package/dist/shared/errorUtils.d.ts +54 -0
  76. package/dist/shared/errorUtils.js +95 -0
  77. package/dist/shared/functionManager.js +20 -19
  78. package/dist/shared/indexManager.js +12 -11
  79. package/dist/shared/jsonSchemaGenerator.js +10 -26
  80. package/dist/shared/logging.d.ts +51 -0
  81. package/dist/shared/logging.js +70 -0
  82. package/dist/shared/messageFormatter.d.ts +2 -0
  83. package/dist/shared/messageFormatter.js +10 -0
  84. package/dist/shared/migrationHelpers.d.ts +6 -16
  85. package/dist/shared/migrationHelpers.js +24 -21
  86. package/dist/shared/operationLogger.d.ts +8 -1
  87. package/dist/shared/operationLogger.js +11 -24
  88. package/dist/shared/operationQueue.d.ts +28 -1
  89. package/dist/shared/operationQueue.js +268 -66
  90. package/dist/shared/operationsTable.d.ts +26 -0
  91. package/dist/shared/operationsTable.js +286 -0
  92. package/dist/shared/operationsTableSchema.d.ts +48 -0
  93. package/dist/shared/operationsTableSchema.js +35 -0
  94. package/dist/shared/relationshipExtractor.d.ts +56 -0
  95. package/dist/shared/relationshipExtractor.js +138 -0
  96. package/dist/shared/schemaGenerator.d.ts +19 -1
  97. package/dist/shared/schemaGenerator.js +56 -75
  98. package/dist/storage/backupCompression.d.ts +20 -0
  99. package/dist/storage/backupCompression.js +67 -0
  100. package/dist/storage/methods.d.ts +16 -2
  101. package/dist/storage/methods.js +98 -14
  102. package/dist/users/methods.js +9 -8
  103. package/dist/utils/configDiscovery.d.ts +78 -0
  104. package/dist/utils/configDiscovery.js +430 -0
  105. package/dist/utils/directoryUtils.d.ts +22 -0
  106. package/dist/utils/directoryUtils.js +59 -0
  107. package/dist/utils/getClientFromConfig.d.ts +17 -8
  108. package/dist/utils/getClientFromConfig.js +162 -17
  109. package/dist/utils/helperFunctions.d.ts +16 -2
  110. package/dist/utils/helperFunctions.js +19 -5
  111. package/dist/utils/loadConfigs.d.ts +34 -9
  112. package/dist/utils/loadConfigs.js +236 -316
  113. package/dist/utils/pathResolvers.d.ts +53 -0
  114. package/dist/utils/pathResolvers.js +72 -0
  115. package/dist/utils/projectConfig.d.ts +119 -0
  116. package/dist/utils/projectConfig.js +171 -0
  117. package/dist/utils/retryFailedPromises.js +4 -2
  118. package/dist/utils/sessionAuth.d.ts +48 -0
  119. package/dist/utils/sessionAuth.js +164 -0
  120. package/dist/utils/sessionPreservationExample.d.ts +1666 -0
  121. package/dist/utils/sessionPreservationExample.js +101 -0
  122. package/dist/utils/setupFiles.js +301 -41
  123. package/dist/utils/typeGuards.d.ts +35 -0
  124. package/dist/utils/typeGuards.js +57 -0
  125. package/dist/utils/versionDetection.js +145 -9
  126. package/dist/utils/yamlConverter.d.ts +53 -3
  127. package/dist/utils/yamlConverter.js +232 -13
  128. package/dist/utils/yamlLoader.d.ts +70 -0
  129. package/dist/utils/yamlLoader.js +263 -0
  130. package/dist/utilsController.d.ts +36 -3
  131. package/dist/utilsController.js +186 -56
  132. package/package.json +12 -2
  133. package/src/adapters/AdapterFactory.ts +263 -35
  134. package/src/adapters/TablesDBAdapter.ts +225 -36
  135. package/src/backups/operations/bucketBackup.ts +277 -0
  136. package/src/backups/operations/collectionBackup.ts +310 -0
  137. package/src/backups/operations/comprehensiveBackup.ts +342 -0
  138. package/src/backups/schemas/bucketManifest.ts +78 -0
  139. package/src/backups/schemas/comprehensiveManifest.ts +76 -0
  140. package/src/backups/tracking/centralizedTracking.ts +352 -0
  141. package/src/cli/commands/configCommands.ts +194 -0
  142. package/src/cli/commands/databaseCommands.ts +635 -0
  143. package/src/cli/commands/functionCommands.ts +379 -0
  144. package/src/cli/commands/schemaCommands.ts +163 -0
  145. package/src/cli/commands/transferCommands.ts +457 -0
  146. package/src/collections/attributes.ts +900 -621
  147. package/src/collections/attributes.ts.backup +1555 -0
  148. package/src/collections/indexes.ts +116 -114
  149. package/src/collections/methods.ts +295 -968
  150. package/src/collections/transferOperations.ts +516 -0
  151. package/src/collections/wipeOperations.ts +501 -0
  152. package/src/config/README.md +274 -0
  153. package/src/config/configMigration.ts +575 -0
  154. package/src/config/configValidation.ts +445 -0
  155. package/src/config/yamlConfig.ts +168 -55
  156. package/src/databases/methods.ts +3 -2
  157. package/src/databases/setup.ts +11 -138
  158. package/src/examples/yamlTerminologyExample.ts +341 -0
  159. package/src/functions/deployments.ts +14 -12
  160. package/src/functions/methods.ts +11 -11
  161. package/src/functions/templates/hono-typescript/README.md +286 -0
  162. package/src/functions/templates/hono-typescript/package.json +26 -0
  163. package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  164. package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  165. package/src/functions/templates/hono-typescript/src/app.ts +180 -0
  166. package/src/functions/templates/hono-typescript/src/context.ts +103 -0
  167. package/src/functions/templates/hono-typescript/src/index.ts +54 -0
  168. package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  169. package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
  170. package/src/functions/templates/typescript-node/package.json +2 -1
  171. package/src/functions/templates/typescript-node/src/context.ts +103 -0
  172. package/src/functions/templates/typescript-node/src/index.ts +18 -12
  173. package/src/functions/templates/uv/pyproject.toml +1 -0
  174. package/src/functions/templates/uv/src/context.py +125 -0
  175. package/src/functions/templates/uv/src/index.py +35 -5
  176. package/src/init.ts +9 -11
  177. package/src/interactiveCLI.ts +274 -1563
  178. package/src/main.ts +418 -24
  179. package/src/migrations/afterImportActions.ts +71 -44
  180. package/src/migrations/appwriteToX.ts +100 -34
  181. package/src/migrations/dataLoader.ts +48 -34
  182. package/src/migrations/importController.ts +44 -39
  183. package/src/migrations/relationships.ts +28 -18
  184. package/src/migrations/services/ImportOrchestrator.ts +24 -27
  185. package/src/migrations/transfer.ts +159 -121
  186. package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
  187. package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
  188. package/src/migrations/yaml/generateImportSchemas.ts +751 -12
  189. package/src/setupController.ts +3 -2
  190. package/src/shared/backupMetadataSchema.ts +93 -0
  191. package/src/shared/backupTracking.ts +211 -0
  192. package/src/shared/confirmationDialogs.ts +19 -19
  193. package/src/shared/errorUtils.ts +110 -0
  194. package/src/shared/functionManager.ts +21 -20
  195. package/src/shared/indexManager.ts +12 -11
  196. package/src/shared/jsonSchemaGenerator.ts +38 -52
  197. package/src/shared/logging.ts +75 -0
  198. package/src/shared/messageFormatter.ts +14 -1
  199. package/src/shared/migrationHelpers.ts +45 -38
  200. package/src/shared/operationLogger.ts +11 -36
  201. package/src/shared/operationQueue.ts +322 -93
  202. package/src/shared/operationsTable.ts +338 -0
  203. package/src/shared/operationsTableSchema.ts +60 -0
  204. package/src/shared/relationshipExtractor.ts +214 -0
  205. package/src/shared/schemaGenerator.ts +179 -219
  206. package/src/storage/backupCompression.ts +88 -0
  207. package/src/storage/methods.ts +131 -34
  208. package/src/users/methods.ts +11 -9
  209. package/src/utils/configDiscovery.ts +502 -0
  210. package/src/utils/directoryUtils.ts +61 -0
  211. package/src/utils/getClientFromConfig.ts +205 -22
  212. package/src/utils/helperFunctions.ts +23 -5
  213. package/src/utils/loadConfigs.ts +313 -345
  214. package/src/utils/pathResolvers.ts +81 -0
  215. package/src/utils/projectConfig.ts +299 -0
  216. package/src/utils/retryFailedPromises.ts +4 -2
  217. package/src/utils/sessionAuth.ts +230 -0
  218. package/src/utils/setupFiles.ts +322 -54
  219. package/src/utils/typeGuards.ts +65 -0
  220. package/src/utils/versionDetection.ts +218 -64
  221. package/src/utils/yamlConverter.ts +296 -13
  222. package/src/utils/yamlLoader.ts +364 -0
  223. package/src/utilsController.ts +314 -110
  224. package/tests/README.md +497 -0
  225. package/tests/adapters/AdapterFactory.test.ts +277 -0
  226. package/tests/integration/syncOperations.test.ts +463 -0
  227. package/tests/jest.config.js +25 -0
  228. package/tests/migration/configMigration.test.ts +546 -0
  229. package/tests/setup.ts +62 -0
  230. package/tests/testUtils.ts +340 -0
  231. package/tests/utils/loadConfigs.test.ts +350 -0
  232. package/tests/validation/configValidation.test.ts +412 -0
  233. package/src/utils/schemaStrings.ts +0 -517
@@ -0,0 +1,289 @@
1
+ import inquirer from "inquirer";
2
+ import { join } from "node:path";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import { ulid } from "ulidx";
6
+ import chalk from "chalk";
7
+ import { Query } from "node-appwrite";
8
+ import { MessageFormatter } from "../../shared/messageFormatter.js";
9
+ import { createFunctionTemplate, deleteFunction, downloadLatestFunctionDeployment, listFunctions, listSpecifications, } from "../../functions/methods.js";
10
+ import { deployLocalFunction } from "../../functions/deployments.js";
11
+ import { addFunctionToYamlConfig, findYamlConfig } from "../../config/yamlConfig.js";
12
+ import { RuntimeSchema } from "appwrite-utils";
13
+ export const functionCommands = {
14
+ async createFunction(cli) {
15
+ const { name } = await inquirer.prompt([
16
+ {
17
+ type: "input",
18
+ name: "name",
19
+ message: "Function name:",
20
+ validate: (input) => input.length > 0,
21
+ },
22
+ ]);
23
+ const { template } = await inquirer.prompt([
24
+ {
25
+ type: "list",
26
+ name: "template",
27
+ message: "Select a template:",
28
+ choices: [
29
+ { name: "TypeScript Node.js", value: "typescript-node" },
30
+ { name: "TypeScript with Hono Web Framework", value: "hono-typescript" },
31
+ { name: "Python with UV", value: "uv" },
32
+ { name: "Count Documents in Collection", value: "count-docs-in-collection" },
33
+ { name: "None (Empty Function)", value: "none" },
34
+ ],
35
+ },
36
+ ]);
37
+ // Get template defaults
38
+ const templateDefaults = cli.getTemplateDefaults(template);
39
+ const { runtime } = await inquirer.prompt([
40
+ {
41
+ type: "list",
42
+ name: "runtime",
43
+ message: "Select runtime:",
44
+ choices: Object.values(RuntimeSchema.Values),
45
+ default: templateDefaults.runtime,
46
+ },
47
+ ]);
48
+ const specifications = await listSpecifications(cli.controller.appwriteServer);
49
+ const { specification } = await inquirer.prompt([
50
+ {
51
+ type: "list",
52
+ name: "specification",
53
+ message: "Select specification:",
54
+ choices: [
55
+ { name: "None", value: undefined },
56
+ ...specifications.specifications.map((s) => ({
57
+ name: s.slug,
58
+ value: s.slug,
59
+ })),
60
+ ],
61
+ default: templateDefaults.specification,
62
+ },
63
+ ]);
64
+ const functionConfig = {
65
+ $id: ulid(),
66
+ name,
67
+ runtime,
68
+ events: [],
69
+ execute: ["any"],
70
+ enabled: true,
71
+ logging: true,
72
+ entrypoint: templateDefaults.entrypoint,
73
+ commands: templateDefaults.commands,
74
+ specification: specification || templateDefaults.specification,
75
+ scopes: [],
76
+ timeout: 15,
77
+ schedule: "",
78
+ installationId: "",
79
+ providerRepositoryId: "",
80
+ providerBranch: "",
81
+ providerSilentMode: false,
82
+ providerRootDirectory: "",
83
+ templateRepository: "",
84
+ templateOwner: "",
85
+ templateRootDirectory: "",
86
+ };
87
+ if (template !== "none") {
88
+ await createFunctionTemplate(template, name, "./functions");
89
+ }
90
+ // Add to in-memory config
91
+ if (!cli.controller.config.functions) {
92
+ cli.controller.config.functions = [];
93
+ }
94
+ cli.controller.config.functions.push(functionConfig);
95
+ // If using YAML config, also add to YAML file
96
+ const yamlConfigPath = findYamlConfig(cli.currentDir);
97
+ if (yamlConfigPath) {
98
+ try {
99
+ await addFunctionToYamlConfig(yamlConfigPath, functionConfig);
100
+ }
101
+ catch (error) {
102
+ MessageFormatter.warning(`Function created but failed to update YAML config: ${error instanceof Error ? error.message : error}`, { prefix: "Functions" });
103
+ }
104
+ }
105
+ MessageFormatter.success("Function created successfully!", { prefix: "Functions" });
106
+ },
107
+ async deployFunction(cli) {
108
+ await cli.initControllerIfNeeded();
109
+ if (!cli.controller?.config) {
110
+ MessageFormatter.error("Failed to initialize controller or load config", undefined, { prefix: "Functions" });
111
+ return;
112
+ }
113
+ const functions = await cli.selectFunctions("Select function(s) to deploy:", true, true);
114
+ if (!functions?.length) {
115
+ MessageFormatter.error("No function selected", undefined, { prefix: "Functions" });
116
+ return;
117
+ }
118
+ for (const functionConfig of functions) {
119
+ if (!functionConfig) {
120
+ MessageFormatter.error("Invalid function configuration", undefined, { prefix: "Functions" });
121
+ return;
122
+ }
123
+ // Ensure functions array exists
124
+ if (!cli.controller.config.functions) {
125
+ cli.controller.config.functions = [];
126
+ }
127
+ const functionNameLower = functionConfig.name
128
+ .toLowerCase()
129
+ .replace(/\s+/g, "-");
130
+ // Debug logging
131
+ MessageFormatter.info(`🔍 Function deployment debug:`, { prefix: "Functions" });
132
+ MessageFormatter.info(` Function name: ${functionConfig.name}`, { prefix: "Functions" });
133
+ MessageFormatter.info(` Function ID: ${functionConfig.$id}`, { prefix: "Functions" });
134
+ MessageFormatter.info(` Config dirPath: ${functionConfig.dirPath || 'undefined'}`, { prefix: "Functions" });
135
+ if (functionConfig.dirPath) {
136
+ const expandedPath = functionConfig.dirPath.startsWith('~/')
137
+ ? functionConfig.dirPath.replace('~', os.homedir())
138
+ : functionConfig.dirPath;
139
+ MessageFormatter.info(` Expanded dirPath: ${expandedPath}`, { prefix: "Functions" });
140
+ }
141
+ MessageFormatter.info(` Appwrite folder: ${cli.controller.getAppwriteFolderPath()}`, { prefix: "Functions" });
142
+ MessageFormatter.info(` Current working dir: ${process.cwd()}`, { prefix: "Functions" });
143
+ // Helper function to expand tilde in paths
144
+ const expandTildePath = (path) => {
145
+ if (path.startsWith('~/')) {
146
+ return path.replace('~', os.homedir());
147
+ }
148
+ return path;
149
+ };
150
+ // Check locations in priority order:
151
+ const priorityLocations = [
152
+ // 1. Config dirPath if specified (with tilde expansion)
153
+ functionConfig.dirPath ? expandTildePath(functionConfig.dirPath) : undefined,
154
+ // 2. Appwrite config folder/functions/name
155
+ join(cli.controller.getAppwriteFolderPath(), "functions", functionNameLower),
156
+ // 3. Current working directory/functions/name
157
+ join(process.cwd(), "functions", functionNameLower),
158
+ // 4. Current working directory/name
159
+ join(process.cwd(), functionNameLower),
160
+ ].filter((val) => val !== undefined);
161
+ MessageFormatter.info(`🔍 Priority locations to check:`, { prefix: "Functions" });
162
+ priorityLocations.forEach((loc, i) => {
163
+ MessageFormatter.info(` ${i + 1}. ${loc}`, { prefix: "Functions" });
164
+ });
165
+ let functionPath = null;
166
+ // Check each priority location
167
+ for (const location of priorityLocations) {
168
+ MessageFormatter.info(` Checking: ${location} - ${fs.existsSync(location) ? 'EXISTS' : 'NOT FOUND'}`, { prefix: "Functions" });
169
+ if (fs.existsSync(location)) {
170
+ MessageFormatter.success(`✅ Found function at: ${location}`, { prefix: "Functions" });
171
+ functionPath = location;
172
+ break;
173
+ }
174
+ }
175
+ // If not found in priority locations, do a broader search
176
+ if (!functionPath) {
177
+ MessageFormatter.info(`Function not found in primary locations, searching subdirectories...`, { prefix: "Functions" });
178
+ // Search in both appwrite config directory and current working directory
179
+ functionPath = await cli.findFunctionInSubdirectories([cli.controller.getAppwriteFolderPath(), process.cwd()], functionNameLower);
180
+ }
181
+ if (!functionPath) {
182
+ const { shouldDownload } = await inquirer.prompt([
183
+ {
184
+ type: "confirm",
185
+ name: "shouldDownload",
186
+ message: "Function not found locally. Would you like to download the latest deployment?",
187
+ default: false,
188
+ },
189
+ ]);
190
+ if (shouldDownload) {
191
+ try {
192
+ MessageFormatter.progress("Downloading latest deployment...", { prefix: "Functions" });
193
+ const { path: downloadedPath, function: remoteFunction } = await downloadLatestFunctionDeployment(cli.controller.appwriteServer, functionConfig.$id, join(cli.controller.getAppwriteFolderPath(), "functions"));
194
+ MessageFormatter.success(`✨ Function downloaded to ${downloadedPath}`, { prefix: "Functions" });
195
+ functionPath = downloadedPath;
196
+ functionConfig.dirPath = downloadedPath;
197
+ const existingIndex = cli.controller.config.functions.findIndex((f) => f?.$id === remoteFunction.$id);
198
+ if (existingIndex >= 0) {
199
+ cli.controller.config.functions[existingIndex].dirPath =
200
+ downloadedPath;
201
+ }
202
+ await cli.reloadConfigWithSessionPreservation();
203
+ }
204
+ catch (error) {
205
+ MessageFormatter.error("Failed to download function deployment", error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
206
+ return;
207
+ }
208
+ }
209
+ else {
210
+ MessageFormatter.error(`Function ${functionConfig.name} not found locally. Cannot deploy.`, undefined, { prefix: "Functions" });
211
+ return;
212
+ }
213
+ }
214
+ if (!cli.controller.appwriteServer) {
215
+ MessageFormatter.error("Appwrite server not initialized", undefined, { prefix: "Functions" });
216
+ return;
217
+ }
218
+ try {
219
+ await deployLocalFunction(cli.controller.appwriteServer, functionConfig.name, {
220
+ ...functionConfig,
221
+ dirPath: functionPath,
222
+ }, functionPath);
223
+ MessageFormatter.success("Function deployed successfully!", { prefix: "Functions" });
224
+ }
225
+ catch (error) {
226
+ MessageFormatter.error("Failed to deploy function", error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
227
+ }
228
+ }
229
+ },
230
+ async deleteFunction(cli) {
231
+ const functions = await cli.selectFunctions("Select functions to delete:", true, false);
232
+ if (!functions.length) {
233
+ MessageFormatter.error("No functions selected", undefined, { prefix: "Functions" });
234
+ return;
235
+ }
236
+ for (const func of functions) {
237
+ try {
238
+ await deleteFunction(cli.controller.appwriteServer, func.$id);
239
+ MessageFormatter.success(`✨ Function ${func.name} deleted successfully!`, { prefix: "Functions" });
240
+ }
241
+ catch (error) {
242
+ MessageFormatter.error(`Failed to delete function ${func.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
243
+ }
244
+ }
245
+ },
246
+ async updateFunctionSpec(cli) {
247
+ const remoteFunctions = await listFunctions(cli.controller.appwriteServer, [Query.limit(1000)]);
248
+ const localFunctions = cli.getLocalFunctions();
249
+ const allFunctions = [
250
+ ...remoteFunctions.functions,
251
+ ...localFunctions.filter((f) => !remoteFunctions.functions.some((rf) => rf.name === f.name)),
252
+ ];
253
+ const functionsToUpdate = await inquirer.prompt([
254
+ {
255
+ type: "checkbox",
256
+ name: "functionId",
257
+ message: "Select functions to update:",
258
+ choices: allFunctions.map((f) => ({
259
+ name: `${f.name} (${f.$id})${localFunctions.some((lf) => lf.name === f.name)
260
+ ? " (Local)"
261
+ : " (Remote)"}`,
262
+ value: f.$id,
263
+ })),
264
+ loop: true,
265
+ },
266
+ ]);
267
+ const specifications = await listSpecifications(cli.controller.appwriteServer);
268
+ const { specification } = await inquirer.prompt([
269
+ {
270
+ type: "list",
271
+ name: "specification",
272
+ message: "Select new specification:",
273
+ choices: specifications.specifications.map((s) => ({
274
+ name: `${s.slug}`,
275
+ value: s.slug,
276
+ })),
277
+ },
278
+ ]);
279
+ try {
280
+ for (const functionId of functionsToUpdate.functionId) {
281
+ await cli.controller.updateFunctionSpecifications(functionId, specification);
282
+ MessageFormatter.success(`Successfully updated function specification to ${specification}`, { prefix: "Functions" });
283
+ }
284
+ }
285
+ catch (error) {
286
+ MessageFormatter.error("Error updating function specification", error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
287
+ }
288
+ }
289
+ };
@@ -0,0 +1,7 @@
1
+ import type { InteractiveCLI } from "../../interactiveCLI.js";
2
+ export declare const schemaCommands: {
3
+ generateSchemas(cli: InteractiveCLI): Promise<void>;
4
+ generateConstants(cli: InteractiveCLI): Promise<void>;
5
+ importData(cli: InteractiveCLI): Promise<void>;
6
+ setupDirsFiles(cli: InteractiveCLI, withExampleData?: boolean): Promise<void>;
7
+ };
@@ -0,0 +1,134 @@
1
+ import inquirer from "inquirer";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+ import { MessageFormatter } from "../../shared/messageFormatter.js";
5
+ import { SchemaGenerator } from "../../shared/schemaGenerator.js";
6
+ import { setupDirsFiles } from "../../utils/setupFiles.js";
7
+ import { fetchAllDatabases } from "../../databases/methods.js";
8
+ export const schemaCommands = {
9
+ async generateSchemas(cli) {
10
+ MessageFormatter.progress("Generating schemas...", { prefix: "Schemas" });
11
+ // Prompt user for schema type preference
12
+ const { schemaType } = await inquirer.prompt([
13
+ {
14
+ type: "list",
15
+ name: "schemaType",
16
+ message: "What type of schemas would you like to generate?",
17
+ choices: [
18
+ { name: "TypeScript (Zod) schemas", value: "zod" },
19
+ { name: "JSON schemas", value: "json" },
20
+ { name: "Both TypeScript and JSON schemas", value: "both" },
21
+ ],
22
+ default: "both",
23
+ },
24
+ ]);
25
+ // Get the config folder path (where the config file is located)
26
+ const configFolderPath = cli.controller.getAppwriteFolderPath();
27
+ if (!configFolderPath) {
28
+ MessageFormatter.error("Failed to get config folder path", undefined, { prefix: "Schemas" });
29
+ return;
30
+ }
31
+ // Create SchemaGenerator with the correct base path and generate schemas
32
+ const schemaGenerator = new SchemaGenerator(cli.controller.config, configFolderPath);
33
+ schemaGenerator.generateSchemas({ format: schemaType, verbose: true });
34
+ MessageFormatter.success("Schema generation completed", { prefix: "Schemas" });
35
+ },
36
+ async generateConstants(cli) {
37
+ MessageFormatter.progress("Generating cross-language constants...", { prefix: "Constants" });
38
+ if (!cli.controller?.config) {
39
+ MessageFormatter.error("No configuration found", undefined, { prefix: "Constants" });
40
+ return;
41
+ }
42
+ // Prompt for languages
43
+ const { languages } = await inquirer.prompt([
44
+ {
45
+ type: "checkbox",
46
+ name: "languages",
47
+ message: "Select languages for constants generation:",
48
+ choices: [
49
+ { name: "TypeScript", value: "typescript", checked: true },
50
+ { name: "JavaScript", value: "javascript" },
51
+ { name: "Python", value: "python" },
52
+ { name: "PHP", value: "php" },
53
+ { name: "Dart", value: "dart" },
54
+ { name: "JSON", value: "json" },
55
+ { name: "Environment Variables", value: "env" },
56
+ ],
57
+ validate: (input) => {
58
+ if (input.length === 0) {
59
+ return "Please select at least one language";
60
+ }
61
+ return true;
62
+ },
63
+ },
64
+ ]);
65
+ // Determine default output directory based on config location
66
+ const configPath = cli.controller.getAppwriteFolderPath();
67
+ const defaultOutputDir = configPath
68
+ ? path.join(configPath, "constants")
69
+ : path.join(process.cwd(), "constants");
70
+ // Prompt for output directory
71
+ const { outputDir } = await inquirer.prompt([
72
+ {
73
+ type: "input",
74
+ name: "outputDir",
75
+ message: "Output directory for constants files:",
76
+ default: defaultOutputDir,
77
+ validate: (input) => {
78
+ if (!input.trim()) {
79
+ return "Output directory cannot be empty";
80
+ }
81
+ return true;
82
+ },
83
+ },
84
+ ]);
85
+ try {
86
+ const { ConstantsGenerator } = await import("../../utils/constantsGenerator.js");
87
+ const generator = new ConstantsGenerator(cli.controller.config);
88
+ MessageFormatter.info(`Generating constants for: ${languages.join(", ")}`, { prefix: "Constants" });
89
+ await generator.generateFiles(languages, outputDir);
90
+ MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
91
+ }
92
+ catch (error) {
93
+ MessageFormatter.error("Failed to generate constants", error instanceof Error ? error : new Error(String(error)), { prefix: "Constants" });
94
+ }
95
+ },
96
+ async importData(cli) {
97
+ MessageFormatter.progress("Importing data...", { prefix: "Import" });
98
+ const { doBackup } = await inquirer.prompt([
99
+ {
100
+ type: "confirm",
101
+ name: "doBackup",
102
+ message: "Do you want to perform a backup before importing?",
103
+ default: true,
104
+ },
105
+ ]);
106
+ const databases = await cli.selectDatabases(await fetchAllDatabases(cli.controller.database), "Select databases to import data into:", true);
107
+ const collections = await cli.selectCollectionsAndTables(databases[0], cli.controller.database, "Select collections/tables to import data into (leave empty for all):", true);
108
+ const { shouldWriteFile } = await inquirer.prompt([
109
+ {
110
+ type: "confirm",
111
+ name: "shouldWriteFile",
112
+ message: "Do you want to write the imported data to a file?",
113
+ default: false,
114
+ },
115
+ ]);
116
+ const options = {
117
+ databases,
118
+ collections: collections.map((c) => c.name),
119
+ doBackup,
120
+ importData: true,
121
+ shouldWriteFile,
122
+ };
123
+ try {
124
+ await cli.controller.importData(options);
125
+ MessageFormatter.success("Data import completed successfully", { prefix: "Import" });
126
+ }
127
+ catch (error) {
128
+ MessageFormatter.error("Error importing data", error instanceof Error ? error : new Error(String(error)), { prefix: "Import" });
129
+ }
130
+ },
131
+ async setupDirsFiles(cli, withExampleData = false) {
132
+ await setupDirsFiles(withExampleData, cli.currentDir);
133
+ }
134
+ };
@@ -0,0 +1,5 @@
1
+ import type { InteractiveCLI } from "../../interactiveCLI.js";
2
+ export declare const transferCommands: {
3
+ transferData(cli: InteractiveCLI): Promise<void>;
4
+ comprehensiveTransfer(cli: InteractiveCLI): Promise<void>;
5
+ };