diff --git a/apps/app/src/app/api/pick/expiry-regression.test.ts b/apps/app/src/app/api/pick/expiry-regression.test.ts new file mode 100644 index 0000000..8dc6fd0 --- /dev/null +++ b/apps/app/src/app/api/pick/expiry-regression.test.ts @@ -0,0 +1,18 @@ +// @vitest-environment node +import { afterEach, it, expect, vi } from "vitest"; +import { getSession, setSession } from "./store"; +afterEach(() => vi.useRealTimers()); +it("expires a prompt even when scheduled timers have not run", () => { + vi.useFakeTimers(); vi.setSystemTime(0); + setSession("expired",{status:"picked",prompt:"stale"}); + vi.setSystemTime(600000); + expect(getSession("expired")).toBeUndefined(); + expect(vi.getTimerCount()).toBe(0); +}); +it("refreshes the deadline when a scan becomes a pick", () => { + vi.useFakeTimers(); vi.setSystemTime(0); + setSession("refresh",{status:"scanned"}); + vi.setSystemTime(500000); setSession("refresh",{status:"picked",prompt:"fresh"}); + vi.setSystemTime(600000); expect(getSession("refresh")?.prompt).toBe("fresh"); + vi.setSystemTime(1100000); expect(getSession("refresh")).toBeUndefined(); +}); diff --git a/apps/app/src/app/api/pick/store.ts b/apps/app/src/app/api/pick/store.ts index db16e66..5a67ee7 100644 --- a/apps/app/src/app/api/pick/store.ts +++ b/apps/app/src/app/api/pick/store.ts @@ -12,14 +12,24 @@ const sessions = new Map(); // Auto-expire sessions after 10 minutes const EXPIRY_MS = 10 * 60 * 1000; +const expiresAt = new Map(); const timers = new Map>(); export function getSession(sessionId: string): PickSession | undefined { + if ((expiresAt.get(sessionId) ?? Infinity) <= Date.now()) { + sessions.delete(sessionId); + expiresAt.delete(sessionId); + const timer = timers.get(sessionId); + if (timer) clearTimeout(timer); + timers.delete(sessionId); + return undefined; + } return sessions.get(sessionId); } export function setSession(sessionId: string, data: PickSession) { sessions.set(sessionId, data); + expiresAt.set(sessionId, Date.now() + EXPIRY_MS); // Reset expiry timer const existing = timers.get(sessionId); @@ -28,6 +38,7 @@ export function setSession(sessionId: string, data: PickSession) { sessionId, setTimeout(() => { sessions.delete(sessionId); + expiresAt.delete(sessionId); timers.delete(sessionId); }, EXPIRY_MS), );