From c7037387a96391ff0c939598ecfc4e5bc837b0ca Mon Sep 17 00:00:00 2001 From: Ally Founder Date: Tue, 11 Aug 2026 20:38:35 -0400 Subject: [PATCH] MessageLogger: show edit history inline, not just the current content --- .../src/patches/fluxIntercept.ts | 10 ++++++ .../message-logger/src/patches/rowStyling.ts | 35 ++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/plugins/message-logger/src/patches/fluxIntercept.ts b/plugins/message-logger/src/patches/fluxIntercept.ts index 3e4b4f3..50eb461 100644 --- a/plugins/message-logger/src/patches/fluxIntercept.ts +++ b/plugins/message-logger/src/patches/fluxIntercept.ts @@ -20,6 +20,11 @@ const UserStore = findByStoreName("UserStore"); // forever if the plugin gets disabled. export const fakedMessages = new Map(); +// Every past content version for a message, oldest first, current content NOT included (rowStyling +// appends that itself from the live record). Same id-in-external-map pattern as fakedMessages - +// row.message.id survives into the row JSON, a custom property doesn't (confirmed live). +export const editHistory = new Map(); + function currentUserId(): string | undefined { return UserStore?.getCurrentUser?.()?.id; } @@ -162,6 +167,10 @@ function handleUpdate(event: any): void { if (!storage.options?.logEdited) return; if (ignoredFor(original, true)) return; + const history = editHistory.get(updated.id) ?? []; + history.push(original.content ?? ""); + editHistory.set(updated.id, history); + addLogEntry(snapshotMessage(original, "edited", newContent, false), limitsFromStorage()); } @@ -205,4 +214,5 @@ export function revertFakedMessages(): void { } } fakedMessages.clear(); + editHistory.clear(); } diff --git a/plugins/message-logger/src/patches/rowStyling.ts b/plugins/message-logger/src/patches/rowStyling.ts index 787c72e..23fd771 100644 --- a/plugins/message-logger/src/patches/rowStyling.ts +++ b/plugins/message-logger/src/patches/rowStyling.ts @@ -2,18 +2,45 @@ import { ReactNative } from "@vendetta/metro/common"; import { after, before } from "@vendetta/patcher"; import { waitFor } from "@shared/lib/waitFor"; import { rawFind, rawFindByName } from "@shared/lib/rawFind"; -import { fakedMessages } from "./fluxIntercept"; +import { editHistory, fakedMessages } from "./fluxIntercept"; const TAG = "[MessageLogger]"; +function textNode(text: string) { + return { content: text, type: "text" }; +} + +// Confirmed live: message.content in the row JSON is an array of {content, type} rich-text nodes, +// not a plain string. Old versions get an inline "(edited)" tag of their own here, stacked above +// the current content - the current version keeps Discord's own native "(edited)" tag rather than +// getting a second one from here, since that already renders correctly on a genuinely-edited +// message with no help needed. +function applyEditHistory(message: any) { + const history = editHistory.get(message.id); + if (!history?.length) return; + + const currentContent: any[] = Array.isArray(message.content) ? message.content : [textNode(String(message.content ?? ""))]; + const nodes: any[] = []; + for (const oldContent of history) { + nodes.push(textNode(oldContent || "(empty)")); + nodes.push(textNode(" (edited)\n")); + } + nodes.push(...currentContent); + message.content = nodes; +} + // Confirmed live: whatever builds the row JSON sent across the native bridge only carries known // schema fields through - a custom property set directly on the MessageRecord (confirmed present // there via eval) never survives into row.message here. message.id does survive, though, so -// checking membership in fluxIntercept's own fakedMessages map (already tracked there for onUnload -// cleanup) works where a custom flag on the row itself can't. +// checking membership in fluxIntercept's own fakedMessages/editHistory maps (already tracked there +// for onUnload cleanup / log capture) works where a custom flag on the row itself can't. function handleRow(row: any) { const message = row?.message; - if (!message?.id || !fakedMessages.has(message.id)) return; + if (!message?.id) return; + + applyEditHistory(message); + + if (!fakedMessages.has(message.id)) return; message.edited = "deleted"; message.textColor = ReactNative.processColor("#E4404380");