appwrite-utils-cli
Version:
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.
167 lines (166 loc) • 9.13 kB
JavaScript
import inquirer from "inquirer";
import { MessageFormatter } from "../../shared/messageFormatter.js";
import { migrateConfig } from "../../utils/configMigration.js";
import { validateCollectionsTablesConfig, reportValidationResults, } from "../../config/configValidation.js";
import { createMigrationPlan, executeMigrationPlan, saveMigrationResult, } from "../../config/configMigration.js";
import { createEmptyCollection } from "../../utils/setupFiles.js";
import chalk from "chalk";
import { ConfigManager } from "../../config/ConfigManager.js";
import { UtilsController } from "../../utilsController.js";
export const configCommands = {
async migrateTypeScriptConfig(cli) {
try {
MessageFormatter.info("Starting TypeScript to YAML configuration migration...", { prefix: "Migration" });
// Perform the migration
await migrateConfig(cli.currentDir);
// Clear instances after migration to reload new config
UtilsController.clearInstance();
ConfigManager.resetInstance();
// Reset the detection flag
cli.isUsingTypeScriptConfig = false;
// Reset the controller to pick up the new config
cli.controller = undefined;
MessageFormatter.success("Migration completed successfully!", { prefix: "Migration" });
MessageFormatter.info("Your configuration has been migrated to the .appwrite directory structure", { prefix: "Migration" });
MessageFormatter.info("You can now use YAML configuration for easier management", { prefix: "Migration" });
}
catch (error) {
MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
}
},
async validateConfiguration(cli) {
try {
MessageFormatter.info("Starting configuration validation...", { prefix: "Validation" });
await cli.initControllerIfNeeded();
const config = cli.controller?.config;
if (!config) {
MessageFormatter.error("No configuration found to validate", undefined, { prefix: "Validation" });
return;
}
const { validateCollectionsTablesConfig, reportValidationResults } = await import("../../config/configValidation.js");
const validation = validateCollectionsTablesConfig(config);
reportValidationResults(validation, { verbose: true });
if (validation.isValid) {
MessageFormatter.success("Configuration validation passed!", { prefix: "Validation" });
}
else {
MessageFormatter.error("Configuration validation failed", undefined, { prefix: "Validation" });
}
}
catch (error) {
MessageFormatter.error("Validation failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Validation" });
}
},
async migrateCollectionsToTables(cli) {
try {
MessageFormatter.info("Starting collections to tables migration...", { prefix: "Migration" });
await cli.initControllerIfNeeded();
// Ensure config is properly loaded with YAML collections
if (!cli.controller?.config) {
MessageFormatter.error("No configuration found", undefined, { prefix: "Migration" });
return;
}
// Check if collections exist
if (!cli.controller.config.collections || cli.controller.config.collections.length === 0) {
MessageFormatter.error("No collections found in configuration. Please check your YAML files or appwriteConfig.ts", undefined, { prefix: "Migration" });
return;
}
const { createMigrationPlan, executeMigrationPlan, saveMigrationResult } = await import("../../config/configMigration.js");
// Get user's migration strategy preference
const { strategy } = await inquirer.prompt([
{
type: "list",
name: "strategy",
message: "Choose migration strategy:",
choices: [
{ name: "Move files (rename collections/ to tables/)", value: "move" },
{ name: "Copy files (keep both collections/ and tables/)", value: "copy" },
{ name: "Dual format (create both .ts and .yaml versions)", value: "dual" }
]
}
]);
// Map user-friendly strategy names to internal MigrationStrategy types
const migrationStrategy = strategy === "move" ? "full_migration" :
strategy === "copy" || strategy === "dual" ? "dual_format" : "full_migration";
const plan = createMigrationPlan(cli.controller.config, migrationStrategy);
const { confirmed } = await inquirer.prompt([
{
type: "confirm",
name: "confirmed",
message: `Proceed with migration? This will affect ${plan.collectionsToMigrate?.length || 0} files.`,
default: false
}
]);
if (confirmed) {
const result = executeMigrationPlan(cli.controller.config, plan);
await saveMigrationResult(result, cli.currentDir);
MessageFormatter.success("Collections to tables migration completed!", { prefix: "Migration" });
}
else {
MessageFormatter.info("Migration cancelled by user", { prefix: "Migration" });
}
}
catch (error) {
MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
}
},
async createCollectionConfig(cli) {
const { collectionName } = await inquirer.prompt([
{
type: "input",
name: "collectionName",
message: chalk.blue("Enter the name of the collection:"),
validate: (input) => input.trim() !== "" || "Collection name cannot be empty.",
},
]);
MessageFormatter.progress(`Creating collection config file for '${collectionName}'...`, { prefix: "Collections" });
createEmptyCollection(collectionName);
MessageFormatter.success(`Collection config file created for '${collectionName}'`, { prefix: "Collections" });
},
async reloadConfigWithSessionPreservation(cli) {
MessageFormatter.progress("Reloading configuration files with session preservation...", { prefix: "Config" });
try {
const controller = cli.controller;
const UtilsController = (await import("../../utilsController.js")).UtilsController;
if (controller) {
const sessionInfo = controller.getSessionInfo();
if (sessionInfo.hasSession) {
// Extract session details for preservation
const sessionData = {
sessionCookie: controller.sessionCookie,
sessionMetadata: controller.sessionMetadata
};
// Store current config values for potential directConfig creation
const currentConfig = controller.config;
let directConfig = undefined;
if (currentConfig?.appwriteEndpoint && currentConfig?.appwriteProject) {
directConfig = {
appwriteEndpoint: currentConfig.appwriteEndpoint,
appwriteProject: currentConfig.appwriteProject,
appwriteKey: currentConfig.appwriteKey,
...sessionData // Preserve session
};
}
// Reinitialize controller with session preservation
UtilsController.clearInstance();
cli.controller = UtilsController.getInstance(cli.currentDir, directConfig);
await cli.controller.init();
MessageFormatter.success("Configuration reloaded with session preserved", { prefix: "Config" });
}
else {
// No session to preserve, standard reload
await controller.reloadConfig();
MessageFormatter.success("Configuration files reloaded successfully", { prefix: "Config" });
}
}
else {
// Initialize if no controller exists
await cli.initControllerIfNeeded();
MessageFormatter.success("Configuration initialized successfully", { prefix: "Config" });
}
}
catch (error) {
MessageFormatter.error("Failed to reload configuration files", error instanceof Error ? error : new Error(String(error)), { prefix: "Config" });
}
}
};