chore: initial commit

This commit is contained in:
2026-10-22 17:07:08 +08:00
commit 0acef64f48
200 changed files with 35546 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import type {bot_instance_context} from '../../instance/bot_instance_init.ts';
import type {Json} from '../../../types/bot/workflow/workflow.ts';
import type {WorkflowStartTemplate} from '../../../types/bot/workflow/metadata.ts';
import {describe, output} from '../metadata.ts';
export const config_template: WorkflowStartTemplate = {
name: 'common', version: '1.0.0',
i18n: describe('普通启动', '手动启动工作流,也可在机器人出生后自动启动。'),
config: [{
name: 'auto_start', type: 'select', required: true, default: 'never',
i18n: describe('自动启动', '选择是否在机器人出生后自动启动工作流。'),
options: [
{value: 'never', i18n: describe('不自动启动', '仅通过手动请求启动。')},
{value: 'spawn', i18n: describe('出生时启动', '机器人出生并就绪后自动启动。')},
],
}],
output: {
...output('object', '启动数据', '手动启动时为调用方提供的 JSON 对象;自动启动时为 {event: "spawn"}。'),
additional_properties: output('json', '触发字段', '手动启动时传入的 JSON 字段值。'),
},
};
export function register_common_start(context: Pick<bot_instance_context<any>, 'on' | 'off'>,
start: (trigger: Record<string, Json>) => void, initially_ready = false): () => void {
let disposed = false;
let spawned = false;
const on_spawn = () => {
if (disposed || spawned) return;
spawned = true;
start({event: 'spawn'});
};
try { context.on('spawn', on_spawn); }
catch (error) { context.off('spawn', on_spawn); throw error; }
if (initially_ready) queueMicrotask(() => { if (!disposed && !spawned) on_spawn(); });
return () => {
if (disposed) return;
disposed = true;
context.off('spawn', on_spawn);
};
}
+68
View File
@@ -0,0 +1,68 @@
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<string, Json>) => 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<bot_instance_context<any>, 'on' | 'off'>,
definition: workflow_config, start: (trigger: Record<string, Json>) => 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);
};
}
+55
View File
@@ -0,0 +1,55 @@
import type {Json} from '../../../types/bot/workflow/workflow.ts';
import type {WorkflowStartTemplate} from '../../../types/bot/workflow/metadata.ts';
import {describe, output} from '../metadata.ts';
export const config_template: WorkflowStartTemplate = {
name: 'timer', 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: 'repeat',
i18n: describe('定时模式', '执行一次或按间隔重复执行。'), options: [
{value: 'once', i18n: describe('一次', '一次启动被接受后停止。')},
{value: 'repeat', i18n: describe('重复', '按间隔持续尝试启动。')},
]},
{name: 'max_runs', type: 'number', nullable: true, required: false, default: null,
integer: true, min: 1, max: 100000,
i18n: describe('最大启动次数', '仅计入已启动或排队的请求;null 表示无限次。')},
{
name: 'interval_ms', type: 'number', required: true, integer: true,
min: 10, max: 2_147_483_647, default: 1000,
i18n: describe('间隔毫秒', '定时触发的间隔,必须是至少 10 毫秒的安全整数。'),
}],
output: {
...output('object', '定时数据', '每次定时触发时生成的事件名称和时间戳。'),
properties: {
event: output('string', '事件名称', '固定为 timer。'),
timestamp: output('number', '触发时间', '触发时的 Unix 时间戳,单位为毫秒。'),
},
},
};
export function schedule_timer_start(interval_ms: number,
start: (trigger: Record<string, Json>) => void): () => void {
if (!Number.isSafeInteger(interval_ms) || interval_ms < 10 || interval_ms > 2_147_483_647) {
throw new Error('Invalid workflow timer interval');
}
const timer = setTimeout(() => start({event: 'timer', timestamp: Date.now()}), interval_ms);
timer.unref?.();
return () => clearTimeout(timer);
}
export function register_timer_start(interval_ms: number,
start: (trigger: Record<string, Json>) => void): () => void {
let disposed = false;
let cancel: () => void;
const schedule = () => {
cancel = schedule_timer_start(interval_ms, trigger => {
try { start(trigger); }
finally { if (!disposed) schedule(); }
});
};
schedule();
return () => { disposed = true; cancel(); };
}