Skip to content

chore: remove deprecated State method getServersInRoom#337

Merged
sampaiodiego merged 5 commits intomainfrom
chore-remove-deprecated-getserversinroom
Mar 9, 2026
Merged

chore: remove deprecated State method getServersInRoom#337
sampaiodiego merged 5 commits intomainfrom
chore-remove-deprecated-getserversinroom

Conversation

@sampaiodiego
Copy link
Member

@sampaiodiego sampaiodiego commented Mar 3, 2026

Summary by CodeRabbit

  • Refactor
    • Server membership checks now use deduplicated server sets for more accurate filtering.
    • Multi-room server operations are processed concurrently for improved performance.
    • Public API now exposes a set-based server view and accepts an optional precomputed room state; a deprecated array-based convenience method was removed.
  • Tests
    • Updated tests to assert set semantics (presence and size) instead of array-based checks.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Replaced array-based server lookups with Set-based APIs: callers now use getServerSetInRoom(roomId, roomState?) which returns a Set; removed getServersInRoom. Presence EDU sending now concurrently aggregates unique non-origin servers via Promise.all before dispatching EDUs.

Changes

Cohort / File(s) Summary
Presence / EDU flow
packages/federation-sdk/src/services/edu.service.ts
Replaced per-room sequential array retrieval with concurrent getServerSetInRoom(roomId) calls via Promise.all, aggregate non-origin servers in a Set, then send EDUs to Array.from(uniqueServers).
Authorization checks
packages/federation-sdk/src/services/event-authorization.service.ts
Switched room server lookup from getServersInRoom(...) (array) to getServerSetInRoom(..., state) (Set) and changed membership test from includes(...) to has(...).
State service API & tests
packages/federation-sdk/src/services/state.service.ts, packages/federation-sdk/src/services/state.service.spec.ts
Updated getServerSetInRoom(roomId, roomState?) to accept an optional roomState and return Set<string>; removed deprecated getServersInRoom; tests updated to use Set.has/Set.size and cover deduplication and join/leave scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant EduSvc as EduService
    participant StateSvc as StateService
    participant Remote as RemoteServerPool

    rect rgba(200,200,255,0.5)
    Caller->>EduSvc: request presence update for roomIds[]
    end

    rect rgba(200,255,200,0.5)
    EduSvc->>StateSvc: Promise.all(getServerSetInRoom(roomId) for each roomId)
    StateSvc-->>EduSvc: Set<string> per room (concurrent)
    end

    rect rgba(255,200,200,0.5)
    EduSvc->>Remote: send EDU to Array.from(aggregateNonOriginServers)
    Remote-->>EduSvc: ACK / responses
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'chore: remove deprecated State method getServersInRoom' directly describes the main change: removing the deprecated getServersInRoom method from StateService and replacing all usages with getServerSetInRoom across multiple service files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

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.

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/edu.service.ts (1)

50-59: Consider bounded concurrency for room fan-out.

Promise.all(roomIds.map(...)) can overload state/backend calls when roomIds is large. A small batch limit keeps latency benefits with better stability.

