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,358 +0,0 @@
1
- import type { AppwriteConfig, ConfigCollection } from "appwrite-utils";
2
- import {
3
- AppwriteException,
4
- Databases,
5
- ID,
6
- Query,
7
- Users,
8
- type Models,
9
- } from "node-appwrite";
10
- import {
11
- AuthUserSchema,
12
- type AuthUser,
13
- type AuthUserCreate,
14
- } from "../schemas/authUser.js";
15
- import { logger, MessageFormatter } from "appwrite-utils-helpers";
16
- import { splitIntoBatches } from "../shared/migrationHelpers.js";
17
- import {
18
- getAppwriteClient,
19
- tryAwaitWithRetry,
20
- } from "appwrite-utils-helpers";
21
- import { isUndefined } from "es-toolkit/compat";
22
- import { isEmpty } from "es-toolkit/compat";
23
-
24
- export class UsersController {
25
- private config: AppwriteConfig;
26
- private users: Users;
27
- static userFields = [
28
- "email",
29
- "name",
30
- "password",
31
- "phone",
32
- "labels",
33
- "prefs",
34
- "userId",
35
- "$createdAt",
36
- "$updatedAt",
37
- ];
38
-
39
- constructor(config: AppwriteConfig, db: Databases) {
40
- this.config = config;
41
- this.users = new Users(this.config.appwriteClient!);
42
- }
43
-
44
- async wipeUsers() {
45
- const allUsers = await this.getAllUsers();
46
- MessageFormatter.progress("Deleting all users...", { prefix: "Users" });
47
-
48
- const createBatches = (finalData: any[], batchSize: number) => {
49
- const finalBatches: any[][] = [];
50
- for (let i = 0; i < finalData.length; i += batchSize) {
51
- finalBatches.push(finalData.slice(i, i + batchSize));
52
- }
53
- return finalBatches;
54
- };
55
-
56
- let usersDeleted = 0;
57
- if (allUsers.length > 0) {
58
- const batchedUserPromises = createBatches(allUsers, 25); // Batch size of 25
59
-
60
- for (const batch of batchedUserPromises) {
61
- MessageFormatter.progress(`Deleting ${batch.length} users...`, { prefix: "Users" });
62
- await Promise.all(
63
- batch.map((user) =>
64
- tryAwaitWithRetry(async () => await this.users.delete(user.$id))
65
- )
66
- );
67
- usersDeleted += batch.length;
68
- if (usersDeleted % 100 === 0) {
69
- MessageFormatter.progress(`Deleted ${usersDeleted} users...`, { prefix: "Users" });
70
- }
71
- }
72
- } else {
73
- MessageFormatter.info("No users to delete", { prefix: "Users" });
74
- }
75
- }
76
-
77
- async getAllUsers() {
78
- const allUsers: Models.User<Models.Preferences>[] = [];
79
- const users = await tryAwaitWithRetry(
80
- async () => await this.users.list([Query.limit(200)])
81
- );
82
- if (users.users.length === 0) {
83
- return [];
84
- }
85
- if (users.users.length === 200) {
86
- let lastDocumentId = users.users[users.users.length - 1].$id;
87
- allUsers.push(...users.users);
88
- while (lastDocumentId) {
89
- const moreUsers = await tryAwaitWithRetry(
90
- async () =>
91
- await this.users.list([
92
- Query.limit(200),
93
- Query.cursorAfter(lastDocumentId),
94
- ])
95
- );
96
- allUsers.push(...moreUsers.users);
97
- if (moreUsers.users.length < 200) {
98
- break;
99
- }
100
- lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
101
- }
102
- } else {
103
- allUsers.push(...users.users);
104
- }
105
- return allUsers;
106
- }
107
-
108
- async createUsersAndReturn(items: AuthUserCreate[]): Promise<any[]> {
109
- const users = await Promise.all(
110
- items.map((item) => this.createUserAndReturn(item))
111
- );
112
- return users;
113
- }
114
-
115
- async createUserAndReturn(item: AuthUserCreate): Promise<any> {
116
- try {
117
- const user = await tryAwaitWithRetry(async () => {
118
- const createdUser = await this.users.create(
119
- item.userId || ID.unique(),
120
- item.email || undefined,
121
- item.phone && item.phone.length < 15 && item.phone.startsWith("+")
122
- ? item.phone
123
- : undefined,
124
- `changeMe${item.email?.toLowerCase()}` || `changeMePlease`,
125
- item.name || undefined
126
- );
127
-
128
- if (item.labels) {
129
- await this.users.updateLabels(createdUser.$id, item.labels);
130
- }
131
- if (item.prefs) {
132
- await this.users.updatePrefs(createdUser.$id, item.prefs);
133
- }
134
-
135
- return createdUser;
136
- }); // Set throwError to true since we want to handle errors
137
-
138
- return user;
139
- } catch (e) {
140
- if (e instanceof Error) {
141
- logger.error("FAILED CREATING USER: ", e.message, item);
142
- }
143
- }
144
- }
145
-
146
- async createAndCheckForUserAndReturn(item: AuthUserCreate) {
147
- let userToReturn: Models.User<Models.Preferences> | undefined = undefined;
148
- try {
149
- // Attempt to find an existing user by email or phone.
150
- let foundUsers: Models.User<Models.Preferences>[] = [];
151
- if (item.email) {
152
- const foundUsersByEmail = await this.users.list([
153
- Query.equal("email", item.email),
154
- ]);
155
- foundUsers = foundUsersByEmail.users;
156
- }
157
- if (item.phone) {
158
- const foundUsersByPhone = await this.users.list([
159
- Query.equal("phone", item.phone),
160
- ]);
161
- foundUsers = foundUsers.length
162
- ? foundUsers.concat(foundUsersByPhone.users)
163
- : foundUsersByPhone.users;
164
- }
165
-
166
- userToReturn = foundUsers[0] || undefined;
167
-
168
- if (!userToReturn) {
169
- userToReturn = await this.users.create(
170
- item.userId || ID.unique(),
171
- item.email || undefined,
172
- item.phone && item.phone.length < 15 && item.phone.startsWith("+")
173
- ? item.phone
174
- : undefined,
175
- item.password?.toLowerCase() ||
176
- `changeMe${item.email?.toLowerCase()}` ||
177
- `changeMePlease`,
178
- item.name || undefined
179
- );
180
- } else {
181
- // Update user details as necessary, ensuring email uniqueness if attempting an update.
182
- if (
183
- item.email &&
184
- item.email !== userToReturn.email &&
185
- !isEmpty(item.email) &&
186
- !isUndefined(item.email)
187
- ) {
188
- const emailExists = await this.users.list([
189
- Query.equal("email", item.email),
190
- ]);
191
- if (emailExists.users.length === 0) {
192
- userToReturn = await this.users.updateEmail(
193
- userToReturn.$id,
194
- item.email
195
- );
196
- } else {
197
- MessageFormatter.warning("Email update skipped: Email already exists.", { prefix: "Users" });
198
- }
199
- }
200
- if (item.password) {
201
- userToReturn = await this.users.updatePassword(
202
- userToReturn.$id,
203
- item.password.toLowerCase()
204
- );
205
- }
206
- if (item.name && item.name !== userToReturn.name) {
207
- userToReturn = await this.users.updateName(
208
- userToReturn.$id,
209
- item.name
210
- );
211
- }
212
- if (
213
- item.phone &&
214
- item.phone !== userToReturn.phone &&
215
- item.phone.length < 15 &&
216
- item.phone.startsWith("+") &&
217
- (isUndefined(userToReturn.phone) || isEmpty(userToReturn.phone))
218
- ) {
219
- const userFoundWithPhone = await this.users.list([
220
- Query.equal("phone", item.phone),
221
- ]);
222
- if (userFoundWithPhone.total === 0) {
223
- userToReturn = await this.users.updatePhone(
224
- userToReturn.$id,
225
- item.phone
226
- );
227
- }
228
- }
229
- }
230
- if (item.$createdAt && item.$updatedAt) {
231
- MessageFormatter.warning(
232
- "$createdAt and $updatedAt are not yet supported, sorry about that!",
233
- { prefix: "Users" }
234
- );
235
- }
236
- if (item.labels && item.labels.length) {
237
- userToReturn = await this.users.updateLabels(
238
- userToReturn.$id,
239
- item.labels
240
- );
241
- }
242
- if (item.prefs && Object.keys(item.prefs).length) {
243
- await this.users.updatePrefs(userToReturn.$id, item.prefs);
244
- userToReturn.prefs = item.prefs;
245
- }
246
- return userToReturn;
247
- } catch (error) {
248
- return userToReturn;
249
- }
250
- }
251
-
252
- async getUserIdByEmailOrPhone(email?: string, phone?: string) {
253
- if (!email && !phone) {
254
- return undefined;
255
- }
256
- if (email && phone) {
257
- const foundUsersByEmail = await this.users.list([
258
- // @ts-ignore
259
- Query.or([Query.equal("email", email), Query.equal("phone", phone)]),
260
- ]);
261
- if (foundUsersByEmail.users.length > 0) {
262
- return foundUsersByEmail.users[0]?.$id;
263
- }
264
- } else if (email) {
265
- const foundUsersByEmail = await this.users.list([
266
- Query.equal("email", email),
267
- ]);
268
- if (foundUsersByEmail.users.length > 0) {
269
- return foundUsersByEmail.users[0]?.$id;
270
- } else {
271
- if (!phone) {
272
- return undefined;
273
- } else {
274
- const foundUsersByPhone = await this.users.list([
275
- Query.equal("phone", phone),
276
- ]);
277
- if (foundUsersByPhone.users.length > 0) {
278
- return foundUsersByPhone.users[0]?.$id;
279
- } else {
280
- return undefined;
281
- }
282
- }
283
- }
284
- }
285
- if (phone) {
286
- const foundUsersByPhone = await this.users.list([
287
- Query.equal("phone", phone),
288
- ]);
289
- if (foundUsersByPhone.users.length > 0) {
290
- return foundUsersByPhone.users[0]?.$id;
291
- } else {
292
- return undefined;
293
- }
294
- }
295
- }
296
-
297
- transferUsersBetweenDbsLocalToRemote = async (
298
- endpoint: string,
299
- projectId: string,
300
- apiKey: string
301
- ) => {
302
- const localUsers = this.users;
303
- const client = getAppwriteClient(endpoint, projectId, apiKey);
304
- const remoteUsers = new Users(client);
305
-
306
- let fromUsers = await localUsers.list([Query.limit(50)]);
307
-
308
- if (fromUsers.users.length === 0) {
309
- MessageFormatter.info("No users found", { prefix: "Users" });
310
- return;
311
- } else if (fromUsers.users.length < 50) {
312
- MessageFormatter.progress(`Transferring ${fromUsers.users.length} users to remote`, { prefix: "Users" });
313
- const batchedPromises = fromUsers.users.map((user) => {
314
- return tryAwaitWithRetry(async () => {
315
- const toCreateObject: Partial<typeof user> = {
316
- ...user,
317
- };
318
- delete toCreateObject.$id;
319
- delete toCreateObject.$createdAt;
320
- delete toCreateObject.$updatedAt;
321
- await remoteUsers.create(
322
- user.$id,
323
- user.email,
324
- user.phone,
325
- user.password,
326
- user.name
327
- );
328
- });
329
- });
330
- await Promise.all(batchedPromises);
331
- } else {
332
- while (fromUsers.users.length === 50) {
333
- fromUsers = await localUsers.list([
334
- Query.limit(50),
335
- Query.cursorAfter(fromUsers.users[fromUsers.users.length - 1].$id),
336
- ]);
337
- const batchedPromises = fromUsers.users.map((user) => {
338
- return tryAwaitWithRetry(async () => {
339
- const toCreateObject: Partial<typeof user> = {
340
- ...user,
341
- };
342
- delete toCreateObject.$id;
343
- delete toCreateObject.$createdAt;
344
- delete toCreateObject.$updatedAt;
345
- await remoteUsers.create(
346
- user.$id,
347
- user.email,
348
- user.phone,
349
- user.password,
350
- user.name
351
- );
352
- });
353
- });
354
- await Promise.all(batchedPromises);
355
- }
356
- }
357
- };
358
- }
@@ -1,348 +0,0 @@
1
- import { promises as fs } from "fs";
2
- import path from "path";
3
- import { existsSync } from "fs";
4
- import { MessageFormatter } from "appwrite-utils-helpers";
5
- import { ConfirmationDialogs } from "../shared/confirmationDialogs.js";
6
- import yaml from "js-yaml";
7
-
8
- interface AppwriteConfigTS {
9
- appwriteEndpoint: string;
10
- appwriteProject: string;
11
- appwriteKey: string;
12
- enableBackups?: boolean;
13
- backupInterval?: number;
14
- backupRetention?: number;
15
- enableBackupCleanup?: boolean;
16
- enableMockData?: boolean;
17
- documentBucketId?: string;
18
- usersCollectionName?: string;
19
- databases: Array<{ $id: string; name: string }>;
20
- buckets: Array<any>;
21
- [key: string]: any;
22
- }
23
-
24
- interface AppwriteConfigYAML {
25
- appwrite: {
26
- endpoint: string;
27
- project: string;
28
- key: string;
29
- };
30
- logging: {
31
- enabled: boolean;
32
- level: string;
33
- console: boolean;
34
- logDirectory: string;
35
- };
36
- backups: {
37
- enabled: boolean;
38
- interval: number;
39
- retention: number;
40
- cleanup: boolean;
41
- };
42
- data: {
43
- enableMockData: boolean;
44
- documentBucketId: string;
45
- usersCollectionName: string;
46
- importDirectory: string;
47
- };
48
- schemas: {
49
- outputDirectory: string;
50
- yamlSchemaDirectory: string;
51
- };
52
- migrations: {
53
- enabled: boolean;
54
- };
55
- databases: Array<{ id: string; name: string; collections?: string[] }>;
56
- buckets: Array<any>;
57
- functions: Array<any>;
58
- }
59
-
60
- export async function migrateConfig(workingDir: string): Promise<void> {
61
- try {
62
- // Look for appwriteConfig.ts files in the working directory and subdirectories
63
- const configFiles = await findAppwriteConfigFiles(workingDir);
64
-
65
- if (configFiles.length === 0) {
66
- MessageFormatter.info("No appwriteConfig.ts files found to migrate", { prefix: "Migration" });
67
- return;
68
- }
69
-
70
- MessageFormatter.info(`Found ${configFiles.length} appwriteConfig.ts file(s) to migrate`, { prefix: "Migration" });
71
-
72
- for (const configFile of configFiles) {
73
- await migrateConfigFile(configFile, workingDir);
74
- }
75
-
76
- MessageFormatter.success("Migration completed successfully", { prefix: "Migration" });
77
- } catch (error) {
78
- MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
79
- throw error;
80
- }
81
- }
82
-
83
- async function findAppwriteConfigFiles(dir: string): Promise<string[]> {
84
- const configFiles: string[] = [];
85
-
86
- const checkDir = async (currentDir: string) => {
87
- try {
88
- const entries = await fs.readdir(currentDir, { withFileTypes: true });
89
-
90
- for (const entry of entries) {
91
- const fullPath = path.join(currentDir, entry.name);
92
-
93
- if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
94
- await checkDir(fullPath);
95
- } else if (entry.isFile() && entry.name === 'appwriteConfig.ts') {
96
- configFiles.push(fullPath);
97
- }
98
- }
99
- } catch (error) {
100
- // Ignore directory access errors
101
- }
102
- };
103
-
104
- await checkDir(dir);
105
- return configFiles;
106
- }
107
-
108
- async function migrateConfigFile(configFilePath: string, workingDir: string): Promise<void> {
109
- const configDir = path.dirname(configFilePath);
110
- const appwriteDir = path.join(path.dirname(configDir), '.appwrite');
111
-
112
- MessageFormatter.info(`Migrating ${path.relative(workingDir, configFilePath)}`, { prefix: "Migration" });
113
-
114
- // Check if .appwrite directory already exists
115
- if (existsSync(appwriteDir)) {
116
- const shouldOverwrite = await ConfirmationDialogs.confirmOverwrite(
117
- `.appwrite directory already exists at ${path.relative(workingDir, appwriteDir)}`
118
- );
119
- if (!shouldOverwrite) {
120
- MessageFormatter.info("Skipping migration for this config", { prefix: "Migration" });
121
- return;
122
- }
123
- }
124
-
125
- // Load and parse the TypeScript config
126
- const config = await parseTypeScriptConfig(configFilePath);
127
-
128
- // Create .appwrite directory
129
- await fs.mkdir(appwriteDir, { recursive: true });
130
-
131
- // Convert config to YAML and save
132
- const yamlConfig = convertToYAMLConfig(config);
133
- const yamlContent = yaml.dump(yamlConfig, {
134
- indent: 2,
135
- lineWidth: 120,
136
- noRefs: true
137
- });
138
- await fs.writeFile(path.join(appwriteDir, 'config.yaml'), yamlContent);
139
-
140
- // Copy all directories except collections and schemas (we handle collections separately, skip schemas entirely)
141
- const entries = await fs.readdir(configDir, { withFileTypes: true });
142
- for (const entry of entries) {
143
- if (entry.isDirectory() && entry.name !== 'collections' && entry.name !== 'schemas') {
144
- const sourcePath = path.join(configDir, entry.name);
145
- const targetPath = path.join(appwriteDir, entry.name);
146
-
147
- await fs.cp(sourcePath, targetPath, { recursive: true });
148
- MessageFormatter.info(`Copied ${entry.name}/ to .appwrite/${entry.name}/`, { prefix: "Migration" });
149
- }
150
- }
151
-
152
- // Convert TypeScript collections to YAML collections
153
- const collectionsPath = path.join(configDir, 'collections');
154
- if (existsSync(collectionsPath)) {
155
- const targetCollectionsPath = path.join(appwriteDir, 'collections');
156
- await fs.mkdir(targetCollectionsPath, { recursive: true });
157
-
158
- const collectionFiles = await fs.readdir(collectionsPath);
159
- for (const file of collectionFiles) {
160
- if (file.endsWith('.ts')) {
161
- await convertCollectionToYaml(path.join(collectionsPath, file), targetCollectionsPath);
162
- }
163
- }
164
- MessageFormatter.info(`Converted TypeScript collections to YAML in .appwrite/collections/`, { prefix: "Migration" });
165
- }
166
-
167
- // Keep original config file in place (no backup needed since we're not deleting it)
168
-
169
- MessageFormatter.success(`Migration completed for ${path.relative(workingDir, configFilePath)}`, { prefix: "Migration" });
170
- }
171
-
172
- async function parseTypeScriptConfig(configFilePath: string): Promise<AppwriteConfigTS> {
173
- try {
174
- // Use tsx to import the TypeScript config file directly
175
- const { register } = await import("tsx/esm/api");
176
- const { pathToFileURL } = await import("node:url");
177
-
178
- const unregister = register();
179
-
180
- try {
181
- const configUrl = pathToFileURL(configFilePath).href;
182
- const configModule = await import(configUrl);
183
- const config = configModule.default?.default || configModule.default || configModule;
184
-
185
- if (!config) {
186
- throw new Error("Failed to load config from TypeScript file");
187
- }
188
-
189
- return config as AppwriteConfigTS;
190
- } finally {
191
- unregister();
192
- }
193
- } catch (error) {
194
- MessageFormatter.error("Could not load TypeScript config", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
195
- throw new Error('Failed to load TypeScript configuration file. Please ensure it exports a valid config object.');
196
- }
197
- }
198
-
199
- function convertToYAMLConfig(config: AppwriteConfigTS): AppwriteConfigYAML {
200
- // Convert the config to the nested YAML structure
201
- const yamlConfig: AppwriteConfigYAML = {
202
- appwrite: {
203
- endpoint: config.appwriteEndpoint,
204
- project: config.appwriteProject,
205
- key: config.appwriteKey
206
- },
207
- logging: {
208
- enabled: config.logging?.enabled ?? false,
209
- level: config.logging?.level ?? "info",
210
- console: config.logging?.console ?? false,
211
- logDirectory: "./logs"
212
- },
213
- backups: {
214
- enabled: config.enableBackups ?? false,
215
- interval: config.backupInterval ?? 3600,
216
- retention: config.backupRetention ?? 30,
217
- cleanup: config.enableBackupCleanup ?? false
218
- },
219
- data: {
220
- enableMockData: config.enableMockData ?? false,
221
- documentBucketId: config.documentBucketId ?? "documents",
222
- usersCollectionName: config.usersCollectionName ?? "Users",
223
- importDirectory: "importData"
224
- },
225
- schemas: {
226
- outputDirectory: "schemas",
227
- yamlSchemaDirectory: ".yaml_schemas"
228
- },
229
- migrations: {
230
- enabled: true
231
- },
232
- databases: (config.databases || []).map(db => ({
233
- id: db.$id,
234
- name: db.name,
235
- collections: [] // Collections will be handled separately
236
- })),
237
- buckets: (config.buckets || []).map(bucket => ({
238
- id: bucket.$id,
239
- name: bucket.name,
240
- permissions: bucket.$permissions?.map((p: any) => ({
241
- permission: p.permission,
242
- target: p.target
243
- })) || [],
244
- fileSecurity: bucket.fileSecurity ?? false,
245
- enabled: bucket.enabled ?? true,
246
- maximumFileSize: bucket.maximumFileSize ?? 30000000,
247
- allowedFileExtensions: bucket.allowedFileExtensions || [],
248
- compression: bucket.compression || "gzip",
249
- encryption: bucket.encryption ?? false,
250
- antivirus: bucket.antivirus ?? false
251
- })),
252
- functions: (config.functions || []).map((func: any) => ({
253
- id: func.$id,
254
- name: func.name,
255
- runtime: func.runtime,
256
- execute: func.execute || [],
257
- events: func.events || [],
258
- schedule: func.schedule || "",
259
- timeout: func.timeout ?? 15,
260
- enabled: func.enabled ?? true,
261
- logging: func.logging ?? false,
262
- entrypoint: func.entrypoint || "src/main.js",
263
- commands: func.commands || "",
264
- scopes: func.scopes || [],
265
- specification: func.specification || "s-1vcpu-512mb"
266
- }))
267
- };
268
-
269
- return yamlConfig;
270
- }
271
-
272
- async function convertCollectionToYaml(tsFilePath: string, targetDir: string): Promise<void> {
273
- try {
274
- // Load the TypeScript collection using tsx
275
- const { register } = await import("tsx/esm/api");
276
- const { pathToFileURL } = await import("node:url");
277
-
278
- const unregister = register();
279
-
280
- try {
281
- const configUrl = pathToFileURL(tsFilePath).href;
282
- const collectionModule = await import(configUrl);
283
- const collection = collectionModule.default?.default || collectionModule.default || collectionModule;
284
-
285
- if (!collection) {
286
- throw new Error("Failed to load collection from TypeScript file");
287
- }
288
-
289
- // Convert collection to YAML format
290
- const yamlCollection = {
291
- name: collection.name,
292
- id: collection.$id,
293
- documentSecurity: collection.documentSecurity ?? false,
294
- enabled: collection.enabled ?? true,
295
- permissions: (collection.permissions || collection.$permissions || []).map((p: any) => ({
296
- permission: p.permission,
297
- target: p.target
298
- })),
299
- attributes: (collection.attributes || []).map((attr: any) => ({
300
- key: attr.key,
301
- type: attr.type,
302
- size: attr.size,
303
- required: attr.required ?? false,
304
- array: attr.array,
305
- default: attr.xdefault || attr.default,
306
- min: attr.min,
307
- max: attr.max,
308
- elements: attr.elements,
309
- relatedCollection: attr.relatedCollection,
310
- relationType: attr.relationType,
311
- twoWay: attr.twoWay,
312
- twoWayKey: attr.twoWayKey,
313
- onDelete: attr.onDelete,
314
- side: attr.side
315
- })),
316
- indexes: (collection.indexes || []).map((idx: any) => ({
317
- key: idx.key,
318
- type: idx.type,
319
- attributes: idx.attributes,
320
- orders: idx.orders
321
- })),
322
- importDefs: collection.importDefs || []
323
- };
324
-
325
- // Remove undefined values
326
- const cleanYamlCollection = JSON.parse(JSON.stringify(yamlCollection, (key, value) =>
327
- value === undefined ? undefined : value
328
- ));
329
-
330
- // Write YAML file
331
- const fileName = path.basename(tsFilePath, '.ts') + '.yaml';
332
- const targetPath = path.join(targetDir, fileName);
333
- const yamlContent = yaml.dump(cleanYamlCollection, {
334
- indent: 2,
335
- lineWidth: 120,
336
- noRefs: true
337
- });
338
-
339
- await fs.writeFile(targetPath, yamlContent);
340
- MessageFormatter.info(`Converted ${path.basename(tsFilePath)} to ${fileName}`, { prefix: "Migration" });
341
-
342
- } finally {
343
- unregister();
344
- }
345
- } catch (error) {
346
- MessageFormatter.error(`Failed to convert collection ${path.basename(tsFilePath)}`, error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
347
- }
348
- }