appwrite-utils-cli 1.5.2 → 1.6.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.
- 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 +479 -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 +209 -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 +274 -1563
- 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
@@ -0,0 +1,384 @@
|
|
1
|
+
import inquirer from "inquirer";
|
2
|
+
import { Databases, Storage } from "node-appwrite";
|
3
|
+
import { MessageFormatter } from "../../shared/messageFormatter.js";
|
4
|
+
import { fetchAllDatabases } from "../../databases/methods.js";
|
5
|
+
import { listBuckets } from "../../storage/methods.js";
|
6
|
+
import { getClient } from "../../utils/getClientFromConfig.js";
|
7
|
+
import { ComprehensiveTransfer } from "../../migrations/comprehensiveTransfer.js";
|
8
|
+
export const transferCommands = {
|
9
|
+
async transferData(cli) {
|
10
|
+
if (!cli.controller.database) {
|
11
|
+
throw new Error("Database is not initialized, is the config file correct & created?");
|
12
|
+
}
|
13
|
+
const { isRemote } = await inquirer.prompt([
|
14
|
+
{
|
15
|
+
type: "confirm",
|
16
|
+
name: "isRemote",
|
17
|
+
message: "Is this a remote transfer?",
|
18
|
+
default: false,
|
19
|
+
},
|
20
|
+
]);
|
21
|
+
let sourceClient = cli.controller.database;
|
22
|
+
let targetClient;
|
23
|
+
let sourceDatabases;
|
24
|
+
let targetDatabases;
|
25
|
+
let remoteOptions;
|
26
|
+
if (isRemote) {
|
27
|
+
remoteOptions = await inquirer.prompt([
|
28
|
+
{
|
29
|
+
type: "input",
|
30
|
+
name: "transferEndpoint",
|
31
|
+
message: "Enter the remote endpoint:",
|
32
|
+
},
|
33
|
+
{
|
34
|
+
type: "input",
|
35
|
+
name: "transferProject",
|
36
|
+
message: "Enter the remote project ID:",
|
37
|
+
},
|
38
|
+
{
|
39
|
+
type: "input",
|
40
|
+
name: "transferKey",
|
41
|
+
message: "Enter the remote API key:",
|
42
|
+
},
|
43
|
+
]);
|
44
|
+
const remoteClient = getClient(remoteOptions.transferEndpoint, remoteOptions.transferProject, remoteOptions.transferKey);
|
45
|
+
targetClient = new Databases(remoteClient);
|
46
|
+
sourceDatabases = await fetchAllDatabases(sourceClient);
|
47
|
+
targetDatabases = await fetchAllDatabases(targetClient);
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
targetClient = sourceClient;
|
51
|
+
const allDatabases = await fetchAllDatabases(sourceClient);
|
52
|
+
sourceDatabases = targetDatabases = allDatabases;
|
53
|
+
}
|
54
|
+
const fromDbs = await cli.selectDatabases(sourceDatabases, "Select the source database:", false);
|
55
|
+
const fromDb = fromDbs[0];
|
56
|
+
if (!fromDb) {
|
57
|
+
throw new Error("No source database selected");
|
58
|
+
}
|
59
|
+
const availableDbs = targetDatabases.filter((db) => db.$id !== fromDb.$id);
|
60
|
+
const targetDbs = await cli.selectDatabases(availableDbs, "Select the target database:", false);
|
61
|
+
const targetDb = targetDbs[0];
|
62
|
+
if (!targetDb) {
|
63
|
+
throw new Error("No target database selected");
|
64
|
+
}
|
65
|
+
const selectedCollections = await cli.selectCollectionsAndTables(fromDb, sourceClient, "Select collections/tables to transfer:", true, false // don't prefer local for transfers
|
66
|
+
);
|
67
|
+
const { transferStorage } = await inquirer.prompt([
|
68
|
+
{
|
69
|
+
type: "confirm",
|
70
|
+
name: "transferStorage",
|
71
|
+
message: "Do you want to transfer storage as well?",
|
72
|
+
default: false,
|
73
|
+
},
|
74
|
+
]);
|
75
|
+
let sourceBucket, targetBucket;
|
76
|
+
if (transferStorage) {
|
77
|
+
const sourceStorage = new Storage(cli.controller.appwriteServer);
|
78
|
+
const targetStorage = isRemote
|
79
|
+
? new Storage(getClient(remoteOptions.transferEndpoint, remoteOptions.transferProject, remoteOptions.transferKey))
|
80
|
+
: sourceStorage;
|
81
|
+
const sourceBuckets = await listBuckets(sourceStorage);
|
82
|
+
const targetBuckets = isRemote
|
83
|
+
? await listBuckets(targetStorage)
|
84
|
+
: sourceBuckets;
|
85
|
+
const sourceBucketPicked = await cli.selectBuckets(sourceBuckets.buckets, "Select the source bucket:", false);
|
86
|
+
const targetBucketPicked = await cli.selectBuckets(targetBuckets.buckets, "Select the target bucket:", false);
|
87
|
+
sourceBucket = sourceBucketPicked[0];
|
88
|
+
targetBucket = targetBucketPicked[0];
|
89
|
+
}
|
90
|
+
let transferOptions = {
|
91
|
+
fromDb,
|
92
|
+
targetDb,
|
93
|
+
isRemote,
|
94
|
+
collections: selectedCollections.length > 0
|
95
|
+
? selectedCollections.map((c) => c.$id)
|
96
|
+
: undefined,
|
97
|
+
sourceBucket,
|
98
|
+
targetBucket,
|
99
|
+
};
|
100
|
+
if (isRemote && remoteOptions) {
|
101
|
+
transferOptions = {
|
102
|
+
...transferOptions,
|
103
|
+
...remoteOptions,
|
104
|
+
};
|
105
|
+
}
|
106
|
+
MessageFormatter.progress("Transferring data...", { prefix: "Transfer" });
|
107
|
+
await cli.controller.transferData(transferOptions);
|
108
|
+
MessageFormatter.success("Data transfer completed", { prefix: "Transfer" });
|
109
|
+
},
|
110
|
+
async comprehensiveTransfer(cli) {
|
111
|
+
MessageFormatter.info("Starting comprehensive transfer configuration...", { prefix: "Transfer" });
|
112
|
+
try {
|
113
|
+
// Initialize controller to optionally load config if available (supports both YAML and TypeScript configs)
|
114
|
+
await cli.initControllerIfNeeded();
|
115
|
+
// Extract session for potential transfer operations
|
116
|
+
const sessionConfig = cli.extractSessionFromController();
|
117
|
+
// Check if user has an appwrite config for easier setup
|
118
|
+
const hasAppwriteConfig = cli.controller?.config?.appwriteEndpoint &&
|
119
|
+
cli.controller?.config?.appwriteProject &&
|
120
|
+
cli.controller?.config?.appwriteKey;
|
121
|
+
let sourceConfig;
|
122
|
+
let targetConfig;
|
123
|
+
if (hasAppwriteConfig) {
|
124
|
+
// Offer to use existing config for source
|
125
|
+
const { useConfigForSource } = await inquirer.prompt([
|
126
|
+
{
|
127
|
+
type: "confirm",
|
128
|
+
name: "useConfigForSource",
|
129
|
+
message: "Use your current appwriteConfig as the source?",
|
130
|
+
default: true,
|
131
|
+
},
|
132
|
+
]);
|
133
|
+
if (useConfigForSource) {
|
134
|
+
sourceConfig = {
|
135
|
+
sourceEndpoint: cli.controller.config.appwriteEndpoint,
|
136
|
+
sourceProject: cli.controller.config.appwriteProject,
|
137
|
+
sourceKey: cli.controller.config.appwriteKey,
|
138
|
+
};
|
139
|
+
// Preserve session for source if available
|
140
|
+
if (sessionConfig?.sessionCookie) {
|
141
|
+
sourceConfig.sessionCookie = sessionConfig.sessionCookie;
|
142
|
+
sourceConfig.sessionMetadata = sessionConfig.sessionMetadata;
|
143
|
+
}
|
144
|
+
MessageFormatter.info(`Using config source: ${sourceConfig.sourceEndpoint}`, { prefix: "Transfer" });
|
145
|
+
}
|
146
|
+
else {
|
147
|
+
// Get source configuration manually
|
148
|
+
sourceConfig = await inquirer.prompt([
|
149
|
+
{
|
150
|
+
type: "input",
|
151
|
+
name: "sourceEndpoint",
|
152
|
+
message: "Enter the source Appwrite endpoint:",
|
153
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
154
|
+
},
|
155
|
+
{
|
156
|
+
type: "input",
|
157
|
+
name: "sourceProject",
|
158
|
+
message: "Enter the source project ID:",
|
159
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
160
|
+
},
|
161
|
+
{
|
162
|
+
type: "password",
|
163
|
+
name: "sourceKey",
|
164
|
+
message: "Enter the source API key:",
|
165
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
166
|
+
},
|
167
|
+
]);
|
168
|
+
}
|
169
|
+
// Offer to use existing config for target
|
170
|
+
const { useConfigForTarget } = await inquirer.prompt([
|
171
|
+
{
|
172
|
+
type: "confirm",
|
173
|
+
name: "useConfigForTarget",
|
174
|
+
message: "Use your current appwriteConfig as the target?",
|
175
|
+
default: false,
|
176
|
+
},
|
177
|
+
]);
|
178
|
+
if (useConfigForTarget) {
|
179
|
+
targetConfig = {
|
180
|
+
targetEndpoint: cli.controller.config.appwriteEndpoint,
|
181
|
+
targetProject: cli.controller.config.appwriteProject,
|
182
|
+
targetKey: cli.controller.config.appwriteKey,
|
183
|
+
};
|
184
|
+
// Preserve session for target if available
|
185
|
+
if (sessionConfig?.sessionCookie) {
|
186
|
+
targetConfig.sessionCookie = sessionConfig.sessionCookie;
|
187
|
+
targetConfig.sessionMetadata = sessionConfig.sessionMetadata;
|
188
|
+
}
|
189
|
+
MessageFormatter.info(`Using config target: ${targetConfig.targetEndpoint}`, { prefix: "Transfer" });
|
190
|
+
}
|
191
|
+
else {
|
192
|
+
// Get target configuration manually
|
193
|
+
targetConfig = await inquirer.prompt([
|
194
|
+
{
|
195
|
+
type: "input",
|
196
|
+
name: "targetEndpoint",
|
197
|
+
message: "Enter the target Appwrite endpoint:",
|
198
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
199
|
+
},
|
200
|
+
{
|
201
|
+
type: "input",
|
202
|
+
name: "targetProject",
|
203
|
+
message: "Enter the target project ID:",
|
204
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
205
|
+
},
|
206
|
+
{
|
207
|
+
type: "password",
|
208
|
+
name: "targetKey",
|
209
|
+
message: "Enter the target API key:",
|
210
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
211
|
+
},
|
212
|
+
]);
|
213
|
+
}
|
214
|
+
}
|
215
|
+
else {
|
216
|
+
// No appwrite config found, get both configurations manually
|
217
|
+
MessageFormatter.info("No appwriteConfig found, please enter source and target configurations manually", { prefix: "Transfer" });
|
218
|
+
// Get source configuration
|
219
|
+
sourceConfig = await inquirer.prompt([
|
220
|
+
{
|
221
|
+
type: "input",
|
222
|
+
name: "sourceEndpoint",
|
223
|
+
message: "Enter the source Appwrite endpoint:",
|
224
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
225
|
+
},
|
226
|
+
{
|
227
|
+
type: "input",
|
228
|
+
name: "sourceProject",
|
229
|
+
message: "Enter the source project ID:",
|
230
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
231
|
+
},
|
232
|
+
{
|
233
|
+
type: "password",
|
234
|
+
name: "sourceKey",
|
235
|
+
message: "Enter the source API key:",
|
236
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
237
|
+
},
|
238
|
+
]);
|
239
|
+
// Get target configuration
|
240
|
+
targetConfig = await inquirer.prompt([
|
241
|
+
{
|
242
|
+
type: "input",
|
243
|
+
name: "targetEndpoint",
|
244
|
+
message: "Enter the target Appwrite endpoint:",
|
245
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
246
|
+
},
|
247
|
+
{
|
248
|
+
type: "input",
|
249
|
+
name: "targetProject",
|
250
|
+
message: "Enter the target project ID:",
|
251
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
252
|
+
},
|
253
|
+
{
|
254
|
+
type: "password",
|
255
|
+
name: "targetKey",
|
256
|
+
message: "Enter the target API key:",
|
257
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
258
|
+
},
|
259
|
+
]);
|
260
|
+
}
|
261
|
+
// Get transfer options
|
262
|
+
const transferOptions = await inquirer.prompt([
|
263
|
+
{
|
264
|
+
type: "checkbox",
|
265
|
+
name: "transferTypes",
|
266
|
+
message: "Select what to transfer:",
|
267
|
+
choices: [
|
268
|
+
{ name: "👥 Users", value: "users", checked: true },
|
269
|
+
{ name: "👥 Teams", value: "teams", checked: true },
|
270
|
+
{ name: "🗄️ Databases", value: "databases", checked: true },
|
271
|
+
{ name: "📦 Storage Buckets", value: "buckets", checked: true },
|
272
|
+
{ name: "⚡ Functions", value: "functions", checked: true },
|
273
|
+
],
|
274
|
+
validate: (input) => input.length > 0 || "Select at least one transfer type",
|
275
|
+
},
|
276
|
+
{
|
277
|
+
type: "list",
|
278
|
+
name: "concurrencyLimit",
|
279
|
+
message: "Select concurrency limit:",
|
280
|
+
choices: [
|
281
|
+
{ name: "5 (Conservative) - Users: 2, Files: 1", value: 5 },
|
282
|
+
{ name: "10 (Balanced) - Users: 5, Files: 2", value: 10 },
|
283
|
+
{ name: "15 - Users: 7, Files: 3", value: 15 },
|
284
|
+
{ name: "20 - Users: 10, Files: 5", value: 20 },
|
285
|
+
{ name: "25 - Users: 12, Files: 6", value: 25 },
|
286
|
+
{ name: "30 - Users: 15, Files: 7", value: 30 },
|
287
|
+
{ name: "35 - Users: 17, Files: 8", value: 35 },
|
288
|
+
{ name: "40 - Users: 20, Files: 10", value: 40 },
|
289
|
+
{ name: "45 - Users: 22, Files: 11", value: 45 },
|
290
|
+
{ name: "50 - Users: 25, Files: 12", value: 50 },
|
291
|
+
{ name: "55 - Users: 27, Files: 13", value: 55 },
|
292
|
+
{ name: "60 - Users: 30, Files: 15", value: 60 },
|
293
|
+
{ name: "65 - Users: 32, Files: 16", value: 65 },
|
294
|
+
{ name: "70 - Users: 35, Files: 17", value: 70 },
|
295
|
+
{ name: "75 - Users: 37, Files: 18", value: 75 },
|
296
|
+
{ name: "80 - Users: 40, Files: 20", value: 80 },
|
297
|
+
{ name: "85 - Users: 42, Files: 21", value: 85 },
|
298
|
+
{ name: "90 - Users: 45, Files: 22", value: 90 },
|
299
|
+
{ name: "95 - Users: 47, Files: 23", value: 95 },
|
300
|
+
{ name: "100 (Aggressive) - Users: 50, Files: 25", value: 100 },
|
301
|
+
],
|
302
|
+
default: 10,
|
303
|
+
},
|
304
|
+
{
|
305
|
+
type: "confirm",
|
306
|
+
name: "dryRun",
|
307
|
+
message: "Run in dry-run mode (no actual changes)?",
|
308
|
+
default: false,
|
309
|
+
},
|
310
|
+
]);
|
311
|
+
// Confirmation
|
312
|
+
const { confirmed } = await inquirer.prompt([
|
313
|
+
{
|
314
|
+
type: "confirm",
|
315
|
+
name: "confirmed",
|
316
|
+
message: `Are you sure you want to ${transferOptions.dryRun ? "dry-run" : "perform"} comprehensive transfer from ${sourceConfig.sourceEndpoint} to ${targetConfig.targetEndpoint}?`,
|
317
|
+
default: false,
|
318
|
+
},
|
319
|
+
]);
|
320
|
+
if (!confirmed) {
|
321
|
+
MessageFormatter.info("Transfer cancelled by user", { prefix: "Transfer" });
|
322
|
+
return;
|
323
|
+
}
|
324
|
+
// Password preservation information
|
325
|
+
if (transferOptions.transferTypes.includes("users") && !transferOptions.dryRun) {
|
326
|
+
MessageFormatter.info("User Password Transfer Information:", { prefix: "Transfer" });
|
327
|
+
MessageFormatter.info("✅ Users with hashed passwords (Argon2, Bcrypt, Scrypt, MD5, SHA, PHPass) will preserve their passwords", { prefix: "Transfer" });
|
328
|
+
MessageFormatter.info("⚠️ Users without hash information will receive temporary passwords and need to reset", { prefix: "Transfer" });
|
329
|
+
MessageFormatter.info("🔒 All user data (preferences, labels, verification status) will be preserved", { prefix: "Transfer" });
|
330
|
+
const { continueWithUsers } = await inquirer.prompt([
|
331
|
+
{
|
332
|
+
type: "confirm",
|
333
|
+
name: "continueWithUsers",
|
334
|
+
message: "Continue with user transfer?",
|
335
|
+
default: true,
|
336
|
+
},
|
337
|
+
]);
|
338
|
+
if (!continueWithUsers) {
|
339
|
+
// Remove users from transfer types
|
340
|
+
transferOptions.transferTypes = transferOptions.transferTypes.filter((type) => type !== "users");
|
341
|
+
if (transferOptions.transferTypes.length === 0) {
|
342
|
+
MessageFormatter.info("No transfer types selected, cancelling", { prefix: "Transfer" });
|
343
|
+
return;
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
// Execute comprehensive transfer
|
348
|
+
const comprehensiveTransferOptions = {
|
349
|
+
sourceEndpoint: sourceConfig.sourceEndpoint,
|
350
|
+
sourceProject: sourceConfig.sourceProject,
|
351
|
+
sourceKey: sourceConfig.sourceKey,
|
352
|
+
targetEndpoint: targetConfig.targetEndpoint,
|
353
|
+
targetProject: targetConfig.targetProject,
|
354
|
+
targetKey: targetConfig.targetKey,
|
355
|
+
transferUsers: transferOptions.transferTypes.includes("users"),
|
356
|
+
transferTeams: transferOptions.transferTypes.includes("teams"),
|
357
|
+
transferDatabases: transferOptions.transferTypes.includes("databases"),
|
358
|
+
transferBuckets: transferOptions.transferTypes.includes("buckets"),
|
359
|
+
transferFunctions: transferOptions.transferTypes.includes("functions"),
|
360
|
+
concurrencyLimit: transferOptions.concurrencyLimit,
|
361
|
+
dryRun: transferOptions.dryRun,
|
362
|
+
};
|
363
|
+
const transfer = new ComprehensiveTransfer(comprehensiveTransferOptions);
|
364
|
+
const results = await transfer.execute();
|
365
|
+
// Display results
|
366
|
+
if (transferOptions.dryRun) {
|
367
|
+
MessageFormatter.success("Dry run completed successfully!", { prefix: "Transfer" });
|
368
|
+
}
|
369
|
+
else {
|
370
|
+
MessageFormatter.success("Comprehensive transfer completed!", { prefix: "Transfer" });
|
371
|
+
if (transferOptions.transferTypes.includes("users") && results.users.transferred > 0) {
|
372
|
+
MessageFormatter.info("Users with preserved password hashes can log in with their original passwords", { prefix: "Transfer" });
|
373
|
+
MessageFormatter.info("Users with temporary passwords will need to reset their passwords", { prefix: "Transfer" });
|
374
|
+
}
|
375
|
+
if (transferOptions.transferTypes.includes("teams") && results.teams.transferred > 0) {
|
376
|
+
MessageFormatter.info("Team memberships have been transferred and may require user acceptance of invitations", { prefix: "Transfer" });
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
catch (error) {
|
381
|
+
MessageFormatter.error("Comprehensive transfer failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
382
|
+
}
|
383
|
+
}
|
384
|
+
};
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import { type Databases, type Models } from "node-appwrite";
|
2
2
|
import { type Attribute } from "appwrite-utils";
|
3
|
+
import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
|
3
4
|
/**
|
4
5
|
* Enhanced attribute creation with proper status monitoring and retry logic
|
5
6
|
*/
|
6
|
-
export declare const createOrUpdateAttributeWithStatusCheck: (db: Databases, dbId: string, collection: Models.Collection, attribute: Attribute, retryCount?: number, maxRetries?: number) => Promise<boolean>;
|
7
|
-
export declare const createOrUpdateAttribute: (db: Databases, dbId: string, collection: Models.Collection, attribute: Attribute) => Promise<"queued" | "processed">;
|
7
|
+
export declare const createOrUpdateAttributeWithStatusCheck: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attribute: Attribute, retryCount?: number, maxRetries?: number) => Promise<boolean>;
|
8
|
+
export declare const createOrUpdateAttribute: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attribute: Attribute) => Promise<"queued" | "processed">;
|
8
9
|
/**
|
9
10
|
* Enhanced collection attribute creation with proper status monitoring
|
10
11
|
*/
|
11
|
-
export declare const createUpdateCollectionAttributesWithStatusCheck: (db: Databases, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<boolean>;
|
12
|
-
export declare const createUpdateCollectionAttributes: (db: Databases, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<void>;
|
12
|
+
export declare const createUpdateCollectionAttributesWithStatusCheck: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<boolean>;
|
13
|
+
export declare const createUpdateCollectionAttributes: (db: Databases | DatabaseAdapter, dbId: string, collection: Models.Collection, attributes: Attribute[]) => Promise<void>;
|