Suggested bounded-concurrency pattern
-			await Promise.all(
-				roomIds.map(async (roomId) => {
-					const servers = await this.stateService.getServerSetInRoom(roomId);
-					for (const server of servers) {
-						if (server !== origin) {
-							uniqueServers.add(server);
-						}
-					}
-				}),
-			);
+			const BATCH_SIZE = 50;
+			for (let i = 0; i < roomIds.length; i += BATCH_SIZE) {
+				const batch = roomIds.slice(i, i + BATCH_SIZE);
+				await Promise.all(
+					batch.map(async (roomId) => {
+						const servers = await this.stateService.getServerSetInRoom(roomId);
+						for (const server of servers) {
+							if (server !== origin) {
+								uniqueServers.add(server);
+							}
+						}
+					}),
+				);
+			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/edu.service.ts` around lines 50 - 59,
The current Promise.all over roomIds can overwhelm state/backend when roomIds is
large; replace the unbounded parallelism in the block that calls
this.stateService.getServerSetInRoom(roomId) (inside the map over roomIds) with
a bounded-concurrency approach (e.g., use a small batch loop over roomIds or a
concurrency limiter like p-limit) so only N calls run at once, still awaiting
each batch before moving on, and continue adding results into uniqueServers
while skipping origin; update the function containing that logic (referencing
roomIds, stateService.getServerSetInRoom, uniqueServers, and origin) to
implement this limiter/batching.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/federation-sdk/src/services/edu.service.ts`:
- Around line 50-59: The current Promise.all over roomIds can overwhelm
state/backend when roomIds is large; replace the unbounded parallelism in the
block that calls this.stateService.getServerSetInRoom(roomId) (inside the map
over roomIds) with a bounded-concurrency approach (e.g., use a small batch loop
over roomIds or a concurrency limiter like p-limit) so only N calls run at once,
still awaiting each batch before moving on, and continue adding results into
uniqueServers while skipping origin; update the function containing that logic
(referencing roomIds, stateService.getServerSetInRoom, uniqueServers, and
origin) to implement this limiter/batching.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb5a49 and 912ad08.

📒 Files selected for processing (3)
  • packages/federation-sdk/src/services/edu.service.ts
  • packages/federation-sdk/src/services/event-authorization.service.ts
  • packages/federation-sdk/src/services/state.service.ts
💤 Files with no reviewable changes (1)
  • packages/federation-sdk/src/services/state.service.ts
📜 Review details
⏰ 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: cubic · AI code reviewer
  • GitHub Check: Code Quality Checks(lint, test, tsc)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/event-authorization.service.ts
  • packages/federation-sdk/src/services/edu.service.ts
🔇 Additional comments (2)
packages/federation-sdk/src/services/edu.service.ts (1)

27-28: Good Set-based server retrieval and origin filtering.

This change cleanly removes duplicate targets and keeps self-origin out of EDU dispatch.

packages/federation-sdk/src/services/event-authorization.service.ts (1)

252-253: Set membership check is a solid update.

Switching to getServerSetInRoom(...).has(...) is correct and more efficient than array membership checks.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

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: 1

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/state.service.spec.ts (1)

1439-1475: Consider consolidating overlapping join/leave server-list tests.

These two cases validate nearly the same flow (remote user join → leave → rejoin). Keeping one as the canonical flow and narrowing the other to a distinct edge case would reduce test maintenance.

Also applies to: 2302-2332

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/state.service.spec.ts` around lines 1439
- 1475, The two tests that exercise the same join→leave→rejoin flow should be
consolidated: keep one full canonical test (the existing "should list correct
servers for a room" that uses joinUser, leaveUser and
stateService.getServerSetInRoom) and remove or narrow the duplicate elsewhere
(the similar block at lines 2302-2332) so it asserts only a distinct edge-case;
update the remaining test to cover the full join/leave/rejoin sequence with bob,
diego and remoteUser, and simplify the duplicated test to validate a single
behavior (e.g., only join or only leave) to avoid overlapping coverage and
reduce maintenance. Ensure references to joinUser, leaveUser, and
getServerSetInRoom remain in the canonical test so behavior is fully validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/federation-sdk/src/services/state.service.spec.ts`:
- Around line 2292-2299: The test name "should return empty set for room with
only creator" contradicts its assertions; update the test description in the
it(...) call to reflect that the server set contains the creator's server (e.g.,
"should return set containing only the room creator's server") so it matches the
behavior exercised by createRoom and stateService.getServerSetInRoom and the
expect checks for 'example.com' and size === 1.

---

Nitpick comments:
In `@packages/federation-sdk/src/services/state.service.spec.ts`:
- Around line 1439-1475: The two tests that exercise the same join→leave→rejoin
flow should be consolidated: keep one full canonical test (the existing "should
list correct servers for a room" that uses joinUser, leaveUser and
stateService.getServerSetInRoom) and remove or narrow the duplicate elsewhere
(the similar block at lines 2302-2332) so it asserts only a distinct edge-case;
update the remaining test to cover the full join/leave/rejoin sequence with bob,
diego and remoteUser, and simplify the duplicated test to validate a single
behavior (e.g., only join or only leave) to avoid overlapping coverage and
reduce maintenance. Ensure references to joinUser, leaveUser, and
getServerSetInRoom remain in the canonical test so behavior is fully validated.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 912ad08 and bb25663.

📒 Files selected for processing (1)
  • packages/federation-sdk/src/services/state.service.spec.ts
📜 Review details
⏰ 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). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/state.service.spec.ts
🧬 Code graph analysis (1)
packages/federation-sdk/src/services/state.service.spec.ts (2)
packages/core/src/events/m.room.create.ts (1)
  • roomCreateEvent (26-39)
packages/room/src/manager/room-state.ts (1)
  • creator (12-22)
