pame-core-cli
Version:
PAME.AI Core Operating System CLI - Open Source AI Platform for Agentic Commerce
447 lines โข 18.8 kB
JavaScript
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