fix(matrix): persist discovered direct rooms during repair

This commit is contained in:
Peter Steinberger
2026-05-11 05:02:57 +01:00
parent 166b42a40f
commit 8d14c9540e
2 changed files with 47 additions and 14 deletions

View File

@@ -210,6 +210,37 @@ describe("repairMatrixDirectRooms", () => {
);
});
it("persists discovered strict rooms alongside an older strict mapped room", async () => {
const setAccountData = vi.fn(async () => undefined);
const client = createClient({
getAccountData: vi.fn(async () => ({
"@alice:example.org": ["!older:example.org"],
})),
getJoinedRooms: vi.fn(async () => ["!older:example.org", "!fresh:example.org"]),
getJoinedRoomMembers: vi.fn(async () => ["@bot:example.org", "@alice:example.org"]),
setAccountData,
});
const result = await repairMatrixDirectRooms({
client,
remoteUserId: "@alice:example.org",
});
expect(result.activeRoomId).toBe("!older:example.org");
expect(result.discoveredStrictRoomIds).toEqual(["!fresh:example.org"]);
expect(result.changed).toBe(true);
expect(result.directContentAfter["@alice:example.org"]).toEqual([
"!older:example.org",
"!fresh:example.org",
]);
expect(setAccountData).toHaveBeenCalledWith(
EventType.Direct,
expect.objectContaining({
"@alice:example.org": ["!older:example.org", "!fresh:example.org"],
}),
);
});
it("rejects unqualified Matrix user ids", async () => {
const client = createClient();

View File

@@ -100,12 +100,14 @@ function normalizeRoomIdList(values: readonly string[]): string[] {
return normalized;
}
function hasPrimaryMatrixDirectRoomMapping(params: {
function hasMatrixDirectRoomMappings(params: {
directContent: MatrixDirectAccountData;
remoteUserId: string;
roomId: string;
roomIds: readonly string[];
}): boolean {
return normalizeMappedRoomIds(params.directContent, params.remoteUserId)[0] === params.roomId;
const current = normalizeMappedRoomIds(params.directContent, params.remoteUserId);
const next = normalizeRoomIdList([...params.roomIds, ...current]);
return current.length === next.length && current.every((roomId, index) => roomId === next[index]);
}
function resolveDirectAccountDataWriteQueue(client: MatrixClient): KeyedAsyncQueue {
@@ -118,10 +120,10 @@ function resolveDirectAccountDataWriteQueue(client: MatrixClient): KeyedAsyncQue
return created;
}
async function writeMatrixDirectRoomMapping(params: {
async function writeMatrixDirectRoomMappings(params: {
client: MatrixClient;
remoteUserId: string;
roomId: string;
roomIds: readonly string[];
}): Promise<MatrixDirectRoomMappingWriteResult> {
return await resolveDirectAccountDataWriteQueue(params.client).enqueue(
DIRECT_ACCOUNT_DATA_QUEUE_KEY,
@@ -130,12 +132,12 @@ async function writeMatrixDirectRoomMapping(params: {
const directContentAfter = buildNextDirectContent({
directContent: directContentBefore,
remoteUserId: params.remoteUserId,
roomId: params.roomId,
roomIds: params.roomIds,
});
const changed = !hasPrimaryMatrixDirectRoomMapping({
const changed = !hasMatrixDirectRoomMappings({
directContent: directContentBefore,
remoteUserId: params.remoteUserId,
roomId: params.roomId,
roomIds: params.roomIds,
});
if (changed) {
await params.client.setAccountData(EventType.Direct, directContentAfter);
@@ -178,10 +180,10 @@ async function classifyDirectRoomCandidate(params: {
function buildNextDirectContent(params: {
directContent: MatrixDirectAccountData;
remoteUserId: string;
roomId: string;
roomIds: readonly string[];
}): MatrixDirectAccountData {
const current = normalizeMappedRoomIds(params.directContent, params.remoteUserId);
const nextRooms = normalizeRoomIdList([params.roomId, ...current]);
const nextRooms = normalizeRoomIdList([...params.roomIds, ...current]);
return {
...params.directContent,
[params.remoteUserId]: nextRooms,
@@ -195,10 +197,10 @@ export async function persistMatrixDirectRoomMapping(params: {
}): Promise<boolean> {
const remoteUserId = normalizeRemoteUserId(params.remoteUserId);
return (
await writeMatrixDirectRoomMapping({
await writeMatrixDirectRoomMappings({
client: params.client,
remoteUserId,
roomId: params.roomId,
roomIds: [params.roomId],
})
).changed;
}
@@ -331,10 +333,10 @@ export async function repairMatrixDirectRooms(params: {
encrypted: params.encrypted === true,
}));
const createdRoomId = inspected.activeRoomId ? null : activeRoomId;
const mappingWrite = await writeMatrixDirectRoomMapping({
const mappingWrite = await writeMatrixDirectRoomMappings({
client: params.client,
remoteUserId,
roomId: activeRoomId,
roomIds: [activeRoomId, ...inspected.discoveredStrictRoomIds],
});
return {
...inspected,