| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import type { StreamEvent } from "@/lib/types"; |
|
|
| export interface EventEntry { |
| |
| index: number; |
| |
| ts: number; |
| event: StreamEvent; |
| } |
|
|
| interface TaskLog { |
| entries: EventEntry[]; |
| done: boolean; |
| } |
|
|
| const logs = new Map<string, TaskLog>(); |
|
|
| function ensureLog(taskId: string): TaskLog { |
| let log = logs.get(taskId); |
| if (!log) { |
| log = { entries: [], done: false }; |
| logs.set(taskId, log); |
| } |
| return log; |
| } |
|
|
| |
| export function appendEvent(taskId: string, event: StreamEvent): EventEntry { |
| const log = ensureLog(taskId); |
| const entry: EventEntry = { |
| index: log.entries.length, |
| ts: Date.now(), |
| event, |
| }; |
| log.entries.push(entry); |
| return entry; |
| } |
|
|
| |
| export function markDone(taskId: string): void { |
| const log = logs.get(taskId); |
| if (log) log.done = true; |
| } |
|
|
| |
| export function readEvents( |
| taskId: string, |
| fromIndex = 0, |
| ): { entries: EventEntry[]; done: boolean } { |
| const log = logs.get(taskId); |
| if (!log) return { entries: [], done: false }; |
| return { |
| entries: log.entries.slice(fromIndex), |
| done: log.done, |
| }; |
| } |
|
|
| |
| export function isDone(taskId: string): boolean { |
| return logs.get(taskId)?.done ?? false; |
| } |
|
|
| |
| export function eventCount(taskId: string): number { |
| return logs.get(taskId)?.entries.length ?? 0; |
| } |
|
|
| |
| export function clearLog(taskId: string): void { |
| logs.delete(taskId); |
| } |
|
|