appwrite-utils-cli 1.0.6 โ 1.0.8
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 +64 -0
- package/dist/config/yamlConfig.js +0 -9
- package/dist/interactiveCLI.d.ts +1 -0
- package/dist/interactiveCLI.js +185 -21
- package/dist/migrations/comprehensiveTransfer.d.ts +66 -0
- package/dist/migrations/comprehensiveTransfer.js +366 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +4 -4
- package/dist/utils/loadConfigs.js +5 -5
- package/package.json +1 -1
- package/src/config/yamlConfig.ts +0 -9
- package/src/interactiveCLI.ts +196 -21
- package/src/migrations/comprehensiveTransfer.ts +505 -0
- package/src/utils/loadConfigs.ts +6 -5
package/src/interactiveCLI.ts
CHANGED
@@ -15,6 +15,7 @@ import {
|
|
15
15
|
} from "node-appwrite";
|
16
16
|
import { getClient } from "./utils/getClientFromConfig.js";
|
17
17
|
import type { TransferOptions } from "./migrations/transfer.js";
|
18
|
+
import { ComprehensiveTransfer, type ComprehensiveTransferOptions } from "./migrations/comprehensiveTransfer.js";
|
18
19
|
import {
|
19
20
|
AppwriteFunctionSchema,
|
20
21
|
parseAttribute,
|
@@ -52,24 +53,25 @@ import { findYamlConfig, addFunctionToYamlConfig } from "./config/yamlConfig.js"
|
|
52
53
|
|
53
54
|
enum CHOICES {
|
54
55
|
MIGRATE_CONFIG = "๐ Migrate TypeScript config to YAML (.appwrite structure)",
|
55
|
-
CREATE_COLLECTION_CONFIG = "Create collection config file",
|
56
|
-
CREATE_FUNCTION = "Create a new function, from scratch or using a template",
|
57
|
-
DEPLOY_FUNCTION = "Deploy function(s)",
|
58
|
-
DELETE_FUNCTION = "Delete function",
|
59
|
-
SETUP_DIRS_FILES = "Setup directories and files",
|
60
|
-
SETUP_DIRS_FILES_WITH_EXAMPLE_DATA = "Setup directories and files with example data",
|
61
|
-
SYNC_DB = "Push local config to Appwrite",
|
62
|
-
SYNCHRONIZE_CONFIGURATIONS = "Synchronize configurations - Pull from Appwrite and write to local config",
|
63
|
-
TRANSFER_DATA = "Transfer data",
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
CREATE_COLLECTION_CONFIG = "๐ Create collection config file",
|
57
|
+
CREATE_FUNCTION = "โก Create a new function, from scratch or using a template",
|
58
|
+
DEPLOY_FUNCTION = "๐ Deploy function(s)",
|
59
|
+
DELETE_FUNCTION = "๐๏ธ Delete function",
|
60
|
+
SETUP_DIRS_FILES = "๐ Setup directories and files",
|
61
|
+
SETUP_DIRS_FILES_WITH_EXAMPLE_DATA = "๐โจ Setup directories and files with example data",
|
62
|
+
SYNC_DB = "โฌ๏ธ Push local config to Appwrite",
|
63
|
+
SYNCHRONIZE_CONFIGURATIONS = "๐ Synchronize configurations - Pull from Appwrite and write to local config",
|
64
|
+
TRANSFER_DATA = "๐ฆ Transfer data",
|
65
|
+
COMPREHENSIVE_TRANSFER = "๐ Comprehensive transfer (users โ databases โ buckets โ functions)",
|
66
|
+
BACKUP_DATABASE = "๐พ Backup database",
|
67
|
+
WIPE_DATABASE = "๐งน Wipe database",
|
68
|
+
WIPE_COLLECTIONS = "๐งน Wipe collections",
|
69
|
+
GENERATE_SCHEMAS = "๐๏ธ Generate schemas",
|
68
70
|
GENERATE_CONSTANTS = "๐ Generate cross-language constants (TypeScript, Python, PHP, Dart, etc.)",
|
69
|
-
IMPORT_DATA = "Import data",
|
70
|
-
RELOAD_CONFIG = "Reload configuration files",
|
71
|
-
UPDATE_FUNCTION_SPEC = "Update function specifications",
|
72
|
-
EXIT = "Exit",
|
71
|
+
IMPORT_DATA = "๐ฅ Import data",
|
72
|
+
RELOAD_CONFIG = "๐ Reload configuration files",
|
73
|
+
UPDATE_FUNCTION_SPEC = "โ๏ธ Update function specifications",
|
74
|
+
EXIT = "๐ Exit",
|
73
75
|
}
|
74
76
|
|
75
77
|
export class InteractiveCLI {
|
@@ -145,6 +147,9 @@ export class InteractiveCLI {
|
|
145
147
|
await this.initControllerIfNeeded();
|
146
148
|
await this.transferData();
|
147
149
|
break;
|
150
|
+
case CHOICES.COMPREHENSIVE_TRANSFER:
|
151
|
+
await this.comprehensiveTransfer();
|
152
|
+
break;
|
148
153
|
case CHOICES.BACKUP_DATABASE:
|
149
154
|
await this.initControllerIfNeeded();
|
150
155
|
await this.backupDatabase();
|
@@ -1903,12 +1908,12 @@ export class InteractiveCLI {
|
|
1903
1908
|
}
|
1904
1909
|
|
1905
1910
|
private async reloadConfig(): Promise<void> {
|
1906
|
-
|
1911
|
+
MessageFormatter.progress("Reloading configuration files...", { prefix: "Config" });
|
1907
1912
|
try {
|
1908
1913
|
await this.controller!.reloadConfig();
|
1909
|
-
|
1914
|
+
MessageFormatter.success("Configuration files reloaded successfully", { prefix: "Config" });
|
1910
1915
|
} catch (error) {
|
1911
|
-
|
1916
|
+
MessageFormatter.error("Failed to reload configuration files", error instanceof Error ? error : new Error(String(error)), { prefix: "Config" });
|
1912
1917
|
}
|
1913
1918
|
}
|
1914
1919
|
|
@@ -1979,7 +1984,6 @@ export class InteractiveCLI {
|
|
1979
1984
|
try {
|
1980
1985
|
// Check for YAML config first
|
1981
1986
|
const yamlConfigPath = findYamlConfig(this.currentDir);
|
1982
|
-
console.log(`DEBUG: YAML config search from ${this.currentDir}, found: ${yamlConfigPath}`);
|
1983
1987
|
if (yamlConfigPath) {
|
1984
1988
|
this.isUsingTypeScriptConfig = false;
|
1985
1989
|
MessageFormatter.info("Using YAML configuration", { prefix: "Config" });
|
@@ -2043,4 +2047,175 @@ export class InteractiveCLI {
|
|
2043
2047
|
MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
|
2044
2048
|
}
|
2045
2049
|
}
|
2050
|
+
|
2051
|
+
private async comprehensiveTransfer(): Promise<void> {
|
2052
|
+
MessageFormatter.info("Starting comprehensive transfer configuration...", { prefix: "Transfer" });
|
2053
|
+
|
2054
|
+
try {
|
2055
|
+
// Get source configuration
|
2056
|
+
const sourceConfig = await inquirer.prompt([
|
2057
|
+
{
|
2058
|
+
type: "input",
|
2059
|
+
name: "sourceEndpoint",
|
2060
|
+
message: "Enter the source Appwrite endpoint:",
|
2061
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
2062
|
+
},
|
2063
|
+
{
|
2064
|
+
type: "input",
|
2065
|
+
name: "sourceProject",
|
2066
|
+
message: "Enter the source project ID:",
|
2067
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
2068
|
+
},
|
2069
|
+
{
|
2070
|
+
type: "password",
|
2071
|
+
name: "sourceKey",
|
2072
|
+
message: "Enter the source API key:",
|
2073
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
2074
|
+
},
|
2075
|
+
]);
|
2076
|
+
|
2077
|
+
// Get target configuration
|
2078
|
+
const targetConfig = await inquirer.prompt([
|
2079
|
+
{
|
2080
|
+
type: "input",
|
2081
|
+
name: "targetEndpoint",
|
2082
|
+
message: "Enter the target Appwrite endpoint:",
|
2083
|
+
validate: (input) => input.trim() !== "" || "Endpoint cannot be empty",
|
2084
|
+
},
|
2085
|
+
{
|
2086
|
+
type: "input",
|
2087
|
+
name: "targetProject",
|
2088
|
+
message: "Enter the target project ID:",
|
2089
|
+
validate: (input) => input.trim() !== "" || "Project ID cannot be empty",
|
2090
|
+
},
|
2091
|
+
{
|
2092
|
+
type: "password",
|
2093
|
+
name: "targetKey",
|
2094
|
+
message: "Enter the target API key:",
|
2095
|
+
validate: (input) => input.trim() !== "" || "API key cannot be empty",
|
2096
|
+
},
|
2097
|
+
]);
|
2098
|
+
|
2099
|
+
// Get transfer options
|
2100
|
+
const transferOptions = await inquirer.prompt([
|
2101
|
+
{
|
2102
|
+
type: "checkbox",
|
2103
|
+
name: "transferTypes",
|
2104
|
+
message: "Select what to transfer:",
|
2105
|
+
choices: [
|
2106
|
+
{ name: "๐ฅ Users", value: "users", checked: true },
|
2107
|
+
{ name: "๐๏ธ Databases", value: "databases", checked: true },
|
2108
|
+
{ name: "๐ฆ Storage Buckets", value: "buckets", checked: true },
|
2109
|
+
{ name: "โก Functions", value: "functions", checked: true },
|
2110
|
+
],
|
2111
|
+
validate: (input) => input.length > 0 || "Select at least one transfer type",
|
2112
|
+
},
|
2113
|
+
{
|
2114
|
+
type: "list",
|
2115
|
+
name: "concurrencyLimit",
|
2116
|
+
message: "Select concurrency limit:",
|
2117
|
+
choices: [
|
2118
|
+
{ name: "5 (Conservative) - Users: 2, Files: 1", value: 5 },
|
2119
|
+
{ name: "10 (Balanced) - Users: 5, Files: 2", value: 10 },
|
2120
|
+
{ name: "15 - Users: 7, Files: 3", value: 15 },
|
2121
|
+
{ name: "20 - Users: 10, Files: 5", value: 20 },
|
2122
|
+
{ name: "25 - Users: 12, Files: 6", value: 25 },
|
2123
|
+
{ name: "30 - Users: 15, Files: 7", value: 30 },
|
2124
|
+
{ name: "35 - Users: 17, Files: 8", value: 35 },
|
2125
|
+
{ name: "40 - Users: 20, Files: 10", value: 40 },
|
2126
|
+
{ name: "45 - Users: 22, Files: 11", value: 45 },
|
2127
|
+
{ name: "50 - Users: 25, Files: 12", value: 50 },
|
2128
|
+
{ name: "55 - Users: 27, Files: 13", value: 55 },
|
2129
|
+
{ name: "60 - Users: 30, Files: 15", value: 60 },
|
2130
|
+
{ name: "65 - Users: 32, Files: 16", value: 65 },
|
2131
|
+
{ name: "70 - Users: 35, Files: 17", value: 70 },
|
2132
|
+
{ name: "75 - Users: 37, Files: 18", value: 75 },
|
2133
|
+
{ name: "80 - Users: 40, Files: 20", value: 80 },
|
2134
|
+
{ name: "85 - Users: 42, Files: 21", value: 85 },
|
2135
|
+
{ name: "90 - Users: 45, Files: 22", value: 90 },
|
2136
|
+
{ name: "95 - Users: 47, Files: 23", value: 95 },
|
2137
|
+
{ name: "100 (Aggressive) - Users: 50, Files: 25", value: 100 },
|
2138
|
+
],
|
2139
|
+
default: 10,
|
2140
|
+
},
|
2141
|
+
{
|
2142
|
+
type: "confirm",
|
2143
|
+
name: "dryRun",
|
2144
|
+
message: "Run in dry-run mode (no actual changes)?",
|
2145
|
+
default: false,
|
2146
|
+
},
|
2147
|
+
]);
|
2148
|
+
|
2149
|
+
// Confirmation
|
2150
|
+
const { confirmed } = await inquirer.prompt([
|
2151
|
+
{
|
2152
|
+
type: "confirm",
|
2153
|
+
name: "confirmed",
|
2154
|
+
message: `Are you sure you want to ${transferOptions.dryRun ? "dry-run" : "perform"} comprehensive transfer from ${sourceConfig.sourceEndpoint} to ${targetConfig.targetEndpoint}?`,
|
2155
|
+
default: false,
|
2156
|
+
},
|
2157
|
+
]);
|
2158
|
+
|
2159
|
+
if (!confirmed) {
|
2160
|
+
MessageFormatter.info("Transfer cancelled by user", { prefix: "Transfer" });
|
2161
|
+
return;
|
2162
|
+
}
|
2163
|
+
|
2164
|
+
// Important password warning
|
2165
|
+
if (transferOptions.transferTypes.includes("users") && !transferOptions.dryRun) {
|
2166
|
+
MessageFormatter.warning("IMPORTANT: User passwords cannot be transferred due to Appwrite security limitations.", { prefix: "Transfer" });
|
2167
|
+
MessageFormatter.warning("Users will need to reset their passwords after transfer.", { prefix: "Transfer" });
|
2168
|
+
|
2169
|
+
const { continueWithUsers } = await inquirer.prompt([
|
2170
|
+
{
|
2171
|
+
type: "confirm",
|
2172
|
+
name: "continueWithUsers",
|
2173
|
+
message: "Continue with user transfer knowing passwords will be reset?",
|
2174
|
+
default: false,
|
2175
|
+
},
|
2176
|
+
]);
|
2177
|
+
|
2178
|
+
if (!continueWithUsers) {
|
2179
|
+
// Remove users from transfer types
|
2180
|
+
transferOptions.transferTypes = transferOptions.transferTypes.filter((type: string) => type !== "users");
|
2181
|
+
if (transferOptions.transferTypes.length === 0) {
|
2182
|
+
MessageFormatter.info("No transfer types selected, cancelling", { prefix: "Transfer" });
|
2183
|
+
return;
|
2184
|
+
}
|
2185
|
+
}
|
2186
|
+
}
|
2187
|
+
|
2188
|
+
// Execute comprehensive transfer
|
2189
|
+
const comprehensiveTransferOptions: ComprehensiveTransferOptions = {
|
2190
|
+
sourceEndpoint: sourceConfig.sourceEndpoint,
|
2191
|
+
sourceProject: sourceConfig.sourceProject,
|
2192
|
+
sourceKey: sourceConfig.sourceKey,
|
2193
|
+
targetEndpoint: targetConfig.targetEndpoint,
|
2194
|
+
targetProject: targetConfig.targetProject,
|
2195
|
+
targetKey: targetConfig.targetKey,
|
2196
|
+
transferUsers: transferOptions.transferTypes.includes("users"),
|
2197
|
+
transferDatabases: transferOptions.transferTypes.includes("databases"),
|
2198
|
+
transferBuckets: transferOptions.transferTypes.includes("buckets"),
|
2199
|
+
transferFunctions: transferOptions.transferTypes.includes("functions"),
|
2200
|
+
concurrencyLimit: transferOptions.concurrencyLimit,
|
2201
|
+
dryRun: transferOptions.dryRun,
|
2202
|
+
};
|
2203
|
+
|
2204
|
+
const transfer = new ComprehensiveTransfer(comprehensiveTransferOptions);
|
2205
|
+
const results = await transfer.execute();
|
2206
|
+
|
2207
|
+
// Display results
|
2208
|
+
if (transferOptions.dryRun) {
|
2209
|
+
MessageFormatter.success("Dry run completed successfully!", { prefix: "Transfer" });
|
2210
|
+
} else {
|
2211
|
+
MessageFormatter.success("Comprehensive transfer completed!", { prefix: "Transfer" });
|
2212
|
+
if (transferOptions.transferTypes.includes("users") && results.users.transferred > 0) {
|
2213
|
+
MessageFormatter.info("Remember to notify users about password reset requirements", { prefix: "Transfer" });
|
2214
|
+
}
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
} catch (error) {
|
2218
|
+
MessageFormatter.error("Comprehensive transfer failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Transfer" });
|
2219
|
+
}
|
2220
|
+
}
|
2046
2221
|
}
|