appwrite-utils-cli 1.3.5 → 1.4.1

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 (116) hide show
  1. package/dist/adapters/AdapterFactory.d.ts +87 -0
  2. package/dist/adapters/AdapterFactory.js +217 -0
  3. package/dist/adapters/DatabaseAdapter.d.ts +217 -0
  4. package/dist/adapters/DatabaseAdapter.js +50 -0
  5. package/dist/adapters/LegacyAdapter.d.ts +49 -0
  6. package/dist/adapters/LegacyAdapter.js +382 -0
  7. package/dist/adapters/TablesDBAdapter.d.ts +55 -0
  8. package/dist/adapters/TablesDBAdapter.js +302 -0
  9. package/dist/adapters/index.d.ts +11 -0
  10. package/dist/adapters/index.js +12 -0
  11. package/dist/collections/attributes.js +41 -22
  12. package/dist/collections/methods.d.ts +4 -3
  13. package/dist/collections/methods.js +34 -14
  14. package/dist/config/yamlConfig.d.ts +40 -437
  15. package/dist/config/yamlConfig.js +8 -2
  16. package/dist/databases/setup.js +2 -2
  17. package/dist/main.js +0 -0
  18. package/dist/migrations/appwriteToX.d.ts +26 -37
  19. package/dist/migrations/comprehensiveTransfer.js +4 -4
  20. package/dist/migrations/dataLoader.d.ts +124 -1484
  21. package/dist/migrations/dataLoader.js +2 -1
  22. package/dist/migrations/relationships.d.ts +2 -3
  23. package/dist/migrations/relationships.js +1 -1
  24. package/dist/migrations/services/UserMappingService.js +1 -1
  25. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +24 -279
  26. package/dist/migrations/yaml/YamlImportConfigLoader.js +7 -2
  27. package/dist/schemas/authUser.d.ts +7 -47
  28. package/dist/schemas/authUser.js +1 -1
  29. package/dist/shared/jsonSchemaGenerator.d.ts +0 -2
  30. package/dist/shared/jsonSchemaGenerator.js +4 -17
  31. package/dist/shared/migrationHelpers.d.ts +17 -119
  32. package/dist/shared/operationQueue.js +16 -7
  33. package/dist/shared/schemaGenerator.js +2 -17
  34. package/dist/storage/schemas.d.ts +149 -296
  35. package/dist/users/methods.d.ts +2 -2
  36. package/dist/utils/configMigration.js +0 -1
  37. package/dist/utils/getClientFromConfig.d.ts +26 -0
  38. package/dist/utils/getClientFromConfig.js +37 -0
  39. package/dist/utils/loadConfigs.js +0 -2
  40. package/dist/utils/schemaStrings.js +2 -17
  41. package/dist/utils/setupFiles.js +2 -0
  42. package/dist/utils/versionDetection.d.ts +56 -0
  43. package/dist/utils/versionDetection.js +217 -0
  44. package/dist/utils/yamlConverter.d.ts +0 -1
  45. package/dist/utils/yamlConverter.js +0 -2
  46. package/dist/utilsController.js +2 -0
  47. package/package.json +3 -2
  48. package/src/adapters/AdapterFactory.ts +296 -0
  49. package/src/adapters/DatabaseAdapter.ts +290 -0
  50. package/src/adapters/LegacyAdapter.ts +667 -0
  51. package/src/adapters/TablesDBAdapter.ts +429 -0
  52. package/src/adapters/index.ts +37 -0
  53. package/src/collections/attributes.ts +347 -153
  54. package/src/collections/methods.ts +43 -28
  55. package/src/config/yamlConfig.ts +8 -2
  56. package/src/databases/setup.ts +2 -2
  57. package/src/migrations/afterImportActions.ts +2 -2
  58. package/src/migrations/comprehensiveTransfer.ts +4 -0
  59. package/src/migrations/dataLoader.ts +2 -1
  60. package/src/migrations/relationships.ts +1 -1
  61. package/src/migrations/services/UserMappingService.ts +1 -1
  62. package/src/migrations/yaml/YamlImportConfigLoader.ts +7 -2
  63. package/src/schemas/authUser.ts +1 -1
  64. package/src/shared/jsonSchemaGenerator.ts +4 -19
  65. package/src/shared/operationQueue.ts +20 -13
  66. package/src/shared/schemaGenerator.ts +2 -16
  67. package/src/types/node-appwrite-tablesdb.d.ts +44 -0
  68. package/src/users/methods.ts +2 -2
  69. package/src/utils/configMigration.ts +0 -1
  70. package/src/utils/getClientFromConfig.ts +56 -0
  71. package/src/utils/loadConfigs.ts +0 -2
  72. package/src/utils/schemaStrings.ts +2 -16
  73. package/src/utils/setupFiles.ts +2 -0
  74. package/src/utils/versionDetection.ts +265 -0
  75. package/src/utils/yamlConverter.ts +0 -2
  76. package/src/utilsController.ts +2 -0
  77. package/dist/functions/openapi.d.ts +0 -4
  78. package/dist/functions/openapi.js +0 -60
  79. package/dist/migrations/attributes.d.ts +0 -4
  80. package/dist/migrations/attributes.js +0 -301
  81. package/dist/migrations/backup.d.ts +0 -687
  82. package/dist/migrations/backup.js +0 -175
  83. package/dist/migrations/collections.d.ts +0 -22
  84. package/dist/migrations/collections.js +0 -347
  85. package/dist/migrations/converters.d.ts +0 -46
  86. package/dist/migrations/converters.js +0 -139
  87. package/dist/migrations/databases.d.ts +0 -2
  88. package/dist/migrations/databases.js +0 -28
  89. package/dist/migrations/dbHelpers.d.ts +0 -5
  90. package/dist/migrations/dbHelpers.js +0 -57
  91. package/dist/migrations/helper.d.ts +0 -3
  92. package/dist/migrations/helper.js +0 -21
  93. package/dist/migrations/indexes.d.ts +0 -4
  94. package/dist/migrations/indexes.js +0 -19
  95. package/dist/migrations/logging.d.ts +0 -10
  96. package/dist/migrations/logging.js +0 -46
  97. package/dist/migrations/migrationHelper.d.ts +0 -173
  98. package/dist/migrations/migrationHelper.js +0 -130
  99. package/dist/migrations/openapi.d.ts +0 -4
  100. package/dist/migrations/openapi.js +0 -60
  101. package/dist/migrations/queue.d.ts +0 -13
  102. package/dist/migrations/queue.js +0 -79
  103. package/dist/migrations/schemaStrings.d.ts +0 -14
  104. package/dist/migrations/schemaStrings.js +0 -478
  105. package/dist/migrations/setupDatabase.d.ts +0 -6
  106. package/dist/migrations/setupDatabase.js +0 -115
  107. package/dist/migrations/storage.d.ts +0 -10
  108. package/dist/migrations/storage.js +0 -340
  109. package/dist/migrations/users.d.ts +0 -16
  110. package/dist/migrations/users.js +0 -276
  111. package/dist/migrations/validationRules.d.ts +0 -43
  112. package/dist/migrations/validationRules.js +0 -42
  113. package/dist/shared/attributeManager.d.ts +0 -17
  114. package/dist/shared/attributeManager.js +0 -272
  115. package/src/functions/openapi.ts +0 -83
  116. package/src/shared/attributeManager.ts +0 -428
@@ -12,7 +12,7 @@ import chalk from "chalk";
12
12
  interface AttributeWithStatus {
13
13
  key: string;
14
14
  type: string;
15
- status: 'available' | 'processing' | 'deleting' | 'stuck' | 'failed';
15
+ status: "available" | "processing" | "deleting" | "stuck" | "failed";
16
16
  error: string;
17
17
  required: boolean;
18
18
  array?: boolean;
@@ -35,72 +35,108 @@ const waitForAttributeAvailable = async (
35
35
  ): Promise<boolean> => {
36
36
  const startTime = Date.now();
37
37
  let checkInterval = 2000; // Start with 2 seconds
38
-
38
+
39
39
  // Calculate exponential backoff: 2s, 4s, 8s, 16s, 30s (capped at 30s)
40
40
  if (retryCount > 0) {
41
41
  const exponentialDelay = Math.min(2000 * Math.pow(2, retryCount), 30000);
42
- console.log(chalk.blue(`Waiting for attribute '${attributeKey}' to become available (retry ${retryCount}, backoff: ${exponentialDelay}ms)...`));
42
+ console.log(
43
+ chalk.blue(
44
+ `Waiting for attribute '${attributeKey}' to become available (retry ${retryCount}, backoff: ${exponentialDelay}ms)...`
45
+ )
46
+ );
43
47
  await delay(exponentialDelay);
44
48
  } else {
45
- console.log(chalk.blue(`Waiting for attribute '${attributeKey}' to become available...`));
49
+ console.log(
50
+ chalk.blue(
51
+ `Waiting for attribute '${attributeKey}' to become available...`
52
+ )
53
+ );
46
54
  }
47
-
55
+
48
56
  while (Date.now() - startTime < maxWaitTime) {
49
57
  try {
50
58
  const collection = await db.getCollection(dbId, collectionId);
51
59
  const attribute = (collection.attributes as any[]).find(
52
60
  (attr: AttributeWithStatus) => attr.key === attributeKey
53
61
  ) as AttributeWithStatus | undefined;
54
-
62
+
55
63
  if (!attribute) {
56
64
  console.log(chalk.red(`Attribute '${attributeKey}' not found`));
57
65
  return false;
58
66
  }
59
-
60
- console.log(chalk.gray(`Attribute '${attributeKey}' status: ${attribute.status}`));
61
-
67
+
68
+ console.log(
69
+ chalk.gray(`Attribute '${attributeKey}' status: ${attribute.status}`)
70
+ );
71
+
62
72
  switch (attribute.status) {
63
- case 'available':
64
- console.log(chalk.green(`✅ Attribute '${attributeKey}' is now available`));
73
+ case "available":
74
+ console.log(
75
+ chalk.green(`✅ Attribute '${attributeKey}' is now available`)
76
+ );
65
77
  return true;
66
-
67
- case 'failed':
68
- console.log(chalk.red(`❌ Attribute '${attributeKey}' failed: ${attribute.error}`));
78
+
79
+ case "failed":
80
+ console.log(
81
+ chalk.red(
82
+ `❌ Attribute '${attributeKey}' failed: ${attribute.error}`
83
+ )
84
+ );
69
85
  return false;
70
-
71
- case 'stuck':
72
- console.log(chalk.yellow(`⚠️ Attribute '${attributeKey}' is stuck, will retry...`));
86
+
87
+ case "stuck":
88
+ console.log(
89
+ chalk.yellow(
90
+ `⚠️ Attribute '${attributeKey}' is stuck, will retry...`
91
+ )
92
+ );
73
93
  return false;
74
-
75
- case 'processing':
94
+
95
+ case "processing":
76
96
  // Continue waiting
77
97
  break;
78
-
79
- case 'deleting':
80
- console.log(chalk.yellow(`Attribute '${attributeKey}' is being deleted`));
98
+
99
+ case "deleting":
100
+ console.log(
101
+ chalk.yellow(`Attribute '${attributeKey}' is being deleted`)
102
+ );
81
103
  break;
82
-
104
+
83
105
  default:
84
- console.log(chalk.yellow(`Unknown status '${attribute.status}' for attribute '${attributeKey}'`));
106
+ console.log(
107
+ chalk.yellow(
108
+ `Unknown status '${attribute.status}' for attribute '${attributeKey}'`
109
+ )
110
+ );
85
111
  break;
86
112
  }
87
-
113
+
88
114
  await delay(checkInterval);
89
115
  } catch (error) {
90
116
  console.log(chalk.red(`Error checking attribute status: ${error}`));
91
117
  return false;
92
118
  }
93
119
  }
94
-
120
+
95
121
  // Timeout reached
96
- console.log(chalk.yellow(`⏰ Timeout waiting for attribute '${attributeKey}' (${maxWaitTime}ms)`));
97
-
122
+ console.log(
123
+ chalk.yellow(
124
+ `⏰ Timeout waiting for attribute '${attributeKey}' (${maxWaitTime}ms)`
125
+ )
126
+ );
127
+
98
128
  // If we have retries left and this isn't the last retry, try recreating
99
129
  if (retryCount < maxRetries) {
100
- console.log(chalk.yellow(`🔄 Retrying attribute creation (attempt ${retryCount + 1}/${maxRetries})`));
130
+ console.log(
131
+ chalk.yellow(
132
+ `🔄 Retrying attribute creation (attempt ${
133
+ retryCount + 1
134
+ }/${maxRetries})`
135
+ )
136
+ );
101
137
  return false; // Signal that we need to retry
102
138
  }
103
-
139
+
104
140
  return false;
105
141
  };
106
142
 
@@ -114,17 +150,27 @@ const waitForAllAttributesAvailable = async (
114
150
  attributeKeys: string[],
115
151
  maxWaitTime: number = 60000
116
152
  ): Promise<string[]> => {
117
- console.log(chalk.blue(`Waiting for ${attributeKeys.length} attributes to become available...`));
118
-
153
+ console.log(
154
+ chalk.blue(
155
+ `Waiting for ${attributeKeys.length} attributes to become available...`
156
+ )
157
+ );
158
+
119
159
  const failedAttributes: string[] = [];
120
-
160
+
121
161
  for (const attributeKey of attributeKeys) {
122
- const success = await waitForAttributeAvailable(db, dbId, collectionId, attributeKey, maxWaitTime);
162
+ const success = await waitForAttributeAvailable(
163
+ db,
164
+ dbId,
165
+ collectionId,
166
+ attributeKey,
167
+ maxWaitTime
168
+ );
123
169
  if (!success) {
124
170
  failedAttributes.push(attributeKey);
125
171
  }
126
172
  }
127
-
173
+
128
174
  return failedAttributes;
129
175
  };
130
176
 
@@ -138,15 +184,19 @@ const deleteAndRecreateCollection = async (
138
184
  retryCount: number
139
185
  ): Promise<Models.Collection | null> => {
140
186
  try {
141
- console.log(chalk.yellow(`🗑️ Deleting collection '${collection.name}' for retry ${retryCount}`));
142
-
187
+ console.log(
188
+ chalk.yellow(
189
+ `🗑️ Deleting collection '${collection.name}' for retry ${retryCount}`
190
+ )
191
+ );
192
+
143
193
  // Delete the collection
144
194
  await db.deleteCollection(dbId, collection.$id);
145
195
  console.log(chalk.yellow(`Deleted collection '${collection.name}'`));
146
-
196
+
147
197
  // Wait a bit before recreating
148
198
  await delay(2000);
149
-
199
+
150
200
  // Recreate the collection
151
201
  console.log(chalk.blue(`🔄 Recreating collection '${collection.name}'`));
152
202
  const newCollection = await db.createCollection(
@@ -157,12 +207,15 @@ const deleteAndRecreateCollection = async (
157
207
  collection.documentSecurity,
158
208
  collection.enabled
159
209
  );
160
-
210
+
161
211
  console.log(chalk.green(`✅ Recreated collection '${collection.name}'`));
162
212
  return newCollection;
163
-
164
213
  } catch (error) {
165
- console.log(chalk.red(`Failed to delete/recreate collection '${collection.name}': ${error}`));
214
+ console.log(
215
+ chalk.red(
216
+ `Failed to delete/recreate collection '${collection.name}': ${error}`
217
+ )
218
+ );
166
219
  return null;
167
220
  }
168
221
  };
@@ -242,111 +295,147 @@ export const createOrUpdateAttributeWithStatusCheck = async (
242
295
  retryCount: number = 0,
243
296
  maxRetries: number = 5
244
297
  ): Promise<boolean> => {
245
- console.log(chalk.blue(`Creating/updating attribute '${attribute.key}' (attempt ${retryCount + 1}/${maxRetries + 1})`));
246
-
298
+ console.log(
299
+ chalk.blue(
300
+ `Creating/updating attribute '${attribute.key}' (attempt ${
301
+ retryCount + 1
302
+ }/${maxRetries + 1})`
303
+ )
304
+ );
305
+
247
306
  try {
248
307
  // First, try to create/update the attribute using existing logic
249
308
  await createOrUpdateAttribute(db, dbId, collection, attribute);
250
-
309
+
251
310
  // Now wait for the attribute to become available
252
311
  const success = await waitForAttributeAvailable(
253
- db,
254
- dbId,
255
- collection.$id,
256
- attribute.key,
312
+ db,
313
+ dbId,
314
+ collection.$id,
315
+ attribute.key,
257
316
  60000, // 1 minute timeout
258
- retryCount,
317
+ retryCount,
259
318
  maxRetries
260
319
  );
261
-
320
+
262
321
  if (success) {
263
322
  return true;
264
323
  }
265
-
324
+
266
325
  // If not successful and we have retries left, delete specific attribute and try again
267
326
  if (retryCount < maxRetries) {
268
- console.log(chalk.yellow(`Attribute '${attribute.key}' failed/stuck, deleting and retrying...`));
269
-
327
+ console.log(
328
+ chalk.yellow(
329
+ `Attribute '${attribute.key}' failed/stuck, deleting and retrying...`
330
+ )
331
+ );
332
+
270
333
  // Try to delete the specific stuck attribute instead of the entire collection
271
334
  try {
272
335
  await db.deleteAttribute(dbId, collection.$id, attribute.key);
273
- console.log(chalk.yellow(`Deleted stuck attribute '${attribute.key}', will retry creation`));
274
-
336
+ console.log(
337
+ chalk.yellow(
338
+ `Deleted stuck attribute '${attribute.key}', will retry creation`
339
+ )
340
+ );
341
+
275
342
  // Wait a bit before retry
276
343
  await delay(3000);
277
-
344
+
278
345
  // Get fresh collection data
279
346
  const freshCollection = await db.getCollection(dbId, collection.$id);
280
-
347
+
281
348
  // Retry with the same collection (attribute should be gone now)
282
349
  return await createOrUpdateAttributeWithStatusCheck(
283
- db,
284
- dbId,
285
- freshCollection,
286
- attribute,
287
- retryCount + 1,
350
+ db,
351
+ dbId,
352
+ freshCollection,
353
+ attribute,
354
+ retryCount + 1,
288
355
  maxRetries
289
356
  );
290
357
  } catch (deleteError) {
291
- console.log(chalk.red(`Failed to delete stuck attribute '${attribute.key}': ${deleteError}`));
292
-
358
+ console.log(
359
+ chalk.red(
360
+ `Failed to delete stuck attribute '${attribute.key}': ${deleteError}`
361
+ )
362
+ );
363
+
293
364
  // If attribute deletion fails, only then try collection recreation as last resort
294
365
  if (retryCount >= maxRetries - 1) {
295
- console.log(chalk.yellow(`Last resort: Recreating collection for attribute '${attribute.key}'`));
296
-
366
+ console.log(
367
+ chalk.yellow(
368
+ `Last resort: Recreating collection for attribute '${attribute.key}'`
369
+ )
370
+ );
371
+
297
372
  // Get fresh collection data
298
373
  const freshCollection = await db.getCollection(dbId, collection.$id);
299
-
374
+
300
375
  // Delete and recreate collection
301
- const newCollection = await deleteAndRecreateCollection(db, dbId, freshCollection, retryCount + 1);
302
-
376
+ const newCollection = await deleteAndRecreateCollection(
377
+ db,
378
+ dbId,
379
+ freshCollection,
380
+ retryCount + 1
381
+ );
382
+
303
383
  if (newCollection) {
304
384
  // Retry with the new collection
305
385
  return await createOrUpdateAttributeWithStatusCheck(
306
- db,
307
- dbId,
308
- newCollection,
309
- attribute,
310
- retryCount + 1,
386
+ db,
387
+ dbId,
388
+ newCollection,
389
+ attribute,
390
+ retryCount + 1,
311
391
  maxRetries
312
392
  );
313
393
  }
314
394
  } else {
315
395
  // Continue to next retry without collection recreation
316
396
  return await createOrUpdateAttributeWithStatusCheck(
317
- db,
318
- dbId,
319
- collection,
320
- attribute,
321
- retryCount + 1,
397
+ db,
398
+ dbId,
399
+ collection,
400
+ attribute,
401
+ retryCount + 1,
322
402
  maxRetries
323
403
  );
324
404
  }
325
405
  }
326
406
  }
327
-
328
- console.log(chalk.red(`❌ Failed to create attribute '${attribute.key}' after ${maxRetries + 1} attempts`));
407
+
408
+ console.log(
409
+ chalk.red(
410
+ `❌ Failed to create attribute '${attribute.key}' after ${
411
+ maxRetries + 1
412
+ } attempts`
413
+ )
414
+ );
329
415
  return false;
330
-
331
416
  } catch (error) {
332
- console.log(chalk.red(`Error creating attribute '${attribute.key}': ${error}`));
333
-
417
+ console.log(
418
+ chalk.red(`Error creating attribute '${attribute.key}': ${error}`)
419
+ );
420
+
334
421
  if (retryCount < maxRetries) {
335
- console.log(chalk.yellow(`Retrying attribute '${attribute.key}' due to error...`));
336
-
422
+ console.log(
423
+ chalk.yellow(`Retrying attribute '${attribute.key}' due to error...`)
424
+ );
425
+
337
426
  // Wait a bit before retry
338
427
  await delay(2000);
339
-
428
+
340
429
  return await createOrUpdateAttributeWithStatusCheck(
341
- db,
342
- dbId,
343
- collection,
344
- attribute,
345
- retryCount + 1,
430
+ db,
431
+ dbId,
432
+ collection,
433
+ attribute,
434
+ retryCount + 1,
346
435
  maxRetries
347
436
  );
348
437
  }
349
-
438
+
350
439
  return false;
351
440
  }
352
441
  };
@@ -408,7 +497,10 @@ export const createOrUpdateAttribute = async (
408
497
  // Relationship attribute logic with adjustments
409
498
  let collectionFoundViaRelatedCollection: Models.Collection | undefined;
410
499
  let relatedCollectionId: string | undefined;
411
- if (finalAttribute.type === "relationship") {
500
+ if (
501
+ finalAttribute.type === "relationship" &&
502
+ finalAttribute.relatedCollection
503
+ ) {
412
504
  if (nameToIdMapping.has(finalAttribute.relatedCollection)) {
413
505
  relatedCollectionId = nameToIdMapping.get(
414
506
  finalAttribute.relatedCollection
@@ -437,9 +529,13 @@ export const createOrUpdateAttribute = async (
437
529
  );
438
530
  }
439
531
  }
440
- // Only queue relationship attributes that have dependencies
441
- if (finalAttribute.type === "relationship" && !(relatedCollectionId && collectionFoundViaRelatedCollection)) {
442
- // console.log(`Enqueueing operation for attribute: ${finalAttribute.key}`);
532
+ // ONLY queue relationship attributes that have actual unresolved dependencies
533
+ if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
534
+ console.log(
535
+ chalk.yellow(
536
+ `⏳ Queueing relationship attribute '${finalAttribute.key}' - related collection '${finalAttribute.relatedCollection}' not found yet`
537
+ )
538
+ );
443
539
  enqueueOperation({
444
540
  type: "attribute",
445
541
  collectionId: collection.$id,
@@ -480,7 +576,8 @@ export const createOrUpdateAttribute = async (
480
576
  finalAttribute.required || false,
481
577
  finalAttribute.xdefault !== undefined && !finalAttribute.required
482
578
  ? finalAttribute.xdefault
483
- : null
579
+ : null,
580
+ finalAttribute.size
484
581
  )
485
582
  );
486
583
  }
@@ -491,14 +588,27 @@ export const createOrUpdateAttribute = async (
491
588
  finalAttribute.min &&
492
589
  BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
493
590
  ) {
494
- delete finalAttribute.min;
591
+ finalAttribute.min = undefined;
495
592
  }
496
593
  if (
497
594
  finalAttribute.max &&
498
595
  BigInt(finalAttribute.max) === BigInt(9223372036854776000)
499
596
  ) {
500
- delete finalAttribute.max;
597
+ finalAttribute.max = undefined;
501
598
  }
599
+ const minValue =
600
+ finalAttribute.min !== undefined && finalAttribute.min !== null
601
+ ? parseInt(finalAttribute.min)
602
+ : -9007199254740991;
603
+ const maxValue =
604
+ finalAttribute.max !== undefined && finalAttribute.max !== null
605
+ ? parseInt(finalAttribute.max)
606
+ : 9007199254740991;
607
+ console.log(
608
+ `DEBUG: Creating integer attribute '${
609
+ finalAttribute.key
610
+ }' with min=${minValue}, max=${maxValue}, minType=${typeof minValue}, maxType=${typeof maxValue}`
611
+ );
502
612
  await tryAwaitWithRetry(
503
613
  async () =>
504
614
  await db.createIntegerAttribute(
@@ -506,8 +616,8 @@ export const createOrUpdateAttribute = async (
506
616
  collection.$id,
507
617
  finalAttribute.key,
508
618
  finalAttribute.required || false,
509
- finalAttribute.min !== undefined ? finalAttribute.min : -2147483647,
510
- finalAttribute.max !== undefined ? finalAttribute.max : 2147483647,
619
+ minValue,
620
+ maxValue,
511
621
  finalAttribute.xdefault !== undefined && !finalAttribute.required
512
622
  ? finalAttribute.xdefault
513
623
  : null,
@@ -519,14 +629,27 @@ export const createOrUpdateAttribute = async (
519
629
  finalAttribute.min &&
520
630
  BigInt(finalAttribute.min) === BigInt(-9223372036854776000)
521
631
  ) {
522
- delete finalAttribute.min;
632
+ finalAttribute.min = undefined;
523
633
  }
524
634
  if (
525
635
  finalAttribute.max &&
526
636
  BigInt(finalAttribute.max) === BigInt(9223372036854776000)
527
637
  ) {
528
- delete finalAttribute.max;
638
+ finalAttribute.max = undefined;
529
639
  }
640
+ const minValue =
641
+ finalAttribute.min !== undefined && finalAttribute.min !== null
642
+ ? parseInt(finalAttribute.min)
643
+ : 9007199254740991;
644
+ const maxValue =
645
+ finalAttribute.max !== undefined && finalAttribute.max !== null
646
+ ? parseInt(finalAttribute.max)
647
+ : 9007199254740991;
648
+ console.log(
649
+ `DEBUG: Updating integer attribute '${
650
+ finalAttribute.key
651
+ }' with min=${minValue}, max=${maxValue}, minType=${typeof minValue}, maxType=${typeof maxValue}`
652
+ );
530
653
  await tryAwaitWithRetry(
531
654
  async () =>
532
655
  await db.updateIntegerAttribute(
@@ -534,11 +657,11 @@ export const createOrUpdateAttribute = async (
534
657
  collection.$id,
535
658
  finalAttribute.key,
536
659
  finalAttribute.required || false,
537
- finalAttribute.min !== undefined ? finalAttribute.min : -2147483647,
538
- finalAttribute.max !== undefined ? finalAttribute.max : 2147483647,
539
660
  finalAttribute.xdefault !== undefined && !finalAttribute.required
540
661
  ? finalAttribute.xdefault
541
- : null
662
+ : null,
663
+ minValue,
664
+ maxValue
542
665
  )
543
666
  );
544
667
  }
@@ -850,115 +973,186 @@ export const createUpdateCollectionAttributesWithStatusCheck = async (
850
973
  }
851
974
 
852
975
  // First, get fresh collection data and determine which attributes actually need processing
853
- console.log(chalk.blue(`Analyzing ${attributes.length} attributes to determine which need processing...`));
854
-
976
+ console.log(
977
+ chalk.blue(
978
+ `Analyzing ${attributes.length} attributes to determine which need processing...`
979
+ )
980
+ );
981
+
855
982
  let currentCollection = collection;
856
983
  try {
857
984
  currentCollection = await db.getCollection(dbId, collection.$id);
858
985
  } catch (error) {
859
- console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
986
+ console.log(
987
+ chalk.yellow(`Warning: Could not refresh collection data: ${error}`)
988
+ );
860
989
  }
861
-
990
+
862
991
  const existingAttributesMap = new Map<string, Attribute>();
863
992
  try {
864
- // @ts-expect-error
865
- const parsedAttributes = currentCollection.attributes.map((attr) => parseAttribute(attr));
866
- parsedAttributes.forEach(attr => existingAttributesMap.set(attr.key, attr));
993
+ const parsedAttributes = currentCollection.attributes.map((attr) =>
994
+ // @ts-expect-error
995
+ parseAttribute(attr)
996
+ );
997
+ parsedAttributes.forEach((attr) =>
998
+ existingAttributesMap.set(attr.key, attr)
999
+ );
867
1000
  } catch (error) {
868
- console.log(chalk.yellow(`Warning: Could not parse existing attributes: ${error}`));
1001
+ console.log(
1002
+ chalk.yellow(`Warning: Could not parse existing attributes: ${error}`)
1003
+ );
869
1004
  }
870
-
1005
+
871
1006
  // Filter to only attributes that need processing (new or changed)
872
- const attributesToProcess = attributes.filter(attribute => {
1007
+ const attributesToProcess = attributes.filter((attribute) => {
873
1008
  const existing = existingAttributesMap.get(attribute.key);
874
1009
  if (!existing) {
875
1010
  console.log(chalk.blue(`➕ New attribute: ${attribute.key}`));
876
1011
  return true;
877
1012
  }
878
-
1013
+
879
1014
  const needsUpdate = !attributesSame(existing, attribute);
880
1015
  if (needsUpdate) {
881
1016
  console.log(chalk.blue(`🔄 Changed attribute: ${attribute.key}`));
882
1017
  } else {
883
- console.log(chalk.gray(`✅ Unchanged attribute: ${attribute.key} (skipping)`));
1018
+ console.log(
1019
+ chalk.gray(`✅ Unchanged attribute: ${attribute.key} (skipping)`)
1020
+ );
884
1021
  }
885
1022
  return needsUpdate;
886
1023
  });
887
-
1024
+
888
1025
  if (attributesToProcess.length === 0) {
889
- console.log(chalk.green(`✅ All ${attributes.length} attributes are already up to date for collection: ${collection.name}`));
1026
+ console.log(
1027
+ chalk.green(
1028
+ `✅ All ${attributes.length} attributes are already up to date for collection: ${collection.name}`
1029
+ )
1030
+ );
890
1031
  return true;
891
1032
  }
892
-
893
- console.log(chalk.blue(`Creating ${attributesToProcess.length} attributes sequentially with status monitoring...`));
894
-
1033
+
1034
+ console.log(
1035
+ chalk.blue(
1036
+ `Creating ${attributesToProcess.length} attributes sequentially with status monitoring...`
1037
+ )
1038
+ );
1039
+
895
1040
  let remainingAttributes = [...attributesToProcess];
896
1041
  let overallRetryCount = 0;
897
1042
  const maxOverallRetries = 3;
898
-
899
- while (remainingAttributes.length > 0 && overallRetryCount < maxOverallRetries) {
1043
+
1044
+ while (
1045
+ remainingAttributes.length > 0 &&
1046
+ overallRetryCount < maxOverallRetries
1047
+ ) {
900
1048
  const attributesToProcessThisRound = [...remainingAttributes];
901
1049
  remainingAttributes = []; // Reset for next iteration
902
-
903
- console.log(chalk.blue(`\n=== Attempt ${overallRetryCount + 1}/${maxOverallRetries} - Processing ${attributesToProcessThisRound.length} attributes ===`));
904
-
1050
+
1051
+ console.log(
1052
+ chalk.blue(
1053
+ `\n=== Attempt ${
1054
+ overallRetryCount + 1
1055
+ }/${maxOverallRetries} - Processing ${
1056
+ attributesToProcessThisRound.length
1057
+ } attributes ===`
1058
+ )
1059
+ );
1060
+
905
1061
  for (const attribute of attributesToProcessThisRound) {
906
- console.log(chalk.blue(`\n--- Processing attribute: ${attribute.key} ---`));
907
-
1062
+ console.log(
1063
+ chalk.blue(`\n--- Processing attribute: ${attribute.key} ---`)
1064
+ );
1065
+
908
1066
  const success = await createOrUpdateAttributeWithStatusCheck(
909
- db,
910
- dbId,
911
- currentCollection,
1067
+ db,
1068
+ dbId,
1069
+ currentCollection,
912
1070
  attribute
913
1071
  );
914
-
1072
+
915
1073
  if (success) {
916
- console.log(chalk.green(`✅ Successfully created attribute: ${attribute.key}`));
917
-
1074
+ console.log(
1075
+ chalk.green(`✅ Successfully created attribute: ${attribute.key}`)
1076
+ );
1077
+
918
1078
  // Get updated collection data for next iteration
919
1079
  try {
920
1080
  currentCollection = await db.getCollection(dbId, collection.$id);
921
1081
  } catch (error) {
922
- console.log(chalk.yellow(`Warning: Could not refresh collection data: ${error}`));
1082
+ console.log(
1083
+ chalk.yellow(`Warning: Could not refresh collection data: ${error}`)
1084
+ );
923
1085
  }
924
-
1086
+
925
1087
  // Add delay between successful attributes
926
1088
  await delay(1000);
927
1089
  } else {
928
- console.log(chalk.red(`❌ Failed to create attribute: ${attribute.key}, will retry in next round`));
1090
+ console.log(
1091
+ chalk.red(
1092
+ `❌ Failed to create attribute: ${attribute.key}, will retry in next round`
1093
+ )
1094
+ );
929
1095
  remainingAttributes.push(attribute); // Add back to retry list
930
1096
  }
931
1097
  }
932
-
1098
+
933
1099
  if (remainingAttributes.length === 0) {
934
- console.log(chalk.green(`\n✅ Successfully created all ${attributesToProcess.length} attributes for collection: ${collection.name}`));
1100
+ console.log(
1101
+ chalk.green(
1102
+ `\n✅ Successfully created all ${attributesToProcess.length} attributes for collection: ${collection.name}`
1103
+ )
1104
+ );
935
1105
  return true;
936
1106
  }
937
-
1107
+
938
1108
  overallRetryCount++;
939
-
1109
+
940
1110
  if (overallRetryCount < maxOverallRetries) {
941
- console.log(chalk.yellow(`\n⏳ Waiting 5 seconds before retrying ${attributesToProcess.length} failed attributes...`));
1111
+ console.log(
1112
+ chalk.yellow(
1113
+ `\n⏳ Waiting 5 seconds before retrying ${attributesToProcess.length} failed attributes...`
1114
+ )
1115
+ );
942
1116
  await delay(5000);
943
-
1117
+
944
1118
  // Refresh collection data before retry
945
1119
  try {
946
1120
  currentCollection = await db.getCollection(dbId, collection.$id);
947
1121
  console.log(chalk.blue(`Refreshed collection data for retry`));
948
1122
  } catch (error) {
949
- console.log(chalk.yellow(`Warning: Could not refresh collection data for retry: ${error}`));
1123
+ console.log(
1124
+ chalk.yellow(
1125
+ `Warning: Could not refresh collection data for retry: ${error}`
1126
+ )
1127
+ );
950
1128
  }
951
1129
  }
952
1130
  }
953
-
1131
+
954
1132
  // If we get here, some attributes still failed after all retries
955
1133
  if (attributesToProcess.length > 0) {
956
- console.log(chalk.red(`\n❌ Failed to create ${attributesToProcess.length} attributes after ${maxOverallRetries} attempts: ${attributesToProcess.map(a => a.key).join(', ')}`));
957
- console.log(chalk.red(`This may indicate a fundamental issue with the attribute definitions or Appwrite instance`));
1134
+ console.log(
1135
+ chalk.red(
1136
+ `\n❌ Failed to create ${
1137
+ attributesToProcess.length
1138
+ } attributes after ${maxOverallRetries} attempts: ${attributesToProcess
1139
+ .map((a) => a.key)
1140
+ .join(", ")}`
1141
+ )
1142
+ );
1143
+ console.log(
1144
+ chalk.red(
1145
+ `This may indicate a fundamental issue with the attribute definitions or Appwrite instance`
1146
+ )
1147
+ );
958
1148
  return false;
959
1149
  }
960
-
961
- console.log(chalk.green(`\n✅ Successfully created all ${attributes.length} attributes for collection: ${collection.name}`));
1150
+
1151
+ console.log(
1152
+ chalk.green(
1153
+ `\n✅ Successfully created all ${attributes.length} attributes for collection: ${collection.name}`
1154
+ )
1155
+ );
962
1156
  return true;
963
1157
  };
964
1158