UNPKG

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.

208 lines (173 loc) 7.94 kB
import chalk from "chalk"; import { logger } from "./logging.js"; export interface MessageOptions { prefix?: string; skipLogging?: boolean; logLevel?: "info" | "warn" | "error" | "debug"; } export class MessageFormatter { static success(message: string, options: MessageOptions = {}) { const formatted = `${chalk.green("✅")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.info(`SUCCESS: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static error(message: string, error?: Error | string, options: MessageOptions = {}) { const errorDetails = error instanceof Error ? error.message : error; const formatted = `${chalk.red("❌")} ${options.prefix ? `${options.prefix}: ` : ""}${message}${errorDetails ? `\n ${chalk.gray(errorDetails)}` : ""}`; console.error(formatted); if (!options.skipLogging) { logger.error(`ERROR: ${options.prefix ? `${options.prefix}: ` : ""}${message}`, { error: errorDetails, stack: error instanceof Error ? error.stack : undefined, }); } } static warning(message: string, options: MessageOptions = {}) { const formatted = `${chalk.yellow("⚠️")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.warn(`WARNING: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static info(message: string, options: MessageOptions = {}) { const formatted = `${chalk.blue("ℹ️")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.info(`INFO: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static step(step: number, total: number, message: string, options: MessageOptions = {}) { const formatted = `${chalk.cyan(`[${step}/${total}]`)} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.info(`STEP ${step}/${total}: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static progress(message: string, options: MessageOptions = {}) { const formatted = `${chalk.gray("⏳")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.debug(`PROGRESS: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static debug(message: string, data?: any, options: MessageOptions = {}) { if (process.env.NODE_ENV === "development" || process.env.DEBUG) { const formatted = `${chalk.magenta("🔍")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (data) { console.log(chalk.gray(JSON.stringify(data, null, 2))); } } if (!options.skipLogging) { logger.debug(`DEBUG: ${options.prefix ? `${options.prefix}: ` : ""}${message}`, data); } } static processing(message: string, options: MessageOptions = {}) { const formatted = `${chalk.cyan("⚙️")} ${options.prefix ? `${options.prefix}: ` : ""}${message}`; console.log(formatted); if (!options.skipLogging) { logger.info(`PROCESSING: ${options.prefix ? `${options.prefix}: ` : ""}${message}`); } } static divider() { console.log(chalk.gray("─".repeat(60))); } static banner(title: string, subtitle?: string) { const divider = chalk.cyan("═".repeat(60)); console.log(`\n${divider}`); console.log(chalk.cyan.bold(` ${title}`)); if (subtitle) { console.log(chalk.gray(` ${subtitle}`)); } console.log(`${divider}\n`); } static section(title: string) { console.log(`\n${chalk.bold.underline(title)}`); } static list(items: string[], title?: string) { if (title) { console.log(chalk.bold(title)); } items.forEach((item, index) => { console.log(`${chalk.gray(` ${index + 1}.`)} ${item}`); }); } static table(data: Record<string, string | number>[], headers?: string[]) { if (data.length === 0) return; const keys = headers || Object.keys(data[0]); const maxWidths = keys.map(key => Math.max( key.length, ...data.map(row => String(row[key]).length) ) ); // Header const headerRow = keys.map((key, i) => chalk.bold(key.padEnd(maxWidths[i])) ).join(" │ "); console.log(`┌─${keys.map((_, i) => "─".repeat(maxWidths[i])).join("─┼─")}─┐`); console.log(`│ ${headerRow} │`); console.log(`├─${keys.map((_, i) => "─".repeat(maxWidths[i])).join("─┼─")}─┤`); // Rows data.forEach(row => { const dataRow = keys.map((key, i) => String(row[key]).padEnd(maxWidths[i]) ).join(" │ "); console.log(`│ ${dataRow} │`); }); console.log(`└─${keys.map((_, i) => "─".repeat(maxWidths[i])).join("─┴─")}─┘`); } static operationSummary(title: string, stats: Record<string, string | number>, duration?: number) { this.section(`${title} Summary`); Object.entries(stats).forEach(([key, value]) => { const formattedKey = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); console.log(`${chalk.gray("●")} ${formattedKey}: ${chalk.cyan(String(value))}`); }); if (duration) { console.log(`${chalk.gray("●")} Duration: ${chalk.cyan(this.formatDuration(duration))}`); } console.log(); } static formatBytes(bytes: number): string { const units = ['B', 'KB', 'MB', 'GB', 'TB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(1)} ${units[unitIndex]}`; } static formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}h ${minutes % 60}m ${seconds % 60}s`; } else if (minutes > 0) { return `${minutes}m ${seconds % 60}s`; } else { return `${seconds}s`; } } static formatNumber(num: number): string { return num.toLocaleString(); } } export const Messages = { CONFIG_NOT_FOUND: "Appwrite configuration not found. Run 'appwrite-migrate setup' first.", CONFIG_LOADED: (type: string, path: string) => `Loaded ${type} configuration from ${path}`, DATABASE_CONNECTION_FAILED: "Failed to connect to Appwrite. Check your endpoint and API key.", OPERATION_CANCELLED: "Operation cancelled by user.", OPERATION_COMPLETED: (operation: string) => `${operation} completed successfully`, BACKUP_STARTED: (database: string) => `Starting backup for database: ${database}`, BACKUP_COMPLETED: (database: string, size: number) => `Backup completed for ${database} (${MessageFormatter.formatBytes(size)})`, IMPORT_STARTED: (collections: number) => `Starting import process for ${collections} collection(s)`, IMPORT_COMPLETED: (documents: number) => `Import completed. Processed ${MessageFormatter.formatNumber(documents)} documents`, FUNCTION_DEPLOYED: (name: string) => `Function '${name}' deployed successfully`, FUNCTION_DEPLOYMENT_FAILED: (name: string, error: string) => `Function '${name}' deployment failed: ${error}`, TRANSFER_STARTED: (source: string, target: string) => `Starting transfer from ${source} to ${target}`, TRANSFER_COMPLETED: (items: number) => `Transfer completed. Moved ${MessageFormatter.formatNumber(items)} items`, } as const;