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;
}
}