@njdamstra/appwrite-utils-cli 1.8.9

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 (392) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1133 -0
  3. package/dist/adapters/AdapterFactory.d.ts +94 -0
  4. package/dist/adapters/AdapterFactory.js +405 -0
  5. package/dist/adapters/DatabaseAdapter.d.ts +233 -0
  6. package/dist/adapters/DatabaseAdapter.js +50 -0
  7. package/dist/adapters/LegacyAdapter.d.ts +50 -0
  8. package/dist/adapters/LegacyAdapter.js +612 -0
  9. package/dist/adapters/TablesDBAdapter.d.ts +45 -0
  10. package/dist/adapters/TablesDBAdapter.js +571 -0
  11. package/dist/adapters/index.d.ts +11 -0
  12. package/dist/adapters/index.js +12 -0
  13. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  14. package/dist/backups/operations/bucketBackup.js +197 -0
  15. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  16. package/dist/backups/operations/collectionBackup.js +201 -0
  17. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  18. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  19. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  20. package/dist/backups/schemas/bucketManifest.js +33 -0
  21. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  22. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  23. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  24. package/dist/backups/tracking/centralizedTracking.js +274 -0
  25. package/dist/cli/commands/configCommands.d.ts +8 -0
  26. package/dist/cli/commands/configCommands.js +166 -0
  27. package/dist/cli/commands/databaseCommands.d.ts +13 -0
  28. package/dist/cli/commands/databaseCommands.js +554 -0
  29. package/dist/cli/commands/functionCommands.d.ts +7 -0
  30. package/dist/cli/commands/functionCommands.js +330 -0
  31. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  32. package/dist/cli/commands/schemaCommands.js +169 -0
  33. package/dist/cli/commands/storageCommands.d.ts +5 -0
  34. package/dist/cli/commands/storageCommands.js +143 -0
  35. package/dist/cli/commands/transferCommands.d.ts +5 -0
  36. package/dist/cli/commands/transferCommands.js +384 -0
  37. package/dist/collections/attributes.d.ts +13 -0
  38. package/dist/collections/attributes.js +1364 -0
  39. package/dist/collections/indexes.d.ts +12 -0
  40. package/dist/collections/indexes.js +217 -0
  41. package/dist/collections/methods.d.ts +19 -0
  42. package/dist/collections/methods.js +682 -0
  43. package/dist/collections/tableOperations.d.ts +86 -0
  44. package/dist/collections/tableOperations.js +434 -0
  45. package/dist/collections/transferOperations.d.ts +8 -0
  46. package/dist/collections/transferOperations.js +412 -0
  47. package/dist/collections/wipeOperations.d.ts +16 -0
  48. package/dist/collections/wipeOperations.js +233 -0
  49. package/dist/config/ConfigManager.d.ts +445 -0
  50. package/dist/config/ConfigManager.js +625 -0
  51. package/dist/config/configMigration.d.ts +87 -0
  52. package/dist/config/configMigration.js +390 -0
  53. package/dist/config/configValidation.d.ts +66 -0
  54. package/dist/config/configValidation.js +358 -0
  55. package/dist/config/index.d.ts +8 -0
  56. package/dist/config/index.js +7 -0
  57. package/dist/config/services/ConfigDiscoveryService.d.ts +126 -0
  58. package/dist/config/services/ConfigDiscoveryService.js +374 -0
  59. package/dist/config/services/ConfigLoaderService.d.ts +129 -0
  60. package/dist/config/services/ConfigLoaderService.js +540 -0
  61. package/dist/config/services/ConfigMergeService.d.ts +208 -0
  62. package/dist/config/services/ConfigMergeService.js +308 -0
  63. package/dist/config/services/ConfigValidationService.d.ts +214 -0
  64. package/dist/config/services/ConfigValidationService.js +310 -0
  65. package/dist/config/services/SessionAuthService.d.ts +225 -0
  66. package/dist/config/services/SessionAuthService.js +456 -0
  67. package/dist/config/services/__tests__/ConfigMergeService.test.d.ts +1 -0
  68. package/dist/config/services/__tests__/ConfigMergeService.test.js +271 -0
  69. package/dist/config/services/index.d.ts +13 -0
  70. package/dist/config/services/index.js +10 -0
  71. package/dist/config/yamlConfig.d.ts +722 -0
  72. package/dist/config/yamlConfig.js +702 -0
  73. package/dist/databases/methods.d.ts +6 -0
  74. package/dist/databases/methods.js +35 -0
  75. package/dist/databases/setup.d.ts +5 -0
  76. package/dist/databases/setup.js +45 -0
  77. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  78. package/dist/examples/yamlTerminologyExample.js +272 -0
  79. package/dist/functions/deployments.d.ts +4 -0
  80. package/dist/functions/deployments.js +146 -0
  81. package/dist/functions/fnConfigDiscovery.d.ts +3 -0
  82. package/dist/functions/fnConfigDiscovery.js +108 -0
  83. package/dist/functions/methods.d.ts +16 -0
  84. package/dist/functions/methods.js +162 -0
  85. package/dist/functions/pathResolution.d.ts +37 -0
  86. package/dist/functions/pathResolution.js +185 -0
  87. package/dist/functions/templates/count-docs-in-collection/README.md +54 -0
  88. package/dist/functions/templates/count-docs-in-collection/src/main.ts +159 -0
  89. package/dist/functions/templates/count-docs-in-collection/src/request.ts +9 -0
  90. package/dist/functions/templates/hono-typescript/README.md +286 -0
  91. package/dist/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  92. package/dist/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  93. package/dist/functions/templates/hono-typescript/src/app.ts +180 -0
  94. package/dist/functions/templates/hono-typescript/src/context.ts +103 -0
  95. package/dist/functions/templates/hono-typescript/src/index.ts +54 -0
  96. package/dist/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  97. package/dist/functions/templates/typescript-node/README.md +32 -0
  98. package/dist/functions/templates/typescript-node/src/context.ts +103 -0
  99. package/dist/functions/templates/typescript-node/src/index.ts +29 -0
  100. package/dist/functions/templates/uv/README.md +31 -0
  101. package/dist/functions/templates/uv/pyproject.toml +30 -0
  102. package/dist/functions/templates/uv/src/__init__.py +0 -0
  103. package/dist/functions/templates/uv/src/context.py +125 -0
  104. package/dist/functions/templates/uv/src/index.py +46 -0
  105. package/dist/init.d.ts +2 -0
  106. package/dist/init.js +57 -0
  107. package/dist/interactiveCLI.d.ts +31 -0
  108. package/dist/interactiveCLI.js +898 -0
  109. package/dist/main.d.ts +2 -0
  110. package/dist/main.js +1172 -0
  111. package/dist/migrations/afterImportActions.d.ts +17 -0
  112. package/dist/migrations/afterImportActions.js +306 -0
  113. package/dist/migrations/appwriteToX.d.ts +211 -0
  114. package/dist/migrations/appwriteToX.js +491 -0
  115. package/dist/migrations/comprehensiveTransfer.d.ts +147 -0
  116. package/dist/migrations/comprehensiveTransfer.js +1317 -0
  117. package/dist/migrations/dataLoader.d.ts +753 -0
  118. package/dist/migrations/dataLoader.js +1250 -0
  119. package/dist/migrations/importController.d.ts +23 -0
  120. package/dist/migrations/importController.js +268 -0
  121. package/dist/migrations/importDataActions.d.ts +50 -0
  122. package/dist/migrations/importDataActions.js +230 -0
  123. package/dist/migrations/relationships.d.ts +29 -0
  124. package/dist/migrations/relationships.js +204 -0
  125. package/dist/migrations/services/DataTransformationService.d.ts +55 -0
  126. package/dist/migrations/services/DataTransformationService.js +158 -0
  127. package/dist/migrations/services/FileHandlerService.d.ts +75 -0
  128. package/dist/migrations/services/FileHandlerService.js +236 -0
  129. package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
  130. package/dist/migrations/services/ImportOrchestrator.js +485 -0
  131. package/dist/migrations/services/RateLimitManager.d.ts +138 -0
  132. package/dist/migrations/services/RateLimitManager.js +279 -0
  133. package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
  134. package/dist/migrations/services/RelationshipResolver.js +332 -0
  135. package/dist/migrations/services/UserMappingService.d.ts +109 -0
  136. package/dist/migrations/services/UserMappingService.js +277 -0
  137. package/dist/migrations/services/ValidationService.d.ts +74 -0
  138. package/dist/migrations/services/ValidationService.js +260 -0
  139. package/dist/migrations/transfer.d.ts +26 -0
  140. package/dist/migrations/transfer.js +608 -0
  141. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +131 -0
  142. package/dist/migrations/yaml/YamlImportConfigLoader.js +383 -0
  143. package/dist/migrations/yaml/YamlImportIntegration.d.ts +93 -0
  144. package/dist/migrations/yaml/YamlImportIntegration.js +341 -0
  145. package/dist/migrations/yaml/generateImportSchemas.d.ts +30 -0
  146. package/dist/migrations/yaml/generateImportSchemas.js +1327 -0
  147. package/dist/schemas/authUser.d.ts +24 -0
  148. package/dist/schemas/authUser.js +17 -0
  149. package/dist/setup.d.ts +2 -0
  150. package/dist/setup.js +5 -0
  151. package/dist/setupCommands.d.ts +58 -0
  152. package/dist/setupCommands.js +490 -0
  153. package/dist/setupController.d.ts +9 -0
  154. package/dist/setupController.js +34 -0
  155. package/dist/shared/attributeMapper.d.ts +20 -0
  156. package/dist/shared/attributeMapper.js +203 -0
  157. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  158. package/dist/shared/backupMetadataSchema.js +38 -0
  159. package/dist/shared/backupTracking.d.ts +18 -0
  160. package/dist/shared/backupTracking.js +176 -0
  161. package/dist/shared/confirmationDialogs.d.ts +75 -0
  162. package/dist/shared/confirmationDialogs.js +236 -0
  163. package/dist/shared/errorUtils.d.ts +54 -0
  164. package/dist/shared/errorUtils.js +95 -0
  165. package/dist/shared/functionManager.d.ts +48 -0
  166. package/dist/shared/functionManager.js +336 -0
  167. package/dist/shared/indexManager.d.ts +24 -0
  168. package/dist/shared/indexManager.js +151 -0
  169. package/dist/shared/jsonSchemaGenerator.d.ts +50 -0
  170. package/dist/shared/jsonSchemaGenerator.js +290 -0
  171. package/dist/shared/logging.d.ts +61 -0
  172. package/dist/shared/logging.js +116 -0
  173. package/dist/shared/messageFormatter.d.ts +39 -0
  174. package/dist/shared/messageFormatter.js +162 -0
  175. package/dist/shared/migrationHelpers.d.ts +61 -0
  176. package/dist/shared/migrationHelpers.js +145 -0
  177. package/dist/shared/operationLogger.d.ts +10 -0
  178. package/dist/shared/operationLogger.js +12 -0
  179. package/dist/shared/operationQueue.d.ts +40 -0
  180. package/dist/shared/operationQueue.js +311 -0
  181. package/dist/shared/operationsTable.d.ts +26 -0
  182. package/dist/shared/operationsTable.js +286 -0
  183. package/dist/shared/operationsTableSchema.d.ts +48 -0
  184. package/dist/shared/operationsTableSchema.js +35 -0
  185. package/dist/shared/progressManager.d.ts +62 -0
  186. package/dist/shared/progressManager.js +215 -0
  187. package/dist/shared/pydanticModelGenerator.d.ts +17 -0
  188. package/dist/shared/pydanticModelGenerator.js +615 -0
  189. package/dist/shared/relationshipExtractor.d.ts +56 -0
  190. package/dist/shared/relationshipExtractor.js +138 -0
  191. package/dist/shared/schemaGenerator.d.ts +40 -0
  192. package/dist/shared/schemaGenerator.js +556 -0
  193. package/dist/shared/selectionDialogs.d.ts +214 -0
  194. package/dist/shared/selectionDialogs.js +544 -0
  195. package/dist/storage/backupCompression.d.ts +20 -0
  196. package/dist/storage/backupCompression.js +67 -0
  197. package/dist/storage/methods.d.ts +32 -0
  198. package/dist/storage/methods.js +472 -0
  199. package/dist/storage/schemas.d.ts +842 -0
  200. package/dist/storage/schemas.js +175 -0
  201. package/dist/types.d.ts +4 -0
  202. package/dist/types.js +3 -0
  203. package/dist/users/methods.d.ts +16 -0
  204. package/dist/users/methods.js +277 -0
  205. package/dist/utils/ClientFactory.d.ts +87 -0
  206. package/dist/utils/ClientFactory.js +212 -0
  207. package/dist/utils/configDiscovery.d.ts +78 -0
  208. package/dist/utils/configDiscovery.js +472 -0
  209. package/dist/utils/configMigration.d.ts +1 -0
  210. package/dist/utils/configMigration.js +261 -0
  211. package/dist/utils/constantsGenerator.d.ts +31 -0
  212. package/dist/utils/constantsGenerator.js +321 -0
  213. package/dist/utils/dataConverters.d.ts +46 -0
  214. package/dist/utils/dataConverters.js +139 -0
  215. package/dist/utils/directoryUtils.d.ts +22 -0
  216. package/dist/utils/directoryUtils.js +59 -0
  217. package/dist/utils/getClientFromConfig.d.ts +39 -0
  218. package/dist/utils/getClientFromConfig.js +199 -0
  219. package/dist/utils/helperFunctions.d.ts +63 -0
  220. package/dist/utils/helperFunctions.js +156 -0
  221. package/dist/utils/index.d.ts +2 -0
  222. package/dist/utils/index.js +2 -0
  223. package/dist/utils/loadConfigs.d.ts +50 -0
  224. package/dist/utils/loadConfigs.js +358 -0
  225. package/dist/utils/pathResolvers.d.ts +53 -0
  226. package/dist/utils/pathResolvers.js +72 -0
  227. package/dist/utils/projectConfig.d.ts +119 -0
  228. package/dist/utils/projectConfig.js +171 -0
  229. package/dist/utils/retryFailedPromises.d.ts +2 -0
  230. package/dist/utils/retryFailedPromises.js +23 -0
  231. package/dist/utils/sessionAuth.d.ts +48 -0
  232. package/dist/utils/sessionAuth.js +164 -0
  233. package/dist/utils/setupFiles.d.ts +4 -0
  234. package/dist/utils/setupFiles.js +1192 -0
  235. package/dist/utils/typeGuards.d.ts +35 -0
  236. package/dist/utils/typeGuards.js +57 -0
  237. package/dist/utils/validationRules.d.ts +43 -0
  238. package/dist/utils/validationRules.js +42 -0
  239. package/dist/utils/versionDetection.d.ts +58 -0
  240. package/dist/utils/versionDetection.js +251 -0
  241. package/dist/utils/yamlConverter.d.ts +100 -0
  242. package/dist/utils/yamlConverter.js +428 -0
  243. package/dist/utils/yamlLoader.d.ts +70 -0
  244. package/dist/utils/yamlLoader.js +267 -0
  245. package/dist/utilsController.d.ts +106 -0
  246. package/dist/utilsController.js +863 -0
  247. package/package.json +75 -0
  248. package/scripts/copy-templates.ts +23 -0
  249. package/src/adapters/AdapterFactory.ts +510 -0
  250. package/src/adapters/DatabaseAdapter.ts +306 -0
  251. package/src/adapters/LegacyAdapter.ts +841 -0
  252. package/src/adapters/TablesDBAdapter.ts +773 -0
  253. package/src/adapters/index.ts +37 -0
  254. package/src/backups/operations/bucketBackup.ts +277 -0
  255. package/src/backups/operations/collectionBackup.ts +310 -0
  256. package/src/backups/operations/comprehensiveBackup.ts +342 -0
  257. package/src/backups/schemas/bucketManifest.ts +78 -0
  258. package/src/backups/schemas/comprehensiveManifest.ts +76 -0
  259. package/src/backups/tracking/centralizedTracking.ts +352 -0
  260. package/src/cli/commands/configCommands.ts +201 -0
  261. package/src/cli/commands/databaseCommands.ts +749 -0
  262. package/src/cli/commands/functionCommands.ts +418 -0
  263. package/src/cli/commands/schemaCommands.ts +200 -0
  264. package/src/cli/commands/storageCommands.ts +152 -0
  265. package/src/cli/commands/transferCommands.ts +457 -0
  266. package/src/collections/attributes.ts +2054 -0
  267. package/src/collections/attributes.ts.backup +1555 -0
  268. package/src/collections/indexes.ts +352 -0
  269. package/src/collections/methods.ts +745 -0
  270. package/src/collections/tableOperations.ts +506 -0
  271. package/src/collections/transferOperations.ts +590 -0
  272. package/src/collections/wipeOperations.ts +346 -0
  273. package/src/config/ConfigManager.ts +808 -0
  274. package/src/config/README.md +274 -0
  275. package/src/config/configMigration.ts +575 -0
  276. package/src/config/configValidation.ts +445 -0
  277. package/src/config/index.ts +10 -0
  278. package/src/config/services/ConfigDiscoveryService.ts +463 -0
  279. package/src/config/services/ConfigLoaderService.ts +740 -0
  280. package/src/config/services/ConfigMergeService.ts +388 -0
  281. package/src/config/services/ConfigValidationService.ts +394 -0
  282. package/src/config/services/SessionAuthService.ts +565 -0
  283. package/src/config/services/__tests__/ConfigMergeService.test.ts +351 -0
  284. package/src/config/services/index.ts +29 -0
  285. package/src/config/yamlConfig.ts +761 -0
  286. package/src/databases/methods.ts +49 -0
  287. package/src/databases/setup.ts +77 -0
  288. package/src/examples/yamlTerminologyExample.ts +346 -0
  289. package/src/functions/deployments.ts +220 -0
  290. package/src/functions/fnConfigDiscovery.ts +103 -0
  291. package/src/functions/methods.ts +271 -0
  292. package/src/functions/pathResolution.ts +227 -0
  293. package/src/functions/templates/count-docs-in-collection/README.md +54 -0
  294. package/src/functions/templates/count-docs-in-collection/src/main.ts +159 -0
  295. package/src/functions/templates/count-docs-in-collection/src/request.ts +9 -0
  296. package/src/functions/templates/hono-typescript/README.md +286 -0
  297. package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  298. package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  299. package/src/functions/templates/hono-typescript/src/app.ts +180 -0
  300. package/src/functions/templates/hono-typescript/src/context.ts +103 -0
  301. package/src/functions/templates/hono-typescript/src/index.ts +54 -0
  302. package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  303. package/src/functions/templates/typescript-node/README.md +32 -0
  304. package/src/functions/templates/typescript-node/src/context.ts +103 -0
  305. package/src/functions/templates/typescript-node/src/index.ts +29 -0
  306. package/src/functions/templates/uv/README.md +31 -0
  307. package/src/functions/templates/uv/pyproject.toml +30 -0
  308. package/src/functions/templates/uv/src/__init__.py +0 -0
  309. package/src/functions/templates/uv/src/context.py +125 -0
  310. package/src/functions/templates/uv/src/index.py +46 -0
  311. package/src/init.ts +62 -0
  312. package/src/interactiveCLI.ts +1136 -0
  313. package/src/main.ts +1661 -0
  314. package/src/migrations/afterImportActions.ts +580 -0
  315. package/src/migrations/appwriteToX.ts +664 -0
  316. package/src/migrations/comprehensiveTransfer.ts +2285 -0
  317. package/src/migrations/dataLoader.ts +1702 -0
  318. package/src/migrations/importController.ts +428 -0
  319. package/src/migrations/importDataActions.ts +315 -0
  320. package/src/migrations/relationships.ts +334 -0
  321. package/src/migrations/services/DataTransformationService.ts +196 -0
  322. package/src/migrations/services/FileHandlerService.ts +311 -0
  323. package/src/migrations/services/ImportOrchestrator.ts +666 -0
  324. package/src/migrations/services/RateLimitManager.ts +363 -0
  325. package/src/migrations/services/RelationshipResolver.ts +461 -0
  326. package/src/migrations/services/UserMappingService.ts +345 -0
  327. package/src/migrations/services/ValidationService.ts +349 -0
  328. package/src/migrations/transfer.ts +1068 -0
  329. package/src/migrations/yaml/YamlImportConfigLoader.ts +439 -0
  330. package/src/migrations/yaml/YamlImportIntegration.ts +446 -0
  331. package/src/migrations/yaml/generateImportSchemas.ts +1354 -0
  332. package/src/schemas/authUser.ts +23 -0
  333. package/src/setup.ts +8 -0
  334. package/src/setupCommands.ts +603 -0
  335. package/src/setupController.ts +43 -0
  336. package/src/shared/attributeMapper.ts +229 -0
  337. package/src/shared/backupMetadataSchema.ts +93 -0
  338. package/src/shared/backupTracking.ts +211 -0
  339. package/src/shared/confirmationDialogs.ts +327 -0
  340. package/src/shared/errorUtils.ts +110 -0
  341. package/src/shared/functionManager.ts +525 -0
  342. package/src/shared/indexManager.ts +254 -0
  343. package/src/shared/jsonSchemaGenerator.ts +383 -0
  344. package/src/shared/logging.ts +149 -0
  345. package/src/shared/messageFormatter.ts +208 -0
  346. package/src/shared/migrationHelpers.ts +232 -0
  347. package/src/shared/operationLogger.ts +20 -0
  348. package/src/shared/operationQueue.ts +377 -0
  349. package/src/shared/operationsTable.ts +338 -0
  350. package/src/shared/operationsTableSchema.ts +60 -0
  351. package/src/shared/progressManager.ts +278 -0
  352. package/src/shared/pydanticModelGenerator.ts +618 -0
  353. package/src/shared/relationshipExtractor.ts +214 -0
  354. package/src/shared/schemaGenerator.ts +644 -0
  355. package/src/shared/selectionDialogs.ts +749 -0
  356. package/src/storage/backupCompression.ts +88 -0
  357. package/src/storage/methods.ts +698 -0
  358. package/src/storage/schemas.ts +205 -0
  359. package/src/types/node-appwrite-tablesdb.d.ts +44 -0
  360. package/src/types.ts +9 -0
  361. package/src/users/methods.ts +359 -0
  362. package/src/utils/ClientFactory.ts +240 -0
  363. package/src/utils/configDiscovery.ts +557 -0
  364. package/src/utils/configMigration.ts +348 -0
  365. package/src/utils/constantsGenerator.ts +369 -0
  366. package/src/utils/dataConverters.ts +159 -0
  367. package/src/utils/directoryUtils.ts +61 -0
  368. package/src/utils/getClientFromConfig.ts +257 -0
  369. package/src/utils/helperFunctions.ts +228 -0
  370. package/src/utils/index.ts +2 -0
  371. package/src/utils/loadConfigs.ts +449 -0
  372. package/src/utils/pathResolvers.ts +81 -0
  373. package/src/utils/projectConfig.ts +299 -0
  374. package/src/utils/retryFailedPromises.ts +29 -0
  375. package/src/utils/sessionAuth.ts +230 -0
  376. package/src/utils/setupFiles.ts +1238 -0
  377. package/src/utils/typeGuards.ts +65 -0
  378. package/src/utils/validationRules.ts +88 -0
  379. package/src/utils/versionDetection.ts +292 -0
  380. package/src/utils/yamlConverter.ts +542 -0
  381. package/src/utils/yamlLoader.ts +371 -0
  382. package/src/utilsController.ts +1203 -0
  383. package/tests/README.md +497 -0
  384. package/tests/adapters/AdapterFactory.test.ts +277 -0
  385. package/tests/integration/syncOperations.test.ts +463 -0
  386. package/tests/jest.config.js +25 -0
  387. package/tests/migration/configMigration.test.ts +546 -0
  388. package/tests/setup.ts +62 -0
  389. package/tests/testUtils.ts +340 -0
  390. package/tests/utils/loadConfigs.test.ts +350 -0
  391. package/tests/validation/configValidation.test.ts +412 -0
  392. package/tsconfig.json +44 -0
