Advanced Usage

This page covers advanced patterns and techniques.

Sequential Execution

Actions always execute sequentially, never in parallel:

const results = await executor.execute([action1, action2, action3], 'submit', context);
// action2 starts only after action1 completes
// action3 starts only after action2 completes

Stop on Failure

Return shouldContinue: false to stop the execution chain:

execute: async (context) => {
	if (!context.isValid) {
		return {
			success: false,
			error: 'Validation failed',
			shouldContinue: false,
		};
	}
	return { success: true };
};

Disabled Actions

Set enabled: false to skip an action:

const action = {
	id: 'my-action',
	$type: 'log',
	enabled: false, // Will be skipped
};

Debug Logging

Enable debug mode to see execution details:

const executor = new ActionExecutor(registry, { debug: true });
// Logs:
// [ActionExecutor] Executing trigger: submit
// [ActionExecutor] Executing action: my-action (log)
// [ActionExecutor] Action my-action executed successfully

Custom Registry

You can implement your own registry by implementing the ActionRegistryProvider interface:

import type { ActionRegistryProvider } from '@schema-engine/actions';
 
class MyActionRegistry implements ActionRegistryProvider<MyContext, MyTrigger> {
	private actions = new Map();
 
	register(action: ActionRegistration<string, MyContext, MyTrigger>) {
		this.actions.set(action.$type, action);
	}
 
	getAction(type: string) {
		return this.actions.get(type);
	}
 
	getActionTypes(): string[] {
		return Array.from(this.actions.keys());
	}
}

Testing Actions

The action system is designed for easy testing:

import { describe, test, expect } from 'bun:test';
 
describe('LogAction', () => {
	test('should log message', async () => {
		const context = { id: 'test', data: {}, isValid: true };
		const config = { id: 'log-1', $type: 'log', message: 'test' };
 
		const result = await logAction.execute({ trigger: 'submit', ...context, config });
 
		expect(result.success).toBe(true);
	});
});