From a5223437b8aff1109fd35e1b51a2efc1b1ab8ece Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Fri, 13 Mar 2026 08:12:54 +0100 Subject: [PATCH] feat: add getDirectConversations to notifications storage Groups ap_notifications with isDirect:true by peer actor and returns them as conversation objects shaped for the DM reader tab template. Co-Authored-By: Claude Sonnet 4.6 --- lib/storage/notifications.js | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/lib/storage/notifications.js b/lib/storage/notifications.js index 80d8b3d..a96589c 100644 --- a/lib/storage/notifications.js +++ b/lib/storage/notifications.js @@ -195,3 +195,62 @@ export async function deleteNotification(collections, uid) { const { ap_notifications } = collections; return await ap_notifications.deleteOne({ uid }); } + +/** + * Get direct message conversations grouped by peer actor. + * Returns conversations sorted by most-recent message, newest first. + * @param {object} collections - MongoDB collections + * @returns {Promise} Array of conversation objects + */ +export async function getDirectConversations(collections) { + const { ap_notifications } = collections; + + const rawItems = await ap_notifications + .find({ isDirect: true }) + .sort({ published: -1 }) + .limit(200) + .toArray(); + + // Group by peer (senderActorUrl or actorUrl) + const byPeer = new Map(); + for (const item of rawItems) { + const peerUrl = item.senderActorUrl || item.actorUrl || ""; + if (!peerUrl) continue; + if (!byPeer.has(peerUrl)) { + byPeer.set(peerUrl, { + peerUrl, + peerName: item.actorName || "", + peerHandle: item.actorHandle || "", + peerPhoto: item.actorPhoto || "", + hasUnread: false, + messages: [], + }); + } + const conv = byPeer.get(peerUrl); + if (!item.read) conv.hasUnread = true; + conv.messages.push({ + direction: "inbound", + url: item.url || "", + content: item.content || {}, + published: + item.published instanceof Date + ? item.published.toISOString() + : item.published || "", + }); + } + + // Each conversation's messages arrived newest-first; reverse to chrono order + const conversations = [...byPeer.values()]; + for (const conv of conversations) { + conv.messages.reverse(); + } + + // Sort conversations by most-recent message (newest first) + conversations.sort((a, b) => { + const aLast = a.messages.at(-1)?.published || ""; + const bLast = b.messages.at(-1)?.published || ""; + return bLast < aLast ? -1 : bLast > aLast ? 1 : 0; + }); + + return conversations; +}