From 15ac538a4b4687b679fefea5bf6a4ce72cbf51a7 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 1 Jul 2026 21:27:57 -0400 Subject: [PATCH] feat(threads): enable SDK threadSupport + unthreaded read receipts (P3-8 step 0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit threadSupport:true makes matrix-js-sdk partition m.thread relations into Thread objects (replies leave the main timeline; roots stay). markAsRead now sends UNTHREADED receipts so one receipt still clears room + thread notification counts — without this, badges would stick unread. The thread panel + summary chips land in the same push. Co-Authored-By: Claude Opus 4.8 --- src/app/utils/notifications.ts | 5 +++++ src/client/initMatrix.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/app/utils/notifications.ts b/src/app/utils/notifications.ts index c0ff68596..cbf6d7158 100644 --- a/src/app/utils/notifications.ts +++ b/src/app/utils/notifications.ts @@ -21,8 +21,13 @@ export async function markAsRead(mx: MatrixClient, roomId: string, privateReceip const latestEvent = getLatestValidEvent(); if (latestEvent === null) return; + // Unthreaded receipt: with client threadSupport enabled the SDK would + // otherwise scope this to the main timeline (thread_id: "main"), leaving + // per-thread notification counts permanently unread. Unthreaded preserves + // the pre-threads wire behavior — one receipt clears everything. await mx.sendReadReceipt( latestEvent, privateReceipt || privateReadReceipts ? ReceiptType.ReadPrivate : ReceiptType.Read, + true, ); } diff --git a/src/client/initMatrix.ts b/src/client/initMatrix.ts index fe5258bee..02d8fcd9e 100644 --- a/src/client/initMatrix.ts +++ b/src/client/initMatrix.ts @@ -64,6 +64,11 @@ export const initClient = async (session: Session): Promise => { export const startClient = async (mx: MatrixClient) => { await mx.startClient({ lazyLoadMembers: true, + // P3-8: partition m.thread relations into Thread objects/timelines. Thread + // replies leave the main timeline (roots stay + get a summary chip); the + // thread panel renders them. markAsRead sends UNTHREADED receipts + // (utils/notifications.ts) so room badges keep clearing. + threadSupport: true, }); };