diff --git a/lib/mastodon/routes/statuses.js b/lib/mastodon/routes/statuses.js index 0c4c264..64fcb41 100644 --- a/lib/mastodon/routes/statuses.js +++ b/lib/mastodon/routes/statuses.js @@ -284,12 +284,14 @@ router.post("/api/v1/statuses", async (req, res, next) => { }); console.info(`[Mastodon API] Sent DM to ${recipientActorUrl}`); - // Store in ap_notifications so it appears in the DM thread view + const now = new Date().toISOString(); + const hostname = new URL(publicationUrl).hostname; + const profile = await collections.ap_profile.findOne({}); + + // Store in ap_notifications for the DM thread view try { const ap_notifications = collections.ap_notifications; if (ap_notifications) { - const hostname = new URL(publicationUrl).hostname; - const profile = await collections.ap_profile.findOne({}); await addNotification({ ap_notifications }, { uid: noteId.href, url: noteId.href, @@ -303,23 +305,54 @@ router.post("/api/v1/statuses", async (req, res, next) => { actorHandle: `@${handle}@${hostname}`, inReplyTo: inReplyTo || null, content: { text: (statusText || "").trim(), html: (statusText || "").trim() }, - published: new Date().toISOString(), - createdAt: new Date().toISOString(), + published: now, + createdAt: now, }); } } catch (storeError) { - console.warn("[Mastodon API] Failed to store outbound DM:", storeError.message); + console.warn("[Mastodon API] Failed to store outbound DM in notifications:", storeError.message); } - // Return a minimal status object so the client doesn't error - return res.json({ - id: noteId.href, - created_at: new Date().toISOString(), - content: (statusText || "").trim(), - visibility: "direct", + // Store in ap_timeline with visibility=direct so serializeStatus can + // produce a full Mastodon status object. Home/public timelines already + // exclude direct-visibility items (visibility: { $nin: ["direct"] }). + const timelineItem = { + uid: noteId.href, url: noteId.href, - account: { acct: handle }, + type: "note", + visibility: "direct", + content: { + text: (statusText || "").trim(), + html: (statusText || "").trim(), + }, + author: { + name: profile?.name || handle, + url: actorUri.href, + photo: profile?.icon || "", + handle: `@${handle}@${hostname}`, + }, + published: now, + createdAt: now, + inReplyTo: inReplyTo || null, + category: [], + counts: { likes: 0, boosts: 0, replies: 0 }, + }; + + try { + await addTimelineItem(collections.ap_timeline, timelineItem); + } catch (storeError) { + console.warn("[Mastodon API] Failed to store outbound DM in timeline:", storeError.message); + } + + // Return a full serialized status so clients (Phanpy, Elk) can render it + const status = serializeStatus(timelineItem, { + baseUrl, + favouritedIds: new Set(), + rebloggedIds: new Set(), + bookmarkedIds: new Set(), + pinnedIds: new Set(), }); + return res.json(status); } // ── End DM path ───────────────────────────────────────────────────────────