@@ -0,0 +1,749 @@
1
+ import inquirer from "inquirer";
2
+ import chalk from "chalk";
3
+ import { join } from "node:path";
4
+ import { MessageFormatter } from "../../shared/messageFormatter.js";
5
+ import { ConfirmationDialogs } from "../../shared/confirmationDialogs.js";
6
+ import { SelectionDialogs } from "../../shared/selectionDialogs.js";
7
+ import type { DatabaseSelection, BucketSelection } from "../../shared/selectionDialogs.js";
8
+ import { logger } from "../../shared/logging.js";
9
+ import { fetchAllDatabases } from "../../databases/methods.js";
10
+ import { listBuckets } from "../../storage/methods.js";
11
+ import { getFunction, downloadLatestFunctionDeployment } from "../../functions/methods.js";
12
+ import type { InteractiveCLI } from "../../interactiveCLI.js";
13
+
14
+ export const databaseCommands = {
15
+ async syncDb(cli: InteractiveCLI): Promise<void> {
16
+ MessageFormatter.progress("Pushing local configuration to Appwrite...", { prefix: "Database" });
17
+
18
+ try {
19
+ // Initialize controller
20
+ await (cli as any).controller!.init();
21
+
22
+ // Get available and configured databases
23
+ const availableDatabases = await fetchAllDatabases((cli as any).controller!.database!);
24
+ const configuredDatabases = (cli as any).controller!.config?.databases || [];
25
+
26
+ // Get local collections for selection
27
+ const localCollections = (cli as any).getLocalCollections();
28
+
29
+ // Push operations always use local configuration as source of truth
30
+
31
+ // Select databases
32
+ const selectedDatabaseIds = await SelectionDialogs.selectDatabases(
33
+ availableDatabases,
34
+ configuredDatabases,
35
+ { showSelectAll: false, allowNewOnly: false, defaultSelected: [] }
36
+ );
37
+
38
+ if (selectedDatabaseIds.length === 0) {
39
+ MessageFormatter.warning("No databases selected. Skipping database sync.", { prefix: "Database" });
40
+ return;
41
+ }
42
+
43
+ // Select tables/collections for each database using the existing method
44
+ const tableSelectionsMap = new Map<string, string[]>();
45
+ const availableTablesMap = new Map<string, any[]>();
46
+
47
+ for (const databaseId of selectedDatabaseIds) {
48
+ const database = availableDatabases.find(db => db.$id === databaseId)!;
49
+
50
+ // Use the existing selectCollectionsAndTables method
51
+ const selectedCollections = await (cli as any).selectCollectionsAndTables(
52
+ database,
53
+ (cli as any).controller!.database!,
54
+ chalk.blue(`Select collections/tables to push to "${database.name}":`),
55
+ true, // multiSelect
56
+ true, // prefer local
57
+ true // shouldFilterByDatabase
58
+ );
59
+
60
+ // Map selected collections to table IDs
61
+ const selectedTableIds = selectedCollections.map((c: any) => c.$id || c.id);
62
+
63
+ // Store selections
64
+ tableSelectionsMap.set(databaseId, selectedTableIds);
65
+ availableTablesMap.set(databaseId, selectedCollections);
66
+
67
+ if (selectedCollections.length === 0) {
68
+ MessageFormatter.warning(`No collections selected for database "${database.name}". Skipping.`, { prefix: "Database" });
69
+ continue;
70
+ }
71
+ }
72
+
73
+ // Ask if user wants to select buckets
74
+ const { selectBuckets } = await inquirer.prompt([
75
+ {
76
+ type: "confirm",
77
+ name: "selectBuckets",
78
+ message: "Do you want to select storage buckets to sync as well?",
79
+ default: false,
80
+ },
81
+ ]);
82
+
83
+ let bucketSelections: BucketSelection[] = [];
84
+
85
+ if (selectBuckets) {
86
+ // Get available and configured buckets
87
+ try {
88
+ const availableBucketsResponse = await listBuckets((cli as any).controller!.storage!);
89
+ const availableBuckets = availableBucketsResponse.buckets || [];
90
+ const configuredBuckets = (cli as any).controller!.config?.buckets || [];
91
+
92
+ if (availableBuckets.length === 0) {
93
+ MessageFormatter.warning("No storage buckets available in remote instance.", { prefix: "Database" });
94
+ } else {
95
+ // Select buckets using SelectionDialogs
96
+ const selectedBucketIds = await SelectionDialogs.selectBucketsForDatabases(
97
+ selectedDatabaseIds,
98
+ availableBuckets,
99
+ configuredBuckets,
100
+ { showSelectAll: false, groupByDatabase: true, defaultSelected: [] }
101
+ );
102
+
103
+ if (selectedBucketIds.length > 0) {
104
+ // Create BucketSelection objects
105
+ bucketSelections = SelectionDialogs.createBucketSelection(
106
+ selectedBucketIds,
107
+ availableBuckets,
108
+ configuredBuckets,
109
+ availableDatabases
110
+ );
111
+
112
+ MessageFormatter.info(`Selected ${bucketSelections.length} storage bucket(s)`, { prefix: "Database" });
113
+ }
114
+ }
115
+ } catch (error) {
116
+ MessageFormatter.warning("Failed to fetch storage buckets. Continuing with databases only.", { prefix: "Database" });
117
+ logger.warn("Storage bucket fetch failed during syncDb", { error: error instanceof Error ? error.message : String(error) });
118
+ }
119
+ }
120
+
121
+ // Create DatabaseSelection objects
122
+ const databaseSelections = SelectionDialogs.createDatabaseSelection(
123
+ selectedDatabaseIds,
124
+ availableDatabases,
125
+ tableSelectionsMap,
126
+ configuredDatabases,
127
+ availableTablesMap
128
+ );
129
+
130
+ // Show confirmation summary
131
+ const selectionSummary = SelectionDialogs.createSyncSelectionSummary(
132
+ databaseSelections,
133
+ bucketSelections
134
+ );
135
+
136
+ const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary, 'push');
137
+
138
+ if (!confirmed) {
139
+ MessageFormatter.info("Push operation cancelled by user", { prefix: "Database" });
140
+ return;
141
+ }
142
+
143
+ // Perform selective push using the controller
144
+ MessageFormatter.progress("Starting selective push...", { prefix: "Database" });
145
+ await (cli as any).controller!.selectivePush(databaseSelections, bucketSelections);
146
+
147
+ MessageFormatter.success("\n✅ All database configurations pushed successfully!", { prefix: "Database" });
148
+
149
+ // Then handle functions if requested
150
+ const { syncFunctions } = await inquirer.prompt([
151
+ {
152
+ type: "confirm",
153
+ name: "syncFunctions",
154
+ message: "Do you want to push local functions to remote?",
155
+ default: false,
156
+ },
157
+ ]);
158
+
159
+ if (syncFunctions && (cli as any).controller!.config?.functions?.length) {
160
+ const functions = await (cli as any).selectFunctions(
161
+ chalk.blue("Select local functions to push:"),
162
+ true,
163
+ true // prefer local
164
+ );
165
+
166
+ for (const func of functions) {
167
+ try {
168
+ await (cli as any).controller!.deployFunction(func.name);
169
+ MessageFormatter.success(`Function ${func.name} deployed successfully`, { prefix: "Functions" });
170
+ } catch (error) {
171
+ MessageFormatter.error(`Failed to deploy function ${func.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
172
+ }
173
+ }
174
+ }
175
+
176
+ MessageFormatter.success("Local configuration push completed successfully!", { prefix: "Database" });
177
+ } catch (error) {
178
+ MessageFormatter.error("Failed to push local configuration", error instanceof Error ? error : new Error(String(error)), { prefix: "Database" });
179
+ throw error;
180
+ }
181
+ },
182
+
183
+ async synchronizeConfigurations(cli: InteractiveCLI): Promise<void> {
184
+ MessageFormatter.progress("Synchronizing configurations...", { prefix: "Config" });
185
+ await (cli as any).controller!.init();
186
+
187
+ // Sync databases, collections, and buckets
188
+ const { syncDatabases } = await inquirer.prompt([
189
+ {
190
+ type: "confirm",
191
+ name: "syncDatabases",
192
+ message: "Do you want to synchronize databases, collections, and their buckets?",
193
+ default: true,
194
+ },
195
+ ]);
196
+
197
+ if (syncDatabases) {
198
+ const remoteDatabases = await fetchAllDatabases(
199
+ (cli as any).controller!.database!
200
+ );
201
+
202
+ // First, prepare the combined database list for bucket configuration
203
+ const localDatabases = (cli as any).controller!.config?.databases || [];
204
+ const allDatabases = [
205
+ ...localDatabases,
206
+ ...remoteDatabases.filter(
207
+ (rd: any) => !localDatabases.some((ld: any) => ld.name === rd.name)
208
+ ),
209
+ ];
210
+
211
+ // Configure buckets FIRST to get user selections before writing config
212
+ MessageFormatter.progress("Configuring storage buckets...", { prefix: "Buckets" });
213
+ const configWithBuckets = await (cli as any).configureBuckets({
214
+ ...(cli as any).controller!.config!,
215
+ databases: allDatabases,
216
+ });
217
+
218
+ // Update controller config with bucket selections
219
+ (cli as any).controller!.config = configWithBuckets;
220
+
221
+ // Now synchronize configurations with the updated config that includes bucket selections
222
+ MessageFormatter.progress("Pulling collections and generating collection files...", { prefix: "Collections" });
223
+ await (cli as any).controller!.synchronizeConfigurations(remoteDatabases, configWithBuckets);
224
+ }
225
+
226
+ // Then sync functions
227
+ const { syncFunctions } = await inquirer.prompt([
228
+ {
229
+ type: "confirm",
230
+ name: "syncFunctions",
231
+ message: "Do you want to synchronize functions?",
232
+ default: true,
233
+ },
234
+ ]);
235
+
236
+ if (syncFunctions) {
237
+ const remoteFunctions = await (cli as any).controller!.listAllFunctions();
238
+ const localFunctions = (cli as any).controller!.config?.functions || [];
239
+
240
+ const allFunctions = [
241
+ ...remoteFunctions,
242
+ ...localFunctions.filter(
243
+ (f: any) => !remoteFunctions.some((rf: any) => rf.$id === f.$id)
244
+ ),
245
+ ];
246
+
247
+ for (const func of allFunctions) {
248
+ const hasLocal = localFunctions.some((lf: any) => lf.$id === func.$id);
249
+ const hasRemote = remoteFunctions.some((rf: any) => rf.$id === func.$id);
250
+
251
+ if (hasLocal && hasRemote) {
252
+ // Function exists in both local and remote
253
+ const { preference } = await inquirer.prompt([
254
+ {
255
+ type: "list",
256
+ name: "preference",
257
+ message: `Function "${func.name}" exists both locally and remotely. What would you like to do?`,
258
+ choices: [
259
+ { name: "Keep local version (deploy to remote)", value: "local" },
260
+ { name: "Use remote version (download)", value: "remote" },
261
+ { name: "Update config only", value: "config" },
262
+ { name: "Skip this function", value: "skip" },
263
+ ],
264
+ },
265
+ ]);
266
+
267
+ if (preference === "local") {
268
+ await (cli as any).controller!.deployFunction(func.name);
269
+ } else if (preference === "remote") {
270
+ await downloadLatestFunctionDeployment(
271
+ (cli as any).controller!.appwriteServer!,
272
+ func.$id,
273
+ join((cli as any).controller!.getAppwriteFolderPath()!, "functions")
274
+ );
275
+ } else if (preference === "config") {
276
+ // Update config with remote function details
277
+ const remoteFunction = await getFunction(
278
+ (cli as any).controller!.appwriteServer!,
279
+ func.$id
280
+ );
281
+
282
+ const newFunction = {
283
+ $id: remoteFunction.$id,
284
+ name: remoteFunction.name,
285
+ runtime: remoteFunction.runtime,
286
+ execute: remoteFunction.execute || [],
287
+ events: remoteFunction.events || [],
288
+ schedule: remoteFunction.schedule || "",
289
+ timeout: remoteFunction.timeout || 15,
290
+ enabled: remoteFunction.enabled !== false,
291
+ logging: remoteFunction.logging !== false,
292
+ entrypoint: remoteFunction.entrypoint || "src/index.ts",
293
+ commands: remoteFunction.commands || "npm install",
294
+ scopes: remoteFunction.scopes || [],
295
+ installationId: remoteFunction.installationId,
296
+ providerRepositoryId: remoteFunction.providerRepositoryId,
297
+ providerBranch: remoteFunction.providerBranch,
298
+ providerSilentMode: remoteFunction.providerSilentMode,
299
+ providerRootDirectory: remoteFunction.providerRootDirectory,
300
+ specification: remoteFunction.specification,
301
+ };
302
+
303
+ const existingIndex = (cli as any).controller!.config!.functions!.findIndex(
304
+ (f: any) => f.$id === remoteFunction.$id
305
+ );
306
+
307
+ if (existingIndex >= 0) {
308
+ (cli as any).controller!.config!.functions![existingIndex] = newFunction;
309
+ } else {
310
+ (cli as any).controller!.config!.functions!.push(newFunction);
311
+ }
312
+ MessageFormatter.success(`Updated config for function: ${func.name}`, { prefix: "Functions" });
313
+ }
314
+ } else if (hasLocal) {
315
+ // Function exists only locally
316
+ const { action } = await inquirer.prompt([
317
+ {
318
+ type: "list",
319
+ name: "action",
320
+ message: `Function "${func.name}" exists only locally. What would you like to do?`,
321
+ choices: [
322
+ { name: "Deploy to remote", value: "deploy" },
323
+ { name: "Skip this function", value: "skip" },
324
+ ],
325
+ },
326
+ ]);
327
+
328
+ if (action === "deploy") {
329
+ await (cli as any).controller!.deployFunction(func.name);
330
+ }
331
+ } else if (hasRemote) {
332
+ // Function exists only remotely
333
+ const { action } = await inquirer.prompt([
334
+ {
335
+ type: "list",
336
+ name: "action",
337
+ message: `Function "${func.name}" exists only remotely. What would you like to do?`,
338
+ choices: [
339
+ { name: "Update config only", value: "config" },
340
+ { name: "Download locally", value: "download" },
341
+ { name: "Skip this function", value: "skip" },
342
+ ],
343
+ },
344
+ ]);
345
+
346
+ if (action === "download") {
347
+ await downloadLatestFunctionDeployment(
348
+ (cli as any).controller!.appwriteServer!,
349
+ func.$id,
350
+ join((cli as any).controller!.getAppwriteFolderPath()!, "functions")
351
+ );
352
+ } else if (action === "config") {
353
+ const remoteFunction = await getFunction(
354
+ (cli as any).controller!.appwriteServer!,
355
+ func.$id
356
+ );
357
+
358
+ const newFunction = {
359
+ $id: remoteFunction.$id,
360
+ name: remoteFunction.name,
361
+ runtime: remoteFunction.runtime,
362
+ execute: remoteFunction.execute || [],
363
+ events: remoteFunction.events || [],
364
+ schedule: remoteFunction.schedule || "",
365
+ timeout: remoteFunction.timeout || 15,
366
+ enabled: remoteFunction.enabled !== false,
367
+ logging: remoteFunction.logging !== false,
368
+ entrypoint: remoteFunction.entrypoint || "src/index.ts",
369
+ commands: remoteFunction.commands || "npm install",
370
+ scopes: remoteFunction.scopes || [],
371
+ installationId: remoteFunction.installationId,
372
+ providerRepositoryId: remoteFunction.providerRepositoryId,
373
+ providerBranch: remoteFunction.providerBranch,
374
+ providerSilentMode: remoteFunction.providerSilentMode,
375
+ providerRootDirectory: remoteFunction.providerRootDirectory,
376
+ specification: remoteFunction.specification,
377
+ };
378
+
379
+ (cli as any).controller!.config!.functions =
380
+ (cli as any).controller!.config!.functions || [];
381
+ (cli as any).controller!.config!.functions.push(newFunction);
382
+ MessageFormatter.success(`Added config for remote function: ${func.name}`, { prefix: "Functions" });
383
+ }
384
+ }
385
+ }
386
+ }
387
+
388
+ MessageFormatter.success("✨ Configurations synchronized successfully!", { prefix: "Config" });
389
+ },
390
+
391
+ async backupDatabase(cli: InteractiveCLI): Promise<void> {
392
+ if (!(cli as any).controller!.database || !(cli as any).controller!.storage) {
393
+ throw new Error(
394
+ "Database or Storage is not initialized, is the config file correct & created?"
395
+ );
396
+ }
397
+
398
+ try {
399
+ // STEP 1: Select tracking database
400
+ MessageFormatter.info("Step 1/5: Select tracking database", { prefix: "Backup" });
401
+ const trackingDb = await this.selectTrackingDatabase(cli);
402
+
403
+ // STEP 2: Ensure backup tracking table exists
404
+ MessageFormatter.info("Step 2/5: Initializing backup tracking", { prefix: "Backup" });
405
+ await this.ensureBackupTrackingTable(cli, trackingDb);
406
+
407
+ // STEP 3: Select backup scope
408
+ MessageFormatter.info("Step 3/5: Select backup scope", { prefix: "Backup" });
409
+ const scope = await this.selectBackupScope(cli);
410
+
411
+ // STEP 4: Show confirmation
412
+ MessageFormatter.info("Step 4/5: Confirm backup plan", { prefix: "Backup" });
413
+ const confirmed = await this.confirmBackupPlan(scope);
414
+ if (!confirmed) {
415
+ MessageFormatter.info("Backup cancelled by user", { prefix: "Backup" });
416
+ return;
417
+ }
418
+
419
+ // STEP 5: Execute unified backup
420
+ MessageFormatter.info("Step 5/5: Executing backup", { prefix: "Backup" });
421
+ await this.executeUnifiedBackup(cli, trackingDb, scope);
422
+
423
+ MessageFormatter.success("Backup operation completed successfully", { prefix: "Backup" });
424
+ } catch (error) {
425
+ MessageFormatter.error(
426
+ "Backup operation failed",
427
+ error instanceof Error ? error : new Error(String(error)),
428
+ { prefix: "Backup" }
429
+ );
430
+ throw error;
431
+ }
432
+ },
433
+
434
+ // Helper method: Select tracking database
435
+ async selectTrackingDatabase(cli: InteractiveCLI): Promise<string> {
436
+ const databases = await fetchAllDatabases((cli as any).controller!.database);
437
+
438
+ const { trackingDatabaseId } = await inquirer.prompt([
439
+ {
440
+ type: "list",
441
+ name: "trackingDatabaseId",
442
+ message: "Select database to store backup metadata:",
443
+ choices: databases.map(db => ({
444
+ name: `${db.name} (${db.$id})`,
445
+ value: db.$id
446
+ }))
447
+ }
448
+ ]);
449
+
450
+ MessageFormatter.info(`Using ${trackingDatabaseId} for backup tracking`, { prefix: "Backup" });
451
+ return trackingDatabaseId;
452
+ },
453
+
454
+ // Helper method: Ensure backup tracking table exists
455
+ async ensureBackupTrackingTable(cli: InteractiveCLI, trackingDatabaseId: string): Promise<void> {
456
+ const { createCentralizedBackupTrackingTable } = await import("../../backups/tracking/centralizedTracking.js");
457
+ const adapter = (cli as any).controller!.adapter;
458
+
459
+ await createCentralizedBackupTrackingTable(adapter, trackingDatabaseId);
460
+ MessageFormatter.success("Backup tracking table ready", { prefix: "Backup" });
461
+ },
462
+
463
+ // Helper method: Select backup scope
464
+ async selectBackupScope(cli: InteractiveCLI): Promise<any> {
465
+ const { scopeType } = await inquirer.prompt([
466
+ {
467
+ type: "list",
468
+ name: "scopeType",
469
+ message: "What would you like to backup?",
470
+ choices: [
471
+ { name: "Comprehensive (ALL databases + ALL buckets)", value: "comprehensive" },
472
+ { name: "Selective databases (choose specific databases)", value: "selective-databases" },
473
+ { name: "Selective collections (choose specific collections)", value: "selective-collections" }
474
+ ]
475
+ }
476
+ ]);
477
+
478
+ if (scopeType === "comprehensive") {
479
+ return { type: "comprehensive" };
480
+ }
481
+
482
+ if (scopeType === "selective-databases") {
483
+ const databases = await fetchAllDatabases((cli as any).controller!.database);
484
+ const selectedDatabases = await (cli as any).selectDatabases(
485
+ databases,
486
+ "Select databases to backup:"
487
+ );
488
+
489
+ const { includeBuckets } = await inquirer.prompt([
490
+ {
491
+ type: "confirm",
492
+ name: "includeBuckets",
493
+ message: "Include storage buckets in backup?",
494
+ default: false
495
+ }
496
+ ]);
497
+
498
+ let selectedBuckets: string[] = [];
499
+ if (includeBuckets) {
500
+ const buckets = await listBuckets((cli as any).controller!.storage);
501
+ const { bucketIds } = await inquirer.prompt([
502
+ {
503
+ type: "checkbox",
504
+ name: "bucketIds",
505
+ message: "Select buckets to backup:",
506
+ choices: buckets.buckets.map((b: any) => ({
507
+ name: `${b.name} (${b.$id})`,
508
+ value: b.$id
509
+ }))
510
+ }
511
+ ]);
512
+ selectedBuckets = bucketIds;
513
+ }
514
+
515
+ return {
516
+ type: "selective-databases",
517
+ databases: selectedDatabases,
518
+ buckets: selectedBuckets
519
+ };
520
+ }
521
+
522
+ if (scopeType === "selective-collections") {
523
+ const databases = await fetchAllDatabases((cli as any).controller!.database);
524
+ const selectedDatabase = await (cli as any).selectDatabases(
525
+ databases,
526
+ "Select database containing collections:",
527
+ false // single selection
528
+ );
529
+
530
+ if (!selectedDatabase || selectedDatabase.length === 0) {
531
+ throw new Error("No database selected");
532
+ }
533
+
534
+ const db = selectedDatabase[0];
535
+ const collections = await (cli as any).selectCollectionsAndTables(
536
+ db,
537
+ (cli as any).controller!.database!,
538
+ "Select collections to backup:",
539
+ true,
540
+ true,
541
+ true
542
+ );
543
+
544
+ return {
545
+ type: "selective-collections",
546
+ databaseId: db.$id,
547
+ databaseName: db.name,
548
+ collections: collections
549
+ };
550
+ }
551
+
552
+ throw new Error("Invalid backup scope selected");
553
+ },
554
+
555
+ // Helper method: Confirm backup plan
556
+ async confirmBackupPlan(scope: any): Promise<boolean> {
557
+ let summary = "\n" + chalk.bold("Backup Plan Summary:") + "\n";
558
+
559
+ if (scope.type === "comprehensive") {
560
+ summary += " • ALL databases\n";
561
+ summary += " • ALL storage buckets\n";
562
+ } else if (scope.type === "selective-databases") {
563
+ summary += ` • ${scope.databases.length} selected databases\n`;
564
+ if (scope.buckets.length > 0) {
565
+ summary += ` • ${scope.buckets.length} selected buckets\n`;
566
+ }
567
+ } else if (scope.type === "selective-collections") {
568
+ summary += ` • Database: ${scope.databaseName}\n`;
569
+ summary += ` • ${scope.collections.length} selected collections\n`;
570
+ }
571
+
572
+ console.log(summary);
573
+
574
+ const { confirmed } = await inquirer.prompt([
575
+ {
576
+ type: "confirm",
577
+ name: "confirmed",
578
+ message: "Proceed with backup?",
579
+ default: true
580
+ }
581
+ ]);
582
+
583
+ return confirmed;
584
+ },
585
+
586
+ // Helper method: Execute unified backup
587
+ async executeUnifiedBackup(cli: InteractiveCLI, trackingDatabaseId: string, scope: any): Promise<void> {
588
+ if (scope.type === "comprehensive") {
589
+ const { comprehensiveBackup } = await import("../../backups/operations/comprehensiveBackup.js");
590
+
591
+ await comprehensiveBackup(
592
+ (cli as any).controller!.config,
593
+ (cli as any).controller!.database,
594
+ (cli as any).controller!.storage,
595
+ (cli as any).controller!.adapter,
596
+ {
597
+ trackingDatabaseId,
598
+ backupFormat: 'zip',
599
+ parallelDownloads: 10,
600
+ onProgress: (message: string) => {
601
+ MessageFormatter.progress(message, { prefix: "Backup" });
602
+ }
603
+ }
604
+ );
605
+ } else if (scope.type === "selective-databases") {
606
+ // Backup each selected database
607
+ for (const db of scope.databases) {
608
+ MessageFormatter.progress(`Backing up database: ${db.name}`, { prefix: "Backup" });
609
+ await (cli as any).controller!.backupDatabase(db);
610
+ }
611
+
612
+ // Backup selected buckets if any
613
+ for (const bucketId of scope.buckets) {
614
+ MessageFormatter.progress(`Backing up bucket: ${bucketId}`, { prefix: "Backup" });
615
+ const { backupBucket } = await import("../../backups/operations/bucketBackup.js");
616
+ await backupBucket(
617
+ (cli as any).controller!.storage,
618
+ bucketId,
619
+ "appwrite-backups",
620
+ { parallelDownloads: 10 }
621
+ );
622
+ }
623
+ } else if (scope.type === "selective-collections") {
624
+ const { backupCollections } = await import("../../backups/operations/collectionBackup.js");
625
+
626
+ await backupCollections(
627
+ (cli as any).controller!.config,
628
+ (cli as any).controller!.database,
629
+ (cli as any).controller!.storage,
630
+ (cli as any).controller!.adapter,
631
+ {
632
+ trackingDatabaseId,
633
+ databaseId: scope.databaseId,
634
+ collectionIds: scope.collections.map((c: any) => c.$id || c.id),
635
+ backupFormat: 'zip',
636
+ onProgress: (message: string) => {
637
+ MessageFormatter.progress(message, { prefix: "Backup" });
638
+ }
639
+ }
640
+ );
641
+ }
642
+ },
643
+
644
+ async wipeDatabase(cli: InteractiveCLI): Promise<void> {
645
+ if (!(cli as any).controller!.database || !(cli as any).controller!.storage) {
646
+ throw new Error(
647
+ "Database or Storage is not initialized, is the config file correct & created?"
648
+ );
649
+ }
650
+ const databases = await fetchAllDatabases((cli as any).controller!.database);
651
+ const storage = await listBuckets((cli as any).controller!.storage);
652
+
653
+ const selectedDatabases = await (cli as any).selectDatabases(
654
+ databases,
655
+ "Select databases to wipe:"
656
+ );
657
+
658
+ const { selectedStorage } = await inquirer.prompt([
659
+ {
660
+ type: "checkbox",
661
+ name: "selectedStorage",
662
+ message: "Select storage buckets to wipe:",
663
+ choices: storage.buckets.map((s: any) => ({ name: s.name, value: s.$id })),
664
+ },
665
+ ]);
666
+
667
+ const { wipeUsers } = await inquirer.prompt([
668
+ {
669
+ type: "confirm",
670
+ name: "wipeUsers",
671
+ message: "Do you want to wipe users as well?",
672
+ default: false,
673
+ },
674
+ ]);
675
+
676
+ const databaseNames = selectedDatabases.map((db: any) => db.name);
677
+ const confirmed = await ConfirmationDialogs.confirmDatabaseWipe(databaseNames, {
678
+ includeStorage: selectedStorage.length > 0,
679
+ includeUsers: wipeUsers
680
+ });
681
+
682
+ if (confirmed) {
683
+ MessageFormatter.info("Starting wipe operation...", { prefix: "Wipe" });
684
+ for (const db of selectedDatabases) {
685
+ await (cli as any).controller!.wipeDatabase(db);
686
+ }
687
+ for (const bucketId of selectedStorage) {
688
+ await (cli as any).controller!.wipeDocumentStorage(bucketId);
689
+ }
690
+ if (wipeUsers) {
691
+ await (cli as any).controller!.wipeUsers();
692
+ }
693
+ MessageFormatter.success("Wipe operation completed", { prefix: "Wipe" });
694
+ } else {
695
+ MessageFormatter.info("Wipe operation cancelled", { prefix: "Wipe" });
696
+ }
697
+ },
698
+
699
+ async wipeCollections(cli: InteractiveCLI): Promise<void> {
700
+ if (!(cli as any).controller!.database) {
701
+ throw new Error(
702
+ "Database is not initialized, is the config file correct & created?"
703
+ );
704
+ }
705
+ const databases = await fetchAllDatabases((cli as any).controller!.database);
706
+ const selectedDatabases = await (cli as any).selectDatabases(
707
+ databases,
708
+ "Select the database(s) containing the collections to wipe:",
709
+ true
710
+ );
711
+
712
+ for (const database of selectedDatabases) {
713
+ const collections = await (cli as any).selectCollectionsAndTables(
714
+ database,
715
+ (cli as any).controller!.database,
716
+ `Select collections/tables to wipe from ${database.name}:`,
717
+ true,
718
+ undefined,
719
+ true
720
+ );
721
+
722
+ const collectionNames = collections.map((c: any) => c.name);
723
+ const confirmed = await ConfirmationDialogs.confirmCollectionWipe(
724
+ database.name,
725
+ collectionNames
726
+ );
727
+
728
+ if (confirmed) {
729
+ MessageFormatter.info(
730
+ `Wiping selected collections from ${database.name}...`,
731
+ { prefix: "Wipe" }
732
+ );
733
+ for (const collection of collections) {
734
+ await (cli as any).controller!.wipeCollection(database, collection);
735
+ MessageFormatter.success(
736
+ `Collection ${collection.name} wiped successfully`,
737
+ { prefix: "Wipe" }
738
+ );
739
+ }
740
+ } else {
741
+ MessageFormatter.info(
742
+ `Wipe operation cancelled for ${database.name}`,
743
+ { prefix: "Wipe" }
744
+ );
745
+ }
746
+ }
747
+ MessageFormatter.success("Wipe collections operation completed", { prefix: "Wipe" });
748
+ }
749
+ };