Skip to content

Conversation

@ggazzo
Copy link
Member

@ggazzo ggazzo commented Dec 2, 2025

https://rocketchat.atlassian.net/browse/FB-52

"Room state is not reflected on Rocket.Chat after joining a room"

When a user enters a room that is already in progress, the room is not reflecting the previous members.

Proposed changes (including videos or screenshots)

Issue(s)

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • Tests

    • Added end-to-end tests covering inviting and accepting remote users and cross-system member visibility.
    • Added test helpers to fetch room members and subscriptions for test flows.
  • Refactor

    • Centralized federation event handling onto a single event service, simplifying wiring and setup.
    • Updated test support client with a public client getter plus room-creation and invite helper methods.
  • Chores

    • Bumped relevant packages with a patch release entry.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Dec 2, 2025

🦋 Changeset detected

Latest commit: 444c5b7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/ui-voip Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Dec 2, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactors federation event wiring to use the centralized federationSDK.eventEmitterService (removing injected emitter parameters) across federation event handlers and coordinator; adds Synapse test-client room/invite helpers and test helpers (getRoomMembers, duplicate getSubscriptions); updates E2E tests to use these helpers.

Changes

Cohort / File(s) Summary
Event Handler Refactor
\ee/packages/federation-matrix/src/events/*`<br>`ee/packages/federation-matrix/src/events/ping.ts`, `ee/packages/federation-matrix/src/events/message.ts`, `ee/packages/federation-matrix/src/events/reaction.ts`, `ee/packages/federation-matrix/src/events/member.ts`, `ee/packages/federation-matrix/src/events/edu.ts`, `ee/packages/federation-matrix/src/events/room.ts``
Removed external emitter parameter from exported handlers; replaced emitter.on(...) with federationSDK.eventEmitterService.on(...); removed Emitter and HomeserverEventSignatures imports; updated function signatures to be parameterless.
Event Coordinator
\ee/packages/federation-matrix/src/events/index.ts``
Made registerEvents parameterless and invoked event modules without passing an emitter; removed emitter-related imports/types.
Setup
\ee/packages/federation-matrix/src/setup.ts``
Stopped creating/passing a local emitter; now calls registerEvents() without arguments.
Synapse Test Client
\ee/packages/federation-matrix/tests/helper/synapse-client.ts``
Renamed backing field to _matrixClient; added matrixClient getter (throws if uninitialized); added createRoom(roomName, visibility) and inviteUserToRoom(roomId, userId) methods; added Visibility import; adjusted init/close to use _matrixClient.
Test Helpers
\apps/meteor/tests/data/rooms.helper.ts``
Added getRoomMembers and getSubscriptions(config?: IRequestConfig) helpers used by tests; note: getSubscriptions appears duplicated in the file.
End-to-End Tests
\ee/packages/federation-matrix/tests/end-to-end/room.spec.ts``
Added E2E scenario "Inviting a RC user from Synapse" using getSubscriptions and getRoomMembers to locate/accept invitations and validate cross-system membership synchronization.
ChangeLog / Release
\.changeset/strong-bags-train.md``
Added a changeset bumping two packages to patch releases with a note about membership update fix.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Setup as Setup (init)
  participant SDK as federationSDK.eventEmitterService
  participant Handlers as events/* handlers
  participant Synapse as Synapse Test Client / Homeserver

  Setup->>SDK: registerEvents() -> handlers subscribe
  SDK-->>Handlers: homeserver.matrix.* events published
  Synapse->>SDK: emits homeserver.matrix.{message,membership,reaction,edu,...}
  SDK-->>Handlers: dispatch event to matching handler
  Handlers->>Handlers: process (invite/join/message/redaction/edu)
  Handlers-->>Synapse: side-effects / result observable in tests (membership, messages)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • Consistency of event names and handler subscriptions across ee/packages/federation-matrix/src/events/*.
    • events/index.ts and setup.ts ordering to ensure handlers are registered before events are emitted.
    • Duplicate getSubscriptions export in apps/meteor/tests/data/rooms.helper.ts — confirm deduplication.
    • New Synapse client methods' matrix-js-sdk usage and proper initialization/teardown.

Possibly related PRs

Suggested reviewers

  • sampaiodiego
  • rodrigok
  • ricardogarim

Poem

🐇 I hop through code with tiny paws,

A single bell now rings the laws.
Events converge, subscriptions sing,
Tests invite — the members spring.
I nibble bugs and dance — hooray, applause!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title mentions removing emitter and handling initial state, which aligns with the core changes (removing emitter parameters across federation event modules) but does not fully capture the scope of test helper additions and federation-matrix test enhancements.
Linked Issues check ✅ Passed The PR adds infrastructure to fetch room state on join (new getSubscriptions helper, getRoomMembers helper, and SynapseClient room management methods) and refactors event emission to use a centralized federationSDK service, directly addressing the issue of room state not being reflected when joining an ongoing room.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective: event emitter refactoring for federation, room member/subscription helpers for state sync, and test enhancements to verify room state is properly reflected on join. No unrelated changes detected.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a9db532 and 444c5b7.

📒 Files selected for processing (1)
  • .changeset/strong-bags-train.md (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ggazzo ggazzo changed the title refactor: remove auto-join invite capability fix(federation): previous states on initial state and remove emitter Dec 2, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.2GiB 1.2GiB +12MiB
rocketchat 360MiB 349MiB +12MiB
omnichannel-transcript-service 132MiB 132MiB +15KiB
queue-worker-service 132MiB 132MiB +15KiB
ddp-streamer-service 126MiB 126MiB +21KiB
account-service 113MiB 113MiB +14KiB
stream-hub-service 111MiB 111MiB +12KiB
presence-service 111MiB 111MiB +21KiB
authorization-service 111MiB 111MiB +16KiB

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 23:02", "11/21 16:49", "11/24 17:34", "11/27 22:32", "11/28 19:05", "12/01 23:01", "12/02 21:57", "12/03 21:00", "12/04 18:17", "12/05 21:56", "12/08 20:15", "12/09 22:17", "12/10 02:07 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.35, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.35]
  line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
Loading

Statistics (last 16 days):

  • 📊 Average: 1.5GiB
  • ⬇️ Minimum: 1.2GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.2GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-37677
  • Baseline: develop
  • Timestamp: 2025-12-10 02:07:29 UTC
  • Historical data points: 16

Updated: Wed, 10 Dec 2025 02:07:29 GMT

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors the federation-matrix package to use the SDK's built-in event emitter service instead of maintaining a local Emitter instance. The changes also improve error messages by adding contextual information.

Key Changes

  • Removes local Emitter instantiation and passes the SDK's eventEmitterService to event handlers instead
  • Updates all event handler functions to access federationSDK.eventEmitterService directly
  • Improves error messages in room event handlers by including roomId and userId context
  • Changes room name event handler to use sender field instead of state_key

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ee/packages/federation-matrix/src/setup.ts Removes local Emitter instantiation and unused imports, simplifies initialization
ee/packages/federation-matrix/src/events/index.ts Updates function signatures to remove emitter parameter
ee/packages/federation-matrix/src/events/room.ts Changes event emitter usage, switches from state_key to sender field, improves error messages
ee/packages/federation-matrix/src/events/reaction.ts Updates to use SDK's event emitter service, removes unused imports
ee/packages/federation-matrix/src/events/ping.ts Updates to use SDK's event emitter service
ee/packages/federation-matrix/src/events/message.ts Updates to use SDK's event emitter service, consolidates imports
ee/packages/federation-matrix/src/events/member.ts Updates to use SDK's event emitter service, reorganizes imports
ee/packages/federation-matrix/src/events/edu.ts Updates to use SDK's event emitter service

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

throw new Error(`mapped room not found: ${roomId}`);
}

const localUserId = await Users.findOneByUsername(userId, { projection: { _id: 1 } });
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sender field in Matrix events contains the full Matrix user ID (format: @username:server.domain), but Users.findOneByUsername() expects only the username part. This will cause the user lookup to fail. Use the getUsernameServername utility function to extract the username, similar to how it's done in the room.role event handler (line 63).

Copilot uses AI. Check for mistakes.
room_id: roomId,
content: { name },
state_key: userId,
sender: userId,
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name userId is misleading as it contains the full Matrix user ID from sender (format: @username:server.domain), not just a local user ID. Consider renaming to senderId or senderMatrixId for clarity, and then use getUsernameServername() to extract the actual username before calling Users.findOneByUsername().

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.21%. Comparing base (742867f) to head (5555b14).

Additional details and impacted files

Impacted file tree graph

@@               Coverage Diff                @@
##           feat/invites   #37677      +/-   ##
================================================
+ Coverage         54.01%   54.21%   +0.20%     
================================================
  Files              2629     2629              
  Lines             50050    50051       +1     
  Branches          11212    11212              
================================================
+ Hits              27033    27135     +102     
+ Misses            20886    20769     -117     
- Partials           2131     2147      +16     
Flag Coverage Δ
e2e 57.32% <ø> (-0.02%) ⬇️
e2e-api 43.18% <ø> (+0.97%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ggazzo ggazzo force-pushed the chore/fed-emit branch 5 times, most recently from 82d2031 to 9525467 Compare December 5, 2025 21:23
@ggazzo ggazzo added this to the 7.14.0 milestone Dec 5, 2025
@sampaiodiego sampaiodiego force-pushed the feat/invites branch 3 times, most recently from 36e006f to 65ca437 Compare December 8, 2025 19:12
@ggazzo ggazzo requested a review from Copilot December 8, 2025 22:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

ee/packages/federation-matrix/src/events/room.ts:82

  • The error messages in this event handler are inconsistent. Lines 17 and 22 were updated to include context (roomId and userId), but similar error messages on lines 37, 42, 58, 71, and 82 still lack this context. For better debugging and consistency, these error messages should also include the relevant IDs like:
  • Line 37: throw new Error(\mapped room not found: ${roomId}`);`
  • Line 42: throw new Error(\mapped user not found: ${userId}`);`
  • Line 58: throw new Error(\mapped room not found: ${roomId}`);`
  • Line 71: throw new Error(\mapped user not found: ${userId}`);`
  • Line 82: throw new Error(\mapped user not found: ${senderId}`);`
			throw new Error('mapped room not found');
		}

		const localUser = await Users.findOneByUsername(userId, { projection: { _id: 1, federation: 1, federated: 1 } });
		if (!localUser) {
			throw new Error('mapped user not found');
		}

		await Room.saveRoomTopic(localRoomId._id, topic, {
			_id: localUser._id,
			username: userId,
			federation: localUser.federation,
			federated: localUser.federated,
		});
	});

	federationSDK.eventEmitterService.on('homeserver.matrix.room.role', async (data) => {
		const { room_id: roomId, user_id: userId, sender_id: senderId, role } = data;

		const localRoomId = await Rooms.findOne({ 'federation.mrid': roomId }, { projection: { _id: 1 } });
		if (!localRoomId) {
			throw new Error('mapped room not found');
		}

		const serverName = federationSDK.getConfig('serverName');

		const [allegedUsernameLocal, , allegedUserLocalIsLocal] = getUsernameServername(userId, serverName);
		const localUserId = allegedUserLocalIsLocal && (await Users.findOneByUsername(allegedUsernameLocal, { projection: { _id: 1 } }));

		if (!allegedUserLocalIsLocal) {
			return;
		}

		if (!localUserId) {
			throw new Error('mapped user not found');
		}

		const [senderUsername, , senderIsLocal] = getUsernameServername(senderId, serverName);

		if (senderIsLocal) {
			return;
		}

		const localSenderId = await Users.findOneByUsername(senderUsername, { projection: { _id: 1 } });
		if (!localSenderId) {
			throw new Error('mapped user not found');

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

await acceptRoomInvite(rid, rc1AdminRequestConfig);
}, 15000);

describe('It should reflect all the members and messagens on the rocket.chat side', () => {
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the describe block: "messagens" should be "messages".

Suggested change
describe('It should reflect all the members and messagens on the rocket.chat side', () => {
describe('It should reflect all the members and messages on the rocket.chat side', () => {

Copilot uses AI. Check for mistakes.
expect(members.members.length).toBe(3);
expect(members.members.find((member: IUser) => member.username === federationConfig.rc1.adminUser)).not.toBeNull();
expect(
members.members.find((member: IUser) => member.username === federationConfig.rc1.additionalUser1.username),
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is checking for the wrong user. Line 1616 checks for federationConfig.rc1.additionalUser1.username, but this user was never invited to the room. Based on the setup in beforeAll, the three members should be:

  1. The Synapse admin who created the room
  2. The Synapse user1 (federationConfig.hs1.additionalUser1.matrixUserId) who was invited on line 1594
  3. The RC admin (federationConfig.rc1.adminUser) who was invited on line 1597

This assertion should check for federationConfig.hs1.additionalUser1.matrixUserId instead of federationConfig.rc1.additionalUser1.username.

Suggested change
members.members.find((member: IUser) => member.username === federationConfig.rc1.additionalUser1.username),
members.members.find((member: IUser) => member.username === federationConfig.hs1.additionalUser1.matrixUserId),

Copilot uses AI. Check for mistakes.
if (!this.matrixClient) {
throw new Error('Matrix client is not initialized');
}
await this.matrixClient.invite(userId, roomId);
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter order in the inviteUserToRoom method wrapper is inconsistent with the direct usage of matrixClient.invite elsewhere in the test file. On lines 1594 and 1597, matrixClient.invite is called with (roomId, userId) order, but this wrapper method calls it with (userId, roomId) on line 159.

Either the wrapper should match the direct usage pattern, or the direct calls should be updated to use the consistent wrapper method. This inconsistency could lead to confusion and bugs when the wrapper is actually used.

Suggested change
await this.matrixClient.invite(userId, roomId);
await this.matrixClient.invite(roomId, userId);

Copilot uses AI. Check for mistakes.
@ggazzo ggazzo marked this pull request as ready for review December 9, 2025 12:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
ee/packages/federation-matrix/src/events/room.ts (1)

28-51: Same Matrix ID format issue in topic handler.

The room.topic handler has the same problem as room.name: it uses sender (full Matrix ID) directly for Users.findOneByUsername() and also passes it as username to saveRoomTopic. Apply the same fix using getUsernameServername().

 	federationSDK.eventEmitterService.on('homeserver.matrix.room.topic', async ({ event }) => {
 		const {
 			room_id: roomId,
 			content: { topic },
-			sender: userId,
+			sender,
 		} = event;

 		const localRoomId = await Rooms.findOne({ 'federation.mrid': roomId }, { projection: { _id: 1 } });
 		if (!localRoomId) {
 			throw new Error('mapped room not found');
 		}

-		const localUser = await Users.findOneByUsername(userId, { projection: { _id: 1, federation: 1, federated: 1 } });
+		const [username] = getUsernameServername(sender, serverName);
+		const localUser = await Users.findOneByUsername(username, { projection: { _id: 1, federation: 1, federated: 1 } });
 		if (!localUser) {
 			throw new Error('mapped user not found');
 		}

 		await Room.saveRoomTopic(localRoomId._id, topic, {
 			_id: localUser._id,
-			username: userId,
+			username,
 			federation: localUser.federation,
 			federated: localUser.federated,
 		});
 	});
ee/packages/federation-matrix/src/events/edu.ts (1)

23-27: Add user validation before broadcasting typing indicator.

The typing handler should validate that the federated user exists and is properly mapped to Rocket.Chat before broadcasting, consistent with the message and reaction handlers. Currently, it broadcasts data.user_id directly without verifying the user exists in Rocket.Chat or is actually federated. Add a lookup like the presence handler does (lines 40-43), or at minimum validate the user before broadcast:

const matrixUser = await Users.findOneByUsername(data.user_id);
if (!matrixUser) {
  logger.debug(`No federated user found for Matrix user_id: ${data.user_id}`);
  return;
}

Then use matrixUser._id in the broadcast instead of the raw data.user_id.

♻️ Duplicate comments (4)
ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

155-160: Incorrect parameter order in matrixClient.invite() call.

The Matrix JS SDK's invite method expects (roomId, userId) order, but the code passes (userId, roomId). This will cause invitations to fail.

Apply this diff to fix the parameter order:

 async inviteUserToRoom(roomId: string, userId: string): Promise<void> {
     if (!this.matrixClient) {
         throw new Error('Matrix client is not initialized');
     }
-    await this.matrixClient.invite(userId, roomId);
+    await this.matrixClient.invite(roomId, userId);
 }
ee/packages/federation-matrix/src/events/room.ts (1)

7-26: User lookup will fail: Matrix sender ID format mismatch.

The sender field contains the full Matrix user ID (e.g., @username:server.domain), but Users.findOneByUsername() expects the local username. The room.role handler (lines 63-64) correctly uses getUsernameServername() to extract the username, but this handler does not.

Apply consistent handling:

+	const serverName = federationSDK.getConfig('serverName');
+
 	federationSDK.eventEmitterService.on('homeserver.matrix.room.name', async ({ event }) => {
 		const {
 			room_id: roomId,
 			content: { name },
-			sender: userId,
+			sender,
 		} = event;

 		const localRoomId = await Rooms.findOne({ 'federation.mrid': roomId }, { projection: { _id: 1 } });
 		if (!localRoomId) {
 			throw new Error(`mapped room not found: ${roomId}`);
 		}

-		const localUserId = await Users.findOneByUsername(userId, { projection: { _id: 1 } });
+		const [username] = getUsernameServername(sender, serverName);
+		const localUserId = await Users.findOneByUsername(username, { projection: { _id: 1 } });
 		if (!localUserId) {
-			throw new Error(`mapped user not found: ${userId}`);
+			throw new Error(`mapped user not found: ${sender}`);
 		}

 		await Room.saveRoomName(localRoomId._id, localUserId._id, name);
 	});
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2)

1610-1610: Typo: "messagens" should be "messages".

-			describe('It should reflect all the members and messagens on the rocket.chat side', () => {
+			describe('It should reflect all the members and messages on the rocket.chat side', () => {

1614-1618: Incorrect member assertion - checking wrong user.

The test checks for federationConfig.rc1.additionalUser1.username (line 1616), but this user was never invited. Based on the setup, the three members are:

  1. federationConfig.hs1.adminMatrixUserId (room creator)
  2. federationConfig.hs1.additionalUser1.matrixUserId (invited at line 1594)
  3. federationConfig.rc1.adminUser (invited at line 1597)
 						expect(members.members.find((member: IUser) => member.username === federationConfig.rc1.adminUser)).not.toBeNull();
-						expect(
-							members.members.find((member: IUser) => member.username === federationConfig.rc1.additionalUser1.username),
-						).not.toBeNull();
+						expect(
+							members.members.find((member: IUser) => member.username === federationConfig.hs1.additionalUser1.matrixUserId),
+						).not.toBeNull();
 						expect(members.members.find((member: IUser) => member.username === federationConfig.hs1.adminMatrixUserId)).not.toBeNull();
🧹 Nitpick comments (4)
ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

142-153: Redundant null checks given the getter throws.

The matrixClient getter (lines 54-59) already throws if _matrixClient is null. The explicit null checks in createRoom, inviteUserToRoom, and other methods are now redundant when accessing via this.matrixClient.

Consider removing the redundant checks since the getter handles this:

 async createRoom(roomName: string, visibility: Visibility = Visibility.Private): Promise<string> {
-    if (!this.matrixClient) {
-        throw new Error('Matrix client is not initialized');
-    }
-
     const room = await this.matrixClient.createRoom({
         name: roomName,
         visibility,
     });

     return room.room_id;
 }

The same applies to inviteUserToRoom and other methods that access this.matrixClient after the getter was introduced.

ee/packages/federation-matrix/src/events/ping.ts (1)

3-7: Unnecessary async keyword.

The ping function no longer awaits anything directly—it only registers an event listener. The async keyword on the outer function is unnecessary and could be removed for clarity.

-export const ping = async () => {
+export const ping = () => {
     federationSDK.eventEmitterService.on('homeserver.ping', async (data) => {
         console.log('Message received from homeserver', data);
     });
 };
ee/packages/federation-matrix/src/events/reaction.ts (1)

17-28: Unused parsed values from sender validation.

Lines 17-21 extract userPart and domain from the sender but neither is used—the code proceeds to use the full event.sender as internalUsername. This is consistent with other handlers (e.g., message.ts) where federated users are stored with the full Matrix ID as username. However, the unused variables could be removed if the validation is only meant to confirm format.

-			const [userPart, domain] = event.sender.split(':');
-			if (!userPart || !domain) {
+			if (!event.sender.includes(':')) {
 				logger.error({ sender: event.sender, msg: 'Invalid Matrix sender ID format' });
 				return;
 			}
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)

1605-1605: Simplify assertion pattern.

Mixing optional chaining (?.) with non-null assertion (!) is confusing. Since line 1603 already asserts pendingInvitation is defined, use the cleaner form:

-				rid = pendingInvitation?.rid!;
+				rid = pendingInvitation!.rid;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 742867f and 5555b14.

📒 Files selected for processing (11)
  • apps/meteor/tests/data/rooms.helper.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/edu.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/index.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/message.ts (5 hunks)
  • ee/packages/federation-matrix/src/events/ping.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/reaction.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/room.ts (3 hunks)
  • ee/packages/federation-matrix/src/setup.ts (1 hunks)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2 hunks)
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • apps/meteor/tests/data/rooms.helper.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-11-16T19:09:43.823Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37496
File: packages/apps-engine/tests/server/runtime/deno/LivenessManager.spec.ts:3-3
Timestamp: 2025-11-16T19:09:43.823Z
Learning: In Node.js, `EventEmitter` can be imported from either the 'events' module or the 'stream' module—both export the same reference. While 'events' is the canonical module, importing from 'stream' is valid and works correctly.

Applied to files:

  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • apps/meteor/tests/data/rooms.helper.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • apps/meteor/tests/data/rooms.helper.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧬 Code graph analysis (4)
ee/packages/federation-matrix/src/events/index.ts (6)
ee/packages/federation-matrix/src/events/ping.ts (1)
  • ping (3-7)
ee/packages/federation-matrix/src/events/message.ts (1)
  • message (113-412)
ee/packages/federation-matrix/src/events/reaction.ts (1)
  • reaction (9-92)
ee/packages/federation-matrix/src/events/member.ts (1)
  • member (229-252)
ee/packages/federation-matrix/src/events/edu.ts (1)
  • edus (9-84)
ee/packages/federation-matrix/src/events/room.ts (1)
  • room (7-87)
ee/packages/federation-matrix/src/setup.ts (1)
ee/packages/federation-matrix/src/events/index.ts (1)
  • registerEvents (8-15)
apps/meteor/tests/data/rooms.helper.ts (3)
apps/meteor/tests/data/users.helper.ts (1)
  • IRequestConfig (18-21)
apps/meteor/tests/data/api-data.ts (2)
  • request (10-10)
  • credentials (39-42)
packages/rest-typings/src/index.ts (1)
  • Endpoints (50-97)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)
apps/meteor/tests/data/rooms.helper.ts (4)
  • rejectRoomInvite (492-508)
  • getSubscriptions (467-479)
  • acceptRoomInvite (439-455)
  • getRoomMembers (259-274)
🔇 Additional comments (14)
apps/meteor/tests/data/rooms.helper.ts (1)

457-479: LGTM!

The getSubscriptions helper follows the established patterns in this file, with proper typing using the Endpoints interface and consistent handling of the optional config parameter. This addition supports federation subscription verification as intended.

ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

33-33: LGTM on the private field refactoring.

The rename to _matrixClient with a getter that enforces initialization is a clean pattern that provides better encapsulation and fail-fast behavior.

Also applies to: 54-59, 73-73, 694-694

ee/packages/federation-matrix/src/setup.ts (1)

109-109: Clean refactor removing explicit emitter wiring.

The change to call registerEvents() without parameters aligns with the broader migration to use federationSDK.eventEmitterService internally. Based on learnings, the init() establishes infrastructure first, so event registration after init is correct.

ee/packages/federation-matrix/src/events/member.ts (2)

229-251: LGTM on the event registration refactor.

The migration from an injected emitter to federationSDK.eventEmitterService is clean and consistent with the other event handlers. The membership handling logic (invite/join/leave) remains unchanged, which is appropriate since the PR focuses on the wiring, not the business logic.


3-3: Import change is appropriate.

The import correctly brings in federationSDK for event subscription while retaining the type imports (HomeserverEventSignatures, PduForType) that are still used within the handler functions.

ee/packages/federation-matrix/src/events/index.ts (1)

8-15: Clean refactoring to centralized event emitter pattern.

The migration from injected emitter parameters to a parameterless registerEvents() that relies on federationSDK.eventEmitterService is clean and consistent with the broader architectural change across all event modules.

ee/packages/federation-matrix/src/events/reaction.ts (1)

9-10: Migration to centralized event emitter is correct.

The function signature and event subscription pattern align with the broader refactoring across all federation event modules.

ee/packages/federation-matrix/src/events/message.ts (2)

113-114: Migration to centralized event emitter is correct.

The function signature change and event subscription pattern align with the broader refactoring. The three event handlers (homeserver.matrix.message, homeserver.matrix.encrypted, homeserver.matrix.redaction) are properly subscribed.


246-261: LGTM on the message saving logic.

The text message handling path correctly formats and saves messages with federation event IDs and thread context.

ee/packages/federation-matrix/src/events/room.ts (1)

53-86: Role handler correctly uses getUsernameServername.

This handler properly extracts the username from Matrix IDs using getUsernameServername(), which should be the pattern for the room.name and room.topic handlers as well.

ee/packages/federation-matrix/src/events/edu.ts (2)

9-10: Migration to centralized event emitter is correct.

The function signature change and event subscription pattern align with the broader refactoring.


39-44: User lookup uses Matrix ID as username - consistent pattern.

The Users.findOneByUsername(data.user_id) call uses the Matrix user ID format, consistent with other federation handlers (message.ts, reaction.ts). This assumes federated users are stored with their full Matrix ID as the username field.

ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2)

12-13: LGTM!

New imports for getRoomMembers and getSubscriptions are correctly added and used in the new test suite.


1568-1580: LGTM!

Multiline formatting improves readability without changing assertion behavior.

sampaiodiego
sampaiodiego previously approved these changes Dec 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

33-60: matrixClient getter + close() semantics: avoid throwing when uninitialized

With the new _matrixClient + matrixClient getter, matrixClient is now either a valid MatrixClient or throws. That makes this pattern in close() problematic:

async close(): Promise<void> {
	if (this.matrixClient) {
		// ...
		this._matrixClient = null;
	}
}

If _matrixClient is null (e.g., tests call close() without a prior initialize()), accessing this.matrixClient will throw before the if check can do anything. Previously, close() was effectively a no-op in that case.

Recommend guarding on _matrixClient directly and working with a local variable:

async close(): Promise<void> {
-	if (this.matrixClient) {
-		this.matrixClient.stopClient();
-		await this.matrixClient.store?.deleteAllData?.();
-		await this.matrixClient.clearStores?.();
-		this.matrixClient.removeAllListeners();
-		await this.matrixClient.logout(true);
-		this._matrixClient = null;
-	}
+	const client = this._matrixClient;
+	if (!client) {
+		return;
+	}
+
+	client.stopClient();
+	await client.store?.deleteAllData?.();
+	await client.clearStores?.();
+	client.removeAllListeners();
+	await client.logout(true);
+	this._matrixClient = null;
}

As an optional follow-up, most if (!this.matrixClient) checks in other methods are now redundant, since the getter already throws when uninitialized; you can simplify by just using const client = this.matrixClient; and operating on client.

Also applies to: 687-695

♻️ Duplicate comments (2)
ee/packages/federation-matrix/src/events/room.ts (1)

8-51: Matrix sender should likely be parsed via getUsernameServername before Users.findOneByUsername

Both room.name and room.topic handlers are using the raw sender value as userId and passing it directly into Users.findOneByUsername(userId). In Matrix, event.sender is normally the full Matrix user ID (e.g. @user:server), while Users.findOneByUsername() expects the local Rocket.Chat username.

You’re already using getUsernameServername plus federationSDK.getConfig('serverName') in the room.role handler to split Matrix IDs and decide what is “local”. For consistency and to avoid failed lookups here, consider doing the same in the room.name and room.topic handlers and using the extracted username when querying and when populating the username field passed to Room.saveRoomTopic.

Example shape (adjust to your needs):

const serverName = federationSDK.getConfig('serverName');
const [username] = getUsernameServername(userId, serverName);
const localUser = await Users.findOneByUsername(username, { projection: { _id: 1, federation: 1, federated: 1 } });

Then use username instead of the raw Matrix ID when saving.

ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

142-160: inviteUserToRoom passes roomId/userId to MatrixClient.invite in the wrong order

The matrix-js-sdk MatrixClient.invite signature is invite(roomId: string, userId: string, opts?). Here the wrapper does:

await this.matrixClient.invite(userId, roomId);

So the room ID and user ID are swapped, which will either fail at runtime or invite the wrong target if the SDK doesn’t validate aggressively. This was already pointed out in a previous review and still needs correction.

Suggested fix:

async inviteUserToRoom(roomId: string, userId: string): Promise<void> {
-	if (!this.matrixClient) {
-		throw new Error('Matrix client is not initialized');
-	}
-	await this.matrixClient.invite(userId, roomId);
+	const client = this.matrixClient;
+	await client.invite(roomId, userId);
}

(This also leverages the non-nullable getter instead of manually checking.)

What is the parameter order for the `invite` method on `MatrixClient` in the `matrix-js-sdk` library?
🧹 Nitpick comments (2)
ee/packages/federation-matrix/src/events/ping.ts (1)

3-7: Consider using Logger instead of console.log for consistency.

Other event modules in this package (edu.ts, reaction.ts, member.ts, message.ts, room.ts) use @rocket.chat/logger for structured logging. Using console.log here breaks the logging consistency pattern.

+import { Logger } from '@rocket.chat/logger';
+
+const logger = new Logger('federation-matrix:ping');
+
 export const ping = async () => {
 	federationSDK.eventEmitterService.on('homeserver.ping', async (data) => {
-		console.log('Message received from homeserver', data);
+		logger.debug('Message received from homeserver', data);
 	});
 };
ee/packages/federation-matrix/src/events/message.ts (1)

3-411: Centralizing event wiring on message() looks correct; just ensure it’s only registered once

The switch from an injected emitter to federationSDK.eventEmitterService keeps handler logic intact for plain, encrypted, and redaction events. The only thing to watch is that message() is invoked exactly once in the lifecycle; otherwise you’ll accumulate duplicate listeners on the shared emitter.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5555b14 and 917d175.

📒 Files selected for processing (11)
  • apps/meteor/tests/data/rooms.helper.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/edu.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/index.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/message.ts (5 hunks)
  • ee/packages/federation-matrix/src/events/ping.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/reaction.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/room.ts (3 hunks)
  • ee/packages/federation-matrix/src/setup.ts (1 hunks)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2 hunks)
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • apps/meteor/tests/data/rooms.helper.ts
🧠 Learnings (15)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: When reviewing federation invite handling in Rocket.Chat (specifically under ee/packages/federation-matrix), understand that rejecting an invite via federationSDK.rejectInvite() triggers an event-driven cleanup: a leave event is emitted and handled by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, which calls Room.performUserRemoval() to remove the subscription. Do not add explicit cleanup in the reject branch of handleInvite(); rely on the existing leave-event flow for cleanup. If making changes, ensure this invariant remains and that any related paths still funnel cleanup through the leave event to avoid duplicate or missing removals.

Applied to files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • ee/packages/federation-matrix/src/events/index.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • apps/meteor/tests/data/rooms.helper.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • apps/meteor/tests/data/rooms.helper.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-16T19:09:43.823Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37496
File: packages/apps-engine/tests/server/runtime/deno/LivenessManager.spec.ts:3-3
Timestamp: 2025-11-16T19:09:43.823Z
Learning: In Node.js, `EventEmitter` can be imported from either the 'events' module or the 'stream' module—both export the same reference. While 'events' is the canonical module, importing from 'stream' is valid and works correctly.

Applied to files:

  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/ping.ts
  • ee/packages/federation-matrix/src/events/index.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • apps/meteor/tests/data/rooms.helper.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/tests/data/rooms.helper.ts
🧬 Code graph analysis (3)
ee/packages/federation-matrix/src/setup.ts (1)
ee/packages/federation-matrix/src/events/index.ts (1)
  • registerEvents (8-15)
ee/packages/federation-matrix/src/events/index.ts (6)
ee/packages/federation-matrix/src/events/ping.ts (1)
  • ping (3-7)
ee/packages/federation-matrix/src/events/message.ts (1)
  • message (113-412)
ee/packages/federation-matrix/src/events/reaction.ts (1)
  • reaction (9-92)
ee/packages/federation-matrix/src/events/member.ts (1)
  • member (238-261)
ee/packages/federation-matrix/src/events/edu.ts (1)
  • edus (9-84)
ee/packages/federation-matrix/src/events/room.ts (1)
  • room (7-87)
apps/meteor/tests/data/rooms.helper.ts (3)
apps/meteor/tests/data/users.helper.ts (1)
  • IRequestConfig (18-21)
apps/meteor/tests/data/api-data.ts (2)
  • request (10-10)
  • credentials (39-42)
packages/rest-typings/src/index.ts (1)
  • Endpoints (50-97)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (6)
ee/packages/federation-matrix/src/setup.ts (1)

109-109: LGTM!

Clean simplification of the setup flow. Removing the emitter argument aligns with the centralized event handling through federationSDK.eventEmitterService. Based on learnings, this ordering is correct since init() establishes infrastructure before event handlers are registered.

ee/packages/federation-matrix/src/events/index.ts (1)

8-14: LGTM!

The parameterless registerEvents() function cleanly orchestrates all event module registrations. Each module now internally subscribes via federationSDK.eventEmitterService, eliminating the need for emitter threading through this coordinator.

ee/packages/federation-matrix/src/events/reaction.ts (1)

9-10: LGTM!

Clean migration to federationSDK.eventEmitterService for both reaction and redaction event handling. Error handling and early-return guards are preserved correctly.

Also applies to: 49-49

ee/packages/federation-matrix/src/events/edu.ts (1)

9-10: LGTM!

The EDU (typing/presence) event handlers are correctly migrated to federationSDK.eventEmitterService. Config checks via federationSDK.getConfig('edu') continue to work as expected, ensuring events are only processed when the respective features are enabled.

Also applies to: 33-33

apps/meteor/tests/data/rooms.helper.ts (1)

457-479: New getSubscriptions helper is consistent with existing REST helpers

The implementation follows the same pattern and typing as getRoomInfo / getRoomMembers / getGroupHistory, including optional IRequestConfig overrides, so this looks good.

ee/packages/federation-matrix/src/events/room.ts (1)

53-86: Role handler’s use of getUsernameServername and sender/target checks is coherent

The room.role handler correctly:

  • Maps the target Matrix user ID via getUsernameServername and only proceeds when the target is local.
  • Ignores role updates originating from local senders to avoid loops.
  • Resolves both target and sender to local users before calling Room.addUserRoleRoomScoped.

This logic is consistent with the rest of the federation mapping strategy.

Base automatically changed from feat/invites to develop December 10, 2025 01:45
@ggazzo ggazzo dismissed sampaiodiego’s stale review December 10, 2025 01:45

The base branch was changed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
ee/packages/federation-matrix/src/events/room.ts (2)

8-26: Extract username from Matrix ID before user lookup.

The sender field contains the full Matrix user ID (format: @username:server.domain), but Users.findOneByUsername() expects only the username part. Use getUsernameServername() to extract the username, as done correctly in the room.role event handler at line 63.

Apply this diff:

 	federationSDK.eventEmitterService.on('homeserver.matrix.room.name', async ({ event }) => {
 		const {
 			room_id: roomId,
 			content: { name },
-			sender: userId,
+			sender: senderId,
 		} = event;
 
 		const localRoomId = await Rooms.findOne({ 'federation.mrid': roomId }, { projection: { _id: 1 } });
 		if (!localRoomId) {
 			throw new Error(`mapped room not found: ${roomId}`);
 		}
 
-		const localUserId = await Users.findOneByUsername(userId, { projection: { _id: 1 } });
+		const serverName = federationSDK.getConfig('serverName');
+		const [senderUsername] = getUsernameServername(senderId, serverName);
+		const localUserId = await Users.findOneByUsername(senderUsername, { projection: { _id: 1 } });
 		if (!localUserId) {
-			throw new Error(`mapped user not found: ${userId}`);
+			throw new Error(`mapped user not found: ${senderId}`);
 		}
 
 		await Room.saveRoomName(localRoomId._id, localUserId._id, name);
 	});

28-51: Extract username from Matrix ID before user lookup.

Same issue as the room.name handler: the sender field contains the full Matrix user ID, but Users.findOneByUsername() expects only the username part.

Apply this diff:

 	federationSDK.eventEmitterService.on('homeserver.matrix.room.topic', async ({ event }) => {
 		const {
 			room_id: roomId,
 			content: { topic },
-			sender: userId,
+			sender: senderId,
 		} = event;
 
 		const localRoomId = await Rooms.findOne({ 'federation.mrid': roomId }, { projection: { _id: 1 } });
 		if (!localRoomId) {
 			throw new Error('mapped room not found');
 		}
 
-		const localUser = await Users.findOneByUsername(userId, { projection: { _id: 1, federation: 1, federated: 1 } });
+		const serverName = federationSDK.getConfig('serverName');
+		const [senderUsername] = getUsernameServername(senderId, serverName);
+		const localUser = await Users.findOneByUsername(senderUsername, { projection: { _id: 1, federation: 1, federated: 1 } });
 		if (!localUser) {
 			throw new Error('mapped user not found');
 		}
 
 		await Room.saveRoomTopic(localRoomId._id, topic, {
 			_id: localUser._id,
-			username: userId,
+			username: senderId,
 			federation: localUser.federation,
 			federated: localUser.federated,
 		});
 	});
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2)

1610-1610: Fix typo in describe block.

"messagens" should be "messages".

-				describe('It should reflect all the members and messagens on the rocket.chat side', () => {
+				describe('It should reflect all the members and messages on the rocket.chat side', () => {

1611-1619: Verify the correct user in member assertion.

Line 1616 checks for federationConfig.rc1.additionalUser1.username, but this user was never invited to the room. Based on the setup in beforeAll, the three members should be:

  1. The Synapse admin who created the room
  2. The Synapse user1 (federationConfig.hs1.additionalUser1.matrixUserId) who was invited on line 1594
  3. The RC admin (federationConfig.rc1.adminUser) who was invited on line 1597

Apply this diff:

 					it('It should show all the three users in the members list', async () => {
 						const members = await getRoomMembers(rid, rc1AdminRequestConfig);
 						expect(members.members.length).toBe(3);
 						expect(members.members.find((member: IUser) => member.username === federationConfig.rc1.adminUser)).not.toBeNull();
 						expect(
-							members.members.find((member: IUser) => member.username === federationConfig.rc1.additionalUser1.username),
+							members.members.find((member: IUser) => member.username === federationConfig.hs1.additionalUser1.matrixUserId),
 						).not.toBeNull();
 						expect(members.members.find((member: IUser) => member.username === federationConfig.hs1.adminMatrixUserId)).not.toBeNull();
 					});
ee/packages/federation-matrix/tests/helper/synapse-client.ts (1)

155-160: inviteUserToRoom likely swaps roomId and userId parameters

MatrixClient.invite is typically called as invite(roomId, userId), and past direct usages in this file (and a previous review comment) follow that order. Here the wrapper calls:

await this.matrixClient.invite(userId, roomId);

which appears reversed and would either fail or invite the wrong target.

This should almost certainly be:

await this.matrixClient.invite(roomId, userId);

Please double‑check against the matrix-js-sdk version you’re using (API for MatrixClient.invite) and any existing direct usages in the repo, then update the argument order accordingly.

🧹 Nitpick comments (2)
ee/packages/federation-matrix/tests/helper/synapse-client.ts (2)

33-59: Getter + backing field pattern is sound; guards using this.matrixClient are redundant

Using a private _matrixClient with a throwing matrixClient getter is a good way to enforce initialization before use. However, constructs like if (!this.matrixClient) { throw new Error(...) } will never see a falsy value—the getter already throws when uninitialized. You can simplify by either:

  • Checking _matrixClient directly in those guards, or
  • Dropping the explicit if (!this.matrixClient) checks and relying on the getter’s error.

Not urgent, but it would reduce noise and double-accesses.


687-695: close() cleanup correctly resets backing field after shutdown

Using the getter inside close() to stop the client, clear stores, remove listeners, and log out, then nulling _matrixClient is consistent with the new encapsulation. Just be aware this will now throw if close() is called before initialization; if you ever need idempotent close(), you could guard on _matrixClient directly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 917d175 and a9db532.

📒 Files selected for processing (11)
  • apps/meteor/tests/data/rooms.helper.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/edu.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/index.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/message.ts (5 hunks)
  • ee/packages/federation-matrix/src/events/ping.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/reaction.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/room.ts (3 hunks)
  • ee/packages/federation-matrix/src/setup.ts (1 hunks)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2 hunks)
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/meteor/tests/data/rooms.helper.ts
  • ee/packages/federation-matrix/src/events/index.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/ping.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧠 Learnings (18)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: When reviewing federation invite handling in Rocket.Chat (specifically under ee/packages/federation-matrix), understand that rejecting an invite via federationSDK.rejectInvite() triggers an event-driven cleanup: a leave event is emitted and handled by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, which calls Room.performUserRemoval() to remove the subscription. Do not add explicit cleanup in the reject branch of handleInvite(); rely on the existing leave-event flow for cleanup. If making changes, ensure this invariant remains and that any related paths still funnel cleanup through the leave event to avoid duplicate or missing removals.

Applied to files:

  • ee/packages/federation-matrix/src/events/reaction.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/edu.ts
  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/message.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • ee/packages/federation-matrix/tests/helper/synapse-client.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-16T19:09:43.823Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37496
File: packages/apps-engine/tests/server/runtime/deno/LivenessManager.spec.ts:3-3
Timestamp: 2025-11-16T19:09:43.823Z
Learning: In Node.js, `EventEmitter` can be imported from either the 'events' module or the 'stream' module—both export the same reference. While 'events' is the canonical module, importing from 'stream' is valid and works correctly.

Applied to files:

  • ee/packages/federation-matrix/src/setup.ts
  • ee/packages/federation-matrix/src/events/ping.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
🧬 Code graph analysis (3)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)
apps/meteor/tests/data/rooms.helper.ts (4)
  • rejectRoomInvite (492-508)
  • getSubscriptions (467-479)
  • acceptRoomInvite (439-455)
  • getRoomMembers (259-274)
ee/packages/federation-matrix/src/setup.ts (1)
ee/packages/federation-matrix/src/events/index.ts (1)
  • registerEvents (8-15)
ee/packages/federation-matrix/src/events/room.ts (1)
packages/core-services/src/index.ts (1)
  • Room (169-169)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (10)
ee/packages/federation-matrix/src/setup.ts (1)

109-109: LGTM! Clean transition to centralized event handling.

The removal of the emitter parameter aligns with the shift to federationSDK.eventEmitterService across all event modules.

ee/packages/federation-matrix/src/events/reaction.ts (1)

9-47: LGTM! Consistent refactor to centralized event handling.

The transition from local emitter to federationSDK.eventEmitterService is correct, and the reaction processing logic remains intact.

ee/packages/federation-matrix/src/events/ping.ts (1)

3-7: LGTM! Clean refactor.

The transition to federationSDK.eventEmitterService is correct.

ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)

1584-1608: Good test coverage for FB-52.

The new test scenario validates that when a user joins an in-progress room (with existing members and messages), the room state is properly reflected on the Rocket.Chat side. This directly addresses the PR objective.

ee/packages/federation-matrix/src/events/message.ts (1)

113-265: LGTM! Event wiring refactored correctly.

The transition to federationSDK.eventEmitterService for message handling is correct, and all message processing logic remains intact.

ee/packages/federation-matrix/src/events/edu.ts (1)

9-31: LGTM! Typing and presence event handling refactored correctly.

The event wiring transition to federationSDK.eventEmitterService is correct, and the EDU processing logic is preserved.

ee/packages/federation-matrix/src/events/member.ts (1)

238-260: The refactored event subscription and membership handling correctly process Matrix membership state.

The test "It should show all the three users in the members list" validates that room members are properly reflected when a user joins an already in-progress room with prior messages. The handleJoin() function correctly processes join events for existing rooms, and the new event subscription wiring via federationSDK.eventEmitterService is the proper implementation approach. No additional changes are needed.

ee/packages/federation-matrix/tests/helper/synapse-client.ts (3)

10-10: Visibility import and usage look consistent with createRoom helper

Importing Visibility and using it as the defaulted visibility parameter in createRoom is a clean, typed way to constrain room visibility in tests; no issues here.


71-74: initialize() assignment to backing field is correct

Creating the client, starting it, and then assigning to _matrixClient aligns with the new getter pattern and avoids exposing a half‑initialized client. This change looks good.


142-153: createRoom helper aligns with matrix-js-sdk usage

Wrapping matrixClient.createRoom with a typed helper that takes roomName and visibility (defaulting to Visibility.Private) is consistent with the SDK’s createRoom options and improves test readability. Implementation looks correct.

If you want to be extra sure this matches the exact version of matrix-js-sdk in use, please confirm the createRoom options shape in the installed SDK docs.

@ggazzo ggazzo added the stat: QA assured Means it has been tested and approved by a company insider label Dec 10, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Dec 10, 2025
@ggazzo ggazzo merged commit 4793aca into develop Dec 10, 2025
5 of 8 checks passed
@ggazzo ggazzo deleted the chore/fed-emit branch December 10, 2025 03:00
@dougfabris dougfabris modified the milestones: 7.14.0, 8.0.0 Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants