appwrite-utils-cli 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +251 -29
  3. package/dist/adapters/AdapterFactory.d.ts +10 -3
  4. package/dist/adapters/AdapterFactory.js +213 -17
  5. package/dist/adapters/TablesDBAdapter.js +60 -17
  6. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  7. package/dist/backups/operations/bucketBackup.js +197 -0
  8. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  9. package/dist/backups/operations/collectionBackup.js +201 -0
  10. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  11. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  12. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  13. package/dist/backups/schemas/bucketManifest.js +33 -0
  14. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  15. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  16. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  17. package/dist/backups/tracking/centralizedTracking.js +274 -0
  18. package/dist/cli/commands/configCommands.d.ts +8 -0
  19. package/dist/cli/commands/configCommands.js +160 -0
  20. package/dist/cli/commands/databaseCommands.d.ts +13 -0
  21. package/dist/cli/commands/databaseCommands.js +479 -0
  22. package/dist/cli/commands/functionCommands.d.ts +7 -0
  23. package/dist/cli/commands/functionCommands.js +289 -0
  24. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  25. package/dist/cli/commands/schemaCommands.js +134 -0
  26. package/dist/cli/commands/transferCommands.d.ts +5 -0
  27. package/dist/cli/commands/transferCommands.js +384 -0
  28. package/dist/collections/attributes.d.ts +5 -4
  29. package/dist/collections/attributes.js +539 -246
  30. package/dist/collections/indexes.js +39 -37
  31. package/dist/collections/methods.d.ts +2 -16
  32. package/dist/collections/methods.js +90 -538
  33. package/dist/collections/transferOperations.d.ts +7 -0
  34. package/dist/collections/transferOperations.js +331 -0
  35. package/dist/collections/wipeOperations.d.ts +16 -0
  36. package/dist/collections/wipeOperations.js +328 -0
  37. package/dist/config/configMigration.d.ts +87 -0
  38. package/dist/config/configMigration.js +390 -0
  39. package/dist/config/configValidation.d.ts +66 -0
  40. package/dist/config/configValidation.js +358 -0
  41. package/dist/config/yamlConfig.d.ts +455 -1
  42. package/dist/config/yamlConfig.js +145 -52
  43. package/dist/databases/methods.js +3 -2
  44. package/dist/databases/setup.d.ts +1 -2
  45. package/dist/databases/setup.js +9 -87
  46. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  47. package/dist/examples/yamlTerminologyExample.js +269 -0
  48. package/dist/functions/deployments.js +11 -10
  49. package/dist/functions/methods.d.ts +1 -1
  50. package/dist/functions/methods.js +5 -4
  51. package/dist/init.js +9 -9
  52. package/dist/interactiveCLI.d.ts +8 -17
  53. package/dist/interactiveCLI.js +209 -1172
  54. package/dist/main.js +364 -21
  55. package/dist/migrations/afterImportActions.js +22 -30
  56. package/dist/migrations/appwriteToX.js +71 -25
  57. package/dist/migrations/dataLoader.js +35 -26
  58. package/dist/migrations/importController.js +29 -30
  59. package/dist/migrations/relationships.js +13 -12
  60. package/dist/migrations/services/ImportOrchestrator.js +16 -19
  61. package/dist/migrations/transfer.js +46 -46
  62. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
  63. package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
  64. package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
  65. package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
  66. package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
  67. package/dist/migrations/yaml/generateImportSchemas.js +736 -7
  68. package/dist/schemas/authUser.d.ts +1 -1
  69. package/dist/setupController.js +3 -2
  70. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  71. package/dist/shared/backupMetadataSchema.js +38 -0
  72. package/dist/shared/backupTracking.d.ts +18 -0
  73. package/dist/shared/backupTracking.js +176 -0
  74. package/dist/shared/confirmationDialogs.js +15 -15
  75. package/dist/shared/errorUtils.d.ts +54 -0
  76. package/dist/shared/errorUtils.js +95 -0
  77. package/dist/shared/functionManager.js +20 -19
  78. package/dist/shared/indexManager.js +12 -11
  79. package/dist/shared/jsonSchemaGenerator.js +10 -26
  80. package/dist/shared/logging.d.ts +51 -0
  81. package/dist/shared/logging.js +70 -0
  82. package/dist/shared/messageFormatter.d.ts +2 -0
  83. package/dist/shared/messageFormatter.js +10 -0
  84. package/dist/shared/migrationHelpers.d.ts +6 -16
  85. package/dist/shared/migrationHelpers.js +24 -21
  86. package/dist/shared/operationLogger.d.ts +8 -1
  87. package/dist/shared/operationLogger.js +11 -24
  88. package/dist/shared/operationQueue.d.ts +28 -1
  89. package/dist/shared/operationQueue.js +268 -66
  90. package/dist/shared/operationsTable.d.ts +26 -0
  91. package/dist/shared/operationsTable.js +286 -0
  92. package/dist/shared/operationsTableSchema.d.ts +48 -0
  93. package/dist/shared/operationsTableSchema.js +35 -0
  94. package/dist/shared/relationshipExtractor.d.ts +56 -0
  95. package/dist/shared/relationshipExtractor.js +138 -0
  96. package/dist/shared/schemaGenerator.d.ts +19 -1
  97. package/dist/shared/schemaGenerator.js +56 -75
  98. package/dist/storage/backupCompression.d.ts +20 -0
  99. package/dist/storage/backupCompression.js +67 -0
  100. package/dist/storage/methods.d.ts +16 -2
  101. package/dist/storage/methods.js +98 -14
  102. package/dist/users/methods.js +9 -8
  103. package/dist/utils/configDiscovery.d.ts +78 -0
  104. package/dist/utils/configDiscovery.js +430 -0
  105. package/dist/utils/directoryUtils.d.ts +22 -0
  106. package/dist/utils/directoryUtils.js +59 -0
  107. package/dist/utils/getClientFromConfig.d.ts +17 -8
  108. package/dist/utils/getClientFromConfig.js +162 -17
  109. package/dist/utils/helperFunctions.d.ts +16 -2
  110. package/dist/utils/helperFunctions.js +19 -5
  111. package/dist/utils/loadConfigs.d.ts +34 -9
  112. package/dist/utils/loadConfigs.js +236 -316
  113. package/dist/utils/pathResolvers.d.ts +53 -0
  114. package/dist/utils/pathResolvers.js +72 -0
  115. package/dist/utils/projectConfig.d.ts +119 -0
  116. package/dist/utils/projectConfig.js +171 -0
  117. package/dist/utils/retryFailedPromises.js +4 -2
  118. package/dist/utils/sessionAuth.d.ts +48 -0
  119. package/dist/utils/sessionAuth.js +164 -0
  120. package/dist/utils/sessionPreservationExample.d.ts +1666 -0
  121. package/dist/utils/sessionPreservationExample.js +101 -0
  122. package/dist/utils/setupFiles.js +301 -41
  123. package/dist/utils/typeGuards.d.ts +35 -0
  124. package/dist/utils/typeGuards.js +57 -0
  125. package/dist/utils/versionDetection.js +145 -9
  126. package/dist/utils/yamlConverter.d.ts +53 -3
  127. package/dist/utils/yamlConverter.js +232 -13
  128. package/dist/utils/yamlLoader.d.ts +70 -0
  129. package/dist/utils/yamlLoader.js +263 -0
  130. package/dist/utilsController.d.ts +36 -3
  131. package/dist/utilsController.js +186 -56
  132. package/package.json +12 -2
  133. package/src/adapters/AdapterFactory.ts +263 -35
  134. package/src/adapters/TablesDBAdapter.ts +225 -36
  135. package/src/backups/operations/bucketBackup.ts +277 -0
  136. package/src/backups/operations/collectionBackup.ts +310 -0
  137. package/src/backups/operations/comprehensiveBackup.ts +342 -0
  138. package/src/backups/schemas/bucketManifest.ts +78 -0
  139. package/src/backups/schemas/comprehensiveManifest.ts +76 -0
  140. package/src/backups/tracking/centralizedTracking.ts +352 -0
  141. package/src/cli/commands/configCommands.ts +194 -0
  142. package/src/cli/commands/databaseCommands.ts +635 -0
  143. package/src/cli/commands/functionCommands.ts +379 -0
  144. package/src/cli/commands/schemaCommands.ts +163 -0
  145. package/src/cli/commands/transferCommands.ts +457 -0
  146. package/src/collections/attributes.ts +900 -621
  147. package/src/collections/attributes.ts.backup +1555 -0
  148. package/src/collections/indexes.ts +116 -114
  149. package/src/collections/methods.ts +295 -968
  150. package/src/collections/transferOperations.ts +516 -0
  151. package/src/collections/wipeOperations.ts +501 -0
  152. package/src/config/README.md +274 -0
  153. package/src/config/configMigration.ts +575 -0
  154. package/src/config/configValidation.ts +445 -0
  155. package/src/config/yamlConfig.ts +168 -55
  156. package/src/databases/methods.ts +3 -2
  157. package/src/databases/setup.ts +11 -138
  158. package/src/examples/yamlTerminologyExample.ts +341 -0
  159. package/src/functions/deployments.ts +14 -12
  160. package/src/functions/methods.ts +11 -11
  161. package/src/functions/templates/hono-typescript/README.md +286 -0
  162. package/src/functions/templates/hono-typescript/package.json +26 -0
  163. package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  164. package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  165. package/src/functions/templates/hono-typescript/src/app.ts +180 -0
  166. package/src/functions/templates/hono-typescript/src/context.ts +103 -0
  167. package/src/functions/templates/hono-typescript/src/index.ts +54 -0
  168. package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  169. package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
  170. package/src/functions/templates/typescript-node/package.json +2 -1
  171. package/src/functions/templates/typescript-node/src/context.ts +103 -0
  172. package/src/functions/templates/typescript-node/src/index.ts +18 -12
  173. package/src/functions/templates/uv/pyproject.toml +1 -0
  174. package/src/functions/templates/uv/src/context.py +125 -0
  175. package/src/functions/templates/uv/src/index.py +35 -5
  176. package/src/init.ts +9 -11
  177. package/src/interactiveCLI.ts +274 -1563
  178. package/src/main.ts +418 -24
  179. package/src/migrations/afterImportActions.ts +71 -44
  180. package/src/migrations/appwriteToX.ts +100 -34
  181. package/src/migrations/dataLoader.ts +48 -34
  182. package/src/migrations/importController.ts +44 -39
  183. package/src/migrations/relationships.ts +28 -18
  184. package/src/migrations/services/ImportOrchestrator.ts +24 -27
  185. package/src/migrations/transfer.ts +159 -121
  186. package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
  187. package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
  188. package/src/migrations/yaml/generateImportSchemas.ts +751 -12
  189. package/src/setupController.ts +3 -2
  190. package/src/shared/backupMetadataSchema.ts +93 -0
  191. package/src/shared/backupTracking.ts +211 -0
  192. package/src/shared/confirmationDialogs.ts +19 -19
  193. package/src/shared/errorUtils.ts +110 -0
  194. package/src/shared/functionManager.ts +21 -20
  195. package/src/shared/indexManager.ts +12 -11
  196. package/src/shared/jsonSchemaGenerator.ts +38 -52
  197. package/src/shared/logging.ts +75 -0
  198. package/src/shared/messageFormatter.ts +14 -1
  199. package/src/shared/migrationHelpers.ts +45 -38
  200. package/src/shared/operationLogger.ts +11 -36
  201. package/src/shared/operationQueue.ts +322 -93
  202. package/src/shared/operationsTable.ts +338 -0
  203. package/src/shared/operationsTableSchema.ts +60 -0
  204. package/src/shared/relationshipExtractor.ts +214 -0
  205. package/src/shared/schemaGenerator.ts +179 -219
  206. package/src/storage/backupCompression.ts +88 -0
  207. package/src/storage/methods.ts +131 -34
  208. package/src/users/methods.ts +11 -9
  209. package/src/utils/configDiscovery.ts +502 -0
  210. package/src/utils/directoryUtils.ts +61 -0
  211. package/src/utils/getClientFromConfig.ts +205 -22
  212. package/src/utils/helperFunctions.ts +23 -5
  213. package/src/utils/loadConfigs.ts +313 -345
  214. package/src/utils/pathResolvers.ts +81 -0
  215. package/src/utils/projectConfig.ts +299 -0
  216. package/src/utils/retryFailedPromises.ts +4 -2
  217. package/src/utils/sessionAuth.ts +230 -0
  218. package/src/utils/setupFiles.ts +322 -54
  219. package/src/utils/typeGuards.ts +65 -0
  220. package/src/utils/versionDetection.ts +218 -64
  221. package/src/utils/yamlConverter.ts +296 -13
  222. package/src/utils/yamlLoader.ts +364 -0
  223. package/src/utilsController.ts +314 -110
  224. package/tests/README.md +497 -0
  225. package/tests/adapters/AdapterFactory.test.ts +277 -0
  226. package/tests/integration/syncOperations.test.ts +463 -0
  227. package/tests/jest.config.js +25 -0
  228. package/tests/migration/configMigration.test.ts +546 -0
  229. package/tests/setup.ts +62 -0
  230. package/tests/testUtils.ts +340 -0
  231. package/tests/utils/loadConfigs.test.ts +350 -0
  232. package/tests/validation/configValidation.test.ts +412 -0
  233. package/src/utils/schemaStrings.ts +0 -517
@@ -0,0 +1,384 @@
1
+ import inquirer from "inquirer";
2
+ import { Databases, Storage } from "node-appwrite";
3
+ import { MessageFormatter } from "../../shared/messageFormatter.js";
4
+ import { fetchAllDatabases } from "../../databases/methods.js";
5
+ import { listBuckets } from "../../storage/methods.js";
6
+ import { getClient } from "../../utils/getClientFromConfig.js";
7
+ import { ComprehensiveTransfer } from "../../migrations/comprehensiveTransfer.js";
8
+ export const transferCommands = {
9
+ async transferData(cli) {
10
+ if (!cli.controller.database) {
11
+ throw new Error("Database is not initialized, is the config file correct & created?");
12
+ }
13
+ const { isRemote } = await inquirer.prompt([
14
+ {
15
+ type: "confirm",
16
+ name: "isRemote",
17
+ message: "Is this a remote transfer?",
18
+ default: false,
19
+ },
20
+ ]);
21
+ let sourceClient = cli.controller.database;
22
+ let targetClient;
23
+ let sourceDatabases;
24
+ let targetDatabases;
25
+ let remoteOptions;
26
+ if (isRemote) {
27
+ remoteOptions = await inquirer.prompt([
28
+ {
29
+ type: "input",
30
+ name: "transferEndpoint",
31
+ message: "Enter the remote endpoint:",
32
+ },
33
+ {
34
+ type: "input",
35
+ name: "transferProject",
36
+ message: "Enter the remote project ID:",
37
+ },
38
+ {
39
+ type: "input",
40
+ name: "transferKey",
41
+ message: "Enter the remote API key:",
42
+ },
43
+ ]);
44
+ const remoteClient = getClient(remoteOptions.transferEndpoint, remoteOptions.transferProject, remoteOptions.transferKey);
45
+ targetClient = new Databases(remoteClient);
46
+ sourceDatabases = await fetchAllDatabases(sourceClient);
47
+ targetDatabases = await fetchAllDatabases(targetClient);
48
+ }
49
+ else {
50
+ targetClient = sourceClient;
51
+ const allDatabases = await fetchAllDatabases(sourceClient);
52
+ sourceDatabases = targetDatabases = allDatabases;
53
+ }
54
+ const fromDbs = await cli.selectDatabases(sourceDatabases, "Select the source database:", false);
55
+ const fromDb = fromDbs[0];
56
+ if (!fromDb) {
57
+ throw new Error("No source database selected");
58
+ }
59
+ const availableDbs = targetDatabases.filter((db) => db.$id !== fromDb.$id);
60
+ const targetDbs = await cli.selectDatabases(availableDbs, "Select the target database:", false);
61
+ const targetDb = targetDbs[0];
62
+ if (!targetDb) {
63
+ throw new Error("No target database selected");
64
+ }
65
+ const selectedCollections = await cli.selectCollectionsAndTables(fromDb, sourceClient, "Select collections/tables to transfer:", true, false // don't prefer local for transfers
66
+ );
67
+ const { transferStorage } = await inquirer.prompt([
68
+ {
69
+ type: "confirm",
70
+ name: "transferStorage",
71
+ message: "Do you want to transfer storage as well?",
72
+ default: false,
73
+ },
74
+ ]);
75
+ let sourceBucket, targetBucket;
76
+ if (transferStorage) {
77
+ const sourceStorage = new Storage(cli.controller.appwriteServer);
78
+ const targetStorage = isRemote
79
+ ? new Storage(getClient(remoteOptions.transferEndpoint, remoteOptions.transferProject, remoteOptions.transferKey))
80
+ : sourceStorage;
81
+ const sourceBuckets = await listBuckets(sourceStorage);
82
+ const targetBuckets = isRemote
83
+ ? await listBuckets(targetStorage)
84
+ : sourceBuckets;
85
+ const sourceBucketPicked = await cli.selectBuckets(sourceBuckets.buckets, "Select the source bucket:", false);
86
+ const targetBucketPicked = await cli.selectBuckets(targetBuckets.buckets, "Select the target bucket:", false);
87
+ sourceBucket = sourceBucketPicked[0];
88
+ targetBucket = targetBucketPicked[0];
89
+ }
90
+ let transferOptions = {
91
+ fromDb,
92
+ targetDb,
93
+ isRemote,
94
+ collections: selectedCollections.length > 0
95
+ ? selectedCollections.map((c) => c.$id)
96
+ : undefined,
97
+ sourceBucket,
98
+ targetBucket,
99
+ };
100
+ if (isRemote && remoteOptions) {
101
+ transferOptions = {
102
+ ...transferOptions,
103
+ ...remoteOptions,
104
+ };
105
+ }
106
+ MessageFormatter.progress("Transferring data...", { prefix: "Transfer" });
107
+ await cli.controller.transferData(transferOptions);
108
+ MessageFormatter.success("Data transfer completed", { prefix: "Transfer" });
109
+ },
110
+ async comprehensiveTransfer(cli) {
111
+ MessageFormatter.info("Starting comprehensive transfer configuration...", { prefix: "Transfer" });
112
+ try {
113
+ // Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
114
+ await cli.initControllerIfNeeded();
115
+ // Extract session for potential transfer operations
116
+ const sessionConfig = cli.extractSessionFromController();
117
+ // Check if user has an appwrite config for easier setup
118
+ const hasAppwriteConfig = cli.controller?.config?.appwriteEndpoint &&
119
+ cli.controller?.config?.appwriteProject &&
120
+ cli.controller?.config?.appwriteKey;
121
+ let sourceConfig;
122
+ let targetConfig;
123
+ if (hasAppwriteConfig) {
124
+ // Offer to use existing config for source
125
+ const { useConfigForSource } = await inquirer.prompt([
126
+ {
127
+ type: "confirm",
128
+ name: "useConfigForSource",
129
+ message: "Use your current appwriteConfig as the source?",
130
+ default: true,
131
+ },
132
+ ]);
133
+ if (useConfigForSource) {
134
+ sourceConfig = {
135
+ sourceEndpoint: cli.controller.config.appwriteEndpoint,
136
+ sourceProject: cli.controller.config.appwriteProject,
137
+ sourceKey: cli.controller.config.appwriteKey,
138
+ };
139
+ // Preserve session for source if available
140
+ if (sessionConfig?.sessionCookie) {
141
+ sourceConfig.sessionCookie = sessionConfig.sessionCookie;
142
+ sourceConfig.sessionMetadata = sessionConfig.sessionMetadata;
143
+ }
144
+ MessageFormatter.info(`Using config source: ${sourceConfig.sourceEndpoint}`, { prefix: "Transfer" });
145
+ }
146
+ else {
147
+ // Get source configuration manually
148
+ sourceConfig = await inquirer.prompt([
149
+ {
150
+ type: "input",
151
+ name: "sourceEndpoint",
152
+ message: "Enter the source Appwrite endpoint:",
153
+ validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
154
+ },
155
+ {
156
+ type: "input",
157
+ name: "sourceProject",
158
+ message: "Enter the source project ID:",
159
+ validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
160
+ },
161
+ {
162
+ type: "password",
163
+ name: "sourceKey",
164
+ message: "Enter the source API key:",
165
+ validate: (input) => input.trim() !== "" || "API key cannot be empty",
166
+ },
167
+ ]);
168
+ }
169
+ // Offer to use existing config for target
170
+ const { useConfigForTarget } = await inquirer.prompt([
171
+ {
172
+ type: "confirm",
173
+ name: "useConfigForTarget",
174
+ message: "Use your current appwriteConfig as the target?",
175
+ default: false,
176
+ },
177
+ ]);
178
+ if (useConfigForTarget) {
179
+ targetConfig = {
180
+ targetEndpoint: cli.controller.config.appwriteEndpoint,
181
+ targetProject: cli.controller.config.appwriteProject,
182
+ targetKey: cli.controller.config.appwriteKey,
183
+ };
184
+ // Preserve session for target if available
185
+ if (sessionConfig?.sessionCookie) {
186
+ targetConfig.sessionCookie = sessionConfig.sessionCookie;
187
+ targetConfig.sessionMetadata = sessionConfig.sessionMetadata;
188
+ }
189
+ MessageFormatter.info(`Using config target: ${targetConfig.targetEndpoint}`, { prefix: "Transfer" });
190
+ }
191
+ else {
192
+ // Get target configuration manually
193
+ targetConfig = await inquirer.prompt([
194
+ {
195
+ type: "input",
196
+ name: "targetEndpoint",
197
+ message: "Enter the target Appwrite endpoint:",
198
+ validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
199
+ },
200
+ {
201
+ type: "input",
202
+ name: "targetProject",
203
+ message: "Enter the target project ID:",
204
+ validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
205
+ },
206
+ {
207
+ type: "password",
208
+ name: "targetKey",
209
+ message: "Enter the target API key:",
210
+ validate: (input) => input.trim() !== "" || "API key cannot be empty",
211
+ },
212
+ ]);
213
+ }
214
+ }
215
+ else {
216
+ // No appwrite config found, get both configurations manually
217
+ MessageFormatter.info("No appwriteConfig found, please enter source and target configurations manually", { prefix: "Transfer" });
218
+ // Get source configuration
219
+ sourceConfig = await inquirer.prompt([
220
+ {
221
+ type: "input",
222
+ name: "sourceEndpoint",
223
+ message: "Enter the source Appwrite endpoint:",
224
+ validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
225
+ },
226
+ {
227
+ type: "input",
228
+ name: "sourceProject",
229
+ message: "Enter the source project ID:",
230
+ validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
231
+ },
232
+ {
233
+ type: "password",
234
+ name: "sourceKey",
235
+ message: "Enter the source API key:",
236
+ validate: (input) => input.trim() !== "" || "API key cannot be empty",
237
+ },
238
+ ]);
239
+ // Get target configuration
240
+ targetConfig = await inquirer.prompt([
241
+ {
242
+ type: "input",
243
+ name: "targetEndpoint",
244
+ message: "Enter the target Appwrite endpoint:",
245
+ validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
246
+ },
247
+ {
248
+ type: "input",
249
+ name: "targetProject",
250
+ message: "Enter the target project ID:",
251
+ validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
252
+ },
253
+ {
254
+ type: "password",
255
+ name: "targetKey",
256
+ message: "Enter the target API key:",
257
+ validate: (input) => input.trim() !== "" || "API key cannot be empty",
258
+ },
259
+ ]);
260
+ }
261
+ // Get transfer options
262
+ const transferOptions = await inquirer.prompt([
263
+ {
264
+ type: "checkbox",
265
+ name: "transferTypes",
266
+ message: "Select what to transfer:",
267
+ choices: [
268
+ { name: "👥 Users", value: "users", checked: true },
269
+ { name: "👥 Teams", value: "teams", checked: true },
270
+ { name: "🗄️ Databases", value: "databases", checked: true },
271
+ { name: "📦 Storage Buckets", value: "buckets", checked: true },
272
+ { name: "⚡ Functions", value: "functions", checked: true },
273
+ ],
274
+ validate: (input) => input.length > 0 || "Select at least one transfer type",
275
+ },
276
+ {
277
+ type: "list",
278
+ name: "concurrencyLimit",
279
+ message: "Select concurrency limit:",
280
+ choices: [
281
+ { name: "5 (Conservative) - Users: 2, Files: 1", value: 5 },
282
+ { name: "10 (Balanced) - Users: 5, Files: 2", value: 10 },
283
+ { name: "15 - Users: 7, Files: 3", value: 15 },
284
+ { name: "20 - Users: 10, Files: 5", value: 20 },
285
+ { name: "25 - Users: 12, Files: 6", value: 25 },
286
+ { name: "30 - Users: 15, Files: 7", value: 30 },
287
+ { name: "35 - Users: 17, Files: 8", value: 35 },
288
+ { name: "40 - Users: 20, Files: 10", value: 40 },
289
+ { name: "45 - Users: 22, Files: 11", value: 45 },
290
+ { name: "50 - Users: 25, Files: 12", value: 50 },
291
+ { name: "55 - Users: 27, Files: 13", value: 55 },
292
+ { name: "60 - Users: 30, Files: 15", value: 60 },
293
+ { name: "65 - Users: 32, Files: 16", value: 65 },
294
+ { name: "70 - Users: 35, Files: 17", value: 70 },
295
+ { name: "75 - Users: 37, Files: 18", value: 75 },
296
+ { name: "80 - Users: 40, Files: 20", value: 80 },
297
+ { name: "85 - Users: 42, Files: 21", value: 85 },
298
+ { name: "90 - Users: 45, Files: 22", value: 90 },
299
+ { name: "95 - Users: 47, Files: 23", value: 95 },
300
+ { name: "100 (Aggressive) - Users: 50, Files: 25", value: 100 },
301
+ ],
302
+ default: 10,
303
+ },
304
+ {
305
+ type: "confirm",
306
+ name: "dryRun",
307
+ message: "Run in dry-run mode (no actual changes)?",
308
+ default: false,
309
+ },
310
+ ]);
311
+ // Confirmation
312
+ const { confirmed } = await inquirer.prompt([
313
+ {
314
+ type: "confirm",
315
+ name: "confirmed",
316
+ message: `Are you sure you want to ${transferOptions.dryRun ? "dry-run" : "perform"} comprehensive transfer from ${sourceConfig.sourceEndpoint} to ${targetConfig.targetEndpoint}?`,
317
+ default: false,
318
+ },
319
+ ]);
320
+ if (!confirmed) {
321
+ MessageFormatter.info("Transfer cancelled by user", { prefix: "Transfer" });
322
+ return;
323
+ }
324
+ // Password preservation information
325
+ if (transferOptions.transferTypes.includes("users") && !transferOptions.dryRun) {
326
+ MessageFormatter.info("User Password Transfer Information:", { prefix: "Transfer" });
327
+ MessageFormatter.info("✅ Users with hashed passwords (Argon2, Bcrypt, Scrypt, MD5, SHA, PHPass) will preserve their passwords", { prefix: "Transfer" });
328
+ MessageFormatter.info("⚠️ Users without hash information will receive temporary passwords and need to reset", { prefix: "Transfer" });
329
+ MessageFormatter.info("🔒 All user data (preferences, labels, verification status) will be preserved", { prefix: "Transfer" });
330
+ const { continueWithUsers } = await inquirer.prompt([
331
+ {
332
+ type: "confirm",
333
+ name: "continueWithUsers",
334
+ message: "Continue with user transfer?",
335
+ default: true,
336
+ },
337
+ ]);
338
+ if (!continueWithUsers) {
339
+ // Remove users from transfer types
340
+ transferOptions.transferTypes = transferOptions.transferTypes.filter((type) => type !== "users");
341
+ if (transferOptions.transferTypes.length === 0) {
342
+ MessageFormatter.info("No transfer types selected, cancelling", { prefix: "Transfer" });
343
+ return;
344
+ }
345
+ }
346
+ }
347
+ // Execute comprehensive transfer
348
+ const comprehensiveTransferOptions = {
349
+ sourceEndpoint: sourceConfig.sourceEndpoint,
350
+ sourceProject: sourceConfig.sourceProject,
351
+ sourceKey: sourceConfig.sourceKey,
352
+ targetEndpoint: targetConfig.targetEndpoint,
353
+ targetProject: targetConfig.targetProject,
354
+ targetKey: targetConfig.targetKey,
355
+ transferUsers: transferOptions.transferTypes.includes("users"),
356
+ transferTeams: transferOptions.transferTypes.includes("teams"),
357
+ transferDatabases: transferOptions.transferTypes.includes("databases"),
358
+ transferBuckets: transferOptions.transferTypes.includes("buckets"),
359
+ transferFunctions: transferOptions.transferTypes.includes("functions"),
360
+ concurrencyLimit: transferOptions.concurrencyLimit,
361
+ dryRun: transferOptions.dryRun,
362
+ };
363
+ const transfer = new ComprehensiveTransfer(comprehensiveTransferOptions);
364
+ const results = await transfer.execute();
365
+ // Display results
366
+ if (transferOptions.dryRun) {
367
+ MessageFormatter.success("Dry run completed successfully!", { prefix: "Transfer" });
368
+ }
369
+ else {
370
+ MessageFormatter.success("Comprehensive transfer completed!", { prefix: "Transfer" });
371
+ if (transferOptions.transferTypes.includes("users") && results.users.transferred > 0) {
372
+ MessageFormatter.info("Users with preserved password hashes can log in with their original passwords", { prefix: "Transfer" });
373
+ MessageFormatter.info("Users with temporary passwords will need to reset their passwords", { prefix: "Transfer" });
374
+ }
375
+ if (transferOptions.transferTypes.includes("teams") && results.teams.transferred > 0) {
376
+ MessageFormatter.info("Team memberships have been transferred and may require user acceptance of invitations", { prefix: "Transfer" });
377
+ }
378
+ }
379
+ }
380
+ catch (error) {
381
+ MessageFormatter.error("Comprehensive transfer failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
382
+ }
383
+ }
384
+ };
@@ -1,12 +1,13 @@
1
1
  import { type Databases, type Models } from "node-appwrite";
2
2
  import { type Attribute } from "appwrite-utils";
3
+ import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
3
4
  /**
4
5
  * Enhanced attribute creation with proper status monitoring and retry logic
5
6
  */
6
- export declare const createOrUpdateAttributeWithStatusCheck: (db: Databases, dbId: string, collection: Models.Collection, attribute: Attribute, retryCount?: number, maxRetries?: number) => Promise<boolean>;
7
- export declare const createOrUpdateAttribute: (db: Databases, dbId: string, collection: Models.Collection, attribute: Attribute) => Promise<"queued" | "processed">;
7
+ export declare const createOrUpdateAttributeWithStatusCheck: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attribute: Attribute, retryCount?: number, maxRetries?: number) => Promise<boolean>;
8
+ export declare const createOrUpdateAttribute: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attribute: Attribute) => Promise<"queued" | "processed">;
8
9
  /**
9
10
  * Enhanced collection attribute creation with proper status monitoring
10
11
  */
11
- export declare const createUpdateCollectionAttributesWithStatusCheck: (db: Databases, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<boolean>;
12
- export declare const createUpdateCollectionAttributes: (db: Databases, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<void>;
12
+ export declare const createUpdateCollectionAttributesWithStatusCheck: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<boolean>;
13
+ export declare const createUpdateCollectionAttributes: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<void>;