appwrite-utils-cli 1.11.0 → 1.12.0

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 (250) hide show
  1. package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -1
  2. package/dist/adapters/index.js +10 -0
  3. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  4. package/dist/backups/operations/bucketBackup.js +197 -0
  5. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  6. package/dist/backups/operations/collectionBackup.js +201 -0
  7. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  8. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  9. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  10. package/dist/backups/schemas/bucketManifest.js +33 -0
  11. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  12. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  13. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  14. package/dist/backups/tracking/centralizedTracking.js +274 -0
  15. package/dist/cli/commands/configCommands.d.ts +8 -0
  16. package/dist/cli/commands/configCommands.js +210 -0
  17. package/dist/cli/commands/databaseCommands.d.ts +14 -0
  18. package/dist/cli/commands/databaseCommands.js +696 -0
  19. package/dist/cli/commands/functionCommands.d.ts +7 -0
  20. package/dist/cli/commands/functionCommands.js +330 -0
  21. package/dist/cli/commands/importFileCommands.d.ts +7 -0
  22. package/dist/cli/commands/importFileCommands.js +674 -0
  23. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  24. package/dist/cli/commands/schemaCommands.js +169 -0
  25. package/dist/cli/commands/storageCommands.d.ts +5 -0
  26. package/dist/cli/commands/storageCommands.js +142 -0
  27. package/dist/cli/commands/transferCommands.d.ts +5 -0
  28. package/dist/cli/commands/transferCommands.js +382 -0
  29. package/dist/collections/columns.d.ts +13 -0
  30. package/dist/collections/columns.js +1339 -0
  31. package/dist/collections/indexes.d.ts +12 -0
  32. package/dist/collections/indexes.js +215 -0
  33. package/dist/collections/methods.d.ts +19 -0
  34. package/dist/collections/methods.js +605 -0
  35. package/dist/collections/tableOperations.d.ts +87 -0
  36. package/dist/collections/tableOperations.js +466 -0
  37. package/dist/collections/transferOperations.d.ts +8 -0
  38. package/dist/collections/transferOperations.js +411 -0
  39. package/dist/collections/wipeOperations.d.ts +17 -0
  40. package/dist/collections/wipeOperations.js +306 -0
  41. package/dist/databases/methods.d.ts +6 -0
  42. package/dist/databases/methods.js +35 -0
  43. package/dist/databases/setup.d.ts +5 -0
  44. package/dist/databases/setup.js +45 -0
  45. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  46. package/dist/examples/yamlTerminologyExample.js +272 -0
  47. package/dist/functions/deployments.d.ts +4 -0
  48. package/dist/functions/deployments.js +146 -0
  49. package/dist/functions/fnConfigDiscovery.d.ts +3 -0
  50. package/dist/functions/fnConfigDiscovery.js +108 -0
  51. package/dist/functions/methods.d.ts +16 -0
  52. package/dist/functions/methods.js +174 -0
  53. package/dist/init.d.ts +2 -0
  54. package/dist/init.js +57 -0
  55. package/dist/interactiveCLI.d.ts +36 -0
  56. package/dist/interactiveCLI.js +952 -0
  57. package/dist/main.d.ts +2 -0
  58. package/dist/main.js +1125 -0
  59. package/dist/migrations/afterImportActions.d.ts +17 -0
  60. package/dist/migrations/afterImportActions.js +305 -0
  61. package/dist/migrations/appwriteToX.d.ts +211 -0
  62. package/dist/migrations/appwriteToX.js +493 -0
  63. package/dist/migrations/comprehensiveTransfer.d.ts +147 -0
  64. package/dist/migrations/comprehensiveTransfer.js +1315 -0
  65. package/dist/migrations/dataLoader.d.ts +755 -0
  66. package/dist/migrations/dataLoader.js +1272 -0
  67. package/dist/migrations/importController.d.ts +25 -0
  68. package/dist/migrations/importController.js +283 -0
  69. package/dist/migrations/importDataActions.d.ts +50 -0
  70. package/dist/migrations/importDataActions.js +230 -0
  71. package/dist/migrations/relationships.d.ts +29 -0
  72. package/dist/migrations/relationships.js +203 -0
  73. package/dist/migrations/services/DataTransformationService.d.ts +55 -0
  74. package/dist/migrations/services/DataTransformationService.js +158 -0
  75. package/dist/migrations/services/FileHandlerService.d.ts +75 -0
  76. package/dist/migrations/services/FileHandlerService.js +236 -0
  77. package/dist/migrations/services/ImportOrchestrator.d.ts +99 -0
  78. package/dist/migrations/services/ImportOrchestrator.js +493 -0
  79. package/dist/migrations/services/RateLimitManager.d.ts +138 -0
  80. package/dist/migrations/services/RateLimitManager.js +279 -0
  81. package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
  82. package/dist/migrations/services/RelationshipResolver.js +332 -0
  83. package/dist/migrations/services/UserMappingService.d.ts +109 -0
  84. package/dist/migrations/services/UserMappingService.js +277 -0
  85. package/dist/migrations/services/ValidationService.d.ts +74 -0
  86. package/dist/migrations/services/ValidationService.js +260 -0
  87. package/dist/migrations/transfer.d.ts +30 -0
  88. package/dist/migrations/transfer.js +661 -0
  89. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +131 -0
  90. package/dist/migrations/yaml/YamlImportConfigLoader.js +383 -0
  91. package/dist/migrations/yaml/YamlImportIntegration.d.ts +93 -0
  92. package/dist/migrations/yaml/YamlImportIntegration.js +341 -0
  93. package/dist/migrations/yaml/generateImportSchemas.d.ts +30 -0
  94. package/dist/migrations/yaml/generateImportSchemas.js +1327 -0
  95. package/dist/schemas/authUser.d.ts +24 -0
  96. package/dist/schemas/authUser.js +17 -0
  97. package/dist/setup.d.ts +2 -0
  98. package/{src/setup.ts → dist/setup.js} +0 -3
  99. package/dist/setupCommands.d.ts +58 -0
  100. package/dist/setupCommands.js +489 -0
  101. package/dist/setupController.d.ts +9 -0
  102. package/dist/setupController.js +34 -0
  103. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  104. package/dist/shared/backupMetadataSchema.js +38 -0
  105. package/dist/shared/backupTracking.d.ts +18 -0
  106. package/dist/shared/backupTracking.js +176 -0
  107. package/dist/shared/confirmationDialogs.d.ts +75 -0
  108. package/dist/shared/confirmationDialogs.js +236 -0
  109. package/dist/shared/migrationHelpers.d.ts +61 -0
  110. package/dist/shared/migrationHelpers.js +145 -0
  111. package/{src/shared/operationLogger.ts → dist/shared/operationLogger.d.ts} +1 -11
  112. package/dist/shared/operationLogger.js +12 -0
  113. package/dist/shared/operationQueue.d.ts +40 -0
  114. package/dist/shared/operationQueue.js +310 -0
  115. package/dist/shared/operationsTable.d.ts +26 -0
  116. package/dist/shared/operationsTable.js +287 -0
  117. package/dist/shared/operationsTableSchema.d.ts +48 -0
  118. package/dist/shared/operationsTableSchema.js +35 -0
  119. package/dist/shared/progressManager.d.ts +62 -0
  120. package/dist/shared/progressManager.js +215 -0
  121. package/dist/shared/relationshipExtractor.d.ts +56 -0
  122. package/dist/shared/relationshipExtractor.js +138 -0
  123. package/dist/shared/selectionDialogs.d.ts +220 -0
  124. package/dist/shared/selectionDialogs.js +588 -0
  125. package/dist/storage/backupCompression.d.ts +20 -0
  126. package/dist/storage/backupCompression.js +67 -0
  127. package/dist/storage/methods.d.ts +44 -0
  128. package/dist/storage/methods.js +475 -0
  129. package/dist/storage/schemas.d.ts +842 -0
  130. package/dist/storage/schemas.js +175 -0
  131. package/dist/tables/indexManager.d.ts +65 -0
  132. package/dist/tables/indexManager.js +294 -0
  133. package/{src/types.ts → dist/types.d.ts} +1 -6
  134. package/dist/types.js +3 -0
  135. package/dist/users/methods.d.ts +16 -0
  136. package/dist/users/methods.js +276 -0
  137. package/dist/utils/configMigration.d.ts +1 -0
  138. package/dist/utils/configMigration.js +261 -0
  139. package/dist/utils/index.js +2 -0
  140. package/dist/utils/loadConfigs.d.ts +50 -0
  141. package/dist/utils/loadConfigs.js +357 -0
  142. package/dist/utils/setupFiles.d.ts +4 -0
  143. package/dist/utils/setupFiles.js +1190 -0
  144. package/dist/utilsController.d.ts +114 -0
  145. package/dist/utilsController.js +898 -0
  146. package/package.json +6 -3
  147. package/CHANGELOG.md +0 -35
  148. package/CONFIG_TODO.md +0 -1189
  149. package/SELECTION_DIALOGS.md +0 -146
  150. package/SERVICE_IMPLEMENTATION_REPORT.md +0 -462
  151. package/scripts/copy-templates.ts +0 -23
  152. package/src/backups/operations/bucketBackup.ts +0 -277
  153. package/src/backups/operations/collectionBackup.ts +0 -310
  154. package/src/backups/operations/comprehensiveBackup.ts +0 -342
  155. package/src/backups/schemas/bucketManifest.ts +0 -78
  156. package/src/backups/schemas/comprehensiveManifest.ts +0 -76
  157. package/src/backups/tracking/centralizedTracking.ts +0 -352
  158. package/src/cli/commands/configCommands.ts +0 -265
  159. package/src/cli/commands/databaseCommands.ts +0 -931
  160. package/src/cli/commands/functionCommands.ts +0 -419
  161. package/src/cli/commands/importFileCommands.ts +0 -815
  162. package/src/cli/commands/schemaCommands.ts +0 -200
  163. package/src/cli/commands/storageCommands.ts +0 -151
  164. package/src/cli/commands/transferCommands.ts +0 -454
  165. package/src/collections/attributes.ts.backup +0 -1555
  166. package/src/collections/columns.ts +0 -2025
  167. package/src/collections/indexes.ts +0 -350
  168. package/src/collections/methods.ts +0 -714
  169. package/src/collections/tableOperations.ts +0 -542
  170. package/src/collections/transferOperations.ts +0 -589
  171. package/src/collections/wipeOperations.ts +0 -449
  172. package/src/databases/methods.ts +0 -49
  173. package/src/databases/setup.ts +0 -77
  174. package/src/examples/yamlTerminologyExample.ts +0 -346
  175. package/src/functions/deployments.ts +0 -221
  176. package/src/functions/fnConfigDiscovery.ts +0 -103
  177. package/src/functions/methods.ts +0 -284
  178. package/src/init.ts +0 -62
  179. package/src/interactiveCLI.ts +0 -1201
  180. package/src/main.ts +0 -1517
  181. package/src/migrations/afterImportActions.ts +0 -579
  182. package/src/migrations/appwriteToX.ts +0 -668
  183. package/src/migrations/comprehensiveTransfer.ts +0 -2285
  184. package/src/migrations/dataLoader.ts +0 -1729
  185. package/src/migrations/importController.ts +0 -440
  186. package/src/migrations/importDataActions.ts +0 -315
  187. package/src/migrations/relationships.ts +0 -333
  188. package/src/migrations/services/DataTransformationService.ts +0 -196
  189. package/src/migrations/services/FileHandlerService.ts +0 -311
  190. package/src/migrations/services/ImportOrchestrator.ts +0 -675
  191. package/src/migrations/services/RateLimitManager.ts +0 -363
  192. package/src/migrations/services/RelationshipResolver.ts +0 -461
  193. package/src/migrations/services/UserMappingService.ts +0 -345
  194. package/src/migrations/services/ValidationService.ts +0 -349
  195. package/src/migrations/transfer.ts +0 -1113
  196. package/src/migrations/yaml/YamlImportConfigLoader.ts +0 -439
  197. package/src/migrations/yaml/YamlImportIntegration.ts +0 -446
  198. package/src/migrations/yaml/generateImportSchemas.ts +0 -1354
  199. package/src/schemas/authUser.ts +0 -23
  200. package/src/setupCommands.ts +0 -602
  201. package/src/setupController.ts +0 -43
  202. package/src/shared/backupMetadataSchema.ts +0 -93
  203. package/src/shared/backupTracking.ts +0 -211
  204. package/src/shared/confirmationDialogs.ts +0 -327
  205. package/src/shared/migrationHelpers.ts +0 -232
  206. package/src/shared/operationQueue.ts +0 -376
  207. package/src/shared/operationsTable.ts +0 -338
  208. package/src/shared/operationsTableSchema.ts +0 -60
  209. package/src/shared/progressManager.ts +0 -278
  210. package/src/shared/relationshipExtractor.ts +0 -214
  211. package/src/shared/selectionDialogs.ts +0 -802
  212. package/src/storage/backupCompression.ts +0 -88
  213. package/src/storage/methods.ts +0 -711
  214. package/src/storage/schemas.ts +0 -205
  215. package/src/tables/indexManager.ts +0 -409
  216. package/src/types/node-appwrite-tablesdb.d.ts +0 -44
  217. package/src/users/methods.ts +0 -358
  218. package/src/utils/configMigration.ts +0 -348
  219. package/src/utils/loadConfigs.ts +0 -457
  220. package/src/utils/setupFiles.ts +0 -1236
  221. package/src/utilsController.ts +0 -1263
  222. package/tests/README.md +0 -497
  223. package/tests/adapters/AdapterFactory.test.ts +0 -277
  224. package/tests/integration/syncOperations.test.ts +0 -463
  225. package/tests/jest.config.js +0 -25
  226. package/tests/migration/configMigration.test.ts +0 -546
  227. package/tests/setup.ts +0 -62
  228. package/tests/testUtils.ts +0 -340
  229. package/tests/utils/loadConfigs.test.ts +0 -350
  230. package/tests/validation/configValidation.test.ts +0 -412
  231. package/tsconfig.json +0 -44
  232. /package/{src → dist}/functions/templates/count-docs-in-collection/README.md +0 -0
  233. /package/{src → dist}/functions/templates/count-docs-in-collection/src/main.ts +0 -0
  234. /package/{src → dist}/functions/templates/count-docs-in-collection/src/request.ts +0 -0
  235. /package/{src → dist}/functions/templates/hono-typescript/README.md +0 -0
  236. /package/{src → dist}/functions/templates/hono-typescript/src/adapters/request.ts +0 -0
  237. /package/{src → dist}/functions/templates/hono-typescript/src/adapters/response.ts +0 -0
  238. /package/{src → dist}/functions/templates/hono-typescript/src/app.ts +0 -0
  239. /package/{src → dist}/functions/templates/hono-typescript/src/context.ts +0 -0
  240. /package/{src → dist}/functions/templates/hono-typescript/src/main.ts +0 -0
  241. /package/{src → dist}/functions/templates/hono-typescript/src/middleware/appwrite.ts +0 -0
  242. /package/{src → dist}/functions/templates/typescript-node/README.md +0 -0
  243. /package/{src → dist}/functions/templates/typescript-node/src/context.ts +0 -0
  244. /package/{src → dist}/functions/templates/typescript-node/src/main.ts +0 -0
  245. /package/{src → dist}/functions/templates/uv/README.md +0 -0
  246. /package/{src → dist}/functions/templates/uv/pyproject.toml +0 -0
  247. /package/{src → dist}/functions/templates/uv/src/__init__.py +0 -0
  248. /package/{src → dist}/functions/templates/uv/src/context.py +0 -0
  249. /package/{src → dist}/functions/templates/uv/src/main.py +0 -0
  250. /package/{src/utils/index.ts → dist/utils/index.d.ts} +0 -0
