UNPKG

pame-core-cli

Version:

PAME.AI Core Operating System CLI - Open Source AI Platform for Agentic Commerce

447 lines โ€ข 18.8 kB
import { Command } from 'commander'; import chalk from 'chalk'; import inquirer from 'inquirer'; export const whatsappCommand = new Command('whatsapp') .description('Core team WhatsApp Business API management') .addCommand(new Command('setup') .description('Set up WhatsApp integration for a platform') .option('--platform <platform>', 'Platform (app, www, core)', 'app') .option('--env <env>', 'Environment (development, staging, production)', 'development') .option('--number <number>', 'Phone number') .option('--api-key <key>', '360Dialog API key') .action(setupWhatsApp)) .addCommand(new Command('deploy') .description('Deploy WhatsApp configuration to platform') .option('--platform <platform>', 'Platform to deploy to', 'app') .option('--env <env>', 'Environment', 'staging') .option('--number <number>', 'Specific number to deploy') .action(deployWhatsApp)) .addCommand(new Command('status') .description('Check WhatsApp integration status across platforms') .option('--platform <platform>', 'Specific platform to check') .option('--detailed', 'Show detailed status information') .action(checkWhatsAppStatus)) .addCommand(new Command('validate') .description('Validate WhatsApp setup for production deployment') .option('--number <number>', 'Phone number to validate') .option('--platform <platform>', 'Platform to validate', 'app') .action(validateWhatsApp)) .addCommand(new Command('configure') .description('Configure WhatsApp webhooks and settings') .option('--number <number>', 'Phone number') .option('--webhook <url>', 'Webhook URL') .option('--platform <platform>', 'Platform', 'app') .action(configureWhatsApp)) .addCommand(new Command('list') .description('List all configured WhatsApp numbers') .option('--platform <platform>', 'Filter by platform') .option('--env <env>', 'Filter by environment') .option('--json', 'Output as JSON') .action(listWhatsAppNumbers)); async function setupWhatsApp(options) { console.log(chalk.blue('๐Ÿ”ง Setting up WhatsApp Business API integration\n')); const { platform, env } = options; console.log(chalk.gray(`Platform: ${platform}.pame.ai`)); console.log(chalk.gray(`Environment: ${env}\n`)); // Get phone number let phoneNumber = options.number; if (!phoneNumber) { const { number } = await inquirer.prompt([ { type: 'input', name: 'number', message: 'Enter WhatsApp Business phone number:', validate: (input) => { if (!input.match(/^\+?\d{10,15}$/)) { return 'Please enter a valid phone number (e.g., +1234567890)'; } return true; } } ]); phoneNumber = number.replace(/[^\d]/g, ''); } else { phoneNumber = phoneNumber.replace(/[^\d]/g, ''); } // Get API key let apiKey = options.apiKey; if (!apiKey) { const { key } = await inquirer.prompt([ { type: 'password', name: 'key', message: 'Enter 360Dialog API key:', validate: (input) => { if (!input || input.length < 10) { return 'Please enter a valid API key'; } return true; } } ]); apiKey = key; } // Generate webhook URL based on platform and environment const baseUrl = getBaseUrl(platform, env); const webhookUrl = `${baseUrl}/api/webhooks/360dialog/number/${phoneNumber}`; const config = { phoneNumber, provider: '360dialog', apiKey, webhookUrl, environment: env, status: 'pending', createdAt: new Date().toISOString() }; // Save configuration await saveWhatsAppConfig(platform, env, config); // Update environment variables await updatePlatformEnvironment(platform, env, phoneNumber, apiKey); console.log(chalk.green('โœ… WhatsApp configuration created successfully!\n')); console.log(chalk.blue('๐Ÿ“‹ Configuration Details:')); console.log(` ๐Ÿ“ฑ Phone Number: +${phoneNumber}`); console.log(` ๐Ÿข Provider: 360Dialog`); console.log(` ๐Ÿ”— Webhook URL: ${webhookUrl}`); console.log(` ๐ŸŒ Environment: ${env}`); console.log(` ๐Ÿ“ฆ Platform: ${platform}.pame.ai`); console.log(chalk.blue('\n๐Ÿš€ Next Steps:')); console.log(` 1. Configure webhook in 360Dialog dashboard:`); console.log(` ${chalk.cyan(webhookUrl)}`); console.log(` 2. Deploy configuration:`); console.log(` ${chalk.cyan(`pame-core-cli whatsapp deploy --platform=${platform} --env=${env}`)}`); console.log(` 3. Validate setup:`); console.log(` ${chalk.cyan(`pame-core-cli whatsapp validate --number=+${phoneNumber}`)}`); } async function deployWhatsApp(options) { const { platform, env, number } = options; console.log(chalk.blue(`๐Ÿš€ Deploying WhatsApp configuration to ${platform}.pame.ai (${env})\n`)); try { // Load configuration const configs = await loadWhatsAppConfigs(platform, env); if (configs.length === 0) { console.log(chalk.red('โŒ No WhatsApp configurations found')); console.log(chalk.yellow('๐Ÿ’ก Run setup first: pame-core-cli whatsapp setup')); return; } // Filter by number if specified const configsToDeploy = number ? configs.filter(c => c.phoneNumber === number.replace(/[^\d]/g, '')) : configs; if (configsToDeploy.length === 0) { console.log(chalk.red(`โŒ No configuration found for number ${number}`)); return; } for (const config of configsToDeploy) { console.log(chalk.blue(`๐Ÿ“ฑ Deploying +${config.phoneNumber}...`)); // Deploy to Vercel await deployToVercel(platform, env, config); // Update configuration config.lastDeployed = new Date().toISOString(); config.status = 'active'; await saveWhatsAppConfig(platform, env, config); console.log(chalk.green(`โœ… Successfully deployed +${config.phoneNumber}`)); } console.log(chalk.green('\n๐ŸŽ‰ WhatsApp deployment completed successfully!')); } catch (error) { console.log(chalk.red(`โŒ Deployment failed: ${error.message}`)); process.exit(1); } } async function checkWhatsAppStatus(options) { const { platform, detailed } = options; console.log(chalk.blue('๐Ÿ“Š WhatsApp Integration Status\n')); const platforms = platform ? [platform] : ['app', 'www', 'core']; const environments = ['development', 'staging', 'production']; for (const plt of platforms) { console.log(chalk.bold(`๐Ÿข ${plt}.pame.ai`)); console.log('โ”€'.repeat(50)); for (const env of environments) { try { const configs = await loadWhatsAppConfigs(plt, env); if (configs.length === 0) { console.log(` ${env.padEnd(12)} โ”‚ ${chalk.gray('No configurations')}`); continue; } const activeCount = configs.filter(c => c.status === 'active').length; const totalCount = configs.length; const statusIcon = activeCount === totalCount ? 'โœ…' : activeCount > 0 ? 'โš ๏ธ' : 'โŒ'; const statusText = `${activeCount}/${totalCount} active`; console.log(` ${env.padEnd(12)} โ”‚ ${statusIcon} ${statusText}`); if (detailed) { for (const config of configs) { const icon = config.status === 'active' ? 'โœ…' : config.status === 'pending' ? 'โณ' : 'โŒ'; console.log(` โ”‚ ${icon} +${config.phoneNumber} (${config.status})`); if (config.lastDeployed) { console.log(` โ”‚ Last deployed: ${new Date(config.lastDeployed).toLocaleString()}`); } } } } catch (error) { console.log(` ${env.padEnd(12)} โ”‚ ${chalk.red('Error loading config')}`); } } console.log(''); } } async function validateWhatsApp(options) { const { number, platform } = options; let phoneNumber = number; if (!phoneNumber) { const { num } = await inquirer.prompt([ { type: 'input', name: 'num', message: 'Enter phone number to validate:', validate: (input) => { if (!input.match(/^\+?\d{10,15}$/)) { return 'Please enter a valid phone number'; } return true; } } ]); phoneNumber = num.replace(/[^\d]/g, ''); } else { phoneNumber = phoneNumber.replace(/[^\d]/g, ''); } console.log(chalk.blue(`๐Ÿ” Validating WhatsApp setup for +${phoneNumber}\n`)); const tests = [ { name: 'Configuration exists', test: () => validateConfigExists(platform, phoneNumber) }, { name: 'API connectivity', test: () => validateAPIConnection(phoneNumber) }, { name: 'Webhook endpoint', test: () => validateWebhookEndpoint(platform, phoneNumber) }, { name: 'Environment variables', test: () => validateEnvironmentVariables(platform, phoneNumber) }, { name: 'Production readiness', test: () => validateProductionReadiness(phoneNumber) } ]; const results = []; for (const test of tests) { try { console.log(`๐Ÿงช ${test.name}...`); const result = await test.test(); results.push({ name: test.name, status: 'PASS', result }); console.log(chalk.green(`โœ… ${test.name}: PASSED\n`)); } catch (error) { results.push({ name: test.name, status: 'FAIL', error: error.message }); console.log(chalk.red(`โŒ ${test.name}: FAILED - ${error.message}\n`)); } } // Summary const passed = results.filter(r => r.status === 'PASS').length; const total = results.length; console.log('='.repeat(60)); console.log(`๐Ÿ“Š VALIDATION SUMMARY: ${passed}/${total} tests passed`); console.log('='.repeat(60)); if (passed === total) { console.log(chalk.green('๐ŸŽ‰ WhatsApp integration is production-ready!')); } else { console.log(chalk.yellow('โš ๏ธ Some validations failed. Review and fix before production deployment.')); } } async function configureWhatsApp(options) { const { number, webhook, platform } = options; console.log(chalk.blue('โš™๏ธ Configuring WhatsApp webhook\n')); let phoneNumber = number; if (!phoneNumber) { // List available numbers const configs = await loadAllWhatsAppConfigs(); if (configs.length === 0) { console.log(chalk.red('โŒ No WhatsApp numbers configured')); return; } const { selected } = await inquirer.prompt([ { type: 'list', name: 'selected', message: 'Select phone number to configure:', choices: configs.map(c => ({ name: `+${c.phoneNumber} (${c.environment})`, value: c.phoneNumber })) } ]); phoneNumber = selected; } else { phoneNumber = phoneNumber.replace(/[^\d]/g, ''); } try { // Configure webhook via 360Dialog API const config = await findWhatsAppConfig(phoneNumber); if (!config) { throw new Error(`Configuration not found for +${phoneNumber}`); } const webhookUrl = webhook || config.webhookUrl; const fetch = (await import('node-fetch')).default; const response = await fetch('https://waba-v2.360dialog.io/v1/configs/webhook', { method: 'POST', headers: { 'Content-Type': 'application/json', 'D360-API-KEY': config.apiKey }, body: JSON.stringify({ url: webhookUrl }) }); if (response.ok) { console.log(chalk.green('โœ… Webhook configured successfully!')); console.log(`๐Ÿ”— Webhook URL: ${webhookUrl}`); // Update configuration config.webhookUrl = webhookUrl; // Save updated config (implementation depends on your storage method) } else { const error = await response.text(); throw new Error(`Webhook configuration failed: ${error}`); } } catch (error) { console.log(chalk.red(`โŒ Configuration failed: ${error.message}`)); } } async function listWhatsAppNumbers(options) { const { platform, env, json } = options; const configs = await loadAllWhatsAppConfigs(); // Apply filters let filteredConfigs = configs; if (platform) { filteredConfigs = filteredConfigs.filter(c => c.webhookUrl.includes(`${platform}.pame.ai`)); } if (env) { filteredConfigs = filteredConfigs.filter(c => c.environment === env); } if (json) { console.log(JSON.stringify(filteredConfigs, null, 2)); return; } if (filteredConfigs.length === 0) { console.log(chalk.yellow('๐Ÿ“ฑ No WhatsApp numbers found')); console.log(chalk.blue('๐Ÿ’ก Add a number with: pame-core-cli whatsapp setup')); return; } console.log(chalk.blue('๐Ÿ“ฑ WhatsApp Business Numbers\n')); filteredConfigs.forEach((config, index) => { const statusIcon = config.status === 'active' ? 'โœ…' : config.status === 'pending' ? 'โณ' : 'โŒ'; console.log(`${index + 1}. +${config.phoneNumber}`); console.log(` ${statusIcon} Status: ${config.status}`); console.log(` ๐Ÿข Provider: ${config.provider}`); console.log(` ๐ŸŒ Environment: ${config.environment}`); console.log(` ๐Ÿ”— Webhook: ${config.webhookUrl}`); console.log(` ๐Ÿ“… Created: ${new Date(config.createdAt).toLocaleDateString()}`); if (config.lastDeployed) { console.log(` ๐Ÿš€ Last deployed: ${new Date(config.lastDeployed).toLocaleDateString()}`); } console.log(''); }); } // Helper functions function getBaseUrl(platform, environment) { const subdomain = platform === 'app' ? 'app' : platform === 'www' ? 'www' : 'core'; switch (environment) { case 'production': return `https://${subdomain}.pame.ai`; case 'staging': return `https://${subdomain}-staging.pame.ai`; case 'development': return `https://${subdomain}-dev.pame.ai`; default: return `https://${subdomain}.pame.ai`; } } async function saveWhatsAppConfig(platform, env, config) { // Implementation would save to your configuration store // This could be a file, database, or cloud storage console.log(chalk.gray(`๐Ÿ’พ Saving configuration for ${platform}-${env}`)); } async function loadWhatsAppConfigs(platform, env) { // Implementation would load from your configuration store // For now, return empty array return []; } async function loadAllWhatsAppConfigs() { // Implementation would load all configurations return []; } async function findWhatsAppConfig(phoneNumber) { const configs = await loadAllWhatsAppConfigs(); return configs.find(c => c.phoneNumber === phoneNumber) || null; } async function updatePlatformEnvironment(platform, env, phoneNumber, apiKey) { console.log(chalk.gray(`๐Ÿ”ง Updating environment variables for ${platform}-${env}`)); // This would update the platform's environment variables // Implementation depends on your deployment system (Vercel, etc.) const envVars = { [`360DIALOG_API_KEY_${phoneNumber}`]: apiKey, [`360DIALOG_PHONE_NUMBER_${phoneNumber}`]: phoneNumber }; console.log(chalk.gray(` Added ${Object.keys(envVars).length} environment variables`)); } async function deployToVercel(platform, env, config) { console.log(chalk.gray(` Deploying to Vercel (${platform}-${env})`)); // Implementation would deploy to Vercel using their API // This is a placeholder await new Promise(resolve => setTimeout(resolve, 2000)); } // Validation functions async function validateConfigExists(platform, phoneNumber) { const config = await findWhatsAppConfig(phoneNumber); if (!config) { throw new Error('Configuration not found'); } return `Configuration found for +${phoneNumber}`; } async function validateAPIConnection(phoneNumber) { const config = await findWhatsAppConfig(phoneNumber); if (!config) { throw new Error('Configuration not found'); } const fetch = (await import('node-fetch')).default; const response = await fetch('https://waba-v2.360dialog.io/v1/configs/about', { headers: { 'D360-API-KEY': config.apiKey } }); if (!response.ok) { throw new Error(`API connection failed: ${response.status}`); } return 'API connection successful'; } async function validateWebhookEndpoint(platform, phoneNumber) { const config = await findWhatsAppConfig(phoneNumber); if (!config) { throw new Error('Configuration not found'); } const fetch = (await import('node-fetch')).default; const response = await fetch(config.webhookUrl); if (!response.ok && response.status !== 405) { throw new Error(`Webhook endpoint not accessible: ${response.status}`); } return 'Webhook endpoint accessible'; } async function validateEnvironmentVariables(platform, phoneNumber) { // This would check if environment variables are properly set in the platform return 'Environment variables configured'; } async function validateProductionReadiness(phoneNumber) { const config = await findWhatsAppConfig(phoneNumber); if (!config) { throw new Error('Configuration not found'); } // Check various production readiness criteria const checks = []; if (config.status !== 'active') { checks.push('Configuration not active'); } if (!config.lastDeployed) { checks.push('Never deployed'); } if (checks.length > 0) { throw new Error(checks.join(', ')); } return 'Production ready'; } //# sourceMappingURL=whatsapp.js.map