import { SchemaBase } from './dsl.js'; import type { ControllerMethodSchema } from './controller.js'; import type { ThirdServiceMethodSchema, ThirdCallbackSchema } from './third-service.js'; import type { TaskSchema } from './task.js'; import type { TableSchema } from './db.js'; import type { PageSchema } from './page.js'; // Cross-domain actions: what happens along a business line (journey). // Distinguished from PageActionSchema (what a user can do ON a page): // an Action is one beat of a journey — a page visit, an API call, a // third-party invocation, a database write, or a task trigger. // // Every action is `type + properties + data`: the type picks the property // set (page for page visits, method for controller/third, table for db, // task for task triggers), and `data` is the input of that beat. No further // classification — page/controller/third/db/task are all actions, only their // properties differ. /** A beat of a journey: type + properties + input data. */ export interface ActionSchema extends SchemaBase { type: 'page' | 'controller' | 'third' | 'db' | 'task'; /** Input data of this beat (blueprint: names first, refined to refs later). */ data?: Record; } /** Visit a page — `data` present means fill/submit a form, absent means pure view. */ export interface PageAction extends ActionSchema { type: 'page'; /** Target page (PageFlow node). */ page: PageSchema; /** Page url/path (e.g. '/bd/apply'). */ url: string; } /** Call a backend controller method. */ export interface ControllerAction extends ActionSchema { type: 'controller'; /** The controller method invoked (shared instance). */ method: ControllerMethodSchema; } /** Invoke a third-party service method or receive its callback. */ export interface ThirdAction extends ActionSchema { type: 'third'; /** The third-party method invoked (outbound). */ method?: ThirdServiceMethodSchema; /** The third-party callback received (inbound) — mutually exclusive with method. */ callback?: ThirdCallbackSchema; /** Wait for the async callback (inbound) before the journey continues. */ async?: boolean; } /** Write to a database table. */ export interface DbAction extends ActionSchema { type: 'db'; /** The table written (shared instance). */ table: TableSchema; /** Write operation: insert | update | delete. */ op: 'insert' | 'update' | 'delete'; } /** Trigger a system task (scheduled or async). */ export interface TaskAction extends ActionSchema { type: 'task'; /** The task triggered (shared instance). */ task: TaskSchema; } /** Builder for a journey action. */ export const action = { page(options: { page: PageSchema; url: string; data?: Record; description?: string }): PageAction { return { name: options.page.name, type: 'page', page: options.page, url: options.url, data: options.data, description: options.description }; }, controller(options: { method: ControllerMethodSchema; data?: Record; description?: string }): ControllerAction { return { name: options.method.name, type: 'controller', method: options.method, data: options.data, description: options.description }; }, third(options: { method?: ThirdServiceMethodSchema; callback?: ThirdCallbackSchema; data?: Record; async?: boolean; description?: string }): ThirdAction { const name = options.method?.name ?? options.callback?.name ?? 'third'; return { name, type: 'third', method: options.method, callback: options.callback, data: options.data, async: options.async, description: options.description }; }, db(options: { table: TableSchema; op: 'insert' | 'update' | 'delete'; data?: Record; description?: string }): DbAction { return { name: options.table.name, type: 'db', table: options.table, op: options.op, data: options.data, description: options.description }; }, task(options: { task: TaskSchema; data?: Record; description?: string }): TaskAction { return { name: options.task.name, type: 'task', task: options.task, data: options.data, description: options.description }; }, };