import type {bot_event_name, bot_instance_context} from '../../instance/bot_instance_init.ts'; import type {BranchState} from '../../../types/bot/workflow/runtime.ts'; import type {Json, workflow_config} from '../../../types/bot/workflow/workflow.ts'; import type {WorkflowStartTemplate} from '../../../types/bot/workflow/metadata.ts'; import {assert_json, evaluate_condition} from '../runtime/value.ts'; import {normalize_event} from '../node_action/event_node/registry.ts'; import {describe, output} from '../metadata.ts'; export const config_template: WorkflowStartTemplate = { name: 'event', version: '1.0.0', i18n: describe('事件启动', '机器人出生并就绪后,监听指定事件并按可选条件启动工作流。'), config: [ {name: 'auto_start', type: 'boolean', required: false, default: true, i18n: describe('自动监听', '机器人连接并出生后自动监听事件。')}, {name: 'mode', type: 'select', required: false, default: 'continuous', i18n: describe('监听模式', '持续监听,或在一次启动被接受后停止监听。'), options: [ {value: 'continuous', i18n: describe('持续', '持续接受匹配的事件。')}, {value: 'once', i18n: describe('一次', '接受一次启动或排队后停止;忙碌跳过时继续监听。')}, ]}, {name: 'event', type: 'string', required: true, provider: 'event', i18n: describe('事件名称', '选择已描述的事件或填写自定义事件名称;不允许 workflow_update。')}, {name: 'condition', type: 'condition', required: false, i18n: describe('触发条件', '使用标准化后的 trigger 数据判断;支持多个条件全部满足(and/且)、任一满足(or/或)和嵌套分组。条件为真时启动,引用缺失时跳过。')}, ], output: { ...output('object', '事件数据', '具体字段由所选事件模板定义;未知事件输出 {event, args}。'), properties: {event: output('string', '事件名称', '当前订阅的事件名称。')}, additional_properties: output('json', '事件字段', '事件适配器提供的有界 JSON 数据。'), }, }; export function create_event_handler(definition: workflow_config, start: (trigger: Record) => void): (...args: unknown[]) => void { if (definition.start.type !== 'event' || definition.start.event === 'workflow_update') { throw new Error('Invalid workflow event trigger'); } const config = definition.start; return (...args: unknown[]) => { if (config.event === 'any' && args[0] === 'workflow_update') return; try { if (args.length > 32) return; const trigger = normalize_event(config.event, args); if (!trigger) return; assert_json(trigger); if (Buffer.byteLength(JSON.stringify(trigger)) > 65_536) return; if (config.condition) { const state: BranchState = {trigger, vars: structuredClone(definition.initial_vars ?? {}), outputs: {}, last_result: null, inputs: {}, retry_counts: {}}; if (!evaluate_condition(config.condition, state)) return; } start(trigger); } catch { /* Unsupported payloads and missing condition references skip this occurrence. */ } }; } export function register_event_start(context: Pick, 'on' | 'off'>, definition: workflow_config, start: (trigger: Record) => void): () => void { const callback = create_event_handler(definition, start); const event = (definition.start as {event: string}).event as bot_event_name; try { context.on(event, callback); } catch (error) { context.off(event, callback); throw error; } let disposed = false; return () => { if (disposed) return; disposed = true; context.off(event, callback); }; }