appwrite-utils-cli 0.0.286 → 0.9.2

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 (109) hide show
  1. package/README.md +162 -96
  2. package/dist/collections/attributes.d.ts +4 -0
  3. package/dist/collections/attributes.js +224 -0
  4. package/dist/collections/indexes.d.ts +4 -0
  5. package/dist/collections/indexes.js +27 -0
  6. package/dist/collections/methods.d.ts +16 -0
  7. package/dist/collections/methods.js +216 -0
  8. package/dist/databases/methods.d.ts +6 -0
  9. package/dist/databases/methods.js +33 -0
  10. package/dist/interactiveCLI.d.ts +19 -0
  11. package/dist/interactiveCLI.js +555 -0
  12. package/dist/main.js +224 -62
  13. package/dist/migrations/afterImportActions.js +37 -40
  14. package/dist/migrations/appwriteToX.d.ts +26 -25
  15. package/dist/migrations/appwriteToX.js +42 -6
  16. package/dist/migrations/attributes.js +21 -20
  17. package/dist/migrations/backup.d.ts +93 -87
  18. package/dist/migrations/collections.d.ts +6 -0
  19. package/dist/migrations/collections.js +149 -20
  20. package/dist/migrations/converters.d.ts +2 -18
  21. package/dist/migrations/converters.js +13 -2
  22. package/dist/migrations/dataLoader.d.ts +276 -161
  23. package/dist/migrations/dataLoader.js +535 -292
  24. package/dist/migrations/databases.js +8 -2
  25. package/dist/migrations/helper.d.ts +3 -0
  26. package/dist/migrations/helper.js +21 -0
  27. package/dist/migrations/importController.d.ts +5 -2
  28. package/dist/migrations/importController.js +125 -88
  29. package/dist/migrations/importDataActions.d.ts +9 -1
  30. package/dist/migrations/importDataActions.js +15 -3
  31. package/dist/migrations/indexes.js +3 -2
  32. package/dist/migrations/logging.js +20 -8
  33. package/dist/migrations/migrationHelper.d.ts +9 -4
  34. package/dist/migrations/migrationHelper.js +6 -5
  35. package/dist/migrations/openapi.d.ts +1 -1
  36. package/dist/migrations/openapi.js +33 -18
  37. package/dist/migrations/queue.js +3 -2
  38. package/dist/migrations/relationships.d.ts +2 -2
  39. package/dist/migrations/schemaStrings.js +53 -41
  40. package/dist/migrations/setupDatabase.d.ts +2 -4
  41. package/dist/migrations/setupDatabase.js +24 -105
  42. package/dist/migrations/storage.d.ts +3 -1
  43. package/dist/migrations/storage.js +110 -16
  44. package/dist/migrations/transfer.d.ts +30 -0
  45. package/dist/migrations/transfer.js +337 -0
  46. package/dist/migrations/users.d.ts +2 -1
  47. package/dist/migrations/users.js +78 -43
  48. package/dist/schemas/authUser.d.ts +2 -2
  49. package/dist/storage/methods.d.ts +15 -0
  50. package/dist/storage/methods.js +207 -0
  51. package/dist/storage/schemas.d.ts +687 -0
  52. package/dist/storage/schemas.js +175 -0
  53. package/dist/utils/getClientFromConfig.d.ts +4 -0
  54. package/dist/utils/getClientFromConfig.js +16 -0
  55. package/dist/utils/helperFunctions.d.ts +11 -1
  56. package/dist/utils/helperFunctions.js +38 -0
  57. package/dist/utils/retryFailedPromises.d.ts +2 -0
  58. package/dist/utils/retryFailedPromises.js +21 -0
  59. package/dist/utils/schemaStrings.d.ts +13 -0
  60. package/dist/utils/schemaStrings.js +403 -0
  61. package/dist/utils/setupFiles.js +110 -61
  62. package/dist/utilsController.d.ts +40 -22
  63. package/dist/utilsController.js +164 -84
  64. package/package.json +13 -15
  65. package/src/collections/attributes.ts +483 -0
  66. package/src/collections/indexes.ts +53 -0
  67. package/src/collections/methods.ts +331 -0
  68. package/src/databases/methods.ts +47 -0
  69. package/src/init.ts +64 -64
  70. package/src/interactiveCLI.ts +767 -0
  71. package/src/main.ts +289 -83
  72. package/src/migrations/afterImportActions.ts +553 -490
  73. package/src/migrations/appwriteToX.ts +237 -174
  74. package/src/migrations/attributes.ts +483 -422
  75. package/src/migrations/backup.ts +205 -205
  76. package/src/migrations/collections.ts +545 -300
  77. package/src/migrations/converters.ts +161 -150
  78. package/src/migrations/dataLoader.ts +1615 -1304
  79. package/src/migrations/databases.ts +44 -25
  80. package/src/migrations/dbHelpers.ts +92 -92
  81. package/src/migrations/helper.ts +40 -0
  82. package/src/migrations/importController.ts +448 -384
  83. package/src/migrations/importDataActions.ts +315 -307
  84. package/src/migrations/indexes.ts +40 -37
  85. package/src/migrations/logging.ts +29 -16
  86. package/src/migrations/migrationHelper.ts +207 -201
  87. package/src/migrations/openapi.ts +83 -70
  88. package/src/migrations/queue.ts +118 -119
  89. package/src/migrations/relationships.ts +324 -324
  90. package/src/migrations/schemaStrings.ts +472 -460
  91. package/src/migrations/setupDatabase.ts +118 -219
  92. package/src/migrations/storage.ts +538 -358
  93. package/src/migrations/transfer.ts +608 -0
  94. package/src/migrations/users.ts +362 -285
  95. package/src/migrations/validationRules.ts +63 -63
  96. package/src/schemas/authUser.ts +23 -23
  97. package/src/setup.ts +8 -8
  98. package/src/storage/methods.ts +371 -0
  99. package/src/storage/schemas.ts +205 -0
  100. package/src/types.ts +9 -9
  101. package/src/utils/getClientFromConfig.ts +17 -0
  102. package/src/utils/helperFunctions.ts +181 -127
  103. package/src/utils/index.ts +2 -2
  104. package/src/utils/loadConfigs.ts +59 -59
  105. package/src/utils/retryFailedPromises.ts +27 -0
  106. package/src/utils/schemaStrings.ts +473 -0
  107. package/src/utils/setupFiles.ts +228 -182
  108. package/src/utilsController.ts +325 -194
  109. package/tsconfig.json +37 -37
