From ac78100883c48a1f4a6661d8d09aab3b3452e47c Mon Sep 17 00:00:00 2001 From: Debdut Date: Wed, 5 Aug 2026 10:59:05 +0530 Subject: [PATCH] fix: use actual room versions instead of `defaultRoomVersion` everywhere --- packages/federation-sdk/src/sdk.ts | 4 ++ .../src/services/room.service.ts | 40 +++++++++++-------- .../external-federation-request.controller.ts | 6 +-- packages/room/src/manager/factory.ts | 2 +- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/federation-sdk/src/sdk.ts b/packages/federation-sdk/src/sdk.ts index f374f9a4f..40e67d1af 100644 --- a/packages/federation-sdk/src/sdk.ts +++ b/packages/federation-sdk/src/sdk.ts @@ -259,6 +259,10 @@ export class FederationSDK { return this.stateService.getLatestRoomState(...args); } + getRoomVersion(...args: Parameters) { + return this.stateService.getRoomVersion(...args); + } + handlePdu(...args: Parameters) { return this.stateService.handlePdu(...args); } diff --git a/packages/federation-sdk/src/services/room.service.ts b/packages/federation-sdk/src/services/room.service.ts index 372ba85f7..46ee3887f 100644 --- a/packages/federation-sdk/src/services/room.service.ts +++ b/packages/federation-sdk/src/services/room.service.ts @@ -440,6 +440,8 @@ export class RoomService { async updateUserPowerLevel(roomId: RoomID, userId: UserID, powerLevel: number, senderId: UserID): Promise { logger.info(`Updating power level for user ${userId} in room ${roomId} to ${powerLevel} by ${senderId}`); + const roomVersion = await this.stateService.getRoomVersion(roomId); + const authEventIds = await this.eventService.getAuthEventIds('m.room.power_levels', { roomId, senderId }); const powerLevelsAuthResult = this.getEventByType(authEventIds, 'm.room.power_levels'); @@ -512,7 +514,7 @@ export class RoomService { origin_server_ts: Date.now(), sender: eventToSign.sender, }, - PersistentEventFactory.defaultRoomVersion, + roomVersion, ); await this.stateService.handlePdu(event); @@ -741,7 +743,7 @@ export class RoomService { origin_server_ts: Date.now(), sender: userId, }, - PersistentEventFactory.defaultRoomVersion, + createEvent.version, ); await stateService.handlePdu(membershipEvent); @@ -760,16 +762,23 @@ export class RoomService { return membershipEvent.eventId; } - // Resident server is remote, need to do join flow - const roomVersion = '10' as const; + // Resident server is remote, need to do join flow. + // If we already have local state for this room (re-join), hint our known + // version to the resident server instead of asking it to pick from the + // full supported list. + let knownRoomVersion: RoomVersion | undefined; + let isRejoin = false; + try { + knownRoomVersion = await stateService.getRoomVersion(roomId); + isRejoin = true; + } catch (error) { + if (!(error instanceof UnknownRoomError)) { + throw error; + } + } // trying to join room from another server - const makeJoinResponse = await federationService.makeJoin( - residentServer, - roomId, - userId, - roomVersion, // NOTE: check the comment in the called method - ); + const makeJoinResponse = await federationService.makeJoin(residentServer, roomId, userId, knownRoomVersion); // after receiving the join event we need to populate with local user profile const profile = await this.profilesService.queryProfile(userId); @@ -799,13 +808,9 @@ export class RoomService { // from send_join and calls notify() for each event, which is how Rocket.Chat learns about // the join. Without this, events go through the staging area where they get stuck on // missing prev_events and are eventually silently dropped after MAX_EVENT_RETRY. - try { - await stateService.getRoomVersion(roomId); + if (isRejoin) { this.logger.info({ roomId }, 'state already exists, updating with new state from send_join (re-join)'); - } catch (error) { - if (!(error instanceof UnknownRoomError)) { - throw error; - } + } else { this.logger.info({ roomId }, 'room not found, processing initial state'); } @@ -1123,6 +1128,7 @@ export class RoomService { if (!room) { throw new HttpException('Room not found', HttpStatus.NOT_FOUND); } + const roomVersion = await this.stateService.getRoomVersion(roomId); const isTombstoned = await this.isRoomTombstoned(roomId); if (isTombstoned) { logger.warn(`Attempted to delete an already tombstoned room: ${roomId}`); @@ -1173,7 +1179,7 @@ export class RoomService { signatures: {}, type: 'm.room.tombstone', }, - PersistentEventFactory.defaultRoomVersion, + roomVersion, ); const _stateId = await this.stateService.handlePdu(event); diff --git a/packages/homeserver/src/controllers/internal/external-federation-request.controller.ts b/packages/homeserver/src/controllers/internal/external-federation-request.controller.ts index 452d5967f..c989b4d1c 100644 --- a/packages/homeserver/src/controllers/internal/external-federation-request.controller.ts +++ b/packages/homeserver/src/controllers/internal/external-federation-request.controller.ts @@ -61,7 +61,7 @@ export const internalRequestPlugin = (app: Elysia) => { roomId: RoomID; sender: UserID; }; - const version = (query.version as RoomVersion | undefined) || PersistentEventFactory.defaultRoomVersion; + const version = (query.version as RoomVersion | undefined) || (await federationSDK.getRoomVersion(roomId)); switch (eventType) { case 'm.room.member': { const event = await federationSDK.buildEvent<'m.room.member'>( @@ -203,7 +203,7 @@ export const internalRequestPlugin = (app: Elysia) => { '/internal/event/send', async ({ body, query }) => { const event = body as Pdu; - const version = (query.version as RoomVersion | undefined) || PersistentEventFactory.defaultRoomVersion; + const version = (query?.version as RoomVersion | undefined) || (await federationSDK.getRoomVersion(event.room_id)); if (!PersistentEventFactory.isSupportedRoomVersion(version)) { throw new Error(`Room version ${version} is not supported`); } @@ -219,7 +219,7 @@ export const internalRequestPlugin = (app: Elysia) => { }, { body: t.Any(), - query: t.Object({ version: t.String({ default: '10' }) }), + query: t.Optional(t.Object({ version: t.Optional(t.String()) })), detail: { tags: ['Devtools'], summary: 'Send an event', diff --git a/packages/room/src/manager/factory.ts b/packages/room/src/manager/factory.ts index 38ed5f027..e54bba8e5 100644 --- a/packages/room/src/manager/factory.ts +++ b/packages/room/src/manager/factory.ts @@ -38,7 +38,7 @@ export class PersistentEventFactory { '11', ]; - static defaultRoomVersion = '10' as const; // same as synapse + static defaultRoomVersion = '11' as const; // same as synapse static isSupportedRoomVersion(roomVersion: string): roomVersion is RoomVersion { return PersistentEventFactory.supportedRoomVersions.includes(roomVersion);