- contracts:补齐生命周期广播事件(订阅、下载、整理结束、刮削、字幕、作品关注 / 元数据 / 季集结构、站点可达性) 的类型与 payload schema,LIFECYCLE_EVENTS 清单与 lifecycleKey 幂等键;HOOK_POINTS 链式钩子挂点; FEATURES 功能清单与 SLOT_POSITIONS 前端插槽位置 - outbox 中继支持一条事件路由给多个订阅方(其余订阅方用 <键>#<任务名>);生命周期事件允许多模块订阅, 没有订阅方时也被中继认领并镜像到 SSE - 服务端 HookRegistry:按注册顺序执行、rewrite / intercept 两类、单钩子超时与异常隔离、无注册零开销; ServerModule 增加 manifest 与 registerHooks,bootstrap 装配 ctx.hooks - ADR-006 与 server README「如何写一个功能模块」 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
// 链式钩子挂点(ADR-006,参考 MoviePilot ChainEventType):同步、按注册顺序执行、可改写或拦截。
|
||
// 这里只登记挂点名称与语义(给功能清单、智能体提示与文档用);入参 / 返回值类型在服务端
|
||
// apps/server/src/hooks/points.ts,因为它们用到 domain 的解析结果等类型。
|
||
|
||
/**
|
||
* - rewrite:每个钩子拿到上一个钩子的结果,返回新值或 undefined(不改);
|
||
* - intercept:任一钩子返回拒绝原因即停止,后面的钩子不再执行。
|
||
*/
|
||
export type HookKind = "rewrite" | "intercept";
|
||
|
||
export const HOOK_POINTS = {
|
||
"name.recognize": {
|
||
kind: "rewrite",
|
||
label: "名称识别",
|
||
when: "资源标题解析之后、按名称召回作品之前",
|
||
effect: "改写解析结果(标题、年份、季集、外部 ID)",
|
||
},
|
||
"organize.rename": {
|
||
kind: "rewrite",
|
||
label: "整理改名",
|
||
when: "按命名模板生成目标路径之后",
|
||
effect: "改写主视频的目标文件名(同主干的字幕等附属文件跟着改)",
|
||
},
|
||
"organize.intercept": {
|
||
kind: "intercept",
|
||
label: "整理拦截",
|
||
when: "整理计划生成后、写整理记录之前",
|
||
effect: "返回原因即拒绝本次整理(记录为失败,原因 intercepted:<原因>)",
|
||
},
|
||
"resource.selection": {
|
||
kind: "rewrite",
|
||
label: "资源选择",
|
||
when: "订阅 / 收录版本重评时候选排好序之后、逐条评估之前",
|
||
effect: "调整候选顺序或过滤掉一部分(不能加入新候选)",
|
||
},
|
||
"subscription.completion.check": {
|
||
kind: "intercept",
|
||
label: "订阅完成判定",
|
||
when: "订阅满足完成条件、标记完成之前",
|
||
effect: "追加完成条件:返回原因即本次不完成,订阅继续追踪",
|
||
},
|
||
} as const satisfies Record<string, { kind: HookKind; label: string; when: string; effect: string }>;
|
||
|
||
export type HookPoint = keyof typeof HOOK_POINTS;
|