appwrite-utils-cli 1.5.2 → 1.6.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/CHANGELOG.md +199 -0
- package/README.md +251 -29
- package/dist/adapters/AdapterFactory.d.ts +10 -3
- package/dist/adapters/AdapterFactory.js +213 -17
- package/dist/adapters/TablesDBAdapter.js +60 -17
- package/dist/backups/operations/bucketBackup.d.ts +19 -0
- package/dist/backups/operations/bucketBackup.js +197 -0
- package/dist/backups/operations/collectionBackup.d.ts +30 -0
- package/dist/backups/operations/collectionBackup.js +201 -0
- package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
- package/dist/backups/operations/comprehensiveBackup.js +238 -0
- package/dist/backups/schemas/bucketManifest.d.ts +93 -0
- package/dist/backups/schemas/bucketManifest.js +33 -0
- package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
- package/dist/backups/schemas/comprehensiveManifest.js +32 -0
- package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
- package/dist/backups/tracking/centralizedTracking.js +274 -0
- package/dist/cli/commands/configCommands.d.ts +8 -0
- package/dist/cli/commands/configCommands.js +160 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +478 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +289 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +134 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +5 -4
- package/dist/collections/attributes.js +539 -246
- package/dist/collections/indexes.js +39 -37
- package/dist/collections/methods.d.ts +2 -16
- package/dist/collections/methods.js +90 -538
- package/dist/collections/transferOperations.d.ts +7 -0
- package/dist/collections/transferOperations.js +331 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +328 -0
- package/dist/config/configMigration.d.ts +87 -0
- package/dist/config/configMigration.js +390 -0
- package/dist/config/configValidation.d.ts +66 -0
- package/dist/config/configValidation.js +358 -0
- package/dist/config/yamlConfig.d.ts +455 -1
- package/dist/config/yamlConfig.js +145 -52
- package/dist/databases/methods.js +3 -2
- package/dist/databases/setup.d.ts +1 -2
- package/dist/databases/setup.js +9 -87
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +269 -0
- package/dist/functions/deployments.js +11 -10
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -4
- package/dist/init.js +9 -9
- package/dist/interactiveCLI.d.ts +8 -17
- package/dist/interactiveCLI.js +181 -1172
- package/dist/main.js +364 -21
- package/dist/migrations/afterImportActions.js +22 -30
- package/dist/migrations/appwriteToX.js +71 -25
- package/dist/migrations/dataLoader.js +35 -26
- package/dist/migrations/importController.js +29 -30
- package/dist/migrations/relationships.js +13 -12
- package/dist/migrations/services/ImportOrchestrator.js +16 -19
- package/dist/migrations/transfer.js +46 -46
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
- package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
- package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
- package/dist/migrations/yaml/generateImportSchemas.js +736 -7
- package/dist/schemas/authUser.d.ts +1 -1
- package/dist/setupController.js +3 -2
- package/dist/shared/backupMetadataSchema.d.ts +94 -0
- package/dist/shared/backupMetadataSchema.js +38 -0
- package/dist/shared/backupTracking.d.ts +18 -0
- package/dist/shared/backupTracking.js +176 -0
- package/dist/shared/confirmationDialogs.js +15 -15
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.js +20 -19
- package/dist/shared/indexManager.js +12 -11
- package/dist/shared/jsonSchemaGenerator.js +10 -26
- package/dist/shared/logging.d.ts +51 -0
- package/dist/shared/logging.js +70 -0
- package/dist/shared/messageFormatter.d.ts +2 -0
- package/dist/shared/messageFormatter.js +10 -0
- package/dist/shared/migrationHelpers.d.ts +6 -16
- package/dist/shared/migrationHelpers.js +24 -21
- package/dist/shared/operationLogger.d.ts +8 -1
- package/dist/shared/operationLogger.js +11 -24
- package/dist/shared/operationQueue.d.ts +28 -1
- package/dist/shared/operationQueue.js +268 -66
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +286 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +19 -1
- package/dist/shared/schemaGenerator.js +56 -75
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +16 -2
- package/dist/storage/methods.js +98 -14
- package/dist/users/methods.js +9 -8
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +430 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +17 -8
- package/dist/utils/getClientFromConfig.js +162 -17
- package/dist/utils/helperFunctions.d.ts +16 -2
- package/dist/utils/helperFunctions.js +19 -5
- package/dist/utils/loadConfigs.d.ts +34 -9
- package/dist/utils/loadConfigs.js +236 -316
- package/dist/utils/pathResolvers.d.ts +53 -0
- package/dist/utils/pathResolvers.js +72 -0
- package/dist/utils/projectConfig.d.ts +119 -0
- package/dist/utils/projectConfig.js +171 -0
- package/dist/utils/retryFailedPromises.js +4 -2
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/sessionPreservationExample.d.ts +1666 -0
- package/dist/utils/sessionPreservationExample.js +101 -0
- package/dist/utils/setupFiles.js +301 -41
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/versionDetection.js +145 -9
- package/dist/utils/yamlConverter.d.ts +53 -3
- package/dist/utils/yamlConverter.js +232 -13
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +263 -0
- package/dist/utilsController.d.ts +36 -3
- package/dist/utilsController.js +186 -56
- package/package.json +12 -2
- package/src/adapters/AdapterFactory.ts +263 -35
- package/src/adapters/TablesDBAdapter.ts +225 -36
- package/src/backups/operations/bucketBackup.ts +277 -0
- package/src/backups/operations/collectionBackup.ts +310 -0
- package/src/backups/operations/comprehensiveBackup.ts +342 -0
- package/src/backups/schemas/bucketManifest.ts +78 -0
- package/src/backups/schemas/comprehensiveManifest.ts +76 -0
- package/src/backups/tracking/centralizedTracking.ts +352 -0
- package/src/cli/commands/configCommands.ts +194 -0
- package/src/cli/commands/databaseCommands.ts +635 -0
- package/src/cli/commands/functionCommands.ts +379 -0
- package/src/cli/commands/schemaCommands.ts +163 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +900 -621
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +116 -114
- package/src/collections/methods.ts +295 -968
- package/src/collections/transferOperations.ts +516 -0
- package/src/collections/wipeOperations.ts +501 -0
- package/src/config/README.md +274 -0
- package/src/config/configMigration.ts +575 -0
- package/src/config/configValidation.ts +445 -0
- package/src/config/yamlConfig.ts +168 -55
- package/src/databases/methods.ts +3 -2
- package/src/databases/setup.ts +11 -138
- package/src/examples/yamlTerminologyExample.ts +341 -0
- package/src/functions/deployments.ts +14 -12
- package/src/functions/methods.ts +11 -11
- package/src/functions/templates/hono-typescript/README.md +286 -0
- package/src/functions/templates/hono-typescript/package.json +26 -0
- package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/src/functions/templates/hono-typescript/src/app.ts +180 -0
- package/src/functions/templates/hono-typescript/src/context.ts +103 -0
- package/src/functions/templates/hono-typescript/src/index.ts +54 -0
- package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/src/functions/templates/typescript-node/package.json +2 -1
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +18 -12
- package/src/functions/templates/uv/pyproject.toml +1 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +35 -5
- package/src/init.ts +9 -11
- package/src/interactiveCLI.ts +278 -1596
- package/src/main.ts +418 -24
- package/src/migrations/afterImportActions.ts +71 -44
- package/src/migrations/appwriteToX.ts +100 -34
- package/src/migrations/dataLoader.ts +48 -34
- package/src/migrations/importController.ts +44 -39
- package/src/migrations/relationships.ts +28 -18
- package/src/migrations/services/ImportOrchestrator.ts +24 -27
- package/src/migrations/transfer.ts +159 -121
- package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
- package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
- package/src/migrations/yaml/generateImportSchemas.ts +751 -12
- package/src/setupController.ts +3 -2
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +19 -19
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +21 -20
- package/src/shared/indexManager.ts +12 -11
- package/src/shared/jsonSchemaGenerator.ts +38 -52
- package/src/shared/logging.ts +75 -0
- package/src/shared/messageFormatter.ts +14 -1
- package/src/shared/migrationHelpers.ts +45 -38
- package/src/shared/operationLogger.ts +11 -36
- package/src/shared/operationQueue.ts +322 -93
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +179 -219
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +131 -34
- package/src/users/methods.ts +11 -9
- package/src/utils/configDiscovery.ts +502 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +205 -22
- package/src/utils/helperFunctions.ts +23 -5
- package/src/utils/loadConfigs.ts +313 -345
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +4 -2
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +322 -54
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/versionDetection.ts +218 -64
- package/src/utils/yamlConverter.ts +296 -13
- package/src/utils/yamlLoader.ts +364 -0
- package/src/utilsController.ts +314 -110
- package/tests/README.md +497 -0
- package/tests/adapters/AdapterFactory.test.ts +277 -0
- package/tests/integration/syncOperations.test.ts +463 -0
- package/tests/jest.config.js +25 -0
- package/tests/migration/configMigration.test.ts +546 -0
- package/tests/setup.ts +62 -0
- package/tests/testUtils.ts +340 -0
- package/tests/utils/loadConfigs.test.ts +350 -0
- package/tests/validation/configValidation.test.ts +412 -0
- package/src/utils/schemaStrings.ts +0 -517
@@ -4,7 +4,6 @@ import {
|
|
4
4
|
Query,
|
5
5
|
ID,
|
6
6
|
type Models,
|
7
|
-
Client,
|
8
7
|
Compression,
|
9
8
|
} from "node-appwrite";
|
10
9
|
import { InputFile } from "node-appwrite/file";
|
@@ -17,24 +16,16 @@ import {
|
|
17
16
|
type AfterImportActions,
|
18
17
|
type AppwriteConfig,
|
19
18
|
} from "appwrite-utils";
|
19
|
+
import { getClientFromConfig } from "../utils/getClientFromConfig.js";
|
20
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
20
21
|
|
21
22
|
export const getDatabaseFromConfig = (config: AppwriteConfig) => {
|
22
|
-
|
23
|
-
config.appwriteClient = new Client()
|
24
|
-
.setEndpoint(config.appwriteEndpoint)
|
25
|
-
.setProject(config.appwriteProject)
|
26
|
-
.setKey(config.appwriteKey);
|
27
|
-
}
|
23
|
+
getClientFromConfig(config); // Sets config.appwriteClient if missing
|
28
24
|
return new Databases(config.appwriteClient!);
|
29
25
|
};
|
30
26
|
|
31
27
|
export const getStorageFromConfig = (config: AppwriteConfig) => {
|
32
|
-
|
33
|
-
config.appwriteClient = new Client()
|
34
|
-
.setEndpoint(config.appwriteEndpoint)
|
35
|
-
.setProject(config.appwriteProject)
|
36
|
-
.setKey(config.appwriteKey);
|
37
|
-
}
|
28
|
+
getClientFromConfig(config); // Sets config.appwriteClient if missing
|
38
29
|
return new Storage(config.appwriteClient!);
|
39
30
|
};
|
40
31
|
|
@@ -52,7 +43,11 @@ export const afterImportActions = {
|
|
52
43
|
async () => await db.updateDocument(dbId, collId, docId, data)
|
53
44
|
);
|
54
45
|
} catch (error) {
|
55
|
-
|
46
|
+
MessageFormatter.error(
|
47
|
+
"Error updating document",
|
48
|
+
error instanceof Error ? error : new Error(String(error)),
|
49
|
+
{ prefix: "Import" }
|
50
|
+
);
|
56
51
|
}
|
57
52
|
},
|
58
53
|
checkAndUpdateFieldInDocument: async (
|
@@ -78,7 +73,11 @@ export const afterImportActions = {
|
|
78
73
|
);
|
79
74
|
}
|
80
75
|
} catch (error) {
|
81
|
-
|
76
|
+
MessageFormatter.error(
|
77
|
+
"Error updating document",
|
78
|
+
error instanceof Error ? error : new Error(String(error)),
|
79
|
+
{ prefix: "Import" }
|
80
|
+
);
|
82
81
|
}
|
83
82
|
},
|
84
83
|
setFieldFromOtherCollectionDocument: async (
|
@@ -133,13 +132,15 @@ export const afterImportActions = {
|
|
133
132
|
);
|
134
133
|
}
|
135
134
|
|
136
|
-
|
137
|
-
`Field ${fieldName} updated successfully in document ${docId}
|
135
|
+
MessageFormatter.success(
|
136
|
+
`Field ${fieldName} updated successfully in document ${docId}`,
|
137
|
+
{ prefix: "Import" }
|
138
138
|
);
|
139
139
|
} catch (error) {
|
140
|
-
|
141
|
-
"Error setting field from other collection document
|
142
|
-
error
|
140
|
+
MessageFormatter.error(
|
141
|
+
"Error setting field from other collection document",
|
142
|
+
error instanceof Error ? error : new Error(String(error)),
|
143
|
+
{ prefix: "Import" }
|
143
144
|
);
|
144
145
|
}
|
145
146
|
},
|
@@ -239,14 +240,16 @@ export const afterImportActions = {
|
|
239
240
|
)
|
240
241
|
);
|
241
242
|
|
242
|
-
|
243
|
-
`Field ${fieldName} updated successfully in document ${docId} with ${documentIds.length} document IDs
|
243
|
+
MessageFormatter.success(
|
244
|
+
`Field ${fieldName} updated successfully in document ${docId} with ${documentIds.length} document IDs`,
|
245
|
+
{ prefix: "Import" }
|
244
246
|
);
|
245
247
|
}
|
246
248
|
} catch (error) {
|
247
|
-
|
248
|
-
"Error setting field from other collection documents
|
249
|
-
error
|
249
|
+
MessageFormatter.error(
|
250
|
+
"Error setting field from other collection documents",
|
251
|
+
error instanceof Error ? error : new Error(String(error)),
|
252
|
+
{ prefix: "Import" }
|
250
253
|
);
|
251
254
|
}
|
252
255
|
},
|
@@ -339,14 +342,16 @@ export const afterImportActions = {
|
|
339
342
|
)
|
340
343
|
);
|
341
344
|
|
342
|
-
|
343
|
-
`Field ${fieldName} updated successfully in document ${docId} with values from field ${targetField}
|
345
|
+
MessageFormatter.success(
|
346
|
+
`Field ${fieldName} updated successfully in document ${docId} with values from field ${targetField}`,
|
347
|
+
{ prefix: "Import" }
|
344
348
|
);
|
345
349
|
}
|
346
350
|
} catch (error) {
|
347
|
-
|
348
|
-
"Error setting field from other collection documents
|
349
|
-
error
|
351
|
+
MessageFormatter.error(
|
352
|
+
"Error setting field from other collection documents",
|
353
|
+
error instanceof Error ? error : new Error(String(error)),
|
354
|
+
{ prefix: "Import" }
|
350
355
|
);
|
351
356
|
}
|
352
357
|
},
|
@@ -410,7 +415,11 @@ export const afterImportActions = {
|
|
410
415
|
);
|
411
416
|
}
|
412
417
|
} catch (error) {
|
413
|
-
|
418
|
+
MessageFormatter.error(
|
419
|
+
"Error creating or getting bucket",
|
420
|
+
error instanceof Error ? error : new Error(String(error)),
|
421
|
+
{ prefix: "Import" }
|
422
|
+
);
|
414
423
|
}
|
415
424
|
},
|
416
425
|
createFileAndUpdateField: async (
|
@@ -435,16 +444,19 @@ export const afterImportActions = {
|
|
435
444
|
// `Processing field ${fieldName} in collection ${collId} for document ${docId} in database ${dbId} in bucket ${bucketId} with path ${filePath} and name ${fileName}...`
|
436
445
|
// );
|
437
446
|
if (filePath.length === 0 || fileName.length === 0) {
|
438
|
-
|
439
|
-
`File path or name is empty for field ${fieldName} in collection ${collId}, skipping
|
447
|
+
MessageFormatter.error(
|
448
|
+
`File path or name is empty for field ${fieldName} in collection ${collId}, skipping...`,
|
449
|
+
undefined,
|
450
|
+
{ prefix: "Import" }
|
440
451
|
);
|
441
452
|
return;
|
442
453
|
}
|
443
454
|
|
444
455
|
let isArray = false;
|
445
456
|
if (!attribute) {
|
446
|
-
|
447
|
-
`Field ${fieldName} not found in collection ${collId}, weird, skipping
|
457
|
+
MessageFormatter.warning(
|
458
|
+
`Field ${fieldName} not found in collection ${collId}, weird, skipping...`,
|
459
|
+
{ prefix: "Import" }
|
448
460
|
);
|
449
461
|
return;
|
450
462
|
} else if (attribute.array === true) {
|
@@ -478,8 +490,10 @@ export const afterImportActions = {
|
|
478
490
|
async () => await fetch(filePath)
|
479
491
|
);
|
480
492
|
if (!response.ok)
|
481
|
-
|
482
|
-
`Failed to fetch ${filePath}: ${response.statusText} for document ${docId} with field ${fieldName}
|
493
|
+
MessageFormatter.error(
|
494
|
+
`Failed to fetch ${filePath}: ${response.statusText} for document ${docId} with field ${fieldName}`,
|
495
|
+
undefined,
|
496
|
+
{ prefix: "Import" }
|
483
497
|
);
|
484
498
|
|
485
499
|
// Use arrayBuffer if buffer is not available
|
@@ -495,7 +509,10 @@ export const afterImportActions = {
|
|
495
509
|
async () => await storage.createFile(bucketId, ID.unique(), inputFile)
|
496
510
|
);
|
497
511
|
|
498
|
-
|
512
|
+
MessageFormatter.success(
|
513
|
+
`Created file from URL: ${file.$id}`,
|
514
|
+
{ prefix: "Import" }
|
515
|
+
);
|
499
516
|
|
500
517
|
// After uploading, adjust the updateData based on whether the field is an array or not
|
501
518
|
if (isArray) {
|
@@ -516,8 +533,10 @@ export const afterImportActions = {
|
|
516
533
|
const files = fs.readdirSync(filePath);
|
517
534
|
const fileFullName = files.find((file) => file.includes(fileName));
|
518
535
|
if (!fileFullName) {
|
519
|
-
|
520
|
-
`File starting with '${fileName}' not found in '${filePath}'
|
536
|
+
MessageFormatter.error(
|
537
|
+
`File starting with '${fileName}' not found in '${filePath}'`,
|
538
|
+
undefined,
|
539
|
+
{ prefix: "Import" }
|
521
540
|
);
|
522
541
|
return;
|
523
542
|
}
|
@@ -538,15 +557,23 @@ export const afterImportActions = {
|
|
538
557
|
[fieldName]: updateData,
|
539
558
|
})
|
540
559
|
);
|
541
|
-
|
560
|
+
MessageFormatter.success(
|
561
|
+
`Created file from path: ${file.$id}`,
|
562
|
+
{ prefix: "Import" }
|
563
|
+
);
|
542
564
|
}
|
543
565
|
} catch (error) {
|
544
566
|
logger.error(
|
545
567
|
`Error creating file and updating field, params were:\ndbId: ${dbId}, collId: ${collId}, docId: ${docId}, fieldName: ${fieldName}, filePath: ${filePath}, fileName: ${fileName}\n\nError: ${error}`
|
546
568
|
);
|
547
|
-
|
548
|
-
|
549
|
-
|
569
|
+
MessageFormatter.error(
|
570
|
+
"Error creating file and updating field",
|
571
|
+
error instanceof Error ? error : new Error(String(error)),
|
572
|
+
{ prefix: "Import" }
|
573
|
+
);
|
574
|
+
MessageFormatter.info(
|
575
|
+
`Params were: dbId: ${dbId}, collId: ${collId}, docId: ${docId}, fieldName: ${fieldName}, filePath: ${filePath}, fileName: ${fileName}`,
|
576
|
+
{ prefix: "Import" }
|
550
577
|
);
|
551
578
|
}
|
552
579
|
},
|
@@ -28,6 +28,7 @@ import {
|
|
28
28
|
import { getDatabaseFromConfig } from "./afterImportActions.js";
|
29
29
|
import { listBuckets } from "../storage/methods.js";
|
30
30
|
import { listFunctions, listFunctionDeployments } from "../functions/methods.js";
|
31
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
31
32
|
|
32
33
|
export class AppwriteToX {
|
33
34
|
config: AppwriteConfig;
|
@@ -96,19 +97,62 @@ export class AppwriteToX {
|
|
96
97
|
async appwriteSync(config: AppwriteConfig, databases?: Models.Database[]) {
|
97
98
|
const db = getDatabaseFromConfig(config);
|
98
99
|
if (!databases) {
|
99
|
-
|
100
|
+
try {
|
101
|
+
MessageFormatter.info("Fetching remote databases...", { prefix: "Migration" });
|
102
|
+
databases = await fetchAllDatabases(db);
|
103
|
+
MessageFormatter.info(`Found ${databases.length} remote databases`, { prefix: "Migration" });
|
104
|
+
} catch (error) {
|
105
|
+
MessageFormatter.error(
|
106
|
+
"Failed to fetch remote databases",
|
107
|
+
error instanceof Error ? error : new Error(String(error)),
|
108
|
+
{ prefix: "Migration" }
|
109
|
+
);
|
110
|
+
throw new Error(`Database fetch failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
111
|
+
}
|
100
112
|
}
|
101
113
|
let updatedConfig: AppwriteConfig = { ...config };
|
102
114
|
|
115
|
+
// Initialize databases array if it doesn't exist
|
116
|
+
if (!updatedConfig.databases) {
|
117
|
+
updatedConfig.databases = [];
|
118
|
+
}
|
119
|
+
|
120
|
+
// Sync remote databases to local config - add missing ones
|
121
|
+
MessageFormatter.info(`Syncing ${databases.length} remote databases with local config...`, { prefix: "Migration" });
|
122
|
+
let addedCount = 0;
|
123
|
+
let updatedCount = 0;
|
124
|
+
|
125
|
+
for (const remoteDb of databases) {
|
126
|
+
// Check if this database already exists in the config
|
127
|
+
const existingDbIndex = updatedConfig.databases.findIndex(
|
128
|
+
(localDb) => localDb.$id === remoteDb.$id
|
129
|
+
);
|
130
|
+
|
131
|
+
if (existingDbIndex === -1) {
|
132
|
+
// Database doesn't exist locally, add it
|
133
|
+
MessageFormatter.success(`Adding new database to config: ${remoteDb.name} (${remoteDb.$id})`, { prefix: "Migration" });
|
134
|
+
updatedConfig.databases.push({
|
135
|
+
$id: remoteDb.$id,
|
136
|
+
name: remoteDb.name,
|
137
|
+
});
|
138
|
+
addedCount++;
|
139
|
+
} else {
|
140
|
+
// Database exists, update name if different
|
141
|
+
if (updatedConfig.databases[existingDbIndex].name !== remoteDb.name) {
|
142
|
+
MessageFormatter.info(`Updating database name: ${updatedConfig.databases[existingDbIndex].name} -> ${remoteDb.name}`, { prefix: "Migration" });
|
143
|
+
updatedConfig.databases[existingDbIndex].name = remoteDb.name;
|
144
|
+
updatedCount++;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
MessageFormatter.success(`Database sync summary: ${addedCount} added, ${updatedCount} updated, ${updatedConfig.databases.length} total`, { prefix: "Migration" });
|
150
|
+
|
103
151
|
// Fetch all buckets
|
104
152
|
const allBuckets = await listBuckets(this.storage);
|
105
153
|
|
106
154
|
// Loop through each database
|
107
155
|
for (const database of databases) {
|
108
|
-
if (!this.config.useMigrations && database.name.toLowerCase() === "migrations") {
|
109
|
-
continue;
|
110
|
-
}
|
111
|
-
|
112
156
|
// Match bucket to database
|
113
157
|
const matchedBucket = allBuckets.buckets.find((bucket) =>
|
114
158
|
bucket.$id.toLowerCase().includes(database.$id.toLowerCase())
|
@@ -139,7 +183,7 @@ export class AppwriteToX {
|
|
139
183
|
updatedConfig.collections = [];
|
140
184
|
}
|
141
185
|
for (const collection of collections) {
|
142
|
-
|
186
|
+
MessageFormatter.processing(`Processing collection: ${collection.name}`, { prefix: "Migration" });
|
143
187
|
const existingCollectionIndex = updatedConfig.collections.findIndex(
|
144
188
|
(c) => c.name === collection.name
|
145
189
|
);
|
@@ -161,23 +205,30 @@ export class AppwriteToX {
|
|
161
205
|
attribute.type === "relationship" &&
|
162
206
|
attribute.relatedCollection
|
163
207
|
) {
|
164
|
-
|
165
|
-
`Fetching related collection for ID: ${attribute.relatedCollection}
|
208
|
+
MessageFormatter.info(
|
209
|
+
`Fetching related collection for ID: ${attribute.relatedCollection}`,
|
210
|
+
{ prefix: "Migration" }
|
166
211
|
);
|
167
212
|
try {
|
168
213
|
const relatedCollectionPulled = await db.getCollection(
|
169
214
|
database.$id,
|
170
215
|
attribute.relatedCollection
|
171
216
|
);
|
172
|
-
|
173
|
-
`Fetched Collection Name: ${relatedCollectionPulled.name}
|
217
|
+
MessageFormatter.info(
|
218
|
+
`Fetched Collection Name: ${relatedCollectionPulled.name}`,
|
219
|
+
{ prefix: "Migration" }
|
174
220
|
);
|
175
221
|
attribute.relatedCollection = relatedCollectionPulled.name;
|
176
|
-
|
177
|
-
`Updated attribute.relatedCollection to: ${attribute.relatedCollection}
|
222
|
+
MessageFormatter.info(
|
223
|
+
`Updated attribute.relatedCollection to: ${attribute.relatedCollection}`,
|
224
|
+
{ prefix: "Migration" }
|
178
225
|
);
|
179
226
|
} catch (error) {
|
180
|
-
|
227
|
+
MessageFormatter.error(
|
228
|
+
"Error fetching related collection",
|
229
|
+
error instanceof Error ? error : new Error(String(error)),
|
230
|
+
{ prefix: "Migration" }
|
231
|
+
);
|
181
232
|
}
|
182
233
|
}
|
183
234
|
}
|
@@ -215,8 +266,9 @@ export class AppwriteToX {
|
|
215
266
|
}
|
216
267
|
}
|
217
268
|
|
218
|
-
|
219
|
-
`Processed ${collections.length} collections in ${database.name}
|
269
|
+
MessageFormatter.success(
|
270
|
+
`Processed ${collections.length} collections in ${database.name}`,
|
271
|
+
{ prefix: "Migration" }
|
220
272
|
);
|
221
273
|
}
|
222
274
|
// Add unmatched buckets as global buckets
|
@@ -260,32 +312,46 @@ export class AppwriteToX {
|
|
260
312
|
})
|
261
313
|
);
|
262
314
|
|
263
|
-
// Make sure to update the config with all changes
|
315
|
+
// Make sure to update the config with all changes including databases
|
264
316
|
updatedConfig.functions = this.updatedConfig.functions;
|
265
317
|
this.updatedConfig = updatedConfig;
|
318
|
+
MessageFormatter.success(`Sync completed - ${updatedConfig.databases.length} databases, ${updatedConfig.collections?.length || 0} collections, ${updatedConfig.buckets?.length || 0} buckets, ${updatedConfig.functions?.length || 0} functions`, { prefix: "Migration" });
|
266
319
|
}
|
267
320
|
|
268
321
|
async toSchemas(databases?: Models.Database[]) {
|
269
|
-
|
270
|
-
|
271
|
-
this.
|
272
|
-
this.appwriteFolderPath
|
273
|
-
);
|
322
|
+
try {
|
323
|
+
MessageFormatter.info("Starting sync-from-Appwrite process...", { prefix: "Migration" });
|
324
|
+
await this.appwriteSync(this.config, databases);
|
274
325
|
|
275
|
-
|
276
|
-
|
277
|
-
|
326
|
+
const generator = new SchemaGenerator(
|
327
|
+
this.updatedConfig,
|
328
|
+
this.appwriteFolderPath
|
329
|
+
);
|
330
|
+
|
331
|
+
// Check if this is a YAML-based project
|
332
|
+
const yamlConfigPath = findYamlConfig(this.appwriteFolderPath);
|
333
|
+
const isYamlProject = !!yamlConfigPath;
|
278
334
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
335
|
+
if (isYamlProject) {
|
336
|
+
MessageFormatter.info("Detected YAML configuration - generating YAML collection definitions", { prefix: "Migration" });
|
337
|
+
generator.updateYamlCollections();
|
338
|
+
await generator.updateConfig(this.updatedConfig, true);
|
339
|
+
} else {
|
340
|
+
MessageFormatter.info("Generating TypeScript collection definitions", { prefix: "Migration" });
|
341
|
+
generator.updateTsSchemas();
|
342
|
+
await generator.updateConfig(this.updatedConfig, false);
|
343
|
+
}
|
344
|
+
|
345
|
+
MessageFormatter.info("Generating Zod schemas from synced collections...", { prefix: "Migration" });
|
346
|
+
generator.generateSchemas();
|
347
|
+
MessageFormatter.success("Sync-from-Appwrite process completed successfully", { prefix: "Migration" });
|
348
|
+
} catch (error) {
|
349
|
+
MessageFormatter.error(
|
350
|
+
"Error during sync-from-Appwrite process",
|
351
|
+
error instanceof Error ? error : new Error(String(error)),
|
352
|
+
{ prefix: "Migration" }
|
353
|
+
);
|
354
|
+
throw error;
|
287
355
|
}
|
288
|
-
|
289
|
-
generator.generateSchemas();
|
290
356
|
}
|
291
357
|
}
|
@@ -21,9 +21,11 @@ import { ID, Users, type Databases } from "node-appwrite";
|
|
21
21
|
import { logger } from "../shared/logging.js";
|
22
22
|
import { findOrCreateOperation, updateOperation } from "../shared/migrationHelpers.js";
|
23
23
|
import { AuthUserCreateSchema } from "../schemas/authUser.js";
|
24
|
+
import { LegacyAdapter } from "../adapters/LegacyAdapter.js";
|
24
25
|
import { UsersController } from "../users/methods.js";
|
25
26
|
import { finalizeByAttributeMap } from "../utils/helperFunctions.js";
|
26
27
|
import { isEmpty } from "es-toolkit/compat";
|
28
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
27
29
|
|
28
30
|
// Define a schema for the structure of collection import data using Zod for validation
|
29
31
|
export const CollectionImportDataSchema = z.object({
|
@@ -185,9 +187,9 @@ export class DataLoader {
|
|
185
187
|
loadData(importDef: ImportDef): any[] {
|
186
188
|
// Simply join appwriteFolderPath with the importDef.filePath
|
187
189
|
const filePath = path.resolve(this.appwriteFolderPath, importDef.filePath);
|
188
|
-
|
190
|
+
MessageFormatter.info(`Loading data from: ${filePath}`, { prefix: "Data" });
|
189
191
|
if (!fs.existsSync(filePath)) {
|
190
|
-
|
192
|
+
MessageFormatter.error(`File not found: ${filePath}`, undefined, { prefix: "Data" });
|
191
193
|
return [];
|
192
194
|
}
|
193
195
|
|
@@ -197,7 +199,7 @@ export class DataLoader {
|
|
197
199
|
? JSON.parse(rawData)[importDef.basePath]
|
198
200
|
: JSON.parse(rawData);
|
199
201
|
|
200
|
-
|
202
|
+
MessageFormatter.success(`Loaded ${parsedData?.length || 0} items from ${filePath}`, { prefix: "Data" });
|
201
203
|
return parsedData;
|
202
204
|
}
|
203
205
|
|
@@ -313,10 +315,12 @@ export class DataLoader {
|
|
313
315
|
collection.$id = collectionExists.$id;
|
314
316
|
this.config.collections[index] = collectionConfig;
|
315
317
|
// Find or create an import operation for the collection
|
318
|
+
const adapter = new LegacyAdapter(this.database);
|
316
319
|
const collectionImportOperation = await findOrCreateOperation(
|
317
|
-
|
318
|
-
|
319
|
-
"importData"
|
320
|
+
adapter,
|
321
|
+
dbId,
|
322
|
+
"importData",
|
323
|
+
collection.$id!
|
320
324
|
);
|
321
325
|
// Store the operation ID in the map
|
322
326
|
this.collectionImportOperations.set(
|
@@ -373,13 +377,14 @@ export class DataLoader {
|
|
373
377
|
|
374
378
|
// Main method to start the data loading process for a given database ID
|
375
379
|
async start(dbId: string) {
|
376
|
-
|
377
|
-
|
378
|
-
|
380
|
+
MessageFormatter.divider();
|
381
|
+
MessageFormatter.info(`Starting data setup for database: ${dbId}`, { prefix: "Data" });
|
382
|
+
MessageFormatter.divider();
|
379
383
|
await this.setupMaps(dbId);
|
380
384
|
const allUsers = await this.getAllUsers();
|
381
|
-
|
382
|
-
`Fetched ${allUsers.length} users, waiting a few seconds to let the program catch up
|
385
|
+
MessageFormatter.info(
|
386
|
+
`Fetched ${allUsers.length} users, waiting a few seconds to let the program catch up...`,
|
387
|
+
{ prefix: "Data" }
|
383
388
|
);
|
384
389
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
385
390
|
// Iterate over the configured databases to find the matching one
|
@@ -431,17 +436,17 @@ export class DataLoader {
|
|
431
436
|
this.prepareUpdateData(db, collection, updateDef);
|
432
437
|
}
|
433
438
|
}
|
434
|
-
|
439
|
+
MessageFormatter.info("Running update references", { prefix: "Data" });
|
435
440
|
// this.dealWithMergedUsers();
|
436
441
|
this.updateOldReferencesForNew();
|
437
|
-
|
442
|
+
MessageFormatter.success("Done running update references", { prefix: "Data" });
|
438
443
|
}
|
439
444
|
// for (const collection of this.config.collections) {
|
440
445
|
// this.resolveDataItemRelationships(collection);
|
441
446
|
// }
|
442
|
-
|
443
|
-
|
444
|
-
|
447
|
+
MessageFormatter.divider();
|
448
|
+
MessageFormatter.success(`Data setup for database: ${dbId} completed`, { prefix: "Data" });
|
449
|
+
MessageFormatter.divider();
|
445
450
|
if (this.shouldWriteFile) {
|
446
451
|
this.writeMapsToJsonFile();
|
447
452
|
}
|
@@ -528,8 +533,9 @@ export class DataLoader {
|
|
528
533
|
|
529
534
|
if (!collectionData || !collectionData.data) continue;
|
530
535
|
|
531
|
-
|
532
|
-
`Updating references for collection: ${collectionConfig.name}
|
536
|
+
MessageFormatter.processing(
|
537
|
+
`Updating references for collection: ${collectionConfig.name}`,
|
538
|
+
{ prefix: "Data" }
|
533
539
|
);
|
534
540
|
|
535
541
|
let needsUpdate = false;
|
@@ -728,10 +734,10 @@ export class DataLoader {
|
|
728
734
|
const outputFile = path.join(outputDir, fileName);
|
729
735
|
fs.writeFile(outputFile, JSON.stringify(data, null, 2), "utf8", (err) => {
|
730
736
|
if (err) {
|
731
|
-
|
737
|
+
MessageFormatter.error(`Error writing data to ${fileName}`, err instanceof Error ? err : new Error(String(err)), { prefix: "Data" });
|
732
738
|
return;
|
733
739
|
}
|
734
|
-
|
740
|
+
MessageFormatter.success(`Data successfully written to ${fileName}`, { prefix: "Data" });
|
735
741
|
});
|
736
742
|
};
|
737
743
|
|
@@ -951,11 +957,13 @@ export class DataLoader {
|
|
951
957
|
this.oldIdToNewIdPerCollectionMap
|
952
958
|
.set(this.getCollectionKey(collection.name), oldIdToNewIdMap)
|
953
959
|
.get(this.getCollectionKey(collection.name));
|
960
|
+
const adapter = new LegacyAdapter(this.database);
|
954
961
|
if (!operationId) {
|
955
962
|
const collectionImportOperation = await findOrCreateOperation(
|
956
|
-
|
957
|
-
|
958
|
-
"importData"
|
963
|
+
adapter,
|
964
|
+
db.$id,
|
965
|
+
"importData",
|
966
|
+
collection.$id!
|
959
967
|
);
|
960
968
|
// Store the operation ID in the map
|
961
969
|
this.collectionImportOperations.set(
|
@@ -964,10 +972,12 @@ export class DataLoader {
|
|
964
972
|
);
|
965
973
|
operationId = collectionImportOperation.$id;
|
966
974
|
}
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
975
|
+
if (operationId) {
|
976
|
+
await updateOperation(adapter, db.$id, operationId, {
|
977
|
+
status: "ready",
|
978
|
+
total: rawData.length,
|
979
|
+
});
|
980
|
+
}
|
971
981
|
// Retrieve the current user data and the current collection data from the import map
|
972
982
|
const currentUserData = this.importMap.get(this.getCollectionKey("users"));
|
973
983
|
const currentData = this.importMap.get(
|
@@ -1178,11 +1188,13 @@ export class DataLoader {
|
|
1178
1188
|
let operationId = this.collectionImportOperations.get(
|
1179
1189
|
this.getCollectionKey(collection.name)
|
1180
1190
|
);
|
1191
|
+
const adapter = new LegacyAdapter(this.database);
|
1181
1192
|
if (!operationId) {
|
1182
1193
|
const collectionImportOperation = await findOrCreateOperation(
|
1183
|
-
|
1184
|
-
|
1185
|
-
"importData"
|
1194
|
+
adapter,
|
1195
|
+
db.$id,
|
1196
|
+
"importData",
|
1197
|
+
collection.$id!
|
1186
1198
|
);
|
1187
1199
|
// Store the operation ID in the map
|
1188
1200
|
this.collectionImportOperations.set(
|
@@ -1191,10 +1203,12 @@ export class DataLoader {
|
|
1191
1203
|
);
|
1192
1204
|
operationId = collectionImportOperation.$id;
|
1193
1205
|
}
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1206
|
+
if (operationId) {
|
1207
|
+
await updateOperation(adapter, db.$id, operationId, {
|
1208
|
+
status: "ready",
|
1209
|
+
total: rawData.length,
|
1210
|
+
});
|
1211
|
+
}
|
1198
1212
|
// Initialize a new map for old ID to new ID mappings
|
1199
1213
|
const oldIdToNewIdMapNew = new Map<string, string>();
|
1200
1214
|
// Retrieve or initialize the collection-specific old ID to new ID map
|