import { db, actionEvents } from "../db"; import { eq, desc, and, isNull, lt, sql } from "drizzle-orm"; export interface RecordActionInput { userId: string; actionType: string; entityType: string; entityId: string; summary: string; beforeState: Record; afterState: Record; inversePatch?: Record; metadata?: Record; undoable?: boolean; } export async function recordAction(input: RecordActionInput) { const [event] = await db .insert(actionEvents) .values({ userId: input.userId, actionType: input.actionType, entityType: input.entityType, entityId: input.entityId, summary: input.summary, beforeState: input.beforeState, afterState: input.afterState, inversePatch: input.inversePatch, metadata: input.metadata ?? {}, undoable: input.undoable ?? true, }) .returning(); return event; } export async function getRecentActions(userId: string, limit = 20) { return db .select() .from(actionEvents) .where(and(eq(actionEvents.userId, userId), isNull(actionEvents.undoneAt))) .orderBy(desc(actionEvents.createdAt)) .limit(limit); } export async function getActionEvent(userId: string, actionEventId: string) { const [event] = await db .select() .from(actionEvents) .where( and(eq(actionEvents.id, actionEventId), eq(actionEvents.userId, userId)) ); return event ?? null; } export async function markUndone(actionEventId: string) { await db .update(actionEvents) .set({ undoneAt: new Date() }) .where(eq(actionEvents.id, actionEventId)); } export async function pruneOldActions(userId: string, daysOld = 90) { const cutoff = new Date(); cutoff.setDate(cutoff.getDate() - daysOld); await db .delete(actionEvents) .where( and( eq(actionEvents.userId, userId), lt(actionEvents.createdAt, cutoff) ) ); }