/** * Lightweight pair of `setInterval` timers managing the heartbeat / cleanup * cadence of a `TypedBroadcastChannel`. Extracted from `channel.ts` so the * channel core stays under the 300-line hard budget while keeping each timer * lifecycle visible and individually testable. */ export interface HeartbeatRunnerOptions { readonly heartbeatInterval: number; readonly onHeartbeat: () => void; readonly onCleanup: () => void; } /** Mutable pair of timers; `start` schedules, `stop` clears. */ export class HeartbeatRunner { private readonly opts: HeartbeatRunnerOptions; private heartbeatTimer: ReturnType | null = null; private cleanupTimer: ReturnType | null = null; public constructor(opts: HeartbeatRunnerOptions) { this.opts = opts; } public start(): void { this.heartbeatTimer = setInterval( () => this.opts.onHeartbeat(), this.opts.heartbeatInterval ); this.cleanupTimer = setInterval( () => this.opts.onCleanup(), this.opts.heartbeatInterval * 2 ); } public stop(): void { if (this.heartbeatTimer !== null) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } if (this.cleanupTimer !== null) { clearInterval(this.cleanupTimer); this.cleanupTimer = null; } } }