🔇 Additional comments (1)
packages/federation-sdk/src/services/state.service.spec.ts (1)

1449-1451: Set-based migration assertions look correct.

The switch to getServerSetInRoom(...) and Set.has/Set.size checks is consistent with the new API and preserves the expected join/leave behavior checks.

Also applies to: 1456-1459, 1464-1466, 1471-1474

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/federation-sdk/src/services/state.service.spec.ts">

<violation number="1" location="packages/federation-sdk/src/services/state.service.spec.ts:2292">
P3: Test name contradicts assertions: it claims an empty set but expects one server (`example.com`). Rename to match actual behavior.</violation>

<violation number="2" location="packages/federation-sdk/src/services/state.service.spec.ts:2302">
P3: New test case substantially duplicates existing join/leave/rejoin server-set coverage in the same spec, increasing maintenance cost.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

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

Removes the deprecated array-based StateService.getServersInRoom API and migrates call sites/tests to the set-based getServerSetInRoom interface for server membership checks.

Changes:

  • Removed deprecated getServersInRoom from StateService.
  • Updated services to use Set semantics (has, size) instead of array operations.
  • Expanded/updated tests to validate set semantics and membership filtering.

Reviewed changes

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

File Description
packages/federation-sdk/src/services/state.service.ts Deletes deprecated convenience wrapper in favor of getServerSetInRoom.
packages/federation-sdk/src/services/state.service.spec.ts Updates existing assertions to set semantics and adds a focused getServerSetInRoom test suite.
packages/federation-sdk/src/services/event-authorization.service.ts Switches room membership check from includes to Set.has.
packages/federation-sdk/src/services/edu.service.ts Uses getServerSetInRoom; presence updates now gather servers concurrently across rooms.

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

Comment on lines +50 to +59
await Promise.all(
roomIds.map(async (roomId) => {
const servers = await this.stateService.getServerSetInRoom(roomId);
for (const server of servers) {
if (server !== origin) {
uniqueServers.add(server);
}
}
}
}
}),
);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Promise.all(roomIds.map(...)) fans out one getServerSetInRoom call per room with no concurrency limit. If roomIds can be large, this can overwhelm the DB/state store and increase tail latency. Consider batching / limiting concurrency (e.g., chunking roomIds, a simple semaphore, or a library like p-limit).

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

codecov-commenter commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 13.33333% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.77%. Comparing base (7bb5a49) to head (edadd9c).

Files with missing lines Patch % Lines
...ackages/federation-sdk/src/services/edu.service.ts 0.00% 11 Missing ⚠️
...on-sdk/src/services/event-authorization.service.ts 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #337      +/-   ##
==========================================
- Coverage   50.78%   50.77%   -0.01%     
==========================================
  Files          97       97              
  Lines       10949    10946       -3     
==========================================
- Hits         5560     5558       -2     
+ Misses       5389     5388       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 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.

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
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: 1

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/state.service.spec.ts (1)

2302-2332: Collapse this into the existing room-server transition test.

This scenario is effectively the same flow already covered by should list correct servers for a room above: initial creator-only set, remote join, remote leave, remote rejoin. Keeping both adds DB-heavy test time and duplicate maintenance without covering a new edge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/state.service.spec.ts` around lines 2302
- 2332, Remove the duplicate test "should update server list when users join and
leave" and consolidate its assertions into the existing "should list correct
servers for a room" test: reuse the same helpers (createRoom, joinUser,
leaveUser) and stateService.getServerSetInRoom calls to add the remote join,
remote leave, and remote rejoin assertions (checking has('remote.com') and size)
at the appropriate points in that existing test so the full flow (creator-only →
join → leave → rejoin) is covered in one test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/federation-sdk/src/services/state.service.spec.ts`:
- Around line 2228-2357: Tests only exercise StateService.getServerSetInRoom but
the PR also changed edu.service.ts and event-authorization.service.ts so add
regression tests that exercise the new callers: write unit/integration tests
that trigger edu.service.ts flows (e.g., call the function that processes EDUs
and ensure it uses Array.from(...).origin filtering) and tests for
event-authorization.service.ts that hit the authorization path that uses
Set.has(...) (simulate events from origins present/absent in the set and assert
allow/deny behavior); locate the entrypoints in edu.service (the EDU processing
method) and in event-authorization.service (the method that checks origins with
Set.has) and add test cases that validate the new filtering/authorization logic
across cross-server scenarios to ensure coverage.

---

