Patch conversation home from realtime events

This commit is contained in:
kris
2026-04-10 19:21:36 +08:00
parent 7131ee9eb1
commit 0781a56aad
7 changed files with 255 additions and 7 deletions

View File

@@ -1,8 +1,13 @@
import { NextRequest } from "next/server";
import { jsonNoStore } from "@/lib/api-response";
import { requireRequestSession } from "@/lib/boss-auth";
import { subscribeBossEvents } from "@/lib/boss-events";
import { getAuditSummaryView, getConversationItems, getOpsSummaryView } from "@/lib/boss-projections";
import { subscribeBossEvents, type BossEventPayload } from "@/lib/boss-events";
import {
getAuditSummaryView,
getConversationHomeItemForProject,
getConversationItems,
getOpsSummaryView,
} from "@/lib/boss-projections";
import { readState } from "@/lib/boss-data";
export const dynamic = "force-dynamic";
@@ -11,6 +16,24 @@ function sseEvent(event: string, data: unknown) {
return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
}
function shouldEnrichConversationPatch(event: string, payload: Pick<BossEventPayload, "projectId">) {
if (!payload.projectId?.trim()) {
return false;
}
return event === "conversation.updated" || event === "project.messages.updated";
}
async function buildEventPayload(event: string, payload: BossEventPayload) {
if (!shouldEnrichConversationPatch(event, payload)) {
return payload;
}
const state = await readState();
return {
...payload,
conversationItem: getConversationHomeItemForProject(state, String(payload.projectId ?? "")),
};
}
export async function GET(request: NextRequest) {
const session = await requireRequestSession(request);
if (!session) {
@@ -46,11 +69,14 @@ export async function GET(request: NextRequest) {
await publishSnapshots();
unsubscribe = subscribeBossEvents((event, payload) => {
try {
controller.enqueue(encoder.encode(sseEvent(event, payload)));
} catch {
unsubscribe?.();
}
void (async () => {
try {
const eventPayload = await buildEventPayload(event, payload);
controller.enqueue(encoder.encode(sseEvent(event, eventPayload)));
} catch {
unsubscribe?.();
}
})();
});
heartbeatTimer = setInterval(() => {

View File

@@ -21,6 +21,7 @@ export interface BossEventPayload {
taskId?: string;
status?: string;
note?: string;
conversationItem?: unknown;
}
type BossEventListener = (event: BossEventName, payload: BossEventPayload) => void;

View File

@@ -654,6 +654,23 @@ export function getConversationHomeItems(state: BossState): ConversationItem[] {
return sortConversationItems(passthrough);
}
export function getConversationHomeItemForProject(state: BossState, projectId: string): ConversationItem | null {
const normalizedProjectId = projectId.trim();
if (!normalizedProjectId) {
return null;
}
return (
getConversationHomeItems(state).find((item) => {
if (item.projectId === normalizedProjectId) {
return true;
}
return Array.isArray(item.searchTargetProjectIds)
? item.searchTargetProjectIds.includes(normalizedProjectId)
: false;
}) ?? null
);
}
export function getConversationFolderView(
state: BossState,
folderKey: string,