import type { RoutineEventBlock } from "@rakazo/contracts"; import { markRoutineEventsRemoved } from "@rakazo/core"; import type { Prisma, PrismaClient } from "./client.js"; import { appendEventInTransaction } from "./events.js"; import { createThreadMessageInTransaction } from "./messages.js"; export interface RoutineNoticeInput { spaceId: string; threadId: string; /** The bot that set the routine up and writes the line. */ botId: string; block: RoutineEventBlock; } /** Write the timeline line for a routine the bot set up and remember it on the routine. */ export async function postRoutineNotice( prisma: PrismaClient, input: RoutineNoticeInput, ): Promise<{ messageId: string; seq: number }> { return prisma.$transaction(async (tx: Prisma.TransactionClient) => { const message = await createThreadMessageInTransaction(tx, { threadId: input.threadId, role: "bot", blocks: [input.block], botId: input.botId, markUnread: false, }); await tx.routine.updateMany({ where: { id: input.block.routineId }, data: { noticeMessageId: message.id }, }); const event = await appendEventInTransaction(tx, { spaceId: input.spaceId, threadId: input.threadId, botId: input.botId, type: "thread.message.created", payload: { messageId: message.id, role: "bot", blocks: [input.block] }, }); return { messageId: message.id, seq: event.seq }; }); } /** * Mark every line about a removed routine in the thread of its latest line. Returns the thread and * event seq to notify, or null when the routine had no line or nothing changed. */ export async function markRoutineNoticesRemoved( prisma: PrismaClient, routine: { id: string; botId: string; noticeMessageId: string | null }, ): Promise<{ threadId: string; seq: number } | null> { if (!routine.noticeMessageId) return null; return prisma.$transaction(async (tx: Prisma.TransactionClient) => { const notice = await tx.message.findUnique({ where: { id: routine.noticeMessageId! }, select: { threadId: true, thread: { select: { spaceId: true } } }, }); if (!notice) return null; const messages = await tx.message.findMany({ where: { threadId: notice.threadId, blocks: { array_contains: [{ kind: "event", routineId: routine.id }] }, }, select: { id: true, role: true, botId: true, blocks: true }, }); let seq: number | null = null; for (const message of messages) { const blocks = markRoutineEventsRemoved(message.blocks as RoutineEventBlock[], routine.id); if (!blocks) continue; await tx.message.update({ where: { id: message.id }, data: { blocks: blocks as Prisma.InputJsonValue }, }); const event = await appendEventInTransaction(tx, { spaceId: notice.thread.spaceId, threadId: notice.threadId, botId: message.botId ?? routine.botId, type: "thread.message.updated", payload: { messageId: message.id, role: message.role, blocks }, }); seq = event.seq; } return seq === null ? null : { threadId: notice.threadId, seq }; }); }