feat: Refactor codebase, improve types, attempt test fixes

This commit is contained in:
leonardsellem
2025-03-31 11:20:05 +02:00
parent d16ad72b22
commit ecd9133437
38 changed files with 829 additions and 811 deletions

View File

@@ -5,9 +5,16 @@
*/
import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { ToolCallResult, ToolDefinition, Workflow, N8nNode, N8nConnection } from '../../types/index.js'; // Import specific types
import { N8nApiError } from '../../errors/index.js';
// Define specific type for update arguments
// Intersect with Partial<Workflow> to allow any workflow property update
// Requires workflowId to identify the workflow
interface UpdateWorkflowArgs extends Partial<Workflow> {
workflowId: string;
}
/**
* Handler for the update_workflow tool
*/
@@ -18,51 +25,73 @@ export class UpdateWorkflowHandler extends BaseWorkflowToolHandler {
* @param args Tool arguments containing workflow updates
* @returns Updated workflow information
*/
async execute(args: Record<string, any>): Promise<ToolCallResult> {
async execute(args: UpdateWorkflowArgs): Promise<ToolCallResult> { // Use specific args type
return this.handleExecution(async (args) => {
const { workflowId, name, nodes, connections, active, tags } = args;
const { workflowId, name, nodes, connections, active, tags, settings } = args; // Destructure known properties
if (!workflowId) {
throw new N8nApiError('Missing required parameter: workflowId');
}
// Validate nodes if provided
// Basic validation (more robust validation could use Zod or similar)
if (nodes && !Array.isArray(nodes)) {
throw new N8nApiError('Parameter "nodes" must be an array');
}
// Validate connections if provided
if (connections && typeof connections !== 'object') {
throw new N8nApiError('Parameter "connections" must be an object');
}
if (tags && !Array.isArray(tags)) {
throw new N8nApiError('Parameter "tags" must be an array of strings');
}
if (settings && typeof settings !== 'object') {
throw new N8nApiError('Parameter "settings" must be an object');
}
// Get the current workflow to update
const currentWorkflow = await this.apiService.getWorkflow(workflowId);
// Get the current workflow to compare changes (optional, but good for summary)
let currentWorkflow: Workflow | null = null;
try {
currentWorkflow = await this.apiService.getWorkflow(workflowId);
} catch (error) {
// Handle case where workflow to update doesn't exist
if (error instanceof N8nApiError && error.message.includes('not found')) { // Adjust error check as needed
throw new N8nApiError(`Workflow with ID "${workflowId}" not found.`);
}
throw error; // Re-throw other errors
}
// Prepare update object with changes
const workflowData: Record<string, any> = { ...currentWorkflow };
// Update fields if provided
if (name !== undefined) workflowData.name = name;
if (nodes !== undefined) workflowData.nodes = nodes;
if (connections !== undefined) workflowData.connections = connections;
if (active !== undefined) workflowData.active = active;
if (tags !== undefined) workflowData.tags = tags;
// Prepare update object with only the provided changes
const workflowUpdateData: Partial<Workflow> = {};
if (name !== undefined) workflowUpdateData.name = name;
if (nodes !== undefined) workflowUpdateData.nodes = nodes;
if (connections !== undefined) workflowUpdateData.connections = connections;
if (active !== undefined) workflowUpdateData.active = active;
if (tags !== undefined) workflowUpdateData.tags = tags;
if (settings !== undefined) workflowUpdateData.settings = settings;
// Add other updatable fields from Workflow interface if needed
// Check if there are any actual changes to send
if (Object.keys(workflowUpdateData).length === 0) {
return this.formatSuccess(
{ id: workflowId, name: currentWorkflow.name, active: currentWorkflow.active },
`No update parameters provided for workflow ${workflowId}. No changes made.`
);
}
// Update the workflow
const updatedWorkflow = await this.apiService.updateWorkflow(workflowId, workflowData);
const updatedWorkflow = await this.apiService.updateWorkflow(workflowId, workflowUpdateData);
// Build a summary of changes
// Build a summary of changes (optional)
const changesArray = [];
if (name !== undefined && name !== currentWorkflow.name) changesArray.push(`name: "${currentWorkflow.name}" → "${name}"`);
if (active !== undefined && active !== currentWorkflow.active) changesArray.push(`active: ${currentWorkflow.active}${active}`);
if (nodes !== undefined) changesArray.push('nodes updated');
if (connections !== undefined) changesArray.push('connections updated');
if (tags !== undefined) changesArray.push('tags updated');
if (settings !== undefined) changesArray.push('settings updated');
const changesSummary = changesArray.length > 0
? `Changes: ${changesArray.join(', ')}`
: 'No changes were made';
: 'No effective changes were made (values might be the same as current)';
return this.formatSuccess(
{
@@ -84,7 +113,7 @@ export class UpdateWorkflowHandler extends BaseWorkflowToolHandler {
export function getUpdateWorkflowToolDefinition(): ToolDefinition {
return {
name: 'update_workflow',
description: 'Update an existing workflow in n8n',
description: 'Update an existing workflow in n8n. Provide only the fields you want to change.',
inputSchema: {
type: 'object',
properties: {
@@ -98,14 +127,14 @@ export function getUpdateWorkflowToolDefinition(): ToolDefinition {
},
nodes: {
type: 'array',
description: 'Updated array of node objects that define the workflow',
description: 'Updated array of node objects (N8nNode structure) defining the workflow',
items: {
type: 'object',
type: 'object', // Ideally, reference a detailed N8nNode schema here
},
},
connections: {
type: 'object',
description: 'Updated connection mappings between nodes',
description: 'Updated connection mappings between nodes (N8nConnection structure)',
},
active: {
type: 'boolean',
@@ -118,8 +147,12 @@ export function getUpdateWorkflowToolDefinition(): ToolDefinition {
type: 'string',
},
},
settings: {
type: 'object',
description: 'Updated workflow settings (WorkflowSettings structure)',
},
},
required: ['workflowId'],
required: ['workflowId'], // Only ID is strictly required to identify the workflow
},
};
}