Files
metabuilder/workflow/executor/ts/plugins/function-executor-adapter.ts
johndoe6345789 ce435a5e1b feat(schema): add n8n workflow schema with first-class variables support
- Moved n8n workflow schema to schemas/n8n-workflow.schema.json
- Added `variables` property at workflow root level for type-safe, reusable workflow configuration
- Implemented full variable system with:
  * Type system (string, number, boolean, array, object, date, any)
  * Validation rules (min, max, pattern, enum)
  * Scope control (workflow, execution, global)
  * Required/optional with default values
- Created comprehensive N8N_VARIABLES_GUIDE.md (6,800+ words) with:
  * 5 real-world use case examples
  * Best practices and migration guide from meta to variables
  * Complete property reference and expression syntax
- Created N8N_VARIABLES_EXAMPLE.json demonstrating e-commerce order processing
- Documented schema gaps in N8N_SCHEMA_GAPS.md (10 missing enterprise features)
- Created migration infrastructure:
  * scripts/migrate-workflows-to-n8n.ts for workflow format conversion
  * npm scripts for dry-run and full migration
  * N8N_COMPLIANCE_AUDIT.md tracking 72 workflows needing migration
- Established packagerepo backend workflows with n8n schema format

Impact: Variables now first-class citizens enabling DRY principle, type safety, and enterprise-grade configuration management across workflows.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-22 18:38:37 +00:00

102 lines
2.3 KiB
TypeScript

/**
* Function Executor Adapter
* Wraps simple plugin functions into INodeExecutor interface
* @packageDocumentation
*/
import {
INodeExecutor,
WorkflowNode,
WorkflowContext,
ExecutionState,
NodeResult,
ValidationResult
} from '../types';
/**
* Type for plugin functions that follow the standard signature
*/
export type PluginFunction = (
node: WorkflowNode,
context: WorkflowContext,
state: ExecutionState
) => Promise<NodeResult>;
/**
* Plugin metadata for documentation and discovery
*/
export interface PluginMeta {
description?: string;
category?: string;
requiredParams?: string[];
optionalParams?: string[];
}
/**
* Creates an INodeExecutor from a simple function
* This adapter allows function-based plugins to be used with the registry
*/
export function createExecutor(
nodeType: string,
fn: PluginFunction,
meta?: PluginMeta
): INodeExecutor {
return {
nodeType,
async execute(
node: WorkflowNode,
context: WorkflowContext,
state: ExecutionState
): Promise<NodeResult> {
return fn(node, context, state);
},
validate(node: WorkflowNode): ValidationResult {
const errors: string[] = [];
const warnings: string[] = [];
// Check required parameters if specified
if (meta?.requiredParams) {
for (const param of meta.requiredParams) {
if (!(param in node.parameters)) {
errors.push(`Missing required parameter: ${param}`);
}
}
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
};
}
/**
* Batch create executors from a plugin map
* @param plugins Map of nodeType -> function
* @param category Category name for all plugins
*/
export function createExecutorsFromMap(
plugins: Record<string, PluginFunction>,
category?: string
): INodeExecutor[] {
return Object.entries(plugins).map(([nodeType, fn]) =>
createExecutor(nodeType, fn, { category })
);
}
/**
* Register a map of plugins to the registry
*/
export function registerPluginMap(
registry: { register(nodeType: string, executor: INodeExecutor): void },
plugins: Record<string, PluginFunction>,
category?: string
): void {
const executors = createExecutorsFromMap(plugins, category);
for (const executor of executors) {
registry.register(executor.nodeType, executor);
}
}