From ccd825fb39477b8340946907e6977078f01f879c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Svaj=C5=ABnas=20Budrys?= <93791044+svajunas-budrys@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:31:26 +0300 Subject: [PATCH] Remove knock state on join (#4977) Signed-off-by: Svajunas Budrys --- spec/unit/sync-accumulator.spec.ts | 43 ++++++++++++++++++++++++++++++ src/sync-accumulator.ts | 5 +++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/spec/unit/sync-accumulator.spec.ts b/spec/unit/sync-accumulator.spec.ts index 89623eeee..22d333600 100644 --- a/spec/unit/sync-accumulator.spec.ts +++ b/spec/unit/sync-accumulator.spec.ts @@ -571,6 +571,49 @@ describe("SyncAccumulator", function () { expect(sa.getJSON().roomsData.knock["!knock:bar"]).toBeUndefined(); }); + it("should delete knock state when room transitions from knock to join", () => { + const initKnockState = makeKnockState(); + sa.accumulate( + syncSkeleton( + {}, + {}, + {}, + { + knock_state: initKnockState, + }, + ), + ); + expect(sa.getJSON().roomsData.knock["!knock:bar"].knock_state).toBe(initKnockState); + + // Room transitions from knock to join (e.g., after approval and joining) + const joinState = { + account_data: { events: [] }, + ephemeral: { events: [] }, + unread_notifications: {}, + state: { + events: [member("bob", KnownMembership.Join)], + }, + }; + + const syncResponse = { + next_batch: "abc", + rooms: { + join: { + "!knock:bar": joinState, + }, + invite: {}, + leave: {}, + }, + } as unknown as ISyncResponse; + + sa.accumulate(syncResponse); + + expect(sa.getJSON().roomsData.knock["!knock:bar"]).toBeUndefined(); + expect(sa.getJSON().roomsData.join["!knock:bar"].state?.events[0]?.content.membership).toEqual( + KnownMembership.Join, + ); + }); + it("should accumulate read receipts", () => { const receipt1 = { type: "m.receipt", diff --git a/src/sync-accumulator.ts b/src/sync-accumulator.ts index 44638d077..816b45de7 100644 --- a/src/sync-accumulator.ts +++ b/src/sync-accumulator.ts @@ -317,7 +317,10 @@ export class SyncAccumulator { break; case Category.Join: - if (this.inviteRooms[roomId]) { + if (this.knockRooms[roomId]) { + // delete knock state on join + delete this.knockRooms[roomId]; + } else if (this.inviteRooms[roomId]) { // (1) // was previously invite, now join. We expect /sync to give // the entire state and timeline on 'join', so delete previous