@@ -1,931 +0,0 @@
1
- import inquirer from "inquirer";
2
- import chalk from "chalk";
3
- import { join } from "node:path";
4
- import { Query } from "node-appwrite";
5
- import { MessageFormatter } from 'appwrite-utils-helpers';
6
- import { ConfirmationDialogs } from "../../shared/confirmationDialogs.js";
7
- import { SelectionDialogs } from "../../shared/selectionDialogs.js";
8
- import type { DatabaseSelection, BucketSelection } from "../../shared/selectionDialogs.js";
9
- import { logger } from 'appwrite-utils-helpers';
10
- import { fetchAllDatabases } from "../../databases/methods.js";
11
- import { listBuckets } from "../../storage/methods.js";
12
- import { getFunction, downloadLatestFunctionDeployment } from "../../functions/methods.js";
13
- import { wipeTableRows } from "../../collections/wipeOperations.js";
14
- import type { InteractiveCLI } from "../../interactiveCLI.js";
15
-
16
- export const databaseCommands = {
17
- async syncDb(cli: InteractiveCLI): Promise<void> {
18
- MessageFormatter.progress("Pushing local configuration to Appwrite...", { prefix: "Push" });
19
-
20
- try {
21
- // Initialize controller
22
- await (cli as any).controller!.init();
23
-
24
- // Ask what to push first
25
- const { pushTargets } = await inquirer.prompt([
26
- {
27
- type: "checkbox",
28
- name: "pushTargets",
29
- message: chalk.blue("What would you like to push to Appwrite?"),
30
- choices: [
31
- { name: "Databases & Tables", value: "databases" },
32
- { name: "Storage Buckets", value: "buckets" },
33
- { name: "Functions", value: "functions" },
34
- ],
35
- validate: (input: string[]) => {
36
- if (input.length === 0) {
37
- return "Please select at least one item to push.";
38
- }
39
- return true;
40
- },
41
- },
42
- ]);
43
-
44
- const pushDatabases = pushTargets.includes("databases");
45
- const pushBuckets = pushTargets.includes("buckets");
46
- const pushFunctions = pushTargets.includes("functions");
47
-
48
- let databaseSelections: DatabaseSelection[] = [];
49
- let bucketSelections: BucketSelection[] = [];
50
- let mergedDatabases: any[] = [];
51
-
52
- // --- Databases & Tables sub-flow ---
53
- if (pushDatabases) {
54
- const serverDatabases = await fetchAllDatabases((cli as any).controller!.database!);
55
- const configuredDatabases = (cli as any).controller!.config?.databases || [];
56
-
57
- const serverDbIds = new Set(serverDatabases.map(db => db.$id));
58
- mergedDatabases = [...serverDatabases];
59
-
60
- for (const configDb of configuredDatabases) {
61
- const dbId = configDb.$id;
62
- if (dbId && !serverDbIds.has(dbId)) {
63
- mergedDatabases.push({
64
- $id: dbId,
65
- name: configDb.name || dbId,
66
- $createdAt: new Date().toISOString(),
67
- $updatedAt: new Date().toISOString(),
68
- enabled: true,
69
- _isLocalOnly: true,
70
- } as any);
71
- MessageFormatter.info(`Including local database "${configDb.name || dbId}" (not yet on server)`, { prefix: "Database" });
72
- }
73
- }
74
-
75
- const selectedDatabaseIds = await SelectionDialogs.selectDatabases(
76
- mergedDatabases,
77
- configuredDatabases,
78
- { showSelectAll: false, allowNewOnly: false, defaultSelected: [] }
79
- );
80
-
81
- if (selectedDatabaseIds.length === 0) {
82
- MessageFormatter.warning("No databases selected.", { prefix: "Database" });
83
- } else {
84
- const tableSelectionsMap = new Map<string, string[]>();
85
- const availableTablesMap = new Map<string, any[]>();
86
-
87
- for (const databaseId of selectedDatabaseIds) {
88
- const database = mergedDatabases.find(db => db.$id === databaseId)!;
89
-
90
- const selectedCollections = await (cli as any).selectCollectionsAndTables(
91
- database,
92
- (cli as any).controller!.database!,
93
- chalk.blue(`Select tables to push to "${database.name}":`),
94
- true,
95
- true,
96
- true
97
- );
98
-
99
- const selectedTableIds = selectedCollections.map((c: any) => c.$id || c.id);
100
- tableSelectionsMap.set(databaseId, selectedTableIds);
101
- availableTablesMap.set(databaseId, selectedCollections);
102
-
103
- if (selectedCollections.length === 0) {
104
- MessageFormatter.warning(`No tables selected for database "${database.name}". Skipping.`, { prefix: "Database" });
105
- }
106
- }
107
-
108
- databaseSelections = SelectionDialogs.createDatabaseSelection(
109
- selectedDatabaseIds,
110
- mergedDatabases,
111
- tableSelectionsMap,
112
- configuredDatabases,
113
- availableTablesMap
114
- );
115
- }
116
- }
117
-
118
- // --- Storage Buckets sub-flow ---
119
- if (pushBuckets) {
120
- try {
121
- let remoteBuckets: any[] = [];
122
- try {
123
- const remoteBucketsResponse = await listBuckets((cli as any).controller!.storage!);
124
- remoteBuckets = remoteBucketsResponse.buckets || [];
125
- } catch (error) {
126
- MessageFormatter.warning("Could not fetch remote buckets, showing local buckets only.", { prefix: "Buckets" });
127
- }
128
-
129
- const configuredBuckets = (cli as any).controller!.config?.buckets || [];
130
-
131
- // Merge local + remote buckets
132
- const remoteBucketIds = new Set(remoteBuckets.map((b: any) => b.$id));
133
- const localBucketIds = new Set(configuredBuckets.map((b: any) => b.$id));
134
-
135
- const mergedBuckets: any[] = [];
136
-
137
- for (const rb of remoteBuckets) {
138
- mergedBuckets.push({
139
- ...rb,
140
- _isLocalOnly: false,
141
- _isRemoteOnly: !localBucketIds.has(rb.$id),
142
- });
143
- }
144
-
145
- for (const lb of configuredBuckets) {
146
- if (!remoteBucketIds.has(lb.$id)) {
147
- mergedBuckets.push({
148
- $id: lb.$id,
149
- name: lb.name,
150
- enabled: lb.enabled,
151
- maximumFileSize: lb.maximumFileSize,
152
- allowedFileExtensions: lb.allowedFileExtensions || [],
153
- compression: lb.compression || 'none',
154
- encryption: lb.encryption || false,
155
- antivirus: lb.antivirus || false,
156
- fileSecurity: lb.fileSecurity || false,
157
- permissions: lb.permissions || [],
158
- $permissions: [],
159
- _isLocalOnly: true,
160
- _isRemoteOnly: false,
161
- });
162
- }
163
- }
164
-
165
- if (mergedBuckets.length === 0) {
166
- MessageFormatter.warning("No storage buckets found (local or remote).", { prefix: "Buckets" });
167
- } else {
168
- const selectedBucketIds = await SelectionDialogs.selectBucketsForPush(
169
- mergedBuckets,
170
- configuredBuckets,
171
- );
172
-
173
- if (selectedBucketIds.length > 0) {
174
- bucketSelections = SelectionDialogs.createBucketSelection(
175
- selectedBucketIds,
176
- mergedBuckets,
177
- configuredBuckets,
178
- mergedDatabases
179
- );
180
- MessageFormatter.info(`Selected ${bucketSelections.length} storage bucket(s)`, { prefix: "Buckets" });
181
- }
182
- }
183
- } catch (error) {
184
- MessageFormatter.warning("Failed during bucket selection.", { prefix: "Buckets" });
185
- logger.warn("Bucket selection failed during syncDb", { error: error instanceof Error ? error.message : String(error) });
186
- }
187
- }
188
-
189
- // --- Confirmation ---
190
- if (databaseSelections.length > 0 || bucketSelections.length > 0) {
191
- const selectionSummary = SelectionDialogs.createSyncSelectionSummary(
192
- databaseSelections,
193
- bucketSelections
194
- );
195
-
196
- const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary, 'push');
197
-
198
- if (!confirmed) {
199
- MessageFormatter.info("Push operation cancelled by user", { prefix: "Push" });
200
- return;
201
- }
202
-
203
- MessageFormatter.progress("Starting selective push...", { prefix: "Push" });
204
- await (cli as any).controller!.selectivePush(databaseSelections, bucketSelections);
205
- MessageFormatter.success("Configuration pushed successfully!", { prefix: "Push" });
206
- }
207
-
208
- // --- Functions sub-flow ---
209
- if (pushFunctions) {
210
- if (!(cli as any).controller!.config?.functions?.length) {
211
- MessageFormatter.warning("No functions defined in local config.", { prefix: "Functions" });
212
- } else {
213
- const functions = await (cli as any).selectFunctions(
214
- chalk.blue("Select local functions to push:"),
215
- true,
216
- true
217
- );
218
-
219
- for (const func of functions) {
220
- try {
221
- await (cli as any).controller!.deployFunction(func.name);
222
- MessageFormatter.success(`Function ${func.name} deployed successfully`, { prefix: "Functions" });
223
- } catch (error) {
224
- MessageFormatter.error(`Failed to deploy function ${func.name}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Functions" });
225
- }
226
- }
227
- }
228
- }
229
-
230
- MessageFormatter.success("Push operation completed!", { prefix: "Push" });
231
- } catch (error) {
232
- MessageFormatter.error("Failed to push local configuration", error instanceof Error ? error : new Error(String(error)), { prefix: "Push" });
233
- throw error;
234
- }
235
- },
236
-
237
- async synchronizeConfigurations(cli: InteractiveCLI): Promise<void> {
238
- MessageFormatter.progress("Synchronizing configurations...", { prefix: "Config" });
239
- await (cli as any).controller!.init();
240
-
241
- // Sync databases, collections, and buckets
242
- const { syncDatabases } = await inquirer.prompt([
243
- {
244
- type: "confirm",
245
- name: "syncDatabases",
246
- message: "Do you want to synchronize databases, tables, and their buckets?",
247
- default: true,
248
- },
249
- ]);
250
-
251
- if (syncDatabases) {
252
- const remoteDatabases = await fetchAllDatabases(
253
- (cli as any).controller!.database!
254
- );
255
-
256
- // First, prepare the combined database list for bucket configuration
257
- const localDatabases = (cli as any).controller!.config?.databases || [];
258
- const allDatabases = [
259
- ...localDatabases,
260
- ...remoteDatabases.filter(
261
- (rd: any) => !localDatabases.some((ld: any) => ld.name === rd.name)
262
- ),
263
- ];
264
-
265
- // Configure buckets FIRST to get user selections before writing config
266
- MessageFormatter.progress("Configuring storage buckets...", { prefix: "Buckets" });
267
- const configWithBuckets = await (cli as any).configureBuckets({
268
- ...(cli as any).controller!.config!,
269
- databases: allDatabases,
270
- });
271
-
272
- // Update controller config with bucket selections
273
- (cli as any).controller!.config = configWithBuckets;
274
-
275
- // Now synchronize configurations with the updated config that includes bucket selections
276
- MessageFormatter.progress("Pulling tables and generating table files...", { prefix: "Tables" });
277
- await (cli as any).controller!.synchronizeConfigurations(remoteDatabases, configWithBuckets);
278
- }
279
-
280
- // Then sync functions
281
- const { syncFunctions } = await inquirer.prompt([
282
- {
283
- type: "confirm",
284
- name: "syncFunctions",
285
- message: "Do you want to synchronize functions?",
286
- default: true,
287
- },
288
- ]);
289
-
290
- if (syncFunctions) {
291
- const remoteFunctions = await (cli as any).controller!.listAllFunctions();
292
- const localFunctions = (cli as any).controller!.config?.functions || [];
293
-
294
- const allFunctions = [
295
- ...remoteFunctions,
296
- ...localFunctions.filter(
297
- (f: any) => !remoteFunctions.some((rf: any) => rf.$id === f.$id)
298
- ),
299
- ];
300
-
301
- for (const func of allFunctions) {
302
- const hasLocal = localFunctions.some((lf: any) => lf.$id === func.$id);
303
- const hasRemote = remoteFunctions.some((rf: any) => rf.$id === func.$id);
304
-
305
- if (hasLocal && hasRemote) {
306
- // Function exists in both local and remote
307
- const { preference } = await inquirer.prompt([
308
- {
309
- type: "list",
310
- name: "preference",
311
- message: `Function "${func.name}" exists both locally and remotely. What would you like to do?`,
312
- choices: [
313
- { name: "Keep local version (deploy to remote)", value: "local" },
314
- { name: "Use remote version (download)", value: "remote" },
315
- { name: "Update config only", value: "config" },
316
- { name: "Skip this function", value: "skip" },
317
- ],
318
- },
319
- ]);
320
-
321
- if (preference === "local") {
322
- await (cli as any).controller!.deployFunction(func.name);
323
- } else if (preference === "remote") {
324
- await downloadLatestFunctionDeployment(
325
- (cli as any).controller!.appwriteServer!,
326
- func.$id,
327
- join((cli as any).controller!.getAppwriteFolderPath()!, "functions")
328
- );
329
- } else if (preference === "config") {
330
- // Update config with remote function details
331
- const remoteFunction = await getFunction(
332
- (cli as any).controller!.appwriteServer!,
333
- func.$id
334
- );
335
-
336
- const newFunction = {
337
- $id: remoteFunction.$id,
338
- name: remoteFunction.name,
339
- runtime: remoteFunction.runtime,
340
- execute: remoteFunction.execute || [],
341
- events: remoteFunction.events || [],
342
- schedule: remoteFunction.schedule || "",
343
- timeout: remoteFunction.timeout || 15,
344
- enabled: remoteFunction.enabled !== false,
345
- logging: remoteFunction.logging !== false,
346
- entrypoint: remoteFunction.entrypoint || "src/main.ts",
347
- commands: remoteFunction.commands || "npm install",
348
- scopes: remoteFunction.scopes || [],
349
- installationId: remoteFunction.installationId,
350
- providerRepositoryId: remoteFunction.providerRepositoryId,
351
- providerBranch: remoteFunction.providerBranch,
352
- providerSilentMode: remoteFunction.providerSilentMode,
353
- providerRootDirectory: remoteFunction.providerRootDirectory,
354
- specification: remoteFunction.specification,
355
- };
356
-
357
- const existingIndex = (cli as any).controller!.config!.functions!.findIndex(
358
- (f: any) => f.$id === remoteFunction.$id
359
- );
360
-
361
- if (existingIndex >= 0) {
362
- (cli as any).controller!.config!.functions![existingIndex] = newFunction;
363
- } else {
364
- (cli as any).controller!.config!.functions!.push(newFunction);
365
- }
366
- MessageFormatter.success(`Updated config for function: ${func.name}`, { prefix: "Functions" });
367
- }
368
- } else if (hasLocal) {
369
- // Function exists only locally
370
- const { action } = await inquirer.prompt([
371
- {
372
- type: "list",
373
- name: "action",
374
- message: `Function "${func.name}" exists only locally. What would you like to do?`,
375
- choices: [
376
- { name: "Deploy to remote", value: "deploy" },
377
- { name: "Skip this function", value: "skip" },
378
- ],
379
- },
380
- ]);
381
-
382
- if (action === "deploy") {
383
- await (cli as any).controller!.deployFunction(func.name);
384
- }
385
- } else if (hasRemote) {
386
- // Function exists only remotely
387
- const { action } = await inquirer.prompt([
388
- {
389
- type: "list",
390
- name: "action",
391
- message: `Function "${func.name}" exists only remotely. What would you like to do?`,
392
- choices: [
393
- { name: "Update config only", value: "config" },
394
- { name: "Download locally", value: "download" },
395
- { name: "Skip this function", value: "skip" },
396
- ],
397
- },
398
- ]);
399
-
400
- if (action === "download") {
401
- await downloadLatestFunctionDeployment(
402
- (cli as any).controller!.appwriteServer!,
403
- func.$id,
404
- join((cli as any).controller!.getAppwriteFolderPath()!, "functions")
405
- );
406
- } else if (action === "config") {
407
- const remoteFunction = await getFunction(
408
- (cli as any).controller!.appwriteServer!,
409
- func.$id
410
- );
411
-
412
- const newFunction = {
413
- $id: remoteFunction.$id,
414
- name: remoteFunction.name,
415
- runtime: remoteFunction.runtime,
416
- execute: remoteFunction.execute || [],
417
- events: remoteFunction.events || [],
418
- schedule: remoteFunction.schedule || "",
419
- timeout: remoteFunction.timeout || 15,
420
- enabled: remoteFunction.enabled !== false,
421
- logging: remoteFunction.logging !== false,
422
- entrypoint: remoteFunction.entrypoint || "src/main.ts",
423
- commands: remoteFunction.commands || "npm install",
424
- scopes: remoteFunction.scopes || [],
425
- installationId: remoteFunction.installationId,
426
- providerRepositoryId: remoteFunction.providerRepositoryId,
427
- providerBranch: remoteFunction.providerBranch,
428
- providerSilentMode: remoteFunction.providerSilentMode,
429
- providerRootDirectory: remoteFunction.providerRootDirectory,
430
- specification: remoteFunction.specification,
431
- };
432
-
433
- (cli as any).controller!.config!.functions =
434
- (cli as any).controller!.config!.functions || [];
435
- (cli as any).controller!.config!.functions.push(newFunction);
436
- MessageFormatter.success(`Added config for remote function: ${func.name}`, { prefix: "Functions" });
437
- }
438
- }
439
- }
440
- }
441
-
442
- MessageFormatter.success("✨ Configurations synchronized successfully!", { prefix: "Config" });
443
- },
444
-
445
- async backupDatabase(cli: InteractiveCLI): Promise<void> {
446
- if (!(cli as any).controller!.database || !(cli as any).controller!.storage) {
447
- throw new Error(
448
- "Database or Storage is not initialized, is the config file correct & created?"
449
- );
450
- }
451
-
452
- try {
453
- // STEP 1: Select tracking database
454
- MessageFormatter.info("Step 1/5: Select tracking database", { prefix: "Backup" });
455
- const trackingDb = await this.selectTrackingDatabase(cli);
456
-
457
- // STEP 2: Ensure backup tracking table exists
458
- MessageFormatter.info("Step 2/5: Initializing backup tracking", { prefix: "Backup" });
459
- await this.ensureBackupTrackingTable(cli, trackingDb);
460
-
461
- // STEP 3: Select backup scope
462
- MessageFormatter.info("Step 3/5: Select backup scope", { prefix: "Backup" });
463
- const scope = await this.selectBackupScope(cli);
464
-
465
- // STEP 4: Show confirmation
466
- MessageFormatter.info("Step 4/5: Confirm backup plan", { prefix: "Backup" });
467
- const confirmed = await this.confirmBackupPlan(scope);
468
- if (!confirmed) {
469
- MessageFormatter.info("Backup cancelled by user", { prefix: "Backup" });
470
- return;
471
- }
472
-
473
- // STEP 5: Execute unified backup
474
- MessageFormatter.info("Step 5/5: Executing backup", { prefix: "Backup" });
475
- await this.executeUnifiedBackup(cli, trackingDb, scope);
476
-
477
- MessageFormatter.success("Backup operation completed successfully", { prefix: "Backup" });
478
- } catch (error) {
479
- MessageFormatter.error(
480
- "Backup operation failed",
481
- error instanceof Error ? error : new Error(String(error)),
482
- { prefix: "Backup" }
483
- );
484
- throw error;
485
- }
486
- },
487
-
488
- // Helper method: Select tracking database
489
- async selectTrackingDatabase(cli: InteractiveCLI): Promise<string> {
490
- const databases = await fetchAllDatabases((cli as any).controller!.database);
491
-
492
- const { trackingDatabaseId } = await inquirer.prompt([
493
- {
494
- type: "list",
495
- name: "trackingDatabaseId",
496
- message: "Select database to store backup metadata:",
497
- choices: databases.map(db => ({
498
- name: `${db.name} (${db.$id})`,
499
- value: db.$id
500
- }))
501
- }
502
- ]);
503
-
504
- MessageFormatter.info(`Using ${trackingDatabaseId} for backup tracking`, { prefix: "Backup" });
505
- return trackingDatabaseId;
506
- },
507
-
508
- // Helper method: Ensure backup tracking table exists
509
- async ensureBackupTrackingTable(cli: InteractiveCLI, trackingDatabaseId: string): Promise<void> {
510
- const { createCentralizedBackupTrackingTable } = await import("../../backups/tracking/centralizedTracking.js");
511
- const adapter = (cli as any).controller!.adapter;
512
-
513
- await createCentralizedBackupTrackingTable(adapter, trackingDatabaseId);
514
- MessageFormatter.success("Backup tracking table ready", { prefix: "Backup" });
515
- },
516
-
517
- // Helper method: Select backup scope
518
- async selectBackupScope(cli: InteractiveCLI): Promise<any> {
519
- const { scopeType } = await inquirer.prompt([
520
- {
521
- type: "list",
522
- name: "scopeType",
523
- message: "What would you like to backup?",
524
- choices: [
525
- { name: "Comprehensive (ALL databases + ALL buckets)", value: "comprehensive" },
526
- { name: "Selective databases (choose specific databases)", value: "selective-databases" },
527
- { name: "Selective tables (choose specific tables)", value: "selective-tables" }
528
- ]
529
- }
530
- ]);
531
-
532
- if (scopeType === "comprehensive") {
533
- return { type: "comprehensive" };
534
- }
535
-
536
- if (scopeType === "selective-databases") {
537
- const databases = await fetchAllDatabases((cli as any).controller!.database);
538
- const selectedDatabases = await (cli as any).selectDatabases(
539
- databases,
540
- "Select databases to backup:"
541
- );
542
-
543
- const { includeBuckets } = await inquirer.prompt([
544
- {
545
- type: "confirm",
546
- name: "includeBuckets",
547
- message: "Include storage buckets in backup?",
548
- default: false
549
- }
550
- ]);
551
-
552
- let selectedBuckets: string[] = [];
553
- if (includeBuckets) {
554
- const buckets = await listBuckets((cli as any).controller!.storage);
555
- const { bucketIds } = await inquirer.prompt([
556
- {
557
- type: "checkbox",
558
- name: "bucketIds",
559
- message: "Select buckets to backup:",
560
- choices: buckets.buckets.map((b: any) => ({
561
- name: `${b.name} (${b.$id})`,
562
- value: b.$id
563
- }))
564
- }
565
- ]);
566
- selectedBuckets = bucketIds;
567
- }
568
-
569
- return {
570
- type: "selective-databases",
571
- databases: selectedDatabases,
572
- buckets: selectedBuckets
573
- };
574
- }
575
-
576
- if (scopeType === "selective-tables") {
577
- const databases = await fetchAllDatabases((cli as any).controller!.database);
578
- const selectedDatabase = await (cli as any).selectDatabases(
579
- databases,
580
- "Select database containing tables:",
581
- false // single selection
582
- );
583
-
584
- if (!selectedDatabase || selectedDatabase.length === 0) {
585
- throw new Error("No database selected");
586
- }
587
-
588
- const db = selectedDatabase[0];
589
- const collections = await (cli as any).selectCollectionsAndTables(
590
- db,
591
- (cli as any).controller!.database!,
592
- "Select tables to backup:",
593
- true,
594
- true,
595
- true
596
- );
597
-
598
- return {
599
- type: "selective-tables",
600
- databaseId: db.$id,
601
- databaseName: db.name,
602
- collections: collections
603
- };
604
- }
605
-
606
- throw new Error("Invalid backup scope selected");
607
- },
608
-
609
- // Helper method: Confirm backup plan
610
- async confirmBackupPlan(scope: any): Promise<boolean> {
611
- let summary = "\n" + chalk.bold("Backup Plan Summary:") + "\n";
612
-
613
- if (scope.type === "comprehensive") {
614
- summary += " • ALL databases\n";
615
- summary += " • ALL storage buckets\n";
616
- } else if (scope.type === "selective-databases") {
617
- summary += ` • ${scope.databases.length} selected databases\n`;
618
- if (scope.buckets.length > 0) {
619
- summary += ` • ${scope.buckets.length} selected buckets\n`;
620
- }
621
- } else if (scope.type === "selective-tables") {
622
- summary += ` • Database: ${scope.databaseName}\n`;
623
- summary += ` • ${scope.collections.length} selected tables\n`;
624
- }
625
-
626
- console.log(summary);
627
-
628
- const { confirmed } = await inquirer.prompt([
629
- {
630
- type: "confirm",
631
- name: "confirmed",
632
- message: "Proceed with backup?",
633
- default: true
634
- }
635
- ]);
636
-
637
- return confirmed;
638
- },
639
-
640
- // Helper method: Execute unified backup
641
- async executeUnifiedBackup(cli: InteractiveCLI, trackingDatabaseId: string, scope: any): Promise<void> {
642
- if (scope.type === "comprehensive") {
643
- const { comprehensiveBackup } = await import("../../backups/operations/comprehensiveBackup.js");
644
-
645
- await comprehensiveBackup(
646
- (cli as any).controller!.config,
647
- (cli as any).controller!.database,
648
- (cli as any).controller!.storage,
649
- (cli as any).controller!.adapter,
650
- {
651
- trackingDatabaseId,
652
- backupFormat: 'zip',
653
- parallelDownloads: 10,
654
- onProgress: (message: string) => {
655
- MessageFormatter.progress(message, { prefix: "Backup" });
656
- }
657
- }
658
- );
659
- } else if (scope.type === "selective-databases") {
660
- // Backup each selected database
661
- for (const db of scope.databases) {
662
- MessageFormatter.progress(`Backing up database: ${db.name}`, { prefix: "Backup" });
663
- await (cli as any).controller!.backupDatabase(db);
664
- }
665
-
666
- // Backup selected buckets if any
667
- for (const bucketId of scope.buckets) {
668
- MessageFormatter.progress(`Backing up bucket: ${bucketId}`, { prefix: "Backup" });
669
- const { backupBucket } = await import("../../backups/operations/bucketBackup.js");
670
- await backupBucket(
671
- (cli as any).controller!.storage,
672
- bucketId,
673
- "appwrite-backups",
674
- { parallelDownloads: 10 }
675
- );
676
- }
677
- } else if (scope.type === "selective-tables") {
678
- const { backupCollections } = await import("../../backups/operations/collectionBackup.js");
679
-
680
- await backupCollections(
681
- (cli as any).controller!.config,
682
- (cli as any).controller!.database,
683
- (cli as any).controller!.storage,
684
- (cli as any).controller!.adapter,
685
- {
686
- trackingDatabaseId,
687
- databaseId: scope.databaseId,
688
- collectionIds: scope.collections.map((c: any) => c.$id || c.id),
689
- backupFormat: 'zip',
690
- onProgress: (message: string) => {
691
- MessageFormatter.progress(message, { prefix: "Backup" });
692
- }
693
- }
694
- );
695
- }
696
- },
697
-
698
- async wipeDatabase(cli: InteractiveCLI): Promise<void> {
699
- if (!(cli as any).controller!.database || !(cli as any).controller!.storage) {
700
- throw new Error(
701
- "Database or Storage is not initialized, is the config file correct & created?"
702
- );
703
- }
704
- const databases = await fetchAllDatabases((cli as any).controller!.database);
705
- const storage = await listBuckets((cli as any).controller!.storage);
706
-
707
- const selectedDatabases = await (cli as any).selectDatabases(
708
- databases,
709
- "Select databases to wipe:"
710
- );
711
-
712
- const { selectedStorage } = await inquirer.prompt([
713
- {
714
- type: "checkbox",
715
- name: "selectedStorage",
716
- message: "Select storage buckets to wipe:",
717
- choices: storage.buckets.map((s: any) => ({ name: s.name, value: s.$id })),
718
- },
719
- ]);
720
-
721
- const { wipeUsers } = await inquirer.prompt([
722
- {
723
- type: "confirm",
724
- name: "wipeUsers",
725
- message: "Do you want to wipe users as well?",
726
- default: false,
727
- },
728
- ]);
729
-
730
- const databaseNames = selectedDatabases.map((db: any) => db.name);
731
- const confirmed = await ConfirmationDialogs.confirmDatabaseWipe(databaseNames, {
732
- includeStorage: selectedStorage.length > 0,
733
- includeUsers: wipeUsers
734
- });
735
-
736
- if (confirmed) {
737
- MessageFormatter.info("Starting wipe operation...", { prefix: "Wipe" });
738
- for (const db of selectedDatabases) {
739
- await (cli as any).controller!.wipeDatabase(db);
740
- }
741
- for (const bucketId of selectedStorage) {
742
- await (cli as any).controller!.wipeDocumentStorage(bucketId);
743
- }
744
- if (wipeUsers) {
745
- await (cli as any).controller!.wipeUsers();
746
- }
747
- MessageFormatter.success("Wipe operation completed", { prefix: "Wipe" });
748
- } else {
749
- MessageFormatter.info("Wipe operation cancelled", { prefix: "Wipe" });
750
- }
751
- },
752
-
753
- async wipeCollections(cli: InteractiveCLI): Promise<void> {
754
- if (!(cli as any).controller!.database) {
755
- throw new Error(
756
- "Database is not initialized, is the config file correct & created?"
757
- );
758
- }
759
- const databases = await fetchAllDatabases((cli as any).controller!.database);
760
- const selectedDatabases = await (cli as any).selectDatabases(
761
- databases,
762
- "Select the database(s) containing the tables to wipe:",
763
- true
764
- );
765
-
766
- for (const database of selectedDatabases) {
767
- const collections = await (cli as any).selectCollectionsAndTables(
768
- database,
769
- (cli as any).controller!.database,
770
- `Select tables to wipe from ${database.name}:`,
771
- true,
772
- undefined,
773
- true
774
- );
775
-
776
- const collectionNames = collections.map((c: any) => c.name);
777
- const confirmed = await ConfirmationDialogs.confirmCollectionWipe(
778
- database.name,
779
- collectionNames
780
- );
781
-
782
- if (confirmed) {
783
- MessageFormatter.info(
784
- `Wiping selected tables from ${database.name}...`,
785
- { prefix: "Wipe" }
786
- );
787
- for (const collection of collections) {
788
- await (cli as any).controller!.wipeCollection(database, collection);
789
- MessageFormatter.success(
790
- `Table ${collection.name} wiped successfully`,
791
- { prefix: "Wipe" }
792
- );
793
- }
794
- } else {
795
- MessageFormatter.info(
796
- `Wipe operation cancelled for ${database.name}`,
797
- { prefix: "Wipe" }
798
- );
799
- }
800
- }
801
- MessageFormatter.success("Wipe tables operation completed", { prefix: "Wipe" });
802
- },
803
-
804
- async wipeTablesData(cli: InteractiveCLI): Promise<void> {
805
- const controller = (cli as any).controller;
806
-
807
- if (!controller?.adapter) {
808
- throw new Error(
809
- "Database adapter is not initialized. TablesDB operations require adapter support."
810
- );
811
- }
812
-
813
- try {
814
- // Step 1: Select database (single selection for clearer UX)
815
- const databases = await fetchAllDatabases(controller.database);
816
-
817
- if (!databases || databases.length === 0) {
818
- MessageFormatter.warning("No databases found", { prefix: "Wipe" });
819
- return;
820
- }
821
-
822
- const { selectedDatabase } = await inquirer.prompt([
823
- {
824
- type: "list",
825
- name: "selectedDatabase",
826
- message: "Select database containing tables to wipe:",
827
- choices: databases.map((db: any) => ({
828
- name: `${db.name} (${db.$id})`,
829
- value: db
830
- }))
831
- }
832
- ]);
833
-
834
- const database = selectedDatabase;
835
-
836
- // Step 2: Get available tables
837
- const adapter = controller.adapter;
838
- const tablesResponse = await adapter.listTables({
839
- databaseId: database.$id,
840
- queries: [Query.limit(500)]
841
- });
842
- const availableTables = (tablesResponse as any).tables || [];
843
-
844
- if (availableTables.length === 0) {
845
- MessageFormatter.warning(`No tables found in database: ${database.name}`, { prefix: "Wipe" });
846
- return;
847
- }
848
-
849
- // Step 3: Select tables using existing SelectionDialogs
850
- const selectedTableIds = await SelectionDialogs.selectTablesForDatabase(
851
- database.$id,
852
- database.name,
853
- availableTables,
854
- [], // No configured tables context needed for wipe
855
- {
856
- showSelectAll: true,
857
- allowNewOnly: false,
858
- defaultSelected: []
859
- }
860
- );
861
-
862
- if (selectedTableIds.length === 0) {
863
- MessageFormatter.warning("No tables selected. Operation cancelled.", { prefix: "Wipe" });
864
- return;
865
- }
866
-
867
- // Step 4: Show confirmation with table details
868
- const selectedTables = availableTables.filter((t: any) =>
869
- selectedTableIds.includes(t.$id)
870
- );
871
- const tableNames = selectedTables.map((t: any) => t.name);
872
-
873
- console.log(chalk.yellow.bold("\n⚠️ WARNING: Table Row Wipe Operation"));
874
- console.log(chalk.yellow("This will delete ALL ROWS from the selected tables."));
875
- console.log(chalk.yellow("The table structures will remain intact.\n"));
876
- console.log(chalk.cyan("Database:"), chalk.white(database.name));
877
- console.log(chalk.cyan("Tables to wipe:"));
878
- tableNames.forEach((name: string) => console.log(chalk.white(` • ${name}`)));
879
- console.log();
880
-
881
- const { confirmed } = await inquirer.prompt([
882
- {
883
- type: "confirm",
884
- name: "confirmed",
885
- message: chalk.red.bold("Are you ABSOLUTELY SURE you want to wipe these table rows?"),
886
- default: false
887
- }
888
- ]);
889
-
890
- if (!confirmed) {
891
- MessageFormatter.info("Wipe operation cancelled by user", { prefix: "Wipe" });
892
- return;
893
- }
894
-
895
- // Step 5: Execute wipe using existing wipeTableRows function
896
- MessageFormatter.progress("Starting table row wipe operation...", { prefix: "Wipe" });
897
-
898
- for (const table of selectedTables) {
899
- try {
900
- MessageFormatter.info(`Wiping rows from table: ${table.name}`, { prefix: "Wipe" });
901
-
902
- // Use existing wipeTableRows from wipeOperations.ts
903
- await wipeTableRows(adapter, database.$id, table.$id);
904
-
905
- MessageFormatter.success(
906
- `Successfully wiped rows from table: ${table.name}`,
907
- { prefix: "Wipe" }
908
- );
909
- } catch (error) {
910
- MessageFormatter.error(
911
- `Failed to wipe table ${table.name}`,
912
- error instanceof Error ? error : new Error(String(error)),
913
- { prefix: "Wipe" }
914
- );
915
- }
916
- }
917
-
918
- MessageFormatter.success(
919
- `Wipe operation completed for ${selectedTables.length} table(s)`,
920
- { prefix: "Wipe" }
921
- );
922
- } catch (error) {
923
- MessageFormatter.error(
924
- "Table wipe operation failed",
925
- error instanceof Error ? error : new Error(String(error)),
926
- { prefix: "Wipe" }
927
- );
928
- throw error;
929
- }
930
- }
931
- };