appwrite-utils-cli 0.0.65 → 0.0.66

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.
@@ -319,6 +319,7 @@ export declare const getMigrationCollectionSchemas: () => {
319
319
  fieldToSet?: string | undefined;
320
320
  targetFieldToMatch?: string | undefined;
321
321
  }[] | undefined;
322
+ createUsers?: boolean | null | undefined;
322
323
  updateMapping?: {
323
324
  targetField: string;
324
325
  originalIdField: string;
@@ -573,6 +574,7 @@ export declare const getMigrationCollectionSchemas: () => {
573
574
  fieldToSet?: string | undefined;
574
575
  targetFieldToMatch?: string | undefined;
575
576
  }[] | undefined;
577
+ createUsers?: boolean | null | undefined;
576
578
  updateMapping?: {
577
579
  targetField: string;
578
580
  originalIdField: string;
@@ -366,7 +366,16 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
366
366
  fieldToSet: z.ZodOptional<z.ZodString>;
367
367
  targetFieldToMatch: z.ZodOptional<z.ZodString>;
368
368
  targetField: z.ZodString;
369
- targetCollection: z.ZodString;
369
+ targetCollection: z.ZodString; /**
370
+ * Prepares the data for updating documents within a collection.
371
+ * This method loads the raw data based on the import definition, transforms it according to the attribute mappings,
372
+ * finds the new ID for each item based on the primary key or update mapping, and then validates the transformed data.
373
+ * If the data is valid, it updates the import definition with any post-import actions and adds the item to the current collection data.
374
+ *
375
+ * @param db - The database configuration.
376
+ * @param collection - The collection configuration.
377
+ * @param importDef - The import definition containing the attribute mappings and other relevant info.
378
+ */
370
379
  }, "strip", z.ZodTypeAny, {
371
380
  sourceField: string;
372
381
  targetField: string;
@@ -380,6 +389,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
380
389
  fieldToSet?: string | undefined;
381
390
  targetFieldToMatch?: string | undefined;
382
391
  }>, "many">>;
392
+ createUsers: z.ZodOptional<z.ZodNullable<z.ZodDefault<z.ZodBoolean>>>;
383
393
  updateMapping: z.ZodOptional<z.ZodObject<{
384
394
  originalIdField: z.ZodString;
385
395
  targetField: z.ZodString;
@@ -494,6 +504,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
494
504
  fieldToSet?: string | undefined;
495
505
  targetFieldToMatch?: string | undefined;
496
506
  }[] | undefined;
507
+ createUsers?: boolean | null | undefined;
497
508
  updateMapping?: {
498
509
  targetField: string;
499
510
  originalIdField: string;
@@ -529,6 +540,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
529
540
  fieldToSet?: string | undefined;
530
541
  targetFieldToMatch?: string | undefined;
531
542
  }[] | undefined;
543
+ createUsers?: boolean | null | undefined;
532
544
  updateMapping?: {
533
545
  targetField: string;
534
546
  originalIdField: string;
@@ -623,16 +635,6 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
623
635
  relatedCollection: string;
624
636
  relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
625
637
  twoWay: boolean;
626
- /**
627
- * Generates attribute mappings with post-import actions based on the provided attribute mappings.
628
- * This method checks each mapping for a fileData attribute and adds a post-import action to create a file
629
- * and update the field with the file's ID if necessary.
630
- *
631
- * @param attributeMappings - The attribute mappings from the import definition.
632
- * @param context - The context object containing information about the database, collection, and document.
633
- * @param item - The item being imported, used for resolving template paths in fileData mappings.
634
- * @returns The attribute mappings updated with any necessary post-import actions.
635
- */
636
638
  twoWayKey: string;
637
639
  onDelete: "setNull" | "cascade" | "restrict";
638
640
  side: "parent" | "child";
@@ -689,6 +691,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
689
691
  fieldToSet?: string | undefined;
690
692
  targetFieldToMatch?: string | undefined;
691
693
  }[] | undefined;
694
+ createUsers?: boolean | null | undefined;
692
695
  updateMapping?: {
693
696
  targetField: string;
694
697
  originalIdField: string;
@@ -845,6 +848,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
845
848
  fieldToSet?: string | undefined;
846
849
  targetFieldToMatch?: string | undefined;
847
850
  }[] | undefined;
851
+ createUsers?: boolean | null | undefined;
848
852
  updateMapping?: {
849
853
  targetField: string;
850
854
  originalIdField: string;
@@ -880,6 +884,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
880
884
  fieldToSet?: string | undefined;
881
885
  targetFieldToMatch?: string | undefined;
882
886
  }>, "many">>;
887
+ createUsers: z.ZodOptional<z.ZodNullable<z.ZodDefault<z.ZodBoolean>>>;
883
888
  updateMapping: z.ZodOptional<z.ZodObject<{
884
889
  originalIdField: z.ZodString;
885
890
  targetField: z.ZodString;
@@ -994,6 +999,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
994
999
  fieldToSet?: string | undefined;
995
1000
  targetFieldToMatch?: string | undefined;
996
1001
  }[] | undefined;
1002
+ createUsers?: boolean | null | undefined;
997
1003
  updateMapping?: {
998
1004
  targetField: string;
999
1005
  originalIdField: string;
@@ -1029,6 +1035,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1029
1035
  fieldToSet?: string | undefined;
1030
1036
  targetFieldToMatch?: string | undefined;
1031
1037
  }[] | undefined;
1038
+ createUsers?: boolean | null | undefined;
1032
1039
  updateMapping?: {
1033
1040
  targetField: string;
1034
1041
  originalIdField: string;
@@ -1069,6 +1076,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1069
1076
  fieldToSet?: string | undefined;
1070
1077
  targetFieldToMatch?: string | undefined;
1071
1078
  }[] | undefined;
1079
+ createUsers?: boolean | null | undefined;
1072
1080
  updateMapping?: {
1073
1081
  targetField: string;
1074
1082
  originalIdField: string;
@@ -1109,6 +1117,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1109
1117
  fieldToSet?: string | undefined;
1110
1118
  targetFieldToMatch?: string | undefined;
1111
1119
  }[] | undefined;
1120
+ createUsers?: boolean | null | undefined;
1112
1121
  updateMapping?: {
1113
1122
  targetField: string;
1114
1123
  originalIdField: string;
@@ -1151,6 +1160,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1151
1160
  fieldToSet?: string | undefined;
1152
1161
  targetFieldToMatch?: string | undefined;
1153
1162
  }[] | undefined;
1163
+ createUsers?: boolean | null | undefined;
1154
1164
  updateMapping?: {
1155
1165
  targetField: string;
1156
1166
  originalIdField: string;
@@ -1245,16 +1255,6 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1245
1255
  relatedCollection: string;
1246
1256
  relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
1247
1257
  twoWay: boolean;
1248
- /**
1249
- * Generates attribute mappings with post-import actions based on the provided attribute mappings.
1250
- * This method checks each mapping for a fileData attribute and adds a post-import action to create a file
1251
- * and update the field with the file's ID if necessary.
1252
- *
1253
- * @param attributeMappings - The attribute mappings from the import definition.
1254
- * @param context - The context object containing information about the database, collection, and document.
1255
- * @param item - The item being imported, used for resolving template paths in fileData mappings.
1256
- * @returns The attribute mappings updated with any necessary post-import actions.
1257
- */
1258
1258
  twoWayKey: string;
1259
1259
  onDelete: "setNull" | "cascade" | "restrict";
1260
1260
  side: "parent" | "child";
@@ -1311,6 +1311,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1311
1311
  fieldToSet?: string | undefined;
1312
1312
  targetFieldToMatch?: string | undefined;
1313
1313
  }[] | undefined;
1314
+ createUsers?: boolean | null | undefined;
1314
1315
  updateMapping?: {
1315
1316
  targetField: string;
1316
1317
  originalIdField: string;
@@ -1357,6 +1358,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1357
1358
  fieldToSet?: string | undefined;
1358
1359
  targetFieldToMatch?: string | undefined;
1359
1360
  }[] | undefined;
1361
+ createUsers?: boolean | null | undefined;
1360
1362
  updateMapping?: {
1361
1363
  targetField: string;
1362
1364
  originalIdField: string;
@@ -1510,6 +1512,7 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
1510
1512
  fieldToSet?: string | undefined;
1511
1513
  targetFieldToMatch?: string | undefined;
1512
1514
  }[] | undefined;
1515
+ createUsers?: boolean | null | undefined;
1513
1516
  updateMapping?: {
1514
1517
  targetField: string;
1515
1518
  originalIdField: string;
@@ -1561,6 +1564,7 @@ export declare class DataLoader {
1561
1564
  fieldToSet?: string | undefined;
1562
1565
  targetFieldToMatch?: string | undefined;
1563
1566
  }[] | undefined;
1567
+ createUsers?: boolean | null | undefined;
1564
1568
  updateMapping?: {
1565
1569
  targetField: string;
1566
1570
  originalIdField: string;
@@ -1655,16 +1659,6 @@ export declare class DataLoader {
1655
1659
  relatedCollection: string;
1656
1660
  relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
1657
1661
  twoWay: boolean;
1658
- /**
1659
- * Generates attribute mappings with post-import actions based on the provided attribute mappings.
1660
- * This method checks each mapping for a fileData attribute and adds a post-import action to create a file
1661
- * and update the field with the file's ID if necessary.
1662
- *
1663
- * @param attributeMappings - The attribute mappings from the import definition.
1664
- * @param context - The context object containing information about the database, collection, and document.
1665
- * @param item - The item being imported, used for resolving template paths in fileData mappings.
1666
- * @returns The attribute mappings updated with any necessary post-import actions.
1667
- */
1668
1662
  twoWayKey: string;
1669
1663
  onDelete: "setNull" | "cascade" | "restrict";
1670
1664
  side: "parent" | "child";
@@ -1721,6 +1715,7 @@ export declare class DataLoader {
1721
1715
  fieldToSet?: string | undefined;
1722
1716
  targetFieldToMatch?: string | undefined;
1723
1717
  }[] | undefined;
1718
+ createUsers?: boolean | null | undefined;
1724
1719
  updateMapping?: {
1725
1720
  targetField: string;
1726
1721
  originalIdField: string;
@@ -1737,6 +1732,7 @@ export declare class DataLoader {
1737
1732
  private mergedUserMap;
1738
1733
  private emailToUserIdMap;
1739
1734
  private phoneToUserIdMap;
1735
+ private userIdSet;
1740
1736
  userExistsMap: Map<string, boolean>;
1741
1737
  private shouldWriteFile;
1742
1738
  constructor(appwriteFolderPath: string, importDataActions: ImportDataActions, database: Databases, config: AppwriteConfig, shouldWriteFile?: boolean);
@@ -45,6 +45,7 @@ export class DataLoader {
45
45
  // Maps to hold email and phone to user ID mappings for unique-ness in User Accounts
46
46
  emailToUserIdMap = new Map();
47
47
  phoneToUserIdMap = new Map();
48
+ userIdSet = new Set();
48
49
  userExistsMap = new Map();
49
50
  shouldWriteFile = false;
50
51
  // Constructor to initialize the DataLoader with necessary configurations
@@ -173,6 +174,7 @@ export class DataLoader {
173
174
  let newId = ID.unique();
174
175
  let condition = this.checkMapValuesForId(newId, collectionName) ||
175
176
  this.userExistsMap.has(newId) ||
177
+ this.userIdSet.has(newId) ||
176
178
  this.importMap
177
179
  .get(this.getCollectionKey("users"))
178
180
  ?.data.some((user) => user.finalData.docId === newId || user.finalData.userId === newId);
@@ -181,6 +183,7 @@ export class DataLoader {
181
183
  condition =
182
184
  this.checkMapValuesForId(newId, collectionName) ||
183
185
  this.userExistsMap.has(newId) ||
186
+ this.userIdSet.has(newId) ||
184
187
  this.importMap
185
188
  .get(this.getCollectionKey("users"))
186
189
  ?.data.some((user) => user.finalData.docId === newId || user.finalData.userId === newId);
@@ -260,12 +263,13 @@ export class DataLoader {
260
263
  // Iterate over the users and setup our maps ahead of time for email and phone
261
264
  for (const user of allUsers) {
262
265
  if (user.email) {
263
- this.emailToUserIdMap.set(user.email, user.$id);
266
+ this.emailToUserIdMap.set(user.email.toLowerCase(), user.$id);
264
267
  }
265
268
  if (user.phone) {
266
269
  this.phoneToUserIdMap.set(user.phone, user.$id);
267
270
  }
268
271
  this.userExistsMap.set(user.$id, true);
272
+ this.userIdSet.add(user.$id);
269
273
  let importData = this.importMap.get(this.getCollectionKey("users"));
270
274
  if (!importData) {
271
275
  importData = {
@@ -275,11 +279,13 @@ export class DataLoader {
275
279
  importData.data.push({
276
280
  finalData: {
277
281
  ...user,
282
+ email: user.email?.toLowerCase(),
278
283
  userId: user.$id,
279
284
  docId: user.$id,
280
285
  },
281
286
  context: {
282
287
  ...user,
288
+ email: user.email?.toLowerCase(),
283
289
  userId: user.$id,
284
290
  docId: user.$id,
285
291
  },
@@ -320,7 +326,7 @@ export class DataLoader {
320
326
  const createDefs = collection.importDefs.filter((def) => def.type === "create" || !def.type);
321
327
  const updateDefs = collection.importDefs.filter((def) => def.type === "update");
322
328
  for (const createDef of createDefs) {
323
- if (!isUsersCollection) {
329
+ if (!isUsersCollection || !createDef.createUsers) {
324
330
  await this.prepareCreateData(db, collection, createDef);
325
331
  }
326
332
  else {
@@ -581,14 +587,18 @@ export class DataLoader {
581
587
  * @returns The transformed item with user-specific keys removed.
582
588
  */
583
589
  prepareUserData(item, attributeMappings, primaryKeyField, newId) {
584
- if (this.userExistsMap.has(newId) ||
590
+ if (this.userIdSet.has(newId) ||
591
+ this.userExistsMap.has(newId) ||
585
592
  Array.from(this.emailToUserIdMap.values()).includes(newId) ||
586
593
  Array.from(this.phoneToUserIdMap.values()).includes(newId)) {
587
594
  newId = this.getTrueUniqueId(this.getCollectionKey("users"));
588
595
  }
589
596
  let transformedItem = this.transformData(item, attributeMappings);
590
- const userData = AuthUserCreateSchema.safeParse(transformedItem);
591
- if (!userData.success || !(userData.data.email && userData.data.phone)) {
597
+ let userData = AuthUserCreateSchema.safeParse(transformedItem);
598
+ if (userData.data?.email) {
599
+ userData.data.email = userData.data.email.toLowerCase();
600
+ }
601
+ if (!userData.success || !(userData.data.email || userData.data.phone)) {
592
602
  logger.error(`Invalid user data: ${JSON.stringify(userData.error?.errors, undefined, 2)} or missing email/phone`);
593
603
  const userKeys = ["email", "phone", "name", "labels", "prefs"];
594
604
  userKeys.forEach((key) => {
@@ -605,7 +615,7 @@ export class DataLoader {
605
615
  },
606
616
  };
607
617
  }
608
- const email = userData.data.email;
618
+ const email = userData.data.email?.toLowerCase();
609
619
  const phone = userData.data.phone;
610
620
  let existingId;
611
621
  // Check for duplicate email and phone
@@ -653,7 +663,12 @@ export class DataLoader {
653
663
  if (userFound) {
654
664
  userFound.finalData.userId = existingId;
655
665
  userFound.finalData.docId = existingId;
656
- this.userExistsMap.set(existingId, true);
666
+ this.userIdSet.add(existingId);
667
+ transformedItem = {
668
+ ...transformedItem,
669
+ userId: existingId,
670
+ docId: existingId,
671
+ };
657
672
  }
658
673
  const userKeys = ["email", "phone", "name", "labels", "prefs"];
659
674
  userKeys.forEach((key) => {
@@ -688,6 +703,7 @@ export class DataLoader {
688
703
  this.importMap.set(this.getCollectionKey("users"), {
689
704
  data: [...(usersMap?.data || []), userDataToAdd],
690
705
  });
706
+ this.userIdSet.add(existingId);
691
707
  return {
692
708
  transformedItem,
693
709
  existingId,
@@ -1033,7 +1049,10 @@ export class DataLoader {
1033
1049
  // Update the import definition with the new attribute mappings
1034
1050
  const newImportDef = {
1035
1051
  ...importDef,
1036
- attributeMappings: mappingsWithActions,
1052
+ attributeMappings: [
1053
+ ...importDef.attributeMappings,
1054
+ ...mappingsWithActions,
1055
+ ],
1037
1056
  };
1038
1057
  if (itemDataToUpdate) {
1039
1058
  itemDataToUpdate.finalData = this.mergeObjects(itemDataToUpdate.finalData, transformedData);
@@ -58,10 +58,10 @@ export class UsersController {
58
58
  Query.cursorAfter(lastDocumentId),
59
59
  ]));
60
60
  allUsers.push(...moreUsers.users);
61
- lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
62
61
  if (moreUsers.users.length < 200) {
63
62
  break;
64
63
  }
64
+ lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
65
65
  }
66
66
  }
67
67
  else {
@@ -99,9 +99,9 @@ export class UsersController {
99
99
  }
100
100
  }
101
101
  if (e instanceof Error) {
102
- logger.error("FAILED CREATING USER: ", e.message);
102
+ logger.error("FAILED CREATING USER: ", e.message, item);
103
103
  }
104
- console.log("FAILED CREATING USER: ", e);
104
+ console.log("FAILED CREATING USER: ", e, item);
105
105
  throw e;
106
106
  }
107
107
  }
package/package.json CHANGED
@@ -1,54 +1,55 @@
1
- {
2
- "name": "appwrite-utils-cli",
3
- "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "0.0.65",
5
- "main": "src/main.ts",
6
- "type": "module",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/zachhandley/AppwriteUtils"
10
- },
11
- "author": "Zach Handley <zach@blackleafdigital.com> (https://zachhandley.com)",
12
- "keywords": [
13
- "appwrite",
14
- "cli",
15
- "utils",
16
- "migrations",
17
- "data",
18
- "database",
19
- "import",
20
- "migration",
21
- "utility"
22
- ],
23
- "bin": {
24
- "appwrite-init": "./dist/init.js",
25
- "appwrite-migrate": "./dist/main.js"
26
- },
27
- "scripts": {
28
- "build": "bun run tsc",
29
- "init": "tsx --no-cache src/init.ts",
30
- "migrate": "tsx --no-cache src/main.ts",
31
- "deploy": "bun run build && npm publish --access public",
32
- "postinstall": "echo 'This package is intended for CLI use only and should not be added as a dependency in other projects.'"
33
- },
34
- "dependencies": {
35
- "@types/inquirer": "^9.0.7",
36
- "appwrite-utils": "^0.3.2",
37
- "commander": "^12.0.0",
38
- "inquirer": "^9.2.20",
39
- "js-yaml": "^4.1.0",
40
- "lodash": "^4.17.21",
41
- "luxon": "^3.4.4",
42
- "nanostores": "^0.10.3",
43
- "node-appwrite": "^12.0.1",
44
- "tsx": "^4.9.3",
45
- "winston": "^3.13.0",
46
- "zod": "^3.22.4"
47
- },
48
- "devDependencies": {
49
- "@types/js-yaml": "^4.0.9",
50
- "@types/lodash": "^4.17.0",
51
- "@types/luxon": "^3.4.2",
52
- "typescript": "^5.0.0"
53
- }
54
- }
1
+ {
2
+ "name": "appwrite-utils-cli",
3
+ "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
+ "version": "0.0.66",
5
+ "main": "src/main.ts",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/zachhandley/AppwriteUtils"
10
+ },
11
+ "author": "Zach Handley <zach@blackleafdigital.com> (https://zachhandley.com)",
12
+ "keywords": [
13
+ "appwrite",
14
+ "cli",
15
+ "utils",
16
+ "migrations",
17
+ "data",
18
+ "database",
19
+ "import",
20
+ "migration",
21
+ "utility"
22
+ ],
23
+ "bin": {
24
+ "appwrite-init": "./dist/init.js",
25
+ "appwrite-migrate": "./dist/main.js"
26
+ },
27
+ "scripts": {
28
+ "build": "bun run tsc",
29
+ "init": "tsx --no-cache src/init.ts",
30
+ "migrate": "tsx --no-cache src/main.ts",
31
+ "deploy": "bun run build && npm publish --access public",
32
+ "postinstall": "echo 'This package is intended for CLI use only and should not be added as a dependency in other projects.'"
33
+ },
34
+ "dependencies": {
35
+ "@types/inquirer": "^9.0.7",
36
+ "appwrite-utils": "^0.3.3",
37
+ "commander": "^12.0.0",
38
+ "inquirer": "^9.2.20",
39
+ "js-yaml": "^4.1.0",
40
+ "lodash": "^4.17.21",
41
+ "luxon": "^3.4.4",
42
+ "nanostores": "^0.10.3",
43
+ "node-appwrite": "^12.0.1",
44
+ "tsx": "^4.9.3",
45
+ "ulid": "^2.3.0",
46
+ "winston": "^3.13.0",
47
+ "zod": "^3.22.4"
48
+ },
49
+ "devDependencies": {
50
+ "@types/js-yaml": "^4.0.9",
51
+ "@types/lodash": "^4.17.0",
52
+ "@types/luxon": "^3.4.2",
53
+ "typescript": "^5.0.0"
54
+ }
55
+ }
@@ -64,6 +64,7 @@ export class DataLoader {
64
64
  // Maps to hold email and phone to user ID mappings for unique-ness in User Accounts
65
65
  private emailToUserIdMap = new Map<string, string>();
66
66
  private phoneToUserIdMap = new Map<string, string>();
67
+ private userIdSet = new Set<string>();
67
68
  userExistsMap = new Map<string, boolean>();
68
69
  private shouldWriteFile = false;
69
70
 
@@ -212,6 +213,7 @@ export class DataLoader {
212
213
  let condition =
213
214
  this.checkMapValuesForId(newId, collectionName) ||
214
215
  this.userExistsMap.has(newId) ||
216
+ this.userIdSet.has(newId) ||
215
217
  this.importMap
216
218
  .get(this.getCollectionKey("users"))
217
219
  ?.data.some(
@@ -223,6 +225,7 @@ export class DataLoader {
223
225
  condition =
224
226
  this.checkMapValuesForId(newId, collectionName) ||
225
227
  this.userExistsMap.has(newId) ||
228
+ this.userIdSet.has(newId) ||
226
229
  this.importMap
227
230
  .get(this.getCollectionKey("users"))
228
231
  ?.data.some(
@@ -330,12 +333,13 @@ export class DataLoader {
330
333
  // Iterate over the users and setup our maps ahead of time for email and phone
331
334
  for (const user of allUsers) {
332
335
  if (user.email) {
333
- this.emailToUserIdMap.set(user.email, user.$id);
336
+ this.emailToUserIdMap.set(user.email.toLowerCase(), user.$id);
334
337
  }
335
338
  if (user.phone) {
336
339
  this.phoneToUserIdMap.set(user.phone, user.$id);
337
340
  }
338
341
  this.userExistsMap.set(user.$id, true);
342
+ this.userIdSet.add(user.$id);
339
343
  let importData = this.importMap.get(this.getCollectionKey("users"));
340
344
  if (!importData) {
341
345
  importData = {
@@ -345,11 +349,13 @@ export class DataLoader {
345
349
  importData.data.push({
346
350
  finalData: {
347
351
  ...user,
352
+ email: user.email?.toLowerCase(),
348
353
  userId: user.$id,
349
354
  docId: user.$id,
350
355
  },
351
356
  context: {
352
357
  ...user,
358
+ email: user.email?.toLowerCase(),
353
359
  userId: user.$id,
354
360
  docId: user.$id,
355
361
  },
@@ -398,7 +404,7 @@ export class DataLoader {
398
404
  (def: ImportDef) => def.type === "update"
399
405
  );
400
406
  for (const createDef of createDefs) {
401
- if (!isUsersCollection) {
407
+ if (!isUsersCollection || !createDef.createUsers) {
402
408
  await this.prepareCreateData(db, collection, createDef);
403
409
  } else {
404
410
  // Special handling for users collection if needed
@@ -761,6 +767,7 @@ export class DataLoader {
761
767
  };
762
768
  } {
763
769
  if (
770
+ this.userIdSet.has(newId) ||
764
771
  this.userExistsMap.has(newId) ||
765
772
  Array.from(this.emailToUserIdMap.values()).includes(newId) ||
766
773
  Array.from(this.phoneToUserIdMap.values()).includes(newId)
@@ -768,8 +775,11 @@ export class DataLoader {
768
775
  newId = this.getTrueUniqueId(this.getCollectionKey("users"));
769
776
  }
770
777
  let transformedItem = this.transformData(item, attributeMappings);
771
- const userData = AuthUserCreateSchema.safeParse(transformedItem);
772
- if (!userData.success || !(userData.data.email && userData.data.phone)) {
778
+ let userData = AuthUserCreateSchema.safeParse(transformedItem);
779
+ if (userData.data?.email) {
780
+ userData.data.email = userData.data.email.toLowerCase();
781
+ }
782
+ if (!userData.success || !(userData.data.email || userData.data.phone)) {
773
783
  logger.error(
774
784
  `Invalid user data: ${JSON.stringify(
775
785
  userData.error?.errors,
@@ -793,7 +803,7 @@ export class DataLoader {
793
803
  },
794
804
  };
795
805
  }
796
- const email = userData.data.email;
806
+ const email = userData.data.email?.toLowerCase();
797
807
  const phone = userData.data.phone;
798
808
  let existingId: string | undefined;
799
809
 
@@ -836,7 +846,12 @@ export class DataLoader {
836
846
  if (userFound) {
837
847
  userFound.finalData.userId = existingId;
838
848
  userFound.finalData.docId = existingId;
839
- this.userExistsMap.set(existingId, true);
849
+ this.userIdSet.add(existingId);
850
+ transformedItem = {
851
+ ...transformedItem,
852
+ userId: existingId,
853
+ docId: existingId,
854
+ };
840
855
  }
841
856
 
842
857
  const userKeys = ["email", "phone", "name", "labels", "prefs"];
@@ -873,6 +888,7 @@ export class DataLoader {
873
888
  this.importMap.set(this.getCollectionKey("users"), {
874
889
  data: [...(usersMap?.data || []), userDataToAdd],
875
890
  });
891
+ this.userIdSet.add(existingId);
876
892
 
877
893
  return {
878
894
  transformedItem,
@@ -1418,7 +1434,10 @@ export class DataLoader {
1418
1434
  // Update the import definition with the new attribute mappings
1419
1435
  const newImportDef = {
1420
1436
  ...importDef,
1421
- attributeMappings: mappingsWithActions,
1437
+ attributeMappings: [
1438
+ ...importDef.attributeMappings,
1439
+ ...mappingsWithActions,
1440
+ ],
1422
1441
  };
1423
1442
 
1424
1443
  if (itemDataToUpdate) {
@@ -89,10 +89,10 @@ export class UsersController {
89
89
  ])
90
90
  );
91
91
  allUsers.push(...moreUsers.users);
92
- lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
93
92
  if (moreUsers.users.length < 200) {
94
93
  break;
95
94
  }
95
+ lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
96
96
  }
97
97
  } else {
98
98
  allUsers.push(...users.users);
@@ -141,9 +141,9 @@ export class UsersController {
141
141
  }
142
142
  }
143
143
  if (e instanceof Error) {
144
- logger.error("FAILED CREATING USER: ", e.message);
144
+ logger.error("FAILED CREATING USER: ", e.message, item);
145
145
  }
146
- console.log("FAILED CREATING USER: ", e);
146
+ console.log("FAILED CREATING USER: ", e, item);
147
147
  throw e;
148
148
  }
149
149
  }