appwrite-utils-cli 0.0.37 → 0.0.38

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.
package/README.md CHANGED
@@ -86,6 +86,7 @@ This setup ensures that developers have robust tools at their fingertips to mana
86
86
 
87
87
  ### Changelog
88
88
 
89
+ - 0.0.38: Lots of optimizations done to the code, added `tryAwaitWithRetry` for `fetch failed` and others like it errors (looking at you `server error`) -- this should prevent things from going sideways.
89
90
  - 0.0.37: Added `documentSecurity`, `enabled`, and `$id` to the `init` collection
90
91
  - 0.0.36: Made it update collections by default, sometimes you gotta do what you gotta do
91
92
  - 0.0.35: Added update collection if it exists and permissions or such are different (`documentSecurity` and `enabled`), also added a check for `fetch failed` errors to retry them with recursion, not sure how well that will work out, but we're gonna try it! It will still fail after 5 tries, but hopefully that gives Appwrite some time to figure it's stuff out
@@ -2,6 +2,7 @@ import { Query } from "node-appwrite";
2
2
  import { attributeSchema, parseAttribute, } from "appwrite-utils";
3
3
  import { nameToIdMapping, enqueueOperation } from "./queue.js";
4
4
  import _ from "lodash";
5
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
5
6
  const attributesSame = (databaseAttribute, configAttribute) => {
6
7
  return (databaseAttribute.key == configAttribute.key &&
7
8
  databaseAttribute.type == configAttribute.type &&
@@ -105,10 +106,10 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
105
106
  switch (finalAttribute.type) {
106
107
  case "string":
107
108
  if (action === "create") {
108
- await db.createStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.size, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array || false, finalAttribute.encrypted);
109
+ await tryAwaitWithRetry(async () => await db.createStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.size, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array || false, finalAttribute.encrypted));
109
110
  }
110
111
  else {
111
- await db.updateStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined);
112
+ await tryAwaitWithRetry(async () => await db.updateStringAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined));
112
113
  }
113
114
  break;
114
115
  case "integer":
@@ -121,7 +122,7 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
121
122
  BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
122
123
  delete finalAttribute.max;
123
124
  }
124
- await db.createIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault || undefined, finalAttribute.array);
125
+ await tryAwaitWithRetry(async () => await db.createIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault || undefined, finalAttribute.array));
125
126
  }
126
127
  else {
127
128
  if (finalAttribute.min &&
@@ -132,71 +133,71 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
132
133
  BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
133
134
  delete finalAttribute.max;
134
135
  }
135
- await db.updateIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || 0, finalAttribute.max || 2147483647, finalAttribute.xdefault || undefined);
136
+ await tryAwaitWithRetry(async () => await db.updateIntegerAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || 0, finalAttribute.max || 2147483647, finalAttribute.xdefault || undefined));
136
137
  }
137
138
  break;
138
139
  case "float":
139
140
  if (action === "create") {
140
- await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault || undefined, finalAttribute.array);
141
+ await tryAwaitWithRetry(async () => await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault || undefined, finalAttribute.array));
141
142
  }
142
143
  else {
143
- await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || 0, finalAttribute.max || 2147483647, finalAttribute.xdefault || undefined);
144
+ await tryAwaitWithRetry(async () => await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min || 0, finalAttribute.max || 2147483647, finalAttribute.xdefault || undefined));
144
145
  }
145
146
  break;
146
147
  case "boolean":
147
148
  if (action === "create") {
148
- await db.createBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
149
+ await tryAwaitWithRetry(async () => await db.createBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
149
150
  }
150
151
  else {
151
- await db.updateBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || null);
152
+ await tryAwaitWithRetry(async () => await db.updateBooleanAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || null));
152
153
  }
153
154
  break;
154
155
  case "datetime":
155
156
  if (action === "create") {
156
- await db.createDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
157
+ await tryAwaitWithRetry(async () => await db.createDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
157
158
  }
158
159
  else {
159
- await db.updateDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined);
160
+ await tryAwaitWithRetry(async () => await db.updateDatetimeAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined));
160
161
  }
161
162
  break;
162
163
  case "email":
163
164
  if (action === "create") {
164
- await db.createEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
165
+ await tryAwaitWithRetry(async () => await db.createEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
165
166
  }
166
167
  else {
167
- await db.updateEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined);
168
+ await tryAwaitWithRetry(async () => await db.updateEmailAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined));
168
169
  }