Nitpick comments:
In `@packages/federation-sdk/src/services/state.service.spec.ts`:
- Around line 2302-2332: Remove the duplicate test "should update server list
when users join and leave" and consolidate its assertions into the existing
"should list correct servers for a room" test: reuse the same helpers
(createRoom, joinUser, leaveUser) and stateService.getServerSetInRoom calls to
add the remote join, remote leave, and remote rejoin assertions (checking
has('remote.com') and size) at the appropriate points in that existing test so
the full flow (creator-only → join → leave → rejoin) is covered in one test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64e4fa74-1af0-4864-bf15-cef21f3ed4fc

📥 Commits

Reviewing files that changed from the base of the PR and between bb25663 and ac71592.

📒 Files selected for processing (1)
  • packages/federation-sdk/src/services/state.service.spec.ts
📜 Review details
⏰ 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). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/state.service.spec.ts

Comment on lines +2228 to +2357
describe('getServerSetInRoom', () => {
it('should return servers with joined members', async () => {
const { roomCreateEvent } = await createRoom('public');

const alice = '@alice:example.com';
const bob = '@bob:remote.com';
const charlie = '@charlie:another.com';

await joinUser(roomCreateEvent.roomId, alice);
await joinUser(roomCreateEvent.roomId, bob);
await joinUser(roomCreateEvent.roomId, charlie);

const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId);

expect(servers.has('example.com')).toBe(true);
expect(servers.has('remote.com')).toBe(true);
expect(servers.has('another.com')).toBe(true);
expect(servers.size).toBe(3);
});

it('should deduplicate servers with multiple users from same domain', async () => {
const { roomCreateEvent } = await createRoom('public');

const alice = '@alice:example.com';
const bob = '@bob:example.com';
const charlie = '@charlie:example.com';

await joinUser(roomCreateEvent.roomId, alice);
await joinUser(roomCreateEvent.roomId, bob);
await joinUser(roomCreateEvent.roomId, charlie);

const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId);

expect(servers.has('example.com')).toBe(true);
expect(servers.size).toBe(1);
});

it('should exclude servers with non-joined members', async () => {
const { roomCreateEvent } = await createRoom('public');

const creator = '@alice:example.com'; // Room creator with admin permissions
const joined = '@joined:joined.com';
const left = '@left:left.com';
const banned = '@banned:banned.com';
const invited = '@invited:invited.com';

await joinUser(roomCreateEvent.roomId, joined);
await joinUser(roomCreateEvent.roomId, left);
await joinUser(roomCreateEvent.roomId, banned);

// Change memberships - use creator for moderation actions
await leaveUser(roomCreateEvent.roomId, left);
await banUser(roomCreateEvent.roomId, banned, creator);
await inviteUser(roomCreateEvent.roomId, invited, creator);

const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId);

expect(servers.has('joined.com')).toBe(true);
expect(servers.has('left.com')).toBe(false);
expect(servers.has('banned.com')).toBe(false);
expect(servers.has('invited.com')).toBe(false);
expect(servers.size).toBe(2); // example.com (creator) + joined.com
});

it('should return creator server for room with only creator', async () => {
const { roomCreateEvent } = await createRoom('public');

const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId);

// Only the room creator from createRoom should be present
expect(servers.has('example.com')).toBe(true);
expect(servers.size).toBe(1);
});

it('should update server list when users join and leave', async () => {
const { roomCreateEvent } = await createRoom('public');

const remoteUser = '@alice:remote.com';

// Initially only creator's server
const servers1 = await stateService.getServerSetInRoom(roomCreateEvent.roomId);
expect(servers1.has('example.com')).toBe(true);
expect(servers1.size).toBe(1);

// Add remote user
await joinUser(roomCreateEvent.roomId, remoteUser);
const servers2 = await stateService.getServerSetInRoom(roomCreateEvent.roomId);
expect(servers2.has('example.com')).toBe(true);
expect(servers2.has('remote.com')).toBe(true);
expect(servers2.size).toBe(2);

// Remove remote user
await leaveUser(roomCreateEvent.roomId, remoteUser);
const servers3 = await stateService.getServerSetInRoom(roomCreateEvent.roomId);
expect(servers3.has('example.com')).toBe(true);
expect(servers3.has('remote.com')).toBe(false);
expect(servers3.size).toBe(1);

// Add remote user back
await joinUser(roomCreateEvent.roomId, remoteUser);
const servers4 = await stateService.getServerSetInRoom(roomCreateEvent.roomId);
expect(servers4.has('example.com')).toBe(true);
expect(servers4.has('remote.com')).toBe(true);
expect(servers4.size).toBe(2);
});

