Scope folder realtime refreshes by device

This commit is contained in:
kris
2026-04-10 12:55:43 +08:00
parent d1e5a1ac5e
commit 0cba837ed3
11 changed files with 357 additions and 9 deletions

View File

@@ -26,6 +26,7 @@ export default async function ConversationFolderPage({
{folder ? (
<RealtimeRefresh
projectIds={folder.threads.map((thread) => thread.projectId)}
deviceId={folder.deviceId}
events={["conversation.updated", "project.messages.updated"]}
/>
) : null}

View File

@@ -262,11 +262,15 @@ export function RealtimeRefresh({
events,
projectId,
projectIds,
deviceId,
deviceIds,
conversationUpdatedNotes,
}: {
events: BossEventName[];
projectId?: string;
projectIds?: string[];
deviceId?: string;
deviceIds?: string[];
conversationUpdatedNotes?: string[];
}) {
const router = useRouter();
@@ -291,6 +295,8 @@ export function RealtimeRefresh({
eventData,
projectId,
projectIds,
deviceId,
deviceIds,
conversationUpdatedNotes,
})) {
return;
@@ -326,7 +332,7 @@ export function RealtimeRefresh({
cancelScheduledRefresh(throttleState);
source.close();
};
}, [conversationUpdatedNotes, events, projectId, projectIds, router]);
}, [conversationUpdatedNotes, deviceId, deviceIds, events, projectId, projectIds, router]);
return null;
}

View File

@@ -1,6 +1,8 @@
export interface RealtimeRefreshScope {
projectId?: string;
projectIds?: string[];
deviceId?: string;
deviceIds?: string[];
conversationUpdatedNotes?: string[];
}
@@ -16,6 +18,7 @@ export type RefreshThrottleDecision =
interface RealtimeEventPayload {
projectId?: string;
deviceId?: string;
note?: string;
}
@@ -44,16 +47,35 @@ export function shouldRefreshRealtimeEvent(input: {
.filter((value): value is string => Boolean(value?.trim()))
.map((value) => value.trim()),
);
const deviceScopeIds = new Set(
[input.deviceId, ...(input.deviceIds ?? [])]
.filter((value): value is string => Boolean(value?.trim()))
.map((value) => value.trim()),
);
let matchedScopedIdentifier = false;
if (projectScopeIds.size > 0) {
if (!payload || typeof payload.projectId !== "string" || !payload.projectId.trim()) {
return true;
if (payload && typeof payload.projectId === "string" && payload.projectId.trim()) {
if (!projectScopeIds.has(payload.projectId.trim())) {
return false;
}
matchedScopedIdentifier = true;
}
if (!projectScopeIds.has(payload.projectId)) {
return false;
}
if (deviceScopeIds.size > 0) {
if (payload && typeof payload.deviceId === "string" && payload.deviceId.trim()) {
if (!deviceScopeIds.has(payload.deviceId.trim())) {
return false;
}
matchedScopedIdentifier = true;
}
}
if ((projectScopeIds.size > 0 || deviceScopeIds.size > 0) && !matchedScopedIdentifier) {
return false;
}
if (input.eventType === "conversation.updated" && input.conversationUpdatedNotes?.length) {
if (!payload || typeof payload.note !== "string" || !payload.note.trim()) {
return false;