feat: persist settings and enrich conversation context

This commit is contained in:
jjbrunton committed 2026-08-08 18:18:28 +01:00
1 parent a36723a325
commit 2c100d72b6
84 files changed
+2248 -644

No files matched your search

+43 -20
View File
@@ -30,16 +30,45 @@ export function createConversationsRouter(ctx: WebContext): Router {
return { messages, state, intent: chooseConversationIntent(messages, state, requestedIntent) };
}
router.get('/conversations', async (_req, res) => {
router.get('/conversations', async (req, res) => {
if (!ctx.services.chat) {
res.json([]);
res.status(503).json({ error: 'Chat service not initialized' });
return;
}
try {
res.json(await ctx.services.chat.getCachedConversations());
const conversations = await ctx.services.chat.getCachedConversations();
if (req.query.includeImageMetadata !== 'true') {
res.json(conversations);
return;
}
const receivedMediaRooms = new Set<string>();
const receivedMediaUsers = new Set<string>();
if (ctx.services.media) {
try {
const mediaItems = await ctx.services.media.getMediaItems();
for (const item of mediaItems) {
if (item.sender.toLowerCase() === 'me') continue;
if (item.chatRoomId) receivedMediaRooms.add(item.chatRoomId);
if (item.chatUsername) receivedMediaUsers.add(item.chatUsername.toLowerCase());
}
} catch (error) {
ctx.logger.warn('Failed to read media index for conversation markers:', error);
}
}
res.json(conversations.map((conversation) => ({
...conversation,
hasReceivedImages:
receivedMediaRooms.has(conversation.roomId ?? '')
|| receivedMediaUsers.has(conversation.username.toLowerCase())
|| (conversation.messages ?? []).some(
(message) => !message.isSelf && (message.media?.length ?? 0) > 0,
),
})));
} catch (error) {
ctx.logger.error('Failed to fetch conversations:', error);
res.json([]);
res.status(500).json({ error: 'Failed to fetch conversations' });
}
});
@@ -49,21 +78,10 @@ export function createConversationsRouter(ctx: WebContext): Router {
return;
}
try {
// If a sync is already in flight (e.g. a Full sync the user kicked off
// from the dashboard), don't queue *another* delta + lazy-load behind it
// — that's what makes the modal sit on "Loading…" for minutes. Render
// from cache and let the frontend show a "sync in progress" banner; the
// user can reopen once it's done.
// Conversation reads never initiate a sync. Sync lifecycle events can
// invalidate this query, so starting a sync here would create a loop.
const syncStatus = ctx.services.chat.getSyncStatus();
const syncInFlight = syncStatus.syncing;
if (!syncInFlight) {
try {
await ctx.services.chat.refreshTopChats();
} catch (err) {
ctx.logger.warn('Pre-open delta sync failed:', err);
}
}
const conversation = await findConversation(decodeURIComponent(req.params.id));
if (!conversation) {
res.status(404).json({ error: 'Conversation not found' });
@@ -94,19 +112,24 @@ export function createConversationsRouter(ctx: WebContext): Router {
subreddit?: string;
title?: string;
url: string;
imageUrl: string | null;
sentAt: number;
} | null = null;
try {
const sent = ctx.repos.messages.getLatestByRecipient(conversation.username);
const sent = conversation.roomId
? ctx.repos.messages.getByChatRoomId(conversation.roomId)
?? ctx.repos.messages.getLatestByRecipient(conversation.username)
: ctx.repos.messages.getLatestByRecipient(conversation.username);
if (sent && sent.postId) {
const url = sent.subreddit
const url = sent.postUrl ?? (sent.subreddit
? `https://www.reddit.com/r/${sent.subreddit}/comments/${sent.postId}/`
: `https://redd.it/${sent.postId}`;
: `https://redd.it/${sent.postId}`);
triggeringPost = {
id: sent.postId,
subreddit: sent.subreddit,
title: sent.postTitle,
url,
imageUrl: sent.postImageUrl ?? null,
sentAt: sent.sentAt,
};
}