/**
* ルートのテスト用: 偽の時計で動く relay(指示書AY 段階7-4。★本物のタイマーで待たない★)。
* `at(t)` で BASE から t 秒まで時計を進め、その間に期限の来たタイマーを順に発火させる。
*/
import { createRelay, DEFAULT_RELAY_LIMITS, type RelayEvent, type RelayLimits } from "@/lib/ds-agent/relay";
export const FAKE_BASE = Date.parse("2026-10-19T12:00:00+09:00");
export async function flush(): Promise<void> {
for (let i = 0; i < 20; i++) await new Promise<void>((resolve) => setImmediate(resolve));
}
export function createFakeRelay(overrides: Partial<RelayLimits> = {}) {
let nowMs = FAKE_BASE;
let nextHandle = 1;
const timers = new Map<number, { at: number; fn: () => void }>();
const events: RelayEvent[] = [];
const limits: RelayLimits = { ...DEFAULT_RELAY_LIMITS, ...overrides };
const relay = createRelay({
now: () => nowMs,
setTimer: (fn, ms) => {
const handle = nextHandle++;
timers.set(handle, { at: nowMs + ms, fn });
return handle;
},
clearTimer: (handle) => {
timers.delete(handle as number);
},
limits,
onEvent: (e) => events.push(e),
});
async function at(t: number): Promise<void> {
const target = FAKE_BASE + Math.round(t * 1000);
for (;;) {
let next: [number, { at: number; fn: () => void }] | undefined;
for (const entry of timers) {
if (entry[1].at <= target && (!next || entry[1].at < next[1].at)) next = entry;
}
if (!next) break;
timers.delete(next[0]);
nowMs = Math.max(nowMs, next[1].at);
next[1].fn();
await flush();
}
nowMs = target;
await flush();
}
return { relay, limits, events, at };
}