import { Command } from 'commander'; import { IntegrationEventPayload, Spec, Message, IntegrationEventType, } from '@core/types'; export abstract class IntegrationCLI { protected program: Command; protected integrationName: string; protected version: string; constructor(integrationName: string, version: string = '1.0.0') { this.integrationName = integrationName; this.version = version; this.program = new Command(); this.setupProgram(); } private setupProgram(): void { this.program .name(`${this.integrationName}-integration`) .description(`${this.integrationName} integration CLI`) .version(this.version); this.setupSpecCommand(); this.setupAccountCommands(); this.setupDataCommands(); this.setupSyncCommand(); } private setupAccountCommands(): void { this.program .command('setup') .description(`Set up a new ${this.integrationName} integration account`) .requiredOption( '--event-body ', 'Event body JSON (e.g. OAuth response or setup data)', ) .requiredOption( '--integration-definition ', 'Integration definition JSON', ) .action(async (options) => { try { const eventBody = JSON.parse(options.eventBody); const integrationDefinition = JSON.parse( options.integrationDefinition, ); const messages: Message[] = await this.handleEvent({ event: IntegrationEventType.SETUP, eventBody, integrationDefinition, }); for (const message of messages) { console.log(JSON.stringify(message)); } } catch (error) { console.error('Error during setup:', error); process.exit(1); } }); } private setupDataCommands(): void { this.program .command('process') .description(`Process ${this.integrationName} integration data`) .requiredOption('--event-data ', 'Event data JSON') .requiredOption('--config ', 'Integration configuration JSON') .action(async (options) => { try { const eventData = JSON.parse(options.eventData); const config = JSON.parse(options.config); const messages: Message[] = await this.handleEvent({ event: IntegrationEventType.PROCESS, eventBody: eventData, config, }); for (const message of messages) { console.log(JSON.stringify(message)); } } catch (error) { console.error('Error processing data:', error); process.exit(1); } }); this.program .command('identify') .description('Identify webhook account') .requiredOption('--webhook-data ', 'Webhook data JSON') .action(async (options) => { try { const webhookData = JSON.parse(options.webhookData); const messages: Message[] = await this.handleEvent({ event: IntegrationEventType.IDENTIFY, eventBody: webhookData, }); for (const message of messages) { console.log(JSON.stringify(message)); } } catch (error) { console.error('Error identifying account:', error); process.exit(1); } }); } private setupSpecCommand(): void { this.program .command('spec') .description('Get integration specification') .action(async () => { try { const spec = await this.getSpec(); const message: Message = { type: 'spec', data: spec, }; // For spec, we keep the single message output for compatibility console.log(JSON.stringify(message)); } catch (error) { console.error('Error getting spec:', error); process.exit(1); } }); } private setupSyncCommand(): void { this.program .command('sync') .description('Perform scheduled sync') .requiredOption('--config ', 'Integration configuration JSON') .option('--state ', 'Integration state JSON', '{}') .action(async (options) => { try { const config = JSON.parse(options.config); const state = options.state ? JSON.parse(options.state) : {}; const messages: Message[] = await this.handleEvent({ event: IntegrationEventType.SYNC, eventBody: {}, config, state, }); for (const message of messages) { console.log(JSON.stringify(message)); } } catch (error) { console.error('Error during sync:', error); process.exit(1); } }); } /** * Abstract method that must be implemented by each integration * This method should handle the integration-specific logic for each event type * and return an array of Message objects. */ protected abstract handleEvent( eventPayload: IntegrationEventPayload, ): Promise; /** * Abstract method that must be implemented by each integration * This method should return the integration specification */ protected abstract getSpec(): Promise; /** * Parse and execute the CLI commands */ public parse(): void { this.program.parse(); } /** * Get the commander program instance for additional customization */ public getProgram(): Command { return this.program; } }