@@ -1,285 +1,362 @@
1
- import type { AppwriteConfig, ConfigCollection } from "appwrite-utils";
2
- import { Databases, ID, Query, Users, type Models } from "node-appwrite";
3
- import {
4
- AuthUserSchema,
5
- type AuthUser,
6
- type AuthUserCreate,
7
- } from "../schemas/authUser.js";
8
- import _ from "lodash";
9
- import { logger } from "./logging.js";
10
- import { splitIntoBatches } from "./migrationHelper.js";
11
-
12
- export class UsersController {
13
- private config: AppwriteConfig;
14
- private users: Users;
15
- static userFields = [
16
- "email",
17
- "name",
18
- "password",
19
- "phone",
20
- "labels",
21
- "prefs",
22
- "userId",
23
- "$createdAt",
24
- "$updatedAt",
25
- ];
26
-
27
- constructor(config: AppwriteConfig, db: Databases) {
28
- this.config = config;
29
- this.users = new Users(this.config.appwriteClient!);
30
- }
31
-
32
- async wipeUsers() {
33
- const users = await this.users.list([Query.limit(200)]);
34
- const allUsers = users.users;
35
- let lastDocumentId: string | undefined;
36
- if (users.users.length >= 200) {
37
- lastDocumentId = users.users[users.users.length - 1].$id;
38
- }
39
- while (lastDocumentId) {
40
- const moreUsers = await this.users.list([
41
- Query.limit(200),
42
- Query.cursorAfter(lastDocumentId),
43
- ]);
44
- allUsers.push(...moreUsers.users);
45
- if (moreUsers.users.length < 200) {
46
- break;
47
- }
48
- lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
49
- }
50
- console.log("Deleting all users...");
51
- const createBatches = (finalData: any[]) => {
52
- let maxBatchLength = 5;
53
- const finalBatches: any[][] = [];
54
- for (let i = 0; i < finalData.length; i++) {
55
- if (i % maxBatchLength === 0) {
56
- finalBatches.push([]);
57
- }
58
- finalBatches[finalBatches.length - 1].push(finalData[i]);
59
- }
60
- return finalBatches;
61
- };
62
- // const userPromises: Promise<string>[] = [];
63
- let usersDeleted = 0;
64
- for (const user of allUsers) {
65
- await this.users.delete(user.$id);
66
- usersDeleted++;
67
- if (usersDeleted % 100 === 0) {
68
- console.log(`Deleted ${usersDeleted} users...`);
69
- }
70
- }
71
- // const batchedUserPromises = createBatches(userPromises);
72
- // for (const batch of batchedUserPromises) {
73
- // console.log(`Deleting ${batch.length} users...`);
74
- // await Promise.all(batch);
75
- // }
76
- }
77
-
78
- async getAllUsers() {
79
- const allUsers: Models.User<Models.Preferences>[] = [];
80
- const users = await this.users.list([Query.limit(200)]);
81
- if (users.users.length === 200) {
82
- let lastDocumentId = users.users[users.users.length - 1].$id;
83
- allUsers.push(...users.users);
84
- while (lastDocumentId) {
85
- const moreUsers = await this.users.list([
86
- Query.limit(200),
87
- Query.cursorAfter(lastDocumentId),
88
- ]);
89
- allUsers.push(...moreUsers.users);
90
- lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
91
- if (moreUsers.users.length < 200) {
92
- break;
93
- }
94
- }
95
- } else {
96
- allUsers.push(...users.users);
97
- }
98
- return allUsers;
99
- }
100
-
101
- async createUsersAndReturn(items: AuthUserCreate[]) {
102
- const users = await Promise.all(
103
- items.map((item) => this.createUserAndReturn(item))
104
- );
105
- return users;
106
- }
107
-
108
- async createUserAndReturn(item: AuthUserCreate) {
109
- try {
110
- const user = await this.users.create(
111
- item.userId || ID.unique(),
112
- item.email || undefined,
113
- item.phone && item.phone.length < 15 && item.phone.startsWith("+")
114
- ? item.phone
115
- : undefined,
116
- item.password?.toLowerCase() ||
117
- `changeMe${item.email?.toLowerCase()}` ||
118
- `changeMePlease`,
119
- item.name || undefined
120
- );
121
- if (item.labels) {
122
- await this.users.updateLabels(user.$id, item.labels);
123
- }
124
- if (item.prefs) {
125
- await this.users.updatePrefs(user.$id, item.prefs);
126
- }
127
- return user;
128
- } catch (e) {
129
- if (e instanceof Error) {
130
- logger.error("FAILED CREATING USER: ", e.message);
131
- }
132
- throw e;
133
- }
134
- }
135
-
136
- async createAndCheckForUserAndReturn(item: AuthUserCreate) {
137
- let userToReturn: Models.User<Models.Preferences> | undefined = undefined;
138
- try {
139
- // Attempt to find an existing user by email or phone.
140
- let foundUsers: Models.User<Models.Preferences>[] = [];
141
- if (item.email) {
142
- const foundUsersByEmail = await this.users.list([
143
- Query.equal("email", item.email),
144
- ]);
145
- foundUsers = foundUsersByEmail.users;
146
- }
147
- if (item.phone) {
148
- const foundUsersByPhone = await this.users.list([
149
- Query.equal("phone", item.phone),
150
- ]);
151
- foundUsers = foundUsers.length
152
- ? foundUsers.concat(foundUsersByPhone.users)
153
- : foundUsersByPhone.users;
154
- }
155
-
156
- userToReturn = foundUsers[0] || undefined;
157
-
158
- if (!userToReturn) {
159
- userToReturn = await this.users.create(
160
- item.userId || ID.unique(),
161
- item.email || undefined,
162
- item.phone && item.phone.length < 15 && item.phone.startsWith("+")
163
- ? item.phone
164
- : undefined,
165
- item.password?.toLowerCase() ||
166
- `changeMe${item.email?.toLowerCase()}` ||
167
- `changeMePlease`,
168
- item.name || undefined
169
- );
170
- } else {
171
- // Update user details as necessary, ensuring email uniqueness if attempting an update.
172
- if (
173
- item.email &&
174
- item.email !== userToReturn.email &&
175
- !_.isEmpty(item.email) &&
176
- !_.isUndefined(item.email)
177
- ) {
178
- const emailExists = await this.users.list([
179
- Query.equal("email", item.email),
180
- ]);
181
- if (emailExists.users.length === 0) {
182
- userToReturn = await this.users.updateEmail(
183
- userToReturn.$id,
184
- item.email
185
- );
186
- } else {
187
- console.log("Email update skipped: Email already exists.");
188
- }
189
- }
190
- if (item.password) {
191
- userToReturn = await this.users.updatePassword(
192
- userToReturn.$id,
193
- item.password.toLowerCase()
194
- );
195
- }
196
- if (item.name && item.name !== userToReturn.name) {
197
- userToReturn = await this.users.updateName(
198
- userToReturn.$id,
199
- item.name
200
- );
201
- }
202
- if (
203
- item.phone &&
204
- item.phone !== userToReturn.phone &&
205
- item.phone.length < 15 &&
206
- item.phone.startsWith("+") &&
207
- (_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))
208
- ) {
209
- const userFoundWithPhone = await this.users.list([
210
- Query.equal("phone", item.phone),
211
- ]);
212
- if (userFoundWithPhone.total === 0) {
213
- userToReturn = await this.users.updatePhone(
214
- userToReturn.$id,
215
- item.phone
216
- );
217
- }
218
- }
219
- }
220
- if (item.$createdAt && item.$updatedAt) {
221
- console.log(
222
- "$createdAt and $updatedAt are not yet supported, sorry about that!"
223
- );
224
- }
225
- if (item.labels && item.labels.length) {
226
- userToReturn = await this.users.updateLabels(
227
- userToReturn.$id,
228
- item.labels
229
- );
230
- }
231
- if (item.prefs && Object.keys(item.prefs).length) {
232
- await this.users.updatePrefs(userToReturn.$id, item.prefs);
233
- userToReturn.prefs = item.prefs;
234
- }
235
- return userToReturn;
236
- } catch (error) {
237
- return userToReturn;
238
- }
239
- }
240
-
241
- async getUserIdByEmailOrPhone(email?: string, phone?: string) {
242
- if (!email && !phone) {
243
- return undefined;
244
- }
245
- if (email && phone) {
246
- const foundUsersByEmail = await this.users.list([
247
- // @ts-ignore
248
- Query.or([Query.equal("email", email), Query.equal("phone", phone)]),
249
- ]);
250
- if (foundUsersByEmail.users.length > 0) {
251
- return foundUsersByEmail.users[0]?.$id;
252
- }
253
- } else if (email) {
254
- const foundUsersByEmail = await this.users.list([
255
- Query.equal("email", email),
256
- ]);
257
- if (foundUsersByEmail.users.length > 0) {
258
- return foundUsersByEmail.users[0]?.$id;
259
- } else {
260
- if (!phone) {
261
- return undefined;
262
- } else {
263
- const foundUsersByPhone = await this.users.list([
264
- Query.equal("phone", phone),
265
- ]);
266
- if (foundUsersByPhone.users.length > 0) {
267
- return foundUsersByPhone.users[0]?.$id;
268
- } else {
269
- return undefined;
270
- }
271
- }
272
- }
273
- }
274
- if (phone) {
275
- const foundUsersByPhone = await this.users.list([
276
- Query.equal("phone", phone),
277
- ]);
278
- if (foundUsersByPhone.users.length > 0) {
279
- return foundUsersByPhone.users[0]?.$id;
280
- } else {
281
- return undefined;
282
- }
283
- }
284
- }
285
- }
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 _ from "lodash";
16
+ import { logger } from "./logging.js";
17
+ import { splitIntoBatches } from "./migrationHelper.js";
18
+ import {
19
+ getAppwriteClient,
20
+ tryAwaitWithRetry,
21
+ } from "../utils/helperFunctions.js";
22
+
23
+ export class UsersController {
24
+ private config: AppwriteConfig;
25
+ private users: Users;
26
+ static userFields = [
27
+ "email",
28
+ "name",
29
+ "password",
30
+ "phone",
31
+ "labels",
32
+ "prefs",
33
+ "userId",
34
+ "$createdAt",
35
+ "$updatedAt",
36
+ ];
37
+
38
+ constructor(config: AppwriteConfig, db: Databases) {
39
+ this.config = config;
40
+ this.users = new Users(this.config.appwriteClient!);
41
+ }
42
+
43
+ async wipeUsers() {
44
+ const allUsers = await this.getAllUsers();
45
+ console.log("Deleting all users...");
46
+
47
+ const createBatches = (finalData: any[], batchSize: number) => {
48
+ const finalBatches: any[][] = [];
49
+ for (let i = 0; i < finalData.length; i += batchSize) {
50
+ finalBatches.push(finalData.slice(i, i + batchSize));
51
+ }
52
+ return finalBatches;
53
+ };
54
+
55
+ let usersDeleted = 0;
56
+ const batchedUserPromises = createBatches(allUsers, 50); // Batch size of 10
57
+
58
+ for (const batch of batchedUserPromises) {
59
+ console.log(`Deleting ${batch.length} users...`);
60
+ await Promise.all(
61
+ batch.map((user) =>
62
+ tryAwaitWithRetry(async () => await this.users.delete(user.$id))
63
+ )
64
+ );
65
+ usersDeleted += batch.length;
66
+ if (usersDeleted % 100 === 0) {
67
+ console.log(`Deleted ${usersDeleted} users...`);
68
+ }
69
+ }
70
+ }
71
+
72
+ async getAllUsers() {
73
+ const allUsers: Models.User<Models.Preferences>[] = [];
74
+ const users = await tryAwaitWithRetry(
75
+ async () => await this.users.list([Query.limit(200)])
76
+ );
77
+ if (users.users.length === 0) {
78
+ return [];
79
+ }
80
+ if (users.users.length === 200) {
81
+ let lastDocumentId = users.users[users.users.length - 1].$id;
82
+ allUsers.push(...users.users);
83
+ while (lastDocumentId) {
84
+ const moreUsers = await tryAwaitWithRetry(
85
+ async () =>
86
+ await this.users.list([
87
+ Query.limit(200),
88
+ Query.cursorAfter(lastDocumentId),
89
+ ])
90
+ );
91
+ allUsers.push(...moreUsers.users);
92
+ if (moreUsers.users.length < 200) {
93
+ break;
94
+ }
95
+ lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
96
+ }
97
+ } else {
98
+ allUsers.push(...users.users);
99
+ }
100
+ return allUsers;
101
+ }
102
+
103
+ async createUsersAndReturn(items: AuthUserCreate[]) {
104
+ const users = await Promise.all(
105
+ items.map((item) => this.createUserAndReturn(item))
106
+ );
107
+ return users;
108
+ }
109
+
110
+ async createUserAndReturn(item: AuthUserCreate, numAttempts?: number) {
111
+ try {
112
+ const user = await this.users.create(
113
+ item.userId || ID.unique(),
114
+ item.email || undefined,
115
+ item.phone && item.phone.length < 15 && item.phone.startsWith("+")
116
+ ? item.phone
117
+ : undefined,
118
+ `changeMe${item.email?.toLowerCase()}` || `changeMePlease`,
119
+ item.name || undefined
120
+ );
121
+ if (item.labels) {
122
+ await this.users.updateLabels(user.$id, item.labels);
123
+ }
124
+ if (item.prefs) {
125
+ await this.users.updatePrefs(user.$id, item.prefs);
126
+ }
127
+ return user;
128
+ } catch (e) {
129
+ if (e instanceof AppwriteException) {
130
+ if (
131
+ e.message.toLowerCase().includes("fetch failed") ||
132
+ e.message.toLowerCase().includes("server error")
133
+ ) {
134
+ const numberOfAttempts = numAttempts || 0;
135
+ if (numberOfAttempts > 5) {
136
+ throw e;
137
+ }
138
+ const user: Models.User<Models.Preferences> =
139
+ await this.createUserAndReturn(item, numberOfAttempts + 1);
140
+ return user;
141
+ }
142
+ }
143
+ if (e instanceof Error) {
144
+ logger.error("FAILED CREATING USER: ", e.message, item);
145
+ }
146
+ console.log("FAILED CREATING USER: ", e, item);
147
+ throw e;
148
+ }
149
+ }
150
+
151
+ async createAndCheckForUserAndReturn(item: AuthUserCreate) {
152
+ let userToReturn: Models.User<Models.Preferences> | undefined = undefined;
153
+ try {
154
+ // Attempt to find an existing user by email or phone.
155
+ let foundUsers: Models.User<Models.Preferences>[] = [];
156
+ if (item.email) {
157
+ const foundUsersByEmail = await this.users.list([
158
+ Query.equal("email", item.email),
159
+ ]);
160
+ foundUsers = foundUsersByEmail.users;
161
+ }
162
+ if (item.phone) {
163
+ const foundUsersByPhone = await this.users.list([
164
+ Query.equal("phone", item.phone),
165
+ ]);
166
+ foundUsers = foundUsers.length
167
+ ? foundUsers.concat(foundUsersByPhone.users)
168
+ : foundUsersByPhone.users;
169
+ }
170
+
171
+ userToReturn = foundUsers[0] || undefined;
172
+
173
+ if (!userToReturn) {
174
+ userToReturn = await this.users.create(
175
+ item.userId || ID.unique(),
176
+ item.email || undefined,
177
+ item.phone && item.phone.length < 15 && item.phone.startsWith("+")
178
+ ? item.phone
179
+ : undefined,
180
+ item.password?.toLowerCase() ||
181
+ `changeMe${item.email?.toLowerCase()}` ||
182
+ `changeMePlease`,
183
+ item.name || undefined
184
+ );
185
+ } else {
186
+ // Update user details as necessary, ensuring email uniqueness if attempting an update.
187
+ if (
188
+ item.email &&
189
+ item.email !== userToReturn.email &&
190
+ !_.isEmpty(item.email) &&
191
+ !_.isUndefined(item.email)
192
+ ) {
193
+ const emailExists = await this.users.list([
194
+ Query.equal("email", item.email),
195
+ ]);
196
+ if (emailExists.users.length === 0) {
197
+ userToReturn = await this.users.updateEmail(
198
+ userToReturn.$id,
199
+ item.email
200
+ );
201
+ } else {
202
+ console.log("Email update skipped: Email already exists.");
203
+ }
204
+ }
205
+ if (item.password) {
206
+ userToReturn = await this.users.updatePassword(
207
+ userToReturn.$id,
208
+ item.password.toLowerCase()
209
+ );
210
+ }
211
+ if (item.name && item.name !== userToReturn.name) {
212
+ userToReturn = await this.users.updateName(
213
+ userToReturn.$id,
214
+ item.name
215
+ );
216
+ }
217
+ if (
218
+ item.phone &&
219
+ item.phone !== userToReturn.phone &&
220
+ item.phone.length < 15 &&
221
+ item.phone.startsWith("+") &&
222
+ (_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))
223
+ ) {
224
+ const userFoundWithPhone = await this.users.list([
225
+ Query.equal("phone", item.phone),
226
+ ]);
227
+ if (userFoundWithPhone.total === 0) {
228
+ userToReturn = await this.users.updatePhone(
229
+ userToReturn.$id,
230
+ item.phone
231
+ );
232
+ }
233
+ }
234
+ }
235
+ if (item.$createdAt && item.$updatedAt) {
236
+ console.log(
237
+ "$createdAt and $updatedAt are not yet supported, sorry about that!"
238
+ );
239
+ }
240
+ if (item.labels && item.labels.length) {
241
+ userToReturn = await this.users.updateLabels(
242
+ userToReturn.$id,
243
+ item.labels
244
+ );
245
+ }
246
+ if (item.prefs && Object.keys(item.prefs).length) {
247
+ await this.users.updatePrefs(userToReturn.$id, item.prefs);
248
+ userToReturn.prefs = item.prefs;
249
+ }
250
+ return userToReturn;
251
+ } catch (error) {
252
+ return userToReturn;
253
+ }
254
+ }
255
+
256
+ async getUserIdByEmailOrPhone(email?: string, phone?: string) {
257
+ if (!email && !phone) {
258
+ return undefined;
259
+ }
260
+ if (email && phone) {
261
+ const foundUsersByEmail = await this.users.list([
262
+ // @ts-ignore
263
+ Query.or([Query.equal("email", email), Query.equal("phone", phone)]),
264
+ ]);
265
+ if (foundUsersByEmail.users.length > 0) {
266
+ return foundUsersByEmail.users[0]?.$id;
267
+ }
268
+ } else if (email) {
269
+ const foundUsersByEmail = await this.users.list([
270
+ Query.equal("email", email),
271
+ ]);
272
+ if (foundUsersByEmail.users.length > 0) {
273
+ return foundUsersByEmail.users[0]?.$id;
274
+ } else {
275
+ if (!phone) {
276
+ return undefined;
277
+ } else {
278
+ const foundUsersByPhone = await this.users.list([
279
+ Query.equal("phone", phone),
280
+ ]);
281
+ if (foundUsersByPhone.users.length > 0) {
282
+ return foundUsersByPhone.users[0]?.$id;
283
+ } else {
284
+ return undefined;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ if (phone) {
290
+ const foundUsersByPhone = await this.users.list([
291
+ Query.equal("phone", phone),
292
+ ]);
293
+ if (foundUsersByPhone.users.length > 0) {
294
+ return foundUsersByPhone.users[0]?.$id;
295
+ } else {
296
+ return undefined;
297
+ }
298
+ }
299
+ }
300
+
301
+ transferUsersBetweenDbsLocalToRemote = async (
302
+ endpoint: string,
303
+ projectId: string,
304
+ apiKey: string
305
+ ) => {
306
+ const localUsers = this.users;
307
+ const client = getAppwriteClient(endpoint, projectId, apiKey);
308
+ const remoteUsers = new Users(client);
309
+
310
+ let fromUsers = await localUsers.list([Query.limit(50)]);
311
+
312
+ if (fromUsers.users.length === 0) {
313
+ console.log(`No users found`);
314
+ return;
315
+ } else if (fromUsers.users.length < 50) {
316
+ console.log(`Transferring ${fromUsers.users.length} users to remote`);
317
+ const batchedPromises = fromUsers.users.map((user) => {
318
+ return tryAwaitWithRetry(async () => {
319
+ const toCreateObject: Partial<typeof user> = {
320
+ ...user,
321
+ };
322
+ delete toCreateObject.$id;
323
+ delete toCreateObject.$createdAt;
324
+ delete toCreateObject.$updatedAt;
325
+ await remoteUsers.create(
326
+ user.$id,
327
+ user.email,
328
+ user.phone,
329
+ user.password,
330
+ user.name
331
+ );
332
+ });
333
+ });
334
+ await Promise.all(batchedPromises);
335
+ } else {
336
+ while (fromUsers.users.length === 50) {
337
+ fromUsers = await localUsers.list([
338
+ Query.limit(50),
339
+ Query.cursorAfter(fromUsers.users[fromUsers.users.length - 1].$id),
340
+ ]);
341
+ const batchedPromises = fromUsers.users.map((user) => {
342
+ return tryAwaitWithRetry(async () => {
343
+ const toCreateObject: Partial<typeof user> = {
344
+ ...user,
345
+ };
346
+ delete toCreateObject.$id;
347
+ delete toCreateObject.$createdAt;
348
+ delete toCreateObject.$updatedAt;
349
+ await remoteUsers.create(
350
+ user.$id,
351
+ user.email,
352
+ user.phone,
353
+ user.password,
354
+ user.name
355
+ );
356
+ });
357
+ });
358
+ await Promise.all(batchedPromises);
359
+ }
360
+ }
361
+ };
362
+ }