diff --git a/nodes/Feather/operations/cancelWorkflowExecution.ts b/nodes/Feather/operations/cancelWorkflowExecution.ts index 9a36018..b95143e 100644 --- a/nodes/Feather/operations/cancelWorkflowExecution.ts +++ b/nodes/Feather/operations/cancelWorkflowExecution.ts @@ -1,49 +1,28 @@ -import { IExecuteFunctions, INodeExecutionData, LoggerProxy as Logger } from 'n8n-workflow'; +import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; export async function executeCancelWorkflowExecution( this: IExecuteFunctions, i: number, baseURL: string, ): Promise { - try { - Logger.info('Starting workflow execution cancellation...'); + // Get the workflow and execution IDs + const workflowId = this.getNodeParameter('workflowId', i) as string; + const executionId = this.getNodeParameter('executionId', i) as string; - // Get the workflow and execution IDs - const workflowId = this.getNodeParameter('workflowId', i) as string; - const executionId = this.getNodeParameter('executionId', i) as string; + const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { + method: 'POST', + url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`, + headers: { + 'Content-Type': 'application/json', + accept: 'application/json, text/plain, */*', + }, + json: true, + }); - Logger.info('Parameters:', { workflowId, executionId }); - - try { - const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { - method: 'POST', - url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`, - headers: { - 'Content-Type': 'application/json', - accept: 'application/json, text/plain, */*', - }, - json: true, - }); - - Logger.info('Workflow execution cancelled successfully:', { response }); - - return { - json: response, - pairedItem: { - item: i, - }, - }; - } catch (apiError) { - Logger.error('API request failed:', { error: apiError }); - Logger.error('Request details:', { - url: `${baseURL}/api/v1/workflow/${workflowId}/executions/${executionId}/cancel`, - workflowId, - executionId, - }); - throw apiError; - } - } catch (error) { - Logger.error('Error in workflow execution cancellation:', { error }); - throw error; - } + return { + json: response, + pairedItem: { + item: i, + }, + }; } diff --git a/nodes/Feather/operations/createAgentWorkflow.ts b/nodes/Feather/operations/createAgentWorkflow.ts index 888fa93..beb1563 100644 --- a/nodes/Feather/operations/createAgentWorkflow.ts +++ b/nodes/Feather/operations/createAgentWorkflow.ts @@ -1,4 +1,4 @@ -import { IExecuteFunctions, INodeExecutionData, LoggerProxy as Logger } from 'n8n-workflow'; +import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; type WorkflowStep = { id: string; @@ -71,168 +71,131 @@ export async function executeCreateAgentWorkflow( i: number, baseURL: string, ): Promise { - try { - Logger.info('Starting workflow creation...'); - - // Get basic workflow information - const name = this.getNodeParameter('name', i) as string; - const description = this.getNodeParameter('description', i) as string; - const active = this.getNodeParameter('active', i) as boolean; - const timezone = this.getNodeParameter('timezone', i) as string; - const agentId = this.getNodeParameter('agentId', i) as string; - - Logger.info('Basic parameters:', { name, description, active, timezone, agentId }); - - // Get step configuration - const stepConfig = this.getNodeParameter('stepConfiguration', i) as Record; - Logger.info('Step configuration:', stepConfig); - - // Get schedule configurations - const workflowScheduleUi = this.getNodeParameter('workflowScheduleUi', i) as Record< - string, - unknown - >; - const tcpaScheduleUi = this.getNodeParameter('tcpaScheduleUi', i) as Record; - - const workflowScheduleData = workflowScheduleUi?.scheduleConfiguration || {}; - const tcpaScheduleData = tcpaScheduleUi?.tcpaConfiguration || {}; - - Logger.info('Schedule configurations:', { workflowScheduleData, tcpaScheduleData }); - - // Build workflow schedule - const workflowSchedule: Schedule = { - monday: { enabled: false, timeRanges: [] }, - tuesday: { enabled: false, timeRanges: [] }, - wednesday: { enabled: false, timeRanges: [] }, - thursday: { enabled: false, timeRanges: [] }, - friday: { enabled: false, timeRanges: [] }, - saturday: { enabled: false, timeRanges: [] }, - sunday: { enabled: false, timeRanges: [] }, - }; - - // Build TCPA schedule - const tcpaSchedule: Schedule = { - monday: { enabled: false, timeRanges: [] }, - tuesday: { enabled: false, timeRanges: [] }, - wednesday: { enabled: false, timeRanges: [] }, - thursday: { enabled: false, timeRanges: [] }, - friday: { enabled: false, timeRanges: [] }, - saturday: { enabled: false, timeRanges: [] }, - sunday: { enabled: false, timeRanges: [] }, - }; - - // Configure workflow schedule - if (workflowScheduleData) { - Logger.info('Configuring workflow schedule...'); - const scheduleData = workflowScheduleData as Record; - const { - workingDays = [], - workingHoursStart = 9, - workingHoursEnd = 17, - workingMinutesStart = 0, - workingMinutesEnd = 0, - } = scheduleData; - - Logger.info('Working days configuration:', { workingDays }); - - if (Array.isArray(workingDays) && workingDays.length > 0) { - for (const day of workingDays) { - workflowSchedule[day as keyof Schedule] = { - enabled: true, - timeRanges: [ - { - startHour: Number(workingHoursStart), - startMinute: Number(workingMinutesStart), - endHour: Number(workingHoursEnd), - endMinute: Number(workingMinutesEnd), - }, - ], - }; - } - Logger.info('Workflow schedule configured:', workflowSchedule); - } else { - Logger.info('No working days configured, using default empty schedule'); - } - } + // Get basic workflow information + const name = this.getNodeParameter('name', i) as string; + const description = this.getNodeParameter('description', i) as string; + const active = this.getNodeParameter('active', i) as boolean; + const timezone = this.getNodeParameter('timezone', i) as string; + const agentId = this.getNodeParameter('agentId', i) as string; + + // Get step configuration + const stepConfig = this.getNodeParameter('stepConfiguration', i) as Record; + + // Get schedule configurations + const workflowScheduleUi = this.getNodeParameter('workflowScheduleUi', i) as Record< + string, + unknown + >; + const tcpaScheduleUi = this.getNodeParameter('tcpaScheduleUi', i) as Record; + + const workflowScheduleData = workflowScheduleUi?.scheduleConfiguration || {}; + const tcpaScheduleData = tcpaScheduleUi?.tcpaConfiguration || {}; + + // Build workflow schedule + const workflowSchedule: Schedule = { + monday: { enabled: false, timeRanges: [] }, + tuesday: { enabled: false, timeRanges: [] }, + wednesday: { enabled: false, timeRanges: [] }, + thursday: { enabled: false, timeRanges: [] }, + friday: { enabled: false, timeRanges: [] }, + saturday: { enabled: false, timeRanges: [] }, + sunday: { enabled: false, timeRanges: [] }, + }; - // Configure TCPA schedule - if (tcpaScheduleData) { - Logger.info('Configuring TCPA schedule...'); - const tcpaData = tcpaScheduleData as Record; - const { - tcpaDays = [], - tcpaHoursStart = 8, - tcpaHoursEnd = 21, - tcpaMinutesStart = 0, - tcpaMinutesEnd = 0, - } = tcpaData; - - Logger.info('TCPA days configuration:', { tcpaDays }); - - if (Array.isArray(tcpaDays) && tcpaDays.length > 0) { - for (const day of tcpaDays) { - tcpaSchedule[day as keyof Schedule] = { - enabled: true, - timeRanges: [ - { - startHour: Number(tcpaHoursStart), - startMinute: Number(tcpaMinutesStart), - endHour: Number(tcpaHoursEnd), - endMinute: Number(tcpaMinutesEnd), - }, - ], - }; - } - Logger.info('TCPA schedule configured:', tcpaSchedule); - } else { - Logger.info('No TCPA days configured, using default empty schedule'); + // Build TCPA schedule + const tcpaSchedule: Schedule = { + monday: { enabled: false, timeRanges: [] }, + tuesday: { enabled: false, timeRanges: [] }, + wednesday: { enabled: false, timeRanges: [] }, + thursday: { enabled: false, timeRanges: [] }, + friday: { enabled: false, timeRanges: [] }, + saturday: { enabled: false, timeRanges: [] }, + sunday: { enabled: false, timeRanges: [] }, + }; + + // Configure workflow schedule + if (workflowScheduleData) { + const scheduleData = workflowScheduleData as Record; + const { + workingDays = [], + workingHoursStart = 9, + workingHoursEnd = 17, + workingMinutesStart = 0, + workingMinutesEnd = 0, + } = scheduleData; + + if (Array.isArray(workingDays) && workingDays.length > 0) { + for (const day of workingDays) { + workflowSchedule[day as keyof Schedule] = { + enabled: true, + timeRanges: [ + { + startHour: Number(workingHoursStart), + startMinute: Number(workingMinutesStart), + endHour: Number(workingHoursEnd), + endMinute: Number(workingMinutesEnd), + }, + ], + }; } } + } - const stepDefinition = buildWorkflowDefinition(agentId, stepConfig?.stepSettings || {}); - - const workflow = { - name, - description, - active, - timezone, - workflowSchedule, - tcpaSchedule, - definition: stepDefinition, - }; - - Logger.info('Preparing API request with workflow:', { workflow }); - - try { - const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { - method: 'POST', - url: `${baseURL}/api/v1/workflow`, - headers: { - 'Content-Type': 'application/json', - accept: 'application/json, text/plain, */*', - }, - body: workflow, - json: true, - }); - - Logger.info('Workflow created successfully:', { response }); - - return { - json: response, - pairedItem: { - item: i, - }, - }; - } catch (apiError) { - Logger.error('API request failed:', apiError); - Logger.error('Request details:', { - url: `${baseURL}/api/v1/workflow`, - workflow, - }); - throw apiError; + // Configure TCPA schedule + if (tcpaScheduleData) { + const tcpaData = tcpaScheduleData as Record; + const { + tcpaDays = [], + tcpaHoursStart = 8, + tcpaHoursEnd = 21, + tcpaMinutesStart = 0, + tcpaMinutesEnd = 0, + } = tcpaData; + + if (Array.isArray(tcpaDays) && tcpaDays.length > 0) { + for (const day of tcpaDays) { + tcpaSchedule[day as keyof Schedule] = { + enabled: true, + timeRanges: [ + { + startHour: Number(tcpaHoursStart), + startMinute: Number(tcpaMinutesStart), + endHour: Number(tcpaHoursEnd), + endMinute: Number(tcpaMinutesEnd), + }, + ], + }; + } } - } catch (error) { - Logger.error('Error in workflow creation:', error); - throw error; } + + const stepDefinition = buildWorkflowDefinition(agentId, stepConfig?.stepSettings || {}); + + const workflow = { + name, + description, + active, + timezone, + workflowSchedule, + tcpaSchedule, + definition: stepDefinition, + }; + + const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { + method: 'POST', + url: `${baseURL}/api/v1/workflow`, + headers: { + 'Content-Type': 'application/json', + accept: 'application/json, text/plain, */*', + }, + body: workflow, + json: true, + }); + + return { + json: response, + pairedItem: { + item: i, + }, + }; } diff --git a/nodes/Feather/operations/createWorkflowExecution.ts b/nodes/Feather/operations/createWorkflowExecution.ts index d177868..af7d506 100644 --- a/nodes/Feather/operations/createWorkflowExecution.ts +++ b/nodes/Feather/operations/createWorkflowExecution.ts @@ -1,169 +1,147 @@ -import { IExecuteFunctions, INodeExecutionData, LoggerProxy as Logger, NodeOperationError } from 'n8n-workflow'; +import { IExecuteFunctions, INodeExecutionData, NodeOperationError } from 'n8n-workflow'; export async function executeCreateWorkflowExecution( this: IExecuteFunctions, i: number, baseURL: string, ): Promise { - try { - Logger.info('Starting workflow execution creation...'); - - // Get required parameters - const workflowId = this.getNodeParameter('workflowId', i) as string; - const customerLeadId = this.getNodeParameter('customerLeadId', i) as string; - const primaryPhone = this.getNodeParameter('primaryPhone', i) as string; - - // Get optional parameters - let zipcode = this.getNodeParameter('zipcode', i, null) as string | null | undefined; - let state = this.getNodeParameter('state', i, null) as string | null | undefined; - const forwardingPhoneNumber = this.getNodeParameter('forwardingPhoneNumber', i, null) as - | string - | null; - - - // Do not pass in request body if zipcode is null - if (zipcode === null) { - zipcode = undefined; - } + // Get required parameters + const workflowId = this.getNodeParameter('workflowId', i) as string; + const customerLeadId = this.getNodeParameter('customerLeadId', i) as string; + const primaryPhone = this.getNodeParameter('primaryPhone', i) as string; + + // Get optional parameters + let zipcode = this.getNodeParameter('zipcode', i, null) as string | null | undefined; + let state = this.getNodeParameter('state', i, null) as string | null | undefined; + const forwardingPhoneNumber = this.getNodeParameter('forwardingPhoneNumber', i, null) as + | string + | null; + + + // Do not pass in request body if zipcode is null + if (zipcode === null) { + zipcode = undefined; + } - if (zipcode !== undefined && zipcode.length === 0) { - zipcode = undefined; - } + if (zipcode !== undefined && zipcode.length === 0) { + zipcode = undefined; + } - if (state === null) { - state = undefined; - } + if (state === null) { + state = undefined; + } - if (state !== undefined && state.length === 0) { - state = undefined; - } + if (state !== undefined && state.length === 0) { + state = undefined; + } - // Get additional fields - const additionalFields = this.getNodeParameter('additionalFields', i, {}) as Record< - string, - unknown - >; + // Get additional fields + const additionalFields = this.getNodeParameter('additionalFields', i, {}) as Record< + string, + unknown + >; + + // Validate that at least one of zipcode or state is provided + if (!zipcode && !state) { + throw new NodeOperationError( + this.getNode(), + 'At least one of Zipcode or State must be provided', + { itemIndex: i }, + ); + } - // Validate that at least one of zipcode or state is provided - if (!zipcode && !state) { + // For state validate that it is 2 characters + if (state) { + if (state.length !== 2) { throw new NodeOperationError( this.getNode(), - 'At least one of Zipcode or State must be provided', + 'State must be 2 characters', { itemIndex: i }, ); } + } - // For state validate that it is 2 characters - if (state) { - if (state.length !== 2) { - throw new NodeOperationError( - this.getNode(), - 'State must be 2 characters', - { itemIndex: i }, - ); - } - } - - // For zipcode validate regex ^[0-9]{5}$ - if (zipcode) { - if (!/^[0-9]{5}$/.test(zipcode)) { - throw new NodeOperationError( - this.getNode(), - 'Zipcode must be 5 digits', - { itemIndex: i }, - ); - } - } - - Logger.info('Basic parameters:', { workflowId, customerLeadId, primaryPhone, zipcode, state }); - - // Build request body - const body: Record = { - customerLeadId, - primaryPhone, - zipcode, - state, - }; - - // Only include forwardingPhoneNumber if it's provided - if (forwardingPhoneNumber) { - body.forwardingPhoneNumber = forwardingPhoneNumber; - } - - // Handle variables (JSON) - if (additionalFields.variables) { - try { - body.variables = - typeof additionalFields.variables === 'string' - ? JSON.parse(additionalFields.variables as string) - : additionalFields.variables; - } catch { - throw new NodeOperationError(this.getNode(), 'Invalid JSON in Variables field', { - itemIndex: i, - }); - } - } else { - body.variables = {}; + // For zipcode validate regex ^[0-9]{5}$ + if (zipcode) { + if (!/^[0-9]{5}$/.test(zipcode)) { + throw new NodeOperationError( + this.getNode(), + 'Zipcode must be 5 digits', + { itemIndex: i }, + ); } + } - // Handle metadata - const metadata: Record = {}; - if (additionalFields.firstName) { - metadata.firstName = additionalFields.firstName; - } - if (additionalFields.lastName) { - metadata.lastName = additionalFields.lastName; - } + // Build request body + const body: Record = { + customerLeadId, + primaryPhone, + zipcode, + state, + }; + + // Only include forwardingPhoneNumber if it's provided + if (forwardingPhoneNumber) { + body.forwardingPhoneNumber = forwardingPhoneNumber; + } - // Add any additional metadata fields - if (additionalFields.additionalMetadata) { - try { - const additionalMetadata = - typeof additionalFields.additionalMetadata === 'string' - ? JSON.parse(additionalFields.additionalMetadata as string) - : additionalFields.additionalMetadata; - Object.assign(metadata, additionalMetadata); - } catch { - throw new NodeOperationError(this.getNode(), 'Invalid JSON in Additional Metadata field', { - itemIndex: i, - }); - } + // Handle variables (JSON) + if (additionalFields.variables) { + try { + body.variables = + typeof additionalFields.variables === 'string' + ? JSON.parse(additionalFields.variables as string) + : additionalFields.variables; + } catch { + throw new NodeOperationError(this.getNode(), 'Invalid JSON in Variables field', { + itemIndex: i, + }); } + } else { + body.variables = {}; + } - body.metadata = metadata; - - Logger.info('Preparing API request with execution data:', { body}); + // Handle metadata + const metadata: Record = {}; + if (additionalFields.firstName) { + metadata.firstName = additionalFields.firstName; + } + if (additionalFields.lastName) { + metadata.lastName = additionalFields.lastName; + } + // Add any additional metadata fields + if (additionalFields.additionalMetadata) { try { - const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { - method: 'POST', - url: `${baseURL}/api/v1/workflow/${workflowId}/execution`, - headers: { - 'Content-Type': 'application/json', - accept: 'application/json, text/plain, */*', - }, - body, - json: true, - }); - - Logger.info('Workflow execution created successfully:', { response }); - return { - json: response, - pairedItem: { - item: i, - }, - }; - } catch (apiError) { - Logger.error('API request failed:', apiError); - Logger.error('Request details:', { - url: `${baseURL}/api/v1/workflow/${workflowId}/execution`, - workflowId, - body, + const additionalMetadata = + typeof additionalFields.additionalMetadata === 'string' + ? JSON.parse(additionalFields.additionalMetadata as string) + : additionalFields.additionalMetadata; + Object.assign(metadata, additionalMetadata); + } catch { + throw new NodeOperationError(this.getNode(), 'Invalid JSON in Additional Metadata field', { + itemIndex: i, }); - throw apiError; } - } catch (error) { - Logger.error('Error in workflow execution creation:', error); - throw error; } + + body.metadata = metadata; + + const response = await this.helpers.httpRequestWithAuthentication.call(this, 'featherApi', { + method: 'POST', + url: `${baseURL}/api/v1/workflow/${workflowId}/execution`, + headers: { + 'Content-Type': 'application/json', + accept: 'application/json, text/plain, */*', + }, + body, + json: true, + }); + + return { + json: response, + pairedItem: { + item: i, + }, + }; }