appwrite-utils-cli 0.0.274 → 0.0.275

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 (77) hide show
  1. package/README.md +4 -39
  2. package/dist/init.d.ts +2 -0
  3. package/dist/init.js +57 -0
  4. package/dist/main.js +62 -100
  5. package/dist/migrations/afterImportActions.d.ts +1 -4
  6. package/dist/migrations/afterImportActions.js +1 -0
  7. package/dist/migrations/appwriteToX.d.ts +46 -46
  8. package/dist/migrations/appwriteToX.js +6 -2
  9. package/dist/migrations/attributes.d.ts +1 -1
  10. package/dist/migrations/attributes.js +97 -71
  11. package/dist/migrations/backup.d.ts +240 -240
  12. package/dist/migrations/backup.js +1 -1
  13. package/dist/migrations/collections.d.ts +1 -1
  14. package/dist/migrations/collections.js +4 -4
  15. package/dist/migrations/converters.d.ts +9 -127
  16. package/dist/migrations/converters.js +1 -504
  17. package/dist/migrations/dataLoader.d.ts +470 -453
  18. package/dist/migrations/dataLoader.js +19 -1
  19. package/dist/migrations/dbHelpers.d.ts +1 -1
  20. package/dist/migrations/dbHelpers.js +3 -0
  21. package/dist/migrations/importController.d.ts +1 -1
  22. package/dist/migrations/importController.js +4 -7
  23. package/dist/migrations/importDataActions.d.ts +4 -6
  24. package/dist/migrations/importDataActions.js +6 -4
  25. package/dist/migrations/indexes.d.ts +1 -1
  26. package/dist/migrations/indexes.js +1 -1
  27. package/dist/migrations/migrationHelper.d.ts +29 -29
  28. package/dist/migrations/migrationHelper.js +1 -1
  29. package/dist/migrations/openapi.d.ts +1 -1
  30. package/dist/migrations/openapi.js +4 -1
  31. package/dist/migrations/queue.d.ts +1 -1
  32. package/dist/migrations/relationships.d.ts +5 -5
  33. package/dist/migrations/relationships.js +3 -0
  34. package/dist/migrations/schemaStrings.d.ts +2 -2
  35. package/dist/migrations/schemaStrings.js +93 -8
  36. package/dist/migrations/setupDatabase.d.ts +1 -1
  37. package/dist/migrations/setupDatabase.js +1 -1
  38. package/dist/migrations/storage.d.ts +1 -1
  39. package/dist/migrations/users.d.ts +1 -1
  40. package/dist/schemas/authUser.d.ts +12 -10
  41. package/dist/types.d.ts +0 -5
  42. package/dist/types.js +0 -2
  43. package/dist/utils/helperFunctions.d.ts +2 -3
  44. package/dist/utils/loadConfigs.d.ts +13 -0
  45. package/dist/utils/loadConfigs.js +47 -0
  46. package/dist/utils/setupFiles.d.ts +1 -0
  47. package/dist/utils/setupFiles.js +98 -223
  48. package/dist/utilsController.d.ts +1 -3
  49. package/dist/utilsController.js +14 -18
  50. package/package.json +9 -2
  51. package/src/init.ts +64 -0
  52. package/src/main.ts +73 -98
  53. package/src/migrations/afterImportActions.ts +1 -5
  54. package/src/migrations/appwriteToX.ts +6 -2
  55. package/src/migrations/attributes.ts +198 -150
  56. package/src/migrations/backup.ts +1 -1
  57. package/src/migrations/collections.ts +5 -11
  58. package/src/migrations/converters.ts +1 -540
  59. package/src/migrations/dataLoader.ts +19 -2
  60. package/src/migrations/dbHelpers.ts +4 -1
  61. package/src/migrations/importController.ts +5 -15
  62. package/src/migrations/importDataActions.ts +10 -14
  63. package/src/migrations/indexes.ts +1 -1
  64. package/src/migrations/migrationHelper.ts +1 -1
  65. package/src/migrations/openapi.ts +4 -1
  66. package/src/migrations/queue.ts +1 -1
  67. package/src/migrations/relationships.ts +4 -1
  68. package/src/migrations/schemaStrings.ts +106 -9
  69. package/src/migrations/setupDatabase.ts +1 -1
  70. package/src/migrations/storage.ts +1 -1
  71. package/src/migrations/users.ts +1 -1
  72. package/src/types.ts +0 -5
  73. package/src/utils/helperFunctions.ts +2 -3
  74. package/src/utils/loadConfigs.ts +55 -0
  75. package/src/utils/setupFiles.ts +114 -225
  76. package/src/utilsController.ts +27 -35
  77. package/src/migrations/schema.ts +0 -748
