Core Concepts

This page explains the fundamental concepts of the action system.

ActionExecutionContext

Context passed to action handlers. Note that context contains domain-specific data:

interface ActionExecutionContext<TContext, TTrigger> {
	trigger: TTrigger;     // What triggered this action
	context: TContext;     // Your domain-specific context
}

ActionExecutionResult

All action handlers must return a result:

interface ActionExecutionResult<TData = unknown> {
	success: boolean;
	message?: string;
	error?: string;
	data?: TData;
	shouldContinue?: boolean;  // If false, stops execution chain
	redirectUrl?: string;
}

ActionRegistration

An action registration defines how an action type behaves:

interface ActionRegistration<TType extends string, TContext, TTrigger> {
	$type: TType;
	schema: z.ZodTypeAny;
	metadata: ActionMetadata<TTrigger>;
	execute: (context: TContext) => Promise<ActionExecutionResult> | ActionExecutionResult;
}

Note: The execute function receives the domain context directly. The executor merges the action config into this context.

Critical Concept: The Merge

When an action executes, the ActionExecutor merges the specific Action Config (id, message, etc.) into your Domain Context.

// 1. Your Domain Context
const domainContext = { userId: "123", db: "..." };
 
// 2. The Specific Action Config
const actionConfig = { id: "action-1", message: "Hello" };
 
// 3. What execute() receives
execute: async (mergedContext) => {
  console.log(mergedContext.userId);  // from Domain Context
  console.log(mergedContext.message); // from Action Config
}

ActionConfigBase

Base interface for action instance configurations:

interface ActionConfigBase<TType extends string = string> {
	id: string;           // Unique identifier for this action instance
	$type: TType;         // References a registered action
	enabled?: boolean;    // Whether this action is enabled
	triggers?: readonly string[];  // Custom triggers for this instance
}

Trigger Matching

Actions execute when:

  1. They have a custom triggers array that includes the current trigger, OR
  2. Their metadata.defaultTriggers includes the current trigger
// Action instance with custom triggers
const action = {
	id: 'my-action',
	$type: 'log',
	triggers: ['submit', 'change'],
};
 
// Action registration with default triggers
const registration = {
	$type: 'log',
	metadata: {
		defaultTriggers: ['mount'],
	},
	execute: async (ctx) => ({ success: true }),
};

Custom triggers on an action instance override the default triggers from the registration.