import { Command } from 'commander'; import fs from 'fs'; import { listComponents, findConnection, searchWebhook, getAssociation, findPuller, extractExpression, } from '../../../../helpers/profileGeneratorHelper'; import { v4 } from 'uuid'; import { webhookEventYaml } from '../../../../components/webhookTemplate'; import { parse, stringify } from 'yaml'; import { paddingList } from '../../../../helpers/paddingList'; import inquirer from 'inquirer'; import { readVariableValue } from '../../../../helpers/variablesHelper'; export function GenerateWebhookReceiverCommand(): Command { const cmd = new Command('add-listener') .alias('al') .description('Generates a HexaSync Webhook Receiver') .option( '-w, --webhook-name ', 'Search for related webhook, e.g.: Shopify, QuickBooks', ) .action(async ({ webhookName }) => { const webhookYml: any = await searchWebhook(webhookName); if (!webhookYml?.connectionId) { console.error(`The webhook is missing connectionId`); return; } const events = Object.keys(webhookYml.targets || {}); const eventNames = events.map((e) => e); if (!events || !events.length) { console.error( `There is no event(s) assigned to the webhook yet. Please add an event for it.`, ); return; } console.log(`Please choose one of the below event(s) to add a listener`); const eventAnswer = await inquirer.prompt<{ value: string }>([ { type: 'list', name: 'value', message: `Select an event:`, choices: eventNames, }, ]); const eventKey = eventAnswer.value; const eventYml = webhookYml.targets[eventKey]; const connectionYml = findConnection(webhookYml.connectionId); if (!connectionYml) { console.error(`Looks like you have dropped the connection.`); return; } const taskYmls = listComponents('Task', (f: any) => f?.objects || []); const taskNames = taskYmls.map((task) => task.__real_name); console.log(`Please choose below task(s) to generate the listener.`); const taskAnswer = await inquirer.prompt<{ values: string[] }>([ { type: 'checkbox', name: 'values', message: `Select tasks:`, choices: taskNames, }, ]); const chosenTasks = taskAnswer.values.map((value) => taskYmls.find((task) => task.__real_name === value), ); if (!chosenTasks || !chosenTasks.length) { console.error('No valid tasks selected.'); return; } // Ask the user which tasks should use custom input console.log( `Select tasks to replace the puller response filter with custom input.`, ); const customInputTasksAnswer = await inquirer.prompt<{ values: string[]; }>([ { type: 'checkbox', name: 'values', message: `Select tasks to use custom input:`, choices: chosenTasks.map((task) => task.__real_name), }, ]); const customInputTasks = customInputTasksAnswer.values; const associations = getAssociation(); const responseFilters = {}; for (const task of chosenTasks) { // Add the task ID to eventYml.objectIds regardless of custom input selection eventYml.objectIds = [...(eventYml.objectIds || []), task.id]; const taskAssociation = associations.objectAssociations[task.id]; if (customInputTasks.includes(task.__real_name)) { console.log( `Skipping listener generation for task "${task.__real_name}" as it will use custom input.`, ); responseFilters[taskAssociation.puller.resultKey || 'items'] = { acceptedStatuses: ['success'], expression: '', }; continue; // Skip to the next task } if (!taskAssociation.puller?.id) { console.error( `The task ${task.__real_name} does not have a valid puller associated`, ); continue; } const puller = findPuller(taskAssociation.puller.id); const pullDataStep = puller.pullSteps?.find( (s: any) => s.key === 'PULL_DATA', ); if (!pullDataStep) { console.error( `The puller ${readVariableValue(puller.name)} has no PULL_DATA step`, ); continue; } responseFilters[taskAssociation.puller.resultKey || 'items'] = { acceptedStatuses: ['success'], expression: extractExpression( taskAssociation.puller.resultKey || 'items', pullDataStep, ), }; } // Ensure objectIds are unique eventYml.objectIds = (eventYml.objectIds || []).filter( (value, index, array) => array.indexOf(value) === index, ); eventYml.dataParser = { jsonata: { ...eventYml.dataParser?.jsonata, ...responseFilters, }, }; webhookYml.targets[eventKey] = { ...eventYml }; const webhookYmlFilePath = webhookYml.__file_path; delete webhookYml.__file_path; delete webhookYml.__real_name; fs.writeFileSync( webhookYmlFilePath, stringify( { webhooks: [webhookYml] }, { keepSourceTokens: true, lineWidth: 0 }, ), ); console.log( 'Remember to edit the expression and the event matching patterns to match your business', ); console.log('Listeners have been added successfully.'); }); return cmd; }