import { Agent } from "agents";
import type { GeneratedEnv } from "@ayjnt/env";
type Tick = { at: number; n: number; load: number };
type State = {
intervalSeconds: number;
ticks: Tick[];
scheduleId: string | null;
};
export default class HeartbeatAgent extends Agent<GeneratedEnv, State> {
override initialState: State = { intervalSeconds: 0, ticks: [], scheduleId: null };
/** Recurring callback — fires every intervalSeconds once started. */
async tick(): Promise<void> {
const last = this.state.ticks[0]?.n ?? 0;
const tick = { at: Date.now(), n: last + 1, load: Math.round(Math.random() * 1000) / 10 };
this.setState({ ...this.state, ticks: [tick, ...this.state.ticks].slice(0, 50) });
}
private async stopTicking() {
if (this.state.scheduleId) await this.cancelSchedule(this.state.scheduleId).catch(() => {});
this.setState({ ...this.state, intervalSeconds: 0, scheduleId: null });
}
override async onRequest(request: Request): Promise<Response> {
if (request.method === "POST") {
const { intervalSeconds = 5, stop } = await request.json() as { intervalSeconds?: number; stop?: boolean };
if (stop) { await this.stopTicking(); return Response.json({ ok: true, running: false }); }
await this.stopTicking(); // ← mandatory before starting a new schedule
const s = await this.scheduleEvery(intervalSeconds, "tick");
this.setState({ ...this.state, intervalSeconds, scheduleId: s.id });
return Response.json({ ok: true, running: true, intervalSeconds });
}
return Response.json({ instance: this.name, ...this.state });
}
}