/** * 会话内事件总线(A1.3)。 * * 职责:给事件分配会话内单调递增的 seq、向订阅者广播、支持从某个 seq 之后回放(断点续传)。 * A3.7 会话落库后,回放改为读存储,这里只保留实时广播;内存缓冲仅作为 A1 的过渡实现。 */ import { PROTOCOL_VERSION, type PlatformEvent } from '@aps/contracts'; type DistributiveOmit = T extends unknown ? Omit : never; /** 发布事件的入参:v 与 seq 由总线分配,ts 可由调用方指定 */ export type EventInput = DistributiveOmit & { ts?: number }; const REPLAY_BUFFER = 500; export class EventBus { private seq = 0; private readonly buffer: PlatformEvent[] = []; private readonly listeners = new Set<(event: PlatformEvent) => void>(); publish(input: EventInput): PlatformEvent { this.seq += 1; const event = { ...input, v: PROTOCOL_VERSION, seq: this.seq, ts: input.ts ?? Date.now() } as PlatformEvent; this.buffer.push(event); if (this.buffer.length > REPLAY_BUFFER) this.buffer.shift(); for (const listener of this.listeners) listener(event); return event; } /** 从 since(不含)之后回放 */ replay(since = 0): PlatformEvent[] { return this.buffer.filter((event) => event.seq > since); } /** 先回放再订阅:避免回放与订阅之间漏事件 */ subscribe(since: number, listener: (event: PlatformEvent) => void): () => void { for (const event of this.replay(since)) listener(event); this.listeners.add(listener); return () => { this.listeners.delete(listener); }; } get lastSeq(): number { return this.seq; } }