-
Notifications
You must be signed in to change notification settings - Fork 13k
chore(federation): refactor edu handling #37013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
WalkthroughConsolidates typing/presence signaling into a single Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Streamer as StreamerCentral
participant EEStart as EE Startup
participant FedSvc as FederationMatrix
participant EDU as Federation EDU
Client->>Streamer: broadcast('notify-room', '.../user-activity/<rid>', [user, activity])
Streamer-->>EEStart: notify-room event (eventName endsWith 'user-activity')
EEStart->>EEStart: parse rid, user, isTyping = activity.includes('user-typing')
EEStart->>FedSvc: notifyUserTyping(rid, user, isTyping)
FedSvc->>FedSvc: resolve local/external room & user mappings
FedSvc->>EDU: send typing EDU to remote homeservers
EDU-->>FedSvc: ack / response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
a19db18 to
d8bd435
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/meteor/ee/server/hooks/federation/index.ts (1)
231-244: Missing ‘user-activity’ emission on local streamer
The listener at apps/meteor/ee/server/hooks/federation/index.ts:231 never fires because NotificationsModule (→ apps/meteor/server/modules/notifications/notifications.module.ts:471–474) is never emitting a'user-activity'event on itsstreamLocal. Add anotifications.streamLocal.emit('user-activity', { rid, username, activities })(e.g. whennotifyRoomhandles a typing event) or switch the hook to subscribe tostreamRoomfor${rid}/user-activity. After making this change, verify the end-to-end flow.
🧹 Nitpick comments (1)
ee/packages/federation-matrix/src/events/edu.ts (1)
75-77: Optionally include previousStatus if availableIf you can read the prior status cheaply, pass it to reduce downstream lookups; otherwise fine to keep undefined.
📜 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.
📒 Files selected for processing (7)
apps/meteor/ee/server/hooks/federation/index.ts(2 hunks)apps/meteor/ee/server/index.ts(0 hunks)apps/meteor/server/modules/listeners/listeners.module.ts(1 hunks)apps/meteor/server/modules/notifications/notifications.module.ts(3 hunks)ee/packages/federation-matrix/src/events/edu.ts(2 hunks)packages/core-services/src/events/Events.ts(1 hunks)packages/ddp-client/src/types/streams.ts(2 hunks)
💤 Files with no reviewable changes (1)
- apps/meteor/ee/server/index.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T15:15:04.613Z
Learnt from: rodrigok
PR: RocketChat/Rocket.Chat#36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.613Z
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:
apps/meteor/ee/server/hooks/federation/index.ts
🧬 Code graph analysis (2)
apps/meteor/ee/server/hooks/federation/index.ts (1)
packages/core-services/src/index.ts (1)
License(160-160)
apps/meteor/server/modules/notifications/notifications.module.ts (1)
apps/meteor/client/lib/cachedStores/CachedStore.ts (1)
eventName(75-80)
⏰ 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)
packages/ddp-client/src/types/streams.ts (2)
47-49: notify-room user-activity typing is consistentSignature
[username, activities]matches server emit usage.
574-583: Local user-activity event is well-defined but depends on server emitTypes align with intended payload. Ensure NotificationsModule emits to streamLocal (see suggested fix there).
Consider a literal union for activities to prevent typos:
type UserActivity = 'user-typing'; activities: UserActivity[];ee/packages/federation-matrix/src/events/edu.ts (1)
31-35: Typing → user-activity broadcast LGTMMinimal, correct mapping.
apps/meteor/server/modules/listeners/listeners.module.ts (2)
154-175: Presence handler inlined correctlyEmits userData, user-status, and presence with proper STATUS_MAP.
183-185: user-activity → notifyRoom wiring looks correctMatches ddp-client signature; pairs with server-side forwarder fix in NotificationsModule.
packages/core-services/src/events/Events.ts (1)
153-153: Approve — new user-activity event signature is correctVerified: repo search shows only expected usages. service.onEvent('user-activity') in apps/meteor/server/modules/listeners/listeners.module.ts already adapts the new { username, isTyping, roomId } payload to the existing notify-room stream (username, activities[]). Remaining occurrences are the stream/client shapes (packages/ddp-client, packages/livechat), the federation bridge (ee/packages/federation-matrix/src/events/edu.ts) and notifications handlers — all expected; no legacy producers require changes.
| public readonly inner = new Emitter<InnerEvents>(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Undefined type and un-wired bus: InnerEvents is missing and inner isn’t bridged to streamLocal
TypeScript will error (InnerEvents not in scope). Also, without forwarding to streamLocal, listeners on notifications.streamLocal('user-activity') will never fire.
Apply this diff to type payloads and forward internally:
- public readonly inner = new Emitter<InnerEvents>();
+ public readonly inner = new Emitter<InnerEvents>();And update notifyRoom to emit properly and bridge to streamLocal:
- this.inner.emit(eventName, {
- rid: room,
- eventName,
- args,
- });
+ if (eventName === 'user-activity') {
+ const [username, activities] = args as [string, string[]];
+ this.inner.emit('user-activity', { rid: room, username, activities });
+ this.streamLocal.emitWithoutBroadcast('user-activity', { rid: room, username, activities });
+ }Add this type (outside changed ranges, e.g., after the class):
type InnerEvents = {
'user-activity': [{ rid: string; username: string; activities: string[] }];
};Run to confirm no remaining gaps:
🏁 Script executed:
#!/bin/bash
rg -nP '(\btype|\binterface)\s+InnerEvents\b'
rg -n "inner\\.on\\('user-activity'"
rg -n "streamLocal\\.emit.*user-activity" -n -C2Length of output: 0
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "PWD: $(pwd)"
echo
echo "1) Locate notifications.module.ts files"
find . -type f -iname 'notifications.module.ts' -print || true
echo
file=$(find . -type f -iname 'notifications.module.ts' -print -quit || true)
if [ -n "$file" ]; then
echo "2) Showing $file (first 300 lines)"
nl -ba "$file" | sed -n '1,300p' || true
else
echo "2) No notifications.module.ts file found"
fi
echo
echo "3) Search for 'InnerEvents' type/interface declarations"
rg -nP '(\btype|\binterface)\s+InnerEvents\b' --hidden || true
echo
echo "4) Search for usages: inner.on('user-activity')"
rg -n "inner\.on\('user-activity'" --hidden || true
echo
echo "5) Search for streamLocal emit of user-activity"
rg -n "streamLocal\.emit.*user-activity" --hidden -n -C2 || true
echo
echo "6) Search for 'inner = new Emitter' occurrences"
rg -n "inner\s*=\s*new\s+Emitter" --hidden -S || true
echo
echo "7) Search for function/method 'notifyRoom'"
rg -n "notifyRoom" --hidden -n -C5 || trueLength of output: 21275
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=apps/meteor/server/modules/notifications/notifications.module.ts
echo "File: $file"
echo "---- head (1-140) ----"
cat -n "$file" | sed -n '1,140p' || true
echo
echo "---- around inner (40-80) ----"
cat -n "$file" | sed -n '40,80p' || true
echo
echo "---- notifyRoom area (470-520) ----"
cat -n "$file" | sed -n '470,520p' || true
echo
echo "---- search for streamLocal, streamRoom, streamLogged in repo ----"
rg -n "streamLocal|streamRoom|streamLogged" --hidden --no-ignore || true
echo
echo "---- search for InnerEvents type/interface ----"
rg -nP '(\btype|\binterface)\s+InnerEvents\b' --hidden --no-ignore || true
echo
echo "---- search for usages of inner.on / inner.emit ----"
rg -n "inner\.on|inner\.emit" --hidden --no-ignore || trueLength of output: 16948
Missing InnerEvents type + bridge 'user-activity' to streamLocal (TypeScript error & listeners won't fire)
InnerEvents is not declared (TypeScript will error) and notifyRoom only emits to inner/streamRoom — it never forwards the typed 'user-activity' payload to streamLocal where code listens (e.g. apps/meteor/ee/server/hooks/federation/index.ts). Fix both: declare the type and forward the event.
- Add this type (e.g. after the class):
type InnerEvents = Record<string, any[]> & {
'user-activity': [{ rid: string; username: string; activities: string[] }];
};- Replace the current inner.emit(...) in notifyRoom with a special-case forward to streamLocal:
if (eventName === 'user-activity') {
const [username, activities] = args as [string, string[]];
const payload = { rid: room, username, activities };
this.inner.emit('user-activity', payload);
this.streamLocal.emitWithoutBroadcast('user-activity', payload);
} else {
this.inner.emit(eventName, {
rid: room,
eventName,
args,
});
}Locations: apps/meteor/server/modules/notifications/notifications.module.ts — inner declaration (line ~51) and notifyRoom (around lines 488–499).
🤖 Prompt for AI Agents
In apps/meteor/server/modules/notifications/notifications.module.ts around lines
51 and 488–499, declare the missing InnerEvents type (e.g. a Record with a
specific 'user-activity' signature: { rid: string; username: string; activities:
string[] }) immediately after the class, and modify notifyRoom so that when
eventName === 'user-activity' you build a payload { rid: room, username,
activities } from the args, emit it to this.inner with the 'user-activity' key
and also forward it to this.streamLocal via emitWithoutBroadcast; for all other
events keep emitting to this.inner with the generic { rid, eventName, args }
shape.
| this.inner.emit(eventName, { | ||
| rid: room, | ||
| eventName, | ||
| args, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Emit only for user-activity and use the correct shape
Guard by event name and pass { rid, username, activities } instead of a generic envelope.
Apply the diff above in the previous comment.
🤖 Prompt for AI Agents
In apps/meteor/server/modules/notifications/notifications.module.ts around lines
493-497, limit emission to only the "user-activity" event and change the emitted
payload shape: check if eventName === 'user-activity' before calling
this.inner.emit, extract username and activities from args (or default them) and
call this.inner.emit(eventName, { rid: room, username, activities }) instead of
the generic envelope containing eventName/args; ensure types/null-safety for
username/activities when extracting.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## chore/federation-backup #37013 +/- ##
===========================================================
+ Coverage 67.33% 67.35% +0.01%
===========================================================
Files 3342 3342
Lines 113397 113398 +1
Branches 20704 20663 -41
===========================================================
+ Hits 76361 76380 +19
+ Misses 34435 34421 -14
+ Partials 2601 2597 -4
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
d8bd435 to
db08115
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/core-services/src/events/Events.ts (1)
153-153: Consider dot-separated naming for consistencyMost events use dot notation (e.g., user.typing, presence.status). Consider 'user.activity' unless there's a strong reason to keep a hyphen.
Apply this diff (if you opt to align):
- 'user-activity'(data: { userId: IUser['_id']; username?: IUser['username']; isTyping: boolean; roomId: IRoom['_id'] }): void; + 'user.activity'(data: { userId: IUser['_id']; username?: IUser['username']; isTyping: boolean; roomId: IRoom['_id'] }): void;
📜 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.
📒 Files selected for processing (7)
apps/meteor/ee/server/hooks/federation/index.ts(2 hunks)apps/meteor/ee/server/index.ts(0 hunks)apps/meteor/server/modules/listeners/listeners.module.ts(1 hunks)apps/meteor/server/modules/notifications/notifications.module.ts(1 hunks)ee/packages/federation-matrix/src/events/edu.ts(2 hunks)packages/core-services/src/events/Events.ts(1 hunks)packages/ddp-client/src/types/streams.ts(2 hunks)
💤 Files with no reviewable changes (1)
- apps/meteor/ee/server/index.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- ee/packages/federation-matrix/src/events/edu.ts
- apps/meteor/ee/server/hooks/federation/index.ts
- packages/ddp-client/src/types/streams.ts
- apps/meteor/server/modules/notifications/notifications.module.ts
- apps/meteor/server/modules/listeners/listeners.module.ts
⏰ 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
| user: Pick<IUser, '_id' | 'username' | 'status' | 'statusText' | 'name' | 'roles'>; | ||
| previousStatus?: UserStatus; | ||
| }): void; | ||
| 'user-activity'(data: { username: string; isTyping: boolean; roomId: string }): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use stable identifiers: prefer userId over username in the event payload
Usernames can change and are not globally unique across federated spaces. Emit a stable ID and keep username optional for UI.
Apply this diff:
- 'user-activity'(data: { username: string; isTyping: boolean; roomId: string }): void;
+ 'user-activity'(data: { userId: IUser['_id']; username?: IUser['username']; isTyping: boolean; roomId: IRoom['_id'] }): void;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'user-activity'(data: { username: string; isTyping: boolean; roomId: string }): void; | |
| 'user-activity'(data: { userId: IUser['_id']; username?: IUser['username']; isTyping: boolean; roomId: IRoom['_id'] }): void; |
🤖 Prompt for AI Agents
In packages/core-services/src/events/Events.ts around line 153, the
'user-activity' event currently requires username but should use a stable userId
instead; update the event signature to accept data: { userId: string; username?:
string; isTyping: boolean; roomId: string } (userId required, username
optional), and then update all emitters and listeners across the codebase to
pass and consume userId rather than username while keeping username as an
optional UI-only field for backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/meteor/ee/server/startup/federation.ts (1)
47-60: Unregister StreamerCentral 'broadcast' listener on stop (apps/meteor/ee/server/startup/federation.ts)Capture the broadcast handler in a const when calling StreamerCentral.on(...) and call StreamerCentral.off('broadcast', handler) inside stopService before destroying the service to avoid callbacks running with federationMatrixService === undefined. (app.unpkg.com)
🧹 Nitpick comments (2)
ee/packages/federation-matrix/src/FederationMatrix.ts (2)
118-151: Presence EDU dispatch looks correct; small guard to avoid no‑op calls.Skip the EDU call when there are no federated rooms for the user. Keeps hot path a bit cleaner.
- const roomsUserIsMemberOf = await Subscriptions.findUserFederatedRoomIds(localUser._id).toArray(); + const roomsUserIsMemberOf = await Subscriptions.findUserFederatedRoomIds(localUser._id).toArray(); + const roomIds = roomsUserIsMemberOf.map(({ externalRoomId }) => externalRoomId).filter(Boolean); + if (roomIds.length === 0) { + return; + } @@ - void instance.homeserverServices.edu.sendPresenceUpdateToRooms( + void instance.homeserverServices.edu.sendPresenceUpdateToRooms( [ { user_id: externalUserId, presence: statusMap[user.status] || 'offline', }, ], - roomsUserIsMemberOf.map(({ externalRoomId }) => externalRoomId).filter(Boolean), + roomIds, );
989-1007: Harden notifyUserTyping: add service guard + explicit return type (hot path).Prevents NPE if service isn’t ready and clarifies intent.
- async notifyUserTyping(rid: string, user: string, isTyping: boolean) { + async notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void> { + if (!this.homeserverServices) { + this.logger.warn('Homeserver services not available, skipping typing notification'); + return; + } if (!rid || !user) { return; }Optional next step: cache recent username→external user id and rid→externalRoomId lookups (small TTL, e.g., 5–10s) to reduce DB hits on bursty typing events.
📜 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.
📒 Files selected for processing (3)
apps/meteor/ee/server/hooks/federation/index.ts(1 hunks)apps/meteor/ee/server/startup/federation.ts(2 hunks)ee/packages/federation-matrix/src/FederationMatrix.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/meteor/ee/server/hooks/federation/index.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
PR: RocketChat/Rocket.Chat#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:
apps/meteor/ee/server/startup/federation.ts
🧬 Code graph analysis (2)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
packages/models/src/index.ts (3)
MatrixBridgedRoom(216-216)Users(209-209)MatrixBridgedUser(217-217)
apps/meteor/ee/server/startup/federation.ts (1)
apps/meteor/client/lib/cachedStores/CachedStore.ts (1)
eventName(75-80)
ccb067f to
567a4e0
Compare
There was a problem hiding this 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)
apps/meteor/ee/server/hooks/federation/index.ts (1)
183-197: Prevent edit-loop: skip Matrix‑origin edits and remove no-op callEdits coming from Matrix can be echoed back because this handler doesn’t guard against
message.federation?.eventIdor external users. Also, Line 190 is a dead call.Apply:
callbacks.add( 'afterSaveMessage', async (message: IMessage, { room }) => { if (FederationActions.shouldPerformFederationAction(room)) { - if (!isEditedMessage(message)) { - return; - } - FederationActions.shouldPerformFederationAction(room); - - await FederationMatrix.updateMessage(message._id, message.msg, message.u); + if (!isEditedMessage(message)) { + return; + } + // Skip events that originated from federation to avoid echo/loops + if (message.federation?.eventId || message.u?.username?.includes(':')) { + return; + } + await FederationMatrix.updateMessage(message._id, message.msg, message.u); } }, callbacks.priority.HIGH, 'federation-matrix-after-room-message-updated', );
🧹 Nitpick comments (3)
apps/meteor/ee/server/hooks/federation/index.ts (3)
93-95: Fix trailing space in callback idTrailing space can create inconsistent IDs and hinder deduplication.
- 'native-federation-on-add-users-to-room ', + 'native-federation-on-add-users-to-room',
1-1: Clean up unused imports
api,License,settings, andnotificationsappear unused here. Remove to keep TS noUnusedLocals happy and reduce bundle noise.-import { api, FederationMatrix } from '@rocket.chat/core-services'; +import { FederationMatrix } from '@rocket.chat/core-services'; -import { License } from '@rocket.chat/license'; -import notifications from '../../../../app/notifications/server/lib/Notifications'; -import { settings } from '../../../../app/settings/server';Also applies to: 3-3, 6-6, 7-7
82-95: Prevent duplicate federation invites — make invites idempotent or guard the hooksVerified: 'federation.onAddUsersToRoom' is invoked from apps/meteor/app/lib/server/methods/addUsersToRoom.ts (bulk), while 'beforeAddUserToRoom' is invoked from apps/meteor/app/lib/server/functions/addUserToRoom.ts and apps/meteor/app/lib/server/functions/createRoom.ts (single/create-room). Either dedupe inside FederationMatrix.inviteUsersToRoom (recommended) or add guards so the same user+room invite isn't sent twice.
📜 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.
📒 Files selected for processing (6)
apps/meteor/ee/server/hooks/federation/index.ts(1 hunks)apps/meteor/ee/server/startup/federation.ts(2 hunks)apps/meteor/server/modules/listeners/listeners.module.ts(1 hunks)ee/packages/federation-matrix/src/FederationMatrix.ts(2 hunks)ee/packages/federation-matrix/src/events/edu.ts(2 hunks)packages/core-services/src/events/Events.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/meteor/server/modules/listeners/listeners.module.ts
- apps/meteor/ee/server/startup/federation.ts
- ee/packages/federation-matrix/src/events/edu.ts
- ee/packages/federation-matrix/src/FederationMatrix.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
PR: RocketChat/Rocket.Chat#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:
apps/meteor/ee/server/hooks/federation/index.ts
⏰ 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). (2)
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (2)
packages/core-services/src/events/Events.ts (2)
152-152: Use explicit identifiers and types; add optional origin to prevent loopsRename
usertouserId, type room/user ids precisely, and include an optionaloriginto help listeners avoid re-broadcast loops.- 'user.activity'(data: { user: string; isTyping: boolean; roomId: string }): void; + 'user.activity'(data: { + userId: IUser['_id']; + roomId: IRoom['_id']; + isTyping: boolean; + origin?: 'local' | 'federation'; + }): void;This also aligns naming with nearby events (e.g.,
user.video-conferenceusesuserId).
152-152: Gate producers/consumers to the new signature — verifiedFound and verified payload uses { user, isTyping, roomId } in:
- ee/packages/federation-matrix/src/events/edu.ts (producer)
- apps/meteor/server/modules/listeners/listeners.module.ts (consumer)
There was a problem hiding this 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)
apps/meteor/ee/server/hooks/federation/index.ts (2)
38-38: Potential crash: user may be undefined.Guard
userwhen checking for external usernames.Apply:
- const shouldBeHandledByFederation = room.federated === true || user.username?.includes(':'); + const shouldBeHandledByFederation = room.federated === true || user?.username?.includes(':');
182-191: Missing loop-prevention and redundant call in edit path.
- Edits originating from Matrix can loop back; skip external users and require
message.federation.eventId.- Remove the no-op duplicate
shouldPerformFederationActioncall.- Add error handling (align with send path).
Apply:
callbacks.add( 'afterSaveMessage', async (message: IMessage, { room }) => { if (FederationActions.shouldPerformFederationAction(room)) { if (!isEditedMessage(message)) { return; } - FederationActions.shouldPerformFederationAction(room); - - await FederationMatrix.updateMessage(message._id, message.msg, message.u); + // Skip updates coming from Matrix (external) to avoid loops + if (message.u?.username?.includes(':')) { + return; + } + // Only federate edits for messages that were federated before + if (!message.federation?.eventId) { + return; + } + try { + await FederationMatrix.updateMessage(message._id, message.msg, message.u); + } catch (error) { + console.error('[updateMessage] Failed to federate message edit:', { mid: message._id, rid: message.rid, error }); + } } }, callbacks.priority.HIGH, 'federation-matrix-after-room-message-updated', );
🧹 Nitpick comments (3)
apps/meteor/ee/server/hooks/federation/index.ts (3)
49-52: Use structured logger instead of console.error.Prefer the project logger to keep logs consistent and searchable.
Example:
- console.error('[sendMessage] Failed to send message to Native Federation:', error); + logger.error({ msg: '[sendMessage] Failed to send message to Native Federation', err: error, mid: message._id, rid: room._id });If
loggerisn’t available here, follow the repo’s standard logging pattern for server hooks.
26-28: Fragile Matrix roomId parsing.
split(':')[1]can be undefined if the format is unexpected. Add a safe parse + guard.Apply:
- const fromServer = federatedRoomId.split(':')[1]; - await MatrixBridgedRoom.createOrUpdateByLocalRoomId(room._id, federatedRoomId, fromServer); + const parts = federatedRoomId.split(':', 2); + const fromServer = parts.length === 2 ? parts[1] : undefined; + if (!fromServer) { + console.warn('[federation] Invalid federatedRoomId, expected "!id:server"', { federatedRoomId, rid: room._id }); + return; + } + await MatrixBridgedRoom.createOrUpdateByLocalRoomId(room._id, federatedRoomId, fromServer);
91-91: Trailing space in callback id.The id string has a trailing space, which can break deduplication/removal of the handler.
Apply:
- 'native-federation-on-add-users-to-room ', + 'native-federation-on-add-users-to-room',
📜 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.
📒 Files selected for processing (2)
apps/meteor/ee/server/hooks/federation/index.ts(1 hunks)apps/meteor/ee/server/startup/federation.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/meteor/ee/server/startup/federation.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
PR: RocketChat/Rocket.Chat#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:
apps/meteor/ee/server/hooks/federation/index.ts
⏰ 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). (2)
- GitHub Check: CodeQL-Build
- GitHub Check: CodeQL-Build
🔇 Additional comments (1)
apps/meteor/ee/server/hooks/federation/index.ts (1)
1-1: FederationMatrix import validated — OK.Verified packages/core-services/index.ts exports:
export const FederationMatrix = proxify<IFederationMatrixService>('federation-matrix');— importing from@rocket.chat/core-servicesis correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/core-services/src/types/IFederationMatrixService.ts (1)
38-38: Disambiguateuser(id vs username); avoid plainstring.If this expects a user id, type it as
IUser['_id'](and consider naminguserId). If it’s a username, rename tousername. If both are acceptable, either document clearly or type asPick<IUser, '_id' | 'username'>.Example if using id:
- notifyUserTyping(rid: IRoomFederated['_id'], user: string, isTyping: boolean): Promise<void>; + notifyUserTyping(rid: IRoomFederated['_id'], userId: IUser['_id'], isTyping: boolean): Promise<void>;
📜 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.
📒 Files selected for processing (2)
apps/meteor/ee/server/startup/federation.ts(2 hunks)packages/core-services/src/types/IFederationMatrixService.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/meteor/ee/server/startup/federation.ts
🔇 Additional comments (1)
packages/core-services/src/types/IFederationMatrixService.ts (1)
38-38: Verified all implementers have the new method - no changes needed.The verification confirms that:
- Only one class implements
IFederationMatrixService: theFederationMatrixclass inee/packages/federation-matrix/src/FederationMatrix.ts- This implementation already includes the
notifyUserTypingmethod (line 989)- The method is properly implemented and called from the federation startup code (line 38 in
apps/meteor/ee/server/startup/federation.ts)- No test mocks or other implementations were found that would break due to the interface change
The interface addition is complete and all implementers are properly updated.
| role: 'moderator' | 'owner' | 'leader' | 'user', | ||
| ): Promise<void>; | ||
| inviteUsersToRoom(room: IRoomFederated, usersUserName: string[], inviter: Pick<IUser, '_id' | 'username'>): Promise<void>; | ||
| notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type rid as IRoomFederated['_id'] for consistency and stronger type safety.
Other methods (e.g., leaveRoom, updateRoomName/Topic) use IRoomFederated['_id']. Keep this consistent.
- notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void>;
+ notifyUserTyping(rid: IRoomFederated['_id'], user: string, isTyping: boolean): Promise<void>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| notifyUserTyping(rid: string, user: string, isTyping: boolean): Promise<void>; | |
| notifyUserTyping(rid: IRoomFederated['_id'], user: string, isTyping: boolean): Promise<void>; |
🤖 Prompt for AI Agents
In packages/core-services/src/types/IFederationMatrixService.ts around line 38,
the notifyUserTyping method currently types its rid parameter as string; change
it to use IRoomFederated['_id'] for consistency and stronger type safety
(aligning with leaveRoom and updateRoomName/Topic). Update the method signature
to accept rid: IRoomFederated['_id'], ensure IRoomFederated is imported in this
file (or add the import), and adjust any call sites/types if necessary to
satisfy the new type.
Co-authored-by: Diego Sampaio <chinello@gmail.com>
Co-authored-by: Diego Sampaio <chinello@gmail.com>
Proposed changes (including videos or screenshots)
Issue(s)
Steps to test or reproduce
Further comments
Summary by CodeRabbit
Bug Fixes
Improvements
Refactor