169
170
  break;
170
171
  case "ip":
171
172
  if (action === "create") {
172
- await db.createIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
173
+ await tryAwaitWithRetry(async () => await db.createIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
173
174
  }
174
175
  else {
175
- await db.updateIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined);
176
+ await tryAwaitWithRetry(async () => await db.updateIpAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined));
176
177
  }
177
178
  break;
178
179
  case "url":
179
180
  if (action === "create") {
180
- await db.createUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
181
+ await tryAwaitWithRetry(async () => await db.createUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
181
182
  }
182
183
  else {
183
- await db.updateUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined);
184
+ await tryAwaitWithRetry(async () => await db.updateUrlAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.xdefault || undefined));
184
185
  }
185
186
  break;
186
187
  case "enum":
187
188
  if (action === "create") {
188
- await db.createEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array);
189
+ await tryAwaitWithRetry(async () => await db.createEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault || undefined, finalAttribute.array));
189
190
  }
190
191
  else {
191
- await db.updateEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault || undefined);
192
+ await tryAwaitWithRetry(async () => await db.updateEnumAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.elements, finalAttribute.required || false, finalAttribute.xdefault || undefined));
192
193
  }
193
194
  break;
194
195
  case "relationship":
195
196
  if (action === "create") {
196
- await db.createRelationshipAttribute(dbId, collection.$id, relatedCollectionId, finalAttribute.relationType, finalAttribute.twoWay, finalAttribute.key, finalAttribute.twoWayKey, finalAttribute.onDelete);
197
+ await tryAwaitWithRetry(async () => await db.createRelationshipAttribute(dbId, collection.$id, relatedCollectionId, finalAttribute.relationType, finalAttribute.twoWay, finalAttribute.key, finalAttribute.twoWayKey, finalAttribute.onDelete));
197
198
  }
198
199
  else {
199
- await db.updateRelationshipAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.onDelete);
200
+ await tryAwaitWithRetry(async () => await db.updateRelationshipAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.onDelete));
200
201
  }
201
202
  break;
202
203
  default:
@@ -4,6 +4,7 @@ import { createUpdateCollectionAttributes } from "./attributes.js";
4
4
  import { createOrUpdateIndexes } from "./indexes.js";
5
5
  import _ from "lodash";
6
6
  import { SchemaGenerator } from "./schemaStrings.js";