@@ -1,49 +1,21 @@
1
1
  import { Query, type Databases, type Models } from "node-appwrite";
2
- import { parseAttribute, type Attribute } from "./schema.js";
2
+ import {
3
+ attributeSchema,
4
+ parseAttribute,
5
+ type Attribute,
6
+ } from "appwrite-utils";
3
7
  import { nameToIdMapping, enqueueOperation } from "./queue.js";
4
8
  import _ from "lodash";
5
9
 
6
- const attributesSame = (a: Attribute, b: Attribute) => {
7
- // Direct type comparison for non-string types
8
- // Also check if the type IS string and has a format for either
9
- // That means the format is the type of the attribute
10
- if (
11
- a.type === b.type &&
12
- !((a.type === "string" && a.format) || (b.type === "string" && b.format))
13
- ) {
14
- if (a.type === "relationship" && b.type === "relationship") {
15
- return (
16
- a.key === b.key &&
17
- a.relationType === b.relationType &&
18
- a.twoWay === b.twoWay &&
19
- a.twoWayKey === b.twoWayKey &&
20
- a.required === b.required
21
- );
22
- }
23
- return a.key === b.key && a.array === b.array && a.required === b.required;
24
- }
25
-
26
- if (a.type === "string" && a.format) {
27
- // @ts-expect-error
28
- a.type = a.format;
29
- }
30
- if (b.type === "string" && b.format) {
31
- // @ts-expect-error
32
- b.type = b.format;
33
- }
34
-
35
- // Handling string types with specific formats in Appwrite
36
- if (a.type === "string" && b.type === "string") {
37
- return (
38
- a.key === b.key &&
39
- a.format === b.format &&
40
- a.array === b.array &&
41
- a.required === b.required
42
- );
43
- }
44
-
45
- // Fallback to false if none of the above conditions are met
46
- return false;
10
+ const attributesSame = (
11
+ databaseAttribute: Attribute,
12
+ configAttribute: Attribute
13
+ ): boolean => {
14
+ return (
15
+ databaseAttribute.key == configAttribute.key &&
16
+ databaseAttribute.type == configAttribute.type &&
17
+ databaseAttribute.array == configAttribute.array
18
+ );
47
19
  };
48
20
 
49
21
  export const createOrUpdateAttribute = async (
@@ -53,41 +25,90 @@ export const createOrUpdateAttribute = async (
53
25
  attribute: Attribute
54
26
  ): Promise<void> => {
55
27
  let action = "create";
56
- let foundAttribute;
28
+ let foundAttribute: Attribute | undefined;
29
+ const updateEnabled = false;
30
+ let finalAttribute: any = attribute;
57
31
  try {
58
- foundAttribute = parseAttribute(
59
- collection.attributes.find(
60
- // @ts-expect-error
61
- (attr) => attr.key === attribute.key
62
- ) as unknown as Attribute
63
- );
64
- foundAttribute = parseAttribute(foundAttribute);
32
+ const collectionAttr = collection.attributes.find(
33
+ // @ts-expect-error
34
+ (attr) => attr.key === attribute.key
35
+ ) as unknown;
36
+ foundAttribute = parseAttribute(collectionAttr);
65
37
  } catch (error) {
66
38
  foundAttribute = undefined;
67
39
  }
68
- let numSameAttributes = 0;
69
- if (foundAttribute && attributesSame(foundAttribute, attribute)) {
70
- numSameAttributes++;
71
- return;
72
- } else if (foundAttribute && !attributesSame(foundAttribute, attribute)) {
40
+
41
+ if (
42
+ foundAttribute &&
43
+ attributesSame(foundAttribute, attribute) &&
44
+ updateEnabled
45
+ ) {
46
+ // Check if mutable properties have changed and set action to "update" if necessary
47
+ const requiredChanged =
48
+ "required" in foundAttribute && "required" in attribute
49
+ ? foundAttribute.required !== attribute.required
50
+ : false;
51
+
52
+ // const xdefaultChanged =
53
+ // "xdefault" in foundAttribute && "xdefault" in attribute
54
+ // ? foundAttribute.xdefault !== attribute.xdefault
55
+ // : false;
56
+
57
+ const onDeleteChanged =
58
+ foundAttribute.type === "relationship" &&
59
+ attribute.type === "relationship" &&
60
+ "onDelete" in foundAttribute &&
61
+ "onDelete" in attribute
62
+ ? foundAttribute.onDelete !== attribute.onDelete
63
+ : false;
64
+
65
+ if (requiredChanged || onDeleteChanged) {
66
+ console.log(
67
+ `Required changed: ${requiredChanged}\nOnDelete changed: ${onDeleteChanged}`
68
+ );
69
+ console.log(
70
+ `Found attribute: ${JSON.stringify(foundAttribute, null, 2)}`
71
+ );
72
+ console.log(`Attribute: ${JSON.stringify(attribute, null, 2)}`);
73
+ finalAttribute = {
74
+ ...attribute,
75
+ ...foundAttribute,
76
+ };
77
+ action = "update";
78
+ } else {
79
+ // If no properties that can be updated have changed, return early
80
+ return;
81
+ }
82
+ } else if (
83
+ foundAttribute &&
84
+ !attributesSame(foundAttribute, attribute) &&
85
+ updateEnabled
86
+ ) {
73
87
  console.log(
74
- `Deleting attribute with same key ${attribute.key} -- ${
75
- foundAttribute.key
76
- } but different values -- ${JSON.stringify(
88
+ `Deleting attribute with same key ${
89
+ attribute.key
90
+ } -- but different values -- ${JSON.stringify(
77
91
  attribute,
78
92
  null,
79
93
  2
80
94
  )} -- ${JSON.stringify(foundAttribute, null, 2)}`
81
95
  );
82
96
  await db.deleteAttribute(dbId, collection.$id, attribute.key);
97
+ // After deletion, you might want to create the attribute anew
98
+ finalAttribute = attribute;
99
+ action = "create";
100
+ } else if (!updateEnabled && foundAttribute) {
101
+ return;
83
102
  }
84
103
 
85
104
  // Relationship attribute logic with adjustments
86
105
  let collectionFoundViaRelatedCollection: Models.Collection | undefined;
87
106
  let relatedCollectionId: string | undefined;
88
- if (attribute.type === "relationship") {
89
- if (nameToIdMapping.has(attribute.relatedCollection)) {
90
- relatedCollectionId = nameToIdMapping.get(attribute.relatedCollection);
107
+ if (finalAttribute.type === "relationship") {
108
+ if (nameToIdMapping.has(finalAttribute.relatedCollection)) {
109
+ relatedCollectionId = nameToIdMapping.get(
110
+ finalAttribute.relatedCollection
111
+ );
91
112
  try {
92
113
  collectionFoundViaRelatedCollection = await db.getCollection(
93
114
  dbId,
@@ -95,77 +116,104 @@ export const createOrUpdateAttribute = async (
95
116
  );
96
117
  } catch (e) {
97
118
  console.log(
98
- `Collection not found: ${attribute.relatedCollection} when nameToIdMapping was set`
119
+ `Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`
99
120
  );
100
121
  collectionFoundViaRelatedCollection = undefined;
101
122
  }
102
123
  } else {
103
124
  const collectionsPulled = await db.listCollections(dbId, [
104
- Query.equal("name", attribute.relatedCollection),
125
+ Query.equal("name", finalAttribute.relatedCollection),
105
126
  ]);
106
127
  if (collectionsPulled.total > 0) {
107
128
  collectionFoundViaRelatedCollection = collectionsPulled.collections[0];
108
129
  relatedCollectionId = collectionFoundViaRelatedCollection.$id;
109
- nameToIdMapping.set(attribute.relatedCollection, relatedCollectionId);
130
+ nameToIdMapping.set(
131
+ finalAttribute.relatedCollection,
132
+ relatedCollectionId
133
+ );
110
134
  }
111
135
  }
112
136
  if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
113
- console.log(`Enqueueing operation for attribute: ${attribute.key}`);
137
+ console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
114
138
  enqueueOperation({
115
139
  type: "attribute",
116
140
  collectionId: collection.$id,
117
141
  collection: collection,
118
142
  attribute,
119
- dependencies: [attribute.relatedCollection],
143
+ dependencies: [finalAttribute.relatedCollection],
120
144
  });
121
145
  return;
122
146
  }
123
147
  }
124
-
125
- switch (attribute.type) {
148
+ finalAttribute = attributeSchema.parse(finalAttribute);
149
+ switch (finalAttribute.type) {
126
150
  case "string":
127
151
  if (action === "create") {
128
152
  await db.createStringAttribute(
129
153
  dbId,
130
154
  collection.$id,
131
- attribute.key,
132
- attribute.size,
133
- attribute.required,
134
- attribute.xdefault || undefined,
135
- attribute.array,
136
- attribute.encrypted
155
+ finalAttribute.key,
156
+ finalAttribute.size,
157
+ finalAttribute.required || false,
158
+ (finalAttribute.xdefault as string) || undefined,
159
+ finalAttribute.array || false,
160
+ finalAttribute.encrypted
137
161
  );
138
162
  } else {
139
163
  await db.updateStringAttribute(
140
164
  dbId,
141
165
  collection.$id,
142
- attribute.key,
143
- attribute.required,
144
- attribute.xdefault || undefined
166
+ finalAttribute.key,
167
+ finalAttribute.required || false,
168
+ (finalAttribute.xdefault as string) || undefined
145
169
  );
146
170
  }
147
171
  break;
148
172
  case "integer":
149
173
  if (action === "create") {
174
+ if (
175
+ finalAttribute.min &&
176
+ BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
177
+ ) {
178
+ delete finalAttribute.min;
179
+ }
180
+ if (
181
+ finalAttribute.max &&
182
+ BigInt(finalAttribute.max) === BigInt(9223372036854776000)
183
+ ) {
184
+ delete finalAttribute.max;
185
+ }
150
186
  await db.createIntegerAttribute(
151
187
  dbId,
152
188
  collection.$id,
153
- attribute.key,
154
- attribute.required,
155
- attribute.min,
156
- attribute.max,
157
- attribute.xdefault || undefined,
158
- attribute.array
189
+ finalAttribute.key,
190
+ finalAttribute.required || false,
191
+ finalAttribute.min,
192
+ finalAttribute.max,
193
+ finalAttribute.xdefault || undefined,
194
+ finalAttribute.array
159
195
  );
160
196
  } else {
197
+ if (
198
+ finalAttribute.min &&
199
+ BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
200
+ ) {
201
+ delete finalAttribute.min;
202
+ }
203
+ if (
204
+ finalAttribute.max &&
205
+ BigInt(finalAttribute.max) === BigInt(9223372036854776000)
206
+ ) {
207
+ delete finalAttribute.max;
208
+ }
161
209
  await db.updateIntegerAttribute(
162
210
  dbId,
163
211
  collection.$id,
164
- attribute.key,
165
- attribute.required,
166
- attribute.min || 0,
167
- attribute.max || 2147483647,
168
- attribute.xdefault || undefined
212
+ finalAttribute.key,
213
+ finalAttribute.required || false,
214
+ finalAttribute.min || 0,
215
+ finalAttribute.max || 2147483647,
216
+ finalAttribute.xdefault || undefined
169
217
  );
170
218
  }
171
219
  break;
@@ -174,22 +222,22 @@ export const createOrUpdateAttribute = async (
174
222
  await db.createFloatAttribute(
175
223
  dbId,
176
224
  collection.$id,
177
- attribute.key,
178
- attribute.required,
179
- attribute.min,
180
- attribute.max,
181
- attribute.xdefault || undefined,
182
- attribute.array
225
+ finalAttribute.key,
226
+ finalAttribute.required || false,
227
+ finalAttribute.min,
228
+ finalAttribute.max,
229
+ finalAttribute.xdefault || undefined,
230
+ finalAttribute.array
183
231
  );
184
232
  } else {
185
233
  await db.updateFloatAttribute(
186
234
  dbId,
187
235
  collection.$id,
188
- attribute.key,
189
- attribute.required,
190
- attribute.min || 0,
191
- attribute.max || 2147483647,
192
- attribute.xdefault || undefined
236
+ finalAttribute.key,
237
+ finalAttribute.required || false,
238
+ finalAttribute.min || 0,
239
+ finalAttribute.max || 2147483647,
240
+ finalAttribute.xdefault || undefined
193
241
  );
194
242
  }
195
243
  break;
@@ -198,18 +246,18 @@ export const createOrUpdateAttribute = async (
198
246
  await db.createBooleanAttribute(
199
247
  dbId,
200
248
  collection.$id,
201
- attribute.key,
202
- attribute.required,
203
- attribute.xdefault || undefined,
204
- attribute.array
249
+ finalAttribute.key,
250
+ finalAttribute.required || false,
251
+ finalAttribute.xdefault || undefined,
252
+ finalAttribute.array
205
253
  );
206
254
  } else {
207
255
  await db.updateBooleanAttribute(
208
256
  dbId,
209
257
  collection.$id,
210
- attribute.key,
211
- attribute.required,
212
- attribute.xdefault || undefined
258
+ finalAttribute.key,
259
+ finalAttribute.required || false,
260
+ finalAttribute.xdefault || null
213
261
  );
214
262
  }
215
263
  break;
@@ -218,18 +266,18 @@ export const createOrUpdateAttribute = async (
218
266
  await db.createDatetimeAttribute(
219
267
  dbId,
220
268
  collection.$id,
221
- attribute.key,
222
- attribute.required,
223
- attribute.xdefault || undefined,
224
- attribute.array
269
+ finalAttribute.key,
270
+ finalAttribute.required || false,
271
+ finalAttribute.xdefault || undefined,
272
+ finalAttribute.array
225
273
  );
226
274
  } else {
227
275
  await db.updateDatetimeAttribute(
228
276
  dbId,
229
277
  collection.$id,
230
- attribute.key,
231
- attribute.required,
232
- attribute.xdefault || undefined
278
+ finalAttribute.key,
279
+ finalAttribute.required || false,
280
+ finalAttribute.xdefault || undefined
233
281
  );
234
282
  }
235
283
  break;
@@ -238,18 +286,18 @@ export const createOrUpdateAttribute = async (
238
286
  await db.createEmailAttribute(
239
287
  dbId,
240
288
  collection.$id,
241
- attribute.key,
242
- attribute.required,
243
- attribute.xdefault || undefined,
244
- attribute.array
289
+ finalAttribute.key,
290
+ finalAttribute.required || false,
291
+ finalAttribute.xdefault || undefined,
292
+ finalAttribute.array
245
293
  );
246
294
  } else {
247
295
  await db.updateEmailAttribute(
248
296
  dbId,
249
297
  collection.$id,
250
- attribute.key,
251
- attribute.required,
252
- attribute.xdefault || undefined
298
+ finalAttribute.key,
299
+ finalAttribute.required || false,
300
+ finalAttribute.xdefault || undefined
253
301
  );
254
302
  }
255
303
  break;
@@ -258,18 +306,18 @@ export const createOrUpdateAttribute = async (
258
306
  await db.createIpAttribute(
259
307
  dbId,
260
308
  collection.$id,
261
- attribute.key,
262
- attribute.required,
263
- attribute.xdefault || undefined,
264
- attribute.array
309
+ finalAttribute.key,
310
+ finalAttribute.required || false,
311
+ finalAttribute.xdefault || undefined,
312
+ finalAttribute.array
265
313
  );
266
314
  } else {
267
315
  await db.updateIpAttribute(
268
316
  dbId,
269
317
  collection.$id,
270
- attribute.key,
271
- attribute.required,
272
- attribute.xdefault || undefined
318
+ finalAttribute.key,
319
+ finalAttribute.required || false,
320
+ finalAttribute.xdefault || undefined
273
321
  );
274
322
  }
275
323
  break;
@@ -278,18 +326,18 @@ export const createOrUpdateAttribute = async (
278
326
  await db.createUrlAttribute(
279
327
  dbId,
280
328
  collection.$id,
281
- attribute.key,
282
- attribute.required,
283
- attribute.xdefault || undefined,
284
- attribute.array
329
+ finalAttribute.key,
330
+ finalAttribute.required || false,
331
+ finalAttribute.xdefault || undefined,
332
+ finalAttribute.array
285
333
  );
286
334
  } else {
287
335
  await db.updateUrlAttribute(
288
336
  dbId,
289
337
  collection.$id,
290
- attribute.key,
291
- attribute.required,
292
- attribute.xdefault || undefined
338
+ finalAttribute.key,
339
+ finalAttribute.required || false,
340
+ finalAttribute.xdefault || undefined
293
341
  );
294
342
  }
295
343
  break;
@@ -298,20 +346,20 @@ export const createOrUpdateAttribute = async (
298
346
  await db.createEnumAttribute(
299
347
  dbId,
300
348
  collection.$id,
301
- attribute.key,
302
- attribute.elements,
303
- attribute.required,
304
- attribute.xdefault || undefined,
305
- attribute.array
349
+ finalAttribute.key,
350
+ finalAttribute.elements,
351
+ finalAttribute.required || false,
352
+ finalAttribute.xdefault || undefined,
353
+ finalAttribute.array
306
354
  );
307
355
  } else {
308
356
  await db.updateEnumAttribute(
309
357
  dbId,
310
358
  collection.$id,
311
- attribute.key,
312
- attribute.elements,
313
- attribute.required,
314
- attribute.xdefault || undefined
359
+ finalAttribute.key,
360
+ finalAttribute.elements,
361
+ finalAttribute.required || false,
362
+ finalAttribute.xdefault || undefined
315
363
  );
316
364
  }
317
365
  break;
@@ -321,18 +369,18 @@ export const createOrUpdateAttribute = async (
321
369
  dbId,
322
370
  collection.$id,
323
371
  relatedCollectionId!,
324
- attribute.relationType,
325
- attribute.twoWay,
326
- attribute.key,
327
- attribute.twoWayKey,
328
- attribute.onDelete
372
+ finalAttribute.relationType,
373
+ finalAttribute.twoWay,
374
+ finalAttribute.key,
375
+ finalAttribute.twoWayKey,
376
+ finalAttribute.onDelete
329
377
  );
330
378
  } else {
331
379
  await db.updateRelationshipAttribute(
332
380
  dbId,
333
381
  collection.$id,
334
- attribute.key,
335
- attribute.onDelete
382
+ finalAttribute.key,
383
+ finalAttribute.onDelete
336
384
  );
337
385
  }
338
386
  break;
@@ -4,7 +4,7 @@ import {
4
4
  type Attribute,
5
5
  parseAttribute,
6
6
  CollectionCreateSchema,
7
- } from "./schema.js";
7
+ } from "appwrite-utils";
8
8
 
9
9
  export const BackupSchema = z.object({
10
10
  $id: z.string(),
@@ -1,19 +1,10 @@
1
1
  import { Databases, ID, Permission, Query, type Models } from "node-appwrite";
2
- import type { AppwriteConfig, CollectionCreate } from "./schema.js";
2
+ import type { AppwriteConfig, CollectionCreate } from "appwrite-utils";
3
3
  import { nameToIdMapping, processQueue } from "./queue.js";
4
4
  import { createUpdateCollectionAttributes } from "./attributes.js";
5
5
  import { createOrUpdateIndexes } from "./indexes.js";
6
- import {
7
- ensureDirectoryExistence,
8
- toCamelCase,
9
- toPascalCase,
10
- writeFileSync,
11
- } from "../utils/index.js";
12
6
  import _ from "lodash";
13
7
  import { SchemaGenerator } from "./schemaStrings.js";
14
- import path from "path";
15
-
16
- const { join } = _;
17
8
 
18
9
  export const documentExists = async (
19
10
  db: Databases,
@@ -157,6 +148,9 @@ export const createOrUpdateCollections = async (
157
148
  deletedCollections?: { collectionId: string; collectionName: string }[]
158
149
  ): Promise<void> => {
159
150
  const configCollections = config.collections;
151
+ if (!configCollections) {
152
+ return;
153
+ }
160
154
  const usedIds = new Set(); // To track IDs used in this operation
161
155
 
162
156
  for (const { attributes, indexes, ...collection } of configCollections) {
@@ -250,7 +244,7 @@ export const createOrUpdateCollections = async (
250
244
  databaseId,
251
245
  database,
252
246
  collectionToUse.$id,
253
- indexes
247
+ indexes ?? []
254
248
  );
255
249
  }
256
250
  // Process any remaining tasks in the queue