it('should handle multiple servers with different user counts', async () => {
const { roomCreateEvent } = await createRoom('public');

// Server 1: 3 users
await joinUser(roomCreateEvent.roomId, '@user1:server1.com');
await joinUser(roomCreateEvent.roomId, '@user2:server1.com');
await joinUser(roomCreateEvent.roomId, '@user3:server1.com');

// Server 2: 2 users
await joinUser(roomCreateEvent.roomId, '@alice:server2.com');
await joinUser(roomCreateEvent.roomId, '@bob:server2.com');

// Server 3: 1 user
await joinUser(roomCreateEvent.roomId, '@charlie:server3.com');

const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId);

expect(servers.has('example.com')).toBe(true);
expect(servers.has('server1.com')).toBe(true);
expect(servers.has('server2.com')).toBe(true);
expect(servers.has('server3.com')).toBe(true);
expect(servers.size).toBe(4);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add regression coverage for the changed callers, not just StateService.

This suite validates getServerSetInRoom itself, but the PR also changes edu.service.ts and event-authorization.service.ts, and those files are still showing 0% patch coverage in the PR report. A bug in the new Array.from(...)/origin filtering or the Set.has(...) authorization path would still slip through with this test set alone.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/state.service.spec.ts` around lines 2228
- 2357, Tests only exercise StateService.getServerSetInRoom but the PR also
changed edu.service.ts and event-authorization.service.ts so add regression
tests that exercise the new callers: write unit/integration tests that trigger
edu.service.ts flows (e.g., call the function that processes EDUs and ensure it
uses Array.from(...).origin filtering) and tests for
event-authorization.service.ts that hit the authorization path that uses
Set.has(...) (simulate events from origins present/absent in the set and assert
allow/deny behavior); locate the entrypoints in edu.service (the EDU processing
method) and in event-authorization.service (the method that checks origins with
Set.has) and add test cases that validate the new filtering/authorization logic
across cross-server scenarios to ensure coverage.

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.

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/event-authorization.service.ts (1)

239-253: Remove the unreachable !state branch while touching this path.

Reusing the fetched state in getServerSetInRoom(roomId, state) is the right optimization. The guard on Line 240 is dead, though: getLatestRoomState(roomId) throws when the room state is missing, so this method never receives undefined.

♻️ Suggested cleanup
 async serverHasAccessToResource(roomId: RoomID, serverName: string): Promise<boolean> {
 	const state = await this.stateService.getLatestRoomState(roomId);
-	if (!state) {
-		this.logger.debug(`Room ${roomId} not found`);
-		return false;
-	}
 
 	const aclEvent = state.get('m.room.server_acl:');
 	const isServerAllowed = await this.checkServerAcl(aclEvent, serverName);
 	if (!isServerAllowed) {
 		this.logger.warn(`Server ${serverName} is denied by room ACL for room ${roomId}`);
Based on learnings, `StateService.getLatestRoomState(roomId: string)` returns `Promise` and throws `No state found for room ${roomId}` when the state is missing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/event-authorization.service.ts` around
lines 239 - 253, The null-check branch for state is unreachable because
stateService.getLatestRoomState(roomId) throws when missing; remove the
conditional that tests if (!state) along with its logger.debug and return false,
and keep using the fetched state variable when calling
this.stateService.getServerSetInRoom(roomId, state). Ensure no other code
assumes state can be undefined in the surrounding flow (methods referenced:
stateService.getLatestRoomState, stateService.getServerSetInRoom, variable
state, and this.logger.debug).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/federation-sdk/src/services/event-authorization.service.ts`:
- Around line 239-253: The null-check branch for state is unreachable because
stateService.getLatestRoomState(roomId) throws when missing; remove the
conditional that tests if (!state) along with its logger.debug and return false,
and keep using the fetched state variable when calling
this.stateService.getServerSetInRoom(roomId, state). Ensure no other code
assumes state can be undefined in the surrounding flow (methods referenced:
stateService.getLatestRoomState, stateService.getServerSetInRoom, variable
state, and this.logger.debug).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0de7fe31-6b33-49b9-a1d7-37f803204b9e

📥 Commits

Reviewing files that changed from the base of the PR and between ac71592 and 2f213eb.

📒 Files selected for processing (2)
  • packages/federation-sdk/src/services/event-authorization.service.ts
  • packages/federation-sdk/src/services/state.service.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/state.service.ts
  • packages/federation-sdk/src/services/event-authorization.service.ts
📚 Learning: 2025-09-14T13:34:12.448Z
Learnt from: ricardogarim
Repo: RocketChat/homeserver PR: 184
File: packages/federation-sdk/src/services/event-authorization.service.ts:213-223
Timestamp: 2025-09-14T13:34:12.448Z
Learning: ACL events (m.room.server_acl) are not yet implemented in the homeserver codebase, so ACL-related code currently handles the simpler case where no ACL events exist in room state.

Applied to files:

  • packages/federation-sdk/src/services/event-authorization.service.ts
🔇 Additional comments (1)
packages/federation-sdk/src/services/state.service.ts (1)

695-720: Nice API upgrade for the deprecated lookup replacement.

Accepting an optional roomState here cleanly removes the redundant fetch and lets callers reuse the same snapshot for membership checks.

ggazzo
ggazzo previously approved these changes Mar 9, 2026
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.

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/state.service.spec.ts (1)

2228-2325: Consider adding tests for the roomState parameter path.

All tests call getServerSetInRoom(roomId) without the optional roomState argument, leaving the externally-supplied-state code path untested. Per the implementation, when roomState is provided, it uses that snapshot directly instead of calling getLatestRoomState().

The event-authorization.service.ts caller passes an explicit state snapshot (line 252 in the implementation), but this branch has no test coverage.

💡 Example test for the `roomState` parameter
it('should use provided roomState instead of fetching latest', async () => {
  const { roomCreateEvent } = await createRoom('public');
  
  // Join a user to create some state
  await joinUser(roomCreateEvent.roomId, '@alice:remote.com');
  
  // Get the current state
  const currentState = await stateService.getLatestRoomState(roomCreateEvent.roomId);
  
  // Join another user (this won't be in our snapshot)
  await joinUser(roomCreateEvent.roomId, '@bob:another.com');
  
  // Call with the earlier state snapshot - should NOT include 'another.com'
  const servers = await stateService.getServerSetInRoom(roomCreateEvent.roomId, currentState);
  
  expect(servers.has('example.com')).toBe(true);
  expect(servers.has('remote.com')).toBe(true);
  expect(servers.has('another.com')).toBe(false); // Not in the snapshot
  expect(servers.size).toBe(2);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/federation-sdk/src/services/state.service.spec.ts` around lines 2228
- 2325, Tests currently never exercise the getServerSetInRoom(roomId, roomState)
code path that uses an externally supplied snapshot; add a unit test that takes
a snapshot via stateService.getLatestRoomState(roomId), mutates the live room
(e.g., join another user), then calls stateService.getServerSetInRoom(roomId,
snapshot) and asserts the later join is NOT included. Locate test suite using
getServerSetInRoom in state.service.spec.ts and add a case similar to the
suggested example that references getLatestRoomState and verifies behavior when
roomState is provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/federation-sdk/src/services/state.service.spec.ts`:
- Around line 2228-2325: Tests currently never exercise the
getServerSetInRoom(roomId, roomState) code path that uses an externally supplied
snapshot; add a unit test that takes a snapshot via
stateService.getLatestRoomState(roomId), mutates the live room (e.g., join
another user), then calls stateService.getServerSetInRoom(roomId, snapshot) and
asserts the later join is NOT included. Locate test suite using
getServerSetInRoom in state.service.spec.ts and add a case similar to the
suggested example that references getLatestRoomState and verifies behavior when
roomState is provided.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a8976964-d6f6-4b0b-83f7-9f49c52836cb

📥 Commits

Reviewing files that changed from the base of the PR and between 2f213eb and edadd9c.

📒 Files selected for processing (1)
  • packages/federation-sdk/src/services/state.service.spec.ts
📜 Review details
⏰ 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). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/state.service.spec.ts
🔇 Additional comments (1)
packages/federation-sdk/src/services/state.service.spec.ts (1)

1449-1474: LGTM!

The migration from array-based checks to Set-based checks (.has(), .size) is correct and properly exercises the join/leave/rejoin scenarios for server membership tracking.

@sampaiodiego sampaiodiego merged commit d1483f4 into main Mar 9, 2026
4 checks passed
@sampaiodiego sampaiodiego deleted the chore-remove-deprecated-getserversinroom branch March 9, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants