n8n/packages/workflow/src/workflow-validation.ts

60 lines
1.7 KiB
TypeScript

import type { INode, INodes, INodeType } from './interfaces';
export interface INodeTypesGetter {
getByNameAndVersion(nodeType: string, version?: number): INodeType | undefined;
}
/**
* Validates that a workflow has at least one trigger-like node (trigger, webhook, or polling node).
* A workflow can only be activated if it has a node that can start the workflow execution.
*
* @param nodes - The workflow nodes to validate
* @param nodeTypes - Node types getter to retrieve node definitions
* @param ignoreNodeTypes - Optional array of node types to ignore (e.g., manual trigger, start node)
* @returns Object with isValid flag and error message if invalid
*/
export function validateWorkflowHasTriggerLikeNode(
nodes: INodes,
nodeTypes: INodeTypesGetter,
ignoreNodeTypes?: string[],
): { isValid: boolean; error?: string } {
let node: INode;
let nodeType: INodeType | undefined;
for (const nodeName of Object.keys(nodes)) {
node = nodes[nodeName];
// Skip disabled nodes - they cannot trigger a run
if (node.disabled === true) {
continue;
}
// Skip ignored node types (e.g., manual trigger, start node)
if (ignoreNodeTypes?.includes(node.type)) {
continue;
}
nodeType = nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
if (nodeType === undefined) {
// Type is not known, skip validation
continue;
}
if (
nodeType.poll !== undefined ||
nodeType.trigger !== undefined ||
nodeType.webhook !== undefined
) {
// Is a trigger node. So workflow can be activated.
return { isValid: true };
}
}
return {
isValid: false,
error:
'Workflow cannot be activated because it has no trigger node. At least one trigger, webhook, or polling node is required.',
};
}