appwrite-utils-cli 1.4.0 → 1.5.0
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 +22 -1
- package/dist/adapters/TablesDBAdapter.js +7 -4
- package/dist/collections/attributes.d.ts +1 -1
- package/dist/collections/attributes.js +24 -6
- package/dist/collections/indexes.js +13 -3
- package/dist/collections/methods.d.ts +9 -0
- package/dist/collections/methods.js +268 -0
- package/dist/migrations/appwriteToX.d.ts +2 -2
- package/dist/migrations/comprehensiveTransfer.js +12 -0
- package/dist/migrations/dataLoader.d.ts +5 -5
- package/dist/migrations/relationships.d.ts +2 -2
- package/dist/shared/jsonSchemaGenerator.d.ts +1 -0
- package/dist/shared/jsonSchemaGenerator.js +6 -2
- package/dist/shared/operationQueue.js +14 -1
- package/dist/shared/schemaGenerator.d.ts +2 -1
- package/dist/shared/schemaGenerator.js +61 -78
- package/dist/storage/schemas.d.ts +8 -8
- package/dist/utils/loadConfigs.js +44 -19
- package/dist/utils/schemaStrings.d.ts +2 -1
- package/dist/utils/schemaStrings.js +61 -78
- package/dist/utils/setupFiles.js +19 -1
- package/dist/utils/versionDetection.d.ts +6 -0
- package/dist/utils/versionDetection.js +30 -0
- package/dist/utilsController.js +28 -4
- package/package.json +2 -2
- package/src/adapters/TablesDBAdapter.ts +20 -17
- package/src/collections/attributes.ts +122 -99
- package/src/collections/indexes.ts +36 -28
- package/src/collections/methods.ts +292 -19
- package/src/migrations/comprehensiveTransfer.ts +22 -8
- package/src/shared/jsonSchemaGenerator.ts +36 -29
- package/src/shared/operationQueue.ts +48 -33
- package/src/shared/schemaGenerator.ts +128 -134
- package/src/utils/loadConfigs.ts +48 -29
- package/src/utils/schemaStrings.ts +124 -130
- package/src/utils/setupFiles.ts +21 -5
- package/src/utils/versionDetection.ts +48 -21
- package/src/utilsController.ts +44 -24
package/dist/utilsController.js
CHANGED
@@ -7,12 +7,14 @@ import { ImportController } from "./migrations/importController.js";
|
|
7
7
|
import { ImportDataActions } from "./migrations/importDataActions.js";
|
8
8
|
import { setupMigrationDatabase, ensureDatabasesExist, wipeOtherDatabases, ensureCollectionsExist, } from "./databases/setup.js";
|
9
9
|
import { createOrUpdateCollections, wipeDatabase, generateSchemas, fetchAllCollections, wipeCollection, } from "./collections/methods.js";
|
10
|
+
import { wipeAllTables, wipeTableRows } from "./collections/methods.js";
|
10
11
|
import { backupDatabase, ensureDatabaseConfigBucketsExist, initOrGetBackupStorage, wipeDocumentStorage, } from "./storage/methods.js";
|
11
12
|
import path from "path";
|
12
13
|
import { converterFunctions, validationRules, } from "appwrite-utils";
|
13
14
|
import { afterImportActions } from "./migrations/afterImportActions.js";
|
14
15
|
import { transferDatabaseLocalToLocal, transferDatabaseLocalToRemote, transferStorageLocalToLocal, transferStorageLocalToRemote, transferUsersLocalToRemote, } from "./migrations/transfer.js";
|
15
16
|
import { getClient } from "./utils/getClientFromConfig.js";
|
17
|
+
import { getAdapterFromConfig } from "./utils/getClientFromConfig.js";
|
16
18
|
import { fetchAllDatabases } from "./databases/methods.js";
|
17
19
|
import { listFunctions, updateFunctionSpecifications, } from "./functions/methods.js";
|
18
20
|
import chalk from "chalk";
|
@@ -291,9 +293,20 @@ export class UtilsController {
|
|
291
293
|
}
|
292
294
|
async wipeDatabase(database, wipeBucket = false) {
|
293
295
|
await this.init();
|
294
|
-
if (!this.database)
|
296
|
+
if (!this.database || !this.config)
|
295
297
|
throw new Error("Database not initialized");
|
296
|
-
|
298
|
+
try {
|
299
|
+
const { adapter, apiMode } = await getAdapterFromConfig(this.config);
|
300
|
+
if (apiMode === 'tablesdb') {
|
301
|
+
await wipeAllTables(adapter, database.$id);
|
302
|
+
}
|
303
|
+
else {
|
304
|
+
await wipeDatabase(this.database, database.$id);
|
305
|
+
}
|
306
|
+
}
|
307
|
+
catch {
|
308
|
+
await wipeDatabase(this.database, database.$id);
|
309
|
+
}
|
297
310
|
if (wipeBucket) {
|
298
311
|
await this.wipeBucketFromDatabase(database);
|
299
312
|
}
|
@@ -323,9 +336,20 @@ export class UtilsController {
|
|
323
336
|
}
|
324
337
|
async wipeCollection(database, collection) {
|
325
338
|
await this.init();
|
326
|
-
if (!this.database)
|
339
|
+
if (!this.database || !this.config)
|
327
340
|
throw new Error("Database not initialized");
|
328
|
-
|
341
|
+
try {
|
342
|
+
const { adapter, apiMode } = await getAdapterFromConfig(this.config);
|
343
|
+
if (apiMode === 'tablesdb') {
|
344
|
+
await wipeTableRows(adapter, database.$id, collection.$id);
|
345
|
+
}
|
346
|
+
else {
|
347
|
+
await wipeCollection(this.database, database.$id, collection.$id);
|
348
|
+
}
|
349
|
+
}
|
350
|
+
catch {
|
351
|
+
await wipeCollection(this.database, database.$id, collection.$id);
|
352
|
+
}
|
329
353
|
}
|
330
354
|
async wipeDocumentStorage(bucketId) {
|
331
355
|
await this.init();
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "appwrite-utils-cli",
|
3
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": "1.
|
4
|
+
"version": "1.5.0",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -33,7 +33,7 @@
|
|
33
33
|
"@types/inquirer": "^9.0.8",
|
34
34
|
"@types/json-schema": "^7.0.15",
|
35
35
|
"@types/yargs": "^17.0.33",
|
36
|
-
"appwrite-utils": "^1.4.
|
36
|
+
"appwrite-utils": "^1.4.1",
|
37
37
|
"chalk": "^5.4.1",
|
38
38
|
"cli-progress": "^3.12.0",
|
39
39
|
"commander": "^12.1.0",
|
@@ -246,12 +246,13 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
246
246
|
}
|
247
247
|
|
248
248
|
// Attribute Operations
|
249
|
-
async createAttribute(params: CreateAttributeParams): Promise<ApiResponse> {
|
250
|
-
try {
|
251
|
-
//
|
252
|
-
const
|
253
|
-
|
254
|
-
|
249
|
+
async createAttribute(params: CreateAttributeParams): Promise<ApiResponse> {
|
250
|
+
try {
|
251
|
+
// Prefer createColumn if available, fallback to createAttribute
|
252
|
+
const fn = this.tablesDB.createColumn || this.tablesDB.createAttribute;
|
253
|
+
const result = await fn.call(this.tablesDB, params);
|
254
|
+
return { data: result };
|
255
|
+
} catch (error) {
|
255
256
|
throw new AdapterError(
|
256
257
|
`Failed to create attribute: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
257
258
|
'CREATE_ATTRIBUTE_FAILED',
|
@@ -260,11 +261,12 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
260
261
|
}
|
261
262
|
}
|
262
263
|
|
263
|
-
async updateAttribute(params: UpdateAttributeParams): Promise<ApiResponse> {
|
264
|
-
try {
|
265
|
-
const
|
266
|
-
|
267
|
-
|
264
|
+
async updateAttribute(params: UpdateAttributeParams): Promise<ApiResponse> {
|
265
|
+
try {
|
266
|
+
const fn = this.tablesDB.updateColumn || this.tablesDB.updateAttribute;
|
267
|
+
const result = await fn.call(this.tablesDB, params);
|
268
|
+
return { data: result };
|
269
|
+
} catch (error) {
|
268
270
|
throw new AdapterError(
|
269
271
|
`Failed to update attribute: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
270
272
|
'UPDATE_ATTRIBUTE_FAILED',
|
@@ -273,11 +275,12 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
273
275
|
}
|
274
276
|
}
|
275
277
|
|
276
|
-
async deleteAttribute(params: DeleteAttributeParams): Promise<ApiResponse> {
|
277
|
-
try {
|
278
|
-
const
|
279
|
-
|
280
|
-
|
278
|
+
async deleteAttribute(params: DeleteAttributeParams): Promise<ApiResponse> {
|
279
|
+
try {
|
280
|
+
const fn = this.tablesDB.deleteColumn || this.tablesDB.deleteAttribute;
|
281
|
+
const result = await fn.call(this.tablesDB, params);
|
282
|
+
return { data: result };
|
283
|
+
} catch (error) {
|
281
284
|
throw new AdapterError(
|
282
285
|
`Failed to delete attribute: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
283
286
|
'DELETE_ATTRIBUTE_FAILED',
|
@@ -426,4 +429,4 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
426
429
|
);
|
427
430
|
}
|
428
431
|
}
|
429
|
-
}
|
432
|
+
}
|
@@ -287,14 +287,14 @@ const attributesSame = (
|
|
287
287
|
/**
|
288
288
|
* Enhanced attribute creation with proper status monitoring and retry logic
|
289
289
|
*/
|
290
|
-
export const createOrUpdateAttributeWithStatusCheck = async (
|
291
|
-
db: Databases,
|
292
|
-
dbId: string,
|
293
|
-
collection: Models.Collection,
|
294
|
-
attribute: Attribute,
|
295
|
-
retryCount: number = 0,
|
296
|
-
maxRetries: number = 5
|
297
|
-
): Promise<boolean> => {
|
290
|
+
export const createOrUpdateAttributeWithStatusCheck = async (
|
291
|
+
db: Databases,
|
292
|
+
dbId: string,
|
293
|
+
collection: Models.Collection,
|
294
|
+
attribute: Attribute,
|
295
|
+
retryCount: number = 0,
|
296
|
+
maxRetries: number = 5
|
297
|
+
): Promise<boolean> => {
|
298
298
|
console.log(
|
299
299
|
chalk.blue(
|
300
300
|
`Creating/updating attribute '${attribute.key}' (attempt ${
|
@@ -303,20 +303,31 @@ export const createOrUpdateAttributeWithStatusCheck = async (
|
|
303
303
|
)
|
304
304
|
);
|
305
305
|
|
306
|
-
try {
|
307
|
-
// First, try to create/update the attribute using existing logic
|
308
|
-
await createOrUpdateAttribute(db, dbId, collection, attribute);
|
309
|
-
|
310
|
-
//
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
306
|
+
try {
|
307
|
+
// First, try to create/update the attribute using existing logic
|
308
|
+
const result = await createOrUpdateAttribute(db, dbId, collection, attribute);
|
309
|
+
|
310
|
+
// If the attribute was queued (relationship dependency unresolved),
|
311
|
+
// skip status polling and retry logic — the queue will handle it later.
|
312
|
+
if (result === "queued") {
|
313
|
+
console.log(
|
314
|
+
chalk.yellow(
|
315
|
+
`⏭️ Deferred relationship attribute '${attribute.key}' — queued for later once dependencies are available`
|
316
|
+
)
|
317
|
+
);
|
318
|
+
return true;
|
319
|
+
}
|
320
|
+
|
321
|
+
// Now wait for the attribute to become available
|
322
|
+
const success = await waitForAttributeAvailable(
|
323
|
+
db,
|
324
|
+
dbId,
|
325
|
+
collection.$id,
|
326
|
+
attribute.key,
|
327
|
+
60000, // 1 minute timeout
|
328
|
+
retryCount,
|
329
|
+
maxRetries
|
330
|
+
);
|
320
331
|
|
321
332
|
if (success) {
|
322
333
|
return true;
|
@@ -440,12 +451,12 @@ export const createOrUpdateAttributeWithStatusCheck = async (
|
|
440
451
|
}
|
441
452
|
};
|
442
453
|
|
443
|
-
export const createOrUpdateAttribute = async (
|
444
|
-
db: Databases,
|
445
|
-
dbId: string,
|
446
|
-
collection: Models.Collection,
|
447
|
-
attribute: Attribute
|
448
|
-
): Promise<
|
454
|
+
export const createOrUpdateAttribute = async (
|
455
|
+
db: Databases,
|
456
|
+
dbId: string,
|
457
|
+
collection: Models.Collection,
|
458
|
+
attribute: Attribute
|
459
|
+
): Promise<"queued" | "processed"> => {
|
449
460
|
let action = "create";
|
450
461
|
let foundAttribute: Attribute | undefined;
|
451
462
|
const updateEnabled = true;
|
@@ -460,13 +471,13 @@ export const createOrUpdateAttribute = async (
|
|
460
471
|
foundAttribute = undefined;
|
461
472
|
}
|
462
473
|
|
463
|
-
if (
|
464
|
-
foundAttribute &&
|
465
|
-
attributesSame(foundAttribute, attribute) &&
|
466
|
-
updateEnabled
|
467
|
-
) {
|
468
|
-
// No need to do anything, they are the same
|
469
|
-
return;
|
474
|
+
if (
|
475
|
+
foundAttribute &&
|
476
|
+
attributesSame(foundAttribute, attribute) &&
|
477
|
+
updateEnabled
|
478
|
+
) {
|
479
|
+
// No need to do anything, they are the same
|
480
|
+
return "processed";
|
470
481
|
} else if (
|
471
482
|
foundAttribute &&
|
472
483
|
!attributesSame(foundAttribute, attribute) &&
|
@@ -484,71 +495,82 @@ export const createOrUpdateAttribute = async (
|
|
484
495
|
!updateEnabled &&
|
485
496
|
foundAttribute &&
|
486
497
|
!attributesSame(foundAttribute, attribute)
|
487
|
-
) {
|
488
|
-
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
489
|
-
console.log(
|
490
|
-
`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`
|
491
|
-
);
|
492
|
-
return;
|
493
|
-
}
|
498
|
+
) {
|
499
|
+
await db.deleteAttribute(dbId, collection.$id, attribute.key);
|
500
|
+
console.log(
|
501
|
+
`Deleted attribute: ${attribute.key} to recreate it because they diff (update disabled temporarily)`
|
502
|
+
);
|
503
|
+
return "processed";
|
504
|
+
}
|
494
505
|
|
495
506
|
// console.log(`${action}-ing attribute: ${finalAttribute.key}`);
|
496
507
|
|
497
508
|
// Relationship attribute logic with adjustments
|
498
509
|
let collectionFoundViaRelatedCollection: Models.Collection | undefined;
|
499
510
|
let relatedCollectionId: string | undefined;
|
500
|
-
if (
|
501
|
-
finalAttribute.type === "relationship" &&
|
502
|
-
finalAttribute.relatedCollection
|
503
|
-
) {
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
nameToIdMapping
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
511
|
+
if (
|
512
|
+
finalAttribute.type === "relationship" &&
|
513
|
+
finalAttribute.relatedCollection
|
514
|
+
) {
|
515
|
+
// First try treating relatedCollection as an ID directly
|
516
|
+
try {
|
517
|
+
const byIdCollection = await db.getCollection(dbId, finalAttribute.relatedCollection);
|
518
|
+
collectionFoundViaRelatedCollection = byIdCollection;
|
519
|
+
relatedCollectionId = byIdCollection.$id;
|
520
|
+
// Cache by name for subsequent lookups
|
521
|
+
nameToIdMapping.set(byIdCollection.name, byIdCollection.$id);
|
522
|
+
} catch (_) {
|
523
|
+
// Not an ID or not found — fall back to name-based resolution below
|
524
|
+
}
|
525
|
+
|
526
|
+
if (!collectionFoundViaRelatedCollection && nameToIdMapping.has(finalAttribute.relatedCollection)) {
|
527
|
+
relatedCollectionId = nameToIdMapping.get(
|
528
|
+
finalAttribute.relatedCollection
|
529
|
+
);
|
530
|
+
try {
|
531
|
+
collectionFoundViaRelatedCollection = await db.getCollection(
|
532
|
+
dbId,
|
533
|
+
relatedCollectionId!
|
534
|
+
);
|
535
|
+
} catch (e) {
|
536
|
+
// console.log(
|
537
|
+
// `Collection not found: ${finalAttribute.relatedCollection} when nameToIdMapping was set`
|
538
|
+
// );
|
539
|
+
collectionFoundViaRelatedCollection = undefined;
|
540
|
+
}
|
541
|
+
} else if (!collectionFoundViaRelatedCollection) {
|
542
|
+
const collectionsPulled = await db.listCollections(dbId, [
|
543
|
+
Query.equal("name", finalAttribute.relatedCollection),
|
544
|
+
]);
|
545
|
+
if (collectionsPulled.total > 0) {
|
546
|
+
collectionFoundViaRelatedCollection = collectionsPulled.collections[0];
|
547
|
+
relatedCollectionId = collectionFoundViaRelatedCollection.$id;
|
548
|
+
nameToIdMapping.set(
|
549
|
+
finalAttribute.relatedCollection,
|
550
|
+
relatedCollectionId
|
551
|
+
);
|
552
|
+
}
|
553
|
+
}
|
554
|
+
// ONLY queue relationship attributes that have actual unresolved dependencies
|
555
|
+
if (!(relatedCollectionId && collectionFoundViaRelatedCollection)) {
|
556
|
+
console.log(
|
557
|
+
chalk.yellow(
|
558
|
+
`⏳ Queueing relationship attribute '${finalAttribute.key}' - related collection '${finalAttribute.relatedCollection}' not found yet`
|
559
|
+
)
|
560
|
+
);
|
561
|
+
enqueueOperation({
|
562
|
+
type: "attribute",
|
563
|
+
collectionId: collection.$id,
|
564
|
+
collection: collection,
|
565
|
+
attribute,
|
566
|
+
dependencies: [finalAttribute.relatedCollection],
|
567
|
+
});
|
568
|
+
return "queued";
|
569
|
+
}
|
570
|
+
}
|
571
|
+
finalAttribute = parseAttribute(finalAttribute);
|
572
|
+
// console.log(`Final Attribute: ${JSON.stringify(finalAttribute)}`);
|
573
|
+
switch (finalAttribute.type) {
|
552
574
|
case "string":
|
553
575
|
if (action === "create") {
|
554
576
|
await tryAwaitWithRetry(
|
@@ -910,11 +932,12 @@ export const createOrUpdateAttribute = async (
|
|
910
932
|
);
|
911
933
|
}
|
912
934
|
break;
|
913
|
-
default:
|
914
|
-
console.error("Invalid attribute type");
|
915
|
-
break;
|
916
|
-
}
|
917
|
-
|
935
|
+
default:
|
936
|
+
console.error("Invalid attribute type");
|
937
|
+
break;
|
938
|
+
}
|
939
|
+
return "processed";
|
940
|
+
};
|
918
941
|
|
919
942
|
/**
|
920
943
|
* Enhanced collection attribute creation with proper status monitoring
|
@@ -1,5 +1,6 @@
|
|
1
|
-
import { indexSchema, type Index } from "appwrite-utils";
|
2
|
-
import { Databases, IndexType, Query, type Models } from "node-appwrite";
|
1
|
+
import { indexSchema, type Index } from "appwrite-utils";
|
2
|
+
import { Databases, IndexType, Query, type Models } from "node-appwrite";
|
3
|
+
import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
|
3
4
|
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
4
5
|
import chalk from "chalk";
|
5
6
|
|
@@ -18,15 +19,15 @@ interface IndexWithStatus {
|
|
18
19
|
/**
|
19
20
|
* Wait for index to become available, with retry logic for stuck indexes and exponential backoff
|
20
21
|
*/
|
21
|
-
const waitForIndexAvailable = async (
|
22
|
-
db: Databases,
|
23
|
-
dbId: string,
|
24
|
-
collectionId: string,
|
25
|
-
indexKey: string,
|
26
|
-
maxWaitTime: number = 60000, // 1 minute
|
27
|
-
retryCount: number = 0,
|
28
|
-
maxRetries: number = 5
|
29
|
-
): Promise<boolean> => {
|
22
|
+
const waitForIndexAvailable = async (
|
23
|
+
db: Databases | DatabaseAdapter,
|
24
|
+
dbId: string,
|
25
|
+
collectionId: string,
|
26
|
+
indexKey: string,
|
27
|
+
maxWaitTime: number = 60000, // 1 minute
|
28
|
+
retryCount: number = 0,
|
29
|
+
maxRetries: number = 5
|
30
|
+
): Promise<boolean> => {
|
30
31
|
const startTime = Date.now();
|
31
32
|
let checkInterval = 2000; // Start with 2 seconds
|
32
33
|
|
@@ -41,22 +42,29 @@ const waitForIndexAvailable = async (
|
|
41
42
|
|
42
43
|
while (Date.now() - startTime < maxWaitTime) {
|
43
44
|
try {
|
44
|
-
const indexList = await db
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
const indexList = await (db instanceof Databases
|
46
|
+
? db.listIndexes(dbId, collectionId)
|
47
|
+
: (db as DatabaseAdapter).listIndexes({ databaseId: dbId, tableId: collectionId }));
|
48
|
+
const indexes: any[] = (db instanceof Databases)
|
49
|
+
? (indexList as any).indexes
|
50
|
+
: ((indexList as any).data || (indexList as any).indexes || []);
|
51
|
+
const index = indexes.find((idx: any) => idx.key === indexKey) as IndexWithStatus | undefined;
|
48
52
|
|
49
53
|
if (!index) {
|
50
54
|
console.log(chalk.red(`Index '${indexKey}' not found`));
|
51
55
|
return false;
|
52
56
|
}
|
53
57
|
|
54
|
-
|
58
|
+
if (db instanceof Databases) {
|
59
|
+
console.log(chalk.gray(`Index '${indexKey}' status: ${(index as any).status}`));
|
60
|
+
} else {
|
61
|
+
console.log(chalk.gray(`Index '${indexKey}' detected (TablesDB)`));
|
62
|
+
}
|
55
63
|
|
56
64
|
switch (index.status) {
|
57
|
-
case 'available':
|
58
|
-
console.log(chalk.green(`✅ Index '${indexKey}' is now available`));
|
59
|
-
return true;
|
65
|
+
case 'available':
|
66
|
+
console.log(chalk.green(`✅ Index '${indexKey}' is now available`));
|
67
|
+
return true;
|
60
68
|
|
61
69
|
case 'failed':
|
62
70
|
console.log(chalk.red(`❌ Index '${indexKey}' failed: ${index.error}`));
|
@@ -66,9 +74,9 @@ const waitForIndexAvailable = async (
|
|
66
74
|
console.log(chalk.yellow(`⚠️ Index '${indexKey}' is stuck, will retry...`));
|
67
75
|
return false;
|
68
76
|
|
69
|
-
case 'processing':
|
70
|
-
// Continue waiting
|
71
|
-
break;
|
77
|
+
case 'processing':
|
78
|
+
// Continue waiting
|
79
|
+
break;
|
72
80
|
|
73
81
|
case 'deleting':
|
74
82
|
console.log(chalk.yellow(`Index '${indexKey}' is being deleted`));
|
@@ -79,12 +87,12 @@ const waitForIndexAvailable = async (
|
|
79
87
|
break;
|
80
88
|
}
|
81
89
|
|
82
|
-
await delay(checkInterval);
|
83
|
-
} catch (error) {
|
84
|
-
console.log(chalk.red(`Error checking index status: ${error}`));
|
85
|
-
return false;
|
86
|
-
}
|
87
|
-
}
|
90
|
+
await delay(checkInterval);
|
91
|
+
} catch (error) {
|
92
|
+
console.log(chalk.red(`Error checking index status: ${error}`));
|
93
|
+
return false;
|
94
|
+
}
|
95
|
+
}
|
88
96
|
|
89
97
|
// Timeout reached
|
90
98
|
console.log(chalk.yellow(`⏰ Timeout waiting for index '${indexKey}' (${maxWaitTime}ms)`));
|