7
+ import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
7
8
  export const documentExists = async (db, dbId, targetCollectionId, toCreateObject) => {
8
9
  // Had to do this because kept running into issues with type checking arrays so, sorry 40ms
9
10
  const collection = await db.getCollection(dbId, targetCollectionId);
@@ -48,9 +49,7 @@ export const documentExists = async (db, dbId, targetCollectionId, toCreateObjec
48
49
  export const checkForCollection = async (db, dbId, collection) => {
49
50
  try {
50
51
  console.log(`Checking for collection with name: ${collection.name}`);
51
- const response = await db.listCollections(dbId, [
52
- Query.equal("name", collection.name),
53
- ]);
52
+ const response = await tryAwaitWithRetry(async () => await db.listCollections(dbId, [Query.equal("name", collection.name)]));
54
53
  if (response.collections.length > 0) {
55
54
  console.log(`Collection found: ${response.collections[0].$id}`);
56
55
  return { ...collection, ...response.collections[0] };
@@ -70,13 +69,11 @@ export const fetchAndCacheCollectionByName = async (db, dbId, collectionName) =>
70
69
  if (nameToIdMapping.has(collectionName)) {
71
70
  const collectionId = nameToIdMapping.get(collectionName);
72
71
  console.log(`\tCollection found in cache: ${collectionId}`);
73
- return await db.getCollection(dbId, collectionId);
72
+ return await tryAwaitWithRetry(async () => await db.getCollection(dbId, collectionId));
74
73
  }
75
74
  else {
76
75
  console.log(`\tFetching collection by name: ${collectionName}`);
77
- const collectionsPulled = await db.listCollections(dbId, [
78
- Query.equal("name", collectionName),
79
- ]);
76
+ const collectionsPulled = await tryAwaitWithRetry(async () => await db.listCollections(dbId, [Query.equal("name", collectionName)]));
80
77
  if (collectionsPulled.total > 0) {
81
78
  const collection = collectionsPulled.collections[0];
82
79
  console.log(`\tCollection found: ${collection.$id}`);
@@ -91,7 +88,7 @@ export const fetchAndCacheCollectionByName = async (db, dbId, collectionName) =>
91
88
  };
92
89
  export const wipeDatabase = async (database, databaseId) => {
93
90
  console.log(`Wiping database: ${databaseId}`);
94
- const { collections: existingCollections } = await database.listCollections(databaseId);
91
+ const { collections: existingCollections } = await tryAwaitWithRetry(async () => await database.listCollections(databaseId));
95
92
  let collectionsDeleted = [];
96
93
  for (const { $id: collectionId, name: name } of existingCollections) {
97
94
  console.log(`Deleting collection: ${collectionId}`);
@@ -141,9 +138,9 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
141
138
  }
142
139
  }
143
140
  // Check if the collection already exists by name
144
- let collectionsFound = await database.listCollections(databaseId, [
141
+ let collectionsFound = await tryAwaitWithRetry(async () => await database.listCollections(databaseId, [
145
142
  Query.equal("name", collection.name),
146
- ]);
143
+ ]));
147
144
  let collectionToUse = collectionsFound.total > 0 ? collectionsFound.collections[0] : null;
148
145
  // Determine the correct ID for the collection
149
146
  let collectionId;
@@ -163,7 +160,7 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
163
160
  usedIds.add(collectionId); // Mark this ID as used
164
161
  // Create the collection with the determined ID
165
162
  try {
166
- collectionToUse = await database.createCollection(databaseId, collectionId, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true);
163
+ collectionToUse = await tryAwaitWithRetry(async () => await database.createCollection(databaseId, collectionId, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
167
164
  collection.$id = collectionToUse.$id;
168
165
  nameToIdMapping.set(collection.name, collectionToUse.$id);
169
166
  }
@@ -174,7 +171,7 @@ export const createOrUpdateCollections = async (database, databaseId, config, de
174
171
  }
175
172
  else {
176
173
  console.log(`Collection ${collection.name} exists, updating it`);
177
- await database.updateCollection(databaseId, collectionToUse.$id, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true);
174
+ await tryAwaitWithRetry(async () => await database.updateCollection(databaseId, collectionToUse.$id, collection.name, permissions, collection.documentSecurity ?? false, collection.enabled ?? true));
178
175
  }
179
176
  // Update attributes and indexes for the collection
180
177
  console.log("Creating Attributes");
@@ -206,7 +203,7 @@ export const fetchAllCollections = async (dbId, database) => {
206
203
  if (lastCollectionId) {
207
204
  queries.push(Query.cursorAfter(lastCollectionId));
208
205
  }
209
- const response = await database.listCollections(dbId, queries);
206
+ const response = await tryAwaitWithRetry(async () => await database.listCollections(dbId, queries));
210
207
  collections = collections.concat(response.collections);
211
208
  moreCollections = response.collections.length === 500;
212
209
  if (moreCollections) {
@@ -2,6 +2,7 @@ import type { ImportDataActions } from "./importDataActions.js";
2
2
  import { type AppwriteConfig, type AttributeMappings, type CollectionCreate, type ConfigDatabase, type ImportDef } from "appwrite-utils";
3
3
  import { z } from "zod";
4
4
  import { type Databases } from "node-appwrite";
5
+ import { AuthUserCreateSchema } from "../schemas/authUser.js";
5
6
  export declare const CollectionImportDataSchema: z.ZodObject<{
6
7
  collection: z.ZodOptional<z.ZodObject<Omit<{
7
8
  name: z.ZodString;
@@ -61,14 +62,6 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
61
62
  required: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
62
63
  array: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
63
64
  min: z.ZodOptional<z.ZodNumber>;
64
- /**
65
- * Prepares the data for creating documents in a collection.
66
- * This involves loading the data, transforming it, and handling ID mappings.
67
- *
68
- * @param db - The database configuration.
69
- * @param collection - The collection configuration.
70
- * @param importDef - The import definition containing the attribute mappings and other relevant info.
71
- */
72
65
  max: z.ZodOptional<z.ZodNumber>;
73
66
  xdefault: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
74
67
  description: z.ZodOptional<z.ZodNullable<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>>;
@@ -367,16 +360,6 @@ export declare const CollectionImportDataSchema: z.ZodObject<{
367
360
  type: z.ZodOptional<z.ZodDefault<z.ZodEnum<["create", "update"]>>>;
368
361
  filePath: z.ZodString;
369
362
  basePath: z.ZodOptional<z.ZodString>;
370
- /**
371
- * Generates attribute mappings with post-import actions based on the provided attribute mappings.
372
- * This method checks each mapping for a fileData attribute and adds a post-import action to create a file
373
- * and update the field with the file's ID if necessary.
374
- *
375
- * @param attributeMappings - The attribute mappings from the import definition.
376
- * @param context - The context object containing information about the database, collection, and document.
377
- * @param item - The item being imported, used for resolving template paths in fileData mappings.
378
- * @returns The attribute mappings updated with any necessary post-import actions.
379
- */
380
363
  primaryKeyField: z.ZodDefault<z.ZodString>;
381
364
  idMappings: z.ZodOptional<z.ZodArray<z.ZodObject<{
382
365
  sourceField: z.ZodString;
@@ -1713,6 +1696,7 @@ export declare class DataLoader {
1713
1696
  * It iterates through the target object's keys and updates the source object if:
1714
1697
  * - The source object has the key.
1715
1698
  * - The target object's value for that key is not null, undefined, or an empty string.
1699
+ * - If the target object has an array value, it concatenates the values and removes duplicates.
1716
1700
  *
1717
1701
  * @param source - The source object to be updated.
1718
1702
  * @param target - The target object with values to update the source object.
@@ -1736,7 +1720,7 @@ export declare class DataLoader {
1736
1720
  getAllUsers(): Promise<import("node-appwrite").Models.User<import("node-appwrite").Models.Preferences>[]>;
1737
1721
  start(dbId: string): Promise<void>;
1738
1722
  dealWithMergedUsers(): void;
1739
- updateOldReferencesForNew(): Promise<void>;
1723
+ updateOldReferencesForNew(): void;
1740
1724
  private writeMapsToJsonFile;
1741
1725
  /**
1742
1726
  * Prepares user data by checking for duplicates based on email or phone, adding to a duplicate map if found,
@@ -1746,7 +1730,14 @@ export declare class DataLoader {
1746
1730
  * @param attributeMappings - The attribute mappings for the item.
1747
1731
  * @returns The transformed item with user-specific keys removed.
1748
1732
  */
1749
- prepareUserData(item: any, attributeMappings: AttributeMappings, primaryKeyField: string, newId: string): Promise<any>;
1733
+ prepareUserData(item: any, attributeMappings: AttributeMappings, primaryKeyField: string, newId: string): {
1734
+ transformedItem: any;
1735
+ existingId: string | undefined;
1736
+ userData: {
1737
+ rawData: any;
1738
+ finalData: z.infer<typeof AuthUserCreateSchema>;
1739
+ };
1740
+ };
1750
1741
  /**
1751
1742
  * Prepares the data for creating user collection documents.
1752
1743
  * This involves loading the data, transforming it according to the import definition,
@@ -1756,7 +1747,7 @@ export declare class DataLoader {
1756
1747
  * @param collection - The collection configuration.
1757
1748
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
1758
1749
  */
1759
- prepareUserCollectionCreateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): Promise<void>;
1750
+ prepareUserCollectionCreateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): void;
1760
1751
  /**
1761
1752
  * Prepares the data for creating documents in a collection.
1762
1753
  * This involves loading the data, transforming it, and handling ID mappings.
@@ -1765,7 +1756,7 @@ export declare class DataLoader {
1765
1756
  * @param collection - The collection configuration.
1766
1757
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
1767
1758
  */
1768
- prepareCreateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): Promise<void>;
1759
+ prepareCreateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): void;
1769
1760
  /**
1770
1761
  * Prepares the data for updating documents within a collection.
1771
1762
  * This method loads the raw data based on the import definition, transforms it according to the attribute mappings,
@@ -1776,7 +1767,7 @@ export declare class DataLoader {
1776
1767
  * @param collection - The collection configuration.
1777
1768
  * @param importDef - The import definition containing the attribute mappings and other relevant info.
1778
1769
  */
1779
- prepareUpdateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): Promise<void>;
1770
+ prepareUpdateData(db: ConfigDatabase, collection: CollectionCreate, importDef: ImportDef): void;
1780
1771
  private updateReferencesBasedOnAttributeMappings;
1781
1772
  private getMergedId;
1782
1773
  /**